diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5ba7951ba..f99a39107 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.6 + - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.7 - [ ] 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/.vscode/settings.json b/.vscode/settings.json index 0188fe67c..f764ed574 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,75 +1,74 @@ { - "platformio-ide.toolbar": [ - { - "text": "$(home)", - "tooltip": "PlatformIO: Home", - "commands": [ - { - "id": "platformio-ide.runPIOCoreCommand", - "args": "pio home" - } - ] - }, - { - "text": "$(trash)", - "tooltip": "PlatformIO: Clean All", - "commands": [ - { - "id": "workbench.action.tasks.runTask", - "args": "PlatformIO: Clean All" - } - ] - }, - { - "text": "$(check)", - "tooltip": "PlatformIO: Build", - "commands": [ - { - "id": "workbench.action.tasks.runTask", - "args": "PlatformIO: Build" - } - ] - }, - { - "text": "$(zap)", - "tooltip": "PlatformIO: Build and Upload", - "commands": [ - { - "id": "workbench.action.tasks.runTask", - "args": "PlatformIO: Upload" - } - ] - }, - { - "text": "$(flame)", - "tooltip": "PlatformIO: Build, Erase and Upload", - "commands": [ - { - "id": "platformio-ide.runPIOCoreCommand", - "args": "pio run -t erase_upload" - } - ] - }, - { - "text": "$(device-desktop)", - "tooltip": "PlatformIO: Serial Monitor", - "commands": [ - { - "id": "workbench.action.tasks.runTask", - "args": "PlatformIO: Monitor" - } - ] - }, - { - "text": "$(refresh)", - "tooltip": "PlatformIO: Rebuild IntelliSense Index", - "commands": [ - { - "id": "workbench.action.tasks.runTask", - "args": "PlatformIO: Rebuild IntelliSense Index" - } - ] - } - ] -} - + "platformio-ide.toolbar": [ + { + "text": "$(home)", + "tooltip": "PlatformIO: Home", + "commands": "platformio-ide.showHome" + }, + { + "text": "$(trash)", + "tooltip": "PlatformIO: Clean", + "commands": "platformio-ide.clean" + }, + { + "text": "$(check)", + "tooltip": "PlatformIO: Build", + "commands": "platformio-ide.build" + }, + { + "text": "Upload", + "tooltip": "PlatformIO: Flash firmware (NO build run)", + "commands": [ + { + "id": "platformio-ide.runPIOCoreCommand", + "args": "pio run -t nobuild -t factory_flash -e ${command:platformio-ide.activeEnvironment}" + } + ] + }, + { + "text": "$(zap)", + "tooltip": "PlatformIO: Build and Upload", + "commands": "platformio-ide.upload" + }, + { + "text": "$(flame)", + "tooltip": "PlatformIO: Build, Erase and Upload", + "commands": [ + { + "id": "platformio-ide.runPIOCoreCommand", + "args": "pio run -t erase_upload -e ${command:platformio-ide.activeEnvironment}" + } + ] + }, + { + "text": "$(error)", + "tooltip": "PlatformIO: Erase Flash", + "commands": [ + { + "id": "platformio-ide.runPIOCoreCommand", + "args": "pio run -t nobuild -t erase -e ${command:platformio-ide.activeEnvironment}" + } + ] + }, + { + "text": "$(arrow-right)", + "tooltip": "PlatformIO: Upload and Monitor", + "commands": "platformio-ide.uploadAndMonitor" + }, + { + "text": "$(device-desktop)", + "tooltip": "PlatformIO: Serial Monitor", + "commands": "platformio-ide.serialMonitor" + }, + { + "text": "$(terminal)", + "tooltip": "PlatformIO: New Terminal", + "commands": "platformio-ide.newTerminal" + }, + { + "text": "$(refresh)", + "tooltip": "PlatformIO: Rebuild IntelliSense Index", + "commands": "platformio-ide.rebuildProjectIndex" + } + ] + } diff --git a/BUILDS.md b/BUILDS.md index e5dadfaa6..5f4102b85 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -123,6 +123,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_LM75AD | - | - / x | - | x | - | - | | USE_APDS9960 | - | - / - | - | - | - | - | | USE_MCP230xx | - | - / - | - | - | - | - | +| USE_MCP23XXX_DRV | - | - / - | - | - | - | - | | USE_PCA9632 | - | - / - | - | - | - | - | | USE_PCA9685 | - | - / - | - | - | - | - | | USE_MPR121 | - | - / - | - | - | - | - | @@ -143,6 +144,9 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_CHIRP | - | - / - | - | - | - | - | | USE_PAJ7620 | - | - / - | - | - | - | - | | USE_PCF8574 | - | - / - | - | - | - | - | +| USE_PMSA003I | - | - / - | - | - | - | - | +| USE_LOX_O2 | - | - / x | - | x | - | - | +| USE_GDK101 | - | - / - | - | - | - | - | | | | | | | | | | Feature or Sensor | l | t | k | s | i | d | Remarks | USE_HIH6 | - | - / x | - | x | - | - | diff --git a/CHANGELOG.md b/CHANGELOG.md index 8537cae71..bfde3bd6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,94 @@ All notable changes to this project will be documented in this file. ## [Released] +## [12.5.0] 20230417 +- Release Peyton + +## [12.4.0.5] 20230417 +### Added +- Matter support for Light and Relays on ESP32 by Stephan Hadinger (#18320) +- ESP32 WIP support for 16 shutters using `#define USE_SHUTTER_ESP32` in addition to `USE_SHUTTER` by Stefan Bode (#18295) +- Berry `webserver.html_escape()` reusing the internal HTML escaping function +- Support for GDK101 gamma radiation sensor by Petr Novacek (#18390) + +### Changed +- ESP32 LVGL library from v8.3.5 to v8.3.6 (no functional change) + +### Fixed +- ESP32 ``Upload``, ``Upgrade``, ``WebGetConfig``, ``WebQuery`` and ``WebSend`` random HTTP(S) connection timeout set to 5 sec (commit 542eca3) +- ESP32 energy monitoring set StartTotalTime regression from v12.3.1.5 (#18385) + +## [12.4.0.4] 20230403 +### Added +- Matter support simple Relay on Apple Homekit by Stephan Hadinger (#18239) +- VSC Pio menu bar extensions by @Jason2866 (#18233) +- Command ``SwitchMode0`` to show or set all SwitchModes + +### Changed +- Support for multiple PCF8574 as switch/button/relay if enabled with `#define USE_PCF8574` and `#define USE_PCF8574_MODE2` + +## [12.4.0.3] 20230322 +### Added +- Support for PMSA003I Air Quality Sensor by Jean-Pierre Deschamps (#18214) +- Support for DingTian virtual switch/button/relay (#18223) +- Berry add `mdns.remove_service()` + +### Fixed +- Refactor energy monitoring reducing stack usage and solve inherent exceptions and watchdogs (#18164) +- Berry fix `tasmota.get_power(index)` + +## [12.4.0.2] 20230317 +### Added +- Support for multiple MCP23008 as switch/button/relay if enabled with `#define USE_MCP23XXX_DRV` +- Support for multiple PCF8574 as switch/button/relay +- Extended Tariff command for forced tariff (#18080) +- Berry support for Tensorflow Lite (TFL) by Christiaan Baars (#18119) +- Zigbee send Tuya 'magic spell' to unlock devices when pairing (#18144) +- Berry `webclient` `set_follow_redirects(bool)` +- Berry `webclient` `collect_headers()` and `set_headers` +- Display TM1650 commands like TM1637 (#18109) +- Berry add `web_get_arg` event to drivers when `FUNC_WEB_GET_ARG` event is processed +- Support for reset settings on filesystem + +### Breaking Changed +- Shelly Pro 4PM using standard MCP23xxx driver and needs one time Auto-Configuration + +### Changed +- Refactored Berry rule engine and support for arrays +- ESP32 LVGL library from v8.3.3 to v8.3.5 (no functional change) +- Removed absolute url from filesystem (#18148) +- ``UrlFetch`` now follows redirects + +### Fixed +- TuyaMcu v1 sequence fix (#17625) +- TuyaMcu v1 timer integer overflow (#18048) +- PZEM energy monitor stabilize period on larger configs (#18103) +- Rule topic comparison (#18144) +- ESP32 energy period shows kWh value instead of Wh regression from v12.3.1.5 (#15856) + +## [12.4.0.1] 20230301 +### Added +- Matter read/write and commands (#18000) +- Matter subscriptions (#18017, #18018) +- Matter multi-fabric (#18019) +- Support for multiple MCP23017/MCP23S17 as switch/button/relay +- NTP time request from gateway (#17984) + +### Changed +- ADC Range oversample from 2 to 32 (#17975) +- ESP32 Framework (Core) from v2.0.6 to v2.0.7 +- Move #define OTA_URL from user_config.h to board files for better inital support (#18008) +- Increase number of (virtual)relays and (virtual)buttons to 32 +- LibTeleinfo from v1.1.3 to v1.1.5 (#18050) + +### Fixed +- SEN5X floats and units (#17961) +- Energytotals cannot be set to negative values (#17965) +- Undocumented support for non-sequential buttons and switches (#17967) +- SR04 driver single pin ultrasonic sensor detection (#17966) +- IR panasonic protocol regression from v12.0.2.4 (#18013) +- EnergyTotal divided twice during minimal upgrade step regression from v12.3.1.3 (#18024) + ## [12.4.0] 20230216 - Release Peter diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md index 9e5b35411..2c8374b59 100644 --- a/CODE_OWNERS.md +++ b/CODE_OWNERS.md @@ -76,6 +76,9 @@ In addition to @arendst the following code is mainly owned by: | xdrv_62_improv | @arendst | xdrv_63_modbus_bridge | @jeroenst | xdrv_64_pca9632 | Pascal Heinrich +| xdrv_65_tuyamcubr | David Gwynne +| xdrv_66_tm1638 | @arendst +| xdrv_67_mcp23xxx | @arendst | | | xdrv_79_esp32_ble | @staars, @btsimonh | xdrv_81_esp32_webcam | @gemu, @philrich @@ -120,7 +123,7 @@ In addition to @arendst the following code is mainly owned by: | xsns_25 | | xsns_26_lm75ad | Andre Thomas | xsns_27_apds9960 | Shawn Hymel -| xsns_28_tm1638 | @arendst +| xsns_28 | | xsns_29_mcp230xx | Andre Thomas | xsns_30_mpr121 | Rene 'Renne' Bartsch | xsns_31_ccs811 | Gerhard Mutz @@ -199,6 +202,9 @@ In addition to @arendst the following code is mainly owned by: | xsns_101_hmc5883l | Andreas Achtzehn | xsns_102_ld2410 | @arendst | xsns_103_sen5x | @tyeth +| xsns_104_pmsa003i | Jean-Pierre Deschamps +| xsns_105_lox_o2 | @ACE1046 +| xsns_106_gdk101 | @Szewcson | | | Libraries | | | @@ -206,6 +212,7 @@ In addition to @arendst the following code is mainly owned by: | ext-printf | @s-hadinger | jsmn | @s-hadinger | unishox | @s-hadinger +| matter | @s-hadinger | | | PlatformIO | | | diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 86090c403..994490ddb 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -6,109 +6,112 @@ Using command ``I2cDriver`` individual drivers can be enabled or disabled at run ## Supported I2C devices The following table lists the supported I2C devices -Index | Define | Driver | Device | Address(es) | Description -------|---------------------|----------|----------|-------------|----------------------------------------------- - 1 | USE_PCA9685 | xdrv_15 | PCA9685 | 0x40 - 0x47 | 16-channel 12-bit pwm driver +Index | Define | Driver | Device | Address(es) | Description +------|---------------------|---------|----------|-------------|----------------------------------------------- + 1 | USE_PCA9685 | xdrv_15 | PCA9685 | 0x40 - 0x47 | 16-channel 12-bit pwm driver 2 | USE_PCF8574 | xdrv_28 | PCF8574 | 0x20 - 0x26 | 8-bit I/O expander (address range overridable) 2 | USE_PCF8574 | xdrv_28 | PCF8574A | 0x39 - 0x3F | 8-bit I/O expander (address range overridable) - 3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | LCD display - 4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | Oled display - 5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | 8x8 led matrix - 6 | USE_DISPLAY_SH1106 | xdsp_07 | SH1106 | 0x3C - 0x3D | Oled display - 7 | USE_ADE7953 | xnrg_07 | ADE7953 | 0x38 | Energy monitor - 8 | USE_SHT | xsns_07 | SHT1X | Any | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | HTU21 | 0x40 | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | SI7013 | 0x40 | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | SI7020 | 0x40 | Temperature and Humidity sensor - 9 | USE_HTU | xsns_08 | SI7021 | 0x40 | Temperature and Humidity sensor - 10 | USE_BMP | xsns_09 | BMP085 | 0x76 - 0x77 | Pressure and temperature sensor - 10 | USE_BMP | xsns_09 | BMP180 | 0x76 - 0x77 | Pressure and temperature sensor - 10 | USE_BMP | xsns_09 | BMP280 | 0x76 - 0x77 | Pressure and temperature sensor - 10 | USE_BMP | xsns_09 | BME280 | 0x76 - 0x77 | Pressure, temperature and humidity sensor - 10 | USE_BMP | xsns_09 | BME680 | 0x76 - 0x77 | Pressure, temperature, humidity and gas sensor - 11 | USE_BH1750 | xsns_10 | BH1750 | 0x23, 0x5C | Ambient light intensity sensor - 12 | USE_VEML6070 | xsns_11 | VEML6070 | 0x38 - 0x39 | Ultra violet light intensity sensor - 13 | USE_ADS1115 | xsns_12 | ADS1115 | 0x48 - 0x4B | 4-channel 16-bit A/D converter - 14 | USE_INA219 | xsns_13 | INA219 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor - 15 | USE_SHT3X | xsns_14 | SHT3X | 0x44 - 0x45 | Temperature and Humidity sensor - 15 | USE_SHT3X | xsns_14 | SHT4X | 0x44 - 0x45 | Temperature and Humidity sensor - 15 | USE_SHT3X | xsns_14 | SHTCX | 0x70 | Temperature and Humidity sensor - 16 | USE_TSL2561 | xsns_16 | TSL2561 | 0x29, 0x39, 0x49 | Light intensity sensor - 17 | USE_MGS | xsns_19 | Grove | 0x04 | Multichannel gas sensor - 18 | USE_SGP30 | xsns_21 | SGP30 | 0x58 | Gas (TVOC) and air quality sensor - 19 | USE_SI1145 | xsns_24 | SI1145 | 0x60 | Ultra violet index and light sensor - 19 | USE_SI1145 | xsns_24 | SI1146 | 0x60 | Ultra violet index and light sensor - 19 | USE_SI1145 | xsns_24 | SI1147 | 0x60 | Ultra violet index and light sensor - 20 | USE_LM75AD | xsns_26 | LM75AD | 0x48 - 0x4F | Temperature sensor - 21 | USE_APDS9960 | xsns_27 | APDS9960 | 0x39 | Proximity ambient light RGB and gesture sensor - 22 | USE_MCP230xx | xsns_29 | MCP23008 | 0x20 - 0x26 | 8-bit I/O expander - 22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander - 23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor - 24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor + 3 | USE_DISPLAY_LCD | xdsp_01 | | 0x27, 0x3F | LCD display + 4 | USE_DISPLAY_SSD1306 | xdsp_02 | SSD1306 | 0x3C - 0x3D | Oled display + 5 | USE_DISPLAY_MATRIX | xdsp_03 | HT16K33 | 0x70 - 0x77 | 8x8 led matrix + 6 | USE_DISPLAY_SH1106 | xdsp_07 | SH1106 | 0x3C - 0x3D | Oled display + 7 | USE_ADE7953 | xnrg_07 | ADE7953 | 0x38 | Energy monitor + 8 | USE_SHT | xsns_07 | SHT1X | Any | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | HTU21 | 0x40 | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | SI7013 | 0x40 | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | SI7020 | 0x40 | Temperature and Humidity sensor + 9 | USE_HTU | xsns_08 | SI7021 | 0x40 | Temperature and Humidity sensor + 10 | USE_BMP | xsns_09 | BMP085 | 0x76 - 0x77 | Pressure and temperature sensor + 10 | USE_BMP | xsns_09 | BMP180 | 0x76 - 0x77 | Pressure and temperature sensor + 10 | USE_BMP | xsns_09 | BMP280 | 0x76 - 0x77 | Pressure and temperature sensor + 10 | USE_BMP | xsns_09 | BME280 | 0x76 - 0x77 | Pressure, temperature and humidity sensor + 10 | USE_BMP | xsns_09 | BME680 | 0x76 - 0x77 | Pressure, temperature, humidity and gas sensor + 11 | USE_BH1750 | xsns_10 | BH1750 | 0x23, 0x5C | Ambient light intensity sensor + 12 | USE_VEML6070 | xsns_11 | VEML6070 | 0x38 - 0x39 | Ultra violet light intensity sensor + 13 | USE_ADS1115 | xsns_12 | ADS1115 | 0x48 - 0x4B | 4-channel 16-bit A/D converter + 14 | USE_INA219 | xsns_13 | INA219 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor + 15 | USE_SHT3X | xsns_14 | SHT3X | 0x44 - 0x45 | Temperature and Humidity sensor + 15 | USE_SHT3X | xsns_14 | SHT4X | 0x44 - 0x45 | Temperature and Humidity sensor + 15 | USE_SHT3X | xsns_14 | SHTCX | 0x70 | Temperature and Humidity sensor + 16 | USE_TSL2561 | xsns_16 | TSL2561 | 0x29, 0x39, 0x49 | Light intensity sensor + 17 | USE_MGS | xsns_19 | Grove | 0x04 | Multichannel gas sensor + 18 | USE_SGP30 | xsns_21 | SGP30 | 0x58 | Gas (TVOC) and air quality sensor + 19 | USE_SI1145 | xsns_24 | SI1145 | 0x60 | Ultra violet index and light sensor + 19 | USE_SI1145 | xsns_24 | SI1146 | 0x60 | Ultra violet index and light sensor + 19 | USE_SI1145 | xsns_24 | SI1147 | 0x60 | Ultra violet index and light sensor + 20 | USE_LM75AD | xsns_26 | LM75AD | 0x48 - 0x4F | Temperature sensor + 21 | USE_APDS9960 | xsns_27 | APDS9960 | 0x39 | Proximity ambient light RGB and gesture sensor + 22 | USE_MCP230xx | xsns_29 | MCP23008 | 0x20 - 0x26 | 8-bit I/O expander + 22 | USE_MCP230xx | xsns_29 | MCP23017 | 0x20 - 0x26 | 16-bit I/O expander + 23 | USE_MPR121 | xsns_30 | MPR121 | 0x5A - 0x5D | Proximity capacitive touch sensor + 24 | USE_CCS811 | xsns_31 | CCS811 | 0x5A | Gas (TVOC) and air quality sensor 24' | USE_CCS811_V2 | xsns_31 | CCS811 | 0x5A - 0x5B | Gas (TVOC) and air quality sensor - 25 | USE_MPU6050 | xsns_32 | MPU6050 | 0x68 - 0x69 | 3-axis gyroscope and temperature sensor - 26 | USE_DS3231 | xsns_33 | DS3231 | 0x68 | Real time clock - 27 | USE_MGC3130 | xsns_36 | MGC3130 | 0x42 | Electric field sensor - 28 | USE_MAX44009 | xsns_41 | MAX44009 | 0x4A - 0x4B | Ambient light intensity sensor - 29 | USE_SCD30 | xsns_42 | SCD30 | 0x61 | CO2 sensor - 30 | USE_SPS30 | xsns_44 | SPS30 | 0x69 | Particle sensor - 31 | USE_VL53L0X | xsns_45 | VL53L0X | 0x29 | Time-of-flight (ToF) distance sensor - 32 | USE_MLX90614 | xsns_46 | MLX90614 | 0x5A | Infra red temperature sensor - 33 | USE_CHIRP | xsns_48 | CHIRP | 0x20 | Soil moisture sensor - 34 | USE_PAJ7620 | xsns_50 | PAJ7620 | 0x73 | Gesture sensor - 35 | USE_INA226 | xsns_54 | INA226 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor - 36 | USE_HIH6 | xsns_55 | HIH6130 | 0x27 | Temperature and Humidity sensor - 37 | USE_24C256 | xdrv_10 | 24C256 | 0x50 | Scripter EEPROM storage - 38 | USE_DISPLAY_ILI9488 | xdsp_08 | FT6236 | 0x38 | Touch panel controller - 39 | USE_DISPLAY_RA8876 | xdsp_10 | FT5316 | 0x38 | Touch panel controller + 25 | USE_MPU6050 | xsns_32 | MPU6050 | 0x68 - 0x69 | 3-axis gyroscope and temperature sensor + 26 | USE_DS3231 | xsns_33 | DS3231 | 0x68 | Real time clock + 27 | USE_MGC3130 | xsns_36 | MGC3130 | 0x42 | Electric field sensor + 28 | USE_MAX44009 | xsns_41 | MAX44009 | 0x4A - 0x4B | Ambient light intensity sensor + 29 | USE_SCD30 | xsns_42 | SCD30 | 0x61 | CO2 sensor + 30 | USE_SPS30 | xsns_44 | SPS30 | 0x69 | Particle sensor + 31 | USE_VL53L0X | xsns_45 | VL53L0X | 0x29 | Time-of-flight (ToF) distance sensor + 32 | USE_MLX90614 | xsns_46 | MLX90614 | 0x5A | Infra red temperature sensor + 33 | USE_CHIRP | xsns_48 | CHIRP | 0x20 | Soil moisture sensor + 34 | USE_PAJ7620 | xsns_50 | PAJ7620 | 0x73 | Gesture sensor + 35 | USE_INA226 | xsns_54 | INA226 | 0x40 - 0x41, 0x44 - 0x45 | Low voltage current sensor + 36 | USE_HIH6 | xsns_55 | HIH6130 | 0x27 | Temperature and Humidity sensor + 37 | USE_24C256 | xdrv_10 | 24C256 | 0x50 | Scripter EEPROM storage + 38 | USE_DISPLAY_ILI9488 | xdsp_08 | FT6236 | 0x38 | Touch panel controller + 39 | USE_DISPLAY_RA8876 | xdsp_10 | FT5316 | 0x38 | Touch panel controller 40 | USE_TSL2591 | xsns_57 | TSL2591 | 0x29 | Light intensity sensor - 41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor - 42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor - 42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor - 43 | USE_AHT1x | xsns_63 | AHT10/15 | 0x38 - 0x39 | Temperature and humidity sensor - 43 | USE_AHT2x | xsns_63 | AHT20 | 0x38 | Temperature and humidity sensor - 43 | USE_AHT2x | xsns_63 | AM2301B | 0x38 | Temperature and humidity sensor - 44 | USE_WEMOS_MOTOR_V1 | xdrv_34 | | 0x2D - 0x30 | WEMOS motor shield v1.0.0 (6612FNG) - 45 | USE_HDC1080 | xsns_65 | HDC1080 | 0x40 | Temperature and Humidity sensor - 46 | USE_IAQ | xsns_66 | IAQ | 0x5a | Air quality sensor - 47 | USE_DISPLAY_SEVENSEG| xdsp_11 | HT16K33 | 0x70 - 0x77 | Seven segment LED - 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor - 49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor - 50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor - 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor - 52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor - 53 | USE_MLX90640 | xdrv_43 | MLX90640 | 0x33 | IR array temperature sensor - 54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor - 55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH sensor - 55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP sensor - 55 | USE_EZORTD | xsns_78 | EZORTD | 0x61 - 0x70 | Temperature sensor - 55 | USE_EZOHUM | xsns_78 | EZOHUM | 0x61 - 0x70 | Humidity sensor - 55 | USE_EZOEC | xsns_78 | EZOEC | 0x61 - 0x70 | Electric conductivity sensor - 55 | USE_EZOCO2 | xsns_78 | EZOCO2 | 0x61 - 0x70 | CO2 sensor - 55 | USE_EZOO2 | xsns_78 | EZOO2 | 0x61 - 0x70 | O2 sensor - 55 | USE_EZOPRS | xsns_78 | EZOPRS | 0x61 - 0x70 | Pressure sensor - 55 | USE_EZOFLO | xsns_78 | EZOFLO | 0x61 - 0x70 | Flow meter sensor - 55 | USE_EZODO | xsns_78 | EZODO | 0x61 - 0x70 | Disolved Oxygen sensor - 55 | USE_EZORGB | xsns_78 | EZORGB | 0x61 - 0x70 | Color sensor - 55 | USE_EZOPMP | xsns_78 | EZOPMP | 0x61 - 0x70 | Peristaltic Pump - 56 | USE_SEESAW_SOIL | xsns_81 | SEESOIL | 0x36 - 0x39 | Adafruit seesaw soil moisture sensor - 57 | USE_TOF10120 | xsns_84 | TOF10120 | 0x52 | Time-of-flight (ToF) distance sensor - 58 | USE_MPU_ACCEL | xsns_85 | MPU_ACCEL| 0x68 | MPU6886/MPU9250 6-axis MotionTracking sensor from M5Stac k - 59 | USE_BM8563 | xdrv_56 | BM8563 | 0x51 | BM8563 RTC from M5Stack - 60 | USE_AM2320 | xsns_88 | AM2320 | 0x5C | Temperature and Humidity sensor - 61 | USE_T67XX | xsns_89 | T67XX | 0x15 | CO2 sensor - 62 | USE_SCD40 | xsns_92 | SCD40 | 0x62 | CO2 sensor Sensirion SCD40/SCD41 - 63 | USE_HM330X | xsns_93 | HM330X | 0x40 | Particule sensor - 64 | USE_HDC2010 | xsns_94 | HDC2010 | 0x40 | Temperature and Humidity sensor - 65 | USE_ADE7880 | xnrg_23 | ADE7880 | 0x38 | Energy monitor - 66 | USE_PCF85363 | xsns_99 | PCF85363 | 0x51 | Real time clock - 67 | USE_DS3502 | xdrv_61 | DS3502 | 0x28 - 0x2B | Digital potentiometer - 68 | USE_HYT | xsns_97 | HYTxxx | 0x28 | Temperature and Humidity sensor - 69 | USE_SGP40 | xsns_98 | SGP40 | 0x59 | Gas (TVOC) and air quality - 70 | USE_LUXV30B | xsns_99 | LUXV30B | 0x4A | DFRobot SEN0390 V30B lux sensor + 41 | USE_DHT12 | xsns_58 | DHT12 | 0x5C | Temperature and humidity sensor + 42 | USE_DS1624 | xsns_59 | DS1621 | 0x48 - 0x4F | Temperature sensor + 42 | USE_DS1624 | xsns_59 | DS1624 | 0x48 - 0x4F | Temperature sensor + 43 | USE_AHT1x | xsns_63 | AHT10/15 | 0x38 - 0x39 | Temperature and humidity sensor + 43 | USE_AHT2x | xsns_63 | AHT20 | 0x38 | Temperature and humidity sensor + 43 | USE_AHT2x | xsns_63 | AM2301B | 0x38 | Temperature and humidity sensor + 44 | USE_WEMOS_MOTOR_V1 | xdrv_34 | | 0x2D - 0x30 | WEMOS motor shield v1.0.0 (6612FNG) + 45 | USE_HDC1080 | xsns_65 | HDC1080 | 0x40 | Temperature and Humidity sensor + 46 | USE_IAQ | xsns_66 | IAQ | 0x5a | Air quality sensor + 47 | USE_DISPLAY_SEVENSEG| xdsp_11 | HT16K33 | 0x70 - 0x77 | Seven segment LED + 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor + 49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor + 50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor + 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor + 52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor + 53 | USE_MLX90640 | xdrv_43 | MLX90640 | 0x33 | IR array temperature sensor + 54 | USE_VL53L1X | xsns_77 | VL53L1X | 0x29 | Time-of-flight (ToF) distance sensor + 55 | USE_EZOPH | xsns_78 | EZOPH | 0x61 - 0x70 | pH sensor + 55 | USE_EZOORP | xsns_78 | EZOORP | 0x61 - 0x70 | ORP sensor + 55 | USE_EZORTD | xsns_78 | EZORTD | 0x61 - 0x70 | Temperature sensor + 55 | USE_EZOHUM | xsns_78 | EZOHUM | 0x61 - 0x70 | Humidity sensor + 55 | USE_EZOEC | xsns_78 | EZOEC | 0x61 - 0x70 | Electric conductivity sensor + 55 | USE_EZOCO2 | xsns_78 | EZOCO2 | 0x61 - 0x70 | CO2 sensor + 55 | USE_EZOO2 | xsns_78 | EZOO2 | 0x61 - 0x70 | O2 sensor + 55 | USE_EZOPRS | xsns_78 | EZOPRS | 0x61 - 0x70 | Pressure sensor + 55 | USE_EZOFLO | xsns_78 | EZOFLO | 0x61 - 0x70 | Flow meter sensor + 55 | USE_EZODO | xsns_78 | EZODO | 0x61 - 0x70 | Disolved Oxygen sensor + 55 | USE_EZORGB | xsns_78 | EZORGB | 0x61 - 0x70 | Color sensor + 55 | USE_EZOPMP | xsns_78 | EZOPMP | 0x61 - 0x70 | Peristaltic Pump + 56 | USE_SEESAW_SOIL | xsns_81 | SEESOIL | 0x36 - 0x39 | Adafruit seesaw soil moisture sensor + 57 | USE_TOF10120 | xsns_84 | TOF10120 | 0x52 | Time-of-flight (ToF) distance sensor + 58 | USE_MPU_ACCEL | xsns_85 | MPU_ACCEL| 0x68 | MPU6886/MPU9250 6-axis MotionTracking sensor from M5Stack + 59 | USE_BM8563 | xdrv_56 | BM8563 | 0x51 | BM8563 RTC from M5Stack + 60 | USE_AM2320 | xsns_88 | AM2320 | 0x5C | Temperature and Humidity sensor + 61 | USE_T67XX | xsns_89 | T67XX | 0x15 | CO2 sensor + 62 | USE_SCD40 | xsns_92 | SCD40 | 0x62 | CO2 sensor Sensirion SCD40/SCD41 + 63 | USE_HM330X | xsns_93 | HM330X | 0x40 | Particule sensor + 64 | USE_HDC2010 | xsns_94 | HDC2010 | 0x40 | Temperature and Humidity sensor + 65 | USE_ADE7880 | xnrg_23 | ADE7880 | 0x38 | Energy monitor + 66 | USE_PCF85363 | xsns_99 | PCF85363 | 0x51 | Real time clock + 67 | USE_DS3502 | xdrv_61 | DS3502 | 0x28 - 0x2B | Digital potentiometer + 68 | USE_HYT | xsns_97 | HYTxxx | 0x28 | Temperature and Humidity sensor + 69 | USE_SGP40 | xsns_98 | SGP40 | 0x59 | Gas (TVOC) and air quality + 70 | USE_LUXV30B | xsns_99 | LUXV30B | 0x4A | DFRobot SEN0390 V30B lux sensor 71 | USE_QMC5883L | xsns_33 | QMC5883L | 0x0D | Magnetic Field Sensor 72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor 73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor 74 | USE_DISPLAY_TM1650 | xdsp_20 | TM1650 | 0x24 - 0x27, 0x34 - 0x37 | Four-digit seven-segment LED controller 75 | USE_PCA9632 | xdrv_64 | PCA9632 | 0x60 | 4-channel 4-bit pwm driver 76 | USE_SEN5X | xsns_103 | SEN5X | 0x69 | Gas (VOC/NOx index) and air quality (PPM <1,<2.5,<4,<10) + 77 | USE_MCP23XXX_DRV | xdrv_67 | MCP23x17 | 0x20 - 0x26 | 16-bit I/O expander as virtual button/switch/relay + 78 | USE_PMSA003I | xsns_104 | PMSA003I | 0x12 | PM2.5 Air Quality Sensor with I2C Interface + 79 | USE_GDK101 | xsns_106 | GDK101 | 0x18 - 0x1B | Gamma Radiation Sensor \ No newline at end of file diff --git a/README.md b/README.md index ed2169f14..e41499fbf 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ See [CHANGELOG.md](CHANGELOG.md) for detailed change information. Unless your Tasmota powered device exhibits a problem or lacks a feature that you need, leave your device alone - it works so don’t make unnecessary changes! If the release version (i.e., the master branch) exhibits unexpected behaviour for your device and configuration, you should upgrade to the latest development version instead to see if your problem is resolved as some bugs in previous releases or development builds may already have been resolved. -Every commit made to the development branch, which is compiling successfuly, will post new binary files at http://ota.tasmota.com/tasmota/ (this web address can be used for OTA updates too). It is important to note that these binaries are based on the current development codebase. These commits are tested as much as is possible and are typically quite stable. However, it is infeasible to test on the hundreds of different types of devices with all the available configuration options permitted. +Every commit made to the development branch, which is compiling successfully, will post new binary files at http://ota.tasmota.com/tasmota/ (this web address can be used for OTA updates too). It is important to note that these binaries are based on the current development codebase. These commits are tested as much as is possible and are typically quite stable. However, it is infeasible to test on the hundreds of different types of devices with all the available configuration options permitted. Note that there is a chance, as with any upgrade, that the device may not function as expected. You must always account for the possibility that you may need to flash the device via the serial programming interface if the OTA upgrade fails. Even with the master release, you should always attempt to test the device or a similar prototype before upgrading a device which is in production or is hard to reach. And, as always, make a backup of the device configuration before beginning any firmware update. @@ -172,4 +172,4 @@ People helping to keep the show on the road: ## License -This program is licensed under GPL-3.0 +This program is licensed under GPL-3.0-only diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7fa36024e..9b626657f 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.6**. +This release will be supported from ESP32/Arduino library Core version **2.0.7**. -Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.6 have been removed. +Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.7 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-12.4.0 +- http://ota.tasmota.com/tasmota/release-12.5.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.6**. +The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.7**. - **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-12.4.0 +- https://ota.tasmota.com/tasmota32/release-12.5.0 The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin`` @@ -110,52 +110,47 @@ 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 v12.4.0 Peter +## Changelog v12.5.0 Peyton ### Added -- Command ``DhtDelay ,`` to allow user control over high and low delay in microseconds [#17944](https://github.com/arendst/Tasmota/issues/17944) -- Support for up to 3 (ESP8266) or 8 (ESP32) phase modbus energy monitoring device using generic Energy Modbus driver -- Support for RGB displays [#17414](https://github.com/arendst/Tasmota/issues/17414) -- Support for IPv6 DNS records (AAAA) and IPv6 ``Ping`` for ESP32 and ESP8266 [#17417](https://github.com/arendst/Tasmota/issues/17417) -- Support for IPv6 only networks on Ethernet (not yet Wifi) -- Support for TM1650 display as used in some clocks by Stefan Oskamp [#17594](https://github.com/arendst/Tasmota/issues/17594) -- Support for PCA9632 4-channel 8-bit PWM driver as light driver by Pascal Heinrich [#17557](https://github.com/arendst/Tasmota/issues/17557) -- support for SEN5X gas and air quality sensor by Tyeth Gundry [#17736](https://github.com/arendst/Tasmota/issues/17736) -- Basic support for Shelly Pro 4PM -- Berry support for ``crypto.SHA256`` [#17430](https://github.com/arendst/Tasmota/issues/17430) -- Berry crypto add ``EC_P256`` and ``PBKDF2_HMAC_SHA256`` algorithms required by Matter protocol [#17473](https://github.com/arendst/Tasmota/issues/17473) -- Berry crypto add ``random`` to generate series of random bytes -- Berry crypto add ``HKDF_HMAC_SHA256`` -- Berry crypto add ``SPAKE2P_Matter`` for Matter support -- Berry add ``mdns`` advanced features and query -- Berry `int64.fromstring()` to convert a string to an int64 [#17953](https://github.com/arendst/Tasmota/issues/17953) -- ESP32 command ``EnergyCols 1..8`` to change number of GUI columns -- ESP32 command ``EnergyDisplay 1..3`` to change GUI column presentation -- ESP32 support for eigth energy phases/channels -- ESP32 support for BMPxxx sensors on two I2C busses [#17643](https://github.com/arendst/Tasmota/issues/17643) -- ESP32 support for Biomine BioPDU 625x12 [#17857](https://github.com/arendst/Tasmota/issues/17857) -- ESP32 preliminary support for Matter protocol, milestone 1 (commissioning) by Stephan Hadinger +- Command ``SwitchMode0`` to show or set all SwitchModes +- Support for multiple MCP23008/MCP23017/MCP23S17 as switch/button/relay if enabled with `#define USE_MCP23XXX_DRV` +- Support for multiple PCF8574 as switch/button/relay if enabled with `#define USE_PCF8574` and `#define USE_PCF8574_MODE2` +- Support for PMSA003I Air Quality Sensor by Jean-Pierre Deschamps [#18214](https://github.com/arendst/Tasmota/issues/18214) +- Support for DingTian virtual switch/button/relay [#18223](https://github.com/arendst/Tasmota/issues/18223) +- Support for GDK101 gamma radiation sensor by Petr Novacek [#18390](https://github.com/arendst/Tasmota/issues/18390) +- NTP time request from gateway [#17984](https://github.com/arendst/Tasmota/issues/17984) +- Extended Tariff command for forced tariff [#18080](https://github.com/arendst/Tasmota/issues/18080) +- Display TM1650 commands like TM1637 [#18109](https://github.com/arendst/Tasmota/issues/18109) +- VSC Pio menu bar extensions by @Jason2866 [#18233](https://github.com/arendst/Tasmota/issues/18233) +- Zigbee send Tuya 'magic spell' to unlock devices when pairing [#18144](https://github.com/arendst/Tasmota/issues/18144) +- ESP32 WIP support for 16 shutters using `#define USE_SHUTTER_ESP32` in addition to `USE_SHUTTER` by Stefan Bode [#18295](https://github.com/arendst/Tasmota/issues/18295) +- Berry support for Tensorflow Lite (TFL) by Christiaan Baars [#18119](https://github.com/arendst/Tasmota/issues/18119) +- Berry `webclient` features +- Matter support for Light and Relays by Stephan Hadinger [#18320](https://github.com/arendst/Tasmota/issues/18320) ### Breaking Changed -- TM1638 button and led support are handled as virtual switches and relays [#11031](https://github.com/arendst/Tasmota/issues/11031) +- Shelly Pro 4PM using standard MCP23xxx driver and needs one time Auto-Configuration ### Changed -- Dht driver from v6 to v7 -- ESP32 Framework (Core) from v2.0.5.3 to v2.0.6 (IPv6 support) -- Energy totals max supported value from +/-21474.83647 to +/-2147483.647 kWh -- Removed delays in TasmotaSerial and TasmotaModbus Tx enable switching -- Keep webserver enabled on command ``upload`` -- Better support for virtual buttons and switches up to a total of 28 -- TuyaMcu support of virtual switches -- Increase rule event buffer from 100 to 256 characters [#16943](https://github.com/arendst/Tasmota/issues/16943) -- Tasmota OTA scripts now support both unzipped and gzipped file uploads [#17378](https://github.com/arendst/Tasmota/issues/17378) -- LVGL allow access to `lv.LAYOUT_GRID` and `lv.LAYOUT_FLEX` [#17948](https://github.com/arendst/Tasmota/issues/17948) +- ESP32 Framework (Core) from v2.0.6 to v2.0.7 +- ESP32 LVGL library from v8.3.3 to v8.3.6 (no functional change) +- LibTeleinfo from v1.1.3 to v1.1.5 [#18050](https://github.com/arendst/Tasmota/issues/18050) +- Increase number of (virtual)relays and (virtual)buttons to 32 +- ADC Range oversample from 2 to 32 [#17975](https://github.com/arendst/Tasmota/issues/17975) +- Move #define OTA_URL from user_config.h to board files for better inital support [#18008](https://github.com/arendst/Tasmota/issues/18008) +- Removed absolute url from filesystem [#18148](https://github.com/arendst/Tasmota/issues/18148) ### Fixed -- Modbus transmit enable GPIO enabled once during write buffer -- Energy dummy switched voltage and power regression from v12.2.0.2 -- Shutter default motorstop set to 0 [#17403](https://github.com/arendst/Tasmota/issues/17403) -- Shutter default tilt configuration [#17484](https://github.com/arendst/Tasmota/issues/17484) -- Orno WE517 modbus serial config 8E1 setting [#17545](https://github.com/arendst/Tasmota/issues/17545) -- Rename ``tasmota4M.bin`` to ``tasmota-4M.bin`` to solve use of ``tasmota-minimal.bin`` [#17674](https://github.com/arendst/Tasmota/issues/17674) -- ESP8266 set GPIO's to input on power on fixing relay spikes [#17531](https://github.com/arendst/Tasmota/issues/17531) -- ESP8266 TLS SNI which would prevent AWS IoT connection [#17936](https://github.com/arendst/Tasmota/issues/17936) +- TuyaMcu v1 sequence fix [#17625](https://github.com/arendst/Tasmota/issues/17625) +- SEN5X floats and units [#17961](https://github.com/arendst/Tasmota/issues/17961) +- Energytotals cannot be set to negative values [#17965](https://github.com/arendst/Tasmota/issues/17965) +- SR04 driver single pin ultrasonic sensor detection [#17966](https://github.com/arendst/Tasmota/issues/17966) +- IR panasonic protocol regression from v12.0.2.4 [#18013](https://github.com/arendst/Tasmota/issues/18013) +- EnergyTotal divided twice during minimal upgrade step regression from v12.3.1.3 [#18024](https://github.com/arendst/Tasmota/issues/18024) +- TuyaMcu v1 timer integer overflow [#18048](https://github.com/arendst/Tasmota/issues/18048) +- PZEM energy monitor stabilize period on larger configs [#18103](https://github.com/arendst/Tasmota/issues/18103) +- Rule topic comparison [#18144](https://github.com/arendst/Tasmota/issues/18144) +- Refactor energy monitoring reducing stack usage and solve inherent exceptions and watchdogs [#18164](https://github.com/arendst/Tasmota/issues/18164) +- ESP32 ``Upload``, ``Upgrade``, ``WebGetConfig``, ``WebQuery`` and ``WebSend`` random HTTP(S) connection timeout set to 5 sec (commit 542eca3) +- ESP32 energy period shows kWh value instead of Wh regression from v12.3.1.5 [#15856](https://github.com/arendst/Tasmota/issues/15856) +- ESP32 energy monitoring set StartTotalTime regression from v12.3.1.5 [#18385](https://github.com/arendst/Tasmota/issues/18385) diff --git a/TEMPLATES.md b/TEMPLATES.md index 440eb0942..739cd6a0e 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -5,7 +5,7 @@ # Templates -Find below the available templates as of February 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 April 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) ## Adapter Board ``` @@ -220,6 +220,7 @@ LoraTap In-Wall {"NAME":"SC500W","GPIO":[0,0,0,576,160,161,0,0,224, LoraTap In-Wall {"NAME":"SC511WSC","GPIO":[0,1,0,320,32,34,0,0,224,33,226,225,0,0],"FLAG":0,"BASE":18} MS-108 In-Wall {"NAME":"MS-108","GPIO":[0,0,0,0,161,160,0,0,224,0,225,0,0,0],"FLAG":0,"BASE":18} MS-108WR RF Curtain Module {"NAME":"MS-108WR","GPIO":[1,1,1,544,32,33,1,1,225,32,224,1,1,1],"FLAG":0,"BASE":18} +Nous {"NAME":" Smart WiFi Curtain Module L12T","GPIO":[1,160,1,161,225,224,1,1,544,1,32,1,1,1],"FLAG":0,"BASE":18} QS-WIFI-C01-RF {"NAME":"Shutter-QS-WIFI-C01","GPIO":[0,0,1,0,288,0,0,0,32,33,224,225,0,0],"FLAG":0,"BASE":18} ``` @@ -251,6 +252,7 @@ Zemismart Backlit {"NAME":"WF-CS01","GPIO":[544,227,289,34,226,161,0, ## DIN Relay ``` +CurrySmarter Power Monitoring 30A {"NAME":"30A Breaker","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} Ketotek Single Phase Energy Monitor {"NAME":"Ketotek KTEM06","GPIO":[0,2272,0,2304,0,0,0,0,0,0,320,0,32,0],"FLAG":0,"BASE":54} @@ -288,10 +290,12 @@ 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 CONNECT {"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} +Dasduino CONNECTPLUS {"NAME":"Dasduino CONNECT","GPIO":[1,1,1376,1,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18} 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} LC Technology MicroPython Maker {"NAME":"LC-ESP-Python","GPIO":[1,1,544,1,1,1,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18} LilyGO RGB LED Ring Encoder {"NAME":"T-Encoder","GPIO":[0,0,1,0,1,0,0,0,1,1,1,1,0,0,0,480,6212,0,0,0,0,449,450,448,0,0,0,0,0,0,0,0,3296,3264,32,0],"FLAG":0,"BASE":1,"CMND":"BuzzerPwm 1"} -LilyGO T7 v1.5 {"NAME":"LilyGO T7 V1.5","GPIO":[1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,544,0,0,0,1,0,1,1,1,0,0,0,0,0,1,1,4704,1,0,0,1],"FLAG":0,"BASE":1} +LilyGO T7 Mini32 V1.5 {"NAME":"LilyGO T7 V1.5","GPIO":[1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,544,0,0,0,1,0,1,1,1,0,0,0,0,0,1,1,4704,1,0,0,1],"FLAG":0,"BASE":1} LilyGO TTGO ESP32 Ethernet {"NAME":"T-Internet-POE v1.2","GPIO":[0,1,1,1,1,1,1,1,1,1,1,1,1,1,5600,1,0,1,1,5568,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1,"CMND":"EthType 0|EthClockMode 1|EthAddress 0"} M5Stack Atom Lite ESP32 {"NAME":"M5Stack Atom Lite","GPIO":[1,1,1,1,1,1,1,1,1056,1,1,1,1,1,1,1,0,1,1,1,0,1,640,1376,0,0,0,0,608,1,1,1,1,0,0,32],"FLAG":0,"BASE":1} M5Stack AtomU USB-A ESP32 "Not available" @@ -467,7 +471,7 @@ Wireless Tag 3.5" Touch {"NAME":"WT32-SC01","GPIO":[6210,1,1,1,1,1,0,0,1,70 ## Display Switch ``` -Lanbon L8 5 in 1 LCD Touch {"NAME":"Lanbon L8","GPIO":[0,0,0,0,0,992,0,0,224,0,225,0,0,0,1024,896,0,6624,6592,864,0,832,416,226,0,0,0,0,417,418,0,352,0,0,0,4736],"FLAG":0,"BASE":1} +Lanbon L8 5 in 1 LCD Touch {"NAME":"Lanbon L8","GPIO":[608,0,0,0,640,992,0,0,224,0,225,0,0,0,1024,736,0,800,768,704,6210,672,416,226,0,0,0,0,417,418,0,2688,0,0,0,0],"FLAG":0,"BASE":1} Sonoff NSPanel Touch {"NAME":"NSPanel","GPIO":[0,0,0,0,3872,0,0,0,0,0,32,0,0,0,0,225,0,480,224,1,0,0,0,33,0,0,0,0,0,0,0,0,0,0,4736,0],"FLAG":0,"BASE":1,"CMND":"ADCParam1 2,11200,10000,3950 | Sleep 0 | BuzzerPWM 1"} ``` @@ -590,6 +594,7 @@ Proscenic {"NAME":"Generic","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1 3DStar ESP IR Blaster xLR {"NAME":"3DS_IR Blaster_xLR","GPIO":[0,0,0,0,0,0,0,0,0,1088,0,1056,0,0],"FLAG":0,"BASE":18} A1 Universal Remote Control {"NAME":"A1 IR Controller","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62} AI Universal Remote {"NAME":"YTF IR Controller","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62} +AI Universal Remote Control {"NAME":"LQ-08","GPIO":[0,0,0,0,0,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62} Alfawise KS1 {"NAME":"KS1","GPIO":[1,1792,32,1824,32,1088,0,0,320,0,1056,0,0,4704],"FLAG":0,"BASE":62} Antsig Universal Remote Controller {"NAME":"Antsig Smart Wi-Fi IR","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62} Automate Things IR Bridge {"NAME":"AT-IRBR-1.0","GPIO":[0,0,0,0,1056,1088,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"Module 0"} @@ -689,6 +694,7 @@ RGB+CCT 12-24V {"NAME":"WS05","GPIO":[0,0,0,0,0,420,0,0,418,417,41 RGBW 12-24V {"NAME":"*WS04","GPIO":[0,0,0,0,0,0,0,0,417,418,416,419,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} Xunata Led Controller High Voltage 110/220V {"NAME":"KL-LED-WIFI-AC","GPIO":[0,0,0,0,0,0,0,0,0,416,0,0,0,0],"FLAG":0,"BASE":18} ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18} ``` @@ -801,6 +807,7 @@ Novostella UT88836 20W Flood {"NAME":"Novo 20W Flood","GPIO":[0,0,0,0,416,419,0 Nue Vision Care Desk Lamp {"NAME":"Nue Vision Desk Lamp VC18","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 21,3 | TuyaMCU 23,4"} Philips Wiz 24W LED White Batten {"NAME":"PHILIPS-wiz-24w","GPIO":[0,0,0,0,417,0,0,0,0,416,0,0,0,0],"FLAG":0,"BASE":18} Polycab Hohm Avenir 20W Batten {"NAME":"PolycabBatten","GPIO":[0,0,0,0,0,416,0,0,0,449,0,0,0,0],"FLAG":0,"BASE":18} +RGB Floor Lamp {"NAME":"Floor Lamp","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Sonoff {"NAME":"Sonoff BN-SZ","GPIO":[0,0,0,0,0,0,0,0,416,320,0,0,0,0],"FLAG":0,"BASE":22} Spotlight 9cm RGB+W 7W {"NAME":"Spotlight RGBW","GPIO":[0,0,0,0,0,0,0,0,0,3008,0,3040,0,0],"FLAG":0,"BASE":27} TCP WPAN Square 600X600mm 36W CCT Panel {"NAME":"TCPsmart LED Panel","GPIO":[0,0,0,0,0,416,0,0,0,449,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO92 1|DimmerRange 30,100"} @@ -838,6 +845,9 @@ Proscenic T21 Air Fryer {"NAME":"Proscenic T21","GPIO":[0,2272,0,2304,0,0,0 RainPoint Indoor Water Pump {"NAME":"RainPoint","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 81,107|TuyaMCU 12,109|TuyaMCU 11,1|TuyaMCU 82,104"} Sinilink PCIe Computer Remote {"NAME":"XY-WPCE","GPIO":[1,1,320,1,32,224,0,0,160,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO114 1 | SwitchMode1 2"} Sinilink USB Computer Remote {"NAME":"XY-WPCL","GPIO":[0,0,320,0,0,224,0,32,160,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO114 1 | Pulsetime 10 | SwitchMode1 2"} +Sinilink XY-Clock Clock Alarm Module {"NAME":"XY-Clock","GPIO":[288,0,289,0,0,416,32,33,608,640,0,0,34,0],"FLAG":0,"BASE":18} +Sunbeam LoftTec Electric Blanket {"NAME":"Sunbeam Heated Blanket","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Ulanzi Smart Pixel Clock {"NAME":"Ulanzi TC001","GPIO":[0,0,0,0,0,0,0,0,0,0,34,480,0,0,0,0,0,640,608,0,0,0,32,33,0,0,0,0,1376,0,4704,4768,0,0,0,0],"FLAG":0,"BASE":1} Xystec USB3.0 4 Port Hub {"NAME":"Xystec USB Hub","GPIO":[0,0,0,0,224,0,0,0,226,227,225,0,0,0],"FLAG":0,"BASE":18} ``` @@ -922,7 +932,9 @@ Kogan Energy Meter IP44 {"NAME":"Kogan Smart Sw IP44","GPIO":[32,0,0,0,2688 Konyks Pluviose 16A IP55 {"NAME":"Konyks Pluviose","GPIO":[32,0,0,0,0,0,0,0,224,288,0,0,0,0],"FLAG":0,"BASE":18} Koolertron {"NAME":"C168 Outdoor","GPIO":[0,32,0,320,2720,2656,0,0,224,2624,225,226,0,0],"FLAG":0,"BASE":18} Ledvance Smart+ 16A {"NAME":"LEDVANCE Smart Wifi Outdoor Plug","GPIO":[0,0,0,320,2688,2656,0,0,224,32,2624,0,0,0],"FLAG":0,"BASE":18} +Ledvance Smart+ Compact {"NAME":"LEDVANCE SMART+ Compact Outdoor Plug ","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} LSC Dual Socket {"NAME":"LSC NFL-022","GPIO":[0,0,0,0,320,32,0,0,0,224,225,0,0,0],"FLAG":0,"BASE":18} +LSC Dual Socket {"NAME":"LSC Outdoor Dual Socket","GPIO":[320,0,0,32,8673,8672,0,0,0,0,8674,0,8675,0],"FLAG":0,"BASE":18} Luminea 2 Outlet {"NAME":"Luminea","GPIO":[0,0,0,0,225,320,0,0,224,321,32,0,0,1],"FLAG":0,"BASE":18} Luminea NX-4458 {"NAME":"Luminea NX4458","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":65} Master {"NAME":"Master_IOT-EXTPLUG","GPIO":[32,1,0,1,1,0,0,0,224,288,0,0,0,0],"FLAG":0,"BASE":1} @@ -957,6 +969,7 @@ WiOn Yard Stake {"NAME":"WiOn 50053","GPIO":[0,0,320,0,0,0,0,0,0,32 WOOX R4051 {"NAME":"WOOX R4051","GPIO":[32,0,0,0,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":18} WOOX R4052 {"NAME":"WOOX R4052","GPIO":[32,0,0,0,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":18} Wyze {"NAME":"Wyze Plug Outdoor","GPIO":[0,0,0,0,0,576,0,0,0,0,0,224,321,7713,7712,320,0,0,0,0,0,2624,2656,2720,0,0,0,0,225,0,4704,0,0,0,0,0],"FLAG":0,"BASE":1} +XtendLan IP66 Double {"NAME":"XtendLan_ZAS4","GPIO":[32,0,0,0,0,225,33,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} ``` ## Plug @@ -1046,6 +1059,7 @@ Avatto OT08 {"NAME":"Avatto OT08","GPIO":[416,0,418,0,417,2720, Awow X5P {"NAME":"Awow","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} AWP02L-N {"NAME":"AWP02L-N","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} AzpenHome Smart {"NAME":"Socket2Me","GPIO":[288,1,1,1,225,1,0,0,224,1,32,1,1,0],"FLAG":0,"BASE":18} +Baco Smart Power Socket {"NAME":"Balco HE200021","GPIO":[0,0,0,32,2720,2656,0,0,2624,576,224,0,0,0],"FLAG":0,"BASE":52} Bagotte SK-EU-A01 {"NAME":"Bagotte SK-EU-A01","GPIO":[96,0,0,0,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":18} Bakibo Mini {"NAME":"SM300","GPIO":[320,0,576,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":59} Bakibo TP22Y {"NAME":"Bakibo TP22Y","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":52} @@ -1180,6 +1194,7 @@ GDTech {"NAME":"GDTech Model: MPV2RO-US","GPIO":[320,0,0,0 GDTech W-US001 {"NAME":"GDTech W-US001","GPIO":[1,32,1,1,1,1,0,0,1,320,224,1,1,4704],"FLAG":0,"BASE":18} GDTech W-US003 {"NAME":"W-US003","GPIO":[0,32,1,1,1,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} Geekbes YM-WS-1 {"NAME":"Office Test Pl","GPIO":[1,1,1,1,1,1,1,1,576,32,163,224,1,1],"FLAG":0,"BASE":18} +Geekome Enchufe Inteligente Chile {"NAME":"Geekhome PG01-CL10A_T","GPIO":[0,0,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":1} Geeni OUTDOOR {"NAME":"Geeni Outdoor","GPIO":[32,0,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} Geeni Spot {"NAME":"Geeni Spot","GPIO":[576,0,0,0,320,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Geeni Spot Glo {"NAME":"Geeni Glo","GPIO":[0,0,0,0,320,0,0,0,224,32,225,0,0,0],"FLAG":0,"BASE":18} @@ -1233,7 +1248,8 @@ HIPER IoT P05 {"NAME":"HIPER IoT P05","GPIO":[0,320,0,32,0,0,0,0, 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} -Hombli Socket Duo {"NAME":"HombliSocketDuo","GPIO":[33,0,0,0,0,0,0,0,0,544,224,225,32,0],"FLAG":0,"BASE":18} +Hombli Smart Socket EU {"NAME":"Hombli HBSS-0109","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18} +Hombli Socket Duo {"NAME":"Hombli HBSD-0109","GPIO":[33,0,0,0,0,0,0,0,0,544,224,225,32,0],"FLAG":0,"BASE":18} Homecube {"NAME":"Homecube SP1","GPIO":[0,321,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":55} HomeMate 16A Heavy Duty {"NAME":"HMLPG16","GPIO":[0,288,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18} Houzetek {"NAME":"AWP07L","GPIO":[320,0,0,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} @@ -1247,11 +1263,13 @@ Hyleton 314 {"NAME":"hyleton-314","GPIO":[321,0,320,0,0,0,0,0,0 Hyleton 315 {"NAME":"hyleton-315","GPIO":[0,0,0,0,321,320,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} Hyleton 317 {"NAME":"hyleton-317","GPIO":[320,0,321,0,322,0,0,0,0,64,0,224,0,0],"FLAG":0,"BASE":18} Hyleton HLT-311 {"NAME":"HLT-311","GPIO":[544,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} +Hyrican SmartPlug 16A {"NAME":"Hyrican TM-MP-EU02","GPIO":[0,0,0,32,2656,2624,0,0,224,2720,320,0,0,0],"FLAG":0,"BASE":18} iClever IC-BS08 {"NAME":"iClever BS08","GPIO":[0,0,0,0,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} iDIGITAL {"NAME":"Brilliant","GPIO":[0,0,0,0,288,0,0,0,224,64,0,0,0,0],"FLAG":0,"BASE":18} iGET Security {"NAME":"iGET Security DP16","GPIO":[320,1,576,1,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} Ihommate 16A {"NAME":"ZCH-02","GPIO":[0,0,0,32,2688,2656,0,0,2624,320,224,0,0,4704],"FLAG":0,"BASE":18} Infray 16A {"NAME":"AWP08L","GPIO":[32,0,288,0,0,0,0,0,0,0,0,224,0,4704],"FLAG":0,"BASE":18} +Insmart {"NAME":"INSMART SP1","GPIO":[320,1,321,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} Insmart WP5 {"NAME":"INSMART","GPIO":[0,0,448,0,0,0,0,0,0,160,0,224,0,0],"FLAG":0,"BASE":18} Intempo Home Euro 2-Pin {"NAME":"Intempo EE5010WHTSTKEU","GPIO":[0,0,0,32,0,2720,0,0,0,576,224,0,0,0],"FLAG":0,"BASE":18} iQtech SmartLife {"NAME":"iQ-Tech WS020","GPIO":[0,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} @@ -1357,6 +1375,7 @@ Moes W-DE004S {"NAME":"Moes DE004S ","GPIO":[321,0,0,0,0,2720,0,0 Moes WS-UEU {"NAME":"MoesHouse","GPIO":[0,0,0,224,32,0,0,0,321,0,0,0,0,0],"FLAG":0,"BASE":18} MoKo 2 USB {"NAME":"MoKo Plug","GPIO":[0,32,0,0,0,0,0,0,0,321,224,0,0,0],"FLAG":0,"BASE":18} MoKo YX-WS01A {"NAME":"MoKo Plug","GPIO":[0,32,0,0,0,0,0,0,0,321,224,0,0,0],"FLAG":0,"BASE":18} +Muvit iO MIOSMP008 {"NAME":"MIOSMP008","GPIO":[0,0,0,32,2656,2624,0,0,224,2720,320,0,0,0],"FLAG":0,"BASE":1} MXQ LED Nightlight {"NAME":"MXQ SP06","GPIO":[0,0,0,0,288,192,0,0,225,321,224,0,0,0],"FLAG":0,"BASE":18} 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} @@ -1389,6 +1408,7 @@ OFFONG 16A {"NAME":"OFFONG P1","GPIO":[0,32,0,0,2720,2656,0,0, Oittm Smart {"NAME":"Oittm","GPIO":[0,0,0,0,224,320,0,0,32,0,0,0,0,0],"FLAG":0,"BASE":1} Olliwon {"NAME":"Olliwon","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Onearz Connect Smart {"NAME":"Onearz Power Plug Wifi","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18} +Oneplug {"NAME":"ONEPLUG UP111","GPIO":[321,0,0,0,2656,2720,0,0,2624,0,224,0,32,0],"FLAG":0,"BASE":18} Onestyle SD-WL-02 {"NAME":"JH-G01B1","GPIO":[0,3072,0,3104,0,0,0,0,32,320,224,0,0,0],"FLAG":0,"BASE":41} Orbecco W-US009 {"NAME":"Orbecco Plug","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,0,0],"FLAG":0,"BASE":18} Orvibo B25 {"NAME":"Orvibo B25","GPIO":[0,0,0,0,289,224,0,0,288,0,32,0,0,0],"FLAG":0,"BASE":18} @@ -1405,8 +1425,8 @@ Panamalar NX-SM200 {"NAME":"NX-SM200","GPIO":[0,0,0,0,320,2720,0,0,262 Positivo PPW1000 {"NAME":"PPW1000","GPIO":[0,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} Positivo Max {"NAME":"PPW1600","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":55} PowerAdd BIE0091 {"NAME":"BIE0091","GPIO":[32,0,0,0,0,0,0,0,416,0,0,224,0,0],"FLAG":0,"BASE":18} +Powertech {"NAME":"Jaycar MS6104","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":52} Powertech {"NAME":"Jaycar","GPIO":[320,0,0,0,0,0,0,0,0,160,0,224,0,0],"FLAG":0,"BASE":6} -Powertech MS6104 {"NAME":"Jaycar MS6104","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":52} Powrui 3-Outlet with 4 USB {"NAME":"POWRUI AHR-077","GPIO":[0,0,0,35,34,33,0,0,225,226,32,224,544,0],"FLAG":0,"BASE":18} Powrui AW-08 {"NAME":"POWRUI AW-08","GPIO":[0,0,0,0,32,224,0,0,0,288,321,0,0,4704],"FLAG":0,"BASE":18} Premier PWIFPLG {"NAME":"Premier Plug","GPIO":[0,0,0,32,0,0,0,0,0,320,224,0,0,4704],"FLAG":0,"BASE":18} @@ -1432,10 +1452,13 @@ SA-P202A {"NAME":"SA-P202A","GPIO":[0,0,0,0,0,320,0,0,224,32 SA-P202C 16A {"NAME":"Elivco 202C-G","GPIO":[0,0,0,32,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18} SA-P302A {"NAME":"KinCam SA-P302A","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Sansui {"NAME":"Sansui YSP-1","GPIO":[288,0,289,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} +Sansui Rewireable {"NAME":"YSP-2","GPIO":[288,0,289,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} See Switches {"NAME":"SEESWITCHES SSPG01WH","GPIO":[321,1,320,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45} +Setti+ {"NAME":"Setti+ SP301","GPIO":[320,0,576,0,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45} Shelly Plug {"NAME":"Shelly Plug EU","GPIO":[0,0,0,0,224,2688,0,0,96,288,289,0,290,0],"FLAG":0,"BASE":18} Shelly Plug S {"NAME":"Shelly Plug S","GPIO":[320,1,576,1,1,2720,0,0,2624,32,2656,224,1,4736],"FLAG":0,"BASE":45} Shelly Plug US {"NAME":"Shelly Plug US","GPIO":[288,0,321,0,224,2720,0,0,2624,32,2656,544,0,0],"FLAG":0,"BASE":45} +Shelly Plus Plug S {"NAME":"Shelly Plus Plug S","GPIO":[0,0,0,0,224,0,32,2720,0,0,0,0,0,0,0,2624,0,0,2656,0,0,288,289,0,0,0,0,0,0,4736,0,0,0,0,0,0],"FLAG":0,"BASE":1} Sieges {"NAME":"Sieges FLHS-ZN01","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} SilentNight {"NAME":"SilentNightPlug","GPIO":[0,0,0,0,288,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Silvergear Slimme Stekker {"NAME":"Silvergear SmartHomePlug","GPIO":[0,0,0,96,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} @@ -1475,6 +1498,8 @@ STITCH {"NAME":"Stitch 27937","GPIO":[32,0,320,0,2688,2656 STITCH {"NAME":"Stitch 35511","GPIO":[320,0,321,0,0,2688,0,0,0,32,2656,224,2624,0],"FLAG":0,"BASE":18} STITCH 15A In-Line {"NAME":"Stitch 39047","GPIO":[0,288,0,32,2688,2656,0,0,2624,0,224,0,0,0],"FLAG":0,"BASE":18} STITCH Mini 10A {"NAME":"STITCH 41730","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} +Strong Helo Plight {"NAME":"Strong HELO-PLIGHT-EU","GPIO":[416,0,418,0,417,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} +Strong Helo PLUSB 2x USB {"NAME":"Helo-PLUSB-EU","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,225,8096,0],"FLAG":0,"BASE":18} SuperNight Dual {"NAME":"SUPERNIGHT","GPIO":[0,32,0,224,2656,2688,0,0,225,2624,576,0,0,4833],"FLAG":0,"BASE":18} SWA1 {"NAME":"SWA1","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18} SWA1 FR {"NAME":"SWA1","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18} @@ -1763,6 +1788,7 @@ AiYaTo 12W {"NAME":"AiYaTo RGBCW","GPIO":[0,0,0,0,419,418,0,0, Alfawise LE12 9W 900LM {"NAME":"Alfawise LE12 ","GPIO":[0,0,0,0,420,417,0,0,418,0,419,416,0,0],"FLAG":0,"BASE":18} Aoycocr JL81 5W 400lm {"NAME":"AoycocrJLB1","GPIO":[0,0,0,0,418,0,0,0,417,420,416,419,0,0],"FLAG":0,"BASE":18} Aoycocr Q10CWM BR30 9W 720lm {"NAME":"AoycocrBR30","GPIO":[0,0,0,0,0,418,0,0,417,0,416,419,0,0],"FLAG":0,"BASE":18} +Arlec 5.5W 470lm {"NAME":"Arlec GLD360HA","GPIO":[0,0,0,0,0,0,0,0,4067,0,4032,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO37 24"} Arlec Smart 10W 830lm {"NAME":"Arlec GLD320HA","GPIO":[0,0,0,0,4067,0,0,0,0,4032,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO37 6"} Arlec Smart 9.5W 806lm {"NAME":"Arlec RGBWW","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} Arlec Smart 9.5W 806lm {"NAME":"Arlec RGBWW","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} @@ -1951,13 +1977,14 @@ cod.m WLAN Pixel Controller v0.8 {"NAME":"cod.m Pixel Controller V0.8","GPIO":[ ESP01 NeoPixel Ring {"NAME":"ESP-01S-RGB-LED-v1.0","GPIO":[1,1,1376,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} H803WF 2048 Pixel 5V-24V {"NAME":"H803WF","GPIO":[0,0,0,0,3840,3840,0,0,3872,1376,0,3872,0,0],"FLAG":0,"BASE":18} IOTMCU {"NAME":"IOTMCU_ESP-12S-RGB-LED-v1","GPIO":[1,1,1,1,0,1376,0,0,1,1088,32,0,0,0],"FLAG":0,"BASE":18} +LifeSmart Cololight MIX {"NAME":"ESP32-DevKit","GPIO":[0,0,0,0,1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,4704,0,0,0,0,0,0],"FLAG":0,"BASE":1} LifeSmart Cololight PRO Hexagonal {"NAME":"Cololight PRO","GPIO":[0,0,0,0,32,0,0,0,0,33,0,0,1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4704,0,0,0,0,0,0],"FLAG":0,"BASE":1} SP501E WS2812B {"NAME":"SP501E","GPIO":[0,32,0,1376,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} ``` ## RGBW ``` -3Stone EBE-QPW36 1050lm {"NAME":"3STONE","GPIO":[0,0,0,0,2944,2912,0,0,416,2976,0,0,0,1],"FLAG":0,"BASE":18} +3Stone EBE-QPW36 1050lm {"NAME":"3Stone","GPIO":[0,0,0,0,2912,417,0,0,0,416,2944,0,0,0],"FLAG":0,"BASE":18} Accewit 7W 650lm {"NAME":"Accewit Bulb","GPIO":[0,0,0,0,0,417,0,0,418,0,419,416,0,0],"FLAG":0,"BASE":18} Aisirer 7W 580lm {"NAME":"Aisirer RGBW","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} Aisirer 7W 580lm {"NAME":"Aisirer RGBW","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} @@ -2093,6 +2120,7 @@ REPSN G45 5W 500lm {"NAME":"REPSN RGBW E14","GPIO":[0,0,0,0,0,0,0,0,40 Riversong Juno 10W {"NAME":"Juno10","GPIO":[0,0,0,0,2912,416,0,0,0,2976,2944,0,0,0],"FLAG":0,"BASE":18} Rogoei EBE-QPZ04 6.5W 450lm {"NAME":"EBE-QPZ04","GPIO":[0,0,0,0,4032,0,0,0,0,0,4064,0,0,0],"FLAG":0,"BASE":18} Saudio 7W 700lm {"NAME":"X002BU0DOL","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} +Sengled {"NAME":"Sengled RGBW","GPIO":[0,0,0,0,0,0,0,0,417,416,419,418,0,0],"FLAG":0,"BASE":18} Shelly Duo RGBW 5W 400lm {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18} Shelly Duo RGBW 9W 800lm {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18} 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} @@ -2129,6 +2157,7 @@ WOOX 4W 350lm {"NAME":"WOOX R4553","GPIO":[0,0,0,0,416,419,0,0,41 WOOX R4553 650lm {"NAME":"WOOX R4553","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} WOOX R5077 {"NAME":"WOOX R5077","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18} Wyze Bulb Color {"NAME":"Wyze Bulb Color","GPIO":[0,0,0,0,0,0,0,0,0,418,416,419,0,0,0,0,0,0,0,224,0,0,417,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} +Xiaomi Mi LED Smart Bulb Essential {"NAME":"Mi LED Smart Bulb Essential","GPIO":[0,0,0,0,418,419,0,0,416,417,0,0,0,0],"FLAG":0,"BASE":18} Zemismart 5W {"NAME":"Zemismart_GU10","GPIO":[0,0,0,0,0,0,0,0,0,3008,0,3040,0,0],"FLAG":0,"BASE":27} Zemismart 5W 480lm {"NAME":"Zemismart-E14-RGBW","GPIO":[0,0,0,0,0,0,0,0,0,3008,0,3040,0,0],"FLAG":0,"BASE":27} Zemismart A19 10W {"NAME":"Zemism_E27_A19","GPIO":[0,0,0,0,0,0,0,0,0,3008,0,3040,0,0],"FLAG":0,"BASE":27} @@ -2145,7 +2174,10 @@ Athom 1Ch Inching/Self-locking {"NAME":"Athom R01","GPIO":[1,1,1,1,1,224,1,1,1, Athom 8Ch Inching/Self-locking 10A {"NAME":"Athom R08","GPIO":[229,1,1,1,230,231,1,1,226,227,225,228,224,0],"FLAG":0,"BASE":18} Claudy 5V {"NAME":"CLAUDY","GPIO":[0,0,225,0,0,0,0,0,0,0,0,224,0,0],"FLAG":0,"BASE":18} Devantech 8x16A {"NAME":"ESP32LR88","GPIO":[0,0,231,0,32,35,0,0,229,230,228,0,33,34,36,37,0,38,39,544,0,225,226,227,0,0,0,0,0,224,3232,3200,0,0,0,0],"FLAG":0,"BASE":1} -DoHome HomeKit DIY Switch {"NAME":"DoHome DIY","GPIO":[1,1,0,1,1,544,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":1} +Dingtian 16 Channel {"NAME":"Dingtian DT-R008","GPIO":[1,9408,1,9440,1,1,1,1,1,9760,9729,9856,9792,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9824,9952,1,1,1,0,0,1],"FLAG":0,"BASE":1} +Dingtian 32 Channel {"NAME":"Dingtian DT-R008","GPIO":[1,9408,1,9440,1,1,1,1,1,9760,9731,9856,9792,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9824,9952,1,1,1,0,0,1],"FLAG":0,"BASE":1} +Dingtian 8 Channel {"NAME":"Dingtian DT-R008","GPIO":[1,9408,1,9440,1,1,1,1,1,9760,9728,9856,9792,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,9824,9952,1,1,1,0,0,1],"FLAG":0,"BASE":1} +DoHome HomeKit DIY Switch {"NAME":"DoHome DIY","GPIO":[1,1,0,1,96,544,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":1} Eachen ST-DC2 {"NAME":"Garage Control","GPIO":[162,0,0,0,226,225,33,0,224,288,163,227,0,4704],"FLAG":0,"BASE":18} Eachen ST-DC4 {"NAME":"Eachen_ST-DC4","GPIO":[160,1,1,1,226,225,1,1,224,544,1,227,1,0],"FLAG":0,"BASE":54} Eachen ST-UDC1 {"NAME":"ST-UDC1","GPIO":[160,0,0,0,0,0,0,0,224,320,0,0,0,4704],"FLAG":0,"BASE":18} @@ -2153,14 +2185,18 @@ Electrodragon Board SPDT {"NAME":"ED Relay Board","GPIO":[1,1,1,1,1,1,0,0,22 Electrodragon ESP8266 {"NAME":"ElectroDragon","GPIO":[33,1,32,1,1,1,0,0,225,224,1,1,288,4704],"FLAG":0,"BASE":15} Electrodragon Inductive Load {"NAME":"ED RelayBoard IL","GPIO":[0,0,1,0,1,1,0,0,224,225,1,1,288,0],"FLAG":0,"BASE":18} ESP-01 Relay V4.0 {"NAME":"ESP01v4","GPIO":[256,320,0,32,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} +ESP-01 Relay V5.0 {"NAME":"ESP01v5","GPIO":[256,320,0,32,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} ESP-01S 5V Relay Module V1.0 {"NAME":"ESP-01S Relay","GPIO":[256,288,1,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} ESP-12F 5V/7-28V 1 Channel 30A {"NAME":"Aideepen","GPIO":[0,0,0,0,0,288,0,0,0,0,0,0,224,0],"FLAG":0,"BASE":18} ESP-12F 5V/7-28V 4 Channel 30A {"NAME":"ESP12F_Relay_30A_X4","GPIO":[1,1,1,1,32,1,1,1,226,227,225,1,224,1],"FLAG":0,"BASE":18} ESP-12F 5V/7-28V 8 Channel {"NAME":"ESP12F_Relay_X8","GPIO":[229,1,1,1,230,231,0,0,226,227,225,228,224,1],"FLAG":0,"BASE":18} +ESP-12F 5V/7-28V 8 Channel {"NAME":"ESP12F_Relay_X8_v1.1","GPIO":[230,1,231,229,1,1,1,1,226,225,227,224,228,1],"FLAG":0,"BASE":18} ESP-12F 5V/7-30V/220V 4 Channel {"NAME":"ESP12F_Relay_X4","GPIO":[1,1,320,1,1,321,1,1,226,227,225,1,224,1],"FLAG":0,"BASE":18} ESP-12F 5V/8-80V 2 Channel {"NAME":"LC-Relay-ESP12-2R-D8","GPIO":[1,1,1,1,224,225,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18} ESP-12F DC 5V/12V/24V 16 Channel {"NAME":"ESP12F_Relay_X16","GPIO":[1,1,1,1,1,7712,1,1,7680,7648,7744,1,1,1],"FLAG":0,"BASE":18} ESP32 4 Channel {"NAME":"RobotDyn ESP32R4","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,224,225,0,0,0,0,0,227,226,32,33,34,0,0,35],"FLAG":0,"BASE":2} +ESP32SR88 - WIFI 8 x 1A {"NAME":"ESP32SR88","GPIO":[0,3200,0,3232,226,544,0,0,0,0,0,0,225,224,32,544,33,34,35,36,0,37,38,39,0,229,228,227,0,0,0,0,231,230,0,0],"FLAG":0,"BASE":1} +ESP8266 4 Channel 5V/12V {"NAME":"4CH Relay","GPIO":[0,0,0,0,0,0,0,0,226,227,225,0,224,0],"FLAG":0,"BASE":18} eWeLink PSF-B04 5V 7-32V 4 Channel {"NAME":"eWeLink 4CH","GPIO":[160,0,0,0,226,225,161,162,224,288,163,227,0,0],"FLAG":0,"BASE":18} Ewelink RF No Neutral 3 Channel {"NAME":"Ewelink 3 Gang Module","GPIO":[32,0,0,0,225,226,33,34,224,544,0,0,0,0],"FLAG":0,"BASE":18} Geekcreit 5V DIY 4 Channel Jog Inching Self-Locking {"NAME":"Geekcreit-4ch","GPIO":[160,0,0,0,226,225,161,162,224,288,163,227,0,0],"FLAG":0,"BASE":18} @@ -2182,7 +2218,7 @@ LC Technology DC5-60V 1 Channel {"NAME":"ESP32_Relay_X1","GPIO":[1,1,1,1,1,1,1, LC Technology DC5-60V 2 Channel {"NAME":"ESP32_Relay_X2","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,0,225,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} LC Technology DC5-60V 4 Channel {"NAME":"ESP32_Relay_X4","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,544,0,226,227,1,0,0,0,0,224,225,1,1,1,0,0,1],"FLAG":0,"BASE":1} LC Technology ESP8266 5V {"NAME":"ESP8266-01S","GPIO":[224,3200,0,3232,0,0,0,0,0,0,0,0,0,4704],"FLAG":0,"BASE":18} -LilyGo T-Relay 8 {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1} +LilyGo T-Relay 5V 8 Channel {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1} LilyGO TTGO 4 Channel ESP32 {"NAME":"T-Relay ESP32","GPIO":[0,0,1,0,1,227,0,0,1,1,1,1,0,0,226,225,0,224,1,1,0,544,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1} LinkNode R4 {"NAME":"LinkNode R4","GPIO":[0,0,0,0,0,0,0,0,224,225,226,0,227,0],"FLAG":0,"BASE":18} LinkNode R8 {"NAME":"LinkNode R8","GPIO":[0,0,0,0,228,229,0,231,226,227,225,230,224,0],"FLAG":0,"BASE":18} @@ -2202,15 +2238,13 @@ Sonoff SV {"NAME":"Sonoff SV","GPIO":[32,1,0,1,1,1,0,0,224,32 Yunshan 7-30V 10A {"NAME":"Yunshan 10A","GPIO":[32,1,288,1,224,161,0,0,225,0,0,0,0,0],"FLAG":0,"BASE":18} ``` -## Relay Module -``` -``` - ## Sensor ``` Bresser 7-Kanal Thermo-/Hygrometer with Outdoor {"NAME":"Bresser","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"SO97 1 | TuyaMCU 73,2 | TuyaMCU 71,102"} Genesense IoT Controller {"NAME":"GNS24","GPIO":[32,1,1312,1,256,320,1,1,256,1216,160,3840,1,4704],"FLAG":0,"BASE":18} +Kaiweets Air Quality {"NAME":"Kaiweets EH-8","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Shelly 3EM Power Monitoring Module {"NAME":"Shelly 3EM","GPIO":[1,1,288,1,32,8065,0,0,640,8064,608,224,8096,0],"FLAG":0,"BASE":18} +Tuya Air Detector 6 in 1 {"NAME":"DCR-KQG","GPIO":[1,2272,544,2304,1,1,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 80,2 | TuyaMCU 71,18 | TuyaMCU 73,19 | TuyaMCU 99,20 | TuyaMCU 76,21 | TuyaMCU 77,22 | HumRes 1 | TempRes 1 "} ``` ## Siren @@ -2232,6 +2266,7 @@ Blitzwolf E27 {"NAME":"BlitzWolf LT-30","GPIO":[0,0,0,0,320,224,0 Elegant Choice E27/E26 {"NAME":"name","GPIO":[0,0,0,0,0,0,0,0,0,0,0,224,0,0],"FLAG":0,"BASE":18} Slampher {"NAME":"Slampher","GPIO":[32,1,0,1,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":9} SmartBase E0260 {"NAME":"SmartBaseE0260","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} +Timeguard Lamp Holder {"NAME":"Timeguard WFLH","GPIO":[0,0,0,0,576,320,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18} ``` ## Soil Sensor @@ -2239,6 +2274,11 @@ SmartBase E0260 {"NAME":"SmartBaseE0260","GPIO":[0,0,0,0,320,0,0,0, DIY MORE ESP32 DHT11 {"NAME":"DIYMORESOILDHT11","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,544,1,1,1,0,1,1184,1,0,1,1,1,0,0,0,0,4864,288,4865,1,1,0,0,1],"FLAG":0,"BASE":1} ``` +## Soldering Iron +``` +T13 100W PD3.0 Portable {"NAME":"PTS200","GPIO":[0,0,33,0,34,0,0,0,6210,0,32,512,0,0,0,0,0,640,608,0,0,224,4704,0,0,0,0,0,0,4737,0,0,0,0,0,0],"FLAG":0,"BASE":1} +``` + ## Switch ``` 3 Way Smart Light {"NAME":"KS-602F","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54} @@ -2273,6 +2313,7 @@ Bardi Smart Wallswitch 1 Gang {"NAME":"Bardi 1 Gang","GPIO":[321,320,544,0,0,32 Bardi Smart Wallswitch 2 Gang {"NAME":"BARDI 2 Gang","GPIO":[320,0,544,33,225,0,0,0,288,224,321,0,32,0],"FLAG":0,"BASE":18} Bardi Smart Wallswitch 3 Gang {"NAME":"BARDI 3 Gang","GPIO":[320,321,544,34,226,33,0,0,288,224,322,225,32,0],"FLAG":0,"BASE":18} BAZZ SWTCHWFW1 {"NAME":"BAZZ KS-602S","GPIO":[32,0,0,0,0,0,224,288,256,320,0,0,0,0],"FLAG":0,"BASE":18} +Bingoelec 1 Gang Touch {"NAME":"Bingoelec W601","GPIO":[0,544,0,0,0,32,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-SS3 1 Gang {"NAME":"BW-SS3-1G-EU","GPIO":[288,0,0,32,0,0,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-SS3 2 Gang {"NAME":"BW-SS3-2G-EU","GPIO":[544,1,1,1,225,33,1,1,32,224,1,1,1,1],"FLAG":0,"BASE":18} BlitzWolf BW-SS3 3 Gang {"NAME":"BlitzWolf SS3","GPIO":[576,0,0,161,225,162,0,0,160,224,0,226,0,0],"FLAG":0,"BASE":18} @@ -2469,6 +2510,7 @@ Smatrul 2 Gang RF No Neutral {"NAME":"SMATRUL 2 GANG","GPIO":[0,544,0,32,33,0,0 Smatrul 5A RF433MHz 1 Gang Touch {"NAME":"TMC01-EU","GPIO":[0,320,0,0,0,160,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} Smatrul 5A RF433MHz 4 Gang Touch {"NAME":"TMW4-01(EU)","GPIO":[0,0,0,33,35,32,0,0,34,224,225,226,227,0],"FLAG":0,"BASE":18} Smatrul 5A RF433MHz 4 Gang Touch {"NAME":"Smatrul RF433MHz 3 Gang Touch Switch (TMW4-01(EU))","GPIO":[0,0,0,160,162,161,0,0,225,224,226,0,0,0],"FLAG":0,"BASE":18} +Smatrul Infrared Sensor {"NAME":"WHS-2","GPIO":[0,0,0,160,288,0,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SwitchMode1 4 | SO13 1"} Sonoff IW101 {"NAME":"Sonoff IW101","GPIO":[32,3072,0,3104,0,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":41} Sonoff SwitchMan M5-1C 1 Gang {"NAME":"Sonoff SwitchMan M5-1C-86","GPIO":[32,0,0,0,288,576,0,0,0,0,0,0,0,0,416,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} Sonoff SwitchMan M5-2C 2 Gang {"NAME":"Sonoff SwitchMan 2C","GPIO":[0,0,0,0,32,576,0,0,0,0,0,33,0,0,416,225,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1} @@ -2523,6 +2565,7 @@ TreatLife {"NAME":"TL SS01S Swtch","GPIO":[0,0,0,0,288,576,0, Treatlife 3-Way {"NAME":"Treatlife SS01 3-Way","GPIO":[0,0,0,0,224,576,0,0,225,33,160,0,0,0],"FLAG":0,"BASE":18} TreatLife 3-Way {"NAME":"Treatlife 3-Way","GPIO":[0,0,0,0,224,576,0,0,225,33,160,0,0,0],"FLAG":0,"BASE":18} TreatLife Single Pole ON/OFF {"NAME":"Treatlife SS02","GPIO":[0,0,0,0,288,576,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} +Tuya 20A {"NAME":"DS-161","GPIO":[544,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1} Tuya 3 Gang {"NAME":"KING-Tuya-key","GPIO":[0,0,0,0,226,225,0,0,224,32,34,0,33,0],"FLAG":0,"BASE":18} TY-US-L1-W {"NAME":"TY-US-L1-W","GPIO":[0,0,0,0,0,32,0,0,0,224,0,0,576,0],"FLAG":0,"BASE":18} TY-US-L3-W {"NAME":"TY-US-L3-W","GPIO":[0,0,0,0,224,33,0,0,34,226,32,225,576,1],"FLAG":0,"BASE":18} @@ -2605,6 +2648,7 @@ Moes {"NAME":"Moes MS-104B","GPIO":[0,0,32,0,480,0,0,0,1 Moes 10A {"NAME":"Moes MS-101","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Moes Mini 3 Gang 1/2 Way {"NAME":"Moes MS-104C","GPIO":[0,0,0,34,32,33,0,0,224,225,226,0,0,0],"FLAG":0,"BASE":18} Nedis 10A {"NAME":"Nedis WIFIPS10WT","GPIO":[0,0,0,0,224,0,0,0,32,321,0,288,0,0],"FLAG":0,"BASE":18} +Nous 1/2 Channel {"NAME":"NOUS L13T Smart Switch Module","GPIO":[1,161,1,160,225,224,1,1,544,1,32,1,1,1],"FLAG":0,"BASE":18} Nova Digital Basic 1 MS101 {"NAME":"NovaDigBasic1","GPIO":[0,1,0,1,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} PPA Contatto Wi-Fi {"NAME":"PPA Contatto","GPIO":[0,0,32,0,224,162,0,0,288,225,0,0,0,0],"FLAG":0,"BASE":18} PS-1604 16A {"NAME":"PS-1604 16A","GPIO":[32,1,1,1,1,0,0,0,224,320,1,0,0,0],"FLAG":0,"BASE":1} @@ -2625,6 +2669,7 @@ Shelly Plus i4 {"NAME":"Shelly Plus i4","GPIO":[0,0,0,0,0,0,0,0,19 Sinilink USB {"NAME":"XY-WFUSB","GPIO":[1,1,0,1,32,224,0,0,0,0,320,0,544,0],"FLAG":0,"BASE":18} Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18} Smart Home SS-8839-01 {"NAME":"SS-8839-01","GPIO":[0,1,0,1,224,0,0,0,32,321,0,320,0,0],"FLAG":0,"BASE":18} +Smart Switch {"NAME":"FL-S124-V1.0","GPIO":[1,1,1,1,32,224,1,1,1,320,1,1,1,1],"FLAG":0,"BASE":18} Sonoff 4CH (R2) {"NAME":"Sonoff 4CH","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":7} Sonoff 4CH Pro (R2) {"NAME":"Sonoff 4CH Pro","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":23} Sonoff 4CHPROR3 {"NAME":"Sonoff 4CHPROR3","GPIO":[32,1,1,1,226,225,33,34,224,320,35,227,0,0],"FLAG":0,"BASE":23} @@ -2713,6 +2758,8 @@ Deta Double Power Point {"NAME":"DETA 2G GPO","GPIO":[0,0,0,0,544,0,0,0,65, DETA Outdoor Double Powerpoint {"NAME":"DETA 6294HA","GPIO":[0,0,0,3104,32,288,0,0,33,224,225,0,0,0],"FLAG":0,"BASE":18} Deta Single Power Point {"NAME":"DETA 1G GPO","GPIO":[0,0,0,3104,64,576,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18} Ener-J 13A Twin Wall Sockets with USB {"NAME":"Ener-J 2-Gang ","GPIO":[32,0,0,0,0,224,33,0,225,320,0,0,0,0],"FLAG":0,"BASE":18} +GHome USB Charger {"NAME":"GHome Smart WO2-1","GPIO":[320,0,0,0,0,257,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} +Globe Double Receptacle 15A {"NAME":"Globe 50024","GPIO":[0,0,0,0,320,32,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} Gosund {"NAME":"Gosund WO1","GPIO":[320,0,576,0,2656,2720,0,0,2624,321,225,224,0,4704],"FLAG":0,"BASE":18} Gosund USB Charger {"NAME":"Gosund WO2","GPIO":[320,0,576,0,0,257,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Hevolta Glasense {"NAME":"Hevolta Socket","GPIO":[0,0,0,0,288,289,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} @@ -2743,6 +2790,7 @@ TopGreener Dual USB {"NAME":"TGWF215U2A","GPIO":[0,320,0,32,2720,2656,0 Vigica VGSPK00815 {"NAME":"VIGICA outlet","GPIO":[32,1,1,1,1,225,33,1,224,1,1,1,1,4704],"FLAG":0,"BASE":18} Virage Labs ViragePlug {"NAME":"ViragePlug","GPIO":[544,0,0,32,320,33,0,0,225,224,320,226,0,0],"FLAG":0,"BASE":18} Woox Dual {"NAME":"Woox R4053","GPIO":[33,0,0,0,0,224,32,0,225,320,0,0,0,0],"FLAG":0,"BASE":18} +Xenon {"NAME":"Xenon SM-PM801-K1","GPIO":[0,320,0,32,2720,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18} Xenon 2AC 1USB {"NAME":"Xenon SM-PW801-U1","GPIO":[0,0,0,0,288,32,0,0,224,0,225,0,226,0],"FLAG":0,"BASE":18} ``` @@ -2761,4 +2809,5 @@ Sonoff ZBBridge {"NAME":"Sonoff ZbBridge","GPIO":[320,3552,0,3584,5 Sonoff ZBBridge Pro {"NAME":"Sonoff Zigbee Pro","GPIO":[0,0,576,0,480,0,0,0,0,1,1,5792,0,0,0,3552,0,320,5793,3584,0,640,608,32,0,0,0,0,0,1,0,0,0,0,0,0],"FLAG":0,"BASE":1} Tube's CC2652P2 Ethernet {"NAME":"Tube ZB CC2652","GPIO":[0,0,0,3840,0,3584,0,0,0,0,0,0,5536,3552,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,3840,5792,0,0,0,0,0,0],"FLAG":0,"BASE":1} Tube's EFR32 Ethernet {"NAME":"Tube ZB EFR32","GPIO":[0,0,0,3840,0,3552,1,0,0,0,0,0,5536,3584,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,5793,5792,0,0,0,0,0,0],"FLAG":0,"BASE":1} +TubesZB CC2652P2 Zigbee to PoE Coordinator 2022 {"NAME":"TubesZB CC2652 PoE Coordinator 2022","GPIO":[1,1,8864,1,5793,3584,0,0,5536,5792,8832,8800,3552,0,5600,1,1,1,1,5568,1,1,1,1,0,0,0,0,1,1,32,1,1,1,1,1],"FLAG":0,"BASE":1} ``` diff --git a/boards/esp32-fix.json b/boards/esp32-fix.json index 90132b94e..a2a9bed87 100644 --- a/boards/esp32-fix.json +++ b/boards/esp32-fix.json @@ -4,7 +4,7 @@ "ldscript": "esp32_out.ld" }, "core": "esp32", - "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M", + "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DESP32_4M", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dio", diff --git a/boards/esp32.json b/boards/esp32.json index 808ba0cd0..1e476569c 100644 --- a/boards/esp32.json +++ b/boards/esp32.json @@ -4,7 +4,7 @@ "ldscript": "esp32_out.ld" }, "core": "esp32", - "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M", + "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DESP32_4M", "f_cpu": "160000000L", "f_flash": "40000000L", "flash_mode": "dio", diff --git a/boards/esp32_solo1.json b/boards/esp32_solo1.json index 85b886a55..3bb85fe05 100644 --- a/boards/esp32_solo1.json +++ b/boards/esp32_solo1.json @@ -4,7 +4,7 @@ "ldscript": "esp32_out.ld" }, "core": "esp32", - "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M -DCORE32SOLO1", + "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DESP32_4M -DCORE32SOLO1", "f_cpu": "240000000L", "f_flash": "40000000L", "flash_mode": "dio", diff --git a/boards/esp32c3.json b/boards/esp32c3.json index 74a740dee..b7f74c3e5 100644 --- a/boards/esp32c3.json +++ b/boards/esp32c3.json @@ -4,7 +4,7 @@ "ldscript": "esp32c3_out.ld" }, "core": "esp32", - "extra_flags": "-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M -DESP32C3", + "extra_flags": "-DESP32_4M -DESP32C3", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "dio", diff --git a/boards/esp32c3cdc.json b/boards/esp32c3cdc.json index b29b2ca98..3d280a73b 100644 --- a/boards/esp32c3cdc.json +++ b/boards/esp32c3cdc.json @@ -4,7 +4,7 @@ "ldscript": "esp32c3_out.ld" }, "core": "esp32", - "extra_flags": "-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M -DESP32C3 -DUSE_USB_CDC_CONSOLE", + "extra_flags": "-DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C3 -DUSE_USB_CDC_CONSOLE", "f_cpu": "160000000L", "f_flash": "80000000L", "flash_mode": "dio", diff --git a/boards/esp32s2.json b/boards/esp32s2.json index e24ffd17d..d13f2a855 100644 --- a/boards/esp32s2.json +++ b/boards/esp32s2.json @@ -4,7 +4,7 @@ "ldscript": "esp32s2_out.ld" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DESP32_4M -DESP32S2", + "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S2", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dio", diff --git a/boards/esp32s2cdc.json b/boards/esp32s2cdc.json index 03be3a6c0..bdd230d5c 100644 --- a/boards/esp32s2cdc.json +++ b/boards/esp32s2cdc.json @@ -4,7 +4,7 @@ "ldscript": "esp32s2_out.ld" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S2", + "extra_flags": "-DBOARD_HAS_PSRAM -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S2", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "dio", diff --git a/boards/esp32s3-qio_opi.json b/boards/esp32s3-qio_opi.json index 003053268..498534e61 100644 --- a/boards/esp32s3-qio_opi.json +++ b/boards/esp32s3-qio_opi.json @@ -5,7 +5,7 @@ "memory_type": "qio_opi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DESP32_4M -DESP32S3", + "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "qio", diff --git a/boards/esp32s3-qio_qspi.json b/boards/esp32s3-qio_qspi.json index 64633ab50..cdc6d70ca 100644 --- a/boards/esp32s3-qio_qspi.json +++ b/boards/esp32s3-qio_qspi.json @@ -5,7 +5,7 @@ "memory_type": "qio_qspi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DESP32_4M -DESP32S3", + "extra_flags": "-DBOARD_HAS_PSRAM -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "qio", diff --git a/boards/esp32s3cdc-qio_opi.json b/boards/esp32s3cdc-qio_opi.json index f01620ffc..67dae1a6e 100644 --- a/boards/esp32s3cdc-qio_opi.json +++ b/boards/esp32s3cdc-qio_opi.json @@ -5,7 +5,7 @@ "memory_type": "qio_opi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", + "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "qio", diff --git a/boards/esp32s3cdc-qio_qspi.json b/boards/esp32s3cdc-qio_qspi.json index 349cbe9ce..f37a47bb5 100644 --- a/boards/esp32s3cdc-qio_qspi.json +++ b/boards/esp32s3cdc-qio_qspi.json @@ -5,7 +5,7 @@ "memory_type": "qio_qspi" }, "core": "esp32", - "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", + "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3", "f_cpu": "240000000L", "f_flash": "80000000L", "flash_mode": "qio", diff --git a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp index a233422be..18cfee1e0 100644 --- a/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp +++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp @@ -228,7 +228,7 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) { #ifdef ESP32 if (TSerial == nullptr) { // Allow for dynamic change in baudrate or config if (freeUart()) { // We prefer UART1 and UART2 and keep UART0 for debugging -#ifdef ARDUINO_USB_CDC_ON_BOOT +#if ARDUINO_USB_MODE TSerial = new HardwareSerial(m_uart); #else if (0 == m_uart) { @@ -239,7 +239,7 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) { } else { TSerial = new HardwareSerial(m_uart); } -#endif // ARDUINO_USB_CDC_ON_BOOT +#endif // ARDUINO_USB_MODE if (serial_buffer_size > 256) { // RX Buffer can't be resized when Serial is already running (HardwareSerial.cpp) TSerial->setRxBufferSize(serial_buffer_size); } @@ -460,6 +460,7 @@ size_t TasmotaSerial::write(uint8_t b) { size = 1; } if (m_tx_enable_pin > -1) { + flush(); // Must wait for all data sent digitalWrite(m_tx_enable_pin, LOW); } return size; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp index 95f7c2af9..00bc1f3ab 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp @@ -411,6 +411,10 @@ void IRrecv::pause(void) { params.rcvstate = kStopState; params.rawlen = 0; params.overflow = false; +#if defined(ESP8266) + os_timer_disarm(&timer); + detachInterrupt(params.recvpin); +#endif #if defined(ESP32) gpio_intr_disable((gpio_num_t)params.recvpin); #endif // ESP32 @@ -424,6 +428,10 @@ void IRrecv::resume(void) { params.rcvstate = kIdleState; params.rawlen = 0; params.overflow = false; +#if defined(ESP8266) + os_timer_setfn(&timer, reinterpret_cast(read_timeout),NULL); + attachInterrupt(params.recvpin, gpio_intr, CHANGE); +#endif #if defined(ESP32) timerAlarmDisable(timer); gpio_intr_enable((gpio_num_t)params.recvpin); 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 4319c5d8a..e9ab03ffa 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp @@ -171,6 +171,7 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 write(frame, framepointer); #ifdef TASMOTA_MODBUS_TX_ENABLE if (mb_tx_enable_pin > -1) { + flush(); // Must wait for all data sent digitalWrite(mb_tx_enable_pin, LOW); } #endif // TASMOTA_MODBUS_TX_ENABLE @@ -203,7 +204,7 @@ uint8_t TasmotaModbus::ReceiveBuffer(uint8_t *buffer, uint8_t register_count, ui } } - timeout = millis() + 10; + timeout = millis() + 20; } } diff --git a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp index 9f6fe4f74..32d0f2ad6 100644 --- a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp +++ b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.cpp @@ -26,13 +26,15 @@ #include #include "epd2in9.h" +#include "tasmota_options.h" - +#ifndef EPD_29_V1 #define EPD_29_V2 +#endif + //#define BUSY_PIN 16 - Epd::Epd(int16_t width, int16_t height) : Paint(width,height) { } @@ -84,7 +86,6 @@ void Epd::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { setTextColor(WHITE,BLACK); setCursor(0,0); fillScreen(BLACK); - disp_bpp = 1; } @@ -99,7 +100,6 @@ void Epd::Begin(int16_t cs,int16_t mosi,int16_t sclk, int16_t rst, int16_t busy) #endif } - void Epd::Init(int8_t p) { if (p == DISPLAY_INIT_PARTIAL) { Init(lut_partial_update); @@ -116,20 +116,14 @@ void Epd::Init(int8_t p) { } } - int Epd::Init(const unsigned char* lut) { - /* this calls the peripheral hardware interface, see epdif */ - /*if (IfInit() != 0) { - return -1; - }*/ -/* - cs_pin=pin[GPIO_SSPI_CS]; - mosi_pin=pin[GPIO_SSPI_MOSI]; - sclk_pin=pin[GPIO_SSPI_SCLK]; -*/ - if (framebuffer) { - // free(framebuffer); + if (iniz) { +#ifndef EPD_29_V2 + this->lut = lut; + SetLut(this->lut); +#endif + return 0; } framebuffer = (uint8_t*)malloc(EPD_WIDTH * EPD_HEIGHT / 8); if (!framebuffer) return -1; @@ -204,6 +198,7 @@ int Epd::Init(const unsigned char* lut) { SetLut(this->lut); #endif /* EPD hardware init end */ + iniz = 1; return 0; } @@ -250,7 +245,9 @@ void Epd::Reset(void) { digitalWrite(rst_pin, HIGH); delay(200); } else { +#ifdef EPD_29_V2 SendCommand(0x12); +#endif } } diff --git a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h index 1fdba92fd..9935f4f9d 100644 --- a/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h +++ b/lib/lib_display/Epaper_29-gemu-1.0/epd2in9.h @@ -109,6 +109,7 @@ private: unsigned int mosi_pin; unsigned int sclk_pin; unsigned char mode; + uint8_t iniz = 0; void delay_busy(uint32_t wait); void SetLut(const unsigned char* lut); void SetMemoryArea(int x_start, int y_start, int x_end, int y_end); diff --git a/lib/lib_div/LibTeleinfo/README.md b/lib/lib_div/LibTeleinfo/README.md index 11a90ac2b..a83d34569 100644 --- a/lib/lib_div/LibTeleinfo/README.md +++ b/lib/lib_div/LibTeleinfo/README.md @@ -1,14 +1,12 @@ -Teleinfo (Aka TIC) Universal Library -==================================== +# Teleinfo (Aka TIC) Universal Library This is a generic Teleinfo French Meter Measure Library, it can be used on Arduino like device and also such as Spark Core, Particle, ESP8266, Raspberry PI or anywhere you can do Cpp code ... -You can see Teleinformation official french datasheet [there][1] +You can see Teleinformation official french datasheet [there][1] and this one is for [Linky][3]. -Since this is really dedicated to French energy measuring system, I will continue in French +Since this is really dedicated to French energy measuring system, I will continue in French. -Installation -============ +# Installation Copier le contenu de ce dossier (download zip) dans le dossier libraries de votre environnement Arduino Vous devriez avoir maintenant quelque chose comme `your_sketchbook_folder/libraries/LibTeleinfo` et ce dossier doit contentir les fichiers .cpp et .h ainsi que le sous dossier `examples`.
@@ -17,14 +15,12 @@ Pour trouver votre dossier de sketchbook, dans l'environnement IDE, allez dans F allez voir ce [tutorial][2] sur les librairies Arduino si beoin.
-Documentation -============= +# Documentation J'ai écrit un article [dédié][10] sur cette librairie, vous pouvez aussi voir les [catégories][6] associées à la téléinfo sur mon [blog][7]. Pour les commentaires et le support vous pouvez allez sur le [forum][8] dédié ou dans la [communauté][9] -Sketch d'exemples -================= +# Sketch d'exemples - [Arduino_Softserial_Etiquette][3] Affiche des informations de téléinformation reçue étiquette par étiquette - [Arduino_Softserial_Blink][11] Affiche des informations de téléinformation reçue trame par trame avec clignotement LED court/long si les données ont été modifiés @@ -32,23 +28,32 @@ Sketch d'exemples - [Raspberry_JSON][12] Retourne les informations de téléinformation au format JSON sur stdout. - [Wifinfo][5] ESP8266, ESP32 Wifi Teleinformation, Web + Rest + bonus, version en cours de développement, à venir mais un article [dédié][13] est déjà présent sur mon blog - [ESP32][14] ESP32 Basic test pour WifInfo32 nouveau nom Denky :-) +- [ESP32_Passthru][14] ESP32 PassThru Basic test pour Denky D4, affiche les données et les stats de la téléinfo dans la console série +- [ESP8266_DataChanged][15] ESP8266 Surveille et affiche les données changées entre 2 trames, clignote la LED RGB en fonction +- [Teleinfo_DenkyD4][16] ESP32 Denky D4 Basic test et stats pour le nouveau Denky D4 basé sur l'ESP32-Pico-V3-02 +- [Teleinfo_Stats][18] ESP32 Programme de test et statistiques pour la qualité de réception + +# Pourquoi -Pourquoi -======== - J'utilise la téléinfo dans plusieurs de mes programmes et j'en avais marre de devoir faire des copier/coller de code constament, j'ai donc décidé de faire une librairie commune que j'utilise sans me poser de question -License -======= +# License + Cette oeuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International. Si vous êtes une entreprise et que vous souhaitez participer car vous utilisez cette librairie dans du hardware (box, automate, ...), vous pouvez toujours m'envoyer un exemplaire de votre fabrication, c'est toujours sympa de voir ce qui est fait avec ce code ;-) -Divers -====== +# Addon + +Ajout des compteurs d'erreurs, et du traitement du caracteres EOT d'interruption de trames + +# Divers + Vous pouvez aller voir les nouveautés et autres projets sur [blog][7] -[1]: http://www.erdf.fr/sites/default/files/ERDF-NOI-CPT_02E.pdf +[1]: https://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_02E.pdf [2]: http://learn.adafruit.com/arduino-tips-tricks-and-techniques/arduino-libraries +[3]: https://www.enedis.fr/sites/default/files/Enedis-NOI-CPT_54E.pdf [6]: https://hallard.me/category/tinfo/ [7]: https://hallard.me [8]: https://community.hallard.me/category/7 @@ -59,7 +64,12 @@ Vous pouvez aller voir les nouveautés et autres projets sur [blog][7] [4]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial_JSON/Arduino_Softserial_JSON.ino [5]: https://github.com/hallard/LibTeleinfo/tree/master/examples/Wifinfo/Wifinfo.ino [11]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Arduino_Softserial/Arduino_Softserial_Blink.ino -[12]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Raspberry_JSON/Raspberry_JSON.ino +[12]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Raspberry_JSON/raspjson.cpp [13]: https://hallard.me/wifiinfo/ [14]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP32/ESP32.ino +[15]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP8266_DataChanged/ESP8266_DataChanged.ino +[16]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Teleinfo_DenkyD4/Teleinfo_DenkyD4.ino +[17]: https://github.com/hallard/LibTeleinfo/blob/master/examples/ESP32_Passthru/ESP32_Passthru.ino +[18]: https://github.com/hallard/LibTeleinfo/blob/master/examples/Teleinfo_Stats/Teleinfo_Stats.ino + diff --git a/lib/lib_div/LibTeleinfo/library.json b/lib/lib_div/LibTeleinfo/library.json index ea6932a9b..84593d3a6 100644 --- a/lib/lib_div/LibTeleinfo/library.json +++ b/lib/lib_div/LibTeleinfo/library.json @@ -1,6 +1,6 @@ { "name": "LibTeleinfo", - "version": "1.1.3", + "version": "1.1.5", "keywords": "teleinfo, french, meter, power, erdf, linky, tic", "description": "Decoder for Teleinfo (aka TIC) from French smart power meters", "repository": diff --git a/lib/lib_div/LibTeleinfo/library.properties b/lib/lib_div/LibTeleinfo/library.properties index ad488ca08..562d96c62 100644 --- a/lib/lib_div/LibTeleinfo/library.properties +++ b/lib/lib_div/LibTeleinfo/library.properties @@ -1,5 +1,5 @@ name=LibTeleinfo -version=1.1.3 +version=1.1.5 author=Charles-Henri Hallard maintainer=Charles-Henri Hallard sentence=Decoder for Teleinfo (aka TIC) from French smart power meters diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp index cdaa8aa9e..92bd7e359 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.cpp @@ -50,6 +50,8 @@ TInfo::TInfo() _fn_data = NULL; _fn_new_frame = NULL; _fn_updated_frame = NULL; + + clearStats(); } /* ====================================================================== @@ -78,6 +80,22 @@ void TInfo::init(_Mode_e mode) } } +/* ====================================================================== +Function: clearStats +Purpose : clear stats counters +Input : - +Output : - +Comments: - +====================================================================== */ +void TInfo::clearStats() +{ + // reset Frame counters stats + _checksumerror =0; + _framesizeerror=0; + _frameformaterror=0; + _frameinterrupted=0; +} + /* ====================================================================== Function: attachADPS Purpose : attach a callback when we detected a ADPS on any phase @@ -226,8 +244,11 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t ValueList *parNode = NULL ; uint32_t ts = 0; + // Time stamped field? if (horodate && *horodate) { ts = horodate2Timestamp(horodate); + // We don't check horodate (not used) on storage so re calculate checksum without this one + checksum = calcChecksum(name,value) ; } // Loop thru the node @@ -257,7 +278,6 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t // Copy it strlcpy(me->value, value , lgvalue + 1 ); me->checksum = checksum ; - // That's all return (me); } else { @@ -279,19 +299,12 @@ ValueList * TInfo::valueAdd(char * name, char * value, uint8_t checksum, uint8_t // Our linked list structure sizeof(ValueList) // + Name + '\0' // + Value + '\0' - size_t size ; - #if defined (ESP8266) || defined (ESP32) - lgname = ESP_allocAlign(lgname+1); // Align name buffer - lgvalue = ESP_allocAlign(lgvalue+1); // Align value buffer - // Align the whole structure - size = ESP_allocAlign( sizeof(ValueList) + lgname + lgvalue ) ; - #else - size = sizeof(ValueList) + lgname + 1 + lgvalue + 1 ; - #endif + size_t size = sizeof(ValueList) + lgname + 1 + lgvalue + 1 ; // Create new node with size to store strings - if ((newNode = (ValueList *) malloc(size) ) == NULL) + if ((newNode = (ValueList *) malloc(size) ) == NULL) { return ( (ValueList *) NULL ); + } // get our buffer Safe memset(newNode, 0, size); @@ -456,10 +469,13 @@ char * TInfo::valueGet(char * name, char * value) if (lgname==strlen(me->name) && strcmp(me->name, name)==0) { // this one has a value ? if (me->value) { - // copy to dest buffer - uint8_t lgvalue = strlen(me->value); - strlcpy(value, me->value , lgvalue + 1 ); - return ( value ); + // Check back checksum + if (me->checksum == calcChecksum(me->name, me->value)) { + // copy to dest buffer + uint8_t lgvalue = strlen(me->value); + strlcpy(value, me->value , lgvalue + 1 ); + return ( value ); + } } } } @@ -494,10 +510,13 @@ char * TInfo::valueGet_P(const char * name, char * value) if (lgname==strlen(me->name) && strcmp_P(me->name, name)==0) { // this one has a value ? if (me->value) { - // copy to dest buffer - uint8_t lgvalue = strlen(me->value); - strlcpy(value, me->value , lgvalue + 1 ); - return ( value ); + // Check back checksum + if (me->checksum == calcChecksum(me->name, me->value)) { + // copy to dest buffer + uint8_t lgvalue = strlen(me->value); + strlcpy(value, me->value , lgvalue + 1 ); + return ( value ); + } } } } @@ -529,6 +548,7 @@ uint8_t TInfo::valuesDump(void) // Get our linked list ValueList * me = &_valueslist; uint8_t index = 0; + uint8_t checksum=0; // Got one ? if (me) { @@ -541,7 +561,7 @@ uint8_t TInfo::valuesDump(void) TI_Debug(index) ; TI_Debug(F(") ")) ; - if (me->name) { + if (me->name ) { TI_Debug(me->name) ; } else { TI_Debug(F("NULL")) ; @@ -555,9 +575,17 @@ uint8_t TInfo::valuesDump(void) TI_Debug(F("NULL")) ; } + if (me->name && me->value && *me->name && *me->value) { + checksum = calcChecksum(me->name, me->value); + } + TI_Debug(F(" '")) ; TI_Debug(me->checksum) ; - TI_Debug(F("' ")); + if (me->checksum != checksum ) { + TI_Debug(F("'!Err ")); + } else { + TI_Debug(F("' ")); + } // Flags management if ( me->flags) { @@ -663,22 +691,51 @@ LF etiquette HT donnee HT Chk CR ====================================================================== */ unsigned char TInfo::calcChecksum(char *etiquette, char *valeur, char * horodate) { + char c; uint8_t sum = (_mode == TINFO_MODE_HISTORIQUE) ? _separator : (2 * _separator); // Somme des codes ASCII du message + 2 separateurs // avoid dead loop, always check all is fine if (etiquette && valeur) { // this will not hurt and may save our life ;-) if (strlen(etiquette) && strlen(valeur)) { - while (*etiquette) - sum += *etiquette++ ; + while (*etiquette) { + c =*etiquette++; + // Add another validity check since checksum may not be sufficient + if ( (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='-' || c=='+') { + sum += c ; + } else { + return 0; + } + } - while(*valeur) - sum += *valeur++ ; + while(*valeur) { + c = *valeur++ ; + // Add another validity check since checksum may not be sufficient (space authorized in Standard mode) + if ( (c>='A' && c<='Z') || (c>='0' && c<='9') || c==' ' || c=='.' || c=='-' || c=='+' || c=='/') { + sum += c ; + } else { + return 0; + } + } if (horodate) { sum += _separator; - while (*horodate) - sum += *horodate++ ; + c = *horodate++; + // Add another validity check starting season [E]té (Summer) or [H]iver (Winter) + if ( c=='E' || c=='H' || c=='e' || c=='h') { + sum += c ; + while (*horodate) { + c = *horodate++ ; + // Add another validity check for horodate digits + if ( c>='0' && c<='9') { + sum += c ; + } else { + return 0; + } + } + } else { + return 0; + } } return ( (sum & 0x3f) + ' ' ) ; @@ -798,6 +855,7 @@ ValueList * TInfo::checkLine(char * pline) // 2 Label + Space + 1 etiquette + space + checksum + \r if ( len < 7 || len >= TINFO_BUFSIZE) { //AddLog(3, PSTR("LibTeleinfo: Error len < 7 || len >= TINFO_BUFSIZE")); + _framesizeerror++; return NULL; } @@ -876,7 +934,8 @@ ValueList * TInfo::checkLine(char * pline) // Always check to avoid bad behavior if(strlen(ptok) && strlen(pvalue)) { // Is checksum is OK - char calc_checksum = calcChecksum(ptok,pvalue,pts); + char calc_checksum = calcChecksum(ptok,pvalue,pts); + if ( calc_checksum == checksum) { // In case we need to do things on specific labels customLabel(ptok, pvalue, &flags); @@ -904,9 +963,18 @@ ValueList * TInfo::checkLine(char * pline) } else { - AddLog(1, PSTR("LibTeleinfo::checkLine Err checksum 0x%02X != 0x%02X"), calc_checksum, checksum); + _checksumerror++; + AddLog(1, PSTR("LibTeleinfo::checkLine Err checksum 0x%02X != 0x%02X (total errors=%d)"), calc_checksum, checksum, _checksumerror); } } + } + else + { + // Specific field not formated has others, don't set as an error + if ( strcmp(ptok, "DATE") ) { + _frameformaterror++; + AddLog(1, PSTR("LibTeleinfo::checkLine frame format error total=%d"), _frameformaterror); + } } } // Next char @@ -948,7 +1016,17 @@ _State_e TInfo::process(char c) _state = TINFO_WAIT_ETX; } break; - + + // frame interruption + case TINFO_EOT: + //AddLog(3, PSTR("LibTeleinfo: case TINFO_EOT >>>>>>>>>>>>>>>>>>")); + // discard incomplete frame + // Clear buffer, begin to store in it + clearBuffer(); + _frameinterrupted++; + _state = TINFO_WAIT_STX; + break; + // End of transmission ? case TINFO_ETX: //AddLog(3, PSTR("LibTeleinfo: case TINFO_ETX >>>>>>>>>>>>>>>>>>")); @@ -1002,8 +1080,12 @@ _State_e TInfo::process(char c) // Are we ready to process ? if (_state == TINFO_READY) { // Store data recceived (we'll need it) - if ( _recv_idx < TINFO_BUFSIZE) + if ( _recv_idx < TINFO_BUFSIZE) { _recv_buff[_recv_idx++]=c; + } else { + // group is too big (some ETX missing) + _framesizeerror++; + } // clear the end of buffer (paranoia inside) memset(&_recv_buff[_recv_idx], 0, TINFO_BUFSIZE-_recv_idx); diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h index 3c947b5ca..8ac4ad034 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h @@ -74,14 +74,6 @@ void AddLog(uint32_t loglevel, PGM_P formatP, ...); #define TI_Debugflush {} #endif -// For 4 bytes Aligment boundaries -#if defined (ESP8266) || defined (ESP32) -#define ESP_allocAlign(size) ((size + 3) & ~((size_t) 3)) -#endif - -#pragma pack(push) // push current alignment to stack -#pragma pack(1) // set alignment to 1 byte boundary - // Linked list structure containing all values received typedef struct _ValueList ValueList; struct _ValueList @@ -94,8 +86,6 @@ struct _ValueList char * value; // value }; -#pragma pack(pop) - // Library state machine enum _Mode_e { TINFO_MODE_HISTORIQUE, // Legacy mode (1200) @@ -125,6 +115,7 @@ enum _State_e { // Teleinfo start and end of frame characters #define TINFO_STX 0x02 #define TINFO_ETX 0x03 +#define TINFO_EOT 0x04 // frame interrupt (End Of Transmission) #define TINFO_HT 0x09 #define TINFO_SGR '\n' // start of group #define TINFO_EGR '\r' // End of group @@ -151,7 +142,12 @@ class TInfo char * valueGet_P(const char * name, char * value); int labelCount(); boolean listDelete(); + void clearStats(); unsigned char calcChecksum(char *etiquette, char *valeur, char *horodate=NULL) ; + uint32_t getChecksumErrorCount() { return _checksumerror; }; + uint32_t getFrameSizeErrorCount() { return _framesizeerror; }; + uint32_t getFrameFormatErrorCount() { return _frameformaterror; }; + uint32_t getFrameInterruptedCount() { return _frameinterrupted; }; private: void clearBuffer(); @@ -169,6 +165,13 @@ class TInfo char _separator; uint8_t _recv_idx; // index in receive buffer boolean _frame_updated; // Data on the frame has been updated + + // Frame counters stats + uint32_t _checksumerror; + uint32_t _framesizeerror; + uint32_t _frameformaterror; + uint32_t _frameinterrupted; + void (*_fn_ADPS)(uint8_t phase, char * label); void (*_fn_data)(ValueList * valueslist, uint8_t state); void (*_fn_new_frame)(ValueList * valueslist); diff --git a/lib/lib_div/ams/GcmParser.cpp b/lib/lib_div/ams/GcmParser.cpp index cbdf130fe..12ac94a2b 100644 --- a/lib/lib_div/ams/GcmParser.cpp +++ b/lib/lib_div/ams/GcmParser.cpp @@ -51,6 +51,10 @@ int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) { ptr += 3; headersize += 3; } else if(((*ptr) & 0xFF) == 0x4f) { + // ???????? single frame did only decode with this compare + ptr++; + headersize++; + } else if(((*ptr) & 0xFF) == 0x5e) { // ???????? single frame did only decode with this compare ptr++; headersize++; diff --git a/lib/lib_div/rfid-1.4.7/src/MFRC522.cpp b/lib/lib_div/rfid-1.4.7/src/MFRC522.cpp index a4f70e6dd..fbae40085 100644 --- a/lib/lib_div/rfid-1.4.7/src/MFRC522.cpp +++ b/lib/lib_div/rfid-1.4.7/src/MFRC522.cpp @@ -130,7 +130,7 @@ void MFRC522::PCD_ReadRegister( PCD_Register reg, ///< The register to read from */ void MFRC522::PCD_SetRegisterBitMask( PCD_Register reg, ///< The register to update. One of the PCD_Register enums. byte mask ///< The bits to set. - ) { + ) { byte tmp; tmp = PCD_ReadRegister(reg); PCD_WriteRegister(reg, tmp | mask); // set bit mask @@ -150,7 +150,7 @@ void MFRC522::PCD_ClearRegisterBitMask( PCD_Register reg, ///< The register to u /** * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to the data to transfer to the FIFO for CRC calculation. @@ -162,7 +162,7 @@ MFRC522::StatusCode MFRC522::PCD_CalculateCRC( byte *data, ///< In: Pointer to PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation - + // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73μs. // TODO check/modify for other architectures than Arduino Uno 16bit @@ -196,12 +196,12 @@ void MFRC522::PCD_Init() { // Set the chipSelectPin as digital output, do not select the slave yet pinMode(_chipSelectPin, OUTPUT); digitalWrite(_chipSelectPin, HIGH); - + // If a valid pin number has been set, pull device out of power down / reset state. if (_resetPowerDownPin != UNUSED_PIN) { // First set the resetPowerDownPin as digital input, to check the MFRC522 power down mode. pinMode(_resetPowerDownPin, INPUT); - + if (digitalRead(_resetPowerDownPin) == LOW) { // The MFRC522 chip is in power down mode. pinMode(_resetPowerDownPin, OUTPUT); // Now set the resetPowerDownPin as digital output. digitalWrite(_resetPowerDownPin, LOW); // Make sure we have a clean LOW state. @@ -216,7 +216,7 @@ void MFRC522::PCD_Init() { if (!hardReset) { // Perform a soft reset if we haven't triggered a hard reset above. PCD_Reset(); } - + // Reset baud rates PCD_WriteRegister(TxModeReg, 0x00); PCD_WriteRegister(RxModeReg, 0x00); @@ -230,7 +230,7 @@ void MFRC522::PCD_Init() { PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25μs. PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. PCD_WriteRegister(TReloadRegL, 0xE8); - + PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) @@ -251,7 +251,7 @@ void MFRC522::PCD_Init( byte chipSelectPin, ///< Arduino pin connected to MFRC5 byte resetPowerDownPin ///< Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) ) { _chipSelectPin = chipSelectPin; - _resetPowerDownPin = resetPowerDownPin; + _resetPowerDownPin = resetPowerDownPin; // Set the chipSelectPin as digital output, do not select the slave yet PCD_Init(); } // End PCD_Init() @@ -262,7 +262,7 @@ void MFRC522::PCD_Init( byte chipSelectPin, ///< Arduino pin connected to MFRC5 void MFRC522::PCD_Reset() { PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command. // The datasheet does not mention how long the SoftRest command takes to complete. - // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) + // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74μs. Let us be generous: 50ms. uint8_t count = 0; do { @@ -293,7 +293,7 @@ void MFRC522::PCD_AntennaOff() { * Get the current MFRC522 Receiver Gain (RxGain[2:0]) value. * See 9.3.3.6 / table 98 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf * NOTE: Return value scrubbed with (0x07<<4)=01110000b as RCFfgReg may use reserved bits. - * + * * @return Value of the RxGain, scrubbed to the 3 bits used. */ byte MFRC522::PCD_GetAntennaGain() { @@ -315,29 +315,29 @@ void MFRC522::PCD_SetAntennaGain(byte mask) { /** * Performs a self-test of the MFRC522 * See 16.1.1 in http://www.nxp.com/documents/data_sheet/MFRC522.pdf - * + * * @return Whether or not the test passed. Or false if no firmware reference is available. */ bool MFRC522::PCD_PerformSelfTest() { // This follows directly the steps outlined in 16.1.1 // 1. Perform a soft reset. PCD_Reset(); - + // 2. Clear the internal buffer by writing 25 bytes of 00h byte ZEROES[25] = {0x00}; PCD_WriteRegister(FIFOLevelReg, 0x80); // flush the FIFO buffer PCD_WriteRegister(FIFODataReg, 25, ZEROES); // write 25 bytes of 00h to FIFO PCD_WriteRegister(CommandReg, PCD_Mem); // transfer to internal buffer - + // 3. Enable self-test PCD_WriteRegister(AutoTestReg, 0x09); - + // 4. Write 00h to FIFO buffer PCD_WriteRegister(FIFODataReg, 0x00); - + // 5. Start self-test by issuing the CalcCRC command PCD_WriteRegister(CommandReg, PCD_CalcCRC); - + // 6. Wait for self-test to complete byte n; for (uint8_t i = 0; i < 0xFF; i++) { @@ -354,18 +354,18 @@ bool MFRC522::PCD_PerformSelfTest() { } } PCD_WriteRegister(CommandReg, PCD_Idle); // Stop calculating CRC for new content in the FIFO. - + // 7. Read out resulting 64 bytes from the FIFO buffer. byte result[64]; PCD_ReadRegister(FIFODataReg, 64, result, 0); - + // Auto self-test done // Reset AutoTestReg register to be 0 again. Required for normal operation. PCD_WriteRegister(AutoTestReg, 0x00); - + // Determine firmware version (see section 9.3.4.8 in spec) byte version = PCD_ReadRegister(VersionReg); - + // Pick the appropriate reference values const byte *reference; switch (version) { @@ -384,14 +384,14 @@ bool MFRC522::PCD_PerformSelfTest() { default: // Unknown version return false; // abort test } - + // Verify that the results match up to our expectations for (uint8_t i = 0; i < 64; i++) { if (result[i] != pgm_read_byte(&(reference[i]))) { return false; } } - + // Test passed; all is good. return true; } // End PCD_PerformSelfTest() @@ -405,22 +405,22 @@ bool MFRC522::PCD_PerformSelfTest() { //For more details about power control, refer to the datasheet - page 33 (8.6) void MFRC522::PCD_SoftPowerDown(){//Note : Only soft power down mode is available throught software - byte val = PCD_ReadRegister(CommandReg); // Read state of the command register - val |= (1<<4);// set PowerDown bit ( bit 4 ) to 1 + byte val = PCD_ReadRegister(CommandReg); // Read state of the command register + val |= (1<<4);// set PowerDown bit ( bit 4 ) to 1 PCD_WriteRegister(CommandReg, val);//write new value to the command register } void MFRC522::PCD_SoftPowerUp(){ - byte val = PCD_ReadRegister(CommandReg); // Read state of the command register - val &= ~(1<<4);// set PowerDown bit ( bit 4 ) to 0 + byte val = PCD_ReadRegister(CommandReg); // Read state of the command register + val &= ~(1<<4);// set PowerDown bit ( bit 4 ) to 0 PCD_WriteRegister(CommandReg, val);//write new value to the command register - // wait until PowerDown bit is cleared (this indicates end of wake up procedure) - const uint32_t timeout = (uint32_t)millis() + 500;// create timer for timeout (just in case) - - while(millis()<=timeout){ // set timeout to 500 ms + // wait until PowerDown bit is cleared (this indicates end of wake up procedure) + const uint32_t timeout = (uint32_t)millis() + 500;// create timer for timeout (just in case) + + while(millis()<=timeout){ // set timeout to 500 ms val = PCD_ReadRegister(CommandReg);// Read state of the command register - if(!(val & (1<<4))){ // if powerdown bit is 0 - break;// wake up procedure is finished + if(!(val & (1<<4))){ // if powerdown bit is 0 + break;// wake up procedure is finished } } } @@ -432,7 +432,7 @@ void MFRC522::PCD_SoftPowerUp(){ /** * Executes the Transceive command. * CRC validation can only be done if backData and backLen are specified. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::PCD_TransceiveData( byte *sendData, ///< Pointer to the data to transfer to the FIFO. @@ -466,7 +466,7 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co // Prepare values for BitFramingReg byte txLastBits = validBits ? *validBits : 0; byte bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] - + PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits PCD_WriteRegister(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization @@ -476,7 +476,7 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co if (command == PCD_Transceive) { PCD_SetRegisterBitMask(BitFramingReg, 0x80); // StartSend=1, transmission of data starts } - + // Wait for the command to complete. // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. // Each iteration of the do-while-loop takes 17.86μs. @@ -495,15 +495,15 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co if (i == 0) { return STATUS_TIMEOUT; } - + // Stop now if any errors except collisions were detected. byte errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr if (errorRegValue & 0x13) { // BufferOvfl ParityErr ProtocolErr return STATUS_ERROR; } - + byte _validBits = 0; - + // If the caller wants data back, get it from the MFRC522. if (backData && backLen) { byte n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO @@ -517,12 +517,12 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co *validBits = _validBits; } } - + // Tell about collisions if (errorRegValue & 0x08) { // CollErr return STATUS_COLLISION; } - + // Perform CRC_A validation if requested. if (backData && backLen && checkCRC) { // In this case a MIFARE Classic NAK is not OK. @@ -543,14 +543,14 @@ MFRC522::StatusCode MFRC522::PCD_CommunicateWithPICC( byte command, ///< The co return STATUS_CRC_WRONG; } } - + return STATUS_OK; } // End PCD_CommunicateWithPICC() /** * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::PICC_RequestA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in @@ -562,7 +562,7 @@ MFRC522::StatusCode MFRC522::PICC_RequestA( byte *bufferATQA, ///< The buffer to /** * Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in @@ -574,16 +574,16 @@ MFRC522::StatusCode MFRC522::PICC_WakeupA( byte *bufferATQA, ///< The buffer to /** * Transmits REQA or WUPA commands. * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. - */ + */ MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command to send - PICC_CMD_REQA or PICC_CMD_WUPA byte *bufferATQA, ///< The buffer to store the ATQA (Answer to request) in byte *bufferSize ///< Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. ) { byte validBits; MFRC522::StatusCode status; - + if (bufferATQA == nullptr || *bufferSize < 2) { // The ATQA response is 2 bytes long. return STATUS_NO_ROOM; } @@ -605,7 +605,7 @@ MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command * On success: * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the ISO/IEC 14443-3 draft.) * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. - * + * * A PICC UID consists of 4, 7 or 10 bytes. * Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: * UID size Number of UID bytes Cascade levels Example of PICC @@ -613,7 +613,7 @@ MFRC522::StatusCode MFRC522::PICC_REQA_or_WUPA( byte command, ///< The command * single 4 1 MIFARE Classic * double 7 2 MIFARE Ultralight * triple 10 3 Not currently in use? - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct. Normally output, but can also be used to supply a known UID. @@ -632,13 +632,13 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct byte buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A byte bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. byte rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. - byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. + byte txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. byte *responseBuffer; byte responseLength; - + // Description of buffer structure: // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 - // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. + // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag. // Byte 3: UID-data // Byte 4: UID-data @@ -657,15 +657,15 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct // 10 bytes 1 CT uid0 uid1 uid2 // 2 CT uid3 uid4 uid5 // 3 uid6 uid7 uid8 uid9 - + // Sanity checks if (validBits > 80) { return STATUS_INVALID; } - + // Prepare MFRC522 PCD_ClearRegisterBitMask(CollReg, 0x80); // ValuesAfterColl=1 => Bits received after collision are cleared. - + // Repeat Cascade Level loop until we have a complete UID. uidComplete = false; while (!uidComplete) { @@ -676,24 +676,24 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct uidIndex = 0; useCascadeTag = validBits && uid->size > 4; // When we know that the UID has more than 4 bytes break; - + case 2: buffer[0] = PICC_CMD_SEL_CL2; uidIndex = 3; useCascadeTag = validBits && uid->size > 7; // When we know that the UID has more than 7 bytes break; - + case 3: buffer[0] = PICC_CMD_SEL_CL3; uidIndex = 6; useCascadeTag = false; // Never used in CL3. break; - + default: return STATUS_INTERNAL_ERROR; break; } - + // How many UID bits are known in this Cascade Level? currentLevelKnownBits = validBits - (8 * uidIndex); if (currentLevelKnownBits < 0) { @@ -718,7 +718,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct if (useCascadeTag) { currentLevelKnownBits += 8; } - + // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. selectDone = false; while (!selectDone) { @@ -750,11 +750,11 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct responseBuffer = &buffer[index]; responseLength = sizeof(buffer) - index; } - + // Set bit adjustments rxAlign = txLastBits; // Having a separate variable is overkill. But it makes the next line easier to read. PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] - + // Transmit the buffer and receive the response. result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign); if (result == STATUS_COLLISION) { // More than one PICC in the field => collision. @@ -766,7 +766,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct if (collisionPos == 0) { collisionPos = 32; } - if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen + if (collisionPos <= currentLevelKnownBits) { // No progress - should not happen return STATUS_INTERNAL_ERROR; } // Choose the PICC with the bit set. @@ -781,7 +781,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct } else { // STATUS_OK if (currentLevelKnownBits >= 32) { // This was a SELECT. - selectDone = true; // No more anticollision + selectDone = true; // No more anticollision // We continue below outside the while. } else { // This was an ANTICOLLISION. @@ -791,16 +791,16 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct } } } // End of while (!selectDone) - + // We do not check the CBB - it was constructed by us above. - + // Copy the found UID bytes from buffer[] to uid->uidByte[] index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] bytesToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; for (count = 0; count < bytesToCopy; count++) { uid->uidByte[uidIndex + count] = buffer[index++]; } - + // Check response SAK (Select Acknowledge) if (responseLength != 3 || txLastBits != 0) { // SAK must be exactly 24 bits (1 byte + CRC_A). return STATUS_ERROR; @@ -821,7 +821,7 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct uid->sak = responseBuffer[0]; } } // End of while (!uidComplete) - + // Set correct uid->size uid->size = 3 * cascadeLevel + 1; @@ -832,11 +832,11 @@ MFRC522::StatusCode MFRC522::PICC_Select( Uid *uid, ///< Pointer to Uid struct * Instructs a PICC in state ACTIVE(*) to go to state HALT. * * @return STATUS_OK on success, STATUS_??? otherwise. - */ + */ MFRC522::StatusCode MFRC522::PICC_HaltA() { MFRC522::StatusCode result; byte buffer[4]; - + // Build command buffer buffer[0] = PICC_CMD_HLTA; buffer[1] = 0; @@ -845,7 +845,7 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { if (result != STATUS_OK) { return result; } - + // Send the command. // The standard says: // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the @@ -872,9 +872,9 @@ MFRC522::StatusCode MFRC522::PICC_HaltA() { * For use with MIFARE Classic PICCs. * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. - * + * * All keys are set to FFFFFFFFFFFFh at chip delivery. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. */ MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B @@ -883,7 +883,7 @@ MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AU Uid *uid ///< Pointer to Uid struct. The first 4 bytes of the UID is used. ) { byte waitIRq = 0x10; // IdleIRq - + // Build command buffer byte sendData[12]; sendData[0] = command; @@ -898,7 +898,7 @@ MFRC522::StatusCode MFRC522::PCD_Authenticate(byte command, ///< PICC_CMD_MF_AU for (byte i = 0; i < 4; i++) { // The last 4 bytes of the UID sendData[8+i] = uid->uidByte[i+uid->size-4]; } - + // Start the authentication. return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData)); } // End PCD_Authenticate() @@ -914,18 +914,18 @@ void MFRC522::PCD_StopCrypto1() { /** * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. - * + * * For MIFARE Classic the sector containing the block must be authenticated before calling this function. - * + * * For MIFARE Ultralight only addresses 00h to 0Fh are decoded. * The MF0ICU1 returns a NAK for higher addresses. * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. - * + * * The buffer must be at least 18 bytes because a CRC_A is also returned. * Checks the CRC_A before returning STATUS_OK. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. @@ -933,12 +933,12 @@ MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: byte *bufferSize ///< Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. ) { MFRC522::StatusCode result; - + // Sanity check if (buffer == nullptr || *bufferSize < 18) { return STATUS_NO_ROOM; } - + // Build command buffer buffer[0] = PICC_CMD_MF_READ; buffer[1] = blockAddr; @@ -947,20 +947,20 @@ MFRC522::StatusCode MFRC522::MIFARE_Read( byte blockAddr, ///< MIFARE Classic: if (result != STATUS_OK) { return result; } - + // Transmit the buffer and receive the response, validate CRC_A. return PCD_TransceiveData(buffer, 4, buffer, bufferSize, nullptr, 0, true); } // End MIFARE_Read() /** * Writes 16 bytes to the active PICC. - * + * * For MIFARE Classic the sector containing the block must be authenticated before calling this function. - * + * * For MIFARE Ultralight the operation is called "COMPATIBILITY WRITE". * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. - * * + * * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. @@ -968,12 +968,12 @@ MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: byte bufferSize ///< Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. ) { MFRC522::StatusCode result; - + // Sanity check if (buffer == nullptr || bufferSize < 16) { return STATUS_INVALID; } - + // Mifare Classic protocol requires two communications to perform a write. // Step 1: Tell the PICC we want to write to block blockAddr. byte cmdBuffer[2]; @@ -983,19 +983,19 @@ MFRC522::StatusCode MFRC522::MIFARE_Write( byte blockAddr, ///< MIFARE Classic: if (result != STATUS_OK) { return result; } - + // Step 2: Transfer the data result = PCD_MIFARE_Transceive(buffer, bufferSize); // Adds CRC_A and checks that the response is MF_ACK. if (result != STATUS_OK) { return result; } - + return STATUS_OK; } // End MIFARE_Write() /** * Writes a 4 byte page to the active MIFARE Ultralight PICC. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page (2-15) to write to. @@ -1003,18 +1003,18 @@ MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page byte bufferSize ///< Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. ) { MFRC522::StatusCode result; - + // Sanity check if (buffer == nullptr || bufferSize < 4) { return STATUS_INVALID; } - + // Build commmand buffer byte cmdBuffer[6]; cmdBuffer[0] = PICC_CMD_UL_WRITE; cmdBuffer[1] = page; memcpy(&cmdBuffer[2], buffer, 4); - + // Perform the write result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK. if (result != STATUS_OK) { @@ -1028,7 +1028,7 @@ MFRC522::StatusCode MFRC522::MIFARE_Ultralight_Write( byte page, ///< The page * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Use MIFARE_Transfer() to store the result in a block. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0-0xff) number. @@ -1042,7 +1042,7 @@ MFRC522::StatusCode MFRC522::MIFARE_Decrement( byte blockAddr, ///< The block (0 * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Use MIFARE_Transfer() to store the result in a block. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0-0xff) number. @@ -1056,7 +1056,7 @@ MFRC522::StatusCode MFRC522::MIFARE_Increment( byte blockAddr, ///< The block (0 * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. * Use MIFARE_Transfer() to store the result in a block. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0xff) number. @@ -1068,7 +1068,7 @@ MFRC522::StatusCode MFRC522::MIFARE_Restore( byte blockAddr ///< The block (0-0x /** * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The command to use @@ -1077,7 +1077,7 @@ MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The comman ) { MFRC522::StatusCode result; byte cmdBuffer[2]; // We only need room for 2 bytes. - + // Step 1: Tell the PICC the command and block address cmdBuffer[0] = command; cmdBuffer[1] = blockAddr; @@ -1085,13 +1085,13 @@ MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The comman if (result != STATUS_OK) { return result; } - + // Step 2: Transfer the data result = PCD_MIFARE_Transceive( (byte *)&data, 4, true); // Adds CRC_A and accept timeout as success. if (result != STATUS_OK) { return result; } - + return STATUS_OK; } // End MIFARE_TwoStepHelper() @@ -1099,14 +1099,14 @@ MFRC522::StatusCode MFRC522::MIFARE_TwoStepHelper( byte command, ///< The comman * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0xff) number. ) { MFRC522::StatusCode result; byte cmdBuffer[2]; // We only need room for 2 bytes. - + // Tell the PICC we want to transfer the result into block blockAddr. cmdBuffer[0] = PICC_CMD_MF_TRANSFER; cmdBuffer[1] = blockAddr; @@ -1119,11 +1119,11 @@ MFRC522::StatusCode MFRC522::MIFARE_Transfer( byte blockAddr ///< The block (0-0 /** * Helper routine to read the current value from a Value Block. - * + * * Only for MIFARE Classic and only for blocks in "value block" mode, that * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing - * the block must be authenticated before calling this function. - * + * the block must be authenticated before calling this function. + * * @param[in] blockAddr The block (0x00-0xff) number. * @param[out] value Current value of the Value Block. * @return STATUS_OK on success, STATUS_??? otherwise. @@ -1132,7 +1132,7 @@ MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, int32_t *value) { MFRC522::StatusCode status; byte buffer[18]; byte size = sizeof(buffer); - + // Read the block status = MIFARE_Read(blockAddr, buffer, &size); if (status == STATUS_OK) { @@ -1144,18 +1144,18 @@ MFRC522::StatusCode MFRC522::MIFARE_GetValue(byte blockAddr, int32_t *value) { /** * Helper routine to write a specific value into a Value Block. - * + * * Only for MIFARE Classic and only for blocks in "value block" mode, that * is: with access bits [C1 C2 C3] = [110] or [001]. The sector containing - * the block must be authenticated before calling this function. - * + * the block must be authenticated before calling this function. + * * @param[in] blockAddr The block (0x00-0xff) number. * @param[in] value New value of the Value Block. * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::MIFARE_SetValue(byte blockAddr, int32_t value) { byte buffer[18]; - + // Translate the int32_t into 4 bytes; repeated 2x in value block buffer[0] = buffer[ 8] = (value & 0xFF); buffer[1] = buffer[ 9] = (value & 0xFF00) >> 8; @@ -1169,16 +1169,16 @@ MFRC522::StatusCode MFRC522::MIFARE_SetValue(byte blockAddr, int32_t value) { // Address 2x with inverse address 2x buffer[12] = buffer[14] = blockAddr; buffer[13] = buffer[15] = ~blockAddr; - + // Write the whole data block return MIFARE_Write(blockAddr, buffer, 16); } // End MIFARE_SetValue() /** * Authenticate with a NTAG216. - * + * * Only for NTAG216. First implemented by Gargantuanman. - * + * * @param[in] passWord password. * @param[in] pACK result success???. * @return STATUS_OK on success, STATUS_??? otherwise. @@ -1190,32 +1190,32 @@ MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Aut MFRC522::StatusCode result; byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. - + cmdBuffer[0] = 0x1B; //Comando de autentificacion - + for (byte i = 0; i<4; i++) cmdBuffer[i+1] = passWord[i]; - + result = PCD_CalculateCRC(cmdBuffer, 5, &cmdBuffer[5]); - + if (result!=STATUS_OK) { return result; } - + // Transceive the data, store the reply in cmdBuffer[] byte waitIRq = 0x30; // RxIRq and IdleIRq // byte cmdBufferSize = sizeof(cmdBuffer); byte validBits = 0; byte rxlength = 5; result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, 7, cmdBuffer, &rxlength, &validBits); - + pACK[0] = cmdBuffer[0]; pACK[1] = cmdBuffer[1]; - + if (result!=STATUS_OK) { return result; } - + return STATUS_OK; } // End PCD_NTAG216_AUTH() @@ -1227,7 +1227,7 @@ MFRC522::StatusCode MFRC522::PCD_NTAG216_AUTH(byte* passWord, byte pACK[]) //Aut /** * Wrapper for MIFARE protocol communication. * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. - * + * * @return STATUS_OK on success, STATUS_??? otherwise. */ MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. @@ -1236,20 +1236,20 @@ MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointe ) { MFRC522::StatusCode result; byte cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. - + // Sanity check if (sendData == nullptr || sendLen > 16) { return STATUS_INVALID; } - + // Copy sendData[] to cmdBuffer[] and add CRC_A memcpy(cmdBuffer, sendData, sendLen); result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]); - if (result != STATUS_OK) { + if (result != STATUS_OK) { return result; } sendLen += 2; - + // Transceive the data, store the reply in cmdBuffer[] byte waitIRq = 0x30; // RxIRq and IdleIRq byte cmdBufferSize = sizeof(cmdBuffer); @@ -1273,9 +1273,10 @@ MFRC522::StatusCode MFRC522::PCD_MIFARE_Transceive( byte *sendData, ///< Pointe /** * Returns a __FlashStringHelper pointer to a status code name. - * + * * @return const __FlashStringHelper * */ +/* const __FlashStringHelper *MFRC522::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. ) { switch (code) { @@ -1291,15 +1292,31 @@ const __FlashStringHelper *MFRC522::GetStatusCodeName(MFRC522::StatusCode code / default: return F("Unknown error"); } } // End GetStatusCodeName() +*/ +String MFRC522::GetStatusCodeName(MFRC522::StatusCode code ///< One of the StatusCode enums. + ) { + switch (code) { + case STATUS_OK: return F("Success."); + case STATUS_ERROR: return F("Error in communication."); + case STATUS_COLLISION: return F("Collision detected."); + case STATUS_TIMEOUT: return F("Timeout in communication."); + case STATUS_NO_ROOM: return F("A buffer is not big enough."); + case STATUS_INTERNAL_ERROR: return F("Internal error in the code. Should not happen."); + case STATUS_INVALID: return F("Invalid argument."); + case STATUS_CRC_WRONG: return F("The CRC_A does not match."); + case STATUS_MIFARE_NACK: return F("A MIFARE PICC responded with NAK."); + default: return F("Unknown error"); + } +} // End GetStatusCodeName() /** * Translates the SAK (Select Acknowledge) to a PICC type. - * + * * @return PICC_Type */ MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak ///< The SAK byte returned from PICC_Select(). ) { - // http://www.nxp.com/documents/application_note/AN10833.pdf + // http://www.nxp.com/documents/application_note/AN10833.pdf // 3.2 Coding of Select Acknowledge (SAK) // ignore 8-bit (iso14443 starts with LSBit = bit 1) // fixes wrong type for manufacturer Infineon (http://nfc-tools.org/index.php?title=ISO14443A) @@ -1321,9 +1338,10 @@ MFRC522::PICC_Type MFRC522::PICC_GetType(byte sak ///< The SAK byte returned fr /** * Returns a __FlashStringHelper pointer to the PICC type name. - * + * * @return const __FlashStringHelper * */ +/* const __FlashStringHelper *MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One of the PICC_Type enums. ) { switch (piccType) { @@ -1341,6 +1359,24 @@ const __FlashStringHelper *MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One default: return F("Unknown type"); } } // End PICC_GetTypeName() +*/ +String MFRC522::PICC_GetTypeName(PICC_Type piccType ///< One of the PICC_Type enums. + ) { + switch (piccType) { + case PICC_TYPE_ISO_14443_4: return F("PICC compliant with ISO/IEC 14443-4"); + case PICC_TYPE_ISO_18092: return F("PICC compliant with ISO/IEC 18092 (NFC)"); + case PICC_TYPE_MIFARE_MINI: return F("MIFARE Mini, 320 bytes"); + case PICC_TYPE_MIFARE_1K: return F("MIFARE 1KB"); + case PICC_TYPE_MIFARE_4K: return F("MIFARE 4KB"); + case PICC_TYPE_MIFARE_UL: return F("MIFARE Ultralight or Ultralight C"); + case PICC_TYPE_MIFARE_PLUS: return F("MIFARE Plus"); + case PICC_TYPE_MIFARE_DESFIRE: return F("MIFARE DESFire"); + case PICC_TYPE_TNP3XXX: return F("MIFARE TNP3XXX"); + case PICC_TYPE_NOT_COMPLETE: return F("SAK indicates UID is not complete."); + case PICC_TYPE_UNKNOWN: + default: return F("Unknown type"); + } +} // End PICC_GetTypeName() /** * Dumps debug info about the connected PCD to Serial. @@ -1368,15 +1404,15 @@ void MFRC522::PCD_DumpVersionToSerial() { /** * Dumps debug info about the selected PICC to Serial. * On success the PICC is halted after dumping the data. - * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. + * For MIFARE Classic the factory default key of 0xFFFFFFFFFFFF is tried. */ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned from a successful PICC_Select(). ) { MIFARE_Key key; - + // Dump UID, SAK and Type PICC_DumpDetailsToSerial(uid); - + // Dump contents PICC_Type piccType = PICC_GetType(uid->sak); switch (piccType) { @@ -1389,11 +1425,11 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro } PICC_DumpMifareClassicToSerial(uid, piccType, &key); break; - + case PICC_TYPE_MIFARE_UL: PICC_DumpMifareUltralightToSerial(); break; - + case PICC_TYPE_ISO_14443_4: case PICC_TYPE_MIFARE_DESFIRE: case PICC_TYPE_ISO_18092: @@ -1401,13 +1437,13 @@ void MFRC522::PICC_DumpToSerial(Uid *uid ///< Pointer to Uid struct returned fro case PICC_TYPE_TNP3XXX: Serial.println(F("Dumping memory contents not implemented for that PICC type.")); break; - + case PICC_TYPE_UNKNOWN: case PICC_TYPE_NOT_COMPLETE: default: break; // No memory dump here } - + Serial.println(); PICC_HaltA(); // Already done if it was a MIFARE Classic PICC. } // End PICC_DumpToSerial() @@ -1425,15 +1461,15 @@ void MFRC522::PICC_DumpDetailsToSerial(Uid *uid ///< Pointer to Uid struct retur else Serial.print(F(" ")); Serial.print(uid->uidByte[i], HEX); - } + } Serial.println(); - + // SAK Serial.print(F("Card SAK: ")); if(uid->sak < 0x10) Serial.print(F("0")); Serial.println(uid->sak, HEX); - + // (suggested) PICC type PICC_Type piccType = PICC_GetType(uid->sak); Serial.print(F("PICC type: ")); @@ -1454,21 +1490,21 @@ void MFRC522::PICC_DumpMifareClassicToSerial( Uid *uid, ///< Pointer to Uid st // Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. no_of_sectors = 5; break; - + case PICC_TYPE_MIFARE_1K: // Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. no_of_sectors = 16; break; - + case PICC_TYPE_MIFARE_4K: // Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. no_of_sectors = 40; break; - + default: // Should not happen. Ignore. break; } - + // Dump sectors, highest address first. if (no_of_sectors) { Serial.println(F("Sector Block 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 AccessBits")); @@ -1493,7 +1529,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U byte firstBlock; // Address of lowest address to dump actually last block dumped) byte no_of_blocks; // Number of blocks in sector bool isSectorTrailer; // Set to true while handling the "last" (ie highest address) in the sector. - + // The access bits are stored in a peculiar fashion. // There are four groups: // g[3] Access bits for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) @@ -1508,7 +1544,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U byte g[4]; // Access bits for each of the four groups. byte group; // 0-3 - active group for access bits bool firstInGroup; // True for the first block dumped in the group - + // Determine position and size of sector. if (sector < 32) { // Sectors 0..31 has 4 blocks each no_of_blocks = 4; @@ -1521,7 +1557,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U else { // Illegal input, no MIFARE Classic PICC has more than 40 sectors. return; } - + // Dump blocks, highest address first. byte byteCount; byte buffer[18]; @@ -1558,7 +1594,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U status = PCD_Authenticate(PICC_CMD_MF_AUTH_KEY_A, firstBlock, key, uid); if (status != STATUS_OK) { Serial.print(F("PCD_Authenticate() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); return; } } @@ -1567,7 +1603,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U status = MIFARE_Read(blockAddr, buffer, &byteCount); if (status != STATUS_OK) { Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); continue; } // Dump data @@ -1596,7 +1632,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U g[3] = ((c1 & 8) >> 1) | ((c2 & 8) >> 2) | ((c3 & 8) >> 3); isSectorTrailer = false; } - + // Which access group is this block in? if (no_of_blocks == 4) { group = blockOffset; @@ -1606,7 +1642,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U group = blockOffset / 5; firstInGroup = (group == 3) || (group != (blockOffset + 1) / 5); } - + if (firstInGroup) { // Print access bits Serial.print(F(" [ ")); @@ -1618,7 +1654,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U Serial.print(F(" Inverted access bits did not match! ")); } } - + if (group != 3 && (g[group] == 1 || g[group] == 6)) { // Not a sector trailer, a value block int32_t value = (int32_t(buffer[3])<<24) | (int32_t(buffer[2])<<16) | (int32_t(buffer[1])<<8) | int32_t(buffer[0]); Serial.print(F(" Value=0x")); Serial.print(value, HEX); @@ -1626,7 +1662,7 @@ void MFRC522::PICC_DumpMifareClassicSectorToSerial(Uid *uid, ///< Pointer to U } Serial.println(); } - + return; } // End PICC_DumpMifareClassicSectorToSerial() @@ -1638,7 +1674,7 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() { byte byteCount; byte buffer[18]; byte i; - + Serial.println(F("Page 0 1 2 3")); // Try the mpages of the original Ultralight. Ultralight C has more pages. for (byte page = 0; page < 16; page +=4) { // Read returns data for 4 pages at a time. @@ -1647,7 +1683,7 @@ void MFRC522::PICC_DumpMifareUltralightToSerial() { status = MIFARE_Read(page, buffer, &byteCount); if (status != STATUS_OK) { Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); break; } // Dump data @@ -1684,7 +1720,7 @@ void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte byte c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); byte c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); byte c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0); - + accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF); accessBitBuffer[2] = c3 << 4 | c2; @@ -1699,7 +1735,7 @@ void MFRC522::MIFARE_SetAccessBits( byte *accessBitBuffer, ///< Pointer to byte * this sequence works immediately when the card is in the reader vicinity. * This means you can use this method even on "bricked" cards that your reader does * not recognise anymore (see MFRC522::MIFARE_UnbrickUidSector). - * + * * Of course with non-bricked devices, you're free to select them before calling this function. */ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { @@ -1710,9 +1746,9 @@ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { // > 43 // < A (4 bits only) // Then you can write to sector 0 without authenticating - + PICC_HaltA(); // 50 00 57 CD - + byte cmd = 0x40; byte validBits = 7; /* Our command is only 7 bits. After receiving card response, this will contain amount of valid response bits. */ @@ -1723,7 +1759,7 @@ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { if(logErrors) { Serial.println(F("Card did not respond to 0x40 after HALT command. Are you sure it is a UID changeable one?")); Serial.print(F("Error name: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); } return false; } @@ -1737,7 +1773,7 @@ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { } return false; } - + cmd = 0x43; validBits = 8; status = PCD_TransceiveData(&cmd, (byte)1, response, &received, &validBits, (byte)0, false); // 43 @@ -1745,7 +1781,7 @@ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { if(logErrors) { Serial.println(F("Error in communication at command 0x43, after successfully executing 0x40")); Serial.print(F("Error name: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); } return false; } @@ -1759,7 +1795,7 @@ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { } return false; } - + // You can now write to sector 0 without authenticating! return true; } // End MIFARE_OpenUidBackdoor() @@ -1773,7 +1809,7 @@ bool MFRC522::MIFARE_OpenUidBackdoor(bool logErrors) { * Make sure to have selected the card before this function is called. */ bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { - + // UID + BCC byte can not be larger than 16 together if (!newUid || !uidSize || uidSize > 15) { if (logErrors) { @@ -1781,31 +1817,31 @@ bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { } return false; } - + // Authenticate for reading MIFARE_Key key = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; MFRC522::StatusCode status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); if (status != STATUS_OK) { - + if (status == STATUS_TIMEOUT) { // We get a read timeout if no card is selected yet, so let's select one - + // Wake the card up again if sleeping // byte atqa_answer[2]; // byte atqa_size = 2; // PICC_WakeupA(atqa_answer, &atqa_size); - + if (!PICC_IsNewCardPresent() || !PICC_ReadCardSerial()) { Serial.println(F("No card was previously selected, and none are available. Failed to set UID.")); return false; } - + status = PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, (byte)1, &key, &uid); if (status != STATUS_OK) { // We tried, time to give up if (logErrors) { Serial.println(F("Failed to authenticate to card for reading, could not set UID: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); } return false; } @@ -1813,12 +1849,12 @@ bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { else { if (logErrors) { Serial.print(F("PCD_Authenticate() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); } return false; } } - + // Read block 0 byte block0_buffer[18]; byte byteCount = sizeof(block0_buffer); @@ -1826,25 +1862,25 @@ bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { if (status != STATUS_OK) { if (logErrors) { Serial.print(F("MIFARE_Read() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); Serial.println(F("Are you sure your KEY A for sector 0 is 0xFFFFFFFFFFFF?")); } return false; } - + // Write new UID to the data we just read, and calculate BCC byte byte bcc = 0; for (uint8_t i = 0; i < uidSize; i++) { block0_buffer[i] = newUid[i]; bcc ^= newUid[i]; } - + // Write BCC byte to buffer block0_buffer[uidSize] = bcc; - + // Stop encrypted traffic so we can send raw bytes PCD_StopCrypto1(); - + // Activate UID backdoor if (!MIFARE_OpenUidBackdoor(logErrors)) { if (logErrors) { @@ -1852,22 +1888,22 @@ bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { } return false; } - + // Write modified block 0 back to card status = MIFARE_Write((byte)0, block0_buffer, (byte)16); if (status != STATUS_OK) { if (logErrors) { Serial.print(F("MIFARE_Write() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); } return false; } - + // Wake the card up again byte atqa_answer[2]; byte atqa_size = 2; PICC_WakeupA(atqa_answer, &atqa_size); - + return true; } @@ -1876,15 +1912,15 @@ bool MFRC522::MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors) { */ bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { MIFARE_OpenUidBackdoor(logErrors); - - byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - + + byte block0_buffer[] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + // Write modified block 0 back to card MFRC522::StatusCode status = MIFARE_Write((byte)0, block0_buffer, (byte)16); if (status != STATUS_OK) { if (logErrors) { Serial.print(F("MIFARE_Write() failed: ")); - Serial.println(GetStatusCodeName(status)); + Serial.println(GetStatusCodeName(status).c_str()); } return false; } @@ -1898,7 +1934,7 @@ bool MFRC522::MIFARE_UnbrickUidSector(bool logErrors) { /** * Returns true if a PICC responds to PICC_CMD_REQA. * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. - * + * * @return bool */ bool MFRC522::PICC_IsNewCardPresent() { @@ -1920,10 +1956,10 @@ bool MFRC522::PICC_IsNewCardPresent() { * Returns true if a UID could be read. * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. * The read UID is available in the class variable uid. - * + * * @return bool */ bool MFRC522::PICC_ReadCardSerial() { MFRC522::StatusCode result = PICC_Select(&uid); return (result == STATUS_OK); -} // End +} // End diff --git a/lib/lib_div/rfid-1.4.7/src/MFRC522.h b/lib/lib_div/rfid-1.4.7/src/MFRC522.h index 5ebbd27dd..f04dd966d 100644 --- a/lib/lib_div/rfid-1.4.7/src/MFRC522.h +++ b/lib/lib_div/rfid-1.4.7/src/MFRC522.h @@ -1,10 +1,10 @@ /** * Library to use Arduino MFRC522 module. - * + * * @authors Dr.Leong, Miguel Balboa, Søren Thing Andersen, Tom Clement, many more! See GitLog. - * + * * For more information read the README. - * + * * Please read this file for an overview and then MFRC522.cpp for comments on the specific functions. */ #ifndef MFRC522_h @@ -92,7 +92,7 @@ public: DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits ComIrqReg = 0x04 << 1, // interrupt request bits DivIrqReg = 0x05 << 1, // interrupt request bits - ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed + ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed Status1Reg = 0x07 << 1, // communication status bits Status2Reg = 0x08 << 1, // receiver and transmitter status bits FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer @@ -102,10 +102,10 @@ public: BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface // 0x0F // reserved for future use - + // Page 1: Command // 0x10 // reserved for future use - ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving + ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving TxModeReg = 0x12 << 1, // defines transmission data rate and framing RxModeReg = 0x13 << 1, // defines reception data rate and framing TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2 @@ -120,7 +120,7 @@ public: MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters // 0x1E // reserved for future use SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface - + // Page 2: Configuration // 0x20 // reserved for future use CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation @@ -129,7 +129,7 @@ public: ModWidthReg = 0x24 << 1, // controls the ModWidth setting? // 0x25 // reserved for future use RFCfgReg = 0x26 << 1, // configures the receiver gain - GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation + GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation TModeReg = 0x2A << 1, // defines settings for the internal timer @@ -138,7 +138,7 @@ public: TReloadRegL = 0x2D << 1, TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value TCounterValueRegL = 0x2F << 1, - + // Page 3: Test Registers // 0x30 // reserved for future use TestSel1Reg = 0x31 << 1, // general test signal configuration @@ -157,7 +157,7 @@ public: // 0x3E // reserved for production tests // 0x3F // reserved for production tests }; - + // MFRC522 commands. Described in chapter 10 of the datasheet. enum PCD_Command : byte { PCD_Idle = 0x00, // no action, cancels current command execution @@ -171,7 +171,7 @@ public: PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader PCD_SoftReset = 0x0F // resets the MFRC522 }; - + // MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD). // Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf enum PCD_RxGain : byte { @@ -187,7 +187,7 @@ public: RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB }; - + // Commands sent to the PICC. enum PICC_Command : byte { // The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) @@ -214,18 +214,18 @@ public: // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC. }; - + // MIFARE constants that does not fit anywhere else enum MIFARE_Misc { MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes. }; - + // PICC types we can detect. Remember to update PICC_GetTypeName() if you add more. // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered enum PICC_Type : byte { PICC_TYPE_UNKNOWN , - PICC_TYPE_ISO_14443_4 , // PICC compliant with ISO/IEC 14443-4 + PICC_TYPE_ISO_14443_4 , // PICC compliant with ISO/IEC 14443-4 PICC_TYPE_ISO_18092 , // PICC compliant with ISO/IEC 18092 (NFC) PICC_TYPE_MIFARE_MINI , // MIFARE Classic protocol, 320 bytes PICC_TYPE_MIFARE_1K , // MIFARE Classic protocol, 1KB @@ -236,7 +236,7 @@ public: PICC_TYPE_TNP3XXX , // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure PICC_TYPE_NOT_COMPLETE = 0xff // SAK indicates UID is not complete. }; - + // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. // last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered enum StatusCode : byte { @@ -250,7 +250,7 @@ public: STATUS_CRC_WRONG , // The CRC_A does not match STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK. }; - + // A struct used for passing the UID of a PICC. typedef struct { byte size; // Number of bytes in the UID. 4, 7 or 10. @@ -262,17 +262,17 @@ public: typedef struct { byte keyByte[MF_KEY_SIZE]; } MIFARE_Key; - + // Member variables Uid uid; // Used by PICC_ReadCardSerial(). - + ///////////////////////////////////////////////////////////////////////////////////// // Functions for setting up the Arduino ///////////////////////////////////////////////////////////////////////////////////// MFRC522(); MFRC522(byte resetPowerDownPin); MFRC522(byte chipSelectPin, byte resetPowerDownPin); - + ///////////////////////////////////////////////////////////////////////////////////// // Basic interface functions for communicating with the MFRC522 ///////////////////////////////////////////////////////////////////////////////////// @@ -283,7 +283,7 @@ public: void PCD_SetRegisterBitMask(PCD_Register reg, byte mask); void PCD_ClearRegisterBitMask(PCD_Register reg, byte mask); StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result); - + ///////////////////////////////////////////////////////////////////////////////////// // Functions for manipulating the MFRC522 ///////////////////////////////////////////////////////////////////////////////////// @@ -296,13 +296,13 @@ public: byte PCD_GetAntennaGain(); void PCD_SetAntennaGain(byte mask); bool PCD_PerformSelfTest(); - + ///////////////////////////////////////////////////////////////////////////////////// // Power control functions ///////////////////////////////////////////////////////////////////////////////////// void PCD_SoftPowerDown(); void PCD_SoftPowerUp(); - + ///////////////////////////////////////////////////////////////////////////////////// // Functions for communicating with PICCs ///////////////////////////////////////////////////////////////////////////////////// @@ -329,19 +329,21 @@ public: StatusCode MIFARE_GetValue(byte blockAddr, int32_t *value); StatusCode MIFARE_SetValue(byte blockAddr, int32_t value); StatusCode PCD_NTAG216_AUTH(byte *passWord, byte pACK[]); - + ///////////////////////////////////////////////////////////////////////////////////// // Support functions ///////////////////////////////////////////////////////////////////////////////////// StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false); // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory //const char *GetStatusCodeName(byte code); - static const __FlashStringHelper *GetStatusCodeName(StatusCode code); +// static const __FlashStringHelper *GetStatusCodeName(StatusCode code); + String GetStatusCodeName(StatusCode code); static PICC_Type PICC_GetType(byte sak); // old function used too much memory, now name moved to flash; if you need char, copy from flash to memory //const char *PICC_GetTypeName(byte type); - static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type); - +// static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type); + String PICC_GetTypeName(PICC_Type type); + // Support functions for debuging void PCD_DumpVersionToSerial(); void PICC_DumpToSerial(Uid *uid); @@ -349,19 +351,19 @@ public: void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key); void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector); void PICC_DumpMifareUltralightToSerial(); - + // Advanced functions for MIFARE void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3); bool MIFARE_OpenUidBackdoor(bool logErrors); bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors); bool MIFARE_UnbrickUidSector(bool logErrors); - + ///////////////////////////////////////////////////////////////////////////////////// // Convenience functions - does not add extra functionality ///////////////////////////////////////////////////////////////////////////////////// virtual bool PICC_IsNewCardPresent(); virtual bool PICC_ReadCardSerial(); - + protected: byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low) byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low) diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/.gitignore b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/.gitignore new file mode 100644 index 000000000..f74c7b473 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/.gitignore @@ -0,0 +1,11 @@ +*~ +Doxyfile* +doxygen_sqlite3.db +html# osx +.DS_Store + +# doxygen +Doxyfile* +doxygen_sqlite3.db +html +*.tmp diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/Adafruit_PM25AQI.cpp b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/Adafruit_PM25AQI.cpp new file mode 100644 index 000000000..a6aee3b8e --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/Adafruit_PM25AQI.cpp @@ -0,0 +1,133 @@ +/*! + * @file Adafruit_PM25AQI.cpp + * + * @mainpage Adafruit PM2.5 air quality sensor driver + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's PM2.5 AQI driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit PM2.5 Air quality sensors: http://www.adafruit.com/products/4632 + * + * These sensors use I2C or UART to communicate. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * + * @section author Author + * Written by Ladyada for Adafruit Industries. + * + * @section license License + * BSD license, all text here must be included in any redistribution. + * + */ + +#include "Adafruit_PM25AQI.h" + +/*! + * @brief Instantiates a new PM25AQI class + */ +Adafruit_PM25AQI::Adafruit_PM25AQI() {} + +/*! + * @brief Setups the hardware and detects a valid PMSA003I. Initializes I2C. + * @param theWire + * Optional pointer to I2C interface, otherwise use Wire + * @return True if PMSA003I found on I2C, False if something went wrong! + */ +bool Adafruit_PM25AQI::begin_I2C(TwoWire *theWire) { + if (!i2c_dev) { + i2c_dev = new Adafruit_I2CDevice(PMSA003I_I2CADDR_DEFAULT, theWire); + } + + if (!i2c_dev->begin()) { + return false; + } + + return true; +} + +/*! + * @brief Setups the hardware and detects a valid UART PM2.5 + * @param theSerial + * Pointer to Stream (HardwareSerial/SoftwareSerial) interface + * @return True + */ +bool Adafruit_PM25AQI::begin_UART(Stream *theSerial) { + serial_dev = theSerial; + + return true; +} + +/*! + * @brief Setups the hardware and detects a valid UART PM2.5 + * @param data + * Pointer to PM25_AQI_Data that will be filled by read()ing + * @return True on successful read, false if timed out or bad data + */ +bool Adafruit_PM25AQI::read(PM25_AQI_Data *data) { + uint8_t buffer[32]; + uint16_t sum = 0; + + if (!data) { + return false; + } + + if (i2c_dev) { // ok using i2c? + if (!i2c_dev->read(buffer, 32)) { + return false; + } + } else if (serial_dev) { // ok using uart + if (!serial_dev->available()) { + return false; + } + int skipped = 0; + while ((skipped < 32) && (serial_dev->peek() != 0x42)) { + serial_dev->read(); + skipped++; + if (!serial_dev->available()) { + return false; + } + } + if (serial_dev->peek() != 0x42) { + serial_dev->read(); + return false; + } + // Now read all 32 bytes + if (serial_dev->available() < 32) { + return false; + } + serial_dev->readBytes(buffer, 32); + } else { + return false; + } + + // Check that start byte is correct! + if (buffer[0] != 0x42) { + return false; + } + + // get checksum ready + for (uint8_t i = 0; i < 30; i++) { + sum += buffer[i]; + } + + // The data comes in endian'd, this solves it so it works on all platforms + uint16_t buffer_u16[15]; + for (uint8_t i = 0; i < 15; i++) { + buffer_u16[i] = buffer[2 + i * 2 + 1]; + buffer_u16[i] += (buffer[2 + i * 2] << 8); + } + + // put it into a nice struct :) + memcpy((void *)data, (void *)buffer_u16, 30); + + if (sum != data->checksum) { + return false; + } + + // success! + return true; +} diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/Adafruit_PM25AQI.h b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/Adafruit_PM25AQI.h new file mode 100644 index 000000000..cd304b312 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/Adafruit_PM25AQI.h @@ -0,0 +1,65 @@ +/*! + * @file Adafruit_PM25AQI.h + * + * This is the documentation for Adafruit's PM25 AQI driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit PM25 air quality sensors: http://www.adafruit.com/products/4632 + * + * These sensors use I2C or UART to communicate. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Ladyada for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ + +#ifndef ADAFRUIT_PM25AQI_H +#define ADAFRUIT_PM25AQI_H + +#include "Arduino.h" +#include + +// the i2c address +#define PMSA003I_I2CADDR_DEFAULT 0x12 ///< PMSA003I has only one I2C address + +/**! Structure holding Plantower's standard packet **/ +typedef struct PMSAQIdata { + uint16_t framelen; ///< How long this data chunk is + uint16_t pm10_standard, ///< Standard PM1.0 + pm25_standard, ///< Standard PM2.5 + pm100_standard; ///< Standard PM10.0 + uint16_t pm10_env, ///< Environmental PM1.0 + pm25_env, ///< Environmental PM2.5 + pm100_env; ///< Environmental PM10.0 + uint16_t particles_03um, ///< 0.3um Particle Count + particles_05um, ///< 0.5um Particle Count + particles_10um, ///< 1.0um Particle Count + particles_25um, ///< 2.5um Particle Count + particles_50um, ///< 5.0um Particle Count + particles_100um; ///< 10.0um Particle Count + uint16_t unused; ///< Unused + uint16_t checksum; ///< Packet checksum +} PM25_AQI_Data; + +/*! + * @brief Class that stores state and functions for interacting with + * PM2.5 Air Quality Sensor + */ +class Adafruit_PM25AQI { +public: + Adafruit_PM25AQI(); + bool begin_I2C(TwoWire *theWire = &Wire); + bool begin_UART(Stream *theStream); + bool read(PM25_AQI_Data *data); + +private: + Adafruit_I2CDevice *i2c_dev = NULL; + Stream *serial_dev = NULL; + uint8_t _readbuffer[32]; +}; + +#endif diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/README.md b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/README.md new file mode 100644 index 000000000..527954ab4 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/README.md @@ -0,0 +1,49 @@ +# Adafruit PM2.5 Air Quality sensor [![Build Status](https://github.com/adafruit/Adafruit_PM25AQI/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_PM25AQI/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_PM25AQI/html/index.html) + +This is the Adafruit PM25AQI Arduino Library for Arduino +Tested and works great with the Adafruit PM2.5 Air Quality Sensor and Breadboard Adapter Kit + +[](https://www.adafruit.com/products/3686) + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +# Installation +To install, use the Arduino Library Manager and search for "Adafruit PM25 AQI" and install the library. + +## Dependencies + * [Adafruit BusIO](https://github.com/adafruit/Adafruit_BusIO) + +# Contributing + +Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/Adafruit_PM25AQI/blob/master/CODE_OF_CONDUCT.md>) +before contributing to help this project stay welcoming. + +## Documentation and doxygen +Documentation is produced by doxygen. Contributions should include documentation for any new code added. + +Some examples of how to use doxygen can be found in these guide pages: + +https://learn.adafruit.com/the-well-automated-arduino-library/doxygen + +https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips + +## Formatting and clang-format +This library uses [`clang-format`](https://releases.llvm.org/download.html) to standardize the formatting of `.cpp` and `.h` files. +Contributions should be formatted using `clang-format`: + +The `-i` flag will make the changes to the file. +```bash +clang-format -i *.cpp *.h +``` +If you prefer to make the changes yourself, running `clang-format` without the `-i` flag will print out a formatted version of the file. You can save this to a file and diff it against the original to see the changes. + +Note that the formatting output by `clang-format` is what the automated formatting checker will expect. Any diffs from this formatting will result in a failed build until they are addressed. Using the `-i` flag is highly recommended. + +### clang-format resources + * [Binary builds and source available on the LLVM downloads page](https://releases.llvm.org/download.html) + * [Documentation and IDE integration](https://clang.llvm.org/docs/ClangFormat.html) + +## About this Driver +Written by Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/code-of-conduct.md b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/code-of-conduct.md new file mode 100644 index 000000000..8ee6e4498 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/code-of-conduct.md @@ -0,0 +1,127 @@ +# Adafruit Community Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and leaders pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level or type of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +We are committed to providing a friendly, safe and welcoming environment for +all. + +Examples of behavior that contributes to creating a positive environment +include: + +* Be kind and courteous to others +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Collaborating with other community members +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and sexual attention or advances +* The use of inappropriate images, including in a community member's avatar +* The use of inappropriate language, including in a community member's nickname +* Any spamming, flaming, baiting or other attention-stealing behavior +* Excessive or unwelcome helping; answering outside the scope of the question + asked +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate + +The goal of the standards and moderation guidelines outlined here is to build +and maintain a respectful community. We ask that you don’t just aim to be +"technically unimpeachable", but rather try to be your best self. + +We value many things beyond technical expertise, including collaboration and +supporting others within our community. Providing a positive experience for +other community members can have a much more significant impact than simply +providing the correct answer. + +## Our Responsibilities + +Project leaders are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project leaders have the right and responsibility to remove, edit, or +reject messages, comments, commits, code, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any community member for other behaviors that they deem +inappropriate, threatening, offensive, or harmful. + +## Moderation + +Instances of behaviors that violate the Adafruit Community Code of Conduct +may be reported by any member of the community. Community members are +encouraged to report these situations, including situations they witness +involving other community members. + +You may report in the following ways: + +In any situation, you may send an email to . + +On the Adafruit Discord, you may send an open message from any channel +to all Community Helpers by tagging @community helpers. You may also send an +open message from any channel, or a direct message to @kattni#1507, +@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or +@Andon#8175. + +Email and direct message reports will be kept confidential. + +In situations on Discord where the issue is particularly egregious, possibly +illegal, requires immediate action, or violates the Discord terms of service, +you should also report the message directly to Discord. + +These are the steps for upholding our community’s standards of conduct. + +1. Any member of the community may report any situation that violates the +Adafruit Community Code of Conduct. All reports will be reviewed and +investigated. +2. If the behavior is an egregious violation, the community member who +committed the violation may be banned immediately, without warning. +3. Otherwise, moderators will first respond to such behavior with a warning. +4. Moderators follow a soft "three strikes" policy - the community member may +be given another chance, if they are receptive to the warning and change their +behavior. +5. If the community member is unreceptive or unreasonable when warned by a +moderator, or the warning goes unheeded, they may be banned for a first or +second offense. Repeated offenses will result in the community member being +banned. + +## Scope + +This Code of Conduct and the enforcement policies listed above apply to all +Adafruit Community venues. This includes but is not limited to any community +spaces (both public and private), the entire Adafruit Discord server, and +Adafruit GitHub repositories. Examples of Adafruit Community spaces include +but are not limited to meet-ups, audio chats on the Adafruit Discord, or +interaction at a conference. + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. As a community +member, you are representing our community, and are expected to behave +accordingly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +, +and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). + +For other projects adopting the Adafruit Community Code of +Conduct, please contact the maintainers of those projects for enforcement. +If you wish to use this code of conduct for your own project, consider +explicitly mentioning your moderation policy or making a copy with your +own moderation policy so as to avoid confusion. diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/examples/PM25_test/PM25_test.ino b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/examples/PM25_test/PM25_test.ino new file mode 100644 index 000000000..9b7454c20 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/examples/PM25_test/PM25_test.ino @@ -0,0 +1,73 @@ +/* Test sketch for Adafruit PM2.5 sensor with UART or I2C */ + +#include "Adafruit_PM25AQI.h" + +// If your PM2.5 is UART only, for UNO and others (without hardware serial) +// we must use software serial... +// pin #2 is IN from sensor (TX pin on sensor), leave pin #3 disconnected +// comment these two lines if using hardware serial +//#include +//SoftwareSerial pmSerial(2, 3); + +Adafruit_PM25AQI aqi = Adafruit_PM25AQI(); + +void setup() { + // Wait for serial monitor to open + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println("Adafruit PMSA003I Air Quality Sensor"); + + // Wait one second for sensor to boot up! + delay(1000); + + // If using serial, initialize it and set baudrate before starting! + // Uncomment one of the following + //Serial1.begin(9600); + //pmSerial.begin(9600); + + // There are 3 options for connectivity! + if (! aqi.begin_I2C()) { // connect to the sensor over I2C + //if (! aqi.begin_UART(&Serial1)) { // connect to the sensor over hardware serial + //if (! aqi.begin_UART(&pmSerial)) { // connect to the sensor over software serial + Serial.println("Could not find PM 2.5 sensor!"); + while (1) delay(10); + } + + Serial.println("PM25 found!"); +} + +void loop() { + PM25_AQI_Data data; + + if (! aqi.read(&data)) { + Serial.println("Could not read from AQI"); + delay(500); // try again in a bit! + return; + } + Serial.println("AQI reading success"); + + Serial.println(); + Serial.println(F("---------------------------------------")); + Serial.println(F("Concentration Units (standard)")); + Serial.println(F("---------------------------------------")); + Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_standard); + Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_standard); + Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_standard); + Serial.println(F("Concentration Units (environmental)")); + Serial.println(F("---------------------------------------")); + Serial.print(F("PM 1.0: ")); Serial.print(data.pm10_env); + Serial.print(F("\t\tPM 2.5: ")); Serial.print(data.pm25_env); + Serial.print(F("\t\tPM 10: ")); Serial.println(data.pm100_env); + Serial.println(F("---------------------------------------")); + Serial.print(F("Particles > 0.3um / 0.1L air:")); Serial.println(data.particles_03um); + Serial.print(F("Particles > 0.5um / 0.1L air:")); Serial.println(data.particles_05um); + Serial.print(F("Particles > 1.0um / 0.1L air:")); Serial.println(data.particles_10um); + Serial.print(F("Particles > 2.5um / 0.1L air:")); Serial.println(data.particles_25um); + Serial.print(F("Particles > 5.0um / 0.1L air:")); Serial.println(data.particles_50um); + Serial.print(F("Particles > 10 um / 0.1L air:")); Serial.println(data.particles_100um); + Serial.println(F("---------------------------------------")); + + + delay(1000); +} diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/library.properties b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/library.properties new file mode 100644 index 000000000..570e61d67 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/library.properties @@ -0,0 +1,10 @@ +name=Adafruit PM25 AQI Sensor +version=1.0.6 +author=Adafruit +maintainer=Adafruit +sentence=This is an Arduino library for the Adafruit PM2.5 Air Quality Sensor +paragraph=This is an Arduino library for the Adafruit PM2.5 Air Quality Sensor +category=Sensors +url=https://github.com/adafruit/Adafruit_PM25AQI +architectures=* +depends=Adafruit BusIO diff --git a/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/license.txt b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/license.txt new file mode 100644 index 000000000..f6a0f22b8 --- /dev/null +++ b/lib/lib_i2c/Adafruit_PM25AQI-1.0.6/license.txt @@ -0,0 +1,26 @@ +Software License Agreement (BSD License) + +Copyright (c) 2012, Adafruit Industries +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. 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. +3. Neither the name of the copyright holders nor the +names of its 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 ''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 HOLDER 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. diff --git a/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp b/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp index a3c798f1c..93b1008db 100644 --- a/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp +++ b/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp @@ -229,17 +229,17 @@ HTTPUpdateResult HTTPUpdateLight::handleUpdate(HTTPClientLight& http, const Stri uint32_t http_connect_time = millis(); - int code = http.GET(); - int len = http.getSize(); + int code = http.GET(); // 0 if ok or < 0 if error + int len = http.getSize(); // -1 if no info or > 0 when Content-Length is set by server // Add specific logging for Tasmota - if (len < 0) { - if (len <= -1000) { - AddLog(LOG_LEVEL_INFO, "OTA: TLS connection error %d after %d ms", -len - 1000, millis() - http_connect_time); - } else if (len == -1) { - AddLog(LOG_LEVEL_INFO, "OTA: Connection timeout after %d ms", len, millis() - http_connect_time); + if (len < 0) { // -1 if no info or > 0 when Content-Length is set by server + if (code <= -1000) { // BearSSL error 46 transformed to -1046 + AddLog(LOG_LEVEL_INFO, "OTA: TLS connection error %d after %d ms", -code - 1000, millis() - http_connect_time); + } else if (code == -1) { // HTTPC_ERROR_CONNECTION_REFUSED + AddLog(LOG_LEVEL_INFO, "OTA: Connection timeout after %d ms", millis() - http_connect_time); } else { - AddLog(LOG_LEVEL_INFO, "OTA: Connection error %d after %d ms", len, millis() - http_connect_time); + AddLog(LOG_LEVEL_INFO, "OTA: Connection error %d after %d ms", code, millis() - http_connect_time); } } else { AddLog(LOG_LEVEL_DEBUG, PSTR("OTA: Connected in %d ms, stack low mark %d"), diff --git a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h index 8c3709399..59f532d08 100644 --- a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h +++ b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h @@ -247,7 +247,7 @@ protected: /// request handling String _host; uint16_t _port = 0; - int32_t _connectTimeout = -1; + int32_t _connectTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; // Do not set to -1 as it fails WiFiClient connect() bool _reuse = true; uint16_t _tcpTimeout = HTTPCLIENT_DEFAULT_TCP_TIMEOUT; bool _useHTTP10 = false; diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp index e2522942d..d5d8edb3c 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp @@ -137,10 +137,10 @@ int WiFiClass32::getPhyMode() { int phy_mode = 0; // " BGNL" uint8_t protocol_bitmap; if (esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap) == ESP_OK) { - if (protocol_bitmap & 1) { phy_mode = WIFI_PHY_MODE_11B; } // 1 = 11b - if (protocol_bitmap & 2) { phy_mode = WIFI_PHY_MODE_11G; } // 2 = 11bg - if (protocol_bitmap & 4) { phy_mode = WIFI_PHY_MODE_11N; } // 3 = 11bgn - if (protocol_bitmap & 8) { phy_mode = 4; } // Low rate + if (protocol_bitmap & 1) { phy_mode = TAS_WIFI_PHY_MODE_11B; } // 1 = 11b (WIFI_PHY_MODE_11B) + if (protocol_bitmap & 2) { phy_mode = TAS_WIFI_PHY_MODE_11G; } // 2 = 11bg (WIFI_PHY_MODE_11G) + if (protocol_bitmap & 4) { phy_mode = TAS_WIFI_PHY_MODE_11N; } // 3 = 11bgn (WIFI_PHY_MODE_11N) + if (protocol_bitmap & 8) { phy_mode = 4; } // Low rate (WIFI_PHY_MODE_LR) } return phy_mode; } @@ -240,7 +240,7 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t ip_addr_t addr; aResult = (uint32_t) 0; // by default set to IPv4 0.0.0.0 dns_ipaddr = *IP4_ADDR_ANY; // by default set to IPv4 0.0.0.0 - + scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use ip_addr_counter++; // increase counter, from now ignore previous responses clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT); @@ -260,7 +260,7 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t waitStatusBits(WIFI_DNS_DONE_BIT, timer_ms); //real internal timeout in lwip library is 14[s] clearStatusBits(WIFI_DNS_DONE_BIT); } - + if (!ip_addr_isany_val(dns_ipaddr)) { #ifdef USE_IPV6 aResult = dns_ipaddr; diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h index 0206b0ec5..943b89e9a 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h @@ -29,11 +29,25 @@ #define WIFI_LIGHT_SLEEP 1 #define WIFI_MODEM_SLEEP 2 +// ESP8266 typedef enum WiFiPhyMode { - WIFI_PHY_MODE_11B = 1, WIFI_PHY_MODE_11G = 2, WIFI_PHY_MODE_11N = 3 + TAS_WIFI_PHY_MODE_LR = 0, TAS_WIFI_PHY_MODE_11B = 1, TAS_WIFI_PHY_MODE_11G = 2, TAS_WIFI_PHY_MODE_11N = 3 } WiFiPhyMode_t; +/* +// ESP32 was never defined until IDF 4.4 +typedef enum +{ + WIFI_PHY_MODE_LR, // PHY mode for Low Rate + WIFI_PHY_MODE_11B, // PHY mode for 11b + WIFI_PHY_MODE_11G, // PHY mode for 11g + WIFI_PHY_MODE_HT20, // PHY mode for 11n Bandwidth HT20 + WIFI_PHY_MODE_HT40, // PHY mode for 11n Bandwidth HT40 + WIFI_PHY_MODE_HE20, // PHY mode for 11n Bandwidth HE20 +} wifi_phy_mode_t; +*/ + class WiFiClass32 : public WiFiClass { public: diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp index 419442290..dfc8c3dab 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp @@ -207,7 +207,7 @@ void analogWriteFreqRange(int32_t freq, int32_t range, int32_t pin) { _analogInit(); // make sure the mapping array is initialized uint32_t timer0_freq = timer_freq_hz[0]; // global values uint8_t timer0_res = timer_duty_resolution[0]; - + int32_t timer = 0; int32_t res = timer0_res; if (pin < 0) { @@ -233,7 +233,7 @@ void analogWriteFreqRange(int32_t freq, int32_t range, int32_t pin) { if (timer != 0) { ledcSetTimer(chan, 0); timer = 0; - } + } // else nothing to change } else { // specific (non-global) values, require a specific timer @@ -293,7 +293,7 @@ int32_t analogAttach(uint32_t pin, bool output_invert) { // returns ledc chan AddLog(LOG_LEVEL_INFO, "PWM: no more PWM (ledc) channel for GPIO %i", pin); return -1; } - + // new channel attached to pin pin_to_channel[pin] = chan + 1; diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index 23ed7f1b4..c544d5d30 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -25,14 +25,14 @@ /*******************************************************************************************\ * ESP32/S2/S3/C3... PWM analog support - * + * * The following supersedes Arduino framework and provides more granular control: * - fine grained phase control (in addition to duty cycle) * - fine control of PWM frequency and resolution per GPIO - * + * * By default, all PWM are using the same timer called Timer 0. * Changes in frequency of resolution apply to all PWM using Timer 0. - * + * * You can specify a different a different resolution/frequency for * specific GPIOs, this will internally assign a new timer to the GPIO. * The limit is 3 specific values in addition to the global value. @@ -129,7 +129,7 @@ uint32_t analogGetTimerFrequency(uint8_t timer); #define os_delay_us ets_delay_us // Serial minimal type to hold the config typedef int SerConfu8; -typedef int SerialConfig; +//typedef int SerialConfig; // Will be replaced enum in esp32_hal-uart.h (#7926) // // UDP diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c index e95c65ba2..d85c26177 100644 --- a/lib/libesp32/berry/default/be_modtab.c +++ b/lib/libesp32/berry/default/be_modtab.c @@ -50,6 +50,7 @@ be_extern_native_module(partition_core); be_extern_native_module(crc); be_extern_native_module(crypto); be_extern_native_module(ULP); +be_extern_native_module(TFL); be_extern_native_module(mdns); #ifdef USE_ZIGBEE be_extern_native_module(zigbee); @@ -171,6 +172,9 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #if defined(USE_BERRY_ULP) && ((CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)) &be_native_module(ULP), #endif // USE_BERRY_ULP +#if defined(USE_BERRY_TF_LITE) + &be_native_module(TFL), +#endif //USE_BERRY_TF_LITE #if defined(USE_MI_ESP32) && !defined(USE_BLE_ESP32) &be_native_module(MI32), &be_native_module(BLE), @@ -301,7 +305,7 @@ BERRY_LOCAL bclass_array be_class_table = { #endif // USE_UFILESYS &be_native_class(AudioOpusDecoder), #endif // USE_I2S_AUDIO_BERRY -#ifdef USE_BERRY_INT64 +#if defined(USE_BERRY_INT64) || defined(USE_MATTER_DEVICE) &be_native_class(int64), #endif #endif // TASMOTA diff --git a/lib/libesp32/berry/default/berry_conf.h b/lib/libesp32/berry/default/berry_conf.h index 4c1294646..18d64ad81 100644 --- a/lib/libesp32/berry/default/berry_conf.h +++ b/lib/libesp32/berry/default/berry_conf.h @@ -259,7 +259,6 @@ * are not required. * The default is to use the functions in the standard library. **/ -#ifdef USE_BERRY_PSRAM #ifdef __cplusplus extern "C" { #endif @@ -270,6 +269,7 @@ extern "C" { #ifdef __cplusplus } #endif +#ifdef USE_BERRY_PSRAM #define BE_EXPLICIT_MALLOC berry_malloc #define BE_EXPLICIT_FREE berry_free #define BE_EXPLICIT_REALLOC berry_realloc @@ -306,6 +306,10 @@ extern "C" { #undef BE_STACK_START #define BE_STACK_START 200 #endif // USE_LVGL + #ifdef USE_MATTER_DEVICE + #undef BE_STACK_START + #define BE_STACK_START 256 + #endif // USE_MATTER_DEVICE #endif // USE_BERRY_DEBUG #endif diff --git a/lib/libesp32/berry/src/be_jsonlib.c b/lib/libesp32/berry/src/be_jsonlib.c index 1d7049ea1..9550d642a 100644 --- a/lib/libesp32/berry/src/be_jsonlib.c +++ b/lib/libesp32/berry/src/be_jsonlib.c @@ -178,11 +178,20 @@ static const char* parser_string(bvm *vm, const char *json) } default: be_free(vm, buf, len); return NULL; /* error */ } + } else if(ch >= 0 && ch <= 0x1f) { + /* control characters must be escaped + as per https://www.rfc-editor.org/rfc/rfc7159#section-7 */ + be_free(vm, buf, len); + return NULL; } else { *dst++ = (char)ch; } } be_assert(ch == '"'); + /* require the stack to have some free space for the string, + since parsing deeply nested objects might + crash the VM due to insufficient stack space. */ + be_stack_require(vm, 1 + BE_STACK_FREE_MIN); be_pushnstring(vm, buf, cast_int(dst - buf)); be_free(vm, buf, len); return json + 1; /* skip '"' */ @@ -269,6 +278,92 @@ static const char* parser_array(bvm *vm, const char *json) return json; } +static const char* parser_number(bvm *vm, const char *json) +{ + char c = *json++; + bbool is_neg = c == '-'; + if(is_neg) { + c = *json++; + if(!is_digit(c)) { + /* minus must be followed by digit */ + return NULL; + } + } + bint intv = 0; + if(c != '0') { + /* parse integer part */ + while(is_digit(c)) { + intv = intv * 10 + c - '0'; + c = *json++; + } + + } else { + /* + Number starts with zero, this is only allowed + if the number is just '0' or + it has a fractional part or exponent. + */ + c = *json++; + + } + if(c != '.' && c != 'e' && c != 'E') { + /* + No fractional part or exponent follows, this is an integer. + If digits follow after it (for example due to a leading zero) + this will cause an error in the calling function. + */ + be_pushint(vm, intv * (is_neg ? -1 : 1)); + json--; + return json; + } + breal realval = (breal) intv; + if(c == '.') { + + breal deci = 0.0, point = 0.1; + /* fractional part */ + c = *json++; + if(!is_digit(c)) { + /* decimal point must be followed by digit */ + return NULL; + } + while (is_digit(c)) { + deci = deci + ((breal)c - '0') * point; + point *= (breal)0.1; + c = *json++; + } + + realval += deci; + } + if(c == 'e' || c == 'E') { + c = *json++; + /* exponent part */ + breal ratio = c == '-' ? (breal)0.1 : 10; + if (c == '+' || c == '-') { + c = *json++; + if(!is_digit(c)) { + return NULL; + } + } + if(!is_digit(c)) { + /* e and sign must be followed by digit */ + return NULL; + } + unsigned int e = 0; + while (is_digit(c)) { + e = e * 10 + c - '0'; + c = *json++; + } + /* e > 0 must be here to prevent infinite loops when e overflows */ + while (e--) { + realval *= ratio; + } + } + + be_pushreal(vm, realval * (is_neg ? -1.0 : 1.0)); + json--; + return json; +} + /* parser json value */ static const char* parser_value(bvm *vm, const char *json) { @@ -288,11 +383,7 @@ static const char* parser_value(bvm *vm, const char *json) return parser_null(vm, json); default: /* number */ if (*json == '-' || is_digit(*json)) { - /* check invalid JSON syntax: 0\d+ */ - if (json[0] == '0' && is_digit(json[1])) { - return NULL; - } - return be_str2num(vm, json); + return parser_number(vm, json); } } return NULL; diff --git a/lib/libesp32/berry/src/be_solidifylib.c b/lib/libesp32/berry/src/be_solidifylib.c index 58501e059..43d9107a3 100644 --- a/lib/libesp32/berry/src/be_solidifylib.c +++ b/lib/libesp32/berry/src/be_solidifylib.c @@ -19,6 +19,7 @@ #include #include #include +#include extern const bclass be_class_list; extern const bclass be_class_map; @@ -323,7 +324,7 @@ static void m_solidify_proto(bvm *vm, bbool str_literal, bproto *pr, const char for (int32_t i = 0; i < pr->nproto; i++) { size_t sub_len = strlen(func_name) + 10; char sub_name[sub_len]; - snprintf(sub_name, sizeof(sub_name), "%s_%d", func_name, i); + snprintf(sub_name, sizeof(sub_name), "%s_%"PRId32, func_name, i); m_solidify_proto(vm, str_literal, pr->ptab[i], sub_name, indent+2, fout); logfmt(",\n"); } @@ -361,7 +362,7 @@ static void m_solidify_proto(bvm *vm, bbool str_literal, bproto *pr, const char logfmt("%*s( &(const binstruction[%2d]) { /* code */\n", indent, "", pr->codesize); for (int pc = 0; pc < pr->codesize; pc++) { uint32_t ins = pr->code[pc]; - logfmt("%*s 0x%08X, //", indent, "", ins); + logfmt("%*s 0x%08"PRIX32", //", indent, "", ins); be_print_inst(ins, pc, fout); bopcode op = IGET_OP(ins); if (op == OP_GETGBL || op == OP_SETGBL) { diff --git a/lib/libesp32/berry/src/be_string.c b/lib/libesp32/berry/src/be_string.c index 2ab0d1004..07a0fb162 100644 --- a/lib/libesp32/berry/src/be_string.c +++ b/lib/libesp32/berry/src/be_string.c @@ -167,6 +167,12 @@ static bstring* find_conststr(const char *str, size_t len) uint32_t hash = str_hash(str, len); bcstring *s = (bcstring*)tab->table[hash % tab->size]; for (; s != NULL; s = next(s)) { + if (len == 0 && s->slen == 0) { + /* special case for the empty string, + since we don't want to compare it using strncmp, + because str might be NULL */ + return (bstring*)s; + } if (len == s->slen && !strncmp(str, s->s, len)) { return (bstring*)s; } diff --git a/lib/libesp32/berry/tests/json.be b/lib/libesp32/berry/tests/json.be index 6e1aaaf8d..92df2f3e6 100644 --- a/lib/libesp32/berry/tests/json.be +++ b/lib/libesp32/berry/tests/json.be @@ -1,9 +1,14 @@ import json - +import string # load tests def assert_load(text, value) - assert(json.load(text) == value) + var loaded_val = json.load(text) + var ok = loaded_val == value + if !ok + print(string.format('for JSON \'%s\' expected %s [%s] but got %s [%s]', text, str(value), type(value), str(loaded_val), type(loaded_val))) + end + assert(ok) end def assert_load_failed(text) @@ -15,6 +20,13 @@ assert_load('true', true) assert_load('false', false) assert_load('123', 123) assert_load('12.3', 12.3) +assert_load('-0.1', -0.1) +assert_load('1e2', 1e2) +assert_load('1e+2', 1e+2) +assert_load('1e-2', 1e-2) +assert_load('1E2', 1e2) +assert_load('1E+2', 1e+2) +assert_load('1.2e7', 1.2e7) assert_load('"abc"', 'abc') # strings assert_load('"\\"\\\\\\/\\b\\f\\n\\r\\t"', '\"\\/\b\f\n\r\t') @@ -30,10 +42,22 @@ assert_load_failed('[1, null') # object var o = json.load('{"key": 1}') assert(o['key'] == 1 && o.size() == 1) + +# parsing an empty string used to cause berry to pass a NULL to strncmp +# make sure we catch this +o = json.load('{"key": ""}') +assert(o['key'] == '' && o.size() == 1) + assert_load_failed('{"ke: 1}') assert_load_failed('{"key": 1x}') assert_load_failed('{"key"}') assert_load_failed('{"key": 1, }') +# insanely long, nested object +var text = 'null' +for i : 0 .. 200 + text = '{"nested":' + text + ', "num": 1, "bool": true, "str": "abc", "n": null, "arr": [1, 2, 3]}' +end +json.load(text) # do nothing, just check that it doesn't crash # dump tests diff --git a/lib/libesp32/berry/tests/json_advenced.be b/lib/libesp32/berry/tests/json_advenced.be new file mode 100644 index 000000000..be3b87e0b --- /dev/null +++ b/lib/libesp32/berry/tests/json_advenced.be @@ -0,0 +1,50 @@ +import os +import json + + + +def assert_load_failed(text) + assert(json.load(text) == nil) +end + +var input_file = open("tests/json_test_cases.json", "r") +var test_cases = json.load(input_file.read()) + +# check positive cases +var has_failed_positives = false +for case_name : test_cases["positive"].keys() + var case = test_cases["positive"][case_name] + var val = json.load(case) + if val == nil && case != "null" + print("Failed to load case: " + case_name) + has_failed_positives = true + end +end + +if has_failed_positives + assert(false) +end + +# check negative cases + +var has_failed_negatives = false +for case_name : test_cases["negative"].keys() + var case = test_cases["negative"][case_name] + + var val = json.load(case) + if val != nil + print("Failed to fail case: " + case_name + ", got: " + json.dump(val)) + has_failed_negatives = true + end +end + +if has_failed_negatives + # assert(false) +end + +# check "any" cases, only for crashes + +for case_name : test_cases["any"].keys() + var case = test_cases["any"][case_name] + var val = json.load(case) +end diff --git a/lib/libesp32/berry/tests/json_test_cases.json b/lib/libesp32/berry/tests/json_test_cases.json new file mode 100644 index 000000000..c6e8e4a53 --- /dev/null +++ b/lib/libesp32/berry/tests/json_test_cases.json @@ -0,0 +1,295 @@ +{ + "___comment": "Adapted from https://github.com/nst/JSONTestSuite", + "positive": { + "array_arraysWithSpaces": "[[] ]", + "array_empty-string": "[\"\"]", + "array_empty": "[]", + "array_ending_with_newline": "[\"a\"]", + "array_false": "[false]", + "array_heterogeneous": "[null, 1, \"1\", {}]", + "array_null": "[null]", + "array_with_1_and_newline": "[1\n]", + "array_with_leading_space": " [1]", + "array_with_several_null": "[1,null,null,null,2]", + "array_with_trailing_space": "[2] ", + "number": "[123e65]", + "number_0e+1": "[0e+1]", + "number_0e1": "[0e1]", + "number_after_space": "[ 4]", + "number_double_close_to_zero": "[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]\n", + "number_int_with_exp": "[20e1]", + "number_minus_zero": "[-0]", + "number_negative_int": "[-123]", + "number_negative_one": "[-1]", + "number_negative_zero": "[-0]", + "number_real_capital_e": "[1E22]", + "number_real_capital_e_neg_exp": "[1E-2]", + "number_real_capital_e_pos_exp": "[1E+2]", + "number_real_exponent": "[123e45]", + "number_real_fraction_exponent": "[123.456e78]", + "number_real_neg_exp": "[1e-2]", + "number_real_pos_exponent": "[1e+2]", + "number_simple_int": "[123]", + "number_simple_real": "[123.456789]", + "object": "{\"asd\":\"sdf\", \"dfg\":\"fgh\"}", + "object_basic": "{\"asd\":\"sdf\"}", + "object_duplicated_key": "{\"a\":\"b\",\"a\":\"c\"}", + "object_duplicated_key_and_value": "{\"a\":\"b\",\"a\":\"b\"}", + "object_empty": "{}", + "object_empty_key": "{\"\":0}", + "object_escaped_null_in_key": "{\"foo\\u0000bar\": 42}", + "object_extreme_numbers": "{ \"min\": -1.0e+28, \"max\": 1.0e+28 }", + "object_long_strings": "{\"x\":[{\"id\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}], \"id\": \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"}", + "object_simple": "{\"a\":[]}", + "object_string_unicode": "{\"title\":\"\\u041f\\u043e\\u043b\\u0442\\u043e\\u0440\\u0430 \\u0417\\u0435\\u043c\\u043b\\u0435\\u043a\\u043e\\u043f\\u0430\" }", + "object_with_newlines": "{\n\"a\": \"b\"\n}", + "string_1_2_3_bytes_UTF-8_sequences": "[\"\\u0060\\u012a\\u12AB\"]", + "string_accepted_surrogate_pair": "[\"\\uD801\\udc37\"]", + "string_accepted_surrogate_pairs": "[\"\\ud83d\\ude39\\ud83d\\udc8d\"]", + "string_allowed_escapes": "[\"\\\"\\\\\\/\\b\\f\\n\\r\\t\"]", + "string_backslash_and_u_escaped_zero": "[\"\\\\u0000\"]", + "string_backslash_doublequotes": "[\"\\\"\"]", + "string_comments": "[\"a/*b*/c/*d//e\"]", + "string_double_escape_a": "[\"\\\\a\"]", + "string_double_escape_n": "[\"\\\\n\"]", + "string_escaped_control_character": "[\"\\u0012\"]", + "string_escaped_noncharacter": "[\"\\uFFFF\"]", + "string_in_array": "[\"asd\"]", + "string_in_array_with_leading_space": "[ \"asd\"]", + "string_last_surrogates_1_and_2": "[\"\\uDBFF\\uDFFF\"]", + "string_nbsp_uescaped": "[\"new\\u00A0line\"]", + "string_nonCharacterInUTF-8_U+10FFFF": "[\"\udbff\udfff\"]", + "string_nonCharacterInUTF-8_U+FFFF": "[\"\uffff\"]", + "string_null_escape": "[\"\\u0000\"]", + "string_one-byte-utf-8": "[\"\\u002c\"]", + "string_pi": "[\"\u03c0\"]", + "string_reservedCharacterInUTF-8_U+1BFFF": "[\"\ud82f\udfff\"]", + "string_simple_ascii": "[\"asd \"]", + "string_space": "\" \"", + "string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF": "[\"\\uD834\\uDd1e\"]", + "string_three-byte-utf-8": "[\"\\u0821\"]", + "string_two-byte-utf-8": "[\"\\u0123\"]", + "string_u+2028_line_sep": "[\"\u2028\"]", + "string_u+2029_par_sep": "[\"\u2029\"]", + "string_uEscape": "[\"\\u0061\\u30af\\u30EA\\u30b9\"]", + "string_uescaped_newline": "[\"new\\u000Aline\"]", + "string_unescaped_char_delete": "[\"\u007f\"]", + "string_unicode": "[\"\\uA66D\"]", + "string_unicodeEscapedBackslash": "[\"\\u005C\"]", + "string_unicode_2": "[\"\u2342\u3234\u2342\"]", + "string_unicode_U+10FFFE_nonchar": "[\"\\uDBFF\\uDFFE\"]", + "string_unicode_U+1FFFE_nonchar": "[\"\\uD83F\\uDFFE\"]", + "string_unicode_U+200B_ZERO_WIDTH_SPACE": "[\"\\u200B\"]", + "string_unicode_U+2064_invisible_plus": "[\"\\u2064\"]", + "string_unicode_U+FDD0_nonchar": "[\"\\uFDD0\"]", + "string_unicode_U+FFFE_nonchar": "[\"\\uFFFE\"]", + "string_unicode_escaped_double_quote": "[\"\\u0022\"]", + "string_utf8": "[\"\u20ac\ud834\udd1e\"]", + "string_with_del_character": "[\"a\u007fa\"]", + "structure_lonely_false": "false", + "structure_lonely_int": "42", + "structure_lonely_negative_real": "-0.1", + "structure_lonely_null": "null", + "structure_lonely_string": "\"asd\"", + "structure_lonely_true": "true", + "structure_string_empty": "\"\"", + "structure_trailing_newline": "[\"a\"]\n", + "structure_true_in_array": "[true]", + "structure_whitespace_array": " [] " + }, + "negative": { + "array_1_true_without_comma": "[1 true]", + "array_colon_instead_of_comma": "[\"\": 1]", + "array_comma_after_close": "[\"\"],", + "array_comma_and_number": "[,1]", + "array_double_comma": "[1,,2]", + "array_double_extra_comma": "[\"x\",,]", + "array_extra_close": "[\"x\"]]", + "array_extra_comma": "[\"\",]", + "array_incomplete": "[\"x\"", + "array_incomplete_invalid_value": "[x", + "array_inner_array_no_comma": "[3[4]]", + "array_items_separated_by_semicolon": "[1:2]", + "array_just_comma": "[,]", + "array_just_minus": "[-]", + "array_missing_value": "[ , \"\"]", + "array_newlines_unclosed": "[\"a\",\n4\n,1,", + "array_number_and_comma": "[1,]", + "array_number_and_several_commas": "[1,,]", + "array_spaces_vertical_tab_formfeed": "[\"\u000ba\"\\f]", + "array_star_inside": "[*]", + "array_unclosed": "[\"\"", + "array_unclosed_trailing_comma": "[1,", + "array_unclosed_with_new_lines": "[1,\n1\n,1", + "array_unclosed_with_object_inside": "[{}", + "incomplete_false": "[fals]", + "incomplete_null": "[nul]", + "incomplete_true": "[tru]", + "number_++": "[++1234]", + "number_+1": "[+1]", + "number_+Inf": "[+Inf]", + "number_-01": "[-01]", + "number_-1.0.": "[-1.0.]", + "number_-2.": "[-2.]", + "number_-NaN": "[-NaN]", + "number_.-1": "[.-1]", + "number_.2e-3": "[.2e-3]", + "number_0.1.2": "[0.1.2]", + "number_0.3e+": "[0.3e+]", + "number_0.3e": "[0.3e]", + "number_0.e1": "[0.e1]", + "number_0_capital_E+": "[0E+]", + "number_0_capital_E": "[0E]", + "number_0e+": "[0e+]", + "number_0e": "[0e]", + "number_1.0e+": "[1.0e+]", + "number_1.0e-": "[1.0e-]", + "number_1.0e": "[1.0e]", + "number_1_000": "[1 000.0]", + "number_1eE2": "[1eE2]", + "number_2.e+3": "[2.e+3]", + "number_2.e-3": "[2.e-3]", + "number_2.e3": "[2.e3]", + "number_9.e+": "[9.e+]", + "number_Inf": "[Inf]", + "number_NaN": "[NaN]", + "number_U+FF11_fullwidth_digit_one": "[\uff11]", + "number_expression": "[1+2]", + "number_hex_1_digit": "[0x1]", + "number_hex_2_digits": "[0x42]", + "number_infinity": "[Infinity]", + "number_invalid+-": "[0e+-1]", + "number_invalid-negative-real": "[-123.123foo]", + "number_minus_infinity": "[-Infinity]", + "number_minus_sign_with_trailing_garbage": "[-foo]", + "number_minus_space_1": "[- 1]", + "number_neg_int_starting_with_zero": "[-012]", + "number_neg_real_without_int_part": "[-.123]", + "number_neg_with_garbage_at_end": "[-1x]", + "number_real_garbage_after_e": "[1ea]", + "number_real_without_fractional_part": "[1.]", + "number_starting_with_dot": "[.123]", + "number_with_alpha": "[1.2a-3]", + "number_with_alpha_char": "[1.8011670033376514H-308]", + "number_with_leading_zero": "[012]", + "object_bad_value": "[\"x\", truth]", + "object_bracket_key": "{[: \"x\"}\n", + "object_comma_instead_of_colon": "{\"x\", null}", + "object_double_colon": "{\"x\"::\"b\"}", + "object_emoji": "{\ud83c\udde8\ud83c\udded}", + "object_garbage_at_end": "{\"a\":\"a\" 123}", + "object_key_with_single_quotes": "{key: 'value'}", + "object_missing_colon": "{\"a\" b}", + "object_missing_key": "{:\"b\"}", + "object_missing_semicolon": "{\"a\" \"b\"}", + "object_missing_value": "{\"a\":", + "object_no-colon": "{\"a\"", + "object_non_string_key": "{1:1}", + "object_non_string_key_but_huge_number_instead": "{9999E9999:1}", + "object_repeated_null_null": "{null:null,null:null}", + "object_several_trailing_commas": "{\"id\":0,,,,,}", + "object_single_quote": "{'a':0}", + "object_trailing_comma": "{\"id\":0,}", + "object_trailing_comment": "{\"a\":\"b\"}/**/", + "object_trailing_comment_open": "{\"a\":\"b\"}/**//", + "object_trailing_comment_slash_open": "{\"a\":\"b\"}//", + "object_trailing_comment_slash_open_incomplete": "{\"a\":\"b\"}/", + "object_two_commas_in_a_row": "{\"a\":\"b\",,\"c\":\"d\"}", + "object_unquoted_key": "{a: \"b\"}", + "object_unterminated-value": "{\"a\":\"a", + "object_with_single_string": "{ \"foo\" : \"bar\", \"a\" }", + "object_with_trailing_garbage": "{\"a\":\"b\"}#", + "single_space": " ", + "string_1_surrogate_then_escape": "[\"\\uD800\\\"]", + "string_1_surrogate_then_escape_u": "[\"\\uD800\\u\"]", + "string_1_surrogate_then_escape_u1": "[\"\\uD800\\u1\"]", + "string_1_surrogate_then_escape_u1x": "[\"\\uD800\\u1x\"]", + "string_accentuated_char_no_quotes": "[\u00e9]", + "string_backslash_00": "[\"\\\u0000\"]", + "string_escape_x": "[\"\\x00\"]", + "string_escaped_backslash_bad": "[\"\\\\\\\"]", + "string_escaped_ctrl_char_tab": "[\"\\\t\"]", + "string_escaped_emoji": "[\"\\\ud83c\udf00\"]", + "string_incomplete_escape": "[\"\\\"]", + "string_incomplete_escaped_character": "[\"\\u00A\"]", + "string_incomplete_surrogate": "[\"\\uD834\\uDd\"]", + "string_incomplete_surrogate_escape_invalid": "[\"\\uD800\\uD800\\x\"]", + "string_invalid_backslash_esc": "[\"\\a\"]", + "string_invalid_unicode_escape": "[\"\\uqqqq\"]", + "string_leading_uescaped_thinspace": "[\\u0020\"asd\"]", + "string_no_quotes_with_bad_escape": "[\\n]", + "string_single_doublequote": "\"", + "string_single_quote": "['single quote']", + "string_single_string_no_double_quotes": "abc", + "string_start_escape_unclosed": "[\"\\", + "string_unescaped_ctrl_char": "[\"a\u0000a\"]", + "string_unescaped_newline": "[\"new\nline\"]", + "string_unescaped_tab": "[\"\t\"]", + "string_unicode_CapitalU": "\"\\UA66D\"", + "string_with_trailing_garbage": "\"\"x", + "structure_U+2060_word_joined": "[\u2060]", + "structure_UTF8_BOM_no_data": "\ufeff", + "structure_angle_bracket_.": "<.>", + "structure_angle_bracket_null": "[]", + "structure_array_trailing_garbage": "[1]x", + "structure_array_with_extra_array_close": "[1]]", + "structure_array_with_unclosed_string": "[\"asd]", + "structure_ascii-unicode-identifier": "a\u00e5", + "structure_capitalized_True": "[True]", + "structure_close_unopened_array": "1]", + "structure_comma_instead_of_closing_brace": "{\"x\": true,", + "structure_double_array": "[][]", + "structure_end_array": "]", + "structure_lone-open-bracket": "[", + "structure_no_data": "", + "structure_null-byte-outside-string": "[\u0000]", + "structure_number_with_trailing_garbage": "2@", + "structure_object_followed_by_closing_object": "{}}", + "structure_object_unclosed_no_value": "{\"\":", + "structure_object_with_comment": "{\"a\":/*comment*/\"b\"}", + "structure_object_with_trailing_garbage": "{\"a\": true} \"x\"", + "structure_open_array_apostrophe": "['", + "structure_open_array_comma": "[,", + "structure_open_array_open_object": "[{", + "structure_open_array_open_string": "[\"a", + "structure_open_array_string": "[\"a\"", + "structure_open_object": "{", + "structure_open_object_close_array": "{]", + "structure_open_object_comma": "{,", + "structure_open_object_open_array": "{[", + "structure_open_object_open_string": "{\"a", + "structure_open_object_string_with_apostrophes": "{'a'", + "structure_open_open": "[\"\\{[\"\\{[\"\\{[\"\\{", + "structure_single_star": "*", + "structure_trailing_#": "{\"a\":\"b\"}#{}", + "structure_uescaped_LF_before_string": "[\\u000A\"\"]", + "structure_unclosed_array": "[1", + "structure_unclosed_array_partial_null": "[ false, nul", + "structure_unclosed_array_unfinished_false": "[ true, fals", + "structure_unclosed_array_unfinished_true": "[ false, tru", + "structure_unclosed_object": "{\"asd\":\"asd\"", + "structure_unicode-identifier": "\u00e5", + "structure_whitespace_U+2060_word_joiner": "[\u2060]", + "structure_whitespace_formfeed": "[\f]" + }, + "any": { + "number_double_huge_neg_exp": "[123.456e-789]", + "number_huge_exp": "[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]", + "number_neg_int_huge_exp": "[-1e+9999]", + "number_pos_double_huge_exp": "[1.5e+9999]", + "number_real_neg_overflow": "[-123123e100000]", + "number_real_pos_overflow": "[123123e100000]", + "number_real_underflow": "[123e-10000000]", + "object_key_lone_2nd_surrogate": "{\"\\uDFAA\":0}", + "string_1st_surrogate_but_2nd_missing": "[\"\\uDADA\"]", + "string_1st_valid_surrogate_2nd_invalid": "[\"\\uD888\\u1234\"]", + "string_incomplete_surrogate_and_escape_valid": "[\"\\uD800\\n\"]", + "string_incomplete_surrogate_pair": "[\"\\uDd1ea\"]", + "string_incomplete_surrogates_escape_valid": "[\"\\uD800\\uD800\\n\"]", + "string_invalid_lonely_surrogate": "[\"\\ud800\"]", + "string_invalid_surrogate": "[\"\\ud800abc\"]", + "string_inverted_surrogates_U+1D11E": "[\"\\uDd1e\\uD834\"]", + "string_lone_second_surrogate": "[\"\\uDFAA\"]", + "structure_UTF-8_BOM_empty_object": "\ufeff{}" + } +} diff --git a/lib/libesp32/berry/tools/coc/str_build.py b/lib/libesp32/berry/tools/coc/str_build.py index 82933abec..31caba1d3 100644 --- a/lib/libesp32/berry/tools/coc/str_build.py +++ b/lib/libesp32/berry/tools/coc/str_build.py @@ -1,6 +1,20 @@ import json from coc_string import * +# from https://stackoverflow.com/questions/14945095/how-to-escape-string-for-generated-c (simplified) +def escape_c(s, encoding='ascii'): + result = '' + for c in s: + if not (32 <= ord(c) < 127): + result += '\\%03o' % ord(c) + elif c == '\\': + result += "\\\\" + elif c == '"': + result += "\\\"" + else: + result += c + return '"' + result + '"' + class str_info: def __init__(self): self.hash = 0 @@ -91,7 +105,7 @@ class str_build: else: next = "NULL" istr += "be_define_const_str(" - istr += node + ", " + json.dumps(info.str) + ", " + istr += node + ", " + escape_c(info.str) + ", " istr += str(info.hash) + "u, " + str(info.extra) + ", " istr += str(len(info.str)) + ", " + next + ");\n" strings[info.str] = istr @@ -104,7 +118,7 @@ class str_build: ostr += "\n/* weak strings */\n" for k in self.str_weak: ostr += "be_define_const_str(" - ostr += escape_operator(k) + ", " + json.dumps(k) + ", " + ostr += escape_operator(k) + ", " + escape_c(k) + ", " ostr += "0u, 0, " + str(len(k)) + ", NULL);\n" ostr += "\n" diff --git a/lib/libesp32/berry_int64/src/be_int64_class.c b/lib/libesp32/berry_int64/src/be_int64_class.c index 5b3d3e3c2..4e06354ea 100644 --- a/lib/libesp32/berry_int64/src/be_int64_class.c +++ b/lib/libesp32/berry_int64/src/be_int64_class.c @@ -72,6 +72,13 @@ void int64_set(int64_t *i64, int32_t high, int32_t low) { } BE_FUNC_CTYPE_DECLARE(int64_set, "", ".ii") +int64_t* int64_fromu32(bvm *vm, uint32_t low) { + int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); + *r64 = low; + return r64; +} +BE_FUNC_CTYPE_DECLARE(int64_fromu32, "int64", "@i") + int64_t* int64_add(bvm *vm, int64_t *i64, int64_t *j64) { int64_t* r64 = (int64_t*)be_malloc(vm, sizeof(int64_t)); // it's possible that arg j64 is nullptr, since class type does allow NULLPTR to come through. @@ -197,6 +204,7 @@ class be_class_int64 (scope: global, name: int64) { init, ctype_func(int64_init) deinit, ctype_func(int64_deinit) set, ctype_func(int64_set) + fromu32, static_ctype_func(int64_fromu32) tostring, ctype_func(int64_tostring) fromstring, static_ctype_func(int64_fromstring) diff --git a/lib/libesp32/berry_matter/generate/Matter_generate_c.be b/lib/libesp32/berry_matter/generate/Matter_generate_c.be index 6c9c13170..86155ec1c 100644 --- a/lib/libesp32/berry_matter/generate/Matter_generate_c.be +++ b/lib/libesp32/berry_matter/generate/Matter_generate_c.be @@ -59,6 +59,8 @@ fprint("* Compact form for attributes and clusters") fprint("*") fprint("* Generated content, do not edit") fprint("\\*********************************************************************************/") +fprint("#include ") +fprint("#include ") fprint() fprint("typedef struct {") fprint(" uint16_t id;") @@ -89,7 +91,10 @@ for cl:cl_ids var attr_ids_local = k2l(attr_id_name) for attr_id:attr_ids_local - fprint(string.format(' { 0x%04X, %i, 0x%02X, "%s" },', attr_id, 0, 0, attributes[attr_id]['attributeName'])) + var reportable = attributes[attr_id].find('reportable', false) + var writable = attributes[attr_id].find('writable', false) + var flags = (writable ? 0x01 : 0x00) | (reportable ? 0x02 : 0x00) + fprint(string.format(' { 0x%04X, %i, 0x%02X, "%s" },', attr_id, 0, flags, attributes[attr_id]['attributeName'])) end fprint(' { 0xFFFF, 0, 0x00, NULL },') fprint("};") diff --git a/lib/libesp32/berry_matter/generate/be_matter_clusters.h b/lib/libesp32/berry_matter/generate/be_matter_clusters.h index fc9171ce6..e25982844 100644 --- a/lib/libesp32/berry_matter/generate/be_matter_clusters.h +++ b/lib/libesp32/berry_matter/generate/be_matter_clusters.h @@ -26,13 +26,13 @@ typedef struct { } matter_cluster_t; const matter_attribute_t matter_Attributes_0003[] = { - { 0x0000, 0, 0x00, "IdentifyTime" }, - { 0x0001, 0, 0x00, "IdentifyType" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "IdentifyTime" }, + { 0x0001, 0, 0x02, "IdentifyType" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -43,12 +43,12 @@ const matter_command_t matter_Commands_0003[] = { }; const matter_attribute_t matter_Attributes_0004[] = { - { 0x0000, 0, 0x00, "NameSupport" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "NameSupport" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -63,16 +63,16 @@ const matter_command_t matter_Commands_0004[] = { }; const matter_attribute_t matter_Attributes_0005[] = { - { 0x0000, 0, 0x00, "SceneCount" }, - { 0x0001, 0, 0x00, "CurrentScene" }, - { 0x0002, 0, 0x00, "CurrentGroup" }, - { 0x0003, 0, 0x00, "SceneValid" }, - { 0x0004, 0, 0x00, "NameSupport" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "SceneCount" }, + { 0x0001, 0, 0x02, "CurrentScene" }, + { 0x0002, 0, 0x02, "CurrentGroup" }, + { 0x0003, 0, 0x02, "SceneValid" }, + { 0x0004, 0, 0x02, "NameSupport" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -88,16 +88,16 @@ const matter_command_t matter_Commands_0005[] = { }; const matter_attribute_t matter_Attributes_0006[] = { - { 0x0000, 0, 0x00, "OnOff" }, - { 0x4000, 0, 0x00, "GlobalSceneControl" }, - { 0x4001, 0, 0x00, "OnTime" }, - { 0x4002, 0, 0x00, "OffWaitTime" }, - { 0x4003, 0, 0x00, "StartUpOnOff" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "OnOff" }, + { 0x4000, 0, 0x02, "GlobalSceneControl" }, + { 0x4001, 0, 0x03, "OnTime" }, + { 0x4002, 0, 0x03, "OffWaitTime" }, + { 0x4003, 0, 0x03, "StartUpOnOff" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -112,13 +112,13 @@ const matter_command_t matter_Commands_0006[] = { }; const matter_attribute_t matter_Attributes_0007[] = { - { 0x0000, 0, 0x00, "SwitchType" }, - { 0x0010, 0, 0x00, "SwitchActions" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "SwitchType" }, + { 0x0010, 0, 0x03, "SwitchActions" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -127,25 +127,25 @@ const matter_command_t matter_Commands_0007[] = { }; const matter_attribute_t matter_Attributes_0008[] = { - { 0x0000, 0, 0x00, "CurrentLevel" }, - { 0x0001, 0, 0x00, "RemainingTime" }, - { 0x0002, 0, 0x00, "MinLevel" }, - { 0x0003, 0, 0x00, "MaxLevel" }, - { 0x0004, 0, 0x00, "CurrentFrequency" }, - { 0x0005, 0, 0x00, "MinFrequency" }, - { 0x0006, 0, 0x00, "MaxFrequency" }, - { 0x000F, 0, 0x00, "Options" }, - { 0x0010, 0, 0x00, "OnOffTransitionTime" }, - { 0x0011, 0, 0x00, "OnLevel" }, - { 0x0012, 0, 0x00, "OnTransitionTime" }, - { 0x0013, 0, 0x00, "OffTransitionTime" }, - { 0x0014, 0, 0x00, "DefaultMoveRate" }, - { 0x4000, 0, 0x00, "StartUpCurrentLevel" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "CurrentLevel" }, + { 0x0001, 0, 0x02, "RemainingTime" }, + { 0x0002, 0, 0x02, "MinLevel" }, + { 0x0003, 0, 0x02, "MaxLevel" }, + { 0x0004, 0, 0x02, "CurrentFrequency" }, + { 0x0005, 0, 0x02, "MinFrequency" }, + { 0x0006, 0, 0x02, "MaxFrequency" }, + { 0x000F, 0, 0x03, "Options" }, + { 0x0010, 0, 0x03, "OnOffTransitionTime" }, + { 0x0011, 0, 0x03, "OnLevel" }, + { 0x0012, 0, 0x03, "OnTransitionTime" }, + { 0x0013, 0, 0x03, "OffTransitionTime" }, + { 0x0014, 0, 0x03, "DefaultMoveRate" }, + { 0x4000, 0, 0x03, "StartUpCurrentLevel" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -162,14 +162,14 @@ const matter_command_t matter_Commands_0008[] = { }; const matter_attribute_t matter_Attributes_000F[] = { - { 0x0051, 0, 0x00, "OutOfService" }, - { 0x0055, 0, 0x00, "PresentValue" }, - { 0x006F, 0, 0x00, "StatusFlags" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0051, 0, 0x03, "OutOfService" }, + { 0x0055, 0, 0x03, "PresentValue" }, + { 0x006F, 0, 0x02, "StatusFlags" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -178,15 +178,15 @@ const matter_command_t matter_Commands_000F[] = { }; const matter_attribute_t matter_Attributes_001D[] = { - { 0x0000, 0, 0x00, "DeviceTypeList" }, - { 0x0001, 0, 0x00, "ServerList" }, - { 0x0002, 0, 0x00, "ClientList" }, - { 0x0003, 0, 0x00, "PartsList" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "DeviceTypeList" }, + { 0x0001, 0, 0x02, "ServerList" }, + { 0x0002, 0, 0x02, "ClientList" }, + { 0x0003, 0, 0x02, "PartsList" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -195,12 +195,12 @@ const matter_command_t matter_Commands_001D[] = { }; const matter_attribute_t matter_Attributes_001E[] = { - { 0x0000, 0, 0x00, "Binding" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "Binding" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -209,16 +209,16 @@ const matter_command_t matter_Commands_001E[] = { }; const matter_attribute_t matter_Attributes_001F[] = { - { 0x0000, 0, 0x00, "Acl" }, - { 0x0001, 0, 0x00, "Extension" }, - { 0x0002, 0, 0x00, "SubjectsPerAccessControlEntry" }, - { 0x0003, 0, 0x00, "TargetsPerAccessControlEntry" }, - { 0x0004, 0, 0x00, "AccessControlEntriesPerFabric" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "Acl" }, + { 0x0001, 0, 0x03, "Extension" }, + { 0x0002, 0, 0x02, "SubjectsPerAccessControlEntry" }, + { 0x0003, 0, 0x02, "TargetsPerAccessControlEntry" }, + { 0x0004, 0, 0x02, "AccessControlEntriesPerFabric" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -227,14 +227,14 @@ const matter_command_t matter_Commands_001F[] = { }; const matter_attribute_t matter_Attributes_0025[] = { - { 0x0000, 0, 0x00, "ActionList" }, - { 0x0001, 0, 0x00, "EndpointLists" }, - { 0x0002, 0, 0x00, "SetupURL" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "ActionList" }, + { 0x0001, 0, 0x02, "EndpointLists" }, + { 0x0002, 0, 0x02, "SetupURL" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -255,31 +255,31 @@ const matter_command_t matter_Commands_0025[] = { }; const matter_attribute_t matter_Attributes_0028[] = { - { 0x0000, 0, 0x00, "DataModelRevision" }, - { 0x0001, 0, 0x00, "VendorName" }, - { 0x0002, 0, 0x00, "VendorID" }, - { 0x0003, 0, 0x00, "ProductName" }, - { 0x0004, 0, 0x00, "ProductID" }, - { 0x0005, 0, 0x00, "NodeLabel" }, - { 0x0006, 0, 0x00, "Location" }, - { 0x0007, 0, 0x00, "HardwareVersion" }, - { 0x0008, 0, 0x00, "HardwareVersionString" }, - { 0x0009, 0, 0x00, "SoftwareVersion" }, - { 0x000A, 0, 0x00, "SoftwareVersionString" }, - { 0x000B, 0, 0x00, "ManufacturingDate" }, - { 0x000C, 0, 0x00, "PartNumber" }, - { 0x000D, 0, 0x00, "ProductURL" }, - { 0x000E, 0, 0x00, "ProductLabel" }, - { 0x000F, 0, 0x00, "SerialNumber" }, - { 0x0010, 0, 0x00, "LocalConfigDisabled" }, - { 0x0011, 0, 0x00, "Reachable" }, - { 0x0012, 0, 0x00, "UniqueID" }, - { 0x0013, 0, 0x00, "CapabilityMinima" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "DataModelRevision" }, + { 0x0001, 0, 0x02, "VendorName" }, + { 0x0002, 0, 0x02, "VendorID" }, + { 0x0003, 0, 0x02, "ProductName" }, + { 0x0004, 0, 0x02, "ProductID" }, + { 0x0005, 0, 0x03, "NodeLabel" }, + { 0x0006, 0, 0x03, "Location" }, + { 0x0007, 0, 0x02, "HardwareVersion" }, + { 0x0008, 0, 0x02, "HardwareVersionString" }, + { 0x0009, 0, 0x02, "SoftwareVersion" }, + { 0x000A, 0, 0x02, "SoftwareVersionString" }, + { 0x000B, 0, 0x02, "ManufacturingDate" }, + { 0x000C, 0, 0x02, "PartNumber" }, + { 0x000D, 0, 0x02, "ProductURL" }, + { 0x000E, 0, 0x02, "ProductLabel" }, + { 0x000F, 0, 0x02, "SerialNumber" }, + { 0x0010, 0, 0x03, "LocalConfigDisabled" }, + { 0x0011, 0, 0x02, "Reachable" }, + { 0x0012, 0, 0x02, "UniqueID" }, + { 0x0013, 0, 0x02, "CapabilityMinima" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -288,9 +288,9 @@ const matter_command_t matter_Commands_0028[] = { }; const matter_attribute_t matter_Attributes_0029[] = { - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -302,13 +302,13 @@ const matter_command_t matter_Commands_0029[] = { }; const matter_attribute_t matter_Attributes_002A[] = { - { 0x0000, 0, 0x00, "DefaultOtaProviders" }, - { 0x0001, 0, 0x00, "UpdatePossible" }, - { 0x0002, 0, 0x00, "UpdateState" }, - { 0x0003, 0, 0x00, "UpdateStateProgress" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "DefaultOtaProviders" }, + { 0x0001, 0, 0x02, "UpdatePossible" }, + { 0x0002, 0, 0x02, "UpdateState" }, + { 0x0003, 0, 0x02, "UpdateStateProgress" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -318,12 +318,12 @@ const matter_command_t matter_Commands_002A[] = { }; const matter_attribute_t matter_Attributes_002B[] = { - { 0x0000, 0, 0x00, "ActiveLocale" }, - { 0x0001, 0, 0x00, "SupportedLocales" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "ActiveLocale" }, + { 0x0001, 0, 0x02, "SupportedLocales" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -332,13 +332,13 @@ const matter_command_t matter_Commands_002B[] = { }; const matter_attribute_t matter_Attributes_002C[] = { - { 0x0000, 0, 0x00, "HourFormat" }, - { 0x0001, 0, 0x00, "ActiveCalendarType" }, - { 0x0002, 0, 0x00, "SupportedCalendarTypes" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "HourFormat" }, + { 0x0001, 0, 0x03, "ActiveCalendarType" }, + { 0x0002, 0, 0x02, "SupportedCalendarTypes" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -347,10 +347,10 @@ const matter_command_t matter_Commands_002C[] = { }; const matter_attribute_t matter_Attributes_002D[] = { - { 0x0000, 0, 0x00, "TemperatureUnit" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "TemperatureUnit" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -359,12 +359,12 @@ const matter_command_t matter_Commands_002D[] = { }; const matter_attribute_t matter_Attributes_002E[] = { - { 0x0000, 0, 0x00, "Sources" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Sources" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -373,42 +373,42 @@ const matter_command_t matter_Commands_002E[] = { }; const matter_attribute_t matter_Attributes_002F[] = { - { 0x0000, 0, 0x00, "Status" }, - { 0x0001, 0, 0x00, "Order" }, - { 0x0002, 0, 0x00, "Description" }, - { 0x0003, 0, 0x00, "WiredAssessedInputVoltage" }, - { 0x0004, 0, 0x00, "WiredAssessedInputFrequency" }, - { 0x0005, 0, 0x00, "WiredCurrentType" }, - { 0x0006, 0, 0x00, "WiredAssessedCurrent" }, - { 0x0007, 0, 0x00, "WiredNominalVoltage" }, - { 0x0008, 0, 0x00, "WiredMaximumCurrent" }, - { 0x0009, 0, 0x00, "WiredPresent" }, - { 0x000A, 0, 0x00, "ActiveWiredFaults" }, - { 0x000B, 0, 0x00, "BatVoltage" }, - { 0x000C, 0, 0x00, "BatPercentRemaining" }, - { 0x000D, 0, 0x00, "BatTimeRemaining" }, - { 0x000E, 0, 0x00, "BatChargeLevel" }, - { 0x000F, 0, 0x00, "BatReplacementNeeded" }, - { 0x0010, 0, 0x00, "BatReplaceability" }, - { 0x0011, 0, 0x00, "BatPresent" }, - { 0x0012, 0, 0x00, "ActiveBatFaults" }, - { 0x0013, 0, 0x00, "BatReplacementDescription" }, - { 0x0014, 0, 0x00, "BatCommonDesignation" }, - { 0x0015, 0, 0x00, "BatANSIDesignation" }, - { 0x0016, 0, 0x00, "BatIECDesignation" }, - { 0x0017, 0, 0x00, "BatApprovedChemistry" }, - { 0x0018, 0, 0x00, "BatCapacity" }, - { 0x0019, 0, 0x00, "BatQuantity" }, - { 0x001A, 0, 0x00, "BatChargeState" }, - { 0x001B, 0, 0x00, "BatTimeToFullCharge" }, - { 0x001C, 0, 0x00, "BatFunctionalWhileCharging" }, - { 0x001D, 0, 0x00, "BatChargingCurrent" }, - { 0x001E, 0, 0x00, "ActiveBatChargeFaults" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Status" }, + { 0x0001, 0, 0x02, "Order" }, + { 0x0002, 0, 0x02, "Description" }, + { 0x0003, 0, 0x02, "WiredAssessedInputVoltage" }, + { 0x0004, 0, 0x02, "WiredAssessedInputFrequency" }, + { 0x0005, 0, 0x02, "WiredCurrentType" }, + { 0x0006, 0, 0x02, "WiredAssessedCurrent" }, + { 0x0007, 0, 0x02, "WiredNominalVoltage" }, + { 0x0008, 0, 0x02, "WiredMaximumCurrent" }, + { 0x0009, 0, 0x02, "WiredPresent" }, + { 0x000A, 0, 0x02, "ActiveWiredFaults" }, + { 0x000B, 0, 0x02, "BatVoltage" }, + { 0x000C, 0, 0x02, "BatPercentRemaining" }, + { 0x000D, 0, 0x02, "BatTimeRemaining" }, + { 0x000E, 0, 0x02, "BatChargeLevel" }, + { 0x000F, 0, 0x02, "BatReplacementNeeded" }, + { 0x0010, 0, 0x02, "BatReplaceability" }, + { 0x0011, 0, 0x02, "BatPresent" }, + { 0x0012, 0, 0x02, "ActiveBatFaults" }, + { 0x0013, 0, 0x02, "BatReplacementDescription" }, + { 0x0014, 0, 0x02, "BatCommonDesignation" }, + { 0x0015, 0, 0x02, "BatANSIDesignation" }, + { 0x0016, 0, 0x02, "BatIECDesignation" }, + { 0x0017, 0, 0x02, "BatApprovedChemistry" }, + { 0x0018, 0, 0x02, "BatCapacity" }, + { 0x0019, 0, 0x02, "BatQuantity" }, + { 0x001A, 0, 0x02, "BatChargeState" }, + { 0x001B, 0, 0x02, "BatTimeToFullCharge" }, + { 0x001C, 0, 0x02, "BatFunctionalWhileCharging" }, + { 0x001D, 0, 0x02, "BatChargingCurrent" }, + { 0x001E, 0, 0x02, "ActiveBatChargeFaults" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -417,16 +417,16 @@ const matter_command_t matter_Commands_002F[] = { }; const matter_attribute_t matter_Attributes_0030[] = { - { 0x0000, 0, 0x00, "Breadcrumb" }, - { 0x0001, 0, 0x00, "BasicCommissioningInfo" }, - { 0x0002, 0, 0x00, "RegulatoryConfig" }, - { 0x0003, 0, 0x00, "LocationCapability" }, - { 0x0004, 0, 0x00, "SupportsConcurrentConnection" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "Breadcrumb" }, + { 0x0001, 0, 0x02, "BasicCommissioningInfo" }, + { 0x0002, 0, 0x02, "RegulatoryConfig" }, + { 0x0003, 0, 0x02, "LocationCapability" }, + { 0x0004, 0, 0x02, "SupportsConcurrentConnection" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -441,18 +441,18 @@ const matter_command_t matter_Commands_0030[] = { }; const matter_attribute_t matter_Attributes_0031[] = { - { 0x0000, 0, 0x00, "MaxNetworks" }, - { 0x0001, 0, 0x00, "Networks" }, - { 0x0002, 0, 0x00, "ScanMaxTimeSeconds" }, - { 0x0003, 0, 0x00, "ConnectMaxTimeSeconds" }, - { 0x0004, 0, 0x00, "InterfaceEnabled" }, - { 0x0005, 0, 0x00, "LastNetworkingStatus" }, - { 0x0006, 0, 0x00, "LastNetworkID" }, - { 0x0007, 0, 0x00, "LastConnectErrorValue" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MaxNetworks" }, + { 0x0001, 0, 0x02, "Networks" }, + { 0x0002, 0, 0x02, "ScanMaxTimeSeconds" }, + { 0x0003, 0, 0x02, "ConnectMaxTimeSeconds" }, + { 0x0004, 0, 0x03, "InterfaceEnabled" }, + { 0x0005, 0, 0x02, "LastNetworkingStatus" }, + { 0x0006, 0, 0x02, "LastNetworkID" }, + { 0x0007, 0, 0x02, "LastConnectErrorValue" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -467,11 +467,11 @@ const matter_command_t matter_Commands_0031[] = { }; const matter_attribute_t matter_Attributes_0032[] = { - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -481,20 +481,20 @@ const matter_command_t matter_Commands_0032[] = { }; const matter_attribute_t matter_Attributes_0033[] = { - { 0x0000, 0, 0x00, "NetworkInterfaces" }, - { 0x0001, 0, 0x00, "RebootCount" }, - { 0x0002, 0, 0x00, "UpTime" }, - { 0x0003, 0, 0x00, "TotalOperationalHours" }, - { 0x0004, 0, 0x00, "BootReasons" }, - { 0x0005, 0, 0x00, "ActiveHardwareFaults" }, - { 0x0006, 0, 0x00, "ActiveRadioFaults" }, - { 0x0007, 0, 0x00, "ActiveNetworkFaults" }, - { 0x0008, 0, 0x00, "TestEventTriggersEnabled" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "NetworkInterfaces" }, + { 0x0001, 0, 0x02, "RebootCount" }, + { 0x0002, 0, 0x02, "UpTime" }, + { 0x0003, 0, 0x02, "TotalOperationalHours" }, + { 0x0004, 0, 0x02, "BootReasons" }, + { 0x0005, 0, 0x02, "ActiveHardwareFaults" }, + { 0x0006, 0, 0x02, "ActiveRadioFaults" }, + { 0x0007, 0, 0x02, "ActiveNetworkFaults" }, + { 0x0008, 0, 0x02, "TestEventTriggersEnabled" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -504,15 +504,15 @@ const matter_command_t matter_Commands_0033[] = { }; const matter_attribute_t matter_Attributes_0034[] = { - { 0x0000, 0, 0x00, "ThreadMetrics" }, - { 0x0001, 0, 0x00, "CurrentHeapFree" }, - { 0x0002, 0, 0x00, "CurrentHeapUsed" }, - { 0x0003, 0, 0x00, "CurrentHeapHighWatermark" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "ThreadMetrics" }, + { 0x0001, 0, 0x02, "CurrentHeapFree" }, + { 0x0002, 0, 0x02, "CurrentHeapUsed" }, + { 0x0003, 0, 0x02, "CurrentHeapHighWatermark" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -522,74 +522,74 @@ const matter_command_t matter_Commands_0034[] = { }; const matter_attribute_t matter_Attributes_0035[] = { - { 0x0000, 0, 0x00, "Channel" }, - { 0x0001, 0, 0x00, "RoutingRole" }, - { 0x0002, 0, 0x00, "NetworkName" }, - { 0x0003, 0, 0x00, "PanId" }, - { 0x0004, 0, 0x00, "ExtendedPanId" }, - { 0x0005, 0, 0x00, "MeshLocalPrefix" }, - { 0x0006, 0, 0x00, "OverrunCount" }, - { 0x0007, 0, 0x00, "NeighborTableList" }, - { 0x0008, 0, 0x00, "RouteTableList" }, - { 0x0009, 0, 0x00, "PartitionId" }, - { 0x000A, 0, 0x00, "Weighting" }, - { 0x000B, 0, 0x00, "DataVersion" }, - { 0x000C, 0, 0x00, "StableDataVersion" }, - { 0x000D, 0, 0x00, "LeaderRouterId" }, - { 0x000E, 0, 0x00, "DetachedRoleCount" }, - { 0x000F, 0, 0x00, "ChildRoleCount" }, - { 0x0010, 0, 0x00, "RouterRoleCount" }, - { 0x0011, 0, 0x00, "LeaderRoleCount" }, - { 0x0012, 0, 0x00, "AttachAttemptCount" }, - { 0x0013, 0, 0x00, "PartitionIdChangeCount" }, - { 0x0014, 0, 0x00, "BetterPartitionAttachAttemptCount" }, - { 0x0015, 0, 0x00, "ParentChangeCount" }, - { 0x0016, 0, 0x00, "TxTotalCount" }, - { 0x0017, 0, 0x00, "TxUnicastCount" }, - { 0x0018, 0, 0x00, "TxBroadcastCount" }, - { 0x0019, 0, 0x00, "TxAckRequestedCount" }, - { 0x001A, 0, 0x00, "TxAckedCount" }, - { 0x001B, 0, 0x00, "TxNoAckRequestedCount" }, - { 0x001C, 0, 0x00, "TxDataCount" }, - { 0x001D, 0, 0x00, "TxDataPollCount" }, - { 0x001E, 0, 0x00, "TxBeaconCount" }, - { 0x001F, 0, 0x00, "TxBeaconRequestCount" }, - { 0x0020, 0, 0x00, "TxOtherCount" }, - { 0x0021, 0, 0x00, "TxRetryCount" }, - { 0x0022, 0, 0x00, "TxDirectMaxRetryExpiryCount" }, - { 0x0023, 0, 0x00, "TxIndirectMaxRetryExpiryCount" }, - { 0x0024, 0, 0x00, "TxErrCcaCount" }, - { 0x0025, 0, 0x00, "TxErrAbortCount" }, - { 0x0026, 0, 0x00, "TxErrBusyChannelCount" }, - { 0x0027, 0, 0x00, "RxTotalCount" }, - { 0x0028, 0, 0x00, "RxUnicastCount" }, - { 0x0029, 0, 0x00, "RxBroadcastCount" }, - { 0x002A, 0, 0x00, "RxDataCount" }, - { 0x002B, 0, 0x00, "RxDataPollCount" }, - { 0x002C, 0, 0x00, "RxBeaconCount" }, - { 0x002D, 0, 0x00, "RxBeaconRequestCount" }, - { 0x002E, 0, 0x00, "RxOtherCount" }, - { 0x002F, 0, 0x00, "RxAddressFilteredCount" }, - { 0x0030, 0, 0x00, "RxDestAddrFilteredCount" }, - { 0x0031, 0, 0x00, "RxDuplicatedCount" }, - { 0x0032, 0, 0x00, "RxErrNoFrameCount" }, - { 0x0033, 0, 0x00, "RxErrUnknownNeighborCount" }, - { 0x0034, 0, 0x00, "RxErrInvalidSrcAddrCount" }, - { 0x0035, 0, 0x00, "RxErrSecCount" }, - { 0x0036, 0, 0x00, "RxErrFcsCount" }, - { 0x0037, 0, 0x00, "RxErrOtherCount" }, - { 0x0038, 0, 0x00, "ActiveTimestamp" }, - { 0x0039, 0, 0x00, "PendingTimestamp" }, - { 0x003A, 0, 0x00, "Delay" }, - { 0x003B, 0, 0x00, "SecurityPolicy" }, - { 0x003C, 0, 0x00, "ChannelPage0Mask" }, - { 0x003D, 0, 0x00, "OperationalDatasetComponents" }, - { 0x003E, 0, 0x00, "ActiveNetworkFaultsList" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Channel" }, + { 0x0001, 0, 0x02, "RoutingRole" }, + { 0x0002, 0, 0x02, "NetworkName" }, + { 0x0003, 0, 0x02, "PanId" }, + { 0x0004, 0, 0x02, "ExtendedPanId" }, + { 0x0005, 0, 0x02, "MeshLocalPrefix" }, + { 0x0006, 0, 0x02, "OverrunCount" }, + { 0x0007, 0, 0x02, "NeighborTableList" }, + { 0x0008, 0, 0x02, "RouteTableList" }, + { 0x0009, 0, 0x02, "PartitionId" }, + { 0x000A, 0, 0x02, "Weighting" }, + { 0x000B, 0, 0x02, "DataVersion" }, + { 0x000C, 0, 0x02, "StableDataVersion" }, + { 0x000D, 0, 0x02, "LeaderRouterId" }, + { 0x000E, 0, 0x02, "DetachedRoleCount" }, + { 0x000F, 0, 0x02, "ChildRoleCount" }, + { 0x0010, 0, 0x02, "RouterRoleCount" }, + { 0x0011, 0, 0x02, "LeaderRoleCount" }, + { 0x0012, 0, 0x02, "AttachAttemptCount" }, + { 0x0013, 0, 0x02, "PartitionIdChangeCount" }, + { 0x0014, 0, 0x02, "BetterPartitionAttachAttemptCount" }, + { 0x0015, 0, 0x02, "ParentChangeCount" }, + { 0x0016, 0, 0x02, "TxTotalCount" }, + { 0x0017, 0, 0x02, "TxUnicastCount" }, + { 0x0018, 0, 0x02, "TxBroadcastCount" }, + { 0x0019, 0, 0x02, "TxAckRequestedCount" }, + { 0x001A, 0, 0x02, "TxAckedCount" }, + { 0x001B, 0, 0x02, "TxNoAckRequestedCount" }, + { 0x001C, 0, 0x02, "TxDataCount" }, + { 0x001D, 0, 0x02, "TxDataPollCount" }, + { 0x001E, 0, 0x02, "TxBeaconCount" }, + { 0x001F, 0, 0x02, "TxBeaconRequestCount" }, + { 0x0020, 0, 0x02, "TxOtherCount" }, + { 0x0021, 0, 0x02, "TxRetryCount" }, + { 0x0022, 0, 0x02, "TxDirectMaxRetryExpiryCount" }, + { 0x0023, 0, 0x02, "TxIndirectMaxRetryExpiryCount" }, + { 0x0024, 0, 0x02, "TxErrCcaCount" }, + { 0x0025, 0, 0x02, "TxErrAbortCount" }, + { 0x0026, 0, 0x02, "TxErrBusyChannelCount" }, + { 0x0027, 0, 0x02, "RxTotalCount" }, + { 0x0028, 0, 0x02, "RxUnicastCount" }, + { 0x0029, 0, 0x02, "RxBroadcastCount" }, + { 0x002A, 0, 0x02, "RxDataCount" }, + { 0x002B, 0, 0x02, "RxDataPollCount" }, + { 0x002C, 0, 0x02, "RxBeaconCount" }, + { 0x002D, 0, 0x02, "RxBeaconRequestCount" }, + { 0x002E, 0, 0x02, "RxOtherCount" }, + { 0x002F, 0, 0x02, "RxAddressFilteredCount" }, + { 0x0030, 0, 0x02, "RxDestAddrFilteredCount" }, + { 0x0031, 0, 0x02, "RxDuplicatedCount" }, + { 0x0032, 0, 0x02, "RxErrNoFrameCount" }, + { 0x0033, 0, 0x02, "RxErrUnknownNeighborCount" }, + { 0x0034, 0, 0x02, "RxErrInvalidSrcAddrCount" }, + { 0x0035, 0, 0x02, "RxErrSecCount" }, + { 0x0036, 0, 0x02, "RxErrFcsCount" }, + { 0x0037, 0, 0x02, "RxErrOtherCount" }, + { 0x0038, 0, 0x02, "ActiveTimestamp" }, + { 0x0039, 0, 0x02, "PendingTimestamp" }, + { 0x003A, 0, 0x02, "Delay" }, + { 0x003B, 0, 0x02, "SecurityPolicy" }, + { 0x003C, 0, 0x02, "ChannelPage0Mask" }, + { 0x003D, 0, 0x02, "OperationalDatasetComponents" }, + { 0x003E, 0, 0x02, "ActiveNetworkFaultsList" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -599,24 +599,24 @@ const matter_command_t matter_Commands_0035[] = { }; const matter_attribute_t matter_Attributes_0036[] = { - { 0x0000, 0, 0x00, "Bssid" }, - { 0x0001, 0, 0x00, "SecurityType" }, - { 0x0002, 0, 0x00, "WiFiVersion" }, - { 0x0003, 0, 0x00, "ChannelNumber" }, - { 0x0004, 0, 0x00, "Rssi" }, - { 0x0005, 0, 0x00, "BeaconLostCount" }, - { 0x0006, 0, 0x00, "BeaconRxCount" }, - { 0x0007, 0, 0x00, "PacketMulticastRxCount" }, - { 0x0008, 0, 0x00, "PacketMulticastTxCount" }, - { 0x0009, 0, 0x00, "PacketUnicastRxCount" }, - { 0x000A, 0, 0x00, "PacketUnicastTxCount" }, - { 0x000B, 0, 0x00, "CurrentMaxRate" }, - { 0x000C, 0, 0x00, "OverrunCount" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Bssid" }, + { 0x0001, 0, 0x02, "SecurityType" }, + { 0x0002, 0, 0x02, "WiFiVersion" }, + { 0x0003, 0, 0x02, "ChannelNumber" }, + { 0x0004, 0, 0x02, "Rssi" }, + { 0x0005, 0, 0x02, "BeaconLostCount" }, + { 0x0006, 0, 0x02, "BeaconRxCount" }, + { 0x0007, 0, 0x02, "PacketMulticastRxCount" }, + { 0x0008, 0, 0x02, "PacketMulticastTxCount" }, + { 0x0009, 0, 0x02, "PacketUnicastRxCount" }, + { 0x000A, 0, 0x02, "PacketUnicastTxCount" }, + { 0x000B, 0, 0x02, "CurrentMaxRate" }, + { 0x000C, 0, 0x02, "OverrunCount" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -626,20 +626,20 @@ const matter_command_t matter_Commands_0036[] = { }; const matter_attribute_t matter_Attributes_0037[] = { - { 0x0000, 0, 0x00, "PHYRate" }, - { 0x0001, 0, 0x00, "FullDuplex" }, - { 0x0002, 0, 0x00, "PacketRxCount" }, - { 0x0003, 0, 0x00, "PacketTxCount" }, - { 0x0004, 0, 0x00, "TxErrCount" }, - { 0x0005, 0, 0x00, "CollisionCount" }, - { 0x0006, 0, 0x00, "OverrunCount" }, - { 0x0007, 0, 0x00, "CarrierDetect" }, - { 0x0008, 0, 0x00, "TimeSinceReset" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "PHYRate" }, + { 0x0001, 0, 0x02, "FullDuplex" }, + { 0x0002, 0, 0x02, "PacketRxCount" }, + { 0x0003, 0, 0x02, "PacketTxCount" }, + { 0x0004, 0, 0x02, "TxErrCount" }, + { 0x0005, 0, 0x02, "CollisionCount" }, + { 0x0006, 0, 0x02, "OverrunCount" }, + { 0x0007, 0, 0x02, "CarrierDetect" }, + { 0x0008, 0, 0x02, "TimeSinceReset" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -649,26 +649,26 @@ const matter_command_t matter_Commands_0037[] = { }; const matter_attribute_t matter_Attributes_0039[] = { - { 0x0001, 0, 0x00, "VendorName" }, - { 0x0002, 0, 0x00, "VendorID" }, - { 0x0003, 0, 0x00, "ProductName" }, - { 0x0005, 0, 0x00, "NodeLabel" }, - { 0x0007, 0, 0x00, "HardwareVersion" }, - { 0x0008, 0, 0x00, "HardwareVersionString" }, - { 0x0009, 0, 0x00, "SoftwareVersion" }, - { 0x000A, 0, 0x00, "SoftwareVersionString" }, - { 0x000B, 0, 0x00, "ManufacturingDate" }, - { 0x000C, 0, 0x00, "PartNumber" }, - { 0x000D, 0, 0x00, "ProductURL" }, - { 0x000E, 0, 0x00, "ProductLabel" }, - { 0x000F, 0, 0x00, "SerialNumber" }, - { 0x0011, 0, 0x00, "Reachable" }, - { 0x0012, 0, 0x00, "UniqueID" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0001, 0, 0x02, "VendorName" }, + { 0x0002, 0, 0x02, "VendorID" }, + { 0x0003, 0, 0x02, "ProductName" }, + { 0x0005, 0, 0x03, "NodeLabel" }, + { 0x0007, 0, 0x02, "HardwareVersion" }, + { 0x0008, 0, 0x02, "HardwareVersionString" }, + { 0x0009, 0, 0x02, "SoftwareVersion" }, + { 0x000A, 0, 0x02, "SoftwareVersionString" }, + { 0x000B, 0, 0x02, "ManufacturingDate" }, + { 0x000C, 0, 0x02, "PartNumber" }, + { 0x000D, 0, 0x02, "ProductURL" }, + { 0x000E, 0, 0x02, "ProductLabel" }, + { 0x000F, 0, 0x02, "SerialNumber" }, + { 0x0011, 0, 0x02, "Reachable" }, + { 0x0012, 0, 0x02, "UniqueID" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -677,14 +677,14 @@ const matter_command_t matter_Commands_0039[] = { }; const matter_attribute_t matter_Attributes_003B[] = { - { 0x0000, 0, 0x00, "NumberOfPositions" }, - { 0x0001, 0, 0x00, "CurrentPosition" }, - { 0x0002, 0, 0x00, "MultiPressMax" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "NumberOfPositions" }, + { 0x0001, 0, 0x02, "CurrentPosition" }, + { 0x0002, 0, 0x02, "MultiPressMax" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -693,14 +693,14 @@ const matter_command_t matter_Commands_003B[] = { }; const matter_attribute_t matter_Attributes_003C[] = { - { 0x0000, 0, 0x00, "WindowStatus" }, - { 0x0001, 0, 0x00, "AdminFabricIndex" }, - { 0x0002, 0, 0x00, "AdminVendorId" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "WindowStatus" }, + { 0x0001, 0, 0x02, "AdminFabricIndex" }, + { 0x0002, 0, 0x02, "AdminVendorId" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -712,17 +712,17 @@ const matter_command_t matter_Commands_003C[] = { }; const matter_attribute_t matter_Attributes_003E[] = { - { 0x0000, 0, 0x00, "NOCs" }, - { 0x0001, 0, 0x00, "Fabrics" }, - { 0x0002, 0, 0x00, "SupportedFabrics" }, - { 0x0003, 0, 0x00, "CommissionedFabrics" }, - { 0x0004, 0, 0x00, "TrustedRootCertificates" }, - { 0x0005, 0, 0x00, "CurrentFabricIndex" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "NOCs" }, + { 0x0001, 0, 0x02, "Fabrics" }, + { 0x0002, 0, 0x02, "SupportedFabrics" }, + { 0x0003, 0, 0x02, "CommissionedFabrics" }, + { 0x0004, 0, 0x02, "TrustedRootCertificates" }, + { 0x0005, 0, 0x02, "CurrentFabricIndex" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -743,15 +743,15 @@ const matter_command_t matter_Commands_003E[] = { }; const matter_attribute_t matter_Attributes_003F[] = { - { 0x0000, 0, 0x00, "GroupKeyMap" }, - { 0x0001, 0, 0x00, "GroupTable" }, - { 0x0002, 0, 0x00, "MaxGroupsPerFabric" }, - { 0x0003, 0, 0x00, "MaxGroupKeysPerFabric" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "GroupKeyMap" }, + { 0x0001, 0, 0x02, "GroupTable" }, + { 0x0002, 0, 0x02, "MaxGroupsPerFabric" }, + { 0x0003, 0, 0x02, "MaxGroupKeysPerFabric" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -764,12 +764,12 @@ const matter_command_t matter_Commands_003F[] = { }; const matter_attribute_t matter_Attributes_0040[] = { - { 0x0000, 0, 0x00, "LabelList" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "LabelList" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -778,11 +778,11 @@ const matter_command_t matter_Commands_0040[] = { }; const matter_attribute_t matter_Attributes_0041[] = { - { 0x0000, 0, 0x00, "LabelList" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "LabelList" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -791,12 +791,12 @@ const matter_command_t matter_Commands_0041[] = { }; const matter_attribute_t matter_Attributes_0045[] = { - { 0x0000, 0, 0x00, "StateValue" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "StateValue" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -805,17 +805,17 @@ const matter_command_t matter_Commands_0045[] = { }; const matter_attribute_t matter_Attributes_0050[] = { - { 0x0000, 0, 0x00, "Description" }, - { 0x0001, 0, 0x00, "StandardNamespace" }, - { 0x0002, 0, 0x00, "SupportedModes" }, - { 0x0003, 0, 0x00, "CurrentMode" }, - { 0x0004, 0, 0x00, "StartUpMode" }, - { 0x0005, 0, 0x00, "OnMode" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Description" }, + { 0x0001, 0, 0x02, "StandardNamespace" }, + { 0x0002, 0, 0x02, "SupportedModes" }, + { 0x0003, 0, 0x02, "CurrentMode" }, + { 0x0004, 0, 0x03, "StartUpMode" }, + { 0x0005, 0, 0x03, "OnMode" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -825,36 +825,36 @@ const matter_command_t matter_Commands_0050[] = { }; const matter_attribute_t matter_Attributes_0101[] = { - { 0x0000, 0, 0x00, "LockState" }, - { 0x0001, 0, 0x00, "LockType" }, - { 0x0002, 0, 0x00, "ActuatorEnabled" }, - { 0x0003, 0, 0x00, "DoorState" }, - { 0x0011, 0, 0x00, "NumberOfTotalUsersSupported" }, - { 0x0012, 0, 0x00, "NumberOfPINUsersSupported" }, - { 0x0013, 0, 0x00, "NumberOfRFIDUsersSupported" }, - { 0x0014, 0, 0x00, "NumberOfWeekDaySchedulesSupportedPerUser" }, - { 0x0015, 0, 0x00, "NumberOfYearDaySchedulesSupportedPerUser" }, - { 0x0016, 0, 0x00, "NumberOfHolidaySchedulesSupported" }, - { 0x0017, 0, 0x00, "MaxPINCodeLength" }, - { 0x0018, 0, 0x00, "MinPINCodeLength" }, - { 0x0019, 0, 0x00, "MaxRFIDCodeLength" }, - { 0x001A, 0, 0x00, "MinRFIDCodeLength" }, - { 0x001C, 0, 0x00, "NumberOfCredentialsSupportedPerUser" }, - { 0x0021, 0, 0x00, "Language" }, - { 0x0023, 0, 0x00, "AutoRelockTime" }, - { 0x0024, 0, 0x00, "SoundVolume" }, - { 0x0025, 0, 0x00, "OperatingMode" }, - { 0x0026, 0, 0x00, "SupportedOperatingModes" }, - { 0x0029, 0, 0x00, "EnableOneTouchLocking" }, - { 0x002B, 0, 0x00, "EnablePrivacyModeButton" }, - { 0x0030, 0, 0x00, "WrongCodeEntryLimit" }, - { 0x0031, 0, 0x00, "UserCodeTemporaryDisableTime" }, - { 0x0033, 0, 0x00, "RequirePINforRemoteOperation" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "LockState" }, + { 0x0001, 0, 0x02, "LockType" }, + { 0x0002, 0, 0x02, "ActuatorEnabled" }, + { 0x0003, 0, 0x02, "DoorState" }, + { 0x0011, 0, 0x02, "NumberOfTotalUsersSupported" }, + { 0x0012, 0, 0x02, "NumberOfPINUsersSupported" }, + { 0x0013, 0, 0x02, "NumberOfRFIDUsersSupported" }, + { 0x0014, 0, 0x02, "NumberOfWeekDaySchedulesSupportedPerUser" }, + { 0x0015, 0, 0x02, "NumberOfYearDaySchedulesSupportedPerUser" }, + { 0x0016, 0, 0x02, "NumberOfHolidaySchedulesSupported" }, + { 0x0017, 0, 0x02, "MaxPINCodeLength" }, + { 0x0018, 0, 0x02, "MinPINCodeLength" }, + { 0x0019, 0, 0x02, "MaxRFIDCodeLength" }, + { 0x001A, 0, 0x02, "MinRFIDCodeLength" }, + { 0x001C, 0, 0x02, "NumberOfCredentialsSupportedPerUser" }, + { 0x0021, 0, 0x03, "Language" }, + { 0x0023, 0, 0x03, "AutoRelockTime" }, + { 0x0024, 0, 0x03, "SoundVolume" }, + { 0x0025, 0, 0x03, "OperatingMode" }, + { 0x0026, 0, 0x02, "SupportedOperatingModes" }, + { 0x0029, 0, 0x03, "EnableOneTouchLocking" }, + { 0x002B, 0, 0x03, "EnablePrivacyModeButton" }, + { 0x0030, 0, 0x03, "WrongCodeEntryLimit" }, + { 0x0031, 0, 0x03, "UserCodeTemporaryDisableTime" }, + { 0x0033, 0, 0x01, "RequirePINforRemoteOperation" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -881,33 +881,33 @@ const matter_command_t matter_Commands_0101[] = { }; const matter_attribute_t matter_Attributes_0102[] = { - { 0x0000, 0, 0x00, "Type" }, - { 0x0001, 0, 0x00, "PhysicalClosedLimitLift" }, - { 0x0002, 0, 0x00, "PhysicalClosedLimitTilt" }, - { 0x0003, 0, 0x00, "CurrentPositionLift" }, - { 0x0004, 0, 0x00, "CurrentPositionTilt" }, - { 0x0005, 0, 0x00, "NumberOfActuationsLift" }, - { 0x0006, 0, 0x00, "NumberOfActuationsTilt" }, - { 0x0007, 0, 0x00, "ConfigStatus" }, - { 0x0008, 0, 0x00, "CurrentPositionLiftPercentage" }, - { 0x0009, 0, 0x00, "CurrentPositionTiltPercentage" }, - { 0x000A, 0, 0x00, "OperationalStatus" }, - { 0x000B, 0, 0x00, "TargetPositionLiftPercent100ths" }, - { 0x000C, 0, 0x00, "TargetPositionTiltPercent100ths" }, - { 0x000D, 0, 0x00, "EndProductType" }, - { 0x000E, 0, 0x00, "CurrentPositionLiftPercent100ths" }, - { 0x000F, 0, 0x00, "CurrentPositionTiltPercent100ths" }, - { 0x0010, 0, 0x00, "InstalledOpenLimitLift" }, - { 0x0011, 0, 0x00, "InstalledClosedLimitLift" }, - { 0x0012, 0, 0x00, "InstalledOpenLimitTilt" }, - { 0x0013, 0, 0x00, "InstalledClosedLimitTilt" }, - { 0x0017, 0, 0x00, "Mode" }, - { 0x001A, 0, 0x00, "SafetyStatus" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Type" }, + { 0x0001, 0, 0x02, "PhysicalClosedLimitLift" }, + { 0x0002, 0, 0x02, "PhysicalClosedLimitTilt" }, + { 0x0003, 0, 0x02, "CurrentPositionLift" }, + { 0x0004, 0, 0x02, "CurrentPositionTilt" }, + { 0x0005, 0, 0x02, "NumberOfActuationsLift" }, + { 0x0006, 0, 0x02, "NumberOfActuationsTilt" }, + { 0x0007, 0, 0x02, "ConfigStatus" }, + { 0x0008, 0, 0x02, "CurrentPositionLiftPercentage" }, + { 0x0009, 0, 0x02, "CurrentPositionTiltPercentage" }, + { 0x000A, 0, 0x02, "OperationalStatus" }, + { 0x000B, 0, 0x02, "TargetPositionLiftPercent100ths" }, + { 0x000C, 0, 0x02, "TargetPositionTiltPercent100ths" }, + { 0x000D, 0, 0x02, "EndProductType" }, + { 0x000E, 0, 0x02, "CurrentPositionLiftPercent100ths" }, + { 0x000F, 0, 0x02, "CurrentPositionTiltPercent100ths" }, + { 0x0010, 0, 0x02, "InstalledOpenLimitLift" }, + { 0x0011, 0, 0x02, "InstalledClosedLimitLift" }, + { 0x0012, 0, 0x02, "InstalledOpenLimitTilt" }, + { 0x0013, 0, 0x02, "InstalledClosedLimitTilt" }, + { 0x0017, 0, 0x03, "Mode" }, + { 0x001A, 0, 0x02, "SafetyStatus" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -923,15 +923,15 @@ const matter_command_t matter_Commands_0102[] = { }; const matter_attribute_t matter_Attributes_0103[] = { - { 0x0001, 0, 0x00, "BarrierMovingState" }, - { 0x0002, 0, 0x00, "BarrierSafetyStatus" }, - { 0x0003, 0, 0x00, "BarrierCapabilities" }, - { 0x000A, 0, 0x00, "BarrierPosition" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0001, 0, 0x02, "BarrierMovingState" }, + { 0x0002, 0, 0x02, "BarrierSafetyStatus" }, + { 0x0003, 0, 0x02, "BarrierCapabilities" }, + { 0x000A, 0, 0x02, "BarrierPosition" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -942,34 +942,34 @@ const matter_command_t matter_Commands_0103[] = { }; const matter_attribute_t matter_Attributes_0200[] = { - { 0x0000, 0, 0x00, "MaxPressure" }, - { 0x0001, 0, 0x00, "MaxSpeed" }, - { 0x0002, 0, 0x00, "MaxFlow" }, - { 0x0003, 0, 0x00, "MinConstPressure" }, - { 0x0004, 0, 0x00, "MaxConstPressure" }, - { 0x0005, 0, 0x00, "MinCompPressure" }, - { 0x0006, 0, 0x00, "MaxCompPressure" }, - { 0x0007, 0, 0x00, "MinConstSpeed" }, - { 0x0008, 0, 0x00, "MaxConstSpeed" }, - { 0x0009, 0, 0x00, "MinConstFlow" }, - { 0x000A, 0, 0x00, "MaxConstFlow" }, - { 0x000B, 0, 0x00, "MinConstTemp" }, - { 0x000C, 0, 0x00, "MaxConstTemp" }, - { 0x0010, 0, 0x00, "PumpStatus" }, - { 0x0011, 0, 0x00, "EffectiveOperationMode" }, - { 0x0012, 0, 0x00, "EffectiveControlMode" }, - { 0x0013, 0, 0x00, "Capacity" }, - { 0x0014, 0, 0x00, "Speed" }, - { 0x0015, 0, 0x00, "LifetimeRunningHours" }, - { 0x0016, 0, 0x00, "Power" }, - { 0x0017, 0, 0x00, "LifetimeEnergyConsumed" }, - { 0x0020, 0, 0x00, "OperationMode" }, - { 0x0021, 0, 0x00, "ControlMode" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MaxPressure" }, + { 0x0001, 0, 0x02, "MaxSpeed" }, + { 0x0002, 0, 0x02, "MaxFlow" }, + { 0x0003, 0, 0x02, "MinConstPressure" }, + { 0x0004, 0, 0x02, "MaxConstPressure" }, + { 0x0005, 0, 0x02, "MinCompPressure" }, + { 0x0006, 0, 0x02, "MaxCompPressure" }, + { 0x0007, 0, 0x02, "MinConstSpeed" }, + { 0x0008, 0, 0x02, "MaxConstSpeed" }, + { 0x0009, 0, 0x02, "MinConstFlow" }, + { 0x000A, 0, 0x02, "MaxConstFlow" }, + { 0x000B, 0, 0x02, "MinConstTemp" }, + { 0x000C, 0, 0x02, "MaxConstTemp" }, + { 0x0010, 0, 0x02, "PumpStatus" }, + { 0x0011, 0, 0x02, "EffectiveOperationMode" }, + { 0x0012, 0, 0x02, "EffectiveControlMode" }, + { 0x0013, 0, 0x02, "Capacity" }, + { 0x0014, 0, 0x02, "Speed" }, + { 0x0015, 0, 0x03, "LifetimeRunningHours" }, + { 0x0016, 0, 0x02, "Power" }, + { 0x0017, 0, 0x03, "LifetimeEnergyConsumed" }, + { 0x0020, 0, 0x03, "OperationMode" }, + { 0x0021, 0, 0x03, "ControlMode" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -978,26 +978,26 @@ const matter_command_t matter_Commands_0200[] = { }; const matter_attribute_t matter_Attributes_0201[] = { - { 0x0000, 0, 0x00, "LocalTemperature" }, - { 0x0003, 0, 0x00, "AbsMinHeatSetpointLimit" }, - { 0x0004, 0, 0x00, "AbsMaxHeatSetpointLimit" }, - { 0x0005, 0, 0x00, "AbsMinCoolSetpointLimit" }, - { 0x0006, 0, 0x00, "AbsMaxCoolSetpointLimit" }, - { 0x0011, 0, 0x00, "OccupiedCoolingSetpoint" }, - { 0x0012, 0, 0x00, "OccupiedHeatingSetpoint" }, - { 0x0015, 0, 0x00, "MinHeatSetpointLimit" }, - { 0x0016, 0, 0x00, "MaxHeatSetpointLimit" }, - { 0x0017, 0, 0x00, "MinCoolSetpointLimit" }, - { 0x0018, 0, 0x00, "MaxCoolSetpointLimit" }, - { 0x0019, 0, 0x00, "MinSetpointDeadBand" }, - { 0x001B, 0, 0x00, "ControlSequenceOfOperation" }, - { 0x001C, 0, 0x00, "SystemMode" }, - { 0x0020, 0, 0x00, "StartOfWeek" }, - { 0x0021, 0, 0x00, "NumberOfWeeklyTransitions" }, - { 0x0022, 0, 0x00, "NumberOfDailyTransitions" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "LocalTemperature" }, + { 0x0003, 0, 0x02, "AbsMinHeatSetpointLimit" }, + { 0x0004, 0, 0x02, "AbsMaxHeatSetpointLimit" }, + { 0x0005, 0, 0x02, "AbsMinCoolSetpointLimit" }, + { 0x0006, 0, 0x02, "AbsMaxCoolSetpointLimit" }, + { 0x0011, 0, 0x03, "OccupiedCoolingSetpoint" }, + { 0x0012, 0, 0x03, "OccupiedHeatingSetpoint" }, + { 0x0015, 0, 0x03, "MinHeatSetpointLimit" }, + { 0x0016, 0, 0x03, "MaxHeatSetpointLimit" }, + { 0x0017, 0, 0x03, "MinCoolSetpointLimit" }, + { 0x0018, 0, 0x03, "MaxCoolSetpointLimit" }, + { 0x0019, 0, 0x03, "MinSetpointDeadBand" }, + { 0x001B, 0, 0x03, "ControlSequenceOfOperation" }, + { 0x001C, 0, 0x03, "SystemMode" }, + { 0x0020, 0, 0x02, "StartOfWeek" }, + { 0x0021, 0, 0x02, "NumberOfWeeklyTransitions" }, + { 0x0022, 0, 0x02, "NumberOfDailyTransitions" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1010,22 +1010,22 @@ const matter_command_t matter_Commands_0201[] = { }; const matter_attribute_t matter_Attributes_0202[] = { - { 0x0000, 0, 0x00, "FanMode" }, - { 0x0001, 0, 0x00, "FanModeSequence" }, - { 0x0002, 0, 0x00, "PercentSetting" }, - { 0x0003, 0, 0x00, "PercentCurrent" }, - { 0x0004, 0, 0x00, "SpeedMax" }, - { 0x0005, 0, 0x00, "SpeedSetting" }, - { 0x0006, 0, 0x00, "SpeedCurrent" }, - { 0x0007, 0, 0x00, "RockSupport" }, - { 0x0008, 0, 0x00, "RockSetting" }, - { 0x0009, 0, 0x00, "WindSupport" }, - { 0x000A, 0, 0x00, "WindSetting" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "FanMode" }, + { 0x0001, 0, 0x03, "FanModeSequence" }, + { 0x0002, 0, 0x03, "PercentSetting" }, + { 0x0003, 0, 0x02, "PercentCurrent" }, + { 0x0004, 0, 0x02, "SpeedMax" }, + { 0x0005, 0, 0x03, "SpeedSetting" }, + { 0x0006, 0, 0x02, "SpeedCurrent" }, + { 0x0007, 0, 0x02, "RockSupport" }, + { 0x0008, 0, 0x03, "RockSetting" }, + { 0x0009, 0, 0x02, "WindSupport" }, + { 0x000A, 0, 0x03, "WindSetting" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1034,14 +1034,14 @@ const matter_command_t matter_Commands_0202[] = { }; const matter_attribute_t matter_Attributes_0204[] = { - { 0x0000, 0, 0x00, "TemperatureDisplayMode" }, - { 0x0001, 0, 0x00, "KeypadLockout" }, - { 0x0002, 0, 0x00, "ScheduleProgrammingVisibility" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x03, "TemperatureDisplayMode" }, + { 0x0001, 0, 0x03, "KeypadLockout" }, + { 0x0002, 0, 0x03, "ScheduleProgrammingVisibility" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1050,63 +1050,63 @@ const matter_command_t matter_Commands_0204[] = { }; const matter_attribute_t matter_Attributes_0300[] = { - { 0x0000, 0, 0x00, "CurrentHue" }, - { 0x0001, 0, 0x00, "CurrentSaturation" }, - { 0x0002, 0, 0x00, "RemainingTime" }, - { 0x0003, 0, 0x00, "CurrentX" }, - { 0x0004, 0, 0x00, "CurrentY" }, - { 0x0005, 0, 0x00, "DriftCompensation" }, - { 0x0006, 0, 0x00, "CompensationText" }, - { 0x0007, 0, 0x00, "ColorTemperatureMireds" }, - { 0x0008, 0, 0x00, "ColorMode" }, - { 0x000F, 0, 0x00, "Options" }, - { 0x0010, 0, 0x00, "NumberOfPrimaries" }, - { 0x0011, 0, 0x00, "Primary1X" }, - { 0x0012, 0, 0x00, "Primary1Y" }, - { 0x0013, 0, 0x00, "Primary1Intensity" }, - { 0x0015, 0, 0x00, "Primary2X" }, - { 0x0016, 0, 0x00, "Primary2Y" }, - { 0x0017, 0, 0x00, "Primary2Intensity" }, - { 0x0019, 0, 0x00, "Primary3X" }, - { 0x001A, 0, 0x00, "Primary3Y" }, - { 0x001B, 0, 0x00, "Primary3Intensity" }, - { 0x0020, 0, 0x00, "Primary4X" }, - { 0x0021, 0, 0x00, "Primary4Y" }, - { 0x0022, 0, 0x00, "Primary4Intensity" }, - { 0x0024, 0, 0x00, "Primary5X" }, - { 0x0025, 0, 0x00, "Primary5Y" }, - { 0x0026, 0, 0x00, "Primary5Intensity" }, - { 0x0028, 0, 0x00, "Primary6X" }, - { 0x0029, 0, 0x00, "Primary6Y" }, - { 0x002A, 0, 0x00, "Primary6Intensity" }, - { 0x0030, 0, 0x00, "WhitePointX" }, - { 0x0031, 0, 0x00, "WhitePointY" }, - { 0x0032, 0, 0x00, "ColorPointRX" }, - { 0x0033, 0, 0x00, "ColorPointRY" }, - { 0x0034, 0, 0x00, "ColorPointRIntensity" }, - { 0x0036, 0, 0x00, "ColorPointGX" }, - { 0x0037, 0, 0x00, "ColorPointGY" }, - { 0x0038, 0, 0x00, "ColorPointGIntensity" }, - { 0x003A, 0, 0x00, "ColorPointBX" }, - { 0x003B, 0, 0x00, "ColorPointBY" }, - { 0x003C, 0, 0x00, "ColorPointBIntensity" }, - { 0x4000, 0, 0x00, "EnhancedCurrentHue" }, - { 0x4001, 0, 0x00, "EnhancedColorMode" }, - { 0x4002, 0, 0x00, "ColorLoopActive" }, - { 0x4003, 0, 0x00, "ColorLoopDirection" }, - { 0x4004, 0, 0x00, "ColorLoopTime" }, - { 0x4005, 0, 0x00, "ColorLoopStartEnhancedHue" }, - { 0x4006, 0, 0x00, "ColorLoopStoredEnhancedHue" }, - { 0x400A, 0, 0x00, "ColorCapabilities" }, - { 0x400B, 0, 0x00, "ColorTempPhysicalMinMireds" }, - { 0x400C, 0, 0x00, "ColorTempPhysicalMaxMireds" }, - { 0x400D, 0, 0x00, "CoupleColorTempToLevelMinMireds" }, - { 0x4010, 0, 0x00, "StartUpColorTemperatureMireds" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "CurrentHue" }, + { 0x0001, 0, 0x02, "CurrentSaturation" }, + { 0x0002, 0, 0x02, "RemainingTime" }, + { 0x0003, 0, 0x02, "CurrentX" }, + { 0x0004, 0, 0x02, "CurrentY" }, + { 0x0005, 0, 0x02, "DriftCompensation" }, + { 0x0006, 0, 0x02, "CompensationText" }, + { 0x0007, 0, 0x02, "ColorTemperatureMireds" }, + { 0x0008, 0, 0x02, "ColorMode" }, + { 0x000F, 0, 0x03, "Options" }, + { 0x0010, 0, 0x02, "NumberOfPrimaries" }, + { 0x0011, 0, 0x02, "Primary1X" }, + { 0x0012, 0, 0x02, "Primary1Y" }, + { 0x0013, 0, 0x02, "Primary1Intensity" }, + { 0x0015, 0, 0x02, "Primary2X" }, + { 0x0016, 0, 0x02, "Primary2Y" }, + { 0x0017, 0, 0x02, "Primary2Intensity" }, + { 0x0019, 0, 0x02, "Primary3X" }, + { 0x001A, 0, 0x02, "Primary3Y" }, + { 0x001B, 0, 0x02, "Primary3Intensity" }, + { 0x0020, 0, 0x02, "Primary4X" }, + { 0x0021, 0, 0x02, "Primary4Y" }, + { 0x0022, 0, 0x02, "Primary4Intensity" }, + { 0x0024, 0, 0x02, "Primary5X" }, + { 0x0025, 0, 0x02, "Primary5Y" }, + { 0x0026, 0, 0x02, "Primary5Intensity" }, + { 0x0028, 0, 0x02, "Primary6X" }, + { 0x0029, 0, 0x02, "Primary6Y" }, + { 0x002A, 0, 0x02, "Primary6Intensity" }, + { 0x0030, 0, 0x03, "WhitePointX" }, + { 0x0031, 0, 0x03, "WhitePointY" }, + { 0x0032, 0, 0x03, "ColorPointRX" }, + { 0x0033, 0, 0x03, "ColorPointRY" }, + { 0x0034, 0, 0x03, "ColorPointRIntensity" }, + { 0x0036, 0, 0x03, "ColorPointGX" }, + { 0x0037, 0, 0x03, "ColorPointGY" }, + { 0x0038, 0, 0x03, "ColorPointGIntensity" }, + { 0x003A, 0, 0x03, "ColorPointBX" }, + { 0x003B, 0, 0x03, "ColorPointBY" }, + { 0x003C, 0, 0x03, "ColorPointBIntensity" }, + { 0x4000, 0, 0x02, "EnhancedCurrentHue" }, + { 0x4001, 0, 0x02, "EnhancedColorMode" }, + { 0x4002, 0, 0x02, "ColorLoopActive" }, + { 0x4003, 0, 0x02, "ColorLoopDirection" }, + { 0x4004, 0, 0x02, "ColorLoopTime" }, + { 0x4005, 0, 0x02, "ColorLoopStartEnhancedHue" }, + { 0x4006, 0, 0x02, "ColorLoopStoredEnhancedHue" }, + { 0x400A, 0, 0x02, "ColorCapabilities" }, + { 0x400B, 0, 0x02, "ColorTempPhysicalMinMireds" }, + { 0x400C, 0, 0x02, "ColorTempPhysicalMaxMireds" }, + { 0x400D, 0, 0x02, "CoupleColorTempToLevelMinMireds" }, + { 0x4010, 0, 0x03, "StartUpColorTemperatureMireds" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1134,25 +1134,25 @@ const matter_command_t matter_Commands_0300[] = { }; const matter_attribute_t matter_Attributes_0301[] = { - { 0x0000, 0, 0x00, "PhysicalMinLevel" }, - { 0x0001, 0, 0x00, "PhysicalMaxLevel" }, - { 0x0002, 0, 0x00, "BallastStatus" }, - { 0x0010, 0, 0x00, "MinLevel" }, - { 0x0011, 0, 0x00, "MaxLevel" }, - { 0x0014, 0, 0x00, "IntrinsicBalanceFactor" }, - { 0x0015, 0, 0x00, "BallastFactorAdjustment" }, - { 0x0020, 0, 0x00, "LampQuantity" }, - { 0x0030, 0, 0x00, "LampType" }, - { 0x0031, 0, 0x00, "LampManufacturer" }, - { 0x0032, 0, 0x00, "LampRatedHours" }, - { 0x0033, 0, 0x00, "LampBurnHours" }, - { 0x0034, 0, 0x00, "LampAlarmMode" }, - { 0x0035, 0, 0x00, "LampBurnHoursTripPoint" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "PhysicalMinLevel" }, + { 0x0001, 0, 0x02, "PhysicalMaxLevel" }, + { 0x0002, 0, 0x02, "BallastStatus" }, + { 0x0010, 0, 0x03, "MinLevel" }, + { 0x0011, 0, 0x03, "MaxLevel" }, + { 0x0014, 0, 0x03, "IntrinsicBalanceFactor" }, + { 0x0015, 0, 0x03, "BallastFactorAdjustment" }, + { 0x0020, 0, 0x02, "LampQuantity" }, + { 0x0030, 0, 0x03, "LampType" }, + { 0x0031, 0, 0x03, "LampManufacturer" }, + { 0x0032, 0, 0x03, "LampRatedHours" }, + { 0x0033, 0, 0x03, "LampBurnHours" }, + { 0x0034, 0, 0x03, "LampAlarmMode" }, + { 0x0035, 0, 0x03, "LampBurnHoursTripPoint" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1161,16 +1161,16 @@ const matter_command_t matter_Commands_0301[] = { }; const matter_attribute_t matter_Attributes_0400[] = { - { 0x0000, 0, 0x00, "MeasuredValue" }, - { 0x0001, 0, 0x00, "MinMeasuredValue" }, - { 0x0002, 0, 0x00, "MaxMeasuredValue" }, - { 0x0003, 0, 0x00, "Tolerance" }, - { 0x0004, 0, 0x00, "LightSensorType" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MeasuredValue" }, + { 0x0001, 0, 0x02, "MinMeasuredValue" }, + { 0x0002, 0, 0x02, "MaxMeasuredValue" }, + { 0x0003, 0, 0x02, "Tolerance" }, + { 0x0004, 0, 0x02, "LightSensorType" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1179,13 +1179,13 @@ const matter_command_t matter_Commands_0400[] = { }; const matter_attribute_t matter_Attributes_0402[] = { - { 0x0000, 0, 0x00, "MeasuredValue" }, - { 0x0001, 0, 0x00, "MinMeasuredValue" }, - { 0x0002, 0, 0x00, "MaxMeasuredValue" }, - { 0x0003, 0, 0x00, "Tolerance" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MeasuredValue" }, + { 0x0001, 0, 0x02, "MinMeasuredValue" }, + { 0x0002, 0, 0x02, "MaxMeasuredValue" }, + { 0x0003, 0, 0x02, "Tolerance" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1194,18 +1194,18 @@ const matter_command_t matter_Commands_0402[] = { }; const matter_attribute_t matter_Attributes_0403[] = { - { 0x0000, 0, 0x00, "MeasuredValue" }, - { 0x0001, 0, 0x00, "MinMeasuredValue" }, - { 0x0002, 0, 0x00, "MaxMeasuredValue" }, - { 0x0003, 0, 0x00, "Tolerance" }, - { 0x0010, 0, 0x00, "ScaledValue" }, - { 0x0011, 0, 0x00, "MinScaledValue" }, - { 0x0012, 0, 0x00, "MaxScaledValue" }, - { 0x0013, 0, 0x00, "ScaledTolerance" }, - { 0x0014, 0, 0x00, "Scale" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MeasuredValue" }, + { 0x0001, 0, 0x02, "MinMeasuredValue" }, + { 0x0002, 0, 0x02, "MaxMeasuredValue" }, + { 0x0003, 0, 0x02, "Tolerance" }, + { 0x0010, 0, 0x02, "ScaledValue" }, + { 0x0011, 0, 0x02, "MinScaledValue" }, + { 0x0012, 0, 0x02, "MaxScaledValue" }, + { 0x0013, 0, 0x02, "ScaledTolerance" }, + { 0x0014, 0, 0x02, "Scale" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1214,15 +1214,15 @@ const matter_command_t matter_Commands_0403[] = { }; const matter_attribute_t matter_Attributes_0404[] = { - { 0x0000, 0, 0x00, "MeasuredValue" }, - { 0x0001, 0, 0x00, "MinMeasuredValue" }, - { 0x0002, 0, 0x00, "MaxMeasuredValue" }, - { 0x0003, 0, 0x00, "Tolerance" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MeasuredValue" }, + { 0x0001, 0, 0x02, "MinMeasuredValue" }, + { 0x0002, 0, 0x02, "MaxMeasuredValue" }, + { 0x0003, 0, 0x02, "Tolerance" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1231,15 +1231,15 @@ const matter_command_t matter_Commands_0404[] = { }; const matter_attribute_t matter_Attributes_0405[] = { - { 0x0000, 0, 0x00, "MeasuredValue" }, - { 0x0001, 0, 0x00, "MinMeasuredValue" }, - { 0x0002, 0, 0x00, "MaxMeasuredValue" }, - { 0x0003, 0, 0x00, "Tolerance" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MeasuredValue" }, + { 0x0001, 0, 0x02, "MinMeasuredValue" }, + { 0x0002, 0, 0x02, "MaxMeasuredValue" }, + { 0x0003, 0, 0x02, "Tolerance" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1248,14 +1248,14 @@ const matter_command_t matter_Commands_0405[] = { }; const matter_attribute_t matter_Attributes_0406[] = { - { 0x0000, 0, 0x00, "Occupancy" }, - { 0x0001, 0, 0x00, "OccupancySensorType" }, - { 0x0002, 0, 0x00, "OccupancySensorTypeBitmap" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "Occupancy" }, + { 0x0001, 0, 0x02, "OccupancySensorType" }, + { 0x0002, 0, 0x02, "OccupancySensorTypeBitmap" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1264,12 +1264,12 @@ const matter_command_t matter_Commands_0406[] = { }; const matter_attribute_t matter_Attributes_0503[] = { - { 0x0000, 0, 0x00, "MACAddress" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MACAddress" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1278,14 +1278,14 @@ const matter_command_t matter_Commands_0503[] = { }; const matter_attribute_t matter_Attributes_0504[] = { - { 0x0000, 0, 0x00, "ChannelList" }, - { 0x0001, 0, 0x00, "Lineup" }, - { 0x0002, 0, 0x00, "CurrentChannel" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "ChannelList" }, + { 0x0001, 0, 0x02, "Lineup" }, + { 0x0002, 0, 0x02, "CurrentChannel" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1297,13 +1297,13 @@ const matter_command_t matter_Commands_0504[] = { }; const matter_attribute_t matter_Attributes_0505[] = { - { 0x0000, 0, 0x00, "TargetList" }, - { 0x0001, 0, 0x00, "CurrentTarget" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "TargetList" }, + { 0x0001, 0, 0x02, "CurrentTarget" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1313,18 +1313,18 @@ const matter_command_t matter_Commands_0505[] = { }; const matter_attribute_t matter_Attributes_0506[] = { - { 0x0000, 0, 0x00, "CurrentState" }, - { 0x0001, 0, 0x00, "StartTime" }, - { 0x0002, 0, 0x00, "Duration" }, - { 0x0003, 0, 0x00, "SampledPosition" }, - { 0x0004, 0, 0x00, "PlaybackSpeed" }, - { 0x0005, 0, 0x00, "SeekRangeEnd" }, - { 0x0006, 0, 0x00, "SeekRangeStart" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "CurrentState" }, + { 0x0001, 0, 0x02, "StartTime" }, + { 0x0002, 0, 0x02, "Duration" }, + { 0x0003, 0, 0x02, "SampledPosition" }, + { 0x0004, 0, 0x02, "PlaybackSpeed" }, + { 0x0005, 0, 0x02, "SeekRangeEnd" }, + { 0x0006, 0, 0x02, "SeekRangeStart" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1344,13 +1344,13 @@ const matter_command_t matter_Commands_0506[] = { }; const matter_attribute_t matter_Attributes_0507[] = { - { 0x0000, 0, 0x00, "InputList" }, - { 0x0001, 0, 0x00, "CurrentInput" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "InputList" }, + { 0x0001, 0, 0x02, "CurrentInput" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1363,11 +1363,11 @@ const matter_command_t matter_Commands_0507[] = { }; const matter_attribute_t matter_Attributes_0508[] = { - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1377,11 +1377,11 @@ const matter_command_t matter_Commands_0508[] = { }; const matter_attribute_t matter_Attributes_0509[] = { - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1391,13 +1391,13 @@ const matter_command_t matter_Commands_0509[] = { }; const matter_attribute_t matter_Attributes_050A[] = { - { 0x0000, 0, 0x00, "AcceptHeader" }, - { 0x0001, 0, 0x00, "SupportedStreamingProtocols" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "AcceptHeader" }, + { 0x0001, 0, 0x03, "SupportedStreamingProtocols" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1408,13 +1408,13 @@ const matter_command_t matter_Commands_050A[] = { }; const matter_attribute_t matter_Attributes_050B[] = { - { 0x0000, 0, 0x00, "OutputList" }, - { 0x0001, 0, 0x00, "CurrentOutput" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "OutputList" }, + { 0x0001, 0, 0x02, "CurrentOutput" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1425,13 +1425,13 @@ const matter_command_t matter_Commands_050B[] = { }; const matter_attribute_t matter_Attributes_050C[] = { - { 0x0000, 0, 0x00, "CatalogList" }, - { 0x0001, 0, 0x00, "CurrentApp" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "CatalogList" }, + { 0x0001, 0, 0x03, "CurrentApp" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1443,19 +1443,19 @@ const matter_command_t matter_Commands_050C[] = { }; const matter_attribute_t matter_Attributes_050D[] = { - { 0x0000, 0, 0x00, "VendorName" }, - { 0x0001, 0, 0x00, "VendorID" }, - { 0x0002, 0, 0x00, "ApplicationName" }, - { 0x0003, 0, 0x00, "ProductID" }, - { 0x0004, 0, 0x00, "Application" }, - { 0x0005, 0, 0x00, "Status" }, - { 0x0006, 0, 0x00, "ApplicationVersion" }, - { 0x0007, 0, 0x00, "AllowedVendorList" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "VendorName" }, + { 0x0001, 0, 0x02, "VendorID" }, + { 0x0002, 0, 0x02, "ApplicationName" }, + { 0x0003, 0, 0x02, "ProductID" }, + { 0x0004, 0, 0x02, "Application" }, + { 0x0005, 0, 0x02, "Status" }, + { 0x0006, 0, 0x02, "ApplicationVersion" }, + { 0x0007, 0, 0x02, "AllowedVendorList" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1464,11 +1464,11 @@ const matter_command_t matter_Commands_050D[] = { }; const matter_attribute_t matter_Attributes_050E[] = { - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; @@ -1480,22 +1480,22 @@ const matter_command_t matter_Commands_050E[] = { }; const matter_attribute_t matter_Attributes_0B04[] = { - { 0x0000, 0, 0x00, "MeasurementType" }, - { 0x0304, 0, 0x00, "TotalActivePower" }, - { 0x0505, 0, 0x00, "RmsVoltage" }, - { 0x0506, 0, 0x00, "RmsVoltageMin" }, - { 0x0507, 0, 0x00, "RmsVoltageMax" }, - { 0x0508, 0, 0x00, "RmsCurrent" }, - { 0x0509, 0, 0x00, "RmsCurrentMin" }, - { 0x050A, 0, 0x00, "RmsCurrentMax" }, - { 0x050B, 0, 0x00, "ActivePower" }, - { 0x050C, 0, 0x00, "ActivePowerMin" }, - { 0x050D, 0, 0x00, "ActivePowerMax" }, - { 0xFFF8, 0, 0x00, "GeneratedCommandList" }, - { 0xFFF9, 0, 0x00, "AcceptedCommandList" }, - { 0xFFFB, 0, 0x00, "AttributeList" }, - { 0xFFFC, 0, 0x00, "FeatureMap" }, - { 0xFFFD, 0, 0x00, "ClusterRevision" }, + { 0x0000, 0, 0x02, "MeasurementType" }, + { 0x0304, 0, 0x02, "TotalActivePower" }, + { 0x0505, 0, 0x02, "RmsVoltage" }, + { 0x0506, 0, 0x02, "RmsVoltageMin" }, + { 0x0507, 0, 0x02, "RmsVoltageMax" }, + { 0x0508, 0, 0x02, "RmsCurrent" }, + { 0x0509, 0, 0x02, "RmsCurrentMin" }, + { 0x050A, 0, 0x02, "RmsCurrentMax" }, + { 0x050B, 0, 0x02, "ActivePower" }, + { 0x050C, 0, 0x02, "ActivePowerMin" }, + { 0x050D, 0, 0x02, "ActivePowerMax" }, + { 0xFFF8, 0, 0x02, "GeneratedCommandList" }, + { 0xFFF9, 0, 0x02, "AcceptedCommandList" }, + { 0xFFFB, 0, 0x02, "AttributeList" }, + { 0xFFFC, 0, 0x02, "FeatureMap" }, + { 0xFFFD, 0, 0x02, "ClusterRevision" }, { 0xFFFF, 0, 0x00, NULL }, }; diff --git a/lib/libesp32/berry_matter/src/be_matter_counter.cpp b/lib/libesp32/berry_matter/src/be_matter_counter.cpp index a33dd6442..f8870156f 100644 --- a/lib/libesp32/berry_matter/src/be_matter_counter.cpp +++ b/lib/libesp32/berry_matter/src/be_matter_counter.cpp @@ -69,6 +69,12 @@ static void mc_deinit(bvm *vm, matter_counter_t *c) { } BE_FUNC_CTYPE_DECLARE(mc_deinit, "", "@.") +// do a unisgned int32 comparison +bbool mc_is_greater(uint32_t a, uint32_t b) { + return a > b; +} +BE_FUNC_CTYPE_DECLARE(mc_is_greater, "b", "ii") + static void mc_reset(matter_counter_t *c, int32_t val) { c->counter = val; c->window.reset(); @@ -175,7 +181,7 @@ static int mc_tostring(bvm *vm) { #include "be_fixed_be_class_Matter_Counter.h" /* @const_object_info_begin -class be_class_Matter_Counter (scope: global, name: Matter_Counter) { +class be_class_Matter_Counter (scope: global, name: Matter_Counter, strings: weak) { _p, var init, ctype_func(mc_init) deinit, ctype_func(mc_deinit) @@ -185,6 +191,8 @@ class be_class_Matter_Counter (scope: global, name: Matter_Counter) { val, ctype_func(mc_val) next, ctype_func(mc_next) validate, ctype_func(mc_validate) + + is_greater, static_ctype_func(mc_is_greater) // compare two numbers as unsigned 32 bits } @const_object_info_end */ diff --git a/lib/libesp32/berry_matter/src/be_matter_module.c b/lib/libesp32/berry_matter/src/be_matter_module.c index dce07d4f7..8b5d31b5c 100644 --- a/lib/libesp32/berry_matter/src/be_matter_module.c +++ b/lib/libesp32/berry_matter/src/be_matter_module.c @@ -25,8 +25,6 @@ #include "be_constobj.h" #include "be_mapping.h" -#include "be_matter_qrcode_min_js.h" - // Matter logo static const uint8_t MATTER_LOGO[] = "" @@ -40,6 +38,7 @@ static const uint8_t MATTER_LOGO[] = extern const bclass be_class_Matter_Counter; extern const bclass be_class_Matter_Verhoeff; +extern const bclass be_class_Matter_QRCode; #include "solidify/solidified_Matter_Module.h" @@ -80,6 +79,34 @@ const char* matter_get_attribute_name(uint16_t cluster, uint16_t attribute) { } BE_FUNC_CTYPE_DECLARE(matter_get_attribute_name, "s", "ii") +bbool matter_is_attribute_writable(uint16_t cluster, uint16_t attribute) { + for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) { + if (cl->id == cluster) { + for (const matter_attribute_t * at = cl->attributes; at->id != 0xFFFF; at++) { + if (at->id == attribute) { + return (at->flags & 0x01) ? btrue : bfalse; + } + } + } + } + return bfalse; +} +BE_FUNC_CTYPE_DECLARE(matter_is_attribute_writable, "b", "ii") + +bbool matter_is_attribute_reportable(uint16_t cluster, uint16_t attribute) { + for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) { + if (cl->id == cluster) { + for (const matter_attribute_t * at = cl->attributes; at->id != 0xFFFF; at++) { + if (at->id == attribute) { + return (at->flags & 0x02) ? btrue : bfalse; + } + } + } + } + return bfalse; +} +BE_FUNC_CTYPE_DECLARE(matter_is_attribute_reportable, "b", "ii") + const char* matter_get_command_name(uint16_t cluster, uint16_t command) { for (const matter_cluster_t * cl = matterAllClusters; cl->id != 0xFFFF; cl++) { if (cl->id == cluster) { @@ -102,15 +129,22 @@ BE_FUNC_CTYPE_DECLARE(matter_get_ip_bytes, "&", "s") #include "solidify/solidified_Matter_inspect.h" extern const bclass be_class_Matter_TLV; // need to declare it upfront because of circular reference +#include "solidify/solidified_Matter_Path.h" #include "solidify/solidified_Matter_TLV.h" #include "solidify/solidified_Matter_IM_Data.h" #include "solidify/solidified_Matter_UDPServer.h" +#include "solidify/solidified_Matter_Expirable.h" +#include "solidify/solidified_Matter_Fabric.h" #include "solidify/solidified_Matter_Session.h" +#include "solidify/solidified_Matter_Session_Store.h" #include "solidify/solidified_Matter_Commissioning_Data.h" #include "solidify/solidified_Matter_Commissioning.h" #include "solidify/solidified_Matter_Message.h" #include "solidify/solidified_Matter_MessageHandler.h" +#include "solidify/solidified_Matter_IM_Message.h" +#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_Base38.h" #include "solidify/solidified_Matter_UI.h" @@ -118,8 +152,14 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because #include "../generate/be_matter_certs.h" -#include "solidify/solidified_Matter_Plugin_core.h" -#include "solidify/solidified_Matter_Plugin_Relay.h" +#include "solidify/solidified_Matter_Plugin_Root.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_Temp_Sensor.h" /*********************************************************************************************\ * Get a bytes() object of the certificate DAC/PAI_Cert @@ -145,9 +185,8 @@ static int matter_CD_FFF1_8000(bvm *vm) { return matter_return_static_bytes(vm, /* @const_object_info_begin -module matter (scope: global) { +module matter (scope: global, strings: weak) { _LOGO, comptr(MATTER_LOGO) - _QRCODE_MINJS, comptr(QRCODE_MINJS) MATTER_OPTION, int(151) // SetOption151 enables Matter Verhoeff, class(be_class_Matter_Verhoeff) @@ -158,6 +197,8 @@ module matter (scope: global) { get_cluster_name, ctype_func(matter_get_cluster_name) get_attribute_name, ctype_func(matter_get_attribute_name) + is_attribute_writable, ctype_func(matter_is_attribute_writable) + is_attribute_reportable, ctype_func(matter_is_attribute_reportable) get_command_name, ctype_func(matter_get_command_name) get_opcode_name, ctype_func(matter_get_opcode_name) TLV, class(be_class_Matter_TLV) @@ -238,7 +279,12 @@ module matter (scope: global) { UDPPacket_sent, class(be_class_Matter_UDPPacket_sent) UDPServer, class(be_class_Matter_UDPServer) + // Expirable + Expirable, class(be_class_Matter_Expirable) + Expirable_list, class(be_class_Matter_Expirable_list) + // Sessions + Fabric, class(be_class_Matter_Fabric) Session, class(be_class_Matter_Session) Session_Store, class(be_class_Matter_Session_Store) @@ -247,11 +293,23 @@ module matter (scope: global) { MessageHandler, class(be_class_Matter_MessageHandler) // Interation Model - Response_container, class(be_class_Matter_Response_container) + Path, class(be_class_Matter_Path) + IM_Status, class(be_class_Matter_IM_Status) + IM_InvokeResponse, class(be_class_Matter_IM_InvokeResponse) + IM_WriteResponse, class(be_class_Matter_IM_WriteResponse) + IM_ReportData, class(be_class_Matter_IM_ReportData) + IM_ReportDataSubscribed, class(be_class_Matter_IM_ReportDataSubscribed) + IM_SubscribeResponse, class(be_class_Matter_IM_SubscribeResponse) + IM_SubscribedHeartbeat, class(be_class_Matter_IM_SubscribedHeartbeat) + IM_Subscription, class(be_class_Matter_IM_Subscription) + IM_Subscription_Shop, class(be_class_Matter_IM_Subscription_Shop) IM, class(be_class_Matter_IM) - Plugin_core, class(be_class_Matter_Plugin_core) + Control_Message, class(be_class_Matter_Control_Message) UI, class(be_class_Matter_UI) + // QR Code + QRCode, class(be_class_Matter_QRCode) + // Base38 for QR Code Base38, class(be_class_Matter_Base38) @@ -265,11 +323,17 @@ module matter (scope: global) { DAC_Cert_FFF1_8000, func(matter_DAC_Cert_FFF1_8000) DAC_Pub_FFF1_8000, func(matter_DAC_Pub_FFF1_8000) DAC_Priv_FFF1_8000, func(matter_DAC_Priv_FFF1_8000) - CD_FFF1_8000, func(matter_CD_FFF1_8000) // Certification Declaration + CD_FFF1_8000, func(matter_CD_FFF1_8000) // Certification Declaration // Plugins - Plugin_core, class(be_class_Matter_Plugin_core) // Generic behavior common to all devices - Plugin_Relay, class(be_class_Matter_Plugin_Relay) // Relay behavior (OnOff) + Plugin_Root, class(be_class_Matter_Plugin_Root) // Generic behavior common to all devices + Plugin_Device, class(be_class_Matter_Plugin_Device) // Generic device (abstract) + Plugin_OnOff, class(be_class_Matter_Plugin_OnOff) // Relay/Light behavior (OnOff) + Plugin_Light0, class(be_class_Matter_Plugin_Light0) // OnOff Light + Plugin_Light1, class(be_class_Matter_Plugin_Light1) // Dimmable Light + Plugin_Light2, class(be_class_Matter_Plugin_Light2) // Color Temperature Light + Plugin_Light3, class(be_class_Matter_Plugin_Light3) // Extended Color Light + Plugin_Temp_Sensor, class(be_class_Matter_Plugin_Temp_Sensor) // Temperature Sensor } @const_object_info_end */ diff --git a/lib/libesp32/berry_matter/src/be_matter_qrcode.c b/lib/libesp32/berry_matter/src/be_matter_qrcode.c new file mode 100644 index 000000000..5bcddef86 --- /dev/null +++ b/lib/libesp32/berry_matter/src/be_matter_qrcode.c @@ -0,0 +1,107 @@ +/* + be_matter_qrcode.cpp - implements Matter QRCode encoder as UTF8 + + 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 . +*/ + +#include +#include "be_constobj.h" +#include "be_mapping.h" +#include "be_mem.h" +#include "be_exec.h" +#include "qrcodegen.h" + +/******************************************************************************************************\ + * + * + * +\******************************************************************************************************/ + +// `matter.QRCode.encode_str(content:string) -> map` +// +int32_t qr_encode_str(bvm *vm) { + int32_t argc = be_top(vm); + if (argc >= 1 && be_isstring(vm, 1)) { + const char * data_str = be_tostring(vm, 1); + size_t data_len = strlen(data_str); + + int32_t qr_version = qrcodegen_getMinFitVersion(qrcodegen_Ecc_MEDIUM, data_len); + if (qr_version <= 0) { be_return_nil(vm); } + int32_t qr_size = qrcodegen_version2size(qr_version); + if (qr_size <= 0) { be_return_nil(vm); } + + uint8_t * qr0 = (uint8_t *) be_os_malloc(qrcodegen_BUFFER_LEN_FOR_VERSION(qr_version)); + if (!qr0) { be_throw(vm, BE_MALLOC_FAIL); } + uint8_t * data_tmp = (uint8_t *) be_os_malloc(qrcodegen_BUFFER_LEN_FOR_VERSION(qr_version)); + if (!qr0) { be_os_free(qr0); be_throw(vm, BE_MALLOC_FAIL); } + + bool ok = qrcodegen_encodeText(data_str, data_tmp, qr0, qrcodegen_Ecc_MEDIUM, qr_version, qr_version, qrcodegen_Mask_AUTO, true); + + if(!ok) { + be_os_free(qr0); + be_os_free(data_tmp); + be_return_nil(vm); + } + + qr_size = qrcodegen_getSize(qr0); + size_t len = qr_size * qr_size; + + be_newobject(vm, "map"); + be_map_insert_int(vm, "size", qr_size); + be_map_insert_int(vm, "version", qr_version); + + be_pushstring(vm, "bitmap"); + be_newobject(vm, "list"); + + for (uint32_t i = 0; i < qr_size; i++) { + char line[qr_size]; + + for (uint32_t j = 0; j < qr_size; j++) { + line[j] = qrcodegen_getModule(qr0, i, j) ? '*' : ' '; + } + + be_pushnstring(vm, line, qr_size); + 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_os_free(qr0); + be_os_free(data_tmp); + + be_return(vm); + } + be_raise(vm, "type_error", NULL); +} + +#include "be_fixed_be_class_Matter_QRCode.h" + +/* @const_object_info_begin +class be_class_Matter_QRCode (scope: global, name: Matter_QRCode, strings: weak) { + encode_str, static_func(qr_encode_str) + + // UTF8 basic blocs for QR Codes + // empty, str(" ") + // lowhalf, str("\342\226\204") + // uphalf, str("\342\226\200") + // full, str("\342\226\210") +} +@const_object_info_end */ diff --git a/lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h b/lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h deleted file mode 100644 index ee97215d0..000000000 --- a/lib/libesp32/berry_matter/src/be_matter_qrcode_min_js.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - be_matter_qrcode_min_js.h - solidify in Flash `qrcode.min.js` for browser-side QRCode generation in Javascript - - 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 . -*/ - -// Lib JS from -// from https://github.com/davidshimjs/qrcodejs -// file qrcode.min.js - -// Converter: https://tomeko.net/online_tools/cpp_text_escape.php?lang=en - -/* -The MIT License (MIT) ---------------------- -Copyright (c) 2012 davidshimjs - -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. -*/ - -static const uint8_t QRCODE_MINJS[] = -"var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+\"/\"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error(\"Too long data\");return c}function s(a){var b=encodeURI(a).toString().replace(/\\%[0-9a-fA-F]{2}/g,\"a\");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+\",\"+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error(\"code length overflow. (\"+g.getLengthInBits()+\">\"+8*l+\")\");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error(\"bad maskPattern:\"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error(\"mode:\"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error(\"mode:\"+a)}else{if(!(41>b))throw new Error(\"type:\"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error(\"mode:\"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error(\"glog(\"+a+\")\");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS(\"http://www.w3.org/2000/svg\",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g(\"svg\",{viewBox:\"0 0 \"+String(d)+\" \"+String(d),width:\"100%\",height:\"100%\",fill:b.colorLight});h.setAttributeNS(\"http://www.w3.org/2000/xmlns/\",\"xmlns:xlink\",\"http://www.w3.org/1999/xlink\"),c.appendChild(h),h.appendChild(g(\"rect\",{fill:b.colorDark,width:\"1\",height:\"1\",id:\"template\"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g(\"use\",{x:String(i),y:String(j)});k.setAttributeNS(\"http://www.w3.org/1999/xlink\",\"href\",\"#template\"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p=\"svg\"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL(\"image/png\"),this._elImage.style.display=\"block\",this._elCanvas.style.display=\"none\"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement(\"img\"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src=\"data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if(\"nodeName\"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else\"undefined\"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement(\"canvas\"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext(\"2d\"),this._bIsPainted=!1,this._elImage=document.createElement(\"img\"),this._elImage.style.display=\"none\",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display=\"none\",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push(\"\");for(var i=0;d>i;i++)g.push('');g.push(\"\")}g.push(\"
\"),c.innerHTML=g.join(\"\");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+\"px \"+k+\"px\")},a.prototype.clear=function(){this._el.innerHTML=\"\"},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:\"#000000\",colorLight:\"#ffffff\",correctLevel:d.H},\"string\"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];\"string\"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){\"function\"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}();" -; diff --git a/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp b/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp index 5e8f56511..9e9f1ae4a 100644 --- a/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp +++ b/lib/libesp32/berry_matter/src/be_matter_verhoeff.cpp @@ -85,7 +85,7 @@ BE_FUNC_CTYPE_DECLARE(vh_validate, "b", "s") #include "be_fixed_be_class_Matter_Verhoeff.h" /* @const_object_info_begin -class be_class_Matter_Verhoeff (scope: global, name: Matter_Verhoeff) { +class be_class_Matter_Verhoeff (scope: global, name: Matter_Verhoeff, strings: weak) { checksum, static_ctype_func(vh_checksum) validate, static_ctype_func(vh_validate) } diff --git a/lib/libesp32/berry_matter/src/berry_tasmota.h b/lib/libesp32/berry_matter/src/berry_matter.h similarity index 100% rename from lib/libesp32/berry_matter/src/berry_tasmota.h rename to lib/libesp32/berry_matter/src/berry_matter.h diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be index d2a5a0fa9..c55432916 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be @@ -1,5 +1,5 @@ # -# Matter_Commissioning.be - suppport for Matter Commissioning process +# Matter_Commissioning.be - suppport for Matter Commissioning process PASE and CASE # # Copyright (C) 2023 Stephan Hadinger & Theo Arends # @@ -35,43 +35,34 @@ class Matter_Commisioning_Context var responder # reference to the caller, sending packets var device # root device object - var spake - var future_initiator_session_id - var future_local_session_id - # used by TT hash - var PBKDFParamRequest, PBKDFParamResponse - # PAKE - var y # 32 bytes random known only by verifier - var pA, pB, cA, cB - var Ke - # CASE - var ResponderEph_priv, ResponderEph_pub - var initiatorEph_pub - # Session data - var session_timestamp - var I2RKey, R2IKey, AttestationChallenge - # is commissioning window open - var window_open - + def init(responder) import crypto self.responder = responder self.device = responder.device - # generate y once - self.y = crypto.random(32) + end - self.window_open = true # auto-commissioning for now + ############################################################# + def add_session(local_session_id, initiator_session_id, i2r, r2i, ac) + import string + # create session object + tasmota.log(string.format("MTR: add_session local_session_id=%i initiator_session_id=%i", local_session_id, initiator_session_id), 3) + + var session = self.device.sessions.create_session(local_session_id, initiator_session_id) + session.set_keys(i2r, r2i, ac) end def process_incoming(msg) # - if !self.window_open + if !self.device.is_commissioning_open() && msg.opcode >= 0x20 && msg.opcode <= 0x24 tasmota.log("MTR: commissioning not open", 2) return false end tasmota.log("MTR: received message " + matter.inspect(msg), 3) - if msg.opcode == 0x20 + if msg.opcode == 0x10 + # don't need to do anything, the message is acked already before this call + elif msg.opcode == 0x20 return self.parse_PBKDFParamRequest(msg) elif msg.opcode == 0x22 return self.parse_Pake1(msg) @@ -81,28 +72,68 @@ class Matter_Commisioning_Context return self.parse_Sigma1(msg) elif msg.opcode == 0x32 return self.parse_Sigma3(msg) + elif msg.opcode == 0x40 + return self.parse_StatusReport(msg) + else + import string + tasmota.log(string.format("MTR: >????????? Unknown OpCode (secure channel) %02X", msg.opcode), 2) + return false end return false end + ################################################################################# + # send_status_report + # + # send a StatusReport message (unencrypted) + # + # Usage: + # # StatusReport(GeneralCode: SUCCESS, ProtocolId: SECURE_CHANNEL, ProtocolCode: SESSION_ESTABLISHMENT_SUCCESS) + # var raw = send_status_report(0x00, 0x0000, 0x0000) + # self.responder.send_response(raw, msg.remote_ip, msg.remote_port, nil) + def send_status_report(msg, general_code, protocol_id, protocol_code, reliable) + # now package the response message + var resp = msg.build_response(0x40 #-StatusReport-#, reliable) + + var status_raw = bytes() + status_raw.add(general_code, 2) + status_raw.add(protocol_id, 4) + status_raw.add(protocol_code, 4) + + var raw = resp.encode_frame(status_raw) + + self.responder.send_response_frame(resp) + end + def parse_PBKDFParamRequest(msg) import crypto + import string + var session = msg.session # sanity checks if msg.opcode != 0x20 || msg.local_session_id != 0 || msg.protocol_id != 0 - raise "protocol_error", "invalid PBKDFParamRequest message" + tasmota.log("MTR: invalid PBKDFParamRequest message", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false end var pbkdfparamreq = matter.PBKDFParamRequest().parse(msg.raw, msg.app_payload_idx) - msg.session.set_mode(matter.Session.__PASE) + msg.session.set_mode_PASE() - self.PBKDFParamRequest = msg.raw[msg.app_payload_idx..] + session.__Msg1 = msg.raw[msg.app_payload_idx..] # sanity check for PBKDFParamRequest - if pbkdfparamreq.passcodeId != 0 raise "protocol_error", "non-zero passcode id" end + if pbkdfparamreq.passcodeId != 0 + tasmota.log("MTR: non-zero passcode id", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false + end # record the initiator_session_id - self.future_initiator_session_id = pbkdfparamreq.initiator_session_id - self.future_local_session_id = self.device.sessions.gen_local_session_id() + session.__future_initiator_session_id = pbkdfparamreq.initiator_session_id + session.__future_local_session_id = self.device.sessions.gen_local_session_id() + tasmota.log(string.format("MTR: +Session (%6i) from '[%s]:%i'", session.__future_local_session_id, msg.remote_ip, msg.remote_port), 2) # prepare response var pbkdfparamresp = matter.PBKDFParamResponse() @@ -110,159 +141,167 @@ class Matter_Commisioning_Context pbkdfparamresp.initiatorRandom = pbkdfparamreq.initiatorRandom # generate 32 bytes random pbkdfparamresp.responderRandom = crypto.random(32) - pbkdfparamresp.responderSessionId = self.future_local_session_id - pbkdfparamresp.pbkdf_parameters_salt = self.device.salt - pbkdfparamresp.pbkdf_parameters_iterations = self.device.iterations - tasmota.log("MTR: pbkdfparamresp: " + str(matter.inspect(pbkdfparamresp)), 3) - var pbkdfparamresp_raw = pbkdfparamresp.encode() - tasmota.log("MTR: pbkdfparamresp_raw: " + pbkdfparamresp_raw.tohex(), 3) + pbkdfparamresp.responderSessionId = session.__future_local_session_id + pbkdfparamresp.pbkdf_parameters_salt = self.device.commissioning_salt + pbkdfparamresp.pbkdf_parameters_iterations = self.device.commissioning_iterations + tasmota.log("MTR: pbkdfparamresp: " + str(matter.inspect(pbkdfparamresp)), 4) + var pbkdfparamresp_raw = pbkdfparamresp.tlv2raw() + tasmota.log("MTR: pbkdfparamresp_raw: " + pbkdfparamresp_raw.tohex(), 4) - self.PBKDFParamResponse = pbkdfparamresp_raw + session.__Msg2 = pbkdfparamresp_raw var resp = msg.build_response(0x21 #-PBKDR Response-#, true) - var raw = resp.encode(pbkdfparamresp_raw) + var raw = resp.encode_frame(pbkdfparamresp_raw) - self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) + self.responder.send_response_frame(resp) + return true end def parse_Pake1(msg) import crypto + var session = msg.session # sanity checks if msg.opcode != 0x22 || msg.local_session_id != 0 || msg.protocol_id != 0 - raise "protocol_error", "invalid Pake1 message" + tasmota.log("MTR: invalid Pake1 message", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false end var pake1 = matter.Pake1().parse(msg.raw, msg.app_payload_idx) - self.pA = pake1.pA - tasmota.log("MTR: received pA=" + self.pA.tohex(), 3) - + var pA = pake1.pA + # tasmota.log("MTR: received pA=" + pA.tohex(), 4) - tasmota.log("MTR: spake: " + matter.inspect(self.spake), 3) # instanciate SPAKE - self.spake = crypto.SPAKE2P_Matter(self.device.w0, self.device.w1, self.device.L) + # for testing purpose, we don't send `w1` to make sure + var spake = crypto.SPAKE2P_Matter(self.device.commissioning_w0, nil, self.device.commissioning_L) + + # generate `y` nonce (not persisted) + var y = crypto.random(32) # 32 bytes random known only by verifier + # compute pB - self.spake.compute_pB(self.y) - self.pB = self.spake.pB - tasmota.log("MTR: y=" + self.y.tohex(), 3) - tasmota.log("MTR: pb=" + self.pB.tohex(), 3) + spake.compute_pB(y) + # tasmota.log("MTR: y=" + y.tohex(), 4) + # tasmota.log("MTR: pb=" + spake.pB.tohex(), 4) # compute ZV - self.spake.compute_ZV_verifier(self.pA) - tasmota.log("MTR: Z=" + self.spake.Z.tohex(), 3) - tasmota.log("MTR: V=" + self.spake.V.tohex(), 3) + spake.compute_ZV_verifier(pA) + # tasmota.log("MTR: Z=" + spake.Z.tohex(), 4) + # tasmota.log("MTR: V=" + spake.V.tohex(), 4) var context = crypto.SHA256() context.update(bytes().fromstring(self.Matter_Context_Prefix)) - context.update(self.PBKDFParamRequest) - context.update(self.PBKDFParamResponse) + context.update(session.__Msg1) + context.update(session.__Msg2) var context_hash = context.out() - tasmota.log("MTR: Context=" + context_hash.tohex(), 3) + # tasmota.log("MTR: Context=" + context_hash.tohex(), 4) # add pA - self.spake.pA = self.pA + spake.pA = pA - self.spake.set_context(context_hash) - self.spake.compute_TT_hash(true) # `true` to indicate it's Matter variant to SPAKE2+ + spake.set_context(context_hash) + spake.compute_TT_hash(true) # `true` to indicate it's Matter variant to SPAKE2+ - tasmota.log("MTR: ------------------------------", 3) - tasmota.log("MTR: Context = " + self.spake.Context.tohex(), 3) - tasmota.log("MTR: A = " + self.spake.A.tohex(), 3) - tasmota.log("MTR: B = " + self.spake.B.tohex(), 3) - tasmota.log("MTR: M = " + self.spake.M.tohex(), 3) - tasmota.log("MTR: N = " + self.spake.N.tohex(), 3) - tasmota.log("MTR: pA = " + self.spake.pA.tohex(), 3) - tasmota.log("MTR: pB = " + self.spake.pB.tohex(), 3) - tasmota.log("MTR: Z = " + self.spake.Z.tohex(), 3) - tasmota.log("MTR: V = " + self.spake.V.tohex(), 3) - tasmota.log("MTR: w0 = " + self.spake.w0.tohex(), 3) - tasmota.log("MTR: ------------------------------", 3) + # tasmota.log("MTR: ------------------------------", 4) + # tasmota.log("MTR: Context = " + spake.Context.tohex(), 4) + # tasmota.log("MTR: M = " + spake.M.tohex(), 4) + # tasmota.log("MTR: N = " + spake.N.tohex(), 4) + # tasmota.log("MTR: pA = " + spake.pA.tohex(), 4) + # tasmota.log("MTR: pB = " + spake.pB.tohex(), 4) + # tasmota.log("MTR: Z = " + spake.Z.tohex(), 4) + # tasmota.log("MTR: V = " + spake.V.tohex(), 4) + # tasmota.log("MTR: w0 = " + spake.w0.tohex(), 4) + # tasmota.log("MTR: ------------------------------", 4) - tasmota.log("MTR: Kmain =" + self.spake.Kmain.tohex(), 3) + # tasmota.log("MTR: Kmain =" + spake.Kmain.tohex(), 4) - tasmota.log("MTR: KcA =" + self.spake.KcA.tohex(), 3) - tasmota.log("MTR: KcB =" + self.spake.KcB.tohex(), 3) - tasmota.log("MTR: K_shared=" + self.spake.K_shared.tohex(), 3) - tasmota.log("MTR: Ke =" + self.spake.Ke.tohex(), 3) - self.cB = self.spake.cB - self.Ke = self.spake.Ke - tasmota.log("MTR: cB=" + self.cB.tohex(), 3) + # tasmota.log("MTR: KcA =" + spake.KcA.tohex(), 4) + # tasmota.log("MTR: KcB =" + spake.KcB.tohex(), 4) + # tasmota.log("MTR: K_shared=" + spake.K_shared.tohex(), 4) + # tasmota.log("MTR: Ke =" + spake.Ke.tohex(), 4) + # tasmota.log("MTR: cB=" + spake.cB.tohex(), 4) var pake2 = matter.Pake2() - pake2.pB = self.pB - pake2.cB = self.cB - tasmota.log("MTR: pake2: " + matter.inspect(pake2), 3) - var pake2_raw = pake2.encode() - tasmota.log("MTR: pake2_raw: " + pake2_raw.tohex(), 3) + pake2.pB = spake.pB + pake2.cB = spake.cB + # tasmota.log("MTR: pake2: " + matter.inspect(pake2), 4) + var pake2_raw = pake2.tlv2raw() + # tasmota.log("MTR: pake2_raw: " + pake2_raw.tohex(), 4) + session.__spake_cA = spake.cA + session.__spake_Ke = spake.Ke # now package the response message var resp = msg.build_response(0x23 #-pake-2-#, true) # no reliable flag - var raw = resp.encode(pake2_raw) + var raw = resp.encode_frame(pake2_raw) - self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) + self.responder.send_response_frame(resp) + return true end def parse_Pake3(msg) import crypto + var session = msg.session # sanity checks if msg.opcode != 0x24 || msg.local_session_id != 0 || msg.protocol_id != 0 - raise "protocol_error", "invalid Pake3 message" + tasmota.log("MTR: invalid Pake3 message", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false end var pake3 = matter.Pake3().parse(msg.raw, msg.app_payload_idx) - self.cA = pake3.cA - tasmota.log("MTR: received cA=" + self.cA.tohex(), 3) + var cA = pake3.cA + # tasmota.log("MTR: received cA=" + cA.tohex(), 4) # check the value against computed - if self.cA != self.spake.cA raise "protocol_error", "invalid cA received" end + if cA != session.__spake_cA + tasmota.log("MTR: invalid cA received", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false + end # send PakeFinished and compute session key - self.session_timestamp = tasmota.rtc()['utc'] - var session_keys = crypto.HKDF_SHA256().derive(self.Ke, bytes(), bytes().fromstring(self.SEKeys_Info), 48) - self.I2RKey = session_keys[0..15] - self.R2IKey = session_keys[16..31] - self.AttestationChallenge = session_keys[32..47] + var created = tasmota.rtc()['utc'] + var session_keys = crypto.HKDF_SHA256().derive(session.__spake_Ke, bytes(), bytes().fromstring(self.SEKeys_Info), 48) + var I2RKey = session_keys[0..15] + var R2IKey = session_keys[16..31] + var AttestationChallenge = session_keys[32..47] - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: session_keys=" + session_keys.tohex(), 3) - tasmota.log("MTR: I2RKey =" + self.I2RKey.tohex(), 3) - tasmota.log("MTR: R2IKey =" + self.R2IKey.tohex(), 3) - tasmota.log("MTR: AC =" + self.AttestationChallenge.tohex(), 3) - tasmota.log("MTR: ******************************", 3) + # tasmota.log("MTR: ******************************", 4) + # tasmota.log("MTR: session_keys=" + session_keys.tohex(), 4) + # tasmota.log("MTR: I2RKey =" + I2RKey.tohex(), 4) + # tasmota.log("MTR: R2IKey =" + R2IKey.tohex(), 4) + # tasmota.log("MTR: AC =" + AttestationChallenge.tohex(), 4) + # tasmota.log("MTR: ******************************", 4) - # now package the response message - var resp = msg.build_response(0x40 #-StatusReport-#, false) # no reliable flag + # StatusReport(GeneralCode: SUCCESS, ProtocolId: SECURE_CHANNEL, ProtocolCode: SESSION_ESTABLISHMENT_SUCCESS) + var raw = self.send_status_report(msg, 0x00, 0x0000, 0x0000, false) - var status_raw = bytes() - status_raw.add(0x00, 2) # GeneralCode = SUCCESS - status_raw.add(0x0000, 4) # ProtocolID = 0 (PROTOCOL_ID_SECURE_CHANNEL) - status_raw.add(0x0000, 4) # ProtocolCode = 0 (SESSION_ESTABLISHMENT_SUCCESS) - - var raw = resp.encode(status_raw) - - self.responder.send_response(raw, msg.remote_ip, msg.remote_port, nil) - self.responder.add_session(self.future_local_session_id, self.future_initiator_session_id, self.I2RKey, self.R2IKey, self.AttestationChallenge, self.session_timestamp) + self.add_session(session.__future_local_session_id, session.__future_initiator_session_id, I2RKey, R2IKey, AttestationChallenge, created) + return true end - def find_session_by_destination_id(destinationId, initiatorRandom) + def find_fabric_by_destination_id(destinationId, initiatorRandom) import crypto # Validate Sigma1 Destination ID, p.162 - # traverse all existing sessions + # traverse all existing fabrics tasmota.log("MTR: SEARCHING: destinationId=" + destinationId.tohex(), 3) - for session:self.device.sessions.sessions - if session.noc == nil || session.fabric == nil || session.deviceid == nil continue 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” - var destinationMessage = initiatorRandom + session.get_ca_pub() + session.get_fabric() + session.get_deviceid() - var key = session.get_ipk_group_key() + 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(), 3) - tasmota.log("MTR: SIGMA1: key_ipk=" + key.tohex(), 3) + tasmota.log("MTR: SIGMA1: key_ipk=" + key.tohex(), 4) var h = crypto.HMAC_SHA256(key) h.update(destinationMessage) var candidateDestinationId = h.out() tasmota.log("MTR: SIGMA1: candidateDestinationId=" + candidateDestinationId.tohex(), 3) if candidateDestinationId == destinationId - return session + return fabric end end return nil @@ -270,130 +309,177 @@ class Matter_Commisioning_Context def parse_Sigma1(msg) import crypto + import string + var session = msg.session # sanity checks if msg.opcode != 0x30 || msg.local_session_id != 0 || msg.protocol_id != 0 - raise "protocol_error", "invalid Pake1 message" + # tasmota.log("MTR: invalid Sigma1 message", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false end var sigma1 = matter.Sigma1().parse(msg.raw, msg.app_payload_idx) + tasmota.log(string.format("MTR: sigma1=%s", matter.inspect(sigma1)), 4) - self.initiatorEph_pub = sigma1.initiatorEphPubKey + session.__initiator_pub = sigma1.initiatorEphPubKey # find session var is_resumption = (sigma1.resumptionID != nil && sigma1.initiatorResumeMIC != nil) + tasmota.log(string.format("MTR: is_resumption=%i", is_resumption ? 1 : 0), 4) + # TODO disable resumption until fixed + is_resumption = false # Check that it's a resumption - var session + var session_resumption if is_resumption - session = self.device.sessions.find_session_by_resumption_id(sigma1.resumptionID) - else - session = self.find_session_by_destination_id(sigma1.destinationId, sigma1.initiatorRandom) + session_resumption = self.device.sessions.find_session_by_resumption_id(sigma1.resumptionID) + tasmota.log(string.format("MTR: session_resumption found session=%s session_resumption=%s", matter.inspect(session), matter.inspect(session_resumption)), 4) + if session_resumption == nil || session_resumption._fabric == nil + is_resumption = false + end end - if session == nil raise "valuer_error", "StatusReport(GeneralCode: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: NO_SHARED_TRUST_ROOTS)" end - session.source_node_id = msg.source_node_id - session.set_mode(matter.Session.__CASE) - - if msg.session - self.device.sessions.remove_session(msg.session) # drop the temporary session that was created - end - msg.session = session - session._future_initiator_session_id = sigma1.initiator_session_id # update initiator_session_id - session._future_local_session_id = self.device.sessions.gen_local_session_id() - self.future_local_session_id = session._future_local_session_id - - + # Check that it's a resumption - if is_resumption && session.shared_secret != nil + if is_resumption # Resumption p.169 var s1rk_salt = sigma1.initiatorRandom + sigma1.resumptionID var s1rk_info = bytes().fromstring("Sigma1_Resume") - var s1rk = crypto.HKDF_SHA256().derive(session.shared_secret, s1rk_salt, s1rk_info, 16) + var s1rk = crypto.HKDF_SHA256().derive(session_resumption.shared_secret, s1rk_salt, s1rk_info, 16) - var Resume1MIC_Nonce = bytes().fromstring("NCASE_SigmaR1") + var Resume1MIC_Nonce = bytes().fromstring("NCASE_SigmaS1") var encrypted = sigma1.initiatorResumeMIC[0..-17] var tag = sigma1.initiatorResumeMIC[-16..] var ec = crypto.AES_CCM(s1rk, Resume1MIC_Nonce, bytes(), size(encrypted), 16) var Resume1MICPayload = ec.decrypt(encrypted) var decrypted_tag = ec.tag() - tasmota.log("****************************************", 3) - tasmota.log("MTR: * s1rk = " + s1rk.tohex(), 3) - tasmota.log("MTR: * tag = " + tag.tohex(), 3) - tasmota.log("MTR: * Resume1MICPayload = " + Resume1MICPayload.tohex(), 3) - tasmota.log("MTR: * decrypted_tag = " + decrypted_tag.tohex(), 3) - tasmota.log("****************************************", 3) + tasmota.log("****************************************", 4) + tasmota.log("MTR: * s1rk = " + s1rk.tohex(), 4) + tasmota.log("MTR: * tag = " + tag.tohex(), 4) + tasmota.log("MTR: * Resume1MICPayload = " + Resume1MICPayload.tohex(), 4) + tasmota.log("MTR: * decrypted_tag = " + decrypted_tag.tohex(), 4) + tasmota.log("****************************************", 4) if tag == decrypted_tag + session._fabric = session_resumption._fabric + session._source_node_id = msg.source_node_id + session.set_mode_CASE() + session.__future_initiator_session_id = sigma1.initiator_session_id # update initiator_session_id + session.__future_local_session_id = self.device.sessions.gen_local_session_id() + tasmota.log(string.format("MTR: +Session (%6i) from '[%s]:%i'", session.__future_local_session_id, msg.remote_ip, msg.remote_port), 2) + # Generate and Send Sigma2_Resume + session.shared_secret = session_resumption.shared_secret session.resumption_id = crypto.random(16) # generate a new resumption id # compute S2RK - var s2rk_info = bytes().fromstring("Sigma2_Resume") + session.resumption_id - var s2rk_salt = sigma1.initiatorRandom + sigma1.resumptionID + var s2rk_info = bytes().fromstring("Sigma2_Resume") + var s2rk_salt = sigma1.initiatorRandom + session.resumption_id var s2rk = crypto.HKDF_SHA256().derive(session.shared_secret, s2rk_salt, s2rk_info, 16) + # compute Resume2MIC - var aes = crypto.AES_CCM(s2rk, bytes().fromstring("NCASE_SigmaR2"), bytes(), 0, 16) + var aes = crypto.AES_CCM(s2rk, bytes().fromstring("NCASE_SigmaS2"), bytes(), 0, 16) var Resume2MIC = aes.tag() var sigma2resume = matter.Sigma2Resume() sigma2resume.resumptionID = session.resumption_id - sigma2resume.responderSessionID = session._future_local_session_id + sigma2resume.responderSessionID = session.__future_local_session_id sigma2resume.sigma2ResumeMIC = Resume2MIC + tasmota.log("****************************************", 4) + tasmota.log("MTR: * s2rk = " + s2rk.tohex(), 4) + tasmota.log("MTR: * s2rk_salt = " + s2rk_salt.tohex(), 4) + tasmota.log("MTR: * new_resumption_id = " + session.resumption_id.tohex(), 4) + tasmota.log("MTR: * responderSessionID= " + str(session.__future_local_session_id), 4) + tasmota.log("MTR: * sigma2ResumeMIC = " + Resume2MIC.tohex(), 4) + tasmota.log("****************************************", 4) # # compute session key, p.178 var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#, - sigma1.initiatorRandom + sigma1.resumptionID #- salt -#, + sigma1.initiatorRandom + session.resumption_id #- salt -#, bytes().fromstring("SessionResumptionKeys") #- info -#, 48) var i2r = session_keys[0..15] var r2i = session_keys[16..31] var ac = session_keys[32..47] - var session_timestamp = tasmota.rtc()['utc'] + var created = tasmota.rtc()['utc'] - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: I2RKey =" + i2r.tohex(), 3) - tasmota.log("MTR: R2IKey =" + r2i.tohex(), 3) - tasmota.log("MTR: AC =" + ac.tohex(), 3) - tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: ******************************", 4) + tasmota.log("MTR: I2RKey =" + i2r.tohex(), 4) + tasmota.log("MTR: R2IKey =" + r2i.tohex(), 4) + tasmota.log("MTR: AC =" + ac.tohex(), 4) + tasmota.log("MTR: ******************************", 4) - var sigma2resume_raw = sigma2resume.encode() - session._Msg1 = nil - tasmota.log("MTR: sigma2resume_raw: " + sigma2resume_raw.tohex(), 3) + var sigma2resume_raw = sigma2resume.tlv2raw() + session.__Msg1 = nil + tasmota.log("MTR: sigma2resume: " + matter.inspect(sigma2resume), 4) + tasmota.log("MTR: sigma2resume_raw: " + sigma2resume_raw.tohex(), 4) # now package the response message var resp = msg.build_response(0x33 #-sigma-2-resume-#, true) - var raw = resp.encode(sigma2resume_raw) + var raw = resp.encode_frame(sigma2resume_raw) - self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) + self.responder.send_response_frame(resp) session.close() - session.set_keys(i2r, r2i, ac, session_timestamp) + session.set_keys(i2r, r2i, ac, created) + + # CASE Session completed, persist it + session._breadcrumb = 0 # clear breadcrumb + session.counter_snd_next() # force a first counter. It's important it's used before set_persist(true) to not have a double save session.set_persist(true) # keep session on flash session.set_no_expiration() # never expire + session.persist_to_fabric() session.save() return true else - sigma1.resumptionID = nil + is_resumption = false # fall through normal sigma1 (non-resumption) end end - if sigma1.resumptionID == nil || sigma1.initiatorResumeMIC == nil + if !is_resumption + # new CASE session, assign to existing fabric + var fabric = self.find_fabric_by_destination_id(sigma1.destinationId, sigma1.initiatorRandom) + session._fabric = fabric + + if session == nil || session._fabric == nil + tasmota.log("MTR: StatusReport(GeneralCode: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: NO_SHARED_TRUST_ROOTS)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0001, false) + return false + end + session._source_node_id = msg.source_node_id + session.set_mode_CASE() + + session.__future_initiator_session_id = sigma1.initiator_session_id # update initiator_session_id + session.__future_local_session_id = self.device.sessions.gen_local_session_id() + tasmota.log(string.format("MTR: +Session (%6i) from '[%s]:%i'", session.__future_local_session_id, msg.remote_ip, msg.remote_port), 2) + + tasmota.log("MTR: fabric="+matter.inspect(session._fabric), 4) + tasmota.log("MTR: no_private_key="+session._fabric.no_private_key.tohex(), 4) + tasmota.log("MTR: noc ="+session._fabric.noc.tohex(), 4) + if session._fabric.get_icac() + tasmota.log("MTR: icac ="+session._fabric.get_icac().tohex(), 4) + end + tasmota.log("MTR: root_ca_cert ="+session._fabric.root_ca_certificate.tohex(), 4) + # Compute Sigma2, p.162 session.resumption_id = crypto.random(16) - self.ResponderEph_priv = crypto.random(32) - self.ResponderEph_pub = crypto.EC_P256().public_key(self.ResponderEph_priv) + session.__responder_priv = crypto.random(32) + session.__responder_pub = crypto.EC_P256().public_key(session.__responder_priv) + tasmota.log("MTR: ResponderEph_priv ="+session.__responder_priv.tohex(), 4) + tasmota.log("MTR: ResponderEph_pub ="+session.__responder_pub.tohex(), 4) var responderRandom = crypto.random(32) - session.shared_secret = crypto.EC_P256().shared_key(self.ResponderEph_priv, sigma1.initiatorEphPubKey) + session.shared_secret = crypto.EC_P256().shared_key(session.__responder_priv, sigma1.initiatorEphPubKey) var sigma2_tbsdata = matter.TLV.Matter_TLV_struct() sigma2_tbsdata.add_TLV(1, matter.TLV.B2, session.get_noc()) sigma2_tbsdata.add_TLV(2, matter.TLV.B2, session.get_icac()) - sigma2_tbsdata.add_TLV(3, matter.TLV.B2, self.ResponderEph_pub) + sigma2_tbsdata.add_TLV(3, matter.TLV.B2, session.__responder_pub) sigma2_tbsdata.add_TLV(4, matter.TLV.B2, sigma1.initiatorEphPubKey) - var TBSData2Signature = crypto.EC_P256().ecdsa_sign_sha256(session.get_pk(), sigma2_tbsdata.encode()) + var TBSData2Signature = crypto.EC_P256().ecdsa_sign_sha256(session.get_pk(), sigma2_tbsdata.tlv2raw()) var sigma2_tbedata = matter.TLV.Matter_TLV_struct() sigma2_tbedata.add_TLV(1, matter.TLV.B2, session.get_noc()) @@ -402,43 +488,46 @@ class Matter_Commisioning_Context sigma2_tbedata.add_TLV(4, matter.TLV.B2, session.resumption_id) # compute TranscriptHash = Crypto_Hash(message = Msg1) - tasmota.log("****************************************", 3) - session._Msg1 = sigma1.Msg1 - tasmota.log("MTR: * MSG1 = " + session._Msg1.tohex(), 3) - var TranscriptHash = crypto.SHA256().update(session._Msg1).out() + tasmota.log("****************************************", 4) + session.__Msg1 = sigma1.Msg1 + tasmota.log("MTR: * resumptionid = " + session.resumption_id.tohex(), 4) + tasmota.log("MTR: * MSG1 = " + session.__Msg1.tohex(), 4) + var TranscriptHash = crypto.SHA256().update(session.__Msg1).out() + tasmota.log("MTR: TranscriptHash =" + TranscriptHash.tohex(), 4) # Compute S2K, p.175 var s2k_info = bytes().fromstring(self.S2K_Info) - var s2k_salt = session.get_ipk_group_key() + responderRandom + self.ResponderEph_pub + TranscriptHash + var s2k_salt = session.get_ipk_group_key() + responderRandom + session.__responder_pub + TranscriptHash var s2k = crypto.HKDF_SHA256().derive(session.shared_secret, s2k_salt, s2k_info, 16) - tasmota.log("MTR: * SharedSecret = " + session.shared_secret.tohex(), 3) - tasmota.log("MTR: * s2k_salt = " + s2k_salt.tohex(), 3) - tasmota.log("MTR: * s2k = " + s2k.tohex(), 3) + tasmota.log("MTR: * SharedSecret = " + session.shared_secret.tohex(), 4) + tasmota.log("MTR: * s2k_salt = " + s2k_salt.tohex(), 4) + tasmota.log("MTR: * s2k = " + s2k.tohex(), 4) - var sigma2_tbedata_raw = sigma2_tbedata.encode() + var sigma2_tbedata_raw = sigma2_tbedata.tlv2raw() + tasmota.log("MTR: * TBEData2Raw = " + sigma2_tbedata_raw.tohex(), 4) # // `AES_CCM.init(secret_key:bytes(16 or 32), iv:bytes(7..13), aad:bytes(), data_len:int, tag_len:int) -> instance` var aes = crypto.AES_CCM(s2k, bytes().fromstring(self.TBEData2_Nonce), bytes(), size(sigma2_tbedata_raw), 16) var TBEData2Encrypted = aes.encrypt(sigma2_tbedata_raw) + aes.tag() - tasmota.log("MTR: * TBEData2Enc = " + TBEData2Encrypted.tohex(), 3) - tasmota.log("****************************************", 3) + tasmota.log("MTR: * TBEData2Enc = " + TBEData2Encrypted.tohex(), 4) + tasmota.log("****************************************", 4) var sigma2 = matter.Sigma2() sigma2.responderRandom = responderRandom - sigma2.responderSessionId = self.future_local_session_id - sigma2.responderEphPubKey = self.ResponderEph_pub + sigma2.responderSessionId = session.__future_local_session_id + sigma2.responderEphPubKey = session.__responder_pub sigma2.encrypted2 = TBEData2Encrypted - tasmota.log("MTR: sigma2: " + matter.inspect(sigma2), 3) - var sigma2_raw = sigma2.encode() - session._Msg2 = sigma2_raw - tasmota.log("MTR: sigma2_raw: " + sigma2_raw.tohex(), 3) + tasmota.log("MTR: sigma2: " + matter.inspect(sigma2), 4) + var sigma2_raw = sigma2.tlv2raw() + session.__Msg2 = sigma2_raw + tasmota.log("MTR: sigma2_raw: " + sigma2_raw.tohex(), 4) # now package the response message var resp = msg.build_response(0x31 #-sigma-2-#, true) # no reliable flag - var raw = resp.encode(sigma2_raw) + var raw = resp.encode_frame(sigma2_raw) - self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) + self.responder.send_response_frame(resp) return true end @@ -449,28 +538,29 @@ class Matter_Commisioning_Context import crypto # sanity checks if msg.opcode != 0x32 || msg.local_session_id != 0 || msg.protocol_id != 0 - raise "protocol_error", "invalid Pake1 message" + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false end var session = msg.session var sigma3 = matter.Sigma3().parse(msg.raw, msg.app_payload_idx) - tasmota.log("****************************************", 3) + tasmota.log("****************************************", 4) # compute TranscriptHash = Crypto_Hash(message = Msg1 || Msg2) - var TranscriptHash = crypto.SHA256().update(session._Msg1).update(session._Msg2).out() - tasmota.log("MTR: * session = " + str(session), 3) - tasmota.log("MTR: session.ipk_epoch_key " + str(session.ipk_epoch_key), 3) - tasmota.log("MTR: session.fabric_compressed " + str(session.fabric_compressed), 3) - tasmota.log("MTR: * ipk_group_key = " + session.get_ipk_group_key().tohex(), 3) - tasmota.log("MTR: * TranscriptHash= " + TranscriptHash.tohex(), 3) + var TranscriptHash = crypto.SHA256().update(session.__Msg1).update(session.__Msg2).out() + tasmota.log("MTR: * session = " + str(session), 4) + tasmota.log("MTR: .ipk_epoch_key=" + str(session.get_ipk_epoch_key()), 4) + tasmota.log("MTR: .fabric_compr = " + str(session.get_fabric_compressed()), 4) + tasmota.log("MTR: * ipk_group_key = " + session.get_ipk_group_key().tohex(), 4) + tasmota.log("MTR: * TranscriptHash= " + TranscriptHash.tohex(), 4) var s3k_info = bytes().fromstring(self.S3K_Info) var s3k = crypto.HKDF_SHA256().derive(session.shared_secret, session.get_ipk_group_key() + TranscriptHash, s3k_info, 16) - tasmota.log("****************************************", 3) - # self.ipk_epoch_key == nil || self.fabric_compressed") - tasmota.log("MTR: * s3k_salt = " + (session.get_ipk_group_key() + TranscriptHash).tohex(), 3) - tasmota.log("MTR: * s3k = " + s3k.tohex(), 3) - tasmota.log("****************************************", 3) + tasmota.log("****************************************", 4) + tasmota.log("MTR: * s3k_salt = " + (session.get_ipk_group_key() + TranscriptHash).tohex(), 4) + tasmota.log("MTR: * s3k = " + s3k.tohex(), 4) + tasmota.log("****************************************", 4) # decrypt var encrypted = sigma3.TBEData3Encrypted[0..-17] @@ -478,17 +568,26 @@ class Matter_Commisioning_Context var ec = crypto.AES_CCM(s3k, bytes().fromstring(self.TBEData3_Nonce), bytes(), size(encrypted), 16) var TBEData3 = ec.decrypt(encrypted) var TBETag3 = ec.tag() - tasmota.log("MTR: * TBEData3 = " + TBEData3.tohex(), 3) - tasmota.log("MTR: * TBETag3 = " + TBETag3.tohex(), 3) - tasmota.log("MTR: * tag_sent = " + tag.tohex(), 3) - tasmota.log("****************************************", 3) + tasmota.log("MTR: * TBEData3 = " + TBEData3.tohex(), 4) + tasmota.log("MTR: * TBETag3 = " + TBETag3.tohex(), 4) + tasmota.log("MTR: * tag_sent = " + tag.tohex(), 4) + tasmota.log("****************************************", 4) - if TBETag3 != tag raise "value_error", "tag do not match" end + if TBETag3 != tag + tasmota.log("MTR: Tag don't match", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false + end var TBEData3TLV = matter.TLV.parse(TBEData3) + tasmota.log("MTR: * TBEData3TLV = " + str(TBEData3TLV), 4) var initiatorNOC = TBEData3TLV.findsubval(1) var initiatorICAC = TBEData3TLV.findsubval(2) var ec_signature = TBEData3TLV.findsubval(3) + tasmota.log("MTR: * initiatorNOC = " + str(initiatorNOC), 4) + tasmota.log("MTR: * initiatorICAC = " + str(initiatorICAC), 4) + tasmota.log("MTR: * ec_signature = " + str(ec_signature), 4) # Success = Crypto_VerifyChain(certificates = [TBEData3.initiatorNOC, TBEData3.initiatorICAC, TrustedRCAC]), when TBEData3.initiatorICAC is present # TODO var initiatorNOCTLV = matter.TLV.parse(initiatorNOC) @@ -503,30 +602,41 @@ class Matter_Commisioning_Context var sigma3_tbs = matter.TLV.Matter_TLV_struct() sigma3_tbs.add_TLV(1, matter.TLV.B1, initiatorNOC) sigma3_tbs.add_TLV(2, matter.TLV.B1, initiatorICAC) - sigma3_tbs.add_TLV(3, matter.TLV.B1, self.initiatorEph_pub) - sigma3_tbs.add_TLV(4, matter.TLV.B1, self.ResponderEph_pub) - var sigma3_tbs_raw = sigma3_tbs.encode() + sigma3_tbs.add_TLV(3, matter.TLV.B1, session.__initiator_pub) + sigma3_tbs.add_TLV(4, matter.TLV.B1, session.__responder_pub) + tasmota.log("MTR: * sigma3_tbs = " + str(sigma3_tbs), 4) + var sigma3_tbs_raw = sigma3_tbs.tlv2raw() + tasmota.log("MTR: * sigma3_tbs_raw= " + sigma3_tbs_raw.tohex(), 4) - tasmota.log("MTR: * initiatorNOCPubKey = " + initiatorNOCPubKey.tohex(), 3) - tasmota.log("MTR: * ec_signature = " + ec_signature.tohex(), 3) - tasmota.log("****************************************", 3) + tasmota.log("MTR: * initiatorNOCPubKey= " + initiatorNOCPubKey.tohex(), 4) + tasmota.log("MTR: * ec_signature = " + ec_signature.tohex(), 4) + tasmota.log("****************************************", 4) # `crypto.EC_P256().ecdsa_verify_sha256(public_key:bytes(65), message:bytes(), hash:bytes()) -> bool` var sigma3_tbs_valid = crypto.EC_P256().ecdsa_verify_sha256(initiatorNOCPubKey, sigma3_tbs_raw, ec_signature) - if !sigma3_tbs_valid raise "value_error", "sigma3_tbs does not have a valid signature" end + if !sigma3_tbs_valid + tasmota.log("MTR: sigma3_tbs does not have a valid signature", 2) + tasmota.log("MTR: StatusReport(General Code: FAILURE, ProtocolId: SECURE_CHANNEL, ProtocolCode: INVALID_PARAMETER)", 2) + var raw = self.send_status_report(msg, 0x01, 0x0000, 0x0002, false) + return false + end # All good, compute new keys tasmota.log("MTR: Sigma3 verified, computing new keys", 3) - TranscriptHash = crypto.SHA256().update(session._Msg1).update(session._Msg2).update(sigma3.Msg3).out() - # we can now free _Msg1 and _Msg2 - session._Msg1 = nil - session._Msg2 = nil + TranscriptHash = crypto.SHA256().update(session.__Msg1).update(session.__Msg2).update(sigma3.Msg3).out() + tasmota.log("MTR: * __Msg1 = " + session.__Msg1.tohex(), 4) + tasmota.log("MTR: * __Msg2 = " + session.__Msg2.tohex(), 4) + tasmota.log("MTR: * __Msg3 = " + sigma3.Msg3.tohex(), 4) + tasmota.log("MTR: * TranscriptHash = " + TranscriptHash.tohex(), 4) + # we can now free __Msg1 and __Msg2 + session.__Msg1 = nil + session.__Msg2 = nil - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: shared_secret =" + session.shared_secret.tohex(), 3) - tasmota.log("MTR: ipk + hash =" + (session.get_ipk_group_key() + TranscriptHash).tohex(), 3) + tasmota.log("MTR: ******************************", 4) + tasmota.log("MTR: shared_secret =" + session.shared_secret.tohex(), 4) + tasmota.log("MTR: ipk + hash =" + (session.get_ipk_group_key() + TranscriptHash).tohex(), 4) # compute session key var session_keys = crypto.HKDF_SHA256().derive(session.shared_secret #- input key -#, session.get_ipk_group_key() + TranscriptHash #- salt -#, @@ -535,35 +645,39 @@ class Matter_Commisioning_Context var i2r = session_keys[0..15] var r2i = session_keys[16..31] var ac = session_keys[32..47] - var session_timestamp = tasmota.rtc()['utc'] + var created = tasmota.rtc()['utc'] - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: I2RKey =" + i2r.tohex(), 3) - tasmota.log("MTR: R2IKey =" + r2i.tohex(), 3) - tasmota.log("MTR: AC =" + ac.tohex(), 3) - tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: ******************************", 4) + tasmota.log("MTR: I2RKey =" + i2r.tohex(), 4) + tasmota.log("MTR: R2IKey =" + r2i.tohex(), 4) + tasmota.log("MTR: AC =" + ac.tohex(), 4) + tasmota.log("MTR: ******************************", 4) - # Send success status report - var resp = msg.build_response(0x40 #-StatusReport-#, true) # reliable flag - - var status_raw = bytes() - status_raw.add(0x00, 2) # GeneralCode = SUCCESS - status_raw.add(0x0000, 4) # ProtocolID = 0 (PROTOCOL_ID_SECURE_CHANNEL) - status_raw.add(0x0000, 4) # ProtocolCode = 0 (SESSION_ESTABLISHMENT_SUCCESS) - - var raw = resp.encode(status_raw) - - self.responder.send_response(raw, msg.remote_ip, msg.remote_port, resp.message_counter) + # StatusReport(GeneralCode: SUCCESS, ProtocolId: SECURE_CHANNEL, ProtocolCode: SESSION_ESTABLISHMENT_SUCCESS) + var raw = self.send_status_report(msg, 0x00, 0x0000, 0x0000, true) session.close() - session.set_keys(i2r, r2i, ac, session_timestamp) + session.set_keys(i2r, r2i, ac, created) + + # CASE Session completed, persist it + session._breadcrumb = 0 # clear breadcrumb + session.counter_snd_next() # force a first counter. It's important it's used before set_persist(true) to not have a double save session.set_persist(true) # keep session on flash session.set_no_expiration() # never expire + session.persist_to_fabric() session.save() return true end + ############################################################# + # placeholder, nothing to run for now + def parse_StatusReport(msg) + var session = msg.session + tasmota.log("MTR: >Status "+msg.raw[msg.app_payload_idx..].tohex(), 2) + return false # we don't explicitly ack the message + end + ############################################################# # placeholder, nothing to run for now def every_second() diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be index 9aca4927c..8b517912b 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning_Data.be @@ -70,7 +70,7 @@ class Matter_PBKDFParamResponse var SLEEPY_IDLE_INTERVAL var SLEEPY_ACTIVE_INTERVAL - def encode(b) + def tlv2raw(b) var s = matter.TLV.Matter_TLV_struct() # initiatorRandom s.add_TLV(1, matter.TLV.B1, self.initiatorRandom) @@ -84,7 +84,7 @@ class Matter_PBKDFParamResponse s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL) s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL) end - return s.encode() + return s.tlv2raw(b) end end matter.PBKDFParamResponse = Matter_PBKDFParamResponse @@ -98,7 +98,7 @@ class Matter_Pake1 def parse(b, idx) if idx == nil idx = 0 end var val = matter.TLV.parse(b, idx) - tasmota.log("MTR: parsed TLV: " + str(val), 3) + tasmota.log("MTR: parsed TLV: " + str(val), 4) self.pA = val.getsubval(1) return self @@ -113,12 +113,12 @@ class Matter_Pake2 var pB # 65 bytes var cB # 32 bytes - def encode(b) + def tlv2raw(b) var s = matter.TLV.Matter_TLV_struct() # s.add_TLV(1, matter.TLV.B1, self.pB) s.add_TLV(2, matter.TLV.B1, self.cB) - return s.encode() + return s.tlv2raw(b) end end matter.Pake2 = Matter_Pake2 @@ -130,7 +130,7 @@ class Matter_Pake3 def parse(b, idx) if idx == nil idx = 0 end var val = matter.TLV.parse(b, idx) - tasmota.log("MTR: parsed TLV: " + str(val), 3) + tasmota.log("MTR: parsed TLV: " + str(val), 4) self.cA = val.getsubval(1) return self @@ -157,7 +157,7 @@ class Matter_Sigma1 if idx == nil idx = 0 end var val = matter.TLV.parse(b, idx) self.Msg1 = b[idx..] - tasmota.log("MTR: Sigma1 TLV=" + str(val), 3) + tasmota.log("MTR: Sigma1 TLV=" + str(val), 4) self.initiatorRandom = val.getsubval(1) self.initiator_session_id = val.getsubval(2) @@ -168,8 +168,8 @@ class Matter_Sigma1 self.SLEEPY_IDLE_INTERVAL = initiatorSEDParams.findsubval(1) self.SLEEPY_ACTIVE_INTERVAL = initiatorSEDParams.findsubval(2) end - var resumptionID = val.findsub(6) - var initiatorResumeMIC = val.findsub(7) + self.resumptionID = val.findsubval(6) + self.initiatorResumeMIC = val.findsubval(7) return self end end @@ -186,7 +186,7 @@ class Matter_Sigma2 var SLEEPY_IDLE_INTERVAL var SLEEPY_ACTIVE_INTERVAL - def encode(b) + def tlv2raw(b) var s = matter.TLV.Matter_TLV_struct() # initiatorRandom s.add_TLV(1, matter.TLV.B1, self.responderRandom) @@ -198,7 +198,7 @@ class Matter_Sigma2 s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL) s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL) end - return s.encode() + return s.tlv2raw(b) end end matter.Sigma2 = Matter_Sigma2 @@ -213,18 +213,18 @@ class Matter_Sigma2Resume var SLEEPY_IDLE_INTERVAL var SLEEPY_ACTIVE_INTERVAL - def encode(b) + def tlv2raw(b) var s = matter.TLV.Matter_TLV_struct() # initiatorRandom s.add_TLV(1, matter.TLV.B1, self.resumptionID) s.add_TLV(2, matter.TLV.B1, self.sigma2ResumeMIC) - s.add_TLV(3, matter.TLV.B1, self.responderSessionID) + s.add_TLV(3, matter.TLV.U2, self.responderSessionID) if self.SLEEPY_IDLE_INTERVAL != nil || self.SLEEPY_ACTIVE_INTERVAL != nil var s2 = s.add_struct(4) s2.add_TLV(1, matter.TLV.U4, self.SLEEPY_IDLE_INTERVAL) s2.add_TLV(2, matter.TLV.U4, self.SLEEPY_ACTIVE_INTERVAL) end - return s.encode() + return s.tlv2raw(b) end end matter.Sigma2Resume = Matter_Sigma2Resume @@ -240,7 +240,7 @@ class Matter_Sigma3 if idx == nil idx = 0 end var val = matter.TLV.parse(b, idx) self.Msg3 = b[idx..] - tasmota.log("MTR: Sigma3 TLV=" + str(val), 3) + tasmota.log("MTR: Sigma3 TLV=" + str(val), 4) self.TBEData3Encrypted = val.getsubval(1) return self diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Control_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_Control_Message.be new file mode 100644 index 000000000..d2d3192ba --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Control_Message.be @@ -0,0 +1,79 @@ +# +# Matter_Control_Message.be - suppport for Matter Control Messages (flag C = 1) +# +# 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 + +#@ solidify:Matter_Control_Message,weak + +################################################################################# +# Class Matter_Control_Message +# +# Control message have C flag = 1 +# Used primarily for Message Counter Synchronization Protocol (MCSP) +################################################################################# +class Matter_Control_Message + var responder # reference to the caller, sending packets + var device # root device object + + def init(responder) + import crypto + self.responder = responder + self.device = responder.device + end + + def process_incoming_control_message(msg) + + tasmota.log("MTR: received control message " + matter.inspect(msg), 2) + if msg.opcode == 0x00 + return self.parse_MsgCounterSyncReq(msg) + elif msg.opcode == 0x01 + return self.parse_MsgCounterSyncRsp(msg) + else + import string + tasmota.log(string.format("MTR: >????????? Unknown OpCode (control message) %02X", msg.opcode), 2) + return false + end + + return false + end + + ############################################################# + # MsgCounterSyncReq + # + # Not yet implemented + def parse_MsgCounterSyncReq(msg) + import string + var session = msg.session + tasmota.log(string.format("MTR: >MCSyncReq * Not implemented %s", msg.raw[msg.app_payload_idx..].tohex()), 2) + return false # we don't explicitly ack the message + end + + ############################################################# + # MsgCounterSyncRsp + # + # Not yet implemented + def parse_MsgCounterSyncRsp(msg) + import string + var session = msg.session + tasmota.log(string.format("MTR: >MCSyncRsp * Not implemented %s", msg.raw[msg.app_payload_idx..].tohex()), 2) + return false # we don't explicitly ack the message + end + +end +matter.Control_Message = Matter_Control_Message diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be index 7765c16b8..312189d2b 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be @@ -26,25 +26,41 @@ class Matter_Device static var VENDOR_ID = 0xFFF1 static var PRODUCT_ID = 0x8000 static var FILENAME = "_matter_device.json" + static var PASE_TIMEOUT = 10*60 # default open commissioning window (10 minutes) + var started # is the Matter Device started (configured, mDNS and UDPServer started) var plugins # list of plugins var udp_server # `matter.UDPServer()` object - var msg_handler # `matter.MessageHandler()` object + var message_handler # `matter.MessageHandler()` object var sessions # `matter.Session_Store()` objet var ui + # Commissioning open + var commissioning_open # timestamp for timeout of commissioning (millis()) or `nil` if closed + var commissioning_iterations # current PBKDF number of iterations + var commissioning_discriminator # commissioning_discriminator + var commissioning_salt # current salt + var commissioning_w0 # current w0 (SPAKE2+) + var commissioning_L # current L (SPAKE2+) + var commissioning_admin_fabric # the fabric that opened the currint commissioning window, or `nil` for default # information about the device - var commissioning_instance_wifi # random instance name for commissioning - var commissioning_instance_eth # random instance name for commissioning + var commissioning_instance_wifi # random instance name for commissioning (mDNS) + var commissioning_instance_eth # random instance name for commissioning (mDNS) var hostname_wifi # MAC-derived hostname for commissioning var hostname_eth # MAC-derived hostname for commissioning var vendorid var productid - var discriminator + # mDNS active announces + var mdns_pase_eth # do we have an active PASE mDNS announce for eth + var mdns_pase_wifi # do we have an active PASE mDNS announce for wifi + # saved in parameters + var root_discriminator # as `int` + var root_passcode # as `int` + var ipv4only # advertize only IPv4 addresses (no IPv6) # context for PBKDF - var passcode - var iterations + var root_iterations # PBKDF number of iterations # PBKDF information used only during PASE (freed afterwards) - var salt - var w0, w1, L + var root_salt + var root_w0 + var root_L ############################################################# def init() @@ -55,87 +71,181 @@ class Matter_Device return end # abort if SetOption 151 is not set + self.started = false self.plugins = [] self.vendorid = self.VENDOR_ID self.productid = self.PRODUCT_ID - self.iterations = self.PBKDF_ITERATIONS + self.root_iterations = self.PBKDF_ITERATIONS + self.root_salt = crypto.random(16) # bytes("5350414B453250204B65792053616C74") + self.ipv4only = false self.load_param() - self.commissioning_instance_wifi = crypto.random(8).tohex() # 16 characters random hostname - self.commissioning_instance_eth = crypto.random(8).tohex() # 16 characters random hostname self.sessions = matter.Session_Store() - self.sessions.load() - self.msg_handler = matter.MessageHandler(self) + self.sessions.load_fabrics() + self.message_handler = matter.MessageHandler(self) self.ui = matter.UI(self) - # add the default plugin - self.plugins.push(matter.Plugin_core(self)) - self.plugins.push(matter.Plugin_Relay(self)) - - self.start_mdns_announce_hostnames() - - if tasmota.wifi()['up'] - self.start_udp(self.UDP_PORT) - else + if tasmota.wifi()['up'] || tasmota.eth()['up'] + self.start() + end + if !tasmota.wifi()['up'] tasmota.add_rule("Wifi#Connected", def () - self.start_udp(self.UDP_PORT) - tasmota.remove_rule("Wifi#Connected", "matter_device_udp") - - end, self) + self.start() + tasmota.remove_rule("Wifi#Connected", "matter_start") + end, "matter_start") end - - if tasmota.eth()['up'] - self.start_udp(self.UDP_PORT) - else + if !tasmota.eth()['up'] tasmota.add_rule("Eth#Connected", def () - self.start_udp(self.UDP_PORT) - tasmota.remove_rule("Eth#Connected", "matter_device_udp") - end, self) + self.start() + tasmota.remove_rule("Eth#Connected", "matter_start") + end, "matter_start") end - self.start_basic_commissioning() + self._init_basic_commissioning() tasmota.add_driver(self) end ############################################################# - # Start Basic Commissioning Window - def start_basic_commissioning() - # compute PBKDF - self.compute_pbkdf(self.passcode) - end + # Start Matter device server when the first network is coming up + def start() + if self.started return end # abort if already started - def finish_commissioning() + # add the default plugin + self.plugins.push(matter.Plugin_Root(self, 0)) + # autoconfigure other plugins + self.autoconf_device() + + # for now read sensors every 5 seconds + tasmota.add_cron("*/5 * * * * *", def () self._trigger_read_sensors() end, "matter_sensors_5s") + + self._start_udp(self.UDP_PORT) + + self.start_mdns_announce_hostnames() + + self.started = true end ############################################################# - # Compute the PBKDF parameters for SPAKE2+ + # Start Basic Commissioning Window if needed at startup + def _init_basic_commissioning() + # if no fabric is configured, automatically open commissioning at restart + if self.sessions.count_active_fabrics() == 0 + self.start_root_basic_commissioning() + end + end + + ############################################################# + # Start Basic Commissioning with root parameters # - # iterations is set to 1000 which is large enough - def compute_pbkdf(passcode_int) + # Open window for `timeout_s` (default 10 minutes) + def start_root_basic_commissioning(timeout_s) + import string + if timeout_s == nil timeout_s = self.PASE_TIMEOUT end + + # show Manual pairing code in logs + var pairing_code = self.compute_manual_pairing_code() + tasmota.log(string.format("MTR: Manual pairing code: %s-%s-%s", pairing_code[0..3], pairing_code[4..6], pairing_code[7..]), 2) + + # compute PBKDF + self._compute_pbkdf(self.root_passcode, self.root_iterations, self.root_salt) + self.start_basic_commissioning(timeout_s, self.root_iterations, self.root_discriminator, self.root_salt, self.root_w0, #-self.root_w1,-# self.root_L, nil) + end + + ##################################################################### + # Remove a fabric and clean all corresponding values and mDNS entries + def remove_fabric(fabric_parent) + var sub_fabrics = self.sessions.find_children_fabrics(fabric_parent.get_fabric_index()) + if sub_fabrics == nil return end + for fabric_index : sub_fabrics + var fabric = self.sessions.find_fabric_by_index(fabric_index) + if fabric != nil + self.message_handler.im.subs_shop.remove_by_fabric(fabric) + self.mdns_remove_op_discovery(fabric) + self.sessions.remove_fabric(fabric) + end + end + self.sessions.save_fabrics() + end + + ############################################################# + # Start Basic Commissioning Window with custom parameters + def start_basic_commissioning(timeout_s, iterations, discriminator, salt, w0, L, admin_fabric) + self.commissioning_open = tasmota.millis() + timeout_s * 1000 + self.commissioning_iterations = iterations + self.commissioning_discriminator = discriminator + self.commissioning_salt = salt + self.commissioning_w0 = w0 + self.commissioning_L = L + self.commissioning_admin_fabric = admin_fabric + + if tasmota.wifi()['up'] || tasmota.eth()['up'] + self.mdns_announce_PASE() + else + tasmota.add_rule("Wifi#Connected", def () + self.mdns_announce_PASE() + tasmota.remove_rule("Wifi#Connected", "mdns_announce_PASE") + end, "mdns_announce_PASE") + tasmota.add_rule("Eth#Connected", def () + self.mdns_announce_PASE() + tasmota.remove_rule("Eth#Connected", "mdns_announce_PASE") + end, "mdns_announce_PASE") + end + end + + ############################################################# + # Is root commissioning currently open. Mostly for UI to know if QRCode needs to be shown. + def is_root_commissioning_open() + return self.commissioning_open != nil && self.commissioning_admin_fabric == nil + end + + ############################################################# + # Stop PASE commissioning, mostly called when CASE is about to start + def stop_basic_commissioning() + self.commissioning_open = nil + + self.mdns_remove_PASE() + + # clear any PBKDF information to free memory + self.commissioning_iterations = nil + self.commissioning_discriminator = nil + self.commissioning_salt = nil + self.commissioning_w0 = nil + # self.commissioning_w1 = nil + self.commissioning_L = nil + self.commissioning_admin_fabric = nil + end + def is_commissioning_open() + return self.commissioning_open != nil + end + + ############################################################# + # (internal) Compute the PBKDF parameters for SPAKE2+ from root parameters + # + def _compute_pbkdf(passcode_int, iterations, salt) import crypto - self.salt = crypto.random(16) # bytes("5350414B453250204B65792053616C74") + import string var passcode = bytes().add(passcode_int, 4) - var tv = crypto.PBKDF2_HMAC_SHA256().derive(passcode, self.salt, self.iterations, 80) + var tv = crypto.PBKDF2_HMAC_SHA256().derive(passcode, salt, iterations, 80) var w0s = tv[0..39] var w1s = tv[40..79] - self.w0 = crypto.EC_P256().mod(w0s) - self.w1 = crypto.EC_P256().mod(w1s) - self.L = crypto.EC_P256().public_key(self.w1) + self.root_w0 = crypto.EC_P256().mod(w0s) + var w1 = crypto.EC_P256().mod(w1s) # w1 is temporarily computed then discarded + # self.root_w1 = crypto.EC_P256().mod(w1s) + self.root_L = crypto.EC_P256().public_key(w1) - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: salt = " + self.salt.tohex(), 3) - tasmota.log("MTR: passcode = " + passcode.tohex(), 3) - tasmota.log("MTR: w0 = " + self.w0.tohex(), 3) - tasmota.log("MTR: w1 = " + self.w1.tohex(), 3) - tasmota.log("MTR: L = " + self.L.tohex(), 3) - tasmota.log("MTR: ******************************", 3) + # tasmota.log("MTR: ******************************", 4) + # tasmota.log("MTR: salt = " + self.root_salt.tohex(), 4) + # tasmota.log("MTR: passcode_hex = " + passcode.tohex(), 4) + # tasmota.log("MTR: w0 = " + self.root_w0.tohex(), 4) + # tasmota.log("MTR: L = " + self.root_L.tohex(), 4) + # tasmota.log("MTR: ******************************", 4) end ############################################################# - # compute QR Code content + # Compute QR Code content - can be done only for root PASE def compute_qrcode_content() var raw = bytes().resize(11) # we don't use TLV Data so it's only 88 bits or 11 bytes # version is `000` dont touch @@ -143,20 +253,22 @@ class Matter_Device raw.setbits(19, 16, self.productid) # custom flow = 0 (offset=35, len=2) raw.setbits(37, 8, 0x04) # already on IP network - raw.setbits(45, 12, self.discriminator & 0xFFF) - raw.setbits(57, 27, self.passcode & 0x7FFFFFF) + raw.setbits(45, 12, self.root_discriminator & 0xFFF) + raw.setbits(57, 27, self.root_passcode & 0x7FFFFFF) # padding (offset=84 len=4) return "MT:" + matter.Base38.encode(raw) end ############################################################# - # compute the 11 digits manual pairing code (wihout vendorid nor productid) p.223 + # Compute the 11 digits manual pairing code (wihout vendorid nor productid) p.223 + #
+ # can be done only for root PASE (we need the passcode, but we don't get it with OpenCommissioningWindow command) def compute_manual_pairing_code() import string - var digit_1 = (self.discriminator & 0x0FFF) >> 10 - var digit_2_6 = ((self.discriminator & 0x0300) << 6) | (self.passcode & 0x3FFF) - var digit_7_10 = (self.passcode >> 14) + var digit_1 = (self.root_discriminator & 0x0FFF) >> 10 + var digit_2_6 = ((self.root_discriminator & 0x0300) << 6) | (self.root_passcode & 0x3FFF) + var digit_7_10 = (self.root_passcode >> 14) var ret = string.format("%1i%05i%04i", digit_1, digit_2_6, digit_7_10) ret += matter.Verhoeff.checksum(ret) @@ -167,31 +279,77 @@ class Matter_Device # dispatch every second click to sub-objects that need it def every_second() self.sessions.every_second() - self.msg_handler.every_second() + self.message_handler.every_second() + if self.commissioning_open != nil && tasmota.time_reached(self.commissioning_open) # timeout reached, close provisioning + self.commissioning_open = nil + end + # call all plugins + var idx = 0 + while idx < size(self.plugins) + self.plugins[idx].every_second() + idx += 1 + end + end + + ############################################################# + # trigger a read_sensors and dispatch to plugins + # Internally used by cron + def _trigger_read_sensors() + import json + var rs_json = tasmota.read_sensors() + if rs_json == nil return end + var rs = json.load(rs_json) + if rs != nil + + # call all plugins + var idx = 0 + while idx < size(self.plugins) + self.plugins[idx].parse_sensors(rs) + idx += 1 + end + + else + tasmota.log("MTR: unable to parse read_sensors: "+str(rs_json), 3) + end + + end + + ############################################################# + # dispatch every 250ms click to sub-objects that need it + def every_250ms() + self.message_handler.every_250ms() end ############################################################# def stop() + tasmota.remove_driver(self) if self.udp_server self.udp_server.stop() end end ############################################################# - # callback when message is received + # Callback when message is received. + # Send to `message_handler` def msg_received(raw, addr, port) - return self.msg_handler.msg_received(raw, addr, port) - end - - def msg_send(raw, addr, port, id) - return self.udp_server.send_response(raw, addr, port, id) - end - - def packet_ack(id) - return self.udp_server.packet_ack(id) + return self.message_handler.msg_received(raw, addr, port) end ############################################################# - # Start UDP Server - def start_udp(port) + # Global entry point for sending a message. + # Delegates to `udp_server` + def msg_send(msg) + return self.udp_server.send_UDP(msg) + end + + ############################################################# + # Signals that a ack was received. + # Delegates to `udp_server` to remove from resending list. + def received_ack(msg) + return self.udp_server.received_ack(msg) + end + + ############################################################# + # (internal) Start UDP Server + def _start_udp(port) if self.udp_server return end # already started if port == nil port = 5540 end tasmota.log("MTR: starting UDP server on port: " + str(port), 2) @@ -200,163 +358,197 @@ class Matter_Device end ############################################################# - # start_operational_dicovery + # Start Operational Discovery for this session # - # Pass control to `device` - def start_operational_dicovery_deferred(session) + # Deferred until next tick. + def start_operational_discovery_deferred(session) # defer to next click - tasmota.set_timer(0, /-> self.start_operational_dicovery(session)) + tasmota.set_timer(0, /-> self.start_operational_discovery(session)) end ############################################################# + # Start Commissioning Complete for this session + # + # Deferred until next tick. def start_commissioning_complete_deferred(session) # defer to next click tasmota.set_timer(0, /-> self.start_commissioning_complete(session)) end ############################################################# - # Start UDP mDNS announcements for commissioning + # Start Operational Discovery for this session # - # eth is `true` if ethernet turned up, `false` is wifi turned up - # def mdns_announce_commissioning() - # var services = { - # "VP":str(self.vendorid) + "+" + str(self.productid), - # "D": self.discriminator, - # "CM":1, # requires passcode - # "T":0, # no support for TCP - # "SII":5000, "SAI":300 - # } - - # if self.self.hostname_eth - # mdns.add_service("_matterc","_udp", 5540, services, self.commissioning_instance_eth, self.hostname_eth) - # end - # if self.self.hostname_wifi - # mdns.add_service("_matter","_tcp", 5540, services, self.commissioning_instance_wifi, self.hostname_wifi) - # end - # end - - ############################################################# - # Start Operational Discovery - def start_operational_dicovery(session) + # Stop Basic Commissioning and clean PASE specific values (to save memory). + # Announce fabric entry in mDNS. + def start_operational_discovery(session) import crypto import mdns import string + self.stop_basic_commissioning() # close all PASE commissioning information # clear any PBKDF information to free memory - self.salt = nil - self.w0 = nil - self.w1 = nil - self.L = nil + self.root_w0 = nil + # self.root_w1 = nil + self.root_L = nil - # save session as persistant - session.set_no_expiration() - session.set_persist(true) - # close the PASE session, it will be re-opened with a CASE session - session.close() - self.sessions.save() + # we keep the PASE session for 1 minute + session.set_expire_in_seconds(60) - self.mdns_announce_op_discovery(session) + self.mdns_announce_op_discovery(session.get_fabric()) end ############################################################# # Commissioning Complete # + # Stop basic commissioning. def start_commissioning_complete(session) tasmota.log("MTR: *** Commissioning complete ***", 2) + self.stop_basic_commissioning() # by default close commissioning when it's complete + end + + + ################################################################################# + # Simple insertion sort - sorts the list in place, and returns the list + # remove duplicates + ################################################################################# + static def sort_distinct(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 + # remove duplicate now that it's sorted + var i = 1 + if size(l) <= 1 return l end # no duplicate if empty or 1 element + var prev = l[0] + while i < size(l) + if l[i] == prev + l.remove(i) + else + prev = l[i] + i += 1 + end + end + return l end ############################################################# - # read an attribute + # Signal that an attribute has been changed and propagate + # to any active subscription. # - # def read_attribute(msg, ctx) - # # dispatch only to plugins that support this endpoint and cluster - # var endpoint = ctx.endpoint - # var cluster = ctx.cluster - - # var idx = 0 - # while idx < size(self.plugins) - # var plugin = self.plugins[idx] - - # if plugin.has(cluster, endpoint) - # var ret = plugin.read_attribute(msg, ctx) - # if ret != nil - # return ret - # end - # end - - # idx += 1 - # end - # end + # Delegates to `message_handler` + def attribute_updated(endpoint, cluster, attribute, fabric_specific) + if fabric_specific == nil fabric_specific = false end + var ctx = matter.Path() + ctx.endpoint = endpoint + ctx.cluster = cluster + ctx.attribute = attribute + self.message_handler.im.subs_shop.attribute_updated_ctx(ctx, fabric_specific) + end ############################################################# - # expand attribute list based + # Proceed to attribute expansion (used for Attribute Read/Write/Subscribe) # - # called only when expansion is needed, - # so we don't need to report any error since they are ignored + # Called only when expansion is needed, so we don't need to report any error since they are ignored + # + # calls `cb(pi, ctx, direct)` for each attribute expanded. + # `pi`: plugin instance targeted by the attribute (via endpoint). Note: nothing is sent if the attribute is not declared in supported attributes in plugin. + # `ctx`: context object with `endpoint`, `cluster`, `attribute` (no `command`) + # `direct`: `true` if the attribute is directly targeted, `false` if listed as part of a wildcard + # returns: `true` if processed succesfully, `false` if error occured. If `direct`, the error is returned to caller, but if expanded the error is silently ignored and the attribute skipped. + # In case of `direct` but the endpoint/cluster/attribute is not suppported, it calls `cb(nil, ctx, true)` so you have a chance to encode the exact error (UNSUPPORTED_ENDPOINT/UNSUPPORTED_CLUSTER/UNSUPPORTED_ATTRIBUTE/UNREPORTABLE_ATTRIBUTE) def process_attribute_expansion(ctx, cb) + ################################################################################# + # Returns the keys of a map as a sorted list + ################################################################################# + def keys_sorted(m) + var l = [] + for k: m.keys() + l.push(k) + end + # 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 + import string var endpoint = ctx.endpoint - var endpoint_mono = [ endpoint ] + # var endpoint_mono = [ endpoint ] var endpoint_found = false # did any endpoint match var cluster = ctx.cluster - var cluster_mono = [ cluster ] + # var cluster_mono = [ cluster ] var cluster_found = false var attribute = ctx.attribute - var attribute_mono = [ attribute ] + # var attribute_mono = [ attribute ] var attribute_found = false var direct = (ctx.endpoint != nil) && (ctx.cluster != nil) && (ctx.attribute != nil) # true if the target is a precise attribute, false if it results from an expansion and error are ignored - tasmota.log(string.format("MTR: process_attribute_expansion %s", str(ctx)), 3) + tasmota.log(string.format("MTR: process_attribute_expansion %s", str(ctx)), 4) + + # build the list of candidates + + # list of all endpoints + var all = {} # map of {endpoint: {cluster: {attributes:[pi]}} + tasmota.log(string.format("MTR: endpoint=%s cluster=%s attribute=%s", endpoint, cluster, attribute), 4) for pi: self.plugins - var ep_list = pi.get_endpoints() # get supported endpoints for this plugin - tasmota.log(string.format("MTR: ep_list %s %s", str(pi), str(ep_list)), 3) - if endpoint != nil - # we have a specific endpoint, make sure it's in the list - if ep_list.find(endpoint) != nil - ep_list = endpoint_mono - endpoint_found = true - else - continue + var ep = pi.get_endpoint() # get supported endpoints for this plugin + + if endpoint != nil && ep != endpoint continue end # skip if specific endpoint and no match + # from now on, 'ep' is a good candidate + if !all.contains(ep) all[ep] = {} end # create empty structure if not already in the list + endpoint_found = true + + # now explore the cluster list for 'ep' + var cluster_list = pi.get_cluster_list(ep) # cluster_list is the actual list of candidate cluster for this pluging and endpoint + tasmota.log(string.format("MTR: pi=%s ep=%s cl_list=%s", str(pi), str(ep), str(cluster_list)), 4) + for cl: cluster_list + if cluster != nil && cl != cluster continue end # skip if specific cluster and no match + # from now on, 'cl' is a good candidate + if !all[ep].contains(cl) all[ep][cl] = {} end + cluster_found = true + + # now filter on attributes + var attr_list = pi.get_attribute_list(ep, cl) + tasmota.log(string.format("MTR: pi=%s ep=%s cl=%s at_list=%s", str(pi), str(ep), str(cl), str(attr_list)), 4) + for at: attr_list + if attribute != nil && at != attribute continue end # skip if specific attribute and no match + # from now on, 'at' is a good candidate + if !all[ep][cl].contains(at) all[ep][cl][at] = [] end + attribute_found = true + + all[ep][cl][at].push(pi) # add plugin to the list end end - # ep_list is the actual list of candidate endpoints for this plugin - # iterate on endpoints - for ep: ep_list - # now filter on clusters - var cluster_list = pi.get_cluster_list(ep) - tasmota.log(string.format("MTR: cluster_list %s %s", str(ep), str(cluster_list)), 3) - if cluster != nil - # we have a specific cluster, make sure it's in the list - if cluster_list.find(cluster) != nil - cluster_list = cluster_mono - cluster_found = true - else - continue - end - end - # cluster_list is the actual list of candidate cluster for this pluging and endpoint - for cl: cluster_list - # now filter on attribute - var attr_list = pi.get_attribute_list(ep, cluster) - tasmota.log(string.format("MTR: attr_list %s %s", str(cl), str(attr_list)), 3) - if attribute != nil - # we have a specific attribute, make sure it's in the list - if attr_list.find(attribute) != nil - attr_list = attribute_mono - attribute_found = true - else - continue - end - for at: attr_list - # we now have the complete candidate: ep/cl/at - tasmota.log(string.format("MTR: expansion [%02X]%04X/%04X", ep, cl, at), 3) - ctx.endpoint = ep - ctx.cluster = cl - ctx.attribute = at - var finished = cb(pi, ctx, direct) # call the callback with the plugin and the context - if finished return end - end + end + + # import json + # tasmota.log("MTR: all = " + json.dump(all), 2) + + # iterate on candidates + for ep: keys_sorted(all) + for cl: keys_sorted(all[ep]) + for at: keys_sorted(all[ep][cl]) + for pi: all[ep][cl][at] + tasmota.log(string.format("MTR: expansion [%02X]%04X/%04X", ep, cl, at), 3) + ctx.endpoint = ep + ctx.cluster = cl + ctx.attribute = at + var finished = cb(pi, ctx, direct) # call the callback with the plugin and the context + if direct && finished return end end end end @@ -374,24 +566,15 @@ class Matter_Device end end - # def process_read_attribute(ctx) - # self.process_attribute_expansion(ctx, - # / pi, ctx, direct -> pi.read_attribute(ctx)) - # end - ############################################################# - # get active endpoints - # - # return the list of endpoints from all plugins (distinct) + # Return the list of endpoints from all plugins (distinct), exclud endpoint zero if `exclude_zero` is `true` def get_active_endpoints(exclude_zero) var ret = [] for p:self.plugins - var e = p.get_endpoints() - for elt:e - if exclude_zero && elt == 0 continue end - if ret.find(elt) == nil - ret.push(elt) - end + var ep = p.get_endpoint() + if exclude_zero && ep == 0 continue end + if ret.find(ep) == nil + ret.push(ep) end end return ret @@ -404,7 +587,7 @@ class Matter_Device # def save_param() import json - var j = json.dump({'distinguish':self.discriminator, 'passcode':self.passcode}) + var j = json.dump({'distinguish':self.root_discriminator, 'passcode':self.root_passcode, 'ipv4only':self.ipv4only}) try import string var f = open(self.FILENAME, "w") @@ -418,6 +601,7 @@ class Matter_Device end ############################################################# + # Load Matter Device parameters def load_param() import string import crypto @@ -430,8 +614,9 @@ class Matter_Device import json var j = json.load(s) - self.discriminator = j.find("distinguish") - self.passcode = j.find("passcode") + self.root_discriminator = j.find("distinguish", self.root_discriminator) + self.root_passcode = j.find("passcode", self.root_passcode) + self.ipv4only = bool(j.find("ipv4only", false)) except .. as e, m if e != "io_error" tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2) @@ -439,12 +624,12 @@ class Matter_Device end var dirty = false - if self.discriminator == nil - self.discriminator = crypto.random(2).get(0,2) & 0xFFF + if self.root_discriminator == nil + self.root_discriminator = crypto.random(2).get(0,2) & 0xFFF dirty = true end - if self.passcode == nil - self.passcode = self.PASSCODE_DEFAULT + if self.root_passcode == nil + self.root_passcode = self.PASSCODE_DEFAULT dirty = true end if dirty self.save_param() end @@ -457,139 +642,201 @@ class Matter_Device # Plugins allow to specify response to read/write attributes # and command invokes ############################################################# - def invoke_request(msg, val, ctx) + def invoke_request(session, val, ctx) var idx = 0 + var endpoint = ctx.endpoint while idx < size(self.plugins) var plugin = self.plugins[idx] - var ret = plugin.invoke_request(msg, val, ctx) - if ret != nil || ctx.status != matter.UNSUPPORTED_COMMAND # default value - return ret + if plugin.endpoint == endpoint + return plugin.invoke_request(session, val, ctx) end idx += 1 end + ctx.status = matter.UNSUPPORTED_ENDPOINT end ############################################################# - # MDNS Configuration + # mDNS Configuration ############################################################# - # Start MDNS and announce hostnames for Wifi and ETH from MAC + # Start mDNS and announce hostnames for Wifi and ETH from MAC # # When the announce is active, `hostname_wifi` and `hostname_eth` # are defined def start_mdns_announce_hostnames() if tasmota.wifi()['up'] - self._start_mdns_announce(false) + self._mdns_announce_hostname(false) else tasmota.add_rule("Wifi#Connected", def () - self._start_mdns_announce(false) - tasmota.remove_rule("Wifi#Connected", "matter_device_mdns") - end, self) + self._mdns_announce_hostname(false) + tasmota.remove_rule("Wifi#Connected", "matter_mdns_host") + end, "matter_mdns_host") end if tasmota.eth()['up'] - self._start_mdns_announce(true) + self._mdns_announce_hostname(true) else tasmota.add_rule("Eth#Connected", def () - self._start_mdns_announce(true) - tasmota.remove_rule("Eth#Connected", "matter_device_mdns") - end, self) + self._mdns_announce_hostname(true) + tasmota.remove_rule("Eth#Connected", "matter_mdns_host") + end, "matter_mdns_host") end end ############################################################# - # Start UDP mDNS announcements for commissioning + # Start UDP mDNS announcements hostname + # This announcement is independant from commissioning windows # # eth is `true` if ethernet turned up, `false` is wifi turned up - def _start_mdns_announce(is_eth) + def _mdns_announce_hostname(is_eth) import mdns import string mdns.start() + try + if is_eth + # Add Hostname (based on MAC) with IPv4/IPv6 addresses + var eth = tasmota.eth() + self.hostname_eth = string.replace(eth.find("mac"), ':', '') + if !self.ipv4only + tasmota.log(string.format("MTR: calling mdns.add_hostname(%s, %s, %s)", self.hostname_eth, eth.find('ip6local',''), eth.find('ip','')), 3) + mdns.add_hostname(self.hostname_eth, eth.find('ip6local',''), eth.find('ip',''), eth.find('ip6','')) + else + tasmota.log(string.format("MTR: calling mdns.add_hostname(%s, %s)", self.hostname_eth, eth.find('ip','')), 3) + mdns.add_hostname(self.hostname_eth, eth.find('ip','')) + end + else + var wifi = tasmota.wifi() + self.hostname_wifi = string.replace(wifi.find("mac"), ':', '') + if !self.ipv4only + tasmota.log(string.format("MTR: calling mdns.add_hostname(%s, %s, %s)", self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip','')), 3) + mdns.add_hostname(self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip',''), wifi.find('ip6','')) + else + tasmota.log(string.format("MTR: calling mdns.add_hostname(%s, %s)", self.hostname_eth, wifi.find('ip','')), 3) + mdns.add_hostname(self.hostname_wifi, wifi.find('ip','')) + end + end + tasmota.log(string.format("MTR: start mDNS on %s host '%s.local'", is_eth ? "eth" : "wifi", is_eth ? self.hostname_eth : self.hostname_wifi), 2) + except .. as e, m + tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) + end + + self.mdns_announce_op_discovery_all_fabrics() + end + + ############################################################# + # Announce MDNS for PASE commissioning + def mdns_announce_PASE() + import mdns + import string + import crypto + var services = { "VP":str(self.vendorid) + "+" + str(self.productid), - "D": self.discriminator, + "D": self.commissioning_discriminator, "CM":1, # requires passcode "T":0, # no support for TCP "SII":5000, "SAI":300 } - # mdns + self.commissioning_instance_wifi = crypto.random(8).tohex() # 16 characters random hostname + self.commissioning_instance_eth = crypto.random(8).tohex() # 16 characters random hostname + try - if is_eth - var eth = tasmota.eth() - self.hostname_eth = string.replace(eth.find("mac"), ':', '') - mdns.add_hostname(self.hostname_eth, eth.find('ip6local',''), eth.find('ip',''), eth.find('ip6','')) + if self.hostname_eth + # Add Matter `_matterc._udp` service + tasmota.log(string.format("MTR: calling mdns.add_service(%s, %s, %i, %s, %s, %s)", "_matterc", "_udp", 5540, str(services), self.commissioning_instance_eth, self.hostname_eth), 3) mdns.add_service("_matterc", "_udp", 5540, services, self.commissioning_instance_eth, self.hostname_eth) + self.mdns_pase_eth = true - tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", is_eth ? "eth" : "wifi", - is_eth ? self.commissioning_instance_eth : self.commissioning_instance_wifi, - is_eth ? self.hostname_eth : self.hostname_wifi), 2) + tasmota.log(string.format("MTR: announce mDNS on %s '%s' ptr to `%s.local`", "eth", self.commissioning_instance_eth, self.hostname_eth), 2) # `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil` - var subtype = "_L" + str(self.discriminator & 0xFFF) - tasmota.log("MTR: adding subtype: "+subtype, 3) + var subtype = "_L" + str(self.commissioning_discriminator & 0xFFF) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) - subtype = "_S" + str((self.discriminator & 0xF00) >> 8) - tasmota.log("MTR: adding subtype: "+subtype, 3) + subtype = "_S" + str((self.commissioning_discriminator & 0xF00) >> 8) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) subtype = "_V" + str(self.vendorid) - tasmota.log("MTR: adding subtype: "+subtype, 3) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) subtype = "_CM1" - tasmota.log("MTR: adding subtype: "+subtype, 3) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth, subtype) - else - var wifi = tasmota.wifi() - self.hostname_wifi = string.replace(wifi.find("mac"), ':', '') - mdns.add_hostname(self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip',''), wifi.find('ip6','')) + end + if self.hostname_wifi + + tasmota.log(string.format("MTR: calling mdns.add_service(%s, %s, %i, %s, %s, %s)", "_matterc", "_udp", 5540, str(services), self.commissioning_instance_wifi, self.hostname_wifi), 3) mdns.add_service("_matterc", "_udp", 5540, services, self.commissioning_instance_wifi, self.hostname_wifi) + self.mdns_pase_wifi = true - tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", is_eth ? "eth" : "wifi", - is_eth ? self.commissioning_instance_eth : self.commissioning_instance_wifi, - is_eth ? self.hostname_eth : self.hostname_wifi), 2) + tasmota.log(string.format("MTR: starting mDNS on %s '%s' ptr to `%s.local`", "wifi", self.commissioning_instance_wifi, self.hostname_wifi), 2) # `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil` - var subtype = "_L" + str(self.discriminator & 0xFFF) - tasmota.log("MTR: adding subtype: "+subtype, 3) + var subtype = "_L" + str(self.commissioning_discriminator & 0xFFF) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) - subtype = "_S" + str((self.discriminator & 0xF00) >> 8) - tasmota.log("MTR: adding subtype: "+subtype, 3) + subtype = "_S" + str((self.commissioning_discriminator & 0xF00) >> 8) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) subtype = "_V" + str(self.vendorid) - tasmota.log("MTR: adding subtype: "+subtype, 3) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) subtype = "_CM1" - tasmota.log("MTR: adding subtype: "+subtype, 3) + tasmota.log("MTR: adding subtype: "+subtype, 2) mdns.add_subtype("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi, subtype) end except .. as e, m tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) end - self.mdns_announce_op_discovery_all_sessions() + end + + ############################################################# + # MDNS remove any PASE announce + def mdns_remove_PASE() + import mdns + import string + + try + if self.mdns_pase_eth + tasmota.log(string.format("MTR: calling mdns.remove_service(%s, %s, %s, %s)", "_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth), 3) + tasmota.log(string.format("MTR: remove mDNS on %s '%s'", "eth", self.commissioning_instance_eth), 2) + self.mdns_pase_eth = false + mdns.remove_service("_matterc", "_udp", self.commissioning_instance_eth, self.hostname_eth) + end + if self.mdns_pase_wifi + tasmota.log(string.format("MTR: calling mdns.remove_service(%s, %s, %s, %s)", "_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi), 3) + tasmota.log(string.format("MTR: remove mDNS on %s '%s'", "wifi", self.commissioning_instance_wifi), 2) + self.mdns_pase_wifi = false + mdns.remove_service("_matterc", "_udp", self.commissioning_instance_wifi, self.hostname_wifi) + end + except .. as e, m + tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) + end end ############################################################# # Start UDP mDNS announcements for commissioning for all persisted sessions - def mdns_announce_op_discovery_all_sessions() - for session: self.sessions.sessions - if session.get_deviceid() && session.get_fabric() - self.mdns_announce_op_discovery(session) + def mdns_announce_op_discovery_all_fabrics() + for fabric: self.sessions.active_fabrics() + if fabric.get_device_id() && fabric.get_fabric_id() + self.mdns_announce_op_discovery(fabric) end end end ############################################################# # Start UDP mDNS announcements for commissioning - def mdns_announce_op_discovery(session) + def mdns_announce_op_discovery(fabric) import mdns import string try - var device_id = session.get_deviceid().copy().reverse() - var k_fabric = session.get_fabric_compressed() + var device_id = fabric.get_device_id().copy().reverse() + var k_fabric = fabric.get_fabric_compressed() var op_node = k_fabric.tohex() + "-" + device_id.tohex() tasmota.log("MTR: Operational Discovery node = " + op_node, 2) @@ -612,6 +859,92 @@ class Matter_Device tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) end end + + ############################################################# + # Remove all mDNS announces for all fabrics + def mdns_remove_op_discovery_all_fabrics() + for fabric: self.sessions.active_fabrics() + if fabric.get_device_id() && fabric.get_fabric_id() + self.mdns_remove_op_discovery(fabric) + end + end + end + + ############################################################# + # Remove mDNS announce for fabric + def mdns_remove_op_discovery(fabric) + import mdns + import string + try + var device_id = fabric.get_device_id().copy().reverse() + var k_fabric = fabric.get_fabric_compressed() + var op_node = k_fabric.tohex() + "-" + device_id.tohex() + + # mdns + if (tasmota.eth().find("up")) + tasmota.log(string.format("MTR: remove mDNS on %s '%s'", "eth", op_node), 2) + mdns.remove_service("_matter", "_tcp", op_node, self.hostname_eth) + end + if (tasmota.wifi().find("up")) + tasmota.log(string.format("MTR: remove mDNS on %s '%s'", "wifi", op_node), 2) + mdns.remove_service("_matter", "_tcp", op_node, self.hostname_wifi) + end + except .. as e, m + tasmota.log("MTR: Exception" + str(e) + "|" + str(m), 2) + end + end + + ############################################################# + # Try to clean MDNS entries before restart. + # + # Called by Tasmota loop as a Tasmota driver. + def save_before_restart() + self.stop_basic_commissioning() + self.mdns_remove_op_discovery_all_fabrics() + end + + ############################################################# + # Autoconfigure device from template + # + def autoconf_device() + import string + # check if we have a light + var endpoint = 1 + var light_present = false + + import light + var light_status = light.get() + if light_status != nil + var channels_count = size(light_status.find('channels', "")) + if channels_count > 0 + if channels_count == 1 + self.plugins.push(matter.Plugin_Light1(self, endpoint)) + tasmota.log(string.format("MTR: Endpoint:%i Light_Dimmer", endpoint), 2) + elif channels_count == 2 + self.plugins.push(matter.Plugin_Light2(self, endpoint)) + tasmota.log(string.format("MTR: Endpoint:%i Light_CT", endpoint), 2) + else + self.plugins.push(matter.Plugin_Light3(self, endpoint)) + tasmota.log(string.format("MTR: Endpoint:%i Light_RGB", endpoint), 2) + end + light_present = true + endpoint += 1 + end + end + + # how many relays are present + var relay_count = size(tasmota.get_power()) + var relay_index = 0 # start at index 0 + if light_present relay_count -= 1 end # last power is taken for lights + + while relay_index < relay_count + self.plugins.push(matter.Plugin_OnOff(self, endpoint, relay_index)) + tasmota.log(string.format("MTR: Endpoint:%i Relay_%i", endpoint, relay_index + 1), 2) + relay_index += 1 + endpoint += 1 + end + + end end matter.Device = Matter_Device diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Expirable.be b/lib/libesp32/berry_matter/src/embedded/Matter_Expirable.be new file mode 100644 index 000000000..391476982 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Expirable.be @@ -0,0 +1,234 @@ +# +# Matter_Expirable.be - Support for Matter Expirable and Persistable objects and lists +# +# 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 + +#@ solidify:Matter_Expirable,weak +#@ solidify:Matter_Expirable_list,weak + +################################################################################# +# Matter_Expirable class +# +# Object that can expire after a certain timestamp or +# that does not expire and can be persisted +# +# There are only 3 valid states: +# - not expirable and not persistable +# - expirable and not persistable +# - not expirable and persistable +# - (both expirable and persistable is normally not valid but still supported) +# +################################################################################# +class Matter_Expirable + var _list # the Expirable_list it belongs to (if any) + var _persist # do we persist this sessions or is it remporary (bool) + var _expiration # if not `nil` the entry is removed after this timestamp + + ############################################################# + def init() + self._persist = false + end + + ############################################################# + def set_parent_list(l) + self._list = l + end + def get_parent_list() + return self._list + end + + ############################################################# + def set_persist(p) + self._persist = bool(p) + end + def does_persist() + return self._persist + end + + ############################################################# + # pre and post process when persist + def persist_pre() + end + def persist_post() + end + + ############################################################# + # post process after the object was loaded + def hydrate_post() + end + + ############################################################# + # before_remove + # + # called right before the element is removed + def before_remove() + end + + ############################################################# + # set absolute time for expiration + def set_no_expiration() + self._expiration = nil + end + + ############################################################# + # set absolute time for expiration + def set_expire_time(t) + self._expiration = int(t) + end + + ############################################################# + # set relative time in the future for expiration (in seconds) + def set_expire_in_seconds(s, now) + if s == nil return end + if now == nil now = tasmota.rtc()['utc'] end + self.set_expire_time(now + s) + end + + ############################################################# + # set relative time in the future for expiration (in seconds) + # returns `true` if expiration date has been reached + def has_expired(now) + if now == nil now = tasmota.rtc()['utc'] end + if self._expiration != nil + return now >= self._expiration + end + return false + end + +end +matter.Expirable = Matter_Expirable + + +################################################################################# +# Matter_Expirable_list class +# +# Subclass of list handling Expirable(s) +# +################################################################################# +class Matter_Expirable_list : list + # no specific attributes + # no specific init() + + ############################################################# + # Accessors with control of arguments classes + def push(o) + if !isinstance(o, matter.Expirable) raise "type_error", "argument must be of class 'Expirable'" end + o.set_parent_list(self) + return super(self).push(o) + end + def setitem(i, o) + if !isinstance(o, matter.Expirable) raise "type_error", "argument must be of class 'Expirable'" end + o.set_parent_list(self) + return super(self).setitem(i, o) + end + + ############################################################# + # remove - override + # + def remove(i) + if i >= 0 && i < size(self) self[i].before_remove() end + return super(self).remove(i) + end + + ############################################################# + # remove_expired + # + # Check is any object has expired + # + # returns `true` if persistable objects were actually removed (i.e. needs to persist again), `false` instead + def remove_expired() + var dirty = false + var i = 0 + while i < size(self) + if self[i].has_expired() + if self[i]._persist dirty = true end # do we need to save + self.remove(i) + else + i += 1 + end + end + return dirty + end + + ############################################################# + # iterator over persistable instances + # + def persistables() + var iterator = self.iter() + var f = def () + while true + var o = iterator() + if o._persist return o end + end + # ends with an exception + end + + return f + end + + ############################################################# + # Count the number of persistable objects + def count_persistables() + var ret = 0 + var idx = 0 + while idx < size(self) + if self[idx]._persist ret += 1 end + idx += 1 + end + return ret + end + + ############################################################# + # every_second + def every_second() + self.remove_expired() + end + +end +matter.Expirable_list = Matter_Expirable_list + +#- + +# tests + +a = matter.Expirable() +a.set_persist(true) +b = matter.Expirable() +c = matter.Expirable() +c.set_persist(true) +l = matter.Expirable_list() + + +l.push(a) +l.push(b) +l.push(c) + +print('---') +for e:l print(e) end +print('---') +for e:l.persistables() print(e) end +print('---') + +l.every_second() +print(size(l)) +l[1].set_expire_time(10) +l.every_second() +print(size(l)) + +-# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be b/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be new file mode 100644 index 000000000..aee02ef36 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Fabric.be @@ -0,0 +1,288 @@ +# +# Matter_Fabric.be - Support for Matter Fabric +# +# 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 + +#@ solidify:Matter_Fabric,weak + +# for solidification only +class Matter_Expirable end + +################################################################################# +# Matter_Fabric class +# +# Record all information for a fabric that has provisioned +# +# By convetion: +# attributes with a normal name are persisted (unless they are instances) +# attributes starting with '_' are not persisted +# attributes starting with '__' are cleared when a new session is created +################################################################################# +class Matter_Fabric : Matter_Expirable + static var _MAX_CASE = 5 # maximum number of concurrent CASE sessions per fabric + static var _GROUP_SND_INCR = 32 # counter increased when persisting + # Group Key Derivation + static var _GROUP_KEY = "GroupKey v1.0" # starting with double `_` means it's not writable + + var _store # reference back to session store + # timestamp + var created + # fabric-index + var fabric_index # index number for fabrics, starts with `1` + var fabric_parent # index of the parent fabric, i.e. the fabric that triggered the provisioning (if nested) + # list of active sessions + var _sessions # only active CASE sessions that need to be persisted + # our own private key + var no_private_key # private key of the device certificate (generated at commissioning) + # NOC information + var root_ca_certificate # root certificate of the initiator + var noc # Node Operational Certificate in TLV Matter Certificate + var icac # Initiator CA Certificate in TLV Matter Certificate + var ipk_epoch_key # timestamp + # Information extracted from `noc` + var fabric_id # fabric identifier as bytes(8) little endian + var fabric_compressed # comrpessed fabric_id identifier, hashed with root_ca public key + var device_id # our own device id bytes(8) little endian + var fabric_label # set by UpdateFabricLabel + # global group counters (send) + var counter_group_data_snd # counter for group data + var counter_group_ctrl_snd # counter for group command + var _counter_group_data_snd_impl# implementation of counter_group_data_snd by matter.Counter() + var _counter_group_ctrl_snd_impl# implementation of counter_group_ctrl_snd by matter.Counter() + # Admin info extracted from NOC/ICAC + var admin_subject + var admin_vendor + + ############################################################# + def init(store) + import crypto + self._store = store + self._sessions = matter.Expirable_list() + self.fabric_label = "" + self.created = tasmota.rtc()['utc'] + # init group counters + self._counter_group_data_snd_impl = matter.Counter() + self._counter_group_ctrl_snd_impl = matter.Counter() + self.counter_group_data_snd = self._counter_group_data_snd_impl.next() + self._GROUP_SND_INCR + self.counter_group_ctrl_snd = self._counter_group_data_snd_impl.next() + self._GROUP_SND_INCR + end + + def get_noc() return self.noc end + def get_icac() return self.icac end + def get_ipk_epoch_key() return self.ipk_epoch_key end + def get_fabric_id() return self.fabric_id end + def get_device_id() return self.device_id end + def get_fabric_compressed() return self.fabric_compressed end + def get_fabric_label() return self.fabric_label end + def get_admin_subject() return self.admin_subject end + def get_admin_vendor() return self.admin_vendor end + def get_ca() return self.root_ca_certificate end + def get_fabric_index() return self.fabric_index end + + def set_fabric_index(v) self.fabric_index = v end + + ############################################################# + # When hydrating from persistance, update counters + def hydrate_post() + # reset counter_snd to highest known. + # We advance it only in case it is actually used + # This avoids updaing counters on dead sessions + self._counter_group_data_snd_impl.reset(self.counter_group_data_snd) + self._counter_group_ctrl_snd_impl.reset(self.counter_group_ctrl_snd) + self.counter_group_data_snd = self._counter_group_data_snd_impl.val() + self.counter_group_ctrl_snd = self._counter_group_ctrl_snd_impl.val() + end + + ############################################################# + # Management of security counters + ############################################################# + # Provide the next counter value, and update the last know persisted if needed + # + def counter_group_data_snd_next() + import string + var next = self._counter_group_data_snd_impl.next() + tasmota.log(string.format("MTR: . Counter_group_data_snd=%i", next), 3) + if matter.Counter.is_greater(next, self.counter_group_data_snd) + self.counter_group_data_snd = next + self._GROUP_SND_INCR + if self.does_persist() + # the persisted counter is behind the actual counter + self.save() + end + end + return next + end + ############################################################# + # Provide the next counter value, and update the last know persisted if needed + # + def counter_group_ctrl_snd_next() + import string + var next = self._counter_group_ctrl_snd_impl.next() + tasmota.log(string.format("MTR: . Counter_group_ctrl_snd=%i", next), 3) + if matter.Counter.is_greater(next, self.counter_group_ctrl_snd) + self.counter_group_ctrl_snd = next + self._GROUP_SND_INCR + if self.does_persist() + # the persisted counter is behind the actual counter + self.save() + end + end + return next + end + + ############################################################# + # Called before removal + def log_new_fabric() + import string + tasmota.log(string.format("MTR: +Fabric fab='%s'", self.get_fabric_id().copy().reverse().tohex()), 2) + end + + ############################################################# + # Called before removal + def before_remove() + import string + tasmota.log(string.format("MTR: -Fabric fab='%s' (removed)", self.get_fabric_id().copy().reverse().tohex()), 2) + end + + ############################################################# + # Operational Group Key Derivation, 4.15.2, p.182 + def get_ipk_group_key() + if self.ipk_epoch_key == nil || self.fabric_compressed == nil return nil end + import crypto + var hk = crypto.HKDF_SHA256() + var info = bytes().fromstring(self._GROUP_KEY) + var hash = hk.derive(self.ipk_epoch_key, self.fabric_compressed, info, 16) + return hash + end + + def get_ca_pub() + var ca = self.root_ca_certificate + if ca + var m = matter.TLV.parse(ca) + return m.findsubval(9) + end + end + + ############################################################# + # add session to list of persisted sessions + # check for duplicates + def add_session(s) + if self._sessions.find(s) == nil + while size(self._sessions) >= self._MAX_CASE + self._sessions.remove(self._sessions.find(self.get_oldest_session())) + end + self._sessions.push(s) + end + end + + def get_oldest_session() return self.get_old_recent_session(true) end + def get_newest_session() return self.get_old_recent_session(false) end + + # get the oldest or most recent session (oldest indicates direction) + def get_old_recent_session(oldest) + if size(self._sessions) == 0 return nil end + var session = self._sessions[0] + var timestamp = session.last_used + + var idx = 1 + while idx < size(self._sessions) + var time2 = self._sessions[idx].last_used + if (oldest ? time2 < timestamp : time2 > timestamp) + session = self._sessions[idx] + timestamp = time2 + end + idx += 1 + end + return session + end + + ############################################################# + # Fabric::tojson() + # + # convert a single entry as json + # returns a JSON string + ############################################################# + def tojson() + import json + import string + import introspect + + self.persist_pre() + var keys = [] + for k : introspect.members(self) + var v = introspect.get(self, k) + if type(v) != 'function' && k[0] != '_' keys.push(k) end + end + keys = matter.sort(keys) + + var r = [] + for k : keys + var v = introspect.get(self, k) + if v == nil continue end + if isinstance(v, bytes) v = "$$" + v.tob64() end # bytes + r.push(string.format("%s:%s", json.dump(str(k)), json.dump(v))) + end + + # add sessions + var s = [] + for sess : self._sessions.persistables() + s.push(sess.tojson()) + end + if size(s) > 0 + var s_list = "[" + s.concat(",") + "]" + r.push('"_sessions":' + s_list) + end + + self.persist_post() + return "{" + r.concat(",") + "}" + end + + ############################################################# + # fromjson() + # + # reads a map and load arguments + # returns an new instance of fabric + # don't load embedded session, this is done by store + # i.e. ignore any key starting with '_' + ############################################################# + static def fromjson(store, values) + import string + import introspect + var self = matter.Fabric(store) + + for k : values.keys() + if k[0] == '_' continue end # ignore if key starts with '_' + var v = values[k] + # standard values + if type(v) == 'string' + if string.find(v, "0x") == 0 # treat as bytes + introspect.set(self, k, bytes().fromhex(v[2..])) + elif string.find(v, "$$") == 0 # treat as bytes + introspect.set(self, k, bytes().fromb64(v[2..])) + else + introspect.set(self, k, v) + end + else + introspect.set(self, k, v) + end + end + self.hydrate_post() + return self + end + +end +matter.Fabric = Matter_Fabric diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be index e03f17aeb..7e4c49e9b 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be @@ -19,50 +19,21 @@ import matter -#@ solidify:Matter_Response_container,weak #@ solidify:Matter_IM,weak -################################################################################# -# Matter_Response_container -# -# Used to store all the elements of the reponse to an attribute or command -################################################################################# -class Matter_Response_container - var endpoint - var cluster - var attribute - var command - var status - - def tostring() - try - import string - var s = "" - s += (self.endpoint != nil ? string.format("[%02X]", self.endpoint) : "[**]") - s += (self.cluster != nil ? string.format("%04X/", self.cluster) : "****/") - s += (self.attribute != nil ? string.format("%04X", self.attribute) : "") - s += (self.command != nil ? string.format("%04X", self.attribute) : "") - return s - except .. as e, m - return "Exception> " + str(e) + ", " + str(m) - end - end - -end -matter.Response_container = Matter_Response_container - ################################################################################# # Matter_IM class ################################################################################# class Matter_IM - static var MAX_MESSAGE = 1200 - static var MSG_TIMEOUT = 10000 # 10s - var responder var device + var subs_shop # subscriptions shop - def init(responder, device) - self.responder = responder + var send_queue # list of IM_Message queued for sending as part of exchange-id + + def init(device) self.device = device + self.send_queue = [] + self.subs_shop = matter.IM_Subscription_Shop(self) end def process_incoming(msg) @@ -71,27 +42,31 @@ class Matter_IM var val = matter.TLV.parse(msg.raw, msg.app_payload_idx) - tasmota.log("MTR: IM TLV: " + str(val), 3) + # tasmota.log("MTR: IM TLV: " + str(val), 3) var InteractionModelRevision = val.findsubval(0xFF) - tasmota.log("MTR: InteractionModelRevision=" + (InteractionModelRevision != nil ? str(InteractionModelRevision) : "nil"), 3) + # tasmota.log("MTR: InteractionModelRevision=" + (InteractionModelRevision != nil ? str(InteractionModelRevision) : "nil"), 4) var opcode = msg.opcode if opcode == 0x01 # Status Response return self.process_status_response(msg, val) elif opcode == 0x02 # Read Request + self.send_ack_now(msg) return self.process_read_request(msg, val) elif opcode == 0x03 # Subscribe Request + self.send_ack_now(msg) return self.subscribe_request(msg, val) elif opcode == 0x04 # Subscribe Response return self.subscribe_response(msg, val) elif opcode == 0x05 # Report Data return self.report_data(msg, val) elif opcode == 0x06 # Write Request + self.send_ack_now(msg) return self.process_write_request(msg, val) elif opcode == 0x07 # Write Response return self.process_write_response(msg, val) elif opcode == 0x08 # Invoke Request + self.send_ack_now(msg) return self.process_invoke_request(msg, val) elif opcode == 0x09 # Invoke Response return self.process_invoke_response(msg, val) @@ -103,26 +78,133 @@ class Matter_IM end ############################################################# - # process IM 0x01 Status Response + # check whether the ack received is of interest to any + # current exchange # - # val is the TLV structure - # returns `true` if processed, `false` if silently ignored, - # or raises an exception - def process_status_response(msg, val) + # return `true` if handled + def process_incoming_ack(msg) import string - var status = val.findsubval(0, 0xFF) - tasmota.log(string.format("MTR: Status Response = 0x%02X", status), 3) - return true + # check if there is an exchange_id interested in receiving this + var message = self.find_sendqueue_by_exchangeid(msg.exchange_id) + tasmota.log(string.format("MTR: process_incoming_ack exch=%i message=%i", msg.exchange_id, message != nil ? 1 : 0), 3) + if message + return message.ack_received(msg) # dispatch to IM_Message + end + return false end ############################################################# - # process IM 0x02 Read Request + # send Ack response now and don't enqueue it + # + # returns `true` if packet could be sent + def send_ack_now(msg) + msg.session._message_handler.send_encrypted_ack(msg, false #-not reliable-#) + end + + ############################################################# + # send enqueued responses + # + # self.send_queue is a list of + # + def send_enqueued(responder) + var idx = 0 + while idx < size(self.send_queue) + var message = self.send_queue[idx] + + if !message.finish && message.ready + message.send_im(responder) # send message + end + + if message.finish + tasmota.log("MTR: remove IM message exch="+str(message.resp.exchange_id), 3) + self.send_queue.remove(idx) + else + idx += 1 + end + end + end + + ############################################################# + # find in send_queue by exchangeid + # + def find_sendqueue_by_exchangeid(exchangeid) + if exchangeid == nil return nil end + var idx = 0 + while idx < size(self.send_queue) + var message = self.send_queue[idx] + if message.get_exchangeid() == exchangeid + return message + end + idx += 1 + end + return nil + end + + ############################################################# + # find in send_queue by exchangeid + # + def remove_sendqueue_by_exchangeid(exchangeid) + if exchangeid == nil return end + var idx = 0 + while idx < size(self.send_queue) + if self.send_queue[idx].get_exchangeid() == exchangeid + self.send_queue.remove(idx) + else + idx += 1 + end + end + end + + ############################################################# + # Remove any queued message that expired + # + def expire_sendqueue() + var idx = 0 + while idx < size(self.send_queue) + var message = self.send_queue[idx] + if tasmota.time_reached(message.expiration) + message.reached_timeout() + self.send_queue.remove(idx) + else + idx += 1 + end + end + return nil + end + + ############################################################# + # process IM 0x01 Status Response # # val is the TLV structure - # returns `true` if processed, `false` if silently ignored, # or raises an exception - def process_read_request(msg, val) - var endpoints = self.device.get_active_endpoints() + # return true if we handled the response and ack, false instead + def process_status_response(msg, val) + import string + var status = val.findsubval(0, 0xFF) + var message = self.find_sendqueue_by_exchangeid(msg.exchange_id) + if status == matter.SUCCESS + if message + return message.status_ok_received(msg) # re-arm the sending of next packets for the same exchange + else + tasmota.log(string.format("MTR: >OK (%6i) exch=%i not found", msg.session.local_session_id, msg.exchange_id), 3) # don't show 'SUCCESS' to not overflow logs with non-information + end + else + # error + tasmota.log(string.format("MTR: >Status ERROR = 0x%02X", status), 2) + if message + message.status_error_received(msg) + self.remove_sendqueue_by_exchangeid(msg.exchange_id) + end + end + return false # we did not ack the message, do it at higher level + end + + ############################################################# + # Inner code shared between read_attributes and subscribe_request + # + # query: `ReadRequestMessage` or `SubscribeRequestMessage` + def _inner_process_read_request(session, query, no_log) + import string ### Inner function to be iterated upon # ret is the ReportDataMessage list to send back @@ -138,7 +220,7 @@ class Matter_IM attr_name = attr_name ? " (" + attr_name + ")" : "" # tasmota.log(string.format("MTR: Read Attribute " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2) # Special case to report unsupported item, if pi==nil - var res = (pi != nil) ? pi.read_attribute(msg, ctx) : nil + var res = (pi != nil) ? pi.read_attribute(session, ctx) : nil if res != nil var a1 = matter.AttributeReportIB() a1.attribute_data = matter.AttributeDataIB() @@ -150,7 +232,9 @@ class Matter_IM a1.attribute_data.data = res ret.attribute_reports.push(a1) - tasmota.log(string.format("MTR: Read_Attr %s%s - %s", str(ctx), attr_name, str(res)), 2) + if !no_log + tasmota.log(string.format("MTR: >Read_Attr (%6i) %s%s - %s", session.local_session_id, str(ctx), attr_name, str(res)), 2) + end return true # stop expansion since we have a value elif ctx.status != nil if direct @@ -164,105 +248,104 @@ class Matter_IM a1.attribute_status.status.status = ctx.status ret.attribute_reports.push(a1) - tasmota.log(string.format("MTR: Read_Attr %s%s - STATUS: 0x%02X %s", str(ctx), attr_name, ctx.status, ctx.status == matter.UNSUPPORTED_ATTRIBUTE ? "UNSUPPORTED_ATTRIBUTE" : ""), 2) + tasmota.log(string.format("MTR: >Read_Attr (%6i) %s%s - STATUS: 0x%02X %s", session.local_session_id, str(ctx), attr_name, ctx.status, ctx.status == matter.UNSUPPORTED_ATTRIBUTE ? "UNSUPPORTED_ATTRIBUTE" : ""), 2) return true end else - tasmota.log(string.format("MTR: Read_Attr %s%s - IGNORED", str(ctx), attr_name), 2) + tasmota.log(string.format("MTR: >Read_Attr (%6i) %s%s - IGNORED", session.local_session_id, str(ctx), attr_name), 2) # ignore if content is nil and status is undefined + return false end end + var endpoints = self.device.get_active_endpoints() # structure is `ReadRequestMessage` 10.6.2 p.558 - tasmota.log("MTR: IM:read_request processing start", 3) - var ctx = matter.Response_container() + var ctx = matter.Path() - var query = matter.ReadRequestMessage().from_TLV(val) - if query.attributes_requests != nil - # prepare the response - var ret = matter.ReportDataMessage() - # ret.suppress_response = true - ret.attribute_reports = [] + # prepare the response + var ret = matter.ReportDataMessage() + # ret.suppress_response = true + ret.attribute_reports = [] - for q:query.attributes_requests - # need to do expansion here - ctx.endpoint = q.endpoint - ctx.cluster = q.cluster - ctx.attribute = q.attribute - ctx.status = matter.UNSUPPORTED_ATTRIBUTE #default error if returned `nil` - - # expand endpoint - if ctx.endpoint == nil || ctx.cluster == nil || ctx.attribute == nil - # we need expansion, log first - if ctx.cluster != nil && ctx.attribute != nil - var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute) - tasmota.log("MTR: Read_Attr " + str(ctx) + (attr_name ? " (" + attr_name + ")" : ""), 2) - else - tasmota.log("MTR: Read_Attr " + str(ctx), 2) - end - + for q:query.attributes_requests + # need to do expansion here + ctx.endpoint = q.endpoint + ctx.cluster = q.cluster + ctx.attribute = q.attribute + ctx.status = matter.UNSUPPORTED_ATTRIBUTE #default error if returned `nil` + + # expand endpoint + if ctx.endpoint == nil || ctx.cluster == nil || ctx.attribute == nil + # we need expansion, log first + if ctx.cluster != nil && ctx.attribute != nil + var attr_name = matter.get_attribute_name(ctx.cluster, ctx.attribute) + tasmota.log(string.format("MTR: >Read_Attr (%6i) %s", session.local_session_id, str(ctx) + (attr_name ? " (" + attr_name + ")" : "")), 2) + else + tasmota.log(string.format("MTR: >Read_Attr (%6i) %s", session.local_session_id, str(ctx)), 2) end - - # implement concrete expansion - self.device.process_attribute_expansion(ctx, - / pi, ctx, direct -> read_single_attribute(ret, pi, ctx, direct) - ) + end - tasmota.log("MTR: ReportDataMessage=" + str(ret), 3) - tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3) + # implement concrete expansion + self.device.process_attribute_expansion(ctx, + / pi, ctx, direct -> read_single_attribute(ret, pi, ctx, direct) + ) + end - # send the reponse that may need to be chunked if too large to fit in a single UDP message - self.send_attr_report(msg, ret) + # tasmota.log("MTR: ReportDataMessage=" + str(ret), 3) + # tasmota.log("MTR: ReportDataMessageTLV=" + str(ret.to_TLV()), 3) + + return ret + end + + ############################################################# + # process IM 0x02 Read Request + # + # val is the TLV structure + # returns `true` if processed, `false` if silently ignored, + # or raises an exception + def process_read_request(msg, val) + var query = matter.ReadRequestMessage().from_TLV(val) + if query.attributes_requests != nil + var ret = self._inner_process_read_request(msg.session, query) + self.send_report_data(msg, ret) end return true end - def send_attr_report(msg, ret) - # class to keep the current chunked reponse - class Matter_Attr_Report - var ret # return structure as ReportDataMessage TLV structure - var resp # response Frame (to keep all fields like session or remote_ip/port) - var expiration + ############################################################# + # process IM 0x03 Subscribe Request + # + def subscribe_request(msg, val) + import string + var query = matter.SubscribeRequestMessage().from_TLV(val) + + if !query.keep_subscriptions + self.subs_shop.remove_by_session(msg.session) # if `keep_subscriptions`, kill all subscriptions from current session end - # compute the acceptable size + tasmota.log("MTR: received SubscribeRequestMessage=" + str(query), 3) - var msg_sz = 0 - var elements = 0 - if size(ret.attribute_reports) > 0 - msg_sz = size(ret.attribute_reports[0].to_TLV().encode()) - elements = 1 - end - while msg_sz < self.MAX_MESSAGE && elements < size(ret.attribute_reports) - var next_sz = size(ret.attribute_reports[elements].to_TLV().encode()) - if msg_sz + next_sz < self.MAX_MESSAGE - msg_sz += next_sz - elements += 1 - end - end - - var next_elemnts = ret.attribute_reports[elements .. ] - ret.attribute_reports = ret.attribute_reports[0 .. elements - 1] - - if size(next_elemnts) > 0 - ret.more_chunked_messages = true - end - - var resp = msg.build_response(0x05 #-Report Data-#, true) - resp.encode(ret.to_TLV().encode()) # payload in cleartext - resp.encrypt() - self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter) - - if size(next_elemnts) > 0 - ret.attribute_reports = next_elemnts - var chunked_next = Matter_Attr_Report() - chunked_next.ret = ret - chunked_next.resp = resp - chunked_next.expiration = tasmota.millis() + self.MSG_TIMEOUT + var sub = self.subs_shop.new_subscription(msg.session, query) + + # expand a string with all attributes requested + var attr_req = [] + var ctx = matter.Path() + for q:query.attributes_requests + ctx.endpoint = q.endpoint + ctx.cluster = q.cluster + ctx.attribute = q.attribute + attr_req.push(str(ctx)) end + tasmota.log(string.format("MTR: >Subscribe (%6i) %s (min=%i, max=%i, keep=%i) sub=%i", + msg.session.local_session_id, attr_req.concat(" "), sub.min_interval, sub.max_interval, query.keep_subscriptions ? 1 : 0, sub.subscription_id), 2) + var ret = self._inner_process_read_request(msg.session, query, true #-no_log-#) + # ret is of type `Matter_ReportDataMessage` + ret.subscription_id = sub.subscription_id # enrich with subscription id TODO + self.send_subscribe_response(msg, ret, sub) + return true end ############################################################# @@ -274,8 +357,8 @@ class Matter_IM def process_invoke_request(msg, val) import string # structure is `ReadRequestMessage` 10.6.2 p.558 - tasmota.log("MTR: IM:invoke_request processing start", 3) - var ctx = matter.Response_container() + tasmota.log("MTR: IM:invoke_request processing start", 4) + var ctx = matter.Path() var query = matter.InvokeRequestMessage().from_TLV(val) if query.invoke_requests != nil @@ -291,11 +374,22 @@ class Matter_IM ctx.status = matter.UNSUPPORTED_COMMAND #default error if returned `nil` var cmd_name = matter.get_command_name(ctx.cluster, ctx.command) - if cmd_name == nil cmd_name = string.format("0x%04X/0x02X", ctx.cluster, ctx.command) end - tasmota.log(string.format("MTR: >Received_cmd %s from [%s]:%i", cmd_name, msg.remote_ip, msg.remote_port), 2) - var res = self.responder.device.invoke_request(msg, q.command_fields, ctx) + var res = self.device.invoke_request(msg.session, q.command_fields, ctx) + var params_log = (ctx.log != nil) ? "(" + str(ctx.log) + ") " : "" + tasmota.log(string.format("MTR: >Command (%6i) %s %s %s", msg.session.local_session_id, str(ctx), cmd_name ? cmd_name : "", params_log), 2) + ctx.log = nil var a1 = matter.InvokeResponseIB() - if res != nil + if res == true || ctx.status == matter.SUCCESS # special case, just respond ok + a1.status = matter.CommandStatusIB() + a1.status.command_path = matter.CommandPathIB() + a1.status.command_path.endpoint = ctx.endpoint + a1.status.command_path.cluster = ctx.cluster + a1.status.command_path.command = ctx.command + a1.status.status = matter.StatusIB() + a1.status.status.status = matter.SUCCESS + ret.invoke_responses.push(a1) + tasmota.log(string.format("MTR: write_single_attribute(ret, pi, ctx, write_data, direct) + ) + end + + tasmota.log("MTR: ReportWriteMessage=" + str(ret), 4) + tasmota.log("MTR: ReportWriteMessageTLV=" + str(ret.to_TLV()), 3) + + # send the reponse that may need to be chunked if too large to fit in a single UDP message + if !suppress_response + self.send_write_response(msg, ret) + end + end + return true end ############################################################# @@ -387,7 +558,7 @@ class Matter_IM def process_write_response(msg, val) import string var query = matter.WriteResponseMessage().from_TLV(val) - tasmota.log("MTR: received WriteResponseMessage=" + str(query), 3) + tasmota.log("MTR: received WriteResponseMessage=" + str(query), 2) return false end @@ -397,7 +568,7 @@ class Matter_IM def process_invoke_response(msg, val) import string var query = matter.InvokeResponseMessage().from_TLV(val) - tasmota.log("MTR: received InvokeResponseMessage=" + str(query), 3) + tasmota.log("MTR: received InvokeResponseMessage=" + str(query), 2) return false end @@ -409,23 +580,113 @@ class Matter_IM var query = matter.TimedRequestMessage().from_TLV(val) tasmota.log("MTR: received TimedRequestMessage=" + str(query), 3) - tasmota.log(string.format("MTR: >Received_IM TimedRequest=%i from [%s]:%i", query.timeout, msg.remote_ip, msg.remote_port), 2) + tasmota.log(string.format("MTR: >Command (%6i) TimedRequest=%i", msg.session.local_session_id, query.timeout), 2) # Send success status report - var sr = matter.StatusResponseMessage() - sr.status = matter.SUCCESS - var resp = msg.build_response(0x01 #-Status Response-#, true #-reliable-#) - resp.encode(sr.to_TLV().encode()) # payload in cleartext - resp.encrypt() - self.responder.send_response(resp.raw, msg.remote_ip, msg.remote_port, resp.message_counter) + self.send_status(msg, matter.SUCCESS) return true end + ############################################################# + # send regular update for data subscribed + # + def send_subscribe_update(sub) + import string + var session = sub.session + + # create a fake read request to feed to the ReportData + var fake_read = matter.ReadRequestMessage() + fake_read.fabric_filtered = false + fake_read.attributes_requests = [] + + for ctx: sub.updates + var p1 = matter.AttributePathIB() + p1.endpoint = ctx.endpoint + p1.cluster = ctx.cluster + p1.attribute = ctx.attribute + fake_read.attributes_requests.push(p1) + end + + tasmota.log(string.format("MTR: . +# + +import matter + +#@ solidify:Matter_IM_Message,weak +#@ solidify:Matter_IM_Status,weak +#@ solidify:Matter_IM_InvokeResponse,weak +#@ solidify:Matter_IM_WriteResponse,weak +#@ solidify:Matter_IM_ReportData,weak +#@ solidify:Matter_IM_ReportDataSubscribed,weak +#@ solidify:Matter_IM_SubscribedHeartbeat,weak +#@ solidify:Matter_IM_SubscribeResponse,weak + +################################################################################# +# Matter_IM_Message +# +# Superclass for all IM responses +################################################################################# +class Matter_IM_Message + static var MSG_TIMEOUT = 5000 # 5s + var expiration # expiration time for the reporting + var resp # response Frame object + var ready # bool: ready to send (true) or wait (false) + var finish # if true, the message is removed from the queue + var data # TLV data of the response (if any) + var last_counter # counter value of last sent packet (to match ack) + + # build a response message stub + def init(msg, opcode, reliable) + self.resp = msg.build_response(opcode, reliable) + self.ready = true # by default send immediately + self.expiration = tasmota.millis() + self.MSG_TIMEOUT + self.last_counter = 0 # avoid `nil` value + self.finish = false + end + + # the message is being removed due to expiration + def reached_timeout() + end + + # ack received for previous message, proceed to next (if any) + # return true if we manage the ack ourselves, false if it needs to be done upper + def ack_received(msg) + tasmota.log("MTR: IM_Message ack_received exch="+str(self.resp.exchange_id), 3) + self.expiration = tasmota.millis() + self.MSG_TIMEOUT # give more time + return false + end + + # Status Report OK received for previous message, proceed to next (if any) + # return true if we manage the ack ourselves, false if it needs to be done upper + def status_ok_received(msg) + import string + tasmota.log(string.format("MTR: IM_Message status_ok_received exch=%i", self.resp.exchange_id), 3) + self.expiration = tasmota.millis() + self.MSG_TIMEOUT # give more time + if msg + self.resp = msg.build_response(self.resp.opcode, self.resp.x_flag_r, self.resp) # update packet + end + self.ready = true + return true + end + + # we received an ACK error, do any necessary cleaning + def status_error_received(msg) + end + + # get the exchange-id for this message + def get_exchangeid() + return self.resp.exchange_id + end + + # default responder for data + def send_im(responder) + import string + tasmota.log(string.format("MTR: IM_Message send_im exch=%i ready=%i", self.resp.exchange_id, self.ready ? 1 : 0), 3) + if !self.ready return false end + var resp = self.resp + resp.encode_frame(self.data.to_TLV().tlv2raw()) # payload in cleartext + resp.encrypt() + tasmota.log(string.format("MTR: 0 + msg_sz = data.attribute_reports[0].to_TLV().encode_len() + elements = 1 + end + while msg_sz < self.MAX_MESSAGE && elements < sz_attribute_reports + var next_sz = data.attribute_reports[elements].to_TLV().encode_len() + if msg_sz + next_sz < self.MAX_MESSAGE + msg_sz += next_sz + elements += 1 + else + break + end + end + + tasmota.log(string.format("MTR: exch=%i elements=%i msg_sz=%i total=%i", self.get_exchangeid(), elements, msg_sz, sz_attribute_reports), 3) + var next_elemnts = [] + if data.attribute_reports != nil + next_elemnts = data.attribute_reports[elements .. ] + data.attribute_reports = data.attribute_reports[0 .. elements - 1] + data.more_chunked_messages = (size(next_elemnts) > 0) + else + data.more_chunked_messages = false + end + + if was_chunked + tasmota.log(string.format("MTR: .Read_Attr next_chunk exch=%i", self.get_exchangeid()), 3) + end + if data.more_chunked_messages + if !was_chunked + tasmota.log(string.format("MTR: .Read_Attr first_chunk exch=%i", self.get_exchangeid()), 3) + end + # tasmota.log("MTR: sending TLV" + str(data), 4) + end + + # print(">>>>> send elements before encode") + var raw_tlv = self.data.to_TLV() + # print(">>>>> send elements before encode 2") + var encoded_tlv = raw_tlv.tlv2raw(bytes(self.MAX_MESSAGE)) # takes time + # print(">>>>> send elements before encode 3") + resp.encode_frame(encoded_tlv) # payload in cleartext, pre-allocate max buffer + # print(">>>>> send elements after encode") + resp.encrypt() + # print(">>>>> send elements after encrypt") + tasmota.log(string.format("MTR: 0 + data.attribute_reports = next_elemnts + tasmota.log(string.format("MTR: to_be_sent_later size=%i exch=%i", size(data.attribute_reports), resp.exchange_id), 3) + self.ready = false # wait for Status Report before continuing sending + # keep alive + else + self.finish = true # finished, remove + end + end + +end +matter.IM_ReportData = Matter_IM_ReportData + + +################################################################################# +# Matter_IM_ReportDataSubscribed +# +# Main difference is that we are the spontaneous initiator +################################################################################# +class Matter_IM_ReportDataSubscribed : Matter_IM_ReportData + var sub # subscription object + var report_data_phase # true during reportdata + + def init(message_handler, session, data, sub) + self.resp = matter.Frame.initiate_response(message_handler, session, 0x05 #-Report Data-#, true) + self.data = data + self.ready = true # by default send immediately + self.expiration = tasmota.millis() + self.MSG_TIMEOUT + # + self.sub = sub + self.report_data_phase = true + end + + def reached_timeout() + self.sub.remove_self() + end + + # ack received, confirm the heartbeat + def ack_received(msg) + import string + tasmota.log(string.format("MTR: IM_ReportDataSubscribed ack_received sub=%i", self.sub.subscription_id), 3) + super(self).ack_received(msg) + if !self.report_data_phase + # if ack is received while all data is sent, means that it finished without error + if self.sub.is_keep_alive # only if keep-alive, for normal reports, re_arm is called at last StatusReport + self.sub.re_arm() # signal that we can proceed to next sub report + end + return true # proceed to calling send() which removes the message + else + return false # do nothing + end + end + + # we received an ACK error, remove subscription + def status_error_received(msg) + import string + tasmota.log(string.format("MTR: IM_ReportDataSubscribed status_error_received sub=%i exch=%i", self.sub.subscription_id, self.resp.exchange_id), 3) + self.sub.remove_self() + end + + # ack received for previous message, proceed to next (if any) + # return true if we manage the ack ourselves, false if it needs to be done upper + def status_ok_received(msg) + import string + tasmota.log(string.format("MTR: IM_ReportDataSubscribed status_ok_received sub=%i exch=%i", self.sub.subscription_id, self.resp.exchange_id), 3) + if self.report_data_phase + return super(self).status_ok_received(msg) + else + self.sub.re_arm() # always re_arm at last StatusReport. The only case where it does not happen is during keep-alive, hence we need to lookg for Ack (see above) + super(self).status_ok_received(nil) + return false # let the caller to the ack + end + end + + # returns true if transaction is complete (remove object from queue) + # default responder for data + def send_im(responder) + import string + tasmota.log(string.format("MTR: IM_ReportDataSubscribed send sub=%i exch=%i ready=%i", self.sub.subscription_id, self.resp.exchange_id, self.ready ? 1 : 0), 3) + tasmota.log(string.format("MTR: ReportDataSubscribed::send_im size(self.data.attribute_reports)=%i ready=%s report_data_phase=%s", size(self.data.attribute_reports), str(self.ready), str(self.report_data_phase)), 3) + if !self.ready return false end + if size(self.data.attribute_reports) > 0 # do we have still attributes to send + if self.report_data_phase + super(self).send_im(responder) + tasmota.log(string.format("MTR: ReportDataSubscribed::send_im called super finish=%i", self.finish), 3) + if !self.finish return end # ReportData needs to continue + # ReportData is finished + self.report_data_phase = false + self.ready = false + self.finish = false # while a ReadReport would stop here, we continue for subscription + else + # send a simple ACK + var resp = self.resp.build_standalone_ack(false) + resp.encode_frame() + resp.encrypt() + tasmota.log(string.format("MTR: Sub_OK (%6i) sub=%i", msg.session.local_session_id, self.sub.subscription_id), 2) + return super(self).status_ok_received(msg) + end + +end +matter.IM_SubscribeResponse = Matter_IM_SubscribeResponse diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM_Subscription.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Subscription.be new file mode 100644 index 000000000..0f526d987 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM_Subscription.be @@ -0,0 +1,254 @@ +# +# Matter_IM_Subscription.be - suppport for Matter Interaction Model subscriptions +# +# 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 + +#@ solidify:Matter_IM_Subscription,weak +#@ solidify:Matter_IM_Subscription_Shop,weak + +################################################################################# +# Matter_IM_Subscription +# +# Individual subscription instance +################################################################################# +class Matter_IM_Subscription + static var MAX_INTERVAL_MARGIN = 5 # we always keep 5s margin + var subs_shop # pointer to sub shop + # parameters of the subscription + var subscription_id # id of the subcription as known by requester + var session # the session it belongs to + var path_list # list of path subscibed to + var min_interval # never send data more often than every `min_interval` seconds + var max_interval # always send data before `max_interal` seconds or the subscription is lost + var fabric_filtered + # manage time + var not_before # rate-limiting + var expiration # expiration epoch, we need to respond before + var wait_status # if `true` wait for Status Response before sending anything new + var is_keep_alive # was the last message sent an empty keep-alive + # updates + var updates + + # req: SubscribeRequestMessage + def init(subs_shop, id, session, req) + self.subs_shop = subs_shop + self.subscription_id = id + self.session = session + # check values for min_interval + var min_interval = req.min_interval_floor + if min_interval < 0 min_interval = 0 end + if min_interval > 60 min_interval = 60 end + self.min_interval = min_interval + # check values for max_interval + var max_interval = req.max_interval_ceiling + if max_interval < 60 max_interval = 60 end + if max_interval > 3600 max_interval = 3600 end + max_interval = 60 + self.max_interval = max_interval + self.wait_status = false + + self.fabric_filtered = req.fabric_filtered + + # get list of path from + self.path_list = [] + + for q: req.attributes_requests + var ctx = matter.Path() + ctx.endpoint = q.endpoint + ctx.cluster = q.cluster + ctx.attribute = q.attribute + self.path_list.push(ctx) + end + + # update next time interval + self.updates = [] + self.clear_before_arm() + self.is_keep_alive = false + + # tasmota.log("MTR: new subsctiption " + matter.inspect(self), 3) + end + + # remove self from subs_shop list + def remove_self() + tasmota.log("MTR: -Sub_Del ( ) sub=" + str(self.subscription_id), 2) + self.subs_shop.remove_sub(self) + end + + # clear log after it was sent, and re-arm next expiration + def clear_before_arm() + self.updates.clear() + self.wait_status = true + end + + # we received a complete ack for previous message, rearm + def re_arm() + import string + self.wait_status = false + var now = tasmota.millis() + self.expiration = now + (self.max_interval - self.MAX_INTERVAL_MARGIN) * 1000 + self.not_before = now + self.min_interval * 1000 - 1 + if !self.is_keep_alive + tasmota.log(string.format("MTR: .Sub_Done ( ) sub=%i", self.subscription_id), 2) + end + end + + # signal that an attribute was updated, to add to the list of reportable + def attribute_updated_ctx(ctx, fabric_specific) + var idx = 0 + while idx < size(self.path_list) + var filter = self.path_list[idx] + if (filter.endpoint == nil || filter.endpoint == ctx.endpoint) && + (filter.cluster == nil || filter.cluster == ctx.cluster) && + (filter.attribute == nil || filter.attribute == ctx.attribute) + + # ready to push the new attribute, check that it + self._add_attribute_unique_path(ctx) + end + idx += 1 + end + end + + # add an attribute path for an updated attribute, remove any duplicate + def _add_attribute_unique_path(ctx) + var idx = 0 + while idx < size(self.updates) + var path = self.updates[idx] + if path.endpoint == ctx.endpoint && + path.cluster == ctx.cluster && + path.attribute == ctx.attribute + return # already exists in the list, abort + end + idx += 1 + end + self.updates.push(ctx) + end + +end +matter.IM_Subscription = Matter_IM_Subscription + +################################################################################# +# Matter_IM_Subscription_Shop (monad) +# +# Handles all subscriptions +################################################################################# +class Matter_IM_Subscription_Shop + var subs # list of subscriptions + var im # pointer to parent `im` object + + def init(im) + self.im = im + self.subs = [] + end + + ############################################################# + # create a new subscription + # + # session object + # SubscribeRequestMessage request + # returns: new subscription + def new_subscription(session, req) + import crypto + var id = crypto.random(2).get(0,2) + while self.get_by_id(id) + id = crypto.random(2).get(0,2) + end + + var sub = matter.IM_Subscription(self, id, session, req) + self.subs.push(sub) + + return sub + end + + def remove_sub(sub) + var idx = 0 + while idx < size(self.subs) + if self.subs[idx] == sub + self.subs.remove(idx) + else + idx += 1 + end + end + end + + def get_by_id(id) + var idx = 0 + while idx < size(self.subs) + if self.subs[idx].subscription_id == id + return self.subs[idx] + end + idx += 1 + end + end + + def remove_by_session(session) + var idx = 0 + while idx < size(self.subs) + if self.subs[idx].session == session + self.subs.remove(idx) + else + idx += 1 + end + end + end + + def remove_by_fabric(fabric) + for session: fabric._sessions + self.remove_by_session(session) + end + end + + ############################################################# + # dispatch every 250ms click to sub-objects that need it + def every_250ms() + # any data ready to send? + var idx = 0 + while idx < size(self.subs) + var sub = self.subs[idx] + if !sub.wait_status && size(sub.updates) > 0 && tasmota.time_reached(sub.not_before) + self.im.send_subscribe_update(sub) + sub.clear_before_arm() + end + idx += 1 + end + + # any heartbeat needing to be sent + idx = 0 + while idx < size(self.subs) + var sub = self.subs[idx] + if !sub.wait_status && tasmota.time_reached(sub.expiration) + self.im.send_subscribe_heartbeat(sub) + sub.clear_before_arm() + sub.re_arm() # signal that we can proceed to next sub report + end + idx += 1 + end + end + + # signal that an attribute was updated, to add to the list of reportable + def attribute_updated_ctx(ctx, fabric_specific) + # signal any relevant subscription + var idx = 0 + while idx < size(self.subs) + self.subs[idx].attribute_updated_ctx(ctx, fabric_specific) + idx += 1 + end + end + +end +matter.IM_Subscription_Shop = Matter_IM_Subscription_Shop diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be index 8ca41200b..d127d1a1c 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Message.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Message.be @@ -52,7 +52,7 @@ class Matter_Frame var x_flag_a var x_flag_i var opcode - var exchange_id + var exchange_id # exchange_id is 16 bits unsigned, we set bit 16 if it's an id generated locally var protocol_id var vendor_id # (opt) var ack_message_counter # (opt) @@ -140,6 +140,7 @@ class Matter_Frame self.opcode = raw.get(idx+1, 1) self.exchange_id = raw.get(idx+2, 2) + if !self.x_flag_i self.exchange_id |= 0x10000 end # special encoding for local exchange_id self.protocol_id = raw.get(idx+4, 2) idx += 6 @@ -170,7 +171,7 @@ class Matter_Frame # # Header is built from attributes # `payload` is a bytes() buffer for the app payload - def encode(payload) + def encode_frame(payload) var raw = bytes() # compute flags if self.flags == nil @@ -210,7 +211,7 @@ class Matter_Frame raw.add(self.x_flags, 1) # opcode (mandatory) raw.add(self.opcode, 1) - raw.add(self.exchange_id, 2) + raw.add(self.exchange_id & 0xFFFF, 2) raw.add(self.protocol_id, 2) if self.x_flag_a raw.add(self.ack_message_counter, 4) end # finally payload @@ -227,38 +228,7 @@ class Matter_Frame ############################################################# # Generate a Standalone Acknowledgment # Uses `PROTOCOL_ID_SECURE_CHANNEL` no ecnryption required - def build_standalone_ack() - import string - # send back response - var resp = classof(self)(self.message_handler) - - if self.flag_s - resp.flag_dsiz = 0x01 - resp.dest_node_id_8 = self.source_node_id - else - resp.flag_dsiz = 0x00 - end - resp.session = self.session # also copy the session object - # message counter - resp.message_counter = self.session.counter_snd.next() - resp.local_session_id = self.session.initiator_session_id - - resp.x_flag_i = 0 # not sent by initiator - resp.opcode = 0x10 # MRP Standalone Acknowledgement - resp.exchange_id = self.exchange_id - resp.protocol_id = 0 # PROTOCOL_ID_SECURE_CHANNEL - resp.x_flag_a = 1 # ACK of previous message - resp.ack_message_counter = self.message_counter - resp.x_flag_r = 0 - - tasmota.log(string.format("MTR: >>>>>>>>>>>>>>>>>>> Compute Privacy TODO", 2) var k = session.get_i2r_privacy() var n = bytes().add(self.local_session_id, -2) + mic[5..15] # session in Big Endian var m = self.raw[4 .. self.payload_idx-1] @@ -340,25 +383,25 @@ class Matter_Frame n.resize(13) # add zeros end - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: i2r =" + i2r.tohex(), 3) - tasmota.log("MTR: p =" + p.tohex(), 3) - tasmota.log("MTR: a =" + a.tohex(), 3) - tasmota.log("MTR: n =" + n.tohex(), 3) - tasmota.log("MTR: mic =" + mic.tohex(), 3) + tasmota.log("MTR: ******************************", 4) + tasmota.log("MTR: i2r =" + i2r.tohex(), 4) + tasmota.log("MTR: p =" + p.tohex(), 4) + tasmota.log("MTR: a =" + a.tohex(), 4) + tasmota.log("MTR: n =" + n.tohex(), 4) + tasmota.log("MTR: mic =" + mic.tohex(), 4) # decrypt var aes = crypto.AES_CCM(i2r, n, a, size(p), 16) var cleartext = aes.decrypt(p) var tag = aes.tag() - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: cleartext =" + cleartext.tohex(), 3) - tasmota.log("MTR: tag =" + tag.tohex(), 3) - tasmota.log("MTR: ******************************", 3) + tasmota.log("MTR: ******************************", 4) + tasmota.log("MTR: cleartext =" + cleartext.tohex(), 4) + tasmota.log("MTR: tag =" + tag.tohex(), 4) + tasmota.log("MTR: ******************************", 4) if tag != mic - tasmota.log("MTR: rejected packet due to invalid MIC", 3) + tasmota.log("MTR: rejected packet due to invalid MIC", 2) return nil end @@ -384,35 +427,35 @@ class Matter_Frame var n = bytes() n.add(self.flags, 1) n.add(self.message_counter, 4) - if session.get_mode() == session.__CASE && session.deviceid - n .. session.deviceid + if session.is_CASE() && session.get_device_id() + n .. session.get_device_id() end n.resize(13) # add zeros - tasmota.log("MTR: cleartext: " + self.raw.tohex(), 3) + # tasmota.log("MTR: cleartext: " + self.raw.tohex(), 4) - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: r2i =" + r2i.tohex(), 3) - tasmota.log("MTR: p =" + p.tohex(), 3) - tasmota.log("MTR: a =" + a.tohex(), 3) - tasmota.log("MTR: n =" + n.tohex(), 3) + # tasmota.log("MTR: ******************************", 4) + # tasmota.log("MTR: r2i =" + r2i.tohex(), 4) + # tasmota.log("MTR: p =" + p.tohex(), 4) + # tasmota.log("MTR: a =" + a.tohex(), 4) + # tasmota.log("MTR: n =" + n.tohex(), 4) # decrypt var aes = crypto.AES_CCM(r2i, n, a, size(p), 16) var ciphertext = aes.encrypt(p) var tag = aes.tag() - tasmota.log("MTR: ******************************", 3) - tasmota.log("MTR: ciphertext =" + ciphertext.tohex(), 3) - tasmota.log("MTR: tag =" + tag.tohex(), 3) - tasmota.log("MTR: ******************************", 3) + # tasmota.log("MTR: ******************************", 4) + # tasmota.log("MTR: ciphertext =" + ciphertext.tohex(), 4) + # tasmota.log("MTR: tag =" + tag.tohex(), 4) + # tasmota.log("MTR: ******************************", 4) # packet is good, put back content in raw self.raw.resize(self.payload_idx) # remove cleartext payload self.raw .. ciphertext # add ciphertext self.raw .. tag # add MIC - # tasmota.log("MTR: encrypted: " + self.raw.tohex(), 3) + # tasmota.log("MTR: encrypted: " + self.raw.tohex(), 4) end ############################################################# @@ -421,7 +464,7 @@ class Matter_Frame var r = matter.Frame(self.message_handler, raw) r.decode_header() r.decode_payload() - tasmota.log("MTR: sending decode: " + matter.inspect(r), 3) + tasmota.log("MTR: sending decode: " + matter.inspect(r), 4) end end matter.Frame = Matter_Frame diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be b/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be index 4da3c5668..fb16f9795 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_MessageHandler.be @@ -26,17 +26,47 @@ class Matter_MessageHandler var device # `tansport.msg_send(raw:bytes() [,...]) -> bool` true if succeeded # handlers - var commissioning - var im # handler for Interaction Model - # counters - var counter_rcv # Global Unencrypted Message Counter incoming + var commissioning # Commissioning Context instance, handling the PASE/CASE phases + var im # Instance of `matter.IM` handling Interaction Model + var control_message # Instance of `matter.Control_Message` for MCSP ############################################################# def init(device) self.device = device self.commissioning = matter.Commisioning_Context(self) - self.im = matter.IM(self, device) - self.counter_rcv = matter.Counter() + self.im = matter.IM(device) + self.control_message = matter.Control_Message(self) + end + + ############################################################# + # Send a unencrypted Ack if needed + # + # reliable: do we send as reliable message + # + def send_simple_ack(frame, reliable) + import string + if frame.x_flag_r # nothing to respond, check if we need a standalone ack + var resp = frame.build_standalone_ack(reliable) + resp.encode_frame() + tasmota.log(string.format("MTR: Received %s from [%s]:%i", op_name, addr, port), 2) + tasmota.log(string.format("MTR: >Received (%6i) %s rid=%i exch=%i from [%s]:%i", session.local_session_id, op_name, frame.message_counter, frame.exchange_id, addr, port), 2) + else + tasmota.log(string.format("MTR: >rcv Ack (%6i) rid=%i exch=%i ack=%s %sfrom [%s]:%i", session.local_session_id, frame.message_counter, frame.x_flag_r ? "{reliable} " : "", frame.exchange_id, str(frame.ack_message_counter), addr, port), 3) end - self.commissioning.process_incoming(frame, addr, port) + ret = self.commissioning.process_incoming(frame) + # if ret is false, the implicit Ack was not sent + if !ret self.send_simple_ack(frame, false #-not reliable-#) end return true else ############################################################# @@ -84,15 +130,19 @@ class Matter_MessageHandler var session = self.device.sessions.get_session_by_local_session_id(frame.local_session_id) if session == nil - tasmota.log("MTR: unknown local_session_id "+str(frame.local_session_id), 3) - tasmota.log("MTR: frame="+matter.inspect(frame), 3) + tasmota.log("MTR: unknown local_session_id="+str(frame.local_session_id), 2) + # tasmota.log("MTR: frame="+matter.inspect(frame), 3) return false end + if addr session._ip = addr end + if port session._port = port end + session._message_handler = self frame.session = session # keep a pointer of the session in the message # check if it's a duplicate - if !session.counter_rcv.validate(frame.message_counter, true) - tasmota.log("MTR: rejected duplicate encrypted message = " + str(frame.message_counter) + " counter=" + str(session.counter_rcv.val()), 3) + if !session.counter_rcv_validate(frame.message_counter, true) + tasmota.log("MTR: . Duplicate encrypted message = " + str(frame.message_counter) + " counter=" + str(session.counter_rcv), 3) + self.send_encrypted_ack(frame, false #-not reliable-#) return false end @@ -104,23 +154,37 @@ class Matter_MessageHandler frame.raw .. cleartext # add cleartext # continue decoding - tasmota.log(string.format("MTR: idx=%i clear=%s", frame.payload_idx, frame.raw.tohex()), 3) + tasmota.log(string.format("MTR: idx=%i clear=%s", frame.payload_idx, frame.raw.tohex()), 4) frame.decode_payload() - tasmota.log("MTR: decrypted message: protocol_id:"+str(frame.protocol_id)+" opcode="+str(frame.opcode)+" exchange_id"+str(frame.exchange_id), 3) + tasmota.log("MTR: > Decrypted message: protocol_id:"+str(frame.protocol_id)+" opcode="+str(frame.opcode)+" exchange_id="+str(frame.exchange_id & 0xFFFF), 3) - self.device.packet_ack(frame.ack_message_counter) # acknowledge packet + tasmota.log(string.format("MTR: >rcv (%6i) [%02X/%02X] rid=%i exch=%i ack=%s %sfrom [%s]:%i", session.local_session_id, frame.protocol_id, frame.opcode, frame.message_counter, frame.exchange_id, str(frame.ack_message_counter), frame.x_flag_r ? "{reliable} " : "", addr, port), 3) + + self.device.received_ack(frame) # remove acknowledge packet from sending list # dispatch according to protocol_id var protocol_id = frame.protocol_id if protocol_id == 0x0000 # PROTOCOL_ID_SECURE_CHANNEL # it should not be encrypted tasmota.log("MTR: PROTOCOL_ID_SECURE_CHANNEL " + matter.inspect(frame), 3) - # if frame.opcode == 0x10 - # end - return true + if frame.opcode == 0x10 # MRPStandaloneAcknowledgement + ret = self.im.process_incoming_ack(frame) + if ret + self.im.send_enqueued(self) + end + end + ret = true elif protocol_id == 0x0001 # PROTOCOL_ID_INTERACTION_MODEL # dispatch to IM Protocol Messages - return self.im.process_incoming(frame, addr, port) + ret = self.im.process_incoming(frame) + # if `ret` is true, we have something to send + if ret + self.im.send_enqueued(self) + + else + self.send_encrypted_ack(frame, true #-reliable-#) + end + ret = true # -- PROTOCOL_ID_BDX is used for file transfer between devices, not used in Tasmota # elif protocol_id == 0x0002 # PROTOCOL_ID_BDX -- BDX not handled at all in Tasmota @@ -132,12 +196,11 @@ class Matter_MessageHandler # return false # ignore for now TODO else tasmota.log("MTR: ignoring unhandled protocol_id:"+str(protocol_id), 3) - return false end end - return true + return ret except .. as e, m tasmota.log("MTR: MessageHandler::msg_received exception: "+str(e)+";"+str(m)) import debug @@ -147,18 +210,18 @@ class Matter_MessageHandler end ############################################################# - def send_response(raw, addr, port, id) - self.device.msg_send(raw, addr, port, id) - end - - ############################################################# - def add_session(local_session_id, initiator_session_id, i2r, r2i, ac, session_timestamp) - import string - # create session object - tasmota.log(string.format("MTR: add_session local_session_id=%i initiator_session_id=%i", local_session_id, initiator_session_id), 3) - - var session = self.device.sessions.create_session(local_session_id, initiator_session_id) - session.set_keys(i2r, r2i, ac, session_timestamp) + # send a frame to target, usually a response + # + # We need the following: + # msg.raw: raw bytes to send (bytes) + # msg.remote_ip: ip address of target (string) + # msg.remote_port: port of target (int) + # msg.x_flag_r: is the frame expecting a Ack back (int) + # msg.message_counter: counter for this message (int) + # msg.exchange_id: exchange id (int) + # msg.local_session_id: local session (for logging) + def send_response_frame(msg) + self.device.msg_send(msg) end ############################################################# @@ -167,5 +230,12 @@ class Matter_MessageHandler self.commissioning.every_second() self.im.every_second() end + + ############################################################# + # dispatch every 250ms click to sub-objects that need it + def every_250ms() + self.im.every_250ms() + end + end matter.MessageHandler = Matter_MessageHandler diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Path.be b/lib/libesp32/berry_matter/src/embedded/Matter_Path.be new file mode 100644 index 000000000..fe04be0aa --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Path.be @@ -0,0 +1,53 @@ +# +# Matter_IM_Path.be - suppport for Matter simple Path object +# +# 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 + +#@ solidify:Matter_Path,weak + +################################################################################# +# Matter_Path +# +# Used to store all the elements of the reponse to an attribute or command +################################################################################# +class Matter_Path + var endpoint # endpoint or `nil` if expansion + var cluster # cluster or `nil` if expansion + var attribute # attribute or `nil` if expansion + var command # command + var status # status to be returned (matter.SUCCESS or matter.) + var log # any string that needs to be logged (used to show significant parameters for commands) + + def tostring() + try + import string + var s = "" + s += (self.endpoint != nil ? string.format("[%02X]", self.endpoint) : "[**]") + s += (self.cluster != nil ? string.format("%04X/", self.cluster) : "****/") + s += (self.attribute != nil ? string.format("%04X", self.attribute) : "") + s += (self.command != nil ? string.format("%04X", self.command) : "") + if self.attribute == nil && self.command == nil s += "****" end + return s + except .. as e, m + return "Exception> " + str(e) + ", " + str(m) + end + end + +end +matter.Path = Matter_Path diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be index d66ecbe92..60cfe112b 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be @@ -23,27 +23,72 @@ #@ solidify:Matter_Plugin,weak class Matter_Plugin - static var EMPTY_LIST = [] - static var EMPTY_MAP = {} + static var CLUSTERS = { + 0x001D: [0,1,2,3,0xFFFC,0xFFFD], # Descriptor Cluster 9.5 p.453 + } var device # reference to the `device` global object - var endpoints # list of supported endpoints - var clusters # map from cluster to list of attributes + var endpoint # current endpoint + var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy + + ############################################################# + # MVC Model + # + # Model linking the plugin to the Tasmota behavior + ############################################################# ############################################################# # Constructor - def init(device) + # + def init(device, endpoint) self.device = device - self.endpoints = self.EMPTY_LIST - self.clusters = self.EMPTY_LIST + self.endpoint = endpoint + self.clusters = self.consolidate_clusters() + end + + ############################################################# + # Stub for updating shadow values (local copies of what we published to the Matter gateway) + def update_shadow() + end + + ############################################################# + # signal that an attribute has been changed + # + # If `endpoint` is `nil`, send to all endpoints + def attribute_updated(endpoint, cluster, attribute, fabric_specific) + if endpoint == nil endpoint = self.endpoint end + self.device.attribute_updated(endpoint, cluster, attribute, fabric_specific) + end + + ############################################################# + # consolidate_clusters + # + # 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 + + o = real_super(o) + end + return ret end ############################################################# # Which endpoints does it handle (list of numbers) - def get_endpoints() - return self.endpoints - end - def get_cluster_map() - return self.clusters + def get_endpoint() + return self.endpoint end def get_cluster_list(ep) var ret = [] @@ -53,7 +98,7 @@ class Matter_Plugin return ret end def get_attribute_list(ep, cluster) - return self.clusters.find(cluster, self.EMPTY_LIST) + return self.clusters.find(cluster, []) end ############################################################# @@ -62,50 +107,114 @@ class Matter_Plugin return self.clusters.contains(cluster) && self.endpoints.find(endpoint) != nil end + ############################################################# + # MVC Model + # + # View reading attributes + ############################################################# ############################################################# # read attribute - def read_attribute(msg, ctx) - return nil + def read_attribute(session, ctx) + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + if cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ========== + + if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ---------- + var dtl = TLV.Matter_TLV_array() + for dt: self.TYPES.keys() + var d1 = dtl.add_struct() + d1.add_TLV(0, TLV.U2, dt) # DeviceType + d1.add_TLV(1, TLV.U2, self.TYPES[dt]) # Revision + end + return dtl + elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ---------- + var sl = TLV.Matter_TLV_array() + for cl: self.get_cluster_list() + sl.add_TLV(nil, TLV.U4, cl) + end + return sl + elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ---------- + var cl = TLV.Matter_TLV_array() + return cl + elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]---------- + var pl = TLV.Matter_TLV_array() + return pl + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 1) # "Initial Release" + end + + else + return nil + end end ############################################################# # read event # TODO - def read_event(msg, endpoint, cluster, eventid) + def read_event(session, endpoint, cluster, eventid) return nil end ############################################################# # subscribe attribute # TODO - def subscribe_attribute(msg, endpoint, cluster, attribute) + def subscribe_attribute(session, endpoint, cluster, attribute) return nil end ############################################################# # subscribe event # TODO - def subscribe_event(msg, endpoint, cluster, eventid) + def subscribe_event(session, endpoint, cluster, eventid) return nil end + ############################################################# + # MVC Model + # + # Controller write attributes + ############################################################# ############################################################# # write attribute - def write_attribute(msg, endpoint, cluster, attribute) + def write_attribute(session, ctx, write_data) return nil end + ############################################################# + # MVC Model + # + # Controller invoke request + ############################################################# ############################################################# # invoke command - def invoke_request(msg, val, ctx) + def invoke_request(session, val, ctx) return nil end ############################################################# # timed request # TODO - should we even support this? - def timed_request(msg, val, ctx) + def timed_request(session, val, ctx) return nil end + + ############################################################# + # parse sensor + # + # The device calls regularly `tasmota.read_sensors()` and converts + # it to json. + def parse_sensors(payload) + end + + ############################################################# + # every_second + def every_second() + self.update_shadow() # force reading value and sending subscriptions + end end + matter.Plugin = Matter_Plugin diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Device.be new file mode 100644 index 000000000..864b536bf --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Device.be @@ -0,0 +1,114 @@ +# +# Matter_Plugin_Device.be - implements the behavior for a standard Device +# +# 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 . +# + +# dummy declaration for solidification +class Matter_Plugin end + +#@ solidify:Matter_Plugin_Device,weak + +class Matter_Plugin_Device : Matter_Plugin + static var CLUSTERS = { + # 0x001D: inherited # Descriptor Cluster 9.5 p.453 + 0x0003: [0,1,0xFFFC,0xFFFD], # Identify 1.2 p.16 + 0x0004: [0,0xFFFC,0xFFFD], # Groups 1.3 p.21 + } + static var TYPES = { 0x0000: 0 } # fake type + + ############################################################# + # Constructor + def init(device, endpoint, tasmota_relay_index) + super(self).init(device, endpoint) + end + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0003 # ========== Identify 1.2 p.16 ========== + if attribute == 0x0000 # ---------- IdentifyTime / u2 ---------- + return TLV.create_TLV(TLV.U2, 0) # no identification in progress + elif attribute == 0x0001 # ---------- IdentifyType / enum8 ---------- + return TLV.create_TLV(TLV.U1, 0) # IdentifyType = 0x00 None + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # no features + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # "new data model format and notation" + end + + # ==================================================================================================== + elif cluster == 0x0004 # ========== Groups 1.3 p.21 ========== + if attribute == 0x0000 # ---------- ---------- + return nil # TODO + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0)# + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4)# "new data model format and notation" + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(session, val, ctx) + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + + # ==================================================================================================== + if cluster == 0x0003 # ========== Identify 1.2 p.16 ========== + + if command == 0x0000 # ---------- Identify ---------- + # ignore + return true + elif command == 0x0001 # ---------- IdentifyQuery ---------- + # create IdentifyQueryResponse + # ID=1 + # 0=Certificate (octstr) + var iqr = TLV.Matter_TLV_struct() + iqr.add_TLV(0, TLV.U2, 0) # Timeout + ctx.command = 0x00 # IdentifyQueryResponse + return iqr + elif command == 0x0040 # ---------- TriggerEffect ---------- + # ignore + return true + end + # ==================================================================================================== + elif cluster == 0x0004 # ========== Groups 1.3 p.21 ========== + # TODO + return true + + else + return super(self).invoke_request(session, val, ctx) + end + end + +end +matter.Plugin_Device = Matter_Plugin_Device diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light0.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light0.be new file mode 100644 index 000000000..37d9dff38 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light0.be @@ -0,0 +1,166 @@ +# +# Matter_Plugin_Light0.be - implements the behavior for a generic Lighting (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 . +# + +# Matter plug-in for core behavior + +# dummy declaration for solidification +class Matter_Plugin end + +#@ solidify:Matter_Plugin_Light0,weak + +class Matter_Plugin_Light0 : Matter_Plugin + static var CLUSTERS = { + # 0x001D: inherited # Descriptor Cluster 9.5 p.453 + 0x0003: [0,1,0xFFFC,0xFFFD], # Identify 1.2 p.16 + 0x0004: [0,0xFFFC,0xFFFD], # Groups 1.3 p.21 + 0x0005: [0,1,2,3,4,5,0xFFFC,0xFFFD], # 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 shadow_onoff + + ############################################################# + # Constructor + def init(device, endpoint) + super(self).init(device, endpoint) + self.shadow_onoff = false + end + + ############################################################# + # Update shadow + # + def update_shadow() + import light + var light_status = light.get() + var pow = light_status.find('power', nil) + if pow != self.shadow_onoff self.attribute_updated(nil, 0x0006, 0x0000) self.shadow_onoff = pow end + end + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0003 # ========== Identify 1.2 p.16 ========== + if attribute == 0x0000 # ---------- IdentifyTime / u2 ---------- + return TLV.create_TLV(TLV.U2, 0) # no identification in progress + elif attribute == 0x0001 # ---------- IdentifyType / enum8 ---------- + return TLV.create_TLV(TLV.U1, 0) # IdentifyType = 0x00 None + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # no features + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # "new data model format and notation" + end + + # ==================================================================================================== + elif cluster == 0x0004 # ========== Groups 1.3 p.21 ========== + if attribute == 0x0000 # ---------- ---------- + return nil # TODO + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0)# + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4)# "new data model format and notation" + end + + # ==================================================================================================== + elif cluster == 0x0005 # ========== Scenes 1.4 p.30 - no writable ========== + if attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # 0 = no Level Control for Lighting + end + + # ==================================================================================================== + elif cluster == 0x0006 # ========== On/Off 1.5 p.48 ========== + if attribute == 0x0000 # ---------- OnOff / bool ---------- + return TLV.create_TLV(TLV.BOOL, self.shadow_onoff) + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # 0 = no Level Control for Lighting + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(session, val, ctx) + import light + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + + # ==================================================================================================== + if cluster == 0x0003 # ========== Identify 1.2 p.16 ========== + + if command == 0x0000 # ---------- Identify ---------- + # ignore + return true + elif command == 0x0001 # ---------- IdentifyQuery ---------- + # create IdentifyQueryResponse + # ID=1 + # 0=Certificate (octstr) + var iqr = TLV.Matter_TLV_struct() + iqr.add_TLV(0, TLV.U2, 0) # Timeout + ctx.command = 0x00 # IdentifyQueryResponse + return iqr + elif command == 0x0040 # ---------- TriggerEffect ---------- + # ignore + return true + end + # ==================================================================================================== + elif cluster == 0x0004 # ========== Groups 1.3 p.21 ========== + # TODO + return true + # ==================================================================================================== + elif cluster == 0x0005 # ========== Scenes 1.4 p.30 ========== + # TODO + return true + # ==================================================================================================== + elif cluster == 0x0006 # ========== On/Off 1.5 p.48 ========== + if command == 0x0000 # ---------- Off ---------- + light.set({'power':false}) + self.update_shadow() + return true + elif command == 0x0001 # ---------- On ---------- + light.set({'power':true}) + self.update_shadow() + return true + elif command == 0x0002 # ---------- Toggle ---------- + light.set({'power':!self.shadow_onoff}) + self.update_shadow() + return true + end + end + end + +end +matter.Plugin_Light0 = Matter_Plugin_Light0 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be new file mode 100644 index 000000000..b917efb01 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be @@ -0,0 +1,146 @@ +# +# Matter_Plugin_Light1.be - implements the behavior for a Light with 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 . +# + +# 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 CLUSTERS = { + # 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 + # var shadow_onoff # inherited + + ############################################################# + # Constructor + def init(device, endpoint) + super(self).init(device, endpoint) + self.shadow_bri = 0 + end + + ############################################################# + # Update shadow + # + def update_shadow() + import light + var light_status = light.get() + var bri = light_status.find('bri', nil) + if bri != nil bri = tasmota.scale_uint(bri, 0, 255, 0, 254) else bri = self.shadow_bri end + if bri != self.shadow_bri self.attribute_updated(nil, 0x0008, 0x0000) self.shadow_bri = bri end + super(self).update_shadow() # superclass manages 'power' + end + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0008 # ========== Level Control 1.6 p.57 ========== + if attribute == 0x0000 # ---------- CurrentLevel / u1 ---------- + return TLV.create_TLV(TLV.U1, self.shadow_bri) + elif attribute == 0x0002 # ---------- MinLevel / u1 ---------- + return TLV.create_TLV(TLV.U1, 0) + elif attribute == 0x0003 # ---------- MaxLevel / u1 ---------- + return TLV.create_TLV(TLV.U1, 254) + elif attribute == 0x000F # ---------- Options / map8 ---------- + return TLV.create_TLV(TLV.U1, 0) # + elif attribute == 0x0011 # ---------- OnLevel / u1 ---------- + return TLV.create_TLV(TLV.U1, self.shadow_bri) + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0X01) # OnOff + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 5) # "new data model format and notation" + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(session, val, ctx) + import light + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + + # ==================================================================================================== + if cluster == 0x0008 # ========== Level Control 1.6 p.57 ========== + 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) + return true + elif command == 0x0001 # ---------- Move ---------- + # TODO, we don't really support it + return true + elif command == 0x0002 # ---------- Step ---------- + # TODO, we don't really support it + return true + elif command == 0x0003 # ---------- Stop ---------- + # 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) + return true + elif command == 0x0005 # ---------- MoveWithOnOff ---------- + # TODO, we don't really support it + return true + elif command == 0x0006 # ---------- StepWithOnOff ---------- + # TODO, we don't really support it + return true + elif command == 0x0007 # ---------- StopWithOnOff ---------- + # TODO, we don't really support it + return true + end + + else + return super(self).invoke_request(session, val, ctx) + end + end + +end +matter.Plugin_Light1 = Matter_Plugin_Light1 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light2.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light2.be new file mode 100644 index 000000000..aa2f38207 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light2.be @@ -0,0 +1,144 @@ +# +# Matter_Plugin_Light2.be - implements the behavior for a 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 . +# + +# 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 CLUSTERS = { + # 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: inherited # Level Control 1.6 p.57 + 0x0300: [7,8,0xF,0x400B,0x400C,0xFFFC,0xFFFD], # Color Control 3.2 p.111 + } + static var TYPES = { 0x010C: 2 } # Color Temperature Light + + var shadow_ct + var ct_min, ct_max + + ############################################################# + # Constructor + def init(device, endpoint) + super(self).init(device, endpoint) + self.shadow_ct = 325 + self.update_ct_minmax() + end + + ############################################################# + # Update shadow + # + def update_shadow() + import light + self.update_ct_minmax() + super(self).update_shadow() + var light_status = light.get() + var ct = light_status.find('ct', nil) + if ct == nil ct = self.shadow_ct end + if ct != self.shadow_ct self.attribute_updated(nil, 0x0300, 0x0007) self.shadow_ct = ct end + end + + ############################################################# + # Update ct_min/max + # + 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 + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0300 # ========== Color Control 3.2 p.111 ========== + if attribute == 0x0007 # ---------- ColorTemperatureMireds / u2 ---------- + return TLV.create_TLV(TLV.U1, self.shadow_ct) + elif attribute == 0x0008 # ---------- ColorMode / u1 ---------- + return TLV.create_TLV(TLV.U1, 2)# 2 = ColorTemperatureMireds + elif attribute == 0x000F # ---------- Options / u1 ---------- + return TLV.create_TLV(TLV.U1, 0) + elif attribute == 0x400B # ---------- ColorTempPhysicalMinMireds / u2 ---------- + return TLV.create_TLV(TLV.U1, self.ct_min) + elif attribute == 0x400C # ---------- ColorTempPhysicalMaxMireds / u2 ---------- + return TLV.create_TLV(TLV.U1, self.ct_max) + + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0x10) # CT + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 5) # "new data model format and notation, FeatureMap support" + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(session, val, ctx) + import light + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + + # ==================================================================================================== + if cluster == 0x0300 # ========== Color Control 3.2 p.111 ========== + 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() + ctx.log = "ct:"+str(ct_in) + return true + elif command == 0x0047 # ---------- StopMoveStep ---------- + # TODO, we don't really support it + return true + elif command == 0x004B # ---------- MoveColorTemperature ---------- + # TODO, we don't really support it + return true + elif command == 0x004C # ---------- StepColorTemperature ---------- + # TODO, we don't really support it + return true + end + + else + return super(self).invoke_request(session, val, ctx) + end + + 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_Light3.be new file mode 100644 index 000000000..7d797b29a --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light3.be @@ -0,0 +1,165 @@ +# +# Matter_Plugin_Light3.be - implements the behavior for a 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 . +# + +# 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 CLUSTERS = { + # 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: 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 + + ############################################################# + # Constructor + def init(device, endpoint) + super(self).init(device, endpoint) + self.shadow_hue = 0 + self.shadow_sat = 0 + end + + ############################################################# + # Update shadow + # + def update_shadow() + import light + super(self).update_shadow() + var light_status = light.get() + 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(nil, 0x0300, 0x0000) self.shadow_hue = hue end + if sat != self.shadow_sat self.attribute_updated(nil, 0x0300, 0x0001) self.shadow_sat = sat end + end + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0300 # ========== Color Control 3.2 p.111 ========== + if attribute == 0x0000 # ---------- CurrentHue / u1 ---------- + return TLV.create_TLV(TLV.U1, self.shadow_hue) + elif attribute == 0x0001 # ---------- CurrentSaturation / u2 ---------- + return TLV.create_TLV(TLV.U1, self.shadow_sat) + elif attribute == 0x0007 # ---------- ColorTemperatureMireds / u2 ---------- + return TLV.create_TLV(TLV.U1, 0) + elif attribute == 0x0008 # ---------- ColorMode / u1 ---------- + return TLV.create_TLV(TLV.U1, 0)# 0 = CurrentHue and CurrentSaturation + elif attribute == 0x000F # ---------- Options / u1 ---------- + return TLV.create_TLV(TLV.U1, 0) + elif attribute == 0x4001 # ---------- EnhancedColorMode / u1 ---------- + return TLV.create_TLV(TLV.U1, 0) + elif attribute == 0x400A # ---------- ColorCapabilities / map2 ---------- + return TLV.create_TLV(TLV.U1, 0) + + # Defined Primaries Information Attribute Set + elif attribute == 0x0010 # ---------- NumberOfPrimaries / u1 ---------- + return TLV.create_TLV(TLV.U1, 0) + + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0x01) # HS + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 5) # "new data model format and notation, FeatureMap support" + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(session, val, ctx) + import light + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + + # ==================================================================================================== + if cluster == 0x0300 # ========== Color Control 3.2 p.111 ========== + 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() + ctx.log = "hue:"+str(hue_in) + return true + elif command == 0x0001 # ---------- MoveHue ---------- + # TODO, we don't really support it + return true + elif command == 0x0002 # ---------- StepHue ---------- + # TODO, we don't really support it + 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() + ctx.log = "sat:"+str(sat_in) + return true + elif command == 0x0004 # ---------- MoveSaturation ---------- + # TODO, we don't really support it + return true + elif command == 0x0005 # ---------- StepSaturation ---------- + # TODO, we don't really support it + 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() + ctx.log = "hue:"+str(hue_in)+" sat:"+str(sat_in) + return true + elif command == 0x0047 # ---------- StopMoveStep ---------- + # TODO, we don't really support it + return true + end + + else + return super(self).invoke_request(session, val, ctx) + end + + end + +end +matter.Plugin_Light3 = Matter_Plugin_Light3 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_OnOff.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_OnOff.be new file mode 100644 index 000000000..a62d4fe39 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_OnOff.be @@ -0,0 +1,223 @@ +# +# Matter_Plugin_OnOff.be - implements the behavior for a Relay (OnOff) +# +# 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 . +# + +# Matter plug-in for core behavior + +# dummy declaration for solidification +class Matter_Plugin end + +#@ solidify:Matter_Plugin_OnOff,weak + +class Matter_Plugin_OnOff : Matter_Plugin + static var CLUSTERS = { + # 0x001D: inherited # Descriptor Cluster 9.5 p.453 + 0x0003: [0,1,0xFFFC,0xFFFD], # Identify 1.2 p.16 + 0x0004: [0,0xFFFC,0xFFFD], # Groups 1.3 p.21 + 0x0005: [0,1,2,3,4,5,0xFFFC,0xFFFD], # Scenes 1.4 p.30 - no writable + 0x0006: [0,0xFFFC,0xFFFD], # On/Off 1.5 p.48 + # 0x0008: [0,15,17,0xFFFC,0xFFFD] # Level Control 1.6 p.57 + } + static var TYPES = { 0x010A: 2 } # On/Off Light + + var tasmota_relay_index # Relay number in Tasmota (zero based) + var shadow_onoff # fake status for now # TODO + + ############################################################# + # Constructor + def init(device, endpoint, tasmota_relay_index) + super(self).init(device, endpoint) + self.get_onoff() # read actual value + if tasmota_relay_index == nil tasmota_relay_index = 0 end + self.tasmota_relay_index = tasmota_relay_index + end + + ############################################################# + # Model + # + def set_onoff(v) + tasmota.set_power(self.tasmota_relay_index, bool(v)) + self.get_onoff() + end + ############################################################# + # get_onoff + # + # Update shadow and signal any change + def get_onoff() + var state = tasmota.get_power(self.tasmota_relay_index) + if state != nil + if self.shadow_onoff != nil && self.shadow_onoff != bool(state) + self.onoff_changed() # signal any change + end + self.shadow_onoff = state + end + if self.shadow_onoff == nil self.shadow_onoff = false end # avoid any `nil` value when initializing + return self.shadow_onoff + end + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0003 # ========== Identify 1.2 p.16 ========== + if attribute == 0x0000 # ---------- IdentifyTime / u2 ---------- + return TLV.create_TLV(TLV.U2, 0) # no identification in progress + elif attribute == 0x0001 # ---------- IdentifyType / enum8 ---------- + return TLV.create_TLV(TLV.U1, 0) # IdentifyType = 0x00 None + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # no features + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # "new data model format and notation" + end + + # ==================================================================================================== + elif cluster == 0x0004 # ========== Groups 1.3 p.21 ========== + if attribute == 0x0000 # ---------- ---------- + return nil # TODO + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0)# + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4)# "new data model format and notation" + end + + # ==================================================================================================== + elif cluster == 0x0005 # ========== Scenes 1.4 p.30 - no writable ========== + if attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # 0 = no Level Control for Lighting + end + + # ==================================================================================================== + elif cluster == 0x0006 # ========== On/Off 1.5 p.48 ========== + if attribute == 0x0000 # ---------- OnOff / bool ---------- + return TLV.create_TLV(TLV.BOOL, self.get_onoff()) + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # 0 = no Level Control for Lighting + end + + # ==================================================================================================== + elif cluster == 0x0008 # ========== Level Control 1.6 p.57 ========== + if attribute == 0x0000 # ---------- CurrentLevel / u1 ---------- + return TLV.create_TLV(TLV.U1, 0x88) + elif attribute == 0x000F # ---------- Options / map8 ---------- + return TLV.create_TLV(TLV.U1, 0) # 0 = no Level Control for Lighting + elif attribute == 0x0010 # ---------- OnLevel / u1 ---------- + return TLV.create_TLV(TLV.U1, 1) # 0 = no Level Control for Lighting + elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- + return TLV.create_TLV(TLV.U4, 0) # 0 = no Level Control for Lighting + elif attribute == 0xFFFD # ---------- ClusterRevision / u2 ---------- + return TLV.create_TLV(TLV.U4, 4) # 0 = no Level Control for Lighting + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # Invoke a command + # + # returns a TLV object if successful, contains the response + # or an `int` to indicate a status + def invoke_request(session, val, ctx) + var TLV = matter.TLV + var cluster = ctx.cluster + var command = ctx.command + + # ==================================================================================================== + if cluster == 0x0003 # ========== Identify 1.2 p.16 ========== + + if command == 0x0000 # ---------- Identify ---------- + # ignore + return true + elif command == 0x0001 # ---------- IdentifyQuery ---------- + # create IdentifyQueryResponse + # ID=1 + # 0=Certificate (octstr) + var iqr = TLV.Matter_TLV_struct() + iqr.add_TLV(0, TLV.U2, 0) # Timeout + ctx.command = 0x00 # IdentifyQueryResponse + return iqr + elif command == 0x0040 # ---------- TriggerEffect ---------- + # ignore + return true + end + # ==================================================================================================== + elif cluster == 0x0004 # ========== Groups 1.3 p.21 ========== + # TODO + return true + # ==================================================================================================== + elif cluster == 0x0005 # ========== Scenes 1.4 p.30 ========== + # TODO + return true + # ==================================================================================================== + elif cluster == 0x0006 # ========== On/Off 1.5 p.48 ========== + if command == 0x0000 # ---------- Off ---------- + self.set_onoff(false) + return true + elif command == 0x0001 # ---------- On ---------- + self.set_onoff(true) + return true + elif command == 0x0002 # ---------- Toggle ---------- + self.set_onoff(!self.get_onoff()) + return true + end + # ==================================================================================================== + elif cluster == 0x0008 # ========== Level Control 1.6 p.57 ========== + if command == 0x0000 # ---------- MoveToLevel ---------- + return true + elif command == 0x0001 # ---------- Move ---------- + return true + elif command == 0x0002 # ---------- Step ---------- + return true + elif command == 0x0003 # ---------- Stop ---------- + return true + elif command == 0x0004 # ---------- MoveToLevelWithOnOff ---------- + return true + elif command == 0x0005 # ---------- MoveWithOnOff ---------- + return true + elif command == 0x0006 # ---------- StepWithOnOff ---------- + return true + elif command == 0x0007 # ---------- StopWithOnOff ---------- + return true + end + end + end + + ############################################################# + # Signal that onoff attribute changed + def onoff_changed() + self.attribute_updated(nil, 0x0006, 0x0000) # send to all endpoints + end + + ############################################################# + # every_second + def every_second() + self.get_onoff() # force reading value and sending subscriptions + end +end +matter.Plugin_OnOff = Matter_Plugin_OnOff diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be deleted file mode 100644 index 8721cca93..000000000 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Relay.be +++ /dev/null @@ -1,93 +0,0 @@ -# -# Matter_Plugin_Relay.be - implements the behavior for a Relay (OnOff) -# -# 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 . -# - -# Matter plug-in for core behavior - -# dummy declaration for solidification -class Matter_Plugin end - -#@ solidify:Matter_Plugin_Relay,weak - -class Matter_Plugin_Relay : Matter_Plugin - static var ENDPOINTS = [ 1 ] - static var CLUSTERS = { - 0x001D: [0,1,2,3], - 0x0003: [], - 0x0004: [], - 0x0005: [], - 0x0006: [0], - 0x0008: [], -# 0x0406: [] - } - static var TYPES = [ 0x0100 ] # On/Off Light - - ############################################################# - # Constructor - def init(device) - super(self).init(device) - self.endpoints = self.ENDPOINTS - self.clusters = self.CLUSTERS - end - - ############################################################# - # read an attribute - # - def read_attribute(msg, ctx) - import string - var TLV = matter.TLV - var cluster = ctx.cluster - var attribute = ctx.attribute - - if cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ========== - - if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ---------- - var dtl = TLV.Matter_TLV_array() - var d1 = dtl.add_struct() - d1.add_TLV(0, TLV.U2, self.TYPES[0]) # DeviceType - d1.add_TLV(1, TLV.U2, 1) # Revision - return dtl - elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ---------- - var sl = TLV.Matter_TLV_array() - for cl: self.get_cluster_list() - sl.add_TLV(nil, TLV.U4, cl) - end - return sl - elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ---------- - var cl = TLV.Matter_TLV_array() - cl.add_TLV(nil, TLV.U2, 0x0006) - return cl - elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]---------- - var pl = TLV.Matter_TLV_array() - return pl - end - end - # no match found, return that the attribute is unsupported end - end - - ############################################################# - # Invoke a command - # - # returns a TLV object if successful, contains the response - # or an `int` to indicate a status - def invoke_request(msg, val, ctx) - # no match found, return that the command is unsupported - end -end -matter.Plugin_core = Matter_Plugin_core - \ No newline at end of file diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Root.be similarity index 56% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Root.be index 4c8929cff..a387ab70f 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_core.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Root.be @@ -1,5 +1,5 @@ # -# Matter_Plugin_core.be - implements the core features that a Matter device must implemment +# Matter_Plugin_Root.be - implements the core features that a Matter device must implemment # # Copyright (C) 2023 Stephan Hadinger & Theo Arends # @@ -17,43 +17,43 @@ # along with this program. If not, see . # -# Matter plug-in for core behavior +# Matter plug-in for root behavior # dummy declaration for solidification class Matter_Plugin end -#@ solidify:Matter_Plugin_core,weak +#@ solidify:Matter_Plugin_Root,weak -class Matter_Plugin_core : Matter_Plugin - static var ENDPOINTS = [ 0 ] +class Matter_Plugin_Root : Matter_Plugin static var CLUSTERS = { - 0x001D: [0,1,2,3], - 0x0028: [0,1,2,3,4,5,6,7,8,9], - 0x002B: [0,1], - 0x002C: [0,1,2], - 0x0030: [0,1,2,3,4], - 0x0031: [3,0xFFFC], - 0x0032: [], - 0x0033: [0,1,2,8], - 0x0034: [], - 0x0038: [0,1,7], - 0x003E: [0,1,2,3,4,5], - 0x003C: [], - 0x003F: [] + # 0x001D: inherited # Descriptor Cluster 9.5 p.453 + 0x001F: [0,2,3,4], # Access Control Cluster, p.461 + 0x0028: [0,1,2,3,4,5,6,7,8,9,0x0A,0x0F,0x12,0x13],# Basic Information Cluster cluster 11.1 p.565 + # 0x002A: [0,1,2,3], # OTA Software Update Requestor Cluster Definition 11.19.7 p.762 + 0x002B: [0,1], # Localization Configuration Cluster 11.3 p.580 + 0x002C: [0,1,2], # Time Format Localization Cluster 11.4 p.581 + 0x0030: [0,1,2,3,4], # GeneralCommissioning cluster 11.9 p.627 + 0x0031: [3,4,0xFFFC], # Network Commissioning Cluster cluster 11.8 p.606 + 0x0032: [], # Diagnostic Logs Cluster 11.10 p.637 + 0x0033: [0,1,2,8], # General Diagnostics Cluster 11.11 p.642 + 0x0034: [], # Software Diagnostics Cluster 11.12 p.654 + 0x0038: [0,1,7], # Time Synchronization 11.16 p.689 + 0x003C: [0,1,2], # Administrator Commissioning Cluster 11.18 p.725 + 0x003E: [0,1,2,3,4,5], # Node Operational Credentials Cluster 11.17 p.704 + 0x003F: [] # Group Key Management Cluster 11.2 p.572 } + static var TYPES = { 0x0016: 1 } # Root node ############################################################# # Constructor - def init(device) - super(self).init(device) - self.endpoints = self.ENDPOINTS - self.clusters = self.CLUSTERS + def init(device, endpoint) + super(self).init(device, endpoint) end ############################################################# # read an attribute # - def read_attribute(msg, ctx) + def read_attribute(session, ctx) import string var TLV = matter.TLV var cluster = ctx.cluster @@ -62,7 +62,7 @@ class Matter_Plugin_core : Matter_Plugin if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== if attribute == 0x0000 # ---------- Breadcrumb ---------- - return TLV.create_TLV(TLV.U8, msg.session.breadcrumb) + return TLV.create_TLV(TLV.U8, session._breadcrumb) elif attribute == 0x0001 # ---------- BasicCommissioningInfo / BasicCommissioningInfo---------- var bci = TLV.Matter_TLV_struct() bci.add_TLV(0, TLV.U2, 60) # FailSafeExpiryLengthSeconds @@ -120,9 +120,9 @@ class Matter_Plugin_core : Matter_Plugin end return nwi elif attribute == 0x0001 # ---------- RebootCount u16 ---------- - return TLV.create_TLV(TLV.U2, tasmota.cmd("Status 1")['StatusPRM']['BootCount']) + return TLV.create_TLV(TLV.U2, tasmota.cmd("Status 1", true)['StatusPRM']['BootCount']) elif attribute == 0x0002 # ---------- UpTime u16 ---------- - return TLV.create_TLV(TLV.U4, tasmota.cmd("Status 11")['StatusSTS']['UptimeSec']) + return TLV.create_TLV(TLV.U4, tasmota.cmd("Status 11", true)['StatusSTS']['UptimeSec']) # TODO add later other attributes elif attribute == 0x0008 # ---------- TestEventTriggersEnabled bool ---------- return TLV.create_TLV(TLV.BOOL, false) # false - maybe can set to true @@ -150,80 +150,125 @@ class Matter_Plugin_core : Matter_Plugin if attribute == 0x0000 # ---------- NOCs / list[NOCStruct] ---------- var nocl = TLV.Matter_TLV_array() # NOCs, p.711 - for session: self.device.sessions.sessions_active() + for loc_fabric: self.device.sessions.active_fabrics() var nocs = nocl.add_struct(nil) - nocs.add_TLV(1, TLV.B2, session.noc) # NOC - nocs.add_TLV(2, TLV.B2, session.icac) # ICAC + nocs.add_TLV(1, TLV.B2, loc_fabric.get_noc()) # NOC + nocs.add_TLV(2, TLV.B2, loc_fabric.get_icac()) # ICAC + nocs.add_TLV(0xFE, TLV.U2, loc_fabric.get_fabric_index()) # Label end return nocl elif attribute == 0x0001 # ---------- Fabrics / list[FabricDescriptorStruct] ---------- var fabrics = TLV.Matter_TLV_array() # Fabrics, p.711 - for session: self.device.sessions.sessions_active() - var root_ca_tlv = TLV.parse(session.get_ca()) + for loc_fabric: self.device.sessions.active_fabrics() + var root_ca_tlv = TLV.parse(loc_fabric.get_ca()) var fab = fabrics.add_struct(nil) # encoding see p.303 fab.add_TLV(1, TLV.B2, root_ca_tlv.findsubval(9)) # RootPublicKey - fab.add_TLV(2, TLV.U2, session.admin_vendor) # VendorID - fab.add_TLV(3, TLV.U8, session.fabric) # FabricID - fab.add_TLV(4, TLV.U8, session.deviceid) # NodeID - fab.add_TLV(5, TLV.UTF1, session.fabric_label) # Label + fab.add_TLV(2, TLV.U2, loc_fabric.get_admin_vendor()) # VendorID + fab.add_TLV(3, TLV.U8, loc_fabric.get_fabric_id()) # FabricID + fab.add_TLV(4, TLV.U8, loc_fabric.get_device_id()) # NodeID + fab.add_TLV(5, TLV.UTF1, loc_fabric.get_fabric_label()) # Label + fab.add_TLV(0xFE, TLV.U2, loc_fabric.get_fabric_index()) # idx end return fabrics elif attribute == 0x0002 # ---------- SupportedFabrics / u1 ---------- - return TLV.create_TLV(TLV.U1, 5) # Max 5 fabrics + return TLV.create_TLV(TLV.U1, matter.Fabric._MAX_CASE) # Max 5 fabrics elif attribute == 0x0003 # ---------- CommissionedFabrics / u1 ---------- - var sessions_active = self.device.sessions.sessions_active() - return TLV.create_TLV(TLV.U1, size(sessions_active)) # number of active sessions + var fabric_actice = self.device.sessions.count_active_fabrics() + return TLV.create_TLV(TLV.U1, fabric_actice) # number of active fabrics elif attribute == 0x0004 # ---------- TrustedRootCertificates / list[octstr] ---------- # TODO elif attribute == 0x0005 # ---------- Current­ FabricIndex / u1 ---------- - var sessions_active = self.device.sessions.sessions_active() - var fabric_index = sessions_active.find(msg.session) - if fabric_index == nil fabric_index = 0 end - return TLV.create_TLV(TLV.U1, fabric_index) # number of active sessions + var fab_index = session._fabric.get_fabric_index() + if fab_index == nil fab_index = 0 end # if PASE session, then the fabric index should be zero + return TLV.create_TLV(TLV.U1, fab_index) # number of active sessions end # ==================================================================================================== elif cluster == 0x003C # ========== Administrator Commissioning Cluster 11.18 p.725 ========== - # TODO - + if attribute == 0x0000 # ---------- WindowStatus / u8 ---------- + var commissioning_open = self.device.is_commissioning_open() + var basic_commissioning = self.device.is_root_commissioning_open() + var val = commissioning_open ? (basic_commissioning ? 2 #-BasicWindowOpen-# : 1 #-EnhancedWindowOpen-#) : 0 #-WindowNotOpen-# + return TLV.create_TLV(TLV.U1, val) + elif attribute == 0x0001 # ---------- AdminFabricIndex / u16 ---------- + var admin_fabric = self.device.commissioning_admin_fabric + if admin_fabric != nil + return TLV.create_TLV(TLV.U2, admin_fabric.get_fabric_index()) + else + return TLV.create_TLV(TLV.NULL, nil) + end + elif attribute == 0x0002 # ---------- AdminVendorId / u16 ---------- + var admin_fabric = self.device.commissioning_admin_fabric + if admin_fabric != nil + return TLV.create_TLV(TLV.U2, admin_fabric.get_admin_vendor()) + else + return TLV.create_TLV(TLV.NULL, nil) + end + end + # ==================================================================================================== elif cluster == 0x0028 # ========== Basic Information Cluster cluster 11.1 p.565 ========== - if attribute == 0x0000 # ---------- DataModelRevision / u16 ---------- - return TLV.create_TLV(TLV.U2, 0) + if attribute == 0x0000 # ---------- DataModelRevision / CommissioningWindowStatus ---------- + return TLV.create_TLV(TLV.U2, 1) elif attribute == 0x0001 # ---------- VendorName / string ---------- return TLV.create_TLV(TLV.UTF1, "Tasmota") elif attribute == 0x0002 # ---------- VendorID / vendor-id ---------- return TLV.create_TLV(TLV.U2, self.device.vendorid) # Vendor ID reserved for development elif attribute == 0x0003 # ---------- ProductName / string ---------- - return TLV.create_TLV(TLV.UTF1, tasmota.cmd("DeviceName")['DeviceName']) + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("DeviceName", true)['DeviceName']) elif attribute == 0x0004 # ---------- ProductID / u16 (opt) ---------- return TLV.create_TLV(TLV.U2, 32768) # taken from esp-matter example elif attribute == 0x0005 # ---------- NodeLabel / string ---------- - return TLV.create_TLV(TLV.UTF1, tasmota.cmd("FriendlyName")['FriendlyName1']) + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("FriendlyName", true)['FriendlyName1']) elif attribute == 0x0006 # ---------- Location / string ---------- return TLV.create_TLV(TLV.UTF1, "XX") # no location elif attribute == 0x0007 # ---------- HardwareVersion / u16 ---------- return TLV.create_TLV(TLV.U2, 0) elif attribute == 0x0008 # ---------- HardwareVersionString / string ---------- - return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Hardware']) + return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2", true)['StatusFWR']['Hardware']) elif attribute == 0x0009 # ---------- SoftwareVersion / u32 ---------- - return TLV.create_TLV(TLV.U2, 0) + return TLV.create_TLV(TLV.U2, 1) elif attribute == 0x000A # ---------- SoftwareVersionString / string ---------- - return TLV.create_TLV(TLV.UTF1, tasmota.cmd("Status 2")['StatusFWR']['Version']) + var version_full = tasmota.cmd("Status 2", true)['StatusFWR']['Version'] + var version_end = string.find(version_full, '(') + if version_end > 0 version_full = version_full[0..version_end - 1] end + return TLV.create_TLV(TLV.UTF1, version_full) + elif attribute == 0x000F # ---------- SerialNumber / string ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.wifi().find("mac", "")) + elif attribute == 0x0012 # ---------- UniqueID / string 32 max ---------- + return TLV.create_TLV(TLV.UTF1, tasmota.wifi().find("mac", "")) + elif attribute == 0x0013 # ---------- CapabilityMinima / CapabilityMinimaStruct ---------- + var cps = TLV.Matter_TLV_struct() + cps.add_TLV(0, TLV.U2, 3) # CaseSessionsPerFabric = 3 + cps.add_TLV(1, TLV.U2, 3) # SubscriptionsPerFabric = 5 + return cps end # ==================================================================================================== elif cluster == 0x003F # ========== Group Key Management Cluster 11.2 p.572 ========== # TODO + # ==================================================================================================== + elif cluster == 0x002A # ========== OTA Software Update Requestor Cluster Definition 11.19.7 p.762 ========== + + if attribute == 0x0000 # ---------- DefaultOTAProviders / list[ProviderLocationStruct] ---------- + return TLV.Matter_TLV_array() # empty list for now TODO + elif attribute == 0x0001 # ---------- UpdatePossible / bool ---------- + return TLV.create_TLV(TLV.BOOL, 0) # we claim that update is not possible, would require to go to Tasmota UI + elif attribute == 0x0002 # ---------- UpdateState / UpdateStateEnum ---------- + return TLV.create_TLV(TLV.U1, 1) # Idle + elif attribute == 0x0003 # ---------- UpdateStateProgress / uint8 ---------- + return TLV.create_TLV(TLV.NULL, nil) # null, nothing in process + end + # ==================================================================================================== elif cluster == 0x002B # ========== Localization Configuration Cluster 11.3 p.580 ========== if attribute == 0x0000 # ---------- ActiveLocale / string ---------- return TLV.create_TLV(TLV.UTF1, tasmota.locale()) elif attribute == 0x0001 # ---------- SupportedLocales / list[string] ---------- - var locl = TLV.Matter_TLV_list() + var locl = TLV.Matter_TLV_array() locl.add_TLV(nil, TLV.UTF1, tasmota.locale()) return locl end @@ -236,7 +281,7 @@ class Matter_Plugin_core : Matter_Plugin elif attribute == 0x0001 # ---------- ActiveCalendarType / CalendarType ---------- return TLV.create_TLV(TLV.U1, 4) # 4 = Gregorian elif attribute == 0x0002 # ---------- SupportedCalendarTypes / list[CalendarType] ---------- - var callist = TLV.Matter_TLV_list() + var callist = TLV.Matter_TLV_array() callist.add_TLV(nil, TLV.create_TLV(TLV.U1, 4)) return callist end @@ -246,32 +291,25 @@ class Matter_Plugin_core : Matter_Plugin if attribute == 0x0003 # ---------- ConnectMaxTimeSeconds / uint8 ---------- return TLV.create_TLV(TLV.U1, 30) # 30 - value taking from example in esp-matter elif attribute == 0xFFFC # ---------- FeatureMap / map32 ---------- - return TLV.create_TLV(TLV.U4, 0) # 15s ??? TOOD what should we put here? + return TLV.create_TLV(TLV.U4, 0x04) # Put Eth for now which should work for any on-network end - # ==================================================================================================== - elif cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ========== - if attribute == 0x0000 # ---------- DeviceTypeList / list[DeviceTypeStruct] ---------- - elif attribute == 0x0001 # ---------- ServerList / list[cluster-id] ---------- - var sl = TLV.Matter_TLV_array() - for cl: self.get_cluster_list() - sl.add_TLV(nil, TLV.U4, cl) - end - return sl - elif attribute == 0x0002 # ---------- ClientList / list[cluster-id] ---------- - var cl = TLV.Matter_TLV_array() - return cl - elif attribute == 0x0003 # ---------- PartsList / list[endpoint-no]---------- - var eps = self.device.get_active_endpoints(true) + elif cluster == 0x001D # ========== Descriptor Cluster 9.5 p.453 ========== + + # overwrite PartsList + if attribute == 0x0003 # ---------- PartsList / list[endpoint-no]---------- var pl = TLV.Matter_TLV_array() + var eps = self.device.get_active_endpoints(true) for ep: eps pl.add_TLV(nil, TLV.U2, ep) # add each endpoint end return pl + else + return super(self).read_attribute(session, ctx) end else - ctx.status = matter.UNSUPPORTED_CLUSTER + return super(self).read_attribute(session, ctx) end # no match found, return that the attribute is unsupported @@ -282,12 +320,12 @@ class Matter_Plugin_core : Matter_Plugin # # returns a TLV object if successful, contains the response # or an `int` to indicate a status - def invoke_request(msg, val, ctx) + def invoke_request(session, val, ctx) import crypto + import string var TLV = matter.TLV var cluster = ctx.cluster var command = ctx.command - var session = msg.session if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== if command == 0x0000 # ---------- ArmFailSafe ---------- @@ -297,7 +335,7 @@ class Matter_Plugin_core : Matter_Plugin # 1=DebugText var ExpiryLengthSeconds = val.findsubval(0, 900) var Breadcrumb = val.findsubval(1, 0) - session.breadcrumb = Breadcrumb + session._breadcrumb = Breadcrumb var afsr = TLV.Matter_TLV_struct() afsr.add_TLV(0, TLV.U1, 0) # ErrorCode = OK @@ -309,7 +347,7 @@ class Matter_Plugin_core : Matter_Plugin var NewRegulatoryConfig = val.findsubval(0) # RegulatoryLocationType Enum var CountryCode = val.findsubval(1, "XX") var Breadcrumb = val.findsubval(2, 0) - session.breadcrumb = Breadcrumb + session._breadcrumb = Breadcrumb # create SetRegulatoryConfigResponse # ID=1 # 0=ErrorCode (OK=0) @@ -322,8 +360,10 @@ class Matter_Plugin_core : Matter_Plugin elif command == 0x0004 # ---------- CommissioningComplete p.636 ---------- # no data - session.breadcrumb = 0 # clear breadcrumb + session._breadcrumb = 0 # clear breadcrumb + session.fabric_completed() # fabric information is complete, persist session.set_no_expiration() + session.save() # create CommissioningCompleteResponse # ID=1 @@ -335,7 +375,7 @@ class Matter_Plugin_core : Matter_Plugin ctx.command = 0x05 # CommissioningCompleteResponse self.device.start_commissioning_complete_deferred(session) - return ccr # trigger a standalone ack + return ccr end elif cluster == 0x003E # ========== Node Operational Credentials Cluster 11.17 p.704 ========== @@ -364,7 +404,7 @@ class Matter_Plugin_core : Matter_Plugin att_elts.add_TLV(1, TLV.B2, matter.CD_FFF1_8000()) # certification_declaration att_elts.add_TLV(2, TLV.B1, AttestationNonce) # attestation_nonce att_elts.add_TLV(3, TLV.U4, tasmota.rtc()['utc']) # timestamp in epoch-s - var attestation_message = att_elts.encode() + var attestation_message = att_elts.tlv2raw() var ac = session.get_ac() var attestation_tbs = attestation_message + ac @@ -391,7 +431,7 @@ class Matter_Plugin_core : Matter_Plugin var nocsr_elements = TLV.Matter_TLV_struct() nocsr_elements.add_TLV(1, TLV.B2, csr) nocsr_elements.add_TLV(2, TLV.B1, CSRNonce) - var nocsr_elements_message = nocsr_elements.encode() + var nocsr_elements_message = nocsr_elements.tlv2raw() # sign with attestation challenge var nocsr_tbs = nocsr_elements_message + session.get_ac() tasmota.log("MTR: nocsr_tbs=" + nocsr_tbs.tohex(), 3) @@ -416,6 +456,8 @@ class Matter_Plugin_core : Matter_Plugin elif command == 0x0006 # ---------- AddNOC ---------- var NOCValue = val.findsubval(0) # octstr max 400 var ICACValue = val.findsubval(1) # octstr max 400 + # Apple sends an empty ICAC instead of a missing attribute, fix this + if size(ICACValue) == 0 ICACValue = nil end var IpkValue = val.findsubval(2) # octstr max 16 var CaseAdminSubject = val.findsubval(3) var AdminVendorId = val.findsubval(4) @@ -427,32 +469,40 @@ class Matter_Plugin_core : Matter_Plugin session.set_noc(NOCValue, ICACValue) session.set_ipk_epoch_key(IpkValue) - session.admin_subject = CaseAdminSubject - session.admin_vendor = AdminVendorId + session.set_admin_subject_vendor(CaseAdminSubject, AdminVendorId) # extract important information from NOC var noc_cert = matter.TLV.parse(NOCValue) var dnlist = noc_cert.findsub(6) - var fabric = dnlist.findsubval(21) + var fabric_id = dnlist.findsubval(21) var deviceid = dnlist.findsubval(17) - if !fabric || !deviceid + if !fabric_id || !deviceid tasmota.log("MTR: Error: no fabricid nor deviceid in NOC certificate", 2) return false end # convert fo bytes(8) - if type(fabric) == 'int' fabric = int64(fabric).tobytes() else fabric = fabric.tobytes() end - if type(deviceid) == 'int' deviceid = int64(deviceid).tobytes() else deviceid = deviceid.tobytes() end + if type(fabric_id) == 'int' fabric_id = int64.fromu32(fabric_id).tobytes() else fabric_id = fabric_id.tobytes() end + if type(deviceid) == 'int' deviceid = int64.fromu32(deviceid).tobytes() else deviceid = deviceid.tobytes() end var root_ca = matter.TLV.parse(session.get_ca()).findsubval(9) # extract public key from ca root_ca = root_ca[1..] # remove first byte as per Matter specification var info = bytes().fromstring("CompressedFabric") # as per spec, 4.3.2.2 p.99 var hk = crypto.HKDF_SHA256() - var fabric_rev = fabric.copy().reverse() + var fabric_rev = fabric_id.copy().reverse() var k_fabric = hk.derive(root_ca, fabric_rev, info, 8) - session.set_fabric_device(fabric, deviceid, k_fabric) + session.set_fabric_device(fabric_id, deviceid, k_fabric, self.device.commissioning_admin_fabric) + + # We have a candidate fabric, add it as expirable for 2 minutes + session.persist_to_fabric() # fabric object is completed, persist it + session.fabric_candidate() # move to next step - self.device.start_operational_dicovery_deferred(session) + self.device.start_operational_discovery_deferred(session) + # session.fabric_completed() + tasmota.log("MTR: ------------------------------------------", 3) + tasmota.log("MTR: fabric=" + matter.inspect(session._fabric), 3) + tasmota.log("MTR: ------------------------------------------", 3) + session._fabric.log_new_fabric() # log that we registered a new fabric # create NOCResponse # 0=StatusCode # 1=FabricIndex (1-254) (opt) @@ -466,27 +516,161 @@ class Matter_Plugin_core : Matter_Plugin elif command == 0x0009 # ---------- UpdateFabricLabel ---------- var label = val.findsubval(0) # Label string max 32 session.set_fabric_label(label) + tasmota.log(string.format("MTR: . Update fabric '%s' label='%s'", session._fabric.get_fabric_id().copy().reverse().tohex(), str(label)), 2) ctx.status = matter.SUCCESS # OK return nil # trigger a standalone ack elif command == 0x000A # ---------- RemoveFabric ---------- var index = val.findsubval(0) # FabricIndex - var sessions_act = self.device.sessions.sessions_active() - if index >= 1 && index <= size(sessions_act) - var session_deleted = sessions_act[index - 1] - tasmota.log("MTR: removing fabric " + session.fabric.copy().reverse().tohex()) - self.device.sessions.remove_session() - self.device.sessions.save() - else - # TODO return error 11 InvalidFabricIndex + + for fab: self.device.sessions.active_fabrics() + if fab.get_fabric_index() == index + tasmota.log("MTR: removing fabric " + fab.get_fabric_id().copy().reverse().tohex(), 2) + # defer actual removal to send a response + tasmota.set_timer(2000, def () self.device.remove_fabric(fab) end) + return true # Ok + end end - ctx.status = matter.SUCCESS # OK + tasmota.log("MTR: RemoveFabric fabric("+str(index)+") not found", 2) + ctx.status = matter.INVALID_ACTION + ctx.log = "fabric_index:"+str(index) return nil # trigger a standalone ack end + + # ==================================================================================================== + elif cluster == 0x003C # ========== Administrator Commissioning Cluster 11.18 p.725 ========== + + if command == 0x0000 # ---------- OpenCommissioningWindow ---------- + var timeout = val.findsubval(0) # CommissioningTimeout u2 + var passcode_verifier = val.findsubval(1) # PAKEPasscodeVerifier octstr + var discriminator = val.findsubval(2) # Discriminator u2 + var iterations = val.findsubval(3) # Iterations u4 + var salt = val.findsubval(4) # Salt octstr + + tasmota.log(string.format("MTR: OpenCommissioningWindow(timeout=%i, passcode=%s, discriminator=%i, iterations=%i, salt=%s)", + timeout, passcode_verifier.tohex(), discriminator, iterations, salt.tohex()), 2) + + # check values + if timeout == nil || passcode_verifier == nil || discriminator == nil || iterations == nil || salt == nil + ctx.status = matter.INVALID_DATA_TYPE + return nil # trigger a standalone ack + end + if size(passcode_verifier) != 32+65 || size(salt) < 16 || size(salt) > 32 + tasmota.log("MTR: wrong size for PAKE parameters") + ctx.status = matter.CONSTRAINT_ERROR + return nil # trigger a standalone ack + end + + var w0 = passcode_verifier[0..31] + var L = passcode_verifier[32..] + + self.device.start_basic_commissioning(timeout, iterations, discriminator, salt, w0, #-w1,-# L, session.get_fabric()) + # TODO announce in MDNS + return true # OK + elif command == 0x0001 # ---------- OpenBasicCommissioningWindow ---------- + var commissioning_timeout = val.findsubval(0) # CommissioningTimeout + tasmota.log("MTR: OpenBasicCommissioningWindow commissioning_timeout="+str(commissioning_timeout), 2) + self.device.start_root_basic_commissioning(commissioning_timeout) + return true + elif command == 0x0002 # ---------- RevokeCommissioning ---------- + # TODO add checks that the commissioning window was opened by the same fabric + self.device.stop_basic_commissioning() + return true + end + + # ==================================================================================================== + elif cluster == 0x002A # ========== OTA Software Update Requestor Cluster Definition 11.19.7 p.762 ========== + + if command == 0x0000 # ---------- DefaultOTAProviders ---------- + return true # OK + end + + else + return super(self).invoke_request(session, val, ctx) end end + + ############################################################# + # write an attribute + # + def write_attribute(session, ctx, write_data) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # 0x001D no writable attributes + # 0x0032 no attributes + # 0x0033 no writable attributes + # 0x0034 no writable attributes + # 0x0038 no mandatory writable attributes + # 0x003C no writable attributes + # 0x003E no writable attributes + + if cluster == 0x0030 # ========== GeneralCommissioning cluster 11.9 p.627 ========== + + if attribute == 0x0000 # ---------- Breadcrumb ---------- + if type(write_data) == 'int' || isinstance(write_data, int64) + session._breadcrumb = write_data + self.attribute_updated(ctx.endpoint, ctx.cluster, ctx.attribute) # TODO should we have a more generalized way each time a write_attribute is triggered, declare the attribute as changed? + return true + else + ctx.status = matter.CONSTRAINT_ERROR + return false + end + end + + # ==================================================================================================== + elif cluster == 0x001F # ========== Access Control Cluster 9.10 p.461 ========== + if attribute == 0x0000 # ACL - list[AccessControlEntryStruct] + return true + end + + # ==================================================================================================== + elif cluster == 0x0028 # ========== Basic Information Cluster cluster 11.1 p.565 ========== + + if attribute == 0x0005 # ---------- NodeLabel / string ---------- + # TODO + return true + elif attribute == 0x0006 # ---------- Location / string ---------- + # TODO + return true + end + # ==================================================================================================== + elif cluster == 0x002A # ========== OTA Software Update Requestor Cluster Definition 11.19.7 p.762 ========== + + if attribute == 0x0000 # ---------- DefaultOTAProviders / list[ProviderLocationStruct] ---------- + return true # silently ignore + end + # ==================================================================================================== + elif cluster == 0x002B # ========== Localization Configuration Cluster 11.3 p.580 ========== + + if attribute == 0x0000 # ---------- ActiveLocale / string ---------- + ctx.status = matter.CONSTRAINT_ERROR # changing locale is not possible + return false + end + # ==================================================================================================== + elif cluster == 0x002C # ========== Time Format Localization Cluster 11.4 p.581 ========== + + if attribute == 0x0000 # ---------- HourFormat / HourFormat ---------- + # TODO + return true + elif attribute == 0x0001 # ---------- ActiveCalendarType / CalendarType ---------- + # TODO + return true + end + # ==================================================================================================== + elif cluster == 0x0031 # ========== Network Commissioning Cluster cluster 11.8 p.606 ========== + if attribute == 0x0004 # ---------- InterfaceEnabled / bool ---------- + ctx.status = matter.INVALID_ACTION + return false + end + + + end + end end -matter.Plugin_core = Matter_Plugin_core +matter.Plugin_Root = Matter_Plugin_Root \ No newline at end of file diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Temp_Sensor.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Temp_Sensor.be new file mode 100644 index 000000000..3375bce6d --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Temp_Sensor.be @@ -0,0 +1,109 @@ +# +# Matter_Plugin_Temp_Sensor.be - implements the behavior for a 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 . +# + +# Matter plug-in for core behavior + +# dummy declaration for solidification +class Matter_Plugin_Device end + +#@ solidify:Matter_Plugin_Temp_Sensor,weak + +class Matter_Plugin_Temp_Sensor : Matter_Plugin_Device + static var CLUSTERS = { + # 0x001D: inherited # Descriptor Cluster 9.5 p.453 + # 0x0003: inherited # Identify 1.2 p.16 + # 0x0004: inherited # Groups 1.3 p.21 + 0x0402: [0,1,2], # Temperature Measurement p.97 - no writable + } + static var TYPES = { 0x0302: 2 } # Temperature Sensor, rev 2 + + var tasmota_sensor_filter # Rule-type filter to the value, like "ESP32#Temperature" + var tasmota_sensor_matcher # Actual matcher object + var shadow_temperature # fake status for now # TODO + + ############################################################# + # Constructor + def init(device, endpoint, sensor_filter) + super(self).init(device, endpoint) + self.tasmota_sensor_filter = sensor_filter + self.tasmota_sensor_matcher = tasmota.Rule_Matcher.parse(sensor_filter) + end + + ############################################################# + # parse sensor + # + # The device calls regularly `tasmota.read_sensors()` and converts + # it to json. + def parse_sensors(payload) + if self.tasmota_sensor_matcher + var val = real(self.tasmota_sensor_matcher.match(payload)) + if val != nil + # import string + # tasmota.log(string.format("MTR: update temperature for endpoint %i - %.1f C", self.endpoint,), 3) + if val != self.shadow_temperature + self.attribute_updated(nil, 0x0402, 0x0000) + end + self.shadow_temperature = val + end + end + end + + ############################################################# + # get_temperature + # + # Update shadow and signal any change + def get_temperature() + return self.shadow_temperature + end + + ############################################################# + # read an attribute + # + def read_attribute(session, ctx) + import string + var TLV = matter.TLV + var cluster = ctx.cluster + var attribute = ctx.attribute + + # ==================================================================================================== + if cluster == 0x0402 # ========== Temperature Measurement 2.3 p.97 ========== + if attribute == 0x0000 # ---------- MeasuredValue / i16 (*100) ---------- + if self.shadow_temperature != nil + return TLV.create_TLV(TLV.I2, int(self.shadow_temperature * 100)) + else + return TLV.create_TLV(TLV.NULL, nil) + end + elif attribute == 0x0001 # ---------- MinMeasuredValue / i16 (*100) ---------- + return TLV.create_TLV(TLV.I2, -5000) # -50 °C + elif attribute == 0x0002 # ---------- MaxMeasuredValue / i16 (*100) ---------- + return TLV.create_TLV(TLV.I2, 15000) # 150 °C + end + + else + return super(self).read_attribute(session, ctx) + end + end + + ############################################################# + # every_second + def every_second() + self.get_temperature() # force reading value and sending subscriptions + end +end +matter.Plugin_Temp_Sensor = Matter_Plugin_Temp_Sensor diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be index 1f46e0f32..5936c44cf 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be @@ -1,5 +1,5 @@ # -# Matter_Session.be - Support for Matter Sessions and Session Store +# Matter_Session.be - Support for Matter Sessions # # Copyright (C) 2023 Stephan Hadinger & Theo Arends # @@ -20,7 +20,9 @@ import matter #@ solidify:Matter_Session,weak -#@ solidify:Matter_Session_Store,weak + +# for compilation +class Matter_Expirable end ################################################################################# # Matter_Session class @@ -29,76 +31,178 @@ import matter # It can also be retrived by `source_node_id` when `local_session_id` is 0 # # By convention, names starting with `_` are not persisted +# Names starting with `__` are cleared when session is closed (transition from PASE to CASE or CASE finished) ################################################################################# -class Matter_Session - static var __PASE = 1 # PASE authentication in progress - static var __CASE = 2 # CASE authentication in progress - var __store # reference back to session store +class Matter_Session : Matter_Expirable + static var _PASE = 1 # PASE authentication in progress + static var _CASE = 2 # CASE authentication in progress + static var _COUNTER_SND_INCR = 1024 # counter increased when persisting + var _store # reference back to session store # mode for Session. Can be PASE=1, CASE=2, Established=10 none=0 var mode + # link to a fabric object, temporary and in construction for PASE, persistent for CASE + var _fabric # sesions var local_session_id # id for the current local session, starts with 1 var initiator_session_id # id used to respond to the initiator - var session_timestamp # timestamp (UTC) when the session was created - var source_node_id # source node if bytes(8) (opt, used only when session is not established) + var created # timestamp (UTC) when the session was created + var last_used # timestamp (UTC) when the session was last used + var _source_node_id # source node if bytes(8) (opt, used only when session is not established) # session_ids when the session will be active - var _future_initiator_session_id - var _future_local_session_id + var __future_initiator_session_id + var __future_local_session_id # counters var counter_rcv # counter for incoming messages - var counter_snd # counter for outgoing messages + var counter_snd # persisted last highest known counter_snd (it is in advance or equal to the actual last used counter_snd) + var _counter_rcv_impl # implementation of counter_rcv by matter.Counter() + var _counter_snd_impl # implementation of counter_snd by matter.Counter() + var _exchange_id # exchange id for locally initiated transaction, non-persistent + # keep track of last known IP/Port of the fabric + var _ip # IP of the last received packet (string) + var _port # port of the last received packet (int) + var _message_handler # pointer to the message handler for this session # non-session counters - var _counter_insecure_rcv # counter for incoming messages - var _counter_insecure_snd # counter for outgoing messages + var _counter_insecure_rcv # counter for incoming messages + var _counter_insecure_snd # counter for outgoing messages # encryption keys and challenges var i2rkey # key initiator to receiver (incoming) var r2ikey # key receiver to initiator (outgoing) var _i2r_privacy # cache for the i2r privacy key - var attestation_challenge # Attestation challenge + var attestation_challenge # Attestation challenge var peer_node_id # breadcrumb - var breadcrumb # breadcrumb attribute for this session - # our own private key - var no_private_key # private key of the device certificate (generated at commissioning) - # NOC information - var root_ca_certificate # root certificate of the initiator - var noc # Node Operational Certificate in TLV Matter Certificate - var icac # Initiator CA Certificate in TLV Matter Certificate - var ipk_epoch_key # timestamp + var _breadcrumb # breadcrumb attribute for this session, prefix `_` so that it is not persisted and untouched # CASE var resumption_id # bytes(16) - var shared_secret # ECDH shared secret used in CASE - # Information extracted from `noc` - var fabric # fabric identifier as bytes(8) little endian - var fabric_compressed # comrpessed fabric identifier, hashed with root_ca public key - var deviceid # our own device id bytes(8) little endian - var fabric_label # set by UpdateFabricLabel - # Admin info extracted from NOC/ICAC - var admin_subject - var admin_vendor + var shared_secret # ECDH shared secret used in CASE + var __responder_priv, __responder_pub + var __initiator_pub + # PASE + var __spake_cA # crypto.SPAKE2P_Matter object, cA + var __spake_Ke # crypto.SPAKE2P_Matter object, Ke # Previous CASE messages for Transcript hash - var _Msg1, _Msg2 - # Expiration - var _persist # do we persist this sessions or is it remporary - var expiration # if not `nil` the entry is removed after this timestamp + var __Msg1, __Msg2 # below are placeholders for ongoing transactions or chunked responses - var _chunked_attr_reports # if not `nil` holds a container for the current _chuked_attr_reports + var __chunked_attr_reports # if not `nil` holds a container for the current _chuked_attr_reports # Group Key Derivation - static var __GROUP_KEY = "GroupKey v1.0" # starting with double `_` means it's not writable + static var _GROUP_KEY = "GroupKey v1.0" # starting with double `_` means it's not writable ############################################################# - def init(store, local_session_id, initiator_session_id) - self.__store = store + def init(store, local_session_id, initiator_session_id, fabric) + import crypto + self._store = store self.mode = 0 self.local_session_id = local_session_id self.initiator_session_id = initiator_session_id - self.counter_rcv = matter.Counter() - self.counter_snd = matter.Counter() + # self.counter_rcv = matter.Counter() + # self.counter_snd = matter.Counter() + self._counter_snd_impl = matter.Counter() + self._counter_rcv_impl = matter.Counter() + self.counter_rcv = 0 # avoid nil values + self.counter_snd = self._counter_snd_impl.next() + self._COUNTER_SND_INCR + # self._counter_insecure_rcv = matter.Counter() self._counter_insecure_snd = matter.Counter() - self.breadcrumb = int64() + self._breadcrumb = 0 + self._exchange_id = crypto.random(2).get(0,2) # generate a random 16 bits number, then increment with rollover + + self._fabric = fabric ? fabric : self._store.create_fabric() + self.update() + end + + ############################################################# + # Called before removal + def before_remove() + import string + tasmota.log(string.format("MTR: -Session (%6i) (removed)", self.local_session_id), 3) + end + + ############################################################# + # Management of security counters + ############################################################# + # Provide the next counter value, and update the last know persisted if needed + # + def counter_snd_next() + import string + var next = self._counter_snd_impl.next() + tasmota.log(string.format("MTR: . Counter_snd=%i", next), 3) + # print(">>> NEXT counter_snd=", self.counter_snd, "_impl=", self._counter_snd_impl.val(), 4) + if matter.Counter.is_greater(next, self.counter_snd) + self.counter_snd = next + self._COUNTER_SND_INCR + if self.does_persist() + # the persisted counter is behind the actual counter + self.save() + end + end + return next + end + # ############################################################# + # # Before savind + # def persist_pre() + # end + + ############################################################# + # When hydrating from persistance, update counters + def hydrate_post() + # reset counter_snd to highest known. + # We advance it only in case it is actually used + # This avoids updaing counters on dead sessions + self._counter_snd_impl.reset(self.counter_snd) + self._counter_rcv_impl.reset(self.counter_rcv) + self.counter_snd = self._counter_snd_impl.val() + self.counter_rcv = self._counter_rcv_impl.val() + end + ############################################################# + # Validate received counter + def counter_rcv_validate(v, t) + var ret = self._counter_rcv_impl.validate(v, t) + if ret self.counter_rcv = self._counter_rcv_impl.val() end # update the validated counter + return ret + end + + ############################################################# + # Update the timestamp or any other information + def update() + self.last_used = tasmota.rtc()['utc'] + end + + def set_mode_PASE() self.set_mode(self._PASE) end + def set_mode_CASE() self.set_mode(self._CASE) end + def is_PASE() return self.mode == self._PASE end + def is_CASE() return self.mode == self._CASE end + + ############################################################# + # Assign a new fabric index + def assign_fabric_index() + if (self._fabric.get_fabric_index() == nil) + self._fabric.set_fabric_index(self._store.next_fabric_idx()) + end + end + + ############################################################# + # Register the fabric as complete (end of commissioning) + def fabric_completed() + self._fabric.set_no_expiration() + self._fabric.set_persist(true) + self.assign_fabric_index() + self._store.add_fabric(self._fabric) + end + + ############################################################# + # Register the frabric as complete (end of commissioning) + def fabric_candidate() + self._fabric.set_expire_in_seconds(120) # expire in 2 minutes + self.assign_fabric_index() + self._store.add_fabric(self._fabric) + end + + ############################################################# + # Persist to fabric + # Add self session to the persisted established CASE session of the fabric + def persist_to_fabric() + self._fabric.add_session(self) end ############################################################# @@ -106,28 +210,24 @@ class Matter_Session # def close() # close the PASE session, it will be re-opened with a CASE session - var persist_save = self._persist - self.local_session_id = self._future_local_session_id - self.initiator_session_id = self._future_initiator_session_id - self.source_node_id = nil - self.counter_rcv.reset() - self.counter_snd.reset() + self.local_session_id = self.__future_local_session_id + self.initiator_session_id = self.__future_initiator_session_id + self._counter_rcv_impl.reset() + self._counter_snd_impl.reset() + self.counter_rcv = 0 + self.counter_snd = self._counter_snd_impl.next() self.i2rkey = nil self._i2r_privacy = nil self.r2ikey = nil self.attestation_challenge = nil - self.fabric_label = "" - # clear any attribute starting with `_` + # clear any attribute starting with `__` import introspect for k : introspect.members(self) var v = introspect.get(self, k) - if type(v) != 'function' && type(v) != 'instance' && k[0] == '_' && k[1] != '_' + if type(v) != 'function' && type(v) != 'instance' && k[0] == '_' && k[1] == '_' self.(k) = nil end end - self._persist = persist_save - # self._future_initiator_session_id = nil - # self._future_local_session_id = nil end ############################################################# @@ -139,30 +239,32 @@ class Matter_Session self._i2r_privacy = nil # clear cache self.r2ikey = r2i self.attestation_challenge = ac - self.session_timestamp = st + self.created = st end def set_ca(ca) - self.root_ca_certificate = ca + self._fabric.root_ca_certificate = ca end def set_noc(noc, icac) - self.noc = noc - self.icac = icac + self._fabric.noc = noc + self._fabric.icac = icac end def set_ipk_epoch_key(ipk_epoch_key) - self.ipk_epoch_key = ipk_epoch_key + self._fabric.ipk_epoch_key = ipk_epoch_key end - def set_fabric_device(fabric, deviceid, fc) - self.fabric = fabric - self.deviceid = deviceid - self.fabric_compressed = fc - self.__store.remove_redundant_session(self) + def set_admin_subject_vendor(admin_subject, admin_vendor) + self._fabric.admin_subject = admin_subject + self._fabric.admin_vendor = admin_vendor end - def set_persist(p) - self._persist = bool(p) + + def set_fabric_device(fabric_id, device_id, fc, fabric_parent) + self._fabric.fabric_id = fabric_id + self._fabric.device_id = device_id + self._fabric.fabric_compressed = fc + self._fabric.fabric_parent = (fabric_parent != nil) ? fabric_parent.get_fabric_index() : nil end def set_fabric_label(s) if type(s) == 'string' - self.fabric_label = s + self._fabric.fabric_label = s end end @@ -188,75 +290,45 @@ class Matter_Session return self.attestation_challenge end def get_ca() - return self.root_ca_certificate + return self._fabric.root_ca_certificate end def get_ca_pub() - if self.root_ca_certificate - var m = matter.TLV.parse(self.root_ca_certificate) - return m.findsubval(9) - end + return self._fabric.get_ca_pub() end - def get_noc() return self.noc end - def get_icac() return self.icac end - def get_ipk_epoch_key() return self.ipk_epoch_key end - def get_fabric() return self.fabric end - def get_deviceid() return self.deviceid end - def get_fabric_compressed() return self.fabric_compressed end + def get_fabric() return self._fabric end + def get_noc() return self._fabric.noc end + def get_icac() return self._fabric.icac end + def get_ipk_epoch_key() return self._fabric.ipk_epoch_key end + def get_fabric_id() return self._fabric.fabric_id end + def get_device_id() return self._fabric.device_id 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 ############################################################# # Generate a private key (or retrieve it) def get_pk() - if !self.no_private_key + if !self._fabric.no_private_key import crypto - self.no_private_key = crypto.random(32) + self._fabric.no_private_key = crypto.random(32) end - return self.no_private_key + return self._fabric.no_private_key end ############################################################# # Operational Group Key Derivation, 4.15.2, p.182 def get_ipk_group_key() - if self.ipk_epoch_key == nil || self.fabric_compressed == nil return nil end + if self.get_ipk_epoch_key() == nil || self.get_fabric_compressed() == nil return nil end import crypto var hk = crypto.HKDF_SHA256() - var info = bytes().fromstring(self.__GROUP_KEY) - var hash = hk.derive(self.ipk_epoch_key, self.fabric_compressed, info, 16) + var info = bytes().fromstring(self._GROUP_KEY) + var hash = hk.derive(self.get_ipk_epoch_key(), self.get_fabric_compressed(), info, 16) return hash end ############################################################# - # set absolute time for expiration - def set_no_expiration() - self.expiration = nil - end - - ############################################################# - # set absolute time for expiration - def set_expire_time(t) - self.expiration = int(t) - end - - ############################################################# - # set relative time in the future for expiration (in seconds) - def set_expire_in_seconds(s, now) - if s == nil return end - if now == nil now = tasmota.rtc()['utc'] end - self.set_expire_time(now + s) - end - - ############################################################# - # set relative time in the future for expiration (in seconds) - # returns `true` if expiration date has been reached - def has_expired(now) - if now == nil now = tasmota.rtc()['utc'] end - if self.expiration != nil - return now >= self.expiration - end - return false - end - - ############################################################# - # to_json() + # Session::to_json() # # convert a single entry as json # returns a JSON string @@ -266,6 +338,7 @@ class Matter_Session import string import introspect + self.persist_pre() var keys = [] for k : introspect.members(self) var v = introspect.get(self, k) @@ -278,57 +351,50 @@ class Matter_Session var v = introspect.get(self, k) if v == nil continue end - if k == "counter_rcv" v = v.val() - elif k == "counter_snd" v = v.val() + 256 # take a margin to avoid reusing the same counter + if isinstance(v, bytes) v = "$$" + v.tob64() # bytes + elif type(v) == 'instance' continue # skip any other instance end - - if isinstance(v, bytes) v = "$$" + v.tob64() end # bytes - # if isinstance(v, bytes) v = "0x" + v.tohex() end - # if type(v) == 'string' v = string.escape(v, true) end r.push(string.format("%s:%s", json.dump(str(k)), json.dump(v))) end + self.persist_post() return "{" + r.concat(",") + "}" end ############################################################# - # fromjson() + # Session::fromjson() # # reads a map and load arguments # returns an new instance of session ############################################################# - static def fromjson(store, values) + static def fromjson(store, values, fabric) import string import introspect - var self = matter.Session(store) + var self = matter.Session(store, nil, nil, fabric) for k:values.keys() var v = values[k] - if k == "counter_rcv" self.counter_rcv.reset(int(v)) - elif k == "counter_snd" self.counter_snd.reset(int(v)) - else - # standard values - if type(v) == 'string' - if string.find(v, "0x") == 0 # treat as bytes - introspect.set(self, k, bytes().fromhex(v[2..])) - elif string.find(v, "$$") == 0 # treat as bytes - introspect.set(self, k, bytes().fromb64(v[2..])) - else - introspect.set(self, k, v) - end + # standard values + if type(v) == 'string' + if string.find(v, "0x") == 0 # treat as bytes + introspect.set(self, k, bytes().fromhex(v[2..])) + elif string.find(v, "$$") == 0 # treat as bytes + introspect.set(self, k, bytes().fromb64(v[2..])) else introspect.set(self, k, v) end + else + introspect.set(self, k, v) end end - + self.hydrate_post() return self end ############################################################# # Callback to Session store def save() - self.__store.save() + self._store.save_fabrics() end ############################################################# @@ -377,234 +443,6 @@ end matter.Session = Matter_Session -################################################################################# -# Matter_Session_Store class -################################################################################# -class Matter_Session_Store - var sessions - static var FILENAME = "_matter_sessions.json" - - ############################################################# - def init() - self.sessions = [] - end - - ############################################################# - # add session - def create_session(local_session_id, initiator_session_id) - var session = self.get_session_by_local_session_id(local_session_id) - if session != nil self.remove_session(session) end - session = matter.Session(self, local_session_id, initiator_session_id) - self.sessions.push(session) - return session - end - - ############################################################# - # add session - def add_session(s, expires_in_seconds) - if expires_in_seconds != nil - s.set_expire_in_seconds(expires_in_seconds) - end - self.sessions.push(s) - end - - ############################################################# - def get_session_by_local_session_id(id) - if id == nil return nil end - var sz = size(self.sessions) - var i = 0 - var sessions = self.sessions - while i < sz - if sessions[i].local_session_id == id return sessions[i] end - i += 1 - end - end - - ############################################################# - def get_session_by_source_node_id(nodeid) - if nodeid == nil return nil end - var sz = size(self.sessions) - var i = 0 - var sessions = self.sessions - while i < sz - if sessions[i].source_node_id == nodeid return sessions[i] end - i += 1 - end - end - - ############################################################# - # Remove session by reference - # - def remove_session(s) - var i = 0 - var sessions = self.sessions - while i < size(self.sessions) - if sessions[i] == s - sessions.remove(i) - else - i += 1 - end - end - end - - ############################################################# - # Remove session by reference - # - # remove all other sessions that have the same: - # fabric / deviceid / fc - def remove_redundant_session(s) - var i = 0 - var sessions = self.sessions - while i < size(self.sessions) - var session = sessions[i] - if session != s && session.fabric == s.fabric && session.deviceid == s.deviceid #- && session.fabric_compressed == s.fabric_compressed -# - sessions.remove(i) - else - i += 1 - end - end - end - - ############################################################# - # Generate a new local_session_id - def gen_local_session_id() - import crypto - while true - var candidate_local_session_id = crypto.random(2).get(0, 2) - - if self.get_session_by_local_session_id(candidate_local_session_id) == nil - return candidate_local_session_id - end - - end - end - - ############################################################# - # remove_expired - # - # Check is any session has expired - def remove_expired() - var dirty = false - var i = 0 - var sessions = self.sessions - while i < size(self.sessions) - if sessions[i].has_expired() - if sessions[i]._persist dirty = true end # do we need to save - sessions.remove(i) - else - i += 1 - end - end - if dirty self.save() end - end - def every_second() - self.remove_expired() - end - - ############################################################# - # find or create a session for unencrypted traffic - # expires in `expire` seconds - def find_session_source_id_unsecure(source_node_id, expire) - var session = self.get_session_by_source_node_id(source_node_id) - if session == nil - session = matter.Session(self, 0, 0) - session.source_node_id = source_node_id - self.sessions.push(session) - end - session.set_expire_in_seconds(expire) - return session - end - - ############################################################# - # find session by resumption id - def find_session_by_resumption_id(resumption_id) - if !resumption_id return nil end - var i = 0 - var sessions = self.sessions - while i < size(sessions) - if sessions[i].resumption_id == resumption_id - return sessions[i] - end - i += 1 - end - end - - ############################################################# - # list of sessions that are active, i.e. have been - # successfully commissioned - # - def sessions_active() - var ret = [] - var idx = 0 - while idx < size(self.sessions) - var session = self.sessions[idx] - if session.get_deviceid() && session.get_fabric() - ret.push(session) - end - idx += 1 - end - return ret - end - - ############################################################# - def save() - import json - self.remove_expired() # clean before saving - - var j = [] - for v:self.sessions - if v._persist - j.push(v.tojson()) - end - end - var j_size = size(j) - j = "[" + j.concat(",") + "]" - - try - import string - var f = open(self.FILENAME, "w") - f.write(j) - f.close() - tasmota.log(string.format("MTR: Saved %i session(s)", j_size), 2) - return j - except .. as e, m - tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2) - return j - end - end - - ############################################################# - def load() - import string - try - self.sessions = [] # remove any left-over - var f = open(self.FILENAME) - var s = f.read() - f.close() - - import json - var j = json.load(s) - s = nil - tasmota.gc() # clean-up a potential long string - - for v:j # iterate on values - var session = matter.Session.fromjson(self, v) - if session != nil - self.add_session(session) - end - end - - tasmota.log(string.format("MTR: Loaded %i session(s)", size(self.sessions)), 2) - except .. as e, m - if e != "io_error" - tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2) - end - end - self.remove_expired() # clean after load - end -end -matter.Session_Store = Matter_Session_Store - #- # Unit test diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be new file mode 100644 index 000000000..86e9af6c9 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session_Store.be @@ -0,0 +1,391 @@ +# +# Matter_Session_Store.be - Support for Matter Session Store +# +# 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 + +#@ solidify:Matter_Session_Store,weak + +# for compilation +class Matter_Expirable end + +################################################################################# +################################################################################# +################################################################################# +# Matter_Session_Store class +################################################################################# +################################################################################# +################################################################################# +class Matter_Session_Store + var sessions + var fabrics # list of provisioned fabrics + static var _FABRICS = "_matter_fabrics.json" + + ############################################################# + def init() + self.sessions = matter.Expirable_list() + self.fabrics = matter.Expirable_list() + end + + ############################################################# + # add provisioned fabric + def add_fabric(fabric) + if !isinstance(fabric, matter.Fabric) raise "value_error", "must be of class matter.Fabric" end + if self.fabrics.find(fabric) == nil + self.remove_redundant_fabric(fabric) + self.fabrics.push(fabric) + end + end + + ############################################################# + # remove fabric + def remove_fabric(fabric) + var idx = 0 + while idx < size(self.sessions) + if self.sessions[idx]._fabric == fabric + self.sessions.remove(idx) + else + idx += 1 + end + end + self.fabrics.remove(self.fabrics.find(fabric)) # fail safe + end + + ############################################################# + # Remove redudant fabric + # + # remove all other fabrics that have the same: + # fabric_id / device_id + def remove_redundant_fabric(f) + var i = 0 + while i < size(self.fabrics) + var fabric = self.fabrics[i] + if fabric != f && fabric.fabric_id == f.fabric_id && fabric.device_id == f.device_id + self.fabrics.remove(i) + else + i += 1 + end + end + end + + ############################################################# + # Returns an iterator on active fabrics + def active_fabrics() + self.remove_expired() # clean before + return self.fabrics.persistables() + end + + ############################################################# + # Count active fabrics + # + # Count the number of commissionned fabrics, i.e. persisted + def count_active_fabrics() + self.remove_expired() # clean before + return self.fabrics.count_persistables() + end + + ############################################################# + # Find fabric by index number + # + def find_fabric_by_index(fabric_index) + for fab : self.active_fabrics() + if fab.get_fabric_index() == fabric_index + return fab + end + end + return nil + end + + ############################################################# + # Find children fabrics + # + # Find all children fabrics recursively and collate in array + # includes the parent fabric as first element + # + # Ex: + # matter_device.sessions.fabrics[1].fabric_parent = 1 + # matter_device.sessions.find_children_fabrics(1) + # + def find_children_fabrics(parent_index) + if parent_index == nil return [] end + var ret = [ parent_index ] + + def find_children_fabrics_inner(index) + for fab: self.active_fabrics() + if fab.fabric_parent == index + # protect against infinite loops + if ret.find() == nil + var sub_index = fab.fabric_index + ret.push(sub_index) + find_children_fabrics_inner(sub_index) + end + end + end + end + + find_children_fabrics_inner(parent_index) + + # ret contains a list of indices + return ret + end + + ############################################################# + # Next fabric-idx + # + # starts at `1`, computes the next available fabric-idx + def next_fabric_idx() + self.remove_expired() # clean before + var next_idx = 1 + for fab: self.active_fabrics() + var fab_idx = fab.fabric_index + if type(fab_idx) == 'int' && fab_idx >= next_idx + next_idx = fab_idx + 1 + end + end + return next_idx + end + + ############################################################# + # add session + def create_session(local_session_id, initiator_session_id) + var session = self.get_session_by_local_session_id(local_session_id) + if session != nil self.remove_session(session) end + session = matter.Session(self, local_session_id, initiator_session_id) + self.sessions.push(session) + return session + end + + ############################################################# + # add session + def add_session(s, expires_in_seconds) + if expires_in_seconds != nil + s.set_expire_in_seconds(expires_in_seconds) + end + self.sessions.push(s) + end + + ############################################################# + def get_session_by_local_session_id(id) + if id == nil return nil end + var sz = size(self.sessions) + var i = 0 + var sessions = self.sessions + while i < sz + var session = sessions[i] + if session.local_session_id == id + session.update() + return session + end + i += 1 + end + end + + ############################################################# + def get_session_by_source_node_id(nodeid) + if nodeid == nil return nil end + var sz = size(self.sessions) + var i = 0 + var sessions = self.sessions + while i < sz + var session = sessions[i] + if session._source_node_id == nodeid + session.update() + return session + end + i += 1 + end + end + + ############################################################# + # Remove session by reference + # + def remove_session(s) + var i = 0 + var sessions = self.sessions + while i < size(self.sessions) + if sessions[i] == s + sessions.remove(i) + else + i += 1 + end + end + end + + ############################################################# + # Generate a new local_session_id + def gen_local_session_id() + import crypto + while true + var candidate_local_session_id = crypto.random(2).get(0, 2) + + if self.get_session_by_local_session_id(candidate_local_session_id) == nil + return candidate_local_session_id + end + + end + end + + ############################################################# + # remove_expired + # + def remove_expired() + self.sessions.every_second() + self.fabrics.every_second() + end + + ############################################################# + # call remove_expired every second + # + def every_second() + self.remove_expired() + end + + ############################################################# + # find or create a session for unencrypted traffic + # expires in `expire` seconds + def find_session_source_id_unsecure(source_node_id, expire) + var session = self.get_session_by_source_node_id(source_node_id) + if session == nil + session = matter.Session(self, 0, 0) + session._source_node_id = source_node_id + self.sessions.push(session) + session.set_expire_in_seconds(expire) + end + session.update() + return session + end + + ############################################################# + # find session by resumption id + def find_session_by_resumption_id(resumption_id) + import string + if !resumption_id return nil end + var i = 0 + var sessions = self.sessions + while i < size(sessions) + var session = sessions[i] + tasmota.log(string.format("MTR: session.resumption_id=%s vs %s", str(session.resumption_id), str(resumption_id))) + if session.resumption_id == resumption_id && session.shared_secret != nil + tasmota.log(string.format("MTR: session.shared_secret=%s", str(session.shared_secret))) + session.update() + return session + end + i += 1 + end + end + + ############################################################# + # list of sessions that are active, i.e. have been + # successfully commissioned + # + def sessions_active() + var ret = [] + var idx = 0 + while idx < size(self.sessions) + var session = self.sessions[idx] + if session.get_device_id() && session.get_fabric_id() + ret.push(session) + end + idx += 1 + end + return ret + end + + ############################################################# + def save_fabrics() + import json + self.remove_expired() # clean before saving + var sessions_saved = 0 + + var fabs = [] + for f : self.fabrics.persistables() + for _ : f._sessions.persistables() sessions_saved += 1 end # count persitable sessions + fabs.push(f.tojson()) + end + var fabs_size = size(fabs) + fabs = "[" + fabs.concat(",") + "]" + + try + import string + + var f = open(self._FABRICS, "w") + f.write(fabs) + f.close() + tasmota.log(string.format("MTR: =Saved %i fabric(s) and %i session(s)", fabs_size, sessions_saved), 2) + except .. as e, m + tasmota.log("MTR: Session_Store::save Exception:" + str(e) + "|" + str(m), 2) + end + end + + ############################################################# + # load fabrics and associated sessions + def load_fabrics() + import string + try + self.sessions = matter.Expirable_list() # remove any left-over + self.fabrics = matter.Expirable_list() # remove any left-over + var f = open(self._FABRICS) + var file_content = f.read() + f.close() + + import json + var file_json = json.load(file_content) + file_content = nil + tasmota.gc() # clean-up a potential long string + + for v : file_json # iterate on values + # read fabric + var fabric = matter.Fabric.fromjson(self, v) + fabric.set_no_expiration() + fabric.set_persist(true) + + # iterate on sessions + var sessions_json = v.find("_sessions", []) + + for sess_json : sessions_json + var session = matter.Session.fromjson(self, sess_json, fabric) + if session != nil + session.set_no_expiration() + session.set_persist(true) + self.add_session(session) + fabric.add_session(session) + end + end + + self.fabrics.push(fabric) + end + + tasmota.log(string.format("MTR: Loaded %i fabric(s)", size(self.fabrics)), 2) + except .. as e, m + if e != "io_error" + tasmota.log("MTR: Session_Store::load Exception:" + str(e) + "|" + str(m), 2) + end + end + # persistables are normally not expiring + # if self.remove_expired() # clean after load + # self.save_fabrics() + # end + end + + ############################################################# + def create_fabric() + var fabric = matter.Fabric(self) + return fabric + end +end +matter.Session_Store = Matter_Session_Store diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be index 8e927da7c..5aae42d03 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_TLV.be @@ -46,6 +46,20 @@ class Matter_TLV ] # type values (enum like) + # + # Type|Description + # :----|:--- + # I1 I2 I4|Signed integer of at most (1/2/4) bytes (as 32 bits signed Berry type) + # U1 U2 U4|Unsiged integer of at motst (1/2/4) bytes (as 32 bits signed Berry type, be careful when comparing. Use `matter.Counter.is_greater(a,b)`) + # I8 U8|Signed/insigned 8 bytes. You can pass `bytes(8)`, `int64()` or `int`. Type is collapsed to a lower type if possible when encoding. + # BOOL|boolean, takes `true` and `false`. Abstracts the internal `BTRUE` and `BFALSE` that you don't need to use + # FLOAT|32 bites float + # UTF1 UTF2|String as UTF, size is encoded as 1 or 2 bytes automatically + # B1 B2|raw `bytes()`, size is encoded as 1 or 2 bytes automatically + # NULL|takes only `nil` value + # STRUCT
ARRAY
LIST
EOC|(internal) Use through abstractions + # DOUBLE
UTF4 UTF8
B4 B8|Unsuppored in Tasmota + static var I1 = 0x00 static var I2 = 0x01 static var I4 = 0x02 @@ -107,7 +121,7 @@ class Matter_TLV ############################################################# # create simple TLV static def create_TLV(t, value) - if value != nil + if value != nil || t == 0x14 #-t == matter.TLV.NULL-# # put the actual number for performance var v = _class() # parent is nil v.typ = t v.val = value @@ -206,7 +220,7 @@ class Matter_TLV # encode TLV # # appends to the bytes() object - def encode(b) + def tlv2raw(b) var TLV = self.TLV if b == nil b = bytes() end # start new buffer if none passed @@ -297,6 +311,83 @@ class Matter_TLV return b end + ############################################################# + # compute the length in bytes of encoded TLV without actually + # allocating buffers (faster and no memory fragmentation) + # + # returns a number of bytes + def encode_len() + var TLV = self.TLV + var len = 0 + + # special case for bool + # we need to change the type according to the value + if self.typ == TLV.BFALSE || self.typ == TLV.BTRUE + self.typ = bool(self.val) ? TLV.BTRUE : TLV.BFALSE + # try to compress ints + elif self.typ >= TLV.I2 && self.typ <= TLV.I4 + var i = int(self.val) + if i <= 127 && i >= -128 self.typ = TLV.I1 + elif i <= 32767 && i >= -32768 self.typ = TLV.I2 + end + elif self.typ >= TLV.U2 && self.typ <= TLV.U4 + var i = int(self.val) + if i <= 255 && i >= 0 self.typ = TLV.U1 + elif i <= 65535 && i >= 0 self.typ = TLV.U2 + end + elif self.typ >= TLV.B1 && self.typ <= TLV.B8 # encode length as minimum possible + if size(self.val) <= 255 + self.typ = TLV.B1 + elif size(self.val) <= 65535 + self.typ = TLV.B2 + else + self.typ = TLV.B4 # B4 is unlikely, B8 is impossible + end + elif self.typ >= TLV.UTF1 && self.typ <= TLV.UTF8 + if size(self.val) <= 255 + self.typ = TLV.UTF1 + elif size(self.val) <= 65535 + self.typ = TLV.UTF2 + else + self.typ = TLV.UTF4 # UTF4 is unlikely, UTF8 is impossible + end + end + + # encode tag and type + len += self._encode_tag_len() + # encode value + + if self.typ == TLV.I1 || self.typ == TLV.U1 + len += 1 + elif self.typ == TLV.I2 || self.typ == TLV.U2 + len += 2 + elif self.typ == TLV.I4 || self.typ == TLV.U4 + len += 4 + elif self.typ == TLV.I8 || self.typ == TLV.U8 + len += 8 + elif self.typ == TLV.BFALSE || self.typ == TLV.BTRUE + # push nothing + elif self.typ == TLV.FLOAT + len += 4 + elif self.typ == TLV.DOUBLE + raise "value_error", "Unsupported type TLV.DOUBLE" + elif self.typ == TLV.UTF1 + len += 1 + size(self.val) + elif self.typ == TLV.UTF2 + len += 2 + size(self.val) + elif self.typ == TLV.B1 + len += 1 + size(self.val) + elif self.typ == TLV.B2 + len += 2 + size(self.val) + elif self.typ == TLV.NULL + # push nothing + else + raise "value_error", "unsupported type " + str(self.typ) + end + + return len + end + ############################################################# # internal_function # encode Tag+Type as the first bytes @@ -341,6 +432,39 @@ class Matter_TLV end end + ############################################################# + # internal_function + # compute len of Tag+Type as the first bytes + def _encode_tag_len() + var tag_number = self.tag_number != nil ? self.tag_number : 0 + var tag_huge = (tag_number >= 65536) || (tag_number < 0) + var tag_control = 0x00 + if self.tag_vendor != nil + # full encoding + if tag_huge + return 9 + else + return 7 + end + elif self.tag_profile == -1 # Matter Common profile + if tag_huge + return 5 + else + return 3 + end + elif self.tag_profile != nil + if tag_huge + return 5 + else + return 3 + end + elif self.tag_sub != nil + return 2 + else # anonymous tag + return 1 + end + end + ############################################################# # Compare the value index with an element # returns: @@ -494,22 +618,21 @@ class Matter_TLV end ############################################################# - # encode TLV - # - # appends to the bytes() object - def _encode_inner(b, is_struct) + # encode to bytes + def tlv2raw(b) if b == nil b = bytes() end # encode tag and type self._encode_tag(b) # sort values - var val_list = self.val.copy() - if is_struct + var val_list = self.val + if self.is_struct + val_list = val_list.copy() self.sort(val_list) end # output each one after the other for v : val_list - v.encode(b) + v.tlv2raw(b) end # add 'end of container' @@ -519,9 +642,22 @@ class Matter_TLV end ############################################################# - # encode to bytes - def encode(b) - return self._encode_inner(b, self.is_struct) + # compute the length in bytes of encoded TLV without actually + # allocating buffers (faster and no memory fragmentation) + # + # returns a number of bytes + def encode_len() + # tag and type + var len = self._encode_tag_len() + # output each one after the other, order doesn't infulence size + var idx = 0 + while idx < size(self.val) + len += self.val[idx].encode_len() + idx += 1 + end + # add 'end of container' + len += 1 + return len end ############################################################# @@ -760,117 +896,52 @@ matter.TLV = Matter_TLV # Test import matter -#load("Matter_TLV.be") +def test_TLV(b, s) + var m = matter.TLV.parse(b) + assert(m.tostring() == s) + assert(m.tlv2raw() == b) + assert(m.encode_len() == size(b)) +end -var m -m = matter.TLV.parse(bytes("2502054C")) -assert(m.tostring() == "2 = 19461U") -assert(m.encode() == bytes("2502054C")) +test_TLV(bytes("2502054C"), "2 = 19461U") +test_TLV(bytes("0001"), "1") +test_TLV(bytes("08"), "false") +test_TLV(bytes("09"), "true") -m = matter.TLV.parse(bytes("0001")) -assert(m.tostring() == "1") -assert(m.encode() == bytes("0001")) +test_TLV(bytes("00FF"), "-1") +test_TLV(bytes("05FFFF"), "65535U") -m = matter.TLV.parse(bytes("08")) -assert(m.tostring() == "false") -assert(m.encode() == bytes("08")) -m = matter.TLV.parse(bytes("09")) -assert(m.tostring() == "true") -assert(m.encode() == bytes("09")) - -m = matter.TLV.parse(bytes("01FFFF")) -assert(m.tostring() == "-1") -assert(m.encode() == bytes("00FF")) -m = matter.TLV.parse(bytes("05FFFF")) -assert(m.tostring() == "65535U") -assert(m.encode() == bytes("05FFFF")) - -m = matter.TLV.parse(bytes("0A0000C03F")) -assert(m.tostring() == "1.5") -assert(m.encode() == bytes("0A0000C03F")) - -m = matter.TLV.parse(bytes("0C06466f6f626172")) -assert(m.tostring() == '"Foobar"') -assert(m.encode() == bytes("0C06466f6f626172")) - -m = matter.TLV.parse(bytes("1006466f6f626172")) -assert(m.tostring() == "466F6F626172") -assert(m.encode() == bytes("1006466f6f626172")) - -m = matter.TLV.parse(bytes("e4f1ffeddeedfe55aa2a")) -assert(m.tostring() == "0xFFF1::0xDEED:0xAA55FEED = 42U") -assert(m.encode() == bytes("e4f1ffeddeedfe55aa2a")) - - -m = matter.TLV.parse(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66")) -assert(m.tostring() == "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66") -assert(m.encode() == bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66")) +test_TLV(bytes("0A0000C03F"), "1.5") +test_TLV(bytes("0C06466f6f626172"), '"Foobar"') +test_TLV(bytes("1006466f6f626172"), "466F6F626172") +test_TLV(bytes("e4f1ffeddeedfe55aa2a"), "0xFFF1::0xDEED:0xAA55FEED = 42U") +test_TLV(bytes("300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66"), "1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66") # context specific -m = matter.TLV.parse(bytes("24012a")) -assert(m.tostring() == "1 = 42U") -assert(m.encode() == bytes("24012a")) - -m = matter.TLV.parse(bytes("4401002a")) -assert(m.tostring() == "Matter::0x00000001 = 42U") -assert(m.encode() == bytes("4401002a")) +test_TLV(bytes("24012a"), "1 = 42U") +test_TLV(bytes("4401002a"), "Matter::0x00000001 = 42U") # int64 -m = matter.TLV.parse(bytes("030102000000000000")) -assert(m.tostring() == "513") -assert(m.encode() == bytes("030102000000000000")) - -m = matter.TLV.parse(bytes("070102000000000000")) -assert(m.tostring() == "513U") -assert(m.encode() == bytes("070102000000000000")) - -m = matter.TLV.parse(bytes("03FFFFFFFFFFFFFFFF")) -assert(m.tostring() == "-1") -assert(m.encode() == bytes("03FFFFFFFFFFFFFFFF")) - -m = matter.TLV.parse(bytes("07FFFFFFFFFFFFFF7F")) -assert(m.tostring() == "9223372036854775807U") -assert(m.encode() == bytes("07FFFFFFFFFFFFFF7F")) +test_TLV(bytes("030102000000000000"), "513") +test_TLV(bytes("070102000000000000"), "513U") +test_TLV(bytes("03FFFFFFFFFFFFFFFF"), "-1") +test_TLV(bytes("07FFFFFFFFFFFFFF7F"), "9223372036854775807U") # structure -m = matter.TLV.parse(bytes("1518")) -assert(m.tostring() == "{}") -assert(m.encode() == bytes("1518")) - -m = matter.TLV.parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418")) -assert(m.tostring() == "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}") -assert(m.encode() == bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418")) - -m = matter.TLV.parse(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) -assert(m.tostring() == "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}") -assert(m.encode() == bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818")) +test_TLV(bytes("1518"), "{}") +test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280418"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false}") +test_TLV(bytes("15300120D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D662502054C240300280435052501881325022C011818"), "{1 = D2DAEE8760C9B1D1B25E0E2E4DD6ECA8AEF6193C0203761356FCB06BBEDD7D66, 2 = 19461U, 3 = 0U, 4 = false, 5 = {1 = 5000U, 2 = 300U}}") # list -m = matter.TLV.parse(bytes("1718")) -assert(m.tostring() == "[[]]") -assert(m.encode() == bytes("1718")) - -m = matter.TLV.parse(bytes("17000120002a000200032000ef18")) -assert(m.tostring() == "[[1, 0 = 42, 2, 3, 0 = -17]]") -assert(m.encode() == bytes("17000120002a000200032000ef18")) - +test_TLV(bytes("1718"), "[[]]") +test_TLV(bytes("17000120002a000200032000ef18"), "[[1, 0 = 42, 2, 3, 0 = -17]]") # array -m = matter.TLV.parse(bytes("1618")) -assert(m.tostring() == "[]") -assert(m.encode() == bytes("1618")) - -m = matter.TLV.parse(bytes("160000000100020003000418")) -assert(m.tostring() == "[0, 1, 2, 3, 4]") -assert(m.encode() == bytes("160000000100020003000418")) +test_TLV(bytes("1618"), "[]") +test_TLV(bytes("160000000100020003000418"), "[0, 1, 2, 3, 4]") # mix -m = matter.TLV.parse(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118")) -assert(m.tostring() == '[42, -170000, {}, 17.9, "Hello!"]') -assert(m.encode() == bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118")) - -m = matter.TLV.parse(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118")) -assert(m.tostring() == '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}') -assert(m.encode() == bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118")) +test_TLV(bytes("16002a02f067fdff15180a33338f410c0648656c6c6f2118"), '[42, -170000, {}, 17.9, "Hello!"]') +test_TLV(bytes("153600172403312504FCFF18172402002403302404001817240200240330240401181724020024033024040218172402002403302404031817240200240328240402181724020024032824040418172403312404031818280324FF0118"), '{0 = [[[3 = 49U, 4 = 65532U]], [[2 = 0U, 3 = 48U, 4 = 0U]], [[2 = 0U, 3 = 48U, 4 = 1U]], [[2 = 0U, 3 = 48U, 4 = 2U]], [[2 = 0U, 3 = 48U, 4 = 3U]], [[2 = 0U, 3 = 40U, 4 = 2U]], [[2 = 0U, 3 = 40U, 4 = 4U]], [[3 = 49U, 4 = 3U]]], 3 = false, 255 = 1U}') -# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be b/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be index 75df885c3..3578b7155 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_UDPServer.be @@ -33,33 +33,28 @@ import matter # A packet that needs to be resent if not acknowledged by the other party ################################################################################# class Matter_UDPPacket_sent - static var RETRY_MS = 500 # retry every 500 ms - static var RETRIES = 4 # retry every 500 ms var raw # bytes() to be sent var addr # ip_address (string) var port # port (int) - var msg_id # (int) message identifier that needs to be acknowledged - var retries # how many retries are allowed, when `0` drop and log + var msg_id # (int) message identifier that needs to be acknowledged, or `nil` if no ack needed + var exchange_id # (int) exchange id, to match ack + var session_id # (int) session id, for logging only + var retries # 0 in first attempts, goes up to RETRIES var next_try # timestamp (millis) when to try again - def init(raw, addr, port, id) - self.raw = raw - self.addr = addr - self.port = port - self.msg_id = id - self.retries = self.RETRIES - self.next_try = tasmota.millis() + self.RETRY_MS + def init(msg) + # extract information from msg + self.raw = msg.raw + self.addr = msg.remote_ip + self.port = msg.remote_port + self.msg_id = msg.x_flag_r ? msg.message_counter : nil + self.exchange_id = (msg.exchange_id != nil) ? msg.exchange_id : 0 + self.session_id = (msg.local_session_id != nil) ? msg.local_session_id : 0 + # other information + self.retries = 0 + self.next_try = tasmota.millis() + matter.UDPServer._backoff_time(self.retries) end - def send(udp_socket) - import string - var ok = udp_socket.send(self.addr ? self.addr : udp_socket.remote_ip, self.port ? self.port : udp_socket.remote_port, self.raw) - if ok - tasmota.log(string.format("MTR: sending packet to '[%s]:%i'", self.addr, self.port), 3) - else - tasmota.log(string.format("MTR: failed to send packet to '[%s]:%i'", self.addr, self.port), 2) - end - end end matter.UDPPacket_sent = Matter_UDPPacket_sent @@ -68,31 +63,35 @@ matter.UDPPacket_sent = Matter_UDPPacket_sent # ################################################################################# class Matter_UDPServer + static var RETRIES = 5 # 6 transmissions max (5 retries) - 1 more than spec `MRP_MAX_TRANSMISSIONS` 4.11.8 p.146 static var MAX_PACKETS_READ = 4 # read at most 4 packets per tick - var address, port # local address and port + var addr, port # local addr and port var listening # true if active var udp_socket var dispatch_cb # callback to call when a message is received - var packets_sent # map of packets sent to be acknowledged + var packets_sent # list map of packets sent to be acknowledged ############################################################# - def init(address, port) - self.address = address ? address : "" + # Init UDP Server listening to `addr` and `port` (opt). + # + # By default, the server listens to `""` (all addresses) and port `5540` + def init(addr, port) + self.addr = addr ? addr : "" self.port = port ? port : 5540 self.listening = false - self.packets_sent = {} + self.packets_sent = [] end ############################################################# - # start the server - # raises an exception if something is wrong - # registers as device handle + # Starts the server. + # Registers as device handler to Tasmota # - # `cb`: callback to call when a message is received + # `cb(packet, from_addr, from_port)`: callback to call when a message is received. + # Raises an exception if something is wrong. def start(cb) if !self.listening self.udp_socket = udp() - var ok = self.udp_socket.begin(self.address, self.port) + var ok = self.udp_socket.begin(self.addr, self.port) if !ok raise "network_error", "could not open UDP server" end self.listening = true self.dispatch_cb = cb @@ -101,8 +100,7 @@ class Matter_UDPServer end ############################################################# - # stop the server - # remove driver + # Stops the server and remove driver def stop() if self.listening self.udp_socket.stop() @@ -112,6 +110,11 @@ class Matter_UDPServer end ############################################################# + # At every tick: + # Check if a packet has arrived, and dispatch to `cb`. + # Read at most `MAX_PACKETS_READ (4) packets at each tick to + # avoid any starvation. + # Then resend queued outgoing packets. def every_50ms() import string var packet_read = 0 @@ -122,7 +125,7 @@ class Matter_UDPServer packet_read += 1 var from_addr = self.udp_socket.remote_ip var from_port = self.udp_socket.remote_port - tasmota.log(string.format("MTR: UDP received from [%s]:%i", from_addr, from_port), 4) + tasmota.log(string.format("MTR: UDP received from [%s]:%i", from_addr, from_port), 3) if self.dispatch_cb self.dispatch_cb(packet, from_addr, from_port) end @@ -133,41 +136,81 @@ class Matter_UDPServer packet = nil end end - self.resend_packets() # resend any packet + self._resend_packets() # resend any packet end ############################################################# - def resend_packets() - for packet:self.packets_sent + # Send packet now. + # + # Returns `true` if packet was successfully sent. + def send(packet) + import string + var ok = self.udp_socket.send(packet.addr ? packet.addr : self.udp_socket.remote_ip, packet.port ? packet.port : self.udp_socket.remote_port, packet.raw) + if ok + tasmota.log(string.format("MTR: sending packet to '[%s]:%i'", packet.addr, packet.port), 4) + else + tasmota.log(string.format("MTR: error sending packet to '[%s]:%i'", packet.addr, packet.port), 2) + end + return ok + end + + ############################################################# + # Resend packets if they have not been acknowledged by receiver + # either with direct Ack packet or ack embedded in another packet. + # Packets with `id`=`nil` are not resent. + #
+ # Packets are re-sent at most `RETRIES` (4) times, i.e. sent maximum 5 times. + # Exponential backoff is added after each resending. + #
+ # If all retries expired, remove packet and log. + def _resend_packets() + var idx = 0 + while idx < size(self.packets_sent) + var packet = self.packets_sent[idx] if tasmota.time_reached(packet.next_try) - tasmota.log("MTR: resending packet id=" + str(packet.msg_id), 3) - packet.send(self.udp_socket) # resend - packet.retries -= 1 - if packet.retries <= 0 - self.packets_sent.remove(packet.msg_id) + if packet.retries <= self.RETRIES + tasmota.log("MTR: . Resending packet id=" + str(packet.msg_id), 3) + self.send(packet) + packet.next_try = tasmota.millis() + self._backoff_time(packet.retries) + packet.retries += 1 + idx += 1 else - packet.next_try = tasmota.millis() + packet.RETRY_MS + import string + self.packets_sent.remove(idx) + tasmota.log(string.format("MTR: . (%6i) Unacked packet '[%s]:%i' msg_id=%i", packet.session_id, packet.addr, packet.port, packet.msg_id), 2) end + else + idx += 1 end end end ############################################################# - # just received acknowledgment, remove packet from sender - def packet_ack(id) + # Just received acknowledgment, remove packet from sender + def received_ack(msg) + var id = msg.ack_message_counter + var exch = msg.exchange_id if id == nil return end - if self.packets_sent.contains(id) - self.packets_sent.remove(id) - tasmota.log("MTR: removed packet from sending list id=" + str(id), 3) + tasmota.log("MTR: receveived ACK id="+str(id), 3) + var idx = 0 + while idx < size(self.packets_sent) + var packet = self.packets_sent[idx] + if packet.msg_id == id && packet.exchange_id == exch + self.packets_sent.remove(idx) + tasmota.log("MTR: . Removed packet from sending list id=" + str(id), 3) + else + idx += 1 + end end end ############################################################# - def send_response(raw, addr, port, id) - var packet = matter.UDPPacket_sent(raw, addr, port, id) - packet.send(self.udp_socket) # send - if id - self.packets_sent[id] = packet + # Send a packet, enqueue it if `id` is not `nil` + def send_UDP(msg) + var packet = matter.UDPPacket_sent(msg) + self.send(packet) + if packet.msg_id + self.packets_sent.push(packet) end end @@ -175,13 +218,25 @@ class Matter_UDPServer # placeholder, nothing to run for now def every_second() end + + ############################################################# + # Compute exponential backoff as per 4.11.2.1 p.137 + static def _backoff_time(n) + def power_int(v, n) + var r = 1 + while n > 0 + r *= v + n -= 1 + end + return r + end + + import math + var i = 300 # SLEEPY_ACTIVE_INTERVAL + var rand = real(math.rand() & 0xFF) / 255 # 0..1 with reasonable granularity + var n_power = n > 0 ? n - 1 : 0 + var mrpBackoffTime = i * power_int(1.6, n_power) * (1.0 + rand * 0.25 ) + return int(mrpBackoffTime) + end end matter.UDPServer = Matter_UDPServer - -#- - -import matter -var udps = matter.UDPServer() -udps.listen() - --# diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be index 7bd6921f4..605c55738 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be @@ -70,12 +70,60 @@ class Matter_UI webserver.content_send(string.format("

") - + webserver.content_send("

") return matter_enabled end + #- ---------------------------------------------------------------------- -# + #- Show QR Code + #- ---------------------------------------------------------------------- -# + def show_qrcode(qr_text) + import webserver + # QRCode via UTF8 + var empty = " " + var lowhalf = "\342\226\204" + var uphalf = "\342\226\200" + var full = "\342\226\210" + + var qr = matter.QRCode.encode_str(qr_text) + var bitmap = qr['bitmap'] + var sz = qr['size'] + + webserver.content_send('') + + + webserver.content_send("
") + + var s = "
" + webserver.content_send(s) + s = "" + for i: 0 .. sz + 1 s += lowhalf end + s += "
" + webserver.content_send(s) + for i: 0 .. (sz+1)/2 - 1 + s = "
" + full + for j: 0 .. sz - 1 + var high = (bitmap[i*2][j] == " ") + var low = (i*2+1 < sz) ? (bitmap[i*2+1][j] == " ") : true # default to true for bottom margin if size is odd + s += high ? (low ? full : uphalf) : (low ? lowhalf : empty) + end + s += full + s += "
" + webserver.content_send(s) + end + # webserver.content_send("
") + if sz % 2 == 0 + s = "
" + for i: 0 .. sz + 1 s += uphalf end + s += "/
" + webserver.content_send(s) + end + + webserver.content_send("
") + end + #- ---------------------------------------------------------------------- -# #- Show commissioning information and QR Code #- ---------------------------------------------------------------------- -# @@ -83,24 +131,40 @@ class Matter_UI import webserver import string - webserver.content_send("
 Matter Passcode 

") + var seconds_left = (self.device.commissioning_open - tasmota.millis()) / 1000 + if seconds_left < 0 seconds_left = 0 end + var min_left = (seconds_left + 30) / 60 + + webserver.content_send(string.format("
 Commissioning open for %i min 

", min_left)) var pairing_code = self.device.compute_manual_pairing_code() webserver.content_send(string.format("

Manual pairing code:
%s-%s-%s


", pairing_code[0..3], pairing_code[4..6], pairing_code[7..])) - - var qr_text = self.device.compute_qrcode_content() - webserver.content_send('
') - webserver.content_send(string.format('', qr_text)) - webserver.content_send(string.format("

%s


", qr_text)) + webserver.content_send(string.format("
")) + var qr_text = self.device.compute_qrcode_content() + self.show_qrcode(qr_text) + webserver.content_send(string.format("

%s

", qr_text)) + webserver.content_send(string.format("
")) + + webserver.content_send("

") + + end + + #- ---------------------------------------------------------------------- -# + #- Show Passcode / discriminator form + #- ---------------------------------------------------------------------- -# + def show_passcode_form() + import webserver + import string + + webserver.content_send("
 Matter Passcode 

") webserver.content_send("
") webserver.content_send("

Passcode:

") - webserver.content_send(string.format("", self.device.passcode)) + webserver.content_send(string.format("", self.device.root_passcode)) webserver.content_send("

Distinguish id:

") - webserver.content_send(string.format("", self.device.discriminator)) + webserver.content_send(string.format("", self.device.root_discriminator)) + webserver.content_send(string.format("

IPv4 only

", self.device.ipv4only ? " checked" : "")) webserver.content_send("

") - - webserver.content_send("

") end @@ -108,52 +172,42 @@ class Matter_UI #- ---------------------------------------------------------------------- -# #- Show commissioning information and QR Code #- ---------------------------------------------------------------------- -# - def show_session_info(p) + def show_fabric_info(p) import webserver import string - webserver.content_send("
 Sessions 

") - webserver.content_send("

Existing sessions:

") + webserver.content_send("
 Fabrics 

") + webserver.content_send("

Existing fabrics:

") if size(self.device.sessions.sessions) == 0 webserver.content_send("

None

") else - var i = 0 - var sz = size(self.device.sessions.sessions) - while i < sz - var s = self.device.sessions.sessions[i] - if s.fabric - webserver.content_send(string.format("
 Session %i 

", s.local_session_id)) - if i != 0 webserver.content_send("
") end - var fabric_rev = s.fabric.copy().reverse() - var deviceid_rev = s.deviceid.copy().reverse() - webserver.content_send(string.format("Fabric: %s
", fabric_rev.tohex())) - webserver.content_send(string.format("Device: %s
 ", deviceid_rev.tohex())) + var first = true + for f : self.device.sessions.fabrics.persistables() + if !first webserver.content_send("
") end + first = false - webserver.content_send("
") - webserver.content_send(string.format("", s.local_session_id)) - webserver.content_send("

") - - webserver.content_send("

") - end - i += 1 + var label = f.fabric_label + if !label label = "" end + label = webserver.html_escape(label) # protect against HTML injection + + webserver.content_send(string.format("
 #%i %s 

", f.get_fabric_index(), label)) + + var fabric_rev = f.get_fabric_id().copy().reverse() + var deviceid_rev = f.get_device_id().copy().reverse() + webserver.content_send(string.format("Fabric: %s
", fabric_rev.tohex())) + webserver.content_send(string.format("Device: %s
 ", deviceid_rev.tohex())) + + webserver.content_send("
") + webserver.content_send(string.format("", f.get_fabric_index())) + webserver.content_send("

") + + webserver.content_send("

") end end webserver.content_send("

") - - end - - ####################################################################### - # Serve qrcode.min.js static file - ####################################################################### - def page_qrcode_min_js() - import webserver - - webserver.content_open(200, "text/javascript") - webserver.content_send(matter._QRCODE_MINJS) end ####################################################################### @@ -162,17 +216,15 @@ class Matter_UI def page_part_mgr() import webserver import string - + if !webserver.check_privileged_access() return nil end webserver.content_start("Matter") #- title of the web page -# webserver.content_send_style() #- send standard Tasmota styles -# - webserver.content_send('') - if self.show_enable() - self.show_commissioning_info() - self.show_session_info() + self.show_passcode_form() + self.show_fabric_info() end webserver.content_button(webserver.BUTTON_CONFIGURATION) webserver.content_stop() #- end of web page -# @@ -188,23 +240,24 @@ class Matter_UI import string import partition_core import persist - + #- check that the partition is valid -# var p = partition_core.Partition() try - + #---------------------------------------------------------------------# # Change Passcode and/or Passcode #---------------------------------------------------------------------# if webserver.has_arg("passcode") || webserver.has_arg("discriminator") if webserver.has_arg("passcode") - self.device.passcode = int(webserver.arg("passcode")) + self.device.root_passcode = int(webserver.arg("passcode")) end if webserver.has_arg("discriminator") - self.device.discriminator = int(webserver.arg("discriminator")) + self.device.root_discriminator = int(webserver.arg("discriminator")) end + self.device.ipv4only = webserver.arg("ipv4") == 'on' self.device.save_param() #- and force restart -# @@ -220,15 +273,21 @@ class Matter_UI #- and force restart -# webserver.redirect("/?rst=") - elif webserver.has_arg("del_session") - var session = self.device.sessions.get_session_by_local_session_id(int(webserver.arg("del_session"))) - if session != nil - self.device.sessions.remove_session(session) - self.device.sessions.save() + elif webserver.has_arg("del_fabric") + var del_fabric = int(webserver.arg("del_fabric")) + var idx = 0 + var fabrics = self.device.sessions.fabrics + while idx < size(fabrics) + if fabrics[idx].get_fabric_index() == del_fabric + self.device.remove_fabric(fabrics[idx]) + break + else + idx += 1 + end end #- and force restart -# - webserver.redirect("/?rst=") + webserver.redirect("/matterc?") end except .. as e, m @@ -244,6 +303,46 @@ class Matter_UI end end + #- display sensor value in the web UI -# + def web_sensor() + import webserver + import string + + var matter_enabled = tasmota.get_option(matter.MATTER_OPTION) + + if matter_enabled + if self.device.is_root_commissioning_open() + self.show_commissioning_info() + end + + # mtc0 = close, mtc1 = open commissioning + var fabrics_count = self.device.sessions.count_active_fabrics() + if fabrics_count == 0 + webserver.content_send(string.format("
%s
", "No active association")) + else + var plural = fabrics_count > 1 + webserver.content_send(string.format("
%s
", str(fabrics_count) + " active association" + (plural ? "s" : ""))) + end + + webserver.content_send(string.format("") + else + webserver.content_send(" Close Commissioning") + end + end + end + + def web_get_arg() + import webserver + if webserver.has_arg("mtc0") # Close Commissioning + self.device.stop_basic_commissioning() + elif webserver.has_arg("mtc1") # Open Commissioning + self.device.start_root_basic_commissioning() + end + end + #- ---------------------------------------------------------------------- -# # respond to web_add_handler() event to register web listeners #- ---------------------------------------------------------------------- -# @@ -253,7 +352,6 @@ class Matter_UI #- we need to register a closure, not just a function, that captures the current instance -# webserver.on("/matterc", / -> self.page_part_mgr(), webserver.HTTP_GET) webserver.on("/matterc", / -> self.page_part_ctl(), webserver.HTTP_POST) - webserver.on("/qrcode.min.js", / -> self.page_qrcode_min_js(), webserver.HTTP_GET) end end matter.UI = Matter_UI diff --git a/lib/libesp32/berry_matter/src/qrcodegen.c b/lib/libesp32/berry_matter/src/qrcodegen.c new file mode 100644 index 000000000..37ee74233 --- /dev/null +++ b/lib/libesp32/berry_matter/src/qrcodegen.c @@ -0,0 +1,1035 @@ +/* + * QR Code generator library (C) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * 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 +#include +#include +#include "qrcodegen.h" + +#ifndef QRCODEGEN_TEST + #define testable static // Keep functions private +#else + #define testable // Expose private functions +#endif + + +/*---- Forward declarations for private functions ----*/ + +// Regarding all public and private functions defined in this source file: +// - They require all pointer/array arguments to be not null unless the array length is zero. +// - They only read input scalar/array arguments, write to output pointer/array +// arguments, and return scalar values; they are "pure" functions. +// - They don't read mutable global variables or write to any global variables. +// - They don't perform I/O, read the clock, print to console, etc. +// - They allocate a small and constant amount of stack memory. +// - They don't allocate or free any memory on the heap. +// - They don't recurse or mutually recurse. All the code +// could be inlined into the top-level public functions. +// - They run in at most quadratic time with respect to input arguments. +// Most functions run in linear time, and some in constant time. +// There are no unbounded loops or non-obvious termination conditions. +// - They are completely thread-safe if the caller does not give the +// same writable buffer to concurrent calls to these functions. + +testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen); + +testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]); +testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); +testable int getNumRawDataModules(int ver); + +testable void calcReedSolomonGenerator(int degree, uint8_t result[]); +testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, + const uint8_t generator[], int degree, uint8_t result[]); +testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y); + +testable void initializeFunctionModules(int version, uint8_t qrcode[]); +static void drawWhiteFunctionModules(uint8_t qrcode[], int version); +static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]); +testable int getAlignmentPatternPositions(int version, uint8_t result[7]); +static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]); + +static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]); +static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask); +static long getPenaltyScore(const uint8_t qrcode[]); +static void addRunToHistory(unsigned char run, unsigned char history[7]); +static bool hasFinderLikePattern(const unsigned char runHistory[7]); + +testable bool getModule(const uint8_t qrcode[], int x, int y); +testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack); +testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack); +static bool getBit(int x, int i); + +testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars); +testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version); +static int numCharCountBits(enum qrcodegen_Mode mode, int version); + + + +/*---- Private tables of constants ----*/ + +// The set of all legal characters in alphanumeric mode, where each character +// value maps to the index in the string. For checking text and encoding segments. +static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + +// For generating error correction codes. +testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low + {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium + {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile + {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High +}; + +#define qrcodegen_REED_SOLOMON_DEGREE_MAX 30 // Based on the table above + +// For generating error correction codes. +testable const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low + {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium + {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile + {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High +}; + +// For automatic mask pattern selection. +static const int PENALTY_N1 = 3; +static const int PENALTY_N2 = 3; +static const int PENALTY_N3 = 40; +static const int PENALTY_N4 = 10; + + + +/*---- High-level QR Code encoding functions ----*/ + +// Public function - see documentation comment in header file. +bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], + enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { + + size_t textLen = strlen(text); + if (textLen == 0) + return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); + size_t bufLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); + + struct qrcodegen_Segment seg; + if (qrcodegen_isNumeric(text)) { + if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) + goto fail; + seg = qrcodegen_makeNumeric(text, tempBuffer); + } else if (qrcodegen_isAlphanumeric(text)) { + if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) + goto fail; + seg = qrcodegen_makeAlphanumeric(text, tempBuffer); + } else { + if (textLen > bufLen) + goto fail; + for (size_t i = 0; i < textLen; i++) + tempBuffer[i] = (uint8_t)text[i]; + seg.mode = qrcodegen_Mode_BYTE; + seg.bitLength = calcSegmentBitLength(seg.mode, textLen); + if (seg.bitLength == -1) + goto fail; + seg.numChars = (int)textLen; + seg.data = tempBuffer; + } + return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); + +fail: + qrcode[0] = 0; // Set size to invalid value for safety + return false; +} + + +// Public function - see documentation comment in header file. +bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], + enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { + + struct qrcodegen_Segment seg; + seg.mode = qrcodegen_Mode_BYTE; + seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); + if (seg.bitLength == -1) { + qrcode[0] = 0; // Set size to invalid value for safety + return false; + } + seg.numChars = (int)dataLen; + seg.data = dataAndTemp; + return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode); +} + + +// Appends the given number of low-order bits of the given value to the given byte-based +// bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits. +testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) { + assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0); + for (int i = numBits - 1; i >= 0; i--, (*bitLen)++) + buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7)); +} + + + +/*---- Low-level QR Code encoding functions ----*/ + +// Public function - see documentation comment in header file. +bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, + enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) { + return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl, + qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, -1, true, tempBuffer, qrcode); +} + + +// Public function - see documentation comment in header file. +bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, + int minVersion, int maxVersion, int mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) { + assert(segs != NULL || len == 0); + assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX); + assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7); + + // Find the minimal version number to use + int version, dataUsedBits; + for (version = minVersion; ; version++) { + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available + dataUsedBits = getTotalBits(segs, len, version); + if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) + break; // This version number is found to be suitable + if (version >= maxVersion) { // All versions in the range could not fit the given data + qrcode[0] = 0; // Set size to invalid value for safety + return false; + } + } + assert(dataUsedBits != -1); + + // Increase the error correction level while the data still fits in the current version number + for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high + if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) + ecl = (enum qrcodegen_Ecc)i; + } + + // Concatenate all segments to create the data bit string + memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); + int bitLen = 0; + for (size_t i = 0; i < len; i++) { + const struct qrcodegen_Segment *seg = &segs[i]; + appendBitsToBuffer((int)seg->mode, 4, qrcode, &bitLen); + appendBitsToBuffer(seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen); + for (int j = 0; j < seg->bitLength; j++) + appendBitsToBuffer((seg->data[j >> 3] >> (7 - (j & 7))) & 1, 1, qrcode, &bitLen); + } + assert(bitLen == dataUsedBits); + + // Add terminator and pad up to a byte if applicable + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; + assert(bitLen <= dataCapacityBits); + int terminatorBits = dataCapacityBits - bitLen; + if (terminatorBits > 4) + terminatorBits = 4; + appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen); + appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen); + assert(bitLen % 8 == 0); + + // Pad with alternating bytes until data capacity is reached + for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + appendBitsToBuffer(padByte, 8, qrcode, &bitLen); + + // Draw function and data codeword modules + addEccAndInterleave(qrcode, version, ecl, tempBuffer); + initializeFunctionModules(version, qrcode); + drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); + drawWhiteFunctionModules(qrcode, version); + initializeFunctionModules(version, tempBuffer); + + // Handle masking + if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask + long minPenalty = LONG_MAX; + for (int i = 0; i < 8; i++) { + enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i; + applyMask(tempBuffer, qrcode, msk); + drawFormatBits(ecl, msk, qrcode); + long penalty = getPenaltyScore(qrcode); + if (penalty < minPenalty) { + mask = msk; + minPenalty = penalty; + } + applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR + } + } + assert(0 <= (int)mask && (int)mask <= 7); + applyMask(tempBuffer, qrcode, mask); + drawFormatBits(ecl, mask, qrcode); + return true; +} + + + +/*---- Error correction code generation functions ----*/ + +// Appends error correction bytes to each block of the given data array, then interleaves +// bytes from the blocks and stores them in the result array. data[0 : dataLen] contains +// the input data. data[dataLen : rawCodewords] is used as a temporary work area and will +// be clobbered by this function. The final answer is stored in result[0 : rawCodewords]. +testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) { + // Calculate parameter numbers + assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); + int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version]; + int blockEccLen = ECC_CODEWORDS_PER_BLOCK [(int)ecl][version]; + int rawCodewords = getNumRawDataModules(version) / 8; + int dataLen = getNumDataCodewords(version, ecl); + int numShortBlocks = numBlocks - rawCodewords % numBlocks; + int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; + + // Split data into blocks, calculate ECC, and interleave + // (not concatenate) the bytes into a single sequence + uint8_t generator[qrcodegen_REED_SOLOMON_DEGREE_MAX]; + calcReedSolomonGenerator(blockEccLen, generator); + const uint8_t *dat = data; + for (int i = 0; i < numBlocks; i++) { + int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); + uint8_t *ecc = &data[dataLen]; // Temporary storage + calcReedSolomonRemainder(dat, datLen, generator, blockEccLen, ecc); + for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data + if (j == shortBlockDataLen) + k -= numShortBlocks; + result[k] = dat[j]; + } + for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC + result[k] = ecc[j]; + dat += datLen; + } +} + + +// Returns the number of 8-bit codewords that can be used for storing data (not ECC), +// for the given version number and error correction level. The result is in the range [9, 2956]. +testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { + int v = version, e = (int)ecl; + assert(0 <= e && e < 4); + return getNumRawDataModules(v) / 8 + - ECC_CODEWORDS_PER_BLOCK [e][v] + * NUM_ERROR_CORRECTION_BLOCKS[e][v]; +} + + +// Returns the number of data bits that can be stored in a QR Code of the given version number, after +// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. +// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. +testable int getNumRawDataModules(int ver) { + assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX); + int result = (16 * ver + 128) * ver + 64; + if (ver >= 2) { + int numAlign = ver / 7 + 2; + result -= (25 * numAlign - 10) * numAlign - 55; + if (ver >= 7) + result -= 36; + } + return result; +} + + + +/*---- Reed-Solomon ECC generator functions ----*/ + +// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree]. +testable void calcReedSolomonGenerator(int degree, uint8_t result[]) { + // Start with the monomial x^0 + assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); + memset(result, 0, degree * sizeof(result[0])); + result[degree - 1] = 1; + + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), + // drop the highest term, and store the rest of the coefficients in order of descending powers. + // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). + uint8_t root = 1; + for (int i = 0; i < degree; i++) { + // Multiply the current product by (x - r^i) + for (int j = 0; j < degree; j++) { + result[j] = finiteFieldMultiply(result[j], root); + if (j + 1 < degree) + result[j] ^= result[j + 1]; + } + root = finiteFieldMultiply(root, 0x02); + } +} + + +// Calculates the remainder of the polynomial data[0 : dataLen] when divided by the generator[0 : degree], where all +// polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree]. +testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, + const uint8_t generator[], int degree, uint8_t result[]) { + + // Perform polynomial division + assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); + memset(result, 0, degree * sizeof(result[0])); + for (int i = 0; i < dataLen; i++) { + uint8_t factor = data[i] ^ result[0]; + memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0])); + result[degree - 1] = 0; + for (int j = 0; j < degree; j++) + result[j] ^= finiteFieldMultiply(generator[j], factor); + } +} + +#undef qrcodegen_REED_SOLOMON_DEGREE_MAX + + +// Returns the product of the two given field elements modulo GF(2^8/0x11D). +// All inputs are valid. This could be implemented as a 256*256 lookup table. +testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) { + // Russian peasant multiplication + uint8_t z = 0; + for (int i = 7; i >= 0; i--) { + z = (z << 1) ^ ((z >> 7) * 0x11D); + z ^= ((y >> i) & 1) * x; + } + return z; +} + + + +/*---- Drawing function modules ----*/ + +// Clears the given QR Code grid with white modules for the given +// version's size, then marks every function module as black. +testable void initializeFunctionModules(int version, uint8_t qrcode[]) { + // Initialize QR Code + int qrsize = version * 4 + 17; + memset(qrcode, 0, ((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0])); + qrcode[0] = (uint8_t)qrsize; + + // Fill horizontal and vertical timing patterns + fillRectangle(6, 0, 1, qrsize, qrcode); + fillRectangle(0, 6, qrsize, 1, qrcode); + + // Fill 3 finder patterns (all corners except bottom right) and format bits + fillRectangle(0, 0, 9, 9, qrcode); + fillRectangle(qrsize - 8, 0, 8, 9, qrcode); + fillRectangle(0, qrsize - 8, 9, 8, qrcode); + + // Fill numerous alignment patterns + uint8_t alignPatPos[7]; + int numAlign = getAlignmentPatternPositions(version, alignPatPos); + for (int i = 0; i < numAlign; i++) { + for (int j = 0; j < numAlign; j++) { + // Don't draw on the three finder corners + if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) + fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode); + } + } + + // Fill version blocks + if (version >= 7) { + fillRectangle(qrsize - 11, 0, 3, 6, qrcode); + fillRectangle(0, qrsize - 11, 6, 3, qrcode); + } +} + + +// Draws white function modules and possibly some black modules onto the given QR Code, without changing +// non-function modules. This does not draw the format bits. This requires all function modules to be previously +// marked black (namely by initializeFunctionModules()), because this may skip redrawing black function modules. +static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { + // Draw horizontal and vertical timing patterns + int qrsize = qrcodegen_getSize(qrcode); + for (int i = 7; i < qrsize - 7; i += 2) { + setModule(qrcode, 6, i, false); + setModule(qrcode, i, 6, false); + } + + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) + for (int dy = -4; dy <= 4; dy++) { + for (int dx = -4; dx <= 4; dx++) { + int dist = abs(dx); + if (abs(dy) > dist) + dist = abs(dy); + if (dist == 2 || dist == 4) { + setModuleBounded(qrcode, 3 + dx, 3 + dy, false); + setModuleBounded(qrcode, qrsize - 4 + dx, 3 + dy, false); + setModuleBounded(qrcode, 3 + dx, qrsize - 4 + dy, false); + } + } + } + + // Draw numerous alignment patterns + uint8_t alignPatPos[7]; + int numAlign = getAlignmentPatternPositions(version, alignPatPos); + for (int i = 0; i < numAlign; i++) { + for (int j = 0; j < numAlign; j++) { + if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)) + continue; // Don't draw on the three finder corners + for (int dy = -1; dy <= 1; dy++) { + for (int dx = -1; dx <= 1; dx++) + setModule(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0); + } + } + } + + // Draw version blocks + if (version >= 7) { + // Calculate error correction code and pack bits + int rem = version; // version is uint6, in the range [7, 40] + for (int i = 0; i < 12; i++) + rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); + long bits = (long)version << 12 | rem; // uint18 + assert(bits >> 18 == 0); + + // Draw two copies + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 3; j++) { + int k = qrsize - 11 + j; + setModule(qrcode, k, i, (bits & 1) != 0); + setModule(qrcode, i, k, (bits & 1) != 0); + bits >>= 1; + } + } + } +} + + +// Draws two copies of the format bits (with its own error correction code) based +// on the given mask and error correction level. This always draws all modules of +// the format bits, unlike drawWhiteFunctionModules() which might skip black modules. +static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) { + // Calculate error correction code and pack bits + assert(0 <= (int)mask && (int)mask <= 7); + static const int table[] = {1, 0, 3, 2}; + int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3 + int rem = data; + for (int i = 0; i < 10; i++) + rem = (rem << 1) ^ ((rem >> 9) * 0x537); + int bits = (data << 10 | rem) ^ 0x5412; // uint15 + assert(bits >> 15 == 0); + + // Draw first copy + for (int i = 0; i <= 5; i++) + setModule(qrcode, 8, i, getBit(bits, i)); + setModule(qrcode, 8, 7, getBit(bits, 6)); + setModule(qrcode, 8, 8, getBit(bits, 7)); + setModule(qrcode, 7, 8, getBit(bits, 8)); + for (int i = 9; i < 15; i++) + setModule(qrcode, 14 - i, 8, getBit(bits, i)); + + // Draw second copy + int qrsize = qrcodegen_getSize(qrcode); + for (int i = 0; i < 8; i++) + setModule(qrcode, qrsize - 1 - i, 8, getBit(bits, i)); + for (int i = 8; i < 15; i++) + setModule(qrcode, 8, qrsize - 15 + i, getBit(bits, i)); + setModule(qrcode, 8, qrsize - 8, true); // Always black +} + + +// Calculates and stores an ascending list of positions of alignment patterns +// for this version number, returning the length of the list (in the range [0,7]). +// Each position is in the range [0,177), and are used on both the x and y axes. +// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. +testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { + if (version == 1) + return 0; + int numAlign = version / 7 + 2; + int step = (version == 32) ? 26 : + (version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2; + for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) + result[i] = pos; + result[0] = 6; + return numAlign; +} + + +// Sets every pixel in the range [left : left + width] * [top : top + height] to black. +static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) { + for (int dy = 0; dy < height; dy++) { + for (int dx = 0; dx < width; dx++) + setModule(qrcode, left + dx, top + dy, true); + } +} + + + +/*---- Drawing data modules and masking ----*/ + +// Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of +// the QR Code to be black at function modules and white at codeword modules (including unused remainder bits). +static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { + int qrsize = qrcodegen_getSize(qrcode); + int i = 0; // Bit index into the data + // Do the funny zigzag scan + for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair + if (right == 6) + right = 5; + for (int vert = 0; vert < qrsize; vert++) { // Vertical counter + for (int j = 0; j < 2; j++) { + int x = right - j; // Actual x coordinate + bool upward = ((right + 1) & 2) == 0; + int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate + if (!getModule(qrcode, x, y) && i < dataLen * 8) { + bool black = getBit(data[i >> 3], 7 - (i & 7)); + setModule(qrcode, x, y, black); + i++; + } + // If this QR Code has any remainder bits (0 to 7), they were assigned as + // 0/false/white by the constructor and are left unchanged by this method + } + } + } + assert(i == dataLen * 8); +} + + +// XORs the codeword modules in this QR Code with the given mask pattern. +// The function modules must be marked and the codeword bits must be drawn +// before masking. Due to the arithmetic of XOR, calling applyMask() with +// the same mask value a second time will undo the mask. A final well-formed +// QR Code needs exactly one (not zero, two, etc.) mask applied. +static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) { + assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO + int qrsize = qrcodegen_getSize(qrcode); + for (int y = 0; y < qrsize; y++) { + for (int x = 0; x < qrsize; x++) { + if (getModule(functionModules, x, y)) + continue; + bool invert; + switch ((int)mask) { + case 0: invert = (x + y) % 2 == 0; break; + case 1: invert = y % 2 == 0; break; + case 2: invert = x % 3 == 0; break; + case 3: invert = (x + y) % 3 == 0; break; + case 4: invert = (x / 3 + y / 2) % 2 == 0; break; + case 5: invert = x * y % 2 + x * y % 3 == 0; break; + case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; + case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; + default: assert(false); return; + } + bool val = getModule(qrcode, x, y); + setModule(qrcode, x, y, val ^ invert); + } + } +} + + +// Calculates and returns the penalty score based on state of the given QR Code's current modules. +// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. +static long getPenaltyScore(const uint8_t qrcode[]) { + int qrsize = qrcodegen_getSize(qrcode); + long result = 0; + + // Adjacent modules in row having same color, and finder-like patterns + for (int y = 0; y < qrsize; y++) { + unsigned char runHistory[7] = {0}; + bool color = false; + unsigned char runX = 0; + for (int x = 0; x < qrsize; x++) { + if (getModule(qrcode, x, y) == color) { + runX++; + if (runX == 5) + result += PENALTY_N1; + else if (runX > 5) + result++; + } else { + addRunToHistory(runX, runHistory); + if (!color && hasFinderLikePattern(runHistory)) + result += PENALTY_N3; + color = getModule(qrcode, x, y); + runX = 1; + } + } + addRunToHistory(runX, runHistory); + if (color) + addRunToHistory(0, runHistory); // Dummy run of white + if (hasFinderLikePattern(runHistory)) + result += PENALTY_N3; + } + // Adjacent modules in column having same color, and finder-like patterns + for (int x = 0; x < qrsize; x++) { + unsigned char runHistory[7] = {0}; + bool color = false; + unsigned char runY = 0; + for (int y = 0; y < qrsize; y++) { + if (getModule(qrcode, x, y) == color) { + runY++; + if (runY == 5) + result += PENALTY_N1; + else if (runY > 5) + result++; + } else { + addRunToHistory(runY, runHistory); + if (!color && hasFinderLikePattern(runHistory)) + result += PENALTY_N3; + color = getModule(qrcode, x, y); + runY = 1; + } + } + addRunToHistory(runY, runHistory); + if (color) + addRunToHistory(0, runHistory); // Dummy run of white + if (hasFinderLikePattern(runHistory)) + result += PENALTY_N3; + } + + // 2*2 blocks of modules having same color + for (int y = 0; y < qrsize - 1; y++) { + for (int x = 0; x < qrsize - 1; x++) { + bool color = getModule(qrcode, x, y); + if ( color == getModule(qrcode, x + 1, y) && + color == getModule(qrcode, x, y + 1) && + color == getModule(qrcode, x + 1, y + 1)) + result += PENALTY_N2; + } + } + + // Balance of black and white modules + int black = 0; + for (int y = 0; y < qrsize; y++) { + for (int x = 0; x < qrsize; x++) { + if (getModule(qrcode, x, y)) + black++; + } + } + int total = qrsize * qrsize; // Note that size is odd, so black/total != 1/2 + // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)% + int k = (int)((labs(black * 20L - total * 10L) + total - 1) / total) - 1; + result += k * PENALTY_N4; + return result; +} + + +// Inserts the given value to the front of the given array, which shifts over the +// existing values and deletes the last value. A helper function for getPenaltyScore(). +static void addRunToHistory(unsigned char run, unsigned char history[7]) { + memmove(&history[1], &history[0], 6 * sizeof(history[0])); + history[0] = run; +} + + +// Tests whether the given run history has the pattern of ratio 1:1:3:1:1 in the middle, and +// surrounded by at least 4 on either or both ends. A helper function for getPenaltyScore(). +// Must only be called immediately after a run of white modules has ended. +static bool hasFinderLikePattern(const unsigned char runHistory[7]) { + unsigned char n = runHistory[1]; + // The maximum QR Code size is 177, hence the run length n <= 177. + // Arithmetic is promoted to int, so n*4 will not overflow. + return n > 0 && runHistory[2] == n && runHistory[4] == n && runHistory[5] == n + && runHistory[3] == n * 3 && (runHistory[0] >= n * 4 || runHistory[6] >= n * 4); +} + + + +/*---- Basic QR Code information ----*/ + +// Public function - see documentation comment in header file. +int qrcodegen_getSize(const uint8_t qrcode[]) { + assert(qrcode != NULL); + int result = qrcode[0]; + assert((qrcodegen_VERSION_MIN * 4 + 17) <= result + && result <= (qrcodegen_VERSION_MAX * 4 + 17)); + return result; +} + + +// Public function - see documentation comment in header file. +bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { + assert(qrcode != NULL); + int qrsize = qrcode[0]; + return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModule(qrcode, x, y); +} + + +// Gets the module at the given coordinates, which must be in bounds. +testable bool getModule(const uint8_t qrcode[], int x, int y) { + int qrsize = qrcode[0]; + assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); + int index = y * qrsize + x; + return getBit(qrcode[(index >> 3) + 1], index & 7); +} + + +// Sets the module at the given coordinates, which must be in bounds. +testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack) { + int qrsize = qrcode[0]; + assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); + int index = y * qrsize + x; + int bitIndex = index & 7; + int byteIndex = (index >> 3) + 1; + if (isBlack) + qrcode[byteIndex] |= 1 << bitIndex; + else + qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF; +} + + +// Sets the module at the given coordinates, doing nothing if out of bounds. +testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack) { + int qrsize = qrcode[0]; + if (0 <= x && x < qrsize && 0 <= y && y < qrsize) + setModule(qrcode, x, y, isBlack); +} + + +// Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14. +static bool getBit(int x, int i) { + return ((x >> i) & 1) != 0; +} + + + +/*---- Segment handling ----*/ + +// Public function - see documentation comment in header file. +bool qrcodegen_isAlphanumeric(const char *text) { + assert(text != NULL); + for (; *text != '\0'; text++) { + if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) + return false; + } + return true; +} + + +// Public function - see documentation comment in header file. +bool qrcodegen_isNumeric(const char *text) { + assert(text != NULL); + for (; *text != '\0'; text++) { + if (*text < '0' || *text > '9') + return false; + } + return true; +} + + +// Public function - see documentation comment in header file. +size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) { + int temp = calcSegmentBitLength(mode, numChars); + if (temp == -1) + return SIZE_MAX; + assert(0 <= temp && temp <= INT16_MAX); + return ((size_t)temp + 7) / 8; +} + + +// Returns the number of data bits needed to represent a segment +// containing the given number of characters using the given mode. Notes: +// - Returns -1 on failure, i.e. numChars > INT16_MAX or +// the number of needed bits exceeds INT16_MAX (i.e. 32767). +// - Otherwise, all valid results are in the range [0, INT16_MAX]. +// - For byte mode, numChars measures the number of bytes, not Unicode code points. +// - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. +// An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. +testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { + // All calculations are designed to avoid overflow on all platforms + if (numChars > (unsigned int)INT16_MAX) + return -1; + long result = (long)numChars; + if (mode == qrcodegen_Mode_NUMERIC) + result = (result * 10 + 2) / 3; // ceil(10/3 * n) + else if (mode == qrcodegen_Mode_ALPHANUMERIC) + result = (result * 11 + 1) / 2; // ceil(11/2 * n) + else if (mode == qrcodegen_Mode_BYTE) + result *= 8; + else if (mode == qrcodegen_Mode_KANJI) + result *= 13; + else if (mode == qrcodegen_Mode_ECI && numChars == 0) + result = 3 * 8; + else { // Invalid argument + assert(false); + return -1; + } + assert(result >= 0); + if ((unsigned int)result > (unsigned int)INT16_MAX) + return -1; + return (int)result; +} + + +// Public function - see documentation comment in header file. +struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) { + assert(data != NULL || len == 0); + struct qrcodegen_Segment result; + result.mode = qrcodegen_Mode_BYTE; + result.bitLength = calcSegmentBitLength(result.mode, len); + assert(result.bitLength != -1); + result.numChars = (int)len; + if (len > 0) + memcpy(buf, data, len * sizeof(buf[0])); + result.data = buf; + return result; +} + + +// Public function - see documentation comment in header file. +struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { + assert(digits != NULL); + struct qrcodegen_Segment result; + size_t len = strlen(digits); + result.mode = qrcodegen_Mode_NUMERIC; + int bitLen = calcSegmentBitLength(result.mode, len); + assert(bitLen != -1); + result.numChars = (int)len; + if (bitLen > 0) + memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); + result.bitLength = 0; + + unsigned int accumData = 0; + int accumCount = 0; + for (; *digits != '\0'; digits++) { + char c = *digits; + assert('0' <= c && c <= '9'); + accumData = accumData * 10 + (unsigned int)(c - '0'); + accumCount++; + if (accumCount == 3) { + appendBitsToBuffer(accumData, 10, buf, &result.bitLength); + accumData = 0; + accumCount = 0; + } + } + if (accumCount > 0) // 1 or 2 digits remaining + appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength); + assert(result.bitLength == bitLen); + result.data = buf; + return result; +} + + +// Public function - see documentation comment in header file. +struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) { + assert(text != NULL); + struct qrcodegen_Segment result; + size_t len = strlen(text); + result.mode = qrcodegen_Mode_ALPHANUMERIC; + int bitLen = calcSegmentBitLength(result.mode, len); + assert(bitLen != -1); + result.numChars = (int)len; + if (bitLen > 0) + memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); + result.bitLength = 0; + + unsigned int accumData = 0; + int accumCount = 0; + for (; *text != '\0'; text++) { + const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); + assert(temp != NULL); + accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); + accumCount++; + if (accumCount == 2) { + appendBitsToBuffer(accumData, 11, buf, &result.bitLength); + accumData = 0; + accumCount = 0; + } + } + if (accumCount > 0) // 1 character remaining + appendBitsToBuffer(accumData, 6, buf, &result.bitLength); + assert(result.bitLength == bitLen); + result.data = buf; + return result; +} + + +// Public function - see documentation comment in header file. +struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { + struct qrcodegen_Segment result; + result.mode = qrcodegen_Mode_ECI; + result.numChars = 0; + result.bitLength = 0; + if (assignVal < 0) { + assert(false); + } else if (assignVal < (1 << 7)) { + memset(buf, 0, 1 * sizeof(buf[0])); + appendBitsToBuffer(assignVal, 8, buf, &result.bitLength); + } else if (assignVal < (1 << 14)) { + memset(buf, 0, 2 * sizeof(buf[0])); + appendBitsToBuffer(2, 2, buf, &result.bitLength); + appendBitsToBuffer(assignVal, 14, buf, &result.bitLength); + } else if (assignVal < 1000000L) { + memset(buf, 0, 3 * sizeof(buf[0])); + appendBitsToBuffer(6, 3, buf, &result.bitLength); + appendBitsToBuffer(assignVal >> 10, 11, buf, &result.bitLength); + appendBitsToBuffer(assignVal & 0x3FF, 10, buf, &result.bitLength); + } else { + assert(false); + } + result.data = buf; + return result; +} + + +// Calculates the number of bits needed to encode the given segments at the given version. +// Returns a non-negative number if successful. Otherwise returns -1 if a segment has too +// many characters to fit its length field, or the total bits exceeds INT16_MAX. +testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) { + assert(segs != NULL || len == 0); + long result = 0; + for (size_t i = 0; i < len; i++) { + int numChars = segs[i].numChars; + int bitLength = segs[i].bitLength; + assert(0 <= numChars && numChars <= INT16_MAX); + assert(0 <= bitLength && bitLength <= INT16_MAX); + int ccbits = numCharCountBits(segs[i].mode, version); + assert(0 <= ccbits && ccbits <= 16); + if (numChars >= (1L << ccbits)) + return -1; // The segment's length doesn't fit the field's bit width + result += 4L + ccbits + bitLength; + if (result > INT16_MAX) + return -1; // The sum might overflow an int type + } + assert(0 <= result && result <= INT16_MAX); + return (int)result; +} + + +// Returns the bit width of the character count field for a segment in the given mode +// in a QR Code at the given version number. The result is in the range [0, 16]. +static int numCharCountBits(enum qrcodegen_Mode mode, int version) { + assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); + int i = (version + 7) / 17; + switch (mode) { + case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; } + case qrcodegen_Mode_ALPHANUMERIC: { static const int temp[] = { 9, 11, 13}; return temp[i]; } + case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; } + case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; } + case qrcodegen_Mode_ECI : return 0; + default: assert(false); return -1; // Dummy value + } +} + +int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, size_t dataLen) +{ + struct qrcodegen_Segment seg; + seg.mode = qrcodegen_Mode_BYTE; + seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); + seg.numChars = (int)dataLen; + + for (int version = qrcodegen_VERSION_MIN; version <= qrcodegen_VERSION_MAX; version++) { + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available + int dataUsedBits = getTotalBits(&seg, 1, version); + if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) + return version; + } + return -1; +} + +int qrcodegen_version2size(int version) +{ + if (version < qrcodegen_VERSION_MIN || version > qrcodegen_VERSION_MAX) { + return -1; + } + + return ((version - 1)*4 + 21); +} diff --git a/lib/libesp32/berry_matter/src/qrcodegen.h b/lib/libesp32/berry_matter/src/qrcodegen.h new file mode 100644 index 000000000..b484e9175 --- /dev/null +++ b/lib/libesp32/berry_matter/src/qrcodegen.h @@ -0,0 +1,319 @@ +/* + * QR Code generator library (C) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * 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. + */ + +#pragma once + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * This library creates QR Code symbols, which is a type of two-dimension barcode. + * Invented by Denso Wave and described in the ISO/IEC 18004 standard. + * A QR Code structure is an immutable square grid of black and white cells. + * The library provides functions to create a QR Code from text or binary data. + * The library covers the QR Code Model 2 specification, supporting all versions (sizes) + * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. + * + * Ways to create a QR Code object: + * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary(). + * - Low level: Custom-make the list of segments and call + * qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced(). + * (Note that all ways require supplying the desired error correction level and various byte buffers.) + */ + + +/*---- Enum and struct types----*/ + +/* + * The error correction level in a QR Code symbol. + */ +enum qrcodegen_Ecc { + // Must be declared in ascending order of error protection + // so that an internal qrcodegen function works properly + qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords + qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords + qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords + qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords +}; + + +/* + * The mask pattern used in a QR Code symbol. + */ +enum qrcodegen_Mask { + // A special value to tell the QR Code encoder to + // automatically select an appropriate mask pattern + qrcodegen_Mask_AUTO = -1, + // The eight actual mask patterns + qrcodegen_Mask_0 = 0, + qrcodegen_Mask_1, + qrcodegen_Mask_2, + qrcodegen_Mask_3, + qrcodegen_Mask_4, + qrcodegen_Mask_5, + qrcodegen_Mask_6, + qrcodegen_Mask_7, +}; + + +/* + * Describes how a segment's data bits are interpreted. + */ +enum qrcodegen_Mode { + qrcodegen_Mode_NUMERIC = 0x1, + qrcodegen_Mode_ALPHANUMERIC = 0x2, + qrcodegen_Mode_BYTE = 0x4, + qrcodegen_Mode_KANJI = 0x8, + qrcodegen_Mode_ECI = 0x7, +}; + + +/* + * A segment of character/binary/control data in a QR Code symbol. + * The mid-level way to create a segment is to take the payload data + * and call a factory function such as qrcodegen_makeNumeric(). + * The low-level way to create a segment is to custom-make the bit buffer + * and initialize a qrcodegen_Segment struct with appropriate values. + * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. + * Any segment longer than this is meaningless for the purpose of generating QR Codes. + * Moreover, the maximum allowed bit length is 32767 because + * the largest QR Code (version 40) has 31329 modules. + */ +struct qrcodegen_Segment { + // The mode indicator of this segment. + enum qrcodegen_Mode mode; + + // The length of this segment's unencoded data. Measured in characters for + // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. + // Always zero or positive. Not the same as the data's bit length. + int numChars; + + // The data bits of this segment, packed in bitwise big endian. + // Can be null if the bit length is zero. + uint8_t *data; + + // The number of valid data bits used in the buffer. Requires + // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. + // The character count (numChars) must agree with the mode and the bit buffer length. + int bitLength; +}; + + + +/*---- Macro constants and functions ----*/ + +#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard +#define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard + +// Calculates the number of bytes needed to store any QR Code up to and including the given version number, +// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];' +// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16). +// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX. +#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1) + +// The worst-case number of bytes needed to store one QR Code, up to and including +// version 40. This value equals 3918, which is just under 4 kilobytes. +// Use this more convenient value to avoid calculating tighter memory bounds for buffers. +#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX) + + + +/*---- Functions (high level) to generate QR Codes ----*/ + +/* + * Encodes the given text string to a QR Code, returning true if encoding succeeded. + * If the data is too long to fit in any version in the given range + * at the given ECC level, then false is returned. + * - The input text must be encoded in UTF-8 and contain no NULs. + * - The variables ecl and mask must correspond to enum constant values. + * - Requires 1 <= minVersion <= maxVersion <= 40. + * - The arrays tempBuffer and qrcode must each have a length + * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). + * - After the function returns, tempBuffer contains no useful data. + * - If successful, the resulting QR Code may use numeric, + * alphanumeric, or byte mode to encode the text. + * - In the most optimistic case, a QR Code at version 40 with low ECC + * can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string + * up to 4296 characters, or any digit string up to 7089 characters. + * These numbers represent the hard upper limit of the QR Code standard. + * - Please consult the QR Code specification for information on + * data capacities per version, ECC level, and text encoding mode. + */ +bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], + enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); + + +/* + * Encodes the given binary data to a QR Code, returning true if encoding succeeded. + * If the data is too long to fit in any version in the given range + * at the given ECC level, then false is returned. + * - The input array range dataAndTemp[0 : dataLen] should normally be + * valid UTF-8 text, but is not required by the QR Code standard. + * - The variables ecl and mask must correspond to enum constant values. + * - Requires 1 <= minVersion <= maxVersion <= 40. + * - The arrays dataAndTemp and qrcode must each have a length + * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). + * - After the function returns, the contents of dataAndTemp may have changed, + * and does not represent useful data anymore. + * - If successful, the resulting QR Code will use byte mode to encode the data. + * - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte + * sequence up to length 2953. This is the hard upper limit of the QR Code standard. + * - Please consult the QR Code specification for information on + * data capacities per version, ECC level, and text encoding mode. + */ +bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], + enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); + + +/*---- Functions (low level) to generate QR Codes ----*/ + +/* + * Renders a QR Code representing the given segments at the given error correction level. + * The smallest possible QR Code version is automatically chosen for the output. Returns true if + * QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level + * of the result may be higher than the ecl argument if it can be done without increasing the version. + * This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). + * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will + * result in them being clobbered, but the QR Code output will still be correct. + * But the qrcode array must not overlap tempBuffer or any segment's data buffer. + */ +bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, + enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); + + +/* + * Renders a QR Code representing the given segments with the given encoding parameters. + * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions. + * The smallest possible QR Code version within the given range is automatically + * chosen for the output. Iff boostEcl is true, then the ECC level of the result + * may be higher than the ecl argument if it can be done without increasing the + * version. The mask number is either between 0 to 7 (inclusive) to force that + * mask, or -1 to automatically choose an appropriate mask (which may be slow). + * This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). + * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will + * result in them being clobbered, but the QR Code output will still be correct. + * But the qrcode array must not overlap tempBuffer or any segment's data buffer. + */ +bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, + int minVersion, int maxVersion, int mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]); + + +/* + * Tests whether the given string can be encoded as a segment in alphanumeric mode. + * A string is encodable iff each character is in the following set: 0 to 9, A to Z + * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ +bool qrcodegen_isAlphanumeric(const char *text); + + +/* + * Tests whether the given string can be encoded as a segment in numeric mode. + * A string is encodable iff each character is in the range 0 to 9. + */ +bool qrcodegen_isNumeric(const char *text); + + +/* + * Returns the number of bytes (uint8_t) needed for the data buffer of a segment + * containing the given number of characters using the given mode. Notes: + * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or + * the number of needed bits exceeds INT16_MAX (i.e. 32767). + * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096. + * - It is okay for the user to allocate more bytes for the buffer than needed. + * - For byte mode, numChars measures the number of bytes, not Unicode code points. + * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned. + * An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. + */ +size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); + + +/* + * Returns a segment representing the given binary data encoded in + * byte mode. All input byte arrays are acceptable. Any text string + * can be converted to UTF-8 bytes and encoded as a byte mode segment. + */ +struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); + + +/* + * Returns a segment representing the given string of decimal digits encoded in numeric mode. + */ +struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); + + +/* + * Returns a segment representing the given text string encoded in alphanumeric mode. + * The characters allowed are: 0 to 9, A to Z (uppercase only), space, + * dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ +struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); + + +/* + * Returns a segment representing an Extended Channel Interpretation + * (ECI) designator with the given assignment value. + */ +struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); + + +/*---- Functions to extract raw data from QR Codes ----*/ + +/* + * Returns the side length of the given QR Code, assuming that encoding succeeded. + * The result is in the range [21, 177]. Note that the length of the array buffer + * is related to the side length - every 'uint8_t qrcode[]' must have length at least + * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1). + */ +int qrcodegen_getSize(const uint8_t qrcode[]); + + +/* + * Returns the color of the module (pixel) at the given coordinates, which is false + * for white or true for black. The top left corner has the coordinates (x=0, y=0). + * If the given coordinates are out of bounds, then false (white) is returned. + */ +bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y); + +/* + * Returns the qrcode size of the specified version. Returns -1 on failure + */ +int qrcodegen_version2size(int version); +/* + * Returns the min version of the data that can be stored. Returns -1 on failure + */ +int qrcodegen_getMinFitVersion(enum qrcodegen_Ecc ecl, size_t dataLen); + +#ifdef __cplusplus +} +#endif diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h index 8888f26c3..0795e40ed 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning.h @@ -7,11 +7,11 @@ extern const bclass be_class_Matter_Commisioning_Context; /******************************************************************** -** Solidified function: parse_PBKDFParamRequest +** Solidified function: parse_StatusReport ********************************************************************/ -be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name */ +be_local_closure(Matter_Commisioning_Context_parse_StatusReport, /* name */ be_nested_proto( - 14, /* nstack */ + 7, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,153 +19,34 @@ be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[48]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(opcode), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(protocol_id), - /* K5 */ be_nested_str_weak(protocol_error), - /* K6 */ be_nested_str_weak(invalid_X20PBKDFParamRequest_X20message), - /* K7 */ be_nested_str_weak(matter), - /* K8 */ be_nested_str_weak(PBKDFParamRequest), - /* K9 */ be_nested_str_weak(parse), - /* K10 */ be_nested_str_weak(raw), - /* K11 */ be_nested_str_weak(app_payload_idx), - /* K12 */ be_nested_str_weak(session), - /* K13 */ be_nested_str_weak(set_mode), - /* K14 */ be_nested_str_weak(Session), - /* K15 */ be_nested_str_weak(__PASE), - /* K16 */ be_const_int(2147483647), - /* K17 */ be_nested_str_weak(passcodeId), - /* K18 */ be_nested_str_weak(non_X2Dzero_X20passcode_X20id), - /* K19 */ be_nested_str_weak(future_initiator_session_id), - /* K20 */ be_nested_str_weak(initiator_session_id), - /* K21 */ be_nested_str_weak(future_local_session_id), - /* K22 */ be_nested_str_weak(device), - /* K23 */ be_nested_str_weak(sessions), - /* K24 */ be_nested_str_weak(gen_local_session_id), - /* K25 */ be_nested_str_weak(PBKDFParamResponse), - /* K26 */ be_nested_str_weak(initiatorRandom), - /* K27 */ be_nested_str_weak(responderRandom), - /* K28 */ be_nested_str_weak(random), - /* K29 */ be_nested_str_weak(responderSessionId), - /* K30 */ be_nested_str_weak(pbkdf_parameters_salt), - /* K31 */ be_nested_str_weak(salt), - /* K32 */ be_nested_str_weak(pbkdf_parameters_iterations), - /* K33 */ be_nested_str_weak(iterations), - /* K34 */ be_nested_str_weak(tasmota), - /* K35 */ be_nested_str_weak(log), - /* K36 */ be_nested_str_weak(MTR_X3A_X20pbkdfparamresp_X3A_X20), - /* K37 */ be_nested_str_weak(inspect), - /* K38 */ be_const_int(3), - /* K39 */ be_nested_str_weak(encode), - /* K40 */ be_nested_str_weak(MTR_X3A_X20pbkdfparamresp_raw_X3A_X20), - /* K41 */ be_nested_str_weak(tohex), - /* K42 */ be_nested_str_weak(build_response), - /* K43 */ be_nested_str_weak(responder), - /* K44 */ be_nested_str_weak(send_response), - /* K45 */ be_nested_str_weak(remote_ip), - /* K46 */ be_nested_str_weak(remote_port), - /* K47 */ be_nested_str_weak(message_counter), + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(session), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20_X3EStatus_X20_X20_X20_X20), + /* K4 */ be_nested_str_weak(raw), + /* K5 */ be_nested_str_weak(app_payload_idx), + /* K6 */ be_const_int(2147483647), + /* K7 */ be_nested_str_weak(tohex), + /* K8 */ be_const_int(2), }), - be_str_weak(parse_PBKDFParamRequest), + be_str_weak(parse_StatusReport), &be_const_str_solidified, - ( &(const binstruction[94]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x880C0301, // 0001 GETMBR R3 R1 K1 - 0x5412001F, // 0002 LDINT R4 32 - 0x200C0604, // 0003 NE R3 R3 R4 - 0x740E0005, // 0004 JMPT R3 #000B - 0x880C0302, // 0005 GETMBR R3 R1 K2 - 0x200C0703, // 0006 NE R3 R3 K3 - 0x740E0002, // 0007 JMPT R3 #000B - 0x880C0304, // 0008 GETMBR R3 R1 K4 - 0x200C0703, // 0009 NE R3 R3 K3 - 0x780E0000, // 000A JMPF R3 #000C - 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB80E0E00, // 000C GETNGBL R3 K7 - 0x8C0C0708, // 000D GETMET R3 R3 K8 - 0x7C0C0200, // 000E CALL R3 1 - 0x8C0C0709, // 000F GETMET R3 R3 K9 - 0x8814030A, // 0010 GETMBR R5 R1 K10 - 0x8818030B, // 0011 GETMBR R6 R1 K11 - 0x7C0C0600, // 0012 CALL R3 3 - 0x8810030C, // 0013 GETMBR R4 R1 K12 - 0x8C10090D, // 0014 GETMET R4 R4 K13 - 0xB81A0E00, // 0015 GETNGBL R6 K7 - 0x88180D0E, // 0016 GETMBR R6 R6 K14 - 0x88180D0F, // 0017 GETMBR R6 R6 K15 - 0x7C100400, // 0018 CALL R4 2 - 0x8810030B, // 0019 GETMBR R4 R1 K11 - 0x40100910, // 001A CONNECT R4 R4 K16 - 0x8814030A, // 001B GETMBR R5 R1 K10 - 0x94100A04, // 001C GETIDX R4 R5 R4 - 0x90021004, // 001D SETMBR R0 K8 R4 - 0x88100711, // 001E GETMBR R4 R3 K17 - 0x20100903, // 001F NE R4 R4 K3 - 0x78120000, // 0020 JMPF R4 #0022 - 0xB0060B12, // 0021 RAISE 1 K5 K18 - 0x88100714, // 0022 GETMBR R4 R3 K20 - 0x90022604, // 0023 SETMBR R0 K19 R4 - 0x88100116, // 0024 GETMBR R4 R0 K22 - 0x88100917, // 0025 GETMBR R4 R4 K23 - 0x8C100918, // 0026 GETMET R4 R4 K24 - 0x7C100200, // 0027 CALL R4 1 - 0x90022A04, // 0028 SETMBR R0 K21 R4 - 0xB8120E00, // 0029 GETNGBL R4 K7 - 0x8C100919, // 002A GETMET R4 R4 K25 - 0x7C100200, // 002B CALL R4 1 - 0x8814071A, // 002C GETMBR R5 R3 K26 - 0x90123405, // 002D SETMBR R4 K26 R5 - 0x8C14051C, // 002E GETMET R5 R2 K28 - 0x541E001F, // 002F LDINT R7 32 - 0x7C140400, // 0030 CALL R5 2 - 0x90123605, // 0031 SETMBR R4 K27 R5 - 0x88140115, // 0032 GETMBR R5 R0 K21 - 0x90123A05, // 0033 SETMBR R4 K29 R5 - 0x88140116, // 0034 GETMBR R5 R0 K22 - 0x88140B1F, // 0035 GETMBR R5 R5 K31 - 0x90123C05, // 0036 SETMBR R4 K30 R5 - 0x88140116, // 0037 GETMBR R5 R0 K22 - 0x88140B21, // 0038 GETMBR R5 R5 K33 - 0x90124005, // 0039 SETMBR R4 K32 R5 - 0xB8164400, // 003A GETNGBL R5 K34 - 0x8C140B23, // 003B GETMET R5 R5 K35 - 0x601C0008, // 003C GETGBL R7 G8 - 0xB8220E00, // 003D GETNGBL R8 K7 - 0x8C201125, // 003E GETMET R8 R8 K37 - 0x5C280800, // 003F MOVE R10 R4 - 0x7C200400, // 0040 CALL R8 2 - 0x7C1C0200, // 0041 CALL R7 1 - 0x001E4807, // 0042 ADD R7 K36 R7 - 0x58200026, // 0043 LDCONST R8 K38 - 0x7C140600, // 0044 CALL R5 3 - 0x8C140927, // 0045 GETMET R5 R4 K39 - 0x7C140200, // 0046 CALL R5 1 - 0xB81A4400, // 0047 GETNGBL R6 K34 - 0x8C180D23, // 0048 GETMET R6 R6 K35 - 0x8C200B29, // 0049 GETMET R8 R5 K41 - 0x7C200200, // 004A CALL R8 1 - 0x00225008, // 004B ADD R8 K40 R8 - 0x58240026, // 004C LDCONST R9 K38 - 0x7C180600, // 004D CALL R6 3 - 0x90023205, // 004E SETMBR R0 K25 R5 - 0x8C18032A, // 004F GETMET R6 R1 K42 - 0x54220020, // 0050 LDINT R8 33 - 0x50240200, // 0051 LDBOOL R9 1 0 - 0x7C180600, // 0052 CALL R6 3 - 0x8C1C0D27, // 0053 GETMET R7 R6 K39 - 0x5C240A00, // 0054 MOVE R9 R5 - 0x7C1C0400, // 0055 CALL R7 2 - 0x8820012B, // 0056 GETMBR R8 R0 K43 - 0x8C20112C, // 0057 GETMET R8 R8 K44 - 0x5C280E00, // 0058 MOVE R10 R7 - 0x882C032D, // 0059 GETMBR R11 R1 K45 - 0x8830032E, // 005A GETMBR R12 R1 K46 - 0x88340D2F, // 005B GETMBR R13 R6 K47 - 0x7C200A00, // 005C CALL R8 5 - 0x80000000, // 005D RET 0 + ( &(const binstruction[14]) { /* code */ + 0x88080300, // 0000 GETMBR R2 R1 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x88140305, // 0003 GETMBR R5 R1 K5 + 0x40140B06, // 0004 CONNECT R5 R5 K6 + 0x88180304, // 0005 GETMBR R6 R1 K4 + 0x94140C05, // 0006 GETIDX R5 R6 R5 + 0x8C140B07, // 0007 GETMET R5 R5 K7 + 0x7C140200, // 0008 CALL R5 1 + 0x00160605, // 0009 ADD R5 K3 R5 + 0x58180008, // 000A LDCONST R6 K8 + 0x7C0C0600, // 000B CALL R3 3 + 0x500C0000, // 000C LDBOOL R3 0 0 + 0x80040600, // 000D RET 1 R3 }) ) ); @@ -173,484 +54,9 @@ be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name /******************************************************************** -** Solidified function: init +** Solidified function: find_fabric_by_destination_id ********************************************************************/ -be_local_closure(Matter_Commisioning_Context_init, /* 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[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(responder), - /* K2 */ be_nested_str_weak(device), - /* K3 */ be_nested_str_weak(y), - /* K4 */ be_nested_str_weak(random), - /* K5 */ be_nested_str_weak(window_open), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x90020201, // 0001 SETMBR R0 K1 R1 - 0x880C0302, // 0002 GETMBR R3 R1 K2 - 0x90020403, // 0003 SETMBR R0 K2 R3 - 0x8C0C0504, // 0004 GETMET R3 R2 K4 - 0x5416001F, // 0005 LDINT R5 32 - 0x7C0C0400, // 0006 CALL R3 2 - 0x90020603, // 0007 SETMBR R0 K3 R3 - 0x500C0200, // 0008 LDBOOL R3 1 0 - 0x90020A03, // 0009 SETMBR R0 K5 R3 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse_Pake1 -********************************************************************/ -be_local_closure(Matter_Commisioning_Context_parse_Pake1, /* name */ - be_nested_proto( - 16, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[84]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(opcode), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(protocol_id), - /* K5 */ be_nested_str_weak(protocol_error), - /* K6 */ be_nested_str_weak(invalid_X20Pake1_X20message), - /* K7 */ be_nested_str_weak(matter), - /* K8 */ be_nested_str_weak(Pake1), - /* K9 */ be_nested_str_weak(parse), - /* K10 */ be_nested_str_weak(raw), - /* K11 */ be_nested_str_weak(app_payload_idx), - /* K12 */ be_nested_str_weak(pA), - /* K13 */ be_nested_str_weak(tasmota), - /* K14 */ be_nested_str_weak(log), - /* K15 */ be_nested_str_weak(MTR_X3A_X20received_X20pA_X3D), - /* K16 */ be_nested_str_weak(tohex), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(MTR_X3A_X20spake_X3A_X20), - /* K19 */ be_nested_str_weak(inspect), - /* K20 */ be_nested_str_weak(spake), - /* K21 */ be_nested_str_weak(SPAKE2P_Matter), - /* K22 */ be_nested_str_weak(device), - /* K23 */ be_nested_str_weak(w0), - /* K24 */ be_nested_str_weak(w1), - /* K25 */ be_nested_str_weak(L), - /* K26 */ be_nested_str_weak(compute_pB), - /* K27 */ be_nested_str_weak(y), - /* K28 */ be_nested_str_weak(pB), - /* K29 */ be_nested_str_weak(MTR_X3A_X20y_X3D), - /* K30 */ be_nested_str_weak(MTR_X3A_X20pb_X3D), - /* K31 */ be_nested_str_weak(compute_ZV_verifier), - /* K32 */ be_nested_str_weak(MTR_X3A_X20Z_X3D), - /* K33 */ be_nested_str_weak(Z), - /* K34 */ be_nested_str_weak(MTR_X3A_X20V_X3D), - /* K35 */ be_nested_str_weak(V), - /* K36 */ be_nested_str_weak(SHA256), - /* K37 */ be_nested_str_weak(update), - /* K38 */ be_nested_str_weak(fromstring), - /* K39 */ be_nested_str_weak(Matter_Context_Prefix), - /* K40 */ be_nested_str_weak(PBKDFParamRequest), - /* K41 */ be_nested_str_weak(PBKDFParamResponse), - /* K42 */ be_nested_str_weak(out), - /* K43 */ be_nested_str_weak(MTR_X3A_X20Context_X3D), - /* K44 */ be_nested_str_weak(set_context), - /* K45 */ be_nested_str_weak(compute_TT_hash), - /* K46 */ be_nested_str_weak(MTR_X3A_X20_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D), - /* K47 */ be_nested_str_weak(MTR_X3A_X20Context_X20_X3D_X20), - /* K48 */ be_nested_str_weak(Context), - /* K49 */ be_nested_str_weak(MTR_X3A_X20A_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K50 */ be_nested_str_weak(A), - /* K51 */ be_nested_str_weak(MTR_X3A_X20B_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K52 */ be_nested_str_weak(B), - /* K53 */ be_nested_str_weak(MTR_X3A_X20M_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K54 */ be_nested_str_weak(M), - /* K55 */ be_nested_str_weak(MTR_X3A_X20N_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K56 */ be_nested_str_weak(N), - /* K57 */ be_nested_str_weak(MTR_X3A_X20pA_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K58 */ be_nested_str_weak(MTR_X3A_X20pB_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K59 */ be_nested_str_weak(MTR_X3A_X20Z_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K60 */ be_nested_str_weak(MTR_X3A_X20V_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K61 */ be_nested_str_weak(MTR_X3A_X20w0_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K62 */ be_nested_str_weak(MTR_X3A_X20Kmain_X20_X20_X20_X3D), - /* K63 */ be_nested_str_weak(Kmain), - /* K64 */ be_nested_str_weak(MTR_X3A_X20KcA_X20_X20_X20_X20_X20_X3D), - /* K65 */ be_nested_str_weak(KcA), - /* K66 */ be_nested_str_weak(MTR_X3A_X20KcB_X20_X20_X20_X20_X20_X3D), - /* K67 */ be_nested_str_weak(KcB), - /* K68 */ be_nested_str_weak(MTR_X3A_X20K_shared_X3D), - /* K69 */ be_nested_str_weak(K_shared), - /* K70 */ be_nested_str_weak(MTR_X3A_X20Ke_X20_X20_X20_X20_X20_X20_X3D), - /* K71 */ be_nested_str_weak(Ke), - /* K72 */ be_nested_str_weak(cB), - /* K73 */ be_nested_str_weak(MTR_X3A_X20cB_X3D), - /* K74 */ be_nested_str_weak(Pake2), - /* K75 */ be_nested_str_weak(MTR_X3A_X20pake2_X3A_X20), - /* K76 */ be_nested_str_weak(encode), - /* K77 */ be_nested_str_weak(MTR_X3A_X20pake2_raw_X3A_X20), - /* K78 */ be_nested_str_weak(build_response), - /* K79 */ be_nested_str_weak(responder), - /* K80 */ be_nested_str_weak(send_response), - /* K81 */ be_nested_str_weak(remote_ip), - /* K82 */ be_nested_str_weak(remote_port), - /* K83 */ be_nested_str_weak(message_counter), - }), - be_str_weak(parse_Pake1), - &be_const_str_solidified, - ( &(const binstruction[326]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x880C0301, // 0001 GETMBR R3 R1 K1 - 0x54120021, // 0002 LDINT R4 34 - 0x200C0604, // 0003 NE R3 R3 R4 - 0x740E0005, // 0004 JMPT R3 #000B - 0x880C0302, // 0005 GETMBR R3 R1 K2 - 0x200C0703, // 0006 NE R3 R3 K3 - 0x740E0002, // 0007 JMPT R3 #000B - 0x880C0304, // 0008 GETMBR R3 R1 K4 - 0x200C0703, // 0009 NE R3 R3 K3 - 0x780E0000, // 000A JMPF R3 #000C - 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB80E0E00, // 000C GETNGBL R3 K7 - 0x8C0C0708, // 000D GETMET R3 R3 K8 - 0x7C0C0200, // 000E CALL R3 1 - 0x8C0C0709, // 000F GETMET R3 R3 K9 - 0x8814030A, // 0010 GETMBR R5 R1 K10 - 0x8818030B, // 0011 GETMBR R6 R1 K11 - 0x7C0C0600, // 0012 CALL R3 3 - 0x8810070C, // 0013 GETMBR R4 R3 K12 - 0x90021804, // 0014 SETMBR R0 K12 R4 - 0xB8121A00, // 0015 GETNGBL R4 K13 - 0x8C10090E, // 0016 GETMET R4 R4 K14 - 0x8818010C, // 0017 GETMBR R6 R0 K12 - 0x8C180D10, // 0018 GETMET R6 R6 K16 - 0x7C180200, // 0019 CALL R6 1 - 0x001A1E06, // 001A ADD R6 K15 R6 - 0x581C0011, // 001B LDCONST R7 K17 - 0x7C100600, // 001C CALL R4 3 - 0xB8121A00, // 001D GETNGBL R4 K13 - 0x8C10090E, // 001E GETMET R4 R4 K14 - 0xB81A0E00, // 001F GETNGBL R6 K7 - 0x8C180D13, // 0020 GETMET R6 R6 K19 - 0x88200114, // 0021 GETMBR R8 R0 K20 - 0x7C180400, // 0022 CALL R6 2 - 0x001A2406, // 0023 ADD R6 K18 R6 - 0x581C0011, // 0024 LDCONST R7 K17 - 0x7C100600, // 0025 CALL R4 3 - 0x8C100515, // 0026 GETMET R4 R2 K21 - 0x88180116, // 0027 GETMBR R6 R0 K22 - 0x88180D17, // 0028 GETMBR R6 R6 K23 - 0x881C0116, // 0029 GETMBR R7 R0 K22 - 0x881C0F18, // 002A GETMBR R7 R7 K24 - 0x88200116, // 002B GETMBR R8 R0 K22 - 0x88201119, // 002C GETMBR R8 R8 K25 - 0x7C100800, // 002D CALL R4 4 - 0x90022804, // 002E SETMBR R0 K20 R4 - 0x88100114, // 002F GETMBR R4 R0 K20 - 0x8C10091A, // 0030 GETMET R4 R4 K26 - 0x8818011B, // 0031 GETMBR R6 R0 K27 - 0x7C100400, // 0032 CALL R4 2 - 0x88100114, // 0033 GETMBR R4 R0 K20 - 0x8810091C, // 0034 GETMBR R4 R4 K28 - 0x90023804, // 0035 SETMBR R0 K28 R4 - 0xB8121A00, // 0036 GETNGBL R4 K13 - 0x8C10090E, // 0037 GETMET R4 R4 K14 - 0x8818011B, // 0038 GETMBR R6 R0 K27 - 0x8C180D10, // 0039 GETMET R6 R6 K16 - 0x7C180200, // 003A CALL R6 1 - 0x001A3A06, // 003B ADD R6 K29 R6 - 0x581C0011, // 003C LDCONST R7 K17 - 0x7C100600, // 003D CALL R4 3 - 0xB8121A00, // 003E GETNGBL R4 K13 - 0x8C10090E, // 003F GETMET R4 R4 K14 - 0x8818011C, // 0040 GETMBR R6 R0 K28 - 0x8C180D10, // 0041 GETMET R6 R6 K16 - 0x7C180200, // 0042 CALL R6 1 - 0x001A3C06, // 0043 ADD R6 K30 R6 - 0x581C0011, // 0044 LDCONST R7 K17 - 0x7C100600, // 0045 CALL R4 3 - 0x88100114, // 0046 GETMBR R4 R0 K20 - 0x8C10091F, // 0047 GETMET R4 R4 K31 - 0x8818010C, // 0048 GETMBR R6 R0 K12 - 0x7C100400, // 0049 CALL R4 2 - 0xB8121A00, // 004A GETNGBL R4 K13 - 0x8C10090E, // 004B GETMET R4 R4 K14 - 0x88180114, // 004C GETMBR R6 R0 K20 - 0x88180D21, // 004D GETMBR R6 R6 K33 - 0x8C180D10, // 004E GETMET R6 R6 K16 - 0x7C180200, // 004F CALL R6 1 - 0x001A4006, // 0050 ADD R6 K32 R6 - 0x581C0011, // 0051 LDCONST R7 K17 - 0x7C100600, // 0052 CALL R4 3 - 0xB8121A00, // 0053 GETNGBL R4 K13 - 0x8C10090E, // 0054 GETMET R4 R4 K14 - 0x88180114, // 0055 GETMBR R6 R0 K20 - 0x88180D23, // 0056 GETMBR R6 R6 K35 - 0x8C180D10, // 0057 GETMET R6 R6 K16 - 0x7C180200, // 0058 CALL R6 1 - 0x001A4406, // 0059 ADD R6 K34 R6 - 0x581C0011, // 005A LDCONST R7 K17 - 0x7C100600, // 005B CALL R4 3 - 0x8C100524, // 005C GETMET R4 R2 K36 - 0x7C100200, // 005D CALL R4 1 - 0x8C140925, // 005E GETMET R5 R4 K37 - 0x601C0015, // 005F GETGBL R7 G21 - 0x7C1C0000, // 0060 CALL R7 0 - 0x8C1C0F26, // 0061 GETMET R7 R7 K38 - 0x88240127, // 0062 GETMBR R9 R0 K39 - 0x7C1C0400, // 0063 CALL R7 2 - 0x7C140400, // 0064 CALL R5 2 - 0x8C140925, // 0065 GETMET R5 R4 K37 - 0x881C0128, // 0066 GETMBR R7 R0 K40 - 0x7C140400, // 0067 CALL R5 2 - 0x8C140925, // 0068 GETMET R5 R4 K37 - 0x881C0129, // 0069 GETMBR R7 R0 K41 - 0x7C140400, // 006A CALL R5 2 - 0x8C14092A, // 006B GETMET R5 R4 K42 - 0x7C140200, // 006C CALL R5 1 - 0xB81A1A00, // 006D GETNGBL R6 K13 - 0x8C180D0E, // 006E GETMET R6 R6 K14 - 0x8C200B10, // 006F GETMET R8 R5 K16 - 0x7C200200, // 0070 CALL R8 1 - 0x00225608, // 0071 ADD R8 K43 R8 - 0x58240011, // 0072 LDCONST R9 K17 - 0x7C180600, // 0073 CALL R6 3 - 0x88180114, // 0074 GETMBR R6 R0 K20 - 0x881C010C, // 0075 GETMBR R7 R0 K12 - 0x901A1807, // 0076 SETMBR R6 K12 R7 - 0x88180114, // 0077 GETMBR R6 R0 K20 - 0x8C180D2C, // 0078 GETMET R6 R6 K44 - 0x5C200A00, // 0079 MOVE R8 R5 - 0x7C180400, // 007A CALL R6 2 - 0x88180114, // 007B GETMBR R6 R0 K20 - 0x8C180D2D, // 007C GETMET R6 R6 K45 - 0x50200200, // 007D LDBOOL R8 1 0 - 0x7C180400, // 007E CALL R6 2 - 0xB81A1A00, // 007F GETNGBL R6 K13 - 0x8C180D0E, // 0080 GETMET R6 R6 K14 - 0x5820002E, // 0081 LDCONST R8 K46 - 0x58240011, // 0082 LDCONST R9 K17 - 0x7C180600, // 0083 CALL R6 3 - 0xB81A1A00, // 0084 GETNGBL R6 K13 - 0x8C180D0E, // 0085 GETMET R6 R6 K14 - 0x88200114, // 0086 GETMBR R8 R0 K20 - 0x88201130, // 0087 GETMBR R8 R8 K48 - 0x8C201110, // 0088 GETMET R8 R8 K16 - 0x7C200200, // 0089 CALL R8 1 - 0x00225E08, // 008A ADD R8 K47 R8 - 0x58240011, // 008B LDCONST R9 K17 - 0x7C180600, // 008C CALL R6 3 - 0xB81A1A00, // 008D GETNGBL R6 K13 - 0x8C180D0E, // 008E GETMET R6 R6 K14 - 0x88200114, // 008F GETMBR R8 R0 K20 - 0x88201132, // 0090 GETMBR R8 R8 K50 - 0x8C201110, // 0091 GETMET R8 R8 K16 - 0x7C200200, // 0092 CALL R8 1 - 0x00226208, // 0093 ADD R8 K49 R8 - 0x58240011, // 0094 LDCONST R9 K17 - 0x7C180600, // 0095 CALL R6 3 - 0xB81A1A00, // 0096 GETNGBL R6 K13 - 0x8C180D0E, // 0097 GETMET R6 R6 K14 - 0x88200114, // 0098 GETMBR R8 R0 K20 - 0x88201134, // 0099 GETMBR R8 R8 K52 - 0x8C201110, // 009A GETMET R8 R8 K16 - 0x7C200200, // 009B CALL R8 1 - 0x00226608, // 009C ADD R8 K51 R8 - 0x58240011, // 009D LDCONST R9 K17 - 0x7C180600, // 009E CALL R6 3 - 0xB81A1A00, // 009F GETNGBL R6 K13 - 0x8C180D0E, // 00A0 GETMET R6 R6 K14 - 0x88200114, // 00A1 GETMBR R8 R0 K20 - 0x88201136, // 00A2 GETMBR R8 R8 K54 - 0x8C201110, // 00A3 GETMET R8 R8 K16 - 0x7C200200, // 00A4 CALL R8 1 - 0x00226A08, // 00A5 ADD R8 K53 R8 - 0x58240011, // 00A6 LDCONST R9 K17 - 0x7C180600, // 00A7 CALL R6 3 - 0xB81A1A00, // 00A8 GETNGBL R6 K13 - 0x8C180D0E, // 00A9 GETMET R6 R6 K14 - 0x88200114, // 00AA GETMBR R8 R0 K20 - 0x88201138, // 00AB GETMBR R8 R8 K56 - 0x8C201110, // 00AC GETMET R8 R8 K16 - 0x7C200200, // 00AD CALL R8 1 - 0x00226E08, // 00AE ADD R8 K55 R8 - 0x58240011, // 00AF LDCONST R9 K17 - 0x7C180600, // 00B0 CALL R6 3 - 0xB81A1A00, // 00B1 GETNGBL R6 K13 - 0x8C180D0E, // 00B2 GETMET R6 R6 K14 - 0x88200114, // 00B3 GETMBR R8 R0 K20 - 0x8820110C, // 00B4 GETMBR R8 R8 K12 - 0x8C201110, // 00B5 GETMET R8 R8 K16 - 0x7C200200, // 00B6 CALL R8 1 - 0x00227208, // 00B7 ADD R8 K57 R8 - 0x58240011, // 00B8 LDCONST R9 K17 - 0x7C180600, // 00B9 CALL R6 3 - 0xB81A1A00, // 00BA GETNGBL R6 K13 - 0x8C180D0E, // 00BB GETMET R6 R6 K14 - 0x88200114, // 00BC GETMBR R8 R0 K20 - 0x8820111C, // 00BD GETMBR R8 R8 K28 - 0x8C201110, // 00BE GETMET R8 R8 K16 - 0x7C200200, // 00BF CALL R8 1 - 0x00227408, // 00C0 ADD R8 K58 R8 - 0x58240011, // 00C1 LDCONST R9 K17 - 0x7C180600, // 00C2 CALL R6 3 - 0xB81A1A00, // 00C3 GETNGBL R6 K13 - 0x8C180D0E, // 00C4 GETMET R6 R6 K14 - 0x88200114, // 00C5 GETMBR R8 R0 K20 - 0x88201121, // 00C6 GETMBR R8 R8 K33 - 0x8C201110, // 00C7 GETMET R8 R8 K16 - 0x7C200200, // 00C8 CALL R8 1 - 0x00227608, // 00C9 ADD R8 K59 R8 - 0x58240011, // 00CA LDCONST R9 K17 - 0x7C180600, // 00CB CALL R6 3 - 0xB81A1A00, // 00CC GETNGBL R6 K13 - 0x8C180D0E, // 00CD GETMET R6 R6 K14 - 0x88200114, // 00CE GETMBR R8 R0 K20 - 0x88201123, // 00CF GETMBR R8 R8 K35 - 0x8C201110, // 00D0 GETMET R8 R8 K16 - 0x7C200200, // 00D1 CALL R8 1 - 0x00227808, // 00D2 ADD R8 K60 R8 - 0x58240011, // 00D3 LDCONST R9 K17 - 0x7C180600, // 00D4 CALL R6 3 - 0xB81A1A00, // 00D5 GETNGBL R6 K13 - 0x8C180D0E, // 00D6 GETMET R6 R6 K14 - 0x88200114, // 00D7 GETMBR R8 R0 K20 - 0x88201117, // 00D8 GETMBR R8 R8 K23 - 0x8C201110, // 00D9 GETMET R8 R8 K16 - 0x7C200200, // 00DA CALL R8 1 - 0x00227A08, // 00DB ADD R8 K61 R8 - 0x58240011, // 00DC LDCONST R9 K17 - 0x7C180600, // 00DD CALL R6 3 - 0xB81A1A00, // 00DE GETNGBL R6 K13 - 0x8C180D0E, // 00DF GETMET R6 R6 K14 - 0x5820002E, // 00E0 LDCONST R8 K46 - 0x58240011, // 00E1 LDCONST R9 K17 - 0x7C180600, // 00E2 CALL R6 3 - 0xB81A1A00, // 00E3 GETNGBL R6 K13 - 0x8C180D0E, // 00E4 GETMET R6 R6 K14 - 0x88200114, // 00E5 GETMBR R8 R0 K20 - 0x8820113F, // 00E6 GETMBR R8 R8 K63 - 0x8C201110, // 00E7 GETMET R8 R8 K16 - 0x7C200200, // 00E8 CALL R8 1 - 0x00227C08, // 00E9 ADD R8 K62 R8 - 0x58240011, // 00EA LDCONST R9 K17 - 0x7C180600, // 00EB CALL R6 3 - 0xB81A1A00, // 00EC GETNGBL R6 K13 - 0x8C180D0E, // 00ED GETMET R6 R6 K14 - 0x88200114, // 00EE GETMBR R8 R0 K20 - 0x88201141, // 00EF GETMBR R8 R8 K65 - 0x8C201110, // 00F0 GETMET R8 R8 K16 - 0x7C200200, // 00F1 CALL R8 1 - 0x00228008, // 00F2 ADD R8 K64 R8 - 0x58240011, // 00F3 LDCONST R9 K17 - 0x7C180600, // 00F4 CALL R6 3 - 0xB81A1A00, // 00F5 GETNGBL R6 K13 - 0x8C180D0E, // 00F6 GETMET R6 R6 K14 - 0x88200114, // 00F7 GETMBR R8 R0 K20 - 0x88201143, // 00F8 GETMBR R8 R8 K67 - 0x8C201110, // 00F9 GETMET R8 R8 K16 - 0x7C200200, // 00FA CALL R8 1 - 0x00228408, // 00FB ADD R8 K66 R8 - 0x58240011, // 00FC LDCONST R9 K17 - 0x7C180600, // 00FD CALL R6 3 - 0xB81A1A00, // 00FE GETNGBL R6 K13 - 0x8C180D0E, // 00FF GETMET R6 R6 K14 - 0x88200114, // 0100 GETMBR R8 R0 K20 - 0x88201145, // 0101 GETMBR R8 R8 K69 - 0x8C201110, // 0102 GETMET R8 R8 K16 - 0x7C200200, // 0103 CALL R8 1 - 0x00228808, // 0104 ADD R8 K68 R8 - 0x58240011, // 0105 LDCONST R9 K17 - 0x7C180600, // 0106 CALL R6 3 - 0xB81A1A00, // 0107 GETNGBL R6 K13 - 0x8C180D0E, // 0108 GETMET R6 R6 K14 - 0x88200114, // 0109 GETMBR R8 R0 K20 - 0x88201147, // 010A GETMBR R8 R8 K71 - 0x8C201110, // 010B GETMET R8 R8 K16 - 0x7C200200, // 010C CALL R8 1 - 0x00228C08, // 010D ADD R8 K70 R8 - 0x58240011, // 010E LDCONST R9 K17 - 0x7C180600, // 010F CALL R6 3 - 0x88180114, // 0110 GETMBR R6 R0 K20 - 0x88180D48, // 0111 GETMBR R6 R6 K72 - 0x90029006, // 0112 SETMBR R0 K72 R6 - 0x88180114, // 0113 GETMBR R6 R0 K20 - 0x88180D47, // 0114 GETMBR R6 R6 K71 - 0x90028E06, // 0115 SETMBR R0 K71 R6 - 0xB81A1A00, // 0116 GETNGBL R6 K13 - 0x8C180D0E, // 0117 GETMET R6 R6 K14 - 0x88200148, // 0118 GETMBR R8 R0 K72 - 0x8C201110, // 0119 GETMET R8 R8 K16 - 0x7C200200, // 011A CALL R8 1 - 0x00229208, // 011B ADD R8 K73 R8 - 0x58240011, // 011C LDCONST R9 K17 - 0x7C180600, // 011D CALL R6 3 - 0xB81A0E00, // 011E GETNGBL R6 K7 - 0x8C180D4A, // 011F GETMET R6 R6 K74 - 0x7C180200, // 0120 CALL R6 1 - 0x881C011C, // 0121 GETMBR R7 R0 K28 - 0x901A3807, // 0122 SETMBR R6 K28 R7 - 0x881C0148, // 0123 GETMBR R7 R0 K72 - 0x901A9007, // 0124 SETMBR R6 K72 R7 - 0xB81E1A00, // 0125 GETNGBL R7 K13 - 0x8C1C0F0E, // 0126 GETMET R7 R7 K14 - 0xB8260E00, // 0127 GETNGBL R9 K7 - 0x8C241313, // 0128 GETMET R9 R9 K19 - 0x5C2C0C00, // 0129 MOVE R11 R6 - 0x7C240400, // 012A CALL R9 2 - 0x00269609, // 012B ADD R9 K75 R9 - 0x58280011, // 012C LDCONST R10 K17 - 0x7C1C0600, // 012D CALL R7 3 - 0x8C1C0D4C, // 012E GETMET R7 R6 K76 - 0x7C1C0200, // 012F CALL R7 1 - 0xB8221A00, // 0130 GETNGBL R8 K13 - 0x8C20110E, // 0131 GETMET R8 R8 K14 - 0x8C280F10, // 0132 GETMET R10 R7 K16 - 0x7C280200, // 0133 CALL R10 1 - 0x002A9A0A, // 0134 ADD R10 K77 R10 - 0x582C0011, // 0135 LDCONST R11 K17 - 0x7C200600, // 0136 CALL R8 3 - 0x8C20034E, // 0137 GETMET R8 R1 K78 - 0x542A0022, // 0138 LDINT R10 35 - 0x502C0200, // 0139 LDBOOL R11 1 0 - 0x7C200600, // 013A CALL R8 3 - 0x8C24114C, // 013B GETMET R9 R8 K76 - 0x5C2C0E00, // 013C MOVE R11 R7 - 0x7C240400, // 013D CALL R9 2 - 0x8828014F, // 013E GETMBR R10 R0 K79 - 0x8C281550, // 013F GETMET R10 R10 K80 - 0x5C301200, // 0140 MOVE R12 R9 - 0x88340351, // 0141 GETMBR R13 R1 K81 - 0x88380352, // 0142 GETMBR R14 R1 K82 - 0x883C1153, // 0143 GETMBR R15 R8 K83 - 0x7C280A00, // 0144 CALL R10 5 - 0x80000000, // 0145 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_session_by_destination_id -********************************************************************/ -be_local_closure(Matter_Commisioning_Context_find_session_by_destination_id, /* name */ +be_local_closure(Matter_Commisioning_Context_find_fabric_by_destination_id, /* name */ be_nested_proto( 14, /* nstack */ 3, /* argc */ @@ -660,7 +66,7 @@ be_local_closure(Matter_Commisioning_Context_find_session_by_destination_id, / 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[22]) { /* constants */ + ( &(const bvalue[21]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(tasmota), /* K2 */ be_nested_str_weak(log), @@ -669,24 +75,23 @@ be_local_closure(Matter_Commisioning_Context_find_session_by_destination_id, / /* K5 */ be_const_int(3), /* K6 */ be_nested_str_weak(device), /* K7 */ be_nested_str_weak(sessions), - /* K8 */ be_nested_str_weak(noc), - /* K9 */ be_nested_str_weak(fabric), - /* K10 */ be_nested_str_weak(deviceid), - /* K11 */ be_nested_str_weak(get_ca_pub), - /* K12 */ be_nested_str_weak(get_fabric), - /* K13 */ be_nested_str_weak(get_deviceid), - /* K14 */ be_nested_str_weak(get_ipk_group_key), - /* K15 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20destinationMessage_X3D), - /* K16 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20key_ipk_X3D), - /* K17 */ be_nested_str_weak(HMAC_SHA256), - /* K18 */ be_nested_str_weak(update), - /* K19 */ be_nested_str_weak(out), - /* K20 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20candidateDestinationId_X3D), - /* K21 */ be_nested_str_weak(stop_iteration), + /* K8 */ be_nested_str_weak(fabrics), + /* K9 */ be_nested_str_weak(noc), + /* K10 */ be_nested_str_weak(fabric_id), + /* K11 */ be_nested_str_weak(device_id), + /* K12 */ be_nested_str_weak(get_ca_pub), + /* K13 */ be_nested_str_weak(get_ipk_group_key), + /* K14 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20destinationMessage_X3D), + /* K15 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20key_ipk_X3D), + /* K16 */ be_nested_str_weak(HMAC_SHA256), + /* K17 */ be_nested_str_weak(update), + /* K18 */ be_nested_str_weak(out), + /* K19 */ be_nested_str_weak(MTR_X3A_X20SIGMA1_X3A_X20candidateDestinationId_X3D), + /* K20 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(find_session_by_destination_id), + be_str_weak(find_fabric_by_destination_id), &be_const_str_solidified, - ( &(const binstruction[79]) { /* code */ + ( &(const binstruction[77]) { /* code */ 0xA40E0000, // 0000 IMPORT R3 K0 0xB8120200, // 0001 GETNGBL R4 K1 0x8C100902, // 0002 GETMET R4 R4 K2 @@ -698,74 +103,72 @@ be_local_closure(Matter_Commisioning_Context_find_session_by_destination_id, / 0x60100010, // 0008 GETGBL R4 G16 0x88140106, // 0009 GETMBR R5 R0 K6 0x88140B07, // 000A GETMBR R5 R5 K7 - 0x88140B07, // 000B GETMBR R5 R5 K7 + 0x88140B08, // 000B GETMBR R5 R5 K8 0x7C100200, // 000C CALL R4 1 - 0xA802003B, // 000D EXBLK 0 #004A + 0xA8020039, // 000D EXBLK 0 #0048 0x5C140800, // 000E MOVE R5 R4 0x7C140000, // 000F CALL R5 0 - 0x88180B08, // 0010 GETMBR R6 R5 K8 + 0x88180B09, // 0010 GETMBR R6 R5 K9 0x4C1C0000, // 0011 LDNIL R7 0x1C180C07, // 0012 EQ R6 R6 R7 0x741A0007, // 0013 JMPT R6 #001C - 0x88180B09, // 0014 GETMBR R6 R5 K9 + 0x88180B0A, // 0014 GETMBR R6 R5 K10 0x4C1C0000, // 0015 LDNIL R7 0x1C180C07, // 0016 EQ R6 R6 R7 0x741A0003, // 0017 JMPT R6 #001C - 0x88180B0A, // 0018 GETMBR R6 R5 K10 + 0x88180B0B, // 0018 GETMBR R6 R5 K11 0x4C1C0000, // 0019 LDNIL R7 0x1C180C07, // 001A EQ R6 R6 R7 0x781A0000, // 001B JMPF R6 #001D 0x7001FFF0, // 001C JMP #000E - 0x8C180B0B, // 001D GETMET R6 R5 K11 + 0x8C180B0C, // 001D GETMET R6 R5 K12 0x7C180200, // 001E CALL R6 1 0x00180406, // 001F ADD R6 R2 R6 - 0x8C1C0B0C, // 0020 GETMET R7 R5 K12 - 0x7C1C0200, // 0021 CALL R7 1 - 0x00180C07, // 0022 ADD R6 R6 R7 - 0x8C1C0B0D, // 0023 GETMET R7 R5 K13 - 0x7C1C0200, // 0024 CALL R7 1 - 0x00180C07, // 0025 ADD R6 R6 R7 - 0x8C1C0B0E, // 0026 GETMET R7 R5 K14 - 0x7C1C0200, // 0027 CALL R7 1 - 0xB8220200, // 0028 GETNGBL R8 K1 - 0x8C201102, // 0029 GETMET R8 R8 K2 - 0x8C280D04, // 002A GETMET R10 R6 K4 - 0x7C280200, // 002B CALL R10 1 - 0x002A1E0A, // 002C ADD R10 K15 R10 - 0x582C0005, // 002D LDCONST R11 K5 - 0x7C200600, // 002E CALL R8 3 - 0xB8220200, // 002F GETNGBL R8 K1 - 0x8C201102, // 0030 GETMET R8 R8 K2 - 0x8C280F04, // 0031 GETMET R10 R7 K4 - 0x7C280200, // 0032 CALL R10 1 - 0x002A200A, // 0033 ADD R10 K16 R10 - 0x582C0005, // 0034 LDCONST R11 K5 - 0x7C200600, // 0035 CALL R8 3 - 0x8C200711, // 0036 GETMET R8 R3 K17 - 0x5C280E00, // 0037 MOVE R10 R7 - 0x7C200400, // 0038 CALL R8 2 - 0x8C241112, // 0039 GETMET R9 R8 K18 - 0x5C2C0C00, // 003A MOVE R11 R6 - 0x7C240400, // 003B CALL R9 2 - 0x8C241113, // 003C GETMET R9 R8 K19 - 0x7C240200, // 003D CALL R9 1 - 0xB82A0200, // 003E GETNGBL R10 K1 - 0x8C281502, // 003F GETMET R10 R10 K2 - 0x8C301304, // 0040 GETMET R12 R9 K4 - 0x7C300200, // 0041 CALL R12 1 - 0x0032280C, // 0042 ADD R12 K20 R12 - 0x58340005, // 0043 LDCONST R13 K5 - 0x7C280600, // 0044 CALL R10 3 - 0x1C281201, // 0045 EQ R10 R9 R1 - 0x782A0001, // 0046 JMPF R10 #0049 - 0xA8040001, // 0047 EXBLK 1 1 - 0x80040A00, // 0048 RET 1 R5 - 0x7001FFC3, // 0049 JMP #000E - 0x58100015, // 004A LDCONST R4 K21 - 0xAC100200, // 004B CATCH R4 1 0 - 0xB0080000, // 004C RAISE 2 R0 R0 - 0x4C100000, // 004D LDNIL R4 - 0x80040800, // 004E RET 1 R4 + 0x881C0B0A, // 0020 GETMBR R7 R5 K10 + 0x00180C07, // 0021 ADD R6 R6 R7 + 0x881C0B0B, // 0022 GETMBR R7 R5 K11 + 0x00180C07, // 0023 ADD R6 R6 R7 + 0x8C1C0B0D, // 0024 GETMET R7 R5 K13 + 0x7C1C0200, // 0025 CALL R7 1 + 0xB8220200, // 0026 GETNGBL R8 K1 + 0x8C201102, // 0027 GETMET R8 R8 K2 + 0x8C280D04, // 0028 GETMET R10 R6 K4 + 0x7C280200, // 0029 CALL R10 1 + 0x002A1C0A, // 002A ADD R10 K14 R10 + 0x582C0005, // 002B LDCONST R11 K5 + 0x7C200600, // 002C CALL R8 3 + 0xB8220200, // 002D GETNGBL R8 K1 + 0x8C201102, // 002E GETMET R8 R8 K2 + 0x8C280F04, // 002F GETMET R10 R7 K4 + 0x7C280200, // 0030 CALL R10 1 + 0x002A1E0A, // 0031 ADD R10 K15 R10 + 0x542E0003, // 0032 LDINT R11 4 + 0x7C200600, // 0033 CALL R8 3 + 0x8C200710, // 0034 GETMET R8 R3 K16 + 0x5C280E00, // 0035 MOVE R10 R7 + 0x7C200400, // 0036 CALL R8 2 + 0x8C241111, // 0037 GETMET R9 R8 K17 + 0x5C2C0C00, // 0038 MOVE R11 R6 + 0x7C240400, // 0039 CALL R9 2 + 0x8C241112, // 003A GETMET R9 R8 K18 + 0x7C240200, // 003B CALL R9 1 + 0xB82A0200, // 003C GETNGBL R10 K1 + 0x8C281502, // 003D GETMET R10 R10 K2 + 0x8C301304, // 003E GETMET R12 R9 K4 + 0x7C300200, // 003F CALL R12 1 + 0x0032260C, // 0040 ADD R12 K19 R12 + 0x58340005, // 0041 LDCONST R13 K5 + 0x7C280600, // 0042 CALL R10 3 + 0x1C281201, // 0043 EQ R10 R9 R1 + 0x782A0001, // 0044 JMPF R10 #0047 + 0xA8040001, // 0045 EXBLK 1 1 + 0x80040A00, // 0046 RET 1 R5 + 0x7001FFC5, // 0047 JMP #000E + 0x58100014, // 0048 LDCONST R4 K20 + 0xAC100200, // 0049 CATCH R4 1 0 + 0xB0080000, // 004A RAISE 2 R0 R0 + 0x4C100000, // 004B LDNIL R4 + 0x80040800, // 004C RET 1 R4 }) ) ); @@ -797,562 +200,55 @@ be_local_closure(Matter_Commisioning_Context_every_second, /* name */ /******************************************************************** -** Solidified function: parse_Sigma3 +** Solidified function: add_session ********************************************************************/ -be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ +be_local_closure(Matter_Commisioning_Context_add_session, /* name */ be_nested_proto( - 38, /* nstack */ - 2, /* argc */ + 14, /* nstack */ + 6, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[94]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(opcode), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(protocol_id), - /* K5 */ be_nested_str_weak(protocol_error), - /* K6 */ be_nested_str_weak(invalid_X20Pake1_X20message), - /* K7 */ be_nested_str_weak(session), - /* K8 */ be_nested_str_weak(matter), - /* K9 */ be_nested_str_weak(Sigma3), - /* K10 */ be_nested_str_weak(parse), - /* K11 */ be_nested_str_weak(raw), - /* K12 */ be_nested_str_weak(app_payload_idx), - /* K13 */ be_nested_str_weak(tasmota), - /* K14 */ be_nested_str_weak(log), - /* K15 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K16 */ be_const_int(3), - /* K17 */ be_nested_str_weak(SHA256), - /* K18 */ be_nested_str_weak(update), - /* K19 */ be_nested_str_weak(_Msg1), - /* K20 */ be_nested_str_weak(_Msg2), - /* K21 */ be_nested_str_weak(out), - /* K22 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20session_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K23 */ be_nested_str_weak(MTR_X3A_X20session_X2Eipk_epoch_key_X20), - /* K24 */ be_nested_str_weak(ipk_epoch_key), - /* K25 */ be_nested_str_weak(MTR_X3A_X20session_X2Efabric_compressed_X20), - /* K26 */ be_nested_str_weak(fabric_compressed), - /* K27 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ipk_group_key_X20_X3D_X20), - /* K28 */ be_nested_str_weak(get_ipk_group_key), - /* K29 */ be_nested_str_weak(tohex), - /* K30 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TranscriptHash_X3D_X20), - /* K31 */ be_nested_str_weak(fromstring), - /* K32 */ be_nested_str_weak(S3K_Info), - /* K33 */ be_nested_str_weak(HKDF_SHA256), - /* K34 */ be_nested_str_weak(derive), - /* K35 */ be_nested_str_weak(shared_secret), - /* K36 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s3k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K37 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s3k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K38 */ be_nested_str_weak(TBEData3Encrypted), - /* K39 */ be_const_int(2147483647), - /* K40 */ be_nested_str_weak(AES_CCM), - /* K41 */ be_nested_str_weak(TBEData3_Nonce), - /* K42 */ be_nested_str_weak(decrypt), - /* K43 */ be_nested_str_weak(tag), - /* K44 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData3_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K45 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBETag3_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K46 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_sent_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K47 */ be_nested_str_weak(value_error), - /* K48 */ be_nested_str_weak(tag_X20do_X20not_X20match), - /* K49 */ be_nested_str_weak(TLV), - /* K50 */ be_nested_str_weak(findsubval), - /* K51 */ be_const_int(1), - /* K52 */ be_const_int(2), - /* K53 */ be_nested_str_weak(MTR_X3A_X20initiatorNOCTLV_X20_X3D_X20), - /* K54 */ be_nested_str_weak(findsub), - /* K55 */ be_nested_str_weak(int), - /* K56 */ be_nested_str_weak(int64), - /* K57 */ be_nested_str_weak(peer_node_id), - /* K58 */ be_nested_str_weak(tobytes), - /* K59 */ be_nested_str_weak(MTR_X3A_X20initiatorFabricId_X3D), - /* K60 */ be_nested_str_weak(Matter_TLV_struct), - /* K61 */ be_nested_str_weak(add_TLV), - /* K62 */ be_nested_str_weak(B1), - /* K63 */ be_nested_str_weak(initiatorEph_pub), - /* K64 */ be_nested_str_weak(ResponderEph_pub), - /* K65 */ be_nested_str_weak(encode), - /* K66 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20initiatorNOCPubKey_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K67 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ec_signature_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K68 */ be_nested_str_weak(EC_P256), - /* K69 */ be_nested_str_weak(ecdsa_verify_sha256), - /* K70 */ be_nested_str_weak(sigma3_tbs_X20does_X20not_X20have_X20a_X20valid_X20signature), - /* K71 */ be_nested_str_weak(MTR_X3A_X20Sigma3_X20verified_X2C_X20computing_X20new_X20keys), - /* K72 */ be_nested_str_weak(Msg3), - /* K73 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K74 */ be_nested_str_weak(MTR_X3A_X20shared_secret_X20_X3D), - /* K75 */ be_nested_str_weak(MTR_X3A_X20ipk_X20_X2B_X20hash_X20_X20_X20_X20_X3D), - /* K76 */ be_nested_str_weak(SEKeys_Info), - /* K77 */ be_nested_str_weak(rtc), - /* K78 */ be_nested_str_weak(utc), - /* K79 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), - /* K80 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), - /* K81 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K82 */ be_nested_str_weak(build_response), - /* K83 */ be_nested_str_weak(add), - /* K84 */ be_nested_str_weak(responder), - /* K85 */ be_nested_str_weak(send_response), - /* K86 */ be_nested_str_weak(remote_ip), - /* K87 */ be_nested_str_weak(remote_port), - /* K88 */ be_nested_str_weak(message_counter), - /* K89 */ be_nested_str_weak(close), - /* K90 */ be_nested_str_weak(set_keys), - /* K91 */ be_nested_str_weak(set_persist), - /* K92 */ be_nested_str_weak(set_no_expiration), - /* K93 */ be_nested_str_weak(save), + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20add_session_X20local_session_id_X3D_X25i_X20initiator_session_id_X3D_X25i), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(device), + /* K7 */ be_nested_str_weak(sessions), + /* K8 */ be_nested_str_weak(create_session), + /* K9 */ be_nested_str_weak(set_keys), }), - be_str_weak(parse_Sigma3), + be_str_weak(add_session), &be_const_str_solidified, - ( &(const binstruction[445]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x880C0301, // 0001 GETMBR R3 R1 K1 - 0x54120031, // 0002 LDINT R4 50 - 0x200C0604, // 0003 NE R3 R3 R4 - 0x740E0005, // 0004 JMPT R3 #000B - 0x880C0302, // 0005 GETMBR R3 R1 K2 - 0x200C0703, // 0006 NE R3 R3 K3 - 0x740E0002, // 0007 JMPT R3 #000B - 0x880C0304, // 0008 GETMBR R3 R1 K4 - 0x200C0703, // 0009 NE R3 R3 K3 - 0x780E0000, // 000A JMPF R3 #000C - 0xB0060B06, // 000B RAISE 1 K5 K6 - 0x880C0307, // 000C GETMBR R3 R1 K7 - 0xB8121000, // 000D GETNGBL R4 K8 - 0x8C100909, // 000E GETMET R4 R4 K9 - 0x7C100200, // 000F CALL R4 1 - 0x8C10090A, // 0010 GETMET R4 R4 K10 - 0x8818030B, // 0011 GETMBR R6 R1 K11 - 0x881C030C, // 0012 GETMBR R7 R1 K12 - 0x7C100600, // 0013 CALL R4 3 - 0xB8161A00, // 0014 GETNGBL R5 K13 - 0x8C140B0E, // 0015 GETMET R5 R5 K14 - 0x581C000F, // 0016 LDCONST R7 K15 - 0x58200010, // 0017 LDCONST R8 K16 - 0x7C140600, // 0018 CALL R5 3 - 0x8C140511, // 0019 GETMET R5 R2 K17 - 0x7C140200, // 001A CALL R5 1 - 0x8C140B12, // 001B GETMET R5 R5 K18 - 0x881C0713, // 001C GETMBR R7 R3 K19 - 0x7C140400, // 001D CALL R5 2 - 0x8C140B12, // 001E GETMET R5 R5 K18 - 0x881C0714, // 001F GETMBR R7 R3 K20 - 0x7C140400, // 0020 CALL R5 2 - 0x8C140B15, // 0021 GETMET R5 R5 K21 - 0x7C140200, // 0022 CALL R5 1 - 0xB81A1A00, // 0023 GETNGBL R6 K13 - 0x8C180D0E, // 0024 GETMET R6 R6 K14 - 0x60200008, // 0025 GETGBL R8 G8 - 0x5C240600, // 0026 MOVE R9 R3 - 0x7C200200, // 0027 CALL R8 1 - 0x00222C08, // 0028 ADD R8 K22 R8 - 0x58240010, // 0029 LDCONST R9 K16 - 0x7C180600, // 002A CALL R6 3 - 0xB81A1A00, // 002B GETNGBL R6 K13 - 0x8C180D0E, // 002C GETMET R6 R6 K14 - 0x60200008, // 002D GETGBL R8 G8 - 0x88240718, // 002E GETMBR R9 R3 K24 - 0x7C200200, // 002F CALL R8 1 - 0x00222E08, // 0030 ADD R8 K23 R8 - 0x58240010, // 0031 LDCONST R9 K16 - 0x7C180600, // 0032 CALL R6 3 - 0xB81A1A00, // 0033 GETNGBL R6 K13 - 0x8C180D0E, // 0034 GETMET R6 R6 K14 - 0x60200008, // 0035 GETGBL R8 G8 - 0x8824071A, // 0036 GETMBR R9 R3 K26 - 0x7C200200, // 0037 CALL R8 1 - 0x00223208, // 0038 ADD R8 K25 R8 - 0x58240010, // 0039 LDCONST R9 K16 - 0x7C180600, // 003A CALL R6 3 - 0xB81A1A00, // 003B GETNGBL R6 K13 - 0x8C180D0E, // 003C GETMET R6 R6 K14 - 0x8C20071C, // 003D GETMET R8 R3 K28 - 0x7C200200, // 003E CALL R8 1 - 0x8C20111D, // 003F GETMET R8 R8 K29 - 0x7C200200, // 0040 CALL R8 1 - 0x00223608, // 0041 ADD R8 K27 R8 - 0x58240010, // 0042 LDCONST R9 K16 - 0x7C180600, // 0043 CALL R6 3 - 0xB81A1A00, // 0044 GETNGBL R6 K13 - 0x8C180D0E, // 0045 GETMET R6 R6 K14 - 0x8C200B1D, // 0046 GETMET R8 R5 K29 - 0x7C200200, // 0047 CALL R8 1 - 0x00223C08, // 0048 ADD R8 K30 R8 - 0x58240010, // 0049 LDCONST R9 K16 - 0x7C180600, // 004A CALL R6 3 - 0x60180015, // 004B GETGBL R6 G21 - 0x7C180000, // 004C CALL R6 0 - 0x8C180D1F, // 004D GETMET R6 R6 K31 - 0x88200120, // 004E GETMBR R8 R0 K32 - 0x7C180400, // 004F CALL R6 2 - 0x8C1C0521, // 0050 GETMET R7 R2 K33 - 0x7C1C0200, // 0051 CALL R7 1 - 0x8C1C0F22, // 0052 GETMET R7 R7 K34 - 0x88240723, // 0053 GETMBR R9 R3 K35 - 0x8C28071C, // 0054 GETMET R10 R3 K28 - 0x7C280200, // 0055 CALL R10 1 - 0x00281405, // 0056 ADD R10 R10 R5 - 0x5C2C0C00, // 0057 MOVE R11 R6 - 0x5432000F, // 0058 LDINT R12 16 - 0x7C1C0A00, // 0059 CALL R7 5 - 0xB8221A00, // 005A GETNGBL R8 K13 - 0x8C20110E, // 005B GETMET R8 R8 K14 - 0x5828000F, // 005C LDCONST R10 K15 - 0x582C0010, // 005D LDCONST R11 K16 - 0x7C200600, // 005E CALL R8 3 - 0xB8221A00, // 005F GETNGBL R8 K13 - 0x8C20110E, // 0060 GETMET R8 R8 K14 - 0x8C28071C, // 0061 GETMET R10 R3 K28 - 0x7C280200, // 0062 CALL R10 1 - 0x00281405, // 0063 ADD R10 R10 R5 - 0x8C28151D, // 0064 GETMET R10 R10 K29 - 0x7C280200, // 0065 CALL R10 1 - 0x002A480A, // 0066 ADD R10 K36 R10 - 0x582C0010, // 0067 LDCONST R11 K16 - 0x7C200600, // 0068 CALL R8 3 - 0xB8221A00, // 0069 GETNGBL R8 K13 - 0x8C20110E, // 006A GETMET R8 R8 K14 - 0x8C280F1D, // 006B GETMET R10 R7 K29 - 0x7C280200, // 006C CALL R10 1 - 0x002A4A0A, // 006D ADD R10 K37 R10 - 0x582C0010, // 006E LDCONST R11 K16 - 0x7C200600, // 006F CALL R8 3 - 0xB8221A00, // 0070 GETNGBL R8 K13 - 0x8C20110E, // 0071 GETMET R8 R8 K14 - 0x5828000F, // 0072 LDCONST R10 K15 - 0x582C0010, // 0073 LDCONST R11 K16 - 0x7C200600, // 0074 CALL R8 3 - 0x5421FFEE, // 0075 LDINT R8 -17 - 0x40220608, // 0076 CONNECT R8 K3 R8 - 0x88240926, // 0077 GETMBR R9 R4 K38 - 0x94201208, // 0078 GETIDX R8 R9 R8 - 0x5429FFEF, // 0079 LDINT R10 -16 - 0x40281527, // 007A CONNECT R10 R10 K39 - 0x882C0926, // 007B GETMBR R11 R4 K38 - 0x9424160A, // 007C GETIDX R9 R11 R10 - 0x8C300528, // 007D GETMET R12 R2 K40 - 0x5C380E00, // 007E MOVE R14 R7 - 0x603C0015, // 007F GETGBL R15 G21 - 0x7C3C0000, // 0080 CALL R15 0 - 0x8C3C1F1F, // 0081 GETMET R15 R15 K31 - 0x88440129, // 0082 GETMBR R17 R0 K41 - 0x7C3C0400, // 0083 CALL R15 2 - 0x60400015, // 0084 GETGBL R16 G21 - 0x7C400000, // 0085 CALL R16 0 - 0x6044000C, // 0086 GETGBL R17 G12 - 0x5C481000, // 0087 MOVE R18 R8 - 0x7C440200, // 0088 CALL R17 1 - 0x544A000F, // 0089 LDINT R18 16 - 0x7C300C00, // 008A CALL R12 6 - 0x5C281800, // 008B MOVE R10 R12 - 0x8C30152A, // 008C GETMET R12 R10 K42 - 0x5C381000, // 008D MOVE R14 R8 - 0x7C300400, // 008E CALL R12 2 - 0x5C2C1800, // 008F MOVE R11 R12 - 0x8C30152B, // 0090 GETMET R12 R10 K43 - 0x7C300200, // 0091 CALL R12 1 - 0xB8361A00, // 0092 GETNGBL R13 K13 - 0x8C341B0E, // 0093 GETMET R13 R13 K14 - 0x8C3C171D, // 0094 GETMET R15 R11 K29 - 0x7C3C0200, // 0095 CALL R15 1 - 0x003E580F, // 0096 ADD R15 K44 R15 - 0x58400010, // 0097 LDCONST R16 K16 - 0x7C340600, // 0098 CALL R13 3 - 0xB8361A00, // 0099 GETNGBL R13 K13 - 0x8C341B0E, // 009A GETMET R13 R13 K14 - 0x8C3C191D, // 009B GETMET R15 R12 K29 - 0x7C3C0200, // 009C CALL R15 1 - 0x003E5A0F, // 009D ADD R15 K45 R15 - 0x58400010, // 009E LDCONST R16 K16 - 0x7C340600, // 009F CALL R13 3 - 0xB8361A00, // 00A0 GETNGBL R13 K13 - 0x8C341B0E, // 00A1 GETMET R13 R13 K14 - 0x8C3C131D, // 00A2 GETMET R15 R9 K29 - 0x7C3C0200, // 00A3 CALL R15 1 - 0x003E5C0F, // 00A4 ADD R15 K46 R15 - 0x58400010, // 00A5 LDCONST R16 K16 - 0x7C340600, // 00A6 CALL R13 3 - 0xB8361A00, // 00A7 GETNGBL R13 K13 - 0x8C341B0E, // 00A8 GETMET R13 R13 K14 - 0x583C000F, // 00A9 LDCONST R15 K15 - 0x58400010, // 00AA LDCONST R16 K16 - 0x7C340600, // 00AB CALL R13 3 - 0x20341809, // 00AC NE R13 R12 R9 - 0x78360000, // 00AD JMPF R13 #00AF - 0xB0065F30, // 00AE RAISE 1 K47 K48 - 0xB8361000, // 00AF GETNGBL R13 K8 - 0x88341B31, // 00B0 GETMBR R13 R13 K49 - 0x8C341B0A, // 00B1 GETMET R13 R13 K10 - 0x5C3C1600, // 00B2 MOVE R15 R11 - 0x7C340400, // 00B3 CALL R13 2 - 0x8C381B32, // 00B4 GETMET R14 R13 K50 - 0x58400033, // 00B5 LDCONST R16 K51 - 0x7C380400, // 00B6 CALL R14 2 - 0x8C3C1B32, // 00B7 GETMET R15 R13 K50 - 0x58440034, // 00B8 LDCONST R17 K52 - 0x7C3C0400, // 00B9 CALL R15 2 - 0x8C401B32, // 00BA GETMET R16 R13 K50 - 0x58480010, // 00BB LDCONST R18 K16 - 0x7C400400, // 00BC CALL R16 2 - 0xB8461000, // 00BD GETNGBL R17 K8 - 0x88442331, // 00BE GETMBR R17 R17 K49 - 0x8C44230A, // 00BF GETMET R17 R17 K10 - 0x5C4C1C00, // 00C0 MOVE R19 R14 - 0x7C440400, // 00C1 CALL R17 2 - 0xB84A1A00, // 00C2 GETNGBL R18 K13 - 0x8C48250E, // 00C3 GETMET R18 R18 K14 - 0x60500008, // 00C4 GETGBL R20 G8 - 0x5C542200, // 00C5 MOVE R21 R17 - 0x7C500200, // 00C6 CALL R20 1 - 0x00526A14, // 00C7 ADD R20 K53 R20 - 0x58540010, // 00C8 LDCONST R21 K16 - 0x7C480600, // 00C9 CALL R18 3 - 0x8C482332, // 00CA GETMET R18 R17 K50 - 0x54520008, // 00CB LDINT R20 9 - 0x7C480400, // 00CC CALL R18 2 - 0x8C4C2336, // 00CD GETMET R19 R17 K54 - 0x54560005, // 00CE LDINT R21 6 - 0x7C4C0400, // 00CF CALL R19 2 - 0x8C502732, // 00D0 GETMET R20 R19 K50 - 0x545A0010, // 00D1 LDINT R22 17 - 0x7C500400, // 00D2 CALL R20 2 - 0x60540004, // 00D3 GETGBL R21 G4 - 0x5C582800, // 00D4 MOVE R22 R20 - 0x7C540200, // 00D5 CALL R21 1 - 0x1C542B37, // 00D6 EQ R21 R21 K55 - 0x78560003, // 00D7 JMPF R21 #00DC - 0xB8567000, // 00D8 GETNGBL R21 K56 - 0x5C582800, // 00D9 MOVE R22 R20 - 0x7C540200, // 00DA CALL R21 1 - 0x5C502A00, // 00DB MOVE R20 R21 - 0x8C54293A, // 00DC GETMET R21 R20 K58 - 0x7C540200, // 00DD CALL R21 1 - 0x900E7215, // 00DE SETMBR R3 K57 R21 - 0xB8561A00, // 00DF GETNGBL R21 K13 - 0x8C542B0E, // 00E0 GETMET R21 R21 K14 - 0x605C0008, // 00E1 GETGBL R23 G8 - 0x88600739, // 00E2 GETMBR R24 R3 K57 - 0x7C5C0200, // 00E3 CALL R23 1 - 0x005E7617, // 00E4 ADD R23 K59 R23 - 0x58600010, // 00E5 LDCONST R24 K16 - 0x7C540600, // 00E6 CALL R21 3 - 0xB8561000, // 00E7 GETNGBL R21 K8 - 0x88542B31, // 00E8 GETMBR R21 R21 K49 - 0x8C542B3C, // 00E9 GETMET R21 R21 K60 - 0x7C540200, // 00EA CALL R21 1 - 0x8C582B3D, // 00EB GETMET R22 R21 K61 - 0x58600033, // 00EC LDCONST R24 K51 - 0xB8661000, // 00ED GETNGBL R25 K8 - 0x88643331, // 00EE GETMBR R25 R25 K49 - 0x8864333E, // 00EF GETMBR R25 R25 K62 - 0x5C681C00, // 00F0 MOVE R26 R14 - 0x7C580800, // 00F1 CALL R22 4 - 0x8C582B3D, // 00F2 GETMET R22 R21 K61 - 0x58600034, // 00F3 LDCONST R24 K52 - 0xB8661000, // 00F4 GETNGBL R25 K8 - 0x88643331, // 00F5 GETMBR R25 R25 K49 - 0x8864333E, // 00F6 GETMBR R25 R25 K62 - 0x5C681E00, // 00F7 MOVE R26 R15 - 0x7C580800, // 00F8 CALL R22 4 - 0x8C582B3D, // 00F9 GETMET R22 R21 K61 - 0x58600010, // 00FA LDCONST R24 K16 - 0xB8661000, // 00FB GETNGBL R25 K8 - 0x88643331, // 00FC GETMBR R25 R25 K49 - 0x8864333E, // 00FD GETMBR R25 R25 K62 - 0x8868013F, // 00FE GETMBR R26 R0 K63 - 0x7C580800, // 00FF CALL R22 4 - 0x8C582B3D, // 0100 GETMET R22 R21 K61 - 0x54620003, // 0101 LDINT R24 4 - 0xB8661000, // 0102 GETNGBL R25 K8 - 0x88643331, // 0103 GETMBR R25 R25 K49 - 0x8864333E, // 0104 GETMBR R25 R25 K62 - 0x88680140, // 0105 GETMBR R26 R0 K64 - 0x7C580800, // 0106 CALL R22 4 - 0x8C582B41, // 0107 GETMET R22 R21 K65 - 0x7C580200, // 0108 CALL R22 1 - 0xB85E1A00, // 0109 GETNGBL R23 K13 - 0x8C5C2F0E, // 010A GETMET R23 R23 K14 - 0x8C64251D, // 010B GETMET R25 R18 K29 - 0x7C640200, // 010C CALL R25 1 - 0x00668419, // 010D ADD R25 K66 R25 - 0x58680010, // 010E LDCONST R26 K16 - 0x7C5C0600, // 010F CALL R23 3 - 0xB85E1A00, // 0110 GETNGBL R23 K13 - 0x8C5C2F0E, // 0111 GETMET R23 R23 K14 - 0x8C64211D, // 0112 GETMET R25 R16 K29 - 0x7C640200, // 0113 CALL R25 1 - 0x00668619, // 0114 ADD R25 K67 R25 - 0x58680010, // 0115 LDCONST R26 K16 - 0x7C5C0600, // 0116 CALL R23 3 - 0xB85E1A00, // 0117 GETNGBL R23 K13 - 0x8C5C2F0E, // 0118 GETMET R23 R23 K14 - 0x5864000F, // 0119 LDCONST R25 K15 - 0x58680010, // 011A LDCONST R26 K16 - 0x7C5C0600, // 011B CALL R23 3 - 0x8C5C0544, // 011C GETMET R23 R2 K68 - 0x7C5C0200, // 011D CALL R23 1 - 0x8C5C2F45, // 011E GETMET R23 R23 K69 - 0x5C642400, // 011F MOVE R25 R18 - 0x5C682C00, // 0120 MOVE R26 R22 - 0x5C6C2000, // 0121 MOVE R27 R16 - 0x7C5C0800, // 0122 CALL R23 4 - 0x5C602E00, // 0123 MOVE R24 R23 - 0x74620000, // 0124 JMPT R24 #0126 - 0xB0065F46, // 0125 RAISE 1 K47 K70 - 0xB8621A00, // 0126 GETNGBL R24 K13 - 0x8C60310E, // 0127 GETMET R24 R24 K14 - 0x58680047, // 0128 LDCONST R26 K71 - 0x586C0010, // 0129 LDCONST R27 K16 - 0x7C600600, // 012A CALL R24 3 - 0x8C600511, // 012B GETMET R24 R2 K17 - 0x7C600200, // 012C CALL R24 1 - 0x8C603112, // 012D GETMET R24 R24 K18 - 0x88680713, // 012E GETMBR R26 R3 K19 - 0x7C600400, // 012F CALL R24 2 - 0x8C603112, // 0130 GETMET R24 R24 K18 - 0x88680714, // 0131 GETMBR R26 R3 K20 - 0x7C600400, // 0132 CALL R24 2 - 0x8C603112, // 0133 GETMET R24 R24 K18 - 0x88680948, // 0134 GETMBR R26 R4 K72 - 0x7C600400, // 0135 CALL R24 2 - 0x8C603115, // 0136 GETMET R24 R24 K21 - 0x7C600200, // 0137 CALL R24 1 - 0x5C143000, // 0138 MOVE R5 R24 - 0x4C600000, // 0139 LDNIL R24 - 0x900E2618, // 013A SETMBR R3 K19 R24 - 0x4C600000, // 013B LDNIL R24 - 0x900E2818, // 013C SETMBR R3 K20 R24 - 0xB8621A00, // 013D GETNGBL R24 K13 - 0x8C60310E, // 013E GETMET R24 R24 K14 - 0x58680049, // 013F LDCONST R26 K73 - 0x586C0010, // 0140 LDCONST R27 K16 - 0x7C600600, // 0141 CALL R24 3 - 0xB8621A00, // 0142 GETNGBL R24 K13 - 0x8C60310E, // 0143 GETMET R24 R24 K14 - 0x88680723, // 0144 GETMBR R26 R3 K35 - 0x8C68351D, // 0145 GETMET R26 R26 K29 - 0x7C680200, // 0146 CALL R26 1 - 0x006A941A, // 0147 ADD R26 K74 R26 - 0x586C0010, // 0148 LDCONST R27 K16 - 0x7C600600, // 0149 CALL R24 3 - 0xB8621A00, // 014A GETNGBL R24 K13 - 0x8C60310E, // 014B GETMET R24 R24 K14 - 0x8C68071C, // 014C GETMET R26 R3 K28 - 0x7C680200, // 014D CALL R26 1 - 0x00683405, // 014E ADD R26 R26 R5 - 0x8C68351D, // 014F GETMET R26 R26 K29 - 0x7C680200, // 0150 CALL R26 1 - 0x006A961A, // 0151 ADD R26 K75 R26 - 0x586C0010, // 0152 LDCONST R27 K16 - 0x7C600600, // 0153 CALL R24 3 - 0x8C600521, // 0154 GETMET R24 R2 K33 - 0x7C600200, // 0155 CALL R24 1 - 0x8C603122, // 0156 GETMET R24 R24 K34 - 0x88680723, // 0157 GETMBR R26 R3 K35 - 0x8C6C071C, // 0158 GETMET R27 R3 K28 - 0x7C6C0200, // 0159 CALL R27 1 - 0x006C3605, // 015A ADD R27 R27 R5 - 0x60700015, // 015B GETGBL R28 G21 - 0x7C700000, // 015C CALL R28 0 - 0x8C70391F, // 015D GETMET R28 R28 K31 - 0x8878014C, // 015E GETMBR R30 R0 K76 - 0x7C700400, // 015F CALL R28 2 - 0x5476002F, // 0160 LDINT R29 48 - 0x7C600A00, // 0161 CALL R24 5 - 0x5466000E, // 0162 LDINT R25 15 - 0x40660619, // 0163 CONNECT R25 K3 R25 - 0x94643019, // 0164 GETIDX R25 R24 R25 - 0x546A000F, // 0165 LDINT R26 16 - 0x546E001E, // 0166 LDINT R27 31 - 0x4068341B, // 0167 CONNECT R26 R26 R27 - 0x9468301A, // 0168 GETIDX R26 R24 R26 - 0x546E001F, // 0169 LDINT R27 32 - 0x5472002E, // 016A LDINT R28 47 - 0x406C361C, // 016B CONNECT R27 R27 R28 - 0x946C301B, // 016C GETIDX R27 R24 R27 - 0xB8721A00, // 016D GETNGBL R28 K13 - 0x8C70394D, // 016E GETMET R28 R28 K77 - 0x7C700200, // 016F CALL R28 1 - 0x9470394E, // 0170 GETIDX R28 R28 K78 - 0xB8761A00, // 0171 GETNGBL R29 K13 - 0x8C743B0E, // 0172 GETMET R29 R29 K14 - 0x587C0049, // 0173 LDCONST R31 K73 - 0x58800010, // 0174 LDCONST R32 K16 - 0x7C740600, // 0175 CALL R29 3 - 0xB8761A00, // 0176 GETNGBL R29 K13 - 0x8C743B0E, // 0177 GETMET R29 R29 K14 - 0x8C7C331D, // 0178 GETMET R31 R25 K29 - 0x7C7C0200, // 0179 CALL R31 1 - 0x007E9E1F, // 017A ADD R31 K79 R31 - 0x58800010, // 017B LDCONST R32 K16 - 0x7C740600, // 017C CALL R29 3 - 0xB8761A00, // 017D GETNGBL R29 K13 - 0x8C743B0E, // 017E GETMET R29 R29 K14 - 0x8C7C351D, // 017F GETMET R31 R26 K29 - 0x7C7C0200, // 0180 CALL R31 1 - 0x007EA01F, // 0181 ADD R31 K80 R31 - 0x58800010, // 0182 LDCONST R32 K16 - 0x7C740600, // 0183 CALL R29 3 - 0xB8761A00, // 0184 GETNGBL R29 K13 - 0x8C743B0E, // 0185 GETMET R29 R29 K14 - 0x8C7C371D, // 0186 GETMET R31 R27 K29 - 0x7C7C0200, // 0187 CALL R31 1 - 0x007EA21F, // 0188 ADD R31 K81 R31 - 0x58800010, // 0189 LDCONST R32 K16 - 0x7C740600, // 018A CALL R29 3 - 0xB8761A00, // 018B GETNGBL R29 K13 - 0x8C743B0E, // 018C GETMET R29 R29 K14 - 0x587C0049, // 018D LDCONST R31 K73 - 0x58800010, // 018E LDCONST R32 K16 - 0x7C740600, // 018F CALL R29 3 - 0x8C740352, // 0190 GETMET R29 R1 K82 - 0x547E003F, // 0191 LDINT R31 64 - 0x50800200, // 0192 LDBOOL R32 1 0 - 0x7C740600, // 0193 CALL R29 3 - 0x60780015, // 0194 GETGBL R30 G21 - 0x7C780000, // 0195 CALL R30 0 - 0x8C7C3D53, // 0196 GETMET R31 R30 K83 - 0x58840003, // 0197 LDCONST R33 K3 - 0x58880034, // 0198 LDCONST R34 K52 - 0x7C7C0600, // 0199 CALL R31 3 - 0x8C7C3D53, // 019A GETMET R31 R30 K83 - 0x58840003, // 019B LDCONST R33 K3 - 0x548A0003, // 019C LDINT R34 4 - 0x7C7C0600, // 019D CALL R31 3 - 0x8C7C3D53, // 019E GETMET R31 R30 K83 - 0x58840003, // 019F LDCONST R33 K3 - 0x548A0003, // 01A0 LDINT R34 4 - 0x7C7C0600, // 01A1 CALL R31 3 - 0x8C7C3B41, // 01A2 GETMET R31 R29 K65 - 0x5C843C00, // 01A3 MOVE R33 R30 - 0x7C7C0400, // 01A4 CALL R31 2 - 0x88800154, // 01A5 GETMBR R32 R0 K84 - 0x8C804155, // 01A6 GETMET R32 R32 K85 - 0x5C883E00, // 01A7 MOVE R34 R31 - 0x888C0356, // 01A8 GETMBR R35 R1 K86 - 0x88900357, // 01A9 GETMBR R36 R1 K87 - 0x88943B58, // 01AA GETMBR R37 R29 K88 - 0x7C800A00, // 01AB CALL R32 5 - 0x8C800759, // 01AC GETMET R32 R3 K89 - 0x7C800200, // 01AD CALL R32 1 - 0x8C80075A, // 01AE GETMET R32 R3 K90 - 0x5C883200, // 01AF MOVE R34 R25 - 0x5C8C3400, // 01B0 MOVE R35 R26 - 0x5C903600, // 01B1 MOVE R36 R27 - 0x5C943800, // 01B2 MOVE R37 R28 - 0x7C800A00, // 01B3 CALL R32 5 - 0x8C80075B, // 01B4 GETMET R32 R3 K91 - 0x50880200, // 01B5 LDBOOL R34 1 0 - 0x7C800400, // 01B6 CALL R32 2 - 0x8C80075C, // 01B7 GETMET R32 R3 K92 - 0x7C800200, // 01B8 CALL R32 1 - 0x8C80075D, // 01B9 GETMET R32 R3 K93 - 0x7C800200, // 01BA CALL R32 1 - 0x50800200, // 01BB LDBOOL R32 1 0 - 0x80044000, // 01BC RET 1 R32 + ( &(const binstruction[22]) { /* code */ + 0xA41A0000, // 0000 IMPORT R6 K0 + 0xB81E0200, // 0001 GETNGBL R7 K1 + 0x8C1C0F02, // 0002 GETMET R7 R7 K2 + 0x8C240D03, // 0003 GETMET R9 R6 K3 + 0x582C0004, // 0004 LDCONST R11 K4 + 0x5C300200, // 0005 MOVE R12 R1 + 0x5C340400, // 0006 MOVE R13 R2 + 0x7C240800, // 0007 CALL R9 4 + 0x58280005, // 0008 LDCONST R10 K5 + 0x7C1C0600, // 0009 CALL R7 3 + 0x881C0106, // 000A GETMBR R7 R0 K6 + 0x881C0F07, // 000B GETMBR R7 R7 K7 + 0x8C1C0F08, // 000C GETMET R7 R7 K8 + 0x5C240200, // 000D MOVE R9 R1 + 0x5C280400, // 000E MOVE R10 R2 + 0x7C1C0600, // 000F CALL R7 3 + 0x8C200F09, // 0010 GETMET R8 R7 K9 + 0x5C280600, // 0011 MOVE R10 R3 + 0x5C2C0800, // 0012 MOVE R11 R4 + 0x5C300A00, // 0013 MOVE R12 R5 + 0x7C200800, // 0014 CALL R8 4 + 0x80000000, // 0015 RET 0 }) ) ); @@ -1360,11 +256,11 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ /******************************************************************** -** Solidified function: parse_Sigma1 +** Solidified function: parse_PBKDFParamRequest ********************************************************************/ -be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ +be_local_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest, /* name */ be_nested_proto( - 35, /* nstack */ + 14, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1372,694 +268,465 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[119]) { /* constants */ + ( &(const bvalue[53]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(opcode), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(protocol_id), - /* K5 */ be_nested_str_weak(protocol_error), - /* K6 */ be_nested_str_weak(invalid_X20Pake1_X20message), - /* K7 */ be_nested_str_weak(matter), - /* K8 */ be_nested_str_weak(Sigma1), - /* K9 */ be_nested_str_weak(parse), - /* K10 */ be_nested_str_weak(raw), - /* K11 */ be_nested_str_weak(app_payload_idx), - /* K12 */ be_nested_str_weak(initiatorEph_pub), - /* K13 */ be_nested_str_weak(initiatorEphPubKey), - /* K14 */ be_nested_str_weak(resumptionID), - /* K15 */ be_nested_str_weak(initiatorResumeMIC), - /* K16 */ be_nested_str_weak(device), - /* K17 */ be_nested_str_weak(sessions), - /* K18 */ be_nested_str_weak(find_session_by_resumption_id), - /* K19 */ be_nested_str_weak(find_session_by_destination_id), - /* K20 */ be_nested_str_weak(destinationId), - /* K21 */ be_nested_str_weak(initiatorRandom), - /* K22 */ be_nested_str_weak(valuer_error), - /* K23 */ be_nested_str_weak(StatusReport_X28GeneralCode_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20NO_SHARED_TRUST_ROOTS_X29), - /* K24 */ be_nested_str_weak(source_node_id), - /* K25 */ be_nested_str_weak(set_mode), - /* K26 */ be_nested_str_weak(Session), - /* K27 */ be_nested_str_weak(__CASE), - /* K28 */ be_nested_str_weak(session), - /* K29 */ be_nested_str_weak(remove_session), - /* K30 */ be_nested_str_weak(_future_initiator_session_id), - /* K31 */ be_nested_str_weak(initiator_session_id), - /* K32 */ be_nested_str_weak(_future_local_session_id), - /* K33 */ be_nested_str_weak(gen_local_session_id), - /* K34 */ be_nested_str_weak(future_local_session_id), - /* K35 */ be_nested_str_weak(shared_secret), - /* K36 */ be_nested_str_weak(fromstring), - /* K37 */ be_nested_str_weak(Sigma1_Resume), - /* K38 */ be_nested_str_weak(HKDF_SHA256), - /* K39 */ be_nested_str_weak(derive), - /* K40 */ be_nested_str_weak(NCASE_SigmaR1), - /* K41 */ be_const_int(2147483647), - /* K42 */ be_nested_str_weak(AES_CCM), - /* K43 */ be_nested_str_weak(decrypt), - /* K44 */ be_nested_str_weak(tag), - /* K45 */ be_nested_str_weak(tasmota), - /* K46 */ be_nested_str_weak(log), - /* K47 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K48 */ be_const_int(3), - /* K49 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s1rk_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K50 */ be_nested_str_weak(tohex), - /* K51 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K52 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20Resume1MICPayload_X20_X3D_X20), - /* K53 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20decrypted_tag_X20_X20_X20_X20_X20_X3D_X20), - /* K54 */ be_nested_str_weak(resumption_id), - /* K55 */ be_nested_str_weak(random), - /* K56 */ be_nested_str_weak(Sigma2_Resume), - /* K57 */ be_nested_str_weak(NCASE_SigmaR2), - /* K58 */ be_nested_str_weak(Sigma2Resume), - /* K59 */ be_nested_str_weak(responderSessionID), - /* K60 */ be_nested_str_weak(sigma2ResumeMIC), - /* K61 */ be_nested_str_weak(SessionResumptionKeys), - /* K62 */ be_nested_str_weak(rtc), - /* K63 */ be_nested_str_weak(utc), - /* K64 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K65 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), - /* K66 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), - /* K67 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K68 */ be_nested_str_weak(encode), - /* K69 */ be_nested_str_weak(_Msg1), - /* K70 */ be_nested_str_weak(MTR_X3A_X20sigma2resume_raw_X3A_X20), - /* K71 */ be_nested_str_weak(build_response), - /* K72 */ be_nested_str_weak(responder), - /* K73 */ be_nested_str_weak(send_response), - /* K74 */ be_nested_str_weak(remote_ip), - /* K75 */ be_nested_str_weak(remote_port), - /* K76 */ be_nested_str_weak(message_counter), - /* K77 */ be_nested_str_weak(close), - /* K78 */ be_nested_str_weak(set_keys), - /* K79 */ be_nested_str_weak(set_persist), - /* K80 */ be_nested_str_weak(set_no_expiration), - /* K81 */ be_nested_str_weak(save), - /* K82 */ be_nested_str_weak(ResponderEph_priv), - /* K83 */ be_nested_str_weak(ResponderEph_pub), - /* K84 */ be_nested_str_weak(EC_P256), - /* K85 */ be_nested_str_weak(public_key), - /* K86 */ be_nested_str_weak(shared_key), - /* K87 */ be_nested_str_weak(TLV), - /* K88 */ be_nested_str_weak(Matter_TLV_struct), - /* K89 */ be_nested_str_weak(add_TLV), - /* K90 */ be_const_int(1), - /* K91 */ be_nested_str_weak(B2), - /* K92 */ be_nested_str_weak(get_noc), - /* K93 */ be_const_int(2), - /* K94 */ be_nested_str_weak(get_icac), - /* K95 */ be_nested_str_weak(ecdsa_sign_sha256), - /* K96 */ be_nested_str_weak(get_pk), - /* K97 */ be_nested_str_weak(Msg1), - /* K98 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20MSG1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K99 */ be_nested_str_weak(SHA256), - /* K100 */ be_nested_str_weak(update), - /* K101 */ be_nested_str_weak(out), - /* K102 */ be_nested_str_weak(S2K_Info), - /* K103 */ be_nested_str_weak(get_ipk_group_key), - /* K104 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20SharedSecret_X20_X20_X3D_X20), - /* K105 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K106 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K107 */ be_nested_str_weak(TBEData2_Nonce), - /* K108 */ be_nested_str_weak(encrypt), - /* K109 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData2Enc_X20_X20_X20_X3D_X20), - /* K110 */ be_nested_str_weak(Sigma2), - /* K111 */ be_nested_str_weak(responderRandom), - /* K112 */ be_nested_str_weak(responderSessionId), - /* K113 */ be_nested_str_weak(responderEphPubKey), - /* K114 */ be_nested_str_weak(encrypted2), - /* K115 */ be_nested_str_weak(MTR_X3A_X20sigma2_X3A_X20), - /* K116 */ be_nested_str_weak(inspect), - /* K117 */ be_nested_str_weak(_Msg2), - /* K118 */ be_nested_str_weak(MTR_X3A_X20sigma2_raw_X3A_X20), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(session), + /* K3 */ be_nested_str_weak(opcode), + /* K4 */ be_nested_str_weak(local_session_id), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(protocol_id), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(MTR_X3A_X20invalid_X20PBKDFParamRequest_X20message), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(MTR_X3A_X20StatusReport_X28General_X20Code_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20INVALID_PARAMETER_X29), + /* K12 */ be_nested_str_weak(send_status_report), + /* K13 */ be_const_int(1), + /* K14 */ be_nested_str_weak(matter), + /* K15 */ be_nested_str_weak(PBKDFParamRequest), + /* K16 */ be_nested_str_weak(parse), + /* K17 */ be_nested_str_weak(raw), + /* K18 */ be_nested_str_weak(app_payload_idx), + /* K19 */ be_nested_str_weak(set_mode_PASE), + /* K20 */ be_nested_str_weak(__Msg1), + /* K21 */ be_const_int(2147483647), + /* K22 */ be_nested_str_weak(passcodeId), + /* K23 */ be_nested_str_weak(MTR_X3A_X20non_X2Dzero_X20passcode_X20id), + /* K24 */ be_nested_str_weak(__future_initiator_session_id), + /* K25 */ be_nested_str_weak(initiator_session_id), + /* K26 */ be_nested_str_weak(__future_local_session_id), + /* K27 */ be_nested_str_weak(device), + /* K28 */ be_nested_str_weak(sessions), + /* K29 */ be_nested_str_weak(gen_local_session_id), + /* K30 */ be_nested_str_weak(format), + /* K31 */ be_nested_str_weak(MTR_X3A_X20_X2BSession_X20_X20_X20_X28_X256i_X29_X20from_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), + /* K32 */ be_nested_str_weak(remote_ip), + /* K33 */ be_nested_str_weak(remote_port), + /* K34 */ be_nested_str_weak(PBKDFParamResponse), + /* K35 */ be_nested_str_weak(initiatorRandom), + /* K36 */ be_nested_str_weak(responderRandom), + /* K37 */ be_nested_str_weak(random), + /* K38 */ be_nested_str_weak(responderSessionId), + /* K39 */ be_nested_str_weak(pbkdf_parameters_salt), + /* K40 */ be_nested_str_weak(commissioning_salt), + /* K41 */ be_nested_str_weak(pbkdf_parameters_iterations), + /* K42 */ be_nested_str_weak(commissioning_iterations), + /* K43 */ be_nested_str_weak(MTR_X3A_X20pbkdfparamresp_X3A_X20), + /* K44 */ be_nested_str_weak(inspect), + /* K45 */ be_nested_str_weak(tlv2raw), + /* K46 */ be_nested_str_weak(MTR_X3A_X20pbkdfparamresp_raw_X3A_X20), + /* K47 */ be_nested_str_weak(tohex), + /* K48 */ be_nested_str_weak(__Msg2), + /* K49 */ be_nested_str_weak(build_response), + /* K50 */ be_nested_str_weak(encode_frame), + /* K51 */ be_nested_str_weak(responder), + /* K52 */ be_nested_str_weak(send_response_frame), }), - be_str_weak(parse_Sigma1), + be_str_weak(parse_PBKDFParamRequest), &be_const_str_solidified, - ( &(const binstruction[564]) { /* code */ + ( &(const binstruction[137]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x88100302, // 0002 GETMBR R4 R1 K2 + 0x88140303, // 0003 GETMBR R5 R1 K3 + 0x541A001F, // 0004 LDINT R6 32 + 0x20140A06, // 0005 NE R5 R5 R6 + 0x74160005, // 0006 JMPT R5 #000D + 0x88140304, // 0007 GETMBR R5 R1 K4 + 0x20140B05, // 0008 NE R5 R5 K5 + 0x74160002, // 0009 JMPT R5 #000D + 0x88140306, // 000A GETMBR R5 R1 K6 + 0x20140B05, // 000B NE R5 R5 K5 + 0x78160012, // 000C JMPF R5 #0020 + 0xB8160E00, // 000D GETNGBL R5 K7 + 0x8C140B08, // 000E GETMET R5 R5 K8 + 0x581C0009, // 000F LDCONST R7 K9 + 0x5820000A, // 0010 LDCONST R8 K10 + 0x7C140600, // 0011 CALL R5 3 + 0xB8160E00, // 0012 GETNGBL R5 K7 + 0x8C140B08, // 0013 GETMET R5 R5 K8 + 0x581C000B, // 0014 LDCONST R7 K11 + 0x5820000A, // 0015 LDCONST R8 K10 + 0x7C140600, // 0016 CALL R5 3 + 0x8C14010C, // 0017 GETMET R5 R0 K12 + 0x5C1C0200, // 0018 MOVE R7 R1 + 0x5820000D, // 0019 LDCONST R8 K13 + 0x58240005, // 001A LDCONST R9 K5 + 0x5828000A, // 001B LDCONST R10 K10 + 0x502C0000, // 001C LDBOOL R11 0 0 + 0x7C140C00, // 001D CALL R5 6 + 0x50180000, // 001E LDBOOL R6 0 0 + 0x80040C00, // 001F RET 1 R6 + 0xB8161C00, // 0020 GETNGBL R5 K14 + 0x8C140B0F, // 0021 GETMET R5 R5 K15 + 0x7C140200, // 0022 CALL R5 1 + 0x8C140B10, // 0023 GETMET R5 R5 K16 + 0x881C0311, // 0024 GETMBR R7 R1 K17 + 0x88200312, // 0025 GETMBR R8 R1 K18 + 0x7C140600, // 0026 CALL R5 3 + 0x88180302, // 0027 GETMBR R6 R1 K2 + 0x8C180D13, // 0028 GETMET R6 R6 K19 + 0x7C180200, // 0029 CALL R6 1 + 0x88180312, // 002A GETMBR R6 R1 K18 + 0x40180D15, // 002B CONNECT R6 R6 K21 + 0x881C0311, // 002C GETMBR R7 R1 K17 + 0x94180E06, // 002D GETIDX R6 R7 R6 + 0x90122806, // 002E SETMBR R4 K20 R6 + 0x88180B16, // 002F GETMBR R6 R5 K22 + 0x20180D05, // 0030 NE R6 R6 K5 + 0x781A0012, // 0031 JMPF R6 #0045 + 0xB81A0E00, // 0032 GETNGBL R6 K7 + 0x8C180D08, // 0033 GETMET R6 R6 K8 + 0x58200017, // 0034 LDCONST R8 K23 + 0x5824000A, // 0035 LDCONST R9 K10 + 0x7C180600, // 0036 CALL R6 3 + 0xB81A0E00, // 0037 GETNGBL R6 K7 + 0x8C180D08, // 0038 GETMET R6 R6 K8 + 0x5820000B, // 0039 LDCONST R8 K11 + 0x5824000A, // 003A LDCONST R9 K10 + 0x7C180600, // 003B CALL R6 3 + 0x8C18010C, // 003C GETMET R6 R0 K12 + 0x5C200200, // 003D MOVE R8 R1 + 0x5824000D, // 003E LDCONST R9 K13 + 0x58280005, // 003F LDCONST R10 K5 + 0x582C000A, // 0040 LDCONST R11 K10 + 0x50300000, // 0041 LDBOOL R12 0 0 + 0x7C180C00, // 0042 CALL R6 6 + 0x501C0000, // 0043 LDBOOL R7 0 0 + 0x80040E00, // 0044 RET 1 R7 + 0x88180B19, // 0045 GETMBR R6 R5 K25 + 0x90123006, // 0046 SETMBR R4 K24 R6 + 0x8818011B, // 0047 GETMBR R6 R0 K27 + 0x88180D1C, // 0048 GETMBR R6 R6 K28 + 0x8C180D1D, // 0049 GETMET R6 R6 K29 + 0x7C180200, // 004A CALL R6 1 + 0x90123406, // 004B SETMBR R4 K26 R6 + 0xB81A0E00, // 004C GETNGBL R6 K7 + 0x8C180D08, // 004D GETMET R6 R6 K8 + 0x8C20071E, // 004E GETMET R8 R3 K30 + 0x5828001F, // 004F LDCONST R10 K31 + 0x882C091A, // 0050 GETMBR R11 R4 K26 + 0x88300320, // 0051 GETMBR R12 R1 K32 + 0x88340321, // 0052 GETMBR R13 R1 K33 + 0x7C200A00, // 0053 CALL R8 5 + 0x5824000A, // 0054 LDCONST R9 K10 + 0x7C180600, // 0055 CALL R6 3 + 0xB81A1C00, // 0056 GETNGBL R6 K14 + 0x8C180D22, // 0057 GETMET R6 R6 K34 + 0x7C180200, // 0058 CALL R6 1 + 0x881C0B23, // 0059 GETMBR R7 R5 K35 + 0x901A4607, // 005A SETMBR R6 K35 R7 + 0x8C1C0525, // 005B GETMET R7 R2 K37 + 0x5426001F, // 005C LDINT R9 32 + 0x7C1C0400, // 005D CALL R7 2 + 0x901A4807, // 005E SETMBR R6 K36 R7 + 0x881C091A, // 005F GETMBR R7 R4 K26 + 0x901A4C07, // 0060 SETMBR R6 K38 R7 + 0x881C011B, // 0061 GETMBR R7 R0 K27 + 0x881C0F28, // 0062 GETMBR R7 R7 K40 + 0x901A4E07, // 0063 SETMBR R6 K39 R7 + 0x881C011B, // 0064 GETMBR R7 R0 K27 + 0x881C0F2A, // 0065 GETMBR R7 R7 K42 + 0x901A5207, // 0066 SETMBR R6 K41 R7 + 0xB81E0E00, // 0067 GETNGBL R7 K7 + 0x8C1C0F08, // 0068 GETMET R7 R7 K8 + 0x60240008, // 0069 GETGBL R9 G8 + 0xB82A1C00, // 006A GETNGBL R10 K14 + 0x8C28152C, // 006B GETMET R10 R10 K44 + 0x5C300C00, // 006C MOVE R12 R6 + 0x7C280400, // 006D CALL R10 2 + 0x7C240200, // 006E CALL R9 1 + 0x00265609, // 006F ADD R9 K43 R9 + 0x542A0003, // 0070 LDINT R10 4 + 0x7C1C0600, // 0071 CALL R7 3 + 0x8C1C0D2D, // 0072 GETMET R7 R6 K45 + 0x7C1C0200, // 0073 CALL R7 1 + 0xB8220E00, // 0074 GETNGBL R8 K7 + 0x8C201108, // 0075 GETMET R8 R8 K8 + 0x8C280F2F, // 0076 GETMET R10 R7 K47 + 0x7C280200, // 0077 CALL R10 1 + 0x002A5C0A, // 0078 ADD R10 K46 R10 + 0x542E0003, // 0079 LDINT R11 4 + 0x7C200600, // 007A CALL R8 3 + 0x90126007, // 007B SETMBR R4 K48 R7 + 0x8C200331, // 007C GETMET R8 R1 K49 + 0x542A0020, // 007D LDINT R10 33 + 0x502C0200, // 007E LDBOOL R11 1 0 + 0x7C200600, // 007F CALL R8 3 + 0x8C241132, // 0080 GETMET R9 R8 K50 + 0x5C2C0E00, // 0081 MOVE R11 R7 + 0x7C240400, // 0082 CALL R9 2 + 0x88280133, // 0083 GETMBR R10 R0 K51 + 0x8C281534, // 0084 GETMET R10 R10 K52 + 0x5C301000, // 0085 MOVE R12 R8 + 0x7C280400, // 0086 CALL R10 2 + 0x50280200, // 0087 LDBOOL R10 1 0 + 0x80041400, // 0088 RET 1 R10 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_status_report +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_send_status_report, /* name */ + be_nested_proto( + 12, /* nstack */ + 6, /* 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(build_response), + /* K1 */ be_nested_str_weak(add), + /* K2 */ be_const_int(2), + /* K3 */ be_nested_str_weak(encode_frame), + /* K4 */ be_nested_str_weak(responder), + /* K5 */ be_nested_str_weak(send_response_frame), + }), + be_str_weak(send_status_report), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x8C180300, // 0000 GETMET R6 R1 K0 + 0x5422003F, // 0001 LDINT R8 64 + 0x5C240A00, // 0002 MOVE R9 R5 + 0x7C180600, // 0003 CALL R6 3 + 0x601C0015, // 0004 GETGBL R7 G21 + 0x7C1C0000, // 0005 CALL R7 0 + 0x8C200F01, // 0006 GETMET R8 R7 K1 + 0x5C280400, // 0007 MOVE R10 R2 + 0x582C0002, // 0008 LDCONST R11 K2 + 0x7C200600, // 0009 CALL R8 3 + 0x8C200F01, // 000A GETMET R8 R7 K1 + 0x5C280600, // 000B MOVE R10 R3 + 0x542E0003, // 000C LDINT R11 4 + 0x7C200600, // 000D CALL R8 3 + 0x8C200F01, // 000E GETMET R8 R7 K1 + 0x5C280800, // 000F MOVE R10 R4 + 0x542E0003, // 0010 LDINT R11 4 + 0x7C200600, // 0011 CALL R8 3 + 0x8C200D03, // 0012 GETMET R8 R6 K3 + 0x5C280E00, // 0013 MOVE R10 R7 + 0x7C200400, // 0014 CALL R8 2 + 0x88240104, // 0015 GETMBR R9 R0 K4 + 0x8C241305, // 0016 GETMET R9 R9 K5 + 0x5C2C0C00, // 0017 MOVE R11 R6 + 0x7C240400, // 0018 CALL R9 2 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Pake1 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Pake1, /* name */ + be_nested_proto( + 17, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[47]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(opcode), + /* K3 */ be_nested_str_weak(local_session_id), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(protocol_id), + /* K6 */ be_nested_str_weak(tasmota), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20invalid_X20Pake1_X20message), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_str_weak(MTR_X3A_X20StatusReport_X28General_X20Code_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20INVALID_PARAMETER_X29), + /* K11 */ be_nested_str_weak(send_status_report), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_weak(matter), + /* K14 */ be_nested_str_weak(Pake1), + /* K15 */ be_nested_str_weak(parse), + /* K16 */ be_nested_str_weak(raw), + /* K17 */ be_nested_str_weak(app_payload_idx), + /* K18 */ be_nested_str_weak(pA), + /* K19 */ be_nested_str_weak(SPAKE2P_Matter), + /* K20 */ be_nested_str_weak(device), + /* K21 */ be_nested_str_weak(commissioning_w0), + /* K22 */ be_nested_str_weak(commissioning_L), + /* K23 */ be_nested_str_weak(random), + /* K24 */ be_nested_str_weak(compute_pB), + /* K25 */ be_nested_str_weak(compute_ZV_verifier), + /* K26 */ be_nested_str_weak(SHA256), + /* K27 */ be_nested_str_weak(update), + /* K28 */ be_nested_str_weak(fromstring), + /* K29 */ be_nested_str_weak(Matter_Context_Prefix), + /* K30 */ be_nested_str_weak(__Msg1), + /* K31 */ be_nested_str_weak(__Msg2), + /* K32 */ be_nested_str_weak(out), + /* K33 */ be_nested_str_weak(set_context), + /* K34 */ be_nested_str_weak(compute_TT_hash), + /* K35 */ be_nested_str_weak(Pake2), + /* K36 */ be_nested_str_weak(pB), + /* K37 */ be_nested_str_weak(cB), + /* K38 */ be_nested_str_weak(tlv2raw), + /* K39 */ be_nested_str_weak(__spake_cA), + /* K40 */ be_nested_str_weak(cA), + /* K41 */ be_nested_str_weak(__spake_Ke), + /* K42 */ be_nested_str_weak(Ke), + /* K43 */ be_nested_str_weak(build_response), + /* K44 */ be_nested_str_weak(encode_frame), + /* K45 */ be_nested_str_weak(responder), + /* K46 */ be_nested_str_weak(send_response_frame), + }), + be_str_weak(parse_Pake1), + &be_const_str_solidified, + ( &(const binstruction[105]) { /* code */ 0xA40A0000, // 0000 IMPORT R2 K0 0x880C0301, // 0001 GETMBR R3 R1 K1 - 0x5412002F, // 0002 LDINT R4 48 - 0x200C0604, // 0003 NE R3 R3 R4 - 0x740E0005, // 0004 JMPT R3 #000B - 0x880C0302, // 0005 GETMBR R3 R1 K2 - 0x200C0703, // 0006 NE R3 R3 K3 - 0x740E0002, // 0007 JMPT R3 #000B - 0x880C0304, // 0008 GETMBR R3 R1 K4 - 0x200C0703, // 0009 NE R3 R3 K3 - 0x780E0000, // 000A JMPF R3 #000C - 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB80E0E00, // 000C GETNGBL R3 K7 - 0x8C0C0708, // 000D GETMET R3 R3 K8 - 0x7C0C0200, // 000E CALL R3 1 - 0x8C0C0709, // 000F GETMET R3 R3 K9 - 0x8814030A, // 0010 GETMBR R5 R1 K10 - 0x8818030B, // 0011 GETMBR R6 R1 K11 - 0x7C0C0600, // 0012 CALL R3 3 - 0x8810070D, // 0013 GETMBR R4 R3 K13 - 0x90021804, // 0014 SETMBR R0 K12 R4 - 0x8810070E, // 0015 GETMBR R4 R3 K14 - 0x4C140000, // 0016 LDNIL R5 - 0x20100805, // 0017 NE R4 R4 R5 - 0x78120003, // 0018 JMPF R4 #001D - 0x8810070F, // 0019 GETMBR R4 R3 K15 - 0x4C140000, // 001A LDNIL R5 - 0x20100805, // 001B NE R4 R4 R5 - 0x74120000, // 001C JMPT R4 #001E - 0x50100001, // 001D LDBOOL R4 0 1 - 0x50100200, // 001E LDBOOL R4 1 0 - 0x4C140000, // 001F LDNIL R5 - 0x78120006, // 0020 JMPF R4 #0028 - 0x88180110, // 0021 GETMBR R6 R0 K16 - 0x88180D11, // 0022 GETMBR R6 R6 K17 - 0x8C180D12, // 0023 GETMET R6 R6 K18 - 0x8820070E, // 0024 GETMBR R8 R3 K14 - 0x7C180400, // 0025 CALL R6 2 - 0x5C140C00, // 0026 MOVE R5 R6 - 0x70020004, // 0027 JMP #002D - 0x8C180113, // 0028 GETMET R6 R0 K19 - 0x88200714, // 0029 GETMBR R8 R3 K20 - 0x88240715, // 002A GETMBR R9 R3 K21 - 0x7C180600, // 002B CALL R6 3 - 0x5C140C00, // 002C MOVE R5 R6 - 0x4C180000, // 002D LDNIL R6 - 0x1C180A06, // 002E EQ R6 R5 R6 - 0x781A0000, // 002F JMPF R6 #0031 - 0xB0062D17, // 0030 RAISE 1 K22 K23 - 0x88180318, // 0031 GETMBR R6 R1 K24 - 0x90163006, // 0032 SETMBR R5 K24 R6 - 0x8C180B19, // 0033 GETMET R6 R5 K25 - 0xB8220E00, // 0034 GETNGBL R8 K7 - 0x8820111A, // 0035 GETMBR R8 R8 K26 - 0x8820111B, // 0036 GETMBR R8 R8 K27 - 0x7C180400, // 0037 CALL R6 2 - 0x8818031C, // 0038 GETMBR R6 R1 K28 - 0x781A0004, // 0039 JMPF R6 #003F - 0x88180110, // 003A GETMBR R6 R0 K16 - 0x88180D11, // 003B GETMBR R6 R6 K17 - 0x8C180D1D, // 003C GETMET R6 R6 K29 - 0x8820031C, // 003D GETMBR R8 R1 K28 - 0x7C180400, // 003E CALL R6 2 - 0x90063805, // 003F SETMBR R1 K28 R5 - 0x8818071F, // 0040 GETMBR R6 R3 K31 - 0x90163C06, // 0041 SETMBR R5 K30 R6 - 0x88180110, // 0042 GETMBR R6 R0 K16 - 0x88180D11, // 0043 GETMBR R6 R6 K17 - 0x8C180D21, // 0044 GETMET R6 R6 K33 - 0x7C180200, // 0045 CALL R6 1 - 0x90164006, // 0046 SETMBR R5 K32 R6 - 0x88180B20, // 0047 GETMBR R6 R5 K32 - 0x90024406, // 0048 SETMBR R0 K34 R6 - 0x781200EE, // 0049 JMPF R4 #0139 - 0x88180B23, // 004A GETMBR R6 R5 K35 - 0x4C1C0000, // 004B LDNIL R7 - 0x20180C07, // 004C NE R6 R6 R7 - 0x781A00EA, // 004D JMPF R6 #0139 - 0x88180715, // 004E GETMBR R6 R3 K21 - 0x881C070E, // 004F GETMBR R7 R3 K14 - 0x00180C07, // 0050 ADD R6 R6 R7 - 0x601C0015, // 0051 GETGBL R7 G21 - 0x7C1C0000, // 0052 CALL R7 0 - 0x8C1C0F24, // 0053 GETMET R7 R7 K36 - 0x58240025, // 0054 LDCONST R9 K37 - 0x7C1C0400, // 0055 CALL R7 2 - 0x8C200526, // 0056 GETMET R8 R2 K38 - 0x7C200200, // 0057 CALL R8 1 - 0x8C201127, // 0058 GETMET R8 R8 K39 - 0x88280B23, // 0059 GETMBR R10 R5 K35 - 0x5C2C0C00, // 005A MOVE R11 R6 - 0x5C300E00, // 005B MOVE R12 R7 - 0x5436000F, // 005C LDINT R13 16 - 0x7C200A00, // 005D CALL R8 5 - 0x60240015, // 005E GETGBL R9 G21 - 0x7C240000, // 005F CALL R9 0 - 0x8C241324, // 0060 GETMET R9 R9 K36 - 0x582C0028, // 0061 LDCONST R11 K40 - 0x7C240400, // 0062 CALL R9 2 - 0x5429FFEE, // 0063 LDINT R10 -17 - 0x402A060A, // 0064 CONNECT R10 K3 R10 - 0x882C070F, // 0065 GETMBR R11 R3 K15 - 0x9428160A, // 0066 GETIDX R10 R11 R10 - 0x5431FFEF, // 0067 LDINT R12 -16 - 0x40301929, // 0068 CONNECT R12 R12 K41 - 0x8834070F, // 0069 GETMBR R13 R3 K15 - 0x942C1A0C, // 006A GETIDX R11 R13 R12 - 0x8C38052A, // 006B GETMET R14 R2 K42 - 0x5C401000, // 006C MOVE R16 R8 - 0x5C441200, // 006D MOVE R17 R9 - 0x60480015, // 006E GETGBL R18 G21 - 0x7C480000, // 006F CALL R18 0 - 0x604C000C, // 0070 GETGBL R19 G12 - 0x5C501400, // 0071 MOVE R20 R10 - 0x7C4C0200, // 0072 CALL R19 1 - 0x5452000F, // 0073 LDINT R20 16 - 0x7C380C00, // 0074 CALL R14 6 - 0x5C301C00, // 0075 MOVE R12 R14 - 0x8C38192B, // 0076 GETMET R14 R12 K43 - 0x5C401400, // 0077 MOVE R16 R10 - 0x7C380400, // 0078 CALL R14 2 - 0x5C341C00, // 0079 MOVE R13 R14 - 0x8C38192C, // 007A GETMET R14 R12 K44 - 0x7C380200, // 007B CALL R14 1 - 0xB83E5A00, // 007C GETNGBL R15 K45 - 0x8C3C1F2E, // 007D GETMET R15 R15 K46 - 0x5844002F, // 007E LDCONST R17 K47 - 0x58480030, // 007F LDCONST R18 K48 - 0x7C3C0600, // 0080 CALL R15 3 - 0xB83E5A00, // 0081 GETNGBL R15 K45 - 0x8C3C1F2E, // 0082 GETMET R15 R15 K46 - 0x8C441132, // 0083 GETMET R17 R8 K50 - 0x7C440200, // 0084 CALL R17 1 - 0x00466211, // 0085 ADD R17 K49 R17 - 0x58480030, // 0086 LDCONST R18 K48 - 0x7C3C0600, // 0087 CALL R15 3 - 0xB83E5A00, // 0088 GETNGBL R15 K45 - 0x8C3C1F2E, // 0089 GETMET R15 R15 K46 - 0x8C441732, // 008A GETMET R17 R11 K50 - 0x7C440200, // 008B CALL R17 1 - 0x00466611, // 008C ADD R17 K51 R17 - 0x58480030, // 008D LDCONST R18 K48 - 0x7C3C0600, // 008E CALL R15 3 - 0xB83E5A00, // 008F GETNGBL R15 K45 - 0x8C3C1F2E, // 0090 GETMET R15 R15 K46 - 0x8C441B32, // 0091 GETMET R17 R13 K50 - 0x7C440200, // 0092 CALL R17 1 - 0x00466811, // 0093 ADD R17 K52 R17 - 0x58480030, // 0094 LDCONST R18 K48 - 0x7C3C0600, // 0095 CALL R15 3 - 0xB83E5A00, // 0096 GETNGBL R15 K45 - 0x8C3C1F2E, // 0097 GETMET R15 R15 K46 - 0x8C441D32, // 0098 GETMET R17 R14 K50 - 0x7C440200, // 0099 CALL R17 1 - 0x00466A11, // 009A ADD R17 K53 R17 - 0x58480030, // 009B LDCONST R18 K48 - 0x7C3C0600, // 009C CALL R15 3 - 0xB83E5A00, // 009D GETNGBL R15 K45 - 0x8C3C1F2E, // 009E GETMET R15 R15 K46 - 0x5844002F, // 009F LDCONST R17 K47 - 0x58480030, // 00A0 LDCONST R18 K48 - 0x7C3C0600, // 00A1 CALL R15 3 - 0x1C3C160E, // 00A2 EQ R15 R11 R14 - 0x783E0092, // 00A3 JMPF R15 #0137 - 0x8C3C0537, // 00A4 GETMET R15 R2 K55 - 0x5446000F, // 00A5 LDINT R17 16 - 0x7C3C0400, // 00A6 CALL R15 2 - 0x90166C0F, // 00A7 SETMBR R5 K54 R15 - 0x603C0015, // 00A8 GETGBL R15 G21 - 0x7C3C0000, // 00A9 CALL R15 0 - 0x8C3C1F24, // 00AA GETMET R15 R15 K36 - 0x58440038, // 00AB LDCONST R17 K56 - 0x7C3C0400, // 00AC CALL R15 2 - 0x88400B36, // 00AD GETMBR R16 R5 K54 - 0x003C1E10, // 00AE ADD R15 R15 R16 - 0x88400715, // 00AF GETMBR R16 R3 K21 - 0x8844070E, // 00B0 GETMBR R17 R3 K14 - 0x00402011, // 00B1 ADD R16 R16 R17 - 0x8C440526, // 00B2 GETMET R17 R2 K38 - 0x7C440200, // 00B3 CALL R17 1 - 0x8C442327, // 00B4 GETMET R17 R17 K39 - 0x884C0B23, // 00B5 GETMBR R19 R5 K35 - 0x5C502000, // 00B6 MOVE R20 R16 - 0x5C541E00, // 00B7 MOVE R21 R15 - 0x545A000F, // 00B8 LDINT R22 16 - 0x7C440A00, // 00B9 CALL R17 5 - 0x8C48052A, // 00BA GETMET R18 R2 K42 - 0x5C502200, // 00BB MOVE R20 R17 - 0x60540015, // 00BC GETGBL R21 G21 - 0x7C540000, // 00BD CALL R21 0 - 0x8C542B24, // 00BE GETMET R21 R21 K36 - 0x585C0039, // 00BF LDCONST R23 K57 - 0x7C540400, // 00C0 CALL R21 2 - 0x60580015, // 00C1 GETGBL R22 G21 - 0x7C580000, // 00C2 CALL R22 0 - 0x585C0003, // 00C3 LDCONST R23 K3 - 0x5462000F, // 00C4 LDINT R24 16 - 0x7C480C00, // 00C5 CALL R18 6 - 0x8C4C252C, // 00C6 GETMET R19 R18 K44 - 0x7C4C0200, // 00C7 CALL R19 1 - 0xB8520E00, // 00C8 GETNGBL R20 K7 - 0x8C50293A, // 00C9 GETMET R20 R20 K58 - 0x7C500200, // 00CA CALL R20 1 - 0x88540B36, // 00CB GETMBR R21 R5 K54 - 0x90521C15, // 00CC SETMBR R20 K14 R21 - 0x88540B20, // 00CD GETMBR R21 R5 K32 - 0x90527615, // 00CE SETMBR R20 K59 R21 - 0x90527813, // 00CF SETMBR R20 K60 R19 - 0x8C540526, // 00D0 GETMET R21 R2 K38 - 0x7C540200, // 00D1 CALL R21 1 - 0x8C542B27, // 00D2 GETMET R21 R21 K39 - 0x885C0B23, // 00D3 GETMBR R23 R5 K35 - 0x88600715, // 00D4 GETMBR R24 R3 K21 - 0x8864070E, // 00D5 GETMBR R25 R3 K14 - 0x00603019, // 00D6 ADD R24 R24 R25 - 0x60640015, // 00D7 GETGBL R25 G21 - 0x7C640000, // 00D8 CALL R25 0 - 0x8C643324, // 00D9 GETMET R25 R25 K36 - 0x586C003D, // 00DA LDCONST R27 K61 - 0x7C640400, // 00DB CALL R25 2 - 0x546A002F, // 00DC LDINT R26 48 - 0x7C540A00, // 00DD CALL R21 5 - 0x545A000E, // 00DE LDINT R22 15 - 0x405A0616, // 00DF CONNECT R22 K3 R22 - 0x94582A16, // 00E0 GETIDX R22 R21 R22 - 0x545E000F, // 00E1 LDINT R23 16 - 0x5462001E, // 00E2 LDINT R24 31 - 0x405C2E18, // 00E3 CONNECT R23 R23 R24 - 0x945C2A17, // 00E4 GETIDX R23 R21 R23 - 0x5462001F, // 00E5 LDINT R24 32 - 0x5466002E, // 00E6 LDINT R25 47 - 0x40603019, // 00E7 CONNECT R24 R24 R25 - 0x94602A18, // 00E8 GETIDX R24 R21 R24 - 0xB8665A00, // 00E9 GETNGBL R25 K45 - 0x8C64333E, // 00EA GETMET R25 R25 K62 - 0x7C640200, // 00EB CALL R25 1 - 0x9464333F, // 00EC GETIDX R25 R25 K63 - 0xB86A5A00, // 00ED GETNGBL R26 K45 - 0x8C68352E, // 00EE GETMET R26 R26 K46 - 0x58700040, // 00EF LDCONST R28 K64 - 0x58740030, // 00F0 LDCONST R29 K48 - 0x7C680600, // 00F1 CALL R26 3 - 0xB86A5A00, // 00F2 GETNGBL R26 K45 - 0x8C68352E, // 00F3 GETMET R26 R26 K46 - 0x8C702D32, // 00F4 GETMET R28 R22 K50 - 0x7C700200, // 00F5 CALL R28 1 - 0x0072821C, // 00F6 ADD R28 K65 R28 - 0x58740030, // 00F7 LDCONST R29 K48 - 0x7C680600, // 00F8 CALL R26 3 - 0xB86A5A00, // 00F9 GETNGBL R26 K45 - 0x8C68352E, // 00FA GETMET R26 R26 K46 - 0x8C702F32, // 00FB GETMET R28 R23 K50 - 0x7C700200, // 00FC CALL R28 1 - 0x0072841C, // 00FD ADD R28 K66 R28 - 0x58740030, // 00FE LDCONST R29 K48 - 0x7C680600, // 00FF CALL R26 3 - 0xB86A5A00, // 0100 GETNGBL R26 K45 - 0x8C68352E, // 0101 GETMET R26 R26 K46 - 0x8C703132, // 0102 GETMET R28 R24 K50 - 0x7C700200, // 0103 CALL R28 1 - 0x0072861C, // 0104 ADD R28 K67 R28 - 0x58740030, // 0105 LDCONST R29 K48 - 0x7C680600, // 0106 CALL R26 3 - 0xB86A5A00, // 0107 GETNGBL R26 K45 - 0x8C68352E, // 0108 GETMET R26 R26 K46 - 0x58700040, // 0109 LDCONST R28 K64 - 0x58740030, // 010A LDCONST R29 K48 - 0x7C680600, // 010B CALL R26 3 - 0x8C682944, // 010C GETMET R26 R20 K68 - 0x7C680200, // 010D CALL R26 1 - 0x4C6C0000, // 010E LDNIL R27 - 0x90168A1B, // 010F SETMBR R5 K69 R27 - 0xB86E5A00, // 0110 GETNGBL R27 K45 - 0x8C6C372E, // 0111 GETMET R27 R27 K46 - 0x8C743532, // 0112 GETMET R29 R26 K50 - 0x7C740200, // 0113 CALL R29 1 - 0x00768C1D, // 0114 ADD R29 K70 R29 - 0x58780030, // 0115 LDCONST R30 K48 - 0x7C6C0600, // 0116 CALL R27 3 - 0x8C6C0347, // 0117 GETMET R27 R1 K71 - 0x54760032, // 0118 LDINT R29 51 - 0x50780200, // 0119 LDBOOL R30 1 0 - 0x7C6C0600, // 011A CALL R27 3 - 0x8C703744, // 011B GETMET R28 R27 K68 - 0x5C783400, // 011C MOVE R30 R26 - 0x7C700400, // 011D CALL R28 2 - 0x88740148, // 011E GETMBR R29 R0 K72 - 0x8C743B49, // 011F GETMET R29 R29 K73 - 0x5C7C3800, // 0120 MOVE R31 R28 - 0x8880034A, // 0121 GETMBR R32 R1 K74 - 0x8884034B, // 0122 GETMBR R33 R1 K75 - 0x8888374C, // 0123 GETMBR R34 R27 K76 - 0x7C740A00, // 0124 CALL R29 5 - 0x8C740B4D, // 0125 GETMET R29 R5 K77 - 0x7C740200, // 0126 CALL R29 1 - 0x8C740B4E, // 0127 GETMET R29 R5 K78 - 0x5C7C2C00, // 0128 MOVE R31 R22 - 0x5C802E00, // 0129 MOVE R32 R23 - 0x5C843000, // 012A MOVE R33 R24 - 0x5C883200, // 012B MOVE R34 R25 - 0x7C740A00, // 012C CALL R29 5 - 0x8C740B4F, // 012D GETMET R29 R5 K79 - 0x507C0200, // 012E LDBOOL R31 1 0 - 0x7C740400, // 012F CALL R29 2 - 0x8C740B50, // 0130 GETMET R29 R5 K80 - 0x7C740200, // 0131 CALL R29 1 - 0x8C740B51, // 0132 GETMET R29 R5 K81 - 0x7C740200, // 0133 CALL R29 1 - 0x50740200, // 0134 LDBOOL R29 1 0 - 0x80043A00, // 0135 RET 1 R29 - 0x70020001, // 0136 JMP #0139 - 0x4C3C0000, // 0137 LDNIL R15 - 0x900E1C0F, // 0138 SETMBR R3 K14 R15 - 0x8818070E, // 0139 GETMBR R6 R3 K14 - 0x4C1C0000, // 013A LDNIL R7 - 0x1C180C07, // 013B EQ R6 R6 R7 - 0x741A0003, // 013C JMPT R6 #0141 - 0x8818070F, // 013D GETMBR R6 R3 K15 - 0x4C1C0000, // 013E LDNIL R7 - 0x1C180C07, // 013F EQ R6 R6 R7 - 0x781A00F0, // 0140 JMPF R6 #0232 - 0x8C180537, // 0141 GETMET R6 R2 K55 - 0x5422000F, // 0142 LDINT R8 16 - 0x7C180400, // 0143 CALL R6 2 - 0x90166C06, // 0144 SETMBR R5 K54 R6 - 0x8C180537, // 0145 GETMET R6 R2 K55 - 0x5422001F, // 0146 LDINT R8 32 - 0x7C180400, // 0147 CALL R6 2 - 0x9002A406, // 0148 SETMBR R0 K82 R6 - 0x8C180554, // 0149 GETMET R6 R2 K84 - 0x7C180200, // 014A CALL R6 1 - 0x8C180D55, // 014B GETMET R6 R6 K85 - 0x88200152, // 014C GETMBR R8 R0 K82 - 0x7C180400, // 014D CALL R6 2 - 0x9002A606, // 014E SETMBR R0 K83 R6 - 0x8C180537, // 014F GETMET R6 R2 K55 - 0x5422001F, // 0150 LDINT R8 32 - 0x7C180400, // 0151 CALL R6 2 - 0x8C1C0554, // 0152 GETMET R7 R2 K84 - 0x7C1C0200, // 0153 CALL R7 1 - 0x8C1C0F56, // 0154 GETMET R7 R7 K86 - 0x88240152, // 0155 GETMBR R9 R0 K82 - 0x8828070D, // 0156 GETMBR R10 R3 K13 - 0x7C1C0600, // 0157 CALL R7 3 - 0x90164607, // 0158 SETMBR R5 K35 R7 - 0xB81E0E00, // 0159 GETNGBL R7 K7 - 0x881C0F57, // 015A GETMBR R7 R7 K87 - 0x8C1C0F58, // 015B GETMET R7 R7 K88 - 0x7C1C0200, // 015C CALL R7 1 - 0x8C200F59, // 015D GETMET R8 R7 K89 - 0x5828005A, // 015E LDCONST R10 K90 - 0xB82E0E00, // 015F GETNGBL R11 K7 - 0x882C1757, // 0160 GETMBR R11 R11 K87 - 0x882C175B, // 0161 GETMBR R11 R11 K91 - 0x8C300B5C, // 0162 GETMET R12 R5 K92 - 0x7C300200, // 0163 CALL R12 1 - 0x7C200800, // 0164 CALL R8 4 - 0x8C200F59, // 0165 GETMET R8 R7 K89 - 0x5828005D, // 0166 LDCONST R10 K93 - 0xB82E0E00, // 0167 GETNGBL R11 K7 - 0x882C1757, // 0168 GETMBR R11 R11 K87 - 0x882C175B, // 0169 GETMBR R11 R11 K91 - 0x8C300B5E, // 016A GETMET R12 R5 K94 - 0x7C300200, // 016B CALL R12 1 - 0x7C200800, // 016C CALL R8 4 - 0x8C200F59, // 016D GETMET R8 R7 K89 - 0x58280030, // 016E LDCONST R10 K48 - 0xB82E0E00, // 016F GETNGBL R11 K7 - 0x882C1757, // 0170 GETMBR R11 R11 K87 - 0x882C175B, // 0171 GETMBR R11 R11 K91 - 0x88300153, // 0172 GETMBR R12 R0 K83 - 0x7C200800, // 0173 CALL R8 4 - 0x8C200F59, // 0174 GETMET R8 R7 K89 - 0x542A0003, // 0175 LDINT R10 4 - 0xB82E0E00, // 0176 GETNGBL R11 K7 - 0x882C1757, // 0177 GETMBR R11 R11 K87 - 0x882C175B, // 0178 GETMBR R11 R11 K91 - 0x8830070D, // 0179 GETMBR R12 R3 K13 - 0x7C200800, // 017A CALL R8 4 - 0x8C200554, // 017B GETMET R8 R2 K84 - 0x7C200200, // 017C CALL R8 1 - 0x8C20115F, // 017D GETMET R8 R8 K95 - 0x8C280B60, // 017E GETMET R10 R5 K96 - 0x7C280200, // 017F CALL R10 1 - 0x8C2C0F44, // 0180 GETMET R11 R7 K68 - 0x7C2C0200, // 0181 CALL R11 1 - 0x7C200600, // 0182 CALL R8 3 - 0xB8260E00, // 0183 GETNGBL R9 K7 - 0x88241357, // 0184 GETMBR R9 R9 K87 - 0x8C241358, // 0185 GETMET R9 R9 K88 - 0x7C240200, // 0186 CALL R9 1 - 0x8C281359, // 0187 GETMET R10 R9 K89 - 0x5830005A, // 0188 LDCONST R12 K90 - 0xB8360E00, // 0189 GETNGBL R13 K7 - 0x88341B57, // 018A GETMBR R13 R13 K87 - 0x88341B5B, // 018B GETMBR R13 R13 K91 - 0x8C380B5C, // 018C GETMET R14 R5 K92 - 0x7C380200, // 018D CALL R14 1 - 0x7C280800, // 018E CALL R10 4 - 0x8C281359, // 018F GETMET R10 R9 K89 - 0x5830005D, // 0190 LDCONST R12 K93 - 0xB8360E00, // 0191 GETNGBL R13 K7 - 0x88341B57, // 0192 GETMBR R13 R13 K87 - 0x88341B5B, // 0193 GETMBR R13 R13 K91 - 0x8C380B5E, // 0194 GETMET R14 R5 K94 - 0x7C380200, // 0195 CALL R14 1 - 0x7C280800, // 0196 CALL R10 4 - 0x8C281359, // 0197 GETMET R10 R9 K89 - 0x58300030, // 0198 LDCONST R12 K48 - 0xB8360E00, // 0199 GETNGBL R13 K7 - 0x88341B57, // 019A GETMBR R13 R13 K87 - 0x88341B5B, // 019B GETMBR R13 R13 K91 - 0x5C381000, // 019C MOVE R14 R8 - 0x7C280800, // 019D CALL R10 4 - 0x8C281359, // 019E GETMET R10 R9 K89 - 0x54320003, // 019F LDINT R12 4 - 0xB8360E00, // 01A0 GETNGBL R13 K7 - 0x88341B57, // 01A1 GETMBR R13 R13 K87 - 0x88341B5B, // 01A2 GETMBR R13 R13 K91 - 0x88380B36, // 01A3 GETMBR R14 R5 K54 - 0x7C280800, // 01A4 CALL R10 4 - 0xB82A5A00, // 01A5 GETNGBL R10 K45 - 0x8C28152E, // 01A6 GETMET R10 R10 K46 - 0x5830002F, // 01A7 LDCONST R12 K47 - 0x58340030, // 01A8 LDCONST R13 K48 - 0x7C280600, // 01A9 CALL R10 3 - 0x88280761, // 01AA GETMBR R10 R3 K97 - 0x90168A0A, // 01AB SETMBR R5 K69 R10 - 0xB82A5A00, // 01AC GETNGBL R10 K45 - 0x8C28152E, // 01AD GETMET R10 R10 K46 - 0x88300B45, // 01AE GETMBR R12 R5 K69 - 0x8C301932, // 01AF GETMET R12 R12 K50 - 0x7C300200, // 01B0 CALL R12 1 - 0x0032C40C, // 01B1 ADD R12 K98 R12 - 0x58340030, // 01B2 LDCONST R13 K48 - 0x7C280600, // 01B3 CALL R10 3 - 0x8C280563, // 01B4 GETMET R10 R2 K99 - 0x7C280200, // 01B5 CALL R10 1 - 0x8C281564, // 01B6 GETMET R10 R10 K100 - 0x88300B45, // 01B7 GETMBR R12 R5 K69 - 0x7C280400, // 01B8 CALL R10 2 - 0x8C281565, // 01B9 GETMET R10 R10 K101 - 0x7C280200, // 01BA CALL R10 1 - 0x602C0015, // 01BB GETGBL R11 G21 - 0x7C2C0000, // 01BC CALL R11 0 - 0x8C2C1724, // 01BD GETMET R11 R11 K36 - 0x88340166, // 01BE GETMBR R13 R0 K102 - 0x7C2C0400, // 01BF CALL R11 2 - 0x8C300B67, // 01C0 GETMET R12 R5 K103 - 0x7C300200, // 01C1 CALL R12 1 - 0x00301806, // 01C2 ADD R12 R12 R6 - 0x88340153, // 01C3 GETMBR R13 R0 K83 - 0x0030180D, // 01C4 ADD R12 R12 R13 - 0x0030180A, // 01C5 ADD R12 R12 R10 - 0x8C340526, // 01C6 GETMET R13 R2 K38 - 0x7C340200, // 01C7 CALL R13 1 - 0x8C341B27, // 01C8 GETMET R13 R13 K39 - 0x883C0B23, // 01C9 GETMBR R15 R5 K35 - 0x5C401800, // 01CA MOVE R16 R12 - 0x5C441600, // 01CB MOVE R17 R11 - 0x544A000F, // 01CC LDINT R18 16 - 0x7C340A00, // 01CD CALL R13 5 - 0xB83A5A00, // 01CE GETNGBL R14 K45 - 0x8C381D2E, // 01CF GETMET R14 R14 K46 - 0x88400B23, // 01D0 GETMBR R16 R5 K35 - 0x8C402132, // 01D1 GETMET R16 R16 K50 - 0x7C400200, // 01D2 CALL R16 1 - 0x0042D010, // 01D3 ADD R16 K104 R16 - 0x58440030, // 01D4 LDCONST R17 K48 - 0x7C380600, // 01D5 CALL R14 3 - 0xB83A5A00, // 01D6 GETNGBL R14 K45 - 0x8C381D2E, // 01D7 GETMET R14 R14 K46 - 0x8C401932, // 01D8 GETMET R16 R12 K50 - 0x7C400200, // 01D9 CALL R16 1 - 0x0042D210, // 01DA ADD R16 K105 R16 - 0x58440030, // 01DB LDCONST R17 K48 - 0x7C380600, // 01DC CALL R14 3 - 0xB83A5A00, // 01DD GETNGBL R14 K45 - 0x8C381D2E, // 01DE GETMET R14 R14 K46 - 0x8C401B32, // 01DF GETMET R16 R13 K50 - 0x7C400200, // 01E0 CALL R16 1 - 0x0042D410, // 01E1 ADD R16 K106 R16 - 0x58440030, // 01E2 LDCONST R17 K48 - 0x7C380600, // 01E3 CALL R14 3 - 0x8C381344, // 01E4 GETMET R14 R9 K68 - 0x7C380200, // 01E5 CALL R14 1 - 0x8C3C052A, // 01E6 GETMET R15 R2 K42 - 0x5C441A00, // 01E7 MOVE R17 R13 - 0x60480015, // 01E8 GETGBL R18 G21 - 0x7C480000, // 01E9 CALL R18 0 - 0x8C482524, // 01EA GETMET R18 R18 K36 - 0x8850016B, // 01EB GETMBR R20 R0 K107 - 0x7C480400, // 01EC CALL R18 2 - 0x604C0015, // 01ED GETGBL R19 G21 - 0x7C4C0000, // 01EE CALL R19 0 - 0x6050000C, // 01EF GETGBL R20 G12 - 0x5C541C00, // 01F0 MOVE R21 R14 - 0x7C500200, // 01F1 CALL R20 1 - 0x5456000F, // 01F2 LDINT R21 16 - 0x7C3C0C00, // 01F3 CALL R15 6 - 0x8C401F6C, // 01F4 GETMET R16 R15 K108 - 0x5C481C00, // 01F5 MOVE R18 R14 - 0x7C400400, // 01F6 CALL R16 2 - 0x8C441F2C, // 01F7 GETMET R17 R15 K44 - 0x7C440200, // 01F8 CALL R17 1 - 0x00402011, // 01F9 ADD R16 R16 R17 - 0xB8465A00, // 01FA GETNGBL R17 K45 - 0x8C44232E, // 01FB GETMET R17 R17 K46 - 0x8C4C2132, // 01FC GETMET R19 R16 K50 - 0x7C4C0200, // 01FD CALL R19 1 - 0x004EDA13, // 01FE ADD R19 K109 R19 - 0x58500030, // 01FF LDCONST R20 K48 - 0x7C440600, // 0200 CALL R17 3 - 0xB8465A00, // 0201 GETNGBL R17 K45 - 0x8C44232E, // 0202 GETMET R17 R17 K46 - 0x584C002F, // 0203 LDCONST R19 K47 - 0x58500030, // 0204 LDCONST R20 K48 - 0x7C440600, // 0205 CALL R17 3 - 0xB8460E00, // 0206 GETNGBL R17 K7 - 0x8C44236E, // 0207 GETMET R17 R17 K110 - 0x7C440200, // 0208 CALL R17 1 - 0x9046DE06, // 0209 SETMBR R17 K111 R6 - 0x88480122, // 020A GETMBR R18 R0 K34 - 0x9046E012, // 020B SETMBR R17 K112 R18 - 0x88480153, // 020C GETMBR R18 R0 K83 - 0x9046E212, // 020D SETMBR R17 K113 R18 - 0x9046E410, // 020E SETMBR R17 K114 R16 - 0xB84A5A00, // 020F GETNGBL R18 K45 - 0x8C48252E, // 0210 GETMET R18 R18 K46 - 0xB8520E00, // 0211 GETNGBL R20 K7 - 0x8C502974, // 0212 GETMET R20 R20 K116 - 0x5C582200, // 0213 MOVE R22 R17 - 0x7C500400, // 0214 CALL R20 2 - 0x0052E614, // 0215 ADD R20 K115 R20 - 0x58540030, // 0216 LDCONST R21 K48 - 0x7C480600, // 0217 CALL R18 3 - 0x8C482344, // 0218 GETMET R18 R17 K68 - 0x7C480200, // 0219 CALL R18 1 - 0x9016EA12, // 021A SETMBR R5 K117 R18 - 0xB84E5A00, // 021B GETNGBL R19 K45 - 0x8C4C272E, // 021C GETMET R19 R19 K46 - 0x8C542532, // 021D GETMET R21 R18 K50 - 0x7C540200, // 021E CALL R21 1 - 0x0056EC15, // 021F ADD R21 K118 R21 - 0x58580030, // 0220 LDCONST R22 K48 - 0x7C4C0600, // 0221 CALL R19 3 - 0x8C4C0347, // 0222 GETMET R19 R1 K71 - 0x54560030, // 0223 LDINT R21 49 - 0x50580200, // 0224 LDBOOL R22 1 0 - 0x7C4C0600, // 0225 CALL R19 3 - 0x8C502744, // 0226 GETMET R20 R19 K68 - 0x5C582400, // 0227 MOVE R22 R18 - 0x7C500400, // 0228 CALL R20 2 - 0x88540148, // 0229 GETMBR R21 R0 K72 - 0x8C542B49, // 022A GETMET R21 R21 K73 - 0x5C5C2800, // 022B MOVE R23 R20 - 0x8860034A, // 022C GETMBR R24 R1 K74 - 0x8864034B, // 022D GETMBR R25 R1 K75 - 0x8868274C, // 022E GETMBR R26 R19 K76 - 0x7C540A00, // 022F CALL R21 5 - 0x50540200, // 0230 LDBOOL R21 1 0 - 0x80042A00, // 0231 RET 1 R21 - 0x50180200, // 0232 LDBOOL R6 1 0 - 0x80040C00, // 0233 RET 1 R6 + 0x88100302, // 0002 GETMBR R4 R1 K2 + 0x54160021, // 0003 LDINT R5 34 + 0x20100805, // 0004 NE R4 R4 R5 + 0x74120005, // 0005 JMPT R4 #000C + 0x88100303, // 0006 GETMBR R4 R1 K3 + 0x20100904, // 0007 NE R4 R4 K4 + 0x74120002, // 0008 JMPT R4 #000C + 0x88100305, // 0009 GETMBR R4 R1 K5 + 0x20100904, // 000A NE R4 R4 K4 + 0x78120012, // 000B JMPF R4 #001F + 0xB8120C00, // 000C GETNGBL R4 K6 + 0x8C100907, // 000D GETMET R4 R4 K7 + 0x58180008, // 000E LDCONST R6 K8 + 0x581C0009, // 000F LDCONST R7 K9 + 0x7C100600, // 0010 CALL R4 3 + 0xB8120C00, // 0011 GETNGBL R4 K6 + 0x8C100907, // 0012 GETMET R4 R4 K7 + 0x5818000A, // 0013 LDCONST R6 K10 + 0x581C0009, // 0014 LDCONST R7 K9 + 0x7C100600, // 0015 CALL R4 3 + 0x8C10010B, // 0016 GETMET R4 R0 K11 + 0x5C180200, // 0017 MOVE R6 R1 + 0x581C000C, // 0018 LDCONST R7 K12 + 0x58200004, // 0019 LDCONST R8 K4 + 0x58240009, // 001A LDCONST R9 K9 + 0x50280000, // 001B LDBOOL R10 0 0 + 0x7C100C00, // 001C CALL R4 6 + 0x50140000, // 001D LDBOOL R5 0 0 + 0x80040A00, // 001E RET 1 R5 + 0xB8121A00, // 001F GETNGBL R4 K13 + 0x8C10090E, // 0020 GETMET R4 R4 K14 + 0x7C100200, // 0021 CALL R4 1 + 0x8C10090F, // 0022 GETMET R4 R4 K15 + 0x88180310, // 0023 GETMBR R6 R1 K16 + 0x881C0311, // 0024 GETMBR R7 R1 K17 + 0x7C100600, // 0025 CALL R4 3 + 0x88140912, // 0026 GETMBR R5 R4 K18 + 0x8C180513, // 0027 GETMET R6 R2 K19 + 0x88200114, // 0028 GETMBR R8 R0 K20 + 0x88201115, // 0029 GETMBR R8 R8 K21 + 0x4C240000, // 002A LDNIL R9 + 0x88280114, // 002B GETMBR R10 R0 K20 + 0x88281516, // 002C GETMBR R10 R10 K22 + 0x7C180800, // 002D CALL R6 4 + 0x8C1C0517, // 002E GETMET R7 R2 K23 + 0x5426001F, // 002F LDINT R9 32 + 0x7C1C0400, // 0030 CALL R7 2 + 0x8C200D18, // 0031 GETMET R8 R6 K24 + 0x5C280E00, // 0032 MOVE R10 R7 + 0x7C200400, // 0033 CALL R8 2 + 0x8C200D19, // 0034 GETMET R8 R6 K25 + 0x5C280A00, // 0035 MOVE R10 R5 + 0x7C200400, // 0036 CALL R8 2 + 0x8C20051A, // 0037 GETMET R8 R2 K26 + 0x7C200200, // 0038 CALL R8 1 + 0x8C24111B, // 0039 GETMET R9 R8 K27 + 0x602C0015, // 003A GETGBL R11 G21 + 0x7C2C0000, // 003B CALL R11 0 + 0x8C2C171C, // 003C GETMET R11 R11 K28 + 0x8834011D, // 003D GETMBR R13 R0 K29 + 0x7C2C0400, // 003E CALL R11 2 + 0x7C240400, // 003F CALL R9 2 + 0x8C24111B, // 0040 GETMET R9 R8 K27 + 0x882C071E, // 0041 GETMBR R11 R3 K30 + 0x7C240400, // 0042 CALL R9 2 + 0x8C24111B, // 0043 GETMET R9 R8 K27 + 0x882C071F, // 0044 GETMBR R11 R3 K31 + 0x7C240400, // 0045 CALL R9 2 + 0x8C241120, // 0046 GETMET R9 R8 K32 + 0x7C240200, // 0047 CALL R9 1 + 0x901A2405, // 0048 SETMBR R6 K18 R5 + 0x8C280D21, // 0049 GETMET R10 R6 K33 + 0x5C301200, // 004A MOVE R12 R9 + 0x7C280400, // 004B CALL R10 2 + 0x8C280D22, // 004C GETMET R10 R6 K34 + 0x50300200, // 004D LDBOOL R12 1 0 + 0x7C280400, // 004E CALL R10 2 + 0xB82A1A00, // 004F GETNGBL R10 K13 + 0x8C281523, // 0050 GETMET R10 R10 K35 + 0x7C280200, // 0051 CALL R10 1 + 0x882C0D24, // 0052 GETMBR R11 R6 K36 + 0x902A480B, // 0053 SETMBR R10 K36 R11 + 0x882C0D25, // 0054 GETMBR R11 R6 K37 + 0x902A4A0B, // 0055 SETMBR R10 K37 R11 + 0x8C2C1526, // 0056 GETMET R11 R10 K38 + 0x7C2C0200, // 0057 CALL R11 1 + 0x88300D28, // 0058 GETMBR R12 R6 K40 + 0x900E4E0C, // 0059 SETMBR R3 K39 R12 + 0x88300D2A, // 005A GETMBR R12 R6 K42 + 0x900E520C, // 005B SETMBR R3 K41 R12 + 0x8C30032B, // 005C GETMET R12 R1 K43 + 0x543A0022, // 005D LDINT R14 35 + 0x503C0200, // 005E LDBOOL R15 1 0 + 0x7C300600, // 005F CALL R12 3 + 0x8C34192C, // 0060 GETMET R13 R12 K44 + 0x5C3C1600, // 0061 MOVE R15 R11 + 0x7C340400, // 0062 CALL R13 2 + 0x8838012D, // 0063 GETMBR R14 R0 K45 + 0x8C381D2E, // 0064 GETMET R14 R14 K46 + 0x5C401800, // 0065 MOVE R16 R12 + 0x7C380400, // 0066 CALL R14 2 + 0x50380200, // 0067 LDBOOL R14 1 0 + 0x80041C00, // 0068 RET 1 R14 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_init, /* name */ + be_nested_proto( + 4, /* 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(crypto), + /* K1 */ be_nested_str_weak(responder), + /* K2 */ be_nested_str_weak(device), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x90020201, // 0001 SETMBR R0 K1 R1 + 0x880C0302, // 0002 GETMBR R3 R1 K2 + 0x90020403, // 0003 SETMBR R0 K2 R3 + 0x80000000, // 0004 RET 0 }) ) ); @@ -2071,7 +738,7 @@ be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ be_nested_proto( - 16, /* nstack */ + 20, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -2079,61 +746,274 @@ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[47]) { /* constants */ + ( &(const bvalue[31]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(opcode), + /* K3 */ be_nested_str_weak(local_session_id), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(protocol_id), + /* K6 */ be_nested_str_weak(tasmota), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20invalid_X20Pake3_X20message), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_str_weak(MTR_X3A_X20StatusReport_X28General_X20Code_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20INVALID_PARAMETER_X29), + /* K11 */ be_nested_str_weak(send_status_report), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_weak(matter), + /* K14 */ be_nested_str_weak(Pake3), + /* K15 */ be_nested_str_weak(parse), + /* K16 */ be_nested_str_weak(raw), + /* K17 */ be_nested_str_weak(app_payload_idx), + /* K18 */ be_nested_str_weak(cA), + /* K19 */ be_nested_str_weak(__spake_cA), + /* K20 */ be_nested_str_weak(MTR_X3A_X20invalid_X20cA_X20received), + /* K21 */ be_nested_str_weak(rtc), + /* K22 */ be_nested_str_weak(utc), + /* K23 */ be_nested_str_weak(HKDF_SHA256), + /* K24 */ be_nested_str_weak(derive), + /* K25 */ be_nested_str_weak(__spake_Ke), + /* K26 */ be_nested_str_weak(fromstring), + /* K27 */ be_nested_str_weak(SEKeys_Info), + /* K28 */ be_nested_str_weak(add_session), + /* K29 */ be_nested_str_weak(__future_local_session_id), + /* K30 */ be_nested_str_weak(__future_initiator_session_id), + }), + be_str_weak(parse_Pake3), + &be_const_str_solidified, + ( &(const binstruction[106]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x88100302, // 0002 GETMBR R4 R1 K2 + 0x54160023, // 0003 LDINT R5 36 + 0x20100805, // 0004 NE R4 R4 R5 + 0x74120005, // 0005 JMPT R4 #000C + 0x88100303, // 0006 GETMBR R4 R1 K3 + 0x20100904, // 0007 NE R4 R4 K4 + 0x74120002, // 0008 JMPT R4 #000C + 0x88100305, // 0009 GETMBR R4 R1 K5 + 0x20100904, // 000A NE R4 R4 K4 + 0x78120012, // 000B JMPF R4 #001F + 0xB8120C00, // 000C GETNGBL R4 K6 + 0x8C100907, // 000D GETMET R4 R4 K7 + 0x58180008, // 000E LDCONST R6 K8 + 0x581C0009, // 000F LDCONST R7 K9 + 0x7C100600, // 0010 CALL R4 3 + 0xB8120C00, // 0011 GETNGBL R4 K6 + 0x8C100907, // 0012 GETMET R4 R4 K7 + 0x5818000A, // 0013 LDCONST R6 K10 + 0x581C0009, // 0014 LDCONST R7 K9 + 0x7C100600, // 0015 CALL R4 3 + 0x8C10010B, // 0016 GETMET R4 R0 K11 + 0x5C180200, // 0017 MOVE R6 R1 + 0x581C000C, // 0018 LDCONST R7 K12 + 0x58200004, // 0019 LDCONST R8 K4 + 0x58240009, // 001A LDCONST R9 K9 + 0x50280000, // 001B LDBOOL R10 0 0 + 0x7C100C00, // 001C CALL R4 6 + 0x50140000, // 001D LDBOOL R5 0 0 + 0x80040A00, // 001E RET 1 R5 + 0xB8121A00, // 001F GETNGBL R4 K13 + 0x8C10090E, // 0020 GETMET R4 R4 K14 + 0x7C100200, // 0021 CALL R4 1 + 0x8C10090F, // 0022 GETMET R4 R4 K15 + 0x88180310, // 0023 GETMBR R6 R1 K16 + 0x881C0311, // 0024 GETMBR R7 R1 K17 + 0x7C100600, // 0025 CALL R4 3 + 0x88140912, // 0026 GETMBR R5 R4 K18 + 0x88180713, // 0027 GETMBR R6 R3 K19 + 0x20180A06, // 0028 NE R6 R5 R6 + 0x781A0012, // 0029 JMPF R6 #003D + 0xB81A0C00, // 002A GETNGBL R6 K6 + 0x8C180D07, // 002B GETMET R6 R6 K7 + 0x58200014, // 002C LDCONST R8 K20 + 0x58240009, // 002D LDCONST R9 K9 + 0x7C180600, // 002E CALL R6 3 + 0xB81A0C00, // 002F GETNGBL R6 K6 + 0x8C180D07, // 0030 GETMET R6 R6 K7 + 0x5820000A, // 0031 LDCONST R8 K10 + 0x58240009, // 0032 LDCONST R9 K9 + 0x7C180600, // 0033 CALL R6 3 + 0x8C18010B, // 0034 GETMET R6 R0 K11 + 0x5C200200, // 0035 MOVE R8 R1 + 0x5824000C, // 0036 LDCONST R9 K12 + 0x58280004, // 0037 LDCONST R10 K4 + 0x582C0009, // 0038 LDCONST R11 K9 + 0x50300000, // 0039 LDBOOL R12 0 0 + 0x7C180C00, // 003A CALL R6 6 + 0x501C0000, // 003B LDBOOL R7 0 0 + 0x80040E00, // 003C RET 1 R7 + 0xB81A0C00, // 003D GETNGBL R6 K6 + 0x8C180D15, // 003E GETMET R6 R6 K21 + 0x7C180200, // 003F CALL R6 1 + 0x94180D16, // 0040 GETIDX R6 R6 K22 + 0x8C1C0517, // 0041 GETMET R7 R2 K23 + 0x7C1C0200, // 0042 CALL R7 1 + 0x8C1C0F18, // 0043 GETMET R7 R7 K24 + 0x88240719, // 0044 GETMBR R9 R3 K25 + 0x60280015, // 0045 GETGBL R10 G21 + 0x7C280000, // 0046 CALL R10 0 + 0x602C0015, // 0047 GETGBL R11 G21 + 0x7C2C0000, // 0048 CALL R11 0 + 0x8C2C171A, // 0049 GETMET R11 R11 K26 + 0x8834011B, // 004A GETMBR R13 R0 K27 + 0x7C2C0400, // 004B CALL R11 2 + 0x5432002F, // 004C LDINT R12 48 + 0x7C1C0A00, // 004D CALL R7 5 + 0x5422000E, // 004E LDINT R8 15 + 0x40220808, // 004F CONNECT R8 K4 R8 + 0x94200E08, // 0050 GETIDX R8 R7 R8 + 0x5426000F, // 0051 LDINT R9 16 + 0x542A001E, // 0052 LDINT R10 31 + 0x4024120A, // 0053 CONNECT R9 R9 R10 + 0x94240E09, // 0054 GETIDX R9 R7 R9 + 0x542A001F, // 0055 LDINT R10 32 + 0x542E002E, // 0056 LDINT R11 47 + 0x4028140B, // 0057 CONNECT R10 R10 R11 + 0x94280E0A, // 0058 GETIDX R10 R7 R10 + 0x8C2C010B, // 0059 GETMET R11 R0 K11 + 0x5C340200, // 005A MOVE R13 R1 + 0x58380004, // 005B LDCONST R14 K4 + 0x583C0004, // 005C LDCONST R15 K4 + 0x58400004, // 005D LDCONST R16 K4 + 0x50440000, // 005E LDBOOL R17 0 0 + 0x7C2C0C00, // 005F CALL R11 6 + 0x8C30011C, // 0060 GETMET R12 R0 K28 + 0x8838071D, // 0061 GETMBR R14 R3 K29 + 0x883C071E, // 0062 GETMBR R15 R3 K30 + 0x5C401000, // 0063 MOVE R16 R8 + 0x5C441200, // 0064 MOVE R17 R9 + 0x5C481400, // 0065 MOVE R18 R10 + 0x5C4C0C00, // 0066 MOVE R19 R6 + 0x7C300E00, // 0067 CALL R12 7 + 0x50300200, // 0068 LDBOOL R12 1 0 + 0x80041800, // 0069 RET 1 R12 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Sigma3 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Sigma3, /* name */ + be_nested_proto( + 36, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[99]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(opcode), /* K2 */ be_nested_str_weak(local_session_id), /* K3 */ be_const_int(0), /* K4 */ be_nested_str_weak(protocol_id), - /* K5 */ be_nested_str_weak(protocol_error), - /* K6 */ be_nested_str_weak(invalid_X20Pake3_X20message), - /* K7 */ be_nested_str_weak(matter), - /* K8 */ be_nested_str_weak(Pake3), - /* K9 */ be_nested_str_weak(parse), - /* K10 */ be_nested_str_weak(raw), - /* K11 */ be_nested_str_weak(app_payload_idx), - /* K12 */ be_nested_str_weak(cA), - /* K13 */ be_nested_str_weak(tasmota), - /* K14 */ be_nested_str_weak(log), - /* K15 */ be_nested_str_weak(MTR_X3A_X20received_X20cA_X3D), - /* K16 */ be_nested_str_weak(tohex), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(spake), - /* K19 */ be_nested_str_weak(invalid_X20cA_X20received), - /* K20 */ be_nested_str_weak(session_timestamp), - /* K21 */ be_nested_str_weak(rtc), - /* K22 */ be_nested_str_weak(utc), - /* K23 */ be_nested_str_weak(HKDF_SHA256), - /* K24 */ be_nested_str_weak(derive), - /* K25 */ be_nested_str_weak(Ke), - /* K26 */ be_nested_str_weak(fromstring), - /* K27 */ be_nested_str_weak(SEKeys_Info), - /* K28 */ be_nested_str_weak(I2RKey), - /* K29 */ be_nested_str_weak(R2IKey), - /* K30 */ be_nested_str_weak(AttestationChallenge), - /* K31 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K32 */ be_nested_str_weak(MTR_X3A_X20session_keys_X3D), - /* K33 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), - /* K34 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), - /* K35 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K36 */ be_nested_str_weak(build_response), - /* K37 */ be_nested_str_weak(add), - /* K38 */ be_const_int(2), - /* K39 */ be_nested_str_weak(encode), - /* K40 */ be_nested_str_weak(responder), - /* K41 */ be_nested_str_weak(send_response), - /* K42 */ be_nested_str_weak(remote_ip), - /* K43 */ be_nested_str_weak(remote_port), - /* K44 */ be_nested_str_weak(add_session), - /* K45 */ be_nested_str_weak(future_local_session_id), - /* K46 */ be_nested_str_weak(future_initiator_session_id), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(MTR_X3A_X20StatusReport_X28General_X20Code_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20INVALID_PARAMETER_X29), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(send_status_report), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_str_weak(session), + /* K12 */ be_nested_str_weak(matter), + /* K13 */ be_nested_str_weak(Sigma3), + /* K14 */ be_nested_str_weak(parse), + /* K15 */ be_nested_str_weak(raw), + /* K16 */ be_nested_str_weak(app_payload_idx), + /* K17 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K18 */ be_nested_str_weak(SHA256), + /* K19 */ be_nested_str_weak(update), + /* K20 */ be_nested_str_weak(__Msg1), + /* K21 */ be_nested_str_weak(__Msg2), + /* K22 */ be_nested_str_weak(out), + /* K23 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20session_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K24 */ be_nested_str_weak(MTR_X3A_X20_X20_X20_X2Eipk_epoch_key_X3D), + /* K25 */ be_nested_str_weak(get_ipk_epoch_key), + /* K26 */ be_nested_str_weak(MTR_X3A_X20_X20_X20_X2Efabric_compr_X20_X3D_X20), + /* K27 */ be_nested_str_weak(get_fabric_compressed), + /* K28 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ipk_group_key_X20_X3D_X20), + /* K29 */ be_nested_str_weak(get_ipk_group_key), + /* K30 */ be_nested_str_weak(tohex), + /* K31 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TranscriptHash_X3D_X20), + /* K32 */ be_nested_str_weak(fromstring), + /* K33 */ be_nested_str_weak(S3K_Info), + /* K34 */ be_nested_str_weak(HKDF_SHA256), + /* K35 */ be_nested_str_weak(derive), + /* K36 */ be_nested_str_weak(shared_secret), + /* K37 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s3k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K38 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s3k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K39 */ be_nested_str_weak(TBEData3Encrypted), + /* K40 */ be_const_int(2147483647), + /* K41 */ be_nested_str_weak(AES_CCM), + /* K42 */ be_nested_str_weak(TBEData3_Nonce), + /* K43 */ be_nested_str_weak(decrypt), + /* K44 */ be_nested_str_weak(tag), + /* K45 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData3_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K46 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBETag3_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K47 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_sent_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K48 */ be_nested_str_weak(MTR_X3A_X20Tag_X20don_X27t_X20match), + /* K49 */ be_nested_str_weak(TLV), + /* K50 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData3TLV_X20_X20_X20_X3D_X20), + /* K51 */ be_nested_str_weak(findsubval), + /* K52 */ be_const_int(3), + /* K53 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20initiatorNOC_X20_X20_X3D_X20), + /* K54 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20initiatorICAC_X20_X3D_X20), + /* K55 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ec_signature_X20_X20_X3D_X20), + /* K56 */ be_nested_str_weak(MTR_X3A_X20initiatorNOCTLV_X20_X3D_X20), + /* K57 */ be_nested_str_weak(findsub), + /* K58 */ be_nested_str_weak(int), + /* K59 */ be_nested_str_weak(int64), + /* K60 */ be_nested_str_weak(peer_node_id), + /* K61 */ be_nested_str_weak(tobytes), + /* K62 */ be_nested_str_weak(MTR_X3A_X20initiatorFabricId_X3D), + /* K63 */ be_nested_str_weak(Matter_TLV_struct), + /* K64 */ be_nested_str_weak(add_TLV), + /* K65 */ be_nested_str_weak(B1), + /* K66 */ be_nested_str_weak(__initiator_pub), + /* K67 */ be_nested_str_weak(__responder_pub), + /* K68 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20sigma3_tbs_X20_X20_X20_X20_X3D_X20), + /* K69 */ be_nested_str_weak(tlv2raw), + /* K70 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20sigma3_tbs_raw_X3D_X20), + /* K71 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20initiatorNOCPubKey_X3D_X20), + /* K72 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20ec_signature_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K73 */ be_nested_str_weak(EC_P256), + /* K74 */ be_nested_str_weak(ecdsa_verify_sha256), + /* K75 */ be_nested_str_weak(MTR_X3A_X20sigma3_tbs_X20does_X20not_X20have_X20a_X20valid_X20signature), + /* K76 */ be_nested_str_weak(MTR_X3A_X20Sigma3_X20verified_X2C_X20computing_X20new_X20keys), + /* K77 */ be_nested_str_weak(Msg3), + /* K78 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20__Msg1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K79 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20__Msg2_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K80 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20__Msg3_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K81 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TranscriptHash_X20_X20_X20_X20_X3D_X20), + /* K82 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K83 */ be_nested_str_weak(MTR_X3A_X20shared_secret_X20_X3D), + /* K84 */ be_nested_str_weak(MTR_X3A_X20ipk_X20_X2B_X20hash_X20_X20_X20_X20_X3D), + /* K85 */ be_nested_str_weak(SEKeys_Info), + /* K86 */ be_nested_str_weak(rtc), + /* K87 */ be_nested_str_weak(utc), + /* K88 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), + /* K89 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), + /* K90 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K91 */ be_nested_str_weak(close), + /* K92 */ be_nested_str_weak(set_keys), + /* K93 */ be_nested_str_weak(_breadcrumb), + /* K94 */ be_nested_str_weak(counter_snd_next), + /* K95 */ be_nested_str_weak(set_persist), + /* K96 */ be_nested_str_weak(set_no_expiration), + /* K97 */ be_nested_str_weak(persist_to_fabric), + /* K98 */ be_nested_str_weak(save), }), - be_str_weak(parse_Pake3), + be_str_weak(parse_Sigma3), &be_const_str_solidified, - ( &(const binstruction[146]) { /* code */ + ( &(const binstruction[558]) { /* code */ 0xA40A0000, // 0000 IMPORT R2 K0 0x880C0301, // 0001 GETMBR R3 R1 K1 - 0x54120023, // 0002 LDINT R4 36 + 0x54120031, // 0002 LDINT R4 50 0x200C0604, // 0003 NE R3 R3 R4 0x740E0005, // 0004 JMPT R3 #000B 0x880C0302, // 0005 GETMBR R3 R1 K2 @@ -2141,142 +1021,554 @@ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ 0x740E0002, // 0007 JMPT R3 #000B 0x880C0304, // 0008 GETMBR R3 R1 K4 0x200C0703, // 0009 NE R3 R3 K3 - 0x780E0000, // 000A JMPF R3 #000C - 0xB0060B06, // 000B RAISE 1 K5 K6 - 0xB80E0E00, // 000C GETNGBL R3 K7 - 0x8C0C0708, // 000D GETMET R3 R3 K8 - 0x7C0C0200, // 000E CALL R3 1 - 0x8C0C0709, // 000F GETMET R3 R3 K9 - 0x8814030A, // 0010 GETMBR R5 R1 K10 - 0x8818030B, // 0011 GETMBR R6 R1 K11 - 0x7C0C0600, // 0012 CALL R3 3 - 0x8810070C, // 0013 GETMBR R4 R3 K12 - 0x90021804, // 0014 SETMBR R0 K12 R4 - 0xB8121A00, // 0015 GETNGBL R4 K13 - 0x8C10090E, // 0016 GETMET R4 R4 K14 - 0x8818010C, // 0017 GETMBR R6 R0 K12 - 0x8C180D10, // 0018 GETMET R6 R6 K16 - 0x7C180200, // 0019 CALL R6 1 - 0x001A1E06, // 001A ADD R6 K15 R6 - 0x581C0011, // 001B LDCONST R7 K17 - 0x7C100600, // 001C CALL R4 3 - 0x8810010C, // 001D GETMBR R4 R0 K12 - 0x88140112, // 001E GETMBR R5 R0 K18 - 0x88140B0C, // 001F GETMBR R5 R5 K12 - 0x20100805, // 0020 NE R4 R4 R5 - 0x78120000, // 0021 JMPF R4 #0023 - 0xB0060B13, // 0022 RAISE 1 K5 K19 - 0xB8121A00, // 0023 GETNGBL R4 K13 - 0x8C100915, // 0024 GETMET R4 R4 K21 - 0x7C100200, // 0025 CALL R4 1 - 0x94100916, // 0026 GETIDX R4 R4 K22 - 0x90022804, // 0027 SETMBR R0 K20 R4 - 0x8C100517, // 0028 GETMET R4 R2 K23 - 0x7C100200, // 0029 CALL R4 1 - 0x8C100918, // 002A GETMET R4 R4 K24 - 0x88180119, // 002B GETMBR R6 R0 K25 - 0x601C0015, // 002C GETGBL R7 G21 - 0x7C1C0000, // 002D CALL R7 0 - 0x60200015, // 002E GETGBL R8 G21 - 0x7C200000, // 002F CALL R8 0 - 0x8C20111A, // 0030 GETMET R8 R8 K26 - 0x8828011B, // 0031 GETMBR R10 R0 K27 - 0x7C200400, // 0032 CALL R8 2 - 0x5426002F, // 0033 LDINT R9 48 - 0x7C100A00, // 0034 CALL R4 5 - 0x5416000E, // 0035 LDINT R5 15 - 0x40160605, // 0036 CONNECT R5 K3 R5 - 0x94140805, // 0037 GETIDX R5 R4 R5 - 0x90023805, // 0038 SETMBR R0 K28 R5 - 0x5416000F, // 0039 LDINT R5 16 - 0x541A001E, // 003A LDINT R6 31 - 0x40140A06, // 003B CONNECT R5 R5 R6 - 0x94140805, // 003C GETIDX R5 R4 R5 - 0x90023A05, // 003D SETMBR R0 K29 R5 - 0x5416001F, // 003E LDINT R5 32 - 0x541A002E, // 003F LDINT R6 47 - 0x40140A06, // 0040 CONNECT R5 R5 R6 - 0x94140805, // 0041 GETIDX R5 R4 R5 - 0x90023C05, // 0042 SETMBR R0 K30 R5 - 0xB8161A00, // 0043 GETNGBL R5 K13 - 0x8C140B0E, // 0044 GETMET R5 R5 K14 - 0x581C001F, // 0045 LDCONST R7 K31 - 0x58200011, // 0046 LDCONST R8 K17 - 0x7C140600, // 0047 CALL R5 3 - 0xB8161A00, // 0048 GETNGBL R5 K13 - 0x8C140B0E, // 0049 GETMET R5 R5 K14 - 0x8C1C0910, // 004A GETMET R7 R4 K16 - 0x7C1C0200, // 004B CALL R7 1 - 0x001E4007, // 004C ADD R7 K32 R7 - 0x58200011, // 004D LDCONST R8 K17 - 0x7C140600, // 004E CALL R5 3 - 0xB8161A00, // 004F GETNGBL R5 K13 - 0x8C140B0E, // 0050 GETMET R5 R5 K14 - 0x881C011C, // 0051 GETMBR R7 R0 K28 - 0x8C1C0F10, // 0052 GETMET R7 R7 K16 - 0x7C1C0200, // 0053 CALL R7 1 - 0x001E4207, // 0054 ADD R7 K33 R7 - 0x58200011, // 0055 LDCONST R8 K17 - 0x7C140600, // 0056 CALL R5 3 - 0xB8161A00, // 0057 GETNGBL R5 K13 - 0x8C140B0E, // 0058 GETMET R5 R5 K14 - 0x881C011D, // 0059 GETMBR R7 R0 K29 - 0x8C1C0F10, // 005A GETMET R7 R7 K16 - 0x7C1C0200, // 005B CALL R7 1 - 0x001E4407, // 005C ADD R7 K34 R7 - 0x58200011, // 005D LDCONST R8 K17 - 0x7C140600, // 005E CALL R5 3 - 0xB8161A00, // 005F GETNGBL R5 K13 - 0x8C140B0E, // 0060 GETMET R5 R5 K14 - 0x881C011E, // 0061 GETMBR R7 R0 K30 - 0x8C1C0F10, // 0062 GETMET R7 R7 K16 - 0x7C1C0200, // 0063 CALL R7 1 - 0x001E4607, // 0064 ADD R7 K35 R7 - 0x58200011, // 0065 LDCONST R8 K17 - 0x7C140600, // 0066 CALL R5 3 - 0xB8161A00, // 0067 GETNGBL R5 K13 - 0x8C140B0E, // 0068 GETMET R5 R5 K14 - 0x581C001F, // 0069 LDCONST R7 K31 - 0x58200011, // 006A LDCONST R8 K17 - 0x7C140600, // 006B CALL R5 3 - 0x8C140324, // 006C GETMET R5 R1 K36 - 0x541E003F, // 006D LDINT R7 64 - 0x50200000, // 006E LDBOOL R8 0 0 - 0x7C140600, // 006F CALL R5 3 - 0x60180015, // 0070 GETGBL R6 G21 - 0x7C180000, // 0071 CALL R6 0 - 0x8C1C0D25, // 0072 GETMET R7 R6 K37 - 0x58240003, // 0073 LDCONST R9 K3 - 0x58280026, // 0074 LDCONST R10 K38 - 0x7C1C0600, // 0075 CALL R7 3 - 0x8C1C0D25, // 0076 GETMET R7 R6 K37 - 0x58240003, // 0077 LDCONST R9 K3 - 0x542A0003, // 0078 LDINT R10 4 - 0x7C1C0600, // 0079 CALL R7 3 - 0x8C1C0D25, // 007A GETMET R7 R6 K37 - 0x58240003, // 007B LDCONST R9 K3 - 0x542A0003, // 007C LDINT R10 4 - 0x7C1C0600, // 007D CALL R7 3 - 0x8C1C0B27, // 007E GETMET R7 R5 K39 - 0x5C240C00, // 007F MOVE R9 R6 - 0x7C1C0400, // 0080 CALL R7 2 - 0x88200128, // 0081 GETMBR R8 R0 K40 - 0x8C201129, // 0082 GETMET R8 R8 K41 - 0x5C280E00, // 0083 MOVE R10 R7 - 0x882C032A, // 0084 GETMBR R11 R1 K42 - 0x8830032B, // 0085 GETMBR R12 R1 K43 - 0x4C340000, // 0086 LDNIL R13 - 0x7C200A00, // 0087 CALL R8 5 - 0x88200128, // 0088 GETMBR R8 R0 K40 - 0x8C20112C, // 0089 GETMET R8 R8 K44 - 0x8828012D, // 008A GETMBR R10 R0 K45 - 0x882C012E, // 008B GETMBR R11 R0 K46 - 0x8830011C, // 008C GETMBR R12 R0 K28 - 0x8834011D, // 008D GETMBR R13 R0 K29 - 0x8838011E, // 008E GETMBR R14 R0 K30 - 0x883C0114, // 008F GETMBR R15 R0 K20 - 0x7C200E00, // 0090 CALL R8 7 - 0x80000000, // 0091 RET 0 + 0x780E000D, // 000A JMPF R3 #0019 + 0xB80E0A00, // 000B GETNGBL R3 K5 + 0x8C0C0706, // 000C GETMET R3 R3 K6 + 0x58140007, // 000D LDCONST R5 K7 + 0x58180008, // 000E LDCONST R6 K8 + 0x7C0C0600, // 000F CALL R3 3 + 0x8C0C0109, // 0010 GETMET R3 R0 K9 + 0x5C140200, // 0011 MOVE R5 R1 + 0x5818000A, // 0012 LDCONST R6 K10 + 0x581C0003, // 0013 LDCONST R7 K3 + 0x58200008, // 0014 LDCONST R8 K8 + 0x50240000, // 0015 LDBOOL R9 0 0 + 0x7C0C0C00, // 0016 CALL R3 6 + 0x50100000, // 0017 LDBOOL R4 0 0 + 0x80040800, // 0018 RET 1 R4 + 0x880C030B, // 0019 GETMBR R3 R1 K11 + 0xB8121800, // 001A GETNGBL R4 K12 + 0x8C10090D, // 001B GETMET R4 R4 K13 + 0x7C100200, // 001C CALL R4 1 + 0x8C10090E, // 001D GETMET R4 R4 K14 + 0x8818030F, // 001E GETMBR R6 R1 K15 + 0x881C0310, // 001F GETMBR R7 R1 K16 + 0x7C100600, // 0020 CALL R4 3 + 0xB8160A00, // 0021 GETNGBL R5 K5 + 0x8C140B06, // 0022 GETMET R5 R5 K6 + 0x581C0011, // 0023 LDCONST R7 K17 + 0x54220003, // 0024 LDINT R8 4 + 0x7C140600, // 0025 CALL R5 3 + 0x8C140512, // 0026 GETMET R5 R2 K18 + 0x7C140200, // 0027 CALL R5 1 + 0x8C140B13, // 0028 GETMET R5 R5 K19 + 0x881C0714, // 0029 GETMBR R7 R3 K20 + 0x7C140400, // 002A CALL R5 2 + 0x8C140B13, // 002B GETMET R5 R5 K19 + 0x881C0715, // 002C GETMBR R7 R3 K21 + 0x7C140400, // 002D CALL R5 2 + 0x8C140B16, // 002E GETMET R5 R5 K22 + 0x7C140200, // 002F CALL R5 1 + 0xB81A0A00, // 0030 GETNGBL R6 K5 + 0x8C180D06, // 0031 GETMET R6 R6 K6 + 0x60200008, // 0032 GETGBL R8 G8 + 0x5C240600, // 0033 MOVE R9 R3 + 0x7C200200, // 0034 CALL R8 1 + 0x00222E08, // 0035 ADD R8 K23 R8 + 0x54260003, // 0036 LDINT R9 4 + 0x7C180600, // 0037 CALL R6 3 + 0xB81A0A00, // 0038 GETNGBL R6 K5 + 0x8C180D06, // 0039 GETMET R6 R6 K6 + 0x60200008, // 003A GETGBL R8 G8 + 0x8C240719, // 003B GETMET R9 R3 K25 + 0x7C240200, // 003C CALL R9 1 + 0x7C200200, // 003D CALL R8 1 + 0x00223008, // 003E ADD R8 K24 R8 + 0x54260003, // 003F LDINT R9 4 + 0x7C180600, // 0040 CALL R6 3 + 0xB81A0A00, // 0041 GETNGBL R6 K5 + 0x8C180D06, // 0042 GETMET R6 R6 K6 + 0x60200008, // 0043 GETGBL R8 G8 + 0x8C24071B, // 0044 GETMET R9 R3 K27 + 0x7C240200, // 0045 CALL R9 1 + 0x7C200200, // 0046 CALL R8 1 + 0x00223408, // 0047 ADD R8 K26 R8 + 0x54260003, // 0048 LDINT R9 4 + 0x7C180600, // 0049 CALL R6 3 + 0xB81A0A00, // 004A GETNGBL R6 K5 + 0x8C180D06, // 004B GETMET R6 R6 K6 + 0x8C20071D, // 004C GETMET R8 R3 K29 + 0x7C200200, // 004D CALL R8 1 + 0x8C20111E, // 004E GETMET R8 R8 K30 + 0x7C200200, // 004F CALL R8 1 + 0x00223808, // 0050 ADD R8 K28 R8 + 0x54260003, // 0051 LDINT R9 4 + 0x7C180600, // 0052 CALL R6 3 + 0xB81A0A00, // 0053 GETNGBL R6 K5 + 0x8C180D06, // 0054 GETMET R6 R6 K6 + 0x8C200B1E, // 0055 GETMET R8 R5 K30 + 0x7C200200, // 0056 CALL R8 1 + 0x00223E08, // 0057 ADD R8 K31 R8 + 0x54260003, // 0058 LDINT R9 4 + 0x7C180600, // 0059 CALL R6 3 + 0x60180015, // 005A GETGBL R6 G21 + 0x7C180000, // 005B CALL R6 0 + 0x8C180D20, // 005C GETMET R6 R6 K32 + 0x88200121, // 005D GETMBR R8 R0 K33 + 0x7C180400, // 005E CALL R6 2 + 0x8C1C0522, // 005F GETMET R7 R2 K34 + 0x7C1C0200, // 0060 CALL R7 1 + 0x8C1C0F23, // 0061 GETMET R7 R7 K35 + 0x88240724, // 0062 GETMBR R9 R3 K36 + 0x8C28071D, // 0063 GETMET R10 R3 K29 + 0x7C280200, // 0064 CALL R10 1 + 0x00281405, // 0065 ADD R10 R10 R5 + 0x5C2C0C00, // 0066 MOVE R11 R6 + 0x5432000F, // 0067 LDINT R12 16 + 0x7C1C0A00, // 0068 CALL R7 5 + 0xB8220A00, // 0069 GETNGBL R8 K5 + 0x8C201106, // 006A GETMET R8 R8 K6 + 0x58280011, // 006B LDCONST R10 K17 + 0x542E0003, // 006C LDINT R11 4 + 0x7C200600, // 006D CALL R8 3 + 0xB8220A00, // 006E GETNGBL R8 K5 + 0x8C201106, // 006F GETMET R8 R8 K6 + 0x8C28071D, // 0070 GETMET R10 R3 K29 + 0x7C280200, // 0071 CALL R10 1 + 0x00281405, // 0072 ADD R10 R10 R5 + 0x8C28151E, // 0073 GETMET R10 R10 K30 + 0x7C280200, // 0074 CALL R10 1 + 0x002A4A0A, // 0075 ADD R10 K37 R10 + 0x542E0003, // 0076 LDINT R11 4 + 0x7C200600, // 0077 CALL R8 3 + 0xB8220A00, // 0078 GETNGBL R8 K5 + 0x8C201106, // 0079 GETMET R8 R8 K6 + 0x8C280F1E, // 007A GETMET R10 R7 K30 + 0x7C280200, // 007B CALL R10 1 + 0x002A4C0A, // 007C ADD R10 K38 R10 + 0x542E0003, // 007D LDINT R11 4 + 0x7C200600, // 007E CALL R8 3 + 0xB8220A00, // 007F GETNGBL R8 K5 + 0x8C201106, // 0080 GETMET R8 R8 K6 + 0x58280011, // 0081 LDCONST R10 K17 + 0x542E0003, // 0082 LDINT R11 4 + 0x7C200600, // 0083 CALL R8 3 + 0x5421FFEE, // 0084 LDINT R8 -17 + 0x40220608, // 0085 CONNECT R8 K3 R8 + 0x88240927, // 0086 GETMBR R9 R4 K39 + 0x94201208, // 0087 GETIDX R8 R9 R8 + 0x5429FFEF, // 0088 LDINT R10 -16 + 0x40281528, // 0089 CONNECT R10 R10 K40 + 0x882C0927, // 008A GETMBR R11 R4 K39 + 0x9424160A, // 008B GETIDX R9 R11 R10 + 0x8C300529, // 008C GETMET R12 R2 K41 + 0x5C380E00, // 008D MOVE R14 R7 + 0x603C0015, // 008E GETGBL R15 G21 + 0x7C3C0000, // 008F CALL R15 0 + 0x8C3C1F20, // 0090 GETMET R15 R15 K32 + 0x8844012A, // 0091 GETMBR R17 R0 K42 + 0x7C3C0400, // 0092 CALL R15 2 + 0x60400015, // 0093 GETGBL R16 G21 + 0x7C400000, // 0094 CALL R16 0 + 0x6044000C, // 0095 GETGBL R17 G12 + 0x5C481000, // 0096 MOVE R18 R8 + 0x7C440200, // 0097 CALL R17 1 + 0x544A000F, // 0098 LDINT R18 16 + 0x7C300C00, // 0099 CALL R12 6 + 0x5C281800, // 009A MOVE R10 R12 + 0x8C30152B, // 009B GETMET R12 R10 K43 + 0x5C381000, // 009C MOVE R14 R8 + 0x7C300400, // 009D CALL R12 2 + 0x5C2C1800, // 009E MOVE R11 R12 + 0x8C30152C, // 009F GETMET R12 R10 K44 + 0x7C300200, // 00A0 CALL R12 1 + 0xB8360A00, // 00A1 GETNGBL R13 K5 + 0x8C341B06, // 00A2 GETMET R13 R13 K6 + 0x8C3C171E, // 00A3 GETMET R15 R11 K30 + 0x7C3C0200, // 00A4 CALL R15 1 + 0x003E5A0F, // 00A5 ADD R15 K45 R15 + 0x54420003, // 00A6 LDINT R16 4 + 0x7C340600, // 00A7 CALL R13 3 + 0xB8360A00, // 00A8 GETNGBL R13 K5 + 0x8C341B06, // 00A9 GETMET R13 R13 K6 + 0x8C3C191E, // 00AA GETMET R15 R12 K30 + 0x7C3C0200, // 00AB CALL R15 1 + 0x003E5C0F, // 00AC ADD R15 K46 R15 + 0x54420003, // 00AD LDINT R16 4 + 0x7C340600, // 00AE CALL R13 3 + 0xB8360A00, // 00AF GETNGBL R13 K5 + 0x8C341B06, // 00B0 GETMET R13 R13 K6 + 0x8C3C131E, // 00B1 GETMET R15 R9 K30 + 0x7C3C0200, // 00B2 CALL R15 1 + 0x003E5E0F, // 00B3 ADD R15 K47 R15 + 0x54420003, // 00B4 LDINT R16 4 + 0x7C340600, // 00B5 CALL R13 3 + 0xB8360A00, // 00B6 GETNGBL R13 K5 + 0x8C341B06, // 00B7 GETMET R13 R13 K6 + 0x583C0011, // 00B8 LDCONST R15 K17 + 0x54420003, // 00B9 LDINT R16 4 + 0x7C340600, // 00BA CALL R13 3 + 0x20341809, // 00BB NE R13 R12 R9 + 0x78360012, // 00BC JMPF R13 #00D0 + 0xB8360A00, // 00BD GETNGBL R13 K5 + 0x8C341B06, // 00BE GETMET R13 R13 K6 + 0x583C0030, // 00BF LDCONST R15 K48 + 0x58400008, // 00C0 LDCONST R16 K8 + 0x7C340600, // 00C1 CALL R13 3 + 0xB8360A00, // 00C2 GETNGBL R13 K5 + 0x8C341B06, // 00C3 GETMET R13 R13 K6 + 0x583C0007, // 00C4 LDCONST R15 K7 + 0x58400008, // 00C5 LDCONST R16 K8 + 0x7C340600, // 00C6 CALL R13 3 + 0x8C340109, // 00C7 GETMET R13 R0 K9 + 0x5C3C0200, // 00C8 MOVE R15 R1 + 0x5840000A, // 00C9 LDCONST R16 K10 + 0x58440003, // 00CA LDCONST R17 K3 + 0x58480008, // 00CB LDCONST R18 K8 + 0x504C0000, // 00CC LDBOOL R19 0 0 + 0x7C340C00, // 00CD CALL R13 6 + 0x50380000, // 00CE LDBOOL R14 0 0 + 0x80041C00, // 00CF RET 1 R14 + 0xB8361800, // 00D0 GETNGBL R13 K12 + 0x88341B31, // 00D1 GETMBR R13 R13 K49 + 0x8C341B0E, // 00D2 GETMET R13 R13 K14 + 0x5C3C1600, // 00D3 MOVE R15 R11 + 0x7C340400, // 00D4 CALL R13 2 + 0xB83A0A00, // 00D5 GETNGBL R14 K5 + 0x8C381D06, // 00D6 GETMET R14 R14 K6 + 0x60400008, // 00D7 GETGBL R16 G8 + 0x5C441A00, // 00D8 MOVE R17 R13 + 0x7C400200, // 00D9 CALL R16 1 + 0x00426410, // 00DA ADD R16 K50 R16 + 0x54460003, // 00DB LDINT R17 4 + 0x7C380600, // 00DC CALL R14 3 + 0x8C381B33, // 00DD GETMET R14 R13 K51 + 0x5840000A, // 00DE LDCONST R16 K10 + 0x7C380400, // 00DF CALL R14 2 + 0x8C3C1B33, // 00E0 GETMET R15 R13 K51 + 0x58440008, // 00E1 LDCONST R17 K8 + 0x7C3C0400, // 00E2 CALL R15 2 + 0x8C401B33, // 00E3 GETMET R16 R13 K51 + 0x58480034, // 00E4 LDCONST R18 K52 + 0x7C400400, // 00E5 CALL R16 2 + 0xB8460A00, // 00E6 GETNGBL R17 K5 + 0x8C442306, // 00E7 GETMET R17 R17 K6 + 0x604C0008, // 00E8 GETGBL R19 G8 + 0x5C501C00, // 00E9 MOVE R20 R14 + 0x7C4C0200, // 00EA CALL R19 1 + 0x004E6A13, // 00EB ADD R19 K53 R19 + 0x54520003, // 00EC LDINT R20 4 + 0x7C440600, // 00ED CALL R17 3 + 0xB8460A00, // 00EE GETNGBL R17 K5 + 0x8C442306, // 00EF GETMET R17 R17 K6 + 0x604C0008, // 00F0 GETGBL R19 G8 + 0x5C501E00, // 00F1 MOVE R20 R15 + 0x7C4C0200, // 00F2 CALL R19 1 + 0x004E6C13, // 00F3 ADD R19 K54 R19 + 0x54520003, // 00F4 LDINT R20 4 + 0x7C440600, // 00F5 CALL R17 3 + 0xB8460A00, // 00F6 GETNGBL R17 K5 + 0x8C442306, // 00F7 GETMET R17 R17 K6 + 0x604C0008, // 00F8 GETGBL R19 G8 + 0x5C502000, // 00F9 MOVE R20 R16 + 0x7C4C0200, // 00FA CALL R19 1 + 0x004E6E13, // 00FB ADD R19 K55 R19 + 0x54520003, // 00FC LDINT R20 4 + 0x7C440600, // 00FD CALL R17 3 + 0xB8461800, // 00FE GETNGBL R17 K12 + 0x88442331, // 00FF GETMBR R17 R17 K49 + 0x8C44230E, // 0100 GETMET R17 R17 K14 + 0x5C4C1C00, // 0101 MOVE R19 R14 + 0x7C440400, // 0102 CALL R17 2 + 0xB84A0A00, // 0103 GETNGBL R18 K5 + 0x8C482506, // 0104 GETMET R18 R18 K6 + 0x60500008, // 0105 GETGBL R20 G8 + 0x5C542200, // 0106 MOVE R21 R17 + 0x7C500200, // 0107 CALL R20 1 + 0x00527014, // 0108 ADD R20 K56 R20 + 0x58540034, // 0109 LDCONST R21 K52 + 0x7C480600, // 010A CALL R18 3 + 0x8C482333, // 010B GETMET R18 R17 K51 + 0x54520008, // 010C LDINT R20 9 + 0x7C480400, // 010D CALL R18 2 + 0x8C4C2339, // 010E GETMET R19 R17 K57 + 0x54560005, // 010F LDINT R21 6 + 0x7C4C0400, // 0110 CALL R19 2 + 0x8C502733, // 0111 GETMET R20 R19 K51 + 0x545A0010, // 0112 LDINT R22 17 + 0x7C500400, // 0113 CALL R20 2 + 0x60540004, // 0114 GETGBL R21 G4 + 0x5C582800, // 0115 MOVE R22 R20 + 0x7C540200, // 0116 CALL R21 1 + 0x1C542B3A, // 0117 EQ R21 R21 K58 + 0x78560003, // 0118 JMPF R21 #011D + 0xB8567600, // 0119 GETNGBL R21 K59 + 0x5C582800, // 011A MOVE R22 R20 + 0x7C540200, // 011B CALL R21 1 + 0x5C502A00, // 011C MOVE R20 R21 + 0x8C54293D, // 011D GETMET R21 R20 K61 + 0x7C540200, // 011E CALL R21 1 + 0x900E7815, // 011F SETMBR R3 K60 R21 + 0xB8560A00, // 0120 GETNGBL R21 K5 + 0x8C542B06, // 0121 GETMET R21 R21 K6 + 0x605C0008, // 0122 GETGBL R23 G8 + 0x8860073C, // 0123 GETMBR R24 R3 K60 + 0x7C5C0200, // 0124 CALL R23 1 + 0x005E7C17, // 0125 ADD R23 K62 R23 + 0x58600034, // 0126 LDCONST R24 K52 + 0x7C540600, // 0127 CALL R21 3 + 0xB8561800, // 0128 GETNGBL R21 K12 + 0x88542B31, // 0129 GETMBR R21 R21 K49 + 0x8C542B3F, // 012A GETMET R21 R21 K63 + 0x7C540200, // 012B CALL R21 1 + 0x8C582B40, // 012C GETMET R22 R21 K64 + 0x5860000A, // 012D LDCONST R24 K10 + 0xB8661800, // 012E GETNGBL R25 K12 + 0x88643331, // 012F GETMBR R25 R25 K49 + 0x88643341, // 0130 GETMBR R25 R25 K65 + 0x5C681C00, // 0131 MOVE R26 R14 + 0x7C580800, // 0132 CALL R22 4 + 0x8C582B40, // 0133 GETMET R22 R21 K64 + 0x58600008, // 0134 LDCONST R24 K8 + 0xB8661800, // 0135 GETNGBL R25 K12 + 0x88643331, // 0136 GETMBR R25 R25 K49 + 0x88643341, // 0137 GETMBR R25 R25 K65 + 0x5C681E00, // 0138 MOVE R26 R15 + 0x7C580800, // 0139 CALL R22 4 + 0x8C582B40, // 013A GETMET R22 R21 K64 + 0x58600034, // 013B LDCONST R24 K52 + 0xB8661800, // 013C GETNGBL R25 K12 + 0x88643331, // 013D GETMBR R25 R25 K49 + 0x88643341, // 013E GETMBR R25 R25 K65 + 0x88680742, // 013F GETMBR R26 R3 K66 + 0x7C580800, // 0140 CALL R22 4 + 0x8C582B40, // 0141 GETMET R22 R21 K64 + 0x54620003, // 0142 LDINT R24 4 + 0xB8661800, // 0143 GETNGBL R25 K12 + 0x88643331, // 0144 GETMBR R25 R25 K49 + 0x88643341, // 0145 GETMBR R25 R25 K65 + 0x88680743, // 0146 GETMBR R26 R3 K67 + 0x7C580800, // 0147 CALL R22 4 + 0xB85A0A00, // 0148 GETNGBL R22 K5 + 0x8C582D06, // 0149 GETMET R22 R22 K6 + 0x60600008, // 014A GETGBL R24 G8 + 0x5C642A00, // 014B MOVE R25 R21 + 0x7C600200, // 014C CALL R24 1 + 0x00628818, // 014D ADD R24 K68 R24 + 0x54660003, // 014E LDINT R25 4 + 0x7C580600, // 014F CALL R22 3 + 0x8C582B45, // 0150 GETMET R22 R21 K69 + 0x7C580200, // 0151 CALL R22 1 + 0xB85E0A00, // 0152 GETNGBL R23 K5 + 0x8C5C2F06, // 0153 GETMET R23 R23 K6 + 0x8C642D1E, // 0154 GETMET R25 R22 K30 + 0x7C640200, // 0155 CALL R25 1 + 0x00668C19, // 0156 ADD R25 K70 R25 + 0x546A0003, // 0157 LDINT R26 4 + 0x7C5C0600, // 0158 CALL R23 3 + 0xB85E0A00, // 0159 GETNGBL R23 K5 + 0x8C5C2F06, // 015A GETMET R23 R23 K6 + 0x8C64251E, // 015B GETMET R25 R18 K30 + 0x7C640200, // 015C CALL R25 1 + 0x00668E19, // 015D ADD R25 K71 R25 + 0x546A0003, // 015E LDINT R26 4 + 0x7C5C0600, // 015F CALL R23 3 + 0xB85E0A00, // 0160 GETNGBL R23 K5 + 0x8C5C2F06, // 0161 GETMET R23 R23 K6 + 0x8C64211E, // 0162 GETMET R25 R16 K30 + 0x7C640200, // 0163 CALL R25 1 + 0x00669019, // 0164 ADD R25 K72 R25 + 0x546A0003, // 0165 LDINT R26 4 + 0x7C5C0600, // 0166 CALL R23 3 + 0xB85E0A00, // 0167 GETNGBL R23 K5 + 0x8C5C2F06, // 0168 GETMET R23 R23 K6 + 0x58640011, // 0169 LDCONST R25 K17 + 0x546A0003, // 016A LDINT R26 4 + 0x7C5C0600, // 016B CALL R23 3 + 0x8C5C0549, // 016C GETMET R23 R2 K73 + 0x7C5C0200, // 016D CALL R23 1 + 0x8C5C2F4A, // 016E GETMET R23 R23 K74 + 0x5C642400, // 016F MOVE R25 R18 + 0x5C682C00, // 0170 MOVE R26 R22 + 0x5C6C2000, // 0171 MOVE R27 R16 + 0x7C5C0800, // 0172 CALL R23 4 + 0x5C602E00, // 0173 MOVE R24 R23 + 0x74620012, // 0174 JMPT R24 #0188 + 0xB8620A00, // 0175 GETNGBL R24 K5 + 0x8C603106, // 0176 GETMET R24 R24 K6 + 0x5868004B, // 0177 LDCONST R26 K75 + 0x586C0008, // 0178 LDCONST R27 K8 + 0x7C600600, // 0179 CALL R24 3 + 0xB8620A00, // 017A GETNGBL R24 K5 + 0x8C603106, // 017B GETMET R24 R24 K6 + 0x58680007, // 017C LDCONST R26 K7 + 0x586C0008, // 017D LDCONST R27 K8 + 0x7C600600, // 017E CALL R24 3 + 0x8C600109, // 017F GETMET R24 R0 K9 + 0x5C680200, // 0180 MOVE R26 R1 + 0x586C000A, // 0181 LDCONST R27 K10 + 0x58700003, // 0182 LDCONST R28 K3 + 0x58740008, // 0183 LDCONST R29 K8 + 0x50780000, // 0184 LDBOOL R30 0 0 + 0x7C600C00, // 0185 CALL R24 6 + 0x50640000, // 0186 LDBOOL R25 0 0 + 0x80043200, // 0187 RET 1 R25 + 0xB8620A00, // 0188 GETNGBL R24 K5 + 0x8C603106, // 0189 GETMET R24 R24 K6 + 0x5868004C, // 018A LDCONST R26 K76 + 0x586C0034, // 018B LDCONST R27 K52 + 0x7C600600, // 018C CALL R24 3 + 0x8C600512, // 018D GETMET R24 R2 K18 + 0x7C600200, // 018E CALL R24 1 + 0x8C603113, // 018F GETMET R24 R24 K19 + 0x88680714, // 0190 GETMBR R26 R3 K20 + 0x7C600400, // 0191 CALL R24 2 + 0x8C603113, // 0192 GETMET R24 R24 K19 + 0x88680715, // 0193 GETMBR R26 R3 K21 + 0x7C600400, // 0194 CALL R24 2 + 0x8C603113, // 0195 GETMET R24 R24 K19 + 0x8868094D, // 0196 GETMBR R26 R4 K77 + 0x7C600400, // 0197 CALL R24 2 + 0x8C603116, // 0198 GETMET R24 R24 K22 + 0x7C600200, // 0199 CALL R24 1 + 0x5C143000, // 019A MOVE R5 R24 + 0xB8620A00, // 019B GETNGBL R24 K5 + 0x8C603106, // 019C GETMET R24 R24 K6 + 0x88680714, // 019D GETMBR R26 R3 K20 + 0x8C68351E, // 019E GETMET R26 R26 K30 + 0x7C680200, // 019F CALL R26 1 + 0x006A9C1A, // 01A0 ADD R26 K78 R26 + 0x546E0003, // 01A1 LDINT R27 4 + 0x7C600600, // 01A2 CALL R24 3 + 0xB8620A00, // 01A3 GETNGBL R24 K5 + 0x8C603106, // 01A4 GETMET R24 R24 K6 + 0x88680715, // 01A5 GETMBR R26 R3 K21 + 0x8C68351E, // 01A6 GETMET R26 R26 K30 + 0x7C680200, // 01A7 CALL R26 1 + 0x006A9E1A, // 01A8 ADD R26 K79 R26 + 0x546E0003, // 01A9 LDINT R27 4 + 0x7C600600, // 01AA CALL R24 3 + 0xB8620A00, // 01AB GETNGBL R24 K5 + 0x8C603106, // 01AC GETMET R24 R24 K6 + 0x8868094D, // 01AD GETMBR R26 R4 K77 + 0x8C68351E, // 01AE GETMET R26 R26 K30 + 0x7C680200, // 01AF CALL R26 1 + 0x006AA01A, // 01B0 ADD R26 K80 R26 + 0x546E0003, // 01B1 LDINT R27 4 + 0x7C600600, // 01B2 CALL R24 3 + 0xB8620A00, // 01B3 GETNGBL R24 K5 + 0x8C603106, // 01B4 GETMET R24 R24 K6 + 0x8C680B1E, // 01B5 GETMET R26 R5 K30 + 0x7C680200, // 01B6 CALL R26 1 + 0x006AA21A, // 01B7 ADD R26 K81 R26 + 0x546E0003, // 01B8 LDINT R27 4 + 0x7C600600, // 01B9 CALL R24 3 + 0x4C600000, // 01BA LDNIL R24 + 0x900E2818, // 01BB SETMBR R3 K20 R24 + 0x4C600000, // 01BC LDNIL R24 + 0x900E2A18, // 01BD SETMBR R3 K21 R24 + 0xB8620A00, // 01BE GETNGBL R24 K5 + 0x8C603106, // 01BF GETMET R24 R24 K6 + 0x58680052, // 01C0 LDCONST R26 K82 + 0x546E0003, // 01C1 LDINT R27 4 + 0x7C600600, // 01C2 CALL R24 3 + 0xB8620A00, // 01C3 GETNGBL R24 K5 + 0x8C603106, // 01C4 GETMET R24 R24 K6 + 0x88680724, // 01C5 GETMBR R26 R3 K36 + 0x8C68351E, // 01C6 GETMET R26 R26 K30 + 0x7C680200, // 01C7 CALL R26 1 + 0x006AA61A, // 01C8 ADD R26 K83 R26 + 0x546E0003, // 01C9 LDINT R27 4 + 0x7C600600, // 01CA CALL R24 3 + 0xB8620A00, // 01CB GETNGBL R24 K5 + 0x8C603106, // 01CC GETMET R24 R24 K6 + 0x8C68071D, // 01CD GETMET R26 R3 K29 + 0x7C680200, // 01CE CALL R26 1 + 0x00683405, // 01CF ADD R26 R26 R5 + 0x8C68351E, // 01D0 GETMET R26 R26 K30 + 0x7C680200, // 01D1 CALL R26 1 + 0x006AA81A, // 01D2 ADD R26 K84 R26 + 0x546E0003, // 01D3 LDINT R27 4 + 0x7C600600, // 01D4 CALL R24 3 + 0x8C600522, // 01D5 GETMET R24 R2 K34 + 0x7C600200, // 01D6 CALL R24 1 + 0x8C603123, // 01D7 GETMET R24 R24 K35 + 0x88680724, // 01D8 GETMBR R26 R3 K36 + 0x8C6C071D, // 01D9 GETMET R27 R3 K29 + 0x7C6C0200, // 01DA CALL R27 1 + 0x006C3605, // 01DB ADD R27 R27 R5 + 0x60700015, // 01DC GETGBL R28 G21 + 0x7C700000, // 01DD CALL R28 0 + 0x8C703920, // 01DE GETMET R28 R28 K32 + 0x88780155, // 01DF GETMBR R30 R0 K85 + 0x7C700400, // 01E0 CALL R28 2 + 0x5476002F, // 01E1 LDINT R29 48 + 0x7C600A00, // 01E2 CALL R24 5 + 0x5466000E, // 01E3 LDINT R25 15 + 0x40660619, // 01E4 CONNECT R25 K3 R25 + 0x94643019, // 01E5 GETIDX R25 R24 R25 + 0x546A000F, // 01E6 LDINT R26 16 + 0x546E001E, // 01E7 LDINT R27 31 + 0x4068341B, // 01E8 CONNECT R26 R26 R27 + 0x9468301A, // 01E9 GETIDX R26 R24 R26 + 0x546E001F, // 01EA LDINT R27 32 + 0x5472002E, // 01EB LDINT R28 47 + 0x406C361C, // 01EC CONNECT R27 R27 R28 + 0x946C301B, // 01ED GETIDX R27 R24 R27 + 0xB8720A00, // 01EE GETNGBL R28 K5 + 0x8C703956, // 01EF GETMET R28 R28 K86 + 0x7C700200, // 01F0 CALL R28 1 + 0x94703957, // 01F1 GETIDX R28 R28 K87 + 0xB8760A00, // 01F2 GETNGBL R29 K5 + 0x8C743B06, // 01F3 GETMET R29 R29 K6 + 0x587C0052, // 01F4 LDCONST R31 K82 + 0x54820003, // 01F5 LDINT R32 4 + 0x7C740600, // 01F6 CALL R29 3 + 0xB8760A00, // 01F7 GETNGBL R29 K5 + 0x8C743B06, // 01F8 GETMET R29 R29 K6 + 0x8C7C331E, // 01F9 GETMET R31 R25 K30 + 0x7C7C0200, // 01FA CALL R31 1 + 0x007EB01F, // 01FB ADD R31 K88 R31 + 0x54820003, // 01FC LDINT R32 4 + 0x7C740600, // 01FD CALL R29 3 + 0xB8760A00, // 01FE GETNGBL R29 K5 + 0x8C743B06, // 01FF GETMET R29 R29 K6 + 0x8C7C351E, // 0200 GETMET R31 R26 K30 + 0x7C7C0200, // 0201 CALL R31 1 + 0x007EB21F, // 0202 ADD R31 K89 R31 + 0x54820003, // 0203 LDINT R32 4 + 0x7C740600, // 0204 CALL R29 3 + 0xB8760A00, // 0205 GETNGBL R29 K5 + 0x8C743B06, // 0206 GETMET R29 R29 K6 + 0x8C7C371E, // 0207 GETMET R31 R27 K30 + 0x7C7C0200, // 0208 CALL R31 1 + 0x007EB41F, // 0209 ADD R31 K90 R31 + 0x54820003, // 020A LDINT R32 4 + 0x7C740600, // 020B CALL R29 3 + 0xB8760A00, // 020C GETNGBL R29 K5 + 0x8C743B06, // 020D GETMET R29 R29 K6 + 0x587C0052, // 020E LDCONST R31 K82 + 0x54820003, // 020F LDINT R32 4 + 0x7C740600, // 0210 CALL R29 3 + 0x8C740109, // 0211 GETMET R29 R0 K9 + 0x5C7C0200, // 0212 MOVE R31 R1 + 0x58800003, // 0213 LDCONST R32 K3 + 0x58840003, // 0214 LDCONST R33 K3 + 0x58880003, // 0215 LDCONST R34 K3 + 0x508C0200, // 0216 LDBOOL R35 1 0 + 0x7C740C00, // 0217 CALL R29 6 + 0x8C78075B, // 0218 GETMET R30 R3 K91 + 0x7C780200, // 0219 CALL R30 1 + 0x8C78075C, // 021A GETMET R30 R3 K92 + 0x5C803200, // 021B MOVE R32 R25 + 0x5C843400, // 021C MOVE R33 R26 + 0x5C883600, // 021D MOVE R34 R27 + 0x5C8C3800, // 021E MOVE R35 R28 + 0x7C780A00, // 021F CALL R30 5 + 0x900EBB03, // 0220 SETMBR R3 K93 K3 + 0x8C78075E, // 0221 GETMET R30 R3 K94 + 0x7C780200, // 0222 CALL R30 1 + 0x8C78075F, // 0223 GETMET R30 R3 K95 + 0x50800200, // 0224 LDBOOL R32 1 0 + 0x7C780400, // 0225 CALL R30 2 + 0x8C780760, // 0226 GETMET R30 R3 K96 + 0x7C780200, // 0227 CALL R30 1 + 0x8C780761, // 0228 GETMET R30 R3 K97 + 0x7C780200, // 0229 CALL R30 1 + 0x8C780762, // 022A GETMET R30 R3 K98 + 0x7C780200, // 022B CALL R30 1 + 0x50780200, // 022C LDBOOL R30 1 0 + 0x80043C00, // 022D RET 1 R30 }) ) ); @@ -2288,7 +1580,7 @@ be_local_closure(Matter_Commisioning_Context_parse_Pake3, /* name */ ********************************************************************/ be_local_closure(Matter_Commisioning_Context_process_incoming, /* name */ be_nested_proto( - 7, /* nstack */ + 9, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -2296,90 +1588,1092 @@ be_local_closure(Matter_Commisioning_Context_process_incoming, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[15]) { /* constants */ - /* K0 */ be_nested_str_weak(window_open), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(MTR_X3A_X20commissioning_X20not_X20open), - /* K4 */ be_const_int(2), - /* K5 */ be_nested_str_weak(MTR_X3A_X20received_X20message_X20), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(inspect), - /* K8 */ be_const_int(3), - /* K9 */ be_nested_str_weak(opcode), - /* K10 */ be_nested_str_weak(parse_PBKDFParamRequest), - /* K11 */ be_nested_str_weak(parse_Pake1), - /* K12 */ be_nested_str_weak(parse_Pake3), - /* K13 */ be_nested_str_weak(parse_Sigma1), - /* K14 */ be_nested_str_weak(parse_Sigma3), + ( &(const bvalue[20]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(is_commissioning_open), + /* K2 */ be_nested_str_weak(opcode), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(MTR_X3A_X20commissioning_X20not_X20open), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str_weak(MTR_X3A_X20received_X20message_X20), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(inspect), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(parse_PBKDFParamRequest), + /* K12 */ be_nested_str_weak(parse_Pake1), + /* K13 */ be_nested_str_weak(parse_Pake3), + /* K14 */ be_nested_str_weak(parse_Sigma1), + /* K15 */ be_nested_str_weak(parse_Sigma3), + /* K16 */ be_nested_str_weak(parse_StatusReport), + /* K17 */ be_nested_str_weak(string), + /* K18 */ be_nested_str_weak(format), + /* K19 */ be_nested_str_weak(MTR_X3A_X20_X3E_X3F_X3F_X3F_X3F_X3F_X3F_X3F_X3F_X3F_X20Unknown_X20OpCode_X20_X28secure_X20channel_X29_X20_X2502X), }), be_str_weak(process_incoming), &be_const_str_solidified, - ( &(const binstruction[64]) { /* code */ + ( &(const binstruction[100]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x740A0006, // 0001 JMPT R2 #0009 - 0xB80A0200, // 0002 GETNGBL R2 K1 - 0x8C080502, // 0003 GETMET R2 R2 K2 - 0x58100003, // 0004 LDCONST R4 K3 - 0x58140004, // 0005 LDCONST R5 K4 - 0x7C080600, // 0006 CALL R2 3 - 0x50080000, // 0007 LDBOOL R2 0 0 - 0x80040400, // 0008 RET 1 R2 - 0xB80A0200, // 0009 GETNGBL R2 K1 - 0x8C080502, // 000A GETMET R2 R2 K2 - 0xB8120C00, // 000B GETNGBL R4 K6 - 0x8C100907, // 000C GETMET R4 R4 K7 - 0x5C180200, // 000D MOVE R6 R1 - 0x7C100400, // 000E CALL R4 2 - 0x00120A04, // 000F ADD R4 K5 R4 - 0x58140008, // 0010 LDCONST R5 K8 - 0x7C080600, // 0011 CALL R2 3 - 0x88080309, // 0012 GETMBR R2 R1 K9 - 0x540E001F, // 0013 LDINT R3 32 - 0x1C080403, // 0014 EQ R2 R2 R3 - 0x780A0004, // 0015 JMPF R2 #001B - 0x8C08010A, // 0016 GETMET R2 R0 K10 - 0x5C100200, // 0017 MOVE R4 R1 - 0x7C080400, // 0018 CALL R2 2 - 0x80040400, // 0019 RET 1 R2 - 0x70020022, // 001A JMP #003E - 0x88080309, // 001B GETMBR R2 R1 K9 - 0x540E0021, // 001C LDINT R3 34 - 0x1C080403, // 001D EQ R2 R2 R3 - 0x780A0004, // 001E JMPF R2 #0024 - 0x8C08010B, // 001F GETMET R2 R0 K11 - 0x5C100200, // 0020 MOVE R4 R1 - 0x7C080400, // 0021 CALL R2 2 - 0x80040400, // 0022 RET 1 R2 - 0x70020019, // 0023 JMP #003E - 0x88080309, // 0024 GETMBR R2 R1 K9 - 0x540E0023, // 0025 LDINT R3 36 - 0x1C080403, // 0026 EQ R2 R2 R3 - 0x780A0004, // 0027 JMPF R2 #002D - 0x8C08010C, // 0028 GETMET R2 R0 K12 - 0x5C100200, // 0029 MOVE R4 R1 - 0x7C080400, // 002A CALL R2 2 - 0x80040400, // 002B RET 1 R2 - 0x70020010, // 002C JMP #003E - 0x88080309, // 002D GETMBR R2 R1 K9 - 0x540E002F, // 002E LDINT R3 48 - 0x1C080403, // 002F EQ R2 R2 R3 - 0x780A0004, // 0030 JMPF R2 #0036 - 0x8C08010D, // 0031 GETMET R2 R0 K13 - 0x5C100200, // 0032 MOVE R4 R1 - 0x7C080400, // 0033 CALL R2 2 - 0x80040400, // 0034 RET 1 R2 - 0x70020007, // 0035 JMP #003E - 0x88080309, // 0036 GETMBR R2 R1 K9 - 0x540E0031, // 0037 LDINT R3 50 - 0x1C080403, // 0038 EQ R2 R2 R3 - 0x780A0003, // 0039 JMPF R2 #003E - 0x8C08010E, // 003A GETMET R2 R0 K14 - 0x5C100200, // 003B MOVE R4 R1 - 0x7C080400, // 003C CALL R2 2 - 0x80040400, // 003D RET 1 R2 - 0x50080000, // 003E LDBOOL R2 0 0 - 0x80040400, // 003F RET 1 R2 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x740A000E, // 0003 JMPT R2 #0013 + 0x88080302, // 0004 GETMBR R2 R1 K2 + 0x540E001F, // 0005 LDINT R3 32 + 0x28080403, // 0006 GE R2 R2 R3 + 0x780A000A, // 0007 JMPF R2 #0013 + 0x88080302, // 0008 GETMBR R2 R1 K2 + 0x540E0023, // 0009 LDINT R3 36 + 0x18080403, // 000A LE R2 R2 R3 + 0x780A0006, // 000B JMPF R2 #0013 + 0xB80A0600, // 000C GETNGBL R2 K3 + 0x8C080504, // 000D GETMET R2 R2 K4 + 0x58100005, // 000E LDCONST R4 K5 + 0x58140006, // 000F LDCONST R5 K6 + 0x7C080600, // 0010 CALL R2 3 + 0x50080000, // 0011 LDBOOL R2 0 0 + 0x80040400, // 0012 RET 1 R2 + 0xB80A0600, // 0013 GETNGBL R2 K3 + 0x8C080504, // 0014 GETMET R2 R2 K4 + 0xB8121000, // 0015 GETNGBL R4 K8 + 0x8C100909, // 0016 GETMET R4 R4 K9 + 0x5C180200, // 0017 MOVE R6 R1 + 0x7C100400, // 0018 CALL R4 2 + 0x00120E04, // 0019 ADD R4 K7 R4 + 0x5814000A, // 001A LDCONST R5 K10 + 0x7C080600, // 001B CALL R2 3 + 0x88080302, // 001C GETMBR R2 R1 K2 + 0x540E000F, // 001D LDINT R3 16 + 0x1C080403, // 001E EQ R2 R2 R3 + 0x780A0000, // 001F JMPF R2 #0021 + 0x70020040, // 0020 JMP #0062 + 0x88080302, // 0021 GETMBR R2 R1 K2 + 0x540E001F, // 0022 LDINT R3 32 + 0x1C080403, // 0023 EQ R2 R2 R3 + 0x780A0004, // 0024 JMPF R2 #002A + 0x8C08010B, // 0025 GETMET R2 R0 K11 + 0x5C100200, // 0026 MOVE R4 R1 + 0x7C080400, // 0027 CALL R2 2 + 0x80040400, // 0028 RET 1 R2 + 0x70020037, // 0029 JMP #0062 + 0x88080302, // 002A GETMBR R2 R1 K2 + 0x540E0021, // 002B LDINT R3 34 + 0x1C080403, // 002C EQ R2 R2 R3 + 0x780A0004, // 002D JMPF R2 #0033 + 0x8C08010C, // 002E GETMET R2 R0 K12 + 0x5C100200, // 002F MOVE R4 R1 + 0x7C080400, // 0030 CALL R2 2 + 0x80040400, // 0031 RET 1 R2 + 0x7002002E, // 0032 JMP #0062 + 0x88080302, // 0033 GETMBR R2 R1 K2 + 0x540E0023, // 0034 LDINT R3 36 + 0x1C080403, // 0035 EQ R2 R2 R3 + 0x780A0004, // 0036 JMPF R2 #003C + 0x8C08010D, // 0037 GETMET R2 R0 K13 + 0x5C100200, // 0038 MOVE R4 R1 + 0x7C080400, // 0039 CALL R2 2 + 0x80040400, // 003A RET 1 R2 + 0x70020025, // 003B JMP #0062 + 0x88080302, // 003C GETMBR R2 R1 K2 + 0x540E002F, // 003D LDINT R3 48 + 0x1C080403, // 003E EQ R2 R2 R3 + 0x780A0004, // 003F JMPF R2 #0045 + 0x8C08010E, // 0040 GETMET R2 R0 K14 + 0x5C100200, // 0041 MOVE R4 R1 + 0x7C080400, // 0042 CALL R2 2 + 0x80040400, // 0043 RET 1 R2 + 0x7002001C, // 0044 JMP #0062 + 0x88080302, // 0045 GETMBR R2 R1 K2 + 0x540E0031, // 0046 LDINT R3 50 + 0x1C080403, // 0047 EQ R2 R2 R3 + 0x780A0004, // 0048 JMPF R2 #004E + 0x8C08010F, // 0049 GETMET R2 R0 K15 + 0x5C100200, // 004A MOVE R4 R1 + 0x7C080400, // 004B CALL R2 2 + 0x80040400, // 004C RET 1 R2 + 0x70020013, // 004D JMP #0062 + 0x88080302, // 004E GETMBR R2 R1 K2 + 0x540E003F, // 004F LDINT R3 64 + 0x1C080403, // 0050 EQ R2 R2 R3 + 0x780A0004, // 0051 JMPF R2 #0057 + 0x8C080110, // 0052 GETMET R2 R0 K16 + 0x5C100200, // 0053 MOVE R4 R1 + 0x7C080400, // 0054 CALL R2 2 + 0x80040400, // 0055 RET 1 R2 + 0x7002000A, // 0056 JMP #0062 + 0xA40A2200, // 0057 IMPORT R2 K17 + 0xB80E0600, // 0058 GETNGBL R3 K3 + 0x8C0C0704, // 0059 GETMET R3 R3 K4 + 0x8C140512, // 005A GETMET R5 R2 K18 + 0x581C0013, // 005B LDCONST R7 K19 + 0x88200302, // 005C GETMBR R8 R1 K2 + 0x7C140600, // 005D CALL R5 3 + 0x58180006, // 005E LDCONST R6 K6 + 0x7C0C0600, // 005F CALL R3 3 + 0x500C0000, // 0060 LDBOOL R3 0 0 + 0x80040600, // 0061 RET 1 R3 + 0x50080000, // 0062 LDBOOL R2 0 0 + 0x80040400, // 0063 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_Sigma1 +********************************************************************/ +be_local_closure(Matter_Commisioning_Context_parse_Sigma1, /* name */ + be_nested_proto( + 37, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[144]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(session), + /* K3 */ be_nested_str_weak(opcode), + /* K4 */ be_nested_str_weak(local_session_id), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(protocol_id), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(MTR_X3A_X20StatusReport_X28General_X20Code_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20INVALID_PARAMETER_X29), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(send_status_report), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_weak(matter), + /* K14 */ be_nested_str_weak(Sigma1), + /* K15 */ be_nested_str_weak(parse), + /* K16 */ be_nested_str_weak(raw), + /* K17 */ be_nested_str_weak(app_payload_idx), + /* K18 */ be_nested_str_weak(format), + /* K19 */ be_nested_str_weak(MTR_X3A_X20sigma1_X3D_X25s), + /* K20 */ be_nested_str_weak(inspect), + /* K21 */ be_nested_str_weak(__initiator_pub), + /* K22 */ be_nested_str_weak(initiatorEphPubKey), + /* K23 */ be_nested_str_weak(resumptionID), + /* K24 */ be_nested_str_weak(initiatorResumeMIC), + /* K25 */ be_nested_str_weak(MTR_X3A_X20is_resumption_X3D_X25i), + /* K26 */ be_nested_str_weak(device), + /* K27 */ be_nested_str_weak(sessions), + /* K28 */ be_nested_str_weak(find_session_by_resumption_id), + /* K29 */ be_nested_str_weak(MTR_X3A_X20session_resumption_X20found_X20session_X3D_X25s_X20session_resumption_X3D_X25s), + /* K30 */ be_nested_str_weak(_fabric), + /* K31 */ be_nested_str_weak(initiatorRandom), + /* K32 */ be_nested_str_weak(fromstring), + /* K33 */ be_nested_str_weak(Sigma1_Resume), + /* K34 */ be_nested_str_weak(HKDF_SHA256), + /* K35 */ be_nested_str_weak(derive), + /* K36 */ be_nested_str_weak(shared_secret), + /* K37 */ be_nested_str_weak(NCASE_SigmaS1), + /* K38 */ be_const_int(2147483647), + /* K39 */ be_nested_str_weak(AES_CCM), + /* K40 */ be_nested_str_weak(decrypt), + /* K41 */ be_nested_str_weak(tag), + /* K42 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K43 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s1rk_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K44 */ be_nested_str_weak(tohex), + /* K45 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K46 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20Resume1MICPayload_X20_X3D_X20), + /* K47 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20decrypted_tag_X20_X20_X20_X20_X20_X3D_X20), + /* K48 */ be_nested_str_weak(_source_node_id), + /* K49 */ be_nested_str_weak(source_node_id), + /* K50 */ be_nested_str_weak(set_mode_CASE), + /* K51 */ be_nested_str_weak(__future_initiator_session_id), + /* K52 */ be_nested_str_weak(initiator_session_id), + /* K53 */ be_nested_str_weak(__future_local_session_id), + /* K54 */ be_nested_str_weak(gen_local_session_id), + /* K55 */ be_nested_str_weak(MTR_X3A_X20_X2BSession_X20_X20_X20_X28_X256i_X29_X20from_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), + /* K56 */ be_nested_str_weak(remote_ip), + /* K57 */ be_nested_str_weak(remote_port), + /* K58 */ be_nested_str_weak(resumption_id), + /* K59 */ be_nested_str_weak(random), + /* K60 */ be_nested_str_weak(Sigma2_Resume), + /* K61 */ be_nested_str_weak(NCASE_SigmaS2), + /* K62 */ be_nested_str_weak(Sigma2Resume), + /* K63 */ be_nested_str_weak(responderSessionID), + /* K64 */ be_nested_str_weak(sigma2ResumeMIC), + /* K65 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2rk_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K66 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2rk_salt_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K67 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20new_resumption_id_X20_X3D_X20), + /* K68 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20responderSessionID_X3D_X20), + /* K69 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20sigma2ResumeMIC_X20_X20_X20_X3D_X20), + /* K70 */ be_nested_str_weak(SessionResumptionKeys), + /* K71 */ be_nested_str_weak(rtc), + /* K72 */ be_nested_str_weak(utc), + /* K73 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K74 */ be_nested_str_weak(MTR_X3A_X20I2RKey_X20_X20_X20_X20_X20_X20_X3D), + /* K75 */ be_nested_str_weak(MTR_X3A_X20R2IKey_X20_X20_X20_X20_X20_X20_X3D), + /* K76 */ be_nested_str_weak(MTR_X3A_X20AC_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K77 */ be_nested_str_weak(tlv2raw), + /* K78 */ be_nested_str_weak(__Msg1), + /* K79 */ be_nested_str_weak(MTR_X3A_X20sigma2resume_X3A_X20), + /* K80 */ be_nested_str_weak(MTR_X3A_X20sigma2resume_raw_X3A_X20), + /* K81 */ be_nested_str_weak(build_response), + /* K82 */ be_nested_str_weak(encode_frame), + /* K83 */ be_nested_str_weak(responder), + /* K84 */ be_nested_str_weak(send_response_frame), + /* K85 */ be_nested_str_weak(close), + /* K86 */ be_nested_str_weak(set_keys), + /* K87 */ be_nested_str_weak(_breadcrumb), + /* K88 */ be_nested_str_weak(counter_snd_next), + /* K89 */ be_nested_str_weak(set_persist), + /* K90 */ be_nested_str_weak(set_no_expiration), + /* K91 */ be_nested_str_weak(persist_to_fabric), + /* K92 */ be_nested_str_weak(save), + /* K93 */ be_nested_str_weak(find_fabric_by_destination_id), + /* K94 */ be_nested_str_weak(destinationId), + /* K95 */ be_nested_str_weak(MTR_X3A_X20StatusReport_X28GeneralCode_X3A_X20FAILURE_X2C_X20ProtocolId_X3A_X20SECURE_CHANNEL_X2C_X20ProtocolCode_X3A_X20NO_SHARED_TRUST_ROOTS_X29), + /* K96 */ be_nested_str_weak(MTR_X3A_X20fabric_X3D), + /* K97 */ be_nested_str_weak(MTR_X3A_X20no_private_key_X3D), + /* K98 */ be_nested_str_weak(no_private_key), + /* K99 */ be_nested_str_weak(MTR_X3A_X20noc_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K100 */ be_nested_str_weak(noc), + /* K101 */ be_nested_str_weak(get_icac), + /* K102 */ be_nested_str_weak(MTR_X3A_X20icac_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K103 */ be_nested_str_weak(MTR_X3A_X20root_ca_cert_X20_X20_X3D), + /* K104 */ be_nested_str_weak(root_ca_certificate), + /* K105 */ be_nested_str_weak(__responder_priv), + /* K106 */ be_nested_str_weak(__responder_pub), + /* K107 */ be_nested_str_weak(EC_P256), + /* K108 */ be_nested_str_weak(public_key), + /* K109 */ be_nested_str_weak(MTR_X3A_X20ResponderEph_priv_X20_X20_X3D), + /* K110 */ be_nested_str_weak(MTR_X3A_X20ResponderEph_pub_X20_X20_X3D), + /* K111 */ be_nested_str_weak(shared_key), + /* K112 */ be_nested_str_weak(TLV), + /* K113 */ be_nested_str_weak(Matter_TLV_struct), + /* K114 */ be_nested_str_weak(add_TLV), + /* K115 */ be_nested_str_weak(B2), + /* K116 */ be_nested_str_weak(get_noc), + /* K117 */ be_const_int(3), + /* K118 */ be_nested_str_weak(ecdsa_sign_sha256), + /* K119 */ be_nested_str_weak(get_pk), + /* K120 */ be_nested_str_weak(Msg1), + /* K121 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20resumptionid_X20_X20_X3D_X20), + /* K122 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20MSG1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K123 */ be_nested_str_weak(SHA256), + /* K124 */ be_nested_str_weak(update), + /* K125 */ be_nested_str_weak(out), + /* K126 */ be_nested_str_weak(MTR_X3A_X20TranscriptHash_X20_X3D), + /* K127 */ be_nested_str_weak(S2K_Info), + /* K128 */ be_nested_str_weak(get_ipk_group_key), + /* K129 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20SharedSecret_X20_X20_X3D_X20), + /* K130 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_salt_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K131 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20s2k_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), + /* K132 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData2Raw_X20_X20_X20_X3D_X20), + /* K133 */ be_nested_str_weak(TBEData2_Nonce), + /* K134 */ be_nested_str_weak(encrypt), + /* K135 */ be_nested_str_weak(MTR_X3A_X20_X2A_X20TBEData2Enc_X20_X20_X20_X3D_X20), + /* K136 */ be_nested_str_weak(Sigma2), + /* K137 */ be_nested_str_weak(responderRandom), + /* K138 */ be_nested_str_weak(responderSessionId), + /* K139 */ be_nested_str_weak(responderEphPubKey), + /* K140 */ be_nested_str_weak(encrypted2), + /* K141 */ be_nested_str_weak(MTR_X3A_X20sigma2_X3A_X20), + /* K142 */ be_nested_str_weak(__Msg2), + /* K143 */ be_nested_str_weak(MTR_X3A_X20sigma2_raw_X3A_X20), + }), + be_str_weak(parse_Sigma1), + &be_const_str_solidified, + ( &(const binstruction[793]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x88100302, // 0002 GETMBR R4 R1 K2 + 0x88140303, // 0003 GETMBR R5 R1 K3 + 0x541A002F, // 0004 LDINT R6 48 + 0x20140A06, // 0005 NE R5 R5 R6 + 0x74160005, // 0006 JMPT R5 #000D + 0x88140304, // 0007 GETMBR R5 R1 K4 + 0x20140B05, // 0008 NE R5 R5 K5 + 0x74160002, // 0009 JMPT R5 #000D + 0x88140306, // 000A GETMBR R5 R1 K6 + 0x20140B05, // 000B NE R5 R5 K5 + 0x7816000D, // 000C JMPF R5 #001B + 0xB8160E00, // 000D GETNGBL R5 K7 + 0x8C140B08, // 000E GETMET R5 R5 K8 + 0x581C0009, // 000F LDCONST R7 K9 + 0x5820000A, // 0010 LDCONST R8 K10 + 0x7C140600, // 0011 CALL R5 3 + 0x8C14010B, // 0012 GETMET R5 R0 K11 + 0x5C1C0200, // 0013 MOVE R7 R1 + 0x5820000C, // 0014 LDCONST R8 K12 + 0x58240005, // 0015 LDCONST R9 K5 + 0x5828000A, // 0016 LDCONST R10 K10 + 0x502C0000, // 0017 LDBOOL R11 0 0 + 0x7C140C00, // 0018 CALL R5 6 + 0x50180000, // 0019 LDBOOL R6 0 0 + 0x80040C00, // 001A RET 1 R6 + 0xB8161A00, // 001B GETNGBL R5 K13 + 0x8C140B0E, // 001C GETMET R5 R5 K14 + 0x7C140200, // 001D CALL R5 1 + 0x8C140B0F, // 001E GETMET R5 R5 K15 + 0x881C0310, // 001F GETMBR R7 R1 K16 + 0x88200311, // 0020 GETMBR R8 R1 K17 + 0x7C140600, // 0021 CALL R5 3 + 0xB81A0E00, // 0022 GETNGBL R6 K7 + 0x8C180D08, // 0023 GETMET R6 R6 K8 + 0x8C200712, // 0024 GETMET R8 R3 K18 + 0x58280013, // 0025 LDCONST R10 K19 + 0xB82E1A00, // 0026 GETNGBL R11 K13 + 0x8C2C1714, // 0027 GETMET R11 R11 K20 + 0x5C340A00, // 0028 MOVE R13 R5 + 0x7C2C0400, // 0029 CALL R11 2 + 0x7C200600, // 002A CALL R8 3 + 0x54260003, // 002B LDINT R9 4 + 0x7C180600, // 002C CALL R6 3 + 0x88180B16, // 002D GETMBR R6 R5 K22 + 0x90122A06, // 002E SETMBR R4 K21 R6 + 0x88180B17, // 002F GETMBR R6 R5 K23 + 0x4C1C0000, // 0030 LDNIL R7 + 0x20180C07, // 0031 NE R6 R6 R7 + 0x781A0003, // 0032 JMPF R6 #0037 + 0x88180B18, // 0033 GETMBR R6 R5 K24 + 0x4C1C0000, // 0034 LDNIL R7 + 0x20180C07, // 0035 NE R6 R6 R7 + 0x741A0000, // 0036 JMPT R6 #0038 + 0x50180001, // 0037 LDBOOL R6 0 1 + 0x50180200, // 0038 LDBOOL R6 1 0 + 0xB81E0E00, // 0039 GETNGBL R7 K7 + 0x8C1C0F08, // 003A GETMET R7 R7 K8 + 0x8C240712, // 003B GETMET R9 R3 K18 + 0x582C0019, // 003C LDCONST R11 K25 + 0x781A0001, // 003D JMPF R6 #0040 + 0x5830000C, // 003E LDCONST R12 K12 + 0x70020000, // 003F JMP #0041 + 0x58300005, // 0040 LDCONST R12 K5 + 0x7C240600, // 0041 CALL R9 3 + 0x542A0003, // 0042 LDINT R10 4 + 0x7C1C0600, // 0043 CALL R7 3 + 0x50180000, // 0044 LDBOOL R6 0 0 + 0x4C1C0000, // 0045 LDNIL R7 + 0x781A001C, // 0046 JMPF R6 #0064 + 0x8820011A, // 0047 GETMBR R8 R0 K26 + 0x8820111B, // 0048 GETMBR R8 R8 K27 + 0x8C20111C, // 0049 GETMET R8 R8 K28 + 0x88280B17, // 004A GETMBR R10 R5 K23 + 0x7C200400, // 004B CALL R8 2 + 0x5C1C1000, // 004C MOVE R7 R8 + 0xB8220E00, // 004D GETNGBL R8 K7 + 0x8C201108, // 004E GETMET R8 R8 K8 + 0x8C280712, // 004F GETMET R10 R3 K18 + 0x5830001D, // 0050 LDCONST R12 K29 + 0xB8361A00, // 0051 GETNGBL R13 K13 + 0x8C341B14, // 0052 GETMET R13 R13 K20 + 0x5C3C0800, // 0053 MOVE R15 R4 + 0x7C340400, // 0054 CALL R13 2 + 0xB83A1A00, // 0055 GETNGBL R14 K13 + 0x8C381D14, // 0056 GETMET R14 R14 K20 + 0x5C400E00, // 0057 MOVE R16 R7 + 0x7C380400, // 0058 CALL R14 2 + 0x7C280800, // 0059 CALL R10 4 + 0x542E0003, // 005A LDINT R11 4 + 0x7C200600, // 005B CALL R8 3 + 0x4C200000, // 005C LDNIL R8 + 0x1C200E08, // 005D EQ R8 R7 R8 + 0x74220003, // 005E JMPT R8 #0063 + 0x88200F1E, // 005F GETMBR R8 R7 K30 + 0x4C240000, // 0060 LDNIL R9 + 0x1C201009, // 0061 EQ R8 R8 R9 + 0x78220000, // 0062 JMPF R8 #0064 + 0x50180000, // 0063 LDBOOL R6 0 0 + 0x781A013A, // 0064 JMPF R6 #01A0 + 0x88200B1F, // 0065 GETMBR R8 R5 K31 + 0x88240B17, // 0066 GETMBR R9 R5 K23 + 0x00201009, // 0067 ADD R8 R8 R9 + 0x60240015, // 0068 GETGBL R9 G21 + 0x7C240000, // 0069 CALL R9 0 + 0x8C241320, // 006A GETMET R9 R9 K32 + 0x582C0021, // 006B LDCONST R11 K33 + 0x7C240400, // 006C CALL R9 2 + 0x8C280522, // 006D GETMET R10 R2 K34 + 0x7C280200, // 006E CALL R10 1 + 0x8C281523, // 006F GETMET R10 R10 K35 + 0x88300F24, // 0070 GETMBR R12 R7 K36 + 0x5C341000, // 0071 MOVE R13 R8 + 0x5C381200, // 0072 MOVE R14 R9 + 0x543E000F, // 0073 LDINT R15 16 + 0x7C280A00, // 0074 CALL R10 5 + 0x602C0015, // 0075 GETGBL R11 G21 + 0x7C2C0000, // 0076 CALL R11 0 + 0x8C2C1720, // 0077 GETMET R11 R11 K32 + 0x58340025, // 0078 LDCONST R13 K37 + 0x7C2C0400, // 0079 CALL R11 2 + 0x5431FFEE, // 007A LDINT R12 -17 + 0x40320A0C, // 007B CONNECT R12 K5 R12 + 0x88340B18, // 007C GETMBR R13 R5 K24 + 0x94301A0C, // 007D GETIDX R12 R13 R12 + 0x5439FFEF, // 007E LDINT R14 -16 + 0x40381D26, // 007F CONNECT R14 R14 K38 + 0x883C0B18, // 0080 GETMBR R15 R5 K24 + 0x94341E0E, // 0081 GETIDX R13 R15 R14 + 0x8C400527, // 0082 GETMET R16 R2 K39 + 0x5C481400, // 0083 MOVE R18 R10 + 0x5C4C1600, // 0084 MOVE R19 R11 + 0x60500015, // 0085 GETGBL R20 G21 + 0x7C500000, // 0086 CALL R20 0 + 0x6054000C, // 0087 GETGBL R21 G12 + 0x5C581800, // 0088 MOVE R22 R12 + 0x7C540200, // 0089 CALL R21 1 + 0x545A000F, // 008A LDINT R22 16 + 0x7C400C00, // 008B CALL R16 6 + 0x5C382000, // 008C MOVE R14 R16 + 0x8C401D28, // 008D GETMET R16 R14 K40 + 0x5C481800, // 008E MOVE R18 R12 + 0x7C400400, // 008F CALL R16 2 + 0x5C3C2000, // 0090 MOVE R15 R16 + 0x8C401D29, // 0091 GETMET R16 R14 K41 + 0x7C400200, // 0092 CALL R16 1 + 0xB8460E00, // 0093 GETNGBL R17 K7 + 0x8C442308, // 0094 GETMET R17 R17 K8 + 0x584C002A, // 0095 LDCONST R19 K42 + 0x54520003, // 0096 LDINT R20 4 + 0x7C440600, // 0097 CALL R17 3 + 0xB8460E00, // 0098 GETNGBL R17 K7 + 0x8C442308, // 0099 GETMET R17 R17 K8 + 0x8C4C152C, // 009A GETMET R19 R10 K44 + 0x7C4C0200, // 009B CALL R19 1 + 0x004E5613, // 009C ADD R19 K43 R19 + 0x54520003, // 009D LDINT R20 4 + 0x7C440600, // 009E CALL R17 3 + 0xB8460E00, // 009F GETNGBL R17 K7 + 0x8C442308, // 00A0 GETMET R17 R17 K8 + 0x8C4C1B2C, // 00A1 GETMET R19 R13 K44 + 0x7C4C0200, // 00A2 CALL R19 1 + 0x004E5A13, // 00A3 ADD R19 K45 R19 + 0x54520003, // 00A4 LDINT R20 4 + 0x7C440600, // 00A5 CALL R17 3 + 0xB8460E00, // 00A6 GETNGBL R17 K7 + 0x8C442308, // 00A7 GETMET R17 R17 K8 + 0x8C4C1F2C, // 00A8 GETMET R19 R15 K44 + 0x7C4C0200, // 00A9 CALL R19 1 + 0x004E5C13, // 00AA ADD R19 K46 R19 + 0x54520003, // 00AB LDINT R20 4 + 0x7C440600, // 00AC CALL R17 3 + 0xB8460E00, // 00AD GETNGBL R17 K7 + 0x8C442308, // 00AE GETMET R17 R17 K8 + 0x8C4C212C, // 00AF GETMET R19 R16 K44 + 0x7C4C0200, // 00B0 CALL R19 1 + 0x004E5E13, // 00B1 ADD R19 K47 R19 + 0x54520003, // 00B2 LDINT R20 4 + 0x7C440600, // 00B3 CALL R17 3 + 0xB8460E00, // 00B4 GETNGBL R17 K7 + 0x8C442308, // 00B5 GETMET R17 R17 K8 + 0x584C002A, // 00B6 LDCONST R19 K42 + 0x54520003, // 00B7 LDINT R20 4 + 0x7C440600, // 00B8 CALL R17 3 + 0x1C441A10, // 00B9 EQ R17 R13 R16 + 0x784600E3, // 00BA JMPF R17 #019F + 0x88440F1E, // 00BB GETMBR R17 R7 K30 + 0x90123C11, // 00BC SETMBR R4 K30 R17 + 0x88440331, // 00BD GETMBR R17 R1 K49 + 0x90126011, // 00BE SETMBR R4 K48 R17 + 0x8C440932, // 00BF GETMET R17 R4 K50 + 0x7C440200, // 00C0 CALL R17 1 + 0x88440B34, // 00C1 GETMBR R17 R5 K52 + 0x90126611, // 00C2 SETMBR R4 K51 R17 + 0x8844011A, // 00C3 GETMBR R17 R0 K26 + 0x8844231B, // 00C4 GETMBR R17 R17 K27 + 0x8C442336, // 00C5 GETMET R17 R17 K54 + 0x7C440200, // 00C6 CALL R17 1 + 0x90126A11, // 00C7 SETMBR R4 K53 R17 + 0xB8460E00, // 00C8 GETNGBL R17 K7 + 0x8C442308, // 00C9 GETMET R17 R17 K8 + 0x8C4C0712, // 00CA GETMET R19 R3 K18 + 0x58540037, // 00CB LDCONST R21 K55 + 0x88580935, // 00CC GETMBR R22 R4 K53 + 0x885C0338, // 00CD GETMBR R23 R1 K56 + 0x88600339, // 00CE GETMBR R24 R1 K57 + 0x7C4C0A00, // 00CF CALL R19 5 + 0x5850000A, // 00D0 LDCONST R20 K10 + 0x7C440600, // 00D1 CALL R17 3 + 0x88440F24, // 00D2 GETMBR R17 R7 K36 + 0x90124811, // 00D3 SETMBR R4 K36 R17 + 0x8C44053B, // 00D4 GETMET R17 R2 K59 + 0x544E000F, // 00D5 LDINT R19 16 + 0x7C440400, // 00D6 CALL R17 2 + 0x90127411, // 00D7 SETMBR R4 K58 R17 + 0x60440015, // 00D8 GETGBL R17 G21 + 0x7C440000, // 00D9 CALL R17 0 + 0x8C442320, // 00DA GETMET R17 R17 K32 + 0x584C003C, // 00DB LDCONST R19 K60 + 0x7C440400, // 00DC CALL R17 2 + 0x88480B1F, // 00DD GETMBR R18 R5 K31 + 0x884C093A, // 00DE GETMBR R19 R4 K58 + 0x00482413, // 00DF ADD R18 R18 R19 + 0x8C4C0522, // 00E0 GETMET R19 R2 K34 + 0x7C4C0200, // 00E1 CALL R19 1 + 0x8C4C2723, // 00E2 GETMET R19 R19 K35 + 0x88540924, // 00E3 GETMBR R21 R4 K36 + 0x5C582400, // 00E4 MOVE R22 R18 + 0x5C5C2200, // 00E5 MOVE R23 R17 + 0x5462000F, // 00E6 LDINT R24 16 + 0x7C4C0A00, // 00E7 CALL R19 5 + 0x8C500527, // 00E8 GETMET R20 R2 K39 + 0x5C582600, // 00E9 MOVE R22 R19 + 0x605C0015, // 00EA GETGBL R23 G21 + 0x7C5C0000, // 00EB CALL R23 0 + 0x8C5C2F20, // 00EC GETMET R23 R23 K32 + 0x5864003D, // 00ED LDCONST R25 K61 + 0x7C5C0400, // 00EE CALL R23 2 + 0x60600015, // 00EF GETGBL R24 G21 + 0x7C600000, // 00F0 CALL R24 0 + 0x58640005, // 00F1 LDCONST R25 K5 + 0x546A000F, // 00F2 LDINT R26 16 + 0x7C500C00, // 00F3 CALL R20 6 + 0x8C542929, // 00F4 GETMET R21 R20 K41 + 0x7C540200, // 00F5 CALL R21 1 + 0xB85A1A00, // 00F6 GETNGBL R22 K13 + 0x8C582D3E, // 00F7 GETMET R22 R22 K62 + 0x7C580200, // 00F8 CALL R22 1 + 0x885C093A, // 00F9 GETMBR R23 R4 K58 + 0x905A2E17, // 00FA SETMBR R22 K23 R23 + 0x885C0935, // 00FB GETMBR R23 R4 K53 + 0x905A7E17, // 00FC SETMBR R22 K63 R23 + 0x905A8015, // 00FD SETMBR R22 K64 R21 + 0xB85E0E00, // 00FE GETNGBL R23 K7 + 0x8C5C2F08, // 00FF GETMET R23 R23 K8 + 0x5864002A, // 0100 LDCONST R25 K42 + 0x546A0003, // 0101 LDINT R26 4 + 0x7C5C0600, // 0102 CALL R23 3 + 0xB85E0E00, // 0103 GETNGBL R23 K7 + 0x8C5C2F08, // 0104 GETMET R23 R23 K8 + 0x8C64272C, // 0105 GETMET R25 R19 K44 + 0x7C640200, // 0106 CALL R25 1 + 0x00668219, // 0107 ADD R25 K65 R25 + 0x546A0003, // 0108 LDINT R26 4 + 0x7C5C0600, // 0109 CALL R23 3 + 0xB85E0E00, // 010A GETNGBL R23 K7 + 0x8C5C2F08, // 010B GETMET R23 R23 K8 + 0x8C64252C, // 010C GETMET R25 R18 K44 + 0x7C640200, // 010D CALL R25 1 + 0x00668419, // 010E ADD R25 K66 R25 + 0x546A0003, // 010F LDINT R26 4 + 0x7C5C0600, // 0110 CALL R23 3 + 0xB85E0E00, // 0111 GETNGBL R23 K7 + 0x8C5C2F08, // 0112 GETMET R23 R23 K8 + 0x8864093A, // 0113 GETMBR R25 R4 K58 + 0x8C64332C, // 0114 GETMET R25 R25 K44 + 0x7C640200, // 0115 CALL R25 1 + 0x00668619, // 0116 ADD R25 K67 R25 + 0x546A0003, // 0117 LDINT R26 4 + 0x7C5C0600, // 0118 CALL R23 3 + 0xB85E0E00, // 0119 GETNGBL R23 K7 + 0x8C5C2F08, // 011A GETMET R23 R23 K8 + 0x60640008, // 011B GETGBL R25 G8 + 0x88680935, // 011C GETMBR R26 R4 K53 + 0x7C640200, // 011D CALL R25 1 + 0x00668819, // 011E ADD R25 K68 R25 + 0x546A0003, // 011F LDINT R26 4 + 0x7C5C0600, // 0120 CALL R23 3 + 0xB85E0E00, // 0121 GETNGBL R23 K7 + 0x8C5C2F08, // 0122 GETMET R23 R23 K8 + 0x8C642B2C, // 0123 GETMET R25 R21 K44 + 0x7C640200, // 0124 CALL R25 1 + 0x00668A19, // 0125 ADD R25 K69 R25 + 0x546A0003, // 0126 LDINT R26 4 + 0x7C5C0600, // 0127 CALL R23 3 + 0xB85E0E00, // 0128 GETNGBL R23 K7 + 0x8C5C2F08, // 0129 GETMET R23 R23 K8 + 0x5864002A, // 012A LDCONST R25 K42 + 0x546A0003, // 012B LDINT R26 4 + 0x7C5C0600, // 012C CALL R23 3 + 0x8C5C0522, // 012D GETMET R23 R2 K34 + 0x7C5C0200, // 012E CALL R23 1 + 0x8C5C2F23, // 012F GETMET R23 R23 K35 + 0x88640924, // 0130 GETMBR R25 R4 K36 + 0x88680B1F, // 0131 GETMBR R26 R5 K31 + 0x886C093A, // 0132 GETMBR R27 R4 K58 + 0x0068341B, // 0133 ADD R26 R26 R27 + 0x606C0015, // 0134 GETGBL R27 G21 + 0x7C6C0000, // 0135 CALL R27 0 + 0x8C6C3720, // 0136 GETMET R27 R27 K32 + 0x58740046, // 0137 LDCONST R29 K70 + 0x7C6C0400, // 0138 CALL R27 2 + 0x5472002F, // 0139 LDINT R28 48 + 0x7C5C0A00, // 013A CALL R23 5 + 0x5462000E, // 013B LDINT R24 15 + 0x40620A18, // 013C CONNECT R24 K5 R24 + 0x94602E18, // 013D GETIDX R24 R23 R24 + 0x5466000F, // 013E LDINT R25 16 + 0x546A001E, // 013F LDINT R26 31 + 0x4064321A, // 0140 CONNECT R25 R25 R26 + 0x94642E19, // 0141 GETIDX R25 R23 R25 + 0x546A001F, // 0142 LDINT R26 32 + 0x546E002E, // 0143 LDINT R27 47 + 0x4068341B, // 0144 CONNECT R26 R26 R27 + 0x94682E1A, // 0145 GETIDX R26 R23 R26 + 0xB86E0E00, // 0146 GETNGBL R27 K7 + 0x8C6C3747, // 0147 GETMET R27 R27 K71 + 0x7C6C0200, // 0148 CALL R27 1 + 0x946C3748, // 0149 GETIDX R27 R27 K72 + 0xB8720E00, // 014A GETNGBL R28 K7 + 0x8C703908, // 014B GETMET R28 R28 K8 + 0x58780049, // 014C LDCONST R30 K73 + 0x547E0003, // 014D LDINT R31 4 + 0x7C700600, // 014E CALL R28 3 + 0xB8720E00, // 014F GETNGBL R28 K7 + 0x8C703908, // 0150 GETMET R28 R28 K8 + 0x8C78312C, // 0151 GETMET R30 R24 K44 + 0x7C780200, // 0152 CALL R30 1 + 0x007A941E, // 0153 ADD R30 K74 R30 + 0x547E0003, // 0154 LDINT R31 4 + 0x7C700600, // 0155 CALL R28 3 + 0xB8720E00, // 0156 GETNGBL R28 K7 + 0x8C703908, // 0157 GETMET R28 R28 K8 + 0x8C78332C, // 0158 GETMET R30 R25 K44 + 0x7C780200, // 0159 CALL R30 1 + 0x007A961E, // 015A ADD R30 K75 R30 + 0x547E0003, // 015B LDINT R31 4 + 0x7C700600, // 015C CALL R28 3 + 0xB8720E00, // 015D GETNGBL R28 K7 + 0x8C703908, // 015E GETMET R28 R28 K8 + 0x8C78352C, // 015F GETMET R30 R26 K44 + 0x7C780200, // 0160 CALL R30 1 + 0x007A981E, // 0161 ADD R30 K76 R30 + 0x547E0003, // 0162 LDINT R31 4 + 0x7C700600, // 0163 CALL R28 3 + 0xB8720E00, // 0164 GETNGBL R28 K7 + 0x8C703908, // 0165 GETMET R28 R28 K8 + 0x58780049, // 0166 LDCONST R30 K73 + 0x547E0003, // 0167 LDINT R31 4 + 0x7C700600, // 0168 CALL R28 3 + 0x8C702D4D, // 0169 GETMET R28 R22 K77 + 0x7C700200, // 016A CALL R28 1 + 0x4C740000, // 016B LDNIL R29 + 0x90129C1D, // 016C SETMBR R4 K78 R29 + 0xB8760E00, // 016D GETNGBL R29 K7 + 0x8C743B08, // 016E GETMET R29 R29 K8 + 0xB87E1A00, // 016F GETNGBL R31 K13 + 0x8C7C3F14, // 0170 GETMET R31 R31 K20 + 0x5C842C00, // 0171 MOVE R33 R22 + 0x7C7C0400, // 0172 CALL R31 2 + 0x007E9E1F, // 0173 ADD R31 K79 R31 + 0x54820003, // 0174 LDINT R32 4 + 0x7C740600, // 0175 CALL R29 3 + 0xB8760E00, // 0176 GETNGBL R29 K7 + 0x8C743B08, // 0177 GETMET R29 R29 K8 + 0x8C7C392C, // 0178 GETMET R31 R28 K44 + 0x7C7C0200, // 0179 CALL R31 1 + 0x007EA01F, // 017A ADD R31 K80 R31 + 0x54820003, // 017B LDINT R32 4 + 0x7C740600, // 017C CALL R29 3 + 0x8C740351, // 017D GETMET R29 R1 K81 + 0x547E0032, // 017E LDINT R31 51 + 0x50800200, // 017F LDBOOL R32 1 0 + 0x7C740600, // 0180 CALL R29 3 + 0x8C783B52, // 0181 GETMET R30 R29 K82 + 0x5C803800, // 0182 MOVE R32 R28 + 0x7C780400, // 0183 CALL R30 2 + 0x887C0153, // 0184 GETMBR R31 R0 K83 + 0x8C7C3F54, // 0185 GETMET R31 R31 K84 + 0x5C843A00, // 0186 MOVE R33 R29 + 0x7C7C0400, // 0187 CALL R31 2 + 0x8C7C0955, // 0188 GETMET R31 R4 K85 + 0x7C7C0200, // 0189 CALL R31 1 + 0x8C7C0956, // 018A GETMET R31 R4 K86 + 0x5C843000, // 018B MOVE R33 R24 + 0x5C883200, // 018C MOVE R34 R25 + 0x5C8C3400, // 018D MOVE R35 R26 + 0x5C903600, // 018E MOVE R36 R27 + 0x7C7C0A00, // 018F CALL R31 5 + 0x9012AF05, // 0190 SETMBR R4 K87 K5 + 0x8C7C0958, // 0191 GETMET R31 R4 K88 + 0x7C7C0200, // 0192 CALL R31 1 + 0x8C7C0959, // 0193 GETMET R31 R4 K89 + 0x50840200, // 0194 LDBOOL R33 1 0 + 0x7C7C0400, // 0195 CALL R31 2 + 0x8C7C095A, // 0196 GETMET R31 R4 K90 + 0x7C7C0200, // 0197 CALL R31 1 + 0x8C7C095B, // 0198 GETMET R31 R4 K91 + 0x7C7C0200, // 0199 CALL R31 1 + 0x8C7C095C, // 019A GETMET R31 R4 K92 + 0x7C7C0200, // 019B CALL R31 1 + 0x507C0200, // 019C LDBOOL R31 1 0 + 0x80043E00, // 019D RET 1 R31 + 0x70020000, // 019E JMP #01A0 + 0x50180000, // 019F LDBOOL R6 0 0 + 0x5C200C00, // 01A0 MOVE R8 R6 + 0x74220174, // 01A1 JMPT R8 #0317 + 0x8C20015D, // 01A2 GETMET R8 R0 K93 + 0x88280B5E, // 01A3 GETMBR R10 R5 K94 + 0x882C0B1F, // 01A4 GETMBR R11 R5 K31 + 0x7C200600, // 01A5 CALL R8 3 + 0x90123C08, // 01A6 SETMBR R4 K30 R8 + 0x4C240000, // 01A7 LDNIL R9 + 0x1C240809, // 01A8 EQ R9 R4 R9 + 0x74260003, // 01A9 JMPT R9 #01AE + 0x8824091E, // 01AA GETMBR R9 R4 K30 + 0x4C280000, // 01AB LDNIL R10 + 0x1C24120A, // 01AC EQ R9 R9 R10 + 0x7826000D, // 01AD JMPF R9 #01BC + 0xB8260E00, // 01AE GETNGBL R9 K7 + 0x8C241308, // 01AF GETMET R9 R9 K8 + 0x582C005F, // 01B0 LDCONST R11 K95 + 0x5830000A, // 01B1 LDCONST R12 K10 + 0x7C240600, // 01B2 CALL R9 3 + 0x8C24010B, // 01B3 GETMET R9 R0 K11 + 0x5C2C0200, // 01B4 MOVE R11 R1 + 0x5830000C, // 01B5 LDCONST R12 K12 + 0x58340005, // 01B6 LDCONST R13 K5 + 0x5838000C, // 01B7 LDCONST R14 K12 + 0x503C0000, // 01B8 LDBOOL R15 0 0 + 0x7C240C00, // 01B9 CALL R9 6 + 0x50280000, // 01BA LDBOOL R10 0 0 + 0x80041400, // 01BB RET 1 R10 + 0x88240331, // 01BC GETMBR R9 R1 K49 + 0x90126009, // 01BD SETMBR R4 K48 R9 + 0x8C240932, // 01BE GETMET R9 R4 K50 + 0x7C240200, // 01BF CALL R9 1 + 0x88240B34, // 01C0 GETMBR R9 R5 K52 + 0x90126609, // 01C1 SETMBR R4 K51 R9 + 0x8824011A, // 01C2 GETMBR R9 R0 K26 + 0x8824131B, // 01C3 GETMBR R9 R9 K27 + 0x8C241336, // 01C4 GETMET R9 R9 K54 + 0x7C240200, // 01C5 CALL R9 1 + 0x90126A09, // 01C6 SETMBR R4 K53 R9 + 0xB8260E00, // 01C7 GETNGBL R9 K7 + 0x8C241308, // 01C8 GETMET R9 R9 K8 + 0x8C2C0712, // 01C9 GETMET R11 R3 K18 + 0x58340037, // 01CA LDCONST R13 K55 + 0x88380935, // 01CB GETMBR R14 R4 K53 + 0x883C0338, // 01CC GETMBR R15 R1 K56 + 0x88400339, // 01CD GETMBR R16 R1 K57 + 0x7C2C0A00, // 01CE CALL R11 5 + 0x5830000A, // 01CF LDCONST R12 K10 + 0x7C240600, // 01D0 CALL R9 3 + 0xB8260E00, // 01D1 GETNGBL R9 K7 + 0x8C241308, // 01D2 GETMET R9 R9 K8 + 0xB82E1A00, // 01D3 GETNGBL R11 K13 + 0x8C2C1714, // 01D4 GETMET R11 R11 K20 + 0x8834091E, // 01D5 GETMBR R13 R4 K30 + 0x7C2C0400, // 01D6 CALL R11 2 + 0x002EC00B, // 01D7 ADD R11 K96 R11 + 0x54320003, // 01D8 LDINT R12 4 + 0x7C240600, // 01D9 CALL R9 3 + 0xB8260E00, // 01DA GETNGBL R9 K7 + 0x8C241308, // 01DB GETMET R9 R9 K8 + 0x882C091E, // 01DC GETMBR R11 R4 K30 + 0x882C1762, // 01DD GETMBR R11 R11 K98 + 0x8C2C172C, // 01DE GETMET R11 R11 K44 + 0x7C2C0200, // 01DF CALL R11 1 + 0x002EC20B, // 01E0 ADD R11 K97 R11 + 0x54320003, // 01E1 LDINT R12 4 + 0x7C240600, // 01E2 CALL R9 3 + 0xB8260E00, // 01E3 GETNGBL R9 K7 + 0x8C241308, // 01E4 GETMET R9 R9 K8 + 0x882C091E, // 01E5 GETMBR R11 R4 K30 + 0x882C1764, // 01E6 GETMBR R11 R11 K100 + 0x8C2C172C, // 01E7 GETMET R11 R11 K44 + 0x7C2C0200, // 01E8 CALL R11 1 + 0x002EC60B, // 01E9 ADD R11 K99 R11 + 0x54320003, // 01EA LDINT R12 4 + 0x7C240600, // 01EB CALL R9 3 + 0x8824091E, // 01EC GETMBR R9 R4 K30 + 0x8C241365, // 01ED GETMET R9 R9 K101 + 0x7C240200, // 01EE CALL R9 1 + 0x78260009, // 01EF JMPF R9 #01FA + 0xB8260E00, // 01F0 GETNGBL R9 K7 + 0x8C241308, // 01F1 GETMET R9 R9 K8 + 0x882C091E, // 01F2 GETMBR R11 R4 K30 + 0x8C2C1765, // 01F3 GETMET R11 R11 K101 + 0x7C2C0200, // 01F4 CALL R11 1 + 0x8C2C172C, // 01F5 GETMET R11 R11 K44 + 0x7C2C0200, // 01F6 CALL R11 1 + 0x002ECC0B, // 01F7 ADD R11 K102 R11 + 0x54320003, // 01F8 LDINT R12 4 + 0x7C240600, // 01F9 CALL R9 3 + 0xB8260E00, // 01FA GETNGBL R9 K7 + 0x8C241308, // 01FB GETMET R9 R9 K8 + 0x882C091E, // 01FC GETMBR R11 R4 K30 + 0x882C1768, // 01FD GETMBR R11 R11 K104 + 0x8C2C172C, // 01FE GETMET R11 R11 K44 + 0x7C2C0200, // 01FF CALL R11 1 + 0x002ECE0B, // 0200 ADD R11 K103 R11 + 0x54320003, // 0201 LDINT R12 4 + 0x7C240600, // 0202 CALL R9 3 + 0x8C24053B, // 0203 GETMET R9 R2 K59 + 0x542E000F, // 0204 LDINT R11 16 + 0x7C240400, // 0205 CALL R9 2 + 0x90127409, // 0206 SETMBR R4 K58 R9 + 0x8C24053B, // 0207 GETMET R9 R2 K59 + 0x542E001F, // 0208 LDINT R11 32 + 0x7C240400, // 0209 CALL R9 2 + 0x9012D209, // 020A SETMBR R4 K105 R9 + 0x8C24056B, // 020B GETMET R9 R2 K107 + 0x7C240200, // 020C CALL R9 1 + 0x8C24136C, // 020D GETMET R9 R9 K108 + 0x882C0969, // 020E GETMBR R11 R4 K105 + 0x7C240400, // 020F CALL R9 2 + 0x9012D409, // 0210 SETMBR R4 K106 R9 + 0xB8260E00, // 0211 GETNGBL R9 K7 + 0x8C241308, // 0212 GETMET R9 R9 K8 + 0x882C0969, // 0213 GETMBR R11 R4 K105 + 0x8C2C172C, // 0214 GETMET R11 R11 K44 + 0x7C2C0200, // 0215 CALL R11 1 + 0x002EDA0B, // 0216 ADD R11 K109 R11 + 0x54320003, // 0217 LDINT R12 4 + 0x7C240600, // 0218 CALL R9 3 + 0xB8260E00, // 0219 GETNGBL R9 K7 + 0x8C241308, // 021A GETMET R9 R9 K8 + 0x882C096A, // 021B GETMBR R11 R4 K106 + 0x8C2C172C, // 021C GETMET R11 R11 K44 + 0x7C2C0200, // 021D CALL R11 1 + 0x002EDC0B, // 021E ADD R11 K110 R11 + 0x54320003, // 021F LDINT R12 4 + 0x7C240600, // 0220 CALL R9 3 + 0x8C24053B, // 0221 GETMET R9 R2 K59 + 0x542E001F, // 0222 LDINT R11 32 + 0x7C240400, // 0223 CALL R9 2 + 0x8C28056B, // 0224 GETMET R10 R2 K107 + 0x7C280200, // 0225 CALL R10 1 + 0x8C28156F, // 0226 GETMET R10 R10 K111 + 0x88300969, // 0227 GETMBR R12 R4 K105 + 0x88340B16, // 0228 GETMBR R13 R5 K22 + 0x7C280600, // 0229 CALL R10 3 + 0x9012480A, // 022A SETMBR R4 K36 R10 + 0xB82A1A00, // 022B GETNGBL R10 K13 + 0x88281570, // 022C GETMBR R10 R10 K112 + 0x8C281571, // 022D GETMET R10 R10 K113 + 0x7C280200, // 022E CALL R10 1 + 0x8C2C1572, // 022F GETMET R11 R10 K114 + 0x5834000C, // 0230 LDCONST R13 K12 + 0xB83A1A00, // 0231 GETNGBL R14 K13 + 0x88381D70, // 0232 GETMBR R14 R14 K112 + 0x88381D73, // 0233 GETMBR R14 R14 K115 + 0x8C3C0974, // 0234 GETMET R15 R4 K116 + 0x7C3C0200, // 0235 CALL R15 1 + 0x7C2C0800, // 0236 CALL R11 4 + 0x8C2C1572, // 0237 GETMET R11 R10 K114 + 0x5834000A, // 0238 LDCONST R13 K10 + 0xB83A1A00, // 0239 GETNGBL R14 K13 + 0x88381D70, // 023A GETMBR R14 R14 K112 + 0x88381D73, // 023B GETMBR R14 R14 K115 + 0x8C3C0965, // 023C GETMET R15 R4 K101 + 0x7C3C0200, // 023D CALL R15 1 + 0x7C2C0800, // 023E CALL R11 4 + 0x8C2C1572, // 023F GETMET R11 R10 K114 + 0x58340075, // 0240 LDCONST R13 K117 + 0xB83A1A00, // 0241 GETNGBL R14 K13 + 0x88381D70, // 0242 GETMBR R14 R14 K112 + 0x88381D73, // 0243 GETMBR R14 R14 K115 + 0x883C096A, // 0244 GETMBR R15 R4 K106 + 0x7C2C0800, // 0245 CALL R11 4 + 0x8C2C1572, // 0246 GETMET R11 R10 K114 + 0x54360003, // 0247 LDINT R13 4 + 0xB83A1A00, // 0248 GETNGBL R14 K13 + 0x88381D70, // 0249 GETMBR R14 R14 K112 + 0x88381D73, // 024A GETMBR R14 R14 K115 + 0x883C0B16, // 024B GETMBR R15 R5 K22 + 0x7C2C0800, // 024C CALL R11 4 + 0x8C2C056B, // 024D GETMET R11 R2 K107 + 0x7C2C0200, // 024E CALL R11 1 + 0x8C2C1776, // 024F GETMET R11 R11 K118 + 0x8C340977, // 0250 GETMET R13 R4 K119 + 0x7C340200, // 0251 CALL R13 1 + 0x8C38154D, // 0252 GETMET R14 R10 K77 + 0x7C380200, // 0253 CALL R14 1 + 0x7C2C0600, // 0254 CALL R11 3 + 0xB8321A00, // 0255 GETNGBL R12 K13 + 0x88301970, // 0256 GETMBR R12 R12 K112 + 0x8C301971, // 0257 GETMET R12 R12 K113 + 0x7C300200, // 0258 CALL R12 1 + 0x8C341972, // 0259 GETMET R13 R12 K114 + 0x583C000C, // 025A LDCONST R15 K12 + 0xB8421A00, // 025B GETNGBL R16 K13 + 0x88402170, // 025C GETMBR R16 R16 K112 + 0x88402173, // 025D GETMBR R16 R16 K115 + 0x8C440974, // 025E GETMET R17 R4 K116 + 0x7C440200, // 025F CALL R17 1 + 0x7C340800, // 0260 CALL R13 4 + 0x8C341972, // 0261 GETMET R13 R12 K114 + 0x583C000A, // 0262 LDCONST R15 K10 + 0xB8421A00, // 0263 GETNGBL R16 K13 + 0x88402170, // 0264 GETMBR R16 R16 K112 + 0x88402173, // 0265 GETMBR R16 R16 K115 + 0x8C440965, // 0266 GETMET R17 R4 K101 + 0x7C440200, // 0267 CALL R17 1 + 0x7C340800, // 0268 CALL R13 4 + 0x8C341972, // 0269 GETMET R13 R12 K114 + 0x583C0075, // 026A LDCONST R15 K117 + 0xB8421A00, // 026B GETNGBL R16 K13 + 0x88402170, // 026C GETMBR R16 R16 K112 + 0x88402173, // 026D GETMBR R16 R16 K115 + 0x5C441600, // 026E MOVE R17 R11 + 0x7C340800, // 026F CALL R13 4 + 0x8C341972, // 0270 GETMET R13 R12 K114 + 0x543E0003, // 0271 LDINT R15 4 + 0xB8421A00, // 0272 GETNGBL R16 K13 + 0x88402170, // 0273 GETMBR R16 R16 K112 + 0x88402173, // 0274 GETMBR R16 R16 K115 + 0x8844093A, // 0275 GETMBR R17 R4 K58 + 0x7C340800, // 0276 CALL R13 4 + 0xB8360E00, // 0277 GETNGBL R13 K7 + 0x8C341B08, // 0278 GETMET R13 R13 K8 + 0x583C002A, // 0279 LDCONST R15 K42 + 0x54420003, // 027A LDINT R16 4 + 0x7C340600, // 027B CALL R13 3 + 0x88340B78, // 027C GETMBR R13 R5 K120 + 0x90129C0D, // 027D SETMBR R4 K78 R13 + 0xB8360E00, // 027E GETNGBL R13 K7 + 0x8C341B08, // 027F GETMET R13 R13 K8 + 0x883C093A, // 0280 GETMBR R15 R4 K58 + 0x8C3C1F2C, // 0281 GETMET R15 R15 K44 + 0x7C3C0200, // 0282 CALL R15 1 + 0x003EF20F, // 0283 ADD R15 K121 R15 + 0x54420003, // 0284 LDINT R16 4 + 0x7C340600, // 0285 CALL R13 3 + 0xB8360E00, // 0286 GETNGBL R13 K7 + 0x8C341B08, // 0287 GETMET R13 R13 K8 + 0x883C094E, // 0288 GETMBR R15 R4 K78 + 0x8C3C1F2C, // 0289 GETMET R15 R15 K44 + 0x7C3C0200, // 028A CALL R15 1 + 0x003EF40F, // 028B ADD R15 K122 R15 + 0x54420003, // 028C LDINT R16 4 + 0x7C340600, // 028D CALL R13 3 + 0x8C34057B, // 028E GETMET R13 R2 K123 + 0x7C340200, // 028F CALL R13 1 + 0x8C341B7C, // 0290 GETMET R13 R13 K124 + 0x883C094E, // 0291 GETMBR R15 R4 K78 + 0x7C340400, // 0292 CALL R13 2 + 0x8C341B7D, // 0293 GETMET R13 R13 K125 + 0x7C340200, // 0294 CALL R13 1 + 0xB83A0E00, // 0295 GETNGBL R14 K7 + 0x8C381D08, // 0296 GETMET R14 R14 K8 + 0x8C401B2C, // 0297 GETMET R16 R13 K44 + 0x7C400200, // 0298 CALL R16 1 + 0x0042FC10, // 0299 ADD R16 K126 R16 + 0x54460003, // 029A LDINT R17 4 + 0x7C380600, // 029B CALL R14 3 + 0x60380015, // 029C GETGBL R14 G21 + 0x7C380000, // 029D CALL R14 0 + 0x8C381D20, // 029E GETMET R14 R14 K32 + 0x8840017F, // 029F GETMBR R16 R0 K127 + 0x7C380400, // 02A0 CALL R14 2 + 0x8C3C0980, // 02A1 GETMET R15 R4 K128 + 0x7C3C0200, // 02A2 CALL R15 1 + 0x003C1E09, // 02A3 ADD R15 R15 R9 + 0x8840096A, // 02A4 GETMBR R16 R4 K106 + 0x003C1E10, // 02A5 ADD R15 R15 R16 + 0x003C1E0D, // 02A6 ADD R15 R15 R13 + 0x8C400522, // 02A7 GETMET R16 R2 K34 + 0x7C400200, // 02A8 CALL R16 1 + 0x8C402123, // 02A9 GETMET R16 R16 K35 + 0x88480924, // 02AA GETMBR R18 R4 K36 + 0x5C4C1E00, // 02AB MOVE R19 R15 + 0x5C501C00, // 02AC MOVE R20 R14 + 0x5456000F, // 02AD LDINT R21 16 + 0x7C400A00, // 02AE CALL R16 5 + 0xB8460E00, // 02AF GETNGBL R17 K7 + 0x8C442308, // 02B0 GETMET R17 R17 K8 + 0x884C0924, // 02B1 GETMBR R19 R4 K36 + 0x8C4C272C, // 02B2 GETMET R19 R19 K44 + 0x7C4C0200, // 02B3 CALL R19 1 + 0x004F0213, // 02B4 ADD R19 K129 R19 + 0x54520003, // 02B5 LDINT R20 4 + 0x7C440600, // 02B6 CALL R17 3 + 0xB8460E00, // 02B7 GETNGBL R17 K7 + 0x8C442308, // 02B8 GETMET R17 R17 K8 + 0x8C4C1F2C, // 02B9 GETMET R19 R15 K44 + 0x7C4C0200, // 02BA CALL R19 1 + 0x004F0413, // 02BB ADD R19 K130 R19 + 0x54520003, // 02BC LDINT R20 4 + 0x7C440600, // 02BD CALL R17 3 + 0xB8460E00, // 02BE GETNGBL R17 K7 + 0x8C442308, // 02BF GETMET R17 R17 K8 + 0x8C4C212C, // 02C0 GETMET R19 R16 K44 + 0x7C4C0200, // 02C1 CALL R19 1 + 0x004F0613, // 02C2 ADD R19 K131 R19 + 0x54520003, // 02C3 LDINT R20 4 + 0x7C440600, // 02C4 CALL R17 3 + 0x8C44194D, // 02C5 GETMET R17 R12 K77 + 0x7C440200, // 02C6 CALL R17 1 + 0xB84A0E00, // 02C7 GETNGBL R18 K7 + 0x8C482508, // 02C8 GETMET R18 R18 K8 + 0x8C50232C, // 02C9 GETMET R20 R17 K44 + 0x7C500200, // 02CA CALL R20 1 + 0x00530814, // 02CB ADD R20 K132 R20 + 0x54560003, // 02CC LDINT R21 4 + 0x7C480600, // 02CD CALL R18 3 + 0x8C480527, // 02CE GETMET R18 R2 K39 + 0x5C502000, // 02CF MOVE R20 R16 + 0x60540015, // 02D0 GETGBL R21 G21 + 0x7C540000, // 02D1 CALL R21 0 + 0x8C542B20, // 02D2 GETMET R21 R21 K32 + 0x885C0185, // 02D3 GETMBR R23 R0 K133 + 0x7C540400, // 02D4 CALL R21 2 + 0x60580015, // 02D5 GETGBL R22 G21 + 0x7C580000, // 02D6 CALL R22 0 + 0x605C000C, // 02D7 GETGBL R23 G12 + 0x5C602200, // 02D8 MOVE R24 R17 + 0x7C5C0200, // 02D9 CALL R23 1 + 0x5462000F, // 02DA LDINT R24 16 + 0x7C480C00, // 02DB CALL R18 6 + 0x8C4C2586, // 02DC GETMET R19 R18 K134 + 0x5C542200, // 02DD MOVE R21 R17 + 0x7C4C0400, // 02DE CALL R19 2 + 0x8C502529, // 02DF GETMET R20 R18 K41 + 0x7C500200, // 02E0 CALL R20 1 + 0x004C2614, // 02E1 ADD R19 R19 R20 + 0xB8520E00, // 02E2 GETNGBL R20 K7 + 0x8C502908, // 02E3 GETMET R20 R20 K8 + 0x8C58272C, // 02E4 GETMET R22 R19 K44 + 0x7C580200, // 02E5 CALL R22 1 + 0x005B0E16, // 02E6 ADD R22 K135 R22 + 0x545E0003, // 02E7 LDINT R23 4 + 0x7C500600, // 02E8 CALL R20 3 + 0xB8520E00, // 02E9 GETNGBL R20 K7 + 0x8C502908, // 02EA GETMET R20 R20 K8 + 0x5858002A, // 02EB LDCONST R22 K42 + 0x545E0003, // 02EC LDINT R23 4 + 0x7C500600, // 02ED CALL R20 3 + 0xB8521A00, // 02EE GETNGBL R20 K13 + 0x8C502988, // 02EF GETMET R20 R20 K136 + 0x7C500200, // 02F0 CALL R20 1 + 0x90531209, // 02F1 SETMBR R20 K137 R9 + 0x88540935, // 02F2 GETMBR R21 R4 K53 + 0x90531415, // 02F3 SETMBR R20 K138 R21 + 0x8854096A, // 02F4 GETMBR R21 R4 K106 + 0x90531615, // 02F5 SETMBR R20 K139 R21 + 0x90531813, // 02F6 SETMBR R20 K140 R19 + 0xB8560E00, // 02F7 GETNGBL R21 K7 + 0x8C542B08, // 02F8 GETMET R21 R21 K8 + 0xB85E1A00, // 02F9 GETNGBL R23 K13 + 0x8C5C2F14, // 02FA GETMET R23 R23 K20 + 0x5C642800, // 02FB MOVE R25 R20 + 0x7C5C0400, // 02FC CALL R23 2 + 0x005F1A17, // 02FD ADD R23 K141 R23 + 0x54620003, // 02FE LDINT R24 4 + 0x7C540600, // 02FF CALL R21 3 + 0x8C54294D, // 0300 GETMET R21 R20 K77 + 0x7C540200, // 0301 CALL R21 1 + 0x90131C15, // 0302 SETMBR R4 K142 R21 + 0xB85A0E00, // 0303 GETNGBL R22 K7 + 0x8C582D08, // 0304 GETMET R22 R22 K8 + 0x8C602B2C, // 0305 GETMET R24 R21 K44 + 0x7C600200, // 0306 CALL R24 1 + 0x00631E18, // 0307 ADD R24 K143 R24 + 0x54660003, // 0308 LDINT R25 4 + 0x7C580600, // 0309 CALL R22 3 + 0x8C580351, // 030A GETMET R22 R1 K81 + 0x54620030, // 030B LDINT R24 49 + 0x50640200, // 030C LDBOOL R25 1 0 + 0x7C580600, // 030D CALL R22 3 + 0x8C5C2D52, // 030E GETMET R23 R22 K82 + 0x5C642A00, // 030F MOVE R25 R21 + 0x7C5C0400, // 0310 CALL R23 2 + 0x88600153, // 0311 GETMBR R24 R0 K83 + 0x8C603154, // 0312 GETMET R24 R24 K84 + 0x5C682C00, // 0313 MOVE R26 R22 + 0x7C600400, // 0314 CALL R24 2 + 0x50600200, // 0315 LDBOOL R24 1 0 + 0x80043000, // 0316 RET 1 R24 + 0x50200200, // 0317 LDBOOL R8 1 0 + 0x80041000, // 0318 RET 1 R8 }) ) ); @@ -2390,46 +2684,30 @@ be_local_closure(Matter_Commisioning_Context_process_incoming, /* name */ ** Solidified class: Matter_Commisioning_Context ********************************************************************/ be_local_class(Matter_Commisioning_Context, - 21, + 2, NULL, - be_nested_map(36, + be_nested_map(20, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(parse_PBKDFParamRequest, -1), be_const_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest_closure) }, - { be_const_key_weak(cA, 32), be_const_var(10) }, - { be_const_key_weak(PBKDFParamRequest, -1), be_const_var(5) }, - { be_const_key_weak(parse_Pake3, 20), be_const_closure(Matter_Commisioning_Context_parse_Pake3_closure) }, - { be_const_key_weak(cB, -1), be_const_var(11) }, - { be_const_key_weak(spake, -1), be_const_var(2) }, - { be_const_key_weak(find_session_by_destination_id, 2), be_const_closure(Matter_Commisioning_Context_find_session_by_destination_id_closure) }, - { be_const_key_weak(R2IKey, -1), be_const_var(18) }, - { be_const_key_weak(Ke, -1), be_const_var(12) }, - { be_const_key_weak(parse_Sigma1, -1), be_const_closure(Matter_Commisioning_Context_parse_Sigma1_closure) }, - { be_const_key_weak(SEKeys_Info, -1), be_nested_str_weak(SessionKeys) }, - { be_const_key_weak(I2RKey, -1), be_const_var(17) }, - { be_const_key_weak(ResponderEph_priv, -1), be_const_var(13) }, - { be_const_key_weak(parse_Pake1, -1), be_const_closure(Matter_Commisioning_Context_parse_Pake1_closure) }, - { be_const_key_weak(AttestationChallenge, -1), be_const_var(19) }, - { be_const_key_weak(init, 3), be_const_closure(Matter_Commisioning_Context_init_closure) }, - { be_const_key_weak(ResponderEph_pub, 6), be_const_var(14) }, - { be_const_key_weak(initiatorEph_pub, -1), be_const_var(15) }, - { be_const_key_weak(window_open, -1), be_const_var(20) }, - { be_const_key_weak(session_timestamp, 26), be_const_var(16) }, - { be_const_key_weak(future_local_session_id, 34), be_const_var(4) }, - { be_const_key_weak(Matter_Context_Prefix, 27), be_nested_str_weak(CHIP_X20PAKE_X20V1_X20Commissioning) }, - { be_const_key_weak(pA, 30), be_const_var(8) }, - { be_const_key_weak(pB, -1), be_const_var(9) }, - { be_const_key_weak(TBEData2_Nonce, -1), be_nested_str_weak(NCASE_Sigma2N) }, - { be_const_key_weak(future_initiator_session_id, -1), be_const_var(3) }, - { be_const_key_weak(PBKDFParamResponse, -1), be_const_var(6) }, { be_const_key_weak(every_second, -1), be_const_closure(Matter_Commisioning_Context_every_second_closure) }, - { be_const_key_weak(y, 19), be_const_var(7) }, - { be_const_key_weak(parse_Sigma3, 8), be_const_closure(Matter_Commisioning_Context_parse_Sigma3_closure) }, + { be_const_key_weak(parse_StatusReport, -1), be_const_closure(Matter_Commisioning_Context_parse_StatusReport_closure) }, { be_const_key_weak(S2K_Info, -1), be_nested_str_weak(Sigma2) }, - { be_const_key_weak(TBEData3_Nonce, 9), be_nested_str_weak(NCASE_Sigma3N) }, - { be_const_key_weak(responder, -1), be_const_var(0) }, - { be_const_key_weak(S3K_Info, -1), be_nested_str_weak(Sigma3) }, + { be_const_key_weak(find_fabric_by_destination_id, -1), be_const_closure(Matter_Commisioning_Context_find_fabric_by_destination_id_closure) }, + { be_const_key_weak(process_incoming, 18), be_const_closure(Matter_Commisioning_Context_process_incoming_closure) }, + { be_const_key_weak(Matter_Context_Prefix, 0), be_nested_str_weak(CHIP_X20PAKE_X20V1_X20Commissioning) }, + { be_const_key_weak(SEKeys_Info, -1), be_nested_str_weak(SessionKeys) }, + { be_const_key_weak(TBEData3_Nonce, 4), be_nested_str_weak(NCASE_Sigma3N) }, + { be_const_key_weak(parse_PBKDFParamRequest, -1), be_const_closure(Matter_Commisioning_Context_parse_PBKDFParamRequest_closure) }, + { be_const_key_weak(send_status_report, -1), be_const_closure(Matter_Commisioning_Context_send_status_report_closure) }, + { be_const_key_weak(parse_Sigma3, -1), be_const_closure(Matter_Commisioning_Context_parse_Sigma3_closure) }, { be_const_key_weak(device, -1), be_const_var(1) }, - { be_const_key_weak(process_incoming, -1), be_const_closure(Matter_Commisioning_Context_process_incoming_closure) }, + { be_const_key_weak(TBEData2_Nonce, -1), be_nested_str_weak(NCASE_Sigma2N) }, + { be_const_key_weak(responder, 16), be_const_var(0) }, + { be_const_key_weak(parse_Pake3, -1), be_const_closure(Matter_Commisioning_Context_parse_Pake3_closure) }, + { be_const_key_weak(init, 14), be_const_closure(Matter_Commisioning_Context_init_closure) }, + { be_const_key_weak(parse_Pake1, -1), be_const_closure(Matter_Commisioning_Context_parse_Pake1_closure) }, + { be_const_key_weak(S3K_Info, 10), be_nested_str_weak(Sigma3) }, + { be_const_key_weak(add_session, -1), be_const_closure(Matter_Commisioning_Context_add_session_closure) }, + { be_const_key_weak(parse_Sigma1, -1), be_const_closure(Matter_Commisioning_Context_parse_Sigma1_closure) }, })), be_str_weak(Matter_Commisioning_Context) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h index 2c2bb647a..ff4c9ef5b 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Commissioning_Data.h @@ -116,9 +116,9 @@ void be_load_Matter_PBKDFParamRequest_class(bvm *vm) { extern const bclass be_class_Matter_PBKDFParamResponse; /******************************************************************** -** Solidified function: encode +** Solidified function: tlv2raw ********************************************************************/ -be_local_closure(Matter_PBKDFParamResponse_encode, /* name */ +be_local_closure(Matter_PBKDFParamResponse_tlv2raw, /* name */ be_nested_proto( 10, /* nstack */ 2, /* argc */ @@ -147,11 +147,11 @@ be_local_closure(Matter_PBKDFParamResponse_encode, /* name */ /* K15 */ be_nested_str_weak(pbkdf_parameters_salt), /* K16 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), /* K17 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), - /* K18 */ be_nested_str_weak(encode), + /* K18 */ be_nested_str_weak(tlv2raw), }), - be_str_weak(encode), + be_str_weak(tlv2raw), &be_const_str_solidified, - ( &(const binstruction[70]) { /* code */ + ( &(const binstruction[71]) { /* code */ 0xB80A0000, // 0000 GETNGBL R2 K0 0x88080501, // 0001 GETMBR R2 R2 K1 0x8C080502, // 0002 GETMET R2 R2 K2 @@ -220,8 +220,9 @@ be_local_closure(Matter_PBKDFParamResponse_encode, /* name */ 0x88240111, // 0041 GETMBR R9 R0 K17 0x7C140800, // 0042 CALL R5 4 0x8C100512, // 0043 GETMET R4 R2 K18 - 0x7C100200, // 0044 CALL R4 1 - 0x80040800, // 0045 RET 1 R4 + 0x5C180200, // 0044 MOVE R6 R1 + 0x7C100400, // 0045 CALL R4 2 + 0x80040800, // 0046 RET 1 R4 }) ) ); @@ -237,13 +238,13 @@ be_local_class(Matter_PBKDFParamResponse, be_nested_map(8, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(pbkdf_parameters_salt, -1), be_const_var(4) }, - { be_const_key_weak(SLEEPY_IDLE_INTERVAL, -1), be_const_var(5) }, - { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 1), be_const_var(6) }, - { be_const_key_weak(responderRandom, -1), be_const_var(1) }, + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(6) }, + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, 1), be_const_var(5) }, + { be_const_key_weak(responderSessionId, -1), be_const_var(2) }, { be_const_key_weak(pbkdf_parameters_iterations, -1), be_const_var(3) }, - { be_const_key_weak(initiatorRandom, -1), be_const_var(0) }, - { be_const_key_weak(responderSessionId, 3), be_const_var(2) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_PBKDFParamResponse_encode_closure) }, + { be_const_key_weak(initiatorRandom, 7), be_const_var(0) }, + { be_const_key_weak(responderRandom, 3), be_const_var(1) }, + { be_const_key_weak(tlv2raw, -1), be_const_closure(Matter_PBKDFParamResponse_tlv2raw_closure) }, })), be_str_weak(Matter_PBKDFParamResponse) ); @@ -270,7 +271,7 @@ be_local_closure(Matter_Pake1_parse, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ + ( &(const bvalue[10]) { /* constants */ /* K0 */ be_const_int(0), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TLV), @@ -278,10 +279,9 @@ be_local_closure(Matter_Pake1_parse, /* name */ /* K4 */ be_nested_str_weak(tasmota), /* K5 */ be_nested_str_weak(log), /* K6 */ be_nested_str_weak(MTR_X3A_X20parsed_X20TLV_X3A_X20), - /* K7 */ be_const_int(3), - /* K8 */ be_nested_str_weak(pA), - /* K9 */ be_nested_str_weak(getsubval), - /* K10 */ be_const_int(1), + /* K7 */ be_nested_str_weak(pA), + /* K8 */ be_nested_str_weak(getsubval), + /* K9 */ be_const_int(1), }), be_str_weak(parse), &be_const_str_solidified, @@ -302,12 +302,12 @@ be_local_closure(Matter_Pake1_parse, /* name */ 0x5C1C0600, // 000D MOVE R7 R3 0x7C180200, // 000E CALL R6 1 0x001A0C06, // 000F ADD R6 K6 R6 - 0x581C0007, // 0010 LDCONST R7 K7 + 0x541E0003, // 0010 LDINT R7 4 0x7C100600, // 0011 CALL R4 3 - 0x8C100709, // 0012 GETMET R4 R3 K9 - 0x5818000A, // 0013 LDCONST R6 K10 + 0x8C100708, // 0012 GETMET R4 R3 K8 + 0x58180009, // 0013 LDCONST R6 K9 0x7C100400, // 0014 CALL R4 2 - 0x90021004, // 0015 SETMBR R0 K8 R4 + 0x90020E04, // 0015 SETMBR R0 K7 R4 0x80040000, // 0016 RET 1 R0 }) ) @@ -339,9 +339,9 @@ void be_load_Matter_Pake1_class(bvm *vm) { extern const bclass be_class_Matter_Pake2; /******************************************************************** -** Solidified function: encode +** Solidified function: tlv2raw ********************************************************************/ -be_local_closure(Matter_Pake2_encode, /* name */ +be_local_closure(Matter_Pake2_tlv2raw, /* name */ be_nested_proto( 8, /* nstack */ 2, /* argc */ @@ -361,11 +361,11 @@ be_local_closure(Matter_Pake2_encode, /* name */ /* K6 */ be_nested_str_weak(pB), /* K7 */ be_const_int(2), /* K8 */ be_nested_str_weak(cB), - /* K9 */ be_nested_str_weak(encode), + /* K9 */ be_nested_str_weak(tlv2raw), }), - be_str_weak(encode), + be_str_weak(tlv2raw), &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ + ( &(const binstruction[22]) { /* code */ 0xB80A0000, // 0000 GETNGBL R2 K0 0x88080501, // 0001 GETMBR R2 R2 K1 0x8C080502, // 0002 GETMET R2 R2 K2 @@ -385,8 +385,9 @@ be_local_closure(Matter_Pake2_encode, /* name */ 0x881C0108, // 0010 GETMBR R7 R0 K8 0x7C0C0800, // 0011 CALL R3 4 0x8C0C0509, // 0012 GETMET R3 R2 K9 - 0x7C0C0200, // 0013 CALL R3 1 - 0x80040600, // 0014 RET 1 R3 + 0x5C140200, // 0013 MOVE R5 R1 + 0x7C0C0400, // 0014 CALL R3 2 + 0x80040600, // 0015 RET 1 R3 }) ) ); @@ -401,7 +402,7 @@ be_local_class(Matter_Pake2, NULL, be_nested_map(3, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(encode, -1), be_const_closure(Matter_Pake2_encode_closure) }, + { be_const_key_weak(tlv2raw, -1), be_const_closure(Matter_Pake2_tlv2raw_closure) }, { be_const_key_weak(cB, -1), be_const_var(1) }, { be_const_key_weak(pB, 0), be_const_var(0) }, })), @@ -430,7 +431,7 @@ be_local_closure(Matter_Pake3_parse, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ + ( &(const bvalue[10]) { /* constants */ /* K0 */ be_const_int(0), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TLV), @@ -438,10 +439,9 @@ be_local_closure(Matter_Pake3_parse, /* name */ /* K4 */ be_nested_str_weak(tasmota), /* K5 */ be_nested_str_weak(log), /* K6 */ be_nested_str_weak(MTR_X3A_X20parsed_X20TLV_X3A_X20), - /* K7 */ be_const_int(3), - /* K8 */ be_nested_str_weak(cA), - /* K9 */ be_nested_str_weak(getsubval), - /* K10 */ be_const_int(1), + /* K7 */ be_nested_str_weak(cA), + /* K8 */ be_nested_str_weak(getsubval), + /* K9 */ be_const_int(1), }), be_str_weak(parse), &be_const_str_solidified, @@ -462,12 +462,12 @@ be_local_closure(Matter_Pake3_parse, /* name */ 0x5C1C0600, // 000D MOVE R7 R3 0x7C180200, // 000E CALL R6 1 0x001A0C06, // 000F ADD R6 K6 R6 - 0x581C0007, // 0010 LDCONST R7 K7 + 0x541E0003, // 0010 LDINT R7 4 0x7C100600, // 0011 CALL R4 3 - 0x8C100709, // 0012 GETMET R4 R3 K9 - 0x5818000A, // 0013 LDCONST R6 K10 + 0x8C100708, // 0012 GETMET R4 R3 K8 + 0x58180009, // 0013 LDCONST R6 K9 0x7C100400, // 0014 CALL R4 2 - 0x90021004, // 0015 SETMBR R0 K8 R4 + 0x90020E04, // 0015 SETMBR R0 K7 R4 0x80040000, // 0016 RET 1 R0 }) ) @@ -503,7 +503,7 @@ extern const bclass be_class_Matter_Sigma1; ********************************************************************/ be_local_closure(Matter_Sigma1_parse, /* name */ be_nested_proto( - 9, /* nstack */ + 8, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -511,7 +511,7 @@ be_local_closure(Matter_Sigma1_parse, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[21]) { /* constants */ + ( &(const bvalue[23]) { /* constants */ /* K0 */ be_const_int(0), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TLV), @@ -521,22 +521,24 @@ be_local_closure(Matter_Sigma1_parse, /* name */ /* K6 */ be_nested_str_weak(tasmota), /* K7 */ be_nested_str_weak(log), /* K8 */ be_nested_str_weak(MTR_X3A_X20Sigma1_X20TLV_X3D), - /* K9 */ be_const_int(3), - /* K10 */ be_nested_str_weak(initiatorRandom), - /* K11 */ be_nested_str_weak(getsubval), - /* K12 */ be_const_int(1), - /* K13 */ be_nested_str_weak(initiator_session_id), - /* K14 */ be_const_int(2), - /* K15 */ be_nested_str_weak(destinationId), + /* K9 */ be_nested_str_weak(initiatorRandom), + /* K10 */ be_nested_str_weak(getsubval), + /* K11 */ be_const_int(1), + /* K12 */ be_nested_str_weak(initiator_session_id), + /* K13 */ be_const_int(2), + /* K14 */ be_nested_str_weak(destinationId), + /* K15 */ be_const_int(3), /* K16 */ be_nested_str_weak(initiatorEphPubKey), /* K17 */ be_nested_str_weak(findsub), /* K18 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), /* K19 */ be_nested_str_weak(findsubval), /* K20 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + /* K21 */ be_nested_str_weak(resumptionID), + /* K22 */ be_nested_str_weak(initiatorResumeMIC), }), be_str_weak(parse), &be_const_str_solidified, - ( &(const binstruction[58]) { /* code */ + ( &(const binstruction[60]) { /* code */ 0x4C0C0000, // 0000 LDNIL R3 0x1C0C0403, // 0001 EQ R3 R2 R3 0x780E0000, // 0002 JMPF R3 #0004 @@ -556,21 +558,21 @@ be_local_closure(Matter_Sigma1_parse, /* name */ 0x5C1C0600, // 0010 MOVE R7 R3 0x7C180200, // 0011 CALL R6 1 0x001A1006, // 0012 ADD R6 K8 R6 - 0x581C0009, // 0013 LDCONST R7 K9 + 0x541E0003, // 0013 LDINT R7 4 0x7C100600, // 0014 CALL R4 3 - 0x8C10070B, // 0015 GETMET R4 R3 K11 - 0x5818000C, // 0016 LDCONST R6 K12 + 0x8C10070A, // 0015 GETMET R4 R3 K10 + 0x5818000B, // 0016 LDCONST R6 K11 0x7C100400, // 0017 CALL R4 2 - 0x90021404, // 0018 SETMBR R0 K10 R4 - 0x8C10070B, // 0019 GETMET R4 R3 K11 - 0x5818000E, // 001A LDCONST R6 K14 + 0x90021204, // 0018 SETMBR R0 K9 R4 + 0x8C10070A, // 0019 GETMET R4 R3 K10 + 0x5818000D, // 001A LDCONST R6 K13 0x7C100400, // 001B CALL R4 2 - 0x90021A04, // 001C SETMBR R0 K13 R4 - 0x8C10070B, // 001D GETMET R4 R3 K11 - 0x58180009, // 001E LDCONST R6 K9 + 0x90021804, // 001C SETMBR R0 K12 R4 + 0x8C10070A, // 001D GETMET R4 R3 K10 + 0x5818000F, // 001E LDCONST R6 K15 0x7C100400, // 001F CALL R4 2 - 0x90021E04, // 0020 SETMBR R0 K15 R4 - 0x8C10070B, // 0021 GETMET R4 R3 K11 + 0x90021C04, // 0020 SETMBR R0 K14 R4 + 0x8C10070A, // 0021 GETMET R4 R3 K10 0x541A0003, // 0022 LDINT R6 4 0x7C100400, // 0023 CALL R4 2 0x90022004, // 0024 SETMBR R0 K16 R4 @@ -581,20 +583,22 @@ be_local_closure(Matter_Sigma1_parse, /* name */ 0x20140805, // 0029 NE R5 R4 R5 0x78160007, // 002A JMPF R5 #0033 0x8C140913, // 002B GETMET R5 R4 K19 - 0x581C000C, // 002C LDCONST R7 K12 + 0x581C000B, // 002C LDCONST R7 K11 0x7C140400, // 002D CALL R5 2 0x90022405, // 002E SETMBR R0 K18 R5 0x8C140913, // 002F GETMET R5 R4 K19 - 0x581C000E, // 0030 LDCONST R7 K14 + 0x581C000D, // 0030 LDCONST R7 K13 0x7C140400, // 0031 CALL R5 2 0x90022805, // 0032 SETMBR R0 K20 R5 - 0x8C140711, // 0033 GETMET R5 R3 K17 + 0x8C140713, // 0033 GETMET R5 R3 K19 0x541E0005, // 0034 LDINT R7 6 0x7C140400, // 0035 CALL R5 2 - 0x8C180711, // 0036 GETMET R6 R3 K17 - 0x54220006, // 0037 LDINT R8 7 - 0x7C180400, // 0038 CALL R6 2 - 0x80040000, // 0039 RET 1 R0 + 0x90022A05, // 0036 SETMBR R0 K21 R5 + 0x8C140713, // 0037 GETMET R5 R3 K19 + 0x541E0006, // 0038 LDINT R7 7 + 0x7C140400, // 0039 CALL R5 2 + 0x90022C05, // 003A SETMBR R0 K22 R5 + 0x80040000, // 003B RET 1 R0 }) ) ); @@ -633,9 +637,9 @@ void be_load_Matter_Sigma1_class(bvm *vm) { extern const bclass be_class_Matter_Sigma2; /******************************************************************** -** Solidified function: encode +** Solidified function: tlv2raw ********************************************************************/ -be_local_closure(Matter_Sigma2_encode, /* name */ +be_local_closure(Matter_Sigma2_tlv2raw, /* name */ be_nested_proto( 9, /* nstack */ 2, /* argc */ @@ -663,11 +667,11 @@ be_local_closure(Matter_Sigma2_encode, /* name */ /* K14 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), /* K15 */ be_nested_str_weak(add_struct), /* K16 */ be_nested_str_weak(U4), - /* K17 */ be_nested_str_weak(encode), + /* K17 */ be_nested_str_weak(tlv2raw), }), - be_str_weak(encode), + be_str_weak(tlv2raw), &be_const_str_solidified, - ( &(const binstruction[60]) { /* code */ + ( &(const binstruction[61]) { /* code */ 0xB80A0000, // 0000 GETNGBL R2 K0 0x88080501, // 0001 GETMBR R2 R2 K1 0x8C080502, // 0002 GETMET R2 R2 K2 @@ -726,8 +730,9 @@ be_local_closure(Matter_Sigma2_encode, /* name */ 0x8820010E, // 0037 GETMBR R8 R0 K14 0x7C100800, // 0038 CALL R4 4 0x8C0C0511, // 0039 GETMET R3 R2 K17 - 0x7C0C0200, // 003A CALL R3 1 - 0x80040600, // 003B RET 1 R3 + 0x5C140200, // 003A MOVE R5 R1 + 0x7C0C0400, // 003B CALL R3 2 + 0x80040600, // 003C RET 1 R3 }) ) ); @@ -742,13 +747,13 @@ be_local_class(Matter_Sigma2, NULL, be_nested_map(7, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(encrypted2, -1), be_const_var(3) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_Sigma2_encode_closure) }, + { be_const_key_weak(tlv2raw, -1), be_const_closure(Matter_Sigma2_tlv2raw_closure) }, + { be_const_key_weak(responderEphPubKey, 3), be_const_var(2) }, { be_const_key_weak(responderSessionId, -1), be_const_var(1) }, - { be_const_key_weak(SLEEPY_IDLE_INTERVAL, 6), be_const_var(4) }, - { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 0), be_const_var(5) }, - { be_const_key_weak(responderRandom, 3), be_const_var(0) }, - { be_const_key_weak(responderEphPubKey, -1), be_const_var(2) }, + { be_const_key_weak(SLEEPY_IDLE_INTERVAL, -1), be_const_var(4) }, + { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, 6), be_const_var(5) }, + { be_const_key_weak(responderRandom, 1), be_const_var(0) }, + { be_const_key_weak(encrypted2, -1), be_const_var(3) }, })), be_str_weak(Matter_Sigma2) ); @@ -763,9 +768,9 @@ void be_load_Matter_Sigma2_class(bvm *vm) { extern const bclass be_class_Matter_Sigma2Resume; /******************************************************************** -** Solidified function: encode +** Solidified function: tlv2raw ********************************************************************/ -be_local_closure(Matter_Sigma2Resume_encode, /* name */ +be_local_closure(Matter_Sigma2Resume_tlv2raw, /* name */ be_nested_proto( 9, /* nstack */ 2, /* argc */ @@ -775,7 +780,7 @@ be_local_closure(Matter_Sigma2Resume_encode, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ + ( &(const bvalue[17]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(TLV), /* K2 */ be_nested_str_weak(Matter_TLV_struct), @@ -786,16 +791,17 @@ be_local_closure(Matter_Sigma2Resume_encode, /* name */ /* K7 */ be_const_int(2), /* K8 */ be_nested_str_weak(sigma2ResumeMIC), /* K9 */ be_const_int(3), - /* K10 */ be_nested_str_weak(responderSessionID), - /* K11 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), - /* K12 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), - /* K13 */ be_nested_str_weak(add_struct), - /* K14 */ be_nested_str_weak(U4), - /* K15 */ be_nested_str_weak(encode), + /* K10 */ be_nested_str_weak(U2), + /* K11 */ be_nested_str_weak(responderSessionID), + /* K12 */ be_nested_str_weak(SLEEPY_IDLE_INTERVAL), + /* K13 */ be_nested_str_weak(SLEEPY_ACTIVE_INTERVAL), + /* K14 */ be_nested_str_weak(add_struct), + /* K15 */ be_nested_str_weak(U4), + /* K16 */ be_nested_str_weak(tlv2raw), }), - be_str_weak(encode), + be_str_weak(tlv2raw), &be_const_str_solidified, - ( &(const binstruction[53]) { /* code */ + ( &(const binstruction[54]) { /* code */ 0xB80A0000, // 0000 GETNGBL R2 K0 0x88080501, // 0001 GETMBR R2 R2 K1 0x8C080502, // 0002 GETMET R2 R2 K2 @@ -818,37 +824,38 @@ be_local_closure(Matter_Sigma2Resume_encode, /* name */ 0x58140009, // 0013 LDCONST R5 K9 0xB81A0000, // 0014 GETNGBL R6 K0 0x88180D01, // 0015 GETMBR R6 R6 K1 - 0x88180D05, // 0016 GETMBR R6 R6 K5 - 0x881C010A, // 0017 GETMBR R7 R0 K10 + 0x88180D0A, // 0016 GETMBR R6 R6 K10 + 0x881C010B, // 0017 GETMBR R7 R0 K11 0x7C0C0800, // 0018 CALL R3 4 - 0x880C010B, // 0019 GETMBR R3 R0 K11 + 0x880C010C, // 0019 GETMBR R3 R0 K12 0x4C100000, // 001A LDNIL R4 0x200C0604, // 001B NE R3 R3 R4 0x740E0003, // 001C JMPT R3 #0021 - 0x880C010C, // 001D GETMBR R3 R0 K12 + 0x880C010D, // 001D GETMBR R3 R0 K13 0x4C100000, // 001E LDNIL R4 0x200C0604, // 001F NE R3 R3 R4 0x780E0010, // 0020 JMPF R3 #0032 - 0x8C0C050D, // 0021 GETMET R3 R2 K13 + 0x8C0C050E, // 0021 GETMET R3 R2 K14 0x54160003, // 0022 LDINT R5 4 0x7C0C0400, // 0023 CALL R3 2 0x8C100703, // 0024 GETMET R4 R3 K3 0x58180004, // 0025 LDCONST R6 K4 0xB81E0000, // 0026 GETNGBL R7 K0 0x881C0F01, // 0027 GETMBR R7 R7 K1 - 0x881C0F0E, // 0028 GETMBR R7 R7 K14 - 0x8820010B, // 0029 GETMBR R8 R0 K11 + 0x881C0F0F, // 0028 GETMBR R7 R7 K15 + 0x8820010C, // 0029 GETMBR R8 R0 K12 0x7C100800, // 002A CALL R4 4 0x8C100703, // 002B GETMET R4 R3 K3 0x58180007, // 002C LDCONST R6 K7 0xB81E0000, // 002D GETNGBL R7 K0 0x881C0F01, // 002E GETMBR R7 R7 K1 - 0x881C0F0E, // 002F GETMBR R7 R7 K14 - 0x8820010C, // 0030 GETMBR R8 R0 K12 + 0x881C0F0F, // 002F GETMBR R7 R7 K15 + 0x8820010D, // 0030 GETMBR R8 R0 K13 0x7C100800, // 0031 CALL R4 4 - 0x8C0C050F, // 0032 GETMET R3 R2 K15 - 0x7C0C0200, // 0033 CALL R3 1 - 0x80040600, // 0034 RET 1 R3 + 0x8C0C0510, // 0032 GETMET R3 R2 K16 + 0x5C140200, // 0033 MOVE R5 R1 + 0x7C0C0400, // 0034 CALL R3 2 + 0x80040600, // 0035 RET 1 R3 }) ) ); @@ -868,7 +875,7 @@ be_local_class(Matter_Sigma2Resume, { be_const_key_weak(sigma2ResumeMIC, -1), be_const_var(1) }, { be_const_key_weak(responderSessionID, 1), be_const_var(2) }, { be_const_key_weak(SLEEPY_ACTIVE_INTERVAL, -1), be_const_var(4) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_Sigma2Resume_encode_closure) }, + { be_const_key_weak(tlv2raw, -1), be_const_closure(Matter_Sigma2Resume_tlv2raw_closure) }, })), be_str_weak(Matter_Sigma2Resume) ); @@ -895,7 +902,7 @@ be_local_closure(Matter_Sigma3_parse, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ + ( &(const bvalue[12]) { /* constants */ /* K0 */ be_const_int(0), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TLV), @@ -905,10 +912,9 @@ be_local_closure(Matter_Sigma3_parse, /* name */ /* K6 */ be_nested_str_weak(tasmota), /* K7 */ be_nested_str_weak(log), /* K8 */ be_nested_str_weak(MTR_X3A_X20Sigma3_X20TLV_X3D), - /* K9 */ be_const_int(3), - /* K10 */ be_nested_str_weak(TBEData3Encrypted), - /* K11 */ be_nested_str_weak(getsubval), - /* K12 */ be_const_int(1), + /* K9 */ be_nested_str_weak(TBEData3Encrypted), + /* K10 */ be_nested_str_weak(getsubval), + /* K11 */ be_const_int(1), }), be_str_weak(parse), &be_const_str_solidified, @@ -932,12 +938,12 @@ be_local_closure(Matter_Sigma3_parse, /* name */ 0x5C1C0600, // 0010 MOVE R7 R3 0x7C180200, // 0011 CALL R6 1 0x001A1006, // 0012 ADD R6 K8 R6 - 0x581C0009, // 0013 LDCONST R7 K9 + 0x541E0003, // 0013 LDINT R7 4 0x7C100600, // 0014 CALL R4 3 - 0x8C10070B, // 0015 GETMET R4 R3 K11 - 0x5818000C, // 0016 LDCONST R6 K12 + 0x8C10070A, // 0015 GETMET R4 R3 K10 + 0x5818000B, // 0016 LDCONST R6 K11 0x7C100400, // 0017 CALL R4 2 - 0x90021404, // 0018 SETMBR R0 K10 R4 + 0x90021204, // 0018 SETMBR R0 K9 R4 0x80040000, // 0019 RET 1 R0 }) ) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Control_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Control_Message.h new file mode 100644 index 000000000..967c09a27 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Control_Message.h @@ -0,0 +1,246 @@ +/* Solidification of Matter_Control_Message.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Control_Message; + +/******************************************************************** +** Solidified function: parse_MsgCounterSyncRsp +********************************************************************/ +be_local_closure(Matter_Control_Message_parse_MsgCounterSyncRsp, /* 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(string), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(format), + /* K5 */ be_nested_str_weak(MTR_X3A_X20_X3EMCSyncRsp_X20_X2A_X20Not_X20implemented_X20_X25s), + /* K6 */ be_nested_str_weak(raw), + /* K7 */ be_nested_str_weak(app_payload_idx), + /* K8 */ be_const_int(2147483647), + /* K9 */ be_nested_str_weak(tohex), + /* K10 */ be_const_int(2), + }), + be_str_weak(parse_MsgCounterSyncRsp), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0xB8120400, // 0002 GETNGBL R4 K2 + 0x8C100903, // 0003 GETMET R4 R4 K3 + 0x8C180504, // 0004 GETMET R6 R2 K4 + 0x58200005, // 0005 LDCONST R8 K5 + 0x88240307, // 0006 GETMBR R9 R1 K7 + 0x40241308, // 0007 CONNECT R9 R9 K8 + 0x88280306, // 0008 GETMBR R10 R1 K6 + 0x94241409, // 0009 GETIDX R9 R10 R9 + 0x8C241309, // 000A GETMET R9 R9 K9 + 0x7C240200, // 000B CALL R9 1 + 0x7C180600, // 000C CALL R6 3 + 0x581C000A, // 000D LDCONST R7 K10 + 0x7C100600, // 000E CALL R4 3 + 0x50100000, // 000F LDBOOL R4 0 0 + 0x80040800, // 0010 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_MsgCounterSyncReq +********************************************************************/ +be_local_closure(Matter_Control_Message_parse_MsgCounterSyncReq, /* 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(string), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(format), + /* K5 */ be_nested_str_weak(MTR_X3A_X20_X3EMCSyncReq_X20_X2A_X20Not_X20implemented_X20_X25s), + /* K6 */ be_nested_str_weak(raw), + /* K7 */ be_nested_str_weak(app_payload_idx), + /* K8 */ be_const_int(2147483647), + /* K9 */ be_nested_str_weak(tohex), + /* K10 */ be_const_int(2), + }), + be_str_weak(parse_MsgCounterSyncReq), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0xB8120400, // 0002 GETNGBL R4 K2 + 0x8C100903, // 0003 GETMET R4 R4 K3 + 0x8C180504, // 0004 GETMET R6 R2 K4 + 0x58200005, // 0005 LDCONST R8 K5 + 0x88240307, // 0006 GETMBR R9 R1 K7 + 0x40241308, // 0007 CONNECT R9 R9 K8 + 0x88280306, // 0008 GETMBR R10 R1 K6 + 0x94241409, // 0009 GETIDX R9 R10 R9 + 0x8C241309, // 000A GETMET R9 R9 K9 + 0x7C240200, // 000B CALL R9 1 + 0x7C180600, // 000C CALL R6 3 + 0x581C000A, // 000D LDCONST R7 K10 + 0x7C100600, // 000E CALL R4 3 + 0x50100000, // 000F LDBOOL R4 0 0 + 0x80040800, // 0010 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Control_Message_init, /* name */ + be_nested_proto( + 4, /* 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(crypto), + /* K1 */ be_nested_str_weak(responder), + /* K2 */ be_nested_str_weak(device), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x90020201, // 0001 SETMBR R0 K1 R1 + 0x880C0302, // 0002 GETMBR R3 R1 K2 + 0x90020403, // 0003 SETMBR R0 K2 R3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_incoming_control_message +********************************************************************/ +be_local_closure(Matter_Control_Message_process_incoming_control_message, /* 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[14]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20received_X20control_X20message_X20), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(inspect), + /* K5 */ be_const_int(2), + /* K6 */ be_nested_str_weak(opcode), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(parse_MsgCounterSyncReq), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(parse_MsgCounterSyncRsp), + /* K11 */ be_nested_str_weak(string), + /* K12 */ be_nested_str_weak(format), + /* K13 */ be_nested_str_weak(MTR_X3A_X20_X3E_X3F_X3F_X3F_X3F_X3F_X3F_X3F_X3F_X3F_X20Unknown_X20OpCode_X20_X28control_X20message_X29_X20_X2502X), + }), + be_str_weak(process_incoming_control_message), + &be_const_str_solidified, + ( &(const binstruction[38]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0xB8120600, // 0002 GETNGBL R4 K3 + 0x8C100904, // 0003 GETMET R4 R4 K4 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C100400, // 0005 CALL R4 2 + 0x00120404, // 0006 ADD R4 K2 R4 + 0x58140005, // 0007 LDCONST R5 K5 + 0x7C080600, // 0008 CALL R2 3 + 0x88080306, // 0009 GETMBR R2 R1 K6 + 0x1C080507, // 000A EQ R2 R2 K7 + 0x780A0004, // 000B JMPF R2 #0011 + 0x8C080108, // 000C GETMET R2 R0 K8 + 0x5C100200, // 000D MOVE R4 R1 + 0x7C080400, // 000E CALL R2 2 + 0x80040400, // 000F RET 1 R2 + 0x70020012, // 0010 JMP #0024 + 0x88080306, // 0011 GETMBR R2 R1 K6 + 0x1C080509, // 0012 EQ R2 R2 K9 + 0x780A0004, // 0013 JMPF R2 #0019 + 0x8C08010A, // 0014 GETMET R2 R0 K10 + 0x5C100200, // 0015 MOVE R4 R1 + 0x7C080400, // 0016 CALL R2 2 + 0x80040400, // 0017 RET 1 R2 + 0x7002000A, // 0018 JMP #0024 + 0xA40A1600, // 0019 IMPORT R2 K11 + 0xB80E0000, // 001A GETNGBL R3 K0 + 0x8C0C0701, // 001B GETMET R3 R3 K1 + 0x8C14050C, // 001C GETMET R5 R2 K12 + 0x581C000D, // 001D LDCONST R7 K13 + 0x88200306, // 001E GETMBR R8 R1 K6 + 0x7C140600, // 001F CALL R5 3 + 0x58180005, // 0020 LDCONST R6 K5 + 0x7C0C0600, // 0021 CALL R3 3 + 0x500C0000, // 0022 LDBOOL R3 0 0 + 0x80040600, // 0023 RET 1 R3 + 0x50080000, // 0024 LDBOOL R2 0 0 + 0x80040400, // 0025 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Control_Message +********************************************************************/ +be_local_class(Matter_Control_Message, + 2, + NULL, + be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(parse_MsgCounterSyncRsp, -1), be_const_closure(Matter_Control_Message_parse_MsgCounterSyncRsp_closure) }, + { be_const_key_weak(responder, 2), be_const_var(0) }, + { be_const_key_weak(parse_MsgCounterSyncReq, -1), be_const_closure(Matter_Control_Message_parse_MsgCounterSyncReq_closure) }, + { be_const_key_weak(init, 4), be_const_closure(Matter_Control_Message_init_closure) }, + { be_const_key_weak(device, -1), be_const_var(1) }, + { be_const_key_weak(process_incoming_control_message, -1), be_const_closure(Matter_Control_Message_process_incoming_control_message_closure) }, + })), + be_str_weak(Matter_Control_Message) +); +/*******************************************************************/ + +void be_load_Matter_Control_Message_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Control_Message); + be_setglobal(vm, "Matter_Control_Message"); + be_pop(vm, 1); +} +/********************************************************************/ +/* 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 b52678302..afddf3b57 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h @@ -6,6 +6,92 @@ extern const bclass be_class_Matter_Device; +/******************************************************************** +** Solidified function: start_operational_discovery +********************************************************************/ +be_local_closure(Matter_Device_start_operational_discovery, /* 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[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(mdns), + /* K2 */ be_nested_str_weak(string), + /* K3 */ be_nested_str_weak(stop_basic_commissioning), + /* K4 */ be_nested_str_weak(root_w0), + /* K5 */ be_nested_str_weak(root_L), + /* K6 */ be_nested_str_weak(set_expire_in_seconds), + /* K7 */ be_nested_str_weak(mdns_announce_op_discovery), + /* K8 */ be_nested_str_weak(get_fabric), + }), + be_str_weak(start_operational_discovery), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0x8C140103, // 0003 GETMET R5 R0 K3 + 0x7C140200, // 0004 CALL R5 1 + 0x4C140000, // 0005 LDNIL R5 + 0x90020805, // 0006 SETMBR R0 K4 R5 + 0x4C140000, // 0007 LDNIL R5 + 0x90020A05, // 0008 SETMBR R0 K5 R5 + 0x8C140306, // 0009 GETMET R5 R1 K6 + 0x541E003B, // 000A LDINT R7 60 + 0x7C140400, // 000B CALL R5 2 + 0x8C140107, // 000C GETMET R5 R0 K7 + 0x8C1C0308, // 000D GETMET R7 R1 K8 + 0x7C1C0200, // 000E CALL R7 1 + 0x7C140400, // 000F CALL R5 2 + 0x80000000, // 0010 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: compute_manual_pairing_code ********************************************************************/ @@ -21,8 +107,8 @@ be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ 1, /* has constants */ ( &(const bvalue[ 8]) { /* constants */ /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(discriminator), - /* K2 */ be_nested_str_weak(passcode), + /* K1 */ be_nested_str_weak(root_discriminator), + /* K2 */ be_nested_str_weak(root_passcode), /* K3 */ be_nested_str_weak(format), /* K4 */ be_nested_str_weak(_X251i_X2505i_X2504i), /* K5 */ be_nested_str_weak(matter), @@ -70,276 +156,11 @@ be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ /******************************************************************** -** Solidified function: process_attribute_expansion +** Solidified function: _trigger_read_sensors ********************************************************************/ -be_local_closure(Matter_Device_process_attribute_expansion, /* name */ +be_local_closure(Matter_Device__trigger_read_sensors, /* name */ be_nested_proto( - 33, /* nstack */ - 3, /* 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(string), - /* K1 */ be_nested_str_weak(endpoint), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(attribute), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(format), - /* K7 */ be_nested_str_weak(MTR_X3A_X20process_attribute_expansion_X20_X25s), - /* K8 */ be_const_int(3), - /* K9 */ be_nested_str_weak(plugins), - /* K10 */ be_nested_str_weak(get_endpoints), - /* K11 */ be_nested_str_weak(MTR_X3A_X20ep_list_X20_X25s_X20_X25s), - /* K12 */ be_nested_str_weak(find), - /* K13 */ be_nested_str_weak(get_cluster_list), - /* K14 */ be_nested_str_weak(MTR_X3A_X20cluster_list_X20_X25s_X20_X25s), - /* K15 */ be_nested_str_weak(get_attribute_list), - /* K16 */ be_nested_str_weak(MTR_X3A_X20attr_list_X20_X25s_X20_X25s), - /* K17 */ be_nested_str_weak(MTR_X3A_X20expansion_X20_X5B_X2502X_X5D_X2504X_X2F_X2504X), - /* K18 */ be_nested_str_weak(stop_iteration), - /* K19 */ be_nested_str_weak(status), - /* K20 */ be_nested_str_weak(matter), - /* K21 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), - /* K22 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), - /* K23 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), - /* K24 */ be_nested_str_weak(UNREPORTABLE_ATTRIBUTE), - }), - be_str_weak(process_attribute_expansion), - &be_const_str_solidified, - ( &(const binstruction[216]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0x88100301, // 0001 GETMBR R4 R1 K1 - 0x60140012, // 0002 GETGBL R5 G18 - 0x7C140000, // 0003 CALL R5 0 - 0x40180A04, // 0004 CONNECT R6 R5 R4 - 0x50180000, // 0005 LDBOOL R6 0 0 - 0x881C0302, // 0006 GETMBR R7 R1 K2 - 0x60200012, // 0007 GETGBL R8 G18 - 0x7C200000, // 0008 CALL R8 0 - 0x40241007, // 0009 CONNECT R9 R8 R7 - 0x50240000, // 000A LDBOOL R9 0 0 - 0x88280303, // 000B GETMBR R10 R1 K3 - 0x602C0012, // 000C GETGBL R11 G18 - 0x7C2C0000, // 000D CALL R11 0 - 0x4030160A, // 000E CONNECT R12 R11 R10 - 0x50300000, // 000F LDBOOL R12 0 0 - 0x88340301, // 0010 GETMBR R13 R1 K1 - 0x4C380000, // 0011 LDNIL R14 - 0x20341A0E, // 0012 NE R13 R13 R14 - 0x78360007, // 0013 JMPF R13 #001C - 0x88340302, // 0014 GETMBR R13 R1 K2 - 0x4C380000, // 0015 LDNIL R14 - 0x20341A0E, // 0016 NE R13 R13 R14 - 0x78360003, // 0017 JMPF R13 #001C - 0x88340303, // 0018 GETMBR R13 R1 K3 - 0x4C380000, // 0019 LDNIL R14 - 0x20341A0E, // 001A NE R13 R13 R14 - 0x74360000, // 001B JMPT R13 #001D - 0x50340001, // 001C LDBOOL R13 0 1 - 0x50340200, // 001D LDBOOL R13 1 0 - 0xB83A0800, // 001E GETNGBL R14 K4 - 0x8C381D05, // 001F GETMET R14 R14 K5 - 0x8C400706, // 0020 GETMET R16 R3 K6 - 0x58480007, // 0021 LDCONST R18 K7 - 0x604C0008, // 0022 GETGBL R19 G8 - 0x5C500200, // 0023 MOVE R20 R1 - 0x7C4C0200, // 0024 CALL R19 1 - 0x7C400600, // 0025 CALL R16 3 - 0x58440008, // 0026 LDCONST R17 K8 - 0x7C380600, // 0027 CALL R14 3 - 0x60380010, // 0028 GETGBL R14 G16 - 0x883C0109, // 0029 GETMBR R15 R0 K9 - 0x7C380200, // 002A CALL R14 1 - 0xA802008C, // 002B EXBLK 0 #00B9 - 0x5C3C1C00, // 002C MOVE R15 R14 - 0x7C3C0000, // 002D CALL R15 0 - 0x8C401F0A, // 002E GETMET R16 R15 K10 - 0x7C400200, // 002F CALL R16 1 - 0xB8460800, // 0030 GETNGBL R17 K4 - 0x8C442305, // 0031 GETMET R17 R17 K5 - 0x8C4C0706, // 0032 GETMET R19 R3 K6 - 0x5854000B, // 0033 LDCONST R21 K11 - 0x60580008, // 0034 GETGBL R22 G8 - 0x5C5C1E00, // 0035 MOVE R23 R15 - 0x7C580200, // 0036 CALL R22 1 - 0x605C0008, // 0037 GETGBL R23 G8 - 0x5C602000, // 0038 MOVE R24 R16 - 0x7C5C0200, // 0039 CALL R23 1 - 0x7C4C0800, // 003A CALL R19 4 - 0x58500008, // 003B LDCONST R20 K8 - 0x7C440600, // 003C CALL R17 3 - 0x4C440000, // 003D LDNIL R17 - 0x20440811, // 003E NE R17 R4 R17 - 0x78460009, // 003F JMPF R17 #004A - 0x8C44210C, // 0040 GETMET R17 R16 K12 - 0x5C4C0800, // 0041 MOVE R19 R4 - 0x7C440400, // 0042 CALL R17 2 - 0x4C480000, // 0043 LDNIL R18 - 0x20442212, // 0044 NE R17 R17 R18 - 0x78460002, // 0045 JMPF R17 #0049 - 0x5C400A00, // 0046 MOVE R16 R5 - 0x50180200, // 0047 LDBOOL R6 1 0 - 0x70020000, // 0048 JMP #004A - 0x7001FFE1, // 0049 JMP #002C - 0x60440010, // 004A GETGBL R17 G16 - 0x5C482000, // 004B MOVE R18 R16 - 0x7C440200, // 004C CALL R17 1 - 0xA8020066, // 004D EXBLK 0 #00B5 - 0x5C482200, // 004E MOVE R18 R17 - 0x7C480000, // 004F CALL R18 0 - 0x8C4C1F0D, // 0050 GETMET R19 R15 K13 - 0x5C542400, // 0051 MOVE R21 R18 - 0x7C4C0400, // 0052 CALL R19 2 - 0xB8520800, // 0053 GETNGBL R20 K4 - 0x8C502905, // 0054 GETMET R20 R20 K5 - 0x8C580706, // 0055 GETMET R22 R3 K6 - 0x5860000E, // 0056 LDCONST R24 K14 - 0x60640008, // 0057 GETGBL R25 G8 - 0x5C682400, // 0058 MOVE R26 R18 - 0x7C640200, // 0059 CALL R25 1 - 0x60680008, // 005A GETGBL R26 G8 - 0x5C6C2600, // 005B MOVE R27 R19 - 0x7C680200, // 005C CALL R26 1 - 0x7C580800, // 005D CALL R22 4 - 0x585C0008, // 005E LDCONST R23 K8 - 0x7C500600, // 005F CALL R20 3 - 0x4C500000, // 0060 LDNIL R20 - 0x20500E14, // 0061 NE R20 R7 R20 - 0x78520009, // 0062 JMPF R20 #006D - 0x8C50270C, // 0063 GETMET R20 R19 K12 - 0x5C580E00, // 0064 MOVE R22 R7 - 0x7C500400, // 0065 CALL R20 2 - 0x4C540000, // 0066 LDNIL R21 - 0x20502815, // 0067 NE R20 R20 R21 - 0x78520002, // 0068 JMPF R20 #006C - 0x5C4C1000, // 0069 MOVE R19 R8 - 0x50240200, // 006A LDBOOL R9 1 0 - 0x70020000, // 006B JMP #006D - 0x7001FFE0, // 006C JMP #004E - 0x60500010, // 006D GETGBL R20 G16 - 0x5C542600, // 006E MOVE R21 R19 - 0x7C500200, // 006F CALL R20 1 - 0xA802003F, // 0070 EXBLK 0 #00B1 - 0x5C542800, // 0071 MOVE R21 R20 - 0x7C540000, // 0072 CALL R21 0 - 0x8C581F0F, // 0073 GETMET R22 R15 K15 - 0x5C602400, // 0074 MOVE R24 R18 - 0x5C640E00, // 0075 MOVE R25 R7 - 0x7C580600, // 0076 CALL R22 3 - 0xB85E0800, // 0077 GETNGBL R23 K4 - 0x8C5C2F05, // 0078 GETMET R23 R23 K5 - 0x8C640706, // 0079 GETMET R25 R3 K6 - 0x586C0010, // 007A LDCONST R27 K16 - 0x60700008, // 007B GETGBL R28 G8 - 0x5C742A00, // 007C MOVE R29 R21 - 0x7C700200, // 007D CALL R28 1 - 0x60740008, // 007E GETGBL R29 G8 - 0x5C782C00, // 007F MOVE R30 R22 - 0x7C740200, // 0080 CALL R29 1 - 0x7C640800, // 0081 CALL R25 4 - 0x58680008, // 0082 LDCONST R26 K8 - 0x7C5C0600, // 0083 CALL R23 3 - 0x4C5C0000, // 0084 LDNIL R23 - 0x205C1417, // 0085 NE R23 R10 R23 - 0x785E0028, // 0086 JMPF R23 #00B0 - 0x8C5C2D0C, // 0087 GETMET R23 R22 K12 - 0x5C641400, // 0088 MOVE R25 R10 - 0x7C5C0400, // 0089 CALL R23 2 - 0x4C600000, // 008A LDNIL R24 - 0x205C2E18, // 008B NE R23 R23 R24 - 0x785E0002, // 008C JMPF R23 #0090 - 0x5C581600, // 008D MOVE R22 R11 - 0x50300200, // 008E LDBOOL R12 1 0 - 0x70020000, // 008F JMP #0091 - 0x7001FFDF, // 0090 JMP #0071 - 0x605C0010, // 0091 GETGBL R23 G16 - 0x5C602C00, // 0092 MOVE R24 R22 - 0x7C5C0200, // 0093 CALL R23 1 - 0xA8020017, // 0094 EXBLK 0 #00AD - 0x5C602E00, // 0095 MOVE R24 R23 - 0x7C600000, // 0096 CALL R24 0 - 0xB8660800, // 0097 GETNGBL R25 K4 - 0x8C643305, // 0098 GETMET R25 R25 K5 - 0x8C6C0706, // 0099 GETMET R27 R3 K6 - 0x58740011, // 009A LDCONST R29 K17 - 0x5C782400, // 009B MOVE R30 R18 - 0x5C7C2A00, // 009C MOVE R31 R21 - 0x5C803000, // 009D MOVE R32 R24 - 0x7C6C0A00, // 009E CALL R27 5 - 0x58700008, // 009F LDCONST R28 K8 - 0x7C640600, // 00A0 CALL R25 3 - 0x90060212, // 00A1 SETMBR R1 K1 R18 - 0x90060415, // 00A2 SETMBR R1 K2 R21 - 0x90060618, // 00A3 SETMBR R1 K3 R24 - 0x5C640400, // 00A4 MOVE R25 R2 - 0x5C681E00, // 00A5 MOVE R26 R15 - 0x5C6C0200, // 00A6 MOVE R27 R1 - 0x5C701A00, // 00A7 MOVE R28 R13 - 0x7C640600, // 00A8 CALL R25 3 - 0x78660001, // 00A9 JMPF R25 #00AC - 0xA8040004, // 00AA EXBLK 1 4 - 0x80003400, // 00AB RET 0 - 0x7001FFE7, // 00AC JMP #0095 - 0x585C0012, // 00AD LDCONST R23 K18 - 0xAC5C0200, // 00AE CATCH R23 1 0 - 0xB0080000, // 00AF RAISE 2 R0 R0 - 0x7001FFBF, // 00B0 JMP #0071 - 0x58500012, // 00B1 LDCONST R20 K18 - 0xAC500200, // 00B2 CATCH R20 1 0 - 0xB0080000, // 00B3 RAISE 2 R0 R0 - 0x7001FF98, // 00B4 JMP #004E - 0x58440012, // 00B5 LDCONST R17 K18 - 0xAC440200, // 00B6 CATCH R17 1 0 - 0xB0080000, // 00B7 RAISE 2 R0 R0 - 0x7001FF72, // 00B8 JMP #002C - 0x58380012, // 00B9 LDCONST R14 K18 - 0xAC380200, // 00BA CATCH R14 1 0 - 0xB0080000, // 00BB RAISE 2 R0 R0 - 0x78360019, // 00BC JMPF R13 #00D7 - 0x5C380C00, // 00BD MOVE R14 R6 - 0x743A0003, // 00BE JMPT R14 #00C3 - 0xB83A2800, // 00BF GETNGBL R14 K20 - 0x88381D15, // 00C0 GETMBR R14 R14 K21 - 0x9006260E, // 00C1 SETMBR R1 K19 R14 - 0x7002000E, // 00C2 JMP #00D2 - 0x5C381200, // 00C3 MOVE R14 R9 - 0x743A0003, // 00C4 JMPT R14 #00C9 - 0xB83A2800, // 00C5 GETNGBL R14 K20 - 0x88381D16, // 00C6 GETMBR R14 R14 K22 - 0x9006260E, // 00C7 SETMBR R1 K19 R14 - 0x70020008, // 00C8 JMP #00D2 - 0x5C381800, // 00C9 MOVE R14 R12 - 0x743A0003, // 00CA JMPT R14 #00CF - 0xB83A2800, // 00CB GETNGBL R14 K20 - 0x88381D17, // 00CC GETMBR R14 R14 K23 - 0x9006260E, // 00CD SETMBR R1 K19 R14 - 0x70020002, // 00CE JMP #00D2 - 0xB83A2800, // 00CF GETNGBL R14 K20 - 0x88381D18, // 00D0 GETMBR R14 R14 K24 - 0x9006260E, // 00D1 SETMBR R1 K19 R14 - 0x5C380400, // 00D2 MOVE R14 R2 - 0x4C3C0000, // 00D3 LDNIL R15 - 0x5C400200, // 00D4 MOVE R16 R1 - 0x50440200, // 00D5 LDBOOL R17 1 0 - 0x7C380600, // 00D6 CALL R14 3 - 0x80000000, // 00D7 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: save_param -********************************************************************/ -be_local_closure(Matter_Device_save_param, /* name */ - be_nested_proto( - 10, /* nstack */ + 8, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -347,69 +168,59 @@ be_local_closure(Matter_Device_save_param, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[15]) { /* constants */ + ( &(const bvalue[11]) { /* constants */ /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(dump), - /* K2 */ be_nested_str_weak(distinguish), - /* K3 */ be_nested_str_weak(discriminator), - /* K4 */ be_nested_str_weak(passcode), - /* K5 */ be_nested_str_weak(string), - /* K6 */ be_nested_str_weak(FILENAME), - /* K7 */ be_nested_str_weak(w), - /* K8 */ be_nested_str_weak(write), - /* K9 */ be_nested_str_weak(close), - /* K10 */ be_nested_str_weak(tasmota), - /* K11 */ be_nested_str_weak(log), - /* K12 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), - /* K13 */ be_nested_str_weak(_X7C), - /* K14 */ be_const_int(2), + /* 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(save_param), + be_str_weak(_trigger_read_sensors), &be_const_str_solidified, - ( &(const binstruction[43]) { /* code */ + ( &(const binstruction[37]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x60100013, // 0002 GETGBL R4 G19 - 0x7C100000, // 0003 CALL R4 0 - 0x88140103, // 0004 GETMBR R5 R0 K3 - 0x98120405, // 0005 SETIDX R4 K2 R5 - 0x88140104, // 0006 GETMBR R5 R0 K4 - 0x98120805, // 0007 SETIDX R4 K4 R5 - 0x7C080400, // 0008 CALL R2 2 - 0xA802000D, // 0009 EXBLK 0 #0018 - 0xA40E0A00, // 000A IMPORT R3 K5 - 0x60100011, // 000B GETGBL R4 G17 - 0x88140106, // 000C GETMBR R5 R0 K6 - 0x58180007, // 000D LDCONST R6 K7 - 0x7C100400, // 000E CALL R4 2 - 0x8C140908, // 000F GETMET R5 R4 K8 - 0x5C1C0400, // 0010 MOVE R7 R2 - 0x7C140400, // 0011 CALL R5 2 - 0x8C140909, // 0012 GETMET R5 R4 K9 - 0x7C140200, // 0013 CALL R5 1 - 0xA8040001, // 0014 EXBLK 1 1 - 0x80040400, // 0015 RET 1 R2 - 0xA8040001, // 0016 EXBLK 1 1 - 0x70020011, // 0017 JMP #002A - 0xAC0C0002, // 0018 CATCH R3 0 2 - 0x7002000E, // 0019 JMP #0029 - 0xB8161400, // 001A GETNGBL R5 K10 - 0x8C140B0B, // 001B GETMET R5 R5 K11 - 0x601C0008, // 001C GETGBL R7 G8 - 0x5C200600, // 001D MOVE R8 R3 - 0x7C1C0200, // 001E CALL R7 1 - 0x001E1807, // 001F ADD R7 K12 R7 - 0x001C0F0D, // 0020 ADD R7 R7 K13 - 0x60200008, // 0021 GETGBL R8 G8 - 0x5C240800, // 0022 MOVE R9 R4 - 0x7C200200, // 0023 CALL R8 1 - 0x001C0E08, // 0024 ADD R7 R7 R8 - 0x5820000E, // 0025 LDCONST R8 K14 - 0x7C140600, // 0026 CALL R5 3 - 0x80040400, // 0027 RET 1 R2 - 0x70020000, // 0028 JMP #002A - 0xB0080000, // 0029 RAISE 2 R0 R0 - 0x80000000, // 002A RET 0 + 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 }) ) ); @@ -417,20 +228,20 @@ be_local_closure(Matter_Device_save_param, /* name */ /******************************************************************** -** Solidified function: start_udp +** Solidified function: start ********************************************************************/ -be_local_closure(Matter_Device_start_udp, /* name */ +be_local_closure(Matter_Device_start, /* name */ be_nested_proto( - 6, /* nstack */ - 2, /* argc */ + 7, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 1, /* has sup protos */ ( &(const struct bproto*[ 1]) { be_nested_proto( - 8, /* nstack */ - 3, /* argc */ + 2, /* nstack */ + 0, /* argc */ 0, /* varg */ 1, /* has upvals */ ( &(const bupvaldesc[ 1]) { /* upvals */ @@ -440,63 +251,66 @@ be_local_closure(Matter_Device_start_udp, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(msg_received), + /* K0 */ be_nested_str_weak(_trigger_read_sensors), }), - be_str_weak(_X3Clambda_X3E), + be_str_weak(_anonymous_), &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 + ( &(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(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), + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(started), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(push), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Plugin_Root), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(autoconf_device), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(add_cron), + /* K9 */ be_nested_str_weak(_X2A_X2F5_X20_X2A_X20_X2A_X20_X2A_X20_X2A_X20_X2A), + /* K10 */ be_nested_str_weak(matter_sensors_5s), + /* K11 */ be_nested_str_weak(_start_udp), + /* K12 */ be_nested_str_weak(UDP_PORT), + /* K13 */ be_nested_str_weak(start_mdns_announce_hostnames), }), - be_str_weak(start_udp), + be_str_weak(start), &be_const_str_solidified, - ( &(const binstruction[27]) { /* 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 - 0x58100007, // 0011 LDCONST R4 K7 - 0x5C140200, // 0012 MOVE R5 R1 - 0x7C080600, // 0013 CALL R2 3 - 0x90020002, // 0014 SETMBR R0 K0 R2 - 0x88080100, // 0015 GETMBR R2 R0 K0 - 0x8C080508, // 0016 GETMET R2 R2 K8 - 0x84100000, // 0017 CLOSURE R4 P0 - 0x7C080400, // 0018 CALL R2 2 - 0xA0000000, // 0019 CLOSE R0 - 0x80000000, // 001A RET 0 + ( &(const binstruction[28]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060000, // 0001 JMPF R1 #0003 + 0x80000200, // 0002 RET 0 + 0x88040101, // 0003 GETMBR R1 R0 K1 + 0x8C040302, // 0004 GETMET R1 R1 K2 + 0xB80E0600, // 0005 GETNGBL R3 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x5C140000, // 0007 MOVE R5 R0 + 0x58180005, // 0008 LDCONST R6 K5 + 0x7C0C0600, // 0009 CALL R3 3 + 0x7C040400, // 000A CALL R1 2 + 0x8C040106, // 000B GETMET R1 R0 K6 + 0x7C040200, // 000C CALL R1 1 + 0xB8060E00, // 000D GETNGBL R1 K7 + 0x8C040308, // 000E GETMET R1 R1 K8 + 0x580C0009, // 000F LDCONST R3 K9 + 0x84100000, // 0010 CLOSURE R4 P0 + 0x5814000A, // 0011 LDCONST R5 K10 + 0x7C040800, // 0012 CALL R1 4 + 0x8C04010B, // 0013 GETMET R1 R0 K11 + 0x880C010C, // 0014 GETMBR R3 R0 K12 + 0x7C040400, // 0015 CALL R1 2 + 0x8C04010D, // 0016 GETMET R1 R0 K13 + 0x7C040200, // 0017 CALL R1 1 + 0x50040200, // 0018 LDBOOL R1 1 0 + 0x90020001, // 0019 SETMBR R0 K0 R1 + 0xA0000000, // 001A CLOSE R0 + 0x80000000, // 001B RET 0 }) ) ); @@ -504,11 +318,11 @@ be_local_closure(Matter_Device_start_udp, /* name */ /******************************************************************** -** Solidified function: load_param +** Solidified function: stop_basic_commissioning ********************************************************************/ -be_local_closure(Matter_Device_load_param, /* name */ +be_local_closure(Matter_Device_stop_basic_commissioning, /* name */ be_nested_proto( - 10, /* nstack */ + 3, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -516,103 +330,36 @@ be_local_closure(Matter_Device_load_param, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[22]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(FILENAME), - /* K3 */ be_nested_str_weak(read), - /* K4 */ be_nested_str_weak(close), - /* K5 */ be_nested_str_weak(json), - /* K6 */ be_nested_str_weak(load), - /* K7 */ be_nested_str_weak(discriminator), - /* K8 */ be_nested_str_weak(find), - /* K9 */ be_nested_str_weak(distinguish), - /* K10 */ be_nested_str_weak(passcode), - /* K11 */ be_nested_str_weak(io_error), - /* K12 */ be_nested_str_weak(tasmota), - /* K13 */ be_nested_str_weak(log), - /* K14 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), - /* K15 */ be_nested_str_weak(_X7C), - /* K16 */ be_const_int(2), - /* K17 */ be_nested_str_weak(random), - /* K18 */ be_nested_str_weak(get), - /* K19 */ be_const_int(0), - /* K20 */ be_nested_str_weak(PASSCODE_DEFAULT), - /* K21 */ be_nested_str_weak(save_param), + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(commissioning_open), + /* K1 */ be_nested_str_weak(mdns_remove_PASE), + /* K2 */ be_nested_str_weak(commissioning_iterations), + /* K3 */ be_nested_str_weak(commissioning_discriminator), + /* K4 */ be_nested_str_weak(commissioning_salt), + /* K5 */ be_nested_str_weak(commissioning_w0), + /* K6 */ be_nested_str_weak(commissioning_L), + /* K7 */ be_nested_str_weak(commissioning_admin_fabric), }), - be_str_weak(load_param), + be_str_weak(stop_basic_commissioning), &be_const_str_solidified, - ( &(const binstruction[70]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA40A0200, // 0001 IMPORT R2 K1 - 0xA8020014, // 0002 EXBLK 0 #0018 - 0x600C0011, // 0003 GETGBL R3 G17 - 0x88100102, // 0004 GETMBR R4 R0 K2 - 0x7C0C0200, // 0005 CALL R3 1 - 0x8C100703, // 0006 GETMET R4 R3 K3 - 0x7C100200, // 0007 CALL R4 1 - 0x8C140704, // 0008 GETMET R5 R3 K4 - 0x7C140200, // 0009 CALL R5 1 - 0xA4160A00, // 000A IMPORT R5 K5 - 0x8C180B06, // 000B GETMET R6 R5 K6 - 0x5C200800, // 000C MOVE R8 R4 - 0x7C180400, // 000D CALL R6 2 - 0x8C1C0D08, // 000E GETMET R7 R6 K8 - 0x58240009, // 000F LDCONST R9 K9 - 0x7C1C0400, // 0010 CALL R7 2 - 0x90020E07, // 0011 SETMBR R0 K7 R7 - 0x8C1C0D08, // 0012 GETMET R7 R6 K8 - 0x5824000A, // 0013 LDCONST R9 K10 - 0x7C1C0400, // 0014 CALL R7 2 - 0x90021407, // 0015 SETMBR R0 K10 R7 - 0xA8040001, // 0016 EXBLK 1 1 - 0x70020012, // 0017 JMP #002B - 0xAC0C0002, // 0018 CATCH R3 0 2 - 0x7002000F, // 0019 JMP #002A - 0x2014070B, // 001A NE R5 R3 K11 - 0x7816000C, // 001B JMPF R5 #0029 - 0xB8161800, // 001C GETNGBL R5 K12 - 0x8C140B0D, // 001D GETMET R5 R5 K13 - 0x601C0008, // 001E GETGBL R7 G8 - 0x5C200600, // 001F MOVE R8 R3 - 0x7C1C0200, // 0020 CALL R7 1 - 0x001E1C07, // 0021 ADD R7 K14 R7 - 0x001C0F0F, // 0022 ADD R7 R7 K15 - 0x60200008, // 0023 GETGBL R8 G8 - 0x5C240800, // 0024 MOVE R9 R4 - 0x7C200200, // 0025 CALL R8 1 - 0x001C0E08, // 0026 ADD R7 R7 R8 - 0x58200010, // 0027 LDCONST R8 K16 - 0x7C140600, // 0028 CALL R5 3 - 0x70020000, // 0029 JMP #002B - 0xB0080000, // 002A RAISE 2 R0 R0 - 0x500C0000, // 002B LDBOOL R3 0 0 - 0x88100107, // 002C GETMBR R4 R0 K7 - 0x4C140000, // 002D LDNIL R5 - 0x1C100805, // 002E EQ R4 R4 R5 - 0x7812000A, // 002F JMPF R4 #003B - 0x8C100511, // 0030 GETMET R4 R2 K17 - 0x58180010, // 0031 LDCONST R6 K16 - 0x7C100400, // 0032 CALL R4 2 - 0x8C100912, // 0033 GETMET R4 R4 K18 - 0x58180013, // 0034 LDCONST R6 K19 - 0x581C0010, // 0035 LDCONST R7 K16 - 0x7C100600, // 0036 CALL R4 3 - 0x54160FFE, // 0037 LDINT R5 4095 - 0x2C100805, // 0038 AND R4 R4 R5 - 0x90020E04, // 0039 SETMBR R0 K7 R4 - 0x500C0200, // 003A LDBOOL R3 1 0 - 0x8810010A, // 003B GETMBR R4 R0 K10 - 0x4C140000, // 003C LDNIL R5 - 0x1C100805, // 003D EQ R4 R4 R5 - 0x78120002, // 003E JMPF R4 #0042 - 0x88100114, // 003F GETMBR R4 R0 K20 - 0x90021404, // 0040 SETMBR R0 K10 R4 - 0x500C0200, // 0041 LDBOOL R3 1 0 - 0x780E0001, // 0042 JMPF R3 #0045 - 0x8C100115, // 0043 GETMET R4 R0 K21 - 0x7C100200, // 0044 CALL R4 1 - 0x80000000, // 0045 RET 0 + ( &(const binstruction[17]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x8C040101, // 0002 GETMET R1 R0 K1 + 0x7C040200, // 0003 CALL R1 1 + 0x4C040000, // 0004 LDNIL R1 + 0x90020401, // 0005 SETMBR R0 K2 R1 + 0x4C040000, // 0006 LDNIL R1 + 0x90020601, // 0007 SETMBR R0 K3 R1 + 0x4C040000, // 0008 LDNIL R1 + 0x90020801, // 0009 SETMBR R0 K4 R1 + 0x4C040000, // 000A LDNIL R1 + 0x90020A01, // 000B SETMBR R0 K5 R1 + 0x4C040000, // 000C LDNIL R1 + 0x90020C01, // 000D SETMBR R0 K6 R1 + 0x4C040000, // 000E LDNIL R1 + 0x90020E01, // 000F SETMBR R0 K7 R1 + 0x80000000, // 0010 RET 0 }) ) ); @@ -620,9 +367,9 @@ be_local_closure(Matter_Device_load_param, /* name */ /******************************************************************** -** Solidified function: start_operational_dicovery_deferred +** Solidified function: start_operational_discovery_deferred ********************************************************************/ -be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ +be_local_closure(Matter_Device_start_operational_discovery_deferred, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -644,7 +391,7 @@ be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(start_operational_dicovery), + /* K0 */ be_nested_str_weak(start_operational_discovery), }), be_str_weak(_X3Clambda_X3E), &be_const_str_solidified, @@ -663,7 +410,7 @@ be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ /* K1 */ be_nested_str_weak(set_timer), /* K2 */ be_const_int(0), }), - be_str_weak(start_operational_dicovery_deferred), + be_str_weak(start_operational_discovery_deferred), &be_const_str_solidified, ( &(const binstruction[ 7]) { /* code */ 0xB80A0000, // 0000 GETNGBL R2 K0 @@ -680,12 +427,91 @@ be_local_closure(Matter_Device_start_operational_dicovery_deferred, /* name */ /******************************************************************** -** Solidified function: stop +** Solidified function: remove_fabric ********************************************************************/ -be_local_closure(Matter_Device_stop, /* name */ +be_local_closure(Matter_Device_remove_fabric, /* name */ be_nested_proto( - 3, /* nstack */ - 1, /* argc */ + 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[12]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(find_children_fabrics), + /* K2 */ be_nested_str_weak(get_fabric_index), + /* K3 */ be_nested_str_weak(find_fabric_by_index), + /* K4 */ be_nested_str_weak(message_handler), + /* K5 */ be_nested_str_weak(im), + /* K6 */ be_nested_str_weak(subs_shop), + /* K7 */ be_nested_str_weak(remove_by_fabric), + /* K8 */ be_nested_str_weak(mdns_remove_op_discovery), + /* K9 */ be_nested_str_weak(remove_fabric), + /* K10 */ be_nested_str_weak(stop_iteration), + /* K11 */ be_nested_str_weak(save_fabrics), + }), + be_str_weak(remove_fabric), + &be_const_str_solidified, + ( &(const binstruction[43]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x8C100302, // 0002 GETMET R4 R1 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x7C080400, // 0004 CALL R2 2 + 0x4C0C0000, // 0005 LDNIL R3 + 0x1C0C0403, // 0006 EQ R3 R2 R3 + 0x780E0000, // 0007 JMPF R3 #0009 + 0x80000600, // 0008 RET 0 + 0x600C0010, // 0009 GETGBL R3 G16 + 0x5C100400, // 000A MOVE R4 R2 + 0x7C0C0200, // 000B CALL R3 1 + 0xA8020016, // 000C EXBLK 0 #0024 + 0x5C100600, // 000D MOVE R4 R3 + 0x7C100000, // 000E CALL R4 0 + 0x88140100, // 000F GETMBR R5 R0 K0 + 0x8C140B03, // 0010 GETMET R5 R5 K3 + 0x5C1C0800, // 0011 MOVE R7 R4 + 0x7C140400, // 0012 CALL R5 2 + 0x4C180000, // 0013 LDNIL R6 + 0x20180A06, // 0014 NE R6 R5 R6 + 0x781A000C, // 0015 JMPF R6 #0023 + 0x88180104, // 0016 GETMBR R6 R0 K4 + 0x88180D05, // 0017 GETMBR R6 R6 K5 + 0x88180D06, // 0018 GETMBR R6 R6 K6 + 0x8C180D07, // 0019 GETMET R6 R6 K7 + 0x5C200A00, // 001A MOVE R8 R5 + 0x7C180400, // 001B CALL R6 2 + 0x8C180108, // 001C GETMET R6 R0 K8 + 0x5C200A00, // 001D MOVE R8 R5 + 0x7C180400, // 001E CALL R6 2 + 0x88180100, // 001F GETMBR R6 R0 K0 + 0x8C180D09, // 0020 GETMET R6 R6 K9 + 0x5C200A00, // 0021 MOVE R8 R5 + 0x7C180400, // 0022 CALL R6 2 + 0x7001FFE8, // 0023 JMP #000D + 0x580C000A, // 0024 LDCONST R3 K10 + 0xAC0C0200, // 0025 CATCH R3 1 0 + 0xB0080000, // 0026 RAISE 2 R0 R0 + 0x880C0100, // 0027 GETMBR R3 R0 K0 + 0x8C0C070B, // 0028 GETMET R3 R3 K11 + 0x7C0C0200, // 0029 CALL R3 1 + 0x80000000, // 002A 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 */ @@ -694,17 +520,16 @@ be_local_closure(Matter_Device_stop, /* name */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(stop), + /* K1 */ be_nested_str_weak(received_ack), }), - be_str_weak(stop), + be_str_weak(received_ack), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060002, // 0001 JMPF R1 #0005 - 0x88040100, // 0002 GETMBR R1 R0 K0 - 0x8C040301, // 0003 GETMET R1 R1 K1 - 0x7C040200, // 0004 CALL R1 1 - 0x80000000, // 0005 RET 0 + ( &(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 }) ) ); @@ -712,55 +537,80 @@ be_local_closure(Matter_Device_stop, /* name */ /******************************************************************** -** Solidified function: invoke_request +** Solidified function: start_root_basic_commissioning ********************************************************************/ -be_local_closure(Matter_Device_invoke_request, /* name */ +be_local_closure(Matter_Device_start_root_basic_commissioning, /* name */ be_nested_proto( - 11, /* nstack */ - 4, /* argc */ + 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[ 7]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(plugins), - /* K2 */ be_nested_str_weak(invoke_request), - /* K3 */ be_nested_str_weak(status), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(UNSUPPORTED_COMMAND), - /* K6 */ be_const_int(1), + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(PASE_TIMEOUT), + /* K2 */ be_nested_str_weak(compute_manual_pairing_code), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20Manual_X20pairing_X20code_X3A_X20_X25s_X2D_X25s_X2D_X25s), + /* K7 */ be_const_int(0), + /* K8 */ be_const_int(3), + /* K9 */ be_const_int(2147483647), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(_compute_pbkdf), + /* K12 */ be_nested_str_weak(root_passcode), + /* K13 */ be_nested_str_weak(root_iterations), + /* K14 */ be_nested_str_weak(root_salt), + /* K15 */ be_nested_str_weak(start_basic_commissioning), + /* K16 */ be_nested_str_weak(root_discriminator), + /* K17 */ be_nested_str_weak(root_w0), + /* K18 */ be_nested_str_weak(root_L), }), - be_str_weak(invoke_request), + be_str_weak(start_root_basic_commissioning), &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x58100000, // 0000 LDCONST R4 K0 - 0x6014000C, // 0001 GETGBL R5 G12 - 0x88180101, // 0002 GETMBR R6 R0 K1 - 0x7C140200, // 0003 CALL R5 1 - 0x14140805, // 0004 LT R5 R4 R5 - 0x78160011, // 0005 JMPF R5 #0018 - 0x88140101, // 0006 GETMBR R5 R0 K1 - 0x94140A04, // 0007 GETIDX R5 R5 R4 - 0x8C180B02, // 0008 GETMET R6 R5 K2 - 0x5C200200, // 0009 MOVE R8 R1 - 0x5C240400, // 000A MOVE R9 R2 - 0x5C280600, // 000B MOVE R10 R3 - 0x7C180800, // 000C CALL R6 4 - 0x4C1C0000, // 000D LDNIL R7 - 0x201C0C07, // 000E NE R7 R6 R7 - 0x741E0004, // 000F JMPT R7 #0015 - 0x881C0703, // 0010 GETMBR R7 R3 K3 - 0xB8220800, // 0011 GETNGBL R8 K4 - 0x88201105, // 0012 GETMBR R8 R8 K5 - 0x201C0E08, // 0013 NE R7 R7 R8 - 0x781E0000, // 0014 JMPF R7 #0016 - 0x80040C00, // 0015 RET 1 R6 - 0x00100906, // 0016 ADD R4 R4 K6 - 0x7001FFE8, // 0017 JMP #0001 - 0x80000000, // 0018 RET 0 + ( &(const binstruction[38]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C0C0203, // 0002 EQ R3 R1 R3 + 0x780E0000, // 0003 JMPF R3 #0005 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x8C0C0102, // 0005 GETMET R3 R0 K2 + 0x7C0C0200, // 0006 CALL R3 1 + 0xB8120600, // 0007 GETNGBL R4 K3 + 0x8C100904, // 0008 GETMET R4 R4 K4 + 0x8C180505, // 0009 GETMET R6 R2 K5 + 0x58200006, // 000A LDCONST R8 K6 + 0x40260F08, // 000B CONNECT R9 K7 K8 + 0x94240609, // 000C GETIDX R9 R3 R9 + 0x542A0003, // 000D LDINT R10 4 + 0x542E0005, // 000E LDINT R11 6 + 0x4028140B, // 000F CONNECT R10 R10 R11 + 0x9428060A, // 0010 GETIDX R10 R3 R10 + 0x542E0006, // 0011 LDINT R11 7 + 0x402C1709, // 0012 CONNECT R11 R11 K9 + 0x942C060B, // 0013 GETIDX R11 R3 R11 + 0x7C180A00, // 0014 CALL R6 5 + 0x581C000A, // 0015 LDCONST R7 K10 + 0x7C100600, // 0016 CALL R4 3 + 0x8C10010B, // 0017 GETMET R4 R0 K11 + 0x8818010C, // 0018 GETMBR R6 R0 K12 + 0x881C010D, // 0019 GETMBR R7 R0 K13 + 0x8820010E, // 001A GETMBR R8 R0 K14 + 0x7C100800, // 001B CALL R4 4 + 0x8C10010F, // 001C GETMET R4 R0 K15 + 0x5C180200, // 001D MOVE R6 R1 + 0x881C010D, // 001E GETMBR R7 R0 K13 + 0x88200110, // 001F GETMBR R8 R0 K16 + 0x8824010E, // 0020 GETMBR R9 R0 K14 + 0x88280111, // 0021 GETMBR R10 R0 K17 + 0x882C0112, // 0022 GETMBR R11 R0 K18 + 0x4C300000, // 0023 LDNIL R12 + 0x7C101000, // 0024 CALL R4 8 + 0x80000000, // 0025 RET 0 }) ) ); @@ -768,190 +618,9 @@ be_local_closure(Matter_Device_invoke_request, /* name */ /******************************************************************** -** Solidified function: start_mdns_announce_hostnames +** Solidified function: save_before_restart ********************************************************************/ -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(_start_mdns_announce), - /* 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_device_mdns), - }), - 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(_start_mdns_announce), - /* 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_device_mdns), - }), - 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[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(wifi), - /* K2 */ be_nested_str_weak(up), - /* K3 */ be_nested_str_weak(_start_mdns_announce), - /* K4 */ be_nested_str_weak(add_rule), - /* K5 */ be_nested_str_weak(Wifi_X23Connected), - /* K6 */ be_nested_str_weak(eth), - /* K7 */ 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 - 0x5C140000, // 000D MOVE R5 R0 - 0x7C040800, // 000E CALL R1 4 - 0xB8060000, // 000F GETNGBL R1 K0 - 0x8C040306, // 0010 GETMET R1 R1 K6 - 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 - 0x580C0007, // 001A LDCONST R3 K7 - 0x84100001, // 001B CLOSURE R4 P1 - 0x5C140000, // 001C MOVE R5 R0 - 0x7C040800, // 001D CALL R1 4 - 0xA0000000, // 001E CLOSE R0 - 0x80000000, // 001F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: mdns_announce_op_discovery_all_sessions -********************************************************************/ -be_local_closure(Matter_Device_mdns_announce_op_discovery_all_sessions, /* 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[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(get_deviceid), - /* K2 */ be_nested_str_weak(get_fabric), - /* K3 */ be_nested_str_weak(mdns_announce_op_discovery), - /* K4 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(mdns_announce_op_discovery_all_sessions), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x88080500, // 0002 GETMBR R2 R2 K0 - 0x7C040200, // 0003 CALL R1 1 - 0xA802000B, // 0004 EXBLK 0 #0011 - 0x5C080200, // 0005 MOVE R2 R1 - 0x7C080000, // 0006 CALL R2 0 - 0x8C0C0501, // 0007 GETMET R3 R2 K1 - 0x7C0C0200, // 0008 CALL R3 1 - 0x780E0005, // 0009 JMPF R3 #0010 - 0x8C0C0502, // 000A GETMET R3 R2 K2 - 0x7C0C0200, // 000B CALL R3 1 - 0x780E0002, // 000C JMPF R3 #0010 - 0x8C0C0103, // 000D GETMET R3 R0 K3 - 0x5C140400, // 000E MOVE R5 R2 - 0x7C0C0400, // 000F CALL R3 2 - 0x7001FFF3, // 0010 JMP #0005 - 0x58040004, // 0011 LDCONST R1 K4 - 0xAC040200, // 0012 CATCH R1 1 0 - 0xB0080000, // 0013 RAISE 2 R0 R0 - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_second -********************************************************************/ -be_local_closure(Matter_Device_every_second, /* name */ +be_local_closure(Matter_Device_save_before_restart, /* name */ be_nested_proto( 3, /* nstack */ 1, /* argc */ @@ -961,388 +630,18 @@ be_local_closure(Matter_Device_every_second, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(every_second), - /* K2 */ be_nested_str_weak(msg_handler), - }), - be_str_weak(every_second), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* 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 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Device_init, /* name */ - be_nested_proto( - 8, /* 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[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(start_udp), - /* K1 */ be_nested_str_weak(UDP_PORT), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(remove_rule), - /* K4 */ be_nested_str_weak(Wifi_X23Connected), - /* K5 */ be_nested_str_weak(matter_device_udp), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080000, // 0002 GETUPV R2 U0 - 0x88080501, // 0003 GETMBR R2 R2 K1 - 0x7C000400, // 0004 CALL R0 2 - 0xB8020400, // 0005 GETNGBL R0 K2 - 0x8C000103, // 0006 GETMET R0 R0 K3 - 0x58080004, // 0007 LDCONST R2 K4 - 0x580C0005, // 0008 LDCONST R3 K5 - 0x7C000600, // 0009 CALL R0 3 - 0x80000000, // 000A 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[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(start_udp), - /* K1 */ be_nested_str_weak(UDP_PORT), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(remove_rule), - /* K4 */ be_nested_str_weak(Eth_X23Connected), - /* K5 */ be_nested_str_weak(matter_device_udp), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080000, // 0002 GETUPV R2 U0 - 0x88080501, // 0003 GETMBR R2 R2 K1 - 0x7C000400, // 0004 CALL R0 2 - 0xB8020400, // 0005 GETNGBL R0 K2 - 0x8C000103, // 0006 GETMET R0 R0 K3 - 0x58080004, // 0007 LDCONST R2 K4 - 0x580C0005, // 0008 LDCONST R3 K5 - 0x7C000600, // 0009 CALL R0 3 - 0x80000000, // 000A RET 0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[39]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(get_option), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(MATTER_OPTION), - /* K6 */ be_nested_str_weak(UI), - /* K7 */ be_nested_str_weak(plugins), - /* K8 */ be_nested_str_weak(vendorid), - /* K9 */ be_nested_str_weak(VENDOR_ID), - /* K10 */ be_nested_str_weak(productid), - /* K11 */ be_nested_str_weak(PRODUCT_ID), - /* K12 */ be_nested_str_weak(iterations), - /* K13 */ be_nested_str_weak(PBKDF_ITERATIONS), - /* K14 */ be_nested_str_weak(load_param), - /* K15 */ be_nested_str_weak(commissioning_instance_wifi), - /* K16 */ be_nested_str_weak(random), - /* K17 */ be_nested_str_weak(tohex), - /* K18 */ be_nested_str_weak(commissioning_instance_eth), - /* K19 */ be_nested_str_weak(sessions), - /* K20 */ be_nested_str_weak(Session_Store), - /* K21 */ be_nested_str_weak(load), - /* K22 */ be_nested_str_weak(msg_handler), - /* K23 */ be_nested_str_weak(MessageHandler), - /* K24 */ be_nested_str_weak(ui), - /* K25 */ be_nested_str_weak(push), - /* K26 */ be_nested_str_weak(Plugin_core), - /* K27 */ be_nested_str_weak(Plugin_Relay), - /* K28 */ be_nested_str_weak(start_mdns_announce_hostnames), - /* K29 */ be_nested_str_weak(wifi), - /* K30 */ be_nested_str_weak(up), - /* K31 */ be_nested_str_weak(start_udp), - /* K32 */ be_nested_str_weak(UDP_PORT), - /* K33 */ be_nested_str_weak(add_rule), - /* K34 */ be_nested_str_weak(Wifi_X23Connected), - /* K35 */ be_nested_str_weak(eth), - /* K36 */ be_nested_str_weak(Eth_X23Connected), - /* K37 */ be_nested_str_weak(start_basic_commissioning), - /* K38 */ be_nested_str_weak(add_driver), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[107]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA40A0200, // 0001 IMPORT R2 K1 - 0xB80E0400, // 0002 GETNGBL R3 K2 - 0x8C0C0703, // 0003 GETMET R3 R3 K3 - 0xB8160800, // 0004 GETNGBL R5 K4 - 0x88140B05, // 0005 GETMBR R5 R5 K5 - 0x7C0C0400, // 0006 CALL R3 2 - 0x740E0004, // 0007 JMPT R3 #000D - 0xB80E0800, // 0008 GETNGBL R3 K4 - 0x8C0C0706, // 0009 GETMET R3 R3 K6 - 0x5C140000, // 000A MOVE R5 R0 - 0x7C0C0400, // 000B CALL R3 2 - 0x80000600, // 000C RET 0 - 0x600C0012, // 000D GETGBL R3 G18 - 0x7C0C0000, // 000E CALL R3 0 - 0x90020E03, // 000F SETMBR R0 K7 R3 - 0x880C0109, // 0010 GETMBR R3 R0 K9 - 0x90021003, // 0011 SETMBR R0 K8 R3 - 0x880C010B, // 0012 GETMBR R3 R0 K11 - 0x90021403, // 0013 SETMBR R0 K10 R3 - 0x880C010D, // 0014 GETMBR R3 R0 K13 - 0x90021803, // 0015 SETMBR R0 K12 R3 - 0x8C0C010E, // 0016 GETMET R3 R0 K14 - 0x7C0C0200, // 0017 CALL R3 1 - 0x8C0C0310, // 0018 GETMET R3 R1 K16 - 0x54160007, // 0019 LDINT R5 8 - 0x7C0C0400, // 001A CALL R3 2 - 0x8C0C0711, // 001B GETMET R3 R3 K17 - 0x7C0C0200, // 001C CALL R3 1 - 0x90021E03, // 001D SETMBR R0 K15 R3 - 0x8C0C0310, // 001E GETMET R3 R1 K16 - 0x54160007, // 001F LDINT R5 8 - 0x7C0C0400, // 0020 CALL R3 2 - 0x8C0C0711, // 0021 GETMET R3 R3 K17 - 0x7C0C0200, // 0022 CALL R3 1 - 0x90022403, // 0023 SETMBR R0 K18 R3 - 0xB80E0800, // 0024 GETNGBL R3 K4 - 0x8C0C0714, // 0025 GETMET R3 R3 K20 - 0x7C0C0200, // 0026 CALL R3 1 - 0x90022603, // 0027 SETMBR R0 K19 R3 - 0x880C0113, // 0028 GETMBR R3 R0 K19 - 0x8C0C0715, // 0029 GETMET R3 R3 K21 - 0x7C0C0200, // 002A CALL R3 1 - 0xB80E0800, // 002B GETNGBL R3 K4 - 0x8C0C0717, // 002C GETMET R3 R3 K23 - 0x5C140000, // 002D MOVE R5 R0 - 0x7C0C0400, // 002E CALL R3 2 - 0x90022C03, // 002F SETMBR R0 K22 R3 - 0xB80E0800, // 0030 GETNGBL R3 K4 - 0x8C0C0706, // 0031 GETMET R3 R3 K6 - 0x5C140000, // 0032 MOVE R5 R0 - 0x7C0C0400, // 0033 CALL R3 2 - 0x90023003, // 0034 SETMBR R0 K24 R3 - 0x880C0107, // 0035 GETMBR R3 R0 K7 - 0x8C0C0719, // 0036 GETMET R3 R3 K25 - 0xB8160800, // 0037 GETNGBL R5 K4 - 0x8C140B1A, // 0038 GETMET R5 R5 K26 - 0x5C1C0000, // 0039 MOVE R7 R0 - 0x7C140400, // 003A CALL R5 2 - 0x7C0C0400, // 003B CALL R3 2 - 0x880C0107, // 003C GETMBR R3 R0 K7 - 0x8C0C0719, // 003D GETMET R3 R3 K25 - 0xB8160800, // 003E GETNGBL R5 K4 - 0x8C140B1B, // 003F GETMET R5 R5 K27 - 0x5C1C0000, // 0040 MOVE R7 R0 - 0x7C140400, // 0041 CALL R5 2 - 0x7C0C0400, // 0042 CALL R3 2 - 0x8C0C011C, // 0043 GETMET R3 R0 K28 - 0x7C0C0200, // 0044 CALL R3 1 - 0xB80E0400, // 0045 GETNGBL R3 K2 - 0x8C0C071D, // 0046 GETMET R3 R3 K29 - 0x7C0C0200, // 0047 CALL R3 1 - 0x940C071E, // 0048 GETIDX R3 R3 K30 - 0x780E0003, // 0049 JMPF R3 #004E - 0x8C0C011F, // 004A GETMET R3 R0 K31 - 0x88140120, // 004B GETMBR R5 R0 K32 - 0x7C0C0400, // 004C CALL R3 2 - 0x70020005, // 004D JMP #0054 - 0xB80E0400, // 004E GETNGBL R3 K2 - 0x8C0C0721, // 004F GETMET R3 R3 K33 - 0x58140022, // 0050 LDCONST R5 K34 - 0x84180000, // 0051 CLOSURE R6 P0 - 0x5C1C0000, // 0052 MOVE R7 R0 - 0x7C0C0800, // 0053 CALL R3 4 - 0xB80E0400, // 0054 GETNGBL R3 K2 - 0x8C0C0723, // 0055 GETMET R3 R3 K35 - 0x7C0C0200, // 0056 CALL R3 1 - 0x940C071E, // 0057 GETIDX R3 R3 K30 - 0x780E0003, // 0058 JMPF R3 #005D - 0x8C0C011F, // 0059 GETMET R3 R0 K31 - 0x88140120, // 005A GETMBR R5 R0 K32 - 0x7C0C0400, // 005B CALL R3 2 - 0x70020005, // 005C JMP #0063 - 0xB80E0400, // 005D GETNGBL R3 K2 - 0x8C0C0721, // 005E GETMET R3 R3 K33 - 0x58140024, // 005F LDCONST R5 K36 - 0x84180001, // 0060 CLOSURE R6 P1 - 0x5C1C0000, // 0061 MOVE R7 R0 - 0x7C0C0800, // 0062 CALL R3 4 - 0x8C0C0125, // 0063 GETMET R3 R0 K37 - 0x7C0C0200, // 0064 CALL R3 1 - 0xB80E0400, // 0065 GETNGBL R3 K2 - 0x8C0C0726, // 0066 GETMET R3 R3 K38 - 0x5C140000, // 0067 MOVE R5 R0 - 0x7C0C0400, // 0068 CALL R3 2 - 0xA0000000, // 0069 CLOSE R0 - 0x80000000, // 006A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_basic_commissioning -********************************************************************/ -be_local_closure(Matter_Device_start_basic_commissioning, /* 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[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(compute_pbkdf), - /* K1 */ be_nested_str_weak(passcode), + /* K0 */ be_nested_str_weak(stop_basic_commissioning), + /* K1 */ be_nested_str_weak(mdns_remove_op_discovery_all_fabrics), }), - be_str_weak(start_basic_commissioning), + be_str_weak(save_before_restart), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ + ( &(const binstruction[ 5]) { /* code */ 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x7C040400, // 0002 CALL R1 2 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_operational_dicovery -********************************************************************/ -be_local_closure(Matter_Device_start_operational_dicovery, /* 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[13]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(mdns), - /* K2 */ be_nested_str_weak(string), - /* K3 */ be_nested_str_weak(salt), - /* K4 */ be_nested_str_weak(w0), - /* K5 */ be_nested_str_weak(w1), - /* K6 */ be_nested_str_weak(L), - /* K7 */ be_nested_str_weak(set_no_expiration), - /* K8 */ be_nested_str_weak(set_persist), - /* K9 */ be_nested_str_weak(close), - /* K10 */ be_nested_str_weak(sessions), - /* K11 */ be_nested_str_weak(save), - /* K12 */ be_nested_str_weak(mdns_announce_op_discovery), - }), - be_str_weak(start_operational_dicovery), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0xA4120400, // 0002 IMPORT R4 K2 - 0x4C140000, // 0003 LDNIL R5 - 0x90020605, // 0004 SETMBR R0 K3 R5 - 0x4C140000, // 0005 LDNIL R5 - 0x90020805, // 0006 SETMBR R0 K4 R5 - 0x4C140000, // 0007 LDNIL R5 - 0x90020A05, // 0008 SETMBR R0 K5 R5 - 0x4C140000, // 0009 LDNIL R5 - 0x90020C05, // 000A SETMBR R0 K6 R5 - 0x8C140307, // 000B GETMET R5 R1 K7 - 0x7C140200, // 000C CALL R5 1 - 0x8C140308, // 000D GETMET R5 R1 K8 - 0x501C0200, // 000E LDBOOL R7 1 0 - 0x7C140400, // 000F CALL R5 2 - 0x8C140309, // 0010 GETMET R5 R1 K9 - 0x7C140200, // 0011 CALL R5 1 - 0x8814010A, // 0012 GETMBR R5 R0 K10 - 0x8C140B0B, // 0013 GETMET R5 R5 K11 - 0x7C140200, // 0014 CALL R5 1 - 0x8C14010C, // 0015 GETMET R5 R0 K12 - 0x5C1C0200, // 0016 MOVE R7 R1 - 0x7C140400, // 0017 CALL R5 2 - 0x80000000, // 0018 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_commissioning_complete -********************************************************************/ -be_local_closure(Matter_Device_start_commissioning_complete, /* 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(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X20Commissioning_X20complete_X20_X2A_X2A_X2A), - /* K3 */ be_const_int(2), - }), - be_str_weak(start_commissioning_complete), - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x58100002, // 0002 LDCONST R4 K2 - 0x58140003, // 0003 LDCONST R5 K3 - 0x7C080600, // 0004 CALL R2 3 - 0x80000000, // 0005 RET 0 + 0x7C040200, // 0001 CALL R1 1 + 0x8C040101, // 0002 GETMET R1 R0 K1 + 0x7C040200, // 0003 CALL R1 1 + 0x80000000, // 0004 RET 0 }) ) ); @@ -1368,8 +667,8 @@ be_local_closure(Matter_Device_compute_qrcode_content, /* name */ /* K2 */ be_const_int(3), /* K3 */ be_nested_str_weak(vendorid), /* K4 */ be_nested_str_weak(productid), - /* K5 */ be_nested_str_weak(discriminator), - /* K6 */ be_nested_str_weak(passcode), + /* 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), @@ -1426,23 +725,2872 @@ be_local_closure(Matter_Device_compute_qrcode_content, /* name */ /******************************************************************** -** Solidified function: finish_commissioning +** Solidified function: _start_udp ********************************************************************/ -be_local_closure(Matter_Device_finish_commissioning, /* name */ +be_local_closure(Matter_Device__start_udp, /* name */ be_nested_proto( - 1, /* nstack */ + 6, /* 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[27]) { /* 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 + 0x58100007, // 0011 LDCONST R4 K7 + 0x5C140200, // 0012 MOVE R5 R1 + 0x7C080600, // 0013 CALL R2 3 + 0x90020002, // 0014 SETMBR R0 K0 R2 + 0x88080100, // 0015 GETMBR R2 R0 K0 + 0x8C080508, // 0016 GETMET R2 R2 K8 + 0x84100000, // 0017 CLOSURE R4 P0 + 0x7C080400, // 0018 CALL R2 2 + 0xA0000000, // 0019 CLOSE R0 + 0x80000000, // 001A 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: every_250ms +********************************************************************/ +be_local_closure(Matter_Device_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 */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(finish_commissioning), + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(message_handler), + /* K1 */ be_nested_str_weak(every_250ms), + }), + be_str_weak(every_250ms), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + ( &(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: process_attribute_expansion +********************************************************************/ +be_local_closure(Matter_Device_process_attribute_expansion, /* name */ + be_nested_proto( + 30, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 7, /* nstack */ + 1, /* 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(keys), + /* K1 */ be_nested_str_weak(push), + /* K2 */ be_nested_str_weak(stop_iteration), + /* K3 */ be_const_int(1), + /* K4 */ be_const_int(0), + }), + be_str_weak(keys_sorted), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x60080010, // 0002 GETGBL R2 G16 + 0x8C0C0100, // 0003 GETMET R3 R0 K0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x7C080200, // 0005 CALL R2 1 + 0xA8020005, // 0006 EXBLK 0 #000D + 0x5C0C0400, // 0007 MOVE R3 R2 + 0x7C0C0000, // 0008 CALL R3 0 + 0x8C100301, // 0009 GETMET R4 R1 K1 + 0x5C180600, // 000A MOVE R6 R3 + 0x7C100400, // 000B CALL R4 2 + 0x7001FFF9, // 000C JMP #0007 + 0x58080002, // 000D LDCONST R2 K2 + 0xAC080200, // 000E CATCH R2 1 0 + 0xB0080000, // 000F RAISE 2 R0 R0 + 0x60080010, // 0010 GETGBL R2 G16 + 0x600C000C, // 0011 GETGBL R3 G12 + 0x5C100200, // 0012 MOVE R4 R1 + 0x7C0C0200, // 0013 CALL R3 1 + 0x040C0703, // 0014 SUB R3 R3 K3 + 0x400E0603, // 0015 CONNECT R3 K3 R3 + 0x7C080200, // 0016 CALL R2 1 + 0xA8020010, // 0017 EXBLK 0 #0029 + 0x5C0C0400, // 0018 MOVE R3 R2 + 0x7C0C0000, // 0019 CALL R3 0 + 0x94100203, // 001A GETIDX R4 R1 R3 + 0x5C140600, // 001B MOVE R5 R3 + 0x24180B04, // 001C GT R6 R5 K4 + 0x781A0008, // 001D JMPF R6 #0027 + 0x04180B03, // 001E SUB R6 R5 K3 + 0x94180206, // 001F GETIDX R6 R1 R6 + 0x24180C04, // 0020 GT R6 R6 R4 + 0x781A0004, // 0021 JMPF R6 #0027 + 0x04180B03, // 0022 SUB R6 R5 K3 + 0x94180206, // 0023 GETIDX R6 R1 R6 + 0x98040A06, // 0024 SETIDX R1 R5 R6 + 0x04140B03, // 0025 SUB R5 R5 K3 + 0x7001FFF4, // 0026 JMP #001C + 0x98040A04, // 0027 SETIDX R1 R5 R4 + 0x7001FFEE, // 0028 JMP #0018 + 0x58080002, // 0029 LDCONST R2 K2 + 0xAC080200, // 002A CATCH R2 1 0 + 0xB0080000, // 002B RAISE 2 R0 R0 + 0x80040200, // 002C RET 1 R1 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[26]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(endpoint), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(attribute), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(format), + /* K7 */ be_nested_str_weak(MTR_X3A_X20process_attribute_expansion_X20_X25s), + /* K8 */ be_nested_str_weak(MTR_X3A_X20endpoint_X3D_X25s_X20cluster_X3D_X25s_X20attribute_X3D_X25s), + /* K9 */ be_nested_str_weak(plugins), + /* K10 */ be_nested_str_weak(get_endpoint), + /* K11 */ be_nested_str_weak(contains), + /* K12 */ be_nested_str_weak(get_cluster_list), + /* K13 */ be_nested_str_weak(MTR_X3A_X20pi_X3D_X25s_X20ep_X3D_X25s_X20cl_list_X3D_X25s), + /* K14 */ be_nested_str_weak(get_attribute_list), + /* K15 */ be_nested_str_weak(MTR_X3A_X20pi_X3D_X25s_X20ep_X3D_X25s_X20cl_X3D_X25s_X20at_list_X3D_X25s), + /* K16 */ be_nested_str_weak(push), + /* K17 */ be_nested_str_weak(stop_iteration), + /* K18 */ be_nested_str_weak(MTR_X3A_X20expansion_X20_X5B_X2502X_X5D_X2504X_X2F_X2504X), + /* K19 */ be_const_int(3), + /* K20 */ be_nested_str_weak(status), + /* K21 */ be_nested_str_weak(matter), + /* K22 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), + /* K23 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), + /* K24 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K25 */ be_nested_str_weak(UNREPORTABLE_ATTRIBUTE), + }), + be_str_weak(process_attribute_expansion), + &be_const_str_solidified, + ( &(const binstruction[271]) { /* code */ + 0x840C0000, // 0000 CLOSURE R3 P0 + 0xA4120000, // 0001 IMPORT R4 K0 + 0x88140301, // 0002 GETMBR R5 R1 K1 + 0x50180000, // 0003 LDBOOL R6 0 0 + 0x881C0302, // 0004 GETMBR R7 R1 K2 + 0x50200000, // 0005 LDBOOL R8 0 0 + 0x88240303, // 0006 GETMBR R9 R1 K3 + 0x50280000, // 0007 LDBOOL R10 0 0 + 0x882C0301, // 0008 GETMBR R11 R1 K1 + 0x4C300000, // 0009 LDNIL R12 + 0x202C160C, // 000A NE R11 R11 R12 + 0x782E0007, // 000B JMPF R11 #0014 + 0x882C0302, // 000C GETMBR R11 R1 K2 + 0x4C300000, // 000D LDNIL R12 + 0x202C160C, // 000E NE R11 R11 R12 + 0x782E0003, // 000F JMPF R11 #0014 + 0x882C0303, // 0010 GETMBR R11 R1 K3 + 0x4C300000, // 0011 LDNIL R12 + 0x202C160C, // 0012 NE R11 R11 R12 + 0x742E0000, // 0013 JMPT R11 #0015 + 0x502C0001, // 0014 LDBOOL R11 0 1 + 0x502C0200, // 0015 LDBOOL R11 1 0 + 0xB8320800, // 0016 GETNGBL R12 K4 + 0x8C301905, // 0017 GETMET R12 R12 K5 + 0x8C380906, // 0018 GETMET R14 R4 K6 + 0x58400007, // 0019 LDCONST R16 K7 + 0x60440008, // 001A GETGBL R17 G8 + 0x5C480200, // 001B MOVE R18 R1 + 0x7C440200, // 001C CALL R17 1 + 0x7C380600, // 001D CALL R14 3 + 0x543E0003, // 001E LDINT R15 4 + 0x7C300600, // 001F CALL R12 3 + 0x60300013, // 0020 GETGBL R12 G19 + 0x7C300000, // 0021 CALL R12 0 + 0xB8360800, // 0022 GETNGBL R13 K4 + 0x8C341B05, // 0023 GETMET R13 R13 K5 + 0x8C3C0906, // 0024 GETMET R15 R4 K6 + 0x58440008, // 0025 LDCONST R17 K8 + 0x5C480A00, // 0026 MOVE R18 R5 + 0x5C4C0E00, // 0027 MOVE R19 R7 + 0x5C501200, // 0028 MOVE R20 R9 + 0x7C3C0A00, // 0029 CALL R15 5 + 0x54420003, // 002A LDINT R16 4 + 0x7C340600, // 002B CALL R13 3 + 0x60340010, // 002C GETGBL R13 G16 + 0x88380109, // 002D GETMBR R14 R0 K9 + 0x7C340200, // 002E CALL R13 1 + 0xA8020078, // 002F EXBLK 0 #00A9 + 0x5C381A00, // 0030 MOVE R14 R13 + 0x7C380000, // 0031 CALL R14 0 + 0x8C3C1D0A, // 0032 GETMET R15 R14 K10 + 0x7C3C0200, // 0033 CALL R15 1 + 0x4C400000, // 0034 LDNIL R16 + 0x20400A10, // 0035 NE R16 R5 R16 + 0x78420002, // 0036 JMPF R16 #003A + 0x20401E05, // 0037 NE R16 R15 R5 + 0x78420000, // 0038 JMPF R16 #003A + 0x7001FFF5, // 0039 JMP #0030 + 0x8C40190B, // 003A GETMET R16 R12 K11 + 0x5C481E00, // 003B MOVE R18 R15 + 0x7C400400, // 003C CALL R16 2 + 0x74420002, // 003D JMPT R16 #0041 + 0x60400013, // 003E GETGBL R16 G19 + 0x7C400000, // 003F CALL R16 0 + 0x98301E10, // 0040 SETIDX R12 R15 R16 + 0x50180200, // 0041 LDBOOL R6 1 0 + 0x8C401D0C, // 0042 GETMET R16 R14 K12 + 0x5C481E00, // 0043 MOVE R18 R15 + 0x7C400400, // 0044 CALL R16 2 + 0xB8460800, // 0045 GETNGBL R17 K4 + 0x8C442305, // 0046 GETMET R17 R17 K5 + 0x8C4C0906, // 0047 GETMET R19 R4 K6 + 0x5854000D, // 0048 LDCONST R21 K13 + 0x60580008, // 0049 GETGBL R22 G8 + 0x5C5C1C00, // 004A MOVE R23 R14 + 0x7C580200, // 004B CALL R22 1 + 0x605C0008, // 004C GETGBL R23 G8 + 0x5C601E00, // 004D MOVE R24 R15 + 0x7C5C0200, // 004E CALL R23 1 + 0x60600008, // 004F GETGBL R24 G8 + 0x5C642000, // 0050 MOVE R25 R16 + 0x7C600200, // 0051 CALL R24 1 + 0x7C4C0A00, // 0052 CALL R19 5 + 0x54520003, // 0053 LDINT R20 4 + 0x7C440600, // 0054 CALL R17 3 + 0x60440010, // 0055 GETGBL R17 G16 + 0x5C482000, // 0056 MOVE R18 R16 + 0x7C440200, // 0057 CALL R17 1 + 0xA802004B, // 0058 EXBLK 0 #00A5 + 0x5C482200, // 0059 MOVE R18 R17 + 0x7C480000, // 005A CALL R18 0 + 0x4C4C0000, // 005B LDNIL R19 + 0x204C0E13, // 005C NE R19 R7 R19 + 0x784E0002, // 005D JMPF R19 #0061 + 0x204C2407, // 005E NE R19 R18 R7 + 0x784E0000, // 005F JMPF R19 #0061 + 0x7001FFF7, // 0060 JMP #0059 + 0x944C180F, // 0061 GETIDX R19 R12 R15 + 0x8C4C270B, // 0062 GETMET R19 R19 K11 + 0x5C542400, // 0063 MOVE R21 R18 + 0x7C4C0400, // 0064 CALL R19 2 + 0x744E0003, // 0065 JMPT R19 #006A + 0x944C180F, // 0066 GETIDX R19 R12 R15 + 0x60500013, // 0067 GETGBL R20 G19 + 0x7C500000, // 0068 CALL R20 0 + 0x984C2414, // 0069 SETIDX R19 R18 R20 + 0x50200200, // 006A LDBOOL R8 1 0 + 0x8C4C1D0E, // 006B GETMET R19 R14 K14 + 0x5C541E00, // 006C MOVE R21 R15 + 0x5C582400, // 006D MOVE R22 R18 + 0x7C4C0600, // 006E CALL R19 3 + 0xB8520800, // 006F GETNGBL R20 K4 + 0x8C502905, // 0070 GETMET R20 R20 K5 + 0x8C580906, // 0071 GETMET R22 R4 K6 + 0x5860000F, // 0072 LDCONST R24 K15 + 0x60640008, // 0073 GETGBL R25 G8 + 0x5C681C00, // 0074 MOVE R26 R14 + 0x7C640200, // 0075 CALL R25 1 + 0x60680008, // 0076 GETGBL R26 G8 + 0x5C6C1E00, // 0077 MOVE R27 R15 + 0x7C680200, // 0078 CALL R26 1 + 0x606C0008, // 0079 GETGBL R27 G8 + 0x5C702400, // 007A MOVE R28 R18 + 0x7C6C0200, // 007B CALL R27 1 + 0x60700008, // 007C GETGBL R28 G8 + 0x5C742600, // 007D MOVE R29 R19 + 0x7C700200, // 007E CALL R28 1 + 0x7C580C00, // 007F CALL R22 6 + 0x545E0003, // 0080 LDINT R23 4 + 0x7C500600, // 0081 CALL R20 3 + 0x60500010, // 0082 GETGBL R20 G16 + 0x5C542600, // 0083 MOVE R21 R19 + 0x7C500200, // 0084 CALL R20 1 + 0xA802001A, // 0085 EXBLK 0 #00A1 + 0x5C542800, // 0086 MOVE R21 R20 + 0x7C540000, // 0087 CALL R21 0 + 0x4C580000, // 0088 LDNIL R22 + 0x20581216, // 0089 NE R22 R9 R22 + 0x785A0002, // 008A JMPF R22 #008E + 0x20582A09, // 008B NE R22 R21 R9 + 0x785A0000, // 008C JMPF R22 #008E + 0x7001FFF7, // 008D JMP #0086 + 0x9458180F, // 008E GETIDX R22 R12 R15 + 0x94582C12, // 008F GETIDX R22 R22 R18 + 0x8C582D0B, // 0090 GETMET R22 R22 K11 + 0x5C602A00, // 0091 MOVE R24 R21 + 0x7C580400, // 0092 CALL R22 2 + 0x745A0004, // 0093 JMPT R22 #0099 + 0x9458180F, // 0094 GETIDX R22 R12 R15 + 0x94582C12, // 0095 GETIDX R22 R22 R18 + 0x605C0012, // 0096 GETGBL R23 G18 + 0x7C5C0000, // 0097 CALL R23 0 + 0x98582A17, // 0098 SETIDX R22 R21 R23 + 0x50280200, // 0099 LDBOOL R10 1 0 + 0x9458180F, // 009A GETIDX R22 R12 R15 + 0x94582C12, // 009B GETIDX R22 R22 R18 + 0x94582C15, // 009C GETIDX R22 R22 R21 + 0x8C582D10, // 009D GETMET R22 R22 K16 + 0x5C601C00, // 009E MOVE R24 R14 + 0x7C580400, // 009F CALL R22 2 + 0x7001FFE4, // 00A0 JMP #0086 + 0x58500011, // 00A1 LDCONST R20 K17 + 0xAC500200, // 00A2 CATCH R20 1 0 + 0xB0080000, // 00A3 RAISE 2 R0 R0 + 0x7001FFB3, // 00A4 JMP #0059 + 0x58440011, // 00A5 LDCONST R17 K17 + 0xAC440200, // 00A6 CATCH R17 1 0 + 0xB0080000, // 00A7 RAISE 2 R0 R0 + 0x7001FF86, // 00A8 JMP #0030 + 0x58340011, // 00A9 LDCONST R13 K17 + 0xAC340200, // 00AA CATCH R13 1 0 + 0xB0080000, // 00AB RAISE 2 R0 R0 + 0x60340010, // 00AC GETGBL R13 G16 + 0x5C380600, // 00AD MOVE R14 R3 + 0x5C3C1800, // 00AE MOVE R15 R12 + 0x7C380200, // 00AF CALL R14 1 + 0x7C340200, // 00B0 CALL R13 1 + 0xA802003D, // 00B1 EXBLK 0 #00F0 + 0x5C381A00, // 00B2 MOVE R14 R13 + 0x7C380000, // 00B3 CALL R14 0 + 0x603C0010, // 00B4 GETGBL R15 G16 + 0x5C400600, // 00B5 MOVE R16 R3 + 0x9444180E, // 00B6 GETIDX R17 R12 R14 + 0x7C400200, // 00B7 CALL R16 1 + 0x7C3C0200, // 00B8 CALL R15 1 + 0xA8020031, // 00B9 EXBLK 0 #00EC + 0x5C401E00, // 00BA MOVE R16 R15 + 0x7C400000, // 00BB CALL R16 0 + 0x60440010, // 00BC GETGBL R17 G16 + 0x5C480600, // 00BD MOVE R18 R3 + 0x944C180E, // 00BE GETIDX R19 R12 R14 + 0x944C2610, // 00BF GETIDX R19 R19 R16 + 0x7C480200, // 00C0 CALL R18 1 + 0x7C440200, // 00C1 CALL R17 1 + 0xA8020024, // 00C2 EXBLK 0 #00E8 + 0x5C482200, // 00C3 MOVE R18 R17 + 0x7C480000, // 00C4 CALL R18 0 + 0x604C0010, // 00C5 GETGBL R19 G16 + 0x9450180E, // 00C6 GETIDX R20 R12 R14 + 0x94502810, // 00C7 GETIDX R20 R20 R16 + 0x94502812, // 00C8 GETIDX R20 R20 R18 + 0x7C4C0200, // 00C9 CALL R19 1 + 0xA8020018, // 00CA EXBLK 0 #00E4 + 0x5C502600, // 00CB MOVE R20 R19 + 0x7C500000, // 00CC CALL R20 0 + 0xB8560800, // 00CD GETNGBL R21 K4 + 0x8C542B05, // 00CE GETMET R21 R21 K5 + 0x8C5C0906, // 00CF GETMET R23 R4 K6 + 0x58640012, // 00D0 LDCONST R25 K18 + 0x5C681C00, // 00D1 MOVE R26 R14 + 0x5C6C2000, // 00D2 MOVE R27 R16 + 0x5C702400, // 00D3 MOVE R28 R18 + 0x7C5C0A00, // 00D4 CALL R23 5 + 0x58600013, // 00D5 LDCONST R24 K19 + 0x7C540600, // 00D6 CALL R21 3 + 0x9006020E, // 00D7 SETMBR R1 K1 R14 + 0x90060410, // 00D8 SETMBR R1 K2 R16 + 0x90060612, // 00D9 SETMBR R1 K3 R18 + 0x5C540400, // 00DA MOVE R21 R2 + 0x5C582800, // 00DB MOVE R22 R20 + 0x5C5C0200, // 00DC MOVE R23 R1 + 0x5C601600, // 00DD MOVE R24 R11 + 0x7C540600, // 00DE CALL R21 3 + 0x782E0002, // 00DF JMPF R11 #00E3 + 0x78560001, // 00E0 JMPF R21 #00E3 + 0xA8040004, // 00E1 EXBLK 1 4 + 0x80002C00, // 00E2 RET 0 + 0x7001FFE6, // 00E3 JMP #00CB + 0x584C0011, // 00E4 LDCONST R19 K17 + 0xAC4C0200, // 00E5 CATCH R19 1 0 + 0xB0080000, // 00E6 RAISE 2 R0 R0 + 0x7001FFDA, // 00E7 JMP #00C3 + 0x58440011, // 00E8 LDCONST R17 K17 + 0xAC440200, // 00E9 CATCH R17 1 0 + 0xB0080000, // 00EA RAISE 2 R0 R0 + 0x7001FFCD, // 00EB JMP #00BA + 0x583C0011, // 00EC LDCONST R15 K17 + 0xAC3C0200, // 00ED CATCH R15 1 0 + 0xB0080000, // 00EE RAISE 2 R0 R0 + 0x7001FFC1, // 00EF JMP #00B2 + 0x58340011, // 00F0 LDCONST R13 K17 + 0xAC340200, // 00F1 CATCH R13 1 0 + 0xB0080000, // 00F2 RAISE 2 R0 R0 + 0x782E0019, // 00F3 JMPF R11 #010E + 0x5C340C00, // 00F4 MOVE R13 R6 + 0x74360003, // 00F5 JMPT R13 #00FA + 0xB8362A00, // 00F6 GETNGBL R13 K21 + 0x88341B16, // 00F7 GETMBR R13 R13 K22 + 0x9006280D, // 00F8 SETMBR R1 K20 R13 + 0x7002000E, // 00F9 JMP #0109 + 0x5C341000, // 00FA MOVE R13 R8 + 0x74360003, // 00FB JMPT R13 #0100 + 0xB8362A00, // 00FC GETNGBL R13 K21 + 0x88341B17, // 00FD GETMBR R13 R13 K23 + 0x9006280D, // 00FE SETMBR R1 K20 R13 + 0x70020008, // 00FF JMP #0109 + 0x5C341400, // 0100 MOVE R13 R10 + 0x74360003, // 0101 JMPT R13 #0106 + 0xB8362A00, // 0102 GETNGBL R13 K21 + 0x88341B18, // 0103 GETMBR R13 R13 K24 + 0x9006280D, // 0104 SETMBR R1 K20 R13 + 0x70020002, // 0105 JMP #0109 + 0xB8362A00, // 0106 GETNGBL R13 K21 + 0x88341B19, // 0107 GETMBR R13 R13 K25 + 0x9006280D, // 0108 SETMBR R1 K20 R13 + 0x5C340400, // 0109 MOVE R13 R2 + 0x4C380000, // 010A LDNIL R14 + 0x5C3C0200, // 010B MOVE R15 R1 + 0x50400200, // 010C LDBOOL R16 1 0 + 0x7C340600, // 010D CALL R13 3 + 0x80000000, // 010E 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[17]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(dump), + /* K2 */ be_nested_str_weak(distinguish), + /* K3 */ be_nested_str_weak(root_discriminator), + /* K4 */ be_nested_str_weak(passcode), + /* K5 */ be_nested_str_weak(root_passcode), + /* K6 */ be_nested_str_weak(ipv4only), + /* K7 */ be_nested_str_weak(string), + /* K8 */ be_nested_str_weak(FILENAME), + /* K9 */ be_nested_str_weak(w), + /* K10 */ be_nested_str_weak(write), + /* K11 */ be_nested_str_weak(close), + /* K12 */ be_nested_str_weak(tasmota), + /* K13 */ be_nested_str_weak(log), + /* K14 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K15 */ be_nested_str_weak(_X7C), + /* K16 */ be_const_int(2), + }), + be_str_weak(save_param), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x60100013, // 0002 GETGBL R4 G19 + 0x7C100000, // 0003 CALL R4 0 + 0x88140103, // 0004 GETMBR R5 R0 K3 + 0x98120405, // 0005 SETIDX R4 K2 R5 + 0x88140105, // 0006 GETMBR R5 R0 K5 + 0x98120805, // 0007 SETIDX R4 K4 R5 + 0x88140106, // 0008 GETMBR R5 R0 K6 + 0x98120C05, // 0009 SETIDX R4 K6 R5 + 0x7C080400, // 000A CALL R2 2 + 0xA802000D, // 000B EXBLK 0 #001A + 0xA40E0E00, // 000C IMPORT R3 K7 + 0x60100011, // 000D GETGBL R4 G17 + 0x88140108, // 000E GETMBR R5 R0 K8 + 0x58180009, // 000F LDCONST R6 K9 + 0x7C100400, // 0010 CALL R4 2 + 0x8C14090A, // 0011 GETMET R5 R4 K10 + 0x5C1C0400, // 0012 MOVE R7 R2 + 0x7C140400, // 0013 CALL R5 2 + 0x8C14090B, // 0014 GETMET R5 R4 K11 + 0x7C140200, // 0015 CALL R5 1 + 0xA8040001, // 0016 EXBLK 1 1 + 0x80040400, // 0017 RET 1 R2 + 0xA8040001, // 0018 EXBLK 1 1 + 0x70020011, // 0019 JMP #002C + 0xAC0C0002, // 001A CATCH R3 0 2 + 0x7002000E, // 001B JMP #002B + 0xB8161800, // 001C GETNGBL R5 K12 + 0x8C140B0D, // 001D GETMET R5 R5 K13 + 0x601C0008, // 001E GETGBL R7 G8 + 0x5C200600, // 001F MOVE R8 R3 + 0x7C1C0200, // 0020 CALL R7 1 + 0x001E1C07, // 0021 ADD R7 K14 R7 + 0x001C0F0F, // 0022 ADD R7 R7 K15 + 0x60200008, // 0023 GETGBL R8 G8 + 0x5C240800, // 0024 MOVE R9 R4 + 0x7C200200, // 0025 CALL R8 1 + 0x001C0E08, // 0026 ADD R7 R7 R8 + 0x58200010, // 0027 LDCONST R8 K16 + 0x7C140600, // 0028 CALL R5 3 + 0x80040400, // 0029 RET 1 R2 + 0x70020000, // 002A JMP #002C + 0xB0080000, // 002B RAISE 2 R0 R0 + 0x80000000, // 002C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_announce_PASE +********************************************************************/ +be_local_closure(Matter_Device_mdns_announce_PASE, /* name */ + be_nested_proto( + 16, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[44]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(VP), + /* K4 */ be_nested_str_weak(vendorid), + /* K5 */ be_nested_str_weak(_X2B), + /* K6 */ be_nested_str_weak(productid), + /* K7 */ be_nested_str_weak(D), + /* K8 */ be_nested_str_weak(commissioning_discriminator), + /* K9 */ be_nested_str_weak(CM), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_str_weak(T), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_str_weak(SII), + /* K14 */ be_nested_str_weak(SAI), + /* K15 */ be_nested_str_weak(commissioning_instance_wifi), + /* K16 */ be_nested_str_weak(random), + /* K17 */ be_nested_str_weak(tohex), + /* K18 */ be_nested_str_weak(commissioning_instance_eth), + /* K19 */ be_nested_str_weak(hostname_eth), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(log), + /* K22 */ be_nested_str_weak(format), + /* K23 */ be_nested_str_weak(MTR_X3A_X20calling_X20mdns_X2Eadd_service_X28_X25s_X2C_X20_X25s_X2C_X20_X25i_X2C_X20_X25s_X2C_X20_X25s_X2C_X20_X25s_X29), + /* K24 */ be_nested_str_weak(_matterc), + /* K25 */ be_nested_str_weak(_udp), + /* K26 */ be_const_int(3), + /* K27 */ be_nested_str_weak(add_service), + /* K28 */ be_nested_str_weak(mdns_pase_eth), + /* K29 */ be_nested_str_weak(MTR_X3A_X20announce_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), + /* K30 */ be_nested_str_weak(eth), + /* K31 */ be_const_int(2), + /* K32 */ be_nested_str_weak(_L), + /* K33 */ be_nested_str_weak(MTR_X3A_X20adding_X20subtype_X3A_X20), + /* K34 */ be_nested_str_weak(add_subtype), + /* K35 */ be_nested_str_weak(_S), + /* K36 */ be_nested_str_weak(_V), + /* K37 */ be_nested_str_weak(_CM1), + /* K38 */ be_nested_str_weak(hostname_wifi), + /* K39 */ be_nested_str_weak(mdns_pase_wifi), + /* K40 */ be_nested_str_weak(MTR_X3A_X20starting_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), + /* K41 */ be_nested_str_weak(wifi), + /* K42 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K43 */ be_nested_str_weak(_X7C), + }), + be_str_weak(mdns_announce_PASE), + &be_const_str_solidified, + ( &(const binstruction[267]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA40E0400, // 0002 IMPORT R3 K2 + 0x60100013, // 0003 GETGBL R4 G19 + 0x7C100000, // 0004 CALL R4 0 + 0x60140008, // 0005 GETGBL R5 G8 + 0x88180104, // 0006 GETMBR R6 R0 K4 + 0x7C140200, // 0007 CALL R5 1 + 0x00140B05, // 0008 ADD R5 R5 K5 + 0x60180008, // 0009 GETGBL R6 G8 + 0x881C0106, // 000A GETMBR R7 R0 K6 + 0x7C180200, // 000B CALL R6 1 + 0x00140A06, // 000C ADD R5 R5 R6 + 0x98120605, // 000D SETIDX R4 K3 R5 + 0x88140108, // 000E GETMBR R5 R0 K8 + 0x98120E05, // 000F SETIDX R4 K7 R5 + 0x9812130A, // 0010 SETIDX R4 K9 K10 + 0x9812170C, // 0011 SETIDX R4 K11 K12 + 0x54161387, // 0012 LDINT R5 5000 + 0x98121A05, // 0013 SETIDX R4 K13 R5 + 0x5416012B, // 0014 LDINT R5 300 + 0x98121C05, // 0015 SETIDX R4 K14 R5 + 0x8C140710, // 0016 GETMET R5 R3 K16 + 0x541E0007, // 0017 LDINT R7 8 + 0x7C140400, // 0018 CALL R5 2 + 0x8C140B11, // 0019 GETMET R5 R5 K17 + 0x7C140200, // 001A CALL R5 1 + 0x90021E05, // 001B SETMBR R0 K15 R5 + 0x8C140710, // 001C GETMET R5 R3 K16 + 0x541E0007, // 001D LDINT R7 8 + 0x7C140400, // 001E CALL R5 2 + 0x8C140B11, // 001F GETMET R5 R5 K17 + 0x7C140200, // 0020 CALL R5 1 + 0x90022405, // 0021 SETMBR R0 K18 R5 + 0xA80200D5, // 0022 EXBLK 0 #00F9 + 0x88140113, // 0023 GETMBR R5 R0 K19 + 0x78160067, // 0024 JMPF R5 #008D + 0xB8162800, // 0025 GETNGBL R5 K20 + 0x8C140B15, // 0026 GETMET R5 R5 K21 + 0x8C1C0516, // 0027 GETMET R7 R2 K22 + 0x58240017, // 0028 LDCONST R9 K23 + 0x58280018, // 0029 LDCONST R10 K24 + 0x582C0019, // 002A LDCONST R11 K25 + 0x543215A3, // 002B LDINT R12 5540 + 0x60340008, // 002C GETGBL R13 G8 + 0x5C380800, // 002D MOVE R14 R4 + 0x7C340200, // 002E CALL R13 1 + 0x88380112, // 002F GETMBR R14 R0 K18 + 0x883C0113, // 0030 GETMBR R15 R0 K19 + 0x7C1C1000, // 0031 CALL R7 8 + 0x5820001A, // 0032 LDCONST R8 K26 + 0x7C140600, // 0033 CALL R5 3 + 0x8C14031B, // 0034 GETMET R5 R1 K27 + 0x581C0018, // 0035 LDCONST R7 K24 + 0x58200019, // 0036 LDCONST R8 K25 + 0x542615A3, // 0037 LDINT R9 5540 + 0x5C280800, // 0038 MOVE R10 R4 + 0x882C0112, // 0039 GETMBR R11 R0 K18 + 0x88300113, // 003A GETMBR R12 R0 K19 + 0x7C140E00, // 003B CALL R5 7 + 0x50140200, // 003C LDBOOL R5 1 0 + 0x90023805, // 003D SETMBR R0 K28 R5 + 0xB8162800, // 003E GETNGBL R5 K20 + 0x8C140B15, // 003F GETMET R5 R5 K21 + 0x8C1C0516, // 0040 GETMET R7 R2 K22 + 0x5824001D, // 0041 LDCONST R9 K29 + 0x5828001E, // 0042 LDCONST R10 K30 + 0x882C0112, // 0043 GETMBR R11 R0 K18 + 0x88300113, // 0044 GETMBR R12 R0 K19 + 0x7C1C0A00, // 0045 CALL R7 5 + 0x5820001F, // 0046 LDCONST R8 K31 + 0x7C140600, // 0047 CALL R5 3 + 0x60140008, // 0048 GETGBL R5 G8 + 0x88180108, // 0049 GETMBR R6 R0 K8 + 0x541E0FFE, // 004A LDINT R7 4095 + 0x2C180C07, // 004B AND R6 R6 R7 + 0x7C140200, // 004C CALL R5 1 + 0x00164005, // 004D ADD R5 K32 R5 + 0xB81A2800, // 004E GETNGBL R6 K20 + 0x8C180D15, // 004F GETMET R6 R6 K21 + 0x00224205, // 0050 ADD R8 K33 R5 + 0x5824001F, // 0051 LDCONST R9 K31 + 0x7C180600, // 0052 CALL R6 3 + 0x8C180322, // 0053 GETMET R6 R1 K34 + 0x58200018, // 0054 LDCONST R8 K24 + 0x58240019, // 0055 LDCONST R9 K25 + 0x88280112, // 0056 GETMBR R10 R0 K18 + 0x882C0113, // 0057 GETMBR R11 R0 K19 + 0x5C300A00, // 0058 MOVE R12 R5 + 0x7C180C00, // 0059 CALL R6 6 + 0x60180008, // 005A GETGBL R6 G8 + 0x881C0108, // 005B GETMBR R7 R0 K8 + 0x54220EFF, // 005C LDINT R8 3840 + 0x2C1C0E08, // 005D AND R7 R7 R8 + 0x54220007, // 005E LDINT R8 8 + 0x3C1C0E08, // 005F SHR R7 R7 R8 + 0x7C180200, // 0060 CALL R6 1 + 0x001A4606, // 0061 ADD R6 K35 R6 + 0x5C140C00, // 0062 MOVE R5 R6 + 0xB81A2800, // 0063 GETNGBL R6 K20 + 0x8C180D15, // 0064 GETMET R6 R6 K21 + 0x00224205, // 0065 ADD R8 K33 R5 + 0x5824001F, // 0066 LDCONST R9 K31 + 0x7C180600, // 0067 CALL R6 3 + 0x8C180322, // 0068 GETMET R6 R1 K34 + 0x58200018, // 0069 LDCONST R8 K24 + 0x58240019, // 006A LDCONST R9 K25 + 0x88280112, // 006B GETMBR R10 R0 K18 + 0x882C0113, // 006C GETMBR R11 R0 K19 + 0x5C300A00, // 006D MOVE R12 R5 + 0x7C180C00, // 006E CALL R6 6 + 0x60180008, // 006F GETGBL R6 G8 + 0x881C0104, // 0070 GETMBR R7 R0 K4 + 0x7C180200, // 0071 CALL R6 1 + 0x001A4806, // 0072 ADD R6 K36 R6 + 0x5C140C00, // 0073 MOVE R5 R6 + 0xB81A2800, // 0074 GETNGBL R6 K20 + 0x8C180D15, // 0075 GETMET R6 R6 K21 + 0x00224205, // 0076 ADD R8 K33 R5 + 0x5824001F, // 0077 LDCONST R9 K31 + 0x7C180600, // 0078 CALL R6 3 + 0x8C180322, // 0079 GETMET R6 R1 K34 + 0x58200018, // 007A LDCONST R8 K24 + 0x58240019, // 007B LDCONST R9 K25 + 0x88280112, // 007C GETMBR R10 R0 K18 + 0x882C0113, // 007D GETMBR R11 R0 K19 + 0x5C300A00, // 007E MOVE R12 R5 + 0x7C180C00, // 007F CALL R6 6 + 0x58140025, // 0080 LDCONST R5 K37 + 0xB81A2800, // 0081 GETNGBL R6 K20 + 0x8C180D15, // 0082 GETMET R6 R6 K21 + 0x00224205, // 0083 ADD R8 K33 R5 + 0x5824001F, // 0084 LDCONST R9 K31 + 0x7C180600, // 0085 CALL R6 3 + 0x8C180322, // 0086 GETMET R6 R1 K34 + 0x58200018, // 0087 LDCONST R8 K24 + 0x58240019, // 0088 LDCONST R9 K25 + 0x88280112, // 0089 GETMBR R10 R0 K18 + 0x882C0113, // 008A GETMBR R11 R0 K19 + 0x5C300A00, // 008B MOVE R12 R5 + 0x7C180C00, // 008C CALL R6 6 + 0x88140126, // 008D GETMBR R5 R0 K38 + 0x78160067, // 008E JMPF R5 #00F7 + 0xB8162800, // 008F GETNGBL R5 K20 + 0x8C140B15, // 0090 GETMET R5 R5 K21 + 0x8C1C0516, // 0091 GETMET R7 R2 K22 + 0x58240017, // 0092 LDCONST R9 K23 + 0x58280018, // 0093 LDCONST R10 K24 + 0x582C0019, // 0094 LDCONST R11 K25 + 0x543215A3, // 0095 LDINT R12 5540 + 0x60340008, // 0096 GETGBL R13 G8 + 0x5C380800, // 0097 MOVE R14 R4 + 0x7C340200, // 0098 CALL R13 1 + 0x8838010F, // 0099 GETMBR R14 R0 K15 + 0x883C0126, // 009A GETMBR R15 R0 K38 + 0x7C1C1000, // 009B CALL R7 8 + 0x5820001A, // 009C LDCONST R8 K26 + 0x7C140600, // 009D CALL R5 3 + 0x8C14031B, // 009E GETMET R5 R1 K27 + 0x581C0018, // 009F LDCONST R7 K24 + 0x58200019, // 00A0 LDCONST R8 K25 + 0x542615A3, // 00A1 LDINT R9 5540 + 0x5C280800, // 00A2 MOVE R10 R4 + 0x882C010F, // 00A3 GETMBR R11 R0 K15 + 0x88300126, // 00A4 GETMBR R12 R0 K38 + 0x7C140E00, // 00A5 CALL R5 7 + 0x50140200, // 00A6 LDBOOL R5 1 0 + 0x90024E05, // 00A7 SETMBR R0 K39 R5 + 0xB8162800, // 00A8 GETNGBL R5 K20 + 0x8C140B15, // 00A9 GETMET R5 R5 K21 + 0x8C1C0516, // 00AA GETMET R7 R2 K22 + 0x58240028, // 00AB LDCONST R9 K40 + 0x58280029, // 00AC LDCONST R10 K41 + 0x882C010F, // 00AD GETMBR R11 R0 K15 + 0x88300126, // 00AE GETMBR R12 R0 K38 + 0x7C1C0A00, // 00AF CALL R7 5 + 0x5820001F, // 00B0 LDCONST R8 K31 + 0x7C140600, // 00B1 CALL R5 3 + 0x60140008, // 00B2 GETGBL R5 G8 + 0x88180108, // 00B3 GETMBR R6 R0 K8 + 0x541E0FFE, // 00B4 LDINT R7 4095 + 0x2C180C07, // 00B5 AND R6 R6 R7 + 0x7C140200, // 00B6 CALL R5 1 + 0x00164005, // 00B7 ADD R5 K32 R5 + 0xB81A2800, // 00B8 GETNGBL R6 K20 + 0x8C180D15, // 00B9 GETMET R6 R6 K21 + 0x00224205, // 00BA ADD R8 K33 R5 + 0x5824001F, // 00BB LDCONST R9 K31 + 0x7C180600, // 00BC CALL R6 3 + 0x8C180322, // 00BD GETMET R6 R1 K34 + 0x58200018, // 00BE LDCONST R8 K24 + 0x58240019, // 00BF LDCONST R9 K25 + 0x8828010F, // 00C0 GETMBR R10 R0 K15 + 0x882C0126, // 00C1 GETMBR R11 R0 K38 + 0x5C300A00, // 00C2 MOVE R12 R5 + 0x7C180C00, // 00C3 CALL R6 6 + 0x60180008, // 00C4 GETGBL R6 G8 + 0x881C0108, // 00C5 GETMBR R7 R0 K8 + 0x54220EFF, // 00C6 LDINT R8 3840 + 0x2C1C0E08, // 00C7 AND R7 R7 R8 + 0x54220007, // 00C8 LDINT R8 8 + 0x3C1C0E08, // 00C9 SHR R7 R7 R8 + 0x7C180200, // 00CA CALL R6 1 + 0x001A4606, // 00CB ADD R6 K35 R6 + 0x5C140C00, // 00CC MOVE R5 R6 + 0xB81A2800, // 00CD GETNGBL R6 K20 + 0x8C180D15, // 00CE GETMET R6 R6 K21 + 0x00224205, // 00CF ADD R8 K33 R5 + 0x5824001F, // 00D0 LDCONST R9 K31 + 0x7C180600, // 00D1 CALL R6 3 + 0x8C180322, // 00D2 GETMET R6 R1 K34 + 0x58200018, // 00D3 LDCONST R8 K24 + 0x58240019, // 00D4 LDCONST R9 K25 + 0x8828010F, // 00D5 GETMBR R10 R0 K15 + 0x882C0126, // 00D6 GETMBR R11 R0 K38 + 0x5C300A00, // 00D7 MOVE R12 R5 + 0x7C180C00, // 00D8 CALL R6 6 + 0x60180008, // 00D9 GETGBL R6 G8 + 0x881C0104, // 00DA GETMBR R7 R0 K4 + 0x7C180200, // 00DB CALL R6 1 + 0x001A4806, // 00DC ADD R6 K36 R6 + 0x5C140C00, // 00DD MOVE R5 R6 + 0xB81A2800, // 00DE GETNGBL R6 K20 + 0x8C180D15, // 00DF GETMET R6 R6 K21 + 0x00224205, // 00E0 ADD R8 K33 R5 + 0x5824001F, // 00E1 LDCONST R9 K31 + 0x7C180600, // 00E2 CALL R6 3 + 0x8C180322, // 00E3 GETMET R6 R1 K34 + 0x58200018, // 00E4 LDCONST R8 K24 + 0x58240019, // 00E5 LDCONST R9 K25 + 0x8828010F, // 00E6 GETMBR R10 R0 K15 + 0x882C0126, // 00E7 GETMBR R11 R0 K38 + 0x5C300A00, // 00E8 MOVE R12 R5 + 0x7C180C00, // 00E9 CALL R6 6 + 0x58140025, // 00EA LDCONST R5 K37 + 0xB81A2800, // 00EB GETNGBL R6 K20 + 0x8C180D15, // 00EC GETMET R6 R6 K21 + 0x00224205, // 00ED ADD R8 K33 R5 + 0x5824001F, // 00EE LDCONST R9 K31 + 0x7C180600, // 00EF CALL R6 3 + 0x8C180322, // 00F0 GETMET R6 R1 K34 + 0x58200018, // 00F1 LDCONST R8 K24 + 0x58240019, // 00F2 LDCONST R9 K25 + 0x8828010F, // 00F3 GETMBR R10 R0 K15 + 0x882C0126, // 00F4 GETMBR R11 R0 K38 + 0x5C300A00, // 00F5 MOVE R12 R5 + 0x7C180C00, // 00F6 CALL R6 6 + 0xA8040001, // 00F7 EXBLK 1 1 + 0x70020010, // 00F8 JMP #010A + 0xAC140002, // 00F9 CATCH R5 0 2 + 0x7002000D, // 00FA JMP #0109 + 0xB81E2800, // 00FB GETNGBL R7 K20 + 0x8C1C0F15, // 00FC GETMET R7 R7 K21 + 0x60240008, // 00FD GETGBL R9 G8 + 0x5C280A00, // 00FE MOVE R10 R5 + 0x7C240200, // 00FF CALL R9 1 + 0x00265409, // 0100 ADD R9 K42 R9 + 0x0024132B, // 0101 ADD R9 R9 K43 + 0x60280008, // 0102 GETGBL R10 G8 + 0x5C2C0C00, // 0103 MOVE R11 R6 + 0x7C280200, // 0104 CALL R10 1 + 0x0024120A, // 0105 ADD R9 R9 R10 + 0x5828001F, // 0106 LDCONST R10 K31 + 0x7C1C0600, // 0107 CALL R7 3 + 0x70020000, // 0108 JMP #010A + 0xB0080000, // 0109 RAISE 2 R0 R0 + 0x80000000, // 010A 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: init +********************************************************************/ +be_local_closure(Matter_Device_init, /* name */ + be_nested_proto( + 8, /* 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[35]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(get_option), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(MATTER_OPTION), + /* K6 */ be_nested_str_weak(UI), + /* K7 */ be_nested_str_weak(started), + /* K8 */ be_nested_str_weak(plugins), + /* K9 */ be_nested_str_weak(vendorid), + /* K10 */ be_nested_str_weak(VENDOR_ID), + /* K11 */ be_nested_str_weak(productid), + /* K12 */ be_nested_str_weak(PRODUCT_ID), + /* K13 */ be_nested_str_weak(root_iterations), + /* K14 */ be_nested_str_weak(PBKDF_ITERATIONS), + /* K15 */ be_nested_str_weak(root_salt), + /* K16 */ be_nested_str_weak(random), + /* K17 */ be_nested_str_weak(ipv4only), + /* K18 */ be_nested_str_weak(load_param), + /* K19 */ be_nested_str_weak(sessions), + /* K20 */ be_nested_str_weak(Session_Store), + /* K21 */ be_nested_str_weak(load_fabrics), + /* K22 */ be_nested_str_weak(message_handler), + /* K23 */ be_nested_str_weak(MessageHandler), + /* K24 */ be_nested_str_weak(ui), + /* K25 */ be_nested_str_weak(wifi), + /* K26 */ be_nested_str_weak(up), + /* K27 */ be_nested_str_weak(eth), + /* K28 */ be_nested_str_weak(start), + /* K29 */ be_nested_str_weak(add_rule), + /* K30 */ be_nested_str_weak(Wifi_X23Connected), + /* K31 */ be_nested_str_weak(matter_start), + /* K32 */ be_nested_str_weak(Eth_X23Connected), + /* K33 */ be_nested_str_weak(_init_basic_commissioning), + /* K34 */ be_nested_str_weak(add_driver), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[91]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x8C0C0703, // 0003 GETMET R3 R3 K3 + 0xB8160800, // 0004 GETNGBL R5 K4 + 0x88140B05, // 0005 GETMBR R5 R5 K5 + 0x7C0C0400, // 0006 CALL R3 2 + 0x740E0004, // 0007 JMPT R3 #000D + 0xB80E0800, // 0008 GETNGBL R3 K4 + 0x8C0C0706, // 0009 GETMET R3 R3 K6 + 0x5C140000, // 000A MOVE R5 R0 + 0x7C0C0400, // 000B CALL R3 2 + 0x80000600, // 000C RET 0 + 0x500C0000, // 000D LDBOOL R3 0 0 + 0x90020E03, // 000E SETMBR R0 K7 R3 + 0x600C0012, // 000F GETGBL R3 G18 + 0x7C0C0000, // 0010 CALL R3 0 + 0x90021003, // 0011 SETMBR R0 K8 R3 + 0x880C010A, // 0012 GETMBR R3 R0 K10 + 0x90021203, // 0013 SETMBR R0 K9 R3 + 0x880C010C, // 0014 GETMBR R3 R0 K12 + 0x90021603, // 0015 SETMBR R0 K11 R3 + 0x880C010E, // 0016 GETMBR R3 R0 K14 + 0x90021A03, // 0017 SETMBR R0 K13 R3 + 0x8C0C0310, // 0018 GETMET R3 R1 K16 + 0x5416000F, // 0019 LDINT R5 16 + 0x7C0C0400, // 001A CALL R3 2 + 0x90021E03, // 001B SETMBR R0 K15 R3 + 0x500C0000, // 001C LDBOOL R3 0 0 + 0x90022203, // 001D SETMBR R0 K17 R3 + 0x8C0C0112, // 001E GETMET R3 R0 K18 + 0x7C0C0200, // 001F CALL R3 1 + 0xB80E0800, // 0020 GETNGBL R3 K4 + 0x8C0C0714, // 0021 GETMET R3 R3 K20 + 0x7C0C0200, // 0022 CALL R3 1 + 0x90022603, // 0023 SETMBR R0 K19 R3 + 0x880C0113, // 0024 GETMBR R3 R0 K19 + 0x8C0C0715, // 0025 GETMET R3 R3 K21 + 0x7C0C0200, // 0026 CALL R3 1 + 0xB80E0800, // 0027 GETNGBL R3 K4 + 0x8C0C0717, // 0028 GETMET R3 R3 K23 + 0x5C140000, // 0029 MOVE R5 R0 + 0x7C0C0400, // 002A CALL R3 2 + 0x90022C03, // 002B SETMBR R0 K22 R3 + 0xB80E0800, // 002C GETNGBL R3 K4 + 0x8C0C0706, // 002D GETMET R3 R3 K6 + 0x5C140000, // 002E MOVE R5 R0 + 0x7C0C0400, // 002F CALL R3 2 + 0x90023003, // 0030 SETMBR R0 K24 R3 + 0xB80E0400, // 0031 GETNGBL R3 K2 + 0x8C0C0719, // 0032 GETMET R3 R3 K25 + 0x7C0C0200, // 0033 CALL R3 1 + 0x940C071A, // 0034 GETIDX R3 R3 K26 + 0x740E0004, // 0035 JMPT R3 #003B + 0xB80E0400, // 0036 GETNGBL R3 K2 + 0x8C0C071B, // 0037 GETMET R3 R3 K27 + 0x7C0C0200, // 0038 CALL R3 1 + 0x940C071A, // 0039 GETIDX R3 R3 K26 + 0x780E0001, // 003A JMPF R3 #003D + 0x8C0C011C, // 003B GETMET R3 R0 K28 + 0x7C0C0200, // 003C CALL R3 1 + 0xB80E0400, // 003D GETNGBL R3 K2 + 0x8C0C0719, // 003E GETMET R3 R3 K25 + 0x7C0C0200, // 003F CALL R3 1 + 0x940C071A, // 0040 GETIDX R3 R3 K26 + 0x740E0005, // 0041 JMPT R3 #0048 + 0xB80E0400, // 0042 GETNGBL R3 K2 + 0x8C0C071D, // 0043 GETMET R3 R3 K29 + 0x5814001E, // 0044 LDCONST R5 K30 + 0x84180000, // 0045 CLOSURE R6 P0 + 0x581C001F, // 0046 LDCONST R7 K31 + 0x7C0C0800, // 0047 CALL R3 4 + 0xB80E0400, // 0048 GETNGBL R3 K2 + 0x8C0C071B, // 0049 GETMET R3 R3 K27 + 0x7C0C0200, // 004A CALL R3 1 + 0x940C071A, // 004B GETIDX R3 R3 K26 + 0x740E0005, // 004C JMPT R3 #0053 + 0xB80E0400, // 004D GETNGBL R3 K2 + 0x8C0C071D, // 004E GETMET R3 R3 K29 + 0x58140020, // 004F LDCONST R5 K32 + 0x84180001, // 0050 CLOSURE R6 P1 + 0x581C001F, // 0051 LDCONST R7 K31 + 0x7C0C0800, // 0052 CALL R3 4 + 0x8C0C0121, // 0053 GETMET R3 R0 K33 + 0x7C0C0200, // 0054 CALL R3 1 + 0xB80E0400, // 0055 GETNGBL R3 K2 + 0x8C0C0722, // 0056 GETMET R3 R3 K34 + 0x5C140000, // 0057 MOVE R5 R0 + 0x7C0C0400, // 0058 CALL R3 2 + 0xA0000000, // 0059 CLOSE R0 + 0x80000000, // 005A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_commissioning_complete +********************************************************************/ +be_local_closure(Matter_Device_start_commissioning_complete, /* 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[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X20Commissioning_X20complete_X20_X2A_X2A_X2A), + /* K3 */ be_const_int(2), + /* K4 */ be_nested_str_weak(stop_basic_commissioning), + }), + be_str_weak(start_commissioning_complete), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C080600, // 0004 CALL R2 3 + 0x8C080104, // 0005 GETMET R2 R0 K4 + 0x7C080200, // 0006 CALL R2 1 + 0x80000000, // 0007 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: 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: 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: mdns_remove_op_discovery +********************************************************************/ +be_local_closure(Matter_Device_mdns_remove_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[24]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(get_device_id), + /* K3 */ be_nested_str_weak(copy), + /* K4 */ be_nested_str_weak(reverse), + /* K5 */ be_nested_str_weak(get_fabric_compressed), + /* K6 */ be_nested_str_weak(tohex), + /* K7 */ be_nested_str_weak(_X2D), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(eth), + /* K10 */ be_nested_str_weak(find), + /* K11 */ be_nested_str_weak(up), + /* K12 */ be_nested_str_weak(log), + /* K13 */ be_nested_str_weak(format), + /* K14 */ be_nested_str_weak(MTR_X3A_X20remove_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27), + /* K15 */ be_const_int(2), + /* K16 */ be_nested_str_weak(remove_service), + /* K17 */ be_nested_str_weak(_matter), + /* K18 */ be_nested_str_weak(_tcp), + /* K19 */ be_nested_str_weak(hostname_eth), + /* K20 */ be_nested_str_weak(wifi), + /* K21 */ be_nested_str_weak(hostname_wifi), + /* K22 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K23 */ be_nested_str_weak(_X7C), + }), + be_str_weak(mdns_remove_op_discovery), + &be_const_str_solidified, + ( &(const binstruction[81]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA802003B, // 0002 EXBLK 0 #003F + 0x8C100302, // 0003 GETMET R4 R1 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x8C100903, // 0005 GETMET R4 R4 K3 + 0x7C100200, // 0006 CALL R4 1 + 0x8C100904, // 0007 GETMET R4 R4 K4 + 0x7C100200, // 0008 CALL R4 1 + 0x8C140305, // 0009 GETMET R5 R1 K5 + 0x7C140200, // 000A CALL R5 1 + 0x8C180B06, // 000B GETMET R6 R5 K6 + 0x7C180200, // 000C CALL R6 1 + 0x00180D07, // 000D ADD R6 R6 K7 + 0x8C1C0906, // 000E GETMET R7 R4 K6 + 0x7C1C0200, // 000F CALL R7 1 + 0x00180C07, // 0010 ADD R6 R6 R7 + 0xB81E1000, // 0011 GETNGBL R7 K8 + 0x8C1C0F09, // 0012 GETMET R7 R7 K9 + 0x7C1C0200, // 0013 CALL R7 1 + 0x8C1C0F0A, // 0014 GETMET R7 R7 K10 + 0x5824000B, // 0015 LDCONST R9 K11 + 0x7C1C0400, // 0016 CALL R7 2 + 0x781E000E, // 0017 JMPF R7 #0027 + 0xB81E1000, // 0018 GETNGBL R7 K8 + 0x8C1C0F0C, // 0019 GETMET R7 R7 K12 + 0x8C24070D, // 001A GETMET R9 R3 K13 + 0x582C000E, // 001B LDCONST R11 K14 + 0x58300009, // 001C LDCONST R12 K9 + 0x5C340C00, // 001D MOVE R13 R6 + 0x7C240800, // 001E CALL R9 4 + 0x5828000F, // 001F LDCONST R10 K15 + 0x7C1C0600, // 0020 CALL R7 3 + 0x8C1C0510, // 0021 GETMET R7 R2 K16 + 0x58240011, // 0022 LDCONST R9 K17 + 0x58280012, // 0023 LDCONST R10 K18 + 0x5C2C0C00, // 0024 MOVE R11 R6 + 0x88300113, // 0025 GETMBR R12 R0 K19 + 0x7C1C0A00, // 0026 CALL R7 5 + 0xB81E1000, // 0027 GETNGBL R7 K8 + 0x8C1C0F14, // 0028 GETMET R7 R7 K20 + 0x7C1C0200, // 0029 CALL R7 1 + 0x8C1C0F0A, // 002A GETMET R7 R7 K10 + 0x5824000B, // 002B LDCONST R9 K11 + 0x7C1C0400, // 002C CALL R7 2 + 0x781E000E, // 002D JMPF R7 #003D + 0xB81E1000, // 002E GETNGBL R7 K8 + 0x8C1C0F0C, // 002F GETMET R7 R7 K12 + 0x8C24070D, // 0030 GETMET R9 R3 K13 + 0x582C000E, // 0031 LDCONST R11 K14 + 0x58300014, // 0032 LDCONST R12 K20 + 0x5C340C00, // 0033 MOVE R13 R6 + 0x7C240800, // 0034 CALL R9 4 + 0x5828000F, // 0035 LDCONST R10 K15 + 0x7C1C0600, // 0036 CALL R7 3 + 0x8C1C0510, // 0037 GETMET R7 R2 K16 + 0x58240011, // 0038 LDCONST R9 K17 + 0x58280012, // 0039 LDCONST R10 K18 + 0x5C2C0C00, // 003A MOVE R11 R6 + 0x88300115, // 003B GETMBR R12 R0 K21 + 0x7C1C0A00, // 003C CALL R7 5 + 0xA8040001, // 003D EXBLK 1 1 + 0x70020010, // 003E JMP #0050 + 0xAC100002, // 003F CATCH R4 0 2 + 0x7002000D, // 0040 JMP #004F + 0xB81A1000, // 0041 GETNGBL R6 K8 + 0x8C180D0C, // 0042 GETMET R6 R6 K12 + 0x60200008, // 0043 GETGBL R8 G8 + 0x5C240800, // 0044 MOVE R9 R4 + 0x7C200200, // 0045 CALL R8 1 + 0x00222C08, // 0046 ADD R8 K22 R8 + 0x00201117, // 0047 ADD R8 R8 K23 + 0x60240008, // 0048 GETGBL R9 G8 + 0x5C280A00, // 0049 MOVE R10 R5 + 0x7C240200, // 004A CALL R9 1 + 0x00201009, // 004B ADD R8 R8 R9 + 0x5824000F, // 004C LDCONST R9 K15 + 0x7C180600, // 004D CALL R6 3 + 0x70020000, // 004E JMP #0050 + 0xB0080000, // 004F RAISE 2 R0 R0 + 0x80000000, // 0050 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: 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: 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: _mdns_announce_hostname +********************************************************************/ +be_local_closure(Matter_Device__mdns_announce_hostname, /* name */ + be_nested_proto( + 16, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[28]) { /* 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(log), + /* K13 */ be_nested_str_weak(format), + /* K14 */ be_nested_str_weak(MTR_X3A_X20calling_X20mdns_X2Eadd_hostname_X28_X25s_X2C_X20_X25s_X2C_X20_X25s_X29), + /* K15 */ be_nested_str_weak(ip6local), + /* K16 */ be_nested_str_weak(ip), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(add_hostname), + /* K19 */ be_nested_str_weak(ip6), + /* K20 */ be_nested_str_weak(MTR_X3A_X20calling_X20mdns_X2Eadd_hostname_X28_X25s_X2C_X20_X25s_X29), + /* K21 */ be_nested_str_weak(wifi), + /* K22 */ be_nested_str_weak(hostname_wifi), + /* K23 */ be_nested_str_weak(MTR_X3A_X20start_X20mDNS_X20on_X20_X25s_X20host_X20_X27_X25s_X2Elocal_X27), + /* K24 */ be_const_int(2), + /* K25 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K26 */ be_nested_str_weak(_X7C), + /* K27 */ be_nested_str_weak(mdns_announce_op_discovery_all_fabrics), + }), + be_str_weak(_mdns_announce_hostname), + &be_const_str_solidified, + ( &(const binstruction[172]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100502, // 0002 GETMET R4 R2 K2 + 0x7C100200, // 0003 CALL R4 1 + 0xA8020092, // 0004 EXBLK 0 #0098 + 0x78060040, // 0005 JMPF R1 #0047 + 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 + 0x7416001F, // 0012 JMPT R5 #0033 + 0xB8160600, // 0013 GETNGBL R5 K3 + 0x8C140B0C, // 0014 GETMET R5 R5 K12 + 0x8C1C070D, // 0015 GETMET R7 R3 K13 + 0x5824000E, // 0016 LDCONST R9 K14 + 0x88280105, // 0017 GETMBR R10 R0 K5 + 0x8C2C0907, // 0018 GETMET R11 R4 K7 + 0x5834000F, // 0019 LDCONST R13 K15 + 0x5838000A, // 001A LDCONST R14 K10 + 0x7C2C0600, // 001B CALL R11 3 + 0x8C300907, // 001C GETMET R12 R4 K7 + 0x58380010, // 001D LDCONST R14 K16 + 0x583C000A, // 001E LDCONST R15 K10 + 0x7C300600, // 001F CALL R12 3 + 0x7C1C0A00, // 0020 CALL R7 5 + 0x58200011, // 0021 LDCONST R8 K17 + 0x7C140600, // 0022 CALL R5 3 + 0x8C140512, // 0023 GETMET R5 R2 K18 + 0x881C0105, // 0024 GETMBR R7 R0 K5 + 0x8C200907, // 0025 GETMET R8 R4 K7 + 0x5828000F, // 0026 LDCONST R10 K15 + 0x582C000A, // 0027 LDCONST R11 K10 + 0x7C200600, // 0028 CALL R8 3 + 0x8C240907, // 0029 GETMET R9 R4 K7 + 0x582C0010, // 002A LDCONST R11 K16 + 0x5830000A, // 002B LDCONST R12 K10 + 0x7C240600, // 002C CALL R9 3 + 0x8C280907, // 002D GETMET R10 R4 K7 + 0x58300013, // 002E LDCONST R12 K19 + 0x5834000A, // 002F LDCONST R13 K10 + 0x7C280600, // 0030 CALL R10 3 + 0x7C140A00, // 0031 CALL R5 5 + 0x70020012, // 0032 JMP #0046 + 0xB8160600, // 0033 GETNGBL R5 K3 + 0x8C140B0C, // 0034 GETMET R5 R5 K12 + 0x8C1C070D, // 0035 GETMET R7 R3 K13 + 0x58240014, // 0036 LDCONST R9 K20 + 0x88280105, // 0037 GETMBR R10 R0 K5 + 0x8C2C0907, // 0038 GETMET R11 R4 K7 + 0x58340010, // 0039 LDCONST R13 K16 + 0x5838000A, // 003A LDCONST R14 K10 + 0x7C2C0600, // 003B CALL R11 3 + 0x7C1C0800, // 003C CALL R7 4 + 0x58200011, // 003D LDCONST R8 K17 + 0x7C140600, // 003E CALL R5 3 + 0x8C140512, // 003F GETMET R5 R2 K18 + 0x881C0105, // 0040 GETMBR R7 R0 K5 + 0x8C200907, // 0041 GETMET R8 R4 K7 + 0x58280010, // 0042 LDCONST R10 K16 + 0x582C000A, // 0043 LDCONST R11 K10 + 0x7C200600, // 0044 CALL R8 3 + 0x7C140600, // 0045 CALL R5 3 + 0x7002003F, // 0046 JMP #0087 + 0xB8120600, // 0047 GETNGBL R4 K3 + 0x8C100915, // 0048 GETMET R4 R4 K21 + 0x7C100200, // 0049 CALL R4 1 + 0x8C140706, // 004A GETMET R5 R3 K6 + 0x8C1C0907, // 004B GETMET R7 R4 K7 + 0x58240008, // 004C LDCONST R9 K8 + 0x7C1C0400, // 004D CALL R7 2 + 0x58200009, // 004E LDCONST R8 K9 + 0x5824000A, // 004F LDCONST R9 K10 + 0x7C140800, // 0050 CALL R5 4 + 0x90022C05, // 0051 SETMBR R0 K22 R5 + 0x8814010B, // 0052 GETMBR R5 R0 K11 + 0x7416001F, // 0053 JMPT R5 #0074 + 0xB8160600, // 0054 GETNGBL R5 K3 + 0x8C140B0C, // 0055 GETMET R5 R5 K12 + 0x8C1C070D, // 0056 GETMET R7 R3 K13 + 0x5824000E, // 0057 LDCONST R9 K14 + 0x88280116, // 0058 GETMBR R10 R0 K22 + 0x8C2C0907, // 0059 GETMET R11 R4 K7 + 0x5834000F, // 005A LDCONST R13 K15 + 0x5838000A, // 005B LDCONST R14 K10 + 0x7C2C0600, // 005C CALL R11 3 + 0x8C300907, // 005D GETMET R12 R4 K7 + 0x58380010, // 005E LDCONST R14 K16 + 0x583C000A, // 005F LDCONST R15 K10 + 0x7C300600, // 0060 CALL R12 3 + 0x7C1C0A00, // 0061 CALL R7 5 + 0x58200011, // 0062 LDCONST R8 K17 + 0x7C140600, // 0063 CALL R5 3 + 0x8C140512, // 0064 GETMET R5 R2 K18 + 0x881C0116, // 0065 GETMBR R7 R0 K22 + 0x8C200907, // 0066 GETMET R8 R4 K7 + 0x5828000F, // 0067 LDCONST R10 K15 + 0x582C000A, // 0068 LDCONST R11 K10 + 0x7C200600, // 0069 CALL R8 3 + 0x8C240907, // 006A GETMET R9 R4 K7 + 0x582C0010, // 006B LDCONST R11 K16 + 0x5830000A, // 006C LDCONST R12 K10 + 0x7C240600, // 006D CALL R9 3 + 0x8C280907, // 006E GETMET R10 R4 K7 + 0x58300013, // 006F LDCONST R12 K19 + 0x5834000A, // 0070 LDCONST R13 K10 + 0x7C280600, // 0071 CALL R10 3 + 0x7C140A00, // 0072 CALL R5 5 + 0x70020012, // 0073 JMP #0087 + 0xB8160600, // 0074 GETNGBL R5 K3 + 0x8C140B0C, // 0075 GETMET R5 R5 K12 + 0x8C1C070D, // 0076 GETMET R7 R3 K13 + 0x58240014, // 0077 LDCONST R9 K20 + 0x88280105, // 0078 GETMBR R10 R0 K5 + 0x8C2C0907, // 0079 GETMET R11 R4 K7 + 0x58340010, // 007A LDCONST R13 K16 + 0x5838000A, // 007B LDCONST R14 K10 + 0x7C2C0600, // 007C CALL R11 3 + 0x7C1C0800, // 007D CALL R7 4 + 0x58200011, // 007E LDCONST R8 K17 + 0x7C140600, // 007F CALL R5 3 + 0x8C140512, // 0080 GETMET R5 R2 K18 + 0x881C0116, // 0081 GETMBR R7 R0 K22 + 0x8C200907, // 0082 GETMET R8 R4 K7 + 0x58280010, // 0083 LDCONST R10 K16 + 0x582C000A, // 0084 LDCONST R11 K10 + 0x7C200600, // 0085 CALL R8 3 + 0x7C140600, // 0086 CALL R5 3 + 0xB8120600, // 0087 GETNGBL R4 K3 + 0x8C10090C, // 0088 GETMET R4 R4 K12 + 0x8C18070D, // 0089 GETMET R6 R3 K13 + 0x58200017, // 008A LDCONST R8 K23 + 0x78060001, // 008B JMPF R1 #008E + 0x58240004, // 008C LDCONST R9 K4 + 0x70020000, // 008D JMP #008F + 0x58240015, // 008E LDCONST R9 K21 + 0x78060001, // 008F JMPF R1 #0092 + 0x88280105, // 0090 GETMBR R10 R0 K5 + 0x70020000, // 0091 JMP #0093 + 0x88280116, // 0092 GETMBR R10 R0 K22 + 0x7C180800, // 0093 CALL R6 4 + 0x581C0018, // 0094 LDCONST R7 K24 + 0x7C100600, // 0095 CALL R4 3 + 0xA8040001, // 0096 EXBLK 1 1 + 0x70020010, // 0097 JMP #00A9 + 0xAC100002, // 0098 CATCH R4 0 2 + 0x7002000D, // 0099 JMP #00A8 + 0xB81A0600, // 009A GETNGBL R6 K3 + 0x8C180D0C, // 009B GETMET R6 R6 K12 + 0x60200008, // 009C GETGBL R8 G8 + 0x5C240800, // 009D MOVE R9 R4 + 0x7C200200, // 009E CALL R8 1 + 0x00223208, // 009F ADD R8 K25 R8 + 0x0020111A, // 00A0 ADD R8 R8 K26 + 0x60240008, // 00A1 GETGBL R9 G8 + 0x5C280A00, // 00A2 MOVE R10 R5 + 0x7C240200, // 00A3 CALL R9 1 + 0x00201009, // 00A4 ADD R8 R8 R9 + 0x58240018, // 00A5 LDCONST R9 K24 + 0x7C180600, // 00A6 CALL R6 3 + 0x70020000, // 00A7 JMP #00A9 + 0xB0080000, // 00A8 RAISE 2 R0 R0 + 0x8C10011B, // 00A9 GETMET R4 R0 K27 + 0x7C100200, // 00AA CALL R4 1 + 0x80000000, // 00AB RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load_param +********************************************************************/ +be_local_closure(Matter_Device_load_param, /* 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[24]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(crypto), + /* K2 */ be_nested_str_weak(FILENAME), + /* K3 */ be_nested_str_weak(read), + /* K4 */ be_nested_str_weak(close), + /* K5 */ be_nested_str_weak(json), + /* K6 */ be_nested_str_weak(load), + /* K7 */ be_nested_str_weak(root_discriminator), + /* K8 */ be_nested_str_weak(find), + /* K9 */ be_nested_str_weak(distinguish), + /* K10 */ be_nested_str_weak(root_passcode), + /* K11 */ be_nested_str_weak(passcode), + /* K12 */ be_nested_str_weak(ipv4only), + /* K13 */ be_nested_str_weak(io_error), + /* K14 */ be_nested_str_weak(tasmota), + /* K15 */ be_nested_str_weak(log), + /* K16 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), + /* K17 */ be_nested_str_weak(_X7C), + /* K18 */ be_const_int(2), + /* K19 */ be_nested_str_weak(random), + /* K20 */ be_nested_str_weak(get), + /* K21 */ be_const_int(0), + /* K22 */ be_nested_str_weak(PASSCODE_DEFAULT), + /* K23 */ be_nested_str_weak(save_param), + }), + be_str_weak(load_param), + &be_const_str_solidified, + ( &(const binstruction[79]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA802001D, // 0002 EXBLK 0 #0021 + 0x600C0011, // 0003 GETGBL R3 G17 + 0x88100102, // 0004 GETMBR R4 R0 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x8C100703, // 0006 GETMET R4 R3 K3 + 0x7C100200, // 0007 CALL R4 1 + 0x8C140704, // 0008 GETMET R5 R3 K4 + 0x7C140200, // 0009 CALL R5 1 + 0xA4160A00, // 000A IMPORT R5 K5 + 0x8C180B06, // 000B GETMET R6 R5 K6 + 0x5C200800, // 000C MOVE R8 R4 + 0x7C180400, // 000D CALL R6 2 + 0x8C1C0D08, // 000E GETMET R7 R6 K8 + 0x58240009, // 000F LDCONST R9 K9 + 0x88280107, // 0010 GETMBR R10 R0 K7 + 0x7C1C0600, // 0011 CALL R7 3 + 0x90020E07, // 0012 SETMBR R0 K7 R7 + 0x8C1C0D08, // 0013 GETMET R7 R6 K8 + 0x5824000B, // 0014 LDCONST R9 K11 + 0x8828010A, // 0015 GETMBR R10 R0 K10 + 0x7C1C0600, // 0016 CALL R7 3 + 0x90021407, // 0017 SETMBR R0 K10 R7 + 0x601C0017, // 0018 GETGBL R7 G23 + 0x8C200D08, // 0019 GETMET R8 R6 K8 + 0x5828000C, // 001A LDCONST R10 K12 + 0x502C0000, // 001B LDBOOL R11 0 0 + 0x7C200600, // 001C CALL R8 3 + 0x7C1C0200, // 001D CALL R7 1 + 0x90021807, // 001E SETMBR R0 K12 R7 + 0xA8040001, // 001F EXBLK 1 1 + 0x70020012, // 0020 JMP #0034 + 0xAC0C0002, // 0021 CATCH R3 0 2 + 0x7002000F, // 0022 JMP #0033 + 0x2014070D, // 0023 NE R5 R3 K13 + 0x7816000C, // 0024 JMPF R5 #0032 + 0xB8161C00, // 0025 GETNGBL R5 K14 + 0x8C140B0F, // 0026 GETMET R5 R5 K15 + 0x601C0008, // 0027 GETGBL R7 G8 + 0x5C200600, // 0028 MOVE R8 R3 + 0x7C1C0200, // 0029 CALL R7 1 + 0x001E2007, // 002A ADD R7 K16 R7 + 0x001C0F11, // 002B ADD R7 R7 K17 + 0x60200008, // 002C GETGBL R8 G8 + 0x5C240800, // 002D MOVE R9 R4 + 0x7C200200, // 002E CALL R8 1 + 0x001C0E08, // 002F ADD R7 R7 R8 + 0x58200012, // 0030 LDCONST R8 K18 + 0x7C140600, // 0031 CALL R5 3 + 0x70020000, // 0032 JMP #0034 + 0xB0080000, // 0033 RAISE 2 R0 R0 + 0x500C0000, // 0034 LDBOOL R3 0 0 + 0x88100107, // 0035 GETMBR R4 R0 K7 + 0x4C140000, // 0036 LDNIL R5 + 0x1C100805, // 0037 EQ R4 R4 R5 + 0x7812000A, // 0038 JMPF R4 #0044 + 0x8C100513, // 0039 GETMET R4 R2 K19 + 0x58180012, // 003A LDCONST R6 K18 + 0x7C100400, // 003B CALL R4 2 + 0x8C100914, // 003C GETMET R4 R4 K20 + 0x58180015, // 003D LDCONST R6 K21 + 0x581C0012, // 003E LDCONST R7 K18 + 0x7C100600, // 003F CALL R4 3 + 0x54160FFE, // 0040 LDINT R5 4095 + 0x2C100805, // 0041 AND R4 R4 R5 + 0x90020E04, // 0042 SETMBR R0 K7 R4 + 0x500C0200, // 0043 LDBOOL R3 1 0 + 0x8810010A, // 0044 GETMBR R4 R0 K10 + 0x4C140000, // 0045 LDNIL R5 + 0x1C100805, // 0046 EQ R4 R4 R5 + 0x78120002, // 0047 JMPF R4 #004B + 0x88100116, // 0048 GETMBR R4 R0 K22 + 0x90021404, // 0049 SETMBR R0 K10 R4 + 0x500C0200, // 004A LDBOOL R3 1 0 + 0x780E0001, // 004B JMPF R3 #004E + 0x8C100117, // 004C GETMET R4 R0 K23 + 0x7C100200, // 004D CALL R4 1 + 0x80000000, // 004E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _compute_pbkdf +********************************************************************/ +be_local_closure(Matter_Device__compute_pbkdf, /* 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[11]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(add), + /* K3 */ be_nested_str_weak(PBKDF2_HMAC_SHA256), + /* K4 */ be_nested_str_weak(derive), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(root_w0), + /* K7 */ be_nested_str_weak(EC_P256), + /* K8 */ be_nested_str_weak(mod), + /* K9 */ be_nested_str_weak(root_L), + /* K10 */ be_nested_str_weak(public_key), + }), + be_str_weak(_compute_pbkdf), + &be_const_str_solidified, + ( &(const binstruction[41]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xA4160200, // 0001 IMPORT R5 K1 + 0x60180015, // 0002 GETGBL R6 G21 + 0x7C180000, // 0003 CALL R6 0 + 0x8C180D02, // 0004 GETMET R6 R6 K2 + 0x5C200200, // 0005 MOVE R8 R1 + 0x54260003, // 0006 LDINT R9 4 + 0x7C180600, // 0007 CALL R6 3 + 0x8C1C0903, // 0008 GETMET R7 R4 K3 + 0x7C1C0200, // 0009 CALL R7 1 + 0x8C1C0F04, // 000A GETMET R7 R7 K4 + 0x5C240C00, // 000B MOVE R9 R6 + 0x5C280600, // 000C MOVE R10 R3 + 0x5C2C0400, // 000D MOVE R11 R2 + 0x5432004F, // 000E LDINT R12 80 + 0x7C1C0A00, // 000F CALL R7 5 + 0x54220026, // 0010 LDINT R8 39 + 0x40220A08, // 0011 CONNECT R8 K5 R8 + 0x94200E08, // 0012 GETIDX R8 R7 R8 + 0x54260027, // 0013 LDINT R9 40 + 0x542A004E, // 0014 LDINT R10 79 + 0x4024120A, // 0015 CONNECT R9 R9 R10 + 0x94240E09, // 0016 GETIDX R9 R7 R9 + 0x8C280907, // 0017 GETMET R10 R4 K7 + 0x7C280200, // 0018 CALL R10 1 + 0x8C281508, // 0019 GETMET R10 R10 K8 + 0x5C301000, // 001A MOVE R12 R8 + 0x7C280400, // 001B CALL R10 2 + 0x90020C0A, // 001C SETMBR R0 K6 R10 + 0x8C280907, // 001D GETMET R10 R4 K7 + 0x7C280200, // 001E CALL R10 1 + 0x8C281508, // 001F GETMET R10 R10 K8 + 0x5C301200, // 0020 MOVE R12 R9 + 0x7C280400, // 0021 CALL R10 2 + 0x8C2C0907, // 0022 GETMET R11 R4 K7 + 0x7C2C0200, // 0023 CALL R11 1 + 0x8C2C170A, // 0024 GETMET R11 R11 K10 + 0x5C341400, // 0025 MOVE R13 R10 + 0x7C2C0400, // 0026 CALL R11 2 + 0x9002120B, // 0027 SETMBR R0 K9 R11 + 0x80000000, // 0028 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** 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: mdns_remove_PASE +********************************************************************/ +be_local_closure(Matter_Device_mdns_remove_PASE, /* 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[22]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(mdns_pase_eth), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20calling_X20mdns_X2Eremove_service_X28_X25s_X2C_X20_X25s_X2C_X20_X25s_X2C_X20_X25s_X29), + /* K7 */ be_nested_str_weak(_matterc), + /* K8 */ be_nested_str_weak(_udp), + /* K9 */ be_nested_str_weak(commissioning_instance_eth), + /* K10 */ be_nested_str_weak(hostname_eth), + /* K11 */ be_const_int(3), + /* K12 */ be_nested_str_weak(MTR_X3A_X20remove_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27), + /* K13 */ be_nested_str_weak(eth), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(remove_service), + /* K16 */ be_nested_str_weak(mdns_pase_wifi), + /* K17 */ be_nested_str_weak(commissioning_instance_wifi), + /* K18 */ be_nested_str_weak(hostname_wifi), + /* K19 */ be_nested_str_weak(wifi), + /* K20 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K21 */ be_nested_str_weak(_X7C), + }), + be_str_weak(mdns_remove_PASE), + &be_const_str_solidified, + ( &(const binstruction[83]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA802003D, // 0002 EXBLK 0 #0041 + 0x880C0102, // 0003 GETMBR R3 R0 K2 + 0x780E001B, // 0004 JMPF R3 #0021 + 0xB80E0600, // 0005 GETNGBL R3 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x8C140505, // 0007 GETMET R5 R2 K5 + 0x581C0006, // 0008 LDCONST R7 K6 + 0x58200007, // 0009 LDCONST R8 K7 + 0x58240008, // 000A LDCONST R9 K8 + 0x88280109, // 000B GETMBR R10 R0 K9 + 0x882C010A, // 000C GETMBR R11 R0 K10 + 0x7C140C00, // 000D CALL R5 6 + 0x5818000B, // 000E LDCONST R6 K11 + 0x7C0C0600, // 000F CALL R3 3 + 0xB80E0600, // 0010 GETNGBL R3 K3 + 0x8C0C0704, // 0011 GETMET R3 R3 K4 + 0x8C140505, // 0012 GETMET R5 R2 K5 + 0x581C000C, // 0013 LDCONST R7 K12 + 0x5820000D, // 0014 LDCONST R8 K13 + 0x88240109, // 0015 GETMBR R9 R0 K9 + 0x7C140800, // 0016 CALL R5 4 + 0x5818000E, // 0017 LDCONST R6 K14 + 0x7C0C0600, // 0018 CALL R3 3 + 0x500C0000, // 0019 LDBOOL R3 0 0 + 0x90020403, // 001A SETMBR R0 K2 R3 + 0x8C0C030F, // 001B GETMET R3 R1 K15 + 0x58140007, // 001C LDCONST R5 K7 + 0x58180008, // 001D LDCONST R6 K8 + 0x881C0109, // 001E GETMBR R7 R0 K9 + 0x8820010A, // 001F GETMBR R8 R0 K10 + 0x7C0C0A00, // 0020 CALL R3 5 + 0x880C0110, // 0021 GETMBR R3 R0 K16 + 0x780E001B, // 0022 JMPF R3 #003F + 0xB80E0600, // 0023 GETNGBL R3 K3 + 0x8C0C0704, // 0024 GETMET R3 R3 K4 + 0x8C140505, // 0025 GETMET R5 R2 K5 + 0x581C0006, // 0026 LDCONST R7 K6 + 0x58200007, // 0027 LDCONST R8 K7 + 0x58240008, // 0028 LDCONST R9 K8 + 0x88280111, // 0029 GETMBR R10 R0 K17 + 0x882C0112, // 002A GETMBR R11 R0 K18 + 0x7C140C00, // 002B CALL R5 6 + 0x5818000B, // 002C LDCONST R6 K11 + 0x7C0C0600, // 002D CALL R3 3 + 0xB80E0600, // 002E GETNGBL R3 K3 + 0x8C0C0704, // 002F GETMET R3 R3 K4 + 0x8C140505, // 0030 GETMET R5 R2 K5 + 0x581C000C, // 0031 LDCONST R7 K12 + 0x58200013, // 0032 LDCONST R8 K19 + 0x88240111, // 0033 GETMBR R9 R0 K17 + 0x7C140800, // 0034 CALL R5 4 + 0x5818000E, // 0035 LDCONST R6 K14 + 0x7C0C0600, // 0036 CALL R3 3 + 0x500C0000, // 0037 LDBOOL R3 0 0 + 0x90022003, // 0038 SETMBR R0 K16 R3 + 0x8C0C030F, // 0039 GETMET R3 R1 K15 + 0x58140007, // 003A LDCONST R5 K7 + 0x58180008, // 003B LDCONST R6 K8 + 0x881C0111, // 003C GETMBR R7 R0 K17 + 0x88200112, // 003D GETMBR R8 R0 K18 + 0x7C0C0A00, // 003E CALL R3 5 + 0xA8040001, // 003F EXBLK 1 1 + 0x70020010, // 0040 JMP #0052 + 0xAC0C0002, // 0041 CATCH R3 0 2 + 0x7002000D, // 0042 JMP #0051 + 0xB8160600, // 0043 GETNGBL R5 K3 + 0x8C140B04, // 0044 GETMET R5 R5 K4 + 0x601C0008, // 0045 GETGBL R7 G8 + 0x5C200600, // 0046 MOVE R8 R3 + 0x7C1C0200, // 0047 CALL R7 1 + 0x001E2807, // 0048 ADD R7 K20 R7 + 0x001C0F15, // 0049 ADD R7 R7 K21 + 0x60200008, // 004A GETGBL R8 G8 + 0x5C240800, // 004B MOVE R9 R4 + 0x7C200200, // 004C CALL R8 1 + 0x001C0E08, // 004D ADD R7 R7 R8 + 0x5820000E, // 004E LDCONST R8 K14 + 0x7C140600, // 004F CALL R5 3 + 0x70020000, // 0050 JMP #0052 + 0xB0080000, // 0051 RAISE 2 R0 R0 + 0x80000000, // 0052 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** 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: 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: autoconf_device +********************************************************************/ +be_local_closure(Matter_Device_autoconf_device, /* name */ + be_nested_proto( + 15, /* nstack */ + 1, /* 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(string), + /* 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(plugins), + /* K9 */ be_nested_str_weak(push), + /* K10 */ be_nested_str_weak(matter), + /* K11 */ be_nested_str_weak(Plugin_Light1), + /* K12 */ be_nested_str_weak(tasmota), + /* K13 */ be_nested_str_weak(log), + /* K14 */ be_nested_str_weak(format), + /* K15 */ be_nested_str_weak(MTR_X3A_X20Endpoint_X3A_X25i_X20Light_Dimmer), + /* K16 */ be_const_int(2), + /* K17 */ be_nested_str_weak(Plugin_Light2), + /* K18 */ be_nested_str_weak(MTR_X3A_X20Endpoint_X3A_X25i_X20Light_CT), + /* K19 */ be_nested_str_weak(Plugin_Light3), + /* K20 */ be_nested_str_weak(MTR_X3A_X20Endpoint_X3A_X25i_X20Light_RGB), + /* K21 */ be_nested_str_weak(get_power), + /* K22 */ be_nested_str_weak(Plugin_OnOff), + /* K23 */ be_nested_str_weak(MTR_X3A_X20Endpoint_X3A_X25i_X20Relay__X25i), + }), + be_str_weak(autoconf_device), + &be_const_str_solidified, + ( &(const binstruction[105]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0x500C0000, // 0002 LDBOOL R3 0 0 + 0xA4120400, // 0003 IMPORT R4 K2 + 0x8C140903, // 0004 GETMET R5 R4 K3 + 0x7C140200, // 0005 CALL R5 1 + 0x4C180000, // 0006 LDNIL R6 + 0x20180A06, // 0007 NE R6 R5 R6 + 0x781A003F, // 0008 JMPF R6 #0049 + 0x6018000C, // 0009 GETGBL R6 G12 + 0x8C1C0B04, // 000A GETMET R7 R5 K4 + 0x58240005, // 000B LDCONST R9 K5 + 0x58280006, // 000C LDCONST R10 K6 + 0x7C1C0600, // 000D CALL R7 3 + 0x7C180200, // 000E CALL R6 1 + 0x241C0D07, // 000F GT R7 R6 K7 + 0x781E0037, // 0010 JMPF R7 #0049 + 0x1C1C0D01, // 0011 EQ R7 R6 K1 + 0x781E0010, // 0012 JMPF R7 #0024 + 0x881C0108, // 0013 GETMBR R7 R0 K8 + 0x8C1C0F09, // 0014 GETMET R7 R7 K9 + 0xB8261400, // 0015 GETNGBL R9 K10 + 0x8C24130B, // 0016 GETMET R9 R9 K11 + 0x5C2C0000, // 0017 MOVE R11 R0 + 0x5C300400, // 0018 MOVE R12 R2 + 0x7C240600, // 0019 CALL R9 3 + 0x7C1C0400, // 001A CALL R7 2 + 0xB81E1800, // 001B GETNGBL R7 K12 + 0x8C1C0F0D, // 001C GETMET R7 R7 K13 + 0x8C24030E, // 001D GETMET R9 R1 K14 + 0x582C000F, // 001E LDCONST R11 K15 + 0x5C300400, // 001F MOVE R12 R2 + 0x7C240600, // 0020 CALL R9 3 + 0x58280010, // 0021 LDCONST R10 K16 + 0x7C1C0600, // 0022 CALL R7 3 + 0x70020022, // 0023 JMP #0047 + 0x1C1C0D10, // 0024 EQ R7 R6 K16 + 0x781E0010, // 0025 JMPF R7 #0037 + 0x881C0108, // 0026 GETMBR R7 R0 K8 + 0x8C1C0F09, // 0027 GETMET R7 R7 K9 + 0xB8261400, // 0028 GETNGBL R9 K10 + 0x8C241311, // 0029 GETMET R9 R9 K17 + 0x5C2C0000, // 002A MOVE R11 R0 + 0x5C300400, // 002B MOVE R12 R2 + 0x7C240600, // 002C CALL R9 3 + 0x7C1C0400, // 002D CALL R7 2 + 0xB81E1800, // 002E GETNGBL R7 K12 + 0x8C1C0F0D, // 002F GETMET R7 R7 K13 + 0x8C24030E, // 0030 GETMET R9 R1 K14 + 0x582C0012, // 0031 LDCONST R11 K18 + 0x5C300400, // 0032 MOVE R12 R2 + 0x7C240600, // 0033 CALL R9 3 + 0x58280010, // 0034 LDCONST R10 K16 + 0x7C1C0600, // 0035 CALL R7 3 + 0x7002000F, // 0036 JMP #0047 + 0x881C0108, // 0037 GETMBR R7 R0 K8 + 0x8C1C0F09, // 0038 GETMET R7 R7 K9 + 0xB8261400, // 0039 GETNGBL R9 K10 + 0x8C241313, // 003A GETMET R9 R9 K19 + 0x5C2C0000, // 003B MOVE R11 R0 + 0x5C300400, // 003C MOVE R12 R2 + 0x7C240600, // 003D CALL R9 3 + 0x7C1C0400, // 003E CALL R7 2 + 0xB81E1800, // 003F GETNGBL R7 K12 + 0x8C1C0F0D, // 0040 GETMET R7 R7 K13 + 0x8C24030E, // 0041 GETMET R9 R1 K14 + 0x582C0014, // 0042 LDCONST R11 K20 + 0x5C300400, // 0043 MOVE R12 R2 + 0x7C240600, // 0044 CALL R9 3 + 0x58280010, // 0045 LDCONST R10 K16 + 0x7C1C0600, // 0046 CALL R7 3 + 0x500C0200, // 0047 LDBOOL R3 1 0 + 0x00080501, // 0048 ADD R2 R2 K1 + 0x6018000C, // 0049 GETGBL R6 G12 + 0xB81E1800, // 004A GETNGBL R7 K12 + 0x8C1C0F15, // 004B GETMET R7 R7 K21 + 0x7C1C0200, // 004C CALL R7 1 + 0x7C180200, // 004D CALL R6 1 + 0x581C0007, // 004E LDCONST R7 K7 + 0x780E0000, // 004F JMPF R3 #0051 + 0x04180D01, // 0050 SUB R6 R6 K1 + 0x14200E06, // 0051 LT R8 R7 R6 + 0x78220014, // 0052 JMPF R8 #0068 + 0x88200108, // 0053 GETMBR R8 R0 K8 + 0x8C201109, // 0054 GETMET R8 R8 K9 + 0xB82A1400, // 0055 GETNGBL R10 K10 + 0x8C281516, // 0056 GETMET R10 R10 K22 + 0x5C300000, // 0057 MOVE R12 R0 + 0x5C340400, // 0058 MOVE R13 R2 + 0x5C380E00, // 0059 MOVE R14 R7 + 0x7C280800, // 005A CALL R10 4 + 0x7C200400, // 005B CALL R8 2 + 0xB8221800, // 005C GETNGBL R8 K12 + 0x8C20110D, // 005D GETMET R8 R8 K13 + 0x8C28030E, // 005E GETMET R10 R1 K14 + 0x58300017, // 005F LDCONST R12 K23 + 0x5C340400, // 0060 MOVE R13 R2 + 0x00380F01, // 0061 ADD R14 R7 K1 + 0x7C280800, // 0062 CALL R10 4 + 0x582C0010, // 0063 LDCONST R11 K16 + 0x7C200600, // 0064 CALL R8 3 + 0x001C0F01, // 0065 ADD R7 R7 K1 + 0x00080501, // 0066 ADD R2 R2 K1 + 0x7001FFE8, // 0067 JMP #0051 + 0x80000000, // 0068 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: 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[ 9]) { /* 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), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(plugins), + /* K8 */ be_const_int(1), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* 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 + 0x58040006, // 0011 LDCONST R1 K6 + 0x6008000C, // 0012 GETGBL R2 G12 + 0x880C0107, // 0013 GETMBR R3 R0 K7 + 0x7C080200, // 0014 CALL R2 1 + 0x14080202, // 0015 LT R2 R1 R2 + 0x780A0005, // 0016 JMPF R2 #001D + 0x88080107, // 0017 GETMBR R2 R0 K7 + 0x94080401, // 0018 GETIDX R2 R2 R1 + 0x8C080501, // 0019 GETMET R2 R2 K1 + 0x7C080200, // 001A CALL R2 1 + 0x00040308, // 001B ADD R1 R1 K8 + 0x7001FFF4, // 001C JMP #0012 + 0x80000000, // 001D 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 }) ) ); @@ -1465,7 +3613,7 @@ be_local_closure(Matter_Device_mdns_announce_op_discovery, /* name */ ( &(const bvalue[29]) { /* constants */ /* K0 */ be_nested_str_weak(mdns), /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(get_deviceid), + /* K2 */ be_nested_str_weak(get_device_id), /* K3 */ be_nested_str_weak(copy), /* K4 */ be_nested_str_weak(reverse), /* K5 */ be_nested_str_weak(get_fabric_compressed), @@ -1684,735 +3832,90 @@ be_local_closure(Matter_Device_start_commissioning_complete_deferred, /* name /*******************************************************************/ -/******************************************************************** -** Solidified function: compute_pbkdf -********************************************************************/ -be_local_closure(Matter_Device_compute_pbkdf, /* 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[24]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(salt), - /* K2 */ be_nested_str_weak(random), - /* K3 */ be_nested_str_weak(add), - /* K4 */ be_nested_str_weak(PBKDF2_HMAC_SHA256), - /* K5 */ be_nested_str_weak(derive), - /* K6 */ be_nested_str_weak(iterations), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(w0), - /* K9 */ be_nested_str_weak(EC_P256), - /* K10 */ be_nested_str_weak(mod), - /* K11 */ be_nested_str_weak(w1), - /* K12 */ be_nested_str_weak(L), - /* K13 */ be_nested_str_weak(public_key), - /* K14 */ be_nested_str_weak(tasmota), - /* K15 */ be_nested_str_weak(log), - /* K16 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(MTR_X3A_X20salt_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K19 */ be_nested_str_weak(tohex), - /* K20 */ be_nested_str_weak(MTR_X3A_X20passcode_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K21 */ be_nested_str_weak(MTR_X3A_X20w0_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K22 */ be_nested_str_weak(MTR_X3A_X20w1_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - /* K23 */ be_nested_str_weak(MTR_X3A_X20L_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D_X20), - }), - be_str_weak(compute_pbkdf), - &be_const_str_solidified, - ( &(const binstruction[94]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0502, // 0001 GETMET R3 R2 K2 - 0x5416000F, // 0002 LDINT R5 16 - 0x7C0C0400, // 0003 CALL R3 2 - 0x90020203, // 0004 SETMBR R0 K1 R3 - 0x600C0015, // 0005 GETGBL R3 G21 - 0x7C0C0000, // 0006 CALL R3 0 - 0x8C0C0703, // 0007 GETMET R3 R3 K3 - 0x5C140200, // 0008 MOVE R5 R1 - 0x541A0003, // 0009 LDINT R6 4 - 0x7C0C0600, // 000A CALL R3 3 - 0x8C100504, // 000B GETMET R4 R2 K4 - 0x7C100200, // 000C CALL R4 1 - 0x8C100905, // 000D GETMET R4 R4 K5 - 0x5C180600, // 000E MOVE R6 R3 - 0x881C0101, // 000F GETMBR R7 R0 K1 - 0x88200106, // 0010 GETMBR R8 R0 K6 - 0x5426004F, // 0011 LDINT R9 80 - 0x7C100A00, // 0012 CALL R4 5 - 0x54160026, // 0013 LDINT R5 39 - 0x40160E05, // 0014 CONNECT R5 K7 R5 - 0x94140805, // 0015 GETIDX R5 R4 R5 - 0x541A0027, // 0016 LDINT R6 40 - 0x541E004E, // 0017 LDINT R7 79 - 0x40180C07, // 0018 CONNECT R6 R6 R7 - 0x94180806, // 0019 GETIDX R6 R4 R6 - 0x8C1C0509, // 001A GETMET R7 R2 K9 - 0x7C1C0200, // 001B CALL R7 1 - 0x8C1C0F0A, // 001C GETMET R7 R7 K10 - 0x5C240A00, // 001D MOVE R9 R5 - 0x7C1C0400, // 001E CALL R7 2 - 0x90021007, // 001F SETMBR R0 K8 R7 - 0x8C1C0509, // 0020 GETMET R7 R2 K9 - 0x7C1C0200, // 0021 CALL R7 1 - 0x8C1C0F0A, // 0022 GETMET R7 R7 K10 - 0x5C240C00, // 0023 MOVE R9 R6 - 0x7C1C0400, // 0024 CALL R7 2 - 0x90021607, // 0025 SETMBR R0 K11 R7 - 0x8C1C0509, // 0026 GETMET R7 R2 K9 - 0x7C1C0200, // 0027 CALL R7 1 - 0x8C1C0F0D, // 0028 GETMET R7 R7 K13 - 0x8824010B, // 0029 GETMBR R9 R0 K11 - 0x7C1C0400, // 002A CALL R7 2 - 0x90021807, // 002B SETMBR R0 K12 R7 - 0xB81E1C00, // 002C GETNGBL R7 K14 - 0x8C1C0F0F, // 002D GETMET R7 R7 K15 - 0x58240010, // 002E LDCONST R9 K16 - 0x58280011, // 002F LDCONST R10 K17 - 0x7C1C0600, // 0030 CALL R7 3 - 0xB81E1C00, // 0031 GETNGBL R7 K14 - 0x8C1C0F0F, // 0032 GETMET R7 R7 K15 - 0x88240101, // 0033 GETMBR R9 R0 K1 - 0x8C241313, // 0034 GETMET R9 R9 K19 - 0x7C240200, // 0035 CALL R9 1 - 0x00262409, // 0036 ADD R9 K18 R9 - 0x58280011, // 0037 LDCONST R10 K17 - 0x7C1C0600, // 0038 CALL R7 3 - 0xB81E1C00, // 0039 GETNGBL R7 K14 - 0x8C1C0F0F, // 003A GETMET R7 R7 K15 - 0x8C240713, // 003B GETMET R9 R3 K19 - 0x7C240200, // 003C CALL R9 1 - 0x00262809, // 003D ADD R9 K20 R9 - 0x58280011, // 003E LDCONST R10 K17 - 0x7C1C0600, // 003F CALL R7 3 - 0xB81E1C00, // 0040 GETNGBL R7 K14 - 0x8C1C0F0F, // 0041 GETMET R7 R7 K15 - 0x88240108, // 0042 GETMBR R9 R0 K8 - 0x8C241313, // 0043 GETMET R9 R9 K19 - 0x7C240200, // 0044 CALL R9 1 - 0x00262A09, // 0045 ADD R9 K21 R9 - 0x58280011, // 0046 LDCONST R10 K17 - 0x7C1C0600, // 0047 CALL R7 3 - 0xB81E1C00, // 0048 GETNGBL R7 K14 - 0x8C1C0F0F, // 0049 GETMET R7 R7 K15 - 0x8824010B, // 004A GETMBR R9 R0 K11 - 0x8C241313, // 004B GETMET R9 R9 K19 - 0x7C240200, // 004C CALL R9 1 - 0x00262C09, // 004D ADD R9 K22 R9 - 0x58280011, // 004E LDCONST R10 K17 - 0x7C1C0600, // 004F CALL R7 3 - 0xB81E1C00, // 0050 GETNGBL R7 K14 - 0x8C1C0F0F, // 0051 GETMET R7 R7 K15 - 0x8824010C, // 0052 GETMBR R9 R0 K12 - 0x8C241313, // 0053 GETMET R9 R9 K19 - 0x7C240200, // 0054 CALL R9 1 - 0x00262E09, // 0055 ADD R9 K23 R9 - 0x58280011, // 0056 LDCONST R10 K17 - 0x7C1C0600, // 0057 CALL R7 3 - 0xB81E1C00, // 0058 GETNGBL R7 K14 - 0x8C1C0F0F, // 0059 GETMET R7 R7 K15 - 0x58240010, // 005A LDCONST R9 K16 - 0x58280011, // 005B LDCONST R10 K17 - 0x7C1C0600, // 005C CALL R7 3 - 0x80000000, // 005D RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_active_endpoints -********************************************************************/ -be_local_closure(Matter_Device_get_active_endpoints, /* 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[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins), - /* K1 */ be_nested_str_weak(get_endpoints), - /* 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[38]) { /* 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 - 0xA802001B, // 0005 EXBLK 0 #0022 - 0x5C100600, // 0006 MOVE R4 R3 - 0x7C100000, // 0007 CALL R4 0 - 0x8C140901, // 0008 GETMET R5 R4 K1 - 0x7C140200, // 0009 CALL R5 1 - 0x60180010, // 000A GETGBL R6 G16 - 0x5C1C0A00, // 000B MOVE R7 R5 - 0x7C180200, // 000C CALL R6 1 - 0xA802000F, // 000D EXBLK 0 #001E - 0x5C1C0C00, // 000E MOVE R7 R6 - 0x7C1C0000, // 000F CALL R7 0 - 0x78060002, // 0010 JMPF R1 #0014 - 0x1C200F02, // 0011 EQ R8 R7 K2 - 0x78220000, // 0012 JMPF R8 #0014 - 0x7001FFF9, // 0013 JMP #000E - 0x8C200503, // 0014 GETMET R8 R2 K3 - 0x5C280E00, // 0015 MOVE R10 R7 - 0x7C200400, // 0016 CALL R8 2 - 0x4C240000, // 0017 LDNIL R9 - 0x1C201009, // 0018 EQ R8 R8 R9 - 0x78220002, // 0019 JMPF R8 #001D - 0x8C200504, // 001A GETMET R8 R2 K4 - 0x5C280E00, // 001B MOVE R10 R7 - 0x7C200400, // 001C CALL R8 2 - 0x7001FFEF, // 001D JMP #000E - 0x58180005, // 001E LDCONST R6 K5 - 0xAC180200, // 001F CATCH R6 1 0 - 0xB0080000, // 0020 RAISE 2 R0 R0 - 0x7001FFE3, // 0021 JMP #0006 - 0x580C0005, // 0022 LDCONST R3 K5 - 0xAC0C0200, // 0023 CATCH R3 1 0 - 0xB0080000, // 0024 RAISE 2 R0 R0 - 0x80040400, // 0025 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 */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(msg_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: _start_mdns_announce -********************************************************************/ -be_local_closure(Matter_Device__start_mdns_announce, /* name */ - be_nested_proto( - 15, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[48]) { /* constants */ - /* K0 */ be_nested_str_weak(mdns), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(start), - /* K3 */ be_nested_str_weak(VP), - /* K4 */ be_nested_str_weak(vendorid), - /* K5 */ be_nested_str_weak(_X2B), - /* K6 */ be_nested_str_weak(productid), - /* K7 */ be_nested_str_weak(D), - /* K8 */ be_nested_str_weak(discriminator), - /* K9 */ be_nested_str_weak(CM), - /* K10 */ be_const_int(1), - /* K11 */ be_nested_str_weak(T), - /* K12 */ be_const_int(0), - /* K13 */ be_nested_str_weak(SII), - /* K14 */ be_nested_str_weak(SAI), - /* K15 */ be_nested_str_weak(tasmota), - /* K16 */ be_nested_str_weak(eth), - /* K17 */ be_nested_str_weak(hostname_eth), - /* K18 */ be_nested_str_weak(replace), - /* K19 */ be_nested_str_weak(find), - /* K20 */ be_nested_str_weak(mac), - /* K21 */ be_nested_str_weak(_X3A), - /* K22 */ be_nested_str_weak(), - /* K23 */ be_nested_str_weak(add_hostname), - /* K24 */ be_nested_str_weak(ip6local), - /* K25 */ be_nested_str_weak(ip), - /* K26 */ be_nested_str_weak(ip6), - /* K27 */ be_nested_str_weak(add_service), - /* K28 */ be_nested_str_weak(_matterc), - /* K29 */ be_nested_str_weak(_udp), - /* K30 */ be_nested_str_weak(commissioning_instance_eth), - /* K31 */ be_nested_str_weak(log), - /* K32 */ be_nested_str_weak(format), - /* K33 */ be_nested_str_weak(MTR_X3A_X20starting_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), - /* K34 */ be_nested_str_weak(wifi), - /* K35 */ be_nested_str_weak(commissioning_instance_wifi), - /* K36 */ be_nested_str_weak(hostname_wifi), - /* K37 */ be_const_int(2), - /* K38 */ be_nested_str_weak(_L), - /* K39 */ be_nested_str_weak(MTR_X3A_X20adding_X20subtype_X3A_X20), - /* K40 */ be_const_int(3), - /* K41 */ be_nested_str_weak(add_subtype), - /* K42 */ be_nested_str_weak(_S), - /* K43 */ be_nested_str_weak(_V), - /* K44 */ be_nested_str_weak(_CM1), - /* K45 */ be_nested_str_weak(MTR_X3A_X20Exception), - /* K46 */ be_nested_str_weak(_X7C), - /* K47 */ be_nested_str_weak(mdns_announce_op_discovery_all_sessions), - }), - be_str_weak(_start_mdns_announce), - &be_const_str_solidified, - ( &(const binstruction[292]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0x8C100502, // 0002 GETMET R4 R2 K2 - 0x7C100200, // 0003 CALL R4 1 - 0x60100013, // 0004 GETGBL R4 G19 - 0x7C100000, // 0005 CALL R4 0 - 0x60140008, // 0006 GETGBL R5 G8 - 0x88180104, // 0007 GETMBR R6 R0 K4 - 0x7C140200, // 0008 CALL R5 1 - 0x00140B05, // 0009 ADD R5 R5 K5 - 0x60180008, // 000A GETGBL R6 G8 - 0x881C0106, // 000B GETMBR R7 R0 K6 - 0x7C180200, // 000C CALL R6 1 - 0x00140A06, // 000D ADD R5 R5 R6 - 0x98120605, // 000E SETIDX R4 K3 R5 - 0x88140108, // 000F GETMBR R5 R0 K8 - 0x98120E05, // 0010 SETIDX R4 K7 R5 - 0x9812130A, // 0011 SETIDX R4 K9 K10 - 0x9812170C, // 0012 SETIDX R4 K11 K12 - 0x54161387, // 0013 LDINT R5 5000 - 0x98121A05, // 0014 SETIDX R4 K13 R5 - 0x5416012B, // 0015 LDINT R5 300 - 0x98121C05, // 0016 SETIDX R4 K14 R5 - 0xA80200F7, // 0017 EXBLK 0 #0110 - 0x7806007A, // 0018 JMPF R1 #0094 - 0xB8161E00, // 0019 GETNGBL R5 K15 - 0x8C140B10, // 001A GETMET R5 R5 K16 - 0x7C140200, // 001B CALL R5 1 - 0x8C180712, // 001C GETMET R6 R3 K18 - 0x8C200B13, // 001D GETMET R8 R5 K19 - 0x58280014, // 001E LDCONST R10 K20 - 0x7C200400, // 001F CALL R8 2 - 0x58240015, // 0020 LDCONST R9 K21 - 0x58280016, // 0021 LDCONST R10 K22 - 0x7C180800, // 0022 CALL R6 4 - 0x90022206, // 0023 SETMBR R0 K17 R6 - 0x8C180517, // 0024 GETMET R6 R2 K23 - 0x88200111, // 0025 GETMBR R8 R0 K17 - 0x8C240B13, // 0026 GETMET R9 R5 K19 - 0x582C0018, // 0027 LDCONST R11 K24 - 0x58300016, // 0028 LDCONST R12 K22 - 0x7C240600, // 0029 CALL R9 3 - 0x8C280B13, // 002A GETMET R10 R5 K19 - 0x58300019, // 002B LDCONST R12 K25 - 0x58340016, // 002C LDCONST R13 K22 - 0x7C280600, // 002D CALL R10 3 - 0x8C2C0B13, // 002E GETMET R11 R5 K19 - 0x5834001A, // 002F LDCONST R13 K26 - 0x58380016, // 0030 LDCONST R14 K22 - 0x7C2C0600, // 0031 CALL R11 3 - 0x7C180A00, // 0032 CALL R6 5 - 0x8C18051B, // 0033 GETMET R6 R2 K27 - 0x5820001C, // 0034 LDCONST R8 K28 - 0x5824001D, // 0035 LDCONST R9 K29 - 0x542A15A3, // 0036 LDINT R10 5540 - 0x5C2C0800, // 0037 MOVE R11 R4 - 0x8830011E, // 0038 GETMBR R12 R0 K30 - 0x88340111, // 0039 GETMBR R13 R0 K17 - 0x7C180E00, // 003A CALL R6 7 - 0xB81A1E00, // 003B GETNGBL R6 K15 - 0x8C180D1F, // 003C GETMET R6 R6 K31 - 0x8C200720, // 003D GETMET R8 R3 K32 - 0x58280021, // 003E LDCONST R10 K33 - 0x78060001, // 003F JMPF R1 #0042 - 0x582C0010, // 0040 LDCONST R11 K16 - 0x70020000, // 0041 JMP #0043 - 0x582C0022, // 0042 LDCONST R11 K34 - 0x78060001, // 0043 JMPF R1 #0046 - 0x8830011E, // 0044 GETMBR R12 R0 K30 - 0x70020000, // 0045 JMP #0047 - 0x88300123, // 0046 GETMBR R12 R0 K35 - 0x78060001, // 0047 JMPF R1 #004A - 0x88340111, // 0048 GETMBR R13 R0 K17 - 0x70020000, // 0049 JMP #004B - 0x88340124, // 004A GETMBR R13 R0 K36 - 0x7C200A00, // 004B CALL R8 5 - 0x58240025, // 004C LDCONST R9 K37 - 0x7C180600, // 004D CALL R6 3 - 0x60180008, // 004E GETGBL R6 G8 - 0x881C0108, // 004F GETMBR R7 R0 K8 - 0x54220FFE, // 0050 LDINT R8 4095 - 0x2C1C0E08, // 0051 AND R7 R7 R8 - 0x7C180200, // 0052 CALL R6 1 - 0x001A4C06, // 0053 ADD R6 K38 R6 - 0xB81E1E00, // 0054 GETNGBL R7 K15 - 0x8C1C0F1F, // 0055 GETMET R7 R7 K31 - 0x00264E06, // 0056 ADD R9 K39 R6 - 0x58280028, // 0057 LDCONST R10 K40 - 0x7C1C0600, // 0058 CALL R7 3 - 0x8C1C0529, // 0059 GETMET R7 R2 K41 - 0x5824001C, // 005A LDCONST R9 K28 - 0x5828001D, // 005B LDCONST R10 K29 - 0x882C011E, // 005C GETMBR R11 R0 K30 - 0x88300111, // 005D GETMBR R12 R0 K17 - 0x5C340C00, // 005E MOVE R13 R6 - 0x7C1C0C00, // 005F CALL R7 6 - 0x601C0008, // 0060 GETGBL R7 G8 - 0x88200108, // 0061 GETMBR R8 R0 K8 - 0x54260EFF, // 0062 LDINT R9 3840 - 0x2C201009, // 0063 AND R8 R8 R9 - 0x54260007, // 0064 LDINT R9 8 - 0x3C201009, // 0065 SHR R8 R8 R9 - 0x7C1C0200, // 0066 CALL R7 1 - 0x001E5407, // 0067 ADD R7 K42 R7 - 0x5C180E00, // 0068 MOVE R6 R7 - 0xB81E1E00, // 0069 GETNGBL R7 K15 - 0x8C1C0F1F, // 006A GETMET R7 R7 K31 - 0x00264E06, // 006B ADD R9 K39 R6 - 0x58280028, // 006C LDCONST R10 K40 - 0x7C1C0600, // 006D CALL R7 3 - 0x8C1C0529, // 006E GETMET R7 R2 K41 - 0x5824001C, // 006F LDCONST R9 K28 - 0x5828001D, // 0070 LDCONST R10 K29 - 0x882C011E, // 0071 GETMBR R11 R0 K30 - 0x88300111, // 0072 GETMBR R12 R0 K17 - 0x5C340C00, // 0073 MOVE R13 R6 - 0x7C1C0C00, // 0074 CALL R7 6 - 0x601C0008, // 0075 GETGBL R7 G8 - 0x88200104, // 0076 GETMBR R8 R0 K4 - 0x7C1C0200, // 0077 CALL R7 1 - 0x001E5607, // 0078 ADD R7 K43 R7 - 0x5C180E00, // 0079 MOVE R6 R7 - 0xB81E1E00, // 007A GETNGBL R7 K15 - 0x8C1C0F1F, // 007B GETMET R7 R7 K31 - 0x00264E06, // 007C ADD R9 K39 R6 - 0x58280028, // 007D LDCONST R10 K40 - 0x7C1C0600, // 007E CALL R7 3 - 0x8C1C0529, // 007F GETMET R7 R2 K41 - 0x5824001C, // 0080 LDCONST R9 K28 - 0x5828001D, // 0081 LDCONST R10 K29 - 0x882C011E, // 0082 GETMBR R11 R0 K30 - 0x88300111, // 0083 GETMBR R12 R0 K17 - 0x5C340C00, // 0084 MOVE R13 R6 - 0x7C1C0C00, // 0085 CALL R7 6 - 0x5818002C, // 0086 LDCONST R6 K44 - 0xB81E1E00, // 0087 GETNGBL R7 K15 - 0x8C1C0F1F, // 0088 GETMET R7 R7 K31 - 0x00264E06, // 0089 ADD R9 K39 R6 - 0x58280028, // 008A LDCONST R10 K40 - 0x7C1C0600, // 008B CALL R7 3 - 0x8C1C0529, // 008C GETMET R7 R2 K41 - 0x5824001C, // 008D LDCONST R9 K28 - 0x5828001D, // 008E LDCONST R10 K29 - 0x882C011E, // 008F GETMBR R11 R0 K30 - 0x88300111, // 0090 GETMBR R12 R0 K17 - 0x5C340C00, // 0091 MOVE R13 R6 - 0x7C1C0C00, // 0092 CALL R7 6 - 0x70020079, // 0093 JMP #010E - 0xB8161E00, // 0094 GETNGBL R5 K15 - 0x8C140B22, // 0095 GETMET R5 R5 K34 - 0x7C140200, // 0096 CALL R5 1 - 0x8C180712, // 0097 GETMET R6 R3 K18 - 0x8C200B13, // 0098 GETMET R8 R5 K19 - 0x58280014, // 0099 LDCONST R10 K20 - 0x7C200400, // 009A CALL R8 2 - 0x58240015, // 009B LDCONST R9 K21 - 0x58280016, // 009C LDCONST R10 K22 - 0x7C180800, // 009D CALL R6 4 - 0x90024806, // 009E SETMBR R0 K36 R6 - 0x8C180517, // 009F GETMET R6 R2 K23 - 0x88200124, // 00A0 GETMBR R8 R0 K36 - 0x8C240B13, // 00A1 GETMET R9 R5 K19 - 0x582C0018, // 00A2 LDCONST R11 K24 - 0x58300016, // 00A3 LDCONST R12 K22 - 0x7C240600, // 00A4 CALL R9 3 - 0x8C280B13, // 00A5 GETMET R10 R5 K19 - 0x58300019, // 00A6 LDCONST R12 K25 - 0x58340016, // 00A7 LDCONST R13 K22 - 0x7C280600, // 00A8 CALL R10 3 - 0x8C2C0B13, // 00A9 GETMET R11 R5 K19 - 0x5834001A, // 00AA LDCONST R13 K26 - 0x58380016, // 00AB LDCONST R14 K22 - 0x7C2C0600, // 00AC CALL R11 3 - 0x7C180A00, // 00AD CALL R6 5 - 0x8C18051B, // 00AE GETMET R6 R2 K27 - 0x5820001C, // 00AF LDCONST R8 K28 - 0x5824001D, // 00B0 LDCONST R9 K29 - 0x542A15A3, // 00B1 LDINT R10 5540 - 0x5C2C0800, // 00B2 MOVE R11 R4 - 0x88300123, // 00B3 GETMBR R12 R0 K35 - 0x88340124, // 00B4 GETMBR R13 R0 K36 - 0x7C180E00, // 00B5 CALL R6 7 - 0xB81A1E00, // 00B6 GETNGBL R6 K15 - 0x8C180D1F, // 00B7 GETMET R6 R6 K31 - 0x8C200720, // 00B8 GETMET R8 R3 K32 - 0x58280021, // 00B9 LDCONST R10 K33 - 0x78060001, // 00BA JMPF R1 #00BD - 0x582C0010, // 00BB LDCONST R11 K16 - 0x70020000, // 00BC JMP #00BE - 0x582C0022, // 00BD LDCONST R11 K34 - 0x78060001, // 00BE JMPF R1 #00C1 - 0x8830011E, // 00BF GETMBR R12 R0 K30 - 0x70020000, // 00C0 JMP #00C2 - 0x88300123, // 00C1 GETMBR R12 R0 K35 - 0x78060001, // 00C2 JMPF R1 #00C5 - 0x88340111, // 00C3 GETMBR R13 R0 K17 - 0x70020000, // 00C4 JMP #00C6 - 0x88340124, // 00C5 GETMBR R13 R0 K36 - 0x7C200A00, // 00C6 CALL R8 5 - 0x58240025, // 00C7 LDCONST R9 K37 - 0x7C180600, // 00C8 CALL R6 3 - 0x60180008, // 00C9 GETGBL R6 G8 - 0x881C0108, // 00CA GETMBR R7 R0 K8 - 0x54220FFE, // 00CB LDINT R8 4095 - 0x2C1C0E08, // 00CC AND R7 R7 R8 - 0x7C180200, // 00CD CALL R6 1 - 0x001A4C06, // 00CE ADD R6 K38 R6 - 0xB81E1E00, // 00CF GETNGBL R7 K15 - 0x8C1C0F1F, // 00D0 GETMET R7 R7 K31 - 0x00264E06, // 00D1 ADD R9 K39 R6 - 0x58280028, // 00D2 LDCONST R10 K40 - 0x7C1C0600, // 00D3 CALL R7 3 - 0x8C1C0529, // 00D4 GETMET R7 R2 K41 - 0x5824001C, // 00D5 LDCONST R9 K28 - 0x5828001D, // 00D6 LDCONST R10 K29 - 0x882C0123, // 00D7 GETMBR R11 R0 K35 - 0x88300124, // 00D8 GETMBR R12 R0 K36 - 0x5C340C00, // 00D9 MOVE R13 R6 - 0x7C1C0C00, // 00DA CALL R7 6 - 0x601C0008, // 00DB GETGBL R7 G8 - 0x88200108, // 00DC GETMBR R8 R0 K8 - 0x54260EFF, // 00DD LDINT R9 3840 - 0x2C201009, // 00DE AND R8 R8 R9 - 0x54260007, // 00DF LDINT R9 8 - 0x3C201009, // 00E0 SHR R8 R8 R9 - 0x7C1C0200, // 00E1 CALL R7 1 - 0x001E5407, // 00E2 ADD R7 K42 R7 - 0x5C180E00, // 00E3 MOVE R6 R7 - 0xB81E1E00, // 00E4 GETNGBL R7 K15 - 0x8C1C0F1F, // 00E5 GETMET R7 R7 K31 - 0x00264E06, // 00E6 ADD R9 K39 R6 - 0x58280028, // 00E7 LDCONST R10 K40 - 0x7C1C0600, // 00E8 CALL R7 3 - 0x8C1C0529, // 00E9 GETMET R7 R2 K41 - 0x5824001C, // 00EA LDCONST R9 K28 - 0x5828001D, // 00EB LDCONST R10 K29 - 0x882C0123, // 00EC GETMBR R11 R0 K35 - 0x88300124, // 00ED GETMBR R12 R0 K36 - 0x5C340C00, // 00EE MOVE R13 R6 - 0x7C1C0C00, // 00EF CALL R7 6 - 0x601C0008, // 00F0 GETGBL R7 G8 - 0x88200104, // 00F1 GETMBR R8 R0 K4 - 0x7C1C0200, // 00F2 CALL R7 1 - 0x001E5607, // 00F3 ADD R7 K43 R7 - 0x5C180E00, // 00F4 MOVE R6 R7 - 0xB81E1E00, // 00F5 GETNGBL R7 K15 - 0x8C1C0F1F, // 00F6 GETMET R7 R7 K31 - 0x00264E06, // 00F7 ADD R9 K39 R6 - 0x58280028, // 00F8 LDCONST R10 K40 - 0x7C1C0600, // 00F9 CALL R7 3 - 0x8C1C0529, // 00FA GETMET R7 R2 K41 - 0x5824001C, // 00FB LDCONST R9 K28 - 0x5828001D, // 00FC LDCONST R10 K29 - 0x882C0123, // 00FD GETMBR R11 R0 K35 - 0x88300124, // 00FE GETMBR R12 R0 K36 - 0x5C340C00, // 00FF MOVE R13 R6 - 0x7C1C0C00, // 0100 CALL R7 6 - 0x5818002C, // 0101 LDCONST R6 K44 - 0xB81E1E00, // 0102 GETNGBL R7 K15 - 0x8C1C0F1F, // 0103 GETMET R7 R7 K31 - 0x00264E06, // 0104 ADD R9 K39 R6 - 0x58280028, // 0105 LDCONST R10 K40 - 0x7C1C0600, // 0106 CALL R7 3 - 0x8C1C0529, // 0107 GETMET R7 R2 K41 - 0x5824001C, // 0108 LDCONST R9 K28 - 0x5828001D, // 0109 LDCONST R10 K29 - 0x882C0123, // 010A GETMBR R11 R0 K35 - 0x88300124, // 010B GETMBR R12 R0 K36 - 0x5C340C00, // 010C MOVE R13 R6 - 0x7C1C0C00, // 010D CALL R7 6 - 0xA8040001, // 010E EXBLK 1 1 - 0x70020010, // 010F JMP #0121 - 0xAC140002, // 0110 CATCH R5 0 2 - 0x7002000D, // 0111 JMP #0120 - 0xB81E1E00, // 0112 GETNGBL R7 K15 - 0x8C1C0F1F, // 0113 GETMET R7 R7 K31 - 0x60240008, // 0114 GETGBL R9 G8 - 0x5C280A00, // 0115 MOVE R10 R5 - 0x7C240200, // 0116 CALL R9 1 - 0x00265A09, // 0117 ADD R9 K45 R9 - 0x0024132E, // 0118 ADD R9 R9 K46 - 0x60280008, // 0119 GETGBL R10 G8 - 0x5C2C0C00, // 011A MOVE R11 R6 - 0x7C280200, // 011B CALL R10 1 - 0x0024120A, // 011C ADD R9 R9 R10 - 0x58280025, // 011D LDCONST R10 K37 - 0x7C1C0600, // 011E CALL R7 3 - 0x70020000, // 011F JMP #0121 - 0xB0080000, // 0120 RAISE 2 R0 R0 - 0x8C14012F, // 0121 GETMET R5 R0 K47 - 0x7C140200, // 0122 CALL R5 1 - 0x80000000, // 0123 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: packet_ack -********************************************************************/ -be_local_closure(Matter_Device_packet_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(packet_ack), - }), - be_str_weak(packet_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: msg_send -********************************************************************/ -be_local_closure(Matter_Device_msg_send, /* name */ - be_nested_proto( - 11, /* nstack */ - 5, /* 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_response), - }), - be_str_weak(msg_send), - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x88140100, // 0000 GETMBR R5 R0 K0 - 0x8C140B01, // 0001 GETMET R5 R5 K1 - 0x5C1C0200, // 0002 MOVE R7 R1 - 0x5C200400, // 0003 MOVE R8 R2 - 0x5C240600, // 0004 MOVE R9 R3 - 0x5C280800, // 0005 MOVE R10 R4 - 0x7C140A00, // 0006 CALL R5 5 - 0x80040A00, // 0007 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Device ********************************************************************/ be_local_class(Matter_Device, - 18, + 28, NULL, - be_nested_map(49, + be_nested_map(76, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(compute_manual_pairing_code, 12), be_const_closure(Matter_Device_compute_manual_pairing_code_closure) }, - { be_const_key_weak(msg_handler, 45), be_const_var(2) }, - { be_const_key_weak(FILENAME, 20), be_nested_str_weak(_matter_device_X2Ejson) }, - { be_const_key_weak(plugins, 40), be_const_var(0) }, - { be_const_key_weak(process_attribute_expansion, -1), be_const_closure(Matter_Device_process_attribute_expansion_closure) }, - { be_const_key_weak(msg_send, -1), be_const_closure(Matter_Device_msg_send_closure) }, - { be_const_key_weak(packet_ack, -1), be_const_closure(Matter_Device_packet_ack_closure) }, - { be_const_key_weak(save_param, 48), be_const_closure(Matter_Device_save_param_closure) }, - { be_const_key_weak(_start_mdns_announce, -1), be_const_closure(Matter_Device__start_mdns_announce_closure) }, - { be_const_key_weak(start_operational_dicovery_deferred, -1), be_const_closure(Matter_Device_start_operational_dicovery_deferred_closure) }, - { be_const_key_weak(ui, 47), be_const_var(4) }, - { be_const_key_weak(w0, -1), be_const_var(15) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Device_invoke_request_closure) }, - { be_const_key_weak(passcode, 15), be_const_var(12) }, - { be_const_key_weak(start_mdns_announce_hostnames, -1), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, - { be_const_key_weak(hostname_eth, 31), be_const_var(8) }, - { be_const_key_weak(L, -1), be_const_var(17) }, - { be_const_key_weak(every_second, 8), be_const_closure(Matter_Device_every_second_closure) }, - { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Device_init_closure) }, - { be_const_key_weak(get_active_endpoints, -1), be_const_closure(Matter_Device_get_active_endpoints_closure) }, - { be_const_key_weak(iterations, 43), be_const_var(13) }, - { be_const_key_weak(commissioning_instance_eth, -1), be_const_var(6) }, - { be_const_key_weak(start_operational_dicovery, 41), be_const_closure(Matter_Device_start_operational_dicovery_closure) }, - { be_const_key_weak(start_commissioning_complete, 16), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, - { be_const_key_weak(start_basic_commissioning, 42), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, - { be_const_key_weak(productid, -1), be_const_var(10) }, { be_const_key_weak(PRODUCT_ID, -1), be_const_int(32768) }, - { be_const_key_weak(PBKDF_ITERATIONS, 36), be_const_int(1000) }, - { be_const_key_weak(salt, 5), be_const_var(14) }, - { be_const_key_weak(w1, -1), be_const_var(16) }, - { be_const_key_weak(start_commissioning_complete_deferred, -1), be_const_closure(Matter_Device_start_commissioning_complete_deferred_closure) }, - { be_const_key_weak(mdns_announce_op_discovery, 27), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, - { be_const_key_weak(discriminator, -1), be_const_var(11) }, - { be_const_key_weak(commissioning_instance_wifi, -1), be_const_var(5) }, - { be_const_key_weak(start_udp, 34), be_const_closure(Matter_Device_start_udp_closure) }, + { be_const_key_weak(start_operational_discovery, 57), be_const_closure(Matter_Device_start_operational_discovery_closure) }, + { be_const_key_weak(root_L, 14), be_const_var(27) }, + { be_const_key_weak(commissioning_discriminator, 10), be_const_var(8) }, + { be_const_key_weak(FILENAME, 41), be_nested_str_weak(_matter_device_X2Ejson) }, + { be_const_key_weak(_init_basic_commissioning, -1), 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(_trigger_read_sensors, -1), be_const_closure(Matter_Device__trigger_read_sensors_closure) }, + { be_const_key_weak(hostname_eth, -1), be_const_var(16) }, + { be_const_key_weak(productid, 44), be_const_var(18) }, + { be_const_key_weak(start, -1), be_const_closure(Matter_Device_start_closure) }, + { be_const_key_weak(root_salt, -1), be_const_var(25) }, + { be_const_key_weak(mdns_announce_op_discovery, 65), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, + { be_const_key_weak(start_operational_discovery_deferred, -1), be_const_closure(Matter_Device_start_operational_discovery_deferred_closure) }, + { 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(UDP_PORT, -1), be_const_int(5540) }, - { be_const_key_weak(compute_pbkdf, -1), be_const_closure(Matter_Device_compute_pbkdf_closure) }, - { be_const_key_weak(hostname_wifi, -1), be_const_var(7) }, - { be_const_key_weak(udp_server, 2), be_const_var(1) }, - { be_const_key_weak(finish_commissioning, -1), be_const_closure(Matter_Device_finish_commissioning_closure) }, - { be_const_key_weak(compute_qrcode_content, -1), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, + { be_const_key_weak(compute_qrcode_content, 71), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, + { be_const_key_weak(msg_send, 42), be_const_closure(Matter_Device_msg_send_closure) }, + { be_const_key_weak(commissioning_instance_eth, -1), be_const_var(14) }, + { be_const_key_weak(PBKDF_ITERATIONS, 16), be_const_int(1000) }, + { be_const_key_weak(received_ack, -1), be_const_closure(Matter_Device_received_ack_closure) }, + { 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(plugins, 40), be_const_var(1) }, + { be_const_key_weak(commissioning_admin_fabric, -1), be_const_var(12) }, + { be_const_key_weak(commissioning_iterations, 17), be_const_var(7) }, + { be_const_key_weak(root_passcode, 63), be_const_var(22) }, + { be_const_key_weak(mdns_pase_eth, 36), be_const_var(19) }, + { be_const_key_weak(autoconf_device, 33), be_const_closure(Matter_Device_autoconf_device_closure) }, + { be_const_key_weak(mdns_announce_PASE, -1), be_const_closure(Matter_Device_mdns_announce_PASE_closure) }, + { be_const_key_weak(get_active_endpoints, 29), be_const_closure(Matter_Device_get_active_endpoints_closure) }, + { be_const_key_weak(attribute_updated, -1), be_const_closure(Matter_Device_attribute_updated_closure) }, + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_Device_every_250ms_closure) }, + { 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(save_param, 12), be_const_closure(Matter_Device_save_param_closure) }, + { be_const_key_weak(process_attribute_expansion, 30), be_const_closure(Matter_Device_process_attribute_expansion_closure) }, + { be_const_key_weak(commissioning_L, -1), be_const_var(11) }, + { be_const_key_weak(root_w0, -1), be_const_var(26) }, + { be_const_key_weak(started, 64), be_const_var(0) }, + { be_const_key_weak(message_handler, -1), be_const_var(3) }, { be_const_key_weak(PASSCODE_DEFAULT, -1), be_const_int(20202021) }, - { be_const_key_weak(vendorid, 44), be_const_var(9) }, - { be_const_key_weak(sessions, -1), be_const_var(3) }, - { be_const_key_weak(mdns_announce_op_discovery_all_sessions, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_all_sessions_closure) }, - { be_const_key_weak(msg_received, 6), be_const_closure(Matter_Device_msg_received_closure) }, + { be_const_key_weak(stop_basic_commissioning, -1), be_const_closure(Matter_Device_stop_basic_commissioning_closure) }, + { be_const_key_weak(_compute_pbkdf, -1), be_const_closure(Matter_Device__compute_pbkdf_closure) }, + { be_const_key_weak(is_root_commissioning_open, -1), be_const_closure(Matter_Device_is_root_commissioning_open_closure) }, + { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, + { be_const_key_weak(commissioning_open, -1), be_const_var(6) }, + { be_const_key_weak(commissioning_instance_wifi, 60), be_const_var(13) }, + { be_const_key_weak(mdns_remove_op_discovery, 62), be_const_closure(Matter_Device_mdns_remove_op_discovery_closure) }, + { be_const_key_weak(sessions, -1), be_const_var(4) }, { be_const_key_weak(stop, -1), be_const_closure(Matter_Device_stop_closure) }, + { be_const_key_weak(root_discriminator, -1), be_const_var(21) }, + { be_const_key_weak(init, 55), be_const_closure(Matter_Device_init_closure) }, + { be_const_key_weak(msg_received, -1), be_const_closure(Matter_Device_msg_received_closure) }, + { be_const_key_weak(commissioning_salt, -1), be_const_var(9) }, + { be_const_key_weak(sort_distinct, -1), be_const_static_closure(Matter_Device_sort_distinct_closure) }, + { be_const_key_weak(ui, 47), be_const_var(5) }, + { be_const_key_weak(hostname_wifi, -1), be_const_var(15) }, + { be_const_key_weak(start_mdns_announce_hostnames, 13), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, + { be_const_key_weak(_mdns_announce_hostname, -1), be_const_closure(Matter_Device__mdns_announce_hostname_closure) }, { be_const_key_weak(load_param, -1), be_const_closure(Matter_Device_load_param_closure) }, + { be_const_key_weak(vendorid, 73), be_const_var(17) }, + { be_const_key_weak(mdns_pase_wifi, -1), be_const_var(20) }, + { be_const_key_weak(start_commissioning_complete, -1), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, + { be_const_key_weak(commissioning_w0, 68), be_const_var(10) }, + { be_const_key_weak(start_basic_commissioning, -1), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, + { be_const_key_weak(PASE_TIMEOUT, -1), be_const_int(600) }, + { be_const_key_weak(udp_server, -1), be_const_var(2) }, + { be_const_key_weak(invoke_request, 28), be_const_closure(Matter_Device_invoke_request_closure) }, + { be_const_key_weak(_start_udp, -1), be_const_closure(Matter_Device__start_udp_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Device_every_second_closure) }, + { be_const_key_weak(mdns_remove_PASE, 15), be_const_closure(Matter_Device_mdns_remove_PASE_closure) }, + { be_const_key_weak(remove_fabric, -1), be_const_closure(Matter_Device_remove_fabric_closure) }, + { be_const_key_weak(ipv4only, -1), be_const_var(23) }, + { be_const_key_weak(root_iterations, -1), be_const_var(24) }, + { be_const_key_weak(is_commissioning_open, 11), 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_str_weak(Matter_Device) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Expirable.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Expirable.h new file mode 100644 index 000000000..59867c307 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Expirable.h @@ -0,0 +1,771 @@ +/* Solidification of Matter_Expirable.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Expirable; + +/******************************************************************** +** Solidified function: before_remove +********************************************************************/ +be_local_closure(Matter_Expirable_before_remove, /* 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(before_remove), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_no_expiration +********************************************************************/ +be_local_closure(Matter_Expirable_set_no_expiration, /* 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(_expiration), + }), + be_str_weak(set_no_expiration), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x4C040000, // 0000 LDNIL R1 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Expirable_init, /* 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(_persist), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_expire_time +********************************************************************/ +be_local_closure(Matter_Expirable_set_expire_time, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* 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(_expiration), + }), + be_str_weak(set_expire_time), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: has_expired +********************************************************************/ +be_local_closure(Matter_Expirable_has_expired, /* name */ + be_nested_proto( + 4, /* 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(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(_expiration), + }), + be_str_weak(has_expired), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0003, // 0002 JMPF R2 #0007 + 0xB80A0000, // 0003 GETNGBL R2 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x7C080200, // 0005 CALL R2 1 + 0x94040502, // 0006 GETIDX R1 R2 K2 + 0x88080103, // 0007 GETMBR R2 R0 K3 + 0x4C0C0000, // 0008 LDNIL R3 + 0x20080403, // 0009 NE R2 R2 R3 + 0x780A0002, // 000A JMPF R2 #000E + 0x88080103, // 000B GETMBR R2 R0 K3 + 0x28080202, // 000C GE R2 R1 R2 + 0x80040400, // 000D RET 1 R2 + 0x50080000, // 000E LDBOOL R2 0 0 + 0x80040400, // 000F RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_parent_list +********************************************************************/ +be_local_closure(Matter_Expirable_set_parent_list, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(_list), + }), + be_str_weak(set_parent_list), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: hydrate_post +********************************************************************/ +be_local_closure(Matter_Expirable_hydrate_post, /* 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(hydrate_post), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_expire_in_seconds +********************************************************************/ +be_local_closure(Matter_Expirable_set_expire_in_seconds, /* 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(tasmota), + /* K1 */ be_nested_str_weak(rtc), + /* K2 */ be_nested_str_weak(utc), + /* K3 */ be_nested_str_weak(set_expire_time), + }), + be_str_weak(set_expire_in_seconds), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x80000600, // 0003 RET 0 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C0C0403, // 0005 EQ R3 R2 R3 + 0x780E0003, // 0006 JMPF R3 #000B + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x94080702, // 000A GETIDX R2 R3 K2 + 0x8C0C0103, // 000B GETMET R3 R0 K3 + 0x00140401, // 000C ADD R5 R2 R1 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_parent_list +********************************************************************/ +be_local_closure(Matter_Expirable_get_parent_list, /* 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(_list), + }), + be_str_weak(get_parent_list), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: does_persist +********************************************************************/ +be_local_closure(Matter_Expirable_does_persist, /* 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(_persist), + }), + be_str_weak(does_persist), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_persist +********************************************************************/ +be_local_closure(Matter_Expirable_set_persist, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* 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(_persist), + }), + be_str_weak(set_persist), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080017, // 0000 GETGBL R2 G23 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: persist_pre +********************************************************************/ +be_local_closure(Matter_Expirable_persist_pre, /* 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(persist_pre), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: persist_post +********************************************************************/ +be_local_closure(Matter_Expirable_persist_post, /* 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(persist_post), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Expirable +********************************************************************/ +be_local_class(Matter_Expirable, + 3, + NULL, + be_nested_map(16, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(_expiration, -1), be_const_var(2) }, + { be_const_key_weak(set_no_expiration, 9), be_const_closure(Matter_Expirable_set_no_expiration_closure) }, + { be_const_key_weak(persist_post, -1), be_const_closure(Matter_Expirable_persist_post_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Expirable_init_closure) }, + { be_const_key_weak(has_expired, -1), be_const_closure(Matter_Expirable_has_expired_closure) }, + { be_const_key_weak(set_expire_time, 6), be_const_closure(Matter_Expirable_set_expire_time_closure) }, + { be_const_key_weak(set_parent_list, 4), be_const_closure(Matter_Expirable_set_parent_list_closure) }, + { be_const_key_weak(hydrate_post, -1), be_const_closure(Matter_Expirable_hydrate_post_closure) }, + { be_const_key_weak(set_expire_in_seconds, -1), be_const_closure(Matter_Expirable_set_expire_in_seconds_closure) }, + { be_const_key_weak(get_parent_list, 8), be_const_closure(Matter_Expirable_get_parent_list_closure) }, + { be_const_key_weak(_list, -1), be_const_var(0) }, + { be_const_key_weak(does_persist, -1), be_const_closure(Matter_Expirable_does_persist_closure) }, + { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Expirable_set_persist_closure) }, + { be_const_key_weak(persist_pre, -1), be_const_closure(Matter_Expirable_persist_pre_closure) }, + { be_const_key_weak(_persist, 2), be_const_var(1) }, + { be_const_key_weak(before_remove, 0), be_const_closure(Matter_Expirable_before_remove_closure) }, + })), + be_str_weak(Matter_Expirable) +); +/*******************************************************************/ + +void be_load_Matter_Expirable_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Expirable); + be_setglobal(vm, "Matter_Expirable"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_Expirable_list; + +/******************************************************************** +** Solidified function: count_persistables +********************************************************************/ +be_local_closure(Matter_Expirable_list_count_persistables, /* 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_const_int(0), + /* K1 */ be_nested_str_weak(_persist), + /* K2 */ be_const_int(1), + }), + be_str_weak(count_persistables), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x58080000, // 0001 LDCONST R2 K0 + 0x600C000C, // 0002 GETGBL R3 G12 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x140C0403, // 0005 LT R3 R2 R3 + 0x780E0005, // 0006 JMPF R3 #000D + 0x940C0002, // 0007 GETIDX R3 R0 R2 + 0x880C0701, // 0008 GETMBR R3 R3 K1 + 0x780E0000, // 0009 JMPF R3 #000B + 0x00040302, // 000A ADD R1 R1 K2 + 0x00080502, // 000B ADD R2 R2 K2 + 0x7001FFF4, // 000C JMP #0002 + 0x80040200, // 000D RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove +********************************************************************/ +be_local_closure(Matter_Expirable_list_remove, /* 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[ 3]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(before_remove), + /* K2 */ be_nested_str_weak(remove), + }), + be_str_weak(remove), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x28080300, // 0000 GE R2 R1 K0 + 0x780A0007, // 0001 JMPF R2 #000A + 0x6008000C, // 0002 GETGBL R2 G12 + 0x5C0C0000, // 0003 MOVE R3 R0 + 0x7C080200, // 0004 CALL R2 1 + 0x14080202, // 0005 LT R2 R1 R2 + 0x780A0002, // 0006 JMPF R2 #000A + 0x94080001, // 0007 GETIDX R2 R0 R1 + 0x8C080501, // 0008 GETMET R2 R2 K1 + 0x7C080200, // 0009 CALL R2 1 + 0x60080003, // 000A GETGBL R2 G3 + 0x5C0C0000, // 000B MOVE R3 R0 + 0x7C080200, // 000C CALL R2 1 + 0x8C080502, // 000D GETMET R2 R2 K2 + 0x5C100200, // 000E MOVE R4 R1 + 0x7C080400, // 000F CALL R2 2 + 0x80040400, // 0010 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: push +********************************************************************/ +be_local_closure(Matter_Expirable_list_push, /* 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[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Expirable), + /* K2 */ be_nested_str_weak(type_error), + /* K3 */ be_nested_str_weak(argument_X20must_X20be_X20of_X20class_X20_X27Expirable_X27), + /* K4 */ be_nested_str_weak(set_parent_list), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(push), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x6008000F, // 0000 GETGBL R2 G15 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0xB8120000, // 0002 GETNGBL R4 K0 + 0x88100901, // 0003 GETMBR R4 R4 K1 + 0x7C080400, // 0004 CALL R2 2 + 0x740A0000, // 0005 JMPT R2 #0007 + 0xB0060503, // 0006 RAISE 1 K2 K3 + 0x8C080304, // 0007 GETMET R2 R1 K4 + 0x5C100000, // 0008 MOVE R4 R0 + 0x7C080400, // 0009 CALL R2 2 + 0x60080003, // 000A GETGBL R2 G3 + 0x5C0C0000, // 000B MOVE R3 R0 + 0x7C080200, // 000C CALL R2 1 + 0x8C080505, // 000D GETMET R2 R2 K5 + 0x5C100200, // 000E MOVE R4 R1 + 0x7C080400, // 000F CALL R2 2 + 0x80040400, // 0010 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Expirable_list_every_second, /* 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(remove_expired), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_expired +********************************************************************/ +be_local_closure(Matter_Expirable_list_remove_expired, /* 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[ 5]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(has_expired), + /* K2 */ be_nested_str_weak(_persist), + /* K3 */ be_nested_str_weak(remove), + /* K4 */ be_const_int(1), + }), + be_str_weak(remove_expired), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x58080000, // 0001 LDCONST R2 K0 + 0x600C000C, // 0002 GETGBL R3 G12 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x140C0403, // 0005 LT R3 R2 R3 + 0x780E000D, // 0006 JMPF R3 #0015 + 0x940C0002, // 0007 GETIDX R3 R0 R2 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x780E0007, // 000A JMPF R3 #0013 + 0x940C0002, // 000B GETIDX R3 R0 R2 + 0x880C0702, // 000C GETMBR R3 R3 K2 + 0x780E0000, // 000D JMPF R3 #000F + 0x50040200, // 000E LDBOOL R1 1 0 + 0x8C0C0103, // 000F GETMET R3 R0 K3 + 0x5C140400, // 0010 MOVE R5 R2 + 0x7C0C0400, // 0011 CALL R3 2 + 0x70020000, // 0012 JMP #0014 + 0x00080504, // 0013 ADD R2 R2 K4 + 0x7001FFEC, // 0014 JMP #0002 + 0x80040200, // 0015 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: persistables +********************************************************************/ +be_local_closure(Matter_Expirable_list_persistables, /* name */ + be_nested_proto( + 3, /* 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, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_persist), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x50000200, // 0000 LDBOOL R0 1 0 + 0x78020005, // 0001 JMPF R0 #0008 + 0x68000000, // 0002 GETUPV R0 U0 + 0x7C000000, // 0003 CALL R0 0 + 0x88040100, // 0004 GETMBR R1 R0 K0 + 0x78060000, // 0005 JMPF R1 #0007 + 0x80040000, // 0006 RET 1 R0 + 0x7001FFF7, // 0007 JMP #0000 + 0x80000000, // 0008 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(iter), + }), + be_str_weak(persistables), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x84080000, // 0002 CLOSURE R2 P0 + 0xA0000000, // 0003 CLOSE R0 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: setitem +********************************************************************/ +be_local_closure(Matter_Expirable_list_setitem, /* 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[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Expirable), + /* K2 */ be_nested_str_weak(type_error), + /* K3 */ be_nested_str_weak(argument_X20must_X20be_X20of_X20class_X20_X27Expirable_X27), + /* K4 */ be_nested_str_weak(set_parent_list), + /* K5 */ be_nested_str_weak(setitem), + }), + be_str_weak(setitem), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x600C000F, // 0000 GETGBL R3 G15 + 0x5C100400, // 0001 MOVE R4 R2 + 0xB8160000, // 0002 GETNGBL R5 K0 + 0x88140B01, // 0003 GETMBR R5 R5 K1 + 0x7C0C0400, // 0004 CALL R3 2 + 0x740E0000, // 0005 JMPT R3 #0007 + 0xB0060503, // 0006 RAISE 1 K2 K3 + 0x8C0C0504, // 0007 GETMET R3 R2 K4 + 0x5C140000, // 0008 MOVE R5 R0 + 0x7C0C0400, // 0009 CALL R3 2 + 0x600C0003, // 000A GETGBL R3 G3 + 0x5C100000, // 000B MOVE R4 R0 + 0x7C0C0200, // 000C CALL R3 1 + 0x8C0C0705, // 000D GETMET R3 R3 K5 + 0x5C140200, // 000E MOVE R5 R1 + 0x5C180400, // 000F MOVE R6 R2 + 0x7C0C0600, // 0010 CALL R3 3 + 0x80040600, // 0011 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Expirable_list +********************************************************************/ +extern const bclass be_class_list; +be_local_class(Matter_Expirable_list, + 0, + &be_class_list, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(count_persistables, 4), be_const_closure(Matter_Expirable_list_count_persistables_closure) }, + { be_const_key_weak(remove, -1), be_const_closure(Matter_Expirable_list_remove_closure) }, + { be_const_key_weak(push, 5), be_const_closure(Matter_Expirable_list_push_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Expirable_list_every_second_closure) }, + { be_const_key_weak(setitem, 6), be_const_closure(Matter_Expirable_list_setitem_closure) }, + { be_const_key_weak(persistables, -1), be_const_closure(Matter_Expirable_list_persistables_closure) }, + { be_const_key_weak(remove_expired, -1), be_const_closure(Matter_Expirable_list_remove_expired_closure) }, + })), + be_str_weak(Matter_Expirable_list) +); +/*******************************************************************/ + +void be_load_Matter_Expirable_list_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Expirable_list); + be_setglobal(vm, "Matter_Expirable_list"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h new file mode 100644 index 000000000..94d1f1d16 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Fabric.h @@ -0,0 +1,1321 @@ +/* Solidification of Matter_Fabric.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Fabric; + +/******************************************************************** +** Solidified function: tojson +********************************************************************/ +be_local_closure(Matter_Fabric_tojson, /* name */ + be_nested_proto( + 18, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[29]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(persist_pre), + /* K4 */ be_nested_str_weak(members), + /* K5 */ be_nested_str_weak(get), + /* K6 */ be_nested_str_weak(function), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(_), + /* K9 */ be_nested_str_weak(push), + /* K10 */ be_nested_str_weak(stop_iteration), + /* K11 */ be_nested_str_weak(matter), + /* K12 */ be_nested_str_weak(sort), + /* K13 */ be_nested_str_weak(_X24_X24), + /* K14 */ be_nested_str_weak(tob64), + /* K15 */ be_nested_str_weak(format), + /* K16 */ be_nested_str_weak(_X25s_X3A_X25s), + /* K17 */ be_nested_str_weak(dump), + /* K18 */ be_nested_str_weak(_sessions), + /* K19 */ be_nested_str_weak(persistables), + /* K20 */ be_nested_str_weak(tojson), + /* K21 */ be_nested_str_weak(_X5B), + /* K22 */ be_nested_str_weak(concat), + /* K23 */ be_nested_str_weak(_X2C), + /* K24 */ be_nested_str_weak(_X5D), + /* K25 */ be_nested_str_weak(_X22_sessions_X22_X3A), + /* K26 */ be_nested_str_weak(persist_post), + /* K27 */ be_nested_str_weak(_X7B), + /* K28 */ be_nested_str_weak(_X7D), + }), + be_str_weak(tojson), + &be_const_str_solidified, + ( &(const binstruction[120]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA40E0400, // 0002 IMPORT R3 K2 + 0x8C100103, // 0003 GETMET R4 R0 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x60100012, // 0005 GETGBL R4 G18 + 0x7C100000, // 0006 CALL R4 0 + 0x60140010, // 0007 GETGBL R5 G16 + 0x8C180704, // 0008 GETMET R6 R3 K4 + 0x5C200000, // 0009 MOVE R8 R0 + 0x7C180400, // 000A CALL R6 2 + 0x7C140200, // 000B CALL R5 1 + 0xA8020011, // 000C EXBLK 0 #001F + 0x5C180A00, // 000D MOVE R6 R5 + 0x7C180000, // 000E CALL R6 0 + 0x8C1C0705, // 000F GETMET R7 R3 K5 + 0x5C240000, // 0010 MOVE R9 R0 + 0x5C280C00, // 0011 MOVE R10 R6 + 0x7C1C0600, // 0012 CALL R7 3 + 0x60200004, // 0013 GETGBL R8 G4 + 0x5C240E00, // 0014 MOVE R9 R7 + 0x7C200200, // 0015 CALL R8 1 + 0x20201106, // 0016 NE R8 R8 K6 + 0x78220005, // 0017 JMPF R8 #001E + 0x94200D07, // 0018 GETIDX R8 R6 K7 + 0x20201108, // 0019 NE R8 R8 K8 + 0x78220002, // 001A JMPF R8 #001E + 0x8C200909, // 001B GETMET R8 R4 K9 + 0x5C280C00, // 001C MOVE R10 R6 + 0x7C200400, // 001D CALL R8 2 + 0x7001FFED, // 001E JMP #000D + 0x5814000A, // 001F LDCONST R5 K10 + 0xAC140200, // 0020 CATCH R5 1 0 + 0xB0080000, // 0021 RAISE 2 R0 R0 + 0xB8161600, // 0022 GETNGBL R5 K11 + 0x8C140B0C, // 0023 GETMET R5 R5 K12 + 0x5C1C0800, // 0024 MOVE R7 R4 + 0x7C140400, // 0025 CALL R5 2 + 0x5C100A00, // 0026 MOVE R4 R5 + 0x60140012, // 0027 GETGBL R5 G18 + 0x7C140000, // 0028 CALL R5 0 + 0x60180010, // 0029 GETGBL R6 G16 + 0x5C1C0800, // 002A MOVE R7 R4 + 0x7C180200, // 002B CALL R6 1 + 0xA8020020, // 002C EXBLK 0 #004E + 0x5C1C0C00, // 002D MOVE R7 R6 + 0x7C1C0000, // 002E CALL R7 0 + 0x8C200705, // 002F GETMET R8 R3 K5 + 0x5C280000, // 0030 MOVE R10 R0 + 0x5C2C0E00, // 0031 MOVE R11 R7 + 0x7C200600, // 0032 CALL R8 3 + 0x4C240000, // 0033 LDNIL R9 + 0x1C241009, // 0034 EQ R9 R8 R9 + 0x78260000, // 0035 JMPF R9 #0037 + 0x7001FFF5, // 0036 JMP #002D + 0x6024000F, // 0037 GETGBL R9 G15 + 0x5C281000, // 0038 MOVE R10 R8 + 0x602C0015, // 0039 GETGBL R11 G21 + 0x7C240400, // 003A CALL R9 2 + 0x78260003, // 003B JMPF R9 #0040 + 0x8C24110E, // 003C GETMET R9 R8 K14 + 0x7C240200, // 003D CALL R9 1 + 0x00261A09, // 003E ADD R9 K13 R9 + 0x5C201200, // 003F MOVE R8 R9 + 0x8C240B09, // 0040 GETMET R9 R5 K9 + 0x8C2C050F, // 0041 GETMET R11 R2 K15 + 0x58340010, // 0042 LDCONST R13 K16 + 0x8C380311, // 0043 GETMET R14 R1 K17 + 0x60400008, // 0044 GETGBL R16 G8 + 0x5C440E00, // 0045 MOVE R17 R7 + 0x7C400200, // 0046 CALL R16 1 + 0x7C380400, // 0047 CALL R14 2 + 0x8C3C0311, // 0048 GETMET R15 R1 K17 + 0x5C441000, // 0049 MOVE R17 R8 + 0x7C3C0400, // 004A CALL R15 2 + 0x7C2C0800, // 004B CALL R11 4 + 0x7C240400, // 004C CALL R9 2 + 0x7001FFDE, // 004D JMP #002D + 0x5818000A, // 004E LDCONST R6 K10 + 0xAC180200, // 004F CATCH R6 1 0 + 0xB0080000, // 0050 RAISE 2 R0 R0 + 0x60180012, // 0051 GETGBL R6 G18 + 0x7C180000, // 0052 CALL R6 0 + 0x601C0010, // 0053 GETGBL R7 G16 + 0x88200112, // 0054 GETMBR R8 R0 K18 + 0x8C201113, // 0055 GETMET R8 R8 K19 + 0x7C200200, // 0056 CALL R8 1 + 0x7C1C0200, // 0057 CALL R7 1 + 0xA8020006, // 0058 EXBLK 0 #0060 + 0x5C200E00, // 0059 MOVE R8 R7 + 0x7C200000, // 005A CALL R8 0 + 0x8C240D09, // 005B GETMET R9 R6 K9 + 0x8C2C1114, // 005C GETMET R11 R8 K20 + 0x7C2C0200, // 005D CALL R11 1 + 0x7C240400, // 005E CALL R9 2 + 0x7001FFF8, // 005F JMP #0059 + 0x581C000A, // 0060 LDCONST R7 K10 + 0xAC1C0200, // 0061 CATCH R7 1 0 + 0xB0080000, // 0062 RAISE 2 R0 R0 + 0x601C000C, // 0063 GETGBL R7 G12 + 0x5C200C00, // 0064 MOVE R8 R6 + 0x7C1C0200, // 0065 CALL R7 1 + 0x241C0F07, // 0066 GT R7 R7 K7 + 0x781E0007, // 0067 JMPF R7 #0070 + 0x8C1C0D16, // 0068 GETMET R7 R6 K22 + 0x58240017, // 0069 LDCONST R9 K23 + 0x7C1C0400, // 006A CALL R7 2 + 0x001E2A07, // 006B ADD R7 K21 R7 + 0x001C0F18, // 006C ADD R7 R7 K24 + 0x8C200B09, // 006D GETMET R8 R5 K9 + 0x002A3207, // 006E ADD R10 K25 R7 + 0x7C200400, // 006F CALL R8 2 + 0x8C1C011A, // 0070 GETMET R7 R0 K26 + 0x7C1C0200, // 0071 CALL R7 1 + 0x8C1C0B16, // 0072 GETMET R7 R5 K22 + 0x58240017, // 0073 LDCONST R9 K23 + 0x7C1C0400, // 0074 CALL R7 2 + 0x001E3607, // 0075 ADD R7 K27 R7 + 0x001C0F1C, // 0076 ADD R7 R7 K28 + 0x80040E00, // 0077 RET 1 R7 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_index +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_index, /* 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(fabric_index), + }), + be_str_weak(get_fabric_index), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_admin_subject +********************************************************************/ +be_local_closure(Matter_Fabric_get_admin_subject, /* 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(admin_subject), + }), + be_str_weak(get_admin_subject), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_old_recent_session +********************************************************************/ +be_local_closure(Matter_Fabric_get_old_recent_session, /* 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(_sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(last_used), + /* K3 */ be_const_int(1), + }), + be_str_weak(get_old_recent_session), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0x6008000C, // 0000 GETGBL R2 G12 + 0x880C0100, // 0001 GETMBR R3 R0 K0 + 0x7C080200, // 0002 CALL R2 1 + 0x1C080501, // 0003 EQ R2 R2 K1 + 0x780A0001, // 0004 JMPF R2 #0007 + 0x4C080000, // 0005 LDNIL R2 + 0x80040400, // 0006 RET 1 R2 + 0x88080100, // 0007 GETMBR R2 R0 K0 + 0x94080501, // 0008 GETIDX R2 R2 K1 + 0x880C0502, // 0009 GETMBR R3 R2 K2 + 0x58100003, // 000A LDCONST R4 K3 + 0x6014000C, // 000B GETGBL R5 G12 + 0x88180100, // 000C GETMBR R6 R0 K0 + 0x7C140200, // 000D CALL R5 1 + 0x14140805, // 000E LT R5 R4 R5 + 0x7816000C, // 000F JMPF R5 #001D + 0x88140100, // 0010 GETMBR R5 R0 K0 + 0x94140A04, // 0011 GETIDX R5 R5 R4 + 0x88140B02, // 0012 GETMBR R5 R5 K2 + 0x78060001, // 0013 JMPF R1 #0016 + 0x14180A03, // 0014 LT R6 R5 R3 + 0x70020000, // 0015 JMP #0017 + 0x24180A03, // 0016 GT R6 R5 R3 + 0x781A0002, // 0017 JMPF R6 #001B + 0x88180100, // 0018 GETMBR R6 R0 K0 + 0x94080C04, // 0019 GETIDX R2 R6 R4 + 0x5C0C0A00, // 001A MOVE R3 R5 + 0x00100903, // 001B ADD R4 R4 K3 + 0x7001FFED, // 001C JMP #000B + 0x80040400, // 001D RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_device_id +********************************************************************/ +be_local_closure(Matter_Fabric_get_device_id, /* 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(device_id), + }), + be_str_weak(get_device_id), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: counter_group_ctrl_snd_next +********************************************************************/ +be_local_closure(Matter_Fabric_counter_group_ctrl_snd_next, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), + /* K2 */ be_nested_str_weak(next), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Counter_group_ctrl_snd_X3D_X25i), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(Counter), + /* K10 */ be_nested_str_weak(is_greater), + /* K11 */ be_nested_str_weak(counter_group_ctrl_snd), + /* K12 */ be_nested_str_weak(_GROUP_SND_INCR), + /* K13 */ be_nested_str_weak(does_persist), + /* K14 */ be_nested_str_weak(save), + }), + be_str_weak(counter_group_ctrl_snd_next), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0xB80E0600, // 0004 GETNGBL R3 K3 + 0x8C0C0704, // 0005 GETMET R3 R3 K4 + 0x8C140305, // 0006 GETMET R5 R1 K5 + 0x581C0006, // 0007 LDCONST R7 K6 + 0x5C200400, // 0008 MOVE R8 R2 + 0x7C140600, // 0009 CALL R5 3 + 0x58180007, // 000A LDCONST R6 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0xB80E1000, // 000C GETNGBL R3 K8 + 0x880C0709, // 000D GETMBR R3 R3 K9 + 0x8C0C070A, // 000E GETMET R3 R3 K10 + 0x5C140400, // 000F MOVE R5 R2 + 0x8818010B, // 0010 GETMBR R6 R0 K11 + 0x7C0C0600, // 0011 CALL R3 3 + 0x780E0007, // 0012 JMPF R3 #001B + 0x880C010C, // 0013 GETMBR R3 R0 K12 + 0x000C0403, // 0014 ADD R3 R2 R3 + 0x90021603, // 0015 SETMBR R0 K11 R3 + 0x8C0C010D, // 0016 GETMET R3 R0 K13 + 0x7C0C0200, // 0017 CALL R3 1 + 0x780E0001, // 0018 JMPF R3 #001B + 0x8C0C010E, // 0019 GETMET R3 R0 K14 + 0x7C0C0200, // 001A CALL R3 1 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fabric_index +********************************************************************/ +be_local_closure(Matter_Fabric_set_fabric_index, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(fabric_index), + }), + be_str_weak(set_fabric_index), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_compressed +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_compressed, /* 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(fabric_compressed), + }), + be_str_weak(get_fabric_compressed), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_session +********************************************************************/ +be_local_closure(Matter_Fabric_add_session, /* 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[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(_sessions), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(_MAX_CASE), + /* K3 */ be_nested_str_weak(remove), + /* K4 */ be_nested_str_weak(get_oldest_session), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(add_session), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C080403, // 0005 EQ R2 R2 R3 + 0x780A0012, // 0006 JMPF R2 #001A + 0x6008000C, // 0007 GETGBL R2 G12 + 0x880C0100, // 0008 GETMBR R3 R0 K0 + 0x7C080200, // 0009 CALL R2 1 + 0x880C0102, // 000A GETMBR R3 R0 K2 + 0x28080403, // 000B GE R2 R2 R3 + 0x780A0008, // 000C JMPF R2 #0016 + 0x88080100, // 000D GETMBR R2 R0 K0 + 0x8C080503, // 000E GETMET R2 R2 K3 + 0x88100100, // 000F GETMBR R4 R0 K0 + 0x8C100901, // 0010 GETMET R4 R4 K1 + 0x8C180104, // 0011 GETMET R6 R0 K4 + 0x7C180200, // 0012 CALL R6 1 + 0x7C100400, // 0013 CALL R4 2 + 0x7C080400, // 0014 CALL R2 2 + 0x7001FFF0, // 0015 JMP #0007 + 0x88080100, // 0016 GETMBR R2 R0 K0 + 0x8C080505, // 0017 GETMET R2 R2 K5 + 0x5C100200, // 0018 MOVE R4 R1 + 0x7C080400, // 0019 CALL R2 2 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: log_new_fabric +********************************************************************/ +be_local_closure(Matter_Fabric_log_new_fabric, /* 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[10]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20_X2BFabric_X20_X20_X20_X20fab_X3D_X27_X25s_X27), + /* K5 */ be_nested_str_weak(get_fabric_id), + /* K6 */ be_nested_str_weak(copy), + /* K7 */ be_nested_str_weak(reverse), + /* K8 */ be_nested_str_weak(tohex), + /* K9 */ be_const_int(2), + }), + be_str_weak(log_new_fabric), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x8C100303, // 0003 GETMET R4 R1 K3 + 0x58180004, // 0004 LDCONST R6 K4 + 0x8C1C0105, // 0005 GETMET R7 R0 K5 + 0x7C1C0200, // 0006 CALL R7 1 + 0x8C1C0F06, // 0007 GETMET R7 R7 K6 + 0x7C1C0200, // 0008 CALL R7 1 + 0x8C1C0F07, // 0009 GETMET R7 R7 K7 + 0x7C1C0200, // 000A CALL R7 1 + 0x8C1C0F08, // 000B GETMET R7 R7 K8 + 0x7C1C0200, // 000C CALL R7 1 + 0x7C100600, // 000D CALL R4 3 + 0x58140009, // 000E LDCONST R5 K9 + 0x7C080600, // 000F CALL R2 3 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: before_remove +********************************************************************/ +be_local_closure(Matter_Fabric_before_remove, /* 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[10]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20_X2DFabric_X20_X20_X20_X20fab_X3D_X27_X25s_X27_X20_X28removed_X29), + /* K5 */ be_nested_str_weak(get_fabric_id), + /* K6 */ be_nested_str_weak(copy), + /* K7 */ be_nested_str_weak(reverse), + /* K8 */ be_nested_str_weak(tohex), + /* K9 */ be_const_int(2), + }), + be_str_weak(before_remove), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x8C100303, // 0003 GETMET R4 R1 K3 + 0x58180004, // 0004 LDCONST R6 K4 + 0x8C1C0105, // 0005 GETMET R7 R0 K5 + 0x7C1C0200, // 0006 CALL R7 1 + 0x8C1C0F06, // 0007 GETMET R7 R7 K6 + 0x7C1C0200, // 0008 CALL R7 1 + 0x8C1C0F07, // 0009 GETMET R7 R7 K7 + 0x7C1C0200, // 000A CALL R7 1 + 0x8C1C0F08, // 000B GETMET R7 R7 K8 + 0x7C1C0200, // 000C CALL R7 1 + 0x7C100600, // 000D CALL R4 3 + 0x58140009, // 000E LDCONST R5 K9 + 0x7C080600, // 000F CALL R2 3 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fromjson +********************************************************************/ +be_local_closure(Matter_Fabric_fromjson, /* name */ + be_nested_proto( + 16, /* nstack */ + 2, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Fabric), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Fabric), + /* K5 */ be_nested_str_weak(keys), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(_), + /* K8 */ be_nested_str_weak(find), + /* K9 */ be_nested_str_weak(0x), + /* K10 */ be_nested_str_weak(set), + /* K11 */ be_nested_str_weak(fromhex), + /* K12 */ be_const_int(2), + /* K13 */ be_const_int(2147483647), + /* K14 */ be_nested_str_weak(_X24_X24), + /* K15 */ be_nested_str_weak(fromb64), + /* K16 */ be_nested_str_weak(stop_iteration), + /* K17 */ be_nested_str_weak(hydrate_post), + }), + be_str_weak(fromjson), + &be_const_str_solidified, + ( &(const binstruction[76]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0xA4120400, // 0002 IMPORT R4 K2 + 0xB8160600, // 0003 GETNGBL R5 K3 + 0x8C140B04, // 0004 GETMET R5 R5 K4 + 0x5C1C0000, // 0005 MOVE R7 R0 + 0x7C140400, // 0006 CALL R5 2 + 0x60180010, // 0007 GETGBL R6 G16 + 0x8C1C0305, // 0008 GETMET R7 R1 K5 + 0x7C1C0200, // 0009 CALL R7 1 + 0x7C180200, // 000A CALL R6 1 + 0xA8020039, // 000B EXBLK 0 #0046 + 0x5C1C0C00, // 000C MOVE R7 R6 + 0x7C1C0000, // 000D CALL R7 0 + 0x94200F06, // 000E GETIDX R8 R7 K6 + 0x1C201107, // 000F EQ R8 R8 K7 + 0x78220000, // 0010 JMPF R8 #0012 + 0x7001FFF9, // 0011 JMP #000C + 0x94200207, // 0012 GETIDX R8 R1 R7 + 0x60240004, // 0013 GETGBL R9 G4 + 0x5C281000, // 0014 MOVE R10 R8 + 0x7C240200, // 0015 CALL R9 1 + 0x1C241301, // 0016 EQ R9 R9 K1 + 0x78260027, // 0017 JMPF R9 #0040 + 0x8C240708, // 0018 GETMET R9 R3 K8 + 0x5C2C1000, // 0019 MOVE R11 R8 + 0x58300009, // 001A LDCONST R12 K9 + 0x7C240600, // 001B CALL R9 3 + 0x1C241306, // 001C EQ R9 R9 K6 + 0x7826000A, // 001D JMPF R9 #0029 + 0x8C24090A, // 001E GETMET R9 R4 K10 + 0x5C2C0A00, // 001F MOVE R11 R5 + 0x5C300E00, // 0020 MOVE R12 R7 + 0x60340015, // 0021 GETGBL R13 G21 + 0x7C340000, // 0022 CALL R13 0 + 0x8C341B0B, // 0023 GETMET R13 R13 K11 + 0x403E190D, // 0024 CONNECT R15 K12 K13 + 0x943C100F, // 0025 GETIDX R15 R8 R15 + 0x7C340400, // 0026 CALL R13 2 + 0x7C240800, // 0027 CALL R9 4 + 0x70020015, // 0028 JMP #003F + 0x8C240708, // 0029 GETMET R9 R3 K8 + 0x5C2C1000, // 002A MOVE R11 R8 + 0x5830000E, // 002B LDCONST R12 K14 + 0x7C240600, // 002C CALL R9 3 + 0x1C241306, // 002D EQ R9 R9 K6 + 0x7826000A, // 002E JMPF R9 #003A + 0x8C24090A, // 002F GETMET R9 R4 K10 + 0x5C2C0A00, // 0030 MOVE R11 R5 + 0x5C300E00, // 0031 MOVE R12 R7 + 0x60340015, // 0032 GETGBL R13 G21 + 0x7C340000, // 0033 CALL R13 0 + 0x8C341B0F, // 0034 GETMET R13 R13 K15 + 0x403E190D, // 0035 CONNECT R15 K12 K13 + 0x943C100F, // 0036 GETIDX R15 R8 R15 + 0x7C340400, // 0037 CALL R13 2 + 0x7C240800, // 0038 CALL R9 4 + 0x70020004, // 0039 JMP #003F + 0x8C24090A, // 003A GETMET R9 R4 K10 + 0x5C2C0A00, // 003B MOVE R11 R5 + 0x5C300E00, // 003C MOVE R12 R7 + 0x5C341000, // 003D MOVE R13 R8 + 0x7C240800, // 003E CALL R9 4 + 0x70020004, // 003F JMP #0045 + 0x8C24090A, // 0040 GETMET R9 R4 K10 + 0x5C2C0A00, // 0041 MOVE R11 R5 + 0x5C300E00, // 0042 MOVE R12 R7 + 0x5C341000, // 0043 MOVE R13 R8 + 0x7C240800, // 0044 CALL R9 4 + 0x7001FFC5, // 0045 JMP #000C + 0x58180010, // 0046 LDCONST R6 K16 + 0xAC180200, // 0047 CATCH R6 1 0 + 0xB0080000, // 0048 RAISE 2 R0 R0 + 0x8C180B11, // 0049 GETMET R6 R5 K17 + 0x7C180200, // 004A CALL R6 1 + 0x80040A00, // 004B RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Fabric_init, /* 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[18]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(_store), + /* K2 */ be_nested_str_weak(_sessions), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Expirable_list), + /* K5 */ be_nested_str_weak(fabric_label), + /* K6 */ be_nested_str_weak(), + /* K7 */ be_nested_str_weak(created), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(rtc), + /* K10 */ be_nested_str_weak(utc), + /* K11 */ be_nested_str_weak(_counter_group_data_snd_impl), + /* K12 */ be_nested_str_weak(Counter), + /* K13 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), + /* K14 */ be_nested_str_weak(counter_group_data_snd), + /* K15 */ be_nested_str_weak(next), + /* K16 */ be_nested_str_weak(_GROUP_SND_INCR), + /* K17 */ be_nested_str_weak(counter_group_ctrl_snd), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x90020201, // 0001 SETMBR R0 K1 R1 + 0xB80E0600, // 0002 GETNGBL R3 K3 + 0x8C0C0704, // 0003 GETMET R3 R3 K4 + 0x7C0C0200, // 0004 CALL R3 1 + 0x90020403, // 0005 SETMBR R0 K2 R3 + 0x90020B06, // 0006 SETMBR R0 K5 K6 + 0xB80E1000, // 0007 GETNGBL R3 K8 + 0x8C0C0709, // 0008 GETMET R3 R3 K9 + 0x7C0C0200, // 0009 CALL R3 1 + 0x940C070A, // 000A GETIDX R3 R3 K10 + 0x90020E03, // 000B SETMBR R0 K7 R3 + 0xB80E0600, // 000C GETNGBL R3 K3 + 0x8C0C070C, // 000D GETMET R3 R3 K12 + 0x7C0C0200, // 000E CALL R3 1 + 0x90021603, // 000F SETMBR R0 K11 R3 + 0xB80E0600, // 0010 GETNGBL R3 K3 + 0x8C0C070C, // 0011 GETMET R3 R3 K12 + 0x7C0C0200, // 0012 CALL R3 1 + 0x90021A03, // 0013 SETMBR R0 K13 R3 + 0x880C010B, // 0014 GETMBR R3 R0 K11 + 0x8C0C070F, // 0015 GETMET R3 R3 K15 + 0x7C0C0200, // 0016 CALL R3 1 + 0x88100110, // 0017 GETMBR R4 R0 K16 + 0x000C0604, // 0018 ADD R3 R3 R4 + 0x90021C03, // 0019 SETMBR R0 K14 R3 + 0x880C010B, // 001A GETMBR R3 R0 K11 + 0x8C0C070F, // 001B GETMET R3 R3 K15 + 0x7C0C0200, // 001C CALL R3 1 + 0x88100110, // 001D GETMBR R4 R0 K16 + 0x000C0604, // 001E ADD R3 R3 R4 + 0x90022203, // 001F SETMBR R0 K17 R3 + 0x80000000, // 0020 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_group_key +********************************************************************/ +be_local_closure(Matter_Fabric_get_ipk_group_key, /* 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[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(ipk_epoch_key), + /* K1 */ be_nested_str_weak(fabric_compressed), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(HKDF_SHA256), + /* K4 */ be_nested_str_weak(fromstring), + /* K5 */ be_nested_str_weak(_GROUP_KEY), + /* K6 */ be_nested_str_weak(derive), + }), + be_str_weak(get_ipk_group_key), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x74060003, // 0003 JMPT R1 #0008 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x4C080000, // 0005 LDNIL R2 + 0x1C040202, // 0006 EQ R1 R1 R2 + 0x78060001, // 0007 JMPF R1 #000A + 0x4C040000, // 0008 LDNIL R1 + 0x80040200, // 0009 RET 1 R1 + 0xA4060400, // 000A IMPORT R1 K2 + 0x8C080303, // 000B GETMET R2 R1 K3 + 0x7C080200, // 000C CALL R2 1 + 0x600C0015, // 000D GETGBL R3 G21 + 0x7C0C0000, // 000E CALL R3 0 + 0x8C0C0704, // 000F GETMET R3 R3 K4 + 0x88140105, // 0010 GETMBR R5 R0 K5 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8C100506, // 0012 GETMET R4 R2 K6 + 0x88180100, // 0013 GETMBR R6 R0 K0 + 0x881C0101, // 0014 GETMBR R7 R0 K1 + 0x5C200600, // 0015 MOVE R8 R3 + 0x5426000F, // 0016 LDINT R9 16 + 0x7C100A00, // 0017 CALL R4 5 + 0x80040800, // 0018 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Fabric_get_ipk_epoch_key, /* 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(ipk_epoch_key), + }), + be_str_weak(get_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_oldest_session +********************************************************************/ +be_local_closure(Matter_Fabric_get_oldest_session, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(get_old_recent_session), + }), + be_str_weak(get_oldest_session), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0200, // 0001 LDBOOL R3 1 0 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_label +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_label, /* 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(fabric_label), + }), + be_str_weak(get_fabric_label), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_newest_session +********************************************************************/ +be_local_closure(Matter_Fabric_get_newest_session, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(get_old_recent_session), + }), + be_str_weak(get_newest_session), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0000, // 0001 LDBOOL R3 0 0 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca +********************************************************************/ +be_local_closure(Matter_Fabric_get_ca, /* 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(root_ca_certificate), + }), + be_str_weak(get_ca), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_icac +********************************************************************/ +be_local_closure(Matter_Fabric_get_icac, /* 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(icac), + }), + be_str_weak(get_icac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_noc +********************************************************************/ +be_local_closure(Matter_Fabric_get_noc, /* 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(noc), + }), + be_str_weak(get_noc), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_id +********************************************************************/ +be_local_closure(Matter_Fabric_get_fabric_id, /* 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(fabric_id), + }), + be_str_weak(get_fabric_id), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_admin_vendor +********************************************************************/ +be_local_closure(Matter_Fabric_get_admin_vendor, /* 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(admin_vendor), + }), + be_str_weak(get_admin_vendor), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: hydrate_post +********************************************************************/ +be_local_closure(Matter_Fabric_hydrate_post, /* 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(_counter_group_data_snd_impl), + /* K1 */ be_nested_str_weak(reset), + /* K2 */ be_nested_str_weak(counter_group_data_snd), + /* K3 */ be_nested_str_weak(_counter_group_ctrl_snd_impl), + /* K4 */ be_nested_str_weak(counter_group_ctrl_snd), + /* K5 */ be_nested_str_weak(val), + }), + be_str_weak(hydrate_post), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x88040103, // 0004 GETMBR R1 R0 K3 + 0x8C040301, // 0005 GETMET R1 R1 K1 + 0x880C0104, // 0006 GETMBR R3 R0 K4 + 0x7C040400, // 0007 CALL R1 2 + 0x88040100, // 0008 GETMBR R1 R0 K0 + 0x8C040305, // 0009 GETMET R1 R1 K5 + 0x7C040200, // 000A CALL R1 1 + 0x90020401, // 000B SETMBR R0 K2 R1 + 0x88040103, // 000C GETMBR R1 R0 K3 + 0x8C040305, // 000D GETMET R1 R1 K5 + 0x7C040200, // 000E CALL R1 1 + 0x90020801, // 000F SETMBR R0 K4 R1 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: counter_group_data_snd_next +********************************************************************/ +be_local_closure(Matter_Fabric_counter_group_data_snd_next, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(_counter_group_data_snd_impl), + /* K2 */ be_nested_str_weak(next), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Counter_group_data_snd_X3D_X25i), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(Counter), + /* K10 */ be_nested_str_weak(is_greater), + /* K11 */ be_nested_str_weak(counter_group_data_snd), + /* K12 */ be_nested_str_weak(_GROUP_SND_INCR), + /* K13 */ be_nested_str_weak(does_persist), + /* K14 */ be_nested_str_weak(save), + }), + be_str_weak(counter_group_data_snd_next), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0xB80E0600, // 0004 GETNGBL R3 K3 + 0x8C0C0704, // 0005 GETMET R3 R3 K4 + 0x8C140305, // 0006 GETMET R5 R1 K5 + 0x581C0006, // 0007 LDCONST R7 K6 + 0x5C200400, // 0008 MOVE R8 R2 + 0x7C140600, // 0009 CALL R5 3 + 0x58180007, // 000A LDCONST R6 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0xB80E1000, // 000C GETNGBL R3 K8 + 0x880C0709, // 000D GETMBR R3 R3 K9 + 0x8C0C070A, // 000E GETMET R3 R3 K10 + 0x5C140400, // 000F MOVE R5 R2 + 0x8818010B, // 0010 GETMBR R6 R0 K11 + 0x7C0C0600, // 0011 CALL R3 3 + 0x780E0007, // 0012 JMPF R3 #001B + 0x880C010C, // 0013 GETMBR R3 R0 K12 + 0x000C0403, // 0014 ADD R3 R2 R3 + 0x90021603, // 0015 SETMBR R0 K11 R3 + 0x8C0C010D, // 0016 GETMET R3 R0 K13 + 0x7C0C0200, // 0017 CALL R3 1 + 0x780E0001, // 0018 JMPF R3 #001B + 0x8C0C010E, // 0019 GETMET R3 R0 K14 + 0x7C0C0200, // 001A CALL R3 1 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca_pub +********************************************************************/ +be_local_closure(Matter_Fabric_get_ca_pub, /* 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[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(root_ca_certificate), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(parse), + /* K4 */ be_nested_str_weak(findsubval), + }), + be_str_weak(get_ca_pub), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060008, // 0001 JMPF R1 #000B + 0xB80A0200, // 0002 GETNGBL R2 K1 + 0x88080502, // 0003 GETMBR R2 R2 K2 + 0x8C080503, // 0004 GETMET R2 R2 K3 + 0x5C100200, // 0005 MOVE R4 R1 + 0x7C080400, // 0006 CALL R2 2 + 0x8C0C0504, // 0007 GETMET R3 R2 K4 + 0x54160008, // 0008 LDINT R5 9 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80040600, // 000A RET 1 R3 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Fabric +********************************************************************/ +extern const bclass be_class_Matter_Expirable; +be_local_class(Matter_Fabric, + 20, + &be_class_Matter_Expirable, + be_nested_map(49, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(no_private_key, -1), be_const_var(5) }, + { be_const_key_weak(tojson, 8), be_const_closure(Matter_Fabric_tojson_closure) }, + { be_const_key_weak(counter_group_data_snd, -1), be_const_var(14) }, + { be_const_key_weak(fabric_label, -1), be_const_var(13) }, + { be_const_key_weak(_sessions, 34), be_const_var(4) }, + { be_const_key_weak(created, -1), be_const_var(1) }, + { be_const_key_weak(_GROUP_SND_INCR, -1), be_const_int(32) }, + { be_const_key_weak(get_admin_subject, -1), be_const_closure(Matter_Fabric_get_admin_subject_closure) }, + { be_const_key_weak(add_session, -1), be_const_closure(Matter_Fabric_add_session_closure) }, + { be_const_key_weak(get_old_recent_session, -1), be_const_closure(Matter_Fabric_get_old_recent_session_closure) }, + { be_const_key_weak(counter_group_data_snd_next, -1), be_const_closure(Matter_Fabric_counter_group_data_snd_next_closure) }, + { be_const_key_weak(ipk_epoch_key, -1), be_const_var(9) }, + { be_const_key_weak(get_device_id, -1), be_const_closure(Matter_Fabric_get_device_id_closure) }, + { be_const_key_weak(counter_group_ctrl_snd_next, -1), be_const_closure(Matter_Fabric_counter_group_ctrl_snd_next_closure) }, + { be_const_key_weak(_counter_group_ctrl_snd_impl, -1), be_const_var(17) }, + { be_const_key_weak(admin_subject, 3), be_const_var(18) }, + { be_const_key_weak(set_fabric_index, -1), be_const_closure(Matter_Fabric_set_fabric_index_closure) }, + { be_const_key_weak(get_fabric_compressed, 32), be_const_closure(Matter_Fabric_get_fabric_compressed_closure) }, + { be_const_key_weak(fabric_index, -1), be_const_var(2) }, + { be_const_key_weak(counter_group_ctrl_snd, 21), be_const_var(15) }, + { be_const_key_weak(log_new_fabric, -1), be_const_closure(Matter_Fabric_log_new_fabric_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Fabric_init_closure) }, + { be_const_key_weak(get_fabric_id, -1), be_const_closure(Matter_Fabric_get_fabric_id_closure) }, + { be_const_key_weak(_store, 15), be_const_var(0) }, + { be_const_key_weak(admin_vendor, 20), be_const_var(19) }, + { be_const_key_weak(device_id, 40), be_const_var(12) }, + { be_const_key_weak(before_remove, 28), be_const_closure(Matter_Fabric_before_remove_closure) }, + { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Fabric_fromjson_closure) }, + { be_const_key_weak(get_noc, 39), be_const_closure(Matter_Fabric_get_noc_closure) }, + { be_const_key_weak(get_fabric_index, 38), be_const_closure(Matter_Fabric_get_fabric_index_closure) }, + { be_const_key_weak(_MAX_CASE, -1), be_const_int(5) }, + { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Fabric_get_ipk_epoch_key_closure) }, + { be_const_key_weak(_GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(_counter_group_data_snd_impl, -1), be_const_var(16) }, + { be_const_key_weak(fabric_parent, -1), be_const_var(3) }, + { be_const_key_weak(fabric_id, -1), be_const_var(10) }, + { be_const_key_weak(icac, 35), be_const_var(8) }, + { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Fabric_get_ca_closure) }, + { be_const_key_weak(get_ipk_group_key, 6), be_const_closure(Matter_Fabric_get_ipk_group_key_closure) }, + { be_const_key_weak(get_fabric_label, -1), be_const_closure(Matter_Fabric_get_fabric_label_closure) }, + { be_const_key_weak(get_oldest_session, -1), be_const_closure(Matter_Fabric_get_oldest_session_closure) }, + { be_const_key_weak(get_newest_session, 22), be_const_closure(Matter_Fabric_get_newest_session_closure) }, + { be_const_key_weak(get_admin_vendor, -1), be_const_closure(Matter_Fabric_get_admin_vendor_closure) }, + { be_const_key_weak(noc, -1), be_const_var(7) }, + { be_const_key_weak(hydrate_post, -1), be_const_closure(Matter_Fabric_hydrate_post_closure) }, + { be_const_key_weak(get_icac, 10), be_const_closure(Matter_Fabric_get_icac_closure) }, + { be_const_key_weak(fabric_compressed, -1), be_const_var(11) }, + { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Fabric_get_ca_pub_closure) }, + { be_const_key_weak(root_ca_certificate, -1), be_const_var(6) }, + })), + be_str_weak(Matter_Fabric) +); +/*******************************************************************/ + +void be_load_Matter_Fabric_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Fabric); + be_setglobal(vm, "Matter_Fabric"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ 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 1e828f15b..18c27b534 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h @@ -4,14 +4,14 @@ \********************************************************************/ #include "be_constobj.h" -extern const bclass be_class_Matter_Response_container; +extern const bclass be_class_Matter_IM; /******************************************************************** -** Solidified function: tostring +** Solidified function: expire_sendqueue ********************************************************************/ -be_local_closure(Matter_Response_container_tostring, /* name */ +be_local_closure(Matter_IM_expire_sendqueue, /* name */ be_nested_proto( - 7, /* nstack */ + 6, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,91 +19,43 @@ be_local_closure(Matter_Response_container_tostring, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[14]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(), - /* K2 */ be_nested_str_weak(endpoint), - /* K3 */ be_nested_str_weak(format), - /* K4 */ be_nested_str_weak(_X5B_X2502X_X5D), - /* K5 */ be_nested_str_weak(_X5B_X2A_X2A_X5D), - /* K6 */ be_nested_str_weak(cluster), - /* K7 */ be_nested_str_weak(_X2504X_X2F), - /* K8 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2F), - /* K9 */ be_nested_str_weak(attribute), - /* K10 */ be_nested_str_weak(_X2504X), - /* K11 */ be_nested_str_weak(command), - /* K12 */ be_nested_str_weak(Exception_X3E_X20), - /* K13 */ be_nested_str_weak(_X2C_X20), + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(send_queue), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(time_reached), + /* K4 */ be_nested_str_weak(expiration), + /* K5 */ be_nested_str_weak(reached_timeout), + /* K6 */ be_nested_str_weak(remove), + /* K7 */ be_const_int(1), }), - be_str_weak(tostring), + be_str_weak(expire_sendqueue), &be_const_str_solidified, - ( &(const binstruction[66]) { /* code */ - 0xA8020031, // 0000 EXBLK 0 #0033 - 0xA4060000, // 0001 IMPORT R1 K0 - 0x58080001, // 0002 LDCONST R2 K1 - 0x880C0102, // 0003 GETMBR R3 R0 K2 - 0x4C100000, // 0004 LDNIL R4 - 0x200C0604, // 0005 NE R3 R3 R4 - 0x780E0004, // 0006 JMPF R3 #000C - 0x8C0C0303, // 0007 GETMET R3 R1 K3 - 0x58140004, // 0008 LDCONST R5 K4 - 0x88180102, // 0009 GETMBR R6 R0 K2 - 0x7C0C0600, // 000A CALL R3 3 - 0x70020000, // 000B JMP #000D - 0x580C0005, // 000C LDCONST R3 K5 - 0x00080403, // 000D ADD R2 R2 R3 - 0x880C0106, // 000E GETMBR R3 R0 K6 - 0x4C100000, // 000F LDNIL R4 - 0x200C0604, // 0010 NE R3 R3 R4 - 0x780E0004, // 0011 JMPF R3 #0017 - 0x8C0C0303, // 0012 GETMET R3 R1 K3 - 0x58140007, // 0013 LDCONST R5 K7 - 0x88180106, // 0014 GETMBR R6 R0 K6 - 0x7C0C0600, // 0015 CALL R3 3 - 0x70020000, // 0016 JMP #0018 - 0x580C0008, // 0017 LDCONST R3 K8 - 0x00080403, // 0018 ADD R2 R2 R3 - 0x880C0109, // 0019 GETMBR R3 R0 K9 - 0x4C100000, // 001A LDNIL R4 - 0x200C0604, // 001B NE R3 R3 R4 - 0x780E0004, // 001C JMPF R3 #0022 - 0x8C0C0303, // 001D GETMET R3 R1 K3 - 0x5814000A, // 001E LDCONST R5 K10 - 0x88180109, // 001F GETMBR R6 R0 K9 - 0x7C0C0600, // 0020 CALL R3 3 - 0x70020000, // 0021 JMP #0023 - 0x580C0001, // 0022 LDCONST R3 K1 - 0x00080403, // 0023 ADD R2 R2 R3 - 0x880C010B, // 0024 GETMBR R3 R0 K11 - 0x4C100000, // 0025 LDNIL R4 - 0x200C0604, // 0026 NE R3 R3 R4 - 0x780E0004, // 0027 JMPF R3 #002D - 0x8C0C0303, // 0028 GETMET R3 R1 K3 - 0x5814000A, // 0029 LDCONST R5 K10 - 0x88180109, // 002A GETMBR R6 R0 K9 - 0x7C0C0600, // 002B CALL R3 3 - 0x70020000, // 002C JMP #002E - 0x580C0001, // 002D LDCONST R3 K1 - 0x00080403, // 002E ADD R2 R2 R3 - 0xA8040001, // 002F EXBLK 1 1 - 0x80040400, // 0030 RET 1 R2 - 0xA8040001, // 0031 EXBLK 1 1 - 0x7002000D, // 0032 JMP #0041 - 0xAC040002, // 0033 CATCH R1 0 2 - 0x7002000A, // 0034 JMP #0040 - 0x600C0008, // 0035 GETGBL R3 G8 - 0x5C100200, // 0036 MOVE R4 R1 - 0x7C0C0200, // 0037 CALL R3 1 - 0x000E1803, // 0038 ADD R3 K12 R3 - 0x000C070D, // 0039 ADD R3 R3 K13 - 0x60100008, // 003A GETGBL R4 G8 - 0x5C140400, // 003B MOVE R5 R2 - 0x7C100200, // 003C CALL R4 1 - 0x000C0604, // 003D ADD R3 R3 R4 - 0x80040600, // 003E RET 1 R3 - 0x70020000, // 003F JMP #0041 - 0xB0080000, // 0040 RAISE 2 R0 R0 - 0x80000000, // 0041 RET 0 + ( &(const binstruction[24]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x14080202, // 0004 LT R2 R1 R2 + 0x780A000F, // 0005 JMPF R2 #0016 + 0x88080101, // 0006 GETMBR R2 R0 K1 + 0x94080401, // 0007 GETIDX R2 R2 R1 + 0xB80E0400, // 0008 GETNGBL R3 K2 + 0x8C0C0703, // 0009 GETMET R3 R3 K3 + 0x88140504, // 000A GETMBR R5 R2 K4 + 0x7C0C0400, // 000B CALL R3 2 + 0x780E0006, // 000C JMPF R3 #0014 + 0x8C0C0505, // 000D GETMET R3 R2 K5 + 0x7C0C0200, // 000E CALL R3 1 + 0x880C0101, // 000F GETMBR R3 R0 K1 + 0x8C0C0706, // 0010 GETMET R3 R3 K6 + 0x5C140200, // 0011 MOVE R5 R1 + 0x7C0C0400, // 0012 CALL R3 2 + 0x70020000, // 0013 JMP #0015 + 0x00040307, // 0014 ADD R1 R1 K7 + 0x7001FFEA, // 0015 JMP #0001 + 0x4C080000, // 0016 LDNIL R2 + 0x80040400, // 0017 RET 1 R2 }) ) ); @@ -111,36 +63,1979 @@ be_local_closure(Matter_Response_container_tostring, /* name */ /******************************************************************** -** Solidified class: Matter_Response_container +** Solidified function: process_invoke_request ********************************************************************/ -be_local_class(Matter_Response_container, - 5, - NULL, - be_nested_map(6, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(tostring, -1), be_const_closure(Matter_Response_container_tostring_closure) }, - { be_const_key_weak(cluster, 3), be_const_var(1) }, - { be_const_key_weak(command, -1), be_const_var(3) }, - { be_const_key_weak(status, 0), be_const_var(4) }, - { be_const_key_weak(endpoint, -1), be_const_var(0) }, - { be_const_key_weak(attribute, -1), be_const_var(2) }, - })), - be_str_weak(Matter_Response_container) +be_local_closure(Matter_IM_process_invoke_request, /* name */ + be_nested_proto( + 21, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[50]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20IM_X3Ainvoke_request_X20processing_X20start), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(Path), + /* K6 */ be_nested_str_weak(InvokeRequestMessage), + /* K7 */ be_nested_str_weak(from_TLV), + /* K8 */ be_nested_str_weak(invoke_requests), + /* K9 */ be_nested_str_weak(InvokeResponseMessage), + /* K10 */ be_nested_str_weak(suppress_response), + /* K11 */ be_nested_str_weak(invoke_responses), + /* K12 */ be_nested_str_weak(endpoint), + /* K13 */ be_nested_str_weak(command_path), + /* K14 */ be_nested_str_weak(cluster), + /* K15 */ be_nested_str_weak(command), + /* K16 */ be_nested_str_weak(status), + /* K17 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K18 */ be_nested_str_weak(get_command_name), + /* K19 */ be_nested_str_weak(device), + /* K20 */ be_nested_str_weak(invoke_request), + /* K21 */ be_nested_str_weak(session), + /* K22 */ be_nested_str_weak(command_fields), + /* K23 */ be_nested_str_weak(_X28), + /* K24 */ be_nested_str_weak(_X29_X20), + /* K25 */ be_nested_str_weak(), + /* K26 */ be_nested_str_weak(format), + /* K27 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand_X20_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s_X20_X25s), + /* K28 */ be_nested_str_weak(local_session_id), + /* K29 */ be_const_int(2), + /* K30 */ be_nested_str_weak(InvokeResponseIB), + /* K31 */ be_nested_str_weak(SUCCESS), + /* K32 */ be_nested_str_weak(CommandStatusIB), + /* K33 */ be_nested_str_weak(CommandPathIB), + /* K34 */ be_nested_str_weak(StatusIB), + /* K35 */ be_nested_str_weak(push), + /* K36 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20OK_X20exch_X3D_X25i), + /* K37 */ be_nested_str_weak(exchange_id), + /* K38 */ be_nested_str_weak(CommandDataIB), + /* 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(MTR_X3A_X20invoke_responses_X3D), + /* K44 */ be_const_int(0), + /* K45 */ be_nested_str_weak(MTR_X3A_X20InvokeResponse_X3D), + /* K46 */ be_nested_str_weak(MTR_X3A_X20InvokeResponseTLV_X3D), + /* K47 */ be_nested_str_weak(to_TLV), + /* K48 */ be_const_int(3), + /* K49 */ be_nested_str_weak(send_invoke_response), + }), + be_str_weak(process_invoke_request), + &be_const_str_solidified, + ( &(const binstruction[300]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x58180003, // 0003 LDCONST R6 K3 + 0x541E0003, // 0004 LDINT R7 4 + 0x7C100600, // 0005 CALL R4 3 + 0xB8120800, // 0006 GETNGBL R4 K4 + 0x8C100905, // 0007 GETMET R4 R4 K5 + 0x7C100200, // 0008 CALL R4 1 + 0xB8160800, // 0009 GETNGBL R5 K4 + 0x8C140B06, // 000A GETMET R5 R5 K6 + 0x7C140200, // 000B CALL R5 1 + 0x8C140B07, // 000C GETMET R5 R5 K7 + 0x5C1C0400, // 000D MOVE R7 R2 + 0x7C140400, // 000E CALL R5 2 + 0x88180B08, // 000F GETMBR R6 R5 K8 + 0x4C1C0000, // 0010 LDNIL R7 + 0x20180C07, // 0011 NE R6 R6 R7 + 0x781A0117, // 0012 JMPF R6 #012B + 0xB81A0800, // 0013 GETNGBL R6 K4 + 0x8C180D09, // 0014 GETMET R6 R6 K9 + 0x7C180200, // 0015 CALL R6 1 + 0x501C0000, // 0016 LDBOOL R7 0 0 + 0x901A1407, // 0017 SETMBR R6 K10 R7 + 0x601C0012, // 0018 GETGBL R7 G18 + 0x7C1C0000, // 0019 CALL R7 0 + 0x901A1607, // 001A SETMBR R6 K11 R7 + 0x601C0010, // 001B GETGBL R7 G16 + 0x88200B08, // 001C GETMBR R8 R5 K8 + 0x7C1C0200, // 001D CALL R7 1 + 0xA80200E1, // 001E EXBLK 0 #0101 + 0x5C200E00, // 001F MOVE R8 R7 + 0x7C200000, // 0020 CALL R8 0 + 0x8824110D, // 0021 GETMBR R9 R8 K13 + 0x8824130C, // 0022 GETMBR R9 R9 K12 + 0x90121809, // 0023 SETMBR R4 K12 R9 + 0x8824110D, // 0024 GETMBR R9 R8 K13 + 0x8824130E, // 0025 GETMBR R9 R9 K14 + 0x90121C09, // 0026 SETMBR R4 K14 R9 + 0x8824110D, // 0027 GETMBR R9 R8 K13 + 0x8824130F, // 0028 GETMBR R9 R9 K15 + 0x90121E09, // 0029 SETMBR R4 K15 R9 + 0xB8260800, // 002A GETNGBL R9 K4 + 0x88241311, // 002B GETMBR R9 R9 K17 + 0x90122009, // 002C SETMBR R4 K16 R9 + 0xB8260800, // 002D GETNGBL R9 K4 + 0x8C241312, // 002E GETMET R9 R9 K18 + 0x882C090E, // 002F GETMBR R11 R4 K14 + 0x8830090F, // 0030 GETMBR R12 R4 K15 + 0x7C240600, // 0031 CALL R9 3 + 0x88280113, // 0032 GETMBR R10 R0 K19 + 0x8C281514, // 0033 GETMET R10 R10 K20 + 0x88300315, // 0034 GETMBR R12 R1 K21 + 0x88341116, // 0035 GETMBR R13 R8 K22 + 0x5C380800, // 0036 MOVE R14 R4 + 0x7C280800, // 0037 CALL R10 4 + 0x882C0902, // 0038 GETMBR R11 R4 K2 + 0x4C300000, // 0039 LDNIL R12 + 0x202C160C, // 003A NE R11 R11 R12 + 0x782E0005, // 003B JMPF R11 #0042 + 0x602C0008, // 003C GETGBL R11 G8 + 0x88300902, // 003D GETMBR R12 R4 K2 + 0x7C2C0200, // 003E CALL R11 1 + 0x002E2E0B, // 003F ADD R11 K23 R11 + 0x002C1718, // 0040 ADD R11 R11 K24 + 0x70020000, // 0041 JMP #0043 + 0x582C0019, // 0042 LDCONST R11 K25 + 0xB8320200, // 0043 GETNGBL R12 K1 + 0x8C301902, // 0044 GETMET R12 R12 K2 + 0x8C38071A, // 0045 GETMET R14 R3 K26 + 0x5840001B, // 0046 LDCONST R16 K27 + 0x88440315, // 0047 GETMBR R17 R1 K21 + 0x8844231C, // 0048 GETMBR R17 R17 K28 + 0x60480008, // 0049 GETGBL R18 G8 + 0x5C4C0800, // 004A MOVE R19 R4 + 0x7C480200, // 004B CALL R18 1 + 0x78260001, // 004C JMPF R9 #004F + 0x5C4C1200, // 004D MOVE R19 R9 + 0x70020000, // 004E JMP #0050 + 0x584C0019, // 004F LDCONST R19 K25 + 0x5C501600, // 0050 MOVE R20 R11 + 0x7C380C00, // 0051 CALL R14 6 + 0x583C001D, // 0052 LDCONST R15 K29 + 0x7C300600, // 0053 CALL R12 3 + 0x4C300000, // 0054 LDNIL R12 + 0x9012040C, // 0055 SETMBR R4 K2 R12 + 0xB8320800, // 0056 GETNGBL R12 K4 + 0x8C30191E, // 0057 GETMET R12 R12 K30 + 0x7C300200, // 0058 CALL R12 1 + 0x50340200, // 0059 LDBOOL R13 1 0 + 0x1C34140D, // 005A EQ R13 R10 R13 + 0x74360004, // 005B JMPT R13 #0061 + 0x88340910, // 005C GETMBR R13 R4 K16 + 0xB83A0800, // 005D GETNGBL R14 K4 + 0x88381D1F, // 005E GETMBR R14 R14 K31 + 0x1C341A0E, // 005F EQ R13 R13 R14 + 0x7836002D, // 0060 JMPF R13 #008F + 0xB8360800, // 0061 GETNGBL R13 K4 + 0x8C341B20, // 0062 GETMET R13 R13 K32 + 0x7C340200, // 0063 CALL R13 1 + 0x9032200D, // 0064 SETMBR R12 K16 R13 + 0x88341910, // 0065 GETMBR R13 R12 K16 + 0xB83A0800, // 0066 GETNGBL R14 K4 + 0x8C381D21, // 0067 GETMET R14 R14 K33 + 0x7C380200, // 0068 CALL R14 1 + 0x90361A0E, // 0069 SETMBR R13 K13 R14 + 0x88341910, // 006A GETMBR R13 R12 K16 + 0x88341B0D, // 006B GETMBR R13 R13 K13 + 0x8838090C, // 006C GETMBR R14 R4 K12 + 0x9036180E, // 006D SETMBR R13 K12 R14 + 0x88341910, // 006E GETMBR R13 R12 K16 + 0x88341B0D, // 006F GETMBR R13 R13 K13 + 0x8838090E, // 0070 GETMBR R14 R4 K14 + 0x90361C0E, // 0071 SETMBR R13 K14 R14 + 0x88341910, // 0072 GETMBR R13 R12 K16 + 0x88341B0D, // 0073 GETMBR R13 R13 K13 + 0x8838090F, // 0074 GETMBR R14 R4 K15 + 0x90361E0E, // 0075 SETMBR R13 K15 R14 + 0x88341910, // 0076 GETMBR R13 R12 K16 + 0xB83A0800, // 0077 GETNGBL R14 K4 + 0x8C381D22, // 0078 GETMET R14 R14 K34 + 0x7C380200, // 0079 CALL R14 1 + 0x9036200E, // 007A SETMBR R13 K16 R14 + 0x88341910, // 007B GETMBR R13 R12 K16 + 0x88341B10, // 007C GETMBR R13 R13 K16 + 0xB83A0800, // 007D GETNGBL R14 K4 + 0x88381D1F, // 007E GETMBR R14 R14 K31 + 0x9036200E, // 007F SETMBR R13 K16 R14 + 0x88340D0B, // 0080 GETMBR R13 R6 K11 + 0x8C341B23, // 0081 GETMET R13 R13 K35 + 0x5C3C1800, // 0082 MOVE R15 R12 + 0x7C340400, // 0083 CALL R13 2 + 0xB8360200, // 0084 GETNGBL R13 K1 + 0x8C341B02, // 0085 GETMET R13 R13 K2 + 0x8C3C071A, // 0086 GETMET R15 R3 K26 + 0x58440024, // 0087 LDCONST R17 K36 + 0x88480315, // 0088 GETMBR R18 R1 K21 + 0x8848251C, // 0089 GETMBR R18 R18 K28 + 0x884C0325, // 008A GETMBR R19 R1 K37 + 0x7C3C0800, // 008B CALL R15 4 + 0x5840001D, // 008C LDCONST R16 K29 + 0x7C340600, // 008D CALL R13 3 + 0x70020070, // 008E JMP #0100 + 0x4C340000, // 008F LDNIL R13 + 0x2034140D, // 0090 NE R13 R10 R13 + 0x78360031, // 0091 JMPF R13 #00C4 + 0xB8360800, // 0092 GETNGBL R13 K4 + 0x8C341B26, // 0093 GETMET R13 R13 K38 + 0x7C340200, // 0094 CALL R13 1 + 0x90321E0D, // 0095 SETMBR R12 K15 R13 + 0x8834190F, // 0096 GETMBR R13 R12 K15 + 0xB83A0800, // 0097 GETNGBL R14 K4 + 0x8C381D21, // 0098 GETMET R14 R14 K33 + 0x7C380200, // 0099 CALL R14 1 + 0x90361A0E, // 009A SETMBR R13 K13 R14 + 0x8834190F, // 009B GETMBR R13 R12 K15 + 0x88341B0D, // 009C GETMBR R13 R13 K13 + 0x8838090C, // 009D GETMBR R14 R4 K12 + 0x9036180E, // 009E SETMBR R13 K12 R14 + 0x8834190F, // 009F GETMBR R13 R12 K15 + 0x88341B0D, // 00A0 GETMBR R13 R13 K13 + 0x8838090E, // 00A1 GETMBR R14 R4 K14 + 0x90361C0E, // 00A2 SETMBR R13 K14 R14 + 0x8834190F, // 00A3 GETMBR R13 R12 K15 + 0x88341B0D, // 00A4 GETMBR R13 R13 K13 + 0x8838090F, // 00A5 GETMBR R14 R4 K15 + 0x90361E0E, // 00A6 SETMBR R13 K15 R14 + 0x8834190F, // 00A7 GETMBR R13 R12 K15 + 0x90362C0A, // 00A8 SETMBR R13 K22 R10 + 0x88340D0B, // 00A9 GETMBR R13 R6 K11 + 0x8C341B23, // 00AA GETMET R13 R13 K35 + 0x5C3C1800, // 00AB MOVE R15 R12 + 0x7C340400, // 00AC CALL R13 2 + 0xB8360800, // 00AD GETNGBL R13 K4 + 0x8C341B12, // 00AE GETMET R13 R13 K18 + 0x883C090E, // 00AF GETMBR R15 R4 K14 + 0x8840090F, // 00B0 GETMBR R16 R4 K15 + 0x7C340600, // 00B1 CALL R13 3 + 0x5C241A00, // 00B2 MOVE R9 R13 + 0xB8360200, // 00B3 GETNGBL R13 K1 + 0x8C341B02, // 00B4 GETMET R13 R13 K2 + 0x8C3C071A, // 00B5 GETMET R15 R3 K26 + 0x58440027, // 00B6 LDCONST R17 K39 + 0x88480315, // 00B7 GETMBR R18 R1 K21 + 0x8848251C, // 00B8 GETMBR R18 R18 K28 + 0x604C0008, // 00B9 GETGBL R19 G8 + 0x5C500800, // 00BA MOVE R20 R4 + 0x7C4C0200, // 00BB CALL R19 1 + 0x78260001, // 00BC JMPF R9 #00BF + 0x5C501200, // 00BD MOVE R20 R9 + 0x70020000, // 00BE JMP #00C0 + 0x58500019, // 00BF LDCONST R20 K25 + 0x7C3C0A00, // 00C0 CALL R15 5 + 0x5840001D, // 00C1 LDCONST R16 K29 + 0x7C340600, // 00C2 CALL R13 3 + 0x7002003B, // 00C3 JMP #0100 + 0x88340910, // 00C4 GETMBR R13 R4 K16 + 0x4C380000, // 00C5 LDNIL R14 + 0x20341A0E, // 00C6 NE R13 R13 R14 + 0x7836002D, // 00C7 JMPF R13 #00F6 + 0xB8360800, // 00C8 GETNGBL R13 K4 + 0x8C341B20, // 00C9 GETMET R13 R13 K32 + 0x7C340200, // 00CA CALL R13 1 + 0x9032200D, // 00CB SETMBR R12 K16 R13 + 0x88341910, // 00CC GETMBR R13 R12 K16 + 0xB83A0800, // 00CD GETNGBL R14 K4 + 0x8C381D21, // 00CE GETMET R14 R14 K33 + 0x7C380200, // 00CF CALL R14 1 + 0x90361A0E, // 00D0 SETMBR R13 K13 R14 + 0x88341910, // 00D1 GETMBR R13 R12 K16 + 0x88341B0D, // 00D2 GETMBR R13 R13 K13 + 0x8838090C, // 00D3 GETMBR R14 R4 K12 + 0x9036180E, // 00D4 SETMBR R13 K12 R14 + 0x88341910, // 00D5 GETMBR R13 R12 K16 + 0x88341B0D, // 00D6 GETMBR R13 R13 K13 + 0x8838090E, // 00D7 GETMBR R14 R4 K14 + 0x90361C0E, // 00D8 SETMBR R13 K14 R14 + 0x88341910, // 00D9 GETMBR R13 R12 K16 + 0x88341B0D, // 00DA GETMBR R13 R13 K13 + 0x8838090F, // 00DB GETMBR R14 R4 K15 + 0x90361E0E, // 00DC SETMBR R13 K15 R14 + 0x88341910, // 00DD GETMBR R13 R12 K16 + 0xB83A0800, // 00DE GETNGBL R14 K4 + 0x8C381D22, // 00DF GETMET R14 R14 K34 + 0x7C380200, // 00E0 CALL R14 1 + 0x9036200E, // 00E1 SETMBR R13 K16 R14 + 0x88341910, // 00E2 GETMBR R13 R12 K16 + 0x88341B10, // 00E3 GETMBR R13 R13 K16 + 0x88380910, // 00E4 GETMBR R14 R4 K16 + 0x9036200E, // 00E5 SETMBR R13 K16 R14 + 0x88340D0B, // 00E6 GETMBR R13 R6 K11 + 0x8C341B23, // 00E7 GETMET R13 R13 K35 + 0x5C3C1800, // 00E8 MOVE R15 R12 + 0x7C340400, // 00E9 CALL R13 2 + 0xB8360200, // 00EA GETNGBL R13 K1 + 0x8C341B02, // 00EB GETMET R13 R13 K2 + 0x8C3C071A, // 00EC GETMET R15 R3 K26 + 0x58440028, // 00ED LDCONST R17 K40 + 0x88480315, // 00EE GETMBR R18 R1 K21 + 0x8848251C, // 00EF GETMBR R18 R18 K28 + 0x884C0910, // 00F0 GETMBR R19 R4 K16 + 0x88500325, // 00F1 GETMBR R20 R1 K37 + 0x7C3C0A00, // 00F2 CALL R15 5 + 0x5840001D, // 00F3 LDCONST R16 K29 + 0x7C340600, // 00F4 CALL R13 3 + 0x70020009, // 00F5 JMP #0100 + 0xB8360200, // 00F6 GETNGBL R13 K1 + 0x8C341B02, // 00F7 GETMET R13 R13 K2 + 0x8C3C071A, // 00F8 GETMET R15 R3 K26 + 0x58440029, // 00F9 LDCONST R17 K41 + 0x88480315, // 00FA GETMBR R18 R1 K21 + 0x8848251C, // 00FB GETMBR R18 R18 K28 + 0x884C0325, // 00FC GETMBR R19 R1 K37 + 0x7C3C0800, // 00FD CALL R15 4 + 0x5840001D, // 00FE LDCONST R16 K29 + 0x7C340600, // 00FF CALL R13 3 + 0x7001FF1D, // 0100 JMP #001F + 0x581C002A, // 0101 LDCONST R7 K42 + 0xAC1C0200, // 0102 CATCH R7 1 0 + 0xB0080000, // 0103 RAISE 2 R0 R0 + 0xB81E0200, // 0104 GETNGBL R7 K1 + 0x8C1C0F02, // 0105 GETMET R7 R7 K2 + 0x60240008, // 0106 GETGBL R9 G8 + 0x88280D0B, // 0107 GETMBR R10 R6 K11 + 0x7C240200, // 0108 CALL R9 1 + 0x00265609, // 0109 ADD R9 K43 R9 + 0x542A0003, // 010A LDINT R10 4 + 0x7C1C0600, // 010B CALL R7 3 + 0x601C000C, // 010C GETGBL R7 G12 + 0x88200D0B, // 010D GETMBR R8 R6 K11 + 0x7C1C0200, // 010E CALL R7 1 + 0x241C0F2C, // 010F GT R7 R7 K44 + 0x781E0015, // 0110 JMPF R7 #0127 + 0xB81E0200, // 0111 GETNGBL R7 K1 + 0x8C1C0F02, // 0112 GETMET R7 R7 K2 + 0x60240008, // 0113 GETGBL R9 G8 + 0x5C280C00, // 0114 MOVE R10 R6 + 0x7C240200, // 0115 CALL R9 1 + 0x00265A09, // 0116 ADD R9 K45 R9 + 0x542A0003, // 0117 LDINT R10 4 + 0x7C1C0600, // 0118 CALL R7 3 + 0xB81E0200, // 0119 GETNGBL R7 K1 + 0x8C1C0F02, // 011A GETMET R7 R7 K2 + 0x60240008, // 011B GETGBL R9 G8 + 0x8C280D2F, // 011C GETMET R10 R6 K47 + 0x7C280200, // 011D CALL R10 1 + 0x7C240200, // 011E CALL R9 1 + 0x00265C09, // 011F ADD R9 K46 R9 + 0x58280030, // 0120 LDCONST R10 K48 + 0x7C1C0600, // 0121 CALL R7 3 + 0x8C1C0131, // 0122 GETMET R7 R0 K49 + 0x5C240200, // 0123 MOVE R9 R1 + 0x5C280C00, // 0124 MOVE R10 R6 + 0x7C1C0600, // 0125 CALL R7 3 + 0x70020001, // 0126 JMP #0129 + 0x501C0000, // 0127 LDBOOL R7 0 0 + 0x80040E00, // 0128 RET 1 R7 + 0x501C0200, // 0129 LDBOOL R7 1 0 + 0x80040E00, // 012A RET 1 R7 + 0x80000000, // 012B RET 0 + }) + ) ); /*******************************************************************/ -void be_load_Matter_Response_container_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Response_container); - be_setglobal(vm, "Matter_Response_container"); - be_pop(vm, 1); -} - -extern const bclass be_class_Matter_IM; /******************************************************************** -** Solidified function: process_timed_request +** Solidified function: subscribe_request ********************************************************************/ -be_local_closure(Matter_IM_process_timed_request, /* name */ +be_local_closure(Matter_IM_subscribe_request, /* name */ + be_nested_proto( + 19, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[33]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(SubscribeRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(keep_subscriptions), + /* K5 */ be_nested_str_weak(subs_shop), + /* K6 */ be_nested_str_weak(remove_by_session), + /* K7 */ be_nested_str_weak(session), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeRequestMessage_X3D), + /* K11 */ be_const_int(3), + /* K12 */ be_nested_str_weak(new_subscription), + /* K13 */ be_nested_str_weak(Path), + /* K14 */ be_nested_str_weak(attributes_requests), + /* K15 */ be_nested_str_weak(endpoint), + /* K16 */ be_nested_str_weak(cluster), + /* K17 */ be_nested_str_weak(attribute), + /* K18 */ be_nested_str_weak(push), + /* K19 */ be_nested_str_weak(stop_iteration), + /* K20 */ be_nested_str_weak(format), + /* K21 */ be_nested_str_weak(MTR_X3A_X20_X3ESubscribe_X20_X28_X256i_X29_X20_X25s_X20_X28min_X3D_X25i_X2C_X20max_X3D_X25i_X2C_X20keep_X3D_X25i_X29_X20sub_X3D_X25i), + /* K22 */ be_nested_str_weak(local_session_id), + /* K23 */ be_nested_str_weak(concat), + /* K24 */ be_nested_str_weak(_X20), + /* K25 */ be_nested_str_weak(min_interval), + /* K26 */ be_nested_str_weak(max_interval), + /* K27 */ be_const_int(1), + /* K28 */ be_const_int(0), + /* K29 */ be_nested_str_weak(subscription_id), + /* K30 */ be_const_int(2), + /* K31 */ be_nested_str_weak(_inner_process_read_request), + /* K32 */ be_nested_str_weak(send_subscribe_response), + }), + be_str_weak(subscribe_request), + &be_const_str_solidified, + ( &(const binstruction[86]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0x88140904, // 0007 GETMBR R5 R4 K4 + 0x74160003, // 0008 JMPT R5 #000D + 0x88140105, // 0009 GETMBR R5 R0 K5 + 0x8C140B06, // 000A GETMET R5 R5 K6 + 0x881C0307, // 000B GETMBR R7 R1 K7 + 0x7C140400, // 000C CALL R5 2 + 0xB8161000, // 000D GETNGBL R5 K8 + 0x8C140B09, // 000E GETMET R5 R5 K9 + 0x601C0008, // 000F GETGBL R7 G8 + 0x5C200800, // 0010 MOVE R8 R4 + 0x7C1C0200, // 0011 CALL R7 1 + 0x001E1407, // 0012 ADD R7 K10 R7 + 0x5820000B, // 0013 LDCONST R8 K11 + 0x7C140600, // 0014 CALL R5 3 + 0x88140105, // 0015 GETMBR R5 R0 K5 + 0x8C140B0C, // 0016 GETMET R5 R5 K12 + 0x881C0307, // 0017 GETMBR R7 R1 K7 + 0x5C200800, // 0018 MOVE R8 R4 + 0x7C140600, // 0019 CALL R5 3 + 0x60180012, // 001A GETGBL R6 G18 + 0x7C180000, // 001B CALL R6 0 + 0xB81E0200, // 001C GETNGBL R7 K1 + 0x8C1C0F0D, // 001D GETMET R7 R7 K13 + 0x7C1C0200, // 001E CALL R7 1 + 0x60200010, // 001F GETGBL R8 G16 + 0x8824090E, // 0020 GETMBR R9 R4 K14 + 0x7C200200, // 0021 CALL R8 1 + 0xA802000D, // 0022 EXBLK 0 #0031 + 0x5C241000, // 0023 MOVE R9 R8 + 0x7C240000, // 0024 CALL R9 0 + 0x8828130F, // 0025 GETMBR R10 R9 K15 + 0x901E1E0A, // 0026 SETMBR R7 K15 R10 + 0x88281310, // 0027 GETMBR R10 R9 K16 + 0x901E200A, // 0028 SETMBR R7 K16 R10 + 0x88281311, // 0029 GETMBR R10 R9 K17 + 0x901E220A, // 002A SETMBR R7 K17 R10 + 0x8C280D12, // 002B GETMET R10 R6 K18 + 0x60300008, // 002C GETGBL R12 G8 + 0x5C340E00, // 002D MOVE R13 R7 + 0x7C300200, // 002E CALL R12 1 + 0x7C280400, // 002F CALL R10 2 + 0x7001FFF1, // 0030 JMP #0023 + 0x58200013, // 0031 LDCONST R8 K19 + 0xAC200200, // 0032 CATCH R8 1 0 + 0xB0080000, // 0033 RAISE 2 R0 R0 + 0xB8221000, // 0034 GETNGBL R8 K8 + 0x8C201109, // 0035 GETMET R8 R8 K9 + 0x8C280714, // 0036 GETMET R10 R3 K20 + 0x58300015, // 0037 LDCONST R12 K21 + 0x88340307, // 0038 GETMBR R13 R1 K7 + 0x88341B16, // 0039 GETMBR R13 R13 K22 + 0x8C380D17, // 003A GETMET R14 R6 K23 + 0x58400018, // 003B LDCONST R16 K24 + 0x7C380400, // 003C CALL R14 2 + 0x883C0B19, // 003D GETMBR R15 R5 K25 + 0x88400B1A, // 003E GETMBR R16 R5 K26 + 0x88440904, // 003F GETMBR R17 R4 K4 + 0x78460001, // 0040 JMPF R17 #0043 + 0x5844001B, // 0041 LDCONST R17 K27 + 0x70020000, // 0042 JMP #0044 + 0x5844001C, // 0043 LDCONST R17 K28 + 0x88480B1D, // 0044 GETMBR R18 R5 K29 + 0x7C281000, // 0045 CALL R10 8 + 0x582C001E, // 0046 LDCONST R11 K30 + 0x7C200600, // 0047 CALL R8 3 + 0x8C20011F, // 0048 GETMET R8 R0 K31 + 0x88280307, // 0049 GETMBR R10 R1 K7 + 0x5C2C0800, // 004A MOVE R11 R4 + 0x50300200, // 004B LDBOOL R12 1 0 + 0x7C200800, // 004C CALL R8 4 + 0x88240B1D, // 004D GETMBR R9 R5 K29 + 0x90223A09, // 004E SETMBR R8 K29 R9 + 0x8C240120, // 004F GETMET R9 R0 K32 + 0x5C2C0200, // 0050 MOVE R11 R1 + 0x5C301000, // 0051 MOVE R12 R8 + 0x5C340A00, // 0052 MOVE R13 R5 + 0x7C240800, // 0053 CALL R9 4 + 0x50240200, // 0054 LDBOOL R9 1 0 + 0x80041200, // 0055 RET 1 R9 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_write_request +********************************************************************/ +be_local_closure(Matter_IM_process_write_request, /* name */ + be_nested_proto( + 20, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 19, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[26]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(get_attribute_name), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_nested_str_weak(_X20_X28), + /* K6 */ be_nested_str_weak(_X29), + /* K7 */ be_nested_str_weak(), + /* K8 */ be_nested_str_weak(status), + /* K9 */ be_nested_str_weak(UNSUPPORTED_WRITE), + /* K10 */ be_nested_str_weak(write_attribute), + /* K11 */ be_nested_str_weak(session), + /* K12 */ be_nested_str_weak(SUCCESS), + /* K13 */ be_nested_str_weak(AttributeStatusIB), + /* K14 */ be_nested_str_weak(path), + /* K15 */ be_nested_str_weak(AttributePathIB), + /* K16 */ be_nested_str_weak(StatusIB), + /* K17 */ be_nested_str_weak(endpoint), + /* K18 */ be_nested_str_weak(write_responses), + /* K19 */ be_nested_str_weak(push), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(log), + /* K22 */ be_nested_str_weak(format), + /* K23 */ be_nested_str_weak(MTR_X3A_X20Write_Attr_X20_X25s_X25s_X20_X2D_X20STATUS_X3A_X200x_X2502X_X20_X25s), + /* K24 */ be_const_int(2), + /* K25 */ be_nested_str_weak(MTR_X3A_X20Write_Attr_X20_X25s_X25s_X20_X2D_X20IGNORED), + }), + be_str_weak(write_single_attribute), + &be_const_str_solidified, + ( &(const binstruction[97]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0xB81A0200, // 0001 GETNGBL R6 K1 + 0x8C180D02, // 0002 GETMET R6 R6 K2 + 0x88200503, // 0003 GETMBR R8 R2 K3 + 0x88240504, // 0004 GETMBR R9 R2 K4 + 0x7C180600, // 0005 CALL R6 3 + 0x781A0002, // 0006 JMPF R6 #000A + 0x001E0A06, // 0007 ADD R7 K5 R6 + 0x001C0F06, // 0008 ADD R7 R7 K6 + 0x70020000, // 0009 JMP #000B + 0x581C0007, // 000A LDCONST R7 K7 + 0x5C180E00, // 000B MOVE R6 R7 + 0xB81E0200, // 000C GETNGBL R7 K1 + 0x881C0F09, // 000D GETMBR R7 R7 K9 + 0x900A1007, // 000E SETMBR R2 K8 R7 + 0x4C1C0000, // 000F LDNIL R7 + 0x201C0207, // 0010 NE R7 R1 R7 + 0x781E0006, // 0011 JMPF R7 #0019 + 0x8C1C030A, // 0012 GETMET R7 R1 K10 + 0x68240000, // 0013 GETUPV R9 U0 + 0x8824130B, // 0014 GETMBR R9 R9 K11 + 0x5C280400, // 0015 MOVE R10 R2 + 0x5C2C0600, // 0016 MOVE R11 R3 + 0x7C1C0800, // 0017 CALL R7 4 + 0x70020000, // 0018 JMP #001A + 0x4C1C0000, // 0019 LDNIL R7 + 0x781E0002, // 001A JMPF R7 #001E + 0xB8220200, // 001B GETNGBL R8 K1 + 0x8820110C, // 001C GETMBR R8 R8 K12 + 0x900A1008, // 001D SETMBR R2 K8 R8 + 0x88200508, // 001E GETMBR R8 R2 K8 + 0x4C240000, // 001F LDNIL R9 + 0x20201009, // 0020 NE R8 R8 R9 + 0x78220032, // 0021 JMPF R8 #0055 + 0x78120030, // 0022 JMPF R4 #0054 + 0xB8220200, // 0023 GETNGBL R8 K1 + 0x8C20110D, // 0024 GETMET R8 R8 K13 + 0x7C200200, // 0025 CALL R8 1 + 0xB8260200, // 0026 GETNGBL R9 K1 + 0x8C24130F, // 0027 GETMET R9 R9 K15 + 0x7C240200, // 0028 CALL R9 1 + 0x90221C09, // 0029 SETMBR R8 K14 R9 + 0xB8260200, // 002A GETNGBL R9 K1 + 0x8C241310, // 002B GETMET R9 R9 K16 + 0x7C240200, // 002C CALL R9 1 + 0x90221009, // 002D SETMBR R8 K8 R9 + 0x8824110E, // 002E GETMBR R9 R8 K14 + 0x88280511, // 002F GETMBR R10 R2 K17 + 0x9026220A, // 0030 SETMBR R9 K17 R10 + 0x8824110E, // 0031 GETMBR R9 R8 K14 + 0x88280503, // 0032 GETMBR R10 R2 K3 + 0x9026060A, // 0033 SETMBR R9 K3 R10 + 0x8824110E, // 0034 GETMBR R9 R8 K14 + 0x88280504, // 0035 GETMBR R10 R2 K4 + 0x9026080A, // 0036 SETMBR R9 K4 R10 + 0x88241108, // 0037 GETMBR R9 R8 K8 + 0x88280508, // 0038 GETMBR R10 R2 K8 + 0x9026100A, // 0039 SETMBR R9 K8 R10 + 0x88240112, // 003A GETMBR R9 R0 K18 + 0x8C241313, // 003B GETMET R9 R9 K19 + 0x5C2C1000, // 003C MOVE R11 R8 + 0x7C240400, // 003D CALL R9 2 + 0xB8262800, // 003E GETNGBL R9 K20 + 0x8C241315, // 003F GETMET R9 R9 K21 + 0x8C2C0B16, // 0040 GETMET R11 R5 K22 + 0x58340017, // 0041 LDCONST R13 K23 + 0x60380008, // 0042 GETGBL R14 G8 + 0x5C3C0400, // 0043 MOVE R15 R2 + 0x7C380200, // 0044 CALL R14 1 + 0x5C3C0C00, // 0045 MOVE R15 R6 + 0x88400508, // 0046 GETMBR R16 R2 K8 + 0x88440508, // 0047 GETMBR R17 R2 K8 + 0xB84A0200, // 0048 GETNGBL R18 K1 + 0x8848250C, // 0049 GETMBR R18 R18 K12 + 0x1C442212, // 004A EQ R17 R17 R18 + 0x78460001, // 004B JMPF R17 #004E + 0x5844000C, // 004C LDCONST R17 K12 + 0x70020000, // 004D JMP #004F + 0x58440007, // 004E LDCONST R17 K7 + 0x7C2C0C00, // 004F CALL R11 6 + 0x58300018, // 0050 LDCONST R12 K24 + 0x7C240600, // 0051 CALL R9 3 + 0x50240200, // 0052 LDBOOL R9 1 0 + 0x80041200, // 0053 RET 1 R9 + 0x7002000A, // 0054 JMP #0060 + 0xB8222800, // 0055 GETNGBL R8 K20 + 0x8C201115, // 0056 GETMET R8 R8 K21 + 0x8C280B16, // 0057 GETMET R10 R5 K22 + 0x58300019, // 0058 LDCONST R12 K25 + 0x60340008, // 0059 GETGBL R13 G8 + 0x5C380400, // 005A MOVE R14 R2 + 0x7C340200, // 005B CALL R13 1 + 0x5C380C00, // 005C MOVE R14 R6 + 0x7C280800, // 005D CALL R10 4 + 0x582C0018, // 005E LDCONST R11 K24 + 0x7C200600, // 005F CALL R8 3 + 0x80000000, // 0060 RET 0 + }) + ), + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 3]) { /* upvals */ + be_local_const_upval(1, 7), + be_local_const_upval(1, 9), + be_local_const_upval(1, 13), + }), + 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[ 8]) { /* code */ + 0x680C0000, // 0000 GETUPV R3 U0 + 0x68100001, // 0001 GETUPV R4 U1 + 0x5C140000, // 0002 MOVE R5 R0 + 0x5C180200, // 0003 MOVE R6 R1 + 0x681C0002, // 0004 GETUPV R7 U2 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C0C0A00, // 0006 CALL R3 5 + 0x80040600, // 0007 RET 1 R3 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[36]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(WriteRequestMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteRequestMessage_X3D), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(suppress_response), + /* K9 */ be_nested_str_weak(device), + /* K10 */ be_nested_str_weak(get_active_endpoints), + /* K11 */ be_nested_str_weak(MTR_X3A_X20IM_X3Awrite_request_X20processing_X20start), + /* K12 */ be_nested_str_weak(Path), + /* K13 */ be_nested_str_weak(write_requests), + /* K14 */ be_nested_str_weak(WriteResponseMessage), + /* K15 */ be_nested_str_weak(write_responses), + /* K16 */ be_nested_str_weak(path), + /* K17 */ be_nested_str_weak(data), + /* K18 */ be_nested_str_weak(endpoint), + /* K19 */ be_nested_str_weak(cluster), + /* K20 */ be_nested_str_weak(attribute), + /* K21 */ be_nested_str_weak(status), + /* K22 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K23 */ be_nested_str_weak(INVALID_ACTION), + /* K24 */ be_nested_str_weak(get_attribute_name), + /* K25 */ be_nested_str_weak(MTR_X3A_X20Write_Attr_X20), + /* K26 */ be_nested_str_weak(_X20_X28), + /* K27 */ be_nested_str_weak(_X29), + /* K28 */ be_nested_str_weak(), + /* K29 */ be_const_int(2), + /* K30 */ be_nested_str_weak(process_attribute_expansion), + /* K31 */ be_nested_str_weak(stop_iteration), + /* K32 */ be_nested_str_weak(MTR_X3A_X20ReportWriteMessage_X3D), + /* K33 */ be_nested_str_weak(MTR_X3A_X20ReportWriteMessageTLV_X3D), + /* K34 */ be_nested_str_weak(to_TLV), + /* K35 */ be_nested_str_weak(send_write_response), + }), + be_str_weak(process_write_request), + &be_const_str_solidified, + ( &(const binstruction[134]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x88140908, // 000F GETMBR R5 R4 K8 + 0x88180109, // 0010 GETMBR R6 R0 K9 + 0x8C180D0A, // 0011 GETMET R6 R6 K10 + 0x7C180200, // 0012 CALL R6 1 + 0x841C0000, // 0013 CLOSURE R7 P0 + 0xB8220800, // 0014 GETNGBL R8 K4 + 0x8C201105, // 0015 GETMET R8 R8 K5 + 0x5828000B, // 0016 LDCONST R10 K11 + 0x542E0003, // 0017 LDINT R11 4 + 0x7C200600, // 0018 CALL R8 3 + 0xB8220200, // 0019 GETNGBL R8 K1 + 0x8C20110C, // 001A GETMET R8 R8 K12 + 0x7C200200, // 001B CALL R8 1 + 0x8824090D, // 001C GETMBR R9 R4 K13 + 0x4C280000, // 001D LDNIL R10 + 0x2024120A, // 001E NE R9 R9 R10 + 0x78260062, // 001F JMPF R9 #0083 + 0xB8260200, // 0020 GETNGBL R9 K1 + 0x8C24130E, // 0021 GETMET R9 R9 K14 + 0x7C240200, // 0022 CALL R9 1 + 0x60280012, // 0023 GETGBL R10 G18 + 0x7C280000, // 0024 CALL R10 0 + 0x90261E0A, // 0025 SETMBR R9 K15 R10 + 0x60280010, // 0026 GETGBL R10 G16 + 0x882C090D, // 0027 GETMBR R11 R4 K13 + 0x7C280200, // 0028 CALL R10 1 + 0xA802003D, // 0029 EXBLK 0 #0068 + 0x5C2C1400, // 002A MOVE R11 R10 + 0x7C2C0000, // 002B CALL R11 0 + 0x88301710, // 002C GETMBR R12 R11 K16 + 0x88341711, // 002D GETMBR R13 R11 K17 + 0x88381912, // 002E GETMBR R14 R12 K18 + 0x9022240E, // 002F SETMBR R8 K18 R14 + 0x88381913, // 0030 GETMBR R14 R12 K19 + 0x9022260E, // 0031 SETMBR R8 K19 R14 + 0x88381914, // 0032 GETMBR R14 R12 K20 + 0x9022280E, // 0033 SETMBR R8 K20 R14 + 0xB83A0200, // 0034 GETNGBL R14 K1 + 0x88381D16, // 0035 GETMBR R14 R14 K22 + 0x90222A0E, // 0036 SETMBR R8 K21 R14 + 0x88381113, // 0037 GETMBR R14 R8 K19 + 0x4C3C0000, // 0038 LDNIL R15 + 0x1C381C0F, // 0039 EQ R14 R14 R15 + 0x743A0003, // 003A JMPT R14 #003F + 0x88381114, // 003B GETMBR R14 R8 K20 + 0x4C3C0000, // 003C LDNIL R15 + 0x1C381C0F, // 003D EQ R14 R14 R15 + 0x783A000A, // 003E JMPF R14 #004A + 0xB83A0200, // 003F GETNGBL R14 K1 + 0x88381D17, // 0040 GETMBR R14 R14 K23 + 0x90222A0E, // 0041 SETMBR R8 K21 R14 + 0x5C380E00, // 0042 MOVE R14 R7 + 0x5C3C1200, // 0043 MOVE R15 R9 + 0x4C400000, // 0044 LDNIL R16 + 0x5C441000, // 0045 MOVE R17 R8 + 0x4C480000, // 0046 LDNIL R18 + 0x504C0200, // 0047 LDBOOL R19 1 0 + 0x7C380A00, // 0048 CALL R14 5 + 0x7001FFDF, // 0049 JMP #002A + 0x88381112, // 004A GETMBR R14 R8 K18 + 0x4C3C0000, // 004B LDNIL R15 + 0x1C381C0F, // 004C EQ R14 R14 R15 + 0x783A0012, // 004D JMPF R14 #0061 + 0xB83A0200, // 004E GETNGBL R14 K1 + 0x8C381D18, // 004F GETMET R14 R14 K24 + 0x88401113, // 0050 GETMBR R16 R8 K19 + 0x88441114, // 0051 GETMBR R17 R8 K20 + 0x7C380600, // 0052 CALL R14 3 + 0xB83E0800, // 0053 GETNGBL R15 K4 + 0x8C3C1F05, // 0054 GETMET R15 R15 K5 + 0x60440008, // 0055 GETGBL R17 G8 + 0x5C481000, // 0056 MOVE R18 R8 + 0x7C440200, // 0057 CALL R17 1 + 0x00463211, // 0058 ADD R17 K25 R17 + 0x783A0002, // 0059 JMPF R14 #005D + 0x004A340E, // 005A ADD R18 K26 R14 + 0x0048251B, // 005B ADD R18 R18 K27 + 0x70020000, // 005C JMP #005E + 0x5848001C, // 005D LDCONST R18 K28 + 0x00442212, // 005E ADD R17 R17 R18 + 0x5848001D, // 005F LDCONST R18 K29 + 0x7C3C0600, // 0060 CALL R15 3 + 0x88380109, // 0061 GETMBR R14 R0 K9 + 0x8C381D1E, // 0062 GETMET R14 R14 K30 + 0x5C401000, // 0063 MOVE R16 R8 + 0x84440001, // 0064 CLOSURE R17 P1 + 0x7C380600, // 0065 CALL R14 3 + 0xA0280000, // 0066 CLOSE R10 + 0x7001FFC1, // 0067 JMP #002A + 0x5828001F, // 0068 LDCONST R10 K31 + 0xAC280200, // 0069 CATCH R10 1 0 + 0xB0080000, // 006A RAISE 2 R0 R0 + 0xB82A0800, // 006B GETNGBL R10 K4 + 0x8C281505, // 006C GETMET R10 R10 K5 + 0x60300008, // 006D GETGBL R12 G8 + 0x5C341200, // 006E MOVE R13 R9 + 0x7C300200, // 006F CALL R12 1 + 0x0032400C, // 0070 ADD R12 K32 R12 + 0x54360003, // 0071 LDINT R13 4 + 0x7C280600, // 0072 CALL R10 3 + 0xB82A0800, // 0073 GETNGBL R10 K4 + 0x8C281505, // 0074 GETMET R10 R10 K5 + 0x60300008, // 0075 GETGBL R12 G8 + 0x8C341322, // 0076 GETMET R13 R9 K34 + 0x7C340200, // 0077 CALL R13 1 + 0x7C300200, // 0078 CALL R12 1 + 0x0032420C, // 0079 ADD R12 K33 R12 + 0x58340007, // 007A LDCONST R13 K7 + 0x7C280600, // 007B CALL R10 3 + 0x5C280A00, // 007C MOVE R10 R5 + 0x742A0003, // 007D JMPT R10 #0082 + 0x8C280123, // 007E GETMET R10 R0 K35 + 0x5C300200, // 007F MOVE R12 R1 + 0x5C341200, // 0080 MOVE R13 R9 + 0x7C280600, // 0081 CALL R10 3 + 0xA0240000, // 0082 CLOSE R9 + 0x50240200, // 0083 LDBOOL R9 1 0 + 0xA0000000, // 0084 CLOSE R0 + 0x80041200, // 0085 RET 1 R9 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_write_response +********************************************************************/ +be_local_closure(Matter_IM_send_write_response, /* 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_weak(send_queue), + /* K1 */ be_nested_str_weak(push), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(IM_WriteResponse), + }), + be_str_weak(send_write_response), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0xB8160400, // 0002 GETNGBL R5 K2 + 0x8C140B03, // 0003 GETMET R5 R5 K3 + 0x5C1C0200, // 0004 MOVE R7 R1 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C140600, // 0006 CALL R5 3 + 0x7C0C0400, // 0007 CALL R3 2 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_sendqueue_by_exchangeid +********************************************************************/ +be_local_closure(Matter_IM_remove_sendqueue_by_exchangeid, /* 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[ 5]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(send_queue), + /* K2 */ be_nested_str_weak(get_exchangeid), + /* K3 */ be_nested_str_weak(remove), + /* K4 */ be_const_int(1), + }), + be_str_weak(remove_sendqueue_by_exchangeid), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0000, // 0002 JMPF R2 #0004 + 0x80000400, // 0003 RET 0 + 0x58080000, // 0004 LDCONST R2 K0 + 0x600C000C, // 0005 GETGBL R3 G12 + 0x88100101, // 0006 GETMBR R4 R0 K1 + 0x7C0C0200, // 0007 CALL R3 1 + 0x140C0403, // 0008 LT R3 R2 R3 + 0x780E000C, // 0009 JMPF R3 #0017 + 0x880C0101, // 000A GETMBR R3 R0 K1 + 0x940C0602, // 000B GETIDX R3 R3 R2 + 0x8C0C0702, // 000C GETMET R3 R3 K2 + 0x7C0C0200, // 000D CALL R3 1 + 0x1C0C0601, // 000E EQ R3 R3 R1 + 0x780E0004, // 000F JMPF R3 #0015 + 0x880C0101, // 0010 GETMBR R3 R0 K1 + 0x8C0C0703, // 0011 GETMET R3 R3 K3 + 0x5C140400, // 0012 MOVE R5 R2 + 0x7C0C0400, // 0013 CALL R3 2 + 0x70020000, // 0014 JMP #0016 + 0x00080504, // 0015 ADD R2 R2 K4 + 0x7001FFED, // 0016 JMP #0005 + 0x80000000, // 0017 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_IM_every_second, /* 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(expire_sendqueue), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_ack_now +********************************************************************/ +be_local_closure(Matter_IM_send_ack_now, /* 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_weak(session), + /* K1 */ be_nested_str_weak(_message_handler), + /* K2 */ be_nested_str_weak(send_encrypted_ack), + }), + be_str_weak(send_ack_now), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88080300, // 0000 GETMBR R2 R1 K0 + 0x88080501, // 0001 GETMBR R2 R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x5C100200, // 0003 MOVE R4 R1 + 0x50140000, // 0004 LDBOOL R5 0 0 + 0x7C080600, // 0005 CALL R2 3 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_250ms +********************************************************************/ +be_local_closure(Matter_IM_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(subs_shop), + /* K1 */ be_nested_str_weak(every_250ms), + }), + 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: send_subscribe_response +********************************************************************/ +be_local_closure(Matter_IM_send_subscribe_response, /* name */ + be_nested_proto( + 11, /* 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(send_queue), + /* K1 */ be_nested_str_weak(push), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(IM_SubscribeResponse), + }), + be_str_weak(send_subscribe_response), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x8C100901, // 0001 GETMET R4 R4 K1 + 0xB81A0400, // 0002 GETNGBL R6 K2 + 0x8C180D03, // 0003 GETMET R6 R6 K3 + 0x5C200200, // 0004 MOVE R8 R1 + 0x5C240400, // 0005 MOVE R9 R2 + 0x5C280600, // 0006 MOVE R10 R3 + 0x7C180800, // 0007 CALL R6 4 + 0x7C100400, // 0008 CALL R4 2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_invoke_response +********************************************************************/ +be_local_closure(Matter_IM_send_invoke_response, /* 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_weak(send_queue), + /* K1 */ be_nested_str_weak(push), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(IM_InvokeResponse), + }), + be_str_weak(send_invoke_response), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0xB8160400, // 0002 GETNGBL R5 K2 + 0x8C140B03, // 0003 GETMET R5 R5 K3 + 0x5C1C0200, // 0004 MOVE R7 R1 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C140600, // 0006 CALL R5 3 + 0x7C0C0400, // 0007 CALL R3 2 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_status +********************************************************************/ +be_local_closure(Matter_IM_send_status, /* 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_weak(send_queue), + /* K1 */ be_nested_str_weak(push), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(IM_Status), + }), + be_str_weak(send_status), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0xB8160400, // 0002 GETNGBL R5 K2 + 0x8C140B03, // 0003 GETMET R5 R5 K3 + 0x5C1C0200, // 0004 MOVE R7 R1 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C140600, // 0006 CALL R5 3 + 0x7C0C0400, // 0007 CALL R3 2 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_response +********************************************************************/ +be_local_closure(Matter_IM_subscribe_response, /* 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(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(SubscribeResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeResponsetMessage_X3D), + /* K7 */ be_const_int(2), + }), + be_str_weak(subscribe_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_incoming +********************************************************************/ +be_local_closure(Matter_IM_process_incoming, /* 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[25]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20received_X20IM_X20message_X20), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(inspect), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(TLV), + /* K7 */ be_nested_str_weak(parse), + /* K8 */ be_nested_str_weak(raw), + /* K9 */ be_nested_str_weak(app_payload_idx), + /* K10 */ be_nested_str_weak(findsubval), + /* K11 */ be_nested_str_weak(opcode), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_weak(process_status_response), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(send_ack_now), + /* K16 */ be_nested_str_weak(process_read_request), + /* K17 */ be_nested_str_weak(subscribe_request), + /* K18 */ be_nested_str_weak(subscribe_response), + /* K19 */ be_nested_str_weak(report_data), + /* K20 */ be_nested_str_weak(process_write_request), + /* K21 */ be_nested_str_weak(process_write_response), + /* K22 */ be_nested_str_weak(process_invoke_request), + /* K23 */ be_nested_str_weak(process_invoke_response), + /* K24 */ be_nested_str_weak(process_timed_request), + }), + be_str_weak(process_incoming), + &be_const_str_solidified, + ( &(const binstruction[119]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0xB8120600, // 0002 GETNGBL R4 K3 + 0x8C100904, // 0003 GETMET R4 R4 K4 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C100400, // 0005 CALL R4 2 + 0x00120404, // 0006 ADD R4 K2 R4 + 0x58140005, // 0007 LDCONST R5 K5 + 0x7C080600, // 0008 CALL R2 3 + 0xB80A0600, // 0009 GETNGBL R2 K3 + 0x88080506, // 000A GETMBR R2 R2 K6 + 0x8C080507, // 000B GETMET R2 R2 K7 + 0x88100308, // 000C GETMBR R4 R1 K8 + 0x88140309, // 000D GETMBR R5 R1 K9 + 0x7C080600, // 000E CALL R2 3 + 0x8C0C050A, // 000F GETMET R3 R2 K10 + 0x541600FE, // 0010 LDINT R5 255 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8810030B, // 0012 GETMBR R4 R1 K11 + 0x1C14090C, // 0013 EQ R5 R4 K12 + 0x78160005, // 0014 JMPF R5 #001B + 0x8C14010D, // 0015 GETMET R5 R0 K13 + 0x5C1C0200, // 0016 MOVE R7 R1 + 0x5C200400, // 0017 MOVE R8 R2 + 0x7C140600, // 0018 CALL R5 3 + 0x80040A00, // 0019 RET 1 R5 + 0x70020059, // 001A JMP #0075 + 0x1C14090E, // 001B EQ R5 R4 K14 + 0x78160008, // 001C JMPF R5 #0026 + 0x8C14010F, // 001D GETMET R5 R0 K15 + 0x5C1C0200, // 001E MOVE R7 R1 + 0x7C140400, // 001F CALL R5 2 + 0x8C140110, // 0020 GETMET R5 R0 K16 + 0x5C1C0200, // 0021 MOVE R7 R1 + 0x5C200400, // 0022 MOVE R8 R2 + 0x7C140600, // 0023 CALL R5 3 + 0x80040A00, // 0024 RET 1 R5 + 0x7002004E, // 0025 JMP #0075 + 0x1C140905, // 0026 EQ R5 R4 K5 + 0x78160008, // 0027 JMPF R5 #0031 + 0x8C14010F, // 0028 GETMET R5 R0 K15 + 0x5C1C0200, // 0029 MOVE R7 R1 + 0x7C140400, // 002A CALL R5 2 + 0x8C140111, // 002B GETMET R5 R0 K17 + 0x5C1C0200, // 002C MOVE R7 R1 + 0x5C200400, // 002D MOVE R8 R2 + 0x7C140600, // 002E CALL R5 3 + 0x80040A00, // 002F RET 1 R5 + 0x70020043, // 0030 JMP #0075 + 0x54160003, // 0031 LDINT R5 4 + 0x1C140805, // 0032 EQ R5 R4 R5 + 0x78160005, // 0033 JMPF R5 #003A + 0x8C140112, // 0034 GETMET R5 R0 K18 + 0x5C1C0200, // 0035 MOVE R7 R1 + 0x5C200400, // 0036 MOVE R8 R2 + 0x7C140600, // 0037 CALL R5 3 + 0x80040A00, // 0038 RET 1 R5 + 0x7002003A, // 0039 JMP #0075 + 0x54160004, // 003A LDINT R5 5 + 0x1C140805, // 003B EQ R5 R4 R5 + 0x78160005, // 003C JMPF R5 #0043 + 0x8C140113, // 003D GETMET R5 R0 K19 + 0x5C1C0200, // 003E MOVE R7 R1 + 0x5C200400, // 003F MOVE R8 R2 + 0x7C140600, // 0040 CALL R5 3 + 0x80040A00, // 0041 RET 1 R5 + 0x70020031, // 0042 JMP #0075 + 0x54160005, // 0043 LDINT R5 6 + 0x1C140805, // 0044 EQ R5 R4 R5 + 0x78160008, // 0045 JMPF R5 #004F + 0x8C14010F, // 0046 GETMET R5 R0 K15 + 0x5C1C0200, // 0047 MOVE R7 R1 + 0x7C140400, // 0048 CALL R5 2 + 0x8C140114, // 0049 GETMET R5 R0 K20 + 0x5C1C0200, // 004A MOVE R7 R1 + 0x5C200400, // 004B MOVE R8 R2 + 0x7C140600, // 004C CALL R5 3 + 0x80040A00, // 004D RET 1 R5 + 0x70020025, // 004E JMP #0075 + 0x54160006, // 004F LDINT R5 7 + 0x1C140805, // 0050 EQ R5 R4 R5 + 0x78160005, // 0051 JMPF R5 #0058 + 0x8C140115, // 0052 GETMET R5 R0 K21 + 0x5C1C0200, // 0053 MOVE R7 R1 + 0x5C200400, // 0054 MOVE R8 R2 + 0x7C140600, // 0055 CALL R5 3 + 0x80040A00, // 0056 RET 1 R5 + 0x7002001C, // 0057 JMP #0075 + 0x54160007, // 0058 LDINT R5 8 + 0x1C140805, // 0059 EQ R5 R4 R5 + 0x78160008, // 005A JMPF R5 #0064 + 0x8C14010F, // 005B GETMET R5 R0 K15 + 0x5C1C0200, // 005C MOVE R7 R1 + 0x7C140400, // 005D CALL R5 2 + 0x8C140116, // 005E GETMET R5 R0 K22 + 0x5C1C0200, // 005F MOVE R7 R1 + 0x5C200400, // 0060 MOVE R8 R2 + 0x7C140600, // 0061 CALL R5 3 + 0x80040A00, // 0062 RET 1 R5 + 0x70020010, // 0063 JMP #0075 + 0x54160008, // 0064 LDINT R5 9 + 0x1C140805, // 0065 EQ R5 R4 R5 + 0x78160005, // 0066 JMPF R5 #006D + 0x8C140117, // 0067 GETMET R5 R0 K23 + 0x5C1C0200, // 0068 MOVE R7 R1 + 0x5C200400, // 0069 MOVE R8 R2 + 0x7C140600, // 006A CALL R5 3 + 0x80040A00, // 006B RET 1 R5 + 0x70020007, // 006C JMP #0075 + 0x54160009, // 006D LDINT R5 10 + 0x1C140805, // 006E EQ R5 R4 R5 + 0x78160004, // 006F JMPF R5 #0075 + 0x8C140118, // 0070 GETMET R5 R0 K24 + 0x5C1C0200, // 0071 MOVE R7 R1 + 0x5C200400, // 0072 MOVE R8 R2 + 0x7C140600, // 0073 CALL R5 3 + 0x80040A00, // 0074 RET 1 R5 + 0x50140000, // 0075 LDBOOL R5 0 0 + 0x80040A00, // 0076 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _inner_process_read_request +********************************************************************/ +be_local_closure(Matter_IM__inner_process_read_request, /* name */ + be_nested_proto( + 20, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 19, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 1), + be_local_const_upval(1, 3), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[33]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(get_attribute_name), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_nested_str_weak(_X20_X28), + /* K6 */ be_nested_str_weak(_X29), + /* K7 */ be_nested_str_weak(), + /* K8 */ be_nested_str_weak(read_attribute), + /* K9 */ be_nested_str_weak(AttributeReportIB), + /* K10 */ be_nested_str_weak(attribute_data), + /* K11 */ be_nested_str_weak(AttributeDataIB), + /* K12 */ be_nested_str_weak(data_version), + /* K13 */ be_const_int(1), + /* K14 */ be_nested_str_weak(path), + /* K15 */ be_nested_str_weak(AttributePathIB), + /* K16 */ be_nested_str_weak(endpoint), + /* K17 */ be_nested_str_weak(data), + /* K18 */ be_nested_str_weak(attribute_reports), + /* K19 */ be_nested_str_weak(push), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(log), + /* K22 */ be_nested_str_weak(format), + /* K23 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s_X25s_X20_X2D_X20_X25s), + /* K24 */ be_nested_str_weak(local_session_id), + /* K25 */ be_const_int(2), + /* K26 */ be_nested_str_weak(status), + /* K27 */ be_nested_str_weak(attribute_status), + /* K28 */ be_nested_str_weak(AttributeStatusIB), + /* K29 */ be_nested_str_weak(StatusIB), + /* K30 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s_X25s_X20_X2D_X20STATUS_X3A_X200x_X2502X_X20_X25s), + /* K31 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K32 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s_X25s_X20_X2D_X20IGNORED), + }), + be_str_weak(read_single_attribute), + &be_const_str_solidified, + ( &(const binstruction[160]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x8C140B02, // 0002 GETMET R5 R5 K2 + 0x881C0503, // 0003 GETMBR R7 R2 K3 + 0x88200504, // 0004 GETMBR R8 R2 K4 + 0x7C140600, // 0005 CALL R5 3 + 0x78160002, // 0006 JMPF R5 #000A + 0x001A0A05, // 0007 ADD R6 K5 R5 + 0x00180D06, // 0008 ADD R6 R6 K6 + 0x70020000, // 0009 JMP #000B + 0x58180007, // 000A LDCONST R6 K7 + 0x5C140C00, // 000B MOVE R5 R6 + 0x4C180000, // 000C LDNIL R6 + 0x20180206, // 000D NE R6 R1 R6 + 0x781A0004, // 000E JMPF R6 #0014 + 0x8C180308, // 000F GETMET R6 R1 K8 + 0x68200000, // 0010 GETUPV R8 U0 + 0x5C240400, // 0011 MOVE R9 R2 + 0x7C180600, // 0012 CALL R6 3 + 0x70020000, // 0013 JMP #0015 + 0x4C180000, // 0014 LDNIL R6 + 0x4C1C0000, // 0015 LDNIL R7 + 0x201C0C07, // 0016 NE R7 R6 R7 + 0x781E0034, // 0017 JMPF R7 #004D + 0xB81E0200, // 0018 GETNGBL R7 K1 + 0x8C1C0F09, // 0019 GETMET R7 R7 K9 + 0x7C1C0200, // 001A CALL R7 1 + 0xB8220200, // 001B GETNGBL R8 K1 + 0x8C20110B, // 001C GETMET R8 R8 K11 + 0x7C200200, // 001D CALL R8 1 + 0x901E1408, // 001E SETMBR R7 K10 R8 + 0x88200F0A, // 001F GETMBR R8 R7 K10 + 0x9022190D, // 0020 SETMBR R8 K12 K13 + 0x88200F0A, // 0021 GETMBR R8 R7 K10 + 0xB8260200, // 0022 GETNGBL R9 K1 + 0x8C24130F, // 0023 GETMET R9 R9 K15 + 0x7C240200, // 0024 CALL R9 1 + 0x90221C09, // 0025 SETMBR R8 K14 R9 + 0x88200F0A, // 0026 GETMBR R8 R7 K10 + 0x8820110E, // 0027 GETMBR R8 R8 K14 + 0x88240510, // 0028 GETMBR R9 R2 K16 + 0x90222009, // 0029 SETMBR R8 K16 R9 + 0x88200F0A, // 002A GETMBR R8 R7 K10 + 0x8820110E, // 002B GETMBR R8 R8 K14 + 0x88240503, // 002C GETMBR R9 R2 K3 + 0x90220609, // 002D SETMBR R8 K3 R9 + 0x88200F0A, // 002E GETMBR R8 R7 K10 + 0x8820110E, // 002F GETMBR R8 R8 K14 + 0x88240504, // 0030 GETMBR R9 R2 K4 + 0x90220809, // 0031 SETMBR R8 K4 R9 + 0x88200F0A, // 0032 GETMBR R8 R7 K10 + 0x90222206, // 0033 SETMBR R8 K17 R6 + 0x88200112, // 0034 GETMBR R8 R0 K18 + 0x8C201113, // 0035 GETMET R8 R8 K19 + 0x5C280E00, // 0036 MOVE R10 R7 + 0x7C200400, // 0037 CALL R8 2 + 0x68200001, // 0038 GETUPV R8 U1 + 0x7422000F, // 0039 JMPT R8 #004A + 0xB8222800, // 003A GETNGBL R8 K20 + 0x8C201115, // 003B GETMET R8 R8 K21 + 0x8C280916, // 003C GETMET R10 R4 K22 + 0x58300017, // 003D LDCONST R12 K23 + 0x68340000, // 003E GETUPV R13 U0 + 0x88341B18, // 003F GETMBR R13 R13 K24 + 0x60380008, // 0040 GETGBL R14 G8 + 0x5C3C0400, // 0041 MOVE R15 R2 + 0x7C380200, // 0042 CALL R14 1 + 0x5C3C0A00, // 0043 MOVE R15 R5 + 0x60400008, // 0044 GETGBL R16 G8 + 0x5C440C00, // 0045 MOVE R17 R6 + 0x7C400200, // 0046 CALL R16 1 + 0x7C280C00, // 0047 CALL R10 6 + 0x582C0019, // 0048 LDCONST R11 K25 + 0x7C200600, // 0049 CALL R8 3 + 0x50200200, // 004A LDBOOL R8 1 0 + 0x80041000, // 004B RET 1 R8 + 0x70020051, // 004C JMP #009F + 0x881C051A, // 004D GETMBR R7 R2 K26 + 0x4C200000, // 004E LDNIL R8 + 0x201C0E08, // 004F NE R7 R7 R8 + 0x781E003E, // 0050 JMPF R7 #0090 + 0x780E003C, // 0051 JMPF R3 #008F + 0xB81E0200, // 0052 GETNGBL R7 K1 + 0x8C1C0F09, // 0053 GETMET R7 R7 K9 + 0x7C1C0200, // 0054 CALL R7 1 + 0xB8220200, // 0055 GETNGBL R8 K1 + 0x8C20111C, // 0056 GETMET R8 R8 K28 + 0x7C200200, // 0057 CALL R8 1 + 0x901E3608, // 0058 SETMBR R7 K27 R8 + 0x88200F1B, // 0059 GETMBR R8 R7 K27 + 0xB8260200, // 005A GETNGBL R9 K1 + 0x8C24130F, // 005B GETMET R9 R9 K15 + 0x7C240200, // 005C CALL R9 1 + 0x90221C09, // 005D SETMBR R8 K14 R9 + 0x88200F1B, // 005E GETMBR R8 R7 K27 + 0xB8260200, // 005F GETNGBL R9 K1 + 0x8C24131D, // 0060 GETMET R9 R9 K29 + 0x7C240200, // 0061 CALL R9 1 + 0x90223409, // 0062 SETMBR R8 K26 R9 + 0x88200F1B, // 0063 GETMBR R8 R7 K27 + 0x8820110E, // 0064 GETMBR R8 R8 K14 + 0x88240510, // 0065 GETMBR R9 R2 K16 + 0x90222009, // 0066 SETMBR R8 K16 R9 + 0x88200F1B, // 0067 GETMBR R8 R7 K27 + 0x8820110E, // 0068 GETMBR R8 R8 K14 + 0x88240503, // 0069 GETMBR R9 R2 K3 + 0x90220609, // 006A SETMBR R8 K3 R9 + 0x88200F1B, // 006B GETMBR R8 R7 K27 + 0x8820110E, // 006C GETMBR R8 R8 K14 + 0x88240504, // 006D GETMBR R9 R2 K4 + 0x90220809, // 006E SETMBR R8 K4 R9 + 0x88200F1B, // 006F GETMBR R8 R7 K27 + 0x8820111A, // 0070 GETMBR R8 R8 K26 + 0x8824051A, // 0071 GETMBR R9 R2 K26 + 0x90223409, // 0072 SETMBR R8 K26 R9 + 0x88200112, // 0073 GETMBR R8 R0 K18 + 0x8C201113, // 0074 GETMET R8 R8 K19 + 0x5C280E00, // 0075 MOVE R10 R7 + 0x7C200400, // 0076 CALL R8 2 + 0xB8222800, // 0077 GETNGBL R8 K20 + 0x8C201115, // 0078 GETMET R8 R8 K21 + 0x8C280916, // 0079 GETMET R10 R4 K22 + 0x5830001E, // 007A LDCONST R12 K30 + 0x68340000, // 007B GETUPV R13 U0 + 0x88341B18, // 007C GETMBR R13 R13 K24 + 0x60380008, // 007D GETGBL R14 G8 + 0x5C3C0400, // 007E MOVE R15 R2 + 0x7C380200, // 007F CALL R14 1 + 0x5C3C0A00, // 0080 MOVE R15 R5 + 0x8840051A, // 0081 GETMBR R16 R2 K26 + 0x8844051A, // 0082 GETMBR R17 R2 K26 + 0xB84A0200, // 0083 GETNGBL R18 K1 + 0x8848251F, // 0084 GETMBR R18 R18 K31 + 0x1C442212, // 0085 EQ R17 R17 R18 + 0x78460001, // 0086 JMPF R17 #0089 + 0x5844001F, // 0087 LDCONST R17 K31 + 0x70020000, // 0088 JMP #008A + 0x58440007, // 0089 LDCONST R17 K7 + 0x7C280E00, // 008A CALL R10 7 + 0x582C0019, // 008B LDCONST R11 K25 + 0x7C200600, // 008C CALL R8 3 + 0x50200200, // 008D LDBOOL R8 1 0 + 0x80041000, // 008E RET 1 R8 + 0x7002000E, // 008F JMP #009F + 0xB81E2800, // 0090 GETNGBL R7 K20 + 0x8C1C0F15, // 0091 GETMET R7 R7 K21 + 0x8C240916, // 0092 GETMET R9 R4 K22 + 0x582C0020, // 0093 LDCONST R11 K32 + 0x68300000, // 0094 GETUPV R12 U0 + 0x88301918, // 0095 GETMBR R12 R12 K24 + 0x60340008, // 0096 GETGBL R13 G8 + 0x5C380400, // 0097 MOVE R14 R2 + 0x7C340200, // 0098 CALL R13 1 + 0x5C380A00, // 0099 MOVE R14 R5 + 0x7C240A00, // 009A CALL R9 5 + 0x58280019, // 009B LDCONST R10 K25 + 0x7C1C0600, // 009C CALL R7 3 + 0x501C0000, // 009D LDBOOL R7 0 0 + 0x80040E00, // 009E RET 1 R7 + 0x80000000, // 009F RET 0 + }) + ), + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 5), + be_local_const_upval(1, 8), + }), + 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[ 7]) { /* code */ + 0x680C0000, // 0000 GETUPV R3 U0 + 0x68100001, // 0001 GETUPV R4 U1 + 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[25]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(device), + /* K2 */ be_nested_str_weak(get_active_endpoints), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Path), + /* K5 */ be_nested_str_weak(ReportDataMessage), + /* K6 */ be_nested_str_weak(attribute_reports), + /* K7 */ be_nested_str_weak(attributes_requests), + /* K8 */ be_nested_str_weak(endpoint), + /* K9 */ be_nested_str_weak(cluster), + /* K10 */ be_nested_str_weak(attribute), + /* K11 */ be_nested_str_weak(status), + /* K12 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + /* K13 */ be_nested_str_weak(get_attribute_name), + /* K14 */ be_nested_str_weak(tasmota), + /* K15 */ be_nested_str_weak(log), + /* K16 */ be_nested_str_weak(format), + /* K17 */ be_nested_str_weak(MTR_X3A_X20_X3ERead_Attr_X20_X28_X256i_X29_X20_X25s), + /* K18 */ be_nested_str_weak(local_session_id), + /* K19 */ be_nested_str_weak(_X20_X28), + /* K20 */ be_nested_str_weak(_X29), + /* K21 */ be_nested_str_weak(), + /* K22 */ be_const_int(2), + /* K23 */ be_nested_str_weak(process_attribute_expansion), + /* K24 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(_inner_process_read_request), + &be_const_str_solidified, + ( &(const binstruction[94]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x84140000, // 0001 CLOSURE R5 P0 + 0x88180101, // 0002 GETMBR R6 R0 K1 + 0x8C180D02, // 0003 GETMET R6 R6 K2 + 0x7C180200, // 0004 CALL R6 1 + 0xB81E0600, // 0005 GETNGBL R7 K3 + 0x8C1C0F04, // 0006 GETMET R7 R7 K4 + 0x7C1C0200, // 0007 CALL R7 1 + 0xB8220600, // 0008 GETNGBL R8 K3 + 0x8C201105, // 0009 GETMET R8 R8 K5 + 0x7C200200, // 000A CALL R8 1 + 0x60240012, // 000B GETGBL R9 G18 + 0x7C240000, // 000C CALL R9 0 + 0x90220C09, // 000D SETMBR R8 K6 R9 + 0x60240010, // 000E GETGBL R9 G16 + 0x88280507, // 000F GETMBR R10 R2 K7 + 0x7C240200, // 0010 CALL R9 1 + 0xA8020046, // 0011 EXBLK 0 #0059 + 0x5C281200, // 0012 MOVE R10 R9 + 0x7C280000, // 0013 CALL R10 0 + 0x882C1508, // 0014 GETMBR R11 R10 K8 + 0x901E100B, // 0015 SETMBR R7 K8 R11 + 0x882C1509, // 0016 GETMBR R11 R10 K9 + 0x901E120B, // 0017 SETMBR R7 K9 R11 + 0x882C150A, // 0018 GETMBR R11 R10 K10 + 0x901E140B, // 0019 SETMBR R7 K10 R11 + 0xB82E0600, // 001A GETNGBL R11 K3 + 0x882C170C, // 001B GETMBR R11 R11 K12 + 0x901E160B, // 001C SETMBR R7 K11 R11 + 0x882C0F08, // 001D GETMBR R11 R7 K8 + 0x4C300000, // 001E LDNIL R12 + 0x1C2C160C, // 001F EQ R11 R11 R12 + 0x742E0007, // 0020 JMPT R11 #0029 + 0x882C0F09, // 0021 GETMBR R11 R7 K9 + 0x4C300000, // 0022 LDNIL R12 + 0x1C2C160C, // 0023 EQ R11 R11 R12 + 0x742E0003, // 0024 JMPT R11 #0029 + 0x882C0F0A, // 0025 GETMBR R11 R7 K10 + 0x4C300000, // 0026 LDNIL R12 + 0x1C2C160C, // 0027 EQ R11 R11 R12 + 0x782E0029, // 0028 JMPF R11 #0053 + 0x882C0F09, // 0029 GETMBR R11 R7 K9 + 0x4C300000, // 002A LDNIL R12 + 0x202C160C, // 002B NE R11 R11 R12 + 0x782E001A, // 002C JMPF R11 #0048 + 0x882C0F0A, // 002D GETMBR R11 R7 K10 + 0x4C300000, // 002E LDNIL R12 + 0x202C160C, // 002F NE R11 R11 R12 + 0x782E0016, // 0030 JMPF R11 #0048 + 0xB82E0600, // 0031 GETNGBL R11 K3 + 0x8C2C170D, // 0032 GETMET R11 R11 K13 + 0x88340F09, // 0033 GETMBR R13 R7 K9 + 0x88380F0A, // 0034 GETMBR R14 R7 K10 + 0x7C2C0600, // 0035 CALL R11 3 + 0xB8321C00, // 0036 GETNGBL R12 K14 + 0x8C30190F, // 0037 GETMET R12 R12 K15 + 0x8C380910, // 0038 GETMET R14 R4 K16 + 0x58400011, // 0039 LDCONST R16 K17 + 0x88440312, // 003A GETMBR R17 R1 K18 + 0x60480008, // 003B GETGBL R18 G8 + 0x5C4C0E00, // 003C MOVE R19 R7 + 0x7C480200, // 003D CALL R18 1 + 0x782E0002, // 003E JMPF R11 #0042 + 0x004E260B, // 003F ADD R19 K19 R11 + 0x004C2714, // 0040 ADD R19 R19 K20 + 0x70020000, // 0041 JMP #0043 + 0x584C0015, // 0042 LDCONST R19 K21 + 0x00482413, // 0043 ADD R18 R18 R19 + 0x7C380800, // 0044 CALL R14 4 + 0x583C0016, // 0045 LDCONST R15 K22 + 0x7C300600, // 0046 CALL R12 3 + 0x7002000A, // 0047 JMP #0053 + 0xB82E1C00, // 0048 GETNGBL R11 K14 + 0x8C2C170F, // 0049 GETMET R11 R11 K15 + 0x8C340910, // 004A GETMET R13 R4 K16 + 0x583C0011, // 004B LDCONST R15 K17 + 0x88400312, // 004C GETMBR R16 R1 K18 + 0x60440008, // 004D GETGBL R17 G8 + 0x5C480E00, // 004E MOVE R18 R7 + 0x7C440200, // 004F CALL R17 1 + 0x7C340800, // 0050 CALL R13 4 + 0x58380016, // 0051 LDCONST R14 K22 + 0x7C2C0600, // 0052 CALL R11 3 + 0x882C0101, // 0053 GETMBR R11 R0 K1 + 0x8C2C1717, // 0054 GETMET R11 R11 K23 + 0x5C340E00, // 0055 MOVE R13 R7 + 0x84380001, // 0056 CLOSURE R14 P1 + 0x7C2C0600, // 0057 CALL R11 3 + 0x7001FFB8, // 0058 JMP #0012 + 0x58240018, // 0059 LDCONST R9 K24 + 0xAC240200, // 005A CATCH R9 1 0 + 0xB0080000, // 005B RAISE 2 R0 R0 + 0xA0000000, // 005C CLOSE R0 + 0x80041000, // 005D RET 1 R8 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_sendqueue_by_exchangeid +********************************************************************/ +be_local_closure(Matter_IM_find_sendqueue_by_exchangeid, /* 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(send_queue), + /* K2 */ be_nested_str_weak(get_exchangeid), + /* K3 */ be_const_int(1), + }), + be_str_weak(find_sendqueue_by_exchangeid), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x58080000, // 0005 LDCONST R2 K0 + 0x600C000C, // 0006 GETGBL R3 G12 + 0x88100101, // 0007 GETMBR R4 R0 K1 + 0x7C0C0200, // 0008 CALL R3 1 + 0x140C0403, // 0009 LT R3 R2 R3 + 0x780E0008, // 000A JMPF R3 #0014 + 0x880C0101, // 000B GETMBR R3 R0 K1 + 0x940C0602, // 000C GETIDX R3 R3 R2 + 0x8C100702, // 000D GETMET R4 R3 K2 + 0x7C100200, // 000E CALL R4 1 + 0x1C100801, // 000F EQ R4 R4 R1 + 0x78120000, // 0010 JMPF R4 #0012 + 0x80040600, // 0011 RET 1 R3 + 0x00080503, // 0012 ADD R2 R2 K3 + 0x7001FFF1, // 0013 JMP #0006 + 0x4C0C0000, // 0014 LDNIL R3 + 0x80040600, // 0015 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_incoming_ack +********************************************************************/ +be_local_closure(Matter_IM_process_incoming_ack, /* 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(string), + /* K1 */ be_nested_str_weak(find_sendqueue_by_exchangeid), + /* K2 */ be_nested_str_weak(exchange_id), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20process_incoming_ack_X20exch_X3D_X25i_X20message_X3D_X25i), + /* K7 */ be_const_int(1), + /* K8 */ be_const_int(0), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(ack_received), + }), + be_str_weak(process_incoming_ack), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0101, // 0001 GETMET R3 R0 K1 + 0x88140302, // 0002 GETMBR R5 R1 K2 + 0x7C0C0400, // 0003 CALL R3 2 + 0xB8120600, // 0004 GETNGBL R4 K3 + 0x8C100904, // 0005 GETMET R4 R4 K4 + 0x8C180505, // 0006 GETMET R6 R2 K5 + 0x58200006, // 0007 LDCONST R8 K6 + 0x88240302, // 0008 GETMBR R9 R1 K2 + 0x4C280000, // 0009 LDNIL R10 + 0x2028060A, // 000A NE R10 R3 R10 + 0x782A0001, // 000B JMPF R10 #000E + 0x58280007, // 000C LDCONST R10 K7 + 0x70020000, // 000D JMP #000F + 0x58280008, // 000E LDCONST R10 K8 + 0x7C180800, // 000F CALL R6 4 + 0x581C0009, // 0010 LDCONST R7 K9 + 0x7C100600, // 0011 CALL R4 3 + 0x780E0003, // 0012 JMPF R3 #0017 + 0x8C10070A, // 0013 GETMET R4 R3 K10 + 0x5C180200, // 0014 MOVE R6 R1 + 0x7C100400, // 0015 CALL R4 2 + 0x80040800, // 0016 RET 1 R4 + 0x50100000, // 0017 LDBOOL R4 0 0 + 0x80040800, // 0018 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_read_request +********************************************************************/ +be_local_closure(Matter_IM_process_read_request, /* 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[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(ReadRequestMessage), + /* K2 */ be_nested_str_weak(from_TLV), + /* K3 */ be_nested_str_weak(attributes_requests), + /* K4 */ be_nested_str_weak(_inner_process_read_request), + /* K5 */ be_nested_str_weak(session), + /* K6 */ be_nested_str_weak(send_report_data), + }), + be_str_weak(process_read_request), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xB80E0000, // 0000 GETNGBL R3 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0702, // 0003 GETMET R3 R3 K2 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x88100703, // 0006 GETMBR R4 R3 K3 + 0x4C140000, // 0007 LDNIL R5 + 0x20100805, // 0008 NE R4 R4 R5 + 0x78120007, // 0009 JMPF R4 #0012 + 0x8C100104, // 000A GETMET R4 R0 K4 + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x5C1C0600, // 000C MOVE R7 R3 + 0x7C100600, // 000D CALL R4 3 + 0x8C140106, // 000E GETMET R5 R0 K6 + 0x5C1C0200, // 000F MOVE R7 R1 + 0x5C200800, // 0010 MOVE R8 R4 + 0x7C140600, // 0011 CALL R5 3 + 0x50100200, // 0012 LDBOOL R4 1 0 + 0x80040800, // 0013 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_report_data +********************************************************************/ +be_local_closure(Matter_IM_send_report_data, /* 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_weak(send_queue), + /* K1 */ be_nested_str_weak(push), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(IM_ReportData), + }), + be_str_weak(send_report_data), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0xB8160400, // 0002 GETNGBL R5 K2 + 0x8C140B03, // 0003 GETMET R5 R5 K3 + 0x5C1C0200, // 0004 MOVE R7 R1 + 0x5C200400, // 0005 MOVE R8 R2 + 0x7C140600, // 0006 CALL R5 3 + 0x7C0C0400, // 0007 CALL R3 2 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_status_response +********************************************************************/ +be_local_closure(Matter_IM_process_status_response, /* name */ be_nested_proto( 13, /* nstack */ 3, /* argc */ @@ -150,7 +2045,334 @@ be_local_closure(Matter_IM_process_timed_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[26]) { /* constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(findsubval), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(find_sendqueue_by_exchangeid), + /* K4 */ be_nested_str_weak(exchange_id), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(SUCCESS), + /* K7 */ be_nested_str_weak(status_ok_received), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(format), + /* K11 */ be_nested_str_weak(MTR_X3A_X20_X3EOK_X20_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20exch_X3D_X25i_X20not_X20found), + /* K12 */ be_nested_str_weak(session), + /* K13 */ be_nested_str_weak(local_session_id), + /* K14 */ be_const_int(3), + /* K15 */ be_nested_str_weak(MTR_X3A_X20_X3EStatus_X20_X20_X20_X20ERROR_X20_X3D_X200x_X2502X), + /* K16 */ be_const_int(2), + /* K17 */ be_nested_str_weak(status_error_received), + /* K18 */ be_nested_str_weak(remove_sendqueue_by_exchangeid), + }), + be_str_weak(process_status_response), + &be_const_str_solidified, + ( &(const binstruction[46]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x8C100501, // 0001 GETMET R4 R2 K1 + 0x58180002, // 0002 LDCONST R6 K2 + 0x541E00FE, // 0003 LDINT R7 255 + 0x7C100600, // 0004 CALL R4 3 + 0x8C140103, // 0005 GETMET R5 R0 K3 + 0x881C0304, // 0006 GETMBR R7 R1 K4 + 0x7C140400, // 0007 CALL R5 2 + 0xB81A0A00, // 0008 GETNGBL R6 K5 + 0x88180D06, // 0009 GETMBR R6 R6 K6 + 0x1C180806, // 000A EQ R6 R4 R6 + 0x781A0010, // 000B JMPF R6 #001D + 0x78160004, // 000C JMPF R5 #0012 + 0x8C180B07, // 000D GETMET R6 R5 K7 + 0x5C200200, // 000E MOVE R8 R1 + 0x7C180400, // 000F CALL R6 2 + 0x80040C00, // 0010 RET 1 R6 + 0x70020009, // 0011 JMP #001C + 0xB81A1000, // 0012 GETNGBL R6 K8 + 0x8C180D09, // 0013 GETMET R6 R6 K9 + 0x8C20070A, // 0014 GETMET R8 R3 K10 + 0x5828000B, // 0015 LDCONST R10 K11 + 0x882C030C, // 0016 GETMBR R11 R1 K12 + 0x882C170D, // 0017 GETMBR R11 R11 K13 + 0x88300304, // 0018 GETMBR R12 R1 K4 + 0x7C200800, // 0019 CALL R8 4 + 0x5824000E, // 001A LDCONST R9 K14 + 0x7C180600, // 001B CALL R6 3 + 0x7002000E, // 001C JMP #002C + 0xB81A1000, // 001D GETNGBL R6 K8 + 0x8C180D09, // 001E GETMET R6 R6 K9 + 0x8C20070A, // 001F GETMET R8 R3 K10 + 0x5828000F, // 0020 LDCONST R10 K15 + 0x5C2C0800, // 0021 MOVE R11 R4 + 0x7C200600, // 0022 CALL R8 3 + 0x58240010, // 0023 LDCONST R9 K16 + 0x7C180600, // 0024 CALL R6 3 + 0x78160005, // 0025 JMPF R5 #002C + 0x8C180B11, // 0026 GETMET R6 R5 K17 + 0x5C200200, // 0027 MOVE R8 R1 + 0x7C180400, // 0028 CALL R6 2 + 0x8C180112, // 0029 GETMET R6 R0 K18 + 0x88200304, // 002A GETMBR R8 R1 K4 + 0x7C180400, // 002B CALL R6 2 + 0x50180000, // 002C LDBOOL R6 0 0 + 0x80040C00, // 002D RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_write_response +********************************************************************/ +be_local_closure(Matter_IM_process_write_response, /* 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(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(WriteResponseMessage), + /* K3 */ be_nested_str_weak(from_TLV), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteResponseMessage_X3D), + /* K7 */ be_const_int(2), + }), + be_str_weak(process_write_response), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x8C100902, // 0002 GETMET R4 R4 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C100400, // 0006 CALL R4 2 + 0xB8160800, // 0007 GETNGBL R5 K4 + 0x8C140B05, // 0008 GETMET R5 R5 K5 + 0x601C0008, // 0009 GETGBL R7 G8 + 0x5C200800, // 000A MOVE R8 R4 + 0x7C1C0200, // 000B CALL R7 1 + 0x001E0C07, // 000C ADD R7 K6 R7 + 0x58200007, // 000D LDCONST R8 K7 + 0x7C140600, // 000E CALL R5 3 + 0x50140000, // 000F LDBOOL R5 0 0 + 0x80040A00, // 0010 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_subscribe_update +********************************************************************/ +be_local_closure(Matter_IM_send_subscribe_update, /* 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[27]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(ReadRequestMessage), + /* K4 */ be_nested_str_weak(fabric_filtered), + /* K5 */ be_nested_str_weak(attributes_requests), + /* K6 */ be_nested_str_weak(updates), + /* K7 */ be_nested_str_weak(AttributePathIB), + /* K8 */ be_nested_str_weak(endpoint), + /* K9 */ be_nested_str_weak(cluster), + /* K10 */ be_nested_str_weak(attribute), + /* K11 */ be_nested_str_weak(push), + /* K12 */ be_nested_str_weak(stop_iteration), + /* K13 */ be_nested_str_weak(tasmota), + /* K14 */ be_nested_str_weak(log), + /* K15 */ be_nested_str_weak(format), + /* K16 */ be_nested_str_weak(MTR_X3A_X20_X3CSub_Data_X20_X20_X28_X256i_X29_X20sub_X3D_X25i), + /* K17 */ be_nested_str_weak(local_session_id), + /* K18 */ be_nested_str_weak(subscription_id), + /* K19 */ be_const_int(2), + /* K20 */ be_nested_str_weak(is_keep_alive), + /* K21 */ be_nested_str_weak(_inner_process_read_request), + /* K22 */ be_nested_str_weak(suppress_response), + /* K23 */ be_nested_str_weak(IM_ReportDataSubscribed), + /* K24 */ be_nested_str_weak(_message_handler), + /* K25 */ be_nested_str_weak(send_queue), + /* K26 */ be_nested_str_weak(send_enqueued), + }), + be_str_weak(send_subscribe_update), + &be_const_str_solidified, + ( &(const binstruction[67]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0xB8120400, // 0002 GETNGBL R4 K2 + 0x8C100903, // 0003 GETMET R4 R4 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x50140000, // 0005 LDBOOL R5 0 0 + 0x90120805, // 0006 SETMBR R4 K4 R5 + 0x60140012, // 0007 GETGBL R5 G18 + 0x7C140000, // 0008 CALL R5 0 + 0x90120A05, // 0009 SETMBR R4 K5 R5 + 0x60140010, // 000A GETGBL R5 G16 + 0x88180306, // 000B GETMBR R6 R1 K6 + 0x7C140200, // 000C CALL R5 1 + 0xA802000F, // 000D EXBLK 0 #001E + 0x5C180A00, // 000E MOVE R6 R5 + 0x7C180000, // 000F CALL R6 0 + 0xB81E0400, // 0010 GETNGBL R7 K2 + 0x8C1C0F07, // 0011 GETMET R7 R7 K7 + 0x7C1C0200, // 0012 CALL R7 1 + 0x88200D08, // 0013 GETMBR R8 R6 K8 + 0x901E1008, // 0014 SETMBR R7 K8 R8 + 0x88200D09, // 0015 GETMBR R8 R6 K9 + 0x901E1208, // 0016 SETMBR R7 K9 R8 + 0x88200D0A, // 0017 GETMBR R8 R6 K10 + 0x901E1408, // 0018 SETMBR R7 K10 R8 + 0x88200905, // 0019 GETMBR R8 R4 K5 + 0x8C20110B, // 001A GETMET R8 R8 K11 + 0x5C280E00, // 001B MOVE R10 R7 + 0x7C200400, // 001C CALL R8 2 + 0x7001FFEF, // 001D JMP #000E + 0x5814000C, // 001E LDCONST R5 K12 + 0xAC140200, // 001F CATCH R5 1 0 + 0xB0080000, // 0020 RAISE 2 R0 R0 + 0xB8161A00, // 0021 GETNGBL R5 K13 + 0x8C140B0E, // 0022 GETMET R5 R5 K14 + 0x8C1C050F, // 0023 GETMET R7 R2 K15 + 0x58240010, // 0024 LDCONST R9 K16 + 0x88280711, // 0025 GETMBR R10 R3 K17 + 0x882C0312, // 0026 GETMBR R11 R1 K18 + 0x7C1C0800, // 0027 CALL R7 4 + 0x58200013, // 0028 LDCONST R8 K19 + 0x7C140600, // 0029 CALL R5 3 + 0x50140000, // 002A LDBOOL R5 0 0 + 0x90062805, // 002B SETMBR R1 K20 R5 + 0x8C140115, // 002C GETMET R5 R0 K21 + 0x5C1C0600, // 002D MOVE R7 R3 + 0x5C200800, // 002E MOVE R8 R4 + 0x7C140600, // 002F CALL R5 3 + 0x50180000, // 0030 LDBOOL R6 0 0 + 0x90162C06, // 0031 SETMBR R5 K22 R6 + 0x88180312, // 0032 GETMBR R6 R1 K18 + 0x90162406, // 0033 SETMBR R5 K18 R6 + 0xB81A0400, // 0034 GETNGBL R6 K2 + 0x8C180D17, // 0035 GETMET R6 R6 K23 + 0x88200718, // 0036 GETMBR R8 R3 K24 + 0x5C240600, // 0037 MOVE R9 R3 + 0x5C280A00, // 0038 MOVE R10 R5 + 0x5C2C0200, // 0039 MOVE R11 R1 + 0x7C180A00, // 003A CALL R6 5 + 0x881C0119, // 003B GETMBR R7 R0 K25 + 0x8C1C0F0B, // 003C GETMET R7 R7 K11 + 0x5C240C00, // 003D MOVE R9 R6 + 0x7C1C0400, // 003E CALL R7 2 + 0x8C1C011A, // 003F GETMET R7 R0 K26 + 0x88240718, // 0040 GETMBR R9 R3 K24 + 0x7C1C0400, // 0041 CALL R7 2 + 0x80000000, // 0042 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_enqueued +********************************************************************/ +be_local_closure(Matter_IM_send_enqueued, /* 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[13]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(send_queue), + /* K2 */ be_nested_str_weak(finish), + /* K3 */ be_nested_str_weak(ready), + /* K4 */ be_nested_str_weak(send_im), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(MTR_X3A_X20remove_X20IM_X20message_X20exch_X3D), + /* K8 */ be_nested_str_weak(resp), + /* K9 */ be_nested_str_weak(exchange_id), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(remove), + /* K12 */ be_const_int(1), + }), + be_str_weak(send_enqueued), + &be_const_str_solidified, + ( &(const binstruction[34]) { /* 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 + 0x780E001A, // 0005 JMPF R3 #0021 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x88100702, // 0008 GETMBR R4 R3 K2 + 0x74120004, // 0009 JMPT R4 #000F + 0x88100703, // 000A GETMBR R4 R3 K3 + 0x78120002, // 000B JMPF R4 #000F + 0x8C100704, // 000C GETMET R4 R3 K4 + 0x5C180200, // 000D MOVE R6 R1 + 0x7C100400, // 000E CALL R4 2 + 0x88100702, // 000F GETMBR R4 R3 K2 + 0x7812000D, // 0010 JMPF R4 #001F + 0xB8120A00, // 0011 GETNGBL R4 K5 + 0x8C100906, // 0012 GETMET R4 R4 K6 + 0x60180008, // 0013 GETGBL R6 G8 + 0x881C0708, // 0014 GETMBR R7 R3 K8 + 0x881C0F09, // 0015 GETMBR R7 R7 K9 + 0x7C180200, // 0016 CALL R6 1 + 0x001A0E06, // 0017 ADD R6 K7 R6 + 0x581C000A, // 0018 LDCONST R7 K10 + 0x7C100600, // 0019 CALL R4 3 + 0x88100101, // 001A GETMBR R4 R0 K1 + 0x8C10090B, // 001B GETMET R4 R4 K11 + 0x5C180400, // 001C MOVE R6 R2 + 0x7C100400, // 001D CALL R4 2 + 0x70020000, // 001E JMP #0020 + 0x0008050C, // 001F ADD R2 R2 K12 + 0x7001FFDF, // 0020 JMP #0001 + 0x80000000, // 0021 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_timed_request +********************************************************************/ +be_local_closure(Matter_IM_process_timed_request, /* 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[16]) { /* constants */ /* K0 */ be_nested_str_weak(string), /* K1 */ be_nested_str_weak(matter), /* K2 */ be_nested_str_weak(TimedRequestMessage), @@ -160,27 +2382,17 @@ be_local_closure(Matter_IM_process_timed_request, /* name */ /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20TimedRequestMessage_X3D), /* K7 */ be_const_int(3), /* K8 */ be_nested_str_weak(format), - /* K9 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_IM_X20_X20_X20TimedRequest_X3D_X25i_X20from_X20_X5B_X25s_X5D_X3A_X25i), - /* K10 */ be_nested_str_weak(timeout), - /* K11 */ be_nested_str_weak(remote_ip), - /* K12 */ be_nested_str_weak(remote_port), + /* K9 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand_X20_X20_X20_X28_X256i_X29_X20TimedRequest_X3D_X25i), + /* K10 */ be_nested_str_weak(session), + /* K11 */ be_nested_str_weak(local_session_id), + /* K12 */ be_nested_str_weak(timeout), /* K13 */ be_const_int(2), - /* K14 */ be_nested_str_weak(StatusResponseMessage), - /* K15 */ be_nested_str_weak(status), - /* K16 */ be_nested_str_weak(SUCCESS), - /* K17 */ be_nested_str_weak(build_response), - /* K18 */ be_const_int(1), - /* K19 */ be_nested_str_weak(encode), - /* K20 */ be_nested_str_weak(to_TLV), - /* K21 */ be_nested_str_weak(encrypt), - /* K22 */ be_nested_str_weak(responder), - /* K23 */ be_nested_str_weak(send_response), - /* K24 */ be_nested_str_weak(raw), - /* K25 */ be_nested_str_weak(message_counter), + /* K14 */ be_nested_str_weak(send_status), + /* K15 */ be_nested_str_weak(SUCCESS), }), be_str_weak(process_timed_request), &be_const_str_solidified, - ( &(const binstruction[52]) { /* code */ + ( &(const binstruction[32]) { /* code */ 0xA40E0000, // 0000 IMPORT R3 K0 0xB8120200, // 0001 GETNGBL R4 K1 0x8C100902, // 0002 GETMET R4 R4 K2 @@ -200,110 +2412,19 @@ be_local_closure(Matter_IM_process_timed_request, /* name */ 0x8C140B05, // 0010 GETMET R5 R5 K5 0x8C1C0708, // 0011 GETMET R7 R3 K8 0x58240009, // 0012 LDCONST R9 K9 - 0x8828090A, // 0013 GETMBR R10 R4 K10 - 0x882C030B, // 0014 GETMBR R11 R1 K11 - 0x8830030C, // 0015 GETMBR R12 R1 K12 - 0x7C1C0A00, // 0016 CALL R7 5 + 0x8828030A, // 0013 GETMBR R10 R1 K10 + 0x8828150B, // 0014 GETMBR R10 R10 K11 + 0x882C090C, // 0015 GETMBR R11 R4 K12 + 0x7C1C0800, // 0016 CALL R7 4 0x5820000D, // 0017 LDCONST R8 K13 0x7C140600, // 0018 CALL R5 3 - 0xB8160200, // 0019 GETNGBL R5 K1 - 0x8C140B0E, // 001A GETMET R5 R5 K14 - 0x7C140200, // 001B CALL R5 1 - 0xB81A0200, // 001C GETNGBL R6 K1 - 0x88180D10, // 001D GETMBR R6 R6 K16 - 0x90161E06, // 001E SETMBR R5 K15 R6 - 0x8C180311, // 001F GETMET R6 R1 K17 - 0x58200012, // 0020 LDCONST R8 K18 - 0x50240200, // 0021 LDBOOL R9 1 0 - 0x7C180600, // 0022 CALL R6 3 - 0x8C1C0D13, // 0023 GETMET R7 R6 K19 - 0x8C240B14, // 0024 GETMET R9 R5 K20 - 0x7C240200, // 0025 CALL R9 1 - 0x8C241313, // 0026 GETMET R9 R9 K19 - 0x7C240200, // 0027 CALL R9 1 - 0x7C1C0400, // 0028 CALL R7 2 - 0x8C1C0D15, // 0029 GETMET R7 R6 K21 - 0x7C1C0200, // 002A CALL R7 1 - 0x881C0116, // 002B GETMBR R7 R0 K22 - 0x8C1C0F17, // 002C GETMET R7 R7 K23 - 0x88240D18, // 002D GETMBR R9 R6 K24 - 0x8828030B, // 002E GETMBR R10 R1 K11 - 0x882C030C, // 002F GETMBR R11 R1 K12 - 0x88300D19, // 0030 GETMBR R12 R6 K25 - 0x7C1C0A00, // 0031 CALL R7 5 - 0x501C0200, // 0032 LDBOOL R7 1 0 - 0x80040E00, // 0033 RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_status_response -********************************************************************/ -be_local_closure(Matter_IM_process_status_response, /* 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[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(findsubval), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(tasmota), - /* K4 */ be_nested_str_weak(log), - /* K5 */ be_nested_str_weak(format), - /* K6 */ be_nested_str_weak(MTR_X3A_X20Status_X20Response_X20_X3D_X200x_X2502X), - /* K7 */ be_const_int(3), - }), - be_str_weak(process_status_response), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0x8C100501, // 0001 GETMET R4 R2 K1 - 0x58180002, // 0002 LDCONST R6 K2 - 0x541E00FE, // 0003 LDINT R7 255 - 0x7C100600, // 0004 CALL R4 3 - 0xB8160600, // 0005 GETNGBL R5 K3 - 0x8C140B04, // 0006 GETMET R5 R5 K4 - 0x8C1C0705, // 0007 GETMET R7 R3 K5 - 0x58240006, // 0008 LDCONST R9 K6 - 0x5C280800, // 0009 MOVE R10 R4 - 0x7C1C0600, // 000A CALL R7 3 - 0x58200007, // 000B LDCONST R8 K7 - 0x7C140600, // 000C CALL R5 3 - 0x50140200, // 000D LDBOOL R5 1 0 - 0x80040A00, // 000E RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_second -********************************************************************/ -be_local_closure(Matter_IM_every_second, /* 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(every_second), - &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + 0x8C14010E, // 0019 GETMET R5 R0 K14 + 0x5C1C0200, // 001A MOVE R7 R1 + 0xB8220200, // 001B GETNGBL R8 K1 + 0x8820110F, // 001C GETMBR R8 R8 K15 + 0x7C140600, // 001D CALL R5 3 + 0x50140200, // 001E LDBOOL R5 1 0 + 0x80040A00, // 001F RET 1 R5 }) ) ); @@ -331,7 +2452,7 @@ be_local_closure(Matter_IM_report_data, /* name */ /* K4 */ be_nested_str_weak(tasmota), /* K5 */ be_nested_str_weak(log), /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20ReportDataMessage_X3D), - /* K7 */ be_const_int(3), + /* K7 */ be_const_int(2), }), be_str_weak(report_data), &be_const_str_solidified, @@ -380,7 +2501,7 @@ be_local_closure(Matter_IM_process_invoke_response, /* name */ /* K4 */ be_nested_str_weak(tasmota), /* K5 */ be_nested_str_weak(log), /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20InvokeResponseMessage_X3D), - /* K7 */ be_const_int(3), + /* K7 */ be_const_int(2), }), be_str_weak(process_invoke_response), &be_const_str_solidified, @@ -408,1117 +2529,12 @@ be_local_closure(Matter_IM_process_invoke_response, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: process_read_request -********************************************************************/ -be_local_closure(Matter_IM_process_read_request, /* name */ - be_nested_proto( - 15, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 2]) { - be_nested_proto( - 18, /* nstack */ - 4, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 1), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[32]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(get_attribute_name), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(attribute), - /* K5 */ be_nested_str_weak(_X20_X28), - /* K6 */ be_nested_str_weak(_X29), - /* K7 */ be_nested_str_weak(), - /* K8 */ be_nested_str_weak(read_attribute), - /* K9 */ be_nested_str_weak(AttributeReportIB), - /* K10 */ be_nested_str_weak(attribute_data), - /* K11 */ be_nested_str_weak(AttributeDataIB), - /* K12 */ be_nested_str_weak(data_version), - /* K13 */ be_const_int(1), - /* K14 */ be_nested_str_weak(path), - /* K15 */ be_nested_str_weak(AttributePathIB), - /* K16 */ be_nested_str_weak(endpoint), - /* K17 */ be_nested_str_weak(data), - /* K18 */ be_nested_str_weak(attribute_reports), - /* K19 */ be_nested_str_weak(push), - /* K20 */ be_nested_str_weak(tasmota), - /* K21 */ be_nested_str_weak(log), - /* K22 */ be_nested_str_weak(format), - /* K23 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20_X25s_X25s_X20_X2D_X20_X25s), - /* K24 */ be_const_int(2), - /* K25 */ be_nested_str_weak(status), - /* K26 */ be_nested_str_weak(attribute_status), - /* K27 */ be_nested_str_weak(AttributeStatusIB), - /* K28 */ be_nested_str_weak(StatusIB), - /* K29 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20_X25s_X25s_X20_X2D_X20STATUS_X3A_X200x_X2502X_X20_X25s), - /* K30 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), - /* K31 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20_X25s_X25s_X20_X2D_X20IGNORED), - }), - be_str_weak(read_single_attribute), - &be_const_str_solidified, - ( &(const binstruction[150]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x8C140B02, // 0002 GETMET R5 R5 K2 - 0x881C0503, // 0003 GETMBR R7 R2 K3 - 0x88200504, // 0004 GETMBR R8 R2 K4 - 0x7C140600, // 0005 CALL R5 3 - 0x78160002, // 0006 JMPF R5 #000A - 0x001A0A05, // 0007 ADD R6 K5 R5 - 0x00180D06, // 0008 ADD R6 R6 K6 - 0x70020000, // 0009 JMP #000B - 0x58180007, // 000A LDCONST R6 K7 - 0x5C140C00, // 000B MOVE R5 R6 - 0x4C180000, // 000C LDNIL R6 - 0x20180206, // 000D NE R6 R1 R6 - 0x781A0004, // 000E JMPF R6 #0014 - 0x8C180308, // 000F GETMET R6 R1 K8 - 0x68200000, // 0010 GETUPV R8 U0 - 0x5C240400, // 0011 MOVE R9 R2 - 0x7C180600, // 0012 CALL R6 3 - 0x70020000, // 0013 JMP #0015 - 0x4C180000, // 0014 LDNIL R6 - 0x4C1C0000, // 0015 LDNIL R7 - 0x201C0C07, // 0016 NE R7 R6 R7 - 0x781E0030, // 0017 JMPF R7 #0049 - 0xB81E0200, // 0018 GETNGBL R7 K1 - 0x8C1C0F09, // 0019 GETMET R7 R7 K9 - 0x7C1C0200, // 001A CALL R7 1 - 0xB8220200, // 001B GETNGBL R8 K1 - 0x8C20110B, // 001C GETMET R8 R8 K11 - 0x7C200200, // 001D CALL R8 1 - 0x901E1408, // 001E SETMBR R7 K10 R8 - 0x88200F0A, // 001F GETMBR R8 R7 K10 - 0x9022190D, // 0020 SETMBR R8 K12 K13 - 0x88200F0A, // 0021 GETMBR R8 R7 K10 - 0xB8260200, // 0022 GETNGBL R9 K1 - 0x8C24130F, // 0023 GETMET R9 R9 K15 - 0x7C240200, // 0024 CALL R9 1 - 0x90221C09, // 0025 SETMBR R8 K14 R9 - 0x88200F0A, // 0026 GETMBR R8 R7 K10 - 0x8820110E, // 0027 GETMBR R8 R8 K14 - 0x88240510, // 0028 GETMBR R9 R2 K16 - 0x90222009, // 0029 SETMBR R8 K16 R9 - 0x88200F0A, // 002A GETMBR R8 R7 K10 - 0x8820110E, // 002B GETMBR R8 R8 K14 - 0x88240503, // 002C GETMBR R9 R2 K3 - 0x90220609, // 002D SETMBR R8 K3 R9 - 0x88200F0A, // 002E GETMBR R8 R7 K10 - 0x8820110E, // 002F GETMBR R8 R8 K14 - 0x88240504, // 0030 GETMBR R9 R2 K4 - 0x90220809, // 0031 SETMBR R8 K4 R9 - 0x88200F0A, // 0032 GETMBR R8 R7 K10 - 0x90222206, // 0033 SETMBR R8 K17 R6 - 0x88200112, // 0034 GETMBR R8 R0 K18 - 0x8C201113, // 0035 GETMET R8 R8 K19 - 0x5C280E00, // 0036 MOVE R10 R7 - 0x7C200400, // 0037 CALL R8 2 - 0xB8222800, // 0038 GETNGBL R8 K20 - 0x8C201115, // 0039 GETMET R8 R8 K21 - 0x8C280916, // 003A GETMET R10 R4 K22 - 0x58300017, // 003B LDCONST R12 K23 - 0x60340008, // 003C GETGBL R13 G8 - 0x5C380400, // 003D MOVE R14 R2 - 0x7C340200, // 003E CALL R13 1 - 0x5C380A00, // 003F MOVE R14 R5 - 0x603C0008, // 0040 GETGBL R15 G8 - 0x5C400C00, // 0041 MOVE R16 R6 - 0x7C3C0200, // 0042 CALL R15 1 - 0x7C280A00, // 0043 CALL R10 5 - 0x582C0018, // 0044 LDCONST R11 K24 - 0x7C200600, // 0045 CALL R8 3 - 0x50200200, // 0046 LDBOOL R8 1 0 - 0x80041000, // 0047 RET 1 R8 - 0x7002004B, // 0048 JMP #0095 - 0x881C0519, // 0049 GETMBR R7 R2 K25 - 0x4C200000, // 004A LDNIL R8 - 0x201C0E08, // 004B NE R7 R7 R8 - 0x781E003C, // 004C JMPF R7 #008A - 0x780E003A, // 004D JMPF R3 #0089 - 0xB81E0200, // 004E GETNGBL R7 K1 - 0x8C1C0F09, // 004F GETMET R7 R7 K9 - 0x7C1C0200, // 0050 CALL R7 1 - 0xB8220200, // 0051 GETNGBL R8 K1 - 0x8C20111B, // 0052 GETMET R8 R8 K27 - 0x7C200200, // 0053 CALL R8 1 - 0x901E3408, // 0054 SETMBR R7 K26 R8 - 0x88200F1A, // 0055 GETMBR R8 R7 K26 - 0xB8260200, // 0056 GETNGBL R9 K1 - 0x8C24130F, // 0057 GETMET R9 R9 K15 - 0x7C240200, // 0058 CALL R9 1 - 0x90221C09, // 0059 SETMBR R8 K14 R9 - 0x88200F1A, // 005A GETMBR R8 R7 K26 - 0xB8260200, // 005B GETNGBL R9 K1 - 0x8C24131C, // 005C GETMET R9 R9 K28 - 0x7C240200, // 005D CALL R9 1 - 0x90223209, // 005E SETMBR R8 K25 R9 - 0x88200F1A, // 005F GETMBR R8 R7 K26 - 0x8820110E, // 0060 GETMBR R8 R8 K14 - 0x88240510, // 0061 GETMBR R9 R2 K16 - 0x90222009, // 0062 SETMBR R8 K16 R9 - 0x88200F1A, // 0063 GETMBR R8 R7 K26 - 0x8820110E, // 0064 GETMBR R8 R8 K14 - 0x88240503, // 0065 GETMBR R9 R2 K3 - 0x90220609, // 0066 SETMBR R8 K3 R9 - 0x88200F1A, // 0067 GETMBR R8 R7 K26 - 0x8820110E, // 0068 GETMBR R8 R8 K14 - 0x88240504, // 0069 GETMBR R9 R2 K4 - 0x90220809, // 006A SETMBR R8 K4 R9 - 0x88200F1A, // 006B GETMBR R8 R7 K26 - 0x88201119, // 006C GETMBR R8 R8 K25 - 0x88240519, // 006D GETMBR R9 R2 K25 - 0x90223209, // 006E SETMBR R8 K25 R9 - 0x88200112, // 006F GETMBR R8 R0 K18 - 0x8C201113, // 0070 GETMET R8 R8 K19 - 0x5C280E00, // 0071 MOVE R10 R7 - 0x7C200400, // 0072 CALL R8 2 - 0xB8222800, // 0073 GETNGBL R8 K20 - 0x8C201115, // 0074 GETMET R8 R8 K21 - 0x8C280916, // 0075 GETMET R10 R4 K22 - 0x5830001D, // 0076 LDCONST R12 K29 - 0x60340008, // 0077 GETGBL R13 G8 - 0x5C380400, // 0078 MOVE R14 R2 - 0x7C340200, // 0079 CALL R13 1 - 0x5C380A00, // 007A MOVE R14 R5 - 0x883C0519, // 007B GETMBR R15 R2 K25 - 0x88400519, // 007C GETMBR R16 R2 K25 - 0xB8460200, // 007D GETNGBL R17 K1 - 0x8844231E, // 007E GETMBR R17 R17 K30 - 0x1C402011, // 007F EQ R16 R16 R17 - 0x78420001, // 0080 JMPF R16 #0083 - 0x5840001E, // 0081 LDCONST R16 K30 - 0x70020000, // 0082 JMP #0084 - 0x58400007, // 0083 LDCONST R16 K7 - 0x7C280C00, // 0084 CALL R10 6 - 0x582C0018, // 0085 LDCONST R11 K24 - 0x7C200600, // 0086 CALL R8 3 - 0x50200200, // 0087 LDBOOL R8 1 0 - 0x80041000, // 0088 RET 1 R8 - 0x7002000A, // 0089 JMP #0095 - 0xB81E2800, // 008A GETNGBL R7 K20 - 0x8C1C0F15, // 008B GETMET R7 R7 K21 - 0x8C240916, // 008C GETMET R9 R4 K22 - 0x582C001F, // 008D LDCONST R11 K31 - 0x60300008, // 008E GETGBL R12 G8 - 0x5C340400, // 008F MOVE R13 R2 - 0x7C300200, // 0090 CALL R12 1 - 0x5C340A00, // 0091 MOVE R13 R5 - 0x7C240800, // 0092 CALL R9 4 - 0x58280018, // 0093 LDCONST R10 K24 - 0x7C1C0600, // 0094 CALL R7 3 - 0x80000000, // 0095 RET 0 - }) - ), - be_nested_proto( - 8, /* nstack */ - 3, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 2]) { /* upvals */ - be_local_const_upval(1, 4), - be_local_const_upval(1, 7), - }), - 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[ 7]) { /* code */ - 0x680C0000, // 0000 GETUPV R3 U0 - 0x68100001, // 0001 GETUPV R4 U1 - 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[30]) { /* constants */ - /* K0 */ be_nested_str_weak(device), - /* K1 */ be_nested_str_weak(get_active_endpoints), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(log), - /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_X3Aread_request_X20processing_X20start), - /* K5 */ be_const_int(3), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(Response_container), - /* K8 */ be_nested_str_weak(ReadRequestMessage), - /* K9 */ be_nested_str_weak(from_TLV), - /* K10 */ be_nested_str_weak(attributes_requests), - /* K11 */ be_nested_str_weak(ReportDataMessage), - /* K12 */ be_nested_str_weak(attribute_reports), - /* K13 */ be_nested_str_weak(endpoint), - /* K14 */ be_nested_str_weak(cluster), - /* K15 */ be_nested_str_weak(attribute), - /* K16 */ be_nested_str_weak(status), - /* K17 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), - /* K18 */ be_nested_str_weak(get_attribute_name), - /* K19 */ be_nested_str_weak(MTR_X3A_X20Read_Attr_X20), - /* K20 */ be_nested_str_weak(_X20_X28), - /* K21 */ be_nested_str_weak(_X29), - /* K22 */ be_nested_str_weak(), - /* K23 */ be_const_int(2), - /* K24 */ be_nested_str_weak(process_attribute_expansion), - /* K25 */ be_nested_str_weak(stop_iteration), - /* K26 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessage_X3D), - /* K27 */ be_nested_str_weak(MTR_X3A_X20ReportDataMessageTLV_X3D), - /* K28 */ be_nested_str_weak(to_TLV), - /* K29 */ be_nested_str_weak(send_attr_report), - }), - be_str_weak(process_read_request), - &be_const_str_solidified, - ( &(const binstruction[125]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x8C0C0701, // 0001 GETMET R3 R3 K1 - 0x7C0C0200, // 0002 CALL R3 1 - 0x84100000, // 0003 CLOSURE R4 P0 - 0xB8160400, // 0004 GETNGBL R5 K2 - 0x8C140B03, // 0005 GETMET R5 R5 K3 - 0x581C0004, // 0006 LDCONST R7 K4 - 0x58200005, // 0007 LDCONST R8 K5 - 0x7C140600, // 0008 CALL R5 3 - 0xB8160C00, // 0009 GETNGBL R5 K6 - 0x8C140B07, // 000A GETMET R5 R5 K7 - 0x7C140200, // 000B CALL R5 1 - 0xB81A0C00, // 000C GETNGBL R6 K6 - 0x8C180D08, // 000D GETMET R6 R6 K8 - 0x7C180200, // 000E CALL R6 1 - 0x8C180D09, // 000F GETMET R6 R6 K9 - 0x5C200400, // 0010 MOVE R8 R2 - 0x7C180400, // 0011 CALL R6 2 - 0x881C0D0A, // 0012 GETMBR R7 R6 K10 - 0x4C200000, // 0013 LDNIL R8 - 0x201C0E08, // 0014 NE R7 R7 R8 - 0x781E0063, // 0015 JMPF R7 #007A - 0xB81E0C00, // 0016 GETNGBL R7 K6 - 0x8C1C0F0B, // 0017 GETMET R7 R7 K11 - 0x7C1C0200, // 0018 CALL R7 1 - 0x60200012, // 0019 GETGBL R8 G18 - 0x7C200000, // 001A CALL R8 0 - 0x901E1808, // 001B SETMBR R7 K12 R8 - 0x60200010, // 001C GETGBL R8 G16 - 0x88240D0A, // 001D GETMBR R9 R6 K10 - 0x7C200200, // 001E CALL R8 1 - 0xA8020040, // 001F EXBLK 0 #0061 - 0x5C241000, // 0020 MOVE R9 R8 - 0x7C240000, // 0021 CALL R9 0 - 0x8828130D, // 0022 GETMBR R10 R9 K13 - 0x90161A0A, // 0023 SETMBR R5 K13 R10 - 0x8828130E, // 0024 GETMBR R10 R9 K14 - 0x90161C0A, // 0025 SETMBR R5 K14 R10 - 0x8828130F, // 0026 GETMBR R10 R9 K15 - 0x90161E0A, // 0027 SETMBR R5 K15 R10 - 0xB82A0C00, // 0028 GETNGBL R10 K6 - 0x88281511, // 0029 GETMBR R10 R10 K17 - 0x9016200A, // 002A SETMBR R5 K16 R10 - 0x88280B0D, // 002B GETMBR R10 R5 K13 - 0x4C2C0000, // 002C LDNIL R11 - 0x1C28140B, // 002D EQ R10 R10 R11 - 0x742A0007, // 002E JMPT R10 #0037 - 0x88280B0E, // 002F GETMBR R10 R5 K14 - 0x4C2C0000, // 0030 LDNIL R11 - 0x1C28140B, // 0031 EQ R10 R10 R11 - 0x742A0003, // 0032 JMPT R10 #0037 - 0x88280B0F, // 0033 GETMBR R10 R5 K15 - 0x4C2C0000, // 0034 LDNIL R11 - 0x1C28140B, // 0035 EQ R10 R10 R11 - 0x782A0023, // 0036 JMPF R10 #005B - 0x88280B0E, // 0037 GETMBR R10 R5 K14 - 0x4C2C0000, // 0038 LDNIL R11 - 0x2028140B, // 0039 NE R10 R10 R11 - 0x782A0017, // 003A JMPF R10 #0053 - 0x88280B0F, // 003B GETMBR R10 R5 K15 - 0x4C2C0000, // 003C LDNIL R11 - 0x2028140B, // 003D NE R10 R10 R11 - 0x782A0013, // 003E JMPF R10 #0053 - 0xB82A0C00, // 003F GETNGBL R10 K6 - 0x8C281512, // 0040 GETMET R10 R10 K18 - 0x88300B0E, // 0041 GETMBR R12 R5 K14 - 0x88340B0F, // 0042 GETMBR R13 R5 K15 - 0x7C280600, // 0043 CALL R10 3 - 0xB82E0400, // 0044 GETNGBL R11 K2 - 0x8C2C1703, // 0045 GETMET R11 R11 K3 - 0x60340008, // 0046 GETGBL R13 G8 - 0x5C380A00, // 0047 MOVE R14 R5 - 0x7C340200, // 0048 CALL R13 1 - 0x0036260D, // 0049 ADD R13 K19 R13 - 0x782A0002, // 004A JMPF R10 #004E - 0x003A280A, // 004B ADD R14 K20 R10 - 0x00381D15, // 004C ADD R14 R14 K21 - 0x70020000, // 004D JMP #004F - 0x58380016, // 004E LDCONST R14 K22 - 0x00341A0E, // 004F ADD R13 R13 R14 - 0x58380017, // 0050 LDCONST R14 K23 - 0x7C2C0600, // 0051 CALL R11 3 - 0x70020007, // 0052 JMP #005B - 0xB82A0400, // 0053 GETNGBL R10 K2 - 0x8C281503, // 0054 GETMET R10 R10 K3 - 0x60300008, // 0055 GETGBL R12 G8 - 0x5C340A00, // 0056 MOVE R13 R5 - 0x7C300200, // 0057 CALL R12 1 - 0x0032260C, // 0058 ADD R12 K19 R12 - 0x58340017, // 0059 LDCONST R13 K23 - 0x7C280600, // 005A CALL R10 3 - 0x88280100, // 005B GETMBR R10 R0 K0 - 0x8C281518, // 005C GETMET R10 R10 K24 - 0x5C300A00, // 005D MOVE R12 R5 - 0x84340001, // 005E CLOSURE R13 P1 - 0x7C280600, // 005F CALL R10 3 - 0x7001FFBE, // 0060 JMP #0020 - 0x58200019, // 0061 LDCONST R8 K25 - 0xAC200200, // 0062 CATCH R8 1 0 - 0xB0080000, // 0063 RAISE 2 R0 R0 - 0xB8220400, // 0064 GETNGBL R8 K2 - 0x8C201103, // 0065 GETMET R8 R8 K3 - 0x60280008, // 0066 GETGBL R10 G8 - 0x5C2C0E00, // 0067 MOVE R11 R7 - 0x7C280200, // 0068 CALL R10 1 - 0x002A340A, // 0069 ADD R10 K26 R10 - 0x582C0005, // 006A LDCONST R11 K5 - 0x7C200600, // 006B CALL R8 3 - 0xB8220400, // 006C GETNGBL R8 K2 - 0x8C201103, // 006D GETMET R8 R8 K3 - 0x60280008, // 006E GETGBL R10 G8 - 0x8C2C0F1C, // 006F GETMET R11 R7 K28 - 0x7C2C0200, // 0070 CALL R11 1 - 0x7C280200, // 0071 CALL R10 1 - 0x002A360A, // 0072 ADD R10 K27 R10 - 0x582C0005, // 0073 LDCONST R11 K5 - 0x7C200600, // 0074 CALL R8 3 - 0x8C20011D, // 0075 GETMET R8 R0 K29 - 0x5C280200, // 0076 MOVE R10 R1 - 0x5C2C0E00, // 0077 MOVE R11 R7 - 0x7C200600, // 0078 CALL R8 3 - 0xA01C0000, // 0079 CLOSE R7 - 0x501C0200, // 007A LDBOOL R7 1 0 - 0xA0000000, // 007B CLOSE R0 - 0x80040E00, // 007C RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_write_request -********************************************************************/ -be_local_closure(Matter_IM_process_write_request, /* 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(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(WriteRequestMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteRequestMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(process_write_request), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x8C100902, // 0002 GETMET R4 R4 K2 - 0x7C100200, // 0003 CALL R4 1 - 0x8C100903, // 0004 GETMET R4 R4 K3 - 0x5C180400, // 0005 MOVE R6 R2 - 0x7C100400, // 0006 CALL R4 2 - 0xB8160800, // 0007 GETNGBL R5 K4 - 0x8C140B05, // 0008 GETMET R5 R5 K5 - 0x601C0008, // 0009 GETGBL R7 G8 - 0x5C200800, // 000A MOVE R8 R4 - 0x7C1C0200, // 000B CALL R7 1 - 0x001E0C07, // 000C ADD R7 K6 R7 - 0x58200007, // 000D LDCONST R8 K7 - 0x7C140600, // 000E CALL R5 3 - 0x50140000, // 000F LDBOOL R5 0 0 - 0x80040A00, // 0010 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_invoke_request -********************************************************************/ -be_local_closure(Matter_IM_process_invoke_request, /* name */ - be_nested_proto( - 18, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[52]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(MTR_X3A_X20IM_X3Ainvoke_request_X20processing_X20start), - /* K4 */ be_const_int(3), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(Response_container), - /* K7 */ be_nested_str_weak(InvokeRequestMessage), - /* K8 */ be_nested_str_weak(from_TLV), - /* K9 */ be_nested_str_weak(invoke_requests), - /* K10 */ be_nested_str_weak(InvokeResponseMessage), - /* K11 */ be_nested_str_weak(suppress_response), - /* K12 */ be_nested_str_weak(invoke_responses), - /* K13 */ be_nested_str_weak(endpoint), - /* K14 */ be_nested_str_weak(command_path), - /* K15 */ be_nested_str_weak(cluster), - /* K16 */ be_nested_str_weak(command), - /* K17 */ be_nested_str_weak(status), - /* K18 */ be_nested_str_weak(UNSUPPORTED_COMMAND), - /* K19 */ be_nested_str_weak(get_command_name), - /* K20 */ be_nested_str_weak(format), - /* K21 */ be_nested_str_weak(0x_X2504X_X2F0x02X), - /* K22 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_cmd_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i), - /* K23 */ be_nested_str_weak(remote_ip), - /* K24 */ be_nested_str_weak(remote_port), - /* K25 */ be_const_int(2), - /* K26 */ be_nested_str_weak(responder), - /* K27 */ be_nested_str_weak(device), - /* K28 */ be_nested_str_weak(invoke_request), - /* K29 */ be_nested_str_weak(command_fields), - /* K30 */ be_nested_str_weak(InvokeResponseIB), - /* K31 */ be_nested_str_weak(CommandDataIB), - /* K32 */ be_nested_str_weak(CommandPathIB), - /* K33 */ be_nested_str_weak(push), - /* K34 */ be_nested_str_weak(0x_X2504X_X2F0x_X2502X), - /* K35 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_cmd_X20_X20_X20_X25s), - /* K36 */ be_nested_str_weak(CommandStatusIB), - /* K37 */ be_nested_str_weak(StatusIB), - /* K38 */ be_nested_str_weak(stop_iteration), - /* K39 */ be_nested_str_weak(MTR_X3A_X20invoke_responses_X3D), - /* K40 */ be_const_int(0), - /* K41 */ be_nested_str_weak(MTR_X3A_X20InvokeResponse_X3D), - /* K42 */ be_nested_str_weak(MTR_X3A_X20InvokeResponseTLV_X3D), - /* K43 */ be_nested_str_weak(to_TLV), - /* K44 */ be_nested_str_weak(build_response), - /* K45 */ be_nested_str_weak(encode), - /* K46 */ be_nested_str_weak(encrypt), - /* K47 */ be_nested_str_weak(send_response), - /* K48 */ be_nested_str_weak(raw), - /* K49 */ be_nested_str_weak(message_counter), - /* K50 */ be_nested_str_weak(x_flag_r), - /* K51 */ be_nested_str_weak(build_standalone_ack), - }), - be_str_weak(process_invoke_request), - &be_const_str_solidified, - ( &(const binstruction[242]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x8C100902, // 0002 GETMET R4 R4 K2 - 0x58180003, // 0003 LDCONST R6 K3 - 0x581C0004, // 0004 LDCONST R7 K4 - 0x7C100600, // 0005 CALL R4 3 - 0xB8120A00, // 0006 GETNGBL R4 K5 - 0x8C100906, // 0007 GETMET R4 R4 K6 - 0x7C100200, // 0008 CALL R4 1 - 0xB8160A00, // 0009 GETNGBL R5 K5 - 0x8C140B07, // 000A GETMET R5 R5 K7 - 0x7C140200, // 000B CALL R5 1 - 0x8C140B08, // 000C GETMET R5 R5 K8 - 0x5C1C0400, // 000D MOVE R7 R2 - 0x7C140400, // 000E CALL R5 2 - 0x88180B09, // 000F GETMBR R6 R5 K9 - 0x4C1C0000, // 0010 LDNIL R7 - 0x20180C07, // 0011 NE R6 R6 R7 - 0x781A00DD, // 0012 JMPF R6 #00F1 - 0xB81A0A00, // 0013 GETNGBL R6 K5 - 0x8C180D0A, // 0014 GETMET R6 R6 K10 - 0x7C180200, // 0015 CALL R6 1 - 0x501C0000, // 0016 LDBOOL R7 0 0 - 0x901A1607, // 0017 SETMBR R6 K11 R7 - 0x601C0012, // 0018 GETGBL R7 G18 - 0x7C1C0000, // 0019 CALL R7 0 - 0x901A1807, // 001A SETMBR R6 K12 R7 - 0x601C0010, // 001B GETGBL R7 G16 - 0x88200B09, // 001C GETMBR R8 R5 K9 - 0x7C1C0200, // 001D CALL R7 1 - 0xA802008D, // 001E EXBLK 0 #00AD - 0x5C200E00, // 001F MOVE R8 R7 - 0x7C200000, // 0020 CALL R8 0 - 0x8824110E, // 0021 GETMBR R9 R8 K14 - 0x8824130D, // 0022 GETMBR R9 R9 K13 - 0x90121A09, // 0023 SETMBR R4 K13 R9 - 0x8824110E, // 0024 GETMBR R9 R8 K14 - 0x8824130F, // 0025 GETMBR R9 R9 K15 - 0x90121E09, // 0026 SETMBR R4 K15 R9 - 0x8824110E, // 0027 GETMBR R9 R8 K14 - 0x88241310, // 0028 GETMBR R9 R9 K16 - 0x90122009, // 0029 SETMBR R4 K16 R9 - 0xB8260A00, // 002A GETNGBL R9 K5 - 0x88241312, // 002B GETMBR R9 R9 K18 - 0x90122209, // 002C SETMBR R4 K17 R9 - 0xB8260A00, // 002D GETNGBL R9 K5 - 0x8C241313, // 002E GETMET R9 R9 K19 - 0x882C090F, // 002F GETMBR R11 R4 K15 - 0x88300910, // 0030 GETMBR R12 R4 K16 - 0x7C240600, // 0031 CALL R9 3 - 0x4C280000, // 0032 LDNIL R10 - 0x1C28120A, // 0033 EQ R10 R9 R10 - 0x782A0005, // 0034 JMPF R10 #003B - 0x8C280714, // 0035 GETMET R10 R3 K20 - 0x58300015, // 0036 LDCONST R12 K21 - 0x8834090F, // 0037 GETMBR R13 R4 K15 - 0x88380910, // 0038 GETMBR R14 R4 K16 - 0x7C280800, // 0039 CALL R10 4 - 0x5C241400, // 003A MOVE R9 R10 - 0xB82A0200, // 003B GETNGBL R10 K1 - 0x8C281502, // 003C GETMET R10 R10 K2 - 0x8C300714, // 003D GETMET R12 R3 K20 - 0x58380016, // 003E LDCONST R14 K22 - 0x5C3C1200, // 003F MOVE R15 R9 - 0x88400317, // 0040 GETMBR R16 R1 K23 - 0x88440318, // 0041 GETMBR R17 R1 K24 - 0x7C300A00, // 0042 CALL R12 5 - 0x58340019, // 0043 LDCONST R13 K25 - 0x7C280600, // 0044 CALL R10 3 - 0x8828011A, // 0045 GETMBR R10 R0 K26 - 0x8828151B, // 0046 GETMBR R10 R10 K27 - 0x8C28151C, // 0047 GETMET R10 R10 K28 - 0x5C300200, // 0048 MOVE R12 R1 - 0x8834111D, // 0049 GETMBR R13 R8 K29 - 0x5C380800, // 004A MOVE R14 R4 - 0x7C280800, // 004B CALL R10 4 - 0xB82E0A00, // 004C GETNGBL R11 K5 - 0x8C2C171E, // 004D GETMET R11 R11 K30 - 0x7C2C0200, // 004E CALL R11 1 - 0x4C300000, // 004F LDNIL R12 - 0x2030140C, // 0050 NE R12 R10 R12 - 0x78320032, // 0051 JMPF R12 #0085 - 0xB8320A00, // 0052 GETNGBL R12 K5 - 0x8C30191F, // 0053 GETMET R12 R12 K31 - 0x7C300200, // 0054 CALL R12 1 - 0x902E200C, // 0055 SETMBR R11 K16 R12 - 0x88301710, // 0056 GETMBR R12 R11 K16 - 0xB8360A00, // 0057 GETNGBL R13 K5 - 0x8C341B20, // 0058 GETMET R13 R13 K32 - 0x7C340200, // 0059 CALL R13 1 - 0x90321C0D, // 005A SETMBR R12 K14 R13 - 0x88301710, // 005B GETMBR R12 R11 K16 - 0x8830190E, // 005C GETMBR R12 R12 K14 - 0x8834090D, // 005D GETMBR R13 R4 K13 - 0x90321A0D, // 005E SETMBR R12 K13 R13 - 0x88301710, // 005F GETMBR R12 R11 K16 - 0x8830190E, // 0060 GETMBR R12 R12 K14 - 0x8834090F, // 0061 GETMBR R13 R4 K15 - 0x90321E0D, // 0062 SETMBR R12 K15 R13 - 0x88301710, // 0063 GETMBR R12 R11 K16 - 0x8830190E, // 0064 GETMBR R12 R12 K14 - 0x88340910, // 0065 GETMBR R13 R4 K16 - 0x9032200D, // 0066 SETMBR R12 K16 R13 - 0x88301710, // 0067 GETMBR R12 R11 K16 - 0x90323A0A, // 0068 SETMBR R12 K29 R10 - 0x88300D0C, // 0069 GETMBR R12 R6 K12 - 0x8C301921, // 006A GETMET R12 R12 K33 - 0x5C381600, // 006B MOVE R14 R11 - 0x7C300400, // 006C CALL R12 2 - 0xB8320A00, // 006D GETNGBL R12 K5 - 0x8C301913, // 006E GETMET R12 R12 K19 - 0x8838090F, // 006F GETMBR R14 R4 K15 - 0x883C0910, // 0070 GETMBR R15 R4 K16 - 0x7C300600, // 0071 CALL R12 3 - 0x5C241800, // 0072 MOVE R9 R12 - 0x4C300000, // 0073 LDNIL R12 - 0x1C30120C, // 0074 EQ R12 R9 R12 - 0x78320005, // 0075 JMPF R12 #007C - 0x8C300714, // 0076 GETMET R12 R3 K20 - 0x58380022, // 0077 LDCONST R14 K34 - 0x883C090F, // 0078 GETMBR R15 R4 K15 - 0x88400910, // 0079 GETMBR R16 R4 K16 - 0x7C300800, // 007A CALL R12 4 - 0x5C241800, // 007B MOVE R9 R12 - 0xB8320200, // 007C GETNGBL R12 K1 - 0x8C301902, // 007D GETMET R12 R12 K2 - 0x8C380714, // 007E GETMET R14 R3 K20 - 0x58400023, // 007F LDCONST R16 K35 - 0x5C441200, // 0080 MOVE R17 R9 - 0x7C380600, // 0081 CALL R14 3 - 0x583C0019, // 0082 LDCONST R15 K25 - 0x7C300600, // 0083 CALL R12 3 - 0x70020026, // 0084 JMP #00AC - 0x88300911, // 0085 GETMBR R12 R4 K17 - 0x4C340000, // 0086 LDNIL R13 - 0x2030180D, // 0087 NE R12 R12 R13 - 0x78320022, // 0088 JMPF R12 #00AC - 0xB8320A00, // 0089 GETNGBL R12 K5 - 0x8C301924, // 008A GETMET R12 R12 K36 - 0x7C300200, // 008B CALL R12 1 - 0x902E220C, // 008C SETMBR R11 K17 R12 - 0x88301711, // 008D GETMBR R12 R11 K17 - 0xB8360A00, // 008E GETNGBL R13 K5 - 0x8C341B20, // 008F GETMET R13 R13 K32 - 0x7C340200, // 0090 CALL R13 1 - 0x90321C0D, // 0091 SETMBR R12 K14 R13 - 0x88301711, // 0092 GETMBR R12 R11 K17 - 0x8830190E, // 0093 GETMBR R12 R12 K14 - 0x8834090D, // 0094 GETMBR R13 R4 K13 - 0x90321A0D, // 0095 SETMBR R12 K13 R13 - 0x88301711, // 0096 GETMBR R12 R11 K17 - 0x8830190E, // 0097 GETMBR R12 R12 K14 - 0x8834090F, // 0098 GETMBR R13 R4 K15 - 0x90321E0D, // 0099 SETMBR R12 K15 R13 - 0x88301711, // 009A GETMBR R12 R11 K17 - 0x8830190E, // 009B GETMBR R12 R12 K14 - 0x88340910, // 009C GETMBR R13 R4 K16 - 0x9032200D, // 009D SETMBR R12 K16 R13 - 0x88301711, // 009E GETMBR R12 R11 K17 - 0xB8360A00, // 009F GETNGBL R13 K5 - 0x8C341B25, // 00A0 GETMET R13 R13 K37 - 0x7C340200, // 00A1 CALL R13 1 - 0x9032220D, // 00A2 SETMBR R12 K17 R13 - 0x88301711, // 00A3 GETMBR R12 R11 K17 - 0x88301911, // 00A4 GETMBR R12 R12 K17 - 0x88340911, // 00A5 GETMBR R13 R4 K17 - 0x9032220D, // 00A6 SETMBR R12 K17 R13 - 0x88300D0C, // 00A7 GETMBR R12 R6 K12 - 0x8C301921, // 00A8 GETMET R12 R12 K33 - 0x5C381600, // 00A9 MOVE R14 R11 - 0x7C300400, // 00AA CALL R12 2 - 0x7001FFFF, // 00AB JMP #00AC - 0x7001FF71, // 00AC JMP #001F - 0x581C0026, // 00AD LDCONST R7 K38 - 0xAC1C0200, // 00AE CATCH R7 1 0 - 0xB0080000, // 00AF RAISE 2 R0 R0 - 0xB81E0200, // 00B0 GETNGBL R7 K1 - 0x8C1C0F02, // 00B1 GETMET R7 R7 K2 - 0x60240008, // 00B2 GETGBL R9 G8 - 0x88280D0C, // 00B3 GETMBR R10 R6 K12 - 0x7C240200, // 00B4 CALL R9 1 - 0x00264E09, // 00B5 ADD R9 K39 R9 - 0x58280004, // 00B6 LDCONST R10 K4 - 0x7C1C0600, // 00B7 CALL R7 3 - 0x601C000C, // 00B8 GETGBL R7 G12 - 0x88200D0C, // 00B9 GETMBR R8 R6 K12 - 0x7C1C0200, // 00BA CALL R7 1 - 0x241C0F28, // 00BB GT R7 R7 K40 - 0x781E0024, // 00BC JMPF R7 #00E2 - 0xB81E0200, // 00BD GETNGBL R7 K1 - 0x8C1C0F02, // 00BE GETMET R7 R7 K2 - 0x60240008, // 00BF GETGBL R9 G8 - 0x5C280C00, // 00C0 MOVE R10 R6 - 0x7C240200, // 00C1 CALL R9 1 - 0x00265209, // 00C2 ADD R9 K41 R9 - 0x58280004, // 00C3 LDCONST R10 K4 - 0x7C1C0600, // 00C4 CALL R7 3 - 0xB81E0200, // 00C5 GETNGBL R7 K1 - 0x8C1C0F02, // 00C6 GETMET R7 R7 K2 - 0x60240008, // 00C7 GETGBL R9 G8 - 0x8C280D2B, // 00C8 GETMET R10 R6 K43 - 0x7C280200, // 00C9 CALL R10 1 - 0x7C240200, // 00CA CALL R9 1 - 0x00265409, // 00CB ADD R9 K42 R9 - 0x58280004, // 00CC LDCONST R10 K4 - 0x7C1C0600, // 00CD CALL R7 3 - 0x8C1C032C, // 00CE GETMET R7 R1 K44 - 0x54260008, // 00CF LDINT R9 9 - 0x50280200, // 00D0 LDBOOL R10 1 0 - 0x7C1C0600, // 00D1 CALL R7 3 - 0x8C200F2D, // 00D2 GETMET R8 R7 K45 - 0x8C280D2B, // 00D3 GETMET R10 R6 K43 - 0x7C280200, // 00D4 CALL R10 1 - 0x8C28152D, // 00D5 GETMET R10 R10 K45 - 0x7C280200, // 00D6 CALL R10 1 - 0x7C200400, // 00D7 CALL R8 2 - 0x8C200F2E, // 00D8 GETMET R8 R7 K46 - 0x7C200200, // 00D9 CALL R8 1 - 0x8820011A, // 00DA GETMBR R8 R0 K26 - 0x8C20112F, // 00DB GETMET R8 R8 K47 - 0x88280F30, // 00DC GETMBR R10 R7 K48 - 0x882C0317, // 00DD GETMBR R11 R1 K23 - 0x88300318, // 00DE GETMBR R12 R1 K24 - 0x88340F31, // 00DF GETMBR R13 R7 K49 - 0x7C200A00, // 00E0 CALL R8 5 - 0x7002000E, // 00E1 JMP #00F1 - 0x881C0332, // 00E2 GETMBR R7 R1 K50 - 0x781E000C, // 00E3 JMPF R7 #00F1 - 0x8C1C0333, // 00E4 GETMET R7 R1 K51 - 0x7C1C0200, // 00E5 CALL R7 1 - 0x8C200F2D, // 00E6 GETMET R8 R7 K45 - 0x7C200200, // 00E7 CALL R8 1 - 0x8C200F2E, // 00E8 GETMET R8 R7 K46 - 0x7C200200, // 00E9 CALL R8 1 - 0x8820011A, // 00EA GETMBR R8 R0 K26 - 0x8C20112F, // 00EB GETMET R8 R8 K47 - 0x88280F30, // 00EC GETMBR R10 R7 K48 - 0x882C0317, // 00ED GETMBR R11 R1 K23 - 0x88300318, // 00EE GETMBR R12 R1 K24 - 0x88340F31, // 00EF GETMBR R13 R7 K49 - 0x7C200A00, // 00F0 CALL R8 5 - 0x80000000, // 00F1 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: init ********************************************************************/ be_local_closure(Matter_IM_init, /* name */ be_nested_proto( - 3, /* 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_weak(responder), - /* K1 */ be_nested_str_weak(device), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -extern const bclass be_class_Matter_Attr_Report; - -/******************************************************************** -** Solidified class: Matter_Attr_Report -********************************************************************/ -be_local_class(Matter_Attr_Report, - 3, - NULL, - be_nested_map(3, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ret, 1), be_const_var(0) }, - { be_const_key_weak(expiration, 2), be_const_var(2) }, - { be_const_key_weak(resp, -1), be_const_var(1) }, - })), - be_str_weak(Matter_Attr_Report) -); - -/******************************************************************** -** Solidified function: send_attr_report -********************************************************************/ -be_local_closure(Matter_IM_send_attr_report, /* 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[23]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Attr_Report), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(attribute_reports), - /* K3 */ be_nested_str_weak(to_TLV), - /* K4 */ be_nested_str_weak(encode), - /* K5 */ be_const_int(1), - /* K6 */ be_nested_str_weak(MAX_MESSAGE), - /* K7 */ be_const_int(2147483647), - /* K8 */ be_nested_str_weak(more_chunked_messages), - /* K9 */ be_nested_str_weak(build_response), - /* K10 */ be_nested_str_weak(encrypt), - /* K11 */ be_nested_str_weak(responder), - /* K12 */ be_nested_str_weak(send_response), - /* K13 */ be_nested_str_weak(raw), - /* K14 */ be_nested_str_weak(remote_ip), - /* K15 */ be_nested_str_weak(remote_port), - /* K16 */ be_nested_str_weak(message_counter), - /* K17 */ be_nested_str_weak(ret), - /* K18 */ be_nested_str_weak(resp), - /* K19 */ be_nested_str_weak(expiration), - /* K20 */ be_nested_str_weak(tasmota), - /* K21 */ be_nested_str_weak(millis), - /* K22 */ be_nested_str_weak(MSG_TIMEOUT), - }), - be_str_weak(send_attr_report), - &be_const_str_solidified, - ( &(const binstruction[93]) { /* code */ - 0x580C0000, // 0000 LDCONST R3 K0 - 0xB4000000, // 0001 CLASS K0 - 0x58100001, // 0002 LDCONST R4 K1 - 0x58140001, // 0003 LDCONST R5 K1 - 0x6018000C, // 0004 GETGBL R6 G12 - 0x881C0502, // 0005 GETMBR R7 R2 K2 - 0x7C180200, // 0006 CALL R6 1 - 0x24180D01, // 0007 GT R6 R6 K1 - 0x781A0009, // 0008 JMPF R6 #0013 - 0x6018000C, // 0009 GETGBL R6 G12 - 0x881C0502, // 000A GETMBR R7 R2 K2 - 0x941C0F01, // 000B GETIDX R7 R7 K1 - 0x8C1C0F03, // 000C GETMET R7 R7 K3 - 0x7C1C0200, // 000D CALL R7 1 - 0x8C1C0F04, // 000E GETMET R7 R7 K4 - 0x7C1C0200, // 000F CALL R7 1 - 0x7C180200, // 0010 CALL R6 1 - 0x5C100C00, // 0011 MOVE R4 R6 - 0x58140005, // 0012 LDCONST R5 K5 - 0x88180106, // 0013 GETMBR R6 R0 K6 - 0x14180806, // 0014 LT R6 R4 R6 - 0x781A0013, // 0015 JMPF R6 #002A - 0x6018000C, // 0016 GETGBL R6 G12 - 0x881C0502, // 0017 GETMBR R7 R2 K2 - 0x7C180200, // 0018 CALL R6 1 - 0x14180A06, // 0019 LT R6 R5 R6 - 0x781A000E, // 001A JMPF R6 #002A - 0x6018000C, // 001B GETGBL R6 G12 - 0x881C0502, // 001C GETMBR R7 R2 K2 - 0x941C0E05, // 001D GETIDX R7 R7 R5 - 0x8C1C0F03, // 001E GETMET R7 R7 K3 - 0x7C1C0200, // 001F CALL R7 1 - 0x8C1C0F04, // 0020 GETMET R7 R7 K4 - 0x7C1C0200, // 0021 CALL R7 1 - 0x7C180200, // 0022 CALL R6 1 - 0x001C0806, // 0023 ADD R7 R4 R6 - 0x88200106, // 0024 GETMBR R8 R0 K6 - 0x141C0E08, // 0025 LT R7 R7 R8 - 0x781E0001, // 0026 JMPF R7 #0029 - 0x00100806, // 0027 ADD R4 R4 R6 - 0x00140B05, // 0028 ADD R5 R5 K5 - 0x7001FFE8, // 0029 JMP #0013 - 0x40180B07, // 002A CONNECT R6 R5 K7 - 0x881C0502, // 002B GETMBR R7 R2 K2 - 0x94180E06, // 002C GETIDX R6 R7 R6 - 0x04200B05, // 002D SUB R8 R5 K5 - 0x40220208, // 002E CONNECT R8 K1 R8 - 0x88240502, // 002F GETMBR R9 R2 K2 - 0x94201208, // 0030 GETIDX R8 R9 R8 - 0x900A0408, // 0031 SETMBR R2 K2 R8 - 0x6020000C, // 0032 GETGBL R8 G12 - 0x5C240C00, // 0033 MOVE R9 R6 - 0x7C200200, // 0034 CALL R8 1 - 0x24201101, // 0035 GT R8 R8 K1 - 0x78220001, // 0036 JMPF R8 #0039 - 0x50200200, // 0037 LDBOOL R8 1 0 - 0x900A1008, // 0038 SETMBR R2 K8 R8 - 0x8C1C0309, // 0039 GETMET R7 R1 K9 - 0x54260004, // 003A LDINT R9 5 - 0x50280200, // 003B LDBOOL R10 1 0 - 0x7C1C0600, // 003C CALL R7 3 - 0x8C200F04, // 003D GETMET R8 R7 K4 - 0x8C280503, // 003E GETMET R10 R2 K3 - 0x7C280200, // 003F CALL R10 1 - 0x8C281504, // 0040 GETMET R10 R10 K4 - 0x7C280200, // 0041 CALL R10 1 - 0x7C200400, // 0042 CALL R8 2 - 0x8C200F0A, // 0043 GETMET R8 R7 K10 - 0x7C200200, // 0044 CALL R8 1 - 0x8820010B, // 0045 GETMBR R8 R0 K11 - 0x8C20110C, // 0046 GETMET R8 R8 K12 - 0x88280F0D, // 0047 GETMBR R10 R7 K13 - 0x882C030E, // 0048 GETMBR R11 R1 K14 - 0x8830030F, // 0049 GETMBR R12 R1 K15 - 0x88340F10, // 004A GETMBR R13 R7 K16 - 0x7C200A00, // 004B CALL R8 5 - 0x6020000C, // 004C GETGBL R8 G12 - 0x5C240C00, // 004D MOVE R9 R6 - 0x7C200200, // 004E CALL R8 1 - 0x24201101, // 004F GT R8 R8 K1 - 0x7822000A, // 0050 JMPF R8 #005C - 0x900A0406, // 0051 SETMBR R2 K2 R6 - 0x5C200600, // 0052 MOVE R8 R3 - 0x7C200000, // 0053 CALL R8 0 - 0x90222202, // 0054 SETMBR R8 K17 R2 - 0x90222407, // 0055 SETMBR R8 K18 R7 - 0xB8262800, // 0056 GETNGBL R9 K20 - 0x8C241315, // 0057 GETMET R9 R9 K21 - 0x7C240200, // 0058 CALL R9 1 - 0x88280116, // 0059 GETMBR R10 R0 K22 - 0x0024120A, // 005A ADD R9 R9 R10 - 0x90222609, // 005B SETMBR R8 K19 R9 - 0x80000000, // 005C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_response -********************************************************************/ -be_local_closure(Matter_IM_subscribe_response, /* 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(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(SubscribeResponseMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeResponsetMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(subscribe_response), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x8C100902, // 0002 GETMET R4 R4 K2 - 0x7C100200, // 0003 CALL R4 1 - 0x8C100903, // 0004 GETMET R4 R4 K3 - 0x5C180400, // 0005 MOVE R6 R2 - 0x7C100400, // 0006 CALL R4 2 - 0xB8160800, // 0007 GETNGBL R5 K4 - 0x8C140B05, // 0008 GETMET R5 R5 K5 - 0x601C0008, // 0009 GETGBL R7 G8 - 0x5C200800, // 000A MOVE R8 R4 - 0x7C1C0200, // 000B CALL R7 1 - 0x001E0C07, // 000C ADD R7 K6 R7 - 0x58200007, // 000D LDCONST R8 K7 - 0x7C140600, // 000E CALL R5 3 - 0x50140000, // 000F LDBOOL R5 0 0 - 0x80040A00, // 0010 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_request -********************************************************************/ -be_local_closure(Matter_IM_subscribe_request, /* 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(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(SubscribeRequestMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20SubscribeRequestMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(subscribe_request), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x8C100902, // 0002 GETMET R4 R4 K2 - 0x7C100200, // 0003 CALL R4 1 - 0x8C100903, // 0004 GETMET R4 R4 K3 - 0x5C180400, // 0005 MOVE R6 R2 - 0x7C100400, // 0006 CALL R4 2 - 0xB8160800, // 0007 GETNGBL R5 K4 - 0x8C140B05, // 0008 GETMET R5 R5 K5 - 0x601C0008, // 0009 GETGBL R7 G8 - 0x5C200800, // 000A MOVE R8 R4 - 0x7C1C0200, // 000B CALL R7 1 - 0x001E0C07, // 000C ADD R7 K6 R7 - 0x58200007, // 000D LDCONST R8 K7 - 0x7C140600, // 000E CALL R5 3 - 0x50140000, // 000F LDBOOL R5 0 0 - 0x80040A00, // 0010 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_write_response -********************************************************************/ -be_local_closure(Matter_IM_process_write_response, /* 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(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(WriteResponseMessage), - /* K3 */ be_nested_str_weak(from_TLV), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(log), - /* K6 */ be_nested_str_weak(MTR_X3A_X20received_X20WriteResponseMessage_X3D), - /* K7 */ be_const_int(3), - }), - be_str_weak(process_write_response), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x8C100902, // 0002 GETMET R4 R4 K2 - 0x7C100200, // 0003 CALL R4 1 - 0x8C100903, // 0004 GETMET R4 R4 K3 - 0x5C180400, // 0005 MOVE R6 R2 - 0x7C100400, // 0006 CALL R4 2 - 0xB8160800, // 0007 GETNGBL R5 K4 - 0x8C140B05, // 0008 GETMET R5 R5 K5 - 0x601C0008, // 0009 GETGBL R7 G8 - 0x5C200800, // 000A MOVE R8 R4 - 0x7C1C0200, // 000B CALL R7 1 - 0x001E0C07, // 000C ADD R7 K6 R7 - 0x58200007, // 000D LDCONST R8 K7 - 0x7C140600, // 000E CALL R5 3 - 0x50140000, // 000F LDBOOL R5 0 0 - 0x80040A00, // 0010 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_incoming -********************************************************************/ -be_local_closure(Matter_IM_process_incoming, /* name */ - be_nested_proto( - 9, /* nstack */ + 5, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1526,166 +2542,103 @@ be_local_closure(Matter_IM_process_incoming, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[27]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20received_X20IM_X20message_X20), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(send_queue), + /* K2 */ be_nested_str_weak(subs_shop), /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(inspect), - /* K5 */ be_const_int(3), - /* K6 */ be_nested_str_weak(TLV), - /* K7 */ be_nested_str_weak(parse), - /* K8 */ be_nested_str_weak(raw), - /* K9 */ be_nested_str_weak(app_payload_idx), - /* K10 */ be_nested_str_weak(MTR_X3A_X20IM_X20TLV_X3A_X20), - /* K11 */ be_nested_str_weak(findsubval), - /* K12 */ be_nested_str_weak(MTR_X3A_X20InteractionModelRevision_X3D), - /* K13 */ be_nested_str_weak(nil), - /* K14 */ be_nested_str_weak(opcode), - /* K15 */ be_const_int(1), - /* K16 */ be_nested_str_weak(process_status_response), - /* K17 */ be_const_int(2), - /* K18 */ be_nested_str_weak(process_read_request), - /* K19 */ be_nested_str_weak(subscribe_request), - /* K20 */ be_nested_str_weak(subscribe_response), - /* K21 */ be_nested_str_weak(report_data), - /* K22 */ be_nested_str_weak(process_write_request), - /* K23 */ be_nested_str_weak(process_write_response), - /* K24 */ be_nested_str_weak(process_invoke_request), - /* K25 */ be_nested_str_weak(process_invoke_response), - /* K26 */ be_nested_str_weak(process_timed_request), + /* K4 */ be_nested_str_weak(IM_Subscription_Shop), }), - be_str_weak(process_incoming), + be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[128]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0xB8120600, // 0002 GETNGBL R4 K3 - 0x8C100904, // 0003 GETMET R4 R4 K4 - 0x5C180200, // 0004 MOVE R6 R1 - 0x7C100400, // 0005 CALL R4 2 - 0x00120404, // 0006 ADD R4 K2 R4 - 0x58140005, // 0007 LDCONST R5 K5 - 0x7C080600, // 0008 CALL R2 3 - 0xB80A0600, // 0009 GETNGBL R2 K3 - 0x88080506, // 000A GETMBR R2 R2 K6 - 0x8C080507, // 000B GETMET R2 R2 K7 - 0x88100308, // 000C GETMBR R4 R1 K8 - 0x88140309, // 000D GETMBR R5 R1 K9 - 0x7C080600, // 000E CALL R2 3 - 0xB80E0000, // 000F GETNGBL R3 K0 - 0x8C0C0701, // 0010 GETMET R3 R3 K1 - 0x60140008, // 0011 GETGBL R5 G8 - 0x5C180400, // 0012 MOVE R6 R2 - 0x7C140200, // 0013 CALL R5 1 - 0x00161405, // 0014 ADD R5 K10 R5 - 0x58180005, // 0015 LDCONST R6 K5 - 0x7C0C0600, // 0016 CALL R3 3 - 0x8C0C050B, // 0017 GETMET R3 R2 K11 - 0x541600FE, // 0018 LDINT R5 255 - 0x7C0C0400, // 0019 CALL R3 2 - 0xB8120000, // 001A GETNGBL R4 K0 - 0x8C100901, // 001B GETMET R4 R4 K1 - 0x4C180000, // 001C LDNIL R6 - 0x20180606, // 001D NE R6 R3 R6 - 0x781A0003, // 001E JMPF R6 #0023 - 0x60180008, // 001F GETGBL R6 G8 - 0x5C1C0600, // 0020 MOVE R7 R3 - 0x7C180200, // 0021 CALL R6 1 - 0x70020000, // 0022 JMP #0024 - 0x5818000D, // 0023 LDCONST R6 K13 - 0x001A1806, // 0024 ADD R6 K12 R6 - 0x581C0005, // 0025 LDCONST R7 K5 - 0x7C100600, // 0026 CALL R4 3 - 0x8810030E, // 0027 GETMBR R4 R1 K14 - 0x1C14090F, // 0028 EQ R5 R4 K15 - 0x78160005, // 0029 JMPF R5 #0030 - 0x8C140110, // 002A GETMET R5 R0 K16 - 0x5C1C0200, // 002B MOVE R7 R1 - 0x5C200400, // 002C MOVE R8 R2 - 0x7C140600, // 002D CALL R5 3 - 0x80040A00, // 002E RET 1 R5 - 0x7002004D, // 002F JMP #007E - 0x1C140911, // 0030 EQ R5 R4 K17 - 0x78160005, // 0031 JMPF R5 #0038 - 0x8C140112, // 0032 GETMET R5 R0 K18 - 0x5C1C0200, // 0033 MOVE R7 R1 - 0x5C200400, // 0034 MOVE R8 R2 - 0x7C140600, // 0035 CALL R5 3 - 0x80040A00, // 0036 RET 1 R5 - 0x70020045, // 0037 JMP #007E - 0x1C140905, // 0038 EQ R5 R4 K5 - 0x78160005, // 0039 JMPF R5 #0040 - 0x8C140113, // 003A GETMET R5 R0 K19 - 0x5C1C0200, // 003B MOVE R7 R1 - 0x5C200400, // 003C MOVE R8 R2 - 0x7C140600, // 003D CALL R5 3 - 0x80040A00, // 003E RET 1 R5 - 0x7002003D, // 003F JMP #007E - 0x54160003, // 0040 LDINT R5 4 - 0x1C140805, // 0041 EQ R5 R4 R5 - 0x78160005, // 0042 JMPF R5 #0049 - 0x8C140114, // 0043 GETMET R5 R0 K20 - 0x5C1C0200, // 0044 MOVE R7 R1 - 0x5C200400, // 0045 MOVE R8 R2 - 0x7C140600, // 0046 CALL R5 3 - 0x80040A00, // 0047 RET 1 R5 - 0x70020034, // 0048 JMP #007E - 0x54160004, // 0049 LDINT R5 5 - 0x1C140805, // 004A EQ R5 R4 R5 - 0x78160005, // 004B JMPF R5 #0052 - 0x8C140115, // 004C GETMET R5 R0 K21 - 0x5C1C0200, // 004D MOVE R7 R1 - 0x5C200400, // 004E MOVE R8 R2 - 0x7C140600, // 004F CALL R5 3 - 0x80040A00, // 0050 RET 1 R5 - 0x7002002B, // 0051 JMP #007E - 0x54160005, // 0052 LDINT R5 6 - 0x1C140805, // 0053 EQ R5 R4 R5 - 0x78160005, // 0054 JMPF R5 #005B - 0x8C140116, // 0055 GETMET R5 R0 K22 - 0x5C1C0200, // 0056 MOVE R7 R1 - 0x5C200400, // 0057 MOVE R8 R2 - 0x7C140600, // 0058 CALL R5 3 - 0x80040A00, // 0059 RET 1 R5 - 0x70020022, // 005A JMP #007E - 0x54160006, // 005B LDINT R5 7 - 0x1C140805, // 005C EQ R5 R4 R5 - 0x78160005, // 005D JMPF R5 #0064 - 0x8C140117, // 005E GETMET R5 R0 K23 - 0x5C1C0200, // 005F MOVE R7 R1 - 0x5C200400, // 0060 MOVE R8 R2 - 0x7C140600, // 0061 CALL R5 3 - 0x80040A00, // 0062 RET 1 R5 - 0x70020019, // 0063 JMP #007E - 0x54160007, // 0064 LDINT R5 8 - 0x1C140805, // 0065 EQ R5 R4 R5 - 0x78160005, // 0066 JMPF R5 #006D - 0x8C140118, // 0067 GETMET R5 R0 K24 - 0x5C1C0200, // 0068 MOVE R7 R1 - 0x5C200400, // 0069 MOVE R8 R2 - 0x7C140600, // 006A CALL R5 3 - 0x80040A00, // 006B RET 1 R5 - 0x70020010, // 006C JMP #007E - 0x54160008, // 006D LDINT R5 9 - 0x1C140805, // 006E EQ R5 R4 R5 - 0x78160005, // 006F JMPF R5 #0076 - 0x8C140119, // 0070 GETMET R5 R0 K25 - 0x5C1C0200, // 0071 MOVE R7 R1 - 0x5C200400, // 0072 MOVE R8 R2 - 0x7C140600, // 0073 CALL R5 3 - 0x80040A00, // 0074 RET 1 R5 - 0x70020007, // 0075 JMP #007E - 0x54160009, // 0076 LDINT R5 10 - 0x1C140805, // 0077 EQ R5 R4 R5 - 0x78160004, // 0078 JMPF R5 #007E - 0x8C14011A, // 0079 GETMET R5 R0 K26 - 0x5C1C0200, // 007A MOVE R7 R1 - 0x5C200400, // 007B MOVE R8 R2 - 0x7C140600, // 007C CALL R5 3 - 0x80040A00, // 007D RET 1 R5 - 0x50140000, // 007E LDBOOL R5 0 0 - 0x80040A00, // 007F RET 1 R5 + ( &(const binstruction[10]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x60080012, // 0001 GETGBL R2 G18 + 0x7C080000, // 0002 CALL R2 0 + 0x90020202, // 0003 SETMBR R0 K1 R2 + 0xB80A0600, // 0004 GETNGBL R2 K3 + 0x8C080504, // 0005 GETMET R2 R2 K4 + 0x5C100000, // 0006 MOVE R4 R0 + 0x7C080400, // 0007 CALL R2 2 + 0x90020402, // 0008 SETMBR R0 K2 R2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_subscribe_heartbeat +********************************************************************/ +be_local_closure(Matter_IM_send_subscribe_heartbeat, /* 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(string), + /* K1 */ be_nested_str_weak(session), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(format), + /* K5 */ be_nested_str_weak(MTR_X3A_X20_X3CSub_Alive_X20_X28_X256i_X29_X20sub_X3D_X25i), + /* K6 */ be_nested_str_weak(local_session_id), + /* K7 */ be_nested_str_weak(subscription_id), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(is_keep_alive), + /* K10 */ be_nested_str_weak(matter), + /* K11 */ be_nested_str_weak(ReportDataMessage), + /* K12 */ be_nested_str_weak(suppress_response), + /* K13 */ be_nested_str_weak(IM_SubscribedHeartbeat), + /* K14 */ be_nested_str_weak(_message_handler), + /* K15 */ be_nested_str_weak(send_queue), + /* K16 */ be_nested_str_weak(push), + /* K17 */ be_nested_str_weak(send_enqueued), + }), + be_str_weak(send_subscribe_heartbeat), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0xB8120400, // 0002 GETNGBL R4 K2 + 0x8C100903, // 0003 GETMET R4 R4 K3 + 0x8C180504, // 0004 GETMET R6 R2 K4 + 0x58200005, // 0005 LDCONST R8 K5 + 0x88240706, // 0006 GETMBR R9 R3 K6 + 0x88280307, // 0007 GETMBR R10 R1 K7 + 0x7C180800, // 0008 CALL R6 4 + 0x581C0008, // 0009 LDCONST R7 K8 + 0x7C100600, // 000A CALL R4 3 + 0x50100200, // 000B LDBOOL R4 1 0 + 0x90061204, // 000C SETMBR R1 K9 R4 + 0xB8121400, // 000D GETNGBL R4 K10 + 0x8C10090B, // 000E GETMET R4 R4 K11 + 0x7C100200, // 000F CALL R4 1 + 0x50140200, // 0010 LDBOOL R5 1 0 + 0x90121805, // 0011 SETMBR R4 K12 R5 + 0x88140307, // 0012 GETMBR R5 R1 K7 + 0x90120E05, // 0013 SETMBR R4 K7 R5 + 0xB8161400, // 0014 GETNGBL R5 K10 + 0x8C140B0D, // 0015 GETMET R5 R5 K13 + 0x881C070E, // 0016 GETMBR R7 R3 K14 + 0x5C200600, // 0017 MOVE R8 R3 + 0x5C240800, // 0018 MOVE R9 R4 + 0x5C280200, // 0019 MOVE R10 R1 + 0x7C140A00, // 001A CALL R5 5 + 0x8818010F, // 001B GETMBR R6 R0 K15 + 0x8C180D10, // 001C GETMET R6 R6 K16 + 0x5C200A00, // 001D MOVE R8 R5 + 0x7C180400, // 001E CALL R6 2 + 0x8C180111, // 001F GETMET R6 R0 K17 + 0x8820070E, // 0020 GETMBR R8 R3 K14 + 0x7C180400, // 0021 CALL R6 2 + 0x80000000, // 0022 RET 0 }) ) ); @@ -1696,28 +2649,41 @@ be_local_closure(Matter_IM_process_incoming, /* name */ ** Solidified class: Matter_IM ********************************************************************/ be_local_class(Matter_IM, - 2, + 3, NULL, - be_nested_map(18, + be_nested_map(31, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(process_timed_request, 14), be_const_closure(Matter_IM_process_timed_request_closure) }, - { be_const_key_weak(responder, -1), be_const_var(0) }, - { be_const_key_weak(process_read_request, -1), be_const_closure(Matter_IM_process_read_request_closure) }, - { be_const_key_weak(every_second, 2), be_const_closure(Matter_IM_every_second_closure) }, - { be_const_key_weak(report_data, -1), be_const_closure(Matter_IM_report_data_closure) }, - { be_const_key_weak(process_invoke_response, -1), be_const_closure(Matter_IM_process_invoke_response_closure) }, - { be_const_key_weak(process_write_response, -1), be_const_closure(Matter_IM_process_write_response_closure) }, - { be_const_key_weak(device, -1), be_const_var(1) }, - { be_const_key_weak(subscribe_request, -1), be_const_closure(Matter_IM_subscribe_request_closure) }, + { be_const_key_weak(send_subscribe_heartbeat, -1), be_const_closure(Matter_IM_send_subscribe_heartbeat_closure) }, + { be_const_key_weak(subs_shop, 23), be_const_var(1) }, + { be_const_key_weak(send_queue, 30), be_const_var(2) }, { be_const_key_weak(process_invoke_request, -1), be_const_closure(Matter_IM_process_invoke_request_closure) }, - { be_const_key_weak(MAX_MESSAGE, -1), be_const_int(1200) }, - { be_const_key_weak(process_status_response, 10), be_const_closure(Matter_IM_process_status_response_closure) }, - { be_const_key_weak(send_attr_report, -1), be_const_closure(Matter_IM_send_attr_report_closure) }, - { be_const_key_weak(subscribe_response, 8), be_const_closure(Matter_IM_subscribe_response_closure) }, - { be_const_key_weak(process_write_request, -1), be_const_closure(Matter_IM_process_write_request_closure) }, - { be_const_key_weak(init, 7), be_const_closure(Matter_IM_init_closure) }, - { be_const_key_weak(MSG_TIMEOUT, 6), be_const_int(10000) }, + { be_const_key_weak(subscribe_request, -1), be_const_closure(Matter_IM_subscribe_request_closure) }, + { be_const_key_weak(process_write_request, 11), be_const_closure(Matter_IM_process_write_request_closure) }, + { be_const_key_weak(send_write_response, -1), be_const_closure(Matter_IM_send_write_response_closure) }, + { be_const_key_weak(remove_sendqueue_by_exchangeid, -1), be_const_closure(Matter_IM_remove_sendqueue_by_exchangeid_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_IM_every_second_closure) }, + { be_const_key_weak(send_ack_now, -1), be_const_closure(Matter_IM_send_ack_now_closure) }, + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_IM_every_250ms_closure) }, + { be_const_key_weak(send_invoke_response, -1), be_const_closure(Matter_IM_send_invoke_response_closure) }, + { be_const_key_weak(process_invoke_response, 21), be_const_closure(Matter_IM_process_invoke_response_closure) }, + { be_const_key_weak(_inner_process_read_request, -1), be_const_closure(Matter_IM__inner_process_read_request_closure) }, + { be_const_key_weak(subscribe_response, 22), be_const_closure(Matter_IM_subscribe_response_closure) }, { be_const_key_weak(process_incoming, -1), be_const_closure(Matter_IM_process_incoming_closure) }, + { be_const_key_weak(send_subscribe_response, 18), be_const_closure(Matter_IM_send_subscribe_response_closure) }, + { be_const_key_weak(find_sendqueue_by_exchangeid, -1), be_const_closure(Matter_IM_find_sendqueue_by_exchangeid_closure) }, + { be_const_key_weak(process_incoming_ack, 13), be_const_closure(Matter_IM_process_incoming_ack_closure) }, + { be_const_key_weak(process_read_request, -1), be_const_closure(Matter_IM_process_read_request_closure) }, + { be_const_key_weak(send_report_data, -1), be_const_closure(Matter_IM_send_report_data_closure) }, + { be_const_key_weak(process_timed_request, -1), be_const_closure(Matter_IM_process_timed_request_closure) }, + { be_const_key_weak(process_status_response, -1), be_const_closure(Matter_IM_process_status_response_closure) }, + { be_const_key_weak(send_subscribe_update, 28), be_const_closure(Matter_IM_send_subscribe_update_closure) }, + { be_const_key_weak(send_enqueued, -1), be_const_closure(Matter_IM_send_enqueued_closure) }, + { be_const_key_weak(process_write_response, 12), be_const_closure(Matter_IM_process_write_response_closure) }, + { be_const_key_weak(report_data, 0), be_const_closure(Matter_IM_report_data_closure) }, + { be_const_key_weak(device, -1), be_const_var(0) }, + { be_const_key_weak(send_status, -1), be_const_closure(Matter_IM_send_status_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_init_closure) }, + { be_const_key_weak(expire_sendqueue, -1), be_const_closure(Matter_IM_expire_sendqueue_closure) }, })), be_str_weak(Matter_IM) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h index 738b9ec91..aecff66c6 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Data.h @@ -3026,7 +3026,7 @@ be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */ /* K4 */ be_const_int(1), /* K5 */ be_nested_str_weak(max_interval_ceiling), /* K6 */ be_const_int(2), - /* K7 */ be_nested_str_weak(attribute_requests), + /* K7 */ be_nested_str_weak(attributes_requests), /* K8 */ be_nested_str_weak(from_TLV_array), /* K9 */ be_const_int(3), /* K10 */ be_nested_str_weak(matter), @@ -3041,7 +3041,7 @@ be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */ }), be_str_weak(from_TLV), &be_const_str_solidified, - ( &(const binstruction[54]) { /* code */ + ( &(const binstruction[58]) { /* code */ 0x4C080000, // 0000 LDNIL R2 0x1C080202, // 0001 EQ R2 R1 R2 0x780A0001, // 0002 JMPF R2 #0005 @@ -3049,53 +3049,57 @@ be_local_closure(Matter_SubscribeRequestMessage_from_TLV, /* name */ 0x80040400, // 0004 RET 1 R2 0x8C080301, // 0005 GETMET R2 R1 K1 0x58100002, // 0006 LDCONST R4 K2 - 0x7C080400, // 0007 CALL R2 2 - 0x90020002, // 0008 SETMBR R0 K0 R2 - 0x8C080301, // 0009 GETMET R2 R1 K1 - 0x58100004, // 000A LDCONST R4 K4 - 0x7C080400, // 000B CALL R2 2 - 0x90020602, // 000C SETMBR R0 K3 R2 - 0x8C080301, // 000D GETMET R2 R1 K1 - 0x58100006, // 000E LDCONST R4 K6 - 0x7C080400, // 000F CALL R2 2 - 0x90020A02, // 0010 SETMBR R0 K5 R2 - 0x8C080108, // 0011 GETMET R2 R0 K8 - 0x8C100301, // 0012 GETMET R4 R1 K1 - 0x58180009, // 0013 LDCONST R6 K9 - 0x7C100400, // 0014 CALL R4 2 - 0xB8161400, // 0015 GETNGBL R5 K10 - 0x88140B0B, // 0016 GETMBR R5 R5 K11 - 0x7C080600, // 0017 CALL R2 3 - 0x90020E02, // 0018 SETMBR R0 K7 R2 - 0x8C080108, // 0019 GETMET R2 R0 K8 - 0x8C100301, // 001A GETMET R4 R1 K1 - 0x541A0003, // 001B LDINT R6 4 - 0x7C100400, // 001C CALL R4 2 - 0xB8161400, // 001D GETNGBL R5 K10 - 0x88140B0D, // 001E GETMBR R5 R5 K13 - 0x7C080600, // 001F CALL R2 3 - 0x90021802, // 0020 SETMBR R0 K12 R2 - 0x8C080108, // 0021 GETMET R2 R0 K8 - 0x8C100301, // 0022 GETMET R4 R1 K1 - 0x541A0004, // 0023 LDINT R6 5 - 0x7C100400, // 0024 CALL R4 2 - 0xB8161400, // 0025 GETNGBL R5 K10 - 0x88140B0F, // 0026 GETMBR R5 R5 K15 - 0x7C080600, // 0027 CALL R2 3 - 0x90021C02, // 0028 SETMBR R0 K14 R2 - 0x8C080301, // 0029 GETMET R2 R1 K1 - 0x54120006, // 002A LDINT R4 7 - 0x7C080400, // 002B CALL R2 2 - 0x90022002, // 002C SETMBR R0 K16 R2 - 0x8C080108, // 002D GETMET R2 R0 K8 - 0x8C100301, // 002E GETMET R4 R1 K1 - 0x541A0007, // 002F LDINT R6 8 - 0x7C100400, // 0030 CALL R4 2 - 0xB8161400, // 0031 GETNGBL R5 K10 - 0x88140B12, // 0032 GETMBR R5 R5 K18 - 0x7C080600, // 0033 CALL R2 3 - 0x90022202, // 0034 SETMBR R0 K17 R2 - 0x80040000, // 0035 RET 1 R0 + 0x50140000, // 0007 LDBOOL R5 0 0 + 0x7C080600, // 0008 CALL R2 3 + 0x90020002, // 0009 SETMBR R0 K0 R2 + 0x8C080301, // 000A GETMET R2 R1 K1 + 0x58100004, // 000B LDCONST R4 K4 + 0x58140002, // 000C LDCONST R5 K2 + 0x7C080600, // 000D CALL R2 3 + 0x90020602, // 000E SETMBR R0 K3 R2 + 0x8C080301, // 000F GETMET R2 R1 K1 + 0x58100006, // 0010 LDCONST R4 K6 + 0x5416003B, // 0011 LDINT R5 60 + 0x7C080600, // 0012 CALL R2 3 + 0x90020A02, // 0013 SETMBR R0 K5 R2 + 0x8C080108, // 0014 GETMET R2 R0 K8 + 0x8C100301, // 0015 GETMET R4 R1 K1 + 0x58180009, // 0016 LDCONST R6 K9 + 0x7C100400, // 0017 CALL R4 2 + 0xB8161400, // 0018 GETNGBL R5 K10 + 0x88140B0B, // 0019 GETMBR R5 R5 K11 + 0x7C080600, // 001A CALL R2 3 + 0x90020E02, // 001B SETMBR R0 K7 R2 + 0x8C080108, // 001C GETMET R2 R0 K8 + 0x8C100301, // 001D GETMET R4 R1 K1 + 0x541A0003, // 001E LDINT R6 4 + 0x7C100400, // 001F CALL R4 2 + 0xB8161400, // 0020 GETNGBL R5 K10 + 0x88140B0D, // 0021 GETMBR R5 R5 K13 + 0x7C080600, // 0022 CALL R2 3 + 0x90021802, // 0023 SETMBR R0 K12 R2 + 0x8C080108, // 0024 GETMET R2 R0 K8 + 0x8C100301, // 0025 GETMET R4 R1 K1 + 0x541A0004, // 0026 LDINT R6 5 + 0x7C100400, // 0027 CALL R4 2 + 0xB8161400, // 0028 GETNGBL R5 K10 + 0x88140B0F, // 0029 GETMBR R5 R5 K15 + 0x7C080600, // 002A CALL R2 3 + 0x90021C02, // 002B SETMBR R0 K14 R2 + 0x8C080301, // 002C GETMET R2 R1 K1 + 0x54120006, // 002D LDINT R4 7 + 0x50140000, // 002E LDBOOL R5 0 0 + 0x7C080600, // 002F CALL R2 3 + 0x90022002, // 0030 SETMBR R0 K16 R2 + 0x8C080108, // 0031 GETMET R2 R0 K8 + 0x8C100301, // 0032 GETMET R4 R1 K1 + 0x541A0007, // 0033 LDINT R6 8 + 0x7C100400, // 0034 CALL R4 2 + 0xB8161400, // 0035 GETNGBL R5 K10 + 0x88140B12, // 0036 GETMBR R5 R5 K18 + 0x7C080600, // 0037 CALL R2 3 + 0x90022202, // 0038 SETMBR R0 K17 R2 + 0x80040000, // 0039 RET 1 R0 }) ) ); @@ -3130,7 +3134,7 @@ be_local_closure(Matter_SubscribeRequestMessage_to_TLV, /* name */ /* K11 */ be_nested_str_weak(max_interval_ceiling), /* K12 */ be_nested_str_weak(to_TLV_array), /* K13 */ be_const_int(3), - /* K14 */ be_nested_str_weak(attribute_requests), + /* K14 */ be_nested_str_weak(attributes_requests), /* K15 */ be_nested_str_weak(event_requests), /* K16 */ be_nested_str_weak(event_filters), /* K17 */ be_nested_str_weak(fabric_filtered), @@ -3207,13 +3211,13 @@ be_local_class(Matter_SubscribeRequestMessage, be_nested_map(10, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_SubscribeRequestMessage_to_TLV_closure) }, - { be_const_key_weak(event_filters, -1), be_const_var(5) }, - { be_const_key_weak(event_requests, 6), be_const_var(4) }, + { be_const_key_weak(attributes_requests, 7), be_const_var(3) }, + { be_const_key_weak(fabric_filtered, 6), be_const_var(6) }, { be_const_key_weak(min_interval_floor, -1), be_const_var(1) }, { be_const_key_weak(data_version_filters, -1), be_const_var(7) }, { be_const_key_weak(max_interval_ceiling, -1), be_const_var(2) }, - { be_const_key_weak(attribute_requests, 7), be_const_var(3) }, - { be_const_key_weak(fabric_filtered, 3), be_const_var(6) }, + { be_const_key_weak(event_requests, 3), be_const_var(4) }, + { be_const_key_weak(event_filters, -1), be_const_var(5) }, { be_const_key_weak(from_TLV, -1), be_const_closure(Matter_SubscribeRequestMessage_from_TLV_closure) }, { be_const_key_weak(keep_subscriptions, 0), be_const_var(0) }, })), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h new file mode 100644 index 000000000..023811a39 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Message.h @@ -0,0 +1,1942 @@ +/* Solidification of Matter_IM_Message.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_IM_Message; + +/******************************************************************** +** Solidified function: status_error_received +********************************************************************/ +be_local_closure(Matter_IM_Message_status_error_received, /* 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(status_error_received), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_im +********************************************************************/ +be_local_closure(Matter_IM_Message_send_im, /* 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[24]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_Message_X20send_im_X20exch_X3D_X25i_X20ready_X3D_X25i), + /* K5 */ be_nested_str_weak(resp), + /* K6 */ be_nested_str_weak(exchange_id), + /* K7 */ be_nested_str_weak(ready), + /* K8 */ be_const_int(1), + /* K9 */ be_const_int(0), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(encode_frame), + /* K12 */ be_nested_str_weak(data), + /* K13 */ be_nested_str_weak(to_TLV), + /* K14 */ be_nested_str_weak(tlv2raw), + /* K15 */ be_nested_str_weak(encrypt), + /* K16 */ be_nested_str_weak(MTR_X3A_X20_X3Csnd_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20id_X3D_X25i_X20exch_X3D_X25i_X20rack_X3D_X25s), + /* K17 */ be_nested_str_weak(session), + /* K18 */ be_nested_str_weak(local_session_id), + /* K19 */ be_nested_str_weak(message_counter), + /* K20 */ be_nested_str_weak(ack_message_counter), + /* K21 */ be_nested_str_weak(send_response_frame), + /* K22 */ be_nested_str_weak(last_counter), + /* K23 */ be_nested_str_weak(finish), + }), + be_str_weak(send_im), + &be_const_str_solidified, + ( &(const binstruction[49]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x78260001, // 0008 JMPF R9 #000B + 0x58240008, // 0009 LDCONST R9 K8 + 0x70020000, // 000A JMP #000C + 0x58240009, // 000B LDCONST R9 K9 + 0x7C140800, // 000C CALL R5 4 + 0x5818000A, // 000D LDCONST R6 K10 + 0x7C0C0600, // 000E CALL R3 3 + 0x880C0107, // 000F GETMBR R3 R0 K7 + 0x740E0001, // 0010 JMPT R3 #0013 + 0x500C0000, // 0011 LDBOOL R3 0 0 + 0x80040600, // 0012 RET 1 R3 + 0x880C0105, // 0013 GETMBR R3 R0 K5 + 0x8C10070B, // 0014 GETMET R4 R3 K11 + 0x8818010C, // 0015 GETMBR R6 R0 K12 + 0x8C180D0D, // 0016 GETMET R6 R6 K13 + 0x7C180200, // 0017 CALL R6 1 + 0x8C180D0E, // 0018 GETMET R6 R6 K14 + 0x7C180200, // 0019 CALL R6 1 + 0x7C100400, // 001A CALL R4 2 + 0x8C10070F, // 001B GETMET R4 R3 K15 + 0x7C100200, // 001C CALL R4 1 + 0xB8120200, // 001D GETNGBL R4 K1 + 0x8C100902, // 001E GETMET R4 R4 K2 + 0x8C180503, // 001F GETMET R6 R2 K3 + 0x58200010, // 0020 LDCONST R8 K16 + 0x88240711, // 0021 GETMBR R9 R3 K17 + 0x88241312, // 0022 GETMBR R9 R9 K18 + 0x88280713, // 0023 GETMBR R10 R3 K19 + 0x882C0706, // 0024 GETMBR R11 R3 K6 + 0x88300714, // 0025 GETMBR R12 R3 K20 + 0x7C180C00, // 0026 CALL R6 6 + 0x581C000A, // 0027 LDCONST R7 K10 + 0x7C100600, // 0028 CALL R4 3 + 0x8C100315, // 0029 GETMET R4 R1 K21 + 0x5C180600, // 002A MOVE R6 R3 + 0x7C100400, // 002B CALL R4 2 + 0x88100713, // 002C GETMBR R4 R3 K19 + 0x90022C04, // 002D SETMBR R0 K22 R4 + 0x50100200, // 002E LDBOOL R4 1 0 + 0x90022E04, // 002F SETMBR R0 K23 R4 + 0x80000000, // 0030 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_exchangeid +********************************************************************/ +be_local_closure(Matter_IM_Message_get_exchangeid, /* 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(resp), + /* K1 */ be_nested_str_weak(exchange_id), + }), + be_str_weak(get_exchangeid), + &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(Matter_IM_Message_init, /* name */ + be_nested_proto( + 8, /* nstack */ + 4, /* 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(resp), + /* K1 */ be_nested_str_weak(build_response), + /* K2 */ be_nested_str_weak(ready), + /* K3 */ be_nested_str_weak(expiration), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(millis), + /* K6 */ be_nested_str_weak(MSG_TIMEOUT), + /* K7 */ be_nested_str_weak(last_counter), + /* K8 */ be_const_int(0), + /* K9 */ be_nested_str_weak(finish), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x8C100301, // 0000 GETMET R4 R1 K1 + 0x5C180400, // 0001 MOVE R6 R2 + 0x5C1C0600, // 0002 MOVE R7 R3 + 0x7C100600, // 0003 CALL R4 3 + 0x90020004, // 0004 SETMBR R0 K0 R4 + 0x50100200, // 0005 LDBOOL R4 1 0 + 0x90020404, // 0006 SETMBR R0 K2 R4 + 0xB8120800, // 0007 GETNGBL R4 K4 + 0x8C100905, // 0008 GETMET R4 R4 K5 + 0x7C100200, // 0009 CALL R4 1 + 0x88140106, // 000A GETMBR R5 R0 K6 + 0x00100805, // 000B ADD R4 R4 R5 + 0x90020604, // 000C SETMBR R0 K3 R4 + 0x90020F08, // 000D SETMBR R0 K7 K8 + 0x50100000, // 000E LDBOOL R4 0 0 + 0x90021204, // 000F SETMBR R0 K9 R4 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: ack_received +********************************************************************/ +be_local_closure(Matter_IM_Message_ack_received, /* 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(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20IM_Message_X20ack_received_X20exch_X3D), + /* K3 */ be_nested_str_weak(resp), + /* K4 */ be_nested_str_weak(exchange_id), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str_weak(expiration), + /* K7 */ be_nested_str_weak(millis), + /* K8 */ be_nested_str_weak(MSG_TIMEOUT), + }), + be_str_weak(ack_received), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x60100008, // 0002 GETGBL R4 G8 + 0x88140103, // 0003 GETMBR R5 R0 K3 + 0x88140B04, // 0004 GETMBR R5 R5 K4 + 0x7C100200, // 0005 CALL R4 1 + 0x00120404, // 0006 ADD R4 K2 R4 + 0x58140005, // 0007 LDCONST R5 K5 + 0x7C080600, // 0008 CALL R2 3 + 0xB80A0000, // 0009 GETNGBL R2 K0 + 0x8C080507, // 000A GETMET R2 R2 K7 + 0x7C080200, // 000B CALL R2 1 + 0x880C0108, // 000C GETMBR R3 R0 K8 + 0x00080403, // 000D ADD R2 R2 R3 + 0x90020C02, // 000E SETMBR R0 K6 R2 + 0x50080000, // 000F LDBOOL R2 0 0 + 0x80040400, // 0010 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: reached_timeout +********************************************************************/ +be_local_closure(Matter_IM_Message_reached_timeout, /* 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(reached_timeout), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: status_ok_received +********************************************************************/ +be_local_closure(Matter_IM_Message_status_ok_received, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_Message_X20status_ok_received_X20exch_X3D_X25i), + /* K5 */ be_nested_str_weak(resp), + /* K6 */ be_nested_str_weak(exchange_id), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(expiration), + /* K9 */ be_nested_str_weak(millis), + /* K10 */ be_nested_str_weak(MSG_TIMEOUT), + /* K11 */ be_nested_str_weak(build_response), + /* K12 */ be_nested_str_weak(opcode), + /* K13 */ be_nested_str_weak(x_flag_r), + /* K14 */ be_nested_str_weak(ready), + }), + be_str_weak(status_ok_received), + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x7C140600, // 0007 CALL R5 3 + 0x58180007, // 0008 LDCONST R6 K7 + 0x7C0C0600, // 0009 CALL R3 3 + 0xB80E0200, // 000A GETNGBL R3 K1 + 0x8C0C0709, // 000B GETMET R3 R3 K9 + 0x7C0C0200, // 000C CALL R3 1 + 0x8810010A, // 000D GETMBR R4 R0 K10 + 0x000C0604, // 000E ADD R3 R3 R4 + 0x90021003, // 000F SETMBR R0 K8 R3 + 0x78060007, // 0010 JMPF R1 #0019 + 0x8C0C030B, // 0011 GETMET R3 R1 K11 + 0x88140105, // 0012 GETMBR R5 R0 K5 + 0x88140B0C, // 0013 GETMBR R5 R5 K12 + 0x88180105, // 0014 GETMBR R6 R0 K5 + 0x88180D0D, // 0015 GETMBR R6 R6 K13 + 0x881C0105, // 0016 GETMBR R7 R0 K5 + 0x7C0C0800, // 0017 CALL R3 4 + 0x90020A03, // 0018 SETMBR R0 K5 R3 + 0x500C0200, // 0019 LDBOOL R3 1 0 + 0x90021C03, // 001A SETMBR R0 K14 R3 + 0x500C0200, // 001B LDBOOL R3 1 0 + 0x80040600, // 001C RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_Message +********************************************************************/ +be_local_class(Matter_IM_Message, + 6, + NULL, + be_nested_map(14, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(MSG_TIMEOUT, -1), be_const_int(5000) }, + { be_const_key_weak(data, -1), be_const_var(4) }, + { be_const_key_weak(send_im, -1), be_const_closure(Matter_IM_Message_send_im_closure) }, + { be_const_key_weak(status_ok_received, -1), be_const_closure(Matter_IM_Message_status_ok_received_closure) }, + { be_const_key_weak(get_exchangeid, 0), be_const_closure(Matter_IM_Message_get_exchangeid_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_Message_init_closure) }, + { be_const_key_weak(expiration, -1), be_const_var(0) }, + { be_const_key_weak(resp, -1), be_const_var(1) }, + { be_const_key_weak(finish, 13), be_const_var(3) }, + { be_const_key_weak(last_counter, 6), be_const_var(5) }, + { be_const_key_weak(ack_received, 9), be_const_closure(Matter_IM_Message_ack_received_closure) }, + { be_const_key_weak(reached_timeout, -1), be_const_closure(Matter_IM_Message_reached_timeout_closure) }, + { be_const_key_weak(status_error_received, 3), be_const_closure(Matter_IM_Message_status_error_received_closure) }, + { be_const_key_weak(ready, -1), be_const_var(2) }, + })), + be_str_weak(Matter_IM_Message) +); +/*******************************************************************/ + +void be_load_Matter_IM_Message_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_Message); + be_setglobal(vm, "Matter_IM_Message"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_Status; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_Status_init, /* 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[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_const_int(1), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(StatusResponseMessage), + /* K4 */ be_nested_str_weak(status), + /* K5 */ be_nested_str_weak(data), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x58180001, // 0005 LDCONST R6 K1 + 0x501C0200, // 0006 LDBOOL R7 1 0 + 0x7C0C0800, // 0007 CALL R3 4 + 0xB80E0400, // 0008 GETNGBL R3 K2 + 0x8C0C0703, // 0009 GETMET R3 R3 K3 + 0x7C0C0200, // 000A CALL R3 1 + 0x900E0802, // 000B SETMBR R3 K4 R2 + 0x90020A03, // 000C SETMBR R0 K5 R3 + 0x80000000, // 000D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_Status +********************************************************************/ +extern const bclass be_class_Matter_IM_Message; +be_local_class(Matter_IM_Status, + 0, + &be_class_Matter_IM_Message, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_Status_init_closure) }, + })), + be_str_weak(Matter_IM_Status) +); +/*******************************************************************/ + +void be_load_Matter_IM_Status_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_Status); + be_setglobal(vm, "Matter_IM_Status"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_InvokeResponse; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_InvokeResponse_init, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(data), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x541A0008, // 0005 LDINT R6 9 + 0x501C0200, // 0006 LDBOOL R7 1 0 + 0x7C0C0800, // 0007 CALL R3 4 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_InvokeResponse +********************************************************************/ +extern const bclass be_class_Matter_IM_Message; +be_local_class(Matter_IM_InvokeResponse, + 0, + &be_class_Matter_IM_Message, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_InvokeResponse_init_closure) }, + })), + be_str_weak(Matter_IM_InvokeResponse) +); +/*******************************************************************/ + +void be_load_Matter_IM_InvokeResponse_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_InvokeResponse); + be_setglobal(vm, "Matter_IM_InvokeResponse"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_WriteResponse; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_WriteResponse_init, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(data), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x541A0006, // 0005 LDINT R6 7 + 0x501C0200, // 0006 LDBOOL R7 1 0 + 0x7C0C0800, // 0007 CALL R3 4 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_WriteResponse +********************************************************************/ +extern const bclass be_class_Matter_IM_Message; +be_local_class(Matter_IM_WriteResponse, + 0, + &be_class_Matter_IM_Message, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_WriteResponse_init_closure) }, + })), + be_str_weak(Matter_IM_WriteResponse) +); +/*******************************************************************/ + +void be_load_Matter_IM_WriteResponse_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_WriteResponse); + be_setglobal(vm, "Matter_IM_WriteResponse"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_ReportData; + +/******************************************************************** +** Solidified function: send_im +********************************************************************/ +be_local_closure(Matter_IM_ReportData_send_im, /* name */ + be_nested_proto( + 21, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[34]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_ReportData_X20send_im_X20exch_X3D_X25i_X20ready_X3D_X25i), + /* K5 */ be_nested_str_weak(resp), + /* K6 */ be_nested_str_weak(exchange_id), + /* K7 */ be_nested_str_weak(ready), + /* K8 */ be_const_int(1), + /* K9 */ be_const_int(0), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(data), + /* K12 */ be_nested_str_weak(more_chunked_messages), + /* K13 */ be_nested_str_weak(attribute_reports), + /* K14 */ be_nested_str_weak(to_TLV), + /* K15 */ be_nested_str_weak(encode_len), + /* K16 */ be_nested_str_weak(MAX_MESSAGE), + /* K17 */ be_nested_str_weak(MTR_X3A_X20exch_X3D_X25i_X20elements_X3D_X25i_X20msg_sz_X3D_X25i_X20total_X3D_X25i), + /* K18 */ be_nested_str_weak(get_exchangeid), + /* K19 */ be_const_int(2147483647), + /* K20 */ be_nested_str_weak(MTR_X3A_X20_X2ERead_Attr_X20next_chunk_X20exch_X3D_X25i), + /* K21 */ be_nested_str_weak(MTR_X3A_X20_X2ERead_Attr_X20first_chunk_X20exch_X3D_X25i), + /* K22 */ be_nested_str_weak(tlv2raw), + /* K23 */ be_nested_str_weak(encode_frame), + /* K24 */ be_nested_str_weak(encrypt), + /* K25 */ be_nested_str_weak(MTR_X3A_X20_X3Csnd_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20id_X3D_X25i_X20exch_X3D_X25i_X20rack_X3D_X25s), + /* K26 */ be_nested_str_weak(session), + /* K27 */ be_nested_str_weak(local_session_id), + /* K28 */ be_nested_str_weak(message_counter), + /* K29 */ be_nested_str_weak(ack_message_counter), + /* K30 */ be_nested_str_weak(send_response_frame), + /* K31 */ be_nested_str_weak(last_counter), + /* K32 */ be_nested_str_weak(MTR_X3A_X20to_be_sent_later_X20size_X3D_X25i_X20exch_X3D_X25i), + /* K33 */ be_nested_str_weak(finish), + }), + be_str_weak(send_im), + &be_const_str_solidified, + ( &(const binstruction[173]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x78260001, // 0008 JMPF R9 #000B + 0x58240008, // 0009 LDCONST R9 K8 + 0x70020000, // 000A JMP #000C + 0x58240009, // 000B LDCONST R9 K9 + 0x7C140800, // 000C CALL R5 4 + 0x5818000A, // 000D LDCONST R6 K10 + 0x7C0C0600, // 000E CALL R3 3 + 0x880C0107, // 000F GETMBR R3 R0 K7 + 0x740E0001, // 0010 JMPT R3 #0013 + 0x500C0000, // 0011 LDBOOL R3 0 0 + 0x80040600, // 0012 RET 1 R3 + 0x880C0105, // 0013 GETMBR R3 R0 K5 + 0x8810010B, // 0014 GETMBR R4 R0 K11 + 0x8814090C, // 0015 GETMBR R5 R4 K12 + 0x58180009, // 0016 LDCONST R6 K9 + 0x581C0009, // 0017 LDCONST R7 K9 + 0x8820090D, // 0018 GETMBR R8 R4 K13 + 0x4C240000, // 0019 LDNIL R9 + 0x20201009, // 001A NE R8 R8 R9 + 0x78220003, // 001B JMPF R8 #0020 + 0x6020000C, // 001C GETGBL R8 G12 + 0x8824090D, // 001D GETMBR R9 R4 K13 + 0x7C200200, // 001E CALL R8 1 + 0x70020000, // 001F JMP #0021 + 0x58200009, // 0020 LDCONST R8 K9 + 0x24241109, // 0021 GT R9 R8 K9 + 0x78260007, // 0022 JMPF R9 #002B + 0x8824090D, // 0023 GETMBR R9 R4 K13 + 0x94241309, // 0024 GETIDX R9 R9 K9 + 0x8C24130E, // 0025 GETMET R9 R9 K14 + 0x7C240200, // 0026 CALL R9 1 + 0x8C24130F, // 0027 GETMET R9 R9 K15 + 0x7C240200, // 0028 CALL R9 1 + 0x5C181200, // 0029 MOVE R6 R9 + 0x581C0008, // 002A LDCONST R7 K8 + 0x88240110, // 002B GETMBR R9 R0 K16 + 0x14240C09, // 002C LT R9 R6 R9 + 0x78260010, // 002D JMPF R9 #003F + 0x14240E08, // 002E LT R9 R7 R8 + 0x7826000E, // 002F JMPF R9 #003F + 0x8824090D, // 0030 GETMBR R9 R4 K13 + 0x94241207, // 0031 GETIDX R9 R9 R7 + 0x8C24130E, // 0032 GETMET R9 R9 K14 + 0x7C240200, // 0033 CALL R9 1 + 0x8C24130F, // 0034 GETMET R9 R9 K15 + 0x7C240200, // 0035 CALL R9 1 + 0x00280C09, // 0036 ADD R10 R6 R9 + 0x882C0110, // 0037 GETMBR R11 R0 K16 + 0x1428140B, // 0038 LT R10 R10 R11 + 0x782A0002, // 0039 JMPF R10 #003D + 0x00180C09, // 003A ADD R6 R6 R9 + 0x001C0F08, // 003B ADD R7 R7 K8 + 0x70020000, // 003C JMP #003E + 0x70020000, // 003D JMP #003F + 0x7001FFEB, // 003E JMP #002B + 0xB8260200, // 003F GETNGBL R9 K1 + 0x8C241302, // 0040 GETMET R9 R9 K2 + 0x8C2C0503, // 0041 GETMET R11 R2 K3 + 0x58340011, // 0042 LDCONST R13 K17 + 0x8C380112, // 0043 GETMET R14 R0 K18 + 0x7C380200, // 0044 CALL R14 1 + 0x5C3C0E00, // 0045 MOVE R15 R7 + 0x5C400C00, // 0046 MOVE R16 R6 + 0x5C441000, // 0047 MOVE R17 R8 + 0x7C2C0C00, // 0048 CALL R11 6 + 0x5830000A, // 0049 LDCONST R12 K10 + 0x7C240600, // 004A CALL R9 3 + 0x60240012, // 004B GETGBL R9 G18 + 0x7C240000, // 004C CALL R9 0 + 0x8828090D, // 004D GETMBR R10 R4 K13 + 0x4C2C0000, // 004E LDNIL R11 + 0x2028140B, // 004F NE R10 R10 R11 + 0x782A000D, // 0050 JMPF R10 #005F + 0x40280F13, // 0051 CONNECT R10 R7 K19 + 0x882C090D, // 0052 GETMBR R11 R4 K13 + 0x9424160A, // 0053 GETIDX R9 R11 R10 + 0x04300F08, // 0054 SUB R12 R7 K8 + 0x4032120C, // 0055 CONNECT R12 K9 R12 + 0x8834090D, // 0056 GETMBR R13 R4 K13 + 0x94301A0C, // 0057 GETIDX R12 R13 R12 + 0x90121A0C, // 0058 SETMBR R4 K13 R12 + 0x6030000C, // 0059 GETGBL R12 G12 + 0x5C341200, // 005A MOVE R13 R9 + 0x7C300200, // 005B CALL R12 1 + 0x24301909, // 005C GT R12 R12 K9 + 0x9012180C, // 005D SETMBR R4 K12 R12 + 0x70020001, // 005E JMP #0061 + 0x50280000, // 005F LDBOOL R10 0 0 + 0x9012180A, // 0060 SETMBR R4 K12 R10 + 0x78160008, // 0061 JMPF R5 #006B + 0xB82A0200, // 0062 GETNGBL R10 K1 + 0x8C281502, // 0063 GETMET R10 R10 K2 + 0x8C300503, // 0064 GETMET R12 R2 K3 + 0x58380014, // 0065 LDCONST R14 K20 + 0x8C3C0112, // 0066 GETMET R15 R0 K18 + 0x7C3C0200, // 0067 CALL R15 1 + 0x7C300600, // 0068 CALL R12 3 + 0x5834000A, // 0069 LDCONST R13 K10 + 0x7C280600, // 006A CALL R10 3 + 0x8828090C, // 006B GETMBR R10 R4 K12 + 0x782A000A, // 006C JMPF R10 #0078 + 0x5C280A00, // 006D MOVE R10 R5 + 0x742A0008, // 006E JMPT R10 #0078 + 0xB82A0200, // 006F GETNGBL R10 K1 + 0x8C281502, // 0070 GETMET R10 R10 K2 + 0x8C300503, // 0071 GETMET R12 R2 K3 + 0x58380015, // 0072 LDCONST R14 K21 + 0x8C3C0112, // 0073 GETMET R15 R0 K18 + 0x7C3C0200, // 0074 CALL R15 1 + 0x7C300600, // 0075 CALL R12 3 + 0x5834000A, // 0076 LDCONST R13 K10 + 0x7C280600, // 0077 CALL R10 3 + 0x8828010B, // 0078 GETMBR R10 R0 K11 + 0x8C28150E, // 0079 GETMET R10 R10 K14 + 0x7C280200, // 007A CALL R10 1 + 0x8C2C1516, // 007B GETMET R11 R10 K22 + 0x60340015, // 007C GETGBL R13 G21 + 0x88380110, // 007D GETMBR R14 R0 K16 + 0x7C340200, // 007E CALL R13 1 + 0x7C2C0400, // 007F CALL R11 2 + 0x8C300717, // 0080 GETMET R12 R3 K23 + 0x5C381600, // 0081 MOVE R14 R11 + 0x7C300400, // 0082 CALL R12 2 + 0x8C300718, // 0083 GETMET R12 R3 K24 + 0x7C300200, // 0084 CALL R12 1 + 0xB8320200, // 0085 GETNGBL R12 K1 + 0x8C301902, // 0086 GETMET R12 R12 K2 + 0x8C380503, // 0087 GETMET R14 R2 K3 + 0x58400019, // 0088 LDCONST R16 K25 + 0x8844071A, // 0089 GETMBR R17 R3 K26 + 0x8844231B, // 008A GETMBR R17 R17 K27 + 0x8848071C, // 008B GETMBR R18 R3 K28 + 0x884C0706, // 008C GETMBR R19 R3 K6 + 0x8850071D, // 008D GETMBR R20 R3 K29 + 0x7C380C00, // 008E CALL R14 6 + 0x583C000A, // 008F LDCONST R15 K10 + 0x7C300600, // 0090 CALL R12 3 + 0x8C30031E, // 0091 GETMET R12 R1 K30 + 0x5C380600, // 0092 MOVE R14 R3 + 0x7C300400, // 0093 CALL R12 2 + 0x8830071C, // 0094 GETMBR R12 R3 K28 + 0x90023E0C, // 0095 SETMBR R0 K31 R12 + 0x6030000C, // 0096 GETGBL R12 G12 + 0x5C341200, // 0097 MOVE R13 R9 + 0x7C300200, // 0098 CALL R12 1 + 0x24301909, // 0099 GT R12 R12 K9 + 0x7832000E, // 009A JMPF R12 #00AA + 0x90121A09, // 009B SETMBR R4 K13 R9 + 0xB8320200, // 009C GETNGBL R12 K1 + 0x8C301902, // 009D GETMET R12 R12 K2 + 0x8C380503, // 009E GETMET R14 R2 K3 + 0x58400020, // 009F LDCONST R16 K32 + 0x6044000C, // 00A0 GETGBL R17 G12 + 0x8848090D, // 00A1 GETMBR R18 R4 K13 + 0x7C440200, // 00A2 CALL R17 1 + 0x88480706, // 00A3 GETMBR R18 R3 K6 + 0x7C380800, // 00A4 CALL R14 4 + 0x583C000A, // 00A5 LDCONST R15 K10 + 0x7C300600, // 00A6 CALL R12 3 + 0x50300000, // 00A7 LDBOOL R12 0 0 + 0x90020E0C, // 00A8 SETMBR R0 K7 R12 + 0x70020001, // 00A9 JMP #00AC + 0x50300200, // 00AA LDBOOL R12 1 0 + 0x9002420C, // 00AB SETMBR R0 K33 R12 + 0x80000000, // 00AC RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_ReportData_init, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(data), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x541A0004, // 0005 LDINT R6 5 + 0x501C0200, // 0006 LDBOOL R7 1 0 + 0x7C0C0800, // 0007 CALL R3 4 + 0x90020202, // 0008 SETMBR R0 K1 R2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_ReportData +********************************************************************/ +extern const bclass be_class_Matter_IM_Message; +be_local_class(Matter_IM_ReportData, + 0, + &be_class_Matter_IM_Message, + be_nested_map(3, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(send_im, 1), be_const_closure(Matter_IM_ReportData_send_im_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_ReportData_init_closure) }, + { be_const_key_weak(MAX_MESSAGE, -1), be_const_int(1200) }, + })), + be_str_weak(Matter_IM_ReportData) +); +/*******************************************************************/ + +void be_load_Matter_IM_ReportData_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_ReportData); + be_setglobal(vm, "Matter_IM_ReportData"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_ReportDataSubscribed; + +/******************************************************************** +** Solidified function: ack_received +********************************************************************/ +be_local_closure(Matter_IM_ReportDataSubscribed_ack_received, /* 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[12]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_ReportDataSubscribed_X20ack_received_X20sub_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(ack_received), + /* K9 */ be_nested_str_weak(report_data_phase), + /* K10 */ be_nested_str_weak(is_keep_alive), + /* K11 */ be_nested_str_weak(re_arm), + }), + be_str_weak(ack_received), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x7C140600, // 0007 CALL R5 3 + 0x58180007, // 0008 LDCONST R6 K7 + 0x7C0C0600, // 0009 CALL R3 3 + 0x600C0003, // 000A GETGBL R3 G3 + 0x5C100000, // 000B MOVE R4 R0 + 0x7C0C0200, // 000C CALL R3 1 + 0x8C0C0708, // 000D GETMET R3 R3 K8 + 0x5C140200, // 000E MOVE R5 R1 + 0x7C0C0400, // 000F CALL R3 2 + 0x880C0109, // 0010 GETMBR R3 R0 K9 + 0x740E0008, // 0011 JMPT R3 #001B + 0x880C0105, // 0012 GETMBR R3 R0 K5 + 0x880C070A, // 0013 GETMBR R3 R3 K10 + 0x780E0002, // 0014 JMPF R3 #0018 + 0x880C0105, // 0015 GETMBR R3 R0 K5 + 0x8C0C070B, // 0016 GETMET R3 R3 K11 + 0x7C0C0200, // 0017 CALL R3 1 + 0x500C0200, // 0018 LDBOOL R3 1 0 + 0x80040600, // 0019 RET 1 R3 + 0x70020001, // 001A JMP #001D + 0x500C0000, // 001B LDBOOL R3 0 0 + 0x80040600, // 001C RET 1 R3 + 0x80000000, // 001D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_im +********************************************************************/ +be_local_closure(Matter_IM_ReportDataSubscribed_send_im, /* 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[30]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_ReportDataSubscribed_X20send_X20sub_X3D_X25i_X20exch_X3D_X25i_X20ready_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_nested_str_weak(ready), + /* K10 */ be_const_int(1), + /* K11 */ be_const_int(0), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(MTR_X3A_X20ReportDataSubscribed_X3A_X3Asend_im_X20size_X28self_X2Edata_X2Eattribute_reports_X29_X3D_X25i_X20ready_X3D_X25s_X20report_data_phase_X3D_X25s), + /* K14 */ be_nested_str_weak(data), + /* K15 */ be_nested_str_weak(attribute_reports), + /* K16 */ be_nested_str_weak(report_data_phase), + /* K17 */ be_nested_str_weak(send_im), + /* K18 */ be_nested_str_weak(MTR_X3A_X20ReportDataSubscribed_X3A_X3Asend_im_X20called_X20super_X20finish_X3D_X25i), + /* K19 */ be_nested_str_weak(finish), + /* K20 */ be_nested_str_weak(build_standalone_ack), + /* K21 */ be_nested_str_weak(encode_frame), + /* K22 */ be_nested_str_weak(encrypt), + /* K23 */ be_nested_str_weak(MTR_X3A_X20_X3CAck_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20ack_X3D_X25i_X20id_X3D_X25i), + /* K24 */ be_nested_str_weak(session), + /* K25 */ be_nested_str_weak(local_session_id), + /* K26 */ be_nested_str_weak(ack_message_counter), + /* K27 */ be_nested_str_weak(message_counter), + /* K28 */ be_nested_str_weak(send_response_frame), + /* K29 */ be_nested_str_weak(last_counter), + }), + be_str_weak(send_im), + &be_const_str_solidified, + ( &(const binstruction[111]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x88280109, // 0009 GETMBR R10 R0 K9 + 0x782A0001, // 000A JMPF R10 #000D + 0x5828000A, // 000B LDCONST R10 K10 + 0x70020000, // 000C JMP #000E + 0x5828000B, // 000D LDCONST R10 K11 + 0x7C140A00, // 000E CALL R5 5 + 0x5818000C, // 000F LDCONST R6 K12 + 0x7C0C0600, // 0010 CALL R3 3 + 0xB80E0200, // 0011 GETNGBL R3 K1 + 0x8C0C0702, // 0012 GETMET R3 R3 K2 + 0x8C140503, // 0013 GETMET R5 R2 K3 + 0x581C000D, // 0014 LDCONST R7 K13 + 0x6020000C, // 0015 GETGBL R8 G12 + 0x8824010E, // 0016 GETMBR R9 R0 K14 + 0x8824130F, // 0017 GETMBR R9 R9 K15 + 0x7C200200, // 0018 CALL R8 1 + 0x60240008, // 0019 GETGBL R9 G8 + 0x88280109, // 001A GETMBR R10 R0 K9 + 0x7C240200, // 001B CALL R9 1 + 0x60280008, // 001C GETGBL R10 G8 + 0x882C0110, // 001D GETMBR R11 R0 K16 + 0x7C280200, // 001E CALL R10 1 + 0x7C140A00, // 001F CALL R5 5 + 0x5818000C, // 0020 LDCONST R6 K12 + 0x7C0C0600, // 0021 CALL R3 3 + 0x880C0109, // 0022 GETMBR R3 R0 K9 + 0x740E0001, // 0023 JMPT R3 #0026 + 0x500C0000, // 0024 LDBOOL R3 0 0 + 0x80040600, // 0025 RET 1 R3 + 0x600C000C, // 0026 GETGBL R3 G12 + 0x8810010E, // 0027 GETMBR R4 R0 K14 + 0x8810090F, // 0028 GETMBR R4 R4 K15 + 0x7C0C0200, // 0029 CALL R3 1 + 0x240C070B, // 002A GT R3 R3 K11 + 0x780E0034, // 002B JMPF R3 #0061 + 0x880C0110, // 002C GETMBR R3 R0 K16 + 0x780E0017, // 002D JMPF R3 #0046 + 0x600C0003, // 002E GETGBL R3 G3 + 0x5C100000, // 002F MOVE R4 R0 + 0x7C0C0200, // 0030 CALL R3 1 + 0x8C0C0711, // 0031 GETMET R3 R3 K17 + 0x5C140200, // 0032 MOVE R5 R1 + 0x7C0C0400, // 0033 CALL R3 2 + 0xB80E0200, // 0034 GETNGBL R3 K1 + 0x8C0C0702, // 0035 GETMET R3 R3 K2 + 0x8C140503, // 0036 GETMET R5 R2 K3 + 0x581C0012, // 0037 LDCONST R7 K18 + 0x88200113, // 0038 GETMBR R8 R0 K19 + 0x7C140600, // 0039 CALL R5 3 + 0x5818000C, // 003A LDCONST R6 K12 + 0x7C0C0600, // 003B CALL R3 3 + 0x880C0113, // 003C GETMBR R3 R0 K19 + 0x740E0000, // 003D JMPT R3 #003F + 0x80000600, // 003E RET 0 + 0x500C0000, // 003F LDBOOL R3 0 0 + 0x90022003, // 0040 SETMBR R0 K16 R3 + 0x500C0000, // 0041 LDBOOL R3 0 0 + 0x90021203, // 0042 SETMBR R0 K9 R3 + 0x500C0000, // 0043 LDBOOL R3 0 0 + 0x90022603, // 0044 SETMBR R0 K19 R3 + 0x70020019, // 0045 JMP #0060 + 0x880C0107, // 0046 GETMBR R3 R0 K7 + 0x8C0C0714, // 0047 GETMET R3 R3 K20 + 0x50140000, // 0048 LDBOOL R5 0 0 + 0x7C0C0400, // 0049 CALL R3 2 + 0x8C100715, // 004A GETMET R4 R3 K21 + 0x7C100200, // 004B CALL R4 1 + 0x8C100716, // 004C GETMET R4 R3 K22 + 0x7C100200, // 004D CALL R4 1 + 0xB8120200, // 004E GETNGBL R4 K1 + 0x8C100902, // 004F GETMET R4 R4 K2 + 0x8C180503, // 0050 GETMET R6 R2 K3 + 0x58200017, // 0051 LDCONST R8 K23 + 0x88240718, // 0052 GETMBR R9 R3 K24 + 0x88241319, // 0053 GETMBR R9 R9 K25 + 0x8828071A, // 0054 GETMBR R10 R3 K26 + 0x882C071B, // 0055 GETMBR R11 R3 K27 + 0x7C180A00, // 0056 CALL R6 5 + 0x581C000C, // 0057 LDCONST R7 K12 + 0x7C100600, // 0058 CALL R4 3 + 0x8C10031C, // 0059 GETMET R4 R1 K28 + 0x5C180600, // 005A MOVE R6 R3 + 0x7C100400, // 005B CALL R4 2 + 0x8810071B, // 005C GETMBR R4 R3 K27 + 0x90023A04, // 005D SETMBR R0 K29 R4 + 0x50100200, // 005E LDBOOL R4 1 0 + 0x90022604, // 005F SETMBR R0 K19 R4 + 0x7002000C, // 0060 JMP #006E + 0x880C0110, // 0061 GETMBR R3 R0 K16 + 0x780E0008, // 0062 JMPF R3 #006C + 0x600C0003, // 0063 GETGBL R3 G3 + 0x5C100000, // 0064 MOVE R4 R0 + 0x7C0C0200, // 0065 CALL R3 1 + 0x8C0C0711, // 0066 GETMET R3 R3 K17 + 0x5C140200, // 0067 MOVE R5 R1 + 0x7C0C0400, // 0068 CALL R3 2 + 0x500C0000, // 0069 LDBOOL R3 0 0 + 0x90022003, // 006A SETMBR R0 K16 R3 + 0x70020001, // 006B JMP #006E + 0x500C0200, // 006C LDBOOL R3 1 0 + 0x90022603, // 006D SETMBR R0 K19 R3 + 0x80000000, // 006E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_ReportDataSubscribed_init, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* 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(resp), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Frame), + /* K3 */ be_nested_str_weak(initiate_response), + /* K4 */ be_nested_str_weak(data), + /* K5 */ be_nested_str_weak(ready), + /* K6 */ be_nested_str_weak(expiration), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(millis), + /* K9 */ be_nested_str_weak(MSG_TIMEOUT), + /* K10 */ be_nested_str_weak(sub), + /* K11 */ be_nested_str_weak(report_data_phase), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0xB8160200, // 0000 GETNGBL R5 K1 + 0x88140B02, // 0001 GETMBR R5 R5 K2 + 0x8C140B03, // 0002 GETMET R5 R5 K3 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x54260004, // 0005 LDINT R9 5 + 0x50280200, // 0006 LDBOOL R10 1 0 + 0x7C140A00, // 0007 CALL R5 5 + 0x90020005, // 0008 SETMBR R0 K0 R5 + 0x90020803, // 0009 SETMBR R0 K4 R3 + 0x50140200, // 000A LDBOOL R5 1 0 + 0x90020A05, // 000B SETMBR R0 K5 R5 + 0xB8160E00, // 000C GETNGBL R5 K7 + 0x8C140B08, // 000D GETMET R5 R5 K8 + 0x7C140200, // 000E CALL R5 1 + 0x88180109, // 000F GETMBR R6 R0 K9 + 0x00140A06, // 0010 ADD R5 R5 R6 + 0x90020C05, // 0011 SETMBR R0 K6 R5 + 0x90021404, // 0012 SETMBR R0 K10 R4 + 0x50140200, // 0013 LDBOOL R5 1 0 + 0x90021605, // 0014 SETMBR R0 K11 R5 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: status_error_received +********************************************************************/ +be_local_closure(Matter_IM_ReportDataSubscribed_status_error_received, /* 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(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_ReportDataSubscribed_X20status_error_received_X20sub_X3D_X25i_X20exch_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(remove_self), + }), + be_str_weak(status_error_received), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x7C140800, // 0009 CALL R5 4 + 0x58180009, // 000A LDCONST R6 K9 + 0x7C0C0600, // 000B CALL R3 3 + 0x880C0105, // 000C GETMBR R3 R0 K5 + 0x8C0C070A, // 000D GETMET R3 R3 K10 + 0x7C0C0200, // 000E CALL R3 1 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: reached_timeout +********************************************************************/ +be_local_closure(Matter_IM_ReportDataSubscribed_reached_timeout, /* 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(sub), + /* K1 */ be_nested_str_weak(remove_self), + }), + be_str_weak(reached_timeout), + &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: status_ok_received +********************************************************************/ +be_local_closure(Matter_IM_ReportDataSubscribed_status_ok_received, /* 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[13]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_ReportDataSubscribed_X20status_ok_received_X20sub_X3D_X25i_X20exch_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(report_data_phase), + /* K11 */ be_nested_str_weak(status_ok_received), + /* K12 */ be_nested_str_weak(re_arm), + }), + be_str_weak(status_ok_received), + &be_const_str_solidified, + ( &(const binstruction[34]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x7C140800, // 0009 CALL R5 4 + 0x58180009, // 000A LDCONST R6 K9 + 0x7C0C0600, // 000B CALL R3 3 + 0x880C010A, // 000C GETMBR R3 R0 K10 + 0x780E0007, // 000D JMPF R3 #0016 + 0x600C0003, // 000E GETGBL R3 G3 + 0x5C100000, // 000F MOVE R4 R0 + 0x7C0C0200, // 0010 CALL R3 1 + 0x8C0C070B, // 0011 GETMET R3 R3 K11 + 0x5C140200, // 0012 MOVE R5 R1 + 0x7C0C0400, // 0013 CALL R3 2 + 0x80040600, // 0014 RET 1 R3 + 0x7002000A, // 0015 JMP #0021 + 0x880C0105, // 0016 GETMBR R3 R0 K5 + 0x8C0C070C, // 0017 GETMET R3 R3 K12 + 0x7C0C0200, // 0018 CALL R3 1 + 0x600C0003, // 0019 GETGBL R3 G3 + 0x5C100000, // 001A MOVE R4 R0 + 0x7C0C0200, // 001B CALL R3 1 + 0x8C0C070B, // 001C GETMET R3 R3 K11 + 0x4C140000, // 001D LDNIL R5 + 0x7C0C0400, // 001E CALL R3 2 + 0x500C0000, // 001F LDBOOL R3 0 0 + 0x80040600, // 0020 RET 1 R3 + 0x80000000, // 0021 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_ReportDataSubscribed +********************************************************************/ +extern const bclass be_class_Matter_IM_ReportData; +be_local_class(Matter_IM_ReportDataSubscribed, + 2, + &be_class_Matter_IM_ReportData, + be_nested_map(8, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(ack_received, 1), be_const_closure(Matter_IM_ReportDataSubscribed_ack_received_closure) }, + { be_const_key_weak(status_ok_received, -1), be_const_closure(Matter_IM_ReportDataSubscribed_status_ok_received_closure) }, + { be_const_key_weak(send_im, -1), be_const_closure(Matter_IM_ReportDataSubscribed_send_im_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_ReportDataSubscribed_init_closure) }, + { be_const_key_weak(report_data_phase, 7), be_const_var(1) }, + { be_const_key_weak(sub, 6), be_const_var(0) }, + { be_const_key_weak(reached_timeout, -1), be_const_closure(Matter_IM_ReportDataSubscribed_reached_timeout_closure) }, + { be_const_key_weak(status_error_received, -1), be_const_closure(Matter_IM_ReportDataSubscribed_status_error_received_closure) }, + })), + be_str_weak(Matter_IM_ReportDataSubscribed) +); +/*******************************************************************/ + +void be_load_Matter_IM_ReportDataSubscribed_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_ReportDataSubscribed); + be_setglobal(vm, "Matter_IM_ReportDataSubscribed"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_SubscribedHeartbeat; + +/******************************************************************** +** Solidified function: status_error_received +********************************************************************/ +be_local_closure(Matter_IM_SubscribedHeartbeat_status_error_received, /* 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(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20Matter_IM_SubscribedHeartbeat_X20status_error_received_X20sub_X3D_X25i_X20exch_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_const_int(3), + /* K10 */ be_nested_str_weak(remove_self), + }), + be_str_weak(status_error_received), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x7C140800, // 0009 CALL R5 4 + 0x58180009, // 000A LDCONST R6 K9 + 0x7C0C0600, // 000B CALL R3 3 + 0x880C0105, // 000C GETMBR R3 R0 K5 + 0x8C0C070A, // 000D GETMET R3 R3 K10 + 0x7C0C0200, // 000E CALL R3 1 + 0x500C0000, // 000F LDBOOL R3 0 0 + 0x80040600, // 0010 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_im +********************************************************************/ +be_local_closure(Matter_IM_SubscribedHeartbeat_send_im, /* 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[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20Matter_IM_SubscribedHeartbeat_X20send_X20sub_X3D_X25i_X20exch_X3D_X25i_X20ready_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_nested_str_weak(ready), + /* K10 */ be_const_int(1), + /* K11 */ be_const_int(0), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(send_im), + }), + be_str_weak(send_im), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x88280109, // 0009 GETMBR R10 R0 K9 + 0x782A0001, // 000A JMPF R10 #000D + 0x5828000A, // 000B LDCONST R10 K10 + 0x70020000, // 000C JMP #000E + 0x5828000B, // 000D LDCONST R10 K11 + 0x7C140A00, // 000E CALL R5 5 + 0x5818000C, // 000F LDCONST R6 K12 + 0x7C0C0600, // 0010 CALL R3 3 + 0x880C0109, // 0011 GETMBR R3 R0 K9 + 0x740E0001, // 0012 JMPT R3 #0015 + 0x500C0000, // 0013 LDBOOL R3 0 0 + 0x80040600, // 0014 RET 1 R3 + 0x600C0003, // 0015 GETGBL R3 G3 + 0x5C100000, // 0016 MOVE R4 R0 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C0C070D, // 0018 GETMET R3 R3 K13 + 0x5C140200, // 0019 MOVE R5 R1 + 0x7C0C0400, // 001A CALL R3 2 + 0x500C0000, // 001B LDBOOL R3 0 0 + 0x90021203, // 001C SETMBR R0 K9 R3 + 0x80000000, // 001D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: ack_received +********************************************************************/ +be_local_closure(Matter_IM_SubscribedHeartbeat_ack_received, /* 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[10]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20Matter_IM_SubscribedHeartbeat_X20ack_received_X20sub_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(ack_received), + /* K9 */ be_nested_str_weak(finish), + }), + be_str_weak(ack_received), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x7C140600, // 0007 CALL R5 3 + 0x58180007, // 0008 LDCONST R6 K7 + 0x7C0C0600, // 0009 CALL R3 3 + 0x600C0003, // 000A GETGBL R3 G3 + 0x5C100000, // 000B MOVE R4 R0 + 0x7C0C0200, // 000C CALL R3 1 + 0x8C0C0708, // 000D GETMET R3 R3 K8 + 0x5C140200, // 000E MOVE R5 R1 + 0x7C0C0400, // 000F CALL R3 2 + 0x500C0200, // 0010 LDBOOL R3 1 0 + 0x90021203, // 0011 SETMBR R0 K9 R3 + 0x500C0200, // 0012 LDBOOL R3 1 0 + 0x80040600, // 0013 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: reached_timeout +********************************************************************/ +be_local_closure(Matter_IM_SubscribedHeartbeat_reached_timeout, /* 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(sub), + /* K1 */ be_nested_str_weak(remove_self), + }), + be_str_weak(reached_timeout), + &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: status_ok_received +********************************************************************/ +be_local_closure(Matter_IM_SubscribedHeartbeat_status_ok_received, /* 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[10]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20Matter_IM_SubscribedHeartbeat_X20status_ok_received_X20sub_X3D_X25i_X20exch_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_const_int(3), + }), + be_str_weak(status_ok_received), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x7C140800, // 0009 CALL R5 4 + 0x58180009, // 000A LDCONST R6 K9 + 0x7C0C0600, // 000B CALL R3 3 + 0x500C0000, // 000C LDBOOL R3 0 0 + 0x80040600, // 000D RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_SubscribedHeartbeat_init, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* 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(resp), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Frame), + /* K3 */ be_nested_str_weak(initiate_response), + /* K4 */ be_nested_str_weak(data), + /* K5 */ be_nested_str_weak(ready), + /* K6 */ be_nested_str_weak(expiration), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(millis), + /* K9 */ be_nested_str_weak(MSG_TIMEOUT), + /* K10 */ be_nested_str_weak(sub), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xB8160200, // 0000 GETNGBL R5 K1 + 0x88140B02, // 0001 GETMBR R5 R5 K2 + 0x8C140B03, // 0002 GETMET R5 R5 K3 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x54260004, // 0005 LDINT R9 5 + 0x50280200, // 0006 LDBOOL R10 1 0 + 0x7C140A00, // 0007 CALL R5 5 + 0x90020005, // 0008 SETMBR R0 K0 R5 + 0x90020803, // 0009 SETMBR R0 K4 R3 + 0x50140200, // 000A LDBOOL R5 1 0 + 0x90020A05, // 000B SETMBR R0 K5 R5 + 0xB8160E00, // 000C GETNGBL R5 K7 + 0x8C140B08, // 000D GETMET R5 R5 K8 + 0x7C140200, // 000E CALL R5 1 + 0x88180109, // 000F GETMBR R6 R0 K9 + 0x00140A06, // 0010 ADD R5 R5 R6 + 0x90020C05, // 0011 SETMBR R0 K6 R5 + 0x90021404, // 0012 SETMBR R0 K10 R4 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_SubscribedHeartbeat +********************************************************************/ +extern const bclass be_class_Matter_IM_ReportData; +be_local_class(Matter_IM_SubscribedHeartbeat, + 1, + &be_class_Matter_IM_ReportData, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, 1), be_const_closure(Matter_IM_SubscribedHeartbeat_init_closure) }, + { be_const_key_weak(status_ok_received, -1), be_const_closure(Matter_IM_SubscribedHeartbeat_status_ok_received_closure) }, + { be_const_key_weak(sub, 6), be_const_var(0) }, + { be_const_key_weak(ack_received, -1), be_const_closure(Matter_IM_SubscribedHeartbeat_ack_received_closure) }, + { be_const_key_weak(reached_timeout, -1), be_const_closure(Matter_IM_SubscribedHeartbeat_reached_timeout_closure) }, + { be_const_key_weak(status_error_received, 0), be_const_closure(Matter_IM_SubscribedHeartbeat_status_error_received_closure) }, + { be_const_key_weak(send_im, -1), be_const_closure(Matter_IM_SubscribedHeartbeat_send_im_closure) }, + })), + be_str_weak(Matter_IM_SubscribedHeartbeat) +); +/*******************************************************************/ + +void be_load_Matter_IM_SubscribedHeartbeat_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_SubscribedHeartbeat); + be_setglobal(vm, "Matter_IM_SubscribedHeartbeat"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_SubscribeResponse; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_SubscribeResponse_init, /* name */ + be_nested_proto( + 8, /* 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(sub), + /* K2 */ be_nested_str_weak(report_data_phase), + }), + 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 + 0x7C100600, // 0006 CALL R4 3 + 0x90020203, // 0007 SETMBR R0 K1 R3 + 0x50100200, // 0008 LDBOOL R4 1 0 + 0x90020404, // 0009 SETMBR R0 K2 R4 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: status_ok_received +********************************************************************/ +be_local_closure(Matter_IM_SubscribeResponse_status_ok_received, /* 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[18]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20IM_SubscribeResponse_X20status_ok_received_X20sub_X3D_X25i_X20exch_X3D_X25i_X20ack_X3D_X25i_X20last_counter_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(resp), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_nested_str_weak(ack_message_counter), + /* K10 */ be_const_int(0), + /* K11 */ be_nested_str_weak(last_counter), + /* K12 */ be_const_int(3), + /* K13 */ be_nested_str_weak(MTR_X3A_X20_X3ESub_OK_X20_X20_X20_X20_X28_X256i_X29_X20sub_X3D_X25i), + /* K14 */ be_nested_str_weak(session), + /* K15 */ be_nested_str_weak(local_session_id), + /* K16 */ be_const_int(2), + /* K17 */ be_nested_str_weak(status_ok_received), + }), + be_str_weak(status_ok_received), + &be_const_str_solidified, + ( &(const binstruction[36]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x88241308, // 0008 GETMBR R9 R9 K8 + 0x88280309, // 0009 GETMBR R10 R1 K9 + 0x782A0001, // 000A JMPF R10 #000D + 0x88280309, // 000B GETMBR R10 R1 K9 + 0x70020000, // 000C JMP #000E + 0x5828000A, // 000D LDCONST R10 K10 + 0x882C010B, // 000E GETMBR R11 R0 K11 + 0x7C140C00, // 000F CALL R5 6 + 0x5818000C, // 0010 LDCONST R6 K12 + 0x7C0C0600, // 0011 CALL R3 3 + 0xB80E0200, // 0012 GETNGBL R3 K1 + 0x8C0C0702, // 0013 GETMET R3 R3 K2 + 0x8C140503, // 0014 GETMET R5 R2 K3 + 0x581C000D, // 0015 LDCONST R7 K13 + 0x8820030E, // 0016 GETMBR R8 R1 K14 + 0x8820110F, // 0017 GETMBR R8 R8 K15 + 0x88240105, // 0018 GETMBR R9 R0 K5 + 0x88241306, // 0019 GETMBR R9 R9 K6 + 0x7C140800, // 001A CALL R5 4 + 0x58180010, // 001B LDCONST R6 K16 + 0x7C0C0600, // 001C CALL R3 3 + 0x600C0003, // 001D GETGBL R3 G3 + 0x5C100000, // 001E MOVE R4 R0 + 0x7C0C0200, // 001F CALL R3 1 + 0x8C0C0711, // 0020 GETMET R3 R3 K17 + 0x5C140200, // 0021 MOVE R5 R1 + 0x7C0C0400, // 0022 CALL R3 2 + 0x80040600, // 0023 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send_im +********************************************************************/ +be_local_closure(Matter_IM_SubscribeResponse_send_im, /* 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[28]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20Matter_IM_SubscribeResponse_X20send_X20sub_X3D_X25i_X20ready_X3D_X25i), + /* K5 */ be_nested_str_weak(sub), + /* K6 */ be_nested_str_weak(subscription_id), + /* K7 */ be_nested_str_weak(ready), + /* K8 */ be_const_int(1), + /* K9 */ be_const_int(0), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(report_data_phase), + /* K12 */ be_nested_str_weak(send_im), + /* K13 */ be_nested_str_weak(finish), + /* K14 */ be_nested_str_weak(resp), + /* K15 */ be_nested_str_weak(matter), + /* K16 */ be_nested_str_weak(SubscribeResponseMessage), + /* K17 */ be_nested_str_weak(max_interval), + /* K18 */ be_nested_str_weak(opcode), + /* K19 */ be_nested_str_weak(encode_frame), + /* K20 */ be_nested_str_weak(to_TLV), + /* K21 */ be_nested_str_weak(tlv2raw), + /* K22 */ be_nested_str_weak(encrypt), + /* K23 */ be_nested_str_weak(send_response_frame), + /* K24 */ be_nested_str_weak(last_counter), + /* K25 */ be_nested_str_weak(message_counter), + /* K26 */ be_nested_str_weak(MTR_X3A_X20Send_X20SubscribeResponseMessage_X20sub_X3D_X25i_X20id_X3D_X25i), + /* K27 */ be_nested_str_weak(re_arm), + }), + be_str_weak(send_im), + &be_const_str_solidified, + ( &(const binstruction[78]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x8C140503, // 0003 GETMET R5 R2 K3 + 0x581C0004, // 0004 LDCONST R7 K4 + 0x88200105, // 0005 GETMBR R8 R0 K5 + 0x88201106, // 0006 GETMBR R8 R8 K6 + 0x88240107, // 0007 GETMBR R9 R0 K7 + 0x78260001, // 0008 JMPF R9 #000B + 0x58240008, // 0009 LDCONST R9 K8 + 0x70020000, // 000A JMP #000C + 0x58240009, // 000B LDCONST R9 K9 + 0x7C140800, // 000C CALL R5 4 + 0x5818000A, // 000D LDCONST R6 K10 + 0x7C0C0600, // 000E CALL R3 3 + 0x880C0107, // 000F GETMBR R3 R0 K7 + 0x740E0001, // 0010 JMPT R3 #0013 + 0x500C0000, // 0011 LDBOOL R3 0 0 + 0x80040600, // 0012 RET 1 R3 + 0x880C010B, // 0013 GETMBR R3 R0 K11 + 0x780E000E, // 0014 JMPF R3 #0024 + 0x600C0003, // 0015 GETGBL R3 G3 + 0x5C100000, // 0016 MOVE R4 R0 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C0C070C, // 0018 GETMET R3 R3 K12 + 0x5C140200, // 0019 MOVE R5 R1 + 0x7C0C0400, // 001A CALL R3 2 + 0x880C010D, // 001B GETMBR R3 R0 K13 + 0x780E0003, // 001C JMPF R3 #0021 + 0x500C0000, // 001D LDBOOL R3 0 0 + 0x90021603, // 001E SETMBR R0 K11 R3 + 0x500C0000, // 001F LDBOOL R3 0 0 + 0x90021A03, // 0020 SETMBR R0 K13 R3 + 0x500C0000, // 0021 LDBOOL R3 0 0 + 0x90020E03, // 0022 SETMBR R0 K7 R3 + 0x70020028, // 0023 JMP #004D + 0x880C010E, // 0024 GETMBR R3 R0 K14 + 0xB8121E00, // 0025 GETNGBL R4 K15 + 0x8C100910, // 0026 GETMET R4 R4 K16 + 0x7C100200, // 0027 CALL R4 1 + 0x88140105, // 0028 GETMBR R5 R0 K5 + 0x88140B06, // 0029 GETMBR R5 R5 K6 + 0x90120C05, // 002A SETMBR R4 K6 R5 + 0x88140105, // 002B GETMBR R5 R0 K5 + 0x88140B11, // 002C GETMBR R5 R5 K17 + 0x90122205, // 002D SETMBR R4 K17 R5 + 0x8814010E, // 002E GETMBR R5 R0 K14 + 0x541A0003, // 002F LDINT R6 4 + 0x90162406, // 0030 SETMBR R5 K18 R6 + 0x8C140713, // 0031 GETMET R5 R3 K19 + 0x8C1C0914, // 0032 GETMET R7 R4 K20 + 0x7C1C0200, // 0033 CALL R7 1 + 0x8C1C0F15, // 0034 GETMET R7 R7 K21 + 0x7C1C0200, // 0035 CALL R7 1 + 0x7C140400, // 0036 CALL R5 2 + 0x8C140716, // 0037 GETMET R5 R3 K22 + 0x7C140200, // 0038 CALL R5 1 + 0x8C140317, // 0039 GETMET R5 R1 K23 + 0x5C1C0600, // 003A MOVE R7 R3 + 0x7C140400, // 003B CALL R5 2 + 0x88140719, // 003C GETMBR R5 R3 K25 + 0x90023005, // 003D SETMBR R0 K24 R5 + 0xB8160200, // 003E GETNGBL R5 K1 + 0x8C140B02, // 003F GETMET R5 R5 K2 + 0x8C1C0503, // 0040 GETMET R7 R2 K3 + 0x5824001A, // 0041 LDCONST R9 K26 + 0x88280105, // 0042 GETMBR R10 R0 K5 + 0x88281506, // 0043 GETMBR R10 R10 K6 + 0x882C0719, // 0044 GETMBR R11 R3 K25 + 0x7C1C0800, // 0045 CALL R7 4 + 0x5820000A, // 0046 LDCONST R8 K10 + 0x7C140600, // 0047 CALL R5 3 + 0x88140105, // 0048 GETMBR R5 R0 K5 + 0x8C140B1B, // 0049 GETMET R5 R5 K27 + 0x7C140200, // 004A CALL R5 1 + 0x50140200, // 004B LDBOOL R5 1 0 + 0x90021A05, // 004C SETMBR R0 K13 R5 + 0x80000000, // 004D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_SubscribeResponse +********************************************************************/ +extern const bclass be_class_Matter_IM_ReportData; +be_local_class(Matter_IM_SubscribeResponse, + 2, + &be_class_Matter_IM_ReportData, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(init, 4), be_const_closure(Matter_IM_SubscribeResponse_init_closure) }, + { be_const_key_weak(sub, -1), be_const_var(0) }, + { be_const_key_weak(status_ok_received, -1), be_const_closure(Matter_IM_SubscribeResponse_status_ok_received_closure) }, + { be_const_key_weak(send_im, -1), be_const_closure(Matter_IM_SubscribeResponse_send_im_closure) }, + { be_const_key_weak(report_data_phase, -1), be_const_var(1) }, + })), + be_str_weak(Matter_IM_SubscribeResponse) +); +/*******************************************************************/ + +void be_load_Matter_IM_SubscribeResponse_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_SubscribeResponse); + be_setglobal(vm, "Matter_IM_SubscribeResponse"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Subscription.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Subscription.h new file mode 100644 index 000000000..e2f48b099 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM_Subscription.h @@ -0,0 +1,873 @@ +/* Solidification of Matter_IM_Subscription.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_IM_Subscription; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_Subscription_init, /* name */ + be_nested_proto( + 13, /* nstack */ + 5, /* 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(subs_shop), + /* K1 */ be_nested_str_weak(subscription_id), + /* K2 */ be_nested_str_weak(session), + /* K3 */ be_nested_str_weak(min_interval_floor), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(min_interval), + /* K6 */ be_nested_str_weak(max_interval_ceiling), + /* K7 */ be_nested_str_weak(max_interval), + /* K8 */ be_nested_str_weak(wait_status), + /* K9 */ be_nested_str_weak(fabric_filtered), + /* K10 */ be_nested_str_weak(path_list), + /* K11 */ be_nested_str_weak(attributes_requests), + /* K12 */ be_nested_str_weak(matter), + /* K13 */ be_nested_str_weak(Path), + /* K14 */ be_nested_str_weak(endpoint), + /* K15 */ be_nested_str_weak(cluster), + /* K16 */ be_nested_str_weak(attribute), + /* K17 */ be_nested_str_weak(push), + /* K18 */ be_nested_str_weak(stop_iteration), + /* K19 */ be_nested_str_weak(updates), + /* K20 */ be_nested_str_weak(clear_before_arm), + /* K21 */ be_nested_str_weak(is_keep_alive), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[61]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x88140903, // 0003 GETMBR R5 R4 K3 + 0x14180B04, // 0004 LT R6 R5 K4 + 0x781A0000, // 0005 JMPF R6 #0007 + 0x58140004, // 0006 LDCONST R5 K4 + 0x541A003B, // 0007 LDINT R6 60 + 0x24180A06, // 0008 GT R6 R5 R6 + 0x781A0000, // 0009 JMPF R6 #000B + 0x5416003B, // 000A LDINT R5 60 + 0x90020A05, // 000B SETMBR R0 K5 R5 + 0x88180906, // 000C GETMBR R6 R4 K6 + 0x541E003B, // 000D LDINT R7 60 + 0x141C0C07, // 000E LT R7 R6 R7 + 0x781E0000, // 000F JMPF R7 #0011 + 0x541A003B, // 0010 LDINT R6 60 + 0x541E0E0F, // 0011 LDINT R7 3600 + 0x241C0C07, // 0012 GT R7 R6 R7 + 0x781E0000, // 0013 JMPF R7 #0015 + 0x541A0E0F, // 0014 LDINT R6 3600 + 0x541A003B, // 0015 LDINT R6 60 + 0x90020E06, // 0016 SETMBR R0 K7 R6 + 0x501C0000, // 0017 LDBOOL R7 0 0 + 0x90021007, // 0018 SETMBR R0 K8 R7 + 0x881C0909, // 0019 GETMBR R7 R4 K9 + 0x90021207, // 001A SETMBR R0 K9 R7 + 0x601C0012, // 001B GETGBL R7 G18 + 0x7C1C0000, // 001C CALL R7 0 + 0x90021407, // 001D SETMBR R0 K10 R7 + 0x601C0010, // 001E GETGBL R7 G16 + 0x8820090B, // 001F GETMBR R8 R4 K11 + 0x7C1C0200, // 0020 CALL R7 1 + 0xA802000F, // 0021 EXBLK 0 #0032 + 0x5C200E00, // 0022 MOVE R8 R7 + 0x7C200000, // 0023 CALL R8 0 + 0xB8261800, // 0024 GETNGBL R9 K12 + 0x8C24130D, // 0025 GETMET R9 R9 K13 + 0x7C240200, // 0026 CALL R9 1 + 0x8828110E, // 0027 GETMBR R10 R8 K14 + 0x90261C0A, // 0028 SETMBR R9 K14 R10 + 0x8828110F, // 0029 GETMBR R10 R8 K15 + 0x90261E0A, // 002A SETMBR R9 K15 R10 + 0x88281110, // 002B GETMBR R10 R8 K16 + 0x9026200A, // 002C SETMBR R9 K16 R10 + 0x8828010A, // 002D GETMBR R10 R0 K10 + 0x8C281511, // 002E GETMET R10 R10 K17 + 0x5C301200, // 002F MOVE R12 R9 + 0x7C280400, // 0030 CALL R10 2 + 0x7001FFEF, // 0031 JMP #0022 + 0x581C0012, // 0032 LDCONST R7 K18 + 0xAC1C0200, // 0033 CATCH R7 1 0 + 0xB0080000, // 0034 RAISE 2 R0 R0 + 0x601C0012, // 0035 GETGBL R7 G18 + 0x7C1C0000, // 0036 CALL R7 0 + 0x90022607, // 0037 SETMBR R0 K19 R7 + 0x8C1C0114, // 0038 GETMET R7 R0 K20 + 0x7C1C0200, // 0039 CALL R7 1 + 0x501C0000, // 003A LDBOOL R7 0 0 + 0x90022A07, // 003B SETMBR R0 K21 R7 + 0x80000000, // 003C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _add_attribute_unique_path +********************************************************************/ +be_local_closure(Matter_IM_Subscription__add_attribute_unique_path, /* 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_weak(updates), + /* K2 */ be_nested_str_weak(endpoint), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(push), + }), + be_str_weak(_add_attribute_unique_path), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* 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 + 0x780E0010, // 0005 JMPF R3 #0017 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x88100702, // 0008 GETMBR R4 R3 K2 + 0x88140302, // 0009 GETMBR R5 R1 K2 + 0x1C100805, // 000A EQ R4 R4 R5 + 0x78120008, // 000B JMPF R4 #0015 + 0x88100703, // 000C GETMBR R4 R3 K3 + 0x88140303, // 000D GETMBR R5 R1 K3 + 0x1C100805, // 000E EQ R4 R4 R5 + 0x78120004, // 000F JMPF R4 #0015 + 0x88100704, // 0010 GETMBR R4 R3 K4 + 0x88140304, // 0011 GETMBR R5 R1 K4 + 0x1C100805, // 0012 EQ R4 R4 R5 + 0x78120000, // 0013 JMPF R4 #0015 + 0x80000800, // 0014 RET 0 + 0x00080505, // 0015 ADD R2 R2 K5 + 0x7001FFE9, // 0016 JMP #0001 + 0x880C0101, // 0017 GETMBR R3 R0 K1 + 0x8C0C0706, // 0018 GETMET R3 R3 K6 + 0x5C140200, // 0019 MOVE R5 R1 + 0x7C0C0400, // 001A CALL R3 2 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_self +********************************************************************/ +be_local_closure(Matter_IM_Subscription_remove_self, /* 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[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20_X2DSub_Del_X20_X20_X20_X28_X20_X20_X20_X20_X20_X20_X29_X20sub_X3D), + /* K3 */ be_nested_str_weak(subscription_id), + /* K4 */ be_const_int(2), + /* K5 */ be_nested_str_weak(subs_shop), + /* K6 */ be_nested_str_weak(remove_sub), + }), + be_str_weak(remove_self), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x600C0008, // 0002 GETGBL R3 G8 + 0x88100103, // 0003 GETMBR R4 R0 K3 + 0x7C0C0200, // 0004 CALL R3 1 + 0x000E0403, // 0005 ADD R3 K2 R3 + 0x58100004, // 0006 LDCONST R4 K4 + 0x7C040600, // 0007 CALL R1 3 + 0x88040105, // 0008 GETMBR R1 R0 K5 + 0x8C040306, // 0009 GETMET R1 R1 K6 + 0x5C0C0000, // 000A MOVE R3 R0 + 0x7C040400, // 000B CALL R1 2 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear_before_arm +********************************************************************/ +be_local_closure(Matter_IM_Subscription_clear_before_arm, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(updates), + /* K1 */ be_nested_str_weak(clear), + /* K2 */ be_nested_str_weak(wait_status), + }), + be_str_weak(clear_before_arm), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x50040200, // 0003 LDBOOL R1 1 0 + 0x90020401, // 0004 SETMBR R0 K2 R1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: attribute_updated_ctx +********************************************************************/ +be_local_closure(Matter_IM_Subscription_attribute_updated_ctx, /* 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_const_int(0), + /* K1 */ be_nested_str_weak(path_list), + /* K2 */ be_nested_str_weak(endpoint), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_nested_str_weak(_add_attribute_unique_path), + /* K6 */ be_const_int(1), + }), + be_str_weak(attribute_updated_ctx), + &be_const_str_solidified, + ( &(const binstruction[38]) { /* code */ + 0x580C0000, // 0000 LDCONST R3 K0 + 0x6010000C, // 0001 GETGBL R4 G12 + 0x88140101, // 0002 GETMBR R5 R0 K1 + 0x7C100200, // 0003 CALL R4 1 + 0x14100604, // 0004 LT R4 R3 R4 + 0x7812001E, // 0005 JMPF R4 #0025 + 0x88100101, // 0006 GETMBR R4 R0 K1 + 0x94100803, // 0007 GETIDX R4 R4 R3 + 0x88140902, // 0008 GETMBR R5 R4 K2 + 0x4C180000, // 0009 LDNIL R6 + 0x1C140A06, // 000A EQ R5 R5 R6 + 0x74160003, // 000B JMPT R5 #0010 + 0x88140902, // 000C GETMBR R5 R4 K2 + 0x88180302, // 000D GETMBR R6 R1 K2 + 0x1C140A06, // 000E EQ R5 R5 R6 + 0x78160012, // 000F JMPF R5 #0023 + 0x88140903, // 0010 GETMBR R5 R4 K3 + 0x4C180000, // 0011 LDNIL R6 + 0x1C140A06, // 0012 EQ R5 R5 R6 + 0x74160003, // 0013 JMPT R5 #0018 + 0x88140903, // 0014 GETMBR R5 R4 K3 + 0x88180303, // 0015 GETMBR R6 R1 K3 + 0x1C140A06, // 0016 EQ R5 R5 R6 + 0x7816000A, // 0017 JMPF R5 #0023 + 0x88140904, // 0018 GETMBR R5 R4 K4 + 0x4C180000, // 0019 LDNIL R6 + 0x1C140A06, // 001A EQ R5 R5 R6 + 0x74160003, // 001B JMPT R5 #0020 + 0x88140904, // 001C GETMBR R5 R4 K4 + 0x88180304, // 001D GETMBR R6 R1 K4 + 0x1C140A06, // 001E EQ R5 R5 R6 + 0x78160002, // 001F JMPF R5 #0023 + 0x8C140105, // 0020 GETMET R5 R0 K5 + 0x5C1C0200, // 0021 MOVE R7 R1 + 0x7C140400, // 0022 CALL R5 2 + 0x000C0706, // 0023 ADD R3 R3 K6 + 0x7001FFDB, // 0024 JMP #0001 + 0x80000000, // 0025 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: re_arm +********************************************************************/ +be_local_closure(Matter_IM_Subscription_re_arm, /* 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[16]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(wait_status), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(millis), + /* K4 */ be_nested_str_weak(expiration), + /* K5 */ be_nested_str_weak(max_interval), + /* K6 */ be_nested_str_weak(MAX_INTERVAL_MARGIN), + /* K7 */ be_nested_str_weak(not_before), + /* K8 */ be_nested_str_weak(min_interval), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(is_keep_alive), + /* K11 */ be_nested_str_weak(log), + /* K12 */ be_nested_str_weak(format), + /* K13 */ be_nested_str_weak(MTR_X3A_X20_X2ESub_Done_X20_X20_X28_X20_X20_X20_X20_X20_X20_X29_X20sub_X3D_X25i), + /* K14 */ be_nested_str_weak(subscription_id), + /* K15 */ be_const_int(2), + }), + be_str_weak(re_arm), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x50080000, // 0001 LDBOOL R2 0 0 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0xB80A0400, // 0003 GETNGBL R2 K2 + 0x8C080503, // 0004 GETMET R2 R2 K3 + 0x7C080200, // 0005 CALL R2 1 + 0x880C0105, // 0006 GETMBR R3 R0 K5 + 0x88100106, // 0007 GETMBR R4 R0 K6 + 0x040C0604, // 0008 SUB R3 R3 R4 + 0x541203E7, // 0009 LDINT R4 1000 + 0x080C0604, // 000A MUL R3 R3 R4 + 0x000C0403, // 000B ADD R3 R2 R3 + 0x90020803, // 000C SETMBR R0 K4 R3 + 0x880C0108, // 000D GETMBR R3 R0 K8 + 0x541203E7, // 000E LDINT R4 1000 + 0x080C0604, // 000F MUL R3 R3 R4 + 0x000C0403, // 0010 ADD R3 R2 R3 + 0x040C0709, // 0011 SUB R3 R3 K9 + 0x90020E03, // 0012 SETMBR R0 K7 R3 + 0x880C010A, // 0013 GETMBR R3 R0 K10 + 0x740E0007, // 0014 JMPT R3 #001D + 0xB80E0400, // 0015 GETNGBL R3 K2 + 0x8C0C070B, // 0016 GETMET R3 R3 K11 + 0x8C14030C, // 0017 GETMET R5 R1 K12 + 0x581C000D, // 0018 LDCONST R7 K13 + 0x8820010E, // 0019 GETMBR R8 R0 K14 + 0x7C140600, // 001A CALL R5 3 + 0x5818000F, // 001B LDCONST R6 K15 + 0x7C0C0600, // 001C CALL R3 3 + 0x80000000, // 001D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_Subscription +********************************************************************/ +be_local_class(Matter_IM_Subscription, + 12, + NULL, + be_nested_map(19, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(not_before, -1), be_const_var(7) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_IM_Subscription_init_closure) }, + { be_const_key_weak(attribute_updated_ctx, -1), be_const_closure(Matter_IM_Subscription_attribute_updated_ctx_closure) }, + { be_const_key_weak(updates, -1), be_const_var(11) }, + { be_const_key_weak(min_interval, -1), be_const_var(4) }, + { be_const_key_weak(expiration, -1), be_const_var(8) }, + { be_const_key_weak(subscription_id, 3), be_const_var(1) }, + { be_const_key_weak(subs_shop, -1), be_const_var(0) }, + { be_const_key_weak(max_interval, -1), be_const_var(5) }, + { be_const_key_weak(remove_self, 1), be_const_closure(Matter_IM_Subscription_remove_self_closure) }, + { be_const_key_weak(MAX_INTERVAL_MARGIN, -1), be_const_int(5) }, + { be_const_key_weak(fabric_filtered, 7), be_const_var(6) }, + { be_const_key_weak(_add_attribute_unique_path, 11), be_const_closure(Matter_IM_Subscription__add_attribute_unique_path_closure) }, + { be_const_key_weak(path_list, 9), be_const_var(3) }, + { be_const_key_weak(is_keep_alive, -1), be_const_var(10) }, + { be_const_key_weak(clear_before_arm, -1), be_const_closure(Matter_IM_Subscription_clear_before_arm_closure) }, + { be_const_key_weak(session, 2), be_const_var(2) }, + { be_const_key_weak(re_arm, -1), be_const_closure(Matter_IM_Subscription_re_arm_closure) }, + { be_const_key_weak(wait_status, 0), be_const_var(9) }, + })), + be_str_weak(Matter_IM_Subscription) +); +/*******************************************************************/ + +void be_load_Matter_IM_Subscription_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_Subscription); + be_setglobal(vm, "Matter_IM_Subscription"); + be_pop(vm, 1); +} + +extern const bclass be_class_Matter_IM_Subscription_Shop; + +/******************************************************************** +** Solidified function: every_250ms +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_every_250ms, /* 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[14]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(subs), + /* K2 */ be_nested_str_weak(wait_status), + /* K3 */ be_nested_str_weak(updates), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(time_reached), + /* K6 */ be_nested_str_weak(not_before), + /* K7 */ be_nested_str_weak(im), + /* K8 */ be_nested_str_weak(send_subscribe_update), + /* K9 */ be_nested_str_weak(clear_before_arm), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_str_weak(expiration), + /* K12 */ be_nested_str_weak(send_subscribe_heartbeat), + /* K13 */ be_nested_str_weak(re_arm), + }), + be_str_weak(every_250ms), + &be_const_str_solidified, + ( &(const binstruction[54]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x14080202, // 0004 LT R2 R1 R2 + 0x780A0015, // 0005 JMPF R2 #001C + 0x88080101, // 0006 GETMBR R2 R0 K1 + 0x94080401, // 0007 GETIDX R2 R2 R1 + 0x880C0502, // 0008 GETMBR R3 R2 K2 + 0x740E000F, // 0009 JMPT R3 #001A + 0x600C000C, // 000A GETGBL R3 G12 + 0x88100503, // 000B GETMBR R4 R2 K3 + 0x7C0C0200, // 000C CALL R3 1 + 0x240C0700, // 000D GT R3 R3 K0 + 0x780E000A, // 000E JMPF R3 #001A + 0xB80E0800, // 000F GETNGBL R3 K4 + 0x8C0C0705, // 0010 GETMET R3 R3 K5 + 0x88140506, // 0011 GETMBR R5 R2 K6 + 0x7C0C0400, // 0012 CALL R3 2 + 0x780E0005, // 0013 JMPF R3 #001A + 0x880C0107, // 0014 GETMBR R3 R0 K7 + 0x8C0C0708, // 0015 GETMET R3 R3 K8 + 0x5C140400, // 0016 MOVE R5 R2 + 0x7C0C0400, // 0017 CALL R3 2 + 0x8C0C0509, // 0018 GETMET R3 R2 K9 + 0x7C0C0200, // 0019 CALL R3 1 + 0x0004030A, // 001A ADD R1 R1 K10 + 0x7001FFE4, // 001B JMP #0001 + 0x58040000, // 001C LDCONST R1 K0 + 0x6008000C, // 001D GETGBL R2 G12 + 0x880C0101, // 001E GETMBR R3 R0 K1 + 0x7C080200, // 001F CALL R2 1 + 0x14080202, // 0020 LT R2 R1 R2 + 0x780A0012, // 0021 JMPF R2 #0035 + 0x88080101, // 0022 GETMBR R2 R0 K1 + 0x94080401, // 0023 GETIDX R2 R2 R1 + 0x880C0502, // 0024 GETMBR R3 R2 K2 + 0x740E000C, // 0025 JMPT R3 #0033 + 0xB80E0800, // 0026 GETNGBL R3 K4 + 0x8C0C0705, // 0027 GETMET R3 R3 K5 + 0x8814050B, // 0028 GETMBR R5 R2 K11 + 0x7C0C0400, // 0029 CALL R3 2 + 0x780E0007, // 002A JMPF R3 #0033 + 0x880C0107, // 002B GETMBR R3 R0 K7 + 0x8C0C070C, // 002C GETMET R3 R3 K12 + 0x5C140400, // 002D MOVE R5 R2 + 0x7C0C0400, // 002E CALL R3 2 + 0x8C0C0509, // 002F GETMET R3 R2 K9 + 0x7C0C0200, // 0030 CALL R3 1 + 0x8C0C050D, // 0031 GETMET R3 R2 K13 + 0x7C0C0200, // 0032 CALL R3 1 + 0x0004030A, // 0033 ADD R1 R1 K10 + 0x7001FFE7, // 0034 JMP #001D + 0x80000000, // 0035 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_by_id +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_get_by_id, /* 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_const_int(0), + /* K1 */ be_nested_str_weak(subs), + /* K2 */ be_nested_str_weak(subscription_id), + /* K3 */ be_const_int(1), + }), + be_str_weak(get_by_id), + &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 + 0x780E0009, // 0005 JMPF R3 #0010 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x880C0702, // 0008 GETMBR R3 R3 K2 + 0x1C0C0601, // 0009 EQ R3 R3 R1 + 0x780E0002, // 000A JMPF R3 #000E + 0x880C0101, // 000B GETMBR R3 R0 K1 + 0x940C0602, // 000C GETIDX R3 R3 R2 + 0x80040600, // 000D RET 1 R3 + 0x00080503, // 000E ADD R2 R2 K3 + 0x7001FFF0, // 000F JMP #0001 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: new_subscription +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_new_subscription, /* 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[10]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_const_int(2), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(get_by_id), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(IM_Subscription), + /* K8 */ be_nested_str_weak(subs), + /* K9 */ be_nested_str_weak(push), + }), + be_str_weak(new_subscription), + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x8C100701, // 0001 GETMET R4 R3 K1 + 0x58180002, // 0002 LDCONST R6 K2 + 0x7C100400, // 0003 CALL R4 2 + 0x8C100903, // 0004 GETMET R4 R4 K3 + 0x58180004, // 0005 LDCONST R6 K4 + 0x581C0002, // 0006 LDCONST R7 K2 + 0x7C100600, // 0007 CALL R4 3 + 0x8C140105, // 0008 GETMET R5 R0 K5 + 0x5C1C0800, // 0009 MOVE R7 R4 + 0x7C140400, // 000A CALL R5 2 + 0x78160008, // 000B JMPF R5 #0015 + 0x8C140701, // 000C GETMET R5 R3 K1 + 0x581C0002, // 000D LDCONST R7 K2 + 0x7C140400, // 000E CALL R5 2 + 0x8C140B03, // 000F GETMET R5 R5 K3 + 0x581C0004, // 0010 LDCONST R7 K4 + 0x58200002, // 0011 LDCONST R8 K2 + 0x7C140600, // 0012 CALL R5 3 + 0x5C100A00, // 0013 MOVE R4 R5 + 0x7001FFF2, // 0014 JMP #0008 + 0xB8160C00, // 0015 GETNGBL R5 K6 + 0x8C140B07, // 0016 GETMET R5 R5 K7 + 0x5C1C0000, // 0017 MOVE R7 R0 + 0x5C200800, // 0018 MOVE R8 R4 + 0x5C240200, // 0019 MOVE R9 R1 + 0x5C280400, // 001A MOVE R10 R2 + 0x7C140A00, // 001B CALL R5 5 + 0x88180108, // 001C GETMBR R6 R0 K8 + 0x8C180D09, // 001D GETMET R6 R6 K9 + 0x5C200A00, // 001E MOVE R8 R5 + 0x7C180400, // 001F CALL R6 2 + 0x80040A00, // 0020 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_sub +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_remove_sub, /* 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(subs), + /* K2 */ be_nested_str_weak(remove), + /* K3 */ be_const_int(1), + }), + be_str_weak(remove_sub), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* 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 + 0x780E000A, // 0005 JMPF R3 #0011 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x1C0C0601, // 0008 EQ R3 R3 R1 + 0x780E0004, // 0009 JMPF R3 #000F + 0x880C0101, // 000A GETMBR R3 R0 K1 + 0x8C0C0702, // 000B GETMET R3 R3 K2 + 0x5C140400, // 000C MOVE R5 R2 + 0x7C0C0400, // 000D CALL R3 2 + 0x70020000, // 000E JMP #0010 + 0x00080503, // 000F ADD R2 R2 K3 + 0x7001FFEF, // 0010 JMP #0001 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: attribute_updated_ctx +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_attribute_updated_ctx, /* 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[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(subs), + /* K2 */ be_nested_str_weak(attribute_updated_ctx), + /* K3 */ be_const_int(1), + }), + be_str_weak(attribute_updated_ctx), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x580C0000, // 0000 LDCONST R3 K0 + 0x6010000C, // 0001 GETGBL R4 G12 + 0x88140101, // 0002 GETMBR R5 R0 K1 + 0x7C100200, // 0003 CALL R4 1 + 0x14100604, // 0004 LT R4 R3 R4 + 0x78120007, // 0005 JMPF R4 #000E + 0x88100101, // 0006 GETMBR R4 R0 K1 + 0x94100803, // 0007 GETIDX R4 R4 R3 + 0x8C100902, // 0008 GETMET R4 R4 K2 + 0x5C180200, // 0009 MOVE R6 R1 + 0x5C1C0400, // 000A MOVE R7 R2 + 0x7C100600, // 000B CALL R4 3 + 0x000C0703, // 000C ADD R3 R3 K3 + 0x7001FFF2, // 000D JMP #0001 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_by_session +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_remove_by_session, /* 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[ 5]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(subs), + /* K2 */ be_nested_str_weak(session), + /* K3 */ be_nested_str_weak(remove), + /* K4 */ be_const_int(1), + }), + be_str_weak(remove_by_session), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* 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 + 0x780E000B, // 0005 JMPF R3 #0012 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x880C0702, // 0008 GETMBR R3 R3 K2 + 0x1C0C0601, // 0009 EQ R3 R3 R1 + 0x780E0004, // 000A JMPF R3 #0010 + 0x880C0101, // 000B GETMBR R3 R0 K1 + 0x8C0C0703, // 000C GETMET R3 R3 K3 + 0x5C140400, // 000D MOVE R5 R2 + 0x7C0C0400, // 000E CALL R3 2 + 0x70020000, // 000F JMP #0011 + 0x00080504, // 0010 ADD R2 R2 K4 + 0x7001FFEE, // 0011 JMP #0001 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_init, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(im), + /* K1 */ be_nested_str_weak(subs), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x60080012, // 0001 GETGBL R2 G18 + 0x7C080000, // 0002 CALL R2 0 + 0x90020202, // 0003 SETMBR R0 K1 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_by_fabric +********************************************************************/ +be_local_closure(Matter_IM_Subscription_Shop_remove_by_fabric, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(_sessions), + /* K1 */ be_nested_str_weak(remove_by_session), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(remove_by_fabric), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x60080010, // 0000 GETGBL R2 G16 + 0x880C0300, // 0001 GETMBR R3 R1 K0 + 0x7C080200, // 0002 CALL R2 1 + 0xA8020005, // 0003 EXBLK 0 #000A + 0x5C0C0400, // 0004 MOVE R3 R2 + 0x7C0C0000, // 0005 CALL R3 0 + 0x8C100101, // 0006 GETMET R4 R0 K1 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0x7001FFF9, // 0009 JMP #0004 + 0x58080002, // 000A LDCONST R2 K2 + 0xAC080200, // 000B CATCH R2 1 0 + 0xB0080000, // 000C RAISE 2 R0 R0 + 0x80000000, // 000D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_IM_Subscription_Shop +********************************************************************/ +be_local_class(Matter_IM_Subscription_Shop, + 2, + NULL, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_IM_Subscription_Shop_every_250ms_closure) }, + { be_const_key_weak(get_by_id, -1), be_const_closure(Matter_IM_Subscription_Shop_get_by_id_closure) }, + { be_const_key_weak(attribute_updated_ctx, -1), be_const_closure(Matter_IM_Subscription_Shop_attribute_updated_ctx_closure) }, + { be_const_key_weak(init, 2), be_const_closure(Matter_IM_Subscription_Shop_init_closure) }, + { be_const_key_weak(remove_sub, -1), be_const_closure(Matter_IM_Subscription_Shop_remove_sub_closure) }, + { be_const_key_weak(new_subscription, 3), be_const_closure(Matter_IM_Subscription_Shop_new_subscription_closure) }, + { be_const_key_weak(subs, 8), be_const_var(0) }, + { be_const_key_weak(im, -1), be_const_var(1) }, + { be_const_key_weak(remove_by_session, -1), be_const_closure(Matter_IM_Subscription_Shop_remove_by_session_closure) }, + { be_const_key_weak(remove_by_fabric, -1), be_const_closure(Matter_IM_Subscription_Shop_remove_by_fabric_closure) }, + })), + be_str_weak(Matter_IM_Subscription_Shop) +); +/*******************************************************************/ + +void be_load_Matter_IM_Subscription_Shop_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_IM_Subscription_Shop); + be_setglobal(vm, "Matter_IM_Subscription_Shop"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h index 76f644b3a..fbb32f5c4 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Message.h @@ -6,6 +6,206 @@ extern const bclass be_class_Matter_Frame; +/******************************************************************** +** Solidified function: encode_frame +********************************************************************/ +be_local_closure(Matter_Frame_encode_frame, /* 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[30]) { /* constants */ + /* K0 */ be_nested_str_weak(flags), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(flag_s), + /* K3 */ be_nested_str_weak(flag_dsiz), + /* K4 */ be_const_int(3), + /* K5 */ be_nested_str_weak(add), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(local_session_id), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(sec_flags), + /* K10 */ be_nested_str_weak(sec_p), + /* K11 */ be_nested_str_weak(sec_c), + /* K12 */ be_nested_str_weak(sec_sesstype), + /* K13 */ be_nested_str_weak(message_counter), + /* K14 */ be_nested_str_weak(source_node_id), + /* K15 */ be_nested_str_weak(dest_node_id_8), + /* K16 */ be_nested_str_weak(dest_node_id_2), + /* K17 */ be_nested_str_weak(payload_idx), + /* K18 */ be_nested_str_weak(x_flags), + /* K19 */ be_nested_str_weak(x_flag_v), + /* K20 */ be_nested_str_weak(x_flag_r), + /* K21 */ be_nested_str_weak(x_flag_a), + /* K22 */ be_nested_str_weak(x_flag_i), + /* K23 */ be_nested_str_weak(opcode), + /* K24 */ be_nested_str_weak(exchange_id), + /* K25 */ be_nested_str_weak(protocol_id), + /* K26 */ be_nested_str_weak(ack_message_counter), + /* K27 */ be_nested_str_weak(app_payload_idx), + /* K28 */ be_nested_str_weak(debug), + /* K29 */ be_nested_str_weak(raw), + }), + be_str_weak(encode_frame), + &be_const_str_solidified, + ( &(const binstruction[146]) { /* code */ + 0x60080015, // 0000 GETGBL R2 G21 + 0x7C080000, // 0001 CALL R2 0 + 0x880C0100, // 0002 GETMBR R3 R0 K0 + 0x4C100000, // 0003 LDNIL R4 + 0x1C0C0604, // 0004 EQ R3 R3 R4 + 0x780E000D, // 0005 JMPF R3 #0014 + 0x90020101, // 0006 SETMBR R0 K0 K1 + 0x880C0102, // 0007 GETMBR R3 R0 K2 + 0x780E0003, // 0008 JMPF R3 #000D + 0x880C0100, // 0009 GETMBR R3 R0 K0 + 0x54120003, // 000A LDINT R4 4 + 0x300C0604, // 000B OR R3 R3 R4 + 0x90020003, // 000C SETMBR R0 K0 R3 + 0x880C0103, // 000D GETMBR R3 R0 K3 + 0x780E0004, // 000E JMPF R3 #0014 + 0x880C0100, // 000F GETMBR R3 R0 K0 + 0x88100103, // 0010 GETMBR R4 R0 K3 + 0x2C100904, // 0011 AND R4 R4 K4 + 0x300C0604, // 0012 OR R3 R3 R4 + 0x90020003, // 0013 SETMBR R0 K0 R3 + 0x8C0C0505, // 0014 GETMET R3 R2 K5 + 0x88140100, // 0015 GETMBR R5 R0 K0 + 0x58180006, // 0016 LDCONST R6 K6 + 0x7C0C0600, // 0017 CALL R3 3 + 0x8C0C0505, // 0018 GETMET R3 R2 K5 + 0x88140107, // 0019 GETMBR R5 R0 K7 + 0x78160001, // 001A JMPF R5 #001D + 0x88140107, // 001B GETMBR R5 R0 K7 + 0x70020000, // 001C JMP #001E + 0x58140001, // 001D LDCONST R5 K1 + 0x58180008, // 001E LDCONST R6 K8 + 0x7C0C0600, // 001F CALL R3 3 + 0x880C0109, // 0020 GETMBR R3 R0 K9 + 0x4C100000, // 0021 LDNIL R4 + 0x1C0C0604, // 0022 EQ R3 R3 R4 + 0x780E0013, // 0023 JMPF R3 #0038 + 0x90021301, // 0024 SETMBR R0 K9 K1 + 0x880C010A, // 0025 GETMBR R3 R0 K10 + 0x780E0003, // 0026 JMPF R3 #002B + 0x880C0109, // 0027 GETMBR R3 R0 K9 + 0x5412007F, // 0028 LDINT R4 128 + 0x300C0604, // 0029 OR R3 R3 R4 + 0x90021203, // 002A SETMBR R0 K9 R3 + 0x880C010B, // 002B GETMBR R3 R0 K11 + 0x780E0003, // 002C JMPF R3 #0031 + 0x880C0109, // 002D GETMBR R3 R0 K9 + 0x5412003F, // 002E LDINT R4 64 + 0x300C0604, // 002F OR R3 R3 R4 + 0x90021203, // 0030 SETMBR R0 K9 R3 + 0x880C010C, // 0031 GETMBR R3 R0 K12 + 0x780E0004, // 0032 JMPF R3 #0038 + 0x880C0109, // 0033 GETMBR R3 R0 K9 + 0x8810010C, // 0034 GETMBR R4 R0 K12 + 0x2C100904, // 0035 AND R4 R4 K4 + 0x300C0604, // 0036 OR R3 R3 R4 + 0x90021203, // 0037 SETMBR R0 K9 R3 + 0x8C0C0505, // 0038 GETMET R3 R2 K5 + 0x88140109, // 0039 GETMBR R5 R0 K9 + 0x58180006, // 003A LDCONST R6 K6 + 0x7C0C0600, // 003B CALL R3 3 + 0x8C0C0505, // 003C GETMET R3 R2 K5 + 0x8814010D, // 003D GETMBR R5 R0 K13 + 0x541A0003, // 003E LDINT R6 4 + 0x7C0C0600, // 003F CALL R3 3 + 0x880C0102, // 0040 GETMBR R3 R0 K2 + 0x780E0001, // 0041 JMPF R3 #0044 + 0x880C010E, // 0042 GETMBR R3 R0 K14 + 0x400C0403, // 0043 CONNECT R3 R2 R3 + 0x880C0103, // 0044 GETMBR R3 R0 K3 + 0x1C0C0706, // 0045 EQ R3 R3 K6 + 0x780E0001, // 0046 JMPF R3 #0049 + 0x880C010F, // 0047 GETMBR R3 R0 K15 + 0x400C0403, // 0048 CONNECT R3 R2 R3 + 0x880C0103, // 0049 GETMBR R3 R0 K3 + 0x1C0C0708, // 004A EQ R3 R3 K8 + 0x780E0003, // 004B JMPF R3 #0050 + 0x8C0C0505, // 004C GETMET R3 R2 K5 + 0x88140110, // 004D GETMBR R5 R0 K16 + 0x58180008, // 004E LDCONST R6 K8 + 0x7C0C0600, // 004F CALL R3 3 + 0x600C000C, // 0050 GETGBL R3 G12 + 0x5C100400, // 0051 MOVE R4 R2 + 0x7C0C0200, // 0052 CALL R3 1 + 0x90022203, // 0053 SETMBR R0 K17 R3 + 0x880C0112, // 0054 GETMBR R3 R0 K18 + 0x4C100000, // 0055 LDNIL R4 + 0x1C0C0604, // 0056 EQ R3 R3 R4 + 0x780E0016, // 0057 JMPF R3 #006F + 0x90022501, // 0058 SETMBR R0 K18 K1 + 0x880C0113, // 0059 GETMBR R3 R0 K19 + 0x780E0003, // 005A JMPF R3 #005F + 0x880C0112, // 005B GETMBR R3 R0 K18 + 0x5412000F, // 005C LDINT R4 16 + 0x300C0604, // 005D OR R3 R3 R4 + 0x90022403, // 005E SETMBR R0 K18 R3 + 0x880C0114, // 005F GETMBR R3 R0 K20 + 0x780E0003, // 0060 JMPF R3 #0065 + 0x880C0112, // 0061 GETMBR R3 R0 K18 + 0x54120003, // 0062 LDINT R4 4 + 0x300C0604, // 0063 OR R3 R3 R4 + 0x90022403, // 0064 SETMBR R0 K18 R3 + 0x880C0115, // 0065 GETMBR R3 R0 K21 + 0x780E0002, // 0066 JMPF R3 #006A + 0x880C0112, // 0067 GETMBR R3 R0 K18 + 0x300C0708, // 0068 OR R3 R3 K8 + 0x90022403, // 0069 SETMBR R0 K18 R3 + 0x880C0116, // 006A GETMBR R3 R0 K22 + 0x780E0002, // 006B JMPF R3 #006F + 0x880C0112, // 006C GETMBR R3 R0 K18 + 0x300C0706, // 006D OR R3 R3 K6 + 0x90022403, // 006E SETMBR R0 K18 R3 + 0x8C0C0505, // 006F GETMET R3 R2 K5 + 0x88140112, // 0070 GETMBR R5 R0 K18 + 0x58180006, // 0071 LDCONST R6 K6 + 0x7C0C0600, // 0072 CALL R3 3 + 0x8C0C0505, // 0073 GETMET R3 R2 K5 + 0x88140117, // 0074 GETMBR R5 R0 K23 + 0x58180006, // 0075 LDCONST R6 K6 + 0x7C0C0600, // 0076 CALL R3 3 + 0x8C0C0505, // 0077 GETMET R3 R2 K5 + 0x88140118, // 0078 GETMBR R5 R0 K24 + 0x541AFFFE, // 0079 LDINT R6 65535 + 0x2C140A06, // 007A AND R5 R5 R6 + 0x58180008, // 007B LDCONST R6 K8 + 0x7C0C0600, // 007C CALL R3 3 + 0x8C0C0505, // 007D GETMET R3 R2 K5 + 0x88140119, // 007E GETMBR R5 R0 K25 + 0x58180008, // 007F LDCONST R6 K8 + 0x7C0C0600, // 0080 CALL R3 3 + 0x880C0115, // 0081 GETMBR R3 R0 K21 + 0x780E0003, // 0082 JMPF R3 #0087 + 0x8C0C0505, // 0083 GETMET R3 R2 K5 + 0x8814011A, // 0084 GETMBR R5 R0 K26 + 0x541A0003, // 0085 LDINT R6 4 + 0x7C0C0600, // 0086 CALL R3 3 + 0x600C000C, // 0087 GETGBL R3 G12 + 0x5C100400, // 0088 MOVE R4 R2 + 0x7C0C0200, // 0089 CALL R3 1 + 0x90023603, // 008A SETMBR R0 K27 R3 + 0x78060000, // 008B JMPF R1 #008D + 0x400C0401, // 008C CONNECT R3 R2 R1 + 0x8C0C011C, // 008D GETMET R3 R0 K28 + 0x5C140400, // 008E MOVE R5 R2 + 0x7C0C0400, // 008F CALL R3 2 + 0x90023A02, // 0090 SETMBR R0 K29 R2 + 0x80040400, // 0091 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: encrypt ********************************************************************/ @@ -19,7 +219,7 @@ be_local_closure(Matter_Frame_encrypt, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[30]) { /* constants */ + ( &(const bvalue[17]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(raw), /* K2 */ be_nested_str_weak(session), @@ -31,29 +231,16 @@ be_local_closure(Matter_Frame_encrypt, /* name */ /* K8 */ be_nested_str_weak(add), /* K9 */ be_nested_str_weak(flags), /* K10 */ be_nested_str_weak(message_counter), - /* K11 */ be_nested_str_weak(get_mode), - /* K12 */ be_nested_str_weak(__CASE), - /* K13 */ be_nested_str_weak(deviceid), - /* K14 */ be_nested_str_weak(resize), - /* K15 */ be_nested_str_weak(tasmota), - /* K16 */ be_nested_str_weak(log), - /* K17 */ be_nested_str_weak(MTR_X3A_X20cleartext_X3A_X20), - /* K18 */ be_nested_str_weak(tohex), - /* K19 */ be_const_int(3), - /* K20 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K21 */ be_nested_str_weak(MTR_X3A_X20r2i_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K22 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K23 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K24 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K25 */ be_nested_str_weak(AES_CCM), - /* K26 */ be_nested_str_weak(encrypt), - /* K27 */ be_nested_str_weak(tag), - /* K28 */ be_nested_str_weak(MTR_X3A_X20ciphertext_X20_X20_X3D), - /* K29 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K11 */ be_nested_str_weak(is_CASE), + /* K12 */ be_nested_str_weak(get_device_id), + /* K13 */ be_nested_str_weak(resize), + /* K14 */ be_nested_str_weak(AES_CCM), + /* K15 */ be_nested_str_weak(encrypt), + /* K16 */ be_nested_str_weak(tag), }), be_str_weak(encrypt), &be_const_str_solidified, - ( &(const binstruction[122]) { /* code */ + ( &(const binstruction[57]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x88080101, // 0001 GETMBR R2 R0 K1 0x880C0102, // 0002 GETMBR R3 R0 K2 @@ -78,104 +265,183 @@ be_local_closure(Matter_Frame_encrypt, /* name */ 0x7C200600, // 0015 CALL R8 3 0x8C20070B, // 0016 GETMET R8 R3 K11 0x7C200200, // 0017 CALL R8 1 - 0x8824070C, // 0018 GETMBR R9 R3 K12 - 0x1C201009, // 0019 EQ R8 R8 R9 - 0x78220003, // 001A JMPF R8 #001F - 0x8820070D, // 001B GETMBR R8 R3 K13 - 0x78220001, // 001C JMPF R8 #001F - 0x8820070D, // 001D GETMBR R8 R3 K13 + 0x78220005, // 0018 JMPF R8 #001F + 0x8C20070C, // 0019 GETMET R8 R3 K12 + 0x7C200200, // 001A CALL R8 1 + 0x78220002, // 001B JMPF R8 #001F + 0x8C20070C, // 001C GETMET R8 R3 K12 + 0x7C200200, // 001D CALL R8 1 0x40200E08, // 001E CONNECT R8 R7 R8 - 0x8C200F0E, // 001F GETMET R8 R7 K14 + 0x8C200F0D, // 001F GETMET R8 R7 K13 0x542A000C, // 0020 LDINT R10 13 0x7C200400, // 0021 CALL R8 2 - 0xB8221E00, // 0022 GETNGBL R8 K15 - 0x8C201110, // 0023 GETMET R8 R8 K16 - 0x88280101, // 0024 GETMBR R10 R0 K1 - 0x8C281512, // 0025 GETMET R10 R10 K18 - 0x7C280200, // 0026 CALL R10 1 - 0x002A220A, // 0027 ADD R10 K17 R10 - 0x582C0013, // 0028 LDCONST R11 K19 - 0x7C200600, // 0029 CALL R8 3 - 0xB8221E00, // 002A GETNGBL R8 K15 - 0x8C201110, // 002B GETMET R8 R8 K16 - 0x58280014, // 002C LDCONST R10 K20 - 0x582C0013, // 002D LDCONST R11 K19 - 0x7C200600, // 002E CALL R8 3 - 0xB8221E00, // 002F GETNGBL R8 K15 - 0x8C201110, // 0030 GETMET R8 R8 K16 - 0x8C280912, // 0031 GETMET R10 R4 K18 - 0x7C280200, // 0032 CALL R10 1 - 0x002A2A0A, // 0033 ADD R10 K21 R10 - 0x582C0013, // 0034 LDCONST R11 K19 - 0x7C200600, // 0035 CALL R8 3 - 0xB8221E00, // 0036 GETNGBL R8 K15 - 0x8C201110, // 0037 GETMET R8 R8 K16 - 0x8C280D12, // 0038 GETMET R10 R6 K18 - 0x7C280200, // 0039 CALL R10 1 - 0x002A2C0A, // 003A ADD R10 K22 R10 - 0x582C0013, // 003B LDCONST R11 K19 - 0x7C200600, // 003C CALL R8 3 - 0xB8221E00, // 003D GETNGBL R8 K15 - 0x8C201110, // 003E GETMET R8 R8 K16 - 0x8C280B12, // 003F GETMET R10 R5 K18 - 0x7C280200, // 0040 CALL R10 1 - 0x002A2E0A, // 0041 ADD R10 K23 R10 - 0x582C0013, // 0042 LDCONST R11 K19 - 0x7C200600, // 0043 CALL R8 3 - 0xB8221E00, // 0044 GETNGBL R8 K15 - 0x8C201110, // 0045 GETMET R8 R8 K16 - 0x8C280F12, // 0046 GETMET R10 R7 K18 - 0x7C280200, // 0047 CALL R10 1 - 0x002A300A, // 0048 ADD R10 K24 R10 - 0x582C0013, // 0049 LDCONST R11 K19 - 0x7C200600, // 004A CALL R8 3 - 0x8C200319, // 004B GETMET R8 R1 K25 - 0x5C280800, // 004C MOVE R10 R4 - 0x5C2C0E00, // 004D MOVE R11 R7 - 0x5C300A00, // 004E MOVE R12 R5 - 0x6034000C, // 004F GETGBL R13 G12 - 0x5C380C00, // 0050 MOVE R14 R6 - 0x7C340200, // 0051 CALL R13 1 - 0x543A000F, // 0052 LDINT R14 16 - 0x7C200C00, // 0053 CALL R8 6 - 0x8C24111A, // 0054 GETMET R9 R8 K26 - 0x5C2C0C00, // 0055 MOVE R11 R6 - 0x7C240400, // 0056 CALL R9 2 - 0x8C28111B, // 0057 GETMET R10 R8 K27 - 0x7C280200, // 0058 CALL R10 1 - 0xB82E1E00, // 0059 GETNGBL R11 K15 - 0x8C2C1710, // 005A GETMET R11 R11 K16 - 0x58340014, // 005B LDCONST R13 K20 - 0x58380013, // 005C LDCONST R14 K19 - 0x7C2C0600, // 005D CALL R11 3 - 0xB82E1E00, // 005E GETNGBL R11 K15 - 0x8C2C1710, // 005F GETMET R11 R11 K16 - 0x8C341312, // 0060 GETMET R13 R9 K18 - 0x7C340200, // 0061 CALL R13 1 - 0x0036380D, // 0062 ADD R13 K28 R13 - 0x58380013, // 0063 LDCONST R14 K19 - 0x7C2C0600, // 0064 CALL R11 3 - 0xB82E1E00, // 0065 GETNGBL R11 K15 - 0x8C2C1710, // 0066 GETMET R11 R11 K16 - 0x8C341512, // 0067 GETMET R13 R10 K18 - 0x7C340200, // 0068 CALL R13 1 - 0x00363A0D, // 0069 ADD R13 K29 R13 - 0x58380013, // 006A LDCONST R14 K19 - 0x7C2C0600, // 006B CALL R11 3 - 0xB82E1E00, // 006C GETNGBL R11 K15 - 0x8C2C1710, // 006D GETMET R11 R11 K16 - 0x58340014, // 006E LDCONST R13 K20 - 0x58380013, // 006F LDCONST R14 K19 - 0x7C2C0600, // 0070 CALL R11 3 - 0x882C0101, // 0071 GETMBR R11 R0 K1 - 0x8C2C170E, // 0072 GETMET R11 R11 K14 - 0x88340105, // 0073 GETMBR R13 R0 K5 - 0x7C2C0400, // 0074 CALL R11 2 - 0x882C0101, // 0075 GETMBR R11 R0 K1 - 0x402C1609, // 0076 CONNECT R11 R11 R9 - 0x882C0101, // 0077 GETMBR R11 R0 K1 - 0x402C160A, // 0078 CONNECT R11 R11 R10 - 0x80000000, // 0079 RET 0 + 0x8C20030E, // 0022 GETMET R8 R1 K14 + 0x5C280800, // 0023 MOVE R10 R4 + 0x5C2C0E00, // 0024 MOVE R11 R7 + 0x5C300A00, // 0025 MOVE R12 R5 + 0x6034000C, // 0026 GETGBL R13 G12 + 0x5C380C00, // 0027 MOVE R14 R6 + 0x7C340200, // 0028 CALL R13 1 + 0x543A000F, // 0029 LDINT R14 16 + 0x7C200C00, // 002A CALL R8 6 + 0x8C24110F, // 002B GETMET R9 R8 K15 + 0x5C2C0C00, // 002C MOVE R11 R6 + 0x7C240400, // 002D CALL R9 2 + 0x8C281110, // 002E GETMET R10 R8 K16 + 0x7C280200, // 002F CALL R10 1 + 0x882C0101, // 0030 GETMBR R11 R0 K1 + 0x8C2C170D, // 0031 GETMET R11 R11 K13 + 0x88340105, // 0032 GETMBR R13 R0 K5 + 0x7C2C0400, // 0033 CALL R11 2 + 0x882C0101, // 0034 GETMBR R11 R0 K1 + 0x402C1609, // 0035 CONNECT R11 R11 R9 + 0x882C0101, // 0036 GETMBR R11 R0 K1 + 0x402C160A, // 0037 CONNECT R11 R11 R10 + 0x80000000, // 0038 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: debug +********************************************************************/ +be_local_closure(Matter_Frame_debug, /* 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[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Frame), + /* K2 */ be_nested_str_weak(message_handler), + /* K3 */ be_nested_str_weak(decode_header), + /* K4 */ be_nested_str_weak(decode_payload), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(MTR_X3A_X20sending_X20decode_X3A_X20), + /* K8 */ be_nested_str_weak(inspect), + }), + be_str_weak(debug), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x5C140200, // 0003 MOVE R5 R1 + 0x7C080600, // 0004 CALL R2 3 + 0x8C0C0503, // 0005 GETMET R3 R2 K3 + 0x7C0C0200, // 0006 CALL R3 1 + 0x8C0C0504, // 0007 GETMET R3 R2 K4 + 0x7C0C0200, // 0008 CALL R3 1 + 0xB80E0A00, // 0009 GETNGBL R3 K5 + 0x8C0C0706, // 000A GETMET R3 R3 K6 + 0xB8160000, // 000B GETNGBL R5 K0 + 0x8C140B08, // 000C GETMET R5 R5 K8 + 0x5C1C0400, // 000D MOVE R7 R2 + 0x7C140400, // 000E CALL R5 2 + 0x00160E05, // 000F ADD R5 K7 R5 + 0x541A0003, // 0010 LDINT R6 4 + 0x7C0C0600, // 0011 CALL R3 3 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: build_standalone_ack +********************************************************************/ +be_local_closure(Matter_Frame_build_standalone_ack, /* 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[22]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(message_handler), + /* K2 */ be_nested_str_weak(remote_ip), + /* K3 */ be_nested_str_weak(remote_port), + /* K4 */ be_nested_str_weak(flag_s), + /* K5 */ be_nested_str_weak(flag_dsiz), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(dest_node_id_8), + /* K8 */ be_nested_str_weak(source_node_id), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(session), + /* K11 */ be_nested_str_weak(message_counter), + /* K12 */ be_nested_str_weak(counter_snd_next), + /* K13 */ be_nested_str_weak(local_session_id), + /* K14 */ be_nested_str_weak(initiator_session_id), + /* K15 */ be_nested_str_weak(x_flag_i), + /* K16 */ be_nested_str_weak(opcode), + /* K17 */ be_nested_str_weak(exchange_id), + /* K18 */ be_nested_str_weak(protocol_id), + /* K19 */ be_nested_str_weak(x_flag_a), + /* K20 */ be_nested_str_weak(ack_message_counter), + /* K21 */ be_nested_str_weak(x_flag_r), + }), + be_str_weak(build_standalone_ack), + &be_const_str_solidified, + ( &(const binstruction[46]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x600C0006, // 0001 GETGBL R3 G6 + 0x5C100000, // 0002 MOVE R4 R0 + 0x7C0C0200, // 0003 CALL R3 1 + 0x88100101, // 0004 GETMBR R4 R0 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x88100102, // 0006 GETMBR R4 R0 K2 + 0x900E0404, // 0007 SETMBR R3 K2 R4 + 0x88100103, // 0008 GETMBR R4 R0 K3 + 0x900E0604, // 0009 SETMBR R3 K3 R4 + 0x88100104, // 000A GETMBR R4 R0 K4 + 0x78120003, // 000B JMPF R4 #0010 + 0x900E0B06, // 000C SETMBR R3 K5 K6 + 0x88100108, // 000D GETMBR R4 R0 K8 + 0x900E0E04, // 000E SETMBR R3 K7 R4 + 0x70020000, // 000F JMP #0011 + 0x900E0B09, // 0010 SETMBR R3 K5 K9 + 0x8810010A, // 0011 GETMBR R4 R0 K10 + 0x900E1404, // 0012 SETMBR R3 K10 R4 + 0x8810010A, // 0013 GETMBR R4 R0 K10 + 0x8C10090C, // 0014 GETMET R4 R4 K12 + 0x7C100200, // 0015 CALL R4 1 + 0x900E1604, // 0016 SETMBR R3 K11 R4 + 0x8810010A, // 0017 GETMBR R4 R0 K10 + 0x8810090E, // 0018 GETMBR R4 R4 K14 + 0x900E1A04, // 0019 SETMBR R3 K13 R4 + 0x8810010F, // 001A GETMBR R4 R0 K15 + 0x78120001, // 001B JMPF R4 #001E + 0x58100009, // 001C LDCONST R4 K9 + 0x70020000, // 001D JMP #001F + 0x58100006, // 001E LDCONST R4 K6 + 0x900E1E04, // 001F SETMBR R3 K15 R4 + 0x5412000F, // 0020 LDINT R4 16 + 0x900E2004, // 0021 SETMBR R3 K16 R4 + 0x88100111, // 0022 GETMBR R4 R0 K17 + 0x900E2204, // 0023 SETMBR R3 K17 R4 + 0x900E2509, // 0024 SETMBR R3 K18 K9 + 0x900E2706, // 0025 SETMBR R3 K19 K6 + 0x8810010B, // 0026 GETMBR R4 R0 K11 + 0x900E2804, // 0027 SETMBR R3 K20 R4 + 0x78060001, // 0028 JMPF R1 #002B + 0x58100006, // 0029 LDCONST R4 K6 + 0x70020000, // 002A JMP #002C + 0x58100009, // 002B LDCONST R4 K9 + 0x900E2A04, // 002C SETMBR R3 K21 R4 + 0x80040600, // 002D RET 1 R3 }) ) ); @@ -187,8 +453,8 @@ be_local_closure(Matter_Frame_encrypt, /* name */ ********************************************************************/ be_local_closure(Matter_Frame_build_response, /* name */ be_nested_proto( - 12, /* nstack */ - 3, /* argc */ + 13, /* nstack */ + 4, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -210,9 +476,9 @@ be_local_closure(Matter_Frame_build_response, /* name */ /* K11 */ be_nested_str_weak(local_session_id), /* K12 */ be_nested_str_weak(initiator_session_id), /* K13 */ be_nested_str_weak(message_counter), - /* K14 */ be_nested_str_weak(counter_snd), - /* K15 */ be_nested_str_weak(next), - /* K16 */ be_nested_str_weak(_counter_insecure_snd), + /* K14 */ be_nested_str_weak(counter_snd_next), + /* K15 */ be_nested_str_weak(_counter_insecure_snd), + /* K16 */ be_nested_str_weak(next), /* K17 */ be_nested_str_weak(x_flag_i), /* K18 */ be_nested_str_weak(opcode), /* K19 */ be_nested_str_weak(exchange_id), @@ -226,94 +492,104 @@ be_local_closure(Matter_Frame_build_response, /* name */ /* K27 */ be_nested_str_weak(0x_X2502X), /* K28 */ be_nested_str_weak(tasmota), /* K29 */ be_nested_str_weak(log), - /* K30 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), + /* K30 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20_X25s), /* K31 */ be_const_int(2), }), be_str_weak(build_response), &be_const_str_solidified, - ( &(const binstruction[82]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0x60100006, // 0001 GETGBL R4 G6 - 0x5C140000, // 0002 MOVE R5 R0 - 0x7C100200, // 0003 CALL R4 1 - 0x88140101, // 0004 GETMBR R5 R0 K1 - 0x7C100200, // 0005 CALL R4 1 - 0x88140102, // 0006 GETMBR R5 R0 K2 - 0x90120405, // 0007 SETMBR R4 K2 R5 - 0x88140103, // 0008 GETMBR R5 R0 K3 - 0x90120605, // 0009 SETMBR R4 K3 R5 - 0x88140104, // 000A GETMBR R5 R0 K4 - 0x78160003, // 000B JMPF R5 #0010 - 0x90120B06, // 000C SETMBR R4 K5 K6 - 0x88140108, // 000D GETMBR R5 R0 K8 - 0x90120E05, // 000E SETMBR R4 K7 R5 - 0x70020000, // 000F JMP #0011 - 0x90120B09, // 0010 SETMBR R4 K5 K9 - 0x8814010A, // 0011 GETMBR R5 R0 K10 - 0x90121405, // 0012 SETMBR R4 K10 R5 - 0x8814010B, // 0013 GETMBR R5 R0 K11 - 0x20140B09, // 0014 NE R5 R5 K9 - 0x7816000E, // 0015 JMPF R5 #0025 - 0x8814010A, // 0016 GETMBR R5 R0 K10 - 0x7816000C, // 0017 JMPF R5 #0025 - 0x8814010A, // 0018 GETMBR R5 R0 K10 - 0x88140B0C, // 0019 GETMBR R5 R5 K12 - 0x20140B09, // 001A NE R5 R5 K9 - 0x78160008, // 001B JMPF R5 #0025 + ( &(const binstruction[92]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x4C140000, // 0001 LDNIL R5 + 0x1C140605, // 0002 EQ R5 R3 R5 + 0x78160005, // 0003 JMPF R5 #000A + 0x60140006, // 0004 GETGBL R5 G6 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C140200, // 0006 CALL R5 1 + 0x88180101, // 0007 GETMBR R6 R0 K1 + 0x7C140200, // 0008 CALL R5 1 + 0x5C0C0A00, // 0009 MOVE R3 R5 + 0x88140102, // 000A GETMBR R5 R0 K2 + 0x900E0405, // 000B SETMBR R3 K2 R5 + 0x88140103, // 000C GETMBR R5 R0 K3 + 0x900E0605, // 000D SETMBR R3 K3 R5 + 0x88140104, // 000E GETMBR R5 R0 K4 + 0x78160003, // 000F JMPF R5 #0014 + 0x900E0B06, // 0010 SETMBR R3 K5 K6 + 0x88140108, // 0011 GETMBR R5 R0 K8 + 0x900E0E05, // 0012 SETMBR R3 K7 R5 + 0x70020000, // 0013 JMP #0015 + 0x900E0B09, // 0014 SETMBR R3 K5 K9 + 0x8814010A, // 0015 GETMBR R5 R0 K10 + 0x900E1405, // 0016 SETMBR R3 K10 R5 + 0x8814010B, // 0017 GETMBR R5 R0 K11 + 0x20140B09, // 0018 NE R5 R5 K9 + 0x7816000D, // 0019 JMPF R5 #0028 + 0x8814010A, // 001A GETMBR R5 R0 K10 + 0x7816000B, // 001B JMPF R5 #0028 0x8814010A, // 001C GETMBR R5 R0 K10 - 0x88140B0E, // 001D GETMBR R5 R5 K14 - 0x8C140B0F, // 001E GETMET R5 R5 K15 - 0x7C140200, // 001F CALL R5 1 - 0x90121A05, // 0020 SETMBR R4 K13 R5 - 0x8814010A, // 0021 GETMBR R5 R0 K10 - 0x88140B0C, // 0022 GETMBR R5 R5 K12 - 0x90121605, // 0023 SETMBR R4 K11 R5 - 0x70020005, // 0024 JMP #002B - 0x8814010A, // 0025 GETMBR R5 R0 K10 - 0x88140B10, // 0026 GETMBR R5 R5 K16 - 0x8C140B0F, // 0027 GETMET R5 R5 K15 - 0x7C140200, // 0028 CALL R5 1 - 0x90121A05, // 0029 SETMBR R4 K13 R5 - 0x90121709, // 002A SETMBR R4 K11 K9 - 0x90122309, // 002B SETMBR R4 K17 K9 - 0x90122401, // 002C SETMBR R4 K18 R1 - 0x88140113, // 002D GETMBR R5 R0 K19 - 0x90122605, // 002E SETMBR R4 K19 R5 - 0x88140114, // 002F GETMBR R5 R0 K20 - 0x90122805, // 0030 SETMBR R4 K20 R5 - 0x88140115, // 0031 GETMBR R5 R0 K21 - 0x78160002, // 0032 JMPF R5 #0036 - 0x90122D06, // 0033 SETMBR R4 K22 K6 - 0x8814010D, // 0034 GETMBR R5 R0 K13 - 0x90122E05, // 0035 SETMBR R4 K23 R5 - 0x780A0001, // 0036 JMPF R2 #0039 - 0x58140006, // 0037 LDCONST R5 K6 - 0x70020000, // 0038 JMP #003A - 0x58140009, // 0039 LDCONST R5 K9 - 0x90122A05, // 003A SETMBR R4 K21 R5 - 0x8814090B, // 003B GETMBR R5 R4 K11 - 0x1C140B09, // 003C EQ R5 R5 K9 - 0x78160012, // 003D JMPF R5 #0051 - 0xB8163000, // 003E GETNGBL R5 K24 - 0x8C140B19, // 003F GETMET R5 R5 K25 - 0x881C0912, // 0040 GETMBR R7 R4 K18 - 0x7C140400, // 0041 CALL R5 2 - 0x5C180A00, // 0042 MOVE R6 R5 - 0x741A0004, // 0043 JMPT R6 #0049 - 0x8C18071A, // 0044 GETMET R6 R3 K26 - 0x5820001B, // 0045 LDCONST R8 K27 - 0x88240912, // 0046 GETMBR R9 R4 K18 - 0x7C180600, // 0047 CALL R6 3 - 0x5C140C00, // 0048 MOVE R5 R6 - 0xB81A3800, // 0049 GETNGBL R6 K28 - 0x8C180D1D, // 004A GETMET R6 R6 K29 - 0x8C20071A, // 004B GETMET R8 R3 K26 - 0x5828001E, // 004C LDCONST R10 K30 - 0x5C2C0A00, // 004D MOVE R11 R5 - 0x7C200600, // 004E CALL R8 3 - 0x5824001F, // 004F LDCONST R9 K31 - 0x7C180600, // 0050 CALL R6 3 - 0x80040800, // 0051 RET 1 R4 + 0x88140B0C, // 001D GETMBR R5 R5 K12 + 0x20140B09, // 001E NE R5 R5 K9 + 0x78160007, // 001F JMPF R5 #0028 + 0x8814010A, // 0020 GETMBR R5 R0 K10 + 0x8C140B0E, // 0021 GETMET R5 R5 K14 + 0x7C140200, // 0022 CALL R5 1 + 0x900E1A05, // 0023 SETMBR R3 K13 R5 + 0x8814010A, // 0024 GETMBR R5 R0 K10 + 0x88140B0C, // 0025 GETMBR R5 R5 K12 + 0x900E1605, // 0026 SETMBR R3 K11 R5 + 0x70020005, // 0027 JMP #002E + 0x8814010A, // 0028 GETMBR R5 R0 K10 + 0x88140B0F, // 0029 GETMBR R5 R5 K15 + 0x8C140B10, // 002A GETMET R5 R5 K16 + 0x7C140200, // 002B CALL R5 1 + 0x900E1A05, // 002C SETMBR R3 K13 R5 + 0x900E1709, // 002D SETMBR R3 K11 K9 + 0x88140111, // 002E GETMBR R5 R0 K17 + 0x78160001, // 002F JMPF R5 #0032 + 0x58140009, // 0030 LDCONST R5 K9 + 0x70020000, // 0031 JMP #0033 + 0x58140006, // 0032 LDCONST R5 K6 + 0x900E2205, // 0033 SETMBR R3 K17 R5 + 0x900E2401, // 0034 SETMBR R3 K18 R1 + 0x88140113, // 0035 GETMBR R5 R0 K19 + 0x900E2605, // 0036 SETMBR R3 K19 R5 + 0x88140114, // 0037 GETMBR R5 R0 K20 + 0x900E2805, // 0038 SETMBR R3 K20 R5 + 0x88140115, // 0039 GETMBR R5 R0 K21 + 0x78160002, // 003A JMPF R5 #003E + 0x900E2D06, // 003B SETMBR R3 K22 K6 + 0x8814010D, // 003C GETMBR R5 R0 K13 + 0x900E2E05, // 003D SETMBR R3 K23 R5 + 0x780A0001, // 003E JMPF R2 #0041 + 0x58140006, // 003F LDCONST R5 K6 + 0x70020000, // 0040 JMP #0042 + 0x58140009, // 0041 LDCONST R5 K9 + 0x900E2A05, // 0042 SETMBR R3 K21 R5 + 0x8814070B, // 0043 GETMBR R5 R3 K11 + 0x1C140B09, // 0044 EQ R5 R5 K9 + 0x78160014, // 0045 JMPF R5 #005B + 0xB8163000, // 0046 GETNGBL R5 K24 + 0x8C140B19, // 0047 GETMET R5 R5 K25 + 0x881C0712, // 0048 GETMBR R7 R3 K18 + 0x7C140400, // 0049 CALL R5 2 + 0x5C180A00, // 004A MOVE R6 R5 + 0x741A0004, // 004B JMPT R6 #0051 + 0x8C18091A, // 004C GETMET R6 R4 K26 + 0x5820001B, // 004D LDCONST R8 K27 + 0x88240712, // 004E GETMBR R9 R3 K18 + 0x7C180600, // 004F CALL R6 3 + 0x5C140C00, // 0050 MOVE R5 R6 + 0xB81A3800, // 0051 GETNGBL R6 K28 + 0x8C180D1D, // 0052 GETMET R6 R6 K29 + 0x8C20091A, // 0053 GETMET R8 R4 K26 + 0x5828001E, // 0054 LDCONST R10 K30 + 0x882C070A, // 0055 GETMBR R11 R3 K10 + 0x882C170B, // 0056 GETMBR R11 R11 K11 + 0x5C300A00, // 0057 MOVE R12 R5 + 0x7C200800, // 0058 CALL R8 4 + 0x5824001F, // 0059 LDCONST R9 K31 + 0x7C180600, // 005A CALL R6 3 + 0x80040600, // 005B RET 1 R3 }) ) ); @@ -321,32 +597,94 @@ be_local_closure(Matter_Frame_build_response, /* name */ /******************************************************************** -** Solidified function: init +** Solidified function: initiate_response ********************************************************************/ -be_local_closure(Matter_Frame_init, /* name */ +be_local_closure(Matter_Frame_initiate_response, /* name */ be_nested_proto( - 5, /* nstack */ + 10, /* nstack */ 5, /* argc */ - 2, /* varg */ + 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_nested_str_weak(message_handler), - /* K1 */ be_nested_str_weak(raw), - /* K2 */ be_nested_str_weak(remote_ip), - /* K3 */ be_nested_str_weak(remote_port), + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Frame), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Frame), + /* K4 */ be_nested_str_weak(remote_ip), + /* K5 */ be_nested_str_weak(_ip), + /* K6 */ be_nested_str_weak(remote_port), + /* K7 */ be_nested_str_weak(_port), + /* K8 */ be_nested_str_weak(flag_dsiz), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(session), + /* K11 */ be_nested_str_weak(initiator_session_id), + /* K12 */ be_nested_str_weak(message_counter), + /* K13 */ be_nested_str_weak(counter_snd_next), + /* K14 */ be_nested_str_weak(local_session_id), + /* K15 */ be_nested_str_weak(_counter_insecure_snd), + /* K16 */ be_nested_str_weak(next), + /* K17 */ be_nested_str_weak(x_flag_i), + /* K18 */ be_const_int(1), + /* K19 */ be_nested_str_weak(opcode), + /* K20 */ be_nested_str_weak(_exchange_id), + /* K21 */ be_nested_str_weak(exchange_id), + /* K22 */ be_nested_str_weak(protocol_id), + /* K23 */ be_nested_str_weak(x_flag_r), }), - be_str_weak(init), + be_str_weak(initiate_response), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x90020604, // 0003 SETMBR R0 K3 R4 - 0x80000000, // 0004 RET 0 + ( &(const binstruction[47]) { /* code */ + 0x58140000, // 0000 LDCONST R5 K0 + 0xA41A0200, // 0001 IMPORT R6 K1 + 0x4C1C0000, // 0002 LDNIL R7 + 0x1C1C0807, // 0003 EQ R7 R4 R7 + 0x781E0004, // 0004 JMPF R7 #000A + 0xB81E0400, // 0005 GETNGBL R7 K2 + 0x8C1C0F03, // 0006 GETMET R7 R7 K3 + 0x5C240000, // 0007 MOVE R9 R0 + 0x7C1C0400, // 0008 CALL R7 2 + 0x5C100E00, // 0009 MOVE R4 R7 + 0x881C0305, // 000A GETMBR R7 R1 K5 + 0x90120807, // 000B SETMBR R4 K4 R7 + 0x881C0307, // 000C GETMBR R7 R1 K7 + 0x90120C07, // 000D SETMBR R4 K6 R7 + 0x90121109, // 000E SETMBR R4 K8 K9 + 0x90121401, // 000F SETMBR R4 K10 R1 + 0x78060008, // 0010 JMPF R1 #001A + 0x881C030B, // 0011 GETMBR R7 R1 K11 + 0x201C0F09, // 0012 NE R7 R7 K9 + 0x781E0005, // 0013 JMPF R7 #001A + 0x8C1C030D, // 0014 GETMET R7 R1 K13 + 0x7C1C0200, // 0015 CALL R7 1 + 0x90121807, // 0016 SETMBR R4 K12 R7 + 0x881C030B, // 0017 GETMBR R7 R1 K11 + 0x90121C07, // 0018 SETMBR R4 K14 R7 + 0x70020004, // 0019 JMP #001F + 0x881C030F, // 001A GETMBR R7 R1 K15 + 0x8C1C0F10, // 001B GETMET R7 R7 K16 + 0x7C1C0200, // 001C CALL R7 1 + 0x90121807, // 001D SETMBR R4 K12 R7 + 0x90121D09, // 001E SETMBR R4 K14 K9 + 0x90122312, // 001F SETMBR R4 K17 K18 + 0x90122602, // 0020 SETMBR R4 K19 R2 + 0x881C0314, // 0021 GETMBR R7 R1 K20 + 0x001C0F12, // 0022 ADD R7 R7 K18 + 0x90062807, // 0023 SETMBR R1 K20 R7 + 0x881C0314, // 0024 GETMBR R7 R1 K20 + 0x5422FFFF, // 0025 LDINT R8 65536 + 0x301C0E08, // 0026 OR R7 R7 R8 + 0x90122A07, // 0027 SETMBR R4 K21 R7 + 0x90122D12, // 0028 SETMBR R4 K22 K18 + 0x780E0001, // 0029 JMPF R3 #002C + 0x581C0012, // 002A LDCONST R7 K18 + 0x70020000, // 002B JMP #002D + 0x581C0009, // 002C LDCONST R7 K9 + 0x90122E07, // 002D SETMBR R4 K23 R7 + 0x80040800, // 002E RET 1 R4 }) ) ); @@ -519,6 +857,39 @@ be_local_closure(Matter_Frame_decode_header, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Frame_init, /* name */ + be_nested_proto( + 5, /* 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(message_handler), + /* K1 */ be_nested_str_weak(raw), + /* K2 */ be_nested_str_weak(remote_ip), + /* K3 */ be_nested_str_weak(remote_port), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x90020604, // 0003 SETMBR R0 K3 R4 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: decode_payload ********************************************************************/ @@ -555,7 +926,7 @@ be_local_closure(Matter_Frame_decode_payload, /* name */ }), be_str_weak(decode_payload), &be_const_str_solidified, - ( &(const binstruction[87]) { /* code */ + ( &(const binstruction[93]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 0x88080101, // 0001 GETMBR R2 R0 K1 0x8C0C0503, // 0002 GETMET R3 R2 K3 @@ -608,191 +979,47 @@ be_local_closure(Matter_Frame_decode_payload, /* name */ 0x5818000A, // 0031 LDCONST R6 K10 0x7C0C0600, // 0032 CALL R3 3 0x90021C03, // 0033 SETMBR R0 K14 R3 - 0x8C0C0503, // 0034 GETMET R3 R2 K3 - 0x54160003, // 0035 LDINT R5 4 - 0x00140205, // 0036 ADD R5 R1 R5 - 0x5818000A, // 0037 LDCONST R6 K10 - 0x7C0C0600, // 0038 CALL R3 3 - 0x90021E03, // 0039 SETMBR R0 K15 R3 - 0x540E0005, // 003A LDINT R3 6 - 0x00040203, // 003B ADD R1 R1 R3 - 0x880C0105, // 003C GETMBR R3 R0 K5 - 0x780E0005, // 003D JMPF R3 #0044 - 0x8C0C0503, // 003E GETMET R3 R2 K3 - 0x5C140200, // 003F MOVE R5 R1 - 0x5818000A, // 0040 LDCONST R6 K10 - 0x7C0C0600, // 0041 CALL R3 3 - 0x90022003, // 0042 SETMBR R0 K16 R3 - 0x0004030A, // 0043 ADD R1 R1 K10 - 0x880C010B, // 0044 GETMBR R3 R0 K11 - 0x780E0006, // 0045 JMPF R3 #004D - 0x8C0C0503, // 0046 GETMET R3 R2 K3 - 0x5C140200, // 0047 MOVE R5 R1 - 0x541A0003, // 0048 LDINT R6 4 - 0x7C0C0600, // 0049 CALL R3 3 - 0x90022203, // 004A SETMBR R0 K17 R3 - 0x540E0003, // 004B LDINT R3 4 - 0x00040203, // 004C ADD R1 R1 R3 - 0x880C0107, // 004D GETMBR R3 R0 K7 - 0x780E0005, // 004E JMPF R3 #0055 - 0x8C0C0503, // 004F GETMET R3 R2 K3 - 0x5C140200, // 0050 MOVE R5 R1 - 0x5818000A, // 0051 LDCONST R6 K10 - 0x7C0C0600, // 0052 CALL R3 3 - 0x0010070A, // 0053 ADD R4 R3 K10 - 0x00040204, // 0054 ADD R1 R1 R4 - 0x90022401, // 0055 SETMBR R0 K18 R1 - 0x80040000, // 0056 RET 1 R0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: debug -********************************************************************/ -be_local_closure(Matter_Frame_debug, /* 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[10]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(Frame), - /* K2 */ be_nested_str_weak(message_handler), - /* K3 */ be_nested_str_weak(decode_header), - /* K4 */ be_nested_str_weak(decode_payload), - /* K5 */ be_nested_str_weak(tasmota), - /* K6 */ be_nested_str_weak(log), - /* K7 */ be_nested_str_weak(MTR_X3A_X20sending_X20decode_X3A_X20), - /* K8 */ be_nested_str_weak(inspect), - /* K9 */ be_const_int(3), - }), - be_str_weak(debug), - &be_const_str_solidified, - ( &(const binstruction[19]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x88100102, // 0002 GETMBR R4 R0 K2 - 0x5C140200, // 0003 MOVE R5 R1 - 0x7C080600, // 0004 CALL R2 3 - 0x8C0C0503, // 0005 GETMET R3 R2 K3 - 0x7C0C0200, // 0006 CALL R3 1 - 0x8C0C0504, // 0007 GETMET R3 R2 K4 - 0x7C0C0200, // 0008 CALL R3 1 - 0xB80E0A00, // 0009 GETNGBL R3 K5 - 0x8C0C0706, // 000A GETMET R3 R3 K6 - 0xB8160000, // 000B GETNGBL R5 K0 - 0x8C140B08, // 000C GETMET R5 R5 K8 - 0x5C1C0400, // 000D MOVE R7 R2 - 0x7C140400, // 000E CALL R5 2 - 0x00160E05, // 000F ADD R5 K7 R5 - 0x58180009, // 0010 LDCONST R6 K9 - 0x7C0C0600, // 0011 CALL R3 3 - 0x80000000, // 0012 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: build_standalone_ack -********************************************************************/ -be_local_closure(Matter_Frame_build_standalone_ack, /* 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[28]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(message_handler), - /* K2 */ be_nested_str_weak(flag_s), - /* K3 */ be_nested_str_weak(flag_dsiz), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(dest_node_id_8), - /* K6 */ be_nested_str_weak(source_node_id), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(session), - /* K9 */ be_nested_str_weak(message_counter), - /* K10 */ be_nested_str_weak(counter_snd), - /* K11 */ be_nested_str_weak(next), - /* K12 */ be_nested_str_weak(local_session_id), - /* K13 */ be_nested_str_weak(initiator_session_id), - /* K14 */ be_nested_str_weak(x_flag_i), - /* K15 */ be_nested_str_weak(opcode), - /* K16 */ be_nested_str_weak(exchange_id), - /* K17 */ be_nested_str_weak(protocol_id), - /* K18 */ be_nested_str_weak(x_flag_a), - /* K19 */ be_nested_str_weak(ack_message_counter), - /* K20 */ be_nested_str_weak(x_flag_r), - /* K21 */ be_nested_str_weak(tasmota), - /* K22 */ be_nested_str_weak(log), - /* K23 */ be_nested_str_weak(format), - /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X20_X20_X20_X20_X25s), - /* K25 */ be_nested_str_weak(matter), - /* K26 */ be_nested_str_weak(get_opcode_name), - /* K27 */ be_const_int(2), - }), - be_str_weak(build_standalone_ack), - &be_const_str_solidified, - ( &(const binstruction[45]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x60080006, // 0001 GETGBL R2 G6 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C080200, // 0003 CALL R2 1 - 0x880C0101, // 0004 GETMBR R3 R0 K1 - 0x7C080200, // 0005 CALL R2 1 - 0x880C0102, // 0006 GETMBR R3 R0 K2 - 0x780E0003, // 0007 JMPF R3 #000C - 0x900A0704, // 0008 SETMBR R2 K3 K4 - 0x880C0106, // 0009 GETMBR R3 R0 K6 - 0x900A0A03, // 000A SETMBR R2 K5 R3 - 0x70020000, // 000B JMP #000D - 0x900A0707, // 000C SETMBR R2 K3 K7 - 0x880C0108, // 000D GETMBR R3 R0 K8 - 0x900A1003, // 000E SETMBR R2 K8 R3 - 0x880C0108, // 000F GETMBR R3 R0 K8 - 0x880C070A, // 0010 GETMBR R3 R3 K10 - 0x8C0C070B, // 0011 GETMET R3 R3 K11 - 0x7C0C0200, // 0012 CALL R3 1 - 0x900A1203, // 0013 SETMBR R2 K9 R3 - 0x880C0108, // 0014 GETMBR R3 R0 K8 - 0x880C070D, // 0015 GETMBR R3 R3 K13 - 0x900A1803, // 0016 SETMBR R2 K12 R3 - 0x900A1D07, // 0017 SETMBR R2 K14 K7 - 0x540E000F, // 0018 LDINT R3 16 - 0x900A1E03, // 0019 SETMBR R2 K15 R3 - 0x880C0110, // 001A GETMBR R3 R0 K16 - 0x900A2003, // 001B SETMBR R2 K16 R3 - 0x900A2307, // 001C SETMBR R2 K17 K7 - 0x900A2504, // 001D SETMBR R2 K18 K4 - 0x880C0109, // 001E GETMBR R3 R0 K9 - 0x900A2603, // 001F SETMBR R2 K19 R3 - 0x900A2907, // 0020 SETMBR R2 K20 K7 - 0xB80E2A00, // 0021 GETNGBL R3 K21 - 0x8C0C0716, // 0022 GETMET R3 R3 K22 - 0x8C140317, // 0023 GETMET R5 R1 K23 - 0x581C0018, // 0024 LDCONST R7 K24 - 0xB8223200, // 0025 GETNGBL R8 K25 - 0x8C20111A, // 0026 GETMET R8 R8 K26 - 0x8828050F, // 0027 GETMBR R10 R2 K15 - 0x7C200400, // 0028 CALL R8 2 - 0x7C140600, // 0029 CALL R5 3 - 0x5818001B, // 002A LDCONST R6 K27 - 0x7C0C0600, // 002B CALL R3 3 - 0x80040400, // 002C RET 1 R2 + 0x880C010C, // 0034 GETMBR R3 R0 K12 + 0x740E0003, // 0035 JMPT R3 #003A + 0x880C010E, // 0036 GETMBR R3 R0 K14 + 0x5412FFFF, // 0037 LDINT R4 65536 + 0x300C0604, // 0038 OR R3 R3 R4 + 0x90021C03, // 0039 SETMBR R0 K14 R3 + 0x8C0C0503, // 003A GETMET R3 R2 K3 + 0x54160003, // 003B LDINT R5 4 + 0x00140205, // 003C ADD R5 R1 R5 + 0x5818000A, // 003D LDCONST R6 K10 + 0x7C0C0600, // 003E CALL R3 3 + 0x90021E03, // 003F SETMBR R0 K15 R3 + 0x540E0005, // 0040 LDINT R3 6 + 0x00040203, // 0041 ADD R1 R1 R3 + 0x880C0105, // 0042 GETMBR R3 R0 K5 + 0x780E0005, // 0043 JMPF R3 #004A + 0x8C0C0503, // 0044 GETMET R3 R2 K3 + 0x5C140200, // 0045 MOVE R5 R1 + 0x5818000A, // 0046 LDCONST R6 K10 + 0x7C0C0600, // 0047 CALL R3 3 + 0x90022003, // 0048 SETMBR R0 K16 R3 + 0x0004030A, // 0049 ADD R1 R1 K10 + 0x880C010B, // 004A GETMBR R3 R0 K11 + 0x780E0006, // 004B JMPF R3 #0053 + 0x8C0C0503, // 004C GETMET R3 R2 K3 + 0x5C140200, // 004D MOVE R5 R1 + 0x541A0003, // 004E LDINT R6 4 + 0x7C0C0600, // 004F CALL R3 3 + 0x90022203, // 0050 SETMBR R0 K17 R3 + 0x540E0003, // 0051 LDINT R3 4 + 0x00040203, // 0052 ADD R1 R1 R3 + 0x880C0107, // 0053 GETMBR R3 R0 K7 + 0x780E0005, // 0054 JMPF R3 #005B + 0x8C0C0503, // 0055 GETMET R3 R2 K3 + 0x5C140200, // 0056 MOVE R5 R1 + 0x5818000A, // 0057 LDCONST R6 K10 + 0x7C0C0600, // 0058 CALL R3 3 + 0x0010070A, // 0059 ADD R4 R3 K10 + 0x00040204, // 005A ADD R1 R1 R4 + 0x90022401, // 005B SETMBR R0 K18 R1 + 0x80040000, // 005C RET 1 R0 }) ) ); @@ -812,47 +1039,48 @@ be_local_closure(Matter_Frame_decrypt, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[36]) { /* constants */ + ( &(const bvalue[37]) { /* constants */ /* K0 */ be_nested_str_weak(crypto), /* K1 */ be_nested_str_weak(session), /* K2 */ be_nested_str_weak(raw), /* K3 */ be_const_int(2147483647), /* K4 */ be_nested_str_weak(get_i2r), /* K5 */ be_nested_str_weak(sec_p), - /* K6 */ be_nested_str_weak(get_i2r_privacy), - /* K7 */ be_nested_str_weak(add), - /* K8 */ be_nested_str_weak(local_session_id), - /* K9 */ be_nested_str_weak(payload_idx), - /* K10 */ be_const_int(1), - /* K11 */ be_nested_str_weak(AES_CTR), - /* K12 */ be_nested_str_weak(decrypt), - /* K13 */ be_const_int(2), - /* K14 */ be_const_int(0), - /* K15 */ be_const_int(3), - /* K16 */ be_nested_str_weak(self), - /* K17 */ be_nested_str_weak(flags), - /* K18 */ be_nested_str_weak(message_counter), - /* K19 */ be_nested_str_weak(source_node_id), - /* K20 */ be_nested_str_weak(peer_node_id), - /* K21 */ be_nested_str_weak(resize), - /* K22 */ be_nested_str_weak(tasmota), - /* K23 */ be_nested_str_weak(log), - /* K24 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), - /* K25 */ be_nested_str_weak(MTR_X3A_X20i2r_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K26 */ be_nested_str_weak(tohex), - /* K27 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K28 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K29 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K30 */ be_nested_str_weak(MTR_X3A_X20mic_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K31 */ be_nested_str_weak(AES_CCM), - /* K32 */ be_nested_str_weak(tag), - /* K33 */ be_nested_str_weak(MTR_X3A_X20cleartext_X20_X20_X20_X3D), - /* K34 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), - /* K35 */ be_nested_str_weak(MTR_X3A_X20rejected_X20packet_X20due_X20to_X20invalid_X20MIC), + /* K6 */ be_nested_str_weak(tasmota), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X3E_X20Compute_X20Privacy_X20TODO), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_str_weak(get_i2r_privacy), + /* K11 */ be_nested_str_weak(add), + /* K12 */ be_nested_str_weak(local_session_id), + /* K13 */ be_nested_str_weak(payload_idx), + /* K14 */ be_const_int(1), + /* K15 */ be_nested_str_weak(AES_CTR), + /* K16 */ be_nested_str_weak(decrypt), + /* K17 */ be_const_int(0), + /* K18 */ be_const_int(3), + /* K19 */ be_nested_str_weak(self), + /* K20 */ be_nested_str_weak(flags), + /* K21 */ be_nested_str_weak(message_counter), + /* K22 */ be_nested_str_weak(source_node_id), + /* K23 */ be_nested_str_weak(peer_node_id), + /* K24 */ be_nested_str_weak(resize), + /* K25 */ be_nested_str_weak(MTR_X3A_X20_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A_X2A), + /* K26 */ be_nested_str_weak(MTR_X3A_X20i2r_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K27 */ be_nested_str_weak(tohex), + /* K28 */ be_nested_str_weak(MTR_X3A_X20p_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K29 */ be_nested_str_weak(MTR_X3A_X20a_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K30 */ be_nested_str_weak(MTR_X3A_X20n_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K31 */ be_nested_str_weak(MTR_X3A_X20mic_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K32 */ be_nested_str_weak(AES_CCM), + /* K33 */ be_nested_str_weak(tag), + /* K34 */ be_nested_str_weak(MTR_X3A_X20cleartext_X20_X20_X20_X3D), + /* K35 */ be_nested_str_weak(MTR_X3A_X20tag_X20_X20_X20_X20_X20_X20_X20_X20_X20_X3D), + /* K36 */ be_nested_str_weak(MTR_X3A_X20rejected_X20packet_X20due_X20to_X20invalid_X20MIC), }), be_str_weak(decrypt), &be_const_str_solidified, - ( &(const binstruction[165]) { /* code */ + ( &(const binstruction[170]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x88080101, // 0001 GETMBR R2 R0 K1 0x880C0102, // 0002 GETMBR R3 R0 K2 @@ -862,360 +1090,167 @@ be_local_closure(Matter_Frame_decrypt, /* name */ 0x8C140504, // 0006 GETMET R5 R2 K4 0x7C140200, // 0007 CALL R5 1 0x88180105, // 0008 GETMBR R6 R0 K5 - 0x781A0025, // 0009 JMPF R6 #0030 - 0x8C180506, // 000A GETMET R6 R2 K6 - 0x7C180200, // 000B CALL R6 1 - 0x601C0015, // 000C GETGBL R7 G21 - 0x7C1C0000, // 000D CALL R7 0 - 0x8C1C0F07, // 000E GETMET R7 R7 K7 - 0x88240108, // 000F GETMBR R9 R0 K8 - 0x5429FFFD, // 0010 LDINT R10 -2 - 0x7C1C0600, // 0011 CALL R7 3 - 0x54220004, // 0012 LDINT R8 5 - 0x5426000E, // 0013 LDINT R9 15 - 0x40201009, // 0014 CONNECT R8 R8 R9 - 0x94200808, // 0015 GETIDX R8 R4 R8 - 0x001C0E08, // 0016 ADD R7 R7 R8 - 0x54220003, // 0017 LDINT R8 4 - 0x88240109, // 0018 GETMBR R9 R0 K9 - 0x0424130A, // 0019 SUB R9 R9 K10 - 0x40201009, // 001A CONNECT R8 R8 R9 - 0x88240102, // 001B GETMBR R9 R0 K2 - 0x94201208, // 001C GETIDX R8 R9 R8 - 0x8C28030B, // 001D GETMET R10 R1 K11 - 0x5C300C00, // 001E MOVE R12 R6 - 0x7C280400, // 001F CALL R10 2 - 0x8C28150C, // 0020 GETMET R10 R10 K12 - 0x5C301000, // 0021 MOVE R12 R8 - 0x5C340E00, // 0022 MOVE R13 R7 - 0x5838000D, // 0023 LDCONST R14 K13 - 0x7C280800, // 0024 CALL R10 4 - 0x5C241400, // 0025 MOVE R9 R10 - 0x402A1D0F, // 0026 CONNECT R10 K14 K15 - 0x882C0102, // 0027 GETMBR R11 R0 K2 - 0x9428160A, // 0028 GETIDX R10 R11 R10 - 0x00281409, // 0029 ADD R10 R10 R9 - 0x882C0110, // 002A GETMBR R11 R0 K16 - 0x882C1709, // 002B GETMBR R11 R11 K9 - 0x402C1703, // 002C CONNECT R11 R11 K3 - 0x942C100B, // 002D GETIDX R11 R8 R11 - 0x0028140B, // 002E ADD R10 R10 R11 - 0x9002040A, // 002F SETMBR R0 K2 R10 - 0x88180109, // 0030 GETMBR R6 R0 K9 - 0x04180D0A, // 0031 SUB R6 R6 K10 - 0x401A1C06, // 0032 CONNECT R6 K14 R6 - 0x94180606, // 0033 GETIDX R6 R3 R6 - 0x881C0109, // 0034 GETMBR R7 R0 K9 - 0x5421FFEE, // 0035 LDINT R8 -17 - 0x401C0E08, // 0036 CONNECT R7 R7 R8 - 0x941C0607, // 0037 GETIDX R7 R3 R7 - 0x60200015, // 0038 GETGBL R8 G21 - 0x7C200000, // 0039 CALL R8 0 - 0x8C241107, // 003A GETMET R9 R8 K7 - 0x882C0111, // 003B GETMBR R11 R0 K17 - 0x5830000A, // 003C LDCONST R12 K10 - 0x7C240600, // 003D CALL R9 3 - 0x8C241107, // 003E GETMET R9 R8 K7 - 0x882C0112, // 003F GETMBR R11 R0 K18 - 0x54320003, // 0040 LDINT R12 4 - 0x7C240600, // 0041 CALL R9 3 - 0x88240113, // 0042 GETMBR R9 R0 K19 - 0x78260001, // 0043 JMPF R9 #0046 - 0x40241103, // 0044 CONNECT R9 R8 K3 - 0x70020006, // 0045 JMP #004D - 0x88240514, // 0046 GETMBR R9 R2 K20 - 0x78260001, // 0047 JMPF R9 #004A - 0x88240514, // 0048 GETMBR R9 R2 K20 - 0x40241009, // 0049 CONNECT R9 R8 R9 - 0x8C241115, // 004A GETMET R9 R8 K21 - 0x542E000C, // 004B LDINT R11 13 - 0x7C240400, // 004C CALL R9 2 - 0xB8262C00, // 004D GETNGBL R9 K22 - 0x8C241317, // 004E GETMET R9 R9 K23 - 0x582C0018, // 004F LDCONST R11 K24 - 0x5830000F, // 0050 LDCONST R12 K15 - 0x7C240600, // 0051 CALL R9 3 - 0xB8262C00, // 0052 GETNGBL R9 K22 - 0x8C241317, // 0053 GETMET R9 R9 K23 - 0x8C2C0B1A, // 0054 GETMET R11 R5 K26 - 0x7C2C0200, // 0055 CALL R11 1 - 0x002E320B, // 0056 ADD R11 K25 R11 - 0x5830000F, // 0057 LDCONST R12 K15 - 0x7C240600, // 0058 CALL R9 3 - 0xB8262C00, // 0059 GETNGBL R9 K22 - 0x8C241317, // 005A GETMET R9 R9 K23 - 0x8C2C0F1A, // 005B GETMET R11 R7 K26 - 0x7C2C0200, // 005C CALL R11 1 - 0x002E360B, // 005D ADD R11 K27 R11 - 0x5830000F, // 005E LDCONST R12 K15 - 0x7C240600, // 005F CALL R9 3 - 0xB8262C00, // 0060 GETNGBL R9 K22 - 0x8C241317, // 0061 GETMET R9 R9 K23 - 0x8C2C0D1A, // 0062 GETMET R11 R6 K26 - 0x7C2C0200, // 0063 CALL R11 1 - 0x002E380B, // 0064 ADD R11 K28 R11 - 0x5830000F, // 0065 LDCONST R12 K15 - 0x7C240600, // 0066 CALL R9 3 - 0xB8262C00, // 0067 GETNGBL R9 K22 - 0x8C241317, // 0068 GETMET R9 R9 K23 - 0x8C2C111A, // 0069 GETMET R11 R8 K26 - 0x7C2C0200, // 006A CALL R11 1 - 0x002E3A0B, // 006B ADD R11 K29 R11 - 0x5830000F, // 006C LDCONST R12 K15 - 0x7C240600, // 006D CALL R9 3 - 0xB8262C00, // 006E GETNGBL R9 K22 - 0x8C241317, // 006F GETMET R9 R9 K23 - 0x8C2C091A, // 0070 GETMET R11 R4 K26 - 0x7C2C0200, // 0071 CALL R11 1 - 0x002E3C0B, // 0072 ADD R11 K30 R11 - 0x5830000F, // 0073 LDCONST R12 K15 - 0x7C240600, // 0074 CALL R9 3 - 0x8C24031F, // 0075 GETMET R9 R1 K31 - 0x5C2C0A00, // 0076 MOVE R11 R5 - 0x5C301000, // 0077 MOVE R12 R8 - 0x5C340C00, // 0078 MOVE R13 R6 - 0x6038000C, // 0079 GETGBL R14 G12 - 0x5C3C0E00, // 007A MOVE R15 R7 - 0x7C380200, // 007B CALL R14 1 - 0x543E000F, // 007C LDINT R15 16 - 0x7C240C00, // 007D CALL R9 6 - 0x8C28130C, // 007E GETMET R10 R9 K12 - 0x5C300E00, // 007F MOVE R12 R7 - 0x7C280400, // 0080 CALL R10 2 - 0x8C2C1320, // 0081 GETMET R11 R9 K32 - 0x7C2C0200, // 0082 CALL R11 1 - 0xB8322C00, // 0083 GETNGBL R12 K22 - 0x8C301917, // 0084 GETMET R12 R12 K23 - 0x58380018, // 0085 LDCONST R14 K24 - 0x583C000F, // 0086 LDCONST R15 K15 - 0x7C300600, // 0087 CALL R12 3 - 0xB8322C00, // 0088 GETNGBL R12 K22 - 0x8C301917, // 0089 GETMET R12 R12 K23 - 0x8C38151A, // 008A GETMET R14 R10 K26 - 0x7C380200, // 008B CALL R14 1 - 0x003A420E, // 008C ADD R14 K33 R14 - 0x583C000F, // 008D LDCONST R15 K15 - 0x7C300600, // 008E CALL R12 3 - 0xB8322C00, // 008F GETNGBL R12 K22 - 0x8C301917, // 0090 GETMET R12 R12 K23 - 0x8C38171A, // 0091 GETMET R14 R11 K26 - 0x7C380200, // 0092 CALL R14 1 - 0x003A440E, // 0093 ADD R14 K34 R14 - 0x583C000F, // 0094 LDCONST R15 K15 - 0x7C300600, // 0095 CALL R12 3 - 0xB8322C00, // 0096 GETNGBL R12 K22 - 0x8C301917, // 0097 GETMET R12 R12 K23 - 0x58380018, // 0098 LDCONST R14 K24 - 0x583C000F, // 0099 LDCONST R15 K15 + 0x781A002A, // 0009 JMPF R6 #0035 + 0xB81A0C00, // 000A GETNGBL R6 K6 + 0x8C180D07, // 000B GETMET R6 R6 K7 + 0x58200008, // 000C LDCONST R8 K8 + 0x58240009, // 000D LDCONST R9 K9 + 0x7C180600, // 000E CALL R6 3 + 0x8C18050A, // 000F GETMET R6 R2 K10 + 0x7C180200, // 0010 CALL R6 1 + 0x601C0015, // 0011 GETGBL R7 G21 + 0x7C1C0000, // 0012 CALL R7 0 + 0x8C1C0F0B, // 0013 GETMET R7 R7 K11 + 0x8824010C, // 0014 GETMBR R9 R0 K12 + 0x5429FFFD, // 0015 LDINT R10 -2 + 0x7C1C0600, // 0016 CALL R7 3 + 0x54220004, // 0017 LDINT R8 5 + 0x5426000E, // 0018 LDINT R9 15 + 0x40201009, // 0019 CONNECT R8 R8 R9 + 0x94200808, // 001A GETIDX R8 R4 R8 + 0x001C0E08, // 001B ADD R7 R7 R8 + 0x54220003, // 001C LDINT R8 4 + 0x8824010D, // 001D GETMBR R9 R0 K13 + 0x0424130E, // 001E SUB R9 R9 K14 + 0x40201009, // 001F CONNECT R8 R8 R9 + 0x88240102, // 0020 GETMBR R9 R0 K2 + 0x94201208, // 0021 GETIDX R8 R9 R8 + 0x8C28030F, // 0022 GETMET R10 R1 K15 + 0x5C300C00, // 0023 MOVE R12 R6 + 0x7C280400, // 0024 CALL R10 2 + 0x8C281510, // 0025 GETMET R10 R10 K16 + 0x5C301000, // 0026 MOVE R12 R8 + 0x5C340E00, // 0027 MOVE R13 R7 + 0x58380009, // 0028 LDCONST R14 K9 + 0x7C280800, // 0029 CALL R10 4 + 0x5C241400, // 002A MOVE R9 R10 + 0x402A2312, // 002B CONNECT R10 K17 K18 + 0x882C0102, // 002C GETMBR R11 R0 K2 + 0x9428160A, // 002D GETIDX R10 R11 R10 + 0x00281409, // 002E ADD R10 R10 R9 + 0x882C0113, // 002F GETMBR R11 R0 K19 + 0x882C170D, // 0030 GETMBR R11 R11 K13 + 0x402C1703, // 0031 CONNECT R11 R11 K3 + 0x942C100B, // 0032 GETIDX R11 R8 R11 + 0x0028140B, // 0033 ADD R10 R10 R11 + 0x9002040A, // 0034 SETMBR R0 K2 R10 + 0x8818010D, // 0035 GETMBR R6 R0 K13 + 0x04180D0E, // 0036 SUB R6 R6 K14 + 0x401A2206, // 0037 CONNECT R6 K17 R6 + 0x94180606, // 0038 GETIDX R6 R3 R6 + 0x881C010D, // 0039 GETMBR R7 R0 K13 + 0x5421FFEE, // 003A LDINT R8 -17 + 0x401C0E08, // 003B CONNECT R7 R7 R8 + 0x941C0607, // 003C GETIDX R7 R3 R7 + 0x60200015, // 003D GETGBL R8 G21 + 0x7C200000, // 003E CALL R8 0 + 0x8C24110B, // 003F GETMET R9 R8 K11 + 0x882C0114, // 0040 GETMBR R11 R0 K20 + 0x5830000E, // 0041 LDCONST R12 K14 + 0x7C240600, // 0042 CALL R9 3 + 0x8C24110B, // 0043 GETMET R9 R8 K11 + 0x882C0115, // 0044 GETMBR R11 R0 K21 + 0x54320003, // 0045 LDINT R12 4 + 0x7C240600, // 0046 CALL R9 3 + 0x88240116, // 0047 GETMBR R9 R0 K22 + 0x78260001, // 0048 JMPF R9 #004B + 0x40241103, // 0049 CONNECT R9 R8 K3 + 0x70020006, // 004A JMP #0052 + 0x88240517, // 004B GETMBR R9 R2 K23 + 0x78260001, // 004C JMPF R9 #004F + 0x88240517, // 004D GETMBR R9 R2 K23 + 0x40241009, // 004E CONNECT R9 R8 R9 + 0x8C241118, // 004F GETMET R9 R8 K24 + 0x542E000C, // 0050 LDINT R11 13 + 0x7C240400, // 0051 CALL R9 2 + 0xB8260C00, // 0052 GETNGBL R9 K6 + 0x8C241307, // 0053 GETMET R9 R9 K7 + 0x582C0019, // 0054 LDCONST R11 K25 + 0x54320003, // 0055 LDINT R12 4 + 0x7C240600, // 0056 CALL R9 3 + 0xB8260C00, // 0057 GETNGBL R9 K6 + 0x8C241307, // 0058 GETMET R9 R9 K7 + 0x8C2C0B1B, // 0059 GETMET R11 R5 K27 + 0x7C2C0200, // 005A CALL R11 1 + 0x002E340B, // 005B ADD R11 K26 R11 + 0x54320003, // 005C LDINT R12 4 + 0x7C240600, // 005D CALL R9 3 + 0xB8260C00, // 005E GETNGBL R9 K6 + 0x8C241307, // 005F GETMET R9 R9 K7 + 0x8C2C0F1B, // 0060 GETMET R11 R7 K27 + 0x7C2C0200, // 0061 CALL R11 1 + 0x002E380B, // 0062 ADD R11 K28 R11 + 0x54320003, // 0063 LDINT R12 4 + 0x7C240600, // 0064 CALL R9 3 + 0xB8260C00, // 0065 GETNGBL R9 K6 + 0x8C241307, // 0066 GETMET R9 R9 K7 + 0x8C2C0D1B, // 0067 GETMET R11 R6 K27 + 0x7C2C0200, // 0068 CALL R11 1 + 0x002E3A0B, // 0069 ADD R11 K29 R11 + 0x54320003, // 006A LDINT R12 4 + 0x7C240600, // 006B CALL R9 3 + 0xB8260C00, // 006C GETNGBL R9 K6 + 0x8C241307, // 006D GETMET R9 R9 K7 + 0x8C2C111B, // 006E GETMET R11 R8 K27 + 0x7C2C0200, // 006F CALL R11 1 + 0x002E3C0B, // 0070 ADD R11 K30 R11 + 0x54320003, // 0071 LDINT R12 4 + 0x7C240600, // 0072 CALL R9 3 + 0xB8260C00, // 0073 GETNGBL R9 K6 + 0x8C241307, // 0074 GETMET R9 R9 K7 + 0x8C2C091B, // 0075 GETMET R11 R4 K27 + 0x7C2C0200, // 0076 CALL R11 1 + 0x002E3E0B, // 0077 ADD R11 K31 R11 + 0x54320003, // 0078 LDINT R12 4 + 0x7C240600, // 0079 CALL R9 3 + 0x8C240320, // 007A GETMET R9 R1 K32 + 0x5C2C0A00, // 007B MOVE R11 R5 + 0x5C301000, // 007C MOVE R12 R8 + 0x5C340C00, // 007D MOVE R13 R6 + 0x6038000C, // 007E GETGBL R14 G12 + 0x5C3C0E00, // 007F MOVE R15 R7 + 0x7C380200, // 0080 CALL R14 1 + 0x543E000F, // 0081 LDINT R15 16 + 0x7C240C00, // 0082 CALL R9 6 + 0x8C281310, // 0083 GETMET R10 R9 K16 + 0x5C300E00, // 0084 MOVE R12 R7 + 0x7C280400, // 0085 CALL R10 2 + 0x8C2C1321, // 0086 GETMET R11 R9 K33 + 0x7C2C0200, // 0087 CALL R11 1 + 0xB8320C00, // 0088 GETNGBL R12 K6 + 0x8C301907, // 0089 GETMET R12 R12 K7 + 0x58380019, // 008A LDCONST R14 K25 + 0x543E0003, // 008B LDINT R15 4 + 0x7C300600, // 008C CALL R12 3 + 0xB8320C00, // 008D GETNGBL R12 K6 + 0x8C301907, // 008E GETMET R12 R12 K7 + 0x8C38151B, // 008F GETMET R14 R10 K27 + 0x7C380200, // 0090 CALL R14 1 + 0x003A440E, // 0091 ADD R14 K34 R14 + 0x543E0003, // 0092 LDINT R15 4 + 0x7C300600, // 0093 CALL R12 3 + 0xB8320C00, // 0094 GETNGBL R12 K6 + 0x8C301907, // 0095 GETMET R12 R12 K7 + 0x8C38171B, // 0096 GETMET R14 R11 K27 + 0x7C380200, // 0097 CALL R14 1 + 0x003A460E, // 0098 ADD R14 K35 R14 + 0x543E0003, // 0099 LDINT R15 4 0x7C300600, // 009A CALL R12 3 - 0x20301604, // 009B NE R12 R11 R4 - 0x78320006, // 009C JMPF R12 #00A4 - 0xB8322C00, // 009D GETNGBL R12 K22 - 0x8C301917, // 009E GETMET R12 R12 K23 - 0x58380023, // 009F LDCONST R14 K35 - 0x583C000F, // 00A0 LDCONST R15 K15 - 0x7C300600, // 00A1 CALL R12 3 - 0x4C300000, // 00A2 LDNIL R12 - 0x80041800, // 00A3 RET 1 R12 - 0x80041400, // 00A4 RET 1 R10 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: encode -********************************************************************/ -be_local_closure(Matter_Frame_encode, /* 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[30]) { /* constants */ - /* K0 */ be_nested_str_weak(flags), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(flag_s), - /* K3 */ be_nested_str_weak(flag_dsiz), - /* K4 */ be_const_int(3), - /* K5 */ be_nested_str_weak(add), - /* K6 */ be_const_int(1), - /* K7 */ be_nested_str_weak(local_session_id), - /* K8 */ be_const_int(2), - /* K9 */ be_nested_str_weak(sec_flags), - /* K10 */ be_nested_str_weak(sec_p), - /* K11 */ be_nested_str_weak(sec_c), - /* K12 */ be_nested_str_weak(sec_sesstype), - /* K13 */ be_nested_str_weak(message_counter), - /* K14 */ be_nested_str_weak(source_node_id), - /* K15 */ be_nested_str_weak(dest_node_id_8), - /* K16 */ be_nested_str_weak(dest_node_id_2), - /* K17 */ be_nested_str_weak(payload_idx), - /* K18 */ be_nested_str_weak(x_flags), - /* K19 */ be_nested_str_weak(x_flag_v), - /* K20 */ be_nested_str_weak(x_flag_r), - /* K21 */ be_nested_str_weak(x_flag_a), - /* K22 */ be_nested_str_weak(x_flag_i), - /* K23 */ be_nested_str_weak(opcode), - /* K24 */ be_nested_str_weak(exchange_id), - /* K25 */ be_nested_str_weak(protocol_id), - /* K26 */ be_nested_str_weak(ack_message_counter), - /* K27 */ be_nested_str_weak(app_payload_idx), - /* K28 */ be_nested_str_weak(debug), - /* K29 */ be_nested_str_weak(raw), - }), - be_str_weak(encode), - &be_const_str_solidified, - ( &(const binstruction[144]) { /* code */ - 0x60080015, // 0000 GETGBL R2 G21 - 0x7C080000, // 0001 CALL R2 0 - 0x880C0100, // 0002 GETMBR R3 R0 K0 - 0x4C100000, // 0003 LDNIL R4 - 0x1C0C0604, // 0004 EQ R3 R3 R4 - 0x780E000D, // 0005 JMPF R3 #0014 - 0x90020101, // 0006 SETMBR R0 K0 K1 - 0x880C0102, // 0007 GETMBR R3 R0 K2 - 0x780E0003, // 0008 JMPF R3 #000D - 0x880C0100, // 0009 GETMBR R3 R0 K0 - 0x54120003, // 000A LDINT R4 4 - 0x300C0604, // 000B OR R3 R3 R4 - 0x90020003, // 000C SETMBR R0 K0 R3 - 0x880C0103, // 000D GETMBR R3 R0 K3 - 0x780E0004, // 000E JMPF R3 #0014 - 0x880C0100, // 000F GETMBR R3 R0 K0 - 0x88100103, // 0010 GETMBR R4 R0 K3 - 0x2C100904, // 0011 AND R4 R4 K4 - 0x300C0604, // 0012 OR R3 R3 R4 - 0x90020003, // 0013 SETMBR R0 K0 R3 - 0x8C0C0505, // 0014 GETMET R3 R2 K5 - 0x88140100, // 0015 GETMBR R5 R0 K0 - 0x58180006, // 0016 LDCONST R6 K6 - 0x7C0C0600, // 0017 CALL R3 3 - 0x8C0C0505, // 0018 GETMET R3 R2 K5 - 0x88140107, // 0019 GETMBR R5 R0 K7 - 0x78160001, // 001A JMPF R5 #001D - 0x88140107, // 001B GETMBR R5 R0 K7 - 0x70020000, // 001C JMP #001E - 0x58140001, // 001D LDCONST R5 K1 - 0x58180008, // 001E LDCONST R6 K8 - 0x7C0C0600, // 001F CALL R3 3 - 0x880C0109, // 0020 GETMBR R3 R0 K9 - 0x4C100000, // 0021 LDNIL R4 - 0x1C0C0604, // 0022 EQ R3 R3 R4 - 0x780E0013, // 0023 JMPF R3 #0038 - 0x90021301, // 0024 SETMBR R0 K9 K1 - 0x880C010A, // 0025 GETMBR R3 R0 K10 - 0x780E0003, // 0026 JMPF R3 #002B - 0x880C0109, // 0027 GETMBR R3 R0 K9 - 0x5412007F, // 0028 LDINT R4 128 - 0x300C0604, // 0029 OR R3 R3 R4 - 0x90021203, // 002A SETMBR R0 K9 R3 - 0x880C010B, // 002B GETMBR R3 R0 K11 - 0x780E0003, // 002C JMPF R3 #0031 - 0x880C0109, // 002D GETMBR R3 R0 K9 - 0x5412003F, // 002E LDINT R4 64 - 0x300C0604, // 002F OR R3 R3 R4 - 0x90021203, // 0030 SETMBR R0 K9 R3 - 0x880C010C, // 0031 GETMBR R3 R0 K12 - 0x780E0004, // 0032 JMPF R3 #0038 - 0x880C0109, // 0033 GETMBR R3 R0 K9 - 0x8810010C, // 0034 GETMBR R4 R0 K12 - 0x2C100904, // 0035 AND R4 R4 K4 - 0x300C0604, // 0036 OR R3 R3 R4 - 0x90021203, // 0037 SETMBR R0 K9 R3 - 0x8C0C0505, // 0038 GETMET R3 R2 K5 - 0x88140109, // 0039 GETMBR R5 R0 K9 - 0x58180006, // 003A LDCONST R6 K6 - 0x7C0C0600, // 003B CALL R3 3 - 0x8C0C0505, // 003C GETMET R3 R2 K5 - 0x8814010D, // 003D GETMBR R5 R0 K13 - 0x541A0003, // 003E LDINT R6 4 - 0x7C0C0600, // 003F CALL R3 3 - 0x880C0102, // 0040 GETMBR R3 R0 K2 - 0x780E0001, // 0041 JMPF R3 #0044 - 0x880C010E, // 0042 GETMBR R3 R0 K14 - 0x400C0403, // 0043 CONNECT R3 R2 R3 - 0x880C0103, // 0044 GETMBR R3 R0 K3 - 0x1C0C0706, // 0045 EQ R3 R3 K6 - 0x780E0001, // 0046 JMPF R3 #0049 - 0x880C010F, // 0047 GETMBR R3 R0 K15 - 0x400C0403, // 0048 CONNECT R3 R2 R3 - 0x880C0103, // 0049 GETMBR R3 R0 K3 - 0x1C0C0708, // 004A EQ R3 R3 K8 - 0x780E0003, // 004B JMPF R3 #0050 - 0x8C0C0505, // 004C GETMET R3 R2 K5 - 0x88140110, // 004D GETMBR R5 R0 K16 - 0x58180008, // 004E LDCONST R6 K8 - 0x7C0C0600, // 004F CALL R3 3 - 0x600C000C, // 0050 GETGBL R3 G12 - 0x5C100400, // 0051 MOVE R4 R2 - 0x7C0C0200, // 0052 CALL R3 1 - 0x90022203, // 0053 SETMBR R0 K17 R3 - 0x880C0112, // 0054 GETMBR R3 R0 K18 - 0x4C100000, // 0055 LDNIL R4 - 0x1C0C0604, // 0056 EQ R3 R3 R4 - 0x780E0016, // 0057 JMPF R3 #006F - 0x90022501, // 0058 SETMBR R0 K18 K1 - 0x880C0113, // 0059 GETMBR R3 R0 K19 - 0x780E0003, // 005A JMPF R3 #005F - 0x880C0112, // 005B GETMBR R3 R0 K18 - 0x5412000F, // 005C LDINT R4 16 - 0x300C0604, // 005D OR R3 R3 R4 - 0x90022403, // 005E SETMBR R0 K18 R3 - 0x880C0114, // 005F GETMBR R3 R0 K20 - 0x780E0003, // 0060 JMPF R3 #0065 - 0x880C0112, // 0061 GETMBR R3 R0 K18 - 0x54120003, // 0062 LDINT R4 4 - 0x300C0604, // 0063 OR R3 R3 R4 - 0x90022403, // 0064 SETMBR R0 K18 R3 - 0x880C0115, // 0065 GETMBR R3 R0 K21 - 0x780E0002, // 0066 JMPF R3 #006A - 0x880C0112, // 0067 GETMBR R3 R0 K18 - 0x300C0708, // 0068 OR R3 R3 K8 - 0x90022403, // 0069 SETMBR R0 K18 R3 - 0x880C0116, // 006A GETMBR R3 R0 K22 - 0x780E0002, // 006B JMPF R3 #006F - 0x880C0112, // 006C GETMBR R3 R0 K18 - 0x300C0706, // 006D OR R3 R3 K6 - 0x90022403, // 006E SETMBR R0 K18 R3 - 0x8C0C0505, // 006F GETMET R3 R2 K5 - 0x88140112, // 0070 GETMBR R5 R0 K18 - 0x58180006, // 0071 LDCONST R6 K6 - 0x7C0C0600, // 0072 CALL R3 3 - 0x8C0C0505, // 0073 GETMET R3 R2 K5 - 0x88140117, // 0074 GETMBR R5 R0 K23 - 0x58180006, // 0075 LDCONST R6 K6 - 0x7C0C0600, // 0076 CALL R3 3 - 0x8C0C0505, // 0077 GETMET R3 R2 K5 - 0x88140118, // 0078 GETMBR R5 R0 K24 - 0x58180008, // 0079 LDCONST R6 K8 - 0x7C0C0600, // 007A CALL R3 3 - 0x8C0C0505, // 007B GETMET R3 R2 K5 - 0x88140119, // 007C GETMBR R5 R0 K25 - 0x58180008, // 007D LDCONST R6 K8 - 0x7C0C0600, // 007E CALL R3 3 - 0x880C0115, // 007F GETMBR R3 R0 K21 - 0x780E0003, // 0080 JMPF R3 #0085 - 0x8C0C0505, // 0081 GETMET R3 R2 K5 - 0x8814011A, // 0082 GETMBR R5 R0 K26 - 0x541A0003, // 0083 LDINT R6 4 - 0x7C0C0600, // 0084 CALL R3 3 - 0x600C000C, // 0085 GETGBL R3 G12 - 0x5C100400, // 0086 MOVE R4 R2 - 0x7C0C0200, // 0087 CALL R3 1 - 0x90023603, // 0088 SETMBR R0 K27 R3 - 0x78060000, // 0089 JMPF R1 #008B - 0x400C0401, // 008A CONNECT R3 R2 R1 - 0x8C0C011C, // 008B GETMET R3 R0 K28 - 0x5C140400, // 008C MOVE R5 R2 - 0x7C0C0400, // 008D CALL R3 2 - 0x90023A02, // 008E SETMBR R0 K29 R2 - 0x80040400, // 008F RET 1 R2 + 0xB8320C00, // 009B GETNGBL R12 K6 + 0x8C301907, // 009C GETMET R12 R12 K7 + 0x58380019, // 009D LDCONST R14 K25 + 0x543E0003, // 009E LDINT R15 4 + 0x7C300600, // 009F CALL R12 3 + 0x20301604, // 00A0 NE R12 R11 R4 + 0x78320006, // 00A1 JMPF R12 #00A9 + 0xB8320C00, // 00A2 GETNGBL R12 K6 + 0x8C301907, // 00A3 GETMET R12 R12 K7 + 0x58380024, // 00A4 LDCONST R14 K36 + 0x583C0009, // 00A5 LDCONST R15 K9 + 0x7C300600, // 00A6 CALL R12 3 + 0x4C300000, // 00A7 LDNIL R12 + 0x80041800, // 00A8 RET 1 R12 + 0x80041400, // 00A9 RET 1 R10 }) ) ); @@ -1228,49 +1263,50 @@ be_local_closure(Matter_Frame_encode, /* name */ be_local_class(Matter_Frame, 32, NULL, - be_nested_map(41, + be_nested_map(42, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(x_flag_a, 8), be_const_var(21) }, + { be_const_key_weak(x_flag_i, -1), be_const_var(22) }, + { be_const_key_weak(dest_node_id_8, 7), be_const_var(16) }, { be_const_key_weak(x_flags, -1), be_const_var(17) }, - { be_const_key_weak(raw, 37), be_const_var(2) }, - { be_const_key_weak(sec_sesstype, 0), be_const_var(12) }, - { be_const_key_weak(build_response, 5), be_const_closure(Matter_Frame_build_response_closure) }, - { be_const_key_weak(sec_mx, -1), be_const_var(11) }, - { be_const_key_weak(dest_node_id_2, 32), be_const_var(15) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_Frame_encode_closure) }, + { be_const_key_weak(x_flag_a, -1), be_const_var(21) }, + { be_const_key_weak(exchange_id, -1), be_const_var(24) }, + { be_const_key_weak(opcode, -1), be_const_var(23) }, + { be_const_key_weak(encode_frame, -1), be_const_closure(Matter_Frame_encode_frame_closure) }, + { be_const_key_weak(app_payload_idx, -1), be_const_var(29) }, + { be_const_key_weak(payload_idx, -1), be_const_var(3) }, + { be_const_key_weak(ack_message_counter, 24), be_const_var(27) }, + { be_const_key_weak(build_standalone_ack, -1), be_const_closure(Matter_Frame_build_standalone_ack_closure) }, + { be_const_key_weak(x_flag_v, 6), be_const_var(18) }, + { be_const_key_weak(sec_c, -1), be_const_var(10) }, + { be_const_key_weak(vendor_id, 32), be_const_var(26) }, + { be_const_key_weak(local_session_id, -1), be_const_var(7) }, + { be_const_key_weak(flag_s, -1), be_const_var(5) }, + { be_const_key_weak(debug, -1), be_const_closure(Matter_Frame_debug_closure) }, + { be_const_key_weak(message_handler, 10), be_const_var(0) }, + { be_const_key_weak(encrypt, 34), be_const_closure(Matter_Frame_encrypt_closure) }, + { be_const_key_weak(session, -1), be_const_var(1) }, + { be_const_key_weak(sec_flags, -1), be_const_var(8) }, + { be_const_key_weak(build_response, -1), be_const_closure(Matter_Frame_build_response_closure) }, + { be_const_key_weak(initiate_response, -1), be_const_static_closure(Matter_Frame_initiate_response_closure) }, + { be_const_key_weak(remote_port, -1), be_const_var(31) }, + { be_const_key_weak(sec_sesstype, -1), be_const_var(12) }, + { be_const_key_weak(decode_header, 23), be_const_closure(Matter_Frame_decode_header_closure) }, + { be_const_key_weak(flags, -1), be_const_var(4) }, + { be_const_key_weak(protocol_id, 13), be_const_var(25) }, + { be_const_key_weak(raw, -1), be_const_var(2) }, + { be_const_key_weak(source_node_id, 28), be_const_var(14) }, + { be_const_key_weak(flag_dsiz, -1), be_const_var(6) }, + { be_const_key_weak(x_flag_r, -1), be_const_var(20) }, + { be_const_key_weak(message_counter, -1), be_const_var(13) }, + { be_const_key_weak(init, 14), be_const_closure(Matter_Frame_init_closure) }, + { be_const_key_weak(x_flag_sx, 12), be_const_var(19) }, + { be_const_key_weak(dest_node_id_2, -1), be_const_var(15) }, + { be_const_key_weak(decode_payload, -1), be_const_closure(Matter_Frame_decode_payload_closure) }, + { be_const_key_weak(sec_p, 8), be_const_var(9) }, { be_const_key_weak(decrypt, -1), be_const_closure(Matter_Frame_decrypt_closure) }, { be_const_key_weak(sec_extensions, -1), be_const_var(28) }, - { be_const_key_weak(remote_ip, 7), be_const_var(30) }, - { be_const_key_weak(message_counter, 33), be_const_var(13) }, - { be_const_key_weak(ack_message_counter, -1), be_const_var(27) }, - { be_const_key_weak(x_flag_i, -1), be_const_var(22) }, - { be_const_key_weak(dest_node_id_8, -1), be_const_var(16) }, - { be_const_key_weak(x_flag_r, 2), be_const_var(20) }, - { be_const_key_weak(x_flag_v, -1), be_const_var(18) }, - { be_const_key_weak(opcode, -1), be_const_var(23) }, - { be_const_key_weak(sec_c, 25), be_const_var(10) }, - { be_const_key_weak(sec_p, -1), be_const_var(9) }, - { be_const_key_weak(protocol_id, 29), be_const_var(25) }, - { be_const_key_weak(sec_flags, -1), be_const_var(8) }, - { be_const_key_weak(message_handler, -1), be_const_var(0) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Frame_init_closure) }, - { be_const_key_weak(encrypt, 19), be_const_closure(Matter_Frame_encrypt_closure) }, - { be_const_key_weak(build_standalone_ack, 27), be_const_closure(Matter_Frame_build_standalone_ack_closure) }, - { be_const_key_weak(decode_payload, -1), be_const_closure(Matter_Frame_decode_payload_closure) }, - { be_const_key_weak(remote_port, 36), be_const_var(31) }, - { be_const_key_weak(flag_dsiz, -1), be_const_var(6) }, - { be_const_key_weak(vendor_id, 16), be_const_var(26) }, - { be_const_key_weak(payload_idx, -1), be_const_var(3) }, - { be_const_key_weak(debug, -1), be_const_closure(Matter_Frame_debug_closure) }, - { be_const_key_weak(x_flag_sx, 39), be_const_var(19) }, - { be_const_key_weak(decode_header, -1), be_const_closure(Matter_Frame_decode_header_closure) }, - { be_const_key_weak(flag_s, -1), be_const_var(5) }, - { be_const_key_weak(app_payload_idx, -1), be_const_var(29) }, - { be_const_key_weak(source_node_id, -1), be_const_var(14) }, - { be_const_key_weak(session, -1), be_const_var(1) }, - { be_const_key_weak(flags, -1), be_const_var(4) }, - { be_const_key_weak(local_session_id, 40), be_const_var(7) }, - { be_const_key_weak(exchange_id, -1), be_const_var(24) }, + { be_const_key_weak(sec_mx, 3), be_const_var(11) }, + { be_const_key_weak(remote_ip, 2), be_const_var(30) }, })), be_str_weak(Matter_Frame) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h index 453348f65..24a47772d 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_MessageHandler.h @@ -7,12 +7,12 @@ extern const bclass be_class_Matter_MessageHandler; /******************************************************************** -** Solidified function: send_response +** Solidified function: send_response_frame ********************************************************************/ -be_local_closure(Matter_MessageHandler_send_response, /* name */ +be_local_closure(Matter_MessageHandler_send_response_frame, /* name */ be_nested_proto( - 11, /* nstack */ - 5, /* argc */ + 5, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -23,17 +23,14 @@ be_local_closure(Matter_MessageHandler_send_response, /* name */ /* K0 */ be_nested_str_weak(device), /* K1 */ be_nested_str_weak(msg_send), }), - be_str_weak(send_response), + be_str_weak(send_response_frame), &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x88140100, // 0000 GETMBR R5 R0 K0 - 0x8C140B01, // 0001 GETMET R5 R5 K1 - 0x5C1C0200, // 0002 MOVE R7 R1 - 0x5C200400, // 0003 MOVE R8 R2 - 0x5C240600, // 0004 MOVE R9 R3 - 0x5C280800, // 0005 MOVE R10 R4 - 0x7C140A00, // 0006 CALL R5 5 - 0x80000000, // 0007 RET 0 + ( &(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 + 0x80000000, // 0004 RET 0 }) ) ); @@ -41,479 +38,69 @@ be_local_closure(Matter_MessageHandler_send_response, /* name */ /******************************************************************** -** Solidified function: msg_received +** Solidified function: send_encrypted_ack ********************************************************************/ -be_local_closure(Matter_MessageHandler_msg_received, /* name */ +be_local_closure(Matter_MessageHandler_send_encrypted_ack, /* name */ be_nested_proto( - 17, /* nstack */ - 4, /* argc */ + 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[59]) { /* constants */ + ( &(const bvalue[17]) { /* constants */ /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20raw_X3D), - /* K4 */ be_nested_str_weak(tohex), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(Frame), - /* K7 */ be_nested_str_weak(decode_header), - /* K8 */ be_nested_str_weak(local_session_id), - /* K9 */ be_const_int(0), - /* K10 */ be_nested_str_weak(sec_sesstype), - /* K11 */ be_nested_str_weak(device), - /* K12 */ be_nested_str_weak(sessions), - /* K13 */ be_nested_str_weak(find_session_source_id_unsecure), - /* K14 */ be_nested_str_weak(source_node_id), - /* K15 */ be_nested_str_weak(MTR_X3A_X20find_X20session_X20by_X20source_node_id_X20_X3D_X20), - /* K16 */ be_nested_str_weak(session_id_X20_X3D_X20), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(session), - /* K19 */ be_nested_str_weak(counter_rcv), - /* K20 */ be_nested_str_weak(validate), - /* K21 */ be_nested_str_weak(message_counter), - /* K22 */ be_nested_str_weak(format), - /* K23 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20unencrypted_X20message_X20_X3D_X20_X25i_X20ref_X20_X3D_X20_X25i), - /* K24 */ be_nested_str_weak(val), - /* K25 */ be_nested_str_weak(decode_payload), - /* K26 */ be_nested_str_weak(packet_ack), - /* K27 */ be_nested_str_weak(ack_message_counter), - /* K28 */ be_nested_str_weak(opcode), - /* K29 */ be_nested_str_weak(get_opcode_name), - /* K30 */ be_nested_str_weak(0x_X2502X), - /* K31 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_X20_X20_X20_X20_X20_X20_X25s_X20from_X20_X5B_X25s_X5D_X3A_X25i), - /* K32 */ be_const_int(2), - /* K33 */ be_nested_str_weak(commissioning), - /* K34 */ be_nested_str_weak(process_incoming), - /* K35 */ be_nested_str_weak(MTR_X3A_X20decode_X20header_X3A_X20local_session_id_X3D_X25i_X20message_counter_X3D_X25i), - /* K36 */ be_nested_str_weak(get_session_by_local_session_id), - /* K37 */ be_nested_str_weak(MTR_X3A_X20unknown_X20local_session_id_X20), - /* K38 */ be_nested_str_weak(MTR_X3A_X20frame_X3D), - /* K39 */ be_nested_str_weak(inspect), - /* K40 */ be_nested_str_weak(MTR_X3A_X20rejected_X20duplicate_X20encrypted_X20message_X20_X3D_X20), - /* K41 */ be_nested_str_weak(_X20counter_X3D), - /* K42 */ be_nested_str_weak(decrypt), - /* K43 */ be_nested_str_weak(raw), - /* K44 */ be_nested_str_weak(payload_idx), - /* K45 */ be_const_int(1), - /* K46 */ be_nested_str_weak(MTR_X3A_X20idx_X3D_X25i_X20clear_X3D_X25s), - /* K47 */ be_nested_str_weak(MTR_X3A_X20decrypted_X20message_X3A_X20protocol_id_X3A), - /* K48 */ be_nested_str_weak(protocol_id), - /* K49 */ be_nested_str_weak(_X20opcode_X3D), - /* K50 */ be_nested_str_weak(_X20exchange_id), - /* K51 */ be_nested_str_weak(exchange_id), - /* K52 */ be_nested_str_weak(MTR_X3A_X20PROTOCOL_ID_SECURE_CHANNEL_X20), - /* K53 */ be_nested_str_weak(im), - /* K54 */ be_nested_str_weak(MTR_X3A_X20ignoring_X20unhandled_X20protocol_id_X3A), - /* K55 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20exception_X3A_X20), - /* K56 */ be_nested_str_weak(_X3B), - /* K57 */ be_nested_str_weak(debug), - /* K58 */ be_nested_str_weak(traceback), + /* K1 */ be_nested_str_weak(x_flag_r), + /* K2 */ be_nested_str_weak(build_standalone_ack), + /* K3 */ be_nested_str_weak(encode_frame), + /* K4 */ be_nested_str_weak(encrypt), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(format), + /* K8 */ be_nested_str_weak(MTR_X3A_X20_X3CAck_X2A_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20ack_X3D_X25i_X20id_X3D_X25i_X20_X25s), + /* K9 */ be_nested_str_weak(session), + /* K10 */ be_nested_str_weak(local_session_id), + /* K11 */ be_nested_str_weak(ack_message_counter), + /* K12 */ be_nested_str_weak(message_counter), + /* K13 */ be_nested_str_weak(_X7Breliable_X7D), + /* K14 */ be_nested_str_weak(), + /* K15 */ be_const_int(3), + /* K16 */ be_nested_str_weak(send_response_frame), }), - be_str_weak(msg_received), + be_str_weak(send_encrypted_ack), &be_const_str_solidified, - ( &(const binstruction[291]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xA802010A, // 0001 EXBLK 0 #010D - 0xB8160200, // 0002 GETNGBL R5 K1 - 0x8C140B02, // 0003 GETMET R5 R5 K2 - 0x8C1C0304, // 0004 GETMET R7 R1 K4 - 0x7C1C0200, // 0005 CALL R7 1 - 0x001E0607, // 0006 ADD R7 K3 R7 - 0x54220003, // 0007 LDINT R8 4 - 0x7C140600, // 0008 CALL R5 3 - 0xB8160A00, // 0009 GETNGBL R5 K5 - 0x8C140B06, // 000A GETMET R5 R5 K6 - 0x5C1C0000, // 000B MOVE R7 R0 - 0x5C200200, // 000C MOVE R8 R1 - 0x5C240400, // 000D MOVE R9 R2 - 0x5C280600, // 000E MOVE R10 R3 - 0x7C140A00, // 000F CALL R5 5 - 0x8C180B07, // 0010 GETMET R6 R5 K7 - 0x7C180200, // 0011 CALL R6 1 - 0x5C1C0C00, // 0012 MOVE R7 R6 - 0x741E0002, // 0013 JMPT R7 #0017 - 0x501C0000, // 0014 LDBOOL R7 0 0 - 0xA8040001, // 0015 EXBLK 1 1 - 0x80040E00, // 0016 RET 1 R7 - 0x881C0B08, // 0017 GETMBR R7 R5 K8 - 0x1C1C0F09, // 0018 EQ R7 R7 K9 - 0x781E0057, // 0019 JMPF R7 #0072 - 0x881C0B0A, // 001A GETMBR R7 R5 K10 - 0x1C1C0F09, // 001B EQ R7 R7 K9 - 0x781E0054, // 001C JMPF R7 #0072 - 0x881C010B, // 001D GETMBR R7 R0 K11 - 0x881C0F0C, // 001E GETMBR R7 R7 K12 - 0x8C1C0F0D, // 001F GETMET R7 R7 K13 - 0x88240B0E, // 0020 GETMBR R9 R5 K14 - 0x542A0059, // 0021 LDINT R10 90 - 0x7C1C0600, // 0022 CALL R7 3 - 0xB8220200, // 0023 GETNGBL R8 K1 - 0x8C201102, // 0024 GETMET R8 R8 K2 - 0x60280008, // 0025 GETGBL R10 G8 - 0x882C0B0E, // 0026 GETMBR R11 R5 K14 - 0x7C280200, // 0027 CALL R10 1 - 0x002A1E0A, // 0028 ADD R10 K15 R10 - 0x00281510, // 0029 ADD R10 R10 K16 - 0x602C0008, // 002A GETGBL R11 G8 - 0x88300F08, // 002B GETMBR R12 R7 K8 - 0x7C2C0200, // 002C CALL R11 1 - 0x0028140B, // 002D ADD R10 R10 R11 - 0x582C0011, // 002E LDCONST R11 K17 - 0x7C200600, // 002F CALL R8 3 - 0x90162407, // 0030 SETMBR R5 K18 R7 - 0x88200113, // 0031 GETMBR R8 R0 K19 - 0x8C201114, // 0032 GETMET R8 R8 K20 - 0x88280B15, // 0033 GETMBR R10 R5 K21 - 0x502C0000, // 0034 LDBOOL R11 0 0 - 0x7C200600, // 0035 CALL R8 3 - 0x7422000D, // 0036 JMPT R8 #0045 - 0xB8220200, // 0037 GETNGBL R8 K1 - 0x8C201102, // 0038 GETMET R8 R8 K2 - 0x8C280916, // 0039 GETMET R10 R4 K22 - 0x58300017, // 003A LDCONST R12 K23 - 0x88340B15, // 003B GETMBR R13 R5 K21 - 0x88380113, // 003C GETMBR R14 R0 K19 - 0x8C381D18, // 003D GETMET R14 R14 K24 - 0x7C380200, // 003E CALL R14 1 - 0x7C280800, // 003F CALL R10 4 - 0x582C0011, // 0040 LDCONST R11 K17 - 0x7C200600, // 0041 CALL R8 3 - 0x50200000, // 0042 LDBOOL R8 0 0 - 0xA8040001, // 0043 EXBLK 1 1 - 0x80041000, // 0044 RET 1 R8 - 0x8C200B19, // 0045 GETMET R8 R5 K25 - 0x7C200200, // 0046 CALL R8 1 - 0x74220002, // 0047 JMPT R8 #004B - 0x50200000, // 0048 LDBOOL R8 0 0 - 0xA8040001, // 0049 EXBLK 1 1 - 0x80041000, // 004A RET 1 R8 - 0x8820010B, // 004B GETMBR R8 R0 K11 - 0x8C20111A, // 004C GETMET R8 R8 K26 - 0x88280B1B, // 004D GETMBR R10 R5 K27 - 0x7C200400, // 004E CALL R8 2 - 0x88200B1C, // 004F GETMBR R8 R5 K28 - 0x5426000F, // 0050 LDINT R9 16 - 0x20201009, // 0051 NE R8 R8 R9 - 0x78220014, // 0052 JMPF R8 #0068 - 0xB8220A00, // 0053 GETNGBL R8 K5 - 0x8C20111D, // 0054 GETMET R8 R8 K29 - 0x88280B1C, // 0055 GETMBR R10 R5 K28 - 0x7C200400, // 0056 CALL R8 2 - 0x5C241000, // 0057 MOVE R9 R8 - 0x74260004, // 0058 JMPT R9 #005E - 0x8C240916, // 0059 GETMET R9 R4 K22 - 0x582C001E, // 005A LDCONST R11 K30 - 0x88300B1C, // 005B GETMBR R12 R5 K28 - 0x7C240600, // 005C CALL R9 3 - 0x5C201200, // 005D MOVE R8 R9 - 0xB8260200, // 005E GETNGBL R9 K1 - 0x8C241302, // 005F GETMET R9 R9 K2 - 0x8C2C0916, // 0060 GETMET R11 R4 K22 - 0x5834001F, // 0061 LDCONST R13 K31 - 0x5C381000, // 0062 MOVE R14 R8 - 0x5C3C0400, // 0063 MOVE R15 R2 - 0x5C400600, // 0064 MOVE R16 R3 - 0x7C2C0A00, // 0065 CALL R11 5 - 0x58300020, // 0066 LDCONST R12 K32 - 0x7C240600, // 0067 CALL R9 3 - 0x88200121, // 0068 GETMBR R8 R0 K33 - 0x8C201122, // 0069 GETMET R8 R8 K34 - 0x5C280A00, // 006A MOVE R10 R5 - 0x5C2C0400, // 006B MOVE R11 R2 - 0x5C300600, // 006C MOVE R12 R3 - 0x7C200800, // 006D CALL R8 4 - 0x50200200, // 006E LDBOOL R8 1 0 - 0xA8040001, // 006F EXBLK 1 1 - 0x80041000, // 0070 RET 1 R8 - 0x70020095, // 0071 JMP #0108 - 0xB81E0200, // 0072 GETNGBL R7 K1 - 0x8C1C0F02, // 0073 GETMET R7 R7 K2 - 0x8C240916, // 0074 GETMET R9 R4 K22 - 0x582C0023, // 0075 LDCONST R11 K35 - 0x88300B08, // 0076 GETMBR R12 R5 K8 - 0x88340B15, // 0077 GETMBR R13 R5 K21 - 0x7C240800, // 0078 CALL R9 4 - 0x58280011, // 0079 LDCONST R10 K17 - 0x7C1C0600, // 007A CALL R7 3 - 0x881C010B, // 007B GETMBR R7 R0 K11 - 0x881C0F0C, // 007C GETMBR R7 R7 K12 - 0x8C1C0F24, // 007D GETMET R7 R7 K36 - 0x88240B08, // 007E GETMBR R9 R5 K8 - 0x7C1C0400, // 007F CALL R7 2 - 0x4C200000, // 0080 LDNIL R8 - 0x1C200E08, // 0081 EQ R8 R7 R8 - 0x78220013, // 0082 JMPF R8 #0097 - 0xB8220200, // 0083 GETNGBL R8 K1 - 0x8C201102, // 0084 GETMET R8 R8 K2 - 0x60280008, // 0085 GETGBL R10 G8 - 0x882C0B08, // 0086 GETMBR R11 R5 K8 - 0x7C280200, // 0087 CALL R10 1 - 0x002A4A0A, // 0088 ADD R10 K37 R10 - 0x582C0011, // 0089 LDCONST R11 K17 - 0x7C200600, // 008A CALL R8 3 - 0xB8220200, // 008B GETNGBL R8 K1 - 0x8C201102, // 008C GETMET R8 R8 K2 - 0xB82A0A00, // 008D GETNGBL R10 K5 - 0x8C281527, // 008E GETMET R10 R10 K39 - 0x5C300A00, // 008F MOVE R12 R5 - 0x7C280400, // 0090 CALL R10 2 - 0x002A4C0A, // 0091 ADD R10 K38 R10 - 0x582C0011, // 0092 LDCONST R11 K17 - 0x7C200600, // 0093 CALL R8 3 - 0x50200000, // 0094 LDBOOL R8 0 0 - 0xA8040001, // 0095 EXBLK 1 1 - 0x80041000, // 0096 RET 1 R8 - 0x90162407, // 0097 SETMBR R5 K18 R7 - 0x88200F13, // 0098 GETMBR R8 R7 K19 - 0x8C201114, // 0099 GETMET R8 R8 K20 - 0x88280B15, // 009A GETMBR R10 R5 K21 - 0x502C0200, // 009B LDBOOL R11 1 0 - 0x7C200600, // 009C CALL R8 3 - 0x74220011, // 009D JMPT R8 #00B0 - 0xB8220200, // 009E GETNGBL R8 K1 - 0x8C201102, // 009F GETMET R8 R8 K2 - 0x60280008, // 00A0 GETGBL R10 G8 - 0x882C0B15, // 00A1 GETMBR R11 R5 K21 - 0x7C280200, // 00A2 CALL R10 1 - 0x002A500A, // 00A3 ADD R10 K40 R10 - 0x00281529, // 00A4 ADD R10 R10 K41 - 0x602C0008, // 00A5 GETGBL R11 G8 - 0x88300F13, // 00A6 GETMBR R12 R7 K19 - 0x8C301918, // 00A7 GETMET R12 R12 K24 - 0x7C300200, // 00A8 CALL R12 1 - 0x7C2C0200, // 00A9 CALL R11 1 - 0x0028140B, // 00AA ADD R10 R10 R11 - 0x582C0011, // 00AB LDCONST R11 K17 - 0x7C200600, // 00AC CALL R8 3 - 0x50200000, // 00AD LDBOOL R8 0 0 - 0xA8040001, // 00AE EXBLK 1 1 - 0x80041000, // 00AF RET 1 R8 - 0x8C200B2A, // 00B0 GETMET R8 R5 K42 - 0x7C200200, // 00B1 CALL R8 1 - 0x5C241000, // 00B2 MOVE R9 R8 - 0x74260002, // 00B3 JMPT R9 #00B7 - 0x50240000, // 00B4 LDBOOL R9 0 0 - 0xA8040001, // 00B5 EXBLK 1 1 - 0x80041200, // 00B6 RET 1 R9 - 0x88240B2C, // 00B7 GETMBR R9 R5 K44 - 0x0424132D, // 00B8 SUB R9 R9 K45 - 0x40261209, // 00B9 CONNECT R9 K9 R9 - 0x88280B2B, // 00BA GETMBR R10 R5 K43 - 0x94241409, // 00BB GETIDX R9 R10 R9 - 0x90165609, // 00BC SETMBR R5 K43 R9 - 0x88240B2B, // 00BD GETMBR R9 R5 K43 - 0x40241208, // 00BE CONNECT R9 R9 R8 - 0xB8260200, // 00BF GETNGBL R9 K1 - 0x8C241302, // 00C0 GETMET R9 R9 K2 - 0x8C2C0916, // 00C1 GETMET R11 R4 K22 - 0x5834002E, // 00C2 LDCONST R13 K46 - 0x88380B2C, // 00C3 GETMBR R14 R5 K44 - 0x883C0B2B, // 00C4 GETMBR R15 R5 K43 - 0x8C3C1F04, // 00C5 GETMET R15 R15 K4 - 0x7C3C0200, // 00C6 CALL R15 1 - 0x7C2C0800, // 00C7 CALL R11 4 - 0x58300011, // 00C8 LDCONST R12 K17 - 0x7C240600, // 00C9 CALL R9 3 - 0x8C240B19, // 00CA GETMET R9 R5 K25 - 0x7C240200, // 00CB CALL R9 1 - 0xB8260200, // 00CC GETNGBL R9 K1 - 0x8C241302, // 00CD GETMET R9 R9 K2 - 0x602C0008, // 00CE GETGBL R11 G8 - 0x88300B30, // 00CF GETMBR R12 R5 K48 - 0x7C2C0200, // 00D0 CALL R11 1 - 0x002E5E0B, // 00D1 ADD R11 K47 R11 - 0x002C1731, // 00D2 ADD R11 R11 K49 - 0x60300008, // 00D3 GETGBL R12 G8 - 0x88340B1C, // 00D4 GETMBR R13 R5 K28 - 0x7C300200, // 00D5 CALL R12 1 - 0x002C160C, // 00D6 ADD R11 R11 R12 - 0x002C1732, // 00D7 ADD R11 R11 K50 - 0x60300008, // 00D8 GETGBL R12 G8 - 0x88340B33, // 00D9 GETMBR R13 R5 K51 - 0x7C300200, // 00DA CALL R12 1 - 0x002C160C, // 00DB ADD R11 R11 R12 - 0x58300011, // 00DC LDCONST R12 K17 - 0x7C240600, // 00DD CALL R9 3 - 0x8824010B, // 00DE GETMBR R9 R0 K11 - 0x8C24131A, // 00DF GETMET R9 R9 K26 - 0x882C0B1B, // 00E0 GETMBR R11 R5 K27 - 0x7C240400, // 00E1 CALL R9 2 - 0x88240B30, // 00E2 GETMBR R9 R5 K48 - 0x1C281309, // 00E3 EQ R10 R9 K9 - 0x782A000C, // 00E4 JMPF R10 #00F2 - 0xB82A0200, // 00E5 GETNGBL R10 K1 - 0x8C281502, // 00E6 GETMET R10 R10 K2 - 0xB8320A00, // 00E7 GETNGBL R12 K5 - 0x8C301927, // 00E8 GETMET R12 R12 K39 - 0x5C380A00, // 00E9 MOVE R14 R5 - 0x7C300400, // 00EA CALL R12 2 - 0x0032680C, // 00EB ADD R12 K52 R12 - 0x58340011, // 00EC LDCONST R13 K17 - 0x7C280600, // 00ED CALL R10 3 - 0x50280200, // 00EE LDBOOL R10 1 0 - 0xA8040001, // 00EF EXBLK 1 1 - 0x80041400, // 00F0 RET 1 R10 - 0x70020015, // 00F1 JMP #0108 - 0x1C28132D, // 00F2 EQ R10 R9 K45 - 0x782A0008, // 00F3 JMPF R10 #00FD - 0x88280135, // 00F4 GETMBR R10 R0 K53 - 0x8C281522, // 00F5 GETMET R10 R10 K34 - 0x5C300A00, // 00F6 MOVE R12 R5 - 0x5C340400, // 00F7 MOVE R13 R2 - 0x5C380600, // 00F8 MOVE R14 R3 - 0x7C280800, // 00F9 CALL R10 4 - 0xA8040001, // 00FA EXBLK 1 1 - 0x80041400, // 00FB RET 1 R10 - 0x7002000A, // 00FC JMP #0108 - 0xB82A0200, // 00FD GETNGBL R10 K1 - 0x8C281502, // 00FE GETMET R10 R10 K2 - 0x60300008, // 00FF GETGBL R12 G8 - 0x5C341200, // 0100 MOVE R13 R9 - 0x7C300200, // 0101 CALL R12 1 - 0x00326C0C, // 0102 ADD R12 K54 R12 - 0x58340011, // 0103 LDCONST R13 K17 - 0x7C280600, // 0104 CALL R10 3 - 0x50280000, // 0105 LDBOOL R10 0 0 - 0xA8040001, // 0106 EXBLK 1 1 - 0x80041400, // 0107 RET 1 R10 - 0x501C0200, // 0108 LDBOOL R7 1 0 - 0xA8040001, // 0109 EXBLK 1 1 - 0x80040E00, // 010A RET 1 R7 - 0xA8040001, // 010B EXBLK 1 1 - 0x70020014, // 010C JMP #0122 - 0xAC140002, // 010D CATCH R5 0 2 - 0x70020011, // 010E JMP #0121 - 0xB81E0200, // 010F GETNGBL R7 K1 - 0x8C1C0F02, // 0110 GETMET R7 R7 K2 - 0x60240008, // 0111 GETGBL R9 G8 - 0x5C280A00, // 0112 MOVE R10 R5 - 0x7C240200, // 0113 CALL R9 1 - 0x00266E09, // 0114 ADD R9 K55 R9 - 0x00241338, // 0115 ADD R9 R9 K56 - 0x60280008, // 0116 GETGBL R10 G8 - 0x5C2C0C00, // 0117 MOVE R11 R6 - 0x7C280200, // 0118 CALL R10 1 - 0x0024120A, // 0119 ADD R9 R9 R10 - 0x7C1C0400, // 011A CALL R7 2 - 0xA41E7200, // 011B IMPORT R7 K57 - 0x8C200F3A, // 011C GETMET R8 R7 K58 - 0x7C200200, // 011D CALL R8 1 - 0x50200000, // 011E LDBOOL R8 0 0 - 0x80041000, // 011F RET 1 R8 - 0x70020000, // 0120 JMP #0122 - 0xB0080000, // 0121 RAISE 2 R0 R0 - 0x80000000, // 0122 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_session -********************************************************************/ -be_local_closure(Matter_MessageHandler_add_session, /* name */ - be_nested_proto( - 15, /* nstack */ - 7, /* 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(string), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(format), - /* K4 */ be_nested_str_weak(MTR_X3A_X20add_session_X20local_session_id_X3D_X25i_X20initiator_session_id_X3D_X25i), - /* K5 */ be_const_int(3), - /* K6 */ be_nested_str_weak(device), - /* K7 */ be_nested_str_weak(sessions), - /* K8 */ be_nested_str_weak(create_session), - /* K9 */ be_nested_str_weak(set_keys), - }), - be_str_weak(add_session), - &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0xA41E0000, // 0000 IMPORT R7 K0 - 0xB8220200, // 0001 GETNGBL R8 K1 - 0x8C201102, // 0002 GETMET R8 R8 K2 - 0x8C280F03, // 0003 GETMET R10 R7 K3 - 0x58300004, // 0004 LDCONST R12 K4 - 0x5C340200, // 0005 MOVE R13 R1 - 0x5C380400, // 0006 MOVE R14 R2 - 0x7C280800, // 0007 CALL R10 4 - 0x582C0005, // 0008 LDCONST R11 K5 - 0x7C200600, // 0009 CALL R8 3 - 0x88200106, // 000A GETMBR R8 R0 K6 - 0x88201107, // 000B GETMBR R8 R8 K7 - 0x8C201108, // 000C GETMET R8 R8 K8 - 0x5C280200, // 000D MOVE R10 R1 - 0x5C2C0400, // 000E MOVE R11 R2 - 0x7C200600, // 000F CALL R8 3 - 0x8C241109, // 0010 GETMET R9 R8 K9 - 0x5C2C0600, // 0011 MOVE R11 R3 - 0x5C300800, // 0012 MOVE R12 R4 - 0x5C340A00, // 0013 MOVE R13 R5 - 0x5C380C00, // 0014 MOVE R14 R6 - 0x7C240A00, // 0015 CALL R9 5 - 0x80000000, // 0016 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_MessageHandler_init, /* 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(device), - /* K1 */ be_nested_str_weak(commissioning), - /* K2 */ be_nested_str_weak(matter), - /* K3 */ be_nested_str_weak(Commisioning_Context), - /* K4 */ be_nested_str_weak(im), - /* K5 */ be_nested_str_weak(IM), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(Counter), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0xB80A0400, // 0001 GETNGBL R2 K2 - 0x8C080503, // 0002 GETMET R2 R2 K3 - 0x5C100000, // 0003 MOVE R4 R0 - 0x7C080400, // 0004 CALL R2 2 - 0x90020202, // 0005 SETMBR R0 K1 R2 - 0xB80A0400, // 0006 GETNGBL R2 K2 - 0x8C080505, // 0007 GETMET R2 R2 K5 - 0x5C100000, // 0008 MOVE R4 R0 - 0x5C140200, // 0009 MOVE R5 R1 - 0x7C080600, // 000A CALL R2 3 - 0x90020802, // 000B SETMBR R0 K4 R2 - 0xB80A0400, // 000C GETNGBL R2 K2 - 0x8C080507, // 000D GETMET R2 R2 K7 - 0x7C080200, // 000E CALL R2 1 - 0x90020C02, // 000F SETMBR R0 K6 R2 - 0x80000000, // 0010 RET 0 + ( &(const binstruction[29]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x88100301, // 0001 GETMBR R4 R1 K1 + 0x78120018, // 0002 JMPF R4 #001C + 0x8C100302, // 0003 GETMET R4 R1 K2 + 0x5C180400, // 0004 MOVE R6 R2 + 0x7C100400, // 0005 CALL R4 2 + 0x8C140903, // 0006 GETMET R5 R4 K3 + 0x7C140200, // 0007 CALL R5 1 + 0x8C140904, // 0008 GETMET R5 R4 K4 + 0x7C140200, // 0009 CALL R5 1 + 0xB8160A00, // 000A GETNGBL R5 K5 + 0x8C140B06, // 000B GETMET R5 R5 K6 + 0x8C1C0707, // 000C GETMET R7 R3 K7 + 0x58240008, // 000D LDCONST R9 K8 + 0x88280909, // 000E GETMBR R10 R4 K9 + 0x8828150A, // 000F GETMBR R10 R10 K10 + 0x882C090B, // 0010 GETMBR R11 R4 K11 + 0x8830090C, // 0011 GETMBR R12 R4 K12 + 0x780A0001, // 0012 JMPF R2 #0015 + 0x5834000D, // 0013 LDCONST R13 K13 + 0x70020000, // 0014 JMP #0016 + 0x5834000E, // 0015 LDCONST R13 K14 + 0x7C1C0C00, // 0016 CALL R7 6 + 0x5820000F, // 0017 LDCONST R8 K15 + 0x7C140600, // 0018 CALL R5 3 + 0x8C140110, // 0019 GETMET R5 R0 K16 + 0x5C1C0800, // 001A MOVE R7 R4 + 0x7C140400, // 001B CALL R5 2 + 0x80000000, // 001C RET 0 }) ) ); @@ -554,23 +141,666 @@ be_local_closure(Matter_MessageHandler_every_second, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: send_simple_ack +********************************************************************/ +be_local_closure(Matter_MessageHandler_send_simple_ack, /* 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[16]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(x_flag_r), + /* K2 */ be_nested_str_weak(build_standalone_ack), + /* K3 */ be_nested_str_weak(encode_frame), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(log), + /* K6 */ be_nested_str_weak(format), + /* K7 */ be_nested_str_weak(MTR_X3A_X20_X3CAck_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20ack_X3D_X25i_X20id_X3D_X25i_X20_X25s), + /* K8 */ be_nested_str_weak(session), + /* K9 */ be_nested_str_weak(local_session_id), + /* K10 */ be_nested_str_weak(ack_message_counter), + /* K11 */ be_nested_str_weak(message_counter), + /* K12 */ be_nested_str_weak(_X7Breliable_X7D), + /* K13 */ be_nested_str_weak(), + /* K14 */ be_const_int(3), + /* K15 */ be_nested_str_weak(send_response_frame), + }), + be_str_weak(send_simple_ack), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x88100301, // 0001 GETMBR R4 R1 K1 + 0x78120016, // 0002 JMPF R4 #001A + 0x8C100302, // 0003 GETMET R4 R1 K2 + 0x5C180400, // 0004 MOVE R6 R2 + 0x7C100400, // 0005 CALL R4 2 + 0x8C140903, // 0006 GETMET R5 R4 K3 + 0x7C140200, // 0007 CALL R5 1 + 0xB8160800, // 0008 GETNGBL R5 K4 + 0x8C140B05, // 0009 GETMET R5 R5 K5 + 0x8C1C0706, // 000A GETMET R7 R3 K6 + 0x58240007, // 000B LDCONST R9 K7 + 0x88280908, // 000C GETMBR R10 R4 K8 + 0x88281509, // 000D GETMBR R10 R10 K9 + 0x882C090A, // 000E GETMBR R11 R4 K10 + 0x8830090B, // 000F GETMBR R12 R4 K11 + 0x780A0001, // 0010 JMPF R2 #0013 + 0x5834000C, // 0011 LDCONST R13 K12 + 0x70020000, // 0012 JMP #0014 + 0x5834000D, // 0013 LDCONST R13 K13 + 0x7C1C0C00, // 0014 CALL R7 6 + 0x5820000E, // 0015 LDCONST R8 K14 + 0x7C140600, // 0016 CALL R5 3 + 0x8C14010F, // 0017 GETMET R5 R0 K15 + 0x5C1C0800, // 0018 MOVE R7 R4 + 0x7C140400, // 0019 CALL R5 2 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: msg_received +********************************************************************/ +be_local_closure(Matter_MessageHandler_msg_received, /* name */ + be_nested_proto( + 24, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[75]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Frame), + /* K3 */ be_nested_str_weak(decode_header), + /* K4 */ be_nested_str_weak(sec_p), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(log), + /* K7 */ be_nested_str_weak(MTR_X3A_X20CONTROL_X20MESSAGE_X3D), + /* K8 */ be_nested_str_weak(inspect), + /* K9 */ be_nested_str_weak(device), + /* K10 */ be_nested_str_weak(sessions), + /* K11 */ be_nested_str_weak(find_session_source_id_unsecure), + /* K12 */ be_nested_str_weak(source_node_id), + /* K13 */ be_nested_str_weak(MTR_X3A_X20find_X20session_X20by_X20source_node_id_X20_X3D_X20), + /* K14 */ be_nested_str_weak(_X20session_id_X20_X3D_X20), + /* K15 */ be_nested_str_weak(local_session_id), + /* K16 */ be_const_int(2), + /* K17 */ be_nested_str_weak(control_message), + /* K18 */ be_nested_str_weak(process_incoming_control_message), + /* K19 */ be_const_int(0), + /* K20 */ be_nested_str_weak(sec_sesstype), + /* K21 */ be_const_int(3), + /* K22 */ be_nested_str_weak(_ip), + /* K23 */ be_nested_str_weak(_port), + /* K24 */ be_nested_str_weak(_message_handler), + /* K25 */ be_nested_str_weak(session), + /* K26 */ be_nested_str_weak(_counter_insecure_rcv), + /* K27 */ be_nested_str_weak(validate), + /* K28 */ be_nested_str_weak(message_counter), + /* K29 */ be_nested_str_weak(format), + /* K30 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Duplicate_X20unencrypted_X20message_X20_X3D_X20_X25i_X20ref_X20_X3D_X20_X25i), + /* K31 */ be_nested_str_weak(val), + /* K32 */ be_nested_str_weak(send_simple_ack), + /* K33 */ be_nested_str_weak(decode_payload), + /* K34 */ be_nested_str_weak(received_ack), + /* K35 */ be_nested_str_weak(opcode), + /* K36 */ be_nested_str_weak(get_opcode_name), + /* K37 */ be_nested_str_weak(0x_X2502X), + /* K38 */ be_nested_str_weak(MTR_X3A_X20_X3EReceived_X20_X20_X28_X256i_X29_X20_X25s_X20rid_X3D_X25i_X20exch_X3D_X25i_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K39 */ be_nested_str_weak(exchange_id), + /* K40 */ be_nested_str_weak(MTR_X3A_X20_X3Ercv_X20Ack_X20_X20_X20_X28_X256i_X29_X20rid_X3D_X25i_X20exch_X3D_X25i_X20ack_X3D_X25s_X20_X25sfrom_X20_X5B_X25s_X5D_X3A_X25i), + /* K41 */ be_nested_str_weak(x_flag_r), + /* K42 */ be_nested_str_weak(_X7Breliable_X7D_X20), + /* K43 */ be_nested_str_weak(), + /* K44 */ be_nested_str_weak(ack_message_counter), + /* K45 */ be_nested_str_weak(commissioning), + /* K46 */ be_nested_str_weak(process_incoming), + /* K47 */ be_nested_str_weak(MTR_X3A_X20decode_X20header_X3A_X20local_session_id_X3D_X25i_X20message_counter_X3D_X25i), + /* K48 */ be_nested_str_weak(get_session_by_local_session_id), + /* K49 */ be_nested_str_weak(MTR_X3A_X20unknown_X20local_session_id_X3D), + /* K50 */ be_nested_str_weak(counter_rcv_validate), + /* K51 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Duplicate_X20encrypted_X20message_X20_X3D_X20), + /* K52 */ be_nested_str_weak(_X20counter_X3D), + /* K53 */ be_nested_str_weak(counter_rcv), + /* K54 */ be_nested_str_weak(send_encrypted_ack), + /* K55 */ be_nested_str_weak(decrypt), + /* K56 */ be_nested_str_weak(raw), + /* K57 */ be_nested_str_weak(payload_idx), + /* K58 */ be_const_int(1), + /* K59 */ be_nested_str_weak(MTR_X3A_X20idx_X3D_X25i_X20clear_X3D_X25s), + /* K60 */ be_nested_str_weak(tohex), + /* K61 */ be_nested_str_weak(MTR_X3A_X20_X3E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Decrypted_X20message_X3A_X20protocol_id_X3A), + /* K62 */ be_nested_str_weak(protocol_id), + /* K63 */ be_nested_str_weak(_X20opcode_X3D), + /* K64 */ be_nested_str_weak(_X20exchange_id_X3D), + /* K65 */ be_nested_str_weak(MTR_X3A_X20_X3Ercv_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20_X5B_X2502X_X2F_X2502X_X5D_X20rid_X3D_X25i_X20exch_X3D_X25i_X20ack_X3D_X25s_X20_X25sfrom_X20_X5B_X25s_X5D_X3A_X25i), + /* K66 */ be_nested_str_weak(MTR_X3A_X20PROTOCOL_ID_SECURE_CHANNEL_X20), + /* K67 */ be_nested_str_weak(im), + /* K68 */ be_nested_str_weak(process_incoming_ack), + /* K69 */ be_nested_str_weak(send_enqueued), + /* K70 */ be_nested_str_weak(MTR_X3A_X20ignoring_X20unhandled_X20protocol_id_X3A), + /* K71 */ be_nested_str_weak(MTR_X3A_X20MessageHandler_X3A_X3Amsg_received_X20exception_X3A_X20), + /* K72 */ be_nested_str_weak(_X3B), + /* K73 */ be_nested_str_weak(debug), + /* K74 */ be_nested_str_weak(traceback), + }), + be_str_weak(msg_received), + &be_const_str_solidified, + ( &(const binstruction[396]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0x50140000, // 0001 LDBOOL R5 0 0 + 0xA8020172, // 0002 EXBLK 0 #0176 + 0xB81A0200, // 0003 GETNGBL R6 K1 + 0x8C180D02, // 0004 GETMET R6 R6 K2 + 0x5C200000, // 0005 MOVE R8 R0 + 0x5C240200, // 0006 MOVE R9 R1 + 0x5C280400, // 0007 MOVE R10 R2 + 0x5C2C0600, // 0008 MOVE R11 R3 + 0x7C180A00, // 0009 CALL R6 5 + 0x8C1C0D03, // 000A GETMET R7 R6 K3 + 0x7C1C0200, // 000B CALL R7 1 + 0x5C200E00, // 000C MOVE R8 R7 + 0x74220002, // 000D JMPT R8 #0011 + 0x50200000, // 000E LDBOOL R8 0 0 + 0xA8040001, // 000F EXBLK 1 1 + 0x80041000, // 0010 RET 1 R8 + 0x88200D04, // 0011 GETMBR R8 R6 K4 + 0x78220021, // 0012 JMPF R8 #0035 + 0xB8220A00, // 0013 GETNGBL R8 K5 + 0x8C201106, // 0014 GETMET R8 R8 K6 + 0xB82A0200, // 0015 GETNGBL R10 K1 + 0x8C281508, // 0016 GETMET R10 R10 K8 + 0x5C300C00, // 0017 MOVE R12 R6 + 0x7C280400, // 0018 CALL R10 2 + 0x002A0E0A, // 0019 ADD R10 K7 R10 + 0x7C200400, // 001A CALL R8 2 + 0x88200109, // 001B GETMBR R8 R0 K9 + 0x8820110A, // 001C GETMBR R8 R8 K10 + 0x8C20110B, // 001D GETMET R8 R8 K11 + 0x88280D0C, // 001E GETMBR R10 R6 K12 + 0x542E0059, // 001F LDINT R11 90 + 0x7C200600, // 0020 CALL R8 3 + 0xB8260A00, // 0021 GETNGBL R9 K5 + 0x8C241306, // 0022 GETMET R9 R9 K6 + 0x602C0008, // 0023 GETGBL R11 G8 + 0x88300D0C, // 0024 GETMBR R12 R6 K12 + 0x7C2C0200, // 0025 CALL R11 1 + 0x002E1A0B, // 0026 ADD R11 K13 R11 + 0x002C170E, // 0027 ADD R11 R11 K14 + 0x60300008, // 0028 GETGBL R12 G8 + 0x8834110F, // 0029 GETMBR R13 R8 K15 + 0x7C300200, // 002A CALL R12 1 + 0x002C160C, // 002B ADD R11 R11 R12 + 0x58300010, // 002C LDCONST R12 K16 + 0x7C240600, // 002D CALL R9 3 + 0x88240111, // 002E GETMBR R9 R0 K17 + 0x8C241312, // 002F GETMET R9 R9 K18 + 0x5C2C0C00, // 0030 MOVE R11 R6 + 0x7C240400, // 0031 CALL R9 2 + 0xA8040001, // 0032 EXBLK 1 1 + 0x80041200, // 0033 RET 1 R9 + 0x7002013C, // 0034 JMP #0172 + 0x88200D0F, // 0035 GETMBR R8 R6 K15 + 0x1C201113, // 0036 EQ R8 R8 K19 + 0x7822007D, // 0037 JMPF R8 #00B6 + 0x88200D14, // 0038 GETMBR R8 R6 K20 + 0x1C201113, // 0039 EQ R8 R8 K19 + 0x7822007A, // 003A JMPF R8 #00B6 + 0x88200109, // 003B GETMBR R8 R0 K9 + 0x8820110A, // 003C GETMBR R8 R8 K10 + 0x8C20110B, // 003D GETMET R8 R8 K11 + 0x88280D0C, // 003E GETMBR R10 R6 K12 + 0x542E0059, // 003F LDINT R11 90 + 0x7C200600, // 0040 CALL R8 3 + 0xB8260A00, // 0041 GETNGBL R9 K5 + 0x8C241306, // 0042 GETMET R9 R9 K6 + 0x602C0008, // 0043 GETGBL R11 G8 + 0x88300D0C, // 0044 GETMBR R12 R6 K12 + 0x7C2C0200, // 0045 CALL R11 1 + 0x002E1A0B, // 0046 ADD R11 K13 R11 + 0x002C170E, // 0047 ADD R11 R11 K14 + 0x60300008, // 0048 GETGBL R12 G8 + 0x8834110F, // 0049 GETMBR R13 R8 K15 + 0x7C300200, // 004A CALL R12 1 + 0x002C160C, // 004B ADD R11 R11 R12 + 0x58300015, // 004C LDCONST R12 K21 + 0x7C240600, // 004D CALL R9 3 + 0x780A0000, // 004E JMPF R2 #0050 + 0x90222C02, // 004F SETMBR R8 K22 R2 + 0x780E0000, // 0050 JMPF R3 #0052 + 0x90222E03, // 0051 SETMBR R8 K23 R3 + 0x90223000, // 0052 SETMBR R8 K24 R0 + 0x901A3208, // 0053 SETMBR R6 K25 R8 + 0x8824111A, // 0054 GETMBR R9 R8 K26 + 0x8C24131B, // 0055 GETMET R9 R9 K27 + 0x882C0D1C, // 0056 GETMBR R11 R6 K28 + 0x50300000, // 0057 LDBOOL R12 0 0 + 0x7C240600, // 0058 CALL R9 3 + 0x74260011, // 0059 JMPT R9 #006C + 0xB8260A00, // 005A GETNGBL R9 K5 + 0x8C241306, // 005B GETMET R9 R9 K6 + 0x8C2C091D, // 005C GETMET R11 R4 K29 + 0x5834001E, // 005D LDCONST R13 K30 + 0x88380D1C, // 005E GETMBR R14 R6 K28 + 0x883C111A, // 005F GETMBR R15 R8 K26 + 0x8C3C1F1F, // 0060 GETMET R15 R15 K31 + 0x7C3C0200, // 0061 CALL R15 1 + 0x7C2C0800, // 0062 CALL R11 4 + 0x58300015, // 0063 LDCONST R12 K21 + 0x7C240600, // 0064 CALL R9 3 + 0x8C240120, // 0065 GETMET R9 R0 K32 + 0x5C2C0C00, // 0066 MOVE R11 R6 + 0x50300000, // 0067 LDBOOL R12 0 0 + 0x7C240600, // 0068 CALL R9 3 + 0x50240000, // 0069 LDBOOL R9 0 0 + 0xA8040001, // 006A EXBLK 1 1 + 0x80041200, // 006B RET 1 R9 + 0x8C240D21, // 006C GETMET R9 R6 K33 + 0x7C240200, // 006D CALL R9 1 + 0x74260002, // 006E JMPT R9 #0072 + 0x50240000, // 006F LDBOOL R9 0 0 + 0xA8040001, // 0070 EXBLK 1 1 + 0x80041200, // 0071 RET 1 R9 + 0x88240109, // 0072 GETMBR R9 R0 K9 + 0x8C241322, // 0073 GETMET R9 R9 K34 + 0x5C2C0C00, // 0074 MOVE R11 R6 + 0x7C240400, // 0075 CALL R9 2 + 0x88240D23, // 0076 GETMBR R9 R6 K35 + 0x542A000F, // 0077 LDINT R10 16 + 0x2024120A, // 0078 NE R9 R9 R10 + 0x78260018, // 0079 JMPF R9 #0093 + 0xB8260200, // 007A GETNGBL R9 K1 + 0x8C241324, // 007B GETMET R9 R9 K36 + 0x882C0D23, // 007C GETMBR R11 R6 K35 + 0x7C240400, // 007D CALL R9 2 + 0x5C281200, // 007E MOVE R10 R9 + 0x742A0004, // 007F JMPT R10 #0085 + 0x8C28091D, // 0080 GETMET R10 R4 K29 + 0x58300025, // 0081 LDCONST R12 K37 + 0x88340D23, // 0082 GETMBR R13 R6 K35 + 0x7C280600, // 0083 CALL R10 3 + 0x5C241400, // 0084 MOVE R9 R10 + 0xB82A0A00, // 0085 GETNGBL R10 K5 + 0x8C281506, // 0086 GETMET R10 R10 K6 + 0x8C30091D, // 0087 GETMET R12 R4 K29 + 0x58380026, // 0088 LDCONST R14 K38 + 0x883C110F, // 0089 GETMBR R15 R8 K15 + 0x5C401200, // 008A MOVE R16 R9 + 0x88440D1C, // 008B GETMBR R17 R6 K28 + 0x88480D27, // 008C GETMBR R18 R6 K39 + 0x5C4C0400, // 008D MOVE R19 R2 + 0x5C500600, // 008E MOVE R20 R3 + 0x7C301000, // 008F CALL R12 8 + 0x58340010, // 0090 LDCONST R13 K16 + 0x7C280600, // 0091 CALL R10 3 + 0x70020013, // 0092 JMP #00A7 + 0xB8260A00, // 0093 GETNGBL R9 K5 + 0x8C241306, // 0094 GETMET R9 R9 K6 + 0x8C2C091D, // 0095 GETMET R11 R4 K29 + 0x58340028, // 0096 LDCONST R13 K40 + 0x8838110F, // 0097 GETMBR R14 R8 K15 + 0x883C0D1C, // 0098 GETMBR R15 R6 K28 + 0x88400D29, // 0099 GETMBR R16 R6 K41 + 0x78420001, // 009A JMPF R16 #009D + 0x5840002A, // 009B LDCONST R16 K42 + 0x70020000, // 009C JMP #009E + 0x5840002B, // 009D LDCONST R16 K43 + 0x88440D27, // 009E GETMBR R17 R6 K39 + 0x60480008, // 009F GETGBL R18 G8 + 0x884C0D2C, // 00A0 GETMBR R19 R6 K44 + 0x7C480200, // 00A1 CALL R18 1 + 0x5C4C0400, // 00A2 MOVE R19 R2 + 0x5C500600, // 00A3 MOVE R20 R3 + 0x7C2C1200, // 00A4 CALL R11 9 + 0x58300015, // 00A5 LDCONST R12 K21 + 0x7C240600, // 00A6 CALL R9 3 + 0x8824012D, // 00A7 GETMBR R9 R0 K45 + 0x8C24132E, // 00A8 GETMET R9 R9 K46 + 0x5C2C0C00, // 00A9 MOVE R11 R6 + 0x7C240400, // 00AA CALL R9 2 + 0x5C141200, // 00AB MOVE R5 R9 + 0x5C240A00, // 00AC MOVE R9 R5 + 0x74260003, // 00AD JMPT R9 #00B2 + 0x8C240120, // 00AE GETMET R9 R0 K32 + 0x5C2C0C00, // 00AF MOVE R11 R6 + 0x50300000, // 00B0 LDBOOL R12 0 0 + 0x7C240600, // 00B1 CALL R9 3 + 0x50240200, // 00B2 LDBOOL R9 1 0 + 0xA8040001, // 00B3 EXBLK 1 1 + 0x80041200, // 00B4 RET 1 R9 + 0x700200BB, // 00B5 JMP #0172 + 0xB8220A00, // 00B6 GETNGBL R8 K5 + 0x8C201106, // 00B7 GETMET R8 R8 K6 + 0x8C28091D, // 00B8 GETMET R10 R4 K29 + 0x5830002F, // 00B9 LDCONST R12 K47 + 0x88340D0F, // 00BA GETMBR R13 R6 K15 + 0x88380D1C, // 00BB GETMBR R14 R6 K28 + 0x7C280800, // 00BC CALL R10 4 + 0x582C0015, // 00BD LDCONST R11 K21 + 0x7C200600, // 00BE CALL R8 3 + 0x88200109, // 00BF GETMBR R8 R0 K9 + 0x8820110A, // 00C0 GETMBR R8 R8 K10 + 0x8C201130, // 00C1 GETMET R8 R8 K48 + 0x88280D0F, // 00C2 GETMBR R10 R6 K15 + 0x7C200400, // 00C3 CALL R8 2 + 0x4C240000, // 00C4 LDNIL R9 + 0x1C241009, // 00C5 EQ R9 R8 R9 + 0x7826000A, // 00C6 JMPF R9 #00D2 + 0xB8260A00, // 00C7 GETNGBL R9 K5 + 0x8C241306, // 00C8 GETMET R9 R9 K6 + 0x602C0008, // 00C9 GETGBL R11 G8 + 0x88300D0F, // 00CA GETMBR R12 R6 K15 + 0x7C2C0200, // 00CB CALL R11 1 + 0x002E620B, // 00CC ADD R11 K49 R11 + 0x58300010, // 00CD LDCONST R12 K16 + 0x7C240600, // 00CE CALL R9 3 + 0x50240000, // 00CF LDBOOL R9 0 0 + 0xA8040001, // 00D0 EXBLK 1 1 + 0x80041200, // 00D1 RET 1 R9 + 0x780A0000, // 00D2 JMPF R2 #00D4 + 0x90222C02, // 00D3 SETMBR R8 K22 R2 + 0x780E0000, // 00D4 JMPF R3 #00D6 + 0x90222E03, // 00D5 SETMBR R8 K23 R3 + 0x90223000, // 00D6 SETMBR R8 K24 R0 + 0x901A3208, // 00D7 SETMBR R6 K25 R8 + 0x8C241132, // 00D8 GETMET R9 R8 K50 + 0x882C0D1C, // 00D9 GETMBR R11 R6 K28 + 0x50300200, // 00DA LDBOOL R12 1 0 + 0x7C240600, // 00DB CALL R9 3 + 0x74260013, // 00DC JMPT R9 #00F1 + 0xB8260A00, // 00DD GETNGBL R9 K5 + 0x8C241306, // 00DE GETMET R9 R9 K6 + 0x602C0008, // 00DF GETGBL R11 G8 + 0x88300D1C, // 00E0 GETMBR R12 R6 K28 + 0x7C2C0200, // 00E1 CALL R11 1 + 0x002E660B, // 00E2 ADD R11 K51 R11 + 0x002C1734, // 00E3 ADD R11 R11 K52 + 0x60300008, // 00E4 GETGBL R12 G8 + 0x88341135, // 00E5 GETMBR R13 R8 K53 + 0x7C300200, // 00E6 CALL R12 1 + 0x002C160C, // 00E7 ADD R11 R11 R12 + 0x58300015, // 00E8 LDCONST R12 K21 + 0x7C240600, // 00E9 CALL R9 3 + 0x8C240136, // 00EA GETMET R9 R0 K54 + 0x5C2C0C00, // 00EB MOVE R11 R6 + 0x50300000, // 00EC LDBOOL R12 0 0 + 0x7C240600, // 00ED CALL R9 3 + 0x50240000, // 00EE LDBOOL R9 0 0 + 0xA8040001, // 00EF EXBLK 1 1 + 0x80041200, // 00F0 RET 1 R9 + 0x8C240D37, // 00F1 GETMET R9 R6 K55 + 0x7C240200, // 00F2 CALL R9 1 + 0x5C281200, // 00F3 MOVE R10 R9 + 0x742A0002, // 00F4 JMPT R10 #00F8 + 0x50280000, // 00F5 LDBOOL R10 0 0 + 0xA8040001, // 00F6 EXBLK 1 1 + 0x80041400, // 00F7 RET 1 R10 + 0x88280D39, // 00F8 GETMBR R10 R6 K57 + 0x0428153A, // 00F9 SUB R10 R10 K58 + 0x402A260A, // 00FA CONNECT R10 K19 R10 + 0x882C0D38, // 00FB GETMBR R11 R6 K56 + 0x9428160A, // 00FC GETIDX R10 R11 R10 + 0x901A700A, // 00FD SETMBR R6 K56 R10 + 0x88280D38, // 00FE GETMBR R10 R6 K56 + 0x40281409, // 00FF CONNECT R10 R10 R9 + 0xB82A0A00, // 0100 GETNGBL R10 K5 + 0x8C281506, // 0101 GETMET R10 R10 K6 + 0x8C30091D, // 0102 GETMET R12 R4 K29 + 0x5838003B, // 0103 LDCONST R14 K59 + 0x883C0D39, // 0104 GETMBR R15 R6 K57 + 0x88400D38, // 0105 GETMBR R16 R6 K56 + 0x8C40213C, // 0106 GETMET R16 R16 K60 + 0x7C400200, // 0107 CALL R16 1 + 0x7C300800, // 0108 CALL R12 4 + 0x54360003, // 0109 LDINT R13 4 + 0x7C280600, // 010A CALL R10 3 + 0x8C280D21, // 010B GETMET R10 R6 K33 + 0x7C280200, // 010C CALL R10 1 + 0xB82A0A00, // 010D GETNGBL R10 K5 + 0x8C281506, // 010E GETMET R10 R10 K6 + 0x60300008, // 010F GETGBL R12 G8 + 0x88340D3E, // 0110 GETMBR R13 R6 K62 + 0x7C300200, // 0111 CALL R12 1 + 0x00327A0C, // 0112 ADD R12 K61 R12 + 0x0030193F, // 0113 ADD R12 R12 K63 + 0x60340008, // 0114 GETGBL R13 G8 + 0x88380D23, // 0115 GETMBR R14 R6 K35 + 0x7C340200, // 0116 CALL R13 1 + 0x0030180D, // 0117 ADD R12 R12 R13 + 0x00301940, // 0118 ADD R12 R12 K64 + 0x60340008, // 0119 GETGBL R13 G8 + 0x88380D27, // 011A GETMBR R14 R6 K39 + 0x543EFFFE, // 011B LDINT R15 65535 + 0x2C381C0F, // 011C AND R14 R14 R15 + 0x7C340200, // 011D CALL R13 1 + 0x0030180D, // 011E ADD R12 R12 R13 + 0x58340015, // 011F LDCONST R13 K21 + 0x7C280600, // 0120 CALL R10 3 + 0xB82A0A00, // 0121 GETNGBL R10 K5 + 0x8C281506, // 0122 GETMET R10 R10 K6 + 0x8C30091D, // 0123 GETMET R12 R4 K29 + 0x58380041, // 0124 LDCONST R14 K65 + 0x883C110F, // 0125 GETMBR R15 R8 K15 + 0x88400D3E, // 0126 GETMBR R16 R6 K62 + 0x88440D23, // 0127 GETMBR R17 R6 K35 + 0x88480D1C, // 0128 GETMBR R18 R6 K28 + 0x884C0D27, // 0129 GETMBR R19 R6 K39 + 0x60500008, // 012A GETGBL R20 G8 + 0x88540D2C, // 012B GETMBR R21 R6 K44 + 0x7C500200, // 012C CALL R20 1 + 0x88540D29, // 012D GETMBR R21 R6 K41 + 0x78560001, // 012E JMPF R21 #0131 + 0x5854002A, // 012F LDCONST R21 K42 + 0x70020000, // 0130 JMP #0132 + 0x5854002B, // 0131 LDCONST R21 K43 + 0x5C580400, // 0132 MOVE R22 R2 + 0x5C5C0600, // 0133 MOVE R23 R3 + 0x7C301600, // 0134 CALL R12 11 + 0x58340015, // 0135 LDCONST R13 K21 + 0x7C280600, // 0136 CALL R10 3 + 0x88280109, // 0137 GETMBR R10 R0 K9 + 0x8C281522, // 0138 GETMET R10 R10 K34 + 0x5C300C00, // 0139 MOVE R12 R6 + 0x7C280400, // 013A CALL R10 2 + 0x88280D3E, // 013B GETMBR R10 R6 K62 + 0x1C2C1513, // 013C EQ R11 R10 K19 + 0x782E0018, // 013D JMPF R11 #0157 + 0xB82E0A00, // 013E GETNGBL R11 K5 + 0x8C2C1706, // 013F GETMET R11 R11 K6 + 0xB8360200, // 0140 GETNGBL R13 K1 + 0x8C341B08, // 0141 GETMET R13 R13 K8 + 0x5C3C0C00, // 0142 MOVE R15 R6 + 0x7C340400, // 0143 CALL R13 2 + 0x0036840D, // 0144 ADD R13 K66 R13 + 0x58380015, // 0145 LDCONST R14 K21 + 0x7C2C0600, // 0146 CALL R11 3 + 0x882C0D23, // 0147 GETMBR R11 R6 K35 + 0x5432000F, // 0148 LDINT R12 16 + 0x1C2C160C, // 0149 EQ R11 R11 R12 + 0x782E0009, // 014A JMPF R11 #0155 + 0x882C0143, // 014B GETMBR R11 R0 K67 + 0x8C2C1744, // 014C GETMET R11 R11 K68 + 0x5C340C00, // 014D MOVE R13 R6 + 0x7C2C0400, // 014E CALL R11 2 + 0x5C141600, // 014F MOVE R5 R11 + 0x78160003, // 0150 JMPF R5 #0155 + 0x882C0143, // 0151 GETMBR R11 R0 K67 + 0x8C2C1745, // 0152 GETMET R11 R11 K69 + 0x5C340000, // 0153 MOVE R13 R0 + 0x7C2C0400, // 0154 CALL R11 2 + 0x50140200, // 0155 LDBOOL R5 1 0 + 0x7002001A, // 0156 JMP #0172 + 0x1C2C153A, // 0157 EQ R11 R10 K58 + 0x782E0010, // 0158 JMPF R11 #016A + 0x882C0143, // 0159 GETMBR R11 R0 K67 + 0x8C2C172E, // 015A GETMET R11 R11 K46 + 0x5C340C00, // 015B MOVE R13 R6 + 0x7C2C0400, // 015C CALL R11 2 + 0x5C141600, // 015D MOVE R5 R11 + 0x78160004, // 015E JMPF R5 #0164 + 0x882C0143, // 015F GETMBR R11 R0 K67 + 0x8C2C1745, // 0160 GETMET R11 R11 K69 + 0x5C340000, // 0161 MOVE R13 R0 + 0x7C2C0400, // 0162 CALL R11 2 + 0x70020003, // 0163 JMP #0168 + 0x8C2C0136, // 0164 GETMET R11 R0 K54 + 0x5C340C00, // 0165 MOVE R13 R6 + 0x50380200, // 0166 LDBOOL R14 1 0 + 0x7C2C0600, // 0167 CALL R11 3 + 0x50140200, // 0168 LDBOOL R5 1 0 + 0x70020007, // 0169 JMP #0172 + 0xB82E0A00, // 016A GETNGBL R11 K5 + 0x8C2C1706, // 016B GETMET R11 R11 K6 + 0x60340008, // 016C GETGBL R13 G8 + 0x5C381400, // 016D MOVE R14 R10 + 0x7C340200, // 016E CALL R13 1 + 0x00368C0D, // 016F ADD R13 K70 R13 + 0x58380015, // 0170 LDCONST R14 K21 + 0x7C2C0600, // 0171 CALL R11 3 + 0xA8040001, // 0172 EXBLK 1 1 + 0x80040A00, // 0173 RET 1 R5 + 0xA8040001, // 0174 EXBLK 1 1 + 0x70020014, // 0175 JMP #018B + 0xAC180002, // 0176 CATCH R6 0 2 + 0x70020011, // 0177 JMP #018A + 0xB8220A00, // 0178 GETNGBL R8 K5 + 0x8C201106, // 0179 GETMET R8 R8 K6 + 0x60280008, // 017A GETGBL R10 G8 + 0x5C2C0C00, // 017B MOVE R11 R6 + 0x7C280200, // 017C CALL R10 1 + 0x002A8E0A, // 017D ADD R10 K71 R10 + 0x00281548, // 017E ADD R10 R10 K72 + 0x602C0008, // 017F GETGBL R11 G8 + 0x5C300E00, // 0180 MOVE R12 R7 + 0x7C2C0200, // 0181 CALL R11 1 + 0x0028140B, // 0182 ADD R10 R10 R11 + 0x7C200400, // 0183 CALL R8 2 + 0xA4229200, // 0184 IMPORT R8 K73 + 0x8C24114A, // 0185 GETMET R9 R8 K74 + 0x7C240200, // 0186 CALL R9 1 + 0x50240000, // 0187 LDBOOL R9 0 0 + 0x80041200, // 0188 RET 1 R9 + 0x70020000, // 0189 JMP #018B + 0xB0080000, // 018A RAISE 2 R0 R0 + 0x80000000, // 018B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_250ms +********************************************************************/ +be_local_closure(Matter_MessageHandler_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(im), + /* K1 */ be_nested_str_weak(every_250ms), + }), + 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: init +********************************************************************/ +be_local_closure(Matter_MessageHandler_init, /* 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[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(commissioning), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Commisioning_Context), + /* K4 */ be_nested_str_weak(im), + /* K5 */ be_nested_str_weak(IM), + /* K6 */ be_nested_str_weak(control_message), + /* K7 */ be_nested_str_weak(Control_Message), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0xB80A0400, // 0001 GETNGBL R2 K2 + 0x8C080503, // 0002 GETMET R2 R2 K3 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C080400, // 0004 CALL R2 2 + 0x90020202, // 0005 SETMBR R0 K1 R2 + 0xB80A0400, // 0006 GETNGBL R2 K2 + 0x8C080505, // 0007 GETMET R2 R2 K5 + 0x5C100200, // 0008 MOVE R4 R1 + 0x7C080400, // 0009 CALL R2 2 + 0x90020802, // 000A SETMBR R0 K4 R2 + 0xB80A0400, // 000B GETNGBL R2 K2 + 0x8C080507, // 000C GETMET R2 R2 K7 + 0x5C100000, // 000D MOVE R4 R0 + 0x7C080400, // 000E CALL R2 2 + 0x90020C02, // 000F SETMBR R0 K6 R2 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_MessageHandler ********************************************************************/ be_local_class(Matter_MessageHandler, 4, NULL, - be_nested_map(9, + be_nested_map(11, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(im, 3), be_const_var(2) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_MessageHandler_init_closure) }, + { be_const_key_weak(send_encrypted_ack, -1), be_const_closure(Matter_MessageHandler_send_encrypted_ack_closure) }, { be_const_key_weak(every_second, -1), be_const_closure(Matter_MessageHandler_every_second_closure) }, + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_MessageHandler_every_250ms_closure) }, + { be_const_key_weak(device, -1), be_const_var(0) }, { be_const_key_weak(msg_received, -1), be_const_closure(Matter_MessageHandler_msg_received_closure) }, - { be_const_key_weak(counter_rcv, -1), be_const_var(3) }, - { be_const_key_weak(commissioning, 0), be_const_var(1) }, - { be_const_key_weak(device, 5), be_const_var(0) }, - { be_const_key_weak(init, 8), be_const_closure(Matter_MessageHandler_init_closure) }, - { be_const_key_weak(send_response, 4), be_const_closure(Matter_MessageHandler_send_response_closure) }, - { be_const_key_weak(add_session, 2), be_const_closure(Matter_MessageHandler_add_session_closure) }, - { be_const_key_weak(im, -1), be_const_var(2) }, + { be_const_key_weak(control_message, 4), be_const_var(3) }, + { be_const_key_weak(commissioning, -1), be_const_var(1) }, + { be_const_key_weak(send_simple_ack, 1), be_const_closure(Matter_MessageHandler_send_simple_ack_closure) }, + { be_const_key_weak(send_response_frame, 0), be_const_closure(Matter_MessageHandler_send_response_frame_closure) }, })), be_str_weak(Matter_MessageHandler) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path.h new file mode 100644 index 000000000..1916265ee --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Path.h @@ -0,0 +1,149 @@ +/* Solidification of Matter_Path.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Path; + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_Path_tostring, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(endpoint), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(_X5B_X2502X_X5D), + /* K5 */ be_nested_str_weak(_X5B_X2A_X2A_X5D), + /* K6 */ be_nested_str_weak(cluster), + /* K7 */ be_nested_str_weak(_X2504X_X2F), + /* K8 */ be_nested_str_weak(_X2A_X2A_X2A_X2A_X2F), + /* K9 */ be_nested_str_weak(attribute), + /* K10 */ be_nested_str_weak(_X2504X), + /* K11 */ be_nested_str_weak(command), + /* K12 */ be_nested_str_weak(_X2A_X2A_X2A_X2A), + /* K13 */ be_nested_str_weak(Exception_X3E_X20), + /* K14 */ be_nested_str_weak(_X2C_X20), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[75]) { /* code */ + 0xA802003A, // 0000 EXBLK 0 #003C + 0xA4060000, // 0001 IMPORT R1 K0 + 0x58080001, // 0002 LDCONST R2 K1 + 0x880C0102, // 0003 GETMBR R3 R0 K2 + 0x4C100000, // 0004 LDNIL R4 + 0x200C0604, // 0005 NE R3 R3 R4 + 0x780E0004, // 0006 JMPF R3 #000C + 0x8C0C0303, // 0007 GETMET R3 R1 K3 + 0x58140004, // 0008 LDCONST R5 K4 + 0x88180102, // 0009 GETMBR R6 R0 K2 + 0x7C0C0600, // 000A CALL R3 3 + 0x70020000, // 000B JMP #000D + 0x580C0005, // 000C LDCONST R3 K5 + 0x00080403, // 000D ADD R2 R2 R3 + 0x880C0106, // 000E GETMBR R3 R0 K6 + 0x4C100000, // 000F LDNIL R4 + 0x200C0604, // 0010 NE R3 R3 R4 + 0x780E0004, // 0011 JMPF R3 #0017 + 0x8C0C0303, // 0012 GETMET R3 R1 K3 + 0x58140007, // 0013 LDCONST R5 K7 + 0x88180106, // 0014 GETMBR R6 R0 K6 + 0x7C0C0600, // 0015 CALL R3 3 + 0x70020000, // 0016 JMP #0018 + 0x580C0008, // 0017 LDCONST R3 K8 + 0x00080403, // 0018 ADD R2 R2 R3 + 0x880C0109, // 0019 GETMBR R3 R0 K9 + 0x4C100000, // 001A LDNIL R4 + 0x200C0604, // 001B NE R3 R3 R4 + 0x780E0004, // 001C JMPF R3 #0022 + 0x8C0C0303, // 001D GETMET R3 R1 K3 + 0x5814000A, // 001E LDCONST R5 K10 + 0x88180109, // 001F GETMBR R6 R0 K9 + 0x7C0C0600, // 0020 CALL R3 3 + 0x70020000, // 0021 JMP #0023 + 0x580C0001, // 0022 LDCONST R3 K1 + 0x00080403, // 0023 ADD R2 R2 R3 + 0x880C010B, // 0024 GETMBR R3 R0 K11 + 0x4C100000, // 0025 LDNIL R4 + 0x200C0604, // 0026 NE R3 R3 R4 + 0x780E0004, // 0027 JMPF R3 #002D + 0x8C0C0303, // 0028 GETMET R3 R1 K3 + 0x5814000A, // 0029 LDCONST R5 K10 + 0x8818010B, // 002A GETMBR R6 R0 K11 + 0x7C0C0600, // 002B CALL R3 3 + 0x70020000, // 002C JMP #002E + 0x580C0001, // 002D LDCONST R3 K1 + 0x00080403, // 002E ADD R2 R2 R3 + 0x880C0109, // 002F GETMBR R3 R0 K9 + 0x4C100000, // 0030 LDNIL R4 + 0x1C0C0604, // 0031 EQ R3 R3 R4 + 0x780E0004, // 0032 JMPF R3 #0038 + 0x880C010B, // 0033 GETMBR R3 R0 K11 + 0x4C100000, // 0034 LDNIL R4 + 0x1C0C0604, // 0035 EQ R3 R3 R4 + 0x780E0000, // 0036 JMPF R3 #0038 + 0x0008050C, // 0037 ADD R2 R2 K12 + 0xA8040001, // 0038 EXBLK 1 1 + 0x80040400, // 0039 RET 1 R2 + 0xA8040001, // 003A EXBLK 1 1 + 0x7002000D, // 003B JMP #004A + 0xAC040002, // 003C CATCH R1 0 2 + 0x7002000A, // 003D JMP #0049 + 0x600C0008, // 003E GETGBL R3 G8 + 0x5C100200, // 003F MOVE R4 R1 + 0x7C0C0200, // 0040 CALL R3 1 + 0x000E1A03, // 0041 ADD R3 K13 R3 + 0x000C070E, // 0042 ADD R3 R3 K14 + 0x60100008, // 0043 GETGBL R4 G8 + 0x5C140400, // 0044 MOVE R5 R2 + 0x7C100200, // 0045 CALL R4 1 + 0x000C0604, // 0046 ADD R3 R3 R4 + 0x80040600, // 0047 RET 1 R3 + 0x70020000, // 0048 JMP #004A + 0xB0080000, // 0049 RAISE 2 R0 R0 + 0x80000000, // 004A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Path +********************************************************************/ +be_local_class(Matter_Path, + 6, + NULL, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(log, 4), be_const_var(5) }, + { be_const_key_weak(command, 2), be_const_var(3) }, + { be_const_key_weak(status, -1), be_const_var(4) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_Path_tostring_closure) }, + { be_const_key_weak(cluster, 5), be_const_var(1) }, + { be_const_key_weak(endpoint, -1), be_const_var(0) }, + { be_const_key_weak(attribute, -1), be_const_var(2) }, + })), + be_str_weak(Matter_Path) +); +/*******************************************************************/ + +void be_load_Matter_Path_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Path); + be_setglobal(vm, "Matter_Path"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h index 8091439a8..dac3fc7df 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h @@ -7,58 +7,134 @@ extern const bclass be_class_Matter_Plugin; /******************************************************************** -** Solidified function: read_event +** Solidified function: read_attribute ********************************************************************/ -be_local_closure(Matter_Plugin_read_event, /* name */ +be_local_closure(Matter_Plugin_read_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(read_event), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_init, /* name */ - be_nested_proto( - 3, /* nstack */ - 2, /* argc */ + 15, /* 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(device), - /* K1 */ be_nested_str_weak(endpoints), - /* K2 */ be_nested_str_weak(EMPTY_LIST), - /* K3 */ be_nested_str_weak(clusters), + ( &(const bvalue[18]) { /* 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_const_int(0), + /* K5 */ be_nested_str_weak(Matter_TLV_array), + /* K6 */ be_nested_str_weak(TYPES), + /* K7 */ be_nested_str_weak(keys), + /* K8 */ be_nested_str_weak(add_struct), + /* K9 */ be_nested_str_weak(add_TLV), + /* K10 */ be_nested_str_weak(U2), + /* K11 */ be_const_int(1), + /* K12 */ be_nested_str_weak(stop_iteration), + /* K13 */ be_nested_str_weak(get_cluster_list), + /* K14 */ be_nested_str_weak(U4), + /* K15 */ be_const_int(2), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(create_TLV), }), - be_str_weak(init), + be_str_weak(read_attribute), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x88080102, // 0001 GETMBR R2 R0 K2 - 0x90020202, // 0002 SETMBR R0 K1 R2 - 0x88080102, // 0003 GETMBR R2 R0 K2 - 0x90020602, // 0004 SETMBR R0 K3 R2 - 0x80000000, // 0005 RET 0 + ( &(const binstruction[93]) { /* code */ + 0xB80E0000, // 0000 GETNGBL R3 K0 + 0x880C0701, // 0001 GETMBR R3 R3 K1 + 0x88100502, // 0002 GETMBR R4 R2 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x541A001C, // 0004 LDINT R6 29 + 0x1C180806, // 0005 EQ R6 R4 R6 + 0x781A0052, // 0006 JMPF R6 #005A + 0x1C180B04, // 0007 EQ R6 R5 K4 + 0x781A001C, // 0008 JMPF R6 #0026 + 0x8C180705, // 0009 GETMET R6 R3 K5 + 0x7C180200, // 000A CALL R6 1 + 0x601C0010, // 000B GETGBL R7 G16 + 0x88200106, // 000C GETMBR R8 R0 K6 + 0x8C201107, // 000D GETMET R8 R8 K7 + 0x7C200200, // 000E CALL R8 1 + 0x7C1C0200, // 000F CALL R7 1 + 0xA802000F, // 0010 EXBLK 0 #0021 + 0x5C200E00, // 0011 MOVE R8 R7 + 0x7C200000, // 0012 CALL R8 0 + 0x8C240D08, // 0013 GETMET R9 R6 K8 + 0x7C240200, // 0014 CALL R9 1 + 0x8C281309, // 0015 GETMET R10 R9 K9 + 0x58300004, // 0016 LDCONST R12 K4 + 0x8834070A, // 0017 GETMBR R13 R3 K10 + 0x5C381000, // 0018 MOVE R14 R8 + 0x7C280800, // 0019 CALL R10 4 + 0x8C281309, // 001A GETMET R10 R9 K9 + 0x5830000B, // 001B LDCONST R12 K11 + 0x8834070A, // 001C GETMBR R13 R3 K10 + 0x88380106, // 001D GETMBR R14 R0 K6 + 0x94381C08, // 001E GETIDX R14 R14 R8 + 0x7C280800, // 001F CALL R10 4 + 0x7001FFEF, // 0020 JMP #0011 + 0x581C000C, // 0021 LDCONST R7 K12 + 0xAC1C0200, // 0022 CATCH R7 1 0 + 0xB0080000, // 0023 RAISE 2 R0 R0 + 0x80040C00, // 0024 RET 1 R6 + 0x70020032, // 0025 JMP #0059 + 0x1C180B0B, // 0026 EQ R6 R5 K11 + 0x781A0013, // 0027 JMPF R6 #003C + 0x8C180705, // 0028 GETMET R6 R3 K5 + 0x7C180200, // 0029 CALL R6 1 + 0x601C0010, // 002A GETGBL R7 G16 + 0x8C20010D, // 002B GETMET R8 R0 K13 + 0x7C200200, // 002C CALL R8 1 + 0x7C1C0200, // 002D CALL R7 1 + 0xA8020007, // 002E EXBLK 0 #0037 + 0x5C200E00, // 002F MOVE R8 R7 + 0x7C200000, // 0030 CALL R8 0 + 0x8C240D09, // 0031 GETMET R9 R6 K9 + 0x4C2C0000, // 0032 LDNIL R11 + 0x8830070E, // 0033 GETMBR R12 R3 K14 + 0x5C341000, // 0034 MOVE R13 R8 + 0x7C240800, // 0035 CALL R9 4 + 0x7001FFF7, // 0036 JMP #002F + 0x581C000C, // 0037 LDCONST R7 K12 + 0xAC1C0200, // 0038 CATCH R7 1 0 + 0xB0080000, // 0039 RAISE 2 R0 R0 + 0x80040C00, // 003A RET 1 R6 + 0x7002001C, // 003B JMP #0059 + 0x1C180B0F, // 003C EQ R6 R5 K15 + 0x781A0003, // 003D JMPF R6 #0042 + 0x8C180705, // 003E GETMET R6 R3 K5 + 0x7C180200, // 003F CALL R6 1 + 0x80040C00, // 0040 RET 1 R6 + 0x70020016, // 0041 JMP #0059 + 0x1C180B10, // 0042 EQ R6 R5 K16 + 0x781A0003, // 0043 JMPF R6 #0048 + 0x8C180705, // 0044 GETMET R6 R3 K5 + 0x7C180200, // 0045 CALL R6 1 + 0x80040C00, // 0046 RET 1 R6 + 0x70020010, // 0047 JMP #0059 + 0x541AFFFB, // 0048 LDINT R6 65532 + 0x1C180A06, // 0049 EQ R6 R5 R6 + 0x781A0005, // 004A JMPF R6 #0051 + 0x8C180711, // 004B GETMET R6 R3 K17 + 0x8820070E, // 004C GETMBR R8 R3 K14 + 0x58240004, // 004D LDCONST R9 K4 + 0x7C180600, // 004E CALL R6 3 + 0x80040C00, // 004F RET 1 R6 + 0x70020007, // 0050 JMP #0059 + 0x541AFFFC, // 0051 LDINT R6 65533 + 0x1C180A06, // 0052 EQ R6 R5 R6 + 0x781A0004, // 0053 JMPF R6 #0059 + 0x8C180711, // 0054 GETMET R6 R3 K17 + 0x8820070E, // 0055 GETMBR R8 R3 K14 + 0x5824000B, // 0056 LDCONST R9 K11 + 0x7C180600, // 0057 CALL R6 3 + 0x80040C00, // 0058 RET 1 R6 + 0x70020001, // 0059 JMP #005C + 0x4C180000, // 005A LDNIL R6 + 0x80040C00, // 005B RET 1 R6 + 0x80000000, // 005C RET 0 }) ) ); @@ -108,6 +184,347 @@ be_local_closure(Matter_Plugin_has, /* name */ /*******************************************************************/ +/******************************************************************** +** 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: every_second +********************************************************************/ +be_local_closure(Matter_Plugin_every_second, /* 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(update_shadow), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 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 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** 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( + 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(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 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: get_endpoint +********************************************************************/ +be_local_closure(Matter_Plugin_get_endpoint, /* 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(endpoint), + }), + be_str_weak(get_endpoint), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 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: init +********************************************************************/ +be_local_closure(Matter_Plugin_init, /* name */ + be_nested_proto( + 5, /* 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(device), + /* K1 */ be_nested_str_weak(endpoint), + /* K2 */ be_nested_str_weak(clusters), + /* K3 */ be_nested_str_weak(consolidate_clusters), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x8C0C0103, // 0002 GETMET R3 R0 K3 + 0x7C0C0200, // 0003 CALL R3 1 + 0x90020403, // 0004 SETMBR R0 K2 R3 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** 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: get_attribute_list ********************************************************************/ @@ -121,20 +538,20 @@ be_local_closure(Matter_Plugin_get_attribute_list, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ + ( &(const bvalue[ 2]) { /* constants */ /* K0 */ be_nested_str_weak(clusters), /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(EMPTY_LIST), }), be_str_weak(get_attribute_list), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ + ( &(const binstruction[ 7]) { /* code */ 0x880C0100, // 0000 GETMBR R3 R0 K0 0x8C0C0701, // 0001 GETMET R3 R3 K1 0x5C140400, // 0002 MOVE R5 R2 - 0x88180102, // 0003 GETMBR R6 R0 K2 - 0x7C0C0600, // 0004 CALL R3 3 - 0x80040600, // 0005 RET 1 R3 + 0x60180012, // 0003 GETGBL R6 G18 + 0x7C180000, // 0004 CALL R6 0 + 0x7C0C0600, // 0005 CALL R3 3 + 0x80040600, // 0006 RET 1 R3 }) ) ); @@ -187,6 +604,30 @@ be_local_closure(Matter_Plugin_get_cluster_list, /* name */ /*******************************************************************/ +/******************************************************************** +** 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: invoke_request ********************************************************************/ @@ -213,178 +654,38 @@ be_local_closure(Matter_Plugin_invoke_request, /* name */ /******************************************************************** -** Solidified function: read_attribute +** Solidified function: attribute_updated ********************************************************************/ -be_local_closure(Matter_Plugin_read_attribute, /* name */ +be_local_closure(Matter_Plugin_attribute_updated, /* name */ be_nested_proto( - 4, /* nstack */ - 3, /* 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_attribute), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x80040600, // 0001 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_event -********************************************************************/ -be_local_closure(Matter_Plugin_subscribe_event, /* name */ - be_nested_proto( - 6, /* nstack */ + 11, /* 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: get_cluster_map -********************************************************************/ -be_local_closure(Matter_Plugin_get_cluster_map, /* 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(clusters), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(endpoint), + /* K1 */ be_nested_str_weak(device), + /* K2 */ be_nested_str_weak(attribute_updated), }), - be_str_weak(get_cluster_map), + be_str_weak(attribute_updated), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_endpoints -********************************************************************/ -be_local_closure(Matter_Plugin_get_endpoints, /* 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(endpoints), - }), - be_str_weak(get_endpoints), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: write_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_write_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(write_attribute), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ + ( &(const binstruction[12]) { /* code */ 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** 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_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 + 0x1C140205, // 0001 EQ R5 R1 R5 + 0x78160000, // 0002 JMPF R5 #0004 + 0x88040100, // 0003 GETMBR R1 R0 K0 + 0x88140101, // 0004 GETMBR R5 R0 K1 + 0x8C140B02, // 0005 GETMET R5 R5 K2 + 0x5C1C0200, // 0006 MOVE R7 R1 + 0x5C200400, // 0007 MOVE R8 R2 + 0x5C240600, // 0008 MOVE R9 R3 + 0x5C280800, // 0009 MOVE R10 R4 + 0x7C140A00, // 000A CALL R5 5 + 0x80000000, // 000B RET 0 }) ) ); @@ -397,32 +698,42 @@ be_local_closure(Matter_Plugin_subscribe_attribute, /* name */ be_local_class(Matter_Plugin, 3, NULL, - be_nested_map(18, + be_nested_map(21, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_event, -1), be_const_closure(Matter_Plugin_read_event_closure) }, - { be_const_key_weak(get_cluster_list, -1), be_const_closure(Matter_Plugin_get_cluster_list_closure) }, - { be_const_key_weak(endpoints, 1), be_const_var(1) }, - { be_const_key_weak(get_attribute_list, 9), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, - { be_const_key_weak(device, -1), be_const_var(0) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_invoke_request_closure) }, { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) }, - { be_const_key_weak(has, 13), be_const_closure(Matter_Plugin_has_closure) }, + { be_const_key_weak(attribute_updated, 18), be_const_closure(Matter_Plugin_attribute_updated_closure) }, + { be_const_key_weak(consolidate_clusters, -1), be_const_closure(Matter_Plugin_consolidate_clusters_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Plugin_every_second_closure) }, + { be_const_key_weak(subscribe_attribute, 1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, { be_const_key_weak(subscribe_event, -1), be_const_closure(Matter_Plugin_subscribe_event_closure) }, - { be_const_key_weak(get_cluster_map, -1), be_const_closure(Matter_Plugin_get_cluster_map_closure) }, - { be_const_key_weak(clusters, -1), be_const_var(2) }, - { be_const_key_weak(EMPTY_MAP, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(0, + { be_const_key_weak(device, -1), be_const_var(0) }, + { be_const_key_weak(update_shadow, 17), be_const_closure(Matter_Plugin_update_shadow_closure) }, + { be_const_key_weak(get_endpoint, -1), be_const_closure(Matter_Plugin_get_endpoint_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_invoke_request_closure) }, + { be_const_key_weak(has, 8), be_const_closure(Matter_Plugin_has_closure) }, + { be_const_key_weak(parse_sensors, 13), be_const_closure(Matter_Plugin_parse_sensors_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_init_closure) }, + { be_const_key_weak(get_attribute_list, -1), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, + { be_const_key_weak(timed_request, 9), be_const_closure(Matter_Plugin_timed_request_closure) }, + { be_const_key_weak(read_event, 11), be_const_closure(Matter_Plugin_read_event_closure) }, + { be_const_key_weak(get_cluster_list, -1), be_const_closure(Matter_Plugin_get_cluster_list_closure) }, + { be_const_key_weak(CLUSTERS, 20), 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_weak(get_endpoints, -1), be_const_closure(Matter_Plugin_get_endpoints_closure) }, - { be_const_key_weak(write_attribute, 2), be_const_closure(Matter_Plugin_write_attribute_closure) }, - { be_const_key_weak(timed_request, -1), be_const_closure(Matter_Plugin_timed_request_closure) }, - { be_const_key_weak(init, 4), be_const_closure(Matter_Plugin_init_closure) }, - { be_const_key_weak(subscribe_attribute, -1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, - { be_const_key_weak(EMPTY_LIST, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(0, + { 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(write_attribute, -1), be_const_closure(Matter_Plugin_write_attribute_closure) }, + { be_const_key_weak(clusters, -1), be_const_var(2) }, + { be_const_key_weak(endpoint, -1), be_const_var(1) }, })), 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_Device.h new file mode 100644 index 000000000..b50a887fe --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Device.h @@ -0,0 +1,282 @@ +/* Solidification of Matter_Plugin_Device.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Device; + +/******************************************************************** +** 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[45]) { /* 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 + 0x7002000E, // 001C JMP #002C + 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 + 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: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Device_read_attribute, /* 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_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(3), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(create_TLV), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(U1), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[76]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x1C1C0B05, // 0005 EQ R7 R5 K5 + 0x781E0021, // 0006 JMPF R7 #0029 + 0x1C1C0D06, // 0007 EQ R7 R6 K6 + 0x781E0005, // 0008 JMPF R7 #000F + 0x8C1C0907, // 0009 GETMET R7 R4 K7 + 0x88240908, // 000A GETMBR R9 R4 K8 + 0x58280006, // 000B LDCONST R10 K6 + 0x7C1C0600, // 000C CALL R7 3 + 0x80040E00, // 000D RET 1 R7 + 0x70020018, // 000E JMP #0028 + 0x1C1C0D09, // 000F EQ R7 R6 K9 + 0x781E0005, // 0010 JMPF R7 #0017 + 0x8C1C0907, // 0011 GETMET R7 R4 K7 + 0x8824090A, // 0012 GETMBR R9 R4 K10 + 0x58280006, // 0013 LDCONST R10 K6 + 0x7C1C0600, // 0014 CALL R7 3 + 0x80040E00, // 0015 RET 1 R7 + 0x70020010, // 0016 JMP #0028 + 0x541EFFFB, // 0017 LDINT R7 65532 + 0x1C1C0C07, // 0018 EQ R7 R6 R7 + 0x781E0005, // 0019 JMPF R7 #0020 + 0x8C1C0907, // 001A GETMET R7 R4 K7 + 0x8824090B, // 001B GETMBR R9 R4 K11 + 0x58280006, // 001C LDCONST R10 K6 + 0x7C1C0600, // 001D CALL R7 3 + 0x80040E00, // 001E RET 1 R7 + 0x70020007, // 001F JMP #0028 + 0x541EFFFC, // 0020 LDINT R7 65533 + 0x1C1C0C07, // 0021 EQ R7 R6 R7 + 0x781E0004, // 0022 JMPF R7 #0028 + 0x8C1C0907, // 0023 GETMET R7 R4 K7 + 0x8824090B, // 0024 GETMBR R9 R4 K11 + 0x542A0003, // 0025 LDINT R10 4 + 0x7C1C0600, // 0026 CALL R7 3 + 0x80040E00, // 0027 RET 1 R7 + 0x70020021, // 0028 JMP #004B + 0x541E0003, // 0029 LDINT R7 4 + 0x1C1C0A07, // 002A EQ R7 R5 R7 + 0x781E0016, // 002B JMPF R7 #0043 + 0x1C1C0D06, // 002C EQ R7 R6 K6 + 0x781E0002, // 002D JMPF R7 #0031 + 0x4C1C0000, // 002E LDNIL R7 + 0x80040E00, // 002F RET 1 R7 + 0x70020010, // 0030 JMP #0042 + 0x541EFFFB, // 0031 LDINT R7 65532 + 0x1C1C0C07, // 0032 EQ R7 R6 R7 + 0x781E0005, // 0033 JMPF R7 #003A + 0x8C1C0907, // 0034 GETMET R7 R4 K7 + 0x8824090B, // 0035 GETMBR R9 R4 K11 + 0x58280006, // 0036 LDCONST R10 K6 + 0x7C1C0600, // 0037 CALL R7 3 + 0x80040E00, // 0038 RET 1 R7 + 0x70020007, // 0039 JMP #0042 + 0x541EFFFC, // 003A LDINT R7 65533 + 0x1C1C0C07, // 003B EQ R7 R6 R7 + 0x781E0004, // 003C JMPF R7 #0042 + 0x8C1C0907, // 003D GETMET R7 R4 K7 + 0x8824090B, // 003E GETMBR R9 R4 K11 + 0x542A0003, // 003F LDINT R10 4 + 0x7C1C0600, // 0040 CALL R7 3 + 0x80040E00, // 0041 RET 1 R7 + 0x70020007, // 0042 JMP #004B + 0x601C0003, // 0043 GETGBL R7 G3 + 0x5C200000, // 0044 MOVE R8 R0 + 0x7C1C0200, // 0045 CALL R7 1 + 0x8C1C0F0C, // 0046 GETMET R7 R7 K12 + 0x5C240200, // 0047 MOVE R9 R1 + 0x5C280400, // 0048 MOVE R10 R2 + 0x7C1C0600, // 0049 CALL R7 3 + 0x80040E00, // 004A RET 1 R7 + 0x80000000, // 004B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Device_init, /* name */ + be_nested_proto( + 8, /* nstack */ + 4, /* 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(init), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* 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 + 0x7C100600, // 0006 CALL R4 3 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Device +********************************************************************/ +extern const bclass be_class_Matter_Plugin; +be_local_class(Matter_Plugin_Device, + 0, + &be_class_Matter_Plugin, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { 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(0, -1), be_const_int(0) }, + })) ) } )) }, + { 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(init, -1), be_const_closure(Matter_Plugin_Device_init_closure) }, + { 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(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(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_str_weak(Matter_Plugin_Device) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Device_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Device); + be_setglobal(vm, "Matter_Plugin_Device"); + 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 new file mode 100644 index 000000000..40809e95f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light0.h @@ -0,0 +1,453 @@ +/* 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: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_read_attribute, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(3), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(create_TLV), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(U1), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_nested_str_weak(BOOL), + /* K13 */ be_nested_str_weak(shadow_onoff), + /* K14 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[126]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x1C1C0B05, // 0005 EQ R7 R5 K5 + 0x781E0021, // 0006 JMPF R7 #0029 + 0x1C1C0D06, // 0007 EQ R7 R6 K6 + 0x781E0005, // 0008 JMPF R7 #000F + 0x8C1C0907, // 0009 GETMET R7 R4 K7 + 0x88240908, // 000A GETMBR R9 R4 K8 + 0x58280006, // 000B LDCONST R10 K6 + 0x7C1C0600, // 000C CALL R7 3 + 0x80040E00, // 000D RET 1 R7 + 0x70020018, // 000E JMP #0028 + 0x1C1C0D09, // 000F EQ R7 R6 K9 + 0x781E0005, // 0010 JMPF R7 #0017 + 0x8C1C0907, // 0011 GETMET R7 R4 K7 + 0x8824090A, // 0012 GETMBR R9 R4 K10 + 0x58280006, // 0013 LDCONST R10 K6 + 0x7C1C0600, // 0014 CALL R7 3 + 0x80040E00, // 0015 RET 1 R7 + 0x70020010, // 0016 JMP #0028 + 0x541EFFFB, // 0017 LDINT R7 65532 + 0x1C1C0C07, // 0018 EQ R7 R6 R7 + 0x781E0005, // 0019 JMPF R7 #0020 + 0x8C1C0907, // 001A GETMET R7 R4 K7 + 0x8824090B, // 001B GETMBR R9 R4 K11 + 0x58280006, // 001C LDCONST R10 K6 + 0x7C1C0600, // 001D CALL R7 3 + 0x80040E00, // 001E RET 1 R7 + 0x70020007, // 001F JMP #0028 + 0x541EFFFC, // 0020 LDINT R7 65533 + 0x1C1C0C07, // 0021 EQ R7 R6 R7 + 0x781E0004, // 0022 JMPF R7 #0028 + 0x8C1C0907, // 0023 GETMET R7 R4 K7 + 0x8824090B, // 0024 GETMBR R9 R4 K11 + 0x542A0003, // 0025 LDINT R10 4 + 0x7C1C0600, // 0026 CALL R7 3 + 0x80040E00, // 0027 RET 1 R7 + 0x70020053, // 0028 JMP #007D + 0x541E0003, // 0029 LDINT R7 4 + 0x1C1C0A07, // 002A EQ R7 R5 R7 + 0x781E0016, // 002B JMPF R7 #0043 + 0x1C1C0D06, // 002C EQ R7 R6 K6 + 0x781E0002, // 002D JMPF R7 #0031 + 0x4C1C0000, // 002E LDNIL R7 + 0x80040E00, // 002F RET 1 R7 + 0x70020010, // 0030 JMP #0042 + 0x541EFFFB, // 0031 LDINT R7 65532 + 0x1C1C0C07, // 0032 EQ R7 R6 R7 + 0x781E0005, // 0033 JMPF R7 #003A + 0x8C1C0907, // 0034 GETMET R7 R4 K7 + 0x8824090B, // 0035 GETMBR R9 R4 K11 + 0x58280006, // 0036 LDCONST R10 K6 + 0x7C1C0600, // 0037 CALL R7 3 + 0x80040E00, // 0038 RET 1 R7 + 0x70020007, // 0039 JMP #0042 + 0x541EFFFC, // 003A LDINT R7 65533 + 0x1C1C0C07, // 003B EQ R7 R6 R7 + 0x781E0004, // 003C JMPF R7 #0042 + 0x8C1C0907, // 003D GETMET R7 R4 K7 + 0x8824090B, // 003E GETMBR R9 R4 K11 + 0x542A0003, // 003F LDINT R10 4 + 0x7C1C0600, // 0040 CALL R7 3 + 0x80040E00, // 0041 RET 1 R7 + 0x70020039, // 0042 JMP #007D + 0x541E0004, // 0043 LDINT R7 5 + 0x1C1C0A07, // 0044 EQ R7 R5 R7 + 0x781E0011, // 0045 JMPF R7 #0058 + 0x541EFFFB, // 0046 LDINT R7 65532 + 0x1C1C0C07, // 0047 EQ R7 R6 R7 + 0x781E0005, // 0048 JMPF R7 #004F + 0x8C1C0907, // 0049 GETMET R7 R4 K7 + 0x8824090B, // 004A GETMBR R9 R4 K11 + 0x58280006, // 004B LDCONST R10 K6 + 0x7C1C0600, // 004C CALL R7 3 + 0x80040E00, // 004D RET 1 R7 + 0x70020007, // 004E JMP #0057 + 0x541EFFFC, // 004F LDINT R7 65533 + 0x1C1C0C07, // 0050 EQ R7 R6 R7 + 0x781E0004, // 0051 JMPF R7 #0057 + 0x8C1C0907, // 0052 GETMET R7 R4 K7 + 0x8824090B, // 0053 GETMBR R9 R4 K11 + 0x542A0003, // 0054 LDINT R10 4 + 0x7C1C0600, // 0055 CALL R7 3 + 0x80040E00, // 0056 RET 1 R7 + 0x70020024, // 0057 JMP #007D + 0x541E0005, // 0058 LDINT R7 6 + 0x1C1C0A07, // 0059 EQ R7 R5 R7 + 0x781E0019, // 005A JMPF R7 #0075 + 0x1C1C0D06, // 005B EQ R7 R6 K6 + 0x781E0005, // 005C JMPF R7 #0063 + 0x8C1C0907, // 005D GETMET R7 R4 K7 + 0x8824090C, // 005E GETMBR R9 R4 K12 + 0x8828010D, // 005F GETMBR R10 R0 K13 + 0x7C1C0600, // 0060 CALL R7 3 + 0x80040E00, // 0061 RET 1 R7 + 0x70020010, // 0062 JMP #0074 + 0x541EFFFB, // 0063 LDINT R7 65532 + 0x1C1C0C07, // 0064 EQ R7 R6 R7 + 0x781E0005, // 0065 JMPF R7 #006C + 0x8C1C0907, // 0066 GETMET R7 R4 K7 + 0x8824090B, // 0067 GETMBR R9 R4 K11 + 0x58280006, // 0068 LDCONST R10 K6 + 0x7C1C0600, // 0069 CALL R7 3 + 0x80040E00, // 006A RET 1 R7 + 0x70020007, // 006B JMP #0074 + 0x541EFFFC, // 006C LDINT R7 65533 + 0x1C1C0C07, // 006D EQ R7 R6 R7 + 0x781E0004, // 006E JMPF R7 #0074 + 0x8C1C0907, // 006F GETMET R7 R4 K7 + 0x8824090B, // 0070 GETMBR R9 R4 K11 + 0x542A0003, // 0071 LDINT R10 4 + 0x7C1C0600, // 0072 CALL R7 3 + 0x80040E00, // 0073 RET 1 R7 + 0x70020007, // 0074 JMP #007D + 0x601C0003, // 0075 GETGBL R7 G3 + 0x5C200000, // 0076 MOVE R8 R0 + 0x7C1C0200, // 0077 CALL R7 1 + 0x8C1C0F0E, // 0078 GETMET R7 R7 K14 + 0x5C240200, // 0079 MOVE R9 R1 + 0x5C280400, // 007A MOVE R10 R2 + 0x7C1C0600, // 007B CALL R7 3 + 0x80040E00, // 007C RET 1 R7 + 0x80000000, // 007D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_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[ 7]) { /* 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), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x8C0C0502, // 0003 GETMET R3 R2 K2 + 0x58140003, // 0004 LDCONST R5 K3 + 0x4C180000, // 0005 LDNIL R6 + 0x7C0C0600, // 0006 CALL R3 3 + 0x88100104, // 0007 GETMBR R4 R0 K4 + 0x20100604, // 0008 NE R4 R3 R4 + 0x78120005, // 0009 JMPF R4 #0010 + 0x8C100105, // 000A GETMET R4 R0 K5 + 0x4C180000, // 000B LDNIL R6 + 0x541E0005, // 000C LDINT R7 6 + 0x58200006, // 000D LDCONST R8 K6 + 0x7C100800, // 000E CALL R4 4 + 0x90020803, // 000F SETMBR R0 K4 R3 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_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[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_const_int(3), + /* K6 */ be_const_int(0), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(Matter_TLV_struct), + /* K9 */ be_nested_str_weak(add_TLV), + /* K10 */ be_nested_str_weak(U2), + /* K11 */ be_nested_str_weak(set), + /* K12 */ be_nested_str_weak(power), + /* K13 */ be_nested_str_weak(update_shadow), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(shadow_onoff), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[87]) { /* 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 + 0x1C200D05, // 0005 EQ R8 R6 K5 + 0x78220016, // 0006 JMPF R8 #001E + 0x1C200F06, // 0007 EQ R8 R7 K6 + 0x78220002, // 0008 JMPF R8 #000C + 0x50200200, // 0009 LDBOOL R8 1 0 + 0x80041000, // 000A RET 1 R8 + 0x70020010, // 000B JMP #001D + 0x1C200F07, // 000C EQ R8 R7 K7 + 0x78220009, // 000D JMPF R8 #0018 + 0x8C200B08, // 000E GETMET R8 R5 K8 + 0x7C200200, // 000F CALL R8 1 + 0x8C241109, // 0010 GETMET R9 R8 K9 + 0x582C0006, // 0011 LDCONST R11 K6 + 0x88300B0A, // 0012 GETMBR R12 R5 K10 + 0x58340006, // 0013 LDCONST R13 K6 + 0x7C240800, // 0014 CALL R9 4 + 0x900E0906, // 0015 SETMBR R3 K4 K6 + 0x80041000, // 0016 RET 1 R8 + 0x70020004, // 0017 JMP #001D + 0x5422003F, // 0018 LDINT R8 64 + 0x1C200E08, // 0019 EQ R8 R7 R8 + 0x78220001, // 001A JMPF R8 #001D + 0x50200200, // 001B LDBOOL R8 1 0 + 0x80041000, // 001C RET 1 R8 + 0x70020037, // 001D JMP #0056 + 0x54220003, // 001E LDINT R8 4 + 0x1C200C08, // 001F EQ R8 R6 R8 + 0x78220002, // 0020 JMPF R8 #0024 + 0x50200200, // 0021 LDBOOL R8 1 0 + 0x80041000, // 0022 RET 1 R8 + 0x70020031, // 0023 JMP #0056 + 0x54220004, // 0024 LDINT R8 5 + 0x1C200C08, // 0025 EQ R8 R6 R8 + 0x78220002, // 0026 JMPF R8 #002A + 0x50200200, // 0027 LDBOOL R8 1 0 + 0x80041000, // 0028 RET 1 R8 + 0x7002002B, // 0029 JMP #0056 + 0x54220005, // 002A LDINT R8 6 + 0x1C200C08, // 002B EQ R8 R6 R8 + 0x78220028, // 002C JMPF R8 #0056 + 0x1C200F06, // 002D EQ R8 R7 K6 + 0x7822000A, // 002E JMPF R8 #003A + 0x8C20090B, // 002F GETMET R8 R4 K11 + 0x60280013, // 0030 GETGBL R10 G19 + 0x7C280000, // 0031 CALL R10 0 + 0x502C0000, // 0032 LDBOOL R11 0 0 + 0x982A180B, // 0033 SETIDX R10 K12 R11 + 0x7C200400, // 0034 CALL R8 2 + 0x8C20010D, // 0035 GETMET R8 R0 K13 + 0x7C200200, // 0036 CALL R8 1 + 0x50200200, // 0037 LDBOOL R8 1 0 + 0x80041000, // 0038 RET 1 R8 + 0x7002001B, // 0039 JMP #0056 + 0x1C200F07, // 003A EQ R8 R7 K7 + 0x7822000A, // 003B JMPF R8 #0047 + 0x8C20090B, // 003C GETMET R8 R4 K11 + 0x60280013, // 003D GETGBL R10 G19 + 0x7C280000, // 003E CALL R10 0 + 0x502C0200, // 003F LDBOOL R11 1 0 + 0x982A180B, // 0040 SETIDX R10 K12 R11 + 0x7C200400, // 0041 CALL R8 2 + 0x8C20010D, // 0042 GETMET R8 R0 K13 + 0x7C200200, // 0043 CALL R8 1 + 0x50200200, // 0044 LDBOOL R8 1 0 + 0x80041000, // 0045 RET 1 R8 + 0x7002000E, // 0046 JMP #0056 + 0x1C200F0E, // 0047 EQ R8 R7 K14 + 0x7822000C, // 0048 JMPF R8 #0056 + 0x8C20090B, // 0049 GETMET R8 R4 K11 + 0x60280013, // 004A GETGBL R10 G19 + 0x7C280000, // 004B CALL R10 0 + 0x882C010F, // 004C GETMBR R11 R0 K15 + 0x782E0000, // 004D JMPF R11 #004F + 0x502C0001, // 004E LDBOOL R11 0 1 + 0x502C0200, // 004F LDBOOL R11 1 0 + 0x982A180B, // 0050 SETIDX R10 K12 R11 + 0x7C200400, // 0051 CALL R8 2 + 0x8C20010D, // 0052 GETMET R8 R0 K13 + 0x7C200200, // 0053 CALL R8 1 + 0x50200200, // 0054 LDBOOL R8 1 0 + 0x80041000, // 0055 RET 1 R8 + 0x80000000, // 0056 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_init, /* 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[ 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[10]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C0C0600, // 0006 CALL R3 3 + 0x500C0000, // 0007 LDBOOL R3 0 0 + 0x90020203, // 0008 SETMBR R0 K1 R3 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Light0 +********************************************************************/ +extern const bclass be_class_Matter_Plugin; +be_local_class(Matter_Plugin_Light0, + 1, + &be_class_Matter_Plugin, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_Light0_read_attribute_closure) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Light0_update_shadow_closure) }, + { be_const_key_weak(CLUSTERS, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(4, + ( (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(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_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_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(invoke_request, 2), be_const_closure(Matter_Plugin_Light0_invoke_request_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light0_init_closure) }, + { be_const_key_weak(shadow_onoff, -1), be_const_var(0) }, + })), + 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 new file mode 100644 index 000000000..b19758c0f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light1.h @@ -0,0 +1,428 @@ +/* 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: 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[19]) { /* 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_const_int(0), + /* K6 */ be_nested_str_weak(findsubval), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(scale_uint), + /* K9 */ be_nested_str_weak(set), + /* K10 */ be_nested_str_weak(bri), + /* K11 */ be_nested_str_weak(update_shadow), + /* K12 */ be_nested_str_weak(log), + /* K13 */ be_nested_str_weak(bri_X3A), + /* K14 */ be_const_int(1), + /* K15 */ be_const_int(2), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(power), + /* K18 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[110]) { /* 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 + 0x7822005B, // 0007 JMPF R8 #0064 + 0x1C200F05, // 0008 EQ R8 R7 K5 + 0x78220019, // 0009 JMPF R8 #0024 + 0x8C200506, // 000A GETMET R8 R2 K6 + 0x58280005, // 000B LDCONST R10 K5 + 0x7C200400, // 000C CALL R8 2 + 0xB8260E00, // 000D GETNGBL R9 K7 + 0x8C241308, // 000E GETMET R9 R9 K8 + 0x5C2C1000, // 000F MOVE R11 R8 + 0x58300005, // 0010 LDCONST R12 K5 + 0x543600FD, // 0011 LDINT R13 254 + 0x58380005, // 0012 LDCONST R14 K5 + 0x543E00FE, // 0013 LDINT R15 255 + 0x7C240C00, // 0014 CALL R9 6 + 0x8C280909, // 0015 GETMET R10 R4 K9 + 0x60300013, // 0016 GETGBL R12 G19 + 0x7C300000, // 0017 CALL R12 0 + 0x98321409, // 0018 SETIDX R12 K10 R9 + 0x7C280400, // 0019 CALL R10 2 + 0x8C28010B, // 001A GETMET R10 R0 K11 + 0x7C280200, // 001B CALL R10 1 + 0x60280008, // 001C GETGBL R10 G8 + 0x5C2C1000, // 001D MOVE R11 R8 + 0x7C280200, // 001E CALL R10 1 + 0x002A1A0A, // 001F ADD R10 K13 R10 + 0x900E180A, // 0020 SETMBR R3 K12 R10 + 0x50280200, // 0021 LDBOOL R10 1 0 + 0x80041400, // 0022 RET 1 R10 + 0x7002003E, // 0023 JMP #0063 + 0x1C200F0E, // 0024 EQ R8 R7 K14 + 0x78220002, // 0025 JMPF R8 #0029 + 0x50200200, // 0026 LDBOOL R8 1 0 + 0x80041000, // 0027 RET 1 R8 + 0x70020039, // 0028 JMP #0063 + 0x1C200F0F, // 0029 EQ R8 R7 K15 + 0x78220002, // 002A JMPF R8 #002E + 0x50200200, // 002B LDBOOL R8 1 0 + 0x80041000, // 002C RET 1 R8 + 0x70020034, // 002D JMP #0063 + 0x1C200F10, // 002E EQ R8 R7 K16 + 0x78220002, // 002F JMPF R8 #0033 + 0x50200200, // 0030 LDBOOL R8 1 0 + 0x80041000, // 0031 RET 1 R8 + 0x7002002F, // 0032 JMP #0063 + 0x54220003, // 0033 LDINT R8 4 + 0x1C200E08, // 0034 EQ R8 R7 R8 + 0x7822001B, // 0035 JMPF R8 #0052 + 0x8C200506, // 0036 GETMET R8 R2 K6 + 0x58280005, // 0037 LDCONST R10 K5 + 0x7C200400, // 0038 CALL R8 2 + 0xB8260E00, // 0039 GETNGBL R9 K7 + 0x8C241308, // 003A GETMET R9 R9 K8 + 0x5C2C1000, // 003B MOVE R11 R8 + 0x58300005, // 003C LDCONST R12 K5 + 0x543600FD, // 003D LDINT R13 254 + 0x58380005, // 003E LDCONST R14 K5 + 0x543E00FE, // 003F LDINT R15 255 + 0x7C240C00, // 0040 CALL R9 6 + 0x24281305, // 0041 GT R10 R9 K5 + 0x8C2C0909, // 0042 GETMET R11 R4 K9 + 0x60340013, // 0043 GETGBL R13 G19 + 0x7C340000, // 0044 CALL R13 0 + 0x98361409, // 0045 SETIDX R13 K10 R9 + 0x9836220A, // 0046 SETIDX R13 K17 R10 + 0x7C2C0400, // 0047 CALL R11 2 + 0x8C2C010B, // 0048 GETMET R11 R0 K11 + 0x7C2C0200, // 0049 CALL R11 1 + 0x602C0008, // 004A GETGBL R11 G8 + 0x5C301000, // 004B MOVE R12 R8 + 0x7C2C0200, // 004C CALL R11 1 + 0x002E1A0B, // 004D ADD R11 K13 R11 + 0x900E180B, // 004E SETMBR R3 K12 R11 + 0x502C0200, // 004F LDBOOL R11 1 0 + 0x80041600, // 0050 RET 1 R11 + 0x70020010, // 0051 JMP #0063 + 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 + 0x7002000A, // 0057 JMP #0063 + 0x54220005, // 0058 LDINT R8 6 + 0x1C200E08, // 0059 EQ R8 R7 R8 + 0x78220002, // 005A JMPF R8 #005E + 0x50200200, // 005B LDBOOL R8 1 0 + 0x80041000, // 005C RET 1 R8 + 0x70020004, // 005D JMP #0063 + 0x54220006, // 005E LDINT R8 7 + 0x1C200E08, // 005F EQ R8 R7 R8 + 0x78220001, // 0060 JMPF R8 #0063 + 0x50200200, // 0061 LDBOOL R8 1 0 + 0x80041000, // 0062 RET 1 R8 + 0x70020008, // 0063 JMP #006D + 0x60200003, // 0064 GETGBL R8 G3 + 0x5C240000, // 0065 MOVE R9 R0 + 0x7C200200, // 0066 CALL R8 1 + 0x8C201112, // 0067 GETMET R8 R8 K18 + 0x5C280200, // 0068 MOVE R10 R1 + 0x5C2C0400, // 0069 MOVE R11 R2 + 0x5C300600, // 006A MOVE R12 R3 + 0x7C200800, // 006B CALL R8 4 + 0x80041000, // 006C RET 1 R8 + 0x80000000, // 006D 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[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 + 0x8C0C0502, // 0003 GETMET R3 R2 K2 + 0x58140003, // 0004 LDCONST R5 K3 + 0x4C180000, // 0005 LDNIL R6 + 0x7C0C0600, // 0006 CALL R3 3 + 0x4C100000, // 0007 LDNIL R4 + 0x20100604, // 0008 NE R4 R3 R4 + 0x78120009, // 0009 JMPF R4 #0014 + 0xB8120800, // 000A GETNGBL R4 K4 + 0x8C100905, // 000B GETMET R4 R4 K5 + 0x5C180600, // 000C MOVE R6 R3 + 0x581C0006, // 000D LDCONST R7 K6 + 0x542200FE, // 000E LDINT R8 255 + 0x58240006, // 000F LDCONST R9 K6 + 0x542A00FD, // 0010 LDINT R10 254 + 0x7C100C00, // 0011 CALL R4 6 + 0x5C0C0800, // 0012 MOVE R3 R4 + 0x70020000, // 0013 JMP #0015 + 0x880C0107, // 0014 GETMBR R3 R0 K7 + 0x88100107, // 0015 GETMBR R4 R0 K7 + 0x20100604, // 0016 NE R4 R3 R4 + 0x78120005, // 0017 JMPF R4 #001E + 0x8C100108, // 0018 GETMET R4 R0 K8 + 0x4C180000, // 0019 LDNIL R6 + 0x541E0007, // 001A LDINT R7 8 + 0x58200006, // 001B LDCONST R8 K6 + 0x7C100800, // 001C CALL R4 4 + 0x90020E03, // 001D SETMBR R0 K7 R3 + 0x60100003, // 001E GETGBL R4 G3 + 0x5C140000, // 001F MOVE R5 R0 + 0x7C100200, // 0020 CALL R4 1 + 0x8C100909, // 0021 GETMET R4 R4 K9 + 0x7C100200, // 0022 CALL R4 1 + 0x80000000, // 0023 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_init, /* 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[ 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[ 9]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C0C0600, // 0006 CALL R3 3 + 0x90020302, // 0007 SETMBR R0 K1 K2 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_read_attribute, /* 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[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(create_TLV), + /* 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[77]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E0007, // 0005 LDINT R7 8 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E003B, // 0007 JMPF R7 #0044 + 0x1C1C0D05, // 0008 EQ R7 R6 K5 + 0x781E0005, // 0009 JMPF R7 #0010 + 0x8C1C0906, // 000A GETMET R7 R4 K6 + 0x88240907, // 000B GETMBR R9 R4 K7 + 0x88280108, // 000C GETMBR R10 R0 K8 + 0x7C1C0600, // 000D CALL R7 3 + 0x80040E00, // 000E RET 1 R7 + 0x70020032, // 000F JMP #0043 + 0x1C1C0D09, // 0010 EQ R7 R6 K9 + 0x781E0005, // 0011 JMPF R7 #0018 + 0x8C1C0906, // 0012 GETMET R7 R4 K6 + 0x88240907, // 0013 GETMBR R9 R4 K7 + 0x58280005, // 0014 LDCONST R10 K5 + 0x7C1C0600, // 0015 CALL R7 3 + 0x80040E00, // 0016 RET 1 R7 + 0x7002002A, // 0017 JMP #0043 + 0x1C1C0D0A, // 0018 EQ R7 R6 K10 + 0x781E0005, // 0019 JMPF R7 #0020 + 0x8C1C0906, // 001A GETMET R7 R4 K6 + 0x88240907, // 001B GETMBR R9 R4 K7 + 0x542A00FD, // 001C LDINT R10 254 + 0x7C1C0600, // 001D CALL R7 3 + 0x80040E00, // 001E RET 1 R7 + 0x70020022, // 001F JMP #0043 + 0x541E000E, // 0020 LDINT R7 15 + 0x1C1C0C07, // 0021 EQ R7 R6 R7 + 0x781E0005, // 0022 JMPF R7 #0029 + 0x8C1C0906, // 0023 GETMET R7 R4 K6 + 0x88240907, // 0024 GETMBR R9 R4 K7 + 0x58280005, // 0025 LDCONST R10 K5 + 0x7C1C0600, // 0026 CALL R7 3 + 0x80040E00, // 0027 RET 1 R7 + 0x70020019, // 0028 JMP #0043 + 0x541E0010, // 0029 LDINT R7 17 + 0x1C1C0C07, // 002A EQ R7 R6 R7 + 0x781E0005, // 002B JMPF R7 #0032 + 0x8C1C0906, // 002C GETMET R7 R4 K6 + 0x88240907, // 002D GETMBR R9 R4 K7 + 0x88280108, // 002E GETMBR R10 R0 K8 + 0x7C1C0600, // 002F CALL R7 3 + 0x80040E00, // 0030 RET 1 R7 + 0x70020010, // 0031 JMP #0043 + 0x541EFFFB, // 0032 LDINT R7 65532 + 0x1C1C0C07, // 0033 EQ R7 R6 R7 + 0x781E0005, // 0034 JMPF R7 #003B + 0x8C1C0906, // 0035 GETMET R7 R4 K6 + 0x8824090B, // 0036 GETMBR R9 R4 K11 + 0x5828000C, // 0037 LDCONST R10 K12 + 0x7C1C0600, // 0038 CALL R7 3 + 0x80040E00, // 0039 RET 1 R7 + 0x70020007, // 003A JMP #0043 + 0x541EFFFC, // 003B LDINT R7 65533 + 0x1C1C0C07, // 003C EQ R7 R6 R7 + 0x781E0004, // 003D JMPF R7 #0043 + 0x8C1C0906, // 003E GETMET R7 R4 K6 + 0x8824090B, // 003F GETMBR R9 R4 K11 + 0x542A0004, // 0040 LDINT R10 5 + 0x7C1C0600, // 0041 CALL R7 3 + 0x80040E00, // 0042 RET 1 R7 + 0x70020007, // 0043 JMP #004C + 0x601C0003, // 0044 GETGBL R7 G3 + 0x5C200000, // 0045 MOVE R8 R0 + 0x7C1C0200, // 0046 CALL R7 1 + 0x8C1C0F0D, // 0047 GETMET R7 R7 K13 + 0x5C240200, // 0048 MOVE R9 R1 + 0x5C280400, // 0049 MOVE R10 R2 + 0x7C1C0600, // 004A CALL R7 3 + 0x80040E00, // 004B RET 1 R7 + 0x80000000, // 004C 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(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_Light1_invoke_request_closure) }, + { be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_Light1_read_attribute_closure) }, + { be_const_key_weak(shadow_bri, -1), 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_shadow, 6), be_const_closure(Matter_Plugin_Light1_update_shadow_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light1_init_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(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_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_Light2.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light2.h new file mode 100644 index 000000000..d572d80e2 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light2.h @@ -0,0 +1,421 @@ +/* Solidification of Matter_Plugin_Light2.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Light2; + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_read_attribute, /* 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[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_nested_str_weak(create_TLV), + /* K6 */ be_nested_str_weak(U1), + /* K7 */ be_nested_str_weak(shadow_ct), + /* K8 */ be_const_int(2), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(ct_min), + /* K11 */ be_nested_str_weak(ct_max), + /* K12 */ be_nested_str_weak(U4), + /* K13 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[80]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E02FF, // 0005 LDINT R7 768 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E003E, // 0007 JMPF R7 #0047 + 0x541E0006, // 0008 LDINT R7 7 + 0x1C1C0C07, // 0009 EQ R7 R6 R7 + 0x781E0005, // 000A JMPF R7 #0011 + 0x8C1C0905, // 000B GETMET R7 R4 K5 + 0x88240906, // 000C GETMBR R9 R4 K6 + 0x88280107, // 000D GETMBR R10 R0 K7 + 0x7C1C0600, // 000E CALL R7 3 + 0x80040E00, // 000F RET 1 R7 + 0x70020034, // 0010 JMP #0046 + 0x541E0007, // 0011 LDINT R7 8 + 0x1C1C0C07, // 0012 EQ R7 R6 R7 + 0x781E0005, // 0013 JMPF R7 #001A + 0x8C1C0905, // 0014 GETMET R7 R4 K5 + 0x88240906, // 0015 GETMBR R9 R4 K6 + 0x58280008, // 0016 LDCONST R10 K8 + 0x7C1C0600, // 0017 CALL R7 3 + 0x80040E00, // 0018 RET 1 R7 + 0x7002002B, // 0019 JMP #0046 + 0x541E000E, // 001A LDINT R7 15 + 0x1C1C0C07, // 001B EQ R7 R6 R7 + 0x781E0005, // 001C JMPF R7 #0023 + 0x8C1C0905, // 001D GETMET R7 R4 K5 + 0x88240906, // 001E GETMBR R9 R4 K6 + 0x58280009, // 001F LDCONST R10 K9 + 0x7C1C0600, // 0020 CALL R7 3 + 0x80040E00, // 0021 RET 1 R7 + 0x70020022, // 0022 JMP #0046 + 0x541E400A, // 0023 LDINT R7 16395 + 0x1C1C0C07, // 0024 EQ R7 R6 R7 + 0x781E0005, // 0025 JMPF R7 #002C + 0x8C1C0905, // 0026 GETMET R7 R4 K5 + 0x88240906, // 0027 GETMBR R9 R4 K6 + 0x8828010A, // 0028 GETMBR R10 R0 K10 + 0x7C1C0600, // 0029 CALL R7 3 + 0x80040E00, // 002A RET 1 R7 + 0x70020019, // 002B JMP #0046 + 0x541E400B, // 002C LDINT R7 16396 + 0x1C1C0C07, // 002D EQ R7 R6 R7 + 0x781E0005, // 002E JMPF R7 #0035 + 0x8C1C0905, // 002F GETMET R7 R4 K5 + 0x88240906, // 0030 GETMBR R9 R4 K6 + 0x8828010B, // 0031 GETMBR R10 R0 K11 + 0x7C1C0600, // 0032 CALL R7 3 + 0x80040E00, // 0033 RET 1 R7 + 0x70020010, // 0034 JMP #0046 + 0x541EFFFB, // 0035 LDINT R7 65532 + 0x1C1C0C07, // 0036 EQ R7 R6 R7 + 0x781E0005, // 0037 JMPF R7 #003E + 0x8C1C0905, // 0038 GETMET R7 R4 K5 + 0x8824090C, // 0039 GETMBR R9 R4 K12 + 0x542A000F, // 003A LDINT R10 16 + 0x7C1C0600, // 003B CALL R7 3 + 0x80040E00, // 003C RET 1 R7 + 0x70020007, // 003D JMP #0046 + 0x541EFFFC, // 003E LDINT R7 65533 + 0x1C1C0C07, // 003F EQ R7 R6 R7 + 0x781E0004, // 0040 JMPF R7 #0046 + 0x8C1C0905, // 0041 GETMET R7 R4 K5 + 0x8824090C, // 0042 GETMBR R9 R4 K12 + 0x542A0004, // 0043 LDINT R10 5 + 0x7C1C0600, // 0044 CALL R7 3 + 0x80040E00, // 0045 RET 1 R7 + 0x70020007, // 0046 JMP #004F + 0x601C0003, // 0047 GETGBL R7 G3 + 0x5C200000, // 0048 MOVE R8 R0 + 0x7C1C0200, // 0049 CALL R7 1 + 0x8C1C0F0D, // 004A GETMET R7 R7 K13 + 0x5C240200, // 004B MOVE R9 R1 + 0x5C280400, // 004C MOVE R10 R2 + 0x7C1C0600, // 004D CALL R7 3 + 0x80040E00, // 004E RET 1 R7 + 0x80000000, // 004F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_init, /* 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[ 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[12]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C0C0600, // 0006 CALL R3 3 + 0x540E0144, // 0007 LDINT R3 325 + 0x90020203, // 0008 SETMBR R0 K1 R3 + 0x8C0C0102, // 0009 GETMET R3 R0 K2 + 0x7C0C0200, // 000A CALL R3 1 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_ct_minmax +********************************************************************/ +be_local_closure(Matter_Plugin_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 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[15]) { /* 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(findsubval), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(ct_min), + /* K8 */ be_nested_str_weak(ct_max), + /* K9 */ be_nested_str_weak(set), + /* K10 */ be_nested_str_weak(ct), + /* K11 */ be_nested_str_weak(update_shadow), + /* K12 */ be_nested_str_weak(log), + /* K13 */ be_nested_str_weak(ct_X3A), + /* K14 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[65]) { /* 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 + 0x7822002E, // 0007 JMPF R8 #0037 + 0x54220009, // 0008 LDINT R8 10 + 0x1C200E08, // 0009 EQ R8 R7 R8 + 0x78220019, // 000A JMPF R8 #0025 + 0x8C200505, // 000B GETMET R8 R2 K5 + 0x58280006, // 000C LDCONST R10 K6 + 0x7C200400, // 000D CALL R8 2 + 0x88240107, // 000E GETMBR R9 R0 K7 + 0x14241009, // 000F LT R9 R8 R9 + 0x78260000, // 0010 JMPF R9 #0012 + 0x88200107, // 0011 GETMBR R8 R0 K7 + 0x88240108, // 0012 GETMBR R9 R0 K8 + 0x24241009, // 0013 GT R9 R8 R9 + 0x78260000, // 0014 JMPF R9 #0016 + 0x88200108, // 0015 GETMBR R8 R0 K8 + 0x8C240909, // 0016 GETMET R9 R4 K9 + 0x602C0013, // 0017 GETGBL R11 G19 + 0x7C2C0000, // 0018 CALL R11 0 + 0x982E1408, // 0019 SETIDX R11 K10 R8 + 0x7C240400, // 001A CALL R9 2 + 0x8C24010B, // 001B GETMET R9 R0 K11 + 0x7C240200, // 001C CALL R9 1 + 0x60240008, // 001D GETGBL R9 G8 + 0x5C281000, // 001E MOVE R10 R8 + 0x7C240200, // 001F CALL R9 1 + 0x00261A09, // 0020 ADD R9 K13 R9 + 0x900E1809, // 0021 SETMBR R3 K12 R9 + 0x50240200, // 0022 LDBOOL R9 1 0 + 0x80041200, // 0023 RET 1 R9 + 0x70020010, // 0024 JMP #0036 + 0x54220046, // 0025 LDINT R8 71 + 0x1C200E08, // 0026 EQ R8 R7 R8 + 0x78220002, // 0027 JMPF R8 #002B + 0x50200200, // 0028 LDBOOL R8 1 0 + 0x80041000, // 0029 RET 1 R8 + 0x7002000A, // 002A JMP #0036 + 0x5422004A, // 002B LDINT R8 75 + 0x1C200E08, // 002C EQ R8 R7 R8 + 0x78220002, // 002D JMPF R8 #0031 + 0x50200200, // 002E LDBOOL R8 1 0 + 0x80041000, // 002F RET 1 R8 + 0x70020004, // 0030 JMP #0036 + 0x5422004B, // 0031 LDINT R8 76 + 0x1C200E08, // 0032 EQ R8 R7 R8 + 0x78220001, // 0033 JMPF R8 #0036 + 0x50200200, // 0034 LDBOOL R8 1 0 + 0x80041000, // 0035 RET 1 R8 + 0x70020008, // 0036 JMP #0040 + 0x60200003, // 0037 GETGBL R8 G3 + 0x5C240000, // 0038 MOVE R9 R0 + 0x7C200200, // 0039 CALL R8 1 + 0x8C20110E, // 003A GETMET R8 R8 K14 + 0x5C280200, // 003B MOVE R10 R1 + 0x5C2C0400, // 003C MOVE R11 R2 + 0x5C300600, // 003D MOVE R12 R3 + 0x7C200800, // 003E CALL R8 4 + 0x80041000, // 003F RET 1 R8 + 0x80000000, // 0040 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_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[ 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[28]) { /* 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 + 0x8C0C0504, // 000A GETMET R3 R2 K4 + 0x58140005, // 000B LDCONST R5 K5 + 0x4C180000, // 000C LDNIL R6 + 0x7C0C0600, // 000D CALL R3 3 + 0x4C100000, // 000E LDNIL R4 + 0x1C100604, // 000F EQ R4 R3 R4 + 0x78120000, // 0010 JMPF R4 #0012 + 0x880C0106, // 0011 GETMBR R3 R0 K6 + 0x88100106, // 0012 GETMBR R4 R0 K6 + 0x20100604, // 0013 NE R4 R3 R4 + 0x78120005, // 0014 JMPF R4 #001B + 0x8C100107, // 0015 GETMET R4 R0 K7 + 0x4C180000, // 0016 LDNIL R6 + 0x541E02FF, // 0017 LDINT R7 768 + 0x54220006, // 0018 LDINT R8 7 + 0x7C100800, // 0019 CALL R4 4 + 0x90020C03, // 001A SETMBR R0 K6 R3 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Light2 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light1; +be_local_class(Matter_Plugin_Light2, + 3, + &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(268, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(shadow_ct, -1), be_const_var(0) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light2_read_attribute_closure) }, + { be_const_key_weak(ct_min, 8), be_const_var(1) }, + { 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(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(7), + be_const_int(8), + be_const_int(15), + be_const_int(16395), + be_const_int(16396), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light2_init_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light2_invoke_request_closure) }, + { be_const_key_weak(update_ct_minmax, 6), be_const_closure(Matter_Plugin_Light2_update_ct_minmax_closure) }, + { be_const_key_weak(ct_max, -1), be_const_var(2) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Light2_update_shadow_closure) }, + })), + be_str_weak(Matter_Plugin_Light2) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Light2_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Light2); + be_setglobal(vm, "Matter_Plugin_Light2"); + 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 new file mode 100644 index 000000000..2c86c864a --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light3.h @@ -0,0 +1,530 @@ +/* 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: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_init, /* 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(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[10]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C0C0600, // 0006 CALL R3 3 + 0x90020302, // 0007 SETMBR R0 K1 K2 + 0x90020702, // 0008 SETMBR R0 K3 K2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_read_attribute, /* 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_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(create_TLV), + /* 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[105]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E02FF, // 0005 LDINT R7 768 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E0057, // 0007 JMPF R7 #0060 + 0x1C1C0D05, // 0008 EQ R7 R6 K5 + 0x781E0005, // 0009 JMPF R7 #0010 + 0x8C1C0906, // 000A GETMET R7 R4 K6 + 0x88240907, // 000B GETMBR R9 R4 K7 + 0x88280108, // 000C GETMBR R10 R0 K8 + 0x7C1C0600, // 000D CALL R7 3 + 0x80040E00, // 000E RET 1 R7 + 0x7002004E, // 000F JMP #005F + 0x1C1C0D09, // 0010 EQ R7 R6 K9 + 0x781E0005, // 0011 JMPF R7 #0018 + 0x8C1C0906, // 0012 GETMET R7 R4 K6 + 0x88240907, // 0013 GETMBR R9 R4 K7 + 0x8828010A, // 0014 GETMBR R10 R0 K10 + 0x7C1C0600, // 0015 CALL R7 3 + 0x80040E00, // 0016 RET 1 R7 + 0x70020046, // 0017 JMP #005F + 0x541E0006, // 0018 LDINT R7 7 + 0x1C1C0C07, // 0019 EQ R7 R6 R7 + 0x781E0005, // 001A JMPF R7 #0021 + 0x8C1C0906, // 001B GETMET R7 R4 K6 + 0x88240907, // 001C GETMBR R9 R4 K7 + 0x58280005, // 001D LDCONST R10 K5 + 0x7C1C0600, // 001E CALL R7 3 + 0x80040E00, // 001F RET 1 R7 + 0x7002003D, // 0020 JMP #005F + 0x541E0007, // 0021 LDINT R7 8 + 0x1C1C0C07, // 0022 EQ R7 R6 R7 + 0x781E0005, // 0023 JMPF R7 #002A + 0x8C1C0906, // 0024 GETMET R7 R4 K6 + 0x88240907, // 0025 GETMBR R9 R4 K7 + 0x58280005, // 0026 LDCONST R10 K5 + 0x7C1C0600, // 0027 CALL R7 3 + 0x80040E00, // 0028 RET 1 R7 + 0x70020034, // 0029 JMP #005F + 0x541E000E, // 002A LDINT R7 15 + 0x1C1C0C07, // 002B EQ R7 R6 R7 + 0x781E0005, // 002C JMPF R7 #0033 + 0x8C1C0906, // 002D GETMET R7 R4 K6 + 0x88240907, // 002E GETMBR R9 R4 K7 + 0x58280005, // 002F LDCONST R10 K5 + 0x7C1C0600, // 0030 CALL R7 3 + 0x80040E00, // 0031 RET 1 R7 + 0x7002002B, // 0032 JMP #005F + 0x541E4000, // 0033 LDINT R7 16385 + 0x1C1C0C07, // 0034 EQ R7 R6 R7 + 0x781E0005, // 0035 JMPF R7 #003C + 0x8C1C0906, // 0036 GETMET R7 R4 K6 + 0x88240907, // 0037 GETMBR R9 R4 K7 + 0x58280005, // 0038 LDCONST R10 K5 + 0x7C1C0600, // 0039 CALL R7 3 + 0x80040E00, // 003A RET 1 R7 + 0x70020022, // 003B JMP #005F + 0x541E4009, // 003C LDINT R7 16394 + 0x1C1C0C07, // 003D EQ R7 R6 R7 + 0x781E0005, // 003E JMPF R7 #0045 + 0x8C1C0906, // 003F GETMET R7 R4 K6 + 0x88240907, // 0040 GETMBR R9 R4 K7 + 0x58280005, // 0041 LDCONST R10 K5 + 0x7C1C0600, // 0042 CALL R7 3 + 0x80040E00, // 0043 RET 1 R7 + 0x70020019, // 0044 JMP #005F + 0x541E000F, // 0045 LDINT R7 16 + 0x1C1C0C07, // 0046 EQ R7 R6 R7 + 0x781E0005, // 0047 JMPF R7 #004E + 0x8C1C0906, // 0048 GETMET R7 R4 K6 + 0x88240907, // 0049 GETMBR R9 R4 K7 + 0x58280005, // 004A LDCONST R10 K5 + 0x7C1C0600, // 004B CALL R7 3 + 0x80040E00, // 004C RET 1 R7 + 0x70020010, // 004D JMP #005F + 0x541EFFFB, // 004E LDINT R7 65532 + 0x1C1C0C07, // 004F EQ R7 R6 R7 + 0x781E0005, // 0050 JMPF R7 #0057 + 0x8C1C0906, // 0051 GETMET R7 R4 K6 + 0x8824090B, // 0052 GETMBR R9 R4 K11 + 0x58280009, // 0053 LDCONST R10 K9 + 0x7C1C0600, // 0054 CALL R7 3 + 0x80040E00, // 0055 RET 1 R7 + 0x70020007, // 0056 JMP #005F + 0x541EFFFC, // 0057 LDINT R7 65533 + 0x1C1C0C07, // 0058 EQ R7 R6 R7 + 0x781E0004, // 0059 JMPF R7 #005F + 0x8C1C0906, // 005A GETMET R7 R4 K6 + 0x8824090B, // 005B GETMBR R9 R4 K11 + 0x542A0004, // 005C LDINT R10 5 + 0x7C1C0600, // 005D CALL R7 3 + 0x80040E00, // 005E RET 1 R7 + 0x70020007, // 005F JMP #0068 + 0x601C0003, // 0060 GETGBL R7 G3 + 0x5C200000, // 0061 MOVE R8 R0 + 0x7C1C0200, // 0062 CALL R7 1 + 0x8C1C0F0C, // 0063 GETMET R7 R7 K12 + 0x5C240200, // 0064 MOVE R9 R1 + 0x5C280400, // 0065 MOVE R10 R2 + 0x7C1C0600, // 0066 CALL R7 3 + 0x80040E00, // 0067 RET 1 R7 + 0x80000000, // 0068 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[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_const_int(0), + /* K6 */ be_nested_str_weak(findsubval), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(scale_uint), + /* K9 */ be_nested_str_weak(set), + /* K10 */ be_nested_str_weak(hue), + /* K11 */ be_nested_str_weak(update_shadow), + /* K12 */ be_nested_str_weak(log), + /* K13 */ be_nested_str_weak(hue_X3A), + /* K14 */ be_const_int(1), + /* K15 */ be_const_int(2), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(sat), + /* K18 */ be_nested_str_weak(sat_X3A), + /* K19 */ be_nested_str_weak(_X20sat_X3A), + /* K20 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[148]) { /* 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 + 0x78220081, // 0007 JMPF R8 #008A + 0x1C200F05, // 0008 EQ R8 R7 K5 + 0x78220019, // 0009 JMPF R8 #0024 + 0x8C200506, // 000A GETMET R8 R2 K6 + 0x58280005, // 000B LDCONST R10 K5 + 0x7C200400, // 000C CALL R8 2 + 0xB8260E00, // 000D GETNGBL R9 K7 + 0x8C241308, // 000E GETMET R9 R9 K8 + 0x5C2C1000, // 000F MOVE R11 R8 + 0x58300005, // 0010 LDCONST R12 K5 + 0x543600FD, // 0011 LDINT R13 254 + 0x58380005, // 0012 LDCONST R14 K5 + 0x543E0167, // 0013 LDINT R15 360 + 0x7C240C00, // 0014 CALL R9 6 + 0x8C280909, // 0015 GETMET R10 R4 K9 + 0x60300013, // 0016 GETGBL R12 G19 + 0x7C300000, // 0017 CALL R12 0 + 0x98321409, // 0018 SETIDX R12 K10 R9 + 0x7C280400, // 0019 CALL R10 2 + 0x8C28010B, // 001A GETMET R10 R0 K11 + 0x7C280200, // 001B CALL R10 1 + 0x60280008, // 001C GETGBL R10 G8 + 0x5C2C1000, // 001D MOVE R11 R8 + 0x7C280200, // 001E CALL R10 1 + 0x002A1A0A, // 001F ADD R10 K13 R10 + 0x900E180A, // 0020 SETMBR R3 K12 R10 + 0x50280200, // 0021 LDBOOL R10 1 0 + 0x80041400, // 0022 RET 1 R10 + 0x70020064, // 0023 JMP #0089 + 0x1C200F0E, // 0024 EQ R8 R7 K14 + 0x78220002, // 0025 JMPF R8 #0029 + 0x50200200, // 0026 LDBOOL R8 1 0 + 0x80041000, // 0027 RET 1 R8 + 0x7002005F, // 0028 JMP #0089 + 0x1C200F0F, // 0029 EQ R8 R7 K15 + 0x78220002, // 002A JMPF R8 #002E + 0x50200200, // 002B LDBOOL R8 1 0 + 0x80041000, // 002C RET 1 R8 + 0x7002005A, // 002D JMP #0089 + 0x1C200F10, // 002E EQ R8 R7 K16 + 0x78220019, // 002F JMPF R8 #004A + 0x8C200506, // 0030 GETMET R8 R2 K6 + 0x58280005, // 0031 LDCONST R10 K5 + 0x7C200400, // 0032 CALL R8 2 + 0xB8260E00, // 0033 GETNGBL R9 K7 + 0x8C241308, // 0034 GETMET R9 R9 K8 + 0x5C2C1000, // 0035 MOVE R11 R8 + 0x58300005, // 0036 LDCONST R12 K5 + 0x543600FD, // 0037 LDINT R13 254 + 0x58380005, // 0038 LDCONST R14 K5 + 0x543E00FE, // 0039 LDINT R15 255 + 0x7C240C00, // 003A CALL R9 6 + 0x8C280909, // 003B GETMET R10 R4 K9 + 0x60300013, // 003C GETGBL R12 G19 + 0x7C300000, // 003D CALL R12 0 + 0x98322209, // 003E SETIDX R12 K17 R9 + 0x7C280400, // 003F CALL R10 2 + 0x8C28010B, // 0040 GETMET R10 R0 K11 + 0x7C280200, // 0041 CALL R10 1 + 0x60280008, // 0042 GETGBL R10 G8 + 0x5C2C1000, // 0043 MOVE R11 R8 + 0x7C280200, // 0044 CALL R10 1 + 0x002A240A, // 0045 ADD R10 K18 R10 + 0x900E180A, // 0046 SETMBR R3 K12 R10 + 0x50280200, // 0047 LDBOOL R10 1 0 + 0x80041400, // 0048 RET 1 R10 + 0x7002003E, // 0049 JMP #0089 + 0x54220003, // 004A LDINT R8 4 + 0x1C200E08, // 004B EQ R8 R7 R8 + 0x78220002, // 004C JMPF R8 #0050 + 0x50200200, // 004D LDBOOL R8 1 0 + 0x80041000, // 004E RET 1 R8 + 0x70020038, // 004F JMP #0089 + 0x54220004, // 0050 LDINT R8 5 + 0x1C200E08, // 0051 EQ R8 R7 R8 + 0x78220002, // 0052 JMPF R8 #0056 + 0x50200200, // 0053 LDBOOL R8 1 0 + 0x80041000, // 0054 RET 1 R8 + 0x70020032, // 0055 JMP #0089 + 0x54220005, // 0056 LDINT R8 6 + 0x1C200E08, // 0057 EQ R8 R7 R8 + 0x7822002A, // 0058 JMPF R8 #0084 + 0x8C200506, // 0059 GETMET R8 R2 K6 + 0x58280005, // 005A LDCONST R10 K5 + 0x7C200400, // 005B CALL R8 2 + 0xB8260E00, // 005C GETNGBL R9 K7 + 0x8C241308, // 005D GETMET R9 R9 K8 + 0x5C2C1000, // 005E MOVE R11 R8 + 0x58300005, // 005F LDCONST R12 K5 + 0x543600FD, // 0060 LDINT R13 254 + 0x58380005, // 0061 LDCONST R14 K5 + 0x543E0167, // 0062 LDINT R15 360 + 0x7C240C00, // 0063 CALL R9 6 + 0x8C280506, // 0064 GETMET R10 R2 K6 + 0x5830000E, // 0065 LDCONST R12 K14 + 0x7C280400, // 0066 CALL R10 2 + 0xB82E0E00, // 0067 GETNGBL R11 K7 + 0x8C2C1708, // 0068 GETMET R11 R11 K8 + 0x5C341400, // 0069 MOVE R13 R10 + 0x58380005, // 006A LDCONST R14 K5 + 0x543E00FD, // 006B LDINT R15 254 + 0x58400005, // 006C LDCONST R16 K5 + 0x544600FE, // 006D LDINT R17 255 + 0x7C2C0C00, // 006E CALL R11 6 + 0x8C300909, // 006F GETMET R12 R4 K9 + 0x60380013, // 0070 GETGBL R14 G19 + 0x7C380000, // 0071 CALL R14 0 + 0x983A1409, // 0072 SETIDX R14 K10 R9 + 0x983A220B, // 0073 SETIDX R14 K17 R11 + 0x7C300400, // 0074 CALL R12 2 + 0x8C30010B, // 0075 GETMET R12 R0 K11 + 0x7C300200, // 0076 CALL R12 1 + 0x60300008, // 0077 GETGBL R12 G8 + 0x5C341000, // 0078 MOVE R13 R8 + 0x7C300200, // 0079 CALL R12 1 + 0x00321A0C, // 007A ADD R12 K13 R12 + 0x00301913, // 007B ADD R12 R12 K19 + 0x60340008, // 007C GETGBL R13 G8 + 0x5C381400, // 007D MOVE R14 R10 + 0x7C340200, // 007E CALL R13 1 + 0x0030180D, // 007F ADD R12 R12 R13 + 0x900E180C, // 0080 SETMBR R3 K12 R12 + 0x50300200, // 0081 LDBOOL R12 1 0 + 0x80041800, // 0082 RET 1 R12 + 0x70020004, // 0083 JMP #0089 + 0x54220046, // 0084 LDINT R8 71 + 0x1C200E08, // 0085 EQ R8 R7 R8 + 0x78220001, // 0086 JMPF R8 #0089 + 0x50200200, // 0087 LDBOOL R8 1 0 + 0x80041000, // 0088 RET 1 R8 + 0x70020008, // 0089 JMP #0093 + 0x60200003, // 008A GETGBL R8 G3 + 0x5C240000, // 008B MOVE R9 R0 + 0x7C200200, // 008C CALL R8 1 + 0x8C201114, // 008D GETMET R8 R8 K20 + 0x5C280200, // 008E MOVE R10 R1 + 0x5C2C0400, // 008F MOVE R11 R2 + 0x5C300600, // 0090 MOVE R12 R3 + 0x7C200800, // 0091 CALL R8 4 + 0x80041000, // 0092 RET 1 R8 + 0x80000000, // 0093 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[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[63]) { /* 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 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140004, // 0009 LDCONST R5 K4 + 0x4C180000, // 000A LDNIL R6 + 0x7C0C0600, // 000B CALL R3 3 + 0x8C100503, // 000C GETMET R4 R2 K3 + 0x58180005, // 000D LDCONST R6 K5 + 0x4C1C0000, // 000E LDNIL R7 + 0x7C100600, // 000F CALL R4 3 + 0x4C140000, // 0010 LDNIL R5 + 0x20140605, // 0011 NE R5 R3 R5 + 0x78160009, // 0012 JMPF R5 #001D + 0xB8160C00, // 0013 GETNGBL R5 K6 + 0x8C140B07, // 0014 GETMET R5 R5 K7 + 0x5C1C0600, // 0015 MOVE R7 R3 + 0x58200008, // 0016 LDCONST R8 K8 + 0x54260167, // 0017 LDINT R9 360 + 0x58280008, // 0018 LDCONST R10 K8 + 0x542E00FD, // 0019 LDINT R11 254 + 0x7C140C00, // 001A CALL R5 6 + 0x5C0C0A00, // 001B MOVE R3 R5 + 0x70020000, // 001C JMP #001E + 0x880C0109, // 001D GETMBR R3 R0 K9 + 0x4C140000, // 001E LDNIL R5 + 0x20140805, // 001F NE R5 R4 R5 + 0x78160009, // 0020 JMPF R5 #002B + 0xB8160C00, // 0021 GETNGBL R5 K6 + 0x8C140B07, // 0022 GETMET R5 R5 K7 + 0x5C1C0800, // 0023 MOVE R7 R4 + 0x58200008, // 0024 LDCONST R8 K8 + 0x542600FE, // 0025 LDINT R9 255 + 0x58280008, // 0026 LDCONST R10 K8 + 0x542E00FD, // 0027 LDINT R11 254 + 0x7C140C00, // 0028 CALL R5 6 + 0x5C100A00, // 0029 MOVE R4 R5 + 0x70020000, // 002A JMP #002C + 0x8810010A, // 002B GETMBR R4 R0 K10 + 0x88140109, // 002C GETMBR R5 R0 K9 + 0x20140605, // 002D NE R5 R3 R5 + 0x78160005, // 002E JMPF R5 #0035 + 0x8C14010B, // 002F GETMET R5 R0 K11 + 0x4C1C0000, // 0030 LDNIL R7 + 0x542202FF, // 0031 LDINT R8 768 + 0x58240008, // 0032 LDCONST R9 K8 + 0x7C140800, // 0033 CALL R5 4 + 0x90021203, // 0034 SETMBR R0 K9 R3 + 0x8814010A, // 0035 GETMBR R5 R0 K10 + 0x20140805, // 0036 NE R5 R4 R5 + 0x78160005, // 0037 JMPF R5 #003E + 0x8C14010B, // 0038 GETMET R5 R0 K11 + 0x4C1C0000, // 0039 LDNIL R7 + 0x542202FF, // 003A LDINT R8 768 + 0x5824000C, // 003B LDCONST R9 K12 + 0x7C140800, // 003C CALL R5 4 + 0x90021404, // 003D SETMBR R0 K10 R4 + 0x80000000, // 003E 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(8, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(CLUSTERS, 7), 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(invoke_request, -1), be_const_closure(Matter_Plugin_Light3_invoke_request_closure) }, + { be_const_key_weak(TYPES, 0), 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(init, 1), be_const_closure(Matter_Plugin_Light3_init_closure) }, + { be_const_key_weak(shadow_hue, -1), be_const_var(0) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Light3_update_shadow_closure) }, + { be_const_key_weak(shadow_sat, -1), be_const_var(1) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light3_read_attribute_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_Plugin_OnOff.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_OnOff.h new file mode 100644 index 000000000..f0ecd333d --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_OnOff.h @@ -0,0 +1,648 @@ +/* Solidification of Matter_Plugin_OnOff.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_OnOff; + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_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[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(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(set_onoff), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(get_onoff), + }), + 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 + 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 + 0x70020058, // 001C JMP #0076 + 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 + 0x70020052, // 0022 JMP #0076 + 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 + 0x7002004C, // 0028 JMP #0076 + 0x541E0005, // 0029 LDINT R7 6 + 0x1C1C0A07, // 002A EQ R7 R5 R7 + 0x781E001B, // 002B JMPF R7 #0048 + 0x1C1C0D05, // 002C EQ R7 R6 K5 + 0x781E0005, // 002D JMPF R7 #0034 + 0x8C1C010A, // 002E GETMET R7 R0 K10 + 0x50240000, // 002F LDBOOL R9 0 0 + 0x7C1C0400, // 0030 CALL R7 2 + 0x501C0200, // 0031 LDBOOL R7 1 0 + 0x80040E00, // 0032 RET 1 R7 + 0x70020012, // 0033 JMP #0047 + 0x1C1C0D06, // 0034 EQ R7 R6 K6 + 0x781E0005, // 0035 JMPF R7 #003C + 0x8C1C010A, // 0036 GETMET R7 R0 K10 + 0x50240200, // 0037 LDBOOL R9 1 0 + 0x7C1C0400, // 0038 CALL R7 2 + 0x501C0200, // 0039 LDBOOL R7 1 0 + 0x80040E00, // 003A RET 1 R7 + 0x7002000A, // 003B JMP #0047 + 0x1C1C0D0B, // 003C EQ R7 R6 K11 + 0x781E0008, // 003D JMPF R7 #0047 + 0x8C1C010A, // 003E GETMET R7 R0 K10 + 0x8C24010C, // 003F GETMET R9 R0 K12 + 0x7C240200, // 0040 CALL R9 1 + 0x78260000, // 0041 JMPF R9 #0043 + 0x50240001, // 0042 LDBOOL R9 0 1 + 0x50240200, // 0043 LDBOOL R9 1 0 + 0x7C1C0400, // 0044 CALL R7 2 + 0x501C0200, // 0045 LDBOOL R7 1 0 + 0x80040E00, // 0046 RET 1 R7 + 0x7002002D, // 0047 JMP #0076 + 0x541E0007, // 0048 LDINT R7 8 + 0x1C1C0A07, // 0049 EQ R7 R5 R7 + 0x781E002A, // 004A JMPF R7 #0076 + 0x1C1C0D05, // 004B EQ R7 R6 K5 + 0x781E0002, // 004C JMPF R7 #0050 + 0x501C0200, // 004D LDBOOL R7 1 0 + 0x80040E00, // 004E RET 1 R7 + 0x70020025, // 004F JMP #0076 + 0x1C1C0D06, // 0050 EQ R7 R6 K6 + 0x781E0002, // 0051 JMPF R7 #0055 + 0x501C0200, // 0052 LDBOOL R7 1 0 + 0x80040E00, // 0053 RET 1 R7 + 0x70020020, // 0054 JMP #0076 + 0x1C1C0D0B, // 0055 EQ R7 R6 K11 + 0x781E0002, // 0056 JMPF R7 #005A + 0x501C0200, // 0057 LDBOOL R7 1 0 + 0x80040E00, // 0058 RET 1 R7 + 0x7002001B, // 0059 JMP #0076 + 0x1C1C0D04, // 005A EQ R7 R6 K4 + 0x781E0002, // 005B JMPF R7 #005F + 0x501C0200, // 005C LDBOOL R7 1 0 + 0x80040E00, // 005D RET 1 R7 + 0x70020016, // 005E JMP #0076 + 0x541E0003, // 005F LDINT R7 4 + 0x1C1C0C07, // 0060 EQ R7 R6 R7 + 0x781E0002, // 0061 JMPF R7 #0065 + 0x501C0200, // 0062 LDBOOL R7 1 0 + 0x80040E00, // 0063 RET 1 R7 + 0x70020010, // 0064 JMP #0076 + 0x541E0004, // 0065 LDINT R7 5 + 0x1C1C0C07, // 0066 EQ R7 R6 R7 + 0x781E0002, // 0067 JMPF R7 #006B + 0x501C0200, // 0068 LDBOOL R7 1 0 + 0x80040E00, // 0069 RET 1 R7 + 0x7002000A, // 006A JMP #0076 + 0x541E0005, // 006B LDINT R7 6 + 0x1C1C0C07, // 006C EQ R7 R6 R7 + 0x781E0002, // 006D JMPF R7 #0071 + 0x501C0200, // 006E LDBOOL R7 1 0 + 0x80040E00, // 006F RET 1 R7 + 0x70020004, // 0070 JMP #0076 + 0x541E0006, // 0071 LDINT R7 7 + 0x1C1C0C07, // 0072 EQ R7 R6 R7 + 0x781E0001, // 0073 JMPF R7 #0076 + 0x501C0200, // 0074 LDBOOL R7 1 0 + 0x80040E00, // 0075 RET 1 R7 + 0x80000000, // 0076 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_onoff +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_get_onoff, /* 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(tasmota), + /* K1 */ be_nested_str_weak(get_power), + /* K2 */ be_nested_str_weak(tasmota_relay_index), + /* K3 */ be_nested_str_weak(shadow_onoff), + /* K4 */ be_nested_str_weak(onoff_changed), + }), + be_str_weak(get_onoff), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x4C080000, // 0004 LDNIL R2 + 0x20080202, // 0005 NE R2 R1 R2 + 0x780A000C, // 0006 JMPF R2 #0014 + 0x88080103, // 0007 GETMBR R2 R0 K3 + 0x4C0C0000, // 0008 LDNIL R3 + 0x20080403, // 0009 NE R2 R2 R3 + 0x780A0007, // 000A JMPF R2 #0013 + 0x88080103, // 000B GETMBR R2 R0 K3 + 0x600C0017, // 000C GETGBL R3 G23 + 0x5C100200, // 000D MOVE R4 R1 + 0x7C0C0200, // 000E CALL R3 1 + 0x20080403, // 000F NE R2 R2 R3 + 0x780A0001, // 0010 JMPF R2 #0013 + 0x8C080104, // 0011 GETMET R2 R0 K4 + 0x7C080200, // 0012 CALL R2 1 + 0x90020601, // 0013 SETMBR R0 K3 R1 + 0x88080103, // 0014 GETMBR R2 R0 K3 + 0x4C0C0000, // 0015 LDNIL R3 + 0x1C080403, // 0016 EQ R2 R2 R3 + 0x780A0001, // 0017 JMPF R2 #001A + 0x50080000, // 0018 LDBOOL R2 0 0 + 0x90020602, // 0019 SETMBR R0 K3 R2 + 0x88080103, // 001A GETMBR R2 R0 K3 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: onoff_changed +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_onoff_changed, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(onoff_changed), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x54120005, // 0002 LDINT R4 6 + 0x58140001, // 0003 LDCONST R5 K1 + 0x7C040800, // 0004 CALL R1 4 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** 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[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_power), + /* K2 */ be_nested_str_weak(tasmota_relay_index), + /* K3 */ be_nested_str_weak(get_onoff), + }), + be_str_weak(set_onoff), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x88100102, // 0002 GETMBR R4 R0 K2 + 0x60140017, // 0003 GETGBL R5 G23 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C140200, // 0005 CALL R5 1 + 0x7C080600, // 0006 CALL R2 3 + 0x8C080103, // 0007 GETMET R2 R0 K3 + 0x7C080200, // 0008 CALL R2 1 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_read_attribute, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(3), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(create_TLV), + /* K8 */ be_nested_str_weak(U2), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(U1), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_nested_str_weak(BOOL), + /* K13 */ be_nested_str_weak(get_onoff), + /* K14 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[174]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x1C1C0B05, // 0005 EQ R7 R5 K5 + 0x781E0021, // 0006 JMPF R7 #0029 + 0x1C1C0D06, // 0007 EQ R7 R6 K6 + 0x781E0005, // 0008 JMPF R7 #000F + 0x8C1C0907, // 0009 GETMET R7 R4 K7 + 0x88240908, // 000A GETMBR R9 R4 K8 + 0x58280006, // 000B LDCONST R10 K6 + 0x7C1C0600, // 000C CALL R7 3 + 0x80040E00, // 000D RET 1 R7 + 0x70020018, // 000E JMP #0028 + 0x1C1C0D09, // 000F EQ R7 R6 K9 + 0x781E0005, // 0010 JMPF R7 #0017 + 0x8C1C0907, // 0011 GETMET R7 R4 K7 + 0x8824090A, // 0012 GETMBR R9 R4 K10 + 0x58280006, // 0013 LDCONST R10 K6 + 0x7C1C0600, // 0014 CALL R7 3 + 0x80040E00, // 0015 RET 1 R7 + 0x70020010, // 0016 JMP #0028 + 0x541EFFFB, // 0017 LDINT R7 65532 + 0x1C1C0C07, // 0018 EQ R7 R6 R7 + 0x781E0005, // 0019 JMPF R7 #0020 + 0x8C1C0907, // 001A GETMET R7 R4 K7 + 0x8824090B, // 001B GETMBR R9 R4 K11 + 0x58280006, // 001C LDCONST R10 K6 + 0x7C1C0600, // 001D CALL R7 3 + 0x80040E00, // 001E RET 1 R7 + 0x70020007, // 001F JMP #0028 + 0x541EFFFC, // 0020 LDINT R7 65533 + 0x1C1C0C07, // 0021 EQ R7 R6 R7 + 0x781E0004, // 0022 JMPF R7 #0028 + 0x8C1C0907, // 0023 GETMET R7 R4 K7 + 0x8824090B, // 0024 GETMBR R9 R4 K11 + 0x542A0003, // 0025 LDINT R10 4 + 0x7C1C0600, // 0026 CALL R7 3 + 0x80040E00, // 0027 RET 1 R7 + 0x70020083, // 0028 JMP #00AD + 0x541E0003, // 0029 LDINT R7 4 + 0x1C1C0A07, // 002A EQ R7 R5 R7 + 0x781E0016, // 002B JMPF R7 #0043 + 0x1C1C0D06, // 002C EQ R7 R6 K6 + 0x781E0002, // 002D JMPF R7 #0031 + 0x4C1C0000, // 002E LDNIL R7 + 0x80040E00, // 002F RET 1 R7 + 0x70020010, // 0030 JMP #0042 + 0x541EFFFB, // 0031 LDINT R7 65532 + 0x1C1C0C07, // 0032 EQ R7 R6 R7 + 0x781E0005, // 0033 JMPF R7 #003A + 0x8C1C0907, // 0034 GETMET R7 R4 K7 + 0x8824090B, // 0035 GETMBR R9 R4 K11 + 0x58280006, // 0036 LDCONST R10 K6 + 0x7C1C0600, // 0037 CALL R7 3 + 0x80040E00, // 0038 RET 1 R7 + 0x70020007, // 0039 JMP #0042 + 0x541EFFFC, // 003A LDINT R7 65533 + 0x1C1C0C07, // 003B EQ R7 R6 R7 + 0x781E0004, // 003C JMPF R7 #0042 + 0x8C1C0907, // 003D GETMET R7 R4 K7 + 0x8824090B, // 003E GETMBR R9 R4 K11 + 0x542A0003, // 003F LDINT R10 4 + 0x7C1C0600, // 0040 CALL R7 3 + 0x80040E00, // 0041 RET 1 R7 + 0x70020069, // 0042 JMP #00AD + 0x541E0004, // 0043 LDINT R7 5 + 0x1C1C0A07, // 0044 EQ R7 R5 R7 + 0x781E0011, // 0045 JMPF R7 #0058 + 0x541EFFFB, // 0046 LDINT R7 65532 + 0x1C1C0C07, // 0047 EQ R7 R6 R7 + 0x781E0005, // 0048 JMPF R7 #004F + 0x8C1C0907, // 0049 GETMET R7 R4 K7 + 0x8824090B, // 004A GETMBR R9 R4 K11 + 0x58280006, // 004B LDCONST R10 K6 + 0x7C1C0600, // 004C CALL R7 3 + 0x80040E00, // 004D RET 1 R7 + 0x70020007, // 004E JMP #0057 + 0x541EFFFC, // 004F LDINT R7 65533 + 0x1C1C0C07, // 0050 EQ R7 R6 R7 + 0x781E0004, // 0051 JMPF R7 #0057 + 0x8C1C0907, // 0052 GETMET R7 R4 K7 + 0x8824090B, // 0053 GETMBR R9 R4 K11 + 0x542A0003, // 0054 LDINT R10 4 + 0x7C1C0600, // 0055 CALL R7 3 + 0x80040E00, // 0056 RET 1 R7 + 0x70020054, // 0057 JMP #00AD + 0x541E0005, // 0058 LDINT R7 6 + 0x1C1C0A07, // 0059 EQ R7 R5 R7 + 0x781E001A, // 005A JMPF R7 #0076 + 0x1C1C0D06, // 005B EQ R7 R6 K6 + 0x781E0006, // 005C JMPF R7 #0064 + 0x8C1C0907, // 005D GETMET R7 R4 K7 + 0x8824090C, // 005E GETMBR R9 R4 K12 + 0x8C28010D, // 005F GETMET R10 R0 K13 + 0x7C280200, // 0060 CALL R10 1 + 0x7C1C0600, // 0061 CALL R7 3 + 0x80040E00, // 0062 RET 1 R7 + 0x70020010, // 0063 JMP #0075 + 0x541EFFFB, // 0064 LDINT R7 65532 + 0x1C1C0C07, // 0065 EQ R7 R6 R7 + 0x781E0005, // 0066 JMPF R7 #006D + 0x8C1C0907, // 0067 GETMET R7 R4 K7 + 0x8824090B, // 0068 GETMBR R9 R4 K11 + 0x58280006, // 0069 LDCONST R10 K6 + 0x7C1C0600, // 006A CALL R7 3 + 0x80040E00, // 006B RET 1 R7 + 0x70020007, // 006C JMP #0075 + 0x541EFFFC, // 006D LDINT R7 65533 + 0x1C1C0C07, // 006E EQ R7 R6 R7 + 0x781E0004, // 006F JMPF R7 #0075 + 0x8C1C0907, // 0070 GETMET R7 R4 K7 + 0x8824090B, // 0071 GETMBR R9 R4 K11 + 0x542A0003, // 0072 LDINT R10 4 + 0x7C1C0600, // 0073 CALL R7 3 + 0x80040E00, // 0074 RET 1 R7 + 0x70020036, // 0075 JMP #00AD + 0x541E0007, // 0076 LDINT R7 8 + 0x1C1C0A07, // 0077 EQ R7 R5 R7 + 0x781E002B, // 0078 JMPF R7 #00A5 + 0x1C1C0D06, // 0079 EQ R7 R6 K6 + 0x781E0005, // 007A JMPF R7 #0081 + 0x8C1C0907, // 007B GETMET R7 R4 K7 + 0x8824090A, // 007C GETMBR R9 R4 K10 + 0x542A0087, // 007D LDINT R10 136 + 0x7C1C0600, // 007E CALL R7 3 + 0x80040E00, // 007F RET 1 R7 + 0x70020022, // 0080 JMP #00A4 + 0x541E000E, // 0081 LDINT R7 15 + 0x1C1C0C07, // 0082 EQ R7 R6 R7 + 0x781E0005, // 0083 JMPF R7 #008A + 0x8C1C0907, // 0084 GETMET R7 R4 K7 + 0x8824090A, // 0085 GETMBR R9 R4 K10 + 0x58280006, // 0086 LDCONST R10 K6 + 0x7C1C0600, // 0087 CALL R7 3 + 0x80040E00, // 0088 RET 1 R7 + 0x70020019, // 0089 JMP #00A4 + 0x541E000F, // 008A LDINT R7 16 + 0x1C1C0C07, // 008B EQ R7 R6 R7 + 0x781E0005, // 008C JMPF R7 #0093 + 0x8C1C0907, // 008D GETMET R7 R4 K7 + 0x8824090A, // 008E GETMBR R9 R4 K10 + 0x58280009, // 008F LDCONST R10 K9 + 0x7C1C0600, // 0090 CALL R7 3 + 0x80040E00, // 0091 RET 1 R7 + 0x70020010, // 0092 JMP #00A4 + 0x541EFFFB, // 0093 LDINT R7 65532 + 0x1C1C0C07, // 0094 EQ R7 R6 R7 + 0x781E0005, // 0095 JMPF R7 #009C + 0x8C1C0907, // 0096 GETMET R7 R4 K7 + 0x8824090B, // 0097 GETMBR R9 R4 K11 + 0x58280006, // 0098 LDCONST R10 K6 + 0x7C1C0600, // 0099 CALL R7 3 + 0x80040E00, // 009A RET 1 R7 + 0x70020007, // 009B JMP #00A4 + 0x541EFFFC, // 009C LDINT R7 65533 + 0x1C1C0C07, // 009D EQ R7 R6 R7 + 0x781E0004, // 009E JMPF R7 #00A4 + 0x8C1C0907, // 009F GETMET R7 R4 K7 + 0x8824090B, // 00A0 GETMBR R9 R4 K11 + 0x542A0003, // 00A1 LDINT R10 4 + 0x7C1C0600, // 00A2 CALL R7 3 + 0x80040E00, // 00A3 RET 1 R7 + 0x70020007, // 00A4 JMP #00AD + 0x601C0003, // 00A5 GETGBL R7 G3 + 0x5C200000, // 00A6 MOVE R8 R0 + 0x7C1C0200, // 00A7 CALL R7 1 + 0x8C1C0F0E, // 00A8 GETMET R7 R7 K14 + 0x5C240200, // 00A9 MOVE R9 R1 + 0x5C280400, // 00AA MOVE R10 R2 + 0x7C1C0600, // 00AB CALL R7 3 + 0x80040E00, // 00AC RET 1 R7 + 0x80000000, // 00AD RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_init, /* name */ + be_nested_proto( + 8, /* 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(get_onoff), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(tasmota_relay_index), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* 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 + 0x7C100600, // 0006 CALL R4 3 + 0x8C100101, // 0007 GETMET R4 R0 K1 + 0x7C100200, // 0008 CALL R4 1 + 0x4C100000, // 0009 LDNIL R4 + 0x1C100604, // 000A EQ R4 R3 R4 + 0x78120000, // 000B JMPF R4 #000D + 0x580C0002, // 000C LDCONST R3 K2 + 0x90020603, // 000D SETMBR R0 K3 R3 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_every_second, /* 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(get_onoff), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_OnOff +********************************************************************/ +extern const bclass be_class_Matter_Plugin; +be_local_class(Matter_Plugin_OnOff, + 2, + &be_class_Matter_Plugin, + be_nested_map(11, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Plugin_OnOff_every_second_closure) }, + { be_const_key_weak(get_onoff, 8), be_const_closure(Matter_Plugin_OnOff_get_onoff_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_OnOff_init_closure) }, + { be_const_key_weak(shadow_onoff, 5), be_const_var(1) }, + { be_const_key_weak(TYPES, 7), 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(read_attribute, -1), be_const_closure(Matter_Plugin_OnOff_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(4, + ( (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(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_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_weak(set_onoff, -1), be_const_closure(Matter_Plugin_OnOff_set_onoff_closure) }, + { be_const_key_weak(onoff_changed, -1), be_const_closure(Matter_Plugin_OnOff_onoff_changed_closure) }, + { be_const_key_weak(tasmota_relay_index, 2), be_const_var(0) }, + { be_const_key_weak(invoke_request, 0), be_const_closure(Matter_Plugin_OnOff_invoke_request_closure) }, + })), + be_str_weak(Matter_Plugin_OnOff) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_OnOff_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_OnOff); + be_setglobal(vm, "Matter_Plugin_OnOff"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h deleted file mode 100644 index 8a68d6822..000000000 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Relay.h +++ /dev/null @@ -1,246 +0,0 @@ -/* Solidification of Matter_Plugin_Relay.h */ -/********************************************************************\ -* Generated code, don't edit * -\********************************************************************/ -#include "be_constobj.h" - -extern const bclass be_class_Matter_Plugin_Relay; - -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_Relay_read_attribute, /* name */ - be_nested_proto( - 15, /* 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_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(attribute), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(Matter_TLV_array), - /* K7 */ be_nested_str_weak(add_struct), - /* K8 */ be_nested_str_weak(add_TLV), - /* K9 */ be_nested_str_weak(U2), - /* K10 */ be_nested_str_weak(TYPES), - /* K11 */ be_const_int(1), - /* K12 */ be_nested_str_weak(get_cluster_list), - /* K13 */ be_nested_str_weak(U4), - /* K14 */ be_nested_str_weak(stop_iteration), - /* K15 */ be_const_int(2), - /* K16 */ be_const_int(3), - }), - be_str_weak(read_attribute), - &be_const_str_solidified, - ( &(const binstruction[66]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x88100902, // 0002 GETMBR R4 R4 K2 - 0x88140503, // 0003 GETMBR R5 R2 K3 - 0x88180504, // 0004 GETMBR R6 R2 K4 - 0x541E001C, // 0005 LDINT R7 29 - 0x1C1C0A07, // 0006 EQ R7 R5 R7 - 0x781E0038, // 0007 JMPF R7 #0041 - 0x1C1C0D05, // 0008 EQ R7 R6 K5 - 0x781E0010, // 0009 JMPF R7 #001B - 0x8C1C0906, // 000A GETMET R7 R4 K6 - 0x7C1C0200, // 000B CALL R7 1 - 0x8C200F07, // 000C GETMET R8 R7 K7 - 0x7C200200, // 000D CALL R8 1 - 0x8C241108, // 000E GETMET R9 R8 K8 - 0x582C0005, // 000F LDCONST R11 K5 - 0x88300909, // 0010 GETMBR R12 R4 K9 - 0x8834010A, // 0011 GETMBR R13 R0 K10 - 0x94341B05, // 0012 GETIDX R13 R13 K5 - 0x7C240800, // 0013 CALL R9 4 - 0x8C241108, // 0014 GETMET R9 R8 K8 - 0x582C000B, // 0015 LDCONST R11 K11 - 0x88300909, // 0016 GETMBR R12 R4 K9 - 0x5834000B, // 0017 LDCONST R13 K11 - 0x7C240800, // 0018 CALL R9 4 - 0x80040E00, // 0019 RET 1 R7 - 0x70020025, // 001A JMP #0041 - 0x1C1C0D0B, // 001B EQ R7 R6 K11 - 0x781E0013, // 001C JMPF R7 #0031 - 0x8C1C0906, // 001D GETMET R7 R4 K6 - 0x7C1C0200, // 001E CALL R7 1 - 0x60200010, // 001F GETGBL R8 G16 - 0x8C24010C, // 0020 GETMET R9 R0 K12 - 0x7C240200, // 0021 CALL R9 1 - 0x7C200200, // 0022 CALL R8 1 - 0xA8020007, // 0023 EXBLK 0 #002C - 0x5C241000, // 0024 MOVE R9 R8 - 0x7C240000, // 0025 CALL R9 0 - 0x8C280F08, // 0026 GETMET R10 R7 K8 - 0x4C300000, // 0027 LDNIL R12 - 0x8834090D, // 0028 GETMBR R13 R4 K13 - 0x5C381200, // 0029 MOVE R14 R9 - 0x7C280800, // 002A CALL R10 4 - 0x7001FFF7, // 002B JMP #0024 - 0x5820000E, // 002C LDCONST R8 K14 - 0xAC200200, // 002D CATCH R8 1 0 - 0xB0080000, // 002E RAISE 2 R0 R0 - 0x80040E00, // 002F RET 1 R7 - 0x7002000F, // 0030 JMP #0041 - 0x1C1C0D0F, // 0031 EQ R7 R6 K15 - 0x781E0008, // 0032 JMPF R7 #003C - 0x8C1C0906, // 0033 GETMET R7 R4 K6 - 0x7C1C0200, // 0034 CALL R7 1 - 0x8C200F08, // 0035 GETMET R8 R7 K8 - 0x4C280000, // 0036 LDNIL R10 - 0x882C0909, // 0037 GETMBR R11 R4 K9 - 0x54320005, // 0038 LDINT R12 6 - 0x7C200800, // 0039 CALL R8 4 - 0x80040E00, // 003A RET 1 R7 - 0x70020004, // 003B JMP #0041 - 0x1C1C0D10, // 003C EQ R7 R6 K16 - 0x781E0002, // 003D JMPF R7 #0041 - 0x8C1C0906, // 003E GETMET R7 R4 K6 - 0x7C1C0200, // 003F CALL R7 1 - 0x80040E00, // 0040 RET 1 R7 - 0x80000000, // 0041 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Relay_init, /* 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(init), - /* K1 */ be_nested_str_weak(endpoints), - /* K2 */ be_nested_str_weak(ENDPOINTS), - /* K3 */ be_nested_str_weak(clusters), - /* K4 */ be_nested_str_weak(CLUSTERS), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x60080003, // 0000 GETGBL R2 G3 - 0x5C0C0000, // 0001 MOVE R3 R0 - 0x7C080200, // 0002 CALL R2 1 - 0x8C080500, // 0003 GETMET R2 R2 K0 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x88080102, // 0006 GETMBR R2 R0 K2 - 0x90020202, // 0007 SETMBR R0 K1 R2 - 0x88080104, // 0008 GETMBR R2 R0 K4 - 0x90020602, // 0009 SETMBR R0 K3 R2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Relay_invoke_request, /* name */ - be_nested_proto( - 4, /* 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[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified class: Matter_Plugin_Relay -********************************************************************/ -extern const bclass be_class_Matter_Plugin; -be_local_class(Matter_Plugin_Relay, - 0, - &be_class_Matter_Plugin, - be_nested_map(6, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Relay_read_attribute_closure) }, - { be_const_key_weak(ENDPOINTS, -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(1), - })) ) } )) }, - { be_const_key_weak(TYPES, -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(256), - })) ) } )) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Relay_init_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(1, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - })) ) } )) }, - { be_const_key_int(29, -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(3), - })) ) } )) }, - { be_const_key_int(8, -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(3, -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(4, -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(5, 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(invoke_request, -1), be_const_closure(Matter_Plugin_Relay_invoke_request_closure) }, - })), - be_str_weak(Matter_Plugin_Relay) -); -/*******************************************************************/ - -void be_load_Matter_Plugin_Relay_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Plugin_Relay); - be_setglobal(vm, "Matter_Plugin_Relay"); - be_pop(vm, 1); -} -/********************************************************************/ -/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Root.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Root.h new file mode 100644 index 000000000..b8eed6db6 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Root.h @@ -0,0 +1,2201 @@ +/* Solidification of Matter_Plugin_Root.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Root; + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Root_read_attribute, /* name */ + be_nested_proto( + 24, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[87]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(create_TLV), + /* K7 */ be_nested_str_weak(U8), + /* K8 */ be_nested_str_weak(_breadcrumb), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(Matter_TLV_struct), + /* K11 */ be_nested_str_weak(add_TLV), + /* K12 */ be_nested_str_weak(U2), + /* K13 */ be_const_int(2), + /* K14 */ be_nested_str_weak(U1), + /* K15 */ be_const_int(3), + /* K16 */ be_nested_str_weak(BOOL), + /* K17 */ be_nested_str_weak(Matter_TLV_array), + /* K18 */ be_nested_str_weak(tasmota), + /* K19 */ be_nested_str_weak(eth), + /* K20 */ be_nested_str_weak(up), + /* K21 */ be_nested_str_weak(add_struct), + /* K22 */ be_nested_str_weak(UTF1), + /* K23 */ be_nested_str_weak(ethernet), + /* K24 */ be_nested_str_weak(NULL), + /* K25 */ be_nested_str_weak(fromhex), + /* K26 */ be_nested_str_weak(replace), + /* K27 */ be_nested_str_weak(find), + /* K28 */ be_nested_str_weak(mac), + /* K29 */ be_nested_str_weak(), + /* K30 */ be_nested_str_weak(_X3A), + /* K31 */ be_nested_str_weak(B1), + /* K32 */ be_nested_str_weak(add_array), + /* K33 */ be_nested_str_weak(get_ip_bytes), + /* K34 */ be_nested_str_weak(ip), + /* K35 */ be_nested_str_weak(ip6local), + /* K36 */ be_nested_str_weak(ip6), + /* K37 */ be_nested_str_weak(wifi), + /* K38 */ be_nested_str_weak(cmd), + /* K39 */ be_nested_str_weak(Status_X201), + /* K40 */ be_nested_str_weak(StatusPRM), + /* K41 */ be_nested_str_weak(BootCount), + /* K42 */ be_nested_str_weak(U4), + /* K43 */ be_nested_str_weak(Status_X2011), + /* K44 */ be_nested_str_weak(StatusSTS), + /* K45 */ be_nested_str_weak(UptimeSec), + /* K46 */ be_nested_str_weak(int64), + /* K47 */ be_nested_str_weak(rtc), + /* K48 */ be_nested_str_weak(utc), + /* K49 */ be_const_int(1000000), + /* K50 */ be_nested_str_weak(local), + /* K51 */ be_nested_str_weak(device), + /* K52 */ be_nested_str_weak(sessions), + /* K53 */ be_nested_str_weak(active_fabrics), + /* K54 */ be_nested_str_weak(B2), + /* K55 */ be_nested_str_weak(get_noc), + /* K56 */ be_nested_str_weak(get_icac), + /* K57 */ be_nested_str_weak(get_fabric_index), + /* K58 */ be_nested_str_weak(stop_iteration), + /* K59 */ be_nested_str_weak(parse), + /* K60 */ be_nested_str_weak(get_ca), + /* K61 */ be_nested_str_weak(findsubval), + /* K62 */ be_nested_str_weak(get_admin_vendor), + /* K63 */ be_nested_str_weak(get_fabric_id), + /* K64 */ be_nested_str_weak(get_device_id), + /* K65 */ be_nested_str_weak(get_fabric_label), + /* K66 */ be_nested_str_weak(Fabric), + /* K67 */ be_nested_str_weak(_MAX_CASE), + /* K68 */ be_nested_str_weak(count_active_fabrics), + /* K69 */ be_nested_str_weak(_fabric), + /* K70 */ be_nested_str_weak(is_commissioning_open), + /* K71 */ be_nested_str_weak(is_root_commissioning_open), + /* K72 */ be_nested_str_weak(commissioning_admin_fabric), + /* K73 */ be_nested_str_weak(Tasmota), + /* K74 */ be_nested_str_weak(vendorid), + /* K75 */ be_nested_str_weak(DeviceName), + /* K76 */ be_nested_str_weak(FriendlyName), + /* K77 */ be_nested_str_weak(FriendlyName1), + /* K78 */ be_nested_str_weak(XX), + /* K79 */ be_nested_str_weak(Status_X202), + /* K80 */ be_nested_str_weak(StatusFWR), + /* K81 */ be_nested_str_weak(Hardware), + /* K82 */ be_nested_str_weak(Version), + /* K83 */ be_nested_str_weak(_X28), + /* K84 */ be_nested_str_weak(locale), + /* K85 */ be_nested_str_weak(get_active_endpoints), + /* K86 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[888]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E002F, // 0005 LDINT R7 48 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E0030, // 0007 JMPF R7 #0039 + 0x1C1C0D05, // 0008 EQ R7 R6 K5 + 0x781E0005, // 0009 JMPF R7 #0010 + 0x8C1C0906, // 000A GETMET R7 R4 K6 + 0x88240907, // 000B GETMBR R9 R4 K7 + 0x88280308, // 000C GETMBR R10 R1 K8 + 0x7C1C0600, // 000D CALL R7 3 + 0x80040E00, // 000E RET 1 R7 + 0x70020027, // 000F JMP #0038 + 0x1C1C0D09, // 0010 EQ R7 R6 K9 + 0x781E000D, // 0011 JMPF R7 #0020 + 0x8C1C090A, // 0012 GETMET R7 R4 K10 + 0x7C1C0200, // 0013 CALL R7 1 + 0x8C200F0B, // 0014 GETMET R8 R7 K11 + 0x58280005, // 0015 LDCONST R10 K5 + 0x882C090C, // 0016 GETMBR R11 R4 K12 + 0x5432003B, // 0017 LDINT R12 60 + 0x7C200800, // 0018 CALL R8 4 + 0x8C200F0B, // 0019 GETMET R8 R7 K11 + 0x58280009, // 001A LDCONST R10 K9 + 0x882C090C, // 001B GETMBR R11 R4 K12 + 0x54320383, // 001C LDINT R12 900 + 0x7C200800, // 001D CALL R8 4 + 0x80040E00, // 001E RET 1 R7 + 0x70020017, // 001F JMP #0038 + 0x1C1C0D0D, // 0020 EQ R7 R6 K13 + 0x781E0005, // 0021 JMPF R7 #0028 + 0x8C1C0906, // 0022 GETMET R7 R4 K6 + 0x8824090E, // 0023 GETMBR R9 R4 K14 + 0x5828000D, // 0024 LDCONST R10 K13 + 0x7C1C0600, // 0025 CALL R7 3 + 0x80040E00, // 0026 RET 1 R7 + 0x7002000F, // 0027 JMP #0038 + 0x1C1C0D0F, // 0028 EQ R7 R6 K15 + 0x781E0005, // 0029 JMPF R7 #0030 + 0x8C1C0906, // 002A GETMET R7 R4 K6 + 0x8824090E, // 002B GETMBR R9 R4 K14 + 0x5828000D, // 002C LDCONST R10 K13 + 0x7C1C0600, // 002D CALL R7 3 + 0x80040E00, // 002E RET 1 R7 + 0x70020007, // 002F JMP #0038 + 0x541E0003, // 0030 LDINT R7 4 + 0x1C1C0C07, // 0031 EQ R7 R6 R7 + 0x781E0004, // 0032 JMPF R7 #0038 + 0x8C1C0906, // 0033 GETMET R7 R4 K6 + 0x88240910, // 0034 GETMBR R9 R4 K16 + 0x50280000, // 0035 LDBOOL R10 0 0 + 0x7C1C0600, // 0036 CALL R7 3 + 0x80040E00, // 0037 RET 1 R7 + 0x7002033D, // 0038 JMP #0377 + 0x541E0031, // 0039 LDINT R7 50 + 0x1C1C0A07, // 003A EQ R7 R5 R7 + 0x781E0000, // 003B JMPF R7 #003D + 0x70020339, // 003C JMP #0377 + 0x541E0032, // 003D LDINT R7 51 + 0x1C1C0A07, // 003E EQ R7 R5 R7 + 0x781E00DC, // 003F JMPF R7 #011D + 0x1C1C0D05, // 0040 EQ R7 R6 K5 + 0x781E00B5, // 0041 JMPF R7 #00F8 + 0x8C1C0911, // 0042 GETMET R7 R4 K17 + 0x7C1C0200, // 0043 CALL R7 1 + 0xB8222400, // 0044 GETNGBL R8 K18 + 0x8C201113, // 0045 GETMET R8 R8 K19 + 0x7C200200, // 0046 CALL R8 1 + 0x94241114, // 0047 GETIDX R9 R8 K20 + 0x78260053, // 0048 JMPF R9 #009D + 0x8C240F15, // 0049 GETMET R9 R7 K21 + 0x4C2C0000, // 004A LDNIL R11 + 0x7C240400, // 004B CALL R9 2 + 0x8C28130B, // 004C GETMET R10 R9 K11 + 0x58300005, // 004D LDCONST R12 K5 + 0x88340916, // 004E GETMBR R13 R4 K22 + 0x58380017, // 004F LDCONST R14 K23 + 0x7C280800, // 0050 CALL R10 4 + 0x8C28130B, // 0051 GETMET R10 R9 K11 + 0x58300009, // 0052 LDCONST R12 K9 + 0x88340910, // 0053 GETMBR R13 R4 K16 + 0x58380009, // 0054 LDCONST R14 K9 + 0x7C280800, // 0055 CALL R10 4 + 0x8C28130B, // 0056 GETMET R10 R9 K11 + 0x5830000D, // 0057 LDCONST R12 K13 + 0x88340910, // 0058 GETMBR R13 R4 K16 + 0x58380009, // 0059 LDCONST R14 K9 + 0x7C280800, // 005A CALL R10 4 + 0x8C28130B, // 005B GETMET R10 R9 K11 + 0x5830000F, // 005C LDCONST R12 K15 + 0x88340918, // 005D GETMBR R13 R4 K24 + 0x4C380000, // 005E LDNIL R14 + 0x7C280800, // 005F CALL R10 4 + 0x60280015, // 0060 GETGBL R10 G21 + 0x7C280000, // 0061 CALL R10 0 + 0x8C281519, // 0062 GETMET R10 R10 K25 + 0x8C30071A, // 0063 GETMET R12 R3 K26 + 0x8C38111B, // 0064 GETMET R14 R8 K27 + 0x5840001C, // 0065 LDCONST R16 K28 + 0x5844001D, // 0066 LDCONST R17 K29 + 0x7C380600, // 0067 CALL R14 3 + 0x583C001E, // 0068 LDCONST R15 K30 + 0x5840001D, // 0069 LDCONST R16 K29 + 0x7C300800, // 006A CALL R12 4 + 0x7C280400, // 006B CALL R10 2 + 0x8C2C130B, // 006C GETMET R11 R9 K11 + 0x54360003, // 006D LDINT R13 4 + 0x8838091F, // 006E GETMBR R14 R4 K31 + 0x5C3C1400, // 006F MOVE R15 R10 + 0x7C2C0800, // 0070 CALL R11 4 + 0x8C2C1320, // 0071 GETMET R11 R9 K32 + 0x54360004, // 0072 LDINT R13 5 + 0x7C2C0400, // 0073 CALL R11 2 + 0x8C30170B, // 0074 GETMET R12 R11 K11 + 0x4C380000, // 0075 LDNIL R14 + 0x883C091F, // 0076 GETMBR R15 R4 K31 + 0xB8420200, // 0077 GETNGBL R16 K1 + 0x8C402121, // 0078 GETMET R16 R16 K33 + 0x8C48111B, // 0079 GETMET R18 R8 K27 + 0x58500022, // 007A LDCONST R20 K34 + 0x5854001D, // 007B LDCONST R21 K29 + 0x7C480600, // 007C CALL R18 3 + 0x7C400400, // 007D CALL R16 2 + 0x7C300800, // 007E CALL R12 4 + 0x8C301320, // 007F GETMET R12 R9 K32 + 0x543A0005, // 0080 LDINT R14 6 + 0x7C300400, // 0081 CALL R12 2 + 0x8C34190B, // 0082 GETMET R13 R12 K11 + 0x4C3C0000, // 0083 LDNIL R15 + 0x8840091F, // 0084 GETMBR R16 R4 K31 + 0xB8460200, // 0085 GETNGBL R17 K1 + 0x8C442321, // 0086 GETMET R17 R17 K33 + 0x8C4C111B, // 0087 GETMET R19 R8 K27 + 0x58540023, // 0088 LDCONST R21 K35 + 0x5858001D, // 0089 LDCONST R22 K29 + 0x7C4C0600, // 008A CALL R19 3 + 0x7C440400, // 008B CALL R17 2 + 0x7C340800, // 008C CALL R13 4 + 0x8C34190B, // 008D GETMET R13 R12 K11 + 0x4C3C0000, // 008E LDNIL R15 + 0x8840091F, // 008F GETMBR R16 R4 K31 + 0xB8460200, // 0090 GETNGBL R17 K1 + 0x8C442321, // 0091 GETMET R17 R17 K33 + 0x8C4C111B, // 0092 GETMET R19 R8 K27 + 0x58540024, // 0093 LDCONST R21 K36 + 0x5858001D, // 0094 LDCONST R22 K29 + 0x7C4C0600, // 0095 CALL R19 3 + 0x7C440400, // 0096 CALL R17 2 + 0x7C340800, // 0097 CALL R13 4 + 0x8C34130B, // 0098 GETMET R13 R9 K11 + 0x543E0006, // 0099 LDINT R15 7 + 0x8840090E, // 009A GETMBR R16 R4 K14 + 0x5844000D, // 009B LDCONST R17 K13 + 0x7C340800, // 009C CALL R13 4 + 0xB8262400, // 009D GETNGBL R9 K18 + 0x8C241325, // 009E GETMET R9 R9 K37 + 0x7C240200, // 009F CALL R9 1 + 0x94281314, // 00A0 GETIDX R10 R9 K20 + 0x782A0053, // 00A1 JMPF R10 #00F6 + 0x8C280F15, // 00A2 GETMET R10 R7 K21 + 0x4C300000, // 00A3 LDNIL R12 + 0x7C280400, // 00A4 CALL R10 2 + 0x8C2C150B, // 00A5 GETMET R11 R10 K11 + 0x58340005, // 00A6 LDCONST R13 K5 + 0x88380916, // 00A7 GETMBR R14 R4 K22 + 0x583C0025, // 00A8 LDCONST R15 K37 + 0x7C2C0800, // 00A9 CALL R11 4 + 0x8C2C150B, // 00AA GETMET R11 R10 K11 + 0x58340009, // 00AB LDCONST R13 K9 + 0x88380910, // 00AC GETMBR R14 R4 K16 + 0x583C0009, // 00AD LDCONST R15 K9 + 0x7C2C0800, // 00AE CALL R11 4 + 0x8C2C150B, // 00AF GETMET R11 R10 K11 + 0x5834000D, // 00B0 LDCONST R13 K13 + 0x88380910, // 00B1 GETMBR R14 R4 K16 + 0x583C0009, // 00B2 LDCONST R15 K9 + 0x7C2C0800, // 00B3 CALL R11 4 + 0x8C2C150B, // 00B4 GETMET R11 R10 K11 + 0x5834000F, // 00B5 LDCONST R13 K15 + 0x88380918, // 00B6 GETMBR R14 R4 K24 + 0x4C3C0000, // 00B7 LDNIL R15 + 0x7C2C0800, // 00B8 CALL R11 4 + 0x602C0015, // 00B9 GETGBL R11 G21 + 0x7C2C0000, // 00BA CALL R11 0 + 0x8C2C1719, // 00BB GETMET R11 R11 K25 + 0x8C34071A, // 00BC GETMET R13 R3 K26 + 0x8C3C131B, // 00BD GETMET R15 R9 K27 + 0x5844001C, // 00BE LDCONST R17 K28 + 0x5848001D, // 00BF LDCONST R18 K29 + 0x7C3C0600, // 00C0 CALL R15 3 + 0x5840001E, // 00C1 LDCONST R16 K30 + 0x5844001D, // 00C2 LDCONST R17 K29 + 0x7C340800, // 00C3 CALL R13 4 + 0x7C2C0400, // 00C4 CALL R11 2 + 0x8C30150B, // 00C5 GETMET R12 R10 K11 + 0x543A0003, // 00C6 LDINT R14 4 + 0x883C091F, // 00C7 GETMBR R15 R4 K31 + 0x5C401600, // 00C8 MOVE R16 R11 + 0x7C300800, // 00C9 CALL R12 4 + 0x8C301520, // 00CA GETMET R12 R10 K32 + 0x543A0004, // 00CB LDINT R14 5 + 0x7C300400, // 00CC CALL R12 2 + 0x8C34190B, // 00CD GETMET R13 R12 K11 + 0x4C3C0000, // 00CE LDNIL R15 + 0x8840091F, // 00CF GETMBR R16 R4 K31 + 0xB8460200, // 00D0 GETNGBL R17 K1 + 0x8C442321, // 00D1 GETMET R17 R17 K33 + 0x8C4C131B, // 00D2 GETMET R19 R9 K27 + 0x58540022, // 00D3 LDCONST R21 K34 + 0x5858001D, // 00D4 LDCONST R22 K29 + 0x7C4C0600, // 00D5 CALL R19 3 + 0x7C440400, // 00D6 CALL R17 2 + 0x7C340800, // 00D7 CALL R13 4 + 0x8C341520, // 00D8 GETMET R13 R10 K32 + 0x543E0005, // 00D9 LDINT R15 6 + 0x7C340400, // 00DA CALL R13 2 + 0x8C381B0B, // 00DB GETMET R14 R13 K11 + 0x4C400000, // 00DC LDNIL R16 + 0x8844091F, // 00DD GETMBR R17 R4 K31 + 0xB84A0200, // 00DE GETNGBL R18 K1 + 0x8C482521, // 00DF GETMET R18 R18 K33 + 0x8C50131B, // 00E0 GETMET R20 R9 K27 + 0x58580023, // 00E1 LDCONST R22 K35 + 0x585C001D, // 00E2 LDCONST R23 K29 + 0x7C500600, // 00E3 CALL R20 3 + 0x7C480400, // 00E4 CALL R18 2 + 0x7C380800, // 00E5 CALL R14 4 + 0x8C381B0B, // 00E6 GETMET R14 R13 K11 + 0x4C400000, // 00E7 LDNIL R16 + 0x8844091F, // 00E8 GETMBR R17 R4 K31 + 0xB84A0200, // 00E9 GETNGBL R18 K1 + 0x8C482521, // 00EA GETMET R18 R18 K33 + 0x8C50131B, // 00EB GETMET R20 R9 K27 + 0x58580024, // 00EC LDCONST R22 K36 + 0x585C001D, // 00ED LDCONST R23 K29 + 0x7C500600, // 00EE CALL R20 3 + 0x7C480400, // 00EF CALL R18 2 + 0x7C380800, // 00F0 CALL R14 4 + 0x8C38150B, // 00F1 GETMET R14 R10 K11 + 0x54420006, // 00F2 LDINT R16 7 + 0x8844090E, // 00F3 GETMBR R17 R4 K14 + 0x58480009, // 00F4 LDCONST R18 K9 + 0x7C380800, // 00F5 CALL R14 4 + 0x80040E00, // 00F6 RET 1 R7 + 0x70020023, // 00F7 JMP #011C + 0x1C1C0D09, // 00F8 EQ R7 R6 K9 + 0x781E000B, // 00F9 JMPF R7 #0106 + 0x8C1C0906, // 00FA GETMET R7 R4 K6 + 0x8824090C, // 00FB GETMBR R9 R4 K12 + 0xB82A2400, // 00FC GETNGBL R10 K18 + 0x8C281526, // 00FD GETMET R10 R10 K38 + 0x58300027, // 00FE LDCONST R12 K39 + 0x50340200, // 00FF LDBOOL R13 1 0 + 0x7C280600, // 0100 CALL R10 3 + 0x94281528, // 0101 GETIDX R10 R10 K40 + 0x94281529, // 0102 GETIDX R10 R10 K41 + 0x7C1C0600, // 0103 CALL R7 3 + 0x80040E00, // 0104 RET 1 R7 + 0x70020015, // 0105 JMP #011C + 0x1C1C0D0D, // 0106 EQ R7 R6 K13 + 0x781E000B, // 0107 JMPF R7 #0114 + 0x8C1C0906, // 0108 GETMET R7 R4 K6 + 0x8824092A, // 0109 GETMBR R9 R4 K42 + 0xB82A2400, // 010A GETNGBL R10 K18 + 0x8C281526, // 010B GETMET R10 R10 K38 + 0x5830002B, // 010C LDCONST R12 K43 + 0x50340200, // 010D LDBOOL R13 1 0 + 0x7C280600, // 010E CALL R10 3 + 0x9428152C, // 010F GETIDX R10 R10 K44 + 0x9428152D, // 0110 GETIDX R10 R10 K45 + 0x7C1C0600, // 0111 CALL R7 3 + 0x80040E00, // 0112 RET 1 R7 + 0x70020007, // 0113 JMP #011C + 0x541E0007, // 0114 LDINT R7 8 + 0x1C1C0C07, // 0115 EQ R7 R6 R7 + 0x781E0004, // 0116 JMPF R7 #011C + 0x8C1C0906, // 0117 GETMET R7 R4 K6 + 0x88240910, // 0118 GETMBR R9 R4 K16 + 0x50280000, // 0119 LDBOOL R10 0 0 + 0x7C1C0600, // 011A CALL R7 3 + 0x80040E00, // 011B RET 1 R7 + 0x70020259, // 011C JMP #0377 + 0x541E0033, // 011D LDINT R7 52 + 0x1C1C0A07, // 011E EQ R7 R5 R7 + 0x781E0000, // 011F JMPF R7 #0121 + 0x70020255, // 0120 JMP #0377 + 0x541E0037, // 0121 LDINT R7 56 + 0x1C1C0A07, // 0122 EQ R7 R5 R7 + 0x781E002C, // 0123 JMPF R7 #0151 + 0x1C1C0D05, // 0124 EQ R7 R6 K5 + 0x781E000F, // 0125 JMPF R7 #0136 + 0xB81E5C00, // 0126 GETNGBL R7 K46 + 0xB8222400, // 0127 GETNGBL R8 K18 + 0x8C20112F, // 0128 GETMET R8 R8 K47 + 0x7C200200, // 0129 CALL R8 1 + 0x94201130, // 012A GETIDX R8 R8 K48 + 0x7C1C0200, // 012B CALL R7 1 + 0xB8225C00, // 012C GETNGBL R8 K46 + 0x58240031, // 012D LDCONST R9 K49 + 0x7C200200, // 012E CALL R8 1 + 0x081C0E08, // 012F MUL R7 R7 R8 + 0x8C200906, // 0130 GETMET R8 R4 K6 + 0x88280907, // 0131 GETMBR R10 R4 K7 + 0x5C2C0E00, // 0132 MOVE R11 R7 + 0x7C200600, // 0133 CALL R8 3 + 0x80041000, // 0134 RET 1 R8 + 0x70020019, // 0135 JMP #0150 + 0x1C1C0D09, // 0136 EQ R7 R6 K9 + 0x781E0005, // 0137 JMPF R7 #013E + 0x8C1C0906, // 0138 GETMET R7 R4 K6 + 0x8824090E, // 0139 GETMBR R9 R4 K14 + 0x5828000F, // 013A LDCONST R10 K15 + 0x7C1C0600, // 013B CALL R7 3 + 0x80040E00, // 013C RET 1 R7 + 0x70020011, // 013D JMP #0150 + 0x541E0006, // 013E LDINT R7 7 + 0x1C1C0C07, // 013F EQ R7 R6 R7 + 0x781E000E, // 0140 JMPF R7 #0150 + 0xB81E5C00, // 0141 GETNGBL R7 K46 + 0xB8222400, // 0142 GETNGBL R8 K18 + 0x8C20112F, // 0143 GETMET R8 R8 K47 + 0x7C200200, // 0144 CALL R8 1 + 0x94201132, // 0145 GETIDX R8 R8 K50 + 0x7C1C0200, // 0146 CALL R7 1 + 0xB8225C00, // 0147 GETNGBL R8 K46 + 0x58240031, // 0148 LDCONST R9 K49 + 0x7C200200, // 0149 CALL R8 1 + 0x081C0E08, // 014A MUL R7 R7 R8 + 0x8C200906, // 014B GETMET R8 R4 K6 + 0x88280907, // 014C GETMBR R10 R4 K7 + 0x5C2C0E00, // 014D MOVE R11 R7 + 0x7C200600, // 014E CALL R8 3 + 0x80041000, // 014F RET 1 R8 + 0x70020225, // 0150 JMP #0377 + 0x541E003D, // 0151 LDINT R7 62 + 0x1C1C0A07, // 0152 EQ R7 R5 R7 + 0x781E0090, // 0153 JMPF R7 #01E5 + 0x1C1C0D05, // 0154 EQ R7 R6 K5 + 0x781E0025, // 0155 JMPF R7 #017C + 0x8C1C0911, // 0156 GETMET R7 R4 K17 + 0x7C1C0200, // 0157 CALL R7 1 + 0x60200010, // 0158 GETGBL R8 G16 + 0x88240133, // 0159 GETMBR R9 R0 K51 + 0x88241334, // 015A GETMBR R9 R9 K52 + 0x8C241335, // 015B GETMET R9 R9 K53 + 0x7C240200, // 015C CALL R9 1 + 0x7C200200, // 015D CALL R8 1 + 0xA8020017, // 015E EXBLK 0 #0177 + 0x5C241000, // 015F MOVE R9 R8 + 0x7C240000, // 0160 CALL R9 0 + 0x8C280F15, // 0161 GETMET R10 R7 K21 + 0x4C300000, // 0162 LDNIL R12 + 0x7C280400, // 0163 CALL R10 2 + 0x8C2C150B, // 0164 GETMET R11 R10 K11 + 0x58340009, // 0165 LDCONST R13 K9 + 0x88380936, // 0166 GETMBR R14 R4 K54 + 0x8C3C1337, // 0167 GETMET R15 R9 K55 + 0x7C3C0200, // 0168 CALL R15 1 + 0x7C2C0800, // 0169 CALL R11 4 + 0x8C2C150B, // 016A GETMET R11 R10 K11 + 0x5834000D, // 016B LDCONST R13 K13 + 0x88380936, // 016C GETMBR R14 R4 K54 + 0x8C3C1338, // 016D GETMET R15 R9 K56 + 0x7C3C0200, // 016E CALL R15 1 + 0x7C2C0800, // 016F CALL R11 4 + 0x8C2C150B, // 0170 GETMET R11 R10 K11 + 0x543600FD, // 0171 LDINT R13 254 + 0x8838090C, // 0172 GETMBR R14 R4 K12 + 0x8C3C1339, // 0173 GETMET R15 R9 K57 + 0x7C3C0200, // 0174 CALL R15 1 + 0x7C2C0800, // 0175 CALL R11 4 + 0x7001FFE7, // 0176 JMP #015F + 0x5820003A, // 0177 LDCONST R8 K58 + 0xAC200200, // 0178 CATCH R8 1 0 + 0xB0080000, // 0179 RAISE 2 R0 R0 + 0x80040E00, // 017A RET 1 R7 + 0x70020067, // 017B JMP #01E4 + 0x1C1C0D09, // 017C EQ R7 R6 K9 + 0x781E003C, // 017D JMPF R7 #01BB + 0x8C1C0911, // 017E GETMET R7 R4 K17 + 0x7C1C0200, // 017F CALL R7 1 + 0x60200010, // 0180 GETGBL R8 G16 + 0x88240133, // 0181 GETMBR R9 R0 K51 + 0x88241334, // 0182 GETMBR R9 R9 K52 + 0x8C241335, // 0183 GETMET R9 R9 K53 + 0x7C240200, // 0184 CALL R9 1 + 0x7C200200, // 0185 CALL R8 1 + 0xA802002E, // 0186 EXBLK 0 #01B6 + 0x5C241000, // 0187 MOVE R9 R8 + 0x7C240000, // 0188 CALL R9 0 + 0x8C28093B, // 0189 GETMET R10 R4 K59 + 0x8C30133C, // 018A GETMET R12 R9 K60 + 0x7C300200, // 018B CALL R12 1 + 0x7C280400, // 018C CALL R10 2 + 0x8C2C0F15, // 018D GETMET R11 R7 K21 + 0x4C340000, // 018E LDNIL R13 + 0x7C2C0400, // 018F CALL R11 2 + 0x8C30170B, // 0190 GETMET R12 R11 K11 + 0x58380009, // 0191 LDCONST R14 K9 + 0x883C0936, // 0192 GETMBR R15 R4 K54 + 0x8C40153D, // 0193 GETMET R16 R10 K61 + 0x544A0008, // 0194 LDINT R18 9 + 0x7C400400, // 0195 CALL R16 2 + 0x7C300800, // 0196 CALL R12 4 + 0x8C30170B, // 0197 GETMET R12 R11 K11 + 0x5838000D, // 0198 LDCONST R14 K13 + 0x883C090C, // 0199 GETMBR R15 R4 K12 + 0x8C40133E, // 019A GETMET R16 R9 K62 + 0x7C400200, // 019B CALL R16 1 + 0x7C300800, // 019C CALL R12 4 + 0x8C30170B, // 019D GETMET R12 R11 K11 + 0x5838000F, // 019E LDCONST R14 K15 + 0x883C0907, // 019F GETMBR R15 R4 K7 + 0x8C40133F, // 01A0 GETMET R16 R9 K63 + 0x7C400200, // 01A1 CALL R16 1 + 0x7C300800, // 01A2 CALL R12 4 + 0x8C30170B, // 01A3 GETMET R12 R11 K11 + 0x543A0003, // 01A4 LDINT R14 4 + 0x883C0907, // 01A5 GETMBR R15 R4 K7 + 0x8C401340, // 01A6 GETMET R16 R9 K64 + 0x7C400200, // 01A7 CALL R16 1 + 0x7C300800, // 01A8 CALL R12 4 + 0x8C30170B, // 01A9 GETMET R12 R11 K11 + 0x543A0004, // 01AA LDINT R14 5 + 0x883C0916, // 01AB GETMBR R15 R4 K22 + 0x8C401341, // 01AC GETMET R16 R9 K65 + 0x7C400200, // 01AD CALL R16 1 + 0x7C300800, // 01AE CALL R12 4 + 0x8C30170B, // 01AF GETMET R12 R11 K11 + 0x543A00FD, // 01B0 LDINT R14 254 + 0x883C090C, // 01B1 GETMBR R15 R4 K12 + 0x8C401339, // 01B2 GETMET R16 R9 K57 + 0x7C400200, // 01B3 CALL R16 1 + 0x7C300800, // 01B4 CALL R12 4 + 0x7001FFD0, // 01B5 JMP #0187 + 0x5820003A, // 01B6 LDCONST R8 K58 + 0xAC200200, // 01B7 CATCH R8 1 0 + 0xB0080000, // 01B8 RAISE 2 R0 R0 + 0x80040E00, // 01B9 RET 1 R7 + 0x70020028, // 01BA JMP #01E4 + 0x1C1C0D0D, // 01BB EQ R7 R6 K13 + 0x781E0007, // 01BC JMPF R7 #01C5 + 0x8C1C0906, // 01BD GETMET R7 R4 K6 + 0x8824090E, // 01BE GETMBR R9 R4 K14 + 0xB82A0200, // 01BF GETNGBL R10 K1 + 0x88281542, // 01C0 GETMBR R10 R10 K66 + 0x88281543, // 01C1 GETMBR R10 R10 K67 + 0x7C1C0600, // 01C2 CALL R7 3 + 0x80040E00, // 01C3 RET 1 R7 + 0x7002001E, // 01C4 JMP #01E4 + 0x1C1C0D0F, // 01C5 EQ R7 R6 K15 + 0x781E0009, // 01C6 JMPF R7 #01D1 + 0x881C0133, // 01C7 GETMBR R7 R0 K51 + 0x881C0F34, // 01C8 GETMBR R7 R7 K52 + 0x8C1C0F44, // 01C9 GETMET R7 R7 K68 + 0x7C1C0200, // 01CA CALL R7 1 + 0x8C200906, // 01CB GETMET R8 R4 K6 + 0x8828090E, // 01CC GETMBR R10 R4 K14 + 0x5C2C0E00, // 01CD MOVE R11 R7 + 0x7C200600, // 01CE CALL R8 3 + 0x80041000, // 01CF RET 1 R8 + 0x70020012, // 01D0 JMP #01E4 + 0x541E0003, // 01D1 LDINT R7 4 + 0x1C1C0C07, // 01D2 EQ R7 R6 R7 + 0x781E0000, // 01D3 JMPF R7 #01D5 + 0x7002000E, // 01D4 JMP #01E4 + 0x541E0004, // 01D5 LDINT R7 5 + 0x1C1C0C07, // 01D6 EQ R7 R6 R7 + 0x781E000B, // 01D7 JMPF R7 #01E4 + 0x881C0345, // 01D8 GETMBR R7 R1 K69 + 0x8C1C0F39, // 01D9 GETMET R7 R7 K57 + 0x7C1C0200, // 01DA CALL R7 1 + 0x4C200000, // 01DB LDNIL R8 + 0x1C200E08, // 01DC EQ R8 R7 R8 + 0x78220000, // 01DD JMPF R8 #01DF + 0x581C0005, // 01DE LDCONST R7 K5 + 0x8C200906, // 01DF GETMET R8 R4 K6 + 0x8828090E, // 01E0 GETMBR R10 R4 K14 + 0x5C2C0E00, // 01E1 MOVE R11 R7 + 0x7C200600, // 01E2 CALL R8 3 + 0x80041000, // 01E3 RET 1 R8 + 0x70020191, // 01E4 JMP #0377 + 0x541E003B, // 01E5 LDINT R7 60 + 0x1C1C0A07, // 01E6 EQ R7 R5 R7 + 0x781E003C, // 01E7 JMPF R7 #0225 + 0x1C1C0D05, // 01E8 EQ R7 R6 K5 + 0x781E0012, // 01E9 JMPF R7 #01FD + 0x881C0133, // 01EA GETMBR R7 R0 K51 + 0x8C1C0F46, // 01EB GETMET R7 R7 K70 + 0x7C1C0200, // 01EC CALL R7 1 + 0x88200133, // 01ED GETMBR R8 R0 K51 + 0x8C201147, // 01EE GETMET R8 R8 K71 + 0x7C200200, // 01EF CALL R8 1 + 0x781E0004, // 01F0 JMPF R7 #01F6 + 0x78220001, // 01F1 JMPF R8 #01F4 + 0x5824000D, // 01F2 LDCONST R9 K13 + 0x70020000, // 01F3 JMP #01F5 + 0x58240009, // 01F4 LDCONST R9 K9 + 0x70020000, // 01F5 JMP #01F7 + 0x58240005, // 01F6 LDCONST R9 K5 + 0x8C280906, // 01F7 GETMET R10 R4 K6 + 0x8830090E, // 01F8 GETMBR R12 R4 K14 + 0x5C341200, // 01F9 MOVE R13 R9 + 0x7C280600, // 01FA CALL R10 3 + 0x80041400, // 01FB RET 1 R10 + 0x70020026, // 01FC JMP #0224 + 0x1C1C0D09, // 01FD EQ R7 R6 K9 + 0x781E0011, // 01FE JMPF R7 #0211 + 0x881C0133, // 01FF GETMBR R7 R0 K51 + 0x881C0F48, // 0200 GETMBR R7 R7 K72 + 0x4C200000, // 0201 LDNIL R8 + 0x20200E08, // 0202 NE R8 R7 R8 + 0x78220006, // 0203 JMPF R8 #020B + 0x8C200906, // 0204 GETMET R8 R4 K6 + 0x8828090C, // 0205 GETMBR R10 R4 K12 + 0x8C2C0F39, // 0206 GETMET R11 R7 K57 + 0x7C2C0200, // 0207 CALL R11 1 + 0x7C200600, // 0208 CALL R8 3 + 0x80041000, // 0209 RET 1 R8 + 0x70020004, // 020A JMP #0210 + 0x8C200906, // 020B GETMET R8 R4 K6 + 0x88280918, // 020C GETMBR R10 R4 K24 + 0x4C2C0000, // 020D LDNIL R11 + 0x7C200600, // 020E CALL R8 3 + 0x80041000, // 020F RET 1 R8 + 0x70020012, // 0210 JMP #0224 + 0x1C1C0D0D, // 0211 EQ R7 R6 K13 + 0x781E0010, // 0212 JMPF R7 #0224 + 0x881C0133, // 0213 GETMBR R7 R0 K51 + 0x881C0F48, // 0214 GETMBR R7 R7 K72 + 0x4C200000, // 0215 LDNIL R8 + 0x20200E08, // 0216 NE R8 R7 R8 + 0x78220006, // 0217 JMPF R8 #021F + 0x8C200906, // 0218 GETMET R8 R4 K6 + 0x8828090C, // 0219 GETMBR R10 R4 K12 + 0x8C2C0F3E, // 021A GETMET R11 R7 K62 + 0x7C2C0200, // 021B CALL R11 1 + 0x7C200600, // 021C CALL R8 3 + 0x80041000, // 021D RET 1 R8 + 0x70020004, // 021E JMP #0224 + 0x8C200906, // 021F GETMET R8 R4 K6 + 0x88280918, // 0220 GETMBR R10 R4 K24 + 0x4C2C0000, // 0221 LDNIL R11 + 0x7C200600, // 0222 CALL R8 3 + 0x80041000, // 0223 RET 1 R8 + 0x70020151, // 0224 JMP #0377 + 0x541E0027, // 0225 LDINT R7 40 + 0x1C1C0A07, // 0226 EQ R7 R5 R7 + 0x781E00AE, // 0227 JMPF R7 #02D7 + 0x1C1C0D05, // 0228 EQ R7 R6 K5 + 0x781E0005, // 0229 JMPF R7 #0230 + 0x8C1C0906, // 022A GETMET R7 R4 K6 + 0x8824090C, // 022B GETMBR R9 R4 K12 + 0x58280009, // 022C LDCONST R10 K9 + 0x7C1C0600, // 022D CALL R7 3 + 0x80040E00, // 022E RET 1 R7 + 0x700200A5, // 022F JMP #02D6 + 0x1C1C0D09, // 0230 EQ R7 R6 K9 + 0x781E0005, // 0231 JMPF R7 #0238 + 0x8C1C0906, // 0232 GETMET R7 R4 K6 + 0x88240916, // 0233 GETMBR R9 R4 K22 + 0x58280049, // 0234 LDCONST R10 K73 + 0x7C1C0600, // 0235 CALL R7 3 + 0x80040E00, // 0236 RET 1 R7 + 0x7002009D, // 0237 JMP #02D6 + 0x1C1C0D0D, // 0238 EQ R7 R6 K13 + 0x781E0006, // 0239 JMPF R7 #0241 + 0x8C1C0906, // 023A GETMET R7 R4 K6 + 0x8824090C, // 023B GETMBR R9 R4 K12 + 0x88280133, // 023C GETMBR R10 R0 K51 + 0x8828154A, // 023D GETMBR R10 R10 K74 + 0x7C1C0600, // 023E CALL R7 3 + 0x80040E00, // 023F RET 1 R7 + 0x70020094, // 0240 JMP #02D6 + 0x1C1C0D0F, // 0241 EQ R7 R6 K15 + 0x781E000A, // 0242 JMPF R7 #024E + 0x8C1C0906, // 0243 GETMET R7 R4 K6 + 0x88240916, // 0244 GETMBR R9 R4 K22 + 0xB82A2400, // 0245 GETNGBL R10 K18 + 0x8C281526, // 0246 GETMET R10 R10 K38 + 0x5830004B, // 0247 LDCONST R12 K75 + 0x50340200, // 0248 LDBOOL R13 1 0 + 0x7C280600, // 0249 CALL R10 3 + 0x9428154B, // 024A GETIDX R10 R10 K75 + 0x7C1C0600, // 024B CALL R7 3 + 0x80040E00, // 024C RET 1 R7 + 0x70020087, // 024D JMP #02D6 + 0x541E0003, // 024E LDINT R7 4 + 0x1C1C0C07, // 024F EQ R7 R6 R7 + 0x781E0005, // 0250 JMPF R7 #0257 + 0x8C1C0906, // 0251 GETMET R7 R4 K6 + 0x8824090C, // 0252 GETMBR R9 R4 K12 + 0x542A7FFF, // 0253 LDINT R10 32768 + 0x7C1C0600, // 0254 CALL R7 3 + 0x80040E00, // 0255 RET 1 R7 + 0x7002007E, // 0256 JMP #02D6 + 0x541E0004, // 0257 LDINT R7 5 + 0x1C1C0C07, // 0258 EQ R7 R6 R7 + 0x781E000A, // 0259 JMPF R7 #0265 + 0x8C1C0906, // 025A GETMET R7 R4 K6 + 0x88240916, // 025B GETMBR R9 R4 K22 + 0xB82A2400, // 025C GETNGBL R10 K18 + 0x8C281526, // 025D GETMET R10 R10 K38 + 0x5830004C, // 025E LDCONST R12 K76 + 0x50340200, // 025F LDBOOL R13 1 0 + 0x7C280600, // 0260 CALL R10 3 + 0x9428154D, // 0261 GETIDX R10 R10 K77 + 0x7C1C0600, // 0262 CALL R7 3 + 0x80040E00, // 0263 RET 1 R7 + 0x70020070, // 0264 JMP #02D6 + 0x541E0005, // 0265 LDINT R7 6 + 0x1C1C0C07, // 0266 EQ R7 R6 R7 + 0x781E0005, // 0267 JMPF R7 #026E + 0x8C1C0906, // 0268 GETMET R7 R4 K6 + 0x88240916, // 0269 GETMBR R9 R4 K22 + 0x5828004E, // 026A LDCONST R10 K78 + 0x7C1C0600, // 026B CALL R7 3 + 0x80040E00, // 026C RET 1 R7 + 0x70020067, // 026D JMP #02D6 + 0x541E0006, // 026E LDINT R7 7 + 0x1C1C0C07, // 026F EQ R7 R6 R7 + 0x781E0005, // 0270 JMPF R7 #0277 + 0x8C1C0906, // 0271 GETMET R7 R4 K6 + 0x8824090C, // 0272 GETMBR R9 R4 K12 + 0x58280005, // 0273 LDCONST R10 K5 + 0x7C1C0600, // 0274 CALL R7 3 + 0x80040E00, // 0275 RET 1 R7 + 0x7002005E, // 0276 JMP #02D6 + 0x541E0007, // 0277 LDINT R7 8 + 0x1C1C0C07, // 0278 EQ R7 R6 R7 + 0x781E000B, // 0279 JMPF R7 #0286 + 0x8C1C0906, // 027A GETMET R7 R4 K6 + 0x88240916, // 027B GETMBR R9 R4 K22 + 0xB82A2400, // 027C GETNGBL R10 K18 + 0x8C281526, // 027D GETMET R10 R10 K38 + 0x5830004F, // 027E LDCONST R12 K79 + 0x50340200, // 027F LDBOOL R13 1 0 + 0x7C280600, // 0280 CALL R10 3 + 0x94281550, // 0281 GETIDX R10 R10 K80 + 0x94281551, // 0282 GETIDX R10 R10 K81 + 0x7C1C0600, // 0283 CALL R7 3 + 0x80040E00, // 0284 RET 1 R7 + 0x7002004F, // 0285 JMP #02D6 + 0x541E0008, // 0286 LDINT R7 9 + 0x1C1C0C07, // 0287 EQ R7 R6 R7 + 0x781E0005, // 0288 JMPF R7 #028F + 0x8C1C0906, // 0289 GETMET R7 R4 K6 + 0x8824090C, // 028A GETMBR R9 R4 K12 + 0x58280009, // 028B LDCONST R10 K9 + 0x7C1C0600, // 028C CALL R7 3 + 0x80040E00, // 028D RET 1 R7 + 0x70020046, // 028E JMP #02D6 + 0x541E0009, // 028F LDINT R7 10 + 0x1C1C0C07, // 0290 EQ R7 R6 R7 + 0x781E0015, // 0291 JMPF R7 #02A8 + 0xB81E2400, // 0292 GETNGBL R7 K18 + 0x8C1C0F26, // 0293 GETMET R7 R7 K38 + 0x5824004F, // 0294 LDCONST R9 K79 + 0x50280200, // 0295 LDBOOL R10 1 0 + 0x7C1C0600, // 0296 CALL R7 3 + 0x941C0F50, // 0297 GETIDX R7 R7 K80 + 0x941C0F52, // 0298 GETIDX R7 R7 K82 + 0x8C20071B, // 0299 GETMET R8 R3 K27 + 0x5C280E00, // 029A MOVE R10 R7 + 0x582C0053, // 029B LDCONST R11 K83 + 0x7C200600, // 029C CALL R8 3 + 0x24241105, // 029D GT R9 R8 K5 + 0x78260002, // 029E JMPF R9 #02A2 + 0x04241109, // 029F SUB R9 R8 K9 + 0x40260A09, // 02A0 CONNECT R9 K5 R9 + 0x941C0E09, // 02A1 GETIDX R7 R7 R9 + 0x8C240906, // 02A2 GETMET R9 R4 K6 + 0x882C0916, // 02A3 GETMBR R11 R4 K22 + 0x5C300E00, // 02A4 MOVE R12 R7 + 0x7C240600, // 02A5 CALL R9 3 + 0x80041200, // 02A6 RET 1 R9 + 0x7002002D, // 02A7 JMP #02D6 + 0x541E000E, // 02A8 LDINT R7 15 + 0x1C1C0C07, // 02A9 EQ R7 R6 R7 + 0x781E000B, // 02AA JMPF R7 #02B7 + 0x8C1C0906, // 02AB GETMET R7 R4 K6 + 0x88240916, // 02AC GETMBR R9 R4 K22 + 0xB82A2400, // 02AD GETNGBL R10 K18 + 0x8C281525, // 02AE GETMET R10 R10 K37 + 0x7C280200, // 02AF CALL R10 1 + 0x8C28151B, // 02B0 GETMET R10 R10 K27 + 0x5830001C, // 02B1 LDCONST R12 K28 + 0x5834001D, // 02B2 LDCONST R13 K29 + 0x7C280600, // 02B3 CALL R10 3 + 0x7C1C0600, // 02B4 CALL R7 3 + 0x80040E00, // 02B5 RET 1 R7 + 0x7002001E, // 02B6 JMP #02D6 + 0x541E0011, // 02B7 LDINT R7 18 + 0x1C1C0C07, // 02B8 EQ R7 R6 R7 + 0x781E000B, // 02B9 JMPF R7 #02C6 + 0x8C1C0906, // 02BA GETMET R7 R4 K6 + 0x88240916, // 02BB GETMBR R9 R4 K22 + 0xB82A2400, // 02BC GETNGBL R10 K18 + 0x8C281525, // 02BD GETMET R10 R10 K37 + 0x7C280200, // 02BE CALL R10 1 + 0x8C28151B, // 02BF GETMET R10 R10 K27 + 0x5830001C, // 02C0 LDCONST R12 K28 + 0x5834001D, // 02C1 LDCONST R13 K29 + 0x7C280600, // 02C2 CALL R10 3 + 0x7C1C0600, // 02C3 CALL R7 3 + 0x80040E00, // 02C4 RET 1 R7 + 0x7002000F, // 02C5 JMP #02D6 + 0x541E0012, // 02C6 LDINT R7 19 + 0x1C1C0C07, // 02C7 EQ R7 R6 R7 + 0x781E000C, // 02C8 JMPF R7 #02D6 + 0x8C1C090A, // 02C9 GETMET R7 R4 K10 + 0x7C1C0200, // 02CA CALL R7 1 + 0x8C200F0B, // 02CB GETMET R8 R7 K11 + 0x58280005, // 02CC LDCONST R10 K5 + 0x882C090C, // 02CD GETMBR R11 R4 K12 + 0x5830000F, // 02CE LDCONST R12 K15 + 0x7C200800, // 02CF CALL R8 4 + 0x8C200F0B, // 02D0 GETMET R8 R7 K11 + 0x58280009, // 02D1 LDCONST R10 K9 + 0x882C090C, // 02D2 GETMBR R11 R4 K12 + 0x5830000F, // 02D3 LDCONST R12 K15 + 0x7C200800, // 02D4 CALL R8 4 + 0x80040E00, // 02D5 RET 1 R7 + 0x7002009F, // 02D6 JMP #0377 + 0x541E003E, // 02D7 LDINT R7 63 + 0x1C1C0A07, // 02D8 EQ R7 R5 R7 + 0x781E0000, // 02D9 JMPF R7 #02DB + 0x7002009B, // 02DA JMP #0377 + 0x541E0029, // 02DB LDINT R7 42 + 0x1C1C0A07, // 02DC EQ R7 R5 R7 + 0x781E001D, // 02DD JMPF R7 #02FC + 0x1C1C0D05, // 02DE EQ R7 R6 K5 + 0x781E0003, // 02DF JMPF R7 #02E4 + 0x8C1C0911, // 02E0 GETMET R7 R4 K17 + 0x7C1C0200, // 02E1 CALL R7 1 + 0x80040E00, // 02E2 RET 1 R7 + 0x70020016, // 02E3 JMP #02FB + 0x1C1C0D09, // 02E4 EQ R7 R6 K9 + 0x781E0005, // 02E5 JMPF R7 #02EC + 0x8C1C0906, // 02E6 GETMET R7 R4 K6 + 0x88240910, // 02E7 GETMBR R9 R4 K16 + 0x58280005, // 02E8 LDCONST R10 K5 + 0x7C1C0600, // 02E9 CALL R7 3 + 0x80040E00, // 02EA RET 1 R7 + 0x7002000E, // 02EB JMP #02FB + 0x1C1C0D0D, // 02EC EQ R7 R6 K13 + 0x781E0005, // 02ED JMPF R7 #02F4 + 0x8C1C0906, // 02EE GETMET R7 R4 K6 + 0x8824090E, // 02EF GETMBR R9 R4 K14 + 0x58280009, // 02F0 LDCONST R10 K9 + 0x7C1C0600, // 02F1 CALL R7 3 + 0x80040E00, // 02F2 RET 1 R7 + 0x70020006, // 02F3 JMP #02FB + 0x1C1C0D0F, // 02F4 EQ R7 R6 K15 + 0x781E0004, // 02F5 JMPF R7 #02FB + 0x8C1C0906, // 02F6 GETMET R7 R4 K6 + 0x88240918, // 02F7 GETMBR R9 R4 K24 + 0x4C280000, // 02F8 LDNIL R10 + 0x7C1C0600, // 02F9 CALL R7 3 + 0x80040E00, // 02FA RET 1 R7 + 0x7002007A, // 02FB JMP #0377 + 0x541E002A, // 02FC LDINT R7 43 + 0x1C1C0A07, // 02FD EQ R7 R5 R7 + 0x781E0016, // 02FE JMPF R7 #0316 + 0x1C1C0D05, // 02FF EQ R7 R6 K5 + 0x781E0007, // 0300 JMPF R7 #0309 + 0x8C1C0906, // 0301 GETMET R7 R4 K6 + 0x88240916, // 0302 GETMBR R9 R4 K22 + 0xB82A2400, // 0303 GETNGBL R10 K18 + 0x8C281554, // 0304 GETMET R10 R10 K84 + 0x7C280200, // 0305 CALL R10 1 + 0x7C1C0600, // 0306 CALL R7 3 + 0x80040E00, // 0307 RET 1 R7 + 0x7002000B, // 0308 JMP #0315 + 0x1C1C0D09, // 0309 EQ R7 R6 K9 + 0x781E0009, // 030A JMPF R7 #0315 + 0x8C1C0911, // 030B GETMET R7 R4 K17 + 0x7C1C0200, // 030C CALL R7 1 + 0x8C200F0B, // 030D GETMET R8 R7 K11 + 0x4C280000, // 030E LDNIL R10 + 0x882C0916, // 030F GETMBR R11 R4 K22 + 0xB8322400, // 0310 GETNGBL R12 K18 + 0x8C301954, // 0311 GETMET R12 R12 K84 + 0x7C300200, // 0312 CALL R12 1 + 0x7C200800, // 0313 CALL R8 4 + 0x80040E00, // 0314 RET 1 R7 + 0x70020060, // 0315 JMP #0377 + 0x541E002B, // 0316 LDINT R7 44 + 0x1C1C0A07, // 0317 EQ R7 R5 R7 + 0x781E001C, // 0318 JMPF R7 #0336 + 0x1C1C0D05, // 0319 EQ R7 R6 K5 + 0x781E0005, // 031A JMPF R7 #0321 + 0x8C1C0906, // 031B GETMET R7 R4 K6 + 0x8824090E, // 031C GETMBR R9 R4 K14 + 0x58280009, // 031D LDCONST R10 K9 + 0x7C1C0600, // 031E CALL R7 3 + 0x80040E00, // 031F RET 1 R7 + 0x70020013, // 0320 JMP #0335 + 0x1C1C0D09, // 0321 EQ R7 R6 K9 + 0x781E0005, // 0322 JMPF R7 #0329 + 0x8C1C0906, // 0323 GETMET R7 R4 K6 + 0x8824090E, // 0324 GETMBR R9 R4 K14 + 0x542A0003, // 0325 LDINT R10 4 + 0x7C1C0600, // 0326 CALL R7 3 + 0x80040E00, // 0327 RET 1 R7 + 0x7002000B, // 0328 JMP #0335 + 0x1C1C0D0D, // 0329 EQ R7 R6 K13 + 0x781E0009, // 032A JMPF R7 #0335 + 0x8C1C0911, // 032B GETMET R7 R4 K17 + 0x7C1C0200, // 032C CALL R7 1 + 0x8C200F0B, // 032D GETMET R8 R7 K11 + 0x4C280000, // 032E LDNIL R10 + 0x8C2C0906, // 032F GETMET R11 R4 K6 + 0x8834090E, // 0330 GETMBR R13 R4 K14 + 0x543A0003, // 0331 LDINT R14 4 + 0x7C2C0600, // 0332 CALL R11 3 + 0x7C200600, // 0333 CALL R8 3 + 0x80040E00, // 0334 RET 1 R7 + 0x70020040, // 0335 JMP #0377 + 0x541E0030, // 0336 LDINT R7 49 + 0x1C1C0A07, // 0337 EQ R7 R5 R7 + 0x781E0010, // 0338 JMPF R7 #034A + 0x1C1C0D0F, // 0339 EQ R7 R6 K15 + 0x781E0005, // 033A JMPF R7 #0341 + 0x8C1C0906, // 033B GETMET R7 R4 K6 + 0x8824090E, // 033C GETMBR R9 R4 K14 + 0x542A001D, // 033D LDINT R10 30 + 0x7C1C0600, // 033E CALL R7 3 + 0x80040E00, // 033F RET 1 R7 + 0x70020007, // 0340 JMP #0349 + 0x541EFFFB, // 0341 LDINT R7 65532 + 0x1C1C0C07, // 0342 EQ R7 R6 R7 + 0x781E0004, // 0343 JMPF R7 #0349 + 0x8C1C0906, // 0344 GETMET R7 R4 K6 + 0x8824092A, // 0345 GETMBR R9 R4 K42 + 0x542A0003, // 0346 LDINT R10 4 + 0x7C1C0600, // 0347 CALL R7 3 + 0x80040E00, // 0348 RET 1 R7 + 0x7002002C, // 0349 JMP #0377 + 0x541E001C, // 034A LDINT R7 29 + 0x1C1C0A07, // 034B EQ R7 R5 R7 + 0x781E0021, // 034C JMPF R7 #036F + 0x1C1C0D0F, // 034D EQ R7 R6 K15 + 0x781E0016, // 034E JMPF R7 #0366 + 0x8C1C0911, // 034F GETMET R7 R4 K17 + 0x7C1C0200, // 0350 CALL R7 1 + 0x88200133, // 0351 GETMBR R8 R0 K51 + 0x8C201155, // 0352 GETMET R8 R8 K85 + 0x50280200, // 0353 LDBOOL R10 1 0 + 0x7C200400, // 0354 CALL R8 2 + 0x60240010, // 0355 GETGBL R9 G16 + 0x5C281000, // 0356 MOVE R10 R8 + 0x7C240200, // 0357 CALL R9 1 + 0xA8020007, // 0358 EXBLK 0 #0361 + 0x5C281200, // 0359 MOVE R10 R9 + 0x7C280000, // 035A CALL R10 0 + 0x8C2C0F0B, // 035B GETMET R11 R7 K11 + 0x4C340000, // 035C LDNIL R13 + 0x8838090C, // 035D GETMBR R14 R4 K12 + 0x5C3C1400, // 035E MOVE R15 R10 + 0x7C2C0800, // 035F CALL R11 4 + 0x7001FFF7, // 0360 JMP #0359 + 0x5824003A, // 0361 LDCONST R9 K58 + 0xAC240200, // 0362 CATCH R9 1 0 + 0xB0080000, // 0363 RAISE 2 R0 R0 + 0x80040E00, // 0364 RET 1 R7 + 0x70020007, // 0365 JMP #036E + 0x601C0003, // 0366 GETGBL R7 G3 + 0x5C200000, // 0367 MOVE R8 R0 + 0x7C1C0200, // 0368 CALL R7 1 + 0x8C1C0F56, // 0369 GETMET R7 R7 K86 + 0x5C240200, // 036A MOVE R9 R1 + 0x5C280400, // 036B MOVE R10 R2 + 0x7C1C0600, // 036C CALL R7 3 + 0x80040E00, // 036D RET 1 R7 + 0x70020007, // 036E JMP #0377 + 0x601C0003, // 036F GETGBL R7 G3 + 0x5C200000, // 0370 MOVE R8 R0 + 0x7C1C0200, // 0371 CALL R7 1 + 0x8C1C0F56, // 0372 GETMET R7 R7 K86 + 0x5C240200, // 0373 MOVE R9 R1 + 0x5C280400, // 0374 MOVE R10 R2 + 0x7C1C0600, // 0375 CALL R7 3 + 0x80040E00, // 0376 RET 1 R7 + 0x80000000, // 0377 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: write_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Root_write_attribute, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(int), + /* K7 */ be_nested_str_weak(int64), + /* K8 */ be_nested_str_weak(_breadcrumb), + /* K9 */ be_nested_str_weak(attribute_updated), + /* K10 */ be_nested_str_weak(endpoint), + /* K11 */ be_nested_str_weak(status), + /* K12 */ be_nested_str_weak(CONSTRAINT_ERROR), + /* K13 */ be_const_int(1), + /* K14 */ be_nested_str_weak(INVALID_ACTION), + }), + be_str_weak(write_attribute), + &be_const_str_solidified, + ( &(const binstruction[102]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180503, // 0003 GETMBR R6 R2 K3 + 0x881C0504, // 0004 GETMBR R7 R2 K4 + 0x5422002F, // 0005 LDINT R8 48 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x7822001A, // 0007 JMPF R8 #0023 + 0x1C200F05, // 0008 EQ R8 R7 K5 + 0x78220017, // 0009 JMPF R8 #0022 + 0x60200004, // 000A GETGBL R8 G4 + 0x5C240600, // 000B MOVE R9 R3 + 0x7C200200, // 000C CALL R8 1 + 0x1C201106, // 000D EQ R8 R8 K6 + 0x74220004, // 000E JMPT R8 #0014 + 0x6020000F, // 000F GETGBL R8 G15 + 0x5C240600, // 0010 MOVE R9 R3 + 0xB82A0E00, // 0011 GETNGBL R10 K7 + 0x7C200400, // 0012 CALL R8 2 + 0x78220008, // 0013 JMPF R8 #001D + 0x90061003, // 0014 SETMBR R1 K8 R3 + 0x8C200109, // 0015 GETMET R8 R0 K9 + 0x8828050A, // 0016 GETMBR R10 R2 K10 + 0x882C0503, // 0017 GETMBR R11 R2 K3 + 0x88300504, // 0018 GETMBR R12 R2 K4 + 0x7C200800, // 0019 CALL R8 4 + 0x50200200, // 001A LDBOOL R8 1 0 + 0x80041000, // 001B RET 1 R8 + 0x70020004, // 001C JMP #0022 + 0xB8220200, // 001D GETNGBL R8 K1 + 0x8820110C, // 001E GETMBR R8 R8 K12 + 0x900A1608, // 001F SETMBR R2 K11 R8 + 0x50200000, // 0020 LDBOOL R8 0 0 + 0x80041000, // 0021 RET 1 R8 + 0x70020041, // 0022 JMP #0065 + 0x5422001E, // 0023 LDINT R8 31 + 0x1C200C08, // 0024 EQ R8 R6 R8 + 0x78220004, // 0025 JMPF R8 #002B + 0x1C200F05, // 0026 EQ R8 R7 K5 + 0x78220001, // 0027 JMPF R8 #002A + 0x50200200, // 0028 LDBOOL R8 1 0 + 0x80041000, // 0029 RET 1 R8 + 0x70020039, // 002A JMP #0065 + 0x54220027, // 002B LDINT R8 40 + 0x1C200C08, // 002C EQ R8 R6 R8 + 0x7822000B, // 002D JMPF R8 #003A + 0x54220004, // 002E LDINT R8 5 + 0x1C200E08, // 002F EQ R8 R7 R8 + 0x78220002, // 0030 JMPF R8 #0034 + 0x50200200, // 0031 LDBOOL R8 1 0 + 0x80041000, // 0032 RET 1 R8 + 0x70020004, // 0033 JMP #0039 + 0x54220005, // 0034 LDINT R8 6 + 0x1C200E08, // 0035 EQ R8 R7 R8 + 0x78220001, // 0036 JMPF R8 #0039 + 0x50200200, // 0037 LDBOOL R8 1 0 + 0x80041000, // 0038 RET 1 R8 + 0x7002002A, // 0039 JMP #0065 + 0x54220029, // 003A LDINT R8 42 + 0x1C200C08, // 003B EQ R8 R6 R8 + 0x78220004, // 003C JMPF R8 #0042 + 0x1C200F05, // 003D EQ R8 R7 K5 + 0x78220001, // 003E JMPF R8 #0041 + 0x50200200, // 003F LDBOOL R8 1 0 + 0x80041000, // 0040 RET 1 R8 + 0x70020022, // 0041 JMP #0065 + 0x5422002A, // 0042 LDINT R8 43 + 0x1C200C08, // 0043 EQ R8 R6 R8 + 0x78220007, // 0044 JMPF R8 #004D + 0x1C200F05, // 0045 EQ R8 R7 K5 + 0x78220004, // 0046 JMPF R8 #004C + 0xB8220200, // 0047 GETNGBL R8 K1 + 0x8820110C, // 0048 GETMBR R8 R8 K12 + 0x900A1608, // 0049 SETMBR R2 K11 R8 + 0x50200000, // 004A LDBOOL R8 0 0 + 0x80041000, // 004B RET 1 R8 + 0x70020017, // 004C JMP #0065 + 0x5422002B, // 004D LDINT R8 44 + 0x1C200C08, // 004E EQ R8 R6 R8 + 0x78220009, // 004F JMPF R8 #005A + 0x1C200F05, // 0050 EQ R8 R7 K5 + 0x78220002, // 0051 JMPF R8 #0055 + 0x50200200, // 0052 LDBOOL R8 1 0 + 0x80041000, // 0053 RET 1 R8 + 0x70020003, // 0054 JMP #0059 + 0x1C200F0D, // 0055 EQ R8 R7 K13 + 0x78220001, // 0056 JMPF R8 #0059 + 0x50200200, // 0057 LDBOOL R8 1 0 + 0x80041000, // 0058 RET 1 R8 + 0x7002000A, // 0059 JMP #0065 + 0x54220030, // 005A LDINT R8 49 + 0x1C200C08, // 005B EQ R8 R6 R8 + 0x78220007, // 005C JMPF R8 #0065 + 0x54220003, // 005D LDINT R8 4 + 0x1C200E08, // 005E EQ R8 R7 R8 + 0x78220004, // 005F JMPF R8 #0065 + 0xB8220200, // 0060 GETNGBL R8 K1 + 0x8820110E, // 0061 GETMBR R8 R8 K14 + 0x900A1608, // 0062 SETMBR R2 K11 R8 + 0x50200000, // 0063 LDBOOL R8 0 0 + 0x80041000, // 0064 RET 1 R8 + 0x80000000, // 0065 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Root_init, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x600C0003, // 0000 GETGBL R3 G3 + 0x5C100000, // 0001 MOVE R4 R0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x8C0C0700, // 0003 GETMET R3 R3 K0 + 0x5C140200, // 0004 MOVE R5 R1 + 0x5C180400, // 0005 MOVE R6 R2 + 0x7C0C0600, // 0006 CALL R3 3 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Root_invoke_request, /* name */ + be_nested_proto( + 29, /* 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, 11), + }), + 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(string), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(TLV), + /* K4 */ be_nested_str_weak(cluster), + /* K5 */ be_nested_str_weak(command), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(findsubval), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(_breadcrumb), + /* K10 */ be_nested_str_weak(Matter_TLV_struct), + /* K11 */ be_nested_str_weak(add_TLV), + /* K12 */ be_nested_str_weak(U1), + /* K13 */ be_nested_str_weak(UTF1), + /* K14 */ be_nested_str_weak(), + /* K15 */ be_const_int(2), + /* K16 */ be_nested_str_weak(XX), + /* K17 */ be_const_int(3), + /* K18 */ be_nested_str_weak(fabric_completed), + /* K19 */ be_nested_str_weak(set_no_expiration), + /* K20 */ be_nested_str_weak(save), + /* K21 */ be_nested_str_weak(device), + /* K22 */ be_nested_str_weak(start_commissioning_complete_deferred), + /* K23 */ be_nested_str_weak(status), + /* K24 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K25 */ be_nested_str_weak(B2), + /* K26 */ be_nested_str_weak(DAC_Cert_FFF1_8000), + /* K27 */ be_nested_str_weak(PAI_Cert_FFF1), + /* K28 */ be_nested_str_weak(CD_FFF1_8000), + /* K29 */ be_nested_str_weak(B1), + /* K30 */ be_nested_str_weak(U4), + /* K31 */ be_nested_str_weak(tasmota), + /* K32 */ be_nested_str_weak(rtc), + /* K33 */ be_nested_str_weak(utc), + /* K34 */ be_nested_str_weak(tlv2raw), + /* K35 */ be_nested_str_weak(get_ac), + /* K36 */ be_nested_str_weak(log), + /* K37 */ be_nested_str_weak(MTR_X3A_X20attestation_tbs_X3D), + /* K38 */ be_nested_str_weak(tohex), + /* K39 */ be_nested_str_weak(EC_P256), + /* K40 */ be_nested_str_weak(ecdsa_sign_sha256), + /* K41 */ be_nested_str_weak(DAC_Priv_FFF1_8000), + /* K42 */ be_nested_str_weak(gen_CSR), + /* K43 */ be_nested_str_weak(MTR_X3A_X20nocsr_tbs_X3D), + /* K44 */ be_nested_str_weak(set_ca), + /* K45 */ be_nested_str_weak(MTR_X3A_X20received_X20ca_root_X3D), + /* K46 */ be_nested_str_weak(SUCCESS), + /* K47 */ be_nested_str_weak(get_ca), + /* K48 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20AdNOC_X20without_X20CA), + /* K49 */ be_nested_str_weak(set_noc), + /* K50 */ be_nested_str_weak(set_ipk_epoch_key), + /* K51 */ be_nested_str_weak(set_admin_subject_vendor), + /* K52 */ be_nested_str_weak(parse), + /* K53 */ be_nested_str_weak(findsub), + /* K54 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20no_X20fabricid_X20nor_X20deviceid_X20in_X20NOC_X20certificate), + /* K55 */ be_nested_str_weak(int), + /* K56 */ be_nested_str_weak(int64), + /* K57 */ be_nested_str_weak(fromu32), + /* K58 */ be_nested_str_weak(tobytes), + /* K59 */ be_const_int(2147483647), + /* K60 */ be_nested_str_weak(fromstring), + /* K61 */ be_nested_str_weak(CompressedFabric), + /* K62 */ be_nested_str_weak(HKDF_SHA256), + /* K63 */ be_nested_str_weak(copy), + /* K64 */ be_nested_str_weak(reverse), + /* K65 */ be_nested_str_weak(derive), + /* K66 */ be_nested_str_weak(set_fabric_device), + /* K67 */ be_nested_str_weak(commissioning_admin_fabric), + /* K68 */ be_nested_str_weak(persist_to_fabric), + /* K69 */ be_nested_str_weak(fabric_candidate), + /* K70 */ be_nested_str_weak(start_operational_discovery_deferred), + /* K71 */ be_nested_str_weak(MTR_X3A_X20_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D_X2D), + /* K72 */ be_nested_str_weak(MTR_X3A_X20fabric_X3D), + /* K73 */ be_nested_str_weak(inspect), + /* K74 */ be_nested_str_weak(_fabric), + /* K75 */ be_nested_str_weak(log_new_fabric), + /* K76 */ be_nested_str_weak(set_fabric_label), + /* K77 */ be_nested_str_weak(format), + /* K78 */ 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), + /* K79 */ be_nested_str_weak(get_fabric_id), + /* K80 */ be_nested_str_weak(sessions), + /* K81 */ be_nested_str_weak(active_fabrics), + /* K82 */ be_nested_str_weak(get_fabric_index), + /* K83 */ be_nested_str_weak(MTR_X3A_X20removing_X20fabric_X20), + /* K84 */ be_nested_str_weak(set_timer), + /* K85 */ be_nested_str_weak(stop_iteration), + /* K86 */ be_nested_str_weak(MTR_X3A_X20RemoveFabric_X20fabric_X28), + /* K87 */ be_nested_str_weak(_X29_X20not_X20found), + /* K88 */ be_nested_str_weak(INVALID_ACTION), + /* K89 */ be_nested_str_weak(fabric_index_X3A), + /* 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[735]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xA4160200, // 0001 IMPORT R5 K1 + 0xB81A0400, // 0002 GETNGBL R6 K2 + 0x88180D03, // 0003 GETMBR R6 R6 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x88200705, // 0005 GETMBR R8 R3 K5 + 0x5426002F, // 0006 LDINT R9 48 + 0x1C240E09, // 0007 EQ R9 R7 R9 + 0x78260054, // 0008 JMPF R9 #005E + 0x1C241106, // 0009 EQ R9 R8 K6 + 0x78260017, // 000A JMPF R9 #0023 + 0x8C240507, // 000B GETMET R9 R2 K7 + 0x582C0006, // 000C LDCONST R11 K6 + 0x54320383, // 000D LDINT R12 900 + 0x7C240600, // 000E CALL R9 3 + 0x8C280507, // 000F GETMET R10 R2 K7 + 0x58300008, // 0010 LDCONST R12 K8 + 0x58340006, // 0011 LDCONST R13 K6 + 0x7C280600, // 0012 CALL R10 3 + 0x9006120A, // 0013 SETMBR R1 K9 R10 + 0x8C2C0D0A, // 0014 GETMET R11 R6 K10 + 0x7C2C0200, // 0015 CALL R11 1 + 0x8C30170B, // 0016 GETMET R12 R11 K11 + 0x58380006, // 0017 LDCONST R14 K6 + 0x883C0D0C, // 0018 GETMBR R15 R6 K12 + 0x58400006, // 0019 LDCONST R16 K6 + 0x7C300800, // 001A CALL R12 4 + 0x8C30170B, // 001B GETMET R12 R11 K11 + 0x58380008, // 001C LDCONST R14 K8 + 0x883C0D0D, // 001D GETMBR R15 R6 K13 + 0x5840000E, // 001E LDCONST R16 K14 + 0x7C300800, // 001F CALL R12 4 + 0x900E0B08, // 0020 SETMBR R3 K5 K8 + 0x80041600, // 0021 RET 1 R11 + 0x70020039, // 0022 JMP #005D + 0x1C24110F, // 0023 EQ R9 R8 K15 + 0x7826001A, // 0024 JMPF R9 #0040 + 0x8C240507, // 0025 GETMET R9 R2 K7 + 0x582C0006, // 0026 LDCONST R11 K6 + 0x7C240400, // 0027 CALL R9 2 + 0x8C280507, // 0028 GETMET R10 R2 K7 + 0x58300008, // 0029 LDCONST R12 K8 + 0x58340010, // 002A LDCONST R13 K16 + 0x7C280600, // 002B CALL R10 3 + 0x8C2C0507, // 002C GETMET R11 R2 K7 + 0x5834000F, // 002D LDCONST R13 K15 + 0x58380006, // 002E LDCONST R14 K6 + 0x7C2C0600, // 002F CALL R11 3 + 0x9006120B, // 0030 SETMBR R1 K9 R11 + 0x8C300D0A, // 0031 GETMET R12 R6 K10 + 0x7C300200, // 0032 CALL R12 1 + 0x8C34190B, // 0033 GETMET R13 R12 K11 + 0x583C0006, // 0034 LDCONST R15 K6 + 0x88400D0C, // 0035 GETMBR R16 R6 K12 + 0x58440006, // 0036 LDCONST R17 K6 + 0x7C340800, // 0037 CALL R13 4 + 0x8C34190B, // 0038 GETMET R13 R12 K11 + 0x583C0008, // 0039 LDCONST R15 K8 + 0x88400D0D, // 003A GETMBR R16 R6 K13 + 0x5844000E, // 003B LDCONST R17 K14 + 0x7C340800, // 003C CALL R13 4 + 0x900E0B11, // 003D SETMBR R3 K5 K17 + 0x80041800, // 003E RET 1 R12 + 0x7002001C, // 003F JMP #005D + 0x54260003, // 0040 LDINT R9 4 + 0x1C241009, // 0041 EQ R9 R8 R9 + 0x78260019, // 0042 JMPF R9 #005D + 0x90061306, // 0043 SETMBR R1 K9 K6 + 0x8C240312, // 0044 GETMET R9 R1 K18 + 0x7C240200, // 0045 CALL R9 1 + 0x8C240313, // 0046 GETMET R9 R1 K19 + 0x7C240200, // 0047 CALL R9 1 + 0x8C240314, // 0048 GETMET R9 R1 K20 + 0x7C240200, // 0049 CALL R9 1 + 0x8C240D0A, // 004A GETMET R9 R6 K10 + 0x7C240200, // 004B CALL R9 1 + 0x8C28130B, // 004C GETMET R10 R9 K11 + 0x58300006, // 004D LDCONST R12 K6 + 0x88340D0C, // 004E GETMBR R13 R6 K12 + 0x58380006, // 004F LDCONST R14 K6 + 0x7C280800, // 0050 CALL R10 4 + 0x8C28130B, // 0051 GETMET R10 R9 K11 + 0x58300008, // 0052 LDCONST R12 K8 + 0x88340D0D, // 0053 GETMBR R13 R6 K13 + 0x5838000E, // 0054 LDCONST R14 K14 + 0x7C280800, // 0055 CALL R10 4 + 0x542A0004, // 0056 LDINT R10 5 + 0x900E0A0A, // 0057 SETMBR R3 K5 R10 + 0x88280115, // 0058 GETMBR R10 R0 K21 + 0x8C281516, // 0059 GETMET R10 R10 K22 + 0x5C300200, // 005A MOVE R12 R1 + 0x7C280400, // 005B CALL R10 2 + 0x80041200, // 005C RET 1 R9 + 0x7002027E, // 005D JMP #02DD + 0x5426003D, // 005E LDINT R9 62 + 0x1C240E09, // 005F EQ R9 R7 R9 + 0x782601E0, // 0060 JMPF R9 #0242 + 0x1C24110F, // 0061 EQ R9 R8 K15 + 0x7826001D, // 0062 JMPF R9 #0081 + 0x8C240507, // 0063 GETMET R9 R2 K7 + 0x582C0006, // 0064 LDCONST R11 K6 + 0x7C240400, // 0065 CALL R9 2 + 0x20281308, // 0066 NE R10 R9 K8 + 0x782A0006, // 0067 JMPF R10 #006F + 0x2028130F, // 0068 NE R10 R9 K15 + 0x782A0004, // 0069 JMPF R10 #006F + 0xB82A0400, // 006A GETNGBL R10 K2 + 0x88281518, // 006B GETMBR R10 R10 K24 + 0x900E2E0A, // 006C SETMBR R3 K23 R10 + 0x4C280000, // 006D LDNIL R10 + 0x80041400, // 006E RET 1 R10 + 0x8C280D0A, // 006F GETMET R10 R6 K10 + 0x7C280200, // 0070 CALL R10 1 + 0x8C2C150B, // 0071 GETMET R11 R10 K11 + 0x58340006, // 0072 LDCONST R13 K6 + 0x88380D19, // 0073 GETMBR R14 R6 K25 + 0x1C3C1308, // 0074 EQ R15 R9 K8 + 0x783E0003, // 0075 JMPF R15 #007A + 0xB83E0400, // 0076 GETNGBL R15 K2 + 0x8C3C1F1A, // 0077 GETMET R15 R15 K26 + 0x7C3C0200, // 0078 CALL R15 1 + 0x70020002, // 0079 JMP #007D + 0xB83E0400, // 007A GETNGBL R15 K2 + 0x8C3C1F1B, // 007B GETMET R15 R15 K27 + 0x7C3C0200, // 007C CALL R15 1 + 0x7C2C0800, // 007D CALL R11 4 + 0x900E0B11, // 007E SETMBR R3 K5 K17 + 0x80041400, // 007F RET 1 R10 + 0x700201BF, // 0080 JMP #0241 + 0x1C241106, // 0081 EQ R9 R8 K6 + 0x78260044, // 0082 JMPF R9 #00C8 + 0x8C240507, // 0083 GETMET R9 R2 K7 + 0x582C0006, // 0084 LDCONST R11 K6 + 0x7C240400, // 0085 CALL R9 2 + 0x6028000C, // 0086 GETGBL R10 G12 + 0x5C2C1200, // 0087 MOVE R11 R9 + 0x7C280200, // 0088 CALL R10 1 + 0x542E001F, // 0089 LDINT R11 32 + 0x2028140B, // 008A NE R10 R10 R11 + 0x782A0001, // 008B JMPF R10 #008E + 0x4C280000, // 008C LDNIL R10 + 0x80041400, // 008D RET 1 R10 + 0x900E0B08, // 008E SETMBR R3 K5 K8 + 0x8C280D0A, // 008F GETMET R10 R6 K10 + 0x7C280200, // 0090 CALL R10 1 + 0x8C2C150B, // 0091 GETMET R11 R10 K11 + 0x58340008, // 0092 LDCONST R13 K8 + 0x88380D19, // 0093 GETMBR R14 R6 K25 + 0xB83E0400, // 0094 GETNGBL R15 K2 + 0x8C3C1F1C, // 0095 GETMET R15 R15 K28 + 0x7C3C0200, // 0096 CALL R15 1 + 0x7C2C0800, // 0097 CALL R11 4 + 0x8C2C150B, // 0098 GETMET R11 R10 K11 + 0x5834000F, // 0099 LDCONST R13 K15 + 0x88380D1D, // 009A GETMBR R14 R6 K29 + 0x5C3C1200, // 009B MOVE R15 R9 + 0x7C2C0800, // 009C CALL R11 4 + 0x8C2C150B, // 009D GETMET R11 R10 K11 + 0x58340011, // 009E LDCONST R13 K17 + 0x88380D1E, // 009F GETMBR R14 R6 K30 + 0xB83E3E00, // 00A0 GETNGBL R15 K31 + 0x8C3C1F20, // 00A1 GETMET R15 R15 K32 + 0x7C3C0200, // 00A2 CALL R15 1 + 0x943C1F21, // 00A3 GETIDX R15 R15 K33 + 0x7C2C0800, // 00A4 CALL R11 4 + 0x8C2C1522, // 00A5 GETMET R11 R10 K34 + 0x7C2C0200, // 00A6 CALL R11 1 + 0x8C300323, // 00A7 GETMET R12 R1 K35 + 0x7C300200, // 00A8 CALL R12 1 + 0x0034160C, // 00A9 ADD R13 R11 R12 + 0xB83A3E00, // 00AA GETNGBL R14 K31 + 0x8C381D24, // 00AB GETMET R14 R14 K36 + 0x8C401B26, // 00AC GETMET R16 R13 K38 + 0x7C400200, // 00AD CALL R16 1 + 0x00424A10, // 00AE ADD R16 K37 R16 + 0x58440011, // 00AF LDCONST R17 K17 + 0x7C380600, // 00B0 CALL R14 3 + 0x8C380927, // 00B1 GETMET R14 R4 K39 + 0x7C380200, // 00B2 CALL R14 1 + 0x8C381D28, // 00B3 GETMET R14 R14 K40 + 0xB8420400, // 00B4 GETNGBL R16 K2 + 0x8C402129, // 00B5 GETMET R16 R16 K41 + 0x7C400200, // 00B6 CALL R16 1 + 0x5C441A00, // 00B7 MOVE R17 R13 + 0x7C380600, // 00B8 CALL R14 3 + 0x8C3C0D0A, // 00B9 GETMET R15 R6 K10 + 0x7C3C0200, // 00BA CALL R15 1 + 0x8C401F0B, // 00BB GETMET R16 R15 K11 + 0x58480006, // 00BC LDCONST R18 K6 + 0x884C0D19, // 00BD GETMBR R19 R6 K25 + 0x5C501600, // 00BE MOVE R20 R11 + 0x7C400800, // 00BF CALL R16 4 + 0x8C401F0B, // 00C0 GETMET R16 R15 K11 + 0x58480008, // 00C1 LDCONST R18 K8 + 0x884C0D1D, // 00C2 GETMBR R19 R6 K29 + 0x5C501C00, // 00C3 MOVE R20 R14 + 0x7C400800, // 00C4 CALL R16 4 + 0x900E0B08, // 00C5 SETMBR R3 K5 K8 + 0x80041E00, // 00C6 RET 1 R15 + 0x70020178, // 00C7 JMP #0241 + 0x54260003, // 00C8 LDINT R9 4 + 0x1C241009, // 00C9 EQ R9 R8 R9 + 0x78260040, // 00CA JMPF R9 #010C + 0x8C240507, // 00CB GETMET R9 R2 K7 + 0x582C0006, // 00CC LDCONST R11 K6 + 0x7C240400, // 00CD CALL R9 2 + 0x6028000C, // 00CE GETGBL R10 G12 + 0x5C2C1200, // 00CF MOVE R11 R9 + 0x7C280200, // 00D0 CALL R10 1 + 0x542E001F, // 00D1 LDINT R11 32 + 0x2028140B, // 00D2 NE R10 R10 R11 + 0x782A0001, // 00D3 JMPF R10 #00D6 + 0x4C280000, // 00D4 LDNIL R10 + 0x80041400, // 00D5 RET 1 R10 + 0x8C280507, // 00D6 GETMET R10 R2 K7 + 0x58300008, // 00D7 LDCONST R12 K8 + 0x50340000, // 00D8 LDBOOL R13 0 0 + 0x7C280600, // 00D9 CALL R10 3 + 0x8C2C032A, // 00DA GETMET R11 R1 K42 + 0x7C2C0200, // 00DB CALL R11 1 + 0x8C300D0A, // 00DC GETMET R12 R6 K10 + 0x7C300200, // 00DD CALL R12 1 + 0x8C34190B, // 00DE GETMET R13 R12 K11 + 0x583C0008, // 00DF LDCONST R15 K8 + 0x88400D19, // 00E0 GETMBR R16 R6 K25 + 0x5C441600, // 00E1 MOVE R17 R11 + 0x7C340800, // 00E2 CALL R13 4 + 0x8C34190B, // 00E3 GETMET R13 R12 K11 + 0x583C000F, // 00E4 LDCONST R15 K15 + 0x88400D1D, // 00E5 GETMBR R16 R6 K29 + 0x5C441200, // 00E6 MOVE R17 R9 + 0x7C340800, // 00E7 CALL R13 4 + 0x8C341922, // 00E8 GETMET R13 R12 K34 + 0x7C340200, // 00E9 CALL R13 1 + 0x8C380323, // 00EA GETMET R14 R1 K35 + 0x7C380200, // 00EB CALL R14 1 + 0x00381A0E, // 00EC ADD R14 R13 R14 + 0xB83E3E00, // 00ED GETNGBL R15 K31 + 0x8C3C1F24, // 00EE GETMET R15 R15 K36 + 0x8C441D26, // 00EF GETMET R17 R14 K38 + 0x7C440200, // 00F0 CALL R17 1 + 0x00465611, // 00F1 ADD R17 K43 R17 + 0x58480011, // 00F2 LDCONST R18 K17 + 0x7C3C0600, // 00F3 CALL R15 3 + 0x8C3C0927, // 00F4 GETMET R15 R4 K39 + 0x7C3C0200, // 00F5 CALL R15 1 + 0x8C3C1F28, // 00F6 GETMET R15 R15 K40 + 0xB8460400, // 00F7 GETNGBL R17 K2 + 0x8C442329, // 00F8 GETMET R17 R17 K41 + 0x7C440200, // 00F9 CALL R17 1 + 0x5C481C00, // 00FA MOVE R18 R14 + 0x7C3C0600, // 00FB CALL R15 3 + 0x8C400D0A, // 00FC GETMET R16 R6 K10 + 0x7C400200, // 00FD CALL R16 1 + 0x8C44210B, // 00FE GETMET R17 R16 K11 + 0x584C0006, // 00FF LDCONST R19 K6 + 0x88500D19, // 0100 GETMBR R20 R6 K25 + 0x5C541A00, // 0101 MOVE R21 R13 + 0x7C440800, // 0102 CALL R17 4 + 0x8C44210B, // 0103 GETMET R17 R16 K11 + 0x584C0008, // 0104 LDCONST R19 K8 + 0x88500D1D, // 0105 GETMBR R20 R6 K29 + 0x5C541E00, // 0106 MOVE R21 R15 + 0x7C440800, // 0107 CALL R17 4 + 0x54460004, // 0108 LDINT R17 5 + 0x900E0A11, // 0109 SETMBR R3 K5 R17 + 0x80042000, // 010A RET 1 R16 + 0x70020134, // 010B JMP #0241 + 0x5426000A, // 010C LDINT R9 11 + 0x1C241009, // 010D EQ R9 R8 R9 + 0x78260012, // 010E JMPF R9 #0122 + 0x8C240507, // 010F GETMET R9 R2 K7 + 0x582C0006, // 0110 LDCONST R11 K6 + 0x7C240400, // 0111 CALL R9 2 + 0x8C28032C, // 0112 GETMET R10 R1 K44 + 0x5C301200, // 0113 MOVE R12 R9 + 0x7C280400, // 0114 CALL R10 2 + 0xB82A3E00, // 0115 GETNGBL R10 K31 + 0x8C281524, // 0116 GETMET R10 R10 K36 + 0x8C301326, // 0117 GETMET R12 R9 K38 + 0x7C300200, // 0118 CALL R12 1 + 0x00325A0C, // 0119 ADD R12 K45 R12 + 0x58340011, // 011A LDCONST R13 K17 + 0x7C280600, // 011B CALL R10 3 + 0xB82A0400, // 011C GETNGBL R10 K2 + 0x8828152E, // 011D GETMBR R10 R10 K46 + 0x900E2E0A, // 011E SETMBR R3 K23 R10 + 0x4C280000, // 011F LDNIL R10 + 0x80041400, // 0120 RET 1 R10 + 0x7002011E, // 0121 JMP #0241 + 0x54260005, // 0122 LDINT R9 6 + 0x1C241009, // 0123 EQ R9 R8 R9 + 0x782600B7, // 0124 JMPF R9 #01DD + 0x8C240507, // 0125 GETMET R9 R2 K7 + 0x582C0006, // 0126 LDCONST R11 K6 + 0x7C240400, // 0127 CALL R9 2 + 0x8C280507, // 0128 GETMET R10 R2 K7 + 0x58300008, // 0129 LDCONST R12 K8 + 0x7C280400, // 012A CALL R10 2 + 0x602C000C, // 012B GETGBL R11 G12 + 0x5C301400, // 012C MOVE R12 R10 + 0x7C2C0200, // 012D CALL R11 1 + 0x1C2C1706, // 012E EQ R11 R11 K6 + 0x782E0000, // 012F JMPF R11 #0131 + 0x4C280000, // 0130 LDNIL R10 + 0x8C2C0507, // 0131 GETMET R11 R2 K7 + 0x5834000F, // 0132 LDCONST R13 K15 + 0x7C2C0400, // 0133 CALL R11 2 + 0x8C300507, // 0134 GETMET R12 R2 K7 + 0x58380011, // 0135 LDCONST R14 K17 + 0x7C300400, // 0136 CALL R12 2 + 0x8C340507, // 0137 GETMET R13 R2 K7 + 0x543E0003, // 0138 LDINT R15 4 + 0x7C340400, // 0139 CALL R13 2 + 0x8C38032F, // 013A GETMET R14 R1 K47 + 0x7C380200, // 013B CALL R14 1 + 0x4C3C0000, // 013C LDNIL R15 + 0x1C381C0F, // 013D EQ R14 R14 R15 + 0x783A0006, // 013E JMPF R14 #0146 + 0xB83A3E00, // 013F GETNGBL R14 K31 + 0x8C381D24, // 0140 GETMET R14 R14 K36 + 0x58400030, // 0141 LDCONST R16 K48 + 0x5844000F, // 0142 LDCONST R17 K15 + 0x7C380600, // 0143 CALL R14 3 + 0x4C380000, // 0144 LDNIL R14 + 0x80041C00, // 0145 RET 1 R14 + 0x8C380331, // 0146 GETMET R14 R1 K49 + 0x5C401200, // 0147 MOVE R16 R9 + 0x5C441400, // 0148 MOVE R17 R10 + 0x7C380600, // 0149 CALL R14 3 + 0x8C380332, // 014A GETMET R14 R1 K50 + 0x5C401600, // 014B MOVE R16 R11 + 0x7C380400, // 014C CALL R14 2 + 0x8C380333, // 014D GETMET R14 R1 K51 + 0x5C401800, // 014E MOVE R16 R12 + 0x5C441A00, // 014F MOVE R17 R13 + 0x7C380600, // 0150 CALL R14 3 + 0xB83A0400, // 0151 GETNGBL R14 K2 + 0x88381D03, // 0152 GETMBR R14 R14 K3 + 0x8C381D34, // 0153 GETMET R14 R14 K52 + 0x5C401200, // 0154 MOVE R16 R9 + 0x7C380400, // 0155 CALL R14 2 + 0x8C3C1D35, // 0156 GETMET R15 R14 K53 + 0x54460005, // 0157 LDINT R17 6 + 0x7C3C0400, // 0158 CALL R15 2 + 0x8C401F07, // 0159 GETMET R16 R15 K7 + 0x544A0014, // 015A LDINT R18 21 + 0x7C400400, // 015B CALL R16 2 + 0x8C441F07, // 015C GETMET R17 R15 K7 + 0x544E0010, // 015D LDINT R19 17 + 0x7C440400, // 015E CALL R17 2 + 0x5C482000, // 015F MOVE R18 R16 + 0x784A0001, // 0160 JMPF R18 #0163 + 0x5C482200, // 0161 MOVE R18 R17 + 0x744A0006, // 0162 JMPT R18 #016A + 0xB84A3E00, // 0163 GETNGBL R18 K31 + 0x8C482524, // 0164 GETMET R18 R18 K36 + 0x58500036, // 0165 LDCONST R20 K54 + 0x5854000F, // 0166 LDCONST R21 K15 + 0x7C480600, // 0167 CALL R18 3 + 0x50480000, // 0168 LDBOOL R18 0 0 + 0x80042400, // 0169 RET 1 R18 + 0x60480004, // 016A GETGBL R18 G4 + 0x5C4C2000, // 016B MOVE R19 R16 + 0x7C480200, // 016C CALL R18 1 + 0x1C482537, // 016D EQ R18 R18 K55 + 0x784A0007, // 016E JMPF R18 #0177 + 0xB84A7000, // 016F GETNGBL R18 K56 + 0x8C482539, // 0170 GETMET R18 R18 K57 + 0x5C502000, // 0171 MOVE R20 R16 + 0x7C480400, // 0172 CALL R18 2 + 0x8C48253A, // 0173 GETMET R18 R18 K58 + 0x7C480200, // 0174 CALL R18 1 + 0x5C402400, // 0175 MOVE R16 R18 + 0x70020002, // 0176 JMP #017A + 0x8C48213A, // 0177 GETMET R18 R16 K58 + 0x7C480200, // 0178 CALL R18 1 + 0x5C402400, // 0179 MOVE R16 R18 + 0x60480004, // 017A GETGBL R18 G4 + 0x5C4C2200, // 017B MOVE R19 R17 + 0x7C480200, // 017C CALL R18 1 + 0x1C482537, // 017D EQ R18 R18 K55 + 0x784A0007, // 017E JMPF R18 #0187 + 0xB84A7000, // 017F GETNGBL R18 K56 + 0x8C482539, // 0180 GETMET R18 R18 K57 + 0x5C502200, // 0181 MOVE R20 R17 + 0x7C480400, // 0182 CALL R18 2 + 0x8C48253A, // 0183 GETMET R18 R18 K58 + 0x7C480200, // 0184 CALL R18 1 + 0x5C442400, // 0185 MOVE R17 R18 + 0x70020002, // 0186 JMP #018A + 0x8C48233A, // 0187 GETMET R18 R17 K58 + 0x7C480200, // 0188 CALL R18 1 + 0x5C442400, // 0189 MOVE R17 R18 + 0xB84A0400, // 018A GETNGBL R18 K2 + 0x88482503, // 018B GETMBR R18 R18 K3 + 0x8C482534, // 018C GETMET R18 R18 K52 + 0x8C50032F, // 018D GETMET R20 R1 K47 + 0x7C500200, // 018E CALL R20 1 + 0x7C480400, // 018F CALL R18 2 + 0x8C482507, // 0190 GETMET R18 R18 K7 + 0x54520008, // 0191 LDINT R20 9 + 0x7C480400, // 0192 CALL R18 2 + 0x404E113B, // 0193 CONNECT R19 K8 K59 + 0x94482413, // 0194 GETIDX R18 R18 R19 + 0x60500015, // 0195 GETGBL R20 G21 + 0x7C500000, // 0196 CALL R20 0 + 0x8C50293C, // 0197 GETMET R20 R20 K60 + 0x5858003D, // 0198 LDCONST R22 K61 + 0x7C500400, // 0199 CALL R20 2 + 0x5C4C2800, // 019A MOVE R19 R20 + 0x8C50093E, // 019B GETMET R20 R4 K62 + 0x7C500200, // 019C CALL R20 1 + 0x8C54213F, // 019D GETMET R21 R16 K63 + 0x7C540200, // 019E CALL R21 1 + 0x8C542B40, // 019F GETMET R21 R21 K64 + 0x7C540200, // 01A0 CALL R21 1 + 0x8C582941, // 01A1 GETMET R22 R20 K65 + 0x5C602400, // 01A2 MOVE R24 R18 + 0x5C642A00, // 01A3 MOVE R25 R21 + 0x5C682600, // 01A4 MOVE R26 R19 + 0x546E0007, // 01A5 LDINT R27 8 + 0x7C580A00, // 01A6 CALL R22 5 + 0x8C5C0342, // 01A7 GETMET R23 R1 K66 + 0x5C642000, // 01A8 MOVE R25 R16 + 0x5C682200, // 01A9 MOVE R26 R17 + 0x5C6C2C00, // 01AA MOVE R27 R22 + 0x88700115, // 01AB GETMBR R28 R0 K21 + 0x88703943, // 01AC GETMBR R28 R28 K67 + 0x7C5C0A00, // 01AD CALL R23 5 + 0x8C5C0344, // 01AE GETMET R23 R1 K68 + 0x7C5C0200, // 01AF CALL R23 1 + 0x8C5C0345, // 01B0 GETMET R23 R1 K69 + 0x7C5C0200, // 01B1 CALL R23 1 + 0x885C0115, // 01B2 GETMBR R23 R0 K21 + 0x8C5C2F46, // 01B3 GETMET R23 R23 K70 + 0x5C640200, // 01B4 MOVE R25 R1 + 0x7C5C0400, // 01B5 CALL R23 2 + 0xB85E3E00, // 01B6 GETNGBL R23 K31 + 0x8C5C2F24, // 01B7 GETMET R23 R23 K36 + 0x58640047, // 01B8 LDCONST R25 K71 + 0x58680011, // 01B9 LDCONST R26 K17 + 0x7C5C0600, // 01BA CALL R23 3 + 0xB85E3E00, // 01BB GETNGBL R23 K31 + 0x8C5C2F24, // 01BC GETMET R23 R23 K36 + 0xB8660400, // 01BD GETNGBL R25 K2 + 0x8C643349, // 01BE GETMET R25 R25 K73 + 0x886C034A, // 01BF GETMBR R27 R1 K74 + 0x7C640400, // 01C0 CALL R25 2 + 0x00669019, // 01C1 ADD R25 K72 R25 + 0x58680011, // 01C2 LDCONST R26 K17 + 0x7C5C0600, // 01C3 CALL R23 3 + 0xB85E3E00, // 01C4 GETNGBL R23 K31 + 0x8C5C2F24, // 01C5 GETMET R23 R23 K36 + 0x58640047, // 01C6 LDCONST R25 K71 + 0x58680011, // 01C7 LDCONST R26 K17 + 0x7C5C0600, // 01C8 CALL R23 3 + 0x885C034A, // 01C9 GETMBR R23 R1 K74 + 0x8C5C2F4B, // 01CA GETMET R23 R23 K75 + 0x7C5C0200, // 01CB CALL R23 1 + 0x8C5C0D0A, // 01CC GETMET R23 R6 K10 + 0x7C5C0200, // 01CD CALL R23 1 + 0x8C602F0B, // 01CE GETMET R24 R23 K11 + 0x58680006, // 01CF LDCONST R26 K6 + 0x886C0D0C, // 01D0 GETMBR R27 R6 K12 + 0xB8720400, // 01D1 GETNGBL R28 K2 + 0x8870392E, // 01D2 GETMBR R28 R28 K46 + 0x7C600800, // 01D3 CALL R24 4 + 0x8C602F0B, // 01D4 GETMET R24 R23 K11 + 0x58680008, // 01D5 LDCONST R26 K8 + 0x886C0D0C, // 01D6 GETMBR R27 R6 K12 + 0x58700008, // 01D7 LDCONST R28 K8 + 0x7C600800, // 01D8 CALL R24 4 + 0x54620007, // 01D9 LDINT R24 8 + 0x900E0A18, // 01DA SETMBR R3 K5 R24 + 0x80042E00, // 01DB RET 1 R23 + 0x70020063, // 01DC JMP #0241 + 0x54260008, // 01DD LDINT R9 9 + 0x1C241009, // 01DE EQ R9 R8 R9 + 0x7826001E, // 01DF JMPF R9 #01FF + 0x8C240507, // 01E0 GETMET R9 R2 K7 + 0x582C0006, // 01E1 LDCONST R11 K6 + 0x7C240400, // 01E2 CALL R9 2 + 0x8C28034C, // 01E3 GETMET R10 R1 K76 + 0x5C301200, // 01E4 MOVE R12 R9 + 0x7C280400, // 01E5 CALL R10 2 + 0xB82A3E00, // 01E6 GETNGBL R10 K31 + 0x8C281524, // 01E7 GETMET R10 R10 K36 + 0x8C300B4D, // 01E8 GETMET R12 R5 K77 + 0x5838004E, // 01E9 LDCONST R14 K78 + 0x883C034A, // 01EA GETMBR R15 R1 K74 + 0x8C3C1F4F, // 01EB GETMET R15 R15 K79 + 0x7C3C0200, // 01EC CALL R15 1 + 0x8C3C1F3F, // 01ED GETMET R15 R15 K63 + 0x7C3C0200, // 01EE CALL R15 1 + 0x8C3C1F40, // 01EF GETMET R15 R15 K64 + 0x7C3C0200, // 01F0 CALL R15 1 + 0x8C3C1F26, // 01F1 GETMET R15 R15 K38 + 0x7C3C0200, // 01F2 CALL R15 1 + 0x60400008, // 01F3 GETGBL R16 G8 + 0x5C441200, // 01F4 MOVE R17 R9 + 0x7C400200, // 01F5 CALL R16 1 + 0x7C300800, // 01F6 CALL R12 4 + 0x5834000F, // 01F7 LDCONST R13 K15 + 0x7C280600, // 01F8 CALL R10 3 + 0xB82A0400, // 01F9 GETNGBL R10 K2 + 0x8828152E, // 01FA GETMBR R10 R10 K46 + 0x900E2E0A, // 01FB SETMBR R3 K23 R10 + 0x4C280000, // 01FC LDNIL R10 + 0x80041400, // 01FD RET 1 R10 + 0x70020041, // 01FE JMP #0241 + 0x54260009, // 01FF LDINT R9 10 + 0x1C241009, // 0200 EQ R9 R8 R9 + 0x7826003E, // 0201 JMPF R9 #0241 + 0x8C240507, // 0202 GETMET R9 R2 K7 + 0x582C0006, // 0203 LDCONST R11 K6 + 0x7C240400, // 0204 CALL R9 2 + 0x60280010, // 0205 GETGBL R10 G16 + 0x882C0115, // 0206 GETMBR R11 R0 K21 + 0x882C1750, // 0207 GETMBR R11 R11 K80 + 0x8C2C1751, // 0208 GETMET R11 R11 K81 + 0x7C2C0200, // 0209 CALL R11 1 + 0x7C280200, // 020A CALL R10 1 + 0xA802001D, // 020B EXBLK 0 #022A + 0x5C2C1400, // 020C MOVE R11 R10 + 0x7C2C0000, // 020D CALL R11 0 + 0x8C301752, // 020E GETMET R12 R11 K82 + 0x7C300200, // 020F CALL R12 1 + 0x1C301809, // 0210 EQ R12 R12 R9 + 0x78320015, // 0211 JMPF R12 #0228 + 0xB8323E00, // 0212 GETNGBL R12 K31 + 0x8C301924, // 0213 GETMET R12 R12 K36 + 0x8C38174F, // 0214 GETMET R14 R11 K79 + 0x7C380200, // 0215 CALL R14 1 + 0x8C381D3F, // 0216 GETMET R14 R14 K63 + 0x7C380200, // 0217 CALL R14 1 + 0x8C381D40, // 0218 GETMET R14 R14 K64 + 0x7C380200, // 0219 CALL R14 1 + 0x8C381D26, // 021A GETMET R14 R14 K38 + 0x7C380200, // 021B CALL R14 1 + 0x003AA60E, // 021C ADD R14 K83 R14 + 0x583C000F, // 021D LDCONST R15 K15 + 0x7C300600, // 021E CALL R12 3 + 0xB8323E00, // 021F GETNGBL R12 K31 + 0x8C301954, // 0220 GETMET R12 R12 K84 + 0x543A07CF, // 0221 LDINT R14 2000 + 0x843C0000, // 0222 CLOSURE R15 P0 + 0x7C300600, // 0223 CALL R12 3 + 0x50300200, // 0224 LDBOOL R12 1 0 + 0xA0000000, // 0225 CLOSE R0 + 0xA8040001, // 0226 EXBLK 1 1 + 0x80041800, // 0227 RET 1 R12 + 0xA0280000, // 0228 CLOSE R10 + 0x7001FFE1, // 0229 JMP #020C + 0x58280055, // 022A LDCONST R10 K85 + 0xAC280200, // 022B CATCH R10 1 0 + 0xB0080000, // 022C RAISE 2 R0 R0 + 0xB82A3E00, // 022D GETNGBL R10 K31 + 0x8C281524, // 022E GETMET R10 R10 K36 + 0x60300008, // 022F GETGBL R12 G8 + 0x5C341200, // 0230 MOVE R13 R9 + 0x7C300200, // 0231 CALL R12 1 + 0x0032AC0C, // 0232 ADD R12 K86 R12 + 0x00301957, // 0233 ADD R12 R12 K87 + 0x5834000F, // 0234 LDCONST R13 K15 + 0x7C280600, // 0235 CALL R10 3 + 0xB82A0400, // 0236 GETNGBL R10 K2 + 0x88281558, // 0237 GETMBR R10 R10 K88 + 0x900E2E0A, // 0238 SETMBR R3 K23 R10 + 0x60280008, // 0239 GETGBL R10 G8 + 0x5C2C1200, // 023A MOVE R11 R9 + 0x7C280200, // 023B CALL R10 1 + 0x002AB20A, // 023C ADD R10 K89 R10 + 0x900E480A, // 023D SETMBR R3 K36 R10 + 0x4C280000, // 023E LDNIL R10 + 0xA0000000, // 023F CLOSE R0 + 0x80041400, // 0240 RET 1 R10 + 0x7002009A, // 0241 JMP #02DD + 0x5426003B, // 0242 LDINT R9 60 + 0x1C240E09, // 0243 EQ R9 R7 R9 + 0x78260084, // 0244 JMPF R9 #02CA + 0x1C241106, // 0245 EQ R9 R8 K6 + 0x78260064, // 0246 JMPF R9 #02AC + 0x8C240507, // 0247 GETMET R9 R2 K7 + 0x582C0006, // 0248 LDCONST R11 K6 + 0x7C240400, // 0249 CALL R9 2 + 0x8C280507, // 024A GETMET R10 R2 K7 + 0x58300008, // 024B LDCONST R12 K8 + 0x7C280400, // 024C CALL R10 2 + 0x8C2C0507, // 024D GETMET R11 R2 K7 + 0x5834000F, // 024E LDCONST R13 K15 + 0x7C2C0400, // 024F CALL R11 2 + 0x8C300507, // 0250 GETMET R12 R2 K7 + 0x58380011, // 0251 LDCONST R14 K17 + 0x7C300400, // 0252 CALL R12 2 + 0x8C340507, // 0253 GETMET R13 R2 K7 + 0x543E0003, // 0254 LDINT R15 4 + 0x7C340400, // 0255 CALL R13 2 + 0xB83A3E00, // 0256 GETNGBL R14 K31 + 0x8C381D24, // 0257 GETMET R14 R14 K36 + 0x8C400B4D, // 0258 GETMET R16 R5 K77 + 0x5848005A, // 0259 LDCONST R18 K90 + 0x5C4C1200, // 025A MOVE R19 R9 + 0x8C501526, // 025B GETMET R20 R10 K38 + 0x7C500200, // 025C CALL R20 1 + 0x5C541600, // 025D MOVE R21 R11 + 0x5C581800, // 025E MOVE R22 R12 + 0x8C5C1B26, // 025F GETMET R23 R13 K38 + 0x7C5C0200, // 0260 CALL R23 1 + 0x7C400E00, // 0261 CALL R16 7 + 0x5844000F, // 0262 LDCONST R17 K15 + 0x7C380600, // 0263 CALL R14 3 + 0x4C380000, // 0264 LDNIL R14 + 0x1C38120E, // 0265 EQ R14 R9 R14 + 0x743A000B, // 0266 JMPT R14 #0273 + 0x4C380000, // 0267 LDNIL R14 + 0x1C38140E, // 0268 EQ R14 R10 R14 + 0x743A0008, // 0269 JMPT R14 #0273 + 0x4C380000, // 026A LDNIL R14 + 0x1C38160E, // 026B EQ R14 R11 R14 + 0x743A0005, // 026C JMPT R14 #0273 + 0x4C380000, // 026D LDNIL R14 + 0x1C38180E, // 026E EQ R14 R12 R14 + 0x743A0002, // 026F JMPT R14 #0273 + 0x4C380000, // 0270 LDNIL R14 + 0x1C381A0E, // 0271 EQ R14 R13 R14 + 0x783A0005, // 0272 JMPF R14 #0279 + 0xB83A0400, // 0273 GETNGBL R14 K2 + 0x88381D5B, // 0274 GETMBR R14 R14 K91 + 0x900E2E0E, // 0275 SETMBR R3 K23 R14 + 0x4C380000, // 0276 LDNIL R14 + 0xA0000000, // 0277 CLOSE R0 + 0x80041C00, // 0278 RET 1 R14 + 0x6038000C, // 0279 GETGBL R14 G12 + 0x5C3C1400, // 027A MOVE R15 R10 + 0x7C380200, // 027B CALL R14 1 + 0x543E001F, // 027C LDINT R15 32 + 0x54420040, // 027D LDINT R16 65 + 0x003C1E10, // 027E ADD R15 R15 R16 + 0x20381C0F, // 027F NE R14 R14 R15 + 0x743A000B, // 0280 JMPT R14 #028D + 0x6038000C, // 0281 GETGBL R14 G12 + 0x5C3C1A00, // 0282 MOVE R15 R13 + 0x7C380200, // 0283 CALL R14 1 + 0x543E000F, // 0284 LDINT R15 16 + 0x14381C0F, // 0285 LT R14 R14 R15 + 0x743A0005, // 0286 JMPT R14 #028D + 0x6038000C, // 0287 GETGBL R14 G12 + 0x5C3C1A00, // 0288 MOVE R15 R13 + 0x7C380200, // 0289 CALL R14 1 + 0x543E001F, // 028A LDINT R15 32 + 0x24381C0F, // 028B GT R14 R14 R15 + 0x783A0009, // 028C JMPF R14 #0297 + 0xB83A3E00, // 028D GETNGBL R14 K31 + 0x8C381D24, // 028E GETMET R14 R14 K36 + 0x5840005C, // 028F LDCONST R16 K92 + 0x7C380400, // 0290 CALL R14 2 + 0xB83A0400, // 0291 GETNGBL R14 K2 + 0x88381D5D, // 0292 GETMBR R14 R14 K93 + 0x900E2E0E, // 0293 SETMBR R3 K23 R14 + 0x4C380000, // 0294 LDNIL R14 + 0xA0000000, // 0295 CLOSE R0 + 0x80041C00, // 0296 RET 1 R14 + 0x543A001E, // 0297 LDINT R14 31 + 0x403A0C0E, // 0298 CONNECT R14 K6 R14 + 0x9438140E, // 0299 GETIDX R14 R10 R14 + 0x543E001F, // 029A LDINT R15 32 + 0x403C1F3B, // 029B CONNECT R15 R15 K59 + 0x943C140F, // 029C GETIDX R15 R10 R15 + 0x88400115, // 029D GETMBR R16 R0 K21 + 0x8C40215E, // 029E GETMET R16 R16 K94 + 0x5C481200, // 029F MOVE R18 R9 + 0x5C4C1800, // 02A0 MOVE R19 R12 + 0x5C501600, // 02A1 MOVE R20 R11 + 0x5C541A00, // 02A2 MOVE R21 R13 + 0x5C581C00, // 02A3 MOVE R22 R14 + 0x5C5C1E00, // 02A4 MOVE R23 R15 + 0x8C60035F, // 02A5 GETMET R24 R1 K95 + 0x7C600200, // 02A6 CALL R24 1 + 0x7C401000, // 02A7 CALL R16 8 + 0x50400200, // 02A8 LDBOOL R16 1 0 + 0xA0000000, // 02A9 CLOSE R0 + 0x80042000, // 02AA RET 1 R16 + 0x7002001C, // 02AB JMP #02C9 + 0x1C241108, // 02AC EQ R9 R8 K8 + 0x78260012, // 02AD JMPF R9 #02C1 + 0x8C240507, // 02AE GETMET R9 R2 K7 + 0x582C0006, // 02AF LDCONST R11 K6 + 0x7C240400, // 02B0 CALL R9 2 + 0xB82A3E00, // 02B1 GETNGBL R10 K31 + 0x8C281524, // 02B2 GETMET R10 R10 K36 + 0x60300008, // 02B3 GETGBL R12 G8 + 0x5C341200, // 02B4 MOVE R13 R9 + 0x7C300200, // 02B5 CALL R12 1 + 0x0032C00C, // 02B6 ADD R12 K96 R12 + 0x5834000F, // 02B7 LDCONST R13 K15 + 0x7C280600, // 02B8 CALL R10 3 + 0x88280115, // 02B9 GETMBR R10 R0 K21 + 0x8C281561, // 02BA GETMET R10 R10 K97 + 0x5C301200, // 02BB MOVE R12 R9 + 0x7C280400, // 02BC CALL R10 2 + 0x50280200, // 02BD LDBOOL R10 1 0 + 0xA0000000, // 02BE CLOSE R0 + 0x80041400, // 02BF RET 1 R10 + 0x70020007, // 02C0 JMP #02C9 + 0x1C24110F, // 02C1 EQ R9 R8 K15 + 0x78260005, // 02C2 JMPF R9 #02C9 + 0x88240115, // 02C3 GETMBR R9 R0 K21 + 0x8C241362, // 02C4 GETMET R9 R9 K98 + 0x7C240200, // 02C5 CALL R9 1 + 0x50240200, // 02C6 LDBOOL R9 1 0 + 0xA0000000, // 02C7 CLOSE R0 + 0x80041200, // 02C8 RET 1 R9 + 0x70020012, // 02C9 JMP #02DD + 0x54260029, // 02CA LDINT R9 42 + 0x1C240E09, // 02CB EQ R9 R7 R9 + 0x78260005, // 02CC JMPF R9 #02D3 + 0x1C241106, // 02CD EQ R9 R8 K6 + 0x78260002, // 02CE JMPF R9 #02D2 + 0x50240200, // 02CF LDBOOL R9 1 0 + 0xA0000000, // 02D0 CLOSE R0 + 0x80041200, // 02D1 RET 1 R9 + 0x70020009, // 02D2 JMP #02DD + 0x60240003, // 02D3 GETGBL R9 G3 + 0x5C280000, // 02D4 MOVE R10 R0 + 0x7C240200, // 02D5 CALL R9 1 + 0x8C241363, // 02D6 GETMET R9 R9 K99 + 0x5C2C0200, // 02D7 MOVE R11 R1 + 0x5C300400, // 02D8 MOVE R12 R2 + 0x5C340600, // 02D9 MOVE R13 R3 + 0x7C240800, // 02DA CALL R9 4 + 0xA0000000, // 02DB CLOSE R0 + 0x80041200, // 02DC RET 1 R9 + 0xA0000000, // 02DD CLOSE R0 + 0x80000000, // 02DE RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Root +********************************************************************/ +extern const bclass be_class_Matter_Plugin; +be_local_class(Matter_Plugin_Root, + 0, + &be_class_Matter_Plugin, + be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Root_read_attribute_closure) }, + { be_const_key_weak(write_attribute, -1), be_const_closure(Matter_Plugin_Root_write_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(22, -1), be_const_int(1) }, + })) ) } )) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Root_init_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(13, + ( (struct bmapnode*) &(const bmapnode[]) { + { 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(40, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(14, + ( (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(6), + be_const_int(7), + be_const_int(8), + be_const_int(9), + be_const_int(10), + be_const_int(15), + 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_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, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + })) ) } )) }, + { be_const_key_int(43, -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(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_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(invoke_request, -1), be_const_closure(Matter_Plugin_Root_invoke_request_closure) }, + })), + be_str_weak(Matter_Plugin_Root) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Root_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Root); + be_setglobal(vm, "Matter_Plugin_Root"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Temp_Sensor.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Temp_Sensor.h new file mode 100644 index 000000000..0c91b56c3 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Temp_Sensor.h @@ -0,0 +1,295 @@ +/* Solidification of Matter_Plugin_Temp_Sensor.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Temp_Sensor; + +/******************************************************************** +** Solidified function: get_temperature +********************************************************************/ +be_local_closure(Matter_Plugin_Temp_Sensor_get_temperature, /* 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(shadow_temperature), + }), + be_str_weak(get_temperature), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Plugin_Temp_Sensor_every_second, /* 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(get_temperature), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_sensors +********************************************************************/ +be_local_closure(Matter_Plugin_Temp_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(match), + /* K2 */ be_nested_str_weak(shadow_temperature), + /* K3 */ be_nested_str_weak(attribute_updated), + /* K4 */ be_const_int(0), + }), + be_str_weak(parse_sensors), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0011, // 0001 JMPF R2 #0014 + 0x6008000A, // 0002 GETGBL R2 G10 + 0x880C0100, // 0003 GETMBR R3 R0 K0 + 0x8C0C0701, // 0004 GETMET R3 R3 K1 + 0x5C140200, // 0005 MOVE R5 R1 + 0x7C0C0400, // 0006 CALL R3 2 + 0x7C080200, // 0007 CALL R2 1 + 0x4C0C0000, // 0008 LDNIL R3 + 0x200C0403, // 0009 NE R3 R2 R3 + 0x780E0008, // 000A JMPF R3 #0014 + 0x880C0102, // 000B GETMBR R3 R0 K2 + 0x200C0403, // 000C NE R3 R2 R3 + 0x780E0004, // 000D JMPF R3 #0013 + 0x8C0C0103, // 000E GETMET R3 R0 K3 + 0x4C140000, // 000F LDNIL R5 + 0x541A0401, // 0010 LDINT R6 1026 + 0x581C0004, // 0011 LDCONST R7 K4 + 0x7C0C0800, // 0012 CALL R3 4 + 0x90020402, // 0013 SETMBR R0 K2 R2 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Temp_Sensor_init, /* name */ + be_nested_proto( + 8, /* 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_weak(init), + /* K1 */ be_nested_str_weak(tasmota_sensor_filter), + /* K2 */ be_nested_str_weak(tasmota_sensor_matcher), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(Rule_Matcher), + /* K5 */ be_nested_str_weak(parse), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* 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 + 0x7C100600, // 0006 CALL R4 3 + 0x90020203, // 0007 SETMBR R0 K1 R3 + 0xB8120600, // 0008 GETNGBL R4 K3 + 0x88100904, // 0009 GETMBR R4 R4 K4 + 0x8C100905, // 000A GETMET R4 R4 K5 + 0x5C180600, // 000B MOVE R6 R3 + 0x7C100400, // 000C CALL R4 2 + 0x90020404, // 000D SETMBR R0 K2 R4 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Temp_Sensor_read_attribute, /* name */ + be_nested_proto( + 13, /* 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_nested_str_weak(string), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(shadow_temperature), + /* K7 */ be_nested_str_weak(create_TLV), + /* K8 */ be_nested_str_weak(I2), + /* K9 */ be_nested_str_weak(NULL), + /* K10 */ be_const_int(1), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[55]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xB8120200, // 0001 GETNGBL R4 K1 + 0x88100902, // 0002 GETMBR R4 R4 K2 + 0x88140503, // 0003 GETMBR R5 R2 K3 + 0x88180504, // 0004 GETMBR R6 R2 K4 + 0x541E0401, // 0005 LDINT R7 1026 + 0x1C1C0A07, // 0006 EQ R7 R5 R7 + 0x781E0025, // 0007 JMPF R7 #002E + 0x1C1C0D05, // 0008 EQ R7 R6 K5 + 0x781E0013, // 0009 JMPF R7 #001E + 0x881C0106, // 000A GETMBR R7 R0 K6 + 0x4C200000, // 000B LDNIL R8 + 0x201C0E08, // 000C NE R7 R7 R8 + 0x781E0009, // 000D JMPF R7 #0018 + 0x8C1C0907, // 000E GETMET R7 R4 K7 + 0x88240908, // 000F GETMBR R9 R4 K8 + 0x60280009, // 0010 GETGBL R10 G9 + 0x882C0106, // 0011 GETMBR R11 R0 K6 + 0x54320063, // 0012 LDINT R12 100 + 0x082C160C, // 0013 MUL R11 R11 R12 + 0x7C280200, // 0014 CALL R10 1 + 0x7C1C0600, // 0015 CALL R7 3 + 0x80040E00, // 0016 RET 1 R7 + 0x70020004, // 0017 JMP #001D + 0x8C1C0907, // 0018 GETMET R7 R4 K7 + 0x88240909, // 0019 GETMBR R9 R4 K9 + 0x4C280000, // 001A LDNIL R10 + 0x7C1C0600, // 001B CALL R7 3 + 0x80040E00, // 001C RET 1 R7 + 0x7002000E, // 001D JMP #002D + 0x1C1C0D0A, // 001E EQ R7 R6 K10 + 0x781E0005, // 001F JMPF R7 #0026 + 0x8C1C0907, // 0020 GETMET R7 R4 K7 + 0x88240908, // 0021 GETMBR R9 R4 K8 + 0x5429EC77, // 0022 LDINT R10 -5000 + 0x7C1C0600, // 0023 CALL R7 3 + 0x80040E00, // 0024 RET 1 R7 + 0x70020006, // 0025 JMP #002D + 0x1C1C0D0B, // 0026 EQ R7 R6 K11 + 0x781E0004, // 0027 JMPF R7 #002D + 0x8C1C0907, // 0028 GETMET R7 R4 K7 + 0x88240908, // 0029 GETMBR R9 R4 K8 + 0x542A3A97, // 002A LDINT R10 15000 + 0x7C1C0600, // 002B CALL R7 3 + 0x80040E00, // 002C RET 1 R7 + 0x70020007, // 002D JMP #0036 + 0x601C0003, // 002E GETGBL R7 G3 + 0x5C200000, // 002F MOVE R8 R0 + 0x7C1C0200, // 0030 CALL R7 1 + 0x8C1C0F0C, // 0031 GETMET R7 R7 K12 + 0x5C240200, // 0032 MOVE R9 R1 + 0x5C280400, // 0033 MOVE R10 R2 + 0x7C1C0600, // 0034 CALL R7 3 + 0x80040E00, // 0035 RET 1 R7 + 0x80000000, // 0036 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Temp_Sensor +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Device; +be_local_class(Matter_Plugin_Temp_Sensor, + 3, + &be_class_Matter_Plugin_Device, + be_nested_map(10, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(TYPES, 7), 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, -1), be_const_closure(Matter_Plugin_Temp_Sensor_read_attribute_closure) }, + { be_const_key_weak(get_temperature, 1), be_const_closure(Matter_Plugin_Temp_Sensor_get_temperature_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Temp_Sensor_init_closure) }, + { be_const_key_weak(CLUSTERS, 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(1026, -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_weak(every_second, 3), be_const_closure(Matter_Plugin_Temp_Sensor_every_second_closure) }, + { be_const_key_weak(tasmota_sensor_filter, 8), be_const_var(0) }, + { be_const_key_weak(tasmota_sensor_matcher, -1), be_const_var(1) }, + { be_const_key_weak(parse_sensors, -1), be_const_closure(Matter_Plugin_Temp_Sensor_parse_sensors_closure) }, + { be_const_key_weak(shadow_temperature, -1), be_const_var(2) }, + })), + be_str_weak(Matter_Plugin_Temp_Sensor) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Temp_Sensor_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Temp_Sensor); + be_setglobal(vm, "Matter_Plugin_Temp_Sensor"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h deleted file mode 100644 index 10592a17a..000000000 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_core.h +++ /dev/null @@ -1,1606 +0,0 @@ -/* Solidification of Matter_Plugin_core.h */ -/********************************************************************\ -* Generated code, don't edit * -\********************************************************************/ -#include "be_constobj.h" - -extern const bclass be_class_Matter_Plugin_core; - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_core_invoke_request, /* name */ - be_nested_proto( - 29, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[73]) { /* 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_nested_str_weak(session), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(findsubval), - /* K8 */ be_const_int(1), - /* K9 */ be_nested_str_weak(breadcrumb), - /* K10 */ be_nested_str_weak(Matter_TLV_struct), - /* K11 */ be_nested_str_weak(add_TLV), - /* K12 */ be_nested_str_weak(U1), - /* K13 */ be_nested_str_weak(UTF1), - /* K14 */ be_nested_str_weak(), - /* K15 */ be_const_int(2), - /* K16 */ be_nested_str_weak(XX), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(set_no_expiration), - /* K19 */ be_nested_str_weak(device), - /* K20 */ be_nested_str_weak(start_commissioning_complete_deferred), - /* K21 */ be_nested_str_weak(status), - /* K22 */ be_nested_str_weak(UNSUPPORTED_COMMAND), - /* K23 */ be_nested_str_weak(B2), - /* K24 */ be_nested_str_weak(DAC_Cert_FFF1_8000), - /* K25 */ be_nested_str_weak(PAI_Cert_FFF1), - /* K26 */ be_nested_str_weak(CD_FFF1_8000), - /* K27 */ be_nested_str_weak(B1), - /* K28 */ be_nested_str_weak(U4), - /* K29 */ be_nested_str_weak(tasmota), - /* K30 */ be_nested_str_weak(rtc), - /* K31 */ be_nested_str_weak(utc), - /* K32 */ be_nested_str_weak(encode), - /* K33 */ be_nested_str_weak(get_ac), - /* K34 */ be_nested_str_weak(log), - /* K35 */ be_nested_str_weak(MTR_X3A_X20attestation_tbs_X3D), - /* K36 */ be_nested_str_weak(tohex), - /* K37 */ be_nested_str_weak(EC_P256), - /* K38 */ be_nested_str_weak(ecdsa_sign_sha256), - /* K39 */ be_nested_str_weak(DAC_Priv_FFF1_8000), - /* K40 */ be_nested_str_weak(gen_CSR), - /* K41 */ be_nested_str_weak(MTR_X3A_X20nocsr_tbs_X3D), - /* K42 */ be_nested_str_weak(set_ca), - /* K43 */ be_nested_str_weak(MTR_X3A_X20received_X20ca_root_X3D), - /* K44 */ be_nested_str_weak(SUCCESS), - /* K45 */ be_nested_str_weak(get_ca), - /* K46 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20AdNOC_X20without_X20CA), - /* K47 */ be_nested_str_weak(set_noc), - /* K48 */ be_nested_str_weak(set_ipk_epoch_key), - /* K49 */ be_nested_str_weak(admin_subject), - /* K50 */ be_nested_str_weak(admin_vendor), - /* K51 */ be_nested_str_weak(parse), - /* K52 */ be_nested_str_weak(findsub), - /* K53 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20no_X20fabricid_X20nor_X20deviceid_X20in_X20NOC_X20certificate), - /* K54 */ be_nested_str_weak(int), - /* K55 */ be_nested_str_weak(int64), - /* K56 */ be_nested_str_weak(tobytes), - /* K57 */ be_const_int(2147483647), - /* K58 */ be_nested_str_weak(fromstring), - /* K59 */ be_nested_str_weak(CompressedFabric), - /* K60 */ be_nested_str_weak(HKDF_SHA256), - /* K61 */ be_nested_str_weak(copy), - /* K62 */ be_nested_str_weak(reverse), - /* K63 */ be_nested_str_weak(derive), - /* K64 */ be_nested_str_weak(set_fabric_device), - /* K65 */ be_nested_str_weak(start_operational_dicovery_deferred), - /* K66 */ be_nested_str_weak(set_fabric_label), - /* K67 */ be_nested_str_weak(sessions), - /* K68 */ be_nested_str_weak(sessions_active), - /* K69 */ be_nested_str_weak(MTR_X3A_X20removing_X20fabric_X20), - /* K70 */ be_nested_str_weak(fabric), - /* K71 */ be_nested_str_weak(remove_session), - /* K72 */ be_nested_str_weak(save), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[495]) { /* 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 - 0x88200305, // 0005 GETMBR R8 R1 K5 - 0x5426002F, // 0006 LDINT R9 48 - 0x1C240C09, // 0007 EQ R9 R6 R9 - 0x78260050, // 0008 JMPF R9 #005A - 0x1C240F06, // 0009 EQ R9 R7 K6 - 0x78260017, // 000A JMPF R9 #0023 - 0x8C240507, // 000B GETMET R9 R2 K7 - 0x582C0006, // 000C LDCONST R11 K6 - 0x54320383, // 000D LDINT R12 900 - 0x7C240600, // 000E CALL R9 3 - 0x8C280507, // 000F GETMET R10 R2 K7 - 0x58300008, // 0010 LDCONST R12 K8 - 0x58340006, // 0011 LDCONST R13 K6 - 0x7C280600, // 0012 CALL R10 3 - 0x9022120A, // 0013 SETMBR R8 K9 R10 - 0x8C2C0B0A, // 0014 GETMET R11 R5 K10 - 0x7C2C0200, // 0015 CALL R11 1 - 0x8C30170B, // 0016 GETMET R12 R11 K11 - 0x58380006, // 0017 LDCONST R14 K6 - 0x883C0B0C, // 0018 GETMBR R15 R5 K12 - 0x58400006, // 0019 LDCONST R16 K6 - 0x7C300800, // 001A CALL R12 4 - 0x8C30170B, // 001B GETMET R12 R11 K11 - 0x58380008, // 001C LDCONST R14 K8 - 0x883C0B0D, // 001D GETMBR R15 R5 K13 - 0x5840000E, // 001E LDCONST R16 K14 - 0x7C300800, // 001F CALL R12 4 - 0x900E0908, // 0020 SETMBR R3 K4 K8 - 0x80041600, // 0021 RET 1 R11 - 0x70020035, // 0022 JMP #0059 - 0x1C240F0F, // 0023 EQ R9 R7 K15 - 0x7826001A, // 0024 JMPF R9 #0040 - 0x8C240507, // 0025 GETMET R9 R2 K7 - 0x582C0006, // 0026 LDCONST R11 K6 - 0x7C240400, // 0027 CALL R9 2 - 0x8C280507, // 0028 GETMET R10 R2 K7 - 0x58300008, // 0029 LDCONST R12 K8 - 0x58340010, // 002A LDCONST R13 K16 - 0x7C280600, // 002B CALL R10 3 - 0x8C2C0507, // 002C GETMET R11 R2 K7 - 0x5834000F, // 002D LDCONST R13 K15 - 0x58380006, // 002E LDCONST R14 K6 - 0x7C2C0600, // 002F CALL R11 3 - 0x9022120B, // 0030 SETMBR R8 K9 R11 - 0x8C300B0A, // 0031 GETMET R12 R5 K10 - 0x7C300200, // 0032 CALL R12 1 - 0x8C34190B, // 0033 GETMET R13 R12 K11 - 0x583C0006, // 0034 LDCONST R15 K6 - 0x88400B0C, // 0035 GETMBR R16 R5 K12 - 0x58440006, // 0036 LDCONST R17 K6 - 0x7C340800, // 0037 CALL R13 4 - 0x8C34190B, // 0038 GETMET R13 R12 K11 - 0x583C0008, // 0039 LDCONST R15 K8 - 0x88400B0D, // 003A GETMBR R16 R5 K13 - 0x5844000E, // 003B LDCONST R17 K14 - 0x7C340800, // 003C CALL R13 4 - 0x900E0911, // 003D SETMBR R3 K4 K17 - 0x80041800, // 003E RET 1 R12 - 0x70020018, // 003F JMP #0059 - 0x54260003, // 0040 LDINT R9 4 - 0x1C240E09, // 0041 EQ R9 R7 R9 - 0x78260015, // 0042 JMPF R9 #0059 - 0x90221306, // 0043 SETMBR R8 K9 K6 - 0x8C241112, // 0044 GETMET R9 R8 K18 - 0x7C240200, // 0045 CALL R9 1 - 0x8C240B0A, // 0046 GETMET R9 R5 K10 - 0x7C240200, // 0047 CALL R9 1 - 0x8C28130B, // 0048 GETMET R10 R9 K11 - 0x58300006, // 0049 LDCONST R12 K6 - 0x88340B0C, // 004A GETMBR R13 R5 K12 - 0x58380006, // 004B LDCONST R14 K6 - 0x7C280800, // 004C CALL R10 4 - 0x8C28130B, // 004D GETMET R10 R9 K11 - 0x58300008, // 004E LDCONST R12 K8 - 0x88340B0D, // 004F GETMBR R13 R5 K13 - 0x5838000E, // 0050 LDCONST R14 K14 - 0x7C280800, // 0051 CALL R10 4 - 0x542A0004, // 0052 LDINT R10 5 - 0x900E080A, // 0053 SETMBR R3 K4 R10 - 0x88280113, // 0054 GETMBR R10 R0 K19 - 0x8C281514, // 0055 GETMET R10 R10 K20 - 0x5C301000, // 0056 MOVE R12 R8 - 0x7C280400, // 0057 CALL R10 2 - 0x80041200, // 0058 RET 1 R9 - 0x70020193, // 0059 JMP #01EE - 0x5426003D, // 005A LDINT R9 62 - 0x1C240C09, // 005B EQ R9 R6 R9 - 0x78260190, // 005C JMPF R9 #01EE - 0x1C240F0F, // 005D EQ R9 R7 K15 - 0x7826001D, // 005E JMPF R9 #007D - 0x8C240507, // 005F GETMET R9 R2 K7 - 0x582C0006, // 0060 LDCONST R11 K6 - 0x7C240400, // 0061 CALL R9 2 - 0x20281308, // 0062 NE R10 R9 K8 - 0x782A0006, // 0063 JMPF R10 #006B - 0x2028130F, // 0064 NE R10 R9 K15 - 0x782A0004, // 0065 JMPF R10 #006B - 0xB82A0200, // 0066 GETNGBL R10 K1 - 0x88281516, // 0067 GETMBR R10 R10 K22 - 0x900E2A0A, // 0068 SETMBR R3 K21 R10 - 0x4C280000, // 0069 LDNIL R10 - 0x80041400, // 006A RET 1 R10 - 0x8C280B0A, // 006B GETMET R10 R5 K10 - 0x7C280200, // 006C CALL R10 1 - 0x8C2C150B, // 006D GETMET R11 R10 K11 - 0x58340006, // 006E LDCONST R13 K6 - 0x88380B17, // 006F GETMBR R14 R5 K23 - 0x1C3C1308, // 0070 EQ R15 R9 K8 - 0x783E0003, // 0071 JMPF R15 #0076 - 0xB83E0200, // 0072 GETNGBL R15 K1 - 0x8C3C1F18, // 0073 GETMET R15 R15 K24 - 0x7C3C0200, // 0074 CALL R15 1 - 0x70020002, // 0075 JMP #0079 - 0xB83E0200, // 0076 GETNGBL R15 K1 - 0x8C3C1F19, // 0077 GETMET R15 R15 K25 - 0x7C3C0200, // 0078 CALL R15 1 - 0x7C2C0800, // 0079 CALL R11 4 - 0x900E0911, // 007A SETMBR R3 K4 K17 - 0x80041400, // 007B RET 1 R10 - 0x70020170, // 007C JMP #01EE - 0x1C240F06, // 007D EQ R9 R7 K6 - 0x78260044, // 007E JMPF R9 #00C4 - 0x8C240507, // 007F GETMET R9 R2 K7 - 0x582C0006, // 0080 LDCONST R11 K6 - 0x7C240400, // 0081 CALL R9 2 - 0x6028000C, // 0082 GETGBL R10 G12 - 0x5C2C1200, // 0083 MOVE R11 R9 - 0x7C280200, // 0084 CALL R10 1 - 0x542E001F, // 0085 LDINT R11 32 - 0x2028140B, // 0086 NE R10 R10 R11 - 0x782A0001, // 0087 JMPF R10 #008A - 0x4C280000, // 0088 LDNIL R10 - 0x80041400, // 0089 RET 1 R10 - 0x900E0908, // 008A SETMBR R3 K4 K8 - 0x8C280B0A, // 008B GETMET R10 R5 K10 - 0x7C280200, // 008C CALL R10 1 - 0x8C2C150B, // 008D GETMET R11 R10 K11 - 0x58340008, // 008E LDCONST R13 K8 - 0x88380B17, // 008F GETMBR R14 R5 K23 - 0xB83E0200, // 0090 GETNGBL R15 K1 - 0x8C3C1F1A, // 0091 GETMET R15 R15 K26 - 0x7C3C0200, // 0092 CALL R15 1 - 0x7C2C0800, // 0093 CALL R11 4 - 0x8C2C150B, // 0094 GETMET R11 R10 K11 - 0x5834000F, // 0095 LDCONST R13 K15 - 0x88380B1B, // 0096 GETMBR R14 R5 K27 - 0x5C3C1200, // 0097 MOVE R15 R9 - 0x7C2C0800, // 0098 CALL R11 4 - 0x8C2C150B, // 0099 GETMET R11 R10 K11 - 0x58340011, // 009A LDCONST R13 K17 - 0x88380B1C, // 009B GETMBR R14 R5 K28 - 0xB83E3A00, // 009C GETNGBL R15 K29 - 0x8C3C1F1E, // 009D GETMET R15 R15 K30 - 0x7C3C0200, // 009E CALL R15 1 - 0x943C1F1F, // 009F GETIDX R15 R15 K31 - 0x7C2C0800, // 00A0 CALL R11 4 - 0x8C2C1520, // 00A1 GETMET R11 R10 K32 - 0x7C2C0200, // 00A2 CALL R11 1 - 0x8C301121, // 00A3 GETMET R12 R8 K33 - 0x7C300200, // 00A4 CALL R12 1 - 0x0034160C, // 00A5 ADD R13 R11 R12 - 0xB83A3A00, // 00A6 GETNGBL R14 K29 - 0x8C381D22, // 00A7 GETMET R14 R14 K34 - 0x8C401B24, // 00A8 GETMET R16 R13 K36 - 0x7C400200, // 00A9 CALL R16 1 - 0x00424610, // 00AA ADD R16 K35 R16 - 0x58440011, // 00AB LDCONST R17 K17 - 0x7C380600, // 00AC CALL R14 3 - 0x8C380925, // 00AD GETMET R14 R4 K37 - 0x7C380200, // 00AE CALL R14 1 - 0x8C381D26, // 00AF GETMET R14 R14 K38 - 0xB8420200, // 00B0 GETNGBL R16 K1 - 0x8C402127, // 00B1 GETMET R16 R16 K39 - 0x7C400200, // 00B2 CALL R16 1 - 0x5C441A00, // 00B3 MOVE R17 R13 - 0x7C380600, // 00B4 CALL R14 3 - 0x8C3C0B0A, // 00B5 GETMET R15 R5 K10 - 0x7C3C0200, // 00B6 CALL R15 1 - 0x8C401F0B, // 00B7 GETMET R16 R15 K11 - 0x58480006, // 00B8 LDCONST R18 K6 - 0x884C0B17, // 00B9 GETMBR R19 R5 K23 - 0x5C501600, // 00BA MOVE R20 R11 - 0x7C400800, // 00BB CALL R16 4 - 0x8C401F0B, // 00BC GETMET R16 R15 K11 - 0x58480008, // 00BD LDCONST R18 K8 - 0x884C0B1B, // 00BE GETMBR R19 R5 K27 - 0x5C501C00, // 00BF MOVE R20 R14 - 0x7C400800, // 00C0 CALL R16 4 - 0x900E0908, // 00C1 SETMBR R3 K4 K8 - 0x80041E00, // 00C2 RET 1 R15 - 0x70020129, // 00C3 JMP #01EE - 0x54260003, // 00C4 LDINT R9 4 - 0x1C240E09, // 00C5 EQ R9 R7 R9 - 0x78260040, // 00C6 JMPF R9 #0108 - 0x8C240507, // 00C7 GETMET R9 R2 K7 - 0x582C0006, // 00C8 LDCONST R11 K6 - 0x7C240400, // 00C9 CALL R9 2 - 0x6028000C, // 00CA GETGBL R10 G12 - 0x5C2C1200, // 00CB MOVE R11 R9 - 0x7C280200, // 00CC CALL R10 1 - 0x542E001F, // 00CD LDINT R11 32 - 0x2028140B, // 00CE NE R10 R10 R11 - 0x782A0001, // 00CF JMPF R10 #00D2 - 0x4C280000, // 00D0 LDNIL R10 - 0x80041400, // 00D1 RET 1 R10 - 0x8C280507, // 00D2 GETMET R10 R2 K7 - 0x58300008, // 00D3 LDCONST R12 K8 - 0x50340000, // 00D4 LDBOOL R13 0 0 - 0x7C280600, // 00D5 CALL R10 3 - 0x8C2C1128, // 00D6 GETMET R11 R8 K40 - 0x7C2C0200, // 00D7 CALL R11 1 - 0x8C300B0A, // 00D8 GETMET R12 R5 K10 - 0x7C300200, // 00D9 CALL R12 1 - 0x8C34190B, // 00DA GETMET R13 R12 K11 - 0x583C0008, // 00DB LDCONST R15 K8 - 0x88400B17, // 00DC GETMBR R16 R5 K23 - 0x5C441600, // 00DD MOVE R17 R11 - 0x7C340800, // 00DE CALL R13 4 - 0x8C34190B, // 00DF GETMET R13 R12 K11 - 0x583C000F, // 00E0 LDCONST R15 K15 - 0x88400B1B, // 00E1 GETMBR R16 R5 K27 - 0x5C441200, // 00E2 MOVE R17 R9 - 0x7C340800, // 00E3 CALL R13 4 - 0x8C341920, // 00E4 GETMET R13 R12 K32 - 0x7C340200, // 00E5 CALL R13 1 - 0x8C381121, // 00E6 GETMET R14 R8 K33 - 0x7C380200, // 00E7 CALL R14 1 - 0x00381A0E, // 00E8 ADD R14 R13 R14 - 0xB83E3A00, // 00E9 GETNGBL R15 K29 - 0x8C3C1F22, // 00EA GETMET R15 R15 K34 - 0x8C441D24, // 00EB GETMET R17 R14 K36 - 0x7C440200, // 00EC CALL R17 1 - 0x00465211, // 00ED ADD R17 K41 R17 - 0x58480011, // 00EE LDCONST R18 K17 - 0x7C3C0600, // 00EF CALL R15 3 - 0x8C3C0925, // 00F0 GETMET R15 R4 K37 - 0x7C3C0200, // 00F1 CALL R15 1 - 0x8C3C1F26, // 00F2 GETMET R15 R15 K38 - 0xB8460200, // 00F3 GETNGBL R17 K1 - 0x8C442327, // 00F4 GETMET R17 R17 K39 - 0x7C440200, // 00F5 CALL R17 1 - 0x5C481C00, // 00F6 MOVE R18 R14 - 0x7C3C0600, // 00F7 CALL R15 3 - 0x8C400B0A, // 00F8 GETMET R16 R5 K10 - 0x7C400200, // 00F9 CALL R16 1 - 0x8C44210B, // 00FA GETMET R17 R16 K11 - 0x584C0006, // 00FB LDCONST R19 K6 - 0x88500B17, // 00FC GETMBR R20 R5 K23 - 0x5C541A00, // 00FD MOVE R21 R13 - 0x7C440800, // 00FE CALL R17 4 - 0x8C44210B, // 00FF GETMET R17 R16 K11 - 0x584C0008, // 0100 LDCONST R19 K8 - 0x88500B1B, // 0101 GETMBR R20 R5 K27 - 0x5C541E00, // 0102 MOVE R21 R15 - 0x7C440800, // 0103 CALL R17 4 - 0x54460004, // 0104 LDINT R17 5 - 0x900E0811, // 0105 SETMBR R3 K4 R17 - 0x80042000, // 0106 RET 1 R16 - 0x700200E5, // 0107 JMP #01EE - 0x5426000A, // 0108 LDINT R9 11 - 0x1C240E09, // 0109 EQ R9 R7 R9 - 0x78260012, // 010A JMPF R9 #011E - 0x8C240507, // 010B GETMET R9 R2 K7 - 0x582C0006, // 010C LDCONST R11 K6 - 0x7C240400, // 010D CALL R9 2 - 0x8C28112A, // 010E GETMET R10 R8 K42 - 0x5C301200, // 010F MOVE R12 R9 - 0x7C280400, // 0110 CALL R10 2 - 0xB82A3A00, // 0111 GETNGBL R10 K29 - 0x8C281522, // 0112 GETMET R10 R10 K34 - 0x8C301324, // 0113 GETMET R12 R9 K36 - 0x7C300200, // 0114 CALL R12 1 - 0x0032560C, // 0115 ADD R12 K43 R12 - 0x58340011, // 0116 LDCONST R13 K17 - 0x7C280600, // 0117 CALL R10 3 - 0xB82A0200, // 0118 GETNGBL R10 K1 - 0x8828152C, // 0119 GETMBR R10 R10 K44 - 0x900E2A0A, // 011A SETMBR R3 K21 R10 - 0x4C280000, // 011B LDNIL R10 - 0x80041400, // 011C RET 1 R10 - 0x700200CF, // 011D JMP #01EE - 0x54260005, // 011E LDINT R9 6 - 0x1C240E09, // 011F EQ R9 R7 R9 - 0x78260091, // 0120 JMPF R9 #01B3 - 0x8C240507, // 0121 GETMET R9 R2 K7 - 0x582C0006, // 0122 LDCONST R11 K6 - 0x7C240400, // 0123 CALL R9 2 - 0x8C280507, // 0124 GETMET R10 R2 K7 - 0x58300008, // 0125 LDCONST R12 K8 - 0x7C280400, // 0126 CALL R10 2 - 0x8C2C0507, // 0127 GETMET R11 R2 K7 - 0x5834000F, // 0128 LDCONST R13 K15 - 0x7C2C0400, // 0129 CALL R11 2 - 0x8C300507, // 012A GETMET R12 R2 K7 - 0x58380011, // 012B LDCONST R14 K17 - 0x7C300400, // 012C CALL R12 2 - 0x8C340507, // 012D GETMET R13 R2 K7 - 0x543E0003, // 012E LDINT R15 4 - 0x7C340400, // 012F CALL R13 2 - 0x8C38112D, // 0130 GETMET R14 R8 K45 - 0x7C380200, // 0131 CALL R14 1 - 0x4C3C0000, // 0132 LDNIL R15 - 0x1C381C0F, // 0133 EQ R14 R14 R15 - 0x783A0006, // 0134 JMPF R14 #013C - 0xB83A3A00, // 0135 GETNGBL R14 K29 - 0x8C381D22, // 0136 GETMET R14 R14 K34 - 0x5840002E, // 0137 LDCONST R16 K46 - 0x5844000F, // 0138 LDCONST R17 K15 - 0x7C380600, // 0139 CALL R14 3 - 0x4C380000, // 013A LDNIL R14 - 0x80041C00, // 013B RET 1 R14 - 0x8C38112F, // 013C GETMET R14 R8 K47 - 0x5C401200, // 013D MOVE R16 R9 - 0x5C441400, // 013E MOVE R17 R10 - 0x7C380600, // 013F CALL R14 3 - 0x8C381130, // 0140 GETMET R14 R8 K48 - 0x5C401600, // 0141 MOVE R16 R11 - 0x7C380400, // 0142 CALL R14 2 - 0x9022620C, // 0143 SETMBR R8 K49 R12 - 0x9022640D, // 0144 SETMBR R8 K50 R13 - 0xB83A0200, // 0145 GETNGBL R14 K1 - 0x88381D02, // 0146 GETMBR R14 R14 K2 - 0x8C381D33, // 0147 GETMET R14 R14 K51 - 0x5C401200, // 0148 MOVE R16 R9 - 0x7C380400, // 0149 CALL R14 2 - 0x8C3C1D34, // 014A GETMET R15 R14 K52 - 0x54460005, // 014B LDINT R17 6 - 0x7C3C0400, // 014C CALL R15 2 - 0x8C401F07, // 014D GETMET R16 R15 K7 - 0x544A0014, // 014E LDINT R18 21 - 0x7C400400, // 014F CALL R16 2 - 0x8C441F07, // 0150 GETMET R17 R15 K7 - 0x544E0010, // 0151 LDINT R19 17 - 0x7C440400, // 0152 CALL R17 2 - 0x5C482000, // 0153 MOVE R18 R16 - 0x784A0001, // 0154 JMPF R18 #0157 - 0x5C482200, // 0155 MOVE R18 R17 - 0x744A0006, // 0156 JMPT R18 #015E - 0xB84A3A00, // 0157 GETNGBL R18 K29 - 0x8C482522, // 0158 GETMET R18 R18 K34 - 0x58500035, // 0159 LDCONST R20 K53 - 0x5854000F, // 015A LDCONST R21 K15 - 0x7C480600, // 015B CALL R18 3 - 0x50480000, // 015C LDBOOL R18 0 0 - 0x80042400, // 015D RET 1 R18 - 0x60480004, // 015E GETGBL R18 G4 - 0x5C4C2000, // 015F MOVE R19 R16 - 0x7C480200, // 0160 CALL R18 1 - 0x1C482536, // 0161 EQ R18 R18 K54 - 0x784A0006, // 0162 JMPF R18 #016A - 0xB84A6E00, // 0163 GETNGBL R18 K55 - 0x5C4C2000, // 0164 MOVE R19 R16 - 0x7C480200, // 0165 CALL R18 1 - 0x8C482538, // 0166 GETMET R18 R18 K56 - 0x7C480200, // 0167 CALL R18 1 - 0x5C402400, // 0168 MOVE R16 R18 - 0x70020002, // 0169 JMP #016D - 0x8C482138, // 016A GETMET R18 R16 K56 - 0x7C480200, // 016B CALL R18 1 - 0x5C402400, // 016C MOVE R16 R18 - 0x60480004, // 016D GETGBL R18 G4 - 0x5C4C2200, // 016E MOVE R19 R17 - 0x7C480200, // 016F CALL R18 1 - 0x1C482536, // 0170 EQ R18 R18 K54 - 0x784A0006, // 0171 JMPF R18 #0179 - 0xB84A6E00, // 0172 GETNGBL R18 K55 - 0x5C4C2200, // 0173 MOVE R19 R17 - 0x7C480200, // 0174 CALL R18 1 - 0x8C482538, // 0175 GETMET R18 R18 K56 - 0x7C480200, // 0176 CALL R18 1 - 0x5C442400, // 0177 MOVE R17 R18 - 0x70020002, // 0178 JMP #017C - 0x8C482338, // 0179 GETMET R18 R17 K56 - 0x7C480200, // 017A CALL R18 1 - 0x5C442400, // 017B MOVE R17 R18 - 0xB84A0200, // 017C GETNGBL R18 K1 - 0x88482502, // 017D GETMBR R18 R18 K2 - 0x8C482533, // 017E GETMET R18 R18 K51 - 0x8C50112D, // 017F GETMET R20 R8 K45 - 0x7C500200, // 0180 CALL R20 1 - 0x7C480400, // 0181 CALL R18 2 - 0x8C482507, // 0182 GETMET R18 R18 K7 - 0x54520008, // 0183 LDINT R20 9 - 0x7C480400, // 0184 CALL R18 2 - 0x404E1139, // 0185 CONNECT R19 K8 K57 - 0x94482413, // 0186 GETIDX R18 R18 R19 - 0x60500015, // 0187 GETGBL R20 G21 - 0x7C500000, // 0188 CALL R20 0 - 0x8C50293A, // 0189 GETMET R20 R20 K58 - 0x5858003B, // 018A LDCONST R22 K59 - 0x7C500400, // 018B CALL R20 2 - 0x5C4C2800, // 018C MOVE R19 R20 - 0x8C50093C, // 018D GETMET R20 R4 K60 - 0x7C500200, // 018E CALL R20 1 - 0x8C54213D, // 018F GETMET R21 R16 K61 - 0x7C540200, // 0190 CALL R21 1 - 0x8C542B3E, // 0191 GETMET R21 R21 K62 - 0x7C540200, // 0192 CALL R21 1 - 0x8C58293F, // 0193 GETMET R22 R20 K63 - 0x5C602400, // 0194 MOVE R24 R18 - 0x5C642A00, // 0195 MOVE R25 R21 - 0x5C682600, // 0196 MOVE R26 R19 - 0x546E0007, // 0197 LDINT R27 8 - 0x7C580A00, // 0198 CALL R22 5 - 0x8C5C1140, // 0199 GETMET R23 R8 K64 - 0x5C642000, // 019A MOVE R25 R16 - 0x5C682200, // 019B MOVE R26 R17 - 0x5C6C2C00, // 019C MOVE R27 R22 - 0x7C5C0800, // 019D CALL R23 4 - 0x885C0113, // 019E GETMBR R23 R0 K19 - 0x8C5C2F41, // 019F GETMET R23 R23 K65 - 0x5C641000, // 01A0 MOVE R25 R8 - 0x7C5C0400, // 01A1 CALL R23 2 - 0x8C5C0B0A, // 01A2 GETMET R23 R5 K10 - 0x7C5C0200, // 01A3 CALL R23 1 - 0x8C602F0B, // 01A4 GETMET R24 R23 K11 - 0x58680006, // 01A5 LDCONST R26 K6 - 0x886C0B0C, // 01A6 GETMBR R27 R5 K12 - 0xB8720200, // 01A7 GETNGBL R28 K1 - 0x8870392C, // 01A8 GETMBR R28 R28 K44 - 0x7C600800, // 01A9 CALL R24 4 - 0x8C602F0B, // 01AA GETMET R24 R23 K11 - 0x58680008, // 01AB LDCONST R26 K8 - 0x886C0B0C, // 01AC GETMBR R27 R5 K12 - 0x58700008, // 01AD LDCONST R28 K8 - 0x7C600800, // 01AE CALL R24 4 - 0x54620007, // 01AF LDINT R24 8 - 0x900E0818, // 01B0 SETMBR R3 K4 R24 - 0x80042E00, // 01B1 RET 1 R23 - 0x7002003A, // 01B2 JMP #01EE - 0x54260008, // 01B3 LDINT R9 9 - 0x1C240E09, // 01B4 EQ R9 R7 R9 - 0x7826000B, // 01B5 JMPF R9 #01C2 - 0x8C240507, // 01B6 GETMET R9 R2 K7 - 0x582C0006, // 01B7 LDCONST R11 K6 - 0x7C240400, // 01B8 CALL R9 2 - 0x8C281142, // 01B9 GETMET R10 R8 K66 - 0x5C301200, // 01BA MOVE R12 R9 - 0x7C280400, // 01BB CALL R10 2 - 0xB82A0200, // 01BC GETNGBL R10 K1 - 0x8828152C, // 01BD GETMBR R10 R10 K44 - 0x900E2A0A, // 01BE SETMBR R3 K21 R10 - 0x4C280000, // 01BF LDNIL R10 - 0x80041400, // 01C0 RET 1 R10 - 0x7002002B, // 01C1 JMP #01EE - 0x54260009, // 01C2 LDINT R9 10 - 0x1C240E09, // 01C3 EQ R9 R7 R9 - 0x78260028, // 01C4 JMPF R9 #01EE - 0x8C240507, // 01C5 GETMET R9 R2 K7 - 0x582C0006, // 01C6 LDCONST R11 K6 - 0x7C240400, // 01C7 CALL R9 2 - 0x88280113, // 01C8 GETMBR R10 R0 K19 - 0x88281543, // 01C9 GETMBR R10 R10 K67 - 0x8C281544, // 01CA GETMET R10 R10 K68 - 0x7C280200, // 01CB CALL R10 1 - 0x282C1308, // 01CC GE R11 R9 K8 - 0x782E001A, // 01CD JMPF R11 #01E9 - 0x602C000C, // 01CE GETGBL R11 G12 - 0x5C301400, // 01CF MOVE R12 R10 - 0x7C2C0200, // 01D0 CALL R11 1 - 0x182C120B, // 01D1 LE R11 R9 R11 - 0x782E0015, // 01D2 JMPF R11 #01E9 - 0x042C1308, // 01D3 SUB R11 R9 K8 - 0x942C140B, // 01D4 GETIDX R11 R10 R11 - 0xB8323A00, // 01D5 GETNGBL R12 K29 - 0x8C301922, // 01D6 GETMET R12 R12 K34 - 0x88381146, // 01D7 GETMBR R14 R8 K70 - 0x8C381D3D, // 01D8 GETMET R14 R14 K61 - 0x7C380200, // 01D9 CALL R14 1 - 0x8C381D3E, // 01DA GETMET R14 R14 K62 - 0x7C380200, // 01DB CALL R14 1 - 0x8C381D24, // 01DC GETMET R14 R14 K36 - 0x7C380200, // 01DD CALL R14 1 - 0x003A8A0E, // 01DE ADD R14 K69 R14 - 0x7C300400, // 01DF CALL R12 2 - 0x88300113, // 01E0 GETMBR R12 R0 K19 - 0x88301943, // 01E1 GETMBR R12 R12 K67 - 0x8C301947, // 01E2 GETMET R12 R12 K71 - 0x7C300200, // 01E3 CALL R12 1 - 0x88300113, // 01E4 GETMBR R12 R0 K19 - 0x88301943, // 01E5 GETMBR R12 R12 K67 - 0x8C301948, // 01E6 GETMET R12 R12 K72 - 0x7C300200, // 01E7 CALL R12 1 - 0x7001FFFF, // 01E8 JMP #01E9 - 0xB82E0200, // 01E9 GETNGBL R11 K1 - 0x882C172C, // 01EA GETMBR R11 R11 K44 - 0x900E2A0B, // 01EB SETMBR R3 K21 R11 - 0x4C2C0000, // 01EC LDNIL R11 - 0x80041600, // 01ED RET 1 R11 - 0x80000000, // 01EE RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_core_read_attribute, /* name */ - be_nested_proto( - 24, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[82]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(attribute), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(create_TLV), - /* K7 */ be_nested_str_weak(U8), - /* K8 */ be_nested_str_weak(session), - /* K9 */ be_nested_str_weak(breadcrumb), - /* K10 */ be_const_int(1), - /* K11 */ be_nested_str_weak(Matter_TLV_struct), - /* K12 */ be_nested_str_weak(add_TLV), - /* K13 */ be_nested_str_weak(U2), - /* K14 */ be_const_int(2), - /* K15 */ be_nested_str_weak(U1), - /* K16 */ be_const_int(3), - /* K17 */ be_nested_str_weak(BOOL), - /* K18 */ be_nested_str_weak(Matter_TLV_array), - /* K19 */ be_nested_str_weak(tasmota), - /* K20 */ be_nested_str_weak(eth), - /* K21 */ be_nested_str_weak(up), - /* K22 */ be_nested_str_weak(add_struct), - /* K23 */ be_nested_str_weak(UTF1), - /* K24 */ be_nested_str_weak(ethernet), - /* K25 */ be_nested_str_weak(NULL), - /* K26 */ be_nested_str_weak(fromhex), - /* K27 */ be_nested_str_weak(replace), - /* K28 */ be_nested_str_weak(find), - /* K29 */ be_nested_str_weak(mac), - /* K30 */ be_nested_str_weak(), - /* K31 */ be_nested_str_weak(_X3A), - /* K32 */ be_nested_str_weak(B1), - /* K33 */ be_nested_str_weak(add_array), - /* K34 */ be_nested_str_weak(get_ip_bytes), - /* K35 */ be_nested_str_weak(ip), - /* K36 */ be_nested_str_weak(ip6local), - /* K37 */ be_nested_str_weak(ip6), - /* K38 */ be_nested_str_weak(wifi), - /* K39 */ be_nested_str_weak(cmd), - /* K40 */ be_nested_str_weak(Status_X201), - /* K41 */ be_nested_str_weak(StatusPRM), - /* K42 */ be_nested_str_weak(BootCount), - /* K43 */ be_nested_str_weak(U4), - /* K44 */ be_nested_str_weak(Status_X2011), - /* K45 */ be_nested_str_weak(StatusSTS), - /* K46 */ be_nested_str_weak(UptimeSec), - /* K47 */ be_nested_str_weak(int64), - /* K48 */ be_nested_str_weak(rtc), - /* K49 */ be_nested_str_weak(utc), - /* K50 */ be_const_int(1000000), - /* K51 */ be_nested_str_weak(local), - /* K52 */ be_nested_str_weak(device), - /* K53 */ be_nested_str_weak(sessions), - /* K54 */ be_nested_str_weak(sessions_active), - /* K55 */ be_nested_str_weak(B2), - /* K56 */ be_nested_str_weak(noc), - /* K57 */ be_nested_str_weak(icac), - /* K58 */ be_nested_str_weak(stop_iteration), - /* K59 */ be_nested_str_weak(parse), - /* K60 */ be_nested_str_weak(get_ca), - /* K61 */ be_nested_str_weak(findsubval), - /* K62 */ be_nested_str_weak(admin_vendor), - /* K63 */ be_nested_str_weak(fabric), - /* K64 */ be_nested_str_weak(deviceid), - /* K65 */ be_nested_str_weak(fabric_label), - /* K66 */ be_nested_str_weak(Tasmota), - /* K67 */ be_nested_str_weak(vendorid), - /* K68 */ be_nested_str_weak(DeviceName), - /* K69 */ be_nested_str_weak(FriendlyName), - /* K70 */ be_nested_str_weak(FriendlyName1), - /* K71 */ be_nested_str_weak(XX), - /* K72 */ be_nested_str_weak(Status_X202), - /* K73 */ be_nested_str_weak(StatusFWR), - /* K74 */ be_nested_str_weak(Hardware), - /* K75 */ be_nested_str_weak(Version), - /* K76 */ be_nested_str_weak(locale), - /* K77 */ be_nested_str_weak(Matter_TLV_list), - /* K78 */ be_nested_str_weak(get_cluster_list), - /* K79 */ be_nested_str_weak(get_active_endpoints), - /* K80 */ be_nested_str_weak(status), - /* K81 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), - }), - be_str_weak(read_attribute), - &be_const_str_solidified, - ( &(const binstruction[736]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xB8120200, // 0001 GETNGBL R4 K1 - 0x88100902, // 0002 GETMBR R4 R4 K2 - 0x88140503, // 0003 GETMBR R5 R2 K3 - 0x88180504, // 0004 GETMBR R6 R2 K4 - 0x541E002F, // 0005 LDINT R7 48 - 0x1C1C0A07, // 0006 EQ R7 R5 R7 - 0x781E0031, // 0007 JMPF R7 #003A - 0x1C1C0D05, // 0008 EQ R7 R6 K5 - 0x781E0006, // 0009 JMPF R7 #0011 - 0x8C1C0906, // 000A GETMET R7 R4 K6 - 0x88240907, // 000B GETMBR R9 R4 K7 - 0x88280308, // 000C GETMBR R10 R1 K8 - 0x88281509, // 000D GETMBR R10 R10 K9 - 0x7C1C0600, // 000E CALL R7 3 - 0x80040E00, // 000F RET 1 R7 - 0x70020027, // 0010 JMP #0039 - 0x1C1C0D0A, // 0011 EQ R7 R6 K10 - 0x781E000D, // 0012 JMPF R7 #0021 - 0x8C1C090B, // 0013 GETMET R7 R4 K11 - 0x7C1C0200, // 0014 CALL R7 1 - 0x8C200F0C, // 0015 GETMET R8 R7 K12 - 0x58280005, // 0016 LDCONST R10 K5 - 0x882C090D, // 0017 GETMBR R11 R4 K13 - 0x5432003B, // 0018 LDINT R12 60 - 0x7C200800, // 0019 CALL R8 4 - 0x8C200F0C, // 001A GETMET R8 R7 K12 - 0x5828000A, // 001B LDCONST R10 K10 - 0x882C090D, // 001C GETMBR R11 R4 K13 - 0x54320383, // 001D LDINT R12 900 - 0x7C200800, // 001E CALL R8 4 - 0x80040E00, // 001F RET 1 R7 - 0x70020017, // 0020 JMP #0039 - 0x1C1C0D0E, // 0021 EQ R7 R6 K14 - 0x781E0005, // 0022 JMPF R7 #0029 - 0x8C1C0906, // 0023 GETMET R7 R4 K6 - 0x8824090F, // 0024 GETMBR R9 R4 K15 - 0x5828000E, // 0025 LDCONST R10 K14 - 0x7C1C0600, // 0026 CALL R7 3 - 0x80040E00, // 0027 RET 1 R7 - 0x7002000F, // 0028 JMP #0039 - 0x1C1C0D10, // 0029 EQ R7 R6 K16 - 0x781E0005, // 002A JMPF R7 #0031 - 0x8C1C0906, // 002B GETMET R7 R4 K6 - 0x8824090F, // 002C GETMBR R9 R4 K15 - 0x5828000E, // 002D LDCONST R10 K14 - 0x7C1C0600, // 002E CALL R7 3 - 0x80040E00, // 002F RET 1 R7 - 0x70020007, // 0030 JMP #0039 - 0x541E0003, // 0031 LDINT R7 4 - 0x1C1C0C07, // 0032 EQ R7 R6 R7 - 0x781E0004, // 0033 JMPF R7 #0039 - 0x8C1C0906, // 0034 GETMET R7 R4 K6 - 0x88240911, // 0035 GETMBR R9 R4 K17 - 0x50280000, // 0036 LDBOOL R10 0 0 - 0x7C1C0600, // 0037 CALL R7 3 - 0x80040E00, // 0038 RET 1 R7 - 0x700202A4, // 0039 JMP #02DF - 0x541E0031, // 003A LDINT R7 50 - 0x1C1C0A07, // 003B EQ R7 R5 R7 - 0x781E0000, // 003C JMPF R7 #003E - 0x700202A0, // 003D JMP #02DF - 0x541E0032, // 003E LDINT R7 51 - 0x1C1C0A07, // 003F EQ R7 R5 R7 - 0x781E00DA, // 0040 JMPF R7 #011C - 0x1C1C0D05, // 0041 EQ R7 R6 K5 - 0x781E00B5, // 0042 JMPF R7 #00F9 - 0x8C1C0912, // 0043 GETMET R7 R4 K18 - 0x7C1C0200, // 0044 CALL R7 1 - 0xB8222600, // 0045 GETNGBL R8 K19 - 0x8C201114, // 0046 GETMET R8 R8 K20 - 0x7C200200, // 0047 CALL R8 1 - 0x94241115, // 0048 GETIDX R9 R8 K21 - 0x78260053, // 0049 JMPF R9 #009E - 0x8C240F16, // 004A GETMET R9 R7 K22 - 0x4C2C0000, // 004B LDNIL R11 - 0x7C240400, // 004C CALL R9 2 - 0x8C28130C, // 004D GETMET R10 R9 K12 - 0x58300005, // 004E LDCONST R12 K5 - 0x88340917, // 004F GETMBR R13 R4 K23 - 0x58380018, // 0050 LDCONST R14 K24 - 0x7C280800, // 0051 CALL R10 4 - 0x8C28130C, // 0052 GETMET R10 R9 K12 - 0x5830000A, // 0053 LDCONST R12 K10 - 0x88340911, // 0054 GETMBR R13 R4 K17 - 0x5838000A, // 0055 LDCONST R14 K10 - 0x7C280800, // 0056 CALL R10 4 - 0x8C28130C, // 0057 GETMET R10 R9 K12 - 0x5830000E, // 0058 LDCONST R12 K14 - 0x88340911, // 0059 GETMBR R13 R4 K17 - 0x5838000A, // 005A LDCONST R14 K10 - 0x7C280800, // 005B CALL R10 4 - 0x8C28130C, // 005C GETMET R10 R9 K12 - 0x58300010, // 005D LDCONST R12 K16 - 0x88340919, // 005E GETMBR R13 R4 K25 - 0x4C380000, // 005F LDNIL R14 - 0x7C280800, // 0060 CALL R10 4 - 0x60280015, // 0061 GETGBL R10 G21 - 0x7C280000, // 0062 CALL R10 0 - 0x8C28151A, // 0063 GETMET R10 R10 K26 - 0x8C30071B, // 0064 GETMET R12 R3 K27 - 0x8C38111C, // 0065 GETMET R14 R8 K28 - 0x5840001D, // 0066 LDCONST R16 K29 - 0x5844001E, // 0067 LDCONST R17 K30 - 0x7C380600, // 0068 CALL R14 3 - 0x583C001F, // 0069 LDCONST R15 K31 - 0x5840001E, // 006A LDCONST R16 K30 - 0x7C300800, // 006B CALL R12 4 - 0x7C280400, // 006C CALL R10 2 - 0x8C2C130C, // 006D GETMET R11 R9 K12 - 0x54360003, // 006E LDINT R13 4 - 0x88380920, // 006F GETMBR R14 R4 K32 - 0x5C3C1400, // 0070 MOVE R15 R10 - 0x7C2C0800, // 0071 CALL R11 4 - 0x8C2C1321, // 0072 GETMET R11 R9 K33 - 0x54360004, // 0073 LDINT R13 5 - 0x7C2C0400, // 0074 CALL R11 2 - 0x8C30170C, // 0075 GETMET R12 R11 K12 - 0x4C380000, // 0076 LDNIL R14 - 0x883C0920, // 0077 GETMBR R15 R4 K32 - 0xB8420200, // 0078 GETNGBL R16 K1 - 0x8C402122, // 0079 GETMET R16 R16 K34 - 0x8C48111C, // 007A GETMET R18 R8 K28 - 0x58500023, // 007B LDCONST R20 K35 - 0x5854001E, // 007C LDCONST R21 K30 - 0x7C480600, // 007D CALL R18 3 - 0x7C400400, // 007E CALL R16 2 - 0x7C300800, // 007F CALL R12 4 - 0x8C301321, // 0080 GETMET R12 R9 K33 - 0x543A0005, // 0081 LDINT R14 6 - 0x7C300400, // 0082 CALL R12 2 - 0x8C34190C, // 0083 GETMET R13 R12 K12 - 0x4C3C0000, // 0084 LDNIL R15 - 0x88400920, // 0085 GETMBR R16 R4 K32 - 0xB8460200, // 0086 GETNGBL R17 K1 - 0x8C442322, // 0087 GETMET R17 R17 K34 - 0x8C4C111C, // 0088 GETMET R19 R8 K28 - 0x58540024, // 0089 LDCONST R21 K36 - 0x5858001E, // 008A LDCONST R22 K30 - 0x7C4C0600, // 008B CALL R19 3 - 0x7C440400, // 008C CALL R17 2 - 0x7C340800, // 008D CALL R13 4 - 0x8C34190C, // 008E GETMET R13 R12 K12 - 0x4C3C0000, // 008F LDNIL R15 - 0x88400920, // 0090 GETMBR R16 R4 K32 - 0xB8460200, // 0091 GETNGBL R17 K1 - 0x8C442322, // 0092 GETMET R17 R17 K34 - 0x8C4C111C, // 0093 GETMET R19 R8 K28 - 0x58540025, // 0094 LDCONST R21 K37 - 0x5858001E, // 0095 LDCONST R22 K30 - 0x7C4C0600, // 0096 CALL R19 3 - 0x7C440400, // 0097 CALL R17 2 - 0x7C340800, // 0098 CALL R13 4 - 0x8C34130C, // 0099 GETMET R13 R9 K12 - 0x543E0006, // 009A LDINT R15 7 - 0x8840090F, // 009B GETMBR R16 R4 K15 - 0x5844000E, // 009C LDCONST R17 K14 - 0x7C340800, // 009D CALL R13 4 - 0xB8262600, // 009E GETNGBL R9 K19 - 0x8C241326, // 009F GETMET R9 R9 K38 - 0x7C240200, // 00A0 CALL R9 1 - 0x94281315, // 00A1 GETIDX R10 R9 K21 - 0x782A0053, // 00A2 JMPF R10 #00F7 - 0x8C280F16, // 00A3 GETMET R10 R7 K22 - 0x4C300000, // 00A4 LDNIL R12 - 0x7C280400, // 00A5 CALL R10 2 - 0x8C2C150C, // 00A6 GETMET R11 R10 K12 - 0x58340005, // 00A7 LDCONST R13 K5 - 0x88380917, // 00A8 GETMBR R14 R4 K23 - 0x583C0026, // 00A9 LDCONST R15 K38 - 0x7C2C0800, // 00AA CALL R11 4 - 0x8C2C150C, // 00AB GETMET R11 R10 K12 - 0x5834000A, // 00AC LDCONST R13 K10 - 0x88380911, // 00AD GETMBR R14 R4 K17 - 0x583C000A, // 00AE LDCONST R15 K10 - 0x7C2C0800, // 00AF CALL R11 4 - 0x8C2C150C, // 00B0 GETMET R11 R10 K12 - 0x5834000E, // 00B1 LDCONST R13 K14 - 0x88380911, // 00B2 GETMBR R14 R4 K17 - 0x583C000A, // 00B3 LDCONST R15 K10 - 0x7C2C0800, // 00B4 CALL R11 4 - 0x8C2C150C, // 00B5 GETMET R11 R10 K12 - 0x58340010, // 00B6 LDCONST R13 K16 - 0x88380919, // 00B7 GETMBR R14 R4 K25 - 0x4C3C0000, // 00B8 LDNIL R15 - 0x7C2C0800, // 00B9 CALL R11 4 - 0x602C0015, // 00BA GETGBL R11 G21 - 0x7C2C0000, // 00BB CALL R11 0 - 0x8C2C171A, // 00BC GETMET R11 R11 K26 - 0x8C34071B, // 00BD GETMET R13 R3 K27 - 0x8C3C131C, // 00BE GETMET R15 R9 K28 - 0x5844001D, // 00BF LDCONST R17 K29 - 0x5848001E, // 00C0 LDCONST R18 K30 - 0x7C3C0600, // 00C1 CALL R15 3 - 0x5840001F, // 00C2 LDCONST R16 K31 - 0x5844001E, // 00C3 LDCONST R17 K30 - 0x7C340800, // 00C4 CALL R13 4 - 0x7C2C0400, // 00C5 CALL R11 2 - 0x8C30150C, // 00C6 GETMET R12 R10 K12 - 0x543A0003, // 00C7 LDINT R14 4 - 0x883C0920, // 00C8 GETMBR R15 R4 K32 - 0x5C401600, // 00C9 MOVE R16 R11 - 0x7C300800, // 00CA CALL R12 4 - 0x8C301521, // 00CB GETMET R12 R10 K33 - 0x543A0004, // 00CC LDINT R14 5 - 0x7C300400, // 00CD CALL R12 2 - 0x8C34190C, // 00CE GETMET R13 R12 K12 - 0x4C3C0000, // 00CF LDNIL R15 - 0x88400920, // 00D0 GETMBR R16 R4 K32 - 0xB8460200, // 00D1 GETNGBL R17 K1 - 0x8C442322, // 00D2 GETMET R17 R17 K34 - 0x8C4C131C, // 00D3 GETMET R19 R9 K28 - 0x58540023, // 00D4 LDCONST R21 K35 - 0x5858001E, // 00D5 LDCONST R22 K30 - 0x7C4C0600, // 00D6 CALL R19 3 - 0x7C440400, // 00D7 CALL R17 2 - 0x7C340800, // 00D8 CALL R13 4 - 0x8C341521, // 00D9 GETMET R13 R10 K33 - 0x543E0005, // 00DA LDINT R15 6 - 0x7C340400, // 00DB CALL R13 2 - 0x8C381B0C, // 00DC GETMET R14 R13 K12 - 0x4C400000, // 00DD LDNIL R16 - 0x88440920, // 00DE GETMBR R17 R4 K32 - 0xB84A0200, // 00DF GETNGBL R18 K1 - 0x8C482522, // 00E0 GETMET R18 R18 K34 - 0x8C50131C, // 00E1 GETMET R20 R9 K28 - 0x58580024, // 00E2 LDCONST R22 K36 - 0x585C001E, // 00E3 LDCONST R23 K30 - 0x7C500600, // 00E4 CALL R20 3 - 0x7C480400, // 00E5 CALL R18 2 - 0x7C380800, // 00E6 CALL R14 4 - 0x8C381B0C, // 00E7 GETMET R14 R13 K12 - 0x4C400000, // 00E8 LDNIL R16 - 0x88440920, // 00E9 GETMBR R17 R4 K32 - 0xB84A0200, // 00EA GETNGBL R18 K1 - 0x8C482522, // 00EB GETMET R18 R18 K34 - 0x8C50131C, // 00EC GETMET R20 R9 K28 - 0x58580025, // 00ED LDCONST R22 K37 - 0x585C001E, // 00EE LDCONST R23 K30 - 0x7C500600, // 00EF CALL R20 3 - 0x7C480400, // 00F0 CALL R18 2 - 0x7C380800, // 00F1 CALL R14 4 - 0x8C38150C, // 00F2 GETMET R14 R10 K12 - 0x54420006, // 00F3 LDINT R16 7 - 0x8844090F, // 00F4 GETMBR R17 R4 K15 - 0x5848000A, // 00F5 LDCONST R18 K10 - 0x7C380800, // 00F6 CALL R14 4 - 0x80040E00, // 00F7 RET 1 R7 - 0x70020021, // 00F8 JMP #011B - 0x1C1C0D0A, // 00F9 EQ R7 R6 K10 - 0x781E000A, // 00FA JMPF R7 #0106 - 0x8C1C0906, // 00FB GETMET R7 R4 K6 - 0x8824090D, // 00FC GETMBR R9 R4 K13 - 0xB82A2600, // 00FD GETNGBL R10 K19 - 0x8C281527, // 00FE GETMET R10 R10 K39 - 0x58300028, // 00FF LDCONST R12 K40 - 0x7C280400, // 0100 CALL R10 2 - 0x94281529, // 0101 GETIDX R10 R10 K41 - 0x9428152A, // 0102 GETIDX R10 R10 K42 - 0x7C1C0600, // 0103 CALL R7 3 - 0x80040E00, // 0104 RET 1 R7 - 0x70020014, // 0105 JMP #011B - 0x1C1C0D0E, // 0106 EQ R7 R6 K14 - 0x781E000A, // 0107 JMPF R7 #0113 - 0x8C1C0906, // 0108 GETMET R7 R4 K6 - 0x8824092B, // 0109 GETMBR R9 R4 K43 - 0xB82A2600, // 010A GETNGBL R10 K19 - 0x8C281527, // 010B GETMET R10 R10 K39 - 0x5830002C, // 010C LDCONST R12 K44 - 0x7C280400, // 010D CALL R10 2 - 0x9428152D, // 010E GETIDX R10 R10 K45 - 0x9428152E, // 010F GETIDX R10 R10 K46 - 0x7C1C0600, // 0110 CALL R7 3 - 0x80040E00, // 0111 RET 1 R7 - 0x70020007, // 0112 JMP #011B - 0x541E0007, // 0113 LDINT R7 8 - 0x1C1C0C07, // 0114 EQ R7 R6 R7 - 0x781E0004, // 0115 JMPF R7 #011B - 0x8C1C0906, // 0116 GETMET R7 R4 K6 - 0x88240911, // 0117 GETMBR R9 R4 K17 - 0x50280000, // 0118 LDBOOL R10 0 0 - 0x7C1C0600, // 0119 CALL R7 3 - 0x80040E00, // 011A RET 1 R7 - 0x700201C2, // 011B JMP #02DF - 0x541E0033, // 011C LDINT R7 52 - 0x1C1C0A07, // 011D EQ R7 R5 R7 - 0x781E0000, // 011E JMPF R7 #0120 - 0x700201BE, // 011F JMP #02DF - 0x541E0037, // 0120 LDINT R7 56 - 0x1C1C0A07, // 0121 EQ R7 R5 R7 - 0x781E002C, // 0122 JMPF R7 #0150 - 0x1C1C0D05, // 0123 EQ R7 R6 K5 - 0x781E000F, // 0124 JMPF R7 #0135 - 0xB81E5E00, // 0125 GETNGBL R7 K47 - 0xB8222600, // 0126 GETNGBL R8 K19 - 0x8C201130, // 0127 GETMET R8 R8 K48 - 0x7C200200, // 0128 CALL R8 1 - 0x94201131, // 0129 GETIDX R8 R8 K49 - 0x7C1C0200, // 012A CALL R7 1 - 0xB8225E00, // 012B GETNGBL R8 K47 - 0x58240032, // 012C LDCONST R9 K50 - 0x7C200200, // 012D CALL R8 1 - 0x081C0E08, // 012E MUL R7 R7 R8 - 0x8C200906, // 012F GETMET R8 R4 K6 - 0x88280907, // 0130 GETMBR R10 R4 K7 - 0x5C2C0E00, // 0131 MOVE R11 R7 - 0x7C200600, // 0132 CALL R8 3 - 0x80041000, // 0133 RET 1 R8 - 0x70020019, // 0134 JMP #014F - 0x1C1C0D0A, // 0135 EQ R7 R6 K10 - 0x781E0005, // 0136 JMPF R7 #013D - 0x8C1C0906, // 0137 GETMET R7 R4 K6 - 0x8824090F, // 0138 GETMBR R9 R4 K15 - 0x58280010, // 0139 LDCONST R10 K16 - 0x7C1C0600, // 013A CALL R7 3 - 0x80040E00, // 013B RET 1 R7 - 0x70020011, // 013C JMP #014F - 0x541E0006, // 013D LDINT R7 7 - 0x1C1C0C07, // 013E EQ R7 R6 R7 - 0x781E000E, // 013F JMPF R7 #014F - 0xB81E5E00, // 0140 GETNGBL R7 K47 - 0xB8222600, // 0141 GETNGBL R8 K19 - 0x8C201130, // 0142 GETMET R8 R8 K48 - 0x7C200200, // 0143 CALL R8 1 - 0x94201133, // 0144 GETIDX R8 R8 K51 - 0x7C1C0200, // 0145 CALL R7 1 - 0xB8225E00, // 0146 GETNGBL R8 K47 - 0x58240032, // 0147 LDCONST R9 K50 - 0x7C200200, // 0148 CALL R8 1 - 0x081C0E08, // 0149 MUL R7 R7 R8 - 0x8C200906, // 014A GETMET R8 R4 K6 - 0x88280907, // 014B GETMBR R10 R4 K7 - 0x5C2C0E00, // 014C MOVE R11 R7 - 0x7C200600, // 014D CALL R8 3 - 0x80041000, // 014E RET 1 R8 - 0x7002018E, // 014F JMP #02DF - 0x541E003D, // 0150 LDINT R7 62 - 0x1C1C0A07, // 0151 EQ R7 R5 R7 - 0x781E0082, // 0152 JMPF R7 #01D6 - 0x1C1C0D05, // 0153 EQ R7 R6 K5 - 0x781E001D, // 0154 JMPF R7 #0173 - 0x8C1C0912, // 0155 GETMET R7 R4 K18 - 0x7C1C0200, // 0156 CALL R7 1 - 0x60200010, // 0157 GETGBL R8 G16 - 0x88240134, // 0158 GETMBR R9 R0 K52 - 0x88241335, // 0159 GETMBR R9 R9 K53 - 0x8C241336, // 015A GETMET R9 R9 K54 - 0x7C240200, // 015B CALL R9 1 - 0x7C200200, // 015C CALL R8 1 - 0xA802000F, // 015D EXBLK 0 #016E - 0x5C241000, // 015E MOVE R9 R8 - 0x7C240000, // 015F CALL R9 0 - 0x8C280F16, // 0160 GETMET R10 R7 K22 - 0x4C300000, // 0161 LDNIL R12 - 0x7C280400, // 0162 CALL R10 2 - 0x8C2C150C, // 0163 GETMET R11 R10 K12 - 0x5834000A, // 0164 LDCONST R13 K10 - 0x88380937, // 0165 GETMBR R14 R4 K55 - 0x883C1338, // 0166 GETMBR R15 R9 K56 - 0x7C2C0800, // 0167 CALL R11 4 - 0x8C2C150C, // 0168 GETMET R11 R10 K12 - 0x5834000E, // 0169 LDCONST R13 K14 - 0x88380937, // 016A GETMBR R14 R4 K55 - 0x883C1339, // 016B GETMBR R15 R9 K57 - 0x7C2C0800, // 016C CALL R11 4 - 0x7001FFEF, // 016D JMP #015E - 0x5820003A, // 016E LDCONST R8 K58 - 0xAC200200, // 016F CATCH R8 1 0 - 0xB0080000, // 0170 RAISE 2 R0 R0 - 0x80040E00, // 0171 RET 1 R7 - 0x70020061, // 0172 JMP #01D5 - 0x1C1C0D0A, // 0173 EQ R7 R6 K10 - 0x781E0032, // 0174 JMPF R7 #01A8 - 0x8C1C0912, // 0175 GETMET R7 R4 K18 - 0x7C1C0200, // 0176 CALL R7 1 - 0x60200010, // 0177 GETGBL R8 G16 - 0x88240134, // 0178 GETMBR R9 R0 K52 - 0x88241335, // 0179 GETMBR R9 R9 K53 - 0x8C241336, // 017A GETMET R9 R9 K54 - 0x7C240200, // 017B CALL R9 1 - 0x7C200200, // 017C CALL R8 1 - 0xA8020024, // 017D EXBLK 0 #01A3 - 0x5C241000, // 017E MOVE R9 R8 - 0x7C240000, // 017F CALL R9 0 - 0x8C28093B, // 0180 GETMET R10 R4 K59 - 0x8C30133C, // 0181 GETMET R12 R9 K60 - 0x7C300200, // 0182 CALL R12 1 - 0x7C280400, // 0183 CALL R10 2 - 0x8C2C0F16, // 0184 GETMET R11 R7 K22 - 0x4C340000, // 0185 LDNIL R13 - 0x7C2C0400, // 0186 CALL R11 2 - 0x8C30170C, // 0187 GETMET R12 R11 K12 - 0x5838000A, // 0188 LDCONST R14 K10 - 0x883C0937, // 0189 GETMBR R15 R4 K55 - 0x8C40153D, // 018A GETMET R16 R10 K61 - 0x544A0008, // 018B LDINT R18 9 - 0x7C400400, // 018C CALL R16 2 - 0x7C300800, // 018D CALL R12 4 - 0x8C30170C, // 018E GETMET R12 R11 K12 - 0x5838000E, // 018F LDCONST R14 K14 - 0x883C090D, // 0190 GETMBR R15 R4 K13 - 0x8840133E, // 0191 GETMBR R16 R9 K62 - 0x7C300800, // 0192 CALL R12 4 - 0x8C30170C, // 0193 GETMET R12 R11 K12 - 0x58380010, // 0194 LDCONST R14 K16 - 0x883C0907, // 0195 GETMBR R15 R4 K7 - 0x8840133F, // 0196 GETMBR R16 R9 K63 - 0x7C300800, // 0197 CALL R12 4 - 0x8C30170C, // 0198 GETMET R12 R11 K12 - 0x543A0003, // 0199 LDINT R14 4 - 0x883C0907, // 019A GETMBR R15 R4 K7 - 0x88401340, // 019B GETMBR R16 R9 K64 - 0x7C300800, // 019C CALL R12 4 - 0x8C30170C, // 019D GETMET R12 R11 K12 - 0x543A0004, // 019E LDINT R14 5 - 0x883C0917, // 019F GETMBR R15 R4 K23 - 0x88401341, // 01A0 GETMBR R16 R9 K65 - 0x7C300800, // 01A1 CALL R12 4 - 0x7001FFDA, // 01A2 JMP #017E - 0x5820003A, // 01A3 LDCONST R8 K58 - 0xAC200200, // 01A4 CATCH R8 1 0 - 0xB0080000, // 01A5 RAISE 2 R0 R0 - 0x80040E00, // 01A6 RET 1 R7 - 0x7002002C, // 01A7 JMP #01D5 - 0x1C1C0D0E, // 01A8 EQ R7 R6 K14 - 0x781E0005, // 01A9 JMPF R7 #01B0 - 0x8C1C0906, // 01AA GETMET R7 R4 K6 - 0x8824090F, // 01AB GETMBR R9 R4 K15 - 0x542A0004, // 01AC LDINT R10 5 - 0x7C1C0600, // 01AD CALL R7 3 - 0x80040E00, // 01AE RET 1 R7 - 0x70020024, // 01AF JMP #01D5 - 0x1C1C0D10, // 01B0 EQ R7 R6 K16 - 0x781E000B, // 01B1 JMPF R7 #01BE - 0x881C0134, // 01B2 GETMBR R7 R0 K52 - 0x881C0F35, // 01B3 GETMBR R7 R7 K53 - 0x8C1C0F36, // 01B4 GETMET R7 R7 K54 - 0x7C1C0200, // 01B5 CALL R7 1 - 0x8C200906, // 01B6 GETMET R8 R4 K6 - 0x8828090F, // 01B7 GETMBR R10 R4 K15 - 0x602C000C, // 01B8 GETGBL R11 G12 - 0x5C300E00, // 01B9 MOVE R12 R7 - 0x7C2C0200, // 01BA CALL R11 1 - 0x7C200600, // 01BB CALL R8 3 - 0x80041000, // 01BC RET 1 R8 - 0x70020016, // 01BD JMP #01D5 - 0x541E0003, // 01BE LDINT R7 4 - 0x1C1C0C07, // 01BF EQ R7 R6 R7 - 0x781E0000, // 01C0 JMPF R7 #01C2 - 0x70020012, // 01C1 JMP #01D5 - 0x541E0004, // 01C2 LDINT R7 5 - 0x1C1C0C07, // 01C3 EQ R7 R6 R7 - 0x781E000F, // 01C4 JMPF R7 #01D5 - 0x881C0134, // 01C5 GETMBR R7 R0 K52 - 0x881C0F35, // 01C6 GETMBR R7 R7 K53 - 0x8C1C0F36, // 01C7 GETMET R7 R7 K54 - 0x7C1C0200, // 01C8 CALL R7 1 - 0x8C200F1C, // 01C9 GETMET R8 R7 K28 - 0x88280308, // 01CA GETMBR R10 R1 K8 - 0x7C200400, // 01CB CALL R8 2 - 0x4C240000, // 01CC LDNIL R9 - 0x1C241009, // 01CD EQ R9 R8 R9 - 0x78260000, // 01CE JMPF R9 #01D0 - 0x58200005, // 01CF LDCONST R8 K5 - 0x8C240906, // 01D0 GETMET R9 R4 K6 - 0x882C090F, // 01D1 GETMBR R11 R4 K15 - 0x5C301000, // 01D2 MOVE R12 R8 - 0x7C240600, // 01D3 CALL R9 3 - 0x80041200, // 01D4 RET 1 R9 - 0x70020108, // 01D5 JMP #02DF - 0x541E003B, // 01D6 LDINT R7 60 - 0x1C1C0A07, // 01D7 EQ R7 R5 R7 - 0x781E0000, // 01D8 JMPF R7 #01DA - 0x70020104, // 01D9 JMP #02DF - 0x541E0027, // 01DA LDINT R7 40 - 0x1C1C0A07, // 01DB EQ R7 R5 R7 - 0x781E0071, // 01DC JMPF R7 #024F - 0x1C1C0D05, // 01DD EQ R7 R6 K5 - 0x781E0005, // 01DE JMPF R7 #01E5 - 0x8C1C0906, // 01DF GETMET R7 R4 K6 - 0x8824090D, // 01E0 GETMBR R9 R4 K13 - 0x58280005, // 01E1 LDCONST R10 K5 - 0x7C1C0600, // 01E2 CALL R7 3 - 0x80040E00, // 01E3 RET 1 R7 - 0x70020068, // 01E4 JMP #024E - 0x1C1C0D0A, // 01E5 EQ R7 R6 K10 - 0x781E0005, // 01E6 JMPF R7 #01ED - 0x8C1C0906, // 01E7 GETMET R7 R4 K6 - 0x88240917, // 01E8 GETMBR R9 R4 K23 - 0x58280042, // 01E9 LDCONST R10 K66 - 0x7C1C0600, // 01EA CALL R7 3 - 0x80040E00, // 01EB RET 1 R7 - 0x70020060, // 01EC JMP #024E - 0x1C1C0D0E, // 01ED EQ R7 R6 K14 - 0x781E0006, // 01EE JMPF R7 #01F6 - 0x8C1C0906, // 01EF GETMET R7 R4 K6 - 0x8824090D, // 01F0 GETMBR R9 R4 K13 - 0x88280134, // 01F1 GETMBR R10 R0 K52 - 0x88281543, // 01F2 GETMBR R10 R10 K67 - 0x7C1C0600, // 01F3 CALL R7 3 - 0x80040E00, // 01F4 RET 1 R7 - 0x70020057, // 01F5 JMP #024E - 0x1C1C0D10, // 01F6 EQ R7 R6 K16 - 0x781E0009, // 01F7 JMPF R7 #0202 - 0x8C1C0906, // 01F8 GETMET R7 R4 K6 - 0x88240917, // 01F9 GETMBR R9 R4 K23 - 0xB82A2600, // 01FA GETNGBL R10 K19 - 0x8C281527, // 01FB GETMET R10 R10 K39 - 0x58300044, // 01FC LDCONST R12 K68 - 0x7C280400, // 01FD CALL R10 2 - 0x94281544, // 01FE GETIDX R10 R10 K68 - 0x7C1C0600, // 01FF CALL R7 3 - 0x80040E00, // 0200 RET 1 R7 - 0x7002004B, // 0201 JMP #024E - 0x541E0003, // 0202 LDINT R7 4 - 0x1C1C0C07, // 0203 EQ R7 R6 R7 - 0x781E0005, // 0204 JMPF R7 #020B - 0x8C1C0906, // 0205 GETMET R7 R4 K6 - 0x8824090D, // 0206 GETMBR R9 R4 K13 - 0x542A7FFF, // 0207 LDINT R10 32768 - 0x7C1C0600, // 0208 CALL R7 3 - 0x80040E00, // 0209 RET 1 R7 - 0x70020042, // 020A JMP #024E - 0x541E0004, // 020B LDINT R7 5 - 0x1C1C0C07, // 020C EQ R7 R6 R7 - 0x781E0009, // 020D JMPF R7 #0218 - 0x8C1C0906, // 020E GETMET R7 R4 K6 - 0x88240917, // 020F GETMBR R9 R4 K23 - 0xB82A2600, // 0210 GETNGBL R10 K19 - 0x8C281527, // 0211 GETMET R10 R10 K39 - 0x58300045, // 0212 LDCONST R12 K69 - 0x7C280400, // 0213 CALL R10 2 - 0x94281546, // 0214 GETIDX R10 R10 K70 - 0x7C1C0600, // 0215 CALL R7 3 - 0x80040E00, // 0216 RET 1 R7 - 0x70020035, // 0217 JMP #024E - 0x541E0005, // 0218 LDINT R7 6 - 0x1C1C0C07, // 0219 EQ R7 R6 R7 - 0x781E0005, // 021A JMPF R7 #0221 - 0x8C1C0906, // 021B GETMET R7 R4 K6 - 0x88240917, // 021C GETMBR R9 R4 K23 - 0x58280047, // 021D LDCONST R10 K71 - 0x7C1C0600, // 021E CALL R7 3 - 0x80040E00, // 021F RET 1 R7 - 0x7002002C, // 0220 JMP #024E - 0x541E0006, // 0221 LDINT R7 7 - 0x1C1C0C07, // 0222 EQ R7 R6 R7 - 0x781E0005, // 0223 JMPF R7 #022A - 0x8C1C0906, // 0224 GETMET R7 R4 K6 - 0x8824090D, // 0225 GETMBR R9 R4 K13 - 0x58280005, // 0226 LDCONST R10 K5 - 0x7C1C0600, // 0227 CALL R7 3 - 0x80040E00, // 0228 RET 1 R7 - 0x70020023, // 0229 JMP #024E - 0x541E0007, // 022A LDINT R7 8 - 0x1C1C0C07, // 022B EQ R7 R6 R7 - 0x781E000A, // 022C JMPF R7 #0238 - 0x8C1C0906, // 022D GETMET R7 R4 K6 - 0x88240917, // 022E GETMBR R9 R4 K23 - 0xB82A2600, // 022F GETNGBL R10 K19 - 0x8C281527, // 0230 GETMET R10 R10 K39 - 0x58300048, // 0231 LDCONST R12 K72 - 0x7C280400, // 0232 CALL R10 2 - 0x94281549, // 0233 GETIDX R10 R10 K73 - 0x9428154A, // 0234 GETIDX R10 R10 K74 - 0x7C1C0600, // 0235 CALL R7 3 - 0x80040E00, // 0236 RET 1 R7 - 0x70020015, // 0237 JMP #024E - 0x541E0008, // 0238 LDINT R7 9 - 0x1C1C0C07, // 0239 EQ R7 R6 R7 - 0x781E0005, // 023A JMPF R7 #0241 - 0x8C1C0906, // 023B GETMET R7 R4 K6 - 0x8824090D, // 023C GETMBR R9 R4 K13 - 0x58280005, // 023D LDCONST R10 K5 - 0x7C1C0600, // 023E CALL R7 3 - 0x80040E00, // 023F RET 1 R7 - 0x7002000C, // 0240 JMP #024E - 0x541E0009, // 0241 LDINT R7 10 - 0x1C1C0C07, // 0242 EQ R7 R6 R7 - 0x781E0009, // 0243 JMPF R7 #024E - 0x8C1C0906, // 0244 GETMET R7 R4 K6 - 0x88240917, // 0245 GETMBR R9 R4 K23 - 0xB82A2600, // 0246 GETNGBL R10 K19 - 0x8C281527, // 0247 GETMET R10 R10 K39 - 0x58300048, // 0248 LDCONST R12 K72 - 0x7C280400, // 0249 CALL R10 2 - 0x94281549, // 024A GETIDX R10 R10 K73 - 0x9428154B, // 024B GETIDX R10 R10 K75 - 0x7C1C0600, // 024C CALL R7 3 - 0x80040E00, // 024D RET 1 R7 - 0x7002008F, // 024E JMP #02DF - 0x541E003E, // 024F LDINT R7 63 - 0x1C1C0A07, // 0250 EQ R7 R5 R7 - 0x781E0000, // 0251 JMPF R7 #0253 - 0x7002008B, // 0252 JMP #02DF - 0x541E002A, // 0253 LDINT R7 43 - 0x1C1C0A07, // 0254 EQ R7 R5 R7 - 0x781E0016, // 0255 JMPF R7 #026D - 0x1C1C0D05, // 0256 EQ R7 R6 K5 - 0x781E0007, // 0257 JMPF R7 #0260 - 0x8C1C0906, // 0258 GETMET R7 R4 K6 - 0x88240917, // 0259 GETMBR R9 R4 K23 - 0xB82A2600, // 025A GETNGBL R10 K19 - 0x8C28154C, // 025B GETMET R10 R10 K76 - 0x7C280200, // 025C CALL R10 1 - 0x7C1C0600, // 025D CALL R7 3 - 0x80040E00, // 025E RET 1 R7 - 0x7002000B, // 025F JMP #026C - 0x1C1C0D0A, // 0260 EQ R7 R6 K10 - 0x781E0009, // 0261 JMPF R7 #026C - 0x8C1C094D, // 0262 GETMET R7 R4 K77 - 0x7C1C0200, // 0263 CALL R7 1 - 0x8C200F0C, // 0264 GETMET R8 R7 K12 - 0x4C280000, // 0265 LDNIL R10 - 0x882C0917, // 0266 GETMBR R11 R4 K23 - 0xB8322600, // 0267 GETNGBL R12 K19 - 0x8C30194C, // 0268 GETMET R12 R12 K76 - 0x7C300200, // 0269 CALL R12 1 - 0x7C200800, // 026A CALL R8 4 - 0x80040E00, // 026B RET 1 R7 - 0x70020071, // 026C JMP #02DF - 0x541E002B, // 026D LDINT R7 44 - 0x1C1C0A07, // 026E EQ R7 R5 R7 - 0x781E001C, // 026F JMPF R7 #028D - 0x1C1C0D05, // 0270 EQ R7 R6 K5 - 0x781E0005, // 0271 JMPF R7 #0278 - 0x8C1C0906, // 0272 GETMET R7 R4 K6 - 0x8824090F, // 0273 GETMBR R9 R4 K15 - 0x5828000A, // 0274 LDCONST R10 K10 - 0x7C1C0600, // 0275 CALL R7 3 - 0x80040E00, // 0276 RET 1 R7 - 0x70020013, // 0277 JMP #028C - 0x1C1C0D0A, // 0278 EQ R7 R6 K10 - 0x781E0005, // 0279 JMPF R7 #0280 - 0x8C1C0906, // 027A GETMET R7 R4 K6 - 0x8824090F, // 027B GETMBR R9 R4 K15 - 0x542A0003, // 027C LDINT R10 4 - 0x7C1C0600, // 027D CALL R7 3 - 0x80040E00, // 027E RET 1 R7 - 0x7002000B, // 027F JMP #028C - 0x1C1C0D0E, // 0280 EQ R7 R6 K14 - 0x781E0009, // 0281 JMPF R7 #028C - 0x8C1C094D, // 0282 GETMET R7 R4 K77 - 0x7C1C0200, // 0283 CALL R7 1 - 0x8C200F0C, // 0284 GETMET R8 R7 K12 - 0x4C280000, // 0285 LDNIL R10 - 0x8C2C0906, // 0286 GETMET R11 R4 K6 - 0x8834090F, // 0287 GETMBR R13 R4 K15 - 0x543A0003, // 0288 LDINT R14 4 - 0x7C2C0600, // 0289 CALL R11 3 - 0x7C200600, // 028A CALL R8 3 - 0x80040E00, // 028B RET 1 R7 - 0x70020051, // 028C JMP #02DF - 0x541E0030, // 028D LDINT R7 49 - 0x1C1C0A07, // 028E EQ R7 R5 R7 - 0x781E0010, // 028F JMPF R7 #02A1 - 0x1C1C0D10, // 0290 EQ R7 R6 K16 - 0x781E0005, // 0291 JMPF R7 #0298 - 0x8C1C0906, // 0292 GETMET R7 R4 K6 - 0x8824090F, // 0293 GETMBR R9 R4 K15 - 0x542A001D, // 0294 LDINT R10 30 - 0x7C1C0600, // 0295 CALL R7 3 - 0x80040E00, // 0296 RET 1 R7 - 0x70020007, // 0297 JMP #02A0 - 0x541EFFFB, // 0298 LDINT R7 65532 - 0x1C1C0C07, // 0299 EQ R7 R6 R7 - 0x781E0004, // 029A JMPF R7 #02A0 - 0x8C1C0906, // 029B GETMET R7 R4 K6 - 0x8824092B, // 029C GETMBR R9 R4 K43 - 0x58280005, // 029D LDCONST R10 K5 - 0x7C1C0600, // 029E CALL R7 3 - 0x80040E00, // 029F RET 1 R7 - 0x7002003D, // 02A0 JMP #02DF - 0x541E001C, // 02A1 LDINT R7 29 - 0x1C1C0A07, // 02A2 EQ R7 R5 R7 - 0x781E0037, // 02A3 JMPF R7 #02DC - 0x1C1C0D05, // 02A4 EQ R7 R6 K5 - 0x781E0000, // 02A5 JMPF R7 #02A7 - 0x70020033, // 02A6 JMP #02DB - 0x1C1C0D0A, // 02A7 EQ R7 R6 K10 - 0x781E0013, // 02A8 JMPF R7 #02BD - 0x8C1C0912, // 02A9 GETMET R7 R4 K18 - 0x7C1C0200, // 02AA CALL R7 1 - 0x60200010, // 02AB GETGBL R8 G16 - 0x8C24014E, // 02AC GETMET R9 R0 K78 - 0x7C240200, // 02AD CALL R9 1 - 0x7C200200, // 02AE CALL R8 1 - 0xA8020007, // 02AF EXBLK 0 #02B8 - 0x5C241000, // 02B0 MOVE R9 R8 - 0x7C240000, // 02B1 CALL R9 0 - 0x8C280F0C, // 02B2 GETMET R10 R7 K12 - 0x4C300000, // 02B3 LDNIL R12 - 0x8834092B, // 02B4 GETMBR R13 R4 K43 - 0x5C381200, // 02B5 MOVE R14 R9 - 0x7C280800, // 02B6 CALL R10 4 - 0x7001FFF7, // 02B7 JMP #02B0 - 0x5820003A, // 02B8 LDCONST R8 K58 - 0xAC200200, // 02B9 CATCH R8 1 0 - 0xB0080000, // 02BA RAISE 2 R0 R0 - 0x80040E00, // 02BB RET 1 R7 - 0x7002001D, // 02BC JMP #02DB - 0x1C1C0D0E, // 02BD EQ R7 R6 K14 - 0x781E0003, // 02BE JMPF R7 #02C3 - 0x8C1C0912, // 02BF GETMET R7 R4 K18 - 0x7C1C0200, // 02C0 CALL R7 1 - 0x80040E00, // 02C1 RET 1 R7 - 0x70020017, // 02C2 JMP #02DB - 0x1C1C0D10, // 02C3 EQ R7 R6 K16 - 0x781E0015, // 02C4 JMPF R7 #02DB - 0x881C0134, // 02C5 GETMBR R7 R0 K52 - 0x8C1C0F4F, // 02C6 GETMET R7 R7 K79 - 0x50240200, // 02C7 LDBOOL R9 1 0 - 0x7C1C0400, // 02C8 CALL R7 2 - 0x8C200912, // 02C9 GETMET R8 R4 K18 - 0x7C200200, // 02CA CALL R8 1 - 0x60240010, // 02CB GETGBL R9 G16 - 0x5C280E00, // 02CC MOVE R10 R7 - 0x7C240200, // 02CD CALL R9 1 - 0xA8020007, // 02CE EXBLK 0 #02D7 - 0x5C281200, // 02CF MOVE R10 R9 - 0x7C280000, // 02D0 CALL R10 0 - 0x8C2C110C, // 02D1 GETMET R11 R8 K12 - 0x4C340000, // 02D2 LDNIL R13 - 0x8838090D, // 02D3 GETMBR R14 R4 K13 - 0x5C3C1400, // 02D4 MOVE R15 R10 - 0x7C2C0800, // 02D5 CALL R11 4 - 0x7001FFF7, // 02D6 JMP #02CF - 0x5824003A, // 02D7 LDCONST R9 K58 - 0xAC240200, // 02D8 CATCH R9 1 0 - 0xB0080000, // 02D9 RAISE 2 R0 R0 - 0x80041000, // 02DA RET 1 R8 - 0x70020002, // 02DB JMP #02DF - 0xB81E0200, // 02DC GETNGBL R7 K1 - 0x881C0F51, // 02DD GETMBR R7 R7 K81 - 0x900AA007, // 02DE SETMBR R2 K80 R7 - 0x80000000, // 02DF RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_core_init, /* 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(init), - /* K1 */ be_nested_str_weak(endpoints), - /* K2 */ be_nested_str_weak(ENDPOINTS), - /* K3 */ be_nested_str_weak(clusters), - /* K4 */ be_nested_str_weak(CLUSTERS), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x60080003, // 0000 GETGBL R2 G3 - 0x5C0C0000, // 0001 MOVE R3 R0 - 0x7C080200, // 0002 CALL R2 1 - 0x8C080500, // 0003 GETMET R2 R2 K0 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x88080102, // 0006 GETMBR R2 R0 K2 - 0x90020202, // 0007 SETMBR R0 K1 R2 - 0x88080104, // 0008 GETMBR R2 R0 K4 - 0x90020602, // 0009 SETMBR R0 K3 R2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified class: Matter_Plugin_core -********************************************************************/ -extern const bclass be_class_Matter_Plugin; -be_local_class(Matter_Plugin_core, - 0, - &be_class_Matter_Plugin, - be_nested_map(5, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ENDPOINTS, 3), 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_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_core_read_attribute_closure) }, - { be_const_key_weak(invoke_request, 1), be_const_closure(Matter_Plugin_core_invoke_request_closure) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_core_init_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(13, - ( (struct bmapnode*) &(const bmapnode[]) { - { 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(40, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(10, - ( (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(6), - be_const_int(7), - be_const_int(8), - be_const_int(9), - })) ) } )) }, - { be_const_key_int(43, -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(0), - be_const_int(1), - })) ) } )) }, - { be_const_key_int(29, -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(3), - })) ) } )) }, - { be_const_key_int(56, 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(1), - be_const_int(7), - })) ) } )) }, - { be_const_key_int(44, -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(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(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(60, -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(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, 6), 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(3), - be_const_int(65532), - })) ) } )) }, - { be_const_key_int(63, 7), 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_str_weak(Matter_Plugin_core) -); -/*******************************************************************/ - -void be_load_Matter_Plugin_core_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Plugin_core); - be_setglobal(vm, "Matter_Plugin_core"); - 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 45fcfe981..d35617f1e 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h @@ -6,6 +6,662 @@ extern const bclass be_class_Matter_Session; +/******************************************************************** +** Solidified function: get_i2r +********************************************************************/ +be_local_closure(Matter_Session_get_i2r, /* 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(i2rkey), + }), + be_str_weak(get_i2r), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tojson +********************************************************************/ +be_local_closure(Matter_Session_tojson, /* name */ + be_nested_proto( + 18, /* nstack */ + 1, /* 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(json), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(persist_pre), + /* K4 */ be_nested_str_weak(members), + /* K5 */ be_nested_str_weak(get), + /* K6 */ be_nested_str_weak(function), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(_), + /* K9 */ be_nested_str_weak(push), + /* K10 */ be_nested_str_weak(stop_iteration), + /* K11 */ be_nested_str_weak(matter), + /* K12 */ be_nested_str_weak(sort), + /* K13 */ be_nested_str_weak(_X24_X24), + /* K14 */ be_nested_str_weak(tob64), + /* K15 */ be_nested_str_weak(instance), + /* K16 */ be_nested_str_weak(format), + /* K17 */ be_nested_str_weak(_X25s_X3A_X25s), + /* K18 */ be_nested_str_weak(dump), + /* K19 */ be_nested_str_weak(persist_post), + /* K20 */ be_nested_str_weak(_X7B), + /* K21 */ be_nested_str_weak(concat), + /* K22 */ be_nested_str_weak(_X2C), + /* K23 */ be_nested_str_weak(_X7D), + }), + be_str_weak(tojson), + &be_const_str_solidified, + ( &(const binstruction[96]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA40E0400, // 0002 IMPORT R3 K2 + 0x8C100103, // 0003 GETMET R4 R0 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x60100012, // 0005 GETGBL R4 G18 + 0x7C100000, // 0006 CALL R4 0 + 0x60140010, // 0007 GETGBL R5 G16 + 0x8C180704, // 0008 GETMET R6 R3 K4 + 0x5C200000, // 0009 MOVE R8 R0 + 0x7C180400, // 000A CALL R6 2 + 0x7C140200, // 000B CALL R5 1 + 0xA8020011, // 000C EXBLK 0 #001F + 0x5C180A00, // 000D MOVE R6 R5 + 0x7C180000, // 000E CALL R6 0 + 0x8C1C0705, // 000F GETMET R7 R3 K5 + 0x5C240000, // 0010 MOVE R9 R0 + 0x5C280C00, // 0011 MOVE R10 R6 + 0x7C1C0600, // 0012 CALL R7 3 + 0x60200004, // 0013 GETGBL R8 G4 + 0x5C240E00, // 0014 MOVE R9 R7 + 0x7C200200, // 0015 CALL R8 1 + 0x20201106, // 0016 NE R8 R8 K6 + 0x78220005, // 0017 JMPF R8 #001E + 0x94200D07, // 0018 GETIDX R8 R6 K7 + 0x20201108, // 0019 NE R8 R8 K8 + 0x78220002, // 001A JMPF R8 #001E + 0x8C200909, // 001B GETMET R8 R4 K9 + 0x5C280C00, // 001C MOVE R10 R6 + 0x7C200400, // 001D CALL R8 2 + 0x7001FFED, // 001E JMP #000D + 0x5814000A, // 001F LDCONST R5 K10 + 0xAC140200, // 0020 CATCH R5 1 0 + 0xB0080000, // 0021 RAISE 2 R0 R0 + 0xB8161600, // 0022 GETNGBL R5 K11 + 0x8C140B0C, // 0023 GETMET R5 R5 K12 + 0x5C1C0800, // 0024 MOVE R7 R4 + 0x7C140400, // 0025 CALL R5 2 + 0x5C100A00, // 0026 MOVE R4 R5 + 0x60140012, // 0027 GETGBL R5 G18 + 0x7C140000, // 0028 CALL R5 0 + 0x60180010, // 0029 GETGBL R6 G16 + 0x5C1C0800, // 002A MOVE R7 R4 + 0x7C180200, // 002B CALL R6 1 + 0xA8020027, // 002C EXBLK 0 #0055 + 0x5C1C0C00, // 002D MOVE R7 R6 + 0x7C1C0000, // 002E CALL R7 0 + 0x8C200705, // 002F GETMET R8 R3 K5 + 0x5C280000, // 0030 MOVE R10 R0 + 0x5C2C0E00, // 0031 MOVE R11 R7 + 0x7C200600, // 0032 CALL R8 3 + 0x4C240000, // 0033 LDNIL R9 + 0x1C241009, // 0034 EQ R9 R8 R9 + 0x78260000, // 0035 JMPF R9 #0037 + 0x7001FFF5, // 0036 JMP #002D + 0x6024000F, // 0037 GETGBL R9 G15 + 0x5C281000, // 0038 MOVE R10 R8 + 0x602C0015, // 0039 GETGBL R11 G21 + 0x7C240400, // 003A CALL R9 2 + 0x78260004, // 003B JMPF R9 #0041 + 0x8C24110E, // 003C GETMET R9 R8 K14 + 0x7C240200, // 003D CALL R9 1 + 0x00261A09, // 003E ADD R9 K13 R9 + 0x5C201200, // 003F MOVE R8 R9 + 0x70020005, // 0040 JMP #0047 + 0x60240004, // 0041 GETGBL R9 G4 + 0x5C281000, // 0042 MOVE R10 R8 + 0x7C240200, // 0043 CALL R9 1 + 0x1C24130F, // 0044 EQ R9 R9 K15 + 0x78260000, // 0045 JMPF R9 #0047 + 0x7001FFE5, // 0046 JMP #002D + 0x8C240B09, // 0047 GETMET R9 R5 K9 + 0x8C2C0510, // 0048 GETMET R11 R2 K16 + 0x58340011, // 0049 LDCONST R13 K17 + 0x8C380312, // 004A GETMET R14 R1 K18 + 0x60400008, // 004B GETGBL R16 G8 + 0x5C440E00, // 004C MOVE R17 R7 + 0x7C400200, // 004D CALL R16 1 + 0x7C380400, // 004E CALL R14 2 + 0x8C3C0312, // 004F GETMET R15 R1 K18 + 0x5C441000, // 0050 MOVE R17 R8 + 0x7C3C0400, // 0051 CALL R15 2 + 0x7C2C0800, // 0052 CALL R11 4 + 0x7C240400, // 0053 CALL R9 2 + 0x7001FFD7, // 0054 JMP #002D + 0x5818000A, // 0055 LDCONST R6 K10 + 0xAC180200, // 0056 CATCH R6 1 0 + 0xB0080000, // 0057 RAISE 2 R0 R0 + 0x8C180113, // 0058 GETMET R6 R0 K19 + 0x7C180200, // 0059 CALL R6 1 + 0x8C180B15, // 005A GETMET R6 R5 K21 + 0x58200016, // 005B LDCONST R8 K22 + 0x7C180400, // 005C CALL R6 2 + 0x001A2806, // 005D ADD R6 K20 R6 + 0x00180D17, // 005E ADD R6 R6 K23 + 0x80040C00, // 005F RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: assign_fabric_index +********************************************************************/ +be_local_closure(Matter_Session_assign_fabric_index, /* 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(_fabric), + /* K1 */ be_nested_str_weak(get_fabric_index), + /* K2 */ be_nested_str_weak(set_fabric_index), + /* K3 */ be_nested_str_weak(_store), + /* K4 */ be_nested_str_weak(next_fabric_idx), + }), + be_str_weak(assign_fabric_index), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x4C080000, // 0003 LDNIL R2 + 0x1C040202, // 0004 EQ R1 R1 R2 + 0x78060005, // 0005 JMPF R1 #000C + 0x88040100, // 0006 GETMBR R1 R0 K0 + 0x8C040302, // 0007 GETMET R1 R1 K2 + 0x880C0103, // 0008 GETMBR R3 R0 K3 + 0x8C0C0704, // 0009 GETMET R3 R3 K4 + 0x7C0C0200, // 000A CALL R3 1 + 0x7C040400, // 000B CALL R1 2 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: persist_to_fabric +********************************************************************/ +be_local_closure(Matter_Session_persist_to_fabric, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(add_session), + }), + be_str_weak(persist_to_fabric), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_mode_PASE +********************************************************************/ +be_local_closure(Matter_Session_set_mode_PASE, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(set_mode), + /* K1 */ be_nested_str_weak(_PASE), + }), + be_str_weak(set_mode_PASE), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_label +********************************************************************/ +be_local_closure(Matter_Session_get_fabric_label, /* 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(_fabric), + /* K1 */ be_nested_str_weak(fabric_label), + }), + be_str_weak(get_fabric_label), + &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: get_device_id +********************************************************************/ +be_local_closure(Matter_Session_get_device_id, /* 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(_fabric), + /* K1 */ be_nested_str_weak(device_id), + }), + be_str_weak(get_device_id), + &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: get_r2i +********************************************************************/ +be_local_closure(Matter_Session_get_r2i, /* 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(r2ikey), + }), + be_str_weak(get_r2i), + &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_Session_init, /* 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[24]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(_store), + /* K2 */ be_nested_str_weak(mode), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(local_session_id), + /* K5 */ be_nested_str_weak(initiator_session_id), + /* K6 */ be_nested_str_weak(_counter_snd_impl), + /* K7 */ be_nested_str_weak(matter), + /* K8 */ be_nested_str_weak(Counter), + /* K9 */ be_nested_str_weak(_counter_rcv_impl), + /* K10 */ be_nested_str_weak(counter_rcv), + /* K11 */ be_nested_str_weak(counter_snd), + /* K12 */ be_nested_str_weak(next), + /* K13 */ be_nested_str_weak(_COUNTER_SND_INCR), + /* K14 */ be_nested_str_weak(_counter_insecure_rcv), + /* K15 */ be_nested_str_weak(_counter_insecure_snd), + /* K16 */ be_nested_str_weak(_breadcrumb), + /* K17 */ be_nested_str_weak(_exchange_id), + /* K18 */ be_nested_str_weak(random), + /* K19 */ be_const_int(2), + /* K20 */ be_nested_str_weak(get), + /* K21 */ be_nested_str_weak(_fabric), + /* K22 */ be_nested_str_weak(create_fabric), + /* K23 */ be_nested_str_weak(update), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[47]) { /* code */ + 0xA4160000, // 0000 IMPORT R5 K0 + 0x90020201, // 0001 SETMBR R0 K1 R1 + 0x90020503, // 0002 SETMBR R0 K2 K3 + 0x90020802, // 0003 SETMBR R0 K4 R2 + 0x90020A03, // 0004 SETMBR R0 K5 R3 + 0xB81A0E00, // 0005 GETNGBL R6 K7 + 0x8C180D08, // 0006 GETMET R6 R6 K8 + 0x7C180200, // 0007 CALL R6 1 + 0x90020C06, // 0008 SETMBR R0 K6 R6 + 0xB81A0E00, // 0009 GETNGBL R6 K7 + 0x8C180D08, // 000A GETMET R6 R6 K8 + 0x7C180200, // 000B CALL R6 1 + 0x90021206, // 000C SETMBR R0 K9 R6 + 0x90021503, // 000D SETMBR R0 K10 K3 + 0x88180106, // 000E GETMBR R6 R0 K6 + 0x8C180D0C, // 000F GETMET R6 R6 K12 + 0x7C180200, // 0010 CALL R6 1 + 0x881C010D, // 0011 GETMBR R7 R0 K13 + 0x00180C07, // 0012 ADD R6 R6 R7 + 0x90021606, // 0013 SETMBR R0 K11 R6 + 0xB81A0E00, // 0014 GETNGBL R6 K7 + 0x8C180D08, // 0015 GETMET R6 R6 K8 + 0x7C180200, // 0016 CALL R6 1 + 0x90021C06, // 0017 SETMBR R0 K14 R6 + 0xB81A0E00, // 0018 GETNGBL R6 K7 + 0x8C180D08, // 0019 GETMET R6 R6 K8 + 0x7C180200, // 001A CALL R6 1 + 0x90021E06, // 001B SETMBR R0 K15 R6 + 0x90022103, // 001C SETMBR R0 K16 K3 + 0x8C180B12, // 001D GETMET R6 R5 K18 + 0x58200013, // 001E LDCONST R8 K19 + 0x7C180400, // 001F CALL R6 2 + 0x8C180D14, // 0020 GETMET R6 R6 K20 + 0x58200003, // 0021 LDCONST R8 K3 + 0x58240013, // 0022 LDCONST R9 K19 + 0x7C180600, // 0023 CALL R6 3 + 0x90022206, // 0024 SETMBR R0 K17 R6 + 0x78120001, // 0025 JMPF R4 #0028 + 0x5C180800, // 0026 MOVE R6 R4 + 0x70020002, // 0027 JMP #002B + 0x88180101, // 0028 GETMBR R6 R0 K1 + 0x8C180D16, // 0029 GETMET R6 R6 K22 + 0x7C180200, // 002A CALL R6 1 + 0x90022A06, // 002B SETMBR R0 K21 R6 + 0x8C180117, // 002C GETMET R6 R0 K23 + 0x7C180200, // 002D CALL R6 1 + 0x80000000, // 002E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_mode +********************************************************************/ +be_local_closure(Matter_Session_get_mode, /* 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(mode), + }), + be_str_weak(get_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fromjson +********************************************************************/ +be_local_closure(Matter_Session_fromjson, /* name */ + be_nested_proto( + 17, /* nstack */ + 3, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Session), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(introspect), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Session), + /* K5 */ be_nested_str_weak(keys), + /* K6 */ be_nested_str_weak(find), + /* K7 */ be_nested_str_weak(0x), + /* K8 */ be_const_int(0), + /* K9 */ be_nested_str_weak(set), + /* K10 */ be_nested_str_weak(fromhex), + /* K11 */ be_const_int(2), + /* K12 */ be_const_int(2147483647), + /* K13 */ be_nested_str_weak(_X24_X24), + /* K14 */ be_nested_str_weak(fromb64), + /* K15 */ be_nested_str_weak(stop_iteration), + /* K16 */ be_nested_str_weak(hydrate_post), + }), + be_str_weak(fromjson), + &be_const_str_solidified, + ( &(const binstruction[75]) { /* code */ + 0x580C0000, // 0000 LDCONST R3 K0 + 0xA4120200, // 0001 IMPORT R4 K1 + 0xA4160400, // 0002 IMPORT R5 K2 + 0xB81A0600, // 0003 GETNGBL R6 K3 + 0x8C180D04, // 0004 GETMET R6 R6 K4 + 0x5C200000, // 0005 MOVE R8 R0 + 0x4C240000, // 0006 LDNIL R9 + 0x4C280000, // 0007 LDNIL R10 + 0x5C2C0400, // 0008 MOVE R11 R2 + 0x7C180A00, // 0009 CALL R6 5 + 0x601C0010, // 000A GETGBL R7 G16 + 0x8C200305, // 000B GETMET R8 R1 K5 + 0x7C200200, // 000C CALL R8 1 + 0x7C1C0200, // 000D CALL R7 1 + 0xA8020035, // 000E EXBLK 0 #0045 + 0x5C200E00, // 000F MOVE R8 R7 + 0x7C200000, // 0010 CALL R8 0 + 0x94240208, // 0011 GETIDX R9 R1 R8 + 0x60280004, // 0012 GETGBL R10 G4 + 0x5C2C1200, // 0013 MOVE R11 R9 + 0x7C280200, // 0014 CALL R10 1 + 0x1C281501, // 0015 EQ R10 R10 K1 + 0x782A0027, // 0016 JMPF R10 #003F + 0x8C280906, // 0017 GETMET R10 R4 K6 + 0x5C301200, // 0018 MOVE R12 R9 + 0x58340007, // 0019 LDCONST R13 K7 + 0x7C280600, // 001A CALL R10 3 + 0x1C281508, // 001B EQ R10 R10 K8 + 0x782A000A, // 001C JMPF R10 #0028 + 0x8C280B09, // 001D GETMET R10 R5 K9 + 0x5C300C00, // 001E MOVE R12 R6 + 0x5C341000, // 001F MOVE R13 R8 + 0x60380015, // 0020 GETGBL R14 G21 + 0x7C380000, // 0021 CALL R14 0 + 0x8C381D0A, // 0022 GETMET R14 R14 K10 + 0x4042170C, // 0023 CONNECT R16 K11 K12 + 0x94401210, // 0024 GETIDX R16 R9 R16 + 0x7C380400, // 0025 CALL R14 2 + 0x7C280800, // 0026 CALL R10 4 + 0x70020015, // 0027 JMP #003E + 0x8C280906, // 0028 GETMET R10 R4 K6 + 0x5C301200, // 0029 MOVE R12 R9 + 0x5834000D, // 002A LDCONST R13 K13 + 0x7C280600, // 002B CALL R10 3 + 0x1C281508, // 002C EQ R10 R10 K8 + 0x782A000A, // 002D JMPF R10 #0039 + 0x8C280B09, // 002E GETMET R10 R5 K9 + 0x5C300C00, // 002F MOVE R12 R6 + 0x5C341000, // 0030 MOVE R13 R8 + 0x60380015, // 0031 GETGBL R14 G21 + 0x7C380000, // 0032 CALL R14 0 + 0x8C381D0E, // 0033 GETMET R14 R14 K14 + 0x4042170C, // 0034 CONNECT R16 K11 K12 + 0x94401210, // 0035 GETIDX R16 R9 R16 + 0x7C380400, // 0036 CALL R14 2 + 0x7C280800, // 0037 CALL R10 4 + 0x70020004, // 0038 JMP #003E + 0x8C280B09, // 0039 GETMET R10 R5 K9 + 0x5C300C00, // 003A MOVE R12 R6 + 0x5C341000, // 003B MOVE R13 R8 + 0x5C381200, // 003C MOVE R14 R9 + 0x7C280800, // 003D CALL R10 4 + 0x70020004, // 003E JMP #0044 + 0x8C280B09, // 003F GETMET R10 R5 K9 + 0x5C300C00, // 0040 MOVE R12 R6 + 0x5C341000, // 0041 MOVE R13 R8 + 0x5C381200, // 0042 MOVE R14 R9 + 0x7C280800, // 0043 CALL R10 4 + 0x7001FFC9, // 0044 JMP #000F + 0x581C000F, // 0045 LDCONST R7 K15 + 0xAC1C0200, // 0046 CATCH R7 1 0 + 0xB0080000, // 0047 RAISE 2 R0 R0 + 0x8C1C0D10, // 0048 GETMET R7 R6 K16 + 0x7C1C0200, // 0049 CALL R7 1 + 0x80040C00, // 004A RET 1 R6 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_PASE +********************************************************************/ +be_local_closure(Matter_Session_is_PASE, /* 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(mode), + /* K1 */ be_nested_str_weak(_PASE), + }), + be_str_weak(is_PASE), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_admin_subject +********************************************************************/ +be_local_closure(Matter_Session_get_admin_subject, /* 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(_fabric), + /* K1 */ be_nested_str_weak(admin_subject), + }), + be_str_weak(get_admin_subject), + &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: save ********************************************************************/ @@ -20,8 +676,8 @@ be_local_closure(Matter_Session_save, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(__store), - /* K1 */ be_nested_str_weak(save), + /* K0 */ be_nested_str_weak(_store), + /* K1 */ be_nested_str_weak(save_fabrics), }), be_str_weak(save), &be_const_str_solidified, @@ -37,11 +693,598 @@ be_local_closure(Matter_Session_save, /* name */ /******************************************************************** -** Solidified function: set_expire_in_seconds +** Solidified function: get_ipk_epoch_key ********************************************************************/ -be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ +be_local_closure(Matter_Session_get_ipk_epoch_key, /* 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(_fabric), + /* K1 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(get_ipk_epoch_key), + &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: is_CASE +********************************************************************/ +be_local_closure(Matter_Session_is_CASE, /* 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(mode), + /* K1 */ be_nested_str_weak(_CASE), + }), + be_str_weak(is_CASE), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fabric_candidate +********************************************************************/ +be_local_closure(Matter_Session_fabric_candidate, /* 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[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(set_expire_in_seconds), + /* K2 */ be_nested_str_weak(assign_fabric_index), + /* K3 */ be_nested_str_weak(_store), + /* K4 */ be_nested_str_weak(add_fabric), + }), + be_str_weak(fabric_candidate), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x540E0077, // 0002 LDINT R3 120 + 0x7C040400, // 0003 CALL R1 2 + 0x8C040102, // 0004 GETMET R1 R0 K2 + 0x7C040200, // 0005 CALL R1 1 + 0x88040103, // 0006 GETMBR R1 R0 K3 + 0x8C040304, // 0007 GETMET R1 R1 K4 + 0x880C0100, // 0008 GETMBR R3 R0 K0 + 0x7C040400, // 0009 CALL R1 2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ipk_group_key +********************************************************************/ +be_local_closure(Matter_Session_get_ipk_group_key, /* 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[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(get_ipk_epoch_key), + /* K1 */ be_nested_str_weak(get_fabric_compressed), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(HKDF_SHA256), + /* K4 */ be_nested_str_weak(fromstring), + /* K5 */ be_nested_str_weak(_GROUP_KEY), + /* K6 */ be_nested_str_weak(derive), + }), + be_str_weak(get_ipk_group_key), + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x4C080000, // 0002 LDNIL R2 + 0x1C040202, // 0003 EQ R1 R1 R2 + 0x74060004, // 0004 JMPT R1 #000A + 0x8C040101, // 0005 GETMET R1 R0 K1 + 0x7C040200, // 0006 CALL R1 1 + 0x4C080000, // 0007 LDNIL R2 + 0x1C040202, // 0008 EQ R1 R1 R2 + 0x78060001, // 0009 JMPF R1 #000C + 0x4C040000, // 000A LDNIL R1 + 0x80040200, // 000B RET 1 R1 + 0xA4060400, // 000C IMPORT R1 K2 + 0x8C080303, // 000D GETMET R2 R1 K3 + 0x7C080200, // 000E CALL R2 1 + 0x600C0015, // 000F GETGBL R3 G21 + 0x7C0C0000, // 0010 CALL R3 0 + 0x8C0C0704, // 0011 GETMET R3 R3 K4 + 0x88140105, // 0012 GETMBR R5 R0 K5 + 0x7C0C0400, // 0013 CALL R3 2 + 0x8C100506, // 0014 GETMET R4 R2 K6 + 0x8C180100, // 0015 GETMET R6 R0 K0 + 0x7C180200, // 0016 CALL R6 1 + 0x8C1C0101, // 0017 GETMET R7 R0 K1 + 0x7C1C0200, // 0018 CALL R7 1 + 0x5C200600, // 0019 MOVE R8 R3 + 0x5426000F, // 001A LDINT R9 16 + 0x7C100A00, // 001B CALL R4 5 + 0x80040800, // 001C RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_noc +********************************************************************/ +be_local_closure(Matter_Session_get_noc, /* 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(_fabric), + /* K1 */ be_nested_str_weak(noc), + }), + be_str_weak(get_noc), + &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: fabric_completed +********************************************************************/ +be_local_closure(Matter_Session_fabric_completed, /* 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(_fabric), + /* K1 */ be_nested_str_weak(set_no_expiration), + /* K2 */ be_nested_str_weak(set_persist), + /* K3 */ be_nested_str_weak(assign_fabric_index), + /* K4 */ be_nested_str_weak(_store), + /* K5 */ be_nested_str_weak(add_fabric), + }), + be_str_weak(fabric_completed), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x88040100, // 0003 GETMBR R1 R0 K0 + 0x8C040302, // 0004 GETMET R1 R1 K2 + 0x500C0200, // 0005 LDBOOL R3 1 0 + 0x7C040400, // 0006 CALL R1 2 + 0x8C040103, // 0007 GETMET R1 R0 K3 + 0x7C040200, // 0008 CALL R1 1 + 0x88040104, // 0009 GETMBR R1 R0 K4 + 0x8C040305, // 000A GETMET R1 R1 K5 + 0x880C0100, // 000B GETMBR R3 R0 K0 + 0x7C040400, // 000C CALL R1 2 + 0x80000000, // 000D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_keys +********************************************************************/ +be_local_closure(Matter_Session_set_keys, /* name */ be_nested_proto( 6, /* nstack */ + 5, /* 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(i2rkey), + /* K1 */ be_nested_str_weak(_i2r_privacy), + /* K2 */ be_nested_str_weak(r2ikey), + /* K3 */ be_nested_str_weak(attestation_challenge), + /* K4 */ be_nested_str_weak(created), + }), + be_str_weak(set_keys), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x4C140000, // 0001 LDNIL R5 + 0x90020205, // 0002 SETMBR R0 K1 R5 + 0x90020402, // 0003 SETMBR R0 K2 R2 + 0x90020603, // 0004 SETMBR R0 K3 R3 + 0x90020804, // 0005 SETMBR R0 K4 R4 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: counter_snd_next +********************************************************************/ +be_local_closure(Matter_Session_counter_snd_next, /* 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[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(_counter_snd_impl), + /* K2 */ be_nested_str_weak(next), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Counter_snd_X3D_X25i), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_str_weak(matter), + /* K9 */ be_nested_str_weak(Counter), + /* K10 */ be_nested_str_weak(is_greater), + /* K11 */ be_nested_str_weak(counter_snd), + /* K12 */ be_nested_str_weak(_COUNTER_SND_INCR), + /* K13 */ be_nested_str_weak(does_persist), + /* K14 */ be_nested_str_weak(save), + }), + be_str_weak(counter_snd_next), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0xB80E0600, // 0004 GETNGBL R3 K3 + 0x8C0C0704, // 0005 GETMET R3 R3 K4 + 0x8C140305, // 0006 GETMET R5 R1 K5 + 0x581C0006, // 0007 LDCONST R7 K6 + 0x5C200400, // 0008 MOVE R8 R2 + 0x7C140600, // 0009 CALL R5 3 + 0x58180007, // 000A LDCONST R6 K7 + 0x7C0C0600, // 000B CALL R3 3 + 0xB80E1000, // 000C GETNGBL R3 K8 + 0x880C0709, // 000D GETMBR R3 R3 K9 + 0x8C0C070A, // 000E GETMET R3 R3 K10 + 0x5C140400, // 000F MOVE R5 R2 + 0x8818010B, // 0010 GETMBR R6 R0 K11 + 0x7C0C0600, // 0011 CALL R3 3 + 0x780E0007, // 0012 JMPF R3 #001B + 0x880C010C, // 0013 GETMBR R3 R0 K12 + 0x000C0403, // 0014 ADD R3 R2 R3 + 0x90021603, // 0015 SETMBR R0 K11 R3 + 0x8C0C010D, // 0016 GETMET R3 R0 K13 + 0x7C0C0200, // 0017 CALL R3 1 + 0x780E0001, // 0018 JMPF R3 #001B + 0x8C0C010E, // 0019 GETMET R3 R0 K14 + 0x7C0C0200, // 001A CALL R3 1 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_fabric_id +********************************************************************/ +be_local_closure(Matter_Session_get_fabric_id, /* 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(_fabric), + /* K1 */ be_nested_str_weak(fabric_id), + }), + be_str_weak(get_fabric_id), + &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: set_ca +********************************************************************/ +be_local_closure(Matter_Session_set_ca, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(set_ca), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x900A0201, // 0001 SETMBR R2 K1 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fabric_label +********************************************************************/ +be_local_closure(Matter_Session_set_fabric_label, /* name */ + be_nested_proto( + 4, /* 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(string), + /* K1 */ be_nested_str_weak(_fabric), + /* K2 */ be_nested_str_weak(fabric_label), + }), + be_str_weak(set_fabric_label), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x60080004, // 0000 GETGBL R2 G4 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x1C080500, // 0003 EQ R2 R2 K0 + 0x780A0001, // 0004 JMPF R2 #0007 + 0x88080101, // 0005 GETMBR R2 R0 K1 + 0x900A0401, // 0006 SETMBR R2 K2 R1 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ca +********************************************************************/ +be_local_closure(Matter_Session_get_ca, /* 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(_fabric), + /* K1 */ be_nested_str_weak(root_ca_certificate), + }), + be_str_weak(get_ca), + &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: set_mode +********************************************************************/ +be_local_closure(Matter_Session_set_mode, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(mode), + }), + be_str_weak(set_mode), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ac +********************************************************************/ +be_local_closure(Matter_Session_get_ac, /* 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(attestation_challenge), + }), + be_str_weak(get_ac), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: hydrate_post +********************************************************************/ +be_local_closure(Matter_Session_hydrate_post, /* 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(_counter_snd_impl), + /* K1 */ be_nested_str_weak(reset), + /* K2 */ be_nested_str_weak(counter_snd), + /* K3 */ be_nested_str_weak(_counter_rcv_impl), + /* K4 */ be_nested_str_weak(counter_rcv), + /* K5 */ be_nested_str_weak(val), + }), + be_str_weak(hydrate_post), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x7C040400, // 0003 CALL R1 2 + 0x88040103, // 0004 GETMBR R1 R0 K3 + 0x8C040301, // 0005 GETMET R1 R1 K1 + 0x880C0104, // 0006 GETMBR R3 R0 K4 + 0x7C040400, // 0007 CALL R1 2 + 0x88040100, // 0008 GETMBR R1 R0 K0 + 0x8C040305, // 0009 GETMET R1 R1 K5 + 0x7C040200, // 000A CALL R1 1 + 0x90020401, // 000B SETMBR R0 K2 R1 + 0x88040103, // 000C GETMBR R1 R0 K3 + 0x8C040305, // 000D GETMET R1 R1 K5 + 0x7C040200, // 000E CALL R1 1 + 0x90020801, // 000F SETMBR R0 K4 R1 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_icac +********************************************************************/ +be_local_closure(Matter_Session_get_icac, /* 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(_fabric), + /* K1 */ be_nested_str_weak(icac), + }), + be_str_weak(get_icac), + &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: set_admin_subject_vendor +********************************************************************/ +be_local_closure(Matter_Session_set_admin_subject_vendor, /* name */ + be_nested_proto( + 4, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -49,30 +1292,153 @@ be_local_closure(Matter_Session_set_expire_in_seconds, /* name */ 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(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(set_expire_time), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(admin_subject), + /* K2 */ be_nested_str_weak(admin_vendor), }), - be_str_weak(set_expire_in_seconds), + be_str_weak(set_admin_subject_vendor), &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0203, // 0001 EQ R3 R1 R3 - 0x780E0000, // 0002 JMPF R3 #0004 - 0x80000600, // 0003 RET 0 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C0C0403, // 0005 EQ R3 R2 R3 - 0x780E0003, // 0006 JMPF R3 #000B - 0xB80E0000, // 0007 GETNGBL R3 K0 - 0x8C0C0701, // 0008 GETMET R3 R3 K1 - 0x7C0C0200, // 0009 CALL R3 1 - 0x94080702, // 000A GETIDX R2 R3 K2 - 0x8C0C0103, // 000B GETMET R3 R0 K3 - 0x00140401, // 000C ADD R5 R2 R1 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 + ( &(const binstruction[ 5]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x900E0201, // 0001 SETMBR R3 K1 R1 + 0x880C0100, // 0002 GETMBR R3 R0 K0 + 0x900E0402, // 0003 SETMBR R3 K2 R2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ipk_epoch_key +********************************************************************/ +be_local_closure(Matter_Session_set_ipk_epoch_key, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(ipk_epoch_key), + }), + be_str_weak(set_ipk_epoch_key), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x900A0201, // 0001 SETMBR R2 K1 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: before_remove +********************************************************************/ +be_local_closure(Matter_Session_before_remove, /* 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[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(format), + /* K4 */ be_nested_str_weak(MTR_X3A_X20_X2DSession_X20_X20_X20_X28_X256i_X29_X20_X28removed_X29), + /* K5 */ be_nested_str_weak(local_session_id), + /* K6 */ be_const_int(3), + }), + be_str_weak(before_remove), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x8C100303, // 0003 GETMET R4 R1 K3 + 0x58180004, // 0004 LDCONST R6 K4 + 0x881C0105, // 0005 GETMBR R7 R0 K5 + 0x7C100600, // 0006 CALL R4 3 + 0x58140006, // 0007 LDCONST R5 K6 + 0x7C080600, // 0008 CALL R2 3 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update +********************************************************************/ +be_local_closure(Matter_Session_update, /* 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(last_used), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(rtc), + /* K3 */ be_nested_str_weak(utc), + }), + be_str_weak(update), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0xB8060200, // 0000 GETNGBL R1 K1 + 0x8C040302, // 0001 GETMET R1 R1 K2 + 0x7C040200, // 0002 CALL R1 1 + 0x94040303, // 0003 GETIDX R1 R1 K3 + 0x90020001, // 0004 SETMBR R0 K0 R1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_mode_CASE +********************************************************************/ +be_local_closure(Matter_Session_set_mode_CASE, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(set_mode), + /* K1 */ be_nested_str_weak(_CASE), + }), + be_str_weak(set_mode_CASE), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 }) ) ); @@ -133,55 +1499,11 @@ be_local_closure(Matter_Session_get_i2r_privacy, /* name */ /******************************************************************** -** Solidified function: has_expired +** Solidified function: get_ca_pub ********************************************************************/ -be_local_closure(Matter_Session_has_expired, /* name */ +be_local_closure(Matter_Session_get_ca_pub, /* name */ be_nested_proto( - 4, /* 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(tasmota), - /* K1 */ be_nested_str_weak(rtc), - /* K2 */ be_nested_str_weak(utc), - /* K3 */ be_nested_str_weak(expiration), - }), - be_str_weak(has_expired), - &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0003, // 0002 JMPF R2 #0007 - 0xB80A0000, // 0003 GETNGBL R2 K0 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x7C080200, // 0005 CALL R2 1 - 0x94040502, // 0006 GETIDX R1 R2 K2 - 0x88080103, // 0007 GETMBR R2 R0 K3 - 0x4C0C0000, // 0008 LDNIL R3 - 0x20080403, // 0009 NE R2 R2 R3 - 0x780A0002, // 000A JMPF R2 #000E - 0x88080103, // 000B GETMBR R2 R0 K3 - 0x28080202, // 000C GE R2 R1 R2 - 0x80040400, // 000D RET 1 R2 - 0x50080000, // 000E LDBOOL R2 0 0 - 0x80040400, // 000F RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_icac -********************************************************************/ -be_local_closure(Matter_Session_get_icac, /* name */ - be_nested_proto( - 2, /* nstack */ + 3, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -189,68 +1511,17 @@ be_local_closure(Matter_Session_get_icac, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(icac), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(get_ca_pub), }), - be_str_weak(get_icac), + be_str_weak(get_ca_pub), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ + ( &(const binstruction[ 4]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_deviceid -********************************************************************/ -be_local_closure(Matter_Session_get_deviceid, /* 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(deviceid), - }), - be_str_weak(get_deviceid), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_noc -********************************************************************/ -be_local_closure(Matter_Session_get_noc, /* 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(noc), - }), - be_str_weak(get_noc), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 }) ) ); @@ -262,7 +1533,7 @@ be_local_closure(Matter_Session_get_noc, /* name */ ********************************************************************/ be_local_closure(Matter_Session_close, /* name */ be_nested_proto( - 9, /* nstack */ + 8, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -270,480 +1541,93 @@ be_local_closure(Matter_Session_close, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[24]) { /* constants */ - /* K0 */ be_nested_str_weak(_persist), - /* K1 */ be_nested_str_weak(local_session_id), - /* K2 */ be_nested_str_weak(_future_local_session_id), - /* K3 */ be_nested_str_weak(initiator_session_id), - /* K4 */ be_nested_str_weak(_future_initiator_session_id), - /* K5 */ be_nested_str_weak(source_node_id), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(reset), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(i2rkey), - /* K10 */ be_nested_str_weak(_i2r_privacy), - /* K11 */ be_nested_str_weak(r2ikey), - /* K12 */ be_nested_str_weak(attestation_challenge), - /* K13 */ be_nested_str_weak(fabric_label), - /* K14 */ be_nested_str_weak(), + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_nested_str_weak(local_session_id), + /* K1 */ be_nested_str_weak(__future_local_session_id), + /* K2 */ be_nested_str_weak(initiator_session_id), + /* K3 */ be_nested_str_weak(__future_initiator_session_id), + /* K4 */ be_nested_str_weak(_counter_rcv_impl), + /* K5 */ be_nested_str_weak(reset), + /* K6 */ be_nested_str_weak(_counter_snd_impl), + /* K7 */ be_nested_str_weak(counter_rcv), + /* K8 */ be_const_int(0), + /* K9 */ be_nested_str_weak(counter_snd), + /* K10 */ be_nested_str_weak(next), + /* K11 */ be_nested_str_weak(i2rkey), + /* K12 */ be_nested_str_weak(_i2r_privacy), + /* K13 */ be_nested_str_weak(r2ikey), + /* K14 */ be_nested_str_weak(attestation_challenge), /* K15 */ be_nested_str_weak(introspect), /* K16 */ be_nested_str_weak(members), /* K17 */ be_nested_str_weak(get), /* K18 */ be_nested_str_weak(function), /* K19 */ be_nested_str_weak(instance), - /* K20 */ be_const_int(0), - /* K21 */ be_nested_str_weak(_), - /* K22 */ be_const_int(1), - /* K23 */ be_nested_str_weak(stop_iteration), + /* K20 */ be_nested_str_weak(_), + /* K21 */ be_const_int(1), + /* K22 */ be_nested_str_weak(stop_iteration), }), be_str_weak(close), &be_const_str_solidified, ( &(const binstruction[59]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88080102, // 0001 GETMBR R2 R0 K2 - 0x90020202, // 0002 SETMBR R0 K1 R2 - 0x88080104, // 0003 GETMBR R2 R0 K4 - 0x90020602, // 0004 SETMBR R0 K3 R2 - 0x4C080000, // 0005 LDNIL R2 - 0x90020A02, // 0006 SETMBR R0 K5 R2 - 0x88080106, // 0007 GETMBR R2 R0 K6 - 0x8C080507, // 0008 GETMET R2 R2 K7 - 0x7C080200, // 0009 CALL R2 1 - 0x88080108, // 000A GETMBR R2 R0 K8 - 0x8C080507, // 000B GETMET R2 R2 K7 - 0x7C080200, // 000C CALL R2 1 - 0x4C080000, // 000D LDNIL R2 - 0x90021202, // 000E SETMBR R0 K9 R2 - 0x4C080000, // 000F LDNIL R2 - 0x90021402, // 0010 SETMBR R0 K10 R2 - 0x4C080000, // 0011 LDNIL R2 - 0x90021602, // 0012 SETMBR R0 K11 R2 - 0x4C080000, // 0013 LDNIL R2 - 0x90021802, // 0014 SETMBR R0 K12 R2 - 0x90021B0E, // 0015 SETMBR R0 K13 K14 - 0xA40A1E00, // 0016 IMPORT R2 K15 - 0x600C0010, // 0017 GETGBL R3 G16 - 0x8C100510, // 0018 GETMET R4 R2 K16 - 0x5C180000, // 0019 MOVE R6 R0 - 0x7C100400, // 001A CALL R4 2 - 0x7C0C0200, // 001B CALL R3 1 - 0xA8020018, // 001C EXBLK 0 #0036 - 0x5C100600, // 001D MOVE R4 R3 - 0x7C100000, // 001E CALL R4 0 - 0x8C140511, // 001F GETMET R5 R2 K17 - 0x5C1C0000, // 0020 MOVE R7 R0 - 0x5C200800, // 0021 MOVE R8 R4 - 0x7C140600, // 0022 CALL R5 3 - 0x60180004, // 0023 GETGBL R6 G4 - 0x5C1C0A00, // 0024 MOVE R7 R5 - 0x7C180200, // 0025 CALL R6 1 - 0x20180D12, // 0026 NE R6 R6 K18 - 0x781A000C, // 0027 JMPF R6 #0035 - 0x60180004, // 0028 GETGBL R6 G4 - 0x5C1C0A00, // 0029 MOVE R7 R5 - 0x7C180200, // 002A CALL R6 1 - 0x20180D13, // 002B NE R6 R6 K19 - 0x781A0007, // 002C JMPF R6 #0035 - 0x94180914, // 002D GETIDX R6 R4 K20 - 0x1C180D15, // 002E EQ R6 R6 K21 - 0x781A0004, // 002F JMPF R6 #0035 - 0x94180916, // 0030 GETIDX R6 R4 K22 - 0x20180D15, // 0031 NE R6 R6 K21 - 0x781A0001, // 0032 JMPF R6 #0035 - 0x4C180000, // 0033 LDNIL R6 - 0x90000806, // 0034 SETMBR R0 R4 R6 - 0x7001FFE6, // 0035 JMP #001D - 0x580C0017, // 0036 LDCONST R3 K23 - 0xAC0C0200, // 0037 CATCH R3 1 0 - 0xB0080000, // 0038 RAISE 2 R0 R0 - 0x90020001, // 0039 SETMBR R0 K0 R1 - 0x80000000, // 003A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: fromjson -********************************************************************/ -be_local_closure(Matter_Session_fromjson, /* name */ - be_nested_proto( - 16, /* nstack */ - 2, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[19]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Session), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(introspect), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(Session), - /* K5 */ be_nested_str_weak(keys), - /* K6 */ be_nested_str_weak(counter_rcv), - /* K7 */ be_nested_str_weak(reset), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(find), - /* K10 */ be_nested_str_weak(0x), - /* K11 */ be_const_int(0), - /* K12 */ be_nested_str_weak(set), - /* K13 */ be_nested_str_weak(fromhex), - /* K14 */ be_const_int(2), - /* K15 */ be_const_int(2147483647), - /* K16 */ be_nested_str_weak(_X24_X24), - /* K17 */ be_nested_str_weak(fromb64), - /* K18 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(fromjson), - &be_const_str_solidified, - ( &(const binstruction[88]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0xA4120400, // 0002 IMPORT R4 K2 - 0xB8160600, // 0003 GETNGBL R5 K3 - 0x8C140B04, // 0004 GETMET R5 R5 K4 - 0x5C1C0000, // 0005 MOVE R7 R0 - 0x7C140400, // 0006 CALL R5 2 - 0x60180010, // 0007 GETGBL R6 G16 - 0x8C1C0305, // 0008 GETMET R7 R1 K5 - 0x7C1C0200, // 0009 CALL R7 1 - 0x7C180200, // 000A CALL R6 1 - 0xA8020047, // 000B EXBLK 0 #0054 - 0x5C1C0C00, // 000C MOVE R7 R6 - 0x7C1C0000, // 000D CALL R7 0 - 0x94200207, // 000E GETIDX R8 R1 R7 - 0x1C240F06, // 000F EQ R9 R7 K6 - 0x78260006, // 0010 JMPF R9 #0018 - 0x88240B06, // 0011 GETMBR R9 R5 K6 - 0x8C241307, // 0012 GETMET R9 R9 K7 - 0x602C0009, // 0013 GETGBL R11 G9 - 0x5C301000, // 0014 MOVE R12 R8 - 0x7C2C0200, // 0015 CALL R11 1 - 0x7C240400, // 0016 CALL R9 2 - 0x7002003A, // 0017 JMP #0053 - 0x1C240F08, // 0018 EQ R9 R7 K8 - 0x78260006, // 0019 JMPF R9 #0021 - 0x88240B08, // 001A GETMBR R9 R5 K8 - 0x8C241307, // 001B GETMET R9 R9 K7 - 0x602C0009, // 001C GETGBL R11 G9 - 0x5C301000, // 001D MOVE R12 R8 - 0x7C2C0200, // 001E CALL R11 1 - 0x7C240400, // 001F CALL R9 2 - 0x70020031, // 0020 JMP #0053 - 0x60240004, // 0021 GETGBL R9 G4 - 0x5C281000, // 0022 MOVE R10 R8 - 0x7C240200, // 0023 CALL R9 1 - 0x1C241301, // 0024 EQ R9 R9 K1 - 0x78260027, // 0025 JMPF R9 #004E - 0x8C240709, // 0026 GETMET R9 R3 K9 - 0x5C2C1000, // 0027 MOVE R11 R8 - 0x5830000A, // 0028 LDCONST R12 K10 - 0x7C240600, // 0029 CALL R9 3 - 0x1C24130B, // 002A EQ R9 R9 K11 - 0x7826000A, // 002B JMPF R9 #0037 - 0x8C24090C, // 002C GETMET R9 R4 K12 - 0x5C2C0A00, // 002D MOVE R11 R5 - 0x5C300E00, // 002E MOVE R12 R7 - 0x60340015, // 002F GETGBL R13 G21 - 0x7C340000, // 0030 CALL R13 0 - 0x8C341B0D, // 0031 GETMET R13 R13 K13 - 0x403E1D0F, // 0032 CONNECT R15 K14 K15 - 0x943C100F, // 0033 GETIDX R15 R8 R15 - 0x7C340400, // 0034 CALL R13 2 - 0x7C240800, // 0035 CALL R9 4 - 0x70020015, // 0036 JMP #004D - 0x8C240709, // 0037 GETMET R9 R3 K9 - 0x5C2C1000, // 0038 MOVE R11 R8 - 0x58300010, // 0039 LDCONST R12 K16 - 0x7C240600, // 003A CALL R9 3 - 0x1C24130B, // 003B EQ R9 R9 K11 - 0x7826000A, // 003C JMPF R9 #0048 - 0x8C24090C, // 003D GETMET R9 R4 K12 - 0x5C2C0A00, // 003E MOVE R11 R5 - 0x5C300E00, // 003F MOVE R12 R7 - 0x60340015, // 0040 GETGBL R13 G21 - 0x7C340000, // 0041 CALL R13 0 - 0x8C341B11, // 0042 GETMET R13 R13 K17 - 0x403E1D0F, // 0043 CONNECT R15 K14 K15 - 0x943C100F, // 0044 GETIDX R15 R8 R15 - 0x7C340400, // 0045 CALL R13 2 - 0x7C240800, // 0046 CALL R9 4 - 0x70020004, // 0047 JMP #004D - 0x8C24090C, // 0048 GETMET R9 R4 K12 - 0x5C2C0A00, // 0049 MOVE R11 R5 - 0x5C300E00, // 004A MOVE R12 R7 - 0x5C341000, // 004B MOVE R13 R8 - 0x7C240800, // 004C CALL R9 4 - 0x70020004, // 004D JMP #0053 - 0x8C24090C, // 004E GETMET R9 R4 K12 - 0x5C2C0A00, // 004F MOVE R11 R5 - 0x5C300E00, // 0050 MOVE R12 R7 - 0x5C341000, // 0051 MOVE R13 R8 - 0x7C240800, // 0052 CALL R9 4 - 0x7001FFB7, // 0053 JMP #000C - 0x58180012, // 0054 LDCONST R6 K18 - 0xAC180200, // 0055 CATCH R6 1 0 - 0xB0080000, // 0056 RAISE 2 R0 R0 - 0x80040A00, // 0057 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_epoch_key -********************************************************************/ -be_local_closure(Matter_Session_get_ipk_epoch_key, /* 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(ipk_epoch_key), - }), - be_str_weak(get_ipk_epoch_key), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: tojson -********************************************************************/ -be_local_closure(Matter_Session_tojson, /* name */ - be_nested_proto( - 18, /* nstack */ - 1, /* 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(json), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(introspect), - /* K3 */ be_nested_str_weak(members), - /* K4 */ be_nested_str_weak(get), - /* K5 */ be_nested_str_weak(function), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(_), - /* K8 */ be_nested_str_weak(push), - /* K9 */ be_nested_str_weak(stop_iteration), - /* K10 */ be_nested_str_weak(matter), - /* K11 */ be_nested_str_weak(sort), - /* K12 */ be_nested_str_weak(counter_rcv), - /* K13 */ be_nested_str_weak(val), - /* K14 */ be_nested_str_weak(counter_snd), - /* K15 */ be_nested_str_weak(_X24_X24), - /* K16 */ be_nested_str_weak(tob64), - /* K17 */ be_nested_str_weak(format), - /* K18 */ be_nested_str_weak(_X25s_X3A_X25s), - /* K19 */ be_nested_str_weak(dump), - /* K20 */ be_nested_str_weak(_X7B), - /* K21 */ be_nested_str_weak(concat), - /* K22 */ be_nested_str_weak(_X2C), - /* K23 */ be_nested_str_weak(_X7D), - }), - be_str_weak(tojson), - &be_const_str_solidified, - ( &(const binstruction[98]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA40A0200, // 0001 IMPORT R2 K1 - 0xA40E0400, // 0002 IMPORT R3 K2 - 0x60100012, // 0003 GETGBL R4 G18 - 0x7C100000, // 0004 CALL R4 0 - 0x60140010, // 0005 GETGBL R5 G16 - 0x8C180703, // 0006 GETMET R6 R3 K3 - 0x5C200000, // 0007 MOVE R8 R0 - 0x7C180400, // 0008 CALL R6 2 - 0x7C140200, // 0009 CALL R5 1 - 0xA8020011, // 000A EXBLK 0 #001D - 0x5C180A00, // 000B MOVE R6 R5 - 0x7C180000, // 000C CALL R6 0 - 0x8C1C0704, // 000D GETMET R7 R3 K4 - 0x5C240000, // 000E MOVE R9 R0 - 0x5C280C00, // 000F MOVE R10 R6 - 0x7C1C0600, // 0010 CALL R7 3 - 0x60200004, // 0011 GETGBL R8 G4 - 0x5C240E00, // 0012 MOVE R9 R7 - 0x7C200200, // 0013 CALL R8 1 - 0x20201105, // 0014 NE R8 R8 K5 - 0x78220005, // 0015 JMPF R8 #001C - 0x94200D06, // 0016 GETIDX R8 R6 K6 - 0x20201107, // 0017 NE R8 R8 K7 - 0x78220002, // 0018 JMPF R8 #001C - 0x8C200908, // 0019 GETMET R8 R4 K8 - 0x5C280C00, // 001A MOVE R10 R6 - 0x7C200400, // 001B CALL R8 2 - 0x7001FFED, // 001C JMP #000B - 0x58140009, // 001D LDCONST R5 K9 - 0xAC140200, // 001E CATCH R5 1 0 - 0xB0080000, // 001F RAISE 2 R0 R0 - 0xB8161400, // 0020 GETNGBL R5 K10 - 0x8C140B0B, // 0021 GETMET R5 R5 K11 - 0x5C1C0800, // 0022 MOVE R7 R4 - 0x7C140400, // 0023 CALL R5 2 - 0x5C100A00, // 0024 MOVE R4 R5 - 0x60140012, // 0025 GETGBL R5 G18 - 0x7C140000, // 0026 CALL R5 0 - 0x60180010, // 0027 GETGBL R6 G16 - 0x5C1C0800, // 0028 MOVE R7 R4 - 0x7C180200, // 0029 CALL R6 1 - 0xA802002D, // 002A EXBLK 0 #0059 - 0x5C1C0C00, // 002B MOVE R7 R6 - 0x7C1C0000, // 002C CALL R7 0 - 0x8C200704, // 002D GETMET R8 R3 K4 - 0x5C280000, // 002E MOVE R10 R0 - 0x5C2C0E00, // 002F MOVE R11 R7 - 0x7C200600, // 0030 CALL R8 3 - 0x4C240000, // 0031 LDNIL R9 - 0x1C241009, // 0032 EQ R9 R8 R9 - 0x78260000, // 0033 JMPF R9 #0035 - 0x7001FFF5, // 0034 JMP #002B - 0x1C240F0C, // 0035 EQ R9 R7 K12 - 0x78260003, // 0036 JMPF R9 #003B - 0x8C24110D, // 0037 GETMET R9 R8 K13 - 0x7C240200, // 0038 CALL R9 1 - 0x5C201200, // 0039 MOVE R8 R9 - 0x70020006, // 003A JMP #0042 - 0x1C240F0E, // 003B EQ R9 R7 K14 - 0x78260004, // 003C JMPF R9 #0042 - 0x8C24110D, // 003D GETMET R9 R8 K13 - 0x7C240200, // 003E CALL R9 1 - 0x542A00FF, // 003F LDINT R10 256 - 0x0024120A, // 0040 ADD R9 R9 R10 - 0x5C201200, // 0041 MOVE R8 R9 - 0x6024000F, // 0042 GETGBL R9 G15 - 0x5C281000, // 0043 MOVE R10 R8 - 0x602C0015, // 0044 GETGBL R11 G21 - 0x7C240400, // 0045 CALL R9 2 - 0x78260003, // 0046 JMPF R9 #004B - 0x8C241110, // 0047 GETMET R9 R8 K16 - 0x7C240200, // 0048 CALL R9 1 - 0x00261E09, // 0049 ADD R9 K15 R9 - 0x5C201200, // 004A MOVE R8 R9 - 0x8C240B08, // 004B GETMET R9 R5 K8 - 0x8C2C0511, // 004C GETMET R11 R2 K17 - 0x58340012, // 004D LDCONST R13 K18 - 0x8C380313, // 004E GETMET R14 R1 K19 - 0x60400008, // 004F GETGBL R16 G8 - 0x5C440E00, // 0050 MOVE R17 R7 - 0x7C400200, // 0051 CALL R16 1 - 0x7C380400, // 0052 CALL R14 2 - 0x8C3C0313, // 0053 GETMET R15 R1 K19 - 0x5C441000, // 0054 MOVE R17 R8 - 0x7C3C0400, // 0055 CALL R15 2 - 0x7C2C0800, // 0056 CALL R11 4 - 0x7C240400, // 0057 CALL R9 2 - 0x7001FFD1, // 0058 JMP #002B - 0x58180009, // 0059 LDCONST R6 K9 - 0xAC180200, // 005A CATCH R6 1 0 - 0xB0080000, // 005B RAISE 2 R0 R0 - 0x8C180B15, // 005C GETMET R6 R5 K21 - 0x58200016, // 005D LDCONST R8 K22 - 0x7C180400, // 005E CALL R6 2 - 0x001A2806, // 005F ADD R6 K20 R6 - 0x00180D17, // 0060 ADD R6 R6 K23 - 0x80040C00, // 0061 RET 1 R6 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ac -********************************************************************/ -be_local_closure(Matter_Session_get_ac, /* 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(attestation_challenge), - }), - be_str_weak(get_ac), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_no_expiration -********************************************************************/ -be_local_closure(Matter_Session_set_no_expiration, /* 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(expiration), - }), - be_str_weak(set_no_expiration), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x4C040000, // 0000 LDNIL R1 + 0x88040101, // 0000 GETMBR R1 R0 K1 0x90020001, // 0001 SETMBR R0 K0 R1 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_r2i -********************************************************************/ -be_local_closure(Matter_Session_get_r2i, /* 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(r2ikey), - }), - be_str_weak(get_r2i), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + 0x88040103, // 0002 GETMBR R1 R0 K3 + 0x90020401, // 0003 SETMBR R0 K2 R1 + 0x88040104, // 0004 GETMBR R1 R0 K4 + 0x8C040305, // 0005 GETMET R1 R1 K5 + 0x7C040200, // 0006 CALL R1 1 + 0x88040106, // 0007 GETMBR R1 R0 K6 + 0x8C040305, // 0008 GETMET R1 R1 K5 + 0x7C040200, // 0009 CALL R1 1 + 0x90020F08, // 000A SETMBR R0 K7 K8 + 0x88040106, // 000B GETMBR R1 R0 K6 + 0x8C04030A, // 000C GETMET R1 R1 K10 + 0x7C040200, // 000D CALL R1 1 + 0x90021201, // 000E SETMBR R0 K9 R1 + 0x4C040000, // 000F LDNIL R1 + 0x90021601, // 0010 SETMBR R0 K11 R1 + 0x4C040000, // 0011 LDNIL R1 + 0x90021801, // 0012 SETMBR R0 K12 R1 + 0x4C040000, // 0013 LDNIL R1 + 0x90021A01, // 0014 SETMBR R0 K13 R1 + 0x4C040000, // 0015 LDNIL R1 + 0x90021C01, // 0016 SETMBR R0 K14 R1 + 0xA4061E00, // 0017 IMPORT R1 K15 + 0x60080010, // 0018 GETGBL R2 G16 + 0x8C0C0310, // 0019 GETMET R3 R1 K16 + 0x5C140000, // 001A MOVE R5 R0 + 0x7C0C0400, // 001B CALL R3 2 + 0x7C080200, // 001C CALL R2 1 + 0xA8020018, // 001D EXBLK 0 #0037 + 0x5C0C0400, // 001E MOVE R3 R2 + 0x7C0C0000, // 001F CALL R3 0 + 0x8C100311, // 0020 GETMET R4 R1 K17 + 0x5C180000, // 0021 MOVE R6 R0 + 0x5C1C0600, // 0022 MOVE R7 R3 + 0x7C100600, // 0023 CALL R4 3 + 0x60140004, // 0024 GETGBL R5 G4 + 0x5C180800, // 0025 MOVE R6 R4 + 0x7C140200, // 0026 CALL R5 1 + 0x20140B12, // 0027 NE R5 R5 K18 + 0x7816000C, // 0028 JMPF R5 #0036 + 0x60140004, // 0029 GETGBL R5 G4 + 0x5C180800, // 002A MOVE R6 R4 + 0x7C140200, // 002B CALL R5 1 + 0x20140B13, // 002C NE R5 R5 K19 + 0x78160007, // 002D JMPF R5 #0036 + 0x94140708, // 002E GETIDX R5 R3 K8 + 0x1C140B14, // 002F EQ R5 R5 K20 + 0x78160004, // 0030 JMPF R5 #0036 + 0x94140715, // 0031 GETIDX R5 R3 K21 + 0x1C140B14, // 0032 EQ R5 R5 K20 + 0x78160001, // 0033 JMPF R5 #0036 + 0x4C140000, // 0034 LDNIL R5 + 0x90000605, // 0035 SETMBR R0 R3 R5 + 0x7001FFE6, // 0036 JMP #001E + 0x58080016, // 0037 LDCONST R2 K22 + 0xAC080200, // 0038 CATCH R2 1 0 + 0xB0080000, // 0039 RAISE 2 R0 R0 + 0x80000000, // 003A RET 0 }) ) ); @@ -763,14 +1647,16 @@ be_local_closure(Matter_Session_get_fabric_compressed, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric_compressed), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(fabric_compressed), }), be_str_weak(get_fabric_compressed), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ + ( &(const binstruction[ 3]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x80040200, // 0002 RET 1 R1 }) ) ); @@ -778,12 +1664,12 @@ be_local_closure(Matter_Session_get_fabric_compressed, /* name */ /******************************************************************** -** Solidified function: set_fabric_label +** Solidified function: get_admin_vendor ********************************************************************/ -be_local_closure(Matter_Session_set_fabric_label, /* name */ +be_local_closure(Matter_Session_get_admin_vendor, /* name */ be_nested_proto( - 4, /* nstack */ - 2, /* argc */ + 2, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -791,19 +1677,15 @@ be_local_closure(Matter_Session_set_fabric_label, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(fabric_label), + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(admin_vendor), }), - be_str_weak(set_fabric_label), + be_str_weak(get_admin_vendor), &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x60080004, // 0000 GETGBL R2 G4 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x1C080500, // 0003 EQ R2 R2 K0 - 0x780A0000, // 0004 JMPF R2 #0006 - 0x90020201, // 0005 SETMBR R0 K1 R1 - 0x80000000, // 0006 RET 0 + ( &(const binstruction[ 3]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x80040200, // 0002 RET 1 R1 }) ) ); @@ -811,26 +1693,39 @@ be_local_closure(Matter_Session_set_fabric_label, /* name */ /******************************************************************** -** Solidified function: set_ipk_epoch_key +** Solidified function: get_pk ********************************************************************/ -be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ +be_local_closure(Matter_Session_get_pk, /* name */ be_nested_proto( - 2, /* nstack */ - 2, /* argc */ + 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[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(no_private_key), + /* K2 */ be_nested_str_weak(crypto), + /* K3 */ be_nested_str_weak(random), }), - be_str_weak(set_ipk_epoch_key), + be_str_weak(get_pk), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x74060005, // 0002 JMPT R1 #0009 + 0xA4060400, // 0003 IMPORT R1 K2 + 0x88080100, // 0004 GETMBR R2 R0 K0 + 0x8C0C0303, // 0005 GETMET R3 R1 K3 + 0x5416001F, // 0006 LDINT R5 32 + 0x7C0C0400, // 0007 CALL R3 2 + 0x900A0203, // 0008 SETMBR R2 K1 R3 + 0x88040100, // 0009 GETMBR R1 R0 K0 + 0x88040301, // 000A GETMBR R1 R1 K1 + 0x80040200, // 000B RET 1 R1 }) ) ); @@ -842,62 +1737,41 @@ be_local_closure(Matter_Session_set_ipk_epoch_key, /* name */ ********************************************************************/ be_local_closure(Matter_Session_set_fabric_device, /* name */ be_nested_proto( - 7, /* nstack */ - 4, /* argc */ + 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[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), - /* K1 */ be_nested_str_weak(deviceid), - /* K2 */ be_nested_str_weak(fabric_compressed), - /* K3 */ be_nested_str_weak(__store), - /* K4 */ be_nested_str_weak(remove_redundant_session), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(fabric_id), + /* K2 */ be_nested_str_weak(device_id), + /* K3 */ be_nested_str_weak(fabric_compressed), + /* K4 */ be_nested_str_weak(fabric_parent), + /* K5 */ be_nested_str_weak(get_fabric_index), }), be_str_weak(set_fabric_device), &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x88100103, // 0003 GETMBR R4 R0 K3 - 0x8C100904, // 0004 GETMET R4 R4 K4 - 0x5C180000, // 0005 MOVE R6 R0 - 0x7C100400, // 0006 CALL R4 2 - 0x80000000, // 0007 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_persist -********************************************************************/ -be_local_closure(Matter_Session_set_persist, /* name */ - be_nested_proto( - 4, /* nstack */ - 2, /* 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(_persist), - }), - be_str_weak(set_persist), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080017, // 0000 GETGBL R2 G23 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 + ( &(const binstruction[16]) { /* code */ + 0x88140100, // 0000 GETMBR R5 R0 K0 + 0x90160201, // 0001 SETMBR R5 K1 R1 + 0x88140100, // 0002 GETMBR R5 R0 K0 + 0x90160402, // 0003 SETMBR R5 K2 R2 + 0x88140100, // 0004 GETMBR R5 R0 K0 + 0x90160603, // 0005 SETMBR R5 K3 R3 + 0x88140100, // 0006 GETMBR R5 R0 K0 + 0x4C180000, // 0007 LDNIL R6 + 0x20180806, // 0008 NE R6 R4 R6 + 0x781A0002, // 0009 JMPF R6 #000D + 0x8C180905, // 000A GETMET R6 R4 K5 + 0x7C180200, // 000B CALL R6 1 + 0x70020000, // 000C JMP #000E + 0x4C180000, // 000D LDNIL R6 + 0x90160806, // 000E SETMBR R5 K4 R6 + 0x80000000, // 000F RET 0 }) ) ); @@ -1013,376 +1887,6 @@ be_local_closure(Matter_Session_gen_CSR, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: set_ca -********************************************************************/ -be_local_closure(Matter_Session_set_ca, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* 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(root_ca_certificate), - }), - be_str_weak(set_ca), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_expire_time -********************************************************************/ -be_local_closure(Matter_Session_set_expire_time, /* name */ - be_nested_proto( - 4, /* nstack */ - 2, /* 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(expiration), - }), - be_str_weak(set_expire_time), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x60080009, // 0000 GETGBL R2 G9 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_i2r -********************************************************************/ -be_local_closure(Matter_Session_get_i2r, /* 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(i2rkey), - }), - be_str_weak(get_i2r), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_keys -********************************************************************/ -be_local_closure(Matter_Session_set_keys, /* name */ - be_nested_proto( - 6, /* nstack */ - 5, /* 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(i2rkey), - /* K1 */ be_nested_str_weak(_i2r_privacy), - /* K2 */ be_nested_str_weak(r2ikey), - /* K3 */ be_nested_str_weak(attestation_challenge), - /* K4 */ be_nested_str_weak(session_timestamp), - }), - be_str_weak(set_keys), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x4C140000, // 0001 LDNIL R5 - 0x90020205, // 0002 SETMBR R0 K1 R5 - 0x90020402, // 0003 SETMBR R0 K2 R2 - 0x90020603, // 0004 SETMBR R0 K3 R3 - 0x90020804, // 0005 SETMBR R0 K4 R4 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca -********************************************************************/ -be_local_closure(Matter_Session_get_ca, /* 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(root_ca_certificate), - }), - be_str_weak(get_ca), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_pk -********************************************************************/ -be_local_closure(Matter_Session_get_pk, /* 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_weak(no_private_key), - /* K1 */ be_nested_str_weak(crypto), - /* K2 */ be_nested_str_weak(random), - }), - be_str_weak(get_pk), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x74060004, // 0001 JMPT R1 #0007 - 0xA4060200, // 0002 IMPORT R1 K1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x5412001F, // 0004 LDINT R4 32 - 0x7C080400, // 0005 CALL R2 2 - 0x90020002, // 0006 SETMBR R0 K0 R2 - 0x88040100, // 0007 GETMBR R1 R0 K0 - 0x80040200, // 0008 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ca_pub -********************************************************************/ -be_local_closure(Matter_Session_get_ca_pub, /* 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(root_ca_certificate), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(parse), - /* K4 */ be_nested_str_weak(findsubval), - }), - be_str_weak(get_ca_pub), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060008, // 0001 JMPF R1 #000B - 0xB8060200, // 0002 GETNGBL R1 K1 - 0x88040302, // 0003 GETMBR R1 R1 K2 - 0x8C040303, // 0004 GETMET R1 R1 K3 - 0x880C0100, // 0005 GETMBR R3 R0 K0 - 0x7C040400, // 0006 CALL R1 2 - 0x8C080304, // 0007 GETMET R2 R1 K4 - 0x54120008, // 0008 LDINT R4 9 - 0x7C080400, // 0009 CALL R2 2 - 0x80040400, // 000A RET 1 R2 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Session_init, /* name */ - be_nested_proto( - 6, /* 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(__store), - /* K1 */ be_nested_str_weak(mode), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(local_session_id), - /* K4 */ be_nested_str_weak(initiator_session_id), - /* K5 */ be_nested_str_weak(counter_rcv), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(Counter), - /* K8 */ be_nested_str_weak(counter_snd), - /* K9 */ be_nested_str_weak(_counter_insecure_rcv), - /* K10 */ be_nested_str_weak(_counter_insecure_snd), - /* K11 */ be_nested_str_weak(breadcrumb), - /* K12 */ be_nested_str_weak(int64), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020302, // 0001 SETMBR R0 K1 K2 - 0x90020602, // 0002 SETMBR R0 K3 R2 - 0x90020803, // 0003 SETMBR R0 K4 R3 - 0xB8120C00, // 0004 GETNGBL R4 K6 - 0x8C100907, // 0005 GETMET R4 R4 K7 - 0x7C100200, // 0006 CALL R4 1 - 0x90020A04, // 0007 SETMBR R0 K5 R4 - 0xB8120C00, // 0008 GETNGBL R4 K6 - 0x8C100907, // 0009 GETMET R4 R4 K7 - 0x7C100200, // 000A CALL R4 1 - 0x90021004, // 000B SETMBR R0 K8 R4 - 0xB8120C00, // 000C GETNGBL R4 K6 - 0x8C100907, // 000D GETMET R4 R4 K7 - 0x7C100200, // 000E CALL R4 1 - 0x90021204, // 000F SETMBR R0 K9 R4 - 0xB8120C00, // 0010 GETNGBL R4 K6 - 0x8C100907, // 0011 GETMET R4 R4 K7 - 0x7C100200, // 0012 CALL R4 1 - 0x90021404, // 0013 SETMBR R0 K10 R4 - 0xB8121800, // 0014 GETNGBL R4 K12 - 0x7C100000, // 0015 CALL R4 0 - 0x90021604, // 0016 SETMBR R0 K11 R4 - 0x80000000, // 0017 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ipk_group_key -********************************************************************/ -be_local_closure(Matter_Session_get_ipk_group_key, /* 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[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(ipk_epoch_key), - /* K1 */ be_nested_str_weak(fabric_compressed), - /* K2 */ be_nested_str_weak(crypto), - /* K3 */ be_nested_str_weak(HKDF_SHA256), - /* K4 */ be_nested_str_weak(fromstring), - /* K5 */ be_nested_str_weak(__GROUP_KEY), - /* K6 */ be_nested_str_weak(derive), - }), - be_str_weak(get_ipk_group_key), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x1C040202, // 0002 EQ R1 R1 R2 - 0x74060003, // 0003 JMPT R1 #0008 - 0x88040101, // 0004 GETMBR R1 R0 K1 - 0x4C080000, // 0005 LDNIL R2 - 0x1C040202, // 0006 EQ R1 R1 R2 - 0x78060001, // 0007 JMPF R1 #000A - 0x4C040000, // 0008 LDNIL R1 - 0x80040200, // 0009 RET 1 R1 - 0xA4060400, // 000A IMPORT R1 K2 - 0x8C080303, // 000B GETMET R2 R1 K3 - 0x7C080200, // 000C CALL R2 1 - 0x600C0015, // 000D GETGBL R3 G21 - 0x7C0C0000, // 000E CALL R3 0 - 0x8C0C0704, // 000F GETMET R3 R3 K4 - 0x88140105, // 0010 GETMBR R5 R0 K5 - 0x7C0C0400, // 0011 CALL R3 2 - 0x8C100506, // 0012 GETMET R4 R2 K6 - 0x88180100, // 0013 GETMBR R6 R0 K0 - 0x881C0101, // 0014 GETMBR R7 R0 K1 - 0x5C200600, // 0015 MOVE R8 R3 - 0x5426000F, // 0016 LDINT R9 16 - 0x7C100A00, // 0017 CALL R4 5 - 0x80040800, // 0018 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_noc -********************************************************************/ -be_local_closure(Matter_Session_set_noc, /* name */ - be_nested_proto( - 3, /* 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_weak(noc), - /* K1 */ be_nested_str_weak(icac), - }), - be_str_weak(set_noc), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: get_fabric ********************************************************************/ @@ -1397,7 +1901,7 @@ be_local_closure(Matter_Session_get_fabric, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(fabric), + /* K0 */ be_nested_str_weak(_fabric), }), be_str_weak(get_fabric), &be_const_str_solidified, @@ -1411,26 +1915,38 @@ be_local_closure(Matter_Session_get_fabric, /* name */ /******************************************************************** -** Solidified function: get_mode +** Solidified function: counter_rcv_validate ********************************************************************/ -be_local_closure(Matter_Session_get_mode, /* name */ +be_local_closure(Matter_Session_counter_rcv_validate, /* name */ be_nested_proto( - 2, /* 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[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(mode), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(_counter_rcv_impl), + /* K1 */ be_nested_str_weak(validate), + /* K2 */ be_nested_str_weak(counter_rcv), + /* K3 */ be_nested_str_weak(val), }), - be_str_weak(get_mode), + be_str_weak(counter_rcv_validate), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 + ( &(const binstruction[11]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x5C180400, // 0003 MOVE R6 R2 + 0x7C0C0600, // 0004 CALL R3 3 + 0x780E0003, // 0005 JMPF R3 #000A + 0x88100100, // 0006 GETMBR R4 R0 K0 + 0x8C100903, // 0007 GETMET R4 R4 K3 + 0x7C100200, // 0008 CALL R4 1 + 0x90020404, // 0009 SETMBR R0 K2 R4 + 0x80040600, // 000A RET 1 R3 }) ) ); @@ -1438,26 +1954,31 @@ be_local_closure(Matter_Session_get_mode, /* name */ /******************************************************************** -** Solidified function: set_mode +** Solidified function: set_noc ********************************************************************/ -be_local_closure(Matter_Session_set_mode, /* name */ +be_local_closure(Matter_Session_set_noc, /* name */ be_nested_proto( - 2, /* nstack */ - 2, /* argc */ + 4, /* nstack */ + 3, /* 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(mode), + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(_fabric), + /* K1 */ be_nested_str_weak(noc), + /* K2 */ be_nested_str_weak(icac), }), - be_str_weak(set_mode), + be_str_weak(set_noc), &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 + ( &(const binstruction[ 5]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x900E0201, // 0001 SETMBR R3 K1 R1 + 0x880C0100, // 0002 GETMBR R3 R0 K0 + 0x900E0402, // 0003 SETMBR R3 K2 R2 + 0x80000000, // 0004 RET 0 }) ) ); @@ -1467,83 +1988,98 @@ be_local_closure(Matter_Session_set_mode, /* name */ /******************************************************************** ** Solidified class: Matter_Session ********************************************************************/ +extern const bclass be_class_Matter_Expirable; be_local_class(Matter_Session, 36, - NULL, - be_nested_map(72, + &be_class_Matter_Expirable, + be_nested_map(86, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(save, -1), be_const_closure(Matter_Session_save_closure) }, - { be_const_key_weak(set_mode, -1), be_const_closure(Matter_Session_set_mode_closure) }, - { be_const_key_weak(root_ca_certificate, -1), be_const_var(19) }, - { be_const_key_weak(admin_subject, 29), be_const_var(29) }, - { be_const_key_weak(get_i2r_privacy, 25), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, - { be_const_key_weak(has_expired, -1), be_const_closure(Matter_Session_has_expired_closure) }, - { be_const_key_weak(set_no_expiration, -1), be_const_closure(Matter_Session_set_no_expiration_closure) }, - { be_const_key_weak(get_deviceid, 61), be_const_closure(Matter_Session_get_deviceid_closure) }, - { be_const_key_weak(local_session_id, -1), be_const_var(2) }, - { be_const_key_weak(get_mode, -1), be_const_closure(Matter_Session_get_mode_closure) }, - { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, - { be_const_key_weak(fromjson, -1), be_const_static_closure(Matter_Session_fromjson_closure) }, - { be_const_key_weak(get_ipk_epoch_key, -1), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, - { be_const_key_weak(get_fabric, 33), be_const_closure(Matter_Session_get_fabric_closure) }, + { be_const_key_weak(__Msg2, -1), be_const_var(34) }, + { be_const_key_weak(_GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, + { be_const_key_weak(set_noc, 50), be_const_closure(Matter_Session_set_noc_closure) }, + { be_const_key_weak(get_i2r, 79), be_const_closure(Matter_Session_get_i2r_closure) }, { be_const_key_weak(tojson, -1), be_const_closure(Matter_Session_tojson_closure) }, - { be_const_key_weak(set_noc, 37), be_const_closure(Matter_Session_set_noc_closure) }, - { be_const_key_weak(get_ac, -1), be_const_closure(Matter_Session_get_ac_closure) }, - { be_const_key_weak(_counter_insecure_snd, 6), be_const_var(11) }, - { be_const_key_weak(initiator_session_id, -1), be_const_var(3) }, - { be_const_key_weak(get_fabric_compressed, -1), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, - { be_const_key_weak(set_fabric_label, -1), be_const_closure(Matter_Session_set_fabric_label_closure) }, - { be_const_key_weak(shared_secret, 8), be_const_var(24) }, - { be_const_key_weak(get_ipk_group_key, 43), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, - { be_const_key_weak(init, 42), be_const_closure(Matter_Session_init_closure) }, - { be_const_key_weak(_chunked_attr_reports, -1), be_const_var(35) }, - { be_const_key_weak(set_persist, -1), be_const_closure(Matter_Session_set_persist_closure) }, - { be_const_key_weak(_future_initiator_session_id, -1), be_const_var(6) }, - { be_const_key_weak(_Msg2, -1), be_const_var(32) }, - { be_const_key_weak(fabric, -1), be_const_var(25) }, - { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, - { be_const_key_weak(_i2r_privacy, -1), be_const_var(14) }, - { be_const_key_weak(ipk_epoch_key, -1), be_const_var(22) }, - { be_const_key_weak(get_ca, 10), be_const_closure(Matter_Session_get_ca_closure) }, - { be_const_key_weak(resumption_id, -1), be_const_var(23) }, - { be_const_key_weak(gen_CSR, 38), be_const_closure(Matter_Session_gen_CSR_closure) }, - { be_const_key_weak(source_node_id, -1), be_const_var(5) }, - { be_const_key_weak(set_ca, -1), be_const_closure(Matter_Session_set_ca_closure) }, - { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, - { be_const_key_weak(_future_local_session_id, -1), be_const_var(7) }, - { be_const_key_weak(get_r2i, 31), be_const_closure(Matter_Session_get_r2i_closure) }, - { be_const_key_weak(icac, -1), be_const_var(21) }, - { be_const_key_weak(fabric_label, -1), be_const_var(28) }, - { be_const_key_weak(attestation_challenge, -1), be_const_var(15) }, - { be_const_key_weak(peer_node_id, 49), be_const_var(16) }, - { be_const_key_weak(get_noc, 53), be_const_closure(Matter_Session_get_noc_closure) }, - { be_const_key_weak(set_expire_time, 40), be_const_closure(Matter_Session_set_expire_time_closure) }, - { be_const_key_weak(deviceid, -1), be_const_var(27) }, - { be_const_key_weak(__CASE, -1), be_const_int(2) }, - { be_const_key_weak(get_icac, 50), be_const_closure(Matter_Session_get_icac_closure) }, - { be_const_key_weak(_Msg1, -1), be_const_var(31) }, - { be_const_key_weak(set_keys, 58), be_const_closure(Matter_Session_set_keys_closure) }, - { be_const_key_weak(noc, 23), be_const_var(20) }, - { be_const_key_weak(__PASE, -1), be_const_int(1) }, - { be_const_key_weak(breadcrumb, 26), be_const_var(17) }, - { be_const_key_weak(__GROUP_KEY, -1), be_nested_str_weak(GroupKey_X20v1_X2E0) }, - { be_const_key_weak(counter_snd, -1), be_const_var(9) }, - { be_const_key_weak(fabric_compressed, 32), be_const_var(26) }, + { be_const_key_weak(assign_fabric_index, 30), be_const_closure(Matter_Session_assign_fabric_index_closure) }, + { be_const_key_weak(get_r2i, -1), be_const_closure(Matter_Session_get_r2i_closure) }, + { be_const_key_weak(_breadcrumb, -1), be_const_var(25) }, + { be_const_key_weak(_counter_snd_impl, -1), be_const_var(13) }, + { be_const_key_weak(gen_CSR, -1), be_const_closure(Matter_Session_gen_CSR_closure) }, + { be_const_key_weak(__future_local_session_id, -1), be_const_var(9) }, + { be_const_key_weak(set_mode_PASE, -1), be_const_closure(Matter_Session_set_mode_PASE_closure) }, + { be_const_key_weak(get_fabric_label, -1), be_const_closure(Matter_Session_get_fabric_label_closure) }, + { be_const_key_weak(__spake_Ke, -1), be_const_var(32) }, + { be_const_key_weak(get_device_id, 85), be_const_closure(Matter_Session_get_device_id_closure) }, + { be_const_key_weak(persist_to_fabric, 6), be_const_closure(Matter_Session_persist_to_fabric_closure) }, + { be_const_key_weak(_COUNTER_SND_INCR, -1), be_const_int(1024) }, + { be_const_key_weak(local_session_id, 18), be_const_var(3) }, + { be_const_key_weak(shared_secret, 42), be_const_var(27) }, + { be_const_key_weak(get_mode, 74), be_const_closure(Matter_Session_get_mode_closure) }, + { be_const_key_weak(peer_node_id, -1), be_const_var(24) }, + { be_const_key_weak(i2rkey, -1), be_const_var(20) }, { be_const_key_weak(get_pk, -1), be_const_closure(Matter_Session_get_pk_closure) }, - { be_const_key_weak(expiration, -1), be_const_var(34) }, - { be_const_key_weak(r2ikey, -1), be_const_var(13) }, + { be_const_key_weak(is_PASE, -1), be_const_closure(Matter_Session_is_PASE_closure) }, + { be_const_key_weak(get_admin_subject, -1), be_const_closure(Matter_Session_get_admin_subject_closure) }, + { be_const_key_weak(get_admin_vendor, -1), be_const_closure(Matter_Session_get_admin_vendor_closure) }, + { be_const_key_weak(get_ipk_epoch_key, 2), be_const_closure(Matter_Session_get_ipk_epoch_key_closure) }, + { be_const_key_weak(_counter_insecure_snd, -1), be_const_var(19) }, + { be_const_key_weak(_i2r_privacy, 78), be_const_var(22) }, + { be_const_key_weak(get_fabric_compressed, -1), be_const_closure(Matter_Session_get_fabric_compressed_closure) }, + { be_const_key_weak(get_fabric_id, -1), be_const_closure(Matter_Session_get_fabric_id_closure) }, + { be_const_key_weak(_exchange_id, 29), be_const_var(14) }, + { be_const_key_weak(fabric_candidate, -1), be_const_closure(Matter_Session_fabric_candidate_closure) }, + { be_const_key_weak(__responder_pub, -1), be_const_var(29) }, + { be_const_key_weak(get_ipk_group_key, -1), be_const_closure(Matter_Session_get_ipk_group_key_closure) }, + { be_const_key_weak(__Msg1, -1), be_const_var(33) }, + { be_const_key_weak(get_noc, -1), be_const_closure(Matter_Session_get_noc_closure) }, + { be_const_key_weak(_port, 48), be_const_var(16) }, + { be_const_key_weak(fabric_completed, -1), be_const_closure(Matter_Session_fabric_completed_closure) }, + { be_const_key_weak(__future_initiator_session_id, -1), be_const_var(8) }, + { be_const_key_weak(__spake_cA, 54), be_const_var(31) }, + { be_const_key_weak(_message_handler, -1), be_const_var(17) }, + { be_const_key_weak(attestation_challenge, 8), be_const_var(23) }, + { be_const_key_weak(get_i2r_privacy, -1), be_const_closure(Matter_Session_get_i2r_privacy_closure) }, + { be_const_key_weak(set_keys, -1), be_const_closure(Matter_Session_set_keys_closure) }, + { be_const_key_weak(counter_snd_next, -1), be_const_closure(Matter_Session_counter_snd_next_closure) }, + { be_const_key_weak(_CASE, -1), be_const_int(2) }, + { be_const_key_weak(last_used, -1), be_const_var(6) }, + { be_const_key_weak(_ip, -1), be_const_var(15) }, + { be_const_key_weak(set_mode_CASE, 28), be_const_closure(Matter_Session_set_mode_CASE_closure) }, + { be_const_key_weak(set_fabric_label, 13), be_const_closure(Matter_Session_set_fabric_label_closure) }, + { be_const_key_weak(hydrate_post, -1), be_const_closure(Matter_Session_hydrate_post_closure) }, + { be_const_key_weak(get_ca, -1), be_const_closure(Matter_Session_get_ca_closure) }, + { be_const_key_weak(init, 69), be_const_closure(Matter_Session_init_closure) }, + { be_const_key_weak(get_icac, 41), be_const_closure(Matter_Session_get_icac_closure) }, + { be_const_key_weak(_store, 51), be_const_var(0) }, + { be_const_key_weak(__chunked_attr_reports, -1), be_const_var(35) }, + { be_const_key_weak(counter_rcv, -1), be_const_var(10) }, + { be_const_key_weak(_source_node_id, -1), be_const_var(7) }, + { be_const_key_weak(set_admin_subject_vendor, 63), be_const_closure(Matter_Session_set_admin_subject_vendor_closure) }, + { be_const_key_weak(set_ipk_epoch_key, -1), be_const_closure(Matter_Session_set_ipk_epoch_key_closure) }, + { be_const_key_weak(_counter_insecure_rcv, 62), be_const_var(18) }, + { be_const_key_weak(before_remove, 64), be_const_closure(Matter_Session_before_remove_closure) }, + { be_const_key_weak(__responder_priv, -1), be_const_var(28) }, + { be_const_key_weak(initiator_session_id, -1), be_const_var(4) }, + { be_const_key_weak(r2ikey, 16), be_const_var(21) }, + { be_const_key_weak(__initiator_pub, -1), be_const_var(30) }, + { be_const_key_weak(resumption_id, -1), be_const_var(26) }, + { be_const_key_weak(save, 49), be_const_closure(Matter_Session_save_closure) }, + { be_const_key_weak(set_mode, 56), be_const_closure(Matter_Session_set_mode_closure) }, + { be_const_key_weak(get_ac, 43), be_const_closure(Matter_Session_get_ac_closure) }, + { be_const_key_weak(_PASE, -1), be_const_int(1) }, { be_const_key_weak(get_ca_pub, -1), be_const_closure(Matter_Session_get_ca_pub_closure) }, - { be_const_key_weak(counter_rcv, -1), be_const_var(8) }, - { be_const_key_weak(_persist, 22), be_const_var(33) }, - { be_const_key_weak(i2rkey, 18), be_const_var(12) }, - { be_const_key_weak(session_timestamp, 15), be_const_var(4) }, - { be_const_key_weak(set_expire_in_seconds, 13), be_const_closure(Matter_Session_set_expire_in_seconds_closure) }, + { be_const_key_weak(close, -1), be_const_closure(Matter_Session_close_closure) }, + { be_const_key_weak(_counter_rcv_impl, -1), be_const_var(12) }, + { be_const_key_weak(_fabric, -1), be_const_var(2) }, + { be_const_key_weak(update, 25), be_const_closure(Matter_Session_update_closure) }, + { be_const_key_weak(fromjson, 22), be_const_static_closure(Matter_Session_fromjson_closure) }, + { be_const_key_weak(is_CASE, -1), be_const_closure(Matter_Session_is_CASE_closure) }, + { be_const_key_weak(counter_snd, -1), be_const_var(11) }, + { be_const_key_weak(set_fabric_device, -1), be_const_closure(Matter_Session_set_fabric_device_closure) }, + { be_const_key_weak(created, 10), be_const_var(5) }, + { be_const_key_weak(set_ca, 9), be_const_closure(Matter_Session_set_ca_closure) }, + { be_const_key_weak(get_fabric, -1), be_const_closure(Matter_Session_get_fabric_closure) }, + { be_const_key_weak(counter_rcv_validate, -1), be_const_closure(Matter_Session_counter_rcv_validate_closure) }, { be_const_key_weak(mode, -1), be_const_var(1) }, - { be_const_key_weak(get_i2r, 9), be_const_closure(Matter_Session_get_i2r_closure) }, - { be_const_key_weak(__store, -1), be_const_var(0) }, - { be_const_key_weak(_counter_insecure_rcv, -1), be_const_var(10) }, - { be_const_key_weak(no_private_key, 2), be_const_var(18) }, - { be_const_key_weak(admin_vendor, 1), be_const_var(30) }, })), be_str_weak(Matter_Session) ); @@ -1554,888 +2090,5 @@ void be_load_Matter_Session_class(bvm *vm) { be_setglobal(vm, "Matter_Session"); be_pop(vm, 1); } - -extern const bclass be_class_Matter_Session_Store; - -/******************************************************************** -** Solidified function: remove_expired -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_expired, /* 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[ 7]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(has_expired), - /* K3 */ be_nested_str_weak(_persist), - /* K4 */ be_nested_str_weak(remove), - /* K5 */ be_const_int(1), - /* K6 */ be_nested_str_weak(save), - }), - be_str_weak(remove_expired), - &be_const_str_solidified, - ( &(const binstruction[26]) { /* code */ - 0x50040000, // 0000 LDBOOL R1 0 0 - 0x58080000, // 0001 LDCONST R2 K0 - 0x880C0101, // 0002 GETMBR R3 R0 K1 - 0x6010000C, // 0003 GETGBL R4 G12 - 0x88140101, // 0004 GETMBR R5 R0 K1 - 0x7C100200, // 0005 CALL R4 1 - 0x14100404, // 0006 LT R4 R2 R4 - 0x7812000D, // 0007 JMPF R4 #0016 - 0x94100602, // 0008 GETIDX R4 R3 R2 - 0x8C100902, // 0009 GETMET R4 R4 K2 - 0x7C100200, // 000A CALL R4 1 - 0x78120007, // 000B JMPF R4 #0014 - 0x94100602, // 000C GETIDX R4 R3 R2 - 0x88100903, // 000D GETMBR R4 R4 K3 - 0x78120000, // 000E JMPF R4 #0010 - 0x50040200, // 000F LDBOOL R1 1 0 - 0x8C100704, // 0010 GETMET R4 R3 K4 - 0x5C180400, // 0011 MOVE R6 R2 - 0x7C100400, // 0012 CALL R4 2 - 0x70020000, // 0013 JMP #0015 - 0x00080505, // 0014 ADD R2 R2 K5 - 0x7001FFEC, // 0015 JMP #0003 - 0x78060001, // 0016 JMPF R1 #0019 - 0x8C100106, // 0017 GETMET R4 R0 K6 - 0x7C100200, // 0018 CALL R4 1 - 0x80000000, // 0019 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_redundant_session -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_redundant_session, /* 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[ 6]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(fabric), - /* K3 */ be_nested_str_weak(deviceid), - /* K4 */ be_nested_str_weak(remove), - /* K5 */ be_const_int(1), - }), - be_str_weak(remove_redundant_session), - &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x6010000C, // 0002 GETGBL R4 G12 - 0x88140101, // 0003 GETMBR R5 R0 K1 - 0x7C100200, // 0004 CALL R4 1 - 0x14100404, // 0005 LT R4 R2 R4 - 0x78120010, // 0006 JMPF R4 #0018 - 0x94100602, // 0007 GETIDX R4 R3 R2 - 0x20140801, // 0008 NE R5 R4 R1 - 0x7816000B, // 0009 JMPF R5 #0016 - 0x88140902, // 000A GETMBR R5 R4 K2 - 0x88180302, // 000B GETMBR R6 R1 K2 - 0x1C140A06, // 000C EQ R5 R5 R6 - 0x78160007, // 000D JMPF R5 #0016 - 0x88140903, // 000E GETMBR R5 R4 K3 - 0x88180303, // 000F GETMBR R6 R1 K3 - 0x1C140A06, // 0010 EQ R5 R5 R6 - 0x78160003, // 0011 JMPF R5 #0016 - 0x8C140704, // 0012 GETMET R5 R3 K4 - 0x5C1C0400, // 0013 MOVE R7 R2 - 0x7C140400, // 0014 CALL R5 2 - 0x70020000, // 0015 JMP #0017 - 0x00080505, // 0016 ADD R2 R2 K5 - 0x7001FFE9, // 0017 JMP #0002 - 0x80000000, // 0018 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_session -********************************************************************/ -be_local_closure(Matter_Session_Store_add_session, /* 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[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(set_expire_in_seconds), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(push), - }), - be_str_weak(add_session), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x200C0403, // 0001 NE R3 R2 R3 - 0x780E0002, // 0002 JMPF R3 #0006 - 0x8C0C0300, // 0003 GETMET R3 R1 K0 - 0x5C140400, // 0004 MOVE R5 R2 - 0x7C0C0400, // 0005 CALL R3 2 - 0x880C0101, // 0006 GETMBR R3 R0 K1 - 0x8C0C0702, // 0007 GETMET R3 R3 K2 - 0x5C140200, // 0008 MOVE R5 R1 - 0x7C0C0400, // 0009 CALL R3 2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: sessions_active -********************************************************************/ -be_local_closure(Matter_Session_Store_sessions_active, /* 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_const_int(0), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(get_deviceid), - /* K3 */ be_nested_str_weak(get_fabric), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_const_int(1), - }), - be_str_weak(sessions_active), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x58080000, // 0002 LDCONST R2 K0 - 0x600C000C, // 0003 GETGBL R3 G12 - 0x88100101, // 0004 GETMBR R4 R0 K1 - 0x7C0C0200, // 0005 CALL R3 1 - 0x140C0403, // 0006 LT R3 R2 R3 - 0x780E000C, // 0007 JMPF R3 #0015 - 0x880C0101, // 0008 GETMBR R3 R0 K1 - 0x940C0602, // 0009 GETIDX R3 R3 R2 - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x7C100200, // 000B CALL R4 1 - 0x78120005, // 000C JMPF R4 #0013 - 0x8C100703, // 000D GETMET R4 R3 K3 - 0x7C100200, // 000E CALL R4 1 - 0x78120002, // 000F JMPF R4 #0013 - 0x8C100304, // 0010 GETMET R4 R1 K4 - 0x5C180600, // 0011 MOVE R6 R3 - 0x7C100400, // 0012 CALL R4 2 - 0x00080505, // 0013 ADD R2 R2 K5 - 0x7001FFED, // 0014 JMP #0003 - 0x80040200, // 0015 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_second -********************************************************************/ -be_local_closure(Matter_Session_Store_every_second, /* 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(remove_expired), - }), - be_str_weak(every_second), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: save -********************************************************************/ -be_local_closure(Matter_Session_Store_save, /* 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[23]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(remove_expired), - /* K2 */ be_nested_str_weak(sessions), - /* K3 */ be_nested_str_weak(_persist), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_nested_str_weak(tojson), - /* K6 */ be_nested_str_weak(stop_iteration), - /* K7 */ be_nested_str_weak(_X5B), - /* K8 */ be_nested_str_weak(concat), - /* K9 */ be_nested_str_weak(_X2C), - /* K10 */ be_nested_str_weak(_X5D), - /* K11 */ be_nested_str_weak(string), - /* K12 */ be_nested_str_weak(FILENAME), - /* K13 */ be_nested_str_weak(w), - /* K14 */ be_nested_str_weak(write), - /* K15 */ be_nested_str_weak(close), - /* K16 */ be_nested_str_weak(tasmota), - /* K17 */ be_nested_str_weak(log), - /* K18 */ be_nested_str_weak(format), - /* K19 */ be_nested_str_weak(MTR_X3A_X20Saved_X20_X25i_X20session_X28s_X29), - /* K20 */ be_const_int(2), - /* K21 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), - /* K22 */ be_nested_str_weak(_X7C), - }), - be_str_weak(save), - &be_const_str_solidified, - ( &(const binstruction[72]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080101, // 0001 GETMET R2 R0 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x60080012, // 0003 GETGBL R2 G18 - 0x7C080000, // 0004 CALL R2 0 - 0x600C0010, // 0005 GETGBL R3 G16 - 0x88100102, // 0006 GETMBR R4 R0 K2 - 0x7C0C0200, // 0007 CALL R3 1 - 0xA8020008, // 0008 EXBLK 0 #0012 - 0x5C100600, // 0009 MOVE R4 R3 - 0x7C100000, // 000A CALL R4 0 - 0x88140903, // 000B GETMBR R5 R4 K3 - 0x78160003, // 000C JMPF R5 #0011 - 0x8C140504, // 000D GETMET R5 R2 K4 - 0x8C1C0905, // 000E GETMET R7 R4 K5 - 0x7C1C0200, // 000F CALL R7 1 - 0x7C140400, // 0010 CALL R5 2 - 0x7001FFF6, // 0011 JMP #0009 - 0x580C0006, // 0012 LDCONST R3 K6 - 0xAC0C0200, // 0013 CATCH R3 1 0 - 0xB0080000, // 0014 RAISE 2 R0 R0 - 0x600C000C, // 0015 GETGBL R3 G12 - 0x5C100400, // 0016 MOVE R4 R2 - 0x7C0C0200, // 0017 CALL R3 1 - 0x8C100508, // 0018 GETMET R4 R2 K8 - 0x58180009, // 0019 LDCONST R6 K9 - 0x7C100400, // 001A CALL R4 2 - 0x00120E04, // 001B ADD R4 K7 R4 - 0x0010090A, // 001C ADD R4 R4 K10 - 0x5C080800, // 001D MOVE R2 R4 - 0xA8020015, // 001E EXBLK 0 #0035 - 0xA4121600, // 001F IMPORT R4 K11 - 0x60140011, // 0020 GETGBL R5 G17 - 0x8818010C, // 0021 GETMBR R6 R0 K12 - 0x581C000D, // 0022 LDCONST R7 K13 - 0x7C140400, // 0023 CALL R5 2 - 0x8C180B0E, // 0024 GETMET R6 R5 K14 - 0x5C200400, // 0025 MOVE R8 R2 - 0x7C180400, // 0026 CALL R6 2 - 0x8C180B0F, // 0027 GETMET R6 R5 K15 - 0x7C180200, // 0028 CALL R6 1 - 0xB81A2000, // 0029 GETNGBL R6 K16 - 0x8C180D11, // 002A GETMET R6 R6 K17 - 0x8C200912, // 002B GETMET R8 R4 K18 - 0x58280013, // 002C LDCONST R10 K19 - 0x5C2C0600, // 002D MOVE R11 R3 - 0x7C200600, // 002E CALL R8 3 - 0x58240014, // 002F LDCONST R9 K20 - 0x7C180600, // 0030 CALL R6 3 - 0xA8040001, // 0031 EXBLK 1 1 - 0x80040400, // 0032 RET 1 R2 - 0xA8040001, // 0033 EXBLK 1 1 - 0x70020011, // 0034 JMP #0047 - 0xAC100002, // 0035 CATCH R4 0 2 - 0x7002000E, // 0036 JMP #0046 - 0xB81A2000, // 0037 GETNGBL R6 K16 - 0x8C180D11, // 0038 GETMET R6 R6 K17 - 0x60200008, // 0039 GETGBL R8 G8 - 0x5C240800, // 003A MOVE R9 R4 - 0x7C200200, // 003B CALL R8 1 - 0x00222A08, // 003C ADD R8 K21 R8 - 0x00201116, // 003D ADD R8 R8 K22 - 0x60240008, // 003E GETGBL R9 G8 - 0x5C280A00, // 003F MOVE R10 R5 - 0x7C240200, // 0040 CALL R9 1 - 0x00201009, // 0041 ADD R8 R8 R9 - 0x58240014, // 0042 LDCONST R9 K20 - 0x7C180600, // 0043 CALL R6 3 - 0x80040400, // 0044 RET 1 R2 - 0x70020000, // 0045 JMP #0047 - 0xB0080000, // 0046 RAISE 2 R0 R0 - 0x80000000, // 0047 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_session_by_resumption_id -********************************************************************/ -be_local_closure(Matter_Session_Store_find_session_by_resumption_id, /* 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(sessions), - /* K2 */ be_nested_str_weak(resumption_id), - /* K3 */ be_const_int(1), - }), - be_str_weak(find_session_by_resumption_id), - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0x5C080200, // 0000 MOVE R2 R1 - 0x740A0001, // 0001 JMPT R2 #0004 - 0x4C080000, // 0002 LDNIL R2 - 0x80040400, // 0003 RET 1 R2 - 0x58080000, // 0004 LDCONST R2 K0 - 0x880C0101, // 0005 GETMBR R3 R0 K1 - 0x6010000C, // 0006 GETGBL R4 G12 - 0x5C140600, // 0007 MOVE R5 R3 - 0x7C100200, // 0008 CALL R4 1 - 0x14100404, // 0009 LT R4 R2 R4 - 0x78120007, // 000A JMPF R4 #0013 - 0x94100602, // 000B GETIDX R4 R3 R2 - 0x88100902, // 000C GETMBR R4 R4 K2 - 0x1C100801, // 000D EQ R4 R4 R1 - 0x78120001, // 000E JMPF R4 #0011 - 0x94100602, // 000F GETIDX R4 R3 R2 - 0x80040800, // 0010 RET 1 R4 - 0x00080503, // 0011 ADD R2 R2 K3 - 0x7001FFF2, // 0012 JMP #0006 - 0x80000000, // 0013 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: gen_local_session_id -********************************************************************/ -be_local_closure(Matter_Session_Store_gen_local_session_id, /* 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(crypto), - /* K1 */ be_nested_str_weak(random), - /* K2 */ be_const_int(2), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str_weak(get_session_by_local_session_id), - }), - be_str_weak(gen_local_session_id), - &be_const_str_solidified, - ( &(const binstruction[19]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x50080200, // 0001 LDBOOL R2 1 0 - 0x780A000E, // 0002 JMPF R2 #0012 - 0x8C080301, // 0003 GETMET R2 R1 K1 - 0x58100002, // 0004 LDCONST R4 K2 - 0x7C080400, // 0005 CALL R2 2 - 0x8C080503, // 0006 GETMET R2 R2 K3 - 0x58100004, // 0007 LDCONST R4 K4 - 0x58140002, // 0008 LDCONST R5 K2 - 0x7C080600, // 0009 CALL R2 3 - 0x8C0C0105, // 000A GETMET R3 R0 K5 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C0C0400, // 000C CALL R3 2 - 0x4C100000, // 000D LDNIL R4 - 0x1C0C0604, // 000E EQ R3 R3 R4 - 0x780E0000, // 000F JMPF R3 #0011 - 0x80040400, // 0010 RET 1 R2 - 0x7001FFEE, // 0011 JMP #0001 - 0x80000000, // 0012 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_session_by_local_session_id -********************************************************************/ -be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* 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(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(local_session_id), - /* K3 */ be_const_int(1), - }), - be_str_weak(get_session_by_local_session_id), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0001, // 0002 JMPF R2 #0005 - 0x4C080000, // 0003 LDNIL R2 - 0x80040400, // 0004 RET 1 R2 - 0x6008000C, // 0005 GETGBL R2 G12 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x7C080200, // 0007 CALL R2 1 - 0x580C0001, // 0008 LDCONST R3 K1 - 0x88100100, // 0009 GETMBR R4 R0 K0 - 0x14140602, // 000A LT R5 R3 R2 - 0x78160007, // 000B JMPF R5 #0014 - 0x94140803, // 000C GETIDX R5 R4 R3 - 0x88140B02, // 000D GETMBR R5 R5 K2 - 0x1C140A01, // 000E EQ R5 R5 R1 - 0x78160001, // 000F JMPF R5 #0012 - 0x94140803, // 0010 GETIDX R5 R4 R3 - 0x80040A00, // 0011 RET 1 R5 - 0x000C0703, // 0012 ADD R3 R3 K3 - 0x7001FFF5, // 0013 JMP #000A - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Session_Store_init, /* 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(sessions), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_session_source_id_unsecure -********************************************************************/ -be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* 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(get_session_by_source_node_id), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(Session), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(source_node_id), - /* K5 */ be_nested_str_weak(sessions), - /* K6 */ be_nested_str_weak(push), - /* K7 */ be_nested_str_weak(set_expire_in_seconds), - }), - be_str_weak(find_session_source_id_unsecure), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x1C100604, // 0004 EQ R4 R3 R4 - 0x7812000B, // 0005 JMPF R4 #0012 - 0xB8120200, // 0006 GETNGBL R4 K1 - 0x8C100902, // 0007 GETMET R4 R4 K2 - 0x5C180000, // 0008 MOVE R6 R0 - 0x581C0003, // 0009 LDCONST R7 K3 - 0x58200003, // 000A LDCONST R8 K3 - 0x7C100800, // 000B CALL R4 4 - 0x5C0C0800, // 000C MOVE R3 R4 - 0x900E0801, // 000D SETMBR R3 K4 R1 - 0x88100105, // 000E GETMBR R4 R0 K5 - 0x8C100906, // 000F GETMET R4 R4 K6 - 0x5C180600, // 0010 MOVE R6 R3 - 0x7C100400, // 0011 CALL R4 2 - 0x8C100707, // 0012 GETMET R4 R3 K7 - 0x5C180400, // 0013 MOVE R6 R2 - 0x7C100400, // 0014 CALL R4 2 - 0x80040600, // 0015 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_session -********************************************************************/ -be_local_closure(Matter_Session_Store_remove_session, /* 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(sessions), - /* K2 */ be_nested_str_weak(remove), - /* K3 */ be_const_int(1), - }), - be_str_weak(remove_session), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x6010000C, // 0002 GETGBL R4 G12 - 0x88140101, // 0003 GETMBR R5 R0 K1 - 0x7C100200, // 0004 CALL R4 1 - 0x14100404, // 0005 LT R4 R2 R4 - 0x78120008, // 0006 JMPF R4 #0010 - 0x94100602, // 0007 GETIDX R4 R3 R2 - 0x1C100801, // 0008 EQ R4 R4 R1 - 0x78120003, // 0009 JMPF R4 #000E - 0x8C100702, // 000A GETMET R4 R3 K2 - 0x5C180400, // 000B MOVE R6 R2 - 0x7C100400, // 000C CALL R4 2 - 0x70020000, // 000D JMP #000F - 0x00080503, // 000E ADD R2 R2 K3 - 0x7001FFF1, // 000F JMP #0002 - 0x80000000, // 0010 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: create_session -********************************************************************/ -be_local_closure(Matter_Session_Store_create_session, /* 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[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(get_session_by_local_session_id), - /* K1 */ be_nested_str_weak(remove_session), - /* K2 */ be_nested_str_weak(matter), - /* K3 */ be_nested_str_weak(Session), - /* K4 */ be_nested_str_weak(sessions), - /* K5 */ be_nested_str_weak(push), - }), - be_str_weak(create_session), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C0C0400, // 0002 CALL R3 2 - 0x4C100000, // 0003 LDNIL R4 - 0x20100604, // 0004 NE R4 R3 R4 - 0x78120002, // 0005 JMPF R4 #0009 - 0x8C100101, // 0006 GETMET R4 R0 K1 - 0x5C180600, // 0007 MOVE R6 R3 - 0x7C100400, // 0008 CALL R4 2 - 0xB8120400, // 0009 GETNGBL R4 K2 - 0x8C100903, // 000A GETMET R4 R4 K3 - 0x5C180000, // 000B MOVE R6 R0 - 0x5C1C0200, // 000C MOVE R7 R1 - 0x5C200400, // 000D MOVE R8 R2 - 0x7C100800, // 000E CALL R4 4 - 0x5C0C0800, // 000F MOVE R3 R4 - 0x88100104, // 0010 GETMBR R4 R0 K4 - 0x8C100905, // 0011 GETMET R4 R4 K5 - 0x5C180600, // 0012 MOVE R6 R3 - 0x7C100400, // 0013 CALL R4 2 - 0x80040600, // 0014 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: load -********************************************************************/ -be_local_closure(Matter_Session_Store_load, /* name */ - be_nested_proto( - 13, /* nstack */ - 1, /* 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(string), - /* K1 */ be_nested_str_weak(sessions), - /* K2 */ be_nested_str_weak(FILENAME), - /* K3 */ be_nested_str_weak(read), - /* K4 */ be_nested_str_weak(close), - /* K5 */ be_nested_str_weak(json), - /* K6 */ be_nested_str_weak(load), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(gc), - /* K9 */ be_nested_str_weak(matter), - /* K10 */ be_nested_str_weak(Session), - /* K11 */ be_nested_str_weak(fromjson), - /* K12 */ be_nested_str_weak(add_session), - /* K13 */ be_nested_str_weak(stop_iteration), - /* K14 */ be_nested_str_weak(log), - /* K15 */ be_nested_str_weak(format), - /* K16 */ be_nested_str_weak(MTR_X3A_X20Loaded_X20_X25i_X20session_X28s_X29), - /* K17 */ be_const_int(2), - /* K18 */ be_nested_str_weak(io_error), - /* K19 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), - /* K20 */ be_nested_str_weak(_X7C), - /* K21 */ be_nested_str_weak(remove_expired), - }), - be_str_weak(load), - &be_const_str_solidified, - ( &(const binstruction[76]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA8020033, // 0001 EXBLK 0 #0036 - 0x60080012, // 0002 GETGBL R2 G18 - 0x7C080000, // 0003 CALL R2 0 - 0x90020202, // 0004 SETMBR R0 K1 R2 - 0x60080011, // 0005 GETGBL R2 G17 - 0x880C0102, // 0006 GETMBR R3 R0 K2 - 0x7C080200, // 0007 CALL R2 1 - 0x8C0C0503, // 0008 GETMET R3 R2 K3 - 0x7C0C0200, // 0009 CALL R3 1 - 0x8C100504, // 000A GETMET R4 R2 K4 - 0x7C100200, // 000B CALL R4 1 - 0xA4120A00, // 000C IMPORT R4 K5 - 0x8C140906, // 000D GETMET R5 R4 K6 - 0x5C1C0600, // 000E MOVE R7 R3 - 0x7C140400, // 000F CALL R5 2 - 0x4C0C0000, // 0010 LDNIL R3 - 0xB81A0E00, // 0011 GETNGBL R6 K7 - 0x8C180D08, // 0012 GETMET R6 R6 K8 - 0x7C180200, // 0013 CALL R6 1 - 0x60180010, // 0014 GETGBL R6 G16 - 0x5C1C0A00, // 0015 MOVE R7 R5 - 0x7C180200, // 0016 CALL R6 1 - 0xA802000E, // 0017 EXBLK 0 #0027 - 0x5C1C0C00, // 0018 MOVE R7 R6 - 0x7C1C0000, // 0019 CALL R7 0 - 0xB8221200, // 001A GETNGBL R8 K9 - 0x8820110A, // 001B GETMBR R8 R8 K10 - 0x8C20110B, // 001C GETMET R8 R8 K11 - 0x5C280000, // 001D MOVE R10 R0 - 0x5C2C0E00, // 001E MOVE R11 R7 - 0x7C200600, // 001F CALL R8 3 - 0x4C240000, // 0020 LDNIL R9 - 0x20241009, // 0021 NE R9 R8 R9 - 0x78260002, // 0022 JMPF R9 #0026 - 0x8C24010C, // 0023 GETMET R9 R0 K12 - 0x5C2C1000, // 0024 MOVE R11 R8 - 0x7C240400, // 0025 CALL R9 2 - 0x7001FFF0, // 0026 JMP #0018 - 0x5818000D, // 0027 LDCONST R6 K13 - 0xAC180200, // 0028 CATCH R6 1 0 - 0xB0080000, // 0029 RAISE 2 R0 R0 - 0xB81A0E00, // 002A GETNGBL R6 K7 - 0x8C180D0E, // 002B GETMET R6 R6 K14 - 0x8C20030F, // 002C GETMET R8 R1 K15 - 0x58280010, // 002D LDCONST R10 K16 - 0x602C000C, // 002E GETGBL R11 G12 - 0x88300101, // 002F GETMBR R12 R0 K1 - 0x7C2C0200, // 0030 CALL R11 1 - 0x7C200600, // 0031 CALL R8 3 - 0x58240011, // 0032 LDCONST R9 K17 - 0x7C180600, // 0033 CALL R6 3 - 0xA8040001, // 0034 EXBLK 1 1 - 0x70020012, // 0035 JMP #0049 - 0xAC080002, // 0036 CATCH R2 0 2 - 0x7002000F, // 0037 JMP #0048 - 0x20100512, // 0038 NE R4 R2 K18 - 0x7812000C, // 0039 JMPF R4 #0047 - 0xB8120E00, // 003A GETNGBL R4 K7 - 0x8C10090E, // 003B GETMET R4 R4 K14 - 0x60180008, // 003C GETGBL R6 G8 - 0x5C1C0400, // 003D MOVE R7 R2 - 0x7C180200, // 003E CALL R6 1 - 0x001A2606, // 003F ADD R6 K19 R6 - 0x00180D14, // 0040 ADD R6 R6 K20 - 0x601C0008, // 0041 GETGBL R7 G8 - 0x5C200600, // 0042 MOVE R8 R3 - 0x7C1C0200, // 0043 CALL R7 1 - 0x00180C07, // 0044 ADD R6 R6 R7 - 0x581C0011, // 0045 LDCONST R7 K17 - 0x7C100600, // 0046 CALL R4 3 - 0x70020000, // 0047 JMP #0049 - 0xB0080000, // 0048 RAISE 2 R0 R0 - 0x8C080115, // 0049 GETMET R2 R0 K21 - 0x7C080200, // 004A CALL R2 1 - 0x80000000, // 004B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_session_by_source_node_id -********************************************************************/ -be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* 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(sessions), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(source_node_id), - /* K3 */ be_const_int(1), - }), - be_str_weak(get_session_by_source_node_id), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0001, // 0002 JMPF R2 #0005 - 0x4C080000, // 0003 LDNIL R2 - 0x80040400, // 0004 RET 1 R2 - 0x6008000C, // 0005 GETGBL R2 G12 - 0x880C0100, // 0006 GETMBR R3 R0 K0 - 0x7C080200, // 0007 CALL R2 1 - 0x580C0001, // 0008 LDCONST R3 K1 - 0x88100100, // 0009 GETMBR R4 R0 K0 - 0x14140602, // 000A LT R5 R3 R2 - 0x78160007, // 000B JMPF R5 #0014 - 0x94140803, // 000C GETIDX R5 R4 R3 - 0x88140B02, // 000D GETMBR R5 R5 K2 - 0x1C140A01, // 000E EQ R5 R5 R1 - 0x78160001, // 000F JMPF R5 #0012 - 0x94140803, // 0010 GETIDX R5 R4 R3 - 0x80040A00, // 0011 RET 1 R5 - 0x000C0703, // 0012 ADD R3 R3 K3 - 0x7001FFF5, // 0013 JMP #000A - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified class: Matter_Session_Store -********************************************************************/ -be_local_class(Matter_Session_Store, - 1, - NULL, - be_nested_map(17, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(remove_expired, 6), be_const_closure(Matter_Session_Store_remove_expired_closure) }, - { be_const_key_weak(remove_redundant_session, -1), be_const_closure(Matter_Session_Store_remove_redundant_session_closure) }, - { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, - { be_const_key_weak(sessions, 12), be_const_var(0) }, - { be_const_key_weak(sessions_active, -1), be_const_closure(Matter_Session_Store_sessions_active_closure) }, - { be_const_key_weak(every_second, 9), be_const_closure(Matter_Session_Store_every_second_closure) }, - { be_const_key_weak(find_session_by_resumption_id, -1), be_const_closure(Matter_Session_Store_find_session_by_resumption_id_closure) }, - { be_const_key_weak(load, -1), be_const_closure(Matter_Session_Store_load_closure) }, - { be_const_key_weak(gen_local_session_id, -1), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, - { be_const_key_weak(get_session_by_local_session_id, -1), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, - { be_const_key_weak(FILENAME, -1), be_nested_str_weak(_matter_sessions_X2Ejson) }, - { be_const_key_weak(save, 10), be_const_closure(Matter_Session_Store_save_closure) }, - { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, - { be_const_key_weak(remove_session, -1), be_const_closure(Matter_Session_Store_remove_session_closure) }, - { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, - { be_const_key_weak(init, 7), be_const_closure(Matter_Session_Store_init_closure) }, - { be_const_key_weak(get_session_by_source_node_id, -1), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, - })), - be_str_weak(Matter_Session_Store) -); -/*******************************************************************/ - -void be_load_Matter_Session_Store_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Session_Store); - be_setglobal(vm, "Matter_Session_Store"); - be_pop(vm, 1); -} /********************************************************************/ /* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h new file mode 100644 index 000000000..c3abc2b85 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session_Store.h @@ -0,0 +1,1395 @@ +/* Solidification of Matter_Session_Store.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Session_Store; + +/******************************************************************** +** Solidified function: gen_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_gen_local_session_id, /* 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(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_const_int(2), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(get_session_by_local_session_id), + }), + be_str_weak(gen_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x50080200, // 0001 LDBOOL R2 1 0 + 0x780A000E, // 0002 JMPF R2 #0012 + 0x8C080301, // 0003 GETMET R2 R1 K1 + 0x58100002, // 0004 LDCONST R4 K2 + 0x7C080400, // 0005 CALL R2 2 + 0x8C080503, // 0006 GETMET R2 R2 K3 + 0x58100004, // 0007 LDCONST R4 K4 + 0x58140002, // 0008 LDCONST R5 K2 + 0x7C080600, // 0009 CALL R2 3 + 0x8C0C0105, // 000A GETMET R3 R0 K5 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x4C100000, // 000D LDNIL R4 + 0x1C0C0604, // 000E EQ R3 R3 R4 + 0x780E0000, // 000F JMPF R3 #0011 + 0x80040400, // 0010 RET 1 R2 + 0x7001FFEE, // 0011 JMP #0001 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_redundant_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_redundant_fabric, /* 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_const_int(0), + /* K1 */ be_nested_str_weak(fabrics), + /* K2 */ be_nested_str_weak(fabric_id), + /* K3 */ be_nested_str_weak(device_id), + /* K4 */ be_nested_str_weak(remove), + /* K5 */ be_const_int(1), + }), + be_str_weak(remove_redundant_fabric), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* 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 + 0x780E0012, // 0005 JMPF R3 #0019 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x20100601, // 0008 NE R4 R3 R1 + 0x7812000C, // 0009 JMPF R4 #0017 + 0x88100702, // 000A GETMBR R4 R3 K2 + 0x88140302, // 000B GETMBR R5 R1 K2 + 0x1C100805, // 000C EQ R4 R4 R5 + 0x78120008, // 000D JMPF R4 #0017 + 0x88100703, // 000E GETMBR R4 R3 K3 + 0x88140303, // 000F GETMBR R5 R1 K3 + 0x1C100805, // 0010 EQ R4 R4 R5 + 0x78120004, // 0011 JMPF R4 #0017 + 0x88100101, // 0012 GETMBR R4 R0 K1 + 0x8C100904, // 0013 GETMET R4 R4 K4 + 0x5C180400, // 0014 MOVE R6 R2 + 0x7C100400, // 0015 CALL R4 2 + 0x70020000, // 0016 JMP #0018 + 0x00080505, // 0017 ADD R2 R2 K5 + 0x7001FFE7, // 0018 JMP #0001 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_session_by_resumption_id +********************************************************************/ +be_local_closure(Matter_Session_Store_find_session_by_resumption_id, /* 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[12]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(sessions), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(MTR_X3A_X20session_X2Eresumption_id_X3D_X25s_X20vs_X20_X25s), + /* K7 */ be_nested_str_weak(resumption_id), + /* K8 */ be_nested_str_weak(shared_secret), + /* K9 */ be_nested_str_weak(MTR_X3A_X20session_X2Eshared_secret_X3D_X25s), + /* K10 */ be_nested_str_weak(update), + /* K11 */ be_const_int(1), + }), + be_str_weak(find_session_by_resumption_id), + &be_const_str_solidified, + ( &(const binstruction[47]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x740E0001, // 0002 JMPT R3 #0005 + 0x4C0C0000, // 0003 LDNIL R3 + 0x80040600, // 0004 RET 1 R3 + 0x580C0001, // 0005 LDCONST R3 K1 + 0x88100102, // 0006 GETMBR R4 R0 K2 + 0x6014000C, // 0007 GETGBL R5 G12 + 0x5C180800, // 0008 MOVE R6 R4 + 0x7C140200, // 0009 CALL R5 1 + 0x14140605, // 000A LT R5 R3 R5 + 0x78160021, // 000B JMPF R5 #002E + 0x94140803, // 000C GETIDX R5 R4 R3 + 0xB81A0600, // 000D GETNGBL R6 K3 + 0x8C180D04, // 000E GETMET R6 R6 K4 + 0x8C200505, // 000F GETMET R8 R2 K5 + 0x58280006, // 0010 LDCONST R10 K6 + 0x602C0008, // 0011 GETGBL R11 G8 + 0x88300B07, // 0012 GETMBR R12 R5 K7 + 0x7C2C0200, // 0013 CALL R11 1 + 0x60300008, // 0014 GETGBL R12 G8 + 0x5C340200, // 0015 MOVE R13 R1 + 0x7C300200, // 0016 CALL R12 1 + 0x7C200800, // 0017 CALL R8 4 + 0x7C180400, // 0018 CALL R6 2 + 0x88180B07, // 0019 GETMBR R6 R5 K7 + 0x1C180C01, // 001A EQ R6 R6 R1 + 0x781A000F, // 001B JMPF R6 #002C + 0x88180B08, // 001C GETMBR R6 R5 K8 + 0x4C1C0000, // 001D LDNIL R7 + 0x20180C07, // 001E NE R6 R6 R7 + 0x781A000B, // 001F JMPF R6 #002C + 0xB81A0600, // 0020 GETNGBL R6 K3 + 0x8C180D04, // 0021 GETMET R6 R6 K4 + 0x8C200505, // 0022 GETMET R8 R2 K5 + 0x58280009, // 0023 LDCONST R10 K9 + 0x602C0008, // 0024 GETGBL R11 G8 + 0x88300B08, // 0025 GETMBR R12 R5 K8 + 0x7C2C0200, // 0026 CALL R11 1 + 0x7C200600, // 0027 CALL R8 3 + 0x7C180400, // 0028 CALL R6 2 + 0x8C180B0A, // 0029 GETMET R6 R5 K10 + 0x7C180200, // 002A CALL R6 1 + 0x80040A00, // 002B RET 1 R5 + 0x000C070B, // 002C ADD R3 R3 K11 + 0x7001FFD8, // 002D JMP #0007 + 0x80000000, // 002E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_fabric, /* 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[ 7]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(_fabric), + /* K3 */ be_nested_str_weak(remove), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(fabrics), + /* K6 */ be_nested_str_weak(find), + }), + be_str_weak(remove_fabric), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* 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 + 0x780E000B, // 0005 JMPF R3 #0012 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x880C0702, // 0008 GETMBR R3 R3 K2 + 0x1C0C0601, // 0009 EQ R3 R3 R1 + 0x780E0004, // 000A JMPF R3 #0010 + 0x880C0101, // 000B GETMBR R3 R0 K1 + 0x8C0C0703, // 000C GETMET R3 R3 K3 + 0x5C140400, // 000D MOVE R5 R2 + 0x7C0C0400, // 000E CALL R3 2 + 0x70020000, // 000F JMP #0011 + 0x00080504, // 0010 ADD R2 R2 K4 + 0x7001FFEE, // 0011 JMP #0001 + 0x880C0105, // 0012 GETMBR R3 R0 K5 + 0x8C0C0703, // 0013 GETMET R3 R3 K3 + 0x88140105, // 0014 GETMBR R5 R0 K5 + 0x8C140B06, // 0015 GETMET R5 R5 K6 + 0x5C1C0200, // 0016 MOVE R7 R1 + 0x7C140400, // 0017 CALL R5 2 + 0x7C0C0400, // 0018 CALL R3 2 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_session_source_id_unsecure +********************************************************************/ +be_local_closure(Matter_Session_Store_find_session_source_id_unsecure, /* 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[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_source_node_id), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Session), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(_source_node_id), + /* K5 */ be_nested_str_weak(sessions), + /* K6 */ be_nested_str_weak(push), + /* K7 */ be_nested_str_weak(set_expire_in_seconds), + /* K8 */ be_nested_str_weak(update), + }), + be_str_weak(find_session_source_id_unsecure), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C100604, // 0004 EQ R4 R3 R4 + 0x7812000E, // 0005 JMPF R4 #0015 + 0xB8120200, // 0006 GETNGBL R4 K1 + 0x8C100902, // 0007 GETMET R4 R4 K2 + 0x5C180000, // 0008 MOVE R6 R0 + 0x581C0003, // 0009 LDCONST R7 K3 + 0x58200003, // 000A LDCONST R8 K3 + 0x7C100800, // 000B CALL R4 4 + 0x5C0C0800, // 000C MOVE R3 R4 + 0x900E0801, // 000D SETMBR R3 K4 R1 + 0x88100105, // 000E GETMBR R4 R0 K5 + 0x8C100906, // 000F GETMET R4 R4 K6 + 0x5C180600, // 0010 MOVE R6 R3 + 0x7C100400, // 0011 CALL R4 2 + 0x8C100707, // 0012 GETMET R4 R3 K7 + 0x5C180400, // 0013 MOVE R6 R2 + 0x7C100400, // 0014 CALL R4 2 + 0x8C100708, // 0015 GETMET R4 R3 K8 + 0x7C100200, // 0016 CALL R4 1 + 0x80040600, // 0017 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_source_node_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_source_node_id, /* 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(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(_source_node_id), + /* K3 */ be_nested_str_weak(update), + /* K4 */ be_const_int(1), + }), + be_str_weak(get_session_by_source_node_id), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160008, // 000B JMPF R5 #0015 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88180B02, // 000D GETMBR R6 R5 K2 + 0x1C180C01, // 000E EQ R6 R6 R1 + 0x781A0002, // 000F JMPF R6 #0013 + 0x8C180B03, // 0010 GETMET R6 R5 K3 + 0x7C180200, // 0011 CALL R6 1 + 0x80040A00, // 0012 RET 1 R5 + 0x000C0704, // 0013 ADD R3 R3 K4 + 0x7001FFF4, // 0014 JMP #000A + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_session +********************************************************************/ +be_local_closure(Matter_Session_Store_add_session, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(set_expire_in_seconds), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(push), + }), + be_str_weak(add_session), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x8C0C0300, // 0003 GETMET R3 R1 K0 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: count_active_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_count_active_fabrics, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(remove_expired), + /* K1 */ be_nested_str_weak(fabrics), + /* K2 */ be_nested_str_weak(count_persistables), + }), + be_str_weak(count_active_fabrics), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_expired +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_expired, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(every_second), + /* K2 */ be_nested_str_weak(fabrics), + }), + be_str_weak(remove_expired), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* 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 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_children_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_find_children_fabrics, /* 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( + 7, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 3]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 2), + be_local_const_upval(1, 3), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(active_fabrics), + /* K1 */ be_nested_str_weak(fabric_parent), + /* K2 */ be_nested_str_weak(find), + /* K3 */ be_nested_str_weak(fabric_index), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(find_children_fabrics_inner), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x68080000, // 0001 GETUPV R2 U0 + 0x8C080500, // 0002 GETMET R2 R2 K0 + 0x7C080200, // 0003 CALL R2 1 + 0x7C040200, // 0004 CALL R1 1 + 0xA8020013, // 0005 EXBLK 0 #001A + 0x5C080200, // 0006 MOVE R2 R1 + 0x7C080000, // 0007 CALL R2 0 + 0x880C0501, // 0008 GETMBR R3 R2 K1 + 0x1C0C0600, // 0009 EQ R3 R3 R0 + 0x780E000D, // 000A JMPF R3 #0019 + 0x680C0001, // 000B GETUPV R3 U1 + 0x8C0C0702, // 000C GETMET R3 R3 K2 + 0x7C0C0200, // 000D CALL R3 1 + 0x4C100000, // 000E LDNIL R4 + 0x1C0C0604, // 000F EQ R3 R3 R4 + 0x780E0007, // 0010 JMPF R3 #0019 + 0x880C0503, // 0011 GETMBR R3 R2 K3 + 0x68100001, // 0012 GETUPV R4 U1 + 0x8C100904, // 0013 GETMET R4 R4 K4 + 0x5C180600, // 0014 MOVE R6 R3 + 0x7C100400, // 0015 CALL R4 2 + 0x68100002, // 0016 GETUPV R4 U2 + 0x5C140600, // 0017 MOVE R5 R3 + 0x7C100200, // 0018 CALL R4 1 + 0x7001FFEB, // 0019 JMP #0006 + 0x58040005, // 001A LDCONST R1 K5 + 0xAC040200, // 001B CATCH R1 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x80000000, // 001D RET 0 + }) + ), + }), + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(find_children_fabrics), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0002, // 0002 JMPF R2 #0006 + 0x60080012, // 0003 GETGBL R2 G18 + 0x7C080000, // 0004 CALL R2 0 + 0x80040400, // 0005 RET 1 R2 + 0x60080012, // 0006 GETGBL R2 G18 + 0x7C080000, // 0007 CALL R2 0 + 0x400C0401, // 0008 CONNECT R3 R2 R1 + 0x840C0000, // 0009 CLOSURE R3 P0 + 0x5C100600, // 000A MOVE R4 R3 + 0x5C140200, // 000B MOVE R5 R1 + 0x7C100200, // 000C CALL R4 1 + 0xA0000000, // 000D CLOSE R0 + 0x80040400, // 000E RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_fabric_by_index +********************************************************************/ +be_local_closure(Matter_Session_Store_find_fabric_by_index, /* 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_weak(active_fabrics), + /* K1 */ be_nested_str_weak(get_fabric_index), + /* K2 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(find_fabric_by_index), + &be_const_str_solidified, + ( &(const binstruction[19]) { /* code */ + 0x60080010, // 0000 GETGBL R2 G16 + 0x8C0C0100, // 0001 GETMET R3 R0 K0 + 0x7C0C0200, // 0002 CALL R3 1 + 0x7C080200, // 0003 CALL R2 1 + 0xA8020008, // 0004 EXBLK 0 #000E + 0x5C0C0400, // 0005 MOVE R3 R2 + 0x7C0C0000, // 0006 CALL R3 0 + 0x8C100701, // 0007 GETMET R4 R3 K1 + 0x7C100200, // 0008 CALL R4 1 + 0x1C100801, // 0009 EQ R4 R4 R1 + 0x78120001, // 000A JMPF R4 #000D + 0xA8040001, // 000B EXBLK 1 1 + 0x80040600, // 000C RET 1 R3 + 0x7001FFF6, // 000D JMP #0005 + 0x58080002, // 000E LDCONST R2 K2 + 0xAC080200, // 000F CATCH R2 1 0 + 0xB0080000, // 0010 RAISE 2 R0 R0 + 0x4C080000, // 0011 LDNIL R2 + 0x80040400, // 0012 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: next_fabric_idx +********************************************************************/ +be_local_closure(Matter_Session_Store_next_fabric_idx, /* 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(remove_expired), + /* K1 */ be_const_int(1), + /* K2 */ be_nested_str_weak(active_fabrics), + /* K3 */ be_nested_str_weak(fabric_index), + /* K4 */ be_nested_str_weak(int), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(next_fabric_idx), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x58040001, // 0002 LDCONST R1 K1 + 0x60080010, // 0003 GETGBL R2 G16 + 0x8C0C0102, // 0004 GETMET R3 R0 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x7C080200, // 0006 CALL R2 1 + 0xA802000C, // 0007 EXBLK 0 #0015 + 0x5C0C0400, // 0008 MOVE R3 R2 + 0x7C0C0000, // 0009 CALL R3 0 + 0x88100703, // 000A GETMBR R4 R3 K3 + 0x60140004, // 000B GETGBL R5 G4 + 0x5C180800, // 000C MOVE R6 R4 + 0x7C140200, // 000D CALL R5 1 + 0x1C140B04, // 000E EQ R5 R5 K4 + 0x78160003, // 000F JMPF R5 #0014 + 0x28140801, // 0010 GE R5 R4 R1 + 0x78160001, // 0011 JMPF R5 #0014 + 0x00140901, // 0012 ADD R5 R4 K1 + 0x5C040A00, // 0013 MOVE R1 R5 + 0x7001FFF2, // 0014 JMP #0008 + 0x58080005, // 0015 LDCONST R2 K5 + 0xAC080200, // 0016 CATCH R2 1 0 + 0xB0080000, // 0017 RAISE 2 R0 R0 + 0x80040200, // 0018 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_session_by_local_session_id +********************************************************************/ +be_local_closure(Matter_Session_Store_get_session_by_local_session_id, /* 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(sessions), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(local_session_id), + /* K3 */ be_nested_str_weak(update), + /* K4 */ be_const_int(1), + }), + be_str_weak(get_session_by_local_session_id), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000C, // 0005 GETGBL R2 G12 + 0x880C0100, // 0006 GETMBR R3 R0 K0 + 0x7C080200, // 0007 CALL R2 1 + 0x580C0001, // 0008 LDCONST R3 K1 + 0x88100100, // 0009 GETMBR R4 R0 K0 + 0x14140602, // 000A LT R5 R3 R2 + 0x78160008, // 000B JMPF R5 #0015 + 0x94140803, // 000C GETIDX R5 R4 R3 + 0x88180B02, // 000D GETMBR R6 R5 K2 + 0x1C180C01, // 000E EQ R6 R6 R1 + 0x781A0002, // 000F JMPF R6 #0013 + 0x8C180B03, // 0010 GETMET R6 R5 K3 + 0x7C180200, // 0011 CALL R6 1 + 0x80040A00, // 0012 RET 1 R5 + 0x000C0704, // 0013 ADD R3 R3 K4 + 0x7001FFF4, // 0014 JMP #000A + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: active_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_active_fabrics, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(remove_expired), + /* K1 */ be_nested_str_weak(fabrics), + /* K2 */ be_nested_str_weak(persistables), + }), + be_str_weak(active_fabrics), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Session_Store_every_second, /* 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(remove_expired), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_session +********************************************************************/ +be_local_closure(Matter_Session_Store_remove_session, /* 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(sessions), + /* K2 */ be_nested_str_weak(remove), + /* K3 */ be_const_int(1), + }), + be_str_weak(remove_session), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x88140101, // 0003 GETMBR R5 R0 K1 + 0x7C100200, // 0004 CALL R4 1 + 0x14100404, // 0005 LT R4 R2 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100602, // 0007 GETIDX R4 R3 R2 + 0x1C100801, // 0008 EQ R4 R4 R1 + 0x78120003, // 0009 JMPF R4 #000E + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x5C180400, // 000B MOVE R6 R2 + 0x7C100400, // 000C CALL R4 2 + 0x70020000, // 000D JMP #000F + 0x00080503, // 000E ADD R2 R2 K3 + 0x7001FFF1, // 000F JMP #0002 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Session_Store_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_weak(sessions), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(Expirable_list), + /* K3 */ be_nested_str_weak(fabrics), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB8060200, // 0000 GETNGBL R1 K1 + 0x8C040302, // 0001 GETMET R1 R1 K2 + 0x7C040200, // 0002 CALL R1 1 + 0x90020001, // 0003 SETMBR R0 K0 R1 + 0xB8060200, // 0004 GETNGBL R1 K1 + 0x8C040302, // 0005 GETMET R1 R1 K2 + 0x7C040200, // 0006 CALL R1 1 + 0x90020601, // 0007 SETMBR R0 K3 R1 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_session +********************************************************************/ +be_local_closure(Matter_Session_Store_create_session, /* 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[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(get_session_by_local_session_id), + /* K1 */ be_nested_str_weak(remove_session), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Session), + /* K4 */ be_nested_str_weak(sessions), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(create_session), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C0C0400, // 0002 CALL R3 2 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120002, // 0005 JMPF R4 #0009 + 0x8C100101, // 0006 GETMET R4 R0 K1 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0xB8120400, // 0009 GETNGBL R4 K2 + 0x8C100903, // 000A GETMET R4 R4 K3 + 0x5C180000, // 000B MOVE R6 R0 + 0x5C1C0200, // 000C MOVE R7 R1 + 0x5C200400, // 000D MOVE R8 R2 + 0x7C100800, // 000E CALL R4 4 + 0x5C0C0800, // 000F MOVE R3 R4 + 0x88100104, // 0010 GETMBR R4 R0 K4 + 0x8C100905, // 0011 GETMET R4 R4 K5 + 0x5C180600, // 0012 MOVE R6 R3 + 0x7C100400, // 0013 CALL R4 2 + 0x80040600, // 0014 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_save_fabrics, /* name */ + be_nested_proto( + 14, /* nstack */ + 1, /* 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(json), + /* K1 */ be_nested_str_weak(remove_expired), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(fabrics), + /* K4 */ be_nested_str_weak(persistables), + /* K5 */ be_nested_str_weak(_sessions), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(stop_iteration), + /* K8 */ be_nested_str_weak(push), + /* K9 */ be_nested_str_weak(tojson), + /* K10 */ be_nested_str_weak(_X5B), + /* K11 */ be_nested_str_weak(concat), + /* K12 */ be_nested_str_weak(_X2C), + /* K13 */ be_nested_str_weak(_X5D), + /* K14 */ be_nested_str_weak(string), + /* K15 */ be_nested_str_weak(_FABRICS), + /* K16 */ be_nested_str_weak(w), + /* K17 */ be_nested_str_weak(write), + /* K18 */ be_nested_str_weak(close), + /* K19 */ be_nested_str_weak(tasmota), + /* K20 */ be_nested_str_weak(log), + /* K21 */ be_nested_str_weak(format), + /* K22 */ be_nested_str_weak(MTR_X3A_X20_X3DSaved_X20_X20_X20_X20_X20_X25i_X20fabric_X28s_X29_X20and_X20_X25i_X20session_X28s_X29), + /* K23 */ be_const_int(2), + /* K24 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K25 */ be_nested_str_weak(_X7C), + }), + be_str_weak(save_fabrics), + &be_const_str_solidified, + ( &(const binstruction[84]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x58080002, // 0003 LDCONST R2 K2 + 0x600C0012, // 0004 GETGBL R3 G18 + 0x7C0C0000, // 0005 CALL R3 0 + 0x60100010, // 0006 GETGBL R4 G16 + 0x88140103, // 0007 GETMBR R5 R0 K3 + 0x8C140B04, // 0008 GETMET R5 R5 K4 + 0x7C140200, // 0009 CALL R5 1 + 0x7C100200, // 000A CALL R4 1 + 0xA8020013, // 000B EXBLK 0 #0020 + 0x5C140800, // 000C MOVE R5 R4 + 0x7C140000, // 000D CALL R5 0 + 0x60180010, // 000E GETGBL R6 G16 + 0x881C0B05, // 000F GETMBR R7 R5 K5 + 0x8C1C0F04, // 0010 GETMET R7 R7 K4 + 0x7C1C0200, // 0011 CALL R7 1 + 0x7C180200, // 0012 CALL R6 1 + 0xA8020003, // 0013 EXBLK 0 #0018 + 0x5C1C0C00, // 0014 MOVE R7 R6 + 0x7C1C0000, // 0015 CALL R7 0 + 0x00080506, // 0016 ADD R2 R2 K6 + 0x7001FFFB, // 0017 JMP #0014 + 0x58180007, // 0018 LDCONST R6 K7 + 0xAC180200, // 0019 CATCH R6 1 0 + 0xB0080000, // 001A RAISE 2 R0 R0 + 0x8C180708, // 001B GETMET R6 R3 K8 + 0x8C200B09, // 001C GETMET R8 R5 K9 + 0x7C200200, // 001D CALL R8 1 + 0x7C180400, // 001E CALL R6 2 + 0x7001FFEB, // 001F JMP #000C + 0x58100007, // 0020 LDCONST R4 K7 + 0xAC100200, // 0021 CATCH R4 1 0 + 0xB0080000, // 0022 RAISE 2 R0 R0 + 0x6010000C, // 0023 GETGBL R4 G12 + 0x5C140600, // 0024 MOVE R5 R3 + 0x7C100200, // 0025 CALL R4 1 + 0x8C14070B, // 0026 GETMET R5 R3 K11 + 0x581C000C, // 0027 LDCONST R7 K12 + 0x7C140400, // 0028 CALL R5 2 + 0x00161405, // 0029 ADD R5 K10 R5 + 0x00140B0D, // 002A ADD R5 R5 K13 + 0x5C0C0A00, // 002B MOVE R3 R5 + 0xA8020014, // 002C EXBLK 0 #0042 + 0xA4161C00, // 002D IMPORT R5 K14 + 0x60180011, // 002E GETGBL R6 G17 + 0x881C010F, // 002F GETMBR R7 R0 K15 + 0x58200010, // 0030 LDCONST R8 K16 + 0x7C180400, // 0031 CALL R6 2 + 0x8C1C0D11, // 0032 GETMET R7 R6 K17 + 0x5C240600, // 0033 MOVE R9 R3 + 0x7C1C0400, // 0034 CALL R7 2 + 0x8C1C0D12, // 0035 GETMET R7 R6 K18 + 0x7C1C0200, // 0036 CALL R7 1 + 0xB81E2600, // 0037 GETNGBL R7 K19 + 0x8C1C0F14, // 0038 GETMET R7 R7 K20 + 0x8C240B15, // 0039 GETMET R9 R5 K21 + 0x582C0016, // 003A LDCONST R11 K22 + 0x5C300800, // 003B MOVE R12 R4 + 0x5C340400, // 003C MOVE R13 R2 + 0x7C240800, // 003D CALL R9 4 + 0x58280017, // 003E LDCONST R10 K23 + 0x7C1C0600, // 003F CALL R7 3 + 0xA8040001, // 0040 EXBLK 1 1 + 0x70020010, // 0041 JMP #0053 + 0xAC140002, // 0042 CATCH R5 0 2 + 0x7002000D, // 0043 JMP #0052 + 0xB81E2600, // 0044 GETNGBL R7 K19 + 0x8C1C0F14, // 0045 GETMET R7 R7 K20 + 0x60240008, // 0046 GETGBL R9 G8 + 0x5C280A00, // 0047 MOVE R10 R5 + 0x7C240200, // 0048 CALL R9 1 + 0x00263009, // 0049 ADD R9 K24 R9 + 0x00241319, // 004A ADD R9 R9 K25 + 0x60280008, // 004B GETGBL R10 G8 + 0x5C2C0C00, // 004C MOVE R11 R6 + 0x7C280200, // 004D CALL R10 1 + 0x0024120A, // 004E ADD R9 R9 R10 + 0x58280017, // 004F LDCONST R10 K23 + 0x7C1C0600, // 0050 CALL R7 3 + 0x70020000, // 0051 JMP #0053 + 0xB0080000, // 0052 RAISE 2 R0 R0 + 0x80000000, // 0053 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load_fabrics +********************************************************************/ +be_local_closure(Matter_Session_Store_load_fabrics, /* name */ + be_nested_proto( + 17, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[29]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(matter), + /* K3 */ be_nested_str_weak(Expirable_list), + /* K4 */ be_nested_str_weak(fabrics), + /* K5 */ be_nested_str_weak(_FABRICS), + /* K6 */ be_nested_str_weak(read), + /* K7 */ be_nested_str_weak(close), + /* K8 */ be_nested_str_weak(json), + /* K9 */ be_nested_str_weak(load), + /* K10 */ be_nested_str_weak(tasmota), + /* K11 */ be_nested_str_weak(gc), + /* K12 */ be_nested_str_weak(Fabric), + /* K13 */ be_nested_str_weak(fromjson), + /* K14 */ be_nested_str_weak(set_no_expiration), + /* K15 */ be_nested_str_weak(set_persist), + /* K16 */ be_nested_str_weak(find), + /* K17 */ be_nested_str_weak(_sessions), + /* K18 */ be_nested_str_weak(Session), + /* K19 */ be_nested_str_weak(add_session), + /* K20 */ be_nested_str_weak(stop_iteration), + /* K21 */ be_nested_str_weak(push), + /* K22 */ be_nested_str_weak(log), + /* K23 */ be_nested_str_weak(format), + /* K24 */ be_nested_str_weak(MTR_X3A_X20Loaded_X20_X25i_X20fabric_X28s_X29), + /* K25 */ be_const_int(2), + /* 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), + }), + be_str_weak(load_fabrics), + &be_const_str_solidified, + ( &(const binstruction[118]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA802005F, // 0001 EXBLK 0 #0062 + 0xB80A0400, // 0002 GETNGBL R2 K2 + 0x8C080503, // 0003 GETMET R2 R2 K3 + 0x7C080200, // 0004 CALL R2 1 + 0x90020202, // 0005 SETMBR R0 K1 R2 + 0xB80A0400, // 0006 GETNGBL R2 K2 + 0x8C080503, // 0007 GETMET R2 R2 K3 + 0x7C080200, // 0008 CALL R2 1 + 0x90020802, // 0009 SETMBR R0 K4 R2 + 0x60080011, // 000A GETGBL R2 G17 + 0x880C0105, // 000B GETMBR R3 R0 K5 + 0x7C080200, // 000C CALL R2 1 + 0x8C0C0506, // 000D GETMET R3 R2 K6 + 0x7C0C0200, // 000E CALL R3 1 + 0x8C100507, // 000F GETMET R4 R2 K7 + 0x7C100200, // 0010 CALL R4 1 + 0xA4121000, // 0011 IMPORT R4 K8 + 0x8C140909, // 0012 GETMET R5 R4 K9 + 0x5C1C0600, // 0013 MOVE R7 R3 + 0x7C140400, // 0014 CALL R5 2 + 0x4C0C0000, // 0015 LDNIL R3 + 0xB81A1400, // 0016 GETNGBL R6 K10 + 0x8C180D0B, // 0017 GETMET R6 R6 K11 + 0x7C180200, // 0018 CALL R6 1 + 0x60180010, // 0019 GETGBL R6 G16 + 0x5C1C0A00, // 001A MOVE R7 R5 + 0x7C180200, // 001B CALL R6 1 + 0xA8020035, // 001C EXBLK 0 #0053 + 0x5C1C0C00, // 001D MOVE R7 R6 + 0x7C1C0000, // 001E CALL R7 0 + 0xB8220400, // 001F GETNGBL R8 K2 + 0x8820110C, // 0020 GETMBR R8 R8 K12 + 0x8C20110D, // 0021 GETMET R8 R8 K13 + 0x5C280000, // 0022 MOVE R10 R0 + 0x5C2C0E00, // 0023 MOVE R11 R7 + 0x7C200600, // 0024 CALL R8 3 + 0x8C24110E, // 0025 GETMET R9 R8 K14 + 0x7C240200, // 0026 CALL R9 1 + 0x8C24110F, // 0027 GETMET R9 R8 K15 + 0x502C0200, // 0028 LDBOOL R11 1 0 + 0x7C240400, // 0029 CALL R9 2 + 0x8C240F10, // 002A GETMET R9 R7 K16 + 0x582C0011, // 002B LDCONST R11 K17 + 0x60300012, // 002C GETGBL R12 G18 + 0x7C300000, // 002D CALL R12 0 + 0x7C240600, // 002E CALL R9 3 + 0x60280010, // 002F GETGBL R10 G16 + 0x5C2C1200, // 0030 MOVE R11 R9 + 0x7C280200, // 0031 CALL R10 1 + 0xA8020017, // 0032 EXBLK 0 #004B + 0x5C2C1400, // 0033 MOVE R11 R10 + 0x7C2C0000, // 0034 CALL R11 0 + 0xB8320400, // 0035 GETNGBL R12 K2 + 0x88301912, // 0036 GETMBR R12 R12 K18 + 0x8C30190D, // 0037 GETMET R12 R12 K13 + 0x5C380000, // 0038 MOVE R14 R0 + 0x5C3C1600, // 0039 MOVE R15 R11 + 0x5C401000, // 003A MOVE R16 R8 + 0x7C300800, // 003B CALL R12 4 + 0x4C340000, // 003C LDNIL R13 + 0x2034180D, // 003D NE R13 R12 R13 + 0x7836000A, // 003E JMPF R13 #004A + 0x8C34190E, // 003F GETMET R13 R12 K14 + 0x7C340200, // 0040 CALL R13 1 + 0x8C34190F, // 0041 GETMET R13 R12 K15 + 0x503C0200, // 0042 LDBOOL R15 1 0 + 0x7C340400, // 0043 CALL R13 2 + 0x8C340113, // 0044 GETMET R13 R0 K19 + 0x5C3C1800, // 0045 MOVE R15 R12 + 0x7C340400, // 0046 CALL R13 2 + 0x8C341113, // 0047 GETMET R13 R8 K19 + 0x5C3C1800, // 0048 MOVE R15 R12 + 0x7C340400, // 0049 CALL R13 2 + 0x7001FFE7, // 004A JMP #0033 + 0x58280014, // 004B LDCONST R10 K20 + 0xAC280200, // 004C CATCH R10 1 0 + 0xB0080000, // 004D RAISE 2 R0 R0 + 0x88280104, // 004E GETMBR R10 R0 K4 + 0x8C281515, // 004F GETMET R10 R10 K21 + 0x5C301000, // 0050 MOVE R12 R8 + 0x7C280400, // 0051 CALL R10 2 + 0x7001FFC9, // 0052 JMP #001D + 0x58180014, // 0053 LDCONST R6 K20 + 0xAC180200, // 0054 CATCH R6 1 0 + 0xB0080000, // 0055 RAISE 2 R0 R0 + 0xB81A1400, // 0056 GETNGBL R6 K10 + 0x8C180D16, // 0057 GETMET R6 R6 K22 + 0x8C200317, // 0058 GETMET R8 R1 K23 + 0x58280018, // 0059 LDCONST R10 K24 + 0x602C000C, // 005A GETGBL R11 G12 + 0x88300104, // 005B GETMBR R12 R0 K4 + 0x7C2C0200, // 005C CALL R11 1 + 0x7C200600, // 005D CALL R8 3 + 0x58240019, // 005E LDCONST R9 K25 + 0x7C180600, // 005F CALL R6 3 + 0xA8040001, // 0060 EXBLK 1 1 + 0x70020012, // 0061 JMP #0075 + 0xAC080002, // 0062 CATCH R2 0 2 + 0x7002000F, // 0063 JMP #0074 + 0x2010051A, // 0064 NE R4 R2 K26 + 0x7812000C, // 0065 JMPF R4 #0073 + 0xB8121400, // 0066 GETNGBL R4 K10 + 0x8C100916, // 0067 GETMET R4 R4 K22 + 0x60180008, // 0068 GETGBL R6 G8 + 0x5C1C0400, // 0069 MOVE R7 R2 + 0x7C180200, // 006A CALL R6 1 + 0x001A3606, // 006B ADD R6 K27 R6 + 0x00180D1C, // 006C ADD R6 R6 K28 + 0x601C0008, // 006D GETGBL R7 G8 + 0x5C200600, // 006E MOVE R8 R3 + 0x7C1C0200, // 006F CALL R7 1 + 0x00180C07, // 0070 ADD R6 R6 R7 + 0x581C0019, // 0071 LDCONST R7 K25 + 0x7C100600, // 0072 CALL R4 3 + 0x70020000, // 0073 JMP #0075 + 0xB0080000, // 0074 RAISE 2 R0 R0 + 0x80000000, // 0075 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: sessions_active +********************************************************************/ +be_local_closure(Matter_Session_Store_sessions_active, /* 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_const_int(0), + /* K1 */ be_nested_str_weak(sessions), + /* K2 */ be_nested_str_weak(get_device_id), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_const_int(1), + }), + be_str_weak(sessions_active), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x58080000, // 0002 LDCONST R2 K0 + 0x600C000C, // 0003 GETGBL R3 G12 + 0x88100101, // 0004 GETMBR R4 R0 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x140C0403, // 0006 LT R3 R2 R3 + 0x780E000C, // 0007 JMPF R3 #0015 + 0x880C0101, // 0008 GETMBR R3 R0 K1 + 0x940C0602, // 0009 GETIDX R3 R3 R2 + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x7C100200, // 000B CALL R4 1 + 0x78120005, // 000C JMPF R4 #0013 + 0x8C100703, // 000D GETMET R4 R3 K3 + 0x7C100200, // 000E CALL R4 1 + 0x78120002, // 000F JMPF R4 #0013 + 0x8C100304, // 0010 GETMET R4 R1 K4 + 0x5C180600, // 0011 MOVE R6 R3 + 0x7C100400, // 0012 CALL R4 2 + 0x00080505, // 0013 ADD R2 R2 K5 + 0x7001FFED, // 0014 JMP #0003 + 0x80040200, // 0015 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_create_fabric, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Fabric), + }), + be_str_weak(create_fabric), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x80040200, // 0004 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_fabric +********************************************************************/ +be_local_closure(Matter_Session_Store_add_fabric, /* 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[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Fabric), + /* K2 */ be_nested_str_weak(value_error), + /* K3 */ be_nested_str_weak(must_X20be_X20of_X20class_X20matter_X2EFabric), + /* K4 */ be_nested_str_weak(fabrics), + /* K5 */ be_nested_str_weak(find), + /* K6 */ be_nested_str_weak(remove_redundant_fabric), + /* K7 */ be_nested_str_weak(push), + }), + be_str_weak(add_fabric), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x6008000F, // 0000 GETGBL R2 G15 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0xB8120000, // 0002 GETNGBL R4 K0 + 0x88100901, // 0003 GETMBR R4 R4 K1 + 0x7C080400, // 0004 CALL R2 2 + 0x740A0000, // 0005 JMPT R2 #0007 + 0xB0060503, // 0006 RAISE 1 K2 K3 + 0x88080104, // 0007 GETMBR R2 R0 K4 + 0x8C080505, // 0008 GETMET R2 R2 K5 + 0x5C100200, // 0009 MOVE R4 R1 + 0x7C080400, // 000A CALL R2 2 + 0x4C0C0000, // 000B LDNIL R3 + 0x1C080403, // 000C EQ R2 R2 R3 + 0x780A0006, // 000D JMPF R2 #0015 + 0x8C080106, // 000E GETMET R2 R0 K6 + 0x5C100200, // 000F MOVE R4 R1 + 0x7C080400, // 0010 CALL R2 2 + 0x88080104, // 0011 GETMBR R2 R0 K4 + 0x8C080507, // 0012 GETMET R2 R2 K7 + 0x5C100200, // 0013 MOVE R4 R1 + 0x7C080400, // 0014 CALL R2 2 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Session_Store +********************************************************************/ +be_local_class(Matter_Session_Store, + 2, + NULL, + be_nested_map(26, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(gen_local_session_id, 25), be_const_closure(Matter_Session_Store_gen_local_session_id_closure) }, + { be_const_key_weak(remove_redundant_fabric, 15), be_const_closure(Matter_Session_Store_remove_redundant_fabric_closure) }, + { be_const_key_weak(find_session_by_resumption_id, -1), be_const_closure(Matter_Session_Store_find_session_by_resumption_id_closure) }, + { be_const_key_weak(fabrics, 5), be_const_var(1) }, + { be_const_key_weak(add_fabric, -1), be_const_closure(Matter_Session_Store_add_fabric_closure) }, + { be_const_key_weak(create_fabric, -1), be_const_closure(Matter_Session_Store_create_fabric_closure) }, + { be_const_key_weak(sessions_active, -1), be_const_closure(Matter_Session_Store_sessions_active_closure) }, + { be_const_key_weak(add_session, -1), be_const_closure(Matter_Session_Store_add_session_closure) }, + { be_const_key_weak(count_active_fabrics, -1), be_const_closure(Matter_Session_Store_count_active_fabrics_closure) }, + { be_const_key_weak(remove_expired, 17), be_const_closure(Matter_Session_Store_remove_expired_closure) }, + { be_const_key_weak(_FABRICS, -1), be_nested_str_weak(_matter_fabrics_X2Ejson) }, + { be_const_key_weak(find_fabric_by_index, -1), be_const_closure(Matter_Session_Store_find_fabric_by_index_closure) }, + { be_const_key_weak(sessions, 4), be_const_var(0) }, + { be_const_key_weak(get_session_by_source_node_id, 11), be_const_closure(Matter_Session_Store_get_session_by_source_node_id_closure) }, + { be_const_key_weak(next_fabric_idx, -1), be_const_closure(Matter_Session_Store_next_fabric_idx_closure) }, + { be_const_key_weak(get_session_by_local_session_id, 24), be_const_closure(Matter_Session_Store_get_session_by_local_session_id_closure) }, + { be_const_key_weak(active_fabrics, -1), be_const_closure(Matter_Session_Store_active_fabrics_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Session_Store_every_second_closure) }, + { be_const_key_weak(remove_session, -1), be_const_closure(Matter_Session_Store_remove_session_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Session_Store_init_closure) }, + { be_const_key_weak(create_session, -1), be_const_closure(Matter_Session_Store_create_session_closure) }, + { be_const_key_weak(save_fabrics, -1), be_const_closure(Matter_Session_Store_save_fabrics_closure) }, + { be_const_key_weak(load_fabrics, -1), be_const_closure(Matter_Session_Store_load_fabrics_closure) }, + { be_const_key_weak(remove_fabric, 6), be_const_closure(Matter_Session_Store_remove_fabric_closure) }, + { be_const_key_weak(find_children_fabrics, -1), be_const_closure(Matter_Session_Store_find_children_fabrics_closure) }, + { be_const_key_weak(find_session_source_id_unsecure, -1), be_const_closure(Matter_Session_Store_find_session_source_id_unsecure_closure) }, + })), + be_str_weak(Matter_Session_Store) +); +/*******************************************************************/ + +void be_load_Matter_Session_Store_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Session_Store); + be_setglobal(vm, "Matter_Session_Store"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h index dc225d633..784417069 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_TLV.h @@ -6,6 +6,101 @@ extern const bclass be_class_Matter_TLV_item; +/******************************************************************** +** Solidified function: set_parent +********************************************************************/ +be_local_closure(Matter_TLV_item_set_parent, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(parent), + }), + be_str_weak(set_parent), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: create_TLV +********************************************************************/ +be_local_closure(Matter_TLV_item_create_TLV, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* 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_TLV_item), + /* K1 */ be_nested_str_weak(typ), + /* K2 */ be_nested_str_weak(val), + }), + be_str_weak(create_TLV), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x200C0203, // 0002 NE R3 R1 R3 + 0x740E0002, // 0003 JMPT R3 #0007 + 0x540E0013, // 0004 LDINT R3 20 + 0x1C0C0003, // 0005 EQ R3 R0 R3 + 0x780E0004, // 0006 JMPF R3 #000C + 0x5C0C0400, // 0007 MOVE R3 R2 + 0x7C0C0000, // 0008 CALL R3 0 + 0x900E0200, // 0009 SETMBR R3 K1 R0 + 0x900E0401, // 000A SETMBR R3 K2 R1 + 0x80040600, // 000B RET 1 R3 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_anonymoustag +********************************************************************/ +be_local_closure(Matter_TLV_item_set_anonymoustag, /* 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(set_fulltag), + }), + be_str_weak(set_anonymoustag), + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: set_commonprofile ********************************************************************/ @@ -38,9 +133,909 @@ be_local_closure(Matter_TLV_item_set_commonprofile, /* name */ /******************************************************************** -** Solidified function: encode +** Solidified function: _cmp_gt ********************************************************************/ -be_local_closure(Matter_TLV_item_encode, /* name */ +be_local_closure(Matter_TLV_item__cmp_gt, /* name */ + be_nested_proto( + 4, /* 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(tag_vendor), + /* K1 */ be_const_int(1), + /* K2 */ be_nested_str_weak(tag_profile), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(tag_number), + /* K5 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(_cmp_gt), + &be_const_str_solidified, + ( &(const binstruction[72]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x20080403, // 0002 NE R2 R2 R3 + 0x780A0012, // 0003 JMPF R2 #0017 + 0x88080300, // 0004 GETMBR R2 R1 K0 + 0x4C0C0000, // 0005 LDNIL R3 + 0x1C080403, // 0006 EQ R2 R2 R3 + 0x780A0000, // 0007 JMPF R2 #0009 + 0x80060200, // 0008 RET 1 K1 + 0x88080100, // 0009 GETMBR R2 R0 K0 + 0x880C0300, // 000A GETMBR R3 R1 K0 + 0x24080403, // 000B GT R2 R2 R3 + 0x780A0000, // 000C JMPF R2 #000E + 0x80060200, // 000D RET 1 K1 + 0x88080100, // 000E GETMBR R2 R0 K0 + 0x880C0300, // 000F GETMBR R3 R1 K0 + 0x1C080403, // 0010 EQ R2 R2 R3 + 0x780A0004, // 0011 JMPF R2 #0017 + 0x88080102, // 0012 GETMBR R2 R0 K2 + 0x880C0302, // 0013 GETMBR R3 R1 K2 + 0x24080403, // 0014 GT R2 R2 R3 + 0x780A0000, // 0015 JMPF R2 #0017 + 0x80060200, // 0016 RET 1 K1 + 0x88080102, // 0017 GETMBR R2 R0 K2 + 0x540DFFFE, // 0018 LDINT R3 -1 + 0x1C080403, // 0019 EQ R2 R2 R3 + 0x780A0005, // 001A JMPF R2 #0021 + 0x88080302, // 001B GETMBR R2 R1 K2 + 0x4C0C0000, // 001C LDNIL R3 + 0x1C080403, // 001D EQ R2 R2 R3 + 0x780A0000, // 001E JMPF R2 #0020 + 0x80060200, // 001F RET 1 K1 + 0x70020008, // 0020 JMP #002A + 0x88080102, // 0021 GETMBR R2 R0 K2 + 0x4C0C0000, // 0022 LDNIL R3 + 0x1C080403, // 0023 EQ R2 R2 R3 + 0x780A0004, // 0024 JMPF R2 #002A + 0x88080302, // 0025 GETMBR R2 R1 K2 + 0x540DFFFE, // 0026 LDINT R3 -1 + 0x1C080403, // 0027 EQ R2 R2 R3 + 0x780A0000, // 0028 JMPF R2 #002A + 0x80060600, // 0029 RET 1 K3 + 0x88080104, // 002A GETMBR R2 R0 K4 + 0x4C0C0000, // 002B LDNIL R3 + 0x20080403, // 002C NE R2 R2 R3 + 0x780A000A, // 002D JMPF R2 #0039 + 0x88080304, // 002E GETMBR R2 R1 K4 + 0x4C0C0000, // 002F LDNIL R3 + 0x1C080403, // 0030 EQ R2 R2 R3 + 0x780A0000, // 0031 JMPF R2 #0033 + 0x80060200, // 0032 RET 1 K1 + 0x88080104, // 0033 GETMBR R2 R0 K4 + 0x880C0304, // 0034 GETMBR R3 R1 K4 + 0x24080403, // 0035 GT R2 R2 R3 + 0x780A0000, // 0036 JMPF R2 #0038 + 0x80060200, // 0037 RET 1 K1 + 0x80060600, // 0038 RET 1 K3 + 0x88080105, // 0039 GETMBR R2 R0 K5 + 0x4C0C0000, // 003A LDNIL R3 + 0x20080403, // 003B NE R2 R2 R3 + 0x780A0009, // 003C JMPF R2 #0047 + 0x88080305, // 003D GETMBR R2 R1 K5 + 0x4C0C0000, // 003E LDNIL R3 + 0x1C080403, // 003F EQ R2 R2 R3 + 0x780A0000, // 0040 JMPF R2 #0042 + 0x80060200, // 0041 RET 1 K1 + 0x88080105, // 0042 GETMBR R2 R0 K5 + 0x880C0305, // 0043 GETMBR R3 R1 K5 + 0x24080403, // 0044 GT R2 R2 R3 + 0x780A0000, // 0045 JMPF R2 #0047 + 0x80060200, // 0046 RET 1 K1 + 0x80060600, // 0047 RET 1 K3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _encode_tag +********************************************************************/ +be_local_closure(Matter_TLV_item__encode_tag, /* 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[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(tag_number), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(tag_vendor), + /* K3 */ be_nested_str_weak(add), + /* K4 */ be_nested_str_weak(typ), + /* K5 */ be_const_int(1), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str_weak(tag_profile), + /* K8 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(_encode_tag), + &be_const_str_solidified, + ( &(const binstruction[133]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x20080403, // 0002 NE R2 R2 R3 + 0x780A0001, // 0003 JMPF R2 #0006 + 0x88080100, // 0004 GETMBR R2 R0 K0 + 0x70020000, // 0005 JMP #0007 + 0x58080001, // 0006 LDCONST R2 K1 + 0x540EFFFF, // 0007 LDINT R3 65536 + 0x280C0403, // 0008 GE R3 R2 R3 + 0x740E0002, // 0009 JMPT R3 #000D + 0x140C0501, // 000A LT R3 R2 K1 + 0x740E0000, // 000B JMPT R3 #000D + 0x500C0001, // 000C LDBOOL R3 0 1 + 0x500C0200, // 000D LDBOOL R3 1 0 + 0x58100001, // 000E LDCONST R4 K1 + 0x88140102, // 000F GETMBR R5 R0 K2 + 0x4C180000, // 0010 LDNIL R6 + 0x20140A06, // 0011 NE R5 R5 R6 + 0x78160026, // 0012 JMPF R5 #003A + 0x780E0012, // 0013 JMPF R3 #0027 + 0x8C140303, // 0014 GETMET R5 R1 K3 + 0x541E00DF, // 0015 LDINT R7 224 + 0x88200104, // 0016 GETMBR R8 R0 K4 + 0x001C0E08, // 0017 ADD R7 R7 R8 + 0x58200005, // 0018 LDCONST R8 K5 + 0x7C140600, // 0019 CALL R5 3 + 0x8C140303, // 001A GETMET R5 R1 K3 + 0x881C0102, // 001B GETMBR R7 R0 K2 + 0x58200006, // 001C LDCONST R8 K6 + 0x7C140600, // 001D CALL R5 3 + 0x8C140303, // 001E GETMET R5 R1 K3 + 0x881C0107, // 001F GETMBR R7 R0 K7 + 0x58200006, // 0020 LDCONST R8 K6 + 0x7C140600, // 0021 CALL R5 3 + 0x8C140303, // 0022 GETMET R5 R1 K3 + 0x881C0100, // 0023 GETMBR R7 R0 K0 + 0x54220003, // 0024 LDINT R8 4 + 0x7C140600, // 0025 CALL R5 3 + 0x70020011, // 0026 JMP #0039 + 0x8C140303, // 0027 GETMET R5 R1 K3 + 0x541E00BF, // 0028 LDINT R7 192 + 0x88200104, // 0029 GETMBR R8 R0 K4 + 0x001C0E08, // 002A ADD R7 R7 R8 + 0x58200005, // 002B LDCONST R8 K5 + 0x7C140600, // 002C CALL R5 3 + 0x8C140303, // 002D GETMET R5 R1 K3 + 0x881C0102, // 002E GETMBR R7 R0 K2 + 0x58200006, // 002F LDCONST R8 K6 + 0x7C140600, // 0030 CALL R5 3 + 0x8C140303, // 0031 GETMET R5 R1 K3 + 0x881C0107, // 0032 GETMBR R7 R0 K7 + 0x58200006, // 0033 LDCONST R8 K6 + 0x7C140600, // 0034 CALL R5 3 + 0x8C140303, // 0035 GETMET R5 R1 K3 + 0x881C0100, // 0036 GETMBR R7 R0 K0 + 0x58200006, // 0037 LDCONST R8 K6 + 0x7C140600, // 0038 CALL R5 3 + 0x70020049, // 0039 JMP #0084 + 0x88140107, // 003A GETMBR R5 R0 K7 + 0x5419FFFE, // 003B LDINT R6 -1 + 0x1C140A06, // 003C EQ R5 R5 R6 + 0x78160016, // 003D JMPF R5 #0055 + 0x780E000A, // 003E JMPF R3 #004A + 0x8C140303, // 003F GETMET R5 R1 K3 + 0x541E005F, // 0040 LDINT R7 96 + 0x88200104, // 0041 GETMBR R8 R0 K4 + 0x001C0E08, // 0042 ADD R7 R7 R8 + 0x58200005, // 0043 LDCONST R8 K5 + 0x7C140600, // 0044 CALL R5 3 + 0x8C140303, // 0045 GETMET R5 R1 K3 + 0x881C0100, // 0046 GETMBR R7 R0 K0 + 0x54220003, // 0047 LDINT R8 4 + 0x7C140600, // 0048 CALL R5 3 + 0x70020009, // 0049 JMP #0054 + 0x8C140303, // 004A GETMET R5 R1 K3 + 0x541E003F, // 004B LDINT R7 64 + 0x88200104, // 004C GETMBR R8 R0 K4 + 0x001C0E08, // 004D ADD R7 R7 R8 + 0x58200005, // 004E LDCONST R8 K5 + 0x7C140600, // 004F CALL R5 3 + 0x8C140303, // 0050 GETMET R5 R1 K3 + 0x881C0100, // 0051 GETMBR R7 R0 K0 + 0x58200006, // 0052 LDCONST R8 K6 + 0x7C140600, // 0053 CALL R5 3 + 0x7002002E, // 0054 JMP #0084 + 0x88140107, // 0055 GETMBR R5 R0 K7 + 0x4C180000, // 0056 LDNIL R6 + 0x20140A06, // 0057 NE R5 R5 R6 + 0x78160016, // 0058 JMPF R5 #0070 + 0x780E000A, // 0059 JMPF R3 #0065 + 0x8C140303, // 005A GETMET R5 R1 K3 + 0x541E009F, // 005B LDINT R7 160 + 0x88200104, // 005C GETMBR R8 R0 K4 + 0x001C0E08, // 005D ADD R7 R7 R8 + 0x58200005, // 005E LDCONST R8 K5 + 0x7C140600, // 005F CALL R5 3 + 0x8C140303, // 0060 GETMET R5 R1 K3 + 0x881C0100, // 0061 GETMBR R7 R0 K0 + 0x54220003, // 0062 LDINT R8 4 + 0x7C140600, // 0063 CALL R5 3 + 0x70020009, // 0064 JMP #006F + 0x8C140303, // 0065 GETMET R5 R1 K3 + 0x541E007F, // 0066 LDINT R7 128 + 0x88200104, // 0067 GETMBR R8 R0 K4 + 0x001C0E08, // 0068 ADD R7 R7 R8 + 0x58200005, // 0069 LDCONST R8 K5 + 0x7C140600, // 006A CALL R5 3 + 0x8C140303, // 006B GETMET R5 R1 K3 + 0x881C0100, // 006C GETMBR R7 R0 K0 + 0x58200006, // 006D LDCONST R8 K6 + 0x7C140600, // 006E CALL R5 3 + 0x70020013, // 006F JMP #0084 + 0x88140108, // 0070 GETMBR R5 R0 K8 + 0x4C180000, // 0071 LDNIL R6 + 0x20140A06, // 0072 NE R5 R5 R6 + 0x7816000A, // 0073 JMPF R5 #007F + 0x8C140303, // 0074 GETMET R5 R1 K3 + 0x541E001F, // 0075 LDINT R7 32 + 0x88200104, // 0076 GETMBR R8 R0 K4 + 0x001C0E08, // 0077 ADD R7 R7 R8 + 0x58200005, // 0078 LDCONST R8 K5 + 0x7C140600, // 0079 CALL R5 3 + 0x8C140303, // 007A GETMET R5 R1 K3 + 0x881C0108, // 007B GETMBR R7 R0 K8 + 0x58200005, // 007C LDCONST R8 K5 + 0x7C140600, // 007D CALL R5 3 + 0x70020004, // 007E JMP #0084 + 0x8C140303, // 007F GETMET R5 R1 K3 + 0x881C0104, // 0080 GETMBR R7 R0 K4 + 0x001E0207, // 0081 ADD R7 K1 R7 + 0x58200005, // 0082 LDCONST R8 K5 + 0x7C140600, // 0083 CALL R5 3 + 0x80000000, // 0084 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: encode_len +********************************************************************/ +be_local_closure(Matter_TLV_item_encode_len, /* 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[31]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(typ), + /* K3 */ be_nested_str_weak(BFALSE), + /* K4 */ be_nested_str_weak(BTRUE), + /* K5 */ be_nested_str_weak(val), + /* K6 */ be_nested_str_weak(I2), + /* K7 */ be_nested_str_weak(I4), + /* K8 */ be_nested_str_weak(I1), + /* K9 */ be_nested_str_weak(U2), + /* K10 */ be_nested_str_weak(U4), + /* K11 */ be_nested_str_weak(U1), + /* K12 */ be_nested_str_weak(B1), + /* K13 */ be_nested_str_weak(B8), + /* K14 */ be_nested_str_weak(B2), + /* K15 */ be_nested_str_weak(B4), + /* K16 */ be_nested_str_weak(UTF1), + /* K17 */ be_nested_str_weak(UTF8), + /* K18 */ be_nested_str_weak(UTF2), + /* K19 */ be_nested_str_weak(UTF4), + /* K20 */ be_nested_str_weak(_encode_tag_len), + /* K21 */ be_const_int(1), + /* K22 */ be_const_int(2), + /* K23 */ be_nested_str_weak(I8), + /* K24 */ be_nested_str_weak(U8), + /* K25 */ be_nested_str_weak(FLOAT), + /* K26 */ be_nested_str_weak(DOUBLE), + /* K27 */ be_nested_str_weak(value_error), + /* K28 */ be_nested_str_weak(Unsupported_X20type_X20TLV_X2EDOUBLE), + /* K29 */ be_nested_str_weak(NULL), + /* K30 */ be_nested_str_weak(unsupported_X20type_X20), + }), + be_str_weak(encode_len), + &be_const_str_solidified, + ( &(const binstruction[250]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x88100303, // 0003 GETMBR R4 R1 K3 + 0x1C0C0604, // 0004 EQ R3 R3 R4 + 0x740E0003, // 0005 JMPT R3 #000A + 0x880C0102, // 0006 GETMBR R3 R0 K2 + 0x88100304, // 0007 GETMBR R4 R1 K4 + 0x1C0C0604, // 0008 EQ R3 R3 R4 + 0x780E0008, // 0009 JMPF R3 #0013 + 0x600C0017, // 000A GETGBL R3 G23 + 0x88100105, // 000B GETMBR R4 R0 K5 + 0x7C0C0200, // 000C CALL R3 1 + 0x780E0001, // 000D JMPF R3 #0010 + 0x880C0304, // 000E GETMBR R3 R1 K4 + 0x70020000, // 000F JMP #0011 + 0x880C0303, // 0010 GETMBR R3 R1 K3 + 0x90020403, // 0011 SETMBR R0 K2 R3 + 0x70020070, // 0012 JMP #0084 + 0x880C0102, // 0013 GETMBR R3 R0 K2 + 0x88100306, // 0014 GETMBR R4 R1 K6 + 0x280C0604, // 0015 GE R3 R3 R4 + 0x780E0018, // 0016 JMPF R3 #0030 + 0x880C0102, // 0017 GETMBR R3 R0 K2 + 0x88100307, // 0018 GETMBR R4 R1 K7 + 0x180C0604, // 0019 LE R3 R3 R4 + 0x780E0014, // 001A JMPF R3 #0030 + 0x600C0009, // 001B GETGBL R3 G9 + 0x88100105, // 001C GETMBR R4 R0 K5 + 0x7C0C0200, // 001D CALL R3 1 + 0x5412007E, // 001E LDINT R4 127 + 0x18100604, // 001F LE R4 R3 R4 + 0x78120005, // 0020 JMPF R4 #0027 + 0x5411FF7F, // 0021 LDINT R4 -128 + 0x28100604, // 0022 GE R4 R3 R4 + 0x78120002, // 0023 JMPF R4 #0027 + 0x88100308, // 0024 GETMBR R4 R1 K8 + 0x90020404, // 0025 SETMBR R0 K2 R4 + 0x70020007, // 0026 JMP #002F + 0x54127FFE, // 0027 LDINT R4 32767 + 0x18100604, // 0028 LE R4 R3 R4 + 0x78120004, // 0029 JMPF R4 #002F + 0x54117FFF, // 002A LDINT R4 -32768 + 0x28100604, // 002B GE R4 R3 R4 + 0x78120001, // 002C JMPF R4 #002F + 0x88100306, // 002D GETMBR R4 R1 K6 + 0x90020404, // 002E SETMBR R0 K2 R4 + 0x70020053, // 002F JMP #0084 + 0x880C0102, // 0030 GETMBR R3 R0 K2 + 0x88100309, // 0031 GETMBR R4 R1 K9 + 0x280C0604, // 0032 GE R3 R3 R4 + 0x780E0016, // 0033 JMPF R3 #004B + 0x880C0102, // 0034 GETMBR R3 R0 K2 + 0x8810030A, // 0035 GETMBR R4 R1 K10 + 0x180C0604, // 0036 LE R3 R3 R4 + 0x780E0012, // 0037 JMPF R3 #004B + 0x600C0009, // 0038 GETGBL R3 G9 + 0x88100105, // 0039 GETMBR R4 R0 K5 + 0x7C0C0200, // 003A CALL R3 1 + 0x541200FE, // 003B LDINT R4 255 + 0x18100604, // 003C LE R4 R3 R4 + 0x78120004, // 003D JMPF R4 #0043 + 0x28100701, // 003E GE R4 R3 K1 + 0x78120002, // 003F JMPF R4 #0043 + 0x8810030B, // 0040 GETMBR R4 R1 K11 + 0x90020404, // 0041 SETMBR R0 K2 R4 + 0x70020006, // 0042 JMP #004A + 0x5412FFFE, // 0043 LDINT R4 65535 + 0x18100604, // 0044 LE R4 R3 R4 + 0x78120003, // 0045 JMPF R4 #004A + 0x28100701, // 0046 GE R4 R3 K1 + 0x78120001, // 0047 JMPF R4 #004A + 0x88100309, // 0048 GETMBR R4 R1 K9 + 0x90020404, // 0049 SETMBR R0 K2 R4 + 0x70020038, // 004A JMP #0084 + 0x880C0102, // 004B GETMBR R3 R0 K2 + 0x8810030C, // 004C GETMBR R4 R1 K12 + 0x280C0604, // 004D GE R3 R3 R4 + 0x780E0018, // 004E JMPF R3 #0068 + 0x880C0102, // 004F GETMBR R3 R0 K2 + 0x8810030D, // 0050 GETMBR R4 R1 K13 + 0x180C0604, // 0051 LE R3 R3 R4 + 0x780E0014, // 0052 JMPF R3 #0068 + 0x600C000C, // 0053 GETGBL R3 G12 + 0x88100105, // 0054 GETMBR R4 R0 K5 + 0x7C0C0200, // 0055 CALL R3 1 + 0x541200FE, // 0056 LDINT R4 255 + 0x180C0604, // 0057 LE R3 R3 R4 + 0x780E0002, // 0058 JMPF R3 #005C + 0x880C030C, // 0059 GETMBR R3 R1 K12 + 0x90020403, // 005A SETMBR R0 K2 R3 + 0x7002000A, // 005B JMP #0067 + 0x600C000C, // 005C GETGBL R3 G12 + 0x88100105, // 005D GETMBR R4 R0 K5 + 0x7C0C0200, // 005E CALL R3 1 + 0x5412FFFE, // 005F LDINT R4 65535 + 0x180C0604, // 0060 LE R3 R3 R4 + 0x780E0002, // 0061 JMPF R3 #0065 + 0x880C030E, // 0062 GETMBR R3 R1 K14 + 0x90020403, // 0063 SETMBR R0 K2 R3 + 0x70020001, // 0064 JMP #0067 + 0x880C030F, // 0065 GETMBR R3 R1 K15 + 0x90020403, // 0066 SETMBR R0 K2 R3 + 0x7002001B, // 0067 JMP #0084 + 0x880C0102, // 0068 GETMBR R3 R0 K2 + 0x88100310, // 0069 GETMBR R4 R1 K16 + 0x280C0604, // 006A GE R3 R3 R4 + 0x780E0017, // 006B JMPF R3 #0084 + 0x880C0102, // 006C GETMBR R3 R0 K2 + 0x88100311, // 006D GETMBR R4 R1 K17 + 0x180C0604, // 006E LE R3 R3 R4 + 0x780E0013, // 006F JMPF R3 #0084 + 0x600C000C, // 0070 GETGBL R3 G12 + 0x88100105, // 0071 GETMBR R4 R0 K5 + 0x7C0C0200, // 0072 CALL R3 1 + 0x541200FE, // 0073 LDINT R4 255 + 0x180C0604, // 0074 LE R3 R3 R4 + 0x780E0002, // 0075 JMPF R3 #0079 + 0x880C0310, // 0076 GETMBR R3 R1 K16 + 0x90020403, // 0077 SETMBR R0 K2 R3 + 0x7002000A, // 0078 JMP #0084 + 0x600C000C, // 0079 GETGBL R3 G12 + 0x88100105, // 007A GETMBR R4 R0 K5 + 0x7C0C0200, // 007B CALL R3 1 + 0x5412FFFE, // 007C LDINT R4 65535 + 0x180C0604, // 007D LE R3 R3 R4 + 0x780E0002, // 007E JMPF R3 #0082 + 0x880C0312, // 007F GETMBR R3 R1 K18 + 0x90020403, // 0080 SETMBR R0 K2 R3 + 0x70020001, // 0081 JMP #0084 + 0x880C0313, // 0082 GETMBR R3 R1 K19 + 0x90020403, // 0083 SETMBR R0 K2 R3 + 0x8C0C0114, // 0084 GETMET R3 R0 K20 + 0x7C0C0200, // 0085 CALL R3 1 + 0x00080403, // 0086 ADD R2 R2 R3 + 0x880C0102, // 0087 GETMBR R3 R0 K2 + 0x88100308, // 0088 GETMBR R4 R1 K8 + 0x1C0C0604, // 0089 EQ R3 R3 R4 + 0x740E0003, // 008A JMPT R3 #008F + 0x880C0102, // 008B GETMBR R3 R0 K2 + 0x8810030B, // 008C GETMBR R4 R1 K11 + 0x1C0C0604, // 008D EQ R3 R3 R4 + 0x780E0001, // 008E JMPF R3 #0091 + 0x00080515, // 008F ADD R2 R2 K21 + 0x70020067, // 0090 JMP #00F9 + 0x880C0102, // 0091 GETMBR R3 R0 K2 + 0x88100306, // 0092 GETMBR R4 R1 K6 + 0x1C0C0604, // 0093 EQ R3 R3 R4 + 0x740E0003, // 0094 JMPT R3 #0099 + 0x880C0102, // 0095 GETMBR R3 R0 K2 + 0x88100309, // 0096 GETMBR R4 R1 K9 + 0x1C0C0604, // 0097 EQ R3 R3 R4 + 0x780E0001, // 0098 JMPF R3 #009B + 0x00080516, // 0099 ADD R2 R2 K22 + 0x7002005D, // 009A JMP #00F9 + 0x880C0102, // 009B GETMBR R3 R0 K2 + 0x88100307, // 009C GETMBR R4 R1 K7 + 0x1C0C0604, // 009D EQ R3 R3 R4 + 0x740E0003, // 009E JMPT R3 #00A3 + 0x880C0102, // 009F GETMBR R3 R0 K2 + 0x8810030A, // 00A0 GETMBR R4 R1 K10 + 0x1C0C0604, // 00A1 EQ R3 R3 R4 + 0x780E0002, // 00A2 JMPF R3 #00A6 + 0x540E0003, // 00A3 LDINT R3 4 + 0x00080403, // 00A4 ADD R2 R2 R3 + 0x70020052, // 00A5 JMP #00F9 + 0x880C0102, // 00A6 GETMBR R3 R0 K2 + 0x88100317, // 00A7 GETMBR R4 R1 K23 + 0x1C0C0604, // 00A8 EQ R3 R3 R4 + 0x740E0003, // 00A9 JMPT R3 #00AE + 0x880C0102, // 00AA GETMBR R3 R0 K2 + 0x88100318, // 00AB GETMBR R4 R1 K24 + 0x1C0C0604, // 00AC EQ R3 R3 R4 + 0x780E0002, // 00AD JMPF R3 #00B1 + 0x540E0007, // 00AE LDINT R3 8 + 0x00080403, // 00AF ADD R2 R2 R3 + 0x70020047, // 00B0 JMP #00F9 + 0x880C0102, // 00B1 GETMBR R3 R0 K2 + 0x88100303, // 00B2 GETMBR R4 R1 K3 + 0x1C0C0604, // 00B3 EQ R3 R3 R4 + 0x740E0003, // 00B4 JMPT R3 #00B9 + 0x880C0102, // 00B5 GETMBR R3 R0 K2 + 0x88100304, // 00B6 GETMBR R4 R1 K4 + 0x1C0C0604, // 00B7 EQ R3 R3 R4 + 0x780E0000, // 00B8 JMPF R3 #00BA + 0x7002003E, // 00B9 JMP #00F9 + 0x880C0102, // 00BA GETMBR R3 R0 K2 + 0x88100319, // 00BB GETMBR R4 R1 K25 + 0x1C0C0604, // 00BC EQ R3 R3 R4 + 0x780E0002, // 00BD JMPF R3 #00C1 + 0x540E0003, // 00BE LDINT R3 4 + 0x00080403, // 00BF ADD R2 R2 R3 + 0x70020037, // 00C0 JMP #00F9 + 0x880C0102, // 00C1 GETMBR R3 R0 K2 + 0x8810031A, // 00C2 GETMBR R4 R1 K26 + 0x1C0C0604, // 00C3 EQ R3 R3 R4 + 0x780E0001, // 00C4 JMPF R3 #00C7 + 0xB006371C, // 00C5 RAISE 1 K27 K28 + 0x70020031, // 00C6 JMP #00F9 + 0x880C0102, // 00C7 GETMBR R3 R0 K2 + 0x88100310, // 00C8 GETMBR R4 R1 K16 + 0x1C0C0604, // 00C9 EQ R3 R3 R4 + 0x780E0005, // 00CA JMPF R3 #00D1 + 0x600C000C, // 00CB GETGBL R3 G12 + 0x88100105, // 00CC GETMBR R4 R0 K5 + 0x7C0C0200, // 00CD CALL R3 1 + 0x000E2A03, // 00CE ADD R3 K21 R3 + 0x00080403, // 00CF ADD R2 R2 R3 + 0x70020027, // 00D0 JMP #00F9 + 0x880C0102, // 00D1 GETMBR R3 R0 K2 + 0x88100312, // 00D2 GETMBR R4 R1 K18 + 0x1C0C0604, // 00D3 EQ R3 R3 R4 + 0x780E0005, // 00D4 JMPF R3 #00DB + 0x600C000C, // 00D5 GETGBL R3 G12 + 0x88100105, // 00D6 GETMBR R4 R0 K5 + 0x7C0C0200, // 00D7 CALL R3 1 + 0x000E2C03, // 00D8 ADD R3 K22 R3 + 0x00080403, // 00D9 ADD R2 R2 R3 + 0x7002001D, // 00DA JMP #00F9 + 0x880C0102, // 00DB GETMBR R3 R0 K2 + 0x8810030C, // 00DC GETMBR R4 R1 K12 + 0x1C0C0604, // 00DD EQ R3 R3 R4 + 0x780E0005, // 00DE JMPF R3 #00E5 + 0x600C000C, // 00DF GETGBL R3 G12 + 0x88100105, // 00E0 GETMBR R4 R0 K5 + 0x7C0C0200, // 00E1 CALL R3 1 + 0x000E2A03, // 00E2 ADD R3 K21 R3 + 0x00080403, // 00E3 ADD R2 R2 R3 + 0x70020013, // 00E4 JMP #00F9 + 0x880C0102, // 00E5 GETMBR R3 R0 K2 + 0x8810030E, // 00E6 GETMBR R4 R1 K14 + 0x1C0C0604, // 00E7 EQ R3 R3 R4 + 0x780E0005, // 00E8 JMPF R3 #00EF + 0x600C000C, // 00E9 GETGBL R3 G12 + 0x88100105, // 00EA GETMBR R4 R0 K5 + 0x7C0C0200, // 00EB CALL R3 1 + 0x000E2C03, // 00EC ADD R3 K22 R3 + 0x00080403, // 00ED ADD R2 R2 R3 + 0x70020009, // 00EE JMP #00F9 + 0x880C0102, // 00EF GETMBR R3 R0 K2 + 0x8810031D, // 00F0 GETMBR R4 R1 K29 + 0x1C0C0604, // 00F1 EQ R3 R3 R4 + 0x780E0000, // 00F2 JMPF R3 #00F4 + 0x70020004, // 00F3 JMP #00F9 + 0x600C0008, // 00F4 GETGBL R3 G8 + 0x88100102, // 00F5 GETMBR R4 R0 K2 + 0x7C0C0200, // 00F6 CALL R3 1 + 0x000E3C03, // 00F7 ADD R3 K30 R3 + 0xB0063603, // 00F8 RAISE 1 K27 R3 + 0x80040400, // 00F9 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_contextspecific +********************************************************************/ +be_local_closure(Matter_TLV_item_set_contextspecific, /* name */ + be_nested_proto( + 4, /* 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(set_fulltag), + /* K1 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(set_contextspecific), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x7C080200, // 0001 CALL R2 1 + 0x60080009, // 0002 GETGBL R2 G9 + 0x5C0C0200, // 0003 MOVE R3 R1 + 0x7C080200, // 0004 CALL R2 1 + 0x90020202, // 0005 SETMBR R0 K1 R2 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_fulltag +********************************************************************/ +be_local_closure(Matter_TLV_item_set_fulltag, /* name */ + be_nested_proto( + 6, /* 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(tag_vendor), + /* K1 */ be_nested_str_weak(tag_profile), + /* K2 */ be_nested_str_weak(tag_number), + /* K3 */ be_nested_str_weak(tag_sub), + }), + be_str_weak(set_fulltag), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x60100009, // 0000 GETGBL R4 G9 + 0x5C140200, // 0001 MOVE R5 R1 + 0x7C100200, // 0002 CALL R4 1 + 0x90020004, // 0003 SETMBR R0 K0 R4 + 0x60100009, // 0004 GETGBL R4 G9 + 0x5C140400, // 0005 MOVE R5 R2 + 0x7C100200, // 0006 CALL R4 1 + 0x90020204, // 0007 SETMBR R0 K1 R4 + 0x60100009, // 0008 GETGBL R4 G9 + 0x5C140600, // 0009 MOVE R5 R3 + 0x7C100200, // 000A CALL R4 1 + 0x90020404, // 000B SETMBR R0 K2 R4 + 0x4C100000, // 000C LDNIL R4 + 0x90020604, // 000D SETMBR R0 K3 R4 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_item_tostring, /* 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[35]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(tag_profile), + /* K3 */ be_nested_str_weak(Matter_X3A_X3A), + /* K4 */ be_nested_str_weak(tag_number), + /* K5 */ be_nested_str_weak(format), + /* K6 */ be_nested_str_weak(0x_X2508X_X20), + /* K7 */ be_nested_str_weak(tag_vendor), + /* K8 */ be_nested_str_weak(0x_X2504X_X3A_X3A), + /* K9 */ be_nested_str_weak(0x_X2504X_X3A), + /* K10 */ be_nested_str_weak(tag_sub), + /* K11 */ be_nested_str_weak(_X25i_X20), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_str_weak(_X3D_X20), + /* K14 */ be_nested_str_weak(val), + /* K15 */ be_nested_str_weak(int), + /* K16 */ be_nested_str_weak(_X25i), + /* K17 */ be_nested_str_weak(typ), + /* K18 */ be_nested_str_weak(TLV), + /* K19 */ be_nested_str_weak(U1), + /* K20 */ be_nested_str_weak(U8), + /* K21 */ be_nested_str_weak(U), + /* K22 */ be_nested_str_weak(bool), + /* K23 */ be_nested_str_weak(true), + /* K24 */ be_nested_str_weak(false), + /* K25 */ be_nested_str_weak(null), + /* K26 */ be_nested_str_weak(real), + /* K27 */ be_nested_str_weak(_X25g), + /* K28 */ be_nested_str_weak(_X22_X25s_X22), + /* K29 */ be_nested_str_weak(int64), + /* K30 */ be_nested_str_weak(tostring), + /* K31 */ be_nested_str_weak(instance), + /* K32 */ be_nested_str_weak(_X25s), + /* K33 */ be_nested_str_weak(tohex), + /* K34 */ be_nested_str_weak(_X20), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[165]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0xA8020099, // 0002 EXBLK 0 #009D + 0x880C0102, // 0003 GETMBR R3 R0 K2 + 0x5411FFFE, // 0004 LDINT R4 -1 + 0x1C0C0604, // 0005 EQ R3 R3 R4 + 0x780E000A, // 0006 JMPF R3 #0012 + 0x00080503, // 0007 ADD R2 R2 K3 + 0x880C0104, // 0008 GETMBR R3 R0 K4 + 0x4C100000, // 0009 LDNIL R4 + 0x200C0604, // 000A NE R3 R3 R4 + 0x780E0004, // 000B JMPF R3 #0011 + 0x8C0C0305, // 000C GETMET R3 R1 K5 + 0x58140006, // 000D LDCONST R5 K6 + 0x88180104, // 000E GETMBR R6 R0 K4 + 0x7C0C0600, // 000F CALL R3 3 + 0x00080403, // 0010 ADD R2 R2 R3 + 0x70020023, // 0011 JMP #0036 + 0x880C0107, // 0012 GETMBR R3 R0 K7 + 0x4C100000, // 0013 LDNIL R4 + 0x200C0604, // 0014 NE R3 R3 R4 + 0x780E0004, // 0015 JMPF R3 #001B + 0x8C0C0305, // 0016 GETMET R3 R1 K5 + 0x58140008, // 0017 LDCONST R5 K8 + 0x88180107, // 0018 GETMBR R6 R0 K7 + 0x7C0C0600, // 0019 CALL R3 3 + 0x00080403, // 001A ADD R2 R2 R3 + 0x880C0102, // 001B GETMBR R3 R0 K2 + 0x4C100000, // 001C LDNIL R4 + 0x200C0604, // 001D NE R3 R3 R4 + 0x780E0004, // 001E JMPF R3 #0024 + 0x8C0C0305, // 001F GETMET R3 R1 K5 + 0x58140009, // 0020 LDCONST R5 K9 + 0x88180102, // 0021 GETMBR R6 R0 K2 + 0x7C0C0600, // 0022 CALL R3 3 + 0x00080403, // 0023 ADD R2 R2 R3 + 0x880C0104, // 0024 GETMBR R3 R0 K4 + 0x4C100000, // 0025 LDNIL R4 + 0x200C0604, // 0026 NE R3 R3 R4 + 0x780E0004, // 0027 JMPF R3 #002D + 0x8C0C0305, // 0028 GETMET R3 R1 K5 + 0x58140006, // 0029 LDCONST R5 K6 + 0x88180104, // 002A GETMBR R6 R0 K4 + 0x7C0C0600, // 002B CALL R3 3 + 0x00080403, // 002C ADD R2 R2 R3 + 0x880C010A, // 002D GETMBR R3 R0 K10 + 0x4C100000, // 002E LDNIL R4 + 0x200C0604, // 002F NE R3 R3 R4 + 0x780E0004, // 0030 JMPF R3 #0036 + 0x8C0C0305, // 0031 GETMET R3 R1 K5 + 0x5814000B, // 0032 LDCONST R5 K11 + 0x8818010A, // 0033 GETMBR R6 R0 K10 + 0x7C0C0600, // 0034 CALL R3 3 + 0x00080403, // 0035 ADD R2 R2 R3 + 0x600C000C, // 0036 GETGBL R3 G12 + 0x5C100400, // 0037 MOVE R4 R2 + 0x7C0C0200, // 0038 CALL R3 1 + 0x240C070C, // 0039 GT R3 R3 K12 + 0x780E0000, // 003A JMPF R3 #003C + 0x0008050D, // 003B ADD R2 R2 K13 + 0x600C0004, // 003C GETGBL R3 G4 + 0x8810010E, // 003D GETMBR R4 R0 K14 + 0x7C0C0200, // 003E CALL R3 1 + 0x1C0C070F, // 003F EQ R3 R3 K15 + 0x780E0010, // 0040 JMPF R3 #0052 + 0x8C0C0305, // 0041 GETMET R3 R1 K5 + 0x58140010, // 0042 LDCONST R5 K16 + 0x8818010E, // 0043 GETMBR R6 R0 K14 + 0x7C0C0600, // 0044 CALL R3 3 + 0x00080403, // 0045 ADD R2 R2 R3 + 0x880C0111, // 0046 GETMBR R3 R0 K17 + 0x88100112, // 0047 GETMBR R4 R0 K18 + 0x88100913, // 0048 GETMBR R4 R4 K19 + 0x280C0604, // 0049 GE R3 R3 R4 + 0x780E0005, // 004A JMPF R3 #0051 + 0x880C0111, // 004B GETMBR R3 R0 K17 + 0x88100112, // 004C GETMBR R4 R0 K18 + 0x88100914, // 004D GETMBR R4 R4 K20 + 0x180C0604, // 004E LE R3 R3 R4 + 0x780E0000, // 004F JMPF R3 #0051 + 0x00080515, // 0050 ADD R2 R2 K21 + 0x70020048, // 0051 JMP #009B + 0x600C0004, // 0052 GETGBL R3 G4 + 0x8810010E, // 0053 GETMBR R4 R0 K14 + 0x7C0C0200, // 0054 CALL R3 1 + 0x1C0C0716, // 0055 EQ R3 R3 K22 + 0x780E0006, // 0056 JMPF R3 #005E + 0x880C010E, // 0057 GETMBR R3 R0 K14 + 0x780E0001, // 0058 JMPF R3 #005B + 0x580C0017, // 0059 LDCONST R3 K23 + 0x70020000, // 005A JMP #005C + 0x580C0018, // 005B LDCONST R3 K24 + 0x00080403, // 005C ADD R2 R2 R3 + 0x7002003C, // 005D JMP #009B + 0x880C010E, // 005E GETMBR R3 R0 K14 + 0x4C100000, // 005F LDNIL R4 + 0x1C0C0604, // 0060 EQ R3 R3 R4 + 0x780E0001, // 0061 JMPF R3 #0064 + 0x00080519, // 0062 ADD R2 R2 K25 + 0x70020036, // 0063 JMP #009B + 0x600C0004, // 0064 GETGBL R3 G4 + 0x8810010E, // 0065 GETMBR R4 R0 K14 + 0x7C0C0200, // 0066 CALL R3 1 + 0x1C0C071A, // 0067 EQ R3 R3 K26 + 0x780E0005, // 0068 JMPF R3 #006F + 0x8C0C0305, // 0069 GETMET R3 R1 K5 + 0x5814001B, // 006A LDCONST R5 K27 + 0x8818010E, // 006B GETMBR R6 R0 K14 + 0x7C0C0600, // 006C CALL R3 3 + 0x00080403, // 006D ADD R2 R2 R3 + 0x7002002B, // 006E JMP #009B + 0x600C0004, // 006F GETGBL R3 G4 + 0x8810010E, // 0070 GETMBR R4 R0 K14 + 0x7C0C0200, // 0071 CALL R3 1 + 0x1C0C0700, // 0072 EQ R3 R3 K0 + 0x780E0005, // 0073 JMPF R3 #007A + 0x8C0C0305, // 0074 GETMET R3 R1 K5 + 0x5814001C, // 0075 LDCONST R5 K28 + 0x8818010E, // 0076 GETMBR R6 R0 K14 + 0x7C0C0600, // 0077 CALL R3 3 + 0x00080403, // 0078 ADD R2 R2 R3 + 0x70020020, // 0079 JMP #009B + 0x600C000F, // 007A GETGBL R3 G15 + 0x8810010E, // 007B GETMBR R4 R0 K14 + 0xB8163A00, // 007C GETNGBL R5 K29 + 0x7C0C0400, // 007D CALL R3 2 + 0x780E000F, // 007E JMPF R3 #008F + 0x880C010E, // 007F GETMBR R3 R0 K14 + 0x8C0C071E, // 0080 GETMET R3 R3 K30 + 0x7C0C0200, // 0081 CALL R3 1 + 0x00080403, // 0082 ADD R2 R2 R3 + 0x880C0111, // 0083 GETMBR R3 R0 K17 + 0x88100112, // 0084 GETMBR R4 R0 K18 + 0x88100913, // 0085 GETMBR R4 R4 K19 + 0x280C0604, // 0086 GE R3 R3 R4 + 0x780E0005, // 0087 JMPF R3 #008E + 0x880C0111, // 0088 GETMBR R3 R0 K17 + 0x88100112, // 0089 GETMBR R4 R0 K18 + 0x88100914, // 008A GETMBR R4 R4 K20 + 0x180C0604, // 008B LE R3 R3 R4 + 0x780E0000, // 008C JMPF R3 #008E + 0x00080515, // 008D ADD R2 R2 K21 + 0x7002000B, // 008E JMP #009B + 0x600C0004, // 008F GETGBL R3 G4 + 0x8810010E, // 0090 GETMBR R4 R0 K14 + 0x7C0C0200, // 0091 CALL R3 1 + 0x1C0C071F, // 0092 EQ R3 R3 K31 + 0x780E0006, // 0093 JMPF R3 #009B + 0x8C0C0305, // 0094 GETMET R3 R1 K5 + 0x58140020, // 0095 LDCONST R5 K32 + 0x8818010E, // 0096 GETMBR R6 R0 K14 + 0x8C180D21, // 0097 GETMET R6 R6 K33 + 0x7C180200, // 0098 CALL R6 1 + 0x7C0C0600, // 0099 CALL R3 3 + 0x00080403, // 009A ADD R2 R2 R3 + 0xA8040001, // 009B EXBLK 1 1 + 0x70020006, // 009C JMP #00A4 + 0xAC0C0002, // 009D CATCH R3 0 2 + 0x70020003, // 009E JMP #00A3 + 0x00140722, // 009F ADD R5 R3 K34 + 0x00140A04, // 00A0 ADD R5 R5 R4 + 0x80040A00, // 00A1 RET 1 R5 + 0x70020000, // 00A2 JMP #00A4 + 0xB0080000, // 00A3 RAISE 2 R0 R0 + 0x80040400, // 00A4 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_TLV_item_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(parent), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tlv2raw +********************************************************************/ +be_local_closure(Matter_TLV_item_tlv2raw, /* name */ be_nested_proto( 9, /* nstack */ 2, /* argc */ @@ -93,7 +1088,7 @@ be_local_closure(Matter_TLV_item_encode, /* name */ /* K39 */ be_nested_str_weak(NULL), /* K40 */ be_nested_str_weak(unsupported_X20type_X20), }), - be_str_weak(encode), + be_str_weak(tlv2raw), &be_const_str_solidified, ( &(const binstruction[361]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 @@ -464,520 +1459,147 @@ be_local_closure(Matter_TLV_item_encode, /* name */ /******************************************************************** -** Solidified function: create_TLV +** Solidified function: _encode_tag_len ********************************************************************/ -be_local_closure(Matter_TLV_item_create_TLV, /* name */ +be_local_closure(Matter_TLV_item__encode_tag_len, /* name */ be_nested_proto( - 4, /* nstack */ - 2, /* argc */ + 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(tag_number), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(tag_vendor), + /* K3 */ be_nested_str_weak(tag_profile), + /* K4 */ be_const_int(3), + /* K5 */ be_nested_str_weak(tag_sub), + /* K6 */ be_const_int(2), + /* K7 */ be_const_int(1), + }), + be_str_weak(_encode_tag_len), + &be_const_str_solidified, + ( &(const binstruction[54]) { /* 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 + 0x540AFFFF, // 0007 LDINT R2 65536 + 0x28080202, // 0008 GE R2 R1 R2 + 0x740A0002, // 0009 JMPT R2 #000D + 0x14080301, // 000A LT R2 R1 K1 + 0x740A0000, // 000B JMPT R2 #000D + 0x50080001, // 000C LDBOOL R2 0 1 + 0x50080200, // 000D LDBOOL R2 1 0 + 0x580C0001, // 000E LDCONST R3 K1 + 0x88100102, // 000F GETMBR R4 R0 K2 + 0x4C140000, // 0010 LDNIL R5 + 0x20100805, // 0011 NE R4 R4 R5 + 0x78120006, // 0012 JMPF R4 #001A + 0x780A0002, // 0013 JMPF R2 #0017 + 0x54120008, // 0014 LDINT R4 9 + 0x80040800, // 0015 RET 1 R4 + 0x70020001, // 0016 JMP #0019 + 0x54120006, // 0017 LDINT R4 7 + 0x80040800, // 0018 RET 1 R4 + 0x7002001A, // 0019 JMP #0035 + 0x88100103, // 001A GETMBR R4 R0 K3 + 0x5415FFFE, // 001B LDINT R5 -1 + 0x1C100805, // 001C EQ R4 R4 R5 + 0x78120005, // 001D JMPF R4 #0024 + 0x780A0002, // 001E JMPF R2 #0022 + 0x54120004, // 001F LDINT R4 5 + 0x80040800, // 0020 RET 1 R4 + 0x70020000, // 0021 JMP #0023 + 0x80060800, // 0022 RET 1 K4 + 0x70020010, // 0023 JMP #0035 + 0x88100103, // 0024 GETMBR R4 R0 K3 + 0x4C140000, // 0025 LDNIL R5 + 0x20100805, // 0026 NE R4 R4 R5 + 0x78120005, // 0027 JMPF R4 #002E + 0x780A0002, // 0028 JMPF R2 #002C + 0x54120004, // 0029 LDINT R4 5 + 0x80040800, // 002A RET 1 R4 + 0x70020000, // 002B JMP #002D + 0x80060800, // 002C RET 1 K4 + 0x70020006, // 002D JMP #0035 + 0x88100105, // 002E GETMBR R4 R0 K5 + 0x4C140000, // 002F LDNIL R5 + 0x20100805, // 0030 NE R4 R4 R5 + 0x78120001, // 0031 JMPF R4 #0034 + 0x80060C00, // 0032 RET 1 K6 + 0x70020000, // 0033 JMP #0035 + 0x80060E00, // 0034 RET 1 K7 + 0x80000000, // 0035 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: sort +********************************************************************/ +be_local_closure(Matter_TLV_item_sort, /* 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[ 3]) { /* constants */ + ( &(const bvalue[ 5]) { /* constants */ /* K0 */ be_const_class(be_class_Matter_TLV_item), - /* K1 */ be_nested_str_weak(typ), - /* K2 */ be_nested_str_weak(val), + /* K1 */ be_const_int(1), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(_cmp_gt), + /* K4 */ be_nested_str_weak(stop_iteration), }), - be_str_weak(create_TLV), + be_str_weak(sort), &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x200C0203, // 0002 NE R3 R1 R3 - 0x780E0004, // 0003 JMPF R3 #0009 - 0x5C0C0400, // 0004 MOVE R3 R2 - 0x7C0C0000, // 0005 CALL R3 0 - 0x900E0200, // 0006 SETMBR R3 K1 R0 - 0x900E0401, // 0007 SETMBR R3 K2 R1 - 0x80040600, // 0008 RET 1 R3 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _encode_tag -********************************************************************/ -be_local_closure(Matter_TLV_item__encode_tag, /* 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[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(tag_number), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(tag_vendor), - /* K3 */ be_nested_str_weak(add), - /* K4 */ be_nested_str_weak(typ), - /* K5 */ be_const_int(1), - /* K6 */ be_const_int(2), - /* K7 */ be_nested_str_weak(tag_profile), - /* K8 */ be_nested_str_weak(tag_sub), - }), - be_str_weak(_encode_tag), - &be_const_str_solidified, - ( &(const binstruction[133]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x20080403, // 0002 NE R2 R2 R3 - 0x780A0001, // 0003 JMPF R2 #0006 - 0x88080100, // 0004 GETMBR R2 R0 K0 - 0x70020000, // 0005 JMP #0007 - 0x58080001, // 0006 LDCONST R2 K1 - 0x540EFFFF, // 0007 LDINT R3 65536 - 0x280C0403, // 0008 GE R3 R2 R3 - 0x740E0002, // 0009 JMPT R3 #000D - 0x140C0501, // 000A LT R3 R2 K1 - 0x740E0000, // 000B JMPT R3 #000D - 0x500C0001, // 000C LDBOOL R3 0 1 - 0x500C0200, // 000D LDBOOL R3 1 0 - 0x58100001, // 000E LDCONST R4 K1 - 0x88140102, // 000F GETMBR R5 R0 K2 - 0x4C180000, // 0010 LDNIL R6 - 0x20140A06, // 0011 NE R5 R5 R6 - 0x78160026, // 0012 JMPF R5 #003A - 0x780E0012, // 0013 JMPF R3 #0027 - 0x8C140303, // 0014 GETMET R5 R1 K3 - 0x541E00DF, // 0015 LDINT R7 224 - 0x88200104, // 0016 GETMBR R8 R0 K4 - 0x001C0E08, // 0017 ADD R7 R7 R8 - 0x58200005, // 0018 LDCONST R8 K5 - 0x7C140600, // 0019 CALL R5 3 - 0x8C140303, // 001A GETMET R5 R1 K3 - 0x881C0102, // 001B GETMBR R7 R0 K2 - 0x58200006, // 001C LDCONST R8 K6 - 0x7C140600, // 001D CALL R5 3 - 0x8C140303, // 001E GETMET R5 R1 K3 - 0x881C0107, // 001F GETMBR R7 R0 K7 - 0x58200006, // 0020 LDCONST R8 K6 - 0x7C140600, // 0021 CALL R5 3 - 0x8C140303, // 0022 GETMET R5 R1 K3 - 0x881C0100, // 0023 GETMBR R7 R0 K0 - 0x54220003, // 0024 LDINT R8 4 - 0x7C140600, // 0025 CALL R5 3 - 0x70020011, // 0026 JMP #0039 - 0x8C140303, // 0027 GETMET R5 R1 K3 - 0x541E00BF, // 0028 LDINT R7 192 - 0x88200104, // 0029 GETMBR R8 R0 K4 - 0x001C0E08, // 002A ADD R7 R7 R8 - 0x58200005, // 002B LDCONST R8 K5 - 0x7C140600, // 002C CALL R5 3 - 0x8C140303, // 002D GETMET R5 R1 K3 - 0x881C0102, // 002E GETMBR R7 R0 K2 - 0x58200006, // 002F LDCONST R8 K6 - 0x7C140600, // 0030 CALL R5 3 - 0x8C140303, // 0031 GETMET R5 R1 K3 - 0x881C0107, // 0032 GETMBR R7 R0 K7 - 0x58200006, // 0033 LDCONST R8 K6 - 0x7C140600, // 0034 CALL R5 3 - 0x8C140303, // 0035 GETMET R5 R1 K3 - 0x881C0100, // 0036 GETMBR R7 R0 K0 - 0x58200006, // 0037 LDCONST R8 K6 - 0x7C140600, // 0038 CALL R5 3 - 0x70020049, // 0039 JMP #0084 - 0x88140107, // 003A GETMBR R5 R0 K7 - 0x5419FFFE, // 003B LDINT R6 -1 - 0x1C140A06, // 003C EQ R5 R5 R6 - 0x78160016, // 003D JMPF R5 #0055 - 0x780E000A, // 003E JMPF R3 #004A - 0x8C140303, // 003F GETMET R5 R1 K3 - 0x541E005F, // 0040 LDINT R7 96 - 0x88200104, // 0041 GETMBR R8 R0 K4 - 0x001C0E08, // 0042 ADD R7 R7 R8 - 0x58200005, // 0043 LDCONST R8 K5 - 0x7C140600, // 0044 CALL R5 3 - 0x8C140303, // 0045 GETMET R5 R1 K3 - 0x881C0100, // 0046 GETMBR R7 R0 K0 - 0x54220003, // 0047 LDINT R8 4 - 0x7C140600, // 0048 CALL R5 3 - 0x70020009, // 0049 JMP #0054 - 0x8C140303, // 004A GETMET R5 R1 K3 - 0x541E003F, // 004B LDINT R7 64 - 0x88200104, // 004C GETMBR R8 R0 K4 - 0x001C0E08, // 004D ADD R7 R7 R8 - 0x58200005, // 004E LDCONST R8 K5 - 0x7C140600, // 004F CALL R5 3 - 0x8C140303, // 0050 GETMET R5 R1 K3 - 0x881C0100, // 0051 GETMBR R7 R0 K0 - 0x58200006, // 0052 LDCONST R8 K6 - 0x7C140600, // 0053 CALL R5 3 - 0x7002002E, // 0054 JMP #0084 - 0x88140107, // 0055 GETMBR R5 R0 K7 - 0x4C180000, // 0056 LDNIL R6 - 0x20140A06, // 0057 NE R5 R5 R6 - 0x78160016, // 0058 JMPF R5 #0070 - 0x780E000A, // 0059 JMPF R3 #0065 - 0x8C140303, // 005A GETMET R5 R1 K3 - 0x541E009F, // 005B LDINT R7 160 - 0x88200104, // 005C GETMBR R8 R0 K4 - 0x001C0E08, // 005D ADD R7 R7 R8 - 0x58200005, // 005E LDCONST R8 K5 - 0x7C140600, // 005F CALL R5 3 - 0x8C140303, // 0060 GETMET R5 R1 K3 - 0x881C0100, // 0061 GETMBR R7 R0 K0 - 0x54220003, // 0062 LDINT R8 4 - 0x7C140600, // 0063 CALL R5 3 - 0x70020009, // 0064 JMP #006F - 0x8C140303, // 0065 GETMET R5 R1 K3 - 0x541E007F, // 0066 LDINT R7 128 - 0x88200104, // 0067 GETMBR R8 R0 K4 - 0x001C0E08, // 0068 ADD R7 R7 R8 - 0x58200005, // 0069 LDCONST R8 K5 - 0x7C140600, // 006A CALL R5 3 - 0x8C140303, // 006B GETMET R5 R1 K3 - 0x881C0100, // 006C GETMBR R7 R0 K0 - 0x58200006, // 006D LDCONST R8 K6 - 0x7C140600, // 006E CALL R5 3 - 0x70020013, // 006F JMP #0084 - 0x88140108, // 0070 GETMBR R5 R0 K8 - 0x4C180000, // 0071 LDNIL R6 - 0x20140A06, // 0072 NE R5 R5 R6 - 0x7816000A, // 0073 JMPF R5 #007F - 0x8C140303, // 0074 GETMET R5 R1 K3 - 0x541E001F, // 0075 LDINT R7 32 - 0x88200104, // 0076 GETMBR R8 R0 K4 - 0x001C0E08, // 0077 ADD R7 R7 R8 - 0x58200005, // 0078 LDCONST R8 K5 - 0x7C140600, // 0079 CALL R5 3 - 0x8C140303, // 007A GETMET R5 R1 K3 - 0x881C0108, // 007B GETMBR R7 R0 K8 - 0x58200005, // 007C LDCONST R8 K5 - 0x7C140600, // 007D CALL R5 3 - 0x70020004, // 007E JMP #0084 - 0x8C140303, // 007F GETMET R5 R1 K3 - 0x881C0104, // 0080 GETMBR R7 R0 K4 - 0x001E0207, // 0081 ADD R7 K1 R7 - 0x58200005, // 0082 LDCONST R8 K5 - 0x7C140600, // 0083 CALL R5 3 - 0x80000000, // 0084 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_parent -********************************************************************/ -be_local_closure(Matter_TLV_item_set_parent, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* 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(parent), - }), - be_str_weak(set_parent), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_fulltag -********************************************************************/ -be_local_closure(Matter_TLV_item_set_fulltag, /* name */ - be_nested_proto( - 6, /* 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(tag_vendor), - /* K1 */ be_nested_str_weak(tag_profile), - /* K2 */ be_nested_str_weak(tag_number), - /* K3 */ be_nested_str_weak(tag_sub), - }), - be_str_weak(set_fulltag), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x60100009, // 0000 GETGBL R4 G9 - 0x5C140200, // 0001 MOVE R5 R1 - 0x7C100200, // 0002 CALL R4 1 - 0x90020004, // 0003 SETMBR R0 K0 R4 - 0x60100009, // 0004 GETGBL R4 G9 - 0x5C140400, // 0005 MOVE R5 R2 - 0x7C100200, // 0006 CALL R4 1 - 0x90020204, // 0007 SETMBR R0 K1 R4 - 0x60100009, // 0008 GETGBL R4 G9 - 0x5C140600, // 0009 MOVE R5 R3 - 0x7C100200, // 000A CALL R4 1 - 0x90020404, // 000B SETMBR R0 K2 R4 - 0x4C100000, // 000C LDNIL R4 - 0x90020604, // 000D SETMBR R0 K3 R4 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: to_TLV -********************************************************************/ -be_local_closure(Matter_TLV_item_to_TLV, /* 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(to_TLV), - &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80040000, // 0000 RET 1 R0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: tostring -********************************************************************/ -be_local_closure(Matter_TLV_item_tostring, /* 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[35]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(), - /* K2 */ be_nested_str_weak(tag_profile), - /* K3 */ be_nested_str_weak(Matter_X3A_X3A), - /* K4 */ be_nested_str_weak(tag_number), - /* K5 */ be_nested_str_weak(format), - /* K6 */ be_nested_str_weak(0x_X2508X_X20), - /* K7 */ be_nested_str_weak(tag_vendor), - /* K8 */ be_nested_str_weak(0x_X2504X_X3A_X3A), - /* K9 */ be_nested_str_weak(0x_X2504X_X3A), - /* K10 */ be_nested_str_weak(tag_sub), - /* K11 */ be_nested_str_weak(_X25i_X20), - /* K12 */ be_const_int(0), - /* K13 */ be_nested_str_weak(_X3D_X20), - /* K14 */ be_nested_str_weak(val), - /* K15 */ be_nested_str_weak(int), - /* K16 */ be_nested_str_weak(_X25i), - /* K17 */ be_nested_str_weak(typ), - /* K18 */ be_nested_str_weak(TLV), - /* K19 */ be_nested_str_weak(U1), - /* K20 */ be_nested_str_weak(U8), - /* K21 */ be_nested_str_weak(U), - /* K22 */ be_nested_str_weak(bool), - /* K23 */ be_nested_str_weak(true), - /* K24 */ be_nested_str_weak(false), - /* K25 */ be_nested_str_weak(null), - /* K26 */ be_nested_str_weak(real), - /* K27 */ be_nested_str_weak(_X25g), - /* K28 */ be_nested_str_weak(_X22_X25s_X22), - /* K29 */ be_nested_str_weak(int64), - /* K30 */ be_nested_str_weak(tostring), - /* K31 */ be_nested_str_weak(instance), - /* K32 */ be_nested_str_weak(_X25s), - /* K33 */ be_nested_str_weak(tohex), - /* K34 */ be_nested_str_weak(_X20), - }), - be_str_weak(tostring), - &be_const_str_solidified, - ( &(const binstruction[165]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x58080001, // 0001 LDCONST R2 K1 - 0xA8020099, // 0002 EXBLK 0 #009D - 0x880C0102, // 0003 GETMBR R3 R0 K2 - 0x5411FFFE, // 0004 LDINT R4 -1 - 0x1C0C0604, // 0005 EQ R3 R3 R4 - 0x780E000A, // 0006 JMPF R3 #0012 - 0x00080503, // 0007 ADD R2 R2 K3 - 0x880C0104, // 0008 GETMBR R3 R0 K4 - 0x4C100000, // 0009 LDNIL R4 - 0x200C0604, // 000A NE R3 R3 R4 - 0x780E0004, // 000B JMPF R3 #0011 - 0x8C0C0305, // 000C GETMET R3 R1 K5 - 0x58140006, // 000D LDCONST R5 K6 - 0x88180104, // 000E GETMBR R6 R0 K4 - 0x7C0C0600, // 000F CALL R3 3 - 0x00080403, // 0010 ADD R2 R2 R3 - 0x70020023, // 0011 JMP #0036 - 0x880C0107, // 0012 GETMBR R3 R0 K7 - 0x4C100000, // 0013 LDNIL R4 - 0x200C0604, // 0014 NE R3 R3 R4 - 0x780E0004, // 0015 JMPF R3 #001B - 0x8C0C0305, // 0016 GETMET R3 R1 K5 - 0x58140008, // 0017 LDCONST R5 K8 - 0x88180107, // 0018 GETMBR R6 R0 K7 - 0x7C0C0600, // 0019 CALL R3 3 - 0x00080403, // 001A ADD R2 R2 R3 - 0x880C0102, // 001B GETMBR R3 R0 K2 - 0x4C100000, // 001C LDNIL R4 - 0x200C0604, // 001D NE R3 R3 R4 - 0x780E0004, // 001E JMPF R3 #0024 - 0x8C0C0305, // 001F GETMET R3 R1 K5 - 0x58140009, // 0020 LDCONST R5 K9 - 0x88180102, // 0021 GETMBR R6 R0 K2 - 0x7C0C0600, // 0022 CALL R3 3 - 0x00080403, // 0023 ADD R2 R2 R3 - 0x880C0104, // 0024 GETMBR R3 R0 K4 - 0x4C100000, // 0025 LDNIL R4 - 0x200C0604, // 0026 NE R3 R3 R4 - 0x780E0004, // 0027 JMPF R3 #002D - 0x8C0C0305, // 0028 GETMET R3 R1 K5 - 0x58140006, // 0029 LDCONST R5 K6 - 0x88180104, // 002A GETMBR R6 R0 K4 - 0x7C0C0600, // 002B CALL R3 3 - 0x00080403, // 002C ADD R2 R2 R3 - 0x880C010A, // 002D GETMBR R3 R0 K10 - 0x4C100000, // 002E LDNIL R4 - 0x200C0604, // 002F NE R3 R3 R4 - 0x780E0004, // 0030 JMPF R3 #0036 - 0x8C0C0305, // 0031 GETMET R3 R1 K5 - 0x5814000B, // 0032 LDCONST R5 K11 - 0x8818010A, // 0033 GETMBR R6 R0 K10 - 0x7C0C0600, // 0034 CALL R3 3 - 0x00080403, // 0035 ADD R2 R2 R3 - 0x600C000C, // 0036 GETGBL R3 G12 - 0x5C100400, // 0037 MOVE R4 R2 - 0x7C0C0200, // 0038 CALL R3 1 - 0x240C070C, // 0039 GT R3 R3 K12 - 0x780E0000, // 003A JMPF R3 #003C - 0x0008050D, // 003B ADD R2 R2 K13 - 0x600C0004, // 003C GETGBL R3 G4 - 0x8810010E, // 003D GETMBR R4 R0 K14 - 0x7C0C0200, // 003E CALL R3 1 - 0x1C0C070F, // 003F EQ R3 R3 K15 - 0x780E0010, // 0040 JMPF R3 #0052 - 0x8C0C0305, // 0041 GETMET R3 R1 K5 - 0x58140010, // 0042 LDCONST R5 K16 - 0x8818010E, // 0043 GETMBR R6 R0 K14 - 0x7C0C0600, // 0044 CALL R3 3 - 0x00080403, // 0045 ADD R2 R2 R3 - 0x880C0111, // 0046 GETMBR R3 R0 K17 - 0x88100112, // 0047 GETMBR R4 R0 K18 - 0x88100913, // 0048 GETMBR R4 R4 K19 - 0x280C0604, // 0049 GE R3 R3 R4 - 0x780E0005, // 004A JMPF R3 #0051 - 0x880C0111, // 004B GETMBR R3 R0 K17 - 0x88100112, // 004C GETMBR R4 R0 K18 - 0x88100914, // 004D GETMBR R4 R4 K20 - 0x180C0604, // 004E LE R3 R3 R4 - 0x780E0000, // 004F JMPF R3 #0051 - 0x00080515, // 0050 ADD R2 R2 K21 - 0x70020048, // 0051 JMP #009B - 0x600C0004, // 0052 GETGBL R3 G4 - 0x8810010E, // 0053 GETMBR R4 R0 K14 - 0x7C0C0200, // 0054 CALL R3 1 - 0x1C0C0716, // 0055 EQ R3 R3 K22 - 0x780E0006, // 0056 JMPF R3 #005E - 0x880C010E, // 0057 GETMBR R3 R0 K14 - 0x780E0001, // 0058 JMPF R3 #005B - 0x580C0017, // 0059 LDCONST R3 K23 - 0x70020000, // 005A JMP #005C - 0x580C0018, // 005B LDCONST R3 K24 - 0x00080403, // 005C ADD R2 R2 R3 - 0x7002003C, // 005D JMP #009B - 0x880C010E, // 005E GETMBR R3 R0 K14 - 0x4C100000, // 005F LDNIL R4 - 0x1C0C0604, // 0060 EQ R3 R3 R4 - 0x780E0001, // 0061 JMPF R3 #0064 - 0x00080519, // 0062 ADD R2 R2 K25 - 0x70020036, // 0063 JMP #009B - 0x600C0004, // 0064 GETGBL R3 G4 - 0x8810010E, // 0065 GETMBR R4 R0 K14 - 0x7C0C0200, // 0066 CALL R3 1 - 0x1C0C071A, // 0067 EQ R3 R3 K26 - 0x780E0005, // 0068 JMPF R3 #006F - 0x8C0C0305, // 0069 GETMET R3 R1 K5 - 0x5814001B, // 006A LDCONST R5 K27 - 0x8818010E, // 006B GETMBR R6 R0 K14 - 0x7C0C0600, // 006C CALL R3 3 - 0x00080403, // 006D ADD R2 R2 R3 - 0x7002002B, // 006E JMP #009B - 0x600C0004, // 006F GETGBL R3 G4 - 0x8810010E, // 0070 GETMBR R4 R0 K14 - 0x7C0C0200, // 0071 CALL R3 1 - 0x1C0C0700, // 0072 EQ R3 R3 K0 - 0x780E0005, // 0073 JMPF R3 #007A - 0x8C0C0305, // 0074 GETMET R3 R1 K5 - 0x5814001C, // 0075 LDCONST R5 K28 - 0x8818010E, // 0076 GETMBR R6 R0 K14 - 0x7C0C0600, // 0077 CALL R3 3 - 0x00080403, // 0078 ADD R2 R2 R3 - 0x70020020, // 0079 JMP #009B - 0x600C000F, // 007A GETGBL R3 G15 - 0x8810010E, // 007B GETMBR R4 R0 K14 - 0xB8163A00, // 007C GETNGBL R5 K29 - 0x7C0C0400, // 007D CALL R3 2 - 0x780E000F, // 007E JMPF R3 #008F - 0x880C010E, // 007F GETMBR R3 R0 K14 - 0x8C0C071E, // 0080 GETMET R3 R3 K30 - 0x7C0C0200, // 0081 CALL R3 1 - 0x00080403, // 0082 ADD R2 R2 R3 - 0x880C0111, // 0083 GETMBR R3 R0 K17 - 0x88100112, // 0084 GETMBR R4 R0 K18 - 0x88100913, // 0085 GETMBR R4 R4 K19 - 0x280C0604, // 0086 GE R3 R3 R4 - 0x780E0005, // 0087 JMPF R3 #008E - 0x880C0111, // 0088 GETMBR R3 R0 K17 - 0x88100112, // 0089 GETMBR R4 R0 K18 - 0x88100914, // 008A GETMBR R4 R4 K20 - 0x180C0604, // 008B LE R3 R3 R4 - 0x780E0000, // 008C JMPF R3 #008E - 0x00080515, // 008D ADD R2 R2 K21 - 0x7002000B, // 008E JMP #009B - 0x600C0004, // 008F GETGBL R3 G4 - 0x8810010E, // 0090 GETMBR R4 R0 K14 - 0x7C0C0200, // 0091 CALL R3 1 - 0x1C0C071F, // 0092 EQ R3 R3 K31 - 0x780E0006, // 0093 JMPF R3 #009B - 0x8C0C0305, // 0094 GETMET R3 R1 K5 - 0x58140020, // 0095 LDCONST R5 K32 - 0x8818010E, // 0096 GETMBR R6 R0 K14 - 0x8C180D21, // 0097 GETMET R6 R6 K33 - 0x7C180200, // 0098 CALL R6 1 - 0x7C0C0600, // 0099 CALL R3 3 - 0x00080403, // 009A ADD R2 R2 R3 - 0xA8040001, // 009B EXBLK 1 1 - 0x70020006, // 009C JMP #00A4 - 0xAC0C0002, // 009D CATCH R3 0 2 - 0x70020003, // 009E JMP #00A3 - 0x00140722, // 009F ADD R5 R3 K34 - 0x00140A04, // 00A0 ADD R5 R5 R4 - 0x80040A00, // 00A1 RET 1 R5 - 0x70020000, // 00A2 JMP #00A4 - 0xB0080000, // 00A3 RAISE 2 R0 R0 - 0x80040400, // 00A4 RET 1 R2 + ( &(const binstruction[33]) { /* 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 + 0xA8020013, // 0008 EXBLK 0 #001D + 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 + 0x781A000B, // 000E JMPF R6 #001B + 0x04180B01, // 000F SUB R6 R5 K1 + 0x94180006, // 0010 GETIDX R6 R0 R6 + 0x8C180D03, // 0011 GETMET R6 R6 K3 + 0x5C200800, // 0012 MOVE R8 R4 + 0x7C180400, // 0013 CALL R6 2 + 0x24180D02, // 0014 GT R6 R6 K2 + 0x781A0004, // 0015 JMPF R6 #001B + 0x04180B01, // 0016 SUB R6 R5 K1 + 0x94180006, // 0017 GETIDX R6 R0 R6 + 0x98000A06, // 0018 SETIDX R0 R5 R6 + 0x04140B01, // 0019 SUB R5 R5 K1 + 0x7001FFF1, // 001A JMP #000D + 0x98000A04, // 001B SETIDX R0 R5 R4 + 0x7001FFEB, // 001C JMP #0009 + 0x58080004, // 001D LDCONST R2 K4 + 0xAC080200, // 001E CATCH R2 1 0 + 0xB0080000, // 001F RAISE 2 R0 R0 + 0x80040000, // 0020 RET 1 R0 }) ) ); @@ -1139,251 +1761,23 @@ be_local_closure(Matter_TLV_item_parse, /* name */ /******************************************************************** -** Solidified function: init +** Solidified function: to_TLV ********************************************************************/ -be_local_closure(Matter_TLV_item_init, /* name */ +be_local_closure(Matter_TLV_item_to_TLV, /* name */ be_nested_proto( - 2, /* nstack */ - 2, /* 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(parent), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x80000000, // 0001 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _cmp_gt -********************************************************************/ -be_local_closure(Matter_TLV_item__cmp_gt, /* name */ - be_nested_proto( - 4, /* 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(tag_vendor), - /* K1 */ be_const_int(1), - /* K2 */ be_nested_str_weak(tag_profile), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(tag_number), - /* K5 */ be_nested_str_weak(tag_sub), - }), - be_str_weak(_cmp_gt), - &be_const_str_solidified, - ( &(const binstruction[72]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x4C0C0000, // 0001 LDNIL R3 - 0x20080403, // 0002 NE R2 R2 R3 - 0x780A0012, // 0003 JMPF R2 #0017 - 0x88080300, // 0004 GETMBR R2 R1 K0 - 0x4C0C0000, // 0005 LDNIL R3 - 0x1C080403, // 0006 EQ R2 R2 R3 - 0x780A0000, // 0007 JMPF R2 #0009 - 0x80060200, // 0008 RET 1 K1 - 0x88080100, // 0009 GETMBR R2 R0 K0 - 0x880C0300, // 000A GETMBR R3 R1 K0 - 0x24080403, // 000B GT R2 R2 R3 - 0x780A0000, // 000C JMPF R2 #000E - 0x80060200, // 000D RET 1 K1 - 0x88080100, // 000E GETMBR R2 R0 K0 - 0x880C0300, // 000F GETMBR R3 R1 K0 - 0x1C080403, // 0010 EQ R2 R2 R3 - 0x780A0004, // 0011 JMPF R2 #0017 - 0x88080102, // 0012 GETMBR R2 R0 K2 - 0x880C0302, // 0013 GETMBR R3 R1 K2 - 0x24080403, // 0014 GT R2 R2 R3 - 0x780A0000, // 0015 JMPF R2 #0017 - 0x80060200, // 0016 RET 1 K1 - 0x88080102, // 0017 GETMBR R2 R0 K2 - 0x540DFFFE, // 0018 LDINT R3 -1 - 0x1C080403, // 0019 EQ R2 R2 R3 - 0x780A0005, // 001A JMPF R2 #0021 - 0x88080302, // 001B GETMBR R2 R1 K2 - 0x4C0C0000, // 001C LDNIL R3 - 0x1C080403, // 001D EQ R2 R2 R3 - 0x780A0000, // 001E JMPF R2 #0020 - 0x80060200, // 001F RET 1 K1 - 0x70020008, // 0020 JMP #002A - 0x88080102, // 0021 GETMBR R2 R0 K2 - 0x4C0C0000, // 0022 LDNIL R3 - 0x1C080403, // 0023 EQ R2 R2 R3 - 0x780A0004, // 0024 JMPF R2 #002A - 0x88080302, // 0025 GETMBR R2 R1 K2 - 0x540DFFFE, // 0026 LDINT R3 -1 - 0x1C080403, // 0027 EQ R2 R2 R3 - 0x780A0000, // 0028 JMPF R2 #002A - 0x80060600, // 0029 RET 1 K3 - 0x88080104, // 002A GETMBR R2 R0 K4 - 0x4C0C0000, // 002B LDNIL R3 - 0x20080403, // 002C NE R2 R2 R3 - 0x780A000A, // 002D JMPF R2 #0039 - 0x88080304, // 002E GETMBR R2 R1 K4 - 0x4C0C0000, // 002F LDNIL R3 - 0x1C080403, // 0030 EQ R2 R2 R3 - 0x780A0000, // 0031 JMPF R2 #0033 - 0x80060200, // 0032 RET 1 K1 - 0x88080104, // 0033 GETMBR R2 R0 K4 - 0x880C0304, // 0034 GETMBR R3 R1 K4 - 0x24080403, // 0035 GT R2 R2 R3 - 0x780A0000, // 0036 JMPF R2 #0038 - 0x80060200, // 0037 RET 1 K1 - 0x80060600, // 0038 RET 1 K3 - 0x88080105, // 0039 GETMBR R2 R0 K5 - 0x4C0C0000, // 003A LDNIL R3 - 0x20080403, // 003B NE R2 R2 R3 - 0x780A0009, // 003C JMPF R2 #0047 - 0x88080305, // 003D GETMBR R2 R1 K5 - 0x4C0C0000, // 003E LDNIL R3 - 0x1C080403, // 003F EQ R2 R2 R3 - 0x780A0000, // 0040 JMPF R2 #0042 - 0x80060200, // 0041 RET 1 K1 - 0x88080105, // 0042 GETMBR R2 R0 K5 - 0x880C0305, // 0043 GETMBR R3 R1 K5 - 0x24080403, // 0044 GT R2 R2 R3 - 0x780A0000, // 0045 JMPF R2 #0047 - 0x80060200, // 0046 RET 1 K1 - 0x80060600, // 0047 RET 1 K3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: sort -********************************************************************/ -be_local_closure(Matter_TLV_item_sort, /* 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[ 5]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_TLV_item), - /* K1 */ be_const_int(1), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(_cmp_gt), - /* K4 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(sort), - &be_const_str_solidified, - ( &(const binstruction[33]) { /* 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 - 0xA8020013, // 0008 EXBLK 0 #001D - 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 - 0x781A000B, // 000E JMPF R6 #001B - 0x04180B01, // 000F SUB R6 R5 K1 - 0x94180006, // 0010 GETIDX R6 R0 R6 - 0x8C180D03, // 0011 GETMET R6 R6 K3 - 0x5C200800, // 0012 MOVE R8 R4 - 0x7C180400, // 0013 CALL R6 2 - 0x24180D02, // 0014 GT R6 R6 K2 - 0x781A0004, // 0015 JMPF R6 #001B - 0x04180B01, // 0016 SUB R6 R5 K1 - 0x94180006, // 0017 GETIDX R6 R0 R6 - 0x98000A06, // 0018 SETIDX R0 R5 R6 - 0x04140B01, // 0019 SUB R5 R5 K1 - 0x7001FFF1, // 001A JMP #000D - 0x98000A04, // 001B SETIDX R0 R5 R4 - 0x7001FFEB, // 001C JMP #0009 - 0x58080004, // 001D LDCONST R2 K4 - 0xAC080200, // 001E CATCH R2 1 0 - 0xB0080000, // 001F RAISE 2 R0 R0 - 0x80040000, // 0020 RET 1 R0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_anonymoustag -********************************************************************/ -be_local_closure(Matter_TLV_item_set_anonymoustag, /* name */ - be_nested_proto( - 3, /* nstack */ + 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(set_fulltag), - }), - be_str_weak(set_anonymoustag), + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(to_TLV), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_contextspecific -********************************************************************/ -be_local_closure(Matter_TLV_item_set_contextspecific, /* name */ - be_nested_proto( - 4, /* 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(set_fulltag), - /* K1 */ be_nested_str_weak(tag_sub), - }), - be_str_weak(set_contextspecific), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x7C080200, // 0001 CALL R2 1 - 0x60080009, // 0002 GETGBL R2 G9 - 0x5C0C0200, // 0003 MOVE R3 R1 - 0x7C080200, // 0004 CALL R2 1 - 0x90020202, // 0005 SETMBR R0 K1 R2 - 0x80000000, // 0006 RET 0 + ( &(const binstruction[ 1]) { /* code */ + 0x80040000, // 0000 RET 1 R0 }) ) ); @@ -1396,31 +1790,33 @@ be_local_closure(Matter_TLV_item_set_contextspecific, /* name */ be_local_class(Matter_TLV_item, 8, NULL, - be_nested_map(23, + be_nested_map(25, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(set_commonprofile, -1), be_const_closure(Matter_TLV_item_set_commonprofile_closure) }, { be_const_key_weak(set_parent, -1), be_const_closure(Matter_TLV_item_set_parent_closure) }, - { be_const_key_weak(tag_profile, 3), be_const_var(3) }, - { be_const_key_weak(set_anonymoustag, 8), be_const_closure(Matter_TLV_item_set_anonymoustag_closure) }, { be_const_key_weak(create_TLV, -1), be_const_static_closure(Matter_TLV_item_create_TLV_closure) }, - { be_const_key_weak(_encode_tag, -1), be_const_closure(Matter_TLV_item__encode_tag_closure) }, - { be_const_key_weak(val, -1), be_const_var(7) }, - { be_const_key_weak(TLV, 20), be_const_class(be_class_Matter_TLV) }, - { be_const_key_weak(tag_vendor, 1), be_const_var(2) }, - { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_item_tostring_closure) }, - { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_item_parse_closure) }, - { be_const_key_weak(tag_number, -1), be_const_var(4) }, - { be_const_key_weak(sort, -1), be_const_static_closure(Matter_TLV_item_sort_closure) }, { be_const_key_weak(next_idx, -1), be_const_var(1) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_item_init_closure) }, - { be_const_key_weak(_cmp_gt, -1), be_const_closure(Matter_TLV_item__cmp_gt_closure) }, - { be_const_key_weak(encode, 12), be_const_closure(Matter_TLV_item_encode_closure) }, - { be_const_key_weak(typ, -1), be_const_var(6) }, - { be_const_key_weak(parent, -1), be_const_var(0) }, - { be_const_key_weak(to_TLV, 6), be_const_closure(Matter_TLV_item_to_TLV_closure) }, + { be_const_key_weak(TLV, -1), be_const_class(be_class_Matter_TLV) }, + { be_const_key_weak(tag_vendor, 22), be_const_var(2) }, + { be_const_key_weak(set_anonymoustag, 17), be_const_closure(Matter_TLV_item_set_anonymoustag_closure) }, + { be_const_key_weak(val, -1), be_const_var(7) }, + { be_const_key_weak(to_TLV, -1), be_const_closure(Matter_TLV_item_to_TLV_closure) }, + { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_item_parse_closure) }, + { be_const_key_weak(_cmp_gt, 7), be_const_closure(Matter_TLV_item__cmp_gt_closure) }, + { be_const_key_weak(tag_profile, -1), be_const_var(3) }, + { be_const_key_weak(encode_len, 10), be_const_closure(Matter_TLV_item_encode_len_closure) }, + { be_const_key_weak(set_contextspecific, 8), be_const_closure(Matter_TLV_item_set_contextspecific_closure) }, { be_const_key_weak(set_fulltag, -1), be_const_closure(Matter_TLV_item_set_fulltag_closure) }, - { be_const_key_weak(tag_sub, 2), be_const_var(5) }, - { be_const_key_weak(set_contextspecific, -1), be_const_closure(Matter_TLV_item_set_contextspecific_closure) }, + { be_const_key_weak(parent, -1), be_const_var(0) }, + { be_const_key_weak(_encode_tag_len, 19), be_const_closure(Matter_TLV_item__encode_tag_len_closure) }, + { be_const_key_weak(tag_sub, -1), be_const_var(5) }, + { be_const_key_weak(init, 23), be_const_closure(Matter_TLV_item_init_closure) }, + { be_const_key_weak(tlv2raw, -1), be_const_closure(Matter_TLV_item_tlv2raw_closure) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_item_tostring_closure) }, + { be_const_key_weak(set_commonprofile, 15), be_const_closure(Matter_TLV_item_set_commonprofile_closure) }, + { be_const_key_weak(sort, -1), be_const_static_closure(Matter_TLV_item_sort_closure) }, + { be_const_key_weak(_encode_tag, -1), be_const_closure(Matter_TLV_item__encode_tag_closure) }, + { be_const_key_weak(tag_number, 16), be_const_var(4) }, + { be_const_key_weak(typ, 3), be_const_var(6) }, })), be_str_weak(Matter_TLV_item) ); @@ -1575,38 +1971,27 @@ be_local_closure(Matter_TLV_list_getsubval, /* name */ /******************************************************************** -** Solidified function: add_list +** Solidified function: setitem ********************************************************************/ -be_local_closure(Matter_TLV_list_add_list, /* name */ +be_local_closure(Matter_TLV_list_setitem, /* name */ be_nested_proto( - 6, /* nstack */ - 2, /* argc */ + 4, /* 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_weak(TLV), - /* K1 */ be_nested_str_weak(Matter_TLV_list), - /* K2 */ be_nested_str_weak(tag_sub), - /* K3 */ be_nested_str_weak(val), - /* K4 */ be_nested_str_weak(push), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(val), }), - be_str_weak(add_list), + be_str_weak(setitem), &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100000, // 0002 MOVE R4 R0 - 0x7C080400, // 0003 CALL R2 2 - 0x900A0401, // 0004 SETMBR R2 K2 R1 - 0x880C0103, // 0005 GETMBR R3 R0 K3 - 0x8C0C0704, // 0006 GETMET R3 R3 K4 - 0x5C140400, // 0007 MOVE R5 R2 - 0x7C0C0400, // 0008 CALL R3 2 - 0x80040400, // 0009 RET 1 R2 + ( &(const binstruction[ 3]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x980C0202, // 0001 SETIDX R3 R1 R2 + 0x80000000, // 0002 RET 0 }) ) ); @@ -1707,9 +2092,9 @@ be_local_closure(Matter_TLV_list_findsubtyp, /* name */ /******************************************************************** -** Solidified function: encode +** Solidified function: add_list ********************************************************************/ -be_local_closure(Matter_TLV_list_encode, /* name */ +be_local_closure(Matter_TLV_list_add_list, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -1719,18 +2104,26 @@ be_local_closure(Matter_TLV_list_encode, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(_encode_inner), - /* K1 */ be_nested_str_weak(is_struct), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(TLV), + /* K1 */ be_nested_str_weak(Matter_TLV_list), + /* K2 */ be_nested_str_weak(tag_sub), + /* K3 */ be_nested_str_weak(val), + /* K4 */ be_nested_str_weak(push), }), - be_str_weak(encode), + be_str_weak(add_list), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x88140101, // 0002 GETMBR R5 R0 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80040400, // 0004 RET 1 R2 + ( &(const binstruction[10]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100000, // 0002 MOVE R4 R0 + 0x7C080400, // 0003 CALL R2 2 + 0x900A0401, // 0004 SETMBR R2 K2 R1 + 0x880C0103, // 0005 GETMBR R3 R0 K3 + 0x8C0C0704, // 0006 GETMET R3 R3 K4 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x80040400, // 0009 RET 1 R2 }) ) ); @@ -1865,11 +2258,11 @@ be_local_closure(Matter_TLV_list_tostring_inner, /* name */ /******************************************************************** -** Solidified function: tostring +** Solidified function: encode_len ********************************************************************/ -be_local_closure(Matter_TLV_list_tostring, /* name */ +be_local_closure(Matter_TLV_list_encode_len, /* name */ be_nested_proto( - 6, /* nstack */ + 5, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1877,20 +2270,33 @@ be_local_closure(Matter_TLV_list_tostring, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tostring_inner), - /* K1 */ be_nested_str_weak(_X5B_X5B), - /* K2 */ be_nested_str_weak(_X5D_X5D), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_encode_tag_len), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(val), + /* K3 */ be_nested_str_weak(encode_len), + /* K4 */ be_const_int(1), }), - be_str_weak(tostring), + be_str_weak(encode_len), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ + ( &(const binstruction[17]) { /* code */ 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x500C0000, // 0001 LDBOOL R3 0 0 - 0x58100001, // 0002 LDCONST R4 K1 - 0x58140002, // 0003 LDCONST R5 K2 - 0x7C040800, // 0004 CALL R1 4 - 0x80040200, // 0005 RET 1 R1 + 0x7C040200, // 0001 CALL R1 1 + 0x58080001, // 0002 LDCONST R2 K1 + 0x600C000C, // 0003 GETGBL R3 G12 + 0x88100102, // 0004 GETMBR R4 R0 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x140C0403, // 0006 LT R3 R2 R3 + 0x780E0006, // 0007 JMPF R3 #000F + 0x880C0102, // 0008 GETMBR R3 R0 K2 + 0x940C0602, // 0009 GETIDX R3 R3 R2 + 0x8C0C0703, // 000A GETMET R3 R3 K3 + 0x7C0C0200, // 000B CALL R3 1 + 0x00040203, // 000C ADD R1 R1 R3 + 0x00080504, // 000D ADD R2 R2 K4 + 0x7001FFF3, // 000E JMP #0003 + 0x00040304, // 000F ADD R1 R1 K4 + 0x80040200, // 0010 RET 1 R1 }) ) ); @@ -2066,96 +2472,71 @@ be_local_closure(Matter_TLV_list_add_TLV, /* name */ /******************************************************************** -** Solidified function: setitem +** Solidified function: tlv2raw ********************************************************************/ -be_local_closure(Matter_TLV_list_setitem, /* name */ +be_local_closure(Matter_TLV_list_tlv2raw, /* name */ be_nested_proto( - 4, /* nstack */ - 3, /* argc */ + 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[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(val), - }), - be_str_weak(setitem), - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x980C0202, // 0001 SETIDX R3 R1 R2 - 0x80000000, // 0002 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _encode_inner -********************************************************************/ -be_local_closure(Matter_TLV_list__encode_inner, /* 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[10]) { /* constants */ + ( &(const bvalue[11]) { /* constants */ /* K0 */ be_nested_str_weak(_encode_tag), /* K1 */ be_nested_str_weak(val), - /* K2 */ be_nested_str_weak(copy), - /* K3 */ be_nested_str_weak(sort), - /* K4 */ be_nested_str_weak(encode), - /* K5 */ be_nested_str_weak(stop_iteration), - /* K6 */ be_nested_str_weak(add), - /* K7 */ be_nested_str_weak(TLV), - /* K8 */ be_nested_str_weak(EOC), - /* K9 */ be_const_int(1), + /* K2 */ be_nested_str_weak(is_struct), + /* K3 */ be_nested_str_weak(copy), + /* K4 */ be_nested_str_weak(sort), + /* K5 */ be_nested_str_weak(tlv2raw), + /* K6 */ be_nested_str_weak(stop_iteration), + /* K7 */ be_nested_str_weak(add), + /* K8 */ be_nested_str_weak(TLV), + /* K9 */ be_nested_str_weak(EOC), + /* K10 */ be_const_int(1), }), - be_str_weak(_encode_inner), + be_str_weak(tlv2raw), &be_const_str_solidified, - ( &(const binstruction[35]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0203, // 0001 EQ R3 R1 R3 - 0x780E0002, // 0002 JMPF R3 #0006 - 0x600C0015, // 0003 GETGBL R3 G21 - 0x7C0C0000, // 0004 CALL R3 0 - 0x5C040600, // 0005 MOVE R1 R3 - 0x8C0C0100, // 0006 GETMET R3 R0 K0 - 0x5C140200, // 0007 MOVE R5 R1 - 0x7C0C0400, // 0008 CALL R3 2 - 0x880C0101, // 0009 GETMBR R3 R0 K1 - 0x8C0C0702, // 000A GETMET R3 R3 K2 - 0x7C0C0200, // 000B CALL R3 1 - 0x780A0002, // 000C JMPF R2 #0010 - 0x8C100103, // 000D GETMET R4 R0 K3 - 0x5C180600, // 000E MOVE R6 R3 - 0x7C100400, // 000F CALL R4 2 - 0x60100010, // 0010 GETGBL R4 G16 - 0x5C140600, // 0011 MOVE R5 R3 - 0x7C100200, // 0012 CALL R4 1 - 0xA8020005, // 0013 EXBLK 0 #001A - 0x5C140800, // 0014 MOVE R5 R4 - 0x7C140000, // 0015 CALL R5 0 - 0x8C180B04, // 0016 GETMET R6 R5 K4 - 0x5C200200, // 0017 MOVE R8 R1 - 0x7C180400, // 0018 CALL R6 2 - 0x7001FFF9, // 0019 JMP #0014 - 0x58100005, // 001A LDCONST R4 K5 - 0xAC100200, // 001B CATCH R4 1 0 - 0xB0080000, // 001C RAISE 2 R0 R0 - 0x8C100306, // 001D GETMET R4 R1 K6 - 0x88180107, // 001E GETMBR R6 R0 K7 - 0x88180D08, // 001F GETMBR R6 R6 K8 - 0x581C0009, // 0020 LDCONST R7 K9 - 0x7C100600, // 0021 CALL R4 3 - 0x80040200, // 0022 RET 1 R1 + ( &(const binstruction[37]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0002, // 0002 JMPF R2 #0006 + 0x60080015, // 0003 GETGBL R2 G21 + 0x7C080000, // 0004 CALL R2 0 + 0x5C040400, // 0005 MOVE R1 R2 + 0x8C080100, // 0006 GETMET R2 R0 K0 + 0x5C100200, // 0007 MOVE R4 R1 + 0x7C080400, // 0008 CALL R2 2 + 0x88080101, // 0009 GETMBR R2 R0 K1 + 0x880C0102, // 000A GETMBR R3 R0 K2 + 0x780E0005, // 000B JMPF R3 #0012 + 0x8C0C0503, // 000C GETMET R3 R2 K3 + 0x7C0C0200, // 000D CALL R3 1 + 0x5C080600, // 000E MOVE R2 R3 + 0x8C0C0104, // 000F GETMET R3 R0 K4 + 0x5C140400, // 0010 MOVE R5 R2 + 0x7C0C0400, // 0011 CALL R3 2 + 0x600C0010, // 0012 GETGBL R3 G16 + 0x5C100400, // 0013 MOVE R4 R2 + 0x7C0C0200, // 0014 CALL R3 1 + 0xA8020005, // 0015 EXBLK 0 #001C + 0x5C100600, // 0016 MOVE R4 R3 + 0x7C100000, // 0017 CALL R4 0 + 0x8C140905, // 0018 GETMET R5 R4 K5 + 0x5C1C0200, // 0019 MOVE R7 R1 + 0x7C140400, // 001A CALL R5 2 + 0x7001FFF9, // 001B JMP #0016 + 0x580C0006, // 001C LDCONST R3 K6 + 0xAC0C0200, // 001D CATCH R3 1 0 + 0xB0080000, // 001E RAISE 2 R0 R0 + 0x8C0C0307, // 001F GETMET R3 R1 K7 + 0x88140108, // 0020 GETMBR R5 R0 K8 + 0x88140B09, // 0021 GETMBR R5 R5 K9 + 0x5818000A, // 0022 LDCONST R6 K10 + 0x7C0C0600, // 0023 CALL R3 3 + 0x80040200, // 0024 RET 1 R1 }) ) ); @@ -2205,6 +2586,39 @@ be_local_closure(Matter_TLV_list_findsub, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Matter_TLV_list_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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tostring_inner), + /* K1 */ be_nested_str_weak(_X5B_X5B), + /* K2 */ be_nested_str_weak(_X5D_X5D), + }), + be_str_weak(tostring), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x500C0000, // 0001 LDBOOL R3 0 0 + 0x58100001, // 0002 LDCONST R4 K1 + 0x58140002, // 0003 LDCONST R5 K2 + 0x7C040800, // 0004 CALL R1 4 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: parse ********************************************************************/ @@ -2308,17 +2722,17 @@ be_local_class(Matter_TLV_list, { be_const_key_weak(parse, -1), be_const_closure(Matter_TLV_list_parse_closure) }, { be_const_key_weak(size, -1), be_const_closure(Matter_TLV_list_size_closure) }, { be_const_key_weak(findsubtyp, -1), be_const_closure(Matter_TLV_list_findsubtyp_closure) }, - { be_const_key_weak(encode, -1), be_const_closure(Matter_TLV_list_encode_closure) }, + { be_const_key_weak(tostring, -1), be_const_closure(Matter_TLV_list_tostring_closure) }, { be_const_key_weak(tostring_inner, 4), be_const_closure(Matter_TLV_list_tostring_inner_closure) }, - { be_const_key_weak(tostring, 16), be_const_closure(Matter_TLV_list_tostring_closure) }, + { be_const_key_weak(encode_len, 8), be_const_closure(Matter_TLV_list_encode_len_closure) }, { be_const_key_weak(findsubval, -1), be_const_closure(Matter_TLV_list_findsubval_closure) }, { be_const_key_weak(init, -1), be_const_closure(Matter_TLV_list_init_closure) }, - { be_const_key_weak(add_array, 15), be_const_closure(Matter_TLV_list_add_array_closure) }, - { be_const_key_weak(add_TLV, 18), be_const_closure(Matter_TLV_list_add_TLV_closure) }, + { be_const_key_weak(add_array, 16), be_const_closure(Matter_TLV_list_add_array_closure) }, + { be_const_key_weak(setitem, 15), be_const_closure(Matter_TLV_list_setitem_closure) }, + { be_const_key_weak(tlv2raw, 18), be_const_closure(Matter_TLV_list_tlv2raw_closure) }, { be_const_key_weak(findsub, -1), be_const_closure(Matter_TLV_list_findsub_closure) }, - { be_const_key_weak(_encode_inner, -1), be_const_closure(Matter_TLV_list__encode_inner_closure) }, { be_const_key_weak(is_struct, -1), be_const_bool(0) }, - { be_const_key_weak(setitem, -1), be_const_closure(Matter_TLV_list_setitem_closure) }, + { be_const_key_weak(add_TLV, -1), be_const_closure(Matter_TLV_list_add_TLV_closure) }, { be_const_key_weak(item, 5), be_const_closure(Matter_TLV_list_item_closure) }, { be_const_key_weak(add_list, -1), be_const_closure(Matter_TLV_list_add_list_closure) }, })), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h index 9cf11d294..a95cc8253 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UDPServer.h @@ -11,54 +11,7 @@ extern const bclass be_class_Matter_UDPPacket_sent; ********************************************************************/ be_local_closure(Matter_UDPPacket_sent_init, /* name */ be_nested_proto( - 7, /* nstack */ - 5, /* 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(raw), - /* K1 */ be_nested_str_weak(addr), - /* K2 */ be_nested_str_weak(port), - /* K3 */ be_nested_str_weak(msg_id), - /* K4 */ be_nested_str_weak(retries), - /* K5 */ be_nested_str_weak(RETRIES), - /* K6 */ be_nested_str_weak(next_try), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(millis), - /* K9 */ be_nested_str_weak(RETRY_MS), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x90020403, // 0002 SETMBR R0 K2 R3 - 0x90020604, // 0003 SETMBR R0 K3 R4 - 0x88140105, // 0004 GETMBR R5 R0 K5 - 0x90020805, // 0005 SETMBR R0 K4 R5 - 0xB8160E00, // 0006 GETNGBL R5 K7 - 0x8C140B08, // 0007 GETMET R5 R5 K8 - 0x7C140200, // 0008 CALL R5 1 - 0x88180109, // 0009 GETMBR R6 R0 K9 - 0x00140A06, // 000A ADD R5 R5 R6 - 0x90020C05, // 000B SETMBR R0 K6 R5 - 0x80000000, // 000C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: send -********************************************************************/ -be_local_closure(Matter_UDPPacket_sent_send, /* name */ - be_nested_proto( - 11, /* nstack */ + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -66,60 +19,70 @@ be_local_closure(Matter_UDPPacket_sent_send, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[14]) { /* constants */ - /* K0 */ be_nested_str_weak(string), - /* K1 */ be_nested_str_weak(send), - /* K2 */ be_nested_str_weak(addr), - /* K3 */ be_nested_str_weak(remote_ip), - /* K4 */ be_nested_str_weak(port), - /* K5 */ be_nested_str_weak(remote_port), - /* K6 */ be_nested_str_weak(raw), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(log), - /* K9 */ be_nested_str_weak(format), - /* K10 */ be_nested_str_weak(MTR_X3A_X20sending_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), - /* K11 */ be_const_int(3), - /* K12 */ be_nested_str_weak(MTR_X3A_X20failed_X20to_X20send_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), - /* K13 */ be_const_int(2), + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(raw), + /* K1 */ be_nested_str_weak(addr), + /* K2 */ be_nested_str_weak(remote_ip), + /* K3 */ be_nested_str_weak(port), + /* K4 */ be_nested_str_weak(remote_port), + /* K5 */ be_nested_str_weak(msg_id), + /* K6 */ be_nested_str_weak(x_flag_r), + /* K7 */ be_nested_str_weak(message_counter), + /* K8 */ be_nested_str_weak(exchange_id), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(session_id), + /* K11 */ be_nested_str_weak(local_session_id), + /* K12 */ be_nested_str_weak(retries), + /* K13 */ be_nested_str_weak(next_try), + /* K14 */ be_nested_str_weak(tasmota), + /* K15 */ be_nested_str_weak(millis), + /* K16 */ be_nested_str_weak(matter), + /* K17 */ be_nested_str_weak(UDPServer), + /* K18 */ be_nested_str_weak(_backoff_time), }), - be_str_weak(send), + be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[35]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0301, // 0001 GETMET R3 R1 K1 - 0x88140102, // 0002 GETMBR R5 R0 K2 - 0x78160001, // 0003 JMPF R5 #0006 - 0x88140102, // 0004 GETMBR R5 R0 K2 - 0x70020000, // 0005 JMP #0007 - 0x88140303, // 0006 GETMBR R5 R1 K3 - 0x88180104, // 0007 GETMBR R6 R0 K4 - 0x781A0001, // 0008 JMPF R6 #000B - 0x88180104, // 0009 GETMBR R6 R0 K4 - 0x70020000, // 000A JMP #000C - 0x88180305, // 000B GETMBR R6 R1 K5 - 0x881C0106, // 000C GETMBR R7 R0 K6 - 0x7C0C0800, // 000D CALL R3 4 - 0x780E0009, // 000E JMPF R3 #0019 - 0xB8120E00, // 000F GETNGBL R4 K7 - 0x8C100908, // 0010 GETMET R4 R4 K8 - 0x8C180509, // 0011 GETMET R6 R2 K9 - 0x5820000A, // 0012 LDCONST R8 K10 - 0x88240102, // 0013 GETMBR R9 R0 K2 - 0x88280104, // 0014 GETMBR R10 R0 K4 - 0x7C180800, // 0015 CALL R6 4 - 0x581C000B, // 0016 LDCONST R7 K11 - 0x7C100600, // 0017 CALL R4 3 - 0x70020008, // 0018 JMP #0022 - 0xB8120E00, // 0019 GETNGBL R4 K7 - 0x8C100908, // 001A GETMET R4 R4 K8 - 0x8C180509, // 001B GETMET R6 R2 K9 - 0x5820000C, // 001C LDCONST R8 K12 - 0x88240102, // 001D GETMBR R9 R0 K2 - 0x88280104, // 001E GETMBR R10 R0 K4 - 0x7C180800, // 001F CALL R6 4 - 0x581C000D, // 0020 LDCONST R7 K13 - 0x7C100600, // 0021 CALL R4 3 - 0x80000000, // 0022 RET 0 + ( &(const binstruction[40]) { /* code */ + 0x88080300, // 0000 GETMBR R2 R1 K0 + 0x90020002, // 0001 SETMBR R0 K0 R2 + 0x88080302, // 0002 GETMBR R2 R1 K2 + 0x90020202, // 0003 SETMBR R0 K1 R2 + 0x88080304, // 0004 GETMBR R2 R1 K4 + 0x90020602, // 0005 SETMBR R0 K3 R2 + 0x88080306, // 0006 GETMBR R2 R1 K6 + 0x780A0001, // 0007 JMPF R2 #000A + 0x88080307, // 0008 GETMBR R2 R1 K7 + 0x70020000, // 0009 JMP #000B + 0x4C080000, // 000A LDNIL R2 + 0x90020A02, // 000B SETMBR R0 K5 R2 + 0x88080308, // 000C GETMBR R2 R1 K8 + 0x4C0C0000, // 000D LDNIL R3 + 0x20080403, // 000E NE R2 R2 R3 + 0x780A0001, // 000F JMPF R2 #0012 + 0x88080308, // 0010 GETMBR R2 R1 K8 + 0x70020000, // 0011 JMP #0013 + 0x58080009, // 0012 LDCONST R2 K9 + 0x90021002, // 0013 SETMBR R0 K8 R2 + 0x8808030B, // 0014 GETMBR R2 R1 K11 + 0x4C0C0000, // 0015 LDNIL R3 + 0x20080403, // 0016 NE R2 R2 R3 + 0x780A0001, // 0017 JMPF R2 #001A + 0x8808030B, // 0018 GETMBR R2 R1 K11 + 0x70020000, // 0019 JMP #001B + 0x58080009, // 001A LDCONST R2 K9 + 0x90021402, // 001B SETMBR R0 K10 R2 + 0x90021909, // 001C SETMBR R0 K12 K9 + 0xB80A1C00, // 001D GETNGBL R2 K14 + 0x8C08050F, // 001E GETMET R2 R2 K15 + 0x7C080200, // 001F CALL R2 1 + 0xB80E2000, // 0020 GETNGBL R3 K16 + 0x880C0711, // 0021 GETMBR R3 R3 K17 + 0x8C0C0712, // 0022 GETMET R3 R3 K18 + 0x8814010C, // 0023 GETMBR R5 R0 K12 + 0x7C0C0400, // 0024 CALL R3 2 + 0x00080403, // 0025 ADD R2 R2 R3 + 0x90021A02, // 0026 SETMBR R0 K13 R2 + 0x80000000, // 0027 RET 0 }) ) ); @@ -130,19 +93,18 @@ be_local_closure(Matter_UDPPacket_sent_send, /* name */ ** Solidified class: Matter_UDPPacket_sent ********************************************************************/ be_local_class(Matter_UDPPacket_sent, - 6, + 8, NULL, - be_nested_map(10, + be_nested_map(9, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(RETRY_MS, 7), be_const_int(500) }, - { be_const_key_weak(raw, 4), be_const_var(0) }, - { be_const_key_weak(next_try, 9), be_const_var(5) }, - { be_const_key_weak(retries, -1), be_const_var(4) }, - { be_const_key_weak(send, 6), be_const_closure(Matter_UDPPacket_sent_send_closure) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_UDPPacket_sent_init_closure) }, - { be_const_key_weak(RETRIES, -1), be_const_int(4) }, - { be_const_key_weak(port, -1), be_const_var(2) }, + { be_const_key_weak(next_try, -1), be_const_var(7) }, + { be_const_key_weak(session_id, 8), be_const_var(5) }, + { be_const_key_weak(retries, 3), be_const_var(6) }, { be_const_key_weak(addr, -1), be_const_var(1) }, + { be_const_key_weak(port, 0), be_const_var(2) }, + { be_const_key_weak(raw, -1), be_const_var(0) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_UDPPacket_sent_init_closure) }, + { be_const_key_weak(exchange_id, -1), be_const_var(4) }, { be_const_key_weak(msg_id, -1), be_const_var(3) }, })), be_str_weak(Matter_UDPPacket_sent) @@ -158,44 +120,194 @@ void be_load_Matter_UDPPacket_sent_class(bvm *vm) { extern const bclass be_class_Matter_UDPServer; /******************************************************************** -** Solidified function: init +** Solidified function: _backoff_time ********************************************************************/ -be_local_closure(Matter_UDPServer_init, /* name */ +be_local_closure(Matter_UDPServer__backoff_time, /* name */ be_nested_proto( - 4, /* nstack */ - 3, /* argc */ + 10, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_const_int(1), + /* K1 */ be_const_int(0), + }), + be_str_weak(power_int), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x240C0301, // 0001 GT R3 R1 K1 + 0x780E0002, // 0002 JMPF R3 #0006 + 0x08080400, // 0003 MUL R2 R2 R0 + 0x04040300, // 0004 SUB R1 R1 K0 + 0x7001FFFA, // 0005 JMP #0001 + 0x80040400, // 0006 RET 1 R2 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_UDPServer), + /* K1 */ be_nested_str_weak(math), + /* K2 */ be_nested_str_weak(rand), + /* K3 */ be_const_int(0), + /* K4 */ be_const_int(1), + /* K5 */ be_const_real_hex(0x3FCCCCCD), + /* K6 */ be_const_real_hex(0x3F800000), + /* K7 */ be_const_real_hex(0x3E800000), + }), + be_str_weak(_backoff_time), + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x84080000, // 0001 CLOSURE R2 P0 + 0xA40E0200, // 0002 IMPORT R3 K1 + 0x5412012B, // 0003 LDINT R4 300 + 0x6014000A, // 0004 GETGBL R5 G10 + 0x8C180702, // 0005 GETMET R6 R3 K2 + 0x7C180200, // 0006 CALL R6 1 + 0x541E00FE, // 0007 LDINT R7 255 + 0x2C180C07, // 0008 AND R6 R6 R7 + 0x7C140200, // 0009 CALL R5 1 + 0x541A00FE, // 000A LDINT R6 255 + 0x0C140A06, // 000B DIV R5 R5 R6 + 0x24180103, // 000C GT R6 R0 K3 + 0x781A0001, // 000D JMPF R6 #0010 + 0x04180104, // 000E SUB R6 R0 K4 + 0x70020000, // 000F JMP #0011 + 0x58180003, // 0010 LDCONST R6 K3 + 0x5C1C0400, // 0011 MOVE R7 R2 + 0x58200005, // 0012 LDCONST R8 K5 + 0x5C240C00, // 0013 MOVE R9 R6 + 0x7C1C0400, // 0014 CALL R7 2 + 0x081C0807, // 0015 MUL R7 R4 R7 + 0x08200B07, // 0016 MUL R8 R5 K7 + 0x00220C08, // 0017 ADD R8 K6 R8 + 0x081C0E08, // 0018 MUL R7 R7 R8 + 0x60200009, // 0019 GETGBL R8 G9 + 0x5C240E00, // 001A MOVE R9 R7 + 0x7C200200, // 001B CALL R8 1 + 0x80041000, // 001C RET 1 R8 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _resend_packets +********************************************************************/ +be_local_closure(Matter_UDPServer__resend_packets, /* name */ + be_nested_proto( + 13, /* 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(address), - /* K1 */ be_nested_str_weak(), - /* K2 */ be_nested_str_weak(port), - /* K3 */ be_nested_str_weak(listening), - /* K4 */ be_nested_str_weak(packets_sent), + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(packets_sent), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(time_reached), + /* K4 */ be_nested_str_weak(next_try), + /* K5 */ be_nested_str_weak(retries), + /* K6 */ be_nested_str_weak(RETRIES), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Resending_X20packet_X20id_X3D), + /* K9 */ be_nested_str_weak(msg_id), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(send), + /* K12 */ be_nested_str_weak(millis), + /* K13 */ be_nested_str_weak(_backoff_time), + /* K14 */ be_const_int(1), + /* K15 */ be_nested_str_weak(string), + /* K16 */ be_nested_str_weak(remove), + /* K17 */ be_nested_str_weak(format), + /* K18 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20_X28_X256i_X29_X20Unacked_X20packet_X20_X27_X5B_X25s_X5D_X3A_X25i_X27_X20msg_id_X3D_X25i), + /* K19 */ be_nested_str_weak(session_id), + /* K20 */ be_nested_str_weak(addr), + /* K21 */ be_nested_str_weak(port), + /* K22 */ be_const_int(2), }), - be_str_weak(init), + be_str_weak(_resend_packets), &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x78060001, // 0000 JMPF R1 #0003 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x70020000, // 0002 JMP #0004 - 0x580C0001, // 0003 LDCONST R3 K1 - 0x90020003, // 0004 SETMBR R0 K0 R3 - 0x780A0001, // 0005 JMPF R2 #0008 - 0x5C0C0400, // 0006 MOVE R3 R2 - 0x70020000, // 0007 JMP #0009 - 0x540E15A3, // 0008 LDINT R3 5540 - 0x90020403, // 0009 SETMBR R0 K2 R3 - 0x500C0000, // 000A LDBOOL R3 0 0 - 0x90020603, // 000B SETMBR R0 K3 R3 - 0x600C0013, // 000C GETGBL R3 G19 - 0x7C0C0000, // 000D CALL R3 0 - 0x90020803, // 000E SETMBR R0 K4 R3 - 0x80000000, // 000F RET 0 + ( &(const binstruction[61]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x14080202, // 0004 LT R2 R1 R2 + 0x780A0035, // 0005 JMPF R2 #003C + 0x88080101, // 0006 GETMBR R2 R0 K1 + 0x94080401, // 0007 GETIDX R2 R2 R1 + 0xB80E0400, // 0008 GETNGBL R3 K2 + 0x8C0C0703, // 0009 GETMET R3 R3 K3 + 0x88140504, // 000A GETMBR R5 R2 K4 + 0x7C0C0400, // 000B CALL R3 2 + 0x780E002C, // 000C JMPF R3 #003A + 0x880C0505, // 000D GETMBR R3 R2 K5 + 0x88100106, // 000E GETMBR R4 R0 K6 + 0x180C0604, // 000F LE R3 R3 R4 + 0x780E0017, // 0010 JMPF R3 #0029 + 0xB80E0400, // 0011 GETNGBL R3 K2 + 0x8C0C0707, // 0012 GETMET R3 R3 K7 + 0x60140008, // 0013 GETGBL R5 G8 + 0x88180509, // 0014 GETMBR R6 R2 K9 + 0x7C140200, // 0015 CALL R5 1 + 0x00161005, // 0016 ADD R5 K8 R5 + 0x5818000A, // 0017 LDCONST R6 K10 + 0x7C0C0600, // 0018 CALL R3 3 + 0x8C0C010B, // 0019 GETMET R3 R0 K11 + 0x5C140400, // 001A MOVE R5 R2 + 0x7C0C0400, // 001B CALL R3 2 + 0xB80E0400, // 001C GETNGBL R3 K2 + 0x8C0C070C, // 001D GETMET R3 R3 K12 + 0x7C0C0200, // 001E CALL R3 1 + 0x8C10010D, // 001F GETMET R4 R0 K13 + 0x88180505, // 0020 GETMBR R6 R2 K5 + 0x7C100400, // 0021 CALL R4 2 + 0x000C0604, // 0022 ADD R3 R3 R4 + 0x900A0803, // 0023 SETMBR R2 K4 R3 + 0x880C0505, // 0024 GETMBR R3 R2 K5 + 0x000C070E, // 0025 ADD R3 R3 K14 + 0x900A0A03, // 0026 SETMBR R2 K5 R3 + 0x0004030E, // 0027 ADD R1 R1 K14 + 0x7002000F, // 0028 JMP #0039 + 0xA40E1E00, // 0029 IMPORT R3 K15 + 0x88100101, // 002A GETMBR R4 R0 K1 + 0x8C100910, // 002B GETMET R4 R4 K16 + 0x5C180200, // 002C MOVE R6 R1 + 0x7C100400, // 002D CALL R4 2 + 0xB8120400, // 002E GETNGBL R4 K2 + 0x8C100907, // 002F GETMET R4 R4 K7 + 0x8C180711, // 0030 GETMET R6 R3 K17 + 0x58200012, // 0031 LDCONST R8 K18 + 0x88240513, // 0032 GETMBR R9 R2 K19 + 0x88280514, // 0033 GETMBR R10 R2 K20 + 0x882C0515, // 0034 GETMBR R11 R2 K21 + 0x88300509, // 0035 GETMBR R12 R2 K9 + 0x7C180C00, // 0036 CALL R6 6 + 0x581C0016, // 0037 LDCONST R7 K22 + 0x7C100600, // 0038 CALL R4 3 + 0x70020000, // 0039 JMP #003B + 0x0004030E, // 003A ADD R1 R1 K14 + 0x7001FFC4, // 003B JMP #0001 + 0x80000000, // 003C RET 0 }) ) ); @@ -226,6 +338,136 @@ be_local_closure(Matter_UDPServer_every_second, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: send_UDP +********************************************************************/ +be_local_closure(Matter_UDPServer_send_UDP, /* 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[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(UDPPacket_sent), + /* K2 */ be_nested_str_weak(send), + /* K3 */ be_nested_str_weak(msg_id), + /* K4 */ be_nested_str_weak(packets_sent), + /* K5 */ be_nested_str_weak(push), + }), + be_str_weak(send_UDP), + &be_const_str_solidified, + ( &(const binstruction[14]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x8C0C0102, // 0004 GETMET R3 R0 K2 + 0x5C140400, // 0005 MOVE R5 R2 + 0x7C0C0400, // 0006 CALL R3 2 + 0x880C0503, // 0007 GETMBR R3 R2 K3 + 0x780E0003, // 0008 JMPF R3 #000D + 0x880C0104, // 0009 GETMBR R3 R0 K4 + 0x8C0C0705, // 000A GETMET R3 R3 K5 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x80000000, // 000D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_50ms +********************************************************************/ +be_local_closure(Matter_UDPServer_every_50ms, /* name */ + be_nested_proto( + 13, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[15]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(udp_socket), + /* K3 */ be_nested_str_weak(read), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(remote_ip), + /* K6 */ be_nested_str_weak(remote_port), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(format), + /* K10 */ be_nested_str_weak(MTR_X3A_X20UDP_X20received_X20from_X20_X5B_X25s_X5D_X3A_X25i), + /* K11 */ be_const_int(3), + /* K12 */ be_nested_str_weak(dispatch_cb), + /* K13 */ be_nested_str_weak(MAX_PACKETS_READ), + /* K14 */ be_nested_str_weak(_resend_packets), + }), + be_str_weak(every_50ms), + &be_const_str_solidified, + ( &(const binstruction[47]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x4C100000, // 0003 LDNIL R4 + 0x1C0C0604, // 0004 EQ R3 R3 R4 + 0x780E0000, // 0005 JMPF R3 #0007 + 0x80000600, // 0006 RET 0 + 0x880C0102, // 0007 GETMBR R3 R0 K2 + 0x8C0C0703, // 0008 GETMET R3 R3 K3 + 0x7C0C0200, // 0009 CALL R3 1 + 0x4C100000, // 000A LDNIL R4 + 0x20100604, // 000B NE R4 R3 R4 + 0x7812001E, // 000C JMPF R4 #002C + 0x00080504, // 000D ADD R2 R2 K4 + 0x88100102, // 000E GETMBR R4 R0 K2 + 0x88100905, // 000F GETMBR R4 R4 K5 + 0x88140102, // 0010 GETMBR R5 R0 K2 + 0x88140B06, // 0011 GETMBR R5 R5 K6 + 0xB81A0E00, // 0012 GETNGBL R6 K7 + 0x8C180D08, // 0013 GETMET R6 R6 K8 + 0x8C200309, // 0014 GETMET R8 R1 K9 + 0x5828000A, // 0015 LDCONST R10 K10 + 0x5C2C0800, // 0016 MOVE R11 R4 + 0x5C300A00, // 0017 MOVE R12 R5 + 0x7C200800, // 0018 CALL R8 4 + 0x5824000B, // 0019 LDCONST R9 K11 + 0x7C180600, // 001A CALL R6 3 + 0x8818010C, // 001B GETMBR R6 R0 K12 + 0x781A0004, // 001C JMPF R6 #0022 + 0x8C18010C, // 001D GETMET R6 R0 K12 + 0x5C200600, // 001E MOVE R8 R3 + 0x5C240800, // 001F MOVE R9 R4 + 0x5C280A00, // 0020 MOVE R10 R5 + 0x7C180800, // 0021 CALL R6 4 + 0x8818010D, // 0022 GETMBR R6 R0 K13 + 0x14180406, // 0023 LT R6 R2 R6 + 0x781A0004, // 0024 JMPF R6 #002A + 0x88180102, // 0025 GETMBR R6 R0 K2 + 0x8C180D03, // 0026 GETMET R6 R6 K3 + 0x7C180200, // 0027 CALL R6 1 + 0x5C0C0C00, // 0028 MOVE R3 R6 + 0x70020000, // 0029 JMP #002B + 0x4C0C0000, // 002A LDNIL R3 + 0x7001FFDD, // 002B JMP #000A + 0x8C10010E, // 002C GETMET R4 R0 K14 + 0x7C100200, // 002D CALL R4 1 + 0x80000000, // 002E RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: stop ********************************************************************/ @@ -267,176 +509,6 @@ be_local_closure(Matter_UDPServer_stop, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: every_50ms -********************************************************************/ -be_local_closure(Matter_UDPServer_every_50ms, /* name */ - be_nested_proto( - 13, /* 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(string), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(udp_socket), - /* K3 */ be_nested_str_weak(read), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(remote_ip), - /* K6 */ be_nested_str_weak(remote_port), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(log), - /* K9 */ be_nested_str_weak(format), - /* K10 */ be_nested_str_weak(MTR_X3A_X20UDP_X20received_X20from_X20_X5B_X25s_X5D_X3A_X25i), - /* K11 */ be_nested_str_weak(dispatch_cb), - /* K12 */ be_nested_str_weak(MAX_PACKETS_READ), - /* K13 */ be_nested_str_weak(resend_packets), - }), - be_str_weak(every_50ms), - &be_const_str_solidified, - ( &(const binstruction[47]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x58080001, // 0001 LDCONST R2 K1 - 0x880C0102, // 0002 GETMBR R3 R0 K2 - 0x4C100000, // 0003 LDNIL R4 - 0x1C0C0604, // 0004 EQ R3 R3 R4 - 0x780E0000, // 0005 JMPF R3 #0007 - 0x80000600, // 0006 RET 0 - 0x880C0102, // 0007 GETMBR R3 R0 K2 - 0x8C0C0703, // 0008 GETMET R3 R3 K3 - 0x7C0C0200, // 0009 CALL R3 1 - 0x4C100000, // 000A LDNIL R4 - 0x20100604, // 000B NE R4 R3 R4 - 0x7812001E, // 000C JMPF R4 #002C - 0x00080504, // 000D ADD R2 R2 K4 - 0x88100102, // 000E GETMBR R4 R0 K2 - 0x88100905, // 000F GETMBR R4 R4 K5 - 0x88140102, // 0010 GETMBR R5 R0 K2 - 0x88140B06, // 0011 GETMBR R5 R5 K6 - 0xB81A0E00, // 0012 GETNGBL R6 K7 - 0x8C180D08, // 0013 GETMET R6 R6 K8 - 0x8C200309, // 0014 GETMET R8 R1 K9 - 0x5828000A, // 0015 LDCONST R10 K10 - 0x5C2C0800, // 0016 MOVE R11 R4 - 0x5C300A00, // 0017 MOVE R12 R5 - 0x7C200800, // 0018 CALL R8 4 - 0x54260003, // 0019 LDINT R9 4 - 0x7C180600, // 001A CALL R6 3 - 0x8818010B, // 001B GETMBR R6 R0 K11 - 0x781A0004, // 001C JMPF R6 #0022 - 0x8C18010B, // 001D GETMET R6 R0 K11 - 0x5C200600, // 001E MOVE R8 R3 - 0x5C240800, // 001F MOVE R9 R4 - 0x5C280A00, // 0020 MOVE R10 R5 - 0x7C180800, // 0021 CALL R6 4 - 0x8818010C, // 0022 GETMBR R6 R0 K12 - 0x14180406, // 0023 LT R6 R2 R6 - 0x781A0004, // 0024 JMPF R6 #002A - 0x88180102, // 0025 GETMBR R6 R0 K2 - 0x8C180D03, // 0026 GETMET R6 R6 K3 - 0x7C180200, // 0027 CALL R6 1 - 0x5C0C0C00, // 0028 MOVE R3 R6 - 0x70020000, // 0029 JMP #002B - 0x4C0C0000, // 002A LDNIL R3 - 0x7001FFDD, // 002B JMP #000A - 0x8C10010D, // 002C GETMET R4 R0 K13 - 0x7C100200, // 002D CALL R4 1 - 0x80000000, // 002E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: resend_packets -********************************************************************/ -be_local_closure(Matter_UDPServer_resend_packets, /* 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[17]) { /* constants */ - /* K0 */ be_nested_str_weak(packets_sent), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(time_reached), - /* K3 */ be_nested_str_weak(next_try), - /* K4 */ be_nested_str_weak(log), - /* K5 */ be_nested_str_weak(MTR_X3A_X20resending_X20packet_X20id_X3D), - /* K6 */ be_nested_str_weak(msg_id), - /* K7 */ be_const_int(3), - /* K8 */ be_nested_str_weak(send), - /* K9 */ be_nested_str_weak(udp_socket), - /* K10 */ be_nested_str_weak(retries), - /* K11 */ be_const_int(1), - /* K12 */ be_const_int(0), - /* K13 */ be_nested_str_weak(remove), - /* K14 */ be_nested_str_weak(millis), - /* K15 */ be_nested_str_weak(RETRY_MS), - /* K16 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(resend_packets), - &be_const_str_solidified, - ( &(const binstruction[44]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x7C040200, // 0002 CALL R1 1 - 0xA8020023, // 0003 EXBLK 0 #0028 - 0x5C080200, // 0004 MOVE R2 R1 - 0x7C080000, // 0005 CALL R2 0 - 0xB80E0200, // 0006 GETNGBL R3 K1 - 0x8C0C0702, // 0007 GETMET R3 R3 K2 - 0x88140503, // 0008 GETMBR R5 R2 K3 - 0x7C0C0400, // 0009 CALL R3 2 - 0x780E001B, // 000A JMPF R3 #0027 - 0xB80E0200, // 000B GETNGBL R3 K1 - 0x8C0C0704, // 000C GETMET R3 R3 K4 - 0x60140008, // 000D GETGBL R5 G8 - 0x88180506, // 000E GETMBR R6 R2 K6 - 0x7C140200, // 000F CALL R5 1 - 0x00160A05, // 0010 ADD R5 K5 R5 - 0x58180007, // 0011 LDCONST R6 K7 - 0x7C0C0600, // 0012 CALL R3 3 - 0x8C0C0508, // 0013 GETMET R3 R2 K8 - 0x88140109, // 0014 GETMBR R5 R0 K9 - 0x7C0C0400, // 0015 CALL R3 2 - 0x880C050A, // 0016 GETMBR R3 R2 K10 - 0x040C070B, // 0017 SUB R3 R3 K11 - 0x900A1403, // 0018 SETMBR R2 K10 R3 - 0x880C050A, // 0019 GETMBR R3 R2 K10 - 0x180C070C, // 001A LE R3 R3 K12 - 0x780E0004, // 001B JMPF R3 #0021 - 0x880C0100, // 001C GETMBR R3 R0 K0 - 0x8C0C070D, // 001D GETMET R3 R3 K13 - 0x88140506, // 001E GETMBR R5 R2 K6 - 0x7C0C0400, // 001F CALL R3 2 - 0x70020005, // 0020 JMP #0027 - 0xB80E0200, // 0021 GETNGBL R3 K1 - 0x8C0C070E, // 0022 GETMET R3 R3 K14 - 0x7C0C0200, // 0023 CALL R3 1 - 0x8810050F, // 0024 GETMBR R4 R2 K15 - 0x000C0604, // 0025 ADD R3 R3 R4 - 0x900A0603, // 0026 SETMBR R2 K3 R3 - 0x7001FFDB, // 0027 JMP #0004 - 0x58040010, // 0028 LDCONST R1 K16 - 0xAC040200, // 0029 CATCH R1 1 0 - 0xB0080000, // 002A RAISE 2 R0 R0 - 0x80000000, // 002B RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: start ********************************************************************/ @@ -455,7 +527,7 @@ be_local_closure(Matter_UDPServer_start, /* name */ /* K1 */ be_nested_str_weak(udp_socket), /* K2 */ be_nested_str_weak(udp), /* K3 */ be_nested_str_weak(begin), - /* K4 */ be_nested_str_weak(address), + /* K4 */ be_nested_str_weak(addr), /* K5 */ be_nested_str_weak(port), /* K6 */ be_nested_str_weak(network_error), /* K7 */ be_nested_str_weak(could_X20not_X20open_X20UDP_X20server), @@ -494,54 +566,11 @@ be_local_closure(Matter_UDPServer_start, /* name */ /******************************************************************** -** Solidified function: send_response +** Solidified function: received_ack ********************************************************************/ -be_local_closure(Matter_UDPServer_send_response, /* name */ +be_local_closure(Matter_UDPServer_received_ack, /* name */ be_nested_proto( - 11, /* nstack */ - 5, /* 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(matter), - /* K1 */ be_nested_str_weak(UDPPacket_sent), - /* K2 */ be_nested_str_weak(send), - /* K3 */ be_nested_str_weak(udp_socket), - /* K4 */ be_nested_str_weak(packets_sent), - }), - be_str_weak(send_response), - &be_const_str_solidified, - ( &(const binstruction[14]) { /* code */ - 0xB8160000, // 0000 GETNGBL R5 K0 - 0x8C140B01, // 0001 GETMET R5 R5 K1 - 0x5C1C0200, // 0002 MOVE R7 R1 - 0x5C200400, // 0003 MOVE R8 R2 - 0x5C240600, // 0004 MOVE R9 R3 - 0x5C280800, // 0005 MOVE R10 R4 - 0x7C140A00, // 0006 CALL R5 5 - 0x8C180B02, // 0007 GETMET R6 R5 K2 - 0x88200103, // 0008 GETMBR R8 R0 K3 - 0x7C180400, // 0009 CALL R6 2 - 0x78120001, // 000A JMPF R4 #000D - 0x88180104, // 000B GETMBR R6 R0 K4 - 0x98180805, // 000C SETIDX R6 R4 R5 - 0x80000000, // 000D RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: packet_ack -********************************************************************/ -be_local_closure(Matter_UDPServer_packet_ack, /* name */ - be_nested_proto( - 6, /* nstack */ + 10, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -549,40 +578,188 @@ be_local_closure(Matter_UDPServer_packet_ack, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str_weak(packets_sent), - /* K1 */ be_nested_str_weak(contains), - /* K2 */ be_nested_str_weak(remove), - /* K3 */ be_nested_str_weak(tasmota), - /* K4 */ be_nested_str_weak(log), - /* K5 */ be_nested_str_weak(MTR_X3A_X20removed_X20packet_X20from_X20sending_X20list_X20id_X3D), - /* K6 */ be_const_int(3), + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(ack_message_counter), + /* K1 */ be_nested_str_weak(exchange_id), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(MTR_X3A_X20receveived_X20ACK_X20id_X3D), + /* K5 */ be_const_int(3), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(packets_sent), + /* K8 */ be_nested_str_weak(msg_id), + /* K9 */ be_nested_str_weak(remove), + /* K10 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Removed_X20packet_X20from_X20sending_X20list_X20id_X3D), + /* K11 */ be_const_int(1), }), - be_str_weak(packet_ack), + be_str_weak(received_ack), &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0000, // 0002 JMPF R2 #0004 - 0x80000400, // 0003 RET 0 - 0x88080100, // 0004 GETMBR R2 R0 K0 - 0x8C080501, // 0005 GETMET R2 R2 K1 - 0x5C100200, // 0006 MOVE R4 R1 - 0x7C080400, // 0007 CALL R2 2 - 0x780A000B, // 0008 JMPF R2 #0015 - 0x88080100, // 0009 GETMBR R2 R0 K0 - 0x8C080502, // 000A GETMET R2 R2 K2 - 0x5C100200, // 000B MOVE R4 R1 - 0x7C080400, // 000C CALL R2 2 - 0xB80A0600, // 000D GETNGBL R2 K3 - 0x8C080504, // 000E GETMET R2 R2 K4 - 0x60100008, // 000F GETGBL R4 G8 - 0x5C140200, // 0010 MOVE R5 R1 - 0x7C100200, // 0011 CALL R4 1 - 0x00120A04, // 0012 ADD R4 K5 R4 - 0x58140006, // 0013 LDCONST R5 K6 - 0x7C080600, // 0014 CALL R2 3 - 0x80000000, // 0015 RET 0 + ( &(const binstruction[44]) { /* code */ + 0x88080300, // 0000 GETMBR R2 R1 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x4C100000, // 0002 LDNIL R4 + 0x1C100404, // 0003 EQ R4 R2 R4 + 0x78120000, // 0004 JMPF R4 #0006 + 0x80000800, // 0005 RET 0 + 0xB8120400, // 0006 GETNGBL R4 K2 + 0x8C100903, // 0007 GETMET R4 R4 K3 + 0x60180008, // 0008 GETGBL R6 G8 + 0x5C1C0400, // 0009 MOVE R7 R2 + 0x7C180200, // 000A CALL R6 1 + 0x001A0806, // 000B ADD R6 K4 R6 + 0x581C0005, // 000C LDCONST R7 K5 + 0x7C100600, // 000D CALL R4 3 + 0x58100006, // 000E LDCONST R4 K6 + 0x6014000C, // 000F GETGBL R5 G12 + 0x88180107, // 0010 GETMBR R6 R0 K7 + 0x7C140200, // 0011 CALL R5 1 + 0x14140805, // 0012 LT R5 R4 R5 + 0x78160016, // 0013 JMPF R5 #002B + 0x88140107, // 0014 GETMBR R5 R0 K7 + 0x94140A04, // 0015 GETIDX R5 R5 R4 + 0x88180B08, // 0016 GETMBR R6 R5 K8 + 0x1C180C02, // 0017 EQ R6 R6 R2 + 0x781A000F, // 0018 JMPF R6 #0029 + 0x88180B01, // 0019 GETMBR R6 R5 K1 + 0x1C180C03, // 001A EQ R6 R6 R3 + 0x781A000C, // 001B JMPF R6 #0029 + 0x88180107, // 001C GETMBR R6 R0 K7 + 0x8C180D09, // 001D GETMET R6 R6 K9 + 0x5C200800, // 001E MOVE R8 R4 + 0x7C180400, // 001F CALL R6 2 + 0xB81A0400, // 0020 GETNGBL R6 K2 + 0x8C180D03, // 0021 GETMET R6 R6 K3 + 0x60200008, // 0022 GETGBL R8 G8 + 0x5C240400, // 0023 MOVE R9 R2 + 0x7C200200, // 0024 CALL R8 1 + 0x00221408, // 0025 ADD R8 K10 R8 + 0x58240005, // 0026 LDCONST R9 K5 + 0x7C180600, // 0027 CALL R6 3 + 0x70020000, // 0028 JMP #002A + 0x0010090B, // 0029 ADD R4 R4 K11 + 0x7001FFE3, // 002A JMP #000F + 0x80000000, // 002B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_UDPServer_init, /* name */ + be_nested_proto( + 4, /* 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_weak(addr), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(port), + /* K3 */ be_nested_str_weak(listening), + /* K4 */ be_nested_str_weak(packets_sent), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x78060001, // 0000 JMPF R1 #0003 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x70020000, // 0002 JMP #0004 + 0x580C0001, // 0003 LDCONST R3 K1 + 0x90020003, // 0004 SETMBR R0 K0 R3 + 0x780A0001, // 0005 JMPF R2 #0008 + 0x5C0C0400, // 0006 MOVE R3 R2 + 0x70020000, // 0007 JMP #0009 + 0x540E15A3, // 0008 LDINT R3 5540 + 0x90020403, // 0009 SETMBR R0 K2 R3 + 0x500C0000, // 000A LDBOOL R3 0 0 + 0x90020603, // 000B SETMBR R0 K3 R3 + 0x600C0012, // 000C GETGBL R3 G18 + 0x7C0C0000, // 000D CALL R3 0 + 0x90020803, // 000E SETMBR R0 K4 R3 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: send +********************************************************************/ +be_local_closure(Matter_UDPServer_send, /* 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[14]) { /* constants */ + /* K0 */ be_nested_str_weak(string), + /* K1 */ be_nested_str_weak(udp_socket), + /* K2 */ be_nested_str_weak(send), + /* K3 */ be_nested_str_weak(addr), + /* K4 */ be_nested_str_weak(remote_ip), + /* K5 */ be_nested_str_weak(port), + /* K6 */ be_nested_str_weak(remote_port), + /* K7 */ be_nested_str_weak(raw), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(format), + /* K11 */ be_nested_str_weak(MTR_X3A_X20sending_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), + /* K12 */ be_nested_str_weak(MTR_X3A_X20error_X20sending_X20packet_X20to_X20_X27_X5B_X25s_X5D_X3A_X25i_X27), + /* K13 */ be_const_int(2), + }), + be_str_weak(send), + &be_const_str_solidified, + ( &(const binstruction[38]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x88140303, // 0003 GETMBR R5 R1 K3 + 0x78160001, // 0004 JMPF R5 #0007 + 0x88140303, // 0005 GETMBR R5 R1 K3 + 0x70020001, // 0006 JMP #0009 + 0x88140101, // 0007 GETMBR R5 R0 K1 + 0x88140B04, // 0008 GETMBR R5 R5 K4 + 0x88180305, // 0009 GETMBR R6 R1 K5 + 0x781A0001, // 000A JMPF R6 #000D + 0x88180305, // 000B GETMBR R6 R1 K5 + 0x70020001, // 000C JMP #000F + 0x88180101, // 000D GETMBR R6 R0 K1 + 0x88180D06, // 000E GETMBR R6 R6 K6 + 0x881C0307, // 000F GETMBR R7 R1 K7 + 0x7C0C0800, // 0010 CALL R3 4 + 0x780E0009, // 0011 JMPF R3 #001C + 0xB8121000, // 0012 GETNGBL R4 K8 + 0x8C100909, // 0013 GETMET R4 R4 K9 + 0x8C18050A, // 0014 GETMET R6 R2 K10 + 0x5820000B, // 0015 LDCONST R8 K11 + 0x88240303, // 0016 GETMBR R9 R1 K3 + 0x88280305, // 0017 GETMBR R10 R1 K5 + 0x7C180800, // 0018 CALL R6 4 + 0x541E0003, // 0019 LDINT R7 4 + 0x7C100600, // 001A CALL R4 3 + 0x70020008, // 001B JMP #0025 + 0xB8121000, // 001C GETNGBL R4 K8 + 0x8C100909, // 001D GETMET R4 R4 K9 + 0x8C18050A, // 001E GETMET R6 R2 K10 + 0x5820000C, // 001F LDCONST R8 K12 + 0x88240303, // 0020 GETMBR R9 R1 K3 + 0x88280305, // 0021 GETMBR R10 R1 K5 + 0x7C180800, // 0022 CALL R6 4 + 0x581C000D, // 0023 LDCONST R7 K13 + 0x7C100600, // 0024 CALL R4 3 + 0x80040600, // 0025 RET 1 R3 }) ) ); @@ -595,23 +772,26 @@ be_local_closure(Matter_UDPServer_packet_ack, /* name */ be_local_class(Matter_UDPServer, 6, NULL, - be_nested_map(15, + be_nested_map(18, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(init, 1), be_const_closure(Matter_UDPServer_init_closure) }, - { be_const_key_weak(every_second, -1), be_const_closure(Matter_UDPServer_every_second_closure) }, - { be_const_key_weak(stop, -1), be_const_closure(Matter_UDPServer_stop_closure) }, - { be_const_key_weak(udp_socket, -1), be_const_var(3) }, - { be_const_key_weak(address, -1), be_const_var(0) }, - { be_const_key_weak(dispatch_cb, -1), be_const_var(4) }, - { be_const_key_weak(packet_ack, 7), be_const_closure(Matter_UDPServer_packet_ack_closure) }, - { be_const_key_weak(MAX_PACKETS_READ, 13), be_const_int(4) }, - { be_const_key_weak(every_50ms, 6), be_const_closure(Matter_UDPServer_every_50ms_closure) }, - { be_const_key_weak(listening, -1), be_const_var(2) }, - { be_const_key_weak(port, -1), be_const_var(1) }, - { be_const_key_weak(start, -1), be_const_closure(Matter_UDPServer_start_closure) }, - { be_const_key_weak(send_response, -1), be_const_closure(Matter_UDPServer_send_response_closure) }, - { be_const_key_weak(resend_packets, -1), be_const_closure(Matter_UDPServer_resend_packets_closure) }, + { be_const_key_weak(_backoff_time, 17), be_const_static_closure(Matter_UDPServer__backoff_time_closure) }, { be_const_key_weak(packets_sent, -1), be_const_var(5) }, + { be_const_key_weak(addr, -1), be_const_var(0) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_UDPServer_every_second_closure) }, + { be_const_key_weak(port, -1), be_const_var(1) }, + { be_const_key_weak(dispatch_cb, 1), be_const_var(4) }, + { be_const_key_weak(udp_socket, -1), be_const_var(3) }, + { be_const_key_weak(send_UDP, -1), be_const_closure(Matter_UDPServer_send_UDP_closure) }, + { be_const_key_weak(every_50ms, -1), be_const_closure(Matter_UDPServer_every_50ms_closure) }, + { be_const_key_weak(send, 10), be_const_closure(Matter_UDPServer_send_closure) }, + { be_const_key_weak(RETRIES, -1), be_const_int(5) }, + { be_const_key_weak(stop, 16), be_const_closure(Matter_UDPServer_stop_closure) }, + { be_const_key_weak(received_ack, -1), be_const_closure(Matter_UDPServer_received_ack_closure) }, + { be_const_key_weak(_resend_packets, 9), be_const_closure(Matter_UDPServer__resend_packets_closure) }, + { be_const_key_weak(MAX_PACKETS_READ, -1), be_const_int(4) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_UDPServer_init_closure) }, + { be_const_key_weak(start, -1), be_const_closure(Matter_UDPServer_start_closure) }, + { be_const_key_weak(listening, -1), be_const_var(2) }, })), be_str_weak(Matter_UDPServer) ); 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 0eaee343f..350e3a387 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h @@ -7,11 +7,167 @@ extern const bclass be_class_Matter_UI; /******************************************************************** -** Solidified function: show_commissioning_info +** Solidified function: show_fabric_info ********************************************************************/ -be_local_closure(Matter_UI_show_commissioning_info, /* name */ +be_local_closure(Matter_UI_show_fabric_info, /* name */ be_nested_proto( - 12, /* nstack */ + 17, /* nstack */ + 2, /* 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(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(content_send), + /* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BFabrics_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K4 */ be_nested_str_weak(_X3Cp_X3EExisting_X20fabrics_X3A_X3C_X2Fp_X3E), + /* K5 */ be_nested_str_weak(device), + /* K6 */ be_nested_str_weak(sessions), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(_X3Cp_X3E_X3Cb_X3ENone_X3C_X2Fb_X3E_X3C_X2Fp_X3E), + /* K9 */ be_nested_str_weak(fabrics), + /* K10 */ be_nested_str_weak(persistables), + /* K11 */ be_nested_str_weak(_X3Chr_X3E), + /* K12 */ be_nested_str_weak(fabric_label), + /* K13 */ be_nested_str_weak(_X3CNo_X20label_X3E), + /* K14 */ be_nested_str_weak(html_escape), + /* K15 */ be_nested_str_weak(format), + /* K16 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3B_X23_X25i_X20_X25s_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K17 */ be_nested_str_weak(get_fabric_index), + /* K18 */ be_nested_str_weak(get_fabric_id), + /* K19 */ be_nested_str_weak(copy), + /* K20 */ be_nested_str_weak(reverse), + /* K21 */ be_nested_str_weak(get_device_id), + /* K22 */ be_nested_str_weak(Fabric_X3A_X20_X25s_X3Cbr_X3E), + /* K23 */ be_nested_str_weak(tohex), + /* K24 */ be_nested_str_weak(Device_X3A_X20_X25s_X3Cbr_X3E_X26nbsp_X3B), + /* K25 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X3E), + /* K26 */ be_nested_str_weak(_X3Cinput_X20name_X3D_X27del_fabric_X27_X20type_X3D_X27hidden_X27_X20value_X3D_X27_X25i_X27_X3E), + /* K27 */ be_nested_str_weak(_X3Cbutton_X20name_X3D_X27del_X27_X20class_X3D_X27button_X20bgrn_X27_X3EDelete_X20Fabric_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + /* K28 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K29 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(show_fabric_info), + &be_const_str_solidified, + ( &(const binstruction[102]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100502, // 0002 GETMET R4 R2 K2 + 0x58180003, // 0003 LDCONST R6 K3 + 0x7C100400, // 0004 CALL R4 2 + 0x8C100502, // 0005 GETMET R4 R2 K2 + 0x58180004, // 0006 LDCONST R6 K4 + 0x7C100400, // 0007 CALL R4 2 + 0x6010000C, // 0008 GETGBL R4 G12 + 0x88140105, // 0009 GETMBR R5 R0 K5 + 0x88140B06, // 000A GETMBR R5 R5 K6 + 0x88140B06, // 000B GETMBR R5 R5 K6 + 0x7C100200, // 000C CALL R4 1 + 0x1C100907, // 000D EQ R4 R4 K7 + 0x78120003, // 000E JMPF R4 #0013 + 0x8C100502, // 000F GETMET R4 R2 K2 + 0x58180008, // 0010 LDCONST R6 K8 + 0x7C100400, // 0011 CALL R4 2 + 0x7002004E, // 0012 JMP #0062 + 0x50100200, // 0013 LDBOOL R4 1 0 + 0x60140010, // 0014 GETGBL R5 G16 + 0x88180105, // 0015 GETMBR R6 R0 K5 + 0x88180D06, // 0016 GETMBR R6 R6 K6 + 0x88180D09, // 0017 GETMBR R6 R6 K9 + 0x8C180D0A, // 0018 GETMET R6 R6 K10 + 0x7C180200, // 0019 CALL R6 1 + 0x7C140200, // 001A CALL R5 1 + 0xA8020042, // 001B EXBLK 0 #005F + 0x5C180A00, // 001C MOVE R6 R5 + 0x7C180000, // 001D CALL R6 0 + 0x5C1C0800, // 001E MOVE R7 R4 + 0x741E0002, // 001F JMPT R7 #0023 + 0x8C1C0502, // 0020 GETMET R7 R2 K2 + 0x5824000B, // 0021 LDCONST R9 K11 + 0x7C1C0400, // 0022 CALL R7 2 + 0x50100000, // 0023 LDBOOL R4 0 0 + 0x881C0D0C, // 0024 GETMBR R7 R6 K12 + 0x5C200E00, // 0025 MOVE R8 R7 + 0x74220000, // 0026 JMPT R8 #0028 + 0x581C000D, // 0027 LDCONST R7 K13 + 0x8C20050E, // 0028 GETMET R8 R2 K14 + 0x5C280E00, // 0029 MOVE R10 R7 + 0x7C200400, // 002A CALL R8 2 + 0x5C1C1000, // 002B MOVE R7 R8 + 0x8C200502, // 002C GETMET R8 R2 K2 + 0x8C28070F, // 002D GETMET R10 R3 K15 + 0x58300010, // 002E LDCONST R12 K16 + 0x8C340D11, // 002F GETMET R13 R6 K17 + 0x7C340200, // 0030 CALL R13 1 + 0x5C380E00, // 0031 MOVE R14 R7 + 0x7C280800, // 0032 CALL R10 4 + 0x7C200400, // 0033 CALL R8 2 + 0x8C200D12, // 0034 GETMET R8 R6 K18 + 0x7C200200, // 0035 CALL R8 1 + 0x8C201113, // 0036 GETMET R8 R8 K19 + 0x7C200200, // 0037 CALL R8 1 + 0x8C201114, // 0038 GETMET R8 R8 K20 + 0x7C200200, // 0039 CALL R8 1 + 0x8C240D15, // 003A GETMET R9 R6 K21 + 0x7C240200, // 003B CALL R9 1 + 0x8C241313, // 003C GETMET R9 R9 K19 + 0x7C240200, // 003D CALL R9 1 + 0x8C241314, // 003E GETMET R9 R9 K20 + 0x7C240200, // 003F CALL R9 1 + 0x8C280502, // 0040 GETMET R10 R2 K2 + 0x8C30070F, // 0041 GETMET R12 R3 K15 + 0x58380016, // 0042 LDCONST R14 K22 + 0x8C3C1117, // 0043 GETMET R15 R8 K23 + 0x7C3C0200, // 0044 CALL R15 1 + 0x7C300600, // 0045 CALL R12 3 + 0x7C280400, // 0046 CALL R10 2 + 0x8C280502, // 0047 GETMET R10 R2 K2 + 0x8C30070F, // 0048 GETMET R12 R3 K15 + 0x58380018, // 0049 LDCONST R14 K24 + 0x8C3C1317, // 004A GETMET R15 R9 K23 + 0x7C3C0200, // 004B CALL R15 1 + 0x7C300600, // 004C CALL R12 3 + 0x7C280400, // 004D CALL R10 2 + 0x8C280502, // 004E GETMET R10 R2 K2 + 0x58300019, // 004F LDCONST R12 K25 + 0x7C280400, // 0050 CALL R10 2 + 0x8C280502, // 0051 GETMET R10 R2 K2 + 0x8C30070F, // 0052 GETMET R12 R3 K15 + 0x5838001A, // 0053 LDCONST R14 K26 + 0x8C3C0D11, // 0054 GETMET R15 R6 K17 + 0x7C3C0200, // 0055 CALL R15 1 + 0x7C300600, // 0056 CALL R12 3 + 0x7C280400, // 0057 CALL R10 2 + 0x8C280502, // 0058 GETMET R10 R2 K2 + 0x5830001B, // 0059 LDCONST R12 K27 + 0x7C280400, // 005A CALL R10 2 + 0x8C280502, // 005B GETMET R10 R2 K2 + 0x5830001C, // 005C LDCONST R12 K28 + 0x7C280400, // 005D CALL R10 2 + 0x7001FFBC, // 005E JMP #001C + 0x5814001D, // 005F LDCONST R5 K29 + 0xAC140200, // 0060 CATCH R5 1 0 + 0xB0080000, // 0061 RAISE 2 R0 R0 + 0x8C100502, // 0062 GETMET R4 R2 K2 + 0x5818001C, // 0063 LDCONST R6 K28 + 0x7C100400, // 0064 CALL R4 2 + 0x80000000, // 0065 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_sensor +********************************************************************/ +be_local_closure(Matter_UI_web_sensor, /* name */ + be_nested_proto( + 13, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,105 +175,292 @@ be_local_closure(Matter_UI_show_commissioning_info, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[24]) { /* constants */ + ( &(const bvalue[25]) { /* constants */ /* K0 */ be_nested_str_weak(webserver), /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(content_send), - /* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BMatter_X20Passcode_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), - /* K4 */ be_nested_str_weak(device), - /* K5 */ be_nested_str_weak(compute_manual_pairing_code), - /* K6 */ be_nested_str_weak(format), - /* K7 */ be_nested_str_weak(_X3Cp_X3EManual_X20pairing_X20code_X3A_X3Cbr_X3E_X3Cb_X3E_X25s_X2D_X25s_X2D_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E_X3Chr_X3E), - /* K8 */ be_const_int(0), - /* K9 */ be_const_int(3), - /* K10 */ be_const_int(2147483647), - /* K11 */ be_nested_str_weak(compute_qrcode_content), - /* K12 */ be_nested_str_weak(_X3Cdiv_X20id_X3D_X22qrcode_X22_X3E_X3C_X2Fdiv_X3E), - /* K13 */ be_nested_str_weak(_X3Cscript_X20type_X3D_X22text_X2Fjavascript_X22_X3E_X20new_X20QRCode_X28document_X2EgetElementById_X28_X22qrcode_X22_X29_X2C_X20_X22_X25s_X22_X29_X3B_X3C_X2Fscript_X3E), - /* K14 */ be_nested_str_weak(_X3Cp_X3E_X25s_X3C_X2Fp_X3E_X3Chr_X3E), - /* K15 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20_X3E), - /* K16 */ be_nested_str_weak(_X3Cp_X3EPasscode_X3A_X3C_X2Fp_X3E), - /* K17 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X271_X27_X20max_X3D_X2799999998_X27_X20name_X3D_X27passcode_X27_X20value_X3D_X27_X25i_X27_X3E), - /* K18 */ be_nested_str_weak(passcode), - /* K19 */ be_nested_str_weak(_X3Cp_X3EDistinguish_X20id_X3A_X3C_X2Fp_X3E), - /* K20 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X270_X27_X20max_X3D_X272047_X27_X20name_X3D_X27discriminator_X27_X20value_X3D_X27_X25i_X27_X3E), - /* K21 */ be_nested_str_weak(discriminator), - /* K22 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3Cbutton_X20name_X3D_X27passcode_X27_X20class_X3D_X27button_X20bgrn_X27_X3EChange_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), - /* K23 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(get_option), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(MATTER_OPTION), + /* K6 */ be_nested_str_weak(device), + /* K7 */ be_nested_str_weak(is_root_commissioning_open), + /* K8 */ be_nested_str_weak(show_commissioning_info), + /* K9 */ be_nested_str_weak(sessions), + /* K10 */ be_nested_str_weak(count_active_fabrics), + /* K11 */ be_const_int(0), + /* K12 */ be_nested_str_weak(content_send), + /* K13 */ be_nested_str_weak(format), + /* K14 */ be_nested_str_weak(_X3Cdiv_X20style_X3D_X27text_X2Dalign_X3Aright_X3Bfont_X2Dsize_X3A11px_X3Bcolor_X3A_X23aaa_X3B_X27_X3E_X25s_X3C_X2Fdiv_X3E), + /* K15 */ be_nested_str_weak(No_X20active_X20association), + /* K16 */ be_const_int(1), + /* K17 */ be_nested_str_weak(_X20active_X20association), + /* K18 */ be_nested_str_weak(s), + /* K19 */ be_nested_str_weak(), + /* K20 */ be_nested_str_weak(_X3Cbutton_X20onclick_X3D_X27la_X28_X22_X26mtc_X25i_X3D1_X22_X29_X3B_X27_X3E), + /* K21 */ be_nested_str_weak(commissioning_open), + /* K22 */ be_nested_str_weak(_LOGO), + /* K23 */ be_nested_str_weak(_X20Open_X20Commissioning_X3C_X2Fbutton_X3E), + /* K24 */ be_nested_str_weak(_X20Close_X20Commissioning_X3C_X2Fbutton_X3E), }), - be_str_weak(show_commissioning_info), + be_str_weak(web_sensor), &be_const_str_solidified, - ( &(const binstruction[70]) { /* code */ + ( &(const binstruction[72]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x8C0C0703, // 0003 GETMET R3 R3 K3 + 0xB8160800, // 0004 GETNGBL R5 K4 + 0x88140B05, // 0005 GETMBR R5 R5 K5 + 0x7C0C0400, // 0006 CALL R3 2 + 0x780E003E, // 0007 JMPF R3 #0047 + 0x88100106, // 0008 GETMBR R4 R0 K6 + 0x8C100907, // 0009 GETMET R4 R4 K7 + 0x7C100200, // 000A CALL R4 1 + 0x78120001, // 000B JMPF R4 #000E + 0x8C100108, // 000C GETMET R4 R0 K8 + 0x7C100200, // 000D CALL R4 1 + 0x88100106, // 000E GETMBR R4 R0 K6 + 0x88100909, // 000F GETMBR R4 R4 K9 + 0x8C10090A, // 0010 GETMET R4 R4 K10 + 0x7C100200, // 0011 CALL R4 1 + 0x1C14090B, // 0012 EQ R5 R4 K11 + 0x78160006, // 0013 JMPF R5 #001B + 0x8C14030C, // 0014 GETMET R5 R1 K12 + 0x8C1C050D, // 0015 GETMET R7 R2 K13 + 0x5824000E, // 0016 LDCONST R9 K14 + 0x5828000F, // 0017 LDCONST R10 K15 + 0x7C1C0600, // 0018 CALL R7 3 + 0x7C140400, // 0019 CALL R5 2 + 0x7002000E, // 001A JMP #002A + 0x24140910, // 001B GT R5 R4 K16 + 0x8C18030C, // 001C GETMET R6 R1 K12 + 0x8C20050D, // 001D GETMET R8 R2 K13 + 0x5828000E, // 001E LDCONST R10 K14 + 0x602C0008, // 001F GETGBL R11 G8 + 0x5C300800, // 0020 MOVE R12 R4 + 0x7C2C0200, // 0021 CALL R11 1 + 0x002C1711, // 0022 ADD R11 R11 K17 + 0x78160001, // 0023 JMPF R5 #0026 + 0x58300012, // 0024 LDCONST R12 K18 + 0x70020000, // 0025 JMP #0027 + 0x58300013, // 0026 LDCONST R12 K19 + 0x002C160C, // 0027 ADD R11 R11 R12 + 0x7C200600, // 0028 CALL R8 3 + 0x7C180400, // 0029 CALL R6 2 + 0x8C14030C, // 002A GETMET R5 R1 K12 + 0x8C1C050D, // 002B GETMET R7 R2 K13 + 0x58240014, // 002C LDCONST R9 K20 + 0x88280106, // 002D GETMBR R10 R0 K6 + 0x88281515, // 002E GETMBR R10 R10 K21 + 0x4C2C0000, // 002F LDNIL R11 + 0x1C28140B, // 0030 EQ R10 R10 R11 + 0x782A0001, // 0031 JMPF R10 #0034 + 0x58280010, // 0032 LDCONST R10 K16 + 0x70020000, // 0033 JMP #0035 + 0x5828000B, // 0034 LDCONST R10 K11 + 0x7C1C0600, // 0035 CALL R7 3 + 0x7C140400, // 0036 CALL R5 2 + 0x8C14030C, // 0037 GETMET R5 R1 K12 + 0xB81E0800, // 0038 GETNGBL R7 K4 + 0x881C0F16, // 0039 GETMBR R7 R7 K22 + 0x7C140400, // 003A CALL R5 2 + 0x88140106, // 003B GETMBR R5 R0 K6 + 0x88140B15, // 003C GETMBR R5 R5 K21 + 0x4C180000, // 003D LDNIL R6 + 0x1C140A06, // 003E EQ R5 R5 R6 + 0x78160003, // 003F JMPF R5 #0044 + 0x8C14030C, // 0040 GETMET R5 R1 K12 + 0x581C0017, // 0041 LDCONST R7 K23 + 0x7C140400, // 0042 CALL R5 2 + 0x70020002, // 0043 JMP #0047 + 0x8C14030C, // 0044 GETMET R5 R1 K12 + 0x581C0018, // 0045 LDCONST R7 K24 + 0x7C140400, // 0046 CALL R5 2 + 0x80000000, // 0047 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_get_arg +********************************************************************/ +be_local_closure(Matter_UI_web_get_arg, /* 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[ 7]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(has_arg), + /* K2 */ be_nested_str_weak(mtc0), + /* K3 */ be_nested_str_weak(device), + /* K4 */ be_nested_str_weak(stop_basic_commissioning), + /* K5 */ be_nested_str_weak(mtc1), + /* K6 */ be_nested_str_weak(start_root_basic_commissioning), + }), + be_str_weak(web_get_arg), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x7C080400, // 0003 CALL R2 2 + 0x780A0003, // 0004 JMPF R2 #0009 + 0x88080103, // 0005 GETMBR R2 R0 K3 + 0x8C080504, // 0006 GETMET R2 R2 K4 + 0x7C080200, // 0007 CALL R2 1 + 0x70020006, // 0008 JMP #0010 + 0x8C080301, // 0009 GETMET R2 R1 K1 + 0x58100005, // 000A LDCONST R4 K5 + 0x7C080400, // 000B CALL R2 2 + 0x780A0002, // 000C JMPF R2 #0010 + 0x88080103, // 000D GETMBR R2 R0 K3 + 0x8C080506, // 000E GETMET R2 R2 K6 + 0x7C080200, // 000F CALL R2 1 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: page_part_mgr +********************************************************************/ +be_local_closure(Matter_UI_page_part_mgr, /* 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[12]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(check_privileged_access), + /* K3 */ be_nested_str_weak(content_start), + /* K4 */ be_nested_str_weak(Matter), + /* K5 */ be_nested_str_weak(content_send_style), + /* K6 */ be_nested_str_weak(show_enable), + /* K7 */ be_nested_str_weak(show_passcode_form), + /* K8 */ be_nested_str_weak(show_fabric_info), + /* K9 */ be_nested_str_weak(content_button), + /* K10 */ be_nested_str_weak(BUTTON_CONFIGURATION), + /* K11 */ be_nested_str_weak(content_stop), + }), + be_str_weak(page_part_mgr), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0xA40A0200, // 0001 IMPORT R2 K1 0x8C0C0302, // 0002 GETMET R3 R1 K2 - 0x58140003, // 0003 LDCONST R5 K3 - 0x7C0C0400, // 0004 CALL R3 2 - 0x880C0104, // 0005 GETMBR R3 R0 K4 - 0x8C0C0705, // 0006 GETMET R3 R3 K5 - 0x7C0C0200, // 0007 CALL R3 1 - 0x8C100302, // 0008 GETMET R4 R1 K2 - 0x8C180506, // 0009 GETMET R6 R2 K6 - 0x58200007, // 000A LDCONST R8 K7 - 0x40261109, // 000B CONNECT R9 K8 K9 - 0x94240609, // 000C GETIDX R9 R3 R9 - 0x542A0003, // 000D LDINT R10 4 - 0x542E0005, // 000E LDINT R11 6 - 0x4028140B, // 000F CONNECT R10 R10 R11 - 0x9428060A, // 0010 GETIDX R10 R3 R10 - 0x542E0006, // 0011 LDINT R11 7 - 0x402C170A, // 0012 CONNECT R11 R11 K10 - 0x942C060B, // 0013 GETIDX R11 R3 R11 - 0x7C180A00, // 0014 CALL R6 5 - 0x7C100400, // 0015 CALL R4 2 - 0x88100104, // 0016 GETMBR R4 R0 K4 - 0x8C10090B, // 0017 GETMET R4 R4 K11 - 0x7C100200, // 0018 CALL R4 1 - 0x8C140302, // 0019 GETMET R5 R1 K2 - 0x581C000C, // 001A LDCONST R7 K12 - 0x7C140400, // 001B CALL R5 2 - 0x8C140302, // 001C GETMET R5 R1 K2 - 0x8C1C0506, // 001D GETMET R7 R2 K6 - 0x5824000D, // 001E LDCONST R9 K13 - 0x5C280800, // 001F MOVE R10 R4 - 0x7C1C0600, // 0020 CALL R7 3 - 0x7C140400, // 0021 CALL R5 2 - 0x8C140302, // 0022 GETMET R5 R1 K2 - 0x8C1C0506, // 0023 GETMET R7 R2 K6 - 0x5824000E, // 0024 LDCONST R9 K14 - 0x5C280800, // 0025 MOVE R10 R4 - 0x7C1C0600, // 0026 CALL R7 3 - 0x7C140400, // 0027 CALL R5 2 - 0x8C140302, // 0028 GETMET R5 R1 K2 - 0x581C000F, // 0029 LDCONST R7 K15 - 0x7C140400, // 002A CALL R5 2 - 0x8C140302, // 002B GETMET R5 R1 K2 - 0x581C0010, // 002C LDCONST R7 K16 - 0x7C140400, // 002D CALL R5 2 - 0x8C140302, // 002E GETMET R5 R1 K2 - 0x8C1C0506, // 002F GETMET R7 R2 K6 - 0x58240011, // 0030 LDCONST R9 K17 - 0x88280104, // 0031 GETMBR R10 R0 K4 - 0x88281512, // 0032 GETMBR R10 R10 K18 - 0x7C1C0600, // 0033 CALL R7 3 - 0x7C140400, // 0034 CALL R5 2 - 0x8C140302, // 0035 GETMET R5 R1 K2 - 0x581C0013, // 0036 LDCONST R7 K19 - 0x7C140400, // 0037 CALL R5 2 - 0x8C140302, // 0038 GETMET R5 R1 K2 - 0x8C1C0506, // 0039 GETMET R7 R2 K6 - 0x58240014, // 003A LDCONST R9 K20 - 0x88280104, // 003B GETMBR R10 R0 K4 - 0x88281515, // 003C GETMBR R10 R10 K21 - 0x7C1C0600, // 003D CALL R7 3 - 0x7C140400, // 003E CALL R5 2 - 0x8C140302, // 003F GETMET R5 R1 K2 - 0x581C0016, // 0040 LDCONST R7 K22 - 0x7C140400, // 0041 CALL R5 2 - 0x8C140302, // 0042 GETMET R5 R1 K2 - 0x581C0017, // 0043 LDCONST R7 K23 - 0x7C140400, // 0044 CALL R5 2 - 0x80000000, // 0045 RET 0 + 0x7C0C0200, // 0003 CALL R3 1 + 0x740E0001, // 0004 JMPT R3 #0007 + 0x4C0C0000, // 0005 LDNIL R3 + 0x80040600, // 0006 RET 1 R3 + 0x8C0C0303, // 0007 GETMET R3 R1 K3 + 0x58140004, // 0008 LDCONST R5 K4 + 0x7C0C0400, // 0009 CALL R3 2 + 0x8C0C0305, // 000A GETMET R3 R1 K5 + 0x7C0C0200, // 000B CALL R3 1 + 0x8C0C0106, // 000C GETMET R3 R0 K6 + 0x7C0C0200, // 000D CALL R3 1 + 0x780E0003, // 000E JMPF R3 #0013 + 0x8C0C0107, // 000F GETMET R3 R0 K7 + 0x7C0C0200, // 0010 CALL R3 1 + 0x8C0C0108, // 0011 GETMET R3 R0 K8 + 0x7C0C0200, // 0012 CALL R3 1 + 0x8C0C0309, // 0013 GETMET R3 R1 K9 + 0x8814030A, // 0014 GETMBR R5 R1 K10 + 0x7C0C0400, // 0015 CALL R3 2 + 0x8C0C030B, // 0016 GETMET R3 R1 K11 + 0x7C0C0200, // 0017 CALL R3 1 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_add_config_button +********************************************************************/ +be_local_closure(Matter_UI_web_add_config_button, /* 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_weak(webserver), + /* K1 */ be_nested_str_weak(content_send), + /* K2 */ be_nested_str_weak(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27matterc_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(_LOGO), + /* K5 */ be_nested_str_weak(_X20Configure_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + }), + be_str_weak(web_add_config_button), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x7C080400, // 0003 CALL R2 2 + 0x8C080301, // 0004 GETMET R2 R1 K1 + 0xB8120600, // 0005 GETNGBL R4 K3 + 0x88100904, // 0006 GETMBR R4 R4 K4 + 0x7C080400, // 0007 CALL R2 2 + 0x8C080301, // 0008 GETMET R2 R1 K1 + 0x58100005, // 0009 LDCONST R4 K5 + 0x7C080400, // 000A CALL R2 2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_UI_init, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(add_driver), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C080400, // 0004 CALL R2 2 + 0x80000000, // 0005 RET 0 }) ) ); @@ -135,7 +478,7 @@ be_local_closure(Matter_UI_web_add_handler, /* name */ 0, /* has upvals */ NULL, /* no upvals */ 1, /* has sup protos */ - ( &(const struct bproto*[ 3]) { + ( &(const struct bproto*[ 2]) { be_nested_proto( 2, /* nstack */ 0, /* argc */ @@ -182,42 +525,18 @@ be_local_closure(Matter_UI_web_add_handler, /* name */ 0x80040000, // 0003 RET 1 R0 }) ), - 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(page_qrcode_min_js), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x7C000200, // 0002 CALL R0 1 - 0x80040000, // 0003 RET 1 R0 - }) - ), }), 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ + ( &(const bvalue[ 5]) { /* constants */ /* K0 */ be_nested_str_weak(webserver), /* K1 */ be_nested_str_weak(on), /* K2 */ be_nested_str_weak(_X2Fmatterc), /* K3 */ be_nested_str_weak(HTTP_GET), /* K4 */ be_nested_str_weak(HTTP_POST), - /* K5 */ be_nested_str_weak(_X2Fqrcode_X2Emin_X2Ejs), }), be_str_weak(web_add_handler), &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ + ( &(const binstruction[13]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x8C080301, // 0001 GETMET R2 R1 K1 0x58100002, // 0002 LDCONST R4 K2 @@ -229,13 +548,8 @@ be_local_closure(Matter_UI_web_add_handler, /* name */ 0x84140001, // 0008 CLOSURE R5 P1 0x88180304, // 0009 GETMBR R6 R1 K4 0x7C080800, // 000A CALL R2 4 - 0x8C080301, // 000B GETMET R2 R1 K1 - 0x58100005, // 000C LDCONST R4 K5 - 0x84140002, // 000D CLOSURE R5 P2 - 0x88180303, // 000E GETMBR R6 R1 K3 - 0x7C080800, // 000F CALL R2 4 - 0xA0000000, // 0010 CLOSE R0 - 0x80000000, // 0011 RET 0 + 0xA0000000, // 000B CLOSE R0 + 0x80000000, // 000C RET 0 }) ) ); @@ -243,11 +557,11 @@ be_local_closure(Matter_UI_web_add_handler, /* name */ /******************************************************************** -** Solidified function: show_session_info +** Solidified function: show_qrcode ********************************************************************/ -be_local_closure(Matter_UI_show_session_info, /* name */ +be_local_closure(Matter_UI_show_qrcode, /* name */ be_nested_proto( - 16, /* nstack */ + 18, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -255,129 +569,242 @@ be_local_closure(Matter_UI_show_session_info, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[26]) { /* constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(_X20), + /* K2 */ be_nested_str_weak(_XE2_X96_X84), + /* K3 */ be_nested_str_weak(_XE2_X96_X80), + /* K4 */ be_nested_str_weak(_XE2_X96_X88), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(QRCode), + /* K7 */ be_nested_str_weak(encode_str), + /* K8 */ be_nested_str_weak(bitmap), + /* K9 */ be_nested_str_weak(size), + /* K10 */ be_nested_str_weak(content_send), + /* K11 */ be_nested_str_weak(_X3Cstyle_X3E_X2Eqr_X7Bfont_X2Dfamily_X3Amonospace_X3B_X20margin_X3A0_X3B_X20padding_X3A0_X3B_X20white_X2Dspace_X3Apre_X3B_X20font_X2Dsize_X3A18px_X3B_X20color_X3A_X23fff_X3B_X20line_X2Dheight_X3A100_X25_X3B_X7D_X3C_X2Fstyle_X3E), + /* K12 */ be_nested_str_weak(_X3Cdiv_X20style_X3D_X27transform_X3Ascale_X28_X2E8_X2C1_X29_X3B_X20display_X3Ainline_X2Dblock_X3B_X27_X3E), + /* K13 */ be_nested_str_weak(_X3Cdiv_X20class_X3D_X27qr_X27_X3E), + /* K14 */ be_nested_str_weak(), + /* K15 */ be_const_int(0), + /* K16 */ be_const_int(1), + /* K17 */ be_nested_str_weak(stop_iteration), + /* K18 */ be_nested_str_weak(_X3C_X2Fdiv_X3E), + /* K19 */ be_const_int(2), + /* K20 */ be_nested_str_weak(_X3Cdiv_X20class_X3D_X27qr_X27_X20style_X3D_X27background_X2Dcolor_X3A_X23000_X3B_X27_X3E), + /* K21 */ be_nested_str_weak(_X2F_X3Cdiv_X3E), + }), + be_str_weak(show_qrcode), + &be_const_str_solidified, + ( &(const binstruction[120]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x58180004, // 0004 LDCONST R6 K4 + 0xB81E0A00, // 0005 GETNGBL R7 K5 + 0x881C0F06, // 0006 GETMBR R7 R7 K6 + 0x8C1C0F07, // 0007 GETMET R7 R7 K7 + 0x5C240200, // 0008 MOVE R9 R1 + 0x7C1C0400, // 0009 CALL R7 2 + 0x94200F08, // 000A GETIDX R8 R7 K8 + 0x94240F09, // 000B GETIDX R9 R7 K9 + 0x8C28050A, // 000C GETMET R10 R2 K10 + 0x5830000B, // 000D LDCONST R12 K11 + 0x7C280400, // 000E CALL R10 2 + 0x8C28050A, // 000F GETMET R10 R2 K10 + 0x5830000C, // 0010 LDCONST R12 K12 + 0x7C280400, // 0011 CALL R10 2 + 0x5828000D, // 0012 LDCONST R10 K13 + 0x8C2C050A, // 0013 GETMET R11 R2 K10 + 0x5C341400, // 0014 MOVE R13 R10 + 0x7C2C0400, // 0015 CALL R11 2 + 0x5828000E, // 0016 LDCONST R10 K14 + 0x602C0010, // 0017 GETGBL R11 G16 + 0x00301310, // 0018 ADD R12 R9 K16 + 0x40321E0C, // 0019 CONNECT R12 K15 R12 + 0x7C2C0200, // 001A CALL R11 1 + 0xA8020003, // 001B EXBLK 0 #0020 + 0x5C301600, // 001C MOVE R12 R11 + 0x7C300000, // 001D CALL R12 0 + 0x00281404, // 001E ADD R10 R10 R4 + 0x7001FFFB, // 001F JMP #001C + 0x582C0011, // 0020 LDCONST R11 K17 + 0xAC2C0200, // 0021 CATCH R11 1 0 + 0xB0080000, // 0022 RAISE 2 R0 R0 + 0x00281512, // 0023 ADD R10 R10 K18 + 0x8C2C050A, // 0024 GETMET R11 R2 K10 + 0x5C341400, // 0025 MOVE R13 R10 + 0x7C2C0400, // 0026 CALL R11 2 + 0x602C0010, // 0027 GETGBL R11 G16 + 0x00301310, // 0028 ADD R12 R9 K16 + 0x0C301913, // 0029 DIV R12 R12 K19 + 0x04301910, // 002A SUB R12 R12 K16 + 0x40321E0C, // 002B CONNECT R12 K15 R12 + 0x7C2C0200, // 002C CALL R11 1 + 0xA802002E, // 002D EXBLK 0 #005D + 0x5C301600, // 002E MOVE R12 R11 + 0x7C300000, // 002F CALL R12 0 + 0x00362806, // 0030 ADD R13 K20 R6 + 0x5C281A00, // 0031 MOVE R10 R13 + 0x60340010, // 0032 GETGBL R13 G16 + 0x04381310, // 0033 SUB R14 R9 K16 + 0x403A1E0E, // 0034 CONNECT R14 K15 R14 + 0x7C340200, // 0035 CALL R13 1 + 0xA802001C, // 0036 EXBLK 0 #0054 + 0x5C381A00, // 0037 MOVE R14 R13 + 0x7C380000, // 0038 CALL R14 0 + 0x083C1913, // 0039 MUL R15 R12 K19 + 0x943C100F, // 003A GETIDX R15 R8 R15 + 0x943C1E0E, // 003B GETIDX R15 R15 R14 + 0x1C3C1F01, // 003C EQ R15 R15 K1 + 0x08401913, // 003D MUL R16 R12 K19 + 0x00402110, // 003E ADD R16 R16 K16 + 0x14402009, // 003F LT R16 R16 R9 + 0x78420005, // 0040 JMPF R16 #0047 + 0x08401913, // 0041 MUL R16 R12 K19 + 0x00402110, // 0042 ADD R16 R16 K16 + 0x94401010, // 0043 GETIDX R16 R8 R16 + 0x9440200E, // 0044 GETIDX R16 R16 R14 + 0x1C402101, // 0045 EQ R16 R16 K1 + 0x70020000, // 0046 JMP #0048 + 0x50400200, // 0047 LDBOOL R16 1 0 + 0x783E0004, // 0048 JMPF R15 #004E + 0x78420001, // 0049 JMPF R16 #004C + 0x5C440C00, // 004A MOVE R17 R6 + 0x70020000, // 004B JMP #004D + 0x5C440A00, // 004C MOVE R17 R5 + 0x70020003, // 004D JMP #0052 + 0x78420001, // 004E JMPF R16 #0051 + 0x5C440800, // 004F MOVE R17 R4 + 0x70020000, // 0050 JMP #0052 + 0x5C440600, // 0051 MOVE R17 R3 + 0x00281411, // 0052 ADD R10 R10 R17 + 0x7001FFE2, // 0053 JMP #0037 + 0x58340011, // 0054 LDCONST R13 K17 + 0xAC340200, // 0055 CATCH R13 1 0 + 0xB0080000, // 0056 RAISE 2 R0 R0 + 0x00281406, // 0057 ADD R10 R10 R6 + 0x00281512, // 0058 ADD R10 R10 K18 + 0x8C34050A, // 0059 GETMET R13 R2 K10 + 0x5C3C1400, // 005A MOVE R15 R10 + 0x7C340400, // 005B CALL R13 2 + 0x7001FFD0, // 005C JMP #002E + 0x582C0011, // 005D LDCONST R11 K17 + 0xAC2C0200, // 005E CATCH R11 1 0 + 0xB0080000, // 005F RAISE 2 R0 R0 + 0x102C1313, // 0060 MOD R11 R9 K19 + 0x1C2C170F, // 0061 EQ R11 R11 K15 + 0x782E0010, // 0062 JMPF R11 #0074 + 0x58280014, // 0063 LDCONST R10 K20 + 0x602C0010, // 0064 GETGBL R11 G16 + 0x00301310, // 0065 ADD R12 R9 K16 + 0x40321E0C, // 0066 CONNECT R12 K15 R12 + 0x7C2C0200, // 0067 CALL R11 1 + 0xA8020003, // 0068 EXBLK 0 #006D + 0x5C301600, // 0069 MOVE R12 R11 + 0x7C300000, // 006A CALL R12 0 + 0x00281405, // 006B ADD R10 R10 R5 + 0x7001FFFB, // 006C JMP #0069 + 0x582C0011, // 006D LDCONST R11 K17 + 0xAC2C0200, // 006E CATCH R11 1 0 + 0xB0080000, // 006F RAISE 2 R0 R0 + 0x00281515, // 0070 ADD R10 R10 K21 + 0x8C2C050A, // 0071 GETMET R11 R2 K10 + 0x5C341400, // 0072 MOVE R13 R10 + 0x7C2C0400, // 0073 CALL R11 2 + 0x8C2C050A, // 0074 GETMET R11 R2 K10 + 0x58340012, // 0075 LDCONST R13 K18 + 0x7C2C0400, // 0076 CALL R11 2 + 0x80000000, // 0077 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: show_passcode_form +********************************************************************/ +be_local_closure(Matter_UI_show_passcode_form, /* 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[19]) { /* constants */ /* K0 */ be_nested_str_weak(webserver), /* K1 */ be_nested_str_weak(string), /* K2 */ be_nested_str_weak(content_send), - /* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BSessions_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), - /* K4 */ be_nested_str_weak(_X3Cp_X3EExisting_X20sessions_X3A_X3C_X2Fp_X3E), - /* K5 */ be_nested_str_weak(device), - /* K6 */ be_nested_str_weak(sessions), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(_X3Cp_X3E_X3Cb_X3ENone_X3C_X2Fb_X3E_X3C_X2Fp_X3E), - /* K9 */ be_nested_str_weak(fabric), - /* K10 */ be_nested_str_weak(format), - /* K11 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BSession_X20_X25i_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), - /* K12 */ be_nested_str_weak(local_session_id), - /* K13 */ be_nested_str_weak(_X3Chr_X3E), - /* K14 */ be_nested_str_weak(copy), - /* K15 */ be_nested_str_weak(reverse), - /* K16 */ be_nested_str_weak(deviceid), - /* K17 */ be_nested_str_weak(Fabric_X3A_X20_X25s_X3Cbr_X3E), - /* K18 */ be_nested_str_weak(tohex), - /* K19 */ be_nested_str_weak(Device_X3A_X20_X25s_X3Cbr_X3E_X26nbsp_X3B), - /* K20 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20), - /* K21 */ be_nested_str_weak(onsubmit_X3D_X27return_X20confirm_X28_X22This_X20will_X20cause_X20a_X20restart_X2E_X22_X29_X3B_X27_X3E), - /* K22 */ be_nested_str_weak(_X3Cinput_X20name_X3D_X27del_session_X27_X20type_X3D_X27hidden_X27_X20value_X3D_X27_X25d_X27_X3E), - /* K23 */ be_nested_str_weak(_X3Cbutton_X20name_X3D_X27del_X27_X20class_X3D_X27button_X20bgrn_X27_X3EDelete_X20Session_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), - /* K24 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), - /* K25 */ be_const_int(1), + /* K3 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BMatter_X20Passcode_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K4 */ be_nested_str_weak(_X3Cform_X20action_X3D_X27_X2Fmatterc_X27_X20method_X3D_X27post_X27_X20_X3E), + /* K5 */ be_nested_str_weak(_X3Cp_X3EPasscode_X3A_X3C_X2Fp_X3E), + /* K6 */ be_nested_str_weak(format), + /* K7 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X271_X27_X20max_X3D_X2799999998_X27_X20name_X3D_X27passcode_X27_X20value_X3D_X27_X25i_X27_X3E), + /* K8 */ be_nested_str_weak(device), + /* K9 */ be_nested_str_weak(root_passcode), + /* K10 */ be_nested_str_weak(_X3Cp_X3EDistinguish_X20id_X3A_X3C_X2Fp_X3E), + /* K11 */ be_nested_str_weak(_X3Cinput_X20type_X3D_X27number_X27_X20min_X3D_X270_X27_X20max_X3D_X274095_X27_X20name_X3D_X27discriminator_X27_X20value_X3D_X27_X25i_X27_X3E), + /* K12 */ be_nested_str_weak(root_discriminator), + /* K13 */ be_nested_str_weak(_X3Cp_X3E_X3Cinput_X20type_X3D_X27checkbox_X27_X20name_X3D_X27ipv4_X27_X25s_X3EIPv4_X20only_X3C_X2Fp_X3E), + /* K14 */ be_nested_str_weak(ipv4only), + /* K15 */ be_nested_str_weak(_X20checked), + /* K16 */ be_nested_str_weak(), + /* K17 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3Cbutton_X20name_X3D_X27passcode_X27_X20class_X3D_X27button_X20bgrn_X27_X3EChange_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + /* K18 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), }), - be_str_weak(show_session_info), + be_str_weak(show_passcode_form), &be_const_str_solidified, - ( &(const binstruction[92]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0x8C100502, // 0002 GETMET R4 R2 K2 - 0x58180003, // 0003 LDCONST R6 K3 - 0x7C100400, // 0004 CALL R4 2 - 0x8C100502, // 0005 GETMET R4 R2 K2 - 0x58180004, // 0006 LDCONST R6 K4 - 0x7C100400, // 0007 CALL R4 2 - 0x6010000C, // 0008 GETGBL R4 G12 - 0x88140105, // 0009 GETMBR R5 R0 K5 - 0x88140B06, // 000A GETMBR R5 R5 K6 - 0x88140B06, // 000B GETMBR R5 R5 K6 - 0x7C100200, // 000C CALL R4 1 - 0x1C100907, // 000D EQ R4 R4 K7 - 0x78120003, // 000E JMPF R4 #0013 - 0x8C100502, // 000F GETMET R4 R2 K2 - 0x58180008, // 0010 LDCONST R6 K8 - 0x7C100400, // 0011 CALL R4 2 - 0x70020044, // 0012 JMP #0058 - 0x58100007, // 0013 LDCONST R4 K7 - 0x6014000C, // 0014 GETGBL R5 G12 - 0x88180105, // 0015 GETMBR R6 R0 K5 - 0x88180D06, // 0016 GETMBR R6 R6 K6 - 0x88180D06, // 0017 GETMBR R6 R6 K6 - 0x7C140200, // 0018 CALL R5 1 - 0x14180805, // 0019 LT R6 R4 R5 - 0x781A003C, // 001A JMPF R6 #0058 - 0x88180105, // 001B GETMBR R6 R0 K5 - 0x88180D06, // 001C GETMBR R6 R6 K6 - 0x88180D06, // 001D GETMBR R6 R6 K6 - 0x94180C04, // 001E GETIDX R6 R6 R4 - 0x881C0D09, // 001F GETMBR R7 R6 K9 - 0x781E0034, // 0020 JMPF R7 #0056 - 0x8C1C0502, // 0021 GETMET R7 R2 K2 - 0x8C24070A, // 0022 GETMET R9 R3 K10 - 0x582C000B, // 0023 LDCONST R11 K11 - 0x88300D0C, // 0024 GETMBR R12 R6 K12 - 0x7C240600, // 0025 CALL R9 3 - 0x7C1C0400, // 0026 CALL R7 2 - 0x201C0907, // 0027 NE R7 R4 K7 - 0x781E0002, // 0028 JMPF R7 #002C - 0x8C1C0502, // 0029 GETMET R7 R2 K2 - 0x5824000D, // 002A LDCONST R9 K13 - 0x7C1C0400, // 002B CALL R7 2 - 0x881C0D09, // 002C GETMBR R7 R6 K9 - 0x8C1C0F0E, // 002D GETMET R7 R7 K14 - 0x7C1C0200, // 002E CALL R7 1 - 0x8C1C0F0F, // 002F GETMET R7 R7 K15 - 0x7C1C0200, // 0030 CALL R7 1 - 0x88200D10, // 0031 GETMBR R8 R6 K16 - 0x8C20110E, // 0032 GETMET R8 R8 K14 - 0x7C200200, // 0033 CALL R8 1 - 0x8C20110F, // 0034 GETMET R8 R8 K15 - 0x7C200200, // 0035 CALL R8 1 - 0x8C240502, // 0036 GETMET R9 R2 K2 - 0x8C2C070A, // 0037 GETMET R11 R3 K10 - 0x58340011, // 0038 LDCONST R13 K17 - 0x8C380F12, // 0039 GETMET R14 R7 K18 - 0x7C380200, // 003A CALL R14 1 - 0x7C2C0600, // 003B CALL R11 3 - 0x7C240400, // 003C CALL R9 2 - 0x8C240502, // 003D GETMET R9 R2 K2 - 0x8C2C070A, // 003E GETMET R11 R3 K10 - 0x58340013, // 003F LDCONST R13 K19 - 0x8C381112, // 0040 GETMET R14 R8 K18 - 0x7C380200, // 0041 CALL R14 1 - 0x7C2C0600, // 0042 CALL R11 3 - 0x7C240400, // 0043 CALL R9 2 - 0x8C240502, // 0044 GETMET R9 R2 K2 - 0x582C0014, // 0045 LDCONST R11 K20 - 0x7C240400, // 0046 CALL R9 2 - 0x8C240502, // 0047 GETMET R9 R2 K2 - 0x582C0015, // 0048 LDCONST R11 K21 - 0x7C240400, // 0049 CALL R9 2 - 0x8C240502, // 004A GETMET R9 R2 K2 - 0x8C2C070A, // 004B GETMET R11 R3 K10 - 0x58340016, // 004C LDCONST R13 K22 - 0x88380D0C, // 004D GETMBR R14 R6 K12 - 0x7C2C0600, // 004E CALL R11 3 - 0x7C240400, // 004F CALL R9 2 - 0x8C240502, // 0050 GETMET R9 R2 K2 - 0x582C0017, // 0051 LDCONST R11 K23 - 0x7C240400, // 0052 CALL R9 2 - 0x8C240502, // 0053 GETMET R9 R2 K2 - 0x582C0018, // 0054 LDCONST R11 K24 - 0x7C240400, // 0055 CALL R9 2 - 0x00100919, // 0056 ADD R4 R4 K25 - 0x7001FFC0, // 0057 JMP #0019 - 0x8C100502, // 0058 GETMET R4 R2 K2 - 0x58180018, // 0059 LDCONST R6 K24 - 0x7C100400, // 005A CALL R4 2 - 0x80000000, // 005B RET 0 + ( &(const binstruction[46]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x8C0C0302, // 0005 GETMET R3 R1 K2 + 0x58140004, // 0006 LDCONST R5 K4 + 0x7C0C0400, // 0007 CALL R3 2 + 0x8C0C0302, // 0008 GETMET R3 R1 K2 + 0x58140005, // 0009 LDCONST R5 K5 + 0x7C0C0400, // 000A CALL R3 2 + 0x8C0C0302, // 000B GETMET R3 R1 K2 + 0x8C140506, // 000C GETMET R5 R2 K6 + 0x581C0007, // 000D LDCONST R7 K7 + 0x88200108, // 000E GETMBR R8 R0 K8 + 0x88201109, // 000F GETMBR R8 R8 K9 + 0x7C140600, // 0010 CALL R5 3 + 0x7C0C0400, // 0011 CALL R3 2 + 0x8C0C0302, // 0012 GETMET R3 R1 K2 + 0x5814000A, // 0013 LDCONST R5 K10 + 0x7C0C0400, // 0014 CALL R3 2 + 0x8C0C0302, // 0015 GETMET R3 R1 K2 + 0x8C140506, // 0016 GETMET R5 R2 K6 + 0x581C000B, // 0017 LDCONST R7 K11 + 0x88200108, // 0018 GETMBR R8 R0 K8 + 0x8820110C, // 0019 GETMBR R8 R8 K12 + 0x7C140600, // 001A CALL R5 3 + 0x7C0C0400, // 001B CALL R3 2 + 0x8C0C0302, // 001C GETMET R3 R1 K2 + 0x8C140506, // 001D GETMET R5 R2 K6 + 0x581C000D, // 001E LDCONST R7 K13 + 0x88200108, // 001F GETMBR R8 R0 K8 + 0x8820110E, // 0020 GETMBR R8 R8 K14 + 0x78220001, // 0021 JMPF R8 #0024 + 0x5820000F, // 0022 LDCONST R8 K15 + 0x70020000, // 0023 JMP #0025 + 0x58200010, // 0024 LDCONST R8 K16 + 0x7C140600, // 0025 CALL R5 3 + 0x7C0C0400, // 0026 CALL R3 2 + 0x8C0C0302, // 0027 GETMET R3 R1 K2 + 0x58140011, // 0028 LDCONST R5 K17 + 0x7C0C0400, // 0029 CALL R3 2 + 0x8C0C0302, // 002A GETMET R3 R1 K2 + 0x58140012, // 002B LDCONST R5 K18 + 0x7C0C0400, // 002C CALL R3 2 + 0x80000000, // 002D RET 0 }) ) ); @@ -473,32 +900,109 @@ be_local_closure(Matter_UI_show_enable, /* name */ /******************************************************************** -** Solidified function: init +** Solidified function: show_commissioning_info ********************************************************************/ -be_local_closure(Matter_UI_init, /* name */ +be_local_closure(Matter_UI_show_commissioning_info, /* name */ be_nested_proto( - 5, /* nstack */ - 2, /* argc */ + 14, /* 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(device), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(add_driver), + ( &(const bvalue[20]) { /* constants */ + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(device), + /* K3 */ be_nested_str_weak(commissioning_open), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(millis), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(content_send), + /* K8 */ be_nested_str_weak(format), + /* K9 */ be_nested_str_weak(_X3Cfieldset_X3E_X3Clegend_X3E_X3Cb_X3E_X26nbsp_X3BCommissioning_X20open_X20for_X20_X25i_X20min_X26nbsp_X3B_X3C_X2Fb_X3E_X3C_X2Flegend_X3E_X3Cp_X3E_X3C_X2Fp_X3E), + /* K10 */ be_nested_str_weak(compute_manual_pairing_code), + /* K11 */ be_nested_str_weak(_X3Cp_X3EManual_X20pairing_X20code_X3A_X3Cbr_X3E_X3Cb_X3E_X25s_X2D_X25s_X2D_X25s_X3C_X2Fb_X3E_X3C_X2Fp_X3E_X3Chr_X3E), + /* K12 */ be_const_int(3), + /* K13 */ be_const_int(2147483647), + /* K14 */ be_nested_str_weak(_X3Cdiv_X3E_X3Ccenter_X3E), + /* K15 */ be_nested_str_weak(compute_qrcode_content), + /* K16 */ be_nested_str_weak(show_qrcode), + /* K17 */ be_nested_str_weak(_X3Cp_X3E_X20_X25s_X3C_X2Fp_X3E), + /* K18 */ be_nested_str_weak(_X3C_X2Fdiv_X3E), + /* K19 */ be_nested_str_weak(_X3Cp_X3E_X3C_X2Fp_X3E_X3C_X2Ffieldset_X3E_X3Cp_X3E_X3C_X2Fp_X3E), }), - be_str_weak(init), + be_str_weak(show_commissioning_info), &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0xB80A0200, // 0001 GETNGBL R2 K1 - 0x8C080502, // 0002 GETMET R2 R2 K2 - 0x5C100000, // 0003 MOVE R4 R0 - 0x7C080400, // 0004 CALL R2 2 - 0x80000000, // 0005 RET 0 + ( &(const binstruction[66]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x880C0102, // 0002 GETMBR R3 R0 K2 + 0x880C0703, // 0003 GETMBR R3 R3 K3 + 0xB8120800, // 0004 GETNGBL R4 K4 + 0x8C100905, // 0005 GETMET R4 R4 K5 + 0x7C100200, // 0006 CALL R4 1 + 0x040C0604, // 0007 SUB R3 R3 R4 + 0x541203E7, // 0008 LDINT R4 1000 + 0x0C0C0604, // 0009 DIV R3 R3 R4 + 0x14100706, // 000A LT R4 R3 K6 + 0x78120000, // 000B JMPF R4 #000D + 0x580C0006, // 000C LDCONST R3 K6 + 0x5412001D, // 000D LDINT R4 30 + 0x00100604, // 000E ADD R4 R3 R4 + 0x5416003B, // 000F LDINT R5 60 + 0x0C100805, // 0010 DIV R4 R4 R5 + 0x8C140307, // 0011 GETMET R5 R1 K7 + 0x8C1C0508, // 0012 GETMET R7 R2 K8 + 0x58240009, // 0013 LDCONST R9 K9 + 0x5C280800, // 0014 MOVE R10 R4 + 0x7C1C0600, // 0015 CALL R7 3 + 0x7C140400, // 0016 CALL R5 2 + 0x88140102, // 0017 GETMBR R5 R0 K2 + 0x8C140B0A, // 0018 GETMET R5 R5 K10 + 0x7C140200, // 0019 CALL R5 1 + 0x8C180307, // 001A GETMET R6 R1 K7 + 0x8C200508, // 001B GETMET R8 R2 K8 + 0x5828000B, // 001C LDCONST R10 K11 + 0x402E0D0C, // 001D CONNECT R11 K6 K12 + 0x942C0A0B, // 001E GETIDX R11 R5 R11 + 0x54320003, // 001F LDINT R12 4 + 0x54360005, // 0020 LDINT R13 6 + 0x4030180D, // 0021 CONNECT R12 R12 R13 + 0x94300A0C, // 0022 GETIDX R12 R5 R12 + 0x54360006, // 0023 LDINT R13 7 + 0x40341B0D, // 0024 CONNECT R13 R13 K13 + 0x94340A0D, // 0025 GETIDX R13 R5 R13 + 0x7C200A00, // 0026 CALL R8 5 + 0x7C180400, // 0027 CALL R6 2 + 0x8C180307, // 0028 GETMET R6 R1 K7 + 0x8C200508, // 0029 GETMET R8 R2 K8 + 0x5828000E, // 002A LDCONST R10 K14 + 0x7C200400, // 002B CALL R8 2 + 0x7C180400, // 002C CALL R6 2 + 0x88180102, // 002D GETMBR R6 R0 K2 + 0x8C180D0F, // 002E GETMET R6 R6 K15 + 0x7C180200, // 002F CALL R6 1 + 0x8C1C0110, // 0030 GETMET R7 R0 K16 + 0x5C240C00, // 0031 MOVE R9 R6 + 0x7C1C0400, // 0032 CALL R7 2 + 0x8C1C0307, // 0033 GETMET R7 R1 K7 + 0x8C240508, // 0034 GETMET R9 R2 K8 + 0x582C0011, // 0035 LDCONST R11 K17 + 0x5C300C00, // 0036 MOVE R12 R6 + 0x7C240600, // 0037 CALL R9 3 + 0x7C1C0400, // 0038 CALL R7 2 + 0x8C1C0307, // 0039 GETMET R7 R1 K7 + 0x8C240508, // 003A GETMET R9 R2 K8 + 0x582C0012, // 003B LDCONST R11 K18 + 0x7C240400, // 003C CALL R9 2 + 0x7C1C0400, // 003D CALL R7 2 + 0x8C1C0307, // 003E GETMET R7 R1 K7 + 0x58240013, // 003F LDCONST R9 K19 + 0x7C1C0400, // 0040 CALL R7 2 + 0x80000000, // 0041 RET 0 }) ) ); @@ -518,7 +1022,7 @@ be_local_closure(Matter_UI_page_part_ctl, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[40]) { /* constants */ + ( &(const bvalue[48]) { /* constants */ /* K0 */ be_nested_str_weak(webserver), /* K1 */ be_nested_str_weak(check_privileged_access), /* K2 */ be_nested_str_weak(string), @@ -529,40 +1033,48 @@ be_local_closure(Matter_UI_page_part_ctl, /* name */ /* K7 */ be_nested_str_weak(passcode), /* K8 */ be_nested_str_weak(discriminator), /* K9 */ be_nested_str_weak(device), - /* K10 */ be_nested_str_weak(arg), - /* K11 */ be_nested_str_weak(save_param), - /* K12 */ be_nested_str_weak(redirect), - /* K13 */ be_nested_str_weak(_X2F_X3Frst_X3D), - /* K14 */ be_nested_str_weak(enable), - /* K15 */ be_nested_str_weak(tasmota), - /* K16 */ be_nested_str_weak(cmd), - /* K17 */ be_nested_str_weak(SetOption), - /* K18 */ be_nested_str_weak(matter), - /* K19 */ be_nested_str_weak(MATTER_OPTION), - /* K20 */ be_nested_str_weak(_X201), - /* K21 */ be_nested_str_weak(disable), - /* K22 */ be_nested_str_weak(_X200), - /* K23 */ be_nested_str_weak(del_session), - /* K24 */ be_nested_str_weak(sessions), - /* K25 */ be_nested_str_weak(get_session_by_local_session_id), - /* K26 */ be_nested_str_weak(remove_session), - /* K27 */ be_nested_str_weak(save), - /* K28 */ be_nested_str_weak(log), - /* K29 */ be_nested_str_weak(format), - /* K30 */ be_nested_str_weak(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), - /* K31 */ be_const_int(2), - /* K32 */ be_nested_str_weak(content_start), - /* K33 */ be_nested_str_weak(Parameter_X20error), - /* K34 */ be_nested_str_weak(content_send_style), - /* K35 */ be_nested_str_weak(content_send), - /* K36 */ be_nested_str_weak(_X3Cp_X20style_X3D_X27width_X3A340px_X3B_X27_X3E_X3Cb_X3EException_X3A_X3C_X2Fb_X3E_X3Cbr_X3E_X27_X25s_X27_X3Cbr_X3E_X25s_X3C_X2Fp_X3E), - /* K37 */ be_nested_str_weak(content_button), - /* K38 */ be_nested_str_weak(BUTTON_MANAGEMENT), - /* K39 */ be_nested_str_weak(content_stop), + /* K10 */ be_nested_str_weak(root_passcode), + /* K11 */ be_nested_str_weak(arg), + /* K12 */ be_nested_str_weak(root_discriminator), + /* K13 */ be_nested_str_weak(ipv4only), + /* K14 */ be_nested_str_weak(ipv4), + /* K15 */ be_nested_str_weak(on), + /* K16 */ be_nested_str_weak(save_param), + /* K17 */ be_nested_str_weak(redirect), + /* K18 */ be_nested_str_weak(_X2F_X3Frst_X3D), + /* K19 */ be_nested_str_weak(enable), + /* K20 */ be_nested_str_weak(tasmota), + /* K21 */ be_nested_str_weak(cmd), + /* K22 */ be_nested_str_weak(SetOption), + /* K23 */ be_nested_str_weak(matter), + /* K24 */ be_nested_str_weak(MATTER_OPTION), + /* K25 */ be_nested_str_weak(_X201), + /* K26 */ be_nested_str_weak(disable), + /* K27 */ be_nested_str_weak(_X200), + /* K28 */ be_nested_str_weak(del_fabric), + /* K29 */ be_const_int(0), + /* K30 */ be_nested_str_weak(sessions), + /* K31 */ be_nested_str_weak(fabrics), + /* K32 */ be_nested_str_weak(get_fabric_index), + /* K33 */ be_nested_str_weak(remove_fabric), + /* K34 */ be_const_int(1), + /* K35 */ be_nested_str_weak(_X2Fmatterc_X3F), + /* K36 */ be_nested_str_weak(log), + /* K37 */ be_nested_str_weak(format), + /* K38 */ be_nested_str_weak(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), + /* K39 */ be_const_int(2), + /* K40 */ be_nested_str_weak(content_start), + /* K41 */ be_nested_str_weak(Parameter_X20error), + /* K42 */ be_nested_str_weak(content_send_style), + /* K43 */ be_nested_str_weak(content_send), + /* K44 */ be_nested_str_weak(_X3Cp_X20style_X3D_X27width_X3A340px_X3B_X27_X3E_X3Cb_X3EException_X3A_X3C_X2Fb_X3E_X3Cbr_X3E_X27_X25s_X27_X3Cbr_X3E_X25s_X3C_X2Fp_X3E), + /* K45 */ be_nested_str_weak(content_button), + /* K46 */ be_nested_str_weak(BUTTON_MANAGEMENT), + /* K47 */ be_nested_str_weak(content_stop), }), be_str_weak(page_part_ctl), &be_const_str_solidified, - ( &(const binstruction[144]) { /* code */ + ( &(const binstruction[156]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x8C080301, // 0001 GETMET R2 R1 K1 0x7C080200, // 0002 CALL R2 1 @@ -574,7 +1086,7 @@ be_local_closure(Matter_UI_page_part_ctl, /* name */ 0xA4120800, // 0008 IMPORT R4 K4 0x8C140705, // 0009 GETMET R5 R3 K5 0x7C140200, // 000A CALL R5 1 - 0xA8020064, // 000B EXBLK 0 #0071 + 0xA8020070, // 000B EXBLK 0 #007D 0x8C180306, // 000C GETMET R6 R1 K6 0x58200007, // 000D LDCONST R8 K7 0x7C180400, // 000E CALL R6 2 @@ -582,279 +1094,143 @@ be_local_closure(Matter_UI_page_part_ctl, /* name */ 0x8C180306, // 0010 GETMET R6 R1 K6 0x58200008, // 0011 LDCONST R8 K8 0x7C180400, // 0012 CALL R6 2 - 0x781A001C, // 0013 JMPF R6 #0031 + 0x781A0022, // 0013 JMPF R6 #0037 0x8C180306, // 0014 GETMET R6 R1 K6 0x58200007, // 0015 LDCONST R8 K7 0x7C180400, // 0016 CALL R6 2 0x781A0006, // 0017 JMPF R6 #001F 0x88180109, // 0018 GETMBR R6 R0 K9 0x601C0009, // 0019 GETGBL R7 G9 - 0x8C20030A, // 001A GETMET R8 R1 K10 + 0x8C20030B, // 001A GETMET R8 R1 K11 0x58280007, // 001B LDCONST R10 K7 0x7C200400, // 001C CALL R8 2 0x7C1C0200, // 001D CALL R7 1 - 0x901A0E07, // 001E SETMBR R6 K7 R7 + 0x901A1407, // 001E SETMBR R6 K10 R7 0x8C180306, // 001F GETMET R6 R1 K6 0x58200008, // 0020 LDCONST R8 K8 0x7C180400, // 0021 CALL R6 2 0x781A0006, // 0022 JMPF R6 #002A 0x88180109, // 0023 GETMBR R6 R0 K9 0x601C0009, // 0024 GETGBL R7 G9 - 0x8C20030A, // 0025 GETMET R8 R1 K10 + 0x8C20030B, // 0025 GETMET R8 R1 K11 0x58280008, // 0026 LDCONST R10 K8 0x7C200400, // 0027 CALL R8 2 0x7C1C0200, // 0028 CALL R7 1 - 0x901A1007, // 0029 SETMBR R6 K8 R7 + 0x901A1807, // 0029 SETMBR R6 K12 R7 0x88180109, // 002A GETMBR R6 R0 K9 - 0x8C180D0B, // 002B GETMET R6 R6 K11 - 0x7C180200, // 002C CALL R6 1 - 0x8C18030C, // 002D GETMET R6 R1 K12 - 0x5820000D, // 002E LDCONST R8 K13 - 0x7C180400, // 002F CALL R6 2 - 0x7002003D, // 0030 JMP #006F - 0x8C180306, // 0031 GETMET R6 R1 K6 - 0x5820000E, // 0032 LDCONST R8 K14 - 0x7C180400, // 0033 CALL R6 2 - 0x781A000C, // 0034 JMPF R6 #0042 - 0xB81A1E00, // 0035 GETNGBL R6 K15 - 0x8C180D10, // 0036 GETMET R6 R6 K16 - 0x60200008, // 0037 GETGBL R8 G8 - 0xB8262400, // 0038 GETNGBL R9 K18 - 0x88241313, // 0039 GETMBR R9 R9 K19 - 0x7C200200, // 003A CALL R8 1 - 0x00222208, // 003B ADD R8 K17 R8 - 0x00201114, // 003C ADD R8 R8 K20 - 0x7C180400, // 003D CALL R6 2 - 0x8C18030C, // 003E GETMET R6 R1 K12 - 0x5820000D, // 003F LDCONST R8 K13 - 0x7C180400, // 0040 CALL R6 2 - 0x7002002C, // 0041 JMP #006F - 0x8C180306, // 0042 GETMET R6 R1 K6 - 0x58200015, // 0043 LDCONST R8 K21 - 0x7C180400, // 0044 CALL R6 2 - 0x781A000C, // 0045 JMPF R6 #0053 - 0xB81A1E00, // 0046 GETNGBL R6 K15 - 0x8C180D10, // 0047 GETMET R6 R6 K16 - 0x60200008, // 0048 GETGBL R8 G8 - 0xB8262400, // 0049 GETNGBL R9 K18 - 0x88241313, // 004A GETMBR R9 R9 K19 - 0x7C200200, // 004B CALL R8 1 - 0x00222208, // 004C ADD R8 K17 R8 - 0x00201116, // 004D ADD R8 R8 K22 - 0x7C180400, // 004E CALL R6 2 - 0x8C18030C, // 004F GETMET R6 R1 K12 - 0x5820000D, // 0050 LDCONST R8 K13 - 0x7C180400, // 0051 CALL R6 2 - 0x7002001B, // 0052 JMP #006F - 0x8C180306, // 0053 GETMET R6 R1 K6 - 0x58200017, // 0054 LDCONST R8 K23 - 0x7C180400, // 0055 CALL R6 2 - 0x781A0017, // 0056 JMPF R6 #006F - 0x88180109, // 0057 GETMBR R6 R0 K9 - 0x88180D18, // 0058 GETMBR R6 R6 K24 - 0x8C180D19, // 0059 GETMET R6 R6 K25 - 0x60200009, // 005A GETGBL R8 G9 - 0x8C24030A, // 005B GETMET R9 R1 K10 - 0x582C0017, // 005C LDCONST R11 K23 - 0x7C240400, // 005D CALL R9 2 - 0x7C200200, // 005E CALL R8 1 - 0x7C180400, // 005F CALL R6 2 - 0x4C1C0000, // 0060 LDNIL R7 - 0x201C0C07, // 0061 NE R7 R6 R7 - 0x781E0008, // 0062 JMPF R7 #006C - 0x881C0109, // 0063 GETMBR R7 R0 K9 - 0x881C0F18, // 0064 GETMBR R7 R7 K24 - 0x8C1C0F1A, // 0065 GETMET R7 R7 K26 - 0x5C240C00, // 0066 MOVE R9 R6 - 0x7C1C0400, // 0067 CALL R7 2 - 0x881C0109, // 0068 GETMBR R7 R0 K9 - 0x881C0F18, // 0069 GETMBR R7 R7 K24 - 0x8C1C0F1B, // 006A GETMET R7 R7 K27 - 0x7C1C0200, // 006B CALL R7 1 - 0x8C1C030C, // 006C GETMET R7 R1 K12 - 0x5824000D, // 006D LDCONST R9 K13 - 0x7C1C0400, // 006E CALL R7 2 - 0xA8040001, // 006F EXBLK 1 1 - 0x7002001D, // 0070 JMP #008F - 0xAC180002, // 0071 CATCH R6 0 2 - 0x7002001A, // 0072 JMP #008E - 0xB8221E00, // 0073 GETNGBL R8 K15 - 0x8C20111C, // 0074 GETMET R8 R8 K28 - 0x8C28051D, // 0075 GETMET R10 R2 K29 - 0x5830001E, // 0076 LDCONST R12 K30 - 0x5C340C00, // 0077 MOVE R13 R6 - 0x5C380E00, // 0078 MOVE R14 R7 - 0x7C280800, // 0079 CALL R10 4 - 0x582C001F, // 007A LDCONST R11 K31 - 0x7C200600, // 007B CALL R8 3 - 0x8C200320, // 007C GETMET R8 R1 K32 - 0x58280021, // 007D LDCONST R10 K33 - 0x7C200400, // 007E CALL R8 2 - 0x8C200322, // 007F GETMET R8 R1 K34 - 0x7C200200, // 0080 CALL R8 1 - 0x8C200323, // 0081 GETMET R8 R1 K35 - 0x8C28051D, // 0082 GETMET R10 R2 K29 - 0x58300024, // 0083 LDCONST R12 K36 - 0x5C340C00, // 0084 MOVE R13 R6 - 0x5C380E00, // 0085 MOVE R14 R7 - 0x7C280800, // 0086 CALL R10 4 - 0x7C200400, // 0087 CALL R8 2 - 0x8C200325, // 0088 GETMET R8 R1 K37 - 0x88280326, // 0089 GETMBR R10 R1 K38 + 0x8C1C030B, // 002B GETMET R7 R1 K11 + 0x5824000E, // 002C LDCONST R9 K14 + 0x7C1C0400, // 002D CALL R7 2 + 0x1C1C0F0F, // 002E EQ R7 R7 K15 + 0x901A1A07, // 002F SETMBR R6 K13 R7 + 0x88180109, // 0030 GETMBR R6 R0 K9 + 0x8C180D10, // 0031 GETMET R6 R6 K16 + 0x7C180200, // 0032 CALL R6 1 + 0x8C180311, // 0033 GETMET R6 R1 K17 + 0x58200012, // 0034 LDCONST R8 K18 + 0x7C180400, // 0035 CALL R6 2 + 0x70020043, // 0036 JMP #007B + 0x8C180306, // 0037 GETMET R6 R1 K6 + 0x58200013, // 0038 LDCONST R8 K19 + 0x7C180400, // 0039 CALL R6 2 + 0x781A000C, // 003A JMPF R6 #0048 + 0xB81A2800, // 003B GETNGBL R6 K20 + 0x8C180D15, // 003C GETMET R6 R6 K21 + 0x60200008, // 003D GETGBL R8 G8 + 0xB8262E00, // 003E GETNGBL R9 K23 + 0x88241318, // 003F GETMBR R9 R9 K24 + 0x7C200200, // 0040 CALL R8 1 + 0x00222C08, // 0041 ADD R8 K22 R8 + 0x00201119, // 0042 ADD R8 R8 K25 + 0x7C180400, // 0043 CALL R6 2 + 0x8C180311, // 0044 GETMET R6 R1 K17 + 0x58200012, // 0045 LDCONST R8 K18 + 0x7C180400, // 0046 CALL R6 2 + 0x70020032, // 0047 JMP #007B + 0x8C180306, // 0048 GETMET R6 R1 K6 + 0x5820001A, // 0049 LDCONST R8 K26 + 0x7C180400, // 004A CALL R6 2 + 0x781A000C, // 004B JMPF R6 #0059 + 0xB81A2800, // 004C GETNGBL R6 K20 + 0x8C180D15, // 004D GETMET R6 R6 K21 + 0x60200008, // 004E GETGBL R8 G8 + 0xB8262E00, // 004F GETNGBL R9 K23 + 0x88241318, // 0050 GETMBR R9 R9 K24 + 0x7C200200, // 0051 CALL R8 1 + 0x00222C08, // 0052 ADD R8 K22 R8 + 0x0020111B, // 0053 ADD R8 R8 K27 + 0x7C180400, // 0054 CALL R6 2 + 0x8C180311, // 0055 GETMET R6 R1 K17 + 0x58200012, // 0056 LDCONST R8 K18 + 0x7C180400, // 0057 CALL R6 2 + 0x70020021, // 0058 JMP #007B + 0x8C180306, // 0059 GETMET R6 R1 K6 + 0x5820001C, // 005A LDCONST R8 K28 + 0x7C180400, // 005B CALL R6 2 + 0x781A001D, // 005C JMPF R6 #007B + 0x60180009, // 005D GETGBL R6 G9 + 0x8C1C030B, // 005E GETMET R7 R1 K11 + 0x5824001C, // 005F LDCONST R9 K28 + 0x7C1C0400, // 0060 CALL R7 2 + 0x7C180200, // 0061 CALL R6 1 + 0x581C001D, // 0062 LDCONST R7 K29 + 0x88200109, // 0063 GETMBR R8 R0 K9 + 0x8820111E, // 0064 GETMBR R8 R8 K30 + 0x8820111F, // 0065 GETMBR R8 R8 K31 + 0x6024000C, // 0066 GETGBL R9 G12 + 0x5C281000, // 0067 MOVE R10 R8 + 0x7C240200, // 0068 CALL R9 1 + 0x14240E09, // 0069 LT R9 R7 R9 + 0x7826000C, // 006A JMPF R9 #0078 + 0x94241007, // 006B GETIDX R9 R8 R7 + 0x8C241320, // 006C GETMET R9 R9 K32 + 0x7C240200, // 006D CALL R9 1 + 0x1C241206, // 006E EQ R9 R9 R6 + 0x78260005, // 006F JMPF R9 #0076 + 0x88240109, // 0070 GETMBR R9 R0 K9 + 0x8C241321, // 0071 GETMET R9 R9 K33 + 0x942C1007, // 0072 GETIDX R11 R8 R7 + 0x7C240400, // 0073 CALL R9 2 + 0x70020002, // 0074 JMP #0078 + 0x70020000, // 0075 JMP #0077 + 0x001C0F22, // 0076 ADD R7 R7 K34 + 0x7001FFED, // 0077 JMP #0066 + 0x8C240311, // 0078 GETMET R9 R1 K17 + 0x582C0023, // 0079 LDCONST R11 K35 + 0x7C240400, // 007A CALL R9 2 + 0xA8040001, // 007B EXBLK 1 1 + 0x7002001D, // 007C JMP #009B + 0xAC180002, // 007D CATCH R6 0 2 + 0x7002001A, // 007E JMP #009A + 0xB8222800, // 007F GETNGBL R8 K20 + 0x8C201124, // 0080 GETMET R8 R8 K36 + 0x8C280525, // 0081 GETMET R10 R2 K37 + 0x58300026, // 0082 LDCONST R12 K38 + 0x5C340C00, // 0083 MOVE R13 R6 + 0x5C380E00, // 0084 MOVE R14 R7 + 0x7C280800, // 0085 CALL R10 4 + 0x582C0027, // 0086 LDCONST R11 K39 + 0x7C200600, // 0087 CALL R8 3 + 0x8C200328, // 0088 GETMET R8 R1 K40 + 0x58280029, // 0089 LDCONST R10 K41 0x7C200400, // 008A CALL R8 2 - 0x8C200327, // 008B GETMET R8 R1 K39 + 0x8C20032A, // 008B GETMET R8 R1 K42 0x7C200200, // 008C CALL R8 1 - 0x70020000, // 008D JMP #008F - 0xB0080000, // 008E RAISE 2 R0 R0 - 0x80000000, // 008F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: web_add_config_button -********************************************************************/ -be_local_closure(Matter_UI_web_add_config_button, /* 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_weak(webserver), - /* K1 */ be_nested_str_weak(content_send), - /* K2 */ be_nested_str_weak(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27matterc_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(_LOGO), - /* K5 */ be_nested_str_weak(_X20Configure_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), - }), - be_str_weak(web_add_config_button), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x58100002, // 0002 LDCONST R4 K2 - 0x7C080400, // 0003 CALL R2 2 - 0x8C080301, // 0004 GETMET R2 R1 K1 - 0xB8120600, // 0005 GETNGBL R4 K3 - 0x88100904, // 0006 GETMBR R4 R4 K4 - 0x7C080400, // 0007 CALL R2 2 - 0x8C080301, // 0008 GETMET R2 R1 K1 - 0x58100005, // 0009 LDCONST R4 K5 - 0x7C080400, // 000A CALL R2 2 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: page_qrcode_min_js -********************************************************************/ -be_local_closure(Matter_UI_page_qrcode_min_js, /* 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(webserver), - /* K1 */ be_nested_str_weak(content_open), - /* K2 */ be_nested_str_weak(text_X2Fjavascript), - /* K3 */ be_nested_str_weak(content_send), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(_QRCODE_MINJS), - }), - be_str_weak(page_qrcode_min_js), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x541200C7, // 0002 LDINT R4 200 - 0x58140002, // 0003 LDCONST R5 K2 - 0x7C080600, // 0004 CALL R2 3 - 0x8C080303, // 0005 GETMET R2 R1 K3 - 0xB8120800, // 0006 GETNGBL R4 K4 - 0x88100905, // 0007 GETMBR R4 R4 K5 - 0x7C080400, // 0008 CALL R2 2 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: page_part_mgr -********************************************************************/ -be_local_closure(Matter_UI_page_part_mgr, /* 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[14]) { /* constants */ - /* K0 */ be_nested_str_weak(webserver), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(check_privileged_access), - /* K3 */ be_nested_str_weak(content_start), - /* K4 */ be_nested_str_weak(Matter), - /* K5 */ be_nested_str_weak(content_send_style), - /* K6 */ be_nested_str_weak(content_send), - /* K7 */ be_nested_str_weak(_X3Cscript_X20type_X3D_X22text_X2Fjavascript_X22_X20src_X3D_X22qrcode_X2Emin_X2Ejs_X22_X3E_X3C_X2Fscript_X3E), - /* K8 */ be_nested_str_weak(show_enable), - /* K9 */ be_nested_str_weak(show_commissioning_info), - /* K10 */ be_nested_str_weak(show_session_info), - /* K11 */ be_nested_str_weak(content_button), - /* K12 */ be_nested_str_weak(BUTTON_CONFIGURATION), - /* K13 */ be_nested_str_weak(content_stop), - }), - be_str_weak(page_part_mgr), - &be_const_str_solidified, - ( &(const binstruction[28]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA40A0200, // 0001 IMPORT R2 K1 - 0x8C0C0302, // 0002 GETMET R3 R1 K2 - 0x7C0C0200, // 0003 CALL R3 1 - 0x740E0001, // 0004 JMPT R3 #0007 - 0x4C0C0000, // 0005 LDNIL R3 - 0x80040600, // 0006 RET 1 R3 - 0x8C0C0303, // 0007 GETMET R3 R1 K3 - 0x58140004, // 0008 LDCONST R5 K4 - 0x7C0C0400, // 0009 CALL R3 2 - 0x8C0C0305, // 000A GETMET R3 R1 K5 - 0x7C0C0200, // 000B CALL R3 1 - 0x8C0C0306, // 000C GETMET R3 R1 K6 - 0x58140007, // 000D LDCONST R5 K7 - 0x7C0C0400, // 000E CALL R3 2 - 0x8C0C0108, // 000F GETMET R3 R0 K8 - 0x7C0C0200, // 0010 CALL R3 1 - 0x780E0003, // 0011 JMPF R3 #0016 - 0x8C0C0109, // 0012 GETMET R3 R0 K9 - 0x7C0C0200, // 0013 CALL R3 1 - 0x8C0C010A, // 0014 GETMET R3 R0 K10 - 0x7C0C0200, // 0015 CALL R3 1 - 0x8C0C030B, // 0016 GETMET R3 R1 K11 - 0x8814030C, // 0017 GETMBR R5 R1 K12 - 0x7C0C0400, // 0018 CALL R3 2 - 0x8C0C030D, // 0019 GETMET R3 R1 K13 - 0x7C0C0200, // 001A CALL R3 1 - 0x80000000, // 001B RET 0 + 0x8C20032B, // 008D GETMET R8 R1 K43 + 0x8C280525, // 008E GETMET R10 R2 K37 + 0x5830002C, // 008F LDCONST R12 K44 + 0x5C340C00, // 0090 MOVE R13 R6 + 0x5C380E00, // 0091 MOVE R14 R7 + 0x7C280800, // 0092 CALL R10 4 + 0x7C200400, // 0093 CALL R8 2 + 0x8C20032D, // 0094 GETMET R8 R1 K45 + 0x8828032E, // 0095 GETMBR R10 R1 K46 + 0x7C200400, // 0096 CALL R8 2 + 0x8C20032F, // 0097 GETMET R8 R1 K47 + 0x7C200200, // 0098 CALL R8 1 + 0x70020000, // 0099 JMP #009B + 0xB0080000, // 009A RAISE 2 R0 R0 + 0x80000000, // 009B RET 0 }) ) ); @@ -867,18 +1243,21 @@ be_local_closure(Matter_UI_page_part_mgr, /* name */ be_local_class(Matter_UI, 1, NULL, - be_nested_map(10, + be_nested_map(13, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(init, -1), be_const_closure(Matter_UI_init_closure) }, - { be_const_key_weak(device, -1), be_const_var(0) }, - { be_const_key_weak(web_add_handler, -1), be_const_closure(Matter_UI_web_add_handler_closure) }, + { be_const_key_weak(show_fabric_info, -1), be_const_closure(Matter_UI_show_fabric_info_closure) }, { be_const_key_weak(page_part_ctl, -1), be_const_closure(Matter_UI_page_part_ctl_closure) }, - { be_const_key_weak(show_enable, -1), be_const_closure(Matter_UI_show_enable_closure) }, - { be_const_key_weak(show_commissioning_info, 7), be_const_closure(Matter_UI_show_commissioning_info_closure) }, - { be_const_key_weak(show_session_info, 3), be_const_closure(Matter_UI_show_session_info_closure) }, - { be_const_key_weak(web_add_config_button, 0), be_const_closure(Matter_UI_web_add_config_button_closure) }, - { be_const_key_weak(page_qrcode_min_js, -1), be_const_closure(Matter_UI_page_qrcode_min_js_closure) }, - { be_const_key_weak(page_part_mgr, -1), be_const_closure(Matter_UI_page_part_mgr_closure) }, + { be_const_key_weak(web_get_arg, -1), be_const_closure(Matter_UI_web_get_arg_closure) }, + { be_const_key_weak(page_part_mgr, 8), be_const_closure(Matter_UI_page_part_mgr_closure) }, + { be_const_key_weak(web_add_config_button, -1), be_const_closure(Matter_UI_web_add_config_button_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_UI_init_closure) }, + { be_const_key_weak(web_sensor, 10), be_const_closure(Matter_UI_web_sensor_closure) }, + { be_const_key_weak(web_add_handler, -1), be_const_closure(Matter_UI_web_add_handler_closure) }, + { be_const_key_weak(show_enable, 12), be_const_closure(Matter_UI_show_enable_closure) }, + { be_const_key_weak(show_passcode_form, 1), be_const_closure(Matter_UI_show_passcode_form_closure) }, + { be_const_key_weak(show_qrcode, 5), be_const_closure(Matter_UI_show_qrcode_closure) }, + { be_const_key_weak(show_commissioning_info, -1), be_const_closure(Matter_UI_show_commissioning_info_closure) }, + { be_const_key_weak(device, -1), be_const_var(0) }, })), be_str_weak(Matter_UI) ); diff --git a/lib/libesp32/berry_tasmota/src/be_TFL_lib.c b/lib/libesp32/berry_tasmota/src/be_TFL_lib.c new file mode 100644 index 000000000..bfc4c2b54 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_TFL_lib.c @@ -0,0 +1,47 @@ +/******************************************************************** + * Tasmota lib + * + * To use: import TFL` + *******************************************************************/ +#include "be_constobj.h" +#include "be_mapping.h" + +#ifdef USE_BERRY_TF_LITE + + +extern const char* be_TFL_log(struct bvm *vm); +BE_FUNC_CTYPE_DECLARE(be_TFL_log, "s", "@"); + +extern const char* be_TFL_stats(struct bvm *vm); +BE_FUNC_CTYPE_DECLARE(be_TFL_stats, "s", "@"); + +extern bbool be_TFL_begin(struct bvm *vm, const char* type, const uint8_t *descriptor, size_t size); +BE_FUNC_CTYPE_DECLARE(be_TFL_begin, "b", "@s[(bytes)~]"); + +extern bbool be_TFL_load(struct bvm *vm, const uint8_t *model_buf, size_t model_size, const uint8_t *output_buf, size_t output_size,int arena); +BE_FUNC_CTYPE_DECLARE(be_TFL_load, "b", "@(bytes)~(bytes)~[i]"); + +extern bbool be_TFL_input(struct bvm *vm, const uint8_t *buf, size_t size); +BE_FUNC_CTYPE_DECLARE(be_TFL_input, "b", "@(bytes)~"); + +extern bbool be_TFL_output(struct bvm *vm, const uint8_t *buf, size_t size); +BE_FUNC_CTYPE_DECLARE(be_TFL_output, "b", "@(bytes)~"); + +extern void be_TFL_rec(struct bvm *vm, const char* filename, size_t seconds); +BE_FUNC_CTYPE_DECLARE(be_TFL_rec, "", "@si"); + +#include "be_fixed_TFL.h" + +/* @const_object_info_begin +module TFL (scope: global) { + begin, ctype_func(be_TFL_begin) + load, ctype_func(be_TFL_load) + input, ctype_func(be_TFL_input) + output, ctype_func(be_TFL_output) + log, ctype_func(be_TFL_log) + stats, ctype_func(be_TFL_stats) + rec, ctype_func(be_TFL_rec) +} +@const_object_info_end */ + +#endif // USE_BERRY_TF_LITE diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c index 90c2ae7c6..621d17113 100644 --- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c @@ -67,18 +67,6 @@ extern const bclass be_class_md5; #include "be_fixed_be_class_hkdf_sha256.h" #include "be_fixed_crypto.h" -// Enable all the crypto required by Matter -#ifdef USE_BERRY_CRYPTO_SPAKE2P_MATTER - #undef USE_BERRY_CRYPTO_EC_P256 - #define USE_BERRY_CRYPTO_EC_P256 - #undef USE_BERRY_CRYPTO_HMAC_SHA256 - #define USE_BERRY_CRYPTO_HMAC_SHA256 - #undef USE_BERRY_CRYPTO_HKDF_SHA256 - #define USE_BERRY_CRYPTO_HKDF_SHA256 - #undef USE_BERRY_CRYPTO_AES_CCM - #define USE_BERRY_CRYPTO_AES_CCM -#endif - const be_const_member_t be_crypto_members[] = { // name with prefix '/' indicates a Berry class // entries need to be sorted (ignoring the prefix char) diff --git a/lib/libesp32/berry_tasmota/src/be_lv_haspmota.c b/lib/libesp32/berry_tasmota/src/be_lv_haspmota.c index 36c7aa7a8..e2063c5d0 100644 --- a/lib/libesp32/berry_tasmota/src/be_lv_haspmota.c +++ b/lib/libesp32/berry_tasmota/src/be_lv_haspmota.c @@ -41,6 +41,7 @@ extern const bclass be_class_lv_theme; extern const bclass be_class_lv_timer; extern const bclass be_class_lv_qrcode; +extern const bclass be_class_lvh_page; /******************************************************************** ** Solidified function: get_obj @@ -464,6 +465,8 @@ void be_load_lvh_page_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_obj; + /******************************************************************** ** Solidified function: set_radius2 ********************************************************************/ @@ -775,9 +778,9 @@ be_local_closure(lvh_obj_set_value_ofs_y, /* name */ ********************************************************************/ be_local_closure(lvh_obj_parse_color, /* name */ be_nested_proto( - 9, /* nstack */ + 10, /* nstack */ 1, /* argc */ - 0, /* varg */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 1, /* has sup protos */ @@ -870,59 +873,61 @@ be_local_closure(lvh_obj_parse_color, /* name */ ), }), 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(_X23), - /* K2 */ be_nested_str_weak(lv), - /* K3 */ be_nested_str_weak(color), - /* K4 */ be_nested_str_weak(string), - /* K5 */ be_nested_str_weak(introspect), - /* K6 */ be_nested_str_weak(COLOR_), - /* K7 */ be_nested_str_weak(toupper), - /* K8 */ be_nested_str_weak(get), + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_const_class(be_class_lvh_obj), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_weak(_X23), + /* K3 */ be_nested_str_weak(lv), + /* K4 */ be_nested_str_weak(color), + /* K5 */ be_nested_str_weak(string), + /* K6 */ be_nested_str_weak(introspect), + /* K7 */ be_nested_str_weak(COLOR_), + /* K8 */ be_nested_str_weak(toupper), + /* K9 */ be_nested_str_weak(get), }), be_str_weak(parse_color), &be_const_str_solidified, - ( &(const binstruction[39]) { /* code */ - 0x84040000, // 0000 CLOSURE R1 P0 - 0x60080008, // 0001 GETGBL R2 G8 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C080200, // 0003 CALL R2 1 - 0x5C000400, // 0004 MOVE R0 R2 - 0x94080100, // 0005 GETIDX R2 R0 K0 - 0x1C080501, // 0006 EQ R2 R2 K1 - 0x780A0007, // 0007 JMPF R2 #0010 - 0xB80A0400, // 0008 GETNGBL R2 K2 - 0x8C080503, // 0009 GETMET R2 R2 K3 - 0x5C100200, // 000A MOVE R4 R1 - 0x5C140000, // 000B MOVE R5 R0 - 0x7C100200, // 000C CALL R4 1 - 0x7C080400, // 000D CALL R2 2 - 0x80040400, // 000E RET 1 R2 - 0x70020011, // 000F JMP #0022 - 0xA40A0800, // 0010 IMPORT R2 K4 + ( &(const binstruction[40]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x84080000, // 0001 CLOSURE R2 P0 + 0x600C0008, // 0002 GETGBL R3 G8 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x5C000600, // 0005 MOVE R0 R3 + 0x940C0101, // 0006 GETIDX R3 R0 K1 + 0x1C0C0702, // 0007 EQ R3 R3 K2 + 0x780E0007, // 0008 JMPF R3 #0011 + 0xB80E0600, // 0009 GETNGBL R3 K3 + 0x8C0C0704, // 000A GETMET R3 R3 K4 + 0x5C140400, // 000B MOVE R5 R2 + 0x5C180000, // 000C MOVE R6 R0 + 0x7C140200, // 000D CALL R5 1 + 0x7C0C0400, // 000E CALL R3 2 + 0x80040600, // 000F RET 1 R3 + 0x70020011, // 0010 JMP #0023 0xA40E0A00, // 0011 IMPORT R3 K5 - 0x8C100507, // 0012 GETMET R4 R2 K7 - 0x5C180000, // 0013 MOVE R6 R0 - 0x7C100400, // 0014 CALL R4 2 - 0x00120C04, // 0015 ADD R4 K6 R4 - 0x8C140708, // 0016 GETMET R5 R3 K8 - 0xB81E0400, // 0017 GETNGBL R7 K2 - 0x5C200800, // 0018 MOVE R8 R4 - 0x7C140600, // 0019 CALL R5 3 - 0x4C180000, // 001A LDNIL R6 - 0x20180A06, // 001B NE R6 R5 R6 - 0x781A0004, // 001C JMPF R6 #0022 - 0xB81A0400, // 001D GETNGBL R6 K2 - 0x8C180D03, // 001E GETMET R6 R6 K3 - 0x5C200A00, // 001F MOVE R8 R5 - 0x7C180400, // 0020 CALL R6 2 - 0x80040C00, // 0021 RET 1 R6 - 0xB80A0400, // 0022 GETNGBL R2 K2 - 0x8C080503, // 0023 GETMET R2 R2 K3 - 0x58100000, // 0024 LDCONST R4 K0 - 0x7C080400, // 0025 CALL R2 2 - 0x80040400, // 0026 RET 1 R2 + 0xA4120C00, // 0012 IMPORT R4 K6 + 0x8C140708, // 0013 GETMET R5 R3 K8 + 0x5C1C0000, // 0014 MOVE R7 R0 + 0x7C140400, // 0015 CALL R5 2 + 0x00160E05, // 0016 ADD R5 K7 R5 + 0x8C180909, // 0017 GETMET R6 R4 K9 + 0xB8220600, // 0018 GETNGBL R8 K3 + 0x5C240A00, // 0019 MOVE R9 R5 + 0x7C180600, // 001A CALL R6 3 + 0x4C1C0000, // 001B LDNIL R7 + 0x201C0C07, // 001C NE R7 R6 R7 + 0x781E0004, // 001D JMPF R7 #0023 + 0xB81E0600, // 001E GETNGBL R7 K3 + 0x8C1C0F04, // 001F GETMET R7 R7 K4 + 0x5C240C00, // 0020 MOVE R9 R6 + 0x7C1C0400, // 0021 CALL R7 2 + 0x80040E00, // 0022 RET 1 R7 + 0xB80E0600, // 0023 GETNGBL R3 K3 + 0x8C0C0704, // 0024 GETMET R3 R3 K4 + 0x58140001, // 0025 LDCONST R5 K1 + 0x7C0C0400, // 0026 CALL R3 2 + 0x80040600, // 0027 RET 1 R3 }) ) ); @@ -1394,45 +1399,47 @@ be_local_closure(lvh_obj_val_rule_matched, /* name */ ********************************************************************/ be_local_closure(lvh_obj_remove_trailing_zeroes, /* name */ be_nested_proto( - 7, /* nstack */ + 8, /* nstack */ 1, /* argc */ - 0, /* varg */ + 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_int(0), - /* K1 */ be_const_int(1), - /* K2 */ be_nested_str_weak(resize), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_lvh_obj), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + /* K3 */ be_nested_str_weak(resize), }), be_str_weak(remove_trailing_zeroes), &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0x6004000C, // 0000 GETGBL R1 G12 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x58080000, // 0003 LDCONST R2 K0 - 0x140C0401, // 0004 LT R3 R2 R1 - 0x780E0007, // 0005 JMPF R3 #000E - 0x540DFFFE, // 0006 LDINT R3 -1 - 0x040C0602, // 0007 SUB R3 R3 R2 - 0x940C0003, // 0008 GETIDX R3 R0 R3 - 0x200C0700, // 0009 NE R3 R3 K0 - 0x780E0000, // 000A JMPF R3 #000C - 0x70020001, // 000B JMP #000E - 0x00080501, // 000C ADD R2 R2 K1 - 0x7001FFF5, // 000D JMP #0004 - 0x240C0500, // 000E GT R3 R2 K0 - 0x780E0005, // 000F JMPF R3 #0016 - 0x8C0C0102, // 0010 GETMET R3 R0 K2 - 0x6014000C, // 0011 GETGBL R5 G12 - 0x5C180000, // 0012 MOVE R6 R0 - 0x7C140200, // 0013 CALL R5 1 - 0x04140A02, // 0014 SUB R5 R5 R2 - 0x7C0C0400, // 0015 CALL R3 2 - 0x80040000, // 0016 RET 1 R0 + ( &(const binstruction[24]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C080200, // 0003 CALL R2 1 + 0x580C0001, // 0004 LDCONST R3 K1 + 0x14100602, // 0005 LT R4 R3 R2 + 0x78120007, // 0006 JMPF R4 #000F + 0x5411FFFE, // 0007 LDINT R4 -1 + 0x04100803, // 0008 SUB R4 R4 R3 + 0x94100004, // 0009 GETIDX R4 R0 R4 + 0x20100901, // 000A NE R4 R4 K1 + 0x78120000, // 000B JMPF R4 #000D + 0x70020001, // 000C JMP #000F + 0x000C0702, // 000D ADD R3 R3 K2 + 0x7001FFF5, // 000E JMP #0005 + 0x24100701, // 000F GT R4 R3 K1 + 0x78120005, // 0010 JMPF R4 #0017 + 0x8C100103, // 0011 GETMET R4 R0 K3 + 0x6018000C, // 0012 GETGBL R6 G12 + 0x5C1C0000, // 0013 MOVE R7 R0 + 0x7C180200, // 0014 CALL R6 1 + 0x04180C03, // 0015 SUB R6 R6 R3 + 0x7C100400, // 0016 CALL R4 2 + 0x80040000, // 0017 RET 1 R0 }) ) ); @@ -2414,32 +2421,34 @@ be_local_closure(lvh_obj_get_obj, /* name */ ********************************************************************/ be_local_closure(lvh_obj_is_color_attribute, /* name */ be_nested_proto( - 8, /* nstack */ + 9, /* nstack */ 1, /* argc */ - 0, /* varg */ + 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_nested_str_weak(re), - /* K1 */ be_nested_str_weak(search), - /* K2 */ be_nested_str_weak(color_X24), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_lvh_obj), + /* K1 */ be_nested_str_weak(re), + /* K2 */ be_nested_str_weak(search), + /* K3 */ be_nested_str_weak(color_X24), }), be_str_weak(is_color_attribute), &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x60080017, // 0001 GETGBL R2 G23 - 0x8C0C0301, // 0002 GETMET R3 R1 K1 - 0x58140002, // 0003 LDCONST R5 K2 - 0x60180008, // 0004 GETGBL R6 G8 - 0x5C1C0000, // 0005 MOVE R7 R0 - 0x7C180200, // 0006 CALL R6 1 - 0x7C0C0600, // 0007 CALL R3 3 - 0x7C080200, // 0008 CALL R2 1 - 0x80040400, // 0009 RET 1 R2 + ( &(const binstruction[11]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x600C0017, // 0002 GETGBL R3 G23 + 0x8C100502, // 0003 GETMET R4 R2 K2 + 0x58180003, // 0004 LDCONST R6 K3 + 0x601C0008, // 0005 GETGBL R7 G8 + 0x5C200000, // 0006 MOVE R8 R0 + 0x7C1C0200, // 0007 CALL R7 1 + 0x7C100600, // 0008 CALL R4 3 + 0x7C0C0200, // 0009 CALL R3 1 + 0x80040600, // 000A RET 1 R3 }) ) ); @@ -4030,6 +4039,8 @@ void be_load_lvh_obj_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_scr; + /******************************************************************** ** Solidified class: lvh_scr ********************************************************************/ @@ -4051,6 +4062,8 @@ void be_load_lvh_scr_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_btn; + /******************************************************************** ** Solidified class: lvh_btn ********************************************************************/ @@ -4072,12 +4085,14 @@ void be_load_lvh_btn_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_switch; + /******************************************************************** -** Solidified function: set_val +** Solidified function: set_radius20 ********************************************************************/ -be_local_closure(lvh_switch_set_val, /* name */ +be_local_closure(lvh_switch_set_radius20, /* name */ be_nested_proto( - 5, /* nstack */ + 7, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -4085,16 +4100,28 @@ be_local_closure(lvh_switch_set_val, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(set_toggle), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_lv_obj), + /* K1 */ be_nested_str_weak(set_style_radius), + /* K2 */ be_nested_str_weak(lv), + /* K3 */ be_nested_str_weak(PART_KNOB), + /* K4 */ be_nested_str_weak(STATE_DEFAULT), }), - be_str_weak(set_val), + be_str_weak(set_radius20), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x7C080400, // 0002 CALL R2 2 - 0x80040400, // 0003 RET 1 R2 + ( &(const binstruction[12]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x60100009, // 0002 GETGBL R4 G9 + 0x5C140200, // 0003 MOVE R5 R1 + 0x7C100200, // 0004 CALL R4 1 + 0xB8160400, // 0005 GETNGBL R5 K2 + 0x88140B03, // 0006 GETMBR R5 R5 K3 + 0xB81A0400, // 0007 GETNGBL R6 K2 + 0x88180D04, // 0008 GETMBR R6 R6 K4 + 0x30140A06, // 0009 OR R5 R5 R6 + 0x7C080600, // 000A CALL R2 3 + 0x80000000, // 000B RET 0 }) ) ); @@ -4129,6 +4156,221 @@ be_local_closure(lvh_switch_get_val, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_bg_color10 +********************************************************************/ +be_local_closure(lvh_switch_get_bg_color10, /* 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(_lv_obj), + /* K1 */ be_nested_str_weak(get_style_bg_color), + /* K2 */ be_nested_str_weak(lv), + /* K3 */ be_nested_str_weak(PART_INDICATOR), + }), + be_str_weak(get_bg_color10), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x880C0703, // 0003 GETMBR R3 R3 K3 + 0x7C040400, // 0004 CALL R1 2 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_bg_color20 +********************************************************************/ +be_local_closure(lvh_switch_set_bg_color20, /* 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(_lv_obj), + /* K1 */ be_nested_str_weak(set_style_bg_color), + /* K2 */ be_nested_str_weak(parse_color), + /* K3 */ be_nested_str_weak(lv), + /* K4 */ be_nested_str_weak(PART_KNOB), + /* K5 */ be_nested_str_weak(STATE_DEFAULT), + }), + be_str_weak(set_bg_color20), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x8C100102, // 0002 GETMET R4 R0 K2 + 0x5C180200, // 0003 MOVE R6 R1 + 0x7C100400, // 0004 CALL R4 2 + 0xB8160600, // 0005 GETNGBL R5 K3 + 0x88140B04, // 0006 GETMBR R5 R5 K4 + 0xB81A0600, // 0007 GETNGBL R6 K3 + 0x88180D05, // 0008 GETMBR R6 R6 K5 + 0x30140A06, // 0009 OR R5 R5 R6 + 0x7C080600, // 000A CALL R2 3 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_bg_color10 +********************************************************************/ +be_local_closure(lvh_switch_set_bg_color10, /* 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(_lv_obj), + /* K1 */ be_nested_str_weak(set_style_bg_color), + /* K2 */ be_nested_str_weak(parse_color), + /* K3 */ be_nested_str_weak(lv), + /* K4 */ be_nested_str_weak(PART_INDICATOR), + /* K5 */ be_nested_str_weak(STATE_CHECKED), + }), + be_str_weak(set_bg_color10), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x8C100102, // 0002 GETMET R4 R0 K2 + 0x5C180200, // 0003 MOVE R6 R1 + 0x7C100400, // 0004 CALL R4 2 + 0xB8160600, // 0005 GETNGBL R5 K3 + 0x88140B04, // 0006 GETMBR R5 R5 K4 + 0xB81A0600, // 0007 GETNGBL R6 K3 + 0x88180D05, // 0008 GETMBR R6 R6 K5 + 0x30140A06, // 0009 OR R5 R5 R6 + 0x7C080600, // 000A CALL R2 3 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_val +********************************************************************/ +be_local_closure(lvh_switch_set_val, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(set_toggle), + }), + be_str_weak(set_val), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x80040400, // 0003 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_radius20 +********************************************************************/ +be_local_closure(lvh_switch_get_radius20, /* 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(_lv_obj), + /* K1 */ be_nested_str_weak(get_style_radius), + /* K2 */ be_nested_str_weak(lv), + /* K3 */ be_nested_str_weak(PART_KNOB), + }), + be_str_weak(get_radius20), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x880C0703, // 0003 GETMBR R3 R3 K3 + 0x7C040400, // 0004 CALL R1 2 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_bg_color20 +********************************************************************/ +be_local_closure(lvh_switch_get_bg_color20, /* 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(_lv_obj), + /* K1 */ be_nested_str_weak(get_style_bg_color), + /* K2 */ be_nested_str_weak(lv), + /* K3 */ be_nested_str_weak(PART_KNOB), + }), + be_str_weak(get_bg_color20), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0xB80E0400, // 0002 GETNGBL R3 K2 + 0x880C0703, // 0003 GETMBR R3 R3 K3 + 0x7C040400, // 0004 CALL R1 2 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: lvh_switch ********************************************************************/ @@ -4136,12 +4378,18 @@ extern const bclass be_class_lvh_obj; be_local_class(lvh_switch, 0, &be_class_lvh_obj, - be_nested_map(4, + be_nested_map(10, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(get_val, 1), be_const_closure(lvh_switch_get_val_closure) }, + { be_const_key_weak(set_radius20, -1), be_const_closure(lvh_switch_set_radius20_closure) }, + { be_const_key_weak(get_val, -1), be_const_closure(lvh_switch_get_val_closure) }, + { be_const_key_weak(get_bg_color10, 9), be_const_closure(lvh_switch_get_bg_color10_closure) }, + { be_const_key_weak(set_bg_color20, 8), be_const_closure(lvh_switch_set_bg_color20_closure) }, + { be_const_key_weak(set_bg_color10, -1), be_const_closure(lvh_switch_set_bg_color10_closure) }, { be_const_key_weak(set_val, -1), be_const_closure(lvh_switch_set_val_closure) }, + { be_const_key_weak(get_radius20, -1), be_const_closure(lvh_switch_get_radius20_closure) }, + { be_const_key_weak(_lv_class, -1), be_const_class(be_class_lv_switch) }, + { be_const_key_weak(get_bg_color20, -1), be_const_closure(lvh_switch_get_bg_color20_closure) }, { be_const_key_weak(_lv_part2_selector, -1), be_const_int(196608) }, - { be_const_key_weak(_lv_class, 0), be_const_class(be_class_lv_switch) }, })), be_str_weak(lvh_switch) ); @@ -4153,6 +4401,8 @@ void be_load_lvh_switch_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_checkbox; + /******************************************************************** ** Solidified class: lvh_checkbox ********************************************************************/ @@ -4174,6 +4424,8 @@ void be_load_lvh_checkbox_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_label; + /******************************************************************** ** Solidified function: post_init ********************************************************************/ @@ -4231,6 +4483,8 @@ void be_load_lvh_label_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_spinner; + /******************************************************************** ** Solidified function: set_angle ********************************************************************/ @@ -4475,6 +4729,8 @@ void be_load_lvh_spinner_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_line; + /******************************************************************** ** Solidified class: lvh_line ********************************************************************/ @@ -4496,6 +4752,8 @@ void be_load_lvh_line_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_img; + /******************************************************************** ** Solidified function: set_angle ********************************************************************/ @@ -4584,6 +4842,8 @@ void be_load_lvh_img_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_roller; + /******************************************************************** ** Solidified function: set_options ********************************************************************/ @@ -4815,6 +5075,8 @@ void be_load_lvh_roller_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_btnmatrix; + /******************************************************************** ** Solidified class: lvh_btnmatrix ********************************************************************/ @@ -4836,6 +5098,8 @@ void be_load_lvh_btnmatrix_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_bar; + /******************************************************************** ** Solidified class: lvh_bar ********************************************************************/ @@ -4857,6 +5121,8 @@ void be_load_lvh_bar_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_slider; + /******************************************************************** ** Solidified function: set_val ********************************************************************/ @@ -4912,6 +5178,8 @@ void be_load_lvh_slider_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_arc; + /******************************************************************** ** Solidified function: set_line_width1 ********************************************************************/ @@ -5308,6 +5576,8 @@ void be_load_lvh_arc_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_textarea; + /******************************************************************** ** Solidified class: lvh_textarea ********************************************************************/ @@ -5329,6 +5599,8 @@ void be_load_lvh_textarea_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_dropdown; + /******************************************************************** ** Solidified function: get_val ********************************************************************/ @@ -5732,6 +6004,8 @@ void be_load_lvh_dropdown_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_lvh_qrcode; + /******************************************************************** ** Solidified function: get_qr_size ********************************************************************/ @@ -6032,6 +6306,8 @@ void be_load_lvh_qrcode_class(bvm *vm) { be_pop(vm, 1); } +extern const bclass be_class_HASPmota; + /******************************************************************** ** Solidified function: do_action ********************************************************************/ @@ -6880,51 +7156,53 @@ be_local_closure(HASPmota_parse, /* name */ ********************************************************************/ be_local_closure(HASPmota_sort, /* name */ be_nested_proto( - 6, /* nstack */ + 7, /* nstack */ 1, /* argc */ - 0, /* varg */ + 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_int(1), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str_weak(stop_iteration), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_HASPmota), + /* K1 */ be_const_int(1), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(stop_iteration), }), be_str_weak(sort), &be_const_str_solidified, - ( &(const binstruction[29]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x6008000C, // 0001 GETGBL R2 G12 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C080200, // 0003 CALL R2 1 - 0x04080500, // 0004 SUB R2 R2 K0 - 0x400A0002, // 0005 CONNECT R2 K0 R2 - 0x7C040200, // 0006 CALL R1 1 - 0xA8020010, // 0007 EXBLK 0 #0019 - 0x5C080200, // 0008 MOVE R2 R1 - 0x7C080000, // 0009 CALL R2 0 - 0x940C0002, // 000A GETIDX R3 R0 R2 - 0x5C100400, // 000B MOVE R4 R2 - 0x24140901, // 000C GT R5 R4 K1 - 0x78160008, // 000D JMPF R5 #0017 - 0x04140900, // 000E SUB R5 R4 K0 - 0x94140005, // 000F GETIDX R5 R0 R5 - 0x24140A03, // 0010 GT R5 R5 R3 - 0x78160004, // 0011 JMPF R5 #0017 - 0x04140900, // 0012 SUB R5 R4 K0 - 0x94140005, // 0013 GETIDX R5 R0 R5 - 0x98000805, // 0014 SETIDX R0 R4 R5 - 0x04100900, // 0015 SUB R4 R4 K0 - 0x7001FFF4, // 0016 JMP #000C - 0x98000803, // 0017 SETIDX R0 R4 R3 - 0x7001FFEE, // 0018 JMP #0008 - 0x58040002, // 0019 LDCONST R1 K2 - 0xAC040200, // 001A CATCH R1 1 0 - 0xB0080000, // 001B RAISE 2 R0 R0 - 0x80040000, // 001C RET 1 R0 + ( &(const binstruction[30]) { /* 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 + 0x80040000, // 001D RET 1 R0 }) ) ); diff --git a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp index dad697ba0..aa7629519 100644 --- a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp +++ b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp @@ -129,6 +129,44 @@ static int32_t m_mdns_add_service(struct bvm *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 @@ -309,6 +347,7 @@ module mdns (scope: global) { 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) diff --git a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c index 0f27586ab..8b64ce03b 100644 --- a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c @@ -58,27 +58,29 @@ extern int l_getswitch(bvm *vm); extern int l_i2cenabled(bvm *vm); extern int tasm_find_op(bvm *vm); +extern int tasm_apply_str_op(bvm *vm); #include "solidify/solidified_tasmota_class.h" +#include "solidify/solidified_rule_matcher.h" +#include "solidify/solidified_trigger_class.h" #include "be_fixed_be_class_tasmota.h" - /* @const_object_info_begin class be_class_tasmota (scope: global, name: Tasmota) { - _fl, var - _rules, var - _timers, var - _crons, var - _ccmd, var - _drivers, var - wire1, var - wire2, var - cmd_res, var - global, var - settings, var - wd, var - _debug_present, var + _fl, var // list of active fast-loop object (faster than drivers) + _rules, var // list of active rules + _timers, var // list of active timers + _crons, var // list of active crons + _ccmd, var // list of active Tasmota commands implemented in Berry + _drivers, var // list of active drivers + wire1, var // Tasmota I2C Wire1 + wire2, var // Tasmota I2C Wire2 + cmd_res, var // store the command result, nil if disables, true if capture enabled, contains return value + global, var // mapping to TasmotaGlobal + settings, var // mapping to Tasmota Settings + wd, var // working dir + _debug_present, var // is `import debug` present? _global_def, comptr(&be_tasmota_global_struct) _settings_def, comptr(&be_tasmota_settings_struct) @@ -137,6 +139,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { remove_fast_loop, closure(Tasmota_remove_fast_loop_closure) cmd, closure(Tasmota_cmd_closure) _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_op, closure(Tasmota_find_op_closure) add_rule, closure(Tasmota_add_rule_closure) @@ -173,5 +176,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { get_light, closure(Tasmota_get_light_closure) set_light, closure(Tasmota_set_light_closure) + + Rule_Matcher, class(be_class_Rule_Matcher) } @const_object_info_end */ diff --git a/lib/libesp32/berry_tasmota/src/be_webclient_lib.c b/lib/libesp32/berry_tasmota/src/be_webclient_lib.c index ace4499a2..a5c888d01 100644 --- a/lib/libesp32/berry_tasmota/src/be_webclient_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_webclient_lib.c @@ -14,7 +14,10 @@ extern int wc_urlencode(bvm *vm); extern int wc_begin(bvm *vm); extern int wc_set_timeouts(bvm *vm); extern int wc_set_useragent(bvm *vm); +extern int wc_set_follow_redirects(bvm *vm); extern int wc_set_auth(bvm *vm); +extern int wc_collect_headers(bvm *vm); +extern int wc_get_header(bvm *vm); extern int wc_connected(bvm *vm); extern int wc_close(bvm *vm); extern int wc_addheader(bvm *vm); @@ -47,7 +50,13 @@ class be_class_webclient (scope: global, name: webclient) { begin, func(wc_begin) set_timeouts, func(wc_set_timeouts) set_useragent, func(wc_set_useragent) + set_follow_redirects, func(wc_set_follow_redirects) set_auth, func(wc_set_auth) + + // collect response headers + collect_headers, func(wc_collect_headers) + get_header, func(wc_get_header) + close, func(wc_close) add_header, func(wc_addheader) GET, func(wc_GET) diff --git a/lib/libesp32/berry_tasmota/src/be_webserver_lib.c b/lib/libesp32/berry_tasmota/src/be_webserver_lib.c index ad7bcadd7..0cdf4ede0 100644 --- a/lib/libesp32/berry_tasmota/src/be_webserver_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_webserver_lib.c @@ -24,6 +24,8 @@ extern int w_webserver_content_flush(bvm *vm); extern int w_webserver_content_stop(bvm *vm); extern int w_webserver_content_button(bvm *vm); +extern int w_webserver_html_escape(bvm *vm); + extern int w_webserver_argsize(bvm *vm); extern int w_webserver_arg(bvm *vm); extern int w_webserver_arg_name(bvm *vm); @@ -48,6 +50,8 @@ module webserver (scope: global) { content_stop, func(w_webserver_content_stop) content_button, func(w_webserver_content_button) + html_escape, func(w_webserver_html_escape) + arg_size, func(w_webserver_argsize) arg, func(w_webserver_arg) arg_name, func(w_webserver_arg_name) diff --git a/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be b/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be new file mode 100644 index 000000000..a3005e6b1 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/embedded/rule_matcher.be @@ -0,0 +1,368 @@ +#- Native code used for testing and code solidification -# +#- Do not use it directly -# + +#@ solidify:Rule_Matcher_Key +#@ solidify:Rule_Matcher_Wildcard +#@ solidify:Rule_Matcher_Operator +#@ solidify:Rule_Matcher_Array +#@ solidify:Rule_Matcher + + +#- +# tests + +tasmota.Rule_Matcher.parse("AA#BB#CC") +# [, , ] + +tasmota.Rule_Matcher.parse("AA") +# [] + +tasmota.Rule_Matcher.parse("AA#BB#CC=2") +# [, , , ] + +tasmota.Rule_Matcher.parse("AA#BB#CC>=3.5") +# [, , , =' val='3.5'>] + +tasmota.Rule_Matcher.parse("AA#BB#CC!3.5") +# [, , ] + +tasmota.Rule_Matcher.parse("AA#BB#CC==3=5") +# [, , , ] + +tasmota.Rule_Matcher.parse("AA#BB#!CC!==3=5") +# [, , , ] + +tasmota.Rule_Matcher.parse("") +# [] + +tasmota.Rule_Matcher.parse("A#?#B") +# [, , ] + +tasmota.Rule_Matcher.parse("A#?>50") +# [, , ' val='50'>] + +tasmota.Rule_Matcher.parse("A[1]") +# [, ] + +tasmota.Rule_Matcher.parse("A[1]#B[2]>3") +# [, , , , ' val='3'>] + +tasmota.Rule_Matcher.parse("A#B[]>3") +# [, , , ' val='3'>] + +################################################################################# + +m = tasmota.Rule_Matcher.parse("AA") +assert(m.match({'aa':1}) == 1) +assert(m.match({'AA':'1'}) == '1') +assert(m.match({'ab':1}) == nil) + +m = tasmota.Rule_Matcher.parse("AA#BB") +assert(m.match({'aa':1}) == nil) +assert(m.match({'aa':{'bb':1}}) == 1) + +m = tasmota.Rule_Matcher.parse("AA#BB#CC==2") +assert(m.match({'aa':1}) == nil) +assert(m.match({'aa':{'bb':1}}) == nil) +assert(m.match({'aa':{'bb':{'cc':1}}}) == nil) +assert(m.match({'aa':{'bb':{'cc':2}}}) == 2) + +m = tasmota.Rule_Matcher.parse("AA#?#CC==2") +assert(m.match({'aa':1}) == nil) +assert(m.match({'aa':{'bb':{'cc':2}}}) == 2) + +m = tasmota.Rule_Matcher.parse("AA#Power[1]") +assert(m.match({'aa':{'power':[0.5,1.5,2.5]}}) == 0.5) +m = tasmota.Rule_Matcher.parse("AA#Power[2]") +assert(m.match({'aa':{'power':[0.5,1.5,2.5]}}) == 1.5) +m = tasmota.Rule_Matcher.parse("AA#Power[3]") +assert(m.match({'aa':{'power':[0.5,1.5,2.5]}}) == 2.5) +m = tasmota.Rule_Matcher.parse("AA#Power[4]") +assert(m.match({'aa':{'power':[0.5,1.5,2.5]}}) == nil) + +m = tasmota.Rule_Matcher.parse("AA#Power[1]>1") +assert(m.match({'aa':{'power':[0.5,1.5,2.5]}}) == nil) +assert(m.match({'aa':{'power':[1.2,1.5,2.5]}}) == 1.2) + +-# + +class Rule_Matcher + + # We don't actually need a superclass, just implementing `match(val)` + # + # static class Rule_Matcher + # def init() + # end + + # # return the next index in tha val string + # # or `nil` if no match + # def match(val) + # return nil + # end + # end + + # Each matcher is an instance that implements `match(val) -> any or nil` + # + # The method takes a map or value as input, applies the matcher and + # returns a new map or value, or `nil` if the matcher did not match anything. + # + # Example: + # Payload#?#Temperature>50 + # is decomposed as: + # , , + # + # Instance types: + # Rule_Matcher_Key(key): checks that the input map contains the key (case insensitive) and + # returns the sub-value or `nil` if the key does not exist + # + # Rule_Matcher_Wildcard: maps any key, which yields to unpredictable behavior if the map + # has multiple keys (gets the first key returned by the iterator) + # + # Rule_Matcher_Operator: checks is a simple value (numerical or string) matches the operator and the value + # returns the value unchanged if match, or `nil` if no match + + static class Rule_Matcher_Key + var name # literal name of what to match + + def init(name) + self.name = name + end + + # find a key in map, case insensitive, return actual key or nil if not found + static def find_key_i(m, keyi) + import string + var keyu = string.toupper(keyi) + if isinstance(m, map) + for k:m.keys() + if string.toupper(k)==keyu + return k + end + end + end + end + + def match(val) + if val == nil return nil end # safeguard + if !isinstance(val, map) return nil end # literal name can only match a map key + var k = self.find_key_i(val, self.name) + if k == nil return nil end # no key with value self.name + return val[k] + end + + def tostring() + return "" + end + end + + static class Rule_Matcher_Array + var index # index in the array, defaults to zero + + def init(index) + self.index = index + end + + def match(val) + if val == nil return nil end # safeguard + if !isinstance(val, list) return val end # ignore index if not a list + if self.index <= 0 return nil end # out of bounds + if self.index > size(val) return nil end # out of bounds + return val[self.index - 1] + end + + def tostring() + return "" + end + end + + static class Rule_Matcher_Wildcard + + def match(val) + if val == nil return nil end # safeguard + if !isinstance(val, map) return nil end # literal name can only match a map key + if size(val) == 0 return nil end + return val.iter()() # get first value from iterator + end + + def tostring() + return "" + end + end + + static class Rule_Matcher_Operator + var op_func # function making the comparison + var op_str # name of the operator like '>' + var op_value # value to compare agains + + def init(op_str, op_value) + self.op_parse(op_str, op_value) + end + + + ########################################################################################### + # Functions to compare two values + ########################################################################################### + def op_parse(op, op_value) + self.op_str = op + + def op_eq_str(a,b) return tasmota._apply_str_op(1, str(a), b) end + def op_neq_str(a,b) return tasmota._apply_str_op(2, str(a), b) end + def op_start_str(a,b) return tasmota._apply_str_op(3, str(a), b) end + def op_end_str(a,b) return tasmota._apply_str_op(4, str(a), b) end + def op_sub_str(a,b) return tasmota._apply_str_op(5, str(a), b) end + def op_notsub_str(a,b) return tasmota._apply_str_op(6, str(a), b) end + def op_eq(a,b) return number(a) == b end + def op_neq(a,b) return number(a) != b end + def op_gt(a,b) return number(a) > b end + def op_gte(a,b) return number(a) >= b end + def op_lt(a,b) return number(a) < b end + def op_lte(a,b) return number(a) <= b end + def op_mod(a,b) return (int(a) % b) == 0 end + + var numerical = false + var f + + if op=='=' f = op_eq_str + elif op=='!==' f = op_neq_str + elif op=='$!' f = op_neq_str + elif op=='$<' f = op_start_str + elif op=='$>' f = op_end_str + elif op=='$|' f = op_sub_str + elif op=='$^' f = op_notsub_str + else + numerical = true + if op=='==' f = op_eq + elif op=='!=' f = op_neq + elif op=='>' f = op_gt + elif op=='>=' f = op_gte + elif op=='<' f = op_lt + elif op=='<=' f = op_lte + elif op=='|' f = op_mod + end + end + + self.op_func = f + if numerical # if numerical comparator, make sure that the value passed is a number + # to check if a number is correct, the safest method is to use a json decoder + import json + var val_num = json.load(op_value) + if type(val_num) != 'int' && type(val_num) != 'real' + raise "value_error", "value needs to be a number" + else + self.op_value = val_num + end + else + self.op_value = str(op) + end + + end + + def match(val) + var t = type(val) + if t != 'int' && t != 'real' && t != 'string' return nil end # must be a simple type + return self.op_func(val, self.op_value) ? val : nil + end + + def tostring() + if type(self.op_value) == 'string' + return "" + else + return "" + end + end + end + + ########################################################################################### + # instance variables + var rule # original pattern of the rules + var trigger # rule pattern of trigger, excluding operator check (ex: "AA#BB>50" would be "AA#BB") + var matchers # array of Rule_Matcher(s) + + def init(rule, trigger, matchers) + self.rule = rule + self.trigger = trigger + self.matchers = matchers + end + + # parses a rule pattern and creates a list of Rule_Matcher(s) + static def parse(pattern) + import string + if pattern == nil return nil end + + var matchers = [] + + # changes "Dimmer>50" to ['Dimmer', '>', '50'] + # Ex: DS18B20#Temperature<20 + var op_list = tasmota.find_op(pattern) + + # ex: 'DS18B20#Temperature' + var value_str = op_list[0] + var op_str = op_list[1] + var op_value = op_list[2] + + var sz = size(value_str) + var idx_start = 0 # index of current cursor + var idx_end = -1 # end of current item + + while idx_start < sz + # split by '#' + var idx_sep = string.find(value_str, '#', idx_start) + var item_str + if idx_sep >= 0 + if idx_sep == idx_start raise "pattern_error", "empty pattern not allowed" end + item_str = value_str[idx_start .. idx_sep - 1] + idx_start = idx_sep + 1 + else + item_str = value_str[idx_start .. ] + idx_start = sz # will end the loop + end + + # check if there is an array accessor + var arr_start = string.find(item_str, '[') + var arr_index = nil + if arr_start >= 0 # we have an array index + var arr_end = string.find(item_str, ']', arr_start) + if arr_end < 0 raise "value_error", "missing ']' in rule pattern" end + var arr_str = item_str[arr_start + 1 .. arr_end - 1] + item_str = item_str[0 .. arr_start - 1] # truncate + arr_index = int(arr_str) + end + + if item_str == '?' + matchers.push(_class.Rule_Matcher_Wildcard()) + else + matchers.push(_class.Rule_Matcher_Key(item_str)) + end + + if arr_index != nil + matchers.push(_class.Rule_Matcher_Array(arr_index)) + end + end + + # if an operator was found, add the operator matcher + if op_str != nil && op_value != nil # we have an operator + matchers.push(_class.Rule_Matcher_Operator(op_str, op_value)) + end + + return _class(pattern, value_str, matchers) # `_class` is a reference to the Rule_Matcher class + end + + # apply all matchers, abort if any returns `nil` + def match(val_in) + if self.matchers == nil return nil end + var val = val_in + + var idx = 0 + while idx < size(self.matchers) + val = self.matchers[idx].match(val) + if val == nil return nil end + idx += 1 + end + + return val + end + + def tostring() + return str(self.matchers) + end + +end diff --git a/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be b/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be index 03d36637a..1295436bd 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be +++ b/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be @@ -1,7 +1,8 @@ #- Native code used for testing and code solidification -# #- Do not use it -# -class Trigger end # for compilation +class Trigger end # for compilation +class Rule_Matche end # for compilation tasmota = nil #@ solidify:Tasmota @@ -65,22 +66,18 @@ class Tasmota # split the item when there is an operator, returns a list of (left,op,right) - # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"] + #- + assert(tasmota.find_op("Dimmer>50") == ['Dimmer', '>', '50']) + assert(tasmota.find_op("Dimmer") == ['Dimmer', nil, nil]) + assert(tasmota.find_op("Status!==Connected") == ['Status', '!==', 'Connected']) + -# def find_op(item) - import string - var op_chars = '=<>!' - var pos = self._find_op(item, false) # initial run - if pos >= 0 - var op_split = string.split(item,pos) - var op_left = op_split[0] - var op_rest = op_split[1] - pos = self._find_op(op_rest, true) - if pos >= 0 - var op_split2 = string.split(op_rest,pos) - var op_middle = op_split2[0] - var op_right = op_split2[1] - return [op_left,op_middle,op_right] - end + var idx_composite = self._find_op(item) + if idx_composite >= 0 + var idx_start = idx_composite & 0x7FFF + var idx_end = idx_composite >> 16 + + return [ item[0 .. idx_start-1], item[idx_start .. idx_end - 1], item[idx_end ..]] end return [item, nil, nil] end @@ -92,7 +89,7 @@ class Tasmota self._rules=[] end if type(f) == 'function' - self._rules.push(Trigger(pat, f, id)) + self._rules.push(Trigger(self.Rule_Matcher.parse(pat), f, id)) else raise 'value_error', 'the second argument is not a function' end @@ -102,7 +99,7 @@ class Tasmota if self._rules var i = 0 while i < size(self._rules) - if self._rules[i].trig == pat && self._rules[i].id == id + if self._rules[i].trig.rule == pat && self._rules[i].id == id self._rules.remove(i) #- don't increment i since we removed the object -# else i += 1 @@ -112,43 +109,19 @@ class Tasmota end # Rules trigger if match. return true if match, false if not - def try_rule(event, rule, f) - import string - var rl_list = self.find_op(rule) - var sub_event = event - var rl = string.split(rl_list[0],'#') - var i = 0 - while i < size(rl) - # for it:rl - var it = rl[i] - var found=self.find_key_i(sub_event,it) - if found == nil return false end - sub_event = sub_event[found] - i += 1 - end - var op=rl_list[1] - var op2=rl_list[2] - if op - if op=='==' - if str(sub_event) != str(op2) return false end - elif op=='!==' - if str(sub_event) == str(op2) return false end - elif op=='=' - if real(sub_event) != real(op2) return false end - elif op=='!=' - if real(sub_event) == real(op2) return false end - elif op=='>' - if real(sub_event) <= real(op2) return false end - elif op=='>=' - if real(sub_event) < real(op2) return false end - elif op=='<' - if real(sub_event) >= real(op2) return false end - elif op=='<=' - if real(sub_event) > real(op2) return false end + # + # event: native Berry map representing the JSON input + # rule: Rule_Matcher instance + # f: callback to call in case of a match + def try_rule(event, rule_matcher, f) + var sub_event = rule_matcher.match(event) + if sub_event != nil + if f != nil + f(sub_event, rule_matcher.trigger, event) end + return true end - f(sub_event, rl_list[0], event) - return true + return false end # Run rules, i.e. check each individual rule @@ -162,7 +135,7 @@ class Tasmota self.cmd_res = nil # disable sunsequent recording of results var ret = false - var ev = json.load(ev_json) # returns nil if invalid JSON + var ev = json.load(ev_json) # returns nil if invalid JSON if ev == nil self.log('BRY: ERROR, bad json: '+ev_json, 3) ev = ev_json # revert to string @@ -567,7 +540,8 @@ class Tasmota # iterate and call each closure var i = 0 - while i < size(fl) + var sz = size(fl) + while i < sz # note: this is not guarded in try/except for performance reasons. The inner function must not raise exceptions fl[i]() i += 1 @@ -663,10 +637,21 @@ class Tasmota end # cmd high-level function - def cmd(command) + # mute: (opt, bool) if true temporarily reduce log_level to 1 + def cmd(command, mute) var save_cmd_res = self.cmd_res # restore value on exit (for reentrant) self.cmd_res = true # signal buffer capture + var seriallog_level = tasmota.global.seriallog_level + var mqttlog_level = tasmota.settings.mqttlog_level + var weblog_level = tasmota.settings.weblog_level + + if mute # mute logging + if seriallog_level >= 2 tasmota.global.seriallog_level = 1 end + if mqttlog_level >= 2 tasmota.settings.mqttlog_level = 1 end + if weblog_level >= 2 tasmota.settings.weblog_level = 1 end + end + self._cmd(command) var ret = nil @@ -675,6 +660,12 @@ class Tasmota end self.cmd_res = save_cmd_res # restore previous state + # restore log_level + if mute + tasmota.global.seriallog_level = seriallog_level + tasmota.settings.mqttlog_level = mqttlog_level + tasmota.settings.weblog_level = weblog_level + end return ret end @@ -764,6 +755,7 @@ class Tasmota end end var wc = webclient() + wc.set_follow_redirects(true) wc.begin(url) var st = wc.GET() if st != 200 diff --git a/lib/libesp32/berry_tasmota/src/embedded/trigger_class.be b/lib/libesp32/berry_tasmota/src/embedded/trigger_class.be index 419a8178c..83a52556a 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/trigger_class.be +++ b/lib/libesp32/berry_tasmota/src/embedded/trigger_class.be @@ -1,21 +1,33 @@ #- Native code used for testing and code solidification -# -#- Do not use it -# +#- Do not use it directly -# #@ solidify:Trigger + class Trigger var trig, f, id var o # optional object + + # trig: trigger of the event, either timestamp (int) or a rule matcher instance + # f: function or closure to call + # id: (any) identifier to allow removal of a specific trigger + # o: (instance, optional) instance implementing `timer_reached(trig)` + # this is used to implement cron with a specific method for matching time reached def init(trig, f, id, o) self.trig = trig self.f = f self.id = id self.o = o end + def tostring() import string return string.format(" 0 return self.o.time_reached(self.trig) diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h new file mode 100644 index 000000000..d00751b01 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_rule_matcher.h @@ -0,0 +1,1356 @@ +/* Solidification of rule_matcher.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Rule_Matcher_Key; + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Rule_Matcher_Key_tostring, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str(_X3CMatcher_X20key_X3D_X27), + /* K1 */ be_nested_str(name), + /* K2 */ be_nested_str(_X27_X3E), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x60040008, // 0000 GETGBL R1 G8 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x00060001, // 0003 ADD R1 K0 R1 + 0x00040302, // 0004 ADD R1 R1 K2 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_key_i +********************************************************************/ +be_local_closure(Rule_Matcher_Key_find_key_i, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* 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_Rule_Matcher_Key), + /* K1 */ be_nested_str(string), + /* K2 */ be_nested_str(toupper), + /* K3 */ be_nested_str(keys), + /* K4 */ be_nested_str(stop_iteration), + }), + &be_const_str_find_key_i, + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100702, // 0002 GETMET R4 R3 K2 + 0x5C180200, // 0003 MOVE R6 R1 + 0x7C100400, // 0004 CALL R4 2 + 0x6014000F, // 0005 GETGBL R5 G15 + 0x5C180000, // 0006 MOVE R6 R0 + 0x601C0013, // 0007 GETGBL R7 G19 + 0x7C140400, // 0008 CALL R5 2 + 0x78160011, // 0009 JMPF R5 #001C + 0x60140010, // 000A GETGBL R5 G16 + 0x8C180103, // 000B GETMET R6 R0 K3 + 0x7C180200, // 000C CALL R6 1 + 0x7C140200, // 000D CALL R5 1 + 0xA8020009, // 000E EXBLK 0 #0019 + 0x5C180A00, // 000F MOVE R6 R5 + 0x7C180000, // 0010 CALL R6 0 + 0x8C1C0702, // 0011 GETMET R7 R3 K2 + 0x5C240C00, // 0012 MOVE R9 R6 + 0x7C1C0400, // 0013 CALL R7 2 + 0x1C1C0E04, // 0014 EQ R7 R7 R4 + 0x781E0001, // 0015 JMPF R7 #0018 + 0xA8040001, // 0016 EXBLK 1 1 + 0x80040C00, // 0017 RET 1 R6 + 0x7001FFF5, // 0018 JMP #000F + 0x58140004, // 0019 LDCONST R5 K4 + 0xAC140200, // 001A CATCH R5 1 0 + 0xB0080000, // 001B RAISE 2 R0 R0 + 0x80000000, // 001C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: match +********************************************************************/ +be_local_closure(Rule_Matcher_Key_match, /* 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(find_key_i), + /* K1 */ be_nested_str(name), + }), + &be_const_str_match, + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000F, // 0005 GETGBL R2 G15 + 0x5C0C0200, // 0006 MOVE R3 R1 + 0x60100013, // 0007 GETGBL R4 G19 + 0x7C080400, // 0008 CALL R2 2 + 0x740A0001, // 0009 JMPT R2 #000C + 0x4C080000, // 000A LDNIL R2 + 0x80040400, // 000B RET 1 R2 + 0x8C080100, // 000C GETMET R2 R0 K0 + 0x5C100200, // 000D MOVE R4 R1 + 0x88140101, // 000E GETMBR R5 R0 K1 + 0x7C080600, // 000F CALL R2 3 + 0x4C0C0000, // 0010 LDNIL R3 + 0x1C0C0403, // 0011 EQ R3 R2 R3 + 0x780E0001, // 0012 JMPF R3 #0015 + 0x4C0C0000, // 0013 LDNIL R3 + 0x80040600, // 0014 RET 1 R3 + 0x940C0202, // 0015 GETIDX R3 R1 R2 + 0x80040600, // 0016 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Rule_Matcher_Key_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(name), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Rule_Matcher_Key +********************************************************************/ +be_local_class(Rule_Matcher_Key, + 1, + NULL, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key(tostring, 3), be_const_closure(Rule_Matcher_Key_tostring_closure) }, + { be_const_key(find_key_i, -1), be_const_static_closure(Rule_Matcher_Key_find_key_i_closure) }, + { be_const_key(name, -1), be_const_var(0) }, + { be_const_key(init, 4), be_const_closure(Rule_Matcher_Key_init_closure) }, + { be_const_key(match, -1), be_const_closure(Rule_Matcher_Key_match_closure) }, + })), + (bstring*) &be_const_str_Rule_Matcher_Key +); +/*******************************************************************/ + +void be_load_Rule_Matcher_Key_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Rule_Matcher_Key); + be_setglobal(vm, "Rule_Matcher_Key"); + be_pop(vm, 1); +} + +extern const bclass be_class_Rule_Matcher_Wildcard; + +/******************************************************************** +** Solidified function: match +********************************************************************/ +be_local_closure(Rule_Matcher_Wildcard_match, /* 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_const_int(0), + /* K1 */ be_nested_str(iter), + }), + &be_const_str_match, + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000F, // 0005 GETGBL R2 G15 + 0x5C0C0200, // 0006 MOVE R3 R1 + 0x60100013, // 0007 GETGBL R4 G19 + 0x7C080400, // 0008 CALL R2 2 + 0x740A0001, // 0009 JMPT R2 #000C + 0x4C080000, // 000A LDNIL R2 + 0x80040400, // 000B RET 1 R2 + 0x6008000C, // 000C GETGBL R2 G12 + 0x5C0C0200, // 000D MOVE R3 R1 + 0x7C080200, // 000E CALL R2 1 + 0x1C080500, // 000F EQ R2 R2 K0 + 0x780A0001, // 0010 JMPF R2 #0013 + 0x4C080000, // 0011 LDNIL R2 + 0x80040400, // 0012 RET 1 R2 + 0x8C080301, // 0013 GETMET R2 R1 K1 + 0x7C080200, // 0014 CALL R2 1 + 0x7C080000, // 0015 CALL R2 0 + 0x80040400, // 0016 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Rule_Matcher_Wildcard_tostring, /* 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(_X3CMatcher_X20any_X3E), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80060000, // 0000 RET 1 K0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Rule_Matcher_Wildcard +********************************************************************/ +be_local_class(Rule_Matcher_Wildcard, + 0, + NULL, + be_nested_map(2, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key(match, -1), be_const_closure(Rule_Matcher_Wildcard_match_closure) }, + { be_const_key(tostring, -1), be_const_closure(Rule_Matcher_Wildcard_tostring_closure) }, + })), + (bstring*) &be_const_str_Rule_Matcher_Wildcard +); +/*******************************************************************/ + +void be_load_Rule_Matcher_Wildcard_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Rule_Matcher_Wildcard); + be_setglobal(vm, "Rule_Matcher_Wildcard"); + be_pop(vm, 1); +} + +extern const bclass be_class_Rule_Matcher_Operator; + +/******************************************************************** +** Solidified function: match +********************************************************************/ +be_local_closure(Rule_Matcher_Operator_match, /* 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(int), + /* K1 */ be_nested_str(real), + /* K2 */ be_nested_str(string), + /* K3 */ be_nested_str(op_func), + /* K4 */ be_nested_str(op_value), + }), + &be_const_str_match, + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x60080004, // 0000 GETGBL R2 G4 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x200C0500, // 0003 NE R3 R2 K0 + 0x780E0005, // 0004 JMPF R3 #000B + 0x200C0501, // 0005 NE R3 R2 K1 + 0x780E0003, // 0006 JMPF R3 #000B + 0x200C0502, // 0007 NE R3 R2 K2 + 0x780E0001, // 0008 JMPF R3 #000B + 0x4C0C0000, // 0009 LDNIL R3 + 0x80040600, // 000A RET 1 R3 + 0x8C0C0103, // 000B GETMET R3 R0 K3 + 0x5C140200, // 000C MOVE R5 R1 + 0x88180104, // 000D GETMBR R6 R0 K4 + 0x7C0C0600, // 000E CALL R3 3 + 0x780E0001, // 000F JMPF R3 #0012 + 0x5C0C0200, // 0010 MOVE R3 R1 + 0x70020000, // 0011 JMP #0013 + 0x4C0C0000, // 0012 LDNIL R3 + 0x80040600, // 0013 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: op_parse +********************************************************************/ +be_local_closure(Rule_Matcher_Operator_op_parse, /* name */ + be_nested_proto( + 22, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[13]) { + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* 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(tasmota), + /* K1 */ be_nested_str(_apply_str_op), + /* K2 */ be_const_int(1), + }), + &be_const_str_op_eq_str, + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x60140008, // 0003 GETGBL R5 G8 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C140200, // 0005 CALL R5 1 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C080800, // 0007 CALL R2 4 + 0x80040400, // 0008 RET 1 R2 + }) + ), + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* 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(tasmota), + /* K1 */ be_nested_str(_apply_str_op), + /* K2 */ be_const_int(2), + }), + &be_const_str_op_neq_str, + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x60140008, // 0003 GETGBL R5 G8 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C140200, // 0005 CALL R5 1 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C080800, // 0007 CALL R2 4 + 0x80040400, // 0008 RET 1 R2 + }) + ), + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* 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(tasmota), + /* K1 */ be_nested_str(_apply_str_op), + /* K2 */ be_const_int(3), + }), + &be_const_str_op_start_str, + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x60140008, // 0003 GETGBL R5 G8 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C140200, // 0005 CALL R5 1 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C080800, // 0007 CALL R2 4 + 0x80040400, // 0008 RET 1 R2 + }) + ), + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* 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(tasmota), + /* K1 */ be_nested_str(_apply_str_op), + }), + &be_const_str_op_end_str, + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x54120003, // 0002 LDINT R4 4 + 0x60140008, // 0003 GETGBL R5 G8 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C140200, // 0005 CALL R5 1 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C080800, // 0007 CALL R2 4 + 0x80040400, // 0008 RET 1 R2 + }) + ), + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* 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(tasmota), + /* K1 */ be_nested_str(_apply_str_op), + }), + &be_const_str_op_sub_str, + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x54120004, // 0002 LDINT R4 5 + 0x60140008, // 0003 GETGBL R5 G8 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C140200, // 0005 CALL R5 1 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C080800, // 0007 CALL R2 4 + 0x80040400, // 0008 RET 1 R2 + }) + ), + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 0, /* 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(tasmota), + /* K1 */ be_nested_str(_apply_str_op), + }), + &be_const_str_op_notsub_str, + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x54120005, // 0002 LDINT R4 6 + 0x60140008, // 0003 GETGBL R5 G8 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C140200, // 0005 CALL R5 1 + 0x5C180200, // 0006 MOVE R6 R1 + 0x7C080800, // 0007 CALL R2 4 + 0x80040400, // 0008 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + &be_const_str_op_eq, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080007, // 0000 GETGBL R2 G7 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x1C080401, // 0003 EQ R2 R2 R1 + 0x80040400, // 0004 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + &be_const_str_op_neq, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080007, // 0000 GETGBL R2 G7 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x20080401, // 0003 NE R2 R2 R1 + 0x80040400, // 0004 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + &be_const_str_op_gt, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080007, // 0000 GETGBL R2 G7 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x24080401, // 0003 GT R2 R2 R1 + 0x80040400, // 0004 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + &be_const_str_op_gte, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080007, // 0000 GETGBL R2 G7 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x28080401, // 0003 GE R2 R2 R1 + 0x80040400, // 0004 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + &be_const_str_op_lt, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080007, // 0000 GETGBL R2 G7 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x14080401, // 0003 LT R2 R2 R1 + 0x80040400, // 0004 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + &be_const_str_op_lte, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x60080007, // 0000 GETGBL R2 G7 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x18080401, // 0003 LE R2 R2 R1 + 0x80040400, // 0004 RET 1 R2 + }) + ), + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_const_int(0), + }), + &be_const_str_op_mod, + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x10080401, // 0003 MOD R2 R2 R1 + 0x1C080500, // 0004 EQ R2 R2 K0 + 0x80040400, // 0005 RET 1 R2 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_nested_str(op_str), + /* K1 */ be_nested_str(_X3D), + /* K2 */ be_nested_str(_X21_X3D_X3D), + /* K3 */ be_nested_str(_X24_X21), + /* K4 */ be_nested_str(_X24_X3C), + /* K5 */ be_nested_str(_X24_X3E), + /* K6 */ be_nested_str(_X24_X7C), + /* K7 */ be_nested_str(_X24_X5E), + /* K8 */ be_nested_str(_X3D_X3D), + /* K9 */ be_nested_str(_X21_X3D), + /* K10 */ be_nested_str(_X3E), + /* K11 */ be_nested_str(_X3E_X3D), + /* K12 */ be_nested_str(_X3C), + /* K13 */ be_nested_str(_X3C_X3D), + /* K14 */ be_nested_str(_X7C), + /* K15 */ be_nested_str(op_func), + /* K16 */ be_nested_str(json), + /* K17 */ be_nested_str(load), + /* K18 */ be_nested_str(int), + /* K19 */ be_nested_str(real), + /* K20 */ be_nested_str(value_error), + /* K21 */ be_nested_str(value_X20needs_X20to_X20be_X20a_X20number), + /* K22 */ be_nested_str(op_value), + }), + &be_const_str_op_parse, + &be_const_str_solidified, + ( &(const binstruction[97]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x840C0000, // 0001 CLOSURE R3 P0 + 0x84100001, // 0002 CLOSURE R4 P1 + 0x84140002, // 0003 CLOSURE R5 P2 + 0x84180003, // 0004 CLOSURE R6 P3 + 0x841C0004, // 0005 CLOSURE R7 P4 + 0x84200005, // 0006 CLOSURE R8 P5 + 0x84240006, // 0007 CLOSURE R9 P6 + 0x84280007, // 0008 CLOSURE R10 P7 + 0x842C0008, // 0009 CLOSURE R11 P8 + 0x84300009, // 000A CLOSURE R12 P9 + 0x8434000A, // 000B CLOSURE R13 P10 + 0x8438000B, // 000C CLOSURE R14 P11 + 0x843C000C, // 000D CLOSURE R15 P12 + 0x50400000, // 000E LDBOOL R16 0 0 + 0x4C440000, // 000F LDNIL R17 + 0x1C480301, // 0010 EQ R18 R1 K1 + 0x784A0001, // 0011 JMPF R18 #0014 + 0x5C440600, // 0012 MOVE R17 R3 + 0x70020033, // 0013 JMP #0048 + 0x1C480302, // 0014 EQ R18 R1 K2 + 0x784A0001, // 0015 JMPF R18 #0018 + 0x5C440800, // 0016 MOVE R17 R4 + 0x7002002F, // 0017 JMP #0048 + 0x1C480303, // 0018 EQ R18 R1 K3 + 0x784A0001, // 0019 JMPF R18 #001C + 0x5C440800, // 001A MOVE R17 R4 + 0x7002002B, // 001B JMP #0048 + 0x1C480304, // 001C EQ R18 R1 K4 + 0x784A0001, // 001D JMPF R18 #0020 + 0x5C440A00, // 001E MOVE R17 R5 + 0x70020027, // 001F JMP #0048 + 0x1C480305, // 0020 EQ R18 R1 K5 + 0x784A0001, // 0021 JMPF R18 #0024 + 0x5C440C00, // 0022 MOVE R17 R6 + 0x70020023, // 0023 JMP #0048 + 0x1C480306, // 0024 EQ R18 R1 K6 + 0x784A0001, // 0025 JMPF R18 #0028 + 0x5C440E00, // 0026 MOVE R17 R7 + 0x7002001F, // 0027 JMP #0048 + 0x1C480307, // 0028 EQ R18 R1 K7 + 0x784A0001, // 0029 JMPF R18 #002C + 0x5C441000, // 002A MOVE R17 R8 + 0x7002001B, // 002B JMP #0048 + 0x50400200, // 002C LDBOOL R16 1 0 + 0x1C480308, // 002D EQ R18 R1 K8 + 0x784A0001, // 002E JMPF R18 #0031 + 0x5C441200, // 002F MOVE R17 R9 + 0x70020016, // 0030 JMP #0048 + 0x1C480309, // 0031 EQ R18 R1 K9 + 0x784A0001, // 0032 JMPF R18 #0035 + 0x5C441400, // 0033 MOVE R17 R10 + 0x70020012, // 0034 JMP #0048 + 0x1C48030A, // 0035 EQ R18 R1 K10 + 0x784A0001, // 0036 JMPF R18 #0039 + 0x5C441600, // 0037 MOVE R17 R11 + 0x7002000E, // 0038 JMP #0048 + 0x1C48030B, // 0039 EQ R18 R1 K11 + 0x784A0001, // 003A JMPF R18 #003D + 0x5C441800, // 003B MOVE R17 R12 + 0x7002000A, // 003C JMP #0048 + 0x1C48030C, // 003D EQ R18 R1 K12 + 0x784A0001, // 003E JMPF R18 #0041 + 0x5C441A00, // 003F MOVE R17 R13 + 0x70020006, // 0040 JMP #0048 + 0x1C48030D, // 0041 EQ R18 R1 K13 + 0x784A0001, // 0042 JMPF R18 #0045 + 0x5C441C00, // 0043 MOVE R17 R14 + 0x70020002, // 0044 JMP #0048 + 0x1C48030E, // 0045 EQ R18 R1 K14 + 0x784A0000, // 0046 JMPF R18 #0048 + 0x5C441E00, // 0047 MOVE R17 R15 + 0x90021E11, // 0048 SETMBR R0 K15 R17 + 0x78420011, // 0049 JMPF R16 #005C + 0xA44A2000, // 004A IMPORT R18 K16 + 0x8C4C2511, // 004B GETMET R19 R18 K17 + 0x5C540400, // 004C MOVE R21 R2 + 0x7C4C0400, // 004D CALL R19 2 + 0x60500004, // 004E GETGBL R20 G4 + 0x5C542600, // 004F MOVE R21 R19 + 0x7C500200, // 0050 CALL R20 1 + 0x20502912, // 0051 NE R20 R20 K18 + 0x78520006, // 0052 JMPF R20 #005A + 0x60500004, // 0053 GETGBL R20 G4 + 0x5C542600, // 0054 MOVE R21 R19 + 0x7C500200, // 0055 CALL R20 1 + 0x20502913, // 0056 NE R20 R20 K19 + 0x78520001, // 0057 JMPF R20 #005A + 0xB0062915, // 0058 RAISE 1 K20 K21 + 0x70020000, // 0059 JMP #005B + 0x90022C13, // 005A SETMBR R0 K22 R19 + 0x70020003, // 005B JMP #0060 + 0x60480008, // 005C GETGBL R18 G8 + 0x5C4C0200, // 005D MOVE R19 R1 + 0x7C480200, // 005E CALL R18 1 + 0x90022C12, // 005F SETMBR R0 K22 R18 + 0x80000000, // 0060 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Rule_Matcher_Operator_tostring, /* 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[ 8]) { /* constants */ + /* K0 */ be_nested_str(op_value), + /* K1 */ be_nested_str(string), + /* K2 */ be_nested_str(_X3CMatcher_X20op_X20_X27), + /* K3 */ be_nested_str(op_str), + /* K4 */ be_nested_str(_X27_X20val_X3D_X27), + /* K5 */ be_nested_str(_X27_X3E), + /* K6 */ be_nested_str(_X27_X20val_X3D), + /* K7 */ be_nested_str(_X3E), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x60040004, // 0000 GETGBL R1 G4 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0x1C040301, // 0003 EQ R1 R1 K1 + 0x78060009, // 0004 JMPF R1 #000F + 0x88040103, // 0005 GETMBR R1 R0 K3 + 0x00060401, // 0006 ADD R1 K2 R1 + 0x00040304, // 0007 ADD R1 R1 K4 + 0x60080008, // 0008 GETGBL R2 G8 + 0x880C0100, // 0009 GETMBR R3 R0 K0 + 0x7C080200, // 000A CALL R2 1 + 0x00040202, // 000B ADD R1 R1 R2 + 0x00040305, // 000C ADD R1 R1 K5 + 0x80040200, // 000D RET 1 R1 + 0x70020008, // 000E JMP #0018 + 0x88040103, // 000F GETMBR R1 R0 K3 + 0x00060401, // 0010 ADD R1 K2 R1 + 0x00040306, // 0011 ADD R1 R1 K6 + 0x60080008, // 0012 GETGBL R2 G8 + 0x880C0100, // 0013 GETMBR R3 R0 K0 + 0x7C080200, // 0014 CALL R2 1 + 0x00040202, // 0015 ADD R1 R1 R2 + 0x00040307, // 0016 ADD R1 R1 K7 + 0x80040200, // 0017 RET 1 R1 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Rule_Matcher_Operator_init, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_str(op_parse), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x5C180400, // 0002 MOVE R6 R2 + 0x7C0C0600, // 0003 CALL R3 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Rule_Matcher_Operator +********************************************************************/ +be_local_class(Rule_Matcher_Operator, + 3, + NULL, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key(op_value, 6), be_const_var(2) }, + { be_const_key(tostring, -1), be_const_closure(Rule_Matcher_Operator_tostring_closure) }, + { be_const_key(op_func, 0), be_const_var(0) }, + { be_const_key(match, 1), be_const_closure(Rule_Matcher_Operator_match_closure) }, + { be_const_key(op_str, -1), be_const_var(1) }, + { be_const_key(init, -1), be_const_closure(Rule_Matcher_Operator_init_closure) }, + { be_const_key(op_parse, -1), be_const_closure(Rule_Matcher_Operator_op_parse_closure) }, + })), + (bstring*) &be_const_str_Rule_Matcher_Operator +); +/*******************************************************************/ + +void be_load_Rule_Matcher_Operator_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Rule_Matcher_Operator); + be_setglobal(vm, "Rule_Matcher_Operator"); + be_pop(vm, 1); +} + +extern const bclass be_class_Rule_Matcher_Array; + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Rule_Matcher_Array_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* 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(index), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Rule_Matcher_Array_tostring, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str(_X3CMatcher_X20_X5B), + /* K1 */ be_nested_str(index), + /* K2 */ be_nested_str(_X5D_X3E), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x60040008, // 0000 GETGBL R1 G8 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x00060001, // 0003 ADD R1 K0 R1 + 0x00040302, // 0004 ADD R1 R1 K2 + 0x80040200, // 0005 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: match +********************************************************************/ +be_local_closure(Rule_Matcher_Array_match, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_str(index), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + }), + &be_const_str_match, + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0001, // 0002 JMPF R2 #0005 + 0x4C080000, // 0003 LDNIL R2 + 0x80040400, // 0004 RET 1 R2 + 0x6008000F, // 0005 GETGBL R2 G15 + 0x5C0C0200, // 0006 MOVE R3 R1 + 0x60100012, // 0007 GETGBL R4 G18 + 0x7C080400, // 0008 CALL R2 2 + 0x740A0000, // 0009 JMPT R2 #000B + 0x80040200, // 000A RET 1 R1 + 0x88080100, // 000B GETMBR R2 R0 K0 + 0x18080501, // 000C LE R2 R2 K1 + 0x780A0001, // 000D JMPF R2 #0010 + 0x4C080000, // 000E LDNIL R2 + 0x80040400, // 000F RET 1 R2 + 0x88080100, // 0010 GETMBR R2 R0 K0 + 0x600C000C, // 0011 GETGBL R3 G12 + 0x5C100200, // 0012 MOVE R4 R1 + 0x7C0C0200, // 0013 CALL R3 1 + 0x24080403, // 0014 GT R2 R2 R3 + 0x780A0001, // 0015 JMPF R2 #0018 + 0x4C080000, // 0016 LDNIL R2 + 0x80040400, // 0017 RET 1 R2 + 0x88080100, // 0018 GETMBR R2 R0 K0 + 0x04080502, // 0019 SUB R2 R2 K2 + 0x94080202, // 001A GETIDX R2 R1 R2 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Rule_Matcher_Array +********************************************************************/ +be_local_class(Rule_Matcher_Array, + 1, + NULL, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key(index, -1), be_const_var(0) }, + { be_const_key(tostring, -1), be_const_closure(Rule_Matcher_Array_tostring_closure) }, + { be_const_key(match, -1), be_const_closure(Rule_Matcher_Array_match_closure) }, + { be_const_key(init, 0), be_const_closure(Rule_Matcher_Array_init_closure) }, + })), + (bstring*) &be_const_str_Rule_Matcher_Array +); +/*******************************************************************/ + +void be_load_Rule_Matcher_Array_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Rule_Matcher_Array); + be_setglobal(vm, "Rule_Matcher_Array"); + be_pop(vm, 1); +} + +extern const bclass be_class_Rule_Matcher; + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Rule_Matcher_tostring, /* 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(matchers), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040008, // 0000 GETGBL R1 G8 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Rule_Matcher_parse, /* name */ + be_nested_proto( + 20, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_const_class(be_class_Rule_Matcher), + /* K1 */ be_nested_str(string), + /* K2 */ be_nested_str(tasmota), + /* K3 */ be_nested_str(find_op), + /* K4 */ be_const_int(0), + /* K5 */ be_const_int(1), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_str(find), + /* K8 */ be_nested_str(_X23), + /* K9 */ be_nested_str(pattern_error), + /* K10 */ be_nested_str(empty_X20pattern_X20not_X20allowed), + /* K11 */ be_const_int(2147483647), + /* K12 */ be_nested_str(_X5B), + /* K13 */ be_nested_str(_X5D), + /* K14 */ be_nested_str(value_error), + /* K15 */ be_nested_str(missing_X20_X27_X5D_X27_X20in_X20rule_X20pattern), + /* K16 */ be_nested_str(_X3F), + /* K17 */ be_nested_str(push), + /* K18 */ be_nested_str(Rule_Matcher_Wildcard), + /* K19 */ be_nested_str(Rule_Matcher_Key), + /* K20 */ be_nested_str(Rule_Matcher_Array), + /* K21 */ be_nested_str(Rule_Matcher_Operator), + }), + &be_const_str_parse, + &be_const_str_solidified, + ( &(const binstruction[108]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x4C0C0000, // 0002 LDNIL R3 + 0x1C0C0003, // 0003 EQ R3 R0 R3 + 0x780E0001, // 0004 JMPF R3 #0007 + 0x4C0C0000, // 0005 LDNIL R3 + 0x80040600, // 0006 RET 1 R3 + 0x600C0012, // 0007 GETGBL R3 G18 + 0x7C0C0000, // 0008 CALL R3 0 + 0xB8120400, // 0009 GETNGBL R4 K2 + 0x8C100903, // 000A GETMET R4 R4 K3 + 0x5C180000, // 000B MOVE R6 R0 + 0x7C100400, // 000C CALL R4 2 + 0x94140904, // 000D GETIDX R5 R4 K4 + 0x94180905, // 000E GETIDX R6 R4 K5 + 0x941C0906, // 000F GETIDX R7 R4 K6 + 0x6020000C, // 0010 GETGBL R8 G12 + 0x5C240A00, // 0011 MOVE R9 R5 + 0x7C200200, // 0012 CALL R8 1 + 0x58240004, // 0013 LDCONST R9 K4 + 0x5429FFFE, // 0014 LDINT R10 -1 + 0x142C1208, // 0015 LT R11 R9 R8 + 0x782E0042, // 0016 JMPF R11 #005A + 0x8C2C0507, // 0017 GETMET R11 R2 K7 + 0x5C340A00, // 0018 MOVE R13 R5 + 0x58380008, // 0019 LDCONST R14 K8 + 0x5C3C1200, // 001A MOVE R15 R9 + 0x7C2C0800, // 001B CALL R11 4 + 0x4C300000, // 001C LDNIL R12 + 0x28341704, // 001D GE R13 R11 K4 + 0x78360008, // 001E JMPF R13 #0028 + 0x1C341609, // 001F EQ R13 R11 R9 + 0x78360000, // 0020 JMPF R13 #0022 + 0xB006130A, // 0021 RAISE 1 K9 K10 + 0x04341705, // 0022 SUB R13 R11 K5 + 0x4034120D, // 0023 CONNECT R13 R9 R13 + 0x94300A0D, // 0024 GETIDX R12 R5 R13 + 0x00381705, // 0025 ADD R14 R11 K5 + 0x5C241C00, // 0026 MOVE R9 R14 + 0x70020002, // 0027 JMP #002B + 0x4034130B, // 0028 CONNECT R13 R9 K11 + 0x94300A0D, // 0029 GETIDX R12 R5 R13 + 0x5C241000, // 002A MOVE R9 R8 + 0x8C340507, // 002B GETMET R13 R2 K7 + 0x5C3C1800, // 002C MOVE R15 R12 + 0x5840000C, // 002D LDCONST R16 K12 + 0x7C340600, // 002E CALL R13 3 + 0x4C380000, // 002F LDNIL R14 + 0x283C1B04, // 0030 GE R15 R13 K4 + 0x783E0012, // 0031 JMPF R15 #0045 + 0x8C3C0507, // 0032 GETMET R15 R2 K7 + 0x5C441800, // 0033 MOVE R17 R12 + 0x5848000D, // 0034 LDCONST R18 K13 + 0x5C4C1A00, // 0035 MOVE R19 R13 + 0x7C3C0800, // 0036 CALL R15 4 + 0x14401F04, // 0037 LT R16 R15 K4 + 0x78420000, // 0038 JMPF R16 #003A + 0xB0061D0F, // 0039 RAISE 1 K14 K15 + 0x00401B05, // 003A ADD R16 R13 K5 + 0x04441F05, // 003B SUB R17 R15 K5 + 0x40402011, // 003C CONNECT R16 R16 R17 + 0x94401810, // 003D GETIDX R16 R12 R16 + 0x04441B05, // 003E SUB R17 R13 K5 + 0x40460811, // 003F CONNECT R17 K4 R17 + 0x94301811, // 0040 GETIDX R12 R12 R17 + 0x60480009, // 0041 GETGBL R18 G9 + 0x5C4C2000, // 0042 MOVE R19 R16 + 0x7C480200, // 0043 CALL R18 1 + 0x5C382400, // 0044 MOVE R14 R18 + 0x1C3C1910, // 0045 EQ R15 R12 K16 + 0x783E0004, // 0046 JMPF R15 #004C + 0x8C3C0711, // 0047 GETMET R15 R3 K17 + 0x8C440312, // 0048 GETMET R17 R1 K18 + 0x7C440200, // 0049 CALL R17 1 + 0x7C3C0400, // 004A CALL R15 2 + 0x70020004, // 004B JMP #0051 + 0x8C3C0711, // 004C GETMET R15 R3 K17 + 0x8C440313, // 004D GETMET R17 R1 K19 + 0x5C4C1800, // 004E MOVE R19 R12 + 0x7C440400, // 004F CALL R17 2 + 0x7C3C0400, // 0050 CALL R15 2 + 0x4C3C0000, // 0051 LDNIL R15 + 0x203C1C0F, // 0052 NE R15 R14 R15 + 0x783E0004, // 0053 JMPF R15 #0059 + 0x8C3C0711, // 0054 GETMET R15 R3 K17 + 0x8C440314, // 0055 GETMET R17 R1 K20 + 0x5C4C1C00, // 0056 MOVE R19 R14 + 0x7C440400, // 0057 CALL R17 2 + 0x7C3C0400, // 0058 CALL R15 2 + 0x7001FFBA, // 0059 JMP #0015 + 0x4C2C0000, // 005A LDNIL R11 + 0x202C0C0B, // 005B NE R11 R6 R11 + 0x782E0008, // 005C JMPF R11 #0066 + 0x4C2C0000, // 005D LDNIL R11 + 0x202C0E0B, // 005E NE R11 R7 R11 + 0x782E0005, // 005F JMPF R11 #0066 + 0x8C2C0711, // 0060 GETMET R11 R3 K17 + 0x8C340315, // 0061 GETMET R13 R1 K21 + 0x5C3C0C00, // 0062 MOVE R15 R6 + 0x5C400E00, // 0063 MOVE R16 R7 + 0x7C340600, // 0064 CALL R13 3 + 0x7C2C0400, // 0065 CALL R11 2 + 0x5C2C0200, // 0066 MOVE R11 R1 + 0x5C300000, // 0067 MOVE R12 R0 + 0x5C340A00, // 0068 MOVE R13 R5 + 0x5C380600, // 0069 MOVE R14 R3 + 0x7C2C0600, // 006A CALL R11 3 + 0x80041600, // 006B RET 1 R11 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Rule_Matcher_init, /* name */ + be_nested_proto( + 4, /* 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(rule), + /* K1 */ be_nested_str(trigger), + /* K2 */ be_nested_str(matchers), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: match +********************************************************************/ +be_local_closure(Rule_Matcher_match, /* 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(matchers), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(match), + /* K3 */ be_const_int(1), + }), + &be_const_str_match, + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0x1C080403, // 0002 EQ R2 R2 R3 + 0x780A0001, // 0003 JMPF R2 #0006 + 0x4C080000, // 0004 LDNIL R2 + 0x80040400, // 0005 RET 1 R2 + 0x5C080200, // 0006 MOVE R2 R1 + 0x580C0001, // 0007 LDCONST R3 K1 + 0x6010000C, // 0008 GETGBL R4 G12 + 0x88140100, // 0009 GETMBR R5 R0 K0 + 0x7C100200, // 000A CALL R4 1 + 0x14100604, // 000B LT R4 R3 R4 + 0x7812000C, // 000C JMPF R4 #001A + 0x88100100, // 000D GETMBR R4 R0 K0 + 0x94100803, // 000E GETIDX R4 R4 R3 + 0x8C100902, // 000F GETMET R4 R4 K2 + 0x5C180400, // 0010 MOVE R6 R2 + 0x7C100400, // 0011 CALL R4 2 + 0x5C080800, // 0012 MOVE R2 R4 + 0x4C100000, // 0013 LDNIL R4 + 0x1C100404, // 0014 EQ R4 R2 R4 + 0x78120001, // 0015 JMPF R4 #0018 + 0x4C100000, // 0016 LDNIL R4 + 0x80040800, // 0017 RET 1 R4 + 0x000C0703, // 0018 ADD R3 R3 K3 + 0x7001FFED, // 0019 JMP #0008 + 0x80040400, // 001A RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Rule_Matcher +********************************************************************/ +be_local_class(Rule_Matcher, + 3, + NULL, + be_nested_map(11, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key(Rule_Matcher_Wildcard, -1), be_const_class(be_class_Rule_Matcher_Wildcard) }, + { be_const_key(Rule_Matcher_Array, -1), be_const_class(be_class_Rule_Matcher_Array) }, + { be_const_key(trigger, -1), be_const_var(1) }, + { be_const_key(tostring, 2), be_const_closure(Rule_Matcher_tostring_closure) }, + { be_const_key(init, 7), be_const_closure(Rule_Matcher_init_closure) }, + { be_const_key(Rule_Matcher_Key, -1), be_const_class(be_class_Rule_Matcher_Key) }, + { be_const_key(parse, -1), be_const_static_closure(Rule_Matcher_parse_closure) }, + { be_const_key(rule, -1), be_const_var(0) }, + { be_const_key(matchers, 6), be_const_var(2) }, + { be_const_key(Rule_Matcher_Operator, 4), be_const_class(be_class_Rule_Matcher_Operator) }, + { be_const_key(match, -1), be_const_closure(Rule_Matcher_match_closure) }, + })), + (bstring*) &be_const_str_Rule_Matcher +); +/*******************************************************************/ + +void be_load_Rule_Matcher_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Rule_Matcher); + be_setglobal(vm, "Rule_Matcher"); + be_pop(vm, 1); +} +/********************************************************************/ +/* 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 af2a338d1..25461a620 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h @@ -97,35 +97,78 @@ be_local_closure(Tasmota_exec_rules, /* name */ ********************************************************************/ be_local_closure(Tasmota_cmd, /* name */ be_nested_proto( - 6, /* nstack */ - 2, /* argc */ + 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[ 2]) { /* constants */ + ( &(const bvalue[10]) { /* constants */ /* K0 */ be_nested_str(cmd_res), - /* K1 */ be_nested_str(_cmd), + /* K1 */ be_nested_str(tasmota), + /* K2 */ be_nested_str(global), + /* K3 */ be_nested_str(seriallog_level), + /* K4 */ be_nested_str(settings), + /* K5 */ be_nested_str(mqttlog_level), + /* K6 */ be_nested_str(weblog_level), + /* K7 */ be_const_int(2), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str(_cmd), }), &be_const_str_cmd, &be_const_str_solidified, - ( &(const binstruction[14]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x500C0200, // 0001 LDBOOL R3 1 0 - 0x90020003, // 0002 SETMBR R0 K0 R3 - 0x8C0C0101, // 0003 GETMET R3 R0 K1 - 0x5C140200, // 0004 MOVE R5 R1 - 0x7C0C0400, // 0005 CALL R3 2 - 0x4C0C0000, // 0006 LDNIL R3 - 0x88100100, // 0007 GETMBR R4 R0 K0 - 0x50140200, // 0008 LDBOOL R5 1 0 - 0x20100805, // 0009 NE R4 R4 R5 - 0x78120000, // 000A JMPF R4 #000C - 0x880C0100, // 000B GETMBR R3 R0 K0 - 0x90020002, // 000C SETMBR R0 K0 R2 - 0x80040600, // 000D RET 1 R3 + ( &(const binstruction[49]) { /* 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 + 0xB8160200, // 0006 GETNGBL R5 K1 + 0x88140B04, // 0007 GETMBR R5 R5 K4 + 0x88140B05, // 0008 GETMBR R5 R5 K5 + 0xB81A0200, // 0009 GETNGBL R6 K1 + 0x88180D04, // 000A GETMBR R6 R6 K4 + 0x88180D06, // 000B GETMBR R6 R6 K6 + 0x780A000E, // 000C JMPF R2 #001C + 0x281C0907, // 000D GE R7 R4 K7 + 0x781E0002, // 000E JMPF R7 #0012 + 0xB81E0200, // 000F GETNGBL R7 K1 + 0x881C0F02, // 0010 GETMBR R7 R7 K2 + 0x901E0708, // 0011 SETMBR R7 K3 K8 + 0x281C0B07, // 0012 GE R7 R5 K7 + 0x781E0002, // 0013 JMPF R7 #0017 + 0xB81E0200, // 0014 GETNGBL R7 K1 + 0x881C0F04, // 0015 GETMBR R7 R7 K4 + 0x901E0B08, // 0016 SETMBR R7 K5 K8 + 0x281C0D07, // 0017 GE R7 R6 K7 + 0x781E0002, // 0018 JMPF R7 #001C + 0xB81E0200, // 0019 GETNGBL R7 K1 + 0x881C0F04, // 001A GETMBR R7 R7 K4 + 0x901E0D08, // 001B SETMBR R7 K6 K8 + 0x8C1C0109, // 001C GETMET R7 R0 K9 + 0x5C240200, // 001D MOVE R9 R1 + 0x7C1C0400, // 001E CALL R7 2 + 0x4C1C0000, // 001F LDNIL R7 + 0x88200100, // 0020 GETMBR R8 R0 K0 + 0x50240200, // 0021 LDBOOL R9 1 0 + 0x20201009, // 0022 NE R8 R8 R9 + 0x78220000, // 0023 JMPF R8 #0025 + 0x881C0100, // 0024 GETMBR R7 R0 K0 + 0x90020003, // 0025 SETMBR R0 K0 R3 + 0x780A0008, // 0026 JMPF R2 #0030 + 0xB8220200, // 0027 GETNGBL R8 K1 + 0x88201102, // 0028 GETMBR R8 R8 K2 + 0x90220604, // 0029 SETMBR R8 K3 R4 + 0xB8220200, // 002A GETNGBL R8 K1 + 0x88201104, // 002B GETMBR R8 R8 K4 + 0x90220A05, // 002C SETMBR R8 K5 R5 + 0xB8220200, // 002D GETNGBL R8 K1 + 0x88201104, // 002E GETMBR R8 R8 K4 + 0x90220C06, // 002F SETMBR R8 K6 R6 + 0x80040E00, // 0030 RET 1 R7 }) ) ); @@ -190,43 +233,45 @@ be_local_closure(Tasmota_remove_rule, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ + ( &(const bvalue[ 7]) { /* constants */ /* K0 */ be_nested_str(_rules), /* K1 */ be_const_int(0), /* K2 */ be_nested_str(trig), - /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(remove), - /* K5 */ be_const_int(1), + /* 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[26]) { /* code */ + ( &(const binstruction[27]) { /* code */ 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x780E0016, // 0001 JMPF R3 #0019 + 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 - 0x78120010, // 0007 JMPF R4 #0019 + 0x78120011, // 0007 JMPF R4 #001A 0x88100100, // 0008 GETMBR R4 R0 K0 0x94100803, // 0009 GETIDX R4 R4 R3 0x88100902, // 000A GETMBR R4 R4 K2 - 0x1C100801, // 000B EQ R4 R4 R1 - 0x78120009, // 000C JMPF R4 #0017 - 0x88100100, // 000D GETMBR R4 R0 K0 - 0x94100803, // 000E GETIDX R4 R4 R3 - 0x88100903, // 000F GETMBR R4 R4 K3 - 0x1C100802, // 0010 EQ R4 R4 R2 - 0x78120004, // 0011 JMPF R4 #0017 - 0x88100100, // 0012 GETMBR R4 R0 K0 - 0x8C100904, // 0013 GETMET R4 R4 K4 - 0x5C180600, // 0014 MOVE R6 R3 - 0x7C100400, // 0015 CALL R4 2 - 0x70020000, // 0016 JMP #0018 - 0x000C0705, // 0017 ADD R3 R3 K5 - 0x7001FFE9, // 0018 JMP #0003 - 0x80000000, // 0019 RET 0 + 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 }) ) ); @@ -1564,7 +1609,7 @@ be_local_closure(Tasmota_urlfetch, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ + ( &(const bvalue[17]) { /* constants */ /* K0 */ be_nested_str(string), /* K1 */ be_nested_str(split), /* K2 */ be_nested_str(_X2F), @@ -1572,19 +1617,20 @@ be_local_closure(Tasmota_urlfetch, /* name */ /* K4 */ be_const_int(0), /* K5 */ be_nested_str(index_X2Ehtml), /* K6 */ be_nested_str(webclient), - /* K7 */ be_nested_str(begin), - /* K8 */ be_nested_str(GET), - /* K9 */ be_nested_str(status_X3A_X20), - /* K10 */ be_nested_str(connection_error), - /* K11 */ be_nested_str(write_file), - /* K12 */ be_nested_str(close), - /* K13 */ be_nested_str(log), - /* K14 */ be_nested_str(BRY_X3A_X20Fetched_X20), - /* K15 */ be_const_int(3), + /* 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[45]) { /* code */ + ( &(const binstruction[48]) { /* code */ 0x4C0C0000, // 0000 LDNIL R3 0x1C0C0403, // 0001 EQ R3 R2 R3 0x780E000D, // 0002 JMPF R3 #0011 @@ -1605,31 +1651,34 @@ be_local_closure(Tasmota_urlfetch, /* name */ 0xB80E0C00, // 0011 GETNGBL R3 K6 0x7C0C0000, // 0012 CALL R3 0 0x8C100707, // 0013 GETMET R4 R3 K7 - 0x5C180200, // 0014 MOVE R6 R1 + 0x50180200, // 0014 LDBOOL R6 1 0 0x7C100400, // 0015 CALL R4 2 0x8C100708, // 0016 GETMET R4 R3 K8 - 0x7C100200, // 0017 CALL R4 1 - 0x541600C7, // 0018 LDINT R5 200 - 0x20140805, // 0019 NE R5 R4 R5 - 0x78160004, // 001A JMPF R5 #0020 - 0x60140008, // 001B GETGBL R5 G8 - 0x5C180800, // 001C MOVE R6 R4 - 0x7C140200, // 001D CALL R5 1 - 0x00161205, // 001E ADD R5 K9 R5 - 0xB0061405, // 001F RAISE 1 K10 R5 - 0x8C14070B, // 0020 GETMET R5 R3 K11 - 0x5C1C0400, // 0021 MOVE R7 R2 - 0x7C140400, // 0022 CALL R5 2 - 0x8C18070C, // 0023 GETMET R6 R3 K12 - 0x7C180200, // 0024 CALL R6 1 - 0x8C18010D, // 0025 GETMET R6 R0 K13 - 0x60200008, // 0026 GETGBL R8 G8 - 0x5C240A00, // 0027 MOVE R9 R5 - 0x7C200200, // 0028 CALL R8 1 - 0x00221C08, // 0029 ADD R8 K14 R8 - 0x5824000F, // 002A LDCONST R9 K15 - 0x7C180600, // 002B CALL R6 3 - 0x80040800, // 002C RET 1 R4 + 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 }) ) ); @@ -1932,7 +1981,7 @@ be_local_closure(Tasmota_hs2rgb, /* name */ ********************************************************************/ be_local_closure(Tasmota_try_rule, /* name */ be_nested_proto( - 15, /* nstack */ + 9, /* nstack */ 4, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1940,168 +1989,31 @@ be_local_closure(Tasmota_try_rule, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_nested_str(string), - /* K1 */ be_nested_str(find_op), - /* K2 */ be_nested_str(split), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str(_X23), - /* K5 */ be_nested_str(find_key_i), - /* K6 */ be_const_int(1), - /* K7 */ be_const_int(2), - /* K8 */ be_nested_str(_X3D_X3D), - /* K9 */ be_nested_str(_X21_X3D_X3D), - /* K10 */ be_nested_str(_X3D), - /* K11 */ be_nested_str(_X21_X3D), - /* K12 */ be_nested_str(_X3E), - /* K13 */ be_nested_str(_X3E_X3D), - /* K14 */ be_nested_str(_X3C), - /* K15 */ be_nested_str(_X3C_X3D), + ( &(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[141]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0x8C140101, // 0001 GETMET R5 R0 K1 - 0x5C1C0400, // 0002 MOVE R7 R2 - 0x7C140400, // 0003 CALL R5 2 - 0x5C180200, // 0004 MOVE R6 R1 - 0x8C1C0902, // 0005 GETMET R7 R4 K2 - 0x94240B03, // 0006 GETIDX R9 R5 K3 - 0x58280004, // 0007 LDCONST R10 K4 - 0x7C1C0600, // 0008 CALL R7 3 - 0x58200003, // 0009 LDCONST R8 K3 - 0x6024000C, // 000A GETGBL R9 G12 - 0x5C280E00, // 000B MOVE R10 R7 - 0x7C240200, // 000C CALL R9 1 - 0x14241009, // 000D LT R9 R8 R9 - 0x7826000C, // 000E JMPF R9 #001C - 0x94240E08, // 000F GETIDX R9 R7 R8 - 0x8C280105, // 0010 GETMET R10 R0 K5 - 0x5C300C00, // 0011 MOVE R12 R6 - 0x5C341200, // 0012 MOVE R13 R9 - 0x7C280600, // 0013 CALL R10 3 - 0x4C2C0000, // 0014 LDNIL R11 - 0x1C2C140B, // 0015 EQ R11 R10 R11 - 0x782E0001, // 0016 JMPF R11 #0019 - 0x502C0000, // 0017 LDBOOL R11 0 0 - 0x80041600, // 0018 RET 1 R11 - 0x94180C0A, // 0019 GETIDX R6 R6 R10 - 0x00201106, // 001A ADD R8 R8 K6 - 0x7001FFED, // 001B JMP #000A - 0x94240B06, // 001C GETIDX R9 R5 K6 - 0x94280B07, // 001D GETIDX R10 R5 K7 - 0x78260066, // 001E JMPF R9 #0086 - 0x1C2C1308, // 001F EQ R11 R9 K8 - 0x782E000A, // 0020 JMPF R11 #002C - 0x602C0008, // 0021 GETGBL R11 G8 - 0x5C300C00, // 0022 MOVE R12 R6 - 0x7C2C0200, // 0023 CALL R11 1 - 0x60300008, // 0024 GETGBL R12 G8 - 0x5C341400, // 0025 MOVE R13 R10 - 0x7C300200, // 0026 CALL R12 1 - 0x202C160C, // 0027 NE R11 R11 R12 - 0x782E0001, // 0028 JMPF R11 #002B - 0x502C0000, // 0029 LDBOOL R11 0 0 - 0x80041600, // 002A RET 1 R11 - 0x70020059, // 002B JMP #0086 - 0x1C2C1309, // 002C EQ R11 R9 K9 - 0x782E000A, // 002D JMPF R11 #0039 - 0x602C0008, // 002E GETGBL R11 G8 - 0x5C300C00, // 002F MOVE R12 R6 - 0x7C2C0200, // 0030 CALL R11 1 - 0x60300008, // 0031 GETGBL R12 G8 - 0x5C341400, // 0032 MOVE R13 R10 - 0x7C300200, // 0033 CALL R12 1 - 0x1C2C160C, // 0034 EQ R11 R11 R12 - 0x782E0001, // 0035 JMPF R11 #0038 - 0x502C0000, // 0036 LDBOOL R11 0 0 - 0x80041600, // 0037 RET 1 R11 - 0x7002004C, // 0038 JMP #0086 - 0x1C2C130A, // 0039 EQ R11 R9 K10 - 0x782E000A, // 003A JMPF R11 #0046 - 0x602C000A, // 003B GETGBL R11 G10 - 0x5C300C00, // 003C MOVE R12 R6 - 0x7C2C0200, // 003D CALL R11 1 - 0x6030000A, // 003E GETGBL R12 G10 - 0x5C341400, // 003F MOVE R13 R10 - 0x7C300200, // 0040 CALL R12 1 - 0x202C160C, // 0041 NE R11 R11 R12 - 0x782E0001, // 0042 JMPF R11 #0045 - 0x502C0000, // 0043 LDBOOL R11 0 0 - 0x80041600, // 0044 RET 1 R11 - 0x7002003F, // 0045 JMP #0086 - 0x1C2C130B, // 0046 EQ R11 R9 K11 - 0x782E000A, // 0047 JMPF R11 #0053 - 0x602C000A, // 0048 GETGBL R11 G10 - 0x5C300C00, // 0049 MOVE R12 R6 - 0x7C2C0200, // 004A CALL R11 1 - 0x6030000A, // 004B GETGBL R12 G10 - 0x5C341400, // 004C MOVE R13 R10 - 0x7C300200, // 004D CALL R12 1 - 0x1C2C160C, // 004E EQ R11 R11 R12 - 0x782E0001, // 004F JMPF R11 #0052 - 0x502C0000, // 0050 LDBOOL R11 0 0 - 0x80041600, // 0051 RET 1 R11 - 0x70020032, // 0052 JMP #0086 - 0x1C2C130C, // 0053 EQ R11 R9 K12 - 0x782E000A, // 0054 JMPF R11 #0060 - 0x602C000A, // 0055 GETGBL R11 G10 - 0x5C300C00, // 0056 MOVE R12 R6 - 0x7C2C0200, // 0057 CALL R11 1 - 0x6030000A, // 0058 GETGBL R12 G10 - 0x5C341400, // 0059 MOVE R13 R10 - 0x7C300200, // 005A CALL R12 1 - 0x182C160C, // 005B LE R11 R11 R12 - 0x782E0001, // 005C JMPF R11 #005F - 0x502C0000, // 005D LDBOOL R11 0 0 - 0x80041600, // 005E RET 1 R11 - 0x70020025, // 005F JMP #0086 - 0x1C2C130D, // 0060 EQ R11 R9 K13 - 0x782E000A, // 0061 JMPF R11 #006D - 0x602C000A, // 0062 GETGBL R11 G10 - 0x5C300C00, // 0063 MOVE R12 R6 - 0x7C2C0200, // 0064 CALL R11 1 - 0x6030000A, // 0065 GETGBL R12 G10 - 0x5C341400, // 0066 MOVE R13 R10 - 0x7C300200, // 0067 CALL R12 1 - 0x142C160C, // 0068 LT R11 R11 R12 - 0x782E0001, // 0069 JMPF R11 #006C - 0x502C0000, // 006A LDBOOL R11 0 0 - 0x80041600, // 006B RET 1 R11 - 0x70020018, // 006C JMP #0086 - 0x1C2C130E, // 006D EQ R11 R9 K14 - 0x782E000A, // 006E JMPF R11 #007A - 0x602C000A, // 006F GETGBL R11 G10 - 0x5C300C00, // 0070 MOVE R12 R6 - 0x7C2C0200, // 0071 CALL R11 1 - 0x6030000A, // 0072 GETGBL R12 G10 - 0x5C341400, // 0073 MOVE R13 R10 - 0x7C300200, // 0074 CALL R12 1 - 0x282C160C, // 0075 GE R11 R11 R12 - 0x782E0001, // 0076 JMPF R11 #0079 - 0x502C0000, // 0077 LDBOOL R11 0 0 - 0x80041600, // 0078 RET 1 R11 - 0x7002000B, // 0079 JMP #0086 - 0x1C2C130F, // 007A EQ R11 R9 K15 - 0x782E0009, // 007B JMPF R11 #0086 - 0x602C000A, // 007C GETGBL R11 G10 - 0x5C300C00, // 007D MOVE R12 R6 - 0x7C2C0200, // 007E CALL R11 1 - 0x6030000A, // 007F GETGBL R12 G10 - 0x5C341400, // 0080 MOVE R13 R10 - 0x7C300200, // 0081 CALL R12 1 - 0x242C160C, // 0082 GT R11 R11 R12 - 0x782E0001, // 0083 JMPF R11 #0086 - 0x502C0000, // 0084 LDBOOL R11 0 0 - 0x80041600, // 0085 RET 1 R11 - 0x5C2C0600, // 0086 MOVE R11 R3 - 0x5C300C00, // 0087 MOVE R12 R6 - 0x94340B03, // 0088 GETIDX R13 R5 K3 - 0x5C380200, // 0089 MOVE R14 R1 - 0x7C2C0600, // 008A CALL R11 3 - 0x502C0200, // 008B LDBOOL R11 1 0 - 0x80041600, // 008C RET 1 R11 + ( &(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 }) ) ); @@ -2216,7 +2128,7 @@ be_local_closure(Tasmota_add_cmd, /* name */ ********************************************************************/ be_local_closure(Tasmota_find_op, /* name */ be_nested_proto( - 13, /* nstack */ + 7, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -2224,58 +2136,46 @@ be_local_closure(Tasmota_find_op, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(string), - /* K1 */ be_nested_str(_X3D_X3C_X3E_X21), - /* K2 */ be_nested_str(_find_op), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str(split), - /* K5 */ be_const_int(1), + ( &(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[41]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x580C0001, // 0001 LDCONST R3 K1 - 0x8C100102, // 0002 GETMET R4 R0 K2 - 0x5C180200, // 0003 MOVE R6 R1 - 0x501C0000, // 0004 LDBOOL R7 0 0 - 0x7C100600, // 0005 CALL R4 3 - 0x28140903, // 0006 GE R5 R4 K3 - 0x78160018, // 0007 JMPF R5 #0021 - 0x8C140504, // 0008 GETMET R5 R2 K4 - 0x5C1C0200, // 0009 MOVE R7 R1 - 0x5C200800, // 000A MOVE R8 R4 - 0x7C140600, // 000B CALL R5 3 - 0x94180B03, // 000C GETIDX R6 R5 K3 - 0x941C0B05, // 000D GETIDX R7 R5 K5 - 0x8C200102, // 000E GETMET R8 R0 K2 - 0x5C280E00, // 000F MOVE R10 R7 - 0x502C0200, // 0010 LDBOOL R11 1 0 - 0x7C200600, // 0011 CALL R8 3 - 0x5C101000, // 0012 MOVE R4 R8 - 0x28200903, // 0013 GE R8 R4 K3 - 0x7822000B, // 0014 JMPF R8 #0021 - 0x8C200504, // 0015 GETMET R8 R2 K4 - 0x5C280E00, // 0016 MOVE R10 R7 - 0x5C2C0800, // 0017 MOVE R11 R4 - 0x7C200600, // 0018 CALL R8 3 - 0x94241103, // 0019 GETIDX R9 R8 K3 - 0x94281105, // 001A GETIDX R10 R8 K5 - 0x602C0012, // 001B GETGBL R11 G18 - 0x7C2C0000, // 001C CALL R11 0 - 0x40301606, // 001D CONNECT R12 R11 R6 - 0x40301609, // 001E CONNECT R12 R11 R9 - 0x4030160A, // 001F CONNECT R12 R11 R10 - 0x80041600, // 0020 RET 1 R11 - 0x60140012, // 0021 GETGBL R5 G18 - 0x7C140000, // 0022 CALL R5 0 - 0x40180A01, // 0023 CONNECT R6 R5 R1 - 0x4C180000, // 0024 LDNIL R6 - 0x40180A06, // 0025 CONNECT R6 R5 R6 - 0x4C180000, // 0026 LDNIL R6 - 0x40180A06, // 0027 CONNECT R6 R5 R6 - 0x80040A00, // 0028 RET 1 R5 + ( &(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 }) ) ); @@ -2349,18 +2249,20 @@ be_local_closure(Tasmota_add_rule, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 7]) { /* 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(value_error), - /* K6 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), + /* 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[24]) { /* code */ + ( &(const binstruction[27]) { /* code */ 0x8C100100, // 0000 GETMET R4 R0 K0 0x5C180400, // 0001 MOVE R6 R2 0x7C100400, // 0002 CALL R4 2 @@ -2373,18 +2275,21 @@ be_local_closure(Tasmota_add_rule, /* name */ 0x5C140400, // 0009 MOVE R5 R2 0x7C100200, // 000A CALL R4 1 0x1C100902, // 000B EQ R4 R4 K2 - 0x78120008, // 000C JMPF R4 #0016 + 0x7812000B, // 000C JMPF R4 #0019 0x88100101, // 000D GETMBR R4 R0 K1 0x8C100903, // 000E GETMET R4 R4 K3 0xB81A0800, // 000F GETNGBL R6 K4 - 0x5C1C0200, // 0010 MOVE R7 R1 - 0x5C200400, // 0011 MOVE R8 R2 - 0x5C240600, // 0012 MOVE R9 R3 - 0x7C180600, // 0013 CALL R6 3 - 0x7C100400, // 0014 CALL R4 2 - 0x70020000, // 0015 JMP #0017 - 0xB0060B06, // 0016 RAISE 1 K5 K6 - 0x80000000, // 0017 RET 0 + 0x881C0105, // 0010 GETMBR R7 R0 K5 + 0x8C1C0F06, // 0011 GETMET R7 R7 K6 + 0x5C240200, // 0012 MOVE R9 R1 + 0x7C1C0400, // 0013 CALL R7 2 + 0x5C200400, // 0014 MOVE R8 R2 + 0x5C240600, // 0015 MOVE R9 R3 + 0x7C180600, // 0016 CALL R6 3 + 0x7C100400, // 0017 CALL R4 2 + 0x70020000, // 0018 JMP #001A + 0xB0060F08, // 0019 RAISE 1 K7 K8 + 0x80000000, // 001A RET 0 }) ) ); @@ -2611,12 +2516,12 @@ be_local_closure(Tasmota_fast_loop, /* name */ 0x600C000C, // 0005 GETGBL R3 G12 0x5C100200, // 0006 MOVE R4 R1 0x7C0C0200, // 0007 CALL R3 1 - 0x140C0403, // 0008 LT R3 R2 R3 - 0x780E0003, // 0009 JMPF R3 #000E - 0x940C0202, // 000A GETIDX R3 R1 R2 - 0x7C0C0000, // 000B CALL R3 0 + 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 - 0x7001FFF6, // 000D JMP #0005 + 0x7001FFF9, // 000D JMP #0008 0x80000000, // 000E RET 0 }) ) diff --git a/lib/libesp32_lvgl/lvgl/library.json b/lib/libesp32_lvgl/lvgl/library.json index fe8ef4c15..928d7beed 100644 --- a/lib/libesp32_lvgl/lvgl/library.json +++ b/lib/libesp32_lvgl/lvgl/library.json @@ -1,6 +1,6 @@ { "name": "lvgl", - "version": "8.3.3", + "version": "8.3.6", "keywords": "graphics, gui, embedded, tft, lvgl", "description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.", "repository": { @@ -8,13 +8,11 @@ "url": "https://github.com/lvgl/lvgl.git" }, "build": { - "includeDir": "." + "includeDir": ".", + "flags": [ "-I$PROJECT_DIR/tasmota/lvgl_berry" ] }, "license": "MIT", "homepage": "https://lvgl.io", "frameworks": "arduino", - "platforms": "espressif32", - "build": { - "flags": [ "-I$PROJECT_DIR/tasmota/lvgl_berry" ] - } + "platforms": "espressif32" } diff --git a/lib/libesp32_lvgl/lvgl/library.properties b/lib/libesp32_lvgl/lvgl/library.properties index 816446a93..19de5008b 100644 --- a/lib/libesp32_lvgl/lvgl/library.properties +++ b/lib/libesp32_lvgl/lvgl/library.properties @@ -1,5 +1,5 @@ name=lvgl -version=8.3.3 +version=8.3.6 author=kisvegabor maintainer=kisvegabor,embeddedt,pete-pjb sentence=Full-featured Graphics Library for Embedded Systems diff --git a/lib/libesp32_lvgl/lvgl/lv_conf_template.h b/lib/libesp32_lvgl/lvgl/lv_conf_template.h index 3d087f0f3..f36af2a28 100644 --- a/lib/libesp32_lvgl/lvgl/lv_conf_template.h +++ b/lib/libesp32_lvgl/lvgl/lv_conf_template.h @@ -1,6 +1,6 @@ /** * @file lv_conf.h - * Configuration file for v8.3.3 + * Configuration file for v8.3.6 */ /* @@ -89,6 +89,9 @@ #if LV_TICK_CUSTOM #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ + /*If using lvgl as ESP32 component*/ + // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" + // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) #endif /*LV_TICK_CUSTOM*/ /*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. @@ -180,7 +183,7 @@ #define LV_USE_GPU_STM32_DMA2D 0 #if LV_USE_GPU_STM32_DMA2D /*Must be defined to include path of CMSIS header of target processor - e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ + e.g. "stm32f7xx.h" or "stm32f4xx.h"*/ #define LV_GPU_DMA2D_CMSIS_INCLUDE #endif diff --git a/lib/libesp32_lvgl/lvgl/lvgl.h b/lib/libesp32_lvgl/lvgl/lvgl.h index c0be411b2..6eedc7f23 100644 --- a/lib/libesp32_lvgl/lvgl/lvgl.h +++ b/lib/libesp32_lvgl/lvgl/lvgl.h @@ -15,7 +15,7 @@ extern "C" { ***************************/ #define LVGL_VERSION_MAJOR 8 #define LVGL_VERSION_MINOR 3 -#define LVGL_VERSION_PATCH 3 +#define LVGL_VERSION_PATCH 6 #define LVGL_VERSION_INFO "" /********************* diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_group.c b/lib/libesp32_lvgl/lvgl/src/core/lv_group.c index 2c4fa93e9..63fde71a0 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_group.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_group.c @@ -92,6 +92,7 @@ void lv_group_del(lv_group_t * group) indev = lv_indev_get_next(indev); } + if(default_group == group) default_group = NULL; _lv_ll_clear(&(group->obj_ll)); _lv_ll_remove(&LV_GC_ROOT(_lv_group_ll), group); lv_mem_free(group); diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c b/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c index ab1265ec8..caf9c3178 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_indev.c @@ -852,8 +852,6 @@ static void indev_proc_press(_lv_indev_proc_t * proc) if(indev_reset_check(proc)) return; } - lv_obj_transform_point(indev_obj_act, &proc->types.pointer.act_point, true, true); - /*If a new object was found reset some variables and send a pressed event handler*/ if(indev_obj_act != proc->types.pointer.act_obj) { proc->types.pointer.last_point.x = proc->types.pointer.act_point.x; @@ -987,6 +985,27 @@ static void indev_proc_release(_lv_indev_proc_t * proc) proc->pr_timestamp = 0; proc->longpr_rep_timestamp = 0; + + /*Get the transformed vector with this object*/ + if(scroll_obj) { + int16_t angle = 0; + int16_t zoom = 256; + lv_point_t pivot = { 0, 0 }; + lv_obj_t * parent = scroll_obj; + while(parent) { + angle += lv_obj_get_style_transform_angle(parent, 0); + zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256); + parent = lv_obj_get_parent(parent); + } + + if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) { + angle = -angle; + zoom = (256 * 256) / zoom; + lv_point_transform(&proc->types.pointer.scroll_throw_vect, angle, zoom, &pivot); + lv_point_transform(&proc->types.pointer.scroll_throw_vect_ori, angle, zoom, &pivot); + } + } + } /*The reset can be set in the Call the ancestor's event handler function. diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c b/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c index c05e3459f..3a7318316 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_indev_scroll.c @@ -45,12 +45,13 @@ static lv_coord_t elastic_diff(lv_obj_t * scroll_obj, lv_coord_t diff, lv_coord_ void _lv_indev_scroll_handler(_lv_indev_proc_t * proc) { + if(proc->types.pointer.vect.x == 0 && proc->types.pointer.vect.y == 0) { + return; + } + lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; /*If there is no scroll object yet try to find one*/ if(scroll_obj == NULL) { - proc->types.pointer.scroll_sum.x += proc->types.pointer.vect.x; - proc->types.pointer.scroll_sum.y += proc->types.pointer.vect.y; - scroll_obj = find_scroll_obj(proc); if(scroll_obj == NULL) return; @@ -61,35 +62,50 @@ void _lv_indev_scroll_handler(_lv_indev_proc_t * proc) } /*Set new position or scroll if the vector is not zero*/ - if(proc->types.pointer.vect.x != 0 || proc->types.pointer.vect.y != 0) { - lv_coord_t diff_x = 0; - lv_coord_t diff_y = 0; - - if(proc->types.pointer.scroll_dir == LV_DIR_HOR) { - lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); - lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); - diff_x = elastic_diff(scroll_obj, proc->types.pointer.vect.x, sl, sr, LV_DIR_HOR); - } - else { - lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); - lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); - diff_y = elastic_diff(scroll_obj, proc->types.pointer.vect.y, st, sb, LV_DIR_VER); - } - - lv_dir_t scroll_dir = lv_obj_get_scroll_dir(scroll_obj); - if((scroll_dir & LV_DIR_LEFT) == 0 && diff_x > 0) diff_x = 0; - if((scroll_dir & LV_DIR_RIGHT) == 0 && diff_x < 0) diff_x = 0; - if((scroll_dir & LV_DIR_TOP) == 0 && diff_y > 0) diff_y = 0; - if((scroll_dir & LV_DIR_BOTTOM) == 0 && diff_y < 0) diff_y = 0; - - /*Respect the scroll limit area*/ - scroll_limit_diff(proc, &diff_x, &diff_y); - - _lv_obj_scroll_by_raw(scroll_obj, diff_x, diff_y); - if(proc->reset_query) return; - proc->types.pointer.scroll_sum.x += diff_x; - proc->types.pointer.scroll_sum.y += diff_y; + int16_t angle = 0; + int16_t zoom = 256; + lv_obj_t * parent = scroll_obj; + while(parent) { + angle += lv_obj_get_style_transform_angle(parent, 0); + zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256); + parent = lv_obj_get_parent(parent); } + + if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) { + angle = -angle; + zoom = (256 * 256) / zoom; + lv_point_t pivot = { 0, 0 }; + lv_point_transform(&proc->types.pointer.vect, angle, zoom, &pivot); + } + + + + lv_coord_t diff_x = 0; + lv_coord_t diff_y = 0; + if(proc->types.pointer.scroll_dir == LV_DIR_HOR) { + lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); + lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); + diff_x = elastic_diff(scroll_obj, proc->types.pointer.vect.x, sl, sr, LV_DIR_HOR); + } + else { + lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); + lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); + diff_y = elastic_diff(scroll_obj, proc->types.pointer.vect.y, st, sb, LV_DIR_VER); + } + + lv_dir_t scroll_dir = lv_obj_get_scroll_dir(scroll_obj); + if((scroll_dir & LV_DIR_LEFT) == 0 && diff_x > 0) diff_x = 0; + if((scroll_dir & LV_DIR_RIGHT) == 0 && diff_x < 0) diff_x = 0; + if((scroll_dir & LV_DIR_TOP) == 0 && diff_y > 0) diff_y = 0; + if((scroll_dir & LV_DIR_BOTTOM) == 0 && diff_y < 0) diff_y = 0; + + /*Respect the scroll limit area*/ + scroll_limit_diff(proc, &diff_x, &diff_y); + + _lv_obj_scroll_by_raw(scroll_obj, diff_x, diff_y); + if(proc->reset_query) return; + proc->types.pointer.scroll_sum.x += diff_x; + proc->types.pointer.scroll_sum.y += diff_y; } @@ -99,7 +115,6 @@ void _lv_indev_scroll_throw_handler(_lv_indev_proc_t * proc) if(scroll_obj == NULL) return; if(proc->types.pointer.scroll_dir == LV_DIR_NONE) return; - lv_indev_t * indev_act = lv_indev_get_act(); lv_coord_t scroll_throw = indev_act->driver->scroll_throw; @@ -259,14 +274,36 @@ static lv_obj_t * find_scroll_obj(_lv_indev_proc_t * proc) /*Decide if it's a horizontal or vertical scroll*/ bool hor_en = false; bool ver_en = false; - if(LV_ABS(proc->types.pointer.scroll_sum.x) > LV_ABS(proc->types.pointer.scroll_sum.y)) { - hor_en = true; - } - else { - ver_en = true; - } + + proc->types.pointer.scroll_sum.x += proc->types.pointer.vect.x; + proc->types.pointer.scroll_sum.y += proc->types.pointer.vect.y; while(obj_act) { + /*Get the transformed scroll_sum with this object*/ + int16_t angle = 0; + int16_t zoom = 256; + lv_point_t pivot = { 0, 0 }; + lv_obj_t * parent = obj_act; + while(parent) { + angle += lv_obj_get_style_transform_angle(parent, 0); + zoom *= (lv_obj_get_style_transform_zoom(parent, 0) / 256); + parent = lv_obj_get_parent(parent); + } + + lv_point_t obj_scroll_sum = proc->types.pointer.scroll_sum; + if(angle != 0 || zoom != LV_IMG_ZOOM_NONE) { + angle = -angle; + zoom = (256 * 256) / zoom; + lv_point_transform(&obj_scroll_sum, angle, zoom, &pivot); + } + + if(LV_ABS(obj_scroll_sum.x) > LV_ABS(obj_scroll_sum.y)) { + hor_en = true; + } + else { + ver_en = true; + } + if(lv_obj_has_flag(obj_act, LV_OBJ_FLAG_SCROLLABLE) == false) { /*If this object don't want to chain the scroll to the parent stop searching*/ if(lv_obj_has_flag(obj_act, LV_OBJ_FLAG_SCROLL_CHAIN_HOR) == false && hor_en) break; @@ -300,15 +337,15 @@ static lv_obj_t * find_scroll_obj(_lv_indev_proc_t * proc) *is propagated to this object it can show at least elastic scroll effect. *But if not hor/ver scrollable do not scroll it at all (so it's not a good candidate)*/ if((st > 0 || sb > 0) && - ((up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || - (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit))) { + ((up_en && obj_scroll_sum.y >= scroll_limit) || + (down_en && obj_scroll_sum.y <= - scroll_limit))) { obj_candidate = obj_act; dir_candidate = LV_DIR_VER; } if((sl > 0 || sr > 0) && - ((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || - (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit))) { + ((left_en && obj_scroll_sum.x >= scroll_limit) || + (right_en && obj_scroll_sum.x <= - scroll_limit))) { obj_candidate = obj_act; dir_candidate = LV_DIR_HOR; } @@ -318,11 +355,11 @@ static lv_obj_t * find_scroll_obj(_lv_indev_proc_t * proc) if(sl <= 0) left_en = false; if(sr <= 0) right_en = false; - /*If the object really can be scrolled into the current direction the use it.*/ - if((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || - (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit) || - (up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || - (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit)) { + /*If the object really can be scrolled into the current direction then use it.*/ + if((left_en && obj_scroll_sum.x >= scroll_limit) || + (right_en && obj_scroll_sum.x <= - scroll_limit) || + (up_en && obj_scroll_sum.y >= scroll_limit) || + (down_en && obj_scroll_sum.y <= - scroll_limit)) { proc->types.pointer.scroll_dir = hor_en ? LV_DIR_HOR : LV_DIR_VER; break; } diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c b/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c index a31c11db8..5fc7db9ee 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_obj_pos.c @@ -1160,9 +1160,21 @@ static void transform_point(const lv_obj_t * obj, lv_point_t * p, bool inv) if(angle == 0 && zoom == LV_IMG_ZOOM_NONE) return; - lv_point_t pivot; - pivot.x = obj->coords.x1 + lv_obj_get_style_transform_pivot_x(obj, 0); - pivot.y = obj->coords.y1 + lv_obj_get_style_transform_pivot_y(obj, 0); + lv_point_t pivot = { + .x = lv_obj_get_style_transform_pivot_x(obj, 0), + .y = lv_obj_get_style_transform_pivot_y(obj, 0) + }; + + if(LV_COORD_IS_PCT(pivot.x)) { + pivot.x = (LV_COORD_GET_PCT(pivot.x) * lv_area_get_width(&obj->coords)) / 100; + } + if(LV_COORD_IS_PCT(pivot.y)) { + pivot.y = (LV_COORD_GET_PCT(pivot.y) * lv_area_get_height(&obj->coords)) / 100; + } + + pivot.x = obj->coords.x1 + pivot.x; + pivot.y = obj->coords.y1 + pivot.y; + if(inv) { angle = -angle; zoom = (256 * 256) / zoom; diff --git a/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c b/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c index 1a56fed0b..45ff2e0e7 100644 --- a/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c +++ b/lib/libesp32_lvgl/lvgl/src/core/lv_refr.c @@ -613,6 +613,9 @@ static void refr_area_part(lv_draw_ctx_t * draw_ctx) { lv_disp_draw_buf_t * draw_buf = lv_disp_get_draw_buf(disp_refr); + if(draw_ctx->init_buf) + draw_ctx->init_buf(draw_ctx); + /* Below the `area_p` area will be redrawn into the draw buffer. * In single buffered mode wait here until the buffer is freed. * In full double buffered mode wait here while the buffers are swapped and a buffer becomes available*/ @@ -914,6 +917,13 @@ void refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj) .y = lv_obj_get_style_transform_pivot_y(obj, 0) }; + if(LV_COORD_IS_PCT(pivot.x)) { + pivot.x = (LV_COORD_GET_PCT(pivot.x) * lv_area_get_width(&obj->coords)) / 100; + } + if(LV_COORD_IS_PCT(pivot.y)) { + pivot.y = (LV_COORD_GET_PCT(pivot.y) * lv_area_get_height(&obj->coords)) / 100; + } + lv_draw_img_dsc_t draw_dsc; lv_draw_img_dsc_init(&draw_dsc); draw_dsc.opa = opa; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c b/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c index 7777fe21b..f294125be 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/arm2d/lv_gpu_arm2d.c @@ -39,6 +39,7 @@ #include "../../core/lv_refr.h" #if LV_USE_GPU_ARM2D +#define __ARM_2D_IMPL__ #include "arm_2d.h" #include "__arm_2d_impl.h" @@ -89,10 +90,12 @@ #define __arm_2d_impl_cl_key_copy __arm_2d_impl_rgb16_cl_key_copy #define __arm_2d_impl_alpha_blending_colour_keying \ __arm_2d_impl_rgb565_alpha_blending_colour_keying -#define arm_2d_tile_transform_with_src_mask_and_opacity \ - arm_2d_rgb565_tile_transform_with_src_mask_and_opacity -#define arm_2d_tile_transform_with_opacity \ - arm_2d_rgb565_tile_transform_with_opacity +#define arm_2d_tile_transform_with_src_mask_and_opacity_prepare \ + arm_2dp_rgb565_tile_transform_with_src_mask_and_opacity_prepare +#define arm_2d_tile_transform_with_opacity_prepare \ + arm_2dp_rgb565_tile_transform_with_opacity_prepare +#define arm_2d_tile_transform_prepare \ + arm_2dp_rgb565_tile_transform_prepare #define __ARM_2D_PIXEL_BLENDING_OPA __ARM_2D_PIXEL_BLENDING_OPA_RGB565 @@ -124,10 +127,12 @@ #define __arm_2d_impl_cl_key_copy __arm_2d_impl_rgb32_cl_key_copy #define __arm_2d_impl_alpha_blending_colour_keying \ __arm_2d_impl_cccn888_alpha_blending_colour_keying -#define arm_2d_tile_transform_with_src_mask_and_opacity \ - arm_2d_cccn888_tile_transform_with_src_mask_and_opacity -#define arm_2d_tile_transform_with_opacity \ - arm_2d_cccn888_tile_transform_with_opacity +#define arm_2d_tile_transform_with_src_mask_and_opacity_prepare \ + arm_2dp_cccn888_tile_transform_with_src_mask_and_opacity_prepare +#define arm_2d_tile_transform_with_opacity_prepare \ + arm_2dp_cccn888_tile_transform_with_opacity_prepare +#define arm_2d_tile_transform_prepare \ + arm_2dp_cccn888_tile_transform_prepare #define __ARM_2D_PIXEL_BLENDING_OPA __ARM_2D_PIXEL_BLENDING_OPA_CCCN888 @@ -298,11 +303,88 @@ /* replace src_buf for the following operation */ \ src_buf = (const uint8_t *)rgb_tmp_buf; \ } \ - __VA_ARGS__ \ + do { \ + __VA_ARGS__ \ + } while(0); \ if (NULL != rgb_tmp_buf) { \ lv_mem_buf_release(rgb_tmp_buf); \ } \ - } while(0); + } while(0); \ + src_buf = src_buf_org; + +#define __RECOLOUR_BEGIN() \ + do { \ + lv_color_t *rgb_tmp_buf = NULL; \ + if(draw_dsc->recolor_opa > LV_OPA_MIN) { \ + rgb_tmp_buf \ + = lv_malloc(src_w * src_h * sizeof(lv_color_t)); \ + if (NULL == rgb_tmp_buf) { \ + LV_LOG_WARN( \ + "Failed to allocate memory for accelerating recolour, " \ + "use normal route instead."); \ + break; \ + } \ + lv_memcpy(rgb_tmp_buf, src_buf, src_w * src_h * sizeof(lv_color_t));\ + arm_2d_size_t copy_size = { \ + .iWidth = src_w, \ + .iHeight = src_h, \ + }; \ + /* apply re-colour */ \ + __arm_2d_impl_colour_filling_with_opacity( \ + (color_int *)rgb_tmp_buf, \ + src_w, \ + ©_size, \ + (color_int)draw_dsc->recolor.full, \ + draw_dsc->recolor_opa); \ + \ + /* replace src_buf for the following operation */ \ + src_buf = (const uint8_t *)rgb_tmp_buf; \ + } \ + do { + +#define __RECOLOUR_END() \ + } while(0); \ + if (NULL != rgb_tmp_buf) { \ + lv_free(rgb_tmp_buf); \ + } \ + } while(0); \ + src_buf = src_buf_org; + +#define __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION(__TRANS_PREPARE, ...) \ + do { \ + __TRANS_PREPARE( \ + NULL, \ + __VA_ARGS__); \ + \ + target_region = (arm_2d_region_t) { \ + .tLocation = { \ + .iX = coords->x1 - draw_ctx->clip_area->x1, \ + .iY = coords->y1 - draw_ctx->clip_area->y1, \ + }, \ + .tSize = { \ + .iWidth = lv_area_get_width(coords), \ + .iHeight = lv_area_get_height(coords), \ + }, \ + }; \ + \ + arm_2d_size_t tTransSize \ + = ARM_2D_CTRL.DefaultOP \ + .tTransform.Source.ptTile->tRegion.tSize; \ + \ + if (target_region.tSize.iWidth < tTransSize.iWidth) { \ + int16_t iDelta = tTransSize.iWidth - target_region.tSize.iWidth;\ + target_region.tLocation.iX -= iDelta / 2; \ + target_region.tSize.iWidth = tTransSize.iWidth; \ + } \ + \ + if (target_region.tSize.iHeight < tTransSize.iHeight) { \ + int16_t iDelta \ + = tTransSize.iHeight - target_region.tSize.iHeight; \ + target_region.tLocation.iY -= iDelta / 2; \ + target_region.tSize.iHeight = tTransSize.iHeight; \ + } \ + } while(0) + /* *INDENT-ON* */ /********************** @@ -601,18 +683,26 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend lv_area_t blend_area; if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + //lv_disp_t * disp = _lv_refr_get_disp_refreshing(); bool is_accelerated = false; do { - if(NULL != disp->driver->set_px_cb) { - break; + + /* target buffer */ + lv_color_t * dest_buf = draw_ctx->buf; + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + if(disp->driver->screen_transp == 0) { + dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1); + } + else { + /*With LV_COLOR_DEPTH 16 it means ARGB8565 (3 bytes format)*/ + uint8_t * dest_buf8 = (uint8_t *) dest_buf; + dest_buf8 += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) * LV_IMG_PX_SIZE_ALPHA_BYTE; + dest_buf8 += (blend_area.x1 - draw_ctx->buf_area->x1) * LV_IMG_PX_SIZE_ALPHA_BYTE; + dest_buf = (lv_color_t *)dest_buf8; } - lv_color_t * dest_buf = draw_ctx->buf; - dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) - + (blend_area.x1 - draw_ctx->buf_area->x1); - + /* source buffer */ const lv_color_t * src_buf = dsc->src_buf; lv_coord_t src_stride; if(src_buf) { @@ -634,7 +724,9 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - + if(disp->driver->screen_transp) { + break; + } if(dsc->src_buf == NULL) { if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) { is_accelerated = arm_2d_fill_normal(dest_buf, @@ -645,14 +737,8 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend mask, mask_stride); } -#if LV_DRAW_COMPLEX - else { - break; - } -#endif } else { - if(dsc->blend_mode == LV_BLEND_MODE_NORMAL) { is_accelerated = arm_2d_copy_normal(dest_buf, &blend_area, @@ -663,11 +749,6 @@ static void lv_draw_arm2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend mask, mask_stride); } -#if LV_DRAW_COMPLEX - else { - break; - } -#endif } } while(0); @@ -698,15 +779,11 @@ static bool arm_2d_fill_normal(lv_color_t * dest_buf, } /*Has opacity*/ else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_colour_filling_with_opacity((color_int *)dest_buf, dest_stride, &target_size, color.full, opa); -#endif } } /*Masked*/ @@ -722,9 +799,6 @@ static bool arm_2d_fill_normal(lv_color_t * dest_buf, } /*With opacity*/ else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_colour_filling_mask_opacity((color_int *)dest_buf, dest_stride, (uint8_t *)mask, @@ -732,7 +806,6 @@ static bool arm_2d_fill_normal(lv_color_t * dest_buf, &target_size, color.full, opa); -#endif } } @@ -759,10 +832,6 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, .iHeight = lv_area_get_height(dest_area), }; -#if LV_COLOR_SCREEN_TRANSP - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); -#endif - /*Simple fill (maybe with opacity), no masking*/ if(mask == NULL) { if(opa >= LV_OPA_MAX) { @@ -773,25 +842,18 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, ©_size); } else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_alpha_blending((color_int *)src_buf, src_stride, (color_int *)dest_buf, dest_stride, ©_size, opa); -#endif } } /*Masked*/ else { /*Only the mask matters*/ if(opa > LV_OPA_MAX) { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_src_msk_copy((color_int *)src_buf, src_stride, (uint8_t *)mask, @@ -800,13 +862,9 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, (color_int *)dest_buf, dest_stride, ©_size); -#endif } /*Handle opa and mask values too*/ else { -#if LV_COLOR_SCREEN_TRANSP - return false; -#else __arm_2d_impl_gray8_alpha_blending((uint8_t *)mask, mask_stride, (uint8_t *)mask, @@ -822,7 +880,6 @@ static bool arm_2d_copy_normal(lv_color_t * dest_buf, (color_int *)dest_buf, dest_stride, ©_size); -#endif } } @@ -839,6 +896,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, /*Use the clip area as draw area*/ lv_area_t draw_area; lv_area_copy(&draw_area, draw_ctx->clip_area); + const uint8_t * src_buf_org = src_buf; bool mask_any = lv_draw_mask_is_any(&draw_area); bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false; @@ -851,6 +909,13 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, blend_dsc.blend_mode = draw_dsc->blend_mode; blend_dsc.blend_area = &blend_area; + if(lv_img_cf_is_chroma_keyed(cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED; + else if(cf == LV_IMG_CF_ALPHA_8BIT) {} + else if(cf == LV_IMG_CF_RGB565A8) {} + else if(lv_img_cf_has_alpha(cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA; + else cf = LV_IMG_CF_TRUE_COLOR; + + /*The simplest case just copy the pixels into the draw_buf*/ if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) { blend_dsc.src_buf = (const lv_color_t *)src_buf; @@ -859,6 +924,9 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, lv_draw_sw_blend(draw_ctx, &blend_dsc); } else if(!mask_any && !transform && cf == LV_IMG_CF_ALPHA_8BIT) { + lv_area_t clipped_coords; + if(!_lv_area_intersect(&clipped_coords, coords, draw_ctx->clip_area)) return; + blend_dsc.mask_buf = (lv_opa_t *)src_buf; blend_dsc.mask_area = coords; blend_dsc.src_buf = NULL; @@ -869,7 +937,8 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, lv_draw_sw_blend(draw_ctx, &blend_dsc); } #if LV_COLOR_DEPTH == 16 - else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP) { + else if(!mask_any && !transform && cf == LV_IMG_CF_RGB565A8 && draw_dsc->recolor_opa == LV_OPA_TRANSP && + blend_dsc.opa >= LV_OPA_MAX) { lv_coord_t src_w = lv_area_get_width(coords); lv_coord_t src_h = lv_area_get_height(coords); blend_dsc.src_buf = (const lv_color_t *)src_buf; @@ -922,6 +991,23 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; blend_dsc.mask_res = mask_res_def; + if(cf == LV_IMG_CF_ALPHA_8BIT) { + /* original code: + lv_color_fill(rgb_buf, draw_dsc->recolor, buf_size); + */ + arm_2d_size_t copy_size = { + .iWidth = buf_w, + .iHeight = buf_h, + }; + + /* apply re-colour */ + __arm_2d_impl_colour_filling( + (color_int *)rgb_buf, + buf_w, + ©_size, + (color_int)draw_dsc->recolor.full); + } + bool is_accelerated = false; if(!transform) { @@ -968,7 +1054,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, } else if((LV_COLOR_DEPTH == 32) && !mask_any - && (cf == LV_IMG_CF_TRUE_COLOR_ALPHA)) { + && (LV_IMG_CF_TRUE_COLOR_ALPHA == cf)) { /* accelerate copy-with-source-masks-and-opacity */ /* *INDENT-OFF* */ @@ -1025,6 +1111,63 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, ) /* *INDENT-ON* */ } + else if(!mask_any + && (LV_IMG_CF_RGB565A8 == cf)) { + /* accelerate copy-with-source-masks-and-opacity */ + + uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h; + /* *INDENT-OFF* */ + __RECOLOUR_WRAPPER( + __PREPARE_LL_ACCELERATION__(); + + uint8_t * mask_temp_buf = NULL; + if(blend_dsc.opa < LV_OPA_MAX) { + mask_temp_buf = lv_mem_buf_get(copy_size.iHeight * copy_size.iWidth); + if(NULL == mask_temp_buf) { + LV_LOG_WARN( + "Failed to allocate memory for alpha mask," + " use normal route instead."); + break; + } + lv_memset_00(mask_temp_buf, copy_size.iHeight * copy_size.iWidth); + + __arm_2d_impl_gray8_colour_filling_mask_opacity( + mask_temp_buf, + src_stride, + mask_after_rgb, + src_stride, + ©_size, + 0xFF, + blend_dsc.opa); + + __arm_2d_impl_src_msk_copy( + (color_int *)src_buf_tmp, + src_stride, + mask_temp_buf, + src_stride, + ©_size, + (color_int *)dest_buf, + dest_stride, + ©_size); + + lv_mem_buf_release(mask_temp_buf); + } + else { + __arm_2d_impl_src_msk_copy( + (color_int *)src_buf_tmp, + src_stride, + mask_after_rgb, + src_stride, + ©_size, + (color_int *)dest_buf, + dest_stride, + ©_size); + } + + is_accelerated = true; + ) + /* *INDENT-ON* */ + } else if(!mask_any && (cf == LV_IMG_CF_TRUE_COLOR)) { /* accelerate copy-with-source-masks-and-opacity */ @@ -1063,6 +1206,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, && (draw_dsc->recolor_opa == LV_OPA_TRANSP) && (((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) || (LV_IMG_CF_TRUE_COLOR == cf)) + || (LV_IMG_CF_RGB565A8 == cf) #if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) && __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__ || ((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) && (LV_COLOR_DEPTH == 32)) @@ -1070,6 +1214,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, ) ) { + uint8_t * mask_after_rgb = src_buf + sizeof(lv_color_t) * src_w * src_h; /* *INDENT-OFF* */ __RECOLOUR_WRAPPER( /* accelerate transform without re-color */ @@ -1108,17 +1253,6 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, &target_tile, false); - target_region = (arm_2d_region_t) { - .tLocation = { - .iX = coords->x1 - draw_ctx->clip_area->x1, - .iY = coords->y1 - draw_ctx->clip_area->y1, - }, - .tSize = { - .iWidth = lv_area_get_width(coords), - .iHeight = lv_area_get_height(coords), - }, - }; - static arm_2d_tile_t source_tile; source_tile = (arm_2d_tile_t) { @@ -1132,45 +1266,81 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, .pchBuffer = (uint8_t *)src_buf, }; - static arm_2d_tile_t mask_tile; - mask_tile = source_tile; - - mask_tile.tInfo.bHasEnforcedColour = true; - mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_CHANNEL_8in32; - mask_tile.pchBuffer += 3; - static arm_2d_location_t source_center, target_center; source_center.iX = draw_dsc->pivot.x; source_center.iY = draw_dsc->pivot.y; - - if((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) || + if((LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED == cf) || (LV_IMG_CF_TRUE_COLOR == cf)) { - arm_2d_tile_transform_with_opacity( + + __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION( + arm_2d_tile_transform_with_opacity_prepare, &source_tile, - &target_tile, - &target_region, source_center, ARM_2D_ANGLE((draw_dsc->angle / 10.0f)), draw_dsc->zoom / 256.0f, (color_int)LV_COLOR_CHROMA_KEY.full, blend_dsc.opa); + arm_2d_tile_transform( + &target_tile, + &target_region, + NULL + ); + is_accelerated = true; + } + else if (LV_IMG_CF_RGB565A8 == cf) { + static arm_2d_tile_t mask_tile; + mask_tile = source_tile; + + mask_tile.tInfo.bHasEnforcedColour = true; + mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_COLOUR_GRAY8; + mask_tile.pchBuffer = mask_after_rgb; + + __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION( + arm_2d_tile_transform_with_src_mask_and_opacity_prepare, + &source_tile, + &mask_tile, + source_center, + ARM_2D_ANGLE((draw_dsc->angle / 10.0f)), + draw_dsc->zoom / 256.0f, + blend_dsc.opa + ); + + arm_2d_tile_transform( + &target_tile, + &target_region, + NULL + ); + is_accelerated = true; } #if defined(__ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__) \ && __ARM_2D_CFG_SUPPORT_COLOUR_CHANNEL_ACCESS__ - else if((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) && + else if((LV_IMG_CF_TRUE_COLOR_ALPHA == cf) && (LV_COLOR_DEPTH == 32)) { - arm_2d_tile_transform_with_src_mask_and_opacity( + static arm_2d_tile_t mask_tile; + mask_tile = source_tile; + + mask_tile.tInfo.bHasEnforcedColour = true; + mask_tile.tInfo.tColourInfo.chScheme = ARM_2D_CHANNEL_8in32; + mask_tile.pchBuffer += 3; + + __ARM_2D_PREPARE_TRANS_AND_TARGET_REGION( + arm_2d_tile_transform_with_src_mask_and_opacity_prepare, &source_tile, &mask_tile, - &target_tile, - &target_region, source_center, ARM_2D_ANGLE((draw_dsc->angle / 10.0f)), draw_dsc->zoom / 256.0f, - blend_dsc.opa); + blend_dsc.opa + ); + + arm_2d_tile_transform( + &target_tile, + &target_region, + NULL + ); is_accelerated = true; } @@ -1208,7 +1378,7 @@ static void lv_draw_arm2d_img_decoded(struct _lv_draw_ctx_t * draw_ctx, (color_int)draw_dsc->recolor.full, draw_dsc->recolor_opa); } -#if LV_DRAW_COMPLEX +#if LV_USE_DRAW_MASKS /*Apply the masks if any*/ if(mask_any) { lv_coord_t y; @@ -1275,7 +1445,7 @@ static void convert_cb(const lv_area_t * dest_area, const void * src_buf, lv_coo if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) { uint32_t px_cnt = lv_area_get_size(dest_area); - lv_memset_ff(abuf, px_cnt); + lv_memset(abuf, 0xff, px_cnt); src_tmp8 += (src_stride * dest_area->y1 * sizeof(lv_color_t)) + dest_area->x1 * sizeof(lv_color_t); uint32_t dest_w = lv_area_get_width(dest_area); diff --git a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h index 80b62e9f0..ffe1d4e27 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw.h @@ -72,6 +72,7 @@ typedef struct _lv_draw_ctx_t { */ const lv_area_t * clip_area; + void (*init_buf)(struct _lv_draw_ctx_t * draw_ctx); void (*draw_rect)(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); diff --git a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c index 41dc0f039..1deb39e0c 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/lv_draw_img.c @@ -69,18 +69,19 @@ void lv_draw_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const if(dsc->opa <= LV_OPA_MIN) return; - lv_res_t res; + lv_res_t res = LV_RES_INV; + if(draw_ctx->draw_img) { res = draw_ctx->draw_img(draw_ctx, dsc, coords, src); } - else { + + if(res != LV_RES_OK) { res = decode_and_draw(draw_ctx, dsc, coords, src); } - if(res == LV_RES_INV) { + if(res != LV_RES_OK) { LV_LOG_WARN("Image draw error"); show_error(draw_ctx, coords, "No\ndata"); - return; } } diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk b/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk index 17371ac98..18a751eab 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_draw_nxp.mk @@ -1,5 +1,3 @@ -CSRCS += lv_gpu_nxp.c - DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c deleted file mode 100644 index 46da9334a..000000000 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.c +++ /dev/null @@ -1,418 +0,0 @@ -/** - * @file lv_gpu_nxp.c - * - */ - -/** - * MIT License - * - * Copyright 2022 NXP - * - * 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 (including the next paragraph) - * 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. - * - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_gpu_nxp.h" - -#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE - -/* - * allow to use both PXP and VGLITE - - * both 2D accelerators can be used at the same time: - * thus VGLITE can be used to accelerate widget drawing - * while PXP accelerates Blit & Fill operations. - */ -#if LV_USE_GPU_NXP_PXP - #include "pxp/lv_draw_pxp_blend.h" -#endif -#if LV_USE_GPU_NXP_VG_LITE - #include "vglite/lv_draw_vglite_blend.h" - #include "vglite/lv_draw_vglite_rect.h" - #include "vglite/lv_draw_vglite_arc.h" -#endif - -#if LV_COLOR_DEPTH != 32 - #include "../../core/lv_refr.h" -#endif - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static void lv_draw_nxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf); - -static void lv_draw_nxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); - -static void lv_draw_nxp_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); - -static lv_res_t draw_nxp_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); - -static void lv_draw_nxp_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - uint16_t radius, uint16_t start_angle, uint16_t end_angle); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_draw_nxp_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) -{ - lv_draw_sw_init_ctx(drv, draw_ctx); - - lv_draw_nxp_ctx_t * nxp_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; - - nxp_draw_ctx->base_draw.draw_arc = lv_draw_nxp_arc; - nxp_draw_ctx->base_draw.draw_rect = lv_draw_nxp_rect; - nxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_nxp_img_decoded; - nxp_draw_ctx->blend = lv_draw_nxp_blend; - //nxp_draw_ctx->base_draw.wait_for_finish = lv_draw_nxp_wait_cb; -} - -void lv_draw_nxp_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) -{ - lv_draw_sw_deinit_ctx(drv, draw_ctx); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -/** - * During rendering, LVGL might initializes new draw_ctxs and start drawing into - * a separate buffer (called layer). If the content to be rendered has "holes", - * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag. - * It means the renderers should draw into an ARGB buffer. - * With 32 bit color depth it's not a big problem but with 16 bit color depth - * the target pixel format is ARGB8565 which is not supported by the GPU. - * In this case, the NXP callbacks should fallback to SW rendering. - */ -static inline bool need_argb8565_support() -{ -#if LV_COLOR_DEPTH != 32 - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - - if(disp->driver->screen_transp == 1) - return true; -#endif - - return false; -} - -static void lv_draw_nxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) -{ - lv_area_t blend_area; - - /*Let's get the blend area which is the intersection of the area to fill and the clip area.*/ - if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) - return; /*Fully clipped, nothing to do*/ - - /*Make the blend area relative to the buffer*/ - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - bool done = false; - - /*Fill/Blend only non masked, normal blended*/ - if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && !need_argb8565_support()) { - lv_color_t * dest_buf = draw_ctx->buf; - lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); -#if LV_USE_GPU_NXP_VG_LITE - lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area); - lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area); -#endif - - const lv_color_t * src_buf = dsc->src_buf; - - if(src_buf == NULL) { -#if LV_USE_GPU_NXP_PXP - done = (lv_gpu_nxp_pxp_fill(dest_buf, dest_stride, &blend_area, - dsc->color, dsc->opa) == LV_RES_OK); - if(!done) - PXP_LOG_TRACE("PXP fill failed. Fallback."); - -#endif -#if LV_USE_GPU_NXP_VG_LITE - if(!done) { - done = (lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &blend_area, - dsc->color, dsc->opa) == LV_RES_OK); - if(!done) - VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback."); - } -#endif - } - else { -#if LV_USE_GPU_NXP_PXP - done = (lv_gpu_nxp_pxp_blit(dest_buf, &blend_area, dest_stride, src_buf, dsc->blend_area, - dsc->opa, LV_DISP_ROT_NONE) == LV_RES_OK); - if(!done) - PXP_LOG_TRACE("PXP blit failed. Fallback."); -#endif -#if LV_USE_GPU_NXP_VG_LITE - if(!done) { - lv_gpu_nxp_vglite_blit_info_t blit; - lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); - - blit.src = src_buf; - blit.src_width = lv_area_get_width(dsc->blend_area); - blit.src_height = lv_area_get_height(dsc->blend_area); - blit.src_stride = src_stride * (int32_t)sizeof(lv_color_t); - blit.src_area.x1 = (blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1)); - blit.src_area.y1 = (blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1)); - blit.src_area.x2 = blit.src_area.x1 + blit.src_width - 1; - blit.src_area.y2 = blit.src_area.y1 + blit.src_height - 1; - - blit.dst = dest_buf; - blit.dst_width = dest_width; - blit.dst_height = dest_height; - blit.dst_stride = dest_stride * (int32_t)sizeof(lv_color_t); - blit.dst_area.x1 = blend_area.x1; - blit.dst_area.y1 = blend_area.y1; - blit.dst_area.x2 = blend_area.x2; - blit.dst_area.y2 = blend_area.y2; - - blit.opa = dsc->opa; - blit.zoom = LV_IMG_ZOOM_NONE; - blit.angle = 0; - - done = (lv_gpu_nxp_vglite_blit(&blit) == LV_RES_OK); - - if(!done) - VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback."); - } -#endif - } - } - - if(!done) - lv_draw_sw_blend_basic(draw_ctx, dsc); -} - -static void lv_draw_nxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf) -{ - /*Use the clip area as draw area*/ - lv_area_t draw_area; - lv_area_copy(&draw_area, draw_ctx->clip_area); - bool mask_any = lv_draw_mask_is_any(&draw_area); -#if LV_USE_GPU_NXP_VG_LITE - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); -#endif -#if LV_USE_GPU_NXP_PXP - bool scale = (dsc->zoom != LV_IMG_ZOOM_NONE); -#endif - bool done = false; - - lv_area_t blend_area; - /*Let's get the blend area which is the intersection of the area to fill and the clip area.*/ - if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area)) - return; /*Fully clipped, nothing to do*/ - - /*Make the blend area relative to the buffer*/ - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - const lv_color_t * src_buf = (const lv_color_t *)map_p; - if(!src_buf) { - lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); - return; - } - - lv_color_t * dest_buf = draw_ctx->buf; - lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); - -#if LV_USE_GPU_NXP_PXP - if(!mask_any && !scale && !need_argb8565_support() -#if LV_COLOR_DEPTH!=32 - && !lv_img_cf_has_alpha(cf) -#endif - ) { - done = (lv_gpu_nxp_pxp_blit_transform(dest_buf, &blend_area, dest_stride, src_buf, coords, - dsc, cf) == LV_RES_OK); - if(!done) - PXP_LOG_TRACE("PXP blit transform failed. Fallback."); - } -#endif - -#if LV_USE_GPU_NXP_VG_LITE - if(!done && !mask_any && !need_argb8565_support() && - !lv_img_cf_is_chroma_keyed(cf) && !recolor -#if LV_COLOR_DEPTH!=32 - && !lv_img_cf_has_alpha(cf) -#endif - ) { - lv_gpu_nxp_vglite_blit_info_t blit; - lv_coord_t src_stride = lv_area_get_width(coords); - - blit.src = src_buf; - blit.src_width = lv_area_get_width(coords); - blit.src_height = lv_area_get_height(coords); - blit.src_stride = src_stride * (int32_t)sizeof(lv_color_t); - blit.src_area.x1 = (blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1)); - blit.src_area.y1 = (blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1)); - blit.src_area.x2 = blit.src_area.x1 + blit.src_width - 1; - blit.src_area.y2 = blit.src_area.y1 + blit.src_height - 1; - - blit.dst = dest_buf; - blit.dst_width = lv_area_get_width(draw_ctx->buf_area); - blit.dst_height = lv_area_get_height(draw_ctx->buf_area); - blit.dst_stride = dest_stride * (int32_t)sizeof(lv_color_t); - blit.dst_area.x1 = blend_area.x1; - blit.dst_area.y1 = blend_area.y1; - blit.dst_area.x2 = blend_area.x2; - blit.dst_area.y2 = blend_area.y2; - - blit.opa = dsc->opa; - blit.angle = dsc->angle; - blit.pivot = dsc->pivot; - blit.zoom = dsc->zoom; - - done = (lv_gpu_nxp_vglite_blit_transform(&blit) == LV_RES_OK); - - if(!done) - VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback."); - } -#endif - - if(!done) - lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); -} - -static void lv_draw_nxp_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) -{ - bool done = false; - lv_draw_rect_dsc_t nxp_dsc; - - lv_memcpy(&nxp_dsc, dsc, sizeof(nxp_dsc)); -#if LV_DRAW_COMPLEX - /* Draw only the shadow */ - nxp_dsc.bg_opa = 0; - nxp_dsc.bg_img_opa = 0; - nxp_dsc.border_opa = 0; - nxp_dsc.outline_opa = 0; - - lv_draw_sw_rect(draw_ctx, &nxp_dsc, coords); - - /* Draw the background */ - nxp_dsc.shadow_opa = 0; - nxp_dsc.bg_opa = dsc->bg_opa; - done = (draw_nxp_bg(draw_ctx, &nxp_dsc, coords) == LV_RES_OK); -#endif /*LV_DRAW_COMPLEX*/ - - /* Draw the remaining parts */ - nxp_dsc.shadow_opa = 0; - if(done) - nxp_dsc.bg_opa = 0; - nxp_dsc.bg_img_opa = dsc->bg_img_opa; - nxp_dsc.border_opa = dsc->border_opa; - nxp_dsc.outline_opa = dsc->outline_opa; - - lv_draw_sw_rect(draw_ctx, &nxp_dsc, coords); -} - -static lv_res_t draw_nxp_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) -{ - if(dsc->bg_opa <= LV_OPA_MIN) - return LV_RES_INV; - - lv_area_t bg_coords; - lv_area_copy(&bg_coords, coords); - - /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/ - if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) { - bg_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0; - bg_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0; - bg_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0; - bg_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0; - } - - lv_area_t clipped_coords; - if(!_lv_area_intersect(&clipped_coords, &bg_coords, draw_ctx->clip_area)) - return LV_RES_INV; - - lv_grad_dir_t grad_dir = dsc->bg_grad.dir; - lv_color_t bg_color = grad_dir == LV_GRAD_DIR_NONE ? dsc->bg_color : dsc->bg_grad.stops[0].color; - if(bg_color.full == dsc->bg_grad.stops[1].color.full) grad_dir = LV_GRAD_DIR_NONE; - - bool mask_any = lv_draw_mask_is_any(&bg_coords); - - /* - * Most simple case: just a plain rectangle (no mask, no radius, no gradient) - * shall fallback to lv_draw_sw_blend(). - * - * Complex case: gradient or radius but no mask. - */ - if(!mask_any && ((dsc->radius != 0) || (grad_dir != LV_GRAD_DIR_NONE)) && !need_argb8565_support()) { -#if LV_USE_GPU_NXP_VG_LITE - lv_res_t res = lv_gpu_nxp_vglite_draw_bg(draw_ctx, dsc, &bg_coords); - if(res != LV_RES_OK) - VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback."); - - return res; -#endif - } - - return LV_RES_INV; -} - -static void lv_draw_nxp_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - uint16_t radius, uint16_t start_angle, uint16_t end_angle) -{ - bool done = false; - -#if LV_DRAW_COMPLEX - if(dsc->opa <= LV_OPA_MIN) - return; - if(dsc->width == 0) - return; - if(start_angle == end_angle) - return; - -#if LV_USE_GPU_NXP_VG_LITE - if(!need_argb8565_support()) { - done = (lv_gpu_nxp_vglite_draw_arc(draw_ctx, dsc, center, (int32_t)radius, - (int32_t)start_angle, (int32_t)end_angle) == LV_RES_OK); - if(!done) - VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback."); - } -#endif -#endif/*LV_DRAW_COMPLEX*/ - - if(!done) - lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); -} - -#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk index ff475a193..5c684bcd5 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_nxp_pxp.mk @@ -1,3 +1,4 @@ +CSRCS += lv_draw_pxp.c CSRCS += lv_draw_pxp_blend.c CSRCS += lv_gpu_nxp_pxp_osa.c CSRCS += lv_gpu_nxp_pxp.c diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c new file mode 100644 index 000000000..a7084b408 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.c @@ -0,0 +1,250 @@ +/** + * @file lv_draw_pxp.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * 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 (including the next paragraph) + * 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. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_pxp.h" + +#if LV_USE_GPU_NXP_PXP +#include "lv_draw_pxp_blend.h" + +#if LV_COLOR_DEPTH != 32 + #include "../../../core/lv_refr.h" +#endif + +/********************* + * DEFINES + *********************/ + +/* Minimum area (in pixels) for PXP blit/fill processing. */ +#ifndef LV_GPU_NXP_PXP_SIZE_LIMIT + #define LV_GPU_NXP_PXP_SIZE_LIMIT 5000 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void lv_draw_pxp_wait_for_finish(lv_draw_ctx_t * draw_ctx); + +static void lv_draw_pxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf); + +static void lv_draw_pxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_draw_pxp_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_init_ctx(drv, draw_ctx); + + lv_draw_pxp_ctx_t * pxp_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; + pxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_pxp_img_decoded; + pxp_draw_ctx->blend = lv_draw_pxp_blend; + pxp_draw_ctx->base_draw.wait_for_finish = lv_draw_pxp_wait_for_finish; +} + +void lv_draw_pxp_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_deinit_ctx(drv, draw_ctx); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * During rendering, LVGL might initializes new draw_ctxs and start drawing into + * a separate buffer (called layer). If the content to be rendered has "holes", + * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag. + * It means the renderers should draw into an ARGB buffer. + * With 32 bit color depth it's not a big problem but with 16 bit color depth + * the target pixel format is ARGB8565 which is not supported by the GPU. + * In this case, the PXP callbacks should fallback to SW rendering. + */ +static inline bool need_argb8565_support() +{ +#if LV_COLOR_DEPTH != 32 + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + + if(disp->driver->screen_transp == 1) + return true; +#endif + + return false; +} + +static void lv_draw_pxp_wait_for_finish(lv_draw_ctx_t * draw_ctx) +{ + lv_gpu_nxp_pxp_wait(); + + lv_draw_sw_wait_for_finish(draw_ctx); +} + +static void lv_draw_pxp_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area*/ + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + if(dsc->mask_buf != NULL || dsc->blend_mode != LV_BLEND_MODE_NORMAL || + lv_area_get_size(&blend_area) < LV_GPU_NXP_PXP_SIZE_LIMIT) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + + /*Fill/Blend only non masked, normal blended*/ + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + const lv_color_t * src_buf = dsc->src_buf; + + if(src_buf == NULL) { + lv_gpu_nxp_pxp_fill(dest_buf, &blend_area, dest_stride, dsc->color, dsc->opa); + } + else { + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1; + src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1; + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + + lv_gpu_nxp_pxp_blit(dest_buf, &blend_area, dest_stride, src_buf, &src_area, src_stride, + dsc->opa, LV_DISP_ROT_NONE); + } +} + +static void lv_draw_pxp_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + const lv_color_t * src_buf = (const lv_color_t *)map_p; + if(!src_buf) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area.*/ + if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_coord_t src_width = lv_area_get_width(coords); + lv_coord_t src_height = lv_area_get_height(coords); + + bool has_mask = lv_draw_mask_is_any(&blend_area); + bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE); + bool has_rotation = (dsc->angle != 0); + bool unsup_rotation = false; + + if(has_rotation) { + /* + * PXP can only rotate at 90x angles. + */ + if(dsc->angle % 900) { + PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); + unsup_rotation = true; + } + + /* + * PXP is set to process 16x16 blocks to optimize the system for memory + * bandwidth and image processing time. + * The output engine essentially truncates any output pixels after the + * desired number of pixels has been written. + * When rotating a source image and the output is not divisible by the block + * size, the incorrect pixels could be truncated and the final output image + * can look shifted. + */ + if(src_width % 16 || src_height % 16) { + PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16."); + unsup_rotation = true; + } + } + + if(has_mask || has_scale || unsup_rotation || lv_area_get_size(&blend_area) < LV_GPU_NXP_PXP_SIZE_LIMIT +#if LV_COLOR_DEPTH != 32 + || lv_img_cf_has_alpha(cf) +#endif + ) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + src_width - 1; + src_area.y2 = src_area.y1 + src_height - 1; + lv_coord_t src_stride = lv_area_get_width(coords); + + lv_gpu_nxp_pxp_blit_transform(dest_buf, &blend_area, dest_stride, src_buf, &src_area, src_stride, + dsc, cf); +} + +#endif /*LV_USE_GPU_NXP_PXP*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.h similarity index 77% rename from lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.h rename to lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.h index 899aff25b..1ace3bca4 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/lv_gpu_nxp.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp.h @@ -1,12 +1,12 @@ /** - * @file lv_gpu_nxp.h + * @file lv_draw_pxp.h * */ /** * MIT License * - * Copyright 2022 NXP + * Copyright 2022, 2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,8 +27,8 @@ * */ -#ifndef LV_GPU_NXP_H -#define LV_GPU_NXP_H +#ifndef LV_DRAW_PXP_H +#define LV_DRAW_PXP_H #ifdef __cplusplus extern "C" { @@ -38,9 +38,10 @@ extern "C" { * INCLUDES *********************/ -#include "../../lv_conf_internal.h" -#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE -#include "../sw/lv_draw_sw.h" +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_PXP +#include "../../sw/lv_draw_sw.h" /********************* * DEFINES @@ -49,23 +50,23 @@ extern "C" { /********************** * TYPEDEFS **********************/ -typedef lv_draw_sw_ctx_t lv_draw_nxp_ctx_t; +typedef lv_draw_sw_ctx_t lv_draw_pxp_ctx_t; /********************** * GLOBAL PROTOTYPES **********************/ -void lv_draw_nxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +void lv_draw_pxp_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); -void lv_draw_nxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +void lv_draw_pxp_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); /********************** * MACROS **********************/ -#endif /*LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE*/ +#endif /*LV_USE_GPU_NXP_PXP*/ #ifdef __cplusplus } /*extern "C"*/ #endif -#endif /*LV_GPU_NXP_H*/ +#endif /*LV_DRAW_PXP_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c index c0a6ecafa..a32c91710 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,20 +34,23 @@ #include "lv_draw_pxp_blend.h" #if LV_USE_GPU_NXP_PXP +#include "lvgl_support.h" /********************* * DEFINES *********************/ +#define PXP_TEMP_BUF_SIZE LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL + #if LV_COLOR_16_SWAP #error Color swap not implemented. Disable LV_COLOR_16_SWAP feature. #endif -#if LV_COLOR_DEPTH==16 +#if LV_COLOR_DEPTH == 16 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565 -#elif LV_COLOR_DEPTH==32 +#elif LV_COLOR_DEPTH == 32 #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatARGB8888 #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatARGB8888 #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB888 @@ -55,13 +58,6 @@ #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. #endif -#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \ - || defined (_WIN64) || defined (__LP64__) || defined (__LLP64__) - #define ALIGN_SIZE 8 -#else - #define ALIGN_SIZE 4 -#endif - /********************** * TYPEDEFS **********************/ @@ -70,63 +66,60 @@ * STATIC PROTOTYPES **********************/ +static LV_ATTRIBUTE_MEM_ALIGN uint8_t temp_buf[PXP_TEMP_BUF_SIZE]; + /** * BLock Image Transfer - copy rectangular image from src buffer to dst buffer * with combination of transformation (rotation, scale, recolor) and opacity, alpha channel * or color keying. This requires two steps. First step is used for transformation into * a temporary buffer and the second one will handle the color format or opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area area to be copied from src_buf to dst_buf - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /** * BLock Image Transfer - copy rectangular image from src buffer to dst buffer * with transformation and full opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area area to be copied from src_buf to dst_buf - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +static void lv_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /** * BLock Image Transfer - copy rectangular image from src buffer to dst buffer * without transformation but handling color format or opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area area to be copied from src_buf to dst_buf - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /********************** * STATIC VARIABLES @@ -136,45 +129,27 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * * MACROS **********************/ -#define ROUND_UP(x, align) ((x + (align - 1)) & ~(align - 1)) - /********************** * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa) +void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + lv_color_t color, lv_opa_t opa) { - uint32_t area_size = lv_area_get_size(fill_area); - lv_coord_t area_w = lv_area_get_width(fill_area); - lv_coord_t area_h = lv_area_get_height(fill_area); + lv_coord_t dest_w = lv_area_get_width(dest_area); + lv_coord_t dest_h = lv_area_get_height(dest_area); - if(opa >= (lv_opa_t)LV_OPA_MAX) { - if(area_size < LV_GPU_NXP_PXP_FILL_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_PXP_FILL_SIZE_LIMIT); - return LV_RES_INV; - } - } - else { - if(area_size < LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT); - return LV_RES_INV; - } - } - - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/ + lv_gpu_nxp_pxp_reset(); /*OUT buffer configure*/ pxp_output_buffer_config_t outputConfig = { .pixelFormat = PXP_OUT_PIXEL_FORMAT, .interlacedMode = kPXP_OutputProgressive, - .buffer0Addr = (uint32_t)(dest_buf + dest_stride * fill_area->y1 + fill_area->x1), + .buffer0Addr = (uint32_t)(dest_buf + dest_stride * dest_area->y1 + dest_area->x1), .buffer1Addr = (uint32_t)NULL, .pitchBytes = dest_stride * sizeof(lv_color_t), - .width = area_w, - .height = area_h + .width = dest_w, + .height = dest_h }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig); @@ -193,7 +168,7 @@ lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, cons }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, area_w, area_h); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); } /*Disable PS, use as color generator*/ @@ -223,34 +198,19 @@ lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, cons PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig); - lv_gpu_nxp_pxp_run(); /*Start PXP task*/ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } -lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle) +void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa, lv_disp_rot_t angle) { - uint32_t dest_size = lv_area_get_size(dest_area); lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area); + lv_coord_t src_w = lv_area_get_width(src_area); + lv_coord_t src_h = lv_area_get_height(src_area); - if(opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT); - return LV_RES_INV; - } - } - else { - if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT); - return LV_RES_INV; - } - } - - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/ + lv_gpu_nxp_pxp_reset(); /* convert rotation angle */ pxp_rotate_degree_t pxp_rot; @@ -297,19 +257,17 @@ lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, asBlendConfig.alphaMode = kPXP_AlphaOverride; PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig); - PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1); + PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); } - lv_coord_t src_stride = lv_area_get_width(src_area); - /*AS buffer - source image*/ pxp_as_buffer_config_t asBufferConfig = { .pixelFormat = PXP_AS_PIXEL_FORMAT, - .bufferAddr = (uint32_t)src_buf, + .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1), .pitchBytes = src_stride * sizeof(lv_color_t) }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); PXP_EnableAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, false); @@ -325,162 +283,102 @@ lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - lv_gpu_nxp_pxp_run(); /* Start PXP task */ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } -lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { - uint32_t dest_size = lv_area_get_size(dest_area); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + bool has_rotation = (dsc->angle != 0); - if(dsc->opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT); - return LV_RES_INV; + if(has_recolor || has_rotation) { + if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf)) { + lv_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf); + return; } - } - else { - if(dest_size < LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) { - PXP_LOG_TRACE("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT); - return LV_RES_INV; - } - } - - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); - bool rotation = (dsc->angle != 0); - - if(rotation) { - if(dsc->angle != 0 && dsc->angle != 900 && dsc->angle != 1800 && dsc->angle != 2700) { - PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); - return LV_RES_INV; - } - } - - if(recolor || rotation) { - if(dsc->opa >= (lv_opa_t)LV_OPA_MAX && !lv_img_cf_has_alpha(cf) && !lv_img_cf_is_chroma_keyed(cf)) - return lv_gpu_nxp_pxp_blit_cover(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); - else + else { /*Recolor and/or rotation with alpha or opacity is done in two steps.*/ - return lv_gpu_nxp_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); + lv_pxp_blit_opa(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf); + return; + } } - return lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, dsc, cf); + lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc, cf); } /********************** * STATIC FUNCTIONS **********************/ -static lv_res_t lv_gpu_nxp_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +static void lv_pxp_blit_opa(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { - lv_coord_t dest_w = lv_area_get_width(dest_area); - lv_coord_t dest_h = lv_area_get_height(dest_area); - lv_res_t res; - uint32_t size = dest_w * dest_h * sizeof(lv_color_t); - - if(ROUND_UP(size, ALIGN_SIZE) >= LV_MEM_SIZE) - PXP_RETURN_INV("Insufficient memory for temporary buffer. Please increase LV_MEM_SIZE."); - - lv_color_t * tmp_buf = (lv_color_t *)lv_mem_buf_get(size); - if(!tmp_buf) - PXP_RETURN_INV("Allocating temporary buffer failed."); - - const lv_area_t tmp_area = { + lv_coord_t temp_area_w = lv_area_get_width(dest_area); + lv_coord_t temp_area_h = lv_area_get_height(dest_area); + const lv_area_t temp_area = { .x1 = 0, .y1 = 0, - .x2 = dest_w - 1, - .y2 = dest_h - 1 + .x2 = temp_area_w - 1, + .y2 = temp_area_h - 1 }; /*Step 1: Transform with full opacity to temporary buffer*/ - res = lv_gpu_nxp_pxp_blit_cover(tmp_buf, &tmp_area, dest_w, src_buf, src_area, dsc, cf); - if(res != LV_RES_OK) { - PXP_LOG_TRACE("Blit cover with full opacity failed."); - lv_mem_buf_release(tmp_buf); + lv_pxp_blit_cover((lv_color_t *)temp_buf, &temp_area, temp_area_w, src_buf, src_area, src_stride, dsc, cf); - return res; - } - - /*Step 2: Blit temporary results with required opacity to output*/ - res = lv_gpu_nxp_pxp_blit_cf(dest_buf, dest_area, dest_stride, tmp_buf, &tmp_area, dsc, cf); - - /*Clean-up memory*/ - lv_mem_buf_release(tmp_buf); - - return res; + /*Step 2: Blit temporary result with required opacity to output*/ + lv_pxp_blit_cf(dest_buf, dest_area, dest_stride, (lv_color_t *)temp_buf, &temp_area, temp_area_w, dsc, cf); } - -static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +static void lv_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area); + lv_coord_t src_w = lv_area_get_width(src_area); + lv_coord_t src_h = lv_area_get_height(src_area); - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); - bool rotation = (dsc->angle != 0); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + bool has_rotation = (dsc->angle != 0); - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/ - - if(rotation) { - /* - * PXP is set to process 16x16 blocks to optimize the system for memory - * bandwidth and image processing time. - * The output engine essentially truncates any output pixels after the - * desired number of pixels has been written. - * When rotating a source image and the output is not divisible by the block - * size, the incorrect pixels could be truncated and the final output image - * can look shifted. - */ - if(lv_area_get_width(src_area) % 16 || lv_area_get_height(src_area) % 16) { - PXP_LOG_TRACE("Rotation is not supported for image w/o alignment to block size 16x16."); - return LV_RES_INV; - } + lv_gpu_nxp_pxp_reset(); + if(has_rotation) { /*Convert rotation angle*/ - pxp_rotate_degree_t pxp_rot; + pxp_rotate_degree_t pxp_angle; switch(dsc->angle) { case 0: - pxp_rot = kPXP_Rotate0; + pxp_angle = kPXP_Rotate0; break; case 900: - pxp_rot = kPXP_Rotate90; + pxp_angle = kPXP_Rotate90; break; case 1800: - pxp_rot = kPXP_Rotate180; + pxp_angle = kPXP_Rotate180; break; case 2700: - pxp_rot = kPXP_Rotate270; + pxp_angle = kPXP_Rotate270; break; default: - PXP_LOG_TRACE("Rotation angle %d is not supported. PXP can rotate only 90x angle.", dsc->angle); - return LV_RES_INV; + pxp_angle = kPXP_Rotate0; } - PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_rot, kPXP_FlipDisable); + PXP_SetRotateConfig(LV_GPU_NXP_PXP_ID, kPXP_RotateOutputBuffer, pxp_angle, kPXP_FlipDisable); } - lv_coord_t src_stride = lv_area_get_width(src_area); - /*AS buffer - source image*/ pxp_as_buffer_config_t asBufferConfig = { .pixelFormat = PXP_AS_PIXEL_FORMAT, - .bufferAddr = (uint32_t)src_buf, + .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1), .pitchBytes = src_stride * sizeof(lv_color_t) }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U); /*Disable PS buffer*/ PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); - if(recolor) + if(has_recolor) /*Use as color generator*/ PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(dsc->recolor)); @@ -496,7 +394,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - if(recolor || lv_img_cf_has_alpha(cf)) { + if(has_recolor || lv_img_cf_has_alpha(cf)) { /** * Configure Porter-Duff blending. * @@ -512,7 +410,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t .srcGlobalAlphaMode = lv_img_cf_has_alpha(cf) ? kPXP_PorterDuffLocalAlpha : kPXP_PorterDuffGlobalAlpha, .dstFactorMode = kPXP_PorterDuffFactorStraight, .srcFactorMode = kPXP_PorterDuffFactorInversed, - .dstGlobalAlpha = recolor ? dsc->recolor_opa : 0x00, + .dstGlobalAlpha = has_recolor ? dsc->recolor_opa : 0x00, .srcGlobalAlpha = 0xff, .dstAlphaMode = kPXP_PorterDuffAlphaStraight, /*don't care*/ .srcAlphaMode = kPXP_PorterDuffAlphaStraight @@ -520,22 +418,19 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cover(lv_color_t * dest_buf, const lv_area_t PXP_SetPorterDuffConfig(LV_GPU_NXP_PXP_ID, &pdConfig); } - lv_gpu_nxp_pxp_run(); /*Start PXP task*/ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } -static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, - lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, - const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) +static void lv_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf) { lv_coord_t dest_w = lv_area_get_width(dest_area); lv_coord_t dest_h = lv_area_get_height(dest_area); + lv_coord_t src_w = lv_area_get_width(src_area); + lv_coord_t src_h = lv_area_get_height(src_area); - PXP_Init(LV_GPU_NXP_PXP_ID); - PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ - PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*block size 16x16 for higher performance*/ + lv_gpu_nxp_pxp_reset(); pxp_as_blend_config_t asBlendConfig = { .alpha = dsc->opa, @@ -566,28 +461,26 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * asBlendConfig.alphaMode = lv_img_cf_has_alpha(cf) ? kPXP_AlphaMultiply : kPXP_AlphaOverride; } PXP_SetProcessSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &psBufferConfig); - PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1, dest_h - 1); + PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); } - lv_coord_t src_stride = lv_area_get_width(src_area); - /*AS buffer - source image*/ pxp_as_buffer_config_t asBufferConfig = { .pixelFormat = PXP_AS_PIXEL_FORMAT, - .bufferAddr = (uint32_t)src_buf, + .bufferAddr = (uint32_t)(src_buf + src_stride * src_area->y1 + src_area->x1), .pitchBytes = src_stride * sizeof(lv_color_t) }; PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); - PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, dest_w - 1U, dest_h - 1U); + PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, src_w - 1U, src_h - 1U); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); if(lv_img_cf_is_chroma_keyed(cf)) { lv_color_t colorKeyLow = LV_COLOR_CHROMA_KEY; lv_color_t colorKeyHigh = LV_COLOR_CHROMA_KEY; - bool recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); - if(recolor) { + if(has_recolor) { /* New color key after recoloring */ lv_color_t colorKey = lv_color_mix(dsc->recolor, LV_COLOR_CHROMA_KEY, dsc->recolor_opa); @@ -595,11 +488,11 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * LV_COLOR_SET_G(colorKeyLow, colorKey.ch.green != 0 ? colorKey.ch.green - 1 : 0); LV_COLOR_SET_B(colorKeyLow, colorKey.ch.blue != 0 ? colorKey.ch.blue - 1 : 0); -#if LV_COLOR_DEPTH==16 +#if LV_COLOR_DEPTH == 16 LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0x1f ? colorKey.ch.red + 1 : 0x1f); LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0x3f ? colorKey.ch.green + 1 : 0x3f); LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0x1f ? colorKey.ch.blue + 1 : 0x1f); -#else /*LV_COLOR_DEPTH==32*/ +#else /*LV_COLOR_DEPTH == 32*/ LV_COLOR_SET_R(colorKeyHigh, colorKey.ch.red != 0xff ? colorKey.ch.red + 1 : 0xff); LV_COLOR_SET_G(colorKeyHigh, colorKey.ch.green != 0xff ? colorKey.ch.green + 1 : 0xff); LV_COLOR_SET_B(colorKeyHigh, colorKey.ch.blue != 0xff ? colorKey.ch.blue + 1 : 0xff); @@ -624,9 +517,7 @@ static lv_res_t lv_gpu_nxp_pxp_blit_cf(lv_color_t * dest_buf, const lv_area_t * }; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - lv_gpu_nxp_pxp_run(); /* Start PXP task */ - - return LV_RES_OK; + lv_gpu_nxp_pxp_run(); } #endif /*LV_USE_GPU_NXP_PXP*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h index 43a6440de..9fe9192f7 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_draw_pxp_blend.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -48,31 +48,6 @@ extern "C" { * DEFINES *********************/ -#ifndef LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with 100% opacity to be handled by PXP*/ -#define LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with transparency to be handled by PXP*/ -#define LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT -/** Minimum invalidated area (in pixels) to be synchronized by PXP during buffer sync */ -#define LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_FILL_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by PXP with 100% opacity*/ -#define LV_GPU_NXP_PXP_FILL_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by PXP with transparency*/ -#define LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT 5000 -#endif - /********************** * TYPEDEFS **********************/ @@ -84,51 +59,49 @@ extern "C" { /** * Fill area, with optional opacity. * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] fill_area area to fill - * @param[in] color color - * @param[in] opa transparency of the color - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] color Color + * @param[in] opa Opacity */ -lv_res_t lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color, lv_opa_t opa); +void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + lv_color_t color, lv_opa_t opa); /** * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects. * By default, image is copied directly, with optional opacity. This function can also * rotate the display output buffer to a specified angle (90x step). * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area destination area - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] opa opacity of the result - * @param[in] angle display rotation angle (90x) - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] opa Opacity + * @param[in] angle Display rotation angle (90x) */ -lv_res_t lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, lv_opa_t opa, lv_disp_rot_t angle); +void lv_gpu_nxp_pxp_blit(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa, lv_disp_rot_t angle); /** * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation. * * - * @param[in/out] dest_buf destination buffer - * @param[in] dest_area destination area - * @param[in] dest_stride width (stride) of destination buffer in pixels - * @param[in] src_buf source buffer - * @param[in] src_area source area with absolute coordinates to draw on destination buffer - * @param[in] dsc image descriptor - * @param[in] cf color format - * @retval LV_RES_OK Fill completed - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_PXP_LOG_ERRORS) + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor + * @param[in] cf Color format */ -lv_res_t lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, const lv_area_t * src_area, const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); +void lv_gpu_nxp_pxp_blit_transform(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc, lv_img_cf_t cf); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c index 94d242a0d..164216f44 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -50,9 +50,9 @@ **********************/ /** - * Clean & invalidate cache. + * Clean and invalidate cache. */ -static void invalidate_cache(void); +static inline void invalidate_cache(void); /********************** * STATIC VARIABLES @@ -70,16 +70,23 @@ static lv_nxp_pxp_cfg_t * pxp_cfg; lv_res_t lv_gpu_nxp_pxp_init(void) { +#if LV_USE_GPU_NXP_PXP_AUTO_INIT pxp_cfg = lv_gpu_nxp_pxp_get_cfg(); +#endif - if(!pxp_cfg || !pxp_cfg->pxp_interrupt_deinit || !pxp_cfg->pxp_interrupt_init || !pxp_cfg->pxp_run) + if(!pxp_cfg || !pxp_cfg->pxp_interrupt_deinit || !pxp_cfg->pxp_interrupt_init || + !pxp_cfg->pxp_run || !pxp_cfg->pxp_wait) PXP_RETURN_INV("PXP configuration error."); PXP_Init(LV_GPU_NXP_PXP_ID); + PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ + PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/ + PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); if(pxp_cfg->pxp_interrupt_init() != LV_RES_OK) { + PXP_DisableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Deinit(LV_GPU_NXP_PXP_ID); PXP_RETURN_INV("PXP interrupt init failed."); } @@ -90,23 +97,38 @@ lv_res_t lv_gpu_nxp_pxp_init(void) void lv_gpu_nxp_pxp_deinit(void) { pxp_cfg->pxp_interrupt_deinit(); - PXP_DisableInterrupts(PXP, kPXP_CompleteInterruptEnable); + PXP_DisableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Deinit(LV_GPU_NXP_PXP_ID); } +void lv_gpu_nxp_pxp_reset(void) +{ + /* Wait for previous command to complete before resetting the registers. */ + lv_gpu_nxp_pxp_wait(); + + PXP_ResetControl(LV_GPU_NXP_PXP_ID); + + PXP_EnableCsc1(LV_GPU_NXP_PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ + PXP_SetProcessBlockSize(LV_GPU_NXP_PXP_ID, kPXP_BlockSize16); /*Block size 16x16 for higher performance*/ +} + void lv_gpu_nxp_pxp_run(void) { - /*Clean & invalidate cache*/ invalidate_cache(); pxp_cfg->pxp_run(); } +void lv_gpu_nxp_pxp_wait(void) +{ + pxp_cfg->pxp_wait(); +} + /********************** * STATIC FUNCTIONS **********************/ -static void invalidate_cache(void) +static inline void invalidate_cache(void) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); if(disp->driver->clean_dcache_cb) diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h index e695d8f13..10a67215a 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -81,8 +81,11 @@ typedef struct { /** Callback for PXP interrupt de-initialization*/ void (*pxp_interrupt_deinit)(void); - /** Callback that should start PXP and wait for operation complete*/ + /** Callback for PXP start*/ void (*pxp_run)(void); + + /** Callback for waiting of PXP completion*/ + void (*pxp_wait)(void); } lv_nxp_pxp_cfg_t; /********************** @@ -104,10 +107,20 @@ lv_res_t lv_gpu_nxp_pxp_init(void); void lv_gpu_nxp_pxp_deinit(void); /** - * Start PXP job and wait for completion. + * Reset PXP device. + */ +void lv_gpu_nxp_pxp_reset(void); + +/** + * Clear cache and start PXP. */ void lv_gpu_nxp_pxp_run(void); +/** + * Wait for PXP completion. + */ +void lv_gpu_nxp_pxp_wait(void); + /********************** * MACROS **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c index c4b8dbe57..8e1884036 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020, 2022 NXP + * Copyright 2020, 2022, 2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -65,24 +65,29 @@ static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void); static void _lv_gpu_nxp_pxp_interrupt_deinit(void); /** - * Start the PXP job and wait for task completion. + * Start the PXP job. */ static void _lv_gpu_nxp_pxp_run(void); +/** + * Wait for PXP completion. + */ +static void _lv_gpu_nxp_pxp_wait(void); + /********************** * STATIC VARIABLES **********************/ #if defined(SDK_OS_FREE_RTOS) - static SemaphoreHandle_t s_pxpIdle; -#else - static volatile bool s_pxpIdle; + static SemaphoreHandle_t s_pxpIdleSem; #endif +static volatile bool s_pxpIdle; static lv_nxp_pxp_cfg_t pxp_default_cfg = { .pxp_interrupt_init = _lv_gpu_nxp_pxp_interrupt_init, .pxp_interrupt_deinit = _lv_gpu_nxp_pxp_interrupt_deinit, - .pxp_run = _lv_gpu_nxp_pxp_run + .pxp_run = _lv_gpu_nxp_pxp_run, + .pxp_wait = _lv_gpu_nxp_pxp_wait, }; /********************** @@ -102,7 +107,7 @@ void PXP_IRQHandler(void) if(kPXP_CompleteFlag & PXP_GetStatusFlags(LV_GPU_NXP_PXP_ID)) { PXP_ClearStatusFlags(LV_GPU_NXP_PXP_ID, kPXP_CompleteFlag); #if defined(SDK_OS_FREE_RTOS) - xSemaphoreGiveFromISR(s_pxpIdle, &taskAwake); + xSemaphoreGiveFromISR(s_pxpIdleSem, &taskAwake); portYIELD_FROM_ISR(taskAwake); #else s_pxpIdle = true; @@ -122,14 +127,13 @@ lv_nxp_pxp_cfg_t * lv_gpu_nxp_pxp_get_cfg(void) static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void) { #if defined(SDK_OS_FREE_RTOS) - s_pxpIdle = xSemaphoreCreateBinary(); - if(s_pxpIdle == NULL) + s_pxpIdleSem = xSemaphoreCreateBinary(); + if(s_pxpIdleSem == NULL) return LV_RES_INV; NVIC_SetPriority(LV_GPU_NXP_PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1); -#else - s_pxpIdle = true; #endif + s_pxpIdle = true; NVIC_EnableIRQ(LV_GPU_NXP_PXP_IRQ_ID); @@ -140,21 +144,33 @@ static void _lv_gpu_nxp_pxp_interrupt_deinit(void) { NVIC_DisableIRQ(LV_GPU_NXP_PXP_IRQ_ID); #if defined(SDK_OS_FREE_RTOS) - vSemaphoreDelete(s_pxpIdle); + vSemaphoreDelete(s_pxpIdleSem); #endif } +/** + * Function to start PXP job. + */ static void _lv_gpu_nxp_pxp_run(void) { -#if !defined(SDK_OS_FREE_RTOS) s_pxpIdle = false; -#endif PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Start(LV_GPU_NXP_PXP_ID); +} +/** + * Function to wait for PXP completion. + */ +static void _lv_gpu_nxp_pxp_wait(void) +{ #if defined(SDK_OS_FREE_RTOS) - PXP_COND_STOP(!xSemaphoreTake(s_pxpIdle, portMAX_DELAY), "xSemaphoreTake failed."); + /* Return if PXP was never started, otherwise the semaphore will lock forever. */ + if(s_pxpIdle == true) + return; + + if(xSemaphoreTake(s_pxpIdleSem, portMAX_DELAY) == pdTRUE) + s_pxpIdle = true; #else while(s_pxpIdle == false) { } diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk index c84e2e47a..c9473cc10 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_nxp_vglite.mk @@ -1,7 +1,10 @@ +CSRCS += lv_draw_vglite.c CSRCS += lv_draw_vglite_arc.c CSRCS += lv_draw_vglite_blend.c +CSRCS += lv_draw_vglite_line.c CSRCS += lv_draw_vglite_rect.c -CSRCS += lv_gpu_nxp_vglite.c +CSRCS += lv_vglite_buf.c +CSRCS += lv_vglite_utils.c DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp/vglite VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/nxp/vglite diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c new file mode 100644 index 000000000..eae1b8a58 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.c @@ -0,0 +1,508 @@ +/** + * @file lv_draw_vglite.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * 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 (including the next paragraph) + * 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. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_vglite.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include +#include "lv_draw_vglite_blend.h" +#include "lv_draw_vglite_line.h" +#include "lv_draw_vglite_rect.h" +#include "lv_draw_vglite_arc.h" +#include "lv_vglite_buf.h" + +#if LV_COLOR_DEPTH != 32 + #include "../../../core/lv_refr.h" +#endif + +/********************* + * DEFINES + *********************/ + +/* Minimum area (in pixels) for VG-Lite blit/fill processing. */ +#ifndef LV_GPU_NXP_VG_LITE_SIZE_LIMIT + #define LV_GPU_NXP_VG_LITE_SIZE_LIMIT 5000 +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx); + +static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx); + +static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf); + +static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); + +static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2); + +static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); + +static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords); + +static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords); + +static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + uint16_t radius, uint16_t start_angle, uint16_t end_angle); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_draw_vglite_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_init_ctx(drv, draw_ctx); + + lv_draw_vglite_ctx_t * vglite_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; + vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf; + vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line; + vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc; + vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect; + vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded; + vglite_draw_ctx->blend = lv_draw_vglite_blend; + vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish; +} + +void lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) +{ + lv_draw_sw_deinit_ctx(drv, draw_ctx); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * During rendering, LVGL might initializes new draw_ctxs and start drawing into + * a separate buffer (called layer). If the content to be rendered has "holes", + * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag. + * It means the renderers should draw into an ARGB buffer. + * With 32 bit color depth it's not a big problem but with 16 bit color depth + * the target pixel format is ARGB8565 which is not supported by the GPU. + * In this case, the VG-Lite callbacks should fallback to SW rendering. + */ +static inline bool need_argb8565_support() +{ +#if LV_COLOR_DEPTH != 32 + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + + if(disp->driver->screen_transp == 1) + return true; +#endif + + return false; +} + +static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx) +{ + lv_gpu_nxp_vglite_init_buf(draw_ctx->buf, draw_ctx->buf_area, lv_area_get_width(draw_ctx->buf_area)); +} + +static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx) +{ + vg_lite_finish(); + + lv_draw_sw_wait_for_finish(draw_ctx); +} + +static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area*/ + if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + bool done = false; + /*Fill/Blend only non masked, normal blended*/ + if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && + lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT) { + const lv_color_t * src_buf = dsc->src_buf; + + if(src_buf == NULL) { + done = (lv_gpu_nxp_vglite_fill(&blend_area, dsc->color, dsc->opa) == LV_RES_OK); + if(!done) + VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback."); + } + else { + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1; + src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1; + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + + done = (lv_gpu_nxp_vglite_blit(dest_buf, &blend_area, dest_stride, + src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK); + + if(!done) + VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback."); + } + } + + if(!done) + lv_draw_sw_blend_basic(draw_ctx, dsc); +} + +static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, + const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf) +{ + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + + if(need_argb8565_support()) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + const lv_color_t * src_buf = (const lv_color_t *)map_p; + if(!src_buf) { + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); + return; + } + + lv_area_t blend_area; + /*Let's get the blend area which is the intersection of the area to draw and the clip area*/ + if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /*Make the blend area relative to the buffer*/ + lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + bool has_mask = lv_draw_mask_is_any(&blend_area); + bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + + bool done = false; + if(!has_mask && !has_recolor && !lv_img_cf_is_chroma_keyed(cf) && + lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT +#if LV_COLOR_DEPTH != 32 + && !lv_img_cf_has_alpha(cf) +#endif + ) { + lv_color_t * dest_buf = draw_ctx->buf; + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + + lv_area_t src_area; + src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1); + src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1); + src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1; + src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1; + lv_coord_t src_stride = lv_area_get_width(coords); + + done = (lv_gpu_nxp_vglite_blit_transform(dest_buf, &blend_area, dest_stride, + src_buf, &src_area, src_stride, dsc) == LV_RES_OK); + + if(!done) + VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback."); + } + + if(!done) + lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf); +} + +static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1, + const lv_point_t * point2) +{ + if(dsc->width == 0) + return; + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + if(point1->x == point2->x && point1->y == point2->y) + return; + + if(need_argb8565_support()) { + lv_draw_sw_line(draw_ctx, dsc, point1, point2); + return; + } + + lv_area_t rel_clip_area; + rel_clip_area.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2; + rel_clip_area.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2; + rel_clip_area.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2; + rel_clip_area.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2; + + bool is_common; + is_common = _lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_ctx->clip_area); + if(!is_common) + return; + + /* Make coordinates relative to the draw buffer */ + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_point_t rel_point1 = { point1->x - draw_ctx->buf_area->x1, point1->y - draw_ctx->buf_area->y1 }; + lv_point_t rel_point2 = { point2->x - draw_ctx->buf_area->x1, point2->y - draw_ctx->buf_area->y1 }; + + bool done = false; + bool mask_any = lv_draw_mask_is_any(&rel_clip_area); + + if(!mask_any) { + done = (lv_gpu_nxp_vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc) == LV_RES_OK); + if(!done) + VG_LITE_LOG_TRACE("VG-Lite draw line failed. Fallback."); + } + + if(!done) + lv_draw_sw_line(draw_ctx, dsc, point1, point2); +} + +static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) +{ + if(need_argb8565_support()) { + lv_draw_sw_rect(draw_ctx, dsc, coords); + return; + } + + lv_draw_rect_dsc_t vglite_dsc; + + lv_memcpy(&vglite_dsc, dsc, sizeof(vglite_dsc)); + vglite_dsc.bg_opa = 0; + vglite_dsc.bg_img_opa = 0; + vglite_dsc.border_opa = 0; + vglite_dsc.outline_opa = 0; +#if LV_DRAW_COMPLEX + /* Draw the shadow with CPU */ + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.shadow_opa = 0; +#endif /*LV_DRAW_COMPLEX*/ + + /* Draw the background */ + vglite_dsc.bg_opa = dsc->bg_opa; + if(lv_draw_vglite_bg(draw_ctx, &vglite_dsc, coords) != LV_RES_OK) + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.bg_opa = 0; + + /* Draw the background image + * It will be done once draw_ctx->draw_img_decoded() + * callback gets called from lv_draw_sw_rect(). + */ + vglite_dsc.bg_img_opa = dsc->bg_img_opa; + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.bg_img_opa = 0; + + /* Draw the border */ + vglite_dsc.border_opa = dsc->border_opa; + if(lv_draw_vglite_border(draw_ctx, &vglite_dsc, coords) != LV_RES_OK) + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); + vglite_dsc.border_opa = 0; + + /* Draw the outline */ + vglite_dsc.outline_opa = dsc->outline_opa; + if(lv_draw_vglite_outline(draw_ctx, &vglite_dsc, coords) != LV_RES_OK) + lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords); +} + +static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) +{ + if(dsc->bg_opa <= (lv_opa_t)LV_OPA_MIN) + return LV_RES_INV; + + lv_area_t rel_coords; + lv_area_copy(&rel_coords, coords); + + /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/ + if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) { + rel_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0; + rel_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0; + rel_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0; + rel_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0; + } + + /* Make coordinates relative to draw buffer */ + lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t clipped_coords; + if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area)) + return LV_RES_INV; + + bool mask_any = lv_draw_mask_is_any(&rel_coords); + lv_grad_dir_t grad_dir = dsc->bg_grad.dir; + lv_color_t bg_color = (grad_dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) ? + dsc->bg_color : dsc->bg_grad.stops[0].color; + if(bg_color.full == dsc->bg_grad.stops[1].color.full) + grad_dir = LV_GRAD_DIR_NONE; + + /* + * Most simple case: just a plain rectangle (no mask, no radius, no gradient) + * shall be handled by draw_ctx->blend(). + * + * Complex case: gradient or radius but no mask. + */ + if(!mask_any && ((dsc->radius != 0) || (grad_dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))) { + lv_res_t res = lv_gpu_nxp_vglite_draw_bg(&rel_coords, &rel_clip_area, dsc); + if(res != LV_RES_OK) + VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback."); + + return res; + } + + return LV_RES_INV; +} + +static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords) +{ + if(dsc->border_opa <= (lv_opa_t)LV_OPA_MIN) + return LV_RES_INV; + if(dsc->border_width == 0) + return LV_RES_INV; + if(dsc->border_post) + return LV_RES_INV; + if(dsc->border_side != (lv_border_side_t)LV_BORDER_SIDE_FULL) + return LV_RES_INV; + + lv_area_t rel_coords; + lv_coord_t border_width = dsc->border_width; + + /* Move border inwards to align with software rendered border */ + rel_coords.x1 = coords->x1 + ceil(border_width / 2.0f); + rel_coords.x2 = coords->x2 - floor(border_width / 2.0f); + rel_coords.y1 = coords->y1 + ceil(border_width / 2.0f); + rel_coords.y2 = coords->y2 - floor(border_width / 2.0f); + + /* Make coordinates relative to the draw buffer */ + lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, true); + if(res != LV_RES_OK) + VG_LITE_LOG_TRACE("VG-Lite draw border failed. Fallback."); + + return res; +} + +static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, + const lv_area_t * coords) +{ + if(dsc->outline_opa <= (lv_opa_t)LV_OPA_MIN) + return LV_RES_INV; + if(dsc->outline_width == 0) + return LV_RES_INV; + + /* Move outline outwards to align with software rendered outline */ + lv_coord_t outline_pad = dsc->outline_pad - 1; + lv_area_t rel_coords; + rel_coords.x1 = coords->x1 - outline_pad - floor(dsc->outline_width / 2.0f); + rel_coords.x2 = coords->x2 + outline_pad + ceil(dsc->outline_width / 2.0f); + rel_coords.y1 = coords->y1 - outline_pad - floor(dsc->outline_width / 2.0f); + rel_coords.y2 = coords->y2 + outline_pad + ceil(dsc->outline_width / 2.0f); + + /* Make coordinates relative to the draw buffer */ + lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, false); + if(res != LV_RES_OK) + VG_LITE_LOG_TRACE("VG-Lite draw outline failed. Fallback."); + + return res; +} + +static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, + uint16_t radius, uint16_t start_angle, uint16_t end_angle) +{ + bool done = false; + +#if LV_DRAW_COMPLEX + if(dsc->opa <= (lv_opa_t)LV_OPA_MIN) + return; + if(dsc->width == 0) + return; + if(start_angle == end_angle) + return; + + if(need_argb8565_support()) { + lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); + return; + } + + /* Make coordinates relative to the draw buffer */ + lv_point_t rel_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1}; + + lv_area_t rel_clip_area; + lv_area_copy(&rel_clip_area, draw_ctx->clip_area); + lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + + done = (lv_gpu_nxp_vglite_draw_arc(&rel_center, (int32_t)radius, (int32_t)start_angle, (int32_t)end_angle, + &rel_clip_area, dsc) == LV_RES_OK); + if(!done) + VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback."); +#endif/*LV_DRAW_COMPLEX*/ + + if(!done) + lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle); +} + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h new file mode 100644 index 000000000..c44cb8fc7 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite.h @@ -0,0 +1,72 @@ +/** + * @file lv_draw_vglite.h + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * 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 (including the next paragraph) + * 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 LV_DRAW_VGLITE_H +#define LV_DRAW_VGLITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "../../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef lv_draw_sw_ctx_t lv_draw_vglite_ctx_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_draw_vglite_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +void lv_draw_vglite_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); + +/********************** + * MACROS + **********************/ +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c index 194f03d88..775bf734b 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,8 @@ #include "lv_draw_vglite_arc.h" #if LV_USE_GPU_NXP_VG_LITE -#include "math.h" +#include "lv_vglite_buf.h" +#include /********************* * DEFINES @@ -88,7 +89,7 @@ typedef struct _cubic_cont_pt { static void rotate_point(int32_t angle, int32_t * x, int32_t * y); static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, - int32_t start_angle, int32_t end_angle, lv_point_t center, bool cw); + int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw); /********************** * STATIC VARIABLES @@ -102,31 +103,20 @@ static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - int32_t radius, int32_t start_angle, int32_t end_angle) +lv_res_t lv_gpu_nxp_vglite_draw_arc(const lv_point_t * center, int32_t radius, int32_t start_angle, int32_t end_angle, + const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc) { - - vg_lite_buffer_t vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; lv_color32_t col32 = {.full = lv_color_to32(dsc->color)}; /*Convert color to RGBA8888*/ - lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area); - lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area); vg_lite_path_t path; vg_lite_color_t vgcol; /* vglite takes ABGR */ - vg_lite_matrix_t matrix; - lv_opa_t opa = dsc->opa; bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false; - lv_point_t clip_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1}; + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); /* path: max size = 16 cubic bezier (7 words each) */ int32_t arc_path[16 * 7]; lv_memset_00(arc_path, sizeof(arc_path)); - /*** Init destination buffer ***/ - if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), - (const lv_color_t *)draw_ctx->buf, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - /*** Init path ***/ lv_coord_t width = dsc->width; /* inner arc radius = outer arc radius - width */ if(width > (lv_coord_t)radius) @@ -140,11 +130,11 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_MOVE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; /* draw 1-5 outer quarters */ - add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, clip_center, true); + add_arc_path(arc_path, &pidx, radius, start_angle, end_angle, center, true); if(donut) { /* close outer circle */ @@ -152,24 +142,24 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; /* start inner circle */ cp_x = radius - width; cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_MOVE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } else if(dsc->rounded != 0U) { /* 1st rounded arc ending */ cp_x = radius - width / 2; cp_y = 0; rotate_point(end_angle, &cp_x, &cp_y); - lv_point_t round_center = {clip_center.x + cp_x, clip_center.y + cp_y}; + lv_point_t round_center = {center->x + cp_x, center->y + cp_y}; add_arc_path(arc_path, &pidx, width / 2, end_angle, (end_angle + 180), - round_center, true); + &round_center, true); } else { /* 1st flat ending */ @@ -177,12 +167,12 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(end_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } /* draw 1-5 inner quarters */ - add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, clip_center, false); + add_arc_path(arc_path, &pidx, radius - width, start_angle, end_angle, center, false); /* last control point of curve */ if(donut) { /* close the loop */ @@ -190,17 +180,17 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } else if(dsc->rounded != 0U) { /* 2nd rounded arc ending */ cp_x = radius - width / 2; cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); - lv_point_t round_center = {clip_center.x + cp_x, clip_center.y + cp_y}; + lv_point_t round_center = {center->x + cp_x, center->y + cp_y}; add_arc_path(arc_path, &pidx, width / 2, (start_angle + 180), (start_angle + 360), - round_center, true); + &round_center, true); } else { /* 2nd flat ending */ @@ -208,46 +198,30 @@ lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_ cp_y = 0; rotate_point(start_angle, &cp_x, &cp_y); arc_path[pidx++] = VLC_OP_LINE; - arc_path[pidx++] = clip_center.x + cp_x; - arc_path[pidx++] = clip_center.y + cp_y; + arc_path[pidx++] = center->x + cp_x; + arc_path[pidx++] = center->y + cp_y; } arc_path[pidx++] = VLC_OP_END; err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, (uint32_t)pidx * sizeof(int32_t), arc_path, - (vg_lite_float_t) draw_ctx->clip_area->x1, (vg_lite_float_t) draw_ctx->clip_area->y1, - ((vg_lite_float_t) draw_ctx->clip_area->x2) + 1.0f, ((vg_lite_float_t) draw_ctx->clip_area->y2) + 1.0f); + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); VG_LITE_ERR_RETURN_INV(err, "Init path failed."); - /* set rotation angle */ + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, dsc->opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); + + vg_lite_matrix_t matrix; vg_lite_identity(&matrix); - if(opa <= (lv_opa_t)LV_OPA_MAX) { - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - col32.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8); - col32.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8); - col32.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8); - } - col32.ch.alpha = opa; - } - -#if LV_COLOR_DEPTH==16 - vgcol = col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) | - (uint32_t)col32.ch.red; -#endif - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); - /*** Draw arc ***/ - err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); VG_LITE_ERR_RETURN_INV(err, "Draw arc failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); err = vg_lite_clear_path(&path); VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); @@ -564,50 +538,50 @@ static void get_arc_control_points(vg_arc * arc, bool start) * center: (in) the center of the circle in draw coordinates * cw: (in) true if arc is clockwise */ -static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, lv_point_t center, bool cw) +static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, const lv_point_t * center, bool cw) { /* assumes first control point already in array arc_path[] */ int idx = *pidx; if(cw) { #if BEZIER_DBG_CONTROL_POINTS arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p3x + center.x; - arc_path[idx++] = q_arc->p3y + center.y; + arc_path[idx++] = q_arc->p3x + center->x; + arc_path[idx++] = q_arc->p3y + center->y; #else arc_path[idx++] = VLC_OP_CUBIC; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; - arc_path[idx++] = q_arc->p3x + center.x; - arc_path[idx++] = q_arc->p3y + center.y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; + arc_path[idx++] = q_arc->p3x + center->x; + arc_path[idx++] = q_arc->p3y + center->y; #endif } else { /* reverse points order when counter-clockwise */ #if BEZIER_DBG_CONTROL_POINTS arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; arc_path[idx++] = VLC_OP_LINE; - arc_path[idx++] = q_arc->p0x + center.x; - arc_path[idx++] = q_arc->p0y + center.y; + arc_path[idx++] = q_arc->p0x + center->x; + arc_path[idx++] = q_arc->p0y + center->y; #else arc_path[idx++] = VLC_OP_CUBIC; - arc_path[idx++] = q_arc->p2x + center.x; - arc_path[idx++] = q_arc->p2y + center.y; - arc_path[idx++] = q_arc->p1x + center.x; - arc_path[idx++] = q_arc->p1y + center.y; - arc_path[idx++] = q_arc->p0x + center.x; - arc_path[idx++] = q_arc->p0y + center.y; + arc_path[idx++] = q_arc->p2x + center->x; + arc_path[idx++] = q_arc->p2y + center->y; + arc_path[idx++] = q_arc->p1x + center->x; + arc_path[idx++] = q_arc->p1y + center->y; + arc_path[idx++] = q_arc->p0x + center->x; + arc_path[idx++] = q_arc->p0y + center->y; #endif } /* update index i n path array*/ @@ -615,7 +589,7 @@ static void add_split_arc_path(int32_t * arc_path, int * pidx, vg_arc * q_arc, l } static void add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, - int32_t start_angle, int32_t end_angle, lv_point_t center, bool cw) + int32_t start_angle, int32_t end_angle, const lv_point_t * center, bool cw) { /* set number of arcs to draw */ vg_arc q_arc; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h index 98ba8a3d0..0fbff3d92 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_arc.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ extern "C" { #include "../../../lv_conf_internal.h" #if LV_USE_GPU_NXP_VG_LITE -#include "lv_gpu_nxp_vglite.h" +#include "lv_vglite_utils.h" /********************* * DEFINES @@ -54,17 +54,21 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -/*** +/** * Draw arc shape with effects - * @param draw_ctx drawing context - * @param dsc the arc description structure (width, rounded ending, opacity) - * @param center the coordinates of the arc center - * @param radius the radius of external arc - * @param start_angle the starting angle in degrees - * @param end_angle the ending angle in degrees + * + * @param[in] center Arc center with relative coordinates + * @param[in] radius Radius of external arc + * @param[in] start_angle Starting angle in degrees + * @param[in] end_angle Ending angle in degrees + * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] dsc Arc description structure (width, rounded ending, opacity) + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center, - int32_t radius, int32_t start_angle, int32_t end_angle); +lv_res_t lv_gpu_nxp_vglite_draw_arc(const lv_point_t * center, int32_t radius, int32_t start_angle, int32_t end_angle, + const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c index b59b143b3..e1408b760 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,12 +34,19 @@ #include "lv_draw_vglite_blend.h" #if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_buf.h" /********************* * DEFINES *********************/ -/* Enable BLIT quality degradation workaround for RT595, recommended for screen's dimension > 352 pixels */ +/** Stride in px required by VG-Lite HW*/ +#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U + +/** + * Enable BLIT quality degradation workaround for RT595, + * recommended for screen's dimension > 352 pixels. + */ #define RT595_BLIT_WRKRND_ENABLED 1 /* Internal compound symbol */ @@ -51,12 +58,13 @@ #define VG_LITE_BLIT_SPLIT_ENABLED 0 #endif -/** - * BLIT split threshold - BLITs with width or height higher than this value will be done - * in multiple steps. Value must be 16-aligned. Don't change. - */ -#define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352 - +#if VG_LITE_BLIT_SPLIT_ENABLED + /** + * BLIT split threshold - BLITs with width or height higher than this value will be done + * in multiple steps. Value must be 16-aligned. Don't change. + */ + #define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352 +#endif /********************** * TYPEDEFS @@ -67,63 +75,87 @@ **********************/ /** - * BLock Image Transfer - single direct BLIT. + * Blit single image, with optional opacity. + * + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] opa Opacity * - * @param[in] blit Description of the transfer * @retval LV_RES_OK Transfer complete * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit); +static lv_res_t lv_vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa); + +/** + * Check source memory and stride alignment. + * + * @param[in] src_buf Source buffer + * @param[in] src_stride Stride of source buffer in pixels + * + * @retval LV_RES_OK Alignment OK + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride); + +/** + * Creates matrix that translates to origin of given destination area. + * + * @param[in] dest_area Area with relative coordinates of destination buffer + */ +static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area); + +/** + * Creates matrix that translates to origin of given destination area with transformation (scale or rotate). + * + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dsc Image descriptor + */ +static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc); #if VG_LITE_BLIT_SPLIT_ENABLED - /** - * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only. - * - * @param[in,out] area Area to be updated - * @param[in,out] buf Pointer to be updated - */ - static void _align_x(lv_area_t * area, lv_color_t ** buf); +/** + * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only. + * + * @param[in/out] area Area to be updated + * @param[in/out] buf Pointer to be updated + */ +static void align_x(lv_area_t * area, lv_color_t ** buf); - /** - * Move buffer pointer to the area start and update variables, Y-axis only. - * - * @param[in,out] area Area to be updated - * @param[in,out] buf Pointer to be updated - * @param[in] stridePx Buffer stride in pixels - */ - static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx); +/** + * Move buffer pointer to the area start and update variables, Y-axis only. + * + * @param[in/out] area Area to be updated + * @param[in/out] buf Pointer to be updated + * @param[in] stride Buffer stride in pixels + */ +static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride); - /** - * Software BLIT as a fall-back scenario. - * - * @param[in] blit BLIT configuration - */ - static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit); - - /** - * Verify BLIT structure - widths, stride, pointer alignment - * - * @param[in] blit BLIT configuration - * @retval LV_RES_OK - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) - */ - static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit); - - /** - * BLock Image Transfer - split BLIT. - * - * @param[in] blit BLIT configuration - * @retval LV_RES_OK Transfer complete - * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) - */ - static lv_res_t _lv_gpu_nxp_vglite_blit_split(lv_gpu_nxp_vglite_blit_info_t * blit); +/** + * Blit image split in tiles, with optional opacity. + * + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] opa Opacity + * + * @retval LV_RES_OK Transfer complete + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa); #endif /********************** * STATIC VARIABLES **********************/ +static vg_lite_matrix_t vgmatrix; + /********************** * MACROS **********************/ @@ -132,98 +164,57 @@ static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * b * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa) +lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa) { - uint32_t area_size = lv_area_get_size(fill_area); - lv_coord_t area_w = lv_area_get_width(fill_area); - lv_coord_t area_h = lv_area_get_height(fill_area); - - if(opa >= (lv_opa_t)LV_OPA_MAX) { - if(area_size < LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT); - } - else { - if(area_size < LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", area_size, LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT); - } - - vg_lite_buffer_t vgbuf; - vg_lite_rectangle_t rect; vg_lite_error_t err = VG_LITE_SUCCESS; lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/ vg_lite_color_t vgcol; /* vglite takes ABGR */ + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); - if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), - (const lv_color_t *)dest_buf, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); if(opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/ - rect.x = fill_area->x1; - rect.y = fill_area->y1; - rect.width = area_w; - rect.height = area_h; + vg_lite_rectangle_t rect = { + .x = dest_area->x1, + .y = dest_area->y1, + .width = lv_area_get_width(dest_area), + .height = lv_area_get_height(dest_area) + }; - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); - -#if LV_COLOR_DEPTH==16 - vgcol = col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) | - (uint32_t)col32.ch.red; -#endif - - err = vg_lite_clear(&vgbuf, &rect, vgcol); + err = vg_lite_clear(vgbuf, &rect, vgcol); VG_LITE_ERR_RETURN_INV(err, "Clear failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); } else { /*fill with transparency*/ vg_lite_path_t path; int32_t path_data[] = { /*VG rectangular path*/ - VLC_OP_MOVE, fill_area->x1, fill_area->y1, - VLC_OP_LINE, fill_area->x2 + 1, fill_area->y1, - VLC_OP_LINE, fill_area->x2 + 1, fill_area->y2 + 1, - VLC_OP_LINE, fill_area->x1, fill_area->y2 + 1, - VLC_OP_LINE, fill_area->x1, fill_area->y1, + VLC_OP_MOVE, dest_area->x1, dest_area->y1, + VLC_OP_LINE, dest_area->x2 + 1, dest_area->y1, + VLC_OP_LINE, dest_area->x2 + 1, dest_area->y2 + 1, + VLC_OP_LINE, dest_area->x1, dest_area->y2 + 1, + VLC_OP_LINE, dest_area->x1, dest_area->y1, VLC_OP_END }; err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(path_data), path_data, - (vg_lite_float_t) fill_area->x1, (vg_lite_float_t) fill_area->y1, - ((vg_lite_float_t) fill_area->x2) + 1.0f, ((vg_lite_float_t) fill_area->y2) + 1.0f); + (vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1, + ((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f); VG_LITE_ERR_RETURN_INV(err, "Init path failed."); - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - col32.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8); - col32.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8); - col32.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8); - } - col32.ch.alpha = opa; - -#if LV_COLOR_DEPTH==16 - vgcol = col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)col32.ch.alpha << 24) | ((uint32_t)col32.ch.blue << 16) | ((uint32_t)col32.ch.green << 8) | - (uint32_t)col32.ch.red; -#endif - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); - vg_lite_matrix_t matrix; vg_lite_identity(&matrix); /*Draw rectangle*/ - err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); VG_LITE_ERR_RETURN_INV(err, "Draw rectangle failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); err = vg_lite_clear_path(&path); VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); @@ -232,41 +223,64 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv return LV_RES_OK; } -lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +lv_res_t lv_gpu_nxp_vglite_blit(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa) { - uint32_t dest_size = lv_area_get_size(&blit->dst_area); + /* Set vgmatrix. */ + lv_vglite_set_translation_matrix(dest_area); - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT); - } - else { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT); - } + /* Set src_vgbuf structure. */ + lv_vglite_set_src_buf(src_buf, src_area, src_stride); #if VG_LITE_BLIT_SPLIT_ENABLED - return _lv_gpu_nxp_vglite_blit_split(blit); -#endif /* non RT595 */ + lv_color_t * orig_dest_buf = dest_buf; - /* Just pass down */ - return _lv_gpu_nxp_vglite_blit_single(blit); + lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, opa); + + /* Restore the original dest_vgbuf memory address. */ + lv_vglite_set_dest_buf_ptr(orig_dest_buf); + + return rv; +#else + LV_UNUSED(dest_buf); + LV_UNUSED(dest_stride); + + if(check_src_alignment(src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); + + return lv_vglite_blit_single(dest_area, src_area, opa); +#endif } -lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit) +lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc) { - uint32_t dest_size = lv_area_get_size(&blit->dst_area); + /* Set vgmatrix. */ + lv_vglite_set_transformation_matrix(dest_area, dsc); - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT); - } - else { - if(dest_size < LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT) - VG_LITE_RETURN_INV("Area size %d smaller than limit %d.", dest_size, LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT); - } + /* Set src_vgbuf structure. */ + lv_vglite_set_src_buf(src_buf, src_area, src_stride); - return _lv_gpu_nxp_vglite_blit_single(blit); +#if VG_LITE_BLIT_SPLIT_ENABLED + lv_color_t * orig_dest_buf = dest_buf; + + lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, dsc->opa); + + /* Restore the original dest_vgbuf memory address. */ + lv_vglite_set_dest_buf_ptr(orig_dest_buf); + + return rv; +#else + LV_UNUSED(dest_buf); + LV_UNUSED(dest_stride); + + if(check_src_alignment(src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); + + return lv_vglite_blit_single(dest_area, src_area, dsc->opa); +#endif } /********************** @@ -274,223 +288,196 @@ lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit) **********************/ #if VG_LITE_BLIT_SPLIT_ENABLED -static lv_res_t _lv_gpu_nxp_vglite_blit_split(lv_gpu_nxp_vglite_blit_info_t * blit) +static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa) { lv_res_t rv = LV_RES_INV; - if(_lv_gpu_nxp_vglite_check_blit(blit) != LV_RES_OK) { - PRINT_BLT("Blit check failed\n"); - return LV_RES_INV; - } + VG_LITE_LOG_TRACE("Blit " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x)", + src_area->x1, src_area->y1, src_area->x2, src_area->y2, + dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2, + lv_area_get_width(src_area), lv_area_get_height(src_area), + lv_area_get_width(dest_area), lv_area_get_height(dest_area), + (uintptr_t)src_buf, (uintptr_t)dest_buf); - PRINT_BLT("BLIT from: " - "Area: %03d,%03d - %03d,%03d " - "Addr: %d\n\n", - blit->src_area.x1, blit->src_area.y1, - blit->src_area.x2, blit->src_area.y2, - (uintptr_t) blit->src); - - PRINT_BLT("BLIT to: " - "Area: %03d,%03d - %03d,%03d " - "Addr: %d\n\n", - blit->dst_area.x1, blit->dst_area.y1, - blit->dst_area.x2, blit->dst_area.y2, - (uintptr_t) blit->src); - - /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */ - _align_x(&blit->src_area, (lv_color_t **)&blit->src); - _align_y(&blit->src_area, (lv_color_t **)&blit->src, blit->src_stride / sizeof(lv_color_t)); - _align_x(&blit->dst_area, (lv_color_t **)&blit->dst); - _align_y(&blit->dst_area, (lv_color_t **)&blit->dst, blit->dst_stride / sizeof(lv_color_t)); + /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */ + align_x(src_area, (lv_color_t **)&src_buf); + align_y(src_area, (lv_color_t **)&src_buf, src_stride); + align_x(dest_area, (lv_color_t **)&dest_buf); + align_y(dest_area, (lv_color_t **)&dest_buf, dest_stride); /* Stage 2: If we're in limit, do a single BLIT */ - if((blit->src_area.x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) && - (blit->src_area.y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) { - PRINT_BLT("Simple blit!\n"); - return _lv_gpu_nxp_vglite_blit_single(blit); + if((src_area->x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) && + (src_area->y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) { + if(check_src_alignment(src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); + + /* Set new dest_vgbuf and src_vgbuf memory addresses. */ + lv_vglite_set_dest_buf_ptr(dest_buf); + lv_vglite_set_src_buf_ptr(src_buf); + + /* Set vgmatrix. */ + lv_vglite_set_translation_matrix(dest_area); + + rv = lv_vglite_blit_single(dest_area, src_area, opa); + + VG_LITE_LOG_TRACE("Single " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x) %s", + src_area->x1, src_area->y1, src_area->x2, src_area->y2, + dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2, + lv_area_get_width(src_area), lv_area_get_height(src_area), + lv_area_get_width(dest_area), lv_area_get_height(dest_area), + (uintptr_t)src_buf, (uintptr_t)dest_buf, + rv == LV_RES_OK ? "OK!" : "FAILED!"); + + return rv; }; /* Stage 3: Split the BLIT into multiple tiles */ - PRINT_BLT("Split blit!\n"); - - PRINT_BLT("Blit " - "([%03d,%03d], [%03d,%03d]) -> " - "([%03d,%03d], [%03d,%03d]) | " - "([%03dx%03d] -> [%03dx%03d]) | " - "A:(%d -> %d)\n", - blit->src_area.x1, blit->src_area.y1, blit->src_area.x2, blit->src_area.y2, - blit->dst_area.x1, blit->dst_area.y1, blit->dst_area.x2, blit->dst_area.y2, - lv_area_get_width(&blit->src_area), lv_area_get_height(&blit->src_area), - lv_area_get_width(&blit->dst_area), lv_area_get_height(&blit->dst_area), - (uintptr_t) blit->src, (uintptr_t) blit->dst); + VG_LITE_LOG_TRACE("Split " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x)", + src_area->x1, src_area->y1, src_area->x2, src_area->y2, + dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2, + lv_area_get_width(src_area), lv_area_get_height(src_area), + lv_area_get_width(dest_area), lv_area_get_height(dest_area), + (uintptr_t)src_buf, (uintptr_t)dest_buf); - lv_coord_t totalWidth = lv_area_get_width(&blit->src_area); - lv_coord_t totalHeight = lv_area_get_height(&blit->src_area); - - lv_gpu_nxp_vglite_blit_info_t tileBlit; + lv_coord_t width = lv_area_get_width(src_area); + lv_coord_t height = lv_area_get_height(src_area); /* Number of tiles needed */ - int totalTilesX = (blit->src_area.x1 + totalWidth + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / - LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; - int totalTilesY = (blit->src_area.y1 + totalHeight + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / - LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + int total_tiles_x = (src_area->x1 + width + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + int total_tiles_y = (src_area->y1 + height + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; /* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as * the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be * different */ - int shiftSrcX = (blit->src_area.x1 > blit->dst_area.x1) ? (blit->src_area.x1 - blit->dst_area.x1) : 0; - int shiftDstX = (blit->src_area.x1 < blit->dst_area.x1) ? (blit->dst_area.x1 - blit->src_area.x1) : 0; + int shift_src_x = (src_area->x1 > dest_area->x1) ? (src_area->x1 - dest_area->x1) : 0; + int shift_dest_x = (src_area->x1 < dest_area->x1) ? (dest_area->x1 - src_area->x1) : 0; - PRINT_BLT("\n"); - PRINT_BLT("Align shift: src: %d, dst: %d\n", shiftSrcX, shiftDstX); + VG_LITE_LOG_TRACE("X shift: src: %d, dst: %d", shift_src_x, shift_dest_x); - tileBlit = *blit; + lv_color_t * tile_dest_buf; + lv_area_t tile_dest_area; + const lv_color_t * tile_src_buf; + lv_area_t tile_src_area; - for(int tileY = 0; tileY < totalTilesY; tileY++) { + for(int y = 0; y < total_tiles_y; y++) { - tileBlit.src_area.y1 = 0; /* no vertical alignment, always start from 0 */ - tileBlit.src_area.y2 = totalHeight - tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; - if(tileBlit.src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { - tileBlit.src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */ + tile_src_area.y1 = 0; /* no vertical alignment, always start from 0 */ + tile_src_area.y2 = height - y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tile_src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tile_src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */ } - tileBlit.src = blit->src + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->src_stride / sizeof( - lv_color_t); /* stride in px! */ + tile_src_buf = src_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * src_stride; - tileBlit.dst_area.y1 = tileBlit.src_area.y1; /* y has no alignment, always in sync with src */ - tileBlit.dst_area.y2 = tileBlit.src_area.y2; + tile_dest_area.y1 = tile_src_area.y1; /* y has no alignment, always in sync with src */ + tile_dest_area.y2 = tile_src_area.y2; - tileBlit.dst = blit->dst + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->dst_stride / sizeof( - lv_color_t); /* stride in px! */ + tile_dest_buf = dest_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * dest_stride; - for(int tileX = 0; tileX < totalTilesX; tileX++) { + for(int x = 0; x < total_tiles_x; x++) { - if(tileX == 0) { + if(x == 0) { /* 1st tile is special - there may be a gap between buffer start pointer * and area.x1 value, as the pointer has to be aligned. - * tileBlit.src pointer - keep init value from Y-loop. + * tile_src_buf pointer - keep init value from Y-loop. * Also, 1st tile start is not shifted! shift is applied from 2nd tile */ - tileBlit.src_area.x1 = blit->src_area.x1; - tileBlit.dst_area.x1 = blit->dst_area.x1; + tile_src_area.x1 = src_area->x1; + tile_dest_area.x1 = dest_area->x1; } else { /* subsequent tiles always starts from 0, but shifted*/ - tileBlit.src_area.x1 = 0 + shiftSrcX; - tileBlit.dst_area.x1 = 0 + shiftDstX; + tile_src_area.x1 = 0 + shift_src_x; + tile_dest_area.x1 = 0 + shift_dest_x; /* and advance start pointer + 1 tile size */ - tileBlit.src += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; - tileBlit.dst += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + tile_src_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + tile_dest_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; } /* Clip tile end coordinates */ - tileBlit.src_area.x2 = totalWidth + blit->src_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; - if(tileBlit.src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { - tileBlit.src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + tile_src_area.x2 = width + src_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tile_src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tile_src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; } - tileBlit.dst_area.x2 = totalWidth + blit->dst_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; - if(tileBlit.dst_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { - tileBlit.dst_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + tile_dest_area.x2 = width + dest_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tile_dest_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tile_dest_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; } - if(tileX < (totalTilesX - 1)) { - /* And adjust end coords if shifted, but not for last tile! */ - tileBlit.src_area.x2 += shiftSrcX; - tileBlit.dst_area.x2 += shiftDstX; + if(x < (total_tiles_x - 1)) { + /* And adjust end coords if shifted, but not for last tile! */ + tile_src_area.x2 += shift_src_x; + tile_dest_area.x2 += shift_dest_x; } - rv = _lv_gpu_nxp_vglite_blit_single(&tileBlit); + if(check_src_alignment(tile_src_buf, src_stride) != LV_RES_OK) + VG_LITE_RETURN_INV("Check src alignment failed."); -#if BLIT_DBG_AREAS - lv_vglite_dbg_draw_rectangle((lv_color_t *) tileBlit.dst, tileBlit.dst_width, tileBlit.dst_height, &tileBlit.dst_area, - LV_COLOR_RED); - lv_vglite_dbg_draw_rectangle((lv_color_t *) tileBlit.src, tileBlit.src_width, tileBlit.src_height, &tileBlit.src_area, - LV_COLOR_GREEN); -#endif + /* Set vgmatrix. */ + lv_vglite_set_translation_matrix(&tile_dest_area); - PRINT_BLT("Tile [%d, %d]: " - "([%d,%d], [%d,%d]) -> " - "([%d,%d], [%d,%d]) | " - "([%dx%d] -> [%dx%d]) | " - "A:(0x%8X -> 0x%8X) %s\n", - tileX, tileY, - tileBlit.src_area.x1, tileBlit.src_area.y1, tileBlit.src_area.x2, tileBlit.src_area.y2, - tileBlit.dst_area.x1, tileBlit.dst_area.y1, tileBlit.dst_area.x2, tileBlit.dst_area.y2, - lv_area_get_width(&tileBlit.src_area), lv_area_get_height(&tileBlit.src_area), - lv_area_get_width(&tileBlit.dst_area), lv_area_get_height(&tileBlit.dst_area), - (uintptr_t) tileBlit.src, (uintptr_t) tileBlit.dst, - rv == LV_RES_OK ? "OK!" : "!!! FAILED !!!"); + /* Set new dest_vgbuf and src_vgbuf memory addresses. */ + lv_vglite_set_dest_buf_ptr(tile_dest_buf); + lv_vglite_set_src_buf_ptr(tile_src_buf); - if(rv != LV_RES_OK) { /* if anything goes wrong... */ -#if LV_GPU_NXP_VG_LITE_LOG_ERRORS - LV_LOG_ERROR("Split blit failed. Trying SW blit instead."); -#endif - _sw_blit(&tileBlit); - rv = LV_RES_OK; /* Don't report error, as SW BLIT was performed */ + rv = lv_vglite_blit_single(&tile_dest_area, &tile_src_area, opa); + + VG_LITE_LOG_TRACE("Tile [%d, %d] " + "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " + "Size: ([%dx%d] -> [%dx%d]) | " + "Addr: (0x%x -> 0x%x) %s", + x, y, + tile_src_area.x1, tile_src_area.y1, tile_src_area.x2, tile_src_area.y2, + tile_dest_area.x1, tile_dest_area.y1, tile_dest_area.x2, tile_dest_area.y2, + lv_area_get_width(&tile_src_area), lv_area_get_height(&tile_src_area), + lv_area_get_width(&tile_dest_area), lv_area_get_height(&tile_dest_area), + (uintptr_t)tile_src_buf, (uintptr_t)tile_dest_buf, + rv == LV_RES_OK ? "OK!" : "FAILED!"); + + if(rv != LV_RES_OK) { + return rv; } - } - PRINT_BLT(" \n"); } - return rv; /* should never fail */ + return rv; } #endif /* VG_LITE_BLIT_SPLIT_ENABLED */ -static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit) +static lv_res_t lv_vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa) { - vg_lite_buffer_t src_vgbuf, dst_vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; - uint32_t rect[4]; - vg_lite_float_t scale = 1.0; + vg_lite_buffer_t * dst_vgbuf = lv_vglite_get_dest_buf(); + vg_lite_buffer_t * src_vgbuf = lv_vglite_get_src_buf(); - if(blit == NULL) { - /*Wrong parameter*/ - return LV_RES_INV; - } - - if(blit->opa < (lv_opa_t) LV_OPA_MIN) { - return LV_RES_OK; /*Nothing to BLIT*/ - } - - /*Wrap src/dst buffer into VG-Lite buffer*/ - if(lv_vglite_init_buf(&src_vgbuf, (uint32_t)blit->src_width, (uint32_t)blit->src_height, (uint32_t)blit->src_stride, - blit->src, true) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - - if(lv_vglite_init_buf(&dst_vgbuf, (uint32_t)blit->dst_width, (uint32_t)blit->dst_height, (uint32_t)blit->dst_stride, - blit->dst, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - - rect[0] = (uint32_t)blit->src_area.x1; /* start x */ - rect[1] = (uint32_t)blit->src_area.y1; /* start y */ - rect[2] = (uint32_t)blit->src_area.x2 - (uint32_t)blit->src_area.x1 + 1U; /* width */ - rect[3] = (uint32_t)blit->src_area.y2 - (uint32_t)blit->src_area.y1 + 1U; /* height */ - - vg_lite_matrix_t matrix; - vg_lite_identity(&matrix); - vg_lite_translate((vg_lite_float_t)blit->dst_area.x1, (vg_lite_float_t)blit->dst_area.y1, &matrix); - - if((blit->angle != 0) || (blit->zoom != LV_IMG_ZOOM_NONE)) { - vg_lite_translate(blit->pivot.x, blit->pivot.y, &matrix); - vg_lite_rotate(blit->angle / 10.0f, &matrix); /* angle is 1/10 degree */ - scale = 1.0f * blit->zoom / LV_IMG_ZOOM_NONE; - vg_lite_scale(scale, scale, &matrix); - vg_lite_translate(0.0f - blit->pivot.x, 0.0f - blit->pivot.y, &matrix); - } - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); + uint32_t rect[] = { + (uint32_t)src_area->x1, /* start x */ + (uint32_t)src_area->y1, /* start y */ + (uint32_t)lv_area_get_width(src_area), /* width */ + (uint32_t)lv_area_get_height(src_area) /* height */ + }; uint32_t color; vg_lite_blend_t blend; - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { + if(opa >= (lv_opa_t)LV_OPA_MAX) { color = 0xFFFFFFFFU; blend = VG_LITE_BLEND_SRC_OVER; - src_vgbuf.transparency_mode = VG_LITE_IMAGE_TRANSPARENT; + src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; } else { - uint32_t opa = (uint32_t)blit->opa; if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { color = (opa << 24) | 0x00FFFFFFU; } @@ -498,94 +485,83 @@ static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * b color = (opa << 24) | (opa << 16) | (opa << 8) | opa; } blend = VG_LITE_BLEND_SRC_OVER; - src_vgbuf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; - src_vgbuf.transparency_mode = VG_LITE_IMAGE_TRANSPARENT; + src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; + src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; } - err = vg_lite_blit_rect(&dst_vgbuf, &src_vgbuf, rect, &matrix, blend, color, VG_LITE_FILTER_POINT); - VG_LITE_ERR_RETURN_INV(err, "Blit rectangle failed."); + bool scissoring = lv_area_get_width(dest_area) < lv_area_get_width(src_area) || + lv_area_get_height(dest_area) < lv_area_get_height(src_area); + if(scissoring) { + vg_lite_enable_scissor(); + vg_lite_set_scissor((int32_t)dest_area->x1, (int32_t)dest_area->y1, + (int32_t)lv_area_get_width(dest_area), + (int32_t)lv_area_get_height(dest_area)); + } - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + err = vg_lite_blit_rect(dst_vgbuf, src_vgbuf, rect, &vgmatrix, blend, color, VG_LITE_FILTER_POINT); + if(err != VG_LITE_SUCCESS) { + if(scissoring) + vg_lite_disable_scissor(); + VG_LITE_RETURN_INV("Blit rectangle failed."); + } + + if(lv_vglite_run() != LV_RES_OK) { + if(scissoring) + vg_lite_disable_scissor(); + VG_LITE_RETURN_INV("Run failed."); + } + + if(scissoring) + vg_lite_disable_scissor(); return LV_RES_OK; } +static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride) +{ + /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */ + + /* Test for pointer alignment */ + if((((uintptr_t)src_buf) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U) + VG_LITE_RETURN_INV("Src buffer ptr (0x%x) not aligned to 0x%x bytes.", + (size_t)src_buf, LV_ATTRIBUTE_MEM_ALIGN_SIZE); + + /* Test for stride alignment */ + if((src_stride % (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0x0U) + VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.", + src_stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); + return LV_RES_OK; +} + +static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area) +{ + vg_lite_identity(&vgmatrix); + vg_lite_translate((vg_lite_float_t)dest_area->x1, (vg_lite_float_t)dest_area->y1, &vgmatrix); +} + +static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc) +{ + lv_vglite_set_translation_matrix(dest_area); + + bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE); + bool has_rotation = (dsc->angle != 0); + + if(has_scale || has_rotation) { + vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &vgmatrix); + if(has_rotation) + vg_lite_rotate(dsc->angle / 10.0f, &vgmatrix); /* angle is 1/10 degree */ + if(has_scale) { + vg_lite_float_t scale = 1.0f * dsc->zoom / LV_IMG_ZOOM_NONE; + vg_lite_scale(scale, scale, &vgmatrix); + } + vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &vgmatrix); + } +} + #if VG_LITE_BLIT_SPLIT_ENABLED - -static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +static void align_x(lv_area_t * area, lv_color_t ** buf) { - int x, y; - - lv_coord_t w = lv_area_get_width(&blit->src_area); - lv_coord_t h = lv_area_get_height(&blit->src_area); - - int32_t srcStridePx = blit->src_stride / (int32_t)sizeof(lv_color_t); - int32_t dstStridePx = blit->dst_stride / (int32_t)sizeof(lv_color_t); - - lv_color_t * src = (lv_color_t *)blit->src + blit->src_area.y1 * srcStridePx + blit->src_area.x1; - lv_color_t * dst = (lv_color_t *)blit->dst + blit->dst_area.y1 * dstStridePx + blit->dst_area.x1; - - if(blit->opa >= (lv_opa_t)LV_OPA_MAX) { - /* simple copy */ - for(y = 0; y < h; y++) { - lv_memcpy(dst, src, (uint32_t)w * sizeof(lv_color_t)); - src += srcStridePx; - dst += dstStridePx; - } - } - else if(blit->opa >= LV_OPA_MIN) { - /* alpha blending */ - for(y = 0; y < h; y++) { - for(x = 0; x < w; x++) { - dst[x] = lv_color_mix(src[x], dst[x], blit->opa); - } - src += srcStridePx; - dst += dstStridePx; - } - } -} - -static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit) -{ - - /* Test for minimal width */ - if(lv_area_get_width(&blit->src_area) < (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) - VG_LITE_RETURN_INV("Src area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->src_area), - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - /* Test for minimal width */ - if(lv_area_get_width(&blit->dst_area) < (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) - VG_LITE_RETURN_INV("Dest area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->dst_area), - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - /* Test for pointer alignment */ - if((((uintptr_t) blit->src) % LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0) - VG_LITE_RETURN_INV("Src buffer ptr (0x%X) not aligned to %d.", (size_t) blit->src, LV_ATTRIBUTE_MEM_ALIGN_SIZE); - - /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */ - - /* Test for stride alignment */ - if((blit->src_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0) - VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.", blit->src_stride, - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - /* Test for stride alignment */ - if((blit->dst_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0) - VG_LITE_RETURN_INV("Dest buffer stride (%d px) not aligned to %d px.", blit->dst_stride, - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - - if((lv_area_get_width(&blit->src_area) != lv_area_get_width(&blit->dst_area)) || - (lv_area_get_height(&blit->src_area) != lv_area_get_height(&blit->dst_area))) - VG_LITE_RETURN_INV("Src and dest buffer areas are not equal."); - - return LV_RES_OK; -} - -static void _align_x(lv_area_t * area, lv_color_t ** buf) -{ - - int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE * 8 / LV_COLOR_DEPTH)); + int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE / sizeof(lv_color_t))); VG_LITE_COND_STOP(alignedAreaStartPx < 0, "Negative X alignment."); area->x1 -= alignedAreaStartPx; @@ -593,17 +569,17 @@ static void _align_x(lv_area_t * area, lv_color_t ** buf) *buf += alignedAreaStartPx; } -static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx) +static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride) { int LineToAlignMem; int alignedAreaStartPy; /* find how many lines of pixels will respect memory alignment requirement */ - if(stridePx % (uint32_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE == 0U) { + if((stride % (lv_coord_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) == 0x0U) { alignedAreaStartPy = area->y1; } else { - LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); - VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX), + LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)); + VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)), "Complex case: need gcd function."); alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem); VG_LITE_COND_STOP(alignedAreaStartPy < 0, "Negative Y alignment."); @@ -611,7 +587,7 @@ static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx) area->y1 -= alignedAreaStartPy; area->y2 -= alignedAreaStartPy; - *buf += (uint32_t)alignedAreaStartPy * stridePx; + *buf += (uint32_t)(alignedAreaStartPy * stride); } #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h index bc448c65a..025d2b5cc 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_blend.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2020-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,64 +41,16 @@ extern "C" { #include "../../../lv_conf_internal.h" #if LV_USE_GPU_NXP_VG_LITE -#include "lv_gpu_nxp_vglite.h" +#include "lv_vglite_utils.h" /********************* * DEFINES *********************/ -#ifndef LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by VG-Lite with 100% opacity*/ -#define LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT -/** Minimum area (in pixels) to be filled by VG-Lite with transparency*/ -#define LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with 100% opacity to be handled by VG-Lite*/ -#define LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT -/** Minimum invalidated area (in pixels) to be synchronized by VG-Lite during buffer sync */ -#define LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT 5000 -#endif - -#ifndef LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT -/** Minimum area (in pixels) for image copy with transparency to be handled by VG-Lite*/ -#define LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT 5000 -#endif - /********************** * TYPEDEFS **********************/ -/** - * BLock Image Transfer descriptor structure - */ -typedef struct { - - const lv_color_t * src; /**< Source buffer pointer (must be aligned on 32 bytes)*/ - lv_area_t src_area; /**< Area to be copied from source*/ - lv_coord_t src_width; /**< Source buffer width*/ - lv_coord_t src_height; /**< Source buffer height*/ - int32_t src_stride; /**< Source buffer stride in bytes (must be aligned on 16 px)*/ - - const lv_color_t * dst; /**< Destination buffer pointer (must be aligned on 32 bytes)*/ - lv_area_t dst_area; /**< Target area in destination buffer (must be the same as src_area)*/ - lv_coord_t dst_width; /**< Destination buffer width*/ - lv_coord_t dst_height; /**< Destination buffer height*/ - int32_t dst_stride; /**< Destination buffer stride in bytes (must be aligned on 16 px)*/ - - lv_opa_t opa; /**< Opacity - alpha mix (0 = source not copied, 255 = 100% opaque)*/ - uint32_t angle; /**< Rotation angle (1/10 of degree)*/ - uint32_t zoom; /**< 256 = no zoom (1:1 scale ratio)*/ - lv_point_t pivot; /**< The coordinates of rotation pivot in source image buffer*/ -} lv_gpu_nxp_vglite_blit_info_t; - /********************** * GLOBAL PROTOTYPES **********************/ @@ -106,35 +58,52 @@ typedef struct { /** * Fill area, with optional opacity. * - * @param[in/out] dest_buf Destination buffer pointer (must be aligned on 32 bytes) - * @param[in] dest_width Destination buffer width in pixels (must be aligned on 16 px) - * @param[in] dest_height Destination buffer height in pixels - * @param[in] fill_area Area to be filled - * @param[in] color Fill color + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] color Color * @param[in] opa Opacity (255 = full, 128 = 50% background/50% color, 0 = no fill) + * * @retval LV_RES_OK Fill completed * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa); +lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa); /** - * BLock Image Transfer. + * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with effects. + * By default, image is copied directly, with optional opacity. + * + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] opa Opacity * - * @param[in] blit Description of the transfer * @retval LV_RES_OK Transfer complete * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit); +lv_res_t lv_gpu_nxp_vglite_blit(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + lv_opa_t opa); /** - * BLock Image Transfer with transformation. + * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation. + * By default, image is copied directly, with optional opacity. + * + * @param[in/out] dest_buf Destination buffer + * @param[in] dest_area Area with relative coordinates of destination buffer + * @param[in] dest_stride Stride of destination buffer in pixels + * @param[in] src_buf Source buffer + * @param[in] src_area Source area with relative coordinates of source buffer + * @param[in] src_stride Stride of source buffer in pixels + * @param[in] dsc Image descriptor * - * @param[in] blit Description of the transfer * @retval LV_RES_OK Transfer complete * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_gpu_nxp_vglite_blit_info_t * blit); +lv_res_t lv_gpu_nxp_vglite_blit_transform(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride, + const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride, + const lv_draw_img_dsc_t * dsc); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c new file mode 100644 index 000000000..f6e1c4352 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.c @@ -0,0 +1,138 @@ +/** + * @file lv_draw_vglite_line.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * 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 (including the next paragraph) + * 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. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_vglite_line.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_buf.h" +#include + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_res_t lv_gpu_nxp_vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2, + const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc) +{ + vg_lite_error_t err = VG_LITE_SUCCESS; + vg_lite_path_t path; + vg_lite_color_t vgcol; /* vglite takes ABGR */ + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); + vg_lite_cap_style_t cap_style = (dsc->round_start || dsc->round_end) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT; + vg_lite_join_style_t join_style = (dsc->round_start || dsc->round_end) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER; + + bool is_dashed = (dsc->dash_width && dsc->dash_gap); + + vg_lite_float_t stroke_dash_pattern[2] = {0, 0}; + uint32_t stroke_dash_count = 0; + vg_lite_float_t stroke_dash_phase = 0; + if(is_dashed) { + stroke_dash_pattern[0] = (vg_lite_float_t)dsc->dash_width; + stroke_dash_pattern[1] = (vg_lite_float_t)dsc->dash_gap; + stroke_dash_count = sizeof(stroke_dash_pattern) / sizeof(vg_lite_float_t); + stroke_dash_phase = (vg_lite_float_t)dsc->dash_width / 2; + } + + /* Choose vglite blend mode based on given lvgl blend mode */ + vg_lite_blend_t vglite_blend_mode = lv_vglite_get_blend_mode(dsc->blend_mode); + + /*** Init path ***/ + lv_coord_t width = dsc->width; + + int32_t line_path[] = { /*VG line path*/ + VLC_OP_MOVE, point1->x, point1->y, + VLC_OP_LINE, point2->x, point2->y, + VLC_OP_END + }; + + err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(line_path), line_path, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); + VG_LITE_ERR_RETURN_INV(err, "Init path failed."); + + vg_lite_matrix_t matrix; + vg_lite_identity(&matrix); + + lv_color32_t col32 = { .full = lv_color_to32(dsc->color) }; /*Convert color to RGBA8888*/ + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, dsc->opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); + + /*** Draw line ***/ + err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH); + VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed."); + + err = vg_lite_set_stroke(&path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count, + stroke_dash_phase, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Set stroke failed."); + + err = vg_lite_update_stroke(&path); + VG_LITE_ERR_RETURN_INV(err, "Update stroke failed."); + + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Draw line failed."); + + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); + + err = vg_lite_clear_path(&path); + VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); + + return LV_RES_OK; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h new file mode 100644 index 000000000..cbd4b95ec --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_line.h @@ -0,0 +1,83 @@ +/** + * @file lv_draw_vglite_line.h + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * 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 (including the next paragraph) + * 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 LV_DRAW_VGLITE_LINE_H +#define LV_DRAW_VGLITE_LINE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_utils.h" +#include "../../lv_draw_line.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Draw line shape with effects + * + * @param[in] point1 Starting point with relative coordinates + * @param[in] point2 Ending point with relative coordinates + * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] dsc Line description structure (width, rounded ending, opacity, ...) + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_gpu_nxp_vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2, + const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_DRAW_VGLITE_RECT_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c index bc1d55c85..39ccaa481 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.c @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,10 +34,28 @@ #include "lv_draw_vglite_rect.h" #if LV_USE_GPU_NXP_VG_LITE +#include "lv_vglite_buf.h" +#include /********************* * DEFINES *********************/ +/********************* + * DEFINES + *********************/ + +/* Path data sizes for different elements */ +#define CUBIC_PATH_DATA_SIZE 7 /* 1 opcode, 6 arguments */ +#define LINE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */ +#define MOVE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */ +#define END_PATH_DATA_SIZE 1 /* 1 opcode, 0 arguments */ +/* Maximum possible rectangle path size + * is in the rounded rectangle case: + * - 1 move for the path start + * - 4 cubics for the corners + * - 4 lines for the sides + * - 1 end for the path end */ +#define RECT_PATH_DATA_MAX_SIZE 1 * MOVE_PATH_DATA_SIZE + 4 * CUBIC_PATH_DATA_SIZE + 4 * LINE_PATH_DATA_SIZE + 1 * END_PATH_DATA_SIZE /********************** * TYPEDEFS @@ -47,6 +65,18 @@ * STATIC PROTOTYPES **********************/ +/** + * Generates path data for rectangle drawing. + * + * @param[in/out] path The path data to initialize + * @param[in/out] path_size The resulting size of the created path data + * @param[in] dsc The style descriptor for the rectangle to be drawn + * @param[in] coords The coordinates of the rectangle to be drawn + */ +static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size, + lv_coord_t radius, + const lv_area_t * coords); + /********************** * STATIC VARIABLES **********************/ @@ -59,94 +89,37 @@ * GLOBAL FUNCTIONS **********************/ -lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords) +lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc) { - vg_lite_buffer_t vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; - lv_coord_t dest_width = lv_area_get_width(draw_ctx->buf_area); - lv_coord_t dest_height = lv_area_get_height(draw_ctx->buf_area); - vg_lite_path_t path; - vg_lite_color_t vgcol; /* vglite takes ABGR */ - vg_lite_matrix_t matrix; lv_coord_t width = lv_area_get_width(coords); lv_coord_t height = lv_area_get_height(coords); - vg_lite_linear_gradient_t gradient; - vg_lite_matrix_t * grad_matrix; + vg_lite_color_t vgcol; + lv_coord_t radius = dsc->radius; + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); if(dsc->radius < 0) return LV_RES_INV; - /* Make areas relative to draw buffer */ - lv_area_t rel_coords; - lv_area_copy(&rel_coords, coords); - lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - lv_area_t rel_clip; - lv_area_copy(&rel_clip, draw_ctx->clip_area); - lv_area_move(&rel_clip, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - - /*** Init destination buffer ***/ - if(lv_vglite_init_buf(&vgbuf, (uint32_t)dest_width, (uint32_t)dest_height, (uint32_t)dest_width * sizeof(lv_color_t), - (const lv_color_t *)draw_ctx->buf, false) != LV_RES_OK) - VG_LITE_RETURN_INV("Init buffer failed."); - /*** Init path ***/ - int32_t rad = dsc->radius; - if(dsc->radius == LV_RADIUS_CIRCLE) { - rad = (width > height) ? height / 2 : width / 2; - } - - if((dsc->radius == LV_RADIUS_CIRCLE) && (width == height)) { - float tang = ((float)rad * BEZIER_OPTIM_CIRCLE); - int32_t cpoff = (int32_t)tang; - int32_t circle_path[] = { /*VG circle path*/ - VLC_OP_MOVE, rel_coords.x1 + rad, rel_coords.y1, - VLC_OP_CUBIC_REL, cpoff, 0, rad, rad - cpoff, rad, rad, /* top-right */ - VLC_OP_CUBIC_REL, 0, cpoff, cpoff - rad, rad, 0 - rad, rad, /* bottom-right */ - VLC_OP_CUBIC_REL, 0 - cpoff, 0, 0 - rad, cpoff - rad, 0 - rad, 0 - rad, /* bottom-left */ - VLC_OP_CUBIC_REL, 0, 0 - cpoff, rad - cpoff, 0 - rad, rad, 0 - rad, /* top-left */ - VLC_OP_END - }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(circle_path), circle_path, - (vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1, - ((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f); - } - else if(dsc->radius > 0) { - float tang = ((float)rad * BEZIER_OPTIM_CIRCLE); - int32_t cpoff = (int32_t)tang; - int32_t rounded_path[] = { /*VG rounded rectangular path*/ - VLC_OP_MOVE, rel_coords.x1 + rad, rel_coords.y1, - VLC_OP_LINE, rel_coords.x2 - rad + 1, rel_coords.y1, /* top */ - VLC_OP_CUBIC_REL, cpoff, 0, rad, rad - cpoff, rad, rad, /* top-right */ - VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y2 - rad + 1, /* right */ - VLC_OP_CUBIC_REL, 0, cpoff, cpoff - rad, rad, 0 - rad, rad, /* bottom-right */ - VLC_OP_LINE, rel_coords.x1 + rad, rel_coords.y2 + 1, /* bottom */ - VLC_OP_CUBIC_REL, 0 - cpoff, 0, 0 - rad, cpoff - rad, 0 - rad, 0 - rad, /* bottom-left */ - VLC_OP_LINE, rel_coords.x1, rel_coords.y1 + rad, /* left */ - VLC_OP_CUBIC_REL, 0, 0 - cpoff, rad - cpoff, 0 - rad, rad, 0 - rad, /* top-left */ - VLC_OP_END - }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(rounded_path), rounded_path, - (vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1, - ((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f); - } - else { - int32_t rect_path[] = { /*VG rectangular path*/ - VLC_OP_MOVE, rel_coords.x1, rel_coords.y1, - VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y1, - VLC_OP_LINE, rel_coords.x2 + 1, rel_coords.y2 + 1, - VLC_OP_LINE, rel_coords.x1, rel_coords.y2 + 1, - VLC_OP_LINE, rel_coords.x1, rel_coords.y1, - VLC_OP_END - }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(rect_path), rect_path, - (vg_lite_float_t) rel_clip.x1, (vg_lite_float_t) rel_clip.y1, - ((vg_lite_float_t) rel_clip.x2) + 1.0f, ((vg_lite_float_t) rel_clip.y2) + 1.0f); - } + int32_t path_data[RECT_PATH_DATA_MAX_SIZE]; + uint32_t path_data_size; + lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords); + vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW; + vg_lite_path_t path; + err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); VG_LITE_ERR_RETURN_INV(err, "Init path failed."); + + vg_lite_matrix_t matrix; vg_lite_identity(&matrix); + vg_lite_matrix_t * grad_matrix; + vg_lite_linear_gradient_t gradient; + /*** Init Color/Gradient ***/ if(dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE) { uint32_t colors[2]; @@ -154,18 +127,14 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ lv_color32_t col32[2]; /* Gradient setup */ - uint8_t cnt = MAX(dsc->bg_grad.stops_count, 2); + uint8_t cnt = LV_MAX(dsc->bg_grad.stops_count, 2); for(uint8_t i = 0; i < cnt; i++) { col32[i].full = lv_color_to32(dsc->bg_grad.stops[i].color); /*Convert color to RGBA8888*/ stops[i] = dsc->bg_grad.stops[i].frac; -#if LV_COLOR_DEPTH==16 - colors[i] = ((uint32_t)col32[i].ch.alpha << 24) | ((uint32_t)col32[i].ch.blue << 16) | - ((uint32_t)col32[i].ch.green << 8) | (uint32_t)col32[i].ch.red; -#else /*LV_COLOR_DEPTH==32*/ - /* watchout: red and blue color components are inverted versus vg_lite_color_t order */ - colors[i] = ((uint32_t)col32[i].ch.alpha << 24) | ((uint32_t)col32[i].ch.red << 16) | - ((uint32_t)col32[i].ch.green << 8) | (uint32_t)col32[i].ch.blue; -#endif + + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_ABGR8888 : VG_LITE_ARGB8888; + if(lv_vglite_premult_and_swizzle(&colors[i], col32[i], dsc->bg_opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); } lv_memset_00(&gradient, sizeof(vg_lite_linear_gradient_t)); @@ -181,7 +150,7 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ grad_matrix = vg_lite_get_grad_matrix(&gradient); vg_lite_identity(grad_matrix); - vg_lite_translate((float)rel_coords.x1, (float)rel_coords.y1, grad_matrix); + vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix); if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) { vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix); @@ -192,39 +161,22 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ } } - lv_opa_t bg_opa = dsc->bg_opa; lv_color32_t bg_col32 = {.full = lv_color_to32(dsc->bg_color)}; /*Convert color to RGBA8888*/ - if(bg_opa <= (lv_opa_t)LV_OPA_MAX) { - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - bg_col32.ch.red = (uint8_t)(((uint16_t)bg_col32.ch.red * bg_opa) >> 8); - bg_col32.ch.green = (uint8_t)(((uint16_t)bg_col32.ch.green * bg_opa) >> 8); - bg_col32.ch.blue = (uint8_t)(((uint16_t)bg_col32.ch.blue * bg_opa) >> 8); - } - bg_col32.ch.alpha = bg_opa; - } - -#if LV_COLOR_DEPTH==16 - vgcol = bg_col32.full; -#else /*LV_COLOR_DEPTH==32*/ - vgcol = ((uint32_t)bg_col32.ch.alpha << 24) | ((uint32_t)bg_col32.ch.blue << 16) | - ((uint32_t)bg_col32.ch.green << 8) | (uint32_t)bg_col32.ch.red; -#endif - - /*Clean & invalidate cache*/ - lv_vglite_invalidate_cache(); + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, bg_col32, dsc->bg_opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); /*** Draw rectangle ***/ if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) { - err = vg_lite_draw(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); } else { - err = vg_lite_draw_gradient(&vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER); + err = vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER); } VG_LITE_ERR_RETURN_INV(err, "Draw gradient failed."); - err = vg_lite_finish(); - VG_LITE_ERR_RETURN_INV(err, "Finish failed."); + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); err = vg_lite_clear_path(&path); VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); @@ -237,6 +189,261 @@ lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_ return LV_RES_OK; } +lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc, bool border) +{ + vg_lite_error_t err = VG_LITE_SUCCESS; + vg_lite_color_t vgcol; /* vglite takes ABGR */ + lv_coord_t radius = dsc->radius; + vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf(); + + if(radius < 0) + return LV_RES_INV; + + if(border) { + /* Draw border - only has radius if object has radius*/ + lv_coord_t border_half = (lv_coord_t)floor(dsc->border_width / 2.0f); + if(radius > border_half) + radius = radius - border_half; + } + else { + /* Draw outline - always has radius, leave the same radius in the circle case */ + lv_coord_t outline_half = (lv_coord_t)ceil(dsc->outline_width / 2.0f); + if(radius < (lv_coord_t)LV_RADIUS_CIRCLE - outline_half) + radius = radius + outline_half; + } + + vg_lite_cap_style_t cap_style = (radius) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT; + vg_lite_join_style_t join_style = (radius) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER; + + /* Choose vglite blend mode based on given lvgl blend mode */ + vg_lite_blend_t vglite_blend_mode = lv_vglite_get_blend_mode(dsc->blend_mode); + + /*** Init path ***/ + int32_t path_data[RECT_PATH_DATA_MAX_SIZE]; + uint32_t path_data_size; + lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords); + vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW; + + vg_lite_path_t path; + err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); + VG_LITE_ERR_RETURN_INV(err, "Init path failed."); + + vg_lite_matrix_t matrix; + vg_lite_identity(&matrix); + + lv_opa_t opa; + lv_color32_t col32; + lv_coord_t line_width; + + if(border) { + opa = dsc->border_opa; + col32.full = lv_color_to32(dsc->border_color); /*Convert color to RGBA8888*/ + line_width = dsc->border_width; + } + else { + opa = dsc->outline_opa; + col32.full = lv_color_to32(dsc->outline_color); /*Convert color to RGBA8888*/ + line_width = dsc->outline_width; + } + + vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888; + if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK) + VG_LITE_RETURN_INV("Premultiplication and swizzle failed."); + + /*** Draw border ***/ + err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH); + VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed."); + + err = vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Set stroke failed."); + + err = vg_lite_update_stroke(&path); + VG_LITE_ERR_RETURN_INV(err, "Update stroke failed."); + + err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol); + VG_LITE_ERR_RETURN_INV(err, "Draw border failed."); + + if(lv_vglite_run() != LV_RES_OK) + VG_LITE_RETURN_INV("Run failed."); + + err = vg_lite_clear_path(&path); + VG_LITE_ERR_RETURN_INV(err, "Clear path failed."); + + return LV_RES_OK; + +} + +static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size, + lv_coord_t radius, + const lv_area_t * coords) +{ + lv_coord_t rect_width = lv_area_get_width(coords); + lv_coord_t rect_height = lv_area_get_height(coords); + + /* Get the final radius. Can't be larger than the half of the shortest side */ + int32_t shortest_side = LV_MIN(rect_width, rect_height); + int32_t final_radius = LV_MIN(radius, shortest_side / 2); + + /* Path data element index */ + uint8_t pidx = 0; + + if((radius == (lv_coord_t)LV_RADIUS_CIRCLE) && (rect_width == rect_height)) { + + /* Get the control point offset for rounded cases */ + int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE); + + /* Circle case */ + /* Starting point */ + path_data[pidx++] = VLC_OP_MOVE; + path_data[pidx++] = coords->x1 + final_radius; + path_data[pidx++] = coords->y1; + + /* Top-right arc */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius; + + /* Bottom-right arc*/ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = cpoff; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + + /* Bottom-left arc */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Top-left arc*/ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Ending point */ + path_data[pidx++] = VLC_OP_END; + } + else if(radius > 0) { + /* Get the control point offset for rounded cases */ + int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE); + + /* Rounded rectangle case */ + /* Starting point */ + path_data[pidx++] = VLC_OP_MOVE; + path_data[pidx++] = coords->x1 + final_radius; + path_data[pidx++] = coords->y1; + + /* Top side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 - final_radius + 1; // Extended for VGLite + path_data[pidx++] = coords->y1; + + /* Top-right corner */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = final_radius; + path_data[pidx++] = final_radius; + + /* Right side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 + 1; // Extended for VGLite + path_data[pidx++] = coords->y2 - final_radius + 1; // Extended for VGLite + + /* Bottom-right corner*/ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = cpoff; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + + /* Bottom side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1 + final_radius; + path_data[pidx++] = coords->y2 + 1; // Extended for VGLite + + /* Bottom-left corner */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = cpoff - final_radius; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Left side*/ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y1 + final_radius; + + /* Top-left corner */ + path_data[pidx++] = VLC_OP_CUBIC_REL; + path_data[pidx++] = 0; + path_data[pidx++] = 0 - cpoff; + path_data[pidx++] = final_radius - cpoff; + path_data[pidx++] = 0 - final_radius; + path_data[pidx++] = final_radius; + path_data[pidx++] = 0 - final_radius; + + /* Ending point */ + path_data[pidx++] = VLC_OP_END; + } + else { + /* Non-rounded rectangle case */ + /* Starting point */ + path_data[pidx++] = VLC_OP_MOVE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y1; + + /* Top side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 + 1; // Extended for VGLite + path_data[pidx++] = coords->y1; + + /* Right side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x2 + 1; // Extended for VGLite + path_data[pidx++] = coords->y2 + 1; // Extended for VGLite + + /* Bottom side */ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y2 + 1; // Extended for VGLite + + /* Left side*/ + path_data[pidx++] = VLC_OP_LINE; + path_data[pidx++] = coords->x1; + path_data[pidx++] = coords->y1; + + /* Ending point */ + path_data[pidx++] = VLC_OP_END; + } + + /* Resulting path size */ + *path_data_size = pidx * sizeof(int32_t); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h index d708e7b42..795822746 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_draw_vglite_rect.h @@ -6,7 +6,7 @@ /** * MIT License * - * Copyright 2021, 2022 NXP + * Copyright 2021-2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ extern "C" { #include "../../../lv_conf_internal.h" #if LV_USE_GPU_NXP_VG_LITE -#include "lv_gpu_nxp_vglite.h" +#include "lv_vglite_utils.h" #include "../../lv_draw_rect.h" /********************* @@ -56,13 +56,33 @@ extern "C" { **********************/ /** - * Draw rectangle shape with effects (rounded corners, gradient) + * Draw rectangle background with effects (rounded corners, gradient) + * + * @param[in] coords Coordinates of the rectangle background (relative to dest buff) + * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] dsc Description of the rectangle background + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) * - * @param draw_ctx drawing context - * @param dsc description of the rectangle - * @param coords the area where rectangle is clipped */ -lv_res_t lv_gpu_nxp_vglite_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords); +lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc); + +/** + * Draw rectangle border/outline shape with effects (rounded corners, opacity) + * + * @param[in] coords Coordinates of the rectangle border/outline (relative to dest buff) + * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] dsc Description of the rectangle border/outline + * @param[in] border True for border, False for outline + * + * @retval LV_RES_OK Draw completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + * + */ +lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_rect_dsc_t * dsc, bool border); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c deleted file mode 100644 index f65ec1d48..000000000 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.c +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @file lv_gpu_nxp_vglite.c - * - */ - -/** - * MIT License - * - * Copyright 2020-2022 NXP - * - * 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 (including the next paragraph) - * 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. - * - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_gpu_nxp_vglite.h" - -#if LV_USE_GPU_NXP_VG_LITE -#include "../../../core/lv_refr.h" -#if BLIT_DBG_AREAS - #include "lv_draw_vglite_blend.h" -#endif - -/********************* - * DEFINES - *********************/ - -#if LV_COLOR_DEPTH==16 - #define VG_LITE_PX_FMT VG_LITE_RGB565 -#elif LV_COLOR_DEPTH==32 - #define VG_LITE_PX_FMT VG_LITE_BGRA8888 -#else - #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. -#endif - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride, - const lv_color_t * ptr, bool source) -{ - /*Test for memory alignment*/ - if((((uintptr_t)ptr) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U) - VG_LITE_RETURN_INV("%s buffer (0x%x) not aligned to %d.", source ? "Src" : "Dest", - (size_t) ptr, LV_ATTRIBUTE_MEM_ALIGN_SIZE); - - /*Test for stride alignment*/ - if(source && (stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t))) != 0x0U) - VG_LITE_RETURN_INV("Src buffer stride (%d bytes) not aligned to %d bytes.", stride, - LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)); - - vgbuf->format = VG_LITE_PX_FMT; - vgbuf->tiled = VG_LITE_LINEAR; - vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE; - vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE; - - vgbuf->width = (int32_t)width; - vgbuf->height = (int32_t)height; - vgbuf->stride = (int32_t)stride; - - lv_memset_00(&vgbuf->yuv, sizeof(vgbuf->yuv)); - - vgbuf->memory = (void *)ptr; - vgbuf->address = (uint32_t)vgbuf->memory; - vgbuf->handle = NULL; - - return LV_RES_OK; -} - -#if BLIT_DBG_AREAS -void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - lv_area_t * fill_area, lv_color_t color) -{ - lv_area_t a; - - /* top line */ - a.x1 = fill_area->x1; - a.x2 = fill_area->x2; - a.y1 = fill_area->y1; - a.y2 = fill_area->y1; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); - - - /* bottom line */ - a.x1 = fill_area->x1; - a.x2 = fill_area->x2; - a.y1 = fill_area->y2; - a.y2 = fill_area->y2; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); - - /* left line */ - a.x1 = fill_area->x1; - a.x2 = fill_area->x1; - a.y1 = fill_area->y1; - a.y2 = fill_area->y2; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); - - /* right line */ - a.x1 = fill_area->x2; - a.x2 = fill_area->x2; - a.y1 = fill_area->y1; - a.y2 = fill_area->y2; - lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); -} -#endif /* BLIT_DBG_AREAS */ - -void lv_vglite_invalidate_cache(void) -{ - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->clean_dcache_cb) - disp->driver->clean_dcache_cb(disp->driver); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c new file mode 100644 index 000000000..f6325ab2a --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.c @@ -0,0 +1,143 @@ +/** + * @file lv_vglite_buf.c + * + */ + +/** + * MIT License + * + * Copyright 2023 NXP + * + * 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 (including the next paragraph) + * 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. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_vglite_buf.h" + +#if LV_USE_GPU_NXP_VG_LITE + +/********************* + * DEFINES + *********************/ + +#if LV_COLOR_DEPTH == 16 + #define VG_LITE_PX_FMT VG_LITE_RGB565 +#elif LV_COLOR_DEPTH == 32 + #define VG_LITE_PX_FMT VG_LITE_BGRA8888 +#else + #error Only 16bit and 32bit color depth are supported. Set LV_COLOR_DEPTH to 16 or 32. +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static inline void lv_vglite_set_dest_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride); +static inline void lv_vglite_set_buf_ptr(vg_lite_buffer_t * vgbuf, const lv_color_t * buf); +static inline void lv_vglite_set_buf(vg_lite_buffer_t * vgbuf, const lv_color_t * buf, + const lv_area_t * area, lv_coord_t stride); + +/********************** + * STATIC VARIABLES + **********************/ + +static vg_lite_buffer_t dest_vgbuf; +static vg_lite_buffer_t src_vgbuf; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_gpu_nxp_vglite_init_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride) +{ + lv_vglite_set_dest_buf(buf, area, stride); +} + +vg_lite_buffer_t * lv_vglite_get_dest_buf(void) +{ + return &dest_vgbuf; +} + +vg_lite_buffer_t * lv_vglite_get_src_buf(void) +{ + return &src_vgbuf; +} + +void lv_vglite_set_dest_buf_ptr(const lv_color_t * buf) +{ + lv_vglite_set_buf_ptr(&dest_vgbuf, buf); +} + +void lv_vglite_set_src_buf_ptr(const lv_color_t * buf) +{ + lv_vglite_set_buf_ptr(&src_vgbuf, buf); +} + +void lv_vglite_set_src_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride) +{ + if(src_vgbuf.memory != (void *)buf) + lv_vglite_set_buf(&src_vgbuf, buf, area, stride); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static inline void lv_vglite_set_dest_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride) +{ + lv_vglite_set_buf(&dest_vgbuf, buf, area, stride); +} + +static inline void lv_vglite_set_buf_ptr(vg_lite_buffer_t * vgbuf, const lv_color_t * buf) +{ + vgbuf->memory = (void *)buf; + vgbuf->address = (uint32_t)vgbuf->memory; +} + +static inline void lv_vglite_set_buf(vg_lite_buffer_t * vgbuf, const lv_color_t * buf, + const lv_area_t * area, lv_coord_t stride) +{ + vgbuf->format = VG_LITE_PX_FMT; + vgbuf->tiled = VG_LITE_LINEAR; + vgbuf->image_mode = VG_LITE_NORMAL_IMAGE_MODE; + vgbuf->transparency_mode = VG_LITE_IMAGE_OPAQUE; + + vgbuf->width = (int32_t)lv_area_get_width(area); + vgbuf->height = (int32_t)lv_area_get_height(area); + vgbuf->stride = (int32_t)(stride) * sizeof(lv_color_t); + + lv_memset_00(&vgbuf->yuv, sizeof(vgbuf->yuv)); + + vgbuf->memory = (void *)buf; + vgbuf->address = (uint32_t)vgbuf->memory; + vgbuf->handle = NULL; +} + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h new file mode 100644 index 000000000..9219dca05 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_buf.h @@ -0,0 +1,113 @@ +/** + * @file lv_vglite_buf.h + * + */ + +/** + * MIT License + * + * Copyright 2023 NXP + * + * 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 (including the next paragraph) + * 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 LV_VGLITE_BUF_H +#define LV_VGLITE_BUF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../../lv_conf_internal.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "vg_lite.h" +#include "../../sw/lv_draw_sw.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +/** + * Init vglite destination buffer. It will be done once per frame. + * + * @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode) + * @param[in] area Destination buffer area (for width and height) + * @param[in] stride Stride of destination buffer + */ +void lv_gpu_nxp_vglite_init_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride); + +/** + * Get vglite destination buffer pointer. + * + * @retval The vglite destination buffer + */ +vg_lite_buffer_t * lv_vglite_get_dest_buf(void); + +/** + * Get vglite source buffer pointer. + * + * @retval The vglite source buffer + */ +vg_lite_buffer_t * lv_vglite_get_src_buf(void); + +/** + * Set vglite destination buffer address only. + * + * @param[in] buf Destination buffer address (does not require alignment for VG_LITE_LINEAR mode) + */ +void lv_vglite_set_dest_buf_ptr(const lv_color_t * buf); + +/** + * Set vglite source buffer address only. + * + * @param[in] buf Source buffer address + */ +void lv_vglite_set_src_buf_ptr(const lv_color_t * buf); + +/** + * Set vglite source buffer. It will be done only if buffer addreess is different. + * + * @param[in] buf Source buffer address + * @param[in] area Source buffer area (for width and height) + * @param[in] stride Stride of source buffer + */ +void lv_vglite_set_src_buf(const lv_color_t * buf, const lv_area_t * area, lv_coord_t stride); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_VGLITE_BUF_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c new file mode 100644 index 000000000..adc9f7712 --- /dev/null +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.c @@ -0,0 +1,149 @@ +/** + * @file lv_vglite_utils.c + * + */ + +/** + * MIT License + * + * Copyright 2022, 2023 NXP + * + * 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 (including the next paragraph) + * 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. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_vglite_utils.h" + +#if LV_USE_GPU_NXP_VG_LITE +#include "../../../core/lv_refr.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/** + * Clean and invalidate cache. + */ +static inline void invalidate_cache(void); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_res_t lv_vglite_run(void) +{ + invalidate_cache(); + + VG_LITE_ERR_RETURN_INV(vg_lite_flush(), "Flush failed."); + + return LV_RES_OK; +} + +lv_res_t lv_vglite_premult_and_swizzle(vg_lite_color_t * vg_col32, lv_color32_t lv_col32, lv_opa_t opa, + vg_lite_buffer_format_t vg_col_format) +{ + + lv_color32_t lv_col32_premul = lv_col32; + if(opa <= (lv_opa_t)LV_OPA_MAX) { + /* Only pre-multiply color if hardware pre-multiplication is not present */ + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { + lv_col32_premul.ch.red = (uint8_t)(((uint16_t)lv_col32.ch.red * opa) >> 8); + lv_col32_premul.ch.green = (uint8_t)(((uint16_t)lv_col32.ch.green * opa) >> 8); + lv_col32_premul.ch.blue = (uint8_t)(((uint16_t)lv_col32.ch.blue * opa) >> 8); + } + lv_col32_premul.ch.alpha = opa; + } + + switch(vg_col_format) { + case VG_LITE_BGRA8888: + *vg_col32 = lv_col32_premul.full; + break; + case VG_LITE_RGBA8888: + *vg_col32 = ((uint32_t)lv_col32_premul.ch.red << 24) | ((uint32_t)lv_col32_premul.ch.green << 16) | + ((uint32_t)lv_col32_premul.ch.blue << 8) | (uint32_t)lv_col32_premul.ch.alpha; + break; + case VG_LITE_ABGR8888: + *vg_col32 = ((uint32_t)lv_col32_premul.ch.alpha << 24) | ((uint32_t)lv_col32_premul.ch.blue << 16) | + ((uint32_t)lv_col32_premul.ch.green << 8) | (uint32_t)lv_col32_premul.ch.red; + break; + case VG_LITE_ARGB8888: + *vg_col32 = ((uint32_t)lv_col32_premul.ch.alpha << 24) | ((uint32_t)lv_col32_premul.ch.red << 16) | + ((uint32_t)lv_col32_premul.ch.green << 8) | (uint32_t)lv_col32_premul.ch.blue; + break; + default: + return LV_RES_INV; + } + + return LV_RES_OK; +} + +vg_lite_blend_t lv_vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode) +{ + vg_lite_blend_t vg_blend_mode; + switch(lv_blend_mode) { + case LV_BLEND_MODE_ADDITIVE: + vg_blend_mode = VG_LITE_BLEND_ADDITIVE; + break; + case LV_BLEND_MODE_SUBTRACTIVE: + vg_blend_mode = VG_LITE_BLEND_SUBTRACT; + break; + case LV_BLEND_MODE_MULTIPLY: + vg_blend_mode = VG_LITE_BLEND_MULTIPLY; + break; + case LV_BLEND_MODE_REPLACE: + vg_blend_mode = VG_LITE_BLEND_NONE; + break; + default: + vg_blend_mode = VG_LITE_BLEND_SRC_OVER; + break; + } + return vg_blend_mode; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static inline void invalidate_cache(void) +{ + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + if(disp->driver->clean_dcache_cb) + disp->driver->clean_dcache_cb(disp->driver); +} + +#endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.h b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.h similarity index 65% rename from lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.h rename to lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.h index c22cae185..9ff4de02f 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_gpu_nxp_vglite.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/nxp/vglite/lv_vglite_utils.h @@ -1,12 +1,12 @@ /** - * @file lv_gpu_nxp_vglite.h + * @file lv_vglite_utils.h * */ /** * MIT License * - * Copyright 2020-2022 NXP + * Copyright 2022, 2023 NXP * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,8 +27,8 @@ * */ -#ifndef LV_GPU_NXP_VGLITE_H -#define LV_GPU_NXP_VGLITE_H +#ifndef LV_VGLITE_UTILS_H +#define LV_VGLITE_UTILS_H #ifdef __cplusplus extern "C" { @@ -43,40 +43,21 @@ extern "C" { #include "vg_lite.h" #include "../../sw/lv_draw_sw.h" #include "../../../misc/lv_log.h" -#include "fsl_debug_console.h" /********************* * DEFINES *********************/ -/** Use this symbol as limit to disable feature (value has to be larger than supported resolution) */ -#define LV_GPU_NXP_VG_LITE_FEATURE_DISABLED (1920*1080+1) - -/** Stride in px required by VG-Lite HW. Don't change this. */ -#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U - #ifndef LV_GPU_NXP_VG_LITE_LOG_ERRORS /** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ #define LV_GPU_NXP_VG_LITE_LOG_ERRORS 1 #endif #ifndef LV_GPU_NXP_VG_LITE_LOG_TRACES -/** Enable logging of VG-Lite errors (\see LV_LOG_ERROR)*/ +/** Enable logging of VG-Lite traces (\see LV_LOG_ERROR)*/ #define LV_GPU_NXP_VG_LITE_LOG_TRACES 0 #endif -/* Draw rectangles around BLIT tiles */ -#define BLIT_DBG_AREAS 0 - -/* Print detailed info to SDK console (NOT to LVGL log system) */ -#define BLIT_DBG_VERBOSE 0 - -/* Verbose debug print */ -#if BLIT_DBG_VERBOSE -#define PRINT_BLT PRINTF -#else -#define PRINT_BLT(...) -#endif /* The optimal Bezier control point offset for radial unit * see: https://spencermortensen.com/articles/bezier-circle/ @@ -95,36 +76,35 @@ extern "C" { **********************/ /** - * Fills vg_lite_buffer_t structure according given parameters. + * Premultiplies and swizzles given LVGL 32bit color to obtain vglite color. * - * @param[in/out] vgbuf Buffer structure to be filled - * @param[in] width Width of buffer in pixels - * @param[in] height Height of buffer in pixels - * @param[in] stride Stride of the buffer in bytes - * @param[in] ptr Pointer to the buffer (must be aligned according VG-Lite requirements) - * @param[in] source Boolean to check if this is a source buffer - */ -lv_res_t lv_vglite_init_buf(vg_lite_buffer_t * vgbuf, uint32_t width, uint32_t height, uint32_t stride, - const lv_color_t * ptr, bool source); - -#if BLIT_DBG_AREAS -/** - * Draw a simple rectangle, 1 px line width. + * @param[in/out] vg_col32 The obtained vglite color + * @param[in] lv_col32 The initial LVGL 32bit color + * @param[in] opa The opacity to premultiply with + * @param[in] vg_col_format The format of the resulting vglite color * - * @param dest_buf Destination buffer - * @param dest_width Destination buffer width (must be aligned on 16px) - * @param dest_height Destination buffer height - * @param fill_area Rectangle coordinates - * @param color Rectangle color + * @retval LV_RES_OK Operation completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ -void lv_vglite_dbg_draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height, - lv_area_t * fill_area, lv_color_t color); -#endif +lv_res_t lv_vglite_premult_and_swizzle(vg_lite_color_t * vg_col32, lv_color32_t lv_col32, lv_opa_t opa, + vg_lite_buffer_format_t vg_col_format); /** - * Clean & invalidate cache. + * Get vglite blend mode. + * + * @param[in] lv_blend_mode The LVGL blend mode + * + * @retval The vglite blend mode */ -void lv_vglite_invalidate_cache(void); +vg_lite_blend_t lv_vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode); + +/** + * Clear cache and flush command to VG-Lite. + * + * @retval LV_RES_OK Run completed + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +lv_res_t lv_vglite_run(void); /********************** * MACROS @@ -142,7 +122,8 @@ void lv_vglite_invalidate_cache(void); #define VG_LITE_ERR_RETURN_INV(err, fmt, ...) \ do { \ if(err != VG_LITE_SUCCESS) { \ - LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + LV_LOG_ERROR(fmt" (err = %d)", \ + err, ##__VA_ARGS__); \ return LV_RES_INV; \ } \ } while (0) @@ -158,7 +139,7 @@ void lv_vglite_invalidate_cache(void); #if LV_GPU_NXP_VG_LITE_LOG_TRACES #define VG_LITE_LOG_TRACE(fmt, ...) \ do { \ - LV_LOG_ERROR(fmt, ##__VA_ARGS__); \ + LV_LOG(fmt, ##__VA_ARGS__); \ } while (0) #define VG_LITE_RETURN_INV(fmt, ...) \ @@ -182,4 +163,4 @@ void lv_vglite_invalidate_cache(void); } /*extern "C"*/ #endif -#endif /*LV_GPU_NXP_VGLITE_H*/ +#endif /*LV_VGLITE_UTILS_H*/ diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c index a303ac764..6418a0af6 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.c @@ -27,6 +27,8 @@ * DEFINES *********************/ +#define FRAG_SPACING 3 + /********************** * TYPEDEFS **********************/ @@ -37,6 +39,23 @@ typedef struct { lv_coord_t size; } lv_draw_rect_bg_key_t; +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; + uint8_t stops_count; + lv_grad_dir_t dir; +} lv_draw_rect_grad_strip_key_t; + +typedef struct { + lv_sdl_cache_key_magic_t magic; + lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]; + uint8_t stops_count; + lv_grad_dir_t dir; + lv_coord_t w; + lv_coord_t h; + lv_coord_t radius; +} lv_draw_rect_grad_frag_key_t; + typedef struct { lv_sdl_cache_key_magic_t magic; lv_coord_t radius; @@ -57,6 +76,12 @@ typedef struct { static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc); +static void draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_grad_dsc_t * grad, bool blend_mod); + +static void draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc); + static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc); @@ -81,6 +106,11 @@ static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_c static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size); +static lv_draw_rect_grad_frag_key_t rect_grad_frag_key_create(const lv_grad_dsc_t * grad, lv_coord_t w, lv_coord_t h, + lv_coord_t radius); + +static lv_draw_rect_grad_strip_key_t rect_grad_strip_key_create(const lv_grad_dsc_t * grad); + static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur); static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, const lv_area_t * outer_area, @@ -148,16 +178,93 @@ void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius) { lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, radius); - lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1}; - lv_area_t coords_frag = {0, 0, radius - 1, radius - 1}; SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); if(texture == NULL) { + lv_area_t coords = {0, 0, radius * 2 - 1, radius * 2 - 1}; + lv_area_t coords_frag = {0, 0, radius - 1, radius - 1}; lv_draw_mask_radius_param_t mask_rout_param; lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false); int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); texture = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords_frag, &mask_id, 1); + SDL_assert(texture != NULL); lv_draw_mask_remove_id(mask_id); - SDL_assert(texture); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); + } + return texture; +} + +SDL_Texture * lv_draw_sdl_rect_grad_frag_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad, lv_coord_t w, + lv_coord_t h, lv_coord_t radius) +{ + lv_draw_rect_grad_frag_key_t key = rect_grad_frag_key_create(grad, w, h, radius); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); + if(texture == NULL) { + lv_area_t coords = {0, 0, radius * 2 + FRAG_SPACING - 1, radius * 2 + FRAG_SPACING - 1}; + texture = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET, + lv_area_get_width(&coords), lv_area_get_height(&coords)); + SDL_assert(texture != NULL); + + lv_draw_mask_radius_param_t mask_rout_param; + lv_draw_mask_radius_init(&mask_rout_param, &coords, radius, false); + int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL); + SDL_Texture * mask = lv_draw_sdl_mask_dump_texture(ctx->renderer, &coords, &mask_id, 1); + SDL_assert(mask != NULL); + SDL_SetTextureBlendMode(mask, SDL_BLENDMODE_NONE); + lv_draw_mask_remove_id(mask_id); + + SDL_Texture * target_backup = SDL_GetRenderTarget(ctx->renderer); + SDL_SetRenderTarget(ctx->renderer, texture); + SDL_RenderCopy(ctx->renderer, mask, NULL, NULL); + SDL_DestroyTexture(mask); + + lv_area_t blend_coords = {.x1 = 0, .y1 = 0, .x2 = w - 1, .y2 = h - 1}; + lv_area_t draw_area = {.x1 = 0, .y1 = 0, .x2 = radius - 1, .y2 = radius - 1}; + /* Align to top left */ + lv_area_align(&coords, &draw_area, LV_ALIGN_TOP_LEFT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_TOP_LEFT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + /* Align to top right */ + lv_area_align(&coords, &draw_area, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_TOP_RIGHT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + /* Align to bottom right */ + lv_area_align(&coords, &draw_area, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + /* Align to bottom left */ + lv_area_align(&coords, &draw_area, LV_ALIGN_BOTTOM_LEFT, 0, 0); + lv_area_align(&coords, &blend_coords, LV_ALIGN_BOTTOM_LEFT, 0, 0); + draw_bg_grad_simple(ctx, &blend_coords, &draw_area, grad, true); + + SDL_SetRenderTarget(ctx->renderer, target_backup); + lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); + } + return texture; +} + +SDL_Texture * lv_draw_sdl_rect_grad_strip_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad) +{ + lv_draw_rect_grad_strip_key_t key = rect_grad_strip_key_create(grad); + SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); + if(texture == NULL) { + Uint32 amask = 0xFF000000; + Uint32 rmask = 0x00FF0000; + Uint32 gmask = 0x0000FF00; + Uint32 bmask = 0x000000FF; + lv_color_t pixels[256]; + for(int i = 0; i < 256; i++) { + pixels[i] = lv_gradient_calculate(grad, 256, i); + } + int width = grad->dir == LV_GRAD_DIR_VER ? 1 : 256; + int height = grad->dir == LV_GRAD_DIR_VER ? 256 : 1; + SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(pixels, width, height, LV_COLOR_DEPTH, width * LV_COLOR_DEPTH / 8, + rmask, gmask, bmask, amask); + texture = SDL_CreateTextureFromSurface(ctx->renderer, surface); + SDL_assert(texture != NULL); + SDL_FreeSurface(surface); lv_draw_sdl_texture_cache_put(ctx, &key, sizeof(key), texture); } return texture; @@ -193,7 +300,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {frag_size + 3 + sx, sy, dw, dh}; + SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, sy, dw, dh}; SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); } else { @@ -212,7 +319,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 3 + sy, dw, dh}; + SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, frag_size + FRAG_SPACING + sy, dw, dh}; SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); } else { @@ -220,7 +327,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture SDL_RenderCopyEx(ctx->renderer, frag, &src_rect, &dst_rect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL); } } - /* Lower left, right edge should not be clip */ + /* Lower left, right edge should not be clipped */ corner_area.x1 = coords->x1; corner_area.x2 = coords->x1 + frag_size - 1; if(_lv_area_intersect(&dst_area, &corner_area, clip)) { @@ -231,7 +338,7 @@ void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - corner_area.x1), sy = (lv_coord_t)(dst_area.y1 - corner_area.y1); - SDL_Rect src_rect = {sx, frag_size + 3 + sy, dw, dh}; + SDL_Rect src_rect = {sx, frag_size + FRAG_SPACING + sy, dw, dh}; SDL_RenderCopy(ctx->renderer, frag, &src_rect, &dst_rect); } else { @@ -252,9 +359,23 @@ static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, con if(dsc->bg_opa == 0) { return; } - SDL_Color bg_color; - lv_color_to_sdl_color(&dsc->bg_color, &bg_color); lv_coord_t radius = dsc->radius; + SDL_Color bg_color; + if(dsc->bg_grad.dir == LV_GRAD_DIR_NONE) { + lv_color_to_sdl_color(&dsc->bg_color, &bg_color); + } + else if(dsc->bg_grad.stops_count == 1) { + lv_color_to_sdl_color(&dsc->bg_grad.stops[0].color, &bg_color); + } + else { + if(radius <= 0) { + draw_bg_grad_simple(ctx, coords, draw_area, &dsc->bg_grad, false); + } + else { + draw_bg_grad_radius(ctx, coords, draw_area, dsc); + } + return; + } if(radius <= 0) { SDL_Rect rect; lv_area_to_sdl_rect(draw_area, &rect); @@ -277,9 +398,111 @@ static void draw_bg_color(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, con frag_render_center(ctx->renderer, texture, real_radius, coords, draw_area, false); } +static void draw_bg_grad_simple(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_grad_dsc_t * grad, bool blend_mod) +{ + SDL_Rect dstrect; + lv_area_to_sdl_rect(draw_area, &dstrect); + SDL_Rect srcrect; + if(grad->dir == LV_GRAD_DIR_VER) { + lv_coord_t coords_h = lv_area_get_height(coords); + srcrect.x = 0; + srcrect.y = (draw_area->y1 - coords->y1) * 255 / coords_h; + srcrect.w = 1; + srcrect.h = dstrect.h * 256 / coords_h; + + if(srcrect.y < 0 || srcrect.y > 255) { + return; + } + } + else { + lv_coord_t coords_w = lv_area_get_width(coords); + srcrect.x = (draw_area->x1 - coords->x1) * 255 / coords_w; + srcrect.y = 0; + srcrect.w = dstrect.w * 256 / coords_w; + srcrect.h = 1; + + if(srcrect.x < 0 || srcrect.x > 255) { + return; + } + } + + SDL_Texture * grad_texture = lv_draw_sdl_rect_grad_strip_obtain(ctx, grad); + if(blend_mod) { + SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_MOD); + } + else { + SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_BLEND); + } + + SDL_RenderCopy(ctx->renderer, grad_texture, &srcrect, &dstrect); +} + +static void draw_bg_grad_radius(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, + const lv_draw_rect_dsc_t * dsc) +{ + lv_coord_t radius = dsc->radius; + /*A small texture with a quarter of the rect is enough*/ + lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords); + lv_coord_t real_radius = LV_MIN3(bg_w / 2, bg_h / 2, radius); + SDL_Texture * grad_texture = lv_draw_sdl_rect_grad_frag_obtain(ctx, &dsc->bg_grad, bg_w, bg_h, radius); + SDL_SetTextureBlendMode(grad_texture, SDL_BLENDMODE_BLEND); + + lv_draw_sdl_rect_bg_frag_draw_corners(ctx, grad_texture, real_radius, coords, draw_area, true); + lv_area_t part_coords; + lv_area_t part_area; + if(bg_w > radius * 2) { + /*Draw left, middle, right*/ + part_coords.x1 = 0; + part_coords.x2 = radius - 1; + part_coords.y1 = radius; + part_coords.y2 = bg_h - radius - 1; + + lv_area_align(coords, &part_coords, LV_ALIGN_LEFT_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + lv_area_align(coords, &part_coords, LV_ALIGN_RIGHT_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + part_coords.x1 = radius; + part_coords.x2 = bg_w - radius - 1; + part_coords.y1 = 0; + part_coords.y2 = bg_h - 1; + lv_area_align(coords, &part_coords, LV_ALIGN_CENTER, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + } + else if(bg_h > radius * 2) { + /*Draw top, middle, bottom*/ + part_coords.x1 = radius; + part_coords.x2 = bg_w - radius - 1; + part_coords.y1 = 0; + part_coords.y2 = radius - 1; + + lv_area_align(coords, &part_coords, LV_ALIGN_TOP_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + lv_area_align(coords, &part_coords, LV_ALIGN_BOTTOM_MID, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + + part_coords.x1 = 0; + part_coords.x2 = bg_w - 1; + part_coords.y1 = radius; + part_coords.y2 = bg_h - radius - 1; + lv_area_align(coords, &part_coords, LV_ALIGN_CENTER, 0, 0); + _lv_area_intersect(&part_area, &part_coords, draw_area); + draw_bg_grad_simple(ctx, coords, &part_area, &dsc->bg_grad, false); + } +} + static void draw_bg_img(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords, const lv_area_t * draw_area, const lv_draw_rect_dsc_t * dsc) { + LV_UNUSED(draw_area); if(SKIP_IMAGE(dsc)) return; lv_img_src_t src_type = lv_img_src_get_type(dsc->bg_img_src); @@ -521,8 +744,8 @@ static void draw_border_generic(lv_draw_sdl_ctx_t * ctx, const lv_area_t * outer lv_coord_t frag_size = LV_MAX(radius, max_side); SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, &key, sizeof(key), NULL); if(texture == NULL) { - /* Create a mask texture with size of (frag_size * 2 + 3) */ - const lv_area_t frag_area = {0, 0, frag_size * 2 + 2, frag_size * 2 + 2}; + /* Create a mask texture with size of (frag_size * 2 + FRAG_SPACING) */ + const lv_area_t frag_area = {0, 0, frag_size * 2 + FRAG_SPACING - 1, frag_size * 2 + FRAG_SPACING - 1}; /*Create mask for the outer area*/ int16_t mask_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV}; @@ -595,7 +818,7 @@ static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_ lv_coord_t dh = lv_area_get_height(&dst_area); if(full) { lv_coord_t sy = (lv_coord_t)(dst_area.y1 - border_area.y1); - SDL_Rect src_rect = {frag_size + 1, frag_size + 3 + sy, 1, dh}; + SDL_Rect src_rect = {frag_size + 1, frag_size + FRAG_SPACING + sy, 1, dh}; SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } else { @@ -634,7 +857,7 @@ static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_ lv_coord_t dw = lv_area_get_width(&dst_area); if(full) { lv_coord_t sx = (lv_coord_t)(dst_area.x1 - border_area.x1); - SDL_Rect src_rect = {frag_size + 3 + sx, frag_size + 1, dw, 1}; + SDL_Rect src_rect = {frag_size + FRAG_SPACING + sx, frag_size + 1, dw, 1}; SDL_RenderCopy(renderer, frag, &src_rect, &dst_rect); } else { @@ -682,6 +905,38 @@ static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t si return key; } +static lv_draw_rect_grad_frag_key_t rect_grad_frag_key_create(const lv_grad_dsc_t * grad, lv_coord_t w, lv_coord_t h, + lv_coord_t radius) +{ + lv_draw_rect_grad_frag_key_t key; + SDL_memset(&key, 0, sizeof(key)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD; + key.stops_count = grad->stops_count; + key.dir = grad->dir; + for(uint8_t i = 0; i < grad->stops_count; i++) { + key.stops[i].frac = grad->stops[i].frac; + key.stops[i].color = grad->stops[i].color; + } + key.w = w; + key.h = h; + key.radius = radius; + return key; +} + +static lv_draw_rect_grad_strip_key_t rect_grad_strip_key_create(const lv_grad_dsc_t * grad) +{ + lv_draw_rect_grad_strip_key_t key; + SDL_memset(&key, 0, sizeof(key)); + key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD; + key.stops_count = grad->stops_count; + key.dir = grad->dir; + for(uint8_t i = 0; i < grad->stops_count; i++) { + key.stops[i].frac = grad->stops[i].frac; + key.stops[i].color = grad->stops[i].color; + } + return key; +} + static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur) { lv_draw_rect_shadow_key_t key; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h index 1e9be3445..3472af31b 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_rect.h @@ -59,6 +59,11 @@ typedef struct lv_draw_sdl_rect_header_t { SDL_Texture * lv_draw_sdl_rect_bg_frag_obtain(lv_draw_sdl_ctx_t * ctx, lv_coord_t radius); +SDL_Texture * lv_draw_sdl_rect_grad_frag_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad, lv_coord_t w, + lv_coord_t h, lv_coord_t radius); + +SDL_Texture * lv_draw_sdl_rect_grad_strip_obtain(lv_draw_sdl_ctx_t * ctx, const lv_grad_dsc_t * grad); + void lv_draw_sdl_rect_bg_frag_draw_corners(lv_draw_sdl_ctx_t * ctx, SDL_Texture * frag, lv_coord_t frag_size, const lv_area_t * coords, const lv_area_t * clip, bool full); diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h index dc8b578e6..1bbf17cd8 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.h @@ -50,6 +50,7 @@ typedef enum { LV_GPU_CACHE_KEY_MAGIC_RECT_BG = 0x31, LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32, LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER = 0x33, + LV_GPU_CACHE_KEY_MAGIC_RECT_GRAD = 0x34, LV_GPU_CACHE_KEY_MAGIC_FONT_GLYPH = 0x41, LV_GPU_CACHE_KEY_MAGIC_MASK = 0x51, } lv_sdl_cache_key_magic_t; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c index 4eb1940ef..908909df8 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c @@ -11,100 +11,71 @@ #if LV_USE_GPU_STM32_DMA2D -#include LV_GPU_DMA2D_CMSIS_INCLUDE - /********************* * DEFINES *********************/ - #if LV_COLOR_16_SWAP - // TODO: F7 has red blue swap bit in control register for all layers and output - #error "Can't use DMA2D with LV_COLOR_16_SWAP 1" + // Note: DMA2D red/blue swap (RBS) works for all color modes + #define RBS_BIT 1U +#else + #define RBS_BIT 0U #endif -#if LV_COLOR_DEPTH == 8 - #error "Can't use DMA2D with LV_COLOR_DEPTH == 8" -#endif +#define CACHE_ROW_SIZE 32U // cache row size in Bytes + +// For code/implementation discussion refer to https://github.com/lvgl/lvgl/issues/3714#issuecomment-1365187036 +// astyle --options=lvgl/scripts/code-format.cfg --ignore-exclude-errors lvgl/src/draw/stm32_dma2d/*.c lvgl/src/draw/stm32_dma2d/*.h #if LV_COLOR_DEPTH == 16 - #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565 + const dma2d_color_format_t LvglColorFormat = RGB565; #elif LV_COLOR_DEPTH == 32 - #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888 + const dma2d_color_format_t LvglColorFormat = ARGB8888; #else - /*Can't use GPU with other formats*/ + #error "Cannot use DMA2D with LV_COLOR_DEPTH other than 16 or 32" #endif -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color); - - -static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa); - -static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format); - - -static void invalidate_cache(void); - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ +static bool isDma2dInProgess = false; // indicates whether DMA2D transfer *initiated here* is in progress /** * Turn on the peripheral and set output color mode, this only needs to be done once */ void lv_draw_stm32_dma2d_init(void) { - /*Enable DMA2D clock*/ + // Enable DMA2D clock #if defined(STM32F4) || defined(STM32F7) - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; // enable DMA2D #elif defined(STM32H7) RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN; #else # warning "LVGL can't enable the clock of DMA2D" #endif - /*Wait for hardware access to complete*/ + // Wait for hardware access to complete __asm volatile("DSB\n"); - /*Delay after setting peripheral clock*/ + // Delay after setting peripheral clock volatile uint32_t temp = RCC->AHB1ENR; LV_UNUSED(temp); - /*set output colour mode*/ - DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT; + // AHB master timer configuration + DMA2D->AMTCR = 0; // AHB bus guaranteed dead time disabled +#if defined(LV_STM32_DMA2D_TEST) + _lv_gpu_stm32_dwt_init(); // init µs timer +#endif } - void lv_draw_stm32_dma2d_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) { - lv_draw_sw_init_ctx(drv, draw_ctx); lv_draw_stm32_dma2d_ctx_t * dma2d_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx; dma2d_draw_ctx->blend = lv_draw_stm32_dma2d_blend; - // dma2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_stm32_dma2d_img_decoded; - dma2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_stm32_dma2d_wait_cb; + dma2d_draw_ctx->base_draw.draw_img_decoded = lv_draw_stm32_dma2d_img_decoded; + //dma2d_draw_ctx->base_draw.draw_img = lv_draw_stm32_dma2d_img; + // Note: currently it does not make sense use lv_gpu_stm32_dma2d_wait_cb() since waiting starts right after the dma2d transfer + //dma2d_draw_ctx->base_draw.wait_for_finish = lv_gpu_stm32_dma2d_wait_cb; dma2d_draw_ctx->base_draw.buffer_copy = lv_draw_stm32_dma2d_buffer_copy; - } void lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx) @@ -113,153 +84,660 @@ void lv_draw_stm32_dma2d_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ct LV_UNUSED(draw_ctx); } - -void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) +static void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - lv_area_t blend_area; - if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; + if(dsc->blend_mode != LV_BLEND_MODE_NORMAL) { + lv_draw_sw_blend_basic(draw_ctx, dsc); + return; + } + // Note: x1 must be zero. Otherwise, there is no way to correctly calculate dest_stride. + //LV_ASSERT_MSG(draw_ctx->buf_area->x1 == 0); // critical? + // Both draw buffer start address and buffer size *must* be 32-byte aligned since draw buffer cache is being invalidated. + //uint32_t drawBufferLength = lv_area_get_size(draw_ctx->buf_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(drawBufferLength % CACHE_ROW_SIZE == 0); // critical, but this is not the way to test it + //LV_ASSERT_MSG((uint32_t)draw_ctx->buf % CACHE_ROW_SIZE == 0, "draw_ctx.buf is not 32B aligned"); // critical? - bool done = false; - - if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) { - lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); - - lv_color_t * dest_buf = draw_ctx->buf; - dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1); - - const lv_color_t * src_buf = dsc->src_buf; - if(src_buf) { - lv_draw_sw_blend_basic(draw_ctx, dsc); - lv_coord_t src_stride; - src_stride = lv_area_get_width(dsc->blend_area); - src_buf += src_stride * (blend_area.y1 - dsc->blend_area->y1) + (blend_area.x1 - dsc->blend_area->x1); - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - lv_draw_stm32_dma2d_blend_map(dest_buf, &blend_area, dest_stride, src_buf, src_stride, dsc->opa); - done = true; - } - else if(dsc->opa >= LV_OPA_MAX) { - lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); - lv_draw_stm32_dma2d_blend_fill(dest_buf, dest_stride, &blend_area, dsc->color); - done = true; - } + if(dsc->src_buf) { + // For performance reasons, both source buffer start address and buffer size *should* be 32-byte aligned since source buffer cache is being cleaned. + //uint32_t srcBufferLength = lv_area_get_size(dsc->blend_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(srcBufferLength % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + //LV_ASSERT_MSG((uint32_t)dsc->src_buf % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) } - if(!done) lv_draw_sw_blend_basic(draw_ctx, dsc); -} + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, dsc->blend_area, draw_ctx->clip_area)) return; + // + draw_ctx->buf_area has the entire draw buffer location + // + draw_ctx->clip_area has the current draw buffer location + // + dsc->blend_area has the location of the area intended to be painted - image etc. + // + draw_area has the area actually being painted + // All coordinates are relative to the screen. -void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, - void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, - void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area) -{ - LV_UNUSED(draw_ctx); - lv_draw_stm32_dma2d_blend_map(dest_buf, dest_area, dest_stride, src_buf, src_stride, LV_OPA_MAX); -} + const lv_opa_t * mask = dsc->mask_buf; + if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return; + else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; -static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, - const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format) -{ - /*TODO basic ARGB8888 image can be handles here*/ + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + if(mask != NULL) { + // For performance reasons, both mask buffer start address and buffer size *should* be 32-byte aligned since mask buffer cache is being cleaned. + //uint32_t srcBufferLength = lv_area_get_size(dsc->mask_area) * sizeof(lv_opa_t); + //LV_ASSERT_MSG(srcBufferLength % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + //LV_ASSERT_MSG((uint32_t)mask % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) - lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, color_format); -} + lv_coord_t mask_stride = lv_area_get_width(dsc->mask_area); + lv_point_t mask_offset = lv_area_get_offset(dsc->mask_area, &draw_area); // mask offset in relation to draw_area -static void lv_draw_stm32_dma2d_blend_fill(lv_color_t * dest_buf, lv_coord_t dest_stride, const lv_area_t * fill_area, - lv_color_t color) -{ - /*Simply fill an area*/ - int32_t area_w = lv_area_get_width(fill_area); - int32_t area_h = lv_area_get_height(fill_area); - invalidate_cache(); + if(dsc->src_buf == NULL) { // 93.5% + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + _lv_draw_stm32_dma2d_blend_paint(draw_ctx->buf, dest_stride, &draw_area, mask, mask_stride, &mask_offset, dsc->color, + dsc->opa); + } + else { // 0.2% + // note: (x)RGB dsc->src_buf does not carry alpha channel bytes, + // alpha channel bytes are carried in dsc->mask_buf +#if LV_COLOR_DEPTH == 32 + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + lv_point_t src_offset = lv_area_get_offset(dsc->blend_area, &draw_area); // source image offset in relation to draw_area + lv_coord_t draw_width = lv_area_get_width(&draw_area); + lv_coord_t draw_height = lv_area_get_height(&draw_area); - DMA2D->CR = 0x30000; - DMA2D->OMAR = (uint32_t)dest_buf; - /*as input color mode is same as output we don't need to convert here do we?*/ - DMA2D->OCOLR = color.full; - DMA2D->OOR = dest_stride - area_w; - DMA2D->NLR = (area_w << DMA2D_NLR_PL_Pos) | (area_h << DMA2D_NLR_NL_Pos); + // merge mask alpha bytes with src RGB bytes + // TODO: optimize by reading 4 or 8 mask bytes at a time + mask += (mask_stride * mask_offset.y) + mask_offset.x; + lv_color_t * src_buf = (lv_color_t *)dsc->src_buf; + src_buf += (src_stride * src_offset.y) + src_offset.x; + uint16_t mask_buffer_offset = mask_stride - draw_width; + uint16_t src_buffer_offset = src_stride - draw_width; + while(draw_height > 0) { + draw_height--; + for(uint16_t x = 0; x < draw_width; x++) { + (*src_buf).ch.alpha = *mask; + src_buf++; + mask++; + } + mask += mask_buffer_offset; + src_buf += src_buffer_offset; + } - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, + -draw_ctx->buf_area->y1); // translate the screen draw area to the origin of the buffer area + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, dsc->src_buf, src_stride, &src_offset, dsc->opa, + ARGB8888, false); +#else + // Note: 16-bit bitmap hardware blending with mask and background is possible, but requires a temp 24 or 32-bit buffer to combine bitmap with mask first. -} - - -static void lv_draw_stm32_dma2d_blend_map(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride, - const lv_color_t * src_buf, lv_coord_t src_stride, lv_opa_t opa) -{ - - /*Simple copy*/ - int32_t dest_w = lv_area_get_width(dest_area); - int32_t dest_h = lv_area_get_height(dest_area); - - invalidate_cache(); - if(opa >= LV_OPA_MAX) { - DMA2D->CR = 0; - /*copy output colour mode, this register controls both input and output colour format*/ - DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT; - DMA2D->FGMAR = (uint32_t)src_buf; - DMA2D->FGOR = src_stride - dest_w; - DMA2D->OMAR = (uint32_t)dest_buf; - DMA2D->OOR = dest_stride - dest_w; - DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; + lv_draw_sw_blend_basic(draw_ctx, dsc); // (e.g. Shop Items) + // clean cache after software drawing - this does not help since this is not the only place where buffer is written without dma2d + // lv_coord_t draw_width = lv_area_get_width(&draw_area); + // lv_coord_t draw_height = lv_area_get_height(&draw_area); + // uint32_t dest_address = (uint32_t)(draw_ctx->buf + (dest_stride * draw_area.y1) + draw_area.x1); + // _lv_gpu_stm32_dma2d_clean_cache(dest_address, dest_stride - draw_width, draw_width, draw_height, sizeof(lv_color_t)); +#endif + } } else { - DMA2D->CR = 0x20000; - - DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT; - DMA2D->BGMAR = (uint32_t)dest_buf; - DMA2D->BGOR = dest_stride - dest_w; - - DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT - /*alpha mode 2, replace with foreground * alpha value*/ - | (2 << DMA2D_FGPFCCR_AM_Pos) - /*alpha value*/ - | (opa << DMA2D_FGPFCCR_ALPHA_Pos); - DMA2D->FGMAR = (uint32_t)src_buf; - DMA2D->FGOR = src_stride - dest_w; - - DMA2D->OMAR = (uint32_t)dest_buf; - DMA2D->OOR = dest_stride - dest_w; - DMA2D->NLR = (dest_w << DMA2D_NLR_PL_Pos) | (dest_h << DMA2D_NLR_NL_Pos); - - /*start transfer*/ - DMA2D->CR |= DMA2D_CR_START_Msk; + if(dsc->src_buf == NULL) { // 6.1% + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, + -draw_ctx->buf_area->y1); // translate the screen draw area to the origin of the buffer area + _lv_draw_stm32_dma2d_blend_fill(draw_ctx->buf, dest_stride, &draw_area, dsc->color, dsc->opa); + } + else { // 0.2% + lv_coord_t src_stride = lv_area_get_width(dsc->blend_area); + lv_point_t src_offset = lv_area_get_offset(dsc->blend_area, &draw_area); // source image offset in relation to draw_area + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, + -draw_ctx->buf_area->y1); // translate the screen draw area to the origin of the buffer area + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, dsc->src_buf, src_stride, &src_offset, dsc->opa, + LvglColorFormat, true); + } } } -void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx) +// Does dest_area = intersect(draw_ctx->clip_area, src_area) ? +// See: https://github.com/lvgl/lvgl/issues/3714#issuecomment-1331710788 +static void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, void * dest_buf, lv_coord_t dest_stride, + const lv_area_t * dest_area, void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area) +{ + // Both draw buffer start address and buffer size *must* be 32-byte aligned since draw buffer cache is being invalidated. + //uint32_t drawBufferLength = lv_area_get_size(draw_ctx->buf_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(drawBufferLength % CACHE_ROW_SIZE == 0); // critical, but this is not the way to test it + //LV_ASSERT_MSG((uint32_t)draw_ctx->buf % CACHE_ROW_SIZE == 0, "draw_ctx.buf is not 32B aligned"); // critical? + // FIXME: + // 1. Both src_buf and dest_buf pixel size *must* be known to use DMA2D. + // 2. Verify both buffers start addresses and lengths are 32-byte (cache row size) aligned. + LV_UNUSED(draw_ctx); + lv_point_t src_offset = lv_area_get_offset(src_area, dest_area); + // FIXME: use lv_area_move(dest_area, -dest_area->x1, -dest_area->y1) here ? + // TODO: It is assumed that dest_buf and src_buf buffers are of lv_color_t type. Verify it, this assumption may be incorrect. + _lv_draw_stm32_dma2d_blend_map((const lv_color_t *)dest_buf, dest_stride, dest_area, (const lv_color_t *)src_buf, + src_stride, &src_offset, 0xff, LvglColorFormat, true); + // TODO: Investigate if output buffer cache needs to be invalidated. It depends on what the destination buffer is and how it is used next - by dma2d or not. + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); // TODO: is this line needed here? +} + +static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t color_format) +{ + if(draw_ctx->draw_img_decoded == NULL) return; + lv_area_t draw_area; + lv_area_copy(&draw_area, draw_ctx->clip_area); + + bool mask_any = lv_draw_mask_is_any(&draw_area); + bool transform = img_dsc->angle != 0 || img_dsc->zoom != LV_IMG_ZOOM_NONE; + const dma2d_color_format_t bitmapColorFormat = lv_color_format_to_dma2d_color_format(color_format); + const bool ignoreBitmapAlpha = (color_format == LV_IMG_CF_RGBX8888); + + if(!mask_any && !transform && bitmapColorFormat != UNSUPPORTED && img_dsc->recolor_opa == LV_OPA_TRANSP) { + // simple bitmap blending, optionally with supported color format conversion - handle directly by dma2d + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + lv_coord_t src_stride = lv_area_get_width(coords); + lv_point_t src_offset = lv_area_get_offset(coords, &draw_area); // source image offset in relation to draw_area + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, src_buf, src_stride, &src_offset, + img_dsc->opa, bitmapColorFormat, ignoreBitmapAlpha); + } + else { + // all more complex cases which require additional image transformations + lv_draw_sw_img_decoded(draw_ctx, img_dsc, coords, src_buf, color_format); + + } +} + +static lv_point_t lv_area_get_offset(const lv_area_t * area1, const lv_area_t * area2) +{ + lv_point_t offset = {x: area2->x1 - area1->x1, y: area2->y1 - area1->y1}; + return offset; +} + +static dma2d_color_format_t lv_color_format_to_dma2d_color_format(lv_img_cf_t color_format) +{ + switch(color_format) { + case LV_IMG_CF_RGBA8888: + // note: LV_IMG_CF_RGBA8888 is actually ARGB8888 + return ARGB8888; + case LV_IMG_CF_RGBX8888: + // note: LV_IMG_CF_RGBX8888 is actually XRGB8888 + return ARGB8888; + case LV_IMG_CF_RGB565: + return RGB565; + case LV_IMG_CF_TRUE_COLOR: + return LvglColorFormat; + case LV_IMG_CF_TRUE_COLOR_ALPHA: +#if LV_COLOR_DEPTH == 16 + // bitmap color format is 24b ARGB8565 - dma2d unsupported + return UNSUPPORTED; +#elif LV_COLOR_DEPTH == 32 + return ARGB8888; +#else + // unknown bitmap color format + return UNSUPPORTED; +#endif + default: + return UNSUPPORTED; + } +} + +static lv_res_t lv_draw_stm32_dma2d_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * src_area, + const void * src) +{ + //if(lv_img_src_get_type(src) != LV_IMG_SRC_VARIABLE) return LV_RES_INV; + return LV_RES_INV; + if(img_dsc->opa <= LV_OPA_MIN) return LV_RES_OK; + const lv_img_dsc_t * img = src; + const dma2d_color_format_t bitmapColorFormat = lv_color_format_to_dma2d_color_format(img->header.cf); + const bool ignoreBitmapAlpha = (img->header.cf == LV_IMG_CF_RGBX8888); + + if(bitmapColorFormat == UNSUPPORTED || img_dsc->angle != 0 || img_dsc->zoom != LV_IMG_ZOOM_NONE) { + return LV_RES_INV; // sorry, dma2d can handle this + } + + // FIXME: handle dsc.pivot, dsc.recolor, dsc.blend_mode + // FIXME: src pixel size *must* be known to use DMA2D + // FIXME: If image is drawn by SW, then output cache needs to be cleaned next. Currently it is not possible. + // Both draw buffer start address and buffer size *must* be 32-byte aligned since draw buffer cache is being invalidated. + //uint32_t drawBufferLength = lv_area_get_size(draw_ctx->buf_area) * sizeof(lv_color_t); + //LV_ASSERT_MSG(drawBufferLength % CACHE_ROW_SIZE == 0); // critical, but this is not the way to test it + //LV_ASSERT_MSG((uint32_t)draw_ctx->buf % CACHE_ROW_SIZE == 0, "draw_ctx.buf is not 32B aligned"); // critical? + + // For performance reasons, both source buffer start address and buffer size *should* be 32-byte aligned since source buffer cache is being cleaned. + //uint32_t srcBufferLength = lv_area_get_size(src_area) * sizeof(lv_color_t); // TODO: verify src pixel size = sizeof(lv_color_t) + //LV_ASSERT_MSG(srcBufferLength % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + //LV_ASSERT_MSG((uint32_t)src % CACHE_ROW_SIZE == 0); // FIXME: assert fails (performance, non-critical) + + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, src_area, draw_ctx->clip_area)) return LV_RES_OK; + + lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); + lv_point_t src_offset = lv_area_get_offset(src_area, &draw_area); // source image offset in relation to draw_area + lv_area_move(&draw_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1); + _lv_draw_stm32_dma2d_blend_map(draw_ctx->buf, dest_stride, &draw_area, img->data, img->header.w, + &src_offset, img_dsc->opa, bitmapColorFormat, ignoreBitmapAlpha); + return LV_RES_OK; +} + +static void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver && disp->driver->wait_cb) { - while(DMA2D->CR & DMA2D_CR_START_Msk) { - disp->driver->wait_cb(disp->driver); - } - } - else { - while(DMA2D->CR & DMA2D_CR_START_Msk); - } + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(disp->driver); lv_draw_sw_wait_for_finish(draw_ctx); - } /********************** * STATIC FUNCTIONS **********************/ -static void invalidate_cache(void) +/** + * @brief Fills draw_area with specified color. + * @param color color to be painted, note: alpha is ignored + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_fill(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, lv_color_t color, lv_opa_t opa) { - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(disp->driver->clean_dcache_cb) disp->driver->clean_dcache_cb(disp->driver); - else { -#if __CORTEX_M >= 0x07 - if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk) - SCB_CleanInvalidateDCache(); + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + if(opa >= LV_OPA_MAX) { + DMA2D->CR = 0x3UL << DMA2D_CR_MODE_Pos; // Register-to-memory (no FG nor BG, only output stage active) + + DMA2D->OPFCCR = LvglColorFormat; +#if defined(DMA2D_OPFCCR_RBS_Pos) + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); #endif + DMA2D->OMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->OOR = dest_stride - draw_width; // out buffer offset + // Note: unlike FGCOLR and BGCOLR, OCOLR bits must match DMA2D_OUTPUT_COLOR, alpha can be specified +#if RBS_BIT + // swap red/blue bits + DMA2D->OCOLR = (color.ch.blue << 11) | (color.ch.green_l << 5 | color.ch.green_h << 8) | (color.ch.red); +#else + DMA2D->OCOLR = color.full; +#endif + } + else { + DMA2D->CR = 0x2UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with blending (FG and BG fetch with PFC and blending) + + DMA2D->FGPFCCR = A8; + DMA2D->FGPFCCR |= (opa << DMA2D_FGPFCCR_ALPHA_Pos); + // Alpha Mode 1: Replace original foreground image alpha channel value by FGPFCCR.ALPHA + DMA2D->FGPFCCR |= (0x1UL << DMA2D_FGPFCCR_AM_Pos); + //DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); + + // Note: in Alpha Mode 1 FGMAR and FGOR are not used to supply foreground A8 bytes, + // those bytes are replaced by constant ALPHA defined in FGPFCCR + DMA2D->FGMAR = (uint32_t)dest_buf; + DMA2D->FGOR = dest_stride; + DMA2D->FGCOLR = lv_color_to32(color) & 0x00ffffff; // swap FGCOLR R/B bits if FGPFCCR.RBS (RBS_BIT) bit is set + + DMA2D->BGPFCCR = LvglColorFormat; +#if defined(DMA2D_BGPFCCR_RBS_Pos) + DMA2D->BGPFCCR |= (RBS_BIT << DMA2D_BGPFCCR_RBS_Pos); +#endif + DMA2D->BGMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->BGOR = dest_stride - draw_width; + DMA2D->BGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->BGMAR, DMA2D->BGOR, draw_width, draw_height, sizeof(lv_color_t)); + + DMA2D->OPFCCR = LvglColorFormat; +#if defined(DMA2D_OPFCCR_RBS_Pos) + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); +#endif + DMA2D->OMAR = DMA2D->BGMAR; + DMA2D->OOR = DMA2D->BGOR; + DMA2D->OCOLR = 0; + } + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +/** + * @brief Draws src (foreground) map on dst (background) map. + * @param src_offset src offset in relation to dst, useful when src is larger than draw_area + * @param opa constant opacity to be applied + * @param bitmapColorCode bitmap color type + * @param ignoreAlpha if TRUE, bitmap src alpha channel is ignored + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_map(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const void * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset, lv_opa_t opa, + dma2d_color_format_t src_color_format, bool ignore_src_alpha) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + if(opa <= LV_OPA_MIN || src_color_format == UNSUPPORTED) return; + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + bool bitmapHasOpacity = !ignore_src_alpha && (src_color_format == ARGB8888 || src_color_format == ARGB1555 || + src_color_format == ARGB4444); + + if(opa >= LV_OPA_MAX) opa = 0xff; + + uint8_t srcBpp; // source bytes per pixel + switch(src_color_format) { + case ARGB8888: + srcBpp = 4; + break; + case RGB888: + srcBpp = 3; + break; + case RGB565: + case ARGB1555: + case ARGB4444: + srcBpp = 2; + break; + default: + LV_LOG_ERROR("unsupported color format"); + return; + } + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + DMA2D->FGPFCCR = src_color_format; + + if(opa == 0xff && !bitmapHasOpacity) { + // no need to blend + if(src_color_format == LvglColorFormat) { + // no need to convert pixel format (PFC) either + DMA2D->CR = 0x0UL; + } + else { + DMA2D->CR = 0x1UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with PFC (FG fetch only with FG PFC active) + } + // Alpha Mode 0: No modification of the foreground image alpha channel value + } + else { + // blend + DMA2D->CR = 0x2UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with blending (FG and BG fetch with PFC and blending) + DMA2D->FGPFCCR |= (opa << DMA2D_FGPFCCR_ALPHA_Pos); + if(bitmapHasOpacity) { + // Alpha Mode 2: Replace original foreground image alpha channel value by FGPFCCR.ALPHA multiplied with original alpha channel value + DMA2D->FGPFCCR |= (0x2UL << DMA2D_FGPFCCR_AM_Pos); + } + else { + // Alpha Mode 1: Replace original foreground image alpha channel value by FGPFCCR.ALPHA + DMA2D->FGPFCCR |= (0x1UL << DMA2D_FGPFCCR_AM_Pos); + } + } +#if defined(DMA2D_FGPFCCR_RBS_Pos) + DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); +#endif + DMA2D->FGMAR = ((uint32_t)src_buf) + srcBpp * ((src_stride * src_offset->y) + src_offset->x); + DMA2D->FGOR = src_stride - draw_width; + DMA2D->FGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->FGMAR, DMA2D->FGOR, draw_width, draw_height, srcBpp); + + DMA2D->OPFCCR = LvglColorFormat; +#if defined(DMA2D_OPFCCR_RBS_Pos) + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); +#endif + DMA2D->OMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->OOR = dest_stride - draw_width; + DMA2D->OCOLR = 0; + + if(opa != 0xff || bitmapHasOpacity) { + // use background (BG*) registers + DMA2D->BGPFCCR = LvglColorFormat; +#if defined(DMA2D_BGPFCCR_RBS_Pos) + DMA2D->BGPFCCR |= (RBS_BIT << DMA2D_BGPFCCR_RBS_Pos); +#endif + DMA2D->BGMAR = DMA2D->OMAR; + DMA2D->BGOR = DMA2D->OOR; + DMA2D->BGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->BGMAR, DMA2D->BGOR, draw_width, draw_height, sizeof(lv_color_t)); + } + + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +/** + * @brief Paints solid color with alpha mask with additional constant opacity. Useful e.g. for painting anti-aliased fonts. + * @param src_offset src offset in relation to dst, useful when src (alpha mask) is larger than draw_area + * @param color color to paint, note: alpha is ignored + * @param opa constant opacity to be applied + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_paint(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const lv_opa_t * mask_buf, lv_coord_t mask_stride, const lv_point_t * mask_offset, + lv_color_t color, lv_opa_t opa) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + DMA2D->CR = 0x2UL << DMA2D_CR_MODE_Pos; // Memory-to-memory with blending (FG and BG fetch with PFC and blending) + + DMA2D->FGPFCCR = A8; + if(opa < LV_OPA_MAX) { + DMA2D->FGPFCCR |= (opa << DMA2D_FGPFCCR_ALPHA_Pos); + DMA2D->FGPFCCR |= (0x2UL << + DMA2D_FGPFCCR_AM_Pos); // Alpha Mode: Replace original foreground image alpha channel value by FGPFCCR.ALPHA multiplied with original alpha channel value + } + //DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); + DMA2D->FGMAR = (uint32_t)(mask_buf + (mask_stride * mask_offset->y) + mask_offset->x); + DMA2D->FGOR = mask_stride - draw_width; + DMA2D->FGCOLR = lv_color_to32(color) & 0x00ffffff; // swap FGCOLR R/B bits if FGPFCCR.RBS (RBS_BIT) bit is set + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->FGMAR, DMA2D->FGOR, draw_width, draw_height, sizeof(lv_opa_t)); + + DMA2D->BGPFCCR = LvglColorFormat; +#if defined(DMA2D_BGPFCCR_RBS_Pos) + DMA2D->BGPFCCR |= (RBS_BIT << DMA2D_BGPFCCR_RBS_Pos); +#endif + DMA2D->BGMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->BGOR = dest_stride - draw_width; + DMA2D->BGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->BGMAR, DMA2D->BGOR, draw_width, draw_height, sizeof(lv_color_t)); + + DMA2D->OPFCCR = LvglColorFormat; +#if defined(DMA2D_OPFCCR_RBS_Pos) + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); +#endif + DMA2D->OMAR = DMA2D->BGMAR; + DMA2D->OOR = DMA2D->BGOR; + DMA2D->OCOLR = 0; + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +/** + * @brief Copies src (foreground) map to the dst (background) map. + * @param src_offset src offset in relation to dst, useful when src is larger than draw_area + */ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_copy_buffer(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const lv_color_t * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); // critical + lv_coord_t draw_width = lv_area_get_width(draw_area); + lv_coord_t draw_height = lv_area_get_height(draw_area); + + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); + + DMA2D->CR = 0x0UL; // Memory-to-memory (FG fetch only) + + DMA2D->FGPFCCR = LvglColorFormat; +#if defined(DMA2D_FGPFCCR_RBS_Pos) + DMA2D->FGPFCCR |= (RBS_BIT << DMA2D_FGPFCCR_RBS_Pos); +#endif + DMA2D->FGMAR = (uint32_t)(src_buf + (src_stride * src_offset->y) + src_offset->x); + DMA2D->FGOR = src_stride - draw_width; + DMA2D->FGCOLR = 0; // used in A4 and A8 modes only + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->FGMAR, DMA2D->FGOR, draw_width, draw_height, sizeof(lv_color_t)); + + // Note BG* registers do not need to be set up since BG is not used + + DMA2D->OPFCCR = LvglColorFormat; +#if defined(DMA2D_OPFCCR_RBS_Pos) + DMA2D->OPFCCR |= (RBS_BIT << DMA2D_OPFCCR_RBS_Pos); +#endif + DMA2D->OMAR = (uint32_t)(dest_buf + (dest_stride * draw_area->y1) + draw_area->x1); + DMA2D->OOR = dest_stride - draw_width; + DMA2D->OCOLR = 0; + + // PL - pixel per lines (14 bit), NL - number of lines (16 bit) + DMA2D->NLR = (draw_width << DMA2D_NLR_PL_Pos) | (draw_height << DMA2D_NLR_NL_Pos); + + _lv_gpu_stm32_dma2d_start_dma_transfer(); +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_start_dma_transfer(void) +{ + LV_ASSERT_MSG(!isDma2dInProgess, "dma2d transfer has not finished"); + isDma2dInProgess = true; + DMA2D->IFCR = 0x3FU; // trigger ISR flags reset + // Note: cleaning output buffer cache is needed only when buffer may be misaligned or adjacent area may have been drawn in sw-fashion, e.g. using lv_draw_sw_blend_basic() +#if LV_COLOR_DEPTH == 16 + _lv_gpu_stm32_dma2d_clean_cache(DMA2D->OMAR, DMA2D->OOR, (DMA2D->NLR & DMA2D_NLR_PL_Msk) >> DMA2D_NLR_PL_Pos, + (DMA2D->NLR & DMA2D_NLR_NL_Msk) >> DMA2D_NLR_NL_Pos, sizeof(lv_color_t)); +#endif + DMA2D->CR |= DMA2D_CR_START; + // Note: for some reason mask buffer gets damaged during transfer if waiting is postponed + _lv_gpu_stm32_dma2d_await_dma_transfer_finish(NULL); // FIXME: this line should not be needed here, but it is +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_await_dma_transfer_finish(lv_disp_drv_t * disp_drv) +{ + if(disp_drv && disp_drv->wait_cb) { + while((DMA2D->CR & DMA2D_CR_START) != 0U) { + disp_drv->wait_cb(disp_drv); + } + } + else { + while((DMA2D->CR & DMA2D_CR_START) != 0U); + } + + __IO uint32_t isrFlags = DMA2D->ISR; + + if(isrFlags & DMA2D_ISR_CEIF) { + LV_LOG_ERROR("DMA2D config error"); + } + + if(isrFlags & DMA2D_ISR_TEIF) { + LV_LOG_ERROR("DMA2D transfer error"); + } + + DMA2D->IFCR = 0x3FU; // trigger ISR flags reset + + if(isDma2dInProgess) { + // invalidate output buffer cached memory ONLY after DMA2D transfer + //_lv_gpu_stm32_dma2d_invalidate_cache(DMA2D->OMAR, DMA2D->OOR, (DMA2D->NLR & DMA2D_NLR_PL_Msk) >> DMA2D_NLR_PL_Pos, (DMA2D->NLR & DMA2D_NLR_NL_Msk) >> DMA2D_NLR_NL_Pos, sizeof(lv_color_t)); + isDma2dInProgess = false; } } +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_invalidate_cache(uint32_t address, lv_coord_t offset, lv_coord_t width, + lv_coord_t height, uint8_t pixel_size) +{ +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if(((SCB->CCR) & SCB_CCR_DC_Msk) == 0) return; // L1 data cache is disabled + uint16_t stride = pixel_size * (width + offset); // in bytes + uint16_t ll = pixel_size * width; // line length in bytes + uint32_t n = 0; // address of the next cache row after the last invalidated row + lv_coord_t h = 0; + + __DSB(); + + while(h < height) { + uint32_t a = address + (h * stride); + uint32_t e = a + ll; // end address, address of the first byte after the current line + a &= ~(CACHE_ROW_SIZE - 1U); + if(a < n) a = n; // prevent the previous last cache row from being invalidated again + + while(a < e) { + SCB->DCIMVAC = a; + a += CACHE_ROW_SIZE; + } + + n = a; + h++; + }; + + __DSB(); + __ISB(); +#endif +} + +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_clean_cache(uint32_t address, lv_coord_t offset, lv_coord_t width, + lv_coord_t height, uint8_t pixel_size) +{ +#if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) + if(((SCB->CCR) & SCB_CCR_DC_Msk) == 0) return; // L1 data cache is disabled + uint16_t stride = pixel_size * (width + offset); // in bytes + uint16_t ll = pixel_size * width; // line length in bytes + uint32_t n = 0; // address of the next cache row after the last cleaned row + lv_coord_t h = 0; + __DSB(); + + while(h < height) { + uint32_t a = address + (h * stride); + uint32_t e = a + ll; // end address, address of the first byte after the current line + a &= ~(CACHE_ROW_SIZE - 1U); + if(a < n) a = n; // prevent the previous last cache row from being cleaned again + + while(a < e) { + SCB->DCCMVAC = a; + a += CACHE_ROW_SIZE; + } + + n = a; + h++; + }; + + __DSB(); + __ISB(); +#endif +} + +// initialize µs timer +LV_STM32_DMA2D_STATIC bool _lv_gpu_stm32_dwt_init(void) +{ + // disable TRC + CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; + // enable TRC + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + +#if defined(__CORTEX_M) && (__CORTEX_M == 7U) + DWT->LAR = 0xC5ACCE55; +#endif + // disable clock cycle counter + DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; + // enable clock cycle counter + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + + // reset the clock cycle counter value + DWT->CYCCNT = 0; + + // 3 NO OPERATION instructions + __ASM volatile("NOP"); + __ASM volatile("NOP"); + __ASM volatile("NOP"); + + // check if clock cycle counter has started + if(DWT->CYCCNT) { + return true; // clock cycle counter started + } + else { + return false; // clock cycle counter not started + } +} + +// get elapsed µs since reset +LV_STM32_DMA2D_STATIC uint32_t _lv_gpu_stm32_dwt_get_us(void) +{ + uint32_t us = (DWT->CYCCNT * 1000000) / HAL_RCC_GetHCLKFreq(); + return us; +} + +// reset µs timer +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dwt_reset(void) +{ + DWT->CYCCNT = 0; +} + #endif diff --git a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h index fa7070e2a..5ecce6deb 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h +++ b/lib/libesp32_lvgl/lvgl/src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.h @@ -10,52 +10,83 @@ extern "C" { #endif -/********************* - * INCLUDES - *********************/ #include "../../misc/lv_color.h" #include "../../hal/lv_hal_disp.h" #include "../sw/lv_draw_sw.h" #if LV_USE_GPU_STM32_DMA2D +/********************* + * INCLUDES + *********************/ +#include LV_GPU_DMA2D_CMSIS_INCLUDE + /********************* * DEFINES *********************/ - -#define LV_DMA2D_ARGB8888 0 -#define LV_DMA2D_RGB888 1 -#define LV_DMA2D_RGB565 2 -#define LV_DMA2D_ARGB1555 3 -#define LV_DMA2D_ARGB4444 4 +#if defined(LV_STM32_DMA2D_TEST) +// removes "static" modifier for some internal methods in order to test them +#define LV_STM32_DMA2D_STATIC +#else +#define LV_STM32_DMA2D_STATIC static +#endif /********************** * TYPEDEFS **********************/ +enum dma2d_color_format { + ARGB8888 = 0x0, + RGB888 = 0x01, + RGB565 = 0x02, + ARGB1555 = 0x03, + ARGB4444 = 0x04, + A8 = 0x09, + UNSUPPORTED = 0xff, +}; +typedef enum dma2d_color_format dma2d_color_format_t; typedef lv_draw_sw_ctx_t lv_draw_stm32_dma2d_ctx_t; - struct _lv_disp_drv_t; /********************** * GLOBAL PROTOTYPES **********************/ - -/** - * Turn on the peripheral and set output color mode, this only needs to be done once - */ void lv_draw_stm32_dma2d_init(void); - void lv_draw_stm32_dma2d_ctx_init(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); - void lv_draw_stm32_dma2d_ctx_deinit(struct _lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx); +static void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); +static void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, + void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, + void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); +static lv_res_t lv_draw_stm32_dma2d_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * src_area, const void * src); +static void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); +static void lv_draw_stm32_dma2d_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * img_dsc, + const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t color_format); +static dma2d_color_format_t lv_color_format_to_dma2d_color_format(lv_img_cf_t color_format); +static lv_point_t lv_area_get_offset(const lv_area_t * area1, const lv_area_t * area2); -void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc); - -void lv_draw_stm32_dma2d_buffer_copy(lv_draw_ctx_t * draw_ctx, - void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area, - void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area); - -void lv_gpu_stm32_dma2d_wait_cb(lv_draw_ctx_t * draw_ctx); +/********************** + * STATIC PROTOTYPES + **********************/ +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_fill(const lv_color_t * dst_buf, lv_coord_t dst_stride, + const lv_area_t * draw_area, lv_color_t color, lv_opa_t opa); +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_map(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const void * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset, lv_opa_t opa, + dma2d_color_format_t src_color_format, bool ignore_src_alpha); +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_blend_paint(const lv_color_t * dst_buf, lv_coord_t dst_stride, + const lv_area_t * draw_area, const lv_opa_t * mask_buf, lv_coord_t mask_stride, const lv_point_t * mask_offset, + lv_color_t color, lv_opa_t opa); +LV_STM32_DMA2D_STATIC void _lv_draw_stm32_dma2d_copy_buffer(const lv_color_t * dest_buf, lv_coord_t dest_stride, + const lv_area_t * draw_area, const lv_color_t * src_buf, lv_coord_t src_stride, const lv_point_t * src_offset); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_await_dma_transfer_finish(lv_disp_drv_t * disp_drv); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_start_dma_transfer(void); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_invalidate_cache(uint32_t address, lv_coord_t offset, + lv_coord_t width, lv_coord_t height, uint8_t pixel_size); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dma2d_clean_cache(uint32_t address, lv_coord_t offset, lv_coord_t width, + lv_coord_t height, uint8_t pixel_size); +LV_STM32_DMA2D_STATIC bool _lv_gpu_stm32_dwt_init(void); +LV_STM32_DMA2D_STATIC void _lv_gpu_stm32_dwt_reset(void); +LV_STM32_DMA2D_STATIC uint32_t _lv_gpu_stm32_dwt_get_us(void); /********************** * MACROS diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c index 428aba62c..bff0a8f19 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_blend.c @@ -103,7 +103,7 @@ void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * d LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc) { - const lv_opa_t * mask; + lv_opa_t * mask; if(dsc->mask_buf == NULL) mask = NULL; if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return; else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL; @@ -129,7 +129,6 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons } } - const lv_color_t * src_buf = dsc->src_buf; lv_coord_t src_stride; if(src_buf) { @@ -142,8 +141,18 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, cons lv_coord_t mask_stride; if(mask) { + /*Round the values in the mask if anti-aliasing is disabled*/ + if(disp->driver->antialiasing == 0) { + int32_t mask_size = lv_area_get_size(dsc->mask_area); + int32_t i; + for(i = 0; i < mask_size; i++) { + mask[i] = mask[i] > 128 ? LV_OPA_COVER : LV_OPA_TRANSP; + } + } + mask_stride = lv_area_get_width(dsc->mask_area); mask += mask_stride * (blend_area.y1 - dsc->mask_area->y1) + (blend_area.x1 - dsc->mask_area->x1); + } else { mask_stride = 0; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c index 9522888c9..7caa74912 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_letter.c @@ -489,8 +489,8 @@ static void draw_letter_subpx(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_ #endif #if LV_FONT_SUBPX_BGR - res_color.ch.blue = (uint32_t)((uint32_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; - res_color.ch.red = (uint32_t)((uint32_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; + res_color.ch.red = (uint32_t)((uint16_t)txt_rgb[0] * font_rgb[2] + (bg_rgb[0] * (255 - font_rgb[2]))) >> 8; + res_color.ch.blue = (uint32_t)((uint16_t)txt_rgb[2] * font_rgb[0] + (bg_rgb[2] * (255 - font_rgb[0]))) >> 8; #else res_color.ch.red = (uint32_t)((uint16_t)txt_rgb[0] * font_rgb[0] + (bg_rgb[0] * (255 - font_rgb[0]))) >> 8; res_color.ch.blue = (uint32_t)((uint16_t)txt_rgb[2] * font_rgb[2] + (bg_rgb[2] * (255 - font_rgb[2]))) >> 8; diff --git a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c index 80b1e6dea..204503a4f 100644 --- a/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c +++ b/lib/libesp32_lvgl/lvgl/src/draw/sw/lv_draw_sw_transform.c @@ -122,8 +122,8 @@ void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, xs_step_256 = (256 * xs_diff) / (dest_w - 1); ys_step_256 = (256 * ys_diff) / (dest_w - 1); } - int32_t xs_ups = xs1_ups; - int32_t ys_ups = ys1_ups; + int32_t xs_ups = xs1_ups + 0x80; + int32_t ys_ups = ys1_ups + 0x80; if(draw_dsc->antialias == 0) { switch(cf) { @@ -180,7 +180,7 @@ static void rgb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, l } else { -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 const uint8_t * src_tmp = src; src_tmp += ys_int * src_stride + xs_int; cbuf[x].full = src_tmp[0]; @@ -221,7 +221,7 @@ static void argb_no_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t src_h, const uint8_t * src_tmp = src; src_tmp += (ys_int * src_stride * LV_IMG_PX_SIZE_ALPHA_BYTE) + xs_int * LV_IMG_PX_SIZE_ALPHA_BYTE; -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 cbuf[x].full = src_tmp[0]; #elif LV_COLOR_DEPTH == 16 cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8); @@ -396,7 +396,7 @@ static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t sr if(abuf[x] == 0x00) continue; -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 c_base.full = px_base[0]; c_ver.full = px_ver[0]; c_hor.full = px_hor[0]; @@ -429,7 +429,7 @@ static void argb_and_rgb_aa(const uint8_t * src, lv_coord_t src_w, lv_coord_t sr } /*Partially out of the image*/ else { -#if LV_COLOR_DEPTH == 8 +#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8 cbuf[x].full = src_tmp[0]; #elif LV_COLOR_DEPTH == 16 cbuf[x].full = src_tmp[0] + (src_tmp[1] << 8); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c b/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c index 405a56b7f..a53c95e88 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/layouts/flex/lv_flex.c @@ -470,8 +470,14 @@ static void children_repos(lv_obj_t * cont, flex_t * f, int32_t item_first_id, i } } - if(f->row) item->w_layout = 1; - else item->h_layout = 1; + if(f->row) { + item->w_layout = 1; + item->h_layout = 0; + } + else { + item->h_layout = 1; + item->w_layout = 0; + } if(s != area_get_main_size(&item->coords)) { lv_obj_invalidate(item); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/libs/fsdrv/lv_fs_posix.c b/lib/libesp32_lvgl/lvgl/src/extra/libs/fsdrv/lv_fs_posix.c index f988daeeb..e656288d3 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/libs/fsdrv/lv_fs_posix.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/libs/fsdrv/lv_fs_posix.c @@ -104,15 +104,15 @@ static void * fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mode) LV_UNUSED(drv); uint32_t flags = 0; - if(mode == LV_FS_MODE_WR) flags = O_WRONLY; + if(mode == LV_FS_MODE_WR) flags = O_WRONLY | O_CREAT; else if(mode == LV_FS_MODE_RD) flags = O_RDONLY; - else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = O_RDWR; + else if(mode == (LV_FS_MODE_WR | LV_FS_MODE_RD)) flags = O_RDWR | O_CREAT; /*Make the path relative to the current directory (the projects root folder)*/ char buf[256]; lv_snprintf(buf, sizeof(buf), LV_FS_POSIX_PATH "%s", path); - int f = open(buf, flags); + int f = open(buf, flags, 0666); if(f < 0) return NULL; return (void *)(lv_uintptr_t)f; diff --git a/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.c b/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.c index 68f50057e..3ee9b7194 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.c @@ -160,6 +160,7 @@ static gd_GIF * gif_open(gd_GIF * gif_base) #endif } gif->anim_start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR); + gif->loop_count = -1; goto ok; fail: f_gif_close(gif_base); @@ -239,6 +240,7 @@ read_application_ext(gd_GIF *gif) { char app_id[8]; char app_auth_code[3]; + uint16_t loop_count; /* Discard block size (always 0x0B). */ f_gif_seek(gif, 1, LV_FS_SEEK_CUR); @@ -249,7 +251,15 @@ read_application_ext(gd_GIF *gif) if (!strncmp(app_id, "NETSCAPE", sizeof(app_id))) { /* Discard block size (0x03) and constant byte (0x01). */ f_gif_seek(gif, 2, LV_FS_SEEK_CUR); - gif->loop_count = read_num(gif); + loop_count = read_num(gif); + if(gif->loop_count < 0) { + if(loop_count == 0) { + gif->loop_count = 0; + } + else{ + gif->loop_count = loop_count + 1; + } + } /* Skip block terminator. */ f_gif_seek(gif, 1, LV_FS_SEEK_CUR); } else if (gif->application) { @@ -568,9 +578,16 @@ gd_get_frame(gd_GIF *gif) dispose(gif); f_gif_read(gif, &sep, 1); while (sep != ',') { - if (sep == ';') - return 0; - if (sep == '!') + if (sep == ';') { + f_gif_seek(gif, gif->anim_start, LV_FS_SEEK_SET); + if(gif->loop_count == 1 || gif->loop_count < 0) { + return 0; + } + else if(gif->loop_count > 1) { + gif->loop_count--; + } + } + else if (sep == '!') read_ext(gif); else return -1; f_gif_read(gif, &sep, 1); @@ -598,6 +615,7 @@ gd_render_frame(gd_GIF *gif, uint8_t *buffer) void gd_rewind(gd_GIF *gif) { + gif->loop_count = -1; f_gif_seek(gif, gif->anim_start, LV_FS_SEEK_SET); } diff --git a/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.h b/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.h index 00f17c1da..b68fab5d4 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.h +++ b/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/gifdec.h @@ -29,7 +29,7 @@ typedef struct gd_GIF { int32_t anim_start; uint16_t width, height; uint16_t depth; - uint16_t loop_count; + int32_t loop_count; gd_GCE gce; gd_Palette *palette; gd_Palette lct, gct; diff --git a/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/lv_gif.c b/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/lv_gif.c index 4cb2955e2..2bd9e013c 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/lv_gif.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/libs/gif/lv_gif.c @@ -99,6 +99,8 @@ void lv_gif_restart(lv_obj_t * obj) { lv_gif_t * gifobj = (lv_gif_t *) obj; gd_rewind(gifobj->gif); + lv_timer_resume(gifobj->timer); + lv_timer_reset(gifobj->timer); } /********************** @@ -111,6 +113,7 @@ static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) lv_gif_t * gifobj = (lv_gif_t *) obj; + gifobj->gif = NULL; gifobj->timer = lv_timer_create(next_frame_task_cb, 10, obj); lv_timer_pause(gifobj->timer); } @@ -120,7 +123,8 @@ static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) LV_UNUSED(class_p); lv_gif_t * gifobj = (lv_gif_t *) obj; lv_img_cache_invalidate_src(&gifobj->imgdsc); - gd_close_gif(gifobj->gif); + if(gifobj->gif) + gd_close_gif(gifobj->gif); lv_timer_del(gifobj->timer); } @@ -136,14 +140,9 @@ static void next_frame_task_cb(lv_timer_t * t) int has_next = gd_get_frame(gifobj->gif); if(has_next == 0) { /*It was the last repeat*/ - if(gifobj->gif->loop_count == 1) { - lv_res_t res = lv_event_send(obj, LV_EVENT_READY, NULL); - if(res != LV_FS_RES_OK) return; - } - else { - if(gifobj->gif->loop_count > 1) gifobj->gif->loop_count--; - gd_rewind(gifobj->gif); - } + lv_res_t res = lv_event_send(obj, LV_EVENT_READY, NULL); + lv_timer_pause(t); + if(res != LV_FS_RES_OK) return; } gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c b/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c index 4eec637bd..505a977b8 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/others/gridnav/lv_gridnav.c @@ -217,6 +217,7 @@ static void gridnav_event_cb(lv_event_t * e) if(dsc->focused_obj == NULL) dsc->focused_obj = find_first_focusable(obj); if(dsc->focused_obj) { lv_obj_add_state(dsc->focused_obj, LV_STATE_FOCUSED | LV_STATE_FOCUS_KEY); + lv_obj_clear_state(dsc->focused_obj, LV_STATE_PRESSED); /*Be sure the focuses obj is not stuck in pressed state*/ lv_obj_scroll_to_view(dsc->focused_obj, LV_ANIM_OFF); } } diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.c b/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.c old mode 100755 new mode 100644 diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.h b/lib/libesp32_lvgl/lvgl/src/extra/others/monkey/lv_monkey.h old mode 100755 new mode 100644 diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.c b/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.c index 8fd434d06..d54279c08 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.c @@ -94,6 +94,25 @@ void lv_msg_unsubscribe(void * s) lv_mem_free(s); } +uint32_t lv_msg_unsubscribe_obj(uint32_t msg_id, lv_obj_t * obj) +{ + uint32_t cnt = 0; + sub_dsc_t * s = _lv_ll_get_head(&subs_ll); + while(s) { + sub_dsc_t * s_next = _lv_ll_get_next(&subs_ll, s); + if(s->callback == obj_notify_cb && + (s->msg_id == LV_MSG_ID_ANY || s->msg_id == msg_id) && + (obj == NULL || s->_priv_data == obj)) { + lv_msg_unsubscribe(s); + cnt++; + } + + s = s_next; + } + + return cnt; +} + void lv_msg_send(uint32_t msg_id, const void * payload) { lv_msg_t m; @@ -129,8 +148,6 @@ lv_msg_t * lv_event_get_msg(lv_event_t * e) } } - - /********************** * STATIC FUNCTIONS **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h b/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h index 11a55b5a7..0ac2f77d5 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h +++ b/lib/libesp32_lvgl/lvgl/src/extra/others/msg/lv_msg.h @@ -19,6 +19,8 @@ extern "C" { /********************* * DEFINES *********************/ +#define LV_MSG_ID_ANY UINT32_MAX +LV_EXPORT_CONST_INT(LV_MSG_ID_ANY); /********************** * TYPEDEFS @@ -70,6 +72,14 @@ void * lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data); */ void lv_msg_unsubscribe(void * s); +/** + * Unsubscribe an object from a message ID + * @param msg_id the message ID to unsubcribe from or `LV_MSG_ID_ANY` for any message ID + * @param obj the object to unsubscribe or NULL for any object + * @return number of unsubscriptions + */ +uint32_t lv_msg_unsubscribe_obj(uint32_t msg_id, lv_obj_t * obj); + /** * Send a message with a given ID and payload * @param msg_id ID of the message to send @@ -105,6 +115,17 @@ void * lv_msg_get_user_data(lv_msg_t * m); */ lv_msg_t * lv_event_get_msg(lv_event_t * e); +/*Fix typo*/ +static inline void * lv_msg_subscribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void * user_data) +{ + return lv_msg_subsribe(msg_id, cb, user_data); +} + +static inline void * lv_msg_subscribe_obj(uint32_t msg_id, lv_obj_t * obj, void * user_data) +{ + return lv_msg_subsribe_obj(msg_id, obj, user_data); +} + /********************** * GLOBAL VARIABLES **********************/ diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c index 135a8a4ba..072d02e05 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.c @@ -64,7 +64,7 @@ lv_obj_t * lv_animimg_create(lv_obj_t * parent) return obj; } -void lv_animimg_set_src(lv_obj_t * obj, lv_img_dsc_t * dsc[], uint8_t num) +void lv_animimg_set_src(lv_obj_t * obj, const void * dsc[], uint8_t num) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_animimg_t * animimg = (lv_animimg_t *)obj; diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h index 632949477..0ba01f239 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/animimg/lv_animimg.h @@ -37,7 +37,7 @@ typedef struct { lv_img_t img; lv_anim_t anim; /*picture sequence */ - lv_img_dsc_t ** dsc; + const void ** dsc; int8_t pic_count; } lv_animimg_t; @@ -69,7 +69,7 @@ lv_obj_t * lv_animimg_create(lv_obj_t * parent); * @param dsc pointer to a series images * @param num images' number */ -void lv_animimg_set_src(lv_obj_t * img, lv_img_dsc_t * dsc[], uint8_t num); +void lv_animimg_set_src(lv_obj_t * img, const void * dsc[], uint8_t num); /** * Startup the image animation. diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c b/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c index da6c18c0e..c5afb8b94 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/chart/lv_chart.c @@ -1182,7 +1182,6 @@ static void draw_series_bar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) const lv_area_t * clip_area_ori = draw_ctx->clip_area; draw_ctx->clip_area = &clip_area; - lv_chart_t * chart = (lv_chart_t *)obj; uint16_t i; @@ -1200,6 +1199,7 @@ static void draw_series_bar(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx) int32_t ser_gap = ((int32_t)lv_obj_get_style_pad_column(obj, LV_PART_ITEMS) * chart->zoom_x) >> 8; /*Gap between the columns on the ~same X*/ lv_coord_t col_w = (block_w - (ser_cnt - 1) * ser_gap) / ser_cnt; + if(col_w < 1) col_w = 1; lv_coord_t border_w = lv_obj_get_style_border_width(obj, LV_PART_MAIN); lv_coord_t x_ofs = pad_left - lv_obj_get_scroll_left(obj) + border_w; @@ -1531,16 +1531,16 @@ static void draw_x_ticks(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_chart_axis lv_coord_t label_gap; if(axis == LV_CHART_AXIS_PRIMARY_X) { label_gap = t->label_en ? lv_obj_get_style_pad_bottom(obj, LV_PART_TICKS) : 0; - y_ofs = obj->coords.y2; + y_ofs = obj->coords.y2 + 1; } else { label_gap = t->label_en ? lv_obj_get_style_pad_top(obj, LV_PART_TICKS) : 0; - y_ofs = obj->coords.y1; + y_ofs = obj->coords.y1 - 1; } if(axis == LV_CHART_AXIS_PRIMARY_X) { if(y_ofs > draw_ctx->clip_area->y2) return; - if(y_ofs + label_gap + label_dsc.font->line_height + t->major_len < draw_ctx->clip_area->y1) return; + if(y_ofs + label_gap + label_dsc.font->line_height + t->major_len < draw_ctx->clip_area->y1) return; } lv_draw_line_dsc_t line_dsc; @@ -1634,7 +1634,6 @@ static void draw_x_ticks(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_chart_axis lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); } - if(p1.x + line_dsc.width / 2 >= obj->coords.x1 && p2.x - line_dsc.width / 2 <= obj->coords.x2) { lv_draw_line(draw_ctx, &line_dsc, &p1, &p2); diff --git a/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c b/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c index 668ab97e9..1e651b572 100644 --- a/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c +++ b/lib/libesp32_lvgl/lvgl/src/extra/widgets/meter/lv_meter.c @@ -612,6 +612,7 @@ static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area if(angle > 3600) angle -= 3600; img_dsc.angle = angle; + part_draw_dsc.id = LV_METER_DRAW_PART_NEEDLE_IMG; part_draw_dsc.img_dsc = &img_dsc; lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc); diff --git a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c index 0dd8f6b30..10640a28a 100644 --- a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c +++ b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_disp.c @@ -23,9 +23,8 @@ #include "../draw/stm32_dma2d/lv_gpu_stm32_dma2d.h" #include "../draw/swm341_dma2d/lv_gpu_swm341_dma2d.h" #include "../draw/arm2d/lv_gpu_arm2d.h" -#if LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE - #include "../draw/nxp/lv_gpu_nxp.h" -#endif +#include "../draw/nxp/vglite/lv_draw_vglite.h" +#include "../draw/nxp/pxp/lv_draw_pxp.h" #if LV_USE_THEME_DEFAULT #include "../extra/themes/default/lv_theme_default.h" @@ -105,10 +104,14 @@ void lv_disp_drv_init(lv_disp_drv_t * driver) driver->draw_ctx_init = lv_draw_swm341_dma2d_ctx_init; driver->draw_ctx_deinit = lv_draw_swm341_dma2d_ctx_init; driver->draw_ctx_size = sizeof(lv_draw_swm341_dma2d_ctx_t); -#elif LV_USE_GPU_NXP_PXP || LV_USE_GPU_NXP_VG_LITE - driver->draw_ctx_init = lv_draw_nxp_ctx_init; - driver->draw_ctx_deinit = lv_draw_nxp_ctx_deinit; - driver->draw_ctx_size = sizeof(lv_draw_nxp_ctx_t); +#elif LV_USE_GPU_NXP_VG_LITE + driver->draw_ctx_init = lv_draw_vglite_ctx_init; + driver->draw_ctx_deinit = lv_draw_vglite_ctx_deinit; + driver->draw_ctx_size = sizeof(lv_draw_vglite_ctx_t); +#elif LV_USE_GPU_NXP_PXP + driver->draw_ctx_init = lv_draw_pxp_ctx_init; + driver->draw_ctx_deinit = lv_draw_pxp_ctx_deinit; + driver->draw_ctx_size = sizeof(lv_draw_pxp_ctx_t); #elif LV_USE_GPU_SDL driver->draw_ctx_init = lv_draw_sdl_init_ctx; driver->draw_ctx_deinit = lv_draw_sdl_deinit_ctx; diff --git a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h index ca51a08c2..5bbcf530e 100644 --- a/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h +++ b/lib/libesp32_lvgl/lvgl/src/hal/lv_hal_indev.h @@ -141,6 +141,7 @@ typedef struct _lv_indev_proc_t { struct { /*Pointer and button data*/ lv_point_t act_point; /**< Current point of input device.*/ + lv_point_t indev_point; lv_point_t last_point; /**< Last point of input device.*/ lv_point_t last_raw_point; /**< Last point read from read_cb. */ lv_point_t vect; /**< Difference between `act_point` and `last_point`.*/ diff --git a/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h b/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h index 97807fe37..4cd3895f2 100644 --- a/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h +++ b/lib/libesp32_lvgl/lvgl/src/lv_conf_internal.h @@ -253,6 +253,9 @@ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ #endif #endif + /*If using lvgl as ESP32 component*/ + // #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h" + // #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL)) #endif /*LV_TICK_CUSTOM*/ /*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings. @@ -432,7 +435,7 @@ #endif #if LV_USE_GPU_STM32_DMA2D /*Must be defined to include path of CMSIS header of target processor - e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ + e.g. "stm32f7xx.h" or "stm32f4xx.h"*/ #ifndef LV_GPU_DMA2D_CMSIS_INCLUDE #ifdef CONFIG_LV_GPU_DMA2D_CMSIS_INCLUDE #define LV_GPU_DMA2D_CMSIS_INCLUDE CONFIG_LV_GPU_DMA2D_CMSIS_INCLUDE diff --git a/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h b/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h index 1792dae88..5cf0b19c1 100644 --- a/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h +++ b/lib/libesp32_lvgl/lvgl/src/misc/lv_style.h @@ -70,11 +70,6 @@ LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE); #endif // *INDENT-ON* -/** On simple system, don't waste resources on gradients */ -#if !defined(LV_DRAW_COMPLEX) || !defined(LV_GRADIENT_MAX_STOPS) -#define LV_GRADIENT_MAX_STOPS 2 -#endif - #define LV_STYLE_PROP_META_INHERIT 0x8000 #define LV_STYLE_PROP_META_INITIAL 0x4000 #define LV_STYLE_PROP_META_MASK (LV_STYLE_PROP_META_INHERIT | LV_STYLE_PROP_META_INITIAL) diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_arc.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_arc.c index 6cab5f339..848c20a72 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_arc.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_arc.c @@ -39,6 +39,7 @@ static void get_center(const lv_obj_t * obj, lv_point_t * center, lv_coord_t * a static lv_coord_t get_angle(const lv_obj_t * obj); static void get_knob_area(lv_obj_t * arc, const lv_point_t * center, lv_coord_t r, lv_area_t * knob_area); static void value_update(lv_obj_t * arc); +static lv_coord_t knob_get_extra_size(lv_obj_t * obj); /********************** * STATIC VARIABLES @@ -600,8 +601,11 @@ static void lv_arc_event(const lv_obj_class_t * class_p, lv_event_t * e) lv_coord_t knob_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_KNOB); lv_coord_t knob_pad = LV_MAX4(knob_left, knob_right, knob_top, knob_bottom) + 2; + lv_coord_t knob_extra_size = knob_pad - bg_pad; + knob_extra_size += knob_get_extra_size(obj); + lv_coord_t * s = lv_event_get_param(e); - *s = LV_MAX(*s, knob_pad - bg_pad); + *s = LV_MAX(*s, knob_extra_size); } else if(code == LV_EVENT_DRAW_MAIN) { lv_arc_draw(e); @@ -716,6 +720,7 @@ static void inv_arc_area(lv_obj_t * obj, uint16_t start_angle, uint16_t end_angl lv_area_t inv_area; lv_draw_arc_get_area(c.x, c.y, r, start_angle, end_angle, w, rounded, &inv_area); + lv_obj_invalidate_area(obj, &inv_area); } @@ -727,6 +732,13 @@ static void inv_knob_area(lv_obj_t * obj) lv_area_t a; get_knob_area(obj, &c, r, &a); + + lv_coord_t knob_extra_size = knob_get_extra_size(obj); + + if(knob_extra_size > 0) { + lv_area_increase(&a, knob_extra_size, knob_extra_size); + } + lv_obj_invalidate_area(obj, &a); } @@ -841,4 +853,19 @@ static void value_update(lv_obj_t * obj) arc->last_angle = angle; /*Cache angle for slew rate limiting*/ } +static lv_coord_t knob_get_extra_size(lv_obj_t * obj) +{ + lv_coord_t knob_shadow_size = 0; + knob_shadow_size += lv_obj_get_style_shadow_width(obj, LV_PART_KNOB); + knob_shadow_size += lv_obj_get_style_shadow_spread(obj, LV_PART_KNOB); + knob_shadow_size += LV_ABS(lv_obj_get_style_shadow_ofs_x(obj, LV_PART_KNOB)); + knob_shadow_size += LV_ABS(lv_obj_get_style_shadow_ofs_y(obj, LV_PART_KNOB)); + + lv_coord_t knob_outline_size = 0; + knob_outline_size += lv_obj_get_style_outline_width(obj, LV_PART_KNOB); + knob_outline_size += lv_obj_get_style_outline_pad(obj, LV_PART_KNOB); + + return LV_MAX(knob_shadow_size, knob_outline_size); +} + #endif diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_bar.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_bar.c index 0da2a9875..a057618ec 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_bar.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_bar.c @@ -571,6 +571,8 @@ static void lv_bar_set_value_with_anim(lv_obj_t * obj, int32_t new_value, int32_ _lv_bar_anim_t * anim_info, lv_anim_enable_t en) { if(en == LV_ANIM_OFF) { + lv_anim_del(anim_info, NULL); + anim_info->anim_state = LV_BAR_ANIM_STATE_INV; *value_ptr = new_value; lv_obj_invalidate((lv_obj_t *)obj); } diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_img.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_img.c index f47a789e7..3246e4a69 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_img.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_img.c @@ -166,8 +166,6 @@ void lv_img_set_offset_x(lv_obj_t * obj, lv_coord_t x) lv_img_t * img = (lv_img_t *)obj; - x = x % img->w; - img->offset.x = x; lv_obj_invalidate(obj); } @@ -178,15 +176,14 @@ void lv_img_set_offset_y(lv_obj_t * obj, lv_coord_t y) lv_img_t * img = (lv_img_t *)obj; - y = y % img->h; - img->offset.y = y; lv_obj_invalidate(obj); } void lv_img_set_angle(lv_obj_t * obj, int16_t angle) { - if(angle < 0 || angle >= 3600) angle = angle % 3600; + while(angle >= 3600) angle -= 3600; + while(angle < 0) angle += 3600; lv_img_t * img = (lv_img_t *)obj; if(angle == img->angle) return; @@ -659,12 +656,14 @@ static void draw_img(lv_event_t * e) draw_ctx->clip_area = &img_clip_area; lv_area_t coords_tmp; - coords_tmp.y1 = img_max_area.y1 + img->offset.y; + lv_coord_t offset_x = img->offset.x % img->w; + lv_coord_t offset_y = img->offset.y % img->h; + coords_tmp.y1 = img_max_area.y1 + offset_y; if(coords_tmp.y1 > img_max_area.y1) coords_tmp.y1 -= img->h; coords_tmp.y2 = coords_tmp.y1 + img->h - 1; for(; coords_tmp.y1 < img_max_area.y2; coords_tmp.y1 += img_size_final.y, coords_tmp.y2 += img_size_final.y) { - coords_tmp.x1 = img_max_area.x1 + img->offset.x; + coords_tmp.x1 = img_max_area.x1 + offset_x; if(coords_tmp.x1 > img_max_area.x1) coords_tmp.x1 -= img->w; coords_tmp.x2 = coords_tmp.x1 + img->w - 1; diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c index fd9b3948f..f79e88274 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_roller.c @@ -477,6 +477,7 @@ static void draw_main(lv_event_t * e) area_ok = _lv_area_intersect(&mask_sel, draw_ctx->clip_area, &sel_area); if(area_ok) { lv_obj_t * label = get_label(obj); + if(lv_label_get_recolor(label)) label_dsc.flag |= LV_TEXT_FLAG_RECOLOR; /*Get the size of the "selected text"*/ lv_point_t res_p; @@ -529,6 +530,8 @@ static void draw_label(lv_event_t * e) lv_draw_label_dsc_t label_draw_dsc; lv_draw_label_dsc_init(&label_draw_dsc); lv_obj_init_draw_label_dsc(roller, LV_PART_MAIN, &label_draw_dsc); + if(lv_label_get_recolor(label_obj)) label_draw_dsc.flag |= LV_TEXT_FLAG_RECOLOR; + lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); /*If the roller has shadow or outline it has some ext. draw size diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_slider.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_slider.c index 3f85efc28..98711da40 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_slider.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_slider.c @@ -239,8 +239,12 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e) new_value = LV_CLAMP(real_min_value, new_value, real_max_value); if(*slider->value_to_set != new_value) { - *slider->value_to_set = new_value; - lv_obj_invalidate(obj); + if(slider->value_to_set == &slider->bar.start_value) { + lv_bar_set_start_value(obj, new_value, LV_ANIM_ON); + } + else { + lv_bar_set_value(obj, new_value, LV_ANIM_ON); + } res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); if(res != LV_RES_OK) return; } diff --git a/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c b/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c index 5ff65ab23..f789e8d33 100644 --- a/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c +++ b/lib/libesp32_lvgl/lvgl/src/widgets/lv_table.c @@ -42,6 +42,7 @@ static lv_res_t get_pressed_cell(lv_obj_t * obj, uint16_t * row, uint16_t * col) static size_t get_cell_txt_len(const char * txt); static void copy_cell_txt(char * dst, const char * txt); static void get_cell_area(lv_obj_t * obj, uint16_t row, uint16_t col, lv_area_t * area); +static void scroll_to_selected_cell(lv_obj_t * obj); static inline bool is_cell_empty(void * cell) { @@ -516,6 +517,7 @@ static void lv_table_event(const lv_obj_class_t * class_p, lv_event_t * e) if(col == LV_TABLE_CELL_NONE || row == LV_TABLE_CELL_NONE) { table->col_act = 0; table->row_act = 0; + scroll_to_selected_cell(obj); lv_obj_invalidate(obj); return; } @@ -560,6 +562,8 @@ static void lv_table_event(const lv_obj_class_t * class_p, lv_event_t * e) table->row_act = row; lv_obj_invalidate(obj); + scroll_to_selected_cell(obj); + res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL); if(res != LV_RES_OK) return; } @@ -1004,4 +1008,26 @@ static void get_cell_area(lv_obj_t * obj, uint16_t row, uint16_t col, lv_area_t } + +static void scroll_to_selected_cell(lv_obj_t * obj) +{ + lv_table_t * table = (lv_table_t *)obj; + + lv_area_t a; + get_cell_area(obj, table->row_act, table->col_act, &a); + if(a.x1 < 0) { + lv_obj_scroll_by_bounded(obj, -a.x1, 0, LV_ANIM_ON); + } + else if(a.x2 > lv_obj_get_width(obj)) { + lv_obj_scroll_by_bounded(obj, lv_obj_get_width(obj) - a.x2, 0, LV_ANIM_ON); + } + + if(a.y1 < 0) { + lv_obj_scroll_by_bounded(obj, 0, -a.y1, LV_ANIM_ON); + } + else if(a.y2 > lv_obj_get_height(obj)) { + lv_obj_scroll_by_bounded(obj, 0, lv_obj_get_height(obj) - a.y2, LV_ANIM_ON); + } + +} #endif diff --git a/lib/libesp32_ml/mel_freq_extractor/library.properties b/lib/libesp32_ml/mel_freq_extractor/library.properties new file mode 100644 index 000000000..9b173d75a --- /dev/null +++ b/lib/libesp32_ml/mel_freq_extractor/library.properties @@ -0,0 +1,7 @@ +name=MElFreqencyExtractor +version=1.0 +author=Christian Baars +maintainer=Christian Baars +sentence=Feature Extractor using mel frequencies +paragraph=Uses ESP-DSP library. +architectures=esp32 diff --git a/lib/libesp32_ml/mel_freq_extractor/src/mfcc.h b/lib/libesp32_ml/mel_freq_extractor/src/mfcc.h new file mode 100644 index 000000000..524d3c6e0 --- /dev/null +++ b/lib/libesp32_ml/mel_freq_extractor/src/mfcc.h @@ -0,0 +1,315 @@ +/* + mfcc.h - mel frequency extractor for ESP32 + + Computes features for slizes of audio data similiar to speechpy + This is intended to provide a stripped down implementation that can work with Edgempulse trained models + + based on: + https://github.com/astorfi/speechpy + https://github.com/AIWintermuteAI/Speech-to-Intent-Micro/blob/main/inference_code/Wio_Terminal/wio_speech_to_intent_150_10/mfcc.cpp + + Copyright (C) 2022 Christian Baars + 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 .@ +*/ + + + +#ifndef MELFREQUENCYEXTRACTOR_H +#define MELFREQUENCYEXTRACTOR_H + +#include +#include +#include "float.h" +#include "esp_dsp.h" + + +class MFCC{ + private: + int num_mfcc_features; + int frame_len; + int frame_len_padded; + int num_bank_bins; + float * m_frame; + float * m_buffer; + float * m_mel_energies; + float * m_dct_matrix; + float * m_mel_fbank; + + uint8_t m_amplification; + float m_preemphasis; + + float * create_dct_matrix(int32_t input_length, int32_t coefficient_count); + void create_mel_filterbank(int samp_freq, int low_freq, int high_freq); + + static inline float InverseMelScale(float mel_freq) { + return 700.0f * (expf (mel_freq / 1127.0f) - 1.0f); + } + + static inline float MelScale(float freq) { + return 1127.0f * logf (1.0f + freq / 700.0f); + } + + + public: + MFCC(int num_mfcc_features, int frame_len,int num_bank_bins, int samp_freq, int low_freq, int high_freq); + ~MFCC(); + void set_preamp(uint8_t amplification); + void set_preemphasis(float preemphasis); + void mfcc_compute(const int16_t* data, float* mfcc_out); + void log10_normalize(float* out_buf, int out_buf_len, int noise_floor_db); +}; + + +MFCC::MFCC(int num_mfcc_features, int frame_len, int num_bank_bins, int samp_freq, int low_freq, int high_freq) +:num_mfcc_features(num_mfcc_features), + frame_len(frame_len), + num_bank_bins(num_bank_bins) +{ + // Round-up to nearest power of 2. + frame_len_padded = pow(2,ceil((log(frame_len)/log(2)))); + + m_frame = new float[frame_len_padded]; + m_buffer = new float[frame_len_padded * 2]; + m_mel_energies = new float[num_bank_bins]; + + //create window function + // window_func = new float[frame_len]; + // dsps_wind_hann_f32(window_func, frame_len); + + m_amplification = 1; + m_preemphasis = 0.0; + + //create mel filterbank + create_mel_filterbank(samp_freq, low_freq, high_freq); + + //create DCT matrix for mfcc mode + if(num_mfcc_features != 0){ + m_dct_matrix = create_dct_matrix(num_bank_bins, num_mfcc_features); + } + + //initialize FFT + int ret = dsps_fft2r_init_fc32(NULL, frame_len_padded); + if(ret==0){ + MicroPrintf("Framelength: %u, (rounded: %u)", frame_len,frame_len_padded); + } + else{ + MicroPrintf("dsps_fft2r_init_fc32 error: %d",ret); + } + +} + +MFCC::~MFCC() { + delete []m_frame; + delete []m_buffer; + delete []m_mel_energies; + // delete []window_func; + + delete []m_dct_matrix; + + // for(int i=0;i(noise_floor_db * -1); + const float noise_scale = 1.0f / (static_cast(noise_floor_db * -1) + 12.0f); + for (size_t ix = 0; ix < out_buf_len; ix++) { + float f = out_buf[ix]; + if (f < 1e-30) { + out_buf[ix] = 0; + return; + } + f = 10.0f * log10(f); // scale by 10 + f += noise; + f *= noise_scale; + // clip again + if (f < 0.0f) f = 0.0f; + else if (f > 1.0f) f = 1.0f; + out_buf[ix] = f; + } +} + +void MFCC::set_preamp(uint8_t amplification){ + m_amplification = amplification; +} + +void MFCC::set_preemphasis(float preemphasis){ + m_preemphasis = preemphasis; + // Speechpy computes this over the window of a sample, here we will compute only over the slize !! +} + + +void MFCC::mfcc_compute(const int16_t * audio_data, float* mfcc_out) { + + int32_t i, j, bin; + int coefficients = frame_len_padded/2 + 1; + int data_clipped = 0; + int data_clipped_low = 0; + float conv_factor = m_amplification; + float clip_thres = 0.99f * (float)(1<<15); + + // MicroPrintf("%d %d %d %d %d %d %d %d",audio_data[0],audio_data[1] ,audio_data[2] ,audio_data[3] ,audio_data[4] ,audio_data[5] ,audio_data[6] ,audio_data[7]); + + //TensorFlow way of normalizing .wav data to (-1,1) for speechpy's MFE + if(num_mfcc_features == 0){ + conv_factor /= (float)(1<<15); + clip_thres /= (float)(1<<15); + } + + for (int i = 0; i < frame_len; i++) { + m_buffer[i] = audio_data[i] * conv_factor; //mfe -1..1, mfcc int16_t as float, both with additional pre_amp factor + } + if(m_buffer[i]> clip_thres){ + m_buffer[i] /= m_amplification; + data_clipped++; + } + else if( m_buffer[i]< -clip_thres){ + m_buffer[i] /= m_amplification; + data_clipped_low++; + } + + if(data_clipped>0) + MicroPrintf("Clip: %d __ %d",data_clipped, data_clipped_low); + + // MicroPrintf("%f %f %f %f %f %f %f %f ",m_buffer[0],m_buffer[1] ,m_buffer[2] ,m_buffer[3] ,m_buffer[4] ,m_buffer[5] ,m_buffer[6] ,m_buffer[7]); + + //pre-emphasis + if(m_preemphasis!=0.0){ + m_frame[0] = m_buffer[0] - m_preemphasis * m_buffer[frame_len - 1]; // roll through the frame "back" to the end + for (i = 1; i < frame_len; i++){ + m_frame[i] = m_buffer[i] - m_preemphasis * m_buffer[i - 1]; + } + } + else{ + for (i = 1; i < frame_len; i++){ + m_frame[i] = m_buffer[i]; + } + } + + // prepare buffer for FFT + for (i = 0; i < frame_len_padded; i++) { + m_buffer[i * 2] = i diff --git a/lib/libesp32_ml/tf_lite_esp32/CODEOWNERS b/lib/libesp32_ml/tf_lite_esp32/CODEOWNERS new file mode 100644 index 000000000..b235a44e8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/CODEOWNERS @@ -0,0 +1,4 @@ +* @tensorflow/micro @ddavis-2015 + +/.github/ @advaitjain +/ci/ @advaitjain diff --git a/lib/libesp32_ml/tf_lite_esp32/LICENSE b/lib/libesp32_ml/tf_lite_esp32/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/LICENSE @@ -0,0 +1,202 @@ + + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/lib/libesp32_ml/tf_lite_esp32/README.md b/lib/libesp32_ml/tf_lite_esp32/README.md new file mode 100644 index 000000000..a0612ee98 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/README.md @@ -0,0 +1,80 @@ +# TensorFlow Lite Micro Library for Arduino-Espressif32 + +This repository has the code (including examples) needed to use Tensorflow Lite Micro on an Arduino. + +## Table of contents + +* [Table of contents](#table-of-contents) +* [Build Status](#build-status) +* [How to Install](#how-to-install) + * [GitHub](#github) + * [Checking your Installation](#checking-your-installation) +* [Compatibility](#compatibility) +* [License](#license) +* [Contributing](#contributing) + + +## Build Status + +Build Type | Status | +--------------- | ------------- | +Arduino CLI on Linux | [![Arduino](https://github.com/tensorflow/tflite-micro-arduino-examples/actions/workflows/ci.yml/badge.svg?event=schedule)](https://github.com/tensorflow/tflite-micro-arduino-examples/actions/workflows/ci.yml) +Sync from tflite-micro | [![Sync from tflite-micro](https://github.com/tensorflow/tflite-micro-arduino-examples/actions/workflows/sync.yml/badge.svg)](https://github.com/tensorflow/tflite-micro-arduino-examples/actions/workflows/sync.yml) + +## How to Install + +### GitHub + +The officially supported TensorFlow Lite Micro library for Arduino resides +in the [tflite-micro-arduino-examples](https://github.com/tensorflow/tflite-micro-arduino-examples) +GitHub repository. +To install the in-development version of this library, you can use the +latest version directly from the GitHub repository. This requires you clone the +repo into the folder that holds libraries for the Arduino IDE. The location for +this folder varies by operating system, but typically it's in +`~/Arduino/libraries` on Linux, `~/Documents/Arduino/libraries/` on MacOS, and +`My Documents\Arduino\Libraries` on Windows. + +Once you're in that folder in the terminal, you can then grab the code using the +git command line tool: + +``` +git clone https://github.com/tensorflow/tflite-micro-arduino-examples Arduino_TensorFlowLite +``` + +To update your clone of the repository to the latest code, use the following terminal commands: +``` +cd Arduino_TensorFlowLite +git pull +``` + +### Checking your Installation + +Once the library has been installed, you should then start the Arduino IDE. +You will now see an `Arduino_TensorFlowLite` +entry in the `File -> Examples` menu of the Arduino IDE. This submenu contains a list +of sample projects you can try out. + +![Hello World](docs/hello_world_screenshot.png) + +## Compatibility + +This library is designed for the `Arduino Nano 33 BLE Sense` board. The framework +code for running machine learning models should be compatible with most Arm Cortex +M-based boards, such as the `Raspberry Pi Pico`, but the code to access peripherals +like microphones, cameras, and accelerometers is specific to the `Nano 33 BLE Sense`. + +## License + +This code is made available under the Apache 2 license. + +## Contributing + +Forks of this library are welcome and encouraged. If you have bug reports or +fixes to contribute, the source of this code is at [https:://github.com/tensorflow/tflite-micro](github.com/tensorflow/tflite-micro) +and all issues and pull requests should be directed there. + +The code here is created through an automatic project generation process +and may differ from +that source of truth, since it's cross-platform and needs to be modified to +work within the Arduino IDE. \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/README.md b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/README.md new file mode 100644 index 000000000..aac6402db --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/README.md @@ -0,0 +1,59 @@ + + +# Hello World Example + +This example is designed to demonstrate the absolute basics of using [TensorFlow +Lite for Microcontrollers](https://www.tensorflow.org/lite/microcontrollers). +It includes the full end-to-end workflow of training a model, converting it for +use with TensorFlow Lite for Microcontrollers for running inference on a +microcontroller. + +The model is trained to replicate a `sine` function and generates a pattern of +data to blink the built-in LED in a fade in/out pattern. + +## Table of contents + +* [Table of contents](#table-of-contents) +* [Deploy to Arduino](#deploy-to-arduino) + * [Install the Arduino_TensorFlowLite library](#install-the-arduino_tensorflowlite-library) + * [Load and run the example](#load-and-run-the-example) + + +## Deploy to Arduino + +The following instructions will help you build and deploy this sample +to [Arduino](https://www.arduino.cc/) devices. + +The sample has been tested with the following devices: + +- [Arduino Nano 33 BLE Sense](https://store.arduino.cc/usa/nano-33-ble-sense-with-headers) +- [Arduino Tiny Machine Learning Kit](https://store-usa.arduino.cc/products/arduino-tiny-machine-learning-kit) + +The sample will use PWM to fade an LED on and off according to the model's +output. In the code, the `LED_BUILTIN` constant is used to specify the board's +built-in LED as the one being controlled. However, on some boards, this built-in +LED is not attached to a pin with PWM capabilities. In this case, the LED will +blink instead of fading. + +![Animation on Nano 33 BLE Sense](../../docs/hello_world_animation.gif) + +### Install the Arduino_TensorFlowLite library + +To install the TensorFlow Lite Micro for Arduino library, see the +[how to install](../../README.md#how-to-install) instructions. + +### Load and run the example + +Once the library has been added, go to `File -> Examples`. You should see an +entry within the list named `Arduino_TensorFlowLite`. Select +it and click `hello_world` to load the example. + +Use the Arduino IDE to build and upload the example. Once it is running, +you should see the built-in LED on your device flashing. + +The Arduino Desktop IDE includes a plotter that we can use to display the sine +wave graphically. To view it, go to `Tools -> Serial Plotter`. You will see one +datapoint being logged for each inference cycle, expressed as a number between 0 +and 255. + +![Serial Plotter with Nano 33 BLE Sense](../../docs/hello_world_serial_plotter.png) diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_constants.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_constants.cpp new file mode 100644 index 000000000..927f8d9be --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_constants.cpp @@ -0,0 +1,20 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "constants.h" + +// This is tuned so that a full cycle takes ~6.6 seconds on an +// Arduino Nano 33 BLE. +const int kInferencesPerCycle = 200; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_main.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_main.cpp new file mode 100644 index 000000000..c70a2bcea --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_main.cpp @@ -0,0 +1,20 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "main_functions.h" + +// Arduino automatically calls the setup() and loop() functions in a sketch, so +// where other systems need their own main routine in this file, it can be left +// empty. diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_output_handler.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_output_handler.cpp new file mode 100644 index 000000000..d41092549 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/arduino_output_handler.cpp @@ -0,0 +1,54 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "Arduino.h" +#include "constants.h" +#include "output_handler.h" + +// The pin of the Arduino's built-in LED +int led = LED_BUILTIN; + +// Track whether the function has run at least once +bool initialized = false; + +// Animates a dot across the screen to represent the current x and y values +void HandleOutput(tflite::ErrorReporter* error_reporter, float x_value, + float y_value) { + // Do this only once + if (!initialized) { + // Set the LED pin to output + pinMode(led, OUTPUT); + initialized = true; + } + + // Calculate the brightness of the LED such that y=-1 is fully off + // and y=1 is fully on. The LED's brightness can range from 0-255. + int brightness = (int)(127.5f * (y_value + 1)); + + // The y value is not actually constrained to the range [-1, 1], so we need to + // clamp the brightness value before sending it to the PWM/LED. + int brightness_clamped = std::min(255, std::max(0, brightness)); + + // Set the brightness of the LED. If the specified pin does not support PWM, + // this will result in the LED being on when brightness_clamped > 127, off + // otherwise. + analogWrite(led, brightness_clamped); + + // Log the current brightness value for display in the Arduino plotter + TF_LITE_REPORT_ERROR(error_reporter, "%d\n", brightness); + delay(33); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/constants.h b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/constants.h new file mode 100644 index 000000000..f45289320 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/constants.h @@ -0,0 +1,32 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_CONSTANTS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_CONSTANTS_H_ + +// This constant represents the range of x values our model was trained on, +// which is from 0 to (2 * Pi). We approximate Pi to avoid requiring additional +// libraries. +const float kXrange = 2.f * 3.14159265359f; + +// This constant determines the number of inferences to perform across the range +// of x values defined above. Since each inference takes time, the higher this +// number, the more time it will take to run through the entire range. The value +// of this constant can be tuned so that one full cycle takes a desired amount +// of time. Since different devices take different amounts of time to perform +// inference, this value should be defined per-device. +extern const int kInferencesPerCycle; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_CONSTANTS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/hello_world.ino b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/hello_world.ino new file mode 100644 index 000000000..ca6536b1e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/hello_world.ino @@ -0,0 +1,123 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "main_functions.h" + +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "constants.h" +#include "model.h" +#include "output_handler.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +// Globals, used for compatibility with Arduino-style sketches. +namespace { +tflite::ErrorReporter* error_reporter = nullptr; +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* input = nullptr; +TfLiteTensor* output = nullptr; +int inference_count = 0; + +constexpr int kTensorArenaSize = 2000; +uint8_t tensor_arena[kTensorArenaSize]; +} // namespace + +// The name of this function is important for Arduino compatibility. +void setup() { + tflite::InitializeTarget(); + + // Set up logging. Google style is to avoid globals or statics because of + // lifetime uncertainty, but since this has a trivial destructor it's okay. + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::MicroErrorReporter micro_error_reporter; + error_reporter = µ_error_reporter; + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + model = tflite::GetModel(g_model); + if (model->version() != TFLITE_SCHEMA_VERSION) { + TF_LITE_REPORT_ERROR(error_reporter, + "Model provided is schema version %d not equal " + "to supported version %d.", + model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // This pulls in all the operation implementations we need. + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::AllOpsResolver resolver; + + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, resolver, tensor_arena, kTensorArenaSize, error_reporter); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + TfLiteStatus allocate_status = interpreter->AllocateTensors(); + if (allocate_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed"); + return; + } + + // Obtain pointers to the model's input and output tensors. + input = interpreter->input(0); + output = interpreter->output(0); + + // Keep track of how many inferences we have performed. + inference_count = 0; +} + +// The name of this function is important for Arduino compatibility. +void loop() { + // Calculate an x value to feed into the model. We compare the current + // inference_count to the number of inferences per cycle to determine + // our position within the range of possible x values the model was + // trained on, and use this to calculate a value. + float position = static_cast(inference_count) / + static_cast(kInferencesPerCycle); + float x = position * kXrange; + + // Quantize the input from floating-point to integer + int8_t x_quantized = x / input->params.scale + input->params.zero_point; + // Place the quantized input in the model's input tensor + input->data.int8[0] = x_quantized; + + // Run inference, and report any error + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed on x: %f\n", + static_cast(x)); + return; + } + + // Obtain the quantized output from model's output tensor + int8_t y_quantized = output->data.int8[0]; + // Dequantize the output from integer to floating-point + float y = (y_quantized - output->params.zero_point) * output->params.scale; + + // Output the results. A custom HandleOutput function can be implemented + // for each supported hardware target. + HandleOutput(error_reporter, x, y); + + // Increment the inference_counter, and reset it if we have reached + // the total number per cycle + inference_count += 1; + if (inference_count >= kInferencesPerCycle) inference_count = 0; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/main_functions.h b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/main_functions.h new file mode 100644 index 000000000..a1ea715c6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/main_functions.h @@ -0,0 +1,37 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MAIN_FUNCTIONS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MAIN_FUNCTIONS_H_ + +// Expose a C friendly interface for main functions. +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes all data needed for the example. The name is important, and needs +// to be setup() for Arduino compatibility. +void setup(); + +// Runs one iteration of data gathering and inference. This should be called +// repeatedly from the application code. The name needs to be loop() for Arduino +// compatibility. +void loop(); + +#ifdef __cplusplus +} +#endif + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MAIN_FUNCTIONS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/model.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/model.cpp new file mode 100644 index 000000000..f04a9f661 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/model.cpp @@ -0,0 +1,237 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ + +// Automatically created from a TensorFlow Lite flatbuffer using the command: +// xxd -i model.tflite > model.cc + +// This is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. + +// See train/README.md for a full description of the creation process. + +#include "model.h" + +// Keep model aligned to 8 bytes to guarantee aligned 64-bit accesses. +alignas(8) const unsigned char g_model[] = { + 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00, + 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, + 0x2c, 0x03, 0x00, 0x00, 0x30, 0x09, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x60, 0xf7, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0xff, 0xff, 0xff, + 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x34, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x76, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, + 0x34, 0x02, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, + 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xfa, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x35, 0x2e, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xfd, 0xff, 0xff, + 0x88, 0xfd, 0xff, 0xff, 0x8c, 0xfd, 0xff, 0xff, 0x22, 0xfe, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x21, 0xa5, 0x8b, 0xca, + 0x5e, 0x1d, 0xce, 0x42, 0x9d, 0xce, 0x1f, 0xb0, 0xdf, 0x54, 0x2f, 0x81, + 0x3e, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0xee, 0xfc, 0x00, 0xec, 0x05, 0x17, 0xef, 0xec, 0xe6, 0xf8, 0x03, 0x01, + 0x00, 0xfa, 0xf8, 0xf5, 0xdc, 0xeb, 0x27, 0x14, 0xf1, 0xde, 0xe2, 0xdb, + 0xf0, 0xde, 0x31, 0x06, 0x02, 0xe6, 0xee, 0xf9, 0x00, 0x16, 0x07, 0xe0, + 0xfe, 0xff, 0xe9, 0x06, 0xe7, 0xef, 0x81, 0x1b, 0x18, 0xea, 0xc9, 0x01, + 0x0f, 0x00, 0xda, 0xf7, 0x0e, 0xec, 0x13, 0x1f, 0x04, 0x13, 0xb4, 0xe6, + 0xfd, 0x06, 0xb9, 0xe0, 0x0d, 0xec, 0xf0, 0xde, 0xeb, 0xf7, 0x05, 0x26, + 0x1a, 0xe4, 0x6f, 0x1a, 0xea, 0x1e, 0x35, 0xdf, 0x1a, 0xf3, 0xf1, 0x19, + 0x0f, 0x03, 0x1b, 0xe1, 0xde, 0x13, 0xf6, 0x19, 0xff, 0xf6, 0x1b, 0x18, + 0xf0, 0x1c, 0xda, 0x1b, 0x1b, 0x20, 0xe5, 0x1a, 0xf5, 0xff, 0x96, 0x0b, + 0x00, 0x01, 0xcd, 0xde, 0x0d, 0xf6, 0x16, 0xe3, 0xed, 0xfc, 0x0e, 0xe9, + 0xfa, 0xeb, 0x5c, 0xfc, 0x1d, 0x02, 0x5b, 0xe2, 0xe1, 0xf5, 0x15, 0xec, + 0xf4, 0x00, 0x13, 0x05, 0xec, 0x0c, 0x1d, 0x14, 0x0e, 0xe7, 0x0b, 0xf4, + 0x19, 0x00, 0xd7, 0x05, 0x27, 0x02, 0x15, 0xea, 0xea, 0x02, 0x9b, 0x00, + 0x0c, 0xfa, 0xe8, 0xea, 0xfd, 0x00, 0x14, 0xfd, 0x0b, 0x02, 0xef, 0xee, + 0x06, 0xee, 0x01, 0x0d, 0x06, 0xe6, 0xf7, 0x11, 0xf7, 0x09, 0xf8, 0xf1, + 0x21, 0xff, 0x0e, 0xf3, 0xec, 0x12, 0x26, 0x1d, 0xf2, 0xe9, 0x28, 0x18, + 0xe0, 0xfb, 0xf3, 0xf4, 0x05, 0x1d, 0x1d, 0xfb, 0xfd, 0x1e, 0xfc, 0x11, + 0xe8, 0x07, 0x09, 0x03, 0x12, 0xf2, 0x36, 0xfb, 0xdc, 0x1c, 0xf9, 0xef, + 0xf3, 0xe7, 0x6f, 0x0c, 0x1d, 0x00, 0x45, 0xfd, 0x0e, 0xf0, 0x0b, 0x19, + 0x1a, 0xfa, 0xe0, 0x19, 0x1f, 0x13, 0x36, 0x1c, 0x12, 0xeb, 0x3b, 0x0c, + 0xb4, 0xcb, 0xe6, 0x13, 0xfa, 0xeb, 0xf1, 0x06, 0x1c, 0xfa, 0x18, 0xe5, + 0xeb, 0xcb, 0x0c, 0xf4, 0x4a, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x75, 0x1c, 0x11, 0xe1, 0x0c, 0x81, 0xa5, 0x42, + 0xfe, 0xd5, 0xd4, 0xb2, 0x61, 0x78, 0x19, 0xdf, 0x66, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x77, 0x0b, 0x00, 0x00, 0x53, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x07, 0x00, 0x00, + 0x67, 0xf5, 0xff, 0xff, 0x34, 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xb2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb5, 0x04, 0x00, 0x00, 0x78, 0x0a, 0x00, 0x00, + 0x2d, 0x06, 0x00, 0x00, 0x71, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x9a, 0x0a, 0x00, 0x00, 0xfe, 0xf7, 0xff, 0xff, 0x0e, 0x05, 0x00, 0x00, + 0xd4, 0x09, 0x00, 0x00, 0x47, 0xfe, 0xff, 0xff, 0xb6, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xac, 0xf7, 0xff, 0xff, 0x4b, 0xf9, 0xff, 0xff, + 0x4a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x8c, 0xef, 0xff, 0xff, 0x84, 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff, + 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c, 0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, + 0xe0, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x96, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0xba, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00, + 0xd0, 0x03, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, + 0x98, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, + 0x24, 0x01, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf0, 0xfb, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x6c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0xdc, 0xfb, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x4a, 0xce, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x34, 0x84, 0x85, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xc5, 0x02, 0x8f, 0xbf, + 0x1e, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, + 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x38, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x6c, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x93, 0xd0, 0xc0, 0x3b, 0x01, 0x00, 0x00, 0x00, + 0xc2, 0x0f, 0xc0, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x74, 0x66, 0x6c, 0x2e, 0x66, 0x75, 0x6c, 0x6c, + 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x08, 0xfd, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xf4, 0xfc, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xe0, 0xdb, 0x47, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x04, 0x14, 0x47, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x74, 0x66, 0x6c, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x5f, 0x63, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0xfe, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x6c, 0xfd, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfb, 0x4b, 0x0b, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x84, 0x4b, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x63, 0x35, 0x8a, 0xbf, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x32, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x72, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, + 0xdc, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x60, 0x01, 0x4f, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x47, 0x6d, 0xb3, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x5d, 0x63, 0xcd, 0xbf, 0x0d, 0x00, 0x00, 0x00, + 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, + 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xe2, 0xfe, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x50, 0x00, 0x00, 0x00, 0x4c, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xd5, 0x6b, 0x8a, 0x3b, 0x01, 0x00, 0x00, 0x00, + 0xab, 0x49, 0x01, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xfd, 0x56, 0x09, 0xbf, + 0x0c, 0x00, 0x00, 0x00, 0x73, 0x74, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x3c, 0x00, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x28, 0xb3, 0xd9, 0x38, 0x0c, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x2f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xaa, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00, 0x00, + 0x9c, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xdd, 0x9b, 0x21, 0x39, 0x0c, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x33, 0x2f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x48, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xf4, 0xd4, 0x51, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x64, 0x65, 0x6e, 0x73, + 0x65, 0x5f, 0x34, 0x2f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x1c, 0x00, + 0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x5d, 0x4f, 0xc9, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x86, 0xc8, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x32, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x3a, 0x30, 0x5f, 0x69, 0x6e, 0x74, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, + 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09}; +const int g_model_len = 2488; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/model.h b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/model.h new file mode 100644 index 000000000..488f47b3a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/model.h @@ -0,0 +1,31 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ + +// Automatically created from a TensorFlow Lite flatbuffer using the command: +// xxd -i model.tflite > model.cc + +// This is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. + +// See train/README.md for a full description of the creation process. + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MODEL_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MODEL_H_ + +extern const unsigned char g_model[]; +extern const int g_model_len; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_MODEL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/output_handler.h b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/output_handler.h new file mode 100644 index 000000000..14e9d7076 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/hello_world/output_handler.h @@ -0,0 +1,26 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_OUTPUT_HANDLER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_OUTPUT_HANDLER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// Called by the main loop to produce some output based on the x and y values +void HandleOutput(tflite::ErrorReporter* error_reporter, float x_value, + float y_value); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_HELLO_WORLD_OUTPUT_HANDLER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/LICENSE b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/LICENSE @@ -0,0 +1,201 @@ + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/README.md b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/README.md new file mode 100644 index 000000000..fd6b7bd96 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/README.md @@ -0,0 +1,114 @@ +# Magic Wand + +Magic Wand example for [TensorFlow Lite Micro](https://www.tensorflow.org/lite/microcontrollers) on the [Arduino Nano 33 BLE Sense](https://store-usa.arduino.cc/products/arduino-nano-33-ble-sense). + +## Table of contents + +* [Introduction](#introduction) +* [Hardware Requirements](#hardware-requirements) +* [Installing the Sketch](#installing-the-sketch) + * [Arduino Desktop IDE](#arduino-desktop-ide) +* [Building the Wand](#building-the-wand) +* [Using the wand](#using-the-wand) +* [Viewing Gestures in the Browser](#viewing-gestures-in-the-browser) +* [Pretrained Model](#pretrained-model) +* [Recording Gestures](#recording-gestures) +* [Training](#training) +* [Deployment](#deployment) + + +## Introduction + +This project shows you how to recognize gestures made by waving a magic wand, using machine learning to analyze accelerometer and gyroscope data. It demonstrates the three main stages of an end-to-end machine learning project: + + - **Gathering Data**. Using a Bluetooth connection to a web page, you can capture gestures, label them, and download the results. + - **Training**. A Python notebook on the free Colab service shows how to use TensorFlow to train a model to recognize gestures from your data. + - **Deployment**. You can deploy your trained model to the Arduino board using TensorFlow Lite Micro and the Arduino IDE. + + ## Hardware Requirements + + You'll need the following: + + - Arduino Nano 33 BLE Sense board. These are available as part of [the TinyML Starter Kit](https://store-usa.arduino.cc/products/arduino-tiny-machine-learning-kit), or separately from Arduino or resellers. Other Arduinos won't work unfortunately, because the Bluetooth and sensor code rely on accessing the particular hardware of the Nano 33 BLE Sense. + - MicroUSB cable. This is included in the TinyML Kit, but you'll need a USB-A adaptor too if your computer only has USB-C ports. + - Computer. The Arduino toolchain runs on Linux, Windows, and MacOS, so you should be able to use most laptops, desktops, or even a Raspberry Pi. For the training process, you'll also need an up-to-date version of the Chrome web browser so you can use the Web Bluetooth APIs. + - Stick. We'll be attaching your Arduino to a 'wand', but this can be practically anything, as long as it's roughly a foot (30 centimeters) long. + +## Installing the Sketch + +You'll need to ensure you can successfully connect and load sketches onto your Arduino board, +using the desktop IDE. +Once you've made sure you can load a simple sketch successfully, you'll follow these steps: + +### Arduino Desktop IDE + +If you're running using the Arduino IDE application, you'll need to fetch the latest version of this sketch. +To install the TensorFlow Lite Micro for Arduino library, see the +[how to install](../../README.md#how-to-install) instructions. + +Open up the magic_wand.ino file in the Arduino editor, and make sure the Arduino board is visible and connected to the right port. You'll need to search for the some libraries that the sketch depends on, using `Sketch->Include Library->Manage Libraries` from the main menu. The [Arduino_LSM9DS1](https://github.com/arduino-libraries/Arduino_LSM9DS1) lets us access the accelerometer and gyroscope readings from the board's IMU, and you need at least version 1.1.0. We'll be using Bluetooth to communicate with the web page, so you should also search for [ArduinoBLE](https://www.arduino.cc/en/Reference/ArduinoBLE) and make sure you've got version 1.1.3 or newer. + +You should now be able to press the upload button to compile and install the sketch on your board. + +## Building the Wand + +The 'wand' itself can be as simple as a stick, it doesn't need to do anything other than keep the board at its end as you hold the other end and wave it about. A cheap wand from an online retailer will work. A simple piece of wood or ruler works just as well. + +You should place the board at the end of the wand, with the USB socket facing downwards, towards where you hold it, so that the cable can run down the handle. The sketch is designed to compensate for any rotation of the board around the wand's shaft, so as long as it's parallel to the wand's length the board's twist won't matter. Use sticky tape or some other easy-to-remove method to attach the board to the wand, and hold the cable in place along the shaft. The end result should look something like this: + +![Image of board attached to wand](../../docs/magic_wand_attachment.jpg) + +If an ASCII-art diagram is more helpful, here's what you should aim for: + +``` + ____ + | |<- Arduino board + | | + | () | <- Reset button + | | + -TT- <- USB port + || + ||<- Wand + .... + || + || + () +``` + +## Using the wand + +The wand can be used with or without the Nano 33 BLE attached to the Tiny Machine Learning Shield. It is easier to use without, as your hand will not tire as quickly. The wand should be held as you would a pencil or pen, about 8 inches from the USB socket. Use your wrist to make strokes, not your arm. Strokes will need to be made somewhat quickly, without stopping during changes in direction. + +## Viewing Gestures in the Browser + +To preview and record gestures, we'll be connecting the sketch you've just uploaded to a web page, using Bluetooth and Chrome's WebBLE API. The code for the page is [in this repository](https://github.com/tensorflow/tflite-micro-arduino-examples/tree/main/examples/magic_wand/website), but it's all implemented using browser-side Javascript in a static HTML page, so you don't need to host it on your own server. Just dragging and dropping the `index.html` file into your browser should work. + +If the sketch has uploaded successfully, the Arduino should be advertising itself through Bluetooth. On the web page, press the 'Bluetooth' button to connect, and you should see a dialog appear asking you to pair with a device. After a second or two, there should be an entry that looks something like "BLESense-2F00". Click on that to pair, and you should be returned to the web page. + +If everything is working as expected, the Bluetooth button should turn blue, with "Connected" next to it. Now try moving the wand and look at the square below the button. As you gesture, you should see tracks appearing as lines in the web page in real time. Try doing small circles, or a 'Z' like Zorro! + +## Pretrained Model + +The sketch comes with a model that's been trained to recognize the hand-drawn digits zero to nine. This is based on a small dataset recorded by Google, so your accuracy may vary, but if you bring up the Serial Monitor in the Arduino IDE you can see what the model predicts for each gesture you make, with a confidence score between 0% and 100%, as well as ASCII art of the gesture outline. + +## Recording Gestures + +As you get familiar with the wand, so should notice that the gestures you have performed start to stack on the right side of the web page. This is where the data you'll eventually want to use for training is stored. When you leave or refresh the web page, these gestures will be lost, so make sure you use the "Download Data" link to save them locally if you've generated a number of them. + +The gestures are automatically split up by times when the wand is kept still. These pauses act like spaces between words, and so when you've finished a gesture you should stop moving the wand so that it ends cleanly. + +To get started, you should pick a couple of easy gestures to perform, like a 'Z' and an 'O'. As you make these gestures, you should see them appear in the right-hand stack of gestures. You can look at the shapes shown there to understand whether the gestures came out cleanly. A good rule of thumb is that if you can't tell what the gesture is by looking at it in the stack, then a model will have a hard time recognizing it too. + +Once you have ten or so of each gesture, scroll through the stack to review them. If any don't seem very recognizable, or are too 'sloppy' (which is very subjective unfortunately), then you can press the trash can button on the top right of the image to remove it. If you removed any, try recording some more so you have at least ten of each gesture. If you are happy with a gesture, click on the label at the top left to type in the correct name for it (for example `O` or `Z`). + +After you've reviewed and labeled all of your data, you can download it as a JSON text file that can be used for training. + +## Training + +Once you have data, you should [run the Python training notebook in Colab](https://colab.research.google.com/github/tensorflow/tflite-micro-arduino-examples/blob/main/examples/magic_wand/train/train_magic_wand_model.ipynb) and follow the steps to create and export your own model. + +## Deployment + +The Python training process should give you a `magic_wand_model_data.cc` file. Replace the file of the same name (but with a `.cpp` suffix) that's in the sketch you're using with this version. You'll also need to update the `labels` and `label_count` variables near the top of the `magic_wand.ino` to reflect any changes you made to the gestures you're trying to recognize. + +Upload this modified sketch, and you should be able to perform gestures and see them recognized in the Serial Monitor of your Arduino editor. diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand.ino b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand.ino new file mode 100644 index 000000000..881e2ee96 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand.ino @@ -0,0 +1,708 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +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 "magic_wand_model_data.h" +#include "rasterize_stroke.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +#define BLE_SENSE_UUID(val) ("4798e0f2-" val "-4d68-af64-8a8f5258404e") + +#undef MAGIC_WAND_DEBUG + +namespace { + +const int VERSION = 0x00000000; + +constexpr int stroke_transmit_stride = 2; +constexpr int stroke_transmit_max_length = 160; +constexpr int stroke_max_length = + stroke_transmit_max_length * stroke_transmit_stride; +constexpr int stroke_points_byte_count = + 2 * sizeof(int8_t) * stroke_transmit_max_length; +constexpr int stroke_struct_byte_count = + (2 * sizeof(int32_t)) + stroke_points_byte_count; +constexpr int moving_sample_count = 50; + +constexpr int raster_width = 32; +constexpr int raster_height = 32; +constexpr int raster_channels = 3; +constexpr int raster_byte_count = + raster_height * raster_width * raster_channels; +int8_t raster_buffer[raster_byte_count]; + +BLEService service(BLE_SENSE_UUID("0000")); +BLECharacteristic strokeCharacteristic(BLE_SENSE_UUID("300a"), BLERead, + stroke_struct_byte_count); + +// String to calculate the local and device name +String name; + +// A buffer holding the last 600 sets of 3-channel values from the +// accelerometer. +constexpr int acceleration_data_length = 600 * 3; +float acceleration_data[acceleration_data_length] = {}; +// The next free entry in the data array. +int acceleration_data_index = 0; +float acceleration_sample_rate = 0.0f; + +// A buffer holding the last 600 sets of 3-channel values from the gyroscope. +constexpr int gyroscope_data_length = 600 * 3; +float gyroscope_data[gyroscope_data_length] = {}; +float orientation_data[gyroscope_data_length] = {}; +// The next free entry in the data array. +int gyroscope_data_index = 0; +float gyroscope_sample_rate = 0.0f; + +float current_velocity[3] = {0.0f, 0.0f, 0.0f}; +float current_position[3] = {0.0f, 0.0f, 0.0f}; +float current_gravity[3] = {0.0f, 0.0f, 0.0f}; +float current_gyroscope_drift[3] = {0.0f, 0.0f, 0.0f}; + +int32_t stroke_length = 0; +uint8_t stroke_struct_buffer[stroke_struct_byte_count] = {}; +int32_t* stroke_state = reinterpret_cast(stroke_struct_buffer); +int32_t* stroke_transmit_length = + reinterpret_cast(stroke_struct_buffer + sizeof(int32_t)); +int8_t* stroke_points = + reinterpret_cast(stroke_struct_buffer + (sizeof(int32_t) * 2)); + +enum { + eWaiting = 0, + eDrawing = 1, + eDone = 2, +}; + +// Create an area of memory to use for input, output, and intermediate arrays. +// The size of this will depend on the model you're using, and may need to be +// determined by experimentation. +constexpr int kTensorArenaSize = 30 * 1024; +uint8_t tensor_arena[kTensorArenaSize]; + +tflite::ErrorReporter* error_reporter = nullptr; +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; + +constexpr int label_count = 10; +const char* labels[label_count] = {"0", "1", "2", "3", "4", + "5", "6", "7", "8", "9"}; + +void SetupIMU() { + // Make sure we are pulling measurements into a FIFO. + // If you see an error on this line, make sure you have at least v1.1.0 of the + // Arduino_LSM9DS1 library installed. + IMU.setContinuousMode(); + + acceleration_sample_rate = IMU.accelerationSampleRate(); + gyroscope_sample_rate = IMU.gyroscopeSampleRate(); +#ifdef MAGIC_WAND_DEBUG + float rate_frac; + float rate_int; + rate_frac = modf(acceleration_sample_rate, &rate_int); + TF_LITE_REPORT_ERROR(error_reporter, "Acceleration sample rate %d.%d Hz", + static_cast(rate_int), + static_cast(rate_frac * 100)); + rate_frac = modf(gyroscope_sample_rate, &rate_int); + TF_LITE_REPORT_ERROR(error_reporter, "Gyroscope sample rate %d.%d Hz", + static_cast(rate_int), + static_cast(rate_frac * 100)); +#endif // MAGIC_WAND_DEBUG +} + +void ReadAccelerometerAndGyroscope(int* new_accelerometer_samples, + int* new_gyroscope_samples) { + // Keep track of whether we stored any new data + *new_accelerometer_samples = 0; + *new_gyroscope_samples = 0; + // Loop through new samples and add to buffer + while (IMU.accelerationAvailable()) { + const int gyroscope_index = (gyroscope_data_index % gyroscope_data_length); + gyroscope_data_index += 3; + float* current_gyroscope_data = &gyroscope_data[gyroscope_index]; + // Read each sample, removing it from the device's FIFO buffer + if (!IMU.readGyroscope(current_gyroscope_data[0], current_gyroscope_data[1], + current_gyroscope_data[2])) { + TF_LITE_REPORT_ERROR(error_reporter, "Failed to read gyroscope data"); + break; + } + *new_gyroscope_samples += 1; + + const int acceleration_index = + (acceleration_data_index % acceleration_data_length); + acceleration_data_index += 3; + float* current_acceleration_data = &acceleration_data[acceleration_index]; + // Read each sample, removing it from the device's FIFO buffer + if (!IMU.readAcceleration(current_acceleration_data[0], + current_acceleration_data[1], + current_acceleration_data[2])) { + TF_LITE_REPORT_ERROR(error_reporter, "Failed to read acceleration data"); + break; + } + *new_accelerometer_samples += 1; + } +} + +float VectorMagnitude(const float* vec) { + const float x = vec[0]; + const float y = vec[1]; + const float z = vec[2]; + return sqrtf((x * x) + (y * y) + (z * z)); +} + +void EstimateGravityDirection(float* gravity) { + int samples_to_average = 100; + if (samples_to_average >= acceleration_data_index) { + samples_to_average = acceleration_data_index; + } + + const int start_index = + ((acceleration_data_index + + (acceleration_data_length - (3 * (samples_to_average + 1)))) % + acceleration_data_length); + + float x_total = 0.0f; + float y_total = 0.0f; + float z_total = 0.0f; + for (int i = 0; i < samples_to_average; ++i) { + const int index = ((start_index + (i * 3)) % acceleration_data_length); + const float* entry = &acceleration_data[index]; + const float x = entry[0]; + const float y = entry[1]; + const float z = entry[2]; + x_total += x; + y_total += y; + z_total += z; + } + gravity[0] = x_total / samples_to_average; + gravity[1] = y_total / samples_to_average; + gravity[2] = z_total / samples_to_average; +} + +void UpdateVelocity(int new_samples, float* gravity) { + const float gravity_x = gravity[0]; + const float gravity_y = gravity[1]; + const float gravity_z = gravity[2]; + + const int start_index = + ((acceleration_data_index + + (acceleration_data_length - (3 * (new_samples + 1)))) % + acceleration_data_length); + + const float friction_fudge = 0.98f; + + for (int i = 0; i < new_samples; ++i) { + const int index = ((start_index + (i * 3)) % acceleration_data_length); + const float* entry = &acceleration_data[index]; + const float ax = entry[0]; + const float ay = entry[1]; + const float az = entry[2]; + + // Try to remove gravity from the raw acceleration values. + const float ax_minus_gravity = ax - gravity_x; + const float ay_minus_gravity = ay - gravity_y; + const float az_minus_gravity = az - gravity_z; + + // Update velocity based on the normalized acceleration. + current_velocity[0] += ax_minus_gravity; + current_velocity[1] += ay_minus_gravity; + current_velocity[2] += az_minus_gravity; + + // Dampen the velocity slightly with a fudge factor to stop it exploding. + current_velocity[0] *= friction_fudge; + current_velocity[1] *= friction_fudge; + current_velocity[2] *= friction_fudge; + + // Update the position estimate based on the velocity. + current_position[0] += current_velocity[0]; + current_position[1] += current_velocity[1]; + current_position[2] += current_velocity[2]; + } +} + +void EstimateGyroscopeDrift(float* drift) { + const bool isMoving = VectorMagnitude(current_velocity) > 0.1f; + if (isMoving) { + return; + } + + int samples_to_average = 20; + if (samples_to_average >= gyroscope_data_index) { + samples_to_average = gyroscope_data_index; + } + + const int start_index = + ((gyroscope_data_index + + (gyroscope_data_length - (3 * (samples_to_average + 1)))) % + gyroscope_data_length); + + float x_total = 0.0f; + float y_total = 0.0f; + float z_total = 0.0f; + for (int i = 0; i < samples_to_average; ++i) { + const int index = ((start_index + (i * 3)) % gyroscope_data_length); + const float* entry = &gyroscope_data[index]; + const float x = entry[0]; + const float y = entry[1]; + const float z = entry[2]; + x_total += x; + y_total += y; + z_total += z; + } + drift[0] = x_total / samples_to_average; + drift[1] = y_total / samples_to_average; + drift[2] = z_total / samples_to_average; +} + +void UpdateOrientation(int new_samples, float* gravity, float* drift) { + const float drift_x = drift[0]; + const float drift_y = drift[1]; + const float drift_z = drift[2]; + + const int start_index = + ((gyroscope_data_index + (gyroscope_data_length - (3 * new_samples))) % + gyroscope_data_length); + + // The gyroscope values are in degrees-per-second, so to approximate + // degrees in the integrated orientation, we need to divide each value + // by the number of samples each second. + const float recip_sample_rate = 1.0f / gyroscope_sample_rate; + + for (int i = 0; i < new_samples; ++i) { + const int index = ((start_index + (i * 3)) % gyroscope_data_length); + const float* entry = &gyroscope_data[index]; + const float dx = entry[0]; + const float dy = entry[1]; + const float dz = entry[2]; + + // Try to remove sensor errors from the raw gyroscope values. + const float dx_minus_drift = dx - drift_x; + const float dy_minus_drift = dy - drift_y; + const float dz_minus_drift = dz - drift_z; + + // Convert from degrees-per-second to appropriate units for this + // time interval. + const float dx_normalized = dx_minus_drift * recip_sample_rate; + const float dy_normalized = dy_minus_drift * recip_sample_rate; + const float dz_normalized = dz_minus_drift * recip_sample_rate; + + // Update orientation based on the gyroscope data. + float* current_orientation = &orientation_data[index]; + const int previous_index = + (index + (gyroscope_data_length - 3)) % gyroscope_data_length; + const float* previous_orientation = &orientation_data[previous_index]; + current_orientation[0] = previous_orientation[0] + dx_normalized; + current_orientation[1] = previous_orientation[1] + dy_normalized; + current_orientation[2] = previous_orientation[2] + dz_normalized; + } +} + +bool IsMoving(int samples_before) { + constexpr float moving_threshold = 9.0f; + + if ((gyroscope_data_index - samples_before) < moving_sample_count) { + return false; + } + + const int start_index = + ((gyroscope_data_index + (gyroscope_data_length - + (3 * (moving_sample_count + samples_before)))) % + gyroscope_data_length); + + float total = 0.0f; + for (int i = 0; i < moving_sample_count; ++i) { + const int index = ((start_index + (i * 3)) % gyroscope_data_length); + float* current_orientation = &orientation_data[index]; + const int previous_index = + (index + (gyroscope_data_length - 3)) % gyroscope_data_length; + const float* previous_orientation = &orientation_data[previous_index]; + const float dx = current_orientation[0] - previous_orientation[0]; + const float dy = current_orientation[1] - previous_orientation[1]; + const float dz = current_orientation[2] - previous_orientation[2]; + const float mag_squared = (dx * dx) + (dy * dy) + (dz * dz); + total += mag_squared; + } + const bool is_moving = (total > moving_threshold); + return is_moving; +} + +void UpdateStroke(int new_samples, bool* done_just_triggered) { + constexpr int minimum_stroke_length = moving_sample_count + 10; + constexpr float minimum_stroke_size = 0.2f; + + *done_just_triggered = false; + + for (int i = 0; i < new_samples; ++i) { + const int current_head = (new_samples - (i + 1)); + const bool is_moving = IsMoving(current_head); + const int32_t old_state = *stroke_state; + if ((old_state == eWaiting) || (old_state == eDone)) { + if (is_moving) { + stroke_length = moving_sample_count; + *stroke_state = eDrawing; + } + } else if (old_state == eDrawing) { + if (!is_moving) { + if (stroke_length > minimum_stroke_length) { + *stroke_state = eDone; + } else { + stroke_length = 0; + *stroke_state = eWaiting; +#ifdef MAGIC_WAND_DEBUG + TF_LITE_REPORT_ERROR(error_reporter, "stroke length too small"); +#endif // MAGIC_WAND_DEBUG + } + } + } + + const bool is_waiting = (*stroke_state == eWaiting); + if (is_waiting) { + continue; + } + + stroke_length += 1; + if (stroke_length > stroke_max_length) { + stroke_length = stroke_max_length; + } + + // Only recalculate the full stroke if it's needed. + const bool draw_last_point = + ((i == (new_samples - 1)) && (*stroke_state == eDrawing)); + *done_just_triggered = ((old_state != eDone) && (*stroke_state == eDone)); + if (!(*done_just_triggered || draw_last_point)) { + continue; + } + + const int start_index = + ((gyroscope_data_index + + (gyroscope_data_length - (3 * (stroke_length + current_head)))) % + gyroscope_data_length); + + float x_total = 0.0f; + float y_total = 0.0f; + float z_total = 0.0f; + for (int j = 0; j < stroke_length; ++j) { + const int index = ((start_index + (j * 3)) % gyroscope_data_length); + const float* entry = &orientation_data[index]; + x_total += entry[0]; + y_total += entry[1]; + z_total += entry[2]; + } + + const float y_mean = y_total / stroke_length; + const float z_mean = z_total / stroke_length; + constexpr float range = 45.0f; + + const float gy = current_gravity[1]; + const float gz = current_gravity[2]; + float gmag = sqrtf((gy * gy) + (gz * gz)); + if (gmag < 0.0001f) { + gmag = 0.0001f; + } + const float ngy = gy / gmag; + const float ngz = gz / gmag; + + const float xaxisz = -ngz; + const float xaxisy = -ngy; + + const float yaxisz = -ngy; + const float yaxisy = ngz; + + *stroke_transmit_length = stroke_length / stroke_transmit_stride; + + float x_min = 0; + float y_min = 0; + float x_max = 0; + float y_max = 0; + for (int j = 0; j < *stroke_transmit_length; ++j) { + const int orientation_index = + ((start_index + ((j * stroke_transmit_stride) * 3)) % + gyroscope_data_length); + const float* orientation_entry = &orientation_data[orientation_index]; + + const float orientation_y = orientation_entry[1]; + const float orientation_z = orientation_entry[2]; + + const float ny = (orientation_y - y_mean) / range; + const float nz = (orientation_z - z_mean) / range; + + const float x_axis = (xaxisz * nz) + (xaxisy * ny); + const float y_axis = (yaxisz * nz) + (yaxisy * ny); + + const int stroke_index = j * 2; + int8_t* stroke_entry = &stroke_points[stroke_index]; + + int32_t unchecked_x = static_cast(roundf(x_axis * 128.0f)); + int8_t stored_x; + if (unchecked_x > 127) { + stored_x = 127; + } else if (unchecked_x < -128) { + stored_x = -128; + } else { + stored_x = unchecked_x; + } + stroke_entry[0] = stored_x; + + int32_t unchecked_y = static_cast(roundf(y_axis * 128.0f)); + int8_t stored_y; + if (unchecked_y > 127) { + stored_y = 127; + } else if (unchecked_y < -128) { + stored_y = -128; + } else { + stored_y = unchecked_y; + } + stroke_entry[1] = stored_y; + + const bool is_first = (j == 0); + if (is_first || (x_axis < x_min)) { + x_min = x_axis; + } + if (is_first || (y_axis < y_min)) { + y_min = y_axis; + } + if (is_first || (x_axis > x_max)) { + x_max = x_axis; + } + if (is_first || (y_axis > y_max)) { + y_max = y_axis; + } + } + + // If the stroke is too small, cancel it. + if (*done_just_triggered) { + const float x_range = (x_max - x_min); + const float y_range = (y_max - y_min); + if ((x_range < minimum_stroke_size) && (y_range < minimum_stroke_size)) { + *done_just_triggered = false; + *stroke_state = eWaiting; + *stroke_transmit_length = 0; + stroke_length = 0; +#ifdef MAGIC_WAND_DEBUG + TF_LITE_REPORT_ERROR(error_reporter, "stroke too small"); +#endif // MAGIC_WAND_DEBUG + } + } + } +} + +} // namespace + +void setup() { + tflite::InitializeTarget(); // setup serial port + + // Set up logging. Google style is to avoid globals or statics because of + // lifetime uncertainty, but since this has a trivial destructor it's okay. + static tflite::MicroErrorReporter micro_error_reporter; // NOLINT + error_reporter = µ_error_reporter; + + TF_LITE_REPORT_ERROR(error_reporter, "Started"); + + if (!IMU.begin()) { + TF_LITE_REPORT_ERROR(error_reporter, "Failed to initialized IMU!"); + while (true) { + // NORETURN + } + } + + SetupIMU(); + + if (!BLE.begin()) { + TF_LITE_REPORT_ERROR(error_reporter, "Failed to initialized BLE!"); + while (true) { + // NORETURN + } + } + + String address = BLE.address(); + + TF_LITE_REPORT_ERROR(error_reporter, "address = %s", address.c_str()); + + address.toUpperCase(); + + name = "BLESense-"; + name += address[address.length() - 5]; + name += address[address.length() - 4]; + name += address[address.length() - 2]; + name += address[address.length() - 1]; + + TF_LITE_REPORT_ERROR(error_reporter, "name = %s", name.c_str()); + + BLE.setLocalName(name.c_str()); + BLE.setDeviceName(name.c_str()); + BLE.setAdvertisedService(service); + + service.addCharacteristic(strokeCharacteristic); + + BLE.addService(service); + + BLE.advertise(); + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + model = tflite::GetModel(g_magic_wand_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + TF_LITE_REPORT_ERROR(error_reporter, + "Model provided is schema version %d not equal " + "to supported version %d.", + model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // Pull in only the operation implementations we need. + // This relies on a complete list of all the ops needed by this graph. + // An easier approach is to just use the AllOpsResolver, but this will + // incur some penalty in code space for op implementations that are not + // needed by this graph. + static tflite::MicroMutableOpResolver<4> micro_op_resolver; // NOLINT + micro_op_resolver.AddConv2D(); + micro_op_resolver.AddMean(); + micro_op_resolver.AddFullyConnected(); + micro_op_resolver.AddSoftmax(); + + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + interpreter->AllocateTensors(); + + TfLiteTensor* model_input = interpreter->input(0); + if ((model_input->dims->size != 4) || (model_input->dims->data[0] != 1) || + (model_input->dims->data[1] != raster_height) || + (model_input->dims->data[2] != raster_width) || + (model_input->dims->data[3] != raster_channels) || + (model_input->type != kTfLiteInt8) || + (model_input->params.zero_point != -128) || + (model_input->params.scale != 1.0)) { + TF_LITE_REPORT_ERROR(error_reporter, + "Bad input tensor parameters in model"); + return; + } + + TfLiteTensor* model_output = interpreter->output(0); + if ((model_output->dims->size != 2) || (model_output->dims->data[0] != 1) || + (model_output->dims->data[1] != label_count) || + (model_output->type != kTfLiteInt8)) { + TF_LITE_REPORT_ERROR(error_reporter, + "Bad output tensor parameters in model"); + return; + } +} + +void loop() { + BLEDevice central = BLE.central(); + + // if a central is connected to the peripheral: + static bool was_connected_last = false; + if (central && !was_connected_last) { + // print the central's BT address: + TF_LITE_REPORT_ERROR(error_reporter, "Connected to central: %s", + central.address().c_str()); + } + was_connected_last = central; + + const bool data_available = + IMU.accelerationAvailable() || IMU.gyroscopeAvailable(); + if (!data_available) { + return; + } + + int accelerometer_samples_read; + int gyroscope_samples_read; + ReadAccelerometerAndGyroscope(&accelerometer_samples_read, + &gyroscope_samples_read); + + bool done_just_triggered = false; + if (gyroscope_samples_read > 0) { + EstimateGyroscopeDrift(current_gyroscope_drift); + UpdateOrientation(gyroscope_samples_read, current_gravity, + current_gyroscope_drift); + UpdateStroke(gyroscope_samples_read, &done_just_triggered); + if (central && central.connected()) { + strokeCharacteristic.writeValue(stroke_struct_buffer, + stroke_struct_byte_count); + } + } + + if (accelerometer_samples_read > 0) { + EstimateGravityDirection(current_gravity); + UpdateVelocity(accelerometer_samples_read, current_gravity); + } + + if (done_just_triggered) { + RasterizeStroke(stroke_points, *stroke_transmit_length, 0.6f, 0.6f, + raster_width, raster_height, raster_buffer); + for (int y = 0; y < raster_height; ++y) { + char line[raster_width + 1]; + for (int x = 0; x < raster_width; ++x) { + const int8_t* pixel = + &raster_buffer[(y * raster_width * raster_channels) + + (x * raster_channels)]; + const int8_t red = pixel[0]; + const int8_t green = pixel[1]; + const int8_t blue = pixel[2]; + char output; + if ((red > -128) || (green > -128) || (blue > -128)) { + output = '#'; + } else { + output = '.'; + } + line[x] = output; + } + line[raster_width] = 0; + TF_LITE_REPORT_ERROR(error_reporter, line); + } +#ifdef MAGIC_WAND_DEBUG + TF_LITE_REPORT_ERROR(error_reporter, "tx len: %d", *stroke_transmit_length); +#endif // MAGIC_WAND_DEBUG + + TfLiteTensor* model_input = interpreter->input(0); + for (int i = 0; i < raster_byte_count; ++i) { + model_input->data.int8[i] = raster_buffer[i]; + } + + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed"); + return; + } + + TfLiteTensor* output = interpreter->output(0); + + int8_t max_score; + int max_index; + for (int i = 0; i < label_count; ++i) { + const int8_t score = output->data.int8[i]; + if ((i == 0) || (score > max_score)) { + max_score = score; + max_index = i; + } + } + float max_score_f = + (max_score - output->params.zero_point) * output->params.scale; + float max_score_int; + float max_score_frac = modf(max_score_f * 100, &max_score_int); + TF_LITE_REPORT_ERROR(error_reporter, "Found %s (%d.%d%%)", + labels[max_index], static_cast(max_score_int), + static_cast(max_score_frac * 100)); + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand_model_data.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand_model_data.cpp new file mode 100644 index 000000000..77c8a05e8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand_model_data.cpp @@ -0,0 +1,2588 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. +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. +==============================================================================*/ + +unsigned char g_magic_wand_model_data[] = { + 0x20, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x1c, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x44, 0x01, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xec, 0x06, 0x00, 0x00, + 0xa4, 0x03, 0x00, 0x00, 0xcc, 0x02, 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x3c, 0x78, 0x00, 0x00, 0x38, 0x78, 0x00, 0x00, 0x08, 0x77, 0x00, 0x00, + 0xc4, 0x73, 0x00, 0x00, 0x04, 0x72, 0x00, 0x00, 0x14, 0x5e, 0x00, 0x00, + 0x4c, 0x5b, 0x00, 0x00, 0xdc, 0x0f, 0x00, 0x00, 0x14, 0x0b, 0x00, 0x00, + 0x24, 0x08, 0x00, 0x00, 0x9c, 0x07, 0x00, 0x00, 0x10, 0x78, 0x00, 0x00, + 0x0c, 0x78, 0x00, 0x00, 0x08, 0x78, 0x00, 0x00, 0x04, 0x78, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0xfc, 0x77, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x00, 0x00, 0x00, 0xa6, 0x89, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, + 0x74, 0x5f, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0xee, 0x89, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x31, 0x34, + 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c, 0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x54, 0x76, 0x00, 0x00, 0xdc, 0x75, 0x00, 0x00, + 0x30, 0x74, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0xd0, 0x6e, 0x00, 0x00, + 0x88, 0x5a, 0x00, 0x00, 0x98, 0x56, 0x00, 0x00, 0xd0, 0x0a, 0x00, 0x00, + 0x60, 0x09, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x64, 0x05, 0x00, 0x00, + 0xfc, 0x03, 0x00, 0x00, 0xd0, 0x02, 0x00, 0x00, 0x14, 0x02, 0x00, 0x00, + 0x3c, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0x94, 0x03, 0x00, 0x00, + 0x68, 0x02, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x03, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xda, 0x8a, 0xff, 0xff, 0x00, 0x00, 0x80, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x38, 0xfb, 0xff, 0xff, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x19, 0x02, 0x00, 0x00, 0x00, 0x78, 0x8a, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x53, 0x74, 0x61, 0x74, 0x65, 0x66, 0x75, 0x6c, + 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, + 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x54, 0x8a, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x36, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0x8a, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0xf4, 0xfb, 0xff, 0xff, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x04, 0x00, 0x00, 0x00, 0x34, 0x8b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, + 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x2f, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, + 0x64, 0x64, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x0a, 0x00, 0x00, 0x00, 0x1c, 0x8b, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x12, 0x0b, 0xe6, 0x3d, + 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x07, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3c, 0x8b, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc8, 0xfc, 0xff, 0xff, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x8c, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x14, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x61, 0x76, 0x65, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x69, 0x6e, 0x67, + 0x32, 0x64, 0x2f, 0x4d, 0x65, 0x61, 0x6e, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x40, 0x00, 0x00, 0x00, 0xec, 0x8b, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0xc3, 0x18, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xaa, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x9c, 0xfd, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xc0, 0x8c, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x32, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, + 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x32, 0x2f, + 0x46, 0x75, 0x73, 0x65, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, + 0x72, 0x6d, 0x56, 0x33, 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x32, 0x2f, 0x62, 0x69, 0x61, 0x73, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x2f, 0x42, 0x69, + 0x61, 0x73, 0x41, 0x64, 0x64, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, + 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x44, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x14, 0x8d, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9f, 0x0a, 0x50, 0x3d, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xd2, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc4, 0xfe, 0xff, 0xff, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0xe8, 0x8d, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, + 0xa0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x31, 0x2f, 0x52, + 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x62, 0x61, + 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x31, 0x2f, 0x46, 0x75, 0x73, 0x65, + 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, 0x72, 0x6d, 0x56, 0x33, + 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x62, 0x69, + 0x61, 0x73, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, + 0x64, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x3c, 0x8e, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x07, 0xdf, 0x24, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x07, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0f, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x4c, 0x8f, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x46, 0x75, 0x73, 0x65, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, + 0x72, 0x6d, 0x56, 0x33, 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, + 0x62, 0x69, 0x61, 0x73, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, + 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, + 0x64, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x32, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x94, 0x8f, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0xb1, 0x5b, 0x3d, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xba, 0x90, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x5a, 0xdf, 0xff, 0xff, + 0x44, 0x05, 0x00, 0x00, 0x31, 0xee, 0xff, 0xff, 0x10, 0xf3, 0xff, 0xff, + 0x31, 0xec, 0xff, 0xff, 0x86, 0xea, 0xff, 0xff, 0x34, 0x01, 0x00, 0x00, + 0x98, 0xfe, 0xff, 0xff, 0xe1, 0xe9, 0xff, 0xff, 0x36, 0xf0, 0xff, 0xff, + 0xd2, 0x90, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x2f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, + 0x1c, 0x90, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x41, 0xaf, 0xe2, 0x38, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x91, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0xfd, 0x11, 0x10, 0x9c, + 0x0c, 0x05, 0xf9, 0xfd, 0x09, 0x10, 0x02, 0x1b, 0xee, 0xfc, 0x18, 0x08, + 0xc5, 0x0c, 0x12, 0xf8, 0xf8, 0x12, 0x87, 0x08, 0x26, 0x1f, 0x08, 0xdd, + 0x14, 0xb7, 0x20, 0x09, 0x18, 0x01, 0x9a, 0xfb, 0xd9, 0xf4, 0xda, 0x8f, + 0x02, 0xe6, 0xdd, 0x28, 0x90, 0xeb, 0x10, 0xfe, 0x06, 0x13, 0xae, 0xd7, + 0xf7, 0xad, 0xf7, 0xc1, 0xe4, 0xba, 0x01, 0xa4, 0x03, 0x03, 0x01, 0xe1, + 0xaf, 0x13, 0x0e, 0xde, 0x14, 0x21, 0xad, 0xc1, 0xab, 0x1b, 0xbf, 0x14, + 0x98, 0xb1, 0xe7, 0xa5, 0x20, 0xdf, 0xae, 0x18, 0xbf, 0x29, 0x0b, 0x1c, + 0xa6, 0xc9, 0xa1, 0xcf, 0xb3, 0x17, 0x12, 0xcb, 0x9f, 0x9f, 0x07, 0xb3, + 0xbf, 0x27, 0xc9, 0x05, 0x1c, 0xdf, 0xac, 0xb5, 0x05, 0xb8, 0xad, 0xb2, + 0x16, 0x14, 0xda, 0xfd, 0xa1, 0x15, 0xb1, 0xba, 0x06, 0x01, 0xa4, 0x0f, + 0xa3, 0x21, 0x1c, 0x02, 0x22, 0xbe, 0xfc, 0xb0, 0xad, 0x22, 0x0c, 0xac, + 0x04, 0x15, 0xbd, 0xd8, 0x09, 0x19, 0x03, 0x0d, 0xb9, 0x0c, 0xdb, 0xba, + 0xce, 0x1e, 0x06, 0x21, 0xf7, 0x11, 0xc5, 0x15, 0x15, 0xeb, 0xbc, 0xd3, + 0x1b, 0x13, 0x12, 0x08, 0xbc, 0xd0, 0x1a, 0x12, 0xc9, 0x00, 0xbb, 0xad, + 0x17, 0xa7, 0x08, 0x14, 0xd5, 0xbe, 0xdc, 0x21, 0xa6, 0xdc, 0x1d, 0xc7, + 0xb9, 0xbd, 0xc5, 0xfe, 0xc3, 0xb5, 0xe5, 0xa9, 0xaf, 0x1f, 0x17, 0x1b, + 0x1b, 0xc2, 0x08, 0xb1, 0xcd, 0x0b, 0xe4, 0xd0, 0x12, 0xd7, 0x0c, 0x07, + 0x2b, 0x03, 0x25, 0xfc, 0xfd, 0xcf, 0xfd, 0xa6, 0x2d, 0xc3, 0xab, 0xf9, + 0xfc, 0xde, 0xfc, 0xf3, 0xc7, 0x94, 0x01, 0x13, 0xb3, 0xaf, 0x1e, 0x03, + 0xa9, 0x15, 0xc1, 0xea, 0xf8, 0xad, 0x14, 0xa7, 0xbb, 0x9a, 0x0b, 0xd6, + 0xcf, 0x11, 0x0d, 0x15, 0x9c, 0xc1, 0x14, 0x07, 0xab, 0xc9, 0xca, 0xd3, + 0x22, 0xa2, 0x93, 0x09, 0x13, 0xe2, 0xb6, 0x1a, 0x2a, 0x90, 0x02, 0x13, + 0xac, 0xb0, 0xc5, 0xb2, 0x0f, 0xbe, 0xd1, 0xd8, 0xa6, 0x0f, 0xe1, 0x10, + 0x26, 0xd4, 0xc8, 0x15, 0x16, 0x06, 0xff, 0xae, 0xee, 0xcd, 0x11, 0xbb, + 0xc3, 0xc3, 0x2d, 0xca, 0xd9, 0xc7, 0x16, 0x22, 0xdc, 0x25, 0x14, 0x0f, + 0xb7, 0x00, 0x20, 0x0d, 0x2d, 0xf0, 0xa9, 0xfd, 0xcf, 0x0f, 0xbc, 0xf5, + 0x0f, 0x10, 0x92, 0x19, 0xcb, 0xcb, 0x8a, 0x0d, 0xc6, 0xaa, 0x0a, 0xc9, + 0xbc, 0x97, 0xc8, 0x1d, 0xfa, 0x18, 0x12, 0x87, 0xd8, 0x8c, 0xc5, 0x12, + 0x1c, 0xc9, 0x0e, 0xa9, 0xe2, 0xa9, 0xcc, 0x0f, 0x14, 0xff, 0x15, 0x1c, + 0xab, 0xb5, 0x07, 0x03, 0x24, 0xbb, 0xec, 0x0d, 0xa3, 0xea, 0x0e, 0x24, + 0x15, 0x14, 0xf7, 0xea, 0x11, 0x8c, 0x16, 0xcd, 0xda, 0x00, 0x08, 0x12, + 0xee, 0xe7, 0xf7, 0x03, 0xbf, 0xc8, 0x22, 0x1d, 0x07, 0x09, 0xff, 0x9e, + 0xe5, 0xc2, 0x11, 0xd2, 0xe2, 0xd3, 0x39, 0x12, 0x12, 0xbe, 0x17, 0xf0, + 0xcf, 0x04, 0xf9, 0xa6, 0xda, 0xdf, 0xcd, 0xfc, 0xf2, 0xdb, 0xbf, 0x0f, + 0xc0, 0x0f, 0xb6, 0xf6, 0xcd, 0x17, 0xb3, 0x18, 0x18, 0xc6, 0xd3, 0xe7, + 0x08, 0x1d, 0x14, 0xbd, 0xa8, 0x12, 0xb8, 0x12, 0x12, 0x01, 0x81, 0x0d, + 0xb2, 0xbd, 0xcd, 0xae, 0x1d, 0x35, 0x08, 0xc2, 0xd9, 0xda, 0xf7, 0x02, + 0xc7, 0xa7, 0xc9, 0x10, 0x03, 0x14, 0x0f, 0xb5, 0x27, 0xcf, 0x35, 0xc1, + 0xb6, 0xca, 0xc0, 0x05, 0xf2, 0x15, 0x1e, 0x17, 0x18, 0xa7, 0x09, 0xa6, + 0xdb, 0x21, 0x27, 0xd1, 0xc0, 0x13, 0xb8, 0x24, 0x1d, 0x19, 0x05, 0xc6, + 0xd8, 0x17, 0xa8, 0x0b, 0xa9, 0xd2, 0x9d, 0x19, 0x0e, 0xdc, 0xad, 0xaa, + 0xae, 0xc4, 0x00, 0xb7, 0x0d, 0xf6, 0xbc, 0xd6, 0xd3, 0xdf, 0xa9, 0x0f, + 0xf3, 0x15, 0xd3, 0xc6, 0x16, 0x07, 0x05, 0xfb, 0xbc, 0xc8, 0xc3, 0x1e, + 0xf4, 0xfb, 0xe5, 0xb4, 0xf9, 0x1c, 0xb4, 0x0d, 0xfc, 0x0a, 0x04, 0x16, + 0x1a, 0xe3, 0xc8, 0x07, 0xd1, 0xe1, 0x12, 0xb0, 0xb5, 0xb0, 0xcc, 0x06, + 0xe1, 0x04, 0xa8, 0xd7, 0x1c, 0x1c, 0xda, 0xa8, 0x14, 0xb8, 0x0e, 0xd8, + 0xbf, 0x16, 0xd2, 0x04, 0xfd, 0xfe, 0x2a, 0xc5, 0x26, 0xba, 0x21, 0xba, + 0x0d, 0xe2, 0x15, 0xb0, 0x17, 0xbf, 0x0e, 0x1a, 0xb8, 0xc2, 0xf4, 0x0b, + 0xfc, 0xe7, 0xa3, 0x1e, 0xb9, 0x05, 0xdb, 0xa2, 0x0a, 0x1b, 0x9f, 0x0e, + 0xe0, 0x9d, 0xa9, 0xbc, 0xa6, 0xca, 0x15, 0xbc, 0xce, 0x11, 0x2c, 0x90, + 0x0b, 0xf1, 0x19, 0xa0, 0x09, 0xfd, 0xfb, 0xb3, 0xa7, 0xbb, 0xc0, 0xfa, + 0xd0, 0x1e, 0x04, 0xf2, 0x0d, 0xbe, 0x10, 0x06, 0xbe, 0x21, 0xf6, 0x1a, + 0xe6, 0x11, 0xf5, 0x25, 0x2e, 0x1b, 0x19, 0x03, 0x1c, 0xe5, 0x96, 0x92, + 0xae, 0x93, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x10, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x64, 0x65, + 0x6e, 0x73, 0x65, 0x2f, 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x00, 0x00, + 0x04, 0x93, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xb4, 0xf0, 0x3d, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x94, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0xe9, 0x01, 0x00, 0x00, 0xfb, 0x07, 0x00, 0x00, 0x42, 0x05, 0x00, 0x00, + 0x3c, 0xe7, 0xff, 0xff, 0x6e, 0xf8, 0xff, 0xff, 0xa8, 0xf0, 0xff, 0xff, + 0x13, 0xfa, 0xff, 0xff, 0x06, 0xfe, 0xff, 0xff, 0xca, 0xfd, 0xff, 0xff, + 0xcd, 0x02, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xc1, 0xf8, 0xff, 0xff, + 0xfb, 0xfe, 0xff, 0xff, 0x13, 0xfb, 0xff, 0xff, 0x99, 0xff, 0xff, 0xff, + 0x75, 0x05, 0x00, 0x00, 0x73, 0xf4, 0xff, 0xff, 0x3e, 0x08, 0x00, 0x00, + 0x41, 0x07, 0x00, 0x00, 0xae, 0xee, 0xff, 0xff, 0xc3, 0xf3, 0xff, 0xff, + 0xa3, 0xfa, 0xff, 0xff, 0xf1, 0xf5, 0xff, 0xff, 0xdb, 0xfe, 0xff, 0xff, + 0xae, 0x03, 0x00, 0x00, 0x25, 0xfe, 0xff, 0xff, 0xb8, 0xfd, 0xff, 0xff, + 0xa6, 0xf5, 0xff, 0xff, 0x51, 0xee, 0xff, 0xff, 0xcd, 0xff, 0xff, 0xff, + 0xd2, 0xef, 0xff, 0xff, 0x80, 0xf6, 0xff, 0xff, 0x90, 0xfd, 0xff, 0xff, + 0x8c, 0xfe, 0xff, 0xff, 0x42, 0xf1, 0xff, 0xff, 0x43, 0x00, 0x00, 0x00, + 0xa6, 0xff, 0xff, 0xff, 0x05, 0xfb, 0xff, 0xff, 0x7e, 0xf1, 0xff, 0xff, + 0x93, 0xf5, 0xff, 0xff, 0x65, 0x03, 0x00, 0x00, 0x92, 0xf2, 0xff, 0xff, + 0x13, 0xfa, 0xff, 0xff, 0xd4, 0xeb, 0xff, 0xff, 0x81, 0xef, 0xff, 0xff, + 0x9f, 0xfb, 0xff, 0xff, 0xa5, 0xf6, 0xff, 0xff, 0x14, 0x01, 0x00, 0x00, + 0x29, 0xfe, 0xff, 0xff, 0xe2, 0x00, 0x00, 0x00, 0x2b, 0xef, 0xff, 0xff, + 0x96, 0xec, 0xff, 0xff, 0xa0, 0x02, 0x00, 0x00, 0xbd, 0xf4, 0xff, 0xff, + 0x8e, 0xfb, 0xff, 0xff, 0x23, 0xe7, 0xff, 0xff, 0xa9, 0xf6, 0xff, 0xff, + 0xc4, 0xf5, 0xff, 0xff, 0x41, 0x02, 0x00, 0x00, 0xe4, 0xf7, 0xff, 0xff, + 0xbc, 0x00, 0x00, 0x00, 0x1d, 0xf4, 0xff, 0xff, 0xea, 0xf9, 0xff, 0xff, + 0x59, 0xf7, 0xff, 0xff, 0x1a, 0x95, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, + 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x7f, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x32, 0x2f, 0x52, + 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x62, 0x61, + 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x32, 0x2f, 0x46, 0x75, 0x73, 0x65, + 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, 0x72, 0x6d, 0x56, 0x33, + 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x2f, 0x62, 0x69, + 0x61, 0x73, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x32, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, + 0x64, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x5f, 0x32, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x00, + 0xd8, 0x94, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x4c, 0x5d, 0x06, 0x39, 0xf5, 0x73, 0x03, 0x39, + 0x79, 0x31, 0x0a, 0x39, 0x60, 0xd6, 0xf8, 0x38, 0x45, 0x5f, 0x24, 0x39, + 0x7d, 0xca, 0xfa, 0x38, 0xa6, 0x58, 0xfa, 0x38, 0xb0, 0xa4, 0x0c, 0x39, + 0x88, 0xf1, 0x01, 0x39, 0x62, 0xe2, 0xe0, 0x38, 0x08, 0xe8, 0xdd, 0x38, + 0x54, 0x03, 0x14, 0x39, 0x6a, 0xad, 0xe7, 0x38, 0xf6, 0xf4, 0xf1, 0x38, + 0xe4, 0x84, 0xee, 0x38, 0x80, 0xba, 0x17, 0x39, 0x74, 0xe1, 0x23, 0x39, + 0x91, 0x30, 0x1f, 0x39, 0x5d, 0x23, 0x18, 0x39, 0xca, 0x32, 0x0f, 0x39, + 0xe6, 0xac, 0xf1, 0x38, 0xcf, 0x67, 0x18, 0x39, 0x83, 0x61, 0xe2, 0x38, + 0xec, 0x4b, 0x1e, 0x39, 0x77, 0x65, 0xf6, 0x38, 0xfb, 0xba, 0x0a, 0x39, + 0x88, 0x47, 0xdd, 0x38, 0x8e, 0xda, 0x06, 0x39, 0xa1, 0xc4, 0x18, 0x39, + 0x1c, 0xcf, 0x13, 0x39, 0x1d, 0x16, 0x0e, 0x39, 0x8f, 0x16, 0x04, 0x39, + 0xec, 0x47, 0x0d, 0x39, 0x6c, 0x30, 0xbb, 0x38, 0x46, 0xe5, 0x00, 0x39, + 0xe9, 0x16, 0xf9, 0x38, 0x5c, 0x5d, 0xd1, 0x38, 0xb6, 0x54, 0x13, 0x39, + 0x2c, 0x83, 0xd3, 0x38, 0x24, 0xe1, 0xce, 0x38, 0x37, 0x2f, 0x1f, 0x39, + 0x0d, 0xcd, 0xf9, 0x38, 0x8d, 0x4a, 0x07, 0x39, 0x70, 0xc0, 0xf9, 0x38, + 0xa6, 0x21, 0xe0, 0x38, 0x19, 0xf1, 0xe5, 0x38, 0x87, 0x56, 0xf1, 0x38, + 0xee, 0x11, 0x16, 0x39, 0x44, 0xc2, 0x0a, 0x39, 0x9d, 0xdc, 0x0c, 0x39, + 0x25, 0xf1, 0xd6, 0x38, 0x2c, 0x2e, 0xec, 0x38, 0x6e, 0xee, 0xc6, 0x38, + 0x65, 0x77, 0x0f, 0x39, 0xf9, 0x7e, 0x1c, 0x39, 0x51, 0x7b, 0xec, 0x38, + 0x0f, 0xac, 0xfd, 0x38, 0x75, 0xef, 0xde, 0x38, 0x13, 0xa4, 0x15, 0x39, + 0xcd, 0x7a, 0x21, 0x39, 0x5c, 0x79, 0x0d, 0x39, 0x50, 0x85, 0xf6, 0x38, + 0x5e, 0xf5, 0x0f, 0x39, 0x87, 0x0a, 0xd5, 0x38, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x98, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x43, 0x2b, 0x15, 0x0a, + 0xef, 0x23, 0x2f, 0x08, 0xf1, 0x1e, 0xf0, 0x11, 0x20, 0x22, 0x2f, 0xfd, + 0x05, 0x25, 0xf8, 0xf8, 0xd0, 0x13, 0xf1, 0xda, 0xfa, 0xc7, 0x11, 0xe4, + 0xee, 0xff, 0xea, 0x1f, 0x08, 0x23, 0x35, 0xd1, 0x3d, 0x30, 0xe2, 0xf8, + 0x0f, 0xf6, 0xed, 0xe3, 0xdc, 0xf6, 0xe2, 0xbb, 0xe4, 0xe1, 0xb6, 0x38, + 0xc1, 0xeb, 0x40, 0xe3, 0x13, 0x04, 0xf2, 0xea, 0x04, 0xe6, 0xfa, 0xe5, + 0x18, 0x1e, 0x03, 0xd4, 0xf3, 0x0e, 0x14, 0x21, 0xe9, 0x24, 0xf0, 0xf7, + 0xfb, 0x05, 0x00, 0x0f, 0xf9, 0x23, 0xe3, 0x26, 0xda, 0xff, 0x13, 0xce, + 0x00, 0xe9, 0x1f, 0xf0, 0xf8, 0xe7, 0xeb, 0x0b, 0xdc, 0xf7, 0xff, 0x33, + 0x0f, 0xf8, 0xf1, 0x26, 0x12, 0x07, 0x1a, 0xde, 0xd6, 0x0b, 0x02, 0xfa, + 0xd3, 0x41, 0x27, 0x0a, 0x10, 0x18, 0x1e, 0x04, 0x35, 0x13, 0xeb, 0x15, + 0x06, 0xe3, 0x24, 0x1a, 0x2b, 0xc5, 0x0c, 0x35, 0xf2, 0xf4, 0x11, 0x13, + 0x0d, 0x01, 0xe1, 0xbf, 0x9e, 0x07, 0xdc, 0xdf, 0xde, 0x34, 0x39, 0x18, + 0xf6, 0x26, 0x00, 0xdc, 0x04, 0xf7, 0xf2, 0x23, 0x09, 0xe0, 0xf8, 0xce, + 0xf7, 0x30, 0xd5, 0x35, 0x23, 0x01, 0xe7, 0x28, 0x02, 0xf9, 0x19, 0xd3, + 0x11, 0xff, 0xe4, 0xff, 0xcd, 0x4b, 0x32, 0x35, 0x04, 0x7f, 0x13, 0xd8, + 0x48, 0x01, 0xf0, 0xfc, 0x18, 0x06, 0x18, 0x09, 0x3f, 0xfc, 0x19, 0xb2, + 0xf6, 0x3a, 0x0b, 0x1c, 0xf1, 0xf5, 0xee, 0xf0, 0xf9, 0x27, 0x09, 0xd0, + 0xf3, 0xe6, 0xee, 0x38, 0xa4, 0xef, 0xdc, 0xfd, 0xf2, 0x8d, 0xef, 0xe5, + 0xf9, 0xd0, 0xe1, 0x02, 0xe9, 0x31, 0x21, 0x9b, 0x60, 0x39, 0xd5, 0x1d, + 0xf8, 0xc2, 0xce, 0xd2, 0xc8, 0xb0, 0xdf, 0xc3, 0x11, 0xca, 0xa9, 0x51, + 0xc2, 0xcb, 0x1e, 0xe4, 0xf0, 0xe8, 0xd1, 0xc3, 0xe8, 0xc3, 0xd8, 0xd4, + 0x20, 0x1b, 0x29, 0xc0, 0xfc, 0x1a, 0x1c, 0x07, 0xfa, 0x17, 0xee, 0x06, + 0xf6, 0x0d, 0x2b, 0xf1, 0xef, 0x34, 0xdd, 0x36, 0xcd, 0x19, 0x0d, 0xb5, + 0xf1, 0xc3, 0xff, 0xe6, 0xe5, 0xdf, 0xcf, 0x16, 0xfd, 0x05, 0xe3, 0x0e, + 0x19, 0x3a, 0xe1, 0x24, 0x20, 0xe4, 0xe5, 0x23, 0x2f, 0x0a, 0x10, 0x02, + 0xeb, 0x07, 0x12, 0x1e, 0xc9, 0x2f, 0xfb, 0xe6, 0xeb, 0x02, 0x13, 0x02, + 0x07, 0xfc, 0x0c, 0x1a, 0xfa, 0xf2, 0xe8, 0x53, 0x12, 0x09, 0x07, 0x06, + 0x05, 0xb6, 0xfb, 0x0c, 0x13, 0xff, 0x49, 0xec, 0x05, 0x14, 0x57, 0xfe, + 0xd9, 0x29, 0xe6, 0xd6, 0x0e, 0x00, 0x04, 0x04, 0xf7, 0x61, 0x1e, 0x7f, + 0xe4, 0xef, 0x09, 0x28, 0xe8, 0x15, 0xef, 0x1f, 0xf9, 0xf1, 0xae, 0x0a, + 0x27, 0xfe, 0xed, 0x0c, 0x08, 0xe9, 0x1d, 0x04, 0xde, 0x2d, 0xd9, 0xf0, + 0xcc, 0xf2, 0x20, 0x15, 0xdc, 0x00, 0xfa, 0x03, 0xde, 0xf5, 0xdf, 0x11, + 0xf8, 0xec, 0xf3, 0xfb, 0xfe, 0xeb, 0xd1, 0x25, 0x23, 0x10, 0x1e, 0x0d, + 0xda, 0xbd, 0xf3, 0x3c, 0xea, 0xe9, 0xea, 0xf5, 0x2e, 0xef, 0x09, 0xc8, + 0x03, 0xe6, 0xd0, 0x2f, 0x11, 0x03, 0x0f, 0xfe, 0x14, 0x08, 0xce, 0x29, + 0x31, 0xeb, 0xe5, 0x0d, 0x08, 0x08, 0xfb, 0xfa, 0x03, 0x13, 0x62, 0xe8, + 0xe2, 0x19, 0xec, 0xe2, 0x36, 0xf8, 0x0a, 0xf7, 0xf2, 0x31, 0x11, 0x4c, + 0xf5, 0xef, 0xde, 0x10, 0xde, 0x01, 0xf8, 0xcb, 0xf7, 0xfa, 0xe1, 0x11, + 0xf8, 0xfc, 0x16, 0x06, 0xf3, 0xb9, 0xfc, 0x22, 0xfa, 0xf7, 0xf1, 0xf8, + 0x1b, 0x08, 0xfe, 0xe4, 0xfb, 0xf5, 0xcf, 0x13, 0xf1, 0xba, 0xcd, 0x33, + 0xda, 0xca, 0xa5, 0xe5, 0xfe, 0x9c, 0xe2, 0xfa, 0x2a, 0xe4, 0x13, 0xfd, + 0xdd, 0xbd, 0x27, 0xe4, 0x9e, 0x10, 0xd3, 0xf0, 0x04, 0xfa, 0xee, 0xce, + 0xf3, 0xb7, 0xc9, 0xe9, 0xc9, 0xee, 0xdd, 0x41, 0xdc, 0xd7, 0x25, 0x19, + 0x09, 0xe2, 0xbc, 0x30, 0xfc, 0x3e, 0x38, 0x17, 0x06, 0xd9, 0x45, 0xdd, + 0x1d, 0x16, 0xe9, 0xe3, 0xeb, 0xf4, 0xee, 0xad, 0xf1, 0x73, 0x15, 0x60, + 0xe5, 0xf4, 0x03, 0x20, 0xd0, 0xdf, 0xab, 0x14, 0xef, 0xd6, 0xbb, 0xe5, + 0x1b, 0x05, 0xde, 0xef, 0xf1, 0xc9, 0x09, 0xf0, 0xa2, 0x0e, 0xc4, 0x08, + 0xfe, 0xf1, 0x02, 0xf5, 0xfb, 0xbf, 0xd8, 0xf1, 0x04, 0x1d, 0xe6, 0xfa, + 0x0c, 0x12, 0xfc, 0x35, 0x1d, 0xf6, 0xdf, 0x1b, 0x59, 0x13, 0x06, 0x09, + 0x00, 0xff, 0x1c, 0x23, 0xc5, 0x2a, 0xee, 0xde, 0xee, 0xfd, 0x14, 0x0e, + 0xfb, 0x06, 0x0b, 0xfb, 0xf2, 0x25, 0xeb, 0x0a, 0xe7, 0xf4, 0xf8, 0x13, + 0x16, 0xec, 0x00, 0x21, 0x1b, 0x0e, 0x3d, 0xfa, 0xfd, 0x31, 0x2f, 0xf1, + 0xea, 0x22, 0xe0, 0xe9, 0x03, 0xed, 0x04, 0xf7, 0xdd, 0x54, 0x36, 0x7f, + 0xea, 0x19, 0xf5, 0x18, 0xe4, 0xf9, 0xd1, 0x10, 0xf1, 0x02, 0xbc, 0x12, + 0x1c, 0xf3, 0xff, 0x11, 0x0c, 0xda, 0x0a, 0xeb, 0xec, 0x09, 0xd7, 0x04, + 0xdf, 0xcb, 0x13, 0x09, 0x07, 0x01, 0xf9, 0xf9, 0x0a, 0x16, 0xdd, 0x3f, + 0xd4, 0xe4, 0xf4, 0x07, 0xfa, 0xf3, 0xc4, 0x2b, 0x63, 0xff, 0x39, 0x1b, + 0x13, 0xc1, 0xe5, 0x43, 0xed, 0x0d, 0xf4, 0xf2, 0xdf, 0x02, 0x43, 0xc3, + 0x03, 0xab, 0xde, 0x1a, 0x2c, 0x04, 0x31, 0x20, 0xff, 0x09, 0xeb, 0x23, + 0x19, 0x00, 0xc9, 0x25, 0x32, 0xf2, 0x13, 0x2c, 0x27, 0x01, 0x5e, 0xd3, + 0xef, 0x56, 0x04, 0xea, 0xf7, 0xf6, 0x28, 0xf7, 0xfa, 0x03, 0x03, 0x2e, + 0xfc, 0x14, 0xf5, 0x33, 0xc2, 0xf0, 0xfb, 0xf9, 0x01, 0xf1, 0xf3, 0x0b, + 0x2a, 0xfe, 0x0c, 0x2d, 0x09, 0xc4, 0xf4, 0x15, 0x17, 0x0a, 0xed, 0x10, + 0xf0, 0x02, 0x39, 0xbd, 0xec, 0xcd, 0xdf, 0x05, 0x0c, 0xf3, 0xe4, 0x07, + 0xdc, 0xdd, 0x8b, 0x03, 0xdf, 0xa2, 0xf0, 0xea, 0x37, 0xe5, 0x00, 0x0a, + 0xcf, 0xdc, 0x11, 0x09, 0x9c, 0x17, 0xfc, 0xf0, 0xf1, 0xe2, 0xef, 0x05, + 0xc9, 0x9a, 0xd1, 0x05, 0xd4, 0x0b, 0x13, 0x21, 0xea, 0xe2, 0x22, 0xf6, + 0x06, 0x13, 0xc9, 0x21, 0xf4, 0x22, 0x35, 0x00, 0x03, 0x1b, 0x23, 0xd6, + 0x19, 0xfc, 0x01, 0xda, 0xfe, 0x04, 0xfe, 0xd5, 0xdf, 0x41, 0x26, 0x64, + 0xe3, 0x17, 0x06, 0x11, 0xc6, 0xd9, 0xc1, 0x11, 0xdb, 0xd7, 0xb0, 0xf6, + 0x24, 0x05, 0xf2, 0x02, 0x00, 0xd7, 0x0b, 0xf5, 0xc9, 0x05, 0xc8, 0x15, + 0xcb, 0xec, 0xef, 0x05, 0x05, 0xd7, 0xee, 0x09, 0x33, 0xbd, 0xd5, 0x09, + 0xfd, 0xee, 0x52, 0xc4, 0x0b, 0x09, 0x00, 0x19, 0xd3, 0xad, 0x02, 0xdd, + 0xdc, 0xfe, 0x0e, 0xd8, 0x0a, 0xfd, 0x1e, 0x06, 0xf6, 0x2f, 0xd9, 0x0b, + 0x11, 0x2c, 0x05, 0xe5, 0x12, 0xcb, 0xe4, 0x0b, 0xd2, 0xdd, 0xff, 0xe3, + 0xd4, 0xf4, 0x4b, 0x16, 0xf5, 0xd8, 0x23, 0x0b, 0x56, 0x0c, 0xfc, 0xf9, + 0x36, 0x0a, 0x1d, 0x03, 0xee, 0xee, 0xff, 0xf4, 0xfe, 0x14, 0xed, 0x0b, + 0x17, 0xc6, 0xe6, 0x08, 0xef, 0xe7, 0x20, 0xe5, 0x05, 0x02, 0x24, 0x13, + 0xc2, 0xd1, 0x19, 0x1d, 0x05, 0x04, 0x10, 0xef, 0x2d, 0x00, 0x22, 0x04, + 0x03, 0x0c, 0x14, 0x21, 0x19, 0x1e, 0xf8, 0xe7, 0x16, 0xe9, 0x0c, 0xa2, + 0x10, 0x05, 0x20, 0xc9, 0xf1, 0x0e, 0xfd, 0xe6, 0x12, 0x0e, 0xe6, 0xfd, + 0xe6, 0x19, 0xc0, 0xba, 0x0b, 0xb1, 0x23, 0x0a, 0xdb, 0x1e, 0xbe, 0xe8, + 0x1b, 0x2e, 0x20, 0xee, 0xf6, 0x17, 0x25, 0xca, 0x29, 0x2a, 0x16, 0x09, + 0xc0, 0x0d, 0x16, 0xfe, 0x00, 0xf3, 0xfc, 0x08, 0x26, 0xed, 0x8e, 0x18, + 0x16, 0xd6, 0x2b, 0x02, 0xe3, 0x41, 0xb9, 0xdf, 0xe3, 0x12, 0xfe, 0xf6, + 0xe4, 0x07, 0x3c, 0xe3, 0x0a, 0xf6, 0x24, 0xd9, 0xf2, 0x31, 0x17, 0x11, + 0xe0, 0x2f, 0xb1, 0xf9, 0x26, 0xd4, 0xd5, 0x0b, 0x2e, 0xc3, 0x1a, 0x30, + 0xb7, 0x2f, 0xc0, 0xeb, 0x10, 0x24, 0x02, 0xd6, 0xff, 0x03, 0xef, 0xc4, + 0xed, 0xdf, 0x1d, 0xc1, 0xf3, 0x15, 0x1a, 0xf4, 0x1a, 0xe8, 0xf8, 0xde, + 0xcf, 0x0e, 0xf4, 0xe7, 0x40, 0x00, 0x16, 0x30, 0xe5, 0x10, 0xcf, 0xff, + 0x03, 0xf8, 0xd1, 0xfb, 0xf4, 0xd7, 0xe9, 0x0f, 0x02, 0xdb, 0xdd, 0xdb, + 0xe0, 0xef, 0x3a, 0xe5, 0xed, 0xc9, 0x24, 0xde, 0x22, 0x0d, 0xff, 0xf6, + 0x42, 0xe2, 0x0a, 0x30, 0xe5, 0x0a, 0xe6, 0xf1, 0x00, 0xd5, 0xe2, 0x1c, + 0xfb, 0xf8, 0xca, 0x08, 0xfa, 0xdc, 0xec, 0xeb, 0xeb, 0x42, 0x37, 0x03, + 0xd3, 0xd7, 0xe6, 0xe8, 0xe4, 0xdb, 0x1a, 0xf5, 0x66, 0xf8, 0x1c, 0x7f, + 0xfe, 0x0d, 0xde, 0xdd, 0x24, 0x08, 0x07, 0xfe, 0x17, 0xd4, 0x0d, 0x02, + 0xd4, 0xde, 0x13, 0xe0, 0xef, 0xfb, 0xfa, 0x0d, 0xf5, 0x0a, 0x06, 0x08, + 0x13, 0x0e, 0x04, 0xce, 0xf7, 0xec, 0xeb, 0x04, 0xe9, 0xd8, 0x0c, 0x0f, + 0x1f, 0x10, 0xef, 0xed, 0xf4, 0xed, 0xed, 0xfc, 0x05, 0xeb, 0x18, 0xef, + 0x26, 0xe9, 0x08, 0x06, 0xef, 0x2c, 0x33, 0xf3, 0x01, 0xfd, 0x24, 0xec, + 0xf2, 0xfa, 0x1c, 0xf4, 0xf4, 0xbb, 0xf8, 0xe2, 0xe5, 0x59, 0x2f, 0x1b, + 0x08, 0xec, 0x0c, 0x06, 0xec, 0xc7, 0xe5, 0xeb, 0xf9, 0xed, 0xe8, 0xfc, + 0xfe, 0xe0, 0xfb, 0x1e, 0x16, 0x1d, 0x0e, 0xdb, 0x01, 0xf1, 0xf4, 0x16, + 0xda, 0xdb, 0x10, 0x39, 0x4c, 0x08, 0xff, 0xdf, 0x47, 0xfe, 0xfc, 0xd5, + 0xc6, 0x12, 0x11, 0xe3, 0xd2, 0xe7, 0xed, 0x14, 0xe4, 0x15, 0x07, 0xf0, + 0xec, 0xce, 0xd3, 0x19, 0x13, 0xe8, 0xf4, 0xfd, 0x0b, 0xfc, 0xe6, 0xad, + 0x34, 0x2d, 0xf2, 0xdd, 0xd4, 0x16, 0x30, 0xf3, 0x25, 0x4a, 0x07, 0x22, + 0x3f, 0x01, 0x1b, 0x25, 0xda, 0x12, 0xec, 0x1a, 0x1b, 0xb8, 0x02, 0xee, + 0xef, 0x13, 0xf4, 0xf5, 0xed, 0xdf, 0x0a, 0xdb, 0x0d, 0x53, 0x2b, 0x04, + 0x37, 0xfb, 0x02, 0xdc, 0xdd, 0x00, 0x01, 0xda, 0xf8, 0x0a, 0xef, 0x1a, + 0xeb, 0x01, 0xea, 0xfe, 0xe9, 0xdb, 0xe5, 0x13, 0x11, 0xc7, 0x04, 0x1c, + 0x08, 0x13, 0xee, 0xb6, 0x30, 0x3d, 0x05, 0xf0, 0x25, 0xe9, 0x09, 0x0e, + 0xdb, 0xd6, 0x14, 0xcc, 0xe8, 0xd1, 0xff, 0x0a, 0xef, 0x1b, 0xec, 0xf4, + 0x1a, 0x06, 0x1f, 0xdd, 0xf6, 0xfa, 0xfb, 0x17, 0xfa, 0xc5, 0xd5, 0x0c, + 0x5f, 0x10, 0xf8, 0xfb, 0xe6, 0xeb, 0xfa, 0x0b, 0x06, 0x0a, 0x19, 0xf4, + 0x03, 0xf6, 0xe9, 0x10, 0xee, 0x2d, 0x33, 0xf1, 0xfa, 0xf6, 0x1d, 0xf1, + 0x0b, 0xee, 0x33, 0x01, 0xf2, 0xd2, 0xf4, 0xe9, 0xf2, 0x54, 0x33, 0x26, + 0xfc, 0xd1, 0xe0, 0x1b, 0xe7, 0xf5, 0x14, 0xe5, 0x24, 0xe4, 0x00, 0xf8, + 0xfe, 0xea, 0xe2, 0x02, 0xf4, 0xe7, 0x17, 0xce, 0x34, 0xe7, 0xf7, 0x7c, + 0xf2, 0xea, 0xf5, 0xf9, 0x7f, 0x37, 0x05, 0xca, 0x02, 0x3f, 0x50, 0xb4, + 0xd8, 0xde, 0xf6, 0xf3, 0xcb, 0x16, 0xf1, 0xef, 0x24, 0xf9, 0xe3, 0x13, + 0x18, 0x04, 0xcd, 0xb1, 0x12, 0xf2, 0xd8, 0xfb, 0xf7, 0x8f, 0x10, 0x07, + 0x24, 0xdd, 0x0a, 0xfb, 0x2e, 0x5c, 0x26, 0xd1, 0xab, 0x0b, 0xc6, 0x00, + 0xf4, 0xf4, 0xf4, 0x02, 0x0f, 0x7f, 0xee, 0x1a, 0x0a, 0xc9, 0x09, 0xd1, + 0xce, 0xea, 0xdb, 0x0c, 0x0f, 0x07, 0x1b, 0x07, 0x09, 0xce, 0x42, 0xfd, + 0x06, 0x4b, 0x3b, 0xd0, 0xed, 0xc7, 0x15, 0xfe, 0xf0, 0x11, 0xd6, 0x08, + 0x23, 0x06, 0xeb, 0x1a, 0x0c, 0xf7, 0xd5, 0xd3, 0x10, 0x00, 0xd5, 0x0c, + 0x05, 0xad, 0x16, 0x23, 0x1c, 0xf6, 0x05, 0xff, 0xf1, 0xfc, 0x16, 0x35, + 0xe3, 0xe7, 0x15, 0x1c, 0xe2, 0xfa, 0x3b, 0xd4, 0x56, 0x05, 0xfc, 0x15, + 0x0c, 0xfc, 0xfe, 0xc9, 0x10, 0x39, 0x02, 0x02, 0xef, 0x07, 0x07, 0xe8, + 0x1f, 0xfd, 0x15, 0xae, 0xe5, 0xec, 0x05, 0x4c, 0xcf, 0xce, 0x32, 0x11, + 0xcc, 0x34, 0xd8, 0x05, 0x23, 0x18, 0xe4, 0x21, 0xf5, 0xdc, 0x15, 0xac, + 0x29, 0xfb, 0x1b, 0xf5, 0xaa, 0x1d, 0xe8, 0x0e, 0x0d, 0x17, 0x44, 0xfb, + 0x13, 0x20, 0xed, 0x3d, 0xea, 0x03, 0xf9, 0x04, 0xea, 0x05, 0x1f, 0xbb, + 0x2e, 0x11, 0xa5, 0xe8, 0xed, 0xe8, 0x00, 0xe4, 0x0a, 0x36, 0xfe, 0x04, + 0x48, 0x02, 0x28, 0xb5, 0x16, 0x1a, 0x33, 0x9c, 0xf2, 0x48, 0x5b, 0xda, + 0xeb, 0xfe, 0x0d, 0xf6, 0xc8, 0x1e, 0x0d, 0x11, 0x0b, 0x0c, 0xec, 0xfd, + 0x02, 0x10, 0xcb, 0xdf, 0x29, 0xe7, 0xe8, 0x0c, 0xe3, 0xe1, 0xf5, 0xef, + 0x0e, 0x02, 0x08, 0xf8, 0xea, 0x7f, 0x5e, 0xec, 0xcc, 0x14, 0xec, 0xf5, + 0xee, 0x16, 0x1e, 0xe9, 0x23, 0x46, 0xb5, 0x1a, 0xf0, 0xec, 0x15, 0xe7, + 0xf8, 0xe1, 0xe5, 0x1d, 0xd8, 0x10, 0xfd, 0xef, 0x1f, 0xe4, 0x40, 0x06, + 0xe3, 0xfd, 0x2f, 0xd3, 0xeb, 0xdf, 0x10, 0xd8, 0x12, 0x05, 0xee, 0xfa, + 0x39, 0xf3, 0xe2, 0xee, 0xfc, 0xfe, 0xb9, 0xe4, 0x57, 0x05, 0xf5, 0x6d, + 0xf7, 0xc2, 0xe2, 0xcf, 0x42, 0xde, 0xe7, 0x00, 0xf6, 0xda, 0xf4, 0x0b, + 0xed, 0xdc, 0xca, 0x0b, 0x02, 0x0a, 0x05, 0xd1, 0xe8, 0xf1, 0x0e, 0x13, + 0x4d, 0xe6, 0x04, 0xdc, 0xdf, 0xdc, 0xd0, 0x00, 0x1a, 0xd1, 0x39, 0x2a, + 0x9d, 0xcd, 0x1a, 0xe4, 0x57, 0xf4, 0xd5, 0x30, 0xe0, 0x0d, 0x25, 0xe8, + 0x0f, 0x1c, 0x26, 0xfb, 0xfd, 0xcf, 0x32, 0x6b, 0x33, 0xdc, 0xc9, 0xe2, + 0xf3, 0x1c, 0xd7, 0xfe, 0x5f, 0xf3, 0x7f, 0x2c, 0xe5, 0xe7, 0xe6, 0xea, + 0x05, 0x09, 0xf5, 0x29, 0xc5, 0xda, 0xcd, 0xff, 0xed, 0xbb, 0x20, 0xf2, + 0xee, 0xe7, 0xf7, 0x38, 0x4d, 0xf7, 0xe9, 0xe8, 0x05, 0xf3, 0xc7, 0x07, + 0x47, 0xae, 0x16, 0xea, 0xda, 0xde, 0x0c, 0xf0, 0xb1, 0x05, 0xed, 0x0c, + 0x0a, 0xdb, 0x0f, 0xd7, 0xfd, 0xf6, 0x01, 0xf5, 0xf7, 0xf1, 0xd7, 0x10, + 0x3b, 0x0f, 0x19, 0xf2, 0xea, 0x67, 0xb8, 0xea, 0x21, 0xb7, 0xe9, 0x32, + 0xd3, 0xfd, 0x00, 0xe7, 0xf0, 0x1d, 0xf4, 0x46, 0xf1, 0xde, 0xee, 0xc7, + 0xe4, 0xff, 0xee, 0xf5, 0x20, 0xca, 0xf3, 0x08, 0x1d, 0x03, 0xa0, 0xde, + 0xe9, 0x22, 0xf7, 0xfa, 0xbb, 0xce, 0xe9, 0x11, 0xd4, 0xd6, 0xb0, 0xd5, + 0xe0, 0xcb, 0xf0, 0x32, 0x1a, 0xe9, 0x15, 0xe3, 0xe6, 0x3a, 0x2a, 0xe2, + 0xd9, 0xfe, 0xcf, 0x16, 0x31, 0x11, 0x0e, 0xcd, 0xf9, 0x3b, 0xc7, 0xe4, + 0x37, 0xf5, 0x11, 0x3d, 0xbe, 0x1b, 0x16, 0xd1, 0x0a, 0x05, 0x35, 0x39, + 0xfc, 0x2c, 0x1d, 0x0f, 0xf5, 0xf4, 0x0e, 0x11, 0xd8, 0x0f, 0x14, 0x26, + 0x41, 0xf5, 0xfb, 0xf1, 0x17, 0xe2, 0xf6, 0xe1, 0x13, 0xe9, 0x53, 0x0e, + 0xe4, 0x13, 0x0c, 0xe7, 0x24, 0xe5, 0x09, 0x6d, 0xe3, 0x46, 0x40, 0xed, + 0x21, 0x3f, 0x23, 0xf2, 0x0f, 0x06, 0x45, 0x5f, 0x28, 0xd9, 0xd6, 0xf1, + 0x19, 0x22, 0xe0, 0xf8, 0x72, 0x3a, 0x62, 0xfd, 0x0f, 0xff, 0xdf, 0xd9, + 0x17, 0x04, 0x16, 0x25, 0xdb, 0x12, 0x14, 0x0f, 0xfa, 0x06, 0x49, 0x19, + 0xd8, 0xff, 0x1e, 0x38, 0x3f, 0x05, 0xf9, 0xdf, 0x51, 0xf7, 0xdb, 0x27, + 0x33, 0xdb, 0x37, 0x0f, 0xf9, 0x04, 0x00, 0xe1, 0xed, 0xf8, 0x16, 0xd1, + 0x10, 0x1f, 0x15, 0xe9, 0x03, 0x14, 0xbd, 0xfb, 0xf6, 0x05, 0x11, 0xb3, + 0xd6, 0xfe, 0x0f, 0x05, 0xf3, 0xeb, 0x23, 0xff, 0xa1, 0x17, 0xad, 0x30, + 0x0f, 0xf2, 0xe2, 0x28, 0xee, 0xf9, 0x1e, 0xd5, 0x25, 0xf6, 0xe2, 0x27, + 0xaf, 0xd4, 0xe0, 0xee, 0x0a, 0xda, 0xe6, 0xaa, 0xfa, 0x51, 0xd6, 0x21, + 0xf5, 0x0c, 0xfb, 0x02, 0x8d, 0xe5, 0x93, 0x42, 0xed, 0xf7, 0x07, 0xe8, + 0x1d, 0x09, 0x06, 0xe1, 0x04, 0x11, 0x0d, 0x09, 0x2f, 0xf5, 0xe5, 0x07, + 0x02, 0x08, 0xe6, 0xa2, 0xcc, 0x03, 0x1c, 0xfc, 0xf0, 0xf2, 0x1f, 0xfc, + 0xb0, 0x0b, 0x98, 0xeb, 0x19, 0x0a, 0x0d, 0x28, 0x3e, 0xe8, 0x1c, 0xf1, + 0x1a, 0x0e, 0xf0, 0xfd, 0x43, 0xc9, 0xc9, 0x03, 0xdb, 0x0d, 0x2e, 0x0a, + 0xea, 0x01, 0x21, 0x1e, 0xd8, 0xcd, 0x0e, 0x02, 0x9c, 0xe6, 0xe5, 0xea, + 0x2c, 0xf5, 0xf1, 0x13, 0x23, 0xe1, 0x14, 0xd4, 0x0c, 0x0e, 0x05, 0x0e, + 0x26, 0xe5, 0xdf, 0xf0, 0xcf, 0x3f, 0x0f, 0x01, 0xfd, 0x22, 0xf8, 0x28, + 0xfb, 0xdd, 0xf2, 0xf3, 0x29, 0xeb, 0x15, 0x00, 0x16, 0x04, 0x2f, 0xe4, + 0x58, 0x16, 0x17, 0x0a, 0x14, 0x1b, 0xfe, 0xfb, 0x2c, 0xea, 0xd1, 0x25, + 0xe7, 0xfc, 0x5c, 0xed, 0xd9, 0x0e, 0x1a, 0x11, 0xe5, 0xd8, 0x11, 0x11, + 0xb7, 0xfc, 0xe1, 0xef, 0x2c, 0x09, 0x04, 0x0b, 0x16, 0x04, 0xed, 0xb2, + 0x34, 0x10, 0x2a, 0x01, 0x17, 0x05, 0xb6, 0x02, 0x11, 0x17, 0x20, 0xdc, + 0xf8, 0x1c, 0x01, 0x15, 0xa6, 0xed, 0x43, 0xc8, 0xe3, 0xf3, 0xd8, 0x07, + 0x1a, 0x22, 0x03, 0x31, 0x08, 0xef, 0x0d, 0xa3, 0x54, 0xf4, 0xc5, 0x06, + 0xe3, 0x94, 0xcf, 0xfb, 0x0a, 0x81, 0xf6, 0xd0, 0xff, 0x38, 0xbf, 0x29, + 0xbc, 0xed, 0x2e, 0xeb, 0xc4, 0xc2, 0xbd, 0x2a, 0x02, 0xf5, 0xeb, 0xfb, + 0x23, 0x19, 0xe0, 0xbc, 0x25, 0x1e, 0x1e, 0xfa, 0x21, 0xdf, 0xed, 0x15, + 0x05, 0xce, 0x11, 0xe6, 0xf5, 0x0a, 0xf8, 0x14, 0xd4, 0xf7, 0x2a, 0xd6, + 0xfc, 0xfc, 0xf3, 0x0c, 0x11, 0x27, 0xfe, 0x10, 0x2e, 0x03, 0x35, 0xe1, + 0xce, 0xf8, 0x27, 0xdc, 0xc3, 0x22, 0xeb, 0x35, 0xec, 0xee, 0x0e, 0x13, + 0x1c, 0x33, 0xd8, 0xdc, 0x1c, 0x2c, 0x04, 0xf8, 0xe2, 0xc7, 0xf8, 0x1a, + 0xfb, 0x00, 0xd5, 0xdb, 0x2c, 0x0a, 0x64, 0xdd, 0x53, 0x3c, 0xd5, 0xe2, + 0x16, 0xe2, 0xec, 0x1b, 0xfc, 0x16, 0x4c, 0xfe, 0x0e, 0xdb, 0xea, 0x20, + 0xd5, 0x1f, 0x43, 0xee, 0xf4, 0xc2, 0x0b, 0xe6, 0x02, 0xe8, 0xe9, 0xd3, + 0x2c, 0x18, 0x2e, 0xe8, 0xd4, 0xf1, 0x17, 0xfb, 0xc9, 0x15, 0xef, 0x25, + 0xe2, 0xf5, 0x28, 0x0d, 0x1d, 0x23, 0xe1, 0x01, 0x14, 0x05, 0xfc, 0xe3, + 0xd0, 0xec, 0x10, 0xfa, 0x0a, 0x04, 0xf6, 0x11, 0x07, 0xf5, 0xe6, 0xdc, + 0x04, 0x0f, 0xed, 0x0a, 0xc9, 0xee, 0x16, 0xed, 0xea, 0x17, 0xb7, 0xf2, + 0xc2, 0x2d, 0xe9, 0xdf, 0x01, 0x3b, 0xea, 0xf7, 0x16, 0x04, 0xc8, 0xd0, + 0x0b, 0x40, 0x19, 0xf6, 0xc0, 0xb2, 0x09, 0xde, 0xe6, 0x28, 0x29, 0xde, + 0xfd, 0xf9, 0xfd, 0x04, 0x1f, 0x1a, 0x15, 0x9e, 0xd2, 0xe2, 0xe9, 0x05, + 0x06, 0x00, 0x03, 0xf9, 0x97, 0xeb, 0x9c, 0x0a, 0xf5, 0x3d, 0xf9, 0xd7, + 0x1a, 0xf3, 0xdf, 0xee, 0xfe, 0x22, 0xff, 0xe3, 0xcf, 0xed, 0x28, 0xe8, + 0xd9, 0xfb, 0xf3, 0x00, 0xe5, 0x19, 0xff, 0xf7, 0xfd, 0x39, 0xd1, 0xef, + 0x2d, 0xf3, 0xd8, 0x8b, 0x06, 0x54, 0x21, 0x00, 0x40, 0xfa, 0x5e, 0xb7, + 0xe7, 0x01, 0x41, 0xe5, 0xe4, 0x28, 0xfb, 0x19, 0xe9, 0xfc, 0x15, 0x12, + 0x09, 0x56, 0xe0, 0xe4, 0x19, 0x09, 0x15, 0xed, 0xf3, 0xe4, 0xed, 0x29, + 0x18, 0x09, 0xe7, 0x0c, 0x01, 0x2f, 0x7f, 0xd8, 0x3e, 0x43, 0xe9, 0xfb, + 0x2e, 0xeb, 0x02, 0xba, 0xc9, 0x20, 0x00, 0xdc, 0xfc, 0xeb, 0xe2, 0x2a, + 0xbd, 0xce, 0x42, 0xed, 0xd9, 0xec, 0xed, 0x0b, 0xe8, 0xdf, 0x06, 0xb5, + 0x20, 0xf7, 0x39, 0xcf, 0xea, 0xd8, 0x31, 0xee, 0xf2, 0x31, 0x02, 0x21, + 0xef, 0xee, 0x1d, 0x0f, 0x22, 0x2a, 0xdd, 0xdf, 0x1c, 0xf0, 0xf7, 0x00, + 0x04, 0xdd, 0xfb, 0x0b, 0x2c, 0x25, 0x04, 0x00, 0x02, 0x65, 0x04, 0xe6, + 0xf2, 0xfd, 0xf3, 0xfe, 0x06, 0x02, 0xe3, 0x0c, 0x3c, 0xd3, 0x00, 0x18, + 0x03, 0xfe, 0xe8, 0xe6, 0xdb, 0x22, 0xf7, 0xed, 0xf5, 0xfc, 0x13, 0x1e, + 0xf0, 0xfa, 0x1d, 0x22, 0x15, 0x5c, 0x0e, 0xdf, 0xc3, 0xb9, 0xd0, 0x15, + 0xf5, 0xcc, 0x01, 0x1b, 0x2f, 0x07, 0x11, 0x0a, 0xe2, 0x2a, 0x0d, 0xa8, + 0xdb, 0xda, 0xd6, 0xef, 0x0c, 0xed, 0x1e, 0x22, 0xd8, 0x13, 0x41, 0x50, + 0xfa, 0x2d, 0x0d, 0xed, 0xeb, 0xb5, 0xb4, 0xf5, 0xfd, 0xe2, 0xb4, 0x07, + 0x1c, 0xf7, 0xfa, 0x21, 0x03, 0xd9, 0x06, 0xed, 0xdd, 0x0b, 0xc8, 0x05, + 0xe5, 0xc6, 0x1f, 0x12, 0xec, 0xdc, 0x0d, 0xfe, 0x13, 0x2e, 0xea, 0x42, + 0xd3, 0xd7, 0x01, 0x0a, 0x04, 0x06, 0xe9, 0xf2, 0x67, 0xeb, 0x4f, 0x30, + 0x0a, 0xdc, 0xed, 0x0e, 0xf7, 0x20, 0x03, 0xf9, 0xd8, 0x23, 0x52, 0xc8, + 0xf3, 0xab, 0xe1, 0x0f, 0x0b, 0x03, 0x20, 0x52, 0xe6, 0xf3, 0x03, 0x34, + 0x01, 0x1f, 0xe2, 0xe3, 0x40, 0xf6, 0x23, 0x3b, 0x2a, 0xdc, 0x47, 0xc2, + 0x09, 0x35, 0x17, 0xd6, 0xd0, 0x17, 0x3c, 0xdd, 0xf1, 0x10, 0x12, 0x14, + 0xf8, 0x22, 0xfc, 0x37, 0xd5, 0xea, 0x24, 0xf0, 0x1a, 0x17, 0xe9, 0xf4, + 0x3e, 0xfd, 0xf9, 0x24, 0x0d, 0xc2, 0xee, 0x0a, 0x16, 0xfd, 0x25, 0x0e, + 0xe6, 0x12, 0x31, 0xc9, 0xfd, 0xcf, 0xe2, 0xf4, 0x02, 0x44, 0x17, 0x03, + 0xe7, 0xe2, 0x81, 0x06, 0xe8, 0x9d, 0xe6, 0xf3, 0x33, 0xf7, 0xff, 0x04, + 0xf5, 0xf8, 0x15, 0x08, 0xac, 0x14, 0xee, 0xf8, 0x05, 0xe1, 0x0c, 0x1d, + 0xee, 0xab, 0xd1, 0x0a, 0xef, 0x31, 0x0f, 0x07, 0xcf, 0xde, 0x0b, 0x07, + 0xf3, 0x27, 0xa5, 0x34, 0xfb, 0x1c, 0x02, 0xf5, 0xf7, 0x42, 0x17, 0xde, + 0x00, 0xd7, 0x15, 0xff, 0xd6, 0xf8, 0xf0, 0x3b, 0xf8, 0x47, 0x2b, 0x40, + 0xca, 0x2f, 0x06, 0x03, 0xf0, 0xe3, 0xd9, 0x0b, 0x09, 0xda, 0xa6, 0xfc, + 0x31, 0x06, 0xe7, 0x0e, 0x00, 0xd0, 0x06, 0xfe, 0xd8, 0x0f, 0xea, 0x17, + 0xc9, 0xe4, 0xd9, 0x0c, 0x18, 0xeb, 0x04, 0x0b, 0x0c, 0xf7, 0x17, 0x12, + 0xd8, 0x37, 0x2b, 0x14, 0xf0, 0x0d, 0x08, 0x2e, 0xd0, 0x25, 0x03, 0x0e, + 0x36, 0x27, 0x06, 0x0d, 0x21, 0x0a, 0xd3, 0xe9, 0x12, 0xb9, 0x05, 0x25, + 0x02, 0x30, 0x10, 0xb9, 0x50, 0xe9, 0xff, 0x38, 0xfc, 0x65, 0x10, 0xed, + 0xfb, 0xe9, 0xde, 0x10, 0x07, 0xfe, 0x4b, 0x11, 0x1f, 0xdf, 0x31, 0xed, + 0xd4, 0x1e, 0xdf, 0xeb, 0x1d, 0xa1, 0x1d, 0x27, 0x00, 0xff, 0xdf, 0xfd, + 0x00, 0xd1, 0x00, 0xfc, 0xec, 0x27, 0x10, 0xee, 0xf0, 0xf5, 0x03, 0x29, + 0xe9, 0x10, 0x0a, 0x02, 0x38, 0x10, 0x08, 0xd2, 0x23, 0xeb, 0xbc, 0xfc, + 0x06, 0xa3, 0xf2, 0x0a, 0x11, 0x44, 0x0e, 0xe4, 0xec, 0xda, 0xe1, 0xed, + 0xe0, 0x02, 0xe0, 0xe1, 0xf1, 0xe4, 0xc6, 0x3d, 0xe6, 0xec, 0x07, 0xb8, + 0xd0, 0x30, 0x2a, 0x14, 0xef, 0x01, 0x9e, 0xef, 0xd7, 0xc2, 0x93, 0x59, + 0xee, 0x68, 0x3b, 0x2a, 0xbe, 0xef, 0xfc, 0xfc, 0x11, 0x53, 0xf0, 0xca, + 0xf2, 0xa5, 0xc8, 0x69, 0x01, 0xc3, 0x3f, 0xaf, 0xb5, 0x13, 0xf4, 0xc2, + 0xf2, 0x5a, 0x07, 0xe9, 0xca, 0xd3, 0xa4, 0xe8, 0xe4, 0x2e, 0xde, 0x1d, + 0x22, 0xc3, 0xeb, 0xd9, 0xd6, 0x04, 0xa8, 0xc2, 0xec, 0xb5, 0xd4, 0x3e, + 0xe3, 0xef, 0xed, 0xcc, 0xde, 0x2e, 0x10, 0x09, 0x0e, 0x0c, 0x94, 0x01, + 0xd5, 0x92, 0xaf, 0x2e, 0xf6, 0x4c, 0x52, 0x03, 0x1d, 0xaf, 0xe5, 0xe7, + 0xcc, 0x1c, 0x1f, 0x3d, 0xf6, 0x11, 0xfb, 0x21, 0xff, 0x2d, 0x10, 0xf0, + 0xf5, 0xec, 0x0f, 0x09, 0x2c, 0xfd, 0xaf, 0x00, 0xec, 0xa4, 0xea, 0x37, + 0x0d, 0x1c, 0x0e, 0xcc, 0x02, 0x81, 0xf0, 0x00, 0xfe, 0x5c, 0x17, 0x0c, + 0x24, 0xf0, 0xf0, 0xaa, 0xdd, 0x45, 0x54, 0xf4, 0xc7, 0x9a, 0x0e, 0xee, + 0xe0, 0x11, 0xbe, 0x1c, 0xdc, 0xcb, 0x19, 0xd4, 0xfd, 0xf5, 0xfa, 0xf8, + 0x16, 0x83, 0xb9, 0xd2, 0xb7, 0x21, 0x13, 0x3d, 0xf0, 0x12, 0xfa, 0x22, + 0xfa, 0x2b, 0xf7, 0xde, 0xde, 0xc1, 0xf8, 0x03, 0x46, 0xfd, 0x8f, 0x25, + 0xed, 0x94, 0xec, 0xe3, 0x2a, 0x5c, 0x1f, 0xe2, 0x2b, 0xdd, 0x18, 0xfd, + 0x18, 0xee, 0x02, 0xd7, 0xfe, 0xd3, 0x26, 0xf5, 0xef, 0x58, 0xf5, 0x17, + 0x04, 0x23, 0xf2, 0xe0, 0x0d, 0xf1, 0x01, 0xf8, 0x3b, 0x08, 0x00, 0x28, + 0x0a, 0xfe, 0xfa, 0xe1, 0xe1, 0xf0, 0xd7, 0xe9, 0x31, 0x0d, 0x17, 0x11, + 0x3d, 0x1b, 0xeb, 0xe8, 0xe2, 0x4e, 0x9e, 0x13, 0xce, 0xe1, 0x19, 0x0a, + 0xc1, 0x0b, 0x20, 0xdd, 0x20, 0xca, 0x20, 0x18, 0xe4, 0x1e, 0x4c, 0x0b, + 0xfb, 0xd1, 0x04, 0x07, 0x15, 0xe5, 0xe7, 0xc9, 0x22, 0xdc, 0x39, 0xfb, + 0x0f, 0x0f, 0xf9, 0x10, 0x13, 0x1c, 0xe3, 0xe8, 0xed, 0xec, 0x0d, 0xf5, + 0x28, 0xf0, 0x1c, 0x11, 0x17, 0xe8, 0xcb, 0xcf, 0x2e, 0xe7, 0x18, 0xea, + 0xfb, 0x10, 0xf4, 0x09, 0x03, 0xfb, 0x08, 0xd9, 0xdd, 0x2e, 0xdb, 0xe9, + 0xd2, 0x24, 0x14, 0xd9, 0xfb, 0xe3, 0xe8, 0xf1, 0x7f, 0xe8, 0x20, 0xf6, + 0x11, 0xfd, 0xfc, 0xe9, 0xc0, 0x14, 0xd8, 0xd1, 0x10, 0xd9, 0xfd, 0xf8, + 0x1f, 0xf5, 0x4d, 0xe0, 0xf2, 0x1a, 0xe6, 0xe7, 0xe7, 0xef, 0x53, 0x0b, + 0xc0, 0x16, 0xf3, 0xde, 0xf3, 0xc3, 0x0c, 0xe9, 0x13, 0x0b, 0x54, 0x1a, + 0x31, 0xcd, 0x05, 0xf0, 0x12, 0x05, 0xf2, 0xdb, 0x12, 0xef, 0xed, 0xe2, + 0xfe, 0x04, 0xf8, 0xfe, 0xca, 0x22, 0xd9, 0xdf, 0xfc, 0xca, 0xe1, 0x0e, + 0x7c, 0xeb, 0x2d, 0x03, 0x15, 0x02, 0xb7, 0xbc, 0x27, 0xef, 0x06, 0x18, + 0x09, 0x0d, 0x02, 0x0d, 0x11, 0xd7, 0x0e, 0x01, 0x1b, 0x53, 0xf8, 0x16, + 0xfd, 0x02, 0xf7, 0x06, 0x1a, 0x2c, 0x06, 0xd0, 0x3d, 0x0f, 0xf9, 0xdd, + 0x37, 0x00, 0x09, 0xf1, 0xdd, 0xd3, 0xae, 0x0f, 0x03, 0x08, 0x0b, 0x26, + 0x39, 0x2e, 0xc6, 0xd7, 0x0f, 0x73, 0xaf, 0x32, 0xde, 0xd3, 0x23, 0xeb, + 0xec, 0x03, 0x11, 0xe2, 0x20, 0xdb, 0x20, 0xff, 0xfe, 0xee, 0x33, 0xf9, + 0xfa, 0xc9, 0xc6, 0x13, 0x16, 0xf8, 0xd6, 0xf0, 0x27, 0xc8, 0x20, 0xf1, + 0xec, 0x1f, 0xfd, 0x11, 0x0d, 0xe5, 0x03, 0xbf, 0x09, 0xe2, 0x00, 0x0e, + 0x4d, 0x27, 0x0f, 0xd9, 0x31, 0xff, 0x03, 0xe7, 0xf8, 0x03, 0xac, 0x37, + 0xde, 0xdf, 0xc3, 0x2f, 0xe7, 0xf9, 0x05, 0xd0, 0xfb, 0x09, 0x15, 0x09, + 0x13, 0xfa, 0x49, 0x0b, 0xdc, 0xf1, 0xe8, 0xdd, 0x11, 0xe5, 0x25, 0x04, + 0xb0, 0xf1, 0x2b, 0x22, 0x24, 0xeb, 0xab, 0x4b, 0xd1, 0x21, 0x09, 0xfb, + 0x15, 0x05, 0xf2, 0xf3, 0x24, 0xa5, 0x1b, 0x18, 0xf1, 0x06, 0xfa, 0xfc, + 0x17, 0x18, 0xb5, 0xfc, 0x44, 0xd5, 0x2b, 0xd2, 0x1c, 0x08, 0xe7, 0x3b, + 0xcf, 0xeb, 0xb0, 0x4c, 0xec, 0x1d, 0xce, 0x2b, 0x00, 0x01, 0x10, 0xe4, + 0x13, 0xef, 0x17, 0x13, 0x09, 0xe9, 0x38, 0x1f, 0xe3, 0xf0, 0xd4, 0xec, + 0x0c, 0xeb, 0x25, 0x08, 0xc9, 0x02, 0x2d, 0x1f, 0x04, 0x15, 0xf3, 0x2f, + 0xf5, 0xeb, 0x2a, 0xf9, 0x2e, 0x2a, 0x18, 0x3f, 0xfa, 0x0d, 0x39, 0x2b, + 0x32, 0xe7, 0x13, 0x51, 0xda, 0x51, 0x08, 0xc3, 0xda, 0x0e, 0x01, 0x64, + 0xb9, 0xba, 0xd7, 0xfb, 0x3f, 0x37, 0x17, 0x50, 0x13, 0xf3, 0xbf, 0x31, + 0xb6, 0x05, 0xef, 0x0a, 0x03, 0xcf, 0xc1, 0x27, 0x56, 0xf6, 0xb4, 0xf7, + 0x16, 0xfd, 0x04, 0xda, 0x2f, 0xe9, 0x39, 0xf4, 0xa7, 0x95, 0x8c, 0xd6, + 0xdd, 0x2a, 0xf7, 0x1e, 0x0a, 0x12, 0x13, 0xe5, 0x31, 0x30, 0x0f, 0x4a, + 0xf0, 0xcd, 0x3a, 0x15, 0x2a, 0xcf, 0xee, 0x25, 0x07, 0x23, 0xf2, 0xed, + 0xf1, 0xd6, 0x2b, 0x34, 0xd4, 0xc7, 0xd1, 0xe9, 0x03, 0x09, 0xfc, 0x2d, + 0x02, 0x38, 0xb7, 0x3a, 0xe5, 0xb3, 0xf9, 0xb9, 0xb4, 0x07, 0x0b, 0x28, + 0x1a, 0x13, 0x27, 0x18, 0xc2, 0xcb, 0xf9, 0xe2, 0x12, 0xdf, 0x36, 0x00, + 0xb8, 0x0a, 0x1d, 0x25, 0x0e, 0xdb, 0xe9, 0x45, 0xe9, 0x1e, 0x38, 0xbf, + 0x23, 0x0b, 0xd7, 0xd7, 0xf6, 0x81, 0x09, 0xd5, 0xcf, 0x2d, 0xf8, 0x04, + 0x28, 0xdb, 0xde, 0xfb, 0x71, 0x28, 0xf9, 0x1e, 0x27, 0x19, 0xdd, 0x14, + 0xb5, 0x0d, 0xfc, 0x21, 0xf9, 0x35, 0xe7, 0x28, 0x08, 0xb1, 0xdc, 0xdd, + 0xe8, 0x0d, 0xfa, 0xf2, 0xff, 0xe7, 0x43, 0x21, 0xd0, 0xda, 0xd4, 0xe2, + 0xcc, 0xe5, 0x15, 0xfd, 0xde, 0x02, 0x14, 0x0f, 0xe1, 0x55, 0x00, 0xff, + 0x3e, 0x13, 0xfd, 0x0b, 0xf0, 0x1a, 0x00, 0x09, 0x07, 0xec, 0xec, 0xf4, + 0x02, 0xef, 0xf6, 0xfe, 0xeb, 0x10, 0x3d, 0xe3, 0x14, 0x4c, 0x01, 0xe5, + 0xbe, 0xee, 0x23, 0x23, 0x25, 0x3a, 0xf7, 0x06, 0xf2, 0xc9, 0xd9, 0xfe, + 0xf0, 0x33, 0x05, 0xde, 0x15, 0xb8, 0xa3, 0x07, 0xf0, 0x58, 0xa6, 0x0f, + 0xfe, 0xc3, 0xe9, 0x06, 0x10, 0x29, 0x0e, 0x2b, 0x3f, 0xc8, 0xb8, 0xa2, + 0xce, 0x40, 0xc6, 0x00, 0x48, 0x0f, 0xe6, 0x01, 0x07, 0xe5, 0xb9, 0xe2, + 0x39, 0xe3, 0xf4, 0xca, 0xc4, 0xd7, 0xf6, 0xef, 0xd5, 0x09, 0x19, 0x05, + 0x9c, 0x71, 0xf8, 0x9f, 0xc4, 0x00, 0x16, 0x2a, 0xef, 0x01, 0xff, 0x55, + 0x49, 0xe8, 0x19, 0x23, 0xfa, 0x33, 0x05, 0xdf, 0x01, 0xf5, 0x28, 0xeb, + 0xe3, 0xfb, 0x18, 0xe1, 0x0d, 0x15, 0x4b, 0xe4, 0xa2, 0x0e, 0x33, 0x0b, + 0xc2, 0xba, 0xee, 0xd2, 0x4b, 0x00, 0xff, 0x2d, 0x0c, 0xf4, 0xf6, 0x13, + 0xe9, 0x1e, 0xee, 0xa0, 0x25, 0xe6, 0xea, 0x29, 0x04, 0x3f, 0xd8, 0xfc, + 0x1a, 0xf6, 0x1c, 0xdb, 0x3c, 0x3d, 0x51, 0x53, 0xf8, 0xbb, 0xee, 0xd5, + 0x06, 0x3b, 0x18, 0x24, 0x2e, 0xef, 0x26, 0x12, 0x17, 0x16, 0x0a, 0x01, + 0x11, 0xe2, 0x5b, 0xf0, 0xd9, 0xba, 0x0d, 0xf2, 0x28, 0x3b, 0x46, 0x06, + 0x81, 0x00, 0x1b, 0x0c, 0xdd, 0xcc, 0xed, 0xda, 0xde, 0x38, 0x19, 0x02, + 0x4e, 0x07, 0x12, 0xd2, 0x0d, 0x2a, 0xd2, 0xaf, 0xfb, 0xdf, 0xf3, 0xda, + 0xdc, 0x1b, 0xda, 0xfa, 0xf3, 0xbb, 0x50, 0xf7, 0xd8, 0x4b, 0xdd, 0x13, + 0xc9, 0xe8, 0xce, 0xfd, 0x05, 0x3e, 0xfe, 0xce, 0x21, 0xe2, 0xfc, 0xf4, + 0xba, 0x0b, 0x02, 0xf4, 0x08, 0x97, 0xd3, 0xe6, 0x1c, 0x48, 0xb6, 0x1e, + 0x16, 0xb2, 0xfa, 0xf3, 0xa8, 0x4c, 0xc0, 0x4b, 0x1a, 0xf3, 0xc0, 0xf4, + 0xe8, 0x43, 0xef, 0xdd, 0x48, 0x10, 0x1f, 0xe8, 0x04, 0x15, 0xd6, 0xda, + 0x11, 0xdc, 0x03, 0xc0, 0xea, 0x15, 0xf7, 0xff, 0xe3, 0xef, 0x17, 0xe6, + 0xbb, 0x1a, 0xc9, 0xfa, 0xef, 0x06, 0x03, 0x56, 0x04, 0xde, 0x09, 0x2a, + 0x1d, 0xdb, 0xe1, 0xf5, 0x04, 0xcb, 0x06, 0xec, 0xec, 0x0e, 0xf4, 0x21, + 0x35, 0x0c, 0x01, 0xbf, 0xd3, 0xf0, 0xf2, 0x01, 0x25, 0x02, 0x2a, 0x4a, + 0xe2, 0xe6, 0x0e, 0xf0, 0x16, 0xd8, 0xda, 0x56, 0x19, 0xfa, 0x20, 0xef, + 0x2f, 0x14, 0xf0, 0xd7, 0x06, 0xd2, 0xeb, 0x2a, 0xed, 0x0e, 0x16, 0xc3, + 0xd5, 0xfb, 0xef, 0xeb, 0x47, 0x0a, 0x4c, 0x56, 0xcd, 0xfa, 0x39, 0x10, + 0x01, 0xe2, 0xd3, 0x3e, 0x0d, 0xc6, 0xbd, 0xfc, 0x05, 0xc4, 0x15, 0xc9, + 0xfa, 0x0c, 0xfc, 0x39, 0x23, 0x15, 0xe9, 0xd3, 0xde, 0xe0, 0xed, 0x16, + 0x2f, 0xe5, 0x31, 0x2e, 0xe7, 0xb2, 0xda, 0xda, 0x08, 0xfa, 0xee, 0xed, + 0x13, 0xf8, 0xfe, 0x02, 0x1b, 0xf7, 0xc4, 0x03, 0xdb, 0x0c, 0xf3, 0x0f, + 0x1c, 0xed, 0xf9, 0x01, 0xd2, 0x32, 0xe8, 0xdc, 0x68, 0xc3, 0x50, 0x1c, + 0xdc, 0xcc, 0xf2, 0xe2, 0xf7, 0x32, 0x0b, 0xea, 0x26, 0xd6, 0xf8, 0xd5, + 0x21, 0x00, 0x2c, 0xd9, 0x13, 0xe1, 0xf0, 0x18, 0x17, 0x03, 0xf6, 0xd1, + 0xbb, 0x1f, 0x0a, 0xd4, 0xfc, 0xc0, 0x22, 0x1a, 0xe4, 0xf5, 0x13, 0xf4, + 0x19, 0xdf, 0xe6, 0x0c, 0xfd, 0xe1, 0xe5, 0xe7, 0x0d, 0x01, 0xfe, 0xc0, + 0xd0, 0xfd, 0xe8, 0x08, 0x0d, 0x07, 0xd3, 0xe3, 0xf6, 0x13, 0xe5, 0xf0, + 0x7f, 0xd0, 0x4b, 0x1f, 0xca, 0xb2, 0xcc, 0xb6, 0x0f, 0xec, 0xf5, 0x57, + 0xf0, 0x15, 0x0c, 0x2a, 0x1b, 0xdb, 0xfb, 0xff, 0x02, 0x35, 0xe9, 0x30, + 0x14, 0xe5, 0x18, 0xda, 0xf7, 0x1a, 0xf5, 0xce, 0x40, 0x1e, 0x4f, 0xcf, + 0xfe, 0x11, 0x09, 0xf6, 0xed, 0xbb, 0xb7, 0x70, 0xd9, 0x1d, 0x4c, 0x17, + 0x2a, 0x63, 0xed, 0xe5, 0xfa, 0x15, 0xf9, 0x2a, 0xdc, 0xe4, 0x24, 0xd9, + 0x25, 0x04, 0xda, 0xde, 0x3b, 0xfa, 0x33, 0xc8, 0xf4, 0x22, 0x33, 0x0a, + 0x23, 0xeb, 0xfd, 0x36, 0x01, 0x10, 0xd0, 0xfa, 0x17, 0xc1, 0x2c, 0xcb, + 0x1a, 0x1d, 0xf9, 0x3c, 0x08, 0x03, 0xfa, 0xea, 0xd7, 0x10, 0xfb, 0xf7, + 0x58, 0xf0, 0x55, 0xf0, 0xe0, 0xfb, 0xf7, 0xf2, 0x12, 0x32, 0xf4, 0xf8, + 0x06, 0x06, 0x03, 0x28, 0xe5, 0x32, 0xe5, 0x35, 0x11, 0xd0, 0x14, 0x0b, + 0x1d, 0x09, 0x1a, 0xfd, 0xdd, 0x16, 0xf1, 0xee, 0xeb, 0xf6, 0x16, 0x33, + 0xe7, 0x14, 0x0c, 0x21, 0x24, 0x18, 0x2a, 0x04, 0xfe, 0x02, 0xe4, 0x01, + 0xf3, 0xd6, 0xfc, 0x15, 0x4f, 0xb3, 0x54, 0x04, 0x1e, 0x3f, 0xf5, 0x0b, + 0xe9, 0xfd, 0xfc, 0xf3, 0xfd, 0xf1, 0x0b, 0x1b, 0x09, 0xe4, 0xe5, 0x1d, + 0xe6, 0x24, 0xf6, 0xe1, 0x12, 0x01, 0xf8, 0x04, 0xe1, 0x1b, 0xca, 0x27, + 0x1b, 0xd5, 0x05, 0xf2, 0x00, 0xef, 0xfe, 0x08, 0xe9, 0xfa, 0xf4, 0xfc, + 0xb5, 0xff, 0xf4, 0xf8, 0xf6, 0x0b, 0xf0, 0x18, 0x0f, 0x09, 0x07, 0x16, + 0xe0, 0xe3, 0x2a, 0xfe, 0xde, 0xec, 0xda, 0x1e, 0xf6, 0xfc, 0x3b, 0x23, + 0x21, 0xe1, 0x01, 0x0e, 0xd8, 0x48, 0x01, 0xdc, 0xe5, 0xed, 0x34, 0xee, + 0xa7, 0xf0, 0x07, 0x0e, 0x51, 0xf5, 0x1e, 0x4c, 0xd3, 0x12, 0xfc, 0x0e, + 0x02, 0xfb, 0xd7, 0x1e, 0x63, 0xda, 0x2f, 0x4d, 0x34, 0x00, 0xdf, 0xee, + 0x02, 0x2f, 0xda, 0xf6, 0xe6, 0xf9, 0x0f, 0xfc, 0xe1, 0xf6, 0xd4, 0xfb, + 0xe3, 0x05, 0xfc, 0x2a, 0xe4, 0xe4, 0x26, 0xf1, 0xe9, 0x00, 0xea, 0x04, + 0xfc, 0xf2, 0x64, 0x22, 0x18, 0xc8, 0xf8, 0x0e, 0xfa, 0x12, 0x0c, 0x01, + 0x81, 0x04, 0x2d, 0xea, 0xc0, 0xe5, 0x08, 0xee, 0x0c, 0x2e, 0x2b, 0x02, + 0xee, 0x05, 0x08, 0x1c, 0xcc, 0x30, 0xd3, 0x1a, 0xf0, 0xc2, 0x14, 0x11, + 0x02, 0xfc, 0x0e, 0xea, 0xdc, 0xeb, 0xec, 0xd8, 0xe0, 0xe1, 0x02, 0x4c, + 0xf1, 0x00, 0x1a, 0x13, 0x29, 0x29, 0x37, 0xf5, 0xcb, 0x05, 0xfa, 0xd5, + 0xf2, 0xe8, 0xd6, 0x40, 0x47, 0xe5, 0x6b, 0xf3, 0x1e, 0x3b, 0xf0, 0xe8, + 0xe4, 0xf9, 0xe4, 0xe6, 0xf0, 0x0a, 0x01, 0x45, 0x21, 0xeb, 0xce, 0x11, + 0xbe, 0x2b, 0x1b, 0xff, 0xee, 0x03, 0x0b, 0x10, 0xdc, 0x07, 0x8f, 0x15, + 0x01, 0xef, 0xee, 0xfb, 0x03, 0xe4, 0xff, 0x07, 0x09, 0xf8, 0xdd, 0xde, + 0x94, 0xed, 0xfd, 0x12, 0xf7, 0x11, 0x08, 0x05, 0x18, 0xed, 0xea, 0x06, + 0xcd, 0xba, 0xf0, 0xdd, 0x0e, 0xf0, 0x0a, 0xfd, 0x11, 0xb7, 0x02, 0x01, + 0xdb, 0x0b, 0x1a, 0xef, 0xdb, 0xff, 0xed, 0xff, 0x0d, 0xdf, 0xe5, 0xf6, + 0x21, 0xec, 0xd2, 0xf2, 0xfb, 0xfa, 0xeb, 0xff, 0x06, 0xcb, 0x0a, 0xe3, + 0x0a, 0xf1, 0x1e, 0x0c, 0xe1, 0x10, 0x30, 0xef, 0x15, 0xe1, 0x1e, 0x0e, + 0x21, 0x07, 0x2e, 0x07, 0x05, 0xfb, 0xf5, 0xb2, 0xee, 0x46, 0x1d, 0x27, + 0x0e, 0xfd, 0xfe, 0x00, 0xc3, 0xc7, 0xe0, 0xff, 0x04, 0xd6, 0x1a, 0xf3, + 0xf8, 0xd1, 0x10, 0x1b, 0x15, 0x09, 0x16, 0x0b, 0xf2, 0x02, 0xdb, 0x34, + 0xf5, 0xbf, 0x10, 0x03, 0x1d, 0xe0, 0xef, 0xdb, 0x0b, 0xe2, 0xfb, 0xc9, + 0xf3, 0x01, 0x10, 0xf0, 0xec, 0x04, 0xfa, 0xf3, 0x1b, 0x06, 0xeb, 0xf1, + 0xe9, 0x05, 0xc9, 0xec, 0x00, 0xe3, 0x03, 0x05, 0xec, 0x10, 0xc6, 0xd7, + 0x2c, 0x2d, 0xfe, 0xee, 0xf1, 0x03, 0x23, 0xf1, 0x25, 0x22, 0x15, 0x21, + 0xe5, 0x0c, 0x15, 0x11, 0xf3, 0x10, 0xe0, 0xf3, 0x1d, 0x05, 0x1f, 0x0f, + 0x1e, 0xdb, 0x23, 0x03, 0xfb, 0x13, 0xd4, 0x05, 0xe9, 0x18, 0x18, 0x28, + 0xea, 0x08, 0xf2, 0xdd, 0xe0, 0xee, 0x28, 0xe0, 0xee, 0x07, 0x00, 0xfd, + 0x0b, 0x23, 0xe8, 0xf8, 0x11, 0xea, 0xe0, 0x33, 0x04, 0xc7, 0xf0, 0x10, + 0xe7, 0x0a, 0xe4, 0xf2, 0x02, 0x0d, 0x00, 0xf8, 0x13, 0xef, 0xf4, 0xee, + 0xe3, 0xc5, 0xea, 0xd6, 0x08, 0x25, 0x0d, 0xfe, 0x11, 0x0d, 0x02, 0xef, + 0xdd, 0x0b, 0xfe, 0xe2, 0x05, 0xe8, 0x07, 0x13, 0xfd, 0xf5, 0xdd, 0xf4, + 0x14, 0xe2, 0xd3, 0xf3, 0xf7, 0x01, 0xf9, 0x17, 0x0e, 0xf0, 0xec, 0xfd, + 0xe7, 0xcb, 0x24, 0xe0, 0xd3, 0xd7, 0x48, 0xec, 0x29, 0x05, 0x26, 0x22, + 0x16, 0x08, 0xf3, 0x1f, 0xff, 0xfe, 0xfc, 0xe1, 0xf9, 0x0f, 0x15, 0x2f, + 0xf0, 0xd9, 0xd4, 0x15, 0xf8, 0xf8, 0x1c, 0xde, 0x0b, 0x17, 0x02, 0x0b, + 0xe7, 0xd6, 0xfb, 0xf7, 0xef, 0xf8, 0x0f, 0xfb, 0x0c, 0x01, 0x0b, 0x7f, + 0xf4, 0x0a, 0xfd, 0xf6, 0x16, 0x0f, 0xfd, 0xe4, 0xfc, 0x0d, 0x01, 0x06, + 0xff, 0x2f, 0xfc, 0x21, 0xf4, 0xfb, 0xe6, 0x1b, 0x21, 0x02, 0x0c, 0x18, + 0x14, 0x11, 0x01, 0x15, 0xc6, 0x0f, 0xec, 0xe9, 0xfc, 0xfc, 0x0f, 0x23, + 0xe0, 0x06, 0x02, 0xee, 0x1f, 0x1c, 0x1e, 0x1f, 0xfd, 0x42, 0x03, 0xff, + 0xf5, 0xf0, 0xf2, 0x25, 0x0f, 0xc7, 0x65, 0x1c, 0x29, 0xf7, 0x28, 0x05, + 0xec, 0x1f, 0xfb, 0xe7, 0x08, 0xfd, 0x34, 0xf5, 0xfa, 0x1c, 0xfb, 0x1f, + 0xfe, 0x07, 0x03, 0x0c, 0xf6, 0x0f, 0xfe, 0x1a, 0xe0, 0xfe, 0xbe, 0x13, + 0x19, 0xfc, 0xfc, 0x09, 0x18, 0xfd, 0x09, 0xfb, 0xff, 0x03, 0xe9, 0xee, + 0xea, 0xe3, 0x0c, 0xff, 0xf3, 0xf6, 0xf0, 0x00, 0xda, 0xf8, 0xfb, 0x1e, + 0xee, 0xfd, 0x0a, 0x0d, 0xd0, 0x03, 0xf0, 0x06, 0x2e, 0xfc, 0x06, 0x15, + 0xfc, 0xf8, 0x0d, 0x08, 0xf5, 0x5f, 0xef, 0xe7, 0x17, 0xe2, 0x22, 0x06, + 0xbd, 0x1a, 0x25, 0x0e, 0xe8, 0xea, 0x04, 0x2e, 0xdd, 0xf8, 0x02, 0xfb, + 0x0e, 0x0d, 0xc7, 0x02, 0x46, 0xf0, 0x29, 0x00, 0x05, 0x42, 0x37, 0xd9, + 0xf2, 0x42, 0xe8, 0xe8, 0xe1, 0xed, 0xd5, 0x25, 0xe4, 0xe2, 0xd6, 0x13, + 0xdb, 0xee, 0xe8, 0x2c, 0xe7, 0xef, 0xfd, 0xf7, 0xa1, 0x02, 0x02, 0xf0, + 0x1d, 0xfe, 0xf8, 0x0d, 0x06, 0xd5, 0x01, 0x08, 0x08, 0x32, 0xec, 0xfa, + 0x16, 0x04, 0x14, 0xe1, 0xb7, 0x0b, 0x09, 0xed, 0xfb, 0x0d, 0x23, 0x15, + 0xbf, 0xe9, 0x05, 0x0f, 0xba, 0x28, 0xe1, 0x1a, 0x0f, 0xd0, 0x1d, 0x1e, + 0x0e, 0x06, 0xf3, 0x11, 0x06, 0x0d, 0xce, 0xf5, 0xe4, 0xb7, 0x17, 0x10, + 0xe9, 0xe4, 0xc3, 0xf8, 0x17, 0x06, 0x3e, 0x02, 0xc4, 0x30, 0xf1, 0xe5, + 0x06, 0xc9, 0xf9, 0x1b, 0x0c, 0x33, 0x7f, 0x14, 0x37, 0xd9, 0x07, 0xdc, + 0xcb, 0x18, 0xd1, 0xde, 0xfa, 0xf4, 0x2d, 0xdb, 0xdd, 0x02, 0xd7, 0x0f, + 0xbc, 0x0f, 0x44, 0x03, 0xb3, 0x04, 0x06, 0x08, 0xac, 0x17, 0xb9, 0x0e, + 0xfc, 0xed, 0x09, 0xfb, 0x15, 0xf2, 0xef, 0x14, 0x0e, 0xf9, 0xb3, 0xea, + 0xc8, 0xb9, 0xf1, 0xf9, 0xfc, 0xed, 0xed, 0xfd, 0x00, 0x08, 0x18, 0x06, + 0x06, 0x1d, 0x0d, 0x00, 0xf3, 0xef, 0xf9, 0x23, 0x0f, 0xbf, 0x17, 0x1c, + 0x2e, 0x0f, 0x07, 0xe7, 0xc6, 0x2b, 0xf6, 0xe8, 0xd2, 0x0f, 0x1d, 0x23, + 0x09, 0x08, 0x00, 0xf8, 0x16, 0x00, 0x17, 0x2d, 0x27, 0x2a, 0x09, 0xee, + 0xf6, 0xe5, 0xf6, 0x2b, 0x20, 0xe4, 0x74, 0x1a, 0x3d, 0xfe, 0x0d, 0xf2, + 0xd8, 0x2a, 0x00, 0xe7, 0xfc, 0xf7, 0x26, 0x18, 0xdb, 0x0a, 0xe3, 0x21, + 0xec, 0x07, 0x10, 0x1a, 0xe0, 0xe0, 0xff, 0xfe, 0xae, 0x04, 0xc3, 0x2f, + 0x06, 0xf6, 0xf2, 0x17, 0x21, 0x0f, 0x00, 0xf3, 0x05, 0x14, 0xcd, 0x04, + 0xb9, 0xe2, 0x12, 0x24, 0x02, 0x00, 0xeb, 0xf3, 0xec, 0xf4, 0xf8, 0xfa, + 0x07, 0xeb, 0x12, 0xed, 0xcd, 0xf9, 0xcf, 0xfe, 0xf6, 0x0d, 0xff, 0x0a, + 0xf9, 0xd3, 0xce, 0x21, 0xf4, 0xfa, 0xec, 0xf9, 0x01, 0xf8, 0x13, 0xd9, + 0xbf, 0x19, 0x1c, 0x21, 0xdd, 0xfc, 0x23, 0x11, 0x0d, 0x27, 0xd7, 0xf6, + 0x44, 0xee, 0xcc, 0x10, 0x1a, 0xec, 0x42, 0xfe, 0xfe, 0x1c, 0xf1, 0xea, + 0xd7, 0x2f, 0xff, 0xe4, 0xdc, 0xfc, 0xe2, 0x21, 0xca, 0x38, 0xd0, 0xf9, + 0xfa, 0xdf, 0xef, 0x0a, 0xde, 0xfe, 0x0c, 0xec, 0xab, 0xf4, 0xec, 0xf7, + 0xe7, 0x09, 0x12, 0x09, 0xfe, 0xcb, 0x08, 0x24, 0x11, 0xec, 0xe9, 0xe7, + 0x01, 0x0e, 0x04, 0xd2, 0xc6, 0x1a, 0x0b, 0x0e, 0xdb, 0xe8, 0x2c, 0x16, + 0xcb, 0xec, 0x38, 0x04, 0xe2, 0x0c, 0xe8, 0x28, 0x09, 0xbb, 0x0c, 0x29, + 0x21, 0xeb, 0x0b, 0xdd, 0x04, 0x0f, 0xd5, 0xe8, 0xce, 0xed, 0x1b, 0x0e, + 0x07, 0xfc, 0xf0, 0xe5, 0x04, 0xc0, 0x35, 0x46, 0x03, 0x10, 0x3e, 0xe5, + 0x12, 0xf8, 0xf5, 0x3d, 0x03, 0x1d, 0x7f, 0x1b, 0x4b, 0xdd, 0x17, 0xba, + 0x0d, 0x30, 0xf9, 0xe4, 0xe8, 0xff, 0x13, 0xd7, 0xdf, 0x44, 0xe2, 0x21, + 0xe1, 0xd4, 0x0e, 0x18, 0xb3, 0x09, 0x1d, 0xef, 0xcb, 0x14, 0xa8, 0x13, + 0xe4, 0xf2, 0xec, 0x25, 0x24, 0xdc, 0xf4, 0xcc, 0x12, 0xf5, 0xc8, 0xde, + 0xc5, 0xdd, 0x00, 0x05, 0x01, 0x09, 0xf6, 0xd7, 0xde, 0xc9, 0x04, 0x21, + 0x13, 0x06, 0x21, 0xd5, 0xe2, 0x23, 0x1d, 0xef, 0xe6, 0xe7, 0xd1, 0xff, + 0x10, 0xdc, 0x0a, 0xdd, 0x19, 0xdf, 0x0d, 0x13, 0xf4, 0x46, 0xdc, 0xdf, + 0xfd, 0xd0, 0xc6, 0xca, 0xef, 0xf3, 0xff, 0x11, 0x19, 0xe5, 0x13, 0x0c, + 0xdc, 0x0d, 0x35, 0x1d, 0xd4, 0x21, 0x05, 0x14, 0x3f, 0xd6, 0x14, 0x0a, + 0x37, 0xe3, 0xf5, 0x07, 0xe9, 0x27, 0xf0, 0xb5, 0x12, 0x39, 0x0a, 0x0e, + 0xdf, 0xe8, 0xe8, 0x16, 0xe9, 0xfc, 0x15, 0xd1, 0x14, 0x05, 0x18, 0x0a, + 0xf6, 0xd1, 0xf2, 0x09, 0x0b, 0xd0, 0x01, 0xfc, 0x09, 0x0b, 0xf2, 0x29, + 0xeb, 0x3d, 0xd6, 0xe4, 0x2f, 0xff, 0xf0, 0xd3, 0xcb, 0xbe, 0xfd, 0xd9, + 0x2f, 0xf8, 0xfb, 0xd9, 0xf9, 0xf2, 0xe4, 0xbe, 0xf6, 0x02, 0xf8, 0xec, + 0xd8, 0x03, 0xe1, 0xc8, 0x04, 0xc9, 0x2d, 0x00, 0xe2, 0x26, 0xe6, 0x0e, + 0xed, 0xf2, 0x11, 0xe5, 0x20, 0xfd, 0x01, 0xe9, 0x14, 0xfa, 0x07, 0xee, + 0xf6, 0x04, 0xdd, 0x09, 0xf2, 0xfa, 0xf3, 0x00, 0xfa, 0x2c, 0x17, 0xce, + 0x0c, 0xe2, 0x22, 0xf1, 0x19, 0x2f, 0x16, 0x21, 0xf7, 0x30, 0x28, 0x15, + 0xe7, 0xe9, 0x04, 0xe6, 0x50, 0xf0, 0x00, 0xe7, 0xf4, 0xf9, 0xea, 0xea, + 0x16, 0x19, 0xd3, 0xfb, 0xfd, 0xf1, 0xf0, 0xeb, 0x0b, 0xd3, 0x1a, 0x11, + 0xfd, 0x0f, 0xea, 0x05, 0x16, 0x09, 0x1f, 0xed, 0xe5, 0x0e, 0x1b, 0x0f, + 0x22, 0x0f, 0x2c, 0xd2, 0xea, 0x1f, 0x0a, 0xf6, 0x29, 0xd9, 0xec, 0xff, + 0xfb, 0x0b, 0xe7, 0xf1, 0x1e, 0xca, 0x1b, 0x1e, 0xd0, 0x3f, 0xcc, 0x26, + 0xfa, 0xe4, 0xce, 0xe1, 0xf1, 0x21, 0x2e, 0x0f, 0x2e, 0xeb, 0xf7, 0x1a, + 0xdd, 0x18, 0x24, 0x2b, 0xe8, 0x25, 0x0e, 0x0b, 0x3f, 0xfb, 0x28, 0xff, + 0x46, 0x0e, 0x0c, 0x0b, 0xdd, 0x41, 0xf0, 0xde, 0x1d, 0x3e, 0x13, 0x2a, + 0xd4, 0x02, 0x09, 0x01, 0x21, 0x0e, 0x1b, 0xd5, 0x10, 0x3d, 0x04, 0xfe, + 0x1f, 0xe4, 0x01, 0xee, 0xd2, 0x0f, 0xee, 0xf3, 0x52, 0x10, 0x19, 0x7f, + 0xef, 0x36, 0xe3, 0x05, 0x2b, 0x10, 0x04, 0xe0, 0xd9, 0xbe, 0xc7, 0x2b, + 0x29, 0x29, 0xf9, 0xf2, 0xce, 0x3c, 0x15, 0xca, 0xc6, 0xe2, 0xfa, 0x0a, + 0x04, 0xde, 0x01, 0xe6, 0x0c, 0xf9, 0xf1, 0x15, 0x18, 0x34, 0xfb, 0xf7, + 0xcf, 0xb7, 0xc2, 0xcb, 0xf5, 0xad, 0xfb, 0x42, 0x16, 0xf8, 0x37, 0x1d, + 0xd4, 0x21, 0x1c, 0xfb, 0xa8, 0x02, 0xfd, 0x31, 0x65, 0xcf, 0x07, 0x1d, + 0x3a, 0xe8, 0xea, 0xde, 0xeb, 0x48, 0x10, 0xd3, 0x19, 0x11, 0xc5, 0xce, + 0xee, 0xe8, 0xf7, 0x4a, 0x08, 0x17, 0x2b, 0xee, 0x06, 0x22, 0x0b, 0x37, + 0xbe, 0xb8, 0xfe, 0x06, 0x23, 0xe6, 0xee, 0x16, 0x37, 0x11, 0xf0, 0x09, + 0xfd, 0x29, 0x06, 0xe1, 0xde, 0x08, 0xd8, 0xe7, 0xb9, 0xd9, 0x05, 0xe1, + 0x3f, 0xea, 0x0e, 0xdb, 0xf8, 0x05, 0xe6, 0xb0, 0xe1, 0x1d, 0x02, 0xf0, + 0xeb, 0xff, 0xd8, 0xcd, 0xf5, 0xbd, 0x15, 0xf6, 0xc4, 0x1d, 0xe0, 0x51, + 0xd7, 0xd4, 0xf3, 0xef, 0x12, 0x0b, 0xe7, 0xe5, 0x05, 0xf2, 0x06, 0xd6, + 0x12, 0x01, 0xe0, 0x02, 0xea, 0xaa, 0xe8, 0xe8, 0xc6, 0x47, 0xd2, 0xfd, + 0x1e, 0xc8, 0x1c, 0xf9, 0x23, 0x2a, 0xf6, 0x45, 0xeb, 0x0e, 0xf9, 0xcc, + 0xc8, 0xdb, 0x10, 0xec, 0x57, 0xef, 0x08, 0xfd, 0xdf, 0x06, 0xe3, 0xfd, + 0xe1, 0x0b, 0xb9, 0xf9, 0xf5, 0xf1, 0xf9, 0xee, 0x14, 0xd8, 0x1c, 0xf3, + 0xd6, 0x04, 0xec, 0x42, 0xea, 0x03, 0x29, 0xf9, 0xcb, 0x11, 0x08, 0x2b, + 0x1e, 0x16, 0x36, 0xc8, 0x09, 0x2e, 0x03, 0xf2, 0x17, 0xd3, 0x02, 0x03, + 0x3e, 0xfe, 0x09, 0x08, 0x09, 0x05, 0x08, 0x05, 0xee, 0x47, 0xe1, 0x1d, + 0xea, 0xe5, 0xef, 0xef, 0x05, 0xf7, 0x1b, 0x42, 0x20, 0xe7, 0x3b, 0x03, + 0xce, 0x0b, 0x3b, 0x2e, 0x08, 0xfc, 0x36, 0x37, 0x7f, 0x08, 0x18, 0xf5, + 0x2f, 0x27, 0xea, 0xdd, 0xdc, 0x6a, 0xed, 0x05, 0x2a, 0x18, 0xcc, 0x05, + 0xe2, 0x14, 0xf9, 0x45, 0x04, 0x15, 0x23, 0xe2, 0x03, 0x41, 0xf9, 0x0a, + 0x1b, 0xec, 0x0e, 0xeb, 0x09, 0xff, 0xf2, 0x03, 0x38, 0x0b, 0x1a, 0x22, + 0xb7, 0x45, 0xd9, 0xfd, 0x07, 0xf4, 0xdf, 0x08, 0x31, 0x2e, 0x22, 0xef, + 0xed, 0x00, 0x06, 0xf6, 0x05, 0x08, 0xf2, 0xf1, 0xe1, 0x0b, 0xf6, 0x14, + 0x02, 0x15, 0xed, 0x0d, 0xed, 0x1c, 0xf6, 0xef, 0x04, 0xe0, 0x0e, 0xeb, + 0x04, 0xf3, 0xfc, 0x05, 0x04, 0x3c, 0x0f, 0xdd, 0x30, 0xfb, 0xdd, 0x0a, + 0x11, 0x26, 0xd9, 0xf3, 0xed, 0x3c, 0xd9, 0xf2, 0xd3, 0xec, 0x28, 0x15, + 0xcc, 0xe5, 0x2a, 0xe2, 0x0c, 0x06, 0xfb, 0xf6, 0x07, 0x0d, 0x32, 0x0f, + 0x2c, 0x29, 0x2a, 0xed, 0xfd, 0x02, 0xe2, 0xfb, 0x19, 0xe9, 0xfc, 0xe2, + 0x0e, 0x1a, 0xfa, 0x26, 0x03, 0x1a, 0xe2, 0xee, 0xbe, 0x18, 0xe5, 0x02, + 0x23, 0xd8, 0x28, 0xe4, 0x09, 0xc6, 0xf9, 0x17, 0x24, 0xfd, 0xbf, 0x36, + 0xfe, 0xee, 0xf7, 0x12, 0xfe, 0x02, 0x16, 0xde, 0x46, 0xf7, 0x0a, 0x16, + 0xc0, 0x17, 0x11, 0xe7, 0x06, 0x3b, 0x08, 0xfb, 0x52, 0x02, 0x53, 0xbe, + 0x11, 0xeb, 0xf6, 0xca, 0xde, 0xef, 0xff, 0x1b, 0xd8, 0xde, 0x0e, 0x1f, + 0x07, 0x16, 0x1c, 0xc9, 0xb2, 0x22, 0xf0, 0xf4, 0xfe, 0xe6, 0x7f, 0xe0, + 0x0a, 0x08, 0x07, 0xe7, 0xd1, 0x01, 0x0f, 0xe3, 0x0b, 0xf9, 0x44, 0x06, + 0x00, 0x2f, 0xf0, 0x42, 0x01, 0xf8, 0xf9, 0x02, 0x27, 0x0e, 0x05, 0xd6, + 0x28, 0x10, 0xec, 0x1b, 0xe4, 0x03, 0xfc, 0xfa, 0xf6, 0x46, 0x18, 0x02, + 0x63, 0x00, 0x30, 0xbd, 0x20, 0xe2, 0xfc, 0xe8, 0x36, 0x13, 0x27, 0xbf, + 0xff, 0x03, 0xd9, 0xe6, 0x14, 0xb4, 0xdc, 0xd0, 0x17, 0x1f, 0xd8, 0xf4, + 0xf3, 0xff, 0xde, 0xe6, 0xce, 0xfd, 0xe6, 0x12, 0x0b, 0xd2, 0xf7, 0xef, + 0x24, 0xd8, 0xed, 0xdd, 0xcc, 0x3f, 0xf2, 0xd1, 0x10, 0xf2, 0xd3, 0x15, + 0xe8, 0xf3, 0xe5, 0xef, 0xe3, 0x32, 0xe6, 0xe5, 0xd4, 0xe0, 0x2d, 0xf3, + 0xeb, 0xd8, 0x46, 0x07, 0xf1, 0xde, 0xf3, 0x16, 0xe5, 0x13, 0x30, 0x2c, + 0x16, 0x19, 0x20, 0xe2, 0xf5, 0xe8, 0xf2, 0xf1, 0x1c, 0x03, 0xe9, 0xee, + 0x18, 0x1f, 0xf6, 0x13, 0xf8, 0x0d, 0xfd, 0xfa, 0xde, 0x08, 0xf6, 0x18, + 0x10, 0xd6, 0xf4, 0xeb, 0x1c, 0xcf, 0xea, 0x05, 0xcc, 0x07, 0x02, 0x09, + 0xff, 0xd8, 0xf3, 0xf4, 0xdf, 0x1f, 0x1f, 0xe6, 0xf4, 0x0a, 0xca, 0xd8, + 0xf5, 0xd4, 0xff, 0xe7, 0x13, 0xd7, 0x05, 0x0a, 0xed, 0x15, 0xca, 0x08, + 0x08, 0x13, 0x12, 0xdf, 0xeb, 0x26, 0x02, 0x0e, 0xd2, 0xef, 0x0e, 0xdc, + 0xc3, 0x09, 0x32, 0xf3, 0xe0, 0xfb, 0xeb, 0xf8, 0x03, 0x19, 0xec, 0xee, + 0x2c, 0xeb, 0xec, 0x10, 0xf5, 0x1c, 0xd7, 0x09, 0xf9, 0xd2, 0xe3, 0xdd, + 0xd0, 0x0a, 0x08, 0xfb, 0xfa, 0xf3, 0x12, 0xf1, 0x02, 0x24, 0x64, 0xfa, + 0xf7, 0x10, 0xe4, 0xe0, 0xf4, 0xc1, 0xe7, 0xe3, 0x7f, 0xee, 0x1c, 0x5e, + 0xd7, 0xff, 0xde, 0xfe, 0x1c, 0x11, 0xf5, 0xee, 0xc8, 0x06, 0x14, 0x1a, + 0xf0, 0xe3, 0x44, 0xfa, 0x03, 0x55, 0x2a, 0xdf, 0xfe, 0x0e, 0xea, 0x16, + 0x2d, 0xe2, 0xf3, 0xcf, 0x15, 0xed, 0x24, 0x0b, 0xbd, 0x28, 0xc3, 0xf2, + 0x0b, 0xdf, 0xd8, 0xe5, 0xd2, 0x08, 0x19, 0x18, 0xf1, 0xff, 0x19, 0x17, + 0xdb, 0x43, 0x06, 0xee, 0xe1, 0xd9, 0xe6, 0x17, 0x29, 0xd8, 0xd6, 0xe4, + 0x28, 0xc5, 0x37, 0x0d, 0xfb, 0x3e, 0xd5, 0xd4, 0xe8, 0xea, 0xf6, 0xf2, + 0xc7, 0x1a, 0x33, 0x22, 0xee, 0x05, 0x0b, 0xfe, 0xfc, 0x38, 0x68, 0xe8, + 0xf1, 0x12, 0xcb, 0x11, 0x0b, 0xec, 0xfe, 0xd1, 0x61, 0xf9, 0x14, 0x62, + 0xe7, 0x57, 0xce, 0xe1, 0x20, 0xec, 0xfc, 0xf6, 0xba, 0x1d, 0xe0, 0xd9, + 0xb9, 0xc6, 0xb1, 0x0e, 0xed, 0xed, 0x18, 0xe8, 0x0b, 0xf7, 0xe0, 0xe4, + 0xcd, 0xb0, 0x12, 0xeb, 0x07, 0xe5, 0xde, 0xf0, 0xec, 0xe6, 0xde, 0xc0, + 0xf6, 0x00, 0x14, 0x12, 0xda, 0x12, 0xeb, 0xe9, 0xe1, 0xd3, 0xd2, 0xd8, + 0xce, 0xf6, 0x47, 0xf2, 0x0b, 0xbd, 0xeb, 0xef, 0xea, 0xea, 0xc2, 0xf2, + 0x2b, 0xfe, 0xf7, 0x13, 0xcf, 0xf2, 0xf8, 0xe1, 0xf3, 0xb9, 0xd8, 0xe5, + 0xe1, 0x2d, 0xd1, 0xe0, 0xd6, 0xea, 0xce, 0xf8, 0xf5, 0xe9, 0x77, 0xe7, + 0xe4, 0xff, 0xec, 0xde, 0xcd, 0xb9, 0xf7, 0xee, 0x52, 0xdf, 0xe5, 0x70, + 0x1f, 0xe7, 0xf1, 0x9e, 0x0a, 0xf2, 0x02, 0x0a, 0x24, 0x21, 0x11, 0x06, + 0xf1, 0x16, 0xfc, 0x15, 0x05, 0x00, 0xf4, 0x13, 0x2d, 0x1a, 0x09, 0x0b, + 0xf0, 0x1a, 0x03, 0x17, 0xe2, 0x1a, 0xe4, 0xe0, 0x1a, 0xe9, 0x08, 0xea, + 0xf2, 0x02, 0x0b, 0x0a, 0x02, 0x2f, 0x0f, 0xf2, 0x2d, 0x08, 0xf5, 0x0b, + 0x03, 0x0e, 0xe2, 0x0b, 0x12, 0x39, 0xee, 0xd6, 0xdb, 0xe3, 0x19, 0x16, + 0xce, 0xf4, 0x1a, 0xe6, 0x0b, 0xf0, 0xf2, 0xd3, 0x0b, 0xfb, 0x23, 0x14, + 0x2d, 0x16, 0xfd, 0xee, 0xfa, 0x00, 0xf8, 0x09, 0x09, 0xf5, 0xf2, 0x11, + 0x2a, 0x19, 0x1c, 0x07, 0xee, 0x12, 0xe5, 0x15, 0xe4, 0x0f, 0x0f, 0xf3, + 0x10, 0xde, 0x0e, 0xef, 0x0c, 0xf9, 0xe4, 0x1b, 0xf8, 0x25, 0xc4, 0x39, + 0xec, 0xe4, 0xf6, 0x0d, 0x13, 0x09, 0x03, 0xf4, 0x56, 0x04, 0xf5, 0x08, + 0xce, 0x29, 0x1d, 0xee, 0xf7, 0x4b, 0x0a, 0x0a, 0x3a, 0xff, 0x0e, 0xec, + 0x15, 0xe5, 0xfe, 0xf4, 0xf2, 0xd6, 0xf1, 0x24, 0xeb, 0xd7, 0xf9, 0x13, + 0xf6, 0x09, 0xf7, 0xe6, 0xd7, 0x19, 0xe7, 0xe0, 0xdf, 0xf8, 0x7f, 0xed, + 0x00, 0x2b, 0xfc, 0xed, 0xe1, 0x04, 0xf3, 0xfd, 0x01, 0xd9, 0x42, 0x12, + 0x06, 0x2e, 0xe3, 0x3b, 0x08, 0xfd, 0xf1, 0x18, 0x02, 0x05, 0x15, 0xcd, + 0x38, 0xfc, 0xf7, 0x0a, 0xe2, 0x24, 0xfb, 0x06, 0xfe, 0x44, 0x04, 0xfc, + 0x51, 0x0d, 0x0c, 0xd9, 0x31, 0xf4, 0x08, 0xeb, 0x2f, 0x14, 0x25, 0xd4, + 0xfc, 0x01, 0xd4, 0xea, 0xe1, 0xd1, 0x0b, 0xc4, 0x3b, 0x14, 0x06, 0xe0, + 0xe9, 0x0c, 0xf9, 0x0f, 0xce, 0xe5, 0xe2, 0x0f, 0x11, 0xb2, 0x07, 0xf8, + 0xe4, 0xbb, 0xd5, 0xe9, 0xe1, 0x3f, 0x10, 0xcd, 0x4c, 0x01, 0xcf, 0x12, + 0xee, 0xd7, 0xca, 0xcd, 0xc6, 0x1c, 0xd6, 0xd0, 0xec, 0xec, 0x14, 0x34, + 0xb8, 0xca, 0x1c, 0xf0, 0xdf, 0xd4, 0xd2, 0x10, 0xf4, 0xf1, 0x0b, 0x1c, + 0x28, 0x23, 0x26, 0xdf, 0xf1, 0x01, 0xf6, 0xff, 0x07, 0xde, 0xf3, 0xf8, + 0x0b, 0x1c, 0x04, 0x0a, 0x0c, 0x19, 0xea, 0x2b, 0xce, 0xf3, 0xf3, 0x06, + 0xfd, 0xbd, 0xe1, 0xfa, 0x00, 0xd6, 0xc9, 0xfa, 0x3a, 0xed, 0x3d, 0xf9, + 0x25, 0x0d, 0x13, 0xf5, 0xfb, 0xee, 0xcc, 0x1a, 0xe6, 0xd2, 0x24, 0x26, + 0x13, 0x37, 0xe9, 0xe6, 0xfe, 0x26, 0x0b, 0xf4, 0xc9, 0x08, 0x1a, 0x2d, + 0x0d, 0x00, 0xfa, 0xf6, 0xf0, 0xed, 0x5c, 0x0c, 0x5f, 0x15, 0x18, 0xc3, + 0x32, 0x19, 0x10, 0xd7, 0x09, 0xb7, 0x51, 0xf7, 0xf8, 0xf2, 0xfb, 0x00, + 0xd4, 0xe8, 0x4e, 0xea, 0xfb, 0xdb, 0x1d, 0x0e, 0xd9, 0x11, 0xdc, 0x26, + 0x34, 0xd4, 0x1e, 0x18, 0xf9, 0xfc, 0x07, 0x0e, 0xd6, 0xe7, 0x04, 0xec, + 0xac, 0x02, 0x11, 0x4a, 0x4c, 0x43, 0xef, 0xf2, 0xcb, 0x1d, 0xf2, 0xe7, + 0x10, 0xf7, 0x40, 0x24, 0xe7, 0xe0, 0xda, 0xd1, 0x4e, 0xfa, 0xf3, 0xf8, + 0xf9, 0x10, 0x0f, 0xe1, 0xf6, 0xe2, 0xf0, 0x17, 0xe8, 0x01, 0xfa, 0x21, + 0xe8, 0x06, 0x85, 0x40, 0xdd, 0xf0, 0xf5, 0xf5, 0x1d, 0xfb, 0x54, 0x87, + 0x0c, 0x15, 0xea, 0xd2, 0x00, 0x11, 0x37, 0xf9, 0x31, 0x39, 0xf1, 0x08, + 0x7f, 0xf4, 0x2c, 0x18, 0xe9, 0xee, 0x33, 0x05, 0x18, 0xed, 0xf7, 0xee, + 0xc1, 0x01, 0x29, 0xd1, 0xf5, 0xe1, 0x0f, 0xfd, 0xec, 0x1d, 0xe5, 0xdc, + 0x0e, 0x01, 0xdd, 0xf7, 0xce, 0xda, 0x08, 0xe7, 0xd5, 0x00, 0xef, 0xf6, + 0xcd, 0x04, 0x09, 0x18, 0xf6, 0xe1, 0xe6, 0x37, 0x12, 0xd5, 0xf6, 0xcf, + 0x19, 0x18, 0x4e, 0xa8, 0xde, 0xee, 0xe2, 0xef, 0x35, 0xaf, 0xe1, 0x08, + 0xeb, 0xff, 0xf0, 0xd8, 0x0c, 0xb2, 0xf3, 0xdf, 0xe9, 0x0b, 0xf6, 0xfb, + 0x18, 0x1c, 0x1e, 0xb0, 0xc6, 0xf1, 0x14, 0xee, 0xf5, 0xed, 0xf6, 0x0d, + 0x0c, 0xfb, 0x0a, 0xe9, 0x04, 0xc3, 0xe9, 0x14, 0x69, 0xf2, 0x41, 0xf6, + 0x3b, 0xf6, 0xe7, 0x11, 0xd4, 0xf1, 0x4f, 0x0a, 0xe2, 0xfb, 0x24, 0xaf, + 0xf7, 0xf7, 0x66, 0xed, 0xf4, 0xc6, 0x22, 0xe9, 0xf2, 0x51, 0x0e, 0x17, + 0x45, 0x9b, 0xe1, 0x1c, 0xcc, 0x8e, 0xb7, 0xff, 0xd4, 0xb5, 0xc2, 0xb7, + 0xed, 0x0a, 0x06, 0x3a, 0x1a, 0xe3, 0x0b, 0xc2, 0xaa, 0xde, 0xb3, 0xee, + 0xf1, 0xe1, 0x2a, 0x08, 0xdd, 0xd3, 0xe0, 0xdf, 0xf4, 0x29, 0x1f, 0xdf, + 0xea, 0xda, 0xdd, 0xf5, 0xd7, 0xd1, 0xd6, 0xed, 0x09, 0xea, 0xec, 0x1f, + 0x32, 0xf9, 0x02, 0xcc, 0xed, 0xc8, 0xf3, 0xf2, 0xe4, 0xed, 0x0a, 0x2a, + 0xef, 0xfb, 0x12, 0x18, 0x29, 0x30, 0x4c, 0xd9, 0xfe, 0x10, 0xe0, 0xe5, + 0xdd, 0x42, 0xfb, 0x01, 0x2e, 0x03, 0x0b, 0x2f, 0x1a, 0x1d, 0xee, 0xd6, + 0xcc, 0x06, 0x27, 0xef, 0xe3, 0x02, 0x23, 0x7f, 0x00, 0xdb, 0x11, 0xde, + 0x03, 0x1b, 0x34, 0xfe, 0x2b, 0x0a, 0xfe, 0xf6, 0xcb, 0xf7, 0xcb, 0x10, + 0xf9, 0xf8, 0xe5, 0x11, 0x0f, 0x04, 0x02, 0xf5, 0x06, 0x05, 0xfd, 0xfc, + 0xbc, 0x0a, 0xdf, 0x39, 0xfd, 0x0a, 0x26, 0x10, 0x39, 0x0c, 0x21, 0x06, + 0xd4, 0xfb, 0x0e, 0xfa, 0xf9, 0xff, 0xf4, 0xef, 0x00, 0xdd, 0x27, 0x10, + 0xed, 0xf4, 0xf9, 0xca, 0xfd, 0x1b, 0x01, 0x0e, 0x07, 0xdf, 0x34, 0xbb, + 0xef, 0x1f, 0x26, 0xf3, 0xd6, 0xef, 0x0f, 0x37, 0xdf, 0xdc, 0x0d, 0xd1, + 0xc9, 0x1b, 0x11, 0x0b, 0x59, 0x07, 0x49, 0x1b, 0x15, 0xf1, 0xf6, 0xbe, + 0x07, 0x5b, 0x10, 0xf1, 0xb9, 0xf6, 0x0f, 0x02, 0xf9, 0x07, 0xfc, 0xd9, + 0x34, 0xeb, 0xfd, 0x1f, 0xf6, 0xfa, 0x06, 0x0a, 0xee, 0x00, 0xf9, 0x15, + 0xfc, 0x11, 0x13, 0xd5, 0xdf, 0xc0, 0xee, 0xe0, 0x12, 0x25, 0x06, 0xf9, + 0x0b, 0x05, 0x66, 0xba, 0xd2, 0x1e, 0x13, 0xd4, 0xf7, 0x28, 0x4d, 0xca, + 0x17, 0xf7, 0x19, 0x05, 0xf2, 0x0c, 0xca, 0x29, 0x14, 0xd2, 0xd9, 0x04, + 0x09, 0xf3, 0xd9, 0xc5, 0x30, 0xf0, 0xe7, 0xf9, 0xff, 0xaf, 0xf2, 0x36, + 0x23, 0x1d, 0x2f, 0x24, 0xed, 0x2d, 0x33, 0xdc, 0xe0, 0x10, 0xe9, 0xee, + 0xd4, 0x19, 0xc4, 0xe8, 0x47, 0x56, 0xec, 0x0f, 0xcf, 0x29, 0x01, 0xa2, + 0xbf, 0xf5, 0xf3, 0xeb, 0xdb, 0xcc, 0xed, 0x73, 0x33, 0xd3, 0x1b, 0xe0, + 0xeb, 0xdd, 0x17, 0xee, 0x1d, 0xf5, 0x07, 0xe4, 0x1b, 0x0b, 0xd8, 0x14, + 0xfe, 0x05, 0xf9, 0x09, 0x18, 0xeb, 0xf4, 0xc2, 0x28, 0x04, 0x08, 0xe6, + 0xe4, 0xd7, 0xfe, 0x41, 0x2c, 0x42, 0x30, 0xfd, 0xf1, 0x1f, 0x02, 0xc5, + 0x26, 0xde, 0x00, 0xee, 0xe3, 0x09, 0xe3, 0x2a, 0x04, 0xb9, 0xf7, 0xe6, + 0x02, 0xf1, 0x04, 0x08, 0x17, 0xbd, 0x19, 0x07, 0xa6, 0x0a, 0xad, 0x46, + 0xf2, 0x2a, 0x1d, 0x0d, 0x29, 0x16, 0x29, 0xd7, 0xf5, 0xe0, 0xc5, 0x0a, + 0xbb, 0xdf, 0x01, 0x40, 0x31, 0x0a, 0x17, 0x2a, 0x34, 0x5e, 0xf0, 0xe5, + 0xdc, 0xeb, 0xf0, 0xff, 0xb3, 0xe1, 0xe3, 0x67, 0x08, 0xb6, 0xda, 0xd8, + 0xe0, 0x1f, 0xfa, 0xe9, 0xf8, 0xfd, 0x2b, 0xfe, 0xf8, 0x2c, 0xd1, 0x37, + 0xfd, 0xf7, 0xef, 0xfc, 0x0c, 0xc4, 0xf7, 0xe8, 0x22, 0xee, 0xfb, 0xf2, + 0x96, 0xeb, 0xba, 0xa0, 0x28, 0x36, 0x1c, 0x11, 0x14, 0x9a, 0x10, 0xef, + 0x1b, 0xdc, 0x04, 0xe5, 0xfb, 0xfd, 0xcb, 0x03, 0xa2, 0xf0, 0x4d, 0xbd, + 0xde, 0xc8, 0x1c, 0xc7, 0xdd, 0xaa, 0x11, 0x00, 0x9b, 0xf6, 0x2c, 0x1c, + 0xd0, 0x0a, 0x2f, 0xfe, 0x28, 0xb3, 0xcd, 0xeb, 0x01, 0x12, 0x1c, 0xd7, + 0xe0, 0xf8, 0xcf, 0x1e, 0x2a, 0xf9, 0x7f, 0x13, 0xff, 0x18, 0xce, 0xe4, + 0x07, 0xf1, 0x17, 0xf2, 0xf2, 0x36, 0x30, 0x18, 0x1c, 0x43, 0xf3, 0xf9, + 0x38, 0xa4, 0xf1, 0xec, 0xd3, 0xf2, 0x23, 0x06, 0xd9, 0xee, 0xd8, 0x22, + 0xe8, 0xee, 0x50, 0xa5, 0xd1, 0xd6, 0x18, 0xd6, 0x02, 0xce, 0xfb, 0x0e, + 0x82, 0xdd, 0x3b, 0x1b, 0xf5, 0x1c, 0x17, 0xeb, 0xc0, 0xde, 0x24, 0xc4, + 0x38, 0x16, 0x44, 0xcd, 0x0a, 0x21, 0xd2, 0x05, 0xfb, 0xc4, 0xda, 0xfa, + 0x0a, 0xf9, 0xc8, 0xd1, 0x0e, 0xf3, 0x26, 0xf3, 0xb2, 0x08, 0xbd, 0x5e, + 0x09, 0x36, 0x2e, 0xc3, 0x17, 0xbd, 0x4d, 0xdd, 0x23, 0xf9, 0xfe, 0xf7, + 0xb4, 0x11, 0xf5, 0x34, 0x1e, 0x3c, 0x17, 0x07, 0x3e, 0x44, 0x01, 0xe4, + 0xf9, 0x05, 0xfd, 0xf4, 0xcc, 0x09, 0xbe, 0x59, 0x0f, 0xf4, 0xf1, 0xf4, + 0xe1, 0xe6, 0x35, 0xe3, 0x67, 0x18, 0x34, 0xcb, 0x24, 0x39, 0xb4, 0x25, + 0xec, 0xd5, 0x03, 0xdb, 0xfd, 0x04, 0xe8, 0xe3, 0x29, 0xfd, 0x23, 0xda, + 0x9b, 0x26, 0xc3, 0x43, 0x22, 0x2f, 0x1a, 0xef, 0x2c, 0xf9, 0x18, 0x33, + 0xdf, 0xff, 0x07, 0xf3, 0xf3, 0xf9, 0x38, 0xfa, 0xd7, 0x26, 0x03, 0x20, + 0x24, 0x31, 0xfb, 0xee, 0xef, 0x01, 0x0a, 0xd3, 0x3e, 0xdb, 0x31, 0xbb, + 0xfb, 0xfd, 0x07, 0xfa, 0x06, 0x16, 0xdc, 0x2b, 0xf5, 0x33, 0x0b, 0xf4, + 0x30, 0x03, 0xf2, 0xdf, 0xe8, 0xc7, 0xc2, 0x21, 0xe1, 0xb1, 0xe7, 0x1e, + 0xec, 0x00, 0x1a, 0xe0, 0x78, 0xcf, 0x4d, 0xb3, 0xf4, 0xdb, 0x08, 0xdf, + 0x21, 0x13, 0x02, 0x26, 0xd0, 0xc2, 0x03, 0xfc, 0x08, 0xd7, 0x51, 0xf0, + 0xe2, 0x24, 0x03, 0x27, 0x07, 0x1f, 0xf2, 0xed, 0xfc, 0x07, 0xf0, 0xe1, + 0x43, 0x01, 0x26, 0xc8, 0xf8, 0xfd, 0xee, 0x0d, 0xee, 0x1d, 0xf8, 0x2f, + 0xff, 0xdd, 0x08, 0xe7, 0xfd, 0x16, 0x2d, 0xec, 0xdd, 0x00, 0xe8, 0xf6, + 0x1b, 0x2f, 0x19, 0xea, 0xeb, 0x70, 0xc5, 0xe2, 0x0b, 0xf2, 0xd7, 0x0d, + 0x03, 0x08, 0x04, 0xff, 0xf2, 0x12, 0xff, 0x3a, 0xe9, 0xba, 0x16, 0xf6, + 0xee, 0x2d, 0x12, 0xc6, 0xb8, 0xff, 0x83, 0xf9, 0x06, 0xd7, 0xce, 0x1a, + 0x05, 0x09, 0x0a, 0xe4, 0xe5, 0xef, 0xe8, 0xda, 0xdb, 0xc0, 0xd1, 0xca, + 0xf7, 0x23, 0xe4, 0x1c, 0x08, 0xf9, 0x04, 0xf7, 0xeb, 0x27, 0x38, 0xf0, + 0xf9, 0xea, 0xdb, 0xfe, 0x1b, 0x30, 0xe0, 0xf4, 0x0e, 0x62, 0xfb, 0xea, + 0x25, 0x07, 0xee, 0xfc, 0x08, 0x09, 0xe1, 0xd1, 0x33, 0xf6, 0x18, 0x32, + 0xe7, 0x12, 0xf3, 0x27, 0xfd, 0xbd, 0x52, 0xcd, 0xa3, 0x36, 0x25, 0x17, + 0x08, 0x37, 0x09, 0x05, 0xee, 0x14, 0xfe, 0xeb, 0x5d, 0x01, 0x45, 0xe1, + 0xee, 0x06, 0x07, 0xee, 0xf3, 0x16, 0xe2, 0x16, 0x04, 0x3c, 0x08, 0xf9, + 0x39, 0x23, 0x12, 0xd7, 0xe1, 0xa4, 0xde, 0x0e, 0xb1, 0xf1, 0xbe, 0x18, + 0x16, 0xe5, 0x22, 0x0b, 0x7f, 0xf6, 0x49, 0xea, 0x09, 0xe9, 0xe8, 0xb8, + 0x1d, 0x05, 0x1d, 0xed, 0xf2, 0x13, 0xd9, 0xf6, 0x12, 0xe5, 0x68, 0xe6, + 0xd5, 0x18, 0x21, 0x17, 0xfd, 0x2a, 0xef, 0xef, 0x08, 0xf8, 0x10, 0x11, + 0x4e, 0xfb, 0x37, 0xf5, 0xfc, 0xf0, 0xf5, 0xf9, 0x15, 0xfe, 0x22, 0x23, + 0x08, 0xfd, 0xf9, 0x08, 0x00, 0xee, 0x02, 0xf9, 0xe5, 0x15, 0x0c, 0x05, + 0x07, 0x05, 0x14, 0x05, 0xf7, 0x0f, 0x31, 0xdf, 0x1b, 0x1c, 0x0c, 0xde, + 0xfe, 0xfc, 0x04, 0x02, 0x09, 0x11, 0x16, 0x0d, 0x37, 0xf1, 0xf7, 0xfc, + 0x2a, 0x47, 0xf3, 0xe6, 0x04, 0xe4, 0x00, 0x09, 0xe7, 0x1e, 0xf1, 0x11, + 0xe2, 0xfd, 0x38, 0xe5, 0xfc, 0xea, 0x0a, 0x2a, 0x19, 0xf2, 0xec, 0xd7, + 0x2f, 0x0b, 0xfa, 0x01, 0x23, 0x12, 0xf8, 0x09, 0x00, 0xd5, 0x13, 0xf8, + 0xe8, 0xec, 0x0d, 0x3d, 0xfc, 0x0a, 0xfd, 0x15, 0xb3, 0xfb, 0x29, 0xd0, + 0x2c, 0x37, 0x23, 0xe8, 0xe6, 0xee, 0x0e, 0x0d, 0x2d, 0x1b, 0x2c, 0x1f, + 0xf7, 0x1f, 0x26, 0xfb, 0x04, 0x2f, 0x4f, 0xfb, 0xea, 0x05, 0xd9, 0xee, + 0xd7, 0x04, 0xfa, 0xf1, 0x29, 0x1d, 0x14, 0x09, 0x07, 0x35, 0x4c, 0xc6, + 0xf2, 0xfd, 0xee, 0xee, 0xdd, 0x18, 0x15, 0x0c, 0xeb, 0xe4, 0xec, 0xfc, + 0xea, 0x20, 0x7f, 0xb5, 0xb3, 0xff, 0x36, 0x02, 0x12, 0xbf, 0xf8, 0x19, + 0xfd, 0xe7, 0x21, 0x07, 0xc9, 0x19, 0x00, 0xe4, 0xd1, 0xcb, 0x05, 0xd4, + 0x3e, 0x1b, 0x01, 0x27, 0xff, 0xfc, 0x1d, 0x0e, 0x30, 0x29, 0x2d, 0x00, + 0xee, 0x01, 0x02, 0x09, 0x01, 0x0f, 0xe7, 0xef, 0x19, 0x1a, 0x0b, 0xe9, + 0x2c, 0x16, 0x4e, 0xe1, 0xf1, 0xf0, 0xe7, 0xd3, 0x16, 0xed, 0x0d, 0x36, + 0xfc, 0xf9, 0xf3, 0xd9, 0xfe, 0xd6, 0x00, 0xf8, 0xed, 0xee, 0xf2, 0x07, + 0xfa, 0x0a, 0x04, 0xd2, 0x23, 0x04, 0x0f, 0x24, 0x0b, 0x25, 0x0a, 0xf8, + 0x0b, 0x00, 0x12, 0xf6, 0xd9, 0xff, 0xbb, 0x1c, 0x03, 0xca, 0xda, 0xc0, + 0xf6, 0x03, 0xf0, 0xc1, 0xe7, 0xfe, 0xe1, 0xe6, 0xa9, 0x3b, 0xf2, 0xca, + 0xfd, 0xbf, 0x61, 0x09, 0xdd, 0xdc, 0xf6, 0x37, 0x10, 0xcf, 0x21, 0xe0, + 0x15, 0x00, 0x1f, 0x08, 0x1b, 0xe3, 0xed, 0xf6, 0x03, 0xd3, 0xf2, 0xee, + 0xda, 0x0d, 0xe2, 0x2f, 0x0f, 0x03, 0xfc, 0xd8, 0xe0, 0xdf, 0x30, 0x02, + 0xfe, 0x22, 0x09, 0xfe, 0x0a, 0xfa, 0x0b, 0x0e, 0x0b, 0xe9, 0xf9, 0xd8, + 0xe5, 0xdd, 0x02, 0xf8, 0x07, 0x0d, 0x26, 0xf9, 0xf5, 0x08, 0xf4, 0xfc, + 0x2a, 0x05, 0xf2, 0xe4, 0x0f, 0xee, 0xe9, 0xe8, 0x24, 0xbc, 0x03, 0x00, + 0x19, 0x1c, 0x10, 0xf5, 0x2e, 0x02, 0xf6, 0xea, 0xf3, 0x07, 0xc7, 0xf9, + 0xee, 0xc3, 0x13, 0xfa, 0xf4, 0x01, 0xe5, 0x26, 0x06, 0xd4, 0x0c, 0x0f, + 0xe4, 0xfb, 0x06, 0xfd, 0x26, 0xd7, 0x18, 0xd1, 0xed, 0xe3, 0x17, 0x05, + 0x19, 0x0e, 0xf9, 0xc7, 0xe9, 0xef, 0x12, 0x06, 0x21, 0x0e, 0x57, 0x01, + 0x02, 0x2d, 0xf4, 0x0f, 0x23, 0x12, 0xf3, 0x03, 0x56, 0xe8, 0xe0, 0x42, + 0x2f, 0xd1, 0x0c, 0xdf, 0x37, 0x1c, 0xf8, 0xe8, 0xef, 0xf5, 0xe3, 0xd6, + 0xe2, 0xe3, 0xf4, 0xdf, 0xd5, 0x01, 0xe9, 0x11, 0x06, 0xf5, 0xdf, 0xda, + 0xdc, 0x12, 0x1d, 0xe7, 0xfe, 0xf1, 0xd8, 0xf9, 0xe9, 0xe7, 0xab, 0x0a, + 0x16, 0x47, 0x27, 0xf8, 0xe4, 0x24, 0xe3, 0xf5, 0xf4, 0xf5, 0x1a, 0xf8, + 0xc4, 0x0d, 0x08, 0x11, 0xdf, 0xea, 0xd9, 0xd8, 0x05, 0x04, 0xf7, 0x01, + 0x01, 0xf9, 0x13, 0x04, 0xe3, 0x07, 0xba, 0xe5, 0xef, 0x12, 0x06, 0x1e, + 0xef, 0xfb, 0xef, 0xf3, 0xd3, 0xe0, 0xea, 0xcd, 0xf1, 0x04, 0x2f, 0x0c, + 0x01, 0xf2, 0xd9, 0xe0, 0xe9, 0x15, 0xfb, 0xe6, 0x38, 0xf6, 0xb9, 0x48, + 0xfb, 0xf1, 0xe1, 0x00, 0x1f, 0x25, 0x22, 0xea, 0xef, 0xd5, 0xef, 0x00, + 0xdf, 0xef, 0xf0, 0x20, 0xed, 0xf1, 0x37, 0xef, 0xe9, 0x2e, 0x09, 0xde, + 0xf1, 0xd5, 0x1f, 0x06, 0x30, 0xe5, 0xdd, 0xec, 0x3f, 0xe1, 0x0d, 0xd8, + 0x0f, 0x29, 0x0f, 0xe3, 0x04, 0xef, 0xee, 0x13, 0xe7, 0x24, 0xdd, 0xe8, + 0xe5, 0xfa, 0x18, 0xe8, 0xc5, 0x00, 0xdc, 0x15, 0x03, 0xe1, 0x02, 0x11, + 0x11, 0xf3, 0xf7, 0x27, 0x19, 0xe1, 0x11, 0xe5, 0xf0, 0xf7, 0xfd, 0xfc, + 0xf1, 0xcd, 0xe8, 0xef, 0xce, 0x10, 0x24, 0xfe, 0x04, 0xc8, 0x6d, 0xf6, + 0xfa, 0x37, 0xe6, 0xf3, 0x0d, 0xe1, 0xd9, 0x00, 0x7f, 0xde, 0xd7, 0x63, + 0x2b, 0xed, 0x02, 0xb3, 0x19, 0x27, 0x1b, 0xd8, 0xfc, 0xc3, 0x07, 0x25, + 0x23, 0xf2, 0xed, 0xe5, 0xf2, 0xc2, 0xd1, 0xe5, 0x0d, 0xfc, 0xef, 0xee, + 0xe7, 0xf6, 0x0b, 0xbb, 0x0d, 0xfb, 0x11, 0x00, 0xfd, 0x32, 0xe5, 0x25, + 0x25, 0x05, 0x1e, 0xf3, 0xde, 0xca, 0xc5, 0x0c, 0xfd, 0xcf, 0x08, 0x1c, + 0xfa, 0x11, 0xdd, 0xf6, 0xfe, 0x10, 0xe4, 0x04, 0xa3, 0x2a, 0x0c, 0xfd, + 0x14, 0xf2, 0x2d, 0x00, 0xb6, 0xe2, 0xf2, 0x11, 0xfa, 0x28, 0x54, 0x07, + 0xd3, 0xe5, 0xff, 0x1a, 0x41, 0xf9, 0xcd, 0xe5, 0x4f, 0xcb, 0x09, 0xce, + 0x10, 0x02, 0xed, 0x10, 0x0d, 0xf6, 0x0e, 0xe3, 0xaf, 0xfe, 0x1c, 0xe6, + 0x12, 0x58, 0x05, 0xfc, 0x43, 0xf8, 0x1d, 0x05, 0x7f, 0xe8, 0x20, 0xb9, + 0xff, 0x21, 0x25, 0xf0, 0x12, 0x16, 0xf5, 0xeb, 0xfe, 0x1d, 0x01, 0xd9, + 0xcb, 0xda, 0xc4, 0xd4, 0x11, 0xd8, 0x1b, 0x16, 0x00, 0x3a, 0x48, 0xad, + 0x16, 0x0c, 0xeb, 0xe4, 0xaa, 0x3f, 0x1f, 0xcf, 0x29, 0x05, 0xe8, 0x05, + 0x0f, 0x06, 0x60, 0xd8, 0xd9, 0x32, 0x25, 0x10, 0x15, 0xbd, 0x25, 0xfa, + 0xc8, 0xf2, 0x1c, 0xe8, 0xcc, 0x0f, 0x28, 0xe5, 0xce, 0x12, 0x5c, 0x0b, + 0x65, 0xf9, 0x1a, 0xf4, 0x06, 0x20, 0x19, 0xef, 0x39, 0x22, 0xe3, 0x05, + 0xf4, 0xfb, 0x10, 0x28, 0xf8, 0xe2, 0xed, 0xea, 0x03, 0xaa, 0x1b, 0xf6, + 0x06, 0x13, 0x2a, 0xf2, 0x2a, 0xf4, 0xc4, 0xe4, 0x00, 0x09, 0x1f, 0x18, + 0x1c, 0xf1, 0x0c, 0xf9, 0x04, 0xc4, 0xf6, 0x30, 0x0d, 0xfb, 0xec, 0xf0, + 0x07, 0xff, 0xf8, 0xdb, 0x23, 0x39, 0x02, 0x17, 0xea, 0x1e, 0xf2, 0x20, + 0x4f, 0x0e, 0x1b, 0x03, 0xce, 0xfb, 0xe9, 0x04, 0xc8, 0xc8, 0xe0, 0x0a, + 0xd7, 0x23, 0xe0, 0xed, 0x0d, 0x46, 0xe1, 0xf9, 0xa7, 0x3d, 0x13, 0xc5, + 0x13, 0xfe, 0x49, 0x03, 0xb3, 0xc3, 0xe0, 0x69, 0xee, 0xde, 0x5a, 0xf9, + 0xe7, 0xf0, 0xfa, 0x2b, 0x2c, 0xf6, 0xca, 0xf7, 0x3b, 0xcf, 0xe1, 0x13, + 0x0a, 0xf2, 0xfa, 0x0e, 0x0b, 0xc8, 0x04, 0xe5, 0xeb, 0x1c, 0x25, 0xfc, + 0xf2, 0x4a, 0xf2, 0xf8, 0x57, 0x2c, 0x1a, 0x04, 0xe7, 0xd6, 0xf6, 0x1d, + 0x17, 0x10, 0xd8, 0xd4, 0x05, 0x08, 0x0e, 0xf8, 0xe5, 0xe1, 0xf5, 0x20, + 0x2d, 0xea, 0xfe, 0xe9, 0x0a, 0xea, 0xfe, 0x0a, 0x16, 0x40, 0x0e, 0x0c, + 0xec, 0xc9, 0xde, 0xcb, 0x06, 0xc3, 0x05, 0x3f, 0x0f, 0x04, 0x31, 0xf6, + 0xea, 0x37, 0x2e, 0x35, 0xa5, 0x1b, 0x05, 0x64, 0x42, 0xc8, 0x05, 0xfd, + 0x0f, 0x22, 0xfc, 0xf2, 0x06, 0x42, 0x30, 0xd8, 0xf5, 0xd4, 0xd2, 0xd2, + 0xd9, 0xea, 0x02, 0x20, 0x0c, 0xfc, 0x04, 0xe7, 0xf3, 0x01, 0xfd, 0x2a, + 0xf8, 0xe4, 0xe8, 0xfe, 0x1b, 0xe4, 0xeb, 0xff, 0x31, 0x25, 0x06, 0xe7, + 0x21, 0x1c, 0xff, 0xee, 0xfb, 0x0f, 0xff, 0xd7, 0xc1, 0xda, 0xfd, 0x17, + 0x3e, 0xf8, 0xdd, 0xf5, 0xf2, 0xe3, 0xdd, 0xae, 0xd1, 0x1e, 0xba, 0xd3, + 0xd5, 0x19, 0xf6, 0xc9, 0xf5, 0xe3, 0xf1, 0x03, 0x0e, 0x10, 0xc0, 0x50, + 0xec, 0xc9, 0x02, 0xe8, 0xb3, 0x0d, 0xed, 0x18, 0x08, 0xf6, 0xfd, 0x96, + 0xe1, 0xef, 0xde, 0x10, 0x27, 0xce, 0x3f, 0xd0, 0xb3, 0x36, 0xe7, 0xd0, + 0x0e, 0x01, 0xfb, 0xf1, 0xb7, 0x1f, 0xbb, 0x59, 0xde, 0x23, 0xec, 0x06, + 0xe2, 0xdf, 0x0c, 0xe4, 0x35, 0x06, 0x06, 0x01, 0xe2, 0xf5, 0xe6, 0xee, + 0xf3, 0x06, 0xd5, 0xd4, 0xf2, 0x07, 0xfd, 0xb0, 0x17, 0xe0, 0xea, 0xf9, + 0x26, 0xec, 0xd6, 0x55, 0xf4, 0x24, 0x2f, 0xf4, 0xdd, 0xfc, 0x23, 0x2d, + 0x33, 0x15, 0x15, 0xe5, 0x10, 0x2f, 0x0d, 0x11, 0x0a, 0xee, 0xe3, 0x0c, + 0x2d, 0x02, 0x07, 0xd5, 0x25, 0x2d, 0x13, 0xfa, 0x0a, 0x4d, 0xed, 0x39, + 0xed, 0xfa, 0xf8, 0xec, 0x05, 0xea, 0x1b, 0x4a, 0x24, 0x01, 0x42, 0x11, + 0xf4, 0x2c, 0x24, 0x52, 0x14, 0x4a, 0x0d, 0x7f, 0x6f, 0xff, 0x1f, 0xc0, + 0xfa, 0x3a, 0x07, 0xd7, 0xe8, 0x43, 0x29, 0x30, 0x1a, 0x11, 0xea, 0xcd, + 0xf4, 0xf7, 0x08, 0x58, 0x39, 0xf3, 0x25, 0xe5, 0xeb, 0x1d, 0x03, 0x20, + 0xec, 0xed, 0xf3, 0x04, 0x21, 0xf8, 0xfb, 0xee, 0x32, 0x19, 0x21, 0x00, + 0xc7, 0x39, 0xe0, 0x1c, 0xf8, 0x10, 0x12, 0xee, 0x11, 0x16, 0x3b, 0xd8, + 0xee, 0xe7, 0xe8, 0xfe, 0xe6, 0xe8, 0xed, 0xf7, 0xfa, 0xdc, 0xf0, 0x0b, + 0x23, 0xfe, 0xfe, 0xd7, 0x01, 0xe7, 0xf0, 0xf9, 0xfb, 0xe9, 0xfd, 0x02, + 0x05, 0xf5, 0x15, 0x07, 0x29, 0x30, 0x38, 0xd4, 0xdc, 0xf3, 0xe4, 0xd7, + 0xf7, 0x1d, 0xf1, 0x16, 0x34, 0xe4, 0x10, 0x11, 0x0a, 0xf4, 0xd5, 0xde, + 0xdc, 0xf8, 0x1a, 0x01, 0x04, 0xce, 0x1c, 0x7f, 0xf1, 0xd7, 0x05, 0xde, + 0x17, 0x23, 0x3e, 0xe6, 0x2b, 0xe7, 0xde, 0xfe, 0xa7, 0xe1, 0xca, 0x0c, + 0xf7, 0x01, 0xfc, 0x0f, 0x23, 0x19, 0x08, 0xf8, 0xfb, 0xfe, 0x00, 0x02, + 0xc9, 0x08, 0x16, 0x25, 0xf4, 0xce, 0x09, 0x10, 0x33, 0x12, 0x22, 0x23, + 0xd2, 0x02, 0x1f, 0xf4, 0xe4, 0xf9, 0x17, 0x10, 0x0c, 0xc1, 0x36, 0x06, + 0xfe, 0xeb, 0xfc, 0xd9, 0xe5, 0x2a, 0xfd, 0xfa, 0xff, 0xf3, 0x27, 0xc0, + 0xe2, 0x1a, 0x1f, 0xea, 0xcc, 0xdd, 0x26, 0x2f, 0xbd, 0xd3, 0x06, 0xe1, + 0xc8, 0x1d, 0x0c, 0xed, 0x60, 0xfb, 0x4b, 0x1c, 0x0c, 0xfc, 0xf4, 0xaa, + 0x14, 0x25, 0xfb, 0xf4, 0xb8, 0xfc, 0x01, 0x28, 0x01, 0xf4, 0xe3, 0xec, + 0x47, 0x00, 0x05, 0x14, 0xe4, 0x12, 0x16, 0x02, 0xd3, 0x06, 0x2e, 0xeb, + 0x1c, 0x06, 0xfd, 0xe0, 0x01, 0xda, 0xfe, 0xd5, 0x11, 0x30, 0x1a, 0xee, + 0x07, 0x03, 0x5e, 0xaf, 0xc7, 0x35, 0x0f, 0xe2, 0xf3, 0x26, 0x46, 0xc8, + 0x16, 0x00, 0x33, 0x00, 0xea, 0x15, 0xe0, 0x25, 0xf9, 0xdf, 0xf9, 0x04, + 0x0e, 0x20, 0xd9, 0xcb, 0x22, 0xeb, 0xf9, 0xdb, 0xf3, 0xda, 0xf4, 0x25, + 0x09, 0x19, 0x22, 0x3c, 0x07, 0x3e, 0x50, 0xe0, 0xff, 0x21, 0xe9, 0xe4, + 0xec, 0x20, 0xc0, 0xfa, 0x44, 0x1d, 0xf9, 0x04, 0xf0, 0x1e, 0xf8, 0xe0, + 0x9a, 0x0c, 0x2a, 0xed, 0xf2, 0xe9, 0x06, 0x3a, 0x1a, 0xd5, 0x0b, 0xdb, + 0x04, 0x02, 0x23, 0xd2, 0xfc, 0x1a, 0x26, 0xfc, 0xeb, 0x11, 0xbd, 0x22, + 0xfc, 0xff, 0xfb, 0xfe, 0x17, 0x09, 0xdd, 0xe4, 0x26, 0xff, 0xee, 0xea, + 0xc6, 0xc8, 0xe7, 0x17, 0x26, 0x3f, 0x1f, 0x01, 0xff, 0x1d, 0xe2, 0xd9, + 0xea, 0x52, 0x3f, 0x21, 0xc9, 0x62, 0xb6, 0x49, 0xfc, 0xef, 0x04, 0x09, + 0x1c, 0xd4, 0x0c, 0x0f, 0xf7, 0xe5, 0xcc, 0xd8, 0xdd, 0xb0, 0xe7, 0x1d, + 0xe1, 0x45, 0x17, 0x48, 0x54, 0x38, 0x09, 0xda, 0xc8, 0x75, 0xff, 0xe4, + 0xed, 0x04, 0x16, 0x08, 0x48, 0xd5, 0x39, 0x13, 0x39, 0x05, 0xbc, 0xf3, + 0xc9, 0xcf, 0xfc, 0x00, 0x07, 0x18, 0x21, 0x51, 0x23, 0xc7, 0xd5, 0xf5, + 0x0b, 0x44, 0xfc, 0xad, 0x0d, 0x3b, 0xef, 0x24, 0x14, 0x20, 0x07, 0xf6, + 0x07, 0xed, 0xf5, 0x08, 0x1d, 0x06, 0xe4, 0x2d, 0xbc, 0xc9, 0x00, 0xe7, + 0x00, 0xcd, 0x1c, 0x1e, 0xe8, 0x02, 0x21, 0x26, 0x07, 0x06, 0x91, 0x10, + 0xd1, 0xe9, 0xbc, 0x2b, 0xbb, 0xe4, 0xf5, 0x09, 0x05, 0xeb, 0x37, 0xbc, + 0xcc, 0x1f, 0x54, 0xe9, 0x02, 0x5a, 0xd2, 0xef, 0x1a, 0x9c, 0xf6, 0x32, + 0xd6, 0x41, 0x60, 0x2a, 0x10, 0xcf, 0xe9, 0x72, 0xe0, 0xd5, 0xf3, 0xf4, + 0xa5, 0x17, 0xb2, 0x03, 0x7f, 0xdc, 0x62, 0xe8, 0xef, 0x4f, 0xdf, 0xb7, + 0x24, 0x3e, 0xd6, 0xf8, 0xa2, 0xe8, 0xd6, 0x42, 0xdf, 0xc5, 0xaf, 0xee, + 0x26, 0xe5, 0xd0, 0x37, 0xe6, 0xef, 0xd7, 0x45, 0xd5, 0xfa, 0x37, 0xfc, + 0x0e, 0xea, 0x5f, 0xdb, 0xd4, 0x1a, 0x4b, 0xff, 0x12, 0x72, 0xd6, 0x00, + 0x0b, 0xde, 0x44, 0x4a, 0x8d, 0x2b, 0x55, 0xd0, 0xcb, 0x54, 0x2d, 0xca, + 0x02, 0x2e, 0x3a, 0x1a, 0xce, 0x5f, 0xab, 0x10, 0x09, 0x1d, 0xff, 0xe5, + 0x08, 0x05, 0xda, 0x20, 0x38, 0xf4, 0xc2, 0xef, 0xc1, 0x94, 0xd9, 0x2a, + 0xfe, 0x21, 0xf1, 0xda, 0x6d, 0x26, 0x0d, 0xe9, 0x25, 0x59, 0xed, 0xb2, + 0xf4, 0xf8, 0xb0, 0xd6, 0xff, 0x25, 0xcd, 0x11, 0x52, 0x10, 0xe7, 0x00, + 0x9c, 0xee, 0xab, 0x12, 0xff, 0x0c, 0xef, 0x76, 0x35, 0xa5, 0xd0, 0xd4, + 0xbf, 0x2d, 0x19, 0xb9, 0xed, 0x68, 0x17, 0x47, 0x02, 0x1e, 0x9f, 0x0b, + 0x21, 0x15, 0xfc, 0xb0, 0x03, 0xe6, 0xdf, 0x38, 0x28, 0xd6, 0xaa, 0x0a, + 0xc0, 0x8f, 0xcb, 0x06, 0x0e, 0xf4, 0x40, 0x0b, 0x22, 0x08, 0x1a, 0x0b, + 0xde, 0xe3, 0x16, 0xf2, 0xec, 0x02, 0x32, 0xf0, 0xf2, 0x19, 0xfe, 0xfb, + 0x09, 0x06, 0x04, 0xe9, 0xfe, 0xe8, 0x0f, 0xf9, 0x0a, 0x08, 0xea, 0xe9, + 0x2f, 0x04, 0xfc, 0xf6, 0xe7, 0x2b, 0x04, 0x02, 0xea, 0xfd, 0x1e, 0xfa, + 0xff, 0x15, 0x2c, 0xf1, 0xea, 0x02, 0xec, 0x03, 0x01, 0xe1, 0x0a, 0x14, + 0x0a, 0xf2, 0x0d, 0xfa, 0xec, 0x16, 0x0b, 0xce, 0x04, 0xff, 0x1d, 0xfd, + 0x0e, 0x0c, 0x2c, 0xfb, 0xe9, 0xf2, 0x13, 0xeb, 0x00, 0x09, 0x78, 0xfd, + 0xf7, 0x13, 0xff, 0x06, 0x10, 0x0d, 0xf9, 0xf4, 0x3c, 0xf4, 0x23, 0x29, + 0x2c, 0xfc, 0x0a, 0x01, 0x28, 0x02, 0xf7, 0xfb, 0x08, 0xfb, 0xf1, 0x1d, + 0xe5, 0xe7, 0x34, 0xff, 0xd3, 0x3d, 0x54, 0xe2, 0xb8, 0x09, 0xe1, 0xec, + 0xea, 0x1b, 0x0b, 0xe1, 0x36, 0xf7, 0x2f, 0xfa, 0xca, 0x4d, 0xde, 0xd1, + 0x15, 0xfb, 0xeb, 0xf9, 0xe0, 0xf7, 0xe4, 0x1c, 0xe1, 0xdc, 0x37, 0xf9, + 0xd7, 0x42, 0x1d, 0xe2, 0xc3, 0xe3, 0xbd, 0xfa, 0x19, 0xc4, 0xdf, 0x20, + 0x27, 0xd2, 0x2f, 0x08, 0xf9, 0x57, 0xf0, 0xc7, 0xe8, 0x02, 0x0c, 0xcf, + 0xde, 0xf1, 0xf9, 0x1a, 0xfe, 0xf7, 0x1b, 0xfd, 0xde, 0x4f, 0x64, 0xe9, + 0xdc, 0x11, 0xc1, 0xfa, 0xf3, 0x14, 0xfe, 0xf0, 0x41, 0xf8, 0x2f, 0x39, + 0xff, 0x55, 0xd6, 0xd3, 0x2a, 0x12, 0xfd, 0xe5, 0x1e, 0xf5, 0xdc, 0x04, + 0xc0, 0xaf, 0xcd, 0xef, 0xb0, 0xf4, 0x28, 0xe8, 0xc0, 0xee, 0x13, 0xdb, + 0xc5, 0x03, 0x00, 0xd6, 0x20, 0xeb, 0xfa, 0x14, 0xf4, 0xf5, 0xed, 0xca, + 0xf0, 0xdf, 0xdc, 0xf2, 0xc7, 0x0e, 0xf0, 0x0a, 0x03, 0xd9, 0xe9, 0xce, + 0xdb, 0xf7, 0x2b, 0xec, 0xc9, 0xbe, 0xf1, 0xeb, 0xe9, 0xef, 0xda, 0x09, + 0x20, 0xea, 0x32, 0x08, 0xe1, 0xfc, 0xeb, 0xdf, 0xe0, 0xda, 0xe2, 0xde, + 0x2a, 0x01, 0xeb, 0x01, 0xd3, 0xda, 0xe7, 0xd3, 0xe7, 0xe8, 0x7f, 0xf8, + 0xdd, 0xd5, 0x0b, 0xf9, 0xe5, 0x0b, 0xd1, 0xe3, 0x73, 0x13, 0xfe, 0x5e, + 0x1b, 0xf9, 0xf6, 0xc6, 0x1e, 0x0b, 0xe1, 0xe7, 0x01, 0xe0, 0xd2, 0x7f, + 0x0a, 0xdc, 0xda, 0x20, 0xf4, 0xea, 0xf7, 0xcd, 0xf0, 0x0b, 0x14, 0x30, + 0x39, 0xf5, 0x1f, 0xda, 0xd8, 0xf5, 0xde, 0xf1, 0x0d, 0xe5, 0x3b, 0x12, + 0xa4, 0xd7, 0x0b, 0xf1, 0x3d, 0xd1, 0xa3, 0x76, 0xd7, 0x23, 0x0f, 0xdd, + 0x23, 0x0c, 0x06, 0xd2, 0xff, 0xa8, 0x26, 0x29, 0xf9, 0xe6, 0xf3, 0xf4, + 0x0a, 0xfd, 0xdb, 0xf1, 0x69, 0xe9, 0x44, 0x05, 0xdd, 0x0c, 0xef, 0x26, + 0x07, 0xda, 0xdd, 0x34, 0xdb, 0x00, 0xc5, 0x39, 0xf3, 0xde, 0x0a, 0xc8, + 0xdb, 0x15, 0xf8, 0x30, 0x0d, 0x00, 0x02, 0x09, 0xfe, 0xd5, 0xcf, 0x13, + 0x18, 0xd9, 0x2a, 0x0e, 0xc3, 0x01, 0x0b, 0xca, 0xcc, 0x03, 0xdd, 0x23, + 0x20, 0xd3, 0xfe, 0xe1, 0x17, 0x08, 0xfe, 0x0a, 0xec, 0x0b, 0xed, 0x19, + 0x23, 0xfa, 0x0b, 0x1d, 0xd3, 0x5e, 0xe9, 0xe3, 0x31, 0xdf, 0x3b, 0x42, + 0xbe, 0xde, 0xfc, 0xf6, 0x1a, 0x27, 0x09, 0x39, 0x22, 0xf6, 0xe0, 0x0c, + 0xf9, 0x10, 0xf0, 0x03, 0x17, 0xd1, 0xc1, 0xfe, 0x0f, 0xff, 0xf4, 0xe8, + 0xf1, 0x24, 0x07, 0xdd, 0xf1, 0xdd, 0x06, 0x21, 0xc3, 0xd2, 0xd0, 0x0a, + 0xd9, 0xf9, 0xc4, 0x3b, 0x0c, 0xde, 0xfd, 0xf0, 0xfc, 0x1a, 0x15, 0x08, + 0xf2, 0xfe, 0xed, 0x0f, 0x13, 0xec, 0xf7, 0x13, 0x13, 0x4e, 0xd4, 0xdd, + 0x3d, 0xe8, 0x1f, 0x2f, 0xc0, 0xe4, 0xed, 0xe4, 0xff, 0xfc, 0xf8, 0x3f, + 0xf4, 0x42, 0xe0, 0x21, 0xf0, 0xb8, 0x09, 0xc4, 0xe9, 0x29, 0x0e, 0x30, + 0x19, 0x11, 0x03, 0xf6, 0xa6, 0xeb, 0xf7, 0xeb, 0x32, 0xef, 0x3e, 0xd6, + 0xca, 0xfa, 0x0d, 0xf7, 0x03, 0xdd, 0xdb, 0x55, 0xd1, 0x2b, 0x3d, 0xeb, + 0x34, 0x47, 0x09, 0xf1, 0xfd, 0xb6, 0x18, 0x10, 0xe9, 0xd2, 0xf5, 0x02, + 0x2d, 0x06, 0xdd, 0xec, 0x65, 0x02, 0x1c, 0xc1, 0x19, 0x31, 0xe8, 0x02, + 0x05, 0xe5, 0xf1, 0x41, 0xf5, 0x21, 0xde, 0x1a, 0xe9, 0xd2, 0x27, 0xbb, + 0xd7, 0x15, 0x09, 0x3a, 0x06, 0x0e, 0x0c, 0x11, 0xde, 0x07, 0xf3, 0x0e, + 0x3f, 0x02, 0x35, 0x07, 0xb5, 0xf2, 0xf2, 0xf4, 0xd8, 0xdb, 0xb1, 0x29, + 0x10, 0xe4, 0x10, 0xf3, 0x06, 0x18, 0x1a, 0xde, 0xe2, 0x17, 0x02, 0x10, + 0xfe, 0x03, 0x0e, 0x11, 0xfb, 0x19, 0x06, 0xe2, 0x3b, 0x20, 0x15, 0xdc, + 0xc8, 0xda, 0x04, 0xef, 0xf7, 0xb8, 0xd1, 0x32, 0x20, 0xe9, 0x0b, 0x35, + 0x01, 0xf9, 0xf8, 0xef, 0xcd, 0x9c, 0xb4, 0x35, 0x34, 0xe9, 0x05, 0x25, + 0xfa, 0x0d, 0x09, 0xef, 0x34, 0x1b, 0x11, 0xfe, 0xde, 0xde, 0xf9, 0xd0, + 0xf6, 0xdf, 0xbd, 0xfe, 0x4e, 0x36, 0x1a, 0xcb, 0x3a, 0x22, 0x16, 0xce, + 0xee, 0xee, 0x06, 0xf8, 0xf2, 0xf5, 0xe8, 0x14, 0xc6, 0x05, 0x21, 0xf5, + 0x22, 0x21, 0x03, 0xfa, 0xb6, 0xf0, 0xfd, 0xdb, 0xd6, 0xfc, 0x06, 0xd5, + 0x2b, 0xfd, 0xc1, 0x1b, 0x02, 0xee, 0xb7, 0xd0, 0xd8, 0x16, 0x0c, 0xaf, + 0xca, 0x55, 0x4b, 0xcb, 0xdc, 0xe5, 0x08, 0xeb, 0x81, 0xf5, 0x9c, 0x79, + 0x02, 0x0b, 0x13, 0x21, 0x1a, 0x1c, 0xe2, 0xc0, 0x01, 0xd2, 0xe8, 0xca, + 0xf2, 0xf7, 0xcf, 0xd5, 0xe9, 0xa1, 0x95, 0xd4, 0xec, 0x3f, 0xbf, 0x3b, + 0xfa, 0xb5, 0x1b, 0xe2, 0x21, 0xf9, 0x10, 0x1b, 0xee, 0xd1, 0x04, 0x06, + 0xb3, 0xed, 0x04, 0xe6, 0x2f, 0x01, 0xf1, 0xe2, 0x1f, 0xf4, 0xc3, 0xd1, + 0xd6, 0xe3, 0x06, 0x03, 0xed, 0x31, 0x44, 0xc8, 0xf0, 0xb7, 0xff, 0xf7, + 0xe9, 0x00, 0xdf, 0x60, 0xe5, 0x02, 0x1e, 0xed, 0xcf, 0xe8, 0xb3, 0x1e, + 0x08, 0x3b, 0x3d, 0x27, 0x1f, 0x0e, 0xa4, 0xe9, 0xe8, 0x38, 0xfb, 0xbf, + 0xed, 0xf7, 0x23, 0x1e, 0xf3, 0x0d, 0xfe, 0xc2, 0xb9, 0x35, 0xa3, 0xf7, + 0xf0, 0x02, 0x03, 0x05, 0xef, 0xce, 0xe0, 0x15, 0xe9, 0xfd, 0x05, 0x3a, + 0xf3, 0xd1, 0xb6, 0x00, 0xf7, 0xa9, 0xc0, 0x54, 0x43, 0xc2, 0xe7, 0x24, + 0x1b, 0x37, 0x9b, 0xef, 0xe8, 0x05, 0x12, 0xca, 0x1f, 0xd2, 0xe4, 0xfc, + 0xd8, 0xe5, 0x9a, 0xfc, 0x26, 0x15, 0x1a, 0x0c, 0x22, 0x29, 0x11, 0x08, + 0x2d, 0x11, 0x01, 0x07, 0xfd, 0xdb, 0xf2, 0x07, 0xcc, 0xe0, 0xfc, 0xe0, + 0x2f, 0x0c, 0x16, 0xca, 0xb4, 0x09, 0xe4, 0xef, 0xd5, 0xf0, 0xf5, 0xc9, + 0x11, 0x0d, 0x33, 0xc5, 0xf8, 0x30, 0xeb, 0xff, 0x3b, 0xdf, 0xf4, 0xf1, + 0x08, 0xfe, 0xc3, 0x02, 0xfa, 0xd2, 0xff, 0xfb, 0xde, 0xfc, 0xda, 0x1e, + 0x07, 0xef, 0xb8, 0xc8, 0x0e, 0x1d, 0x1b, 0xe7, 0x21, 0xe7, 0xcb, 0x01, + 0xcf, 0xc3, 0x0b, 0x0d, 0xdc, 0x1f, 0x0a, 0x07, 0x34, 0xf1, 0x1a, 0x0a, + 0xfb, 0x00, 0xdf, 0xfe, 0xe2, 0x15, 0xf5, 0xef, 0xf2, 0x06, 0x12, 0x13, + 0xe1, 0x16, 0xfd, 0xbb, 0xff, 0x14, 0x35, 0xe3, 0x0b, 0x07, 0xfc, 0x10, + 0xfc, 0xc0, 0xde, 0x02, 0x13, 0xf5, 0xb3, 0x09, 0x16, 0xe0, 0xec, 0x08, + 0xf4, 0x06, 0xe1, 0xff, 0x15, 0x06, 0xea, 0xd3, 0xe4, 0xcd, 0xe2, 0xde, + 0x1b, 0xea, 0xd4, 0x04, 0xd7, 0xe3, 0xe5, 0xc1, 0x33, 0x10, 0x23, 0xf7, + 0xd9, 0xe3, 0x06, 0xee, 0xee, 0xc9, 0x08, 0x06, 0xe0, 0xf3, 0xe5, 0x05, + 0xf1, 0x00, 0x2c, 0xf8, 0x33, 0xe7, 0xd4, 0xee, 0xf6, 0xeb, 0x06, 0x0c, + 0xfe, 0xfb, 0xce, 0x14, 0xed, 0xf5, 0xe5, 0xf7, 0xd2, 0x2c, 0x27, 0xec, + 0x17, 0xd6, 0x0b, 0xff, 0x0c, 0x15, 0xfe, 0x19, 0x00, 0x26, 0x20, 0x2d, + 0xf5, 0xf4, 0xd0, 0xff, 0x1c, 0xd6, 0xe7, 0xf6, 0xf9, 0xd4, 0xf1, 0xe9, + 0x23, 0xff, 0xde, 0x06, 0xf3, 0xec, 0x0a, 0xe5, 0xf7, 0xf7, 0xef, 0x20, + 0xf5, 0xe4, 0xee, 0xff, 0x29, 0x0a, 0x2d, 0xe5, 0xdd, 0xfd, 0x14, 0xde, + 0x07, 0x0b, 0x3b, 0xed, 0xf9, 0x40, 0xe8, 0x0b, 0x42, 0xd4, 0x05, 0xfe, + 0xf6, 0xf4, 0xe8, 0x06, 0xfc, 0x15, 0xe9, 0x15, 0xe0, 0xf1, 0xe5, 0x31, + 0xfe, 0xf1, 0xd7, 0xed, 0xfb, 0x40, 0x35, 0xf3, 0x13, 0xe8, 0xeb, 0x0e, + 0xd0, 0xe6, 0x06, 0x28, 0x01, 0x54, 0xfd, 0xff, 0x39, 0xed, 0x21, 0x02, + 0xfd, 0x0e, 0xc8, 0x19, 0xe3, 0x22, 0xe4, 0xdc, 0x0f, 0x14, 0x0d, 0x30, + 0xdb, 0x20, 0x1e, 0xc3, 0x23, 0x09, 0x12, 0xe1, 0x18, 0x54, 0xf4, 0xff, + 0x29, 0xfa, 0x06, 0xef, 0xce, 0x01, 0xe7, 0x07, 0x1f, 0x14, 0xf1, 0x7f, + 0xe2, 0xfc, 0xd9, 0x10, 0x2e, 0xf9, 0xfa, 0xee, 0x3c, 0x16, 0x0f, 0x1d, + 0xa4, 0xca, 0x0c, 0x03, 0xe7, 0x0f, 0x21, 0x04, 0xe3, 0xfc, 0x14, 0x40, + 0x0a, 0x29, 0x10, 0x00, 0xcd, 0x08, 0x0d, 0xd6, 0x12, 0xba, 0x39, 0xb6, + 0xff, 0xf2, 0xeb, 0x09, 0xfc, 0x24, 0x1c, 0xe7, 0x3f, 0x09, 0x03, 0xd5, + 0x4a, 0x10, 0xfd, 0xe2, 0xee, 0x87, 0x38, 0xf7, 0xe3, 0xc8, 0xf0, 0x37, + 0xee, 0xe5, 0x42, 0xe2, 0x3e, 0xde, 0x34, 0xa2, 0x16, 0x2f, 0x06, 0x0d, + 0x5c, 0x0c, 0x39, 0x19, 0x8a, 0x82, 0x01, 0x0f, 0xd5, 0xd4, 0x02, 0xef, + 0xe9, 0x0d, 0x1c, 0x26, 0x0b, 0x2c, 0xfc, 0x19, 0xe6, 0xf4, 0xf5, 0xed, + 0x1c, 0xc7, 0x36, 0xc0, 0x05, 0xe3, 0xeb, 0x04, 0xe0, 0x3b, 0xf5, 0x13, + 0xfc, 0x17, 0x24, 0x0c, 0xdb, 0x36, 0x58, 0xe2, 0xf6, 0x1e, 0xd8, 0x01, + 0xef, 0xf7, 0xe8, 0x44, 0x24, 0x3c, 0x1f, 0xfa, 0x02, 0x2a, 0xe8, 0x9e, + 0xf6, 0xe3, 0xe0, 0xe2, 0xfc, 0xfd, 0x24, 0x13, 0x03, 0x0d, 0x17, 0x2e, + 0x2c, 0x28, 0x1c, 0xdd, 0xd8, 0x19, 0x99, 0xee, 0x37, 0xa1, 0xc8, 0x20, + 0x0d, 0xf5, 0x19, 0xf3, 0xbe, 0xee, 0xc7, 0x8f, 0xf5, 0xd2, 0xf5, 0xa7, + 0xf4, 0x4e, 0xc6, 0x25, 0x09, 0xea, 0x0a, 0x08, 0xd7, 0x1c, 0x31, 0xde, + 0xe9, 0x0b, 0xd8, 0x0a, 0xe8, 0x0e, 0xe8, 0x2c, 0x17, 0x23, 0x17, 0xde, + 0x28, 0x23, 0xc4, 0xa6, 0x25, 0xf7, 0xe0, 0xcc, 0x63, 0x15, 0x1b, 0x29, + 0xb3, 0xce, 0xe5, 0xb5, 0x9d, 0xba, 0x39, 0xda, 0xcc, 0xde, 0x09, 0xce, + 0xcf, 0x44, 0xfc, 0xed, 0xe2, 0x18, 0x01, 0x2e, 0x16, 0xfa, 0xe1, 0xcc, + 0xf2, 0xc6, 0xae, 0xff, 0xd8, 0x22, 0x05, 0x18, 0x2a, 0x06, 0x0f, 0xa5, + 0x16, 0xfa, 0x0a, 0xfe, 0x98, 0x81, 0x4e, 0xbe, 0xda, 0xfa, 0x14, 0x48, + 0x4d, 0xdb, 0x56, 0x0a, 0x0c, 0xff, 0xd1, 0xc6, 0xf2, 0x2e, 0xed, 0x26, + 0x46, 0x10, 0x34, 0x04, 0xdb, 0xb3, 0xc0, 0xdb, 0xe8, 0xda, 0x26, 0xc3, + 0x84, 0xdc, 0x37, 0x20, 0xf8, 0x43, 0x0a, 0x1c, 0xf6, 0x18, 0x3c, 0x1a, + 0x1f, 0xfd, 0x2e, 0xf3, 0x1f, 0xed, 0xba, 0xec, 0xc0, 0x0c, 0x1c, 0x12, + 0xd4, 0xd0, 0xd8, 0xf1, 0xb5, 0x06, 0x20, 0xe3, 0xda, 0x11, 0xbf, 0xc8, + 0xdc, 0xd5, 0xff, 0xda, 0x1b, 0xdd, 0xf4, 0x0a, 0xdd, 0x12, 0xcd, 0xf3, + 0xfe, 0xfc, 0x00, 0xf4, 0xec, 0x2b, 0xec, 0x26, 0xbb, 0x0a, 0x33, 0xf1, + 0xa7, 0x25, 0x2e, 0xef, 0xec, 0x00, 0xd8, 0xe4, 0xfc, 0xee, 0x14, 0xe9, + 0x33, 0xf1, 0xd2, 0x0a, 0x00, 0x48, 0xed, 0xde, 0xee, 0xd8, 0x18, 0x0c, + 0xa7, 0x0f, 0x18, 0xf5, 0xf1, 0x07, 0x1e, 0xf4, 0xe6, 0x14, 0x4f, 0xf6, + 0x0c, 0x1a, 0xdb, 0xdb, 0x03, 0xbd, 0xec, 0xf1, 0x73, 0xe3, 0x08, 0x6a, + 0xe8, 0x08, 0xda, 0xe1, 0x0e, 0x08, 0x06, 0xf4, 0xb1, 0xf0, 0x16, 0x37, + 0xee, 0xe9, 0x47, 0xf1, 0xe4, 0x66, 0x29, 0xd5, 0xda, 0x0a, 0xba, 0x17, + 0x40, 0xc0, 0x02, 0xc5, 0x2b, 0x05, 0x08, 0xf6, 0xbf, 0x25, 0xdb, 0x1a, + 0xc6, 0xdb, 0xf7, 0xef, 0xd8, 0xf1, 0x0a, 0x47, 0xd4, 0xe9, 0x19, 0x15, + 0x9e, 0x52, 0x12, 0xe7, 0xd7, 0xd9, 0xcb, 0x23, 0x4e, 0xe3, 0xe2, 0xd6, + 0x26, 0xdf, 0x2c, 0x00, 0xc8, 0x59, 0xf0, 0xed, 0xd7, 0x04, 0xf4, 0xf5, + 0xb3, 0xdd, 0x18, 0x36, 0x05, 0x03, 0x30, 0xeb, 0xee, 0x4c, 0x62, 0xea, + 0xd3, 0x0a, 0xbe, 0x19, 0x3c, 0xd0, 0xf3, 0xca, 0x4a, 0xf7, 0x30, 0x36, + 0xe8, 0x44, 0xfd, 0xe6, 0x0c, 0xf1, 0xf7, 0xe1, 0xc8, 0x0b, 0xf2, 0xe4, + 0xb9, 0xd3, 0xbc, 0x13, 0xd7, 0x0a, 0x42, 0xe0, 0xc3, 0x06, 0xf4, 0x05, + 0xd6, 0xc6, 0xff, 0xae, 0x05, 0xe3, 0xe3, 0xf0, 0x12, 0xdc, 0x09, 0xc2, + 0xb1, 0xe0, 0x29, 0xf3, 0x0f, 0x02, 0xeb, 0x0c, 0xc9, 0xe4, 0xf2, 0xfb, + 0xe1, 0x10, 0x43, 0xf0, 0x07, 0xcd, 0x11, 0x41, 0x16, 0xe3, 0xcc, 0xff, + 0x2a, 0x0e, 0xee, 0x0a, 0x1b, 0x10, 0x45, 0xbb, 0x0b, 0xbe, 0xc9, 0xd1, + 0xf1, 0x1b, 0xf1, 0xfa, 0xcd, 0xc3, 0xfe, 0x05, 0xf7, 0xdc, 0x7f, 0xfc, + 0xf9, 0xdf, 0x00, 0x14, 0x03, 0xdd, 0xea, 0xd6, 0x6a, 0xfe, 0xd7, 0x74, + 0x32, 0xf1, 0x09, 0xba, 0x01, 0xe1, 0x0e, 0x0a, 0xe5, 0x05, 0xda, 0x08, + 0x19, 0x2e, 0xf6, 0x1f, 0x25, 0xf8, 0xe1, 0x0f, 0x38, 0x13, 0x11, 0xd4, + 0xd3, 0x10, 0x0e, 0x33, 0xe1, 0x12, 0xf8, 0xed, 0xf0, 0xe6, 0xc2, 0x06, + 0x09, 0x04, 0xfc, 0x06, 0xf3, 0xf7, 0xf3, 0x07, 0x3c, 0x1a, 0xe7, 0x20, + 0xec, 0xd7, 0xe2, 0x17, 0xff, 0x18, 0xf6, 0xed, 0xf5, 0x08, 0x32, 0x1b, + 0xdc, 0x08, 0xf9, 0xf3, 0xcb, 0xff, 0xd4, 0x27, 0xfc, 0x0b, 0x0f, 0x29, + 0xe2, 0xfe, 0xe3, 0xee, 0x20, 0x24, 0x05, 0x0b, 0x1e, 0xfa, 0xe8, 0x1a, + 0x24, 0x07, 0xfc, 0xe8, 0xe3, 0x17, 0xfb, 0x1d, 0xea, 0x1d, 0xfb, 0xf3, + 0xf9, 0xf0, 0xea, 0x17, 0x0d, 0x05, 0xf5, 0x06, 0xdf, 0xd8, 0xde, 0x1a, + 0x01, 0xff, 0xda, 0x00, 0x19, 0xe2, 0xd6, 0x06, 0x48, 0xfd, 0x1b, 0xec, + 0xc7, 0xf3, 0x12, 0x12, 0xee, 0xfd, 0xde, 0xf5, 0xf6, 0xe0, 0xe9, 0x20, + 0x28, 0xf6, 0xf6, 0x16, 0x21, 0xf9, 0xd6, 0xf3, 0x0a, 0xe8, 0xd1, 0x18, + 0x17, 0xe0, 0xc6, 0x06, 0x08, 0x04, 0xf4, 0xef, 0xe0, 0x31, 0x7f, 0xf7, + 0xe5, 0x10, 0xe1, 0xf0, 0x06, 0xe3, 0x0d, 0x1a, 0x19, 0xfa, 0x41, 0x54, + 0xf7, 0xe6, 0xec, 0x15, 0x0e, 0x07, 0xd9, 0x0a, 0x1d, 0xdb, 0xd2, 0x04, + 0x27, 0xf9, 0x15, 0x07, 0xe8, 0x10, 0x1e, 0x0a, 0xed, 0x10, 0xe8, 0x08, + 0x06, 0xdc, 0xf3, 0x12, 0x1f, 0xeb, 0x07, 0x26, 0x03, 0xf0, 0xe3, 0x00, + 0xf2, 0xf7, 0xca, 0x1c, 0x01, 0x01, 0xe7, 0xfc, 0x41, 0x13, 0x09, 0xeb, + 0xda, 0xd6, 0x05, 0x10, 0xc1, 0xee, 0xc9, 0x04, 0xfc, 0xd2, 0xf6, 0xf2, + 0x07, 0xd1, 0xd5, 0xeb, 0xf0, 0x0b, 0xf0, 0xf2, 0x2c, 0x16, 0xef, 0x27, + 0xeb, 0xaa, 0xc9, 0xff, 0x0e, 0x29, 0x03, 0xf8, 0x07, 0xdf, 0x34, 0x1e, + 0xbb, 0xfb, 0xbc, 0xe0, 0xeb, 0xdd, 0xf5, 0xcb, 0xe8, 0xf0, 0x16, 0x34, + 0xee, 0xfe, 0xe9, 0xe5, 0xf9, 0x05, 0x10, 0x18, 0x0a, 0xf6, 0xc4, 0x01, + 0x2e, 0x05, 0xfb, 0xf8, 0xee, 0xeb, 0xf7, 0x1a, 0xbf, 0x1c, 0xbc, 0xf4, + 0xf1, 0xd2, 0xe1, 0xf8, 0x07, 0xd8, 0xea, 0x05, 0xec, 0xd3, 0xca, 0x05, + 0xed, 0xed, 0xa3, 0x3a, 0xf9, 0xc0, 0x06, 0xd9, 0xec, 0x15, 0xe1, 0xe2, + 0xfc, 0xee, 0x23, 0xe5, 0xde, 0xdc, 0xee, 0xf8, 0x1e, 0xf3, 0x1a, 0x17, + 0xe0, 0xd4, 0x2e, 0xfd, 0x25, 0xc3, 0x81, 0x1e, 0xa3, 0x4d, 0x06, 0xd2, + 0x04, 0x05, 0x17, 0xea, 0x12, 0xaa, 0x1d, 0x05, 0xd3, 0x51, 0xf0, 0xe2, + 0x13, 0xeb, 0xc4, 0x08, 0x3a, 0xb9, 0x19, 0x27, 0xf4, 0xbd, 0xe8, 0x0d, + 0xdd, 0xf5, 0xaf, 0x18, 0xd2, 0x0b, 0xd3, 0x1b, 0x13, 0xca, 0xfe, 0xeb, + 0xe6, 0x25, 0xff, 0x07, 0x23, 0xcb, 0x04, 0x1a, 0xe6, 0xf6, 0xbb, 0x10, + 0x09, 0xb6, 0x12, 0xbe, 0x00, 0x36, 0x11, 0x07, 0x19, 0x16, 0xf4, 0xf3, + 0xe3, 0xee, 0x27, 0xe3, 0x2e, 0x2d, 0x0f, 0x4f, 0xd6, 0x01, 0x25, 0x23, + 0x3e, 0xb7, 0x2d, 0x1d, 0xe9, 0x1e, 0xf0, 0xea, 0xff, 0xe5, 0x08, 0x0e, + 0xe2, 0xe4, 0xe8, 0x0a, 0x14, 0x41, 0x2e, 0x4e, 0x30, 0x10, 0xe8, 0x3c, + 0xb8, 0x06, 0x1c, 0x36, 0xda, 0xc2, 0x0b, 0x55, 0x72, 0xed, 0xc4, 0xf6, + 0xf8, 0x2e, 0x01, 0xfd, 0x12, 0xf2, 0x18, 0xf7, 0xf4, 0xe0, 0x90, 0x06, + 0x1a, 0x1b, 0x12, 0xe3, 0xbe, 0xf4, 0x2d, 0xe4, 0x49, 0x20, 0x19, 0x5c, + 0xcd, 0xd3, 0xfa, 0x12, 0x36, 0xe5, 0x0c, 0x1d, 0x0a, 0x02, 0xe2, 0x0a, + 0xf9, 0xd9, 0x0c, 0x0e, 0xdb, 0xf0, 0xed, 0x01, 0xfa, 0xe3, 0xea, 0x08, + 0xf8, 0x0c, 0xcc, 0x41, 0x01, 0xbd, 0xf9, 0xae, 0xd9, 0x17, 0xeb, 0x27, + 0x34, 0xf8, 0x47, 0xf3, 0xd6, 0xcf, 0xf6, 0x10, 0x25, 0xf5, 0x25, 0x1d, + 0xf4, 0x0c, 0x31, 0x04, 0x21, 0xac, 0xcf, 0x14, 0xcf, 0x2f, 0x01, 0xd6, + 0x10, 0xff, 0xf7, 0xce, 0x0e, 0xaa, 0x04, 0xd2, 0xd2, 0x34, 0x0a, 0xdb, + 0x3a, 0xce, 0xde, 0x2b, 0x3f, 0xd0, 0xdf, 0x24, 0xf1, 0x0d, 0x15, 0x10, + 0xdf, 0xe3, 0xf2, 0x09, 0xf8, 0x1e, 0xeb, 0x17, 0x2d, 0xd9, 0x1c, 0xe1, + 0xf1, 0x05, 0xf0, 0xef, 0xf3, 0xe0, 0x1a, 0x16, 0xf2, 0xbd, 0xe6, 0x4d, + 0x0e, 0xca, 0xfd, 0xfb, 0x1e, 0x25, 0x3a, 0xea, 0x34, 0xd4, 0xed, 0x04, + 0xe2, 0x56, 0xfa, 0x07, 0x3a, 0xf8, 0x1b, 0xf7, 0xd6, 0x14, 0x19, 0xe6, + 0xfa, 0x35, 0x44, 0x06, 0xe7, 0xf4, 0x44, 0xd5, 0x24, 0xd9, 0x15, 0xc4, + 0xf3, 0x07, 0xed, 0x18, 0xff, 0xd5, 0xe6, 0x0d, 0x17, 0x09, 0xe3, 0x22, + 0x09, 0xcb, 0xe9, 0xe2, 0xf0, 0xa6, 0xa3, 0x01, 0xf7, 0x04, 0xcf, 0x43, + 0xe7, 0x17, 0x1e, 0xf2, 0x00, 0xcd, 0xfa, 0xda, 0xdd, 0xe3, 0xfb, 0xf0, + 0xf4, 0xef, 0xcb, 0xf3, 0x17, 0x22, 0x06, 0xef, 0x67, 0xeb, 0x0b, 0xf3, + 0xf2, 0x38, 0xeb, 0xef, 0xe9, 0x0d, 0x13, 0x01, 0xe6, 0xe8, 0x1d, 0xdb, + 0x24, 0xfd, 0x15, 0xd0, 0x17, 0x2c, 0xee, 0x18, 0x0c, 0xf5, 0x0f, 0xc5, + 0x04, 0x26, 0xf1, 0x0d, 0x3e, 0x0a, 0xec, 0x09, 0xb3, 0x0d, 0x3a, 0xd3, + 0xc7, 0x63, 0x3b, 0xf9, 0xe5, 0xdc, 0xfa, 0x07, 0x9b, 0xed, 0xc1, 0x2e, + 0x20, 0x03, 0x04, 0x30, 0x00, 0x05, 0xce, 0xd4, 0x18, 0xdf, 0xf4, 0xde, + 0xd6, 0xf3, 0x12, 0xef, 0xcf, 0xd9, 0xcd, 0xe6, 0xe0, 0x02, 0xaf, 0x5d, + 0xf5, 0xb6, 0xf7, 0x04, 0x3b, 0xf2, 0x1e, 0xea, 0xe0, 0xc7, 0xef, 0xee, + 0x21, 0xd8, 0xf3, 0x99, 0x10, 0x2b, 0x1b, 0xce, 0x3c, 0x00, 0xe7, 0x29, + 0xcc, 0xfe, 0x11, 0xda, 0xbd, 0x29, 0x79, 0xdc, 0x06, 0xd5, 0xeb, 0xfc, + 0xe5, 0xe3, 0xbc, 0x0c, 0x2a, 0xff, 0xfe, 0x18, 0x28, 0xf4, 0xd7, 0x02, + 0x0d, 0x20, 0x18, 0x2e, 0x2e, 0xee, 0xcc, 0x0d, 0xe2, 0x1b, 0x1f, 0xb9, + 0xdf, 0x14, 0x17, 0x22, 0xe0, 0xfe, 0x2b, 0xf4, 0xf5, 0x1f, 0xbb, 0x05, + 0x12, 0x04, 0x0b, 0x1a, 0x04, 0xb7, 0xc6, 0x04, 0x0c, 0x04, 0xf4, 0x0c, + 0x03, 0xcb, 0xc1, 0xdd, 0xf0, 0x81, 0xeb, 0xf6, 0x03, 0x38, 0xbb, 0x30, + 0x08, 0x12, 0x09, 0x16, 0xcc, 0xcb, 0xef, 0x09, 0x17, 0xc4, 0xd5, 0xdc, + 0xfe, 0xd3, 0xb2, 0xfd, 0x23, 0x20, 0x17, 0x11, 0x3a, 0xf1, 0x03, 0xe3, + 0xf4, 0x06, 0xfc, 0xf9, 0xf6, 0x0c, 0x21, 0x06, 0xd6, 0xf5, 0x0d, 0xf3, + 0x2f, 0x1d, 0xfd, 0xef, 0xfb, 0x1e, 0x17, 0x0d, 0x08, 0xce, 0x20, 0x1a, + 0x0f, 0x11, 0xf4, 0xe6, 0xf6, 0xf0, 0x1b, 0x24, 0xdb, 0x26, 0xfd, 0x04, + 0x07, 0x07, 0x0c, 0xd3, 0x30, 0x02, 0x22, 0x03, 0x11, 0x37, 0xf7, 0x17, + 0x01, 0x0b, 0xe1, 0xf7, 0xfd, 0xb9, 0x2f, 0x19, 0x29, 0x01, 0x23, 0x09, + 0x13, 0x25, 0x4b, 0x12, 0x96, 0x2e, 0xba, 0x00, 0xeb, 0xe2, 0xdd, 0x1d, + 0x1c, 0x0c, 0x3c, 0xf6, 0xda, 0xe1, 0xfb, 0x29, 0xe4, 0xf7, 0xda, 0xa5, + 0xea, 0xdc, 0x05, 0x1a, 0x42, 0x2d, 0x37, 0xdf, 0x0e, 0xfd, 0x08, 0x36, + 0xb4, 0xf9, 0xe6, 0x17, 0x06, 0xff, 0xf5, 0xfb, 0x35, 0xec, 0x22, 0xe9, + 0xf4, 0x3d, 0xdb, 0x12, 0xfd, 0x17, 0x22, 0xe1, 0x35, 0xd4, 0x3f, 0x99, + 0x0b, 0x1d, 0x07, 0xf6, 0xf9, 0x00, 0x10, 0xf2, 0xc9, 0x22, 0x89, 0xe8, + 0xc4, 0x0d, 0xbc, 0xe6, 0x1e, 0xeb, 0x0c, 0xf8, 0x0f, 0x02, 0x0c, 0xdc, + 0x0b, 0x31, 0xf2, 0xe7, 0xb3, 0xfc, 0x17, 0xcc, 0x1f, 0x1a, 0xf1, 0xce, + 0x35, 0xfb, 0x61, 0xdd, 0xc9, 0x26, 0x21, 0x81, 0xd1, 0xe9, 0xe4, 0x0b, + 0xd9, 0xcf, 0x17, 0xf4, 0xca, 0x08, 0xd6, 0xfc, 0xe2, 0x39, 0x1f, 0xc7, + 0x25, 0xce, 0x16, 0xf3, 0x2f, 0x18, 0x05, 0x01, 0xe6, 0xfd, 0xf6, 0x02, + 0xbb, 0xff, 0xfc, 0xe4, 0xde, 0x02, 0xe9, 0x03, 0x04, 0xf4, 0x30, 0xf5, + 0xee, 0x25, 0x04, 0xe9, 0x06, 0x26, 0xf3, 0xd5, 0x37, 0xef, 0x3c, 0x2a, + 0x15, 0x03, 0xe7, 0xec, 0x04, 0xbb, 0x0a, 0x01, 0xfd, 0x04, 0xfa, 0x13, + 0x15, 0x19, 0xf7, 0xce, 0x33, 0xed, 0x2e, 0x07, 0xfb, 0x3c, 0x14, 0x28, + 0x28, 0x0b, 0x0f, 0x05, 0xd3, 0xc5, 0x1e, 0x18, 0x18, 0x06, 0x2d, 0xbd, + 0x2c, 0x2a, 0x28, 0xdf, 0xf4, 0x4c, 0xba, 0xe4, 0x9c, 0xff, 0x02, 0xdf, + 0x0b, 0xbb, 0x47, 0xcb, 0x12, 0xfd, 0xfb, 0x4c, 0xf9, 0x1b, 0x2f, 0xa6, + 0x17, 0xdb, 0x10, 0x2a, 0x3a, 0xe5, 0x14, 0xf0, 0x0c, 0xec, 0xf2, 0x14, + 0xb8, 0x07, 0xef, 0x10, 0x15, 0x23, 0x0d, 0xcd, 0x3e, 0xda, 0x21, 0xd4, + 0xf8, 0x49, 0xfc, 0x20, 0x45, 0x46, 0x25, 0xe4, 0xc5, 0x17, 0x0c, 0x0f, + 0xf8, 0xea, 0xfa, 0xe3, 0xce, 0x03, 0x0e, 0xf1, 0xe6, 0x13, 0xc7, 0xf7, + 0x04, 0xe3, 0xf2, 0xd7, 0x22, 0xe9, 0xfd, 0x0e, 0xdd, 0x2d, 0xda, 0xf4, + 0x18, 0x0e, 0x17, 0xf7, 0xf7, 0x49, 0x00, 0x0e, 0xbc, 0xfe, 0x09, 0xf4, + 0xb8, 0x3c, 0x41, 0xe2, 0xee, 0x05, 0x99, 0xfd, 0x05, 0xf9, 0xe8, 0xfd, + 0x1e, 0xe9, 0xe9, 0x0a, 0xf9, 0x3d, 0xec, 0xe5, 0x0c, 0xde, 0x12, 0xb4, + 0xd0, 0x1f, 0x1b, 0x05, 0x0a, 0xfa, 0x2f, 0xe3, 0xe6, 0x27, 0x51, 0xfe, + 0xff, 0x0b, 0xe6, 0xdb, 0xf4, 0xd7, 0xee, 0xe5, 0x6c, 0xf7, 0x0f, 0x2c, + 0xea, 0x1f, 0xee, 0xef, 0x18, 0x09, 0x08, 0x03, 0xd3, 0xf9, 0x23, 0x39, + 0xfa, 0xe9, 0x40, 0x02, 0xe9, 0x48, 0x43, 0xd5, 0xc0, 0x07, 0xda, 0x23, + 0x3c, 0xfa, 0x16, 0xe2, 0x2b, 0xf2, 0x31, 0xf4, 0xb8, 0x4b, 0xcf, 0xed, + 0x00, 0xe0, 0xf2, 0xe5, 0xce, 0x04, 0x0a, 0x2f, 0xe3, 0xeb, 0x18, 0x13, + 0xcf, 0x4d, 0x0c, 0xd5, 0xd8, 0xeb, 0xa4, 0x2c, 0x18, 0xd0, 0xe0, 0xed, + 0x29, 0xc4, 0x3f, 0x07, 0xe7, 0x5e, 0xd2, 0xe3, 0xe0, 0xeb, 0x06, 0xd3, + 0xce, 0x1a, 0x0e, 0x3e, 0x03, 0xfc, 0xf1, 0x01, 0x03, 0x43, 0x5e, 0xe5, + 0xe3, 0x03, 0xb3, 0x0c, 0xed, 0xe4, 0x02, 0xf7, 0x62, 0xfb, 0x3e, 0x56, + 0xea, 0x4c, 0xda, 0xe8, 0x16, 0xeb, 0x04, 0xe8, 0xcd, 0x1f, 0xd2, 0xde, + 0xb9, 0xc1, 0xcb, 0x18, 0xbd, 0x02, 0x1a, 0xe7, 0xbd, 0xe7, 0xbc, 0xdc, + 0xd6, 0xd6, 0x00, 0xd8, 0x12, 0xc8, 0xd9, 0x04, 0xb1, 0xe8, 0xe1, 0xca, + 0xc6, 0xe8, 0x18, 0x0c, 0xe2, 0x31, 0x05, 0x04, 0xe8, 0xe9, 0x02, 0xd5, + 0xe0, 0x22, 0x47, 0xed, 0x1a, 0xb8, 0xef, 0x05, 0x01, 0xe6, 0xcc, 0xea, + 0x2a, 0x06, 0x05, 0x1e, 0xd5, 0x32, 0xdb, 0xe4, 0x10, 0xba, 0xdc, 0xdb, + 0x1d, 0x2f, 0xe1, 0xfe, 0xc2, 0xc6, 0xe2, 0xda, 0xd3, 0x08, 0x7b, 0xeb, + 0xe5, 0xe4, 0xc2, 0xe7, 0xc6, 0xdd, 0xd4, 0xf9, 0x7f, 0xe0, 0xeb, 0x60, + 0xf2, 0xee, 0xd8, 0xbb, 0x05, 0xd0, 0xf1, 0xea, 0x30, 0xb1, 0x05, 0xf8, + 0xfb, 0x20, 0x42, 0xe5, 0x20, 0x06, 0x27, 0x0b, 0xa7, 0x2f, 0x13, 0xfa, + 0x0d, 0x2b, 0x04, 0x30, 0xcf, 0x05, 0x2b, 0xe1, 0x2b, 0xf8, 0x03, 0x02, + 0xf6, 0xfc, 0xe9, 0xe8, 0xfb, 0xd3, 0xef, 0xf2, 0x40, 0x12, 0xf1, 0x31, + 0x0b, 0xe4, 0xf8, 0xda, 0xad, 0xf4, 0x8f, 0x07, 0xf4, 0xcb, 0xde, 0x3d, + 0xda, 0x24, 0x39, 0xd0, 0x1a, 0xc6, 0xfe, 0xc8, 0xee, 0xe5, 0x04, 0xd5, + 0x18, 0xc7, 0xdd, 0x04, 0x2f, 0x2c, 0x05, 0xaa, 0x44, 0xed, 0x1b, 0x0c, + 0xd1, 0x01, 0x0b, 0xfd, 0x09, 0x16, 0xd8, 0xf4, 0xf4, 0xeb, 0x1e, 0xe8, + 0x32, 0xf4, 0x20, 0xff, 0x06, 0x16, 0xfb, 0xdb, 0x10, 0xf5, 0x0b, 0xb8, + 0x40, 0xf9, 0xcb, 0x17, 0x07, 0xe9, 0xdf, 0xe6, 0xba, 0x31, 0xea, 0xd0, + 0xc0, 0x60, 0x41, 0xd1, 0xe7, 0xdd, 0xee, 0xf9, 0xa2, 0xe4, 0x88, 0x4b, + 0x19, 0x41, 0x21, 0x26, 0x07, 0x01, 0xe9, 0xae, 0x05, 0xe6, 0x19, 0xe6, + 0x02, 0xdf, 0x08, 0xe4, 0xd3, 0xd0, 0xad, 0xb6, 0xc3, 0x39, 0xba, 0x2a, + 0xed, 0x81, 0x0b, 0xf9, 0x39, 0xec, 0xf4, 0x18, 0xfd, 0x07, 0x07, 0xea, + 0x20, 0xed, 0xff, 0xdd, 0x2e, 0x21, 0xd5, 0xc6, 0x14, 0xf0, 0xeb, 0xea, + 0xb2, 0xec, 0xcf, 0xf2, 0xcb, 0x47, 0xfe, 0xe0, 0xff, 0xcf, 0xf0, 0x02, + 0x12, 0xea, 0xce, 0x39, 0x39, 0x39, 0x13, 0xd4, 0x2d, 0xef, 0xc3, 0x0e, + 0x19, 0x25, 0x50, 0x19, 0x23, 0x29, 0xda, 0x02, 0xe9, 0x3d, 0x30, 0xf3, + 0x01, 0x27, 0x07, 0x2b, 0xea, 0x11, 0x21, 0xbc, 0x2b, 0x1d, 0xec, 0xee, + 0xf9, 0xff, 0xe1, 0x0a, 0xea, 0xa7, 0xd7, 0x20, 0x4f, 0x11, 0x04, 0x3d, + 0x26, 0xd6, 0xd7, 0xd7, 0xf1, 0x97, 0xd2, 0x1e, 0x0e, 0xd6, 0xcf, 0x52, + 0xf2, 0x2c, 0x15, 0xe2, 0x10, 0xe1, 0xf0, 0xe0, 0x0b, 0xe9, 0xdd, 0xd0, + 0x07, 0xcf, 0x97, 0xfc, 0x2e, 0x11, 0x0f, 0xf4, 0x2c, 0x16, 0x11, 0x0c, + 0xf8, 0xcd, 0x01, 0xfd, 0x13, 0x07, 0xe0, 0xfb, 0x27, 0xff, 0x05, 0xf2, + 0x16, 0x13, 0x10, 0xf3, 0xff, 0x0f, 0xe3, 0xe0, 0x35, 0x0a, 0x25, 0x06, + 0x0c, 0xfc, 0xef, 0xf6, 0x00, 0xd1, 0xf5, 0x16, 0xdf, 0xef, 0x0b, 0x24, + 0x0a, 0x23, 0xff, 0xfe, 0xdc, 0x10, 0x37, 0xcf, 0x00, 0x0b, 0x15, 0xf9, + 0x05, 0x07, 0x00, 0x01, 0x11, 0xff, 0x22, 0xf9, 0x3a, 0xda, 0x11, 0xdc, + 0x29, 0x26, 0xf9, 0xfb, 0x04, 0x8e, 0x21, 0xdd, 0xea, 0x3c, 0xea, 0x18, + 0xf0, 0xf5, 0x59, 0xd5, 0xee, 0xc5, 0x0e, 0x28, 0x14, 0x11, 0xe7, 0xfc, + 0x3e, 0x08, 0xf0, 0x16, 0xf5, 0xed, 0xcb, 0x08, 0xf7, 0xa4, 0xd9, 0xf5, + 0xdc, 0xe6, 0x12, 0x29, 0x23, 0x2d, 0x00, 0x14, 0x95, 0xdd, 0x15, 0xed, + 0x16, 0x01, 0x30, 0xcb, 0xf6, 0xf5, 0x0f, 0x0a, 0x4e, 0x28, 0x1a, 0x0f, + 0xf3, 0x2d, 0x23, 0xeb, 0xfa, 0x10, 0x3a, 0x06, 0xe2, 0xef, 0x2b, 0x1b, + 0xfc, 0xcb, 0xd5, 0x1a, 0x22, 0xfb, 0x31, 0xfa, 0xf5, 0x36, 0x43, 0x90, + 0xda, 0xf2, 0xd5, 0xee, 0xf6, 0x06, 0x35, 0x11, 0x03, 0x14, 0xde, 0x2e, + 0x38, 0x1d, 0x67, 0xdd, 0xbc, 0x07, 0x54, 0x19, 0x43, 0xcc, 0xe2, 0x11, + 0xed, 0x15, 0x35, 0xf9, 0xd7, 0x0c, 0x39, 0xb0, 0xe4, 0x03, 0xdc, 0xaf, + 0x79, 0x20, 0x10, 0x25, 0xd9, 0xed, 0x14, 0xfd, 0x1e, 0x17, 0x37, 0x13, + 0xe0, 0xef, 0x21, 0x24, 0x05, 0xec, 0xdf, 0x2d, 0x2d, 0xed, 0x2d, 0xe0, + 0xc9, 0x27, 0x7f, 0xa1, 0x02, 0xdb, 0xdb, 0xee, 0x37, 0xcf, 0x19, 0x1b, + 0x08, 0xd1, 0xd2, 0xc6, 0xf0, 0xa9, 0x01, 0xd2, 0xe9, 0x07, 0x1b, 0x00, + 0xf5, 0x30, 0x0b, 0xb8, 0xde, 0xff, 0x32, 0x0b, 0x0e, 0xe8, 0xf4, 0x01, + 0x1a, 0xe9, 0x18, 0xfd, 0xc6, 0x14, 0xcf, 0xf9, 0x0a, 0xdb, 0xfe, 0xc4, + 0x04, 0xf3, 0xda, 0xec, 0xba, 0xbb, 0x10, 0xe1, 0xa4, 0x3d, 0x08, 0xf1, + 0x18, 0xb8, 0x76, 0x0f, 0xb8, 0xb0, 0xe8, 0x47, 0x12, 0x24, 0x36, 0x08, + 0x60, 0xfe, 0x1c, 0x09, 0x08, 0xd7, 0xda, 0xf0, 0xea, 0xbd, 0xec, 0xf5, + 0xa1, 0x0d, 0xf9, 0x25, 0x15, 0x1d, 0x05, 0xdd, 0xd0, 0xf4, 0x3a, 0xf4, + 0xf0, 0xf9, 0x06, 0x0c, 0x22, 0x06, 0xf5, 0xe8, 0x2d, 0xe3, 0x01, 0xdd, + 0xfe, 0x4e, 0xfd, 0x13, 0xf0, 0xf7, 0xf5, 0x01, 0x01, 0x3c, 0x0d, 0xf2, + 0xfa, 0x0d, 0x0f, 0x07, 0xd9, 0xf2, 0xf8, 0xe2, 0x0f, 0xe1, 0x07, 0x03, + 0xf0, 0x05, 0x0d, 0x19, 0x16, 0x07, 0x08, 0xc6, 0x18, 0x33, 0xf1, 0xfd, + 0x05, 0xfd, 0xeb, 0xd9, 0x11, 0xda, 0xdb, 0xcf, 0xc2, 0x0d, 0xbf, 0x27, + 0xd4, 0xcf, 0x43, 0xed, 0x13, 0xe2, 0x0e, 0x14, 0xf7, 0xea, 0xfd, 0xc7, + 0x05, 0x11, 0xcc, 0xef, 0x0e, 0xfd, 0xfa, 0x17, 0x19, 0xfa, 0xfc, 0x00, + 0xf5, 0x33, 0xf4, 0xfb, 0xf4, 0x10, 0x0e, 0x40, 0xd0, 0xdf, 0x07, 0xd2, + 0x12, 0xc5, 0x03, 0xe2, 0x06, 0x21, 0x17, 0x28, 0x30, 0x2b, 0xdb, 0x23, + 0xf7, 0x0f, 0xe4, 0x14, 0x21, 0xf9, 0xe9, 0x09, 0x05, 0x03, 0x40, 0xf0, + 0xbd, 0x5e, 0x47, 0xfc, 0x00, 0x4a, 0xd6, 0xfd, 0x05, 0xeb, 0xff, 0x24, + 0xec, 0xe7, 0x07, 0x09, 0xf9, 0xe3, 0xf5, 0x2c, 0xf8, 0xe2, 0x0d, 0x0b, + 0xdc, 0x0f, 0x09, 0xc6, 0x18, 0x00, 0x02, 0xfa, 0x03, 0x04, 0x05, 0x1b, + 0xfc, 0x0d, 0x06, 0xf7, 0xc3, 0xf6, 0xf1, 0x06, 0xfa, 0xbc, 0xdf, 0xfe, + 0x43, 0x2a, 0xf1, 0x13, 0xf8, 0x21, 0xf7, 0x1f, 0x29, 0xff, 0x11, 0xfd, + 0x11, 0xf8, 0x47, 0xe2, 0xbc, 0x2e, 0x58, 0xf6, 0x0c, 0x30, 0xfc, 0xec, + 0x16, 0xf4, 0x1b, 0xf8, 0x16, 0xe6, 0xfa, 0x27, 0x07, 0x18, 0x19, 0xdd, + 0x0a, 0x41, 0xf9, 0x1c, 0xdd, 0xc2, 0xe1, 0xd1, 0x02, 0x35, 0x1d, 0xd5, + 0xe5, 0x2d, 0xff, 0x26, 0xd0, 0xec, 0x05, 0x08, 0xeb, 0xc2, 0xf4, 0xf9, + 0xf5, 0xcc, 0xea, 0x25, 0x11, 0x13, 0xff, 0xc2, 0x41, 0x30, 0xda, 0xf3, + 0xfe, 0xd0, 0xd1, 0xb5, 0xf7, 0x81, 0xcb, 0xc6, 0xdd, 0x32, 0xb5, 0x3f, + 0xca, 0xc9, 0x1a, 0x02, 0xf6, 0xea, 0xe1, 0x3c, 0x0d, 0xcb, 0xe1, 0xcb, + 0x03, 0x2b, 0xf4, 0xeb, 0xf7, 0x21, 0xd9, 0x27, 0x09, 0xca, 0xf9, 0xe7, + 0xf5, 0x55, 0x14, 0xf1, 0x0d, 0x15, 0x1c, 0x2a, 0xd1, 0xe1, 0x07, 0xe1, + 0x0e, 0xc7, 0xf9, 0xed, 0xed, 0xef, 0xf6, 0x37, 0xea, 0x02, 0xaf, 0x1c, + 0x3c, 0x18, 0xe1, 0x13, 0x35, 0xe1, 0x07, 0x0b, 0x3b, 0x30, 0x0f, 0xfc, + 0xea, 0xee, 0x04, 0x26, 0xe5, 0x2b, 0xfd, 0xd2, 0x1c, 0xe2, 0x12, 0xd9, + 0xe6, 0x00, 0xfa, 0xf9, 0xf3, 0xe7, 0xab, 0x0c, 0x02, 0x14, 0x15, 0x34, + 0x0a, 0xed, 0xdf, 0x12, 0xf0, 0x10, 0xcc, 0x0e, 0xda, 0xf3, 0x3e, 0x11, + 0xd6, 0x20, 0xcb, 0xf0, 0x2a, 0xed, 0x03, 0xfc, 0xe1, 0x2a, 0x35, 0x3a, + 0xe6, 0xfb, 0xca, 0x01, 0x3b, 0x1e, 0xd3, 0x16, 0x36, 0xe6, 0x12, 0x1c, + 0x30, 0x0e, 0x0b, 0xf8, 0xfe, 0xf7, 0xf4, 0x00, 0xec, 0x20, 0x08, 0xf7, + 0x24, 0xe4, 0x05, 0x07, 0xf4, 0xfa, 0x08, 0x1f, 0xc8, 0xed, 0xe9, 0x41, + 0x05, 0xf4, 0xbc, 0x1b, 0x2a, 0xee, 0xad, 0xd9, 0x4e, 0x22, 0x0d, 0xa0, + 0xb6, 0x47, 0x39, 0xd5, 0xed, 0xf6, 0xaa, 0x03, 0x15, 0xeb, 0x9c, 0x76, + 0x2c, 0xd6, 0x01, 0x0c, 0xea, 0x36, 0xd9, 0x27, 0xfa, 0x9a, 0xce, 0xef, + 0x03, 0xf7, 0xda, 0xf5, 0xdf, 0xeb, 0xde, 0xf5, 0xf3, 0x3c, 0x7e, 0xe2, + 0xf8, 0xfd, 0xca, 0xf5, 0x15, 0xd1, 0x18, 0x1a, 0x16, 0xef, 0x45, 0x7f, + 0xd3, 0xdf, 0x02, 0x0d, 0x02, 0xf1, 0xeb, 0xfb, 0x29, 0xe0, 0xcc, 0xeb, + 0x26, 0xfc, 0xf2, 0x0f, 0xf1, 0x12, 0x27, 0xda, 0xe6, 0x12, 0xa5, 0x13, + 0x46, 0xb2, 0xef, 0x4d, 0xf7, 0xc4, 0xe1, 0x10, 0xb4, 0xdd, 0xea, 0x27, + 0x00, 0x34, 0xf1, 0x2e, 0x0e, 0xeb, 0xac, 0xd3, 0x1e, 0x3a, 0xdc, 0xf9, + 0xed, 0xc4, 0x1b, 0x22, 0xeb, 0x19, 0xdd, 0xcf, 0x5b, 0x60, 0xd8, 0xbb, + 0xe9, 0xe2, 0xfd, 0xfe, 0xdb, 0xe8, 0xca, 0x24, 0xd1, 0xfc, 0xfc, 0x4e, + 0x10, 0xf5, 0xa2, 0xe0, 0x07, 0x7f, 0xa5, 0x3f, 0xe9, 0xb6, 0x46, 0xf0, + 0xe8, 0x10, 0x93, 0xd4, 0x16, 0xfd, 0x1a, 0xa6, 0x0b, 0x05, 0x22, 0x1a, + 0xe3, 0xe5, 0xca, 0x08, 0x2f, 0x35, 0xe4, 0x1c, 0x2c, 0xd8, 0x24, 0xe7, + 0x29, 0x07, 0xf8, 0x0c, 0xf6, 0xc6, 0x01, 0xfa, 0xa4, 0x17, 0xf3, 0xef, + 0x4a, 0x1e, 0x1b, 0xd2, 0xf5, 0xeb, 0x11, 0xea, 0xf4, 0x13, 0x22, 0xf8, + 0x10, 0x22, 0xf3, 0x35, 0x0f, 0xe7, 0xb8, 0x0c, 0x3f, 0x25, 0xf5, 0xc0, + 0xe2, 0xf3, 0x1a, 0x1e, 0xe8, 0x12, 0xf7, 0x02, 0xcd, 0xec, 0x9d, 0x10, + 0x0e, 0xfa, 0x10, 0x1b, 0xda, 0xfb, 0xe8, 0xf1, 0x08, 0x1c, 0xf7, 0x26, + 0xdc, 0xf4, 0xa2, 0x1c, 0x0a, 0x33, 0xf9, 0xad, 0xb0, 0x4c, 0x22, 0xed, + 0xd5, 0x01, 0xf5, 0xeb, 0xa3, 0xdc, 0xa9, 0x5f, 0xea, 0x1c, 0x46, 0x19, + 0x00, 0x0f, 0x0d, 0x04, 0x08, 0x14, 0xef, 0x20, 0x39, 0xde, 0xce, 0x02, + 0x23, 0x19, 0xed, 0xe9, 0xff, 0xf6, 0x0f, 0xf7, 0xff, 0x0b, 0xe3, 0x07, + 0xdf, 0xec, 0xda, 0xf6, 0x4f, 0x25, 0x1c, 0x0f, 0x56, 0xd2, 0xf7, 0x01, + 0xec, 0xfd, 0x03, 0x07, 0x31, 0xdb, 0xc6, 0x29, 0x39, 0x0d, 0x44, 0xed, + 0xf2, 0xd7, 0x1a, 0xff, 0xd4, 0xd3, 0xd9, 0x0d, 0xe2, 0xc6, 0xf5, 0xd3, + 0x40, 0xdf, 0xcd, 0x36, 0xd6, 0x0b, 0x0e, 0xf2, 0xec, 0x06, 0xf4, 0x0c, + 0x16, 0xf5, 0x16, 0x1f, 0xe8, 0x26, 0x3f, 0x02, 0x07, 0xd8, 0x44, 0xf9, + 0xea, 0x33, 0xd3, 0xee, 0xec, 0xc0, 0x00, 0xd9, 0x45, 0x3d, 0x46, 0x45, + 0x71, 0x13, 0x0d, 0xea, 0xc7, 0x24, 0xff, 0xff, 0x1b, 0xdb, 0xc2, 0x2e, + 0x1f, 0x01, 0x4f, 0xfd, 0xf7, 0xe2, 0x0e, 0xfc, 0xd3, 0xf3, 0xe4, 0x15, + 0xd9, 0xd5, 0xf1, 0xbb, 0x30, 0x15, 0xfa, 0x1f, 0xfd, 0xe8, 0xfb, 0xe1, + 0x22, 0x1d, 0xc8, 0x01, 0x39, 0xb9, 0xb3, 0xed, 0x0a, 0x00, 0xf5, 0xe7, + 0xf5, 0xfc, 0x0a, 0x0c, 0xac, 0xf1, 0x11, 0xe0, 0xe2, 0xd1, 0xf7, 0x2a, + 0x49, 0x34, 0x1a, 0x12, 0x04, 0xfb, 0x04, 0xd6, 0x2b, 0xea, 0xd8, 0x15, + 0xe9, 0xc2, 0xb4, 0x1c, 0x18, 0x48, 0xfd, 0xea, 0xe5, 0x32, 0x15, 0xed, + 0xaa, 0xf0, 0x1d, 0xdd, 0xe5, 0x81, 0xe9, 0x31, 0xea, 0x07, 0x2e, 0x1a, + 0x0d, 0x1a, 0xf1, 0xe8, 0x07, 0x06, 0xfa, 0x11, 0x31, 0xce, 0xd4, 0x12, + 0x1a, 0xfd, 0xf4, 0xf3, 0x0b, 0xf8, 0x02, 0x00, 0xc2, 0x08, 0xfa, 0xe5, + 0xec, 0xdf, 0xeb, 0x10, 0x2f, 0x0c, 0x09, 0x04, 0x2c, 0xd4, 0xfd, 0x00, + 0x03, 0xee, 0x29, 0xeb, 0xf1, 0x3a, 0x0b, 0x02, 0xc8, 0xf6, 0xfc, 0xe8, + 0xd9, 0x10, 0x10, 0xf1, 0x0a, 0xf6, 0x2a, 0xf5, 0xe3, 0x3a, 0xcb, 0xec, + 0x14, 0x06, 0xdd, 0xfb, 0xe4, 0xd0, 0x02, 0xfd, 0x24, 0xfc, 0x0d, 0x1e, + 0xeb, 0xf7, 0x36, 0xf7, 0xd2, 0xca, 0x19, 0xd7, 0x2d, 0xec, 0x08, 0x2f, + 0x1b, 0xf3, 0x1f, 0xfc, 0xce, 0x23, 0xda, 0xb7, 0x13, 0x15, 0x0b, 0x00, + 0x15, 0xe3, 0xc8, 0xff, 0xee, 0x05, 0x13, 0xec, 0x12, 0xf4, 0x1d, 0xf7, + 0xc0, 0xda, 0x1c, 0xe8, 0xc1, 0x13, 0x03, 0x13, 0x11, 0x13, 0x29, 0xe4, + 0xf1, 0x24, 0x0a, 0xf2, 0x21, 0xef, 0xea, 0xf1, 0xf5, 0xff, 0x09, 0xb3, + 0x09, 0x0e, 0x10, 0xe6, 0xf9, 0x11, 0x11, 0xd0, 0xe7, 0xf6, 0x36, 0xf9, + 0xf1, 0x0f, 0x0e, 0xb6, 0x23, 0xb0, 0x4c, 0x02, 0x9f, 0x39, 0xd6, 0xf0, + 0x2e, 0x18, 0xfb, 0x1d, 0x3c, 0xf1, 0xf0, 0xbd, 0x17, 0xf7, 0x0e, 0xda, + 0xfa, 0x1f, 0xe2, 0xe0, 0xff, 0xb8, 0xb4, 0x1f, 0x0a, 0xff, 0x9d, 0x47, + 0x28, 0xa3, 0x3f, 0x04, 0x2b, 0x4f, 0x2c, 0xe4, 0x01, 0x0a, 0xff, 0xee, + 0x01, 0xf1, 0x47, 0x00, 0x36, 0x2f, 0x1e, 0xf4, 0x0b, 0x3c, 0x1b, 0xd8, + 0xf9, 0x2a, 0x97, 0x0a, 0x0f, 0x0c, 0xf0, 0xe6, 0x35, 0xc3, 0x24, 0x13, + 0xdc, 0x4e, 0xa4, 0xf6, 0x23, 0x18, 0x18, 0xe8, 0x12, 0xfb, 0xd6, 0xc2, + 0xf1, 0x14, 0x36, 0xce, 0xef, 0x34, 0x1b, 0xdc, 0x99, 0xd9, 0x22, 0xbb, + 0xca, 0x1a, 0x02, 0xff, 0x11, 0xee, 0x1c, 0x10, 0xde, 0xf1, 0xc5, 0xea, + 0x02, 0xe9, 0xbe, 0x02, 0xf7, 0x25, 0x14, 0x02, 0x1e, 0xcd, 0xe3, 0x05, + 0xcc, 0xa7, 0x0b, 0xfa, 0xb1, 0x81, 0xd5, 0xe8, 0x36, 0xe2, 0xaf, 0x23, + 0x50, 0xdc, 0xfe, 0x12, 0xc9, 0x18, 0xbe, 0xd3, 0xfe, 0xe4, 0xbb, 0xcb, + 0x05, 0xea, 0xe6, 0x31, 0x03, 0x19, 0x16, 0xad, 0x26, 0x36, 0x27, 0xf5, + 0xd5, 0xaa, 0xf0, 0xe7, 0xe4, 0xf7, 0xf0, 0xfd, 0x37, 0xde, 0x15, 0x6b, + 0xfc, 0x02, 0xf0, 0xd6, 0x1b, 0xdd, 0xda, 0xf9, 0x23, 0xe7, 0xfa, 0xa9, + 0xe8, 0x04, 0xd4, 0x0f, 0x13, 0xe4, 0x0e, 0xe4, 0x11, 0x4f, 0x01, 0xfc, + 0x1b, 0x27, 0x20, 0x00, 0xca, 0xf0, 0x09, 0xe9, 0x28, 0x89, 0x0f, 0xef, + 0x13, 0xf1, 0x16, 0x12, 0x2d, 0x1e, 0xe2, 0x99, 0xcc, 0x33, 0xe1, 0xd0, + 0xfd, 0xf6, 0xd9, 0xd1, 0x1b, 0xcd, 0xc6, 0xcc, 0xb3, 0x27, 0xb9, 0x01, + 0xcb, 0xdc, 0xfc, 0x19, 0x28, 0x9f, 0xfd, 0x03, 0x13, 0xbf, 0x35, 0xdd, + 0x1c, 0x26, 0x28, 0xcc, 0xd7, 0xdb, 0xe5, 0x0a, 0x2e, 0xd4, 0x06, 0xee, + 0x12, 0x3f, 0xfc, 0xe7, 0xf4, 0xff, 0xfe, 0x2c, 0xd9, 0xe1, 0xf1, 0xf8, + 0x09, 0x81, 0x03, 0xbd, 0x49, 0x13, 0x20, 0x14, 0x30, 0x3a, 0xff, 0x1a, + 0xc2, 0xd6, 0xf0, 0xf4, 0x32, 0x15, 0x4f, 0x31, 0x15, 0xec, 0x1a, 0x14, + 0x27, 0x19, 0x2c, 0xf3, 0x13, 0x34, 0xd8, 0x04, 0x09, 0xd1, 0x13, 0xf8, + 0x29, 0xc8, 0xf2, 0xf4, 0x0c, 0x09, 0x12, 0x5d, 0xef, 0xdc, 0x15, 0x42, + 0xa4, 0x2b, 0x1a, 0xe0, 0xb8, 0x15, 0xc6, 0x2e, 0x3d, 0xc5, 0xdf, 0x03, + 0x2d, 0xf1, 0xfb, 0x06, 0xef, 0xff, 0x12, 0xaf, 0xe5, 0xb4, 0xed, 0xe3, + 0x3d, 0x4e, 0x0e, 0x2c, 0xd7, 0x04, 0x06, 0x0f, 0x39, 0x19, 0x2c, 0x28, + 0x24, 0xe8, 0x07, 0x25, 0x22, 0x1d, 0x16, 0xeb, 0x2f, 0x3c, 0xe7, 0x24, + 0xbb, 0x0d, 0x0b, 0xe0, 0x57, 0xeb, 0xfa, 0xbf, 0x2e, 0x12, 0x14, 0xad, + 0xed, 0x0e, 0xeb, 0x28, 0x0d, 0xc3, 0x08, 0xb9, 0x02, 0x50, 0xeb, 0xd6, + 0xee, 0x17, 0x17, 0x1c, 0xd5, 0xcc, 0xef, 0x15, 0x1d, 0xa3, 0xf2, 0x0b, + 0x21, 0xff, 0x0d, 0xfc, 0x06, 0x2e, 0x07, 0x8d, 0xf0, 0x56, 0xcb, 0xd0, + 0xf9, 0xd2, 0xf6, 0xa4, 0xee, 0x96, 0xcf, 0x99, 0xc1, 0x29, 0xbc, 0x0f, + 0xf6, 0xa0, 0x2c, 0x4a, 0x2a, 0xc6, 0xf0, 0x0d, 0x22, 0xd7, 0xed, 0xa2, + 0x11, 0x37, 0xf0, 0xc3, 0xf9, 0x06, 0xef, 0x02, 0x1b, 0xf7, 0x24, 0xe3, + 0xe1, 0xe6, 0xf7, 0xdf, 0xda, 0x13, 0xeb, 0x2e, 0x11, 0xdc, 0x14, 0x41, + 0x03, 0xc5, 0xf8, 0xf2, 0x29, 0x20, 0x20, 0x10, 0x37, 0x9e, 0x2d, 0xb5, + 0x0b, 0xfb, 0x65, 0xc7, 0xe1, 0x2c, 0xc7, 0x21, 0x9f, 0xeb, 0x21, 0xbb, + 0xcf, 0xf4, 0xcf, 0xe3, 0x0f, 0xf6, 0x26, 0xf4, 0x88, 0xfe, 0xad, 0x35, + 0xf5, 0x07, 0x81, 0xd6, 0xec, 0xe6, 0x5b, 0xa8, 0x25, 0xe6, 0xdc, 0xfd, + 0xdb, 0xa9, 0xd5, 0xb3, 0xa1, 0x05, 0x28, 0xc5, 0x52, 0x17, 0xcf, 0x3a, + 0xd8, 0x15, 0x49, 0xe6, 0x8b, 0xc8, 0x9c, 0xfa, 0x05, 0xf3, 0xd9, 0xbd, + 0x4c, 0xc9, 0x1f, 0xe8, 0xf9, 0x21, 0x50, 0xcf, 0x18, 0x19, 0xf0, 0x24, + 0xa7, 0xd7, 0xdc, 0xc2, 0xbc, 0x4c, 0xbb, 0x10, 0x30, 0xe5, 0x24, 0xe7, + 0xa8, 0xff, 0x88, 0x18, 0x01, 0x18, 0xe4, 0xcb, 0x22, 0xdb, 0x1d, 0xac, + 0x37, 0xff, 0x0a, 0xec, 0xc4, 0xcc, 0xc0, 0xd7, 0xbb, 0x12, 0x06, 0xe7, + 0xe4, 0x1a, 0x10, 0xf2, 0xe2, 0xb1, 0x0f, 0xf3, 0xc2, 0x2b, 0xa8, 0xf1, + 0x2c, 0x65, 0x27, 0x12, 0x3f, 0xab, 0x07, 0xac, 0x16, 0x2d, 0x24, 0x0b, + 0x36, 0xc7, 0xa3, 0xf2, 0xf1, 0x05, 0xdd, 0xec, 0xd0, 0x1a, 0xdc, 0x29, + 0x0a, 0xc9, 0x1a, 0xd6, 0x1b, 0x22, 0x24, 0x0c, 0xf6, 0x41, 0x04, 0xc8, + 0x3d, 0xf3, 0x0e, 0xdc, 0x47, 0x24, 0xe3, 0xe8, 0xf9, 0xbf, 0xdb, 0x15, + 0xe2, 0x04, 0xc8, 0xe0, 0xcd, 0x20, 0x09, 0x24, 0xe9, 0xdd, 0x06, 0xfc, + 0xca, 0x15, 0xaa, 0xf4, 0x40, 0x40, 0x2b, 0x17, 0x27, 0x0d, 0x34, 0xa3, + 0x15, 0x16, 0x5d, 0xd7, 0x02, 0x31, 0xd8, 0x32, 0xf6, 0x02, 0x11, 0xe8, + 0x09, 0x47, 0xe9, 0x20, 0xaf, 0xf9, 0x51, 0xd4, 0xed, 0xf5, 0xd1, 0x05, + 0x17, 0x21, 0xd6, 0xfe, 0x02, 0x15, 0x3a, 0x84, 0x50, 0xec, 0xda, 0x0f, + 0xe5, 0xb8, 0x01, 0x40, 0xf6, 0xa7, 0x28, 0xe3, 0x1c, 0x0e, 0xcc, 0x37, + 0xdd, 0x18, 0x40, 0xf1, 0xba, 0x20, 0xb9, 0xd8, 0x1d, 0xf6, 0xe7, 0xef, + 0x11, 0x06, 0xf4, 0xb5, 0x30, 0xfb, 0x4e, 0xbf, 0x15, 0x24, 0x00, 0x1d, + 0x17, 0xe2, 0xf9, 0x01, 0xd9, 0x2b, 0xd3, 0x31, 0x04, 0xfe, 0x3d, 0xe9, + 0xef, 0x23, 0xf4, 0x2d, 0x23, 0x2b, 0xc2, 0xdb, 0xe6, 0xeb, 0xe3, 0xfe, + 0x04, 0xc8, 0xbb, 0xe3, 0xfc, 0xe5, 0x1f, 0xfa, 0x03, 0xf4, 0xf5, 0xee, + 0xc6, 0xd7, 0x0e, 0xd1, 0x00, 0xf3, 0x13, 0xf8, 0x00, 0x11, 0xda, 0x08, + 0x1b, 0x06, 0x0e, 0xea, 0x02, 0xf7, 0xb7, 0x0d, 0xc8, 0xc0, 0x19, 0xee, + 0xc6, 0xf9, 0x3f, 0x04, 0xf6, 0x04, 0x02, 0xfd, 0x05, 0x1d, 0x02, 0xe0, + 0x2c, 0xff, 0x15, 0x0e, 0xf6, 0xff, 0x05, 0xff, 0xef, 0x28, 0x10, 0x05, + 0xfe, 0xf6, 0xf7, 0xfd, 0xfc, 0xef, 0xfe, 0xf4, 0x0e, 0xed, 0x2a, 0xff, + 0x03, 0xde, 0xf6, 0x1b, 0x0b, 0xf9, 0x03, 0xec, 0x39, 0xf1, 0x06, 0x4d, + 0x05, 0x0d, 0x0b, 0x0a, 0x2f, 0x12, 0x0a, 0xf4, 0x15, 0xfa, 0x12, 0xc7, + 0xe6, 0xff, 0x24, 0xdd, 0xfd, 0x27, 0x06, 0xf4, 0x13, 0x16, 0x0e, 0xe9, + 0x0a, 0xe5, 0xee, 0xc8, 0x07, 0xd7, 0x1c, 0x12, 0xde, 0x1c, 0xed, 0xca, + 0x26, 0xf2, 0xec, 0xf3, 0xe3, 0x24, 0x17, 0xf0, 0x28, 0x0e, 0x0e, 0x1b, + 0xaa, 0x2a, 0x17, 0x07, 0xdd, 0xf6, 0xf9, 0x15, 0x43, 0xde, 0xf5, 0x07, + 0x10, 0xcc, 0x24, 0x17, 0xfc, 0x30, 0xfc, 0xd6, 0xc2, 0x08, 0x1a, 0x23, + 0xec, 0x03, 0x1b, 0xfd, 0xe9, 0xf5, 0x2a, 0xe8, 0x0b, 0x28, 0x17, 0x05, + 0x18, 0x23, 0xe1, 0x06, 0x1c, 0xd6, 0xda, 0x0b, 0x26, 0xc9, 0x29, 0x44, + 0xe4, 0x22, 0xce, 0xdb, 0x15, 0x01, 0xf6, 0xf7, 0xfc, 0xee, 0xf7, 0xfe, + 0xde, 0xce, 0xce, 0xda, 0xf2, 0xee, 0x0f, 0xde, 0x12, 0x03, 0xf9, 0xd1, + 0xdf, 0xe8, 0x27, 0xe2, 0x14, 0xe3, 0xf2, 0x10, 0xf8, 0x07, 0xd6, 0xf2, + 0x13, 0xe1, 0xf8, 0x09, 0xe7, 0x11, 0xdf, 0x22, 0xce, 0xd1, 0xef, 0xce, + 0xb3, 0xe7, 0x0d, 0xe7, 0xda, 0xd4, 0x08, 0xd9, 0xf5, 0x36, 0xfa, 0xf9, + 0x3c, 0xe2, 0x02, 0x1a, 0xd3, 0xf0, 0xda, 0x0d, 0xe1, 0xf4, 0x12, 0x10, + 0xe6, 0x0c, 0xdb, 0x0c, 0xe7, 0xe6, 0xd5, 0xe1, 0xf8, 0xe1, 0x31, 0xe7, + 0xe2, 0xd7, 0xda, 0xeb, 0xd4, 0xcc, 0x07, 0xf2, 0x5a, 0xe0, 0x02, 0x7f, + 0xf6, 0x0a, 0xf1, 0xc6, 0x2c, 0x24, 0x1b, 0xe1, 0xf3, 0x2f, 0xf0, 0x1f, + 0x0a, 0x04, 0x0c, 0xfa, 0xe2, 0x34, 0x0e, 0x07, 0xff, 0xd8, 0x19, 0x0f, + 0xf5, 0xf1, 0x05, 0xfa, 0xe9, 0x05, 0x11, 0xec, 0xfd, 0x1e, 0x14, 0xde, + 0xc3, 0xe7, 0xee, 0x16, 0x0f, 0x20, 0x05, 0x01, 0xfd, 0xdc, 0xff, 0x08, + 0x04, 0x00, 0xf2, 0x18, 0x04, 0xa1, 0x12, 0x10, 0xff, 0x27, 0xe3, 0x0a, + 0x14, 0x02, 0xdf, 0xfe, 0x0f, 0x28, 0x16, 0xce, 0x3b, 0x0d, 0xd2, 0x11, + 0xd5, 0x24, 0xd3, 0x1c, 0x0b, 0x06, 0xf2, 0x01, 0xe2, 0x10, 0xd3, 0xbf, + 0xf4, 0xe2, 0x0d, 0x05, 0xde, 0xd7, 0x00, 0x09, 0xcb, 0xec, 0x04, 0x15, + 0xcb, 0x1e, 0x1e, 0xda, 0x9b, 0xaf, 0xfc, 0x08, 0xd6, 0x1f, 0xee, 0x34, + 0x2b, 0xf5, 0x1e, 0x11, 0x0c, 0x36, 0x02, 0xe1, 0x05, 0x05, 0x18, 0x08, + 0xfc, 0xfb, 0xf8, 0x19, 0x18, 0x27, 0x26, 0xd9, 0xec, 0x25, 0x0a, 0x11, + 0xcf, 0xd3, 0xec, 0xd9, 0x7f, 0xfd, 0x0e, 0x4b, 0x13, 0xdd, 0xfa, 0x1b, + 0xfd, 0x1c, 0xcd, 0xd7, 0x19, 0xfa, 0xc5, 0x19, 0x0b, 0x2f, 0xe9, 0x04, + 0x27, 0xec, 0x1c, 0xe0, 0x34, 0x37, 0x48, 0x4c, 0xed, 0xde, 0xca, 0xd6, + 0xc7, 0x2b, 0xe7, 0x36, 0x31, 0xfc, 0x03, 0x0c, 0x01, 0x07, 0xf9, 0xe6, + 0x10, 0xf8, 0x1f, 0x15, 0x17, 0xdc, 0xf7, 0x18, 0x26, 0x1d, 0x31, 0xdc, + 0xa8, 0x26, 0x2a, 0xfd, 0xb2, 0xc8, 0xf9, 0xe8, 0xf2, 0x2b, 0x04, 0x2d, + 0x1f, 0x27, 0x2a, 0xdc, 0xfb, 0x27, 0xee, 0xe4, 0xf1, 0xe1, 0x1e, 0xdb, + 0xf7, 0x08, 0x0d, 0xf7, 0xe2, 0x00, 0x20, 0xf3, 0xff, 0x37, 0xee, 0xf6, + 0xd2, 0xd7, 0xbb, 0x1e, 0xf7, 0x24, 0x10, 0x28, 0x20, 0xde, 0x05, 0xf5, + 0xd9, 0x19, 0x00, 0x14, 0xc1, 0xab, 0xf9, 0xdc, 0x20, 0x16, 0xf6, 0x1a, + 0x34, 0xdf, 0xf1, 0xf3, 0xe6, 0x34, 0xe8, 0xf5, 0x2e, 0x14, 0xd2, 0x05, + 0xde, 0x24, 0xe7, 0xe7, 0x12, 0x04, 0x0b, 0xfb, 0xf5, 0x0b, 0xc6, 0xd4, + 0xf3, 0xcd, 0x13, 0x04, 0xf2, 0xf8, 0x00, 0x15, 0xd4, 0xe2, 0x0e, 0xe9, + 0xbe, 0x2f, 0x15, 0xff, 0xc1, 0xce, 0xeb, 0x11, 0x27, 0xc5, 0xd8, 0x09, + 0x0a, 0xe3, 0xea, 0xee, 0x07, 0xcc, 0x06, 0x0f, 0xdd, 0xfd, 0x0f, 0xed, + 0xc5, 0x02, 0x2a, 0xce, 0xf6, 0x07, 0x36, 0xe9, 0x05, 0x1c, 0x06, 0xf8, + 0x12, 0x18, 0x23, 0x02, 0xfd, 0xce, 0xb8, 0xfe, 0xd9, 0x9b, 0x05, 0xf1, + 0x02, 0xf7, 0x00, 0x08, 0x10, 0x84, 0x11, 0x01, 0xe3, 0x33, 0xfa, 0x04, + 0x19, 0xfc, 0x36, 0xee, 0xfc, 0xc7, 0x00, 0x0a, 0x12, 0x1d, 0xff, 0xf9, + 0x16, 0xfa, 0xf0, 0x17, 0xfb, 0xf5, 0xea, 0x03, 0x0b, 0xdd, 0x01, 0x03, + 0xd7, 0xcc, 0x12, 0x18, 0x0c, 0x02, 0x19, 0xfa, 0xf9, 0x06, 0x34, 0xd0, + 0x13, 0x35, 0x0b, 0xfd, 0x24, 0x26, 0x16, 0x06, 0x40, 0xf5, 0x23, 0xa9, + 0xf5, 0x05, 0x3b, 0xe1, 0xe6, 0x22, 0x19, 0x0e, 0xd3, 0x13, 0x20, 0xd8, + 0x09, 0xfb, 0xfe, 0x9c, 0x0f, 0xd2, 0x28, 0x13, 0xaf, 0x37, 0xff, 0xdf, + 0x0d, 0x00, 0xe2, 0x05, 0xf9, 0x34, 0x20, 0xe2, 0x2b, 0x25, 0xed, 0x20, + 0xbe, 0x15, 0x23, 0xfb, 0xff, 0xfa, 0x2f, 0x13, 0x34, 0xcb, 0x81, 0x32, + 0xfc, 0xbb, 0x1d, 0x1d, 0x08, 0x30, 0x14, 0xdb, 0xa8, 0xc6, 0xe3, 0xe7, + 0xec, 0x15, 0x39, 0xec, 0xfe, 0xe6, 0x3d, 0xe0, 0x0f, 0x2e, 0x1b, 0x0f, + 0xd3, 0x1d, 0xd3, 0x0b, 0x20, 0xee, 0xd4, 0x1a, 0x22, 0xb7, 0x33, 0x23, + 0xa6, 0x2e, 0xae, 0xf8, 0x11, 0xfd, 0xd3, 0xd8, 0x02, 0xf3, 0xf8, 0xfe, + 0xfb, 0xd5, 0xdb, 0xd4, 0xdb, 0xe2, 0x0d, 0xef, 0xda, 0xf3, 0x03, 0xda, + 0xfd, 0x0b, 0x1c, 0xc4, 0x4b, 0x0e, 0x19, 0x20, 0xe7, 0x1d, 0xcc, 0x13, + 0x08, 0xf7, 0x0f, 0x22, 0x00, 0xe0, 0xd5, 0x24, 0xe1, 0xc8, 0x12, 0xb7, + 0xc5, 0x03, 0x22, 0xd0, 0xf0, 0xab, 0x07, 0xd3, 0xd7, 0x41, 0xef, 0xfa, + 0x3c, 0xbe, 0xf1, 0x26, 0xe3, 0xf6, 0xce, 0x28, 0xf5, 0xd0, 0xe5, 0x05, + 0x0b, 0xe5, 0xdc, 0x16, 0x03, 0xea, 0xec, 0xe3, 0x10, 0xee, 0x18, 0xdf, + 0xad, 0xd2, 0xcd, 0xf5, 0xe7, 0xed, 0x11, 0xeb, 0x49, 0xea, 0x20, 0x3b, + 0xf2, 0x2f, 0xef, 0xdf, 0x2f, 0x3a, 0x19, 0xe4, 0xdc, 0x18, 0x86, 0xf1, + 0x23, 0x35, 0xf8, 0x29, 0x48, 0x0f, 0x16, 0x00, 0x33, 0x16, 0x04, 0xc6, + 0xd7, 0xe6, 0x2c, 0x10, 0xe2, 0xe8, 0xe9, 0xe9, 0x1b, 0xf4, 0xf9, 0xce, + 0x0a, 0x19, 0x08, 0x2b, 0x0a, 0xec, 0xb4, 0xef, 0xfc, 0x16, 0xd1, 0x0d, + 0xe9, 0xd9, 0xd9, 0xd6, 0x07, 0xd6, 0xdf, 0xe5, 0xee, 0xf5, 0xee, 0x1d, + 0xfa, 0xf0, 0xc0, 0x1b, 0xf7, 0x07, 0xeb, 0xd7, 0x15, 0xdd, 0xfa, 0xfb, + 0xd5, 0x16, 0x94, 0xda, 0x19, 0x01, 0x02, 0x24, 0x34, 0x21, 0x21, 0xef, + 0x1c, 0x21, 0xd7, 0xc8, 0xe2, 0xf0, 0x27, 0x27, 0xf6, 0xcb, 0xe6, 0x1a, + 0x22, 0xde, 0xe3, 0xcb, 0x05, 0x0d, 0x01, 0x16, 0x13, 0xb2, 0xf6, 0xee, + 0xe5, 0xea, 0x1a, 0xfa, 0x57, 0x00, 0xb7, 0x26, 0x12, 0xf3, 0x43, 0xcb, + 0xe7, 0x0f, 0x34, 0xe9, 0xd9, 0xc7, 0xfb, 0x03, 0x81, 0xc6, 0xe7, 0x4c, + 0xfe, 0xf1, 0xf6, 0x22, 0x2c, 0x26, 0xf9, 0xeb, 0x09, 0xee, 0xd9, 0x17, + 0xe0, 0xda, 0x00, 0x04, 0xd4, 0xc2, 0x0b, 0x10, 0x05, 0x26, 0x1a, 0x06, + 0xfc, 0xe1, 0xf0, 0x01, 0x1e, 0xd0, 0x25, 0xf6, 0x14, 0x04, 0x2a, 0x51, + 0x21, 0xfa, 0x0d, 0xc9, 0xe3, 0x1f, 0x09, 0xfc, 0x4b, 0xee, 0xb9, 0x23, + 0x08, 0xf0, 0x59, 0xcc, 0xde, 0xd2, 0x52, 0x0e, 0xed, 0xf1, 0x05, 0x48, + 0xad, 0xa6, 0xdd, 0x48, 0x2f, 0xda, 0x08, 0xf4, 0xc3, 0xec, 0xd3, 0xc6, + 0x37, 0x2d, 0x09, 0x0d, 0x48, 0x0a, 0xf3, 0xe6, 0x2d, 0x18, 0xed, 0xba, + 0xca, 0xee, 0x0a, 0x1e, 0xd0, 0xd7, 0x0b, 0x07, 0xd3, 0xf2, 0xbf, 0x18, + 0x0c, 0x25, 0x27, 0xfb, 0x03, 0xda, 0xce, 0xd0, 0xec, 0xff, 0xf9, 0x02, + 0xc3, 0xc5, 0xe8, 0xe5, 0x1c, 0xe4, 0xec, 0xc8, 0x27, 0x2b, 0x0e, 0x00, + 0x0a, 0xf4, 0xca, 0x33, 0xc4, 0xca, 0xc0, 0x36, 0x03, 0xdd, 0x22, 0x01, + 0xc0, 0x01, 0xbd, 0xed, 0x14, 0x20, 0x11, 0x29, 0x3e, 0x17, 0xe3, 0xf4, + 0x1c, 0x29, 0xeb, 0xc6, 0xe0, 0xe8, 0x27, 0x34, 0x1f, 0xc6, 0xde, 0x33, + 0xef, 0xe0, 0xd3, 0xfa, 0x39, 0x18, 0x22, 0x03, 0x2e, 0xeb, 0xcb, 0xd5, + 0x09, 0x11, 0xdd, 0x1b, 0x33, 0xe5, 0x11, 0xe4, 0x06, 0x25, 0xfb, 0xef, + 0xff, 0x1d, 0x26, 0xfd, 0xc4, 0xd7, 0x0d, 0xdf, 0x1c, 0xbe, 0x02, 0x04, + 0x0f, 0x37, 0x13, 0xf9, 0x26, 0xb8, 0x9a, 0xcc, 0xfa, 0x32, 0xe9, 0x07, + 0x04, 0xce, 0xec, 0xc1, 0xdd, 0x81, 0xdb, 0x01, 0xe8, 0x3e, 0xa2, 0x34, + 0xdc, 0xec, 0xef, 0x11, 0x13, 0xb1, 0xf1, 0x22, 0xe6, 0xbd, 0xf1, 0xe9, + 0xfc, 0xc9, 0xb9, 0xca, 0xf6, 0x0e, 0xe4, 0x14, 0x21, 0xdd, 0x1d, 0xe2, + 0xe1, 0x2b, 0xee, 0xe8, 0x0d, 0xff, 0x02, 0x14, 0x0d, 0xda, 0xff, 0x34, + 0x28, 0xb7, 0xff, 0xb2, 0x36, 0x38, 0x0f, 0xef, 0x08, 0xfb, 0xf7, 0xe1, + 0xe4, 0xe9, 0x01, 0xe7, 0x2a, 0xff, 0xe9, 0x36, 0x05, 0x0d, 0x11, 0xd8, + 0xd8, 0x2d, 0x2c, 0x01, 0xf9, 0x0a, 0xc7, 0x12, 0xb6, 0xe9, 0xae, 0x28, + 0x1e, 0x23, 0xf7, 0x12, 0xd8, 0x1f, 0x06, 0x00, 0x11, 0xfa, 0xfa, 0x1c, + 0xd3, 0x07, 0x01, 0x0d, 0xe4, 0xdf, 0xda, 0xf9, 0x08, 0x08, 0xca, 0x1d, + 0x0e, 0xf8, 0x0f, 0x15, 0xe1, 0xeb, 0xc7, 0xd8, 0xde, 0xb3, 0xf2, 0x10, + 0x18, 0xf6, 0x19, 0xca, 0xb6, 0x1c, 0x03, 0xe4, 0x2b, 0xf3, 0xfb, 0x35, + 0xf2, 0x01, 0xf4, 0xed, 0xfa, 0x1d, 0x51, 0x10, 0x31, 0xf9, 0xc8, 0x76, + 0xcf, 0xdb, 0xb9, 0x22, 0x4c, 0x1e, 0xde, 0x14, 0x09, 0xd3, 0xc5, 0xb4, + 0xf2, 0x19, 0xea, 0x2d, 0x20, 0xc6, 0x33, 0xe5, 0xfd, 0x1a, 0x12, 0xc7, + 0xe4, 0xd8, 0x15, 0x23, 0xf9, 0xc9, 0xdc, 0x1a, 0x1c, 0x95, 0xda, 0xd9, + 0x15, 0x23, 0x07, 0xf3, 0xfc, 0xb5, 0xaf, 0xde, 0x05, 0x2f, 0xea, 0xe5, + 0xf9, 0xc2, 0xfa, 0xce, 0x09, 0x9e, 0x01, 0xca, 0xc7, 0xe6, 0xd6, 0x17, + 0x22, 0xf3, 0xe4, 0x33, 0xd2, 0x9c, 0xdd, 0xfd, 0x1f, 0xd4, 0xee, 0xf9, + 0xf2, 0x0a, 0xc2, 0xb6, 0xe0, 0x17, 0x0e, 0x32, 0x1c, 0xfa, 0xfb, 0xe2, + 0xf8, 0x42, 0xd8, 0xe4, 0xe3, 0xe7, 0x12, 0x1b, 0x24, 0xd0, 0xa4, 0x6b, + 0x18, 0x9f, 0xdd, 0xba, 0x42, 0x2a, 0x13, 0x22, 0x0f, 0xf8, 0xc8, 0x07, + 0x29, 0x17, 0xc1, 0x23, 0x27, 0xe1, 0xff, 0x21, 0x0d, 0x01, 0x0e, 0xf8, + 0xdf, 0x13, 0x26, 0x0c, 0xdd, 0x0d, 0x12, 0xf0, 0xf6, 0x01, 0x13, 0x1c, + 0xf9, 0x11, 0xf2, 0x2a, 0xf8, 0xee, 0xd6, 0x3e, 0x04, 0x0d, 0x05, 0x08, + 0xd4, 0xca, 0xfe, 0x0f, 0x24, 0xa9, 0x4b, 0xce, 0xf0, 0x7e, 0x22, 0x19, + 0xf5, 0x1d, 0xf0, 0xf0, 0xfe, 0x08, 0xe9, 0x19, 0xea, 0xec, 0xf3, 0x37, + 0xd9, 0x0f, 0xe8, 0x38, 0x07, 0x27, 0xe0, 0x1c, 0x06, 0xee, 0xf0, 0x11, + 0x16, 0xfb, 0xf3, 0xf2, 0xfc, 0xdc, 0x26, 0x1f, 0xda, 0x10, 0x02, 0xef, + 0xeb, 0x0a, 0xf9, 0xca, 0xd0, 0x16, 0x22, 0x0d, 0x30, 0xdd, 0xfb, 0xf0, + 0x08, 0xf4, 0x25, 0xf9, 0x34, 0xda, 0xca, 0x2b, 0xe6, 0x0e, 0x46, 0xed, + 0xfc, 0xe1, 0xfc, 0x3a, 0xdb, 0xc8, 0x06, 0xf6, 0x8f, 0xc2, 0x07, 0x4a, + 0xd8, 0xda, 0xd7, 0x12, 0x40, 0x0d, 0x20, 0xf4, 0x32, 0x24, 0xd6, 0x14, + 0xfc, 0xeb, 0xfb, 0x11, 0xfc, 0xf3, 0x23, 0x04, 0x1a, 0x3f, 0xe7, 0x1f, + 0xe3, 0x30, 0x0c, 0xf4, 0x5d, 0xfe, 0x47, 0x2b, 0xe6, 0xf7, 0xb8, 0x04, + 0x08, 0x04, 0x21, 0x0a, 0xfc, 0x13, 0x1b, 0xd4, 0x23, 0x12, 0xda, 0x38, + 0xd4, 0xed, 0x6e, 0xec, 0xee, 0xb4, 0x15, 0x3b, 0x0c, 0xcd, 0x08, 0x07, + 0x84, 0xf9, 0x20, 0x34, 0xdc, 0xe4, 0xe2, 0x33, 0xeb, 0xb7, 0xad, 0x04, + 0x37, 0x32, 0x0c, 0xf4, 0x25, 0xe8, 0xa7, 0xe2, 0x0e, 0xf6, 0xfd, 0xec, + 0xf7, 0xe7, 0x1e, 0xf9, 0xbc, 0x04, 0x24, 0xe1, 0xc3, 0x0e, 0xc7, 0x01, + 0xe1, 0x14, 0x14, 0xf8, 0x04, 0xb4, 0xda, 0x2d, 0x09, 0xdc, 0x1b, 0xe2, + 0xd0, 0xb6, 0xd1, 0x17, 0x03, 0x81, 0x4a, 0xe8, 0x19, 0x3b, 0x15, 0xec, + 0x20, 0x0f, 0xe9, 0xef, 0xae, 0xd9, 0xc2, 0x27, 0x2d, 0x16, 0xc6, 0x30, + 0xe9, 0xd1, 0xd4, 0x15, 0x10, 0x22, 0xfb, 0xfe, 0x07, 0xd2, 0xba, 0xcf, + 0x00, 0x0a, 0xfb, 0xda, 0xe6, 0xbf, 0x1a, 0x14, 0x95, 0xe4, 0xe8, 0xd0, + 0xd5, 0x10, 0xe2, 0x01, 0xd1, 0xfc, 0xff, 0xce, 0xf8, 0xfa, 0x17, 0x07, + 0xd8, 0xd1, 0x04, 0xf2, 0xde, 0xff, 0x0d, 0xf6, 0xec, 0xec, 0xef, 0x08, + 0x18, 0xf3, 0x04, 0xe3, 0x01, 0xee, 0xf2, 0xf5, 0xe8, 0xf4, 0x0a, 0x10, + 0x22, 0x05, 0x10, 0xf3, 0xe6, 0x14, 0xfe, 0x01, 0xe4, 0xf3, 0xfd, 0xee, + 0xe6, 0x02, 0x2b, 0xf4, 0xfb, 0x0d, 0x00, 0x1a, 0x0c, 0xf3, 0x07, 0xfe, + 0x10, 0xf7, 0x00, 0x1c, 0xee, 0x0a, 0xf5, 0xe2, 0xf7, 0xfa, 0x10, 0x03, + 0xfd, 0x08, 0xfe, 0xf7, 0x00, 0xef, 0x12, 0xfa, 0x0e, 0x13, 0x3e, 0x00, + 0x03, 0x04, 0xf2, 0x0a, 0x03, 0x0b, 0xf2, 0xef, 0x3a, 0xf0, 0x27, 0x3b, + 0x12, 0x0d, 0x00, 0x15, 0x1e, 0x0c, 0x02, 0xf8, 0xf8, 0x08, 0x0a, 0xfb, + 0xe0, 0xed, 0x20, 0xf6, 0xe2, 0x3c, 0x19, 0xf9, 0xd4, 0xfa, 0xe2, 0x01, + 0x08, 0xef, 0xeb, 0xef, 0x1c, 0xea, 0x15, 0xf6, 0xce, 0x3a, 0xdc, 0xea, + 0x0b, 0x13, 0x07, 0xdc, 0xea, 0x1b, 0x03, 0x09, 0x0c, 0xfd, 0x1b, 0xfb, + 0xe7, 0x34, 0xfc, 0x13, 0xf9, 0xfb, 0xf3, 0x05, 0x21, 0xdd, 0xfa, 0xec, + 0x1d, 0xde, 0x24, 0x0b, 0xf7, 0x40, 0xd1, 0xe7, 0xee, 0x0b, 0x0b, 0x12, + 0xff, 0xe7, 0xff, 0x0e, 0xfe, 0xf6, 0x12, 0xfc, 0xfc, 0x2f, 0x3f, 0xf0, + 0x1d, 0x0b, 0xdc, 0xf1, 0x00, 0xe4, 0xee, 0xf3, 0x42, 0xef, 0x20, 0x31, + 0x03, 0x31, 0xe6, 0xde, 0x1f, 0x08, 0x02, 0xe3, 0xea, 0xe7, 0x0b, 0x0f, + 0xce, 0xce, 0xea, 0xeb, 0xce, 0x0b, 0x1d, 0x02, 0xc3, 0xf1, 0xe2, 0xd3, + 0xef, 0xdf, 0x08, 0xe3, 0x21, 0xd4, 0xde, 0xf1, 0xdd, 0xef, 0xf6, 0xc9, + 0xf5, 0x1d, 0xee, 0xf5, 0xe3, 0x29, 0x0a, 0x19, 0xed, 0xf9, 0xf5, 0xe3, + 0xde, 0x04, 0x2c, 0xf8, 0xd9, 0xde, 0xf1, 0xfa, 0xff, 0xee, 0xf7, 0xf9, + 0x31, 0xea, 0x10, 0x10, 0xed, 0x02, 0xde, 0xdd, 0x01, 0xfe, 0xfd, 0xfa, + 0x08, 0xff, 0xe1, 0xf0, 0xdb, 0xe6, 0xe1, 0xd5, 0xe1, 0xeb, 0x4c, 0xf0, + 0x06, 0xde, 0xf2, 0xe6, 0xdf, 0xe0, 0xf6, 0xf2, 0x74, 0xee, 0xec, 0x7f, + 0x05, 0xf9, 0x05, 0xdc, 0x15, 0xf6, 0xfa, 0xdb, 0xf6, 0x11, 0x1d, 0xd9, + 0x19, 0xff, 0x20, 0x0a, 0xfa, 0x23, 0xc3, 0x25, 0xf4, 0xef, 0xec, 0xb9, + 0xd9, 0xff, 0xfc, 0x00, 0x02, 0xf7, 0x10, 0xf9, 0xa7, 0x01, 0xb4, 0x36, + 0xfc, 0x23, 0xde, 0x2a, 0x09, 0x04, 0x28, 0xd6, 0x39, 0xf0, 0xee, 0x09, + 0xb3, 0xef, 0xcb, 0x17, 0x1e, 0xf3, 0xfb, 0xaa, 0x11, 0x4f, 0xdf, 0x05, + 0xf0, 0xf0, 0xee, 0xf1, 0x81, 0xe5, 0x99, 0x55, 0x09, 0xe1, 0xee, 0xec, + 0xe9, 0x0b, 0x03, 0xe7, 0x15, 0x00, 0x1b, 0x05, 0x0d, 0x06, 0xd2, 0x1a, + 0x05, 0x00, 0xe8, 0xbf, 0xd3, 0x04, 0x0d, 0x07, 0xfa, 0xde, 0x0b, 0xf2, + 0xa8, 0x0b, 0xa2, 0xf6, 0x14, 0x1d, 0x06, 0x01, 0x40, 0xcd, 0xf8, 0xe2, + 0x14, 0x08, 0x17, 0xf5, 0x0d, 0xd7, 0xe1, 0x05, 0xc3, 0xf6, 0x3f, 0xd1, + 0xe5, 0x06, 0x17, 0xfb, 0xd7, 0xcf, 0x08, 0xf4, 0xb4, 0xda, 0xfa, 0xee, + 0xff, 0x18, 0x20, 0x19, 0x19, 0xd8, 0x11, 0xd8, 0xea, 0x21, 0x0f, 0x05, + 0xfe, 0xf3, 0xf3, 0xfb, 0xfd, 0x0f, 0x52, 0x04, 0x02, 0x20, 0xda, 0x13, + 0xf6, 0xee, 0xfd, 0xee, 0x16, 0x01, 0x14, 0x04, 0x17, 0x28, 0x07, 0xe3, + 0x5b, 0x00, 0x19, 0xf3, 0xf0, 0x2e, 0xfd, 0xed, 0x17, 0xe7, 0xd1, 0x14, + 0xe9, 0xf9, 0x56, 0xec, 0xe7, 0x1e, 0x12, 0x17, 0xe8, 0xe1, 0xfd, 0x24, + 0xa8, 0xeb, 0xe5, 0xe6, 0x23, 0x16, 0x1a, 0x0b, 0x2b, 0xf1, 0x09, 0x9f, + 0x44, 0x33, 0x39, 0x01, 0x16, 0x05, 0xba, 0x27, 0xe6, 0x03, 0x00, 0xf4, + 0x07, 0x33, 0xfd, 0x00, 0xb6, 0xe7, 0x37, 0xcc, 0xe8, 0xfd, 0xeb, 0x2e, + 0x1a, 0x2a, 0x09, 0x34, 0x16, 0xee, 0x3a, 0xa3, 0x53, 0xf6, 0xc9, 0xfa, + 0xdf, 0xc8, 0xdd, 0xfd, 0x18, 0xd3, 0x05, 0xd8, 0x0f, 0x44, 0xc9, 0x1d, + 0xbd, 0xe3, 0x3c, 0xda, 0xd0, 0xce, 0xd7, 0x3f, 0xfe, 0xf4, 0xef, 0xe2, + 0x2f, 0x0e, 0xe6, 0xcb, 0x40, 0x21, 0x2c, 0xec, 0x14, 0xe7, 0xe8, 0x3d, + 0xea, 0xdf, 0xf7, 0xe7, 0xe0, 0x20, 0x02, 0x04, 0xe9, 0xe2, 0x33, 0xe1, + 0xe8, 0x0c, 0xda, 0x2f, 0x38, 0x26, 0x04, 0xf5, 0x2f, 0xf1, 0x29, 0xe4, + 0xe1, 0xd8, 0x10, 0xc3, 0xf5, 0x14, 0xff, 0x13, 0x0b, 0x0b, 0xdd, 0x04, + 0x25, 0xe3, 0xcf, 0xd3, 0x15, 0xf9, 0xf3, 0xfe, 0x0a, 0xce, 0xdb, 0x15, + 0x56, 0x16, 0x0b, 0xcf, 0xff, 0x0e, 0x0b, 0xec, 0xe2, 0x0d, 0xf5, 0xfc, + 0x0a, 0xd0, 0xe8, 0xfc, 0xf9, 0x5d, 0xf0, 0x1a, 0xfb, 0xc7, 0x22, 0xe9, + 0xea, 0x0d, 0xf0, 0xf9, 0xd6, 0xc9, 0x00, 0xd4, 0xfa, 0x1d, 0x29, 0x14, + 0x14, 0xeb, 0x0f, 0xe3, 0xec, 0xd3, 0x27, 0xda, 0x24, 0xfc, 0xf4, 0x1f, + 0x0c, 0xea, 0xe7, 0x0f, 0x22, 0xf1, 0xe5, 0xcc, 0x26, 0xff, 0xea, 0x1f, + 0xff, 0xc4, 0xff, 0x22, 0x51, 0x27, 0xfd, 0xdf, 0x24, 0xe1, 0xf3, 0xe3, + 0xe6, 0xdd, 0xe2, 0xe8, 0xcb, 0xec, 0xe4, 0xd4, 0x20, 0x1d, 0xd9, 0xc5, + 0xd9, 0x1e, 0xf0, 0xd5, 0x03, 0xc0, 0xf3, 0x21, 0x09, 0xf7, 0x9e, 0xd5, + 0x45, 0x43, 0x08, 0xe2, 0xdc, 0x03, 0xfe, 0xd8, 0xf3, 0x1a, 0x19, 0x10, + 0xfb, 0xf7, 0xf3, 0x34, 0xf9, 0x1b, 0xf2, 0x08, 0xf6, 0xc9, 0x24, 0xd2, + 0xf6, 0xed, 0xf3, 0xe8, 0xf2, 0x02, 0xed, 0xe0, 0x04, 0x45, 0x33, 0x1e, + 0x31, 0xf2, 0x0e, 0xcf, 0xed, 0x08, 0xfc, 0xd9, 0xf9, 0xe1, 0xfb, 0x14, + 0x16, 0xf8, 0xe3, 0xf2, 0xf6, 0xf7, 0xe3, 0xe3, 0xff, 0xde, 0xdd, 0x51, + 0x14, 0xde, 0x09, 0xd4, 0x35, 0x3e, 0x1e, 0xe4, 0x33, 0xe9, 0x30, 0xd5, + 0xf0, 0xe6, 0x19, 0xee, 0xd2, 0xfa, 0x1e, 0x12, 0xff, 0x20, 0xf3, 0xfa, + 0x10, 0xff, 0xe9, 0xe3, 0x38, 0x1c, 0xe4, 0x12, 0xf5, 0xf5, 0xd5, 0x15, + 0x51, 0x16, 0xe1, 0xcf, 0xe2, 0x17, 0x1a, 0xd7, 0xf5, 0x20, 0xfa, 0x02, + 0xfa, 0xe7, 0x13, 0x06, 0xec, 0x53, 0xef, 0x0b, 0x13, 0xd0, 0x17, 0xff, + 0x0b, 0xf3, 0x3d, 0x11, 0xf2, 0xd7, 0xf8, 0xe9, 0xf6, 0x0e, 0x34, 0x0e, + 0x02, 0xdf, 0x1b, 0xea, 0xf0, 0xeb, 0x2f, 0xe3, 0x14, 0xe2, 0xfe, 0x14, + 0x1d, 0xeb, 0xc7, 0xf6, 0x05, 0xfb, 0x00, 0xd5, 0x6c, 0xf8, 0xd7, 0x7f, + 0x01, 0xe3, 0xf2, 0xf4, 0x64, 0x36, 0x0b, 0xdf, 0xe4, 0xf8, 0xc9, 0x21, + 0x37, 0x04, 0xf1, 0xf3, 0x1a, 0x1d, 0xfc, 0xfe, 0x40, 0xfc, 0xf4, 0x12, + 0x09, 0xff, 0x04, 0x19, 0x03, 0x22, 0xef, 0xf5, 0x2a, 0x37, 0xf3, 0xfb, + 0xe9, 0xdb, 0xf2, 0xe6, 0xc2, 0xf4, 0xd2, 0x08, 0x02, 0xcb, 0xff, 0x2a, + 0xfe, 0x17, 0xf4, 0x13, 0xc5, 0xf2, 0x86, 0x27, 0x03, 0xec, 0x23, 0x16, + 0x04, 0x01, 0xe3, 0xf0, 0x1b, 0x2c, 0x14, 0xf9, 0xfb, 0xfb, 0xfb, 0xf7, + 0xf1, 0x01, 0x96, 0x2a, 0x3a, 0x33, 0xf3, 0xeb, 0x16, 0x01, 0x07, 0xd5, + 0x38, 0xdd, 0xff, 0x06, 0xe8, 0xed, 0xe9, 0x1e, 0xe6, 0x26, 0x0f, 0x05, + 0x19, 0x34, 0x1b, 0xfa, 0xee, 0xd7, 0xd7, 0xd7, 0xc4, 0xef, 0xf6, 0x3f, + 0x39, 0xf6, 0xdf, 0xfe, 0x0c, 0xe4, 0xdc, 0xbb, 0x5e, 0x20, 0x00, 0xba, + 0xbf, 0x10, 0x19, 0xcf, 0x02, 0xc9, 0x01, 0xf4, 0x06, 0x02, 0xe4, 0x4b, + 0x00, 0xe7, 0x00, 0x04, 0xfc, 0x1e, 0xd6, 0xff, 0x00, 0xa9, 0xeb, 0xef, + 0xee, 0xff, 0xe9, 0xbc, 0x06, 0x00, 0xdc, 0xf9, 0xe7, 0x51, 0x7c, 0x03, + 0xea, 0xfb, 0xfe, 0xdf, 0x22, 0x12, 0x1c, 0x3b, 0x08, 0xd9, 0x28, 0x5e, + 0xe0, 0xef, 0xf1, 0xee, 0x1d, 0xeb, 0xfd, 0xf3, 0x36, 0x05, 0xd8, 0xc6, + 0x39, 0xf9, 0xf4, 0xf8, 0xf5, 0x05, 0xfb, 0xc6, 0xf8, 0xc1, 0x0f, 0x07, + 0x2e, 0x03, 0x16, 0x40, 0xf6, 0xd2, 0x16, 0xe6, 0xcf, 0x05, 0xf7, 0x2f, + 0x26, 0x0f, 0x27, 0xee, 0x19, 0x25, 0xb7, 0xde, 0x48, 0x18, 0xef, 0x13, + 0xf6, 0xe1, 0x12, 0xfc, 0xfd, 0x21, 0xf5, 0xe0, 0x3d, 0x5c, 0xe9, 0x02, + 0xee, 0xea, 0xe9, 0x06, 0xd8, 0x11, 0xf1, 0x3e, 0x23, 0xb6, 0x1e, 0x52, + 0xf2, 0x20, 0xcc, 0xfc, 0x00, 0x7f, 0xb0, 0x3d, 0x20, 0xee, 0x2f, 0xf8, + 0x20, 0x1e, 0xdd, 0xcb, 0xe2, 0x3b, 0x00, 0xf6, 0x22, 0x11, 0x1f, 0x2f, + 0xe8, 0x1a, 0xce, 0x08, 0x1d, 0x0f, 0x10, 0xc7, 0x2b, 0xf8, 0x04, 0xc9, + 0x2a, 0xe2, 0x01, 0x16, 0x01, 0xf4, 0xf1, 0x12, 0xbc, 0x00, 0x0c, 0x00, + 0x29, 0x29, 0x16, 0x04, 0xf7, 0xdc, 0xe5, 0x03, 0x27, 0xb0, 0xee, 0x06, + 0xfd, 0xe2, 0x23, 0xef, 0x18, 0x08, 0x21, 0x00, 0xd2, 0x39, 0x01, 0x16, + 0xfb, 0x22, 0x14, 0x01, 0xeb, 0x13, 0x22, 0xf2, 0x48, 0x0a, 0x2a, 0xc9, + 0x00, 0xfc, 0xd2, 0xe9, 0xda, 0xd7, 0xe6, 0x38, 0x54, 0xdd, 0xe7, 0x2f, + 0x21, 0xe3, 0xfa, 0xde, 0xa9, 0x08, 0xa1, 0x12, 0x27, 0xb4, 0x45, 0x5f, + 0xf3, 0x09, 0x2a, 0xdb, 0x33, 0xf5, 0x01, 0xb5, 0xd2, 0xed, 0x14, 0x05, + 0x11, 0xd5, 0xd1, 0xed, 0x1f, 0x29, 0x2b, 0xc0, 0x28, 0xee, 0x35, 0xf2, + 0x07, 0xd7, 0x13, 0x07, 0xef, 0x22, 0xc6, 0x10, 0xd5, 0xfc, 0x17, 0xf6, + 0x23, 0x21, 0x03, 0xf1, 0xfd, 0xfd, 0xdb, 0xd1, 0xcf, 0xfc, 0x02, 0xce, + 0x2b, 0xfe, 0xcd, 0x0e, 0xfe, 0x03, 0xdf, 0xd3, 0x02, 0x2e, 0xf3, 0xd5, + 0xc3, 0x54, 0x4d, 0xf1, 0xef, 0xd7, 0xfe, 0xf4, 0xb3, 0x02, 0x8f, 0x37, + 0x2a, 0x1a, 0x20, 0x01, 0x1a, 0x01, 0xc3, 0xa7, 0x21, 0xdc, 0x01, 0xf5, + 0xf9, 0x09, 0xf3, 0xb0, 0xb5, 0xd6, 0x93, 0xc6, 0xce, 0x22, 0x23, 0x48, + 0x10, 0x92, 0x16, 0xe1, 0x52, 0xff, 0x09, 0x08, 0xec, 0xe5, 0x4f, 0x34, + 0x08, 0xed, 0xdc, 0xdf, 0x43, 0x22, 0xf8, 0xd9, 0x1c, 0xdc, 0xd7, 0xcc, + 0x0d, 0xdf, 0xc1, 0xf2, 0xdd, 0x39, 0x08, 0xea, 0xdf, 0xc3, 0xf5, 0xfb, + 0xfa, 0x0f, 0xbf, 0x11, 0x33, 0x09, 0x1e, 0xdb, 0x2a, 0xe1, 0xac, 0x27, + 0xfc, 0x0c, 0x35, 0x06, 0x20, 0x32, 0x0c, 0x09, 0xdc, 0x29, 0x15, 0x04, + 0xec, 0x0d, 0x2b, 0x06, 0xe1, 0x11, 0x18, 0xdb, 0x50, 0x17, 0x02, 0xe3, + 0x0c, 0xf7, 0xf2, 0x06, 0xfc, 0xf3, 0xd6, 0x33, 0x3d, 0xd0, 0x00, 0x35, + 0x17, 0xc0, 0xd4, 0x0e, 0xd8, 0xb0, 0xc7, 0x1d, 0x25, 0xd6, 0x15, 0x43, + 0xfd, 0x2b, 0x00, 0xe1, 0x1d, 0xfb, 0x00, 0xcb, 0x0c, 0xff, 0x0a, 0x32, + 0xf2, 0xe3, 0x81, 0x07, 0x1c, 0x1e, 0x0e, 0xce, 0x31, 0x1a, 0x2e, 0xf4, + 0x2b, 0x8c, 0x07, 0xf8, 0xef, 0x14, 0xd2, 0x01, 0xe5, 0xf5, 0x1d, 0x0a, + 0x36, 0x17, 0x02, 0xef, 0x12, 0xf8, 0xeb, 0xe1, 0xde, 0xe0, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x00, 0x00, 0x00, 0x40, 0xe0, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x9e, 0xa1, 0x50, 0x3c, 0x50, 0x1c, 0x4c, 0x3c, 0x90, 0x93, 0x56, 0x3c, + 0x35, 0x30, 0x41, 0x3c, 0xa1, 0x39, 0x7f, 0x3c, 0x7a, 0xb4, 0x42, 0x3c, + 0x18, 0x5c, 0x42, 0x3c, 0x76, 0x61, 0x5a, 0x3c, 0x4b, 0xc4, 0x49, 0x3c, + 0x8d, 0x97, 0x2e, 0x3c, 0xb0, 0x47, 0x2c, 0x3c, 0xe6, 0xd2, 0x65, 0x3c, + 0xac, 0xdd, 0x33, 0x3c, 0xb5, 0xd8, 0x3b, 0x3c, 0x74, 0x2d, 0x39, 0x3c, + 0xce, 0x97, 0x6b, 0x3c, 0x44, 0x76, 0x7e, 0x3c, 0x9e, 0x2d, 0x77, 0x3c, + 0xa1, 0x3a, 0x6c, 0x3c, 0x19, 0x59, 0x5e, 0x3c, 0xc3, 0xa0, 0x3b, 0x3c, + 0xe8, 0xa4, 0x6c, 0x3c, 0xff, 0xc0, 0x2f, 0x3c, 0x98, 0xca, 0x75, 0x3c, + 0x0c, 0x4b, 0x3f, 0x3c, 0x14, 0x69, 0x57, 0x3c, 0x15, 0xcb, 0x2b, 0x3c, + 0x1c, 0x64, 0x51, 0x3c, 0x09, 0x35, 0x6d, 0x3c, 0xd0, 0x81, 0x65, 0x3c, + 0x13, 0x9f, 0x5c, 0x3c, 0xc9, 0x18, 0x4d, 0x3c, 0xea, 0x5e, 0x5b, 0x3c, + 0xac, 0x53, 0x11, 0x3c, 0xc3, 0x23, 0x48, 0x3c, 0x4f, 0x62, 0x41, 0x3c, + 0x0a, 0x8b, 0x22, 0x3c, 0xc3, 0xc3, 0x64, 0x3c, 0xe5, 0x35, 0x24, 0x3c, + 0x1a, 0x9d, 0x20, 0x3c, 0x85, 0x2b, 0x77, 0x3c, 0xb7, 0xef, 0x41, 0x3c, + 0x02, 0x12, 0x52, 0x3c, 0xec, 0xe5, 0x41, 0x3c, 0xeb, 0x01, 0x2e, 0x3c, + 0xb8, 0x84, 0x32, 0x3c, 0xb5, 0x5d, 0x3b, 0x3c, 0x91, 0x04, 0x69, 0x3c, + 0x63, 0x74, 0x57, 0x3c, 0x4c, 0xb8, 0x5a, 0x3c, 0x85, 0xdf, 0x26, 0x3c, + 0xa1, 0x5c, 0x37, 0x3c, 0x6d, 0x71, 0x1a, 0x3c, 0xa0, 0xc3, 0x5e, 0x3c, + 0xde, 0xfe, 0x72, 0x3c, 0x86, 0x98, 0x37, 0x3c, 0x19, 0xf1, 0x44, 0x3c, + 0x34, 0x14, 0x2d, 0x3c, 0xfe, 0x59, 0x68, 0x3c, 0xe2, 0xbb, 0x7a, 0x3c, + 0xae, 0xab, 0x5b, 0x3c, 0xc6, 0x63, 0x3f, 0x3c, 0x3a, 0x87, 0x5f, 0x3c, + 0xba, 0x65, 0x25, 0x3c, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xe4, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x10, 0xf6, 0xff, 0xff, + 0xf1, 0xf8, 0xff, 0xff, 0x38, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, + 0xf6, 0x01, 0x00, 0x00, 0xac, 0xe7, 0xff, 0xff, 0x7c, 0x01, 0x00, 0x00, + 0x71, 0xf6, 0xff, 0xff, 0x29, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0xf2, 0x01, 0x00, 0x00, 0x4b, 0xfe, 0xff, 0xff, + 0x55, 0x02, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x8b, 0xff, 0xff, 0xff, 0x19, 0xfb, 0xff, 0xff, 0x22, 0x00, 0x00, 0x00, + 0x7d, 0x5f, 0xff, 0xff, 0xf6, 0x05, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, + 0xbd, 0x00, 0x00, 0x00, 0x8f, 0x0d, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, + 0x28, 0x02, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x98, 0x02, 0x00, 0x00, + 0x1e, 0x05, 0x00, 0x00, 0x3f, 0xfb, 0xff, 0xff, 0x0a, 0xfe, 0xff, 0xff, + 0xb1, 0xfd, 0xff, 0xff, 0xca, 0xe4, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, + 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x7f, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x31, 0x2f, 0x52, + 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x62, 0x61, + 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x31, 0x2f, 0x46, 0x75, 0x73, 0x65, + 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, 0x72, 0x6d, 0x56, 0x33, + 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x62, 0x69, + 0x61, 0x73, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, + 0x64, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x00, + 0x88, 0xe4, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0xdb, 0x41, 0x9f, 0x38, 0xf6, 0x51, 0xd5, 0x38, + 0x08, 0xc1, 0x94, 0x38, 0x91, 0x9e, 0x9a, 0x38, 0xe4, 0x51, 0x82, 0x38, + 0x5f, 0xb3, 0x8b, 0x38, 0x68, 0xf6, 0x99, 0x38, 0xee, 0xff, 0x86, 0x38, + 0x30, 0x75, 0x3f, 0x38, 0xa0, 0x86, 0x46, 0x38, 0xc9, 0x2e, 0x59, 0x38, + 0xb7, 0xa2, 0x88, 0x38, 0xa5, 0x7e, 0x99, 0x38, 0xe0, 0x8b, 0x8b, 0x38, + 0x23, 0x88, 0x8c, 0x38, 0x05, 0x82, 0x7d, 0x38, 0x84, 0xa4, 0x8d, 0x38, + 0xed, 0xff, 0x86, 0x38, 0xa7, 0x18, 0x5c, 0x38, 0x3d, 0x7d, 0xe7, 0x37, + 0xe0, 0x04, 0x68, 0x38, 0x08, 0x0e, 0x9a, 0x38, 0x87, 0x1d, 0x58, 0x38, + 0xb6, 0x3d, 0x54, 0x38, 0xb1, 0x4c, 0x4c, 0x38, 0x8b, 0x42, 0x9d, 0x38, + 0xc6, 0x03, 0x62, 0x38, 0x4d, 0xd9, 0x8d, 0x38, 0xb2, 0x5b, 0x2f, 0x38, + 0x5a, 0x58, 0x78, 0x38, 0xe0, 0x0b, 0x80, 0x38, 0x26, 0xc3, 0x69, 0x38, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xe7, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0xf9, 0xf0, 0x22, 0xca, + 0x13, 0x05, 0x05, 0x14, 0x04, 0xe6, 0x10, 0xf4, 0xe2, 0x0f, 0xfa, 0x81, + 0x24, 0xfb, 0xde, 0x14, 0x03, 0x01, 0xc0, 0xdc, 0x13, 0xef, 0x0f, 0xc2, + 0x1a, 0xcf, 0x1a, 0x22, 0x1b, 0xf4, 0x16, 0x00, 0x08, 0xe3, 0xf8, 0x04, + 0x0a, 0xee, 0x09, 0x02, 0x10, 0xfb, 0x0b, 0x1d, 0xff, 0xac, 0x2d, 0xf3, + 0x10, 0xf1, 0x02, 0x0a, 0x01, 0xb8, 0x0a, 0xf7, 0xd7, 0x0c, 0x00, 0x8f, + 0x16, 0xbd, 0xf6, 0x17, 0x04, 0xe1, 0xda, 0xe4, 0x0b, 0x9f, 0x08, 0xa8, + 0x1e, 0xda, 0x17, 0x11, 0x1b, 0xbe, 0xca, 0x00, 0x0d, 0xbb, 0x02, 0x12, + 0x0c, 0xb0, 0x07, 0x06, 0x0b, 0x06, 0x0f, 0xfb, 0x07, 0xb6, 0x2d, 0xff, + 0x10, 0xe6, 0x06, 0x07, 0x07, 0xa7, 0x0e, 0x11, 0xef, 0x03, 0x09, 0xd5, + 0x01, 0xb7, 0xf8, 0x0d, 0x01, 0xb5, 0xf0, 0xff, 0x0a, 0x96, 0x05, 0xe7, + 0xf4, 0xfb, 0xe8, 0x07, 0x00, 0x9e, 0xb8, 0x02, 0x0d, 0xd7, 0xfa, 0x0b, + 0xe5, 0xc0, 0x02, 0x0a, 0xf1, 0x04, 0xe4, 0xe8, 0x03, 0x02, 0xf3, 0x05, + 0xec, 0x02, 0xc2, 0xc0, 0x07, 0x05, 0xfb, 0xd1, 0x02, 0xd7, 0x03, 0xfd, + 0x05, 0x07, 0xfe, 0x00, 0xbc, 0xfd, 0xb1, 0xa1, 0x02, 0x04, 0xf2, 0x00, + 0x05, 0xc6, 0x03, 0x12, 0x05, 0x06, 0x03, 0xf7, 0xa8, 0xfa, 0x8d, 0x81, + 0x06, 0x01, 0xe5, 0x0d, 0xfe, 0xa8, 0x00, 0x05, 0x04, 0x06, 0xfa, 0x00, + 0xfa, 0x07, 0x0b, 0x09, 0x07, 0x09, 0x00, 0x0f, 0x06, 0x07, 0x08, 0x03, + 0x09, 0x07, 0xf9, 0xf8, 0xe3, 0x06, 0x0a, 0x05, 0x05, 0x06, 0xfa, 0x0f, + 0x06, 0x07, 0x06, 0x0d, 0x0c, 0x03, 0x0c, 0xf5, 0xc5, 0x00, 0x00, 0xfa, + 0xff, 0x00, 0xdc, 0x07, 0x02, 0xf8, 0xfe, 0x0e, 0x02, 0x05, 0x05, 0xed, + 0x08, 0x04, 0x08, 0x04, 0xfb, 0x0b, 0xf5, 0x02, 0x04, 0x04, 0x07, 0xfa, + 0x04, 0x05, 0xfc, 0x03, 0x05, 0x09, 0x03, 0x04, 0x06, 0x05, 0xfd, 0x00, + 0x07, 0x04, 0x06, 0x01, 0xf8, 0xf8, 0xfa, 0xfe, 0x02, 0x01, 0x03, 0x05, + 0xfb, 0x05, 0xe4, 0x07, 0x00, 0x00, 0x05, 0x0a, 0xe9, 0xd8, 0xd3, 0xfd, + 0xec, 0xc8, 0xb1, 0xa2, 0xf5, 0xdf, 0xf8, 0xcc, 0xfd, 0xb3, 0xdf, 0xf9, + 0xb5, 0xce, 0x96, 0xd3, 0x8b, 0xa1, 0xca, 0xe5, 0xd2, 0xac, 0xb2, 0x12, + 0xc4, 0xc1, 0xdc, 0xe1, 0xf0, 0x03, 0xcb, 0x81, 0x8b, 0xee, 0xfd, 0xf4, + 0xed, 0x03, 0x93, 0x0f, 0xed, 0xf9, 0x05, 0xbb, 0x0e, 0x0f, 0xf1, 0x02, + 0xf2, 0xdd, 0xde, 0xde, 0x0b, 0x00, 0xfc, 0x06, 0x0a, 0xe5, 0x14, 0xd8, + 0x16, 0x15, 0xfc, 0x03, 0xde, 0x07, 0x05, 0x09, 0x0d, 0x12, 0xef, 0xfd, + 0x14, 0x10, 0x12, 0x0a, 0xf5, 0x04, 0xd9, 0xd1, 0xea, 0x19, 0x10, 0x12, + 0x00, 0x11, 0xb4, 0x00, 0x01, 0x11, 0x08, 0xed, 0x12, 0x00, 0x06, 0x01, + 0x01, 0x17, 0x04, 0xfd, 0x09, 0x07, 0x03, 0x00, 0x08, 0xf5, 0x0d, 0xfc, + 0x0c, 0x04, 0x1b, 0xfb, 0x0b, 0x0b, 0x0a, 0x09, 0x09, 0x04, 0xfc, 0xfe, + 0x0a, 0x02, 0x0f, 0xec, 0xf9, 0x02, 0x14, 0xf1, 0xf9, 0x14, 0x0f, 0x0c, + 0x0a, 0x10, 0xd7, 0xff, 0x10, 0x0c, 0x19, 0xe4, 0xf7, 0x00, 0xec, 0xca, + 0x14, 0x0f, 0x09, 0x08, 0x05, 0x07, 0xd5, 0xef, 0x0c, 0x07, 0x06, 0xe8, + 0xf8, 0xfc, 0xe2, 0xbd, 0x0a, 0x14, 0x0b, 0x0a, 0x03, 0x0b, 0xe1, 0xe6, + 0x16, 0x0b, 0x15, 0xa3, 0xf9, 0xfa, 0xf3, 0xd6, 0x0c, 0x1c, 0x09, 0x07, + 0xf9, 0x10, 0xe9, 0xf8, 0x0f, 0x07, 0x09, 0xb3, 0xee, 0xf9, 0xa6, 0xca, + 0xe4, 0xfc, 0xde, 0xe8, 0xcb, 0xff, 0xeb, 0xf0, 0x09, 0xc8, 0xe5, 0xc8, + 0xfe, 0xfa, 0xca, 0xdb, 0xf5, 0x0c, 0xfc, 0xfc, 0xc2, 0x06, 0xdf, 0xed, + 0x0b, 0xf5, 0xfb, 0x0c, 0xf1, 0xf5, 0xfe, 0xd2, 0x01, 0x0e, 0x00, 0xfe, + 0xe7, 0x0e, 0xcd, 0xf2, 0x07, 0x00, 0x0a, 0xf8, 0xc2, 0xbe, 0xc3, 0xc3, + 0x0b, 0xe4, 0x08, 0x04, 0x89, 0x9f, 0xd8, 0x0e, 0x97, 0x06, 0xf1, 0xcb, + 0xc1, 0xab, 0xd6, 0xde, 0x0b, 0x07, 0x07, 0x05, 0x9c, 0xbe, 0xb8, 0x05, + 0xc8, 0x02, 0x05, 0xd2, 0xa5, 0x9e, 0x0b, 0xc0, 0x0a, 0xfa, 0x08, 0x03, + 0x81, 0xd7, 0xc4, 0x07, 0xd0, 0x00, 0x02, 0xdb, 0xed, 0xb0, 0xd9, 0x1d, + 0x0a, 0xe4, 0xfb, 0xfb, 0x0e, 0xe1, 0x0e, 0xfb, 0xf8, 0x06, 0x02, 0x06, + 0x81, 0x8d, 0xf9, 0xf4, 0x05, 0x02, 0x08, 0x07, 0xed, 0xe8, 0x01, 0x08, + 0xd7, 0x0f, 0x04, 0x9f, 0xae, 0x9e, 0x13, 0xc2, 0x05, 0xf5, 0x01, 0x02, + 0xf2, 0xbe, 0xf8, 0xff, 0x96, 0x06, 0xf2, 0x93, 0xf7, 0xe7, 0xf5, 0xff, + 0x08, 0x07, 0x07, 0x03, 0x0d, 0xff, 0xff, 0xf7, 0x04, 0x09, 0x07, 0x12, + 0xcf, 0xb8, 0xe2, 0x01, 0x1b, 0x0f, 0x05, 0x05, 0x09, 0x15, 0x0a, 0x06, + 0xea, 0x08, 0x0b, 0xf0, 0xce, 0xbf, 0x07, 0x05, 0x0e, 0xff, 0x08, 0x09, + 0x06, 0xc1, 0x0a, 0x0c, 0x97, 0x0a, 0xf5, 0xf5, 0xf4, 0xe5, 0xf7, 0xff, + 0x0f, 0x06, 0x0c, 0x00, 0x0a, 0x02, 0x07, 0x0a, 0x02, 0x07, 0x0e, 0x07, + 0xe1, 0xa4, 0xfe, 0x0a, 0x15, 0x1d, 0x10, 0x0f, 0x0a, 0x02, 0x08, 0x0f, + 0xed, 0x0f, 0x18, 0xf6, 0xe7, 0xac, 0x17, 0xff, 0x16, 0x0d, 0x0a, 0x12, + 0x0c, 0xd3, 0x08, 0x13, 0xbc, 0x0b, 0x01, 0xf4, 0x81, 0x82, 0xf1, 0xf3, + 0x18, 0xfc, 0x0a, 0x10, 0xe7, 0xd5, 0xf8, 0x10, 0xdb, 0x0f, 0x04, 0xdf, + 0x9e, 0xbc, 0xf7, 0xaf, 0x02, 0x06, 0x0f, 0x0e, 0xd6, 0xd6, 0x9c, 0xf7, + 0xd1, 0x0d, 0x0a, 0x87, 0xe5, 0xf4, 0x06, 0xa3, 0x02, 0x1e, 0x0f, 0x0a, + 0xff, 0x07, 0xb4, 0xeb, 0xea, 0x0c, 0x17, 0xca, 0xe8, 0xec, 0xf4, 0x06, + 0x0c, 0x13, 0x11, 0x0f, 0x04, 0x09, 0x0a, 0x04, 0x0c, 0x12, 0x0c, 0x0f, + 0xe5, 0xf1, 0x0d, 0xc3, 0x07, 0x1f, 0x0d, 0x09, 0x0a, 0x13, 0xcc, 0xf4, + 0x0f, 0x11, 0x13, 0xe0, 0xeb, 0xf3, 0x1a, 0xcf, 0xec, 0x15, 0xfc, 0x04, + 0xfd, 0x0f, 0xc2, 0xf5, 0xfb, 0x02, 0x07, 0x00, 0x0d, 0x03, 0x27, 0x0b, + 0x0b, 0x0c, 0x06, 0x08, 0x15, 0x15, 0xfc, 0x05, 0x12, 0x0b, 0x14, 0x1f, + 0x07, 0x0a, 0x1c, 0xf2, 0x0f, 0x16, 0x0d, 0x07, 0x0c, 0x1c, 0xf5, 0xfb, + 0x15, 0x1a, 0x16, 0x0d, 0xfb, 0xff, 0x18, 0xe8, 0xfc, 0x15, 0x07, 0x08, + 0xf8, 0x09, 0xdc, 0x11, 0x01, 0x0f, 0x17, 0xfe, 0x9d, 0xe2, 0xf4, 0x81, + 0x09, 0x06, 0xfe, 0x05, 0xe4, 0x00, 0xbd, 0x03, 0x03, 0x03, 0x0d, 0x9f, + 0xef, 0xe2, 0x06, 0xa1, 0x0d, 0x21, 0x0c, 0x0c, 0xe9, 0x13, 0xc0, 0x06, + 0x16, 0x0b, 0x1b, 0x11, 0xe5, 0xee, 0x14, 0xd6, 0x09, 0x0f, 0x03, 0x06, + 0xb5, 0xf9, 0xb9, 0xde, 0xf7, 0x0a, 0xe8, 0xec, 0xbf, 0xab, 0x0f, 0x23, + 0x0e, 0x05, 0x0d, 0x06, 0x02, 0xf8, 0x18, 0x07, 0x08, 0x0e, 0x1f, 0xe4, + 0xc7, 0xaa, 0x0c, 0xee, 0x05, 0x05, 0x05, 0x02, 0xdb, 0xff, 0xe9, 0xf1, + 0xfc, 0x05, 0xef, 0xf5, 0xcf, 0x13, 0xf4, 0xd8, 0xce, 0xe4, 0xe9, 0xe4, + 0xd6, 0xc5, 0xb3, 0x00, 0xec, 0xe3, 0xe9, 0xaf, 0xfc, 0xaa, 0x1b, 0x1d, + 0x05, 0xf6, 0xfa, 0xfe, 0x13, 0xf3, 0x1a, 0xd6, 0x11, 0xfa, 0x16, 0xfa, + 0x15, 0xf9, 0xfe, 0x05, 0xde, 0xdb, 0x02, 0x01, 0x02, 0xd6, 0x01, 0x06, + 0xff, 0xff, 0x09, 0xcd, 0x1e, 0x22, 0xf7, 0xf9, 0x1a, 0x09, 0x08, 0x02, + 0x0b, 0xfd, 0xe5, 0x0d, 0x13, 0xff, 0x12, 0xb4, 0x02, 0xfc, 0xf0, 0xff, + 0xff, 0x20, 0x0e, 0x12, 0xfb, 0x17, 0xfb, 0xf7, 0xfe, 0x0c, 0x12, 0xf3, + 0xfc, 0xf7, 0x0a, 0x0a, 0x04, 0x10, 0x07, 0x0c, 0x08, 0x04, 0x02, 0x09, + 0x02, 0x0d, 0x07, 0xfd, 0xf9, 0xe6, 0xf8, 0xff, 0x0b, 0xf6, 0x0e, 0x0a, + 0x04, 0xec, 0x01, 0x14, 0xf7, 0x06, 0x06, 0xf2, 0xdd, 0xf7, 0xbc, 0xbf, + 0xdd, 0x04, 0xe4, 0xe8, 0xc3, 0x0b, 0xd5, 0xb2, 0xf9, 0xef, 0xea, 0xb1, + 0x01, 0xfd, 0x17, 0xfc, 0x19, 0x14, 0x0d, 0x13, 0x0f, 0x0e, 0x04, 0xdc, + 0x04, 0x16, 0x0d, 0xfa, 0x08, 0x05, 0x05, 0x0d, 0x03, 0x0a, 0x0e, 0x0c, + 0x12, 0xff, 0x04, 0x07, 0x08, 0x15, 0x07, 0x0a, 0xf7, 0x0f, 0xf3, 0xc6, + 0xdd, 0x0b, 0xa6, 0x99, 0x01, 0x17, 0xe2, 0x8f, 0x02, 0xb5, 0x02, 0xcc, + 0x0d, 0x15, 0x0c, 0x0b, 0x06, 0x11, 0xe7, 0xe4, 0x07, 0x11, 0x0f, 0x81, + 0x11, 0xe9, 0x0f, 0x29, 0x04, 0x07, 0x0c, 0x0b, 0xd3, 0x02, 0xef, 0xeb, + 0x09, 0x03, 0x02, 0xda, 0x0e, 0xde, 0x08, 0x0f, 0x06, 0xdb, 0xf4, 0x1c, + 0x0c, 0x00, 0xfb, 0xfe, 0x06, 0xe7, 0x19, 0xfb, 0x02, 0xfb, 0x02, 0x23, + 0xe7, 0xa8, 0xf6, 0x28, 0x08, 0xdf, 0xfc, 0xfa, 0x07, 0xb6, 0x14, 0xff, + 0xce, 0x06, 0xfe, 0x03, 0xb1, 0x85, 0x0f, 0x01, 0xfd, 0x00, 0xfc, 0xf6, + 0x01, 0xf0, 0xfd, 0xcc, 0xa9, 0xfc, 0xe5, 0xfa, 0x05, 0xe3, 0xed, 0x18, + 0x08, 0x1b, 0x03, 0x04, 0x0f, 0x06, 0x16, 0xee, 0x01, 0x04, 0x19, 0x0d, + 0xdc, 0xb6, 0x1e, 0xfe, 0x04, 0x10, 0x0b, 0x04, 0xef, 0xe8, 0xfe, 0xf7, + 0xee, 0x09, 0x06, 0x07, 0xc4, 0x90, 0x3f, 0x02, 0xfc, 0xcb, 0xd0, 0xcd, + 0xfe, 0xec, 0x07, 0x81, 0x8d, 0xb8, 0x87, 0x14, 0x04, 0xfb, 0xf0, 0x0e, + 0x0c, 0x14, 0x07, 0x0c, 0x0e, 0x10, 0x0d, 0xf9, 0x13, 0x03, 0x19, 0x10, + 0xbb, 0xd3, 0x14, 0xe7, 0x10, 0x35, 0x14, 0x05, 0xff, 0x1f, 0xba, 0x0f, + 0x02, 0x17, 0x1e, 0xfd, 0xb3, 0x97, 0x5c, 0xc1, 0xee, 0x85, 0xc6, 0xae, + 0xb6, 0x9c, 0xdc, 0xbf, 0x95, 0xb5, 0xa0, 0xca, 0xcb, 0xdd, 0xe2, 0x9d, + 0x17, 0x06, 0x07, 0x02, 0xf0, 0x03, 0xf9, 0x08, 0xfd, 0x09, 0x14, 0xb4, + 0xe2, 0xe1, 0xfc, 0xf2, 0x10, 0x20, 0x0c, 0x06, 0xee, 0x16, 0xe6, 0x08, + 0x14, 0x04, 0x1b, 0x12, 0xd6, 0xe3, 0x01, 0x8c, 0x0a, 0x0e, 0x12, 0x12, + 0xe5, 0x09, 0xd1, 0x17, 0x06, 0x0b, 0xfe, 0xf0, 0xb3, 0xb4, 0xf9, 0x12, + 0x23, 0x1f, 0x1a, 0x1e, 0xf9, 0x02, 0x1c, 0xd3, 0xef, 0x1e, 0x10, 0xe4, + 0xcc, 0xb6, 0x03, 0xe9, 0x0f, 0x03, 0x0e, 0x07, 0xb5, 0x0b, 0xe5, 0xf8, + 0xfe, 0xff, 0xe3, 0xe5, 0x9e, 0xb9, 0xed, 0xb1, 0x12, 0xf5, 0x15, 0x0a, + 0xe2, 0x01, 0xc7, 0x0a, 0xb8, 0x0c, 0xb3, 0xae, 0xe3, 0xc2, 0x05, 0x13, + 0xd7, 0xc5, 0xdf, 0xde, 0xd4, 0xce, 0x00, 0x81, 0x00, 0xd4, 0xd5, 0x0e, + 0x96, 0xf7, 0xc3, 0xc9, 0xca, 0xf8, 0x01, 0xff, 0x90, 0xae, 0x91, 0xc6, + 0xac, 0xf4, 0xdc, 0xc4, 0x0a, 0xb6, 0xed, 0x0a, 0x29, 0xc2, 0xe3, 0xe6, + 0x32, 0xb1, 0x25, 0xf5, 0x93, 0xf5, 0xd9, 0xc9, 0xf8, 0xb8, 0x08, 0x10, + 0x19, 0x04, 0x0c, 0x08, 0x09, 0xdf, 0x13, 0xfe, 0xeb, 0x0e, 0xfa, 0x06, + 0xf4, 0xd0, 0x2d, 0x1c, 0x28, 0xfb, 0x10, 0x0b, 0x0a, 0xf9, 0x0f, 0x1a, + 0xe4, 0x1b, 0xec, 0x02, 0xc4, 0xed, 0x2a, 0x17, 0x11, 0xf2, 0x0b, 0x06, + 0x07, 0xee, 0x05, 0x01, 0xc9, 0x0c, 0xeb, 0x21, 0x07, 0xf6, 0xf8, 0x0b, + 0xf9, 0xf4, 0xff, 0xfc, 0xfb, 0xda, 0x06, 0xf9, 0xfb, 0xed, 0xed, 0x03, + 0x1d, 0xd7, 0xc9, 0x12, 0x1f, 0x03, 0x05, 0xf0, 0x34, 0xc9, 0x0c, 0xf0, + 0xe3, 0x03, 0xe2, 0x0f, 0x03, 0xfa, 0x17, 0x07, 0x0a, 0xd7, 0xfb, 0xf0, + 0x16, 0xc9, 0x0a, 0x01, 0xc8, 0x01, 0xae, 0x38, 0xbe, 0x10, 0xe8, 0xcf, + 0x90, 0xb4, 0xd6, 0xdc, 0x8f, 0xec, 0xa6, 0xf6, 0xc8, 0xec, 0x8c, 0xfd, + 0xa3, 0xdb, 0xd0, 0x9e, 0xa6, 0xb5, 0xb4, 0xc6, 0x8d, 0xe6, 0xbf, 0xf5, + 0xb2, 0xb4, 0x95, 0xcd, 0x99, 0x2e, 0xd0, 0xcb, 0xa5, 0x81, 0xcd, 0xbb, + 0x94, 0xc9, 0xde, 0x0b, 0x95, 0xaf, 0x88, 0x2e, 0xeb, 0xf4, 0xf8, 0xc3, + 0xf5, 0x15, 0x07, 0x05, 0x01, 0x0c, 0xe2, 0xdb, 0x0b, 0x04, 0x17, 0xc1, + 0xfd, 0xf6, 0x1e, 0xed, 0xf9, 0x12, 0x05, 0x07, 0x08, 0x12, 0xf8, 0x81, + 0x10, 0x09, 0x15, 0x15, 0x03, 0xf5, 0x22, 0x08, 0xd1, 0xeb, 0xc3, 0xb8, + 0x11, 0xf5, 0xef, 0xc0, 0x06, 0xdb, 0xff, 0x09, 0x05, 0xfb, 0x0b, 0x0b, + 0x00, 0x1a, 0x0a, 0x05, 0x15, 0x18, 0x0b, 0xa4, 0x17, 0x0e, 0x2a, 0xe3, + 0x09, 0x0b, 0x20, 0x02, 0xfa, 0x09, 0xee, 0xf7, 0x10, 0x07, 0x00, 0x82, + 0x11, 0xfa, 0x13, 0xe2, 0x1a, 0x13, 0xfd, 0x08, 0xed, 0x08, 0xa1, 0xa5, + 0x18, 0x0c, 0x01, 0xc3, 0x08, 0xd4, 0x09, 0xf1, 0xc2, 0xca, 0x16, 0x00, + 0xf5, 0x04, 0xf4, 0x00, 0xb9, 0x04, 0x09, 0x90, 0xf9, 0x00, 0xee, 0xdd, + 0xeb, 0xfa, 0xf9, 0xe5, 0xdf, 0xfc, 0xf8, 0xf1, 0xce, 0x0c, 0xd8, 0x8c, + 0xfd, 0xf3, 0xfd, 0xdf, 0x00, 0x05, 0xf9, 0xf9, 0xe4, 0x10, 0xa8, 0xa3, + 0xbb, 0x0c, 0xfd, 0xbe, 0xff, 0xa6, 0xdf, 0xe8, 0x0e, 0x0c, 0x0f, 0x0d, + 0xfc, 0x22, 0xfa, 0xde, 0x07, 0x11, 0x09, 0x1c, 0x18, 0xe9, 0x0c, 0x1a, + 0x0e, 0xff, 0x05, 0x03, 0xec, 0x10, 0xd6, 0xba, 0x08, 0x06, 0x0b, 0x0c, + 0x0c, 0xd4, 0x03, 0x15, 0x08, 0x0e, 0x2e, 0xf3, 0x88, 0x05, 0xc9, 0xbb, + 0x07, 0x04, 0xdb, 0xf8, 0x0e, 0xe4, 0x01, 0xf8, 0x19, 0x0a, 0x10, 0x01, + 0xf5, 0x06, 0xc7, 0xaf, 0x03, 0x07, 0xfb, 0x22, 0x0a, 0xbb, 0x0e, 0x0e, + 0x0d, 0x08, 0xf8, 0xfd, 0xc6, 0x08, 0x9d, 0xa5, 0x07, 0xfd, 0xf4, 0x16, + 0x00, 0xa4, 0x06, 0x09, 0xf6, 0x00, 0xfd, 0xec, 0x9a, 0x00, 0xda, 0xcf, + 0xf0, 0xf9, 0xdc, 0xdc, 0x03, 0xce, 0x0e, 0xf9, 0x11, 0x0d, 0x17, 0x07, + 0x07, 0x05, 0xdc, 0xd0, 0x15, 0x06, 0xfe, 0x1d, 0x05, 0xd8, 0x0c, 0x09, + 0x04, 0xf3, 0xe3, 0xff, 0xb6, 0xe5, 0xba, 0xad, 0xb9, 0xf3, 0xea, 0xff, + 0xf4, 0x9e, 0xcb, 0x1b, 0xe4, 0xf7, 0xd5, 0xd4, 0xe8, 0x09, 0xbe, 0xbf, + 0xf5, 0x00, 0xf5, 0x81, 0x01, 0xbc, 0xd1, 0xd0, 0x8c, 0xa4, 0xe6, 0x98, + 0xf8, 0xfe, 0x0b, 0x04, 0xc3, 0xe4, 0x81, 0xec, 0xd2, 0x05, 0x08, 0xa6, + 0xdf, 0xe5, 0xee, 0xbe, 0xe2, 0x0e, 0x05, 0x0a, 0xfd, 0xf9, 0xec, 0x01, + 0xfa, 0x07, 0x03, 0xa2, 0xf8, 0xed, 0x0f, 0xf0, 0xfe, 0x0f, 0x07, 0x0b, + 0xfd, 0xfa, 0x00, 0xfc, 0x04, 0x04, 0x03, 0x02, 0xa9, 0xd0, 0x02, 0xa0, + 0xf9, 0x0f, 0xfd, 0xfb, 0xa3, 0xf7, 0xaa, 0xcc, 0xbf, 0xfe, 0xfd, 0xc1, + 0xd9, 0xde, 0xf1, 0xce, 0xed, 0x16, 0x05, 0x05, 0xe1, 0x00, 0xfe, 0xe3, + 0x02, 0x08, 0x06, 0xd2, 0xfa, 0xf6, 0x27, 0xfa, 0xfd, 0x09, 0x0d, 0x10, + 0x05, 0xfc, 0xff, 0x04, 0x09, 0x0c, 0x12, 0x08, 0xc5, 0xd6, 0x1e, 0xb1, + 0xd5, 0xce, 0xe5, 0xe1, 0xbf, 0xe9, 0xa0, 0xe9, 0xc8, 0xcb, 0xc4, 0xef, + 0xf0, 0xfd, 0xe5, 0xc1, 0xc7, 0x12, 0xee, 0xf9, 0xd1, 0xfa, 0xe5, 0xcb, + 0x0a, 0xea, 0x0d, 0xe2, 0x19, 0x0f, 0x31, 0x06, 0xf9, 0x1c, 0x07, 0x02, + 0x11, 0x10, 0xf9, 0xee, 0x1b, 0x06, 0x27, 0x14, 0x00, 0x06, 0x0a, 0xec, + 0xff, 0x0a, 0xf8, 0xde, 0xf9, 0x03, 0xf6, 0xe3, 0x06, 0xf6, 0x02, 0xd3, + 0x24, 0x14, 0x15, 0x0e, 0x0d, 0x08, 0xd3, 0xd6, 0x03, 0x09, 0x02, 0x09, + 0x0f, 0xe6, 0x12, 0x15, 0x14, 0x09, 0xef, 0x14, 0x1b, 0x05, 0xef, 0xf1, + 0x15, 0x00, 0x12, 0xf6, 0x0b, 0xf7, 0x07, 0x06, 0xfe, 0x0a, 0xd6, 0xec, + 0x02, 0x10, 0xec, 0xe4, 0xfb, 0x0b, 0xef, 0xe0, 0xfa, 0xe6, 0xee, 0xea, + 0x13, 0x04, 0xda, 0x09, 0x19, 0x03, 0xd0, 0xd0, 0x02, 0x01, 0x12, 0xf4, + 0x0a, 0xc9, 0xfc, 0xf5, 0x14, 0xd1, 0xcd, 0x1b, 0x26, 0xde, 0xe0, 0xf0, + 0x0e, 0xd2, 0x18, 0xf1, 0xf3, 0xde, 0xfa, 0x00, 0x86, 0xb4, 0xe1, 0xba, + 0xce, 0x9d, 0xfd, 0xfa, 0x81, 0xc0, 0xb4, 0xff, 0x96, 0xfd, 0x81, 0xcb, + 0xbd, 0xb3, 0xaf, 0xee, 0xef, 0xcb, 0xff, 0xfd, 0xc0, 0x9e, 0xff, 0x08, + 0xb3, 0xfe, 0xc0, 0xc2, 0x00, 0xc7, 0xc9, 0x05, 0x08, 0xf1, 0x06, 0x07, + 0x0c, 0xd2, 0x0a, 0x06, 0xfe, 0x09, 0x01, 0xd5, 0x10, 0xe4, 0xeb, 0x04, + 0x02, 0xd3, 0xfa, 0xec, 0x04, 0xb3, 0x0b, 0x0b, 0xf9, 0xf0, 0x0d, 0x02, + 0x05, 0xb8, 0xbd, 0x08, 0xfb, 0x81, 0xa5, 0xb3, 0x0b, 0x81, 0x07, 0xe1, + 0x01, 0xc7, 0x0a, 0xfe, 0xf4, 0xb4, 0xf7, 0x04, 0x09, 0xbf, 0xc7, 0xc9, + 0x04, 0xb0, 0x04, 0xcd, 0xec, 0xe8, 0xf2, 0x00, 0x09, 0x02, 0x06, 0x0f, + 0x0a, 0xef, 0x0d, 0x09, 0x0a, 0xda, 0x07, 0x08, 0x08, 0x04, 0x0b, 0xff, + 0x13, 0x0d, 0xed, 0x02, 0x0d, 0xf4, 0xc9, 0xcd, 0x13, 0x01, 0x0a, 0xc3, + 0x0e, 0xed, 0x10, 0x01, 0x09, 0x04, 0xf9, 0x04, 0x07, 0xe3, 0xcb, 0xd7, + 0x0c, 0xec, 0x06, 0xd4, 0xf8, 0xee, 0xfd, 0x18, 0x0b, 0x0f, 0xfa, 0x08, + 0x0f, 0x10, 0xfc, 0xff, 0x0f, 0xfb, 0x0b, 0xeb, 0x06, 0xff, 0x10, 0xfc, + 0x17, 0x08, 0x08, 0x12, 0x21, 0xfd, 0xd5, 0xd5, 0x14, 0x0c, 0x0f, 0xe3, + 0x10, 0xe6, 0x0d, 0x07, 0x00, 0x09, 0xe8, 0x06, 0xf9, 0x03, 0xd8, 0xeb, + 0x02, 0x00, 0x01, 0xef, 0xfe, 0xdd, 0xff, 0x04, 0x16, 0xbf, 0xc0, 0x0a, + 0x02, 0x9f, 0xcf, 0xb2, 0x06, 0x97, 0x09, 0x08, 0x0a, 0xaa, 0xf7, 0x0a, + 0xd5, 0xb6, 0x96, 0x0a, 0xcf, 0xab, 0x02, 0xfe, 0xe7, 0x94, 0xec, 0x24, + 0xc9, 0x11, 0xe2, 0x14, 0xae, 0xab, 0xd9, 0xaa, 0xf3, 0xf1, 0x01, 0x08, + 0xcc, 0xcc, 0xe3, 0xf5, 0xd5, 0x03, 0xea, 0xbf, 0x05, 0xeb, 0xe4, 0x03, + 0x00, 0xc3, 0xfc, 0xfb, 0x12, 0xda, 0xff, 0xc9, 0x11, 0xfd, 0x19, 0xcf, + 0x19, 0xfc, 0x97, 0x0c, 0x1a, 0xeb, 0xf9, 0xff, 0x1b, 0xef, 0x13, 0xf4, + 0x22, 0x03, 0x1c, 0xba, 0x09, 0xfd, 0xba, 0x08, 0xfa, 0xf7, 0x08, 0x05, + 0x10, 0xfc, 0xf8, 0xed, 0x05, 0x04, 0x0e, 0xb2, 0x06, 0x03, 0x9e, 0x08, + 0x0d, 0x01, 0xee, 0xf4, 0x05, 0x0d, 0x03, 0xb9, 0x0a, 0x00, 0x07, 0xea, + 0x12, 0xfe, 0xae, 0x11, 0x27, 0x0a, 0xe5, 0xfa, 0x13, 0xfe, 0x18, 0x81, + 0x0b, 0xf8, 0x12, 0xdc, 0x00, 0xfa, 0xe8, 0x0e, 0x01, 0x02, 0xfa, 0xfb, + 0x10, 0x05, 0x0b, 0xa7, 0x0c, 0xf4, 0x0a, 0xfb, 0xf7, 0xf9, 0x13, 0xfd, + 0x07, 0x06, 0x10, 0x08, 0xf0, 0xf3, 0x02, 0xf7, 0xfc, 0x0c, 0x0a, 0xda, + 0x35, 0x11, 0xba, 0x1f, 0x1a, 0xe9, 0x8f, 0xb9, 0x11, 0xfe, 0x1a, 0xcc, + 0x05, 0x9c, 0x02, 0x3b, 0xf3, 0xd6, 0xb8, 0x1a, 0x08, 0xa8, 0xe1, 0x0a, + 0x00, 0xc7, 0x0d, 0xae, 0x09, 0xdc, 0x0b, 0x31, 0xaa, 0xb2, 0x38, 0xbf, + 0x15, 0xe3, 0x0b, 0x0c, 0xfa, 0xc2, 0xff, 0x0e, 0xb5, 0x13, 0xf4, 0xb3, + 0xce, 0x9f, 0xe7, 0x05, 0x0c, 0x8c, 0xf7, 0xf1, 0x0e, 0x97, 0x13, 0xf4, + 0x9e, 0xec, 0xbe, 0x12, 0x9b, 0xd8, 0xe5, 0xf8, 0xd7, 0x0c, 0x01, 0x0f, + 0xe4, 0xfd, 0xf3, 0x03, 0xeb, 0x09, 0xff, 0x01, 0xc1, 0x89, 0x13, 0xe0, + 0x06, 0x2b, 0x15, 0x0e, 0xf4, 0x00, 0xfd, 0x05, 0xf6, 0x0b, 0x17, 0x81, + 0xdb, 0x8b, 0x0c, 0x09, 0x09, 0x13, 0x0a, 0x05, 0x1c, 0xfd, 0x17, 0x0d, + 0xfa, 0x0b, 0x0e, 0x06, 0xb8, 0xbc, 0x1c, 0x0a, 0x0c, 0x12, 0x04, 0x0c, + 0xfb, 0xf5, 0x06, 0x11, 0xe5, 0x07, 0x06, 0x14, 0x04, 0x1f, 0xf2, 0xb2, + 0xd4, 0x06, 0xfc, 0x02, 0xb6, 0x0f, 0xcf, 0xd3, 0x03, 0xfd, 0xfe, 0xf8, + 0x15, 0x0d, 0xd8, 0xea, 0xfa, 0x1a, 0x00, 0x05, 0xfb, 0x1d, 0xf5, 0xeb, + 0x12, 0x01, 0x0d, 0xd9, 0x0b, 0xff, 0xff, 0x0c, 0x1c, 0x1b, 0x10, 0x04, + 0x15, 0x03, 0x0f, 0x07, 0x0f, 0x06, 0x0f, 0x06, 0x8d, 0xc7, 0x81, 0xa0, + 0x9e, 0xca, 0xb7, 0xcb, 0xb6, 0xc5, 0xb1, 0xe4, 0xa0, 0x93, 0xa9, 0xa5, + 0x24, 0x03, 0xd8, 0xf7, 0xd8, 0x0f, 0xf7, 0xf4, 0xf7, 0x06, 0xfb, 0xf2, + 0x15, 0xfe, 0x10, 0xee, 0x18, 0xfc, 0x1c, 0x07, 0x06, 0x0b, 0xfc, 0x08, + 0x0d, 0x00, 0x0d, 0xfd, 0x0d, 0xfa, 0x0d, 0x10, 0x96, 0xa8, 0xdc, 0x8b, + 0x04, 0xda, 0x0a, 0xfe, 0xbc, 0x9c, 0xae, 0x01, 0x99, 0xff, 0xe7, 0xc1, + 0x0a, 0xf1, 0x1e, 0xec, 0xf5, 0x02, 0x07, 0x00, 0xf3, 0xe7, 0xf8, 0xfe, + 0x00, 0xf9, 0x01, 0x95, 0x08, 0xfb, 0x13, 0x03, 0x08, 0xfe, 0x05, 0x0d, + 0x10, 0xfa, 0x0b, 0x0f, 0x04, 0x09, 0x09, 0x00, 0x1b, 0x09, 0x33, 0xe5, + 0x31, 0x12, 0x2b, 0x1b, 0xf5, 0xf0, 0x09, 0xf7, 0x02, 0x2f, 0x0c, 0x18, + 0x11, 0xec, 0x0d, 0x0f, 0x29, 0x0d, 0x2c, 0x36, 0x04, 0xfe, 0x13, 0x00, + 0x07, 0x23, 0x21, 0x15, 0x04, 0xcd, 0xf8, 0x10, 0x75, 0x08, 0x32, 0x2d, + 0x15, 0xdc, 0x29, 0x38, 0x06, 0x37, 0x27, 0x08, 0x35, 0x21, 0xd5, 0xfd, + 0x23, 0x45, 0x1a, 0x16, 0x23, 0x31, 0x1b, 0xc0, 0x2a, 0x19, 0x3f, 0x1b, + 0x02, 0xf9, 0xee, 0x1c, 0x2a, 0x2d, 0x16, 0x32, 0x1e, 0x12, 0x16, 0xfc, + 0x2f, 0x11, 0x36, 0xec, 0xd3, 0xa9, 0xf7, 0x1b, 0x41, 0x07, 0x15, 0x25, + 0x33, 0xe6, 0x39, 0x3e, 0x08, 0x1d, 0x27, 0xde, 0x21, 0x2a, 0x04, 0xf1, + 0x19, 0x33, 0xd0, 0xd9, 0x43, 0x37, 0x03, 0x81, 0x29, 0xdd, 0x24, 0x00, + 0xf1, 0xe9, 0xfc, 0x30, 0x12, 0x20, 0x11, 0x1a, 0x3a, 0x19, 0x48, 0xe5, + 0x37, 0x1e, 0x2d, 0x08, 0xc7, 0xbd, 0x12, 0xff, 0x1f, 0x40, 0x2c, 0x34, + 0x26, 0x14, 0x0b, 0x30, 0x1f, 0x27, 0x3f, 0xec, 0xa9, 0xcf, 0x0a, 0x8c, + 0x0f, 0x11, 0x07, 0x09, 0xec, 0xf7, 0x8f, 0xfb, 0xfa, 0x04, 0x12, 0xd0, + 0xf9, 0x00, 0x24, 0xa0, 0x1e, 0x14, 0x16, 0x12, 0x04, 0x16, 0xb9, 0x03, + 0x18, 0x09, 0x0d, 0x1e, 0xe8, 0xf0, 0x04, 0xaa, 0x0f, 0xfc, 0x08, 0x0e, + 0xe2, 0xf7, 0xa5, 0x08, 0xf8, 0x13, 0xf2, 0x01, 0xb0, 0xcc, 0x17, 0x85, + 0x17, 0x15, 0x10, 0x05, 0xcc, 0x00, 0xc0, 0xf4, 0xfa, 0x03, 0x01, 0xdf, + 0x0b, 0xe4, 0x13, 0xd6, 0x07, 0x07, 0xf4, 0xfb, 0xef, 0x19, 0xda, 0xea, + 0x0d, 0xf8, 0xda, 0x2e, 0xd1, 0xf1, 0x0d, 0xb0, 0xfd, 0xec, 0xf8, 0xf0, + 0xbc, 0xf0, 0x9c, 0x10, 0xdf, 0xef, 0xde, 0x45, 0x90, 0x9b, 0x03, 0xa6, + 0x01, 0x14, 0x02, 0xfb, 0xa0, 0xfd, 0xba, 0xf8, 0xe5, 0xfe, 0xe6, 0xc9, + 0xc6, 0xce, 0xa8, 0xeb, 0xce, 0xb2, 0x0a, 0x16, 0x81, 0xb9, 0xe6, 0x29, + 0xb0, 0x02, 0xb0, 0x06, 0xa9, 0x18, 0xb8, 0xad, 0xf6, 0xfe, 0x06, 0x07, + 0xb3, 0xc6, 0x92, 0x1a, 0xdf, 0x09, 0x00, 0x4d, 0xf0, 0x03, 0x01, 0xd3, + 0x04, 0x07, 0x02, 0x02, 0xf5, 0x06, 0xf1, 0xe8, 0xfd, 0xff, 0x00, 0xd7, + 0x05, 0x07, 0x0a, 0x07, 0x0a, 0x11, 0x02, 0x03, 0x0b, 0x13, 0x00, 0xdc, + 0x02, 0x09, 0x0b, 0x00, 0xf5, 0x00, 0x1b, 0xfd, 0x0f, 0x14, 0x05, 0x04, + 0x08, 0x0e, 0x02, 0xf6, 0x05, 0x00, 0x02, 0x0a, 0x05, 0x08, 0xe5, 0xe6, + 0xe9, 0x03, 0xec, 0xe7, 0x06, 0x04, 0xf4, 0xe7, 0x02, 0xdd, 0x09, 0xaf, + 0x10, 0x0d, 0x0f, 0x17, 0x05, 0xff, 0xde, 0xd5, 0x15, 0x04, 0xfe, 0x08, + 0x0e, 0xdc, 0x07, 0x20, 0x10, 0x0b, 0x10, 0x07, 0xf4, 0x0b, 0xde, 0xea, + 0xf6, 0x0d, 0x02, 0xfa, 0xfe, 0xda, 0xf6, 0x28, 0x0d, 0x0d, 0x00, 0xda, + 0xe1, 0x01, 0xe1, 0xd8, 0xf7, 0x11, 0xd1, 0xf7, 0x06, 0xe7, 0x01, 0xf9, + 0xfb, 0xfa, 0xe0, 0xeb, 0xce, 0xfe, 0xba, 0xdd, 0xa4, 0xfa, 0xda, 0x0b, + 0xf4, 0xac, 0xb1, 0x17, 0xca, 0xf8, 0xb1, 0xcb, 0xb7, 0xb8, 0xf1, 0xe8, + 0x9d, 0xd8, 0xca, 0x13, 0xb9, 0xd9, 0x81, 0xff, 0xfb, 0xe7, 0x0a, 0x09, + 0x17, 0x0c, 0x01, 0x08, 0x13, 0xfb, 0x0b, 0xfa, 0x02, 0x08, 0x12, 0x06, + 0xcc, 0xd4, 0x09, 0x06, 0x06, 0x17, 0x06, 0x04, 0xfd, 0xe7, 0x00, 0xf6, + 0x05, 0x0a, 0x24, 0xd2, 0x02, 0x02, 0x1b, 0xee, 0x09, 0xfa, 0x06, 0x01, + 0x00, 0xe9, 0x09, 0x05, 0xd7, 0x0b, 0xf8, 0xf7, 0x03, 0xd8, 0x06, 0x12, + 0x06, 0x02, 0x06, 0x05, 0x0d, 0xe9, 0x0e, 0xf5, 0xfb, 0x02, 0x13, 0xf3, + 0xda, 0xb3, 0x22, 0x00, 0x1e, 0x1a, 0x10, 0x13, 0x03, 0xfc, 0x06, 0x0d, + 0xfb, 0x18, 0x20, 0xf8, 0xfe, 0xc0, 0x1a, 0x07, 0x0f, 0xe6, 0x05, 0x07, + 0xfb, 0xb0, 0x08, 0x13, 0x9f, 0x06, 0xde, 0x04, 0xd6, 0xc3, 0x18, 0x14, + 0x05, 0xeb, 0xfc, 0x03, 0xa8, 0xba, 0x0d, 0x0b, 0xb5, 0x03, 0xee, 0xfc, + 0x84, 0x99, 0x10, 0xd3, 0x17, 0xfc, 0x0d, 0x07, 0x81, 0xb8, 0xc7, 0x12, + 0xb6, 0x12, 0xe0, 0x8d, 0xf8, 0xad, 0xfd, 0x06, 0x01, 0xe8, 0x03, 0xff, + 0xf6, 0x8e, 0x1d, 0x0b, 0x8d, 0x03, 0xd8, 0xb1, 0xe3, 0xc7, 0x10, 0xf1, + 0x1d, 0xf5, 0x07, 0x0b, 0xfa, 0xc9, 0xf0, 0x07, 0xcb, 0x0c, 0xe3, 0xce, + 0xc9, 0xc7, 0x11, 0xeb, 0xdb, 0xd8, 0x01, 0x08, 0xc9, 0xe0, 0xdc, 0x00, + 0xdb, 0x13, 0xbd, 0xe2, 0xd7, 0xd4, 0x2b, 0xf1, 0x07, 0xf5, 0x0b, 0x0e, + 0x10, 0xcd, 0x02, 0x01, 0xcc, 0x0d, 0xf0, 0xfe, 0x1e, 0x23, 0xfa, 0xfe, + 0x00, 0xdf, 0xc6, 0xd3, 0x06, 0x11, 0xbb, 0x1d, 0xf1, 0xec, 0x05, 0xed, + 0xee, 0xfb, 0x14, 0xc8, 0xf1, 0xc0, 0xe4, 0xeb, 0xe5, 0xe5, 0xdf, 0x07, + 0xc4, 0xd9, 0xe0, 0xc7, 0x0c, 0xde, 0x1b, 0x13, 0x17, 0xf6, 0x0b, 0x09, + 0x05, 0xc7, 0x17, 0x03, 0xc9, 0x10, 0xd0, 0xf3, 0x11, 0x21, 0xf4, 0xdb, + 0xa2, 0x17, 0xb8, 0xae, 0x00, 0x2b, 0xbd, 0x10, 0x0c, 0xaf, 0x11, 0x15, + 0x00, 0x2a, 0xf8, 0xd5, 0xa2, 0x0c, 0xbd, 0xd6, 0xfe, 0x24, 0xb0, 0x04, + 0x18, 0xa9, 0x0a, 0x09, 0x81, 0xfb, 0x11, 0x8d, 0xce, 0xab, 0xe3, 0xe0, + 0xa3, 0xd2, 0xad, 0x0e, 0xa3, 0xc5, 0x9a, 0x19, 0x19, 0xa7, 0xe6, 0x1c, + 0x0e, 0xd1, 0xf4, 0xf6, 0x0d, 0xbc, 0x12, 0xc3, 0xf9, 0xf7, 0x08, 0x14, + 0x0e, 0xad, 0x9d, 0x15, 0x19, 0x8d, 0xb0, 0xc9, 0x1b, 0x9b, 0x17, 0x98, + 0xe6, 0xcb, 0x03, 0x31, 0x00, 0xcc, 0xc1, 0x08, 0xfb, 0xc5, 0xa7, 0xb3, + 0xfc, 0xde, 0x05, 0xbb, 0xf1, 0xb0, 0xfb, 0x1d, 0x1c, 0xea, 0xf6, 0x0c, + 0x1d, 0xcc, 0xf8, 0xe0, 0x1b, 0xe2, 0x0c, 0xf6, 0x06, 0xfc, 0x12, 0x20, + 0x04, 0xa5, 0x92, 0x10, 0x13, 0xb0, 0xb8, 0xf2, 0x16, 0x98, 0x09, 0xb3, + 0xe3, 0xea, 0xeb, 0x2f, 0xdc, 0xe7, 0xc2, 0x03, 0x07, 0xeb, 0xb7, 0xc6, + 0xf8, 0xf3, 0x07, 0xbb, 0xab, 0xcd, 0xaa, 0x1e, 0x0c, 0xea, 0xee, 0x21, + 0x13, 0xe4, 0xf6, 0xf3, 0x04, 0xf5, 0x18, 0xff, 0xfe, 0xdd, 0xfe, 0x23, + 0xd0, 0xa3, 0xa7, 0x14, 0x0a, 0x9a, 0xe4, 0xd0, 0xd4, 0xd3, 0x07, 0xe3, + 0x9b, 0xce, 0x8b, 0x30, 0xc0, 0xa4, 0xc6, 0x0b, 0x10, 0xd1, 0xd0, 0xeb, + 0xed, 0xee, 0xfe, 0xcd, 0x81, 0xc2, 0xb2, 0x2d, 0x9f, 0xc1, 0x06, 0x81, + 0x0e, 0x03, 0x0c, 0x04, 0x01, 0x05, 0xc2, 0x05, 0xf7, 0x0c, 0xff, 0x9f, + 0xde, 0x01, 0xfd, 0xab, 0x09, 0x0f, 0x03, 0x03, 0xfa, 0x02, 0xc6, 0x09, + 0xfe, 0x06, 0x11, 0x9c, 0x00, 0x02, 0x04, 0xbf, 0x03, 0x04, 0x0b, 0x06, + 0xf2, 0x07, 0xc2, 0x09, 0x06, 0x05, 0x01, 0xd3, 0xbf, 0xc2, 0xfd, 0xf0, + 0x08, 0xfb, 0x02, 0x07, 0xe8, 0xf1, 0xf3, 0x0d, 0xec, 0x07, 0xf6, 0xbf, + 0xfb, 0x0e, 0x01, 0xea, 0x08, 0x11, 0x0a, 0x0d, 0xdc, 0x0b, 0xf6, 0x07, + 0xfe, 0x08, 0x07, 0xa8, 0x10, 0x0e, 0x13, 0xdc, 0x01, 0x03, 0x03, 0x04, + 0xd5, 0x01, 0xd7, 0x08, 0x09, 0x05, 0x01, 0x1f, 0xf7, 0xcd, 0xea, 0x01, + 0x0b, 0xf7, 0x03, 0x08, 0xf8, 0xb6, 0x00, 0x01, 0xaa, 0x09, 0xfb, 0x00, + 0xfd, 0xb5, 0x04, 0x0c, 0x0d, 0xfa, 0x00, 0x06, 0xe3, 0xbb, 0x0d, 0xff, + 0xaf, 0x05, 0xf1, 0x01, 0xaa, 0xb3, 0x05, 0x00, 0x04, 0xf8, 0x02, 0x06, + 0xaf, 0xaf, 0xc7, 0x0a, 0xac, 0x06, 0xea, 0xdd, 0x21, 0xec, 0xcd, 0x16, + 0x1a, 0xd4, 0xf4, 0xfa, 0x0d, 0xc7, 0x1a, 0xfa, 0x0d, 0xe7, 0x09, 0x0b, + 0x06, 0xcd, 0xd6, 0x15, 0x0f, 0xd5, 0xcc, 0xc1, 0x11, 0xe1, 0x10, 0xfa, + 0x16, 0xdc, 0x12, 0x1d, 0x04, 0xb3, 0xfe, 0x04, 0x03, 0x93, 0xee, 0xf1, + 0x10, 0x87, 0x01, 0xeb, 0x09, 0xf9, 0x04, 0x10, 0x0f, 0xd5, 0xa3, 0x09, + 0x23, 0xb9, 0xc3, 0xb7, 0x0e, 0x9c, 0x0b, 0xbd, 0x11, 0xc7, 0x04, 0x0c, + 0x17, 0xd9, 0x08, 0x11, 0x0e, 0xd9, 0xc3, 0xc9, 0x08, 0xd8, 0x09, 0xdc, + 0x0c, 0xd7, 0x14, 0x09, 0x09, 0xe0, 0x01, 0x05, 0x09, 0xc8, 0xa4, 0xc7, + 0x05, 0xbc, 0x06, 0xa9, 0x0d, 0x9e, 0x07, 0x0a, 0xff, 0xe4, 0x84, 0x04, + 0x09, 0xe7, 0x9d, 0x8f, 0xfe, 0xbb, 0x07, 0xca, 0xfd, 0xae, 0x0c, 0xfc, + 0x0a, 0x03, 0x10, 0x01, 0xff, 0xeb, 0x93, 0x9c, 0x0f, 0xf5, 0x07, 0x0c, + 0x11, 0xa4, 0x0d, 0x19, 0x02, 0xfd, 0x0e, 0x02, 0x02, 0xe3, 0x89, 0x81, + 0xef, 0xe1, 0x00, 0xd6, 0x00, 0x8f, 0xf9, 0x12, 0xe9, 0xbc, 0x98, 0x03, + 0xf6, 0x9e, 0xb4, 0xb6, 0xcc, 0xa8, 0x02, 0xeb, 0xd3, 0xac, 0xa6, 0xf3, + 0xf7, 0xb5, 0xcc, 0x12, 0x0a, 0xa6, 0xb6, 0xce, 0xfe, 0xb3, 0x08, 0xd4, + 0xd4, 0xc1, 0xbd, 0x17, 0x02, 0xad, 0xd9, 0x0a, 0x10, 0xae, 0xdc, 0xef, + 0x08, 0x9c, 0x07, 0xd3, 0xf9, 0xd4, 0xf1, 0x0d, 0xc9, 0xcf, 0xf5, 0xf2, + 0xff, 0xbe, 0xfd, 0x01, 0x05, 0xce, 0x03, 0x11, 0xc2, 0xfe, 0xfe, 0xd2, + 0xdf, 0xc1, 0x06, 0xfa, 0xfa, 0xd6, 0x04, 0x07, 0xfe, 0xde, 0xf6, 0xff, + 0xc9, 0xf7, 0xfc, 0xe8, 0xf9, 0xc4, 0xf7, 0xff, 0x0d, 0x04, 0x00, 0x09, + 0x0c, 0xe0, 0x0c, 0x02, 0xf6, 0x03, 0x08, 0x06, 0x00, 0xb7, 0xeb, 0x11, + 0x09, 0x1a, 0x0a, 0x0e, 0x0f, 0xfc, 0x09, 0x05, 0x0a, 0x0d, 0x12, 0xf1, + 0xf9, 0x81, 0x0f, 0x00, 0x10, 0x0d, 0x0d, 0x13, 0x07, 0xe4, 0x0b, 0x1c, + 0xf8, 0x17, 0x14, 0xec, 0xf7, 0x8d, 0x19, 0x08, 0x1b, 0x00, 0x15, 0x18, + 0x05, 0xde, 0x0e, 0x0e, 0xf8, 0x1a, 0x11, 0xee, 0xf3, 0x0a, 0x16, 0xfd, + 0x0a, 0xfb, 0x0b, 0x0f, 0x00, 0x04, 0x01, 0x0c, 0xf8, 0x0b, 0x00, 0xf7, + 0xd0, 0xdc, 0x0f, 0x07, 0x07, 0xf4, 0xf4, 0xff, 0xfe, 0x01, 0x03, 0x9d, + 0x01, 0xfa, 0xd0, 0x00, 0xb9, 0xbe, 0xb7, 0x0d, 0xd8, 0xa7, 0x95, 0xa7, + 0xfc, 0x97, 0xfe, 0xfc, 0x81, 0xc0, 0xba, 0xfc, 0x03, 0x1c, 0x38, 0xf4, + 0x1a, 0x19, 0x19, 0x1b, 0x00, 0x1b, 0xff, 0x1a, 0x11, 0x15, 0x02, 0xf7, + 0xe4, 0xc4, 0x02, 0x00, 0x0a, 0xd0, 0xe6, 0xe7, 0xfc, 0xbe, 0x05, 0x95, + 0xb6, 0xf4, 0xb3, 0xf2, 0xbc, 0xcc, 0xc9, 0x06, 0xdd, 0xc5, 0xb5, 0xb9, + 0xe7, 0xc6, 0x00, 0xd2, 0xa0, 0xb7, 0xbc, 0x14, 0x10, 0x3c, 0x27, 0xe8, + 0x19, 0x14, 0x12, 0x19, 0x09, 0x21, 0xf6, 0x17, 0xfd, 0x18, 0x07, 0x0e, + 0xf9, 0x05, 0xe4, 0x0e, 0x07, 0xb1, 0xda, 0xd7, 0x0b, 0xfe, 0x03, 0xf7, + 0xcf, 0xd6, 0xca, 0x12, 0xc8, 0xec, 0xdc, 0x01, 0xef, 0xcc, 0xa1, 0xc7, + 0xf7, 0xd7, 0xff, 0xf1, 0xae, 0xbf, 0xcc, 0x0e, 0xd8, 0xda, 0x13, 0x26, + 0x04, 0x09, 0xff, 0x03, 0xea, 0xf6, 0x1c, 0xec, 0x0b, 0x07, 0x13, 0xfd, + 0xe4, 0xf4, 0x25, 0xfb, 0xfd, 0x15, 0x02, 0x03, 0xed, 0x11, 0xf1, 0x90, + 0x17, 0x06, 0x21, 0x1c, 0xf6, 0xf8, 0x47, 0xe0, 0xde, 0x0d, 0xf2, 0xea, + 0xde, 0x09, 0xed, 0x9c, 0x00, 0xe5, 0xf1, 0x2d, 0x85, 0xd4, 0x33, 0x81, + 0x16, 0x1d, 0x0b, 0x10, 0xd3, 0x0c, 0xaa, 0xe9, 0x12, 0x06, 0x1e, 0xae, + 0xcf, 0xef, 0x17, 0xd9, 0x13, 0x1e, 0x05, 0xfe, 0x0d, 0x1a, 0xf2, 0x8a, + 0x10, 0x0b, 0x2e, 0x0c, 0xd7, 0xe0, 0xfa, 0xfb, 0xb3, 0xe3, 0xae, 0xaf, + 0xdf, 0x0d, 0xf8, 0x8f, 0xf7, 0xc1, 0x9d, 0x13, 0xa7, 0xd5, 0x22, 0x9e, + 0x1b, 0x1e, 0x08, 0x02, 0xe2, 0x07, 0xec, 0xfb, 0x0c, 0x0d, 0x0f, 0xb4, + 0xdf, 0xd6, 0x0f, 0x09, 0x1a, 0x16, 0x03, 0x03, 0xfc, 0x19, 0x14, 0x82, + 0x14, 0x02, 0xff, 0x01, 0xbf, 0xfc, 0x9a, 0x17, 0xf0, 0xac, 0xa2, 0xa7, + 0x02, 0xb7, 0x12, 0x9c, 0xbe, 0xc4, 0xab, 0x08, 0xf0, 0xe0, 0x81, 0x2d, + 0x09, 0xe1, 0xdc, 0xf0, 0xeb, 0xd5, 0x1f, 0x98, 0xed, 0xd2, 0xe6, 0x2d, + 0x0b, 0x03, 0x53, 0x0f, 0x0d, 0x16, 0x10, 0x08, 0x0c, 0x0c, 0x09, 0xdb, + 0x11, 0x0f, 0x1e, 0x1a, 0x07, 0x04, 0x17, 0xf0, 0xc7, 0x02, 0x00, 0xea, + 0xd9, 0x09, 0xd5, 0x10, 0x05, 0xf0, 0xf9, 0x0a, 0xb0, 0xc4, 0x9f, 0xbd, + 0xde, 0xfd, 0xdf, 0xe9, 0x9f, 0xdb, 0xda, 0xd5, 0xdf, 0xca, 0xea, 0xb1, + 0x0c, 0x07, 0x45, 0xfc, 0x13, 0x28, 0x10, 0x03, 0x1c, 0x1c, 0xff, 0xde, + 0x1d, 0x0c, 0x27, 0x31, 0xed, 0xd4, 0x23, 0xdc, 0xd7, 0xcf, 0x05, 0xfc, + 0xc3, 0xfd, 0x9c, 0x0c, 0xcf, 0xf9, 0xb8, 0x27, 0xa3, 0xd3, 0xfd, 0xc9, + 0x05, 0x0a, 0x04, 0x00, 0xc9, 0xd7, 0xff, 0xfc, 0xe4, 0x00, 0xf5, 0xea, + 0x0f, 0x0d, 0x33, 0x16, 0x0f, 0x19, 0x0d, 0x04, 0x1d, 0x18, 0x07, 0xec, + 0x21, 0x06, 0x24, 0x1d, 0xdb, 0xe0, 0x2a, 0xd8, 0xe4, 0xca, 0xe4, 0xf3, + 0xed, 0xf9, 0x98, 0xed, 0xe2, 0xe6, 0xd1, 0x42, 0x12, 0x14, 0xf6, 0xf1, + 0xb8, 0x0e, 0xc1, 0xa0, 0x0a, 0x0d, 0xee, 0xe6, 0x0f, 0xc6, 0x11, 0xe6, + 0x22, 0x1f, 0x19, 0x05, 0xf6, 0x15, 0xdf, 0xdf, 0xfb, 0x15, 0xf3, 0x19, + 0x12, 0xec, 0x0b, 0x0e, 0x08, 0x01, 0x00, 0x0e, 0x0f, 0x12, 0xca, 0xc6, + 0xfc, 0x04, 0x0a, 0x05, 0x02, 0xdb, 0xfc, 0x11, 0x03, 0x1d, 0x93, 0xca, + 0xa9, 0x05, 0xc0, 0xb5, 0xce, 0xf2, 0xea, 0x0f, 0x09, 0xb9, 0xe5, 0xc9, + 0x22, 0x19, 0x16, 0xee, 0xf5, 0x0c, 0x0d, 0xec, 0x13, 0x0a, 0xf9, 0x12, + 0x0d, 0x14, 0x0c, 0xf6, 0x09, 0x03, 0x11, 0x01, 0xeb, 0xff, 0xc1, 0xa4, + 0x07, 0x00, 0xfe, 0xfe, 0x01, 0xb6, 0x04, 0x03, 0x8f, 0x97, 0xdf, 0xae, + 0x16, 0xba, 0xfe, 0x04, 0xc6, 0x90, 0xfe, 0xf8, 0x81, 0xfe, 0x96, 0x87, + 0x11, 0xfe, 0xe4, 0x05, 0x0b, 0x00, 0x0f, 0x10, 0xfd, 0xf2, 0x10, 0x10, + 0xfd, 0x06, 0xff, 0xc6, 0x04, 0xff, 0x1b, 0x0f, 0xf7, 0x00, 0x07, 0x09, + 0x10, 0x05, 0x06, 0x0e, 0x04, 0xf6, 0x06, 0x1c, 0x0e, 0xf9, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x00, 0x00, 0x00, 0x70, 0xf8, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xb1, 0x93, 0xb9, 0x3a, 0x15, 0x93, 0xf8, 0x3a, 0x80, 0x56, 0xad, 0x3a, + 0x2f, 0x2c, 0xb4, 0x3a, 0x73, 0xdb, 0x97, 0x3a, 0xcf, 0xc9, 0xa2, 0x3a, + 0x3c, 0x68, 0xb3, 0x3a, 0x7b, 0x4f, 0x9d, 0x3a, 0x5c, 0x19, 0x5f, 0x3a, + 0xd5, 0x55, 0x67, 0x3a, 0x53, 0x13, 0x7d, 0x3a, 0x7a, 0x37, 0x9f, 0x3a, + 0xae, 0xdc, 0xb2, 0x3a, 0xc9, 0x9b, 0xa2, 0x3a, 0xbd, 0xc1, 0xa3, 0x3a, + 0xb3, 0xb3, 0x93, 0x3a, 0x1d, 0x0d, 0xa5, 0x3a, 0x7a, 0x4f, 0x9d, 0x3a, + 0x3b, 0x3c, 0x80, 0x3a, 0x87, 0xdf, 0x06, 0x3a, 0x8e, 0x2e, 0x87, 0x3a, + 0xc3, 0x83, 0xb3, 0x3a, 0xe8, 0xd4, 0x7b, 0x3a, 0x2e, 0x51, 0x77, 0x3a, + 0x2c, 0x10, 0x6e, 0x3a, 0xe1, 0x3f, 0xb7, 0x3a, 0xfd, 0xae, 0x83, 0x3a, + 0xa0, 0x4a, 0xa5, 0x3a, 0xba, 0x56, 0x4c, 0x3a, 0xa7, 0xb1, 0x90, 0x3a, + 0x3f, 0x35, 0x95, 0x3a, 0x91, 0x32, 0x88, 0x3a, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xfb, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x30, 0xff, 0xff, 0xff, + 0x40, 0x04, 0x00, 0x00, 0xa2, 0xfc, 0xff, 0xff, 0xd4, 0xff, 0xff, 0xff, + 0x4c, 0xff, 0xff, 0xff, 0x66, 0xff, 0xff, 0xff, 0x96, 0xfc, 0xff, 0xff, + 0xf9, 0xf3, 0xff, 0xff, 0x06, 0xfe, 0xff, 0xff, 0x9b, 0xfe, 0xff, 0xff, + 0xe8, 0xfe, 0xff, 0xff, 0x59, 0x02, 0x00, 0x00, 0xf6, 0xff, 0xff, 0xff, + 0xc3, 0xfc, 0xff, 0xff, 0x62, 0x0b, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, + 0x3a, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2f, 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, + 0x72, 0x6d, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x46, 0x75, 0x73, 0x65, 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, + 0x72, 0x6d, 0x56, 0x33, 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, + 0x62, 0x69, 0x61, 0x73, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, + 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, + 0x64, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x00, 0x00, 0x00, + 0xf0, 0xfa, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x93, 0xc8, 0x52, 0x39, 0x5c, 0x36, 0x73, 0x39, + 0x26, 0x92, 0x02, 0x39, 0x39, 0xfd, 0x48, 0x39, 0x64, 0x2b, 0x46, 0x39, + 0x76, 0xae, 0x86, 0x39, 0x90, 0x52, 0xbc, 0x38, 0xd0, 0xc2, 0xe2, 0x38, + 0x2c, 0x13, 0xd6, 0x38, 0x55, 0x74, 0x41, 0x39, 0xee, 0xe5, 0xf0, 0x38, + 0x51, 0x0a, 0xb9, 0x39, 0x61, 0xfc, 0xef, 0x38, 0x01, 0xed, 0xc1, 0x38, + 0x1f, 0x36, 0x7a, 0x38, 0xac, 0x4c, 0x0e, 0x39, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xfc, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0xe4, 0x1e, 0xab, 0xfc, + 0x1b, 0xa1, 0xfe, 0x0f, 0x9c, 0xf3, 0x22, 0x98, 0xf2, 0x1b, 0x81, 0x02, + 0x11, 0x8a, 0xf3, 0x11, 0xd2, 0xf3, 0x19, 0xa4, 0x02, 0x0d, 0xcb, 0xcf, + 0x20, 0x87, 0xd7, 0x16, 0xc0, 0xd3, 0x13, 0xc0, 0xbe, 0x23, 0x81, 0xb9, + 0x26, 0x90, 0xad, 0x1d, 0x84, 0xc7, 0x1d, 0xa3, 0xd2, 0x1f, 0xb1, 0xc1, + 0x19, 0xa5, 0xd4, 0x17, 0x33, 0xf5, 0xfc, 0xdc, 0x17, 0xaa, 0x81, 0xcc, + 0x29, 0x17, 0x0a, 0xf7, 0x0d, 0x32, 0xab, 0x8a, 0x87, 0x4a, 0xf7, 0x12, + 0xe4, 0xdd, 0x28, 0xba, 0xb6, 0x48, 0x09, 0x81, 0x39, 0x04, 0xf1, 0x26, + 0xfd, 0x02, 0x49, 0x0f, 0xb3, 0x25, 0x10, 0xba, 0xf8, 0xfe, 0xff, 0x42, + 0xf9, 0xf1, 0x20, 0x03, 0xfe, 0x06, 0x01, 0xff, 0xf3, 0x01, 0x18, 0x22, + 0x02, 0x22, 0x23, 0x01, 0x1f, 0x0c, 0x00, 0x19, 0x1d, 0xfd, 0x2d, 0x3f, + 0x00, 0x13, 0xf2, 0x00, 0x14, 0x20, 0xfb, 0x0e, 0x57, 0xe1, 0x81, 0x81, + 0x10, 0xf1, 0xc7, 0x1e, 0xf4, 0xe6, 0x15, 0xf5, 0xad, 0x14, 0x03, 0xcd, + 0x1b, 0xf7, 0xda, 0x16, 0xf9, 0x0b, 0xf8, 0xf8, 0xec, 0x0c, 0xfe, 0xf5, + 0x06, 0x03, 0x9f, 0x07, 0x48, 0xf3, 0x06, 0x57, 0xf7, 0xff, 0x50, 0xf7, + 0xfe, 0x6b, 0xfe, 0xfb, 0x7f, 0xf7, 0x01, 0x52, 0xfb, 0x00, 0x44, 0xf7, + 0x03, 0x68, 0x05, 0x00, 0x6b, 0xf3, 0x08, 0x3f, 0xff, 0x04, 0x58, 0xf7, + 0x05, 0x3c, 0x08, 0x02, 0x57, 0x03, 0x01, 0x63, 0xf0, 0x09, 0x57, 0x0c, + 0x04, 0x2f, 0x0d, 0xfe, 0x53, 0x0c, 0x04, 0x7f, 0x20, 0xe7, 0x1b, 0x23, + 0xc3, 0x2f, 0x3b, 0xb4, 0x19, 0x0a, 0x3c, 0xbb, 0x4a, 0x64, 0x81, 0x67, + 0xec, 0xfd, 0xe7, 0x37, 0x85, 0x13, 0x4f, 0x9d, 0x43, 0x19, 0xe9, 0x8b, + 0x32, 0xc2, 0xa5, 0x2b, 0xcf, 0xcc, 0x14, 0xf1, 0x81, 0x34, 0x9e, 0x97, + 0x2b, 0xc9, 0xa7, 0x1d, 0xdf, 0xa5, 0x24, 0xae, 0xcb, 0x25, 0xb9, 0xc8, + 0x05, 0xf6, 0x4a, 0xff, 0x05, 0x7f, 0x1a, 0xc4, 0x4a, 0x08, 0xfb, 0x64, + 0xed, 0x20, 0x68, 0xf4, 0x0a, 0x6d, 0x01, 0x00, 0x50, 0xe8, 0x0e, 0x59, + 0xfa, 0x01, 0x53, 0x01, 0x01, 0xde, 0x13, 0x81, 0x04, 0xf2, 0x0b, 0x05, + 0xed, 0x1c, 0xfe, 0x07, 0xf0, 0xfe, 0xeb, 0x34, 0xfb, 0xf6, 0x20, 0xfd, + 0x00, 0x1d, 0xf8, 0xf8, 0x28, 0x02, 0xfa, 0x22, 0xdf, 0x33, 0xb7, 0xcb, + 0x40, 0xba, 0xee, 0x1b, 0xf2, 0xe1, 0x41, 0x91, 0xc5, 0x58, 0x81, 0xc1, + 0x38, 0xab, 0x04, 0x04, 0xf5, 0xe6, 0x29, 0xbd, 0xd3, 0x2c, 0xc4, 0xa5, + 0x0f, 0x4e, 0xdf, 0xfe, 0x57, 0xfc, 0xf8, 0x21, 0xfc, 0x09, 0x63, 0xfc, + 0x00, 0x7f, 0x03, 0xfa, 0x66, 0x09, 0x08, 0x16, 0xf8, 0x09, 0x4f, 0x14, + 0x05, 0x4b, 0xfc, 0x00, 0xfb, 0xe8, 0x20, 0xef, 0xf1, 0x0c, 0xef, 0xfa, + 0x25, 0xce, 0xba, 0x73, 0xd3, 0xbd, 0x4e, 0xdc, 0xf0, 0x49, 0xb1, 0xe4, + 0x7f, 0xc6, 0xc1, 0x79, 0xdf, 0x05, 0x31, 0x82, 0x2f, 0xf9, 0xe1, 0x5c, + 0xa3, 0xd4, 0x00, 0x53, 0x81, 0x45, 0xb6, 0xfc, 0x37, 0xac, 0xff, 0x06, + 0x10, 0xdb, 0x22, 0xca, 0x04, 0x30, 0xb5, 0x04, 0x66, 0xfe, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, + 0x62, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, + 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x46, 0x75, 0x73, 0x65, + 0x64, 0x42, 0x61, 0x74, 0x63, 0x68, 0x4e, 0x6f, 0x72, 0x6d, 0x56, 0x33, + 0x3b, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x62, 0x69, 0x61, 0x73, + 0x3b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x3b, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2f, 0x63, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x31, 0x00, 0x00, 0x28, 0xfe, 0xff, 0xff, + 0x08, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x93, 0xc8, 0x52, 0x39, 0x5c, 0x36, 0x73, 0x39, 0x26, 0x92, 0x02, 0x39, + 0x39, 0xfd, 0x48, 0x39, 0x64, 0x2b, 0x46, 0x39, 0x76, 0xae, 0x86, 0x39, + 0x90, 0x52, 0xbc, 0x38, 0xd0, 0xc2, 0xe2, 0x38, 0x2c, 0x13, 0xd6, 0x38, + 0x55, 0x74, 0x41, 0x39, 0xee, 0xe5, 0xf0, 0x38, 0x51, 0x0a, 0xb9, 0x39, + 0x61, 0xfc, 0xef, 0x38, 0x01, 0xed, 0xc1, 0x38, 0x1f, 0x36, 0x7a, 0x38, + 0xac, 0x4c, 0x0e, 0x39, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, + 0x5f, 0x61, 0x76, 0x65, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x70, 0x6f, 0x6f, + 0x6c, 0x69, 0x6e, 0x67, 0x32, 0x64, 0x2f, 0x4d, 0x65, 0x61, 0x6e, 0x2f, + 0x72, 0x65, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, + 0x64, 0x69, 0x63, 0x65, 0x73, 0x00, 0x00, 0x00, 0x58, 0xff, 0xff, 0xff, + 0x14, 0x00, 0x1c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x31, 0x3a, + 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00}; +unsigned int g_magic_wand_model_data_len = 30880; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand_model_data.h b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand_model_data.h new file mode 100644 index 000000000..9a7b9a814 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/magic_wand_model_data.h @@ -0,0 +1,24 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +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 is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. It was created using the command: +// xxd -i magic_wand_model.tflite > magic_wand_model_data.cc + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_MAGIC_WAND_MAGIC_WAND_MODEL_DATA_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MAGIC_WAND_MAGIC_WAND_MODEL_DATA_H_ + +extern const unsigned char g_magic_wand_model_data[]; +extern const int g_magic_wand_model_data_len; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MAGIC_WAND_MAGIC_WAND_MODEL_DATA_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/rasterize_stroke.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/rasterize_stroke.cpp new file mode 100644 index 000000000..839a85db0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/rasterize_stroke.cpp @@ -0,0 +1,157 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +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 "rasterize_stroke.h" + +namespace { +constexpr int kFixedPoint = 4096; + +int32_t MulFP(int32_t a, int32_t b) { return (a * b) / kFixedPoint; } + +int32_t DivFP(int32_t a, int32_t b) { + if (b == 0) { + b = 1; + } + return (a * kFixedPoint) / b; +} + +int32_t FloatToFP(float a) { return static_cast(a * kFixedPoint); } + +int32_t NormToCoordFP(int32_t a_fp, int32_t range_fp, int32_t half_size_fp) { + const int32_t norm_fp = DivFP(a_fp, range_fp); + return MulFP(norm_fp, half_size_fp) + half_size_fp; +} + +int32_t RoundFPToInt(int32_t a) { + return static_cast((a + (kFixedPoint / 2)) / kFixedPoint); +} + +int32_t Gate(int32_t a, int32_t min, int32_t max) { + if (a < min) { + return min; + } else if (a > max) { + return max; + } else { + return a; + } +} + +int32_t Abs(int32_t a) { + if (a > 0) { + return a; + } else { + return -a; + } +} + +} // namespace + +void RasterizeStroke(int8_t* stroke_points, int stroke_points_count, + float x_range, float y_range, int width, int height, + int8_t* out_buffer) { + constexpr int num_channels = 3; + const int buffer_byte_count = height * width * num_channels; + + for (int i = 0; i < buffer_byte_count; ++i) { + out_buffer[i] = -128; + } + + const int32_t width_fp = width * kFixedPoint; + const int32_t height_fp = height * kFixedPoint; + const int32_t half_width_fp = width_fp / 2; + const int32_t half_height_fp = height_fp / 2; + const int32_t x_range_fp = FloatToFP(x_range); + const int32_t y_range_fp = FloatToFP(y_range); + + const int t_inc_fp = kFixedPoint / stroke_points_count; + + const int one_half_fp = (kFixedPoint / 2); + + for (int point_index = 0; point_index < (stroke_points_count - 1); + ++point_index) { + const int8_t* start_point = &stroke_points[point_index * 2]; + const int32_t start_point_x_fp = (start_point[0] * kFixedPoint) / 128; + const int32_t start_point_y_fp = (start_point[1] * kFixedPoint) / 128; + + const int8_t* end_point = &stroke_points[(point_index + 1) * 2]; + const int32_t end_point_x_fp = (end_point[0] * kFixedPoint) / 128; + const int32_t end_point_y_fp = (end_point[1] * kFixedPoint) / 128; + + const int32_t start_x_fp = + NormToCoordFP(start_point_x_fp, x_range_fp, half_width_fp); + const int32_t start_y_fp = + NormToCoordFP(-start_point_y_fp, y_range_fp, half_height_fp); + const int32_t end_x_fp = + NormToCoordFP(end_point_x_fp, x_range_fp, half_width_fp); + const int32_t end_y_fp = + NormToCoordFP(-end_point_y_fp, y_range_fp, half_height_fp); + const int32_t delta_x_fp = end_x_fp - start_x_fp; + const int32_t delta_y_fp = end_y_fp - start_y_fp; + + const int32_t t_fp = point_index * t_inc_fp; + int32_t red_i32; + int32_t green_i32; + int32_t blue_i32; + if (t_fp < one_half_fp) { + const int32_t local_t_fp = DivFP(t_fp, one_half_fp); + const int32_t one_minus_t_fp = kFixedPoint - local_t_fp; + red_i32 = RoundFPToInt(one_minus_t_fp * 255) - 128; + green_i32 = RoundFPToInt(local_t_fp * 255) - 128; + blue_i32 = -128; + } else { + const int32_t local_t_fp = DivFP(t_fp - one_half_fp, one_half_fp); + const int32_t one_minus_t_fp = kFixedPoint - local_t_fp; + red_i32 = -128; + green_i32 = RoundFPToInt(one_minus_t_fp * 255) - 128; + blue_i32 = RoundFPToInt(local_t_fp * 255) - 128; + } + const int8_t red_i8 = Gate(red_i32, -128, 127); + const int8_t green_i8 = Gate(green_i32, -128, 127); + const int8_t blue_i8 = Gate(blue_i32, -128, 127); + + int line_length; + int32_t x_inc_fp; + int32_t y_inc_fp; + if (Abs(delta_x_fp) > Abs(delta_y_fp)) { + line_length = Abs(RoundFPToInt(delta_x_fp)); + if (delta_x_fp > 0) { + x_inc_fp = 1 * kFixedPoint; + y_inc_fp = DivFP(delta_y_fp, delta_x_fp); + } else { + x_inc_fp = -1 * kFixedPoint; + y_inc_fp = -DivFP(delta_y_fp, delta_x_fp); + } + } else { + line_length = Abs(RoundFPToInt(delta_y_fp)); + if (delta_y_fp > 0) { + y_inc_fp = 1 * kFixedPoint; + x_inc_fp = DivFP(delta_x_fp, delta_y_fp); + } else { + y_inc_fp = -1 * kFixedPoint; + x_inc_fp = -DivFP(delta_x_fp, delta_y_fp); + } + } + for (int i = 0; i < (line_length + 1); ++i) { + const int32_t x_fp = start_x_fp + (i * x_inc_fp); + const int32_t y_fp = start_y_fp + (i * y_inc_fp); + const int x = RoundFPToInt(x_fp); + const int y = RoundFPToInt(y_fp); + if ((x < 0) or (x >= width) or (y < 0) or (y >= height)) { + continue; + } + const int buffer_index = (y * width * num_channels) + (x * num_channels); + out_buffer[buffer_index + 0] = red_i8; + out_buffer[buffer_index + 1] = green_i8; + out_buffer[buffer_index + 2] = blue_i8; + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/rasterize_stroke.h b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/rasterize_stroke.h new file mode 100644 index 000000000..a9c118a32 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/rasterize_stroke.h @@ -0,0 +1,22 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MAGIC_WAND_RASTERIZE_STROKE_H +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MAGIC_WAND_RASTERIZE_STROKE_H + +#include + +void RasterizeStroke(int8_t* stroke_points, int stroke_points_count, + float x_range, float y_range, int width, int height, + int8_t* out_buffer); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MAGIC_WAND_RASTERIZE_STROKE_H diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/train/train_magic_wand_model.ipynb b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/train/train_magic_wand_model.ipynb new file mode 100644 index 000000000..63379fdc6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/train/train_magic_wand_model.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Copy of Magic Wand Training","provenance":[{"file_id":"https://github.com/petewarden/magic_wand/blob/main/train/train_magic_wand_model.ipynb","timestamp":1638386707719}],"collapsed_sections":[]},"kernelspec":{"name":"python3","display_name":"Python 3"}},"cells":[{"cell_type":"code","metadata":{"id":"0g1pF6RfViPr","executionInfo":{"status":"ok","timestamp":1638745473565,"user_tz":480,"elapsed":179,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["SAVED_MODEL_FILENAME = \"saved_model\"\n","FLOAT_TFL_MODEL_FILENAME = \"float_model.tfl\"\n","QUANTIZED_TFL_MODEL_FILENAME = \"quantized_model.tfl\"\n","TFL_CC_MODEL_FILENAME = \"magic_wand_model_data.cc\""],"execution_count":1,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"xvPo0OP0TFDq","executionInfo":{"status":"ok","timestamp":1638745477856,"user_tz":480,"elapsed":2072,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"2b44a027-1c9a-46aa-9660-57db546c8f75"},"source":["!curl -L https://github.com/petewarden/magic_wand_digit_data/archive/8170591863f9addca27b1a963263f7c7bed33f41.zip -o magic_wand_digit_data.zip\n","!unzip magic_wand_digit_data.zip\n","!rm -rf magic_wand_digit_data\n","!mv magic_wand_digit_data-* magic_wand_digit_data\n","!rm -rf magic_wand_digit_data.zip\n","!rm -rf sample_data\n","!mkdir -p checkpoints"],"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":[" % Total % Received % Xferd Average Speed Time Time Time Current\n"," Dload Upload Total Spent Left Speed\n","100 171 0 171 0 0 228 0 --:--:-- --:--:-- --:--:-- 228\n","100 238k 0 238k 0 0 250k 0 --:--:-- --:--:-- --:--:-- 1667k\n","Archive: magic_wand_digit_data.zip\n","8170591863f9addca27b1a963263f7c7bed33f41\n"," creating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/\n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/LICENSE \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_0.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_1.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_2.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_3.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_4.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_5.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_6.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_7.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_8.json \n"," inflating: magic_wand_digit_data-8170591863f9addca27b1a963263f7c7bed33f41/petewarden_9.json \n"]}]},{"cell_type":"code","metadata":{"id":"mWO58-igVFSd","executionInfo":{"status":"ok","timestamp":1638745496968,"user_tz":480,"elapsed":166,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["import glob\n","import json\n","\n","strokes = []\n","for filename in glob.glob(\"magic_wand_digit_data/*.json\"):\n"," with open(filename, \"r\") as file:\n"," file_contents = file.read()\n"," file_data = json.loads(file_contents)\n"," for stroke in file_data[\"strokes\"]:\n"," stroke[\"filename\"] = filename\n"," strokes.append(stroke)"],"execution_count":3,"outputs":[]},{"cell_type":"code","metadata":{"id":"xfLzrpyLVJ5S","executionInfo":{"status":"ok","timestamp":1638745501162,"user_tz":480,"elapsed":171,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["import matplotlib.pyplot as plt\n","\n","def plot_stroke(stroke):\n","\n"," x_array = []\n"," y_array = []\n"," for coords in stroke[\"strokePoints\"]:\n"," x_array.append(coords[\"x\"])\n"," y_array.append(coords[\"y\"])\n","\n"," fig = plt.figure(figsize=(12.8, 4.8))\n"," fig.suptitle(stroke[\"label\"])\n","\n"," ax = fig.add_subplot(131)\n"," ax.set_xlabel('x')\n"," ax.set_ylabel('y')\n"," ax.set_xlim(-0.4, 0.4)\n"," ax.set_ylim(-0.4, 0.4)\n"," ax.plot(x_array, y_array)\n","\n"," plt.show()"],"execution_count":4,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":391},"id":"dveZd2ZuW-jl","executionInfo":{"status":"ok","timestamp":1638746177871,"user_tz":480,"elapsed":466,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"ab8d5f8e-d753-49eb-fc06-607944f55e86"},"source":["import numpy as np\n","\n","shuffled_strokes = list(strokes)\n","np.random.shuffle(shuffled_strokes)\n","plot_stroke(shuffled_strokes[0])\n","print(f\"This stroke: {len(shuffled_strokes[0]['strokePoints'])}\")\n","func = lambda x: len(x[\"strokePoints\"])\n","values = list(map(func, strokes))\n","print(f\"All strokes: min {np.min(values)} max {np.max(values)} avg {np.average(values)}\")"],"execution_count":8,"outputs":[{"output_type":"display_data","data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAZkAAAFUCAYAAAD200GkAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAgAElEQVR4nO3deXhV9b3v8fc3CQlzICRASMIgRCmTIhGsQj0WnFuwilWs06ktta3Wc3tsj/fY2/bae0611rZPj/Yo1T51wqHcqtTZUquiMgSkDAokoISEIWEKc0KS7/0jW2/AkIRkr72y9/68noeHvfb+Ze3Pegj5ZK3fWmubuyMiIhKElLADiIhI4lLJiIhIYFQyIiISGJWMiIgERiUjIiKBUcmIiEhgVDIiIhIYlYyIiLSJmX3OzP5mZtVmVmpmX2nta1QyIiLSKjNLA54HXgCygNnA42Z2cotfpyv+RUSkNWY2BlgE9PJIcZjZa8Bid/9fx/s67cmIiEh7GTCmpQEqGRERaYt1QCXwAzPrYmbnA+cA3Vv6Ih0uExGRNjGzccB/0bj3UgxUATXufuNxv0YlIyIi7WFm7wKPuPuDxxujw2UiItImZjbOzLqaWXczuw3IBf7Y0teoZEREpK2uBbbSODczFTjP3Wta+gIdLhMRkcBoT0ZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkREQkMCoZEREJjEpGREQCo5IREZHAqGRERCQwKhkREQmMSkZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkREQkMCoZEREJTKglY2YXmtk6Mys1s9tbGHe5mbmZFcUyn4iIdExoJWNmqcD9wEXAKGCWmY1qZlwv4FZgcWwTiohIR4W5JzMRKHX3je5eCzwFzGhm3M+Au4HDsQwnIiIdlxbie+cBm5sslwOTmg4ws9OBAnd/0cx+cLwVmdlsYDZAjx49JowcOTKAuCLJZdmyZTvcPSfsHBLfwiyZFplZCvAr4IbWxrr7HGAOQFFRkRcXFwcbTiQJmNmmsDNI/AvzcFkFUNBkOT/y3Cd6AWOAv5vZx8CZwHxN/ouIxI8wS2YpUGhmw8wsHbgKmP/Ji+5e7e7Z7j7U3YcCi4Dp7q7dFBGROBFaybh7HXAz8CrwIfCMu68xszvNbHpYuUREJHpCnZNx95eAl4557sfHGftPscgkIiLRoyv+RUQkMCoZEREJjEpGREQCo5IREZHAqGRERCQwKhkREQmMSkZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkREQkMCoZEREJjEpGREQCo5IREZHAqGRERCQwKhkREQmMSkZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAhNqyZjZhWa2zsxKzez2Zl6/ycxWmdkKM1toZqPCyCkiIu2TFtYbm1kqcD9wHlAOLDWz+e7+QZNhc939gcj46cCvgAtjHlZiZlV5Nfe+vo7dB2pbHHfmSf343tRCemSE9i0sIm0Q5v/QiUCpu28EMLOngBnApyXj7nubjO8BeEwTSszsO3yEe19bz6PvfUxWjwzG5PU+7tiaIw08+NZG/vKPLfx0+mjOHz0wdkFF5ISEWTJ5wOYmy+XApGMHmdl3ge8D6cAXm1uRmc0GZgMMHjw46kElOO7OK6u38dO/rKFyXw3XTBrCbRecQma3Li1+3bJNu/j3P69m9mPLOG/UAO6cMZrczG4xSi0ibdXpJ/7d/X53Hw78G/Cj44yZ4+5F7l6Uk5MT24DSbpt3HeTrf1zKt59YTr8eGfz522fxs0vHtFowABOGZPHC9yZz+0Ujebukipn//R4799fEILWInIgwS6YCKGiynB957nieAi4NNJHExJH6Bh54cwPn/fpNFn+0ix9d8jnm33w24wf3PaH1dElN4aZzhvPMtz7Pjv01fHfuco7UNwSUWkTaI8ySWQoUmtkwM0sHrgLmNx1gZoVNFi8BSmKYTwKwbNMuvvxfC7nr5bVMKczh9e+fwzemnERaavu/Fcfl9+Hnl41l0cZd/MeLH0YxrYh0VGhzMu5eZ2Y3A68CqcAf3H2Nmd0JFLv7fOBmM5sGHAF2A9eHlVc6Zs/BWu5+ZR1PLiljUGZX5lw7IaoT9pedns+aLXt5eOFHjB7UmyuKClr/IhEJnLkn1glbRUVFXlxcHHYMiXB3nl+xhZ+98AF7Dh3h62cP5V+mnRzIqcd19Q1c94clFG/azTPf+jynFfSJ+nskEzNb5u5FYeeQ+NbpJ/4lfh0+Us//eHoF//L0CvKzujP/5rO545JRgV3bkpaawn1Xn07/Xhl867FiKvcdDuR9RKTtVDISiMq9h7lyziKeW7GFfz3vZP787bMYPSgz8PfN6pHOnGuLqD50hO88vpzaOp0IIBImlYxE3aryaqbf9w4l2/fxwDUTuGVqIakpFrP3HzWoN/fMPJXiTbv5339ZE7P3FZHP0j05JKpeWLmF2/70D/r1yGDeTWcxatDxr9wP0pdPHcSaLXt54M0NjB6UydWTdJGuSBhUMhIVDQ3ObxaU8NsFJRQN6csD104gu2dGqJl+cMEpfLh1Lz+Zv5pTBvZkwpCsUPOIJCMdLpOouPOFD/jtghJmTsjniW9OCr1gAFJTjN9eNZ68Pt347hPva35GJAQqGemwZ5Zu5o/vfszXzx7GPTPHkZGWGnakT2V278JPpo9m297DvPbBtrDjiCQdlYx0yPKy3fzoudVMKczm3y8eiVnsJvjb6guFOeT16cbcxWVhRxFJOioZabfKvYe56bFlDMzsyn/NGt+hW8MEKTXFmDWxgHc37OSjHQfCjiOSVDrnTwXp9Grq6vnW48vYd7iOOddNoE/39LAjteirRQWkpRhPLtHejEgsqWSkXX79egnvl+3h3q+eysiB4ZymfCL69+7KtM8NYN6ycmrq6sOOI5I0VDJywg7V1jN38Sa+NC6Xi8fmhh2nza6eNJhdB2p5ZbVOABCJFZWMnLAXVm5h7+E6rjlzSNhRTsjkEdkMzuquEwBEYkglIyds7pIyhuf0YNKw+Lq4MSXFmDVxMIs/2kVp5f6w44gkBZWMnJAPt+7l/bI9zJo4uFOertyaK4ry6ZKqEwBEYkUlIyfk929vJD0thZkT8sOO0i7ZPTM4f/RA5i0r5/ARnQAgEjSVjLTZ00vL+PPyCr5+9rBOf8pyS742cTDVh47w8uqtYUcRSXgqGWmT5WW7+V/PrWFKYTa3nX9y2HE65PPD+zEsuwdPLNIhM5GgqWSkVfFyZX9bmTXeAaB4027Wb98XdhyRhBbfPy0kcDV19dwUR1f2t9XMCQWkp6bodGaRgKlkpEV3vbyW5XF0ZX9bZfVI58IxA/m/y8s5VKsTAESCopKR46pvcOYtK+fS0wbF1ZX9bXX1pMHsO1zHCyu3hB1FJGGpZOS4VpbvYd/hOqZ+bkDYUQIxaVgWw3N6MFfXzIgERiUjx7WwZAcAZ4/IDjlJMBpPABjM+2V7+HDr3rDjiCSkUEvGzC40s3VmVmpmtzfz+vfN7AMzW2lmC8wsvm6WFecWlu5g9KDeZPVIjMn+5syckE96mk4AEAlKaCVjZqnA/cBFwChglpmNOmbY+0CRu48D5gG/iG3K5HWgpo7lZbuZXJiYezGf6NM9nUvG5vLs+xUcrK0LO45IwglzT2YiUOruG929FngKmNF0gLu/4e4HI4uLgPi8l0kcWvLRLo7UO5MT9FBZUzNOG8T+mjreL9sTdhSRhBNmyeQBm5ssl0eeO54bgZebe8HMZptZsZkVV1VVRTFi8lpYuoP0tBTOGBpfd1puj1Pz+wCwqqI65CQiiScuJv7N7BqgCLinudfdfY67F7l7UU5OTmzDJaiFJTs4Y2hfunZJDTtK4Pr2SKcgqxurylUyItEWZslUAAVNlvMjzx3FzKYBdwDT3b0mRtmSWuXew6zbvo/JI5KnsMfmZWpPRiQAYZbMUqDQzIaZWTpwFTC/6QAzGw88SGPBVIaQMSm9s6Hx1OUpCT7p39TYvD6U7TrInoO1YUcRSSihlYy71wE3A68CHwLPuPsaM7vTzKZHht0D9AT+ZGYrzGz+cVYnUfR2yQ6yeqQzKjdxbiPTmrF5mQCsrtD1MiLRlBbmm7v7S8BLxzz34yaPp8U8VJJzdxaW7OCs4f1ISYm/T75sr09KZmXFnoQ/bVskluJi4l9ip6RyP5X7apLi1OWmMrt3YXBWd1ZrXkYkqlQycpRPbiWTjL/Nj83PZKXOMBOJKpWMHGVh6Q6GZfcgv2/3sKPE3Ni8TMp3H2L3AU3+i0SLSkaOsm7bPk4r6BN2jFCMGdQ4L/OBbpYpEjUqGTmKu5OWRBP+TRUO6AlAaeX+kJOIJA6VjEhE/14Z9MpIU8mIRJFKRiTCzBjev6dKRiSKVDIiTRT270lplUpGJFpUMiJNjOjfk6p9NVQfPBJ2FJGEoJIRaWJE/8jkf9W+kJOIJAaVjHxGg4edIDyflozmZUSiQiUjR8nP6s767cn7W3x+3+6kp6WoZESiRCUjR5k8IpvVW6qT9qr31BRjeI7OMBOJFpWMHGVyYTbu//8zZZLRCJ1hJhI1Khk5yri8THp1Tfv0RpnJaEROT8p3H+JQbX3YUUTinkpGjpKWmsLnT+rH2yU7cE/OMwBG9O+JO2zQ3oxIh6lk5DOmFGZTsecQm3YeDDtKKHJ6ZQCwR9fKiHSYSkY+Y3JhDgBvlybnITNLzvuDigRCJSOfMbRfd/L6dGNhSVXYUUQkzqlk5DPMjMkjsnl3w07qk/nKTBHpMJWMNGtyYTb7DtexsnxP2FFEJI6pZKRZZw3vB5DUpzKLSMepZKRZ/XpmMHpQbxYm6eS/iESHSkaOa3JhNsvLdnOgpi7sKCISp0ItGTO70MzWmVmpmd3ezOtfMLPlZlZnZjPDyJjMJo/I5ki9s+SjXWFHEZE4FVrJmFkqcD9wETAKmGVmo44ZVgbcAMyNbToBOGNoFulpKTpkJiLtlhbie08ESt19I4CZPQXMAD74ZIC7fxx5rSGMgMmua5dUJg7N0uS/iLRbmIfL8oDNTZbLI8+dMDObbWbFZlZcVaULCKPp7BHZrNu+j8q9h8OOIiJxKCEm/t19jrsXuXtRTk5O2HESypTCbAAdMhORdgmzZCqAgibL+ZHnpBMZldubvt27qGREpF3CLJmlQKGZDTOzdOAqYH6IeaQZKSnGWSOyWZjEt/4XkfYLrWTcvQ64GXgV+BB4xt3XmNmdZjYdwMzOMLNy4ArgQTNbE1beZDZlRDaV+2oo0UcSi8gJCvPsMtz9JeClY577cZPHS2k8jCYhmhyZl3m7ZAcnD+gVchoRiScJMfEvwcrv252h/brz8qqtNOiuzCJyAlQy0ibfmHISxZt285sFJWFHEZE4opKRNvnapMFcMSGf3y4o4ZXV28KOIyJxQiUjbWJm/OzSMZxa0Id/fWYF67fvCzuSiMQBlYy0WdcuqTx4zQS6pacx+9Fiqg8eCTuSiHRyKhk5IQMzu/LANadTsecQ335iGfsOJ17R6HIgkehRycgJKxqaxd2Xj2PJR7u47HfvUrbzYNiRoqp8d+P29O+dEXISkfinkpF2uez0fB69cSJV+2uYfv9C3tuwM+xIUbOyvJpuXVIZntMz7CgicU8lI+121vBsnvvO2WT3zODahxczd3FZ2JGiYnVFNaMH9SY1xcKOIhL3VDLSIUOze/Dn75zF5MJs/v3ZVfx0/hrq6uP343/qG5w1W/YyJi8z7CgiCUElIx3Wu2sXHr7+DL45ZRh/fPdjrvvDEjbvis95mg1V+zl0pJ5x+SoZkWhQyUhUpKYYd1wyintmjmPF5j2c/+u3ePDNDRyJs72aleXVAIzVnoxIVIR6g0xJPFcUFXDWiGx+On8NP395Lc++X8F/fGUME4ZkRf29Dh+pp3z3oaOey0hLoSCre7vXubqimu7pqZykSX+RqFDJSNTl9enG768r4tU12/jp/DVc/t/vMXFYFteeOYQLRg8kPa3jO9C7D9Ry6e/eYdMxp0+PyevNC7dMafd6V5bv0aS/SBSpZCQwF4weyNkjsnli0SYeX7yJW558n+yeGcyaWMCsiYMZ1Kdbu9ZbV9/AzU8uZ+uew/zHV8bQq2uXT1/L7Nalha9sfb0fbN3L1ROHtHsdInI0lYwEqmdGGt86ZzjfnHISb5ZU8fh7m7jvjVLuf6OUc07OYUDvrp+OTU0xZk7IZ/zgvp8+5+48vPAjSpt8YFrFnkO8U7qTX8wcx1eLCoiW0qr9HD7SwNj83lFbp0iyU8lITKSkGOee0p9zT+nP5l0HeXJJGS+u2soHW/d+Omb/4TrmLinja5MG84MLRpLZrQtz3trIz19eS3bPDFKbHGX73tTCqBYMaNJfJAgqGYm5gqzu/PDCkfzwwpFHPb+/po57X1vHI+9+zKtrtnNlUQG/+3spl4zN5b6rx2MW7DzJ6opqeqSnclK2Jv1FokWnMEun0TMjjZ98eTTzb55MbmZX7nujlJMH9OKeK8YFXjDQuCczOi+TFE36i0SN9mSk0xmTl8mz3zmbV9dso2hIX7qnB/9teqS+gQ+37uWaMzXpLxJNKhnplFJTjIvH5sbs/Uq276emrkFX+otEmQ6XidA4HwPonmUiUaaSEQFWVuyhZ0Yaw/r1CDuKSEIJtWTM7EIzW2dmpWZ2ezOvZ5jZ05HXF5vZ0NinlGSwqmIvY/J6a9JfJMpCKxkzSwXuBy4CRgGzzGzUMcNuBHa7+wjg18DdsU0pyeCTSX9dHyMSfa2WjJndYmZ9WxvXDhOBUnff6O61wFPAjGPGzAAeiTyeB0y1WJzLKkll/fZ91NY1MDa/T9hRRBJOW/ZkBgBLzeyZyOGtaP2QzwM2N1kujzzX7Bh3rwOqgX7HrsjMZptZsZkVV1VVRSmeJItVutJfJDCtloy7/wgoBB4GbgBKzOw/zWx4wNnazN3nuHuRuxfl5OSEHUfizKqKanp1TWNIBz4iQESa16Y5GXd3YFvkTx3QF5hnZr/owHtXAE1vPpUfea7ZMWaWBmQCOzvwniKfsaqimjGDdKW/SBDaMidzq5ktA34BvAOMdfdvAxOAyzvw3kuBQjMbZmbpwFXA/GPGzAeujzyeCfwtUngiUVFb18Darft0EaZIQNpyxX8WcJm7b2r6pLs3mNmX2vvG7l5nZjcDrwKpwB/cfY2Z3QkUu/t8Gg/RPWZmpcAuGotIJGrWb99HbX0DY1UyIoFotWTc/SctvPZhR97c3V8CXjrmuR83eXwYuKIj7yHSklUVmvQXCZKu+JektrK8mt5d0xisSX+RQKhkJKmtrqhmbH5mTD5KQCQZqWQkadXU1bN2217G5ukiTJGgqGQkaa3ftp8j9a4zy0QCpJKRpLX4o8ZLrjTpLxIclYwkJXfnySVljB/chwJN+osERiUjSWnJR7vYUHWAqycODjuKSEJTyUhSemJxGb26pvGlcYPCjiKS0FQyknR2HajlldXbuPz0fLqlp4YdRyShqWQk6cxbtpna+gaunqRDZSJBU8lIUmmc8N9M0ZC+nDygV9hxRBKeSkaSynsbdvLRjgPaixGJEZWMJJUnlpSR2a0LF4/NDTuKSFJQyUjS2LG/htfWbGPmhHy6dtGEv0gsqGQkaTy/YgtH6p1ZujZGJGZUMpI01lRUM7B3V0b07xl2FJGkoZKRpFFatV8FIxJjKhlJCu7OhkqVjEisqWQkKWytPsyB2nqVjEiMqWQkKZRU7gdQyYjEmEpGkkKpSkYkFCoZSQqllfvp070L/Xqkhx1FJKmoZCQpbKjcT2H/nphZ2FFEkopKRpKCTl8WCUcoJWNmWWb2upmVRP7ue5xxr5jZHjN7IdYZJXHs3F/DrgO1DM9RyYjEWlh7MrcDC9y9EFgQWW7OPcC1MUslCUmT/iLhCatkZgCPRB4/Alza3CB3XwDsi1UoSUylVY0lU6jPjxGJubBKZoC7b4083gYM6MjKzGy2mRWbWXFVVVXH00lCWbZpN70y0sjt3TXsKCJJJy2oFZvZX4GBzbx0R9MFd3cz8468l7vPAeYAFBUVdWhdkliqDx3hpVVb+cr4fFJSdGaZSKwFVjLuPu14r5nZdjPLdfetZpYLVAaVQ5Lbs8vLOXykga/pkzBFQhHW4bL5wPWRx9cDz4eUQxKYuzN3SRnj8jMZk5cZdhyRpBRWydwFnGdmJcC0yDJmVmRmD30yyMzeBv4ETDWzcjO7IJS0EpeWbdrN+u37tRcjEqLADpe1xN13AlObeb4Y+EaT5SmxzCWJZe7iMnplpPHlUweFHUUkaemKf0lIew7W8sKqrVw6Po/u6aH8LiUiqGQkQc1bVk5tXQNX61CZSKhUMpJwPpnwHz+4D5/L7R12HJGkppKRhLP4o11srDrA1RO1FyMSNpWMJJw/vvMxvbqm8aVxmvAXCZtKRhLKis17eGXNNv757GF0S08NO45I0lPJSMJwd+5+eS39eqQz+wsnhR1HRFDJSAJ5q2QH723cyS1fHEHPDJ22LNIZqGQkITQ0OHe9vJaCrG5cPWlI2HFEJEIlIwnhLyu38OHWvdx2/imkp+nbWqSz0P9GiXu1dQ388rV1jMrtzZd1RplIp6KSSXK/f2sjSz/eFXaMDpm7eBObdx3i3y4aqc+MEelkVDJJ7q5X1vLmuvj9NNH6BmfOWxuZOCyLLxRmhx1HRI6hkpG49vd1lWypPsw/nzUUM+3FiHQ2KpkkVn3wCA3uxPPP5rmLy8jplcG0UQPCjiIizVDJJKn6BueWp94nLcU4L05/QG/Zc4g31lXy1aJ8uqTqW1mkM9IVa0nqnlfX8db6Kn5+2VjG5fcJO067PLV0Mw5cdYZuhCnSWenXvyRUW9fAnLc2cOlpg5gVp3cqrqtv4OmlZXyhMIeCrO5hxxGR41DJJKEGdxocThkYv5+18re1lWzfW6MPJRPp5HS4LIHtPXyE2Y8Ws/dQ3VHPN7iHlCh65i4pY0DvDKaO7B92FBFpgUomgXVJSWHzrkNU7DnEhCF96ds9/dPXhvbrwbkjc0JM136bdx3kzfVV3HLuCNI04S/SqalkEli39FQevHYCMx94l1Qzfve10xPivl5PLS3DgCvjdD5JJJnE/08cadGYvEzuvnwcSz7exfT7FrJsU3zfQmZ/TR1PLtnMuaf0J69Pt7DjiEgrQikZM8sys9fNrCTyd99mxpxmZu+Z2RozW2lmV4aRNRHMOC2Ph64rYu+hI1z+3+/xP/+8ij0Ha8OO1S6/f2sjuw7UcsvUwrCjiEgbhLUnczuwwN0LgQWR5WMdBK5z99HAhcBvzCw+L+joBKaNGsDr3z+Hb04ZxjPFm5l675ss3rgz7FgnpGpfDQ+9vZGLxw7ktAJ9K4jEg7BKZgbwSOTxI8Clxw5w9/XuXhJ5vAWoBOJzprqT6JGRxh2XjGL+zWeT2b0LNz2+jM27DoYdq83u+1sJh+sauO38U8KOIiJtFFbJDHD3rZHH24AW72tiZhOBdGBD0MGSwehBmfzh+jOob3BmP7aMQ7X1YUdqVdnOg8xdUsaVZxRwUk7PsOOISBsFVjJm9lczW93MnxlNx7m7A8e9cMPMcoHHgH9294bjjJltZsVmVlxVFb+3rY+lodk9+O2s8azdtpcfzPsH3smvnbn39XWkphi3ai5GJK4Edgqzu0873mtmtt3Mct19a6REKo8zrjfwInCHuy9q4b3mAHMAioqKOvdPy07kn07pzw8vGMndr6xlTF4mN50zPOxIzVpdUc3zK7bw3XOHM6B317DjiMgJCOtw2Xzg+sjj64Hnjx1gZunAs8Cj7j4vhtmSyk3nnMQl43K5+5W1PPd+Rafbo6mta+A/X/qQPt278K1OWoIicnxhlcxdwHlmVgJMiyxjZkVm9lBkzFeBLwA3mNmKyJ/TwombuMyMe2aO47SCPvzL0yu48ZHiTnMywK4DtVz78GLe3bCTH14wkt5du4QdSUROkHW231w7qqioyIuLi8OOEXfq6hv447sf86vX1+MOt04r5MbJw0L7nJb12/dx4yNL2b63hl9cPo5Lx+eFkiOZmdkydy8KO4fEN5WMHKVizyF+On8Nr3+wnbw+3bh60mCuPKOA7J4ZMcuw4MPt3PrUCrqlpzLn2gmMH/yZa3UlBlQyEg0qGWnWG2sreWjhRt4p3UmXVOPisblce+YQJgzpiwX0ec3uzpy3NnLXK2sZMyiTOddNIDdTt44Ji0pGokE3yJRmnTuyP+eO7E9p5X6eWLyJecvKeX7FFkYO7MU1Zw7h0vF59MyI3rdP+e6D/PLVdTy3YguXjMvllzNPpVt6atTWLyLh0J6MtMnB2jrmr9jCo+9t4oOte+mZkcZlp+dxzZlDOHlAr3ats6HBeaukiscXbWLB2koMuHXqyXxv6ojA9pak7bQnI9GgkpET4u4sL9vD44s28eLKrdTWN3DmSVlce+ZQzh89oE0nCuw+UMuflm3m8UVllO06SHbPDGZNLOCqiYN1Z+VORCUj0aCSkXbbub+GPy0r5/FFmyjffYi0FCMlpfU9kCP1DbjDxGFZXHvmEC4YPTAhPucm0ahkJBpUMtJh9Q3Om+srWfrxbtry7ZSRlsLFY3M5ZWD7DrNJbKhkJBo08S8dlppifHHkAL44ssX7nIpIEtIxChERCYxKRkREAqOSERGRwKhkREQkMCoZEREJjEpGREQCo5IREZHAqGRERCQwKhkREQmMSkZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkREQkMKGUjJllmdnrZlYS+btvM2OGmNlyM1thZmvM7KYwsoqISPuFtSdzO7DA3QuBBZHlY20FPu/upwGTgNvNbFAMM4qISAeFVTIzgEcijx8BLj12gLvXuntNZDEDHdoTEYk7Yf3gHuDuWyOPtwHNfji8mRWY2UpgM3C3u285zrjZZlZsZsVVVVXBJBYRkROWFtSKzeyvwMBmXrqj6YK7u5l5c+tw983AuMhhsufMbJ67b29m3BxgDkBRUVGz6xIRkdgLrGTcfdrxXjOz7WaW6+5bzSwXqGxlXVvMbDUwBZgX5agiIhKQsA6XzQeujzy+HibW76wAAAWcSURBVHj+2AFmlm9m3SKP+wKTgXUxSygiIh0WVsncBZxnZiXAtMgyZlZkZg9FxnwOWGxm/wDeBH7p7qtCSSsiIu0S2OGylrj7TmBqM88XA9+IPH4dGBfjaCIiEkU6LVhERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkREQkMCoZEREJjEpGREQCo5IREZHAqGRERCQwKhkREQmMSkZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkREQkMCoZEREJjEpGREQCo5IREZHAqGRERCQwKhkREQlMKCVjZllm9rqZlUT+7tvC2N5mVm5m98Uyo4iIdFxYezK3AwvcvRBYEFk+np8Bb8UklYiIRFVYJTMDeCTy+BHg0uYGmdkEYADwWoxyiYhIFKWF9L4D3H1r5PE2GovkKGaWAtwLXANMa2llZjYbmB1ZrDGz1VHM2hlkAzvCDhFFibY9kJjbdErYAST+BVYyZvZXYGAzL93RdMHd3cy8mXHfAV5y93Iza/G93H0OMCfyvsXuXtS+1J1Tom1Tom0PJO42hZ1B4l9gJePux937MLPtZpbr7lvNLBeobGbY54EpZvYdoCeQbmb73b2l+RsREelEwjpcNh+4Hrgr8vfzxw5w96998tjMbgCKVDAiIvElrIn/u4DzzKyExvmWuwDMrMjMHurguud0NFwnlGjblGjbA9omkWaZe3PTISIiIh2nK/5FRCQwKhkREQlM3JdMIt6ipi3bZGanmdl7ZrbGzFaa2ZVhZG2JmV1oZuvMrNTMPnPShpllmNnTkdcXm9nQ2Kc8MW3Ypu+b2QeRf5MFZjYkjJxt1dr2NBl3uZm5mSXUadoSvLgvGRLzFjVt2aaDwHXuPhq4EPiNmfWJYcYWmVkqcD9wETAKmGVmo44ZdiOw291HAL8G7o5tyhPTxm16n8YzIccB84BfxDZl27VxezCzXsCtwOLYJpREkAglk4i3qGl1m9x9vbuXRB5vofFao5yYJWzdRKDU3Te6ey3wFI3b1VTT7ZwHTLXWrrwNV6vb5O5vuPvByOIiID/GGU9EW/6NoPGXs7uBw7EMJ4khEUrmRG5Rc1ssg3VAq9vUlJlNBNKBDUEHOwF5wOYmy+WR55od4+51QDXQLybp2qct29TUjcDLgSbqmFa3x8xOBwrc/cVYBpPEEdbFmCcklreoiZUobNMn68kFHgOud/eG6KaU9jKza4Ai4Jyws7RX5JezXwE3hBxF4lhclEwi3qImCtuEmfUGXgTucPdFAUVtrwqgoMlyfuS55saUm1kakAnsjE28dmnLNmFm02j8ZeEcd6+JUbb2aG17egFjgL9HfjkbCMw3s+nurvuaSZskwuGyT25RAy3cosbdB7v7UBoPmT3ayW9R0+o2mVk68CyN2zIvhtnaailQaGbDIlmvonG7mmq6nTOBv3nnvjq41W0ys/HAg8B0d2/2l4NOpMXtcfdqd89296GR/zuLaNwuFYy0WSKUTJC3qAlLW7bpq8AXgBvMbEXkz2nhxP2syBzLzcCrwIfAM+6+xszuNLPpkWEPA/3MrBT4Pi2fGRi6Nm7TPTTuLf8p8m9ybLF2Gm3cHpEO0W1lREQkMImwJyMiIp2USkZERAKjkhERkcCoZEREJDAqGRERCYxKRkREAqOSERGRwKhkJGbM7IzI56x0NbMekc/CGRN2LhEJji7GlJgys/8DdAW6AeXu/vOQI4lIgFQyElORe2QtpfGzSc5y9/qQI4lIgHS4TGKtH4339upF4x6NiCQw7clITEVuGPkUMAzIdfebQ44kIgGKi8+TkcRgZtcBR9x9buTz5d81sy+6+9/CziYiwdCejIiIBEZzMiIiEhiVjIiIBEYlIyIigVHJiIhIYFQyIiISGJWMiIgERiUjIiKB+X8z34BsjWwClwAAAABJRU5ErkJggg==\n","text/plain":["
"]},"metadata":{"needs_background":"light"}},{"output_type":"stream","name":"stdout","text":["This stroke: 89\n","All strokes: min 32 max 145 avg 94.526\n"]}]},{"cell_type":"code","metadata":{"id":"3FVPj-eqjvoB","executionInfo":{"status":"ok","timestamp":1638746658017,"user_tz":480,"elapsed":192,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["import math\n","import numpy as np\n","import PIL\n","\n","FIXED_POINT = 4096\n","\n","def mul_fp(a, b):\n"," return (a * b) // FIXED_POINT\n","\n","def div_fp(a, b):\n"," if b == 0:\n"," b = 1\n"," return (a * FIXED_POINT) // b\n","\n","def float_to_fp(a):\n"," return math.floor(a * FIXED_POINT)\n","\n","def norm_to_coord_fp(a, range_fp, half_size_fp):\n"," a_fp = float_to_fp(a)\n"," norm_fp = div_fp(a_fp, range_fp)\n"," return mul_fp(norm_fp, half_size_fp) + half_size_fp\n","\n","def round_fp_to_int(a):\n"," return math.floor((a + (FIXED_POINT / 2)) / FIXED_POINT)\n","\n","def gate(a, min, max):\n"," if a < min:\n"," return min\n"," elif a > max:\n"," return max\n"," else:\n"," return a\n","\n","def rasterize_stroke(stroke_points, x_range, y_range, width, height):\n"," num_channels = 3\n"," buffer_byte_count = height * width * num_channels\n"," buffer = bytearray(buffer_byte_count)\n","\n"," width_fp = width * FIXED_POINT\n"," height_fp = height * FIXED_POINT\n"," half_width_fp = width_fp / 2\n"," half_height_fp = height_fp / 2\n"," x_range_fp = float_to_fp(x_range)\n"," y_range_fp = float_to_fp(y_range)\n","\n"," t_inc_fp = FIXED_POINT // len(stroke_points)\n","\n"," one_half_fp = (FIXED_POINT / 2)\n","\n"," for point_index in range(len(stroke_points) - 1):\n"," start_point = stroke_points[point_index]\n"," end_point = stroke_points[point_index + 1]\n"," start_x_fp = norm_to_coord_fp(start_point[\"x\"], x_range_fp, half_width_fp)\n"," start_y_fp = norm_to_coord_fp(-start_point[\"y\"], y_range_fp, half_height_fp)\n"," end_x_fp = norm_to_coord_fp(end_point[\"x\"], x_range_fp, half_width_fp)\n"," end_y_fp = norm_to_coord_fp(-end_point[\"y\"], y_range_fp, half_height_fp)\n"," delta_x_fp = end_x_fp - start_x_fp\n"," delta_y_fp = end_y_fp - start_y_fp\n","\n"," t_fp = point_index * t_inc_fp\n"," if t_fp < one_half_fp:\n"," local_t_fp = div_fp(t_fp, one_half_fp)\n"," one_minus_t_fp = FIXED_POINT - local_t_fp\n"," red = round_fp_to_int(one_minus_t_fp * 255)\n"," green = round_fp_to_int(local_t_fp * 255)\n"," blue = 0\n"," else:\n"," local_t_fp = div_fp(t_fp - one_half_fp, one_half_fp)\n"," one_minus_t_fp = FIXED_POINT - local_t_fp\n"," red = 0\n"," green = round_fp_to_int(one_minus_t_fp * 255)\n"," blue = round_fp_to_int(local_t_fp * 255)\n"," red = gate(red, 0, 255)\n"," green = gate(green, 0, 255)\n"," blue = gate(blue, 0, 255)\n","\n"," if abs(delta_x_fp) > abs(delta_y_fp):\n"," line_length = abs(round_fp_to_int(delta_x_fp))\n"," if delta_x_fp > 0:\n"," x_inc_fp = 1 * FIXED_POINT\n"," y_inc_fp = div_fp(delta_y_fp, delta_x_fp)\n"," else:\n"," x_inc_fp = -1 * FIXED_POINT\n"," y_inc_fp = -div_fp(delta_y_fp, delta_x_fp)\n"," else:\n"," line_length = abs(round_fp_to_int(delta_y_fp))\n"," if delta_y_fp > 0:\n"," y_inc_fp = 1 * FIXED_POINT\n"," x_inc_fp = div_fp(delta_x_fp, delta_y_fp)\n"," else:\n"," y_inc_fp = -1 * FIXED_POINT\n"," x_inc_fp = -div_fp(delta_x_fp, delta_y_fp)\n"," for i in range(line_length + 1):\n"," x_fp = start_x_fp + (i * x_inc_fp)\n"," y_fp = start_y_fp + (i * y_inc_fp)\n"," x = round_fp_to_int(x_fp)\n"," y = round_fp_to_int(y_fp)\n"," if (x < 0) or (x >= width) or (y < 0) or (y >= height):\n"," continue\n"," buffer_index = (y * width * num_channels) + (x * num_channels)\n"," buffer[buffer_index + 0] = red\n"," buffer[buffer_index + 1] = green\n"," buffer[buffer_index + 2] = blue\n"," \n"," np_buffer = np.frombuffer(buffer, dtype=np.uint8).reshape(height, width, num_channels)\n","\n"," return np_buffer"],"execution_count":9,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":529},"id":"sOaxOIjRskJg","executionInfo":{"status":"ok","timestamp":1638746717413,"user_tz":480,"elapsed":165,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"9f3e55ad-2c1e-4441-cdc8-fabc272e3b50"},"source":["raster = rasterize_stroke(shuffled_strokes[0][\"strokePoints\"], 0.5, 0.5, 32, 32)\n","img = PIL.Image.fromarray(raster).resize((512, 512), PIL.Image.NEAREST)\n","display(img)"],"execution_count":10,"outputs":[{"output_type":"display_data","data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAIAAAB7GkOtAAAHHUlEQVR4nO3dIWydZRSA4ZatDUuLRJERDJjN4BDMgIYEiWdmKAwGi8FhhmEaTZgGAwYDZhgQJDSZwtECuWUJimRiITlp7/3v3fs8+tzc494c8397ewAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAxf7SC8AueenX2fzp8Wz+cDWbf/jCbB4e98zSCwCwDAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgKirSy8AS7rxYDa/Op/N//78bP7an7N5uAgXAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQBA1P7SC8D/ef3b2fz5wWz++9dm89vmyj+z+UdeAOExLgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgChfB2erHa5m89/dWs8e2+rR3pXxL+A/LgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgCjvAbBRb301m7//5nr2eGpcHX7f/69nZ/PX/p7Ns1NcAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUd4DYKMOV0tvELc6HP7AewBPMxcAQJQAAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECU9wDYqOPTpTeIG78HwNPMBQAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAEOU9ADbq6Gw2/97ns/l7t2fzOd4D4DEuAIAoAQCIEgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKAEAiBIAgCgBAIgSAIAoAQCIEgCAKO8BsFGfvT+bv3N3PXtknR8svQFbxAUAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABC1v/QCcJk+/GQ2f3A+mz8+nc0fnc3mr5/M5t/5cja/9/PLs/lXfhn+AbvEBQAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAEOU9ACh5cGM2f/On9ezBVnABAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECUAABEXV16AeACfnh1Nn/zx/XswU5yAQBECQBAlAAARAkAQJQAAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQBAlAAARHkPAHbZ+cHSG7DDXAAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFHeA4BdtjpcegN2mAsAIEoAAKIEACBKAACiBAAgSgAAogQAIEoAAKIEACBKAACiBAAgSgAAogQAIEoAAKIEACDKewCwTb5+YzZ/65v17EGCCwAgSgAAogQAIEoAAKIEACBKAACiBAAgSgAAogQAIEoAAKIEACBKAACiBAAgSgAAogQAIMp7AGzW8R+z+dPn1rPHpky/739+sJ494AlcAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUd4D4GKu/zabP9nx7/tPnR3N5t++v5494AlcAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUQIAECUAAFECABAlAABRAgAQJQAAUd4D4GJOXpzNf/zRbP7obDb/waez+akv3p3Nr1br2QMugQsAIEoAAKIEACBKAACiBAAgSgAAogQAIEoAAKIEACBKAACiBAAgSgAAogQAIEoAAKIEACBqf+kF4FLdvTObPxx+r//2vdk8bDEXAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQBAlAAARAkAQJQAAEQJAECUAABECQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDQv3ZkRy9r0+kjAAAAAElFTkSuQmCC\n","text/plain":[""]},"metadata":{}}]},{"cell_type":"code","metadata":{"id":"o-FOVdFpgkdf","executionInfo":{"status":"ok","timestamp":1638746921132,"user_tz":480,"elapsed":150,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["from pathlib import Path\n","import shutil\n","\n","X_RANGE = 0.6\n","Y_RANGE = 0.6\n","\n","def ensure_empty_dir(dirname):\n"," dirpath = Path(dirname)\n"," if dirpath.exists() and dirpath.is_dir():\n"," shutil.rmtree(dirpath)\n"," dirpath.mkdir()\n","\n","def augment_points(points, move_range, scale_range, rotate_range):\n"," move_x = np.random.uniform(low=-move_range, high=move_range)\n"," move_y = np.random.uniform(low=-move_range, high=move_range)\n"," scale = np.random.uniform(low=1.0-scale_range, high=1.0+scale_range)\n"," rotate = np.random.uniform(low=-rotate_range, high=rotate_range)\n","\n"," x_axis_x = math.cos(rotate) * scale\n"," x_axis_y = math.sin(rotate) * scale\n","\n"," y_axis_x = -math.sin(rotate) * scale\n"," y_axis_y = math.cos(rotate) * scale\n","\n"," new_points = []\n"," for point in points:\n"," old_x = point[\"x\"]\n"," old_y = point[\"y\"]\n"," new_x = (x_axis_x * old_x) + (x_axis_y * old_y) + move_x\n"," new_y = (y_axis_x * old_x) + (y_axis_y * old_y) + move_y\n"," new_points.append({\"x\": new_x, \"y\": new_y})\n","\n"," return new_points\n","\n","def save_strokes_as_images(strokes, root_folder, width, height, augment_count):\n"," ensure_empty_dir(root_folder)\n"," labels = set()\n"," for stroke in strokes:\n"," labels.add(stroke[\"label\"].lower())\n"," for label in labels:\n"," label_path = Path(root_folder, label)\n"," ensure_empty_dir(label_path)\n","\n"," label_counts = {}\n"," for stroke in strokes:\n"," points = stroke[\"strokePoints\"]\n"," label = stroke[\"label\"].lower()\n"," if label == \"\":\n"," raise Exception(\"Missing label for %s:%d\" % (stroke[\"filename\"], stroke[\"index\"]))\n"," if label not in label_counts:\n"," label_counts[label] = 0\n"," label_count = label_counts[label]\n"," label_counts[label] += 1\n"," raster = rasterize_stroke(points, X_RANGE, Y_RANGE, width, height)\n"," image = PIL.Image.fromarray(raster)\n"," image.save(Path(root_folder, label, str(label_count) + \".png\"))\n"," for i in range(augment_count):\n"," # Note: no move augmentation as the stroke should be more or less\n"," # centered within the raster\n"," augmented_points = augment_points(points, 0.0, 0.1, 0.3)\n"," raster = rasterize_stroke(augmented_points, X_RANGE, Y_RANGE, width, height)\n"," image = PIL.Image.fromarray(raster)\n"," image.save(Path(root_folder, label, str(label_count) + \"_a\" + str(i) + \".png\"))\n"],"execution_count":11,"outputs":[]},{"cell_type":"code","metadata":{"id":"2cmmhBwW9d_p","executionInfo":{"status":"ok","timestamp":1638747505532,"user_tz":480,"elapsed":13446,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["IMAGE_WIDTH = 32\n","IMAGE_HEIGHT = 32\n","\n","shuffled_strokes = list(strokes)\n","np.random.shuffle(shuffled_strokes)\n","\n","test_percentage = 10\n","validation_percentage = 10\n","train_percentage = 100 - (test_percentage + validation_percentage)\n","\n","test_count = math.floor((len(shuffled_strokes) * test_percentage) / 100)\n","validation_count = math.floor((len(shuffled_strokes) * validation_percentage) / 100)\n","test_strokes = shuffled_strokes[0:test_count]\n","validation_strokes = shuffled_strokes[test_count:(test_count + validation_count)]\n","train_strokes = shuffled_strokes[(test_count + validation_count):]\n","\n","save_strokes_as_images(test_strokes, \"test\", IMAGE_WIDTH, IMAGE_HEIGHT, 10)\n","save_strokes_as_images(validation_strokes, \"validation\", IMAGE_WIDTH, IMAGE_HEIGHT, 0)\n","save_strokes_as_images(train_strokes, \"train\", IMAGE_WIDTH, IMAGE_HEIGHT, 10)"],"execution_count":12,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"9-Ttfz7LlPil","executionInfo":{"status":"ok","timestamp":1638747530290,"user_tz":480,"elapsed":3475,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"2e9daa0f-acea-4c5e-c4c3-89a7060f388a"},"source":["\n","import tensorflow as tf\n","from tensorflow import keras\n","from tensorflow.keras.utils import image_dataset_from_directory\n","\n","validation_ds = image_dataset_from_directory(\n"," directory='validation',\n"," labels='inferred',\n"," label_mode='categorical',\n"," batch_size=32,\n"," image_size=(IMAGE_WIDTH, IMAGE_HEIGHT)).prefetch(buffer_size=32)\n","\n","train_ds = image_dataset_from_directory(\n"," directory='train',\n"," labels='inferred',\n"," label_mode='categorical',\n"," batch_size=32,\n"," image_size=(IMAGE_WIDTH, IMAGE_HEIGHT)).prefetch(buffer_size=32)\n"],"execution_count":13,"outputs":[{"output_type":"stream","name":"stdout","text":["Found 100 files belonging to 10 classes.\n","Found 8800 files belonging to 10 classes.\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":591},"id":"Q_vUMVmQn400","executionInfo":{"status":"ok","timestamp":1638747597760,"user_tz":480,"elapsed":1017,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"07159ba4-ee1b-4364-8776-3726db2e0595"},"source":["import matplotlib.pyplot as plt\n","\n","plt.figure(figsize=(10, 10))\n","for images, labels in train_ds.take(1):\n"," for i in range(9):\n"," ax = plt.subplot(3, 3, i + 1)\n"," ax.set_title(f\"{np.argmax(labels[i])}\")\n"," plt.imshow(images[i].numpy().astype(\"uint8\"))\n"," plt.axis(\"off\")"],"execution_count":15,"outputs":[{"output_type":"display_data","data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAjgAAAI+CAYAAACxLHDrAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+WH4yJAAAaBklEQVR4nO3df7CmZXkf8Otyz7IHWAhYY0JJLYbakGgi1djEGtSJRqKJTDUkJUXFtFgFNyoJUdNi1cqUqFgx8kODCqYkHX9RRg21GDKp4qiBph2NlaipJmWAiLJ2Wdhz2MW7f+xSd/d+dvcs+77v857rfD4zOwPf9xyeaxwf9svNdW6ytRYAAJU8bOwBAAAmTcEBAMpRcACAchQcAKAcBQcAKEfBAQDKUXAAgHIUnCnKzMdk5lJmXjP2LDCmzDwhM6/PzM2ZeWdmXpqZC2PPBWPJzE2ZeUtmLmfm1WPPU5GCM12XRcTNYw8Bc+DyiPhmRBwXESdHxNMi4txRJ4Jx3R4RF0bE+8YepCoFZ0oy84yI+E5E3Dj2LDAHHh0RH2ytLbXW7oyIT0TEY0eeCUbTWru2tXZdRHx77FmqUnCmIDOPjoh/FxG/MfYsMCcuiYgzMvOIzDw+Ip4dO0sOwFQoONPxpoh4b2vttrEHgTnxqdh5YrMlIm6LiFsi4rpRJwJKU3AmLDNPjohnRsTbx54F5kFmPix2ntZcGxFHRsQjIuLYiHjzmHMBtfkphsl7ekScEBF/k5kRERsjYl1m/lhr7QkjzgVjeXhEPCoiLm2tLUfEcmZeFTsXLF896mRAWU5wJu/3IuLE2PmTIidHxLsi4o8i4tQxh4KxtNa+FRFfj4hzMnMhM4+JiLMi4gvjTgbj2fUuLEbEutj5D8GLrk6YLAVnwlpr97XW7nzwV0RsjYil1tpdY88GI3p+RPx8RNwVEV+LiO0Rcd6oE8G4LoiIbRHx2oh4wa4/vmDUiYrJ1trYMwAATJQTHACgHAUHAChHwQEAylFwAIByFBwAoJz9/sx9ZvoRK0bTWsuxZ9ibd4IxeSdgT/t7J5zgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQtjD8A+/Ndn9dmpN8x+DgBYhZzgAADlKDgAQDkKDgBQjoIDAJRjyXge3HZ8n918xOzngGn7mU/32THf6bOPP3f6swClOcEBAMpRcACAchQcAKAcBQcAKMeS8azdfWyfbd8+kK2f/iwwa7f8ZJ/94sf77AX/sc+ueeHk5wHKcoIDAJSj4AAA5Sg4AEA5Cg4AUE621vb9Yea+P+ShuWdjn330tD478w+nP8uca63l2DPszTsxIy++qs8WdvTZe14y/VnmiHeinudd22cblvvs6C0r+7p3vuLQZ1pN9vdOOMEBAMpRcACAchQcAKAcBQcAKMdNxtO0tKHP1t/XZ24thj1d/Wt99rIrZj8HTNkNz+qzoeXhu//O9GepxgkOAFCOggMAlKPgAADlKDgAQDmWjCfkYQ/02Xdjex9eNbA8OXRDK6xyV57dZ0P/V19cWln2vKEQVrl7F9f12caB31A4aE5wAIByFBwAoBwFBwAoR8EBAMqxZDwh6wf2iZcXv9uHVwzcWnz2eyc/EMzQW8/vs6WBneBfv/RQnnJeH53/1j67+LcO5SEwW1uOHgg3z3yMipzgAADlKDgAQDkKDgBQjoIDAJRjyfgh2HhPn21dnP0cMIY3XdBnOwZuKD60heIBF7xpZQ+G1WR5w9gTlOUEBwAoR8EBAMpRcACAchQcAKAcS8YH8Mi/7bPtA7cWD7riZQPfPHCTMawiQzuRr7twBg++8HV9NrR4DPPqG3+/z47769nPsUY4wQEAylFwAIByFBwAoBwFBwAox5Lxbv7BV/ts28BC8Td/YIV/waGF4le886BmgnmzNE+3dm9YHnsCWDm3Fs+UExwAoBwFBwAoR8EBAMpRcACAciwZ72b9wELxs/9Ln614TditxRS0Y+DvGi+7os/edc6EH/z2V/XZ0o4JPwSowgkOAFCOggMAlKPgAADlKDgAQDmWjHfz5R8byAa+7jW/02dvvviuPtx+8SHPBPPmkvP67Owr+2zii8cLAwvFvz3wMsK8cpPxTDnBAQDKUXAAgHIUHACgHAUHACgnW2v7/jBz3x+yp6f9aZ897i+66C1HbOqyI+7rv3XTZROYaZVrreXYM+xtzb0TN/9kny0t9tnQ9cZDXzeUbd24sq97yXv6bI3xTqwiQ+/Ok26Z/RzF7e+dcIIDAJSj4AAA5Sg4AEA5Cg4AUI6bjCflvz29z/7R27vo1W+d/ijwkHzxcX3245Ndijz9Q3324RdO9BEAEeEEBwAoSMEBAMpRcACAchQcAKAcS8bTdMl5Y08Aw75+Qp/tWJr6Y4cuPP7Fj/XZx5879VFgupY3jD3BmucEBwAoR8EBAMpRcACAchQcAKAcS8awFi3s6LNHf2Pqj73ueX32zE9O/bEwe5aMR+cEBwAoR8EBAMpRcACAchQcAKAcS8awFi1O/9bilRq63Xho8fiPf276s8DEWDIenRMcAKAcBQcAKEfBAQDKUXAAgHIsGcNaNLRkvH3gbwfrB248nrClxT773JOn/liYnPe/qM9e/NaBL/yBqY/C9zjBAQDKUXAAgHIUHACgHAUHACjHkjGsRUdt7bPWRwvb+2zH+smOMnSTMawqW47us1e/pc/On/4ofI8THACgHAUHAChHwQEAylFwAIBysrWBzcIHP8zc94cwZa21HHuGva21d2JxW58tDFxuvPWoh/6Mk77cZ7f+6EP/61XmnYA97e+dcIIDAJSj4AAA5Sg4AEA5Cg4AUI4lY+aWhcr5dMzmPhtaPB7KFpf67BuPPvSZ1grvBOzJkjEAsKYoOABAOQoOAFCOggMAlGPJmLlloRL25J2APVkyBgDWFAUHAChHwQEAylFwAIByFBwAoBwFBwAoR8EBAMpRcACAchQcAKAcBQcAKEfBAQDKUXAAgHIUHACgHAUHAChHwQEAylFwAIByFBwAoBwFBwAoR8EBAMrJ1trYMwAATJQTHACgHAUHAChHwQEAylFwAIByFBwAoBwFBwAoR8EBAMpRcACAchQcAKAcBQcAKEfBAQDKUXAAgHIUHACgHAUHAChHwQEAylFwAIByFJwpyMxrMvOOzNySmV/JzLPHngnGlJmbMvOWzFzOzKvHngfGlpknZOb1mbk5M+/MzEszc2HsuSpRcKbjoog4obV2dEScFhEXZuYTR54JxnR7RFwYEe8bexCYE5dHxDcj4riIODkinhYR5446UTEKzhS01r7UWlt+8E93/TpxxJFgVK21a1tr10XEt8eeBebEoyPig621pdbanRHxiYh47MgzlaLgTElmXp6Z90XErRFxR0RcP/JIAMyPSyLijMw8IjOPj4hnx86Sw4QoOFPSWjs3Io6KiFMi4tqIWN7/dwCwhnwqdp7YbImI2yLiloi4btSJilFwpqi19kBr7aaI+KGIOGfseQAYX2Y+LHae1lwbEUdGxCMi4tiIePOYc1Wj4MzGQtjBAWCnh0fEoyLi0tbacmvt2xFxVUQ8Z9yxalFwJiwzH5mZZ2Tmxsxcl5mnRsSvRsSNY88GY8nMhcxcjIh1EbEuMxf9SCxrVWvtWxHx9Yg4Z9e7cUxEnBURXxh3sloUnMlrsfNfR90WEZsj4uKIeFVr7aOjTgXjuiAitkXEayPiBbv++IJRJ4JxPT8ifj4i7oqIr0XE9og4b9SJisnW2tgzAABMlBMcAKAcBQcAKEfBAQDKUXAAgHIUHACgnP3eQ5GZfsSK0bTWcuwZ9uadYEzeCdjT/t4JJzgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUsjD1AZcuH9dmG+2c/B8yzs6/ss5e+u8/+7u19dvxABqvKmdf02eLSyrLLNk1+nkKc4AAA5Sg4AEA5Cg4AUI6CAwCUk621fX+Yue8P2cPv/nqfbT62z+49ss/uH1hGvuS8Q59ptWut5dgz7M07MXk/e2Of/ckzZj/HauCdWOWOvbvPnnVDn33gjD575SV9tn57n138Wwc/1yq2v3fCCQ4AUI6CAwCUo+AAAOUoOABAOW4ynpBXvHOyf71zL+uzoWXklS4tf+T0Q58JpmFoGR9K2vzwLnrPxv7Lzh763ne8qs9ee9Ehj1SZExwAoBwFBwAoR8EBAMpRcACActxkXNBzP9pnHztt9nMcKre21nPSl/vs2M199tl/Mv1ZViPvxOp26cv7bNPAD5Qckje8fiB744QfMj/cZAwArCkKDgBQjoIDAJSj4AAA5bjJeJX72Rv77GPPmP0csBJLi31moZiKLnllny0szeDBi7N4yOrgBAcAKEfBAQDKUXAAgHIUHACgHEvGc+qnPtdn67f32WFbpz8LTMq2w8eeAGZjaKH+Ve+YwYOHlowv/s0+O/9t059lZE5wAIByFBwAoBwFBwAoR8EBAMqxZDwpO9b12b1H9tn9h60o+/z29Sv73lO+uoLhYD5YMmat2DHW765Dm8xD1yqvAU5wAIByFBwAoBwFBwAoR8EBAMqxZHwAh9/XZ0O7vj/8vx/osq/+wy1TmGgvf/HYPhsa8An/Y/qzwG4OW+6zLRtmPweMYbQl43f/qz576SyuUJ4/TnAAgHIUHACgHAUHAChHwQEAyrFkfADbjljZ1412n/DjvtRnn//Hffbpn+mzU26a/Dywy/3rBm73jn4ZHyqaya3d739Rn+3YMYMHrw5OcACAchQcAKAcBQcAKEfBAQDKsWRc0daNfbZx6+znYO3YemSfLdw7+zlgTkz8JuMP/MrAQwYWis/6/Qk/ePVyggMAlKPgAADlKDgAQDkKDgBQjiXjiu4dWPh8xp/Mfg7WjsFrWy0Zs3a97alP6sNPLfbZ0LuzNPB1QwvF/+yDBz/YGuIEBwAoR8EBAMpRcACAchQcAKAcS8ar3Yd/qc9O+8js52BtG1wyhjXiK4/ps6WlLnr5n93cZZdtmsZARDjBAQAKUnAAgHIUHACgHAUHACjHkvE8eP+L+mz99pV97+n/abKzwEMxdPMqrBULA7cM/8QXu+iygW996bv67N0vO/SRcIIDABSk4AAA5Sg4AEA5Cg4AUI4l49393A199slnTfYZV57dZ2e9Z7LPgFnbfGyfPeKuPvvW909/FpimO36wz7YPLBmv0NBC8b8c+C3hvQO/dbB/TnAAgHIUHACgHAUHAChHwQEAyrFkvLvPPrnP/sV7++ykW/ts6Obhw+7vs5dcfvBzwbz7qxP7zEIxFQ3dWnzcnRN9xA6/M0+EExwAoBwFBwAoR8EBAMpRcACAcrK1tu8PM/f9IUxZay3HnmFv3gnG5J2YA/ds7LOjtk79sWde02dDy8gfOGPqo8yV/b0TTnAAgHIUHACgHAUHAChHwQEAyrFkzNyyUAl78k7MgW2LfXb40uzniIjnf6TPhi7Vr7x4bMkYAFhTFBwAoBwFBwAoR8EBAMqxZMzcslAJe/JOjG9hYIn38G19ds/R059lyHP+qM+u/4XZzzErlowBgDVFwQEAylFwAIByFBwAoJyB/9g6ADBkx/o+W7i7z467vc8WBy48HsqGlpYXdqwsWxrnUuW55AQHAChHwQEAylFwAIByFBwAoBw3GTO33NoKe/JOrG4/+r/6bMfAj/oMLR5/8ScmP08FbjIGANYUBQcAKEfBAQDKUXAAgHIsGTO3LFTCnrwTsCdLxgDAmqLgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlZGv+S/cAQC1OcACAchQcAKAcBQcAKEfBAQDKUXAAgHIUHACgHAUHAChHwQEAylFwAIByFBwAoBwFBwAoR8EBAMpRcACAchQcAKAcBQcAKEfBAQDKUXCmIDP/NDOXMnPrrl9/OfZMMKbM3JSZt2TmcmZePfY8MLbMvCYz78jMLZn5lcw8e+yZqlFwpmdTa23jrl8/MvYwMLLbI+LCiHjf2IPAnLgoIk5orR0dEadFxIWZ+cSRZypFwQGmrrV2bWvtuoj49tizwDxorX2ptbb84J/u+nXiiCOVo+BMz0WZ+a3M/ExmPn3sYQCYL5l5eWbeFxG3RsQdEXH9yCOVouBMx2si4ocj4viI+L2I+FhmauYA/H+ttXMj4qiIOCUiro2I5f1/BwdDwZmC1trnW2v3tNaWW2vvj4jPRMRzxp4LgPnSWnugtXZTRPxQRJwz9jyVKDiz0SIixx4CgLm1EHZwJkrBmbDMPCYzT83MxcxcyMwzI+KpEfGJsWeDsex6FxYjYl1ErHvw/Rh7LhhDZj4yM8/IzI2ZuS4zT42IX42IG8eerZJsrY09QymZ+f2xc1HspIh4IHYuj72utfbJUQeDEWXmGyLi9XvFb2ytvWH208C4dv0+8eGIeHzsPGj464j43dbalaMOVoyCAwCU419RAQDlKDgAQDkKDgBQjoIDAJSj4AAA5ez3HorM9CNWjKa1NneXI3onGJN3Ava0v3fCCQ4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFCOggMAlKPgAADlKDgAQDkKDgBQjoIDAJSj4AAA5Sg4AEA5Cg4AUI6CAwCUo+AAAOUoOABAOQoOAFDOwtgDAGvHsXf32eaHz34OoD4nOABAOQoOAFCOggMAlKPgAADlWDIGZmbz9w39M9V3Zz4HUJ8THACgHAUHAChHwQEAylFwAIByLBkDs7Pl6IHwOzMfA6jPCQ4AUI6CAwCUo+AAAOUoOABAOZaMgenYfEyf3X/Y7OcA1iQnOABAOQoOAFCOggMAlKPgAADlZGtt3x9m7vtDZu7Ks/tscanPXnjN9GeZhdZajj3D3rwTh+hv/l4X/dKf/Z8u+8jpsxhm9fFOwJ729044wQEAylFwAIByFBwAoBwFBwAox03GB/CUm/rslE/32eHb+mxoAXj99j5b2LGy7CVX9NnQdt8LBzKYua+d2GeP+qsu2vAHM5gF5sC/fWOf3Xtknw1d+L3SbOvGlT3j+l/os2qc4AAA5Sg4AEA5Cg4AUI6CAwCUY8n4ALYd3me/89uzn2Nf5u5aU3jQ8oYVfdmG5SnPAXPiKZ/ps1NvmP5zn/nJ6T9jHjnBAQDKUXAAgHIUHACgHAUHACjHkvEBDC0ZA5Nz2P1jTwCzMYuF4p/+bJ/98ZOn/9x55AQHAChHwQEAylFwAIByFBwAoBxLxgeww/9C8NC4yRim6gn/vc8O2zr7OeaVExwAoBwFBwAoR8EBAMpRcACAcqzQHsAh3WR801P6bGhreeghQ1+3fX2fPf8/H/xcMEeedPPYE8D8e9wX++zPf3z2c6wmTnAAgHIUHACgHAUHAChHwQEAysnW2r4/zNz3hwX94B19duc9j+nDlS4FP/HPD32o3X3wl1c2y1m/P9nnjqS1lmPPsLe19k4cks/9VJ/99OdnP0ch3on5tG5Hnz2wfbEP7z9sstm9R67s67Zu7LOnfrrPVqH9vRNOcACAchQcAKAcBQcAKEfBAQDKcZPxbu45aiDcNrA99vgvTH2WQb/yoZV93aUv77NNl012FgAiIuKBod9JH7i/zw5fmvosg65/dp+tgR8CcIIDAJSj4AAA5Sg4AEA5Cg4AUI4l493ce/hA3zvqntkPcjAueWWfbXrH7OeAvS1vGHsCGM+67449wfcM3W5cbKF4iBMcAKAcBQcAKEfBAQDKUXAAgHIsGe9ucCnsWzMfY58uem2f7dg++zlgJYYWG4Hp+tDpffZPPzz7OeaAExwAoBwFBwAoR8EBAMpRcACAciwZz6s3XdBn67f12flvm/4s8FC4yZi17KgtfXbP0ZN9xh/88z775T+c7DNWMSc4AEA5Cg4AUI6CAwCUo+AAAOVYMp4HQwvFr7tw9nMAMBnrJ3zL/FUv7rMzr57sM4pxggMAlKPgAADlKDgAQDkKDgBQjiXjWXv9G/psx8yngOm756ixJ4DZeNtv9NmXr+2zx2/qs8PuX1n2a1cf9FhrnRMcAKAcBQcAKEfBAQDKUXAAgHIsGR/II/+2z4aWJ7cdsbK/3vb1ffbv/83BzQSrwfKGsSeA2fjN/zD2BAxwggMAlKPgAADlKDgAQDkKDgBQTrbW9v1h5r4/XCt+5NY++8uTVva9r35zn73lNYc2zxrSWsuxZ9ibd+IgfN93+uzcy/vson89/VmK8E7Anvb3TjjBAQDKUXAAgHIUHACgHAUHACjHTcYHcvL/7LMnX9Vnh2/rs+1Lk58HVov/e0yfXTT7MYC1yQkOAFCOggMAlKPgAADlKDgAQDluMmZuubUV9uSdgD25yRgAWFMUHACgHAUHAChHwQEAylFwAIByFBwAoBwFBwAoR8EBAMpRcACAchQcAKAcBQcAKEfBAQDKUXAAgHIUHACgHAUHAChHwQEAylFwAIByFBwAoBwFBwAoR8EBAMpRcACAchQcAKAcBQcAKEfBAQDKUXAAgHIUHACgHAUHAChHwQEAylFwAIBysrU29gwAABPlBAcAKEfBAQDKUXAAgHIUHACgHAUHAChHwQEAyvl/2VZxmSyeGCkAAAAASUVORK5CYII=\n","text/plain":["
"]},"metadata":{"needs_background":"light"}}]},{"cell_type":"code","metadata":{"id":"21qi3bLAo80t","executionInfo":{"status":"ok","timestamp":1638747856480,"user_tz":480,"elapsed":184,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["from keras import layers\n","\n","def make_model(input_shape, num_classes):\n"," inputs = keras.Input(shape=input_shape)\n","\n"," # Entry block\n"," x = layers.Rescaling(1.0 / 255)(inputs)\n"," x = layers.Conv2D(16, 3, strides=2, padding=\"same\")(x)\n"," x = layers.BatchNormalization()(x)\n"," x = layers.Activation(\"relu\")(x)\n"," x = layers.Dropout(0.5)(x)\n","\n"," x = layers.Conv2D(32, 3, strides=2, padding=\"same\")(x)\n"," x = layers.BatchNormalization()(x)\n"," x = layers.Activation(\"relu\")(x)\n"," x = layers.Dropout(0.5)(x)\n","\n"," x = layers.Conv2D(64, 3, strides=2, padding=\"same\")(x)\n"," x = layers.BatchNormalization()(x)\n"," x = layers.Activation(\"relu\")(x)\n"," x = layers.Dropout(0.5)(x)\n","\n"," x = layers.GlobalAveragePooling2D()(x)\n"," activation = \"softmax\"\n"," units = num_classes\n","\n"," x = layers.Dropout(0.5)(x)\n"," outputs = layers.Dense(units, activation=activation)(x)\n"," return keras.Model(inputs, outputs)"],"execution_count":16,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"id":"7DjpCkt0qZiy","executionInfo":{"status":"ok","timestamp":1638747862714,"user_tz":480,"elapsed":822,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"eb7158b8-b866-455f-e5fb-7dee1fa25e70"},"source":["model = make_model(input_shape=(IMAGE_WIDTH, IMAGE_HEIGHT, 3), num_classes=10)\n","keras.utils.plot_model(model, show_shapes=True)"],"execution_count":17,"outputs":[{"output_type":"execute_result","data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAq0AAAc0CAIAAADqb6jQAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdeVxTV9o48HOBkIQQCLvIIpKIiELVSgewDLVOqZURREBwa62jg9oWWXxFUBQBUdAX+IBQx2UYR6wsSsGqqC+ljLUuPztipbG1EUUE1LCH1YRwf3/c6X3zIktYb+A+37+ac26ePPdcbJ7c5RwMx3EEAAAAAFpSozoBAAAAAFAG6gAAAACAvqAOAAAAAOgL6gAAAACAvjSoToCObt26lZSURHUWAACgWpydnUNDQ6nOgnbgfAAFnj9/fu7cOaqzoMDt27dv375NdRYT2Llz56qrq6nOYszB3wk93b59+9atW1RnQUdwPoAyeXl5VKcw3vz8/BAtd3y0YBgWEhKycuVKqhMZW/B3Qk/EcQfjD84HAAAAAPQFdQAAAABAX1AHAAAAAPQFdQAAAABAX1AHAAAAAPQFdQAAk9zly5d1dXW/+eYbqhMZZZs3b8Z+t3btWsWu4uLiiIiI8+fPW1tbExusW7dOcQN3d3cul6uurj579ux79+6Nb+L/kZCQYGtry2azORyOra1tVFSURCIhe2NiYuzs7HR0dJhMpkAg2LFjR1tbmypHvnDhQkJCglwuJzcuKCggD5ChoaGSHwHGH9QBAExyk3hNUX19/aKiokePHp08eZJs3Lt3b2pqamRkpI+Pz5MnT/h8voGBQVZW1qVLl8htrl27lpeXt2zZMqFQOH/+fCpyR99///2mTZuqqqpevXoVGxubkJDg6+tL9paUlHz++eeVlZX19fXx8fEpKSnKP1ZHSWRPT08Wi7V48eLm5maixcvLq7q6+vr160uXLlUyPqAGDsZdTk4OPUfe19fX19eX6iwmMIRQTk4O1Vn0q6Ojw9nZeeRxlPw7CQwMNDMz69V44MABGxubzs5OsoXP5585c0ZNTc3MzKy5uZlsLyoq8vLyGnm2w+bt7a2YJ/FlXFtbS7z08PDo7u4me4lJI6qqqlQ5Mo7jQUFBzs7OMplM8V3btm0zMDAYNDj8/4EqcD4AADA6Tp48KRaLKUzg8ePHUVFR+/btY7FYiu0uLi7BwcE1NTXbt2+nKrc35efnK+ZpZmaGECJP0V+8eFFdXZ3sJc6rd3R0qHJkhFB0dPT9+/dTUlKUiQZUBNQBAExmN27csLS0xDDsyJEjCKGMjAwOh6OlpVVYWPjRRx/p6OiYm5ufPXuW2Dg1NZXFYhkbG2/evNnU1JTFYrm4uNy5c4foDQoK0tTUnDJlCvHys88+43A4GIbV19cjhIKDg8PCwioqKjAMEwgECKErV67o6Ojs379/3HY2NTUVx3FPT883u+Li4mxsbE6cOFFcXNzne3EcT0pKmjVrFpPJ1NPTW758+a+//kp0DTxoCCG5XL5nzx5LS0s2m+3g4ECc8BsqkUjE4/GmTZvWZ29NTQ2bzZ4+fbqKR9bT03Nzc0tJScEn79WoyQfqAAAms3fffffmzZvky61bt4aEhHR2dnK53JycnIqKCmtr602bNslkMoRQUFDQ+vXrOzo6tm3bVllZee/eve7u7g8++OD58+cIodTUVMUpjdPT0/ft20e+TElJWbZsGZ/Px3H88ePHCCHilrGenp5x29lLly7NnDlTS0vrzS42m/2Pf/xDTU1t06ZN7e3tb24QHR0dERGxa9cusVh8/fr158+fu7q6vnr1Cg02aAihnTt3JiYmJicnv3jxYtmyZatXr/7xxx+VzFkmk9XU1Bw5cqS4uDgtLU1TU/PNbTo6OkpKSjZt2tRnr6pFnjdvXk1NzU8//aR8QEAtqAMAoCMXFxcdHR0jI6OAgID29vaqqiqyS0NDg/hZbGdnl5GR0drampmZOYyP8PDwkEgkUVFRo5f1QNrb258+fcrn8/vbwNnZOSQkpLKycufOnb26Ojs7k5KSVqxYsXbtWl1dXXt7+6NHj9bX1x87dkxxsz4HraurKyMjw9vb28fHh8fj7d69m8FgKD9iFhYW5ubm0dHRiYmJ/v7+fW4THx9vamoaFxenZExqI8+YMQMhVF5ePqSYgEJQBwBAa8SPOfKnbS8LFizQ0tIiz5CrMrFYjON4nycDSHFxcTNnzkxPT79x44Ziu1AobGtrW7BgAdni6OioqalJXhPpRXHQHj161NHRMWfOHKKLzWZPmTJF+RF7/vy5WCz+6quvTp06NW/evDdvsMjPz8/Nzb169SqXy1UyJrWRiUNAnEoBEwLUAQCAgTCZzLq6OqqzGFxXVxdCiMlkDrANi8XKzMzEMGzDhg2dnZ1kO/Gom7a2tuLGPB6vtbV10M8lrjLs3r2bfFb+2bNnSt52hxBiMBhGRkbu7u7Z2dlCoTA+Pl6xNzs7++DBg6WlpVZWVkoGpDwym81Gvx8OMCFAHQAA6JdMJmtubjY3N6c6kcERXz+K89j0ydnZOTQ0VCQSxcbGko08Hg8h1OtbX8kdNzIyQgglJycrPoh169atoeYvEAjU1dWFQiHZkpaWlpWVVVJSMnXq1KFGoyoyQkgqlaLfDweYEKAOAAD0q7S0FMdxJycn4qWGhkZ/VxAoZ2xsjGFYS0vLoFvGxsba2tqWlZWRLXPmzNHW1la8ue/OnTtSqfTtt98eNJqFhQWLxbp///6Qsm1oaFi9erVii0gkksvlFhYWCCEcx8PDw8vLywsKCnqdpVDZyCTiEJiYmAwpOKAQ1AEAgP+jp6enqampu7v7wYMHwcHBlpaW69evJ7oEAkFjY2NBQYFMJqurq3v27JniG/X19WtraysrK1tbW2UyWVFR0Xg+N6ilpWVtbV1dXT3olsTVAcVn6FksVlhYWH5+flZWlkQiKS8v37Jli6mpaWBgoDLRPv3007Nnz2ZkZEgkErlcXl1d/eLFC4RQQECAiYlJn/MWczica9eulZSUSCQSmUxWVlb2ySefcDic0NBQhNDDhw8TExOPHz/OYDAwBYcPHyberoKRScQhsLe3H3TogIqAOgCAyezIkSOOjo4IofDwcC8vr4yMjOTkZISQg4PDkydPjh8/HhYWhhBasmSJSCQi3tLV1WVvb89ms11dXW1sbL777jvyovvWrVsXLVq0atWqmTNnxsbGEud+nZ2diQcLt2zZYmxsbGdnt3Tp0sbGxvHfWQ8PD6FQSF74//rrrwUCQUVFhaOj4xdffKG4pZOTU69vr71798bHx8fExBgaGrq5uVlZWZWWlnI4HITQoIOWkpISEhKSkJBgYGBgamoaHBzc1NSEEJJKpWKxuLCw8M1UWSzWwoULN27caGZmxuVy/fz8rKysbt++TdxvOOjD9yoYmXT37l0zMzMHB4eBPwiokPGdvhDgOMwrDIYLjf28woGBgfr6+mP6EYMa9rzCIpFIQ0Pj9OnTY5ba0MjlcldX15MnT9Incn19PYvFOnz4sGIjzCus4uB8AADg/xj0VjvV0dnZefXqVZFIRNybJhAIYmJiYmJilF9Ab+zI5fKCgoLW1taAgAD6RI6Ojp47d25QUBBCCMfx2traGzduEPNKAZUFdQAAYKJqbGxcsmSJjY3Nhg0biJaIiAg/P7+AgABlbhgcU6WlpefPny8qKhp4SoPJFDkpKen+/fuXL19mMBgIocLCQjMzM1dXV8WVHoEKgjpAdanysvE9PT3JyckuLi6jHvn27duzZs1SU1PDMMzExGSoM52NhOJy9VOmTOm1pD0dREZGZmZmtrS0TJ8+/dy5c1SnM4ijR4+SJzazsrLI9v379wcFBR04cIDC3BBCixcvPnPmDLkcw6SPXFhY+Pr169LSUj09PaJl+fLl5AEiFqEAqkmD6gRAv3BVXahDJBJ9+umnP/zww1tvvTXqwZ2cnH755ZclS5ZcvXr10aNHxIPd48PHx8fHx0cgENTX1798+XLcPld1xMfH95oTZoJyd3d3d3enOgt68fLy8vLyojoLMBxwPkB1eXh4tLS0LFu2bKw/qLOzU/lf9j/99NPOnTu3bNkyd+7cMc1qfAxp3wEAYPKBOgAMbdn4t9566/z582vWrBl4AteJYkj7DgAAkw/UASqKwmXjVY2q7fv3339vZ2enq6vLYrHs7e2vXr2KENq4cSNxYwGfzycmqvv000+1tLR0dXUvXLiA+lmiPjExUUtLi8vlisXisLAwMzOzR48ejebYAQDAoMb/UUWg5PwBxNwsaWlpxMtdu3YhhL799tuWlhaxWOzq6srhcKRSKdEbGBjI4XAePnzY1dUlFAodHR25XG5VVRXRu2bNGhMTEzLyoUOHEEJ1dXXESx8fH2LZ+CH5wx/+8NZbbw3pLco/H/zhhx8ihJqamoiX47nvfD5fV1d3gNzy8vKio6MbGxsbGhqcnJzIB6N9fHzU1dVramrILVevXn3hwgXiv7dv385kMs+dO9fU1BQZGammpnb37l1y17Zt25aWlrZixYpffvllgI9GYz9/gCqA58jpCY47VeB8wAQzDsvGqywV2XdfX9+9e/fq6enp6+t7eno2NDQQy/Ft2bJFLpeTnyuRSO7evbt06VKkxBL1Bw8e/Pzzz8+fP29raztGaQMAQJ/geYGJatIsGz8MqrPvxHPSxMQ777//vo2Nzd///vfIyEgMw7KzswMCAohJ7Ee4RL0if39/f3//0dsD1YVhGNUpgPHm6+tLdQp0BHXApDVRlo0fC2O675cuXTp06JBQKCRWWyHbMQzbvHlzaGjot99++6c//emf//znmTNniC5yifrdu3eT25uamg7j04ODg52dnUe2B6qOmMw/JCSE6kTAuCKOOxh/UAdMThNo2fhRNxb7fv369X//+98hISFVVVXe3t4rVqz4+9//PnXq1LS0tB07dpCbrV+/PjIy8sSJExYWFjo6OtOmTSPaySXqg4ODR5iJs7PzypUrRxhExeXl5SGEJv1ugl6I4w7GH9QBk9MEWjZ+1I3Fvv/73/8mlp4rLy+XyWRbt261trZGb5y71tPT8/f3z87O5nK5mzZtItuHt0Q9AACMA7hPcPIYrWXjKUh9xMZu32Uy2atXr8glaC0tLRFCxcXFXV1dIpGIfECRtGXLltevX1+8eFFxAqgBlqgHAACKUf3AAh0p89xgWloa8dS7lpaWp6dneno6sfLHjBkzKioqjh07pqOjgxCaNm3ab7/9huN4YGAgg8EwMzPT0NDQ0dFZvnx5RUUFGa2hoWHRokUsFmv69OlffPHFf/3XfyGEBAIB8XDdvXv3pk2bxmaz33333ZcvXw6c2K1btxYuXEhe254yZYqLi8u//vUvZXZcmeeCbt++PXv2bDU1NSL4/v37x23fv/zySz6f39+/lPz8fCJgeHi4vr4+j8fz8/MjZnfg8/nkY4o4js+bNy8iIqLXfr1+/To8PNzS0lJDQ8PIyMjHx0coFCYkJLDZbISQhYWFMqvlInhuEExecNypguGqOon9JJabm+vv7z+6I7958+a8vLyGhoZRjDnq/Pz80BhcBVS1fffw8Dhy5Mj06dNHPTKGYTk5OZP+wvkY/Z0AFQfHnSpwXWDymEDLxo86yvedvKbw4MED4twDtfkAAICSoA4A/+vXX3/F+hcQEEB1gqorPDxcJBL99ttvn376aWxsLNXp0MLmzZvJP85ei0QXFxdHREQoLiS9bt06xQ3c3d25XK66uvrs2bPv3bs3von/R0JCgq2tLZvN5nA4tra2UVFREomE7I2JibGzs9PR0WEymQKBYMeOHW1tbaoc+cKFCwkJCYoVeUFBAXmADA0NlfwIQAGqL0zQkZLzCisvIiKCmFrHysoqLy9vFCOPrrG4/qci+75r1y41NTULCwtyIuGxgOD+AAWBgYH6+vpFRUWPHj3q6uoi2/fs2bNs2TKJREK85PP5BgYGCKGLFy8qvr2oqMjLy2t0Mx8SDw+Pw4cPi8Xi1tbW3NxcBoPxwQcfkL1ubm7p6ekNDQ0SiSQnJ4fBYCxZskTFI6ekpLi5uZHTgff09FRXV1+/fn3p0qXk9NsDgPsDqAJ1AAVGvQ6YKODf+QiNdR3Q0dHh7OxMeSjl6wAzM7NejQcOHLCxsens7CRb+Hz+mTNn1NTUzMzMmpubyXbK6wBvb2/FPImr47W1tcRLDw+P7u5uspe4KUTxdlQVjIzjeFBQkLOzs0wmU3zXtm3boA5QZXBdAADwH6O4CjMlCzo/fvw4Kipq3759LBZLsd3FxSU4OLimpmb79u3jnNIA8vPzFfM0MzNDCJGn6C9evEhMSk0gzqt3dHSocmSEUHR09P3791NSUpSJBlQE1AEATCo4jiclJRGrLunp6S1fvpxcyGBIqzCP7oLOV65c0dHR2b9//5jue2pqKo7jnp6eb3bFxcXZ2NicOHGiuLi4z/cOMG4Dr3yN+llUeqhEIhGPxyPnoOylpqaGzWYP7/7T8Yysp6fn5uaWkpKCw5NoEwi1pyPoCa4LgOFBSlwX2LNnj6am5unTp5ubmx88eDB//nxDQ0NyWoghrcI8igs6X7x4kcvlxsTEKLObw74uYG1tbWdn12szPp//9OlTHMdv3ryppqZmZWXV1taGv3FdYOBxG3jl6/4WlVaGVCqtrq5OS0tjMpn9zSHR3t7O5XKDgoKUjElt5IiICIRQWVkZ2QLXBVQcnA8AYPLo7OxMSkpasWLF2rVrdXV17e3tjx49Wl9ff+zYseEFHK0FnT08PCQSSVRU1PDSUEZ7e/vTp08HmAnK2dk5JCSksrJy586dvbqUHLc+V74edFHpgVlYWJibm0dHRycmJva3kmR8fLypqWlcXJySMamNPGPGDIRQeXn5kGICCkEdAMDkIRQK29raFixYQLY4Ojpqamq+Of/xMKj4YtZisRjHcWLqyf7ExcXNnDkzPT39xo0biu1DHTfFla9HuKj08+fPxWLxV199derUqXnz5r15U0V+fn5ubu7Vq1e5XK6SMamNTByCV69eDSkmoBDUAQBMHs3NzQghbW1txUYej9fa2joq8VV5Meuuri6EEJPJHGAbFouVmZmJYdiGDRs6OzvJ9pGMG7moNPms/LNnz5S87Q4hxGAwjIyM3N3ds7OzhUJhfHy8Ym92dvbBgwdLS0utrKyUDEh5ZGKqbOJwgAkB6gAAJg8ej4cQ6vXtNVqrMKv4YtbE18+gM0s6OzuHhoaKRCLF6Z5GMm7kotKKF1xv3bo11PwFAoG6urpQKCRb0tLSsrKySkpKpk6dOtRoVEVGCEmlUvT74QATAtQBAEwec+bM0dbW/vHHH8mWO3fuSKXSt99+m3g5klWYVXwxa2NjYwzDWlpaBt0yNjbW1ta2rKyMbBl03AYwvEWlGxoaVq9erdgiEonkcrmFhQVCCMfx8PDw8vLygoKCXmcpVDYyiTgEJiYmQwoOKAR1AACTB4vFCgsLy8/Pz8rKkkgk5eXlW7ZsMTU1DQwMJDYY6irMo7Wgc1FR0Vg/N6ilpWVtbV1dXT3olsTVAcVn6Acdt4Gj9beodEBAgImJSZ/zFnM4nGvXrpWUlEgkEplMVlZW9sknn3A4nNDQUITQw4cPExMTjx8/zmAwFOf2Pnz4MPF2FYxMIg6Bvb39oEMHVATUAQBMKnv37o2Pj4+JiTE0NHRzc7OysiotLeVwOETv1q1bFy1atGrVqpkzZ8bGxhInb52dnZ8/f44Q2rJli7GxsZ2d3dKlSxsbGxFCXV1d9vb2bDbb1dXVxsbmu+++Iy/ADzXUOPDw8BAKheSF/6+//logEFRUVDg6On7xxReKWzo5OfX69hpg3DIyMpKTkxFCDg4OT548OX78eFhYGEJoyZIlIpEIIZSSkhISEpKQkGBgYGBqahocHNzU1IQQkkqlYrG4sLDwzVRZLNbChQs3btxoZmbG5XL9/PysrKxu375N3G+ID/bwvQpGJt29e9fMzMzBwWHgDwIqZPwfVQQwfwAYHjS+6wsQE/iP28eRhj1/gEgk0tDQ6O9Z+fEnl8tdXV1PnjxJn8j19fUsFuvw4cOKjTB/gIqD8wEAgH5RvqDzwDo7O69evSoSiYh70wQCQUxMTExMjPIL6I0duVxeUFDQ2to66gt1qnLk6OjouXPnBgUFIYRwHK+trb1x48bjx49HNU0wyqAOAABMVI2NjUuWLLGxsdmwYQPREhER4efnFxAQoMwNg2OqtLT0/PnzRUVFA09pMJkiJyUl3b9///LlywwGAyFUWFhoZmbm6up66dKl0c0TjC6oAwAAfYiMjMzMzGxpaZk+ffq5c+eoTqcPR48eJU9sZmVlke379+8PCgo6cOAAhbkhhBYvXnzmzBlyCYZJH7mwsPD169elpaV6enpEy/Lly8kDRCw8AVSTBtUJAABUUXx8fK/5YSYQd3d3d3d3qrOgFy8vLy8vL6qzAMMB5wMAAAAA+oI6AAAAAKAvqAMAAAAA+oI6AAAAAKAvuE+QMrm5uVSnMN6ICUdpuOOjaBgL2Ew48HdCT9XV1Sq7itXkhuGDTTMJRl1ubq6/vz/VWQAAgGrx9fXNy8ujOgvagToAAFrDMCwnJ2flypVUJwIAoAbcHwAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF9QBAAAAAH1BHQAAAADQF4bjONU5AADGT2Bg4KNHj8iX9+7dmz59up6eHvFSXV391KlT5ubmFGUHABhvGlQnAAAYVyYmJseOHVNsefDgAfnf1tbWUAQAQCtwXQAAelm9enV/XZqamuvXrx/HXAAA1IPrAgDQzpw5cx4+fNjnv/1Hjx7Z2NiMf0oAAKrA+QAAaOfjjz9WV1fv1Yhh2FtvvQVFAAB0A3UAALSzatUquVzeq1FdXf2TTz6hJB8AAIXgugAAdOTi4nLnzp2enh6yBcOw58+fm5mZUZgVAGD8wfkAAOho3bp1GIaRL9XU1N59910oAgCgIagDAKAjPz8/xZcYhn388cdUJQMAoBDUAQDQkaGh4eLFi8m7BTEM8/b2pjYlAAAloA4AgKbWrl1L3B6krq7+4YcfGhgYUJ0RAIACUAcAQFMrVqzQ1NRECOE4vnbtWqrTAQBQA+oAAGiKw+H8+c9/RghpamouW7aM6nQAANSAOgAA+lqzZg1CyNvbm8PhUJ0LAIAaMH+ACsnNzfX396c6CwAAGFu+vr55eXlUZwH+A9YbVDk5OTlUp6AS/P39g4ODnZ2dqU5ERY3W+GRlZQUEBGhoqOj/CpKTkxFCISEhVCcCRg1xTIHqgPMBKoQ4HwBHhIBhWE5OzsqVK6lOREWN1vh0dXWxWKxRSWksEPMcwG/HyQSOqaqB+wMAoDVVLgIAAOMA6gAAAACAvqAOAAAAAOgL6gAAAACAvqAOAAAAAOgL6gAAaOTy5cu6urrffPMN1YmMleLi4oiIiPPnz1tbW2MYhmHYunXrFDdwd3fncrnq6uqzZ8++d+8eJUkmJCTY2tqy2WwOh2NraxsVFSWRSMjemJgYOzs7HR0dJpMpEAh27NjR1tamypEvXLiQkJAgl8uVDAVUDdQBANDI5H4qde/evampqZGRkT4+Pk+ePOHz+QYGBllZWZcuXSK3uXbtWl5e3rJly4RC4fz58ynJ8/vvv9+0aVNVVdWrV69iY2MTEhJ8fX3J3pKSks8//7yysrK+vj4+Pj4lJaXXItGqFtnT05PFYi1evLi5uVnJaEC14EBlEDMIUZ2FqkAI5eTkUJ2F6lLx8eno6HB2dh55HF9fX19fX2W2PHDggI2NTWdnJ9nC5/PPnDmjpqZmZmbW3NxMthcVFXl5eY08t2Hz9vZWzJP4Mq6trSVeenh4dHd3k73EFBFVVVWqHBnH8aCgIGdnZ5lMNmgo5Y8pGB9wPgAAMPpOnjwpFovH7eMeP34cFRW1b9++XtMhuLi4BAcH19TUbN++fdySGVR+fr5inmZmZggh8hT9xYsX1dXVyV5DQ0OEUEdHhypHRghFR0ffv38/JSVFmWhApUAdAABd3Lhxw9LSEsOwI0eOIIQyMjI4HI6WllZhYeFHH32ko6Njbm5+9uxZYuPU1FQWi2VsbLx582ZTU1MWi+Xi4nLnzh2iNygoSFNTc8qUKcTLzz77jMPhYBhWX1+PEAoODg4LC6uoqMAwTCAQIISuXLmio6Ozf//+Mdq11NRUHMc9PT3f7IqLi7OxsTlx4kRxcXGf78VxPCkpadasWUwmU09Pb/ny5b/++ivRNfAQIYTkcvmePXssLS3ZbLaDg8PwJgUXiUQ8Hm/atGl99tbU1LDZ7OnTp6t4ZD09PTc3t5SUFHxSX3uanCg+HwEUwHUBRUi1z3tTbnjj8/z5c4RQWloa8XLXrl0IoW+//balpUUsFru6unI4HKlUSvQGBgZyOJyHDx92dXUJhUJHR0cul0ueRl6zZo2JiQkZ+dChQwihuro64qWPjw+fzyd7L168yOVyY2JihpqwkueQra2t7ezsejXy+fynT5/iOH7z5k01NTUrK6u2tjb8jesCe/bs0dTUPH36dHNz84MHD+bPn29oaPjy5Uuid+Ah2r59O5PJPHfuXFNTU2RkpJqa2t27d5XcNalUWl1dnZaWxmQyT58+3ec27e3tXC43KChIyZjURo6IiEAIlZWVDRwErguoGjgfAADdubi46OjoGBkZBQQEtLe3V1VVkV0aGhrED2U7O7uMjIzW1tbMzMxhfISHh4dEIomKihq9rP9Xe3v706dP+Xx+fxs4OzuHhIRUVlbu3LmzV1dnZ2dSUtKKFSvWrl2rq6trb29/9OjR+vr6Y8eOKW7W5y/VCKYAACAASURBVBB1dXVlZGR4e3v7+PjweLzdu3czGAzlx8fCwsLc3Dw6OjoxMbG/hUbj4+NNTU3j4uKUjElt5BkzZiCEysvLhxQTUA7qAADAf2hqaiKEZDJZn70LFizQ0tIiz5mrDrFYjOO4lpbWANvExcXNnDkzPT39xo0biu1CobCtrW3BggVki6Ojo6amJnkFpBfFIXr06FFHR8ecOXOILjabPWXKFOXH5/nz52Kx+Kuvvjp16tS8efPevJ0iPz8/Nzf36tWrXC5XyZjURiYOwatXr4YUE1AO6gAAgLKYTGZdXR3VWfTW1dWFEGIymQNsw2KxMjMzMQzbsGFDZ2cn2U486qatra24MY/Ha21tHfRz29vbEUK7d+/Gfvfs2TMlb7tDCDEYDCMjI3d39+zsbKFQGB8fr9ibnZ198ODB0tJSKysrJQNSHpnNZqPfDweYQKAOAAAoRSaTNTc3m5ubU51Ib8TXz6Dz2Dg7O4eGhopEotjYWLKRx+MhhHp96yu5m0ZGRgih5ORkxUutt27dGmr+AoFAXV1dKBSSLWlpaVlZWSUlJVOnTh1qNKoiI4SkUin6/XCACQTqAACAUkpLS3Ecd3JyIl5qaGj0dwVhnBkbG2MY1tLSMuiWsbGxtra2ZWVlZMucOXO0tbV//PFHsuXOnTtSqfTtt98eNJqFhQWLxbp///6Qsm1oaFi9erVii0gkksvlFhYWCCEcx8PDw8vLywsKCnqdpVDZyCTiEJiYmAwpOKAc1AEAgH719PQ0NTV1d3c/ePAgODjY0tJy/fr1RJdAIGhsbCwoKJDJZHV1dc+ePVN8o76+fm1tbWVlZWtrq0wmKyoqGrvnBrW0tKytraurqwfdkrg6oPgMPYvFCgsLy8/Pz8rKkkgk5eXlW7ZsMTU1DQwMVCbap59+evbs2YyMDIlEIpfLq6urX7x4gRAKCAgwMTHpc95iDodz7dq1kpISiUQik8nKyso++eQTDocTGhqKEHr48GFiYuLx48cZDAam4PDhw8TbVTAyiTgE9vb2gw4dUClQBwBAF0eOHHF0dEQIhYeHe3l5ZWRkJCcnI4QcHByePHly/PjxsLAwhNCSJUtEIhHxlq6uLnt7ezab7erqamNj891335GX4bdu3bpo0aJVq1bNnDkzNjaWOBvs7OxMPJq4ZcsWY2NjOzu7pUuXNjY2jvWueXh4CIVC8sL/119/LRAIKioqHB0dv/jiC8UtnZycen177d27Nz4+PiYmxtDQ0M3NzcrKqrS0lMPhIIQGHaKUlJSQkJCEhAQDAwNTU9Pg4OCmpiaEkFQqFYvFhYWFb6bKYrEWLly4ceNGMzMzLpfr5+dnZWV1+/Zt4n5DfLCH71UwMunu3btmZmYODg4DfxBQOeP/qCLoD8wfoAjB/AEDGofxCQwM1NfXH9OPGJSSz5qLRCINDY3+npUff3K53NXV9eTJk/SJXF9fz2KxDh8+POiWMH+AqoHzAQCAfk2UReQEAkFMTExMTIzyC+iNHblcXlBQ0NraGhAQQJ/I0dHRc+fODQoKGt3EwDiAOgAM5PDhw8RNWEePHiVaVGfhWsW1ZQksFmv69OkbNmx4+vTp+OSgyuNDNxEREX5+fgEBAcrcMDimSktLz58/X1RUNPCUBpMpclJS0v379y9fvsxgMEY3MTAOoA4AA9m+ffvNmzcVW3CVmTycXFtWV1cXx3G5XF5VVRUTE5OTk+Pk5NTQ0DAOOajy+IxQZGRkZmZmS0vL9OnTz507R3U6Stm/f39QUNCBAweoTWPx4sVnzpwhF1+Y9JELCwtfv35dWlqqp6c36omBcaBBdQJggvHw8KD891af1NTUjI2N161b9/PPPycmJhYXF/c3o+qYUtnxGar4+Phes8RMCO7u7u7u7lRnQS9eXl5eXl5UZwGGD84HgPGD43heXl6vmdtHHbHA3cuXL8f0U8bC+IwPAAAogjpggklMTNTS0uJyuWKxOCwszMzM7NGjR/0tfvqvf/3rnXfe0dLS0tHRsbe3l0gkRPvp06cXLFjAYrE4HI6VlRUxvdr3339vZ2enq6vLYrHs7e2vXr365qcPaeFahJBcLo+Pj585cyabzTY0NJw+fXp8fPzKlSvHdIiIB7reeustxTRgfAAAoE9QB0wwO3bsCA0NbWtri4+Pnz59upOTE47jO3fuTExMTE5OfvHixbJly1avXv3jjz+2t7d7enr6+vo2NjaKRCIbGxti1s+UlJSPP/7Y19e3tra2uro6MjLy0aNHCKFXr175+/tXVlbW1tZqa2uvWbPmzU9/9913FS+Hb926NSQkpLOzk8vl5uTkVFRUWFtbb9q0iZxmLiEhYc+ePYcOHWpsbLx27VpXVxePxyNmch0Lzc3Np06dSk9P9/DweO+998h2GB8AAOgXlQ8tgv9LyfkDiAXROzs7iZednZ1aWloBAQHEy46ODiaTuXXr1p9//hkhdPHiRcX3SqVSHo+3aNEisqW7uzslJaXXRxAXholl3Iif119++SXR1ecC9mQy6enpCKHHjx8TLx0dHd955x0y7F//+lc1NbXXr18rMxpIuefje602i2FYXFwcuTw8TvvxmejgWfPJB46pqoH7BCe8/hY/tba2NjY2Xrt27bZt29avX0+sLfbgwYPm5uYPP/yQfLu6uvq2bdt6xSQe/hnGs+O9Fq7t6upisVhkr1wuZzAYirO6jgpdXV1i1bgdO3YcOnRIV1dX8eGlSTw+w1jSZsIhpqrNzc2lOhEwaqqrq1VwtSpao7oQAf9reOcDfvjhhzcPK3G94Oeff/7zn/+soaGBYZi/v39HR0dJSQlC6OjRo2+GvXjxopubm6GhoaamJoZhCKEXL17gQ/y9e/z4cYTQL7/8QrwMDw9XU1MrKCjo6Oi4e/eugYGBj4+PkqOBlD4fQDw3iOO4RCKZMmUKl8utqqoiN5jE4wPABAXnA1QK3B8w4Q2w+Ons2bO/+eab2tra8PDwnJycw4cPE4uN1tfX9wpSVVXl7e09ZcqUO3futLS0JCQkjEpu0dHR77///vr163V0dFasWLFy5Urii3CMcLncgwcPtra2bt26lWycxOMD1wXAROTr6zsq/3zAaIE6YMLrb/HT2trahw8fIoSMjIwOHDgwf/78hw8fWllZ6evrX7t2rdfG5eXlMpls69at1tbWLBaL+L07ckKhsKKioq6uTiaTVVVVZWRkjPVMIx9//PEf/vCHixcvkmeSYXwAAGAAUAdMeP0tflpbW7t58+Zff/1VKpWWlZU9e/bMycmJyWRGRkZev349KCiopqamp6entbX14cOHlpaWCKHi4uKuri6RSHTnzp1Rye3zzz+3tLQczynfMQxLTU3FMCwoKIhY+Q3GBwAABkL1KSLwv5S5PyAhIYFY4NXCwoJcXe3169fh4eGWlpYaGhpGRkY+Pj5CobCystLFxUVPT09dXX3q1Km7du3q7u4mtj9y5Ii9vT2LxWKxWPPmzUtPT8dxPDw8XF9fn8fj+fn5EY+/8/n84OBgExMThBCHw1mxYkVaWhox86iWlpanp2d6ejoxG/mMGTMqKiqOHTumo6ODEJo2bdpvv/2G43hJSYmBgQH5x8ZgMGbNmnX+/HllRgMNdt77hx9+sLGxISJPnTp18+bNZNf69esRQjwe78CBA7Qdn8kBrgtMPnBMVQ2Gww1HKiM3N9ff338yHZGMjAyRSESs4I4QkkqlO3fuzMjIaGpqIqqZAWAYlpOTM7kn1YHxGZSfnx9CKC8vj+pEwKiBY6pq4LlBMFZevnwZFBSkeGFeU1PT0tJSJpPJZLJBv+cmPRgfAIAqgPsDwFhhs9kMBuPkyZOvXr2SyWS1tbUnTpzYs2dPQEAAcXqc5mB8AACqAOoAMFZ0dXWvXbv2888/29jYsNlsOzu7zMzMgwcPnjp1iurUVAKMz1goLi6OiIg4f/68tbU1hmEYhq1bt05xA3d3dy6Xq66uPnv27Hv37lGSZEJCgq2tLZvN5nA4tra2UVFR5NoWCKGYmBg7OzsdHR0mkykQCHbs2KH8naSURL5w4UJCQsIwptUCqoLqGxTA/1JyHiGaQPS4D27YaDI+Q7qnbM+ePcuWLZNIJMRLPp9P3IbZa/booqIiLy+vUU50KDw8PA4fPiwWi1tbW3NzcxkMxgcffED2urm5paenNzQ0SCSSnJwcBoOxZMkSFY+ckpLi5ubW1NSkTCi4T1DVwPkAAEAfOjs7XVxcVC3UAA4ePJidnZ2bm8vlcsnG1NRUNTW1wMDAlpaWsU5AeZqamp999pmRkZG2trafn9/y5cv/53/+58WLF0SvtrZ2YGCgvr4+l8tduXKlt7f3lStXiHkqVTbytm3b3nrrraVLl3Z3dw99PADFoA4AAPTh5MmTYrFY1UL15/Hjx1FRUfv27VNcrwEh5OLiEhwcXFNTs3379jFNYEjy8/MV8zQzM0MIkafoL168qLjGhKGhIUKoo6NDlSMjhKKjo+/fv5+SkqJMNKBSoA4AYNLCcTwpKWnWrFlMJlNPT2/58uW//vor0RUUFKSpqUnMdoAQ+uyzzzgcDoZhxJzKwcHBYWFhFRUVGIYJBILU1FQWi2VsbLx582ZTU1MWi+Xi4kJOpjSkUAihK1eu6Ojo7N+/fxT3NDU1FcdxT0/PN7vi4uJsbGxOnDhRXFw81FHKyMjgcDhaWlqFhYUfffSRjo6Oubn52bNnyffK5fI9e/ZYWlqy2WwHBwfi0t5QiUQiHo83bdq0PntramrYbPb06dNVPLKenp6bmxuxOOcwAgIqUXtZAiiC+wMUIXpc/x42ZcZnz549mpqap0+fbm5ufvDgwfz58w0NDV++fEn0rlmzxsTEhNz40KFDCKG6ujripY+PD5/PJ3sDAwM5HM7Dhw+7urqEQqGjo6Piek5DCnXx4kUulxsTE6PMbip5Ldna2trOzq5XI5/Pf/r0KY7jN2/eVFNTs7Kyamtrw9+4P2DgUSJWivr2229bWlrEYrGrqyuHwyEXtt6+fTuTyTx37lxTU1NkZKSamtrdu3eV2S8cx6VSaXV1dVpaGpPJJOcE66W9vZ3L5QYFBSkZk9rIERERCKGysrKBg8D9AaoGzgcAMDl1dnYmJSWtWLFi7dq1urq69vb2R48era+vP3bs2PACamhoED+a7ezsMjIyWltbMzMzhxHHw8NDIpFERUUNL403tbe3P336lM/n97eBs7NzSEhIZWXlzp07e3UpOUouLi46OjpGRkYBAQHt7e1VVVUIoa6uroyMDG9vbx8fHx6Pt3v3bgaDofyYWFhYmJubR0dHJyYm+vv797lNfHy8qalpXFyckjGpjTxjxgyEUHl5+ZBiAspBHQDA5CQUCtva2hYsWEC2ODo6ampqjsriCAsWLNDS0iLPn1NLLBbjOE5M4dyfuLi4mTNnpqen37hxQ7F9qKOkqamJEJLJZAihR48edXR0zJkzh+his9lTpkxRfkyeP38uFou/+uqrU6dOzZs3781bKPLz83Nzc69evap456MqRyYOwatXr4YUE1AO6gAAJqfm5maEkLa2tmIjj8drbW0dlfhMJrOurm5UQo1QV1cXQojJZA6wDYvFyszMxDBsw4YNnZ2dZPtIRqm9vR0htHv3bux3z549U/K2O4QQg8EwMjJyd3fPzs4WCoXx8fGKvdnZ2QcPHiwtLbWyslIyIOWRiUkwicMBJhCoAwCYnHg8HkKo1/dZc3Ozubn5yIPLZLLRCjVyxNfPoPPYODs7h4aGikSi2NhYsnEko2RkZIQQSk5OVrzUeuvWraHmLxAI1NXVhUIh2ZKWlpaVlVVSUjJ16tShRqMqMkJIKpWi3w8HmECgDgBgcpozZ462tvaPP/5Itty5c0cqlb799tvESw0NDeL89jCUlpbiOO7k5DTyUCNnbGyMYZgyMwTExsba2tqWlZWRLYOO0gAsLCxYLJbiChHKaGhoWL16tWKLSCSSy+UWFhYIIRzHw8PDy8vLCwoKep2lUNnIJOIQECtwggkE6gAAJicWixUWFpafn5+VlSWRSMrLy7ds2WJqahoYGEhsIBAIGhsbCwoKZDJZXV3ds2fPFN+ur69fW1tbWVnZ2tpKfMf39PQ0NTV1d3c/ePAgODjY0tKSWN95qKGKiopG97lBLS0ta2vr6urqQbckrg4oPkM/6CgNHO3TTz89e/ZsRkaGRCKRy+XV1dXE1DoBAQEmJiZ9zlvM4XCuXbtWUlIikUhkMllZWdknn3zC4XBCQ0MRQg8fPkxMTDx+/DiDwcAUHD58mHi7CkYmEYfA3t5+0KEDKgXqAAAmrb1798bHx8fExBgaGrq5uVlZWZWWlnI4HKJ369atixYtWrVq1cyZM2NjY4nTuc7OzsQEc1u2bDE2Nrazs1u6dGljYyNCqKury97ens1mu7q62tjYfPfdd+Ql+aGGGnUeHh5CoZC88P/1118LBIKKigpHR8cvvvhCcUsnJ6de314DjFJGRgaxKrSDg8OTJ0+OHz8eFhaGEFqyZIlIJEIIpaSkhISEJCQkGBgYmJqaBgcHNzU1IYSkUqlYLC4sLHwzVRaLtXDhwo0bN5qZmXG5XD8/Pysrq9u3bxP3G+KDPXyvgpFJd+/eNTMzc3BwGPiDgMoZ/0cVQX9g/gBFCOYPGNA4jw8xH+24fRxJyWfNRSKRhoZGf8/Kjz+5XO7q6nry5En6RK6vr2exWIcPHx50S5g/QNXA+QAAgFJUeUE5gUAQExMTExOj/AJ6Y0culxcUFLS2tgYEBNAncnR09Ny5c4OCgkY3MTAOoA4AAEwGERERfn5+AQEBlC8pVFpaev78+aKiooGnNJhMkZOSku7fv3/58mUGgzG6iYFxAHUAAGAQkZGRmZmZLS0t06dPP3fuHNXp9Gv//v1BQUEHDhygNo3FixefOXOGXHBh0kcuLCx8/fp1aWmpnp7eqCcGxoEG1QkAAFRdfHx8rxljVJa7u7u7uzvVWdCLl5eXl5cX1VmA4YPzAQAAAAB9QR0AAAAA0BfUAQAAAAB9QR0AAAAA0BfcJ6hy/Pz8qE5BVSQnJ+fl5VGdheqiw/jcvn0bwT+KyeX27dvkyhRAFWD4YJNNgnFz69atpKQkqrMA9FJUVDRv3ryxeBQNgP4Qaz9SnQX4D6gDAKA1DMNycnJWrlxJdSIAAGrA/QEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANAX1AEAAAAAfUEdAAAAANCXBtUJAADGVXNzM47jii3t7e1NTU3kS21tbQaDMe55AQCogfX6PwIAYHJ7//33v/vuu/561dXVa2pqTExMxjMlAACF4LoAAPSyatUqDMP67FJTU/vjH/8IRQAAtAJ1AAD04uvrq6HR9wVBDMM+/vjjcc4HAEAtqAMAoBc9PT13d3d1dfU3u9TU1Ly9vcc/JQAAhaAOAIB21q5d29PT06tRQ0PDw8NDV1eXkpQAAFSBOgAA2vH09GQymb0a5XL52rVrKckHAEAhqAMAoB0tLS1vb+9eDwey2eylS5dSlRIAgCpQBwBAR6tXr5bJZORLBoPh6+vLZrMpTAkAQAmoAwCgow8//FDxVgCZTLZ69WoK8wEAUAXqAADoiMFgBAQEaGpqEi95PN7ixYupTQkAQAmoAwCgqVWrVkmlUoQQg8FYu3Ztf5MKAAAmN5hXGACa6unpmTp16qtXrxBCN27cWLhwIdUZAQAoAOcDAKApNTW1devWIYRMTU1dXFyoTgcAQA04E6iKbt269fz5c6qzAJOfoaEhQugPf/hDXl4e1bkAWli5ciXVKYDe4LqAKvLz8zt37hzVWQAAwCiDbxwVBNcFVJSvry9OG76+vrTa3wHk5OQghMbzE/Py8sbz40gIoZycHEo+GlCC+NsGKgjqAABozdfXl+oUAABUgjoAAAAAoC+oAwAAAAD6gjoAAAAAoC+oAwAAAAD6gjoAAAAAoC+oAwCY8C5fvqyrq/vNN99Qncj4KS4ujoiIOH/+vLW1NYZhGIYRcyOS3N3duVyuurr67Nmz7927R0mSCQkJtra2bDabw+HY2tpGRUVJJBKyNyYmxs7OTkdHh8lkCgSCHTt2tLW1qXLkCxcuJCQkyOVyJUOBiQLqAAAmPJxmc7Ps3bs3NTU1MjLSx8fnyZMnfD7fwMAgKyvr0qVL5DbXrl3Ly8tbtmyZUCicP38+JXl+//33mzZtqqqqevXqVWxsbEJCguJTmiUlJZ9//nllZWV9fX18fHxKSoqfn58qR/b09GSxWIsXL25ublYyGpgYqJ5bAvSBbvPq0G1/BzD+8wgNSUdHh7Oz86iEQsOdR+jAgQM2NjadnZ1kC5/PP3PmjJqampmZWXNzM9leVFTk5eU1CrkOl7e3t2KexJdxbW0t8dLDw6O7u5vsJSbcraqqUuXIOI4HBQU5OzvLZDJloilS8b9tOoPzAQAAZZ08eVIsFlOYwOPHj6Oiovbt28disRTbXVxcgoODa2pqtm/fTlVub8rPz1fM08zMDCFEnqK/ePGiuro62Uus9dDR0aHKkRFC0dHR9+/fT0lJUSYamBCgDgBgYrtx44alpSWGYUeOHEEIZWRkcDgcLS2twsLCjz76SEdHx9zc/OzZs8TGqampLBbL2Nh48+bNpqamLBbLxcXlzp07RG9QUJCmpuaUKVOIl5999hmHw8EwrL6+HiEUHBwcFhZWUVGBYZhAIEAIXblyRUdHZ//+/eO2s6mpqTiOe3p6vtkVFxdnY2Nz4sSJ4uLiPt+L43hSUtKsWbOYTKaent7y5ct//fVXomvgQUMIyeXyPXv2WFpastlsBweH4U2RKxKJeDzetGnT+uytqalhs9nTp09X8ch6enpubm4pKSk4za5GTWYUn48AfaHbeXK67e8AhnfulFidMi0tjXi5a9cuhNC3337b0tIiFotdXV05HI5UKiV6AwMDORzOw4cPu7q6hEKho6Mjl8slTxqvWbPGxMSEjHzo0CGEUF1dHfHSx8eHz+eTvRcvXuRyuTExMcPYUzSs6wLW1tZ2dna9Gvl8/tOnT3Ecv3nzppqampWVVVtbG/7GdYE9e/ZoamqePn26ubn5wYMH8+fPNzQ0fPnyJdE78KBt376dyWSeO3euqakpMjJSTU3t7t27SuYslUqrq6vT0tKYTObp06f73Ka9vZ3L5QYFBQ1hLKiLHBERgRAqKysbUky4LqCy4HwAAJOTi4uLjo6OkZFRQEBAe3t7VVUV2aWhoUH8LLazs8vIyGhtbc3MzBzGR3h4eEgkkqioqNHLeiDt7e1Pnz7l8/n9beDs7BwSElJZWblz585eXZ2dnUlJSStWrFi7dq2urq69vf3Ro0fr6+uPHTumuFmfg9bV1ZWRkeHt7e3j48Pj8Xbv3s1gMJQfMQsLC3Nz8+jo6MTERH9//z63iY+PNzU1jYuLUzImtZFnzJiBECovLx9STKCyoA4AYJLT1NRECMlksj57FyxYoKWlRZ4hV2VisRjHcS0trQG2iYuLmzlzZnp6+o0bNxTbhUJhW1vbggULyBZHR0dNTU3ymkgvioP26NGjjo6OOXPmEF1sNnvKlCnKj9jz58/FYvFXX3116tSpefPmvXmDRX5+fm5u7tWrV7lcrpIxqY1MHIJXr14NKSZQWVAHAEB3TCazrq6O6iwG19XVhRBiMpkDbMNisTIzMzEM27BhQ2dnJ9lOPOqmra2tuDGPx2ttbR30c9vb2xFCu3fvxn737NkzJW+7QwgxGAwjIyN3d/fs7GyhUBgfH6/Ym52dffDgwdLSUisrKyUDUh6ZzWaj3w8HmASgDgCA1mQyWXNzs7m5OdWJDI74+hl0HhtnZ+fQ0FCRSBQbG0s28ng8hFCvb30ld9zIyAghlJycrHhJ9datW0PNXyAQqKurC4VCsiUtLS0rK6ukpGTq1KlDjUZVZISQVCpFvx8OMAlAHQAArZWWluI47uTkRLzU0NDo7woC5YyNjTEMa2lpGXTL2NhYW1vbsrIysmXOnDna2to//vgj2XLnzh2pVPr2228PGs3CwoLFYt2/f39I2TY0NKxevVqxRSQSyeVyCwsLhBCO4+Hh4eXl5QUFBb3OUqhsZBJxCExMTIYUHKgsqAMAoJ2enp6mpqbu7u4HDx4EBwdbWlquX7+e6BIIBI2NjQUFBTKZrK6u7tmzZ4pv1NfXr62traysbG1tlclkRUVF4/ncoJaWlrW1dXV19aBbElcHFJ+hZ7FYYWFh+fn5WVlZEomkvLx8y5YtpqamgYGBykT79NNPz549m5GRIZFI5HJ5dXX1ixcvEEIBAQEmJiZ9zlvM4XCuXbtWUlIikUhkMllZWdknn3zC4XBCQ0MRQg8fPkxMTDx+/DiDwcAUHD58mHi7CkYmEYfA3t5+0KEDEwLUAQBMbEeOHHF0dEQIhYeHe3l5ZWRkJCcnI4QcHByePHly/PjxsLAwhNCSJUtEIhHxlq6uLnt7ezab7erqamNj891335EX3bdu3bpo0aJVq1bNnDkzNjaWOPfr7OxMPJq4ZcsWY2NjOzu7pUuXNjY2jv/Oenh4CIVC8sL/119/LRAIKioqHB0dv/jiC8UtnZycen177d27Nz4+PiYmxtDQ0M3NzcrKqrS0lMPhIIQGHbSUlJSQkJCEhAQDAwNTU9Pg4OCmpiaEkFQqFYvFhYWFb6bKYrEWLly4ceNGMzMzLpfr5+dnZWV16pxo+gAAIABJREFU+/Zt4n5DfLCH71UwMunu3btmZmYODg4DfxCYMMb/UUUwKLo9T0+3/R3AODxjHRgYqK+vP6YfoQw0rPkDRCKRhoZGf8/Kjz+5XO7q6nry5En6RK6vr2exWIcPHx7qG2H+AJUF5wMAoJ2Ju2ScQCCIiYmJiYlRfgG9sSOXywsKClpbWwMCAugTOTo6eu7cuUFBQaObGKAQ1AFgCJRfz3Tjxo1cLhfDsKHeXTWoR48effHFF7Nnz+ZyuRoaGrq6ujY2Nh4eHsO4f3uoBth9xQVwCZqamsbGxu+9996hQ4eIc8hgVERERPj5+QUEBChzw+CYKi0tPX/+fFFR0cBTGkymyElJSffv3798+TKDwRjdxACVqD4hAfqgsufJ3dzc0tPTGxoaJBJJTk4Og8FYsmRJfxsT07MrM/mo8vt74sQJBoPxxz/+8cqVK01NTV1dXRUVFdnZ2S4uLn/729+GsCfDMuju8/l8XV1dHMeJG/G+++679evXYxhmamqq5DS0Y33uNCIigpghx8rKKi8vb+w+aFBouOsNEq5evRoeHj6K+YBBFRQUxMfHK65kOCRwXUBlaVBahIAJRltbOzAwkLgNe+XKlefPn8/NzX3+/Hmvx4rGyO3btwMDA93c3K5evaqh8Z8/XWtra2trax6PR94EN3aU330Mw3g83nvvvffee+95eHj4+/t7eHj89ttvurq6Y53kwOLj43vNCTNBubu7u7u7U50FvXh5eXl5eVGdBRh9cF0ADMGQ1jPFMGx0Pz0uLk4ulx84cIAsAkgffvjh559/Prof96bhLefq6+u7fv16sVh89OjRsc0PAACGDuqAie306dMLFixgsVgcDsfKyoqYQA0f7vqqs2bNwjBMTU3t7bffJr7eduzYoaury2Kx/vGPf7z56b3WM8Vx/NChQzNnzmQymbq6uv/1X/81insqlUq//fZbAwODd955Z+Atqdr9ARBP5xcVFQ1hhwEAYHxQfF0C9EXJ6+XEE88HDhxoaGhobGz829/+tmbNGnwE66t2d3dbWVlZWloqXgIMCQnpNaMq4c31THft2oVh2H//9383NTV1dHSkp6ej0bs/4LfffkMIOTk5DRqNqt3HFe4P6EUikSCELCwsBk2ePtdQ0cjuDwATDn3+ticcOCqqSJnvRalUyuPxFi1aRLZ0d3enpKR0dHRoa2sHBASQ7f/v//0/hBC5SDzxRdjZ2Um8JL6tHz9+TLwkaovc3FziZXt7u6WlZUtLy5sJ7Nq1y8bGRiKREC87Ojq0tLQ++OADcoPRvU+QmBH2T3/608CbUbX7hP7qABzHiTsGBk4ep9P/K6EOoBv6/G1POHCf4ET14MGD5ubmDz/8kGxRV1fftm3bjz/+OOz1VRFCGzdujI6OTklJ8fPzQwhlZWUtX75cR0en17uI9UyvXbtGrmf6+PHjjo6OxYsXj94u/h/ETOmDXowfyfKyaAS7P7D29nYcx9+M0x/i0ye95OTkvLw8qrMA40SZCaEBJeD+gImKONVMrKKmaCTrqxJv/Otf/3rz5k3iZ/SXX3755oQhfa5nSvwjJ1ZmGwtWVlYsFou4OjAAqnZ/YETatra2Sm4PAADjBs4HTFTEcqL19fW92keyviohKCgoJSUlOTl5y5YtFhYWfD5fsTctLe3q1aslJSW9vmtZLBZC6PXr10PcD2UxmcwPP/ywsLDwhx9+WLhwYa/exsbGHTt2nDhxgqrdH9iVK1cQQh999JGS29PhVzKGYSEhIStXrqQ6ETBOcnNz/f39qc4C9AHOB0xUVlZW+vr6165d69U+kvVVCebm5itXrjx37lxUVFRwcDDZjg+4numcOXPU1NT+9a9/DWtvlBIdHc1kMkNDQ8llZkg///wz8TAhVbs/gJcvXyYnJ5ubm2/YsEH5dwEAwPiAOmCiYjKZkZGR169fDwoKqqmp6enpaW1tffjw4UjWVyWFhYV1d3c3NTW9//77ZOPA65kaGRn5+PicO3fu5MmTEonkwYMHx44dG91dnjt37pkzZ37++WdXV9fLly+3tLTIZLKnT58eP378L3/5CzHRKVW7T8JxvK2traenB8fxurq6nJychQsXqqurFxQUKH9/AAAAjB9K71IEfVN+nt0jR47Y29uzWCwWizVv3rz09HQcx3t6eg4dOjRjxgwGg6Gnp+ft7f3o0SNi+/T0dGJe8RkzZlRUVBw7doz4cpo2bdpvv/2mGHnRokUnTpxQbCkvL+/zT+jQoUPEBq2trRs3bjQwMNDW1n733Xf37NmDEDI3N//pp59Ga39xHK+qqtq+fbu9vb22tra6ujqPx5s3b95f/vKXH374gdiAkt2/cOGCg4ODlpaWpqammpoa+n1KwXfeeScmJqahoUHJvaPPPdUInhegGfr8bU84GD7YYtVg/BG3i9PhIjGBbvs7AOIaKh3+VWIYlpOTA/cH0Ad9/rYnHLguAAAAANAX1AEAAFVXXFwcERGhuLjzunXrFDdwd3fncrnq6uqzZ8++d+8eVXkihHp6epKTk11cXN7skslk8fHxAoFAU1OTx+PNmTOnsrJygka+cOFCQkKCXC5X/lOAyoI6AACg0vbu3ZuamhoZGenj4/PkyRM+n29gYJCVlXXp0iVym2vXruXl5S1btkwoFM6fP5+qVEUi0R//+MfQ0NA+J7zy9/f/5z//eebMmY6Ojl9++YXP57e1tU3QyJ6eniwWa/HixcSMHWBCg/kDAKCXzs7OxYsX37x5U6VC9efgwYPZ2dk//fQTMUEFITU1dd26dYGBgUKhkPKlnEk//fRTTEzMli1biOkje/VmZ2cXFBT89NNP9vb2CCFTU9PCwsIJHXnbtm1PnjxZunTp9evX31wCFEwgcD4AAHo5efKkWCxWtVB9evz4cVRU1L59+xSLAISQi4tLcHBwTU3N9u3bx+7Th+qtt946f/78mjVrmEzmm71ffvnl/PnziS/USRM5Ojr6/v37KSkpw/hooDqgDgBg4sH7X1s5KChIU1NzypQpxMvPPvuMw+FgGEZMPRkcHBwWFlZRUYFhmEAgSE1NZbFYxsbGmzdvNjU1ZbFYLi4u5FoMQwqFELpy5YqOjs7+/ftHazdTU1NxHPf09HyzKy4uzsbG5sSJE8XFxUMdooGXn0YIyeXyPXv2WFpastlsBwcH4oG3kZBKpbdv3547d+4I46haZD09PTc3t5SUFHgKYEKDOgCAiSc6OjoiImLXrl1isfj69evPnz93dXV99eoVQig1NVXxYbz09PR9+/aRL1NSUpYtW8bn83Ecf/z4cVBQ0Pr16zs6OrZt21ZZWXnv3r3u7u4PPvjg+fPnQw2FECLuGuvp6Rmt3bx06dLMmTOJKR96YbPZ//jHP9TU1DZt2tTe3v7mBgMM0datW0NCQjo7O7lcbk5OTkVFhbW19aZNm8jlpnbu3JmYmJicnPzixYtly5atXr1acYbKYaitrZVKpf/+978XLVpE1FuzZs0iZvsYSVhViDxv3ryampqffvpphB8HKAR1AAATTGdnZ1JS0ooVK9auXaurq2tvb3/06NH6+vphT+CooaFB/G62s7PLyMhobW3NzMwcRhwPDw+JRBIVFTW8NHppb29/+vRpr/UdFDk7O4eEhFRWVu7cubNXl5JD5OLioqOjY2RkFBAQ0N7eXlVVhRDq6urKyMjw9vb28fHh8Xi7d+9mMBjDGxAScW+dkZHR/v37hULhq1evli9f/vnnn3/11VcjCasKkWfMmIEQ6m+WLTAhQB0AwAQz1LWVh2TBggVaWlrkKXQKicViHMf7PBlAiouLmzlzZnp6+o0bNxTbR7L89KNHjzo6OubMmUN0sdnsKVOmjHBAiKvvs2fPdnFx0dfX19XV3bdvn66u7sjn3qY8MnGAiBMtYIKCOgCACWaEaysPislk1tXVjUqokejq6kK/fxv1h8ViZWZmYhi2YcMGxdWnRjJExFWG3bt3k0tIPHv2rM9n6pRnamqK/u/qoJqamtOmTauoqBhJWFWIzGaz0e8HC0xQUAcAMMGMfG3lAchkstEKNULEF8ygM9U4OzuHhoaKRKLY2FiycSRDZGRkhBBKTk5WnID91q1bw9gFkra29owZMx4+fKjY2N3dPfKHHimPLJVK0e8HC0xQUAcAMMEMurayhoYGecvbUJWWluI47uTkNPJQI2RsbIxhWEtLy6BbxsbG2tralpWVkS0jWX7awsKCxWLdv39/eGn3x9/fv6ys7MmTJ8TLjo6OZ8+eDe9hP5WKTBwgExOTkX8coArUAQBMMIOurSwQCBobGwsK/j97dx7X1JnvD/w5kISELQRFoCgoS92wLtVOiVqHYUpvZUAQENw66Iw/qrURsY7iCgi4DnCxYMdbh9YdFS+0V+l4nTvU+io6tyJoqbWAsrkhKIIkbMn5/XFeZnJZA4GchPN5/+VZ8j3Pec4x+XKW55vT3t7+9OnTyspKzY/b2to+fPiwoqKiqamJ+Y1XqVTPnz/v6Oi4detWVFSUs7NzRETEAELl5eUN4nuD5ubmrq6uNTU12nRIZmamqamp5pwBl58WCoUrVqw4depURkZGY2OjUqmsqal59OgRISQ8PNze3n5g4xZHR0e7uLhERERUVVXV19dv2rRJoVCon3A0xsgM5gANStoBrNFTXUPoj37V4R0GuLa/vdCyNmsvtZVpmq6vr/f29hYKhePGjfv44483btxICHF3d6+qqqJpurCw0MXFRSQSzZkz5/Hjx5GRkXw+38nJicfjWVtbBwYGlpeXDyzUxYsXraysEhIStNlTokXdYZlMxufz5XI5M3n+/Hnm9YGRI0euXbu208obN25csGCBNl3UZ/np1tbWTZs2OTs783g8Ozu74ODgkpISmqaDgoIIITt27Oi2tQUFBbNnz2ZuqxNCHBwcpFLpt99+q16hurp68eLFEonEzMzsrbfeysvLUy8yxsgMPz8/JycnlUrVbXxNqDtssHBUDBHXfhe5tr+90P93ZWRkpK2trT63yNAmDygtLeXxeMeOHdNPk/qkVCrnzp175MgRRGbU1dUJhcIDBw5oszLyAIOF+wIAXGewVePc3d3j4+Pj4+O1r5ozdJRKZU5OTlNTU3h4OCIzYmNjp02bJpPJhiI46A3yAAAwXDExMaGhoeHh4do8MDik8vPzs7Oz8/Lyeh/SgCORCSHJyclFRUUXL17k8/mDHhz0CXkAAHdt2bIlMzPzxYsX48aNO3fuHNvN6V5iYqJMJtu9eze7zfDx8Tlx4oS62gLHI+fm5ra2tubn50skkkEPDnqGYpEA3JWUlJSUlMR2K/rm6+vr6+vLdivgXxYsWLBgwQK2WwGDA9cDAAAAuAt5AAAAAHchDwAAAOAu5AEAAADchTwAAACAuyiaptluA3QWGhpqsC9xAQAMGH5xDBDyAENUUFBQXV3NdiuAE8LCwqKiory8vNhuCHDCokWL2G4CdIY8AIDTKIrKysrCtzMAZ+H5AAAAAO5CHgAAAMBdyAMAAAC4C3kAAAAAdyEPAAAA4C7kAQAAANyFPAAAAIC7kAcAAABwF/IAAAAA7kIeAAAAwF3IAwAAALgLeQAAAAB3IQ8AAADgLuQBAAAA3IU8AAAAgLuQBwAAAHAX8gAAAADuQh4AAADAXcgDAAAAuAt5AAAAAHchDwAAAOAu5AEAAADchTwAAACAu5AHAAAAcBfyAAAAAO5CHgAAAMBdyAMAAAC4C3kAAAAAdyEPAAAA4C7kAQAAANyFPAAAAIC7kAcAAABwF4/tBgCAXp06daqpqUlzzuXLlxsaGtSTQUFBdnZ2em8XALCDomma7TYAgP5ERER8+eWXfD6fmWS+ASiKIoQolUpLS8va2lozMzM2mwgAeoT7AgDcsnjxYkJI+ysdHR0dHR3Mv01NTUNDQ5EEAHAKrgcAcEtHR4e9vf2zZ8+6Xfr3v//9N7/5jZ6bBAAswvUAAG7h8XiLFy9W3xfQNHLkyHnz5um/SQDAIuQBAJyzePHi9vb2TjP5fP7y5ctNTU1ZaRIAsAX3BQA4h6ZpZ2fnmpqaTvP/+c9/zpo1i5UmAQBbcD0AgHMoilq2bFmnWwNjxoyZOXMmW00CALYgDwDgok63Bvh8fkREBPP2IABwCu4LAHDUhAkT7t69q5788ccfJ0+ezGJ7AIAVuB4AwFHLly9X3xqYNGkSkgAAbkIeAMBRy5Yt6+joIITw+fzf//73bDcHANiB+wIA3DVz5swbN25QFFVRUeHs7Mx2cwCABbgeAMBdH3zwASHkV7/6FZIAAM5iv95gcnJyQUEB260A4KKWlhaKolpbW0NDQ9luCwBHnT17lt0GsH89oKCg4Nq1a2y3AgzOuXPnug50A4NLKBTa29uPHj2a7Yb0pqam5ty5c2y3Qh9wznONgZzb7D8fwPwhwnpCBIaGoqisrKxFixax3ZBhrqyszN3dne1W9ObMmTNhYWGsf1PpAc55rjGQc5v96wEAwCIDTwIAYKghDwAAAOAu5AEAAADchTwAAACAu5AHAAAAcBfyAAAYhi5evCgWi7/++mu2GzJULl++HBMTk52d7erqSlEURVHLly/XXMHX19fKysrU1HTy5MmFhYVstZMQolKpUlJSpFJp10Xt7e1JSUnu7u4CgcDGxsbT07OiosJII3/11Vd79+5VKpXab8VAIA8AgGGI9XexhtTOnTvT0tK2bNkSHBx87949Nze3ESNGHD9+/MKFC+p1Ll26dPbsWX9//5KSkhkzZrDV1NLS0nfeeSc6Oloul3ddGhYWdvTo0RMnTsjl8jt37ri5ub18+dJIIwcEBAiFQh8fn4aGBi03ZCDYH08QAGDQ+fn5vXjxQg8bUigUPj4+33//vR62xdizZ8/p06eLi4uFQqF6Zlpa2vLlyyMjI0tKSsRisd4a07vi4uL4+PjVq1c3Nzd3zcxOnz6dk5NTXFw8ZcoUQoijo2Nubq5RR163bt29e/fmz59/5coVHs9ofl5xPQAAYOCOHDlSW1urt82VlZVt3749Li5OMwkghEil0qioqAcPHnzyySd6a0yfpk6dmp2dvXTpUjMzs65LDx06NGPGDOYHddhEjo2NLSoqSk1NHcCm2YI8AACGm6tXrzo7O1MU9emnnxJCMjIyLCwszM3Nc3Nz33//fWtr69GjR586dYpZOS0tTSgUjho16sMPP3R0dBQKhVKp9Pr168xSmUwmEAgcHByYyY8++sjCwoKiqLq6OkJIVFTUhg0bysvLKYpiRmT65ptvrK2tExMTh2jX0tLSaJoOCAjouighIeH111///PPPL1++3O1naZpOTk6eOHGimZmZRCIJDAz8+eefmUW9dxEhRKlU7tixw9nZWSQSvfHGG1lZWTruSFtb27Vr16ZNm6ZjHEOLLJFI5s2bl5qaakR3ppAHAMBwM2fOHM0L9WvWrFm/fr1CobCyssrKyiovL3d1dV21alV7ezshRCaTRUREyOXydevWVVRUFBYWdnR0vPvuu9XV1YSQtLQ0zYF+09PT4+Li1JOpqan+/v5ubm40TZeVlRFCmMfEVCrVEO3ahQsXxo8fb25u3nWRSCT64osvTExMVq1a1dzc3HWF2NjYmJiYrVu31tbWXrlypbq6eu7cuU+ePCF9dREhZPPmzfv27UtJSXn06JG/v/+SJUt++OEHXXbk4cOHbW1tN27c8Pb2ZtKviRMnpqen6/7zyXrk6dOnP3jwoLi4WMfN6Q3yAADgCqlUam1tbWdnFx4e3tzcXFVVpV7E4/GYP5QnTZqUkZHR1NSUmZk5gE34+fk1NjZu37598Fr9L83Nzffv33dzc+tpBS8vr/Xr11dUVGzevLnTIoVCkZycvHDhwmXLlonF4ilTpnz22Wd1dXWHDx/WXK3bLmppacnIyAgKCgoODraxsdm2bRufzx9Y/6gxz9bZ2dklJiaWlJQ8efIkMDBw7dq1J0+e1CWsIUT28PAghNy+fVvHzekN8gAA4ByBQEAIUf+x28nMmTPNzc3V18wNR21tLU3T3V4MUEtISBg/fnx6evrVq1c155eUlLx8+XLmzJnqObNmzRIIBOo7IJ1odtHdu3flcrmnpyezSCQSOTg46Ng/zN33yZMnS6VSW1tbsVgcFxcnFos75SXGGJk5QMyFFqOAPAAAoDMzM7OnT5+y3YrOWlpayKtfo54IhcLMzEyKolauXKlQKNTzmZfZLC0tNVe2sbFpamrqc7vMXYZt27ZRr1RWVnb7Tp32HB0dCSHMYxYMgUDg4uJSXl6uS1hDiCwSicirg2UUkAcAAPwf7e3tDQ0No0ePZrshnTE/MH2OVOPl5RUdHV1aWrpr1y71TBsbG0JIp199LXfTzs6OEJKSkkJrKCgoGMAuqFlaWnp4ePz000+aMzs6OnR/6ZH1yG1tbeTVwTIKyAMAAP6P/Px8mqbffvttZpLH4/V0B0HPRo0aRVGUNuMi7Nq1a8KECTdv3lTP8fT0tLS01Hy47/r1621tbW+++Waf0caMGSMUCouKigbW7J6EhYXdvHnz3r17zKRcLq+srBzYy34GFZk5QPb29rpvTj+QBwAAEJVK9fz5846Ojlu3bkVFRTk7O0dERDCL3N3dnz17lpOT097e/vTp08rKSs0P2traPnz4sKKioqmpqb29PS8vb+jeGzQ3N3d1da2pqelzTebugKmpqeacDRs2nD9//vjx442Njbdv3169erWjo2NkZKQ20VasWHHq1KmMjIzGxkalUllTU/Po0SNCSHh4uL29/cDGLY6OjnZxcYmIiKiqqqqvr9+0aZNCoVA/4WiMkRnMARqUtENPaLaFhISEhISw3QowOISQrKwstlsB7GNeVe/XRw4ePMi88W9ubh4QEJCens48uuXh4VFeXn748GFra2tCiIuLyy+//ELTdGRkJJ/Pd3Jy4vF41tbWgYGB5eXl6mj19fXe3t5CoXDcuHEff/zxxo0bCSHu7u5VVVU0TRcWFrq4uIhEojlz5jx+/PjixYtWVlYJCQkD2FNtznmZTMbn8+VyOTN5/vx55vWBkSNHrl27ttPKGzduXLBggXpSpVLt37/fw8ODz+dLJJKgoKC7d+8yi/rsotbW1k2bNjk7O/N4PDs7u+Dg4JKSEpqmg4KCCCE7duzotrUFBQWzZ89mbqsTQhwcHKRS6bfffqteobq6evHixRKJxMzM7K233srLy1MvMsbIDD8/PycnJ5VK1W18TQM4t4cC+y1AHgDdQh4ADD18V0ZGRtra2g7pJrShzTlfWlrK4/GOHTumnyb1SalUzp0798iRI4jMqKurEwqFBw4c0GZlA8kDcF8AAKDvh+8MhLu7e3x8fHx8vPZVc4aOUqnMyclpamoKDw9HZEZsbOy0adNkMtlQBB8iyAMAAIxJTExMaGhoeHi4fgop9SI/Pz87OzsvL6/3IQ04EpkQkpycXFRUdPHiRT6fP+jBh45x5AGzZs0yNTUdivGiCSErVqwQCoUURRnR6569OHDgAPNQ8WeffcbMGdxC7IZT1l2z8jqDx+ONHDnyt7/97fnz5wdrK72fHgZe/Z07J4MutmzZkpmZ+eLFi3Hjxp07d47t5mglMTFRJpPt3r2b3Wb4+PicOHFCXXyB45Fzc3NbW1vz8/MlEsmgBx9SxpEH/O///q+3t/cQBc/MzDSoCl06+uSTTzqVQKUHtdzF4EbThbryulgsZu5yPX36NCsr68GDB8HBwbrXQWH0fnoYePV37pwMukhKSmptbaVp+v79+yEhIWw3R1u+vr579uxhuxXwLwsWLIiJidF8R8NYGEcewKAoqr8fUSgUUql0KBpjRJhC7P7+/gP7eKc+1DHakJJIJD4+Pv/+7/9OCDlz5kyf6w/i6ZGWlmZiYhIZGcn6pdrecedkAAAtGVMeMIA7Lv0qDT6APIML9FxeXXdjx44lr0ZR7d0gnh6GWf190BndyQAAfTKmPKCsrGzChAkWFhYikWju3LmaVTS+++67SZMmicVioVA4ZcqUv/3tb6S70uCEkGPHjs2cOVMoFFpYWIwdO1Y97qaJicmFCxfef/99sVjs6Oj417/+VZsm9Vm0m+654Pe+ffvMzc2trKxqa2s3bNjg5OS0evVqCwsLExOTN998097ens/nW1hYzJgxY+7cucx4XjY2Nn/605963+tOOhViLysro7r47//+by37sFO03newz84ZIrdu3SKEzJs3Tz1HP6eHLtXfcTIAAGtYeVtRk5bjB/j4+Li6ut6/f7+9vf3HH3/81a9+JRQKmQEuaJo+e/ZsbGzss2fP6uvr33777REjRjDzg4ODmdLgjJSUFELI7t276+vrnz179pe//GXp0qU0TW/dupUQ8ve//72hoeHZs2fz5883MzNrbm7Wpv3qz7548aK2tnbu3LkWFhZtbW3M0h07dggEgmPHjjU0NNy6dWvGjBkjR458/Pix5mfXrVt38ODBhQsX3rlzZ+fOnYSQ69evNzc319XV/du//Rsh5MKFC0+fPm1ubmbeRSkqKup9r0tLSwkhhw4dYiaZMuoHDx5kFm3evJnZtUePHkkkEqlUqlQqte9DzWha7mBPndM7ot34AZrPB8jl8ry8PBcXF19f35cvX6rXGerTw83N7f79+zRNf//99yYmJmPHjmW2npeXpzmKC06GgZ0MBvKOtR5oec7DsGEg5zb7LdA+D5g6dap6kvmb75NPPum6ZlJSEnlVoFPza6utrc3Gxsbb21u9ZkdHR2pqKv3qG0qhUDDzjx49Sgj58ccftWl/p8+mp6cTQsrKymialsvllpaW4eHh6pX/+c9/EkLi4+O7/SxN08xXf1NTEzP55ZdfEkJu376t+fHTp0/3vte9fPVrCgoKEgqFP//8c+/Revnq7+8OanZOn7TPAzqltlOmTPnyyy+ZJ7+03zVdTg91HkDT9IYNGwghzMhumnkAToYBnwwG8l2pB8gDuMYoNJVvAAAgAElEQVRAzm3eQK4hGIApU6aIxWImG+iEeYyg66ggt27damhoeO+999RzTE1N161b11OEgVUW0Sza3d+C3z1F6+jo6LNhPe11T86cOfOf//mfe/fuHT9+/ICj6VLRfBCJxWLmaYCOjo4nT55cunRJJpMlJSVdvXp15MiRnVYe6tMjISHhv/7rv9LT08PCwjTn42TopL8nA0ce3wkLC+t05gAMNWPNAwghfD5f/SVy4cKF/fv3l5SUNDY29vTN0tjYSF4V39QPXQp+a0Obve5WfX39xx9/PGvWLOaP1wFHG+od7C8ej+fk5LRixQqlUrlq1ardu3f/+c9/Jvo9PZj6LnPmzFm5cuXevXvV83Ey6GiwXgQ1ZGFhYVFRUV5eXmw3BPSkoKAgNTWV7VYYbR7Q0dHx7NkzZ2dnQkhVVVVQUNDChQv/+te/vvbaawcPHtR8fkrttddeI4TU1dXprZG6FPzuk5Z73a1169Y1NDT8z//8j/pV14FFG9Id1AVT6YspE67/04Op/n7gwIFdu3YxpyjByaCzRYsWDUocQxYWFubl5cWFPQU1Q8gDjOl9AU3/+Mc/VCoVMzzL7du329vb16xZ4+rqygz91u1Hxo4da2tre+nSJb01UpeC333Scq+7unDhwokTJ7Zv3z558mRmzsaNGwcWbUh3UBc3btwghDBXuVk5PQa3+nufcDIAwIAZUx7Q1tb24sWLjo6OwsJCmUzGFIEmhDB/cl2+fLmlpaW0tFTzfqRmaXATE5MtW7ZcuXJFJpM9ePBApVI1NTUxfzIOEV0Kfvepl73uRWNj44cffjht2jSmYHZLS8sPP/xQVFSkZR92ukQ8pDvYLwqFgqny+fDhw8zMzG3bto0cOXL9+vWEpdNjcKu/9wknAwAMHNsPKmr7vkBmZqa3t/eoUaN4PN6IESMWL15cWVmpXrpp0yZbW1sbG5vQ0FDmbWY3N7eqqqpOpcFpmv7000+nTJkiFAqFQuH06dPT09P37t0rEonIq8Lbx48fZ0aHHj16dJ+vDPRZtLuXgt/q7Y4ZM4apIpqamspEGzt27Hfffbdnzx6xWEwIsbe3P3HixOnTp+3t7QkhEonk1KlTPe11VFQUs5qFhcXChQs7FWI/cOBA13Ng/vz5Wvbhtm3bNKP1voN9dk7vSF/PTqsrr2syMzPz8PBYs2YNUxt+qE+Pwar+jpOhFwbyTLUe9HnOwzBjIOc2RbM9QnhoaCgh5OzZs+w2AwwNRVFZWVm4VwpnzpwJCwtj/ZtKD3DOc42BnNvGdF8AAAAABhfygN78/PPPXQdeVQsPD2e7gQDAUZcvX46JiTHwytcMlUqVkpLSbU2v9vb2pKQkd3d3gUBgY2Pj6elZUVFhpJG/+uqrvXv3aj9uh+FAHtCbCRMm9HJP5fTp02w3EAC4aOfOnWlpaVu2bDHwyteEkNLS0nfeeSc6Oloul3ddGhYWdvTo0RMnTsjl8jt37ri5ub18+dJIIwcEBAiFQh8fH22KnBkUYx0/AABgsCgUCh8fn++//96gQvVkz549p0+fLi4uFgqF6plpaWnLly+PjIwsKSlhHik1BMXFxfHx8atXr2bKWHRaevr06ZycnOLiYmbAD0dHx9zcXKOOvG7dunv37s2fP//KlSs8ntH8vOJ6AABw3SDWUx7q0sxlZWXbt2+Pi4vTTAKIoVa+njp1anZ29tKlS83MzLouPXTo0IwZM5gf1GETOTY2tqioyBBGB9Ie8gAAGA7onqsey2QygUDAvOVICPnoo48sLCwoimKGj+xUTzktLU0oFI4aNerDDz90dHQUCoVSqVQ9iEK/QhFCvvnmG2tr68TExMHazbS0NJqmAwICui7SpfJ1n4WhlUrljh07nJ2dRSLRG2+8ofswz21tbdeuXZs2bZqOcQwtskQimTdvHlOibNAbMESQBwDAcBAbGxsTE7N169ba2torV65UV1fPnTv3yZMnhJC0tDTNl/HS09Pj4uLUk6mpqf7+/kwdxbKyMplMFhERIZfL161bV1FRUVhY2NHR8e677zLFFfsViryqz6RSqQZrNy9cuDB+/HhmMIZORCLRF198YWJismrVqubm5q4r9NJFa9asWb9+vUKhsLKyysrKKi8vd3V1XbVqlXq0qM2bN+/bty8lJeXRo0f+/v5LlizRHDtyAB4+fNjW1nbjxg1vb28m35o4cWJ6erruP5+sR54+ffqDBw+Ki4t13JzeIA8AAKOnUCiSk5MXLly4bNkysVg8ZcqUzz77rK6u7vDhwwMLyOPxmL+bJ02alJGR0dTUlJmZOYA4fn5+jY2N27dvH1gzOmlubr5//37X4bPUvLy81q9fX1FRwYwRqUnLLpJKpdbW1nZ2duHh4c3NzVVVVYSQlpaWjIyMoKCg4OBgGxubbdu28fn8gXWIGvNsnZ2dXWJiYklJyZMnTwIDA9euXXvy5EldwhpCZA8PD0LI7du3ddyc3iAPAACjp3tZ517MnDnT3NxcfQmdRbW1tTRNd3sxQC0hIWH8+PHp6elXr17VnK9LYei7d+/K5XJPT09mkUgkcnBw0LFDmLvvkydPlkqltra2YrE4Li5OLBYPOHUznMjMAWIutBgF5AEAYPSGuuqxmZnZ06dPByWULlpaWsirX6OeMLUtKIpauXKlQqFQz9eli5i7DNu2bVOPnlJZWdntO3Xac3R0JP+3wqdAIHBxcSkvL9clrCFEZsYIZw6WUUAeAABGb0irHre3txtCNW3y6gemz5FqmMrXpaWlu3btUs/UpYvs7OwIISkpKZoDqBQUFAxgF9QsLS09PDw6lfLq6OjQ/aVH1iO3tbWRVwfLKCAPAACj12fVYx6P16lAovby8/Npmn777bd1D6WjUaNGURT14sWLPtcc3MrXY8aMEQqFRUVFA2t2T8LCwm7evHnv3j1mUi6XV1ZWDuxlP4OKzBwgpsSXUUAeAABGr8+qx+7u7s+ePcvJyWlvb3/69GllZaXmx7vWU1apVM+fP+/o6Lh161ZUVJSzszNT5by/ofLy8gbxvUFzc3NXV9eamhptOmQQK18LhcIVK1acOnUqIyOjsbFRqVTW1NQ8evSIEBIeHm5vbz+wcYujo6OZ8vFVVVX19fWbNm1SKBTqJxyNMTKDOUCDknboyeCWLxwALesOA9cQ1GAFmqa1rs3aS9Vjmqbr6+u9vb2FQuG4ceM+/vjjjRs3EkLc3d2Z+tSdKlBHRkby+XwnJycej2dtbR0YGFheXj6wUBcvXrSyskpISNBmT7U552UyGZ/Pl8vlzORgVb7uszB0a2vrpk2bnJ2deTyenZ1dcHBwSUkJTdNBQUGEkB07dnTb2oKCgtmzZzO31QkhDg4OUqn022+/Va9QXV29ePFiiURiZmb21ltv5eXlqRcZY2SGn5+fk5OTSqXqNr4mA6k7zH4LkAdAt5AHAEP/35WRkZG2trb63CJDm3O+tLSUx+MdO3ZMP03qk1KpnDt37pEjRxCZUVdXJxQKDxw4oM3KBpIH4L4AAEBnBls1zt3dPT4+Pj4+XvuqOUNHqVTm5OQ0NTUNevFVY4zMiI2NnTZtmkwmG4rgQwR5AACAMYmJiQkNDQ0PD9fmgcEhlZ+fn52dnZeX1/uQBhyJTAhJTk4uKiq6ePEin88f9OBDB3kAAMC/bNmyJTMz88WLF+PGjTt37hzbzeleYmKiTCbbvXs3u83w8fE5ceKEutoCxyPn5ua2trbm5+dLJJJBDz6kjKYwIgCAHiQlJSUlJbHdir75+vr6+vqy3Qr4lwULFixYsIDtVgwErgcAAABwF/IAAAAA7kIeAAAAwF3IAwAAALjLIJ4TrKmpOXPmDNutAIOjYyETGB6Y04AjXxE45znFUA432wMZ0SEhIWz3AQAAADvY/hGmKZqm2e4EAGANRVFZWVmLFi1iuyEAwA48HwAAAMBdyAMAAAC4C3kAAAAAdyEPAAAA4C7kAQAAANyFPAAAAIC7kAcAAABwF/IAAAAA7kIeAAAAwF3IAwAAALgLeQAAAAB3IQ8AAADgLuQBAAAA3IU8AAAAgLuQBwAAAHAX8gAAAADuQh4AAADAXcgDAAAAuAt5AAAAAHchDwAAAOAu5AEAAADchTwAAACAu5AHAAAAcBfyAAAAAO5CHgAAAMBdyAMAAAC4C3kAAAAAdyEPAAAA4C7kAQAAANyFPAAAAIC7kAcAAABwF/IAAAAA7kIeAAAAwF0UTdNstwEA9CcyMvLu3bvqycLCwnHjxkkkEmbS1NT0yy+/HD16NEutAwB947HdAADQK3t7+8OHD2vOuXXrlvrfrq6uSAIAOAX3BQC4ZcmSJT0tEggEERERemwLALAP9wUAOMfT0/Onn37q9v/+3bt3X3/9df03CQDYgusBAJzzwQcfmJqadppJUdTUqVORBABwDfIAAM5ZvHixUqnsNNPU1PT3v/89K+0BABbhvgAAF0ml0uvXr6tUKvUciqKqq6udnJxYbBUA6B+uBwBw0fLlyymKUk+amJjMmTMHSQAAByEPAOCi0NBQzUmKoj744AO2GgMALEIeAMBFI0eO9PHxUT8tSFFUUFAQu00CAFYgDwDgqGXLljGPB5mamr733nsjRoxgu0UAwALkAQActXDhQoFAQAihaXrZsmVsNwcA2IE8AICjLCwsfve73xFCBAKBv78/280BAHYgDwDgrqVLlxJCgoKCLCws2G4LALAD4wfoyZkzZ8LCwthuBQCAcQgJCTl79izbreAE1BvUq6ysLLabYKAKCgpSU1PRP/2SkpJCCFm/fr0uQY4fPx4eHs7jGe5XAc4NDmLObdAPw/3PPywtWrSI7SYYrtTUVPRPvzB/LenYaQEBAUKhcJBaNFRwbnANrgToE54PAOA0w08CAGBIIQ8AAADgLuQBAAAA3IU8AAAAgLuQBwAAAHAX8gAAbrl48aJYLP7666/ZbshQuXz5ckxMTHZ2tqurK0VRFEUtX75ccwVfX18rKytTU9PJkycXFhay1U5CiEqlSklJkUqlXRe1t7cnJSW5u7sLBAIbGxtPT8+KigojjfzVV1/t3btXqVRqvxXQJ+QBANwyvIcO27lzZ1pa2pYtW4KDg+/du+fm5jZixIjjx49fuHBBvc6lS5fOnj3r7+9fUlIyY8YMtppaWlr6zjvvREdHy+XyrkvDwsKOHj164sQJuVx+584dNze3ly9fGmlk5t1UHx+fhoYGLTcE+oTxAwC4xc/P78WLF3rYkEKh8PHx+f777/WwLcaePXtOnz5dXFys+TJkWlra8uXLIyMjS0pKxGKx3hrTu+Li4vj4+NWrVzc3N3fNzE6fPp2Tk1NcXDxlyhRCiKOjY25urlFHXrdu3b179+bPn3/lyhVDHrSKm3A9AACGxJEjR2pra/W2ubKysu3bt8fFxXUaEUEqlUZFRT148OCTTz7RW2P6NHXq1Ozs7KVLl5qZmXVdeujQoRkzZjA/qMMmcmxsbFFRUWpq6gA2DUMKeQAAh1y9etXZ2ZmiqE8//ZQQkpGRYWFhYW5unpub+/7771tbW48ePfrUqVPMymlpaUKhcNSoUR9++KGjo6NQKJRKpdevX2eWymQygUDg4ODATH700UcWFhYURdXV1RFCoqKiNmzYUF5eTlGUu7s7IeSbb76xtrZOTEwcol1LS0ujaTogIKDrooSEhNdff/3zzz+/fPlyt5+laTo5OXnixIlmZmYSiSQwMPDnn39mFvXeRYQQpVK5Y8cOZ2dnkUj0xhtv6D7+cVtb27Vr16ZNm6ZjHEOLLJFI5s2bl5qaOrzvTBkj5AEAHDJnzhzNC/Vr1qxZv369QqGwsrLKysoqLy93dXVdtWpVe3s7IUQmk0VERMjl8nXr1lVUVBQWFnZ0dLz77rvV1dWEkLS0NM2xftPT0+Pi4tSTqamp/v7+bm5uNE2XlZURQpjHxFQq1RDt2oULF8aPH29ubt51kUgk+uKLL0xMTFatWtXc3Nx1hdjY2JiYmK1bt9bW1l65cqW6unru3LlPnjwhfXURIWTz5s379u1LSUl59OiRv7//kiVLfvjhB1125OHDh21tbTdu3PD29mbSr4kTJ6anp+v+88l65OnTpz948KC4uFjHzcHgQh4AAEQqlVpbW9vZ2YWHhzc3N1dVVakX8Xg85g/lSZMmZWRkNDU1ZWZmDmATfn5+jY2N27dvH7xW/0tzc/P9+/fd3Nx6WsHLy2v9+vUVFRWbN2/utEihUCQnJy9cuHDZsmVisXjKlCmfffZZXV3d4cOHNVfrtotaWloyMjKCgoKCg4NtbGy2bdvG5/MH1j9qzLN1dnZ2iYmJJSUlT548CQwMXLt27cmTJ3UJawiRPTw8CCG3b9/WcXMwuJAHAMC/CAQCQoj6j91OZs6caW5urr5mbjhqa2tpmu72YoBaQkLC+PHj09PTr169qjm/pKTk5cuXM2fOVM+ZNWuWQCBQ3wHpRLOL7t69K5fLPT09mUUikcjBwUHH/mHuvk+ePFkqldra2orF4ri4OLFY3CkvMcbIzAFiLrSA4UAeAAD9YGZm9vTpU7Zb0VlLSwt59WvUE6FQmJmZSVHUypUrFQqFej7zMpulpaXmyjY2Nk1NTX1ul7nLsG3bNuqVysrKbt+p056joyMhhHnMgiEQCFxcXMrLy3UJawiRRSIReXWwwHAgDwAAbbW3tzc0NIwePZrthnTG/MD0OVKNl5dXdHR0aWnprl271DNtbGwIIZ1+9bXcTTs7O0JISkoKraGgoGAAu6BmaWnp4eHx008/ac7s6OjQ/aVH1iO3tbWRVwcLDAfyAADQVn5+Pk3Tb7/9NjPJ4/F6uoOgZ6NGjaIoSptxEXbt2jVhwoSbN2+q53h6elpaWmo+3Hf9+vW2trY333yzz2hjxowRCoVFRUUDa3ZPwsLCbt68ee/ePWZSLpdXVlYO7GU/g4rMHCB7e3vdNweDCHkAAPRGpVI9f/68o6Pj1q1bUVFRzs7OERERzCJ3d/dnz57l5OS0t7c/ffq0srJS84O2trYPHz6sqKhoampqb2/Py8sbuvcGzc3NXV1da2pq+lyTuTtgamqqOWfDhg3nz58/fvx4Y2Pj7du3V69e7ejoGBkZqU20FStWnDp1KiMjo7GxUalU1tTUPHr0iBASHh5ub28/sHGLo6OjXVxcIiIiqqqq6uvrN23apFAo1E84GmNkBnOABiXtgMFEg14wbxWz3QrDhf4ZgJCQkJCQkH595ODBg8wb/+bm5gEBAenp6cyjWx4eHuXl5YcPH7a2tiaEuLi4/PLLLzRNR0ZG8vl8JycnHo9nbW0dGBhYXl6ujlZfX+/t7S0UCseNG/fxxx9v3LiREOLu7l5VVUXTdGFhoYuLi0gkmjNnzuPHjy9evGhlZZWQkNDf3dTy3JDJZHw+Xy6XM5Pnz59nXh8YOXLk2rVrO628cePGBQsWqCdVKtX+/fs9PDz4fL5EIgkKCrp79y6zqM8uam1t3bRpk7OzM4/Hs7OzCw4OLikpoWk6KCiIELJjx45uW1tQUDB79mzmtjohxMHBQSqVfvvtt+oVqqurFy9eLJFIzMzM3nrrrby8PPUiY4zM8PPzc3JyUqlU3cbXNIBzGwYM37x6gt+53qF/BkAP35WRkZG2trZDuok+aXlulJaW8ni8Y8eO6aFJ2lAqlXPnzj1y5AgiM+rq6oRC4YEDB7RZGXmAPuG+AAD0xljKxLm7u8fHx8fHx2tfNWfoKJXKnJycpqam8PBwRGbExsZOmzZNJpMNRXDQBfKAYWUoSsoabJnakydPUhTVbf1T7XGqx4a9mJiY0NDQ8PBw/RRS6kV+fn52dnZeXl7vQxpwJDIhJDk5uaio6OLFi3w+f9CDg46QBwwr9BAM3D0UMQfFyZMn3dzcCgoKmGFrB4ZTPdZfW7ZsyczMfPHixbhx486dO8d2c7SSmJgok8l2797NbjN8fHxOnDihLr7A8ci5ubmtra35+fkSiWTQg8MgYPe2BHcM0f1vuVzu5eVl+DH71N/+qaurGzdu3PHjxwkh27dv1/6Dw6bHaM7cQ8WzIxzEkXPbQOB6gHEbitKuei4XOzBnzpzx8/MLCAgQCoXMo2FafpCzPQYA0C3kAYblu+++mzRpklgsFgqFU6ZM+dvf/qZedOzYsZkzZwqFQgsLi7Fjx+7atatTaddOJWUnTpxIUZSJicmbb77JDHT6pz/9iYn8xRdf9LSt3mMS3Sq0DqKTJ08uXLjQysrK19e3oqLiu+++67oOegwAoG8sX4/gDC2vbZ49ezY2NvbZs2f19fVvv/32iBEjmPkpKSmEkN27d9fX1z979uwvf/nL0qVLaZoODg5mSrsymIKwBw8epGm6o6Nj7Nixzs7OHR0d6hXWr1+vHgO1p231EpOm6R07dggEgmPHjjU0NNy6dWvGjBkjR458/Pgxs3Tr1q2EkL///e8vXryora2dO3euhYVFW1vbYPUPo7Ky0s7OjtmvY8eOEUL+8Ic/dFpn2PcYzZlrp7gvwEEcObcNBK4HGJaQkJCdO3dKJBJbW9uAgID6+vqnT5+2t7fHxcV5e3tv3rzZ1tZWIpH84Q9/mDVrVu+hTE1N161bV1VVdf78eWaOXC7Pzs5euXJlL9vqPaYuFVoH0cmTJ3/3u98xQ8IFBASYmZmdPXtWs3IMegwAQEs8thsAPWJesFEqlbdu3WpoaHjvvffUi5hfrD4j/PGPf4yNjU1NTQ0NDSWEHD9+PDAwkBkNradt9R5Qlwqtg+jkyZNJSUnMv62trX19fb/++uvc3Fz1e8/c6bGampozZ85oubKRYsr2DPvdBE01NTUGWM5quEIeYFguXLiwf//+kpKSxsZG9Y9BY2MjeVUVrV8sLS3/3//7f/v37//nP//51ltvHTp0SPPtr2631TtdKrQOlh9//PH27dv+/v6d5h89elSdB3Cnx65duxYWFjYooQwcR3YT1EJCQthuAlfgvoABqaqqCgoKcnBwuH79+osXL/bu3cvMf+2118j/re2tPWbQ9ZSUlCtXrowZM4YZcb2XbfVOlwqtg+XEiROLFy/WvLn17NkzkUh06dKlx48fM+twp8e4cA8VzwdwEJIAfUIeYEBu377d3t6+Zs0aV1dXoVBIURQzf+zYsba2tpcuXRpAzNGjRy9atOjcuXPbt2+Piorqc1u906VC66Cgafr06dMfffSR5kyJRBIaGqpUKk+ePMnMQY8BAGgJeYABcXZ2JoRcvny5paWltLRUfQvZzMxsy5YtV65ckclkDx48UKlUTU1NP/30E+lS2rXbsBs2bOjo6Hj+/PlvfvObPrfVe0xdKrQOiu+//97a2nr27Nmd5q9evZoQcvToUWYSPQYAoC22L/9whZbXNjdt2mRra2tjYxMaGsq8gO7m5sZUcf3000+nTJkiFAqFQuH06dPT09Pp/1vaddu2bZolZTXDent7f/7551puq/eYulRo1bF//vCHP1hYWPB4vKlTpxYWFqrn79q1S10L1cnJiemZYd9jNGfercJ9AQ7iyLltICh6uIyFbuDOnDkTFhaG3u4J+mcAmJcazp49y3ZDhhbODQ7iyLltIHBfAAAAgLuQBwAAAHAX8gAAGFYuX74cExOTnZ3t6upKURRFUcuXL9dcwdfX18rKytTUdPLkyYWFhWy1kxCiUqlSUlKkUmnXRe3t7UlJSe7u7gKBwMbGxtPTs6Kiwkgjf/XVV3v37u1z0C1gC/IAABg+du7cmZaWtmXLluDg4Hv37rm5uY0YMeL48eMXLlxQr3Pp0qWzZ8/6+/uXlJTMmDGDraaWlpa+88470dHRTFGrTsLCwo4ePXrixAm5XH7nzh03N7eXL18aaWSmLqiPjw8zrBYYGownCAA9UigUPj4+33//vUGF6smePXtOnz5dXFwsFArVM9PS0pYvXx4ZGVlSUiIWi4du6/1SXFwcHx+/evXq5ubmro9Anj59Oicnp7i4eMqUKYQQR0fH3Nxco468bt26e/fuzZ8//8qVKzwefncMC64HAECPjhw5Ultba2ihulVWVrZ9+/a4uDjNJIAQIpVKo6KiHjx48Mknnwzd1vtr6tSp2dnZS5cuNTMz67r00KFDM2bMYH5Qh03k2NjYoqKi1NTUAWwahhTyAIBhjqbp5OTkiRMnmpmZSSSSwMDAn3/+mVkkk8kEAgEz4AEh5KOPPrKwsKAoihmSOSoqasOGDeXl5RRFubu7p6WlCYXCUaNGffjhh46OjkKhUCqVqsdT6lcoQsg333xjbW2dmJg4WLuZlpZG03RAQEDXRQkJCa+//vrnn39++fLl/nZRRkaGhYWFubl5bm7u+++/b21tPXr06FOnTqk/q1Qqd+zY4ezsLBKJ3njjDWa0A120tbVdu3Zt2rRpOsYxtMgSiWTevHmpqal4BdTQIA8AGOZiY2NjYmK2bt1aW1t75cqV6urquXPnPnnyhBCSlpa2aNEi9Zrp6elxcXHqydTUVH9/fzc3N5qmy8rKZDJZRESEXC5ft25dRUVFYWFhR0fHu+++W11d3d9Q5FWpRpVKNVi7eeHChfHjxzPjMnUiEom++OILExOTVatWNTc3d12hly5as2bN+vXrFQqFlZVVVlZWeXm5q6vrqlWr1ANHbt68ed++fSkpKY8ePfL391+yZInmMNID8PDhw7a2ths3bnh7ezP51sSJE5lRsHQJawiRp0+f/uDBg+LiYh03B4MLeQDAcKZQKJKTkxcuXLhs2TKxWDxlypTPPvusrq7u8OHDAwvI4/GYv5snTZqUkZHR1NSUmZk5gDh+fn6NjY3bt28fWDM6aW5uvn//vrooVFdeXl7r16+vqKjYvHlzp0VadpFUKrW2trazswsPD29ubq6qqiKEtLS0ZGRkBAUFBQcH29jYbNu2jc/nD6xD1Jhn6+zs7BITE0tKSp48eRIYGLh27Vp1+Qzjjezh4UEIuX37to6bg8GFPABgOLYBp2QAACAASURBVCspKXn58uXMmTPVc2bNmiUQCDTrIwzYzJkzzc3N1ZfQWVRbW0vTdLcXA9QSEhLGjx+fnp5+9epVzfn97SKBQEAIYa4H3L17Vy6Xe3p6MotEIpGDg4OOHcLcfZ88ebJUKrW1tRWLxXFxcWKxeMCpm+FEZg4Qc6EFDAfyAIDhjHlTy9LSUnOmjY1Np1LIA2ZmZvb06dNBCaWLlpYW8urXqCdCoTAzM5OiqJUrVyoUCvV8XbqIucuwbds26pXKyspu36nTHlMsQ7NqtkAgcHFxKS8v1yWsIUQWiUTk1cECw4E8AGA4s7GxIYR0+klraGgYPXq07sHb29sHK5SOmB+YPkeq8fLyio6OLi0t3bVrl3qmLl1kZ2dHCElJSdGs2lJQUDCAXVCztLT08PBgymOqdXR06P7SI+uR29rayKuDBYYDeQDAcObp6Wlpaan55Nr169fb2trefPNNZpLH4/VUf7lP+fn5NE2//fbbuofS0ahRoyiKevHiRZ9r7tq1a8KECTdv3lTP6bOLejFmzBihUFhUVDSwZvckLCzs5s2b9+7dYyblcnllZeXAXvYzqMjMAbK3t9d9czCIkAcADGdCoXDDhg3nz58/fvx4Y2Pj7du3V69e7ejoGBkZyazg7u7+7NmznJyc9vb2p0+fVlZWan7c1tb24cOHFRUVTU1NzG+8SqV6/vx5R0fHrVu3oqKinJ2dIyIiBhAqLy9vEN8bNDc3d3V1ramp0aZDMjMzTU1NNef03kW9R1uxYsWpU6cyMjIaGxuVSmVNTc2jR48IIeHh4fb29gMbtzg6OtrFxSUiIqKqqqq+vn7Tpk0KhUL9hKMxRmYwB2hQ0g4YTPopbwyood479M8AaFmjXaVS7d+/38PDg8/nSySSoKCgu3fvqpfW19d7e3sLhcJx48Z9/PHHGzduJIS4u7tXVVXRNF1YWOji4iISiebMmfP48ePIyEg+n+/k5MTj8aytrQMDA8vLywcW6uLFi1ZWVgkJCX22X8tzQyaT8fl8uVzOTJ4/f555fWDkyJFr167ttPLGjRsXLFigTRelp6czT7d5eHiUl5cfPnzY2tqaEOLi4vLLL7/QNN3a2rpp0yZnZ2cej2dnZxccHFxSUkLTdFBQECFkx44d3ba2oKBg9uzZzG11QoiDg4NUKv3222/VK1RXVy9evFgikZiZmb311lt5eXnqRcYYmeHn5+fk5KRSqbqNr0nLcxsGBb559QS/c71D/wyA/r8rIyMjbW1t9blFWutzo7S0lMfjHTt2TA9N0oZSqZw7d+6RI0cQmVFXVycUCg8cOKDNysgD9An3BQCgHwy2apy7u3t8fHx8fLz2VXOGjlKpzMnJaWpqCg8PR2RGbGzstGnTZDLZUAQHXSAPAIBhIiYmJjQ0NDw8XJsHBodUfn5+dnZ2Xl5e70MacCQyISQ5ObmoqOjixYt8Pn/Qg4OOkAcAgFa2bNmSmZn54sWLcePGnTt3ju3mdC8xMVEmk+3evZvdZvj4+Jw4cUJdbYHjkXNzc1tbW/Pz8yUSyaAHB92h/iMAaCUpKSkpKYntVvTN19fX19eX7VbAvyxYsGDBggVstwJ6hOsBAAAA3IU8AAAAgLuQBwAAAHAX8gAAAADuwnOCehUaGsp2EwwUM+Ao+qdfrl27RjjQaTg3OOjatWvquhUw1CiaptluAycUFBQkJyez3QqAzvLy8qZPnz4Ub4sB6IIpDsl2KzgBeQAAp1EUlZWVtWjRIrYbAgDswPMBAAAA3IU8AAAAgLuQBwAAAHAX8gAAAADuQh4AAADAXcgDAAAAuAt5AAAAAHchDwAAAOAu5AEAAADchTwAAACAu5AHAAAAcBfyAAAAAO5CHgAAAMBdyAMAAAC4C3kAAAAAdyEPAAAA4C7kAQAAANyFPAAAAIC7kAcAAABwF/IAAAAA7kIeAAAAwF3IAwAAALgLeQAAAAB3IQ8AAADgLuQBAAAA3IU8AAAAgLuQBwAAAHAX8gAAAADuQh4AAADAXcgDAAAAuAt5AAAAAHchDwAAAOAuHtsNAAC9amhooGlac05zc/Pz58/Vk5aWlnw+X+/tAgB2UJ2+EQBgePvNb37zj3/8o6elpqamDx48sLe312eTAIBFuC8AwC2LFy+mKKrbRSYmJu+88w6SAABOQR4AwC0hISE8Xvc3BCmK+uCDD/TcHgBgF/IAAG6RSCS+vr6mpqZdF5mYmAQFBem/SQDAIuQBAJyzbNkylUrVaSaPx/Pz8xOLxaw0CQDYgjwAgHMCAgLMzMw6zVQqlcuWLWOlPQDAIuQBAJxjbm4eFBTU6eVAkUg0f/58tpoEAGxBHgDARUuWLGlvb1dP8vn8kJAQkUjEYpMAgBXIAwC46L333tN8FKC9vX3JkiUstgcA2II8AICL+Hx+eHi4QCBgJm1sbHx8fNhtEgCwAnkAAEctXry4ra2NEMLn85ctW9bToAIAMLxhXGEAjlKpVK+99tqTJ08IIVevXp09ezbbLQIAFuB6AABHmZiYLF++nBDi6OgolUrZbg4AsANXAg1RQUFBdXU1262A4W/kyJGEkF/96ldnz55luy3ACYsWLWK7CdAZ7gsYotDQ0HPnzrHdCgCAQYZfHAOE+wIGKiQkhOYeQkhWVhbbrWBTVlYWIUSfWzx79qw+N6eGY801zLkNBgh5AACnhYSEsN0EAGAT8gAAAADuQh4AAADAXcgDAAAAuAt5AAAAAHchDwAAAOAu5AEARu/ixYtisfjrr79muyFD5fLlyzExMdnZ2a6urhRFURTFjISo5uvra2VlZWpqOnny5MLCQrbaSQhRqVQpKSndjs/Y3t6elJTk7u4uEAhsbGw8PT0rKiqMNPJXX321d+9epVKp/VbAYCEPADB69LAem2Xnzp1paWlbtmwJDg6+d++em5vbiBEjjh8/fuHCBfU6ly5dOnv2rL+/f0lJyYwZM9hqamlp6TvvvBMdHS2Xy7suDQsLO3r06IkTJ+Ry+Z07d9zc3F6+fGmkkQMCAoRCoY+PT0NDg5YbAoOFcYUBjJ6fn9+LFy/0sCGFQuHj4/P999/rYVuMPXv2nD59uri4WCgUqmempaUtX748MjKypKRELBbrrTG9Ky4ujo+PX716dXNzc9fM7PTp0zk5OcXFxVOmTCGEODo65ubmGnXkdevW3bt3b/78+VeuXEGxSqOG6wEAoK0jR47U1tbqbXNlZWXbt2+Pi4vTTAIIIVKpNCoq6sGDB5988oneGtOnqVOnZmdnL1261MzMrOvSQ4cOzZgxg/lBHTaRY2Nji4qKUlNTB7BpMBzIAwCM29WrV52dnSmK+vTTTwkhGRkZFhYW5ubmubm577//vrW19ejRo0+dOsWsnJaWJhQKR40a9eGHHzo6OgqFQqlUev36dWapTCYTCAQODg7M5EcffWRhYUFRVF1dHSEkKipqw4YN5eXlFEW5u7sTQr755htra+vExMQh2rW0tDSapgMCArouSkhIeP311z///PPLly93+1mappOTkydOnGhmZiaRSAIDA3/++WdmUe9dRAhRKpU7duxwdnYWiURvvPGG7gPitrW1Xbt2bdq0aTrGMbTIEolk3rx5qampw/vO1LCHPADAuM2ZM0fzQv2aNWvWr1+vUCisrKyysrLKy8tdXV1XrVrV3t5OCJHJZBEREXK5fN26dRUVFYWFhR0dHe+++y5T3zItLU2zHFx6enpcXJx6MjU11d/f383NjabpsrIyQgjzmJhKpRqiXbtw4cL48ePNzc27LhKJRF988YWJicmqVauam5u7rhAbGxsTE7N169ba2torV65UV1fPnTv3yZMnpK8uIoRs3rx53759KSkpjx498vf3X7JkyQ8//KDLjjx8+LCtre3GjRve3t5M+jVx4sT09HTdfz5Zjzx9+vQHDx4UFxfruDlgEfIAgOFJKpVaW1vb2dmFh4c3NzdXVVWpF/F4POYP5UmTJmVkZDQ1NWVmZg5gE35+fo2Njdu3bx+8Vv9Lc3Pz/fv33dzcelrBy8tr/fr1FRUVmzdv7rRIoVAkJycvXLhw2bJlYrF4ypQpn332WV1d3eHDhzVX67aLWlpaMjIygoKCgoODbWxstm3bxufzB9Y/asyzdXZ2domJiSUlJU+ePAkMDFy7du3Jkyd1CWsIkT08PAght2/f1nFzwCLkAQDDnEAgIISo/9jtZObMmebm5upr5oajtraWpuluLwaoJSQkjB8/Pj09/erVq5rzS0pKXr58OXPmTPWcWbNmCQQC9R2QTjS76O7du3K53NPTk1kkEokcHBx07B/m7vvkyZOlUqmtra1YLI6LixOLxZ3yEmOMzBwg5kILGCnkAQBcZ2Zm9vTpU7Zb0VlLSwt59WvUE6FQmJmZSVHUypUrFQqFej7zMpulpaXmyjY2Nk1NTX1ul7nLsG3bNuqVysrKbt+p056joyMhhHnMgiEQCFxcXMrLy3UJawiRRSIReXWwwEghDwDgtPb29oaGhtGjR7PdkM6YH5g+R6rx8vKKjo4uLS3dtWuXeqaNjQ0hpNOvvpa7aWdnRwhJSUmhNRQUFAxgF9QsLS09PDx++uknzZkdHR26v/TIeuS2tjby6mCBkUIeAMBp+fn5NE2//fbbzCSPx+vpDoKejRo1iqIobcZF2LVr14QJE27evKme4+npaWlpqflw3/Xr19va2t58880+o40ZM0YoFBYVFQ2s2T0JCwu7efPmvXv3mEm5XF5ZWTmwl/0MKjJzgOzt7XXfHLAFeQAA56hUqufPn3d0dNy6dSsqKsrZ2TkiIoJZ5O7u/uzZs5ycnPb29qdPn1ZWVmp+0NbW9uHDhxUVFU1NTe3t7Xl5eUP33qC5ubmrq2tNTU2fazJ3B0xNTTXnbNiw4fz588ePH29sbLx9+/bq1asdHR0jIyO1ibZixYpTp05lZGQ0NjYqlcqamppHjx4RQsLDw+3t7Qc2bnF0dLSLi0tERERVVVV9ff2mTZsUCoX6CUdjjMxgDtCgpB3AGhoMT0hISEhICNutYAEhJCsri+1WsIl5Vb1fHzl48CDzxr+5uXlAQEB6ejrz6JaHh0d5efnhw4etra0JIS4uLr/88gtN05GRkXw+38nJicfjWVtbBwYGlpeXq6PV19d7e3sLhcJx48Z9/PHHGzduJIS4u7tXVVXRNF1YWOji4iISiebMmfP48eOLFy9aWVklJCQMYE+1OdYymYzP58vlcmby/PnzzOsDI0eOXLt2baeVN27cuGDBAvWkSqXav3+/h4cHn8+XSCRBQUF3795lFvXZRa2trZs2bXJ2dubxeHZ2dsHBwSUlJTRNBwUFEUJ27NjRbWsLCgpmz57N3FYnhDg4OEil0m+//Va9QnV19eLFiyUSiZmZ2VtvvZWXl6deZIyRGX5+fk5OTiqVqtv4mgZwboN+4KgYIuQBnKWH78rIyEhbW9sh3YQ2tDnWpaWlPB7v2LFj+mlSn5RK5dy5c48cOYLIjLq6OqFQeODAAW1WRh5gsHBfAIBzjKVMnLu7e3x8fHx8vPZVc4aOUqnMyclpamoKDw9HZEZsbOy0adNkMtlQBAe9QR4wTPzxj3+0srKiKGrQn28yKJqVZxkCgWDUqFG//vWv9+/f//z5c7YbCIMsJiYmNDQ0PDxcP4WUepGfn5+dnZ2Xl9f7kAYciUwISU5OLioqunjxIp/PH/TgoE/IA4aJzz///D/+4z/YbsWQU1eeFYvFNE2rVKra2tozZ86MGzdu06ZNkydP1nH812Fvy5YtmZmZL168GDdu3Llz59hujlYSExNlMtnu3bvZbYaPj8+JEyfUxRc4Hjk3N7e1tTU/P18ikQx6cNAz5AEw5BQKhVQqHYrIFEXZ2Nj8+te/zszMPHPmzJMnT/RWgbdfhq4H+ispKam1tZWm6fv374eEhLDdHG35+vru2bOH7VbAvyxYsCAmJkbzHQ0wXsgDhg+KothuQvf0U6w2JCQkIiKitrb2s88+G+pt9Zeey/UCAGgPeYARo2l6//7948ePNzMzE4vFzCtejH379pmbm1tZWdXW1m7YsMHJyYl5aaqnSqy9l6MlvVZx7W+x2qHDvASfl5fH2R4AAOg3Ft9VgJ5o+d7g1q1bKYr685///Pz5c7lcnp6eTgi5efOmeikhZN26dQcPHly4cOGdO3d27NghEAiOHTvW0NBw69atGTNmjBw58vHjx8z6kZGRFhYWP/30U0tLS0lJyaxZs6ysrJi3xmma7v2zS5cutbe3Vzds//79hJCnT58yk8HBwUyx2j4R7d4bVD8f0EljYyMhZMyYMcbbA9x5t0rLYw3DBnfObaOD6wHGSqFQpKSk/Pa3v42OjraxsRGJRLa2tl1X27Nnz9q1a7Ozs11cXPqsxNpTOVotq7iyjnljotOo8pzqAQCA/uKx3QAYoLKyMrlc7uPjo+X6/a3EqlmOtr+fZUtzczNN08zYcF0ZUQ+EhoYORVhDk5KScvbsWbZbAXqizRDRwApcDzBWzH8qpjaaNgZQiVVdjlaXKq769MsvvxBCJkyY0O1SLvQAAEB/4XqAsRIKhYSQ1tZWLdfvbyVWzXK0ulRx1advvvmGEPL+++93u9SIeoALfyVTFLV+/fpFixax3RDQkzNnzoSFhbHdCugGrgcYK09PTxMTk2+//Vb79ftViVWzHG2fnzWEYrWPHz9OSUkZPXr0ypUru11h2PcAAMAAIA8wVkwZtHPnzh05cqSxsfHWrVu9P7OmTSXWnsrR9vnZfhWrHZTdp2n65cuXTJWzp0+fZmVlzZ4929TUNCcnp6fnA4ZZDwAADA5W31aA7mn53mBTU9Mf//jHESNGWFpazpkzZ8eOHYSQ0aNHFxcX7927VyQSEULGjBmjLtfWSyVWuq9ytL1/tl/FanvZI9LXu2RfffXVG2+8YW5uLhAITExMyKshBd966634+Pj6+nr1mkbaA9x5t6rPYw3DDHfObaND0TTNVgoCPWEeF9fzTeIPP/zw7Nmz9fX1+txoJxRFZWVlsXXP2BB6gLmHyoX/lewea9A/7pzbRgf3BeBfjKUc7dBBDwAA1yAPAABDd/ny5ZiYGM2q08uXL9dcwdfX18rKytTUdPLkyYWFhWy1kxCiUqlSUlK6LSvV3t6elJTk7u4uEAhsbGw8PT0rKiqMNPJXX321d+9e5M3DA/IAIMQ4y9EOLvSAwdq5c2daWtqWLVvUVadHjBhx/PjxCxcuqNe5dOnS2bNn/f39S0pKZsyYwVZTS0tL33nnnejoaLlc3nVpWFjY0aNHT5w4IZfL79y54+bm9vLlSyONHBAQIBQKfXx8mKE1wLix/HwCdEfL5wSHH8L5Z8f08CyVXC738vJiPZSWx3r37t2vv/66QqFQz3Fzcztx4oSJiYmTk1NDQ4N6fl5e3oIFCwbWmEFRVFS0cOHC48ePT5s2berUqZ2Wnjp1iqKoW7duDafIMpnMy8urvb1dm23hOUGDhesBANwyiEWQh7qecllZ2fbt2+Pi4phRs9SkUmlUVNSDBw8++eSTodt6f02dOjU7O3vp0qVmZmZdlx46dGjGjBlTpkwZTpFjY2OLiopSU1MHsGkwHMgDAIwPPUhFkHuvttzfesrffPONtbV1YmLiYO1mWloaTdMBAQFdFyUkJLz++uuff/755cuX+9tFGRkZFhYW5ubmubm577//vrW19ejRo0+dOqX+rFKp3LFjh7Ozs0gkeuONN5g/ZHXR1tZ27dq1adOm6RjH0CJLJJJ58+alpqbSeAvAmCEPADA+sbGxMTExW7dura2tvXLlSnV19dy5c588eUIISUtL03wZLz09PS4uTj2Zmprq7+/PFEEuKyuTyWQRERFyuXzdunUVFRWFhYUdHR3vvvtudXV1f0ORV29bqFSqwdrNCxcujB8/3tzcvOsikUj0xRdfmJiYrFq1qrm5uesKvXTRmjVr1q9fr1AorKyssrKyysvLXV1dV61apR7iafPmzfv27UtJSXn06JG/v/+SJUs0h5IcgIcPH7a1td24ccPb25vJtyZOnJienq77zyfrkadPn/7gwYPi4mIdNwcsQh4AYGQGvQhyT9WW+8vPz6+xsXH79u0Da0Ynzc3N9+/fd3Nz62kFLy+v9evXV1RUbN68udMiLbtIKpVaW1vb2dmFh4c3NzdXVVURQlpaWjIyMoKCgoKDg21sbLZt28bn8wfWIWrMs3V2dnaJiYklJSVPnjwJDAxcu3btyZMndQlrCJE9PDwIIbdv39Zxc8Ai5AEARmZIiyBrVltmV21tLU3T3V4MUEtISBg/fnx6evrVq1c15/e3iwQCASGEuR5w9+5duVzu6enJLBKJRA4ODjp2CHP3ffLkyVKp1NbWViwWx8XFicXiAaduhhOZOUDMhRYwUsgDAIzMUBdBVldbZldLSwt59WvUE6FQmJmZSVHUypUrFQqFer4uXcTcZdi2bRv1SmVlZbfv1GnP0dGREMI8V8EQCAQuLi7l5eW6hDWEyMzo3czBAiOFPADAyAxpEWTNasvsYn5g+hypxsvLKzo6urS0dNeuXeqZunSRnZ0dISQlJUXzxaqCgoIB7IKapaWlh4fHTz/9pDmzo6NDLBbrEtYQIre1tZFXBwuMFPIAACMzpEWQNast6xhKR6NGjaIo6sWLF32uuWvXrgkTJty8eVM9p781pjWNGTNGKBQWFRUNrNk9CQsLu3nz5r1795hJuVxeWVk5sJf9DCoyc4Ds7e113xywBXkAgJEZ9CLIPVVb/v/s3XtcE1feP/AzkJCEkHARROQOURHFW7UV1LrUXVzl8YKI4q3V2pZabUS8ICoWEVHURR4sbOvlx7qiAgrFropatdS6tW67SkV8ahEvgDdABMJNIMzvj3k1m40IEUgmOJ/3X82ZOWfOHKfJl5k55/uqTeXk5HTjvEFTU1M3N7fS0lJtBiQlJcXY2Fi9pMMc0+20tmjRoiNHjiQnJ9fU1CiVytLS0kePHhFCgoODbW1tO7ducVhYmLOz88KFC4uLi58+fRoeHt7Q0KB6w7Entsxg/oG6JewA1uh11SLQDtYT5Cwt11zrxiTI7WdbfqWmTp06JZFIYmJitDlTbf6t5XI5n8+vr69nPmZlZTHTB6ytrZctW6ax8+rVq9XXE2xniJKSkpi32/r161dUVLRnzx6pVEoIcXZ2/u2332iafv78eXh4uJOTE4/Hs7GxCQwMLCgooGk6ICCAELJx48Y2e3v58uUxY8Ywj9UJIX369PHx8fnuu+9UO5SUlMyZM8fS0lIgELz55ps5OTmqTT2xZYa/v7+9vX1ra2ub7avDeoIGC/8qhghxAGfp/7syJCTEyspKn0dkaPNvXVhYyOPxDh48qJ8udUipVI4bN27//v1omVFRUSEUCnfu3KnNzogDDBaeCwBwncFmjZPJZNHR0dHR0dpnzdEdpVKZnZ2tUCiCg4PRMiMqKmrYsGFyuVwXjYPeIA4AAMMVERERFBQUHByszQuDOpWbm5uZmZmTk9P+kgYcaZkQEh8fn5eXd+rUKT6f3+2Ngz4hDgDgrh6RbXnLli1yuXzr1q3sdmPChAmHDh1SZVvgeMvHjx9//vx5bm6upaVltzcOesZjuwMAwJrY2NjY2Fi2e9ExPz8/Pz8/tnsB/zFt2rRp06ax3QvoHrgfAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3EXRNM12H0BTUFCQwU7iAgDoNPziGCDEAYbo8uXLJSUlbPcCOGH27NmhoaHe3t5sdwQ4YdasWWx3ATQhDgDgNIqi0tPT8e0MwFl4PwAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3MVjuwMAoFdHjhxRKBTqJefOnauqqlJ9DAgIsLGx0Xu/AIAdFE3TbPcBAPRn4cKFBw4c4PP5zEfmG4CiKEKIUqk0MzMrKysTCARsdhEA9AjPBQC4Zc6cOYSQ5t+1tLS0tLQw/21sbBwUFIQgAIBTcD8AgFtaWlpsbW0rKyvb3Hr+/Pl33nlHz10CABbhfgAAt/B4vDlz5qieC6iztrYeP368/rsEACxCHADAOXPmzGlubtYo5PP5CxYsMDY2ZqVLAMAWPBcA4Byapp2cnEpLSzXK//Wvf40aNYqVLgEAW3A/AIBzKIqaP3++xqMBR0fHkSNHstUlAGAL4gAALtJ4NMDn8xcuXMjMHgQATsFzAQCO8vDwuHXrlurjjRs3Bg0axGJ/AIAVuB8AwFELFixQPRrw9PREEADATYgDADhq/vz5LS0thBA+n//ee++x3R0AYAeeCwBw18iRI//9739TFHXv3j0nJye2uwMALMD9AADuevfddwkhb731FoIAAM5CvkF2xMfHX758me1eANc1NjZSFPX8+fOgoCC2+wJAjh49ynYXuAj3A9hx+fLlH3/8ke1e9Aw//vgjxopRWlp67NixbmxQKBTa2to6ODh0Y5vd4tixYy8ucwSvsW6/tkF7eD+AHcyfXwh+tYGxUsnIyJg9e3b3/j97+/ZtmUzWjQ12C4qi0tPTZ82axXZHQE90cW2DlnA/AIDTDDAIAAB9QhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAr7lTp06Zm5v/4x//YLsjunLu3LmIiIjMzEw3NzeKoiiKWrBggfoOfn5+EonE2Nh40KBBV69eZaufhJDW1tZdu3b5+Pi8uKm5uTk2NlYmk5mYmFhYpiS+QAAAIABJREFUWAwePPjevXs9tOWvv/46Li5OqVRqfxRgEeIAgNfc6z0X67PPPktMTFy3bl1gYOCdO3fc3d179eqVmpp68uRJ1T5nz549evTolClTCgoKRowYwVZXCwsL33777bCwsPr6+he3zp49++9///uhQ4fq6+v/7//+z93dvba2toe2PHXqVKFQOGHChKqqKi0PBCzCeoIArzl/f//q6mo9HKihoWHChAk//PCDHo7F2LZtW1pa2i+//CIUClWFiYmJCxYsCAkJKSgoMDc311tn2vfLL79ER0cvWbKkrq7uxcgsLS0tOzv7l19+8fLyIoTY2dkdP368R7e8fPnyO3fuTJ48+eLFizwefmgMGu4HAED32L9/f1lZmd4Od/v27cjIyE2bNqkHAYQQHx+f0NDQBw8erFq1Sm+d6dDQoUMzMzPnzZsnEAhe3PrXv/51xIgRzA/qa9NyVFRUXl5eQkJCJw4N+oQ4AOB1dunSJScnJ4qiPv/8c0JIcnKyWCw2NTU9fvz4pEmTpFKpg4PDkSNHmJ0TExOFQmHv3r0//vhjOzs7oVDo4+Nz5coVZqtcLjcxMenTpw/zcenSpWKxmKKoiooKQkhoaOjKlSuLioooimLWJjp9+rRUKt2yZYuOTi0xMZGm6alTp764KSYmpn///vv27Tt37lybdWmajo+PHzhwoEAgsLS0nD59+q+//spsan+ICCFKpXLjxo1OTk4ikWjIkCHp6eldPJGmpqYff/xx2LBhXWzH0Fq2tLQcP358QkLC6/1k6jWAOADgdTZ27Fj1G/WffPLJihUrGhoaJBJJenp6UVGRm5vbhx9+2NzcTAiRy+ULFy6sr69fvnz5vXv3rl692tLS8qc//amkpIQQkpiYqL7Qb1JS0qZNm1QfExISpkyZ4u7uTtP07du3CSHMa2Ktra06OrWTJ08OGDDA1NT0xU0ikehvf/ubkZHRhx9+WFdX9+IOUVFRERER69evLysru3jxYklJybhx4548eUI6GiJCyNq1a7dv375r165Hjx5NmTJl7ty5P//8c1dO5OHDh01NTf/+9799fX2Z8GvgwIFJSUld//lkveXhw4c/ePDgl19+6eLhQKcQBwBwkY+Pj1QqtbGxCQ4OrqurKy4uVm3i8XjMH8qenp7JyckKhSIlJaUTh/D396+pqYmMjOy+Xv9HXV3d3bt33d3dX7aDt7f3ihUr7t27t3btWo1NDQ0N8fHxM2bMmD9/vrm5uZeX1xdffFFRUbFnzx713docosbGxuTk5ICAgMDAQAsLiw0bNvD5/M6Njwrzbp2Njc2WLVsKCgqePHkyffr0ZcuWHT58uCvNGkLL/fr1I4Tk5+d38XCgU4gDADjNxMSEEKL6Y1fDyJEjTU1NVffMDUdZWRlN023eDFCJiYkZMGBAUlLSpUuX1MsLCgpqa2tHjhypKhk1apSJiYnqCYgG9SG6detWfX394MGDmU0ikahPnz5dHB/m6fugQYN8fHysrKzMzc03bdpkbm6uEZf0xJaZfyDmRgsYLMQBANAegUBQXl7Odi80NTY2kt9/jV5GKBSmpKRQFPX+++83NDSoypnJbGZmZuo7W1hYKBSKDo/LPGXYsGED9bv79++3OadOe3Z2doQQ5jULhomJibOzc1FRUVeaNYSWRSIR+f0fCwwW4gAAeKnm5uaqqioHBwe2O6KJ+YHpcKUab2/vsLCwwsLCzZs3qwotLCwIIRq/+lqepo2NDSFk165dtJrLly934hRUzMzM+vXrd/PmTfXClpaWrk96ZL3lpqYm8vs/FhgsxAEA8FK5ubk0TY8ePZr5yOPxXvYEQc969+5NUZQ26yJs3rzZw8Pj2rVrqpLBgwebmZmpv9x35cqVpqamN954o8PWHB0dhUJhXl5e57r9MrNnz7527dqdO3eYj/X19ffv3+/cZD+Dapn5B7K1te364UB3EAcAwH9pbW199uxZS0vL9evXQ0NDnZycFi5cyGySyWSVlZXZ2dnNzc3l5eX3799Xr2hlZfXw4cN79+4pFIrm5uacnBzdzRs0NTV1c3MrLS3tcE/m6YCxsbF6ycqVK7OyslJTU2tqavLz85csWWJnZxcSEqJNa4sWLTpy5EhycnJNTY1SqSwtLX306BEhJDg42NbWtnPrFoeFhTk7Oy9cuLC4uPjp06fh4eENDQ2qNxx7YssM5h+oW8IO0CEa2DBz5syZM2ey3YueAWOlwkxVf6Uqu3fvZmb8m5qaTp06NSkpiXl1q1+/fkVFRXv27JFKpYQQZ2fn3377jabpkJAQPp9vb2/P4/GkUun06dOLiopUrT19+tTX11coFLq6un766aerV68mhMhksuLiYpqmr1696uzsLBKJxo4d+/jx41OnTkkkkpiYmE6cKSEkPT29/X3kcjmfz6+vr2c+ZmVlMdMHrK2tly1bprHz6tWrp02bpvrY2tq6Y8eOfv368fl8S0vLgICAW7duMZs6HKLnz5+Hh4c7OTnxeDwbG5vAwMCCggKapgMCAgghGzdubLO3ly9fHjNmDPNYnRDSp08fHx+f7777TrVDSUnJnDlzLC0tBQLBm2++mZOTo9rUE1tm+Pv729vbt7a2ttm+uk5c29BdMO7swG+b9jBWKnr4rgwJCbGystLpIbShTRxQWFjI4/EOHjyony51SKlUjhs3bv/+/WiZUVFRIRQKd+7cqc3OiANYhOcCAPBfekqaOJlMFh0dHR0drX3WHN1RKpXZ2dkKhSI4OBgtM6KiooYNGyaXy3XROHQjxAEA0FNFREQEBQUFBwfrJ5FSO3JzczMzM3Nyctpf0oAjLRNC4uPj8/LyTp06xefzu71x6F6IA+C/REdHe3p6SqVSgUAgk8nWrFnzsj+2PvjgA4lEQlHUK7073U4u825x69atTz/9dNCgQRKJhMfjmZub9+/f39/fv4szu7TRztBlZma6ublRakxMTHr37v2HP/xhx44dz54903XftLRu3bqUlJTq6mpXV9djx46x3R2tbNmyRS6Xb926ld1uTJgw4dChQ6rkCxxv+fjx48+fP8/NzbW0tOz2xqH7sf1ggqMM9pn3+PHjk5KSnj59WlNTk56ezufz//znP79sZyb5yrVr17Rs/LfffhszZgwhZOjQodp3Sfux2rdvH5/Pf/vtt0+fPv3s2bPGxsaioqK0tDQfH58vv/xS+yN2TodD5+7ubm5uTtM080L+t99+u3DhQoqi7OzsfvrpJ20OwZ1nqESL9wPgdcKda9sAIS00/BczM7OQkBBmktWsWbMyMzMzMjJKSkocHR272HL7ucy77scffwwJCRk/fvyZM2dU+c7d3Nzc3NwsLCwKCwu7/YgatB86iqIsLCz+8Ic//OEPf/D39589e7a/v/9vv/3W9dVdAABeFZ4LwH85ceKE+kxra2trQsjLlk2lKEr7ltvPZd51MTExSqVy69atqiBAZeLEicuWLdPFQdW90tCpzJw5c+HChWVlZV988YVu+wcA0BbEAYbu4MGDI0eOFAqFYrHYxcWFWR6V7mz29IEDB1IUZWRk9MYbbzA/UWvWrDE3NxcKhX/7299ePPqDBw9EIpGrqyvzkabpHTt2DBgwQCAQmJubM9PHDUFTU9P58+d79er15ptvtr8nW0PXDmaVnpycnFc4YQCA7sLuYwnO0vKZ965duwghW7duffr0aWVl5Zdffjlv3jyapjdu3GhiYnLw4MGqqqrr16+PGDHC2tr68ePHTK3169cTQs6fP19dXV1WVjZu3DixWNzU1ETTdEtLi4uLi5OTU0tLi+ooK1as0FgvnVFXVyeRSORyuapk/fr1FEX95S9/efbsWX19fVJSEnmV9wMYb731Vre/H/Dbb78RQkaPHt1ha2wNHa32foCGmpoaQoijo2OHnefOM1SC9wM4hjvXtgHC/QDD1dzcvGnTJl9f37Vr11pZWVlaWi5evHjUqFFdyZ5ubGy8fPny4uLirKwsZrf6+vrMzMz333//xQ7Exsba2dnFxMQwHxsaGnbt2vXHP/4xLCzMwsJCJBJZWVnpeAy0xfyUamSQexFbQ9c+ZtqFNsnuAAC6HeIAw3X9+vWqqqqJEyeqSpifoq5kTyeEfPDBB+bm5gkJCczH1NTU6dOnMyunqsvKysrIyDhz5oxEImFKbt++XV9fP2HChG46v+7ERAAdPoxna+jax7w4+WI7L0NxACFk9uzZbPcC9Gf27NlaXv/Q7TBfwHAxf+MyOVLVdSV7OlPxo48+2rFjx7/+9a8333zzr3/964szxdPS0uLj43Nzc/v27asqZFKGMHlXDY2Li4tQKGSeDrSDraFrH9NtDw8PLfdn7qC+3mbPnh0aGurt7c12R0BPLl++rIqwQc8QBxgu5oekoqJCo7wr2dMZcrk8ISFh165dS5YscXR0ZLKzqOzevfvMmTMXLlzQ+L0UCoWEkOfPn7/ieeiDQCCYOHHi8ePH//nPfzJLFKirrKxcs2bNvn372Bq69p0+fZoQMmnSJC33nzVrlvaN91CzZ8/29vbmwpmCCuIAtuC5gOFycXGxsrI6e/asRnlXsqczHBwcZs2adezYscjIyNDQUFU5TdPh4eH5+fnZ2dkv/pINHjzYyMjou+++69TZ6FxUVJRAIAgLC2toaNDYdOPGDWYyIVtD147Hjx/v2rXLwcGhzfcMAAB0DXGA4RIIBOvWrbt48aJcLn/w4EFra6tCobh582ZXsqerrFy5sqWl5dmzZ++8846q8ObNm9u3b9+7dy+fz1d/dLdz505CCJNi9dixY/v376+pqbl+/brG63XsGjZs2KFDh27cuDFu3LhTp05VV1c3NzffvXt37969ixcvZhY5Z2voVGiarq2tZdKwlpeXp6enjxkzxtjYODs7W/v3AwAAuhOrsxW4S/u1cj///HMvLy+hUCgUCocPH56UlER3LXu6iq+v7759+9RL8vPz27xIduzYweygUCg++OCDXr16mZmZjR07duPGjYQQBweHX375pcMT6TCXedfHiqbp4uLiVatWeXl5mZmZGRsbW1hYDB8+fPHixf/85z+ZHVgZuq+//nrIkCGmpqYmJiZGRkbk9yUF33zzzejo6KdPn2p5dtyZW0Uwb5BjuHNtGyCK1sEKr9ChoKAgQsjRo0fZ7kgPgLFSycjImD17Nhf+n6UoKj09He8HcAd3rm0DhOcCAAAA3IU4ALrBr7/+2s7M4ODgYLY7CNx17ty5iIgI9dTPCxYsUN/Bz89PIpEYGxsPGjTo6tWrbPXz8OHDo0aNkkgkzs7OixYtevz4sR7qxsXFeXh4iEQisVjs4eERGRnJTFdmtJNK++uvv46Li1Mqldp3EgwXy88luMpg8w4bIIyVCneeoZJuej9g48aNU6ZMqampYT66u7v36tWLEHLixAn13XJycqZNm9b1w3VaWloaISQuLq6qquratWtubm7Dhg1rbm7WdV1/f/+dO3eWlZUpFIqMjAw+n/+nP/1JtbX9VNoJCQnjx49/9uzZq55sm7hzbRsg3A8AgP9oaGjw8fExtKY6Z9u2bWlpaRkZGeoLOyYmJhoZGYWEhFRXV7PYNw1ffvll3759V69ebW5uPmzYsLCwsLy8vJctc9mNdU1MTJYuXWpjY2NmZhYUFDR9+vRvvvnm0aNHzFYmlbaVlZVEIpk1a1ZAQMDp06dLSkqYrcuXLx86dOjkyZNbWlo6d9ZgIBAHAMB/7N+/v6yszNCa6oTbt29HRkZu2rSJWf9KxcfHJzQ09MGDB6tWrWKrby8qKSmxs7Ojfk/k7ejoSAi5f/++rutmZWWpj4+9vT0hRHXzv8NU2lFRUXl5eVj/p6dDHADwuqFfnltZLpebmJj06dOH+bh06VKxWExRFLNsZWho6MqVK4uKiiiKkslkiYmJQqGwd+/eH3/8sZ2dnVAo9PHxUf2h+UpNEUJOnz4tlUq3bNmin0FITEykaXrq1KkvboqJienfv/++ffvOnTvXZt12BrD95NSEEKVSuXHjRicnJ5FINGTIEC0XgXZzc1OPmZgH/G5ubrquq6GwsNDCwsLZ2bnNrS+m0ra0tBw/fnxCQgKN9/x7NHYfS3AWnnlrD2OlouUz1PZzK8+bN8/W1la1844dOwgh5eXlzMfAwEB3d3fV1pCQELFYfPPmzcbGxoKCAuZltOLi4k40deLECYlEEh0drc2Zki6/H+Dm5ubp6alR6O7ufvfuXZqmf/jhByMjIxcXl9raWvqF9wM6nZyapulVq1YJBIJjx449e/Zs3bp1RkZGP/30U4e9zc3N5fP5iYmJNTU1N27cGDhw4MSJE7U8067UZTQ1NZWWlu7evVsgEBw8eLDNfdpMpU3TdEREBHn15OMvwvsBLML9AIDXipa5lbXH4/GYv4w9PT2Tk5MVCkVKSkon2vH396+pqYmMjOxcN15JXV3d3bt3NbI/qPP29l6xYsW9e/fWrl2rsakryakbGxuTk5MDAgICAwMtLCw2bNjA5/O1Ga7x48eHh4fL5XKpVDp48GCFQrFv3z4tT7YrdRmOjo4ODg5RUVHbt29/Wd6/l6XS7tevHyHkZetoQY+AOADgtfKquZVfyciRI01NTVU3yQ1WWVkZTdPM6pAvExMTM2DAgKSkpEuXLqmXdyU59a1bt+rr6wcPHsxsEolEffr00Wa41q9fv2fPnvPnz9fW1t65c8fHx8fb21v1Rp7u6jJKSkrKysoOHz584MCB4cOHv/hWRzuptJlBfvLkifaHA0ODOADgtdLF3ModEggE5eXl3dKU7jQ2NhJCBAJBO/sIhcKUlBSKot5//3313FRdGcC6ujpCyIYNG1SLZ9y/f1/9xbo2PXr0KC4u7qOPPnrnnXfEYrGrq+vevXsfPnzIPGfRXV0VPp9vY2Pj5+eXlpZWUFAQGxurvjUtLW3btm25ubkuLi4v1hWJROT3AYceCnEAwGul67mV29Hc3NxdTekU8+PU4So33t7eYWFhhYWFmzdvVhV2ZQBtbGwIIbt27VJ/+Hr58uX2axUWFiqVSibPOEMqlVpZWRUUFHR4xK7UfZFMJjM2Nlavu3v37tTU1AsXLqgfQl1TUxP5fcChh0IcAPBa6TC3Mo/HY25id0Jubi5N06NHj+56UzrVu3dviqK0WSFg8+bNHh4e165dU5V0JTm1o6OjUCjMy8t7pd4yEYZq1j4hRKFQVFZWMjMAdVf36dOnc+fOVS9hogqmLq1dKm1mkG1tbTs8HBgsxAEAr5UOcyvLZLLKysrs7Ozm5uby8nKNieZWVlYPHz68d++eQqFgfuNbW1ufPXvW0tJy/fr10NBQJyenhQsXdqKpnJwcvc0bNDU1dXNzKy0t7XBP5umA+iz5riSnFgqFixYtOnLkSHJyck1NjVKpLC0tZX6kg4ODbW1t21y32NXV1dfXd+/evRcvXmxoaCgpKWGOtXjxYmYHHdUVi8Vnz569cOFCTU1Nc3PztWvX3nvvPbFYHBYWRrROpc0MspeXV4eDA4aLlVkKgLlw2sNYqWg5t6qd3Mo0TT99+tTX11coFLq6un766aerV68mhMhkMmY24NWrV52dnUUi0dixYx8/fhwSEsLn8+3t7Xk8nlQqnT59elFRUeeaOnXqlEQiiYmJ0eZMSZfnDcrlcj6fX19fz3zMyspipg9YW1svW7ZMY+fVq1erzxvsSnLq58+fh4eHOzk58Xg8GxubwMDAgoICmqYDAgIIIRs3bmyztxUVFaGhoTKZTCAQmJmZjRkz5quvvlJt1V3dqVOnurq6mpmZCQQCd3f34ODg/Px8ZlOHWcgZ/v7+9vb2ra2tbbavPcwbZBHGnR34bdMexkpF/9+VzLKy+jwio+txQGFhIY/He9lseP1TKpXjxo3bv39/D6rboYqKCqFQuHPnzq43hTiARXguAADt6aE55WQyWXR0dHR0tGqVXBYplcrs7GyFQtGJ3Jts1dVGVFTUsGHD5HK5LhoHvUEcAACvp4iIiKCgoODgYNZTCuXm5mZmZubk5LS/pIFB1e1QfHx8Xl7eqVOn+Hx+tzcO+oQ4AADatm7dupSUlOrqaldX12PHjrHdnc7YsmWLXC7funUru92YMGHCoUOHVLkYekTd9h0/fvz58+e5ubmWlpbd3jjoGY/tDgCAgYqNjdVYUqYn8vPz8/PzY7sXr5tp06ZNmzaN7V5A98D9AAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAd+E9QdaUlpZmZGSw3YsegFm4FGNFCGEy1nBkKDpMzwOvE/xzs4iiaZrtPnBRUFBQD52IBQCgI/g9YgXiAABOoygqPT191qxZbHcEANiB9wMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALiLomma7T4AgP6EhITcunVL9fHq1auurq6WlpbMR2Nj4wMHDjg4OLDUOwDQNx7bHQAAvbK1td2zZ496yfXr11X/7ebmhiAAgFPwXACAW+bOnfuyTSYmJgsXLtRjXwCAfXguAMA5gwcPvnnzZpv/79+6dat///767xIAsAX3AwA459133zU2NtYopChq6NChCAIAuAZxAADnzJkzR6lUahQaGxu/9957rPQHAFiE5wIAXOTj43PlypXW1lZVCUVRJSUl9vb2LPYKAPQP9wMAuGjBggUURak+GhkZjR07FkEAAAchDgDgoqCgIPWPFEW9++67bHUGAFiEOACAi6ytrSdMmKB6W5CiqICAAHa7BACsQBwAwFHz589nXg8yNjaeOHFir1692O4RALAAcQAAR82YMcPExIQQQtP0/Pnz2e4OALADcQAAR4nF4v/5n/8hhJiYmEyZMoXt7gAAOxAHAHDXvHnzCCEBAQFisZjtvgAAS2i2zZw5k+0xAAAAYAfbP8K0QeQbHD169IoVK9juBbw+Zs+eHRoa6u3tzXZHeoDU1NTg4GAezyC+Crrd5cuXExIS0tPT2e6IzuGa74mY65PtXhjAeoLMPOajR4+y2w14nVAUlZ6ePmvWLLY70gM0NjYKhUK2e6ErGRkZs2fPZv1bTg9wzfdEBnJ94v0AAE57jYMAANAG4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAA+C+nTp0yNzf/xz/+wXZHdOXcuXMRERGZmZlubm4URVEUtWDBAvUd/Pz8JBKJsbHxoEGDrl69ylY/Dx8+PGrUKIlE4uzsvGjRosePH+uhblxcnIeHh0gkEovFHh4ekZGRNTU1qq3R0dGenp5SqVQgEMhksjVr1tTW1jKbvv7667i4OKVSqX0nDQTiAACA/8L6PC6d+uyzzxITE9etWxcYGHjnzh13d/devXqlpqaePHlStc/Zs2ePHj06ZcqUgoKCESNGsNLP9PT0efPmBQUFlZaWHj9+/OLFi5MmTWppadF13e+///7DDz8sLi5+8uTJ5s2b4+Li1Be7u3DhwrJly+7du1dRUREbG5uQkKBK4T116lShUDhhwoSqqqpOnC+b2F3GiKbpmTNnzpw5k+1ewGuFEJKens52L4B9zApCbPfiperr6729vbulKS2v+a1bt/bv37+hoUFV4u7ufujQISMjI3t7+6qqKlV5Tk7OtGnTuqVvnePr69u3b9/W1lbm4+eff04IuXTpkq7rBgQEqI8P8zP/8OFD5qO/v39LS4tqK7NgQ3FxsapELpd7e3s3NzdrcywDuT5xPwAAgB379+8vKyvT2+Fu374dGRm5adMmjUUjfHx8QkNDHzx4sGrVKr11pkMlJSV2dnYURTEfHR0dCSH379/Xdd2srCz18bG3tyeEqG7+nzhxwtjYWLXV2tqaEFJfX68qiYqKysvLM4RVArWHOAAA4D8uXbrk5OREURTzR2RycrJYLDY1NT1+/PikSZOkUqmDg8ORI0eYnRMTE4VCYe/evT/++GM7OzuhUOjj43PlyhVmq1wuNzEx6dOnD/Nx6dKlYrGYoqiKigpCSGho6MqVK4uKiiiKkslkhJDTp09LpdItW7bo6NQSExNpmp46deqLm2JiYvr3779v375z5861WZem6fj4+IEDBwoEAktLy+nTp//666/MpvaHiBCiVCo3btzo5OQkEomGDBmi5TLPbm5u6kES84Dfzc1N13U1FBYWWlhYODs7t7n1wYMHIpHI1dVVVWJpaTl+/PiEhAS6Bz1dYvl+BJ4LgA4QPBcAmqY7e9+1pKSEELJ7927m4/r16wkh58+fr66uLisrGzdunFgsbmpqYraGhISIxeKbN282NjYWFBQw76apbhTPmzfP1tZW1fKOHTsIIeXl5czHwMBAd3d31dYTJ05IJJLo6OhOnKk217ybm5unp6dGobu7+927d2ma/uGHH4yMjFxcXGpra+kXngts3LjRxMTk4MGDVVVV169fHzFihLW19ePHj5mt7Q/RqlWrBALBsWPHnj17tm7dOiMjo59++qnDM8rNzeXz+YmJiTU1NTdu3Bg4cODEiRO1HI2u1GU0NTWVlpbu3r1bIBAcPHiwzX3q6uokEolcLtcoj4iIIIRcu3atw6PguQAAQI/h4+MjlUptbGyCg4Pr6uqKi4tVm3g8HvOHsqenZ3JyskKhSElJ6cQh/P39a2pqIiMju6/X/1FXV3f37l13d/eX7eDt7b1ixYp79+6tXbtWY1NDQ0N8fPyMGTPmz59vbm7u5eX1xRdfVFRU7NmzR323NoeosbExOTk5ICAgMDDQwsJiw4YZI2ctAAAgAElEQVQNfD5fm/EZP358eHi4XC6XSqWDBw9WKBT79u3T8mS7Upfh6Ojo4OAQFRW1ffv22bNnt7lPbGysnZ1dTEyMRnm/fv0IIfn5+a90RBYhDgAAeAUmJiaEkObm5ja3jhw50tTUVHXP3HCUlZXRNG1qatrOPjExMQMGDEhKSrp06ZJ6eUFBQW1t7ciRI1Ulo0aNMjExUT0B0aA+RLdu3aqvrx88eDCzSSQS9enTR5vxWb9+/Z49e86fP19bW3vnzh0fHx9vb2/mVo1O6zJKSkrKysoOHz584MCB4cOHv/gaR1ZWVkZGxpkzZyQSicYmZpCfPHmi/eHYhTgAAKA7CQSC8vJytnuhqbGxkRAiEAja2UcoFKakpFAU9f777zc0NKjKmYlwZmZm6jtbWFgoFIoOj1tXV0cI2bBhA/W7+/fvq79Y16ZHjx7FxcV99NFH77zzjlgsdnV13bt378OHD5kHK7qrq8Ln821sbPz8/NLS0goKCmJjY9W3pqWlbdu2LTc318XF5cW6IpGI/D7gPQLiAACAbtPc3FxVVeXg4MB2RzQxP04drnLj7e0dFhZWWFi4efNmVaGFhQUhRONXX8vTtLGxIYTs2rVL/YH05cuX269VWFioVCr79u2rKpFKpVZWVgUFBR0esSt1XySTyYyNjdXr7t69OzU19cKFC+qHUNfU1ER+H/AeAXEAAEC3yc3NpWl69OjRzEcej/eyJwh61rt3b4qiqqurO9xz8+bNHh4e165dU5UMHjzYzMzs559/VpVcuXKlqanpjTfe6LA1R0dHoVCYl5f3Sr1lIoxHjx6pShQKRWVlJTMDUHd1nz59OnfuXPUSJqpg6tI0HR4enp+fn52drXF3RB0zyLa2th0ezkAgDgAA6JLW1tZnz561tLRcv349NDTUyclp4cKFzCaZTFZZWZmdnd3c3FxeXq4xhd3Kyurhw4f37t1TKBTNzc05OTm6mzdoamrq5uZWWlra4Z7M0wH1WfJCoXDlypVZWVmpqak1NTX5+flLliyxs7MLCQnRprVFixYdOXIkOTm5pqZGqVSWlpYyP9LBwcG2trZtrlvs6urq6+u7d+/eixcvNjQ0lJSUMMdavHgxs4OO6orF4rNnz164cKGmpqa5ufnatWvvvfeeWCwOCwsjhNy8eXP79u179+7l8/mUmp07d6o3wgyyl5dXh4NjKFiZpaAO8wah2xHMGwSapjs1L2v37t3MjH9TU9OpU6cmJSUxr33169evqKhoz549UqmUEOLs7Pzbb7/RNB0SEsLn8+3t7Xk8nlQqnT59elFRkaq1p0+f+vr6CoVCV1fXTz/9dPXq1YQQmUzGTCy8evWqs7OzSCQaO3bs48ePT506JZFIYmJiOnGm2lzzcrmcz+fX19czH7OyspjpA9bW1suWLdPYefXq1erzBltbW3fs2NGvXz8+n29paRkQEHDr1i1mU4dD9Pz58/DwcCcnJx6PZ2NjExgYWFBQQNN0QEAAIWTjxo1t9raioiI0NFQmkwkEAjMzszFjxnz11VeqrbqrO3XqVFdXVzMzM4FA4O7uHhwcnJ+fz2x62RSAHTt2qLfg7+9vb2+vWs2wHQYyb5D9HiAOgG6HOAAYevieDQkJsbKy0ukhtKHNNV9YWMjj8V42G17/lErluHHj9u/f34PqdqiiokIoFO7cuVObnQ0kDsBzAQCALukpKeZkMll0dHR0dLRqlVwWKZXK7OxshUIRHBzcU+pqIyoqatiwYXK5XBeN60jPiANGjRplbGw8bNgwXTS+aNEioVBIUVQPmubRjp07dzIvBH3xxRdMSfcmUdVzStbW1tZdu3b5+Ph0b7PqGVcZPB7P2tr6j3/8Y1ZWVncdpf1Ly8Czvr5mFxIwIiIigoKCgoODtXlhUKdyc3MzMzNzcnLaX9LAoOp2KD4+Pi8v79SpU3w+v9sb152eEQf89NNPvr6+Omo8JSXFoLJrdNGqVat++OEH9RK6W5e57t7W2ldYWPj222+HhYV1ONv4VakyrpqbmzN3xsrLy9PT0x88eBAYGKjl+ucdav/SMvCsr6/ThaQ769atS0lJqa6udnV1PXbsGNvd0cqWLVvkcvnWrVvZ7caECRMOHTqkSr7QI+q27/jx48+fP8/NzbW0tOz2xnWqZ8QBDFXyKO01NDR0+5+SPY6/v391dfWUKVM6V11jDLvYmvZ++eWXtWvXLlmyREf3gTRYWlpOmDDhf//3fwkhGRkZHe7fjZdWYmKikZFRSEgI63+ita+HXkg6FRsb+/z5c5qm7969q56l3sD5+flt27aN7V68bqZNmxYREaE+z6Kn6ElxQCfutLxSWs9OxBlcoOfUqCpDhw7NzMycN29e+yugdS9mdTBm9bT2deOlZZhZX7sdWxcSALSvJ8UBt2/f9vDwEIvFIpFo3Lhx6itgf//9956enubm5kKh0MvL68yZM6SttJ6EkIMHD44cOVIoFIrFYhcXF9WaWUZGRidPnpw0aZK5ubmdnd3/+3//T5sudZhwk355ss7t27ebmppKJJKysrKVK1fa29svWbJELBYbGRm98cYbtra2fD5fLBaPGDFi3LhxzFocFhYWa9asaf+sNWgkUb19+zb1gm+++UbLMdRorf0T7HBwDND169cJIePHj1eV6OfS6krWV1xIANAlrMxSUKflvMEJEya4ubndvXu3ubn5xo0bb731llAoZCan0jR99OjRqKioysrKp0+fjh49ulevXky5RlrPXbt2EUK2bt369OnTysrKL7/8ct68ebRa0syqqqrKysrJkycLBIK6ujpt+t9+wk1tknUuX7589+7dM2bM+L//+7/PPvuMEHLlypW6urqKioo///nPhJCTJ0+Wl5fX1dUx76Dm5eW1f9aFhYWEkL/+9a/MR/UkqoWFhWvXrmVO7dGjR5aWlj4+PkqlUvsx1EjJ2pVspFp66623hg4d+kpViHbzBtXfD6ivr8/JyXF2dvbz82PyrjJ0fWl1Y9ZXXEgvMpB5WXqg5TUPBsVArk/2e6B9HKD+Y8D83bZq1aoX92QSQjDJtdS/epqamiwsLHx9fVV7trS0JCQk0L9/yzQ0NDDlf//73wkhN27c0Kb/GnWTkpIIIbdv36Zpur6+3szMLDg4WLXzv/71L0KIKr+4Rl2appmvb4VCwXw8cOAAIUS1igVTPS0trf2zbufrW11AQIBQKPz111/bb62dr+9XPUH1wdGeTuMAjbDYy8vrwIEDzBPfF+ni0lLFATRNr1y5khDCrOiiHgfgQur0hWQg37N6gDigJzKQ65PXmXsIBsDLy8vc3JyJBjQwrxG8OKP3+vXrVVVVEydOVJUYGxsvX778ZS10blVw9YSbr5qs82WttbS0dNixl531y2RkZHz11VdxcXEDBgzodGtdyUZqIMzNzZm3AVpaWp48eXL27Fm5XB4bG3vp0iVra2uNnXV9acXExJw4cSIpKUkj3zkuJA2veiFp8+Lna6DD5D1gaAzkn6ynxgGEED6fr/oiOHny5I4dOwoKCphFodvcv6amhvyeOEs/upKsUxvanHWbnj59+umnn44aNYr5A7TTren6BPWJx+PZ29svWrRIqVR++OGHW7du/ctf/kL0e2kx67qPHTv2/fffj4uLU5XjQuoijbjqdZWQkJCQkMB2L6Dn6UnvCapraWmprKx0cnIihBQXFwcEBPTp0+fKlSvV1dXqX6DqmByRFRUVeutkV5J1dkjLs27T8uXLq6qq1FOJdK41nZ4gW5jsIDdv3iRsXFrdnvW1Q1y4kNi+7aoPBM8FeqDuWqqki3pqHPDtt9+2trYyS6zk5+c3Nzd/8sknbm5uzPJtbVZxcXGxsrI6e/as3jrZlWSdHdLyrF908uTJQ4cORUZGDho0iClZvXp151rT6Qmy5d///jchhLnLzcql1b1ZXzuECwmA43pSHNDU1FRdXd3S0nL16lW5XO7s7Mwk92TuCpw7d66xsbGwsFD9maJ6Wk8jI6N169ZdvHhRLpc/ePCgtbVVoVAwf/bpSFeSdXaonbNuR01Nzccffzxs2LC1a9cSQhobG3/++ee8vDwtx1DjNq9OT1BvGhoamMxgDx8+TElJ2bBhg7W19YoVKwhLl1b3Zn3tEC4kAK5j+76ItvMFUlJSfH19e/fuzePxevXqNWfOnPv376u2hoeHW1lZWVhYBAUFMTOS3d3di4uLNdJ60jT9+eefe3l5CYVCoVA4fPjwpKSkuLg4kUhEfk+amZqayqwK6eDg0OGUgQ4TbraTrFN1XEdHRyYDWEJCAtOai4vL999/v23bNnNzc0KIra3toUOH0tLSbG1tCSGWlpZHjhx52VmHhoYyu4nF4hkzZmgkUdXIk82YPHmylmO4YcMG9dbaP8EOB6d9ly9fHjNmjJ2dHdPJPn36+Pj4fPfddx1WpLW4R6rKuKpOIBD069fvk08+YXLCMnR3aXVX1ldcSO0wkPex9aDDax4MkIFcnxTN9irfQUFBhJCjR4+y2w14nVAUlZ6ePmvWLLY7AizLyMiYPXs2699yeoBrvicykOuzJz0XAAAAgO6FOKA9v/7664uLp6roKH01F2BgAQAMBOKA9nh4eLTzTCUtLY3tDvZUGFgAFp07dy4iIiIzM9PNzY0JvhcsWKC+g5+fn0QiMTY2HjRo0NWrV9nq5+HDh0eNGiWRSJydnRctWvT48WM91I2Li/Pw8BCJRGKx2MPDIzIyklkghBEdHe3p6SmVSgUCgUwmW7NmTW1tLbPp66+/jouL034NLsOBOAAAgEM+++yzxMTEdevWBQYG3rlzx93dvVevXqmpqSdPnlTtc/bs2aNHj06ZMqWgoICZnq1/6enp8+bNCwoKKi0tPX78+MWLFydNmqRaE1N3db///vsPP/ywuLj4yZMnmzdvjouLU88ofeHChWXLlt27d6+ioiI2NjYhIYF5xY0QMnXqVKFQOGHCBG0SlhoUxAEAAJ3X0NDg4+NjaE29zLZt29LS0jIyMiQSiaowMTHRyMgoJCSkurpap0d/JV9++WXfvn1Xr15tbm4+bNiwsLCwvLw8Lee1dqWuiYnJ0qVLbWxszMzMgoKCpk+f/s033zx69IjZamZmFhISYmVlJZFIZs2aFRAQcPr0aSZZBiFk+fLlQ4cOnTx5spYxh4FAHAAA0Hn79+8vKysztKbadPv27cjIyE2bNgmFQvVyHx+f0NDQBw8erFq1SndHf1UlJSV2dnaqpagcHR0JIffv39d13aysLPXxsbe3J4Sobv6fOHFCfW0PJgtJfX29qiQqKiovL69nLfCMOAAAuI6m6fj4+IEDBwoEAktLy+nTp//666/MJrlcbmJiwqx2QAhZunSpWCymKIpZRjo0NHTlypVFRUUURclkssTERKFQ2Lt3748//tjOzk4oFPr4+Kj+DH2lpgghp0+flkqlW7Zs6a7TTExMpGl66tSpL26KiYnp37//vn37zp0796pDlJycLBaLTU1Njx8/PmnSJKlU6uDgcOTIEVVdpVK5ceNGJycnkUg0ZMgQLRfTdXNzU4+KmAf8bm5uuq6robCw0MLCwtnZuc2tDx48EIlErq6uqhJLS8vx48cz6UY7cTh2dNtKBJ2l5TpCANojWFMFaJrWep2WjRs3mpiYHDx4sKqq6vr16yNGjLC2tmaWh6Jpet68eba2tqqdd+zYQQgpLy9nPmrkUw4JCRGLxTdv3mxsbCwoKGBeVVOtTPVKTZ04cUIikaiSL7dPm2vezc3N09NTo1CV+fqHH34wMjJycXGpra2l/zvzNd3REDGJoc+fP19dXV1WVjZu3DixWNzU1MRsXbVqlUAgOHbs2LNnz9atW2dkZPTTTz91eEa5ubl8Pj8xMbGmpubGjRsDBw6cOHGiNkPRxbqMpqam0tLS3bt3CwQCZnmuF9XV1UkkErlcrlEeERFBCLl27VqHRzGQdYRwPwAAOK2hoSE+Pn7GjBnz5883Nzf38vL64osvKioq9uzZ07kGeTwe83ezp6dncnKyQqFISUnpRDv+/v41NTWRkZGd64aGurq6u3fvvriMpoq3t/eKFSvu3bvHrBWtTssh8vHxkUqlNjY2wcHBdXV1xcXFhJDGxsbk5OSAgIDAwEALC4sNGzbw+XxtBmT8+PHh4eFyuVwqlQ4ePFihUOzbt0/Lk+1KXYajo6ODg0NUVNT27dtflq8yNjbWzs4uJiZGo7xfv36EkPz8/Fc6IosQBwAApxUUFNTW1o4cOVJVMmrUKBMTEy1fK2vfyJEjTU1NVbfQWVRWVkbTNLNC88vExMQMGDAgKSnp0qVL6uWvOkQmJiaEECaLxK1bt+rr6wcPHsxsEolEffr00WZA1q9fv2fPnvPnz9fW1t65c8fHx8fb21v1Rp7u6jJKSkrKysoOHz584MCB4cOHv/jeRlZWVkZGxpkzZ9TfuGQwg/zkyRPtD8cuxAEAwGnMLC8zMzP1QgsLC408yJ0mEAjKy8u7pamuaGxsZDrTzj5MjiuKot5///2GhgZVeVeGqK6ujhCyYcMG1UJh9+/fV3+xrk2PHj2Ki4v76KOP3nnnHbFY7Orqunfv3ocPHzJPUnRXV4XP59vY2Pj5+aWlpRUUFMTGxqpvTUtL27ZtW25urouLy4t1mXwfzID3CIgDAIDTLCwsCCEaP2lVVVUODg5db7y5ubm7muoi5sepw1VuvL29w8LCCgsLN2/erCrsyhDZ2NgQQnbt2qX+QPry5cvt1yosLFQqlX379lWVSKVSKyurgoKCDo/YlbovkslkxsbG6nV3796dmpp64cIF9UOoa2pqIr8PeI+AOAAAOG3w4MFmZmY///yzquTKlStNTU1vvPEG85HH42kkStZebm4uTdOjR4/uelNd1Lt3b4qitFkhYPPmzR4eHteuXVOVdDhE7XB0dBQKhXl5ea/UWybCUM3aJ4QoFIrKykpmBqDu6j59+nTu3LnqJUxUwdSlaTo8PDw/Pz87O1vj7og6ZpCZdJ09AuIAAOA0oVC4cuXKrKys1NTUmpqa/Pz8JUuW2NnZhYSEMDvIZLLKysrs7Ozm5uby8nKNaehWVlYPHz68d++eQqFgfuNbW1ufPXvW0tJy/fr10NBQJyenhQsXdqKpnJycbpw3aGpq6ubmVlpaqs2ApKSkqM+S73CI2m9t0aJFR44cSU5OrqmpUSqVpaWlzI90cHCwra1tm+sWu7q6+vr67t279+LFiw0NDSUlJcyxFi9ezOygo7pisfjs2bMXLlyoqalpbm6+du3ae++9JxaLw8LCCCE3b97cvn373r17+Xy+ekoUjTTczCB7eXl1ODiGgpVZCuowbxC6HcG8QaBpWut5Wa2trTt27OjXrx+fz7e0tAwICLh165Zq69OnT319fYVCoaur66effrp69WpCiEwmY2YDXr161dnZWSQSjR079vHjxyEhIXw+397ensfjSaXS6dOnFxUVda6pU6dOSSSSmJgYbc5Um2teLpfz+fz6+nrmY1ZWFjN9wNraetmyZRo7r169Wn3eYDtDlJSUxLwZ169fv6Kioj179kilUkKIs7Pzb7/9RtP08+fPw8PDnZyceDyejY1NYGBgQUEBTdMBAQGEkI0bN7bZ24qKitDQUJlMJhAIzMzMxowZ89VXX6m26q7u1KlTXV1dzczMBAKBu7t7cHBwfn4+s+llUwB27Nih3oK/v7+9vX1ra2ub7aszkHmD7PcAcQB0O8QBwND/9yyz6Kw+j8jQ5povLCzk8Xgvmw2vf0qlcty4cfv37+9BdTtUUVEhFAp37typzc4GEgfguQAAQHcy2IxzMpksOjo6OjpatUoui5RKZXZ2tkKh6ESecbbqaiMqKmrYsGFyuVwXjesI4gAAAK6IiIgICgoKDg5mPaVQbm5uZmZmTk5O+0saGFTdDsXHx+fl5Z06dYrP53d747qDOAAAoHusW7cuJSWlurra1dX12LFjbHenbVu2bJHL5Vu3bmW3GxMmTDh06JAq20KPqNu+48ePP3/+PDc319LSstsb1yke2x0AAHhNxMbGaiw4Y5j8/Pz8/PzY7sXrZtq0adOmTWO7F52B+wEAAADchTgAAACAuxAHAAAAcBfiAAAAAO4yiPcEf/zxx6CgILZ7Aa+VXbt2HT16lO1eAMuYFV458vWCa77H0WaZZz2gaJpmtwfx8fEd5p4CAB3JyckZPny4LqZRAYA2WI/e2I8DAIBFFEWlp6fPmjWL7Y4AADvwfgAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuIvHdgcAQK+qqqpomlYvqaure/bsmeqjmZkZn8/Xe78AgB2UxjcCALze3nnnnW+//fZlW42NjR88eGBra6vPLgEAi/BcAIBb5syZQ1FUm5uMjIzefvttBAEAnII4AIBbZs6cyeO1/UCQoqh3331Xz/0BAHYhDgDgFktLSz8/P2Nj4xc3GRkZBQQE6L9LAMAixAEAnDN//vzW1laNQh6P5+/vb25uzkqXAIAtiAMAOGfq1KkCgUCjUKlUzp8/n5X+AACLEAcAcI6pqWlAQIDG5ECRSDR58mS2ugQAbEEcAMBFc+fObW5uVn3k8/kzZ84UiUQsdgkAWIE4AICLJk6cqP4qQHNz89y5c1nsDwCwBXEAABfx+fzg4GATExPmo4WFxYQJE9jtEgCwAnEAAEfNmTOnqamJEMLn8+fPn/+yRQUA4PWGdYUBOKq1tbVv375PnjwhhFy6dGnMmDFs9wgAWID7AQAcZWRktGDBAkKInZ2dj48P290BAHbgTqCelJaW/vDDD2z3AuC/WFtbE0Leeuuto0ePst0XgP/i6Ojo7e3Ndi84Ac8F9CQjI2P27Nls9wIAoGeYOXMmwlP9wP0AvULUpQtMjIWxfSVBQUGEkKNHjx47dmzmzJlsd0dXcG30UMz1CfqB9wMAOO01DgIAQBuIAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwCAtk6dOmVubv6Pf/yD7Y7oyrlz5yIiIjIzM93c3CiKoiiKWXJRxc/PTyKRGBsbDxo06OrVq2z18/Dhw6NGjZJIJM7OzosWLXr8+LEe6sbFxXl4eIhEIrFY7OHhERkZWVNTo9oaHR3t6ekplUoFAoFMJluzZk1tbS2z6euvv46Li1Mqldp3EvQJcQAAaOv1noj/2WefJSYmrlu3LjAw8M6dO+7u7r169UpNTT158qRqn7Nnzx49enTKlCkFBQUjRoxgpZ/p6enz5s0LCgoqLS09fvz4xYsXJ02a1NLSouu633///YcfflhcXPzkyZPNmzfHxcWpTzq9cOHCsmXL7t27V1FRERsbm5CQoFoDYOrUqUKhcMKECVVVVZ04X9A1xAEAoC1/f//q6uopU6bo+kANDQ16Tnmwbdu2tLS0jIwMiUSiKkxMTDQyMgoJCamurtZnZ9r35Zdf9u3bd/Xq1ebm5sOGDQsLC8vLy7ty5Yqu65qYmCxdutTGxsbMzCwoKGj69OnffPPNo0ePmK1mZmYhISFWVlYSiWTWrFkBAQGnT58uKSlhti5fvnzo0KGTJ0/WMuYAfUIcAAAGZ//+/WVlZXo73O3btyMjIzdt2iQUCtXLfXx8QkNDHzx4sGrVKr11pkMlJSV2dnYURTEfHR0dCSH379/Xdd2srCz18bG3tyeEqG7+nzhxwtjYWLWVSV1RX1+vKomKisrLy0tISNDmWKBPiAMAQCuXLl1ycnKiKOrzzz8nhCQnJ4vFYlNT0+PHj0+aNEkqlTo4OBw5coTZOTExUSgU9u7d++OPP7azsxMKhT4+Pqq/O+VyuYmJSZ8+fZiPS5cuFYvFFEVVVFQQQkJDQ1euXFlUVERRlEwmI4ScPn1aKpVu2bJFR6eWmJhI0/TUqVNf3BQTE9O/f/99+/adO3euzbo0TcfHxw8cOFAgEFhaWk6fPv3XX39lNrU/RIQQpVK5ceNGJycnkUg0ZMiQ9PR0bXrr5uamHiQxD/jd3Nx0XVdDYWGhhYWFs7Nzm1sfPHggEolcXV1VJZaWluPHj09ISHi9ny71SDToBfN/ONu9eD1hbDth5syZM2fOfNVazG3e3bt3Mx/Xr19PCDl//nx1dXVZWdm4cePEYnFTUxOzNSQkRCwW37x5s7GxsaCggHk3rbi4mNk6b948W1tbVcs7duwghJSXlzMfAwMD3d3dVVtPnDghkUiio6NftcNaXhtubm6enp4ahe7u7nfv3qVp+ocffjAyMnJxcamtraVpOicnZ9q0aardNm7caGJicvDgwaqqquvXr48YMcLa2vrx48fM1vaHaNWqVQKB4NixY8+ePVu3bp2RkdFPP/3UYW9zc3P5fH5iYmJNTc2NGzcGDhw4ceJErYaja3UZTU1NpaWlu3fvFggEBw8ebHOfuro6iUQil8s1yiMiIggh165d6/Aonbs+oXNwPwAAusTHx0cqldrY2AQHB9fV1RUXF6s28Xg85g9lT0/P5ORkhUKRkpLSiUP4+/vX1NRERkZ2X6//o66u7u7du+7u7i/bwdvbe8WKFffu3Vu7dq3GpoaGhvj4+BkzZsyfP9/c3NzLy+uLL76oqKjYs2eP+m5tDlFjY2NycnJAQEBgYKCFhcWGDRv4fL424zN+/Pjw8HC5XC6VSgcPHqxQKPbt26flyXalLsPR0dHBwSEqKmr79u0vy6EaGxtrZ2cXExOjUd6vXz9CSH5+/gKottkAACAASURBVCsdEXQNcQAAdA8TExNCSHNzc5tbR44caWpqqrpnbjjKyspomjY1NW1nn5iYmAEDBiQlJV26dEm9vKCgoLa2duTIkaqSUaNGmZiYvOzNO/UhunXrVn19/eDBg5lNIpGoT58+2ozP+vXr9+zZc/78+dra2jt37vj4+Hh7e6veyNNdXUZJSUlZWdnhw4cPHDgwfPjwF1/jyMrKysjIOHPmjPoblwxmkJ88eaL94UAPEAcAgJ4IBILy8nK2e6GpsbGRECIQCNrZRygUpqSkUBT1/vvvNzQ0qMqZiXBmZmbqO1tYWCgUig6PW1dXRwjZsGED9bv79++rv1jXpkePHsXFxX300UfvvPOOWCx2dXXdu3fvw4cPmQcruqurwufzbWxs/Pz80tLSCgoKYmNj1bempaVt27YtNzfXxcXlxboikYj8PuBgOBAHAIA+NDc3V1VVOTg4sN0RTcyPU4er3Hh7e4eFhRUWFm7evFlVaGFhQQjR+NXX8jRtbGwIIbt27VJ/Unv58uX2axUWFiqVyr59+6pKpFKplZVVQUFBh0fsSt0XyWQyY2Nj9bq7d+9OTU29cOGC+iHUNTU1kd8HHAwH4gAA0Ifc3FyapkePHs185PF4L3uCoGe9e/emKEqbFQI2b97s4eFx7do1VcngwYPNzMx+/vlnVcmVK1eampreeOONDltzdHQUCoV5eXmv1FsmwlDN2ieEKBSKyspKZgag7uo+ffp07ty56iVMVMHUpWk6PDw8Pz8/Oztb4+6IOmaQbW1tOzwc6BPiAADQldbW1mfPnrW0tFy/fj00NNTJyWnhwoXMJplMVllZmZ2d3dzcXF5erjGF3crK6uHDh/fu3VMoFM3NzTk5ObqbN2hqaurm5lZaWtrhnszTAfVZ8kKhcOXKlVlZWampqTU1Nfn5+UuWLLGzswsJCdGmtUWLFh05ciQ5ObmmpkapVJaWljI/0sHBwba2tm2uW+zq6urr67t3796LFy82NDSUlJQwx1q8eDGzg47qisXis2fPXrhwoaamprm5+dq1a++9955YLA4LCyOE3Lx5c/v27Xv37uXz+ZSanTt3qjfCDLKXl1eHgwP6hDgAALTy+eefjxo1ihASHh4+bdq05OTkXbt2EUKGDBly586dvXv3rly5khDy5z//ubCwkKnS2Njo5eUlEonGjRvXv3//b7/9VvUY/pNPPvH19Z0zZ86AAQM2b97M3CtWvbO2ZMmS3r17e3p6Tp48ubKyUten5u/vX1BQoHrw/9VXX8lksqKiolGjRn366afqe44ePZr55VP57LPPYmNjo6Ojra2tx48f7+LikpubKxaLCSEdDlFCQsKKFSvi4uJ69eplZ2cXGhr67NkzQkhTU1NZWdnx48df7CpFUUePHg0ODl68eLGlpaWnp2dxcXFmZua4ceOYHXRUVygUjhkz5oMPPrC3t5dIJEFBQS4uLj/++CPzniOt3ZIAP/30k729/ZAhQ7TZGfSHjcmKXIQ57rqDse0EPczPZlaZ1ekhOqTltVFYWMjj8V42G17/lErluHHj9u/f34PqdqiiokIoFO7cuVObnbF+gD7hfgAA6EpPSTEnk8mio6Ojo6NVq+SySKlUZmdnKxSK4ODgnlJXG1FRUcOGDZPL5bpoHLoCccBrRRdpYfWcara1tXXXrl26zjFz+PBhiqK6eJTXYLRBJSIiIigoKDg4mPWUQrm5uZmZmTk5Oe0vaWBQdTsUHx+fl5d36tQpPp/f7Y1DFyEOeK3QOli4WxdtvkxhYeHbb78dFhbW4SzqLjp8+LC7u/vly5dv377d6UZ6+mjr1Lp161JSUqqrq11dXY8dO8Z2d7SyZcsWuVy+detWdrsxYcKEQ4cOqZIv9Ii67Tt+/Pjz589zc3MtLS27vXHoBuw+luAOHT3Drq+v9/b2Nvw2tZGXlzdjxozU1NRhw4YNHTpU+4qvOrYVFRWurq6pqamEkMjISO0rvk6jzZHnr3h3pIfiyPVpIHA/oGfTRXpWPad8VRk6dGhmZua8efPaX9mt6zIyMvz9/adOnSoUCplXw7Ss+DqNNgAAA3GAYfn+++89PT3Nzc2FQqGXl9eZM2dUmw4ePDhy5EihUCgWi11cXDZv3qyRnlUjLezAgQMpijIyMnrjjTeY2+xr1qxhWv7b3/72/9m787gojvR/4NXAMDMMMxyKiNyHiohndCMYl6AbjGFFERC8Eq+EGM2IqFFEDCKiqAu8MJBE9Mdmvbg0YFSMq4YYo+ZYJSJuDKIoeCEIDKfA0L8/+pXZ+SLHcAw92J/3X+nqrurqmonz0N1VT3vn6rhN0rMsqxriyJEjc+bMEYvFHh4eRUVFP/zww8vHYLQBgCtYvh/BGSren0xPTw8PD3/+/Hl5efmkSZMGDBjAlDOzkHfs2FFeXv78+fMvv/xywYIF9EvpWZXTwjY3N9vY2FhZWTU3NysOWLNmjWId0/bO1UGbdM+yrKro9ddfV99zgfv375uYmDBjcvDgQULIsmXLWh3DhdHmyH1XPBfopzjy/dQQuB+gWXx9fT/99FMjIyNjY2MvL6/y8vJnz541NTVt3brV3d1948aNxsbGRkZGy5YtY1Z06YC2tvbq1asfPHhw/PhxpqSuru7YsWNLly7t4Fwdt9mTLKsa4siRI3//+9+ZJeG8vLz4fH56erpy5hiMNgBwig7bHYB2MRNs5HL5jRs3Kisrp0+frtjF/Op02sLy5cvDw8Pj4uL8/PwIIYcOHZo9e7ZEIungXB032JMsqxriyJEjigxpEonEw8Pjm2++ycrKUsyZ5s5oX716lenqK4xZyPaVv8xXz9WrVxWpKEDdcD9As5w6derNN980MTHh8/mffPIJUyiTycifmc26RF9f/4MPPrh8+fLPP/9MCPn888+VF/Fo81wd60mWVU1w8+bNvLy8mTNnKtY/Z2bq/+tf/1Icg9EGAE7B/QAN8uDBA29v7zlz5vy///f/hgwZsnfvXuYHg0niWVZW1o02pVJpXFxcbGzsihUrLC0t7e3tOz5Xx3qSZVUTHD58eN68eUeOHFGUVFRUmJubnz179smTJ8zMae6M9qRJk9LT03ulKY2Vlpbm7+//yl/mqwe3cPoS7gdokLy8vKampo8++sjOzk4gEFAUxZTb2NgYGxufPXu2G21aWFjMnTs3IyMjLCwsKCio03N1rCdZVllH03RKSsrKlSuVC42MjPz8/ORyuSI4wGgDAKcgDtAgVlZWhJBz5841NDQUFBQoHgPz+fxNmzZdvHhRKpU+fPiwpaWlurr61q1b5KX0rG02u3bt2ubm5oqKiqlTp3Z6ro7b7EmWVdZdvnxZIpFMnjy5VfmKFSuI0qMBjDYAcAvbExa4QsX5Sxs2bDA2NjY0NPTz82Mmkdvb2z948ICm6c8++2zUqFECgUAgEIwbNy4hIYGm6WvXrllbWwuFwjfeeGPz5s3MnW09PT0vLy/lZt3d3ffv36/iuTpus6WlZffu3UOHDuXxeEZGRt7e3rdv32YaTEhIYFYmHzp0aGFh4b59+5i35Kytrf/4449Or/3KlSuTJ082MzNjvpmDBw92dXX9/vvve2Vsly1bJhKJdHR0xowZc+3aNUX5tm3bFGc0NzdnRpXmwGhzZF4W5g32Uxz5fmoIin5V1jPXcMxzSoy2OmBsu4F5/vrKPzjHd6Of4sj3U0PguQAAAAB3IQ6AvvD7779T7VNTvnOArjp37lxISMixY8fs7OyYL+eiRYuUD/Dw8BCLxdra2iNHjrx27Rpb/Txy5MjEiRPFYrG1tfWSJUuePHnSB3Wjo6MdHR2FQqFIJHJ0dAwLC2Mm2TIiIiKcnJwkEgmfz3dwcPjkk09qamqYXSdOnIiOju50wQxgDbuPJbgDzynVB2PbDRx5/tql78aWLVtmzpwpk8mYTXt7+wEDBhBCTp48qXxYdnb2rFmzermjXZGSkkIIiY6OrqysvH79up2d3dixY5uamtRd19PTc8+ePaWlpdXV1WlpaTwe76233lLsdXNzS0hIKC8vl8lkqampPB7v7bffVuyNi4tzc3OrqKhQ8Ro58v3UELgfAABqUV9f7+rqqmlNtWfnzp0pKSlpaWlisVhRGB8fr6WlFRgYWFVVpdazd8mXX345ZMiQ9evXGxgYjB07Njg4ODc3t71VJnuxrq6u7sqVK01MTPT19f38/GbPnv3vf//78ePHzF59ff3AwEBjY2OxWDx37lxvb+8zZ84w+TIIIatXrx4zZsw777zT3NzcvasG9UEcAABq0YspldWdnfnOnTthYWFbt24VCATK5a6urkFBQQ8fPly3bp36zt5VxcXFZmZmilUoLC0tCSH3799Xd93jx48rj4+5uTkhRHHz/+TJk0zaDsbAgQMJIUzuTUZ4eHhubm5cXJwq54K+hDgAANpFt5/4WCqV6urqMhMdCSErV64UiUQURTFLMbZKqRwfHy8QCAYNGvThhx+amZkJBAJXV1fFn6FdaooQcubMGYlEsn379t66zPj4eJqmvby8Xt4VGRk5bNiw/fv3nzt3rqtD1GluaLlcvmXLFisrK6FQOHr0aOYpRqfs7OyUoyLmAb+dnZ2667ZSUFBgaGhobW3d5t6HDx8KhUJbW1tFiZGRkZubW1xcHI3pG5qG3ccS3IFn2OqDse0GFZ+/dpz4eMGCBaampoqDd+/eTQh59uwZs9kqpXJgYKBIJLp161ZDQ0N+fj7zqhqzNkZXmzp58qRYLI6IiOi0/yp+N+zs7JycnFoV2tvb37t3j6bpy5cva2lp2djY1NTU0C+9H9CT3NDr1q3j8/kZGRkVFRWbNm3S0tL65ZdfOu1tTk4Oj8eLj4+XyWQ3b94cMWLE9OnTO63V87qMxsbGkpKSvXv38vn8gwcPtnlMbW2tWCyWSqWtykNCQggh169f7/QseD+gL+F+AAC0TcXEx6rT0dFh/m52cnJKTEysrq5OTk7uRjuenp4ymSwsLKx73Wiltrb23r17imQQL3NxcVmzZk1RUdHGjRtb7epJbuiGhobExERvb28fHx9DQ8PNmzfzeDxVBsTNzW3Dhg1SqVQikTg7O1dXV+/fv1/Fi+1JXYalpaWFhUV4ePiuXbv8/f3bPCYqKsrMzCwyMrJV+dChQwkheXl5XTojqBviAABoW1cTH3fJhAkT9PT0FLfQWVRaWkrTNLM4Y3siIyOHDx+ekJBw6dIl5fKe5Ia+fft2XV2ds7Mzs0soFA4ePFiVAQkNDd23b9/58+dramru3r3r6urq4uKieCNPfXUZxcXFpaWlR44c+eqrr8aNG/fyexvHjx9PS0v79ttvld+4ZDCD/PTpU9VPB30AcQAAtE3diY/5fP6zZ896pameaGhoYDrTwTECgSA5OZmiqKVLl9bX1yvKezJEtbW1hJDNmzcrFtK4f/++8ot1bXr8+HF0dPQHH3wwdepUkUhka2ublJT06NEj5kmK+uoq8Hg8ExMTDw+PlJSU/Pz8qKgo5b0pKSk7d+7MycmxsbF5ua5QKCR/DjhoDsQBANA2tSY+bmpq0pCM1cyPU6er3Li4uAQHBxcUFGzbtk1R2JMhMjExIYTExsYqP6m9cuVKx7UKCgrkcjmTHZshkUiMjY3z8/M7PWNP6r7MwcFBW1tbue7evXsPHTp04cIF5VMoa2xsJH8OOGgOxAEA0LZOEx/r6Oi0l3exUzk5OTRNT5o0qedN9dCgQYMoilJlhYBt27Y5Ojpev35dUdKT3NCWlpYCgSA3N7dLvWUiDMWsfUJIdXX18+fPmRmA6qtbXl4+f/585RImqmDq0jS9YcOGvLy8zMzMVndHlDGDbGpq2unpoC8hDgCAtnWa+NjBweH58+eZmZlNTU3Pnj1rNQ395ZTKLS0tFRUVzc3NN27cCAoKsrKyWrx4cTeays7O7sV5g3p6enZ2diUlJaoMSHJysvIs+Z7khhYIBEuWLDl69GhiYqJMJpPL5SUlJcyPdEBAgKmpaZvrFtva2rq7uyclJV28eLG+vr64uJg517Jly5gD1FRXJBKdPXv2woULMpmsqanp+vXr7733nkgkCg4OJoTcunVr165dSUlJPB5PecnwPXv2KDfCDPKoUaM6HRzoU6zMUuAgzG1TH4xtN6g4L6uDxMc0TZeXl7u7uwsEAltb248//nj9+vWEEAcHB2Y2oHJK5SdPngQGBvJ4PHNzcx0dHYlEMnv27MLCwu41dfr0abFYHBkZ2Wn/VfxuSKVSHo9XV1fHbB4/fpyZPjBw4MBVq1a1Onj9+vXK8wZ7khv6xYsXGzZssLKy0tHRMTEx8fHxyc/Pp2na29ubELJly5Y2e1tWVhYUFOTg4MDn8/X19SdPnvz1118r9qqvrpeXl62trb6+Pp/Pt7e3DwgIyMvLY3a1NwVg9+7dyi14enqam5u3tLS02b4yzBvsS/jXs4/gt0p9MLbd0Pf/zjKLzvblGWmVvxsFBQU6OjrtzYbve3K5fMqUKQcOHOhHdTtVVlYmEAj27NmjysGIA/oSngsAQB/R2IxzDg4OERERERERilVyWSSXyzMzM6urq7uRh5OtuqoIDw8fO3asVCpVR+PQE4gDAABISEiIn59fQEAA6ymFcnJyjh07lp2d3fGSBhpVt1MxMTG5ubmnT5/m8Xi93jj0EOIAAFC7TZs2JScnV1VV2draZmRksN2dtm3fvl0qle7YsYPdbkybNu3w4cOKbAv9om7HsrKyXrx4kZOTY2Rk1OuNQ8/psN0BAHj1RUVFtVpwRjN5eHh4eHiw3YtXzaxZs2bNmsV2L6BduB8AAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchfkCfYqiKLa78MrC2HYDRwaNI5f5ivH19WW7C1xB0TTNdh84oaSk5PLly2z3AqA1f3//oKAgFxcXtjsC8H9YWlria9k3EAcAcBpFUampqXPnzmW7IwDADrwfAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADu0mG7AwDQp44ePVpdXa1ccu7cucrKSsWmt7e3iYlJn/cLANhB0TTNdh8AoO8sXrz4q6++4vF4zCbzLwBFUYQQuVyur69fWlrK5/PZ7CIA9CE8FwDglnnz5hFCmv7U3Nzc3NzM/Le2trafnx+CAABOwf0AAG5pbm42NTV9/vx5m3vPnz8/derUPu4SALAI9wMAuEVHR2fevHmK5wLKBg4c6Obm1vddAgAWIQ4A4Jx58+Y1NTW1KuTxeIsWLdLW1malSwDAFjwXAOAcmqatrKxKSkpalf/8888TJ05kpUsAwBbcDwDgHIqiFi5c2OrRgKWl5YQJE9jqEgCwBXEAABe1ejTA4/EWL17MzB4EAE7BcwEAjnJ0dLx9+7Zi8+bNmyNHjmSxPwDACtwPAOCoRYsWKR4NODk5IQgA4CbEAQActXDhwubmZkIIj8d777332O4OALADzwUAuGvChAn/+c9/KIoqKiqysrJiuzsAwALcDwDgrnfffZcQ8vrrryMIAOAs5BvURDExMVeuXGG7F/Dqa2hooCjqxYsXfn5+bPcFOCE9PZ3tLkBruB+gia5cuXL16lW2e9HPZGRkvLwwDqeUlJRkZGR0qYpAIDA1NbWwsFBTl9QEn3V/1I3vJ/QNvB+giZg/zhA4dwlFUampqXPnzmW7I6xJS0vz9/fv6v/Rd+7ccXBwUFOX1ASfdX/Uve8n9AHcDwDgtH4XBABA70IcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAJx2+vRpAwODb775hu2OqMu5c+dCQkKOHTtmZ2dHURRFUYsWLVI+wMPDQywWa2trjxw58tq1a2z188iRIxMnThSLxdbW1kuWLHny5Ekf1I2OjnZ0dBQKhSKRyNHRMSwsTCaTKfZGREQ4OTlJJBI+n+/g4PDJJ5/U1NQwu06cOBEdHS2Xy1XvJGgsxAEAnPZqz+P69NNP4+PjN23a5OPjc/fuXXt7+wEDBhw6dOjUqVOKY86ePZuenj5z5sz8/Pzx48ez0s/U1NQFCxb4+fmVlJRkZWVdvHhxxowZTPYHtdb94Ycf3n///QcPHjx9+nTbtm3R0dG+vr6KvRcuXFi1alVRUVFZWVlUVFRcXJxivSkvLy+BQDBt2rTKyspuXC9oFho0j6+vr6+vL9u96GcIIampqWz3gk2pqama/H90XV2di4tLrzSl4me9Y8eOYcOG1dfXK0rs7e0PHz6spaVlbm5eWVmpKM/Ozp41a1av9K173N3dhwwZ0tLSwmx+9tlnhJBLly6pu663t7fy+DA/848ePWI2PT09m5ubFXuZBRsePHigKJFKpS4uLk1NTaqcS8O/n1yG+wEA0BcOHDhQWlraZ6e7c+dOWFjY1q1bBQKBcrmrq2tQUNDDhw/XrVvXZ53pVHFxsZmZGUVRzKalpSUh5P79++que/z4ceXxMTc3J4Qobv6fPHlSW1tbsXfgwIGEkLq6OkVJeHh4bm5uXFycKucCjYU4AIC7Ll26ZGVlRVEU80dkYmKiSCTS09PLysqaMWOGRCKxsLA4evQoc3B8fLxAIBg0aNCHH35oZmYmEAhcXV1/+uknZq9UKtXV1R08eDCzuXLlSpFIRFFUWVkZISQoKGjt2rWFhYUURTErF505c0YikWzfvl1NlxYfH0/TtJeX18u7IiMjhw0btn///nPnzrVZl6bpmJiYESNG8Pl8IyOj2bNn//7778yujoeIECKXy7ds2WJlZSUUCkePHs38EdwpOzs75SCJecBvZ2en7rqtFBQUGBoaWltbt7n34cOHQqHQ1tZWUWJkZOTm5hYXF0e/0k+XXn0s34+AtuC5QDcQPBfo1n3X4uJiQsjevXuZzdDQUELI+fPnq6qqSktLp0yZIhKJGhsbmb2BgYEikejWrVsNDQ35+fnMu2mKG8ULFiwwNTVVtLx7925CyLNnz5hNHx8fe3t7xd6TJ0+KxeKIiIhuXKkqn7WdnZ2Tk1OrQnt7+3v37tE0ffnyZS0tLRsbm5qaGvql5wJbtmzR1dU9ePBgZWXljRs3xo8fP3DgwCdPnjB7Ox6idevW8fn8jIyMioqKTZs2aWlp/fLLL51eUU5ODo/Hi4+Pl8lkN2/eHDFixPTp01UcjZ7UZTQ2NpaUlOzdu5fP5x88eLDNY2pra8VisVQqbVUeEhJCCLl+/XqnZ8FzAY2F+wEA0Jqrq6tEIjExMQkICKitrX3w4IFil46ODvOHspOTU2JiYnV1dXJycjdO4enpKZPJwsLCeq/X/1NbW3vv3j17e/v2DnBxcVmzZk1RUdHGjRtb7aqvr4+JiZkzZ87ChQsNDAxGjRr1xRdflJWV7du3T/mwNoeooaEhMTHR29vbx8fH0NBw8+bNPB5PlfFxc3PbsGGDVCqVSCTOzs7V1dX79+9X8WJ7UpdhaWlpYWERHh6+a9cuf3//No+JiooyMzOLjIxsVT506FBCSF5eXpfOCBoFcQAAtEtXV5cQ0tTU1ObeCRMm6OnpKe6Za47S0lKapvX09Do4JjIycvjw4QkJCZcuXVIuz8/Pr6mpmTBhgqJk4sSJurq6iicgrSgP0e3bt+vq6pydnZldQqFw8ODBqoxPaGjovn37zp8/X1NTc/fuXVdXVxcXF+ZWjVrrMoqLi0tLS48cOfLVV1+NGzfu5dc4jh8/npaW9u2334rF4la7mEF++vSp6qcDTYM4AAC6j8/nP3v2jO1etNbQ0EAI4fP5HRwjEAiSk5Mpilq6dGl9fb2inJkIp6+vr3ywoaFhdXV1p+etra0lhGzevJn60/3795VfrGvT48ePo6OjP/jgg6lTp4pEIltb26SkpEePHjEPVtRXV4HH45mYmHh4eKSkpOTn50dFRSnvTUlJ2blzZ05Ojo2Nzct1hUIh+XPAoZ9CHAAA3dTU1FRZWWlhYcF2R1pjfpw6XeXGxcUlODi4oKBg27ZtikJDQ0NCSKtffRUv08TEhBASGxur/PD1ypUrHdcqKCiQy+VDhgxRlEgkEmNj4/z8/E7P2JO6L3NwcNDW1lauu3fv3kOHDl24cEH5FMoaGxvJnwMO/RTiAADoppycHJqmJ02axGzq6Oi09wShjw0aNIiiqKqqqk6P3LZtm6Oj4/Xr1xUlzs7O+vr6v/76q6Lkp59+amxsfO211zptzdLSUiAQ5Obmdqm3TITx+PFjRUl1dfXz58+ZGYDqq1teXj5//nzlEiaqYOrSNL1hw4a8vLzMzMxWd0eUMYNsamra6elAYyEOAIAuaGlpqaioaG5uvnHjRlBQkJWV1eLFi5ldDg4Oz58/z8zMbGpqevbsWasp7MbGxo8ePSoqKqqurm5qasrOzlbfvEE9PT07O7uSkpJOj2SeDijPkhcIBGvXrj1+/PihQ4dkMlleXt6KFSvMzMwCAwNVaW3JkiVHjx5NTEyUyWRyubykpIT5kQ4ICDA1NW1z3WJbW1t3d/ekpKSLFy/W19cXFxcz51q2bBlzgJrqikSis2fPXrhwQSaTNTU1Xb9+/b333hOJRMHBwYSQW7du7dq1KykpicfjUUr27Nmj3AgzyKNGjep0cEBzsTJLATqGeYPdQDBvsOvzsvbu3cvM+NfT0/Py8kpISGBe+xo6dGhhYeG+ffskEgkhxNra+o8//qBpOjAwkMfjmZub6+joSCSS2bNnFxYWKlorLy93d3cXCAS2trYff/zx+vXrCSEODg7M7JO8IgAAIABJREFUxMJr165ZW1sLhcI33njjyZMnp0+fFovFkZGR3bhSVT5rqVTK4/Hq6uqYzePHjzPTBwYOHLhq1apWB69fv1553mBLS8vu3buHDh3K4/GMjIy8vb1v377N7Op0iF68eLFhwwYrKysdHR0TExMfH5/8/Hyapr29vQkhW7ZsabO3ZWVlQUFBDg4OfD5fX19/8uTJX3/9tWKv+up6eXnZ2trq6+vz+Xx7e/uAgIC8vDxmV3tTAHbv3q3cgqenp7m5uWI1ww5g3qDGwqeiiRAHdAPigD74dzYwMNDY2Fitp1CFKp91QUGBjo5Oe7Ph+55cLp8yZcqBAwf6Ud1OlZWVCQSCPXv2qHIw4gCNhecCANAF/SXFnIODQ0REREREhGKVXBbJ5fLMzMzq6uqAgID+UlcV4eHhY8eOlUql6mgc+gziAAB4NYWEhPj5+QUEBKjywqBa5eTkHDt2LDs7u+MlDTSqbqdiYmJyc3NPnz7N4/F6vXHoS4gDXhHLly8Xi8UURXX1XWXN1NLSEhsb6+rq2ottKmegZ+jq6g4aNOjNN9/cvXt3RUVFL57rlbRp06bk5OSqqipbW9uMjAy2u6OS7du3S6XSHTt2sNuNadOmHT58WJF8oV/U7VhWVtaLFy9ycnKMjIx6vXHoY4gDXhH79+9PSkpiuxe9o6Cg4K9//WtwcHCnC7B0iSIDvYGBAU3TLS0tpaWlaWlptra2GzZsGDlypPJUMXhZVFTUixcvaJq+d++ecpZ6Defh4bFz5062e/GqmTVrVkhIiPI8C+i/EAeA2tXX16v+l/1vv/22cePGFStWjB07Vq29oijK0NDwzTffTE5OTktLe/r0qaenJ+s3kF/WpdEDAOgqxAGvDkUCck3TpcTzY8aMOXbs2IIFCzpeFLZ3+fr6Ll68uLS09Isvvuizk6qoS6MHANBViAP6MZqmd+/ePXz4cD6fb2BgwEzXZuzatUtPT08sFpeWlq5du9bc3JyZAN1eVvWOU8uTDjOydzXxvGZiFsPJzs4mGD0A4BQW5yxCe1RcPyA0NJSiqH/84x8VFRV1dXUJCQlEKRE4kyV99erVe/funTNnzn//+9+Os6p3nFq+47pdSjyvotdff33MmDGqH09UWz9A8X5AKzKZjBBiaWnJbPbH0ePO/GwVP2vQKNz5fvY7uB/QX9XX18fGxv7tb38LDg42NDQUCoXGxsYvH7Zz585Vq1YdO3bM2tq606zq7aWWVzEje7/GzLZolV0GowcArzwdtjsA3XTnzp26urpp06apeHxXs6orp5bvat3+qLa2lqZpZo3Yl/Wj0dPY10R6l7+/v7+/P9u9AHgVIA7or5j0HkyeU1V0I6u6IrV8TzKy9xd//PEHIcTR0bHNvf1o9Ji7r682f3//oKAgFxcXtjsCXXDlypW4uDi2ewFtQBzQXwkEAkLIixcvVDy+q1nVlVPL9yQje39x5swZQsiMGTPa3NuPRm/u3LnqaFaj+Pv7u7i4cOFKXzGIAzQT3g/or5ydnbW0tL7//nvVj+9SVnXl1PKd1tWcxPPd8+TJk9jYWAsLi6VLl7Z5AEYPAF5ViAP6KyalaUZGxoEDB2Qy2Y0bNzp+70yVrOrtpZbvtG6XEs/3/lh0EU3TNTU1TKbUZ8+epaamTp48WVtbOzMzs733AzB6APDKYnW2ArRNxXmD1dXVy5cvHzBggL6+/htvvLFlyxZCiIWFxW+//RYdHS0UCgkhlpaWitSrHWRVpztLLd9x3S4lnu/4oq5cuTJ58mQzMzPm+zl48GBXV9fvv/++09Egnc0lO3HixOjRo/X09HR1dbW0tMifSwr+5S9/iYiIKC8vVxzZT0ePO/OyOv2sQQNx5/vZ71A0TbMRfkBH/Pz8CCHp6el9edIPP/wwPT29vLy8L0/aiyiKSk1NZeuZsSaMXlpamr+/Pxf+j2b3s4bu4c73s9/BcwH4n/6SWl4zYfQAoD9CHAB95/fff6faFxAQwHYH4RV07ty5kJAQ5azTixYtUj7Aw8NDLBZra2uPHDny2rVrbPXzyJEjzDKU1tbWS5YsefLkSR/UjY6OdnR0FAqFIpHI0dExLCyMWViTERER4eTkJJFI+Hy+g4PDJ598UlNTw+w6ceJEdHQ0Yt9XBMvPJaAtKr4f0ItCQkJ0dXUJITY2Nunp6X156t5C2HtmrCGjx53nr6p/1lu2bJk5c6ZMJmM27e3tBwwYQAg5efKk8mHZ2dmzZs3q/Y6qLCUlhRASHR1dWVl5/fp1Ozu7sWPHNjU1qbuup6fnnj17SktLq6ur09LSeDzeW2+9pdjr5uaWkJBQXl4uk8lSU1N5PN7bb7+t2BsXF+fm5lZRUaHiNXLn+9nv4FPRRH0fB7wCWIwDNEQf/DtbV1fn4uLCelMqftY7duwYNmxYfX29osTe3v7w4cNaWlrm5uaVlZWKctbjAHd39yFDhjBzWGia/uyzzwghly5dUnddb29v5fFh3kx69OgRs+np6dnc3KzYy7yQociaQdO0VCp1cXFRMeZAHKCx8FwAAFTVi0mQ1Z1P+c6dO2FhYVu3bmVW3FJwdXUNCgp6+PDhunXr1Hf2riouLjYzM1OsCW1paUkIaTWDVB11jx8/rjw+5ubmhBDFzf+TJ09qa2sr9g4cOJAQUldXpygJDw/Pzc3F6kD9HeIAAG6heykJcsfZlruaT/nMmTMSiWT79u29dZnx8fE0TXt5eb28KzIyctiwYfv37z937lxXhygxMVEkEunp6WVlZc2YMUMikVhYWBw9elRRVy6Xb9myxcrKSigUjh49WsVlnu3s7JSjIuYBv52dnbrrtlJQUGBoaGhtbd3m3ocPHwqFQltbW0WJkZGRm5tbXFwcjVkA/Rq7tyOgTXgu0A0EzwVUu+/ai0mQO8623KWmTp48KRaLIyIiVLlSVT5rOzs7JyenVoX29vb37t2jafry5ctaWlo2NjY1NTX0S88FOh4iJif1+fPnq6qqSktLp0yZIhKJGhsbmb3r1q3j8/kZGRkVFRWbNm3S0tL65ZdfOr2inJwcHo8XHx8vk8lu3rw5YsSI6dOnqzIUPazLaGxsLCkp2bt3L5/PVyyY0Uptba1YLJZKpa3KQ0JCiFK68w7guYDGwv0AAA7p9STI7WVb7ipPT0+ZTBYWFta9brRSW1t77949e3v79g5wcXFZs2ZNUVHRxo0bW+1ScYhcXV0lEomJiUlAQEBtbe2DBw8IIQ0NDYmJid7e3j4+PoaGhps3b+bxeKoMiJub24YNG6RSqUQicXZ2rq6u3r9/v4oX25O6DEtLSwsLi/Dw8F27drWXxTEqKsrMzCwyMrJV+dChQwkheXl5XTojaBTEAQAcotYkyMrZltlVWlpK07Senl4Hx0RGRg4fPjwhIeHSpUvK5V0dImaqCLPk8+3bt+vq6pydnZldQqFw8ODBqgxIaGjovn37zp8/X1NTc/fuXVdXVxcXl+Li4k4r9rAuo7i4uLS09MiRI1999dW4ceNefm/j+PHjaWlp3377rVgsbrWLGeSnT5+qfjrQNIgDADhE3UmQFdmW2dXQ0MB0poNjBAJBcnIyRVFLly6tr69XlPdkiGprawkhmzdvVqyKcf/+feUX69r0+PHj6OjoDz74YOrUqSKRyNbWNikp6dGjR8yTFPXVVeDxeCYmJh4eHikpKfn5+VFRUcp7U1JSdu7cmZOTY2Nj83JdZgVuZsChn0IcAMAhak2CrJxtmV3Mj1Onq9y4uLgEBwcXFBRs27ZNUdiTITIxMSGExMbGKj98vXLlSse1CgoK5HL5kCFDFCUSicTY2Dg/P7/TM/ak7sscHBy0tbWV6+7du/fQoUMXLlxQPoWyxsZG8ueAQz+FOACAQ9SaBFk523IPm+qhQYMGURRVVVXV6ZHbtm1zdHS8fv26oqSrOaaVWVpaCgSC3NzcLvWWiTAeP36sKKmurn7+/DkzA1B9dcvLy+fPn69cwkQVTF2apjds2JCXl5eZmdnq7ogyZpBNTU07PR1oLMQBABzS60mQ28u23NWmsrOze3HeoJ6enp2dXUlJiSoDkpycrDxLXpUc0x20tmTJkqNHjyYmJspkMrlcXlJSwvxIBwQEmJqatrlusa2trbu7e1JS0sWLF+vr64uLi5lzLVu2jDlATXVFItHZs2cvXLggk8mampquX7/+3nvviUSi4OBgQsitW7d27dqVlJTE4/GU1//es2ePciPMII8aNarTwQHNxcosBegY5g12A8G8QdXmZfViEuSOsy13qanTp0+LxeLIyEhVrlSVz1oqlfJ4vLq6Ombz+PHjzPSBgQMHrlq1qtXB69evV5432MEQJSQkMG/GDR06tLCwcN++fRKJhBBibW39xx9/0DT94sWLDRs2WFlZ6ejomJiY+Pj45Ofn0zTt7e1NCNmyZUubvS0rKwsKCnJwcODz+fr6+pMnT/76668Ve9VX18vLy9bWVl9fn8/n29vbBwQE5OXlMbvamwKwe/du5RY8PT3Nzc0Vqxl2APMGNRY+FU2EOKAbEAf0/b+zgYGBxsbGfXlGhiqfdUFBgY6OTnuz4fueXC6fMmXKgQMH+lHdTpWVlQkEgj179qhyMOIAjYXnAgDQfRqbcc7BwSEiIiIiIkKxSi6L5HJ5ZmZmdXV1N5JqslVXFeHh4WPHjpVKpepoHPoM4gAAeDWFhIT4+fkFBASo8sKgWuXk5Bw7diw7O7vjJQ00qm6nYmJicnNzT58+zePxer1x6EuIAwCgOzZt2pScnFxVVWVra5uRkcF2d9q2fft2qVS6Y8cOdrsxbdq0w4cPK7It9Iu6HcvKynrx4kVOTo6RkVGvNw59TIftDgBAvxQVFdVqwRnN5OHh4eHhwXYvXjWzZs2aNWsW272A3oH7AQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7sJ7ghqqpKQkLS2N7V70M50mdHm1MZfPka8Nxz/r/ggfmcaiaJpmuw/Qmp+fn8ZOxAIA6Db84mggxAEAnEZRVGpq6ty5c9nuCACwA+8HAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF0XTNNt9AIC+ExgYePv2bcXmtWvXbG1tjYyMmE1tbe2vvvrKwsKCpd4BQF/TYbsDANCnTE1N9+3bp1xy48YNxX/b2dkhCADgFDwXAOCW+fPnt7dLV1d38eLFfdgXAGAfngsAcI6zs/OtW7fa/H//9u3bw4YN6/suAQBbcD8AgHPeffddbW3tVoUURY0ZMwZBAADXIA4A4Jx58+bJ5fJWhdra2u+99x4r/QEAFuG5AAAXubq6/vTTTy0tLYoSiqKKi4vNzc1Z7BUA9D3cDwDgokWLFlEUpdjU0tJ64403EAQAcBDiAAAu8vPzU96kKOrdd99lqzMAwCLEAQBcNHDgwGnTpineFqQoytvbm90uAQArEAcAcNTChQuZ14O0tbWnT58+YMAAtnsEACxAHADAUXPmzNHV1SWE0DS9cOFCtrsDAOxAHADAUSKR6O9//zshRFdXd+bMmWx3BwDYgTgAgLsWLFhACPH29haJRGz3BQDYgfUDNJGfn19GRgbbvQAA6GX4xdFAyDeooSZNmrRmzRq2e9EPxMbGEkIwVoSQK1euxMXFpaamdqnWoUOHAgICdHT60z8F/v7+QUFBLi4ubHcEuoD5frLdC2gD7gdoImZud3p6Otsd6QcwVgppaWn+/v5d/T+6oaFBIBCoqUtqQlFUamrq3Llz2e4IdEH3vp/QB/B+AACn9bsgAAB6F+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4A4LTTp08bGBh88803bHdEXc6dOxcSEnLs2DE7OzuKoiiKWrRokfIBHh4eYrFYW1t75MiR165dY6ufR44cmThxolgstra2XrJkyZMnT/qgbnR0tKOjo1AoFIlEjo6OYWFhMplMsTciIsLJyUkikfD5fAcHh08++aSmpobZdeLEiejoaLlcrnonQWMhDgDgtFd7Htenn34aHx+/adMmHx+fu3fv2tvbDxgw4NChQ6dOnVIcc/bs2fT09JkzZ+bn548fP56Vfqampi5YsMDPz6+kpCQrK+vixYszZsxobm5Wd90ffvjh/ffff/DgwdOnT7dt2xYdHe3r66vYe+HChVWrVhUVFZWVlUVFRcXFxSnSVXt5eQkEgmnTplVWVnbjekGjIA4A4DRPT8+qqqo+yC9QX1/v6uqq7rMo27lzZ0pKSlpamlgsVhTGx8draWkFBgZWVVX1ZWc69uWXXw4ZMmT9+vUGBgZjx44NDg7Ozc396aef1F1XV1d35cqVJiYm+vr6fn5+s2fP/ve///348WNmr76+fmBgoLGxsVgsnjt3rre395kzZ4qLi5m9q1evHjNmzDvvvKNizAEaC3EAAPSFAwcOlJaW9tnp7ty5ExYWtnXr1lYLJLi6ugYFBT18+HDdunV91plOFRcXm5mZURTFbFpaWhJC7t+/r+66x48fVx4fc3NzQoji5v/Jkye1tbUVewcOHEgIqaurU5SEh4fn5uZilcD+DnEAAHddunTJysqKoqjPPvuMEJKYmCgSifT09LKysmbMmCGRSCwsLI4ePcocHB8fLxAIBg0a9OGHH5qZmQkEAldXV8XfnVKpVFdXd/DgwczmypUrRSIRRVFlZWWEkKCgoLVr1xYWFlIU5eDgQAg5c+aMRCLZvn27mi4tPj6epmkvL6+Xd0VGRg4bNmz//v3nzp1rsy5N0zExMSNGjODz+UZGRrNnz/7999+ZXR0PESFELpdv2bLFyspKKBSOHj1axWWe7ezslIMk5gG/nZ2duuu2UlBQYGhoaG1t3ebehw8fCoVCW1tbRYmRkZGbm1tcXNyr/XTp1UeD5vH19fX19WW7F/0DxkqB+cnpai3mNu/evXuZzdDQUELI+fPnq6qqSktLp0yZIhKJGhsbmb2BgYEikejWrVsNDQ35+fnMu2kPHjxg9i5YsMDU1FTR8u7duwkhz549YzZ9fHzs7e0Ve0+ePCkWiyMiIrpxpYSQ1NTUjo+xs7NzcnJqVWhvb3/v3j2api9fvqylpWVjY1NTU0PTdHZ29qxZsxSHbdmyRVdX9+DBg5WVlTdu3Bg/fvzAgQOfPHnC7O14iNatW8fn8zMyMioqKjZt2qSlpfXLL790ekU5OTk8Hi8+Pl4mk928eXPEiBHTp09XcTR6UpfR2NhYUlKyd+9ePp9/8ODBNo+pra0Vi8VSqbRVeUhICCHk+vXrnZ6le99P6AO4HwAArbm6ukokEhMTk4CAgNra2gcPHih26ejoMH8oOzk5JSYmVldXJycnd+MUnp6eMpksLCys93r9P7W1tffu3bO3t2/vABcXlzVr1hQVFW3cuLHVrvr6+piYmDlz5ixcuNDAwGDUqFFffPFFWVnZvn37lA9rc4gaGhoSExO9vb19fHwMDQ03b97M4/FUGR83N7cNGzZIpVKJROLs7FxdXb1//34VL7YndRmWlpYWFhbh4eG7du3y9/dv85ioqCgzM7PIyMhW5UOHDiWE5OXldemMoFEQBwBAu3R1dQkhTU1Nbe6dMGGCnp6e4p655igtLaVpWk9Pr4NjIiMjhw8fnpCQcOnSJeXy/Pz8mpqaCRMmKEomTpyoq6vb3pt3ykN0+/bturo6Z2dnZpdQKBw8eLAq4xMaGrpv377z58/X1NTcvXvX1dXVxcVF8Uae+uoyiouLS0tLjxw58tVXX40bN+7l1ziOHz+elpb27bffKr9xyWAG+enTp6qfDjQN4gAA6D4+n//s2TO2e9FaQ0MDIYTP53dwjEAgSE5Opihq6dKl9fX1inJmIpy+vr7ywYaGhtXV1Z2et7a2lhCyefNm6k/3799XfrGuTY8fP46Ojv7ggw+mTp0qEolsbW2TkpIePXrEPFhRX10FHo9nYmLi4eGRkpKSn58fFRWlvDclJWXnzp05OTk2NjYv1xUKheTPAYd+CnEAAHRTU1NTZWWlhYUF2x1pjflx6nSVGxcXl+Dg4IKCgm3btikKDQ0NCSGtfvVVvEwTExNCSGxsrPLD1ytXrnRcq6CgQC6XDxkyRFEikUiMjY3z8/M7PWNP6r7MwcFBW1tbue7evXsPHTp04cIF5VMoa2xsJH8OOPRTiAMAoJtycnJomp40aRKzqaOj094ThD42aNAgiqJUWSFg27Ztjo6O169fV5Q4Ozvr6+v/+uuvipKffvqpsbHxtdde67Q1S0tLgUCQm5vbpd4yEYZi1j4hpLq6+vnz58wMQPXVLS8vnz9/vnIJE1UwdWma3rBhQ15eXmZmZqu7I8qYQTY1Ne30dKCxEAcAQBe0tLRUVFQ0NzffuHEjKCjIyspq8eLFzC4HB4fnz59nZmY2NTU9e/as1RR2Y2PjR48eFRUVVVdXNzU1ZWdnq2/eoJ6enp2dXUlJSadHMk8HlGfJCwSCtWvXHj9+/NChQzKZLC8vb8WKFWZmZoGBgaq0tmTJkqNHjyYmJspkMrlcXlJSwvxIBwQEmJqatrlusa2trbu7e1JS0sWLF+vr64uLi5lzLVu2jDlATXVFItHZs2cvXLggk8mampquX7/+3nvviUSi4OBgQsitW7d27dqVlJTE4/EoJXv27FFuhBnkUaNGdTo4oLEQBwBw12effTZx4kRCyIYNG2bNmpWYmBgbG0sIGT169N27d5OSktauXUsIefvttwsKCpgqDQ0No0aNEgqFU6ZMGTZs2Hfffad4DP/RRx+5u7vPmzdv+PDh27ZtY+4VK95ZW7FixaBBg5ycnN55553nz5+r+9I8PT3z8/MVD/6//vprBweHwsLCiRMnfvzxx8pHTpo0ifnlU/j000+joqIiIiIGDhzo5uZmY2OTk5MjEokIIZ0OUVxc3Jo1a6KjowcMGGBmZhYUFFRRUUEIaWxsLC0tzcrKermrFEWlp6cHBAQsW7bMyMjIycnpwYMHx44dmzJlCnOAmuoKBILJkycvX77c3NxcLBb7+fnZ2NhcvXqVec+RVm1JgF9++cXc3Hz06NGqHAwaio3JitAJzIlXHcZKoQ/mZzOrzKr1FKogKqwfUFBQoKOj095s+L4nl8unTJly4MCBflS3U2VlZQKBYM+ePaocjPUDNBbuBwBAF/SXFHMODg4RERERERGKVXJZJJfLMzMzq6urAwIC+ktdVYSHh48dO1YqlaqjcegziAOgCzrIQ9rK8uXLxWIxRVEqvjOless9cfv27Y8//njkyJFisVhHR8fAwGDYsGGenp6dvtHdcx1coHJKXIauru6gQYPefPPN3bt3M3eVoRtCQkL8/PwCAgJYTymUk5Nz7Nix7Ozsjpc00Ki6nYqJicnNzT19+jSPx+v1xqFPsX1DAtqgsfe63dzcEhISysvLZTJZamoqj8d7++232zuYWXRdlQVHu9qyMtXHav/+/Twe769//euZM2cqKioaGhoKCwtTUlJcXV2//PJLVVroiU4v0N7e3sDAgKZp5kW87777bvHixRRFmZmZqbIwLa3++64hISHMmjk2Njbp6enqO1GniArPBRS+/fbbDRs2qLU/HJSZmRkVFdXc3Kx6FTwX0Fj4VDSRxsYBnp6eyv/nz507lxCiWF6+lS7FAV1qWZmKY3XlyhVtbe2pU6c2NTW12nXmzBnF6vrq0+kFKuIAZenp6VpaWoMGDaqsrOz0FNz5d7ZLcQBoCO58P/sdPBeALug0D6kyRSLUXm+5GyIjI+Vy+Y4dO3R0dFrtmj59+qpVq3rrRO3p3gX6+vouXry4tLT0iy++UG//AICrEAf0bwcPHpwwYYJAIBCJRDY2NsyyaHR3s6aOGDGCoigtLa3XXnuN+Yn65JNPDAwMBALBP//5z5fP3ioPKU3Tu3fvHj58OJ/PNzAwWL9+fbev6+UMpz3R2Nh4/vz5AQMG/OUvf+n4SLaGrgPM7Pzs7OwuXDAAgOpYvh8BbVHxXjczj3nHjh3l5eXPnz//8ssvFyxYQPcga2pzc7ONjY2VlZXyHew1a9a0WieV8XIe0tDQUIqi/vGPf1RUVNTV1SUkJBCVnwt03HIHVBmrP/74gxAyadKkTltja+jodp4L0DQtk8kIIZaWlp12njv3XQmeC/RD3Pl+9jv4VDSRKr9tjY2NhoaG7u7uipLm5ua4uLi6ujp9ff2AgABF+c8//0wIUSR6Z37M6uvrmU3m1/rOnTvMJhNbpKWlMZu1tbVWVlZVVVUvdyA0NHTYsGEymYzZrKur09PTe+uttxQHdOn9gA5a7pgqY8WsEfu3v/2t48PYGjpGe3EATdMURRkaGnbceZpL/84iDuiPuPP97HdaPyuF/uLGjRuVlZXTp09XlGhra69evfrXX3/tdtZUQsjy5cvDw8Pj4uL8/PwIIYcOHZo9e7ZEImlVi8lDevbsWUUe0jt37tTV1U2bNq2H1/Vyyz3HrI7e6cP4niScJT0Yuo7V1tbSNP1yO+1JS0tT8ch+rQ+mekLvwkemsRAH9FfM7WImN5qynmRNZSp+8MEHu3fv/vnnn//yl798/vnnGRkZrY5JSUmJiYnJyclRTkHGLDPO5FvrtjZb7jkbGxuBQMA8HegAW0PXMabbjo6OKh7v7++v4pH9WlxcXFxcHNu9AHgV4D3B/or5ISkrK2tV3pOsqQypVMrj8WJjYy9evGhpaWlvb6+8t708pAKBgBDy4sWLLl5H5y33HJ/Pnz6bKYanAAAgAElEQVR9ellZ2Y8//vjy3ufPny9fvpywN3QdO3PmDCFkxowZKh7P9i3GvkDwXKAfYp4LgAZCHNBf2djYGBsbnz17tlV5T7KmMiwsLObOnZuRkREWFhYUFKQopzvMQ+rs7KylpfX9999341o6brlXhIeH8/n84OBgReIZhZs3bzKTCdkaug48efIkNjbWwsJi6dKlqtcCAFAd4oD+is/nb9q06eLFi1Kp9OHDhy0tLdXV1bdu3epJ1lSFtWvXNjc3V1RUTJ06VVHYcR5SExMTHx+fjIyMAwcOyGSyGzdu7Nu3T8XTqZjhtCfGjh17+PDhmzdvTpky5fTp01VVVU1NTffu3UtKSlq2bBmzMCpbQ6dA03RNTU1LSwtN08+ePUtNTZ08ebK2tnZmZqbq7wcAAHQNqzeKoG2qryf42WefjRo1SiAQCASCcePGJSQk0DTd0tKye/fuoUOH8ng8IyMjb2/v27dvM8cnJCQwK40PHTq0sLBw3759zA+MtbX1H3/8odyyu7v7/v37lUvy8vLa/Art3r2bOaC6unr58uUDBgzQ19d/4403tmzZQgixsLD47bffOr6KTlvulbGiafrBgwfr1q0bNWqUvr6+tra2oaHhuHHjli1b9uOPPzIHsDJ0J06cGD16tJ6enq6urpaWFiGEmSDwl7/8JSIiory8XMWr48772ATPBfoh7nw/+x2KVi3JNPQl5oXz9PR0tjvSD2CsFNLS0vz9/bnwfzRFUampqczazNBfcOf72e/guQAAAAB3IQ4Atfv999+p9qkpMzoAAKgCcQConaOjYwePplJSUtjuILzKzp07FxIScuzYMTs7Oyb0XLRokfIBHh4eYrFYW1t75MiR165dY6ufCg0NDY6Ojps3b+6buk1NTVFRUQ4ODrq6uoaGhs7OzkVFRZ22fOLEiejoaLlc3o1OgqZBHAAAr6xPP/00Pj5+06ZNPj4+d+/etbe3HzBgwKFDh06dOqU45uzZs+np6TNnzszPzx8/fjyLvWWEhobevn27z+r6+/v/61//Onz4cF1d3X//+197e/uamppOW/by8hIIBNOmTWNW34J+DXEAAKiqvr7e1dVV05pqz86dO1NSUtLS0pSXcI6Pj9fS0goMDKyqqlLr2bvn8uXLN2/e7LO6KSkpmZmZ6enpr7/+uo6OjpmZWVZWlrOzsyotr169esyYMe+8805zc3P3OgwaAnEAAKjqwIEDpaWlmtZUm+7cuRMWFrZ161ZmpUsFV1fXoKCghw8frlu3Tn1n7576+vr169d3b73k7tX9/PPPx48fP2rUqO61HB4enpubiwWe+zvEAQDcQtN0TEzMiBEj+Hy+kZHR7Nmzf//9d2aXVCrV1dUdPHgws7ly5UqRSERRFLN8dVBQ0Nq1awsLCymKcnBwiI+PFwgEgwYN+vDDD83MzAQCgaurqyInU5eaIoScOXNGIpFs3769ty4zPj6epmkvL6+Xd0VGRg4bNmz//v3nzp3r6hAlJiaKRCI9Pb2srKwZM2ZIJBILCwsmtSZDLpdv2bLFyspKKBSOHj26S4vphoaGrly5sntJOrpRt7Gx8erVq2PHju12y0ZGRm5ubnFxcZgN2K8hDgDglvDw8JCQkNDQ0NLS0osXLxYXF0+ZMuXp06eEkPj4eOVJ+QkJCVu3blVsxsXFzZw5097enqbpO3fuSKXSxYsX19XVrV69uqio6Nq1a83NzW+99VZxcXFXmyKEMG+ctbS09NZlnjp1avjw4czST60IhcJ//vOfWlpa77//fm1t7csHdDBEH3300Zo1a+rr68VicWpqamFhoZ2d3fvvv69IO7lx48Zdu3bFxsY+fvx45syZ8+fPV16pugM//vhjYWHh/Pnzu3Gx3av76NGjxsbG//znP+7u7kwkN2LECGYtMtVbHjdu3MOHD3/77bdudBs0BOIAAA6pr6+PiYmZM2fOwoULDQwMRo0a9cUXX5SVlam+CHQrOjo6zN/NTk5OiYmJ1dXVycnJ3WjH09NTJpOFhYV1rxut1NbW3rt3r1WeJ2UuLi5r1qwpKirauHFjq10qDpGrq6tEIjExMQkICKitrX3w4AEhpKGhITEx0dvb28fHx9DQcPPmzTweT5UBqa+vDwoKSkxM7MbFdrsu8z6giYnJ9u3b8/Pznz59Onv27FWrVh05ckT1locOHUoIaW/FTOgXEAcAcEh+fn5NTc2ECRMUJRMnTtTV1VXcz++JCRMm6OnpKW6hs6i0tJSm6TZvBihERkYOHz48ISHh0qVLyuVdHSJdXV1CCHM/4Pbt23V1dYr37IRC4eDBg1UZkE2bNn3wwQfm5uadHtmLdfl8PiFk5MiRrq6uxsbGBgYGW7duNTAwUEQ8qrTMDDJzswT6KcQBABzCzPJqlfPQ0NCwVbblbuPz+c+ePeuVpnqioaGB/Pk71x6BQJCcnExR1NKlS5WzUPZkiJinDJs3b1Ysk3X//v26urqOa126dCkvL49Jft1VPalrZmZG/m/ucl1dXWtr68LCQtVbFgqF5M8Bh34KcQAAhxgaGhJCWv2kVVZWWlhY9Lzxpqam3mqqh5gfp05XuXFxcQkODi4oKNi2bZuisCdDxLxMFxsbq7xS1pUrVzqudeDAgfPnz2tpaTGhA9PI9u3bKYrq9N2CntTV19cfOnTorVu3lAubm5sNDAxUb7mxsZH8OeDQTyEOAOAQZ2dnfX195X/Hf/rpp8bGxtdee43Z1NHRUbzy1lU5OTk0TU+aNKnnTfXQoEGDKIpSZYWAbdu2OTo6Xr9+XVHS6RB1wNLSUiAQ5Obmdqm3ycnJynEDc0MlNDSUpmnlxxO9XpcQ4u/vf/369bt37zKbdXV19+/fZ6YRqtgyM8impqZdumTQKIgDADhEIBCsXbv2+PHjhw4dkslkeXl5K1asMDMzCwwMZA5wcHB4/vx5ZmZmU1PTs2fP7t+/r1zd2Nj40aNHRUVF1dXVzG98S0tLRUVFc3PzjRs3goKCrKysFi9e3I2msrOze3HeoJ6enp2dXUlJiSoDkpycrK2trVzS8RB13NqSJUuOHj2amJgok8nkcnlJScnjx48JIQEBAaampt1bt1h9dYODg62trRcvXvzgwYPy8vINGzbU19e//O5kB5hB7ngFAtBwiAMAuOXTTz+NioqKiIgYOHCgm5ubjY1NTk6OSCRi9n700Ufu7u7z5s0bPnz4tm3bmPu9Li4uzGzAFStWDBo0yMnJ6Z133nn+/DkhpKGhYdSoUUKhcMqUKcOGDfvuu+8UT+W72lTv8vT0zM/PVzz4//rrrx0cHAoLCydOnPjxxx8rHzlp0qTg4GAVhygxMTE2NpYQMnr06Lt37yYlJa1du5YQ8vbbbxcUFBBC4uLi1qxZEx0dPWDAADMzs6CgoIqKCkJIY2NjaWlpVlZWN65FfXWNjIx++OEHCwuLsWPHmpub//zzz6dOnep0RQFlv/zyi7m5+ejRo7vRN9AUHSSAAbb4+vr6+vqy3Yv+AWOlwCxZ05dnDAwMNDY27sszMgghqampHR9TUFCgo6Nz8ODBvulSp+Ry+ZQpUw4cONCP6naqrKxMIBDs2bNHlYP7/vsJKsL9AADoPo3NOOfg4BAREREREdFm1pw+JpfLMzMzq6uru5Flm626qggPDx87dqxUKlVH49BnEAcAwKspJCTEz88vICCA9ZRCOTk5x44dy87O7nhJA42q26mYmJjc3NzTp0/zeLxebxz6EuIAAOiOTZs2JScnV1VV2draZmRksN2dtm3fvl0qle7YsYPdbkybNu3w4cOKbAv9om7HsrKyXrx4kZOTY2Rk1OuNQx/TYbsDANAvRUVFRUVFsd2Lznl4eHh4eLDdi1fNrFmzZs2axXYvoHfgfgAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLvwnqCGunr1qp+fH9u96AeuXr1KCMFYkT9XeOXIUMTGxqanp7PdC+gCVZZ5BlZQNE2z3QdoLSYmptMcZQC9Ijs7e9y4ceqYWgbwMkRvGghxAACnURSVmpo6d+5ctjsCAOzA+wEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C7EAQAAANyFOAAAAIC7EAcAAABwF+IAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAAA3IU4AAAAgLsQBwAAAHAX4gAAAADuQhwAAADAXYgDAAAAuAtxAAAAAHchDgAAAOAuxAEAAADchTgAAACAuxAHAAAAcBfiAAAAAO5CHAAAAMBdiAMAAAC4C3EAAAAAdyEOAAAA4C4dtjsAAH2qsrKSpmnlktra2oqKCsWmvr4+j8fr834BADuoVv8iAMCrberUqd999117e7W1tR8+fGhqatqXXQIAFuG5AAC3zJs3j6KoNndpaWn99a9/RRAAwCmIAwC4xdfXV0en7QeCFEW9++67fdwfAGAX4gAAbjEyMvLw8NDW1n55l5aWlre3d993CQBYhDgAgHMWLlzY0tLSqlBHR8fT09PAwICVLgEAWxAHAHCOl5cXn89vVSiXyxcuXMhKfwCARYgDADhHT0/P29u71eRAoVD4zjvvsNUlAGAL4gAALpo/f35TU5Nik8fj+fr6CoVCFrsEAKxAHADARdOnT1d+FaCpqWn+/Pks9gcA2II4AICLeDxeQECArq4us2loaDht2jR2uwQArEAcAMBR8+bNa2xsJITweLyFCxe2t6gAALzasK4wAEe1tLQMGTLk6dOnhJBLly5NnjyZ7R4BAAtwPwCAo7S0tBYtWkQIMTMzc3V1Zbs7AMAO9u8EXrlypbi4mO1eAHDRwIEDCSGvv/56eno6230B4Ki5c+ey3AOabb6+viwPAQAAAEvY/hGm2b8fQAjx9fXFnyPQiyiKSk1NZT/K7g8yMjJe4Vg8LS3N39+f5sBbUPjO90fM95PtXuD9AABue4WDAABQBeIAAAAA7kIcAAAAwF2IAwAAALgLcQAAAAB3IQ4AAADgLsQBAAD/x+nTpw0MDL755hu2O6Iu586dCwkJOXbsmJ2dHUVRFEUxK0sqeHh4iMVibW3tkSNHXrt2ja1+KjQ0NDg6Om7evLlv6jY1NUVFRTk4OOjq6hoaGjo7OxcVFXXa8okTJ6Kjo+VyeTc6yS7EAQAA/8ervd7Ap59+Gh8fv2nTJh8fn7t379rb2w8YMODQoUOnTp1SHHP27Nn09PSZM2fm5+ePHz+exd4yQkNDb9++3Wd1/f39//Wvfx0+fLiuru6///2vvb19TU1Npy17eXkJBIJp06ZVVlZ2r6tsQRwAAPB/eHp6VlVVzZw5U90nqq+v7+PMDjt37kxJSUlLSxOLxYrC+Ph4LS2twMDAqqqqvuyMii5fvnzz5s0+q5uSkpKZmZmenv7666/r6OiYmZllZWU5Ozur0vLq1avHjBnzzjvvNDc3d6/DrEAcAADAjgMHDpSWlvbZ6e7cuRMWFrZ161aBQKBc7urqGhQU9PDhw3Xr1vVZZ1RUX1+/fv36uLi4Pqv7+eefjx8/ftSoUd1rOTw8PDc3t3sdZgviAACA/7l06ZKVlRVFUZ999hkhJDExUSQS6enpZWVlzZgxQyKRWFhYHD16lDk4Pj5eIBAMGjToww8/NDMzEwgErq6uP/30E7NXKpXq6uoOHjyY2Vy5cqVIJKIoqqysjBASFBS0du3awsJCiqIcHBwIIWfOnJFIJNu3b1fTpcXHx9M07eXl9fKuyMjIYcOG7d+//9y5c23WpWk6JiZmxIgRfD7fyMho9uzZv//+O7Or4yEihMjl8i1btlhZWQmFwtGjR6empqre59DQ0JUrV5qYmHTlQrtft7Gx8erVq2PHju12y0ZGRm5ubnFxcf3o6RLiAACA/3njjTcuX76s2Pzoo4/WrFlTX18vFotTU1MLCwvt7Ozef//9pqYmQohUKl28eHFdXd3q1auLioquXbvW3Nz81ltvMTlU4+PjlRf8T0hI2Lp1q2IzLi5u5syZ9vb2NE3fuXOHEMK8YtbS0qKmSzt16tTw4cP19PRe3iUUCv/5z39qaWm9//77tbW1Lx8QHh4eEhISGhpaWlp68eLF4uLiKVOmPH36lHQ2RISQjRs37tq1KzY29vHjxzNnzpw/f/6vv/6qSod//PHHwsLC+fPnd+Niu1f30aNHjY2N//nPf9zd3ZnAbsSIEQkJCco/6p22PG7cuIcPH/7222/d6DYrEAcAAHTO1dVVIpGYmJgEBATU1tY+ePBAsUtHR4f5Q9nJySkxMbG6ujo5Obkbp/D09JTJZGFhYb3X6/+pra29d++evb19ewe4uLisWbOmqKho48aNrXbV19fHxMTMmTNn4cKFBgYGo0aN+uKLL8rKyvbt26d8WJtD1NDQkJiY6O3t7ePjY2houHnzZh6Pp8r41NfXBwUFJSYmduNiu12XeR/QxMRk+/bt+fn5T58+nT179qpVq44cOaJ6y0OHDiWE5OXldaPnrEAcAADQBbq6uoQQxR+7rUyYMEFPT09xz1xzlJaW0jTd5s0AhcjIyOHDhyckJFy6dEm5PD8/v6amZsKECYqSiRP/P3t3HhfFle4N/DQ00M3WgCwSEJRFEAHRyESY8DqME2L0oqIgaEwGMxpcETCJsqgsgusFLgbixDAkcWNRA5kgxquRG43rRImICQMooGgERBbpRmio94/62LcvIt00dBdt/b5/pavqnHrqWOl+qOU8ntra2pI7IP1ID1FlZaVQKJQ8Z8fn88eOHSvP+MTExHz44YdWVlYytxzBtjo6OoSQyZMne3t7m5iYCASChIQEgUAgyXjk6ZkeZPpiiVpAHgAAMJJ0dHSampqYjqK/rq4u8vx37mV4PF5OTg6Hw/nggw9EIpFkOf0inL6+vvTGRkZGHR0dMvdL32WIi4vjPFdXVycUCgdvdeHChfLy8hUrVsjsf2TbWlpaEkLoBzho2tratra2NTU18vfM5/PJ8wFXC8gDAABGTE9PT2trq7W1NdOB9Ef/OMmc5cbLyysqKqqqqiopKUmy0MjIiBDS71dfzsOkH6ZLS0ujpFy6dGnwVtnZ2WfPntXQ0KBTB7qT5ORkDocj89mC4bTV19d3dHS8ffu29EKxWCwQCOTvubu7mzwfcLWAPAAAYMSUlpZSFDVjxgz6I5fLfdkdBBUzNzfncDjyzBCQlJTk7Ox848YNyRJXV1d9fX3pn7orV650d3e//vrrMnsbN24cj8crKysbUrQ5OTnSeQN9fSU2NpaiKOnbEyPelhASHBx848aNO3fu0B+FQmFdXR39GqGcPdODbGFhMaRDZhDyAACAYenr63vy5IlYLL5582ZERISNjU1oaCi9ysHBoaWlpbCwsKenp6mpqa6uTrqhiYnJgwcPamtrOzo6enp6SkpKlPfeoK6urp2d3f3792VuSd8d0NTUlF6ycePGEydOHDp0qL29vby8fPXq1ZaWlmFhYfL0tnz58qNHj2ZlZbW3t/f29t6/f//hw4eEkJCQEAsLC8XmLVZe26ioKFtb29DQ0Pr6+sePH2/atEkkEr347OQg6EEefAaCUQV5AADA//r00089PT0JIZs2bZo/f35WVlZaWhohxN3d/c6dOwcOHNi4cSMhZPbs2VVVVXSTrq4uNzc3Pp/v4+MzceLEc+fOSW7Dr1mzxtfXd8mSJU5OTklJSfS1Yi8vL/rFwtWrV5ubm7u4uMyZM6elpUXZhzZ37tyKigrJjf9vvvnGwcGhpqbG09Nz/fr10lvOmDEjKipKesm2bdtSUlISExNNTU1nzpw5fvz40tJSPT09QojMIUpPT4+MjNy1a9eYMWMsLS0jIiKePHlCCOnu7m5sbCwqKlLgWJTX1tjY+Pz589bW1h4eHlZWVlevXi0uLpY5o4C0a9euWVlZubu7KxAbMyimBQYGBgYGMh0FvFIIIXl5eUxHAcyjp6xR6i7CwsJMTEyUugt5yHPOV1VVcbncgwcPqiYkmXp7e318fLKzs9WorUzNzc08Hm/v3r3ybKyC81MeuB4AADAs6lJizsHBITExMTExccCqOSrW29tbWFjY0dEREhKiLm3lER8f7+HhER4erozOlUQ98gBPT09NTc0hXZmR3/Lly3k8HofDUaPXPAaxd+9e+oGg/fv300tGtoiqykqyJiYmuri4GBoa6ujoODg4fPLJJyP45SVdcZXG5XJNTU3/8pe/nDhxYqT2MvipNcqrvr4yJxJIi46ODgoKCgkJYbykUGlp6fHjx0tKSgaf0mBUtZUpNTW1rKzs5MmTWlpaI9658qhHHnDt2jVfX18ldZ6TkzMKq2so7KOPPpKeFZWMdBHVke1tED/88MO6detqa2ubm5tTUlLS09ODgoJGqnNJxVWBQEBfGWtqasrLy2toaFi0aNGQ5j8fxOCn1iiv+vrKnEhKFRMTk5OT09bWNmHChGPHjjEdjlySk5PDw8N37NjBbBizZs06fPiwpPiCWrQdXFFR0bNnz0pLS42NjUe8c6VSjzyAxuFwhtpE9WU9R6FhFlHtN4YqK8mqr69P33k1MDBYvHhxQEDAqVOn6KerlMHY2HjWrFn/9V//RQjJz8+Xuf0InlqjvOqrhJqeSEqVkpLy7NkziqLu3r0bGBjIdDjy8vPz27lzJ9NRvGrmz58fHR0t/Z6FulCnPECBKy1DKuupQJ7BBioujSrx3XffSf8fZWpqSgiROQ3ZMI0fP548nz1tcCN4ao3mqq8jiKkTCQAGp055QHV1tbOzs56eHv1+jvQM2OfPn3dxcREIBDwez83N7fvvvycDlfUkhBw8eHD69Ok8Hk9PT2/8+PGSObM0NDSKi4vfeecdgUBgaWn5j3/8Q56QZBbcpF5erHP37t26uroGBgaNjY0bN260srJavXq1np6ehobG66+/bmFhoaWlpaenN23aNB8fH3ouDiMjo08++WTwo+6nXxHV6upqzgv++7//W84x7Nfb4Acoc3CGpKGhgc/nT5gwQbHmcrp58yYhZObMmZIlqjm1hlP1FScSAAwLI28pSJPzvcFZs2bZ2dndvXu3p6fn1q1bb7zxBo/H+/e//02vLSgoiI+Pb2lpefz48YwZM8aMGUMvX7RoEV3Wk0a/5Lpjx47Hjx+3tLT8/e9/f/fddymKio2NJYScPXu2tbW1paVlzpw5Ojo6nZ2d8sQvadvW1tbY2Ojj46Onp9fd3U2v3bp1q7a29sGDB1tbW2/evDlt2jRTU9Pff/9duu2GDRv27du3cOHCX3/9ddu2bYSQK1eudHZ2Njc3z549mxBSXFzc1NTU2dlJP4NaVlY2+FHT7+x+9tln9Ef6Wvq+ffvoVZs3b6YP7eHDh8bGxt7e3r29vfKPoXRvch7gywZHfp2dnQYGBuHh4XJuT+R7b1D6+QChUFhSUmJra+vn5/f06VPJNso+tezt7e/evUtR1MWLFzU0NMaPH0/vvaSkZP78+ZLNcCIpdiKNkveyVEDOcx5GlVFyfjIfgfx5wJQpUyQf6b/bPvrooxe3TElJIc+La0l/9XR3dxsZGfn6+kq2FIvF6enp1PNvGZFIRC//+uuvCSG3bt2SJ/5+bTMzMwkh1dXVFEUJhUJ9ff2QkBDJxlevXiWEJCYmDtiWoij667ujo4P++NVXXxFCysvLpZvn5uYOftSDfH1LCwgI4PF4v/322+C9DfL1PdQDlB6cIYmNjZ04cWJ7e7uc28ufB/RLi93c3L766iv6ju+LlHFqSfIAiqLo2VfWrVtH/d88ACeSwifSKPmeVQHkAepolJyfXEWuIYwCbm5uAoGAzgb6oR8jePGN3ps3b7a2tr799tuSJZqamhs2bHhZD4rNCi5dcHOoxTpf1ptYLJYZ2MuO+mXy8/O/+eabXbt2OTk5KdzbcKqRyu/EiRP5+fmnT582MDAYUkN5CAQC+mkAsVj86NGj06dPh4eHp6SkXLhwgX4iQZqyT63t27d/9913mZmZwcHB0stxIvUz1BNpBN80Gc3S0tIKCgqYjgKGQJ5pnlVAnZ4P6EdLS0vyRVBcXPynP/3JzMxMR0dH+santPb2dvK8cJZqDKdYpzzkOeoBPX78eP369Z6envQfoAr3puwDJITk5ubu3LmztLSUfoJPebhcrpWV1fLly/fu3VtZWSl5q0qVp5Yyqr7Kgw0nEgC8jLpeDxCLxS0tLTY2NoSQ+vr6gICAhQsX/uMf/3jttdf27ds34LfPa6+9Rv5vYWllG06xTpnkPOoBbdiwobW19YcffpA8kK9Yb0o9QELIvn37vv/++x9++KHfL4RS0dVB6MKjqj+16Kqve/fuTUpKok9vghNp2NjwVzKHw4mMjFy8eDHTgcAQ5Ofn97v4xwh1vR5w7ty5vr4+eoqV8vLynp6eNWvW2NnZ0dO3Ddhk/PjxJiYmp0+fVlmQwynWKZOcR/2i4uLiw4cPb9myZfLkyfSSjz/+WLHelHeAFEVt2rSpvLy8sLBQlUkAIeTnn38mhNBXuRk5tUa26qtMr/aJBAAyqVMe0N3d3dbWJhaLr1+/Hh4eTpeGJITQfzadOXOmq6urqqpK+p6idFlPDQ2NmJiYH3/8MTw8vKGhoa+vr6Ojg/6zT0mGU6xTpkGOehDt7e2rVq3y8PCgy2h2dXX961//Kisrk3MM+92RVd4B3r59e/fu3QcOHNDS0pJ+M23v3r3D7PlFIpGor6+PoqgHDx7k5OTExcWZmppGRkYShk6tka36KtOrfSIBgGxMP6go7/sCOTk5vr6+5ubmXC53zJgxS5Ysqaurk6zdtGmTiYmJkZFRUFAQ/Uayvb19fX399evXbW1t+Xz+m2++Sb+D9Omnn7q5ufF4PB6PN3Xq1MzMzF27dtHFQB0dHWtqag4dOkTPCmltbS3zlYHMzEx6kmq67eeff25oaEgIsbW1pd9p7Ovr27Nnj6Ojo5aWlrv4CX4AACAASURBVLGxcUBAQGVlJd1Wst9x48bRFcDS09Pp3saPH3/+/PmdO3cKBAJCiIWFxeHDh3Nzcy0sLAghxsbGR48efdlRR0RE0Jvp6ektXLhw37599Ayaurq68+bNG/B3dM6cOXKOYVxcnHRvgx+gzMEZRHl5+YCn6549e2SeKpQcz06fOHHixZcFdHR0HB0d16xZU19fL9lSeaeWJAZTU1P6HQFpH3/8sfR7gziRFDuRRsnz2Cog85yHUWiUnJ8ciulZvulHedlwAw9UhsPh5OXl4V4p0PdfGf+WUwGc8+polJyf6nRfAAAAAEYW8oDB/Pbbby9OniqhpPLVbICBBWDQmTNnoqOjR3nla2ldXV3Ozs5xcXGqadvT05OSkuLg4KCtrW1kZOTq6lpbWyuz52+//XbXrl3yz70xeqjre4Oq4ezszPgVm1cSBhaAKdu2bbtx48bhw4cNDAwWLVrk4ODQ2tp66NChkJCQuXPn0tucPn361KlT+/fvLywsZDZaWmxsbGVlpcraBgcH3759+/Dhw6+//npTU9OqVauePn0qs+d58+bdvXt31qxZhYWFqpyoZvhwPQAAQHEjWIFaBXXSd+7cmZubm5+fLz075yivfH3x4sVbt26prG1ubm5hYWFBQcEbb7zB5XItLS2LiopcXV3l6XnDhg1TpkyZM2eOZO5OtYA8AABAcSNYT1nZpZmrq6u3bNmSkJDA4/Gkl4/mytcikejjjz9OT09XWdvPPvts2rRp9HxiCvQcHx9fVlamWMBMQR4AAGxHvbzqcXh4uLa2Nv2WIyFk7dq1enp6HA6Hnj6yXz3ljIwMHo9nbm6+atUqS0tLHo/n7e0tmURhSF0RQk6dOmVoaJicnDxSh5mRkUFR1Lx5815cNZzK1zILQ/f29m7dutXGxobP57u7u9Mvy8kpNjZ27dq1ZmZmQzlQxdt2d3dfvnzZw8ND4Z6NjY1nzpxJlxkbWrjMQR4AAGwXHx8fHR0dGxvb2Nj4448/3rt3z8fH59GjR4SQjIwM6ZfxMjMzExISJB/T09P9/f3pOorV1dXh4eGhoaFCoXDDhg21tbXXr18Xi8VvvfUWXVxxSF2R5/WZ+vr6Ruowi4uLnZyc6MkY+uHz+V9++aWGhsbKlSs7Oztf3GCQIVqzZk1kZKRIJDIwMMjLy6upqbGzs1u5cqVktqjNmzfv3r07LS3t4cOH/v7+S5culZ47chA//fRTTU3N0qVLFThYxdo+ePCgu7v7559/9vX1pTO5SZMmZWZmSv+oy+x56tSpDQ0Nv/zyiwJhMwJ5AACwmkgkSk1NXbhw4bJlywQCgZub2/79+5ubmz///HPFOuRyufTfzS4uLllZWR0dHTk5OQr0M3fu3Pb29i1btigWRj+dnZ137959cfosCS8vr8jIyNraWnqOSGlyDpG3t7ehoaGZmVlISEhnZ2d9fT0hpKurKysrKyAgYNGiRUZGRnFxcVpaWvIMiEgkioiIyMrKUuBgFW5LPw9oZmaWnJxcUVHx6NGjBQsWrFu37siRI/L37OjoSAh52WRooxDyAABgteGXdR7E9OnTdXV1JZfQGdTY2EhR1IAXAyS2b9/u5OSUmZl54cIF6eXDKQxdWVkpFAolz9nx+fyxY8fKMyAxMTEffvihlZWVzC1HsK2Ojg4hZPLkyd7e3iYmJgKBICEhQSAQSDIeeXqmB5m+WKIWkAcAAKspu+qxjo5OU1PTiHQ1HF1dXeT579zLKKPyNX2XIS4uTjJBSF1dnVAoHLzVhQsXysvLV6xYIbP/kW1raWlJ/m/tUG1tbVtb25qaGvl7puf5pgdcLSAPAABWU2rV456enhEsoDwc9I+TzFlu6MrXVVVVSUlJkoXDGSL6Ybq0tDTpCe0vXbo0eKvs7OyzZ89qaGjQqQPdSXJyMofDkflswXDa6uvrOzo69isSJhaL6Qodcvbc3d1Nng+4WkAeAACsJrPqMZfL7VcgUX6lpaUURc2YMWP4XQ2Tubk5h8ORZ4aAka18PW7cOB6PV1ZWNqRoc3JypPMG+oJKbGwsRVHStydGvC0hJDg4+MaNG3fu3KE/CoXCuro6+jVCOXumB5ku06UWkAcAAKvJrHrs4ODQ0tJSWFjY09PT1NRUV1cn3fzFesp9fX1PnjwRi8U3b96MiIiwsbGhK6QPtauSkpIRfG9QV1fXzs7u/v378gzICFa+5vF4y5cvP3r0aFZWVnt7e29v7/379x8+fEgICQkJsbCwUGzeYuW1jYqKoova19fXP378eNOmTSKR6MVnJwdBD/LgMxCMKsgDAIDttm3blpKSkpiYaGpqOnPmzPHjx5eWlurp6dFr16xZ4+vru2TJEicnp6SkJPp6r5eXF/024OrVq83NzV1cXObMmdPS0kII6erqcnNz4/P5Pj4+EydOPHfunOSu/FC7Gllz586tqKiQ3Pj/5ptvHBwcampqPD09169fL73ljBkzoqKi5ByirKystLQ0Qoi7u/udO3cOHDiwceNGQsjs2bOrqqoIIenp6ZGRkbt27RozZoylpWVERMSTJ08IId3d3Y2NjUVFRQoci/LaGhsbnz9/3tra2sPDw8rK6urVq8XFxTJnFJB27do1Kysrd3d3BWJjxsiULx6GwMDAwMBApqOAVwpBLXagKIqJ+u5hYWEmJiaq3CNNnnO+qqqKy+UePHhQNSHJ1Nvb6+Pjk52drUZtZWpububxeHv37pVnY9WfnwPC9QAAgJE0aivOOTg4JCYmJiYmDlg1R8V6e3sLCws7OjoUqC/KVFt5xMfHe3h4hIeHK6NzJUEeAADAFtHR0UFBQSEhIYyXFCotLT1+/HhJScngUxqMqrYypaamlpWVnTx5UktLa8Q7Vx7kAQAAIyMmJiYnJ6etrW3ChAnHjh1jOpyBJScnh4eH79ixg9kwZs2adfjwYUm1BbVoO7iioqJnz56VlpYaGxuPeOdKxWU6AACAV0RKSkpKSgrTUcjm5+fn5+fHdBSvmvnz58+fP5/pKBSB6wEAAADshTwAAACAvZAHAAAAsBfyAAAAAPZCHgAAAMBiTE9kRAUGBjI9BgAAAMxg+keY4lAUxewQXLp0iZ5bGwBULzg4OCIiwsvLi+lAAFhq8eLFzAbAfB4AAAzicDh5eXmMfxMBAFPwfAAAAAB7IQ8AAABgL+QBAAAA7IU8AAAAgL2QBwAAALAX8gAAAAD2Qh4AAADAXsgDAAAA2At5AAAAAHshDwAAAGAv5AEAAADshTwAAACAvZAHAAAAsBfyAAAAAPZCHgAAAMBeyAMAAADYC3kAAAAAeyEPAAAAYC/kAQAAAOyFPAAAAIC9kAcAAACwF/IAAAAA9kIeAAAAwF7IAwAAANgLeQAAAAB7IQ8AAABgL+QBAAAA7IU8AAAAgL2QBwAAALAX8gAAAAD2Qh4AAADAXsgDAAAA2IvLdAAAoFJHjx7t6OiQXnLmzJnW1lbJx4CAADMzM5XHBQDM4FAUxXQMAKA6oaGhX331lZaWFv2R/gbgcDiEkN7eXn19/cbGRh0dHSZDBAAVwn0BAHZZsmQJIaTnObFYLBaL6f/W1NQMCgpCEgDAKrgeAMAuYrHYwsKipaVlwLVnz57985//rOKQAIBBuB4AwC5cLnfJkiWS+wLSTE1NZ86cqfqQAIBByAMAWGfJkiU9PT39Fmppab333nuampqMhAQATMF9AQDWoSjKxsbm/v37/ZZfvXrV09OTkZAAgCm4HgDAOhwOZ9myZf1uDYwbN2769OlMhQQATEEeAMBG/W4NaGlphYaG0m8PAgCr4L4AAEs5OztXVlZKPt66dWvy5MkMxgMAjMD1AACWeu+99yS3BlxcXJAEALAT8gAAllq2bJlYLCaEaGlp/fWvf2U6HABgBu4LALDX9OnTf/75Zw6HU1tba2Njw3Q4AMAAXA8AYK/333+fEPLGG28gCQBgLdQbVJFLly6lpqYyHQXA/9HV1cXhcJ49exYUFMR0LAD/h5eXV1RUFNNRsAKuB6jIvXv3jh07xnQUr6b79+9jbIfq8uXLly9f5vF4FhYW1tbWTIejLDg31NTly5cvXbrEdBRsgesBKlVQUMB0CK+g/Pz84OBgjO2Q0BcACgoKqqurHRwcmA5HWXBuqClcoFIlXA8AYLVXOAkAAHkgDwAAAGAv5AEAAADshTwAAACAvZAHAAAAsBfyAACQ18mTJwUCwT//+U+mA1GWM2fOREdHHz9+3M7OjsPhcDic9957T3oDPz8/AwMDTU3NyZMnX79+nak4Jbq6upydnePi4lTTtqenJyUlxcHBQVtb28jIyNXVtba2VmbP33777a5du3p7exUIElQAeQAAyOvVnoZ827ZtGRkZMTExixYtunPnjr29/ZgxYw4dOlRcXCzZ5vTp0wUFBf7+/hUVFdOmTWMwWlpsbKx00Uhltw0ODv76668PHz4sFAp//fVXe3v7p0+fyux53rx5PB5v1qxZra2tioUKSoU8AADkNXfu3La2Nn9/f2XvSCQSeXt7K3sv0nbu3Jmbm5ufn29gYCBZmJGRoaGhERYW1tbWpspg5HTx4sVbt26prG1ubm5hYWFBQcEbb7zB5XItLS2LiopcXV3l6XnDhg1TpkyZM2cOXdoKRhXkAQAw6mRnZzc2Nqpsd9XV1Vu2bElISODxeNLLvb29IyIiGhoaPvroI5UFIyeRSPTxxx+np6errO1nn302bdo0Nzc3xXqOj48vKytTLGBQKuQBACCXCxcu2NjYcDicTz/9lBCSlZWlp6enq6tbVFT0zjvvGBoaWltbHz16lN44IyODx+OZm5uvWrXK0tKSx+N5e3tfuXKFXhseHq6trT127Fj649q1a/X09DgcTnNzMyEkIiJi48aNNTU1HA6Hnubo1KlThoaGycnJSjq0jIwMiqLmzZv34qrt27dPnDjxiy++OHPmzIBtKYpKTU2dNGmSjo6OsbHxggULfvvtN3rV4ENECOnt7d26dauNjQ2fz3d3d8/Ly5M/5tjY2LVr15qZmQ3lQBVv293dffnyZQ8PD4V7NjY2njlzZnp6+qt9d0kdIQ8AALm8+eabFy9elHxcs2ZNZGSkSCQyMDDIy8urqamxs7NbuXJlT08PISQ8PDw0NFQoFG7YsKG2tvb69etisfitt966d+8eISQjI2Px4sWSrjIzMxMSEiQf09PT/f397e3tKYqqrq4mhNCPmPX19Snp0IqLi52cnHR1dV9cxefzv/zySw0NjZUrV3Z2dr64QXx8fHR0dGxsbGNj448//njv3j0fH59Hjx4RWUNECNm8efPu3bvT0tIePnzo7++/dOnSf/3rX/IE/NNPP9XU1CxdulSBg1Ws7YMHD7q7u3/++WdfX186sZs0aVJmZqb0j7rMnqdOndrQ0PDLL78oEDYoD/IAABgWb29vQ0NDMzOzkJCQzs7O+vp6ySoul0v/oezi4pKVldXR0ZGTk6PALubOndve3r5ly5aRi/p/dXZ23r17197e/mUbeHl5RUZG1tbWbt68ud8qkUiUmpq6cOHCZcuWCQQCNze3/fv3Nzc3f/7559KbDThEXV1dWVlZAQEBixYtMjIyiouL09LSkmd8RCJRREREVlaWAgercFv6eUAzM7Pk5OSKiopHjx4tWLBg3bp1R44ckb9nR0dHQkh5ebkCkYPyIA8AgJGhra1NCJH8sdvP9OnTdXV1JdfMR4/GxkaKoga8GCCxfft2JyenzMzMCxcuSC+vqKh4+vTp9OnTJUs8PT21tbUld0D6kR6iyspKoVAoec6Oz+ePHTtWnvGJiYn58MMPraysZG45gm11dHQIIZMnT/b29jYxMREIBAkJCQKBQJLxyNMzPcj0xRIYPZAHAICK6OjoNDU1MR1Ff11dXeT579zL8Hi8nJwcDofzwQcfiEQiyXL6RTh9fX3pjY2MjDo6OmTul77LEBcXx3murq5OKBQO3urChQvl5eUrVqyQ2f/ItrW0tCSE0A9w0LS1tW1tbWtqauTvmc/nk+cDDqMH8gAAUIWenp7W1lZra2umA+mP/nGSOcuNl5dXVFRUVVVVUlKSZKGRkREhpN+vvpyHST9Ml5aWRkm5dOnS4K2ys7PPnj2roaFBpw50J8nJyRwOR+azBcNpq6+v7+joePv2bemFYrFYIBDI33N3dzd5PuAweiAPAABVKC0tpShqxowZ9Ecul/uyOwgqZm5uzuFw5JkhICkpydnZ+caNG5Ilrq6u+vr60j91V65c6e7ufv3112X2Nm7cOB6PV1ZWNqRoc3JypPMG+vpKbGwsRVHStydGvC0hJDg4+MaNG3fu3KE/CoXCuro6+jVCOXumB9nCwmJIhwzKhjwAAJSlr6/vyZMnYrH45s2bERERNjY2oaGh9CoHB4eWlpbCwsKenp6mpqa6ujrphiYmJg8ePKitre3o6Ojp6SkpKVHee4O6urp2dnb379+XuSV9d0BTU1N6ycaNG0+cOHHo0KH29vby8vLVq1dbWlqGhYXJ09vy5cuPHj2alZXV3t7e29t7//79hw8fEkJCQkIsLCwUm7dYeW2joqJsbW1DQ0Pr6+sfP368adMmkUj04rOTg6AHefAZCED1kAcAgFw+/fRTT09PQsimTZvmz5+flZWVlpZGCHF3d79z586BAwc2btxICJk9e3ZVVRXdpKury83Njc/n+/j4TJw48dy5c5Lb8GvWrPH19V2yZImTk1NSUhJ9rdjLy4t+sXD16tXm5uYuLi5z5sxpaWlR9qHNnTu3oqJCcuP/m2++cXBwqKmp8fT0XL9+vfSWM2bMiIqKkl6ybdu2lJSUxMREU1PTmTNnjh8/vrS0VE9PjxAic4jS09MjIyN37do1ZswYS0vLiIiIJ0+eEEK6u7sbGxuLiooUOBbltTU2Nj5//ry1tbWHh4eVldXVq1eLi4tlzigg7dq1a1ZWVu7u7grEBkpEgUrQM4QwHcWrCWOrgMDAwMDAQKXuIiwszMTERKm7kEnOc6OqqorL5R48eFAFIcmjt7fXx8cnOztbjdrK1NzczOPx9u7dK8/GKjg/QQLXAwBAWdSlxJyDg0NiYmJiYuKAVXNUrLe3t7CwsKOjIyQkRF3ayiM+Pt7DwyM8PFwZncNwIA8AACDR0dFBQUEhISGMlxQqLS09fvx4SUnJ4FMajKq2MqWmppaVlZ08eVJLS2vEO4dhQh7wSlFGeXiVlZxPTEx0cXExNDTU0dFxcHD45JNPlPfH2ZEjRzgczjAr2qn1aCtbTExMTk5OW1vbhAkTjh07xnQ4cklOTg4PD9+xYwezYcyaNevw4cOS4gtq0XZwRUVFz549Ky0tNTY2HvHOYfi4TAcAI4lSQgEPZfQ5oB9++GHdunUhISFaWlolJSXLli0rLy8vKSlRxr6OHDlib29/6dKl6upqupKNAtR6tJUtJSUlJSWF6SiGzM/Pz8/Pj+koXjXz58+fP38+01HAS+F6gHrrV6Z9RMrDK6NPeejr69NPlhkYGCxevDggIODUqVP00+Mj6/Hjx7dv36YL23z99dfyN3yVRhsAgIY8QL0po0y7iku/S3z33XfSb2abmpoSQmROs6qA/Pz8uXPnzps3j8fj0Y+Iy9nwVRptAAAa8oDR5fz58y4uLgKBgMfjubm5ff/995JVBw8enD59Oo/H09PTGz9+fFJSUr8y7f3Kw0+aNInD4WhoaLz++uv0r+knn3xC9/zll1++bF+D90mGV219SBoaGvh8/oQJExQfzZc4cuTIwoULDQwM/Pz8amtrz58//+I2bBttAGAvBt9ZZBU532MuKCiIj49vaWl5/PjxjBkzxowZQy+nZyPZsWPH48ePW1pa/v73v7/77rsURS1atIgu006jr6Lv27ePoiixWDx+/HgbGxuxWCzZIDIyUjKf+cv2NUifFEVt3bpVW1v74MGDra2tN2/enDZtmqmp6e+//06vjY2NJYScPXu2ra2tsbHRx8dHT0+vu7t7qMPV2dlpYGAQHh4uz8ZDmj+grq7OzMyMHpODBw8SQv72t7/124YNo82S97Mxt4SaYsn5OUrg/xAVUeD7iH7MqrGxsbu728jIyNfXV7JKLBanp6dTsn5F6N+z/Px8+mNnZ6eNjU1bW9sg+xq8T6FQqK+vHxISIll79epVQkhiYiL9kf5lEolE9MfMzExCSHV19ZAOnO5n4sSJ7e3t8mw8pLHdsWPH8uXL6f9ua2vT0dExNDQUCoWSDVgy2iz5nkUeoKZYcn6OErgvMHrRL9r29vbevHmztbX17bfflqzS1NTcsGGDzB5WrFghEAjS09Ppj4cOHVqwYIGhoeEg+xq8w+FUW5ffiRMn8vPzv//+ewMDgyE1lAd9U4D+b0NDQz8/v/b2dumJVNkz2seOHeO86oKDgwkhTEcBQ6Yu75q+GvDe4OhSXFy8Z8+eioqK9vZ2yRd6e3s7eV7hdEj09fU//PDDPXv2XL169Q9/+MNnn30m/X/XgPsa3HCqrcspNzc3NTW1tLT0tddeG6k+JW7dulVeXv7i0/hff/21ZA419oz2jBkzIiMjR6SrUevSpUvp6en0VQFQI/TVNVAN5AGjSH19fUBAwMKFC//xj3+89tpr+/bt++STTwgh9C9ic3OzAn2Gh4enp6enpaWtXr163Lhx9vb2g+9rcMOpti6Pffv2ff/99z/88EO/H7+Rcvjw4SVLlhw5ckSy5MmTJ1ZWVqdPn/7999/pGVTYM9rW1taLFy8eka5Gs/T0dDYc5iumoKCA6RBYBPcFRpHy8vKenp41a9bY2dnxeDwOh0MvHz9+vImJyenTpxXok/6uP3bs2JYtWyIiImTua3DDqbY+OIqiNm3aVF5eXlhYqKQkgKKo3NzctWvXSi80NjYOCgrq7e2VJAdsGG0AAAnkAaOIjY0NIeTMmTNdXV1VVVWS28A6OjoxMTE//vhjeHh4Q0NDX19fR0fH7du3yQtl2gfsduPGjWKx+MmTJ3/+859l7mvwPodTbX1wt2/f3r1794EDB7S0tKRvE+7du3eYPUtcvHjR0NDwj3/8Y7/lq1evJlITCrFhtAEA/hfTDyqyhZzPLW/atMnExMTIyCgoKIh+idze3r6+vp6iqE8//dTNzY3H4/F4vKlTp2ZmZlIUdf36dVtbWz6f/+abb8bFxdFXtnV1defNmyfdra+v7xdffCHnvgbvs6+vb8+ePY6OjlpaWsbGxgEBAZWVlXSHmZmZdIUSR0fHmpqazz//nH5KztbW9t///vfgB15eXj7g+blnz54RGdu//e1venp6XC53ypQp169flyxPSkqytLSk92VlZUWP6is/2hRrnsfG+wJqiiXn5yjBoV6V+cxHufz8/ODgYIy2MmBsFRAUFERYcBcW54aaYsn5OUrgvgAAAAB7IQ8AVfjtt98GeVdY8s4eALPOnDkTHR19/PhxOzs7+uR87733pDfw8/MzMDDQ1NScPHny9evXmYpToqury9nZOS4uTjVte3p6UlJSHBwctLW1jYyMXF1da2trZfb87bff7tq1S+aEGcAU5AGgCs7OzoPcncrNzWU6QACybdu2jIyMmJiYRYsW3blzx97efsyYMYcOHSouLpZsc/r06YKCAn9//4qKimnTpjEYLS02NrayslJlbYODg7/++uvDhw8LhcJff/3V3t7+6dOnMnuma3rNmjWLnhIDRhvkAQCgFP1KKo+Srl5m586dubm5+fn50rNYZmRkaGhohIWFtbW1KXXvirl48eKtW7dU1jY3N7ewsLCgoOCNN97gcrmWlpZFRUWurq7y9Lxhw4YpU6bMmTNHLBYrFjAoD/IAAFCKESyprOzqzNXV1Vu2bElISODxeNLLvb29IyIiGhoaPvroI+XtXTEikejjjz+WzGOtgrafffbZtGnT3NzcFOs5Pj6+rKxMsYBBqZAHAMBLUS8vfBweHq6trU2/6EgIWbt2rZ6eHofDoadi7FdSOSMjg8fjmZubr1q1ytLSksfjeXt7S+ZRGFJXhJBTp04ZGhomJyeP1GFmZGRQFDVv3rwXV23fvn3ixIlffPHFmTNnhjpEMmtD9/b2bt261cbGhs/nu7u7D2n+49jY2LVr15qZmQ3lQBVv293dffnyZQ8PD4V7NjY2njlzJl2ya2jhgpIhDwCAl4qPj4+Ojo6NjW1sbPzxxx/v3bvn4+Pz6NEjQkhGRob0fL2ZmZkJCQmSj+np6f7+/nQpxerq6vDw8NDQUKFQuGHDhtra2uvXr4vF4rfeeouurzikrsjzEk19fX0jdZjFxcVOTk70fAz98Pn8L7/8UkNDY+XKlZ2dnS9uMMgQrVmzJjIyUiQSGRgY5OXl1dTU2NnZrVy5UjJh1ObNm3fv3p2Wlvbw4UN/f/+lS5dKTx85iJ9++qmmpmbp0qUKHKxibR88eNDd3f3zzz/7+vrSmdykSZPoeTXk73nq1KkNDQ2//PKLAmGD8iAPAICBiUSi1NTUhQsXLlu2TCAQuLm57d+/v7m5+fPPP1esQy6XS//d7OLikpWV1dHRkZOTo0A/c+fObW9v37Jli2Jh9NPZ2Xn37l1JMYgXeXl5RUZG1tbWbt68ud8qOYfI29vb0NDQzMwsJCSks7Ozvr6eENLV1ZWVlRUQELBo0SIjI6O4uDgtLS15BkQkEkVERGRlZSlwsAq3pZ8HNDMzS05OrqioePTo0YIFC9atWyeZkFuenh0dHQkhL5s0DJiCPAAABjbUwsdDMn36dF1dXckldAY1NjZSFDXgxQCJ7du3Ozk5ZWZmXrhwQXr5cGpDV1ZWCoVCyXN2fD5/7Nix8gxITEzMhx9+aGVlJXPLEWyro6NDCJk8ebK3t7eJiYlAIEhISBAIBJKMR56e6UGmL5bA6IE8AAAGpuzCxzo6Ok1NTSPS1XB0dXWR579zL8Pj8XJycjgczgcffCASiSTLhzNE9F2GuLg4yUQadXV1QqFw8FYXLlwoj35nxgAAIABJREFULy9fsWKFzP5Hti09/bZ0HU5tbW1bW9uamhr5e+bz+eT5gMPogTwAAAam1MLHPT09I1hDeTjoHyeZs9x4eXlFRUVVVVUlJSVJFg5niOiH6dLS0qTn0rh06dLgrbKzs8+ePauhoUGnDnQnycnJHA5H5rMFw2mrr6/v6OhIF9ySEIvFAoFA/p67u7vJ8wGH0QN5AAAMTGbhYy6X+7K6izKVlpZSFDVjxozhdzVM5ubmHA5HnhkCkpKSnJ2db9y4IVkynNrQ48aN4/F4ZWVlQ4o2JydHOm+gL6jExsZSFCV9e2LE2xJCgoODb9y4cefOHfqjUCisq6ujXyOUs2d6kC0sLIZ0yKBsyAMAYGAyCx87ODi0tLQUFhb29PQ0NTXV1dVJN3+xpHJfX9+TJ0/EYvHNmzcjIiJsbGxCQ0MV6KqkpGQE3xvU1dW1s7O7f/++PAOSk5OjqakpvUTh2tA8Hm/58uVHjx7Nyspqb2/v7e29f//+w4cPCSEhISEWFhaKzVusvLZRUVG2trahoaH19fWPHz/etGmTSCR68dnJQdCDPPgMBKB6yAMA4KW2bduWkpKSmJhoamo6c+bM8ePHl5aW6unp0WvXrFnj6+u7ZMkSJyenpKQk+nqvl5cX/Tbg6tWrzc3NXVxc5syZ09LSQgjp6upyc3Pj8/k+Pj4TJ048d+6c5K78ULsaWXPnzq2oqJDc+P/mm28cHBxqamo8PT3Xr18vveWMGTOioqLkHKKsrKy0tDRCiLu7+507dw4cOLBx40ZCyOzZs6uqqggh6enpkZGRu3btGjNmjKWlZURExJMnTwgh3d3djY2NRUVFChyL8toaGxufP3/e2traw8PDysrq6tWrxcXFMmcUkHbt2jUrKyt3d3cFYgMlGlqZYlAU6qArD8ZWAaqv7x4WFmZiYqLKPVJynxtVVVVcLvfgwYMqCEkevb29Pj4+2dnZatRWpubmZh6Pt3fvXnk2Vv35yWa4HgAAKjJqK845ODgkJiYmJiYOWDVHxXp7ewsLCzs6OhSow8lUW3nEx8d7eHiEh4cro3MYDuQBAAAkOjo6KCgoJCSE8ZJCpaWlx48fLykpGXxKg1HVVqbU1NSysrKTJ09qaWmNeOcwTMgDAEDpYmJicnJy2traJkyYcOzYMabDGVhycnJ4ePiOHTuYDWPWrFmHDx+WVFtQi7aDKyoqevbsWWlpqbGx8Yh3DsPHZToAAHj1paSkpKSkMB2FbH5+fn5+fkxH8aqZP3/+/PnzmY4CXgrXAwAAANgLeQAAAAB7IQ8AAABgL+QBAAAA7IXnBFUqPz+f6RBeQXRpFoztkNAzvL7yg4ZzQ03dv39/NNSgYgkORVFMx8AK+fn5wcHBTEcBAKAeAgMDCwoKmI6CFZAHALAah8PJy8tbvHgx04EAADPwfAAAAAB7IQ8AAABgL+QBAAAA7IU8AAAAgL2QBwAAALAX8gAAAAD2Qh4AAADAXsgDAAAA2At5AAAAAHshDwAAAGAv5AEAAADshTwAAACAvZAHAAAAsBfyAAAAAPZCHgAAAMBeyAMAAADYC3kAAAAAeyEPAAAAYC/kAQAAAOyFPAAAAIC9kAcAAACwF/IAAAAA9kIeAAAAwF7IAwAAANgLeQAAAAB7IQ8AAABgL+QBAAAA7IU8AAAAgL2QBwAAALAX8gAAAAD2Qh4AAADAXsgDAAAA2At5AAAAAHtxKIpiOgYAUJ2wsLDKykrJx+vXr0+YMMHY2Jj+qKmp+dVXX1lbWzMUHQCoGpfpAABApSwsLD7//HPpJTdv3pT8t52dHZIAAFbBfQEAdlm6dOnLVmlra4eGhqowFgBgHu4LALCOq6vr7du3B/x/v7KycuLEiaoPCQCYgusBAKzz/vvva2pq9lvI4XCmTJmCJACAbZAHALDOkiVLent7+y3U1NT861//ykg8AMAg3BcAYCNvb+8rV6709fVJlnA4nHv37llZWTEYFQCoHq4HALDRe++9x+FwJB81NDTefPNNJAEALIQ8AICNgoKCpD9yOJz333+fqWAAgEHIAwDYyNTUdNasWZKnBTkcTkBAALMhAQAjkAcAsNSyZcvox4M0NTXffvvtMWPGMB0RADAAeQAASy1cuFBbW5sQQlHUsmXLmA4HAJiBPACApfT09P7jP/6DEKKtre3v7890OADADOQBAOz17rvvEkICAgL09PSYjgUAmIH5A0ajoKCgY8eOMR0FAMAIwy/OKIR6g6PUjBkzIiMjmY5CnQQHB0dERHh5eTEdCGMuXbqUnp6el5c3pFaHDh0KCQnhctXpqwD/1uqIPj+ZjgIGgOsBoxH9bndBQQHTgagTDoeTl5e3ePFipgNhTH5+fnBw8FD/j+7q6uLxeEoKSUnwb62OFDs/QQXwfAAAq6ldEgAAIwt5AAAAAHshDwAAAGAv5AEAAADshTwAAACAvZAHALDayZMnBQLBP//5T6YDUZYzZ85ER0cfP37czs6Ow+FwOJz33ntPegM/Pz8DAwNNTc3Jkydfv36dqTglurq6nJ2d4+LiVNO2p6cnJSXFwcFBW1vbyMjI1dW1trZWZs/ffvvtrl27ent7FQgSRhvkAQCs9mq/x7Vt27aMjIyYmJhFixbduXPH3t5+zJgxhw4dKi4ulmxz+vTpgoICf3//ioqKadOmMRgtLTY2trKyUmVtg4ODv/7668OHDwuFwl9//dXe3v7p06cye543bx6Px5s1a1Zra6tiocLogTwAgNXmzp3b1tamgvoCIpHI29tb2XuRtnPnztzc3Pz8fAMDA8nCjIwMDQ2NsLCwtrY2VQYjp4sXL966dUtlbXNzcwsLCwsKCt544w0ul2tpaVlUVOTq6ipPzxs2bJgyZcqcOXPEYrFiAcMogTwAAFQhOzu7sbFRZburrq7esmVLQkJCvwkSvL29IyIiGhoaPvroI5UFIyeRSPTxxx8rNumeYm0/++yzadOmubm5KdZzfHx8WVkZZglUd8gDANjrwoULNjY2HA7n008/JYRkZWXp6enp6uoWFRW98847hoaG1tbWR48epTfOyMjg8Xjm5uarVq2ytLTk8Xje3t5Xrlyh14aHh2tra48dO5b+uHbtWj09PQ6H09zcTAiJiIjYuHFjTU0Nh8NxcHAghJw6dcrQ0DA5OVlJh5aRkUFR1Lx5815ctX379okTJ37xxRdnzpwZsC1FUampqZMmTdLR0TE2Nl6wYMFvv/1Grxp8iAghvb29W7dutbGx4fP57u7uQ5rmOTY2du3atWZmZkM5UMXbdnd3X7582cPDQ+GejY2NZ86cmZ6e/mrfXXrlIQ8AYK8333zz4sWLko9r1qyJjIwUiUQGBgZ5eXk1NTV2dnYrV67s6ekhhISHh4eGhgqFwg0bNtTW1l6/fl0sFr/11lv37t0jhGRkZEhP9JuZmZmQkCD5mJ6e7u/vb29vT1FUdXU1IYR+xKyvr09Jh1ZcXOzk5KSrq/viKj6f/+WXX2poaKxcubKzs/PFDeLj46Ojo2NjYxsbG3/88cd79+75+Pg8evSIyBoiQsjmzZt3796dlpb28OFDf3//pUuX/utf/5In4J9++qmmpmbp0qUKHKxibR88eNDd3f3zzz/7+vrSid2kSZMyMzOlf9Rl9jx16tSGhoZffvlFgbBhlEAeAAD9eXt7GxoampmZhYSEdHZ21tfXS1ZxuVz6D2UXF5esrKyOjo6cnBwFdjF37tz29vYtW7aMXNT/q7Oz8+7du/b29i/bwMvLKzIysra2dvPmzf1WiUSi1NTUhQsXLlu2TCAQuLm57d+/v7m5+fPPP5febMAh6urqysrKCggIWLRokZGRUVxcnJaWljzjIxKJIiIisrKyFDhYhdvSzwOamZklJydXVFQ8evRowYIF69atO3LkiPw9Ozo6EkLKy8sViBxGCeQBAPBS2trahBDJH7v9TJ8+XVdXV3LNfPRobGykKGrAiwES27dvd3JyyszMvHDhgvTyioqKp0+fTp8+XbLE09NTW1tbcgekH+khqqysFAqFkufs+Hz+2LFj5RmfmJiYDz/80MrKSuaWI9hWR0eHEDJ58mRvb28TExOBQJCQkCAQCCQZjzw904NMXywBNYU8AAAUp6Oj09TUxHQU/XV1dZHnv3Mvw+PxcnJyOBzOBx98IBKJJMvpF+H09fWlNzYyMuro6JC5X/ouQ1xcHOe5uro6oVA4eKsLFy6Ul5evWLFCZv8j29bS0pIQQj/AQdPW1ra1ta2pqZG/Zz6fT54POKgp5AEAoKCenp7W1lZra2umA+mP/nGSOcuNl5dXVFRUVVVVUlKSZKGRkREhpN+vvpyHST9Ml5aWRkm5dOnS4K2ys7PPnj2roaFBpw50J8nJyRwOR+azBcNpq6+v7+joePv2bemFYrFYIBDI33N3dzd5PuCgppAHAICCSktLKYqaMWMG/ZHL5b7sDoKKmZubczgceWYISEpKcnZ2vnHjhmSJq6urvr6+9E/dlStXuru7X3/9dZm9jRs3jsfjlZWVDSnanJwc6byBvr4SGxtLUZT07YkRb0sICQ4OvnHjxp07d+iPQqGwrq6Ofo1Qzp7pQbawsBjSIcOogjwAAIagr6/vyZMnYrH45s2bERERNjY2oaGh9CoHB4eWlpbCwsKenp6mpqa6ujrphiYmJg8ePKitre3o6Ojp6SkpKVHee4O6urp2dnb379+XuSV9d0BTU1N6ycaNG0+cOHHo0KH29vby8vLVq1dbWlqGhYXJ09vy5cuPHj2alZXV3t7e29t7//79hw8fEkJCQkIsLCwUm7dYeW2joqJsbW1DQ0Pr6+sfP368adMmkUj04rOTg6AHefAZCGCUQx4AwF6ffvqpp6cnIWTTpk3z58/PyspKS0sjhLi7u9+5c+fAgQMbN24khMyePbuqqopu0tXV5ebmxufzfXx8Jk6ceO7cOclt+DVr1vj6+i5ZssTJySkpKYm+Vuzl5UW/WLh69Wpzc3MXF5c5c+a0tLQo+9Dmzp1bUVEhufH/zTffODg41NTUeHp6rl+/XnrLGTNmREVFSS/Ztm1bSkpKYmKiqanpzJkzx48fX1paqqenRwiROUTp6emRkZG7du0aM2aMpaVlRETEkydPCCHd3d2NjY1FRUUKHIvy2hobG58/f97a2trDw8PKyurq1avFxcUyZxSQdu3aNSsrK3d3dwVig9GCgtEnMDAwMDCQ6SjUDCEkLy+P6SiYRE9Zo9RdhIWFmZiYKHUX8pDn37qqqorL5R48eFA1IcnU29vr4+OTnZ2tRm1lam5u5vF4e/fulWdjFZyfoBhcDwCAIVCXEnMODg6JiYmJiYkDVs1Rsd7e3sLCwo6OjpCQEHVpK4/4+HgPD4/w8HBldA4qgzzgFbFixQoDAwMOhzPUZ5RGm8TERBcXF0NDQx0dHQcHh08++WSkvselK8/StLW1zc3N//SnP+3Zs4e+eAuvkujo6KCgoJCQEMZLCpWWlh4/frykpGTwKQ1GVVuZUlNTy8rKTp48qaWlNeKdg0oxfUECBqDYfQF6kvMbN24oIySVmTlzZmZm5uPHj9vb2/Py8rS0tGbPni1PQyLffQF7e3uBQEBRFP2827lz50JDQzkcjqWl5bVr14YbPaOUfd01OjqanjNn/PjxBQUFytuRTHL+W9O+//77TZs2KTUeFiosLExJSRGLxfI3wX2BUQvXA0DphlRwVl9fn74JbWBgsHjx4oCAgFOnTtEPmo0sDodjZGT0pz/9KScnJz8//9GjR3QF3hHf0TCpvlzvy6SkpDx79oyiqLt37wYGBjIdjrz8/Px27tzJdBSvmvnz50dHR0u/ZwHqC3nAq4PD4TAdwsCGVHD2u+++k/5yMTU1JYTInJFtmAIDA0NDQxsbG/fv36/UHSlAxeV6AYBtkAeoMYqi9uzZ4+TkpKOjIxAIPv74Y8mq3bt36+rqGhgYNDY2bty40crKqrKyknp5NdXBS8qSQSuxDrXg7JA0NDTw+fwJEyYoPEpyol+CLykpIa/Q6AEAyMbkTQl4CTmfD4iNjeVwOP/5n//55MkToVCYmZlJpJ4PiI2NJYRs2LBh3759Cxcu/PXXX7du3aqtrX3w4MHW1tabN29OmzbN1NT0999/p7cPCwvT09O7fft2V1dXRUWFp6engYFBfX09vXbwtu+++66FhYUksD179hBCmpqa6I+LFi2iC84OVWdnp4GBQXh4uDwbkyE+H9BPe3s7IWTcuHH0R3UcPfbcf5Xz3xpGFfacn2oH1wPUlUgkSktL+8tf/hIVFWVkZMTn801MTF7cbOfOnevWrTt+/Litra3MaqovKykrZyXWEZeSkmJpabl9+3al7oVGv23Rb1Z5tR49AAB5cJkOABRUXV0tFApnzZol5/ZDraYqXVJ2qG1HxIkTJ/Lz80+fPm1gYKC8vUh0dnZSFGVoaDjgWjUavfz8fGV0O9rILN4Dow3+yUYt5AHqip7Wmy4CJg8FqqlKSsoOpxKrYnJzc1NTU0tLS1977TUl7aKff//734QQZ2fnAdeq0egFBwcro9vRJj09PT09nekoAF4FyAPUFY/HI4Q8e/ZMzu2HWk1VuqTscCqxKmDfvn3ff//9Dz/80O+3U6lOnTpFCHnnnXcGXKtGo0dRlDK6HVU4HE5eXt7ixYuZDgSGID8/nyVJqtrB8wHqytXVVUND43/+53/k335I1VSlS8rKbDtSBWcpitq0aVN5eXlhYaEqk4Dff/89LS3N2tr6gw8+GHADtRg9AAAFIA9QV2ZmZosWLTp27Fh2dnZ7e/vNmzcHf+5MnmqqLyspK7PtkArODhLk7du3d+/efeDAAS0tLekJgPfu3avwQL2IoqinT5/29fVRFNXU1JSXl/fHP/5RU1OzsLDwZc8HqMXoAQAogsF3FeBl5HxvsKOjY8WKFWPGjNHX13/zzTe3bt1KCLG2tv7ll1927dpFV30dN26cpORaX1/fnj17HB0dtbS0jI2NAwIC6NfiaWFhYVpaWlZWVlwu19DQcMGCBTU1NZK1g7d9/Pixr68vj8ebMGHC+vXr6ZkMHBwc6Bfnrl+/bmtry+fz33zzTcnLcgMqLy8f8Czds2ePzNEgst4l+/bbb93d3XV1dbW1tTU0NMjzKQX/8Ic/JCYmPn78WLKlmo4ee97LkvlvDaMQe85PtcOhWHA3Ue0EBQURQgoKClS501WrVhUUFDx+/FiVOx1BzN4zHg2jR99/ZcP/0Xg+QB2x5/xUO7gvAP9LXUrKjk4YPQBQR8gDQHV+++03zsspqUQ6AAAMAnkAEEJITExMTk5OW1vbhAkTjh07pqS9ODs7D3KPKjc3V0n7VTbVjB4o5syZM9HR0cePH7ezs6Mzzvfee096Az8/PwMDA01NzcmTJ1+/fp2pOCW6urqcnZ3j4uJU07anpyclJcXBwUFbW9vIyMjV1bW2tlZmz99+++2uXbtwDezVgDwACFHbkrKjBEZv1Nq2bVtGRkZMTMyiRYvu3Lljb28/ZsyYQ4cOFRcXS7Y5ffp0QUGBv79/RUXFtGnTGIyWFhsbW1lZqbK2wcHBX3/99eHDh4VC4a+//mpvb//06VOZPc+bN4/H482aNYueJgvUGvIAAJCXSCTy9vYebV29zM6dO3Nzc/Pz86Wnps7IyNDQ0AgLC2tra1Pq3hVz8eLFW7duqaxtbm5uYWFhQUHBG2+8weVyLS0ti4qKXF1d5el5w4YNU6ZMmTNnjlgsVixgGCWQBwCAvLKzsxsbG0dbVwOqrq7esmVLQkICPfOmhLe3d0RERENDw0cffaS8vStGJBJ9/PHHis2XrFjbzz77bNq0aW5ubor1HB8fX1ZWhgme1R3yAAB2oSgqNTWVLo1obGy8YMECuh4SISQ8PFxbW3vs2LH0x7Vr1+rp6XE4nObmZkJIRETExo0ba2pqOByOg4NDRkYGj8czNzdftWqVpaUlj8fz9vaWFE8aUleEkFOnThkaGiYnJ4/UYWZkZFAUNW/evBdXbd++feLEiV988cWZM2eGOkRZWVl6enq6urpFRUXvvPOOoaGhtbX10aNHJW17e3u3bt1qY2PD5/Pd3d3pl+blFBsbu3btWvmLhgyzbXd39+XLlz08PBTu2djYeObMmenp6XgbUK0hDwBgl/j4+Ojo6NjY2MbGxh9//PHevXs+Pj6PHj0ihGRkZEi/lJ+ZmZmQkCD5mJ6e7u/vb29vT1FUdXV1eHh4aGioUCjcsGFDbW3t9evXxWLxW2+9de/evaF2RZ6/ddnX1zdSh1lcXOzk5KSrq/viKj6f/+WXX2poaKxcubKzs/PFDQYZojVr1kRGRopEIgMDg7y8vJqaGjs7u5UrV0qmety8efPu3bvT0tIePnzo7++/dOlS6SmlB/HTTz/V1NQsXbpUgYNVrO2DBw+6u7t//vlnX19fOpObNGlSZmam9I+6zJ6nTp3a0NDwyy+/KBA2jBLIAwBYRCQSpaamLly4cNmyZQKBwM3Nbf/+/c3NzYNPSj0ILpdL/93s4uKSlZXV0dGRk5OjQD9z585tb2/fsmWLYmH009nZeffuXXt7+5dt4OXlFRkZWVtbu3nz5n6r5Bwib29vQ0NDMzOzkJCQzs7O+vp6QkhXV1dWVlZAQMCiRYuMjIzi4uK0tLTkGRCRSBQREZGVlaXAwSrcln4e0MzMLDk5uaKi4tGjRwsWLFi3bt2RI0fk79nR0ZEQ8rKZQEEtIA8AYJGKioqnT59Onz5dssTT01NbW1tyPX84pk+frqurK7mEzqDGxkaKoga8GCCxfft2JyenzMzMCxcuSC8f6hBpa2sTQujrAZWVlUKhUPKcHZ/PHzt2rDwDEhMT8+GHH1pZWcnccgTb6ujoEEImT57s7e1tYmIiEAgSEhIEAoEk45GnZ3qQ6YsloKaQBwCwCP2WV79ajkZGRv3KIitMR0enqalpRLoajq6uLvL8d+5leDxeTk4Oh8P54IMPRCKRZPlwhoi+yxAXFyeZHauurk4oFA7e6sKFC+Xl5StWrJDZ/8i2tbS0JITQT2zQtLW1bW1ta2pq5O+ZrsRBDzioKeQBACxiZGRECOn3k9ba2mptbT38znt6ekaqq2Gif5xkznLj5eUVFRVVVVWVlJQkWTicIaIfpktLS5OeIOvSpUuDt8rOzj579qyGhgadOtCdJCcnczgcmc8WDKetvr6+o6Pj7du3pReKxWKBQCB/z93d3eT5gIOaQh4AwCKurq76+vrS3+NXrlzp7u5+/fXX6Y9cLlfh6salpaUURc2YMWP4XQ2Tubk5h8ORZ4aApKQkZ2fnGzduSJbIHKJBjBs3jsfjlZWVDSnanJwc6byBvqASGxtLUZT07YkRb0sICQ4OvnHjxp07d+iPQqGwrq6Ofo1Qzp7pQbawsBjSIcOogjwAgEV4PN7GjRtPnDhx6NCh9vb28vLy1atXW1pahoWF0Rs4ODi0tLQUFhb29PQ0NTXV1dVJNzcxMXnw4EFtbW1HRwf9G9/X1/fkyROxWHzz5s2IiAgbG5vQ0FAFuiopKRnB9wZ1dXXt7Ozu378vz4Dk5ORoampKLxl8iAbvbfny5UePHs3Kympvb+/t7b1///7Dhw8JISEhIRYWForNW6y8tlFRUba2tqGhofX19Y8fP960aZNIJHrx2clB0IM8+AwEMMohDwBgl23btqWkpCQmJpqams6cOXP8+PGlpaV6enr02jVr1vj6+i5ZssTJySkpKYm+3uvl5UW/Dbh69Wpzc3MXF5c5c+a0tLQQQrq6utzc3Ph8vo+Pz8SJE8+dOye5Kz/UrkbW3LlzKyoqJDf+v/nmGwcHh5qaGk9Pz/Xr10tvOWPGjKioKDmHKCsrKy0tjRDi7u5+586dAwcObNy4kRAye/bsqqoqQkh6enpkZOSuXbvGjBljaWkZERHx5MkTQkh3d3djY2NRUZECx6K8tsbGxufPn7e2tvbw8LCysrp69WpxcbHMGQWkXbt2zcrKyt3dXYHYYLQYpO4LMCUwMDAwMJDpKNQMISQvL4/pKJhET1mjyj2GhYWZmJioco80ef6tq6qquFzuwYMHVROSTL29vT4+PtnZ2WrUVqbm5mYej7d37155Nlb9+QlywvUAAFDcqK045+DgkJiYmJiYOGDVHBXr7e0tLCzs6OhQoLg2U23lER8f7+HhER4erozOQWWQBwDAqyk6OjooKCgkJITxkkKlpaXHjx8vKSkZfEqDUdVWptTU1LKyspMnT2ppaY1456BKyAMAQBExMTE5OTltbW0TJkw4duwY0+EMLDk5OTw8fMeOHcyGMWvWrMOHD0uqLahF28EVFRU9e/astLTU2Nh4xDsHFeMyHQAAqKWUlJSUlBSmo5DNz8/Pz8+P6SheNfPnz58/fz7TUcDIwPUAAAAA9kIeAAAAwF7IAwAAANgLeQAAAAB74TnBUery5ctBQUFMR6Fm0tLSCgoKmI6CMfQMryw5bVj+b62O5JnmGRjBoSiK6Rigv9TUVJk1ygBGRElJydSpU5XxahnAi5C9jULIAwBYjcPh5OXlLV68mOlAAIAZeD4AAACAvZAHAAAAsBfyAAAAAPZCHgAAAMBeyAMAAADYC3kAAAAAeyEPAAAAYC/kAQAAAOyFPAAAAIC9kAcAAACwF/IAAAAA9kIeAAAAwF7IAwAAANgLeQAAAAB7IQ8AAABgL+QBAAAA7IU8AAAAgL2QBwAAALAX8gAAAAD2Qh4AAADAXsgDAAAA2At5AAAAAHshDwAAAGAv5AEAAADshTwAAACAvZAHAAAAsBfyAAAAAPZCHgAAAMBeyAMAAADYC3kAAAAAeyEPAAAAYC/kAQAAAOzFZToAAFCp1tZWiqKkl3R2dj558kTyUV9fX0tLS+VxAQAzOP2+EQDg1fbnP//53LlzL1urqanZ0NBgYWGhypAAgEG4LwDALkuWLOFwOAOu0tDQ+H//7/8hCQBgFeSe8kvyAAAgAElEQVQBAOwSGBjI5Q58Q5DD4bz//vsqjgcAmIU8AIBdjI2N/fz8NDU1X1yloaEREBCg+pAAgEHIAwBYZ9myZX19ff0WcrncuXPnCgQCRkICAKYgDwBgnXnz5uno6PRb2Nvbu2zZMkbiAQAGIQ8AYB1dXd2AgIB+Lwfy+fw5c+YwFRIAMAV5AAAbLV26tKenR/JRS0srMDCQz+czGBIAMAJ5AAAbvf3229KPAvT09CxdupTBeACAKcgDANhIS0srJCREW1ub/mhkZDRr1ixmQwIARiAPAGCpJUuWdHd3E0K0tLSWLVv2skkFAODVhnmF4f+zd+9xTVxp48DPQEhCAgmIgCwICgjITWqlFSo/dNmyVQpeAEGru9TVUrXFALrIReUiKNUCi5L6UVm69QpoC7aI64uVVuq1CopoLaCgeCGgyC3BcJnfH/PpvHm5JCGEBJjn+xczc+bMmcNAnsycOQ+gqL6+vj/96U+NjY0IobKysvfee0/dLQIAqAHcDwCAojQ0NFavXo0QMjExcXd3V3dzAADq8X/uBDY0NFy+fFldTQEAqNjkyZMRQu+++25+fr662wIAUJGpU6e6ubn97zIuITc3V30NAwAAAMCoCwgIkPzoH2RkEIwYAGNfXl5eUFAQXKsjd+rUqYCAAHW3YkIJDAxECE34WyzwNzhOEdenJBgfAAClQRAAAMVBHAAAAABQF8QBAAAAAHVBHAAAAABQF8QBAAAAAHVBHAAAAABQF8QBAACgfmfPnuVyud9//726GzJaSkpKoqOjT58+bWlpiWEYhmHEdJYkb29vXV1dTU1NBweHW7duqaudpK6uLjs7u7i4ONXs293dnZKSYm1tTafT9fT0HB0d6+rqZNZ85syZ1NTU3t5eBRpJgjgAAADUb2K/iL9jx47MzMyYmBh/f/+HDx9aWVkZGBgcPXq0qKiILHP+/Pn8/HxfX9+qqqrZs2ersbWE2NjYBw8eqGzfoKCgb7755tixY0Kh8P79+1ZWVh0dHTJr9vPzYzKZXl5er1+/VqypCOIAAAAYC3x8fFpbW319fUf7QCKRSMXpJHbv3n3y5Mm8vDxdXV1yZWZmpoaGRmhoaGtrqyobI6fLly/fvXtXZfuePHmyoKAgPz//3XffpdFoJiYmhYWFjo6O8tS8adOmWbNmLVq0qKenR7EGQxwAAAAUkp2dLRAIVHa4mpqabdu2JSQkMJlMyfXu7u48Hu/p06ebN29WWWPkJBKJtmzZkpGRobJ9v/rqq9mzZzs5OSlWc3x8fEVFhWINRhAHAACA2pWVlZmbm2MYtn//foQQn89ns9ksFquwsHDhwoUcDsfMzOzEiRNE4czMTCaTaWRk9Omnn5qYmDCZTHd392vXrhFbw8LC6HT6lClTiMWNGzey2WwMw5qbmxFCPB4vMjKytrYWwzBra2uE0Llz5zgcTnJy8iidWmZmJo7jfn5+Azft3LnTxsbm8OHDJSUlg+6L43haWtrMmTMZDIa+vv6SJUt+++03YpP0LkII9fb2bt++3dzcXFtb29nZeVjZc2JjYzdu3GhoaDicE1V8X7FYfPXqVRcXF4Vr1tfX9/T0zMjIUOzpEsQBAACgZvPmzZPM9bphw4bw8HCRSKSrq5ubm1tbW2tpablu3bru7m6EUFhYWEhIiFAo3LRpU11d3a1bt3p6et5///0nT54ghDIzM5cvX05WlZWVlZCQQC5mZGT4+vpaWVnhOF5TU4MQIoaY9fX1jdKpFRUV2draslisgZu0tbW//vprDQ2NdevWdXZ2DiwQHx8fHR0dGxsrEAh+/vnnJ0+eeHh4NDY2IlldhBDaunXrF198kZ6e/vz5c19f35UrV/7666/yNPiXX36pra1duXKlAier2L7Pnj0Ti8U3b95csGABEdjNnDkzKytL8kNdZs1vvfXW06dPb9++rUCzIQ4AAIAxyt3dncPhGBoaBgcHd3Z2Pn78mNxEo9GIL8r29vZ8Pr+9vT0nJ0eBQ/j4+LS1tW3btk15rf5fnZ2djx49srKyGqqAm5tbeHh4XV3d1q1b+20SiURpaWnLli1btWoVl8t1cnI6cOBAc3PzwYMHJYsN2kVdXV18Pn/p0qX+/v56enpxcXFaWlry9I9IJOLxeHw+X4GTVXhfYjygoaFhcnJyVVVVY2PjkiVLPvvss+PHj8tf84wZMxBClZWVCrQc4gAAABjr6HQ6Qoj8stvPnDlzWCwWec987BAIBDiOD3ozgLRz505bW9usrKyysjLJ9VVVVR0dHXPmzCHXuLq60ul08glIP5Jd9ODBA6FQSI6z09bWnjJlijz9ExMT88knn5iamsosqcR9GQwGQsjBwcHd3X3SpElcLjchIYHL5ZIRjzw1E51M3CwZLogDAABg3GMwGE1NTepuRX9dXV3oj8+5oTCZzJycHAzD1qxZIxKJyPXEi3A6OjqShfX09Nrb22Uel3jKEBcXh/2hvr5eKBRK36usrKyysnLt2rUy61fuviYmJgghYgAHgU6nW1hY1NbWyl+ztrY2+qPDhwviAAAAGN+6u7tfv35tZmam7ob0R3w4yZzlxs3NLSIiorq6OikpiVypp6eHEOr3qS/naRKD6dLT03EJV65ckb5Xdnb2hQsXNDQ0iNCBqCQ5ORnDMJljC0ayr46OzowZM+7duye5sqenh8vlyl+zWCxGf3T4cEEcAAAA41tpaSmO43PnziUWaTTaUE8QVMzIyAjDMHlmCEhKSrKzsysvLyfXODo66ujoSH7UXbt2TSwWv/322zJrmzp1KpPJrKioGFZrc3JyJOMG4v5KbGwsjuOSjyeUvi9CKCgoqLy8/OHDh8SiUCisr68nXiOUs2aik42NjYd1ygSIAwAAYPzp6+traWnp6em5c+cOj8czNzcPCQkhNllbW7969aqgoKC7u7upqam+vl5yx0mTJj179qyurq69vb27u7u4uHj03htksViWlpYNDQ0ySxJPBzQ1NSXXREZGfvvtt0ePHm1ra6usrFy/fr2JiUloaKg8tX388ccnTpzg8/ltbW29vb0NDQ3Pnz9HCAUHBxsbGys2b/Ho7RsREWFhYRESEvL48eOXL19GRUWJRKKBYyelIDpZ+gwEQ4E4AAAA1Gz//v2urq4IoaioqMWLF/P5/PT0dISQs7Pzw4cPDx06FBkZiRD64IMPqquriV26urqcnJy0tbU9PDxsbGwuXrxIPobfsGHDggULVqxYYWtrm5SURNwrdnNzI14sXL9+vZGRkb29/aJFi169ejXap+bj41NVVUU++P/uu++sra1ra2tdXV0///xzyZJz586NiIiQXLNjx46UlJTExMTJkyd7enpOmzattLSUzWYjhGR2UUZGRnh4eGpqqoGBgYmJCY/Ha2lpQQiJxWKBQFBYWKjAuYzevvr6+pcuXTIzM3NxcTE1Nb1+/XpRUZHMGQUk3bhxw9TU1NnZWYG2IckbDsRMCzgAYx5cq2DMCggICAgIGNVDhIaGTpo0aVQPIZOcf4PV1dU0Gu3IkSMqaJI8ent7PTw8srOzx9G+MjU3NzOZzL1798pTeOD1CfcDAABg/BlhijmVsba2TkxMTExMHDRrjor19vYWFBS0t7cHBwePl33lER8f7+LiEhYWptjuSo4D9u7dSwwMOXDggMzCrq6umpqaw7r1MdxDAHkM7FIlpkBNTEy0t7fncDgMBsPa2vqf//znUP8O1q5dq6uri2HYcEf3yPT7779//vnnDg4OHA6HTqcbGhra2dktW7bsu+++Iwqo/bo9fvw4hmEqzv6iMMnUsRiGaWlpmZqafvTRR/fv3x955eq6GvudFIZhdDrdyMho/vz5e/bsIW4pA8VER0cHBgYGBwerPaVQaWnp6dOni4uLpU9pMKb2lSktLa2iouLs2bNaWloKViF5c0Ap91qJZzNfffWVPIW9vLxmzZo1qocA8ujXpT/88AOHwzlz5szIa/b09MzKynr58mVbW1tubq6WltYHH3wwVGFievDy8nKZ1cp/rebk5NDp9Hnz5p07d66lpaWrq6u2tvb777/38fEJDQ0li6n3uvXx8SHmXKuurh5utepiZWXF5XJxHO/o6Dhz5oy5ubmOjs5vv/028prVeDWSJ0WMwrt48WJISAiGYSYmJjdu3JDzKKP9XCA6OpqYM2fatGn5+fmjdyDphvt58d///jcqKmr02kNNBQUFKSkpPT098u8yFp8LYBim7iaA/pSYAlVHR4d4lqmrq7t8+fKlS5eeO3eOGK+kAlevXl27dq27u/vFixf/+te/6unpMRgMS0vLDz/8MDMzcyQ1K/G6ffny5b1794hJ4L/55htlVasybDbb19f3X//6V0dHx759+5Rev1quRgzD9PT05s+fn5OTk5eX19jYSDRj5G0YuZSUlDdv3uA4/ujRo4CAAHU3R17e3t67d+9WdysmmsWLF0dHR0u+Z6EAJcQBOI7n5+f3m/NZforfyhhXRthL40i/M/3hhx8kr9HJkycjhIaa2EvpQWFycnJvb++uXbtoNFq/TZaWliN5tKTE6zYvL8/Hx8fPz4/JZBLDqZRVswIUvlDfeecdhJDCKdtHyUiuRlJAQEBISIhAIIBnkWBCUiQO6O3tTUlJsbW11dbWnjx58vTp01NSUiQzXEnCh04cSaipqbGzs2Oz2cQLMJJTTF+6dMne3p7L5TKZTCcnp//+978KtHbQSmbOnIlhmIaGxttvv038F/jnP/9JlPn666/REDkrv/jiCxaLpaurKxAIIiMjTU1NHzx4MFQjpfeSAjkxpScbldnVMn8RpGGlQJV5pv08ffpUW1t7+vTpZKv27Nlja2vLYDC4XO6WLVtk9oP8xGJxSUnJpEmTyPlV5KfK6/b48ePLli3T1dX19vauq6u7dOkSuWkcXag9PT1IYgbZ8Xg1SkG8ml9cXCyzJADjj+RDAjmf9yQnJ2tqahYWFgqFwps3bxobG8+fP5/c2u/Z3vbt2+l0+pEjR16/fn3nzp3Zs2dPnjz5xYsXxFYvLy9LS8tHjx51d3ffvXv33XffZTKZv//+O7E1Pz8/Pj7+1atXL1++nDt3roGBwaCHkG7QSnp6eqZNm2Zubi75WCU8PJych3Lz5s0MBuPUqVMtLS0xMTEaGhrE08HY2FiE0KZNm/bt27ds2bL79+8P1UjpvTRU/dKFhoay2ex79+51dXVVVVW5urrq6uo+fvxYnq6WvrVflxJ3Svft20csEmd94cKF1tZWgUDg4eHBZrPFYrE8Zyqps7NTV1c3LCyMXBMbG4th2JdfftnS0iIUCrOyspDyxgf8/vvvCKG5c+fKrA1X33VbX19vaGhIXIdHjhxBCP3jH/8gt47lC5V8lE4gGr9lyxZ5OnBsXo0DT4rU1taGEJo6deqgVfWjgvcGxwJ4d3ecGnh9KhIHuLq6vvPOO+TiJ598oqGhQTyvwv/v37BQKNTR0QkODiYLX79+HSGUmJhILPYbb3Xnzh2E0ObNmwceNCUlBf2RvUrhcYKSlRBzUOTl5RGbOjs7zc3NW1tbcRwXiUQsFotstlAoZDAYGzZswP/4HyQSiWTWL6WXpNQvXWhoqOQ/qRs3biCEEhIScFldLfMXIc9/XvKsiU/rmpoaYlH69SApNjbWxsamra2NPHEWi/X++++TBZQ7TpCYkfQvf/mLzNpw9V23u3bt+vjjj4mfW1tbGQwGh8MRCoVkgTF7oUqOEzx16pSxsbGRkVFDQ4PMDhybV2O/kxqIGDEw6KZ+IA4AY9nA67P/Q1N5dHV1MZlMcrG3t1dLS2vQcQrDTRzp5OTE5XKJ/6r9EI9jR/jKrGQla9eujY+Pz8jICAwMRAgdPXp0yZIlHA4HjSBnpWT9UnpJ4fr7kUw2Kr2rh/uLkK5fClQ5r4dvv/02Ly/v/Pnzurq6xJqamhqhUOjl5aVAG+RBZCojMo9JysvLi4qKqqurQwjZ2dn99NNPRkZGkgVUed0eP36c+FRGCHE4HG9v7++//76wsJB8z3gsX6itra0Yhmlqak6ZMmXRokU7duwgUqOOx6tRus7OThzHiW6Xx9WrV4nf1wRGTGQ74U9z4rl69Wq/R6WKjA9YtGjRzZs3CwsLRSLRr7/+WlBQ8OGHHw4aByiQOFJLS4v8ky4qKpo/f76hoSGDwfjnP/+pQFOlVKKjo/PJJ59cvnyZ+C7y1VdfkZMwDCtn5VD1S+klxXJiDopMNiq9q0eSwVMmea6HkydP7t69u7S0dNq0aeRK4v8IkT5rNFhYWDAYjJqamn7rly9f/ujRIwsLC2Nj4/v37/cLApAKr9u7d+9WVlb6+vqSVwLxlrzkWwNj+UIlvjr39PQ0NDT8+9//trCwkKcDx+bVKB3xjMnOzm7kLQRgrFHkfkB8fPzNmzdDQkI6OjpMTEyWL18+VI6K4SaO7OnpefXqlbm5OULo8ePHS5cuXbZs2b///e8//elP+/btUyAUkF5JWFhYRkZGenr6+vXrp06dSrzAjSRyVvJ4PIXrl9JL8tcvnWSyUeldPZIMnjLJvB727dv33//+98cff+z3r5/43vbmzZuRt2FQTCbzL3/5S1FR0cD4VzqVXbfHjh1bsWLF8ePHyTUtLS2mpqbnz59/8eLFlClTiJXj7kIdj1ejdOfOnUMILVy4UM7yc+fOzc/Pl7/+8SgvLy8oKGjCn+bEM/AWjiJxQFVVVW1tbVNT08B3sfoZbuLIixcv9vX1zZ49GyFUWVnZ3d29YcMGS0tLpOgbZdIrMTMzW758eW5u7rNnz3bs2EGulz9npZT6pfSSYjkxB5JMNiq9q0eSwVMmKWeK4/jWrVtbWloKCgoGbnV0dNTQ0Pjpp5/Wr18/8mYMKiEh4fz581u2bPnxxx/lf9NPNdctjuMnT548evSo5Ep9ff3AwMBvvvnm+PHjZM6VcXehjserUYoXL16kp6ebmZmtWbNm5C0EYKxR5LnAZ599Zm5uLs9k0fIkjhSLxa2trT09Pbdu3QoLCyNyLyKEiG9XJSUlXV1d1dXVij07lFlJZGRkT09PS0vLn//8Z8lmD5WzUv76pfSS/PUPNFSyUeldPZIMnjJJOdN79+598cUXhw4d0tLSkpyxde/evQghQ0NDf3//U6dOZWdnt7W13blzR+nzK7z99ttHjhy5efPm/Pnzz5079/z5856envr6+iNHjkjJtKaa6/by5cscDue9997rt56IivpNKDS+LtTxeDWScBzv6Ojo6+vDcbypqSk3N/e9997T1NQsKCiQf3wAAOOJ5KBBOcd//vjjjwYGBmQNWlpaM2fOPH36NI7jX375pbGxMUKIzWYvW7YMx/G+vr49e/bMmDFDS0tLX19/6dKlDx48IKvKyclZsGCBkZERjUYzMDBYsWJFfX09uTUqKmrSpEl6enqBgYHE28NWVlY8Hq/fIaQbtBLyXTscxxcsWHD48OF+e7158yYqKsrc3JxGoxEfV1VVVampqUQGz6lTp5Lps4aqX0ovDVW/zHMJDQ0l5nKn0WgcDmfJkiW1tbXkVuldLWVrv9/avn37iDvSLBbLz88vKyuLmBN7xowZtbW1Bw8eJP4bWlhYEG/KSTnTysrKQa+6PXv2EIdub29fu3atgYGBjo7OvHnztm/fjhAyMzO7ffu29K4Y1ljlR48e8Xg8BwcHNpvNZDKnT5/u4eGxdevWn3/+edAekNmZI79u//GPf7DZbBqNNmvWrFu3bpH7JiUlmZiYEL1kamqalZVFbho7F+ovv/xiY2NDlDcxMQkMDBzY5+Puajxz5oyzszOLxaLT6RoaGuiPKQXfeeedxMTEly9fynmx4fC+ABjblPPeYFZWFo/HIxffvHkTHh7OYDAkX3YCo9FLYyHZ6EBquR7gf5CyTLA/57FwOhAHgLFMCe8NvnjxIiwsTPKRIZ1ONzc37+7u7u7uJr6FgNHrpbGWbBSuh3Ftgv36JtjpAKAawx4foK2traWllZ2d3djY2N3d/ezZs8OHD2/fvj04OFj1D89+++03bGijlOlZHgr00pg9F+nG1PUAhmuC/fom2OkAUklJSXR0tGRu6NWrV0sW8Pb21tXV1dTUdHBwuHXrlrra2d3dnZKSYm1tTafT9fT0HB0diXlK+unq6rKzs4uLiyMWz5w5k5qaqs7veJI3B+S8z/Pzzz//5S9/4XA4mpqaXC7X3d09Kyuru7tbyTcvxjml99IYSTY6kFquB7gnqSwT7M95LJwOPBdQru3bt/v6+pIzP1pZWRFDQH744QfJYsXFxYsXL1ZBe6RYunSpra3t1atXiTDUz8+vsrJyYDHiVaDY2FhyTUZGhqenZ0tLiwoaqZzxAQCoHVyrYMxSQRwgFArd3NzUW5Vq/gZ37dplY2MjOUO2lZXVsWPHNDQ0TE1NX79+Ta5Xexxw4sQJDMPu3Lkjvdgvv/zi7e3dLw7AcTwsLMzNzU0FMevA61MJeYcBAACoUnZ2tkAgGGtVKV1NTc22bdsSEhIk54pGCLm7u/N4vKdPn27evFldbRvoq6++mj17tpOTk5QyIpFoy5YtGRkZAzfFx8dXVFQMumm0QRwAAABqgA+dfDksLIxOp5MTSm7cuJHNZmMY1tzcjBDi8XiRkZG1tbUYhllbW0vPSD6sqhBC586d43A4Q00Rq2KZmZk4jvv5+Q3ctHPnThsbm8OHD5eUlAy6r5TulSd79XDzwovF4qtXr7q4uEgvFhsbu3HjxkEnU9fX1/f09MzIyMBxXObhlEzy5gDcawXjBVyrYMyS87mA9OTLH330kbGxMVl4z549CKGmpiZi0d/f38rKitwqPSP5sKr64YcfdHV1ydyPUqjgb9DS0tLe3r7fSisrq0ePHuE4fvnyZQ0NjWnTpnV0dOADngtI717p2asVyAv/6NEjhJCLi8v8+fOnTJnCYDDs7Oz2799PTEhFKCsr8/Pzw3GcSArT77kAjuPR0dFIvoSrIwHPBQAAQP1EIlFaWtqyZctWrVrF5XKdnJwOHDjQ3Nys8JSaNBqN+O5rb2/P5/Pb29tzcnIUqMfHx6etrW3btm2KNUOJOjs7Hz16RGbTGMjNzS08PLyurm7r1q39NsnZve7u7hwOx9DQMDg4uLOz8/Hjxwihrq4uPp+/dOlSf39/PT29uLg4LS0tmZ1JTGFpaGiYnJxcVVXV2Ni4ZMmSzz77jMweIhKJeDwen8+XUsmMGTMQQkNNeDV6IA4AAABVU27y5X4kM5KPXwKBAMdxYvrIoezcudPW1jYrK6usrExy/XC7VzJ7tWLpvBkMBkLIwcHB3d190qRJXC43ISGBy+WSkUdMTMwnn3xCJOYeCnGyjY2N0o+ldBAHAACAqo1q8mUkkZF8/Orq6kJ/fL4Ohclk5uTkYBi2Zs0akUhErh9J9yqWF56YDpwYdUGg0+kWFha1tbUIobKyssrKyrVr10qvhJjqijhxVYI4AAAAVG1Uky9LZiQfv4gPRZmz67i5uUVERFRXVyclJZErR9K9ZLptySfoV65ckb6Xjo7OjBkz7t27J7myp6eHy+UihLKzsy9cuKChoUEEFsQhkpOTMQyTTLwpFovJE1cliAMAAEDVZCZfptFoxG1qBUhmJB9hVWpkZGSEYVhra6vMkklJSXZ2duXl5eSakeS2VjjddlBQUHl5+cOHD4lFoVBYX19PvEaYk5MjGVVIjhOUfHhBnCyRZ0uVIA4AAABVk5l82dra+tWrVwUFBd3d3U1NTfX19ZK7T5o06dmzZ3V1de3t7cRn/FAZyYdbVXFx8Rh5b5DFYllaWjY0NMgsSTwd0NTUlFyjcG5rKem2g4ODjY2Nh5q3OCIigsg//vjx45cvX0ZFRYlEooFjGKUgTlb6DASjAeIAAABQgx07dqSkpCQmJk6ePNnT03PatGmlpaVsNpvYumHDhgULFqxYscLW1jYpKYm4V+zm5vbkyROE0Pr1642MjOzt7RctWvTq1SuEUFdXl5OTk7a2toeHh42NzcWLF8kn68Otauzw8fGpqqoiH/x/99131tbWtbW1rq6un3/+uWTJuXPnEpP1kqR0L5/PT09PRwg5Ozs/fPjw0KFDkZGRCKEPPviguroaIZSRkREeHp6ammpgYGBiYsLj8VpaWhBCYrFYIBAUFhYO2lp9ff1Lly6ZmZm5uLiYmppev369qKhI5owCkm7cuGFqaurs7Cz/LsohebMC3skG4wVcq2DMUn1+AbVkJFfB32B1dTWNRjty5MioHkV+vb29Hh4e2dnZo1F5c3Mzk8ncu3fvaFQuCeYPAACACWisZSRXCmtr68TExMTEROLtfPXq7e0tKChob28fpeyv8fHxLi4uYWFho1G5dBAHAAAAGKOio6MDAwODg4PlGTA4qkpLS0+fPl1cXCx9SgPFpKWlVVRUnD17VktLS+mVywRxAAAAjGMxMTE5OTmtra3Tp08/deqUupujfMnJyWFhYbt27VJvM7y8vI4dO0ZmalCiwsLCN2/elJaW6uvrK71yedDUclQAAABKkZKSkpKSou5WjC5vb28iV++EtHjx4sWLF6uxAXA/AAAAAKAuiAMAAAAA6oI4AAAAAKAuiAMAAAAA6oI4AAAAAKCuQd4XwDBM9e0AQAFwrYIxiyIXJ0VOc4IJCAiQXMRwHCcXGhoaLl++rPImAQDUJigoiMfjubm5qbshAAAVmTp1quSf/P+JAwAAVINhWG5u7vLly9XdEACAesD4AAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviANow6CgAACAASURBVAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqAviAAAAAIC6IA4AAAAAqIum7gYAAFTqxIkT7e3tkmtKSkpev35NLi5dutTQ0FDl7QIAqAeG47i62wAAUJ2QkJD//Oc/WlpaxCLxHwDDMIRQb2+vjo6OQCBgMBjqbCIAQIXguQAA1LJixQqEUPcfenp6enp6iJ81NTUDAwMhCACAUuB+AADU0tPTY2xs/OrVq0G3Xrhw4c9//rOKmwQAUCO4HwAAtdBotBUrVpDPBSRNnjzZ09NT9U0CAKgRxAEAUM6KFSu6u7v7rdTS0lq9erWmpqZamgQAUBd4LgAA5eA4bm5u3tDQ0G/99evXXV1d1dIkAIC6wP0AACgHw7BVq1b1ezQwderUOXPmqKtJAAB1gTgAACrq92hAS0srJCSEeHsQAEAp8FwAAIqys7N78OABuXj37l0HBwc1tgcAoBZwPwAAilq9ejX5aMDe3h6CAACoCeIAAChq1apVPT09CCEtLa2///3v6m4OAEA94LkAANQ1Z86cmzdvYhhWV1dnbm6u7uYAANQA7gcAQF1/+9vfEELvvvsuBAEAUBbkG5xo0tLSrly5ou5WgPGhq6sLw7A3b94EBgaquy1g3MjPz1d3E4Aywf2AiebKlStXr15VdyvGmVOnTg2cVIcKmEymsbGxmZlZQ0PDqVOn1N0cVaDs71opqHOdUAqMD5hoiC92ELAPC4Zhubm5y5cvV3dD1KCmpsba2jovLy8oKIgK/w2o/LseOepcJ5QC9wMAoDRra2t1NwEAoE4QBwAAAADUBXEAAAAAQF0QBwAAAADUBXEAAAAAQF0QBwAAFHT27Fkul/v999+ruyGjpaSkJDo6+vTp05aWlhiGYRi2evVqyQLe3t66urqampoODg63bt1SVzu7u7tTUlKsra3pdLqenp6jo2NdXd3AYl1dXXZ2dnFxccTimTNnUlNTe3t7VdpWMPZAHAAAUNDEfn9sx44dmZmZMTEx/v7+Dx8+tLKyMjAwOHr0aFFREVnm/Pnz+fn5vr6+VVVVs2fPVldTg4KCvvnmm2PHjgmFwvv371tZWXV0dAwsFhsbK5lh0s/Pj8lkenl5vX79WoWNBWMOxAEAAAX5+Pi0trb6+vqO9oFEIpG7u/toH0XS7t27T548mZeXp6urS67MzMzU0NAIDQ1tbW1VZWOkO3nyZEFBQX5+/rvvvkuj0UxMTAoLCx0dHfsVu3z58t27d/ut3LRp06xZsxYtWkRknALUBHEAAGCsy87OFggEKjtcTU3Ntm3bEhISmEym5Hp3d3cej/f06dPNmzerrDEyffXVV7Nnz3ZycpJSRiQSbdmyJSMjY+Cm+Pj4ioqKQTcBioA4AACgiLKyMnNzcwzD9u/fjxDi8/lsNpvFYhUWFi5cuJDD4ZiZmZ04cYIonJmZyWQyjYyMPv30UxMTEyaT6e7ufu3aNWJrWFgYnU6fMmUKsbhx40Y2m41hWHNzM0KIx+NFRkbW1tZiGEbMenTu3DkOh5OcnDxKp5aZmYnjuJ+f38BNO3futLGxOXz4cElJyaD74jielpY2c+ZMBoOhr6+/ZMmS3377jdgkvYsQQr29vdu3bzc3N9fW1nZ2ds7NzZXZVLFYfPXqVRcXF+nFYmNjN27caGhoOHCTvr6+p6dnRkbGxH7KA6SAOAAAoIh58+ZdvnyZXNywYUN4eLhIJNLV1c3Nza2trbW0tFy3bl13dzdCKCwsLCQkRCgUbtq0qa6u7tatWz09Pe+///6TJ08QQpmZmZIT/WZlZSUkJJCLGRkZvr6+VlZWOI7X1NQghIihbX19faN0akVFRba2tiwWa+AmbW3tr7/+WkNDY926dZ2dnQMLxMfHR0dHx8bGCgSCn3/++cmTJx4eHo2NjUhWFyGEtm7d+sUXX6Snpz9//tzX13flypW//vqr9KY+e/ZMLBbfvHlzwYIFRIA1c+bMrKwsyQ/1X375pba2duXKlUNV8tZbbz19+vT27dvydA6YeCAOAAAok7u7O4fDMTQ0DA4O7uzsfPz4MbmJRqMRX5Tt7e35fH57e3tOTo4Ch/Dx8Wlra9u2bZvyWv2/Ojs7Hz16ZGVlNVQBNze38PDwurq6rVu39tskEonS0tKWLVu2atUqLpfr5OR04MCB5ubmgwcPShYbtIu6urr4fP7SpUv9/f319PTi4uK0tLRk9g8xHtDQ0DA5ObmqqqqxsXHJkiWfffbZ8ePHySbxeDw+ny+lkhkzZiCEKisrpR8LTFQQBwAARgWdTkcIkV92+5kzZw6LxSLvmY8dAoEAx/FBbwaQdu7caWtrm5WVVVZWJrm+qqqqo6Njzpw55BpXV1c6nU4+AelHsosePHggFArJ8X3a2tpTpkyR2T8MBgMh5ODg4O7uPmnSJC6Xm5CQwOVyycgjJibmk08+MTU1lVIJcbLETQtAQRAHAADUg8FgNDU1qbsV/XV1daE/Pl+HwmQyc3JyMAxbs2aNSCQi1xMv4Ono6EgW1tPTa29vl3lc4ilDXFwc9of6+nqhUCh9LxMTE4QQMZCCQKfTLSwsamtrEUJlZWWVlZVr166VXom2tjb648QBBUEcAABQg+7u7tevX5uZmam7If0RH4oyZ9dxc3OLiIiorq5OSkoiV+rp6SGE+n3qy3maxCC+9PR0XMKVK1ek76WjozNjxox79+5Jruzp6eFyuQih7OzsCxcuaGhoEIEFcYjk5GQMwyRHHojFYvLEAQVBHAAAUIPS0lIcx+fOnUss0mi0oZ4gqJiRkRGGYfLMEJCUlGRnZ1deXk6ucXR01NHRkfyIvXbtmlgsfvvtt2XWNnXqVCaTWVFRMdwGBwUFlZeXP3z4kFgUCoX19fXEa4Q5OTmSUQVx9yU2NhbHccmHF8TJGhsbD/fQYGKAOAAAoCJ9fX0tLS09PT137tzh8Xjm5uYhISHEJmtr61evXhUUFHR3dzc1NdXX10vuOGnSpGfPntXV1bW3t3d3dxcXF4/ee4MsFsvS0rKhoUFmSeLpgKampuSayMjIb7/99ujRo21tbZWVlevXrzcxMQkNDZWnto8//vjEiRN8Pr+tra23t7ehoeH58+cIoeDgYGNj46HmLY6IiLCwsAgJCXn8+PHLly+joqJEItHAMYxSECcrfQYCMIFBHAAAUMT+/ftdXV0RQlFRUYsXL+bz+enp6QghZ2fnhw8fHjp0KDIyEiH0wQcfVFdXE7t0dXU5OTlpa2t7eHjY2NhcvHiRfAy/YcOGBQsWrFixwtbWNikpibhH7ebmRrxYuH79eiMjI3t7+0WLFr169Wq0T83Hx6eqqop88P/dd99ZW1vX1ta6urp+/vnnkiXnzp0bEREhuWbHjh0pKSmJiYmTJ0/29PScNm1aaWkpm81GCMnsooyMjPDw8NTUVAMDAxMTEx6P19LSghASi8UCgaCwsHDQ1urr61+6dMnMzMzFxcXU1PT69etFRUUyZxSQdOPGDVNTU2dnZ/l3ARMKDiaWgICAgIAAdbdinEEI5ebmqrsV6kRMWTOqhwgNDZ00adKoHkIe8vyuq6uraTTakSNHVNMkmXp7ez08PLKzs0ej8ubmZiaTuXfvXnkKq+A6AaoH9wMAACoyXlLbWVtbJyYmJiYmDpqtR8V6e3sLCgra29uDg4NHo/74+HgXF5ewsLDRqByMCxAHAABAf9HR0YGBgcHBwWpPKVRaWnr69Oni4mLpUxooJi0traKi4uzZs1paWkqvHIwXEAcAtHbtWl1dXQzDFBirPKakpqba2dlpa2uz2Ww7O7tt27a1tbUppWbJDPQEOp1uZGQ0f/78PXv2EA9xgRQxMTE5OTmtra3Tp08/deqUupsjl+Tk5LCwsF27dqm3GV5eXseOHSOTLyhRYWHhmzdvSktL9fX1lV45GEcgDgDo8OHDhw4dUncrlODSpUvr1q17/PhxY2NjUlJSampqQECAUmomM9BzuVwcx/v6+gQCQV5e3vTp06OiohwcHGTOA09xKSkpb968wXH80aNHyvqlqIC3t/fu3bvV3YrRsnjx4ujoaMn3HQA1QRwAxrRhJZ6n0+lEUjUdHZ3AwMAlS5b8z//8D/HmlXJhGKanpzd//vycnJy8vLzGxkYfHx+130AeaFi9BwCgJogDAEIIYRim7iYMbliJ57/99lvJhPHEnOqjPdQrICAgJCREIBAcOHBgVA+kgGH1HgCAmiAOoCgcx/fs2WNra8tgMLhc7pYtW8hNX3zxBYvF0tXVFQgEkZGRpqamDx48wIfOqi49tTySmpF9uInnh6W6ulpPT8/CwkLhXpITMRlOcXExmkC9BwCgCjW+swhGg5zzB8TGxmIY9uWXX7a0tAiFwqysLIRQeXk5uRUhtGnTpn379i1btuz+/fvbt2+n0+lHjhx5/fr1nTt3Zs+ePXny5BcvXhDlQ0ND2Wz2vXv3urq6qqqqXF1ddXV1Hz9+TGyVvu9HH31kbGxMNmzPnj0IoaamJmLR39+fSDwvP7FY3NDQsG/fPgaDIecr4Ei++QPI8QH9EKMRp06dSiyOx96jznvhcv6uwaCoc51QCvxGJxp54gChUMhisd5//31yzYkTJwbGASKRiCyvo6MTHBxMlr9+/TpCKDExkVgMDQ2V/IC8ceMGQighIUGefZUeBxDTpBsYGPzrX/8Si8Xy7DLCOADHcWLEAPHzeOw96vx/hzhgJKhznVAKTVX3HcAYUlNTIxQKvby85Cw/3Kzqkqnlh7vvyD158uT169fl5eXR0dEHDx788ccfjYyMRulYhM7OThzHORzOoFvHUe+N2WEiyhUUFBQUFKTuVgAwVkAcQEVEWhEiCak8FMiqTqaWH0lGdsVoaWkZGhp6e3tPnz7dxsYmJSUlIyNjlI5F+P333xFCdnZ2g24dR71HfNub2IKCgng8npubm7obMi5duXJltP+agOpBHEBFxKD6N2/eyFl+uFnVJVPLjyQj+whZW1trampWVVWN9oHOnTuHEFq4cOGgW8dR7y1fvnw0qh1TgoKC3NzcqHCmowTigIkH3hegIkdHRw0NjZ9++kn+8sPKqi6ZWl7mvspKPP/y5cuVK1dKrqmuru7t7Z06derIK5fixYsX6enpZmZma9asGbTAuOg9AABlQRxARYaGhv7+/qdOncrOzm5ra7tz587BgwellJcnq/pQqeVl7jusxPNSGslms8+fP//jjz+2tbV1d3eXl5f//e9/Z7PZ/dLCjhCO4x0dHX19fTiONzU15ebmvvfee5qamgUFBUONDxgXvQcAoC61jlIEyifne4Pt7e1r1641MDDQ0dGZN2/e9u3bEUJmZma3b99OTU0lsr9PnTqVfO+ur69vz549M2bM0NLS0tfXX7p0KfFaPCE0NFRLS8vU1JRGo3E4nCVLltTW1pJbpe/78uXLBQsWMJnM6dOnf/7558RMBtbW1sSLc7du3bKwsNDW1p43bx75stxQ/Pz8pk+frqOjw2AwrKysgoODKysr5ek0JGsM+ZkzZ5ydnVksFp1O19DQQH9MKfjOO+8kJia+fPmSLDlOe48648Bl/q6BFNS5TigFw3FcXSEIGA2BgYEIofz8fFUe9NNPP83Pz3/58qUqD6pEGIbl5uaq65nxWOi9vLy8oKAgKvw3UO/veryjznVCKfBcACjHeEktPzZB7wEA1AXiADA+/Pbbb9jQgoOD1d1AMAGVlJRER0dLZp1evXq1ZAFvb29dXV1NTU0HB4dbt26pq53d3d0pKSnW1tZ0Ol1PT8/R0bGurm5gsa6uLjs7u7i4OGLxzJkzqampEIMCiAPASKkmtbydnZ2U51snT54cpeOONtX0HlDAjh07MjMzY2JiyKzTBgYGR48eLSoqIsucP38+Pz/f19e3qqpq9uzZ6mpqUFDQN998c+zYMaFQeP/+fSsrq0HTa8XGxj548IBc9PPzYzKZXl5exDQVgLIgDgAjNU5Ty48R1Ok9JSZBVkE+5d27d588eTIvL09XV5dcmZmZqaGhERoaOqZyTJ88ebKgoCA/P//dd9+l0WgmJiaFhYWOjo79il2+fPnu3bv9Vm7atGnWrFmLFi3q6elRVXvBmANxAABAFZSYBHm08ynX1NRs27YtISFBMo01Qsjd3Z3H4z19+nTz5s2jd/Th+uqrr2bPnu3k5CSljEgk2rJly6BTAMXHx1dUVMDsQFQGcQAAQF64kpIgS8+2PNx8yufOneNwOMnJyco6zczMTBzH/fz8Bm7auXOnjY3N4cOHS0pKhttFfD6fzWazWKzCwsKFCxdyOBwzMzMixReht7d3+/bt5ubm2trazs7O8kzzLBaLr1696uLiIr1YbGzsxo0bB51KXF9f39PTMyMjA94CoK7RfjERqJic8wcASYjy75TL+V64EpMgS8+2PKyqfvjhB11dXTIHo3Ty/K4tLS3t7e37rbSysnr06BGO45cvX9bQ0Jg2bVpHRweO48XFxYsXLyaLSe8iIhflhQsXWltbBQKBh4cHm80ms2Ju3ryZwWCcOnWqpaUlJiZGQ0Pjxo0b0pv66NEjhJCLi8v8+fOnTJnCYDDs7Oz2799PTHVFKCsr8/Pzw3GcSFoRGxvbr5Lo6GgkkW5UCpg/YEKC+wEAALmIRKK0tLRly5atWrWKy+U6OTkdOHCgublZ+mSUUtBoNOJ7s729PZ/Pb29vz8nJUaAeHx+ftra2bdu2KdaMfjo7Ox89emRlZTVUATc3t/Dw8Lq6uq1bt/bbJGcXubu7czgcQ0PD4ODgzs7Ox48fI4S6urr4fP7SpUv9/f319PTi4uK0tLRkdggxHtDQ0DA5ObmqqqqxsXHJkiWfffbZ8ePHySbxeDw+ny+lkhkzZiCEKisrpR8LTFQQBwAA5DKqSZAlsy2rl0AgwHGcxWJJKbNz505bW9usrKyysjLJ9cPtIjqdjhAipnx+8OCBUCgkx/dpa2tPmTJFZocwGAyEkIODg7u7+6RJk7hcbkJCApfLJSOPmJiYTz75xNTUVEolxMk2NjZKPxaYqCAOAADIZbSTIJPZltWrq6sL/fH5OhQmk5mTk4Nh2Jo1a0QiEbl+JF3U2dmJEIqLiyNnxaivrxcKhdL3MjExQQgRIycIdDrdwsKitrYWIVRWVlZZWbl27VrplRAzYRMnDigI4gAAgFxGNQmyZLZl9SI+FGXOruPm5hYREVFdXZ2UlESuHEkXEYP40tPTJR/cXrlyRfpeOjo6M2bMuHfvnuTKnp4eLpeLEMrOzr5w4YKGhgYRWBCHSE5OxjBMMomlWCwmTxxQEMQBAAC5jGoSZMlsyyOsaoSMjIwwDJNnhoCkpCQ7O7vy8nJyzXBzTEuaOnUqk8msqKgYboODgoLKy8sfPnxILAqFwvr6euI1wpycHMmoQnKcoOTDC+JkjY2Nh3toMDFAHAAAkIvSkyAPlW15uFUVFxcr8b1BFotlaWnZ0NAgT4fk5ORoampKrpGZY1pKbR9//PGJEyf4fH5bW1tvb29DQ8Pz588RQsHBwcbGxkPNWxwREWFhYRESEvL48eOXL19GRUWJRKKBYxilIE5W+gwEYAKDOAAAIK8dO3akpKQkJiZOnjzZ09Nz2rRppaWlbDab2Lphw4YFCxasWLHC1tY2KSmJuM/s5ub25MkThND69euNjIzs7e0XLVr06tUrhFBXV5eTk5O2traHh4eNjc3FixfJp/LDrUq5fHx8qqqqyAf/3333nbW1dW1traur6+effy5Zcu7cuREREXJ2EZ/PT09PRwg5Ozs/fPjw0KFDkZGRCKEPPviguroaIZSRkREeHp6ammpgYGBiYsLj8VpaWhBCYrFYIBAUFhYO2lp9ff1Lly6ZmZm5uLiYmppev369qKhI5owCkm7cuGFqaurs7Cz/LmBCUd0rikAlYP4ABSCYP0Dl74WHhoZOmjRJlUckyPO7rq6uptFoR44cUU2TZOrt7fXw8MjOzh6Nypubm5lM5t69e+UpDPMHTEhwPwAAoB5jNtOdtbV1YmJiYmLioNl6VKy3t7egoKC9vX2UkmrGx8e7uLiEhYWNRuVgXIA4AAAA+ouOjg4MDAwODlZ7SqHS0tLTp08XFxdLn9JAMWlpaRUVFWfPntXS0lJ65WC8gDgAAKBq4yLbcnJyclhY2K5du9TbDC8vr2PHjpHZFpSosLDwzZs3paWl+vr6Sq8cjCM0dTcAAEA5KSkpKSkp6m6FbN7e3t7e3upuxWhZvHjx4sWL1d0KoH5wPwAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCcYITUENDQ15enrpbMc7ITOgysRGnT5HLhuK/65GArpuQMBzH1d0GoEyBgYFj9kUsAMAEAJ8aEwzEAQBQGoZhubm5y5cvV3dDAADqAeMDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAAAAAOrCcBxXdxsAAKoTGhr64MEDcvHWrVvTp0/X19cnFjU1Nf/zn/+YmZmpqXUAAFWjqbsBAACVMjY2PnjwoOSaO3fukD9bWlpCEAAApcBzAQCoZeXKlUNtotPpISEhKmwLAED94LkAAJTj6Oh47969Qf/2Hzx4YGNjo/omAQDUBe4HAEA5f/vb3zQ1NfutxDBs1qxZEAQAQDUQBwBAOStWrOjt7e23UlNT8+9//7ta2gMAUCN4LgAAFbm7u1+7dq2vr49cg2HYkydPTE1N1dgqAIDqwf0AAKho9erVGIaRixoaGvPmzYMgAAAKgjgAACoKDAyUXMQw7G9/+5u6GgMAUCOIAwCgosmTJ3t5eZGjBTEMW7p0qXqbBABQC4gDAKCoVatWEcODNDU1//rXvxoYGKi7RQAANYA4AACKWrZsGZ1ORwjhOL5q1Sp1NwcAoB4QBwBAUWw2+8MPP0QI0el0X19fdTcHAKAeEAcAQF0fffQRQmjp0qVsNlvdbQEAqAfMHwBkyMvLCwoKUncrAACKCAgIyM/PV3crwJgG+QaBXHJzc9XdhBEJCgri8Xhubm7qbohypKenI4TCw8NHXtXRo0eDg4NptLH4r+DKlSsZGRnj/dpTI+I6AUC6sfjHD8ag5cuXq7sJIxIUFOTm5jbez4JEfMNTyun4+fkxmcyR1zNKMjIyJsxvTfXgTgCQB4wPAIDSxnIQAABQAYgDAAAAAOqCOAAAAACgLogDAAAAAOqCOAAAAACgLogDAKCKs2fPcrnc77//Xt0NGS0lJSXR0dGnT5+2tLTEMAzDsNWrV0sW8Pb21tXV1dTUdHBwuHXrlrra2d3dnZKSYm1tTafT9fT0HB0d6+rqBhbr6uqys7OLi4sjFs+cOZOamtrb26vStgIKgDgAAKqY2JOG7dixIzMzMyYmxt/f/+HDh1ZWVgYGBkePHi0qKiLLnD9/Pj8/39fXt6qqavbs2epqalBQ0DfffHPs2DGhUHj//n0rK6uOjo6BxWJjYx88eEAuEm94enl5vX79WoWNBRMfxAEAUIWPj09ra6sKUgmIRCJ3d/fRPoqk3bt3nzx5Mi8vT1dXl1yZmZmpoaERGhra2tqqysZId/LkyYKCgvz8/HfffZdGo5mYmBQWFjo6OvYrdvny5bt37/ZbuWnTplmzZi1atKinp0dV7QUTH8QBAAAly87OFggEKjtcTU3Ntm3bEhIS+s2F4O7uzuPxnj59unnzZpU1Rqavvvpq9uzZTk5OUsqIRKItW7ZkZGQM3BQfH19RUTHoJgAUA3EAAJRQVlZmbm6OYdj+/fsRQnw+n81ms1iswsLChQsXcjgcMzOzEydOEIUzMzOZTKaRkdGnn35qYmLCZDLd3d2vXbtGbA0LC6PT6VOmTCEWN27cyGazMQxrbm5GCPF4vMjIyNraWgzDrK2tEULnzp3jcDjJycmjdGqZmZk4jvv5+Q3ctHPnThsbm8OHD5eUlAy6L47jaWlpM2fOZDAY+vr6S5Ys+e2334hN0rsIIdTb27t9+3Zzc3NtbW1nZ2d55j8Wi8VXr151cXGRXiw2Nnbjxo2GhoYDN+nr63t6emZkZEzspzxAlSAOAIAS5s2bd/nyZXJxw4YN4eHhIpFIV1c3Nze3trbW0tJy3bp13d3dCKGwsLCQkBChULhp06a6urpbt2719PS8//77T548QQhlZmZKzvWblZWVkJBALmZkZPj6+lpZWeE4XlNTgxAihrb19fWN0qkVFRXZ2tqyWKyBm7S1tb/++msNDY1169Z1dnYOLBAfHx8dHR0bGysQCH7++ecnT554eHg0NjYiWV2EENq6desXX3yRnp7+/PlzX1/flStX/vrrr9Kb+uzZM7FYfPPmzQULFhAB1syZM7OysiQ/1H/55Zfa2tqVK1cOVclbb7319OnT27dvy9M5AMgEcQAAlObu7s7hcAwNDYODgzs7Ox8/fkxuotFoxBdle3t7Pp/f3t6ek5OjwCF8fHza2tq2bdumvFb/r87OzkePHllZWQ1VwM3NLTw8vK6ubuvWrf02iUSitLS0ZcuWrVq1isvlOjk5HThwoLm5+eDBg5LFBu2irq4uPp+/dOlSf39/PT29uLg4LS0tmf1DjAc0NDRMTk6uqqpqbGxcsmTJZ599dvz4cbJJPB6Pz+dLqWTGjBkIocrKSunHAkBOEAcAABBCiE6nI4TIL7v9zJkzh8VikffM094QCwAAEfhJREFUxw6BQIDj+KA3A0g7d+60tbXNysoqKyuTXF9VVdXR0TFnzhxyjaurK51OJ5+A9CPZRQ8ePBAKheT4Pm1t7SlTpsjsHwaDgRBycHBwd3efNGkSl8tNSEjgcrlk5BETE/PJJ5+YmppKqYQ4WeKmBQAjB3EAAEAuDAajqalJ3a3or6urC/3x+ToUJpOZk5ODYdiaNWtEIhG5nngBT0dHR7Kwnp5ee3u7zOMSTxni4uKwP9TX1wuFQul7mZiYIISIgRQEOp1uYWFRW1uLECorK6usrFy7dq30SrS1tdEfJw7AyEEcAACQrbu7+/Xr12ZmZupuSH/Eh6LM2XXc3NwiIiKqq6uTkpLIlXp6egihfp/6cp4mMYgvPT0dl3DlyhXpe+no6MyYMePevXuSK3t6erhcLkIoOzv7woULGhoaRGBBHCI5ORnDMMmRB2KxmDxxAEYO4gAAgGylpaU4js+dO5dYpNFoQz1BUDEjIyMMw+SZISApKcnOzq68vJxc4+joqKOjI/kRe+3aNbFY/Pbbb8usberUqUwms6KiYrgNDgoKKi8vf/jwIbEoFArr6+uJ1whzcnIkowri7ktsbCyO45IPL4iTNTY2Hu6hARgUxAEAgMH19fW1tLT09PTcuXOHx+OZm5uHhIQQm6ytrV+9elVQUNDd3d3U1FRfXy+546RJk549e1ZXV9fe3t7d3V1cXDx67w2yWCxLS8uGhgaZJYmnA5qampJrIiMjv/3226NHj7a1tVVWVq5fv97ExCQ0NFSe2j7++OMTJ07w+fy2trbe3t6Ghobnz58jhIKDg42NjYeatzgiIsLCwiIkJOTx48cvX76MiooSiUQDxzBKQZys9BkIAJAfxAEAUML+/ftdXV0RQlFRUYsXL+bz+enp6QghZ2fnhw8fHjp0KDIyEiH0wQcfVFdXE7t0dXU5OTlpa2t7eHjY2NhcvHiRfAy/YcOGBQsWrFixwtbWNikpibhH7ebmRrxYuH79eiMjI3t7+0WLFr169Wq0T83Hx6eqqop88P/dd99ZW1vX1ta6urp+/vnnkiXnzp0bEREhuWbHjh0pKSmJiYmTJ0/29PScNm1aaWkpm81GCMnsooyMjPDw8NTUVAMDAxMTEx6P19LSghASi8UCgaCwsHDQ1urr61+6dMnMzMzFxcXU1PT69etFRUUyZxSQdOPGDVNTU2dnZ/l3AUAaHACpiNlR1N2KkUII5ebmqrsVShMQEBAQEDCqhwgNDZ00adKoHkImOa+96upqGo125MgRFTRJHr29vR4eHtnZ2aNReXNzM5PJ3Lt3rzyFVXCdgAkA7gcAAAY3XlLbWVtbJyYmJiYmDpqtR8V6e3sLCgra29uDg4NHo/74+HgXF5ewsLDRqBxQE8QBQPnWrl2rq6uLYZgCo6jURTJZLYFOpxsZGc2fP3/Pnj3E/V4wZkVHRwcGBgYHB6s9pVBpaenp06eLi4ulT2mgmLS0tIqKirNnz2ppaSm9ckBZEAcA5Tt8+PChQ4fU3YrhIZPVcrlcHMf7+voEAkFeXt706dOjoqIcHBxkThk7kcTExOTk5LS2tk6fPv3UqVPqbo5ckpOTw8LCdu3apd5meHl5HTt2jEy+oESFhYVv3rwpLS3V19dXeuWAymjqbgAAYxGGYXp6evPnz58/f76Pj09QUJCPj8/vv/9OvOc94aWkpKSkpKi7FcPm7e3t7e2t7laMlsWLFy9evFjdrQATENwPAKMCwzB1N0FpAgICQkJCBALBgQMH1N0WAABQMogDgHLgOL5nzx5bW1sGg8Hlcrds2SK5ddAMrTLzuv7000/vvPMOi8XicDhOTk5tbW1DVTXaiPfmi4uLJ8bpAADA/1L3CwtgrJPz3a3Y2FgMw7788suWlhahUJiVlYUQKi8vJ7Zu3ryZwWCcOnWqpaUlJiZGQ0Pjxo0bxF4IoQsXLrS2tgoEAg8PDzabLRaLcRzv6OjgcDipqakikejFixfLli1ramqSUpV0SL73BsnxAf0Qn9lTp04dI6dDkffBJsY7q2pEkesEjBD8jQEZ5PlfLBQKWSzW+++/T64hvgcTcYBIJGKxWMHBwWRhBoOxYcMG/I8PTpFIRGwiooeamhocx+/evYsQ+uGHHyQPJKUq6UYYB+A4TowYGCOnQ5H/7xAHjBBFrhMwQjBOEChBTU2NUCj08vIadKv8GVol87paWloaGRmtWrVq06ZNISEh06ZNG1ZVytXZ2YnjOIfDGTun09DQkJeXp4RzG8OItD0T/jRHT0NDwxhMDQXGHHUHImCsk+c72dmzZxFCkhOoSd4P+OWXXwZeeHPnzsUHfIEm3ja8f/8+sXj37t0PP/yQRqNhGBYUFCQUCqVUJR0a2f0AYq54b2/vMXI6AQEBCv/JA0qB+wFAJhgnCJSAyWQihN68eTPoVsUytCKEHBwcvv/++2fPnkVFReXm5u7du1fhqkbo3LlzCKGFCxeiMXM6VPj/Ds8FRgjiRSAPiAOAEjg6OmpoaPz000+DblUsQ+uzZ8+INO2Ghoa7du2aPXv2vXv3FE72OhIvXrxIT083MzNbs2YNGv+nAwAAkiAOAEpgaGjo7+9/6tSp7Ozstra2O3fuHDx4kNwqJUOrFM+ePfv0009/++03sVhcXl5eX18/d+5cxaoaFhzHOzo6+vr6cBxvamrKzc197733NDU1CwoKiPEB4+t0AABABnXfuAJjnZz3Ztvb29euXWtgYKCjozNv3rzt27cjhMzMzG7fvo3j+Js3b6KioszNzWk0GhE0VFVVZWVlEXOwz5gxo7a29uDBg8QHrYWFxe+//15XV+fu7q6vr6+pqfmnP/0pNja2p6dnqKpkNg/JGh9w5swZZ2dnFotFp9M1NDTQH1MKvvPOO4mJiS9fvpQsrPbTocg4cHguMEIUuU7ACGE4jqstBgHjQV5eXlBQ0Hi/TjAMy83NXb58ubobohyBgYEIofz8fHU3ZHRNjGtPjShynYARgucCAAAAAHVBHAAAAABQF8QBAIAJoqSkJDo6+vTp05aWlhiGYRi2evVqyQLe3t66urqampoODg7EnBDq0tfXl56e7u7uPnBTWVnZe++9x2KxTExMoqKiyNdxz5w5k5qa2tvbq9qWgokP4gAAwESwY8eOzMzMmJgYf3//hw8fWllZGRgYHD16tKioiCxz/vz5/Px8X1/fqqqq2bNnq6up1dXV/+///b+IiAihUNhvU1VVlbe3t5eXV1NT07fffvvvf/97/fr1xCY/Pz8mk+nl5fX69WuVNxlMZBAHAAAGIRKJBv22qt6qhrJ79+6TJ0/m5eXp6uqSKzMzMzU0NEJDQ1tbW0f16MNy+/btrVu3rl+/3sXFZeDWpKSkKVOmJCQksNlsNze3qKior7/+mpxqetOmTbNmzVq0aFFPT49qWw0mMogDAACDyM7OFggEY62qQdXU1Gzbti0hIYGY15Lk7u7O4/GePn26efPm0Tv6cM2aNev06dMfffQRg8Hot6mnp6eoqMjT0xPDMGLNwoULcRwvLCwky8THx1dUVGRkZKiuxWCigzgAgAkLx/G0tLSZM2cyGAx9ff0lS5aQ3yzDwsLodPqUKVOIxY0bN7LZbAzDmpubEUI8Hi8yMrK2thbDMGtr68zMTCaTaWRk9Omnn5qYmDCZTHd392vXrilQFULo3LlzHA4nOTlZWaeZmZmJ47ifn9/ATTt37rSxsTl8+HBJSclwu4jP57PZbBaLVVhYuHDhQg6HY2ZmRiTOIPT29m7fvt3c3FxbW9vZ2ZmY7WAkHj582NHRYW5uTq6xsrJCCN25c4dco6+v7+npmZGRAa9TAmWBOACACSs+Pj46Ojo2NlYgEPz8889Pnjzx8PBobGxECGVmZkrOppCVlZWQkEAuZmRk+Pr6WllZ4TheU1MTFhYWEhIiFAo3bdpUV1d369atnp6e999//8mTJ8OtCiFEjHTr6+tT1mkWFRXZ2toSkzj1o62t/fXXX2toaKxbt66zs3NgASldtGHDhvDwcJFIpKurm5ubW1tba2lpuW7dOiKBJEJo69atX3zxRXp6+vPnz319fVeuXPnrr7+O5ERevHiBEJJ8tMFkMrW1tYn2kN56662nT5/evn17JMcCgARxAAATk0gkSktLW7Zs2apVq7hcrpOT04EDB5qbmyWnfB4WGo1GfG+2t7fn8/nt7e05OTkK1OPj49PW1rZt2zbFmtFPZ2fno0ePiO/Ng3JzcwsPD6+rq9u6dWu/TXJ2kbu7O4fDMTQ0DA4O7uzsfPz4MUKoq6uLz+cvXbrU399fT08vLi5OS0tLsQ4hEa8GaGpqSq7U0tISiUSSa2bMmIEQqqysHMmxACBBHADAxFRVVdXR0TFnzhxyjaurK51OJ+/nj8ScOXNYLBZ5C12NBAIBjuOD3gwg7dy509bWNisrq6ysTHL9cLuITqcjhIj7AQ8ePBAKhY6OjsQmbW3tKVOmjLBDiPEN/cYAisVibW1tyTXEyfa7SQCAwiAOAGBiIt4u09HRkVypp6fX3t6ulPoZDEZTU5NSqhqJrq4uojFSyjCZzJycHAzD1qxZI/ndeiRdRDxliIuLw/5QX18/8D3AYSHGWLS1tZFrhEJhV1eXiYmJZDEiLCBOHICRgzgAgIlJT08PIdTvI+3169dmZmYjr7y7u1tZVY0Q8aEoc3YdNze3iIiI6urqpKQkcuVIusjQ0BAhlJ6eLpmv5cqVKwqcAmn69Om6urr19fXkGmJEhbOzs2QxsViM/jhxAEYO4gAAJiZHR0cdHR3JkWvXrl0Ti8Vvv/02sUij0cghb8NVWlqK4/jcuXNHXtUIGRkZYRgmzwwBSUlJdnZ25eXl5BqZXSTF1KlTmUxmRUWFYs0eFI1GW7Ro0c8//0wOoiwuLsYwrN+rEMTJGhsbK/HQgMogDgBgYmIymZGRkf+/vbsHSeeP4wD+/cEdWZCgFCWCYihNQVNDD0MELg2XhHCjTRLU0XJEQQ9I2WDYVEMQDhURldiiq07nFFE0VAgR0gM9kVYkdd5vECR+9M/Dv3bWvV+b+OXj+74e+tF7+AaDwbW1tVQqdXh4ODg4aDAY3G53boDVar2/vw+FQm9vbzc3Nx9/hhJC9Hr9xcXF2dlZOp3Ofcdns9mHh4f39/eDg4ORkRGTyeRyuYooFYlESnjdYE1NTVNTUzKZlDMhgUDg41l4Bafo62oDAwMbGxtLS0upVEoUxWQyeXl5SQhhWbahoaG4+xZPTExcX19PTU09Pz8LguDz+VwuV3Nz88cxuY1taWkpoj7AJ75zkWP4iX7HGvCEkM3NTaVTlIzMdeWz2azP57PZbDRN63Q6h8NxfHycf/bu7q67u1uj0VgsluHhYZ7nCSFWq/X8/FySpL29PbPZXF1d3dnZeXV15Xa7aZo2Go0URWm12r6+vkQiUVypcDhcW1s7MzNTML/MfY/jOJqmX15ecg+DwWDu8oG6urqhoaF/BvM8zzCMnClaXFzMnZFns9kSicTy8rJWqyWEmM3mk5MTSZIymczo6KjJZKIoqr6+vr+//+joSJIkh8NBCJmcnPw0rSAIHR0d+UP+jY2N7e3tsVgsPyAWi7W1tVVVVRkMBp7nX19f/6nQ29trNBqz2WzBmZG5n4DK/fjPdyg39AEV6Ps/391ut16v/85XlGTve6enpxRFra6ufkMkOURR7OrqWllZKUfx29tbjUYzPz8vZzD6AJADxwUAQJaKXenOarV6PB6Px/P09KR0FiKKYigUSqfTLMuWo/709HRrayvHceUoDuqEPgAAfryxsTGn08myrOJLCkWj0Z2dnUgk8vUtDYrj9/v39/fD4TBN0yUvDqqFPgAAChgfHw8EAo+PjxaLZXt7W+k4n5udneU4bm5uTtkYPT096+vr+dUWSmh3dzeTyUSjUZ1OV/LioGaU0gEAoNJ5vV6v16t0isLsdrvdblc6RbkwDMMwjNIp4BfC/wEAAADqhT4AAABAvdAHAAAAqBf6AAAAAPXCeYIgi9PpVDrC/7WwsLC1taV0itKIx+PkV7wpX8vdQPfXb2b5xOPx/BoQAP/ljyRJSmeAiiYIgt/vVzoFABQjt9Ci0imgoqEPAAAAUC+cHwAAAKBe6AMAAADUC30AAACAeqEPAAAAUK+/SEPUCTMyGBQAAAAASUVORK5CYII=\n","text/plain":[""]},"metadata":{},"execution_count":17}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"287Am2coqkQC","executionInfo":{"status":"ok","timestamp":1638748150465,"user_tz":480,"elapsed":277815,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"85c947d2-d4d2-47ea-c278-5487002ddf45"},"source":["epochs = 30\n","\n","callbacks = [\n"," keras.callbacks.ModelCheckpoint(\"checkpoints/save_at_{epoch}.h5\"),\n","]\n","model.compile(\n"," optimizer=keras.optimizers.Adam(1e-3),\n"," loss=\"binary_crossentropy\",\n"," metrics=[\"accuracy\"],\n",")\n","model.fit(\n"," train_ds, epochs=epochs, callbacks=callbacks, validation_data=validation_ds,\n",")"],"execution_count":18,"outputs":[{"output_type":"stream","name":"stdout","text":["Epoch 1/30\n","275/275 [==============================] - 9s 29ms/step - loss: 0.3763 - accuracy: 0.1932 - val_loss: 0.3480 - val_accuracy: 0.0800\n","Epoch 2/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.2665 - accuracy: 0.4103 - val_loss: 0.2391 - val_accuracy: 0.5800\n","Epoch 3/30\n","275/275 [==============================] - 8s 27ms/step - loss: 0.2268 - accuracy: 0.5433 - val_loss: 0.1719 - val_accuracy: 0.8400\n","Epoch 4/30\n","275/275 [==============================] - 7s 27ms/step - loss: 0.1998 - accuracy: 0.6261 - val_loss: 0.1379 - val_accuracy: 0.9000\n","Epoch 5/30\n","275/275 [==============================] - 7s 27ms/step - loss: 0.1794 - accuracy: 0.6794 - val_loss: 0.1251 - val_accuracy: 0.9300\n","Epoch 6/30\n","275/275 [==============================] - 8s 27ms/step - loss: 0.1657 - accuracy: 0.7163 - val_loss: 0.1016 - val_accuracy: 0.9200\n","Epoch 7/30\n","275/275 [==============================] - 7s 27ms/step - loss: 0.1532 - accuracy: 0.7484 - val_loss: 0.0936 - val_accuracy: 0.9600\n","Epoch 8/30\n","275/275 [==============================] - 8s 27ms/step - loss: 0.1436 - accuracy: 0.7665 - val_loss: 0.0766 - val_accuracy: 0.9700\n","Epoch 9/30\n","275/275 [==============================] - 8s 29ms/step - loss: 0.1361 - accuracy: 0.7812 - val_loss: 0.0657 - val_accuracy: 0.9800\n","Epoch 10/30\n","275/275 [==============================] - 9s 32ms/step - loss: 0.1270 - accuracy: 0.8081 - val_loss: 0.0548 - val_accuracy: 0.9700\n","Epoch 11/30\n","275/275 [==============================] - 8s 30ms/step - loss: 0.1230 - accuracy: 0.8209 - val_loss: 0.0554 - val_accuracy: 0.9900\n","Epoch 12/30\n","275/275 [==============================] - 8s 29ms/step - loss: 0.1163 - accuracy: 0.8323 - val_loss: 0.0468 - val_accuracy: 0.9700\n","Epoch 13/30\n","275/275 [==============================] - 8s 30ms/step - loss: 0.1110 - accuracy: 0.8399 - val_loss: 0.0465 - val_accuracy: 0.9900\n","Epoch 14/30\n","275/275 [==============================] - 8s 29ms/step - loss: 0.1089 - accuracy: 0.8405 - val_loss: 0.0511 - val_accuracy: 0.9800\n","Epoch 15/30\n","275/275 [==============================] - 8s 29ms/step - loss: 0.1047 - accuracy: 0.8505 - val_loss: 0.0376 - val_accuracy: 0.9800\n","Epoch 16/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.1047 - accuracy: 0.8523 - val_loss: 0.0360 - val_accuracy: 0.9800\n","Epoch 17/30\n","275/275 [==============================] - 8s 29ms/step - loss: 0.0993 - accuracy: 0.8637 - val_loss: 0.0337 - val_accuracy: 0.9800\n","Epoch 18/30\n","275/275 [==============================] - 8s 30ms/step - loss: 0.0972 - accuracy: 0.8669 - val_loss: 0.0301 - val_accuracy: 0.9900\n","Epoch 19/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0963 - accuracy: 0.8686 - val_loss: 0.0334 - val_accuracy: 0.9800\n","Epoch 20/30\n","275/275 [==============================] - 8s 29ms/step - loss: 0.0929 - accuracy: 0.8790 - val_loss: 0.0333 - val_accuracy: 0.9800\n","Epoch 21/30\n","275/275 [==============================] - 9s 31ms/step - loss: 0.0913 - accuracy: 0.8805 - val_loss: 0.0323 - val_accuracy: 0.9700\n","Epoch 22/30\n","275/275 [==============================] - 9s 30ms/step - loss: 0.0912 - accuracy: 0.8773 - val_loss: 0.0335 - val_accuracy: 0.9800\n","Epoch 23/30\n","275/275 [==============================] - 8s 30ms/step - loss: 0.0863 - accuracy: 0.8865 - val_loss: 0.0326 - val_accuracy: 0.9800\n","Epoch 24/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0850 - accuracy: 0.8884 - val_loss: 0.0216 - val_accuracy: 0.9900\n","Epoch 25/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0842 - accuracy: 0.8940 - val_loss: 0.0212 - val_accuracy: 0.9800\n","Epoch 26/30\n","275/275 [==============================] - 8s 27ms/step - loss: 0.0835 - accuracy: 0.8914 - val_loss: 0.0194 - val_accuracy: 0.9900\n","Epoch 27/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0818 - accuracy: 0.8917 - val_loss: 0.0214 - val_accuracy: 0.9700\n","Epoch 28/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0811 - accuracy: 0.8917 - val_loss: 0.0214 - val_accuracy: 0.9700\n","Epoch 29/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0794 - accuracy: 0.8950 - val_loss: 0.0201 - val_accuracy: 0.9800\n","Epoch 30/30\n","275/275 [==============================] - 8s 28ms/step - loss: 0.0790 - accuracy: 0.8947 - val_loss: 0.0267 - val_accuracy: 0.9700\n"]},{"output_type":"execute_result","data":{"text/plain":[""]},"metadata":{},"execution_count":18}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"ocE3kudZq24U","executionInfo":{"status":"ok","timestamp":1638748338964,"user_tz":480,"elapsed":367,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"cc43a234-3bd4-460d-ef82-806889fc9d38"},"source":["def predict_image(model, filename):\n"," img = keras.preprocessing.image.load_img(filename, target_size=(IMAGE_WIDTH, IMAGE_HEIGHT))\n"," img_array = keras.preprocessing.image.img_to_array(img)\n"," img_array = tf.expand_dims(img_array, 0) # Create batch axis\n"," predictions = model.predict(img_array).flatten()\n"," predicted_label_index = np.argmax(predictions)\n"," predicted_score = predictions[predicted_label_index]\n"," return (predicted_label_index, predicted_score)\n"," \n","index, score = predict_image(model, \"test/7/2.png\")\n","\n","print(index, score)\n"],"execution_count":19,"outputs":[{"output_type":"stream","name":"stdout","text":["7 0.9931043\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":83},"id":"MYyLaqOYtxTH","executionInfo":{"status":"ok","timestamp":1638748404260,"user_tz":480,"elapsed":54380,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"8c6b1cfc-e51a-461b-d8d6-4064a7f30e61"},"source":["from IPython.display import Image, display\n","\n","SCORE_THRESHOLD = 0.75\n","\n","correct_count = 0\n","wrong_count = 0\n","discarded_count = 0\n","for label_dir in glob.glob(\"test/*\"):\n"," label = int(label_dir.replace(\"test/\", \"\"))\n"," for filename in glob.glob(label_dir + \"/*.png\"):\n"," index, score = predict_image(model, filename)\n"," if score < SCORE_THRESHOLD:\n"," discarded_count += 1\n"," continue\n"," if index == label:\n"," correct_count += 1\n"," else:\n"," wrong_count += 1\n"," print(\"%d expected, %d found with score %f\" % (label, index, score))\n"," display(Image(filename=filename))\n","\n","correct_percentage = (correct_count / (correct_count + wrong_count)) * 100\n","print(\"%.1f%% correct (N=%d, %d unknown)\" % (correct_percentage, (correct_count + wrong_count), discarded_count))"],"execution_count":20,"outputs":[{"output_type":"stream","name":"stdout","text":["9 expected, 7 found with score 0.807747\n"]},{"output_type":"display_data","data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAA8ElEQVR4nGNgGAWjYBTQHDCSocfoLMMvNoav3AxfeBheixFQzEKS0f4bGN4LMvz6xXDOGCrC+Y3hOxc+LUwkWfCblYHtF8MJS4TILzYCWkiwIH0GA/dXhj2uKIJ/f3MQbwJhkDgPlf+dg+EjH34tpAURzxdU/jshBv5P+LWQnIoq2hmE3jGIv2SIb5di+MXGoPiAVBOIBjfViFFFWhChmP6blUy9RIET5kQqJM4HKrdRuIdsGdh+UdUCtl8MvEip5Rcbg9F5Ii0grqiIWMHA+puhkoGBgYFhgz+Dy0YiTScRTM5hWBpFG6NHwSgYBRQBAJY6MnCXjHpLAAAAAElFTkSuQmCC\n","text/plain":[""]},"metadata":{}},{"output_type":"stream","name":"stdout","text":["99.9% correct (N=1027, 73 unknown)\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"d26wGJn0t20g","executionInfo":{"status":"ok","timestamp":1638748436167,"user_tz":480,"elapsed":2605,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"5d525abe-97bc-4a71-c757-79d8db945d4f"},"source":["model.save(SAVED_MODEL_FILENAME)"],"execution_count":21,"outputs":[{"output_type":"stream","name":"stdout","text":["INFO:tensorflow:Assets written to: saved_model/assets\n"]}]},{"cell_type":"code","metadata":{"id":"ki3E7lM_Kr0C"},"source":["#!curl -L https://storage.googleapis.com/download.tensorflow.org/models/tflite/micro/magic_wand_saved_model_2021_01_02.tgz -o saved_model.tgz\n","#!tar -xzf saved_model.tgz"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"t-hU8aU24gbL","executionInfo":{"status":"ok","timestamp":1638748457118,"user_tz":480,"elapsed":3003,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"8b57dc82-3d72-4bd1-988b-b3a8b85cb101"},"source":["converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_FILENAME)\n","model_no_quant_tflite = converter.convert()\n","\n","# Save the model to disk\n","open(FLOAT_TFL_MODEL_FILENAME, \"wb\").write(model_no_quant_tflite)\n","\n","def representative_dataset():\n"," for filename in glob.glob(\"test/*/*.png\"):\n"," img = keras.preprocessing.image.load_img(filename, target_size=(IMAGE_WIDTH, IMAGE_HEIGHT))\n"," img_array = keras.preprocessing.image.img_to_array(img)\n"," img_array = tf.expand_dims(img_array, 0) # Create batch axis for images, labels in train_ds.take(1):\n"," yield([img_array])\n","# Set the optimization flag.\n","converter.optimizations = [tf.lite.Optimize.DEFAULT]\n","# Enforce integer only quantization\n","converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]\n","converter.inference_input_type = tf.int8\n","converter.inference_output_type = tf.int8\n","# Provide a representative dataset to ensure we quantize correctly.\n","converter.representative_dataset = representative_dataset\n","model_tflite = converter.convert()\n","\n","# Save the model to disk\n","open(QUANTIZED_TFL_MODEL_FILENAME, \"wb\").write(model_tflite)"],"execution_count":22,"outputs":[{"output_type":"stream","name":"stderr","text":["WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded\n","WARNING:absl:Buffer deduplication procedure will be skipped when flatbuffer library is not properly loaded\n"]},{"output_type":"execute_result","data":{"text/plain":["30880"]},"metadata":{},"execution_count":22}]},{"cell_type":"code","metadata":{"id":"w5QZTfwRLFAi","executionInfo":{"status":"ok","timestamp":1638748759830,"user_tz":480,"elapsed":192,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}}},"source":["def predict_tflite(tflite_model, filename):\n"," img = keras.preprocessing.image.load_img(filename, target_size=(IMAGE_WIDTH, IMAGE_HEIGHT))\n"," img_array = keras.preprocessing.image.img_to_array(img)\n"," img_array = tf.expand_dims(img_array, 0)\n","\n"," # Initialize the TFLite interpreter\n"," interpreter = tf.lite.Interpreter(model_content=tflite_model)\n"," interpreter.allocate_tensors()\n","\n"," input_details = interpreter.get_input_details()[0]\n"," output_details = interpreter.get_output_details()[0]\n","\n"," # If required, quantize the input layer (from float to integer)\n"," input_scale, input_zero_point = input_details[\"quantization\"]\n"," if (input_scale, input_zero_point) != (0.0, 0):\n"," img_array = np.multiply(img_array, 1.0 / input_scale) + input_zero_point\n"," img_array = img_array.astype(input_details[\"dtype\"])\n"," \n"," # Invoke the interpreter\n"," interpreter.set_tensor(input_details[\"index\"], img_array)\n"," interpreter.invoke()\n"," pred = interpreter.get_tensor(output_details[\"index\"])[0]\n"," \n"," # If required, dequantized the output layer (from integer to float)\n"," output_scale, output_zero_point = output_details[\"quantization\"]\n"," if (output_scale, output_zero_point) != (0.0, 0):\n"," pred = pred.astype(np.float32)\n"," pred = np.multiply((pred - output_zero_point), output_scale)\n"," \n"," predicted_label_index = np.argmax(pred)\n"," predicted_score = pred[predicted_label_index]\n"," return (predicted_label_index, predicted_score)"],"execution_count":27,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"vtee_WxPMgup","executionInfo":{"status":"ok","timestamp":1638748762171,"user_tz":480,"elapsed":137,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"0008362b-c68d-408b-efec-b64136898b4a"},"source":["predict_tflite(model_no_quant_tflite, \"test/7/2.png\")"],"execution_count":28,"outputs":[{"output_type":"execute_result","data":{"text/plain":["(7, 0.9931043)"]},"metadata":{},"execution_count":28}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"0rp0LirfN9vB","executionInfo":{"status":"ok","timestamp":1638748770247,"user_tz":480,"elapsed":165,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"c63b8114-3f8a-45d2-d72b-585a058cb875"},"source":["predict_tflite(model_tflite, \"test/7/2.png\")"],"execution_count":29,"outputs":[{"output_type":"execute_result","data":{"text/plain":["(7, 0.9921875)"]},"metadata":{},"execution_count":29}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":83},"id":"jdNgTO19PRqO","executionInfo":{"status":"ok","timestamp":1638748783929,"user_tz":480,"elapsed":3912,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"8e6c5f8a-9236-4446-ff31-d5f95e170cee"},"source":["from IPython.display import Image, display\n","\n","correct_count = 0\n","wrong_count = 0\n","discarded_count = 0\n","for label_dir in glob.glob(\"test/*\"):\n"," label = int(label_dir.replace(\"test/\", \"\"))\n"," for filename in glob.glob(label_dir + \"/*.png\"):\n"," index, score = predict_tflite(model_tflite, filename)\n"," if score < 0.75:\n"," discarded_count += 1\n"," continue\n"," if index == label:\n"," correct_count += 1\n"," else:\n"," wrong_count += 1\n"," print(\"%d expected, %d found with score %f\" % (label, index, score))\n"," display(Image(filename=filename))\n","\n","correct_percentage = (correct_count / (correct_count + wrong_count)) * 100\n","\n","print(\"%.1f%% correct (N=%d, %d unknown)\" % (correct_percentage, (correct_count + wrong_count), discarded_count))"],"execution_count":30,"outputs":[{"output_type":"stream","name":"stdout","text":["9 expected, 7 found with score 0.816406\n"]},{"output_type":"display_data","data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAA8ElEQVR4nGNgGAWjYBTQHDCSocfoLMMvNoav3AxfeBheixFQzEKS0f4bGN4LMvz6xXDOGCrC+Y3hOxc+LUwkWfCblYHtF8MJS4TILzYCWkiwIH0GA/dXhj2uKIJ/f3MQbwJhkDgPlf+dg+EjH34tpAURzxdU/jshBv5P+LWQnIoq2hmE3jGIv2SIb5di+MXGoPiAVBOIBjfViFFFWhChmP6blUy9RIET5kQqJM4HKrdRuIdsGdh+UdUCtl8MvEip5Rcbg9F5Ii0grqiIWMHA+puhkoGBgYFhgz+Dy0YiTScRTM5hWBpFG6NHwSgYBRQBAJY6MnCXjHpLAAAAAElFTkSuQmCC\n","text/plain":[""]},"metadata":{}},{"output_type":"stream","name":"stdout","text":["99.9% correct (N=1027, 73 unknown)\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":173},"id":"NTjGMU8BPpoz","executionInfo":{"status":"ok","timestamp":1638748792684,"user_tz":480,"elapsed":135,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"ea56df39-9336-495c-e214-e39f9fcef78e"},"source":["import os\n","import pandas as pd\n","\n","def get_dir_size(dir):\n"," size = 0\n"," for f in os.scandir(dir):\n"," if f.is_file():\n"," size += f.stat().st_size\n"," elif f.is_dir():\n"," size += get_dir_size(f.path)\n"," return size\n","\n","# Calculate size\n","size_tf = get_dir_size(SAVED_MODEL_FILENAME)\n","size_no_quant_tflite = os.path.getsize(FLOAT_TFL_MODEL_FILENAME)\n","size_tflite = os.path.getsize(QUANTIZED_TFL_MODEL_FILENAME)\n","\n","# Compare size\n","pd.DataFrame.from_records(\n"," [[\"TensorFlow\", f\"{size_tf} bytes\", \"\"],\n"," [\"TensorFlow Lite\", f\"{size_no_quant_tflite} bytes \", f\"(reduced by {size_tf - size_no_quant_tflite} bytes)\"],\n"," [\"TensorFlow Lite Quantized\", f\"{size_tflite} bytes\", f\"(reduced by {size_no_quant_tflite - size_tflite} bytes)\"]],\n"," columns = [\"Model\", \"Size\", \"\"], index=\"Model\")\n"],"execution_count":31,"outputs":[{"output_type":"execute_result","data":{"text/html":["
\n","\n","\n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n"," \n","
Size
Model
TensorFlow668171 bytes
TensorFlow Lite100096 bytes(reduced by 568075 bytes)
TensorFlow Lite Quantized30880 bytes(reduced by 69216 bytes)
\n","
"],"text/plain":[" Size \n","Model \n","TensorFlow 668171 bytes \n","TensorFlow Lite 100096 bytes (reduced by 568075 bytes)\n","TensorFlow Lite Quantized 30880 bytes (reduced by 69216 bytes)"]},"metadata":{},"execution_count":31}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"mrvnEJLfR8KU","executionInfo":{"status":"ok","timestamp":1638748913062,"user_tz":480,"elapsed":12258,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"fa3461ec-a27f-45c5-f6d0-555d339415cf"},"source":["# Install xxd if it is not available\n","!apt-get update && apt-get -qq install xxd\n","# Convert to a C source file, i.e, a TensorFlow Lite for Microcontrollers model\n","!xxd -i {QUANTIZED_TFL_MODEL_FILENAME} > {TFL_CC_MODEL_FILENAME}\n","# Update variable names\n","REPLACE_TEXT = QUANTIZED_TFL_MODEL_FILENAME.replace('/', '_').replace('.', '_')\n","!sed -i 's/'{REPLACE_TEXT}'/g_magic_wand_model_data/g' {TFL_CC_MODEL_FILENAME}"],"execution_count":32,"outputs":[{"output_type":"stream","name":"stdout","text":["\r0% [Working]\r \rGet:1 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]\n","Ign:2 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 InRelease\n","Get:3 https://cloud.r-project.org/bin/linux/ubuntu bionic-cran40/ InRelease [3,626 B]\n","Ign:4 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 InRelease\n","Hit:5 http://archive.ubuntu.com/ubuntu bionic InRelease\n","Get:6 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Release [696 B]\n","Hit:7 https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 Release\n","Get:8 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Release.gpg [836 B]\n","Get:9 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic InRelease [15.9 kB]\n","Get:10 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]\n","Get:11 http://security.ubuntu.com/ubuntu bionic-security/universe amd64 Packages [1,444 kB]\n","Hit:12 http://ppa.launchpad.net/cran/libgit2/ubuntu bionic InRelease\n","Get:13 http://security.ubuntu.com/ubuntu bionic-security/main amd64 Packages [2,461 kB]\n","Get:14 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]\n","Get:15 http://security.ubuntu.com/ubuntu bionic-security/restricted amd64 Packages [691 kB]\n","Hit:16 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic InRelease\n","Get:17 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic InRelease [21.3 kB]\n","Get:19 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 Packages [829 kB]\n","Get:20 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main Sources [1,814 kB]\n","Get:21 http://archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [2,898 kB]\n","Get:22 http://ppa.launchpad.net/c2d4u.team/c2d4u4.0+/ubuntu bionic/main amd64 Packages [931 kB]\n","Get:23 http://archive.ubuntu.com/ubuntu bionic-updates/restricted amd64 Packages [725 kB]\n","Get:24 http://archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [2,225 kB]\n","Get:25 http://ppa.launchpad.net/graphics-drivers/ppa/ubuntu bionic/main amd64 Packages [44.7 kB]\n","Fetched 14.4 MB in 4s (3,767 kB/s)\n","Reading package lists... Done\n","Selecting previously unselected package xxd.\n","(Reading database ... 155222 files and directories currently installed.)\n","Preparing to unpack .../xxd_2%3a8.0.1453-1ubuntu1.7_amd64.deb ...\n","Unpacking xxd (2:8.0.1453-1ubuntu1.7) ...\n","Setting up xxd (2:8.0.1453-1ubuntu1.7) ...\n","Processing triggers for man-db (2.8.3-2ubuntu0.1) ...\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"oazLUtBqWzdJ","executionInfo":{"status":"ok","timestamp":1638748916580,"user_tz":480,"elapsed":339,"user":{"displayName":"David Davis","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"03716636181783186066"}},"outputId":"b6b57fbb-02e9-4972-8bb2-bedc856f0eaa"},"source":["# Print the C source file\n","!tail {TFL_CC_MODEL_FILENAME}"],"execution_count":33,"outputs":[{"output_type":"stream","name":"stdout","text":[" 0x75, 0x6c, 0x74, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x31, 0x3a,\n"," 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\n"," 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n"," 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00,\n"," 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,\n"," 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00,\n"," 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00,\n"," 0x04, 0x00, 0x00, 0x00\n","};\n","unsigned int g_magic_wand_model_data_len = 30880;\n"]}]},{"cell_type":"code","metadata":{"id":"VqN2F42PW-uv"},"source":[""],"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/website/index.html b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/website/index.html new file mode 100644 index 000000000..12e0e284a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/magic_wand/website/index.html @@ -0,0 +1,474 @@ + + + + Magic Wand Gesture Recorder + + + + + +
+
+ To get started recording magic wand gestures: +
    +
  • Upload the Magic Wand Capture sketch to an Arduino Nano BLE Sense board
  • +
  • Connect to the board using the Bluetooth button below.
  • +
  • Wave the wand to make gestures. They'll be recorded and displayed on the right.
  • +
  • Review the gestures, add labels by clicking on the '?', and remove mistakes.
  • +
  • Download the gestures as a JSON data file, ready for model training.
  • +
+
+
+ Download Data + +
Click button to connect to the board
+
+
+ +
+
+ +
+ +
+
+
+ + + diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/README.md b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/README.md new file mode 100644 index 000000000..b7a1b468a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/README.md @@ -0,0 +1,84 @@ + + +# Micro Speech Example + +This example shows how to run a 20 kB model that can recognize 2 keywords, +"yes" and "no", from speech data. + +The application listens to its surroundings with a microphone and indicates +when it has detected a word by lighting an LED or displaying data on a +screen, depending on the capabilities of the device. + +![Animation on Arduino](../../docs/animation_on_arduino.gif) + +The code has a small footprint (for example, around 166 kilobytes on a Cortex +M4) and only uses about 54 kilobytes of additional RAM for working memory. + +## Table of contents + +* [Table of contents](#table-of-contents) +* [Deploy to Arduino](#deploy-to-arduino) + * [Install the Arduino_TensorFlowLite library](#install-the-arduino_tensorflowlite-library) + * [Load and run the example](#load-and-run-the-example) + + +## Deploy to Arduino + +The following instructions will help you build and deploy this example to +[Arduino](https://www.arduino.cc/) devices. + +The example has been tested with the following devices: + +- [Arduino Nano 33 BLE Sense](https://store.arduino.cc/usa/nano-33-ble-sense-with-headers) + +The Arduino Nano 33 BLE Sense is currently the only Arduino with a built-in +microphone. If you're using a different Arduino board and attaching your own +microphone, you'll need to implement your own `audio_provider.cpp` code. It also has a +set of LEDs, which are used to indicate that a word has been recognized. + +### Install the Arduino_TensorFlowLite library + +This example application is included as part of the official TensorFlow Lite Micro +Arduino library. +To install the TensorFlow Lite Micro for Arduino library, see the +[how to install](../../README.md#how-to-install) instructions. + +### Load and run the example + +Once the library has been added, go to `File -> Examples`. You should see an +entry within the list named `Arduino_TensorFlowLite`. Select +it and click `micro_speech` to load the example. + +Use the Arduino IDE to build and upload the example. Once it is running, you +should see the built-in LED on your device flashing. The built-in LED will flash on/off for each inference cycle. Saying the word "yes" will +cause the green LED to remain on for 3 seconds. The current model has fairly low +accuracy, so you may have to repeat "yes" a few times. Saying the word "no" will cause the red LED to light up. The blue LED will be lit for certain "unknown" sounds. + +Word recognition should occur at a distance of approximately 1.5 feet in a low-noise environment. + +The program also outputs inference results to the serial port, which appear as +follows: + +``` +Heard yes (201) @4056ms +Heard no (205) @6448ms +Heard unknown (201) @13696ms +Heard yes (205) @15000ms +``` + +The number after each detected word is its score. By default, the program only +considers matches as valid if their score is over 200, so all of the scores you +see will be at least 200. + +When the program is run, it waits several seconds for a USB-serial connection to be +available. If there is no connection available, it will not output data. To see +the serial output in the Arduino desktop IDE, do the following: + +1. Open the Arduino IDE +1. Connect the Arduino board to your computer via USB +1. Press the reset button on the Arduino board +1. Within 5 seconds, go to `Tools -> Serial Monitor` in the Arduino IDE. You may + have to try several times, since the board will take a moment to connect. + +If you don't see any output, repeat the process again. + diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_audio_provider.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_audio_provider.cpp new file mode 100644 index 000000000..2c5594c9b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_audio_provider.cpp @@ -0,0 +1,194 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) +#define ARDUINO_EXCLUDE_CODE +#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) + +#ifndef ARDUINO_EXCLUDE_CODE + +#include +#include + +#include "PDM.h" +#include "audio_provider.h" +#include "micro_features_micro_model_settings.h" +#include "test_over_serial/test_over_serial.h" + +using namespace test_over_serial; + +namespace { +bool g_is_audio_initialized = false; +// An internal buffer able to fit 16x our sample size +constexpr int kAudioCaptureBufferSize = DEFAULT_PDM_BUFFER_SIZE * 16; +int16_t g_audio_capture_buffer[kAudioCaptureBufferSize]; +// A buffer that holds our output +int16_t g_audio_output_buffer[kMaxAudioSampleSize]; +// Mark as volatile so we can check in a while loop to see if +// any samples have arrived yet. +volatile int32_t g_latest_audio_timestamp = 0; +// error reporter +tflite::ErrorReporter* g_error_reporter; +// test_over_serial sample index +uint32_t g_test_sample_index; +// test_over_serial silence insertion flag +bool g_test_insert_silence = true; +} // namespace + +void CaptureSamples() { + // This is how many bytes of new data we have each time this is called + const int number_of_samples = DEFAULT_PDM_BUFFER_SIZE / 2; + // Calculate what timestamp the last audio sample represents + const int32_t time_in_ms = + g_latest_audio_timestamp + + (number_of_samples / (kAudioSampleFrequency / 1000)); + // Determine the index, in the history of all samples, of the last sample + const int32_t start_sample_offset = + g_latest_audio_timestamp * (kAudioSampleFrequency / 1000); + // Determine the index of this sample in our ring buffer + const int capture_index = start_sample_offset % kAudioCaptureBufferSize; + // Read the data to the correct place in our buffer + int num_read = + PDM.read(g_audio_capture_buffer + capture_index, DEFAULT_PDM_BUFFER_SIZE); + if (num_read != DEFAULT_PDM_BUFFER_SIZE) { + TF_LITE_REPORT_ERROR(g_error_reporter, "### short read (%d/%d) @%dms", + num_read, DEFAULT_PDM_BUFFER_SIZE, time_in_ms); + while (true) { + // NORETURN + } + } + // This is how we let the outside world know that new audio data has arrived. + g_latest_audio_timestamp = time_in_ms; +} + +TfLiteStatus InitAudioRecording(tflite::ErrorReporter* error_reporter) { + if (!g_is_audio_initialized) { + g_error_reporter = error_reporter; + // Hook up the callback that will be called with each sample + PDM.onReceive(CaptureSamples); + // Start listening for audio: MONO @ 16KHz + PDM.begin(1, kAudioSampleFrequency); + // gain: -20db (min) + 6.5db (13) + 3.2db (builtin) = -10.3db + PDM.setGain(13); + // Block until we have our first audio sample + while (!g_latest_audio_timestamp) { + } + g_is_audio_initialized = true; + } + + return kTfLiteOk; +} + +TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, + int start_ms, int duration_ms, + int* audio_samples_size, int16_t** audio_samples) { + // This next part should only be called when the main thread notices that the + // latest audio sample data timestamp has changed, so that there's new data + // in the capture ring buffer. The ring buffer will eventually wrap around and + // overwrite the data, but the assumption is that the main thread is checking + // often enough and the buffer is large enough that this call will be made + // before that happens. + + // Determine the index, in the history of all samples, of the first + // sample we want + const int start_offset = start_ms * (kAudioSampleFrequency / 1000); + // Determine how many samples we want in total + const int duration_sample_count = + duration_ms * (kAudioSampleFrequency / 1000); + for (int i = 0; i < duration_sample_count; ++i) { + // For each sample, transform its index in the history of all samples into + // its index in g_audio_capture_buffer + const int capture_index = (start_offset + i) % kAudioCaptureBufferSize; + // Write the sample to the output buffer + g_audio_output_buffer[i] = g_audio_capture_buffer[capture_index]; + } + + // Set pointers to provide access to the audio + *audio_samples_size = duration_sample_count; + *audio_samples = g_audio_output_buffer; + + return kTfLiteOk; +} + +namespace { + +void InsertSilence(const size_t len, int16_t value) { + for (size_t i = 0; i < len; i++) { + const size_t index = (g_test_sample_index + i) % kAudioCaptureBufferSize; + g_audio_capture_buffer[index] = value; + } + g_test_sample_index += len; +} + +int32_t ProcessTestInput(TestOverSerial& test) { + constexpr size_t samples_16ms = ((kAudioSampleFrequency / 1000) * 16); + + InputHandler handler = [](const InputBuffer* const input) { + if (0 == input->offset) { + // don't insert silence + g_test_insert_silence = false; + } + + for (size_t i = 0; i < input->length; i++) { + const size_t index = (g_test_sample_index + i) % kAudioCaptureBufferSize; + g_audio_capture_buffer[index] = input->data.int16[i]; + } + g_test_sample_index += input->length; + + if (input->total == (input->offset + input->length)) { + // allow silence insertion again + g_test_insert_silence = true; + } + return true; + }; + + test.ProcessInput(&handler); + + if (g_test_insert_silence) { + // add 16ms of silence just like the PDM interface + InsertSilence(samples_16ms, 0); + } + + // Round the timestamp to a multiple of 64ms, + // This emulates the PDM interface during inference processing. + g_latest_audio_timestamp = (g_test_sample_index / (samples_16ms * 4)) * 64; + return g_latest_audio_timestamp; +} + +} // namespace + +int32_t LatestAudioTimestamp() { + TestOverSerial& test = TestOverSerial::Instance(kAUDIO_PCM_16KHZ_MONO_S16); + if (!test.IsTestMode()) { + // check serial port for test mode command + test.ProcessInput(nullptr); + } + if (test.IsTestMode()) { + if (g_is_audio_initialized) { + // stop capture from hardware + PDM.end(); + g_is_audio_initialized = false; + g_test_sample_index = + g_latest_audio_timestamp * (kAudioSampleFrequency / 1000); + } + return ProcessTestInput(test); + } else { + // CaptureSamples() updated the timestamp + return g_latest_audio_timestamp; + } + // NOTREACHED +} + +#endif // ARDUINO_EXCLUDE_CODE diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_command_responder.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_command_responder.cpp new file mode 100644 index 000000000..7fedc6964 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_command_responder.cpp @@ -0,0 +1,89 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) +#define ARDUINO_EXCLUDE_CODE +#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) + +#ifndef ARDUINO_EXCLUDE_CODE + +#include "Arduino.h" +#include "command_responder.h" + +// Toggles the built-in LED every inference, and lights a colored LED depending +// on which word was detected. +void RespondToCommand(tflite::ErrorReporter* error_reporter, + int32_t current_time, const char* found_command, + uint8_t score, bool is_new_command) { + static bool is_initialized = false; + if (!is_initialized) { + pinMode(LED_BUILTIN, OUTPUT); + // Pins for the built-in RGB LEDs on the Arduino Nano 33 BLE Sense + pinMode(LEDR, OUTPUT); + pinMode(LEDG, OUTPUT); + pinMode(LEDB, OUTPUT); + // Ensure the LED is off by default. + // Note: The RGB LEDs on the Arduino Nano 33 BLE + // Sense are on when the pin is LOW, off when HIGH. + digitalWrite(LEDR, HIGH); + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, HIGH); + is_initialized = true; + } + static int32_t last_command_time = 0; + static int count = 0; + + if (is_new_command) { + TF_LITE_REPORT_ERROR(error_reporter, "Heard %s (%d) @%dms", found_command, + score, current_time); + // If we hear a command, light up the appropriate LED + digitalWrite(LEDR, HIGH); + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, HIGH); + + if (found_command[0] == 'y') { + digitalWrite(LEDG, LOW); // Green for yes + } else if (found_command[0] == 'n') { + digitalWrite(LEDR, LOW); // Red for no + } else if (found_command[0] == 'u') { + digitalWrite(LEDB, LOW); // Blue for unknown + } else { + // silence + } + + last_command_time = current_time; + } + + // If last_command_time is non-zero but was >3 seconds ago, zero it + // and switch off the LED. + if (last_command_time != 0) { + if (last_command_time < (current_time - 3000)) { + last_command_time = 0; + digitalWrite(LEDR, HIGH); + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, HIGH); + } + } + + // Otherwise, toggle the LED every time an inference is performed. + ++count; + if (count & 1) { + digitalWrite(LED_BUILTIN, HIGH); + } else { + digitalWrite(LED_BUILTIN, LOW); + } +} + +#endif // ARDUINO_EXCLUDE_CODE diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_main.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_main.cpp new file mode 100644 index 000000000..c70a2bcea --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/arduino_main.cpp @@ -0,0 +1,20 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "main_functions.h" + +// Arduino automatically calls the setup() and loop() functions in a sketch, so +// where other systems need their own main routine in this file, it can be left +// empty. diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/audio_provider.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/audio_provider.h new file mode 100644 index 000000000..88988ba1f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/audio_provider.h @@ -0,0 +1,49 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// This is an abstraction around an audio source like a microphone, and is +// expected to return 16-bit PCM sample data for a given point in time. The +// sample data itself should be used as quickly as possible by the caller, since +// to allow memory optimizations there are no guarantees that the samples won't +// be overwritten by new data in the future. In practice, implementations should +// ensure that there's a reasonable time allowed for clients to access the data +// before any reuse. +// The reference implementation can have no platform-specific dependencies, so +// it just returns an array filled with zeros. For real applications, you should +// ensure there's a specialized implementation that accesses hardware APIs. +TfLiteStatus GetAudioSamples(tflite::ErrorReporter* error_reporter, + int start_ms, int duration_ms, + int* audio_samples_size, int16_t** audio_samples); + +// Returns the time that audio data was last captured in milliseconds. There's +// no contract about what time zero represents, the accuracy, or the granularity +// of the result. Subsequent calls will generally not return a lower value, but +// even that's not guaranteed if there's an overflow wraparound. +// The reference implementation of this function just returns a constantly +// incrementing value for each call, since it would need a non-portable platform +// call to access time information. For real applications, you'll need to write +// your own platform-specific implementation. +int32_t LatestAudioTimestamp(); + +// Starts audio capture +TfLiteStatus InitAudioRecording(tflite::ErrorReporter* error_reporter); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_AUDIO_PROVIDER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/command_responder.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/command_responder.h new file mode 100644 index 000000000..ac3f448ee --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/command_responder.h @@ -0,0 +1,32 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ + +// Provides an interface to take an action based on an audio command. + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_COMMAND_RESPONDER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_COMMAND_RESPONDER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// Called every time the results of an audio recognition run are available. The +// human-readable name of any recognized command is in the `found_command` +// argument, `score` has the numerical confidence, and `is_new_command` is set +// if the previous command was different to this one. +void RespondToCommand(tflite::ErrorReporter* error_reporter, + int32_t current_time, const char* found_command, + uint8_t score, bool is_new_command); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_COMMAND_RESPONDER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/feature_provider.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/feature_provider.cpp new file mode 100644 index 000000000..a9142f7d4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/feature_provider.cpp @@ -0,0 +1,127 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "feature_provider.h" + +#include "audio_provider.h" +#include "micro_features_micro_features_generator.h" +#include "micro_features_micro_model_settings.h" + +FeatureProvider::FeatureProvider(int feature_size, int8_t* feature_data) + : feature_size_(feature_size), + feature_data_(feature_data), + is_first_run_(true) { + // Initialize the feature data to default values. + for (int n = 0; n < feature_size_; ++n) { + feature_data_[n] = 0; + } +} + +FeatureProvider::~FeatureProvider() {} + +TfLiteStatus FeatureProvider::PopulateFeatureData( + tflite::ErrorReporter* error_reporter, int32_t last_time_in_ms, + int32_t time_in_ms, int* how_many_new_slices) { + if (feature_size_ != kFeatureElementCount) { + TF_LITE_REPORT_ERROR(error_reporter, + "Requested feature_data_ size %d doesn't match %d", + feature_size_, kFeatureElementCount); + return kTfLiteError; + } + + // Quantize the time into steps as long as each window stride, so we can + // figure out which audio data we need to fetch. + const int last_step = (last_time_in_ms / kFeatureSliceStrideMs); + // Number of new 20ms slices from which we can take 30ms samples + int slices_needed = + ((((time_in_ms - last_time_in_ms) - kFeatureSliceDurationMs) * + kFeatureSliceStrideMs) / + kFeatureSliceStrideMs + + kFeatureSliceStrideMs) / + kFeatureSliceStrideMs; + // If this is the first call, make sure we don't use any cached information. + if (is_first_run_) { + TfLiteStatus init_status = InitializeMicroFeatures(error_reporter); + if (init_status != kTfLiteOk) { + return init_status; + } + is_first_run_ = false; + return kTfLiteOk; + } + if (slices_needed > kFeatureSliceCount) { + slices_needed = kFeatureSliceCount; + } + if (slices_needed == 0) { + return kTfLiteOk; + } + *how_many_new_slices = slices_needed; + + const int slices_to_keep = kFeatureSliceCount - slices_needed; + const int slices_to_drop = kFeatureSliceCount - slices_to_keep; + // If we can avoid recalculating some slices, just move the existing data + // up in the spectrogram, to perform something like this: + // last time = 80ms current time = 120ms + // +-----------+ +-----------+ + // | data@20ms | --> | data@60ms | + // +-----------+ -- +-----------+ + // | data@40ms | -- --> | data@80ms | + // +-----------+ -- -- +-----------+ + // | data@60ms | -- -- | | + // +-----------+ -- +-----------+ + // | data@80ms | -- | | + // +-----------+ +-----------+ + if (slices_to_keep > 0) { + for (int dest_slice = 0; dest_slice < slices_to_keep; ++dest_slice) { + int8_t* dest_slice_data = + feature_data_ + (dest_slice * kFeatureSliceSize); + const int src_slice = dest_slice + slices_to_drop; + const int8_t* src_slice_data = + feature_data_ + (src_slice * kFeatureSliceSize); + for (int i = 0; i < kFeatureSliceSize; ++i) { + dest_slice_data[i] = src_slice_data[i]; + } + } + } + // Any slices that need to be filled in with feature data have their + // appropriate audio data pulled, and features calculated for that slice. + if (slices_needed > 0) { + for (int new_slice = slices_to_keep; new_slice < kFeatureSliceCount; + ++new_slice) { + const int new_step = last_step + (new_slice - slices_to_keep); + const int32_t slice_start_ms = (new_step * kFeatureSliceStrideMs); + int16_t* audio_samples = nullptr; + int audio_samples_size = 0; + GetAudioSamples(error_reporter, slice_start_ms, kFeatureSliceDurationMs, + &audio_samples_size, &audio_samples); + constexpr int wanted = + kFeatureSliceDurationMs * (kAudioSampleFrequency / 1000); + if (audio_samples_size != wanted) { + TF_LITE_REPORT_ERROR(error_reporter, + "Audio data size %d too small, want %d", + audio_samples_size, wanted); + return kTfLiteError; + } + int8_t* new_slice_data = feature_data_ + (new_slice * kFeatureSliceSize); + size_t num_samples_read; + TfLiteStatus generate_status = GenerateMicroFeatures( + error_reporter, audio_samples, audio_samples_size, kFeatureSliceSize, + new_slice_data, &num_samples_read); + if (generate_status != kTfLiteOk) { + return generate_status; + } + } + } + return kTfLiteOk; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/feature_provider.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/feature_provider.h new file mode 100644 index 000000000..d086e013d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/feature_provider.h @@ -0,0 +1,52 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// Binds itself to an area of memory intended to hold the input features for an +// audio-recognition neural network model, and fills that data area with the +// features representing the current audio input, for example from a microphone. +// The audio features themselves are a two-dimensional array, made up of +// horizontal slices representing the frequencies at one point in time, stacked +// on top of each other to form a spectrogram showing how those frequencies +// changed over time. +class FeatureProvider { + public: + // Create the provider, and bind it to an area of memory. This memory should + // remain accessible for the lifetime of the provider object, since subsequent + // calls will fill it with feature data. The provider does no memory + // management of this data. + FeatureProvider(int feature_size, int8_t* feature_data); + ~FeatureProvider(); + + // Fills the feature data with information from audio inputs, and returns how + // many feature slices were updated. + TfLiteStatus PopulateFeatureData(tflite::ErrorReporter* error_reporter, + int32_t last_time_in_ms, int32_t time_in_ms, + int* how_many_new_slices); + + private: + int feature_size_; + int8_t* feature_data_; + // Make sure we don't try to use cached information if this is the first call + // into the provider. + bool is_first_run_; +}; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_FEATURE_PROVIDER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/main_functions.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/main_functions.h new file mode 100644 index 000000000..0ac067710 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/main_functions.h @@ -0,0 +1,37 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MAIN_FUNCTIONS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MAIN_FUNCTIONS_H_ + +// Expose a C friendly interface for main functions. +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes all data needed for the example. The name is important, and needs +// to be setup() for Arduino compatibility. +void setup(); + +// Runs one iteration of data gathering and inference. This should be called +// repeatedly from the application code. The name needs to be loop() for Arduino +// compatibility. +void loop(); + +#ifdef __cplusplus +} +#endif + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MAIN_FUNCTIONS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_features_generator.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_features_generator.cpp new file mode 100644 index 000000000..2776b2fc8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_features_generator.cpp @@ -0,0 +1,116 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "micro_features_micro_features_generator.h" + +#include +#include + +#include "micro_features_micro_model_settings.h" +#include "tensorflow/lite/experimental/microfrontend/lib/frontend.h" +#include "tensorflow/lite/experimental/microfrontend/lib/frontend_util.h" + +// Configure FFT to output 16 bit fixed point. +#define FIXED_POINT 16 + +namespace { + +FrontendState g_micro_features_state; +bool g_is_first_time = true; + +} // namespace + +TfLiteStatus InitializeMicroFeatures(tflite::ErrorReporter* error_reporter) { + FrontendConfig config; + config.window.size_ms = kFeatureSliceDurationMs; + config.window.step_size_ms = kFeatureSliceStrideMs; + config.noise_reduction.smoothing_bits = 10; + config.filterbank.num_channels = kFeatureSliceSize; + config.filterbank.lower_band_limit = 125.0; + config.filterbank.upper_band_limit = 7500.0; + config.noise_reduction.smoothing_bits = 10; + config.noise_reduction.even_smoothing = 0.025; + config.noise_reduction.odd_smoothing = 0.06; + config.noise_reduction.min_signal_remaining = 0.05; + config.pcan_gain_control.enable_pcan = 1; + config.pcan_gain_control.strength = 0.95; + config.pcan_gain_control.offset = 80.0; + config.pcan_gain_control.gain_bits = 21; + config.log_scale.enable_log = 1; + config.log_scale.scale_shift = 6; + if (!FrontendPopulateState(&config, &g_micro_features_state, + kAudioSampleFrequency)) { + TF_LITE_REPORT_ERROR(error_reporter, "FrontendPopulateState() failed"); + return kTfLiteError; + } + g_is_first_time = true; + return kTfLiteOk; +} + +// This is not exposed in any header, and is only used for testing, to ensure +// that the state is correctly set up before generating results. +void SetMicroFeaturesNoiseEstimates(const uint32_t* estimate_presets) { + for (int i = 0; i < g_micro_features_state.filterbank.num_channels; ++i) { + g_micro_features_state.noise_reduction.estimate[i] = estimate_presets[i]; + } +} + +TfLiteStatus GenerateMicroFeatures(tflite::ErrorReporter* error_reporter, + const int16_t* input, int input_size, + int output_size, int8_t* output, + size_t* num_samples_read) { + const int16_t* frontend_input; + if (g_is_first_time) { + frontend_input = input; + g_is_first_time = false; + } else { + frontend_input = input; + } + FrontendOutput frontend_output = FrontendProcessSamples( + &g_micro_features_state, frontend_input, input_size, num_samples_read); + + for (size_t i = 0; i < frontend_output.size; ++i) { + // These scaling values are derived from those used in input_data.py in the + // training pipeline. + // The feature pipeline outputs 16-bit signed integers in roughly a 0 to 670 + // range. In training, these are then arbitrarily divided by 25.6 to get + // float values in the rough range of 0.0 to 26.0. This scaling is performed + // for historical reasons, to match up with the output of other feature + // generators. + // The process is then further complicated when we quantize the model. This + // means we have to scale the 0.0 to 26.0 real values to the -128 to 127 + // signed integer numbers. + // All this means that to get matching values from our integer feature + // output into the tensor input, we have to perform: + // input = (((feature / 25.6) / 26.0) * 256) - 128 + // To simplify this and perform it in 32-bit integer math, we rearrange to: + // input = (feature * 256) / (25.6 * 26.0) - 128 + constexpr int32_t value_scale = 256; + constexpr int32_t value_div = static_cast((25.6f * 26.0f) + 0.5f); + int32_t value = + ((frontend_output.values[i] * value_scale) + (value_div / 2)) / + value_div; + value -= 128; + if (value < -128) { + value = -128; + } + if (value > 127) { + value = 127; + } + output[i] = value; + } + + return kTfLiteOk; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_features_generator.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_features_generator.h new file mode 100644 index 000000000..293042393 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_features_generator.h @@ -0,0 +1,32 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MICRO_FEATURES_GENERATOR_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MICRO_FEATURES_GENERATOR_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// Sets up any resources needed for the feature generation pipeline. +TfLiteStatus InitializeMicroFeatures(tflite::ErrorReporter* error_reporter); + +// Converts audio sample data into a more compact form that's appropriate for +// feeding into a neural network. +TfLiteStatus GenerateMicroFeatures(tflite::ErrorReporter* error_reporter, + const int16_t* input, int input_size, + int output_size, int8_t* output, + size_t* num_samples_read); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MICRO_FEATURES_GENERATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_model_settings.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_model_settings.cpp new file mode 100644 index 000000000..f772cef9b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_model_settings.cpp @@ -0,0 +1,23 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "micro_features_micro_model_settings.h" + +const char* kCategoryLabels[kCategoryCount] = { + "silence", + "unknown", + "yes", + "no", +}; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_model_settings.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_model_settings.h new file mode 100644 index 000000000..e542213e8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_micro_model_settings.h @@ -0,0 +1,43 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MICRO_MODEL_SETTINGS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MICRO_MODEL_SETTINGS_H_ + +// Keeping these as constant expressions allow us to allocate fixed-sized arrays +// on the stack for our working memory. + +// The size of the input time series data we pass to the FFT to produce the +// frequency information. This has to be a power of two, and since we're dealing +// with 30ms of 16KHz inputs, which means 480 samples, this is the next value. +constexpr int kMaxAudioSampleSize = 512; +constexpr int kAudioSampleFrequency = 16000; + +// The following values are derived from values used during model training. +// If you change the way you preprocess the input, update all these constants. +constexpr int kFeatureSliceSize = 40; +constexpr int kFeatureSliceCount = 49; +constexpr int kFeatureElementCount = (kFeatureSliceSize * kFeatureSliceCount); +constexpr int kFeatureSliceStrideMs = 20; +constexpr int kFeatureSliceDurationMs = 30; + +// Variables for the model's output categories. +constexpr int kSilenceIndex = 0; +constexpr int kUnknownIndex = 1; +// If you modify the output categories, you need to update the following values. +constexpr int kCategoryCount = 4; +extern const char* kCategoryLabels[kCategoryCount]; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MICRO_MODEL_SETTINGS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_model.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_model.cpp new file mode 100644 index 000000000..428616ec5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_model.cpp @@ -0,0 +1,1596 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 is a standard TensorFlow Lite FlatBuffer model file that has been +// converted into a C data array, so it can be easily compiled into a binary +// for devices that don't have a file system. It was created using the command: +// xxd -i model.tflite > model.cc + +#include "micro_features_model.h" + +// We need to keep the data array aligned on some architectures. +#ifdef __has_attribute +#define HAVE_ATTRIBUTE(x) __has_attribute(x) +#else +#define HAVE_ATTRIBUTE(x) 0 +#endif +#if HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__)) +#define DATA_ALIGN_ATTRIBUTE __attribute__((aligned(4))) +#else +#define DATA_ALIGN_ATTRIBUTE +#endif + +const unsigned char g_model[] DATA_ALIGN_ATTRIBUTE = { + 0x20, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x12, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x94, 0x48, 0x00, 0x00, 0x34, 0x42, 0x00, 0x00, + 0x1c, 0x42, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e, 0x5f, + 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd4, 0x41, 0x00, 0x00, + 0xb4, 0x41, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, + 0xec, 0x02, 0x00, 0x00, 0xe4, 0x02, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, + 0xbc, 0x02, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0xbd, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x31, 0x2e, 0x35, 0x2e, + 0x30, 0x00, 0x00, 0x00, 0x94, 0xba, 0xff, 0xff, 0x98, 0xba, 0xff, 0xff, + 0x32, 0xbd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, + 0xfa, 0xee, 0x28, 0xc4, 0xee, 0xfe, 0xcf, 0x0f, 0x1e, 0xf7, 0x1f, 0x06, + 0x0d, 0xed, 0xe9, 0x83, 0x5c, 0xc9, 0x18, 0xe3, 0xf9, 0x14, 0x28, 0x2a, + 0x09, 0xf2, 0x18, 0x34, 0x62, 0xea, 0xef, 0xd6, 0x36, 0xb7, 0x1e, 0xf7, + 0x3b, 0x22, 0x28, 0x39, 0xc2, 0x9d, 0xf1, 0x07, 0x5e, 0x0b, 0x1e, 0x2c, + 0x07, 0xdd, 0xfd, 0xc3, 0xd8, 0x4a, 0xf3, 0x28, 0xa7, 0x16, 0xd5, 0xf1, + 0xc3, 0x05, 0xfd, 0x27, 0xcc, 0xba, 0x1e, 0xcb, 0xd7, 0x3d, 0xd4, 0x29, + 0x00, 0xfd, 0x28, 0x44, 0xfb, 0xf2, 0xf3, 0xb6, 0x4f, 0xcf, 0x09, 0xf0, + 0xfa, 0x45, 0x41, 0x49, 0x05, 0xc5, 0x17, 0x5d, 0x64, 0x00, 0xf8, 0xee, + 0x48, 0x17, 0xf4, 0xe9, 0x2e, 0x4b, 0x2e, 0x3f, 0xdf, 0xee, 0xe4, 0x08, + 0x38, 0xf1, 0x16, 0x13, 0x2f, 0x2a, 0xed, 0xc2, 0xbf, 0x36, 0xf4, 0x02, + 0xcf, 0xaa, 0xd2, 0xfa, 0xac, 0x13, 0xf6, 0xe8, 0xb5, 0x68, 0x12, 0xb6, + 0xce, 0x0e, 0xdf, 0x58, 0xe4, 0x49, 0x14, 0x15, 0x03, 0xed, 0xfa, 0xd4, + 0x40, 0xa7, 0xf6, 0xca, 0xfb, 0x00, 0x4d, 0x5e, 0xe4, 0x55, 0x1d, 0x30, + 0x45, 0xe2, 0xfc, 0x01, 0x48, 0x81, 0xe9, 0xf1, 0x1e, 0xfc, 0x21, 0x32, + 0xed, 0x4b, 0xed, 0xfa, 0x2f, 0xd2, 0xfa, 0xfb, 0x4d, 0xa7, 0xed, 0xc7, + 0x92, 0xdf, 0xe6, 0xdb, 0xf8, 0x1f, 0xd9, 0xfa, 0x91, 0xf5, 0xe5, 0xc5, + 0x8c, 0x17, 0x0f, 0xb9, 0xd2, 0xc7, 0xfe, 0x68, 0xd3, 0x51, 0x2e, 0x49, + 0x1f, 0xbd, 0x01, 0xeb, 0x31, 0x17, 0xf0, 0xef, 0xff, 0xb8, 0x5d, 0x62, + 0x02, 0x0f, 0x1f, 0x78, 0x6a, 0xb0, 0xf9, 0xfe, 0x4f, 0xcc, 0xd3, 0xff, + 0x0a, 0x96, 0x1e, 0x2c, 0xed, 0xbc, 0xf4, 0x0b, 0x42, 0xc8, 0xf1, 0xea, + 0x6e, 0x58, 0xec, 0xc4, 0x99, 0xae, 0xdc, 0xd7, 0x12, 0x87, 0xd8, 0x06, + 0xa2, 0xc2, 0xe6, 0xa2, 0x81, 0x24, 0xe9, 0xac, 0xce, 0xb6, 0x15, 0x6b, + 0xba, 0x00, 0x19, 0x58, 0x29, 0xb6, 0xfe, 0x01, 0x25, 0x96, 0xd2, 0xec, + 0x0e, 0x9c, 0x60, 0x5f, 0xe9, 0xf4, 0xf5, 0x69, 0x6b, 0xb5, 0xe1, 0xf6, + 0x5e, 0xb7, 0xb1, 0xe5, 0x11, 0x9b, 0x18, 0x10, 0xe3, 0xe1, 0xe0, 0x0d, + 0x4f, 0xa5, 0xde, 0xe5, 0x6f, 0xe2, 0xfb, 0x99, 0x82, 0xa5, 0xc9, 0xb6, + 0x1f, 0x46, 0xf3, 0x04, 0xc6, 0xca, 0xd6, 0x97, 0x90, 0x1d, 0xc0, 0x95, + 0xf0, 0x19, 0x30, 0x77, 0xc2, 0x3c, 0xfa, 0x24, 0x02, 0x4d, 0x06, 0x07, + 0x15, 0x02, 0xb0, 0xe7, 0x27, 0x22, 0x67, 0x4d, 0xf1, 0xc2, 0xf4, 0x64, + 0x38, 0x40, 0xdf, 0xf6, 0x3a, 0x43, 0xb8, 0xe1, 0x0d, 0x15, 0x11, 0xfe, + 0xf5, 0xec, 0xf9, 0xe5, 0x22, 0x36, 0xe4, 0xfd, 0x6d, 0xbf, 0x0d, 0x8e, + 0xb7, 0x15, 0xbf, 0x9f, 0x16, 0xad, 0x0a, 0x02, 0x8e, 0x14, 0xda, 0x9b, + 0x8e, 0xc3, 0xa6, 0xca, 0xf5, 0x7f, 0x51, 0x56, 0xc1, 0xb3, 0xd9, 0x35, + 0xf8, 0x7f, 0x04, 0x0a, 0x03, 0x3f, 0xbe, 0xee, 0x19, 0x68, 0x78, 0x50, + 0xf9, 0xa7, 0xf7, 0x7f, 0x1d, 0x76, 0xdb, 0xe8, 0x33, 0xb9, 0xd7, 0xe7, + 0xe8, 0x69, 0x15, 0xf7, 0xf5, 0xb2, 0xfe, 0xe8, 0xf3, 0x5b, 0xe2, 0x06, + 0x6e, 0x09, 0x36, 0xb7, 0xcc, 0x38, 0xbf, 0x8a, 0x28, 0x14, 0x2e, 0x18, + 0xa7, 0x26, 0xcb, 0xb2, 0x95, 0x37, 0xac, 0xcd, 0xd7, 0x51, 0x67, 0x44, + 0xcd, 0x31, 0xde, 0x04, 0xe9, 0x6a, 0x00, 0x13, 0x0a, 0x0c, 0xdd, 0x16, + 0xe0, 0x24, 0x7e, 0x49, 0xf1, 0xb5, 0x04, 0x52, 0x01, 0x50, 0xdd, 0xf5, + 0x26, 0xc9, 0xf4, 0xf8, 0xd6, 0x31, 0x1b, 0xd0, 0xef, 0x03, 0x0a, 0xc0, + 0xd4, 0x4f, 0xe2, 0xfd, 0x72, 0xf4, 0x5a, 0xc9, 0xd7, 0x31, 0xc0, 0x8e, + 0x17, 0x5e, 0x57, 0x00, 0xb4, 0x3a, 0xc8, 0xd2, 0x92, 0x32, 0xcb, 0xd8, + 0xc3, 0xa6, 0x63, 0x26, 0xcf, 0xbc, 0xe8, 0x57, 0x9b, 0xe9, 0xf7, 0x1c, + 0xea, 0x12, 0xf1, 0xf7, 0xdb, 0xb9, 0x7f, 0x16, 0xf6, 0xe0, 0x08, 0x70, + 0xa2, 0xed, 0xcc, 0xf1, 0x1e, 0x10, 0x04, 0xf7, 0xa9, 0xb7, 0x34, 0xaa, + 0x0a, 0xdb, 0x2a, 0xa6, 0xb6, 0x10, 0xea, 0xf8, 0x5e, 0x06, 0x72, 0xdd, + 0xd0, 0xb9, 0xd6, 0xa0, 0x10, 0x9f, 0x5a, 0x17, 0xb1, 0xe7, 0xc0, 0x01, + 0x9d, 0x01, 0xe0, 0xe0, 0xaf, 0x9c, 0x46, 0xd8, 0xaf, 0xe8, 0xce, 0x02, + 0x8a, 0xbb, 0xe4, 0xf6, 0xf3, 0x36, 0x07, 0xca, 0xcb, 0x87, 0x6e, 0xcc, + 0xd6, 0x9e, 0x0a, 0x2a, 0x81, 0xd7, 0xcf, 0xc0, 0x04, 0xeb, 0x24, 0xcc, + 0xc9, 0x95, 0x33, 0x81, 0xf7, 0xad, 0x1c, 0x9c, 0xa4, 0xd6, 0xf9, 0xe6, + 0x3d, 0x84, 0x7f, 0xcc, 0xd4, 0xb0, 0xf4, 0xa2, 0xe9, 0x3c, 0x36, 0xee, + 0xd5, 0xcf, 0xcd, 0x2d, 0x28, 0xbd, 0xff, 0xff, 0xc2, 0xbf, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x31, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0xbd, 0xff, 0xff, 0x4c, 0xbd, 0xff, 0xff, 0xe6, 0xbf, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x8a, 0xfe, 0xff, 0xff, + 0xa9, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 0xd0, 0x00, 0x00, 0x00, + 0x52, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0xfb, 0xff, 0xff, + 0x4a, 0xfd, 0xff, 0xff, 0x12, 0xc0, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x80, 0x3e, 0x00, 0x00, 0xff, 0xf9, 0xfd, 0x0a, 0x07, 0x08, 0x07, 0x03, + 0x07, 0xf2, 0xd1, 0x09, 0xf0, 0xe9, 0x28, 0x09, 0xdf, 0x05, 0xfa, 0xf0, + 0xe8, 0xe3, 0x13, 0x0e, 0x08, 0xef, 0xd3, 0xee, 0x0f, 0xe8, 0xeb, 0x14, + 0xf7, 0xed, 0xfd, 0x1f, 0xe8, 0xd5, 0xeb, 0xfc, 0x0e, 0xf4, 0xf7, 0x07, + 0x05, 0xea, 0xf6, 0x1f, 0xf8, 0xdb, 0xdc, 0x0b, 0x03, 0xdd, 0xd8, 0xf3, + 0x0f, 0x19, 0xe1, 0x09, 0xfc, 0xe4, 0x02, 0x04, 0xf1, 0x04, 0xeb, 0xf3, + 0x1e, 0x06, 0xfd, 0x11, 0xfc, 0xfa, 0xf6, 0x1f, 0x0f, 0x02, 0xf5, 0xf7, + 0xff, 0x24, 0xdf, 0xf7, 0xf8, 0xf3, 0xf6, 0xe9, 0xef, 0x03, 0xdd, 0xf2, + 0x28, 0xe1, 0xf2, 0x22, 0xf4, 0x09, 0xf7, 0xf9, 0xf0, 0xd4, 0xf9, 0xee, + 0xff, 0x14, 0xda, 0xf3, 0x11, 0xe2, 0xf6, 0x0c, 0xf2, 0xeb, 0xf8, 0xe8, + 0xe3, 0x08, 0x02, 0x17, 0xf4, 0x0b, 0x0c, 0x27, 0xe6, 0x02, 0x03, 0xf9, + 0x14, 0x18, 0xf6, 0xeb, 0x1f, 0x0c, 0xf1, 0xee, 0xfc, 0x08, 0xf0, 0xfe, + 0xfd, 0xee, 0x17, 0xfd, 0x1c, 0xef, 0xfd, 0xde, 0x04, 0x05, 0xf0, 0x31, + 0xfa, 0x0b, 0xdc, 0x0d, 0xed, 0xf5, 0xfa, 0xf4, 0x08, 0x0c, 0xd7, 0x1e, + 0x15, 0x03, 0xf5, 0x02, 0xf4, 0xfb, 0xed, 0x01, 0xfe, 0xd6, 0x1f, 0xfd, + 0xfd, 0x0e, 0xfa, 0x06, 0xf1, 0xf9, 0xe2, 0x16, 0xe9, 0xf1, 0x03, 0x0d, + 0x0d, 0xdf, 0xf9, 0x1a, 0x0e, 0xf6, 0xfc, 0x0a, 0x19, 0xe2, 0xe0, 0x09, + 0x15, 0xf0, 0xf1, 0x06, 0xf1, 0xe1, 0xef, 0x1a, 0x08, 0xe8, 0xfd, 0x12, + 0x14, 0x06, 0xf1, 0xfc, 0xea, 0xfb, 0xf7, 0xea, 0x1d, 0x09, 0xfa, 0xf6, + 0x08, 0xf2, 0xe7, 0xf8, 0xfc, 0x16, 0xf5, 0x0e, 0x08, 0xf9, 0x0a, 0x03, + 0x26, 0xd8, 0x02, 0xf5, 0xf6, 0xf6, 0xef, 0x1f, 0xe4, 0xe2, 0xfb, 0x02, + 0x1b, 0xe6, 0xde, 0x00, 0xf2, 0xed, 0xfb, 0x18, 0xe4, 0x16, 0x1a, 0x1d, + 0xf1, 0xf6, 0xea, 0x16, 0x05, 0xde, 0xfb, 0x18, 0xf5, 0xe4, 0xfe, 0xe2, + 0x1b, 0x1c, 0x0c, 0xe8, 0x02, 0xee, 0xfb, 0x07, 0x24, 0xf2, 0xe9, 0xfa, + 0x0d, 0x05, 0xf1, 0x03, 0xfe, 0xf6, 0x19, 0x06, 0xff, 0xf9, 0x04, 0xfb, + 0x15, 0xef, 0xf1, 0xf8, 0xe9, 0xe1, 0x10, 0x04, 0xfc, 0xe6, 0x1f, 0xed, + 0x0b, 0xef, 0x00, 0x1e, 0xe6, 0x16, 0xf3, 0x09, 0xfd, 0x08, 0x08, 0x06, + 0x06, 0x23, 0xdf, 0xfc, 0x08, 0xf4, 0xea, 0x0c, 0xf2, 0xe6, 0x18, 0xf5, + 0x02, 0xf9, 0x50, 0x09, 0x01, 0xda, 0x0b, 0x05, 0x12, 0x18, 0xef, 0x04, + 0x0e, 0xd9, 0xff, 0xdc, 0xf6, 0x16, 0xf9, 0xf4, 0xec, 0xff, 0xea, 0xe6, + 0xfa, 0x0a, 0xed, 0xef, 0x02, 0xf0, 0x25, 0x21, 0xf1, 0x26, 0xf5, 0xed, + 0x09, 0xea, 0xea, 0x24, 0xfa, 0x11, 0xfc, 0xdf, 0xf3, 0x0a, 0x28, 0x0c, + 0x19, 0xff, 0xf5, 0xd6, 0x0e, 0xe2, 0x2a, 0x06, 0xfa, 0x03, 0xf9, 0xe6, + 0xef, 0x23, 0xf9, 0xfa, 0xe6, 0xfe, 0xfc, 0x03, 0x06, 0x1a, 0xf9, 0x08, + 0xe0, 0xe5, 0xff, 0x05, 0x01, 0xe7, 0x12, 0x02, 0x1d, 0x05, 0x03, 0x05, + 0x0b, 0xee, 0xed, 0xfc, 0x0f, 0xf3, 0x02, 0xe0, 0x15, 0xdf, 0x02, 0xed, + 0x10, 0x26, 0xef, 0x0d, 0x06, 0xee, 0xef, 0xf6, 0xeb, 0x11, 0x09, 0xf4, + 0xf7, 0x06, 0x0f, 0x01, 0x2a, 0x0b, 0x01, 0xdd, 0xfc, 0xf4, 0xf1, 0x17, + 0x03, 0x04, 0x07, 0xfc, 0x22, 0xfc, 0xde, 0xfe, 0x0b, 0x03, 0xf3, 0xfb, + 0x0c, 0x25, 0x04, 0x19, 0x04, 0x03, 0x01, 0xfa, 0xfb, 0xf7, 0xf6, 0x0e, + 0x15, 0x0e, 0x09, 0xff, 0x06, 0xfa, 0xfb, 0x1e, 0xfb, 0x05, 0x22, 0xf9, + 0xfe, 0xf7, 0x1d, 0xed, 0xdf, 0x18, 0x09, 0xeb, 0xef, 0x04, 0x12, 0xea, + 0xdf, 0xfb, 0xda, 0xf6, 0xdf, 0x17, 0xef, 0xef, 0xe1, 0x1a, 0xd9, 0xe2, + 0xe2, 0xfc, 0x05, 0x11, 0xf6, 0xee, 0xe8, 0xf2, 0xe1, 0x08, 0x26, 0x04, + 0xed, 0x03, 0xe0, 0xfb, 0xee, 0x0c, 0xee, 0xf6, 0x04, 0x2d, 0xf2, 0xd3, + 0xf4, 0xe0, 0xf8, 0x0c, 0xfe, 0x11, 0x0b, 0xd7, 0xfd, 0x18, 0x07, 0x0d, + 0x07, 0x08, 0xf4, 0xc6, 0x0a, 0x0a, 0x1f, 0x0c, 0xf4, 0x1d, 0x02, 0x0b, + 0x09, 0x0e, 0x21, 0xff, 0x17, 0x0b, 0x0d, 0xf2, 0xed, 0xd7, 0x0a, 0xf8, + 0x03, 0x06, 0xfa, 0xe5, 0xfd, 0x03, 0x14, 0x0f, 0xe9, 0x1a, 0xf4, 0xda, + 0x01, 0xe6, 0x09, 0x06, 0x11, 0x0d, 0xfd, 0xeb, 0x16, 0x23, 0xfa, 0x00, + 0x0b, 0x17, 0xf7, 0xda, 0xd7, 0x1b, 0xfa, 0x01, 0x03, 0x05, 0xfe, 0xd6, + 0x02, 0xee, 0xee, 0x02, 0xf3, 0x06, 0xed, 0x03, 0xec, 0x01, 0xf2, 0x0f, + 0x05, 0x17, 0x0b, 0xfb, 0x0f, 0x05, 0x03, 0x13, 0xff, 0x06, 0x02, 0xf5, + 0xf4, 0x18, 0x2b, 0xf0, 0x00, 0x17, 0xfc, 0xfd, 0x05, 0x0b, 0x0e, 0x14, + 0xe1, 0x24, 0x08, 0x24, 0xe6, 0xeb, 0x21, 0x12, 0xfb, 0x12, 0xe7, 0xf4, + 0xe8, 0x0e, 0x18, 0xee, 0xf5, 0xf3, 0xd9, 0xf3, 0xdb, 0xec, 0x0c, 0x1e, + 0xcf, 0x14, 0xdb, 0xe3, 0xdc, 0x02, 0x0c, 0xfb, 0xdb, 0x1b, 0xd0, 0xfe, + 0xf9, 0xfe, 0x2a, 0xf5, 0x00, 0x0b, 0xcd, 0xe0, 0xe2, 0x0e, 0x04, 0xf8, + 0xda, 0x1c, 0xe5, 0x0f, 0xe8, 0xf4, 0xf7, 0x15, 0x06, 0xf8, 0x02, 0xf7, + 0x0f, 0xfb, 0x17, 0xf9, 0xda, 0x01, 0xda, 0xd1, 0xf6, 0x02, 0xfd, 0x16, + 0xf1, 0xe4, 0xfa, 0x07, 0xee, 0x0a, 0xf3, 0xfd, 0xf2, 0x23, 0xf0, 0xe1, + 0x0a, 0x1a, 0x12, 0x1f, 0xef, 0x27, 0x09, 0xf1, 0x0c, 0x13, 0x23, 0xfd, + 0xf5, 0x03, 0xfe, 0x09, 0xfd, 0x16, 0xf8, 0x07, 0x08, 0x25, 0x08, 0xf8, + 0xf6, 0x0a, 0xf1, 0xf5, 0x07, 0x09, 0x05, 0xcc, 0xf8, 0x08, 0x13, 0xf9, + 0x1d, 0x11, 0x0f, 0xdc, 0xee, 0xf3, 0x27, 0xf9, 0xf9, 0x22, 0xfa, 0x0d, + 0xe2, 0x13, 0xfb, 0x11, 0x03, 0x1e, 0xff, 0xfb, 0xed, 0xf1, 0x0e, 0x0b, + 0x0f, 0x00, 0x06, 0xe0, 0x15, 0xf3, 0x13, 0xfc, 0x18, 0xf9, 0xff, 0x09, + 0xfa, 0x1f, 0x12, 0xe5, 0xe2, 0x06, 0xf9, 0xf4, 0x07, 0x15, 0x0b, 0x04, + 0xdb, 0x0d, 0xeb, 0xf3, 0xe6, 0x06, 0xe5, 0xee, 0xd8, 0x22, 0xd8, 0x10, + 0xea, 0xf9, 0x1c, 0xf7, 0xd3, 0x11, 0xc3, 0xf8, 0xde, 0x05, 0x00, 0xe6, + 0x07, 0xfd, 0xd3, 0x03, 0xea, 0xe0, 0x13, 0x14, 0xcf, 0xeb, 0xcd, 0xd3, + 0xde, 0xf5, 0xf0, 0x0c, 0x0c, 0xfa, 0xeb, 0xd3, 0xfb, 0xfd, 0x08, 0xf9, + 0xf4, 0x10, 0xfa, 0xd3, 0xf4, 0x11, 0x11, 0xf8, 0xef, 0xf8, 0xf8, 0xf1, + 0xfc, 0xe1, 0xf7, 0x12, 0x04, 0xf4, 0xfb, 0xed, 0xef, 0x0c, 0xfd, 0x1c, + 0xfe, 0x0e, 0xfd, 0xe2, 0xfe, 0x0a, 0x02, 0xfe, 0xe6, 0x1f, 0xef, 0xe5, + 0xe6, 0xf8, 0x16, 0x27, 0xe8, 0x20, 0x05, 0xe3, 0xf1, 0xef, 0xee, 0xed, + 0x0d, 0x11, 0x16, 0xfb, 0xf3, 0xff, 0x14, 0x01, 0xff, 0x15, 0x10, 0x02, + 0xe5, 0x28, 0x29, 0x13, 0x13, 0x16, 0xe6, 0x00, 0xd2, 0x26, 0xfd, 0x03, + 0x04, 0x05, 0x07, 0x06, 0xf1, 0x0e, 0x05, 0x0d, 0xe2, 0x0f, 0x02, 0xe1, + 0x07, 0xf7, 0x1c, 0xfa, 0x14, 0x30, 0xf7, 0xee, 0x00, 0xfa, 0x3d, 0x06, + 0x1c, 0x04, 0x06, 0x07, 0x05, 0x1a, 0x10, 0xf6, 0xee, 0x0a, 0xeb, 0x04, + 0xeb, 0xdf, 0x1d, 0x09, 0xd5, 0xe8, 0xd6, 0xf4, 0xf0, 0x0f, 0x1d, 0xea, + 0xf2, 0xf8, 0xa6, 0x0b, 0xdc, 0x09, 0x08, 0x24, 0xee, 0x24, 0xaa, 0xe4, + 0xcb, 0x15, 0xef, 0xe7, 0xe9, 0x0c, 0xcf, 0x06, 0xe3, 0x12, 0x11, 0x00, + 0x07, 0x14, 0xd7, 0xde, 0xf6, 0x0f, 0x0b, 0x04, 0xfb, 0x0d, 0xf8, 0x0d, + 0xf6, 0x1b, 0xf1, 0x21, 0xdd, 0xfc, 0xf4, 0xe9, 0xf8, 0xe8, 0xf7, 0x06, + 0x03, 0x1e, 0xce, 0xe1, 0xea, 0xf6, 0x05, 0xf9, 0x16, 0x15, 0x04, 0xe0, + 0x14, 0xf7, 0x1e, 0x1c, 0x0a, 0x27, 0xef, 0xf3, 0x0f, 0xf3, 0xee, 0x04, + 0xf8, 0xf1, 0x07, 0xe3, 0x05, 0x0b, 0x00, 0x1c, 0x15, 0x27, 0x07, 0xf7, + 0xfa, 0x0b, 0xfa, 0xfa, 0x17, 0x13, 0xe1, 0xf5, 0xfb, 0x0c, 0x21, 0x2f, + 0xd7, 0xfb, 0xf5, 0xfd, 0xd3, 0xf4, 0x07, 0x0e, 0xfd, 0x0b, 0xfc, 0xfa, + 0xf5, 0x0e, 0x02, 0xfa, 0xfa, 0x19, 0xfd, 0xfa, 0xfc, 0x13, 0x24, 0x0c, + 0xe4, 0x31, 0xf8, 0x12, 0xf4, 0x04, 0x18, 0x29, 0x27, 0x19, 0xfc, 0x08, + 0x11, 0xe3, 0x07, 0xfe, 0x26, 0x40, 0x05, 0x02, 0x04, 0x02, 0x0f, 0xee, + 0xf4, 0x27, 0xea, 0xf4, 0xf5, 0x11, 0x26, 0x0b, 0xe7, 0x05, 0xd2, 0xf6, + 0xea, 0xfa, 0x0b, 0xf9, 0xfa, 0x16, 0xba, 0x00, 0xfb, 0x0d, 0x0b, 0xf9, + 0xe6, 0xf6, 0xc5, 0xf8, 0xf6, 0x01, 0x0f, 0xed, 0xed, 0x13, 0xcd, 0x0d, + 0xda, 0x06, 0x17, 0xee, 0x07, 0x1d, 0xb8, 0xfa, 0xe2, 0xea, 0xf2, 0xee, + 0x04, 0x00, 0xdc, 0xd0, 0xfb, 0xf5, 0xec, 0xfe, 0xf1, 0x0d, 0xf0, 0xdb, + 0xf9, 0x0d, 0x03, 0x03, 0x0e, 0x0a, 0xda, 0xd6, 0x01, 0xf2, 0x06, 0x14, + 0x1c, 0x1f, 0xe8, 0xe8, 0x0e, 0xfd, 0x0c, 0xf5, 0xf3, 0x3d, 0xf3, 0x05, + 0x10, 0xfa, 0x1b, 0x18, 0x08, 0x36, 0x09, 0xf1, 0xeb, 0xf9, 0x22, 0x01, + 0xf3, 0xf7, 0xff, 0xf0, 0x0c, 0xe9, 0x01, 0x29, 0x21, 0x15, 0x03, 0xee, + 0xe9, 0x1a, 0xf7, 0x15, 0x06, 0x25, 0xfa, 0xf0, 0xe4, 0xf1, 0x1f, 0x01, + 0xdc, 0x2d, 0xce, 0xe9, 0xea, 0x0b, 0x06, 0x2c, 0x0a, 0x30, 0xe7, 0x09, + 0xf4, 0xf0, 0x10, 0x29, 0xf9, 0x3d, 0xe7, 0xdc, 0xe4, 0xf7, 0x3b, 0x27, + 0x23, 0x3a, 0x0a, 0x06, 0x0e, 0xfd, 0x2c, 0x07, 0x2b, 0x1c, 0xfa, 0x00, + 0xf9, 0x11, 0xea, 0x14, 0xeb, 0xfc, 0x18, 0x03, 0xf1, 0x16, 0x12, 0x04, + 0xcf, 0x12, 0xdd, 0xe4, 0x0e, 0xf0, 0x09, 0xe8, 0xf3, 0xfb, 0xa8, 0xf9, + 0xee, 0xfb, 0x1e, 0x1d, 0xfd, 0x05, 0xab, 0xe5, 0xff, 0x01, 0xfe, 0x04, + 0xf9, 0x02, 0xb9, 0xdc, 0xdf, 0x05, 0xf1, 0xef, 0xf1, 0x1e, 0xc7, 0xee, + 0xf7, 0x1e, 0x00, 0x00, 0xf8, 0x10, 0xec, 0xe8, 0x04, 0x0f, 0xf6, 0xff, + 0x04, 0x09, 0xe0, 0x0a, 0x0e, 0xe4, 0xf0, 0xf1, 0x16, 0x2b, 0xd3, 0xe1, + 0x0a, 0xef, 0xf9, 0xfe, 0x0b, 0x22, 0xf5, 0x01, 0x0a, 0xf8, 0x02, 0x00, + 0x17, 0x19, 0xf3, 0x05, 0x21, 0xfa, 0xee, 0xee, 0x12, 0xf2, 0xfa, 0xf5, + 0x05, 0x12, 0xee, 0xe4, 0x28, 0xfa, 0xf1, 0x03, 0x15, 0x16, 0x18, 0xfd, + 0x0f, 0x21, 0x04, 0xf4, 0xe5, 0x0c, 0x06, 0x13, 0xde, 0x36, 0xe8, 0xfb, + 0xe7, 0xfd, 0xf6, 0x12, 0x0e, 0x1d, 0xea, 0xf8, 0xd4, 0xe8, 0x19, 0x07, + 0xe5, 0x1c, 0xf7, 0x0c, 0xef, 0x05, 0x0f, 0x09, 0xdd, 0x1a, 0xea, 0xd7, + 0xf9, 0xf9, 0x12, 0x17, 0x2e, 0x10, 0x08, 0xfe, 0x14, 0xf5, 0x1d, 0xfa, + 0x06, 0x33, 0xed, 0xfe, 0xf7, 0x11, 0xf0, 0x15, 0xe2, 0x24, 0xf6, 0x0a, + 0xe2, 0xfc, 0x23, 0x12, 0xdd, 0x11, 0xfd, 0xe5, 0x08, 0xff, 0x15, 0xf6, + 0xf1, 0x1b, 0xae, 0xfe, 0xe6, 0x15, 0x2c, 0x2d, 0x15, 0x15, 0xc5, 0xf8, + 0xea, 0xe7, 0x07, 0x04, 0xfe, 0x28, 0xa1, 0xf2, 0xe1, 0xf9, 0xf8, 0xff, + 0xf4, 0x22, 0xb4, 0xdb, 0x03, 0x20, 0xe6, 0xf3, 0x0e, 0x19, 0xe3, 0x0a, + 0xfa, 0xee, 0xf3, 0xe5, 0xd8, 0xf9, 0xf1, 0xde, 0x06, 0x05, 0xf2, 0xf5, + 0xe7, 0x16, 0xd8, 0xfe, 0x07, 0xea, 0xee, 0x0e, 0xfa, 0xff, 0xdb, 0xe7, + 0x03, 0xed, 0x01, 0xfd, 0x09, 0x1a, 0xfa, 0xe6, 0x05, 0x10, 0xe9, 0x01, + 0x1f, 0x13, 0xf7, 0xf6, 0xfb, 0x13, 0xff, 0xdb, 0xed, 0xfe, 0x0a, 0x10, + 0x09, 0x29, 0xf5, 0x04, 0xf5, 0x26, 0x0d, 0x0c, 0xf9, 0x16, 0xfa, 0x02, + 0xf4, 0x2e, 0xde, 0xf5, 0xe1, 0x1d, 0xfb, 0x02, 0x0b, 0x23, 0x07, 0xea, + 0xd9, 0x0a, 0xf3, 0x0a, 0x0f, 0x1e, 0xe7, 0xf1, 0xd7, 0x0b, 0xf6, 0xff, + 0x0d, 0x24, 0xcc, 0x0a, 0xee, 0xda, 0x14, 0x12, 0x11, 0x29, 0xf4, 0x1a, + 0xef, 0x0b, 0xfa, 0xec, 0x0c, 0x1b, 0xf4, 0xff, 0xf5, 0xef, 0x0f, 0x10, + 0xd4, 0x04, 0xf9, 0xf8, 0xec, 0xf9, 0x21, 0x05, 0xd3, 0x27, 0xf3, 0x17, + 0xff, 0xf6, 0x15, 0xf9, 0xed, 0x0a, 0xac, 0x02, 0xfd, 0xfb, 0x04, 0x29, + 0x06, 0x03, 0xb8, 0xe6, 0xd5, 0x17, 0x09, 0x1b, 0xf6, 0x1b, 0xab, 0xdc, + 0xdf, 0xfd, 0x06, 0x09, 0x09, 0x37, 0xbb, 0xed, 0x19, 0xd7, 0xe2, 0xdd, + 0x05, 0x01, 0xec, 0xfb, 0xe4, 0x0e, 0xeb, 0xf0, 0x03, 0x17, 0x04, 0xeb, + 0x09, 0xee, 0xeb, 0xe7, 0x0c, 0x16, 0xcb, 0x0e, 0x17, 0xd8, 0xe1, 0xf8, + 0x2b, 0x19, 0xde, 0xeb, 0x10, 0xf2, 0xff, 0xf8, 0xee, 0x0e, 0xe7, 0xf0, + 0x15, 0x08, 0xf8, 0xdf, 0x06, 0x0d, 0xf9, 0x14, 0xfa, 0x0b, 0x04, 0xfd, + 0x15, 0x23, 0x20, 0xff, 0xfd, 0x1d, 0x0c, 0xf1, 0xfe, 0x15, 0x0a, 0x02, + 0xed, 0xfe, 0xfb, 0x04, 0xfb, 0x1e, 0xdd, 0x05, 0xe0, 0x16, 0xf9, 0xf6, + 0xfd, 0x32, 0xdc, 0xf2, 0xd3, 0x08, 0xf4, 0xec, 0x17, 0x25, 0xe2, 0xf0, + 0xee, 0xf1, 0x0d, 0xfe, 0x13, 0x2d, 0x01, 0x11, 0xd4, 0xe4, 0x07, 0xfb, + 0x32, 0x11, 0x14, 0x07, 0xd7, 0x02, 0x10, 0xeb, 0x2b, 0x1d, 0x01, 0xfc, + 0xf3, 0xf0, 0x13, 0x1a, 0xdb, 0x20, 0x00, 0xf0, 0xf0, 0x05, 0x16, 0x03, + 0xd4, 0xe3, 0xc2, 0xf0, 0x06, 0x02, 0x1e, 0x0a, 0xec, 0x1f, 0xab, 0xea, + 0xfa, 0xe3, 0x20, 0x22, 0x03, 0x1b, 0xb3, 0x0e, 0xe3, 0xf3, 0x1d, 0x27, + 0xe3, 0x10, 0xa7, 0xda, 0xf3, 0x00, 0x0a, 0x0a, 0x04, 0xfb, 0xb2, 0x0f, + 0x0c, 0xf5, 0x07, 0xff, 0x13, 0x1e, 0xdb, 0xf6, 0xf9, 0xef, 0xe8, 0xe7, + 0xfb, 0x18, 0xeb, 0xec, 0x09, 0xda, 0xf1, 0xf0, 0x0b, 0x04, 0xe1, 0xfa, + 0x1c, 0x25, 0xee, 0x01, 0x0b, 0x29, 0xd7, 0x0c, 0x04, 0x0b, 0xef, 0xfd, + 0x1c, 0xfc, 0xf1, 0xfb, 0x0b, 0x0f, 0xdf, 0xed, 0x17, 0x38, 0x0c, 0xd7, + 0xff, 0xfd, 0x01, 0xfc, 0xfb, 0xfb, 0x18, 0x1a, 0x18, 0xe3, 0xf9, 0xf4, + 0xfa, 0x20, 0x06, 0x09, 0x11, 0x08, 0x1d, 0xf8, 0xfa, 0x1d, 0xf5, 0x1c, + 0xf5, 0xfe, 0x03, 0x07, 0xe4, 0x33, 0xc8, 0x0c, 0xe1, 0x13, 0xff, 0xe5, + 0x10, 0x2c, 0xd3, 0xf0, 0xed, 0x04, 0x07, 0x01, 0xf1, 0x16, 0xe0, 0x13, + 0xfa, 0x11, 0x07, 0xfa, 0x19, 0x16, 0x01, 0x00, 0x07, 0x26, 0x00, 0xec, + 0x1d, 0x23, 0x05, 0xf4, 0x07, 0x17, 0x2c, 0x1d, 0xee, 0xf0, 0x0c, 0x09, + 0xe3, 0x1a, 0x24, 0x0b, 0xf3, 0x1e, 0xce, 0xfe, 0xfe, 0x12, 0x21, 0x1a, + 0xf6, 0x23, 0xc3, 0x03, 0xf4, 0x10, 0x1a, 0x2a, 0xf4, 0x08, 0xbf, 0xff, + 0x04, 0xf4, 0x0b, 0x1d, 0x1a, 0xf8, 0xcc, 0x00, 0xf7, 0x13, 0xf4, 0xfd, + 0xf4, 0x19, 0xbd, 0xef, 0x0c, 0x0d, 0x02, 0xfc, 0x12, 0x13, 0xe9, 0xe7, + 0xf5, 0xfa, 0xfa, 0xf6, 0x1a, 0x2e, 0xce, 0xd4, 0x01, 0x12, 0xfd, 0xfc, + 0x26, 0x10, 0xcc, 0xe7, 0xee, 0x13, 0xee, 0xff, 0xef, 0xea, 0x00, 0x0e, + 0x1a, 0x17, 0x04, 0x0c, 0x04, 0x0c, 0xe6, 0xf3, 0xf6, 0xdb, 0xdd, 0x04, + 0xf4, 0x22, 0x11, 0x16, 0xf3, 0x07, 0xec, 0xf8, 0xf2, 0x07, 0x03, 0x02, + 0xf5, 0x0a, 0xf6, 0x02, 0x1d, 0x1b, 0x11, 0x06, 0xf8, 0x06, 0x02, 0xea, + 0xf3, 0x1d, 0xce, 0x00, 0xed, 0xf9, 0xef, 0xf6, 0xec, 0x22, 0xc7, 0xf0, + 0xed, 0xdb, 0xe0, 0x02, 0x11, 0x07, 0xe8, 0xf0, 0xd1, 0xed, 0xff, 0xfd, + 0x0c, 0x2e, 0xd4, 0xed, 0xec, 0x0e, 0xf1, 0x07, 0x01, 0x0e, 0x0e, 0xfe, + 0xda, 0x0b, 0x0a, 0x0a, 0x1f, 0x2e, 0x13, 0x07, 0x00, 0x07, 0x14, 0x21, + 0xe9, 0xfc, 0xf0, 0x1e, 0xd7, 0xea, 0x34, 0x07, 0xc6, 0x0c, 0xd4, 0xec, + 0xfd, 0x06, 0x24, 0x0a, 0xf3, 0x15, 0xaf, 0xff, 0xe9, 0xf1, 0x0d, 0x3e, + 0xe9, 0x18, 0xba, 0x13, 0xed, 0xd7, 0x0b, 0x31, 0x05, 0x0e, 0xaf, 0x13, + 0xd6, 0x0e, 0x10, 0x02, 0x02, 0x14, 0xcb, 0xd5, 0xf9, 0x0c, 0xf9, 0x0e, + 0x1f, 0x24, 0xd5, 0xeb, 0xff, 0xf1, 0xf5, 0x0c, 0x08, 0x07, 0xf4, 0xd7, + 0x06, 0x10, 0xe8, 0xef, 0xfc, 0x2f, 0xee, 0xf1, 0x18, 0xf8, 0xf4, 0x02, + 0x11, 0x21, 0xd3, 0x12, 0x14, 0xe4, 0xf4, 0x02, 0x05, 0x24, 0xca, 0xf2, + 0xf3, 0xeb, 0xe7, 0xf8, 0x16, 0x1a, 0xeb, 0x0d, 0x05, 0x16, 0xf1, 0xec, + 0x11, 0x1c, 0x09, 0x1e, 0xe0, 0xe6, 0xfa, 0x0e, 0x0d, 0x2a, 0xea, 0x2e, + 0xed, 0xf9, 0xf7, 0x16, 0x09, 0x05, 0xdd, 0xd6, 0x02, 0xeb, 0xf5, 0xf3, + 0xe4, 0x3b, 0xed, 0x04, 0xe0, 0x0e, 0xfd, 0x09, 0xfd, 0x35, 0xdc, 0x18, + 0xf3, 0x04, 0xfa, 0x05, 0x15, 0x34, 0xe5, 0xe1, 0xe4, 0xf4, 0xe0, 0xf9, + 0x08, 0x32, 0x04, 0x08, 0xf4, 0x0f, 0xff, 0x08, 0x09, 0x2f, 0x06, 0x02, + 0xfd, 0x05, 0x0c, 0x24, 0xe3, 0x1e, 0xf5, 0x0c, 0xdd, 0xf8, 0x18, 0x20, + 0xd8, 0x14, 0xef, 0xf4, 0x17, 0x08, 0x25, 0x14, 0x04, 0x06, 0xb0, 0xf5, + 0xf5, 0x09, 0x0f, 0x3e, 0xff, 0x28, 0xb3, 0xf5, 0x19, 0xd8, 0x14, 0x21, + 0xd9, 0xf7, 0xb7, 0xe5, 0xfe, 0xe7, 0x07, 0x1e, 0x04, 0x15, 0xc5, 0xf9, + 0x14, 0x20, 0xeb, 0x01, 0x01, 0x18, 0xce, 0x00, 0xe6, 0xe2, 0xf7, 0xfb, + 0xf3, 0x0d, 0xd3, 0xf3, 0x04, 0xf8, 0xf0, 0x03, 0xf1, 0x25, 0xb5, 0xef, + 0x05, 0xe0, 0x01, 0xf6, 0x04, 0x16, 0xd1, 0x01, 0x0a, 0x21, 0x01, 0x05, + 0x0e, 0x01, 0xf0, 0x0a, 0xf3, 0x00, 0x03, 0xf8, 0xfa, 0x03, 0x0b, 0xde, + 0xfe, 0xff, 0xfb, 0xea, 0x09, 0x02, 0xf5, 0xe8, 0xe7, 0x08, 0x00, 0xf5, + 0xf8, 0x0f, 0x13, 0xfa, 0xeb, 0xe8, 0xfb, 0x1f, 0x08, 0x16, 0xe6, 0xfa, + 0xe1, 0x00, 0x03, 0xdd, 0xf1, 0x26, 0xe5, 0x1d, 0xd9, 0xff, 0xf2, 0xf8, + 0xff, 0x33, 0xea, 0xe5, 0x03, 0x0c, 0x07, 0xf9, 0xf8, 0x0f, 0xe1, 0x1e, + 0xdd, 0x0f, 0x00, 0xf1, 0x06, 0x21, 0x09, 0x05, 0xf3, 0xec, 0xe6, 0x04, + 0x07, 0x32, 0xf1, 0xf9, 0xf2, 0x01, 0x18, 0x1f, 0xd2, 0xe2, 0x0a, 0xf4, + 0xca, 0xfc, 0x28, 0x16, 0xc2, 0x10, 0xf2, 0xfc, 0x08, 0xe9, 0x2a, 0x0f, + 0xfa, 0xf5, 0xa9, 0x07, 0xec, 0xe9, 0x19, 0x43, 0x0b, 0x1c, 0xa6, 0xe9, + 0xf4, 0x16, 0x0d, 0x2b, 0xfc, 0x11, 0x9a, 0xe1, 0xf1, 0x1c, 0xf5, 0x0f, + 0xe4, 0x18, 0xc0, 0xd9, 0x14, 0x26, 0xe6, 0xf8, 0x0a, 0x17, 0xec, 0xfb, + 0xe1, 0x22, 0xdf, 0xf2, 0xfe, 0x1e, 0xd4, 0xeb, 0xd7, 0x0e, 0x08, 0xf6, + 0xef, 0xfc, 0xe6, 0xd4, 0xf7, 0x0b, 0xfb, 0xf5, 0x01, 0x25, 0xd7, 0xfb, + 0x0d, 0xfe, 0xff, 0xf3, 0x1d, 0x32, 0xfe, 0xee, 0x12, 0xf2, 0x0c, 0xec, + 0x02, 0x10, 0xef, 0x01, 0xf2, 0x0b, 0xf3, 0xf7, 0xfa, 0x25, 0xfb, 0x0d, + 0x11, 0x15, 0x04, 0xfc, 0x0c, 0x21, 0x12, 0x29, 0x00, 0xfa, 0xf6, 0xf5, + 0x06, 0x22, 0xea, 0xe2, 0xee, 0x00, 0xfd, 0xf0, 0x0b, 0x1d, 0xd3, 0xe4, + 0xe4, 0x0a, 0xfc, 0xe8, 0xea, 0x2c, 0xed, 0xed, 0xef, 0xe8, 0xf2, 0x05, + 0xfd, 0x15, 0xd8, 0xda, 0xca, 0xee, 0xfa, 0x00, 0xfe, 0x0e, 0xf2, 0xf0, + 0x0e, 0xf5, 0x04, 0x03, 0x1d, 0x2b, 0xee, 0x05, 0x0f, 0x10, 0x13, 0x35, + 0xe2, 0x04, 0x10, 0xdf, 0xcf, 0xeb, 0x40, 0x26, 0xe4, 0x03, 0xf3, 0xf9, + 0xf5, 0x14, 0x24, 0x2a, 0xdf, 0xfe, 0xab, 0xe5, 0xfe, 0x1c, 0x27, 0x35, + 0xdb, 0xff, 0xac, 0x01, 0xf6, 0xfc, 0x19, 0x1a, 0x11, 0x1f, 0xa8, 0xf5, + 0x02, 0x0f, 0x1a, 0x1f, 0xf7, 0xf2, 0xa2, 0x00, 0x15, 0x22, 0xe4, 0x13, + 0x00, 0x09, 0xd9, 0xd5, 0x02, 0x19, 0xfd, 0xf8, 0xe7, 0xff, 0xfb, 0xe0, + 0xef, 0xf7, 0xee, 0xf3, 0xf3, 0x19, 0xb0, 0xdf, 0x00, 0x0f, 0x08, 0xf3, + 0x15, 0x17, 0xec, 0x0f, 0x11, 0x14, 0x02, 0x08, 0x10, 0x17, 0xe6, 0x08, + 0xf7, 0x00, 0xed, 0xf7, 0x29, 0x07, 0x10, 0x05, 0x05, 0xe7, 0xed, 0xf4, + 0xf9, 0x15, 0xf9, 0xf0, 0x08, 0x00, 0x03, 0x09, 0x21, 0x28, 0xf6, 0x0e, + 0xfb, 0xf3, 0x03, 0xf7, 0x0f, 0x0c, 0xf0, 0xf5, 0xe3, 0xd8, 0xf8, 0xf2, + 0x09, 0x1c, 0xe7, 0xfb, 0xe4, 0xf6, 0xfa, 0xf8, 0xf1, 0x42, 0xf6, 0xda, + 0xdd, 0xd7, 0xfa, 0xff, 0x2f, 0x2c, 0xda, 0x0a, 0xde, 0xec, 0xf1, 0x14, + 0xfb, 0x1d, 0xeb, 0xee, 0xf2, 0xeb, 0xf3, 0xed, 0x0e, 0x35, 0xf0, 0x06, + 0x19, 0x04, 0x2f, 0x23, 0xe2, 0x07, 0x13, 0x0f, 0xe9, 0xf0, 0x22, 0x2e, + 0xd9, 0x1a, 0xcb, 0xed, 0xfd, 0x04, 0x27, 0x1e, 0xf6, 0x07, 0x96, 0xd6, + 0xd8, 0x11, 0x18, 0x56, 0xd2, 0xfb, 0x92, 0xfc, 0x0b, 0x0a, 0x17, 0x2c, + 0xe5, 0x04, 0xa2, 0xf8, 0xe2, 0x04, 0x1a, 0x0d, 0xeb, 0x11, 0xa2, 0xe5, + 0xe5, 0xf8, 0x02, 0xf7, 0x17, 0x03, 0xca, 0xe9, 0x0c, 0x1f, 0xfe, 0xf5, + 0x18, 0x12, 0xdd, 0x08, 0x15, 0xff, 0xfc, 0xf6, 0xe1, 0x1d, 0xe2, 0xe1, + 0xfe, 0xfc, 0x03, 0xff, 0xf2, 0x23, 0xd2, 0x01, 0x13, 0xdd, 0xf3, 0xf4, + 0xf2, 0x07, 0xef, 0x03, 0x15, 0x21, 0xd8, 0xf8, 0x09, 0xf3, 0xe8, 0xea, + 0xe8, 0xf2, 0x08, 0xf0, 0x04, 0x1a, 0xf2, 0x19, 0xfb, 0x1b, 0x15, 0xfc, + 0x1d, 0x30, 0xe5, 0x1e, 0x09, 0xe8, 0xe9, 0x09, 0xf7, 0x2a, 0xe1, 0x0e, + 0x00, 0x21, 0xf3, 0xff, 0xfb, 0x01, 0xdf, 0xf2, 0xfe, 0xf4, 0xfc, 0xf0, + 0x0b, 0x0b, 0xdd, 0xe4, 0xd2, 0x14, 0xf7, 0xfe, 0x0b, 0x39, 0x01, 0xe6, + 0xe4, 0x27, 0xfa, 0xe4, 0x04, 0x2c, 0xe2, 0x04, 0xf5, 0x07, 0xf2, 0x03, + 0xf0, 0x10, 0xf5, 0xf6, 0xfc, 0x16, 0x22, 0x1b, 0xf8, 0x11, 0xe4, 0x09, + 0xf6, 0xf0, 0x41, 0x1e, 0xcf, 0x04, 0xea, 0xee, 0x0e, 0xf6, 0x1b, 0x2f, + 0xc7, 0xf1, 0xba, 0xef, 0x0f, 0x16, 0x1e, 0x39, 0x05, 0x1e, 0x90, 0xe6, + 0x0d, 0xfa, 0x22, 0x3f, 0xe3, 0x23, 0xa5, 0xe3, 0xe9, 0x0f, 0x05, 0x27, + 0x02, 0x11, 0x99, 0x05, 0xfa, 0x05, 0x03, 0x01, 0xff, 0x26, 0xd3, 0xf7, + 0xf7, 0xf9, 0x05, 0xf4, 0xef, 0x23, 0xd2, 0xdd, 0x05, 0x08, 0xfa, 0xff, + 0x03, 0x04, 0xbd, 0xd7, 0x14, 0x06, 0xef, 0x06, 0xe5, 0x05, 0xea, 0xea, + 0x02, 0xfd, 0x0d, 0x00, 0x08, 0xff, 0xe7, 0xfb, 0xfe, 0x13, 0xfe, 0xec, + 0xf9, 0x02, 0xf3, 0xff, 0xff, 0x08, 0x04, 0xed, 0x19, 0x1d, 0xfa, 0x0a, + 0x0d, 0xf2, 0x0f, 0xec, 0x25, 0x1c, 0xec, 0x0b, 0x01, 0xff, 0x01, 0xf6, + 0x08, 0x09, 0xe8, 0xe2, 0xec, 0x23, 0xe5, 0xe9, 0xf0, 0x2e, 0xbd, 0xe1, + 0xef, 0x14, 0xe9, 0xf6, 0xf5, 0x1d, 0xdc, 0xe3, 0xd7, 0xfc, 0xf9, 0xf2, + 0xfe, 0x24, 0xf2, 0x05, 0xd5, 0xed, 0xe9, 0xf9, 0xfa, 0x2d, 0xf0, 0xfe, + 0xee, 0xf2, 0xe8, 0xf7, 0x06, 0x14, 0x01, 0x10, 0x06, 0xf3, 0x0e, 0x0e, + 0xc2, 0x1d, 0xf2, 0x1c, 0xed, 0xe3, 0x53, 0x21, 0xb8, 0x0c, 0xde, 0x03, + 0x15, 0xeb, 0x46, 0x39, 0xdf, 0xf6, 0xa3, 0xee, 0xf6, 0xe0, 0x33, 0x50, + 0xdd, 0x27, 0x9f, 0x07, 0x13, 0xe2, 0x1f, 0x35, 0xed, 0x1f, 0xb7, 0x07, + 0x11, 0xed, 0x17, 0x28, 0xf4, 0x20, 0xc1, 0xec, 0xef, 0x16, 0x02, 0xfa, + 0xe0, 0x1b, 0xf7, 0xdb, 0xfd, 0x0a, 0xe7, 0xfb, 0xe7, 0x25, 0xe2, 0xe7, + 0xf8, 0xf0, 0xee, 0xe9, 0x02, 0x06, 0xc9, 0xe4, 0x14, 0xe3, 0xe2, 0xf7, + 0xf8, 0xfd, 0xdd, 0xe2, 0x08, 0x0a, 0xe4, 0x05, 0xf5, 0x16, 0xe7, 0x01, + 0x00, 0x1c, 0xe7, 0xf0, 0xf6, 0x19, 0xfe, 0x0c, 0xf2, 0x06, 0x03, 0xe8, + 0x0b, 0xfe, 0xe3, 0x19, 0x08, 0x1a, 0x10, 0xfd, 0x00, 0x21, 0xf0, 0xeb, + 0x18, 0x02, 0xf3, 0x04, 0xf0, 0x18, 0xdb, 0x05, 0x01, 0xde, 0xed, 0xe9, + 0x23, 0x15, 0xaf, 0xe6, 0xf1, 0x0a, 0xe6, 0xea, 0x01, 0x18, 0xd8, 0xfd, + 0xf1, 0xe6, 0xec, 0xf5, 0x0e, 0x1e, 0xcc, 0xfc, 0xe7, 0x00, 0xe9, 0x11, + 0x00, 0x30, 0xf9, 0x14, 0xf4, 0x19, 0xdd, 0xf7, 0xf7, 0x2f, 0xf4, 0xf2, + 0xff, 0x27, 0x15, 0x1c, 0xbc, 0x2f, 0xe9, 0x14, 0xf5, 0xe8, 0x44, 0x30, + 0xe8, 0x1d, 0xe4, 0x18, 0x11, 0x00, 0x0c, 0x2b, 0xf3, 0x29, 0x96, 0xe0, + 0x06, 0xee, 0x3e, 0x55, 0xdc, 0x13, 0x98, 0xdf, 0xf0, 0xfe, 0x17, 0x33, + 0xe8, 0x09, 0xa3, 0x07, 0xef, 0x0e, 0x1d, 0x37, 0xdd, 0xfe, 0xb5, 0x00, + 0xf7, 0xe0, 0xea, 0xfd, 0xfd, 0x19, 0xbc, 0xfd, 0x15, 0xfe, 0x01, 0xf3, + 0xd5, 0x20, 0xbf, 0xe3, 0x15, 0x0e, 0xf0, 0xf6, 0xf2, 0x14, 0xcc, 0xf0, + 0xf7, 0x04, 0xf2, 0xff, 0x0b, 0x02, 0xd2, 0xd8, 0xfa, 0xfc, 0xe5, 0x02, + 0x00, 0xfb, 0xf0, 0xdc, 0x1e, 0x10, 0x02, 0x01, 0x00, 0x18, 0xe9, 0xdb, + 0x1e, 0xf6, 0xfc, 0x03, 0xef, 0x0a, 0x00, 0x16, 0x00, 0x0f, 0xf4, 0x16, + 0xfa, 0x0b, 0xe2, 0xfa, 0xe0, 0x07, 0xfb, 0x02, 0x21, 0x0e, 0xdd, 0x0b, + 0xea, 0xf0, 0xeb, 0xfb, 0x19, 0x09, 0xd4, 0xf2, 0xef, 0x0b, 0x00, 0xeb, + 0x1a, 0x2f, 0xea, 0x06, 0x03, 0xf6, 0xf8, 0xfb, 0xfe, 0x1d, 0xea, 0xdd, + 0xed, 0xfd, 0xfb, 0xe7, 0xfe, 0x18, 0xf4, 0xfc, 0x0b, 0xf6, 0xfc, 0x0b, + 0xfb, 0x28, 0x07, 0xff, 0x07, 0x1e, 0x03, 0x21, 0xcf, 0x22, 0x05, 0xe6, + 0xea, 0xe7, 0x43, 0x2e, 0xe7, 0x14, 0xfb, 0x0a, 0x1e, 0xfe, 0x2c, 0x24, + 0xd5, 0xfd, 0x9e, 0xd1, 0xf2, 0x1c, 0x32, 0x51, 0x01, 0xf3, 0xac, 0xe1, + 0xf4, 0xe5, 0x1c, 0x37, 0xf1, 0x0f, 0xa7, 0xdb, 0x00, 0xf6, 0x0f, 0x18, + 0xe1, 0x10, 0xc9, 0xc5, 0xe8, 0xeb, 0xf2, 0xfd, 0xf6, 0x02, 0xc2, 0xff, + 0x00, 0x19, 0x03, 0x0f, 0x02, 0x22, 0xd4, 0xe7, 0x07, 0x0f, 0xe5, 0x1a, + 0x09, 0x0b, 0xdc, 0xd2, 0x00, 0x05, 0xee, 0xf8, 0xdc, 0x14, 0xd0, 0x0a, + 0x0a, 0xfa, 0xeb, 0x04, 0xf3, 0x06, 0xde, 0x05, 0xfb, 0xfd, 0xe3, 0xec, + 0xfd, 0x14, 0xd7, 0x11, 0x0e, 0xe6, 0x06, 0xec, 0xde, 0x22, 0xd7, 0x00, + 0x03, 0xf5, 0xf5, 0x0d, 0x01, 0x05, 0xea, 0x0b, 0x16, 0x04, 0xff, 0x13, + 0xf3, 0x12, 0xd2, 0xdf, 0x0b, 0xe4, 0x06, 0xf6, 0x08, 0x2d, 0xd3, 0xd6, + 0xe7, 0x0a, 0xec, 0xff, 0xfe, 0x01, 0xdf, 0xf4, 0xdf, 0x1c, 0xfe, 0xf9, + 0xf7, 0x13, 0xca, 0xff, 0x03, 0x06, 0xe9, 0xf7, 0x06, 0x08, 0xd7, 0xf3, + 0xed, 0x08, 0xe3, 0xfd, 0x0c, 0x11, 0x15, 0xfb, 0x15, 0x08, 0x28, 0x40, + 0xe7, 0x0d, 0x08, 0xec, 0xe8, 0x16, 0x67, 0x46, 0xc8, 0x16, 0xf1, 0x02, + 0x24, 0x00, 0x3a, 0x43, 0xd6, 0x12, 0xae, 0xe7, 0xf4, 0xf8, 0x3a, 0x65, + 0xe4, 0x0c, 0xb2, 0xef, 0x1f, 0xe8, 0x29, 0x59, 0xf8, 0x11, 0xc4, 0xe1, + 0xfe, 0xfa, 0x27, 0x43, 0xc9, 0x1e, 0xbb, 0xfb, 0xf3, 0x13, 0x15, 0x0d, + 0xf1, 0x13, 0xcd, 0xf0, 0x07, 0x19, 0x07, 0x00, 0xd8, 0xeb, 0xbf, 0xf0, + 0xfc, 0xf6, 0xef, 0x16, 0x01, 0x02, 0xc1, 0xdf, 0xfd, 0xe9, 0x06, 0x06, + 0xf1, 0x08, 0xd7, 0xcc, 0xfb, 0x0e, 0xfc, 0x14, 0xf2, 0x1a, 0xe2, 0x0d, + 0xeb, 0x09, 0x07, 0x10, 0xe6, 0x13, 0xeb, 0xf5, 0x15, 0x14, 0xeb, 0xfe, + 0xf9, 0x17, 0xd2, 0xe3, 0x1e, 0xf5, 0x04, 0x0a, 0xf1, 0x0e, 0xde, 0xe7, + 0x01, 0x20, 0x0c, 0xfc, 0xdc, 0xf9, 0xe5, 0xe9, 0xff, 0x1d, 0x0a, 0xfe, + 0xec, 0x25, 0xaf, 0xd2, 0x01, 0x16, 0xfc, 0x17, 0xe8, 0x1e, 0xcd, 0xd9, + 0xe2, 0xf1, 0xeb, 0x08, 0xff, 0x33, 0xe5, 0xfb, 0xeb, 0x04, 0xfe, 0xf7, + 0xfd, 0x1f, 0xee, 0xff, 0xed, 0xf8, 0xe0, 0xff, 0xfd, 0x2b, 0x0a, 0xf5, + 0x15, 0x1d, 0xf3, 0x3f, 0x16, 0xf6, 0xf2, 0xee, 0xf4, 0xef, 0xf0, 0x56, + 0x0a, 0x1a, 0xbc, 0xfc, 0x2f, 0xfb, 0xf0, 0x56, 0x1e, 0x0e, 0xc6, 0xe8, + 0x06, 0x0b, 0x11, 0x62, 0x3e, 0xf9, 0xb8, 0xc9, 0xed, 0xeb, 0x02, 0x63, + 0x2c, 0xfd, 0xc5, 0xe9, 0x00, 0x17, 0x0f, 0x37, 0xfe, 0x20, 0xcc, 0xe0, + 0xe0, 0x0e, 0xe6, 0x20, 0x0a, 0xfd, 0xdf, 0xee, 0x0b, 0x02, 0xee, 0x1f, + 0xfb, 0x06, 0xd2, 0xed, 0xfe, 0xeb, 0xfc, 0x12, 0xfd, 0x14, 0x00, 0xd8, + 0x08, 0xf6, 0xec, 0x17, 0xf9, 0x10, 0x00, 0xd9, 0x18, 0xf1, 0xee, 0x0f, + 0xf4, 0x03, 0xee, 0xeb, 0xf0, 0xef, 0xf2, 0x06, 0x04, 0x00, 0xf4, 0x0f, + 0x09, 0x06, 0xf7, 0x0b, 0xfd, 0x01, 0x03, 0x03, 0xf4, 0xf6, 0xdd, 0x14, + 0x1c, 0xef, 0xf1, 0xdd, 0xf7, 0x13, 0xd9, 0x15, 0xef, 0x02, 0xd2, 0xe7, + 0x05, 0x05, 0xe2, 0x09, 0xf2, 0x11, 0xf5, 0xba, 0xf0, 0x04, 0xe0, 0x01, + 0x06, 0x10, 0xe6, 0xef, 0xfc, 0x12, 0xf9, 0xf4, 0x1b, 0x2f, 0xe3, 0x0f, + 0xd7, 0xf6, 0x0b, 0x11, 0xf7, 0x0c, 0x00, 0x06, 0x18, 0xef, 0x06, 0x03, + 0x0a, 0x09, 0xf6, 0x1a, 0x0d, 0xed, 0xfe, 0x2c, 0x43, 0xf4, 0xe5, 0xde, + 0xf5, 0x02, 0x25, 0x5a, 0x49, 0xd4, 0xe6, 0x24, 0x1e, 0xf7, 0x0e, 0x5c, + 0x5d, 0xf0, 0xf9, 0xe4, 0x1c, 0xeb, 0x28, 0x7f, 0x5b, 0xec, 0xfa, 0xdb, + 0x0c, 0xf5, 0x20, 0x49, 0x51, 0xe1, 0xed, 0xe6, 0x0e, 0x26, 0x28, 0x33, + 0x35, 0x05, 0xe1, 0xe4, 0x1f, 0xfc, 0xf9, 0x39, 0x18, 0x04, 0xed, 0xed, + 0x01, 0xe7, 0xe6, 0x08, 0x09, 0x03, 0xe7, 0xf9, 0x0e, 0x06, 0xec, 0x08, + 0x12, 0x1a, 0xda, 0xef, 0xdf, 0xf9, 0xe2, 0x1e, 0x1c, 0x00, 0x12, 0xd7, + 0x01, 0xf7, 0x21, 0x17, 0x13, 0x19, 0xde, 0xe0, 0xec, 0x16, 0x01, 0x1b, + 0x06, 0x0c, 0xf0, 0xe8, 0x18, 0x03, 0x06, 0x0e, 0x09, 0xfa, 0x03, 0xf3, + 0xdd, 0x01, 0xfb, 0x0a, 0x2a, 0xf4, 0xf6, 0xda, 0xe9, 0xfe, 0xe9, 0x12, + 0x19, 0xe9, 0x05, 0xdf, 0x00, 0xeb, 0xf2, 0x10, 0x0c, 0xe1, 0xcd, 0xcb, + 0xf2, 0x1f, 0xd9, 0x0c, 0xfa, 0xfb, 0xe8, 0xde, 0x00, 0xfc, 0xe5, 0x00, + 0x11, 0x02, 0xe6, 0x17, 0x14, 0x00, 0xf2, 0xfd, 0x00, 0xe1, 0x10, 0x24, + 0x12, 0xec, 0xed, 0x1e, 0x09, 0x18, 0x03, 0x0c, 0x04, 0xf4, 0x15, 0x0f, + 0x10, 0x18, 0xd6, 0x29, 0x10, 0x04, 0x1c, 0xef, 0x0f, 0x0c, 0xc7, 0x04, + 0xfe, 0xeb, 0xff, 0xf5, 0xe3, 0x15, 0xfe, 0xcb, 0x10, 0xff, 0x12, 0xfb, + 0xe4, 0xeb, 0xf9, 0x00, 0x02, 0xf1, 0x14, 0x13, 0x01, 0x02, 0xf9, 0x01, + 0x06, 0x0c, 0xf5, 0x0a, 0x1e, 0x01, 0x19, 0x0e, 0x05, 0xf5, 0x0a, 0xff, + 0xff, 0xf2, 0xfb, 0xdb, 0xf8, 0x06, 0x17, 0xf2, 0xf7, 0x0d, 0x0e, 0xf4, + 0xfa, 0xf7, 0x14, 0xdb, 0xe0, 0xfd, 0x08, 0x16, 0xf7, 0x16, 0xfc, 0x09, + 0x27, 0x07, 0x09, 0xfb, 0x0a, 0xfc, 0x0c, 0xe4, 0xdb, 0xee, 0xff, 0x10, + 0xf3, 0x09, 0xfa, 0xf4, 0x23, 0xf3, 0xf4, 0x19, 0xff, 0xfa, 0xff, 0x19, + 0x0f, 0x11, 0xed, 0xec, 0xf8, 0x0f, 0x10, 0xf3, 0xff, 0x0b, 0xf7, 0x06, + 0x0b, 0x0e, 0x07, 0xe4, 0x18, 0x0a, 0x08, 0x0e, 0x02, 0x0a, 0x05, 0x19, + 0x02, 0xf3, 0xfe, 0xfe, 0x0b, 0x0f, 0xfc, 0xfa, 0x05, 0xf9, 0xe2, 0xf9, + 0x1b, 0xf7, 0x0f, 0x07, 0xfc, 0x12, 0xfe, 0x01, 0xfd, 0xf0, 0x04, 0xf4, + 0xfd, 0x07, 0xf2, 0x04, 0x04, 0x07, 0xef, 0x0c, 0xed, 0x0e, 0xf6, 0xef, + 0x08, 0x07, 0x04, 0xe9, 0xf3, 0x20, 0xda, 0x15, 0xf8, 0xff, 0xec, 0xe0, + 0xf6, 0xff, 0xe9, 0x08, 0x01, 0x10, 0xf0, 0xfc, 0xe9, 0x08, 0xe8, 0xf5, + 0xf8, 0xe5, 0x17, 0xe6, 0x03, 0xfc, 0x09, 0xf5, 0xdd, 0xf2, 0xff, 0x05, + 0xf6, 0xf8, 0xf5, 0x07, 0xfc, 0xf1, 0x04, 0xf3, 0x13, 0xe1, 0x0f, 0xf2, + 0x0a, 0xf9, 0xfd, 0x1c, 0xe0, 0x11, 0x1b, 0xe6, 0xef, 0x05, 0x05, 0x0c, + 0x23, 0x10, 0x09, 0xfe, 0xf7, 0x1a, 0xf1, 0xfc, 0x11, 0x1d, 0xff, 0x03, + 0x03, 0xe6, 0x07, 0x11, 0x0c, 0x0d, 0x16, 0x05, 0x05, 0x25, 0xf3, 0x10, + 0x10, 0x06, 0x09, 0xe8, 0x1a, 0xf0, 0xee, 0x09, 0xff, 0x24, 0xf7, 0xfb, + 0xe6, 0x06, 0xfa, 0x08, 0x03, 0x00, 0xf2, 0x04, 0xf0, 0xeb, 0x14, 0x1c, + 0x03, 0x21, 0x14, 0x1d, 0xfe, 0x03, 0xf6, 0x02, 0x09, 0xff, 0x00, 0x13, + 0xef, 0x10, 0x1e, 0x0b, 0x1d, 0x1c, 0xf1, 0xf6, 0xe7, 0xfd, 0x14, 0x01, + 0xff, 0x13, 0xf7, 0xfc, 0x00, 0x21, 0xe3, 0xeb, 0x07, 0x0e, 0x09, 0xf1, + 0xf8, 0xfd, 0x03, 0xee, 0x19, 0xfd, 0xff, 0xfb, 0xff, 0xea, 0xfb, 0x07, + 0xf0, 0x0a, 0x04, 0x04, 0x0b, 0x12, 0xfe, 0x0b, 0xe0, 0xff, 0xf6, 0xe5, + 0xfc, 0x11, 0xed, 0xfd, 0x15, 0x03, 0xdd, 0xdb, 0x04, 0xfe, 0xff, 0x0e, + 0xff, 0xfa, 0xfb, 0xe5, 0xef, 0xf6, 0xfe, 0x22, 0x0f, 0xe8, 0xfe, 0xf4, + 0xfd, 0xd9, 0x03, 0x0a, 0xdf, 0xcf, 0xf1, 0x14, 0x05, 0xfd, 0xfb, 0xf3, + 0xfb, 0xfb, 0x0f, 0xf8, 0x05, 0x09, 0x03, 0xf7, 0x05, 0x05, 0x13, 0xfb, + 0xeb, 0x23, 0xe7, 0x18, 0xfb, 0x00, 0xfe, 0xdd, 0xe9, 0xea, 0xd3, 0xe8, + 0x1a, 0xef, 0x01, 0xf1, 0x09, 0x1d, 0xd8, 0xfc, 0xda, 0x19, 0x03, 0xec, + 0xe5, 0xf3, 0xed, 0x0a, 0xf4, 0x13, 0x0b, 0xf7, 0x0c, 0x00, 0xf9, 0xea, + 0xe3, 0xfe, 0xff, 0x0d, 0x0a, 0x1b, 0xd7, 0x17, 0xeb, 0xe9, 0x00, 0x0e, + 0xee, 0x24, 0xef, 0x09, 0x07, 0xf0, 0xf5, 0x07, 0xf5, 0xf5, 0x10, 0x17, + 0x06, 0xf7, 0xfc, 0x02, 0xfb, 0xf9, 0xe7, 0x0a, 0x26, 0xf3, 0x01, 0x01, + 0x09, 0x0b, 0x02, 0x27, 0xf8, 0xee, 0xfd, 0x1c, 0xf8, 0xf2, 0x0f, 0xfc, + 0x0d, 0xe0, 0xea, 0x02, 0x0b, 0x00, 0xe0, 0x08, 0xfe, 0x10, 0x04, 0xfe, + 0xeb, 0x13, 0x01, 0x0c, 0x0e, 0xed, 0x09, 0x01, 0x0c, 0xe3, 0x10, 0xdf, + 0xd1, 0x14, 0xf3, 0xef, 0x09, 0xf0, 0xee, 0xe5, 0x11, 0xf4, 0xf6, 0x00, + 0xe8, 0x20, 0x0a, 0xfc, 0xea, 0xf7, 0x02, 0x16, 0xe7, 0xf3, 0x0d, 0xe4, + 0x04, 0xe6, 0xef, 0xf8, 0x0f, 0x23, 0x02, 0xe0, 0x01, 0x01, 0x01, 0x05, + 0xf5, 0x0d, 0xf5, 0xf5, 0xe1, 0xff, 0x04, 0x00, 0xf4, 0x0d, 0xee, 0xf1, + 0xef, 0xf7, 0x0b, 0xff, 0x1b, 0xec, 0x05, 0xe7, 0xf3, 0x13, 0x12, 0xf2, + 0xf3, 0xfc, 0xea, 0x06, 0xfe, 0x13, 0x12, 0xdb, 0x11, 0xe2, 0xfc, 0x0d, + 0x1c, 0xe8, 0x1d, 0xfc, 0xf2, 0xe2, 0x13, 0x1d, 0xda, 0xf6, 0x1c, 0x18, + 0x1e, 0xf4, 0xfa, 0x03, 0xdc, 0x0f, 0xff, 0xff, 0x18, 0x0b, 0xed, 0xf1, + 0xf8, 0x02, 0xf4, 0x10, 0xf9, 0xeb, 0x0b, 0x0e, 0x0f, 0x01, 0x02, 0x1b, + 0x06, 0x10, 0x00, 0xe7, 0x23, 0x0d, 0xf6, 0x11, 0x08, 0xf5, 0x0f, 0x05, + 0x13, 0xf7, 0x01, 0x01, 0x0c, 0xf6, 0xf9, 0xf0, 0x29, 0x01, 0xe9, 0x11, + 0x02, 0xfa, 0xeb, 0x16, 0x0e, 0x10, 0x09, 0x0e, 0x1c, 0x0a, 0xe3, 0xd3, + 0x01, 0xe3, 0x00, 0x06, 0xe2, 0xe9, 0x19, 0xef, 0x12, 0xf3, 0xfc, 0x02, + 0x0b, 0x0c, 0x0d, 0xed, 0xfd, 0xf6, 0xf9, 0xe9, 0xf2, 0x28, 0xfe, 0x03, + 0xec, 0x03, 0x00, 0xf8, 0xde, 0x0d, 0x25, 0x07, 0x1a, 0xe7, 0xfd, 0x29, + 0xd8, 0xf7, 0xfb, 0xde, 0x0c, 0x08, 0x06, 0x22, 0xee, 0x1d, 0x05, 0x07, + 0xf0, 0xfb, 0xfe, 0x07, 0xf1, 0x04, 0xe9, 0x01, 0xfc, 0xf1, 0x00, 0xeb, + 0xe3, 0x08, 0xec, 0xfe, 0x04, 0xeb, 0xfc, 0x01, 0xf6, 0x0e, 0xdf, 0xf8, + 0x12, 0xe3, 0x16, 0xdc, 0x21, 0x0a, 0xe6, 0x06, 0xe5, 0x10, 0x07, 0xf7, + 0x1e, 0xde, 0xe3, 0x07, 0x16, 0xed, 0x23, 0xf2, 0x12, 0x0d, 0xe9, 0xf9, + 0xe8, 0xfe, 0x0e, 0x02, 0x18, 0x0a, 0xea, 0xec, 0xfb, 0xfe, 0x0c, 0x1b, + 0x19, 0x20, 0xfa, 0x07, 0xe5, 0x0c, 0x04, 0x27, 0xdb, 0xe6, 0xfe, 0x0d, + 0x0a, 0x0a, 0xfe, 0x39, 0xdd, 0xde, 0x05, 0xec, 0x09, 0x05, 0x0a, 0x2c, + 0xf4, 0x02, 0x1f, 0xd3, 0x24, 0xee, 0x0f, 0x3c, 0xf5, 0xfd, 0xf8, 0xf8, + 0x12, 0xf5, 0xf3, 0x19, 0xf9, 0xda, 0xf6, 0x0a, 0x0a, 0xf4, 0x09, 0x0f, + 0xfc, 0x00, 0x01, 0x01, 0xf3, 0xf8, 0x05, 0xf3, 0x0c, 0x19, 0x0e, 0xfd, + 0xfa, 0xe1, 0xfc, 0x0c, 0x03, 0xfb, 0x1b, 0x06, 0xcc, 0xe4, 0x08, 0xf9, + 0x10, 0xe9, 0x06, 0x00, 0x17, 0xe8, 0x0d, 0x12, 0xca, 0xf5, 0x23, 0xe4, + 0x21, 0xf6, 0x19, 0x33, 0xdd, 0xfa, 0x0c, 0x01, 0x14, 0x07, 0x00, 0x34, + 0xda, 0x05, 0x07, 0x01, 0x07, 0xe4, 0x06, 0x24, 0x02, 0xff, 0xf0, 0x09, + 0xfc, 0xf4, 0x03, 0x06, 0xee, 0x08, 0xe2, 0x1d, 0xfa, 0x0c, 0xfc, 0x02, + 0x03, 0xe5, 0xf0, 0xe2, 0x0a, 0x18, 0x12, 0x0c, 0x1e, 0x20, 0xed, 0x20, + 0xe4, 0x01, 0x2a, 0x09, 0x0d, 0x0e, 0xd0, 0xf4, 0xdd, 0xfd, 0x2b, 0xf2, + 0x08, 0x0c, 0xf8, 0xf7, 0xfc, 0xf9, 0x15, 0xef, 0x19, 0x1c, 0x01, 0xff, + 0xe2, 0x01, 0xf3, 0x30, 0x0e, 0xfb, 0x15, 0xe8, 0x1c, 0x00, 0xfa, 0x16, + 0xef, 0xea, 0xfb, 0x05, 0xf0, 0x0e, 0x02, 0x13, 0xf4, 0x01, 0x03, 0xe5, + 0x29, 0x07, 0x09, 0x24, 0xf9, 0xe3, 0xf8, 0xde, 0x2d, 0xf4, 0xf5, 0x40, + 0xed, 0xdf, 0x07, 0xef, 0x0f, 0x0a, 0x0b, 0x32, 0x0d, 0xe8, 0x00, 0xe6, + 0xf6, 0xfc, 0xfd, 0x19, 0x11, 0x09, 0xf3, 0x03, 0xea, 0xf1, 0xfb, 0x02, + 0xfd, 0x06, 0xff, 0xfe, 0x09, 0xec, 0x06, 0x0c, 0x15, 0xf9, 0x06, 0xd7, + 0xe3, 0xf7, 0xed, 0x01, 0x03, 0xfd, 0x14, 0x01, 0x0e, 0xe0, 0x37, 0x0d, + 0xd2, 0x18, 0x2f, 0xea, 0x12, 0x0d, 0x05, 0x3a, 0xd5, 0x07, 0x1e, 0xf2, + 0x21, 0x11, 0xf9, 0x36, 0xd3, 0xf5, 0x12, 0xf6, 0xfb, 0xf6, 0x06, 0x0f, + 0xde, 0xf9, 0x06, 0x09, 0xdf, 0xff, 0x0b, 0xf3, 0xf5, 0x01, 0xf1, 0xea, + 0xf2, 0x02, 0x12, 0xfc, 0x0e, 0xee, 0xf8, 0xeb, 0x00, 0xef, 0x21, 0x0f, + 0x09, 0xef, 0xeb, 0x1e, 0xef, 0xf2, 0x26, 0xf9, 0x17, 0xf1, 0xf1, 0xf0, + 0x0c, 0x10, 0x1d, 0xff, 0x1d, 0x06, 0x03, 0xf6, 0xfb, 0x14, 0x1b, 0x03, + 0x22, 0xfd, 0xec, 0x03, 0xfa, 0xf8, 0x01, 0x2b, 0x1e, 0x1b, 0x09, 0x09, + 0x07, 0xff, 0xf0, 0x20, 0xee, 0x14, 0xfb, 0xf6, 0xf8, 0x11, 0xd9, 0x29, + 0xf4, 0xfa, 0x07, 0xef, 0x20, 0xf9, 0xf2, 0x30, 0xee, 0xf0, 0xf3, 0xd6, + 0x0d, 0xfe, 0x03, 0x36, 0xf5, 0xd7, 0x01, 0xe6, 0x04, 0xf0, 0x05, 0x1f, + 0x0f, 0xdd, 0xff, 0xf8, 0x1f, 0xf2, 0x04, 0x37, 0xfa, 0x00, 0xfd, 0xf8, + 0x10, 0xe1, 0xfb, 0x0d, 0xed, 0xf6, 0xe2, 0xfe, 0x08, 0xfe, 0x07, 0x08, + 0x08, 0x11, 0x0a, 0xf0, 0xf8, 0xf5, 0x04, 0xea, 0x08, 0x12, 0x06, 0x0d, + 0x0f, 0x10, 0x40, 0x28, 0xc0, 0xfb, 0x3f, 0x08, 0x1d, 0x09, 0x1b, 0x3d, + 0xee, 0xf4, 0x29, 0x13, 0x20, 0xfc, 0x11, 0x4c, 0xdb, 0x02, 0x15, 0x05, + 0xec, 0xeb, 0x0a, 0x22, 0xe7, 0x00, 0x02, 0x01, 0xd4, 0xea, 0x0a, 0xf3, + 0xe3, 0xf8, 0xf5, 0xfa, 0x01, 0x0d, 0x19, 0x06, 0x24, 0x13, 0x02, 0xf5, + 0xf1, 0xf1, 0x1b, 0x0f, 0x19, 0x04, 0xe3, 0xf9, 0xe7, 0x02, 0x29, 0xfc, + 0x29, 0xec, 0xe9, 0x04, 0xdc, 0x22, 0x1d, 0xfd, 0x1f, 0x01, 0xec, 0xe8, + 0xf5, 0x14, 0x1b, 0x19, 0x06, 0x0e, 0x02, 0x0d, 0xf9, 0x06, 0xfc, 0x15, + 0x07, 0xfa, 0x0c, 0xe1, 0x18, 0x1a, 0xe8, 0x1b, 0xe9, 0xef, 0x0a, 0x18, + 0xfc, 0x05, 0xf9, 0x14, 0xdc, 0x04, 0x01, 0xff, 0x07, 0xfd, 0xf0, 0x2c, + 0xf2, 0xec, 0x0e, 0xe7, 0x1a, 0x05, 0xe8, 0x35, 0x13, 0x09, 0xf9, 0x07, + 0xfe, 0xfa, 0x0d, 0x40, 0x0c, 0xea, 0xf4, 0x04, 0x01, 0x11, 0xfc, 0x23, + 0xeb, 0xf4, 0xe9, 0x04, 0xeb, 0xe7, 0x07, 0x09, 0xfb, 0xf1, 0xf6, 0xfd, + 0x02, 0xfa, 0x02, 0xff, 0x00, 0xff, 0xf1, 0xf1, 0x1a, 0xe9, 0x10, 0xe3, + 0x0b, 0x0c, 0x08, 0x04, 0x1b, 0x0a, 0x2b, 0x10, 0xe1, 0x01, 0x1f, 0x06, + 0x04, 0xec, 0x19, 0x49, 0xee, 0xf8, 0x22, 0x0c, 0x20, 0x02, 0x07, 0x31, + 0xe7, 0xff, 0x0f, 0xf0, 0xfd, 0xea, 0x13, 0x26, 0xce, 0xfa, 0xff, 0xee, + 0xe9, 0xfe, 0x15, 0x08, 0x04, 0x05, 0x0d, 0xfa, 0xdd, 0xf8, 0x07, 0x0b, + 0x33, 0xef, 0xec, 0xf9, 0xd9, 0xe6, 0x1d, 0x10, 0x41, 0xf6, 0xdf, 0x11, + 0xe3, 0x14, 0x1d, 0xfb, 0x2b, 0x15, 0xdc, 0x09, 0xf6, 0x05, 0x16, 0x00, + 0x1c, 0x27, 0xe4, 0xfc, 0xf7, 0x16, 0x08, 0x08, 0x2f, 0xdd, 0xf8, 0xfa, + 0xe9, 0x0e, 0x0b, 0x0b, 0x02, 0x12, 0x02, 0xfd, 0x19, 0x03, 0xeb, 0x11, + 0xf4, 0x09, 0x09, 0x15, 0x12, 0x0d, 0xef, 0x1c, 0xe4, 0xfe, 0x17, 0x0c, + 0x09, 0x04, 0xea, 0x2f, 0xf2, 0x1e, 0x02, 0xfb, 0xfe, 0xe3, 0x00, 0x2e, + 0x04, 0xf9, 0x0c, 0x05, 0x27, 0x0c, 0x07, 0x2d, 0xf7, 0x0b, 0xfb, 0xf9, + 0x1c, 0xdf, 0x11, 0x36, 0x05, 0xf2, 0x02, 0xf8, 0x0b, 0x07, 0x05, 0xfb, + 0xfc, 0x0e, 0x13, 0xfa, 0xfb, 0x09, 0xf5, 0xfd, 0x06, 0x15, 0xf9, 0x03, + 0x18, 0xfd, 0x1a, 0x0a, 0x03, 0xe2, 0xfb, 0x00, 0x1e, 0xfe, 0x4f, 0x27, + 0xe1, 0xf7, 0x31, 0xf0, 0x1b, 0xec, 0x07, 0x5f, 0xe2, 0xf8, 0x40, 0x05, + 0x17, 0x24, 0x0c, 0x3c, 0xf3, 0x10, 0x13, 0xf8, 0x0b, 0xf3, 0xf9, 0x36, + 0xe1, 0xf3, 0xf4, 0xe8, 0xef, 0xf8, 0xfc, 0xeb, 0xe3, 0xfb, 0xf0, 0xee, + 0xdb, 0x06, 0x0c, 0x11, 0x1e, 0x10, 0xe2, 0xe9, 0xeb, 0x0d, 0x34, 0x0f, + 0x43, 0xd9, 0xef, 0x08, 0xec, 0x05, 0x1d, 0x02, 0x33, 0xef, 0xf4, 0xf7, + 0xe6, 0xf9, 0x22, 0x07, 0x04, 0x06, 0xe9, 0x02, 0xf0, 0xfc, 0x24, 0x20, + 0x24, 0x17, 0xe6, 0x0f, 0x05, 0xf6, 0xfc, 0x1f, 0xf2, 0x01, 0x0d, 0xe7, + 0xff, 0x1d, 0xf0, 0xfa, 0xd0, 0x00, 0xff, 0x0e, 0x23, 0xf9, 0xf3, 0x11, + 0xde, 0x0d, 0x05, 0x04, 0x0b, 0x0b, 0xfb, 0x26, 0x0d, 0x0d, 0xff, 0xe8, + 0x16, 0xe8, 0x0b, 0x3c, 0x18, 0xe4, 0x04, 0xff, 0xfa, 0xf3, 0xff, 0x40, + 0xee, 0x06, 0xfc, 0x0d, 0x00, 0xf7, 0x13, 0x3f, 0xf7, 0x13, 0x06, 0x08, + 0xf9, 0x13, 0xf2, 0x19, 0xfd, 0xf9, 0xf3, 0xe6, 0xfc, 0x07, 0xf6, 0xfd, + 0x0a, 0x22, 0x00, 0x01, 0x19, 0xff, 0xe7, 0xff, 0x08, 0xfd, 0x03, 0xfd, + 0x1f, 0xe7, 0x28, 0x08, 0xde, 0xf3, 0x43, 0xf6, 0x0c, 0xfe, 0x1e, 0x52, + 0xf2, 0x04, 0x17, 0xf2, 0x08, 0x0d, 0x04, 0x38, 0xde, 0x0c, 0x10, 0xef, + 0xdf, 0x0f, 0x01, 0x24, 0xde, 0xe1, 0x0d, 0xfd, 0xd4, 0xf6, 0x12, 0x0e, + 0xed, 0x01, 0xf0, 0xf3, 0xfd, 0xff, 0x18, 0xf3, 0x36, 0xda, 0xf6, 0xef, + 0xe8, 0xef, 0x37, 0x27, 0x4e, 0xf8, 0xf4, 0xff, 0xe5, 0xf3, 0x32, 0x0b, + 0x36, 0x08, 0xe9, 0xf6, 0xe2, 0x13, 0x21, 0xfe, 0x12, 0xed, 0xdd, 0xfb, + 0xf8, 0x05, 0x0f, 0x03, 0x1c, 0x04, 0xfc, 0xf2, 0x23, 0x0e, 0x03, 0xfc, + 0xf9, 0x18, 0xf7, 0x01, 0x1b, 0x03, 0xf5, 0xfd, 0xde, 0xf3, 0x19, 0xfc, + 0x11, 0x02, 0xe7, 0x13, 0xde, 0xd8, 0xf2, 0x05, 0x28, 0x02, 0x02, 0x27, + 0x07, 0x08, 0xff, 0x07, 0x27, 0x0e, 0x19, 0x40, 0xfb, 0x02, 0x0c, 0xf6, + 0x0d, 0x07, 0x0f, 0x47, 0xf8, 0x05, 0x0e, 0xfd, 0x03, 0x1e, 0x07, 0x32, + 0xe7, 0xf6, 0x24, 0x01, 0x01, 0x02, 0x0a, 0xff, 0xf6, 0x26, 0x15, 0xf0, + 0x04, 0x13, 0x03, 0xfa, 0xfe, 0xf6, 0xf1, 0x09, 0x2a, 0xe6, 0xea, 0xf6, + 0x17, 0x13, 0xeb, 0xff, 0x15, 0xeb, 0x23, 0x06, 0xc8, 0xf6, 0x33, 0xeb, + 0xf4, 0xe7, 0x12, 0x2a, 0xe3, 0xe6, 0x32, 0xfa, 0x16, 0x15, 0x17, 0x40, + 0xf1, 0x08, 0x1a, 0xf3, 0xf6, 0x0c, 0x0c, 0x11, 0xd0, 0x22, 0x02, 0xee, + 0xea, 0xf4, 0xf8, 0xf9, 0x13, 0x10, 0x17, 0xf5, 0xf1, 0x0a, 0x0e, 0xfd, + 0x32, 0xda, 0xf1, 0xe2, 0xdb, 0xf2, 0x34, 0x1f, 0x53, 0xfc, 0xe4, 0xf2, + 0xf6, 0xf2, 0x1d, 0x04, 0x4a, 0xec, 0xee, 0x06, 0xdf, 0x01, 0x1a, 0x04, + 0x27, 0xfc, 0xe6, 0xfd, 0xd9, 0xfd, 0x0e, 0x00, 0x0c, 0x16, 0xf3, 0x03, + 0xf7, 0xfc, 0x0e, 0x0f, 0x09, 0x06, 0x06, 0x04, 0x08, 0x02, 0xed, 0xf5, + 0xe4, 0xe6, 0x07, 0x06, 0x03, 0x18, 0xea, 0x13, 0xe2, 0xfa, 0x10, 0xf2, + 0x02, 0xec, 0x03, 0x3c, 0xf6, 0xf6, 0x0a, 0x10, 0x09, 0xf8, 0x15, 0x24, + 0xfd, 0x0d, 0x09, 0x01, 0x00, 0xff, 0x00, 0x1a, 0xf0, 0xee, 0x08, 0x03, + 0x1d, 0x05, 0x16, 0x46, 0xe6, 0xf8, 0x08, 0x00, 0x09, 0x09, 0xff, 0x01, + 0xfc, 0x20, 0xfc, 0xec, 0x05, 0x1b, 0x03, 0xf1, 0x12, 0xe4, 0xfa, 0x24, + 0x1c, 0xf5, 0xf2, 0x05, 0x11, 0xe7, 0xfa, 0x02, 0x20, 0xea, 0x31, 0x10, + 0xcf, 0xd8, 0x33, 0xee, 0xff, 0x09, 0x20, 0x3f, 0xe2, 0x0a, 0x29, 0xee, + 0x3a, 0xf2, 0x1e, 0x39, 0x02, 0x1e, 0xfe, 0xf2, 0xef, 0xe2, 0x0d, 0x0f, + 0xf1, 0x19, 0x02, 0xe7, 0xec, 0xff, 0xfe, 0xe4, 0xfe, 0xfb, 0x02, 0xf6, + 0xf1, 0xf4, 0x07, 0x1a, 0x2a, 0xf9, 0x06, 0xf9, 0xda, 0xf4, 0x22, 0x02, + 0x4f, 0x0a, 0xf3, 0xfc, 0xf3, 0xf6, 0x25, 0x0a, 0x28, 0x01, 0xf7, 0x09, + 0xe6, 0x05, 0x28, 0xf7, 0x1e, 0xf2, 0xee, 0x13, 0xee, 0x05, 0x0f, 0x0a, + 0x09, 0xe8, 0xe8, 0x0e, 0x05, 0x12, 0x0f, 0x15, 0x02, 0xec, 0xf8, 0x02, + 0xf7, 0x05, 0xf8, 0xff, 0xdc, 0x00, 0x01, 0x00, 0x12, 0x17, 0xec, 0x19, + 0xfa, 0x09, 0xfa, 0xf3, 0x1d, 0x0b, 0x07, 0x25, 0xea, 0x0c, 0xf5, 0xfa, + 0x04, 0xf7, 0xfe, 0x33, 0xfe, 0x14, 0xef, 0x04, 0xf0, 0x00, 0x00, 0x3a, + 0xea, 0xfa, 0x10, 0x01, 0xe4, 0x00, 0xff, 0x23, 0xe9, 0x26, 0x15, 0x10, + 0x04, 0x14, 0x0d, 0x08, 0xf8, 0xfd, 0x10, 0xfb, 0x00, 0x21, 0x06, 0xfa, + 0x0f, 0x08, 0xf1, 0x09, 0x28, 0xf0, 0xd8, 0x0d, 0x08, 0x09, 0x02, 0xfb, + 0x12, 0x03, 0x0e, 0xfb, 0xce, 0xf0, 0x39, 0xe5, 0x09, 0xf6, 0x1f, 0x35, + 0xdd, 0x1c, 0x25, 0xef, 0x17, 0x0c, 0xf6, 0x3e, 0xf0, 0x21, 0x08, 0xff, + 0xd7, 0xfc, 0xfd, 0x1f, 0xe5, 0x18, 0x12, 0xe9, 0xf5, 0xe9, 0x12, 0xf6, + 0x02, 0x13, 0xf4, 0x0a, 0xfd, 0x03, 0x09, 0x08, 0x2f, 0x07, 0xee, 0xfd, + 0xd7, 0x00, 0x2b, 0x29, 0x3b, 0xdb, 0xde, 0xf1, 0xe1, 0xf7, 0x47, 0x12, + 0x35, 0x0c, 0xe4, 0x09, 0xef, 0x17, 0x2b, 0xea, 0x2d, 0xf8, 0xe8, 0x18, + 0xef, 0x03, 0x11, 0x0a, 0x10, 0xff, 0xe8, 0x07, 0x0c, 0x07, 0x03, 0x18, + 0x05, 0x08, 0xf8, 0xf8, 0x06, 0x18, 0xe9, 0xf9, 0xe0, 0x0f, 0x0d, 0x18, + 0x04, 0x01, 0xf0, 0x1c, 0xf6, 0x14, 0xfd, 0x12, 0x0c, 0x0c, 0x02, 0x34, + 0xf6, 0xe6, 0xfd, 0xf9, 0xf9, 0xfd, 0x00, 0x2a, 0xfc, 0xf9, 0xff, 0x0a, + 0xfe, 0x1b, 0xf5, 0x34, 0xdc, 0xf9, 0x15, 0x13, 0xe7, 0x1b, 0xf7, 0x25, + 0xfd, 0x09, 0x08, 0x0a, 0xf0, 0x17, 0x0f, 0x04, 0xf4, 0xe9, 0x06, 0x07, + 0xf5, 0x02, 0xfc, 0xf5, 0x09, 0xee, 0xf1, 0x07, 0x38, 0x03, 0x05, 0x0f, + 0x16, 0x0f, 0xed, 0xff, 0x21, 0xf8, 0x34, 0x07, 0xd1, 0xf9, 0x27, 0x00, + 0x0c, 0x21, 0x18, 0x42, 0xe6, 0x02, 0x1a, 0xf1, 0x2f, 0xf1, 0x0e, 0x3b, + 0xee, 0xf8, 0x08, 0xea, 0xfe, 0xf9, 0x03, 0x18, 0xf5, 0xf8, 0x0d, 0xeb, + 0x01, 0x10, 0x09, 0x02, 0x15, 0xfb, 0xf1, 0x0b, 0xf2, 0x06, 0x08, 0x09, + 0x2f, 0x19, 0x02, 0xfe, 0xe4, 0x06, 0x1f, 0x17, 0x49, 0xf2, 0xe2, 0x02, + 0xef, 0x04, 0x26, 0x16, 0x3f, 0x08, 0xf1, 0x0a, 0xfd, 0xf9, 0x28, 0x01, + 0x15, 0x0b, 0xf9, 0x10, 0xdc, 0x02, 0x20, 0xf7, 0x16, 0xe6, 0x09, 0x03, + 0xf1, 0xf5, 0x12, 0x1c, 0xfb, 0x2a, 0x08, 0xfa, 0x0a, 0x16, 0xf6, 0x15, + 0xf0, 0x06, 0x11, 0xfd, 0x0e, 0xf9, 0xf6, 0x12, 0xed, 0xf3, 0xfd, 0x1f, + 0x0b, 0xfa, 0x08, 0x30, 0xf8, 0xff, 0x0b, 0xeb, 0x10, 0xff, 0x07, 0x22, + 0x0d, 0x07, 0x09, 0x03, 0xf6, 0xf8, 0xfc, 0x26, 0xf8, 0xee, 0x11, 0x02, + 0x03, 0x0a, 0xef, 0x38, 0xfe, 0x13, 0x1b, 0x09, 0xfe, 0x06, 0x05, 0xf3, + 0x04, 0xdf, 0xfc, 0x00, 0xe7, 0x15, 0xec, 0xf1, 0xf8, 0xfc, 0xed, 0x05, + 0x0e, 0xf3, 0x15, 0x09, 0x01, 0x0d, 0xfd, 0x00, 0x24, 0xe2, 0x31, 0x13, + 0xd5, 0x1b, 0x2b, 0xe8, 0x03, 0x08, 0x1d, 0x33, 0xdc, 0xfd, 0x24, 0xe4, + 0x20, 0xfa, 0x07, 0x33, 0x01, 0x12, 0x06, 0xf5, 0xef, 0xf7, 0xfa, 0x13, + 0x01, 0xec, 0xee, 0xe0, 0xfd, 0x0d, 0xff, 0x09, 0xf6, 0x00, 0xed, 0x07, + 0xea, 0x0e, 0xff, 0x0e, 0x26, 0xfc, 0xf0, 0xe7, 0xe7, 0xfe, 0x30, 0xff, + 0x24, 0x04, 0x06, 0xf4, 0xf5, 0xf8, 0x23, 0x0e, 0x3d, 0xf2, 0xfd, 0x04, + 0xe8, 0xfb, 0x23, 0xfe, 0x33, 0xe1, 0x01, 0xfd, 0xdc, 0xfb, 0x0e, 0xfa, + 0x22, 0xfb, 0x11, 0xfa, 0xff, 0x08, 0x21, 0x30, 0x13, 0x03, 0xf2, 0x03, + 0xf8, 0x0f, 0xec, 0x0d, 0xef, 0x0f, 0x10, 0x10, 0x0f, 0xf6, 0xf9, 0x1e, + 0xf7, 0xe5, 0x08, 0xfa, 0x09, 0xff, 0x00, 0x15, 0x02, 0x00, 0x08, 0xfe, + 0xfb, 0x0e, 0x15, 0x28, 0xfa, 0xfb, 0x13, 0x06, 0xfb, 0x05, 0xf6, 0x11, + 0xf6, 0x0b, 0x06, 0x15, 0xe1, 0x00, 0xe9, 0x0f, 0xe1, 0x1d, 0x18, 0xfd, + 0x0b, 0x0f, 0xff, 0xf2, 0xf5, 0xfd, 0x14, 0xff, 0xf4, 0xfe, 0xe2, 0xf8, + 0x14, 0x0b, 0xeb, 0x07, 0x35, 0xe2, 0xeb, 0x0b, 0x04, 0x22, 0xfe, 0x0e, + 0x1d, 0xf2, 0x24, 0x11, 0xcc, 0xec, 0x25, 0xf7, 0xff, 0xf9, 0x06, 0x29, + 0xe4, 0x07, 0x1c, 0xdb, 0xf8, 0x1d, 0xfa, 0x44, 0xf2, 0x01, 0x0f, 0xe6, + 0x11, 0x03, 0xee, 0x17, 0x06, 0xe0, 0x0c, 0xd8, 0xe9, 0xfd, 0x11, 0xfe, + 0x07, 0xdd, 0xea, 0xff, 0xde, 0xdd, 0x0a, 0x09, 0x30, 0xf2, 0x01, 0xe4, + 0xe0, 0xeb, 0x2d, 0x12, 0x2d, 0xeb, 0xfc, 0xf0, 0xe8, 0xf9, 0x1f, 0x08, + 0x3f, 0xeb, 0x0e, 0x13, 0xf9, 0x0c, 0x1c, 0x02, 0x25, 0xec, 0xf6, 0x05, + 0xf3, 0xf4, 0x18, 0x08, 0x12, 0xe9, 0xfb, 0xfd, 0xf9, 0x08, 0x13, 0x1c, + 0x08, 0xec, 0xfe, 0x02, 0xf1, 0x19, 0xf3, 0x1d, 0xf1, 0x07, 0x11, 0x12, + 0xfa, 0xf2, 0xf6, 0x0d, 0xff, 0x17, 0x0a, 0xfb, 0x1f, 0xf8, 0x11, 0x24, + 0xf6, 0xfc, 0xfe, 0x07, 0xed, 0x05, 0x1c, 0x21, 0xfe, 0xfe, 0x16, 0x0d, + 0x08, 0x0f, 0x09, 0x33, 0xf4, 0x1f, 0x14, 0x0c, 0xfe, 0xf5, 0xeb, 0x2a, + 0xee, 0xf3, 0x12, 0x19, 0xec, 0x01, 0x06, 0xf7, 0x05, 0x22, 0x0b, 0xeb, + 0xeb, 0x06, 0xe1, 0xf5, 0x0d, 0xee, 0xfb, 0x0a, 0x31, 0xff, 0xe3, 0xea, + 0x18, 0x09, 0xe3, 0x07, 0x1a, 0xf8, 0x15, 0xfc, 0xcc, 0xf2, 0x2a, 0xe5, + 0x01, 0xea, 0x10, 0x1f, 0xd9, 0x02, 0x13, 0xf6, 0x16, 0x01, 0x0e, 0x3c, + 0x02, 0x17, 0x04, 0xf1, 0xf7, 0x02, 0x07, 0x0c, 0x02, 0x1f, 0xf4, 0xe6, + 0xf0, 0xe9, 0x05, 0xf4, 0xfd, 0xe4, 0xf7, 0xe9, 0xfc, 0xef, 0x06, 0x02, + 0x26, 0xf1, 0xf1, 0xeb, 0xe9, 0xe6, 0x30, 0x1c, 0x38, 0x0f, 0x03, 0xf1, + 0x10, 0x04, 0x30, 0x19, 0x1f, 0xfb, 0xfc, 0x05, 0xe2, 0xfe, 0x18, 0xf2, + 0x1c, 0xf2, 0xf5, 0x0e, 0xf2, 0x05, 0x1d, 0x28, 0x12, 0xf0, 0xf0, 0x0f, + 0x0a, 0x03, 0x1a, 0x1a, 0xf3, 0x08, 0x13, 0xef, 0xf5, 0x1c, 0x06, 0x00, + 0xee, 0x12, 0x1d, 0x03, 0x18, 0x06, 0x0a, 0x0e, 0xf0, 0xeb, 0xfa, 0x0d, + 0x08, 0xff, 0x06, 0x24, 0x0f, 0x03, 0x0a, 0x0f, 0x0e, 0xff, 0x08, 0x33, + 0xfc, 0x00, 0x0e, 0xfb, 0xfb, 0x05, 0x07, 0x19, 0xe8, 0xe7, 0x12, 0x11, + 0x15, 0xf7, 0x0c, 0x1a, 0xf6, 0x28, 0x08, 0xeb, 0xf2, 0x25, 0xee, 0x01, + 0x03, 0xec, 0xed, 0xfa, 0xf0, 0xf2, 0xef, 0xf1, 0x02, 0x23, 0xef, 0x01, + 0x41, 0xfa, 0xf4, 0xf4, 0x15, 0xf5, 0xf5, 0xf9, 0x28, 0xde, 0x20, 0xf6, + 0xc7, 0xde, 0x21, 0xe4, 0xfe, 0xec, 0x0d, 0x2c, 0xee, 0x24, 0x10, 0xf0, + 0x1d, 0x12, 0x0e, 0x2b, 0x06, 0xf8, 0xfd, 0x01, 0x08, 0xef, 0xfd, 0x0f, + 0xeb, 0xed, 0xe1, 0xdf, 0xf1, 0xe5, 0x16, 0xe3, 0x08, 0xfc, 0xf6, 0xf6, + 0xd8, 0xf0, 0x23, 0xfc, 0x2b, 0xf5, 0xff, 0xe7, 0xf4, 0xe9, 0x29, 0x09, + 0x2b, 0x0c, 0xff, 0x08, 0x0b, 0xed, 0x29, 0x14, 0x3c, 0xf5, 0xeb, 0x18, + 0xf6, 0x10, 0x22, 0xf9, 0x17, 0x23, 0x02, 0x0c, 0xf6, 0xfa, 0x2f, 0xfe, + 0x1e, 0xeb, 0xfd, 0x03, 0xf0, 0x07, 0x1c, 0x09, 0xfa, 0xe1, 0x0d, 0x0f, + 0x18, 0x03, 0xfe, 0xf0, 0xec, 0x0b, 0x10, 0x02, 0x14, 0x06, 0xef, 0xf7, + 0xea, 0x0b, 0x05, 0xfe, 0x1f, 0x06, 0x0e, 0x07, 0x00, 0xe1, 0x01, 0x01, + 0x07, 0x05, 0x09, 0xf7, 0xef, 0x15, 0xf7, 0x12, 0x05, 0x03, 0x04, 0x1d, + 0x04, 0x10, 0x12, 0x06, 0x05, 0x00, 0x08, 0x18, 0xd6, 0xf2, 0xfa, 0x07, + 0xf8, 0x12, 0x07, 0xfd, 0xdd, 0x00, 0x04, 0xfb, 0xf8, 0x09, 0xf3, 0x09, + 0xfb, 0xf0, 0xe8, 0x09, 0x27, 0xf5, 0xf8, 0x06, 0x01, 0x02, 0x0e, 0xf6, + 0x1f, 0xfa, 0x29, 0xf8, 0xd6, 0x01, 0x22, 0xf8, 0x1d, 0xe3, 0x1a, 0x39, + 0x0a, 0x0d, 0x19, 0xf5, 0x12, 0xfb, 0x1d, 0x2a, 0x03, 0xf6, 0x0c, 0xf2, + 0xfd, 0xec, 0x18, 0x13, 0xfe, 0x1a, 0xe8, 0xdd, 0x01, 0xf8, 0x30, 0x01, + 0xf8, 0xfe, 0xe4, 0xe7, 0xff, 0xeb, 0x23, 0xfa, 0x2c, 0xf0, 0xfc, 0xe7, + 0x0a, 0xf8, 0x18, 0x10, 0x23, 0x01, 0xfa, 0xe8, 0xf1, 0xfa, 0x1d, 0x0e, + 0x17, 0xe7, 0xe4, 0xf5, 0xf9, 0x0c, 0x17, 0x0c, 0x13, 0xe8, 0xe1, 0x17, + 0x19, 0x05, 0x0b, 0x0f, 0x23, 0xed, 0xff, 0xfe, 0xe0, 0x14, 0x16, 0x00, + 0x0d, 0x1c, 0x0b, 0xf5, 0xfb, 0x18, 0xee, 0xff, 0xff, 0xf3, 0x18, 0x0c, + 0x05, 0xfa, 0xf6, 0xfe, 0xfe, 0xf8, 0xf8, 0x09, 0xef, 0xf8, 0x0e, 0xf0, + 0x00, 0xf8, 0x0c, 0xf8, 0xf6, 0x07, 0x16, 0x11, 0xf8, 0xea, 0xff, 0xff, + 0x01, 0x20, 0x07, 0x08, 0xfd, 0x1c, 0xfc, 0x06, 0xed, 0x0d, 0x08, 0x15, + 0xf0, 0x25, 0x01, 0x1b, 0x00, 0x02, 0xfe, 0x01, 0x05, 0x01, 0xfd, 0xf1, + 0xe5, 0x0c, 0xe4, 0xe1, 0xf0, 0xfa, 0xee, 0x0e, 0x35, 0xee, 0x15, 0xef, + 0x0a, 0xf9, 0x01, 0xf5, 0x1f, 0x05, 0x1f, 0x0d, 0xe1, 0xf4, 0xff, 0xf5, + 0x23, 0x02, 0x18, 0x30, 0xfc, 0xf0, 0x0d, 0x04, 0x0d, 0x06, 0x29, 0x1d, + 0xf9, 0x08, 0x06, 0xe5, 0x13, 0xfd, 0x0d, 0x26, 0xef, 0x09, 0xdc, 0xf2, + 0x05, 0xdf, 0x0c, 0xf6, 0xf3, 0xd9, 0xf8, 0x08, 0xef, 0xeb, 0x0f, 0xf9, + 0x3a, 0x03, 0xff, 0xe0, 0xf7, 0xf0, 0x15, 0x12, 0x41, 0x0b, 0xf1, 0x04, + 0x04, 0xe2, 0x0e, 0x0b, 0x2c, 0x03, 0xea, 0x02, 0xfb, 0xe7, 0x08, 0xe9, + 0x22, 0xf3, 0xf2, 0x1c, 0xfa, 0xf3, 0x11, 0x04, 0x1f, 0xf5, 0x02, 0x0f, + 0x1a, 0x1f, 0x24, 0x0b, 0x06, 0x1f, 0xf3, 0x06, 0x00, 0x02, 0xe8, 0xf6, + 0xf4, 0xe8, 0x07, 0x2e, 0xfb, 0xf8, 0x10, 0x09, 0xf0, 0x0e, 0xff, 0xfe, + 0x1c, 0x14, 0x17, 0x06, 0xe2, 0xf1, 0xfa, 0x01, 0x11, 0x13, 0x12, 0x29, + 0xf1, 0x0f, 0x1f, 0xfa, 0xfd, 0xfd, 0x02, 0x07, 0x0e, 0xfb, 0x0e, 0x04, + 0x01, 0x01, 0xed, 0xfe, 0xde, 0xfd, 0x08, 0xef, 0xf6, 0x0a, 0xff, 0x0f, + 0xe7, 0xf2, 0x0f, 0x02, 0xea, 0x10, 0xf9, 0xec, 0xfd, 0x09, 0xea, 0x1f, + 0x46, 0xdd, 0xe2, 0xf7, 0x08, 0xf5, 0xf7, 0xe9, 0x33, 0xfb, 0x2f, 0xf6, + 0xb5, 0x1d, 0x15, 0xeb, 0x11, 0xf7, 0x2a, 0x2e, 0x08, 0x1d, 0xf4, 0xfb, + 0x15, 0xfa, 0x22, 0x34, 0xff, 0x06, 0xf6, 0xfd, 0xfa, 0xf9, 0x03, 0xf5, + 0xf4, 0xf4, 0xd5, 0xea, 0x01, 0x08, 0x22, 0xf1, 0xf2, 0x06, 0xd1, 0xe5, + 0x0c, 0xef, 0x12, 0x03, 0x08, 0x02, 0xf7, 0x05, 0x1b, 0x07, 0x39, 0x34, + 0x21, 0xe2, 0xe3, 0x0b, 0x0c, 0xf6, 0x29, 0xf7, 0x24, 0x0a, 0xfc, 0xff, + 0x1a, 0xfd, 0x05, 0xff, 0xff, 0x0e, 0x0a, 0x1a, 0x09, 0xfb, 0x15, 0x04, + 0x03, 0xf7, 0xfe, 0x00, 0xfc, 0xfb, 0x11, 0xfa, 0x1d, 0x0e, 0x06, 0xed, + 0xfc, 0x23, 0xd8, 0xf2, 0x04, 0xe5, 0x0f, 0x16, 0x29, 0xfe, 0xf5, 0xec, + 0xe2, 0x0e, 0xeb, 0x09, 0x1d, 0x11, 0x05, 0x11, 0xe4, 0x29, 0x12, 0x02, + 0x12, 0x19, 0x0e, 0x1a, 0xee, 0xf9, 0x05, 0x09, 0xf5, 0xfd, 0x05, 0x04, + 0xe4, 0xf1, 0x17, 0x01, 0xf2, 0xfe, 0x0b, 0xf4, 0x0d, 0x04, 0x06, 0xfe, + 0xff, 0xec, 0xe9, 0x00, 0xff, 0x03, 0x03, 0xfd, 0xf1, 0x15, 0xfc, 0xf3, + 0xff, 0xfe, 0x09, 0xee, 0x3c, 0x01, 0xec, 0x02, 0xf0, 0xf6, 0x20, 0xeb, + 0x16, 0x07, 0x32, 0xf3, 0xce, 0xf0, 0x02, 0xd4, 0x11, 0xe6, 0x28, 0x0e, + 0xe3, 0x21, 0xee, 0xce, 0x1e, 0xd9, 0x23, 0x26, 0x06, 0xfa, 0xf9, 0xf1, + 0x01, 0xe6, 0x0b, 0x07, 0xdc, 0x21, 0xbc, 0xe3, 0xef, 0xf8, 0x12, 0xfc, + 0xe6, 0xfe, 0xf5, 0xd4, 0x15, 0x0a, 0x00, 0x13, 0xfc, 0xec, 0xf3, 0xd6, + 0x1a, 0xe3, 0x21, 0x36, 0x2a, 0x03, 0xe9, 0xe3, 0xff, 0x00, 0x13, 0x1c, + 0x0e, 0x20, 0xe5, 0xf5, 0x24, 0x0b, 0x20, 0x14, 0x13, 0xf8, 0x04, 0x1b, + 0x2f, 0x0a, 0x15, 0x00, 0xf4, 0x1a, 0x11, 0x0d, 0x03, 0x18, 0x0f, 0x18, + 0x04, 0x1f, 0xfb, 0xf2, 0x1f, 0x15, 0x03, 0xfb, 0x0b, 0x17, 0xfb, 0x0b, + 0x1b, 0x1f, 0xf4, 0x07, 0xf9, 0xf9, 0xf8, 0xf4, 0x14, 0x0f, 0xf6, 0xfe, + 0xdd, 0x0b, 0xff, 0x01, 0x18, 0x04, 0x1b, 0x0a, 0xed, 0xe7, 0xf9, 0x16, + 0x02, 0x01, 0x00, 0xf7, 0xf1, 0x07, 0xf0, 0x06, 0xf8, 0x0b, 0x02, 0xf3, + 0xff, 0x20, 0xfd, 0x01, 0x04, 0xf5, 0xd9, 0xf4, 0xf4, 0xf2, 0xe8, 0xff, + 0x04, 0x00, 0xf0, 0xe2, 0xfe, 0xed, 0x1b, 0xef, 0x20, 0xfa, 0xfb, 0xf4, + 0x02, 0x18, 0x07, 0xfb, 0xef, 0xe4, 0x08, 0x0d, 0xe1, 0x0e, 0x25, 0xc6, + 0xfd, 0x0c, 0x1c, 0x0b, 0xf0, 0x01, 0x1c, 0xd4, 0x11, 0xf5, 0x1b, 0x09, + 0xfb, 0xda, 0x13, 0xe3, 0xf9, 0x10, 0x14, 0xf0, 0xf0, 0xfd, 0x1f, 0xcf, + 0xf4, 0xe4, 0xfb, 0x0e, 0x0a, 0x11, 0xed, 0xdc, 0xfc, 0xe6, 0xf7, 0xfc, + 0x13, 0xe1, 0x0b, 0xe4, 0x04, 0x11, 0xee, 0x21, 0x14, 0xe1, 0x07, 0xe4, + 0xfb, 0x08, 0x03, 0x2b, 0x27, 0xf6, 0x0d, 0x02, 0x1b, 0x09, 0x09, 0xf8, + 0x14, 0x19, 0x0f, 0x0b, 0x01, 0x10, 0x09, 0x12, 0x03, 0xf5, 0x18, 0xf3, + 0xfb, 0xf5, 0x02, 0x0e, 0x0d, 0x00, 0x07, 0xfc, 0x18, 0x25, 0x0b, 0xf0, + 0xf9, 0xe6, 0x08, 0x01, 0x24, 0x14, 0xfa, 0xed, 0xe5, 0x1f, 0x09, 0xfe, + 0x08, 0xee, 0x1a, 0x1a, 0x05, 0x00, 0xff, 0x0c, 0xfe, 0xf9, 0x11, 0x11, + 0xea, 0xfe, 0x08, 0xf9, 0xf0, 0xe4, 0x01, 0x0d, 0xf1, 0x00, 0x0b, 0xea, + 0x19, 0xea, 0xf3, 0xf8, 0x08, 0x12, 0x1c, 0x1f, 0xfb, 0xef, 0xf0, 0xf2, + 0x14, 0xe1, 0x03, 0xfa, 0xf9, 0xda, 0xe9, 0xfc, 0xf3, 0xff, 0x12, 0x04, + 0xf7, 0xfc, 0x17, 0x0f, 0xfc, 0x29, 0x03, 0xe5, 0xf2, 0xee, 0x1e, 0xfa, + 0x04, 0xed, 0x25, 0xf4, 0xe1, 0x15, 0x10, 0x1e, 0xef, 0x1c, 0x04, 0xde, + 0xe5, 0x08, 0x21, 0xfd, 0xfd, 0xea, 0x03, 0xca, 0xda, 0x26, 0x00, 0x0a, + 0xfd, 0x05, 0xf0, 0xd4, 0xe1, 0x1a, 0xe4, 0xf5, 0x07, 0xe7, 0xfa, 0xdf, + 0xd4, 0x03, 0xf0, 0x10, 0x15, 0x0c, 0xf4, 0xed, 0xe3, 0xfb, 0x0f, 0x1e, + 0x16, 0x09, 0x00, 0xec, 0xea, 0x13, 0x16, 0x0b, 0x01, 0xfb, 0xff, 0x00, + 0xfb, 0x07, 0x13, 0x08, 0xf4, 0xe4, 0x12, 0x00, 0xfb, 0xfa, 0xfc, 0x08, + 0xeb, 0x19, 0x02, 0x1c, 0xe8, 0x26, 0xf3, 0x10, 0x09, 0x0f, 0x19, 0x02, + 0xfb, 0xec, 0xf7, 0xe2, 0xfb, 0xfa, 0x11, 0xf3, 0x0b, 0x08, 0xff, 0xd9, + 0xf8, 0x12, 0x18, 0x06, 0x07, 0x22, 0xff, 0x19, 0xf5, 0x0b, 0x0a, 0x13, + 0xf2, 0xfa, 0x02, 0x21, 0xeb, 0x11, 0x17, 0x17, 0xec, 0xe1, 0x0e, 0xf7, + 0xe8, 0xd8, 0x0e, 0x01, 0xf1, 0xed, 0xed, 0xf0, 0x09, 0xf7, 0xe7, 0xfd, + 0xf0, 0xf9, 0xdb, 0xee, 0xdc, 0xfb, 0xf8, 0x0a, 0xf5, 0x0b, 0xd4, 0xd7, + 0x08, 0x06, 0x18, 0x06, 0x0c, 0x13, 0xfd, 0x09, 0x13, 0x26, 0x12, 0xf4, + 0xef, 0x00, 0xf5, 0x28, 0x18, 0xfe, 0x04, 0x0e, 0x21, 0x1a, 0x0a, 0x1e, + 0x09, 0xf0, 0x0d, 0x0f, 0xec, 0xf3, 0x17, 0x22, 0x00, 0xec, 0x0e, 0x01, + 0xe9, 0x08, 0x09, 0xf2, 0xf2, 0x08, 0xf0, 0x0b, 0xd9, 0x09, 0x14, 0xf5, + 0xf6, 0x04, 0x19, 0xf4, 0x11, 0xe9, 0xf2, 0x0d, 0x20, 0x17, 0x0a, 0x05, + 0x0c, 0x04, 0x01, 0xfd, 0xf4, 0xfb, 0x1b, 0x0c, 0xf2, 0x0b, 0xff, 0xfe, + 0x01, 0xd8, 0xfa, 0x0e, 0xf5, 0x14, 0xf9, 0x01, 0x04, 0xf8, 0xfa, 0x02, + 0xe8, 0xf9, 0xf9, 0xea, 0xf1, 0x07, 0xff, 0x1e, 0x01, 0x0b, 0xf7, 0x0a, + 0xf7, 0x0c, 0xfd, 0xec, 0xf3, 0x05, 0xf8, 0xda, 0x0b, 0x15, 0xf6, 0xee, + 0xf9, 0x10, 0xfa, 0xfe, 0x08, 0xf0, 0xe6, 0xec, 0x05, 0xff, 0x15, 0x19, + 0x1f, 0x11, 0xfc, 0x09, 0x08, 0x01, 0x06, 0xfe, 0x04, 0x08, 0xfb, 0xfb, + 0x08, 0xf4, 0xf6, 0x28, 0x10, 0xf9, 0x28, 0x0b, 0xf8, 0x0d, 0x01, 0x00, + 0xff, 0x02, 0x05, 0x08, 0xea, 0xe9, 0xf4, 0xf6, 0x01, 0xea, 0xdf, 0x1f, + 0xfe, 0x0a, 0xf9, 0xf7, 0x0c, 0x1b, 0x06, 0xed, 0xf6, 0xf2, 0x03, 0x03, + 0xfd, 0x04, 0xf5, 0x10, 0x0a, 0x0b, 0xf4, 0xf8, 0xf1, 0xe7, 0x05, 0xfe, + 0xe7, 0x0b, 0xf1, 0xec, 0xf4, 0xec, 0x06, 0xee, 0xde, 0x05, 0x1b, 0xfe, + 0x13, 0xf3, 0xd9, 0xea, 0x04, 0x10, 0x05, 0xed, 0x15, 0x02, 0x0b, 0x10, + 0xfa, 0x02, 0x05, 0x0b, 0x02, 0x07, 0xfc, 0xf5, 0x15, 0x14, 0x05, 0xf7, + 0x0c, 0xfe, 0xf6, 0xf4, 0xfa, 0x06, 0xfc, 0x13, 0xdc, 0xe4, 0x09, 0xfa, + 0x02, 0x23, 0xec, 0x06, 0x11, 0x13, 0xf8, 0xfa, 0x27, 0x28, 0x0b, 0x23, + 0xec, 0xf1, 0x09, 0x17, 0x0f, 0x13, 0xff, 0xf2, 0xfc, 0x0a, 0xf5, 0x0d, + 0x03, 0x26, 0x01, 0x0f, 0xfe, 0xf1, 0xfb, 0xe6, 0xf0, 0x02, 0xf2, 0xff, + 0x02, 0x11, 0xff, 0xfd, 0x1c, 0x02, 0x0b, 0xf6, 0x14, 0x0c, 0x0b, 0x21, + 0x28, 0xf0, 0x11, 0x05, 0x06, 0xed, 0xf9, 0x0a, 0xf2, 0xef, 0xf8, 0xf1, + 0xfe, 0x0d, 0xf9, 0xf7, 0xea, 0x00, 0x08, 0xdb, 0x02, 0x0f, 0xfe, 0x04, + 0xef, 0x20, 0x16, 0x01, 0xe8, 0xed, 0xe4, 0x22, 0xf6, 0x19, 0x00, 0x04, + 0x01, 0x13, 0xeb, 0x0d, 0xec, 0x01, 0x08, 0x05, 0x0c, 0x0e, 0xfe, 0x02, + 0x12, 0xf7, 0x27, 0xf9, 0xfd, 0x18, 0xfe, 0x24, 0xf7, 0x13, 0xed, 0x1e, + 0x09, 0xff, 0xd8, 0xf4, 0x12, 0xf8, 0x04, 0x0c, 0x1c, 0x11, 0xfd, 0x17, + 0x1d, 0x01, 0x13, 0xee, 0x11, 0xf3, 0xf8, 0x06, 0xf6, 0x16, 0xfe, 0x15, + 0x16, 0xdc, 0x1f, 0x00, 0x25, 0xee, 0xff, 0xf7, 0xf6, 0x02, 0xdd, 0x15, + 0xf1, 0x14, 0x08, 0xe8, 0xe5, 0x21, 0xea, 0xf0, 0x1a, 0x07, 0xea, 0x08, + 0xea, 0xe4, 0x1e, 0x00, 0x13, 0x17, 0xec, 0x11, 0xd6, 0x11, 0x18, 0x17, + 0x04, 0x15, 0x03, 0x3a, 0xd6, 0x02, 0x07, 0x04, 0xe6, 0xe5, 0xfe, 0x0e, + 0xff, 0xed, 0xfc, 0xfb, 0xff, 0x1c, 0x06, 0x0a, 0xfb, 0xf9, 0xea, 0x1a, + 0x21, 0xf5, 0x04, 0x06, 0x0a, 0xe3, 0x16, 0xea, 0x04, 0xe2, 0xf9, 0xf9, + 0xe6, 0xfb, 0x0f, 0xfc, 0x06, 0xfb, 0x10, 0x07, 0x07, 0x13, 0x07, 0xfc, + 0x16, 0xef, 0x07, 0xdc, 0x12, 0x1f, 0x08, 0xf4, 0xe9, 0x14, 0x06, 0xf7, + 0xf1, 0x0c, 0x01, 0x0c, 0xe6, 0x04, 0xf3, 0xf2, 0xe5, 0xf3, 0xef, 0x1d, + 0xf6, 0x20, 0x07, 0xfe, 0xf4, 0x05, 0xee, 0x10, 0xfd, 0x0e, 0x0b, 0x02, + 0x0d, 0xd8, 0x07, 0xfb, 0x26, 0x0a, 0x1c, 0x21, 0x06, 0x1f, 0xf4, 0x06, + 0x37, 0x18, 0xfa, 0x16, 0x1e, 0x24, 0xfb, 0xf0, 0x12, 0xf9, 0x02, 0x09, + 0x17, 0x16, 0xf3, 0xf9, 0x17, 0xf2, 0x02, 0x0a, 0x2d, 0xe7, 0xe3, 0x25, + 0xf0, 0xf9, 0x0f, 0xdd, 0x15, 0xe6, 0x04, 0xfc, 0xf1, 0x17, 0x0a, 0xea, + 0x24, 0x07, 0xf1, 0x11, 0x13, 0x29, 0xf4, 0xc5, 0xfb, 0x07, 0xef, 0x13, + 0x0b, 0xe1, 0xf1, 0xeb, 0xf8, 0x1b, 0x09, 0x08, 0x1f, 0x15, 0xf2, 0x05, + 0x02, 0xdd, 0x09, 0x0f, 0x16, 0x10, 0x01, 0x30, 0xf2, 0xe0, 0x27, 0xfe, + 0xf1, 0x0e, 0x0e, 0x07, 0xe6, 0x07, 0x0b, 0x18, 0xfe, 0x0f, 0x01, 0x07, + 0xf4, 0x07, 0x10, 0xe7, 0xfb, 0xf3, 0xf7, 0x0b, 0xf9, 0x15, 0x18, 0x25, + 0x0c, 0x14, 0x02, 0x08, 0x0a, 0x0f, 0x10, 0xec, 0xee, 0x1a, 0x03, 0x14, + 0x0f, 0xfa, 0x25, 0xff, 0x18, 0x0d, 0x0b, 0xea, 0x1f, 0x28, 0x10, 0x0c, + 0xe7, 0xee, 0xf7, 0xfa, 0x03, 0x15, 0x0c, 0x1d, 0x01, 0x00, 0x12, 0xee, + 0x01, 0xf1, 0xf8, 0x0b, 0xf3, 0xfd, 0x04, 0xf8, 0x02, 0x1e, 0x0e, 0xf3, + 0x02, 0x10, 0xfd, 0x07, 0x0b, 0x09, 0x03, 0x10, 0x3e, 0x08, 0x0e, 0x0c, + 0xf4, 0xe7, 0xfd, 0x1c, 0x27, 0x1a, 0xed, 0xe1, 0x08, 0xdc, 0xd9, 0xf1, + 0x1e, 0x07, 0x12, 0xf1, 0x10, 0xfb, 0xc8, 0x08, 0x0f, 0x03, 0x1d, 0xdc, + 0x23, 0x04, 0xf9, 0x0a, 0xff, 0x08, 0x0e, 0xc9, 0x39, 0x0a, 0x01, 0x07, + 0xec, 0xe0, 0x05, 0xe8, 0x14, 0xd8, 0xe1, 0xfa, 0xd6, 0xf8, 0xed, 0xdb, + 0xff, 0x1d, 0xf5, 0x17, 0x0f, 0x1c, 0xdc, 0xed, 0xff, 0xff, 0x04, 0x13, + 0xf5, 0xe7, 0xd2, 0x12, 0xdb, 0xe1, 0x13, 0x11, 0x23, 0x0e, 0xf9, 0x31, + 0xdc, 0xef, 0x07, 0x0a, 0x20, 0xf2, 0xf9, 0x13, 0xff, 0x1c, 0x2a, 0xdf, + 0xdb, 0xe7, 0x11, 0xf2, 0xfd, 0xfb, 0x28, 0x00, 0x15, 0x03, 0x02, 0x20, + 0x07, 0xf7, 0x19, 0x13, 0x13, 0xf6, 0x09, 0xfe, 0xfd, 0x20, 0x14, 0xf5, + 0xf5, 0xfc, 0x14, 0x0e, 0x17, 0xfe, 0x15, 0x04, 0xf9, 0xf6, 0x1d, 0xf6, + 0x1b, 0xe4, 0xee, 0xfd, 0x00, 0xe9, 0xee, 0xce, 0x0f, 0x20, 0x05, 0x02, + 0x0d, 0x06, 0x05, 0xf8, 0xef, 0xdf, 0x16, 0x17, 0xe6, 0xf1, 0x10, 0xf3, + 0x06, 0x04, 0xdb, 0xfb, 0xe7, 0xf8, 0x02, 0x11, 0xff, 0x0d, 0x0a, 0xfa, + 0x27, 0x0a, 0xfc, 0xe8, 0x11, 0x17, 0xf0, 0x0d, 0x0d, 0xee, 0xdf, 0xdd, + 0xf1, 0x15, 0xd6, 0xf7, 0x00, 0xef, 0x2e, 0xe6, 0x24, 0xfd, 0xd5, 0x04, + 0xf0, 0x08, 0x08, 0xed, 0x22, 0x07, 0xe1, 0x09, 0xd0, 0x0b, 0x18, 0xe6, + 0x3f, 0x0a, 0xe5, 0xe2, 0xf9, 0x08, 0x02, 0xd6, 0x13, 0x15, 0xbd, 0x00, + 0x0e, 0xf8, 0xe2, 0xca, 0xec, 0x0e, 0xe6, 0xef, 0x15, 0x11, 0xcb, 0xdf, + 0xf9, 0x03, 0x22, 0x10, 0xfb, 0xf9, 0xe5, 0x08, 0xe1, 0x11, 0x10, 0xfc, + 0xfa, 0x00, 0xf8, 0x30, 0xe5, 0x08, 0x14, 0xe8, 0x12, 0xe2, 0x04, 0x19, + 0x0b, 0xfa, 0x33, 0xf3, 0xec, 0xfe, 0xf8, 0x25, 0xf8, 0x21, 0x28, 0xef, + 0x00, 0xde, 0xff, 0x2b, 0x03, 0xfc, 0x10, 0x0c, 0xcf, 0xfd, 0x19, 0x0a, + 0x0c, 0xf2, 0xf7, 0x0c, 0xfd, 0x02, 0x1c, 0xdf, 0x26, 0x0d, 0xf0, 0x0b, + 0xce, 0x15, 0xfb, 0xec, 0x27, 0xf6, 0xf9, 0xe5, 0xe2, 0xfb, 0xfd, 0xd8, + 0x28, 0xec, 0xe9, 0xf2, 0xca, 0x09, 0x02, 0x06, 0x0c, 0xfa, 0x05, 0x01, + 0xd5, 0x0a, 0x02, 0xfb, 0x04, 0x17, 0xdd, 0xfe, 0xeb, 0xf1, 0x09, 0x10, + 0x12, 0xff, 0x00, 0xe0, 0x26, 0xf7, 0xed, 0xf4, 0x00, 0xf2, 0xfa, 0x07, + 0x02, 0xf5, 0x06, 0xe8, 0x03, 0xfd, 0xdc, 0xf2, 0xc2, 0xff, 0x0b, 0xd6, + 0x25, 0x04, 0xe9, 0xf0, 0xd9, 0x08, 0x09, 0xc5, 0x23, 0x12, 0xf6, 0x13, + 0x11, 0xf3, 0x18, 0xf0, 0x34, 0xfe, 0xfe, 0xed, 0xea, 0x02, 0x17, 0xdc, + 0x1b, 0x1b, 0xea, 0xfe, 0xea, 0xfe, 0xf2, 0xc4, 0xfd, 0x04, 0xe9, 0x0d, + 0x0d, 0x09, 0xca, 0xd4, 0xe1, 0x04, 0x1e, 0xff, 0x0f, 0xef, 0xd6, 0x0f, + 0xd5, 0xf8, 0x26, 0xd6, 0x33, 0xe8, 0xf5, 0x3b, 0xf1, 0xe8, 0x39, 0xe8, + 0x08, 0xe5, 0x01, 0x02, 0x04, 0xf6, 0x19, 0x0a, 0xd0, 0xeb, 0x0b, 0x15, + 0xf7, 0x0e, 0x23, 0xf6, 0xf4, 0xd8, 0xf4, 0x17, 0x23, 0x25, 0x14, 0x01, + 0xd7, 0xfd, 0xf9, 0x1f, 0x1b, 0x11, 0x0a, 0x18, 0xf5, 0xf5, 0x0f, 0xe0, + 0x2e, 0x01, 0xe5, 0xdb, 0xe2, 0xf2, 0x14, 0xfa, 0x2a, 0x00, 0xe2, 0xea, + 0xfd, 0x0e, 0xfc, 0xc1, 0x35, 0x08, 0xf6, 0xf9, 0xec, 0x00, 0x06, 0x00, + 0x0b, 0xf6, 0x01, 0xfe, 0xea, 0x0b, 0x08, 0x05, 0xe4, 0xea, 0xd7, 0xfd, + 0xee, 0xf3, 0x0c, 0x0c, 0x0d, 0x02, 0xfd, 0xee, 0x17, 0x10, 0x13, 0xfd, + 0x07, 0x03, 0xf8, 0x0c, 0xd4, 0xed, 0xfe, 0x07, 0xf4, 0xee, 0xf4, 0x03, + 0xc2, 0x18, 0x2c, 0xd1, 0x33, 0xd8, 0xdb, 0xfa, 0xed, 0x10, 0x1c, 0xe3, + 0x37, 0x0a, 0xea, 0xfe, 0xf6, 0xef, 0x20, 0xed, 0x32, 0xf7, 0xf5, 0xf3, + 0xca, 0xfd, 0x0a, 0xcf, 0x0d, 0x10, 0xde, 0x07, 0x18, 0x10, 0xf0, 0xd6, + 0x0c, 0x04, 0xeb, 0x1a, 0xf9, 0x08, 0xc4, 0xcb, 0xe4, 0x0b, 0x19, 0xfc, + 0x29, 0xf6, 0xec, 0x07, 0xf3, 0xed, 0x2b, 0xe9, 0xfa, 0x02, 0xec, 0x2b, + 0xf0, 0xf2, 0x2d, 0xe8, 0xed, 0x00, 0x12, 0x13, 0xed, 0x1a, 0x3d, 0xf0, + 0x05, 0x04, 0xfc, 0x13, 0x10, 0x01, 0x40, 0xf2, 0x06, 0x02, 0xf9, 0x22, + 0x24, 0xff, 0x18, 0x00, 0xeb, 0xe8, 0x14, 0xf9, 0x25, 0xe0, 0xff, 0x03, + 0xe5, 0xfd, 0x08, 0xea, 0x2e, 0x0b, 0x05, 0xe7, 0xde, 0xe4, 0xf5, 0xea, + 0x3a, 0xf4, 0xf4, 0xe7, 0xed, 0xec, 0xf8, 0xee, 0x30, 0x0a, 0xdb, 0x05, + 0xf7, 0x16, 0xff, 0xf7, 0xfa, 0x1f, 0xef, 0xe4, 0xce, 0xf8, 0x13, 0x04, + 0xf9, 0x01, 0xe1, 0x03, 0xf9, 0xf9, 0x08, 0x04, 0xfa, 0xe4, 0xe7, 0xf7, + 0x28, 0xfd, 0xfd, 0x00, 0xfc, 0xfb, 0xef, 0x0a, 0xec, 0x0c, 0x0a, 0xd2, + 0x05, 0xfb, 0xcd, 0xfb, 0x9d, 0xea, 0x1c, 0xe5, 0x25, 0xe8, 0xea, 0x0b, + 0xf0, 0xf3, 0x0d, 0xab, 0x49, 0x0e, 0xeb, 0x00, 0xe2, 0x03, 0x29, 0xe0, + 0x3d, 0x06, 0xf7, 0xf8, 0xcf, 0x0c, 0x1a, 0xd6, 0x1f, 0xef, 0xfd, 0xff, + 0xef, 0x0c, 0xdb, 0xe0, 0x20, 0x06, 0xdf, 0x1a, 0xe7, 0xfc, 0xb2, 0xd1, + 0xdf, 0x13, 0x07, 0x1f, 0x0c, 0xf7, 0xde, 0x0a, 0xdb, 0xdf, 0x1a, 0xf5, + 0x29, 0x0d, 0xeb, 0x2c, 0xcf, 0x0e, 0x26, 0xfe, 0xef, 0x04, 0xf5, 0x14, + 0x09, 0x13, 0x34, 0xff, 0xfe, 0x0e, 0x06, 0x0e, 0x10, 0xf9, 0x2a, 0x0b, + 0xe6, 0xfe, 0xf1, 0x1a, 0x36, 0x29, 0x29, 0x05, 0x05, 0xd8, 0x14, 0x12, + 0x26, 0x0b, 0x18, 0xff, 0xd7, 0xdf, 0x0f, 0xed, 0x31, 0xf7, 0xfc, 0xec, + 0x0b, 0xef, 0x0c, 0xd2, 0x30, 0xf9, 0x04, 0xfe, 0xef, 0xe4, 0xfb, 0xd1, + 0x32, 0xe5, 0xee, 0xf0, 0x0c, 0xe6, 0x13, 0xed, 0x1e, 0x0b, 0xe4, 0xe0, + 0xfa, 0xf4, 0x14, 0xf4, 0x18, 0xf7, 0xd9, 0xf6, 0xed, 0xea, 0xfc, 0x06, + 0xfc, 0xf5, 0xed, 0xeb, 0x05, 0x03, 0x1b, 0x0b, 0xff, 0x0b, 0xef, 0x01, + 0xf1, 0x16, 0x05, 0x00, 0xee, 0x0a, 0xdb, 0x10, 0xb4, 0x14, 0x0f, 0xe1, + 0x1c, 0xfd, 0xf0, 0xf8, 0xc3, 0x11, 0x17, 0xba, 0x47, 0x15, 0xe6, 0x01, + 0xea, 0xf1, 0x0c, 0x08, 0x4a, 0x15, 0xf0, 0xf7, 0xea, 0x00, 0xf5, 0xd4, + 0xf1, 0xff, 0xe0, 0x0c, 0xf4, 0x17, 0xd8, 0xea, 0x03, 0xff, 0xd5, 0x18, + 0xfb, 0x07, 0xc7, 0xc9, 0xdd, 0xf3, 0x15, 0x0d, 0x22, 0xea, 0xdb, 0x0a, + 0xd6, 0x09, 0x1d, 0xe5, 0x2d, 0x04, 0xfc, 0x35, 0xc6, 0x0e, 0x33, 0xf1, + 0xd7, 0xea, 0x01, 0x1b, 0x0e, 0x01, 0x2a, 0xff, 0xef, 0xf1, 0xf7, 0x0f, + 0xff, 0x00, 0x3b, 0xe8, 0x0a, 0xff, 0xf4, 0x0d, 0x1f, 0x04, 0x17, 0xf7, + 0xdf, 0xec, 0x12, 0x26, 0x36, 0x07, 0x0c, 0x06, 0xe7, 0xd6, 0x13, 0xe3, + 0x30, 0x09, 0x00, 0xf5, 0xe0, 0xf3, 0x11, 0xe2, 0x38, 0x0d, 0xf6, 0x05, + 0xec, 0x05, 0x00, 0xe5, 0x24, 0xef, 0xfe, 0xf8, 0x00, 0xd8, 0x18, 0xf1, + 0x26, 0x0b, 0xf2, 0xfc, 0xe0, 0xe4, 0x06, 0x0b, 0x1a, 0x05, 0xc6, 0xf6, + 0xe8, 0xde, 0xfe, 0x0c, 0x03, 0x09, 0xfe, 0xe2, 0x18, 0x1b, 0xfb, 0xf7, + 0x06, 0xf1, 0xfe, 0xf6, 0xef, 0x1b, 0x07, 0x0d, 0x01, 0x0a, 0xed, 0xf0, + 0xad, 0x1a, 0x17, 0xd6, 0x37, 0xfd, 0xd8, 0xec, 0xca, 0xf1, 0x15, 0xc4, + 0x33, 0xf1, 0xed, 0xf0, 0xe9, 0x15, 0x0d, 0xf2, 0x36, 0xde, 0xfd, 0x0e, + 0xfb, 0x10, 0x0f, 0xf6, 0xf9, 0x0c, 0xea, 0xf0, 0xe5, 0x0b, 0xee, 0xc1, + 0x10, 0xf4, 0xe8, 0x1f, 0xee, 0x00, 0xd0, 0xe4, 0xe7, 0x13, 0x07, 0x27, + 0x12, 0xea, 0xea, 0x0f, 0xea, 0xf4, 0x14, 0xee, 0xfe, 0x09, 0xfb, 0x31, + 0xdb, 0x1b, 0x1c, 0xe7, 0xef, 0xf5, 0xf7, 0x1a, 0x06, 0x01, 0x2c, 0xed, + 0xfb, 0x04, 0xfa, 0x07, 0x19, 0xec, 0x2b, 0x0d, 0xfc, 0xd8, 0xfc, 0x0f, + 0x1f, 0xfc, 0x2d, 0xf3, 0xc9, 0xda, 0x0a, 0xfe, 0x29, 0x00, 0xfa, 0x09, + 0xe8, 0xf6, 0x21, 0xf3, 0x4a, 0x1a, 0xf8, 0x00, 0xe7, 0xf0, 0x21, 0x01, + 0x22, 0xf3, 0x00, 0xe9, 0x06, 0xe3, 0x15, 0xd7, 0x3d, 0x0c, 0x07, 0xf1, + 0xf3, 0xec, 0x17, 0xdf, 0x29, 0x1b, 0xfd, 0xfe, 0xeb, 0xed, 0x17, 0xf6, + 0x23, 0x0a, 0xea, 0xee, 0xf9, 0xf3, 0x0f, 0x0c, 0xf8, 0xf5, 0xed, 0xe8, + 0x1c, 0x14, 0x07, 0x17, 0x0b, 0x0d, 0xed, 0xf7, 0xed, 0x10, 0x07, 0xd5, + 0xf2, 0x09, 0xd6, 0xf7, 0xb5, 0xf6, 0x19, 0xc9, 0x25, 0x15, 0xe8, 0xf5, + 0xc4, 0xf9, 0x2a, 0xb0, 0x39, 0x0e, 0x02, 0x11, 0xf0, 0xf7, 0x1d, 0xeb, + 0x39, 0x10, 0x02, 0x15, 0xe0, 0x08, 0x01, 0xee, 0x1c, 0x1e, 0x08, 0x04, + 0xf2, 0x02, 0xe8, 0xda, 0xfa, 0xfb, 0xe0, 0xfe, 0x05, 0x02, 0xd3, 0xca, + 0xf4, 0xec, 0x10, 0x16, 0x05, 0x0d, 0xd7, 0x09, 0xdc, 0xf6, 0x1e, 0xf8, + 0x10, 0xed, 0xf7, 0x27, 0xf5, 0x08, 0x28, 0xee, 0xec, 0xe0, 0xf8, 0x17, + 0xfb, 0x23, 0x2e, 0xf1, 0xfa, 0xf5, 0xfc, 0x1a, 0x10, 0xf7, 0x32, 0xfb, + 0xfb, 0xe8, 0xf1, 0x03, 0x24, 0xeb, 0x25, 0xf9, 0xca, 0xf1, 0xfe, 0x01, + 0x2e, 0x07, 0x18, 0x03, 0xe5, 0xea, 0x10, 0xfa, 0x3b, 0x07, 0x0f, 0x11, + 0x04, 0xf7, 0x1d, 0xf1, 0x24, 0xd9, 0x08, 0xef, 0x02, 0xdd, 0x07, 0xc8, + 0x2c, 0x0d, 0x06, 0xec, 0x17, 0xda, 0x21, 0xdf, 0x34, 0xd9, 0xfb, 0xf2, + 0xf4, 0xec, 0x0e, 0x0a, 0x0f, 0x0f, 0xdb, 0xf0, 0xfb, 0xe6, 0x0f, 0x00, + 0x04, 0xf9, 0x01, 0x05, 0x05, 0xfe, 0x08, 0xf3, 0x0e, 0xf2, 0xfb, 0x01, + 0xfd, 0x18, 0x1d, 0xf6, 0xee, 0x06, 0xcf, 0xfc, 0xae, 0x27, 0x21, 0xd2, + 0x33, 0x03, 0xe0, 0xe0, 0xc9, 0xfb, 0x3a, 0xbd, 0x4d, 0x04, 0xe8, 0xf5, + 0xe6, 0xeb, 0x19, 0xf2, 0x4b, 0x1d, 0xfc, 0xf7, 0xd9, 0xff, 0xfe, 0xea, + 0x0f, 0x04, 0x0e, 0x00, 0xed, 0x19, 0xe9, 0xe9, 0xff, 0x11, 0xef, 0x14, + 0x01, 0x17, 0xbc, 0xb5, 0xef, 0x0c, 0x22, 0x27, 0x0f, 0x01, 0xd4, 0x03, + 0xce, 0x01, 0x25, 0xff, 0xf9, 0xf0, 0x0a, 0x1c, 0xe5, 0x0f, 0x1c, 0xee, + 0xf4, 0xf1, 0xf4, 0x0c, 0x00, 0x08, 0x1c, 0xf4, 0xd5, 0xf1, 0xfc, 0x1f, + 0x11, 0x00, 0x18, 0x03, 0xf7, 0xe4, 0xff, 0x07, 0x09, 0x1a, 0x18, 0xff, + 0xea, 0xec, 0xfd, 0x13, 0x2b, 0xf8, 0x0c, 0xfa, 0xdf, 0xf6, 0x11, 0xda, + 0x2a, 0xdc, 0xfc, 0xff, 0xff, 0xec, 0x12, 0xe1, 0x37, 0xfd, 0xeb, 0xfe, + 0xea, 0xd1, 0x12, 0xfa, 0x28, 0x1a, 0x0d, 0xf0, 0xf7, 0xe0, 0x0c, 0xeb, + 0x35, 0x14, 0xeb, 0x00, 0xeb, 0xe7, 0x1b, 0xfc, 0x09, 0x00, 0xf2, 0x04, + 0xf9, 0xe5, 0x1a, 0x0e, 0x08, 0x12, 0xf8, 0xfe, 0x09, 0x0f, 0x0d, 0xea, + 0x03, 0xe1, 0xfe, 0xf2, 0xec, 0x0d, 0x02, 0xdb, 0x04, 0x1d, 0xd4, 0x01, + 0xca, 0x13, 0x29, 0xca, 0x28, 0x04, 0xe2, 0xf1, 0xdb, 0x0b, 0x2c, 0xcd, + 0x44, 0x00, 0xe7, 0xf4, 0xd0, 0x12, 0x15, 0xff, 0x42, 0x11, 0x05, 0xfd, + 0xd9, 0x11, 0x1c, 0xf4, 0x15, 0xec, 0xf2, 0x24, 0xd6, 0x1d, 0xec, 0xda, + 0xf5, 0xec, 0xe5, 0x22, 0xf2, 0x0b, 0xbd, 0xd0, 0xeb, 0x05, 0x07, 0x1b, + 0x01, 0xed, 0xf5, 0x02, 0xcf, 0x08, 0x15, 0xfd, 0x1c, 0xe5, 0x04, 0x19, + 0xc7, 0x25, 0x22, 0xf3, 0xde, 0xfb, 0xfb, 0x20, 0xf6, 0xeb, 0x25, 0xfe, + 0xf5, 0x08, 0xf5, 0x17, 0x0e, 0x04, 0x1c, 0xf9, 0xee, 0xec, 0xe1, 0x06, + 0x12, 0xff, 0x2a, 0x13, 0xed, 0xfe, 0x05, 0x18, 0x25, 0x20, 0x09, 0x13, + 0xea, 0xd7, 0x05, 0x06, 0x33, 0x25, 0xff, 0x0a, 0xf0, 0xea, 0x17, 0xe1, + 0x30, 0xfa, 0x0d, 0x0a, 0x04, 0x00, 0x0e, 0xe9, 0x16, 0x20, 0x0d, 0x02, + 0xe8, 0xed, 0x07, 0xe8, 0x3c, 0xf1, 0xd9, 0xfa, 0xe1, 0xed, 0x18, 0xfc, + 0xf0, 0x09, 0xe3, 0x05, 0xfe, 0xd1, 0x0b, 0x0e, 0xf5, 0x25, 0xfd, 0xfb, + 0x30, 0x1e, 0x08, 0xfc, 0x0c, 0x21, 0xea, 0xfc, 0xe5, 0x1e, 0x16, 0xf5, + 0xf4, 0xfc, 0xf0, 0xea, 0xc4, 0x21, 0x27, 0xe9, 0x2b, 0xdb, 0xdb, 0xec, + 0xe5, 0xfe, 0x37, 0xe2, 0x46, 0x25, 0xfa, 0xec, 0xe4, 0xf3, 0x19, 0xf2, + 0x4c, 0x06, 0x00, 0xfb, 0xeb, 0x10, 0x10, 0xf7, 0x2a, 0xf8, 0xe9, 0x18, + 0xee, 0x21, 0xe8, 0xd5, 0xf4, 0x0a, 0xed, 0x24, 0xfe, 0xf9, 0xb2, 0xbc, + 0xf3, 0x1d, 0x00, 0x2f, 0x07, 0x08, 0xe1, 0xf1, 0xed, 0x27, 0x27, 0xfe, + 0x22, 0xfd, 0x02, 0x20, 0xd8, 0x05, 0x25, 0xec, 0xf1, 0xff, 0x0a, 0x0f, + 0xe6, 0xfe, 0x46, 0xfd, 0xe1, 0xca, 0xf7, 0x22, 0x03, 0x08, 0x21, 0xf5, + 0x0f, 0xf7, 0xfb, 0x0c, 0xfb, 0x14, 0x2d, 0x03, 0xe5, 0xe4, 0x09, 0x0b, + 0x1a, 0xe6, 0x01, 0x28, 0xe9, 0xd6, 0x0b, 0xf7, 0x2c, 0xfb, 0x11, 0xee, + 0x0b, 0xed, 0x17, 0xf0, 0x3c, 0xf5, 0x08, 0xfa, 0xf8, 0xcd, 0x17, 0xfa, + 0x39, 0xea, 0x11, 0xf5, 0xed, 0xee, 0x0a, 0xec, 0x41, 0xd6, 0xe7, 0xf9, + 0xfa, 0xc8, 0x15, 0xf7, 0x08, 0x0e, 0xe3, 0x08, 0xe8, 0xec, 0xfd, 0xfe, + 0xf1, 0x00, 0xe9, 0xf4, 0x09, 0x26, 0x02, 0x16, 0xf0, 0x01, 0xef, 0x01, + 0xff, 0x03, 0x22, 0xdb, 0xfc, 0xf5, 0xde, 0xe5, 0xc4, 0x01, 0x28, 0xd4, + 0x38, 0x08, 0xd0, 0xec, 0xd5, 0x04, 0x2f, 0xce, 0x4e, 0xeb, 0xf9, 0xe7, + 0xdf, 0xf0, 0x1b, 0xf5, 0x42, 0xf1, 0xf6, 0x09, 0xd5, 0x0a, 0x0d, 0x08, + 0x04, 0x05, 0xe2, 0x0e, 0xd7, 0x19, 0xdb, 0xda, 0xe1, 0x25, 0xde, 0x15, + 0x0e, 0x14, 0xbd, 0xb0, 0xe3, 0xe5, 0x24, 0x1e, 0xf8, 0x0d, 0xd8, 0xf7, + 0xf2, 0xff, 0x18, 0xf5, 0x07, 0xf0, 0x02, 0x25, 0xd5, 0x1e, 0x2e, 0xdf, + 0xe7, 0x05, 0xef, 0x11, 0xe8, 0xe7, 0x47, 0xf4, 0xe1, 0xde, 0x09, 0x36, + 0x1a, 0x11, 0x11, 0xf5, 0x12, 0xe5, 0xe7, 0x18, 0x01, 0x17, 0x2a, 0x03, + 0x05, 0xea, 0x09, 0x0b, 0x12, 0x04, 0x17, 0xf0, 0xee, 0xd7, 0x11, 0xed, + 0x3c, 0x17, 0x16, 0xff, 0x02, 0xdc, 0x21, 0xf3, 0x2e, 0xe5, 0x13, 0xef, + 0xec, 0xe2, 0x10, 0xd0, 0x2e, 0xee, 0xff, 0x01, 0xe0, 0xe5, 0x0b, 0xda, + 0x1f, 0xf8, 0xf6, 0xfb, 0x07, 0xdb, 0x05, 0xf6, 0x0c, 0xf3, 0xf0, 0x10, + 0xf9, 0xf5, 0xf2, 0x0d, 0x10, 0xf7, 0xf6, 0xff, 0x2b, 0x0d, 0x06, 0x1e, + 0xf3, 0x0c, 0xe9, 0x01, 0xf2, 0x23, 0xfe, 0xe9, 0xdd, 0x12, 0xdd, 0xf7, + 0xbb, 0x22, 0x1b, 0xd4, 0x38, 0x29, 0xd4, 0xcf, 0xf5, 0xf9, 0x27, 0xdd, + 0x47, 0x00, 0xf2, 0xe5, 0x09, 0xfc, 0x0e, 0xf9, 0x34, 0x0a, 0x02, 0xfd, + 0xec, 0x25, 0x1d, 0x03, 0x15, 0x09, 0xf1, 0x1b, 0xd0, 0x17, 0xda, 0xda, + 0xe7, 0x07, 0xe3, 0x15, 0xf1, 0x02, 0xb9, 0xce, 0xe6, 0x0c, 0x10, 0x31, + 0xfe, 0xf7, 0xd9, 0xfa, 0xed, 0xed, 0x33, 0xf4, 0x19, 0xe7, 0xfe, 0x3f, + 0xe5, 0x06, 0x2e, 0xe6, 0xf2, 0xdc, 0xf5, 0x18, 0xe6, 0x01, 0x2f, 0xee, + 0xe7, 0xe4, 0xfe, 0x2c, 0x03, 0xf7, 0x20, 0x05, 0x07, 0xe2, 0x06, 0x1e, + 0x05, 0xed, 0x2f, 0x03, 0xea, 0xf8, 0x0e, 0x0c, 0x1f, 0xff, 0x20, 0xf4, + 0xe8, 0xe1, 0x1c, 0xec, 0x22, 0x1e, 0x05, 0xfd, 0xf5, 0xca, 0x30, 0xe9, + 0x30, 0xe4, 0x14, 0xff, 0xf2, 0xdc, 0x17, 0xf8, 0x26, 0xe1, 0x0b, 0x01, + 0x11, 0xc2, 0x02, 0xf1, 0x36, 0x10, 0x02, 0x05, 0xed, 0xf1, 0x15, 0xfa, + 0x17, 0xf8, 0xf7, 0xf1, 0xe8, 0xd3, 0xfd, 0x08, 0xfb, 0x27, 0xf5, 0xf5, + 0x13, 0x06, 0x0b, 0xf0, 0x01, 0xf9, 0xd7, 0x0e, 0xec, 0x12, 0xfe, 0xfd, + 0xee, 0x25, 0xd8, 0xf1, 0xb2, 0x09, 0x1c, 0xbf, 0x34, 0xea, 0xc8, 0xea, + 0xdb, 0x0e, 0x24, 0xde, 0x47, 0xfe, 0xdc, 0xe0, 0xf3, 0x06, 0x20, 0xfe, + 0x2b, 0xf6, 0x18, 0x14, 0xcd, 0x19, 0x16, 0xfe, 0x1a, 0x15, 0xf8, 0x11, + 0xf4, 0x22, 0xd7, 0xcc, 0xdd, 0x15, 0xdc, 0x14, 0xf9, 0x02, 0xbb, 0xca, + 0xe3, 0xf3, 0x0d, 0x1e, 0x2a, 0x0c, 0xe4, 0x05, 0xe0, 0x18, 0x2a, 0x07, + 0x20, 0xed, 0xf6, 0x17, 0xcf, 0xf4, 0x2a, 0xd6, 0xfb, 0xce, 0x03, 0x37, + 0xe2, 0xfd, 0x1d, 0xfb, 0xe5, 0xe0, 0x05, 0x29, 0xef, 0x16, 0x23, 0xf7, + 0x01, 0xf4, 0x0c, 0x14, 0xff, 0xee, 0x31, 0xf9, 0x12, 0xf9, 0x14, 0xf6, + 0x0c, 0xf6, 0x0b, 0x0f, 0xd8, 0xdc, 0xfe, 0x0f, 0x37, 0xfa, 0x01, 0x09, + 0x04, 0xd1, 0x0b, 0x0c, 0x29, 0xf3, 0x0a, 0xf9, 0xed, 0xc2, 0x18, 0xf4, + 0x25, 0x18, 0x0f, 0x08, 0xf7, 0xed, 0x1f, 0xf7, 0x4f, 0x0e, 0xf0, 0xe4, + 0x00, 0xeb, 0xfa, 0x1a, 0x0c, 0x03, 0xe9, 0xfc, 0xf0, 0xcc, 0x06, 0x05, + 0xf2, 0x12, 0x04, 0xe2, 0x16, 0x0a, 0x0a, 0xf3, 0x0b, 0xf3, 0xdc, 0xfd, + 0x10, 0xfc, 0x0e, 0xe2, 0xe0, 0xfe, 0xf0, 0xff, 0xb1, 0x06, 0x1b, 0xe4, + 0x30, 0x13, 0xc6, 0xc3, 0xfa, 0x0c, 0x1e, 0xd9, 0x57, 0x11, 0xe1, 0xd6, + 0xfa, 0xee, 0x1d, 0xf7, 0x37, 0xea, 0xf0, 0x05, 0xef, 0x24, 0x1e, 0xf1, + 0x10, 0xe8, 0xeb, 0x19, 0xd1, 0x18, 0xf5, 0xc8, 0xf8, 0xec, 0xf5, 0x1f, + 0xf2, 0xff, 0xb3, 0xd2, 0xe6, 0x0e, 0x06, 0x2e, 0x07, 0x17, 0xe0, 0xf5, + 0x02, 0xf9, 0x20, 0x07, 0x16, 0x08, 0xe8, 0x1d, 0xd3, 0x08, 0x34, 0xda, + 0xf2, 0xce, 0xfb, 0x1f, 0xe1, 0x00, 0x2d, 0xdb, 0xdf, 0xcc, 0x05, 0xfb, + 0xf7, 0x00, 0x33, 0xf9, 0x0b, 0x01, 0x13, 0x28, 0xf8, 0x07, 0x24, 0xf8, + 0x0f, 0x03, 0x0d, 0xe9, 0x06, 0xfe, 0x18, 0xf9, 0xed, 0xf5, 0x0c, 0xe0, + 0x2c, 0x0e, 0xf9, 0x06, 0xfb, 0xce, 0x27, 0xe8, 0x29, 0x19, 0xf9, 0x01, + 0x0e, 0xc8, 0x25, 0xed, 0x30, 0xeb, 0x01, 0xfe, 0x10, 0xdc, 0x1e, 0x00, + 0x1e, 0x10, 0xf9, 0x00, 0xfc, 0xc8, 0x0e, 0x04, 0x13, 0x04, 0xf0, 0x02, + 0xfe, 0xd8, 0x0f, 0x1b, 0xf7, 0xe1, 0xf8, 0xde, 0x12, 0xe2, 0xef, 0x0a, + 0x02, 0xe0, 0xdd, 0xf1, 0x0e, 0x2a, 0x25, 0x15, 0xeb, 0x02, 0xf4, 0xf0, + 0xbf, 0xfc, 0x27, 0xdc, 0x42, 0x0f, 0xe9, 0xbf, 0xe8, 0x20, 0x33, 0xc9, + 0x3f, 0x10, 0xec, 0xf3, 0x03, 0x02, 0x2c, 0x04, 0x38, 0x06, 0x0a, 0xf9, + 0xe5, 0x1c, 0x3f, 0x0f, 0x0c, 0x25, 0xe2, 0x06, 0xe6, 0x03, 0xf4, 0xd7, + 0xfe, 0xf6, 0xe7, 0x2f, 0xfa, 0x03, 0xb6, 0xcb, 0xf1, 0x11, 0x0a, 0x2c, + 0xfc, 0x1e, 0xe0, 0xff, 0xc2, 0xdd, 0x1d, 0xf3, 0x10, 0xfa, 0x07, 0x1e, + 0xf6, 0x20, 0x07, 0xe6, 0xf1, 0x0a, 0xe8, 0x27, 0xf1, 0xf5, 0x24, 0xed, + 0xfd, 0xee, 0x13, 0x15, 0xe9, 0xe2, 0x22, 0xe5, 0xf9, 0xdd, 0x1d, 0x32, + 0x04, 0xfa, 0x25, 0x00, 0xee, 0xfd, 0x0b, 0x0e, 0x23, 0xfa, 0x0f, 0x01, + 0xf8, 0xf0, 0x15, 0xe4, 0x21, 0xf7, 0x10, 0xf9, 0xe7, 0xc3, 0x19, 0xe1, + 0x34, 0xff, 0xed, 0xf4, 0xef, 0xd7, 0x21, 0x01, 0x31, 0xee, 0xf7, 0xf2, + 0xf3, 0xe5, 0x0a, 0xee, 0x2e, 0x1e, 0xf2, 0x0c, 0x07, 0xc2, 0x08, 0x0a, + 0x14, 0x14, 0x00, 0xfc, 0xf9, 0xd6, 0xfb, 0xf8, 0xe5, 0xf1, 0xfa, 0xe0, + 0x15, 0x21, 0xef, 0x06, 0xf9, 0x00, 0xf5, 0xf4, 0x0b, 0x0b, 0x18, 0x02, + 0xf5, 0x04, 0xdb, 0xfd, 0xcc, 0x32, 0x1d, 0xc9, 0x3b, 0x12, 0xd9, 0xaf, + 0xcf, 0x0f, 0x26, 0xde, 0x35, 0xe4, 0xdb, 0xd3, 0x22, 0x11, 0x2e, 0xfb, + 0x36, 0xfa, 0xfd, 0x02, 0xeb, 0x0f, 0x37, 0x0b, 0x14, 0x1d, 0xdd, 0x18, + 0xe0, 0x10, 0xe0, 0xdf, 0x14, 0xf9, 0xf0, 0x19, 0xf7, 0xfb, 0xc4, 0xe5, + 0xe7, 0x11, 0x01, 0x31, 0x1a, 0xf7, 0xd8, 0xf1, 0xe9, 0xf3, 0x21, 0xf9, + 0xfe, 0xe4, 0xe9, 0x02, 0xd0, 0x06, 0x14, 0xd7, 0xfc, 0xec, 0x06, 0x10, + 0xfc, 0xf0, 0x1c, 0xe7, 0xec, 0xe3, 0x03, 0x21, 0xe4, 0x04, 0x12, 0xf0, + 0xf3, 0xed, 0x16, 0x36, 0x02, 0xfd, 0x13, 0x11, 0xdf, 0xeb, 0x19, 0x07, + 0x10, 0x0c, 0xf9, 0x08, 0xf8, 0xf4, 0x1d, 0xfd, 0x1d, 0x16, 0xf4, 0x0a, + 0x08, 0xec, 0x0c, 0x09, 0x3d, 0xe0, 0x0b, 0xee, 0x10, 0xd1, 0x1e, 0x15, + 0x43, 0xeb, 0xfa, 0xf3, 0x05, 0xc7, 0xf2, 0xd9, 0x25, 0x20, 0xee, 0xe9, + 0xfd, 0xce, 0x16, 0x0c, 0x27, 0x06, 0x0a, 0x06, 0xf9, 0xd6, 0x0b, 0x05, + 0xe8, 0x02, 0xe8, 0xd2, 0x10, 0x01, 0xf2, 0x15, 0x09, 0x04, 0xd3, 0xe2, + 0xfe, 0xf0, 0x32, 0x1b, 0xd9, 0xf5, 0xea, 0xcc, 0xcb, 0x10, 0x1c, 0xf1, + 0x3b, 0x02, 0xd4, 0xbf, 0xca, 0xfe, 0x12, 0xdb, 0x3b, 0xf8, 0xd5, 0xe7, + 0x13, 0x10, 0x1a, 0xf4, 0x38, 0x09, 0x08, 0xee, 0xf4, 0xf4, 0x3c, 0xf7, + 0x15, 0x04, 0xe4, 0xfa, 0xf4, 0x04, 0xee, 0xf4, 0x07, 0xf8, 0xe9, 0x3b, + 0xe2, 0x1f, 0xd5, 0xed, 0xe6, 0xfd, 0x18, 0x49, 0x21, 0x06, 0xd8, 0xde, + 0xfa, 0xf0, 0x1b, 0xfe, 0xde, 0x08, 0xf7, 0x14, 0xc7, 0x0f, 0x1d, 0xcf, + 0x00, 0xea, 0xff, 0x1b, 0xd5, 0x08, 0x0d, 0xd9, 0xf1, 0xf4, 0x16, 0x23, + 0xd8, 0x0c, 0x29, 0xdc, 0xf1, 0xf2, 0x21, 0x49, 0xfc, 0xe2, 0x08, 0x01, + 0xf0, 0xf8, 0x17, 0xf9, 0x0f, 0xf5, 0xfa, 0x1a, 0xef, 0xec, 0x09, 0xeb, + 0x1a, 0x0c, 0x17, 0x09, 0x11, 0xe9, 0x1a, 0xf7, 0x29, 0xf9, 0xfd, 0x07, + 0x01, 0xdd, 0x0a, 0xec, 0x22, 0x15, 0x03, 0xfd, 0xe2, 0xd2, 0x15, 0xec, + 0x4d, 0xd7, 0xfc, 0xf6, 0x0b, 0xcc, 0x0e, 0x04, 0x03, 0xf7, 0xfb, 0xfb, + 0x0d, 0xeb, 0x19, 0x07, 0xf4, 0xf4, 0xe5, 0xde, 0x22, 0x07, 0xea, 0xf7, + 0xeb, 0x23, 0xc8, 0xee, 0x03, 0x04, 0x0f, 0x19, 0xc3, 0xf8, 0x06, 0xd0, + 0xf7, 0xfe, 0x0e, 0xe7, 0x0a, 0x02, 0xb0, 0xb8, 0x00, 0xfb, 0x18, 0x0f, + 0x22, 0xf7, 0xe9, 0xdc, 0x09, 0x15, 0x23, 0x0d, 0x22, 0x13, 0xe2, 0xed, + 0xeb, 0x18, 0x20, 0x0b, 0x12, 0xfc, 0x02, 0xf1, 0xdb, 0x0e, 0xe1, 0x04, + 0xdb, 0x0f, 0xf3, 0x1a, 0x06, 0xef, 0xdb, 0xdc, 0xdd, 0xfb, 0x00, 0x2a, + 0x20, 0xfd, 0xc1, 0xe3, 0xef, 0x01, 0x14, 0xf2, 0x14, 0x00, 0x0f, 0x28, + 0xd9, 0xff, 0xf4, 0xdc, 0x09, 0xfa, 0x1c, 0x08, 0xd1, 0x03, 0x0a, 0xf4, + 0xe4, 0xdb, 0x20, 0x30, 0xea, 0x06, 0x11, 0xe2, 0x26, 0xf7, 0x16, 0x22, + 0xf9, 0x07, 0x02, 0xf5, 0xf6, 0xfb, 0x1d, 0x0c, 0x16, 0x0a, 0x07, 0xf9, + 0x11, 0xde, 0x20, 0x08, 0x19, 0x04, 0x0a, 0x0b, 0x0c, 0xf7, 0xf4, 0xfc, + 0x41, 0xf1, 0xf8, 0x16, 0x09, 0xdc, 0x0e, 0x1a, 0x2b, 0x1f, 0xe7, 0xfe, + 0x01, 0xe0, 0xfd, 0xe2, 0x34, 0xec, 0xf3, 0xf5, 0x03, 0xec, 0x0b, 0xfb, + 0x04, 0xf6, 0xdd, 0xfd, 0x06, 0x14, 0x0d, 0xfa, 0xfc, 0xf1, 0x0a, 0xca, + 0x01, 0xec, 0x0e, 0x0e, 0xec, 0xd7, 0xee, 0xd4, 0xf2, 0xfe, 0x16, 0xfa, + 0xbd, 0x0d, 0xef, 0xcb, 0xc4, 0xee, 0xed, 0x13, 0x10, 0x19, 0xf8, 0xb1, + 0xf1, 0xe3, 0x00, 0xf3, 0x0c, 0xf6, 0xde, 0xc6, 0x15, 0x27, 0x14, 0x29, + 0x15, 0xf6, 0xf4, 0xf5, 0xe7, 0x00, 0x0b, 0x2f, 0x0c, 0xef, 0x03, 0x0f, + 0xfd, 0x08, 0xf3, 0xf9, 0xf9, 0x05, 0x0d, 0x34, 0x15, 0x1b, 0xc8, 0xd1, + 0xf2, 0x1b, 0x0a, 0x22, 0x12, 0x11, 0xe9, 0xf4, 0xe1, 0x2a, 0x20, 0x03, + 0xf2, 0xf8, 0x14, 0x0b, 0xd0, 0xf4, 0x0e, 0xbf, 0xc6, 0xd8, 0x04, 0x05, + 0xf8, 0xf4, 0x04, 0xc9, 0xea, 0xfd, 0xf7, 0xfa, 0xe3, 0x1b, 0x11, 0xde, + 0x0c, 0x11, 0x25, 0x29, 0xe5, 0x02, 0xef, 0xef, 0x02, 0xfa, 0x1a, 0x21, + 0x19, 0x09, 0x08, 0x05, 0x04, 0xe5, 0xfa, 0xed, 0x2d, 0x26, 0xfa, 0x17, + 0xf6, 0xe8, 0x12, 0x12, 0x31, 0xfc, 0x0d, 0x00, 0xf7, 0xeb, 0x19, 0xf1, + 0x2a, 0x06, 0x14, 0xec, 0x08, 0xd3, 0x21, 0x07, 0x32, 0xe3, 0x02, 0x0b, + 0xfb, 0xd8, 0x27, 0x07, 0x05, 0xe6, 0xf5, 0xf5, 0x0a, 0xf7, 0x2c, 0x2a, + 0xd8, 0x1b, 0xda, 0xf7, 0xea, 0xf6, 0xf9, 0x0e, 0xf8, 0x0c, 0x05, 0xc7, + 0xd6, 0x06, 0x12, 0xe3, 0xe1, 0xe1, 0xd8, 0xdb, 0xc6, 0xf8, 0xe6, 0xfa, + 0x0c, 0x07, 0xf8, 0xe7, 0xe1, 0x0f, 0x00, 0xf3, 0x03, 0xf0, 0xde, 0xcc, + 0xf5, 0xfc, 0xef, 0x1e, 0x16, 0x13, 0xfb, 0xf4, 0x03, 0xe9, 0xfc, 0xfa, + 0x15, 0xe8, 0x15, 0x09, 0xf1, 0x0d, 0xdb, 0x0a, 0xe8, 0x09, 0xf5, 0x1a, + 0x04, 0xf8, 0xd8, 0xd4, 0x04, 0xee, 0x25, 0x29, 0x09, 0xfe, 0xf3, 0xf5, + 0xd4, 0x0a, 0x15, 0x19, 0xf5, 0x12, 0xfe, 0x04, 0xe7, 0x01, 0xeb, 0xde, + 0xbe, 0xfe, 0x09, 0x12, 0xdf, 0x13, 0xe0, 0xef, 0xc7, 0xff, 0x03, 0x08, + 0xfe, 0xf2, 0x19, 0xe0, 0xe4, 0x0c, 0x22, 0x1e, 0x05, 0xf7, 0x16, 0xf2, + 0xf9, 0x06, 0x17, 0xf6, 0x0c, 0x1e, 0x23, 0x08, 0xfe, 0xdc, 0xfd, 0x17, + 0x11, 0xdf, 0xf5, 0x0f, 0x01, 0x03, 0x08, 0xee, 0x1b, 0x02, 0x0b, 0x1b, + 0x0c, 0x16, 0x1a, 0x00, 0x0f, 0x26, 0x14, 0xf8, 0xf4, 0xf3, 0x19, 0x16, + 0x22, 0x0a, 0xd0, 0xf9, 0xf1, 0x05, 0x2b, 0x1e, 0x1e, 0xef, 0xf5, 0x06, + 0x05, 0xe7, 0x3f, 0x2a, 0x06, 0xf0, 0x15, 0x14, 0x13, 0x20, 0x1b, 0xde, + 0x10, 0x05, 0x33, 0xf8, 0x08, 0x04, 0x17, 0x0d, 0x0f, 0xf6, 0x01, 0xed, + 0x28, 0x25, 0x1c, 0x13, 0xfb, 0xea, 0xfb, 0xf3, 0x1c, 0xf9, 0x1f, 0xf0, + 0xfb, 0x17, 0xf8, 0xff, 0x10, 0xf7, 0x0b, 0x24, 0x04, 0x00, 0x0d, 0x0c, + 0xf7, 0x0a, 0x16, 0x13, 0xf8, 0x05, 0x0a, 0xf1, 0xf5, 0xee, 0xf8, 0x14, + 0x0e, 0xed, 0xfe, 0x1b, 0xfe, 0x17, 0x13, 0x10, 0x12, 0x21, 0x1c, 0xfa, + 0xe5, 0x0b, 0x08, 0x0c, 0x10, 0x1b, 0x03, 0xef, 0x0d, 0x05, 0x0a, 0xf0, + 0x04, 0x11, 0x15, 0x00, 0xfd, 0xef, 0x02, 0x18, 0xf4, 0x09, 0xfa, 0xf6, + 0x02, 0xf7, 0xfd, 0x13, 0xef, 0x13, 0xf7, 0xf9, 0x17, 0x0f, 0xfa, 0xf8, + 0x15, 0xff, 0x04, 0xef, 0xf0, 0x15, 0xfa, 0xfe, 0xf0, 0xf4, 0xed, 0x06, + 0x1c, 0x02, 0xfb, 0xf7, 0x05, 0xfb, 0x0c, 0xef, 0xf4, 0xf0, 0xf6, 0xec, + 0x17, 0xf3, 0xf5, 0xef, 0x02, 0xfd, 0xe5, 0x21, 0x0c, 0xf1, 0x1e, 0x08, + 0xf1, 0x0b, 0xf7, 0x09, 0x1d, 0xf2, 0xf9, 0xf2, 0xfb, 0x0e, 0xed, 0xf8, + 0xfa, 0xdd, 0xf0, 0xfd, 0xdb, 0x1a, 0xf4, 0xef, 0x0c, 0x06, 0x0f, 0xdf, + 0xe2, 0x06, 0x06, 0xee, 0xfa, 0x0d, 0x17, 0xfc, 0xf9, 0x15, 0x1a, 0xe4, + 0xfb, 0x0c, 0x1a, 0xfc, 0x1b, 0x04, 0x07, 0x20, 0xff, 0x09, 0x0f, 0xf2, + 0x26, 0x19, 0x1f, 0x0d, 0x02, 0x16, 0x03, 0x03, 0xfd, 0x05, 0x01, 0x1b, + 0x0a, 0x11, 0xfa, 0x21, 0x13, 0xfb, 0x0c, 0x05, 0xf3, 0xdd, 0xe4, 0xdc, + 0x22, 0x1b, 0x15, 0x14, 0x0e, 0xe8, 0x00, 0xf7, 0xf8, 0xf4, 0x0b, 0x0b, + 0xfd, 0x21, 0xe3, 0x0f, 0xe1, 0x22, 0x01, 0x21, 0x0b, 0x1f, 0x09, 0x10, + 0xe2, 0x18, 0x11, 0x0e, 0xed, 0x01, 0x14, 0x12, 0xfd, 0x11, 0xf6, 0xe9, + 0x20, 0xe1, 0xf5, 0x1b, 0x27, 0x22, 0xfa, 0xf7, 0xfe, 0x13, 0xf6, 0xdc, + 0x06, 0x0d, 0xf4, 0x05, 0x20, 0x0d, 0x0b, 0xe4, 0x15, 0x28, 0x0c, 0x00, + 0xf5, 0x07, 0x0c, 0x0a, 0x06, 0x0e, 0xf3, 0xfb, 0xfe, 0x04, 0x08, 0xf4, + 0xef, 0x03, 0xe4, 0xeb, 0x06, 0xee, 0xed, 0xdb, 0xeb, 0x1d, 0xf4, 0xfa, + 0x0c, 0xfc, 0xfe, 0x11, 0xf7, 0xf8, 0xf5, 0xef, 0xe7, 0xfc, 0x1b, 0xdc, + 0x17, 0xfd, 0xfe, 0x00, 0xea, 0xf4, 0xf1, 0xf7, 0x0f, 0x21, 0x04, 0xfd, + 0x0d, 0x0c, 0x0a, 0x14, 0xfd, 0x19, 0x09, 0x01, 0xfd, 0xe2, 0x0c, 0x0c, + 0xe0, 0x25, 0xfb, 0xff, 0x0d, 0x18, 0xf6, 0x0b, 0x19, 0x12, 0x10, 0x09, + 0x0b, 0x06, 0x12, 0x1c, 0x10, 0x03, 0x13, 0x0a, 0x05, 0x0f, 0x09, 0x01, + 0x21, 0xe4, 0x01, 0x26, 0xf9, 0xf4, 0x05, 0x19, 0x00, 0xff, 0x0b, 0xff, + 0x16, 0x09, 0xe7, 0xee, 0xed, 0xf5, 0x0f, 0x2f, 0xee, 0x19, 0x03, 0x0a, + 0x10, 0xee, 0xf7, 0x2e, 0xf4, 0x08, 0xf7, 0xee, 0x07, 0x00, 0xfc, 0x0e, + 0xf0, 0x12, 0x08, 0x05, 0xed, 0x11, 0xfc, 0xfb, 0xf7, 0x25, 0xf1, 0x05, + 0x0c, 0xf9, 0xfa, 0x03, 0x0c, 0x16, 0x04, 0x25, 0xf8, 0xe7, 0xfc, 0x11, + 0x0d, 0x19, 0xd8, 0xfa, 0x0b, 0x06, 0xfd, 0xef, 0x13, 0xf6, 0xff, 0x0e, + 0xf9, 0x04, 0xf1, 0xdc, 0xfb, 0xe1, 0xf6, 0x0b, 0x15, 0x07, 0xf7, 0x02, + 0x0e, 0xf1, 0xfd, 0xe3, 0xeb, 0x07, 0xf1, 0xef, 0x03, 0xfe, 0xf8, 0x07, + 0x10, 0xf7, 0x00, 0xf9, 0xf2, 0x0e, 0xf9, 0xf2, 0x1d, 0xf5, 0xd8, 0xff, + 0xe6, 0x18, 0x2a, 0x1b, 0x03, 0x16, 0xfe, 0xf4, 0xf5, 0xfd, 0x04, 0x01, + 0xfe, 0xfe, 0x07, 0xfc, 0x0e, 0xfa, 0x15, 0xeb, 0x02, 0x15, 0xea, 0xfd, + 0x04, 0xe5, 0xfe, 0xed, 0xfe, 0x1a, 0x09, 0x2a, 0x1b, 0xdf, 0xfb, 0xf8, + 0xf1, 0x04, 0x1a, 0x34, 0x07, 0xf9, 0x0d, 0xf5, 0xef, 0xec, 0x10, 0x1a, + 0x0b, 0x0f, 0x13, 0xfe, 0x10, 0x22, 0x1e, 0x02, 0xe6, 0xf7, 0x11, 0xfa, + 0x11, 0xfc, 0x1b, 0x21, 0x12, 0xf4, 0x18, 0x16, 0x29, 0xe4, 0x0c, 0x2e, + 0x12, 0x07, 0x20, 0xf6, 0x1d, 0xf4, 0x12, 0x33, 0xf4, 0xee, 0xfe, 0x05, + 0x06, 0xfb, 0x13, 0x0c, 0x0e, 0xf0, 0x00, 0xf8, 0xee, 0xf3, 0x17, 0x00, + 0xf7, 0xfb, 0xfc, 0x0f, 0xf4, 0xd5, 0x0a, 0xed, 0xeb, 0xf5, 0xe9, 0xef, + 0xd8, 0xf0, 0xf8, 0xe2, 0x19, 0xf7, 0xf8, 0x0a, 0x0b, 0x09, 0xfa, 0xe7, + 0x0f, 0xfc, 0xe8, 0x02, 0x00, 0x1a, 0xfe, 0xfd, 0x1b, 0xe6, 0xef, 0x0f, + 0xe3, 0x10, 0xf1, 0xe2, 0x0b, 0x0e, 0x06, 0x29, 0x00, 0x01, 0xf3, 0x00, + 0x11, 0x04, 0xf2, 0xf7, 0xea, 0xf8, 0xe0, 0x09, 0x0e, 0x13, 0xf4, 0x00, + 0x09, 0xfa, 0xf5, 0x0c, 0xff, 0x18, 0x08, 0x0d, 0xfa, 0xde, 0xfa, 0x03, + 0xf2, 0xf3, 0x1b, 0xeb, 0x06, 0xea, 0xfb, 0xff, 0x0d, 0xf5, 0x10, 0x17, + 0xf8, 0xe8, 0xf1, 0xf1, 0xf5, 0x00, 0x03, 0x0a, 0x09, 0x0a, 0xf3, 0xfb, + 0x33, 0x26, 0xe7, 0x17, 0xe3, 0xfa, 0x1f, 0x24, 0xfc, 0x07, 0x02, 0xe2, + 0xeb, 0x08, 0x2c, 0xf8, 0x02, 0x1f, 0x04, 0xeb, 0x0b, 0x04, 0x17, 0xf7, + 0xff, 0x1c, 0xed, 0x00, 0x3f, 0xd5, 0x17, 0x1d, 0xfe, 0x03, 0xf1, 0x1c, + 0x17, 0xec, 0x0e, 0x54, 0xee, 0xf5, 0x25, 0xfa, 0x08, 0xee, 0x13, 0x32, + 0x0e, 0xd8, 0x09, 0x0f, 0xee, 0xe5, 0x06, 0x10, 0xf4, 0xfb, 0xe4, 0xfb, + 0x09, 0xde, 0x13, 0xff, 0x02, 0xf9, 0xec, 0x0a, 0x00, 0xe9, 0xfd, 0xdc, + 0x06, 0x04, 0xdb, 0x06, 0x01, 0xf8, 0x09, 0xe2, 0x0c, 0x14, 0xda, 0xfe, + 0x20, 0xe3, 0x09, 0xda, 0x14, 0x12, 0xe1, 0x05, 0xff, 0xf3, 0x00, 0x08, + 0xfb, 0xf1, 0xfd, 0xf3, 0x04, 0xfa, 0x08, 0xff, 0x01, 0x1d, 0x0b, 0xfd, + 0x0a, 0xf4, 0xfb, 0xfc, 0xf9, 0x19, 0xed, 0xfc, 0xf2, 0x06, 0xe7, 0x02, + 0xf6, 0x0c, 0xfc, 0xfb, 0x01, 0x0c, 0xeb, 0x1b, 0xff, 0xff, 0x08, 0x1d, + 0xf7, 0xe8, 0xfc, 0xf4, 0x0c, 0xfa, 0xf1, 0xee, 0xed, 0xdd, 0xfc, 0x06, + 0x05, 0xdc, 0x1a, 0xfc, 0xf9, 0x07, 0xdf, 0x1b, 0x14, 0x0c, 0xfc, 0x01, + 0x16, 0xe1, 0xed, 0x09, 0x34, 0xee, 0xe4, 0x1c, 0x1b, 0xfc, 0x3b, 0x03, + 0x15, 0xf2, 0xeb, 0x14, 0x00, 0xdd, 0x24, 0x04, 0xf1, 0xed, 0xfd, 0xe6, + 0x32, 0xf9, 0x24, 0x04, 0x0e, 0x22, 0x03, 0x14, 0x2f, 0xf5, 0x1a, 0x37, + 0xf4, 0x18, 0x03, 0x0f, 0x4b, 0xe6, 0x0d, 0x5c, 0xf7, 0x1f, 0x1c, 0xe6, + 0x23, 0x0c, 0x15, 0x4e, 0xe0, 0x05, 0x1c, 0xec, 0xff, 0x04, 0x13, 0x15, + 0xee, 0x07, 0xec, 0x0c, 0xdd, 0xf8, 0x0e, 0x03, 0x0c, 0x1f, 0xe8, 0x0e, + 0xf5, 0xec, 0xfc, 0xe2, 0xe8, 0xfb, 0xf6, 0x00, 0xe5, 0xea, 0xf3, 0xd3, + 0xf5, 0xfd, 0xd2, 0xfd, 0x1b, 0xed, 0x09, 0xd1, 0x23, 0xfa, 0xd4, 0xf7, + 0xe9, 0xf0, 0x0a, 0xd6, 0x14, 0x03, 0xe6, 0x10, 0xf4, 0x18, 0xfe, 0xe1, + 0x0b, 0x25, 0xf5, 0xfc, 0xe9, 0xf2, 0xe9, 0xf4, 0x0d, 0xf5, 0x00, 0xf9, + 0x17, 0x02, 0xfd, 0x03, 0x04, 0xf8, 0xf5, 0x14, 0xe3, 0xd3, 0xeb, 0xe7, + 0x09, 0xf3, 0x14, 0x17, 0xee, 0xe6, 0xf6, 0xff, 0x11, 0x26, 0xf4, 0xf7, + 0x02, 0xfa, 0x05, 0x08, 0x16, 0xff, 0x0d, 0xf7, 0xf1, 0xf7, 0xe6, 0xfb, + 0x04, 0x04, 0x07, 0x02, 0x04, 0x09, 0xf5, 0xfc, 0x5f, 0xd6, 0xe7, 0x2a, + 0x23, 0xf4, 0x1b, 0x06, 0x01, 0xea, 0xe7, 0x05, 0x25, 0xe3, 0x25, 0x07, + 0xea, 0xfb, 0xfb, 0x09, 0x25, 0xde, 0x37, 0x04, 0x07, 0xe5, 0xff, 0x14, + 0x2f, 0x0a, 0x30, 0x23, 0x04, 0xf0, 0x23, 0xfe, 0x1c, 0xd2, 0x2b, 0x55, + 0x01, 0xe5, 0x26, 0xfe, 0x14, 0xed, 0x24, 0x46, 0xe6, 0xee, 0x0f, 0xfd, + 0xed, 0xef, 0x0e, 0x1e, 0x05, 0x0a, 0x12, 0xff, 0xe4, 0xf5, 0x0c, 0xed, + 0xfd, 0xea, 0x0d, 0x13, 0x1a, 0xe5, 0xfc, 0xc2, 0xef, 0x0a, 0xe2, 0x0f, + 0xfe, 0xff, 0x0c, 0xf0, 0xff, 0xdf, 0xea, 0x00, 0xf6, 0xe1, 0x04, 0xd8, + 0x26, 0x20, 0xdc, 0xf4, 0x19, 0x06, 0xe8, 0xd2, 0x10, 0x04, 0xf1, 0x02, + 0x0c, 0x06, 0xf0, 0xf0, 0x04, 0x1f, 0xf4, 0xf5, 0xed, 0xf1, 0xfa, 0xf1, + 0x04, 0x02, 0xf8, 0xfb, 0x04, 0xf1, 0xe5, 0xe4, 0x0a, 0xf0, 0xfe, 0xef, + 0x1c, 0xe3, 0xeb, 0xf3, 0x00, 0x17, 0x01, 0x13, 0x19, 0xda, 0xf8, 0x06, + 0xde, 0x11, 0xea, 0xf7, 0xf4, 0xef, 0x03, 0x04, 0x0b, 0xe8, 0x08, 0x0e, + 0xe2, 0xee, 0xde, 0x06, 0x0e, 0x29, 0xfb, 0xfa, 0x00, 0x02, 0xec, 0x1b, + 0x52, 0xff, 0xde, 0x3a, 0x2f, 0x13, 0x30, 0xe9, 0xff, 0xf6, 0xe7, 0x15, + 0x1d, 0xd9, 0x3c, 0x0f, 0xe6, 0x14, 0xee, 0x13, 0x1f, 0xe7, 0x33, 0x08, + 0xfc, 0x06, 0x0c, 0x08, 0x19, 0xd9, 0x2b, 0x1f, 0x07, 0x10, 0x24, 0x16, + 0x29, 0xfc, 0x31, 0x4d, 0xf0, 0xd9, 0x3f, 0xf2, 0x20, 0xe2, 0x25, 0x49, + 0xe5, 0xec, 0x0a, 0xf5, 0xf2, 0xd9, 0x22, 0x1f, 0xed, 0x22, 0x02, 0x0a, + 0x16, 0x08, 0xf7, 0xfb, 0x0e, 0xfb, 0xfb, 0x1d, 0xf3, 0x1c, 0xf6, 0xe1, + 0xcf, 0x19, 0xf4, 0x0f, 0xee, 0xf9, 0x04, 0xd1, 0xf9, 0xe2, 0xda, 0xf1, + 0x24, 0xf5, 0x07, 0xdf, 0x1d, 0xf9, 0xdb, 0x18, 0x0b, 0xea, 0x08, 0xca, + 0xf2, 0xfa, 0xec, 0x04, 0x0e, 0x17, 0xed, 0xf1, 0x06, 0x15, 0xfc, 0xfd, + 0x08, 0xfa, 0xe3, 0xe4, 0x0a, 0xfc, 0xee, 0x08, 0xf5, 0x09, 0xef, 0xee, + 0x06, 0xef, 0xe1, 0x19, 0x07, 0xe8, 0xe6, 0xdf, 0xea, 0x0d, 0xf1, 0x16, + 0xee, 0xed, 0xf8, 0x09, 0xfa, 0xfb, 0x0c, 0xf8, 0xeb, 0xda, 0x00, 0xfc, + 0x04, 0xfe, 0xf5, 0xff, 0xf6, 0xe1, 0x0c, 0x0a, 0x13, 0x0d, 0xf6, 0xf5, + 0x15, 0x07, 0xca, 0xec, 0x50, 0x0e, 0xd0, 0x26, 0x4c, 0xf8, 0x23, 0xeb, + 0xff, 0x08, 0xe3, 0x11, 0x2c, 0xf9, 0x2a, 0xf1, 0xe9, 0x0b, 0xe9, 0x0f, + 0x15, 0xec, 0x33, 0x11, 0x0c, 0x0d, 0x01, 0x01, 0x32, 0xe3, 0x41, 0x27, + 0x11, 0x02, 0x2e, 0x07, 0x09, 0xe3, 0x22, 0x4d, 0xf1, 0x05, 0x27, 0x03, + 0x25, 0xf5, 0x2c, 0x3b, 0xf4, 0x00, 0x16, 0x0b, 0xec, 0xfe, 0x17, 0x0d, + 0xff, 0xe7, 0xfe, 0x24, 0x06, 0xee, 0xf0, 0xe9, 0xfa, 0x1c, 0xf2, 0x19, + 0x08, 0xfa, 0xff, 0xd2, 0x01, 0x02, 0xea, 0x05, 0xf2, 0xf4, 0x0b, 0xd2, + 0xf9, 0x0d, 0xcd, 0x0d, 0x12, 0xf2, 0x0e, 0xe1, 0x1f, 0x00, 0xe7, 0x14, + 0x04, 0xff, 0x09, 0xdb, 0xfc, 0xd9, 0x06, 0xf9, 0xeb, 0x01, 0xef, 0xfa, + 0xfb, 0xf5, 0xfc, 0xfb, 0x14, 0xe2, 0xf9, 0xf5, 0x02, 0xfd, 0xfc, 0x01, + 0xf7, 0xf3, 0x00, 0xec, 0xe7, 0xf2, 0x00, 0xf1, 0x11, 0xec, 0xf0, 0xe9, + 0x11, 0x0a, 0x07, 0x04, 0x01, 0xee, 0xfb, 0xf2, 0x14, 0x01, 0x12, 0xf0, + 0xf2, 0xf1, 0xf0, 0xfb, 0x08, 0x03, 0xf8, 0x01, 0xe8, 0xf9, 0x17, 0x26, + 0x0f, 0xea, 0xf7, 0xf8, 0x1e, 0xfe, 0xf2, 0xf8, 0x3f, 0x00, 0xd4, 0x1c, + 0x53, 0xfe, 0x1e, 0x0f, 0xef, 0xdd, 0xed, 0x10, 0x19, 0xe7, 0x34, 0x0e, + 0xde, 0xdf, 0xfa, 0x0e, 0x29, 0xe3, 0x16, 0x09, 0x06, 0x12, 0xeb, 0xf9, + 0x32, 0xe0, 0x1a, 0x1d, 0xf3, 0xed, 0x10, 0x07, 0x31, 0xf2, 0x12, 0x52, + 0xeb, 0xf7, 0x1e, 0xf7, 0x1a, 0xdc, 0x3e, 0x33, 0xe3, 0xfb, 0x1f, 0x0b, + 0x08, 0xfe, 0x13, 0x1a, 0xf4, 0xf8, 0xfe, 0x08, 0xfc, 0xe9, 0xfe, 0xeb, + 0xe6, 0xf6, 0x02, 0x18, 0x02, 0xe8, 0xfb, 0xf3, 0x01, 0x08, 0xd7, 0x13, + 0x04, 0xe6, 0x02, 0xe6, 0xd7, 0x01, 0xd4, 0xf0, 0x0e, 0x05, 0x18, 0xe5, + 0x08, 0xe5, 0xd2, 0x16, 0x12, 0xfe, 0x0e, 0xd3, 0xfc, 0x1f, 0xe9, 0xf8, + 0x11, 0x06, 0xf3, 0xd5, 0xf8, 0xff, 0xf0, 0x04, 0x0a, 0xd9, 0xf8, 0xfd, + 0xf5, 0x12, 0xff, 0x06, 0x1b, 0xe6, 0xfe, 0xfe, 0xde, 0xee, 0xf6, 0x18, + 0xf1, 0xf8, 0x06, 0xf3, 0x02, 0xea, 0x04, 0x14, 0xfc, 0xee, 0xe6, 0x09, + 0xf9, 0xee, 0xe3, 0xe7, 0xfc, 0xd9, 0xef, 0xfc, 0x0a, 0x0c, 0x03, 0xf6, + 0xe2, 0x11, 0x0f, 0x19, 0x18, 0x10, 0xef, 0xe5, 0x22, 0xf5, 0xe5, 0xe9, + 0x4b, 0xf7, 0xdb, 0x0c, 0x4f, 0xde, 0x22, 0x16, 0x09, 0x16, 0xd1, 0xf8, + 0x19, 0xe0, 0x24, 0xfe, 0xb8, 0xfb, 0xe5, 0x12, 0x1c, 0xe3, 0x22, 0x09, + 0x05, 0x29, 0xf7, 0x10, 0x31, 0xe1, 0x33, 0x3f, 0xfd, 0xed, 0x04, 0x03, + 0x2e, 0xed, 0x30, 0x36, 0xee, 0x16, 0x2f, 0xf5, 0x1b, 0xdc, 0x3a, 0x56, + 0xe5, 0xef, 0x26, 0xff, 0x03, 0xd7, 0x31, 0x16, 0xef, 0xf1, 0x08, 0x13, + 0x01, 0x02, 0x03, 0xf1, 0xf2, 0x08, 0xff, 0x05, 0x12, 0xf2, 0xee, 0xda, + 0xed, 0xec, 0xea, 0xf7, 0x0c, 0xf1, 0x09, 0xe6, 0xe6, 0x00, 0xcc, 0x10, + 0x0d, 0x0d, 0x20, 0xf4, 0x18, 0x23, 0xec, 0xf9, 0x00, 0xe4, 0x07, 0xd4, + 0xfb, 0x16, 0xd2, 0x01, 0xe6, 0x01, 0x06, 0xf0, 0xfe, 0x03, 0xf3, 0x09, + 0x01, 0x0d, 0x05, 0xf7, 0xd4, 0x02, 0xfb, 0xfb, 0x08, 0xf0, 0x1f, 0xf3, + 0xfe, 0xeb, 0x02, 0x0e, 0x1b, 0x0f, 0x04, 0xf5, 0xf0, 0x1f, 0x14, 0xf7, + 0x06, 0xdc, 0xf9, 0xe9, 0x01, 0xff, 0x08, 0xf2, 0x06, 0xff, 0xff, 0xf3, + 0x05, 0x1a, 0xfc, 0xfa, 0xeb, 0xfb, 0xfa, 0x12, 0x20, 0xf6, 0xe0, 0xe8, + 0x1c, 0xfa, 0xd6, 0x0d, 0x2c, 0x04, 0xe1, 0x09, 0x3b, 0xd3, 0x2a, 0xee, + 0xf7, 0xed, 0xf1, 0xf7, 0x0d, 0xf0, 0x32, 0x0f, 0xc9, 0x0e, 0x00, 0x10, + 0x24, 0xfb, 0x31, 0xf0, 0xf4, 0xdd, 0xf5, 0x04, 0x25, 0xc7, 0x27, 0x25, + 0x16, 0x11, 0x2e, 0x09, 0x30, 0xd1, 0x2c, 0x34, 0xe6, 0xf0, 0x21, 0xf5, + 0x21, 0xc8, 0x40, 0x39, 0xde, 0xf0, 0x12, 0xf3, 0x10, 0xe8, 0x1f, 0x18, + 0xfa, 0xea, 0x07, 0x11, 0xdf, 0xed, 0xfa, 0xf0, 0x07, 0xef, 0xf3, 0x05, + 0x10, 0xe5, 0xf3, 0xe9, 0xe9, 0xe8, 0xd6, 0x01, 0xf9, 0x05, 0x0b, 0xee, + 0xf9, 0x12, 0xe3, 0x05, 0xfd, 0xe6, 0x16, 0xe2, 0x1b, 0x12, 0xc5, 0x00, + 0xfd, 0x02, 0x04, 0xd2, 0xff, 0xec, 0xf6, 0xfd, 0x00, 0xe4, 0xf7, 0xf3, + 0xeb, 0xfa, 0xf8, 0x0d, 0x03, 0xfa, 0xfe, 0xe4, 0xdb, 0xe3, 0x06, 0xff, + 0xf4, 0xf2, 0x1b, 0xf1, 0xf7, 0x02, 0x01, 0x04, 0x13, 0xe5, 0x0c, 0x05, + 0xf7, 0x0a, 0x03, 0x03, 0x0b, 0x03, 0xee, 0xf7, 0x21, 0x20, 0xff, 0xf3, + 0x09, 0xe5, 0xff, 0xec, 0x17, 0x00, 0x06, 0x14, 0xeb, 0xf2, 0x18, 0x16, + 0x1f, 0xec, 0xee, 0xe1, 0x1e, 0x03, 0xfa, 0xfe, 0x28, 0x03, 0xc9, 0x0c, + 0x3f, 0xd8, 0x30, 0x16, 0x03, 0xf8, 0xe9, 0xfb, 0x28, 0xe1, 0x36, 0x0a, + 0xdf, 0xe5, 0xeb, 0x08, 0x1c, 0xcd, 0x29, 0xf2, 0xfc, 0x0a, 0xed, 0x01, + 0x29, 0xf1, 0x20, 0x13, 0x04, 0xec, 0x17, 0x0a, 0x35, 0xc3, 0x1a, 0x46, + 0xe0, 0xd7, 0x3c, 0x09, 0x28, 0xd1, 0x22, 0x20, 0xd5, 0xfa, 0x28, 0xfa, + 0xff, 0xea, 0x1d, 0x23, 0xe0, 0x07, 0x07, 0x0f, 0xf1, 0xf1, 0x08, 0xf0, + 0xf8, 0xff, 0x05, 0x1b, 0x05, 0xfa, 0xf0, 0xfb, 0xe3, 0xe4, 0xcc, 0x1a, + 0xf9, 0x09, 0x06, 0xee, 0xf4, 0x03, 0xd0, 0x14, 0xf4, 0xff, 0x1d, 0xe8, + 0x11, 0xf4, 0xd1, 0xf4, 0x04, 0x0b, 0xfb, 0xdc, 0x0a, 0x0c, 0xeb, 0xed, + 0x06, 0xf3, 0x04, 0xdd, 0xdf, 0xf9, 0xea, 0xfc, 0xf5, 0xf2, 0xfb, 0xea, + 0xe3, 0x03, 0xee, 0x0e, 0xff, 0xdb, 0x1e, 0x04, 0xf7, 0x1a, 0x04, 0x0c, + 0x0d, 0xda, 0x04, 0xe9, 0xff, 0x04, 0x00, 0x0c, 0xf9, 0xe4, 0xfb, 0xf6, + 0x14, 0xde, 0x1b, 0x00, 0x0b, 0xfe, 0x06, 0xf8, 0x0f, 0xdc, 0x01, 0xef, + 0xef, 0x0d, 0xf8, 0xf1, 0x0f, 0xf9, 0xf9, 0xdf, 0x0d, 0xe4, 0xd9, 0xf9, + 0x2b, 0xee, 0xe8, 0x09, 0x40, 0xf9, 0x2f, 0x0a, 0xfa, 0xe8, 0xe9, 0x01, + 0x0e, 0xe7, 0x23, 0x0a, 0xd0, 0x19, 0xd3, 0x0e, 0x04, 0xda, 0x2b, 0x0f, + 0xe7, 0xe6, 0xf3, 0xfb, 0x2c, 0xd3, 0x36, 0x19, 0x0e, 0xfe, 0x03, 0x1a, + 0x2e, 0xd0, 0x23, 0x32, 0xf1, 0xe1, 0x2a, 0x09, 0x1b, 0xf6, 0x29, 0x3e, + 0xce, 0x15, 0x0a, 0xe8, 0xec, 0xdf, 0x44, 0x28, 0xd9, 0xfd, 0xfa, 0x09, + 0xff, 0xe7, 0x08, 0xec, 0xf4, 0xef, 0x01, 0x19, 0x11, 0xf3, 0xeb, 0xeb, + 0xed, 0x1a, 0xdd, 0x15, 0x0f, 0x07, 0xfe, 0xeb, 0xff, 0xd6, 0xd5, 0x04, + 0xf5, 0x07, 0x10, 0xe6, 0x0c, 0xe4, 0xda, 0x0c, 0x08, 0xee, 0x06, 0xd8, + 0xf8, 0xf1, 0xe0, 0x01, 0x08, 0xfe, 0xf9, 0xf3, 0xdf, 0x03, 0xe6, 0xf4, + 0x0a, 0xff, 0xf2, 0xe0, 0xd9, 0xeb, 0x01, 0x10, 0x02, 0xfc, 0x0d, 0x14, + 0xea, 0xf8, 0x03, 0x18, 0xf3, 0x09, 0xfc, 0x0c, 0x0b, 0x1f, 0xf5, 0x05, + 0xf7, 0xf9, 0x00, 0xfd, 0x04, 0xfc, 0x16, 0x07, 0x00, 0xdf, 0xf9, 0xfa, + 0x0c, 0xfb, 0xf4, 0xf7, 0xf0, 0xeb, 0x07, 0x17, 0x20, 0xfb, 0xf0, 0xec, + 0x04, 0x00, 0xf8, 0xf2, 0x2d, 0xf9, 0xd9, 0x0b, 0x55, 0xec, 0x33, 0x26, + 0xf8, 0x0a, 0xf2, 0x0b, 0x25, 0xdf, 0x29, 0x05, 0xd1, 0x14, 0xe2, 0xf2, + 0x12, 0xdd, 0x28, 0xfc, 0xec, 0x08, 0xfd, 0x02, 0x3a, 0xe6, 0x29, 0x25, + 0x0d, 0x10, 0x09, 0x0a, 0x32, 0xf5, 0x17, 0x2d, 0xea, 0xfb, 0x35, 0xfc, + 0x28, 0xd0, 0x29, 0x2f, 0xcb, 0x06, 0x0f, 0x04, 0xf2, 0xf3, 0x34, 0x1c, + 0xf4, 0x08, 0x05, 0xfc, 0xfd, 0xed, 0x0f, 0xf8, 0xe9, 0xf0, 0x09, 0x16, + 0xfe, 0x02, 0xff, 0xd4, 0xea, 0x0a, 0xeb, 0x0c, 0xf8, 0xf4, 0x09, 0xf4, + 0xf2, 0x07, 0xd9, 0x0b, 0xfd, 0xe4, 0x1a, 0xef, 0x14, 0x08, 0xd8, 0xfc, + 0xf5, 0xe1, 0x03, 0xcf, 0xf1, 0x11, 0xdb, 0x15, 0x07, 0x10, 0xf8, 0xfc, + 0xe2, 0xf1, 0xf5, 0xde, 0xff, 0xe7, 0x01, 0xea, 0xee, 0xe9, 0x02, 0x0a, + 0x18, 0xec, 0xfe, 0xf9, 0x09, 0xf3, 0x0e, 0x02, 0xf1, 0xfc, 0xf9, 0x16, + 0x05, 0x07, 0x09, 0x0d, 0x0e, 0xf7, 0x04, 0xed, 0x04, 0xdb, 0x04, 0x04, + 0xf6, 0xdc, 0xee, 0xec, 0xf5, 0xfe, 0xf4, 0x02, 0xe4, 0x0b, 0xe0, 0x17, + 0x0a, 0xe0, 0xf7, 0xdc, 0x11, 0xd6, 0xfe, 0xfa, 0x35, 0xde, 0xe6, 0x06, + 0x44, 0xf9, 0x35, 0x0a, 0xfb, 0xff, 0xec, 0xfb, 0x16, 0xd9, 0x23, 0x0f, + 0xd4, 0xef, 0xdf, 0x06, 0x0b, 0xd9, 0x25, 0xff, 0xf8, 0xeb, 0xf4, 0x0a, + 0x20, 0xe5, 0x22, 0x1c, 0xeb, 0xf4, 0x0d, 0x0c, 0x19, 0xe1, 0x1e, 0x31, + 0xe9, 0xfb, 0x20, 0xf0, 0x23, 0xfe, 0x35, 0x28, 0xb4, 0x06, 0x28, 0xe7, + 0xfb, 0xe9, 0x2a, 0x1a, 0xef, 0x15, 0x0c, 0xed, 0xf1, 0x04, 0x0e, 0x0a, + 0xff, 0x16, 0x01, 0x04, 0x17, 0xea, 0xec, 0xdc, 0xf4, 0xf7, 0x04, 0x16, + 0x1f, 0x0a, 0x11, 0xef, 0x12, 0xdf, 0xd9, 0x0c, 0xf5, 0x10, 0x02, 0xf3, + 0x10, 0x03, 0xd3, 0xf5, 0x0b, 0x02, 0x00, 0xcb, 0xf6, 0x23, 0xf6, 0xf1, + 0x1f, 0xf9, 0xfc, 0xf0, 0xf6, 0xfe, 0xfa, 0xf8, 0xf9, 0xf4, 0xfb, 0x0a, + 0xd6, 0x29, 0x09, 0x02, 0x00, 0xfc, 0xfc, 0xee, 0xf5, 0x05, 0xfb, 0x1e, + 0xf1, 0xf1, 0xf3, 0x02, 0xec, 0x1c, 0x0c, 0x0e, 0x0b, 0x04, 0xf6, 0xe7, + 0x14, 0x08, 0x27, 0x01, 0xfe, 0xe5, 0xe7, 0x01, 0x1b, 0xf0, 0xf6, 0xff, + 0xf4, 0xe7, 0xee, 0x18, 0x0d, 0x08, 0xf8, 0xd6, 0x07, 0xf4, 0x08, 0xff, + 0x1d, 0x13, 0xe7, 0x0b, 0x42, 0xef, 0x28, 0x00, 0xf9, 0xf0, 0xf3, 0x00, + 0x15, 0xfd, 0x1a, 0x22, 0xc1, 0xf5, 0xe0, 0xf8, 0x09, 0xe6, 0x0e, 0x05, + 0xf9, 0xf6, 0x01, 0x01, 0x13, 0xdc, 0x1f, 0x0d, 0xfb, 0x04, 0x08, 0x0b, + 0x15, 0xdb, 0x28, 0x34, 0xed, 0x0b, 0x3a, 0xed, 0x16, 0xe3, 0x39, 0x32, + 0xc4, 0x0b, 0x20, 0xe7, 0xf7, 0x02, 0x35, 0x24, 0xfc, 0xe8, 0x1c, 0xf8, + 0xf1, 0xfa, 0x0c, 0x1d, 0xf2, 0x05, 0xff, 0x12, 0x0f, 0x01, 0xec, 0xea, + 0xf0, 0x03, 0xe7, 0x15, 0xfd, 0x05, 0x08, 0xe0, 0x1b, 0xf8, 0xe1, 0x1e, + 0xed, 0xdc, 0x11, 0xeb, 0xfd, 0x1a, 0xeb, 0x09, 0xf9, 0xf3, 0x00, 0xe8, + 0xe6, 0x08, 0xf7, 0xde, 0x1e, 0x00, 0x00, 0x00, 0xe4, 0x09, 0xf2, 0xf8, + 0xe7, 0xf2, 0x0d, 0xfa, 0xe2, 0x0f, 0x04, 0x08, 0xf2, 0x13, 0xf8, 0xf9, + 0xf1, 0xff, 0x03, 0x11, 0x12, 0xe9, 0xf4, 0x13, 0x07, 0x0c, 0x13, 0x2b, + 0xf7, 0xdd, 0xf9, 0xe9, 0xfa, 0xdb, 0x1d, 0xf6, 0xf6, 0xf9, 0xe4, 0xf6, + 0x0d, 0xeb, 0x0d, 0x08, 0xe7, 0xe7, 0xf2, 0x03, 0x1d, 0xd9, 0xd8, 0xe4, + 0xf7, 0xea, 0xdc, 0xdc, 0x26, 0x02, 0xee, 0xfa, 0x38, 0xfc, 0x1a, 0xef, + 0xda, 0xf1, 0xdf, 0x0b, 0x1a, 0xe0, 0x16, 0x16, 0xdc, 0x04, 0xfa, 0xf7, + 0xee, 0x02, 0x25, 0x02, 0xf5, 0xfb, 0x08, 0xf6, 0x11, 0xf5, 0x12, 0x08, + 0xf4, 0xe3, 0x1b, 0xf5, 0x3a, 0xdc, 0x20, 0x2e, 0xe0, 0xf5, 0x30, 0xe4, + 0x09, 0xf8, 0x3c, 0x45, 0xd3, 0x08, 0x23, 0xd8, 0x09, 0xe4, 0x35, 0x30, + 0xe4, 0xfe, 0x07, 0xf6, 0x05, 0x01, 0x05, 0xff, 0xf6, 0x0d, 0x02, 0xfd, + 0x03, 0x05, 0x0d, 0x00, 0xf5, 0xd6, 0xcf, 0x19, 0x06, 0xee, 0x0d, 0xf2, + 0x01, 0x18, 0xef, 0x12, 0x04, 0x02, 0x21, 0xd9, 0x02, 0x0d, 0xeb, 0xe9, + 0x13, 0x08, 0x15, 0xf0, 0xee, 0x03, 0xec, 0x06, 0x17, 0xed, 0x00, 0x1a, + 0xee, 0xf2, 0xfc, 0x09, 0xec, 0xf8, 0xf8, 0x18, 0xf4, 0x13, 0x04, 0xf6, + 0x02, 0xf0, 0xfc, 0xfe, 0xe3, 0x01, 0x0a, 0x1c, 0x1b, 0xec, 0x0e, 0x01, + 0xfb, 0x08, 0x11, 0xf5, 0x00, 0x14, 0xe6, 0x12, 0x07, 0xf4, 0x15, 0x07, + 0xfc, 0xfb, 0xf5, 0xf1, 0x01, 0x21, 0x01, 0xe9, 0xe8, 0xef, 0xdb, 0xdf, + 0x1f, 0x0a, 0xdd, 0xd1, 0x16, 0x04, 0xfd, 0xe1, 0x24, 0xf0, 0xec, 0xf4, + 0x38, 0xe1, 0x16, 0xfd, 0xe0, 0xec, 0xe7, 0x0c, 0x2a, 0x04, 0x0c, 0x17, + 0xdc, 0xe8, 0xf2, 0x03, 0xec, 0xfd, 0x19, 0xfe, 0xf3, 0xf0, 0xf3, 0xfb, + 0x18, 0xdf, 0x1c, 0x00, 0x09, 0xf4, 0x18, 0x0b, 0x1f, 0xf6, 0x34, 0x22, + 0xf4, 0x22, 0x45, 0xeb, 0x23, 0xcf, 0x32, 0x34, 0xf2, 0xf9, 0x29, 0xd4, + 0xf7, 0x0b, 0x38, 0x2a, 0x09, 0xe6, 0x05, 0x01, 0x0b, 0xfe, 0x17, 0xfb, + 0x00, 0xeb, 0x08, 0xfd, 0x0c, 0x02, 0x1d, 0xea, 0xfa, 0x0b, 0xeb, 0x09, + 0xfe, 0xfe, 0x10, 0xe0, 0xf6, 0x06, 0xf0, 0x15, 0xf3, 0x09, 0x11, 0xe4, + 0xf9, 0x07, 0xe1, 0xed, 0x17, 0x05, 0x0c, 0xe1, 0xdb, 0xf2, 0xf8, 0xea, + 0x22, 0xe9, 0x02, 0x00, 0xfd, 0xe7, 0xf2, 0xf8, 0xf9, 0xfc, 0xfa, 0xe8, + 0xe8, 0xeb, 0xe9, 0x0d, 0x04, 0xf8, 0xf8, 0xf7, 0xf8, 0x0d, 0x03, 0x0c, + 0x13, 0xf2, 0x0f, 0xf9, 0xe6, 0xfd, 0x0f, 0x19, 0x08, 0xf7, 0xfa, 0x01, + 0xf3, 0x12, 0x1e, 0x05, 0x0a, 0x09, 0xfd, 0x0b, 0x07, 0x08, 0x02, 0xfc, + 0xd6, 0xe8, 0x14, 0x01, 0x13, 0x19, 0xef, 0xda, 0x0e, 0x0a, 0x07, 0xef, + 0x34, 0xe0, 0x05, 0x1e, 0x4e, 0xe9, 0x19, 0xff, 0xe1, 0x04, 0xfb, 0x0e, + 0x11, 0x05, 0x1f, 0x15, 0xd4, 0xec, 0xf9, 0xe7, 0xf9, 0xfc, 0x25, 0xff, + 0x06, 0xf2, 0x01, 0xf6, 0x2a, 0x17, 0x24, 0x11, 0xf3, 0x1a, 0x1f, 0xfb, + 0x32, 0xeb, 0x33, 0x2f, 0x00, 0x08, 0x2c, 0xf0, 0x26, 0xf4, 0x25, 0x36, + 0xd9, 0xf1, 0x1a, 0xd5, 0xec, 0xf9, 0x32, 0x27, 0xfc, 0xf4, 0xf0, 0xe3, + 0xfa, 0x0c, 0x16, 0x17, 0xfa, 0xf9, 0xe5, 0x1f, 0x1f, 0xfa, 0xff, 0xfd, + 0x0d, 0x02, 0xe9, 0x0e, 0xf0, 0x12, 0x09, 0xda, 0x02, 0xea, 0xe5, 0x0a, + 0xff, 0x03, 0x13, 0xf0, 0x0a, 0xf9, 0xe9, 0xff, 0x10, 0xfc, 0x1a, 0xf3, + 0xf7, 0x0f, 0xf4, 0xfa, 0xf4, 0x05, 0x10, 0x0a, 0xdd, 0x09, 0xf7, 0xf0, + 0xe5, 0x07, 0x07, 0xfa, 0x02, 0xd7, 0xf8, 0xf7, 0x01, 0xfb, 0x0e, 0xf8, + 0x07, 0x0f, 0xfe, 0x03, 0x12, 0x05, 0x09, 0x13, 0xf8, 0xdc, 0xfd, 0x27, + 0x0f, 0xec, 0xf7, 0x07, 0x00, 0xfc, 0x12, 0xf8, 0xfb, 0xea, 0xe4, 0xe9, + 0xe9, 0xe0, 0xff, 0xdc, 0xd6, 0xeb, 0xf2, 0xf7, 0x0d, 0x1b, 0xe9, 0xc4, + 0x06, 0x00, 0xfd, 0x04, 0x46, 0xf9, 0xe9, 0x13, 0x2d, 0x0c, 0x1f, 0xf8, + 0xd3, 0x0c, 0x14, 0x11, 0x05, 0xe5, 0x27, 0x08, 0xc5, 0xef, 0xdf, 0xdd, + 0x04, 0xf8, 0x11, 0x10, 0xf0, 0xe7, 0xfb, 0x03, 0x3c, 0xe7, 0x14, 0x0c, + 0xf4, 0xf6, 0x1b, 0x0a, 0x23, 0xf2, 0x2d, 0x1a, 0x08, 0xff, 0x32, 0xe7, + 0x1a, 0x05, 0x2b, 0x34, 0xf1, 0x0a, 0x00, 0xe8, 0x02, 0xdf, 0x2c, 0x2a, + 0x03, 0xe6, 0xfc, 0xef, 0xfc, 0xe4, 0x03, 0x01, 0x03, 0xee, 0xe9, 0x15, + 0x05, 0x03, 0x13, 0x11, 0x0e, 0xee, 0xf5, 0x22, 0x1b, 0x0e, 0xfd, 0xf3, + 0x0a, 0x02, 0xdd, 0x20, 0xeb, 0x06, 0xf8, 0xe2, 0x06, 0x0e, 0xde, 0x0d, + 0xf9, 0x16, 0x1c, 0x0c, 0xe0, 0xf0, 0xec, 0x0c, 0x0f, 0xf2, 0x27, 0x1d, + 0xde, 0xe6, 0xf0, 0xf9, 0xf0, 0x02, 0x0a, 0x07, 0x06, 0xf9, 0x0f, 0xfa, + 0xf0, 0xee, 0xf1, 0xf7, 0xff, 0x02, 0x0b, 0x0d, 0x1b, 0xee, 0xf6, 0x05, + 0xff, 0x1c, 0x17, 0x04, 0x05, 0x17, 0x00, 0xff, 0x0d, 0xf3, 0x23, 0x10, + 0xfd, 0x05, 0xfb, 0xea, 0x03, 0x10, 0x07, 0xd7, 0xf7, 0xff, 0xf3, 0xf1, + 0x17, 0xed, 0xd3, 0xcb, 0x14, 0x1c, 0xf5, 0x03, 0x47, 0xf6, 0xf7, 0xf2, + 0x3e, 0xf2, 0x22, 0xf4, 0xed, 0xfc, 0xee, 0x0b, 0xf4, 0xf1, 0x25, 0x10, + 0xd0, 0xf6, 0x00, 0xef, 0x10, 0xfc, 0x15, 0xe5, 0xdb, 0xf3, 0xea, 0x10, + 0x22, 0xf2, 0x2b, 0x11, 0xf9, 0x0a, 0xfc, 0xf5, 0x53, 0x16, 0x25, 0x43, + 0xe0, 0x0e, 0x13, 0xfc, 0x2d, 0xe2, 0x55, 0x65, 0xf4, 0x08, 0x01, 0xdf, + 0x0a, 0x00, 0x49, 0x1c, 0xfe, 0xdf, 0xef, 0xf2, 0xf9, 0xf6, 0xfd, 0xff, + 0xf3, 0x02, 0xf6, 0x14, 0x0b, 0xe8, 0x09, 0xfc, 0xfc, 0xe2, 0xe5, 0x11, + 0x03, 0x09, 0xfb, 0x06, 0x10, 0x1a, 0xf3, 0x0d, 0xfa, 0x0a, 0xd5, 0xf5, + 0x1a, 0x11, 0xf2, 0xfc, 0x1f, 0xfe, 0x0e, 0xe4, 0xef, 0xd7, 0xee, 0x06, + 0x1e, 0x04, 0x12, 0x28, 0xf7, 0x0e, 0x06, 0xf8, 0xee, 0xf0, 0x1a, 0x01, + 0xf7, 0xfd, 0x03, 0x11, 0x19, 0x10, 0x04, 0xfb, 0xd7, 0xfa, 0x16, 0x06, + 0x07, 0x23, 0xfa, 0x14, 0x11, 0xf1, 0x12, 0x10, 0x04, 0xe1, 0xee, 0xf7, + 0x21, 0x0e, 0x0a, 0x0a, 0xf8, 0x07, 0x0a, 0xee, 0x03, 0x1f, 0xfa, 0xc4, + 0xec, 0x12, 0x01, 0x1e, 0xfd, 0xf1, 0xe8, 0xcc, 0xf4, 0x17, 0xff, 0xdd, + 0x45, 0x10, 0xee, 0xfa, 0x3d, 0xe7, 0x27, 0xdd, 0xd7, 0xf9, 0xf4, 0xf6, + 0x06, 0xf8, 0x1e, 0x13, 0xe7, 0xe2, 0xf1, 0xe3, 0xf3, 0xf7, 0x18, 0x12, + 0xe4, 0x0a, 0xdb, 0xff, 0xff, 0xfe, 0x20, 0x09, 0x00, 0xf7, 0x23, 0xf6, + 0x2d, 0x14, 0x26, 0x28, 0xe5, 0xff, 0x0f, 0xe3, 0x1d, 0xe8, 0x56, 0x43, + 0xe7, 0xfb, 0xf9, 0xe6, 0xe9, 0xe2, 0x19, 0x19, 0x08, 0xfa, 0xf3, 0xe5, + 0x23, 0x07, 0x0f, 0xf8, 0xf8, 0xf3, 0xfc, 0x11, 0x2a, 0x05, 0xf4, 0xf1, + 0xfa, 0xfb, 0xf1, 0x1e, 0x13, 0x0f, 0xf9, 0xf5, 0xfa, 0x09, 0xf9, 0x03, + 0xf0, 0xf0, 0xe7, 0xec, 0xf1, 0x0c, 0xe6, 0xee, 0xf6, 0x20, 0x0f, 0xe9, + 0x00, 0xf4, 0xfe, 0xf0, 0x13, 0x0a, 0x17, 0x13, 0xee, 0x13, 0xfb, 0xff, + 0xf8, 0xfd, 0xf4, 0xe2, 0xe8, 0x06, 0xfc, 0x14, 0x03, 0x17, 0x00, 0x03, + 0xe6, 0xfd, 0xf2, 0x12, 0x12, 0x20, 0xeb, 0x10, 0x02, 0xf7, 0x13, 0x0d, + 0x11, 0xfd, 0xde, 0xf5, 0x07, 0xf3, 0x04, 0xff, 0x06, 0x05, 0xfb, 0xea, + 0xf0, 0x0a, 0x00, 0xb5, 0xe8, 0x1a, 0x03, 0xfe, 0x0d, 0x1a, 0xe7, 0xc0, + 0xd6, 0xdc, 0xf6, 0xf8, 0x39, 0xf5, 0xd5, 0xf8, 0x22, 0xfa, 0x22, 0x05, + 0xd0, 0xf4, 0x2d, 0xfc, 0x00, 0x0a, 0x1b, 0xfc, 0xe6, 0x09, 0x14, 0xfa, + 0x00, 0x1d, 0x1a, 0xfd, 0xf3, 0x18, 0xfc, 0xeb, 0x15, 0xf5, 0x0e, 0x0a, + 0xf3, 0xf1, 0x1b, 0x05, 0x14, 0x03, 0x2d, 0x27, 0xfb, 0x18, 0x22, 0xef, + 0xf6, 0x06, 0x28, 0x2b, 0xde, 0xec, 0xef, 0xe8, 0xd3, 0xfe, 0x17, 0x12, + 0x01, 0x13, 0x05, 0xf7, 0x00, 0xde, 0xf3, 0xe5, 0x03, 0xfb, 0x07, 0x0b, + 0xfd, 0xdc, 0xdf, 0x03, 0x0c, 0x00, 0xfa, 0x06, 0x0e, 0x02, 0x05, 0xfa, + 0xfd, 0xed, 0x09, 0x0c, 0xfd, 0xfb, 0x0c, 0xf0, 0xe4, 0x04, 0xd6, 0xf3, + 0x09, 0x0a, 0xf9, 0xf8, 0xe2, 0xef, 0xdf, 0xf0, 0xf8, 0x03, 0x0f, 0x20, + 0xf4, 0xe3, 0xf8, 0x02, 0xe2, 0xe5, 0x25, 0x0f, 0xeb, 0xf8, 0xe9, 0xfd, + 0x04, 0x0c, 0x0c, 0xfe, 0x01, 0x08, 0xfc, 0xfc, 0x1b, 0x01, 0xe5, 0x13, + 0xf9, 0xe8, 0x07, 0x20, 0xfe, 0x06, 0xec, 0xfe, 0x09, 0xef, 0x14, 0x04, + 0x0b, 0xf5, 0xe7, 0xff, 0x0a, 0x02, 0x09, 0xe9, 0xc4, 0x16, 0x0d, 0xe7, + 0x15, 0x14, 0xf1, 0xd0, 0xec, 0xe7, 0xf0, 0xf0, 0x33, 0x05, 0xda, 0xf2, + 0x0b, 0x08, 0x38, 0x01, 0x07, 0xfd, 0xd8, 0x06, 0xd9, 0xf0, 0x16, 0x1f, + 0xff, 0xf7, 0xe0, 0xd8, 0xf3, 0xf7, 0x12, 0x08, 0x0e, 0x05, 0xf6, 0x03, + 0xef, 0x1b, 0x12, 0xf4, 0xe8, 0x0f, 0x02, 0xfd, 0xf2, 0x16, 0x26, 0x22, + 0xe0, 0x07, 0xf7, 0xe6, 0xeb, 0x16, 0x22, 0x1a, 0x0b, 0x01, 0xf5, 0xea, + 0xd2, 0x22, 0x0f, 0x13, 0x15, 0x08, 0xf0, 0xfb, 0xed, 0x11, 0xf3, 0xe9, + 0xff, 0xde, 0x0a, 0x18, 0x0f, 0x02, 0xfb, 0xf9, 0xfb, 0xe8, 0x12, 0x18, + 0x01, 0xf4, 0xf6, 0xf8, 0xf0, 0x1f, 0x24, 0x15, 0xf5, 0x00, 0x1c, 0xf9, + 0x01, 0x0a, 0x11, 0xd5, 0x01, 0x12, 0x02, 0xec, 0xfd, 0x07, 0xf2, 0xea, + 0xf9, 0xff, 0xf7, 0xfb, 0x15, 0xec, 0xe5, 0x01, 0xeb, 0x05, 0xf9, 0x10, + 0xfe, 0x28, 0xe5, 0x0a, 0xeb, 0x1b, 0x0e, 0xf9, 0xde, 0x02, 0x15, 0x0a, + 0xff, 0xfe, 0x11, 0x24, 0x03, 0xf8, 0x00, 0x08, 0xfd, 0x0e, 0xeb, 0xf3, + 0xf6, 0xf7, 0x14, 0x0e, 0xfc, 0xf5, 0xde, 0xf5, 0x9e, 0xfe, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00, + 0xfa, 0xfd, 0xff, 0xff, 0xa2, 0xff, 0xff, 0xff, 0xba, 0x00, 0x00, 0x00, + 0x24, 0xfc, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x4f, 0x43, 0x4f, + 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0xfb, 0xff, 0xff, + 0x68, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xce, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x03, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1a, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x07, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xc4, 0xfc, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x1a, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x07, 0x00, 0x14, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x31, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x34, 0x04, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, + 0x4c, 0x03, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, + 0x20, 0x02, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0xfc, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf4, 0xfb, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3b, 0x0e, 0x00, 0x00, 0x00, 0x6c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x5f, 0x73, 0x6f, 0x66, 0x74, 0x6d, 0x61, 0x78, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, + 0x10, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0xb4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x11, 0x1e, 0x23, 0x3a, 0x9e, 0xa1, 0x15, 0x39, + 0x23, 0x69, 0x45, 0x3a, 0x09, 0xe4, 0xe4, 0x39, 0x65, 0xd7, 0x13, 0x3a, + 0xe0, 0xb2, 0xfd, 0x39, 0x1b, 0xc1, 0x53, 0x3a, 0xc2, 0x50, 0x2d, 0x3a, + 0x12, 0x00, 0x00, 0x00, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3a, 0xfd, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2c, 0xfd, 0xff, 0xff, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xb5, 0xfa, 0xfa, 0x39, 0x1f, 0x00, 0x00, 0x00, 0x66, 0x69, 0x6e, 0x61, + 0x6c, 0x5f, 0x66, 0x63, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, + 0x2f, 0x72, 0x65, 0x61, 0x64, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, + 0x6f, 0x73, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xa0, 0x0f, 0x00, 0x00, 0xa2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x74, 0xfe, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xdd, 0xbb, 0x3d, + 0x01, 0x00, 0x00, 0x00, 0x32, 0xa3, 0x25, 0x41, 0x01, 0x00, 0x00, 0x00, + 0xf6, 0xa0, 0x50, 0xc1, 0x05, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x5f, + 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0e, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, + 0x2c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, + 0x32, 0x2f, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x4a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x5c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x50, 0xd0, 0x3d, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcf, 0x41, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, + 0x61, 0x70, 0x65, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xc2, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x58, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x94, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x50, 0x50, 0xd0, 0x3d, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xcf, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, + 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xa8, 0x07, 0x00, 0x00, 0x2e, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x60, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x3a, 0x6a, 0xac, 0x3d, 0x01, 0x00, 0x00, 0x00, + 0xd0, 0xbd, 0xab, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x52, 0x65, 0x6c, 0x75, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x9c, 0xff, 0xff, 0xff, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x96, 0x08, 0x29, 0x38, 0x0b, 0x00, 0x00, 0x00, + 0x4d, 0x61, 0x74, 0x4d, 0x75, 0x6c, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x9a, 0xbb, 0x84, 0x38, 0x83, 0x84, 0x73, 0x37, 0x5b, 0xa3, 0xa0, 0x38, + 0x16, 0x41, 0x3a, 0x38, 0xc7, 0x9a, 0x70, 0x38, 0xed, 0x70, 0x4e, 0x38, + 0x54, 0x4f, 0xac, 0x38, 0xfd, 0x07, 0x8d, 0x38, 0x0b, 0x00, 0x00, 0x00, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x19, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x16, 0x0a, 0x00, 0x0e, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x03, 0x00, 0x00, 0x00}; +const int g_model_len = 18712; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_model.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_model.h new file mode 100644 index 000000000..deec2d646 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_features_model.h @@ -0,0 +1,27 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 is a standard TensorFlow Lite FlatBuffer model file that has been +// converted into a C data array, so it can be easily compiled into a binary +// for devices that don't have a file system. It was created using the command: +// xxd -i model.tflite > model.cc + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MODEL_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MODEL_H_ + +extern const unsigned char g_model[]; +extern const int g_model_len; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_MICRO_FEATURES_MODEL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_speech.ino b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_speech.ino new file mode 100644 index 000000000..b995289b6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/micro_speech.ino @@ -0,0 +1,216 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "audio_provider.h" +#include "command_responder.h" +#include "feature_provider.h" +#include "main_functions.h" +#include "micro_features_micro_model_settings.h" +#include "micro_features_model.h" +#include "recognize_commands.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +#undef PROFILE_MICRO_SPEECH + +// Globals, used for compatibility with Arduino-style sketches. +namespace { +tflite::ErrorReporter* error_reporter = nullptr; +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* model_input = nullptr; +FeatureProvider* feature_provider = nullptr; +RecognizeCommands* recognizer = nullptr; +int32_t previous_time = 0; + +// Create an area of memory to use for input, output, and intermediate arrays. +// The size of this will depend on the model you're using, and may need to be +// determined by experimentation. +constexpr int kTensorArenaSize = 10 * 1024; +uint8_t tensor_arena[kTensorArenaSize]; +int8_t feature_buffer[kFeatureElementCount]; +int8_t* model_input_buffer = nullptr; +} // namespace + +// The name of this function is important for Arduino compatibility. +void setup() { + tflite::InitializeTarget(); + + // Set up logging. Google style is to avoid globals or statics because of + // lifetime uncertainty, but since this has a trivial destructor it's okay. + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::MicroErrorReporter micro_error_reporter; + error_reporter = µ_error_reporter; + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + model = tflite::GetModel(g_model); + if (model->version() != TFLITE_SCHEMA_VERSION) { + TF_LITE_REPORT_ERROR(error_reporter, + "Model provided is schema version %d not equal " + "to supported version %d.", + model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // Pull in only the operation implementations we need. + // This relies on a complete list of all the ops needed by this graph. + // An easier approach is to just use the AllOpsResolver, but this will + // incur some penalty in code space for op implementations that are not + // needed by this graph. + // + // tflite::AllOpsResolver resolver; + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::MicroMutableOpResolver<4> micro_op_resolver(error_reporter); + if (micro_op_resolver.AddDepthwiseConv2D() != kTfLiteOk) { + return; + } + if (micro_op_resolver.AddFullyConnected() != kTfLiteOk) { + return; + } + if (micro_op_resolver.AddSoftmax() != kTfLiteOk) { + return; + } + if (micro_op_resolver.AddReshape() != kTfLiteOk) { + return; + } + + // Build an interpreter to run the model with. + static tflite::MicroInterpreter static_interpreter( + model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + TfLiteStatus allocate_status = interpreter->AllocateTensors(); + if (allocate_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed"); + return; + } + + // Get information about the memory area to use for the model's input. + model_input = interpreter->input(0); + if ((model_input->dims->size != 2) || (model_input->dims->data[0] != 1) || + (model_input->dims->data[1] != + (kFeatureSliceCount * kFeatureSliceSize)) || + (model_input->type != kTfLiteInt8)) { + TF_LITE_REPORT_ERROR(error_reporter, + "Bad input tensor parameters in model"); + return; + } + model_input_buffer = model_input->data.int8; + + // Prepare to access the audio spectrograms from a microphone or other source + // that will provide the inputs to the neural network. + // NOLINTNEXTLINE(runtime-global-variables) + static FeatureProvider static_feature_provider(kFeatureElementCount, + feature_buffer); + feature_provider = &static_feature_provider; + + static RecognizeCommands static_recognizer(error_reporter); + recognizer = &static_recognizer; + + previous_time = 0; + + // start the audio + TfLiteStatus init_status = InitAudioRecording(error_reporter); + if (init_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "Unable to initialize audio"); + return; + } + + TF_LITE_REPORT_ERROR(error_reporter, "Initialization complete"); +} + +// The name of this function is important for Arduino compatibility. +void loop() { +#ifdef PROFILE_MICRO_SPEECH + const uint32_t prof_start = millis(); + static uint32_t prof_count = 0; + static uint32_t prof_sum = 0; + static uint32_t prof_min = std::numeric_limits::max(); + static uint32_t prof_max = 0; +#endif // PROFILE_MICRO_SPEECH + + // Fetch the spectrogram for the current time. + const int32_t current_time = LatestAudioTimestamp(); + int how_many_new_slices = 0; + TfLiteStatus feature_status = feature_provider->PopulateFeatureData( + error_reporter, previous_time, current_time, &how_many_new_slices); + if (feature_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "Feature generation failed"); + return; + } + previous_time += how_many_new_slices * kFeatureSliceStrideMs; + // If no new audio samples have been received since last time, don't bother + // running the network model. + if (how_many_new_slices == 0) { + return; + } + + // Copy feature buffer to input tensor + for (int i = 0; i < kFeatureElementCount; i++) { + model_input_buffer[i] = feature_buffer[i]; + } + + // Run the model on the spectrogram input and make sure it succeeds. + TfLiteStatus invoke_status = interpreter->Invoke(); + if (invoke_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed"); + return; + } + + // Obtain a pointer to the output tensor + TfLiteTensor* output = interpreter->output(0); + // Determine whether a command was recognized based on the output of inference + const char* found_command = nullptr; + uint8_t score = 0; + bool is_new_command = false; + TfLiteStatus process_status = recognizer->ProcessLatestResults( + output, current_time, &found_command, &score, &is_new_command); + if (process_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, + "RecognizeCommands::ProcessLatestResults() failed"); + return; + } + // Do something based on the recognized command. The default implementation + // just prints to the error console, but you should replace this with your + // own function for a real application. + RespondToCommand(error_reporter, current_time, found_command, score, + is_new_command); + +#ifdef PROFILE_MICRO_SPEECH + const uint32_t prof_end = millis(); + if (++prof_count > 10) { + uint32_t elapsed = prof_end - prof_start; + prof_sum += elapsed; + if (elapsed < prof_min) { + prof_min = elapsed; + } + if (elapsed > prof_max) { + prof_max = elapsed; + } + if (prof_count % 300 == 0) { + TF_LITE_REPORT_ERROR(error_reporter, + "## time: min %dms max %dms avg %dms", prof_min, + prof_max, prof_sum / prof_count); + } + } +#endif // PROFILE_MICRO_SPEECH +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/recognize_commands.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/recognize_commands.cpp new file mode 100644 index 000000000..552cf58d3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/recognize_commands.cpp @@ -0,0 +1,159 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "recognize_commands.h" + +#include + +#undef DEBUG_MICRO_SPEECH + +RecognizeCommands::RecognizeCommands(tflite::ErrorReporter* error_reporter, + int32_t average_window_duration_ms, + uint8_t detection_threshold, + int32_t suppression_ms, + int32_t minimum_count) + : error_reporter_(error_reporter), + average_window_duration_ms_(average_window_duration_ms), + detection_threshold_(detection_threshold), + suppression_ms_(suppression_ms), + minimum_count_(minimum_count), + previous_results_(error_reporter) { + previous_top_label_ = kCategoryLabels[0]; // silence + previous_top_label_time_ = std::numeric_limits::min(); +} + +TfLiteStatus RecognizeCommands::ProcessLatestResults( + const TfLiteTensor* latest_results, const int32_t current_time_ms, + const char** found_command, uint8_t* score, bool* is_new_command) { + if ((latest_results->dims->size != 2) || + (latest_results->dims->data[0] != 1) || + (latest_results->dims->data[1] != kCategoryCount)) { + TF_LITE_REPORT_ERROR( + error_reporter_, + "The results for recognition should contain %d elements, but there are " + "%d in an %d-dimensional shape", + kCategoryCount, latest_results->dims->data[1], + latest_results->dims->size); + return kTfLiteError; + } + + if (latest_results->type != kTfLiteInt8) { + TF_LITE_REPORT_ERROR( + error_reporter_, + "The results for recognition should be int8_t elements, but are %d", + latest_results->type); + return kTfLiteError; + } + + if ((!previous_results_.empty()) && + (current_time_ms < previous_results_.front().time_)) { + TF_LITE_REPORT_ERROR( + error_reporter_, + "Results must be fed in increasing time order, but received a " + "timestamp of %d that was earlier than the previous one of %d", + current_time_ms, previous_results_.front().time_); + return kTfLiteError; + } + + // Prune any earlier results that are too old for the averaging window. + const int64_t time_limit = current_time_ms - average_window_duration_ms_; + while ((!previous_results_.empty()) && + previous_results_.front().time_ < time_limit) { + previous_results_.pop_front(); + } + + // Add the latest results to the head of the queue. + previous_results_.push_back({current_time_ms, latest_results->data.int8}); + + // If there are too few results, assume the result will be unreliable and + // bail. + const int64_t how_many_results = previous_results_.size(); + const int64_t earliest_time = previous_results_.front().time_; + const int64_t samples_duration = current_time_ms - earliest_time; + if ((how_many_results < minimum_count_) || + (samples_duration < (average_window_duration_ms_ / 4))) { + *found_command = previous_top_label_; + *score = 0; + *is_new_command = false; + return kTfLiteOk; + } + + // Calculate the average score across all the results in the window. + int32_t average_scores[kCategoryCount]; + for (int offset = 0; offset < previous_results_.size(); ++offset) { + PreviousResultsQueue::Result previous_result = + previous_results_.from_front(offset); + const int8_t* scores = previous_result.scores; + for (int i = 0; i < kCategoryCount; ++i) { + if (offset == 0) { + average_scores[i] = scores[i] + 128; + } else { + average_scores[i] += scores[i] + 128; + } + } + } + for (int i = 0; i < kCategoryCount; ++i) { + average_scores[i] /= how_many_results; + } + + // Find the current highest scoring category. + int current_top_index = 0; + int32_t current_top_score = 0; + for (int i = 0; i < kCategoryCount; ++i) { + if (average_scores[i] > current_top_score) { + current_top_score = average_scores[i]; + current_top_index = i; + } + } + const char* current_top_label = kCategoryLabels[current_top_index]; + + // If we've recently had another label trigger, assume one that occurs too + // soon afterwards is a bad result. + int64_t time_since_last_top; + if ((previous_top_label_ == kCategoryLabels[0]) || + (previous_top_label_time_ == std::numeric_limits::min())) { + time_since_last_top = std::numeric_limits::max(); + } else { + time_since_last_top = current_time_ms - previous_top_label_time_; + } + if ((current_top_score > detection_threshold_) && + ((current_top_label != previous_top_label_) || + (time_since_last_top > suppression_ms_))) { +#ifdef DEBUG_MICRO_SPEECH + TF_LITE_REPORT_ERROR( + error_reporter_, "Scores: s %d u %d y %d n %d %s -> %s", + average_scores[0], average_scores[1], average_scores[2], + average_scores[3], previous_top_label_, current_top_label); +#endif // DEBUG_MICRO_SPEECH + previous_top_label_ = current_top_label; + previous_top_label_time_ = current_time_ms; + *is_new_command = true; + } else { +#ifdef DEBUG_MICRO_SPEECH + if (current_top_label != previous_top_label_) { + TF_LITE_REPORT_ERROR( + error_reporter_, "#Scores: s %d u %d y %d n %d %s -> %s", + average_scores[0], average_scores[1], average_scores[2], + average_scores[3], previous_top_label_, current_top_label); + previous_top_label_ = current_top_label; + } +#endif // DEBUG_MICRO_SPEECH + *is_new_command = false; + } + *found_command = current_top_label; + *score = current_top_score; + + return kTfLiteOk; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/recognize_commands.h b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/recognize_commands.h new file mode 100644 index 000000000..fa29d7dde --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/micro_speech/recognize_commands.h @@ -0,0 +1,159 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_RECOGNIZE_COMMANDS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_RECOGNIZE_COMMANDS_H_ + +#include + +#include "micro_features_micro_model_settings.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// Partial implementation of std::dequeue, just providing the functionality +// that's needed to keep a record of previous neural network results over a +// short time period, so they can be averaged together to produce a more +// accurate overall prediction. This doesn't use any dynamic memory allocation +// so it's a better fit for microcontroller applications, but this does mean +// there are hard limits on the number of results it can store. +class PreviousResultsQueue { + public: + PreviousResultsQueue(tflite::ErrorReporter* error_reporter) + : error_reporter_(error_reporter), front_index_(0), size_(0) {} + + // Data structure that holds an inference result, and the time when it + // was recorded. + struct Result { + Result() : time_(0), scores() {} + Result(int32_t time, int8_t* input_scores) : time_(time) { + for (int i = 0; i < kCategoryCount; ++i) { + scores[i] = input_scores[i]; + } + } + int32_t time_; + int8_t scores[kCategoryCount]; + }; + + int size() { return size_; } + bool empty() { return size_ == 0; } + Result& front() { return results_[front_index_]; } + Result& back() { + int back_index = front_index_ + (size_ - 1); + if (back_index >= kMaxResults) { + back_index -= kMaxResults; + } + return results_[back_index]; + } + + void push_back(const Result& entry) { + if (size() >= kMaxResults) { + TF_LITE_REPORT_ERROR( + error_reporter_, + "Couldn't push_back latest result, too many already!"); + return; + } + size_ += 1; + back() = entry; + } + + Result pop_front() { + if (size() <= 0) { + TF_LITE_REPORT_ERROR(error_reporter_, + "Couldn't pop_front result, none present!"); + return Result(); + } + Result result = front(); + front_index_ += 1; + if (front_index_ >= kMaxResults) { + front_index_ = 0; + } + size_ -= 1; + return result; + } + + // Most of the functions are duplicates of dequeue containers, but this + // is a helper that makes it easy to iterate through the contents of the + // queue. + Result& from_front(int offset) { + if ((offset < 0) || (offset >= size_)) { + TF_LITE_REPORT_ERROR(error_reporter_, + "Attempt to read beyond the end of the queue!"); + offset = size_ - 1; + } + int index = front_index_ + offset; + if (index >= kMaxResults) { + index -= kMaxResults; + } + return results_[index]; + } + + private: + tflite::ErrorReporter* error_reporter_; + static constexpr int kMaxResults = 50; + Result results_[kMaxResults]; + + int front_index_; + int size_; +}; + +// This class is designed to apply a very primitive decoding model on top of the +// instantaneous results from running an audio recognition model on a single +// window of samples. It applies smoothing over time so that noisy individual +// label scores are averaged, increasing the confidence that apparent matches +// are real. +// To use it, you should create a class object with the configuration you +// want, and then feed results from running a TensorFlow model into the +// processing method. The timestamp for each subsequent call should be +// increasing from the previous, since the class is designed to process a stream +// of data over time. +class RecognizeCommands { + public: + // labels should be a list of the strings associated with each one-hot score. + // The window duration controls the smoothing. Longer durations will give a + // higher confidence that the results are correct, but may miss some commands. + // The detection threshold has a similar effect, with high values increasing + // the precision at the cost of recall. The minimum count controls how many + // results need to be in the averaging window before it's seen as a reliable + // average. This prevents erroneous results when the averaging window is + // initially being populated for example. The suppression argument disables + // further recognitions for a set time after one has been triggered, which can + // help reduce spurious recognitions. + explicit RecognizeCommands(tflite::ErrorReporter* error_reporter, + int32_t average_window_duration_ms = 1000, + uint8_t detection_threshold = 200, + int32_t suppression_ms = 1500, + int32_t minimum_count = 3); + + // Call this with the results of running a model on sample data. + TfLiteStatus ProcessLatestResults(const TfLiteTensor* latest_results, + const int32_t current_time_ms, + const char** found_command, uint8_t* score, + bool* is_new_command); + + private: + // Configuration + tflite::ErrorReporter* error_reporter_; + int32_t average_window_duration_ms_; + uint8_t detection_threshold_; + int32_t suppression_ms_; + int32_t minimum_count_; + + // Working variables + PreviousResultsQueue previous_results_; + const char* previous_top_label_; + int32_t previous_top_label_time_; +}; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_MICRO_SPEECH_RECOGNIZE_COMMANDS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/README.md b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/README.md new file mode 100644 index 000000000..cfde53712 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/README.md @@ -0,0 +1,69 @@ +# Person detection example + +This example shows how you can use [Tensorflow Lite Micro](https://www.tensorflow.org/lite/microcontrollers) to run a 300.5 kilobyte neural +network to recognize people in images. + +## Table of contents + + * [Deploy to Arduino](#deploy-to-arduino) + * [Install the Arduino_TensorFlowLite library](#install-the-arduino_tensorflowlite-library) + * [Load and run the example](#load-and-run-the-example) + * [Training your own model](#training-your-own-model) + + +## Deploy to Arduino + +The following instructions will help you build and deploy this example to +[Arduino](https://www.arduino.cc/) devices. + +The example has been tested with the following devices: + +- [Tiny Machine Learning Kit](https://store.arduino.cc/products/arduino-tiny-machine-learning-kit) + +The Arduino Tiny Machine Learning Kit uses the OV7675 camera attachment. The OV7675 is currently not supported, and the code will simply generate a blank image (support coming _**soon**_). If you're using a different Arduino board and attaching your own +camera, you'll need to implement your own `arduino_image_provider.cpp` code. It also has a +set of LEDs, which are used to indicate whether a person has been recognized. + +### Install the Arduino_TensorFlowLite library + +This example application is included as part of the official TensorFlow Lite Micro +Arduino library. +To install the TensorFlow Lite Micro for Arduino library, see the +[how to install](../../README.md#how-to-install) instructions. + +### Load and run the example + +Once the library has been added, go to `File -> Examples`. You should see an +entry within the list named `Arduino_TensorFlowLite`. Select +it and click `person_detection` to load the example. + +Use the Arduino IDE to build and upload the example. Once it is running, you +should see the built-in LED on your device flashing. The built-in LED will flash on/off for each inference cycle. The green LED will be lit if a person is predicted, +The blue LED will be lit if the prediction is not-a-person. + +The program also outputs inference results to the serial port, which appear as +follows: + +``` +Cropping image and quantizing +Image cropped and quantized +Person score: 39.6% No person score: 60.93% +``` + +When the program is run, it waits several seconds for a USB-serial connection to be +available. If there is no connection available, it will not output data. To see +the serial output in the Arduino desktop IDE, do the following: + +1. Open the Arduino IDE +1. Connect the Arduino board to your computer via USB +1. Press the reset button on the Arduino board +1. Within 5 seconds, go to `Tools -> Serial Monitor` in the Arduino IDE. You may + have to try several times, since the board will take a moment to connect. + +If you don't see any output, repeat the process again. + +## Training your own model + +You can train your own model with some easy-to-use scripts. See +[training_a_model.md](https://github.com/tensorflow/tflite-micro/blob/main/tensorflow/lite/micro/examples/person_detection/training_a_model.md) for instructions. + diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_detection_responder.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_detection_responder.cpp new file mode 100644 index 000000000..7de122422 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_detection_responder.cpp @@ -0,0 +1,76 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) +#define ARDUINO_EXCLUDE_CODE +#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) + +#ifndef ARDUINO_EXCLUDE_CODE + +#include + +#include "Arduino.h" +#include "detection_responder.h" + +// Flash the yellow (builtin) LED after each inference +void RespondToDetection(tflite::ErrorReporter* error_reporter, + float person_score, float no_person_score) { + static bool is_initialized = false; + if (!is_initialized) { + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + // Pins for the built-in RGB LEDs on the Arduino Nano 33 BLE Sense + pinMode(LEDR, OUTPUT); + pinMode(LEDG, OUTPUT); + pinMode(LEDB, OUTPUT); + // Switch the LEDs off + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, HIGH); + digitalWrite(LEDR, HIGH); + is_initialized = true; + } + + // Note: The RGB LEDs on the Arduino Nano 33 BLE + // Sense are on when the pin is LOW, off when HIGH. + + // Switch on the green LED when a person is detected, + // the blue when no person is detected + if (person_score > no_person_score) { + digitalWrite(LEDG, LOW); + digitalWrite(LEDB, HIGH); + } else { + digitalWrite(LEDG, HIGH); + digitalWrite(LEDB, LOW); + } + + // Flash the yellow LED after every inference. + // The builtin LED is on when the pin is HIGH + digitalWrite(LED_BUILTIN, LOW); + delay(100); + digitalWrite(LED_BUILTIN, HIGH); + + float person_score_frac, person_score_int; + float no_person_score_frac, no_person_score_int; + person_score_frac = std::modf(person_score * 100, &person_score_int); + no_person_score_frac = std::modf(no_person_score * 100, &no_person_score_int); + TF_LITE_REPORT_ERROR(error_reporter, + "Person score: %d.%d%% No person score: %d.%d%%", + static_cast(person_score_int), + static_cast(person_score_frac * 100), + static_cast(no_person_score_int), + static_cast(no_person_score_frac * 100)); +} + +#endif // ARDUINO_EXCLUDE_CODE diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_image_provider.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_image_provider.cpp new file mode 100644 index 000000000..515f55e4c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_image_provider.cpp @@ -0,0 +1,199 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "image_provider.h" +#include "model_settings.h" +#include "tensorflow/lite/micro/micro_utils.h" +#include "test_over_serial/test_over_serial.h" + +using namespace test_over_serial; + +#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) +#define ARDUINO_EXCLUDE_CODE +#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) + +#ifndef ARDUINO_EXCLUDE_CODE + +#include "Arduino.h" + +namespace { + +constexpr size_t kQQVGA_width = 160; // pixels +constexpr size_t kQQVGA_height = 120; // pixels + +uint8_t image_buffer[kQQVGA_height * kQQVGA_width]; +constexpr size_t kImageBufferLength = + std::extent::value; + +// Get the camera module ready +TfLiteStatus InitCamera(tflite::ErrorReporter* error_reporter) { + // This function kept for future implementation + TF_LITE_REPORT_ERROR( + error_reporter, + "OV7675 not yet supported. Blank image will be substituted."); + return kTfLiteOk; +} + +// Begin the capture and wait for it to finish +TfLiteStatus PerformCapture(tflite::ErrorReporter* error_reporter) { + // This function kept for future implementation + TF_LITE_REPORT_ERROR(error_reporter, "Starting capture"); + delay(50); + TF_LITE_REPORT_ERROR(error_reporter, "Image captured"); + return kTfLiteOk; +} + +// Read data from the camera module into a local buffer +TfLiteStatus ReadData(tflite::ErrorReporter* error_reporter) { + // This function kept for future implementation + // until OV7675 supported, just fill with zeros (black image) + std::fill_n(image_buffer, kImageBufferLength, 0); + return kTfLiteOk; +} + +// Decode the image, crop it, and convert it to grayscale +TfLiteStatus CropAndQuantizeImage(tflite::ErrorReporter* error_reporter, + size_t image_width, size_t image_height, + const TfLiteTensor* tensor) { + TF_LITE_REPORT_ERROR(error_reporter, "Cropping image and quantizing"); + + // cropping parameters + const size_t vert_top = (image_height - kNumRows) / 2; + const size_t vert_bottom = vert_top + kNumRows - 1; + const size_t horz_left = (image_width - kNumCols) / 2; + const size_t horz_right = horz_left + kNumCols - 1; + + const uint8_t* p = image_buffer + (vert_top * image_width); + p += horz_left; + int8_t* image_data = tensor->data.int8; + for (size_t line = vert_top; line <= vert_bottom; line++) { + for (size_t row = horz_left; row <= horz_right; row++, p++) { + *image_data++ = tflite::FloatToQuantizedType( + p[0] / 255.0f, tensor->params.scale, tensor->params.zero_point); + } + // move to next line + p += ((image_width - 1) - horz_right) + horz_left; + } + + TF_LITE_REPORT_ERROR(error_reporter, "Image cropped and quantized"); + return kTfLiteOk; +} + +// Get an image from the camera module +TfLiteStatus GetCameraImage(tflite::ErrorReporter* error_reporter, + const TfLiteTensor* tensor) { + static bool g_is_camera_initialized = false; + if (!g_is_camera_initialized) { + TfLiteStatus init_status = InitCamera(error_reporter); + if (init_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "InitCamera failed"); + return init_status; + } + g_is_camera_initialized = true; + } + + TfLiteStatus capture_status = PerformCapture(error_reporter); + if (capture_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "PerformCapture failed"); + return capture_status; + } + + TfLiteStatus read_data_status = ReadData(error_reporter); + if (read_data_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "ReadData failed"); + return read_data_status; + } + + TfLiteStatus decode_status = + CropAndQuantizeImage(error_reporter, kQQVGA_width, kQQVGA_height, tensor); + if (decode_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "CropAndQuantizeImage failed"); + return decode_status; + } + + return kTfLiteOk; +} + +TfLiteStatus GetTestImage(tflite::ErrorReporter* error_reporter, + TestOverSerial& test, const TfLiteTensor* tensor) { + volatile bool done = false; + volatile bool aborted = false; + volatile size_t image_width = 0, image_height = 0; + + InputHandler handler = [&aborted, &done, &image_width, + &image_height](const InputBuffer* const input) { + if (0 == input->offset) { + if ((kQQVGA_height * kQQVGA_width) == input->total) { + image_width = kQQVGA_width; + image_height = kQQVGA_height; + } else if ((kNumCols * kNumRows) == input->total) { + image_width = kNumCols; + image_height = kNumRows; + } else { + // image dimensions are not supported, abort input processing + aborted = true; + return false; + } + } + + std::copy_n(input->data.uint8, input->length, &image_buffer[input->offset]); + if (input->total == (input->offset + input->length)) { + done = true; + } + return true; + }; + + while (!done) { + test.ProcessInput(&handler); + if (aborted) { + TF_LITE_REPORT_ERROR(error_reporter, "Input processing aborted"); + return kTfLiteError; + } + // wait for a full image from serial port before processing + if (done) { + TfLiteStatus decode_status = CropAndQuantizeImage( + error_reporter, image_width, image_height, tensor); + if (decode_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "CropAndQuantizeImage failed"); + return decode_status; + } + } + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteStatus GetImage(tflite::ErrorReporter* error_reporter, + const TfLiteTensor* tensor) { + TestOverSerial& test = TestOverSerial::Instance(kIMAGE_GRAYSCALE); + if (!test.IsTestMode()) { + // check serial port for test mode command + test.ProcessInput(nullptr); + } + if (test.IsTestMode()) { + return GetTestImage(error_reporter, test, tensor); + } else { + // get an image from the camera + return GetCameraImage(error_reporter, tensor); + } + // NOTREACHED +} + +#endif // ARDUINO_EXCLUDE_CODE diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_main.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_main.cpp new file mode 100644 index 000000000..c70a2bcea --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/arduino_main.cpp @@ -0,0 +1,20 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "main_functions.h" + +// Arduino automatically calls the setup() and loop() functions in a sketch, so +// where other systems need their own main routine in this file, it can be left +// empty. diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/detection_responder.h b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/detection_responder.h new file mode 100644 index 000000000..1d9cabcb2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/detection_responder.h @@ -0,0 +1,34 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ + +// Provides an interface to take an action based on the output from the person +// detection model. + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_DETECTION_RESPONDER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_DETECTION_RESPONDER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// Called every time the results of a person detection run are available. The +// `person_score` has the numerical confidence that the captured image contains +// a person, and `no_person_score` has the numerical confidence that the image +// does not contain a person. Typically if person_score > no person score, the +// image is considered to contain a person. This threshold may be adjusted for +// particular applications. +void RespondToDetection(tflite::ErrorReporter* error_reporter, + float person_score, float no_person_score); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_DETECTION_RESPONDER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/image_provider.h b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/image_provider.h new file mode 100644 index 000000000..3fc18bb31 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/image_provider.h @@ -0,0 +1,40 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_IMAGE_PROVIDER_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_IMAGE_PROVIDER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" + +// This is an abstraction around an image source like a camera, and is +// expected to place 8-bit quantized sample data into the tensor. +// +// The assumption is that this will be +// called in a low duty-cycle fashion in a low-power application. In these +// cases, the imaging sensor need not be run in a streaming mode, but rather can +// be idled in a relatively low-power mode between calls to GetImage(). The +// assumption is that the overhead and time of bringing the low-power sensor out +// of this standby mode is commensurate with the expected duty cycle of the +// application. The underlying sensor may actually be put into a streaming +// configuration, but the tensor provided to GetImage should not be +// overwritten by the driver code until the next call to GetImage(); +// +// For real applications, you should +// ensure there's a specialized implementation that accesses hardware APIs. +TfLiteStatus GetImage(tflite::ErrorReporter* error_reporter, + const TfLiteTensor* tensor); + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_IMAGE_PROVIDER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/main_functions.h b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/main_functions.h new file mode 100644 index 000000000..2620097a8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/main_functions.h @@ -0,0 +1,37 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_MAIN_FUNCTIONS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_MAIN_FUNCTIONS_H_ + +// Expose a C friendly interface for main functions. +#ifdef __cplusplus +extern "C" { +#endif + +// Initializes all data needed for the example. The name is important, and needs +// to be setup() for Arduino compatibility. +void setup(); + +// Runs one iteration of data gathering and inference. This should be called +// repeatedly from the application code. The name needs to be loop() for Arduino +// compatibility. +void loop(); + +#ifdef __cplusplus +} +#endif + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_MAIN_FUNCTIONS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/model_settings.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/model_settings.cpp new file mode 100644 index 000000000..2d4ad1e28 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/model_settings.cpp @@ -0,0 +1,21 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "model_settings.h" + +const char* kCategoryLabels[kCategoryCount] = { + "notperson", + "person", +}; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/model_settings.h b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/model_settings.h new file mode 100644 index 000000000..f94d58ed6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/model_settings.h @@ -0,0 +1,35 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_MODEL_SETTINGS_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_MODEL_SETTINGS_H_ + +// Keeping these as constant expressions allow us to allocate fixed-sized arrays +// on the stack for our working memory. + +// All of these values are derived from the values used during model training, +// if you change your model you'll need to update these constants. +constexpr int kNumCols = 96; +constexpr int kNumRows = 96; +constexpr int kNumChannels = 1; + +constexpr int kMaxImageSize = kNumCols * kNumRows * kNumChannels; + +constexpr int kCategoryCount = 2; +constexpr int kPersonIndex = 1; +constexpr int kNotAPersonIndex = 0; +extern const char* kCategoryLabels[kCategoryCount]; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_MODEL_SETTINGS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detect_model_data.cpp b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detect_model_data.cpp new file mode 100644 index 000000000..7e2c73fc1 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detect_model_data.cpp @@ -0,0 +1,23148 @@ + +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 is a TensorFlow Lite model file that has been converted into a C data +// array using the tensorflow.lite.util.convert_bytes_to_c_source() function. +// This form is useful for compiling into a binary for devices that don't have a +// file system. + +#include "person_detect_model_data.h" + +// Keep model aligned to 8 bytes to guarantee aligned 64-bit accesses. +alignas(8) const unsigned char g_person_detect_model_data[] = { + 0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, + 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x84, 0x95, 0x04, + 0x00, 0xec, 0x5b, 0x03, 0x00, 0xd4, 0x5b, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x5a, 0x00, 0x00, 0x00, 0xc4, 0x5b, 0x03, 0x00, 0xac, 0x5b, 0x03, 0x00, 0x94, + 0x5b, 0x03, 0x00, 0x84, 0x59, 0x03, 0x00, 0x74, 0x55, 0x03, 0x00, 0x64, 0x55, + 0x02, 0x00, 0x54, 0x51, 0x02, 0x00, 0x44, 0x48, 0x02, 0x00, 0x34, 0x44, 0x02, + 0x00, 0x24, 0x42, 0x02, 0x00, 0x94, 0x3d, 0x02, 0x00, 0x84, 0x3b, 0x02, 0x00, + 0x74, 0xfb, 0x01, 0x00, 0xe4, 0xf6, 0x01, 0x00, 0xd4, 0xb6, 0x01, 0x00, 0xc4, + 0xb4, 0x01, 0x00, 0xb4, 0x74, 0x01, 0x00, 0xa4, 0x72, 0x01, 0x00, 0x94, 0x70, + 0x01, 0x00, 0x84, 0x6e, 0x01, 0x00, 0x74, 0x2e, 0x01, 0x00, 0x64, 0xee, 0x00, + 0x00, 0x54, 0xec, 0x00, 0x00, 0xc4, 0xe7, 0x00, 0x00, 0xb4, 0xe5, 0x00, 0x00, + 0xa4, 0xc5, 0x00, 0x00, 0x94, 0xc4, 0x00, 0x00, 0x44, 0xc2, 0x00, 0x00, 0x34, + 0xb2, 0x00, 0x00, 0x24, 0xb1, 0x00, 0x00, 0x14, 0xa9, 0x00, 0x00, 0x84, 0xa8, + 0x00, 0x00, 0x54, 0xa7, 0x00, 0x00, 0x44, 0xa3, 0x00, 0x00, 0xb4, 0xa2, 0x00, + 0x00, 0x84, 0xa1, 0x00, 0x00, 0x34, 0xa1, 0x00, 0x00, 0x2c, 0xa1, 0x00, 0x00, + 0x24, 0xa1, 0x00, 0x00, 0x1c, 0xa1, 0x00, 0x00, 0x14, 0xa1, 0x00, 0x00, 0x0c, + 0xa1, 0x00, 0x00, 0x04, 0xa1, 0x00, 0x00, 0xfc, 0xa0, 0x00, 0x00, 0xf4, 0xa0, + 0x00, 0x00, 0xec, 0xa0, 0x00, 0x00, 0xe4, 0xa0, 0x00, 0x00, 0xdc, 0xa0, 0x00, + 0x00, 0x8c, 0xa0, 0x00, 0x00, 0x84, 0xa0, 0x00, 0x00, 0x7c, 0xa0, 0x00, 0x00, + 0x74, 0xa0, 0x00, 0x00, 0x6c, 0xa0, 0x00, 0x00, 0x64, 0xa0, 0x00, 0x00, 0x5c, + 0xa0, 0x00, 0x00, 0x4c, 0x9e, 0x00, 0x00, 0x1c, 0x9e, 0x00, 0x00, 0x14, 0x9e, + 0x00, 0x00, 0x74, 0x9d, 0x00, 0x00, 0xe4, 0x9c, 0x00, 0x00, 0x8c, 0x9c, 0x00, + 0x00, 0x7c, 0x9a, 0x00, 0x00, 0xec, 0x99, 0x00, 0x00, 0x5c, 0x99, 0x00, 0x00, + 0x54, 0x99, 0x00, 0x00, 0x4c, 0x99, 0x00, 0x00, 0x44, 0x99, 0x00, 0x00, 0x3c, + 0x99, 0x00, 0x00, 0xe4, 0x98, 0x00, 0x00, 0xd4, 0x18, 0x00, 0x00, 0xc4, 0x16, + 0x00, 0x00, 0x34, 0x12, 0x00, 0x00, 0xa4, 0x0d, 0x00, 0x00, 0x9c, 0x0d, 0x00, + 0x00, 0x94, 0x0d, 0x00, 0x00, 0x8c, 0x0d, 0x00, 0x00, 0x7c, 0x0c, 0x00, 0x00, + 0x2c, 0x0a, 0x00, 0x00, 0x1c, 0x08, 0x00, 0x00, 0x14, 0x08, 0x00, 0x00, 0x84, + 0x03, 0x00, 0x00, 0x7c, 0x03, 0x00, 0x00, 0x4c, 0x03, 0x00, 0x00, 0x3c, 0x01, + 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x7c, 0xfc, 0xfb, 0xff, 0x80, 0xfc, 0xfb, 0xff, 0x84, 0xfc, 0xfb, 0xff, 0x88, + 0xfc, 0xfb, 0xff, 0x8c, 0xfc, 0xfb, 0xff, 0xba, 0xa4, 0xfc, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x37, 0x0f, 0x00, 0x00, 0x5d, 0xe6, 0xff, + 0xff, 0x75, 0xdd, 0xff, 0xff, 0xee, 0xf7, 0xff, 0xff, 0xa4, 0xfa, 0xff, 0xff, + 0xc7, 0xf5, 0xff, 0xff, 0x0a, 0x0c, 0x00, 0x00, 0xdb, 0x16, 0x00, 0x00, 0x06, + 0x09, 0x00, 0x00, 0x81, 0x1b, 0x00, 0x00, 0xc1, 0x29, 0x00, 0x00, 0xd2, 0x18, + 0x00, 0x00, 0xd0, 0xf6, 0xff, 0xff, 0x93, 0x5c, 0x00, 0x00, 0xf3, 0xb9, 0xff, + 0xff, 0x0a, 0x28, 0x00, 0x00, 0xed, 0xe9, 0xff, 0xff, 0x86, 0xc9, 0xff, 0xff, + 0x28, 0x27, 0x00, 0x00, 0x77, 0x04, 0x00, 0x00, 0x7a, 0xd0, 0xff, 0xff, 0xad, + 0x58, 0x00, 0x00, 0x1c, 0x4b, 0x00, 0x00, 0xb0, 0x9b, 0xff, 0xff, 0xb5, 0xce, + 0xff, 0xff, 0xfc, 0x12, 0x00, 0x00, 0x3e, 0xfd, 0xff, 0xff, 0x4b, 0xf5, 0xff, + 0xff, 0xae, 0xcb, 0xff, 0xff, 0xc3, 0x39, 0x00, 0x00, 0x56, 0xd1, 0xff, 0xff, + 0x3d, 0x19, 0x00, 0x00, 0x4b, 0x18, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0xc6, + 0x6a, 0x00, 0x00, 0xca, 0xb0, 0xff, 0xff, 0xb4, 0x08, 0x00, 0x00, 0x3b, 0x4b, + 0x00, 0x00, 0xc9, 0xbe, 0xff, 0xff, 0xd4, 0x12, 0x00, 0x00, 0xe2, 0xf4, 0xff, + 0xff, 0x36, 0xff, 0xff, 0xff, 0xd0, 0xef, 0xff, 0xff, 0x08, 0xcc, 0xff, 0xff, + 0xa7, 0xd3, 0xff, 0xff, 0x9c, 0x08, 0x00, 0x00, 0x03, 0x1b, 0x00, 0x00, 0xaf, + 0xa2, 0xff, 0xff, 0x71, 0x13, 0x00, 0x00, 0x0c, 0x7b, 0x00, 0x00, 0xf2, 0x03, + 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x1e, 0x29, 0x00, 0x00, 0x0c, 0x04, 0x00, + 0x00, 0x92, 0x59, 0x00, 0x00, 0x27, 0xd4, 0xff, 0xff, 0x30, 0x0c, 0x00, 0x00, + 0xfa, 0xfb, 0xff, 0xff, 0x17, 0xca, 0xff, 0xff, 0x92, 0xd3, 0xff, 0xff, 0x6c, + 0x11, 0x00, 0x00, 0xc9, 0xff, 0xff, 0xff, 0x78, 0x00, 0x00, 0x00, 0x4f, 0x43, + 0x00, 0x00, 0xc6, 0xa5, 0xfc, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x6e, 0xcc, 0xff, 0xff, 0x69, 0x36, 0x00, 0x00, 0xfb, 0xee, 0xff, 0xff, + 0x24, 0x4c, 0x00, 0x00, 0xb3, 0x07, 0x00, 0x00, 0x96, 0x3f, 0x00, 0x00, 0xe1, + 0xd2, 0xff, 0xff, 0xf7, 0xfd, 0xff, 0xff, 0x01, 0x4f, 0x00, 0x00, 0x9b, 0xea, + 0xff, 0xff, 0xcc, 0xe4, 0xff, 0xff, 0xb2, 0x00, 0x00, 0x00, 0x52, 0xed, 0xff, + 0xff, 0xef, 0xad, 0xff, 0xff, 0xef, 0x34, 0x00, 0x00, 0x37, 0x0c, 0x00, 0x00, + 0xea, 0x47, 0x00, 0x00, 0xf8, 0xed, 0xff, 0xff, 0xa0, 0xef, 0xff, 0xff, 0xea, + 0x43, 0x00, 0x00, 0x17, 0xed, 0xff, 0xff, 0xab, 0xfd, 0xff, 0xff, 0x0b, 0xf8, + 0xff, 0xff, 0x37, 0x26, 0x00, 0x00, 0x33, 0xea, 0xff, 0xff, 0x0e, 0x1e, 0x00, + 0x00, 0xc4, 0x09, 0x00, 0x00, 0x6f, 0x1f, 0x00, 0x00, 0xfc, 0x69, 0xff, 0xff, + 0x9c, 0xd9, 0xff, 0xff, 0xc1, 0xf0, 0xff, 0xff, 0x89, 0x19, 0x00, 0x00, 0x9c, + 0x29, 0x00, 0x00, 0x10, 0xb7, 0xff, 0xff, 0x2f, 0xd9, 0xff, 0xff, 0x23, 0xe9, + 0xff, 0xff, 0xaf, 0x57, 0x00, 0x00, 0x05, 0x48, 0x00, 0x00, 0x30, 0xf7, 0xff, + 0xff, 0x1c, 0x12, 0x00, 0x00, 0xa7, 0xcc, 0xff, 0xff, 0xd0, 0xc6, 0xff, 0xff, + 0x9d, 0xea, 0xff, 0xff, 0x9a, 0xfc, 0xff, 0xff, 0xc1, 0xcc, 0xff, 0xff, 0x63, + 0xcf, 0xff, 0xff, 0xa8, 0x11, 0x00, 0x00, 0x1d, 0xfd, 0xff, 0xff, 0xfc, 0xfa, + 0xff, 0xff, 0x14, 0xe9, 0xff, 0xff, 0xb5, 0x37, 0x00, 0x00, 0x46, 0x21, 0x00, + 0x00, 0x3e, 0x02, 0x00, 0x00, 0x77, 0xd2, 0xff, 0xff, 0x0e, 0xe5, 0xff, 0xff, + 0xde, 0x24, 0x00, 0x00, 0xe9, 0x28, 0x00, 0x00, 0xdc, 0x6d, 0xff, 0xff, 0x59, + 0xb6, 0xff, 0xff, 0xb8, 0x0d, 0x00, 0x00, 0x89, 0xf5, 0xff, 0xff, 0xf5, 0x25, + 0x00, 0x00, 0xd6, 0x1e, 0x00, 0x00, 0x03, 0x32, 0x00, 0x00, 0x2f, 0x1f, 0x00, + 0x00, 0xe1, 0xfa, 0xff, 0xff, 0x59, 0xd8, 0xff, 0xff, 0x85, 0x3e, 0x00, 0x00, + 0xae, 0xea, 0xff, 0xff, 0x72, 0x3e, 0x00, 0x00, 0x87, 0xfd, 0xff, 0xff, 0x27, + 0x57, 0x00, 0x00, 0x0b, 0xf2, 0xff, 0xff, 0xc2, 0x1c, 0x00, 0x00, 0xd9, 0x20, + 0x00, 0x00, 0xf9, 0x2e, 0x00, 0x00, 0x84, 0xfd, 0xff, 0xff, 0x6b, 0x22, 0x00, + 0x00, 0x2b, 0x94, 0xff, 0xff, 0xdf, 0xfd, 0xff, 0xff, 0x80, 0xee, 0xff, 0xff, + 0x4d, 0xe6, 0xff, 0xff, 0x71, 0xd4, 0xff, 0xff, 0xd6, 0xd8, 0xff, 0xff, 0xdc, + 0x4d, 0x00, 0x00, 0xfc, 0xb8, 0xff, 0xff, 0xa6, 0x45, 0x00, 0x00, 0xa5, 0xf1, + 0xff, 0xff, 0x63, 0x31, 0x00, 0x00, 0x3c, 0xd8, 0xff, 0xff, 0x12, 0x29, 0x00, + 0x00, 0x34, 0xdb, 0xff, 0xff, 0xae, 0x57, 0x00, 0x00, 0x6c, 0xc9, 0xff, 0xff, + 0x1b, 0x2f, 0x00, 0x00, 0x44, 0x28, 0x00, 0x00, 0x34, 0xf3, 0xff, 0xff, 0xdd, + 0x1c, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0xaa, 0x02, 0x00, 0x00, 0x23, 0x41, + 0x00, 0x00, 0x97, 0x0e, 0x00, 0x00, 0xcf, 0x1b, 0x00, 0x00, 0x50, 0x17, 0x00, + 0x00, 0x67, 0x8b, 0xff, 0xff, 0x22, 0x0b, 0x00, 0x00, 0x56, 0xd1, 0xff, 0xff, + 0xfe, 0xe8, 0xff, 0xff, 0x8d, 0x31, 0x00, 0x00, 0xc9, 0xd1, 0xff, 0xff, 0x98, + 0x10, 0x00, 0x00, 0x9c, 0x44, 0x00, 0x00, 0x0f, 0x0b, 0x00, 0x00, 0xd4, 0x3e, + 0x00, 0x00, 0x64, 0x19, 0x00, 0x00, 0x0c, 0xe8, 0xff, 0xff, 0xcc, 0x04, 0x00, + 0x00, 0xcc, 0xb7, 0xff, 0xff, 0xea, 0x3d, 0x00, 0x00, 0x30, 0x19, 0x00, 0x00, + 0x70, 0x06, 0x00, 0x00, 0x14, 0x2f, 0x00, 0x00, 0xcb, 0xd4, 0xff, 0xff, 0xd2, + 0xee, 0xff, 0xff, 0x4e, 0x26, 0x00, 0x00, 0xd4, 0x23, 0x00, 0x00, 0xa0, 0x55, + 0x00, 0x00, 0x2e, 0x15, 0x00, 0x00, 0xd2, 0xa7, 0xfc, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0xbe, 0x0e, 0x00, 0x00, 0x95, 0xff, 0xff, 0xff, + 0x56, 0xb6, 0xfe, 0xff, 0xac, 0xc9, 0xff, 0xff, 0xd9, 0x50, 0x00, 0x00, 0xfa, + 0xff, 0xff, 0xff, 0xdf, 0x2c, 0x00, 0x00, 0x9a, 0xcb, 0xfd, 0xff, 0xd4, 0xff, + 0xfb, 0xff, 0x02, 0xa8, 0xfc, 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, + 0x00, 0x5e, 0xac, 0x7e, 0x7f, 0xdc, 0xf2, 0xcc, 0x39, 0x8c, 0x81, 0x5e, 0xa5, + 0xa7, 0x7f, 0xbd, 0x37, 0x45, 0x1b, 0xf3, 0x74, 0x7f, 0x1e, 0xc4, 0xfb, 0x00, + 0xbe, 0xfc, 0xfa, 0x03, 0x22, 0x7f, 0x59, 0x38, 0xac, 0x75, 0xeb, 0x56, 0xa8, + 0x9e, 0x00, 0x9a, 0x99, 0xf4, 0xa2, 0x5f, 0x08, 0x7f, 0x44, 0xc9, 0x01, 0x36, + 0x0d, 0xde, 0xc2, 0xbf, 0xa4, 0x01, 0x7f, 0xf8, 0x1a, 0xd2, 0xec, 0x01, 0x41, + 0x41, 0x0f, 0x0c, 0xd8, 0x05, 0xd6, 0x4f, 0x81, 0x37, 0x2e, 0x63, 0x7f, 0x2e, + 0x1c, 0xd1, 0xab, 0xbe, 0x52, 0xb3, 0x7f, 0x7f, 0x14, 0xa3, 0xe0, 0xad, 0x7f, + 0xc1, 0x69, 0xc3, 0xc7, 0xf7, 0x71, 0xc6, 0xaf, 0x81, 0x25, 0x7f, 0x75, 0x18, + 0xc4, 0xcf, 0xdd, 0x4f, 0x1d, 0x9b, 0x04, 0xa4, 0xe9, 0x81, 0xb0, 0x31, 0x89, + 0x4f, 0x1f, 0x14, 0x4d, 0x78, 0x24, 0x81, 0x7f, 0xfb, 0x81, 0xf5, 0xe8, 0x4f, + 0xc5, 0x7f, 0x10, 0x26, 0x50, 0xce, 0xe5, 0xf4, 0x00, 0x0c, 0xac, 0xd6, 0x4f, + 0x50, 0x42, 0x7f, 0x0d, 0xe7, 0x35, 0x3c, 0xfd, 0x4b, 0xf1, 0xae, 0x18, 0xfb, + 0xc9, 0x1f, 0xe3, 0x52, 0x3d, 0x7f, 0xe8, 0x44, 0x7f, 0x3a, 0xd7, 0xe1, 0x3d, + 0x8b, 0xba, 0xc4, 0x57, 0x3b, 0x1d, 0x1b, 0x26, 0x8e, 0x45, 0x3b, 0xcd, 0x4d, + 0xcc, 0x14, 0xb0, 0x2e, 0x60, 0xed, 0xf8, 0xb0, 0xfe, 0xf9, 0x30, 0xfc, 0x22, + 0x7c, 0xc0, 0x15, 0x70, 0x70, 0x20, 0x7f, 0x9c, 0x4d, 0x06, 0x11, 0xc8, 0xb5, + 0xc7, 0xc1, 0x2a, 0xb8, 0x51, 0x1b, 0x4e, 0xbd, 0x9d, 0x5e, 0x30, 0xd3, 0x47, + 0xc5, 0x49, 0xe9, 0x20, 0xc7, 0x2c, 0xf0, 0x59, 0xdf, 0x47, 0x2e, 0xd5, 0x9e, + 0x9e, 0xa7, 0xd1, 0x81, 0xf9, 0xd7, 0x15, 0x9c, 0xa6, 0x6d, 0xfe, 0x7f, 0x79, + 0x7f, 0xd7, 0x7f, 0x4f, 0xdf, 0x7a, 0x00, 0xbf, 0x7f, 0xd6, 0x48, 0x93, 0x3d, + 0x5a, 0x7f, 0xca, 0x81, 0x42, 0xbc, 0xb6, 0x67, 0xb7, 0xae, 0x40, 0xc0, 0x7f, + 0x2f, 0x12, 0x3a, 0x7f, 0x22, 0x43, 0x42, 0xec, 0xc1, 0x21, 0x07, 0xf0, 0x18, + 0xc9, 0x11, 0x30, 0x21, 0xef, 0x26, 0x44, 0xdd, 0xc0, 0xaf, 0x9d, 0xa9, 0x20, + 0xb5, 0x00, 0xbd, 0x0d, 0x54, 0x45, 0x7f, 0x0d, 0x3b, 0x03, 0x1a, 0xaa, 0x21, + 0xc4, 0xec, 0x63, 0xf9, 0x09, 0x08, 0x0b, 0x20, 0x2e, 0xd4, 0x56, 0x73, 0x13, + 0xed, 0x76, 0x81, 0xd7, 0x4d, 0xfb, 0x14, 0xf4, 0xf7, 0x23, 0xc4, 0x99, 0xbc, + 0x1c, 0x14, 0x6a, 0x05, 0xe0, 0x8a, 0x5c, 0x8a, 0xf7, 0xb1, 0x30, 0xf4, 0xf3, + 0x08, 0x0b, 0xfb, 0x7f, 0xaf, 0x39, 0x78, 0x77, 0x25, 0xda, 0xbd, 0x9e, 0xcf, + 0x26, 0xf3, 0x1e, 0xd8, 0x08, 0x5c, 0xcc, 0x77, 0xaa, 0x07, 0xfa, 0x08, 0x14, + 0xce, 0x11, 0xa1, 0x71, 0xa8, 0x8c, 0x5a, 0xf2, 0xd5, 0x9f, 0x60, 0x54, 0xd5, + 0x21, 0xbe, 0x7f, 0xa4, 0xa3, 0x7f, 0x74, 0x81, 0x5c, 0x81, 0xd4, 0x15, 0x13, + 0x7f, 0x68, 0x19, 0x7f, 0xda, 0x68, 0xf9, 0x20, 0x64, 0x1e, 0xcd, 0xe3, 0x03, + 0x16, 0x4f, 0xbe, 0x45, 0xe8, 0xfd, 0x8d, 0xd9, 0xf3, 0xd1, 0xa0, 0x90, 0x81, + 0xfc, 0x81, 0x2c, 0x68, 0xca, 0x21, 0x0a, 0x17, 0xff, 0x81, 0xe5, 0x81, 0x39, + 0x04, 0x00, 0xc6, 0xb3, 0x7f, 0x2a, 0xd7, 0x1b, 0xd8, 0x35, 0xa4, 0x7f, 0x47, + 0x5c, 0xf7, 0x76, 0x67, 0x24, 0xef, 0x4e, 0x41, 0xab, 0xcc, 0xd2, 0x7f, 0x81, + 0x4f, 0x35, 0x7f, 0xb8, 0x99, 0xf9, 0x25, 0x98, 0x7f, 0x81, 0x6f, 0xf5, 0x7f, + 0xd5, 0xc3, 0xc9, 0xd7, 0x59, 0x92, 0x2b, 0xcd, 0x99, 0x94, 0x7f, 0x1e, 0xb1, + 0x40, 0xcc, 0x15, 0x8d, 0x77, 0x63, 0xba, 0x24, 0x2b, 0x28, 0x46, 0xd1, 0x7f, + 0xa2, 0xc3, 0xd2, 0xa1, 0x3b, 0x05, 0x26, 0xd1, 0x1c, 0x19, 0xe1, 0x04, 0x9a, + 0x15, 0x81, 0xb9, 0x41, 0x05, 0x9f, 0xe8, 0x49, 0x18, 0x1b, 0x05, 0x30, 0x71, + 0xe4, 0x17, 0x7f, 0x7f, 0x02, 0x6f, 0x64, 0xee, 0x30, 0xcd, 0x04, 0x27, 0x4b, + 0xeb, 0x7f, 0x7f, 0xf4, 0xca, 0xc5, 0x7f, 0xb9, 0x08, 0x84, 0x3c, 0x43, 0x8b, + 0x6f, 0x6b, 0x1c, 0x42, 0x28, 0x81, 0xeb, 0xae, 0xcf, 0x9f, 0x04, 0x00, 0x7f, + 0xf8, 0xc1, 0x0c, 0xd8, 0x1e, 0x49, 0x9a, 0x50, 0xaf, 0xed, 0x26, 0xb0, 0x49, + 0x45, 0x21, 0xe4, 0xf8, 0x7f, 0x7f, 0xd7, 0xd1, 0xa9, 0x41, 0x38, 0xc6, 0x38, + 0x7f, 0xfd, 0xf8, 0x7f, 0x12, 0xa8, 0xfb, 0xae, 0x7f, 0x07, 0x65, 0x81, 0x59, + 0x94, 0xff, 0xaf, 0xc0, 0x7f, 0xdf, 0xa3, 0x17, 0x05, 0x7f, 0x03, 0xe9, 0xb5, + 0x6c, 0xd5, 0x35, 0x15, 0xf7, 0x56, 0x7f, 0x54, 0xe8, 0x3b, 0x34, 0x06, 0xd6, + 0x81, 0x20, 0x18, 0x25, 0x7f, 0xc6, 0x4f, 0x5a, 0xd2, 0x1b, 0xf4, 0x56, 0xb4, + 0xa3, 0xee, 0x19, 0x89, 0x5c, 0x58, 0x25, 0x11, 0x27, 0x6e, 0x1a, 0x0f, 0x36, + 0x33, 0xee, 0x03, 0x7f, 0x28, 0xbc, 0x42, 0x01, 0xdd, 0x3f, 0x38, 0x05, 0x69, + 0xc8, 0xfa, 0xe0, 0xd3, 0xd1, 0xbb, 0x55, 0x81, 0x70, 0xc9, 0xab, 0x1a, 0x7f, + 0x6c, 0x51, 0x09, 0x00, 0xf5, 0x9e, 0x57, 0xab, 0x2a, 0x08, 0xcf, 0xb5, 0xe5, + 0x3b, 0x13, 0x7f, 0x04, 0x7f, 0x7f, 0x61, 0xfa, 0x7f, 0xb7, 0x31, 0x2d, 0x48, + 0x3f, 0xf0, 0xf1, 0x37, 0xde, 0x9a, 0xc1, 0xf0, 0x5f, 0x30, 0x2e, 0xd9, 0xb9, + 0x53, 0xe4, 0x02, 0x07, 0x09, 0xad, 0x3d, 0x01, 0x3c, 0x31, 0x12, 0xdf, 0x6d, + 0x2f, 0xd4, 0x54, 0x9b, 0x81, 0x81, 0xcd, 0x28, 0xa8, 0x01, 0x81, 0x7f, 0x03, + 0x5a, 0x12, 0x8e, 0x1e, 0x3f, 0x0d, 0x7f, 0x99, 0x2a, 0xa1, 0xe8, 0xac, 0xae, + 0x74, 0xf2, 0xb8, 0xb9, 0x31, 0xf0, 0xe9, 0x76, 0xfd, 0x15, 0xc4, 0x8f, 0x28, + 0x7f, 0x0a, 0xfa, 0xaf, 0xd5, 0x02, 0x56, 0x28, 0x6b, 0xeb, 0x6d, 0x0f, 0x03, + 0x7f, 0x1a, 0x7f, 0x7f, 0x06, 0xb7, 0xd0, 0xc7, 0xa0, 0xbd, 0xd2, 0xfa, 0x58, + 0x7f, 0x89, 0xbe, 0x81, 0x81, 0xeb, 0x82, 0x90, 0x8b, 0xf9, 0xe3, 0xca, 0xca, + 0x42, 0x6a, 0x50, 0xd8, 0x56, 0x45, 0x79, 0xe5, 0x0f, 0x7f, 0xea, 0xdb, 0x7f, + 0x2b, 0x7f, 0xf9, 0x9b, 0xb0, 0x29, 0x5e, 0xfa, 0x59, 0xff, 0x7f, 0x7f, 0xe3, + 0x7a, 0x04, 0xb1, 0x95, 0xe0, 0x60, 0xd8, 0xff, 0xe9, 0x47, 0x8f, 0x5b, 0xa2, + 0x01, 0x81, 0x53, 0xed, 0x51, 0x34, 0x57, 0x0d, 0xcd, 0x9b, 0x2e, 0x09, 0xa9, + 0x13, 0xa4, 0xa1, 0xa6, 0x40, 0x16, 0xdc, 0x61, 0xa0, 0xee, 0xb5, 0x76, 0x8b, + 0xbc, 0xeb, 0xda, 0x00, 0x31, 0x0c, 0x2f, 0xe3, 0x8d, 0x9e, 0x93, 0x16, 0x5f, + 0x86, 0x81, 0x02, 0xa7, 0xba, 0x6a, 0xb8, 0xc7, 0xc9, 0x87, 0xa6, 0xfd, 0xe0, + 0x73, 0xf0, 0xb1, 0x26, 0x2c, 0xef, 0x71, 0xe7, 0x3f, 0x09, 0x6b, 0x1b, 0xad, + 0x53, 0x1e, 0x25, 0xfc, 0x1d, 0x99, 0x1d, 0xcf, 0xbc, 0x15, 0x7f, 0x65, 0xdc, + 0x1b, 0xd2, 0x6e, 0xe0, 0x1e, 0x81, 0xad, 0x0c, 0xdf, 0xe0, 0x81, 0xf7, 0x43, + 0x7f, 0xab, 0x7e, 0xfc, 0x3a, 0xde, 0xfd, 0x10, 0xba, 0xdd, 0x5c, 0x6b, 0x5c, + 0xd3, 0x2e, 0x77, 0xfb, 0x5a, 0xd1, 0x6e, 0x3c, 0x3a, 0x4b, 0xe4, 0x0f, 0x4d, + 0xb0, 0xf3, 0x81, 0x11, 0x2c, 0xbc, 0xc4, 0x51, 0xaa, 0x7f, 0x40, 0x49, 0xbe, + 0xf9, 0x10, 0x64, 0x7f, 0x0a, 0x9f, 0x2b, 0xcb, 0x49, 0xd0, 0x81, 0x38, 0x89, + 0xdb, 0x9a, 0xf7, 0x3b, 0xe8, 0x24, 0x9c, 0x21, 0x8d, 0x60, 0xcf, 0xd2, 0xdd, + 0x10, 0x1e, 0xc0, 0xf5, 0x79, 0xad, 0x8e, 0xbe, 0xce, 0x36, 0x61, 0xae, 0xc2, + 0x1a, 0x32, 0xf2, 0x7f, 0xd1, 0xef, 0x8b, 0xca, 0x08, 0xef, 0x20, 0x2c, 0x4c, + 0xc0, 0xf6, 0x7f, 0x76, 0x56, 0xdf, 0x44, 0xcf, 0xec, 0x5d, 0xe0, 0x0b, 0xad, + 0x7f, 0x7f, 0xe8, 0x81, 0x42, 0x81, 0x2f, 0xfa, 0x0c, 0x32, 0x81, 0xc8, 0xca, + 0x3b, 0xfd, 0x3f, 0xa9, 0x1c, 0x0d, 0x16, 0xf7, 0xda, 0x7f, 0x67, 0x21, 0xe6, + 0x7f, 0x77, 0x7f, 0xb1, 0xd1, 0x69, 0x81, 0x54, 0x5a, 0xef, 0x34, 0xde, 0xc1, + 0x7f, 0xd3, 0x52, 0xdf, 0x66, 0xec, 0x41, 0x21, 0xe0, 0x04, 0xf6, 0x81, 0x81, + 0xfd, 0x48, 0x10, 0xf9, 0xbf, 0xb0, 0x81, 0x60, 0xc0, 0xdc, 0xa3, 0xc3, 0xec, + 0x6d, 0x0c, 0x1d, 0x05, 0x08, 0xbd, 0x7f, 0x0b, 0x8f, 0x06, 0x81, 0xea, 0xcf, + 0xac, 0x11, 0xc6, 0x7f, 0xe9, 0x1c, 0xd7, 0x7f, 0x81, 0x81, 0xd7, 0xdc, 0xf2, + 0x38, 0x13, 0x6a, 0x9f, 0xad, 0xb5, 0x83, 0x02, 0x7f, 0x64, 0x04, 0xfc, 0xff, + 0x92, 0xac, 0xfc, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x7f, + 0xf0, 0xff, 0xff, 0x8a, 0xf8, 0xff, 0xff, 0x87, 0xf6, 0xff, 0xff, 0x8e, 0xff, + 0xff, 0xff, 0x68, 0x11, 0x00, 0x00, 0x24, 0xea, 0xff, 0xff, 0x95, 0x27, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0xe5, 0xff, 0xff, 0x96, 0xef, 0xff, 0xff, + 0xe7, 0xf7, 0xff, 0xff, 0x63, 0x00, 0x00, 0x00, 0x4f, 0xf8, 0xff, 0xff, 0xac, + 0xff, 0xff, 0xff, 0x5d, 0x25, 0x00, 0x00, 0x5a, 0xff, 0xff, 0xff, 0xc1, 0xff, + 0xff, 0xff, 0xe0, 0x07, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00, 0x9a, 0xfd, 0xff, + 0xff, 0xf8, 0x04, 0x00, 0x00, 0xe0, 0xfc, 0xff, 0xff, 0xa2, 0xfd, 0xff, 0xff, + 0xf5, 0xee, 0xff, 0xff, 0x02, 0xfb, 0xff, 0xff, 0x19, 0x20, 0x00, 0x00, 0xd6, + 0x26, 0x00, 0x00, 0xc9, 0xfc, 0xff, 0xff, 0x8e, 0x22, 0x00, 0x00, 0x21, 0xff, + 0xff, 0xff, 0xbf, 0x31, 0x00, 0x00, 0x6b, 0x27, 0x00, 0x00, 0xce, 0xe7, 0xff, + 0xff, 0x52, 0xfd, 0xff, 0xff, 0xfc, 0xfc, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, + 0x8e, 0x20, 0x00, 0x00, 0xd8, 0x04, 0x00, 0x00, 0x2f, 0xfc, 0xff, 0xff, 0xc2, + 0x29, 0x00, 0x00, 0x34, 0xf3, 0xff, 0xff, 0xfd, 0xec, 0xff, 0xff, 0x52, 0xf9, + 0xff, 0xff, 0x66, 0xeb, 0xff, 0xff, 0x90, 0x21, 0x00, 0x00, 0xef, 0x39, 0x00, + 0x00, 0xb4, 0x03, 0x00, 0x00, 0xe5, 0x01, 0x00, 0x00, 0x37, 0xfb, 0xff, 0xff, + 0xf5, 0xf8, 0xff, 0xff, 0xac, 0xf9, 0xff, 0xff, 0x05, 0xf5, 0xff, 0xff, 0x74, + 0xff, 0xff, 0xff, 0xd7, 0xf8, 0xff, 0xff, 0x3a, 0x1e, 0x00, 0x00, 0x43, 0x2e, + 0x00, 0x00, 0xf0, 0xf2, 0xff, 0xff, 0x1f, 0xfd, 0xff, 0xff, 0x4d, 0x1c, 0x00, + 0x00, 0xe9, 0xff, 0xff, 0xff, 0xb6, 0xfc, 0xff, 0xff, 0x45, 0x2c, 0x00, 0x00, + 0xf4, 0x08, 0x00, 0x00, 0xbe, 0xff, 0xff, 0xff, 0x92, 0x29, 0x00, 0x00, 0xf6, + 0x32, 0x00, 0x00, 0x01, 0xf7, 0xff, 0xff, 0xe3, 0xf6, 0xff, 0xff, 0xf2, 0xfd, + 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0x1a, 0xf4, 0xff, 0xff, 0x22, 0x00, 0x00, + 0x00, 0x32, 0xeb, 0xff, 0xff, 0xed, 0x22, 0x00, 0x00, 0x3c, 0xfc, 0xff, 0xff, + 0x95, 0x00, 0x00, 0x00, 0xcb, 0x0b, 0x00, 0x00, 0xc6, 0x32, 0x00, 0x00, 0xf8, + 0xf8, 0xff, 0xff, 0x28, 0x27, 0x00, 0x00, 0x1b, 0x05, 0x00, 0x00, 0xfb, 0xfe, + 0xff, 0xff, 0x05, 0xf9, 0xff, 0xff, 0xb3, 0x27, 0x00, 0x00, 0xb7, 0x2d, 0x00, + 0x00, 0x78, 0x0e, 0x00, 0x00, 0x0e, 0xf7, 0xff, 0xff, 0xe2, 0xf3, 0xff, 0xff, + 0xc4, 0xfe, 0xff, 0xff, 0x35, 0xff, 0xff, 0xff, 0x1b, 0xf6, 0xff, 0xff, 0xa4, + 0xfd, 0xff, 0xff, 0x1d, 0xfd, 0xff, 0xff, 0xe7, 0x28, 0x00, 0x00, 0x1e, 0xf6, + 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x12, 0xf8, 0xff, 0xff, 0x04, 0xf8, 0xff, + 0xff, 0x51, 0xf8, 0xff, 0xff, 0xde, 0xff, 0xff, 0xff, 0x15, 0x07, 0x00, 0x00, + 0xa4, 0xfa, 0xff, 0xff, 0xb4, 0xf8, 0xff, 0xff, 0x8b, 0x2d, 0x00, 0x00, 0xd5, + 0x2f, 0x00, 0x00, 0x47, 0xf9, 0xff, 0xff, 0xbb, 0xf8, 0xff, 0xff, 0xda, 0x39, + 0x00, 0x00, 0xa0, 0x14, 0x00, 0x00, 0x2c, 0xfb, 0xff, 0xff, 0x20, 0x01, 0x00, + 0x00, 0xf5, 0xfc, 0xff, 0xff, 0x4b, 0x29, 0x00, 0x00, 0x80, 0xfd, 0xff, 0xff, + 0x4c, 0x22, 0x00, 0x00, 0xd7, 0x07, 0x00, 0x00, 0xb3, 0x28, 0x00, 0x00, 0x21, + 0xff, 0xff, 0xff, 0xf3, 0xf7, 0xff, 0xff, 0x17, 0xfe, 0xff, 0xff, 0xa3, 0xf4, + 0xff, 0xff, 0x4d, 0x38, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, 0x3b, 0x38, 0x00, + 0x00, 0x7a, 0xfc, 0xff, 0xff, 0x78, 0xfd, 0xff, 0xff, 0x5e, 0x01, 0x00, 0x00, + 0xb6, 0x43, 0x00, 0x00, 0x9e, 0xae, 0xfc, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, + 0x02, 0x00, 0x00, 0x47, 0xc3, 0xfe, 0xec, 0xfe, 0x7f, 0xd6, 0x81, 0x3d, 0x37, + 0x29, 0x0b, 0xb8, 0x1b, 0x0c, 0x3a, 0x13, 0xc8, 0xde, 0x81, 0xd3, 0x01, 0xf4, + 0xbc, 0x3c, 0xf7, 0x44, 0xac, 0x0b, 0xf6, 0x81, 0xc9, 0x30, 0x13, 0xe8, 0x31, + 0x0f, 0x2c, 0x8d, 0xc6, 0x7f, 0x28, 0x0d, 0xf9, 0xb9, 0xa3, 0x4d, 0x81, 0x0b, + 0xed, 0x7f, 0xfb, 0xe2, 0x7f, 0xbf, 0x91, 0x7f, 0xc9, 0xa9, 0x72, 0x30, 0xfb, + 0xe1, 0x42, 0x48, 0x81, 0x1f, 0x3c, 0x7f, 0x7c, 0xac, 0x93, 0x51, 0x7f, 0xdd, + 0x15, 0xf1, 0x13, 0x47, 0x7f, 0x34, 0x90, 0x63, 0xb4, 0xfd, 0x89, 0x7f, 0xb9, + 0x7f, 0x17, 0x31, 0xb5, 0x5f, 0xa1, 0x3d, 0x4c, 0x60, 0x9c, 0x38, 0x81, 0xe9, + 0xf7, 0x82, 0xb6, 0xfd, 0xcf, 0xed, 0x39, 0x81, 0x89, 0xba, 0x8a, 0x19, 0x27, + 0xe8, 0xde, 0x81, 0x44, 0x86, 0xb3, 0x5b, 0xa5, 0x81, 0x37, 0x8b, 0xd5, 0xab, + 0xac, 0x0c, 0xc4, 0x03, 0xfb, 0xea, 0xb8, 0xd5, 0xa4, 0xe3, 0xcd, 0xeb, 0xea, + 0xec, 0x24, 0xce, 0x10, 0xdc, 0xee, 0xdb, 0xe8, 0xe0, 0x35, 0x08, 0xcc, 0xea, + 0xf1, 0x3e, 0xf8, 0xc7, 0xf9, 0x9a, 0xfe, 0x4a, 0x30, 0xf9, 0xdd, 0x1a, 0xec, + 0x0b, 0xd9, 0xd0, 0xd7, 0xf9, 0xd0, 0xfb, 0x9e, 0xf0, 0xbb, 0xdf, 0xf5, 0x0a, + 0xdd, 0xfd, 0xdf, 0xd2, 0x07, 0xe0, 0xfe, 0x05, 0x96, 0x42, 0xf2, 0xec, 0xb9, + 0x3d, 0xf1, 0x66, 0x81, 0x18, 0x77, 0xf4, 0x89, 0x7f, 0xbe, 0x7f, 0x20, 0xf1, + 0x7f, 0xeb, 0xf5, 0x55, 0x81, 0x42, 0xbb, 0xdf, 0xba, 0x00, 0xef, 0x47, 0x03, + 0x8b, 0x81, 0xd6, 0xe0, 0xac, 0xab, 0x70, 0xa4, 0x81, 0xb3, 0x93, 0xa3, 0x75, + 0x7f, 0x4c, 0x24, 0x7f, 0x2d, 0x9b, 0x81, 0x7f, 0x8a, 0x4f, 0x02, 0x5f, 0xa6, + 0xfd, 0x4f, 0x8d, 0x81, 0xe0, 0xcf, 0xcd, 0x7f, 0xf6, 0x81, 0xca, 0xc7, 0x7f, + 0x0a, 0x6b, 0x5d, 0x2c, 0x28, 0x81, 0xbe, 0xa6, 0xdf, 0xba, 0x7f, 0x2c, 0x7e, + 0x7f, 0xf4, 0x7f, 0x94, 0x7f, 0x93, 0x81, 0x81, 0xb1, 0x81, 0x4c, 0x7f, 0x81, + 0x98, 0x7f, 0x81, 0xc2, 0x7f, 0x7f, 0x81, 0x6b, 0x82, 0xe3, 0x81, 0x7f, 0x22, + 0x3b, 0x7f, 0x89, 0x7f, 0x81, 0xab, 0xdb, 0x1e, 0x7f, 0x7f, 0x1b, 0x22, 0x65, + 0x4f, 0x81, 0x99, 0xaa, 0x81, 0x8b, 0x7f, 0x81, 0xef, 0x81, 0x81, 0x08, 0x23, + 0xf6, 0x7d, 0xab, 0xaf, 0xd9, 0x83, 0xc5, 0xfc, 0x0a, 0xf1, 0xea, 0x00, 0x3e, + 0xf3, 0x07, 0xdd, 0x16, 0x17, 0xd4, 0x54, 0x03, 0xfb, 0xec, 0x05, 0xde, 0xb3, + 0x32, 0x13, 0x9d, 0x34, 0xfc, 0xdc, 0x72, 0xdb, 0x7f, 0xc5, 0xfc, 0x1e, 0xf8, + 0xcd, 0xea, 0x02, 0xa3, 0xb8, 0xbf, 0xb4, 0x05, 0x0d, 0x11, 0x7f, 0x08, 0x13, + 0xcf, 0xf2, 0xf7, 0xcf, 0xef, 0xb7, 0x0f, 0xbe, 0xdf, 0x2c, 0xe1, 0x11, 0xad, + 0xb7, 0xf7, 0xbc, 0x58, 0x14, 0xeb, 0x02, 0xfe, 0x01, 0xfa, 0x12, 0xea, 0x07, + 0xf0, 0xd0, 0xf8, 0xfe, 0xe0, 0xee, 0x0c, 0x36, 0x16, 0xf1, 0x17, 0xc2, 0xea, + 0xd2, 0xfb, 0xdc, 0xe0, 0xef, 0x00, 0xc5, 0xd6, 0x32, 0x46, 0x77, 0x01, 0xcf, + 0x2f, 0x0f, 0xc0, 0xd8, 0xec, 0x8b, 0xe7, 0xdb, 0xaa, 0xb9, 0x0a, 0xe6, 0x1d, + 0x22, 0xa5, 0x36, 0xd8, 0xb0, 0x30, 0x8a, 0xf3, 0xf3, 0x14, 0x0e, 0x81, 0xea, + 0xf3, 0xd0, 0xfc, 0xb0, 0xd1, 0xed, 0xea, 0x21, 0x7f, 0x61, 0x01, 0xb2, 0x07, + 0xa0, 0x0e, 0xfd, 0x98, 0x08, 0xd3, 0xe9, 0x07, 0xf0, 0xf2, 0xb4, 0x33, 0xdc, + 0x96, 0xd9, 0x10, 0xcc, 0xd5, 0xb5, 0x02, 0x63, 0x56, 0x1d, 0x2a, 0x5a, 0xea, + 0x2d, 0xba, 0xbd, 0x1c, 0x0d, 0x1f, 0x1e, 0x3a, 0x3f, 0x2e, 0xe4, 0xfc, 0xe4, + 0xb9, 0xd2, 0xb4, 0xd0, 0xb2, 0xc9, 0xd8, 0x2b, 0xe6, 0xf6, 0xe7, 0x2e, 0xef, + 0xf5, 0x28, 0xf0, 0xfd, 0x0b, 0xec, 0xfd, 0x15, 0xcd, 0xee, 0xee, 0xf1, 0x0f, + 0xa1, 0x0b, 0xce, 0xea, 0xf6, 0x07, 0xea, 0xf8, 0xf0, 0x22, 0xfe, 0x0b, 0xe0, + 0x0f, 0x01, 0xf2, 0xed, 0x22, 0x1b, 0x48, 0xd7, 0xf9, 0x05, 0xf5, 0xd1, 0xe1, + 0xe2, 0xf0, 0xf2, 0xb1, 0xf3, 0xee, 0x0c, 0x4d, 0xf4, 0xe9, 0x2d, 0x1d, 0x0e, + 0xd2, 0x08, 0x1e, 0x2c, 0x11, 0x40, 0x28, 0xea, 0xb0, 0xfc, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x8b, 0x31, 0x00, 0x00, 0xe5, 0x8e, 0x00, + 0x00, 0x3e, 0x18, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0xda, 0x3d, 0x00, 0x00, + 0x9d, 0xf1, 0xff, 0xff, 0x5e, 0x56, 0x00, 0x00, 0xe2, 0x3c, 0x00, 0x00, 0xef, + 0xde, 0xff, 0xff, 0x58, 0x35, 0x00, 0x00, 0x4a, 0x14, 0x00, 0x00, 0x9f, 0xf0, + 0xff, 0xff, 0x0e, 0x10, 0x00, 0x00, 0x1f, 0xdc, 0xff, 0xff, 0xf1, 0x08, 0x00, + 0x00, 0x47, 0x32, 0x00, 0x00, 0x12, 0x43, 0x00, 0x00, 0x6d, 0x1c, 0x00, 0x00, + 0x44, 0x7d, 0xff, 0xff, 0x96, 0x0b, 0x00, 0x00, 0xd3, 0x11, 0x00, 0x00, 0x13, + 0x1b, 0x00, 0x00, 0xb4, 0xa8, 0xff, 0xff, 0x1e, 0x1c, 0x00, 0x00, 0x2b, 0xd2, + 0xff, 0xff, 0x4b, 0x8b, 0x00, 0x00, 0x20, 0x27, 0x00, 0x00, 0xcd, 0xff, 0xff, + 0xff, 0x50, 0xce, 0xff, 0xff, 0x02, 0x39, 0x00, 0x00, 0x08, 0x30, 0x00, 0x00, + 0x91, 0xf1, 0xff, 0xff, 0x61, 0x12, 0x00, 0x00, 0xa9, 0x50, 0x00, 0x00, 0x28, + 0x1a, 0x00, 0x00, 0x4a, 0x0d, 0x00, 0x00, 0x60, 0x3b, 0x00, 0x00, 0x07, 0x37, + 0x00, 0x00, 0x15, 0x63, 0x00, 0x00, 0xac, 0x0f, 0x00, 0x00, 0xbe, 0x37, 0x00, + 0x00, 0xfd, 0x2d, 0x00, 0x00, 0x1a, 0x3c, 0x00, 0x00, 0x08, 0x4b, 0x00, 0x00, + 0x05, 0x17, 0x00, 0x00, 0x0a, 0x70, 0x00, 0x00, 0xde, 0xec, 0x00, 0x00, 0x12, + 0xef, 0xff, 0xff, 0xa8, 0xa0, 0xff, 0xff, 0x5d, 0x4b, 0x00, 0x00, 0x62, 0x1f, + 0x00, 0x00, 0x27, 0xfe, 0xff, 0xff, 0x8b, 0x23, 0x00, 0x00, 0xc5, 0xfe, 0xff, + 0xff, 0xc4, 0x02, 0x00, 0x00, 0xfc, 0x6a, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, + 0xf9, 0x44, 0x00, 0x00, 0x15, 0x65, 0x00, 0x00, 0xae, 0x0c, 0x00, 0x00, 0x0d, + 0x6d, 0x00, 0x00, 0x37, 0x14, 0x00, 0x00, 0x86, 0x39, 0x00, 0x00, 0xfd, 0x60, + 0x00, 0x00, 0xcc, 0x09, 0xfc, 0xff, 0xd0, 0x09, 0xfc, 0xff, 0xd4, 0x09, 0xfc, + 0xff, 0x02, 0xb2, 0xfc, 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, + 0x57, 0xc3, 0x64, 0x7f, 0x09, 0x99, 0x87, 0xf8, 0x13, 0x56, 0x0d, 0xbb, 0xe5, + 0x1d, 0xec, 0x1c, 0x72, 0xd5, 0x92, 0xc5, 0xa9, 0x79, 0x1a, 0xb3, 0xfc, 0x07, + 0xed, 0x44, 0x0f, 0x7f, 0x67, 0x4b, 0xee, 0x81, 0xd9, 0xd1, 0x2f, 0x7b, 0x81, + 0x81, 0xb8, 0xa1, 0x81, 0x7f, 0xc1, 0xf0, 0xc3, 0x7f, 0xc8, 0xc6, 0x63, 0x24, + 0x25, 0x26, 0x81, 0x9d, 0x4d, 0x81, 0x57, 0x81, 0xba, 0x12, 0xe7, 0x55, 0xed, + 0x95, 0x5c, 0x22, 0xe0, 0x14, 0x38, 0x33, 0xf9, 0x73, 0xf8, 0x19, 0xaf, 0xb6, + 0x7f, 0x76, 0xa7, 0xd2, 0xca, 0xb2, 0x98, 0xad, 0x40, 0x23, 0x56, 0xdd, 0x59, + 0xd4, 0x23, 0x50, 0xf4, 0xf0, 0xcd, 0x40, 0x56, 0xb8, 0x81, 0xc0, 0x94, 0xd0, + 0xca, 0xb9, 0x2f, 0xf3, 0xf1, 0x0a, 0x3a, 0x7f, 0xbe, 0x6e, 0x7f, 0x73, 0xda, + 0x81, 0x58, 0x87, 0x49, 0x9f, 0xd5, 0x7f, 0x09, 0x5f, 0x1b, 0x16, 0x3e, 0xc1, + 0xb0, 0x26, 0xd9, 0x0c, 0x8c, 0x00, 0xde, 0x25, 0x2e, 0xe7, 0xb7, 0x7f, 0xd7, + 0x65, 0xef, 0x0f, 0x81, 0x8b, 0x9a, 0xf4, 0x5b, 0x0c, 0xd1, 0xaf, 0xdc, 0x05, + 0x10, 0xf8, 0xbf, 0x7d, 0xd9, 0xc6, 0xe2, 0xe2, 0xe5, 0x7f, 0xe3, 0x0d, 0xab, + 0x99, 0x28, 0x22, 0xce, 0x4c, 0xdf, 0x63, 0x0f, 0x9d, 0x7f, 0x7f, 0x19, 0x31, + 0xe7, 0xd4, 0x7f, 0xc5, 0x29, 0x88, 0xe5, 0x06, 0xd2, 0x4e, 0xc7, 0x3b, 0x2b, + 0xf5, 0x7f, 0xd6, 0x2d, 0x02, 0x8c, 0x50, 0xdc, 0xa3, 0xb2, 0x99, 0x32, 0x7f, + 0x56, 0xc7, 0x2a, 0x36, 0xcb, 0xfa, 0xba, 0x40, 0x3e, 0x05, 0x7f, 0xdc, 0x29, + 0x2c, 0xec, 0xfb, 0xc9, 0x7f, 0x08, 0x4a, 0x04, 0xdc, 0xa1, 0x50, 0xdb, 0xe7, + 0xf8, 0x91, 0xe9, 0xfc, 0x67, 0x3b, 0x99, 0x32, 0x69, 0x10, 0xeb, 0x17, 0xa6, + 0xae, 0xf2, 0x78, 0xf3, 0x5d, 0x08, 0x72, 0x35, 0x09, 0x16, 0x83, 0xa1, 0x41, + 0x44, 0x34, 0x55, 0x28, 0x23, 0xd8, 0x44, 0xb6, 0x2b, 0x65, 0xe3, 0xcd, 0x7f, + 0xeb, 0xf3, 0x25, 0xb2, 0x81, 0x7f, 0x15, 0xb4, 0xae, 0x9a, 0x1a, 0x0d, 0xca, + 0x81, 0x1f, 0x81, 0xb7, 0xf8, 0xb6, 0x78, 0x27, 0xa7, 0xab, 0xab, 0xae, 0xdc, + 0xfe, 0xaa, 0x1b, 0x34, 0xf9, 0x38, 0x97, 0x2c, 0x14, 0x37, 0x3e, 0xb8, 0x9a, + 0x4c, 0xc0, 0x7f, 0xdf, 0x9d, 0xca, 0x1d, 0x8f, 0xdd, 0x7f, 0x7f, 0x1a, 0xf2, + 0xef, 0x7f, 0x7f, 0xca, 0x4b, 0xea, 0xd7, 0xb1, 0xfd, 0x61, 0x74, 0x1c, 0xa6, + 0x7f, 0x1b, 0x81, 0x7f, 0xe4, 0x07, 0x7f, 0xee, 0x40, 0xbd, 0x28, 0xf4, 0xe2, + 0x7f, 0xcc, 0x64, 0x2f, 0xf3, 0x92, 0x9b, 0x8c, 0xf5, 0xa0, 0xdc, 0x0d, 0xc2, + 0x03, 0x22, 0x4f, 0x47, 0xbc, 0x17, 0x1d, 0x2e, 0xd5, 0x3a, 0xbd, 0xbd, 0x22, + 0x72, 0xf8, 0x25, 0xfe, 0x7e, 0x7f, 0x04, 0x10, 0xe0, 0x7f, 0x10, 0x46, 0xf1, + 0xad, 0x46, 0x7f, 0x35, 0xff, 0xde, 0xe7, 0xcf, 0xf5, 0x7f, 0x55, 0xf0, 0xbc, + 0xc2, 0xda, 0x7b, 0x51, 0x34, 0x0c, 0xb0, 0x1c, 0x0e, 0x08, 0x26, 0x79, 0x35, + 0x8b, 0x35, 0x0d, 0xe2, 0x6d, 0x14, 0x28, 0x81, 0xa9, 0x81, 0x41, 0x26, 0xf1, + 0x3a, 0xa9, 0x55, 0x81, 0x8f, 0xcc, 0x5f, 0x7f, 0x7f, 0xd2, 0x13, 0xd9, 0xbc, + 0x00, 0x86, 0xc6, 0x7f, 0x25, 0xf6, 0x9b, 0xc2, 0x43, 0x7f, 0xf2, 0x1f, 0x23, + 0x37, 0x53, 0x3f, 0x3e, 0x1a, 0xbb, 0x08, 0x61, 0xdc, 0xf9, 0x9a, 0x22, 0xcf, + 0x9d, 0x2d, 0x7f, 0x35, 0xac, 0xe8, 0xf6, 0x9b, 0x7f, 0x03, 0xdc, 0xe5, 0xfa, + 0xfe, 0x7f, 0x96, 0xc0, 0x81, 0xbf, 0x39, 0xae, 0x4b, 0x29, 0x3d, 0x1e, 0xf0, + 0xaf, 0xe6, 0xc3, 0x7f, 0x8f, 0x22, 0xf3, 0x92, 0x7f, 0xaf, 0x79, 0x83, 0x22, + 0x27, 0x20, 0x7f, 0xb1, 0xdb, 0x54, 0x1b, 0x0a, 0xd2, 0x7f, 0x7f, 0xd1, 0x22, + 0xff, 0x21, 0x29, 0xf1, 0xc6, 0x20, 0x3d, 0x7a, 0xc1, 0xd2, 0xb7, 0xca, 0x7f, + 0x14, 0x2b, 0x7f, 0xf7, 0xa8, 0x4c, 0x1f, 0x08, 0x08, 0x5d, 0x7f, 0xbd, 0x31, + 0x02, 0x32, 0xf6, 0xbf, 0xa5, 0x90, 0x7f, 0x11, 0x9e, 0xf6, 0x28, 0x2d, 0x3d, + 0xfe, 0xda, 0x31, 0x2f, 0x01, 0x15, 0x0b, 0xcc, 0x26, 0x54, 0xb2, 0xf5, 0xd8, + 0x9d, 0x3b, 0xfd, 0x81, 0xca, 0x28, 0x69, 0xef, 0x52, 0x41, 0xd3, 0xec, 0x23, + 0x7f, 0x30, 0x53, 0x81, 0x3d, 0x23, 0xe0, 0x7f, 0xc2, 0xe7, 0x54, 0x68, 0x2a, + 0xd2, 0x11, 0x1e, 0xcf, 0xe0, 0xcd, 0x38, 0x7f, 0x7f, 0x37, 0x7f, 0xf1, 0x75, + 0x57, 0xf9, 0x0c, 0xf3, 0x17, 0xfa, 0x6a, 0x22, 0x11, 0x7f, 0xe2, 0x08, 0x36, + 0x14, 0x5f, 0xbb, 0x0e, 0xf7, 0x78, 0x59, 0x33, 0x78, 0x6c, 0xf9, 0x64, 0x0e, + 0x02, 0xc2, 0x02, 0x7f, 0xe7, 0x82, 0x1f, 0x31, 0x2e, 0x7f, 0x7f, 0x69, 0x16, + 0x7f, 0x20, 0xb3, 0x02, 0x3c, 0xeb, 0x5c, 0xd3, 0x07, 0x81, 0x54, 0x9a, 0x20, + 0xd1, 0xa8, 0x81, 0xdf, 0x33, 0x09, 0xc5, 0xf5, 0x7c, 0xe9, 0xf7, 0x18, 0x13, + 0x7f, 0xf0, 0xd8, 0xcf, 0xc8, 0xcf, 0xcb, 0xf4, 0xd1, 0x1c, 0x35, 0xc9, 0x26, + 0xba, 0xae, 0x3f, 0x31, 0x45, 0xf2, 0x26, 0xf6, 0xca, 0x10, 0xca, 0x94, 0x03, + 0x22, 0xd3, 0x81, 0x29, 0x4b, 0x73, 0x65, 0xea, 0x26, 0x3b, 0x42, 0x78, 0x29, + 0x0f, 0xc6, 0x1e, 0x5c, 0x85, 0x39, 0x81, 0x05, 0x7f, 0x89, 0x28, 0x52, 0x2c, + 0xda, 0x18, 0xdc, 0x1a, 0x43, 0x07, 0x29, 0x5a, 0xee, 0xf4, 0x14, 0x7f, 0xed, + 0xff, 0xbf, 0xe7, 0xa2, 0x3e, 0x7f, 0xb6, 0x1a, 0xf8, 0x2d, 0xfc, 0x97, 0xd9, + 0x12, 0x3f, 0x63, 0xff, 0x2e, 0x81, 0x2b, 0x39, 0x43, 0xf5, 0xfa, 0x77, 0x44, + 0x4e, 0x12, 0x7f, 0x3c, 0x74, 0x15, 0xb7, 0xd2, 0x3a, 0x4a, 0x72, 0xf4, 0x04, + 0x81, 0xad, 0xd9, 0x5a, 0xd8, 0x7f, 0xc2, 0x95, 0xeb, 0x2d, 0xde, 0x52, 0x7f, + 0xe8, 0xa0, 0x01, 0x0e, 0x1c, 0x39, 0x57, 0x01, 0x49, 0x7f, 0xf0, 0xfc, 0x24, + 0x24, 0xfe, 0xe6, 0x8b, 0xd0, 0x02, 0xba, 0x60, 0x10, 0x23, 0xc0, 0xac, 0xa5, + 0xa5, 0x2e, 0x1d, 0x8a, 0x7f, 0xfb, 0xca, 0xf9, 0xe7, 0xec, 0x29, 0x12, 0x94, + 0xab, 0xb6, 0x39, 0x3f, 0xe2, 0x7f, 0xf4, 0x24, 0x48, 0x51, 0x7f, 0x6f, 0x9c, + 0x3a, 0x33, 0xc8, 0x03, 0xe3, 0xb0, 0xf5, 0xad, 0x1d, 0x4b, 0xec, 0xd6, 0x01, + 0xc0, 0x7f, 0xb0, 0x3e, 0xe6, 0xf0, 0xe6, 0x97, 0x7c, 0x8b, 0xb7, 0x1a, 0x81, + 0x37, 0x81, 0x29, 0x33, 0x33, 0xc0, 0x7f, 0x81, 0x96, 0x81, 0xc3, 0x92, 0x62, + 0x30, 0xba, 0xb1, 0xc6, 0x6f, 0xc9, 0x32, 0xc1, 0x7f, 0x0e, 0xe6, 0x25, 0xde, + 0x4c, 0xc8, 0xff, 0x16, 0x37, 0xd7, 0xe8, 0xf3, 0x7f, 0xfc, 0x3a, 0xf3, 0xe2, + 0x81, 0xff, 0xd4, 0x5f, 0xaf, 0xea, 0xe4, 0xe8, 0x52, 0x60, 0x1c, 0x9c, 0x81, + 0x30, 0x7f, 0xaa, 0xa5, 0xb4, 0x54, 0x1f, 0x5b, 0x7f, 0x1c, 0x0f, 0xfc, 0xab, + 0x9e, 0xb0, 0xc6, 0xc9, 0x81, 0x7f, 0x20, 0x8d, 0xd4, 0xa1, 0x93, 0xb2, 0xe9, + 0xf9, 0xe5, 0x34, 0x5a, 0x86, 0xaa, 0x8a, 0x81, 0x2d, 0x03, 0xc6, 0xc0, 0x26, + 0x0e, 0xd4, 0xe3, 0x4f, 0xf3, 0x4c, 0x60, 0xd2, 0x61, 0x1c, 0x1e, 0x7f, 0xdc, + 0xba, 0x25, 0xcb, 0x9a, 0x50, 0xbd, 0x7f, 0xaa, 0x81, 0xc1, 0xeb, 0xb9, 0x52, + 0xe5, 0x1d, 0xff, 0xdd, 0xba, 0xdc, 0x18, 0x5e, 0xd1, 0x9f, 0xac, 0x7f, 0xe9, + 0x7f, 0xf3, 0x7f, 0x2d, 0x7e, 0xed, 0xb5, 0x15, 0xda, 0x9d, 0x23, 0x56, 0x6b, + 0xa2, 0xcc, 0x2f, 0x81, 0x36, 0xb8, 0x07, 0x45, 0xaf, 0x01, 0x0d, 0x73, 0x2f, + 0x45, 0xf3, 0x19, 0xd8, 0x21, 0x4f, 0x31, 0xe4, 0x7f, 0xdb, 0xb9, 0xdf, 0xa5, + 0x0c, 0x10, 0xad, 0xa0, 0x5c, 0xd0, 0x6d, 0xc1, 0xe9, 0x20, 0xa4, 0x7f, 0x35, + 0xfe, 0xc3, 0x23, 0x7e, 0x43, 0x42, 0x13, 0x07, 0x21, 0xcc, 0x15, 0xac, 0x8e, + 0xca, 0xcc, 0x47, 0x5c, 0x7f, 0xc7, 0x2f, 0x81, 0x09, 0x37, 0xda, 0xee, 0x96, + 0x4a, 0x03, 0x93, 0xcf, 0xc4, 0xd7, 0xe2, 0x7f, 0xca, 0xba, 0x2d, 0x1a, 0xf6, + 0x1c, 0xec, 0xf7, 0xc9, 0x7f, 0x40, 0x48, 0x7f, 0x97, 0x74, 0x43, 0xda, 0x74, + 0x14, 0xe1, 0x3e, 0x96, 0x32, 0x25, 0xd9, 0x21, 0x7f, 0xba, 0x53, 0xd3, 0x76, + 0xd2, 0x14, 0xc2, 0xa9, 0xd5, 0x2c, 0xa3, 0x9d, 0x9e, 0x45, 0x87, 0x14, 0x0a, + 0xae, 0xdc, 0x1a, 0x1c, 0xe1, 0xbb, 0xc1, 0x83, 0x7f, 0x7f, 0xe6, 0xba, 0xcd, + 0x7f, 0x4b, 0x7f, 0xcc, 0x49, 0xd8, 0x36, 0x7f, 0x8e, 0xb6, 0xfc, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x81, 0xd9, 0xb1, 0x81, 0x51, 0x0d, + 0x56, 0x42, 0xa4, 0x72, 0xe6, 0xd3, 0x0e, 0x5e, 0xae, 0x23, 0xd1, 0x7f, 0x4a, + 0xe6, 0x0b, 0x0f, 0x24, 0xb8, 0x60, 0x38, 0xf1, 0x3c, 0xf2, 0xeb, 0xed, 0xf8, + 0xe3, 0x37, 0xd9, 0x14, 0x40, 0x35, 0xa9, 0x1c, 0x98, 0x2c, 0x7f, 0x7f, 0xbe, + 0x27, 0x22, 0x37, 0xe3, 0xdd, 0x54, 0xce, 0x9d, 0x11, 0xf6, 0xf4, 0x2b, 0xf3, + 0x40, 0x6d, 0x0b, 0xf5, 0x7f, 0xab, 0xac, 0x0b, 0xaf, 0x81, 0xf5, 0x6e, 0xf4, + 0xd1, 0xd0, 0x81, 0xdb, 0x44, 0x91, 0x99, 0x27, 0xbc, 0x46, 0xa7, 0xd6, 0x20, + 0x0c, 0xa1, 0x81, 0x2e, 0xba, 0xda, 0xc8, 0x2b, 0xd6, 0xa1, 0xdd, 0x15, 0x12, + 0xdf, 0x26, 0x4d, 0xe2, 0xe8, 0xeb, 0xe7, 0x08, 0xd4, 0xb5, 0xd2, 0xa0, 0x7f, + 0xb0, 0x4b, 0xe0, 0x95, 0xb9, 0xc3, 0xb6, 0xcf, 0xc3, 0xc5, 0xad, 0xeb, 0x12, + 0xd4, 0x2f, 0x0a, 0xb1, 0x5e, 0x5d, 0x7f, 0x1e, 0xbb, 0x49, 0xc0, 0x10, 0x7f, + 0xea, 0x8a, 0xa7, 0x4b, 0x47, 0x7f, 0x40, 0x7f, 0xa5, 0x46, 0xf6, 0xda, 0x27, + 0x2f, 0x3a, 0xdc, 0xb6, 0x7f, 0x59, 0x6e, 0xf0, 0x1b, 0x2b, 0x76, 0x1b, 0x72, + 0x8f, 0x77, 0x7f, 0xf3, 0xeb, 0x06, 0xb2, 0xdc, 0x22, 0x38, 0x40, 0x5e, 0x59, + 0x1e, 0x49, 0x6d, 0xe0, 0xe8, 0x09, 0x7f, 0x34, 0x7f, 0x7f, 0x3f, 0x52, 0x34, + 0x7f, 0x99, 0x39, 0xf0, 0xd0, 0x2b, 0xb6, 0x96, 0x87, 0x62, 0xd9, 0x91, 0x93, + 0x8a, 0x3d, 0x0a, 0x8b, 0xf9, 0x97, 0x7f, 0x7f, 0xb0, 0x04, 0x72, 0x4d, 0xb1, + 0x22, 0x7f, 0xae, 0x34, 0xf1, 0x3a, 0xd1, 0x81, 0xac, 0xa0, 0x27, 0x7f, 0x26, + 0x7f, 0xa1, 0xc0, 0xa7, 0x7f, 0x81, 0xc8, 0x81, 0x18, 0xad, 0xdc, 0x9d, 0x0c, + 0x51, 0xd5, 0xb4, 0xf0, 0xb0, 0xdf, 0x16, 0xf0, 0x87, 0x92, 0xf3, 0x1a, 0x7f, + 0x8c, 0x83, 0x55, 0x7c, 0x43, 0xe8, 0x9d, 0x07, 0xf3, 0x7f, 0x24, 0x81, 0xbb, + 0x19, 0x20, 0x2a, 0x1a, 0xa2, 0x61, 0xcb, 0xa2, 0x24, 0xde, 0xc2, 0x39, 0x16, + 0xa4, 0xa6, 0x57, 0xfe, 0x61, 0xd6, 0x46, 0xf0, 0xec, 0x7f, 0x24, 0xcf, 0xe1, + 0x4c, 0xe6, 0x0f, 0xfb, 0xeb, 0xc2, 0x60, 0x7c, 0x53, 0x55, 0xcd, 0x7f, 0xd9, + 0x06, 0xe5, 0xd4, 0xde, 0x1b, 0x0e, 0x38, 0x35, 0x22, 0x27, 0x17, 0x19, 0x29, + 0x59, 0xe0, 0xce, 0xf3, 0x81, 0x9f, 0xd6, 0x74, 0xf2, 0x65, 0xe4, 0x9a, 0x7f, + 0xd5, 0xd1, 0xc3, 0xb8, 0xe2, 0x50, 0x9e, 0x4b, 0x35, 0xfb, 0xab, 0x46, 0x0b, + 0xd1, 0xdc, 0xdb, 0x22, 0xc6, 0xbf, 0xce, 0xe7, 0x08, 0x51, 0xfa, 0xcf, 0x9a, + 0x99, 0xad, 0x30, 0x9c, 0xa9, 0x8b, 0xef, 0x9e, 0xec, 0x98, 0x7f, 0x7f, 0xd5, + 0x7f, 0x35, 0xb1, 0xdb, 0x22, 0xba, 0xe9, 0xc2, 0xf2, 0xdf, 0x89, 0x24, 0xe7, + 0x23, 0xfb, 0xdd, 0x23, 0xd3, 0x12, 0x94, 0x2a, 0x13, 0xd8, 0x8f, 0x81, 0xc8, + 0x3d, 0xca, 0xbc, 0x55, 0xd4, 0x71, 0xe2, 0xc3, 0x01, 0x34, 0xb2, 0xf4, 0x5c, + 0xa8, 0x13, 0xe8, 0x7c, 0x97, 0xe9, 0xeb, 0x9c, 0x7f, 0xb1, 0x32, 0x2b, 0x7f, + 0xcb, 0x1b, 0xb0, 0x7f, 0x24, 0x33, 0x49, 0x7f, 0x34, 0xe3, 0x13, 0xb8, 0x61, + 0xb8, 0x7f, 0x3a, 0x37, 0xd1, 0x27, 0x65, 0xeb, 0x0f, 0x0c, 0xc7, 0x5e, 0x6b, + 0xc6, 0x22, 0x03, 0x8a, 0xf3, 0x81, 0xc6, 0xeb, 0x14, 0xd7, 0x14, 0xf7, 0xb3, + 0xd3, 0x51, 0x0e, 0x41, 0x92, 0x03, 0x7f, 0x45, 0xd8, 0x8d, 0xe6, 0x18, 0x07, + 0x00, 0x69, 0xd1, 0x98, 0xa1, 0x8d, 0x23, 0xd1, 0xe7, 0x2e, 0xe3, 0x72, 0xe0, + 0xf2, 0xdf, 0x93, 0x21, 0xf6, 0xf6, 0x2d, 0x81, 0xf7, 0xe2, 0xfd, 0xa8, 0x14, + 0xad, 0xa6, 0x94, 0x99, 0xcc, 0xcd, 0x7f, 0xfe, 0x35, 0x89, 0x8e, 0x2b, 0x4c, + 0x2e, 0xdf, 0xb3, 0x36, 0x81, 0xbc, 0x32, 0xa4, 0x81, 0xa6, 0x7f, 0x47, 0x43, + 0x8e, 0x68, 0x7f, 0x26, 0x7f, 0xbb, 0x7f, 0x7f, 0xa1, 0xcb, 0x0f, 0x17, 0x7f, + 0x77, 0x4f, 0x57, 0xb2, 0xef, 0x0a, 0x28, 0xb6, 0x2f, 0x19, 0xf7, 0x89, 0x23, + 0xbd, 0xdc, 0x10, 0x26, 0x7f, 0x3e, 0x7f, 0x07, 0x7f, 0x47, 0x9b, 0x81, 0x68, + 0x1f, 0x7f, 0x10, 0x2f, 0x7f, 0x7f, 0xfc, 0x58, 0x81, 0xfa, 0x7f, 0xb6, 0x7f, + 0xcb, 0x8e, 0x40, 0xcb, 0x67, 0xd9, 0x7f, 0x9d, 0xfe, 0xbf, 0xd8, 0xa6, 0x7f, + 0x3e, 0x5f, 0xd2, 0xaf, 0x00, 0x7f, 0x81, 0xd6, 0x18, 0x07, 0x52, 0x2b, 0x79, + 0xeb, 0xaf, 0xcd, 0xb0, 0x4d, 0x4b, 0x4a, 0x6d, 0xe6, 0x7f, 0xaf, 0x5e, 0x9c, + 0xc6, 0x46, 0x38, 0x18, 0xd2, 0xc0, 0xff, 0x4a, 0xf3, 0xb7, 0xe1, 0xe5, 0x81, + 0x7f, 0xb4, 0xbb, 0x7f, 0x7f, 0x7f, 0xdc, 0x81, 0xdb, 0x4f, 0x3b, 0x09, 0x02, + 0xc1, 0x19, 0xfb, 0xff, 0x23, 0xdc, 0xa5, 0x00, 0x52, 0x7f, 0xfe, 0x9d, 0x4d, + 0xe9, 0xed, 0xe5, 0xd5, 0x05, 0x37, 0xd5, 0xeb, 0xdd, 0xe9, 0x22, 0x7f, 0x04, + 0x7f, 0xc5, 0x7f, 0x68, 0x5c, 0x81, 0xc8, 0x27, 0x29, 0x8f, 0xe8, 0x81, 0xa3, + 0x03, 0x35, 0x40, 0x61, 0x26, 0x0a, 0x4d, 0xcd, 0xf6, 0xac, 0x07, 0x0d, 0xf8, + 0x72, 0x03, 0x17, 0x34, 0x14, 0x01, 0xb7, 0x3c, 0xa9, 0xd4, 0x0b, 0xcd, 0xb3, + 0xfa, 0x86, 0x40, 0x7f, 0x16, 0x8b, 0x4f, 0x98, 0x42, 0xc0, 0x37, 0x03, 0xc4, + 0xc4, 0x94, 0x43, 0x02, 0xd2, 0x23, 0xf9, 0xf3, 0xde, 0xd1, 0x7f, 0xe8, 0x8b, + 0x81, 0x81, 0x05, 0x0a, 0x5b, 0x0c, 0x81, 0x43, 0xf7, 0x3c, 0x9a, 0xcc, 0x5b, + 0xfd, 0xf6, 0xc7, 0x98, 0x0b, 0x0e, 0xf0, 0x58, 0x77, 0x81, 0x98, 0xff, 0xa0, + 0xb4, 0x2d, 0x7a, 0xdd, 0xaf, 0xa5, 0x78, 0x2e, 0x7d, 0xc6, 0x7f, 0xb3, 0x22, + 0x43, 0xc3, 0x09, 0xb6, 0x8b, 0xe9, 0xe9, 0x37, 0x5d, 0x81, 0xcc, 0xde, 0x94, + 0xcb, 0x9c, 0x1f, 0xd8, 0xac, 0x81, 0x6e, 0xb3, 0xb5, 0xc7, 0x4e, 0xb3, 0x40, + 0x0e, 0xf2, 0xe9, 0x82, 0x16, 0xe8, 0x4b, 0x81, 0x7f, 0xdc, 0x40, 0xd4, 0xfb, + 0x7c, 0xbe, 0xeb, 0xec, 0x48, 0xe8, 0x7f, 0xaa, 0x3b, 0x2c, 0x1d, 0xbd, 0xc5, + 0xc1, 0xc4, 0x7f, 0xec, 0xfe, 0xda, 0x33, 0x81, 0x0f, 0x8c, 0xe7, 0x07, 0x13, + 0xb6, 0xf6, 0x33, 0x3b, 0x36, 0x81, 0xc5, 0x81, 0xf9, 0xf7, 0xcf, 0xb8, 0x07, + 0x1b, 0x25, 0x8c, 0xeb, 0x0a, 0x61, 0x24, 0xe7, 0xe5, 0x64, 0xd8, 0x8c, 0xb5, + 0x89, 0xad, 0x14, 0xa5, 0xa7, 0x5f, 0x9f, 0xec, 0x9d, 0xdb, 0x1f, 0xeb, 0x38, + 0x12, 0x50, 0x04, 0x05, 0x7f, 0xd5, 0x0d, 0xdf, 0xaf, 0x07, 0xaa, 0x88, 0xe9, + 0x22, 0x03, 0x42, 0xbb, 0x81, 0xb6, 0x5f, 0xb5, 0x74, 0x92, 0x7f, 0x4b, 0x89, + 0xe2, 0x95, 0x9e, 0x85, 0xfd, 0x11, 0x32, 0xb3, 0x58, 0x2e, 0xe0, 0xc8, 0xa2, + 0x1a, 0x6f, 0x81, 0x97, 0x7f, 0x97, 0xc6, 0x28, 0x41, 0x5a, 0x7f, 0xdc, 0xec, + 0x98, 0xba, 0x7f, 0x00, 0x1b, 0xa0, 0x6e, 0xc7, 0xc6, 0xd2, 0x1c, 0x33, 0xcf, + 0x3b, 0xe3, 0x5b, 0x68, 0x04, 0xb6, 0x39, 0x4d, 0x3d, 0xb0, 0x8c, 0x51, 0x26, + 0x5e, 0xd6, 0x9d, 0xeb, 0x1a, 0x05, 0xf7, 0xbe, 0xc8, 0x7f, 0x67, 0x7f, 0xc1, + 0x70, 0x3d, 0xf9, 0xb8, 0x6e, 0xbc, 0x37, 0xd4, 0xf9, 0xe2, 0x7f, 0x23, 0x33, + 0xe7, 0x9a, 0xf9, 0x7f, 0x7f, 0x7f, 0x61, 0x7f, 0xa7, 0xc2, 0xcc, 0x81, 0x01, + 0x7f, 0xd7, 0xa5, 0x6a, 0x81, 0xca, 0x88, 0x81, 0x4d, 0x59, 0x75, 0xb6, 0xc3, + 0xfd, 0x0c, 0x17, 0xcc, 0x7f, 0xab, 0xb6, 0x01, 0x89, 0x09, 0x22, 0x70, 0xf5, + 0xc1, 0xba, 0xf8, 0xfb, 0xd6, 0xfc, 0x65, 0x8c, 0x32, 0x63, 0xfd, 0xf1, 0xce, + 0x15, 0xbe, 0x13, 0x25, 0x73, 0xa2, 0xbf, 0xe6, 0xbe, 0xbb, 0x81, 0x2c, 0x53, + 0xe7, 0xa1, 0x48, 0x8d, 0xeb, 0xf5, 0x7f, 0x05, 0x13, 0x2f, 0x23, 0x02, 0xbd, + 0xf1, 0xff, 0xf5, 0xec, 0x4c, 0xd4, 0xe9, 0xca, 0xd4, 0x30, 0xf1, 0xb0, 0xe9, + 0x29, 0x7f, 0x42, 0x02, 0x30, 0x5b, 0x61, 0xa1, 0xed, 0x32, 0x31, 0x33, 0x0d, + 0x00, 0xda, 0xae, 0x91, 0x1f, 0x8e, 0x01, 0x2e, 0x46, 0x55, 0x36, 0x1c, 0x17, + 0x1e, 0xe2, 0x7f, 0xa1, 0x0f, 0xff, 0x6d, 0x81, 0x19, 0x28, 0xf6, 0xb1, 0xe9, + 0x0b, 0xb0, 0x4c, 0xb7, 0xa9, 0x3b, 0xe7, 0x84, 0x98, 0xc7, 0x26, 0xda, 0xa6, + 0x95, 0x27, 0xb7, 0x07, 0x20, 0xde, 0x4a, 0x7f, 0x7f, 0xcc, 0xf6, 0x01, 0x32, + 0xea, 0x31, 0x74, 0x93, 0x9e, 0xf0, 0x81, 0x81, 0xee, 0xf6, 0xfe, 0xae, 0xd6, + 0x55, 0x81, 0x1a, 0xbb, 0xfc, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0xcc, 0x1b, 0x00, 0x00, 0x82, 0x1f, 0x00, 0x00, 0xeb, 0x2d, 0x00, 0x00, + 0x9a, 0x2d, 0x00, 0x00, 0xff, 0x26, 0x00, 0x00, 0x2f, 0x35, 0x00, 0x00, 0x95, + 0xd4, 0xff, 0xff, 0xef, 0x14, 0x00, 0x00, 0xf3, 0x2f, 0x00, 0x00, 0xad, 0xe7, + 0xff, 0xff, 0x14, 0xd3, 0xff, 0xff, 0xcf, 0x0b, 0x00, 0x00, 0xb5, 0x19, 0x00, + 0x00, 0x22, 0x01, 0x00, 0x00, 0x2c, 0x18, 0x00, 0x00, 0xe6, 0xea, 0xff, 0xff, + 0xbf, 0x0a, 0x00, 0x00, 0x03, 0x0e, 0x00, 0x00, 0x15, 0xcc, 0xff, 0xff, 0xf9, + 0xf0, 0xff, 0xff, 0xfc, 0xea, 0xff, 0xff, 0x04, 0xe3, 0xff, 0xff, 0x68, 0x9d, + 0xff, 0xff, 0x8a, 0xdd, 0xff, 0xff, 0x7f, 0x15, 0x00, 0x00, 0x14, 0xee, 0xff, + 0xff, 0x7e, 0x12, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0xe3, 0x42, 0x00, 0x00, + 0xb2, 0xee, 0xff, 0xff, 0x2a, 0xed, 0xff, 0xff, 0x67, 0x1a, 0x00, 0x00, 0xbf, + 0xff, 0xff, 0xff, 0xdd, 0x3a, 0x00, 0x00, 0xff, 0xc9, 0xff, 0xff, 0x0a, 0xf7, + 0xff, 0xff, 0x89, 0xdb, 0xff, 0xff, 0x97, 0xf0, 0xff, 0xff, 0x30, 0x16, 0x00, + 0x00, 0x15, 0xfd, 0xff, 0xff, 0x52, 0x18, 0x00, 0x00, 0xbb, 0xf5, 0xff, 0xff, + 0xf4, 0xff, 0xff, 0xff, 0xb8, 0x23, 0x00, 0x00, 0x58, 0x2d, 0x00, 0x00, 0xc3, + 0xfe, 0xff, 0xff, 0xe7, 0x34, 0x00, 0x00, 0x8d, 0xcf, 0xff, 0xff, 0x3c, 0x34, + 0x00, 0x00, 0x21, 0x52, 0x00, 0x00, 0x98, 0x26, 0x00, 0x00, 0xc3, 0xef, 0xff, + 0xff, 0x40, 0xf3, 0xff, 0xff, 0xd8, 0x1f, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, + 0x6e, 0xf8, 0xff, 0xff, 0x67, 0x13, 0x00, 0x00, 0x53, 0x17, 0x00, 0x00, 0xcd, + 0xb2, 0xff, 0xff, 0xaf, 0xe6, 0xff, 0xff, 0x6a, 0x1d, 0x00, 0x00, 0xda, 0x27, + 0x00, 0x00, 0xf1, 0x1c, 0x00, 0x00, 0x99, 0x15, 0x00, 0x00, 0x40, 0x08, 0x00, + 0x00, 0x75, 0xd8, 0xff, 0xff, 0x19, 0xdf, 0xff, 0xff, 0x49, 0xfa, 0xff, 0xff, + 0xc0, 0x26, 0x00, 0x00, 0x61, 0x26, 0x00, 0x00, 0xa6, 0x41, 0x00, 0x00, 0x1b, + 0xf3, 0xff, 0xff, 0x64, 0x05, 0x00, 0x00, 0x38, 0x17, 0x00, 0x00, 0x80, 0x3e, + 0x00, 0x00, 0x7e, 0xe7, 0xff, 0xff, 0xd2, 0xd5, 0xff, 0xff, 0xd6, 0xcd, 0xff, + 0xff, 0xe7, 0xde, 0xff, 0xff, 0xad, 0xf9, 0xff, 0xff, 0xc2, 0xe6, 0xff, 0xff, + 0xaf, 0xe5, 0xff, 0xff, 0x35, 0x43, 0x00, 0x00, 0xc1, 0x02, 0x00, 0x00, 0xcf, + 0xfe, 0xff, 0xff, 0x29, 0x1d, 0x00, 0x00, 0x7c, 0xef, 0xff, 0xff, 0x37, 0x0e, + 0x00, 0x00, 0x81, 0x13, 0x00, 0x00, 0x15, 0x31, 0x00, 0x00, 0xb6, 0x26, 0x00, + 0x00, 0x2b, 0x21, 0x00, 0x00, 0x1b, 0xf9, 0xff, 0xff, 0x1d, 0x03, 0x00, 0x00, + 0x71, 0xfd, 0xff, 0xff, 0xf0, 0x1e, 0x00, 0x00, 0x33, 0x21, 0x00, 0x00, 0x03, + 0xfd, 0xff, 0xff, 0x1f, 0xe7, 0xff, 0xff, 0x92, 0xea, 0xff, 0xff, 0x33, 0x08, + 0x00, 0x00, 0x3e, 0xe2, 0xff, 0xff, 0x7e, 0xe2, 0xff, 0xff, 0xc3, 0x12, 0x00, + 0x00, 0x3b, 0xda, 0xff, 0xff, 0x81, 0xf0, 0xff, 0xff, 0x5f, 0x28, 0x00, 0x00, + 0x6f, 0x2c, 0x00, 0x00, 0x8e, 0xf4, 0xff, 0xff, 0xe4, 0xd7, 0xff, 0xff, 0xa7, + 0x23, 0x00, 0x00, 0xe5, 0xe8, 0xff, 0xff, 0xc9, 0xee, 0xff, 0xff, 0xdf, 0x15, + 0x00, 0x00, 0x10, 0x2e, 0x00, 0x00, 0xf9, 0x14, 0x00, 0x00, 0x99, 0xc5, 0xff, + 0xff, 0x47, 0x17, 0x00, 0x00, 0x25, 0x1e, 0x00, 0x00, 0x31, 0x40, 0x00, 0x00, + 0x01, 0xfd, 0xff, 0xff, 0x9e, 0x0c, 0x00, 0x00, 0x50, 0x20, 0x00, 0x00, 0xba, + 0x50, 0x00, 0x00, 0x3e, 0xf3, 0xff, 0xff, 0x5b, 0xfe, 0xff, 0xff, 0x16, 0xe2, + 0xff, 0xff, 0x45, 0xfc, 0xff, 0xff, 0x26, 0xbd, 0xfc, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x2f, 0xf6, 0xb9, 0xd7, 0x23, 0xf5, 0x3b, 0xe2, + 0x24, 0xbf, 0x2c, 0xf9, 0x38, 0x0f, 0x25, 0xc9, 0x00, 0x27, 0xe0, 0xd5, 0x10, + 0x9f, 0xf4, 0x11, 0xd1, 0x25, 0xf0, 0x28, 0x73, 0xc2, 0x11, 0xd8, 0xfc, 0x1f, + 0x3b, 0x1a, 0xed, 0x16, 0xf3, 0xcc, 0x01, 0xdd, 0xce, 0x45, 0x1d, 0xd9, 0x3a, + 0x3c, 0xfc, 0xa9, 0x3c, 0x31, 0xe4, 0xb8, 0xc3, 0x7f, 0xfd, 0x63, 0x00, 0x12, + 0xdf, 0xfd, 0x56, 0xe6, 0x38, 0xf7, 0x0d, 0x27, 0xee, 0xef, 0x1a, 0xe2, 0xc2, + 0xf7, 0x06, 0x01, 0xe1, 0xa3, 0x6a, 0x00, 0xc4, 0x02, 0x24, 0x34, 0xfc, 0xeb, + 0xd5, 0x10, 0xcf, 0xc8, 0x10, 0xeb, 0x49, 0xf9, 0x04, 0x14, 0xf7, 0xc7, 0xff, + 0x23, 0x4b, 0x3c, 0x4f, 0x0c, 0x21, 0x22, 0xb5, 0xf6, 0xd4, 0xd4, 0xde, 0x02, + 0xe6, 0x39, 0x16, 0xfe, 0x73, 0xb6, 0x04, 0x16, 0x12, 0xee, 0xf4, 0x66, 0xe3, + 0x00, 0x0c, 0xd6, 0xbf, 0x2e, 0xd9, 0x02, 0xd9, 0xc6, 0x35, 0x25, 0xdb, 0x3e, + 0x04, 0xc1, 0x17, 0xe5, 0x40, 0x9c, 0x0e, 0xf6, 0xc8, 0xa8, 0x00, 0x54, 0x4a, + 0x2d, 0xd2, 0xb7, 0xb5, 0xfe, 0xe2, 0x4c, 0x30, 0x34, 0xfe, 0xfc, 0x05, 0x32, + 0x46, 0x19, 0xca, 0xe6, 0x77, 0x17, 0x81, 0x62, 0xf0, 0xc7, 0x04, 0x4a, 0x51, + 0x18, 0x0f, 0x07, 0xa3, 0x1b, 0xe3, 0xc0, 0x63, 0x03, 0x01, 0x33, 0x14, 0x17, + 0x35, 0x2e, 0x78, 0x2f, 0x03, 0xdd, 0xf6, 0x53, 0x1c, 0x11, 0x59, 0x23, 0x14, + 0xdc, 0xd7, 0x04, 0xcb, 0x3c, 0x46, 0x0c, 0x2c, 0xa5, 0xf5, 0xf1, 0xef, 0xd8, + 0x4a, 0xcd, 0x3f, 0xb5, 0x37, 0x46, 0xef, 0x56, 0x07, 0x39, 0x19, 0xe7, 0x64, + 0xf1, 0x37, 0x28, 0xe5, 0x24, 0x18, 0x36, 0xe3, 0xc9, 0x64, 0x4c, 0x25, 0x76, + 0xd8, 0x00, 0xfd, 0x83, 0xfd, 0x4c, 0x0c, 0x3a, 0xe9, 0xc3, 0x17, 0x6c, 0xeb, + 0xe0, 0x48, 0x36, 0x07, 0xd7, 0xe2, 0x15, 0xd5, 0xf9, 0xff, 0x05, 0x0a, 0xee, + 0xae, 0x15, 0x09, 0x34, 0xb7, 0x0f, 0xc5, 0xbb, 0xf9, 0xca, 0xbe, 0x13, 0xa9, + 0xa8, 0xd5, 0x60, 0x81, 0xfb, 0x0c, 0x33, 0xf4, 0xd9, 0xf8, 0x31, 0xff, 0x23, + 0x13, 0x13, 0xda, 0x95, 0xfa, 0xe7, 0x4c, 0xc5, 0xe7, 0x5e, 0xf3, 0xc6, 0x1f, + 0x3e, 0xbd, 0x32, 0xe7, 0xe6, 0x35, 0xd5, 0x02, 0x42, 0x3d, 0x05, 0x08, 0xde, + 0xc0, 0x2d, 0x31, 0x94, 0xf4, 0x2c, 0x05, 0xd2, 0xf3, 0xd2, 0xf9, 0xc5, 0x13, + 0x63, 0x22, 0x1e, 0xfa, 0xea, 0x12, 0xc4, 0xb4, 0x22, 0xdf, 0xf0, 0xf9, 0x0d, + 0xfb, 0x35, 0xdd, 0xe9, 0xe4, 0xdb, 0x46, 0xe1, 0x91, 0x1b, 0x2b, 0x10, 0xc4, + 0xc6, 0x16, 0xff, 0xfe, 0xe2, 0x12, 0xfa, 0xbf, 0x18, 0x0d, 0xe0, 0xf1, 0xc6, + 0x1a, 0x49, 0x14, 0xf2, 0x04, 0xf3, 0xe1, 0x1a, 0xbd, 0x0e, 0x5b, 0xa7, 0x41, + 0x2a, 0xed, 0xf0, 0x00, 0x35, 0xe8, 0x1c, 0xe5, 0x2a, 0x35, 0x0b, 0x73, 0x23, + 0xe6, 0x00, 0x0d, 0xf8, 0x09, 0x1e, 0xe4, 0x26, 0x0e, 0x2b, 0xc3, 0x3e, 0x08, + 0x17, 0x15, 0xb7, 0xd5, 0xfe, 0xb7, 0xd1, 0x1a, 0x0e, 0xbd, 0x56, 0x13, 0xcd, + 0x2b, 0x19, 0x06, 0xca, 0xd2, 0x31, 0xcf, 0x0c, 0x3a, 0x0b, 0x19, 0x44, 0xe3, + 0x10, 0xe1, 0x15, 0x18, 0x00, 0x0c, 0x1c, 0x0d, 0xe9, 0x05, 0xdb, 0x3e, 0x40, + 0xeb, 0xb1, 0x08, 0x72, 0xe5, 0x31, 0x56, 0xd7, 0xde, 0xfb, 0x31, 0x00, 0x55, + 0x10, 0xc3, 0x12, 0xfa, 0xf1, 0x15, 0x7b, 0xef, 0xdd, 0x04, 0x20, 0xc7, 0x15, + 0x13, 0xf9, 0x35, 0x0b, 0xe8, 0x2a, 0xff, 0xf8, 0x7f, 0xdd, 0x47, 0xf7, 0xd1, + 0x19, 0x02, 0xfb, 0x02, 0x55, 0xd5, 0x15, 0xe5, 0x43, 0x21, 0xbf, 0x0b, 0xd8, + 0x14, 0x28, 0x0a, 0xd9, 0x12, 0x36, 0x40, 0xf4, 0xfc, 0x22, 0xf2, 0x25, 0x7f, + 0x06, 0x23, 0x01, 0x39, 0xfb, 0xeb, 0xfb, 0xff, 0xdd, 0x1f, 0xee, 0xcd, 0xd0, + 0x10, 0x07, 0xed, 0x17, 0x3e, 0x09, 0xdf, 0x1a, 0xfa, 0x07, 0x36, 0xd5, 0x31, + 0xdf, 0xf3, 0x06, 0xe7, 0x00, 0x1b, 0x10, 0x13, 0x01, 0xee, 0xf5, 0xdc, 0xe9, + 0xe6, 0x24, 0x13, 0x03, 0x00, 0x07, 0xde, 0xe7, 0xdc, 0x02, 0x32, 0xeb, 0xf7, + 0xcf, 0x06, 0xc1, 0xde, 0xba, 0xf4, 0x07, 0x2a, 0x06, 0xf2, 0xeb, 0xce, 0x1e, + 0xe7, 0xcf, 0xfa, 0x01, 0xce, 0xdb, 0x08, 0x24, 0x42, 0xe2, 0x1b, 0x0e, 0xd8, + 0xe8, 0xde, 0xeb, 0xa9, 0xe9, 0xe5, 0x1b, 0x33, 0xe7, 0xe7, 0xde, 0x30, 0x33, + 0x6f, 0xfd, 0xc5, 0x1c, 0xe7, 0x0a, 0xf3, 0xdb, 0xf0, 0x11, 0xf4, 0x07, 0x30, + 0xe8, 0x00, 0x04, 0xc8, 0x13, 0x3e, 0x0a, 0x52, 0x2a, 0xba, 0x31, 0x13, 0xee, + 0x1e, 0x07, 0x1e, 0x10, 0xe8, 0xe6, 0xf8, 0xe6, 0xd5, 0x2a, 0x06, 0x0b, 0xc5, + 0xdb, 0xff, 0x45, 0xf8, 0x0d, 0x25, 0x26, 0x1b, 0xe4, 0xc6, 0x1c, 0xe5, 0x07, + 0xfc, 0x12, 0x70, 0xfe, 0xd3, 0x1c, 0x00, 0xc5, 0xcf, 0xbd, 0x11, 0x01, 0x1e, + 0xe7, 0xe5, 0x25, 0x06, 0x02, 0xfc, 0xbc, 0x01, 0x4b, 0xc3, 0xe8, 0xf1, 0xa9, + 0x54, 0x1d, 0x03, 0x32, 0xaf, 0xd1, 0x0e, 0xdd, 0xf6, 0x37, 0xe9, 0x81, 0x0b, + 0x41, 0x29, 0x92, 0x0a, 0x56, 0x0d, 0xd2, 0xe0, 0x08, 0xfb, 0xf6, 0xa3, 0xf3, + 0x1f, 0xe6, 0xd9, 0xcb, 0x28, 0x4d, 0x34, 0x43, 0x75, 0xdd, 0x1f, 0x47, 0xf8, + 0xea, 0xfd, 0xd7, 0x0e, 0xf8, 0xd8, 0x09, 0xf8, 0x3c, 0x03, 0xee, 0x1c, 0xe1, + 0x2b, 0xdd, 0x06, 0xdc, 0x07, 0xc9, 0xc4, 0xc1, 0xe0, 0xca, 0x2c, 0xe3, 0x30, + 0xfc, 0x2e, 0xe6, 0xf3, 0xff, 0x0f, 0x78, 0x18, 0x60, 0x15, 0x06, 0xf5, 0xbf, + 0x01, 0x00, 0xf0, 0x39, 0x01, 0xfd, 0xcb, 0x03, 0xff, 0xbb, 0xca, 0x09, 0xe9, + 0xe7, 0x81, 0xf5, 0x28, 0xb2, 0x4d, 0x05, 0xc4, 0xe0, 0x27, 0x14, 0x02, 0x0e, + 0x30, 0xf4, 0xee, 0x13, 0xd4, 0x58, 0x0f, 0x07, 0x16, 0x13, 0x48, 0x05, 0x17, + 0xc1, 0x13, 0xf0, 0xdf, 0x00, 0xcd, 0xe6, 0xf3, 0x0c, 0x05, 0x00, 0x2c, 0x0d, + 0xfe, 0x0a, 0x25, 0x03, 0xf8, 0x09, 0xf9, 0x2d, 0x08, 0xf8, 0x00, 0xf4, 0x20, + 0x0c, 0xf3, 0x34, 0x16, 0x0e, 0xee, 0xe7, 0x0a, 0xce, 0xeb, 0x0d, 0xe6, 0xff, + 0x52, 0xe3, 0xdb, 0xff, 0x17, 0x9d, 0x32, 0xd5, 0xe2, 0x0e, 0xd3, 0xec, 0x2a, + 0x4d, 0xf8, 0xe7, 0x47, 0x12, 0x1e, 0x20, 0x01, 0xfe, 0x01, 0xdf, 0x1a, 0xf4, + 0xfe, 0xea, 0xfa, 0xbd, 0x24, 0x3c, 0x0a, 0x2b, 0xef, 0xe8, 0x31, 0x1c, 0xe8, + 0xf9, 0xec, 0xf6, 0x07, 0xf1, 0x1e, 0xdb, 0x0c, 0x35, 0x0f, 0x0b, 0xf6, 0x01, + 0x76, 0x22, 0x1a, 0xc8, 0x07, 0x0f, 0x07, 0xd7, 0x12, 0x1f, 0x1f, 0x04, 0xef, + 0xfa, 0xf7, 0x22, 0x1d, 0x3e, 0x1b, 0x98, 0x0e, 0x0b, 0xf8, 0x0e, 0x1a, 0x06, + 0xff, 0xf8, 0xbf, 0x3f, 0x0f, 0xd3, 0x49, 0xff, 0xdf, 0x7f, 0xd8, 0xcd, 0xe7, + 0x1d, 0xd8, 0x26, 0x2a, 0xdb, 0xed, 0x14, 0x5f, 0xe3, 0xdd, 0x20, 0xe8, 0x0d, + 0xfe, 0x45, 0xfc, 0x39, 0xf8, 0x07, 0xda, 0xfc, 0xff, 0xd9, 0xf0, 0x38, 0x1b, + 0xed, 0x08, 0xf6, 0x05, 0xfc, 0x23, 0xeb, 0xfc, 0x31, 0x19, 0xe3, 0x5c, 0x42, + 0x11, 0xa9, 0x58, 0xcd, 0x1e, 0x20, 0x16, 0xc5, 0x23, 0xe6, 0xf3, 0x06, 0xfd, + 0xea, 0x0a, 0x07, 0x29, 0xe9, 0xee, 0xc4, 0x1d, 0x0f, 0x30, 0x3f, 0xc9, 0x0f, + 0x18, 0xd6, 0x3d, 0x06, 0x0c, 0x10, 0xbf, 0xdd, 0xfa, 0xf6, 0xdd, 0x1f, 0x1a, + 0x0f, 0xd4, 0xe0, 0x2a, 0x26, 0x19, 0x36, 0x0e, 0xec, 0x07, 0xf5, 0x33, 0x28, + 0xc3, 0xae, 0x1e, 0xe5, 0xeb, 0x29, 0xfb, 0x11, 0xeb, 0x34, 0x06, 0x06, 0x1e, + 0x7f, 0x11, 0xfb, 0xe6, 0xf8, 0x0d, 0x0f, 0x34, 0x30, 0x10, 0xc0, 0x0f, 0xf0, + 0x22, 0x65, 0x29, 0xed, 0x1c, 0xbd, 0x21, 0x15, 0x09, 0xde, 0x1c, 0x20, 0xdc, + 0xff, 0x12, 0x22, 0x0b, 0x38, 0x34, 0xf4, 0xc6, 0x37, 0xff, 0x18, 0x49, 0x11, + 0x08, 0xc9, 0x24, 0x12, 0x11, 0x51, 0x09, 0x25, 0xfd, 0xff, 0xd6, 0xff, 0xde, + 0x1b, 0x2d, 0xcc, 0xef, 0xd6, 0xef, 0xfb, 0x18, 0x30, 0x05, 0x35, 0xf3, 0xe7, + 0x2e, 0xfd, 0x08, 0xee, 0x22, 0xda, 0x0e, 0x1e, 0x5c, 0x2a, 0xda, 0x09, 0x04, + 0x07, 0x2f, 0xdb, 0xfd, 0x31, 0xf6, 0x04, 0x24, 0x02, 0xea, 0x1b, 0xed, 0x4f, + 0xfd, 0xd3, 0x1a, 0xf6, 0xd4, 0x04, 0x0c, 0x38, 0x0d, 0xdf, 0xdb, 0x26, 0x04, + 0x26, 0xdb, 0x4c, 0x22, 0x1b, 0xfc, 0xda, 0x19, 0x09, 0x28, 0x17, 0x1f, 0x58, + 0xe5, 0xe1, 0xda, 0x7f, 0xdc, 0x04, 0x16, 0x1d, 0x5b, 0x0b, 0x0f, 0xea, 0xdd, + 0xe1, 0xbc, 0xfa, 0x0e, 0x1c, 0xf8, 0x11, 0x1c, 0xcb, 0x2c, 0xad, 0x3c, 0x23, + 0x06, 0x2d, 0x42, 0xbc, 0xfe, 0xf9, 0x06, 0x5e, 0xee, 0xe2, 0xe6, 0xce, 0x12, + 0x24, 0xec, 0x53, 0xd7, 0x17, 0xd7, 0xdb, 0xe0, 0x04, 0x43, 0xeb, 0x1a, 0xff, + 0x65, 0xd0, 0x00, 0x3c, 0x58, 0xe3, 0xc6, 0xbe, 0x24, 0xc9, 0xde, 0xe3, 0xfa, + 0x1a, 0x38, 0xe8, 0x0f, 0xd8, 0x33, 0xf7, 0x3f, 0x32, 0x19, 0xbe, 0x11, 0xf0, + 0x19, 0x0e, 0x15, 0xed, 0x23, 0xc8, 0x08, 0xc9, 0xec, 0x0b, 0x1a, 0xd1, 0xb9, + 0x15, 0xdf, 0x23, 0x1e, 0x11, 0xf1, 0xf7, 0x35, 0x23, 0x28, 0xff, 0xcf, 0xf6, + 0x2d, 0xc8, 0xeb, 0x2b, 0xd9, 0x45, 0xcf, 0x14, 0x33, 0x69, 0x0d, 0x16, 0xcb, + 0x25, 0x33, 0x40, 0x20, 0xbd, 0x26, 0x19, 0x2d, 0x2a, 0x0e, 0x20, 0xc7, 0xd4, + 0xda, 0x03, 0xd0, 0xfe, 0x13, 0xfa, 0xb9, 0xf2, 0x29, 0x1d, 0x25, 0x04, 0xe8, + 0xd0, 0xf4, 0x21, 0x1b, 0x20, 0x03, 0x60, 0xfc, 0x10, 0xee, 0x6a, 0xf8, 0xfd, + 0x2a, 0xe8, 0xf8, 0xef, 0xf6, 0xbe, 0x28, 0xf9, 0xec, 0xff, 0xd3, 0x0e, 0xca, + 0xf6, 0x00, 0xe2, 0xda, 0x5a, 0xe1, 0x08, 0x15, 0x65, 0xe9, 0xfc, 0x19, 0x19, + 0x20, 0xf2, 0xf6, 0xdf, 0xf6, 0x2a, 0x10, 0xfa, 0x0f, 0xee, 0x08, 0xef, 0x1e, + 0xf5, 0xd5, 0xec, 0x00, 0xf6, 0x2b, 0xcc, 0xea, 0xb5, 0x77, 0x81, 0xfc, 0xc1, + 0xdb, 0xe2, 0xfd, 0xcf, 0x66, 0x53, 0xc2, 0x1b, 0xe0, 0x02, 0x1b, 0x02, 0xe2, + 0x01, 0xee, 0x09, 0x08, 0xc6, 0xfc, 0x0a, 0x16, 0xe6, 0xe9, 0x11, 0x05, 0x34, + 0x0a, 0xfe, 0x11, 0x17, 0x1f, 0xd9, 0xd6, 0xf9, 0x04, 0x21, 0xd8, 0x1a, 0x1f, + 0xfd, 0x13, 0xf6, 0x21, 0x07, 0xeb, 0x06, 0xeb, 0xc8, 0xa4, 0x2a, 0xae, 0x4d, + 0xb9, 0x3f, 0x60, 0x9e, 0x19, 0xe7, 0x11, 0x73, 0xff, 0xec, 0x3c, 0xe4, 0x33, + 0x4f, 0x02, 0xd1, 0xf5, 0xd0, 0xe9, 0x97, 0xb2, 0xa3, 0x46, 0xf9, 0x02, 0xe1, + 0x2a, 0xd0, 0x16, 0xe3, 0x08, 0xf3, 0xf1, 0x32, 0xfe, 0xd4, 0xf3, 0x3a, 0xc8, + 0x20, 0x85, 0xd2, 0x19, 0x73, 0x40, 0x5e, 0xcc, 0xdd, 0x07, 0xa5, 0xba, 0xcf, + 0x60, 0xfe, 0xe7, 0x1e, 0x01, 0xf5, 0xd1, 0x1c, 0x3a, 0xd0, 0x18, 0x19, 0xbe, + 0x1a, 0x2b, 0x7f, 0x4c, 0xef, 0x2f, 0x8b, 0x39, 0xf2, 0x30, 0xb5, 0x59, 0xf1, + 0x6f, 0x02, 0xcc, 0xd4, 0xdf, 0x2e, 0x05, 0xd5, 0x47, 0xd9, 0xec, 0xea, 0xaf, + 0xd2, 0x20, 0x5b, 0x49, 0xd7, 0x30, 0xc3, 0xad, 0xba, 0x05, 0x0b, 0xd9, 0xf4, + 0x3d, 0x72, 0xec, 0x30, 0xb5, 0x48, 0x2e, 0xc7, 0xe7, 0xde, 0xe2, 0xc4, 0x50, + 0xdc, 0x43, 0xf4, 0xe4, 0x2f, 0x14, 0x47, 0xca, 0x04, 0x33, 0x16, 0xf3, 0xae, + 0x0a, 0x66, 0x23, 0x35, 0x21, 0x37, 0xd8, 0x10, 0x12, 0xf5, 0x7f, 0x08, 0x58, + 0x6b, 0x3d, 0xb0, 0xd7, 0x08, 0x18, 0xf4, 0x00, 0x41, 0x29, 0x89, 0x07, 0xfd, + 0xe3, 0x1d, 0x15, 0xee, 0x09, 0x0e, 0x18, 0x07, 0x21, 0x01, 0xd2, 0x23, 0x3f, + 0x30, 0xc5, 0x1e, 0x51, 0x31, 0xbe, 0xd7, 0x5c, 0x1c, 0x11, 0x50, 0xcb, 0xd6, + 0x3c, 0xfc, 0xbd, 0x1a, 0x5d, 0xe9, 0xde, 0x2d, 0xed, 0xae, 0x09, 0x44, 0x4a, + 0x7b, 0x5f, 0x05, 0x22, 0x4c, 0x4f, 0x04, 0x36, 0xf8, 0x07, 0x17, 0xaf, 0xea, + 0x3d, 0xd3, 0x3c, 0xee, 0x21, 0xe4, 0x30, 0x59, 0xf3, 0xce, 0x3f, 0x03, 0x1e, + 0xc4, 0x05, 0x35, 0xd0, 0x12, 0x17, 0xfa, 0x22, 0xfa, 0xf0, 0x24, 0x24, 0xe3, + 0xe9, 0xf9, 0x2d, 0x6a, 0xf6, 0x2e, 0xe4, 0x3b, 0x25, 0xc5, 0xf6, 0x3a, 0xc6, + 0xf2, 0x29, 0xca, 0x2c, 0x7c, 0xf9, 0xeb, 0x00, 0xde, 0xd7, 0x27, 0xd3, 0x22, + 0x21, 0x73, 0x38, 0xec, 0x05, 0xfb, 0xdb, 0xfa, 0xf9, 0x3a, 0xa1, 0xf0, 0xdb, + 0x7f, 0xec, 0xe7, 0x12, 0x1a, 0x3a, 0xfb, 0xc7, 0x10, 0x0e, 0x11, 0x09, 0xf5, + 0xdf, 0xf7, 0xe5, 0xe9, 0x1b, 0x38, 0x12, 0x1e, 0xf3, 0xfa, 0xde, 0x17, 0x04, + 0x06, 0xe3, 0x1e, 0x03, 0xe7, 0xa9, 0xca, 0xb2, 0xdb, 0x0a, 0xde, 0x24, 0x11, + 0x02, 0x19, 0xd3, 0xf7, 0xef, 0xdc, 0x03, 0xfb, 0xe5, 0x22, 0x39, 0x13, 0x3a, + 0x04, 0xe7, 0xf3, 0x41, 0xed, 0xf2, 0xc1, 0x52, 0x03, 0xd4, 0xe9, 0xf9, 0xbb, + 0xc0, 0xee, 0x0f, 0xf0, 0xe1, 0xd4, 0xc4, 0x0e, 0x0d, 0x2b, 0x41, 0xc4, 0xea, + 0xf6, 0x3e, 0xe6, 0xfc, 0xdf, 0x35, 0x15, 0x08, 0x1d, 0x01, 0xd1, 0xe3, 0xf7, + 0xf6, 0xea, 0x1a, 0x1b, 0xfd, 0x1b, 0x08, 0x00, 0xcb, 0x05, 0x12, 0xfb, 0x43, + 0xe1, 0xff, 0x22, 0x0a, 0x02, 0x08, 0xf7, 0xea, 0x13, 0xf3, 0x1a, 0xd8, 0xe4, + 0x25, 0xed, 0x0d, 0x0f, 0xf6, 0x00, 0x0f, 0x12, 0xe1, 0xdd, 0x0c, 0xd3, 0x0b, + 0x03, 0xef, 0x1d, 0xdb, 0xe9, 0x16, 0xe4, 0x3c, 0x25, 0x02, 0xbe, 0x44, 0xe5, + 0x11, 0x39, 0x5b, 0x0c, 0xda, 0x1f, 0x11, 0xee, 0x2c, 0x2d, 0xea, 0x1b, 0x00, + 0x16, 0x1c, 0x0e, 0x07, 0x00, 0xe5, 0x15, 0x1b, 0xfb, 0x16, 0x13, 0xf3, 0x1a, + 0x0e, 0x0b, 0x2d, 0x15, 0xf4, 0xed, 0xfb, 0x22, 0x1f, 0x0a, 0x21, 0xfa, 0x03, + 0xcc, 0x21, 0x0a, 0x03, 0xf5, 0x42, 0xf0, 0xee, 0xfe, 0xf1, 0x0a, 0x7f, 0xdb, + 0x03, 0x14, 0x30, 0x2d, 0x1b, 0xf7, 0x02, 0x11, 0x1f, 0x0b, 0x01, 0x14, 0x3f, + 0xf1, 0x04, 0x08, 0x21, 0xf7, 0x03, 0xe7, 0xf1, 0x18, 0xf3, 0x11, 0x02, 0x41, + 0xee, 0x2b, 0xf3, 0xf1, 0x29, 0x10, 0xe2, 0x17, 0x04, 0xed, 0x2d, 0x02, 0xfb, + 0xc9, 0x09, 0xf9, 0xec, 0x0f, 0x16, 0xdf, 0xf4, 0x0e, 0x1a, 0x07, 0x28, 0x14, + 0x2b, 0xf5, 0x09, 0xe5, 0xfa, 0x0d, 0x31, 0x35, 0x4f, 0x11, 0xfd, 0x10, 0xf5, + 0x7f, 0xf8, 0xee, 0x36, 0xf8, 0x0f, 0xe0, 0xfc, 0xf8, 0x29, 0xe4, 0x0d, 0x02, + 0x10, 0x18, 0xeb, 0x08, 0x11, 0xe6, 0xfe, 0x0c, 0x0e, 0x01, 0x0f, 0xf6, 0xf0, + 0xf3, 0xed, 0xfa, 0xe6, 0x0e, 0x0f, 0xe7, 0xfd, 0xf4, 0x05, 0xfa, 0x05, 0xf5, + 0xe2, 0xed, 0xfe, 0x10, 0xf2, 0x0a, 0x00, 0xc4, 0x42, 0xec, 0xef, 0xfa, 0x1d, + 0xd4, 0x1f, 0xe6, 0xfd, 0x1d, 0xe9, 0xf0, 0x00, 0x0a, 0x02, 0x12, 0xec, 0x05, + 0xfb, 0x03, 0xf6, 0xf8, 0xea, 0x1e, 0x2a, 0x17, 0x15, 0xf5, 0x02, 0xfa, 0x1c, + 0xe8, 0x19, 0xf9, 0x23, 0xdc, 0xea, 0x00, 0x2e, 0x29, 0xee, 0xe8, 0xf8, 0x27, + 0xf4, 0xf6, 0x01, 0xbe, 0xe0, 0x0c, 0x21, 0x0f, 0x65, 0x24, 0xf6, 0xda, 0xf3, + 0x14, 0x39, 0xfa, 0x09, 0xe3, 0xe2, 0x1e, 0xdc, 0x75, 0xcf, 0x2e, 0x31, 0xeb, + 0xf2, 0xe0, 0x24, 0x55, 0xeb, 0xb4, 0xe7, 0x7f, 0xc0, 0x25, 0xea, 0xe5, 0xf9, + 0x23, 0xed, 0x47, 0xf7, 0x01, 0xd3, 0x48, 0xe1, 0x2d, 0xe3, 0xe0, 0xa2, 0xf6, + 0x3b, 0xee, 0xc8, 0x18, 0x08, 0x06, 0x28, 0x2d, 0x26, 0xc9, 0x06, 0xfd, 0x9a, + 0x11, 0x1d, 0xe1, 0x10, 0xd9, 0xdf, 0x1a, 0x0d, 0xf8, 0xe6, 0x04, 0x23, 0x26, + 0xe4, 0xee, 0x0a, 0x4b, 0xeb, 0x3c, 0xbf, 0xfe, 0xe7, 0x4a, 0xf7, 0xec, 0xe7, + 0x28, 0x2f, 0xfa, 0x09, 0xef, 0x06, 0xdf, 0x11, 0x40, 0xdb, 0xfe, 0x18, 0xee, + 0xdf, 0x34, 0x00, 0x09, 0x15, 0xf5, 0x57, 0xe8, 0x4d, 0xeb, 0xd5, 0x15, 0x39, + 0x45, 0x28, 0x14, 0x16, 0x13, 0xd8, 0xca, 0xea, 0x27, 0xe0, 0x21, 0x1d, 0xd3, + 0xf8, 0x26, 0x02, 0x38, 0xff, 0x43, 0xd6, 0x10, 0x42, 0xb5, 0xec, 0xfb, 0xca, + 0x37, 0xe3, 0x10, 0x23, 0x2b, 0xf6, 0x28, 0x47, 0x4c, 0xe0, 0xc9, 0x16, 0x28, + 0xf2, 0xeb, 0x28, 0x7d, 0x7f, 0xe3, 0xf2, 0xf3, 0x04, 0xe5, 0xf6, 0x19, 0x35, + 0xe1, 0x31, 0x4e, 0x00, 0xdc, 0x36, 0xd6, 0xa5, 0x27, 0x4f, 0xe7, 0x2a, 0x1c, + 0x1e, 0x05, 0xfb, 0x33, 0x11, 0x04, 0x30, 0xe4, 0xf4, 0xe6, 0x1e, 0xd6, 0xd7, + 0x12, 0x0b, 0x19, 0x4b, 0xe5, 0xda, 0x4c, 0x26, 0x20, 0x24, 0xe9, 0x0d, 0xdf, + 0xe1, 0x23, 0x33, 0x36, 0x16, 0xd0, 0xbe, 0x4b, 0x6a, 0x48, 0x49, 0xf1, 0x49, + 0xfa, 0xf5, 0x33, 0x21, 0x30, 0xe3, 0xef, 0xef, 0xe4, 0x45, 0xfe, 0xd7, 0x01, + 0x2f, 0x00, 0x10, 0xcf, 0xfe, 0x15, 0x36, 0x15, 0xe6, 0xec, 0x00, 0x28, 0x13, + 0x13, 0xe4, 0x3b, 0xd0, 0xdb, 0xdd, 0x19, 0x0c, 0xfc, 0x0a, 0x59, 0x26, 0xcb, + 0xc8, 0xf1, 0x0a, 0x19, 0x34, 0x06, 0x40, 0x1e, 0x4a, 0x0a, 0x12, 0x07, 0xce, + 0xb9, 0xb5, 0xc8, 0xee, 0x3d, 0x3b, 0x0f, 0x35, 0xc7, 0xf6, 0xda, 0xf2, 0x19, + 0x4b, 0xed, 0xf1, 0x1c, 0x92, 0xd6, 0xbc, 0xda, 0x22, 0x52, 0xf2, 0x57, 0xe0, + 0xea, 0x0d, 0xde, 0xff, 0xe2, 0x54, 0xef, 0xcb, 0xf1, 0xae, 0xee, 0xff, 0xc0, + 0xae, 0xe9, 0x6d, 0xd1, 0xf0, 0x35, 0xd8, 0xfc, 0x0d, 0x60, 0xe9, 0x3a, 0xec, + 0xd0, 0x2a, 0x1f, 0x19, 0x48, 0x33, 0xea, 0xb7, 0xde, 0xbd, 0x48, 0x8e, 0x13, + 0xff, 0x0a, 0x18, 0x17, 0xea, 0xfc, 0xda, 0xbc, 0x7f, 0xf1, 0x2e, 0xdf, 0xfd, + 0xe7, 0x26, 0xce, 0x1d, 0x02, 0x2a, 0xf9, 0xd3, 0x13, 0xfc, 0xe6, 0xd9, 0xb3, + 0xf5, 0x03, 0xfb, 0xd1, 0x34, 0xcc, 0xcf, 0xe8, 0x45, 0xd1, 0x0a, 0xdc, 0x0f, + 0xfa, 0x9d, 0xe7, 0xc2, 0x06, 0xe6, 0x58, 0x35, 0xd0, 0x24, 0xef, 0x04, 0xea, + 0x4b, 0x3c, 0x16, 0x09, 0xaf, 0x24, 0x0d, 0x23, 0x25, 0x1a, 0xf4, 0x2a, 0x39, + 0xcf, 0xd3, 0x0f, 0xaf, 0xe0, 0x1b, 0x39, 0x08, 0x08, 0xb7, 0x38, 0xb1, 0xfb, + 0x01, 0xd1, 0x35, 0x00, 0x17, 0xe8, 0xdc, 0xc7, 0x11, 0xd4, 0xff, 0x4a, 0xa9, + 0x54, 0xd5, 0xdd, 0x31, 0xfd, 0x23, 0xf9, 0xf3, 0xb2, 0xbb, 0x23, 0xe0, 0xef, + 0xfd, 0x02, 0x5a, 0xd4, 0xf6, 0x19, 0xdd, 0xe0, 0x0f, 0xaf, 0xe0, 0x0f, 0xb5, + 0x1c, 0x16, 0xcc, 0xda, 0x10, 0x78, 0xcc, 0x40, 0x0d, 0xd1, 0xe6, 0xf8, 0x51, + 0xef, 0x1f, 0x47, 0x54, 0xef, 0x45, 0xcd, 0xdd, 0x06, 0x36, 0x48, 0xf9, 0xd3, + 0xc5, 0x9d, 0xbb, 0xc7, 0xbd, 0xf2, 0xae, 0x1f, 0x43, 0x39, 0xf8, 0xf2, 0x0a, + 0xea, 0xd1, 0x04, 0x0b, 0xfe, 0xb8, 0xb3, 0x7f, 0x0f, 0x16, 0x1d, 0x5a, 0x00, + 0x12, 0xef, 0x01, 0x55, 0x2a, 0x23, 0xe4, 0xec, 0xf1, 0xb9, 0x5c, 0x08, 0x05, + 0xf8, 0x19, 0x1b, 0xc1, 0x11, 0x1a, 0xe7, 0xe4, 0xc4, 0x02, 0xeb, 0xcc, 0xea, + 0x0e, 0xe9, 0xb3, 0x0c, 0xf4, 0xdb, 0x58, 0xdc, 0x1d, 0xbf, 0x03, 0x19, 0x30, + 0x10, 0xea, 0xf4, 0xf2, 0xe8, 0x5f, 0xf3, 0xe9, 0x13, 0x11, 0xd2, 0x28, 0x34, + 0xeb, 0x2a, 0x04, 0xe0, 0x1f, 0xd8, 0xc6, 0x7f, 0xef, 0x2b, 0xe7, 0xca, 0x0a, + 0xee, 0x31, 0x31, 0xd1, 0x94, 0xf5, 0x11, 0xd6, 0x57, 0xf8, 0x33, 0x12, 0x23, + 0x0e, 0x1c, 0x07, 0x01, 0xeb, 0x16, 0xfb, 0x08, 0xf9, 0x1c, 0xe6, 0x0c, 0x14, + 0xdc, 0xe5, 0xd9, 0xfe, 0xcc, 0xf8, 0xfa, 0xfd, 0x28, 0x01, 0xc6, 0x50, 0xec, + 0x22, 0x61, 0xe2, 0xed, 0x1d, 0x63, 0x17, 0xac, 0x05, 0x5b, 0xbf, 0xc1, 0xe4, + 0xf2, 0xf9, 0xcf, 0xf1, 0xfc, 0x68, 0x0e, 0x31, 0x30, 0x01, 0xe9, 0x1f, 0x05, + 0xfc, 0x0a, 0x17, 0xc3, 0x54, 0xbb, 0x06, 0x5b, 0xec, 0xc3, 0x0d, 0x15, 0x38, + 0x16, 0xbd, 0xce, 0xda, 0xff, 0x30, 0xc9, 0xfa, 0xfb, 0x00, 0xf8, 0xe2, 0x4e, + 0xee, 0x01, 0x0f, 0x1c, 0x1c, 0x1a, 0x49, 0x3b, 0xdc, 0x2a, 0xc9, 0xcd, 0xef, + 0xeb, 0x20, 0x1e, 0xd3, 0xe7, 0xe1, 0x3a, 0x19, 0xe0, 0x05, 0x04, 0xf2, 0x09, + 0xf9, 0x5d, 0x11, 0x5a, 0x18, 0x14, 0xe6, 0xcf, 0x01, 0xfb, 0xfd, 0x27, 0x5d, + 0xfd, 0x27, 0xf8, 0x10, 0x07, 0x0a, 0x09, 0xf2, 0x29, 0x08, 0xda, 0x11, 0xf8, + 0xd2, 0x16, 0x26, 0xe3, 0xfe, 0x2a, 0x7a, 0xe1, 0x07, 0x54, 0x27, 0xf2, 0xce, + 0x38, 0x0f, 0x0d, 0x38, 0xe4, 0xce, 0x4a, 0x3d, 0xee, 0x10, 0x3a, 0xf8, 0x1d, + 0x1b, 0x2c, 0xea, 0x05, 0x2e, 0xef, 0x01, 0x0a, 0xec, 0xda, 0xee, 0x6c, 0xed, + 0xfd, 0x16, 0xf2, 0x2a, 0xe7, 0xce, 0x05, 0x39, 0xf1, 0xf3, 0x44, 0x7f, 0x04, + 0xeb, 0x0b, 0xfc, 0x14, 0x1d, 0x0a, 0x15, 0x21, 0x0c, 0x34, 0x16, 0x15, 0xf8, + 0x34, 0x0e, 0xda, 0xbf, 0xe7, 0x01, 0x04, 0xe2, 0x0e, 0xdd, 0x34, 0x07, 0x03, + 0x03, 0x09, 0xa6, 0x44, 0x1f, 0xc8, 0xfe, 0x06, 0x49, 0x22, 0x29, 0xe2, 0x32, + 0xeb, 0xd7, 0xf0, 0xe3, 0x2c, 0x46, 0xf2, 0xba, 0xd3, 0x1c, 0xc9, 0xe1, 0x47, + 0x01, 0xe6, 0x09, 0x7f, 0xa5, 0xd4, 0x48, 0xff, 0x7a, 0xf3, 0x33, 0xfb, 0x2b, + 0xfc, 0x4a, 0xef, 0xf0, 0x05, 0xd0, 0x27, 0x15, 0x2a, 0x0f, 0xe9, 0xf9, 0xed, + 0xff, 0xfc, 0xc7, 0xcb, 0x25, 0xdb, 0xe3, 0x63, 0x16, 0xe4, 0xab, 0x73, 0xd7, + 0x32, 0xff, 0x10, 0xf7, 0xfd, 0xcb, 0x26, 0xda, 0xeb, 0xfe, 0xf0, 0x26, 0xee, + 0x1c, 0x08, 0xbc, 0x48, 0x28, 0x10, 0x1f, 0x06, 0xf8, 0xfc, 0xe9, 0x3f, 0x17, + 0x14, 0xd5, 0xfd, 0xd2, 0xe3, 0x3f, 0x14, 0x30, 0x27, 0xcc, 0xda, 0xe1, 0x03, + 0xfe, 0x07, 0x20, 0x12, 0xd3, 0x07, 0x1d, 0xfb, 0x0c, 0xc5, 0xda, 0xf9, 0xa8, + 0xcd, 0xce, 0xef, 0x35, 0xef, 0xc8, 0x0a, 0x47, 0xc4, 0xc9, 0x09, 0x06, 0x4d, + 0x09, 0xf3, 0x11, 0xdf, 0xea, 0x0d, 0x0a, 0x0c, 0xc2, 0xd0, 0xcd, 0xec, 0xe7, + 0xf6, 0x3c, 0x04, 0xd9, 0x04, 0xea, 0xe4, 0x09, 0x20, 0x3b, 0xdb, 0xd6, 0x4e, + 0x9f, 0xb1, 0x23, 0xca, 0x81, 0x13, 0xc0, 0x21, 0xab, 0x10, 0x3a, 0x8d, 0xfb, + 0xd4, 0x07, 0xe1, 0x15, 0x26, 0x4f, 0xe1, 0x06, 0xce, 0x34, 0x1f, 0x0d, 0x53, + 0x0e, 0x23, 0x00, 0xf0, 0xb5, 0x09, 0x44, 0xfb, 0xf8, 0xef, 0xde, 0xc8, 0x08, + 0xea, 0x56, 0xf4, 0x47, 0x40, 0x19, 0x4f, 0xe2, 0x96, 0x27, 0xff, 0x03, 0xb2, + 0xf3, 0xc4, 0xdf, 0xdd, 0x06, 0xfc, 0xf7, 0xf7, 0x40, 0xaf, 0xc4, 0x10, 0x2b, + 0xfa, 0xdd, 0xf3, 0xe4, 0xc7, 0x20, 0xa3, 0xfb, 0xe2, 0x0a, 0xc3, 0x11, 0xd7, + 0xf5, 0xff, 0x38, 0xf2, 0x0d, 0xdc, 0x55, 0x2b, 0x2e, 0x34, 0xf8, 0x46, 0xc8, + 0xca, 0x20, 0x0c, 0x15, 0xdf, 0x30, 0x31, 0x0f, 0x25, 0x51, 0xf3, 0xde, 0xdc, + 0xea, 0xcf, 0xa0, 0x9a, 0xd0, 0x28, 0xfc, 0xee, 0xf4, 0x26, 0x0d, 0x09, 0x09, + 0x27, 0xef, 0x13, 0xbf, 0x1a, 0x0d, 0xd4, 0xfe, 0x18, 0xd2, 0x04, 0x4d, 0xde, + 0x21, 0x10, 0x08, 0xcf, 0xfc, 0x0b, 0x12, 0x29, 0xd9, 0xf4, 0xd6, 0xeb, 0x3b, + 0x1e, 0xf3, 0xf0, 0x5a, 0xd3, 0x10, 0x2c, 0x04, 0xfe, 0x20, 0x44, 0x05, 0x12, + 0x6f, 0xfd, 0x08, 0x5b, 0x1f, 0xf5, 0xc2, 0x0c, 0x3d, 0x2c, 0xfc, 0xf6, 0x0a, + 0x7f, 0x2a, 0xe7, 0x62, 0x3e, 0xf1, 0x0c, 0xec, 0x03, 0x18, 0x12, 0xc2, 0xf8, + 0x1d, 0x12, 0x02, 0x04, 0xd2, 0x44, 0x38, 0xd9, 0x17, 0x09, 0xb6, 0x46, 0x1d, + 0x17, 0x6a, 0xf1, 0xe6, 0xd5, 0x2d, 0x0e, 0xd3, 0xfe, 0xee, 0xe9, 0x1c, 0x11, + 0x3e, 0xb8, 0x1a, 0x29, 0x01, 0xcd, 0xb6, 0xfb, 0x1c, 0x05, 0xe6, 0xfd, 0xdd, + 0xd0, 0xea, 0x1e, 0xec, 0xfb, 0xeb, 0x00, 0xe1, 0x0d, 0x19, 0xbd, 0xfa, 0xf8, + 0x34, 0x7f, 0x0b, 0xf8, 0xf3, 0x01, 0x1f, 0xdf, 0xdf, 0xec, 0x02, 0x00, 0xf6, + 0xef, 0x1f, 0xe0, 0xe1, 0x00, 0xec, 0x44, 0x17, 0xda, 0xd6, 0xf3, 0xe9, 0x08, + 0xda, 0x3c, 0x1a, 0xbc, 0x1e, 0x06, 0x05, 0xe1, 0x06, 0xde, 0xe2, 0x23, 0xd4, + 0x28, 0xef, 0x18, 0x08, 0x0b, 0xdc, 0xd1, 0xf4, 0x11, 0xe9, 0xe9, 0xf8, 0xf0, + 0xca, 0x19, 0xeb, 0x07, 0x0e, 0x1e, 0xe6, 0x51, 0x13, 0xe2, 0x18, 0xfb, 0x24, + 0x27, 0x30, 0x13, 0x04, 0xf3, 0xe4, 0xd9, 0x08, 0x07, 0x13, 0x2e, 0xca, 0x4c, + 0x1d, 0xd8, 0x09, 0xcc, 0xbf, 0x02, 0xf2, 0xe6, 0xf6, 0x40, 0xd7, 0x05, 0xd0, + 0xec, 0xe0, 0xd7, 0xd2, 0x02, 0x19, 0x29, 0x32, 0xfd, 0xeb, 0x1c, 0x03, 0x3d, + 0xf1, 0xde, 0x1e, 0x1f, 0x0b, 0xdc, 0x1f, 0xea, 0xf3, 0x44, 0x2c, 0x45, 0xf8, + 0xf8, 0xed, 0xde, 0xc6, 0x0e, 0xdf, 0x17, 0x04, 0x05, 0x52, 0xa5, 0xe7, 0xd3, + 0x62, 0xcd, 0x28, 0x2e, 0x2e, 0xab, 0x12, 0x7f, 0x00, 0x1d, 0xab, 0xcc, 0xfa, + 0xde, 0x1f, 0x5e, 0x55, 0x0f, 0xdd, 0x37, 0x4a, 0xf1, 0x30, 0x29, 0x18, 0xda, + 0x09, 0x23, 0xdc, 0x25, 0xdf, 0x61, 0x09, 0x21, 0x4c, 0xa0, 0x2c, 0xbd, 0x16, + 0xef, 0x1f, 0xe2, 0xff, 0x51, 0x44, 0x08, 0x19, 0xe6, 0xb7, 0xd4, 0x29, 0x2c, + 0xf8, 0x21, 0xdd, 0x2e, 0x08, 0x03, 0x4a, 0xde, 0x05, 0x92, 0xe8, 0xe7, 0xe6, + 0x73, 0x07, 0x3a, 0xa3, 0x02, 0xcf, 0xea, 0x0f, 0x3c, 0x12, 0xd4, 0x00, 0x40, + 0x07, 0xfe, 0x3f, 0xd4, 0xbc, 0x21, 0xe8, 0xbc, 0xd3, 0x5f, 0xf3, 0x45, 0x1a, + 0x29, 0x07, 0xff, 0x1d, 0xb4, 0x2d, 0xfa, 0xfa, 0x27, 0xc9, 0xc0, 0x11, 0x42, + 0xcf, 0xb4, 0xcb, 0xf7, 0xce, 0x0f, 0x00, 0x11, 0x54, 0xc4, 0xd8, 0xc6, 0x04, + 0x10, 0x23, 0x33, 0xd5, 0xf9, 0xe4, 0xc5, 0x19, 0x22, 0xe6, 0xe3, 0x0f, 0x2b, + 0x05, 0x40, 0x23, 0x18, 0x28, 0xc2, 0x49, 0x10, 0xb1, 0xfd, 0xd9, 0xf3, 0x29, + 0x14, 0x21, 0xdb, 0xf7, 0x1d, 0x1c, 0x2f, 0x37, 0xe4, 0x12, 0xd2, 0x15, 0xe4, + 0xfc, 0x02, 0x3d, 0xad, 0xbc, 0xbd, 0xd9, 0xeb, 0x3b, 0xdb, 0xd0, 0x35, 0xf4, + 0xf7, 0x11, 0xee, 0x32, 0x3d, 0x59, 0x2d, 0x1c, 0xe7, 0x05, 0xdb, 0x15, 0x18, + 0x1f, 0xd2, 0xe0, 0x0c, 0x5a, 0xca, 0x08, 0xda, 0x20, 0xbe, 0xf3, 0xf3, 0xb5, + 0x56, 0x08, 0x07, 0xfd, 0x65, 0x16, 0xe9, 0x12, 0x2b, 0x07, 0xbc, 0xdd, 0xf1, + 0xdb, 0xdf, 0xea, 0xde, 0x4c, 0xfc, 0xc5, 0xfb, 0xbc, 0xf8, 0x08, 0x07, 0xde, + 0xea, 0x2c, 0x20, 0x2a, 0x0a, 0x2c, 0x0f, 0x0e, 0xc3, 0x01, 0x24, 0xcf, 0x81, + 0xc2, 0x48, 0xb6, 0xf3, 0xba, 0xda, 0xe0, 0xd2, 0xea, 0x0b, 0xdf, 0x4a, 0x42, + 0x1b, 0xd0, 0xd6, 0xd4, 0x2d, 0x1f, 0xd7, 0x8f, 0xcc, 0x41, 0xda, 0xfc, 0xe1, + 0x36, 0x15, 0xfe, 0x4e, 0xaa, 0x08, 0xe5, 0x0d, 0x8f, 0x11, 0xc3, 0xed, 0xfb, + 0xec, 0x37, 0xa9, 0x65, 0xc2, 0x0d, 0xe4, 0x1a, 0x1c, 0x45, 0x03, 0x08, 0xf4, + 0xf7, 0xbb, 0x23, 0xe4, 0xeb, 0x0e, 0xed, 0x29, 0xfd, 0xff, 0xe9, 0xd5, 0xe8, + 0xb5, 0x0b, 0x0a, 0xdb, 0xb1, 0x3b, 0x2d, 0xf5, 0x42, 0xc1, 0x12, 0x84, 0x10, + 0xe9, 0xe9, 0xe7, 0x3c, 0xa3, 0xd0, 0xe2, 0x11, 0xbc, 0x94, 0x4d, 0xba, 0x00, + 0x0e, 0x53, 0xe8, 0xef, 0xf0, 0xd9, 0xf9, 0xcf, 0xf3, 0xed, 0x5e, 0xe4, 0xf1, + 0x14, 0x2a, 0xfd, 0x0d, 0xea, 0xee, 0x1a, 0xcb, 0xea, 0x2b, 0xa8, 0x48, 0x3e, + 0xf0, 0x0c, 0x18, 0xec, 0x1e, 0xaa, 0x16, 0xb9, 0x75, 0x61, 0x7f, 0xcb, 0xfd, + 0x40, 0x14, 0x3b, 0x41, 0xd5, 0xf7, 0x2b, 0x27, 0x00, 0x10, 0x3b, 0x0a, 0xb9, + 0x31, 0x03, 0x1f, 0xf5, 0x55, 0x12, 0x13, 0x4b, 0x04, 0x0c, 0x25, 0x07, 0xf5, + 0x96, 0x1f, 0x5f, 0xe4, 0x43, 0x11, 0x32, 0xe1, 0xe7, 0x39, 0xfb, 0x1b, 0x0c, + 0x36, 0xfe, 0x0b, 0x08, 0xff, 0x3e, 0x03, 0x1e, 0xe7, 0x0a, 0xf0, 0xe1, 0x34, + 0x18, 0x0e, 0xe1, 0x02, 0xe5, 0xbf, 0xe3, 0x13, 0x05, 0x0e, 0xeb, 0x7f, 0x06, + 0xce, 0x0c, 0x14, 0xcd, 0x09, 0x2f, 0xde, 0x1c, 0x00, 0x09, 0x4b, 0x17, 0x45, + 0xe8, 0x32, 0x28, 0xf5, 0xc4, 0x17, 0xeb, 0xe1, 0xda, 0xdf, 0x03, 0x18, 0x0a, + 0x07, 0x24, 0x21, 0x0d, 0xd4, 0x11, 0xdb, 0x0b, 0xf4, 0xba, 0x10, 0xd0, 0xf6, + 0xd4, 0x0f, 0xec, 0x1f, 0x0b, 0x27, 0xe4, 0x4f, 0xee, 0x4e, 0x3b, 0x32, 0x11, + 0xe0, 0xe8, 0xb8, 0x11, 0xdd, 0x22, 0x27, 0x1d, 0xeb, 0xef, 0xec, 0xe8, 0x21, + 0xee, 0xff, 0xd6, 0xb9, 0xf6, 0x08, 0xc9, 0x30, 0xef, 0x06, 0xb6, 0x9b, 0xe3, + 0x05, 0x21, 0xfd, 0x01, 0x4f, 0xe6, 0xe5, 0xf2, 0x1d, 0xbd, 0xfe, 0xa4, 0x41, + 0x1f, 0xdf, 0xd3, 0xdd, 0xb7, 0x1c, 0xd8, 0xfc, 0xdd, 0xee, 0xfb, 0xd5, 0xc8, + 0xb8, 0x96, 0xdd, 0xb8, 0x11, 0x02, 0xe7, 0xee, 0xbb, 0xd6, 0x19, 0xda, 0xde, + 0x07, 0x19, 0x16, 0x27, 0x0e, 0xfd, 0x17, 0xa9, 0xc4, 0xd2, 0xec, 0xd2, 0x04, + 0xa0, 0xe2, 0x08, 0xb1, 0x08, 0xab, 0xd5, 0x0a, 0xf4, 0xe5, 0xea, 0xcf, 0x06, + 0x1f, 0x8f, 0xd4, 0x0b, 0x02, 0xf5, 0x47, 0xca, 0x05, 0xf3, 0xf2, 0x10, 0x1c, + 0xfb, 0xea, 0x1c, 0xfc, 0x02, 0x08, 0xc5, 0x81, 0xa1, 0xc3, 0x59, 0xb2, 0x59, + 0xfe, 0x29, 0xd2, 0xbf, 0x1f, 0xce, 0xb2, 0x08, 0x27, 0xf1, 0x0a, 0x11, 0xc4, + 0x13, 0xa3, 0x19, 0xfe, 0xee, 0xe5, 0xe5, 0x0f, 0xec, 0x28, 0xe3, 0x1d, 0xc0, + 0xeb, 0xf6, 0xe1, 0x31, 0x0c, 0xd3, 0xea, 0xf6, 0xf6, 0xdc, 0x12, 0x48, 0xd4, + 0xdf, 0xf1, 0x6b, 0xdf, 0xd6, 0xfb, 0x04, 0x4d, 0xec, 0x09, 0x1c, 0xa7, 0xf0, + 0x6d, 0x09, 0xdd, 0x1f, 0x1b, 0xe1, 0xe2, 0xf2, 0xf6, 0xe2, 0xef, 0xeb, 0xfc, + 0xd6, 0xfb, 0x2d, 0xe8, 0x19, 0x0e, 0x0d, 0x07, 0x35, 0xdd, 0xab, 0x29, 0x49, + 0x25, 0xdd, 0xee, 0xed, 0x1a, 0x3c, 0xe0, 0x22, 0x11, 0xde, 0x20, 0x0d, 0x2f, + 0xcc, 0x45, 0x12, 0xf2, 0xd3, 0x40, 0xde, 0xb8, 0xe5, 0x13, 0x17, 0xd5, 0xf3, + 0xd9, 0xe7, 0xe7, 0xeb, 0x03, 0x03, 0x32, 0xf6, 0xd1, 0xf6, 0xe8, 0x22, 0xd7, + 0x1d, 0x06, 0x2b, 0x2a, 0x28, 0x33, 0xe1, 0xdf, 0x21, 0x2c, 0x10, 0xd0, 0xcf, + 0x7f, 0xc9, 0x31, 0x35, 0x21, 0x1b, 0x01, 0x17, 0x3b, 0x09, 0xce, 0x2f, 0xc3, + 0x1a, 0xbb, 0xf6, 0xed, 0x33, 0x0f, 0xec, 0xfa, 0xf4, 0x42, 0xe3, 0xf9, 0x17, + 0x0b, 0x21, 0xdd, 0x57, 0x06, 0xff, 0x2b, 0xec, 0xce, 0x0b, 0x1a, 0x00, 0x1d, + 0xd3, 0xdb, 0x03, 0x12, 0x2f, 0x0f, 0xf2, 0x0b, 0xbe, 0xd7, 0xd7, 0xbd, 0x33, + 0xda, 0x1a, 0xf5, 0xbb, 0x02, 0x66, 0xfd, 0xf6, 0x53, 0x3d, 0x16, 0xcf, 0xfb, + 0x02, 0x4e, 0xf9, 0x51, 0x0b, 0xfa, 0xa4, 0x1b, 0xfe, 0xe6, 0x9a, 0x4f, 0x1f, + 0xf8, 0x0e, 0xd9, 0x7f, 0xbd, 0xfb, 0xd9, 0x05, 0xbd, 0x36, 0x20, 0x12, 0xc6, + 0xec, 0xd4, 0x14, 0xc7, 0x5e, 0xae, 0xe1, 0x31, 0xf4, 0x37, 0x1d, 0xca, 0x13, + 0x0e, 0xbb, 0xda, 0x19, 0x27, 0xf2, 0x01, 0xf4, 0x02, 0x41, 0xeb, 0x0d, 0x02, + 0x11, 0x0c, 0xf9, 0xcd, 0x13, 0x08, 0x19, 0xf2, 0x01, 0x5a, 0x34, 0x06, 0xcf, + 0xff, 0xa1, 0xf9, 0xd6, 0x21, 0xea, 0x25, 0xd6, 0x0e, 0xd0, 0x11, 0x08, 0xc2, + 0xfb, 0xc6, 0xf4, 0x74, 0x7f, 0x17, 0x3a, 0x0e, 0xf9, 0x0b, 0xcd, 0xe0, 0xe3, + 0x17, 0xf4, 0xfa, 0x2d, 0xe0, 0xec, 0xd7, 0x06, 0xe6, 0xff, 0xf8, 0xd6, 0xdd, + 0xfe, 0xea, 0xfb, 0xff, 0xda, 0xfc, 0x2b, 0x63, 0xeb, 0xec, 0xce, 0x61, 0xf9, + 0xdc, 0xf9, 0xfc, 0xe8, 0x01, 0xe0, 0x73, 0x29, 0x08, 0x75, 0xf0, 0x12, 0x6f, + 0x38, 0x07, 0x22, 0x07, 0x20, 0xdc, 0xe2, 0x2e, 0xea, 0xe2, 0x01, 0x2e, 0xde, + 0xff, 0x29, 0x13, 0x11, 0x27, 0xec, 0x08, 0xfc, 0x21, 0x2a, 0x1d, 0x5d, 0xe0, + 0x78, 0x35, 0x07, 0xc8, 0x2f, 0xd9, 0xf6, 0xfb, 0x0b, 0x3a, 0xf8, 0xf8, 0xe1, + 0xfa, 0xce, 0xef, 0x40, 0xcf, 0x3c, 0xeb, 0x67, 0x2e, 0xff, 0x01, 0x1d, 0xdf, + 0xfe, 0xfd, 0x07, 0x0b, 0xfe, 0x27, 0x0d, 0x70, 0x08, 0xfd, 0xf3, 0xf7, 0xfa, + 0xc7, 0xde, 0x0e, 0x53, 0xfc, 0x12, 0x0f, 0xe3, 0xe6, 0x01, 0xe6, 0x12, 0xb3, + 0xad, 0x25, 0x4c, 0xc2, 0x20, 0x1a, 0x28, 0xba, 0x12, 0x31, 0x44, 0x1a, 0x41, + 0x3a, 0x13, 0x06, 0xeb, 0xfd, 0xf4, 0x37, 0x78, 0x0e, 0x31, 0x4b, 0x02, 0xf7, + 0x08, 0x2e, 0x3e, 0xed, 0x03, 0xd3, 0x0f, 0xcf, 0x3a, 0xeb, 0xfb, 0x96, 0xe9, + 0xdb, 0x0f, 0x53, 0x00, 0x2f, 0xec, 0xda, 0x0d, 0x52, 0xf6, 0x6f, 0xd7, 0x3c, + 0x14, 0xa5, 0xe9, 0x81, 0xcd, 0x36, 0x18, 0xee, 0xcb, 0xda, 0xd6, 0xf1, 0xec, + 0x17, 0x27, 0xeb, 0xff, 0x21, 0x1c, 0x0b, 0x7c, 0x34, 0x1c, 0xe7, 0x03, 0x0f, + 0x00, 0xe9, 0x00, 0x19, 0x3e, 0x01, 0xa2, 0xc3, 0x74, 0xe8, 0x31, 0xed, 0xf1, + 0x09, 0xeb, 0xdd, 0xe5, 0x42, 0x52, 0xff, 0xf4, 0xdf, 0xf0, 0xf3, 0x62, 0x01, + 0xfc, 0x12, 0x2c, 0xde, 0xf8, 0xe2, 0x19, 0x1c, 0x1d, 0x15, 0x34, 0x1d, 0xf1, + 0xf0, 0x09, 0x1c, 0xd8, 0x1e, 0xee, 0xfa, 0x30, 0xdf, 0xec, 0x0c, 0x03, 0x1f, + 0x28, 0x20, 0x0a, 0x09, 0xff, 0xf3, 0x43, 0x68, 0xe7, 0x21, 0xe8, 0xfd, 0x7f, + 0xc0, 0xd2, 0xf0, 0x1f, 0xf9, 0x1b, 0x04, 0x25, 0x3b, 0x4a, 0xfc, 0xb2, 0x2c, + 0xf0, 0xcb, 0x42, 0xf7, 0xc6, 0x31, 0x21, 0x35, 0x2b, 0x0a, 0xfa, 0xd3, 0xe6, + 0x35, 0xd2, 0x0f, 0xdc, 0x97, 0x02, 0xc5, 0x19, 0x51, 0xd5, 0xdb, 0xd9, 0xbe, + 0xcc, 0xd8, 0xdd, 0xc8, 0x3b, 0xe6, 0x0b, 0xee, 0xf1, 0x28, 0xc7, 0xdd, 0xec, + 0x11, 0xf2, 0x0d, 0xa5, 0xd9, 0x03, 0x1f, 0xbc, 0xe1, 0x19, 0x3d, 0xf7, 0x00, + 0x60, 0xf4, 0xe9, 0x22, 0x13, 0xd2, 0x02, 0x1a, 0xf3, 0xfe, 0xea, 0xb3, 0xc5, + 0x06, 0xf7, 0xb8, 0x45, 0xc5, 0x27, 0x00, 0x0d, 0xfb, 0x03, 0x3d, 0xd2, 0xf4, + 0x22, 0xcd, 0x23, 0xf7, 0x29, 0x06, 0x9d, 0x26, 0xfd, 0x0f, 0x1a, 0x30, 0x14, + 0x3e, 0xcc, 0xee, 0xe2, 0xba, 0x0d, 0x07, 0x02, 0x68, 0x30, 0xf8, 0x24, 0xe7, + 0x06, 0xdd, 0xed, 0xf2, 0xf2, 0x7f, 0x0f, 0x1c, 0xec, 0x3a, 0xfa, 0x01, 0x18, + 0x03, 0x1e, 0xf4, 0x01, 0xde, 0xfd, 0xe1, 0xf4, 0x08, 0x0a, 0x09, 0xf9, 0x19, + 0x23, 0xff, 0x2e, 0x00, 0xf3, 0xee, 0xf3, 0xf9, 0x03, 0xe4, 0x23, 0xfe, 0x29, + 0x0c, 0x12, 0xec, 0x21, 0x04, 0x03, 0x0c, 0x20, 0x08, 0x23, 0x1e, 0x40, 0xee, + 0x1e, 0x14, 0x08, 0x08, 0x03, 0x0a, 0xfe, 0xdf, 0x00, 0x19, 0xff, 0xf3, 0x04, + 0x0a, 0xf2, 0x01, 0x1e, 0x19, 0x0a, 0x23, 0x09, 0x21, 0xee, 0xff, 0x00, 0x01, + 0x03, 0xfa, 0x1a, 0xfd, 0xf3, 0x0c, 0xee, 0x14, 0x08, 0x0e, 0x03, 0x15, 0xf3, + 0xfe, 0xe9, 0x01, 0xd7, 0x03, 0x03, 0xf0, 0x2c, 0x3a, 0x03, 0x03, 0x04, 0x0b, + 0xe4, 0x05, 0xeb, 0x34, 0xff, 0x00, 0x25, 0x21, 0xdb, 0xd4, 0x0b, 0xd8, 0x06, + 0xec, 0xfe, 0x05, 0x04, 0x04, 0x1c, 0xf2, 0xd9, 0xfb, 0x09, 0xc1, 0xaa, 0x13, + 0x1c, 0x54, 0x8d, 0xcb, 0xd9, 0xc4, 0x1e, 0xc4, 0x21, 0x1f, 0xd4, 0xd7, 0x00, + 0x1a, 0xef, 0xfc, 0x0f, 0x4e, 0x02, 0x10, 0xe8, 0xcf, 0xb2, 0xdd, 0x21, 0x2f, + 0xf4, 0xbe, 0xe3, 0xfb, 0xea, 0xdf, 0x98, 0x03, 0xf0, 0x7f, 0x7c, 0x57, 0x15, + 0xfb, 0x0e, 0xda, 0xd0, 0x5a, 0x20, 0xf6, 0x3a, 0xfb, 0x4a, 0xec, 0xf5, 0xee, + 0x0c, 0xf8, 0xeb, 0xc8, 0xed, 0x03, 0xee, 0x27, 0x28, 0x08, 0xe9, 0xfd, 0x6b, + 0xcf, 0xf3, 0x48, 0x06, 0xba, 0xc5, 0x9d, 0xf3, 0xc6, 0x19, 0xd7, 0xa5, 0x27, + 0x40, 0x27, 0x2b, 0x16, 0x2c, 0xc5, 0x11, 0xe6, 0x23, 0x13, 0xf7, 0xe9, 0x21, + 0x77, 0xab, 0xcd, 0xed, 0x44, 0xfa, 0xeb, 0xca, 0x04, 0xf3, 0xdb, 0xb4, 0xd2, + 0xd5, 0xe0, 0xf4, 0xd4, 0xfa, 0xa4, 0x1c, 0xd7, 0xd1, 0x88, 0xd2, 0x14, 0xcf, + 0x10, 0x0c, 0x05, 0x3d, 0x26, 0x0b, 0x1e, 0xd9, 0xcf, 0x0e, 0xca, 0x01, 0x36, + 0xfe, 0x22, 0xd5, 0x37, 0xd6, 0xd0, 0xbf, 0x19, 0xc9, 0xc9, 0xde, 0x08, 0xb8, + 0x07, 0xf6, 0x2e, 0xdd, 0x10, 0x2e, 0xf8, 0x0e, 0xcb, 0x93, 0xbb, 0xbf, 0x2a, + 0x1d, 0x50, 0x01, 0x0a, 0xdc, 0x2c, 0xed, 0x08, 0xcc, 0x87, 0x5d, 0x1d, 0xee, + 0xed, 0xd0, 0xfb, 0x7f, 0xd5, 0x47, 0x24, 0xa5, 0xd3, 0xe7, 0x02, 0x25, 0xd3, + 0x17, 0xe2, 0xf5, 0xf5, 0xe6, 0xf3, 0x40, 0xca, 0x18, 0xda, 0x4c, 0x01, 0xdf, + 0x67, 0xf2, 0xdf, 0x18, 0x39, 0xf6, 0x12, 0xa3, 0x21, 0xcd, 0x21, 0x62, 0x55, + 0x07, 0x7b, 0xde, 0xea, 0x08, 0xe3, 0xce, 0x00, 0xfe, 0xf6, 0xc4, 0x4f, 0xf3, + 0x39, 0xff, 0xea, 0x31, 0x7e, 0x24, 0xf3, 0xc2, 0x47, 0xaf, 0x10, 0x09, 0x34, + 0xd0, 0xc9, 0xf0, 0x4e, 0xf1, 0x06, 0x1d, 0x58, 0x07, 0x4b, 0x01, 0x0b, 0xd1, + 0x25, 0xe8, 0x0a, 0x40, 0xc4, 0x2f, 0xfd, 0xf9, 0xe5, 0xcf, 0xea, 0x09, 0x00, + 0x1e, 0x07, 0xdd, 0x50, 0x0c, 0xfa, 0xd8, 0x64, 0xe7, 0xdd, 0x0d, 0x1b, 0x06, + 0xcb, 0x7f, 0xf4, 0x18, 0x11, 0x15, 0xe8, 0xdf, 0xeb, 0x03, 0xe0, 0x30, 0x0d, + 0x00, 0xba, 0xe9, 0xe1, 0xb5, 0x05, 0xfb, 0xce, 0xea, 0x3d, 0xc7, 0xd0, 0xd7, + 0x26, 0xde, 0xcc, 0xfb, 0x32, 0xed, 0xdb, 0xec, 0x16, 0x0e, 0x4e, 0x27, 0xfe, + 0x1a, 0x25, 0x15, 0x24, 0xde, 0x0c, 0x20, 0xe3, 0x38, 0xde, 0x0d, 0xf2, 0x22, + 0xd9, 0x2d, 0x47, 0xb7, 0x08, 0xf7, 0xcc, 0x12, 0x13, 0xd6, 0x3a, 0x1b, 0xc4, + 0xaa, 0x06, 0xf7, 0xf2, 0xf0, 0x14, 0xeb, 0x0a, 0xfe, 0x2b, 0xf1, 0x0a, 0x07, + 0x1c, 0xf1, 0xf4, 0x36, 0xba, 0xe2, 0x5c, 0x1a, 0x36, 0xd7, 0xf8, 0xfd, 0x35, + 0xf2, 0xf1, 0x2f, 0x08, 0x07, 0xde, 0x00, 0x39, 0x08, 0xe0, 0xe5, 0x1b, 0xc8, + 0xe9, 0x40, 0xc1, 0xe8, 0x17, 0x18, 0x07, 0x28, 0xd0, 0xc5, 0xd7, 0xf0, 0xc3, + 0x0a, 0xb7, 0xe3, 0x49, 0x2c, 0x15, 0xdb, 0xd8, 0xed, 0x11, 0xc4, 0x96, 0xf5, + 0x19, 0x22, 0x23, 0x05, 0xd7, 0xfa, 0x5e, 0xd6, 0xcc, 0xb0, 0xf5, 0xd4, 0xc0, + 0xff, 0x06, 0x5c, 0xef, 0x0d, 0xe2, 0x29, 0x0b, 0xc1, 0xe1, 0x0d, 0x2d, 0xe6, + 0x04, 0xd3, 0xd8, 0xc0, 0x2c, 0x0b, 0x43, 0x15, 0x09, 0x1b, 0xd5, 0x29, 0xde, + 0xf4, 0x0f, 0x01, 0xf1, 0x04, 0xfb, 0x05, 0x0f, 0xad, 0x26, 0xe7, 0xf1, 0x34, + 0x08, 0xfc, 0xf8, 0x1c, 0xcb, 0xf9, 0x3d, 0x04, 0xf0, 0xf1, 0xd4, 0x02, 0x42, + 0x3b, 0x31, 0x39, 0x1d, 0xe3, 0x30, 0xfc, 0x1f, 0xd5, 0xfd, 0x36, 0x34, 0x00, + 0x3a, 0x0f, 0x0c, 0xd8, 0x53, 0x0a, 0xef, 0x11, 0x1c, 0x7f, 0xaf, 0xd0, 0xfe, + 0x06, 0x05, 0x66, 0xd2, 0xe3, 0xe0, 0xe0, 0x2b, 0xf1, 0xe0, 0xe1, 0x45, 0x56, + 0x12, 0xde, 0xf8, 0x1a, 0xfc, 0x07, 0xcd, 0x0e, 0x03, 0x16, 0x70, 0x2e, 0x30, + 0x35, 0xac, 0x8e, 0x10, 0x14, 0xdd, 0x35, 0x4f, 0x16, 0xfa, 0xeb, 0x0c, 0xf3, + 0xe2, 0x26, 0xbd, 0xfc, 0xd6, 0x2b, 0x92, 0x4d, 0xfa, 0xfa, 0x03, 0xf9, 0xd6, + 0xf2, 0x3a, 0xcc, 0xcc, 0xe0, 0xe9, 0xe7, 0x0f, 0x04, 0xfa, 0xd9, 0xea, 0xe2, + 0xd9, 0x0d, 0xf4, 0xbb, 0xfd, 0x17, 0xfa, 0x29, 0xee, 0xf1, 0x7f, 0xc5, 0xd0, + 0x04, 0x08, 0xeb, 0x14, 0x18, 0xe2, 0x01, 0xca, 0xfc, 0xe2, 0xfc, 0x47, 0x4b, + 0x1c, 0x46, 0xcc, 0x19, 0x08, 0xb8, 0xe4, 0xff, 0x28, 0x3c, 0xfc, 0x25, 0xfe, + 0xc9, 0x03, 0xd9, 0x27, 0xe8, 0x0c, 0x14, 0xda, 0xf7, 0x20, 0xf3, 0x0a, 0x2e, + 0x1d, 0x28, 0xeb, 0x1c, 0x03, 0x18, 0xde, 0xec, 0x42, 0x67, 0x09, 0x16, 0x43, + 0xc6, 0xfe, 0xeb, 0x0e, 0x01, 0xce, 0xe6, 0xe5, 0x01, 0x46, 0x05, 0xef, 0x0c, + 0xe2, 0xe5, 0xe1, 0x9a, 0x27, 0xe8, 0xdf, 0xe6, 0x35, 0xc1, 0x10, 0xf7, 0xcd, + 0x2e, 0x00, 0xda, 0xfd, 0xd8, 0xf8, 0xea, 0x7f, 0xb8, 0xdf, 0xd9, 0xa9, 0x2e, + 0x03, 0xfa, 0xfb, 0xf3, 0x20, 0x1a, 0x64, 0xe2, 0x2c, 0xf7, 0xf7, 0xf8, 0xef, + 0x65, 0xee, 0xe3, 0xc9, 0xf3, 0xf4, 0xdb, 0xf6, 0x65, 0xe3, 0x1d, 0xb0, 0xc7, + 0xdf, 0x00, 0xc7, 0xf8, 0xde, 0x2d, 0xe9, 0x08, 0x3b, 0xde, 0x38, 0x54, 0x06, + 0x22, 0x10, 0xf3, 0x62, 0x0e, 0x43, 0x20, 0x22, 0xe7, 0xd2, 0xfa, 0x3c, 0xe0, + 0xef, 0xe4, 0x39, 0x42, 0x2b, 0xe5, 0x31, 0xf4, 0xe9, 0xfa, 0xcf, 0x37, 0x0c, + 0xf7, 0x18, 0x11, 0xc2, 0x15, 0x3e, 0x24, 0x25, 0x2a, 0xef, 0xf3, 0xe0, 0xd4, + 0x44, 0xff, 0xf8, 0xc4, 0x20, 0xff, 0x0f, 0x07, 0x68, 0xf7, 0x1c, 0x16, 0xa4, + 0x22, 0x0f, 0xda, 0xf4, 0x42, 0xea, 0xee, 0x79, 0x4c, 0x07, 0x1f, 0xe1, 0xd8, + 0x03, 0xfb, 0xf2, 0xf7, 0x05, 0xea, 0x40, 0xf4, 0x1c, 0x3d, 0x1b, 0x11, 0x12, + 0x13, 0x20, 0x47, 0x34, 0x40, 0x19, 0xdf, 0xd1, 0xe1, 0x3e, 0x07, 0x1e, 0x34, + 0xf3, 0x2b, 0x0d, 0xd8, 0x22, 0xea, 0x11, 0x23, 0x03, 0x19, 0xda, 0xf6, 0xf9, + 0x38, 0xcd, 0x06, 0x48, 0xe6, 0x37, 0x46, 0x1a, 0x1b, 0x01, 0x28, 0xf9, 0xed, + 0xfd, 0xea, 0xf2, 0x30, 0x01, 0xe7, 0x0a, 0x0a, 0x22, 0x32, 0xe4, 0x47, 0xdd, + 0x02, 0x23, 0x29, 0x58, 0x22, 0x22, 0xcf, 0xd8, 0x55, 0x44, 0xc2, 0x07, 0x20, + 0xe1, 0x3c, 0xf0, 0x79, 0x13, 0x06, 0x04, 0xfd, 0x01, 0xf3, 0xf0, 0x13, 0xf3, + 0xdb, 0x10, 0xee, 0x29, 0xf7, 0x2e, 0x42, 0x1a, 0xdb, 0xea, 0xeb, 0x02, 0xed, + 0x02, 0xe5, 0x51, 0x0e, 0xf0, 0x12, 0x7f, 0xd8, 0x14, 0xef, 0x45, 0xf7, 0xe9, + 0xce, 0x23, 0x16, 0x16, 0x43, 0x00, 0xec, 0xf2, 0xda, 0xcc, 0x4b, 0xf3, 0x3b, + 0xd5, 0xe8, 0x32, 0xe5, 0x39, 0xe0, 0xc1, 0x56, 0xdb, 0x11, 0xf1, 0xe8, 0x35, + 0x07, 0x1a, 0xd6, 0x25, 0xa4, 0x30, 0xf2, 0xf4, 0xc7, 0x19, 0x69, 0x54, 0xfc, + 0xa8, 0x23, 0xfd, 0xee, 0x07, 0x01, 0xd0, 0xaf, 0x28, 0xfd, 0xdf, 0x20, 0x81, + 0x19, 0x36, 0x03, 0xf2, 0x0f, 0x0d, 0x28, 0xce, 0xc4, 0xc1, 0xc6, 0x26, 0xc9, + 0xe8, 0xa0, 0xe4, 0x8e, 0xd2, 0x24, 0xda, 0xf7, 0xfd, 0xa3, 0xf8, 0xfc, 0xb0, + 0x08, 0x2b, 0x2c, 0x0d, 0x19, 0x17, 0x1b, 0xa3, 0x77, 0x76, 0xfc, 0xdd, 0x2e, + 0x0e, 0xf3, 0xc0, 0x6c, 0x1f, 0xd5, 0x06, 0xb9, 0xe5, 0xd7, 0x00, 0x03, 0xc7, + 0xbd, 0x13, 0x3e, 0xe0, 0x34, 0x0a, 0x36, 0xed, 0x2c, 0xd0, 0xe4, 0xa3, 0x16, + 0xdd, 0xc0, 0x1f, 0xfa, 0xbc, 0xb2, 0x14, 0xf3, 0xea, 0xf7, 0xd6, 0xe9, 0xe6, + 0xf6, 0x23, 0x2d, 0x00, 0xb8, 0xeb, 0x40, 0x17, 0x12, 0x77, 0xd1, 0xc4, 0x01, + 0x11, 0x46, 0xd1, 0x52, 0x36, 0x4c, 0xef, 0x05, 0xe0, 0x29, 0xc1, 0x6b, 0x14, + 0x04, 0x1d, 0x07, 0x2a, 0x41, 0x04, 0x15, 0x1e, 0x25, 0x04, 0x0d, 0x41, 0xe0, + 0xf6, 0xfc, 0xf5, 0xe6, 0xe7, 0x07, 0x37, 0x30, 0x30, 0x27, 0x47, 0xe7, 0xec, + 0x33, 0x00, 0x22, 0x08, 0x02, 0x1c, 0x26, 0x6a, 0xf9, 0x1c, 0xb8, 0xc9, 0xda, + 0xe0, 0xfc, 0xfa, 0x1c, 0xeb, 0x31, 0xf3, 0xc6, 0x22, 0x1b, 0xf6, 0x04, 0xd0, + 0x10, 0xe7, 0x36, 0x0f, 0x7f, 0x08, 0x1d, 0x03, 0xde, 0xc1, 0x30, 0x30, 0x1e, + 0x08, 0xbd, 0xcc, 0x29, 0xe2, 0x06, 0x21, 0xe3, 0xd7, 0x59, 0xe9, 0xcd, 0xf0, + 0x17, 0x07, 0x31, 0xc3, 0xbb, 0xcf, 0xfa, 0x14, 0xe1, 0x67, 0xea, 0x15, 0x0b, + 0x08, 0x23, 0x37, 0x33, 0xdb, 0x29, 0xc0, 0x0e, 0x1f, 0xef, 0xfd, 0x0c, 0x59, + 0x13, 0x1d, 0x71, 0xfa, 0x1b, 0x02, 0xe3, 0xe7, 0xde, 0xcf, 0x54, 0xff, 0x2b, + 0xdd, 0x33, 0x3d, 0xd6, 0xed, 0xb0, 0xd8, 0xe3, 0x0b, 0x0c, 0xfe, 0x3c, 0x0a, + 0x10, 0xf7, 0xd5, 0x48, 0x20, 0xc4, 0xdf, 0x04, 0xe6, 0x12, 0x20, 0x01, 0x38, + 0xfe, 0xd8, 0xea, 0x57, 0xde, 0x9a, 0x45, 0xe4, 0x16, 0x1f, 0x59, 0x17, 0x23, + 0xda, 0x0c, 0xfb, 0xe1, 0x33, 0xe5, 0xcd, 0xd7, 0x17, 0xe6, 0xe1, 0xc5, 0xff, + 0x9a, 0xd3, 0xc8, 0xe6, 0xf5, 0xdf, 0xd5, 0xd5, 0xfc, 0x19, 0xe3, 0x27, 0xb5, + 0xf5, 0xed, 0x27, 0xff, 0xe0, 0xd7, 0x34, 0x0f, 0xe2, 0xd2, 0xfa, 0x08, 0x00, + 0x57, 0xcf, 0xe7, 0xf4, 0x20, 0x09, 0x0f, 0x7f, 0x07, 0x42, 0xda, 0xfc, 0xf9, + 0x0a, 0xdf, 0xda, 0xf7, 0x23, 0xd3, 0x2a, 0x04, 0x04, 0x0b, 0xc2, 0x0e, 0x0d, + 0xf4, 0x13, 0x06, 0xf4, 0x25, 0xe6, 0xf5, 0xed, 0xd3, 0x0e, 0xa7, 0xee, 0xed, + 0x1b, 0x05, 0x3f, 0x4c, 0x1c, 0xd0, 0x34, 0xb3, 0x3a, 0xf8, 0xf4, 0x45, 0x3f, + 0x24, 0xc4, 0xaa, 0xf1, 0xc1, 0x16, 0x0d, 0xf0, 0x5d, 0x2d, 0x2d, 0xeb, 0xfc, + 0xe8, 0xf1, 0x18, 0x0e, 0x22, 0x28, 0xd1, 0xb4, 0x3c, 0x0b, 0xfc, 0x18, 0x11, + 0xe0, 0xfc, 0xe2, 0x3e, 0x01, 0x43, 0xdf, 0x02, 0x72, 0x05, 0x20, 0xec, 0xd3, + 0xc3, 0xfa, 0x35, 0xe5, 0xf7, 0xf7, 0xd9, 0xde, 0xf2, 0xf0, 0xc3, 0xfb, 0xfa, + 0xb7, 0x04, 0x01, 0xc2, 0x55, 0xb4, 0xfa, 0x04, 0xf0, 0x02, 0xa5, 0x2d, 0xe6, + 0x37, 0xb7, 0x16, 0xb1, 0xca, 0x1e, 0xc9, 0xd0, 0x47, 0x1b, 0x2e, 0x52, 0x2f, + 0xbf, 0xd7, 0x06, 0xa3, 0xde, 0x33, 0xef, 0xa4, 0x01, 0x5f, 0xd8, 0xe9, 0xb3, + 0x3d, 0xf8, 0x35, 0x2e, 0xf7, 0x13, 0x27, 0xde, 0xd2, 0x70, 0x1b, 0xd0, 0x12, + 0xfb, 0xac, 0xf0, 0xed, 0xd9, 0xc2, 0xe7, 0x15, 0x05, 0xc8, 0x0e, 0x81, 0x08, + 0x07, 0x12, 0xbc, 0xcb, 0x4a, 0x00, 0xee, 0xd5, 0xdd, 0xd8, 0x2b, 0x2b, 0x0c, + 0x39, 0xc7, 0xf7, 0xc2, 0x30, 0xd1, 0x1c, 0x0c, 0x20, 0x30, 0x0d, 0x26, 0x3e, + 0x2a, 0x28, 0xcf, 0x0e, 0x01, 0x7f, 0xe2, 0xf5, 0xc3, 0x28, 0x05, 0x20, 0x08, + 0xf2, 0x10, 0x04, 0xf7, 0xed, 0xd8, 0x43, 0xf3, 0xf7, 0xd4, 0x2b, 0x26, 0xdd, + 0xe1, 0x51, 0xf2, 0x3f, 0x39, 0xaa, 0xf6, 0x24, 0xd6, 0x2c, 0x15, 0xde, 0xf4, + 0xf9, 0xf6, 0x17, 0xdd, 0x1d, 0xe7, 0xf8, 0x02, 0xd2, 0xbd, 0xe4, 0x13, 0x0c, + 0x42, 0x12, 0x1e, 0x09, 0xfb, 0x40, 0x3c, 0x1f, 0xe2, 0xdc, 0x09, 0x1c, 0x12, + 0x4d, 0x3e, 0x16, 0x37, 0x0a, 0x37, 0x15, 0xf0, 0x24, 0xd1, 0xbb, 0xe7, 0x07, + 0xe3, 0xd8, 0xc9, 0x4f, 0xc1, 0x04, 0x05, 0xd4, 0x1d, 0xae, 0xc1, 0xcc, 0x15, + 0x0d, 0x07, 0x0e, 0x13, 0xcf, 0x0b, 0x07, 0x01, 0x0e, 0xf7, 0xc4, 0x1a, 0x36, + 0xea, 0x15, 0xed, 0xe3, 0x15, 0x7f, 0x2d, 0x2d, 0xf6, 0x10, 0xdd, 0xe4, 0xdf, + 0xf8, 0xf2, 0xe7, 0x06, 0x5d, 0xff, 0xc0, 0x04, 0x06, 0xdb, 0x2e, 0xf5, 0xc1, + 0x52, 0xd1, 0x04, 0xe1, 0x28, 0xdb, 0x15, 0x03, 0x17, 0xda, 0x10, 0xe6, 0x35, + 0xe6, 0xcc, 0xea, 0x33, 0x46, 0x04, 0xc9, 0xd0, 0x4c, 0xf4, 0xfc, 0x64, 0x30, + 0xe0, 0x48, 0xc0, 0x17, 0xd0, 0x1c, 0xdb, 0xfa, 0xe4, 0xf4, 0x1d, 0xe1, 0xb4, + 0x17, 0x13, 0xe0, 0xff, 0xf6, 0xc2, 0x24, 0xea, 0x61, 0x34, 0xf7, 0xfe, 0x1f, + 0xf3, 0xfd, 0xb0, 0x3a, 0xe1, 0xeb, 0x6c, 0x1d, 0x17, 0xf3, 0xec, 0x17, 0xda, + 0xf0, 0x21, 0xf4, 0x00, 0xe5, 0x3d, 0xe3, 0x16, 0x03, 0x07, 0xd3, 0xec, 0x11, + 0x26, 0xde, 0xe1, 0xbb, 0xd8, 0x04, 0x2a, 0x24, 0x11, 0xeb, 0x3c, 0x25, 0x1f, + 0xf3, 0x10, 0xed, 0x2e, 0x3f, 0xff, 0xa3, 0xdf, 0x3a, 0x49, 0xe4, 0xdd, 0x1f, + 0xf1, 0xc8, 0x60, 0xec, 0xe7, 0xe9, 0x36, 0xe9, 0x08, 0xf9, 0xcf, 0xeb, 0x03, + 0x04, 0x17, 0x38, 0xdb, 0xe1, 0x10, 0x11, 0xdf, 0xfe, 0xe9, 0x2f, 0xe0, 0xed, + 0xfc, 0xc0, 0xfd, 0xff, 0xea, 0xdd, 0xd9, 0xdb, 0x25, 0xf9, 0x2a, 0x2f, 0xe7, + 0x1f, 0x31, 0xec, 0xef, 0x71, 0x16, 0x54, 0xe5, 0x03, 0x1d, 0xf8, 0x22, 0xf8, + 0x0e, 0x00, 0x18, 0xf4, 0x03, 0x05, 0x0c, 0x02, 0x29, 0xfb, 0xe3, 0xe3, 0x27, + 0x1c, 0x30, 0x15, 0x35, 0xe6, 0x1d, 0x42, 0xf9, 0xe3, 0xfe, 0xeb, 0xec, 0x19, + 0xb7, 0xf9, 0x02, 0x1c, 0xd3, 0xff, 0xf5, 0xf3, 0x17, 0x0a, 0xfd, 0x08, 0x7f, + 0xf9, 0xfd, 0x06, 0x30, 0xdd, 0x1e, 0xf0, 0x0c, 0x1e, 0x3b, 0xff, 0xf2, 0x2a, + 0xfe, 0x15, 0xde, 0xcf, 0x2c, 0xf9, 0x0d, 0xff, 0x02, 0x01, 0xeb, 0xe9, 0x19, + 0xfe, 0x39, 0x31, 0x03, 0xe1, 0x00, 0x15, 0xea, 0xda, 0x00, 0xca, 0xf7, 0x3f, + 0xfc, 0xfe, 0x13, 0x03, 0xf2, 0xe5, 0x3e, 0x14, 0x44, 0xdf, 0x07, 0x38, 0x05, + 0xda, 0xe0, 0x15, 0x3b, 0x1b, 0x02, 0xe0, 0x06, 0x7f, 0x46, 0x29, 0xf3, 0x0f, + 0xeb, 0x14, 0xf6, 0x0f, 0x07, 0x1a, 0xd8, 0x09, 0xff, 0xee, 0xd4, 0x1e, 0x41, + 0xeb, 0xdf, 0xdb, 0x01, 0xae, 0x1c, 0x35, 0xe0, 0xea, 0xe4, 0xcd, 0xfe, 0x08, + 0xeb, 0xfa, 0x2f, 0x00, 0x09, 0x24, 0x0b, 0x02, 0x15, 0xed, 0x5d, 0xe6, 0x00, + 0x11, 0xfa, 0x34, 0x12, 0xd6, 0xca, 0xc3, 0xd2, 0x31, 0xde, 0xce, 0x29, 0x15, + 0xdc, 0xd0, 0xfc, 0xc8, 0x3b, 0x0f, 0xf9, 0xd5, 0xe4, 0x06, 0xc8, 0x31, 0xfd, + 0x13, 0xf3, 0xf6, 0x1e, 0xf9, 0xec, 0x39, 0xbd, 0x77, 0xdf, 0xde, 0xd3, 0xb6, + 0x51, 0xf0, 0xb0, 0x07, 0xf0, 0xde, 0x11, 0xb8, 0xda, 0x24, 0xe6, 0x23, 0xd4, + 0xec, 0x21, 0x56, 0xb5, 0xbc, 0x13, 0x2c, 0x21, 0x06, 0x03, 0x06, 0xf8, 0x2b, + 0x14, 0x31, 0xc5, 0x65, 0x40, 0xbc, 0xe9, 0x9b, 0x18, 0xe6, 0x0d, 0xf8, 0xf2, + 0x07, 0xf4, 0xea, 0x01, 0x26, 0x46, 0xe4, 0x1b, 0xfb, 0x0e, 0xd0, 0x43, 0x40, + 0xe1, 0xe8, 0x33, 0xc5, 0x44, 0xe9, 0x81, 0xf5, 0xe3, 0xe2, 0x08, 0x0a, 0x40, + 0x14, 0x2c, 0xd6, 0xd9, 0xed, 0xee, 0x54, 0x02, 0xcf, 0xfe, 0x1a, 0xcf, 0xf5, + 0x1d, 0x26, 0xfe, 0xca, 0x30, 0xc5, 0xd8, 0x33, 0x9c, 0xed, 0x1f, 0xf2, 0xdf, + 0xd4, 0x63, 0xdf, 0x20, 0xbf, 0xf8, 0x3c, 0x27, 0xd1, 0xde, 0x00, 0x32, 0xdf, + 0xc2, 0xb4, 0x09, 0xdd, 0x03, 0x0f, 0x0c, 0x08, 0x9c, 0xd2, 0xe0, 0x5a, 0xf8, + 0xb3, 0xe6, 0x15, 0x14, 0xf0, 0x0f, 0x29, 0x11, 0xd8, 0x15, 0x32, 0xda, 0x04, + 0xba, 0xe4, 0xee, 0x44, 0xf2, 0xae, 0x22, 0x25, 0xe0, 0xc2, 0xe7, 0x54, 0xfd, + 0x2d, 0x93, 0x30, 0x1c, 0xf3, 0x49, 0x37, 0xbe, 0x1a, 0xb9, 0x68, 0xec, 0x06, + 0x0b, 0x33, 0xb7, 0xc4, 0xd0, 0x1a, 0xf4, 0x09, 0x13, 0x0c, 0x27, 0xe5, 0x07, + 0xae, 0xf4, 0x20, 0xea, 0xf1, 0xfc, 0xd4, 0x03, 0x3b, 0x35, 0xc4, 0xdd, 0xc4, + 0xf4, 0xea, 0x2f, 0xfb, 0x85, 0x66, 0x02, 0xce, 0x1c, 0xf1, 0xa5, 0x2b, 0xe6, + 0xf8, 0xd7, 0xde, 0xd7, 0xc6, 0x02, 0x81, 0x22, 0x3b, 0xd7, 0x9c, 0x37, 0x20, + 0xe2, 0xee, 0xfe, 0xee, 0x21, 0x0a, 0xe6, 0x0e, 0x18, 0xf7, 0x50, 0x11, 0xe7, + 0x45, 0xa7, 0xd6, 0x07, 0xe8, 0x1b, 0xe1, 0x38, 0xac, 0x04, 0xf6, 0xba, 0x01, + 0xec, 0xec, 0xea, 0xfd, 0xfc, 0x00, 0x51, 0x32, 0xf9, 0xa5, 0xc8, 0xe5, 0xd4, + 0x05, 0x31, 0x04, 0x1e, 0xe0, 0xf0, 0xeb, 0x0e, 0x55, 0xf5, 0x3c, 0x13, 0xe3, + 0x43, 0x1b, 0xb0, 0x30, 0xec, 0x58, 0xda, 0x3f, 0x01, 0x06, 0xc5, 0x1e, 0x58, + 0x27, 0xcb, 0x13, 0x22, 0x67, 0x25, 0xf6, 0x03, 0x0e, 0xeb, 0xcb, 0x10, 0x2f, + 0xdd, 0x0a, 0x06, 0xf8, 0x0e, 0x01, 0x32, 0xf2, 0xdc, 0xf3, 0xc2, 0x4e, 0xfd, + 0xae, 0xc7, 0x5a, 0x13, 0xfb, 0xc4, 0xd0, 0x35, 0x41, 0x15, 0xf6, 0xdf, 0xef, + 0x17, 0x52, 0xc8, 0xdc, 0xf9, 0xc7, 0x51, 0xf8, 0xc2, 0xd2, 0x45, 0x49, 0xde, + 0xe4, 0x58, 0xad, 0x08, 0x0d, 0x26, 0xf4, 0xc8, 0xd3, 0xe6, 0xb3, 0xf7, 0xfa, + 0x16, 0x0f, 0xcf, 0xdf, 0xf5, 0x0e, 0x0f, 0xe4, 0x14, 0xeb, 0x2c, 0x81, 0xfd, + 0xef, 0xf9, 0x4a, 0xf9, 0xfa, 0x01, 0x9a, 0xe2, 0xa3, 0x5b, 0x14, 0x63, 0xe2, + 0xd9, 0xe0, 0xe8, 0xfc, 0x00, 0xf5, 0xdf, 0x07, 0x65, 0xd4, 0x14, 0x10, 0x21, + 0xd9, 0x00, 0xa9, 0x14, 0x2d, 0x05, 0x13, 0xdb, 0x05, 0x27, 0x39, 0xe2, 0x17, + 0xcd, 0xf3, 0xf5, 0xeb, 0xc2, 0xd0, 0xe3, 0x1d, 0xd8, 0x06, 0xfd, 0xc9, 0xcb, + 0x4c, 0xf7, 0xd6, 0xff, 0x0c, 0x28, 0x02, 0x08, 0xbc, 0x31, 0xdb, 0x37, 0xe3, + 0xf7, 0x81, 0x2e, 0xd1, 0xc7, 0x00, 0x41, 0xd2, 0xc4, 0x13, 0x12, 0x04, 0x0e, + 0x19, 0xee, 0xd6, 0x3c, 0x4d, 0xe4, 0xe2, 0x1f, 0x28, 0x04, 0xd7, 0x3d, 0xf5, + 0xcb, 0xeb, 0xb1, 0x1e, 0xbb, 0x17, 0xee, 0x36, 0x2c, 0xf8, 0x15, 0x09, 0xfd, + 0x33, 0xc4, 0xc2, 0xf2, 0xd5, 0xf9, 0xbe, 0x0c, 0xbc, 0x50, 0xb9, 0xed, 0xc4, + 0xd6, 0xdd, 0xed, 0x13, 0x06, 0xfe, 0x1d, 0x0d, 0xf5, 0xa3, 0x0d, 0xd3, 0x6b, + 0xe6, 0xff, 0x65, 0x29, 0xb4, 0x0e, 0xf0, 0xec, 0xe1, 0x1b, 0xee, 0xe4, 0xeb, + 0xf5, 0xec, 0x7b, 0x24, 0x2b, 0x26, 0x06, 0xc8, 0x27, 0x04, 0xfe, 0x2d, 0x12, + 0xa1, 0xe0, 0xe2, 0x18, 0x43, 0x24, 0x57, 0x1f, 0x0a, 0x1c, 0xfc, 0x1b, 0xe5, + 0xdd, 0x1d, 0xe0, 0xf5, 0x16, 0xe0, 0xf0, 0xef, 0xb0, 0x26, 0xdd, 0x17, 0xcf, + 0xe7, 0x0e, 0x11, 0xf7, 0xdf, 0x34, 0x21, 0xfd, 0xbc, 0xd4, 0x07, 0x0b, 0x10, + 0x3a, 0xbb, 0xdb, 0xdc, 0x31, 0x56, 0xfb, 0xf8, 0xff, 0x60, 0x04, 0xb5, 0x7f, + 0xdf, 0xfd, 0x06, 0x2c, 0xd8, 0xea, 0x16, 0xbd, 0xe1, 0x2a, 0x0c, 0xd4, 0xf6, + 0x44, 0x05, 0xd4, 0x19, 0xe1, 0xb8, 0xe8, 0x04, 0x06, 0xd6, 0xcc, 0x53, 0xdb, + 0xef, 0xfe, 0xd1, 0xf0, 0xe5, 0xfa, 0xc1, 0xc1, 0x1a, 0xbf, 0xea, 0x07, 0x08, + 0x52, 0x0d, 0xb8, 0x0d, 0x07, 0x26, 0x4e, 0xe0, 0x02, 0x06, 0x08, 0xe8, 0xfe, + 0xc3, 0xea, 0x50, 0x21, 0x05, 0xe5, 0x10, 0xc3, 0x1c, 0xfd, 0xf9, 0x06, 0x1e, + 0xdb, 0x49, 0x22, 0x1c, 0x07, 0xfd, 0xfe, 0x14, 0xea, 0x0e, 0xdf, 0xfb, 0xed, + 0x12, 0xef, 0x0b, 0x79, 0x1c, 0x2d, 0xc7, 0x11, 0x06, 0x1b, 0x0c, 0xf6, 0x07, + 0x21, 0x0d, 0x0f, 0xf6, 0x39, 0xc0, 0x1c, 0x23, 0xfa, 0xe3, 0x1a, 0x1f, 0x1c, + 0x01, 0xcc, 0xd6, 0x3a, 0x12, 0x3d, 0x97, 0x1e, 0x0d, 0x34, 0x16, 0x39, 0x33, + 0x23, 0xe1, 0xd4, 0x2b, 0x11, 0xfd, 0x1e, 0xd2, 0x2c, 0x9f, 0x01, 0x65, 0x10, + 0xca, 0x1f, 0xca, 0xfb, 0xce, 0x06, 0xbe, 0x29, 0x28, 0xea, 0x7f, 0x06, 0xa3, + 0x15, 0xdc, 0x18, 0x1e, 0xe4, 0x61, 0x0c, 0x0d, 0xeb, 0xcf, 0xf9, 0xb4, 0xe1, + 0x12, 0xb3, 0xff, 0x14, 0xe4, 0xc2, 0xe7, 0x02, 0xe7, 0x03, 0x0e, 0x34, 0x7c, + 0x46, 0x3c, 0x3f, 0x05, 0x06, 0x87, 0xba, 0xdf, 0xdb, 0x28, 0x01, 0x1b, 0xdf, + 0xf9, 0xf1, 0xba, 0x0d, 0xe3, 0xe2, 0xc2, 0xf3, 0x0a, 0xf7, 0xd2, 0x39, 0xea, + 0xb4, 0x11, 0x3b, 0xcb, 0x3d, 0xe9, 0xcd, 0xad, 0xcd, 0xac, 0x46, 0xf3, 0x5c, + 0x14, 0x56, 0xd0, 0xcb, 0xee, 0xc3, 0x12, 0x4c, 0x9d, 0xfa, 0xde, 0x03, 0x30, + 0xe7, 0xd0, 0x00, 0x2c, 0x2f, 0x3d, 0xe9, 0x15, 0x51, 0x18, 0x17, 0xe4, 0xf9, + 0x7f, 0x22, 0xd7, 0xfa, 0x1e, 0x10, 0xfc, 0xea, 0x64, 0x4b, 0xff, 0x2e, 0x12, + 0xda, 0xd0, 0xdb, 0x0a, 0x2c, 0x7a, 0xf3, 0x2d, 0x99, 0xab, 0x23, 0x22, 0x16, + 0x45, 0xcb, 0x1d, 0x0b, 0xfe, 0x0f, 0x00, 0x1c, 0xe2, 0xd1, 0xf4, 0xac, 0x73, + 0xec, 0x01, 0x27, 0xf8, 0x50, 0x3b, 0xd5, 0xdb, 0xef, 0x15, 0xfd, 0x19, 0x14, + 0xe4, 0x49, 0xe4, 0x2f, 0xf2, 0x10, 0x0f, 0x0e, 0x01, 0x23, 0x51, 0x1e, 0x23, + 0x46, 0x14, 0xde, 0xf9, 0x23, 0x2f, 0x03, 0xf4, 0x12, 0x18, 0x63, 0xdb, 0xf7, + 0xf7, 0x07, 0xb7, 0xed, 0x2d, 0xbd, 0xea, 0xdb, 0xdd, 0x2f, 0xfe, 0xe8, 0xff, + 0xf5, 0xf3, 0x08, 0xe7, 0x2d, 0x2e, 0xe9, 0x07, 0xdd, 0xca, 0x1d, 0x4b, 0xf8, + 0xd6, 0x0e, 0x6e, 0xce, 0xc3, 0x17, 0x18, 0xe7, 0xf5, 0xde, 0xf9, 0xcd, 0x31, + 0x78, 0xfd, 0x1b, 0x7c, 0x32, 0x40, 0x43, 0x05, 0xdd, 0x03, 0xf6, 0xe7, 0x0a, + 0xc9, 0x27, 0x26, 0xe8, 0x12, 0xd7, 0xf2, 0xc9, 0x07, 0xf6, 0xe1, 0xea, 0xf3, + 0xfd, 0xd9, 0x05, 0xd8, 0x2a, 0x17, 0x18, 0xe6, 0x1b, 0x25, 0x11, 0x12, 0x35, + 0xe1, 0x32, 0x06, 0xfb, 0x12, 0x2b, 0x3b, 0x14, 0xed, 0xd4, 0xe8, 0x09, 0x02, + 0x10, 0x7f, 0xe2, 0xf8, 0xbd, 0xe4, 0xe7, 0xc3, 0xeb, 0xff, 0x13, 0x04, 0xf8, + 0xdd, 0x11, 0xba, 0x27, 0xf4, 0xc7, 0x00, 0xd8, 0x5b, 0x24, 0x60, 0x44, 0xd7, + 0xfe, 0xc8, 0xce, 0x41, 0xe4, 0x27, 0xd5, 0x1b, 0x36, 0xca, 0xe8, 0x4f, 0xdf, + 0x22, 0x15, 0x18, 0x2e, 0x01, 0x06, 0x27, 0xed, 0xe8, 0xff, 0x29, 0x08, 0xd3, + 0x2b, 0xfe, 0xf1, 0xee, 0xfc, 0xe3, 0x15, 0xb6, 0xe8, 0x6d, 0x05, 0xf3, 0x1b, + 0x4f, 0x4f, 0x0c, 0x0b, 0x6c, 0x1c, 0xda, 0xfa, 0xd4, 0xf9, 0x0e, 0x11, 0xf8, + 0xf1, 0x25, 0x32, 0xfc, 0xfc, 0xef, 0x13, 0xf7, 0xf4, 0x23, 0x40, 0xde, 0x2b, + 0x3e, 0x19, 0xe4, 0xf1, 0x2d, 0xf3, 0xf3, 0x0e, 0x2a, 0x3c, 0x1e, 0x20, 0x09, + 0x12, 0x7a, 0x1d, 0x0d, 0x1f, 0x15, 0x35, 0x0e, 0xfd, 0x1e, 0xf0, 0xff, 0x0e, + 0xde, 0x1f, 0x19, 0xe5, 0x20, 0x1d, 0xee, 0xe5, 0x7f, 0x0b, 0x0e, 0xfa, 0xea, + 0xfd, 0xe9, 0xdf, 0x02, 0xe1, 0xec, 0x01, 0x12, 0x00, 0xe7, 0x11, 0x35, 0xf2, + 0xe2, 0xf9, 0xfb, 0xec, 0x08, 0xd9, 0x0f, 0xea, 0xf4, 0xf0, 0xee, 0x02, 0xf3, + 0xf1, 0x38, 0x1d, 0x1c, 0x37, 0xdf, 0x0b, 0xe2, 0x16, 0xf9, 0xfd, 0x09, 0xe8, + 0xed, 0xef, 0x00, 0x0d, 0x17, 0xf7, 0xeb, 0x0c, 0xf2, 0x12, 0xf3, 0xef, 0x39, + 0xfa, 0xd9, 0x02, 0xdf, 0x0a, 0xe5, 0xf2, 0x1c, 0xf7, 0x0e, 0x19, 0x05, 0x21, + 0x04, 0xf9, 0x24, 0xd9, 0xdf, 0xfc, 0xfa, 0x02, 0x34, 0x16, 0x34, 0x21, 0xff, + 0xd7, 0xf2, 0x1f, 0xf1, 0xec, 0x0d, 0xfe, 0xfd, 0xfe, 0x2a, 0x2f, 0xf7, 0x33, + 0xef, 0x4b, 0xce, 0x36, 0xef, 0xd4, 0xee, 0xf5, 0x5c, 0xee, 0x1a, 0xd5, 0xe9, + 0xe0, 0x51, 0xe4, 0xcb, 0x09, 0x43, 0xd4, 0xfb, 0x12, 0x27, 0xe5, 0x17, 0x21, + 0x05, 0x7f, 0x1e, 0x0c, 0xfe, 0xf0, 0xea, 0xda, 0xe9, 0x47, 0xfc, 0x07, 0x0d, + 0xed, 0xdb, 0xd2, 0xdb, 0xfa, 0xe5, 0x13, 0x08, 0x09, 0xf8, 0x15, 0x15, 0x16, + 0xe7, 0xe7, 0x46, 0x24, 0x18, 0xf2, 0x2d, 0xf8, 0xfc, 0x11, 0x02, 0x2c, 0x13, + 0xce, 0xe5, 0xef, 0x1a, 0x49, 0x21, 0xcd, 0xe7, 0xe9, 0xf6, 0x17, 0x2f, 0xfc, + 0xc3, 0x20, 0xf0, 0x07, 0x06, 0xf3, 0x12, 0x0f, 0x1c, 0xf3, 0xd9, 0xfc, 0xf7, + 0x0b, 0xfd, 0xf9, 0x00, 0x0f, 0x1e, 0xf4, 0xd2, 0xdb, 0x0d, 0xdc, 0x07, 0xee, + 0xf6, 0xe8, 0x22, 0xff, 0x30, 0xd3, 0x19, 0x27, 0x2c, 0xfa, 0xfa, 0x4a, 0xf3, + 0x2a, 0xe8, 0xd6, 0x39, 0xe9, 0x04, 0x0b, 0x1b, 0x34, 0xec, 0xf7, 0x3d, 0xa3, + 0x08, 0x5b, 0x26, 0xdc, 0xc2, 0x48, 0xdd, 0x2f, 0x2d, 0xf6, 0x60, 0x02, 0x37, + 0x59, 0xa4, 0x3a, 0x06, 0x02, 0x36, 0xff, 0x16, 0x1e, 0xf2, 0x68, 0x0b, 0x01, + 0x0e, 0xe8, 0xea, 0x30, 0x6a, 0x4d, 0x37, 0x38, 0xfb, 0xdb, 0xf4, 0x2a, 0x0d, + 0xfb, 0x14, 0xef, 0xe7, 0xce, 0x00, 0xeb, 0x0b, 0x05, 0xb8, 0x10, 0xcb, 0x2c, + 0xf5, 0xbf, 0x2f, 0x27, 0x65, 0x6d, 0x0b, 0x9f, 0x27, 0x4b, 0xfe, 0xe3, 0xee, + 0x24, 0xdd, 0x6a, 0xf1, 0xf3, 0xd5, 0x9d, 0x14, 0xdc, 0xf7, 0xfe, 0x15, 0xca, + 0xaa, 0x52, 0xf5, 0x16, 0xdb, 0xdb, 0x47, 0x10, 0x30, 0xcb, 0x0c, 0xf4, 0x00, + 0x0c, 0xf4, 0xb6, 0x7f, 0xc8, 0xe8, 0xe9, 0x23, 0x37, 0x00, 0x09, 0xf0, 0x0b, + 0xf6, 0xe6, 0xf3, 0x30, 0xe7, 0x37, 0x56, 0x45, 0xd3, 0x10, 0xc1, 0xfc, 0xbb, + 0x8c, 0x32, 0x0d, 0x11, 0xb7, 0x6d, 0xdd, 0x18, 0x5b, 0x46, 0x14, 0xc5, 0x17, + 0x2e, 0xf3, 0x2b, 0x02, 0x45, 0xdb, 0x3c, 0x03, 0xbe, 0xf0, 0x3a, 0x7d, 0x37, + 0xdd, 0xb1, 0xb5, 0x2c, 0x06, 0x3c, 0xb6, 0x66, 0xaf, 0x5d, 0x09, 0xdb, 0xf4, + 0xfb, 0x1f, 0xe7, 0xe7, 0x01, 0x21, 0xe9, 0x34, 0xfd, 0x3d, 0xc6, 0xef, 0xe7, + 0x0a, 0x3d, 0x20, 0x54, 0xdf, 0x0b, 0x07, 0x34, 0x96, 0x01, 0x65, 0x24, 0x63, + 0x28, 0x7f, 0x4e, 0x0b, 0x0e, 0xcb, 0x20, 0x46, 0xc5, 0xa7, 0x55, 0x02, 0xc1, + 0x18, 0x0c, 0xda, 0xe3, 0x3b, 0xbd, 0x3a, 0x22, 0x47, 0x10, 0xe5, 0x21, 0xdf, + 0x3b, 0xdd, 0x0f, 0x0e, 0x05, 0xc6, 0x9b, 0x06, 0x66, 0xf0, 0x3a, 0xd6, 0x20, + 0xba, 0xf3, 0x0a, 0xd1, 0xe6, 0x40, 0xe1, 0xe7, 0xf4, 0x1d, 0x05, 0xf1, 0x2c, + 0xef, 0xd0, 0xe1, 0x18, 0x11, 0x1c, 0x5e, 0x27, 0xfd, 0xff, 0xfb, 0xe9, 0xfb, + 0xf1, 0x1a, 0x40, 0x0d, 0x1d, 0x30, 0x3a, 0xdd, 0xde, 0xd2, 0x13, 0xdf, 0x35, + 0xfe, 0xe8, 0xeb, 0x1c, 0x02, 0x24, 0x10, 0x25, 0x00, 0x0a, 0x0d, 0x04, 0xf7, + 0xfb, 0xfd, 0xee, 0xc9, 0x14, 0xd1, 0x27, 0xd4, 0xdd, 0x21, 0xbd, 0xc6, 0x53, + 0xfd, 0xf2, 0x0d, 0xef, 0x0a, 0xf2, 0xe7, 0x0a, 0x1e, 0x1c, 0xe5, 0xff, 0xf5, + 0xed, 0xd9, 0xf8, 0x1e, 0xe2, 0xfd, 0x04, 0xfd, 0xe3, 0x14, 0xe6, 0x1a, 0x7f, + 0x05, 0x2a, 0xf0, 0xf8, 0xf2, 0x07, 0xfa, 0x11, 0xe4, 0xf8, 0xed, 0xe7, 0xfe, + 0xfc, 0xf9, 0xcf, 0x08, 0xe2, 0xf6, 0xea, 0xec, 0x07, 0x13, 0x0f, 0x25, 0x06, + 0xee, 0xdf, 0xf2, 0x19, 0x1e, 0xd5, 0x18, 0x0b, 0xe5, 0xf5, 0x11, 0xfc, 0x0e, + 0x19, 0xf4, 0xf7, 0xf5, 0xf5, 0x0c, 0x00, 0xf5, 0xfe, 0xfd, 0x04, 0xdf, 0xf0, + 0x0f, 0x43, 0xf2, 0xf9, 0x0a, 0xe1, 0x29, 0xea, 0xdf, 0x63, 0xf5, 0x21, 0xc6, + 0xf2, 0xf5, 0x2c, 0xd1, 0x3b, 0x2e, 0xee, 0x12, 0xc1, 0xe8, 0x0b, 0x05, 0x0a, + 0x1d, 0xbf, 0x57, 0xb8, 0xc4, 0xb4, 0xcc, 0x2c, 0x36, 0xda, 0x2a, 0x9e, 0x46, + 0x05, 0x18, 0xe3, 0x0d, 0x18, 0x03, 0x0f, 0xe6, 0x05, 0xe3, 0xd9, 0xd0, 0x2a, + 0xf6, 0x4c, 0x45, 0xe3, 0x25, 0xec, 0xfa, 0x18, 0xef, 0xfb, 0x9f, 0x10, 0xf5, + 0xfc, 0xd6, 0x08, 0x1e, 0x1b, 0xdf, 0x5a, 0x29, 0xf6, 0xe8, 0xfd, 0x3a, 0xfd, + 0x13, 0x0d, 0xfa, 0xa6, 0xf4, 0x32, 0x5a, 0xd4, 0xfa, 0xf9, 0xbe, 0xa4, 0x17, + 0xae, 0xa6, 0xe7, 0x0c, 0xe7, 0x02, 0x75, 0x05, 0x13, 0xc6, 0x48, 0x42, 0xb6, + 0xf0, 0x10, 0xd3, 0x81, 0xd5, 0xd4, 0xc7, 0x09, 0xea, 0x02, 0x6a, 0xd7, 0xdd, + 0xff, 0x2f, 0x17, 0x00, 0x34, 0xfd, 0xfc, 0x0b, 0xf5, 0x1d, 0xf0, 0x7e, 0xf6, + 0xfc, 0xa9, 0xf6, 0x1e, 0x39, 0x3e, 0x05, 0xd6, 0xfe, 0xf1, 0x62, 0x56, 0xba, + 0x79, 0x58, 0x11, 0x07, 0x05, 0x08, 0x14, 0xd8, 0x24, 0xe0, 0xe6, 0x2c, 0x5f, + 0x18, 0x26, 0x3a, 0x24, 0x0f, 0x4c, 0x5e, 0x5a, 0xb0, 0x31, 0x32, 0x24, 0xb8, + 0x11, 0xba, 0x12, 0x26, 0xc2, 0x3a, 0x11, 0x36, 0xea, 0xfd, 0x21, 0xca, 0xe6, + 0x14, 0x0b, 0xe7, 0x37, 0x4d, 0x05, 0x00, 0xea, 0xbb, 0xd5, 0xfc, 0xdb, 0x27, + 0x24, 0xbc, 0xf5, 0xfd, 0x12, 0xef, 0x0b, 0x59, 0xff, 0xdf, 0x03, 0xf0, 0x14, + 0x9e, 0x08, 0x1e, 0xcf, 0xf4, 0x10, 0xdf, 0xd0, 0xc2, 0x8d, 0x29, 0x2e, 0x1b, + 0xf1, 0xdb, 0xee, 0x46, 0xf3, 0x0f, 0xfc, 0xf4, 0xe7, 0xe6, 0x11, 0x9a, 0x2c, + 0xd1, 0xf3, 0xe3, 0xd3, 0x29, 0x16, 0x05, 0x00, 0xed, 0x75, 0xbb, 0x50, 0x4c, + 0x31, 0x2b, 0x67, 0xd7, 0xd8, 0xd0, 0xe5, 0x0e, 0x00, 0x08, 0xea, 0x7f, 0xb1, + 0xc8, 0x0f, 0xfa, 0xf0, 0x12, 0x2b, 0xfe, 0x7f, 0xe1, 0x29, 0x0a, 0x2f, 0x18, + 0xe1, 0xf3, 0xd3, 0x0f, 0x12, 0x08, 0x1d, 0xf4, 0x10, 0x1c, 0xfd, 0x16, 0xc9, + 0x11, 0xa5, 0x1f, 0xce, 0xbd, 0x11, 0xc4, 0xec, 0xeb, 0x09, 0x09, 0x24, 0xdd, + 0x72, 0xf2, 0xf2, 0x30, 0xea, 0x5a, 0x17, 0x17, 0x18, 0x61, 0xd3, 0x21, 0xe0, + 0xe8, 0xd0, 0x47, 0xf1, 0x2b, 0xb4, 0x2d, 0xf2, 0xf0, 0xcf, 0xcc, 0x34, 0xe2, + 0xf7, 0xf8, 0xdc, 0xc5, 0xe7, 0xd1, 0xed, 0x27, 0x2c, 0xa2, 0x0a, 0x6c, 0x51, + 0x0f, 0x48, 0x1b, 0x15, 0x06, 0xc6, 0xce, 0x0f, 0x1b, 0xdb, 0x1c, 0x49, 0x07, + 0xde, 0x16, 0xfb, 0x21, 0x29, 0xec, 0xf1, 0x2c, 0x4c, 0x18, 0xef, 0xe4, 0x01, + 0xdf, 0xfa, 0x29, 0x1b, 0x43, 0x12, 0xde, 0xd0, 0x06, 0x49, 0x42, 0x2a, 0x21, + 0x14, 0x01, 0x19, 0xf5, 0xf6, 0xe1, 0x1f, 0xc2, 0xfa, 0xcd, 0xe0, 0xf1, 0x3e, + 0xe4, 0x4f, 0x56, 0xcb, 0xc2, 0x0d, 0x79, 0x2d, 0x04, 0x32, 0xf3, 0x0d, 0xe2, + 0xb3, 0xf2, 0xab, 0x29, 0x06, 0xe8, 0x0a, 0xdf, 0xc3, 0x10, 0x1d, 0x26, 0xb1, + 0x17, 0x08, 0x13, 0xfc, 0x03, 0x30, 0x33, 0x2e, 0x0a, 0x24, 0xcf, 0x05, 0x36, + 0x00, 0xea, 0x04, 0xcf, 0x44, 0x21, 0x06, 0x6e, 0xd2, 0xd3, 0xe2, 0xc3, 0x2c, + 0x3c, 0x20, 0x0e, 0x26, 0xb2, 0xbd, 0xf4, 0xfa, 0xe7, 0xc8, 0xbe, 0x15, 0xf1, + 0xc0, 0x3e, 0xe4, 0x0f, 0x6d, 0xdf, 0x1a, 0xe7, 0x0a, 0x3f, 0x22, 0x43, 0x3d, + 0xd1, 0x02, 0x4d, 0xf5, 0xcb, 0x7f, 0x32, 0x43, 0x0e, 0xeb, 0xd6, 0xf1, 0xb5, + 0xf6, 0x2b, 0x02, 0x10, 0x14, 0xef, 0x01, 0xf7, 0x62, 0xec, 0x07, 0x05, 0x62, + 0xad, 0x1c, 0xee, 0xea, 0x2e, 0xed, 0x1e, 0xfa, 0x37, 0xfc, 0x40, 0x0c, 0xfb, + 0x26, 0xf5, 0x0e, 0xa6, 0x07, 0x5a, 0x19, 0x0e, 0xd7, 0x42, 0xd0, 0xe4, 0xe3, + 0x31, 0xc0, 0x21, 0xe4, 0x29, 0xac, 0xdc, 0xf8, 0xee, 0xbe, 0xd7, 0x37, 0xdc, + 0x47, 0xed, 0xfe, 0x20, 0xcc, 0xc6, 0x7f, 0x09, 0xed, 0x08, 0xcb, 0x16, 0xf7, + 0xdf, 0xd8, 0xfa, 0x21, 0x28, 0x3f, 0xc1, 0x95, 0x02, 0xcd, 0xd9, 0xf7, 0xa8, + 0xe6, 0xb9, 0x01, 0xce, 0xe2, 0x06, 0x19, 0x14, 0x31, 0x45, 0x23, 0xe1, 0xd1, + 0x0b, 0xec, 0xed, 0xeb, 0xbe, 0xc6, 0xba, 0xd1, 0xf3, 0xfe, 0x08, 0xf6, 0x3b, + 0x1a, 0xcc, 0xa5, 0xc6, 0x0e, 0x38, 0xd1, 0x00, 0xd5, 0xd6, 0x0e, 0x13, 0xd2, + 0x20, 0x4a, 0xad, 0x1b, 0xb9, 0x4d, 0xe7, 0x0d, 0xf7, 0x13, 0x67, 0xb4, 0xf8, + 0xf3, 0x39, 0x48, 0xf4, 0xf9, 0xe2, 0xe1, 0x22, 0x42, 0x2f, 0x11, 0x37, 0xc8, + 0x01, 0x17, 0xd1, 0xc6, 0x00, 0xc8, 0x29, 0x00, 0x2c, 0xa5, 0xce, 0xd7, 0x66, + 0x2b, 0x00, 0xb7, 0xf8, 0x03, 0x2f, 0x3b, 0x16, 0xf7, 0xf9, 0xf8, 0x49, 0x17, + 0x19, 0xda, 0x08, 0xf3, 0x04, 0xf6, 0x28, 0x15, 0x16, 0x03, 0x0a, 0xf3, 0x04, + 0x30, 0x51, 0x2f, 0xfa, 0xe0, 0xfa, 0x31, 0x10, 0xde, 0xea, 0xe8, 0x1e, 0x27, + 0x6d, 0xde, 0x11, 0x0f, 0x2e, 0xef, 0xd7, 0x2a, 0x0b, 0x5b, 0x18, 0x3f, 0xfb, + 0xd9, 0x49, 0x1d, 0x10, 0xeb, 0x0a, 0x38, 0xfe, 0x34, 0x27, 0x30, 0x20, 0x07, + 0xf5, 0x29, 0x0c, 0x18, 0x23, 0x1d, 0xd7, 0xec, 0x07, 0xff, 0x05, 0xfc, 0x10, + 0xec, 0x56, 0xfd, 0xd8, 0xef, 0xe8, 0x56, 0x29, 0x4c, 0xed, 0x11, 0xcb, 0x04, + 0xdf, 0x1f, 0x32, 0xec, 0xf9, 0xe4, 0xc8, 0x0b, 0xf8, 0x23, 0xed, 0x16, 0xf1, + 0x19, 0x17, 0xe3, 0xeb, 0x0e, 0xf3, 0x18, 0xd3, 0x04, 0x19, 0xed, 0xd3, 0x32, + 0x37, 0x0b, 0xba, 0x7f, 0x3d, 0x3e, 0x3c, 0x2d, 0x70, 0xd6, 0x04, 0x07, 0xfb, + 0xf5, 0xe8, 0x24, 0x4c, 0x60, 0x27, 0xe2, 0xd5, 0xe5, 0xf5, 0xcd, 0x15, 0xc4, + 0xd9, 0xeb, 0x08, 0x0f, 0xe5, 0xc2, 0xf1, 0x36, 0xd3, 0x0e, 0x2b, 0xe0, 0xdb, + 0xed, 0xd2, 0x4b, 0xc7, 0x02, 0xce, 0xfa, 0x55, 0x0f, 0x14, 0xf2, 0xf7, 0x1b, + 0x51, 0xeb, 0x31, 0x9f, 0x3e, 0xcb, 0xed, 0xa2, 0xfb, 0x16, 0xea, 0x33, 0xf3, + 0xd2, 0xf9, 0x4c, 0xdf, 0x28, 0x06, 0x47, 0xa5, 0x1e, 0x17, 0x30, 0xd7, 0x07, + 0x07, 0x02, 0xf0, 0xdf, 0x33, 0xf4, 0x1c, 0x2d, 0xe3, 0xd7, 0x06, 0xed, 0x12, + 0x01, 0xee, 0xc4, 0xba, 0xbf, 0xe2, 0xc6, 0x19, 0x04, 0x0c, 0x47, 0xf3, 0xf5, + 0xe0, 0x7f, 0xd7, 0x2a, 0x0d, 0xee, 0xb7, 0xe5, 0xd3, 0xc2, 0x1b, 0x0b, 0x0e, + 0x05, 0xc7, 0x30, 0x42, 0x02, 0x5b, 0x03, 0xd0, 0xe0, 0xd0, 0xf9, 0xe5, 0xf8, + 0xe1, 0x0f, 0x3e, 0xfa, 0x08, 0x0c, 0xe6, 0x03, 0xdd, 0x11, 0x1e, 0x0b, 0x11, + 0x41, 0x10, 0x15, 0xa3, 0xfb, 0xf3, 0xe1, 0xc3, 0x05, 0x23, 0xef, 0x17, 0x17, + 0x0b, 0x12, 0x19, 0xf3, 0x2f, 0xda, 0xec, 0xed, 0xf5, 0xc7, 0xe8, 0x4d, 0x0b, + 0x6d, 0x07, 0xf8, 0x00, 0x1c, 0x2c, 0xf7, 0x1a, 0xff, 0xdc, 0xf0, 0x42, 0x00, + 0xee, 0xd0, 0xeb, 0xfe, 0x13, 0xee, 0x4a, 0xf1, 0xe0, 0x07, 0x25, 0xda, 0xd8, + 0x12, 0xf0, 0xff, 0xe2, 0xdc, 0x22, 0xb3, 0x7f, 0x18, 0x05, 0xec, 0xe5, 0xe9, + 0xd8, 0xcd, 0x13, 0xd3, 0x0d, 0x01, 0xd7, 0x52, 0xfa, 0xc0, 0xf1, 0xf1, 0xe3, + 0xef, 0x03, 0x19, 0x09, 0xd9, 0xfc, 0x0b, 0xce, 0xdb, 0x21, 0x2e, 0x10, 0xf1, + 0xe8, 0xd8, 0xf3, 0x1a, 0x41, 0xd2, 0x0c, 0xeb, 0x21, 0x39, 0x14, 0x00, 0xfa, + 0xf2, 0x3a, 0x0d, 0xf9, 0x02, 0xb3, 0x04, 0x47, 0xfc, 0xd5, 0x2b, 0xe0, 0x1a, + 0xd2, 0x25, 0xf9, 0xcc, 0x1f, 0x07, 0xe5, 0x28, 0xe4, 0xfb, 0x06, 0x0e, 0x03, + 0x08, 0xfb, 0xf8, 0xed, 0x01, 0xc5, 0xea, 0x1f, 0x03, 0x19, 0x00, 0x11, 0x62, + 0x23, 0x4e, 0xff, 0x06, 0xc2, 0x36, 0x0f, 0xef, 0xee, 0x24, 0x49, 0xf4, 0xef, + 0xd3, 0x05, 0xd2, 0x10, 0x06, 0xdb, 0x3e, 0x1b, 0x03, 0x01, 0xfe, 0x13, 0x0c, + 0x01, 0x7a, 0x23, 0xf5, 0x60, 0x34, 0xc2, 0xfa, 0xfa, 0x0c, 0x44, 0x02, 0x2d, + 0xe0, 0x14, 0xe8, 0x2d, 0xd8, 0xee, 0xde, 0x1e, 0x06, 0xf4, 0xf5, 0xef, 0xf5, + 0xee, 0xfc, 0xf4, 0xde, 0xb7, 0xed, 0x2d, 0x11, 0x0f, 0x31, 0x02, 0xb8, 0xb7, + 0x7f, 0xe6, 0x2b, 0xec, 0x44, 0x0f, 0x01, 0xe8, 0x12, 0xf8, 0x0a, 0xcb, 0x3a, + 0x04, 0x03, 0x13, 0xeb, 0xf2, 0x1f, 0x35, 0xf6, 0xfa, 0x0f, 0x37, 0x26, 0xd2, + 0xf3, 0x24, 0xeb, 0x03, 0xfa, 0x14, 0xeb, 0x22, 0x38, 0xe7, 0xed, 0xd3, 0xe0, + 0xfa, 0x07, 0x22, 0x11, 0xdb, 0x0c, 0xf4, 0x22, 0xec, 0x32, 0x06, 0xfd, 0xe4, + 0x42, 0x01, 0xfa, 0x25, 0x1a, 0x0c, 0x04, 0x19, 0x33, 0xdf, 0x01, 0xe3, 0xd4, + 0xe1, 0x1b, 0x2c, 0x18, 0xdf, 0xbc, 0xcc, 0x06, 0xdf, 0x7c, 0x12, 0x18, 0xd6, + 0xc7, 0xee, 0xd0, 0x0e, 0xea, 0x06, 0xb1, 0xda, 0x1a, 0xf9, 0x94, 0xe6, 0xfe, + 0x05, 0xd0, 0xe3, 0xcc, 0xbb, 0xf2, 0xca, 0xe6, 0x27, 0xf8, 0xd7, 0x04, 0xe2, + 0xbc, 0x7f, 0xe3, 0xfe, 0x5a, 0xea, 0xc6, 0xc3, 0xe4, 0xc3, 0xf0, 0x16, 0xe5, + 0xf2, 0x19, 0xeb, 0x0c, 0x06, 0xaf, 0xf3, 0x06, 0x16, 0xe5, 0xf9, 0xd2, 0x08, + 0x10, 0x0b, 0x18, 0x03, 0xec, 0xd7, 0x27, 0xe0, 0xc6, 0xea, 0x40, 0x08, 0x3e, + 0x46, 0xa8, 0xff, 0x4b, 0x65, 0x70, 0xfc, 0x3d, 0x03, 0x04, 0x67, 0x08, 0x19, + 0xdc, 0xe1, 0xeb, 0x11, 0x12, 0xf2, 0x32, 0xf1, 0xfb, 0xdb, 0x0c, 0xd2, 0x16, + 0x85, 0xcf, 0xef, 0x2b, 0x09, 0xdf, 0x75, 0xce, 0x14, 0x73, 0xeb, 0xe8, 0x47, + 0xee, 0x2b, 0x11, 0xab, 0x3b, 0xef, 0x37, 0xed, 0x10, 0x06, 0xb2, 0xdd, 0xa3, + 0xb6, 0x3f, 0xfc, 0x34, 0x5e, 0x3d, 0xe9, 0x43, 0xf9, 0x03, 0x21, 0xee, 0xd0, + 0xfb, 0xf5, 0x23, 0x06, 0x45, 0xfc, 0xff, 0xc9, 0x25, 0xa2, 0x6d, 0xfb, 0xdc, + 0x11, 0x25, 0x07, 0x18, 0x58, 0x2e, 0x1d, 0xfa, 0x00, 0xe2, 0x28, 0xf8, 0xdb, + 0xc4, 0x12, 0xeb, 0xbf, 0xed, 0xc8, 0xf3, 0xdf, 0xa9, 0xc0, 0xf1, 0x10, 0xce, + 0x01, 0xc5, 0x0c, 0xd2, 0x0f, 0xf9, 0xb8, 0x1f, 0x3d, 0x52, 0x1c, 0x4a, 0xee, + 0x12, 0xe4, 0xef, 0xd7, 0xe0, 0x23, 0xd7, 0x47, 0x05, 0xf6, 0xc3, 0xfd, 0xfc, + 0xf7, 0x7f, 0xfa, 0x1d, 0xe6, 0x04, 0xdd, 0x02, 0xe2, 0x81, 0xca, 0x0f, 0xd0, + 0x2a, 0xca, 0xe7, 0x21, 0xf9, 0x1a, 0x57, 0x1d, 0x1b, 0xf8, 0x2f, 0x2d, 0xba, + 0xc8, 0xc7, 0xf1, 0x22, 0x20, 0x10, 0x30, 0x3e, 0xfd, 0x33, 0x16, 0x13, 0xcf, + 0xe6, 0x21, 0x1b, 0xe3, 0xf0, 0x07, 0x5c, 0xfe, 0x3a, 0x3d, 0x20, 0xbc, 0x44, + 0xf8, 0x09, 0xe8, 0xf8, 0xf5, 0x3b, 0x12, 0xea, 0x1c, 0xf2, 0x13, 0x5a, 0xf0, + 0xfb, 0x18, 0x13, 0xc8, 0x21, 0x31, 0xe7, 0x4b, 0x25, 0xb7, 0x5b, 0x52, 0x18, + 0x2a, 0xd9, 0x17, 0x17, 0x29, 0x33, 0x19, 0x0f, 0x0c, 0xd3, 0x27, 0xf3, 0x27, + 0xf7, 0xe7, 0xdb, 0x18, 0x05, 0x04, 0x17, 0x36, 0x28, 0xf0, 0xe8, 0xcc, 0xef, + 0x22, 0x44, 0xe4, 0x4c, 0x15, 0xfe, 0x02, 0x4b, 0xd9, 0x33, 0x1f, 0xe8, 0xd2, + 0x26, 0x29, 0x22, 0xfe, 0x7f, 0x0e, 0x32, 0xfc, 0x15, 0xf5, 0x1c, 0x10, 0x4b, + 0x04, 0x10, 0x3a, 0xed, 0x24, 0x31, 0xf6, 0x1a, 0x15, 0x48, 0x59, 0x0f, 0x01, + 0x08, 0xed, 0x33, 0x0a, 0x1f, 0x15, 0xfd, 0xe4, 0xde, 0xed, 0xfe, 0x12, 0x14, + 0x0b, 0x18, 0x09, 0x47, 0x11, 0x0a, 0xd9, 0x01, 0xb6, 0xf9, 0x10, 0x23, 0x00, + 0x70, 0x01, 0xfc, 0xe6, 0xec, 0xf7, 0xad, 0x19, 0x47, 0x3d, 0x27, 0x06, 0xe6, + 0xf7, 0x02, 0x1a, 0x16, 0xd4, 0x36, 0x03, 0xcf, 0xe7, 0x4a, 0x0f, 0xd5, 0x0d, + 0x02, 0x25, 0x96, 0x3f, 0x0b, 0xe6, 0xcd, 0x2f, 0x40, 0xce, 0x02, 0xdf, 0xe6, + 0xc0, 0x0e, 0x1e, 0x3e, 0x10, 0x39, 0xed, 0xef, 0x32, 0xed, 0xb3, 0xe2, 0xfa, + 0xd0, 0xf9, 0x0b, 0xf8, 0xfc, 0x07, 0x65, 0x18, 0x0a, 0x49, 0x38, 0x00, 0xe8, + 0x34, 0xe4, 0x06, 0x0d, 0xab, 0xa7, 0xd2, 0x14, 0xfd, 0xdd, 0x06, 0x10, 0x2b, + 0xd2, 0x52, 0x7f, 0xfc, 0xeb, 0xdf, 0x29, 0xc1, 0xf0, 0xdb, 0x05, 0xe2, 0xdc, + 0x24, 0x0e, 0xe3, 0x16, 0x3d, 0xf3, 0xee, 0x0e, 0xf8, 0xea, 0xd1, 0xea, 0x26, + 0x74, 0x1a, 0x3d, 0x1c, 0xd4, 0xb0, 0xf4, 0x09, 0xf5, 0xe7, 0x03, 0xf6, 0xcb, + 0xe5, 0xe6, 0xbf, 0x1d, 0xd1, 0xfd, 0x08, 0xd9, 0x3b, 0xfb, 0xff, 0x1a, 0x00, + 0x0a, 0x00, 0x7a, 0x3b, 0xf1, 0x3a, 0x01, 0xa7, 0xf7, 0x08, 0x22, 0xff, 0xf9, + 0x00, 0xe5, 0x13, 0xf0, 0x35, 0x07, 0x18, 0x50, 0x81, 0x0d, 0x45, 0x08, 0xb0, + 0x2b, 0xdc, 0xc0, 0x34, 0x03, 0x04, 0x6e, 0x38, 0x9d, 0xf5, 0x1a, 0x3c, 0xf0, + 0x26, 0x36, 0x15, 0xf2, 0x0d, 0xd6, 0xf9, 0x39, 0x2d, 0x04, 0xe9, 0xea, 0x14, + 0x15, 0xd2, 0x3b, 0x14, 0x69, 0xee, 0x1b, 0xe4, 0x23, 0x4f, 0x1f, 0xd6, 0x36, + 0xf1, 0xee, 0xc7, 0x2c, 0xda, 0xc1, 0x03, 0xd5, 0xb3, 0x15, 0x19, 0x59, 0xed, + 0x51, 0x05, 0x0b, 0xf7, 0xf9, 0x05, 0x08, 0xe4, 0x14, 0x31, 0x06, 0x22, 0x10, + 0x14, 0x44, 0xc1, 0xdc, 0x1a, 0xc0, 0x0a, 0x0a, 0x06, 0x19, 0xfb, 0x08, 0x08, + 0x05, 0x34, 0xfb, 0xe8, 0xfb, 0x06, 0x20, 0xee, 0x3a, 0x0f, 0x10, 0xed, 0x2b, + 0x14, 0x00, 0xd7, 0xfb, 0xfb, 0xd8, 0x04, 0xe2, 0xfc, 0xfb, 0xff, 0xeb, 0xf3, + 0x13, 0x1b, 0xfa, 0x09, 0x18, 0xb3, 0xf5, 0xf0, 0x14, 0x04, 0xff, 0xea, 0xef, + 0x03, 0xf2, 0x1c, 0xfa, 0xfb, 0x23, 0xce, 0xf6, 0xfd, 0x18, 0xe5, 0x25, 0xf5, + 0xee, 0x11, 0x05, 0xf8, 0x20, 0x04, 0x07, 0xef, 0x02, 0x22, 0xed, 0x04, 0x13, + 0xfb, 0x0a, 0xee, 0x07, 0xf4, 0x09, 0x18, 0xf6, 0xe9, 0x03, 0x05, 0xfc, 0xe5, + 0xd3, 0x04, 0x26, 0x02, 0x13, 0x25, 0x1e, 0xf8, 0x0d, 0xf9, 0x29, 0xea, 0xeb, + 0xf2, 0x33, 0xd2, 0xeb, 0x0e, 0x15, 0xee, 0x08, 0x0f, 0x3d, 0x1b, 0x7f, 0x03, + 0x05, 0xee, 0x23, 0xfa, 0xfb, 0x17, 0x06, 0x1f, 0x23, 0x06, 0x0e, 0xf5, 0x1a, + 0xfd, 0xfe, 0x08, 0x0c, 0xfc, 0x17, 0x19, 0x0f, 0xed, 0x06, 0x07, 0xde, 0x27, + 0xec, 0x00, 0xe8, 0x2d, 0x12, 0x13, 0xfd, 0x12, 0x09, 0xf2, 0x04, 0xd4, 0x0c, + 0xf9, 0x19, 0xca, 0xe8, 0x1f, 0xe7, 0x21, 0xe7, 0x09, 0x05, 0xf5, 0x1d, 0x00, + 0xfd, 0xec, 0x01, 0xe6, 0xf3, 0xf6, 0x26, 0xb6, 0xe9, 0xec, 0xf9, 0xee, 0xf1, + 0xe6, 0x01, 0xda, 0xda, 0xfd, 0xf6, 0xdb, 0x09, 0xf2, 0x0a, 0x1d, 0xef, 0xf6, + 0xdc, 0x27, 0x00, 0x09, 0xb8, 0xb7, 0xf5, 0xba, 0xdf, 0x18, 0xfd, 0xba, 0x0f, + 0x42, 0xdb, 0xff, 0xf9, 0xfc, 0x3a, 0x57, 0x06, 0x00, 0xfb, 0x1d, 0x81, 0x13, + 0x50, 0x32, 0x2c, 0x43, 0x09, 0x02, 0x17, 0x19, 0x0c, 0x1d, 0x28, 0xe9, 0xb2, + 0x32, 0xfb, 0xf4, 0x19, 0xfe, 0xd5, 0xe9, 0x20, 0xbd, 0x07, 0xd0, 0xbc, 0xa9, + 0x06, 0x03, 0xc2, 0xe2, 0xca, 0x27, 0xdb, 0xe5, 0x23, 0x3d, 0x13, 0xf6, 0xec, + 0xc6, 0x06, 0x0e, 0x21, 0x24, 0xef, 0xed, 0xad, 0x35, 0xc7, 0x1c, 0x15, 0x12, + 0x9e, 0xb8, 0xf0, 0xfb, 0x07, 0xe7, 0x07, 0x21, 0xfd, 0x10, 0x23, 0x15, 0x10, + 0x02, 0x28, 0xf2, 0xb0, 0x0d, 0xe1, 0xa9, 0xe7, 0xf9, 0x60, 0x28, 0x77, 0xb4, + 0xfe, 0xf5, 0x16, 0xf9, 0xed, 0xba, 0xd2, 0x46, 0x00, 0xfc, 0xef, 0x71, 0xca, + 0xe9, 0x0d, 0xf3, 0x1f, 0xed, 0x1a, 0x8c, 0xcc, 0x13, 0x2c, 0xb4, 0x4b, 0x0d, + 0xca, 0x3c, 0x38, 0xf2, 0xe3, 0x3b, 0x05, 0xf4, 0x1b, 0xd6, 0xef, 0xd5, 0x22, + 0x40, 0x0b, 0xf2, 0xeb, 0x24, 0xde, 0xc9, 0x0a, 0x22, 0xe8, 0xf6, 0x1a, 0x48, + 0x07, 0xfd, 0xe0, 0x33, 0x44, 0xd9, 0x3e, 0x10, 0xf8, 0x81, 0x0f, 0xc8, 0x09, + 0xe2, 0x1b, 0x97, 0xe5, 0xe1, 0x6a, 0xea, 0xce, 0x21, 0xed, 0xef, 0xd7, 0x08, + 0xf5, 0x46, 0xf5, 0x26, 0x17, 0xd2, 0xf2, 0x11, 0xfd, 0xec, 0x23, 0xfb, 0x3b, + 0xa3, 0x51, 0x03, 0x0a, 0x02, 0x05, 0x02, 0xe2, 0xd9, 0x31, 0x77, 0x20, 0x47, + 0xe5, 0xfa, 0x00, 0xfa, 0x21, 0xd8, 0x67, 0x27, 0x2f, 0x06, 0x5c, 0x02, 0x03, + 0x9d, 0x3f, 0x19, 0xd8, 0xde, 0x04, 0x37, 0xcb, 0x14, 0x15, 0x33, 0x08, 0x20, + 0x29, 0x4e, 0xc9, 0xe5, 0xf3, 0x5c, 0xba, 0x1e, 0xf9, 0xd9, 0x00, 0xed, 0x29, + 0x27, 0xb2, 0xe2, 0xc1, 0x43, 0x14, 0xf2, 0xcf, 0x00, 0xf6, 0x37, 0x47, 0x28, + 0x06, 0x17, 0x03, 0x0b, 0x22, 0x48, 0x11, 0xb2, 0x44, 0x1f, 0x3e, 0xe4, 0x9f, + 0x69, 0xf5, 0xfb, 0xe7, 0x3a, 0xce, 0x0b, 0xdc, 0xd5, 0x2c, 0xda, 0xbd, 0x50, + 0x1b, 0xb1, 0x50, 0x01, 0xc6, 0x03, 0x01, 0x14, 0x55, 0x27, 0x37, 0xc7, 0x0b, + 0x2c, 0xb1, 0xdb, 0x0e, 0xb9, 0x1c, 0x25, 0x8e, 0x00, 0xf2, 0x10, 0xdc, 0x1b, + 0x40, 0x03, 0x04, 0xd6, 0xff, 0xec, 0x26, 0x09, 0xbd, 0xca, 0xf2, 0xee, 0xeb, + 0x1c, 0xe8, 0xab, 0x81, 0x07, 0x20, 0x15, 0x39, 0xb8, 0x0a, 0xe5, 0xdb, 0xf3, + 0x03, 0xe6, 0x06, 0x07, 0xfc, 0xdf, 0x30, 0x1a, 0x32, 0x0b, 0xd2, 0x22, 0xe0, + 0x9d, 0xae, 0x21, 0x33, 0xc7, 0x7d, 0x38, 0x13, 0xc2, 0xdc, 0x27, 0x09, 0xb5, + 0xfe, 0xfe, 0x1a, 0x29, 0x0c, 0xe0, 0xf7, 0x79, 0xf9, 0x04, 0x30, 0xec, 0x5a, + 0xb5, 0x3a, 0x28, 0xf0, 0xe1, 0x2d, 0xba, 0x1a, 0x3d, 0xdd, 0x50, 0x5d, 0xb9, + 0xd7, 0x57, 0x1e, 0x07, 0xbc, 0x4b, 0xdc, 0xe3, 0xb1, 0xf0, 0xd9, 0xf4, 0x1b, + 0x69, 0xe9, 0xdf, 0xf4, 0xe0, 0xe1, 0xd2, 0xcf, 0xec, 0x01, 0xfa, 0xde, 0x5a, + 0xdd, 0xdf, 0x54, 0xcb, 0xf6, 0x81, 0x46, 0xef, 0x39, 0x0e, 0x1a, 0xe3, 0x0c, + 0x2e, 0x09, 0xe3, 0xd7, 0x04, 0xa0, 0xe7, 0xe1, 0x32, 0xfa, 0x02, 0x00, 0x0d, + 0xef, 0xaa, 0x20, 0xf3, 0xfd, 0xe5, 0xf2, 0xe6, 0x48, 0xc0, 0xfc, 0xf4, 0x34, + 0xfd, 0xd0, 0x28, 0x12, 0xf5, 0x32, 0x13, 0x35, 0xf0, 0xd3, 0xd5, 0x0a, 0xdb, + 0x19, 0x36, 0x4a, 0x50, 0x58, 0xcf, 0x37, 0x1f, 0x3e, 0xda, 0x32, 0xef, 0xcb, + 0x4d, 0xce, 0xfc, 0x2f, 0x19, 0xf1, 0xfe, 0xdb, 0x1d, 0x28, 0x1f, 0xfb, 0x4d, + 0xdd, 0xde, 0xc2, 0x3a, 0x0b, 0xf5, 0xb3, 0xe0, 0x68, 0x33, 0x09, 0xd7, 0x11, + 0xeb, 0x3e, 0xb6, 0x39, 0x2c, 0x1d, 0xfe, 0xd5, 0x30, 0xde, 0xe1, 0xc3, 0x0e, + 0xec, 0x1c, 0x64, 0x32, 0xf4, 0x41, 0x2f, 0xee, 0xcb, 0xfe, 0x31, 0x2e, 0xd1, + 0x9e, 0x89, 0xb2, 0x2d, 0x13, 0x17, 0x24, 0xf9, 0xdf, 0xec, 0x0b, 0x3a, 0x6f, + 0x2c, 0xd1, 0x0f, 0xf7, 0x00, 0xea, 0xc7, 0xf3, 0xe6, 0x6c, 0x2d, 0xb9, 0xc6, + 0x26, 0x7f, 0x25, 0x91, 0x07, 0xce, 0xf1, 0xa8, 0xed, 0x7c, 0x09, 0xc6, 0x01, + 0x4b, 0x0c, 0xdc, 0xd4, 0x69, 0x15, 0x0b, 0xdf, 0xf9, 0x2b, 0x0d, 0x62, 0x0a, + 0xc7, 0xf6, 0x28, 0x14, 0xaa, 0xef, 0xb6, 0xef, 0x26, 0xc0, 0xa4, 0x2b, 0xf3, + 0x15, 0xf2, 0x37, 0x1e, 0xdb, 0xc3, 0x34, 0xb6, 0x34, 0x38, 0xf6, 0xe5, 0xf6, + 0x26, 0xd2, 0xe4, 0x1b, 0x4b, 0x3a, 0xb5, 0x15, 0x2b, 0xeb, 0xb6, 0xba, 0x31, + 0xc4, 0x36, 0xfa, 0xdd, 0xec, 0x60, 0xdd, 0x7f, 0xb5, 0x2e, 0xe8, 0x6c, 0xfc, + 0x23, 0x0d, 0x07, 0xd2, 0x14, 0x62, 0xd2, 0x12, 0x36, 0x03, 0x10, 0xb7, 0xd4, + 0xe7, 0xa9, 0x3b, 0x25, 0xb2, 0xce, 0xd1, 0x9b, 0xc0, 0xe5, 0xdb, 0x1d, 0x24, + 0xb3, 0x5b, 0xec, 0x2b, 0x1e, 0x59, 0x35, 0x54, 0xef, 0xef, 0x20, 0x06, 0x70, + 0x20, 0xc7, 0xc5, 0xb7, 0xee, 0x3b, 0xe5, 0x1d, 0x46, 0xe6, 0xde, 0xfb, 0xf5, + 0xb5, 0x19, 0x34, 0x07, 0xe5, 0xfa, 0x18, 0xfa, 0x13, 0xa9, 0x33, 0xb6, 0xfa, + 0x08, 0xdd, 0x0d, 0x22, 0x8e, 0x57, 0xcd, 0x07, 0xd9, 0xec, 0x48, 0xe0, 0xd5, + 0x04, 0xf8, 0xc6, 0xd2, 0xd7, 0xf8, 0x08, 0xf1, 0x48, 0xac, 0x3e, 0x1f, 0x1d, + 0xe7, 0xc9, 0xc5, 0xd9, 0x38, 0x4a, 0xc6, 0x2d, 0x35, 0x3e, 0x1a, 0x1b, 0xf6, + 0x2d, 0xd1, 0x08, 0xe3, 0xa9, 0xc3, 0x2a, 0x6a, 0x17, 0xfd, 0xd9, 0xdb, 0x23, + 0xda, 0xde, 0x1d, 0x1d, 0x06, 0xf5, 0xaa, 0x85, 0xf3, 0x07, 0x30, 0xfb, 0x04, + 0xde, 0xe3, 0x51, 0xea, 0x0d, 0xfc, 0x17, 0x1e, 0x18, 0xd0, 0xdc, 0x28, 0x00, + 0x16, 0x1d, 0x51, 0x81, 0xd4, 0xc6, 0x22, 0xe0, 0x01, 0x02, 0x15, 0x0f, 0x4a, + 0x1e, 0x1e, 0xc4, 0x10, 0x03, 0xf8, 0x19, 0x0d, 0xbd, 0x16, 0x02, 0x1b, 0xf1, + 0x4a, 0xe5, 0x97, 0x39, 0x15, 0xcf, 0x25, 0xb8, 0xfa, 0xf0, 0x2c, 0x19, 0x17, + 0xd4, 0x03, 0x1c, 0x33, 0xde, 0xf3, 0xdc, 0xe9, 0x0c, 0xe3, 0xeb, 0xd2, 0x22, + 0x98, 0x2b, 0xf4, 0xea, 0xd7, 0x11, 0x15, 0xee, 0xd8, 0xf9, 0x0f, 0xfd, 0xd9, + 0xfc, 0xed, 0xed, 0x3d, 0xe2, 0xdf, 0xef, 0x2e, 0x24, 0xf8, 0x1d, 0xd6, 0x37, + 0x52, 0xd0, 0xa6, 0xea, 0x25, 0x07, 0x7f, 0x47, 0x1c, 0xff, 0x1f, 0x05, 0xfa, + 0x4b, 0x1e, 0x44, 0xee, 0x0e, 0x0e, 0xf5, 0xec, 0x1d, 0x10, 0x28, 0xe0, 0x28, + 0xe5, 0xe5, 0x38, 0x02, 0x1b, 0xb0, 0x10, 0xd8, 0x15, 0x2b, 0x00, 0xfb, 0xe2, + 0x26, 0x3d, 0x35, 0xeb, 0x13, 0x3a, 0x13, 0x02, 0x25, 0x39, 0x33, 0xe7, 0x06, + 0x1f, 0xdf, 0x06, 0x2e, 0xf8, 0x25, 0xe5, 0x33, 0xd5, 0xea, 0x17, 0x44, 0xb5, + 0xe3, 0xe6, 0xec, 0x67, 0xeb, 0xcd, 0xcf, 0x05, 0x45, 0x15, 0xec, 0xf8, 0x20, + 0xf9, 0x0f, 0x55, 0xe1, 0xc3, 0x2b, 0xef, 0xc0, 0x0f, 0xf4, 0x84, 0x0b, 0x04, + 0x09, 0xeb, 0xcc, 0xff, 0x40, 0xea, 0x03, 0x5f, 0xeb, 0xee, 0x44, 0xfa, 0xc3, + 0xef, 0x42, 0x09, 0xb4, 0xde, 0xde, 0x30, 0x46, 0x13, 0x45, 0xf7, 0x0a, 0x26, + 0xfc, 0xba, 0x26, 0xfb, 0x3e, 0x11, 0x1e, 0xfd, 0xc5, 0x54, 0xc1, 0xec, 0x37, + 0x08, 0x51, 0xf5, 0x5c, 0xcb, 0x1b, 0xb6, 0x6f, 0x02, 0x1b, 0xdf, 0x2e, 0xf5, + 0x1d, 0x18, 0xe7, 0x23, 0x0c, 0xd0, 0xb8, 0x04, 0xf5, 0x0d, 0x0a, 0x03, 0x3d, + 0x18, 0xc2, 0x3e, 0x2a, 0x10, 0xf1, 0x1c, 0x43, 0xdb, 0x2f, 0x18, 0x07, 0xfd, + 0x1a, 0xf6, 0x01, 0xf1, 0x03, 0xda, 0x1c, 0x69, 0x36, 0x01, 0x05, 0x2a, 0xf3, + 0x34, 0x0f, 0x1f, 0x07, 0x47, 0x40, 0xc3, 0x55, 0x08, 0x14, 0x44, 0x27, 0xeb, + 0x09, 0x05, 0x22, 0x0d, 0x5a, 0x66, 0x2d, 0x04, 0xa5, 0x23, 0x13, 0xf0, 0xe6, + 0xc0, 0x02, 0x7f, 0x1c, 0x54, 0x5a, 0x51, 0xd8, 0xdb, 0xf3, 0x01, 0x26, 0xe9, + 0xe6, 0xc6, 0x18, 0x20, 0x2a, 0x13, 0xfe, 0x48, 0x22, 0xf4, 0x4b, 0x07, 0x27, + 0xec, 0xd7, 0x0f, 0x4c, 0xd9, 0xff, 0xe1, 0x58, 0xcc, 0xbd, 0x04, 0x57, 0x1d, + 0x58, 0x17, 0xf2, 0xea, 0xc8, 0x41, 0x1b, 0x69, 0x41, 0x3a, 0x2c, 0x35, 0x3a, + 0xef, 0xe2, 0xeb, 0x07, 0xc2, 0x46, 0xf3, 0x06, 0x27, 0x0d, 0xfe, 0xc9, 0x0b, + 0x03, 0xff, 0x02, 0x03, 0xf1, 0xc7, 0x10, 0xe9, 0xc7, 0xe1, 0x03, 0x55, 0x7f, + 0xe1, 0xc3, 0x1b, 0x15, 0x05, 0xa2, 0x06, 0xe1, 0xf1, 0xf4, 0xcf, 0x40, 0x07, + 0x10, 0x44, 0x13, 0xf1, 0x51, 0xfd, 0x12, 0xfd, 0x24, 0xe2, 0xdb, 0x06, 0x34, + 0xd2, 0x2c, 0xd0, 0x1b, 0xc6, 0x1a, 0x0f, 0xce, 0x07, 0xf8, 0xe3, 0x28, 0xd8, + 0x11, 0x59, 0xf1, 0x02, 0x19, 0x2a, 0xec, 0xd5, 0xff, 0x59, 0xd3, 0x01, 0x19, + 0xf9, 0xfa, 0x15, 0xdc, 0x2a, 0x27, 0xc9, 0x00, 0xdc, 0x1c, 0x06, 0xfc, 0xec, + 0x37, 0x0b, 0xcd, 0xe8, 0xf3, 0xf1, 0x24, 0xcc, 0x32, 0x04, 0x05, 0x01, 0x0e, + 0x24, 0x03, 0xf1, 0x4a, 0xe9, 0x0e, 0x2c, 0x47, 0xee, 0x94, 0x25, 0x03, 0xfc, + 0xde, 0xfb, 0xbc, 0x20, 0xd2, 0xfb, 0x27, 0xdb, 0xf7, 0xfe, 0x0b, 0x11, 0x04, + 0x2b, 0xf4, 0x35, 0xef, 0x39, 0x0a, 0x0d, 0xcf, 0x0c, 0x06, 0x34, 0xe1, 0x1a, + 0x01, 0x0d, 0x7f, 0x1d, 0x08, 0x0a, 0x46, 0xf8, 0xdd, 0x1c, 0x2c, 0xda, 0x37, + 0x08, 0x40, 0xdd, 0x06, 0x21, 0xc6, 0xeb, 0x09, 0x07, 0x26, 0x4f, 0x34, 0x28, + 0x2e, 0x17, 0xe2, 0x3b, 0xed, 0xd6, 0xbc, 0xf1, 0x44, 0x1b, 0xe8, 0xe7, 0x0e, + 0xeb, 0xe1, 0x24, 0x12, 0x11, 0xed, 0x32, 0xcc, 0xec, 0x12, 0x19, 0xfc, 0x18, + 0x01, 0x2d, 0xe5, 0x12, 0xb0, 0x0d, 0xf5, 0xe3, 0xf7, 0x35, 0xe6, 0xf1, 0xf3, + 0x26, 0x02, 0xf0, 0x02, 0x33, 0x55, 0xe6, 0x28, 0x3a, 0x0b, 0xf8, 0x0f, 0xf9, + 0x1d, 0xce, 0xfd, 0xe1, 0xda, 0xfb, 0x16, 0x04, 0x3a, 0xc8, 0x1b, 0x26, 0x0d, + 0x3e, 0xd8, 0x1c, 0x34, 0x0c, 0xf3, 0x0d, 0x5d, 0xf0, 0xfa, 0x05, 0x13, 0xec, + 0x0f, 0x05, 0x1c, 0xed, 0xeb, 0x0c, 0xef, 0xfd, 0x10, 0x22, 0xfb, 0xee, 0x1e, + 0x3c, 0xfa, 0x32, 0x32, 0x04, 0xea, 0x18, 0xf3, 0x08, 0x07, 0x08, 0x2c, 0x44, + 0x40, 0x10, 0x20, 0x13, 0x7f, 0x1a, 0xf6, 0x11, 0x45, 0x16, 0xda, 0x0f, 0x12, + 0xf4, 0x09, 0x0c, 0xf6, 0x12, 0xfb, 0xed, 0x18, 0x1d, 0x01, 0xe5, 0x1d, 0xe9, + 0xf9, 0xeb, 0xfe, 0x00, 0x00, 0x06, 0x14, 0x11, 0xf1, 0x05, 0x14, 0x05, 0xfb, + 0x03, 0xf4, 0x0e, 0xf5, 0xf9, 0xf7, 0xf8, 0xfc, 0xf0, 0x05, 0x0a, 0xe5, 0x1f, + 0x03, 0xf3, 0xf9, 0x1b, 0xe1, 0x07, 0x28, 0x07, 0xca, 0x09, 0xed, 0x09, 0xf8, + 0xf8, 0xf7, 0xfa, 0x09, 0x1e, 0x09, 0x21, 0xf7, 0xfb, 0x21, 0xf1, 0x0c, 0xf8, + 0xf7, 0x04, 0x0f, 0x00, 0xe4, 0xee, 0xfd, 0xf0, 0xee, 0xf2, 0x04, 0x2b, 0x30, + 0xf3, 0x01, 0x0a, 0xe9, 0xfe, 0x1d, 0x00, 0xf5, 0x05, 0x10, 0xda, 0x12, 0x3a, + 0x13, 0x00, 0xf8, 0x07, 0xfe, 0x03, 0xd6, 0xf6, 0x0a, 0xfa, 0x51, 0xfc, 0x1c, + 0xcb, 0xfa, 0xec, 0xe0, 0x1c, 0x1e, 0xe0, 0x00, 0xfb, 0x37, 0x5c, 0x0b, 0xc5, + 0xf7, 0xe5, 0x20, 0xe5, 0x1a, 0x56, 0x2e, 0xf7, 0xd0, 0x71, 0x7f, 0xc4, 0x38, + 0x1a, 0xd0, 0xc6, 0x5f, 0x2c, 0xc5, 0x26, 0x1b, 0x24, 0xfd, 0xe3, 0x00, 0x40, + 0xe3, 0x20, 0x10, 0x25, 0xec, 0xfc, 0x07, 0xaf, 0xfd, 0x20, 0x9e, 0x0a, 0x4a, + 0xa2, 0xc4, 0x68, 0xdf, 0x28, 0xf3, 0x15, 0x0a, 0xc3, 0x44, 0xc3, 0xe0, 0xce, + 0xb9, 0x2c, 0x2a, 0xeb, 0x1b, 0x75, 0x56, 0x1d, 0xf6, 0xbd, 0x36, 0xa9, 0x08, + 0x67, 0x1a, 0xff, 0x1e, 0xdd, 0x05, 0xb3, 0xfd, 0xc2, 0x0c, 0xe3, 0xe5, 0xe3, + 0xda, 0xdc, 0xd6, 0x13, 0x62, 0x00, 0x31, 0xc6, 0x0c, 0x8e, 0xfa, 0x5c, 0xec, + 0xd8, 0x40, 0xbd, 0xdc, 0xbf, 0x0e, 0xc8, 0x3f, 0xc7, 0x15, 0x10, 0x55, 0xe2, + 0xf7, 0xc3, 0x39, 0x42, 0x1f, 0x08, 0x0f, 0x40, 0xf4, 0xd3, 0x07, 0x15, 0xd4, + 0x5c, 0xfe, 0xe9, 0xda, 0x59, 0x1f, 0xdd, 0x35, 0x5a, 0x9f, 0x04, 0x32, 0xe0, + 0x13, 0xcb, 0xe6, 0xe6, 0xb5, 0x1b, 0x12, 0xcb, 0xdc, 0xc7, 0x1d, 0x0f, 0xf6, + 0x48, 0xe8, 0x16, 0xdb, 0xfe, 0x1a, 0xe7, 0x0f, 0x27, 0xf5, 0x3c, 0xe6, 0xd8, + 0x0f, 0x06, 0x49, 0x09, 0xe8, 0x21, 0xf8, 0x17, 0x06, 0x22, 0x14, 0x50, 0x06, + 0x67, 0xe1, 0xc5, 0xa6, 0xca, 0x04, 0xf4, 0x22, 0xf5, 0xd9, 0xff, 0xf3, 0x67, + 0xef, 0x48, 0xf5, 0x57, 0xcd, 0xb1, 0xf7, 0x09, 0xfb, 0x30, 0x24, 0x10, 0x0a, + 0x3d, 0x0f, 0x15, 0x24, 0x35, 0x0e, 0x10, 0xeb, 0x48, 0xf8, 0x1b, 0xcd, 0x14, + 0xd2, 0x2d, 0x01, 0xe9, 0x51, 0x07, 0xe4, 0x46, 0xff, 0x2d, 0x7f, 0xeb, 0x18, + 0x1b, 0x4f, 0x0e, 0x27, 0x03, 0xdb, 0x42, 0xc1, 0x3c, 0x3b, 0x05, 0xd7, 0x29, + 0x16, 0xec, 0x5a, 0xa4, 0x04, 0xa0, 0x04, 0x1d, 0x1a, 0x08, 0x4a, 0x3b, 0x0d, + 0xf5, 0xf2, 0xdd, 0xd1, 0x34, 0xe9, 0x18, 0xf5, 0x0c, 0xfe, 0x39, 0xd4, 0x41, + 0xeb, 0x09, 0xdb, 0x02, 0x29, 0x35, 0xe9, 0x07, 0xe3, 0xfb, 0xe3, 0xef, 0x0d, + 0xd4, 0x33, 0xfa, 0x1b, 0xe1, 0x13, 0xfc, 0xf8, 0x0b, 0x00, 0xff, 0xee, 0xc8, + 0xdc, 0x31, 0x31, 0x41, 0xe5, 0xff, 0xef, 0x14, 0x4f, 0xee, 0x01, 0xe7, 0xf9, + 0xe7, 0xf1, 0xef, 0x16, 0xfa, 0x00, 0x07, 0xee, 0xf0, 0x1d, 0xd3, 0x1d, 0x04, + 0xf7, 0x7f, 0xbc, 0xf7, 0xd6, 0xfb, 0xd5, 0xe7, 0x31, 0x12, 0xf4, 0x13, 0xe1, + 0xea, 0xfc, 0xdf, 0x15, 0x45, 0xcf, 0xe3, 0x06, 0xed, 0x07, 0xf4, 0x04, 0x1b, + 0xe3, 0xf3, 0x1d, 0x11, 0xf1, 0xf6, 0xf6, 0xfb, 0x24, 0x32, 0x45, 0xf1, 0xeb, + 0xeb, 0x19, 0x26, 0xc0, 0x10, 0x12, 0x04, 0x26, 0x55, 0xe6, 0x25, 0xe1, 0x04, + 0x0e, 0xf1, 0x45, 0x00, 0xda, 0xc1, 0xbb, 0x65, 0x0e, 0x20, 0x18, 0xe3, 0xde, + 0xf3, 0x1b, 0xd1, 0x11, 0xc8, 0xe0, 0xed, 0x04, 0xda, 0xfc, 0x07, 0xe2, 0xe2, + 0xd5, 0xeb, 0xbb, 0xe0, 0xfc, 0x12, 0xf7, 0x1d, 0x16, 0x3d, 0xe9, 0x10, 0x53, + 0x03, 0x02, 0xe7, 0xd4, 0xfc, 0x7f, 0x39, 0x24, 0x2f, 0x22, 0xd8, 0x16, 0xf1, + 0xec, 0xfe, 0x20, 0xf4, 0xdd, 0x0c, 0x04, 0x07, 0x02, 0xb8, 0x0d, 0x03, 0x58, + 0x24, 0x21, 0xd1, 0x28, 0x35, 0xfd, 0x15, 0x05, 0x08, 0xdd, 0x10, 0x0a, 0xdb, + 0x58, 0x06, 0x31, 0x07, 0xfe, 0x22, 0xd4, 0x4b, 0xfe, 0x04, 0xf6, 0x06, 0x15, + 0x3f, 0x24, 0x0b, 0x12, 0x0e, 0x11, 0x10, 0x05, 0xee, 0x14, 0x06, 0xfc, 0xda, + 0x21, 0x22, 0x48, 0xec, 0xff, 0xb5, 0xee, 0xc3, 0xec, 0xbe, 0x0f, 0xfa, 0x23, + 0x11, 0x2f, 0x04, 0xf0, 0x23, 0x0c, 0x14, 0x5e, 0xe2, 0x02, 0xd9, 0x2c, 0xf4, + 0xe7, 0xdd, 0xef, 0xf3, 0x0f, 0x40, 0x35, 0x26, 0x0a, 0xe6, 0x81, 0x23, 0x18, + 0x4d, 0x18, 0x48, 0x0c, 0xf7, 0xf9, 0x2a, 0x5c, 0x17, 0x4d, 0xff, 0xe7, 0xfa, + 0x47, 0xeb, 0xda, 0x0b, 0x09, 0xe2, 0x22, 0x0b, 0xfb, 0x41, 0x20, 0xe1, 0xee, + 0x14, 0x18, 0x1a, 0x4b, 0x3b, 0x1b, 0xf0, 0x13, 0xfb, 0xf0, 0x10, 0x11, 0x13, + 0xee, 0xea, 0x0e, 0x08, 0xde, 0x0f, 0xe9, 0xfa, 0x0e, 0x27, 0xfc, 0xf5, 0x4a, + 0x36, 0x1f, 0x5b, 0x20, 0xf8, 0x10, 0x4f, 0xb4, 0x17, 0x19, 0x26, 0xdf, 0xf3, + 0x0c, 0x6d, 0x24, 0x2b, 0xf4, 0xed, 0x0f, 0x12, 0xe8, 0x0e, 0x1d, 0x12, 0xf8, + 0x08, 0xf1, 0x12, 0x14, 0x58, 0xd5, 0xf4, 0x05, 0x0a, 0xfe, 0xfe, 0x3a, 0x0c, + 0x2d, 0x09, 0xbb, 0x0f, 0x5c, 0x05, 0x33, 0x25, 0x3f, 0x22, 0xe9, 0xef, 0x0b, + 0xf3, 0xf9, 0xf6, 0x01, 0x01, 0xc6, 0x2b, 0x49, 0xac, 0x4e, 0x05, 0x2e, 0x09, + 0x28, 0xb4, 0x26, 0xfe, 0x3a, 0x28, 0xfa, 0xf5, 0x0e, 0x35, 0x11, 0x6a, 0x52, + 0x12, 0x8e, 0x02, 0x3e, 0xec, 0x3f, 0x31, 0x31, 0x3a, 0x9e, 0xe6, 0x5c, 0x00, + 0xbb, 0x00, 0xd7, 0xda, 0x41, 0x19, 0xaa, 0xd9, 0xcd, 0xe7, 0x08, 0xb2, 0xe0, + 0x09, 0x25, 0x46, 0x5d, 0x05, 0x36, 0x20, 0xdb, 0xf6, 0x24, 0xe4, 0x1f, 0x21, + 0x00, 0x26, 0x22, 0x28, 0x52, 0x13, 0x14, 0xe7, 0xe0, 0x17, 0x33, 0xe8, 0x0c, + 0x5d, 0x33, 0xdc, 0xb6, 0x10, 0x0f, 0xb0, 0xe3, 0xae, 0xf6, 0x39, 0xa9, 0x52, + 0x25, 0xf8, 0xc9, 0xf2, 0x2f, 0xf1, 0xe8, 0x44, 0x2e, 0x08, 0xda, 0x35, 0x46, + 0x0f, 0x02, 0x7f, 0xfe, 0xba, 0x04, 0xe8, 0x74, 0x00, 0xe1, 0xe8, 0x2f, 0xee, + 0xe2, 0x27, 0x59, 0x3b, 0x38, 0x33, 0x02, 0x01, 0x0f, 0xb6, 0x11, 0x18, 0x05, + 0x0c, 0xfb, 0x53, 0xeb, 0x0f, 0x18, 0x2b, 0xda, 0x14, 0xe3, 0x5a, 0x0d, 0xff, + 0xef, 0xff, 0xf3, 0x13, 0xdb, 0x28, 0x08, 0xdf, 0xe8, 0xf2, 0xc9, 0xfc, 0x42, + 0xd5, 0x10, 0x09, 0xe0, 0x4b, 0x3b, 0xdc, 0x13, 0xe4, 0xd6, 0x32, 0x45, 0x08, + 0xfb, 0x36, 0xcb, 0x04, 0x59, 0xf6, 0x17, 0xd2, 0x07, 0x46, 0x25, 0xd6, 0xe9, + 0xdb, 0xfc, 0xfd, 0xe2, 0xf3, 0xe6, 0xde, 0xf5, 0xae, 0x04, 0x13, 0xda, 0x55, + 0xd9, 0x4a, 0xde, 0x0f, 0x07, 0x0d, 0xa5, 0xc6, 0xe9, 0xd4, 0xbb, 0xda, 0xf3, + 0x45, 0x81, 0x18, 0xaf, 0xfc, 0x08, 0xfd, 0xb0, 0xe5, 0xcb, 0xda, 0x01, 0x01, + 0xf8, 0x59, 0xf0, 0x02, 0x17, 0x39, 0x0a, 0xdb, 0xac, 0x06, 0x16, 0xdc, 0xf4, + 0xf7, 0xf8, 0x1d, 0x10, 0xc2, 0x0b, 0xcc, 0x21, 0xdb, 0xc9, 0xde, 0x02, 0x11, + 0x57, 0x0c, 0x31, 0xec, 0x29, 0x40, 0x27, 0xe3, 0xe9, 0xed, 0x1e, 0xc0, 0x43, + 0xcf, 0xc0, 0x37, 0x3c, 0xbf, 0xfb, 0xd4, 0x1d, 0xef, 0xd1, 0x64, 0xe8, 0xf3, + 0x18, 0xf4, 0xee, 0x05, 0xeb, 0x03, 0xe0, 0xfb, 0xc2, 0xe7, 0xab, 0x24, 0xc5, + 0xf8, 0x7f, 0x2a, 0x00, 0xc4, 0xe9, 0xf0, 0x04, 0xfc, 0x1c, 0xf1, 0x05, 0xff, + 0xc7, 0x35, 0x15, 0xcd, 0xea, 0xfb, 0x0a, 0xb8, 0x6c, 0x2c, 0x0a, 0x10, 0xde, + 0xf3, 0xfa, 0x9a, 0x33, 0xda, 0x08, 0x24, 0xda, 0x0d, 0x18, 0x4e, 0x11, 0xf2, + 0xfe, 0x1c, 0xe6, 0xd2, 0xe3, 0xf1, 0x3a, 0xdc, 0x01, 0x2f, 0xe2, 0xf1, 0xdb, + 0xfa, 0x28, 0xbc, 0xef, 0x5e, 0xed, 0x05, 0xcf, 0xe9, 0xf2, 0xcb, 0xfa, 0x3a, + 0x2f, 0xf8, 0x28, 0xfa, 0xdf, 0xe9, 0xd7, 0x29, 0x07, 0x02, 0xf0, 0x3a, 0xf0, + 0xd3, 0x08, 0x15, 0x0d, 0x2d, 0xe4, 0x2a, 0x30, 0xe3, 0xc1, 0x1d, 0x2f, 0x17, + 0x14, 0xf9, 0x31, 0x11, 0xff, 0xfd, 0xc9, 0x1b, 0x1c, 0x0e, 0x55, 0xf3, 0xe2, + 0x16, 0xd7, 0xc7, 0xd8, 0x2f, 0xfc, 0xe1, 0x1f, 0x03, 0xcc, 0x32, 0x33, 0x30, + 0xeb, 0xe3, 0xbf, 0x13, 0xf9, 0x06, 0xe7, 0x03, 0x0e, 0xee, 0xf9, 0x3d, 0x51, + 0x05, 0xef, 0x22, 0xef, 0x02, 0xf4, 0x17, 0xdc, 0xbb, 0xf0, 0x0b, 0xcd, 0x48, + 0xf2, 0xd4, 0x32, 0x01, 0xef, 0xd6, 0x15, 0x12, 0x1c, 0xff, 0x2c, 0xf9, 0xca, + 0xd4, 0x15, 0x08, 0xdc, 0x03, 0x0a, 0xf0, 0xe1, 0x1b, 0xf4, 0xd4, 0xbd, 0xed, + 0xdc, 0xff, 0xeb, 0xce, 0x09, 0x25, 0xef, 0x31, 0xee, 0xee, 0x81, 0xfd, 0xf1, + 0xfb, 0xf7, 0x50, 0xaf, 0xd7, 0xcd, 0xec, 0xe3, 0x0a, 0x0c, 0x0c, 0xd7, 0x18, + 0x02, 0x18, 0xf2, 0xe2, 0x0d, 0x21, 0xd1, 0x0b, 0x00, 0x0c, 0x14, 0x41, 0xf3, + 0x14, 0xbc, 0x26, 0xe4, 0x26, 0x37, 0xfc, 0x0a, 0xe3, 0xd4, 0x06, 0x2a, 0xe3, + 0x27, 0x0a, 0xd4, 0xf6, 0xfd, 0xf1, 0xe8, 0x5b, 0xfa, 0xd2, 0xc6, 0x42, 0xdd, + 0x07, 0xe8, 0xed, 0x09, 0x32, 0x5b, 0xf8, 0xfb, 0x2a, 0x0d, 0x3f, 0xd4, 0x16, + 0xd4, 0x23, 0x06, 0xd3, 0x2c, 0xbb, 0x24, 0xd2, 0x14, 0x09, 0xed, 0x01, 0x5d, + 0x7f, 0xbb, 0xfb, 0xd5, 0x14, 0x2d, 0xfe, 0x13, 0xbe, 0x0c, 0xe5, 0x1a, 0x05, + 0x24, 0xd9, 0xbc, 0xef, 0x05, 0xfc, 0x16, 0x32, 0x31, 0x14, 0xd6, 0x33, 0xfc, + 0xe6, 0xe1, 0x1c, 0xe3, 0xef, 0xd8, 0xa7, 0xce, 0xd8, 0x11, 0xca, 0xf8, 0xf8, + 0xdd, 0x1b, 0xf5, 0x51, 0x08, 0x34, 0x09, 0xfb, 0xb7, 0x2f, 0xbf, 0x3e, 0xf2, + 0xda, 0x4a, 0xdc, 0xe2, 0x14, 0xf5, 0x7f, 0x37, 0x42, 0xd3, 0x10, 0xeb, 0xe0, + 0xf8, 0xd8, 0x10, 0xf4, 0xee, 0x48, 0x32, 0x0a, 0xcb, 0x1b, 0xc0, 0xf9, 0x19, + 0x01, 0x1c, 0xd1, 0x04, 0xe9, 0xd6, 0xb9, 0x5a, 0xe8, 0x0a, 0xe1, 0x25, 0x21, + 0x0d, 0xc6, 0xf8, 0xfa, 0xcc, 0x36, 0xe9, 0x22, 0x69, 0x2d, 0xec, 0x4d, 0x36, + 0xc1, 0xee, 0xcb, 0xe1, 0x4b, 0xfe, 0xd5, 0x31, 0xe0, 0xf9, 0x1d, 0xf3, 0xab, + 0x2b, 0x24, 0x4b, 0x15, 0x66, 0xd9, 0x29, 0x14, 0x40, 0x6d, 0xa1, 0xe4, 0xca, + 0x21, 0xb7, 0x07, 0xfb, 0xff, 0xc0, 0x2b, 0xf8, 0xe9, 0xfe, 0xe2, 0xe8, 0xad, + 0x23, 0xc0, 0x3e, 0x17, 0x09, 0xbc, 0x30, 0xcf, 0xd0, 0xf4, 0xd8, 0x1c, 0x5d, + 0xf6, 0x3c, 0x0f, 0xd9, 0x1c, 0x24, 0x0d, 0xd0, 0xc1, 0xd4, 0xd7, 0x00, 0xfd, + 0xe3, 0xa1, 0xde, 0xe1, 0x11, 0x0d, 0x36, 0x29, 0x48, 0x27, 0xf6, 0x3e, 0xf1, + 0x2b, 0x2b, 0x21, 0xc3, 0xe6, 0xf8, 0x10, 0xe3, 0xd8, 0x02, 0xf2, 0x45, 0x4f, + 0xd8, 0xfc, 0xf4, 0x6b, 0xf7, 0xfe, 0xac, 0x18, 0xe8, 0x12, 0xfd, 0x14, 0x1f, + 0x2a, 0xd1, 0x26, 0x56, 0xb8, 0xae, 0x0f, 0x36, 0xac, 0x16, 0xd7, 0x06, 0x0d, + 0x1d, 0x3f, 0xfa, 0x18, 0x40, 0x01, 0x7f, 0xfe, 0x35, 0xed, 0xc8, 0xcc, 0x04, + 0x3a, 0x2f, 0xdd, 0x32, 0x2c, 0xfb, 0x17, 0xf0, 0x0c, 0x17, 0x0e, 0x11, 0xd6, + 0xa7, 0x75, 0xd0, 0xf6, 0x23, 0xd8, 0x46, 0x01, 0x10, 0x06, 0xd1, 0x38, 0xc9, + 0xb7, 0xb0, 0xea, 0xf8, 0xe9, 0x10, 0x55, 0xcd, 0x17, 0x3c, 0x99, 0x0e, 0x81, + 0x27, 0xd5, 0xd3, 0x05, 0x2f, 0x2d, 0xab, 0xfa, 0x41, 0xc5, 0x7a, 0x44, 0xe9, + 0xca, 0xd8, 0xce, 0x0e, 0xc1, 0x23, 0x29, 0xdb, 0xda, 0x32, 0x09, 0x2a, 0xcd, + 0x2b, 0x61, 0xf4, 0x09, 0xf2, 0xe8, 0x18, 0x29, 0x03, 0x47, 0xee, 0xe5, 0xab, + 0xd3, 0xe6, 0x3a, 0x23, 0xe0, 0xb0, 0xcd, 0x2d, 0xce, 0xfd, 0x25, 0x95, 0x24, + 0x46, 0x27, 0x20, 0x49, 0x97, 0xb6, 0xe1, 0x2f, 0x8c, 0xf1, 0x11, 0x08, 0x1a, + 0xa8, 0x0f, 0x2d, 0x11, 0x20, 0x3a, 0xfd, 0x20, 0xfd, 0x20, 0xcc, 0x20, 0x31, + 0x5f, 0x1b, 0x47, 0x24, 0xd8, 0xf1, 0xc5, 0xb3, 0xe5, 0x25, 0xd5, 0x4f, 0x42, + 0x01, 0xbd, 0x27, 0x09, 0xac, 0x37, 0x3f, 0xd4, 0x50, 0xcc, 0xb6, 0x38, 0x1e, + 0xe6, 0x0d, 0x19, 0x0f, 0xd0, 0x1d, 0x0f, 0xf2, 0xa3, 0xf9, 0xe9, 0x07, 0xf4, + 0x09, 0x0c, 0xf6, 0xe8, 0x48, 0x18, 0xdd, 0x47, 0xaa, 0x17, 0x02, 0x00, 0x06, + 0x4b, 0xec, 0x2e, 0xf0, 0xe4, 0x28, 0xea, 0x31, 0x54, 0xa3, 0xe9, 0xb8, 0xee, + 0x2e, 0xa5, 0x9f, 0x00, 0xfa, 0xd0, 0x06, 0x13, 0x0f, 0x24, 0x16, 0x19, 0x58, + 0x1e, 0x07, 0x2e, 0x2f, 0xef, 0xfb, 0xcf, 0xeb, 0x3b, 0xa5, 0xf4, 0xcd, 0xb4, + 0x4e, 0x08, 0x7f, 0x06, 0xee, 0x2d, 0xcc, 0x04, 0x69, 0xe7, 0xe2, 0x1f, 0x00, + 0xe7, 0x00, 0xe5, 0xdb, 0xfb, 0x19, 0xb8, 0x00, 0x42, 0xd2, 0x3d, 0xb0, 0xd0, + 0x1a, 0x07, 0x24, 0xe9, 0xfc, 0x20, 0xec, 0x1a, 0xb8, 0x28, 0xc5, 0x24, 0x14, + 0xc9, 0x9e, 0x11, 0x00, 0xdf, 0xbd, 0x1d, 0xea, 0x19, 0xd5, 0xb0, 0x52, 0xf2, + 0xf3, 0x1d, 0xbe, 0xe9, 0xad, 0x3b, 0xe2, 0xff, 0xaa, 0xd6, 0xf1, 0xfe, 0x1f, + 0xda, 0xfa, 0x0f, 0x06, 0xb1, 0xf8, 0x20, 0x22, 0x67, 0x12, 0xea, 0xda, 0xa1, + 0xc3, 0xd6, 0x25, 0x57, 0xcb, 0xea, 0x1c, 0xf4, 0xcb, 0xb9, 0x44, 0xf7, 0x1f, + 0x3b, 0xe6, 0xb9, 0x9e, 0xd4, 0xd3, 0x2d, 0x4e, 0xe6, 0x09, 0xd8, 0x04, 0x58, + 0xf8, 0xc3, 0x9b, 0xe8, 0x14, 0xec, 0x41, 0xec, 0x01, 0xfe, 0x03, 0x19, 0xcd, + 0xc1, 0x90, 0x0b, 0xef, 0xda, 0x1d, 0xfa, 0x3d, 0xf5, 0x09, 0x11, 0xaa, 0x1d, + 0xe4, 0x10, 0x05, 0x14, 0xff, 0x1d, 0xe7, 0x36, 0x69, 0xee, 0x01, 0xfc, 0xd9, + 0x48, 0xe0, 0x06, 0x40, 0xfa, 0xcb, 0xf8, 0x65, 0x53, 0xfb, 0x0b, 0x7f, 0x53, + 0x2b, 0xed, 0x89, 0x50, 0x07, 0x03, 0x06, 0xf3, 0x12, 0x1c, 0xca, 0x1f, 0x72, + 0xd0, 0xce, 0x1e, 0x99, 0x20, 0x10, 0xbd, 0xf0, 0xd1, 0x48, 0xe1, 0x2b, 0xb6, + 0x38, 0xd0, 0x06, 0x05, 0xf6, 0x04, 0x19, 0x53, 0x1b, 0xbf, 0xaa, 0xd0, 0x06, + 0x26, 0xc4, 0x57, 0x46, 0xff, 0x0f, 0xa3, 0xfb, 0xf1, 0x0c, 0x2b, 0x33, 0xdc, + 0x10, 0x0f, 0x0e, 0xbd, 0x05, 0xbf, 0x2f, 0xe7, 0x2b, 0x0a, 0x00, 0x15, 0xfc, + 0xb1, 0x22, 0x01, 0x1e, 0x17, 0x08, 0x53, 0xfa, 0xcd, 0xf4, 0x39, 0xf7, 0xd6, + 0xe9, 0xd4, 0x01, 0xce, 0xcd, 0x27, 0x48, 0x91, 0xff, 0xd7, 0xaf, 0xbc, 0x32, + 0xb2, 0x26, 0xd4, 0xf6, 0x33, 0xc5, 0x29, 0x0d, 0xc3, 0x5a, 0xfd, 0x7c, 0x24, + 0xfc, 0xf8, 0xc3, 0x31, 0xba, 0xb5, 0x3d, 0xc7, 0xf0, 0x3f, 0xbf, 0x51, 0x17, + 0xd9, 0x79, 0xce, 0x17, 0xba, 0x29, 0xc4, 0x94, 0x33, 0xf9, 0xe9, 0xcb, 0x21, + 0xf7, 0x2e, 0x1e, 0xab, 0xeb, 0xc3, 0xfa, 0x0c, 0x0a, 0xc6, 0x81, 0x40, 0x00, + 0xfb, 0x0a, 0x0c, 0x01, 0xe3, 0x81, 0x00, 0x7e, 0xee, 0x48, 0x23, 0xd7, 0xde, + 0x42, 0x5e, 0xea, 0x11, 0xca, 0x47, 0xe9, 0x02, 0xf7, 0xd2, 0x28, 0x03, 0xf7, + 0xfa, 0x13, 0xc1, 0x2a, 0xdf, 0x01, 0xe7, 0xc8, 0x0b, 0xf6, 0xce, 0x42, 0x38, + 0x0c, 0x23, 0xc8, 0xd8, 0xed, 0x10, 0x22, 0xea, 0xfc, 0x28, 0xf9, 0xc7, 0x00, + 0xd6, 0xeb, 0x7a, 0x31, 0x33, 0xf2, 0xf6, 0xf4, 0x0c, 0x98, 0xe9, 0xd3, 0x2a, + 0xdf, 0x09, 0x1a, 0xf9, 0xf8, 0xfd, 0xe0, 0x1d, 0xec, 0x41, 0x28, 0x72, 0xf9, + 0xa4, 0xe1, 0xbf, 0xf1, 0xd7, 0xde, 0xf3, 0x05, 0x43, 0xf2, 0xcf, 0xc3, 0x1a, + 0xef, 0x05, 0x20, 0xef, 0xff, 0xeb, 0xfb, 0x16, 0x30, 0xc9, 0xe4, 0xcc, 0x1f, + 0xf4, 0xfb, 0xc3, 0x19, 0xf4, 0xa5, 0x32, 0x11, 0x07, 0x13, 0xec, 0x23, 0x50, + 0x0d, 0x02, 0xe1, 0xb0, 0x5c, 0xf8, 0x20, 0xd2, 0x44, 0x2e, 0xd0, 0x19, 0xc8, + 0xf8, 0xe1, 0x0f, 0xed, 0xed, 0xd3, 0x3d, 0xe5, 0x63, 0x4d, 0x3a, 0x32, 0xdb, + 0x31, 0x08, 0x3b, 0x56, 0x2c, 0xc2, 0x05, 0x2f, 0xfe, 0x16, 0xff, 0x17, 0x10, + 0xa0, 0xb7, 0x2a, 0x49, 0xb2, 0xf7, 0x0b, 0xbf, 0x33, 0xf8, 0xb9, 0x46, 0xfd, + 0x1a, 0x27, 0xd4, 0x12, 0x12, 0xe7, 0x25, 0x23, 0xf1, 0x1c, 0xda, 0x23, 0x47, + 0x22, 0xf4, 0x13, 0xda, 0x2d, 0xdc, 0xf1, 0xea, 0xda, 0x21, 0x35, 0xfc, 0x24, + 0xf2, 0xe3, 0x20, 0x0d, 0x39, 0xe8, 0x18, 0xe8, 0x7f, 0xde, 0xd8, 0x11, 0x33, + 0xcb, 0x20, 0xf4, 0x6f, 0x4a, 0xfe, 0x05, 0xf9, 0x2b, 0xff, 0x04, 0xe2, 0x28, + 0xec, 0x32, 0xdc, 0xf2, 0x07, 0x09, 0x43, 0xec, 0x11, 0xef, 0xdf, 0x11, 0xf0, + 0xfa, 0x10, 0xeb, 0xdb, 0x13, 0xc7, 0x19, 0xea, 0xd8, 0x06, 0x32, 0x19, 0x14, + 0x3c, 0x28, 0x09, 0xe4, 0x5b, 0x41, 0x1f, 0xfb, 0x57, 0x61, 0x57, 0x2d, 0x13, + 0xbd, 0x25, 0x38, 0x1b, 0x27, 0x2e, 0x34, 0x11, 0xbe, 0xda, 0x2a, 0x2a, 0xbe, + 0x0c, 0x02, 0x43, 0xe5, 0x1b, 0xf7, 0x08, 0xd8, 0x69, 0xd4, 0x27, 0x19, 0x4b, + 0xc6, 0x04, 0xc0, 0xf2, 0xe9, 0x3a, 0x25, 0xda, 0xc7, 0xf1, 0xd3, 0xae, 0x9e, + 0xc5, 0x2a, 0xea, 0x07, 0xd2, 0x04, 0xb9, 0x05, 0x5e, 0xda, 0x47, 0x81, 0xf6, + 0xf8, 0x01, 0x0a, 0x08, 0xe8, 0x11, 0xcb, 0xe2, 0xd7, 0xbe, 0x02, 0xb5, 0x2e, + 0x15, 0xf4, 0xce, 0xd6, 0x26, 0xf5, 0x28, 0x28, 0x39, 0xcb, 0xf1, 0x2f, 0xac, + 0xcc, 0x91, 0xed, 0x15, 0x0f, 0xd3, 0xd0, 0xed, 0xb8, 0x05, 0x0d, 0x47, 0xe9, + 0x18, 0x03, 0x1e, 0xdf, 0x18, 0xe0, 0xcf, 0xda, 0x5e, 0x99, 0x29, 0xc1, 0x3e, + 0xed, 0xf9, 0x4b, 0x9e, 0x06, 0xf6, 0x68, 0x27, 0xf2, 0xe2, 0xca, 0xf6, 0xc8, + 0xe6, 0xd7, 0xe7, 0xf7, 0xc3, 0xdd, 0x07, 0xf7, 0x17, 0xdb, 0xff, 0x05, 0x09, + 0x02, 0x01, 0xec, 0x0d, 0x01, 0x1d, 0xdf, 0x18, 0xb8, 0x15, 0xff, 0x35, 0xcf, + 0x06, 0x5f, 0x26, 0x1c, 0xdf, 0x05, 0xeb, 0x16, 0x42, 0x4d, 0xf8, 0x1f, 0xcd, + 0x20, 0xc4, 0xd5, 0x11, 0xf6, 0xea, 0x00, 0x23, 0x0b, 0xee, 0x37, 0x12, 0xe2, + 0xf2, 0x41, 0xea, 0x04, 0x0d, 0xd6, 0xd1, 0xd8, 0x18, 0xd5, 0xf1, 0x0f, 0xc1, + 0x01, 0x4a, 0x29, 0xeb, 0xd0, 0xfe, 0x00, 0x27, 0xf8, 0x11, 0x6d, 0x18, 0x5f, + 0x55, 0x47, 0x01, 0xe3, 0xf9, 0x09, 0xee, 0xdd, 0xdc, 0x2a, 0xbc, 0xaf, 0xd5, + 0xe1, 0xbd, 0x12, 0xe8, 0x0e, 0xf7, 0xec, 0xf7, 0xf3, 0x20, 0x1e, 0xc1, 0x19, + 0xfe, 0xe3, 0x1b, 0xff, 0xc1, 0xdc, 0xc3, 0xf0, 0xf7, 0x0b, 0x01, 0x35, 0x7f, + 0xeb, 0x2c, 0x3c, 0x0c, 0x0e, 0x43, 0xd6, 0xf2, 0xec, 0xf1, 0x10, 0xc7, 0xf1, + 0x13, 0x5a, 0x28, 0x0b, 0x0a, 0xf8, 0xe7, 0x2f, 0x02, 0x00, 0xf5, 0x0c, 0xeb, + 0x1b, 0xf8, 0x11, 0xfc, 0xfd, 0x12, 0x06, 0x0c, 0xdc, 0xcf, 0xbc, 0xeb, 0xde, + 0x41, 0x0a, 0xd7, 0x2a, 0xe4, 0x1b, 0x2d, 0x00, 0x0f, 0x39, 0xea, 0xf0, 0x02, + 0xe7, 0xdc, 0x1a, 0x2b, 0xf1, 0xe1, 0x3e, 0x05, 0x17, 0x00, 0x05, 0xe5, 0xef, + 0x32, 0x47, 0xe1, 0x17, 0x2e, 0x08, 0xe3, 0x25, 0x49, 0xfb, 0xff, 0x04, 0xf8, + 0x2b, 0x1e, 0x08, 0x46, 0x3e, 0xeb, 0x0b, 0xeb, 0x5b, 0x1d, 0x65, 0x39, 0xec, + 0x07, 0xb4, 0x15, 0xf9, 0xf5, 0x22, 0xfc, 0xcd, 0x79, 0x02, 0xed, 0xf7, 0x26, + 0xf3, 0xce, 0xc8, 0x21, 0x0e, 0x1e, 0xf1, 0x0f, 0x10, 0x1c, 0x1f, 0xf0, 0x11, + 0x2f, 0xda, 0xfc, 0xfb, 0xf8, 0x13, 0xd2, 0xca, 0xf2, 0x4b, 0xf0, 0x07, 0x31, + 0x7f, 0x05, 0x15, 0xe2, 0x1f, 0x04, 0x4f, 0x1e, 0x1b, 0x07, 0xd9, 0x4c, 0x48, + 0x3d, 0xf9, 0xfa, 0x05, 0xea, 0xe6, 0x14, 0x2b, 0xff, 0xef, 0x29, 0x04, 0xff, + 0xeb, 0x0d, 0x04, 0xeb, 0x16, 0x09, 0x06, 0xd3, 0xec, 0xfd, 0xdc, 0x3b, 0xd7, + 0x31, 0x10, 0x22, 0x7f, 0x3e, 0xc5, 0x24, 0x10, 0x14, 0x49, 0xfa, 0xf0, 0xcb, + 0xcc, 0xcb, 0x2a, 0xe0, 0x18, 0x18, 0xdc, 0xf5, 0xff, 0xed, 0xb0, 0x50, 0xf9, + 0x1a, 0xb7, 0xb4, 0x18, 0xd7, 0x0a, 0x35, 0xfc, 0x06, 0xc7, 0x0f, 0x62, 0xf6, + 0xdf, 0x06, 0xcc, 0x23, 0xbc, 0x45, 0x23, 0x14, 0x2a, 0xe7, 0x3e, 0xe0, 0x09, + 0xf3, 0xf0, 0x10, 0x00, 0xf3, 0x33, 0x3d, 0x37, 0x1d, 0xba, 0x1f, 0xf8, 0xf1, + 0x38, 0x01, 0xd3, 0x9f, 0x19, 0xc8, 0x1f, 0xe0, 0xc3, 0x12, 0xf6, 0x20, 0x57, + 0x24, 0x18, 0x01, 0xf0, 0x08, 0xd0, 0xed, 0x40, 0x0c, 0xdd, 0x17, 0x39, 0x2a, + 0xff, 0x85, 0xfa, 0x22, 0xf7, 0x09, 0xec, 0x02, 0x0f, 0x16, 0xb7, 0xc0, 0xc4, + 0xbd, 0xf0, 0xc4, 0x07, 0xc4, 0xea, 0x00, 0x13, 0xff, 0xd2, 0xf0, 0xf4, 0x0b, + 0xe3, 0xf6, 0xea, 0x0f, 0x36, 0xc2, 0xf9, 0xa8, 0xe1, 0xee, 0xd9, 0x1e, 0x0c, + 0xea, 0xd0, 0x1f, 0xd6, 0xf9, 0x18, 0x46, 0xdb, 0x22, 0xf2, 0xf5, 0x06, 0xda, + 0x39, 0x41, 0xfc, 0x48, 0xe8, 0xf9, 0xf7, 0x48, 0x27, 0x1e, 0x33, 0x0e, 0xd3, + 0xc5, 0xd3, 0x17, 0x7f, 0x05, 0x01, 0x2b, 0x21, 0xef, 0xef, 0x27, 0xf3, 0x12, + 0xfa, 0x01, 0x06, 0x0b, 0x26, 0x08, 0x25, 0x12, 0xf3, 0xf2, 0xc5, 0x0e, 0x07, + 0xd9, 0x07, 0x00, 0x25, 0xeb, 0x1e, 0x0c, 0x18, 0x1e, 0x03, 0xc6, 0x29, 0x20, + 0xfc, 0x04, 0xf0, 0xfa, 0xfe, 0x07, 0xf6, 0x1a, 0x18, 0x51, 0xf0, 0x17, 0xb8, + 0xfc, 0x03, 0x18, 0xe6, 0x0f, 0x36, 0xb9, 0xef, 0x1f, 0x3e, 0x34, 0x01, 0xe2, + 0x4e, 0x0d, 0xf4, 0x21, 0xfb, 0x2c, 0x0b, 0x28, 0x53, 0xef, 0xf7, 0x7b, 0x25, + 0xdb, 0xc9, 0xea, 0xe1, 0xf2, 0x45, 0x4a, 0xe8, 0x0a, 0xdc, 0x5b, 0xb3, 0xb8, + 0x9e, 0xb0, 0xe3, 0xf9, 0x5c, 0xc4, 0x05, 0xf4, 0xf5, 0x09, 0x0d, 0x24, 0xb0, + 0x42, 0x25, 0x22, 0xca, 0x3f, 0xd7, 0xfb, 0x81, 0x23, 0xd2, 0xea, 0x26, 0xf1, + 0xfc, 0x1c, 0x02, 0x0e, 0x4d, 0x06, 0xff, 0xc8, 0x78, 0xb6, 0xdf, 0xb7, 0x11, + 0xf3, 0x15, 0xf9, 0xf9, 0xe8, 0xec, 0x00, 0x67, 0xea, 0xd8, 0xc7, 0xfe, 0xb8, + 0x08, 0xd5, 0xed, 0x5a, 0xd7, 0x30, 0xe5, 0x0c, 0x14, 0x5f, 0xee, 0x23, 0x2b, + 0x32, 0x6c, 0xe8, 0x11, 0x30, 0xc4, 0x32, 0xdb, 0xfe, 0xd9, 0xd5, 0x51, 0xd9, + 0xda, 0x1d, 0x49, 0xdc, 0xe1, 0x04, 0xe1, 0x24, 0x16, 0xbd, 0xe6, 0x1d, 0xf0, + 0x34, 0x20, 0x0b, 0xfa, 0xf2, 0xc7, 0xcd, 0xd2, 0x36, 0x3e, 0xfa, 0x58, 0xf6, + 0xd0, 0x00, 0x0c, 0xde, 0x06, 0x40, 0x14, 0x96, 0x3b, 0xe9, 0x31, 0xe5, 0x34, + 0x0c, 0xf8, 0xf8, 0x63, 0x44, 0x0d, 0x1e, 0x4c, 0xf8, 0x0d, 0xfe, 0xe2, 0xe4, + 0x07, 0x2f, 0x09, 0x41, 0x16, 0xd8, 0x0d, 0x01, 0x36, 0x17, 0xe3, 0x28, 0xd7, + 0xf8, 0x5b, 0xde, 0x33, 0xf5, 0x2e, 0xea, 0x17, 0x07, 0x0f, 0x27, 0xfe, 0x31, + 0xe7, 0xea, 0x4a, 0xfa, 0xfa, 0x32, 0x0c, 0x06, 0xf4, 0x22, 0xfd, 0x5e, 0x3c, + 0x0f, 0x12, 0xfb, 0x1c, 0x23, 0x03, 0xdf, 0xe7, 0x1a, 0x0f, 0xfd, 0xff, 0xd9, + 0x20, 0xdd, 0x30, 0x12, 0xf7, 0xcc, 0xc8, 0x34, 0xfe, 0x19, 0xf6, 0x33, 0x0f, + 0x3d, 0x09, 0x50, 0x53, 0xcc, 0x03, 0x03, 0xd2, 0x10, 0x32, 0x00, 0xeb, 0x02, + 0xf4, 0x25, 0xd1, 0xf3, 0xf1, 0x45, 0xfe, 0xf6, 0x04, 0xee, 0x05, 0xfb, 0x0c, + 0xfb, 0x3d, 0xe8, 0xd9, 0xff, 0x7f, 0xdc, 0xd9, 0xe2, 0x42, 0x02, 0x1a, 0x17, + 0xe8, 0xff, 0x2e, 0x01, 0xfb, 0x0e, 0xfa, 0xff, 0xf4, 0x29, 0x2c, 0x20, 0xf1, + 0xd8, 0xfe, 0x05, 0xf9, 0xf6, 0xcf, 0x15, 0x0f, 0x0d, 0xd3, 0xdc, 0x25, 0x02, + 0xfa, 0xa1, 0xd1, 0xb7, 0xf6, 0x04, 0xe6, 0x19, 0x4d, 0x10, 0x1d, 0xc7, 0xe9, + 0x1d, 0x03, 0x18, 0xf5, 0x0a, 0x09, 0x09, 0x02, 0x12, 0x03, 0xc1, 0xf6, 0x1a, + 0xe0, 0x1b, 0x11, 0xd4, 0xc2, 0xf9, 0xf5, 0x54, 0xeb, 0x52, 0xeb, 0x0e, 0x19, + 0x1f, 0x06, 0xf6, 0x19, 0xf4, 0xf9, 0x1d, 0x10, 0x07, 0x18, 0xfa, 0xe1, 0x7f, + 0x0f, 0xf3, 0xf9, 0x2f, 0x10, 0xd7, 0xf9, 0xe7, 0x1c, 0xed, 0x0b, 0xd2, 0xce, + 0x24, 0x11, 0x50, 0xf3, 0x01, 0x36, 0xec, 0x08, 0xf2, 0x13, 0xc4, 0xfb, 0xdc, + 0x30, 0xf4, 0x0e, 0x14, 0xfa, 0xe6, 0x1f, 0xf5, 0xf4, 0x0a, 0xe6, 0x29, 0xea, + 0x1f, 0x36, 0xd2, 0xd9, 0x0a, 0xfb, 0xe8, 0xfd, 0x2a, 0x20, 0xed, 0xe1, 0x07, + 0x1b, 0xf6, 0xe9, 0xfc, 0x60, 0x01, 0x14, 0xde, 0x04, 0xb5, 0x13, 0x00, 0x1c, + 0x29, 0x27, 0xf9, 0x2c, 0x12, 0x33, 0xee, 0x26, 0xcb, 0x18, 0x01, 0xe6, 0xeb, + 0x27, 0xc1, 0x24, 0x03, 0xb9, 0x12, 0x0a, 0xe4, 0x3a, 0x12, 0x48, 0xeb, 0x22, + 0xef, 0xd6, 0xd1, 0x0d, 0xb7, 0x05, 0x72, 0xfa, 0xf4, 0xf4, 0x28, 0xb3, 0xce, + 0xdc, 0xf1, 0xb9, 0x05, 0x06, 0xd5, 0xfe, 0xf2, 0xaa, 0x23, 0xff, 0x1e, 0x18, + 0xf8, 0x25, 0xd3, 0xf4, 0x06, 0xf1, 0xff, 0x17, 0x0a, 0xef, 0xdc, 0xef, 0x11, + 0xf3, 0xf0, 0xae, 0x11, 0x47, 0xf4, 0xbc, 0xf3, 0xe2, 0x0b, 0xbd, 0xbd, 0x39, + 0xbb, 0x2b, 0x81, 0xe6, 0x04, 0xaa, 0xd1, 0x1b, 0xd2, 0x1f, 0x36, 0xc0, 0xd4, + 0xe0, 0x32, 0xf7, 0xb3, 0xba, 0x17, 0xa5, 0x02, 0xe9, 0x36, 0xf0, 0xcf, 0x2b, + 0xe3, 0x13, 0x05, 0x30, 0x20, 0x14, 0xe6, 0x13, 0x1d, 0xda, 0xfd, 0x58, 0x14, + 0x21, 0x48, 0xc8, 0x13, 0xe8, 0xd4, 0xcd, 0x0a, 0xf3, 0xce, 0xf2, 0xde, 0xff, + 0xe7, 0x03, 0x01, 0x06, 0xff, 0x14, 0xf2, 0x1d, 0xb2, 0xc5, 0x02, 0xd3, 0xf2, + 0x37, 0xc9, 0xf7, 0xfa, 0x36, 0x3d, 0xd5, 0x0c, 0xed, 0xe0, 0xdc, 0x13, 0x16, + 0xf1, 0x0e, 0xd5, 0xd3, 0x03, 0x47, 0x2e, 0xc1, 0x35, 0xe4, 0xd8, 0x1b, 0x04, + 0xce, 0x1c, 0x4e, 0xcd, 0xf3, 0xf8, 0xf5, 0x19, 0x3f, 0xfa, 0x00, 0xda, 0x1b, + 0xe9, 0x36, 0xfe, 0x1e, 0x17, 0x30, 0xf0, 0x0c, 0x3f, 0x10, 0x23, 0xe1, 0x01, + 0xbf, 0xf3, 0x15, 0x1c, 0x0e, 0xf4, 0xf2, 0x51, 0xfe, 0xf0, 0x46, 0x2e, 0x17, + 0xf6, 0x23, 0x05, 0xf8, 0xed, 0xfe, 0xd5, 0xf5, 0xd9, 0xed, 0xce, 0x33, 0x7f, + 0x03, 0x0f, 0xfd, 0x2b, 0x13, 0x0c, 0xff, 0x1b, 0xf9, 0xf3, 0x2d, 0x01, 0x32, + 0xfe, 0xfe, 0xee, 0x06, 0x1c, 0x20, 0x22, 0xeb, 0x24, 0xcd, 0x37, 0x02, 0x3d, + 0x1b, 0x20, 0x20, 0xfa, 0xb2, 0xf0, 0x32, 0xb9, 0xda, 0xf3, 0xdd, 0xf3, 0x19, + 0xe3, 0x0f, 0x17, 0x17, 0xe0, 0xe6, 0xd5, 0x14, 0x38, 0x24, 0xdf, 0x05, 0xce, + 0x28, 0xc7, 0xfa, 0x39, 0x57, 0x34, 0x08, 0xbc, 0x21, 0xcd, 0xf8, 0x1d, 0xee, + 0x21, 0x1a, 0x21, 0x0d, 0xea, 0x3a, 0xda, 0x43, 0xda, 0xf2, 0xe6, 0xf8, 0xd2, + 0xe1, 0x1a, 0xd6, 0xf6, 0xc4, 0x21, 0x3f, 0xd9, 0x1f, 0x02, 0x01, 0xe5, 0xf1, + 0x55, 0x0f, 0xd7, 0x24, 0x18, 0x1c, 0xff, 0xed, 0x0b, 0xef, 0xe2, 0xc8, 0x11, + 0xec, 0xd3, 0x1a, 0x01, 0x7f, 0x64, 0xee, 0x29, 0xde, 0x33, 0x2b, 0xb1, 0x06, + 0x18, 0x21, 0xf0, 0x01, 0x04, 0x1c, 0xc1, 0x07, 0x17, 0x3f, 0x17, 0xce, 0xe3, + 0xce, 0xf9, 0x26, 0x06, 0xdf, 0x21, 0xd4, 0x0c, 0xdd, 0x08, 0x05, 0x2b, 0xf9, + 0x15, 0xd0, 0xdb, 0xde, 0xc6, 0x00, 0xcb, 0xd5, 0x08, 0x1d, 0x09, 0xc9, 0x1f, + 0xdd, 0x1c, 0x57, 0xc6, 0xc9, 0xe7, 0x3b, 0xe7, 0xdb, 0xf8, 0x28, 0xfd, 0xdd, + 0xae, 0xe6, 0xf9, 0x0b, 0x37, 0xe5, 0x1a, 0x06, 0x00, 0x04, 0xd5, 0x18, 0xf4, + 0x1b, 0xc7, 0xd4, 0x06, 0xcc, 0x14, 0x1c, 0x13, 0xd3, 0xc0, 0xe4, 0xc9, 0x5e, + 0xfb, 0xe6, 0xbc, 0xf2, 0x13, 0x15, 0xf2, 0x0f, 0xfd, 0x00, 0xfe, 0xc9, 0xd7, + 0xf3, 0x3f, 0x24, 0x2a, 0xdb, 0xdc, 0xd7, 0xd7, 0x2f, 0xf5, 0xd8, 0xfe, 0x12, + 0x06, 0xdb, 0xf3, 0x08, 0x00, 0xe0, 0xd4, 0xf2, 0xf9, 0xf6, 0xbd, 0xf9, 0x0f, + 0x13, 0xef, 0xfb, 0xfd, 0x47, 0x7f, 0xdc, 0xe6, 0x3a, 0x05, 0xdc, 0xe3, 0xf1, + 0x0f, 0xe9, 0xdc, 0x37, 0x04, 0xd2, 0xe5, 0x0b, 0xe0, 0xf9, 0xc3, 0x19, 0xe9, + 0xe9, 0x02, 0xdc, 0x01, 0xd3, 0xad, 0xea, 0xed, 0xd8, 0x2f, 0x1b, 0xfa, 0x08, + 0x0b, 0x0c, 0xff, 0xc3, 0x0d, 0xf2, 0xe6, 0x22, 0x30, 0x27, 0x10, 0x40, 0x3e, + 0xed, 0xe3, 0xff, 0x44, 0x14, 0x15, 0x1d, 0xff, 0x5e, 0xf6, 0xf0, 0x06, 0x00, + 0x23, 0xe7, 0xe4, 0xcc, 0xf1, 0xa5, 0xd1, 0xde, 0x18, 0x12, 0x1f, 0x0b, 0xf9, + 0xbd, 0xe5, 0xfd, 0xd3, 0xba, 0x29, 0x01, 0xc7, 0x22, 0x6d, 0x39, 0x3d, 0x06, + 0xcc, 0xd2, 0xc6, 0xe9, 0xfd, 0x0e, 0xcf, 0x08, 0x0a, 0x0e, 0xe3, 0xea, 0xd3, + 0xdb, 0x18, 0xc9, 0x3c, 0xfc, 0x08, 0x38, 0xf4, 0x04, 0x14, 0xea, 0x0d, 0x12, + 0xfd, 0x5a, 0xed, 0x44, 0x7f, 0x34, 0x42, 0xb8, 0xd2, 0xf4, 0xc7, 0x0d, 0xc5, + 0x01, 0x17, 0xf4, 0xec, 0xc9, 0x44, 0xad, 0x6f, 0x39, 0x1a, 0xd6, 0xfa, 0xfa, + 0x17, 0xd5, 0x31, 0xf9, 0x1a, 0xdf, 0x25, 0x2b, 0xea, 0xd1, 0x08, 0xe8, 0x13, + 0xd8, 0xef, 0x6d, 0xcd, 0x40, 0xd6, 0x51, 0xe3, 0x55, 0x19, 0x21, 0xde, 0x1d, + 0x57, 0x21, 0x34, 0xd8, 0x3f, 0x46, 0x44, 0x97, 0x1f, 0xe7, 0x09, 0x19, 0x35, + 0x17, 0x1d, 0x3c, 0x5b, 0x23, 0xbb, 0x60, 0x13, 0xc6, 0xeb, 0x6b, 0x1d, 0xe2, + 0x7f, 0x4b, 0xd8, 0xd2, 0xeb, 0x1e, 0xd1, 0x39, 0x10, 0x27, 0x42, 0xfa, 0x1f, + 0xdd, 0xf1, 0xf1, 0xd5, 0xcf, 0x32, 0xe2, 0xf0, 0x31, 0xfd, 0x3d, 0xb8, 0x0f, + 0x32, 0x5e, 0x2e, 0x2e, 0x75, 0x40, 0x08, 0x1c, 0x48, 0x50, 0xe2, 0xf1, 0xe2, + 0xc2, 0x25, 0xf5, 0x21, 0x68, 0xfa, 0xd3, 0x17, 0xeb, 0xdb, 0x0a, 0x0a, 0x0c, + 0x27, 0xed, 0x0e, 0xd6, 0x40, 0x3c, 0x39, 0x0d, 0xb2, 0xed, 0x18, 0xd9, 0xf6, + 0x06, 0x4b, 0x2b, 0xcc, 0x05, 0xdd, 0xd0, 0x35, 0x23, 0x02, 0x4f, 0x4e, 0x05, + 0xdd, 0xe8, 0x18, 0xf5, 0x03, 0x07, 0xdb, 0xe9, 0xe8, 0x46, 0x24, 0x27, 0x1d, + 0xfb, 0xbe, 0xff, 0xfb, 0xab, 0x55, 0xd1, 0x40, 0x06, 0xf7, 0x09, 0x32, 0xf0, + 0x08, 0xe6, 0xeb, 0x53, 0xe6, 0xf0, 0x67, 0x0f, 0x05, 0x11, 0xd6, 0xe1, 0xbf, + 0xd4, 0x24, 0xe9, 0x25, 0xfe, 0xed, 0xce, 0x00, 0x16, 0x21, 0xf8, 0x10, 0x71, + 0xcb, 0xeb, 0xdc, 0xf1, 0xef, 0xfd, 0x06, 0xe2, 0x24, 0xd4, 0xe9, 0xf4, 0x23, + 0x10, 0xff, 0xf8, 0x28, 0xf5, 0xee, 0xf0, 0xe2, 0xe6, 0xe1, 0xab, 0xcf, 0x39, + 0x2a, 0xad, 0xe2, 0xd9, 0xbf, 0xf4, 0x62, 0xa9, 0xcf, 0x2a, 0x24, 0x1c, 0x0d, + 0xd7, 0x1a, 0xd0, 0xa2, 0xfb, 0x14, 0x08, 0xe0, 0xda, 0xd7, 0xf4, 0xd6, 0xec, + 0x16, 0xf1, 0xf7, 0xcd, 0x2e, 0xf4, 0x81, 0xd3, 0x31, 0x89, 0x9d, 0xae, 0x04, + 0xe6, 0x5e, 0x17, 0xd3, 0xf0, 0xd2, 0x2e, 0x19, 0x06, 0x0e, 0xf1, 0x13, 0x14, + 0xf4, 0xda, 0xc4, 0xf6, 0xa9, 0xba, 0x3b, 0xdf, 0xf3, 0xbb, 0x11, 0xee, 0xf4, + 0x20, 0xef, 0x04, 0x1a, 0x02, 0x06, 0x32, 0x06, 0x0e, 0x12, 0xba, 0x14, 0x14, + 0x39, 0xf2, 0xcc, 0x05, 0xf3, 0x03, 0xd6, 0xfc, 0x03, 0xf2, 0x36, 0xee, 0xfe, + 0x2f, 0x42, 0xe1, 0x35, 0xc8, 0x10, 0xed, 0xe6, 0x1b, 0xf0, 0xcc, 0x05, 0x77, + 0xf8, 0x13, 0x0e, 0xc3, 0xcc, 0x19, 0x6c, 0x7f, 0xd9, 0xdd, 0xdc, 0xf9, 0xc8, + 0xf0, 0x08, 0xce, 0xd1, 0x4f, 0xee, 0x4c, 0xf7, 0x22, 0x22, 0xfb, 0x0d, 0x5d, + 0xcb, 0xfc, 0x16, 0xf7, 0xef, 0xfd, 0xe4, 0xf6, 0xe2, 0x27, 0x9d, 0xe0, 0xc4, + 0xec, 0xf9, 0xe7, 0xef, 0xf8, 0xf2, 0x21, 0x10, 0xf9, 0x02, 0x34, 0x15, 0x33, + 0xe2, 0xe9, 0xf5, 0xa7, 0x61, 0x27, 0xcd, 0x16, 0x0a, 0xcf, 0xed, 0xb9, 0xf0, + 0xed, 0x05, 0xf0, 0xb1, 0xf5, 0xb4, 0x00, 0x1e, 0xe9, 0xa4, 0xd5, 0x2c, 0x0d, + 0x3d, 0xd3, 0xc5, 0xd5, 0x0f, 0xd1, 0xea, 0xc0, 0x01, 0xea, 0xbb, 0xf3, 0xee, + 0xd7, 0x0c, 0x0e, 0xf1, 0xa8, 0x05, 0x17, 0xe9, 0x17, 0xfa, 0xfb, 0xfb, 0x1d, + 0xdd, 0xc3, 0x0f, 0x02, 0xe8, 0x1a, 0x0c, 0xdf, 0x48, 0x4c, 0x41, 0xca, 0x27, + 0x12, 0xd2, 0x93, 0xf6, 0xd5, 0xd7, 0xf0, 0x4c, 0x51, 0xeb, 0xf3, 0x56, 0x1b, + 0xa9, 0x39, 0x03, 0x04, 0x7f, 0xd8, 0x26, 0x0e, 0x23, 0xdc, 0x06, 0xeb, 0xce, + 0xb8, 0x2f, 0xe3, 0xec, 0x37, 0x07, 0x26, 0x23, 0x4f, 0x32, 0x09, 0xd4, 0x2f, + 0xff, 0xa4, 0x7d, 0x19, 0x32, 0x67, 0x07, 0xe3, 0x00, 0xab, 0xde, 0xc9, 0xf3, + 0xe5, 0x0f, 0xee, 0xbe, 0x29, 0xf1, 0xd8, 0x1b, 0xcb, 0x12, 0xe2, 0xf8, 0xe2, + 0xe8, 0x20, 0x26, 0xda, 0x63, 0x0c, 0xd6, 0x28, 0xff, 0xc1, 0x49, 0x5f, 0x20, + 0xde, 0xed, 0xf7, 0xee, 0x02, 0x3c, 0x10, 0x22, 0x06, 0x1a, 0xe4, 0xe9, 0x0d, + 0xf6, 0xe8, 0xff, 0xef, 0xe7, 0x00, 0x2b, 0xf3, 0x33, 0xfb, 0x16, 0xd8, 0x52, + 0xfe, 0x2e, 0x07, 0x01, 0x25, 0x06, 0x20, 0x35, 0x25, 0x02, 0x2e, 0x0f, 0xfe, + 0x2f, 0xdb, 0x45, 0x0e, 0x43, 0x2e, 0xe5, 0x02, 0xe5, 0x01, 0x1f, 0xe7, 0x18, + 0xf4, 0x22, 0x06, 0x1d, 0x18, 0xf7, 0x2d, 0xe3, 0xbb, 0xc9, 0x12, 0xce, 0x10, + 0x1e, 0x67, 0xf2, 0x9d, 0xfa, 0x09, 0xd3, 0xca, 0x38, 0x56, 0xed, 0x3f, 0x0e, + 0xb3, 0x71, 0x34, 0xe0, 0xbb, 0xde, 0xd8, 0xad, 0x20, 0x3b, 0x23, 0x2a, 0x01, + 0xdd, 0xc4, 0xcd, 0xec, 0xec, 0x01, 0x37, 0xfe, 0x06, 0xb6, 0xbe, 0x3e, 0xd9, + 0xfb, 0x09, 0xc9, 0x58, 0x2e, 0xf2, 0x29, 0x7c, 0x3d, 0xe1, 0xa0, 0x26, 0xdc, + 0xf5, 0x34, 0xa1, 0x1f, 0x19, 0xb1, 0xe0, 0x1f, 0x7c, 0xfa, 0xde, 0xf2, 0x0d, + 0x10, 0xdb, 0x30, 0xf5, 0x0e, 0x9d, 0xdf, 0xfd, 0xed, 0x52, 0x20, 0x06, 0x0a, + 0xe3, 0xc9, 0x24, 0xe9, 0x0d, 0x52, 0xe1, 0xdf, 0x37, 0x48, 0xb3, 0xa4, 0x23, + 0xac, 0x37, 0x09, 0xd4, 0x24, 0xfa, 0x28, 0x7f, 0xcb, 0x0e, 0x17, 0x29, 0x0c, + 0xc4, 0xcf, 0xfa, 0xdb, 0xb5, 0xe9, 0xb8, 0x0e, 0x15, 0xb1, 0xfd, 0xe1, 0xd8, + 0x0b, 0xf3, 0x20, 0xe9, 0xff, 0xcc, 0x1f, 0xc4, 0xde, 0x08, 0x22, 0x38, 0xe0, + 0x00, 0xf4, 0x1a, 0x36, 0xaa, 0x34, 0x1d, 0x29, 0xcf, 0x2f, 0xea, 0x05, 0x30, + 0x4e, 0x03, 0xdf, 0x07, 0xc9, 0xba, 0x52, 0xf3, 0x39, 0x1f, 0xfa, 0xc2, 0x47, + 0xba, 0xc5, 0xef, 0xf9, 0xf9, 0x2c, 0xfd, 0xf4, 0xf9, 0xe2, 0x24, 0xf8, 0x15, + 0x10, 0xf5, 0x4d, 0xf5, 0x08, 0x3c, 0xe9, 0xf9, 0xc2, 0x0f, 0xba, 0x3f, 0xe3, + 0x81, 0x37, 0xf5, 0x21, 0xb9, 0x3d, 0x10, 0x0a, 0xb9, 0x08, 0x11, 0xf8, 0x15, + 0x12, 0x4b, 0x27, 0xe1, 0xe4, 0xdd, 0xe1, 0x30, 0xd9, 0x76, 0xfd, 0xf2, 0x0f, + 0x09, 0xf5, 0xef, 0x27, 0xfc, 0x90, 0x0a, 0xf5, 0x12, 0xd0, 0x39, 0xf4, 0x0b, + 0xfa, 0x11, 0x06, 0xfa, 0x0b, 0x51, 0x38, 0xe3, 0x36, 0xdd, 0x9c, 0xe8, 0xff, + 0x22, 0x28, 0xaf, 0x26, 0x11, 0xd0, 0xc6, 0xf1, 0x0d, 0xeb, 0x25, 0xce, 0xac, + 0x33, 0x0b, 0xd3, 0x0f, 0xc0, 0xd8, 0xe5, 0x47, 0xcd, 0xb4, 0x59, 0xa6, 0x5b, + 0xff, 0xdb, 0xf8, 0xed, 0xb7, 0x24, 0x37, 0x07, 0x96, 0xee, 0x7f, 0xb8, 0xe6, + 0x1e, 0xa0, 0xc6, 0x3f, 0xc2, 0x48, 0x8c, 0x33, 0x23, 0xe3, 0xea, 0xc5, 0xf1, + 0xf0, 0x28, 0x07, 0x3b, 0x2c, 0xbc, 0x10, 0xc3, 0x3a, 0xf5, 0xdf, 0x35, 0x17, + 0x92, 0x58, 0xc3, 0xf7, 0x50, 0xdf, 0xc0, 0xaf, 0x02, 0xfd, 0x1b, 0xed, 0x05, + 0x3c, 0xf3, 0x08, 0x19, 0x67, 0xd3, 0xe9, 0x39, 0xbf, 0xc1, 0xc2, 0x24, 0xe1, + 0xbc, 0xb0, 0x17, 0xd6, 0xe1, 0x3d, 0x26, 0xc6, 0x34, 0x23, 0xcd, 0xf5, 0xfd, + 0x0c, 0x0f, 0x33, 0x03, 0x09, 0xeb, 0xb3, 0x08, 0x12, 0xfc, 0xfa, 0x00, 0xe9, + 0x39, 0xc3, 0xf3, 0xf3, 0xfe, 0xb7, 0x19, 0x25, 0x17, 0xee, 0xe4, 0xe9, 0xdd, + 0xd4, 0xd0, 0xd4, 0x1c, 0xd8, 0x22, 0x36, 0x1e, 0x1e, 0x7f, 0x2e, 0x18, 0x29, + 0x2e, 0x14, 0x41, 0xed, 0xed, 0x3c, 0x01, 0xd1, 0x1b, 0x14, 0xc5, 0x30, 0xdb, + 0xf9, 0x22, 0xc5, 0x14, 0x10, 0x0f, 0x31, 0x03, 0x3e, 0xca, 0xe3, 0xff, 0x1e, + 0xf7, 0xe7, 0x2d, 0x33, 0x24, 0x17, 0xe6, 0x11, 0x0f, 0xd4, 0xd1, 0x21, 0x0c, + 0x18, 0xfa, 0x1a, 0x52, 0x24, 0x18, 0x49, 0xf6, 0x1e, 0xf4, 0xe7, 0x18, 0x25, + 0x38, 0xf7, 0xf2, 0xdd, 0x44, 0x46, 0x62, 0x51, 0xd5, 0x3d, 0x12, 0x14, 0x19, + 0x1e, 0x5a, 0x03, 0xe5, 0x18, 0x03, 0x11, 0x11, 0x17, 0xe8, 0xfa, 0x1c, 0x3a, + 0xfc, 0x05, 0x2a, 0xf5, 0x06, 0xf4, 0xd2, 0x28, 0x1f, 0xe8, 0xd3, 0x16, 0x21, + 0x32, 0xfa, 0x07, 0x54, 0xfc, 0x00, 0xe4, 0x53, 0x17, 0xf1, 0xf3, 0xf6, 0x25, + 0x17, 0x25, 0x4c, 0xfa, 0x1a, 0x07, 0x0e, 0xca, 0xe1, 0xea, 0x08, 0xde, 0xc8, + 0xdf, 0xc9, 0x13, 0x0a, 0x26, 0x02, 0x23, 0xf9, 0x1c, 0xff, 0xcb, 0xa1, 0xfc, + 0x29, 0xdd, 0x06, 0xcf, 0x49, 0x23, 0x5e, 0x29, 0xfd, 0x7a, 0xf3, 0x03, 0x0f, + 0x1f, 0xe1, 0xe7, 0xb5, 0x26, 0x31, 0xc4, 0x2f, 0x97, 0xbf, 0x20, 0x1d, 0x18, + 0x23, 0xf7, 0x09, 0x15, 0x11, 0x81, 0x2f, 0x3e, 0x66, 0xf4, 0xe9, 0xc3, 0xfb, + 0xe9, 0x49, 0xcb, 0xce, 0x0a, 0xf9, 0xa4, 0xf3, 0xc8, 0x44, 0x14, 0xec, 0x21, + 0x06, 0xff, 0xa9, 0xea, 0x16, 0xfb, 0xd0, 0x17, 0x14, 0xc8, 0x36, 0x1b, 0xbd, + 0xe3, 0x2e, 0xe7, 0xf4, 0x0c, 0x2b, 0x05, 0xa9, 0xcf, 0x45, 0xf0, 0x9e, 0x13, + 0x19, 0x60, 0xbc, 0xea, 0x1a, 0x5a, 0xd9, 0x41, 0x72, 0x31, 0x02, 0x67, 0xfd, + 0x1e, 0xdf, 0x15, 0x2c, 0x41, 0x0f, 0x08, 0x14, 0x10, 0xdb, 0xfc, 0xda, 0x50, + 0x0f, 0x19, 0x02, 0x08, 0xf9, 0x31, 0x04, 0xce, 0xb8, 0x23, 0xc6, 0x08, 0x07, + 0x26, 0xfd, 0xee, 0x05, 0xf9, 0xd2, 0xeb, 0x1e, 0xbd, 0x01, 0xe4, 0xa2, 0xcd, + 0xd4, 0xd3, 0xe8, 0x70, 0xec, 0x0e, 0x06, 0xd8, 0xd5, 0xcb, 0x02, 0x1f, 0xc8, + 0xfc, 0xc1, 0x16, 0x0e, 0x18, 0x2e, 0x05, 0xf2, 0xf4, 0xec, 0xfe, 0x3a, 0xfb, + 0x02, 0x0b, 0xfa, 0x36, 0x92, 0x01, 0x20, 0xef, 0xed, 0xec, 0x23, 0x3b, 0x11, + 0x1f, 0xd3, 0xfa, 0x11, 0xa6, 0xe2, 0x9b, 0xda, 0x28, 0xf0, 0x08, 0xa9, 0x73, + 0xf4, 0xd7, 0xd3, 0xbf, 0xe6, 0xef, 0x33, 0xad, 0xc9, 0x1f, 0x25, 0x19, 0x3f, + 0x0d, 0x25, 0xe2, 0xee, 0x13, 0xf8, 0x2f, 0xbf, 0x04, 0x09, 0x7f, 0xf1, 0x2a, + 0xfa, 0xd2, 0x2a, 0x20, 0x04, 0x47, 0xfe, 0x10, 0x09, 0xae, 0x17, 0x41, 0xd6, + 0x46, 0x2f, 0xea, 0x16, 0x34, 0x12, 0xea, 0x0d, 0x4c, 0x27, 0xf6, 0x05, 0x87, + 0x2b, 0x01, 0x10, 0xe8, 0x1a, 0xdc, 0x0d, 0xf8, 0x03, 0xee, 0x26, 0x44, 0x18, + 0xce, 0x14, 0xf1, 0x35, 0x1c, 0x11, 0xe8, 0x31, 0xfa, 0xdc, 0x03, 0x05, 0x33, + 0x01, 0xd0, 0x03, 0x21, 0xc7, 0x26, 0x2f, 0x1a, 0x0e, 0x23, 0x2b, 0xee, 0x39, + 0x1c, 0xe9, 0xda, 0x55, 0x10, 0x01, 0x09, 0x13, 0x09, 0xf6, 0x25, 0x08, 0x0e, + 0x27, 0x19, 0xbd, 0x06, 0x12, 0x30, 0xee, 0xe7, 0x38, 0x05, 0x27, 0x20, 0x0f, + 0x41, 0xd1, 0x08, 0x33, 0x51, 0x51, 0x17, 0x0f, 0x2b, 0x3f, 0x0b, 0xcb, 0x01, + 0xeb, 0x28, 0x1c, 0xde, 0xf7, 0x4b, 0x14, 0x01, 0x10, 0x45, 0x0e, 0xe6, 0x0f, + 0x00, 0xf1, 0xf3, 0xff, 0x13, 0x16, 0x06, 0x29, 0xc4, 0xdf, 0x4d, 0x5f, 0xe7, + 0x0e, 0xf9, 0xff, 0xeb, 0x19, 0x27, 0x59, 0xe6, 0x0c, 0x04, 0x7f, 0x13, 0xe0, + 0x09, 0x28, 0x23, 0x61, 0xf6, 0xe7, 0x16, 0xc8, 0x36, 0x19, 0x43, 0x02, 0xfe, + 0xb9, 0xe2, 0x05, 0xe8, 0xf5, 0x26, 0x05, 0xcd, 0x31, 0x28, 0xfc, 0x21, 0x18, + 0xfc, 0xd1, 0x23, 0xe7, 0x14, 0xc8, 0x25, 0xea, 0xd3, 0xf6, 0xee, 0x24, 0x1f, + 0x0d, 0xe8, 0xb8, 0x01, 0x30, 0xe1, 0xe6, 0x0c, 0x0a, 0x03, 0x3d, 0x3d, 0x15, + 0x3d, 0xf9, 0x19, 0xff, 0xc4, 0xf2, 0x13, 0xea, 0xe6, 0x3a, 0xf9, 0x29, 0xdb, + 0x5a, 0xe6, 0xdc, 0x18, 0xff, 0xe2, 0x44, 0x15, 0x1d, 0xf6, 0xf6, 0x24, 0xcf, + 0xf1, 0x08, 0xe0, 0x54, 0x0d, 0x1b, 0x3a, 0xf9, 0x04, 0xd5, 0x35, 0xfd, 0x3a, + 0x5b, 0xd4, 0xf7, 0x51, 0xe4, 0xd8, 0x1c, 0xf6, 0x11, 0xdf, 0xd9, 0x07, 0xd1, + 0xfe, 0xff, 0x04, 0xff, 0xfd, 0x02, 0xff, 0x0f, 0x7f, 0xe9, 0xe6, 0x1b, 0x0c, + 0x0b, 0x35, 0xf9, 0x12, 0x66, 0xe8, 0x2e, 0xe8, 0x6a, 0x15, 0x09, 0xfb, 0xfc, + 0xd7, 0xec, 0xf3, 0x05, 0x0b, 0xfb, 0x4a, 0x0c, 0x32, 0xe7, 0x10, 0xe7, 0x01, + 0xe3, 0xca, 0x0c, 0xd6, 0xf1, 0xed, 0x37, 0x13, 0xea, 0xff, 0x01, 0xbd, 0x1b, + 0x00, 0x15, 0xf3, 0xf4, 0xee, 0xff, 0x17, 0xf7, 0x34, 0x01, 0xff, 0x2a, 0x0c, + 0x1f, 0x10, 0xe0, 0xfc, 0x16, 0xfe, 0x06, 0xee, 0x08, 0xe2, 0xcd, 0x06, 0xf2, + 0xf6, 0xe4, 0xea, 0xeb, 0xd6, 0xbe, 0x1f, 0x16, 0xe4, 0xf0, 0xce, 0xfd, 0x05, + 0x0b, 0x0c, 0x03, 0xf3, 0x03, 0x18, 0x06, 0xf6, 0xe2, 0x1e, 0x00, 0x07, 0xe5, + 0x13, 0xf7, 0xea, 0x18, 0xf8, 0x27, 0xcf, 0xd3, 0xda, 0xe4, 0x0b, 0x20, 0xd4, + 0x03, 0x33, 0xf5, 0x18, 0x16, 0x7f, 0xe2, 0xf9, 0x18, 0xcb, 0x2e, 0xe4, 0x05, + 0xed, 0x19, 0xf7, 0x15, 0x14, 0xea, 0x34, 0xe8, 0x19, 0xf6, 0x09, 0x0a, 0xfb, + 0xbd, 0xfe, 0xeb, 0x01, 0x03, 0x44, 0x1a, 0x11, 0xc7, 0xb3, 0xf6, 0x19, 0x35, + 0xf7, 0x07, 0xeb, 0x20, 0x1f, 0x12, 0xf4, 0xf7, 0xdf, 0x12, 0xff, 0xda, 0x2d, + 0xfb, 0xc2, 0xbc, 0x2d, 0x07, 0x33, 0xdd, 0xfa, 0xf8, 0x33, 0xef, 0x10, 0x2b, + 0xe4, 0x1b, 0xc5, 0x65, 0xb2, 0x4a, 0x06, 0x0f, 0xb7, 0x6a, 0x56, 0x55, 0xe2, + 0xf7, 0xbd, 0x16, 0xdd, 0x10, 0xf2, 0xd3, 0xe9, 0x55, 0x53, 0x03, 0x7f, 0xc0, + 0xe1, 0xf6, 0xf8, 0x22, 0x13, 0x06, 0x4d, 0xdc, 0x1a, 0xe9, 0xfa, 0x37, 0xf0, + 0xaa, 0xc3, 0xe9, 0x08, 0xd3, 0x27, 0xcc, 0x06, 0x1e, 0xd9, 0xef, 0xf3, 0x15, + 0xdc, 0x18, 0x27, 0x32, 0xdd, 0x03, 0xfb, 0xed, 0x0e, 0x19, 0xc3, 0xd6, 0xed, + 0xca, 0xf7, 0xb1, 0x08, 0xf2, 0x04, 0xf8, 0xd4, 0x1b, 0xe4, 0x15, 0x5b, 0xd0, + 0xab, 0xd1, 0x41, 0xe4, 0x12, 0xcb, 0xc9, 0x0d, 0xf4, 0xf6, 0xc2, 0x0f, 0xcc, + 0xdd, 0x9e, 0x02, 0x2b, 0xdd, 0x1d, 0xf6, 0xf8, 0xec, 0xcb, 0xea, 0xef, 0xf3, + 0x0d, 0x2b, 0x1b, 0x0f, 0xfe, 0xfd, 0xe9, 0x55, 0x32, 0x49, 0xca, 0x04, 0x29, + 0xe9, 0x3f, 0xca, 0x09, 0x59, 0x05, 0xd7, 0xf5, 0x14, 0xe0, 0xfd, 0x7f, 0x02, + 0xd6, 0x08, 0xf0, 0xd8, 0xfc, 0xae, 0xea, 0xce, 0xeb, 0x04, 0xfa, 0x55, 0xe0, + 0x19, 0x0b, 0xd3, 0xc7, 0xaf, 0x0a, 0xf3, 0xcc, 0xff, 0x2e, 0x0d, 0x16, 0x10, + 0x00, 0xe0, 0xb5, 0xe4, 0xae, 0xba, 0x20, 0x02, 0xe6, 0x19, 0xd9, 0xfd, 0xd6, + 0xf8, 0x02, 0x32, 0xeb, 0xfa, 0xc4, 0xe4, 0xaf, 0x17, 0xcd, 0xfe, 0x02, 0x1d, + 0x11, 0xd8, 0x53, 0x28, 0x6a, 0x44, 0x10, 0xfa, 0xde, 0xee, 0xef, 0x2d, 0x30, + 0xc8, 0xa9, 0x49, 0xdc, 0x14, 0xf9, 0xee, 0xff, 0xf1, 0x3e, 0xf5, 0xec, 0x51, + 0xf6, 0xea, 0xde, 0xc4, 0x28, 0xb0, 0x33, 0x2e, 0x4a, 0xf3, 0x08, 0x01, 0x36, + 0x10, 0x42, 0x01, 0x09, 0xf7, 0xfd, 0x73, 0xbb, 0x33, 0xd0, 0xbf, 0x0e, 0x30, + 0x08, 0xf5, 0xf6, 0x64, 0xd4, 0x1d, 0xc0, 0x3b, 0x13, 0xbb, 0x1b, 0xe7, 0x70, + 0xec, 0x36, 0x20, 0xb3, 0xc1, 0x50, 0x09, 0xb9, 0xf9, 0x4f, 0x72, 0x62, 0x76, + 0x1c, 0x09, 0x22, 0x3c, 0xf1, 0x11, 0xb4, 0x26, 0xe5, 0x26, 0xff, 0xbd, 0x09, + 0xb1, 0x06, 0xe8, 0x31, 0x43, 0xed, 0xf4, 0x33, 0xae, 0xc8, 0x40, 0x46, 0xde, + 0xa9, 0x1e, 0x07, 0xc2, 0x7e, 0xe0, 0x33, 0x5b, 0xa9, 0xee, 0xd7, 0xd5, 0x12, + 0xa8, 0xb4, 0x96, 0xbb, 0xd7, 0xff, 0x2d, 0xbe, 0xae, 0xd4, 0x82, 0xdd, 0x14, + 0xf7, 0xd8, 0x50, 0x00, 0x35, 0x27, 0xbc, 0xd6, 0xef, 0x0f, 0x04, 0x97, 0x1d, + 0x13, 0x09, 0xfd, 0xf8, 0xc4, 0xd6, 0xee, 0x09, 0xbc, 0x12, 0x19, 0x16, 0xdf, + 0x9a, 0xcd, 0x01, 0xfc, 0x0c, 0x9f, 0x34, 0xbe, 0x5a, 0xa0, 0x1b, 0x2a, 0xfd, + 0xd3, 0x2b, 0x3b, 0xb3, 0x7f, 0x05, 0xc6, 0xec, 0x33, 0x00, 0xb2, 0xf9, 0xe6, + 0x38, 0xf9, 0xcd, 0xe7, 0x6c, 0x74, 0xd7, 0xcc, 0x76, 0x27, 0x19, 0x0a, 0x0f, + 0x54, 0x1f, 0xc4, 0xb4, 0x09, 0xbf, 0xd0, 0x5b, 0x54, 0x07, 0x1a, 0x11, 0xd9, + 0x15, 0x23, 0x17, 0xc2, 0x1f, 0x20, 0xdd, 0xf3, 0xe5, 0xdb, 0xf2, 0xbf, 0x06, + 0xdc, 0xbe, 0xe4, 0xe8, 0x3a, 0xab, 0xbd, 0xf4, 0x67, 0x1b, 0x4a, 0xc7, 0x17, + 0xd9, 0xc2, 0x4d, 0xa9, 0xd6, 0xd8, 0x03, 0xfb, 0xf0, 0xdf, 0xea, 0x1e, 0xb6, + 0xdd, 0xd3, 0xd0, 0xa6, 0x00, 0xca, 0x12, 0xfe, 0x13, 0xf8, 0x0b, 0x17, 0xf1, + 0x31, 0xe1, 0x46, 0xe7, 0x09, 0xc4, 0xec, 0xc1, 0xc9, 0x4a, 0xf0, 0x0e, 0x31, + 0xcf, 0xe1, 0x45, 0xc0, 0x37, 0x53, 0x1d, 0xc5, 0x0e, 0x32, 0xe6, 0xff, 0x1e, + 0x81, 0x02, 0x34, 0xba, 0xff, 0xf9, 0x1c, 0x30, 0xb2, 0x40, 0x59, 0x0c, 0x09, + 0x26, 0xa5, 0xee, 0x0f, 0xfc, 0x13, 0xb5, 0x12, 0xfb, 0x2a, 0xdd, 0xf7, 0x42, + 0xe4, 0xe3, 0xd0, 0xe8, 0xda, 0xd3, 0xda, 0x08, 0xe5, 0xbf, 0x3a, 0xdf, 0xc2, + 0x06, 0xe7, 0xc6, 0x2f, 0x00, 0xe8, 0xef, 0xec, 0xd7, 0xf0, 0xae, 0x4e, 0xdd, + 0x0d, 0xe2, 0xb2, 0xc2, 0xdf, 0x5c, 0x16, 0xc0, 0x59, 0xfc, 0xbe, 0xdc, 0x16, + 0x64, 0xf1, 0xef, 0x1c, 0xf6, 0x08, 0xc6, 0x16, 0x7f, 0xe4, 0x5b, 0x0b, 0xf9, + 0xf0, 0xeb, 0xd5, 0xf6, 0x2d, 0x05, 0x19, 0xf1, 0x10, 0xb3, 0xe9, 0xd2, 0xed, + 0xfd, 0x20, 0x07, 0xe5, 0x38, 0xf3, 0x0b, 0x64, 0xbf, 0xf5, 0xf8, 0xc5, 0x08, + 0x25, 0xeb, 0xfb, 0x6a, 0xc9, 0xbb, 0xe9, 0x30, 0xeb, 0x39, 0xc3, 0xff, 0x13, + 0xe8, 0x11, 0xe5, 0x39, 0xc1, 0x64, 0xc9, 0x0d, 0x32, 0x07, 0xd1, 0xdd, 0x00, + 0x39, 0xf0, 0x00, 0x1f, 0x13, 0x27, 0xe3, 0x02, 0x4a, 0xbe, 0x12, 0xfc, 0xfd, + 0x15, 0xf1, 0xe1, 0x11, 0x26, 0x3c, 0xe1, 0x10, 0x4b, 0x6a, 0xf0, 0xc8, 0xe8, + 0x47, 0xfa, 0x31, 0x1c, 0xcd, 0xd5, 0xce, 0x59, 0xe5, 0xf3, 0xd5, 0x35, 0xcf, + 0xd9, 0xe4, 0xfd, 0xc1, 0xd2, 0xbf, 0x4e, 0xe9, 0x0f, 0xe5, 0xcc, 0x10, 0xe2, + 0xab, 0x17, 0xd9, 0xfa, 0xd4, 0x4d, 0x19, 0x04, 0x02, 0x03, 0xad, 0xf5, 0x3b, + 0xd8, 0xed, 0x4c, 0xc4, 0xe5, 0xd7, 0x0b, 0xec, 0xeb, 0x28, 0x4b, 0xed, 0xcf, + 0x45, 0xca, 0xc3, 0x04, 0x1e, 0x39, 0x25, 0xc0, 0x39, 0xfb, 0x21, 0x20, 0x05, + 0x1e, 0x35, 0xfd, 0xcc, 0x2f, 0xdd, 0x15, 0x44, 0xfb, 0xf5, 0xe5, 0xbe, 0x0f, + 0xe1, 0x23, 0x19, 0xdd, 0x11, 0x20, 0xd9, 0xe3, 0x08, 0xfb, 0x0f, 0x07, 0x2a, + 0x15, 0xf2, 0x13, 0xbd, 0x2b, 0xf3, 0x19, 0xf5, 0x81, 0xe5, 0x16, 0xd1, 0x3d, + 0xbf, 0x09, 0x1c, 0x16, 0xfe, 0xd6, 0xd8, 0x3f, 0x2c, 0xff, 0x16, 0xf8, 0xfa, + 0x5a, 0xe0, 0x05, 0xb9, 0x00, 0xcb, 0xb1, 0xf1, 0x1e, 0xcf, 0x3b, 0xf7, 0xb9, + 0xe6, 0xfb, 0x0c, 0xef, 0x24, 0x19, 0xd3, 0xd8, 0xbf, 0x36, 0x5b, 0x04, 0xf6, + 0xc8, 0xdf, 0x19, 0x06, 0xd5, 0x1c, 0x08, 0x0d, 0xe7, 0xdd, 0xea, 0xbf, 0xec, + 0xea, 0x70, 0xe3, 0xcd, 0xba, 0x26, 0xe5, 0x08, 0x7f, 0xd1, 0x0d, 0x09, 0x12, + 0x0a, 0xc1, 0xed, 0xf8, 0xfd, 0xf5, 0x33, 0x01, 0x0f, 0xde, 0xcc, 0xf6, 0xb5, + 0x2c, 0xea, 0xfa, 0xe3, 0x07, 0x0e, 0x4e, 0x28, 0x04, 0xd2, 0xda, 0xfe, 0xdf, + 0x21, 0xdd, 0xe7, 0x4a, 0x00, 0xcb, 0x99, 0x10, 0x28, 0xed, 0x0e, 0xee, 0xef, + 0x0a, 0xeb, 0xd9, 0x50, 0xf8, 0xcb, 0x3f, 0x01, 0xfe, 0x0c, 0xd6, 0x00, 0x16, + 0x30, 0x0b, 0xeb, 0xf3, 0x20, 0x12, 0x07, 0x50, 0x1e, 0x05, 0xc0, 0x20, 0xdf, + 0xdb, 0x23, 0xce, 0xe5, 0xeb, 0x25, 0xdf, 0xe9, 0xe9, 0xcc, 0xf3, 0x2e, 0x1d, + 0xf1, 0x1b, 0x04, 0x4a, 0x41, 0x73, 0xa9, 0x65, 0x01, 0x2d, 0xbb, 0xee, 0x0f, + 0xd4, 0xb7, 0x4c, 0xb2, 0x34, 0xeb, 0x05, 0xa4, 0xc1, 0x10, 0xd3, 0xe2, 0x9e, + 0x90, 0x27, 0x29, 0xf9, 0xc5, 0x2b, 0xee, 0xc2, 0xe6, 0xff, 0xe6, 0x35, 0xfe, + 0xcf, 0x3a, 0xe0, 0xea, 0x37, 0xd9, 0x06, 0xf4, 0xbe, 0x42, 0x42, 0xe0, 0xe4, + 0xe7, 0x3f, 0x35, 0x4c, 0x0c, 0xe4, 0xb3, 0xaf, 0x1f, 0xbc, 0xcb, 0x4d, 0x05, + 0x10, 0xf9, 0xf4, 0x7f, 0x1b, 0x0e, 0x26, 0xef, 0x16, 0x02, 0xfb, 0x2a, 0x12, + 0x48, 0x1d, 0x07, 0xde, 0x95, 0xda, 0x37, 0x3f, 0xdd, 0x1f, 0x2a, 0x0e, 0xfe, + 0xd9, 0xf6, 0xd3, 0x00, 0x13, 0xf2, 0xd6, 0x43, 0x0a, 0x0c, 0xbf, 0xcf, 0x3f, + 0xf5, 0xe6, 0xfb, 0xec, 0x01, 0xf5, 0xd2, 0x18, 0x1c, 0x44, 0xcf, 0xfd, 0x31, + 0xcc, 0x3f, 0x12, 0x10, 0x1e, 0x04, 0xa2, 0x4f, 0xcd, 0x12, 0x10, 0xb6, 0xc8, + 0x40, 0x1b, 0x25, 0x17, 0xb9, 0xff, 0xdd, 0x0c, 0xfc, 0xe1, 0x1b, 0x0f, 0xd7, + 0xd7, 0x3b, 0xfe, 0x02, 0xbc, 0xda, 0xdf, 0xaf, 0xd7, 0xd8, 0xe8, 0x44, 0xd1, + 0x7b, 0xee, 0x27, 0xca, 0xd1, 0x10, 0xce, 0x8f, 0x3f, 0xcc, 0x36, 0x0f, 0x23, + 0xf1, 0xff, 0x0e, 0xd3, 0xc3, 0x1f, 0xfe, 0x35, 0x09, 0x64, 0xbd, 0xf9, 0x0c, + 0x49, 0xcc, 0x0e, 0x26, 0x07, 0x1e, 0xd8, 0x10, 0xd8, 0xef, 0x2f, 0xda, 0x40, + 0x02, 0xa9, 0xf9, 0xd2, 0xf7, 0xf8, 0xf5, 0x1c, 0x4f, 0x0b, 0x0e, 0x2b, 0x26, + 0xf3, 0x78, 0x4b, 0x35, 0x2d, 0xf7, 0x3b, 0xe1, 0x48, 0x8c, 0x00, 0x12, 0x01, + 0x81, 0xf9, 0xe9, 0x2e, 0x2d, 0xe5, 0x40, 0x15, 0x55, 0x12, 0xe0, 0x17, 0x0b, + 0x28, 0xd3, 0xab, 0xf7, 0x04, 0xaf, 0x67, 0x02, 0x69, 0xef, 0x25, 0x10, 0xfa, + 0xec, 0xcb, 0x2a, 0x03, 0x1b, 0xef, 0xe7, 0x0d, 0x04, 0x55, 0xfc, 0x2b, 0x20, + 0xbc, 0xaa, 0x2e, 0xde, 0xd5, 0x59, 0x1e, 0x19, 0xd8, 0x04, 0xdd, 0xeb, 0x54, + 0x01, 0x04, 0x4a, 0x1c, 0xe1, 0x15, 0x27, 0x35, 0xdd, 0xc1, 0xe3, 0x2e, 0x04, + 0x2d, 0x0e, 0xd2, 0xfa, 0xd0, 0x38, 0xf0, 0xd7, 0xaf, 0x4c, 0xf5, 0x08, 0x14, + 0x03, 0x2a, 0xcf, 0x07, 0x1a, 0x08, 0xf9, 0xc1, 0x13, 0xb4, 0xde, 0x27, 0x7f, + 0xc9, 0x34, 0x37, 0x24, 0xe6, 0x3c, 0xd8, 0xaf, 0x06, 0x0c, 0x19, 0xbe, 0x2a, + 0xf4, 0xbe, 0x54, 0x17, 0xdf, 0xfe, 0x33, 0xda, 0x53, 0x0e, 0x4b, 0xe8, 0xf0, + 0xaf, 0x1a, 0x0b, 0x00, 0xc8, 0xcd, 0x56, 0x10, 0xe6, 0x51, 0x1b, 0x4c, 0xe8, + 0xd6, 0x14, 0xd8, 0x31, 0x18, 0xd0, 0x07, 0xde, 0xe5, 0xea, 0x11, 0xdb, 0xe3, + 0x5d, 0x26, 0x5f, 0x09, 0xc5, 0x28, 0x31, 0x15, 0x0e, 0x59, 0x09, 0xf6, 0x5a, + 0xee, 0xab, 0x26, 0x29, 0x3b, 0x31, 0xd7, 0x21, 0xea, 0x1c, 0x52, 0xe5, 0x25, + 0x18, 0xc1, 0xe0, 0xf0, 0x18, 0x30, 0xf8, 0xdb, 0xd2, 0x34, 0x08, 0x29, 0xff, + 0xe0, 0xec, 0x0c, 0x44, 0xf3, 0xde, 0xec, 0x16, 0xbd, 0x06, 0xf3, 0x0f, 0x04, + 0xe4, 0x15, 0x28, 0xf2, 0xea, 0x3a, 0xb9, 0x16, 0xf7, 0x49, 0x10, 0x01, 0xca, + 0x44, 0x14, 0xe9, 0x2e, 0x17, 0xea, 0x37, 0xdb, 0x05, 0x30, 0x06, 0x7f, 0xfe, + 0xff, 0x24, 0xfb, 0xeb, 0x2c, 0x2a, 0xe5, 0x20, 0xf9, 0xf4, 0xe9, 0x09, 0xf4, + 0xdc, 0xe0, 0x36, 0xed, 0xef, 0xfe, 0x08, 0xfb, 0x58, 0xe5, 0xee, 0x11, 0xb6, + 0x17, 0x49, 0xfa, 0xfd, 0x27, 0xc5, 0x01, 0xdb, 0xa4, 0xef, 0x1a, 0xe5, 0x21, + 0x39, 0x0b, 0xf9, 0xf1, 0x2e, 0xf6, 0x10, 0x2e, 0x08, 0xf9, 0x22, 0xd7, 0xc4, + 0x16, 0x0f, 0xfb, 0xf7, 0x2c, 0x0c, 0x09, 0xdc, 0xdf, 0xff, 0xe9, 0xe2, 0xf9, + 0x09, 0x13, 0x10, 0xc9, 0xe5, 0x25, 0x0a, 0xd0, 0x26, 0xfd, 0xff, 0xee, 0xef, + 0x0d, 0x29, 0x10, 0xec, 0x0d, 0xc8, 0xfb, 0x09, 0xed, 0xfe, 0xe6, 0xfc, 0x20, + 0xf4, 0xfb, 0x09, 0xce, 0x08, 0xf9, 0xdc, 0xe7, 0x6b, 0xe1, 0xf0, 0x02, 0x03, + 0xa8, 0x25, 0x22, 0x13, 0x63, 0x1f, 0x65, 0xf3, 0xf6, 0xff, 0x15, 0x08, 0xdb, + 0x09, 0xed, 0x78, 0xf4, 0x03, 0x11, 0x12, 0xec, 0xfe, 0xea, 0xe8, 0xe6, 0x09, + 0x7f, 0x39, 0xfc, 0x00, 0x0c, 0xf0, 0x0f, 0x20, 0xff, 0x05, 0x09, 0xe4, 0x08, + 0xf2, 0x0b, 0x02, 0xde, 0x1a, 0x32, 0xf3, 0x10, 0x0f, 0xde, 0xdb, 0xd7, 0xf3, + 0x2a, 0xf4, 0x29, 0x34, 0x1d, 0xe2, 0x2c, 0xd4, 0xf5, 0x14, 0x09, 0x0f, 0x35, + 0x00, 0xba, 0x04, 0x0c, 0x0d, 0xe0, 0x41, 0x01, 0xe0, 0x55, 0x58, 0x1d, 0xf3, + 0x4f, 0xfb, 0xdc, 0xfc, 0xf5, 0x41, 0x0f, 0x0f, 0x2e, 0xeb, 0x2a, 0xff, 0x22, + 0xb9, 0xe3, 0xe8, 0xfa, 0xe6, 0x26, 0xee, 0x3a, 0x17, 0x2b, 0xf4, 0x21, 0x07, + 0x28, 0xb9, 0x28, 0x81, 0xad, 0xf8, 0xf2, 0xc5, 0xb2, 0x1c, 0x36, 0x4f, 0xe2, + 0x41, 0x2e, 0xd3, 0xc6, 0xf3, 0x6a, 0xc0, 0x02, 0x96, 0x09, 0xd5, 0x04, 0xb4, + 0x3f, 0xe8, 0x17, 0x09, 0x23, 0xff, 0xf0, 0xf9, 0xe0, 0x04, 0x0e, 0x2d, 0xc8, + 0x23, 0x56, 0xd5, 0x15, 0x09, 0xe0, 0xcb, 0xc5, 0x36, 0x4d, 0xcb, 0xcd, 0x0f, + 0x3f, 0xfa, 0x69, 0x0d, 0x5f, 0x29, 0x27, 0xf2, 0xae, 0x38, 0xeb, 0x1f, 0x34, + 0xde, 0x3e, 0x24, 0x13, 0xf5, 0xf0, 0x06, 0xb5, 0xe8, 0xf6, 0xf4, 0x18, 0xbd, + 0x12, 0xe9, 0x22, 0x22, 0xf2, 0xcf, 0x2b, 0xe0, 0x74, 0x06, 0xd5, 0xc9, 0xea, + 0xe6, 0xbf, 0xfe, 0xec, 0xf7, 0xf5, 0xe6, 0xcb, 0x03, 0xfe, 0xfc, 0x67, 0xfd, + 0xae, 0x2b, 0x25, 0xd2, 0x64, 0x0d, 0xc3, 0x0e, 0x4d, 0x15, 0xf7, 0xcc, 0xea, + 0x0b, 0x16, 0x12, 0x1c, 0xec, 0xa2, 0x5f, 0x4b, 0x3b, 0x3c, 0xdf, 0x32, 0xe6, + 0xd8, 0xfe, 0x3b, 0xdf, 0x1d, 0x14, 0x60, 0x5b, 0x09, 0xd1, 0xb2, 0xf2, 0xbf, + 0x39, 0x2e, 0xf4, 0xe4, 0xf7, 0x28, 0x22, 0xf5, 0x01, 0xc0, 0x40, 0xc6, 0xe4, + 0xa3, 0x59, 0xd0, 0x07, 0xb9, 0xd6, 0x09, 0x05, 0xe8, 0xf7, 0x7f, 0x97, 0x18, + 0x28, 0x3c, 0xfe, 0x32, 0x54, 0x49, 0xec, 0xf9, 0x3f, 0x03, 0x0d, 0xbf, 0x0a, + 0xe3, 0xf9, 0xc8, 0xe0, 0xe9, 0xe9, 0xd2, 0x2d, 0xd8, 0x9b, 0x15, 0xeb, 0x29, + 0x78, 0x4d, 0x20, 0xc0, 0x07, 0x0c, 0x2c, 0xc5, 0xe7, 0xf1, 0xfc, 0x2d, 0x2f, + 0x02, 0xff, 0xfe, 0x39, 0x2c, 0x0d, 0xfa, 0x03, 0x00, 0x1b, 0x15, 0x49, 0x03, + 0xf6, 0x1f, 0x17, 0xee, 0x4b, 0x13, 0x9e, 0xe7, 0x04, 0xfe, 0x1e, 0x30, 0xf2, + 0x1c, 0xe0, 0xf3, 0xea, 0x63, 0xfa, 0x2a, 0x26, 0xec, 0xfb, 0xec, 0xfa, 0xcc, + 0xde, 0xb8, 0xf4, 0x16, 0xc1, 0x27, 0xf0, 0xf3, 0x12, 0x1a, 0x4d, 0xd2, 0x26, + 0x23, 0x1c, 0x08, 0x43, 0x08, 0x7f, 0xf5, 0xc7, 0xc6, 0xeb, 0xd9, 0x2b, 0x3a, + 0xe7, 0xfe, 0x10, 0xf6, 0xda, 0xfa, 0x07, 0xdf, 0x1c, 0x15, 0x13, 0xfe, 0x19, + 0xfe, 0x20, 0xf0, 0xd6, 0xf0, 0x02, 0xfa, 0x0f, 0x50, 0xe9, 0xf7, 0x1f, 0xeb, + 0xf7, 0x4c, 0x17, 0x23, 0x03, 0x10, 0x32, 0x26, 0xf8, 0xd5, 0x1e, 0x12, 0xf8, + 0xcd, 0xe9, 0xef, 0xe9, 0xe8, 0xf7, 0x12, 0xf6, 0xcd, 0x01, 0x04, 0x32, 0x1b, + 0x23, 0x00, 0x0a, 0x44, 0xee, 0xd7, 0x50, 0xff, 0xf3, 0x31, 0xe6, 0xe4, 0xde, + 0xf8, 0xd5, 0xe0, 0x10, 0xfe, 0x11, 0xfd, 0xe9, 0xe4, 0x53, 0x07, 0x0d, 0xea, + 0x2f, 0xd5, 0x09, 0xf4, 0x01, 0x03, 0x2d, 0xc1, 0x12, 0x1c, 0xf8, 0xf7, 0xe7, + 0x1c, 0xf7, 0xf1, 0x10, 0x00, 0x25, 0xb9, 0xee, 0xf0, 0x15, 0xec, 0xea, 0x42, + 0x18, 0xa7, 0x09, 0x37, 0x0c, 0xc7, 0x0f, 0xd6, 0xd7, 0x08, 0x79, 0x6e, 0xd7, + 0xf9, 0x25, 0x0c, 0xcb, 0x41, 0xdb, 0xe0, 0x73, 0x12, 0x0a, 0xd7, 0xd0, 0xc9, + 0x25, 0x39, 0x0f, 0x07, 0x21, 0xd4, 0xc9, 0xaf, 0x20, 0x07, 0xfc, 0xcc, 0xed, + 0x2f, 0xde, 0xf0, 0x66, 0x0f, 0x3b, 0x1d, 0xb0, 0xf4, 0x89, 0x33, 0xeb, 0x43, + 0x1e, 0xfe, 0xd0, 0x3c, 0x73, 0x26, 0xe9, 0x0e, 0x25, 0xf0, 0x25, 0xfa, 0xf2, + 0xd8, 0x7d, 0xf3, 0x1f, 0x06, 0x03, 0xf7, 0xc3, 0x1c, 0xfa, 0x47, 0x53, 0xd4, + 0x01, 0xb1, 0xd7, 0x30, 0x11, 0xd6, 0xcd, 0x39, 0x08, 0xa0, 0xe9, 0x3d, 0xf5, + 0xe6, 0xa9, 0x08, 0x3e, 0x2b, 0x0d, 0x30, 0x67, 0xac, 0x4e, 0x47, 0xfb, 0xd5, + 0xf3, 0xdb, 0x93, 0xff, 0x42, 0xd9, 0xfa, 0x2e, 0x01, 0x1f, 0x81, 0x1d, 0x06, + 0x51, 0xca, 0x51, 0xe4, 0x30, 0xe7, 0x1d, 0xf1, 0x13, 0x3b, 0xda, 0x20, 0x13, + 0x3d, 0x36, 0x30, 0xf8, 0xe6, 0xf2, 0x0d, 0x1b, 0x0b, 0x3a, 0xf9, 0xc9, 0x23, + 0x7f, 0x2d, 0xbb, 0xed, 0x04, 0xe5, 0x06, 0x2e, 0x19, 0x42, 0xc6, 0x40, 0xed, + 0x0b, 0xf9, 0x05, 0x07, 0xf7, 0x05, 0x08, 0x38, 0xcb, 0xed, 0xf0, 0xe2, 0xfc, + 0xb1, 0x59, 0xef, 0x20, 0x03, 0xde, 0x21, 0xf8, 0x3d, 0xe8, 0x15, 0xdd, 0x15, + 0x2a, 0xe8, 0xd8, 0x4a, 0x1d, 0x10, 0x28, 0xed, 0x0f, 0xcc, 0x04, 0x39, 0x40, + 0xd0, 0x04, 0xf0, 0xee, 0x0f, 0x04, 0x18, 0xe7, 0xc4, 0x16, 0x0b, 0xe5, 0x14, + 0x62, 0x13, 0x22, 0xec, 0x62, 0xd0, 0xfd, 0x1d, 0x78, 0xf1, 0xf7, 0xde, 0x3d, + 0xfc, 0xd8, 0x1f, 0xeb, 0x51, 0x07, 0xf8, 0x55, 0xf2, 0x42, 0xc7, 0xcb, 0xd4, + 0xf1, 0x02, 0xec, 0x28, 0xf9, 0xc7, 0x6d, 0xca, 0x23, 0xee, 0xd7, 0x0a, 0x38, + 0x0c, 0x08, 0xe2, 0xea, 0x08, 0xde, 0xfc, 0x26, 0x09, 0xea, 0x24, 0x1d, 0xe9, + 0x26, 0x15, 0x03, 0xf6, 0xfe, 0xf7, 0x01, 0x03, 0xde, 0x04, 0xea, 0xec, 0xe7, + 0x2f, 0xf7, 0x37, 0x02, 0x15, 0xc5, 0xe7, 0xd4, 0x30, 0x5c, 0xae, 0xf9, 0xef, + 0xf1, 0xb8, 0x02, 0x1b, 0xa5, 0x0f, 0xe4, 0xf8, 0xdf, 0xfd, 0xd4, 0x2f, 0xba, + 0x32, 0xa7, 0xdb, 0xf7, 0xca, 0x11, 0xb8, 0xd9, 0xe8, 0x16, 0xf2, 0xfa, 0x08, + 0xda, 0xfd, 0xf4, 0xb7, 0x40, 0xbf, 0xcb, 0x0b, 0x34, 0xf5, 0xcd, 0xf7, 0x9e, + 0x16, 0x07, 0x07, 0x0e, 0xf0, 0xc6, 0x27, 0x26, 0x33, 0x01, 0xd3, 0xc0, 0xaf, + 0xdf, 0xe0, 0x15, 0x04, 0x0b, 0xbe, 0xc0, 0xce, 0xc6, 0x1f, 0xdc, 0xd3, 0x0b, + 0xfa, 0xa9, 0x03, 0xf4, 0x4e, 0x0f, 0xb7, 0xed, 0x0a, 0xf6, 0x71, 0x81, 0x05, + 0xe5, 0xf0, 0x06, 0xd9, 0x06, 0x35, 0x1a, 0xaf, 0x05, 0x49, 0x08, 0xf1, 0xe5, + 0xdf, 0xf6, 0xb7, 0x56, 0xfd, 0xe4, 0x05, 0xe3, 0xc4, 0x30, 0xf0, 0x2a, 0xfc, + 0x1a, 0x8d, 0xb1, 0x16, 0x9b, 0x00, 0x48, 0xe2, 0x15, 0xf9, 0x04, 0xe8, 0xc8, + 0x30, 0xce, 0xe9, 0xf3, 0x03, 0x3f, 0xd1, 0x99, 0x15, 0x05, 0x77, 0x28, 0xc7, + 0xd4, 0xc0, 0x5a, 0xed, 0x07, 0xdf, 0xe3, 0xf2, 0xf0, 0xca, 0x74, 0x18, 0xc6, + 0x0d, 0xd1, 0xee, 0x93, 0x0f, 0x2a, 0x6a, 0xc3, 0x02, 0x1c, 0xff, 0xd3, 0x0b, + 0xc0, 0xa0, 0x35, 0x05, 0x37, 0xf2, 0x4a, 0x21, 0xe3, 0xbb, 0xb9, 0xcd, 0x1b, + 0x1f, 0xcb, 0x44, 0x14, 0xc5, 0x2d, 0x07, 0x09, 0xfc, 0x03, 0x10, 0xfd, 0xe9, + 0xe4, 0x17, 0xe7, 0xa8, 0x87, 0xe5, 0xee, 0x30, 0xe9, 0x05, 0x07, 0xca, 0x02, + 0x04, 0x25, 0x08, 0x49, 0xcc, 0xfd, 0xf2, 0x51, 0xe9, 0xdc, 0xbf, 0x31, 0xd2, + 0xf1, 0xf7, 0x29, 0x4f, 0xb4, 0x31, 0x5b, 0xcd, 0xf5, 0x50, 0x20, 0x5f, 0xe6, + 0x01, 0x13, 0x03, 0x03, 0xd2, 0x22, 0x7f, 0x43, 0x8b, 0x2a, 0xe0, 0xed, 0xd2, + 0x1d, 0xe2, 0xec, 0xdb, 0x05, 0x06, 0x66, 0xfe, 0x27, 0x03, 0xf4, 0xf2, 0x09, + 0x16, 0xca, 0xfa, 0xde, 0x05, 0xc9, 0xef, 0x07, 0x1f, 0x12, 0xe8, 0x41, 0x01, + 0x0a, 0xdd, 0xb2, 0xf3, 0xe7, 0x0e, 0x16, 0xfa, 0x0f, 0xdf, 0x2e, 0x31, 0xcd, + 0xf7, 0xbb, 0x03, 0x14, 0x1f, 0xed, 0x36, 0x34, 0xf4, 0xba, 0x7f, 0xd2, 0xba, + 0x16, 0x0b, 0x05, 0xf2, 0x1d, 0x36, 0xfc, 0xff, 0xee, 0xf5, 0x0f, 0x1a, 0xeb, + 0x0a, 0xfa, 0xe7, 0x27, 0x17, 0xf8, 0xec, 0x27, 0x15, 0x2d, 0xea, 0x06, 0xd8, + 0xdb, 0xad, 0xfb, 0xe4, 0x14, 0xeb, 0x08, 0x21, 0x01, 0xd4, 0x05, 0x0b, 0x3f, + 0xd7, 0xc7, 0x20, 0x0a, 0xf7, 0xd6, 0x0b, 0x67, 0xc1, 0x03, 0x05, 0x20, 0x0a, + 0xb5, 0xe0, 0x2d, 0xc1, 0xf6, 0xd2, 0xfb, 0xf0, 0x2e, 0xfd, 0x0d, 0x0d, 0x07, + 0x1e, 0xf4, 0x07, 0x3f, 0xfa, 0x09, 0x27, 0x0d, 0x17, 0xfa, 0xfe, 0x05, 0xfd, + 0x17, 0x0d, 0xf9, 0x15, 0x20, 0xe9, 0x25, 0x03, 0xf3, 0xdc, 0x0a, 0x03, 0xf5, + 0x2a, 0xef, 0x0a, 0x05, 0x0a, 0xdc, 0x02, 0x1a, 0xe9, 0x04, 0xe1, 0xf6, 0xf3, + 0xee, 0x03, 0x09, 0x07, 0xce, 0x1d, 0xed, 0x1c, 0x01, 0x22, 0x22, 0x03, 0x03, + 0x07, 0x17, 0x7f, 0x16, 0x1b, 0xf7, 0x08, 0xe5, 0x05, 0xf6, 0xed, 0x1c, 0xf7, + 0x02, 0xe9, 0xec, 0xed, 0x27, 0xfd, 0x00, 0xe1, 0xf7, 0xed, 0x07, 0x05, 0x0d, + 0x1a, 0x24, 0x04, 0xef, 0x21, 0x16, 0xf9, 0x0b, 0x05, 0xf8, 0x25, 0xf0, 0x01, + 0xec, 0x0f, 0xeb, 0x06, 0x0e, 0x03, 0xf7, 0xee, 0xf2, 0x04, 0x45, 0xe7, 0x0e, + 0xee, 0x1a, 0xf5, 0x11, 0x14, 0x0c, 0xfe, 0xfa, 0x0f, 0xf4, 0x12, 0xf7, 0x0a, + 0xfc, 0xf9, 0x00, 0xff, 0xec, 0xe8, 0x09, 0xee, 0xf6, 0x12, 0xea, 0xf4, 0x01, + 0x17, 0xfd, 0xe0, 0x15, 0x13, 0x37, 0x5c, 0xfb, 0xea, 0xae, 0xe3, 0xeb, 0xfe, + 0x95, 0xee, 0x54, 0xf1, 0x14, 0xe2, 0x2f, 0xd9, 0xf8, 0xc5, 0xea, 0xb0, 0xbb, + 0xac, 0x10, 0xfc, 0xd6, 0xfa, 0x2b, 0xff, 0xdd, 0xdb, 0x28, 0x05, 0xbd, 0xc5, + 0x48, 0x0c, 0x08, 0x10, 0xe5, 0xf6, 0x7f, 0xfe, 0x03, 0x1d, 0xed, 0x02, 0x02, + 0x06, 0x16, 0x34, 0x01, 0x35, 0x9e, 0x03, 0x12, 0xd3, 0x3d, 0x0d, 0x0f, 0x3f, + 0xee, 0x30, 0x4b, 0x1e, 0xfa, 0x1a, 0xe7, 0xea, 0x05, 0x50, 0x0b, 0x5e, 0x78, + 0xfb, 0x2f, 0xbf, 0x17, 0xf7, 0xf2, 0x50, 0xf6, 0x24, 0x52, 0xf3, 0xe5, 0x76, + 0x43, 0x37, 0xec, 0x3e, 0xea, 0xf2, 0x2e, 0x21, 0xef, 0x0f, 0xcf, 0x2c, 0x11, + 0xf1, 0x1c, 0xf4, 0xff, 0x1f, 0x57, 0xe7, 0x07, 0xbe, 0x05, 0x70, 0xdf, 0x22, + 0xef, 0x63, 0x41, 0x69, 0xae, 0x07, 0x2d, 0x4e, 0xd6, 0x08, 0xe8, 0xfb, 0x29, + 0x24, 0x11, 0x16, 0xe9, 0x20, 0x2f, 0xf4, 0x12, 0x24, 0xef, 0x02, 0xf5, 0xe6, + 0x2f, 0xef, 0x07, 0xb4, 0xd0, 0xf2, 0x2f, 0xf9, 0x28, 0x00, 0xec, 0xa0, 0x39, + 0xd9, 0x23, 0x06, 0x11, 0xda, 0x1c, 0xea, 0x07, 0x32, 0x0d, 0x1f, 0x0b, 0x20, + 0xee, 0x0d, 0x76, 0x1d, 0xb1, 0xed, 0xde, 0x02, 0x28, 0xeb, 0x53, 0x11, 0xe9, + 0x26, 0xde, 0xf5, 0x3c, 0x1f, 0x21, 0xb4, 0xf3, 0xe3, 0x06, 0xfc, 0xe0, 0x4b, + 0xcf, 0x2f, 0x49, 0xfe, 0xf9, 0x03, 0xab, 0x1f, 0x62, 0xa0, 0x1e, 0x20, 0xfb, + 0x27, 0xd4, 0xda, 0x01, 0x2b, 0x14, 0x0e, 0x09, 0x45, 0xbb, 0x33, 0x16, 0xf8, + 0x16, 0x3e, 0xfa, 0x15, 0x0c, 0xfd, 0x10, 0x21, 0x19, 0x16, 0xed, 0x2e, 0x5e, + 0x7f, 0x10, 0x53, 0xca, 0x4b, 0x22, 0x49, 0x06, 0x32, 0xc3, 0x2a, 0x1f, 0x26, + 0xef, 0x37, 0x13, 0x16, 0x16, 0xd1, 0x40, 0x04, 0x23, 0xe6, 0x41, 0xe2, 0x33, + 0xcf, 0x24, 0x03, 0x0b, 0x18, 0xf1, 0xfa, 0xfa, 0xb5, 0x32, 0x0c, 0x1b, 0x07, + 0x28, 0xea, 0xb8, 0x81, 0xfa, 0x06, 0x34, 0x16, 0x26, 0x02, 0x1b, 0x04, 0xfe, + 0x16, 0x18, 0xe2, 0x0b, 0xf4, 0xbf, 0xfc, 0xff, 0xdf, 0x24, 0xc9, 0xf4, 0xfa, + 0x0b, 0xfb, 0xcf, 0x02, 0x08, 0xda, 0x0f, 0x15, 0x03, 0xf8, 0xdd, 0x18, 0x02, + 0xf5, 0x1b, 0x25, 0x0c, 0x39, 0x1b, 0xda, 0xef, 0xe9, 0x0c, 0x08, 0xec, 0xd2, + 0xf8, 0xe5, 0xe1, 0x1c, 0xed, 0xe4, 0x0d, 0xc4, 0x10, 0xec, 0x22, 0x23, 0x1c, + 0xbc, 0x0d, 0xf0, 0x05, 0xe7, 0xf7, 0xe3, 0x56, 0xde, 0x1d, 0xf6, 0x01, 0xe8, + 0xf7, 0xf7, 0x0e, 0x22, 0xef, 0x02, 0x0f, 0xe1, 0x1e, 0xda, 0xd7, 0xee, 0xe6, + 0x03, 0x2b, 0xd0, 0x17, 0xf0, 0x2b, 0xea, 0x04, 0x08, 0xf7, 0xdd, 0x14, 0x0d, + 0x1d, 0xd0, 0x1e, 0xdc, 0xf2, 0xbe, 0x20, 0xeb, 0x1c, 0x23, 0x0c, 0x1c, 0x37, + 0x02, 0x04, 0x3a, 0x05, 0x01, 0xc3, 0x43, 0xf9, 0xc6, 0x10, 0x54, 0x2c, 0xf4, + 0xd2, 0xfc, 0x04, 0x06, 0x11, 0xb5, 0xe6, 0x00, 0x10, 0xf9, 0x0d, 0x25, 0x17, + 0x08, 0xf7, 0x32, 0x57, 0xbd, 0xf1, 0x42, 0xfc, 0xe7, 0x00, 0xf4, 0x17, 0x1a, + 0xe0, 0x30, 0xf9, 0x15, 0x2a, 0x45, 0x24, 0x21, 0xfa, 0xed, 0xef, 0xe6, 0x11, + 0xf0, 0x69, 0x39, 0x23, 0x12, 0xc8, 0xf8, 0x08, 0xfd, 0xd9, 0xf3, 0x08, 0x01, + 0x0f, 0x22, 0xd4, 0xf2, 0x3a, 0xe2, 0xec, 0xf2, 0xf8, 0x62, 0xe5, 0x68, 0x23, + 0x01, 0x50, 0xef, 0xe2, 0xd2, 0x1d, 0xee, 0x19, 0x0c, 0x01, 0x01, 0x07, 0xdd, + 0xdd, 0xfc, 0x10, 0x06, 0x26, 0xf5, 0xe9, 0x0d, 0xc6, 0x08, 0xf1, 0x02, 0xfe, + 0x1e, 0xf7, 0x2f, 0xd7, 0xee, 0xe7, 0xff, 0x02, 0x0c, 0x04, 0xfa, 0x2b, 0xd1, + 0x0b, 0xf2, 0xfe, 0x06, 0x19, 0xf9, 0x02, 0x7f, 0x0f, 0x03, 0xf9, 0xdd, 0xf4, + 0x4f, 0xfc, 0x31, 0xf0, 0x37, 0xdd, 0x1c, 0x5d, 0x0e, 0x3a, 0xe4, 0xa5, 0xe2, + 0xfd, 0xe4, 0xc4, 0x7f, 0x19, 0x26, 0xf7, 0x20, 0xca, 0xfa, 0x02, 0x46, 0x5a, + 0xe2, 0x00, 0x1b, 0xff, 0x36, 0x2d, 0x12, 0x0c, 0xd1, 0xf5, 0x32, 0xc7, 0x01, + 0xf4, 0xd7, 0x66, 0x14, 0xd9, 0x08, 0xdf, 0xf1, 0xd8, 0xdc, 0x01, 0x36, 0x25, + 0xff, 0x3f, 0xf8, 0xf5, 0xae, 0xdc, 0x1c, 0xd9, 0x0a, 0x7d, 0xde, 0xe6, 0x1d, + 0x27, 0x1c, 0x27, 0x02, 0xea, 0x98, 0xdb, 0xdb, 0x08, 0xdd, 0xf2, 0x10, 0xe8, + 0xfc, 0x26, 0x11, 0x14, 0xf7, 0x3e, 0x07, 0x07, 0x3c, 0x27, 0xff, 0xfa, 0x24, + 0xe0, 0x45, 0x05, 0x2e, 0xce, 0x01, 0xfd, 0x56, 0xed, 0xe9, 0x4e, 0x2f, 0xfe, + 0x0d, 0xe1, 0xe6, 0x1b, 0x06, 0xea, 0x3b, 0x15, 0xea, 0xa9, 0x00, 0x05, 0x15, + 0xde, 0x82, 0x36, 0xdb, 0x11, 0xbe, 0xe1, 0x2b, 0x09, 0x28, 0x46, 0x5d, 0xde, + 0x36, 0x27, 0xfc, 0x50, 0xd0, 0x33, 0x0d, 0x10, 0x3b, 0xfd, 0xe3, 0xdf, 0x01, + 0xf6, 0xbc, 0x48, 0x2e, 0xfe, 0x1b, 0x2f, 0x20, 0xed, 0xf8, 0xfb, 0x8e, 0xf5, + 0xc3, 0x2e, 0x48, 0x68, 0xef, 0x3b, 0x40, 0xf1, 0xe8, 0xaf, 0x23, 0xeb, 0x16, + 0x37, 0x44, 0x93, 0x12, 0x07, 0x1c, 0x9a, 0xfb, 0xf5, 0xff, 0x78, 0x15, 0x18, + 0xf9, 0x42, 0xbc, 0xe2, 0x07, 0x2b, 0xc8, 0xdd, 0xa1, 0xbe, 0xc4, 0x0a, 0x1d, + 0xd6, 0xc1, 0xe9, 0xa4, 0xf3, 0x15, 0x3b, 0xe3, 0xf7, 0x0a, 0x1a, 0xee, 0xd8, + 0xe3, 0x6a, 0xf7, 0xd2, 0xf6, 0xdf, 0xf3, 0xdd, 0xd4, 0x9d, 0x22, 0x0b, 0xc2, + 0x16, 0x42, 0x58, 0x23, 0xf0, 0x03, 0xee, 0x1d, 0x1b, 0xf4, 0x18, 0xea, 0x2b, + 0xc2, 0x62, 0x2a, 0x9a, 0xfb, 0x2d, 0x28, 0xcf, 0x9f, 0xdb, 0xfa, 0xe9, 0xd5, + 0xcf, 0xef, 0xda, 0x0b, 0x9f, 0x7f, 0xec, 0x10, 0xca, 0x4d, 0xc4, 0x05, 0x09, + 0x33, 0x2b, 0x0f, 0x08, 0x0f, 0x27, 0x33, 0x0e, 0xec, 0xf3, 0x20, 0x19, 0xdf, + 0x31, 0xda, 0x10, 0x06, 0xf1, 0xcc, 0x08, 0xd9, 0x0a, 0x01, 0x14, 0x31, 0x0b, + 0x26, 0x14, 0x03, 0xf6, 0xcd, 0xd2, 0x0e, 0x1a, 0x39, 0x1a, 0x2c, 0xab, 0x1f, + 0xfb, 0x2f, 0x37, 0x25, 0x2c, 0xe8, 0x07, 0xec, 0x4d, 0xdf, 0x1c, 0x09, 0x0c, + 0x09, 0x06, 0xe4, 0xf2, 0x27, 0x05, 0x08, 0x1a, 0xfe, 0x06, 0x29, 0xce, 0x5e, + 0x21, 0xe6, 0xf9, 0xf6, 0x00, 0x49, 0x20, 0x14, 0xeb, 0xe6, 0x70, 0xd7, 0x32, + 0x77, 0xb3, 0xef, 0x07, 0xc4, 0x0b, 0x12, 0x05, 0x06, 0xc3, 0xdd, 0x45, 0x00, + 0xcf, 0x00, 0x22, 0x3d, 0xd0, 0xe1, 0xf7, 0xde, 0xe7, 0xe2, 0x03, 0x7f, 0xdf, + 0x13, 0x4b, 0x76, 0xe7, 0x23, 0x16, 0x5a, 0x21, 0xf8, 0xeb, 0xcc, 0xdf, 0xbc, + 0x1d, 0x0f, 0x28, 0x25, 0x33, 0x29, 0x1e, 0x15, 0xf7, 0x07, 0x19, 0x36, 0x40, + 0xbe, 0x56, 0x25, 0x41, 0xe4, 0xe4, 0xd1, 0x6f, 0xea, 0x04, 0x32, 0x41, 0x7f, + 0x1a, 0x3b, 0xe3, 0x43, 0x15, 0x02, 0x2f, 0x3e, 0x64, 0x63, 0xbc, 0xff, 0xc2, + 0x0b, 0x05, 0x31, 0x05, 0x11, 0x38, 0x22, 0x78, 0xff, 0xf6, 0x38, 0xb2, 0x19, + 0x00, 0x54, 0x10, 0x31, 0xde, 0x49, 0x19, 0x37, 0x2b, 0x41, 0xe2, 0x08, 0x1a, + 0x39, 0x0a, 0x20, 0xd4, 0x04, 0x35, 0x22, 0x06, 0x21, 0x57, 0x41, 0x66, 0xb6, + 0xfd, 0x0e, 0x3f, 0xd1, 0x58, 0x1e, 0x2d, 0x2f, 0x68, 0x14, 0xfd, 0x18, 0x9e, + 0xe5, 0x36, 0xf9, 0x15, 0xe4, 0x22, 0x13, 0x4b, 0xdd, 0x3c, 0x4f, 0xf0, 0xfa, + 0x03, 0x03, 0x19, 0xe5, 0x0d, 0x05, 0x1c, 0x58, 0xfa, 0x2c, 0x35, 0x07, 0x22, + 0x2f, 0x3a, 0x22, 0xe9, 0xf2, 0x37, 0x11, 0x3e, 0x23, 0x50, 0x23, 0x1b, 0x45, + 0x1d, 0xed, 0xce, 0x1b, 0xef, 0x28, 0x3e, 0xe5, 0x34, 0x17, 0xbf, 0x92, 0x4f, + 0xfb, 0xd7, 0xd0, 0x07, 0xeb, 0xf1, 0x2e, 0xce, 0xf3, 0xd2, 0xfa, 0x14, 0x33, + 0x02, 0x07, 0xee, 0xc7, 0xda, 0xd8, 0xd9, 0x0e, 0xf3, 0xdf, 0xfe, 0xf1, 0x19, + 0x0d, 0x1f, 0x0f, 0xe1, 0x5a, 0x74, 0x1b, 0xd3, 0xe1, 0xd2, 0x24, 0x43, 0x73, + 0x33, 0xdd, 0xd6, 0x25, 0xce, 0xec, 0x30, 0x05, 0x0f, 0xe1, 0xef, 0xd5, 0xea, + 0xbf, 0x02, 0xe0, 0xea, 0xf7, 0x0c, 0x66, 0xc9, 0x7f, 0x51, 0xf2, 0xc8, 0x02, + 0xec, 0x0e, 0x73, 0x0c, 0x02, 0x0a, 0xec, 0xd8, 0xd0, 0xeb, 0xe5, 0xe7, 0xdc, + 0x13, 0x00, 0xf9, 0xef, 0xc2, 0x5e, 0xd9, 0x17, 0x0e, 0xf0, 0x0a, 0x2d, 0x13, + 0xd8, 0x01, 0x26, 0xbb, 0x21, 0x2d, 0xec, 0x32, 0x08, 0x15, 0x10, 0x1c, 0x38, + 0xd8, 0xf7, 0x39, 0xe3, 0x1c, 0x2a, 0x1c, 0x21, 0x79, 0xd9, 0xeb, 0x43, 0xfa, + 0x20, 0xca, 0xec, 0x21, 0xd2, 0xea, 0xfa, 0x10, 0xdd, 0x3a, 0xf8, 0x14, 0xd3, + 0xdd, 0xc4, 0xda, 0xce, 0x02, 0x16, 0x05, 0x0c, 0x04, 0xd8, 0x0c, 0xf7, 0x16, + 0xe1, 0x45, 0x17, 0xe7, 0xb9, 0xeb, 0xfa, 0x11, 0x0b, 0x15, 0x9f, 0x49, 0xec, + 0x14, 0xe4, 0xde, 0xc0, 0xd3, 0x0b, 0xb7, 0x08, 0x12, 0xfe, 0x26, 0x17, 0x29, + 0x48, 0xe4, 0x0a, 0x22, 0x51, 0x21, 0x16, 0x12, 0xf0, 0x0e, 0xd6, 0xf2, 0x32, + 0x1b, 0x0c, 0xf4, 0x31, 0x12, 0x4b, 0xf0, 0x06, 0x0e, 0x03, 0xfe, 0x81, 0xcb, + 0x0d, 0x1d, 0xe9, 0x17, 0xff, 0xf5, 0x27, 0x05, 0x75, 0x01, 0xf7, 0x07, 0x15, + 0xec, 0xb4, 0xba, 0xf4, 0xe4, 0x04, 0x16, 0x09, 0x47, 0x30, 0xe9, 0xa5, 0x43, + 0x0e, 0x93, 0x05, 0xfa, 0xe8, 0x09, 0xfa, 0x53, 0xc5, 0x11, 0x0e, 0xf5, 0xb4, + 0xd3, 0x4e, 0xf8, 0x02, 0xd7, 0x10, 0xdd, 0xbb, 0xa7, 0xdd, 0x26, 0xd1, 0xdc, + 0xfc, 0x11, 0x3a, 0x13, 0x27, 0x10, 0x05, 0xaa, 0x13, 0x00, 0xe1, 0x25, 0xea, + 0xf7, 0xed, 0x0a, 0xa3, 0x0b, 0xe8, 0xec, 0x16, 0xfa, 0x12, 0xf8, 0xdc, 0xed, + 0x14, 0x23, 0xd1, 0x0a, 0x10, 0x03, 0xed, 0xf5, 0x26, 0xef, 0x08, 0x13, 0xb9, + 0xf6, 0x7f, 0x05, 0x25, 0xf9, 0xe0, 0x4a, 0x06, 0x68, 0x18, 0xf6, 0xef, 0xf6, + 0xf9, 0x0c, 0xee, 0x0d, 0xf1, 0xe9, 0x05, 0xb5, 0x12, 0xe4, 0xee, 0xde, 0x10, + 0x10, 0xfc, 0x23, 0xea, 0x1c, 0x3b, 0x10, 0xf9, 0x3c, 0x17, 0x09, 0xf4, 0x4b, + 0xbd, 0x12, 0xf7, 0xf7, 0x0b, 0xfb, 0xdf, 0xf9, 0xf8, 0xfb, 0x30, 0x1c, 0xff, + 0x19, 0x54, 0x15, 0xf6, 0x09, 0x27, 0x04, 0x1e, 0xef, 0x14, 0xe5, 0x07, 0xfd, + 0x13, 0x40, 0xcf, 0x67, 0xec, 0xe4, 0x21, 0xe1, 0x05, 0x02, 0xfd, 0xf9, 0x07, + 0xf9, 0xe5, 0x20, 0xeb, 0xf7, 0xe1, 0x31, 0xe2, 0x27, 0xe0, 0xe3, 0xf4, 0xea, + 0x0a, 0xe7, 0xd4, 0xc8, 0x14, 0x1c, 0x07, 0x1a, 0x44, 0xed, 0xe1, 0x1b, 0x19, + 0x19, 0x10, 0xe3, 0xe5, 0xe7, 0xe7, 0xd9, 0xe2, 0xf9, 0x3b, 0x0b, 0x37, 0xf2, + 0x5f, 0xfe, 0x2c, 0xed, 0xf5, 0xfa, 0xf1, 0xf0, 0x26, 0x13, 0xfc, 0x20, 0xec, + 0x27, 0xd8, 0xf7, 0xf7, 0xd0, 0xe5, 0xfd, 0xe5, 0xee, 0xe0, 0xf8, 0xf9, 0xfa, + 0x16, 0x2f, 0x33, 0xf2, 0x1d, 0x7f, 0xc5, 0xe7, 0xfd, 0xdc, 0x21, 0x03, 0xf6, + 0x0b, 0x06, 0x1b, 0xe5, 0x2a, 0xda, 0x4e, 0xe9, 0x39, 0xd0, 0x0f, 0x76, 0xfe, + 0x10, 0x20, 0xcc, 0xff, 0xf9, 0x0f, 0x0c, 0x14, 0x19, 0xfb, 0x23, 0xd1, 0xcf, + 0xed, 0xfd, 0xf6, 0xd9, 0xfe, 0x12, 0x0c, 0xd3, 0x25, 0xf2, 0x1a, 0x2a, 0x10, + 0xfa, 0x23, 0xd2, 0xe8, 0xe4, 0x0c, 0xff, 0x12, 0xfb, 0x1a, 0x0f, 0x05, 0xf9, + 0xf9, 0x2c, 0x14, 0x03, 0xca, 0x39, 0x19, 0x21, 0xef, 0x07, 0x1b, 0x38, 0x09, + 0xe6, 0xff, 0x38, 0xfc, 0x4f, 0x52, 0x17, 0x03, 0xd4, 0xb5, 0xfd, 0xbd, 0x46, + 0x6a, 0xef, 0x19, 0x04, 0x38, 0xf4, 0x38, 0xfb, 0x52, 0x51, 0x00, 0xb5, 0x22, + 0x07, 0x18, 0xe7, 0x17, 0x20, 0xf0, 0x03, 0xe5, 0x05, 0x4f, 0x2a, 0x12, 0x35, + 0x4b, 0x21, 0x11, 0xd7, 0x39, 0x0d, 0xe8, 0x01, 0x7f, 0xe3, 0x57, 0xe8, 0xe4, + 0xd4, 0xe5, 0xe9, 0xfb, 0x21, 0xe5, 0xf3, 0x1a, 0xb3, 0xde, 0xfe, 0x11, 0xe2, + 0xd6, 0xf5, 0x08, 0xed, 0x43, 0x31, 0xe8, 0x40, 0x44, 0x1f, 0xde, 0x0d, 0x0b, + 0x68, 0xd7, 0xf1, 0xb8, 0x2a, 0xe9, 0xdd, 0x4d, 0x23, 0x07, 0x33, 0x26, 0xe0, + 0x05, 0x16, 0xec, 0xf5, 0xc0, 0x0b, 0xfd, 0xff, 0xca, 0x01, 0xfd, 0xfe, 0xe9, + 0x18, 0xbd, 0x08, 0xf2, 0x1a, 0xfe, 0x3f, 0xd1, 0xf6, 0xcf, 0x1d, 0xfc, 0xe8, + 0x2a, 0x23, 0xa6, 0x02, 0x3a, 0xe9, 0xd9, 0xd6, 0xdc, 0x18, 0x0a, 0x1f, 0xbe, + 0xfd, 0xef, 0xf6, 0x15, 0x18, 0x15, 0xf8, 0x0e, 0x23, 0x2b, 0x1d, 0xda, 0xf0, + 0x26, 0xf9, 0xef, 0x2c, 0x25, 0x0c, 0xeb, 0x13, 0x53, 0xf5, 0x09, 0x1a, 0x5f, + 0xbc, 0xe9, 0x3a, 0xca, 0xf6, 0xfa, 0x03, 0xd9, 0xc1, 0x2d, 0x03, 0xf3, 0xfc, + 0x26, 0x2f, 0x07, 0x22, 0x20, 0x0e, 0xd5, 0xed, 0xcf, 0xfb, 0x17, 0xfa, 0x2c, + 0xe9, 0x5e, 0x18, 0xba, 0x3c, 0xd9, 0xff, 0x21, 0x1c, 0xff, 0x18, 0x13, 0x1c, + 0xc7, 0xe7, 0xa4, 0x19, 0x1a, 0x0b, 0x46, 0xdf, 0x17, 0xcf, 0xa3, 0xd0, 0x78, + 0xca, 0xfb, 0xc8, 0xcc, 0x01, 0xf8, 0xfa, 0x41, 0x0b, 0x38, 0xfe, 0x34, 0xf6, + 0xb1, 0x29, 0x1e, 0xd5, 0x0b, 0xff, 0xc4, 0x01, 0x3d, 0xf9, 0x2b, 0xf2, 0x04, + 0x7f, 0xde, 0xfd, 0xf7, 0xc2, 0x3c, 0x34, 0x22, 0x1b, 0x20, 0x10, 0x35, 0x06, + 0x0b, 0x00, 0xd0, 0xe3, 0x0f, 0x41, 0x59, 0xbe, 0x20, 0x45, 0xf9, 0xe3, 0xe8, + 0xec, 0xee, 0xd8, 0x1d, 0x04, 0xeb, 0x48, 0xf9, 0xdc, 0xe9, 0x08, 0xbf, 0xe7, + 0x22, 0xe7, 0x37, 0x0b, 0xcd, 0xd1, 0x05, 0xd4, 0x28, 0x33, 0xc3, 0xed, 0x2c, + 0x01, 0xfe, 0x42, 0xf5, 0xc1, 0x4a, 0x3a, 0x03, 0x05, 0xd0, 0xe5, 0xf2, 0xfb, + 0x0a, 0xd2, 0x30, 0x09, 0xf8, 0xff, 0x1f, 0x25, 0xe5, 0xf4, 0x10, 0x26, 0x1b, + 0x4c, 0x07, 0x00, 0xf2, 0xe6, 0xe5, 0xe4, 0x09, 0xdf, 0x16, 0x4d, 0xf4, 0x35, + 0x81, 0x0e, 0x18, 0x24, 0x06, 0xf6, 0xe4, 0xf6, 0xe8, 0xee, 0x79, 0x0b, 0x16, + 0xf7, 0xdc, 0xe5, 0x2d, 0x28, 0xeb, 0x2b, 0xfa, 0x0a, 0x21, 0xff, 0xf4, 0x00, + 0x1a, 0x36, 0x1e, 0x17, 0xda, 0xcd, 0xed, 0xc9, 0x43, 0xe5, 0x08, 0x0e, 0x33, + 0xf6, 0xdf, 0xdb, 0x1e, 0xc8, 0x11, 0xe3, 0x00, 0xfe, 0x21, 0xf7, 0x1b, 0xe5, + 0xd0, 0x08, 0xe0, 0x1a, 0x1a, 0x2e, 0xf7, 0xb5, 0x16, 0x2f, 0x28, 0x1f, 0xdf, + 0xe3, 0xcf, 0x34, 0xf8, 0xe0, 0xf7, 0x2b, 0xeb, 0x11, 0xd0, 0x1c, 0xe8, 0x03, + 0x03, 0xe5, 0x06, 0x54, 0xbf, 0xcf, 0xea, 0x3a, 0xe0, 0xff, 0xcf, 0x2c, 0x02, + 0xd4, 0xf4, 0xf9, 0xcf, 0x7f, 0xf2, 0x0d, 0x23, 0x2e, 0xe0, 0xc6, 0x38, 0xe7, + 0xe8, 0x1c, 0xbd, 0x30, 0xeb, 0x10, 0x10, 0xe8, 0x24, 0x0b, 0xf1, 0xfd, 0x23, + 0x07, 0x0e, 0xe4, 0x12, 0xcd, 0x50, 0x33, 0xfe, 0xf6, 0x0a, 0x03, 0x38, 0x00, + 0xf2, 0xec, 0x0b, 0xe2, 0xdd, 0xf2, 0x38, 0xd6, 0xdc, 0xf8, 0x40, 0x39, 0xe0, + 0x12, 0x03, 0x04, 0xe6, 0x0c, 0x00, 0xd1, 0x1a, 0xff, 0xd3, 0x40, 0x05, 0x50, + 0xf7, 0x0f, 0xfe, 0xcc, 0xee, 0xf0, 0x1d, 0x16, 0x2b, 0xec, 0xf4, 0xf4, 0xf8, + 0x25, 0xee, 0x09, 0xd3, 0x2f, 0x02, 0x07, 0xde, 0xa7, 0xeb, 0xd3, 0x3a, 0xdf, + 0x2d, 0x2f, 0xf0, 0x49, 0xfe, 0x0c, 0x81, 0xf8, 0xb3, 0xe8, 0xfb, 0x18, 0x24, + 0xd0, 0xc1, 0xef, 0x44, 0x9d, 0x0c, 0x15, 0xc4, 0xc0, 0xe1, 0xd6, 0x09, 0x1f, + 0x04, 0x0b, 0x0e, 0x19, 0xab, 0xac, 0x32, 0x10, 0x11, 0xb7, 0x02, 0xfe, 0x70, + 0x48, 0xe7, 0xcb, 0xd3, 0x9f, 0x2a, 0x28, 0x69, 0xe6, 0x97, 0xfe, 0xab, 0x14, + 0x3e, 0xd6, 0x26, 0xd1, 0x44, 0xf3, 0x0c, 0xf7, 0x18, 0xec, 0xcc, 0xe4, 0xf3, + 0xbe, 0x26, 0x1a, 0xa6, 0x0a, 0xdd, 0xa2, 0x87, 0x07, 0x43, 0x50, 0xd8, 0x46, + 0xa9, 0xf7, 0x36, 0xb1, 0xb4, 0x23, 0x14, 0x10, 0x4a, 0x2a, 0xfc, 0x35, 0xef, + 0xd5, 0x1e, 0x36, 0x40, 0x1c, 0xac, 0x23, 0x37, 0x03, 0xaa, 0xc0, 0xb5, 0x2b, + 0x3f, 0x54, 0x62, 0x0a, 0xaa, 0x92, 0xf0, 0x1a, 0xe9, 0x02, 0x31, 0xdc, 0x13, + 0x2e, 0xee, 0x15, 0x13, 0x13, 0x07, 0x3c, 0xcc, 0x05, 0x37, 0x5a, 0x02, 0x32, + 0x0f, 0x1d, 0x3a, 0x39, 0x0f, 0x2c, 0x0b, 0x3f, 0x6e, 0x51, 0xfc, 0x44, 0xcc, + 0xf9, 0xed, 0x23, 0xbf, 0x63, 0x0d, 0xd9, 0xdf, 0x16, 0x43, 0x0f, 0xbc, 0xf8, + 0xc1, 0x29, 0x26, 0xff, 0xb3, 0x11, 0xdd, 0x3d, 0x12, 0x2d, 0x0b, 0x7f, 0xfb, + 0x05, 0x01, 0xd6, 0x38, 0xea, 0xff, 0xf6, 0x37, 0xcd, 0x29, 0xa9, 0xde, 0x1a, + 0xce, 0xf7, 0x1f, 0xfb, 0x26, 0x17, 0x16, 0x45, 0x22, 0xde, 0x21, 0x0f, 0xeb, + 0xe3, 0x05, 0x0b, 0xee, 0x2b, 0x37, 0x2e, 0xd9, 0x7c, 0xf4, 0x18, 0x15, 0x1a, + 0xd1, 0xf9, 0xe1, 0x58, 0x1f, 0x20, 0x0f, 0x35, 0x17, 0x0f, 0xde, 0x52, 0x03, + 0xf9, 0xf6, 0xfa, 0x3a, 0x07, 0x22, 0x52, 0xc2, 0x21, 0x1a, 0x1d, 0xb0, 0xe5, + 0xfd, 0x0a, 0x1f, 0xc0, 0x3e, 0x4d, 0x53, 0x08, 0xf8, 0xd1, 0xf2, 0x0d, 0xf8, + 0x18, 0x2d, 0x21, 0xe8, 0x56, 0xe9, 0x06, 0x03, 0x1d, 0x16, 0x0e, 0x16, 0xf4, + 0x0d, 0xe6, 0xfc, 0x3a, 0x0d, 0x25, 0x19, 0x20, 0x03, 0x29, 0x13, 0x2a, 0xf3, + 0x4d, 0xc3, 0xc9, 0x10, 0x1e, 0x15, 0xcc, 0x56, 0x24, 0xb7, 0xea, 0xf8, 0x00, + 0x72, 0xe9, 0x0a, 0x51, 0x00, 0xc6, 0xda, 0x18, 0x1e, 0x15, 0xab, 0xf7, 0xe4, + 0xa4, 0xfb, 0x2d, 0x4f, 0x03, 0x9b, 0x17, 0x04, 0x3e, 0xc1, 0xcc, 0xe7, 0x0f, + 0x92, 0xfe, 0x22, 0x07, 0x20, 0xe7, 0xcf, 0xe2, 0xdf, 0xfa, 0x18, 0xda, 0x0e, + 0xe0, 0xe0, 0xe6, 0xb4, 0x2e, 0x38, 0x35, 0x28, 0x23, 0xd6, 0x02, 0x1d, 0xfc, + 0xed, 0x83, 0xe6, 0xfd, 0x1a, 0xad, 0xb4, 0xf9, 0x0a, 0x1a, 0xcb, 0x16, 0xd1, + 0x11, 0xc9, 0x24, 0xef, 0x0c, 0xfd, 0xf5, 0x00, 0x17, 0x02, 0x11, 0x14, 0x28, + 0x0a, 0x91, 0xf2, 0x2d, 0xf2, 0xf7, 0x3f, 0x25, 0xee, 0xe7, 0xd3, 0xf8, 0xdd, + 0x25, 0x20, 0x11, 0x7f, 0x42, 0xb3, 0x08, 0xe4, 0x2f, 0xda, 0xf7, 0xf3, 0x92, + 0x1f, 0x1c, 0x12, 0xae, 0xdc, 0xc3, 0xe1, 0x17, 0xef, 0xf5, 0x05, 0xcd, 0x15, + 0xf2, 0xf5, 0x21, 0xff, 0x26, 0xc2, 0x1b, 0xce, 0xfa, 0x03, 0xea, 0x02, 0xfc, + 0xe1, 0xca, 0xda, 0x1a, 0x02, 0x61, 0x20, 0xeb, 0xc7, 0xe2, 0x84, 0xfc, 0x00, + 0x1b, 0xca, 0xa8, 0xd0, 0x29, 0xef, 0x20, 0xcf, 0x2b, 0xfe, 0x40, 0x17, 0xff, + 0xf8, 0xf1, 0x29, 0x91, 0x07, 0xa8, 0xfe, 0xc0, 0xff, 0xff, 0x07, 0xfc, 0xd5, + 0xe2, 0x00, 0xed, 0xd7, 0x09, 0x29, 0xbc, 0x07, 0x68, 0xb1, 0xc3, 0x81, 0x10, + 0xf1, 0x00, 0x1d, 0xf8, 0xd1, 0x0d, 0xf5, 0xe8, 0xf1, 0xe3, 0xd4, 0x47, 0xf7, + 0xec, 0xe0, 0xe7, 0xde, 0x24, 0xf4, 0x61, 0xe3, 0xfe, 0xcb, 0x26, 0xe9, 0xb7, + 0x03, 0xd7, 0xb5, 0xe9, 0x2b, 0xec, 0xef, 0x17, 0xde, 0x29, 0xcf, 0x08, 0xf1, + 0xe5, 0xd0, 0xa9, 0x00, 0x1f, 0xee, 0x1e, 0xe9, 0x4f, 0x03, 0x18, 0xe0, 0x20, + 0xfc, 0x13, 0x6b, 0x0a, 0x01, 0xb8, 0xd3, 0x13, 0xf4, 0x09, 0x1e, 0x33, 0x44, + 0xec, 0x02, 0xff, 0x50, 0x5b, 0x00, 0xc7, 0x34, 0xea, 0xe1, 0x1e, 0x45, 0xde, + 0xf2, 0x29, 0xd1, 0xe2, 0x14, 0xd4, 0x36, 0x61, 0x7f, 0x12, 0x49, 0xdd, 0xec, + 0xe9, 0xf8, 0xc2, 0xf9, 0xc7, 0x05, 0x1d, 0xf9, 0xe2, 0x20, 0x04, 0xf4, 0xe2, + 0xe9, 0x2f, 0xeb, 0x0b, 0xef, 0x1f, 0xc0, 0xb8, 0xe8, 0xdd, 0xf9, 0xf3, 0xb4, + 0x39, 0x41, 0x18, 0xf8, 0xf0, 0xf3, 0x45, 0xd1, 0xc8, 0xd6, 0x3d, 0xf3, 0xee, + 0xec, 0x00, 0x2f, 0x03, 0xf7, 0x1d, 0x20, 0xf5, 0xe8, 0xfd, 0x24, 0xe2, 0x17, + 0xf3, 0x07, 0xee, 0xed, 0xd8, 0x2b, 0x3d, 0x18, 0x08, 0xf5, 0x24, 0x0e, 0xf7, + 0xed, 0x35, 0x22, 0x0e, 0x30, 0xf4, 0xc6, 0xb9, 0x21, 0xfc, 0x09, 0x06, 0x10, + 0xed, 0xfc, 0x38, 0x2b, 0x21, 0x96, 0x05, 0xdb, 0x09, 0xbe, 0x2e, 0xba, 0x52, + 0xfc, 0x3d, 0xd4, 0xd0, 0x04, 0x27, 0xae, 0x9d, 0x13, 0x57, 0x34, 0x0c, 0x11, + 0xe6, 0x3f, 0x1f, 0xb8, 0x2c, 0xf8, 0x2e, 0xe8, 0xe6, 0x06, 0x32, 0xe6, 0x23, + 0xc6, 0x29, 0x11, 0xcd, 0x06, 0xe6, 0xf8, 0x1a, 0x2f, 0x0e, 0x18, 0xc0, 0x11, + 0xeb, 0xdb, 0xec, 0x7f, 0xfe, 0xe4, 0xfe, 0xe0, 0xf2, 0xc8, 0x1b, 0x19, 0x0d, + 0xe3, 0xcb, 0xdd, 0xc8, 0xd9, 0xde, 0x09, 0xb5, 0xfc, 0x03, 0xef, 0xe9, 0xf0, + 0x3e, 0xfc, 0x12, 0xe9, 0xdf, 0xe7, 0xe8, 0xf9, 0xfd, 0xea, 0xff, 0x25, 0x03, + 0xd3, 0xd8, 0x14, 0x28, 0x0b, 0x31, 0x52, 0xd9, 0xfd, 0x0a, 0xe0, 0xe0, 0x02, + 0xec, 0xc5, 0x12, 0xf0, 0x17, 0xc8, 0x2a, 0xf0, 0x34, 0xd0, 0x1e, 0xea, 0xd5, + 0x47, 0x34, 0x29, 0xd0, 0xeb, 0xd4, 0x04, 0x0c, 0x38, 0x0d, 0xc7, 0x10, 0xd1, + 0x1d, 0x05, 0xdc, 0xe8, 0xeb, 0x0e, 0xe6, 0x17, 0xf3, 0x30, 0x26, 0xee, 0xf9, + 0x50, 0x25, 0xc7, 0x2e, 0x11, 0xd5, 0xbe, 0xfa, 0xca, 0xe5, 0xec, 0xa8, 0x05, + 0x00, 0x01, 0xd9, 0xb2, 0x1e, 0x37, 0xee, 0x81, 0x22, 0x0a, 0xb5, 0x26, 0x2e, + 0xbf, 0x56, 0x26, 0xfb, 0xe9, 0xbf, 0xee, 0xff, 0x21, 0x02, 0x18, 0xfc, 0x52, + 0xe8, 0x20, 0x28, 0xf7, 0xfe, 0xfe, 0xf2, 0x0c, 0x3f, 0xfe, 0xf8, 0x30, 0xfd, + 0x1f, 0xdc, 0xfb, 0x20, 0x77, 0x3e, 0xca, 0x3d, 0x2e, 0xf7, 0xca, 0xef, 0xfc, + 0x04, 0xec, 0xf6, 0xf4, 0x55, 0x11, 0xfd, 0xef, 0x0e, 0xed, 0xd4, 0x01, 0x09, + 0xf6, 0xe5, 0x01, 0x20, 0x04, 0x1a, 0xf2, 0xdf, 0x00, 0x44, 0x9e, 0xfc, 0x0a, + 0xe6, 0xff, 0xe8, 0xc8, 0x28, 0x5d, 0x26, 0x04, 0xeb, 0xd5, 0xf9, 0x04, 0xf9, + 0xb4, 0xd1, 0x14, 0x1d, 0x38, 0xf4, 0xf0, 0x33, 0x2e, 0x19, 0xd7, 0xe8, 0x13, + 0xe7, 0x15, 0x2f, 0x07, 0x00, 0x10, 0x00, 0x6f, 0x31, 0x31, 0x13, 0x3d, 0x28, + 0xda, 0x2d, 0xf0, 0x14, 0x2d, 0x13, 0x81, 0xd6, 0xe7, 0x2a, 0x1e, 0x34, 0x2b, + 0x0f, 0xc1, 0x1c, 0xcb, 0x21, 0xb7, 0x2f, 0x28, 0xe1, 0x3f, 0x23, 0xf6, 0x3b, + 0x20, 0xad, 0x41, 0xe4, 0xe4, 0x11, 0x3c, 0x27, 0x4c, 0x3a, 0x26, 0x23, 0x1f, + 0xec, 0x35, 0xe6, 0x1f, 0xf5, 0x3e, 0xfa, 0x07, 0x38, 0x28, 0x20, 0x03, 0x14, + 0x31, 0xfa, 0x4b, 0xf5, 0x1a, 0x47, 0x07, 0x32, 0xdc, 0x3d, 0x11, 0xd2, 0x05, + 0xf9, 0xd8, 0x08, 0x41, 0x33, 0x01, 0x11, 0x2b, 0x1c, 0x0a, 0x0b, 0xe7, 0x03, + 0x0a, 0xdc, 0x39, 0x39, 0x10, 0x24, 0xe5, 0x34, 0xfe, 0xf8, 0xe9, 0xec, 0xd9, + 0xd6, 0x07, 0x1b, 0x30, 0x3b, 0xf6, 0xcc, 0x53, 0xd1, 0xf6, 0x09, 0x1e, 0x20, + 0xee, 0x13, 0x14, 0xe8, 0xa4, 0x63, 0xc6, 0x1f, 0x0f, 0x0f, 0xd0, 0xe1, 0x5a, + 0x13, 0x0c, 0xb3, 0x1a, 0x21, 0x37, 0xc3, 0x58, 0xbf, 0x43, 0xcc, 0x09, 0xe9, + 0xc0, 0x63, 0xd6, 0xe0, 0xd9, 0x03, 0xbd, 0x10, 0x19, 0xe9, 0xc1, 0x13, 0xbc, + 0xd0, 0x51, 0x0a, 0xa9, 0x39, 0x0b, 0xca, 0x3c, 0xdf, 0xd2, 0x12, 0xbf, 0xcc, + 0x15, 0xe5, 0x1d, 0x08, 0xcb, 0xe5, 0x0e, 0xcb, 0x3c, 0xf2, 0xb1, 0x3b, 0xcc, + 0xb2, 0x0e, 0x12, 0x35, 0xfa, 0xff, 0xc8, 0x2d, 0xed, 0xfa, 0x3b, 0x04, 0xfc, + 0x09, 0xfd, 0xf4, 0xff, 0xf6, 0xe4, 0x02, 0xd4, 0x00, 0x92, 0x26, 0x17, 0xd2, + 0xe2, 0xad, 0x27, 0xef, 0xd9, 0x06, 0x64, 0xfe, 0x2d, 0x18, 0x2e, 0xe1, 0xb7, + 0x45, 0x30, 0x43, 0xde, 0xdc, 0xff, 0xaf, 0x18, 0xdb, 0xc9, 0xee, 0xf2, 0xd3, + 0x3c, 0x13, 0x06, 0x00, 0xf7, 0x13, 0x08, 0xdc, 0xf9, 0xf9, 0xfd, 0x2a, 0xf9, + 0xdb, 0xc5, 0x05, 0x23, 0x1c, 0x7f, 0x31, 0xe3, 0xdd, 0x51, 0xe8, 0x05, 0xf5, + 0x51, 0xbf, 0xa1, 0x2a, 0x46, 0xdf, 0x73, 0xec, 0xdb, 0xd6, 0xc7, 0x1a, 0xc8, + 0xfa, 0xcc, 0x08, 0xbe, 0x05, 0xe6, 0xf8, 0x04, 0x2e, 0x43, 0x08, 0x0f, 0x90, + 0x12, 0xe1, 0x25, 0xbb, 0xdd, 0xd8, 0x16, 0x3e, 0xda, 0x5f, 0x12, 0x19, 0xe5, + 0xf0, 0xf7, 0x2b, 0x02, 0x1e, 0xf4, 0xef, 0xaf, 0x2e, 0xcf, 0x49, 0xc2, 0xdc, + 0xea, 0x1f, 0xc1, 0xee, 0x09, 0x08, 0xf9, 0x36, 0x2a, 0xf0, 0x0d, 0x2b, 0xf0, + 0x11, 0x28, 0x28, 0x2a, 0x36, 0xda, 0xb5, 0x7f, 0xe7, 0xdd, 0x32, 0x03, 0x06, + 0xfe, 0x07, 0xfc, 0xf6, 0x4a, 0xfc, 0xe9, 0x04, 0x0f, 0xff, 0x0d, 0x4f, 0x1b, + 0x07, 0xf7, 0x1f, 0x04, 0xcf, 0xdc, 0x15, 0x0b, 0x2d, 0x47, 0x18, 0xf6, 0xb9, + 0xb4, 0xc4, 0xd8, 0x0c, 0x76, 0xe0, 0x06, 0xa8, 0xf5, 0xe0, 0x17, 0x1e, 0x07, + 0xe2, 0x5a, 0xec, 0xd7, 0x03, 0xdf, 0xf5, 0x01, 0x04, 0xeb, 0x05, 0xea, 0xdf, + 0x42, 0xe6, 0xe4, 0xce, 0x09, 0xfa, 0x38, 0x53, 0x02, 0xda, 0x16, 0xe7, 0x19, + 0x41, 0x14, 0xf2, 0xf9, 0xf6, 0x17, 0x03, 0x2d, 0x24, 0x20, 0x6b, 0xf3, 0x55, + 0x23, 0xf5, 0xe2, 0x0e, 0x4c, 0xe0, 0x0f, 0xd2, 0x7f, 0xba, 0x1e, 0xd3, 0x1a, + 0xd8, 0x3b, 0x18, 0x01, 0x0b, 0xe6, 0xfd, 0x20, 0xde, 0x14, 0xe0, 0x15, 0xf8, + 0x0c, 0xfd, 0xd1, 0x0c, 0x3c, 0x04, 0x09, 0x1f, 0xfa, 0xc3, 0x2e, 0x06, 0xf2, + 0xf5, 0x0d, 0xa2, 0x19, 0x37, 0xe7, 0xe3, 0xcb, 0xfd, 0x18, 0xdf, 0xf9, 0x02, + 0xf0, 0x0c, 0x2e, 0xd7, 0xff, 0xf5, 0x0c, 0xfa, 0xf5, 0x2b, 0x17, 0xe8, 0xb4, + 0xfd, 0xe4, 0x25, 0x2e, 0x0b, 0x31, 0x27, 0x1c, 0x03, 0x04, 0x06, 0xdb, 0xd1, + 0xff, 0x23, 0x15, 0x21, 0x43, 0xab, 0x20, 0xfb, 0x24, 0x02, 0xf6, 0x28, 0x03, + 0xfc, 0xcd, 0x2f, 0xed, 0x34, 0x21, 0x2f, 0x3c, 0xfa, 0xf9, 0x1b, 0xd3, 0xe6, + 0x13, 0x4d, 0xe2, 0x1d, 0x7a, 0x01, 0xc6, 0xd7, 0x14, 0xdf, 0x57, 0x4f, 0xdc, + 0xd1, 0xaf, 0x97, 0xc7, 0x52, 0xa2, 0x4d, 0x38, 0x6f, 0xe4, 0xe2, 0x60, 0x4b, + 0xcb, 0xf8, 0xd5, 0xbd, 0x33, 0x1d, 0xfa, 0x6a, 0x14, 0xf8, 0xed, 0x1e, 0x57, + 0x5f, 0xdb, 0xcf, 0xc5, 0xbf, 0xf2, 0xe4, 0x3c, 0xc5, 0xf2, 0x12, 0xee, 0x15, + 0x0e, 0x44, 0x3c, 0xde, 0x20, 0x23, 0x21, 0x48, 0xd5, 0x32, 0x5d, 0x07, 0xf7, + 0xe3, 0x26, 0x7f, 0xe2, 0xe3, 0xe7, 0xcd, 0x27, 0x5f, 0xe4, 0x37, 0x49, 0x21, + 0x2c, 0xd7, 0x39, 0xd5, 0x39, 0x2f, 0x00, 0xad, 0x24, 0x2f, 0xfb, 0xef, 0xf7, + 0x24, 0x2f, 0xe8, 0x02, 0x17, 0xb8, 0xdd, 0xf5, 0x41, 0x8f, 0x06, 0x34, 0x65, + 0xfe, 0xf5, 0x8b, 0x5b, 0x22, 0xfa, 0x24, 0x13, 0x0d, 0xdf, 0xec, 0x5f, 0xd9, + 0xca, 0x0e, 0xd0, 0xf1, 0x0e, 0xeb, 0x4b, 0xc4, 0xcf, 0xda, 0xce, 0xea, 0xec, + 0xd9, 0x1c, 0xc6, 0xc8, 0xf3, 0x05, 0xbd, 0x04, 0xf9, 0xea, 0x06, 0xd8, 0x26, + 0xaa, 0x08, 0x31, 0xc3, 0xe1, 0xef, 0xec, 0xfe, 0x55, 0x1e, 0x15, 0x03, 0xfe, + 0x06, 0x15, 0xf1, 0xdd, 0x0e, 0xe2, 0xf3, 0x9e, 0xb7, 0x30, 0x2a, 0x9c, 0x47, + 0xfb, 0xe6, 0xdb, 0xff, 0xcb, 0x2e, 0xce, 0x0a, 0xfd, 0x05, 0xde, 0xb3, 0xd8, + 0xe4, 0x34, 0x34, 0xed, 0x10, 0xb7, 0xf3, 0x37, 0xcf, 0xd4, 0xb5, 0xdc, 0xf4, + 0xe7, 0xca, 0xff, 0xcb, 0x2e, 0x31, 0xff, 0x25, 0xf7, 0x29, 0xb9, 0xc4, 0xf5, + 0x2f, 0x0d, 0x16, 0x04, 0xe0, 0x11, 0x10, 0x17, 0x08, 0x1e, 0xed, 0xef, 0x0e, + 0xf0, 0x06, 0xdf, 0xc6, 0xcf, 0xfa, 0xff, 0x08, 0x2d, 0xca, 0xe1, 0x15, 0xc5, + 0xa9, 0xfb, 0xea, 0xf8, 0xa8, 0x08, 0xf3, 0xdd, 0xc0, 0x7f, 0x34, 0x20, 0x01, + 0x19, 0xde, 0xd3, 0x96, 0x11, 0x27, 0xea, 0xd5, 0xfc, 0x02, 0xcb, 0xac, 0x16, + 0xbe, 0x62, 0xe5, 0x3e, 0xf6, 0xdd, 0x1a, 0xd5, 0x24, 0xd8, 0x37, 0xf9, 0xe1, + 0xcc, 0x8e, 0xe8, 0x4e, 0x04, 0x1b, 0xe3, 0xe0, 0xdf, 0x08, 0xe6, 0x6c, 0x02, + 0x97, 0xf2, 0x1c, 0x2d, 0xed, 0xc1, 0xc9, 0x29, 0x1b, 0x0f, 0xfb, 0x15, 0xb3, + 0xf1, 0xd4, 0xcd, 0x7a, 0xce, 0x01, 0xf9, 0x56, 0x02, 0xf6, 0x06, 0xe4, 0x46, + 0x71, 0xf4, 0xb4, 0x5b, 0x14, 0x2b, 0x34, 0x10, 0x17, 0xd1, 0xea, 0x1a, 0xe9, + 0xe5, 0xbe, 0xc0, 0xf4, 0xb0, 0xb1, 0x3a, 0x8d, 0x47, 0xc0, 0xfb, 0x20, 0xdf, + 0xff, 0xf0, 0xf7, 0x15, 0x64, 0x2a, 0xe2, 0x42, 0x49, 0xf2, 0xcf, 0xfa, 0x1f, + 0x22, 0x00, 0x2d, 0x03, 0x2d, 0xbb, 0xfc, 0x7f, 0x31, 0x15, 0xdf, 0xd3, 0x0b, + 0xfb, 0xf4, 0x1e, 0x20, 0xc4, 0xdd, 0x0c, 0xef, 0xe4, 0xc4, 0xfd, 0x14, 0x2e, + 0xe1, 0xd0, 0xec, 0x03, 0x01, 0xf0, 0x31, 0x2b, 0x13, 0xd7, 0x1f, 0xf7, 0x08, + 0x24, 0x35, 0xe8, 0x18, 0x00, 0xfc, 0x0d, 0xf6, 0x15, 0xf8, 0x24, 0x1b, 0xc0, + 0xd2, 0xf8, 0x0e, 0xee, 0xd1, 0xee, 0x0d, 0xd0, 0xfb, 0x42, 0xfd, 0x42, 0x39, + 0x18, 0x26, 0xbb, 0x09, 0x02, 0x2c, 0x2c, 0x37, 0x01, 0x31, 0xe5, 0xe9, 0x16, + 0xdb, 0x1f, 0x02, 0x31, 0x04, 0xec, 0x3d, 0x1a, 0xe3, 0x21, 0xf8, 0x0a, 0x1b, + 0xf3, 0x7f, 0x0e, 0x3c, 0x3b, 0x0f, 0x0e, 0x15, 0x12, 0x35, 0xee, 0x17, 0x09, + 0xf3, 0x36, 0x2f, 0xdd, 0x06, 0x40, 0x0c, 0x2f, 0x08, 0x23, 0xe8, 0xe1, 0x10, + 0x49, 0xeb, 0x03, 0x03, 0xd5, 0x10, 0x44, 0xf0, 0x5d, 0xf8, 0xf3, 0x00, 0xda, + 0x4a, 0xe4, 0x2a, 0xf4, 0xdb, 0x0d, 0x49, 0xee, 0x1b, 0x12, 0xf4, 0xed, 0x0d, + 0x12, 0xf9, 0xec, 0xbe, 0x05, 0xf4, 0x19, 0x49, 0xf7, 0x07, 0xb6, 0xfa, 0xc2, + 0x06, 0xd0, 0xa0, 0x0d, 0x45, 0x03, 0x8e, 0x34, 0x40, 0xe3, 0xc7, 0x19, 0x17, + 0xfc, 0xa3, 0x15, 0xea, 0xf1, 0x9f, 0xe4, 0xaa, 0x11, 0xbc, 0x30, 0xdb, 0xad, + 0x7f, 0x41, 0xf5, 0x34, 0x3e, 0xec, 0xfd, 0xf0, 0xfe, 0xa0, 0x13, 0x28, 0xf6, + 0xdf, 0xc4, 0xfd, 0xe8, 0x2a, 0xc0, 0xed, 0x54, 0x93, 0x4e, 0xfd, 0xd4, 0xec, + 0xf3, 0x24, 0xd1, 0x39, 0xd3, 0xd1, 0xe6, 0xd5, 0xe6, 0xd9, 0xef, 0xb6, 0xd3, + 0x2a, 0x04, 0xd8, 0x33, 0xd6, 0xc9, 0xd3, 0xb6, 0xdc, 0xbb, 0x19, 0x16, 0xfe, + 0xfa, 0xe1, 0x09, 0x9b, 0xb0, 0xa0, 0x44, 0x17, 0xfc, 0xd1, 0xcf, 0xd6, 0xdb, + 0x51, 0x0e, 0xec, 0x37, 0xc3, 0xe0, 0x0d, 0xbb, 0xda, 0xfa, 0xe2, 0xf0, 0xcf, + 0x2c, 0xa2, 0x25, 0xf8, 0xc1, 0xde, 0x42, 0x27, 0x09, 0xd7, 0x27, 0x9a, 0x53, + 0xf5, 0x14, 0x43, 0x69, 0x6f, 0x14, 0x23, 0x0d, 0xda, 0x4b, 0xf4, 0xf2, 0x0b, + 0x4c, 0x7f, 0x19, 0x36, 0x33, 0x1b, 0xca, 0xe9, 0x1e, 0x0c, 0x04, 0x48, 0x04, + 0xdb, 0xe1, 0xf2, 0xf2, 0x1f, 0xf4, 0x24, 0xec, 0x29, 0xf2, 0x16, 0x0f, 0xfb, + 0xdf, 0xb9, 0xe1, 0x41, 0xfa, 0x2c, 0x0d, 0xe7, 0xdf, 0xd4, 0xb9, 0xf4, 0x37, + 0x16, 0x25, 0xf8, 0xfd, 0xc9, 0x29, 0x02, 0x2a, 0xea, 0x40, 0xf1, 0x04, 0x1b, + 0x12, 0x02, 0x5b, 0xbb, 0xd4, 0x23, 0x0c, 0xd4, 0xe5, 0xd0, 0x02, 0x13, 0xec, + 0x0d, 0x0e, 0xeb, 0x01, 0x1c, 0x41, 0x04, 0xfa, 0x21, 0x1e, 0xf3, 0x14, 0x1b, + 0xc8, 0x15, 0xf2, 0xe1, 0xd8, 0xf2, 0xfa, 0x21, 0xe8, 0xd5, 0x5e, 0xfa, 0x02, + 0x00, 0xeb, 0x13, 0xdb, 0xa7, 0xf3, 0x16, 0x26, 0x18, 0xf5, 0x29, 0x0b, 0xd2, + 0x18, 0x1f, 0x3c, 0x18, 0x2f, 0x1c, 0x0b, 0x00, 0x25, 0xed, 0xb2, 0xe0, 0x47, + 0x3a, 0x05, 0x55, 0x12, 0xe4, 0x08, 0x7f, 0xe7, 0xbc, 0x53, 0xc3, 0xab, 0x2a, + 0x37, 0x05, 0x03, 0x1e, 0xed, 0xdf, 0xbf, 0x0d, 0x2b, 0xea, 0xd2, 0xee, 0xde, + 0x01, 0xbb, 0x07, 0xf6, 0x22, 0x2e, 0x69, 0x08, 0x30, 0xf6, 0xe6, 0x0e, 0xe9, + 0xc0, 0xf5, 0xf7, 0xf5, 0x09, 0x0d, 0x26, 0xf6, 0xbf, 0xd6, 0xa7, 0x00, 0x07, + 0x0f, 0x32, 0xb5, 0x17, 0x98, 0x22, 0x1c, 0x0b, 0x51, 0x32, 0xf3, 0xdb, 0x13, + 0x41, 0x94, 0x1a, 0x0a, 0x1e, 0x25, 0xf5, 0x19, 0x6f, 0x3d, 0x00, 0x3b, 0x19, + 0x33, 0xc7, 0xc3, 0xff, 0xee, 0xe8, 0x20, 0xc6, 0xe8, 0xf3, 0xe2, 0xfe, 0xf1, + 0xd9, 0xfd, 0x37, 0x22, 0xfc, 0xea, 0xf4, 0xfe, 0x75, 0xef, 0x16, 0xef, 0x4e, + 0x2f, 0xfe, 0xd0, 0xca, 0x09, 0xfa, 0xee, 0x01, 0x1e, 0x1b, 0xfe, 0x13, 0x0a, + 0x12, 0x07, 0x01, 0xf7, 0x03, 0xee, 0x31, 0x41, 0xa8, 0x09, 0xef, 0x3b, 0x13, + 0x05, 0xfc, 0x09, 0x20, 0x30, 0x18, 0xf3, 0x19, 0xf9, 0x42, 0x30, 0x74, 0xdb, + 0x07, 0xc7, 0xb7, 0xef, 0xde, 0xee, 0x18, 0xd2, 0xb3, 0xb9, 0x01, 0x04, 0x11, + 0xff, 0xb9, 0xc3, 0x01, 0xd4, 0x24, 0xd2, 0xcc, 0x1a, 0x4a, 0xd2, 0xe4, 0x2d, + 0xa8, 0xad, 0xa9, 0xe7, 0xaf, 0x2d, 0xe0, 0x69, 0x07, 0xfc, 0xb7, 0x40, 0xe2, + 0xe8, 0xf3, 0xb1, 0xfd, 0x1c, 0xfd, 0x51, 0x03, 0xe1, 0xeb, 0xf1, 0x9f, 0xca, + 0xe1, 0x46, 0xd6, 0xce, 0xe5, 0x27, 0x34, 0xdf, 0x4a, 0xeb, 0x09, 0x09, 0xb3, + 0xdc, 0xf5, 0xb2, 0xd9, 0x44, 0x34, 0x0c, 0xf0, 0xf2, 0xcf, 0xe7, 0xc1, 0x90, + 0xbf, 0x0a, 0x10, 0xc0, 0x23, 0xf7, 0x67, 0xbd, 0xca, 0x28, 0xd7, 0x14, 0xc3, + 0x54, 0xea, 0xb6, 0x7f, 0xd3, 0xc8, 0xd3, 0x10, 0xe4, 0xe5, 0x3a, 0x43, 0x0b, + 0xdb, 0xc8, 0xb5, 0xec, 0x53, 0x34, 0x26, 0xc9, 0x1d, 0xcc, 0xc7, 0xf0, 0x1c, + 0x25, 0x0a, 0x27, 0xe1, 0x08, 0xec, 0xd4, 0x15, 0xb4, 0x49, 0xe5, 0x60, 0x6c, + 0xf9, 0xd0, 0xa3, 0x41, 0xea, 0x2a, 0xf3, 0xfa, 0x29, 0xc0, 0x06, 0xe3, 0xe3, + 0x39, 0x29, 0xd8, 0x61, 0x16, 0xf4, 0x27, 0x42, 0x07, 0xb8, 0x15, 0x27, 0xd2, + 0xe9, 0xc2, 0x7f, 0x07, 0xe1, 0x6d, 0x2a, 0xec, 0x35, 0xf3, 0x09, 0xf3, 0x3d, + 0xf1, 0xeb, 0x34, 0x01, 0x07, 0xf4, 0xfd, 0x00, 0xd8, 0x1f, 0x1d, 0xfd, 0xe5, + 0x07, 0xe5, 0xfc, 0xfe, 0x24, 0x3f, 0xe3, 0x3e, 0x19, 0x09, 0x4a, 0xe3, 0xe7, + 0x6d, 0xdd, 0x17, 0xee, 0x16, 0x38, 0x13, 0xea, 0xb1, 0xf5, 0xf4, 0xd2, 0x0d, + 0x10, 0x01, 0xdb, 0x11, 0xfb, 0xef, 0xd3, 0x27, 0xe9, 0x22, 0x31, 0xe6, 0x47, + 0x14, 0x24, 0xc8, 0x14, 0xd1, 0xeb, 0x04, 0x11, 0x0d, 0xee, 0xf6, 0xe2, 0x14, + 0xdf, 0xfe, 0xdd, 0x0a, 0xf8, 0xf6, 0x27, 0x75, 0xe1, 0xa7, 0xde, 0x5c, 0x0f, + 0xcc, 0xd7, 0xe9, 0xf9, 0xcd, 0x0d, 0x91, 0xef, 0xf1, 0xf2, 0x7f, 0xd7, 0xd4, + 0x12, 0xf5, 0x0e, 0xd4, 0xdb, 0x3f, 0x4c, 0xcd, 0x10, 0xf9, 0x4d, 0x05, 0xe9, + 0x3d, 0x1b, 0x4e, 0xdc, 0x13, 0x33, 0x0a, 0x16, 0xf0, 0xeb, 0xa6, 0xe0, 0xdf, + 0x12, 0x08, 0xd6, 0x12, 0x00, 0x1b, 0x1b, 0xf6, 0x06, 0x38, 0xf5, 0xd2, 0x57, + 0xf5, 0xfa, 0x0b, 0xf3, 0x2f, 0x14, 0xfe, 0x26, 0xf2, 0xd3, 0xe5, 0x1e, 0xfb, + 0xdb, 0xea, 0xbe, 0x0b, 0x52, 0x0f, 0x16, 0xec, 0xef, 0x04, 0x0f, 0x34, 0x08, + 0xfa, 0x20, 0xc4, 0x01, 0x41, 0x18, 0xdf, 0xd0, 0xd0, 0x07, 0xf0, 0xf0, 0x11, + 0xf6, 0xc8, 0xee, 0x28, 0x14, 0xc6, 0xbf, 0xf6, 0xf4, 0x0f, 0x29, 0xf5, 0x1b, + 0x09, 0x09, 0x01, 0xe1, 0xf4, 0xc0, 0xe2, 0xe2, 0x13, 0x1a, 0xf8, 0x07, 0x07, + 0x08, 0xf2, 0xd0, 0xea, 0x0d, 0x4c, 0x01, 0xa6, 0x48, 0x04, 0x0a, 0x14, 0x90, + 0xfe, 0x0f, 0x2b, 0xa6, 0x7f, 0x84, 0x2d, 0x37, 0x07, 0xb2, 0xeb, 0x63, 0x0b, + 0xc9, 0xa5, 0xef, 0x35, 0x0c, 0xe3, 0x13, 0xf6, 0x20, 0xe5, 0xec, 0x09, 0x21, + 0x6b, 0xe2, 0x02, 0xc2, 0xd3, 0xe5, 0x13, 0xe6, 0x4a, 0x19, 0x9c, 0x24, 0x3b, + 0xba, 0xcb, 0xda, 0x00, 0x55, 0xee, 0x35, 0xad, 0xf2, 0x9a, 0x75, 0xe8, 0xf0, + 0x03, 0x0b, 0x17, 0xed, 0xd5, 0x18, 0xc9, 0xfe, 0xe0, 0xf6, 0xbd, 0xe8, 0xb8, + 0x53, 0xd8, 0xe8, 0x1f, 0x16, 0xd2, 0xdd, 0x1f, 0x50, 0x37, 0xf7, 0x54, 0x23, + 0x17, 0xd4, 0xd7, 0xd7, 0xf7, 0xd3, 0xd9, 0x08, 0x37, 0x21, 0xcf, 0xf5, 0x17, + 0xe3, 0xd9, 0xb6, 0xe5, 0x25, 0xd0, 0xee, 0x27, 0xd3, 0x46, 0x8b, 0x12, 0x21, + 0x26, 0x74, 0xaa, 0x10, 0x02, 0xff, 0x46, 0x31, 0x16, 0x30, 0xb2, 0x0b, 0x3e, + 0xc4, 0x30, 0x61, 0xfe, 0xf8, 0x4c, 0xb8, 0xfc, 0xee, 0x19, 0xf0, 0xcd, 0x1b, + 0x26, 0x35, 0x38, 0x0c, 0xe7, 0xf0, 0xfd, 0xec, 0xe5, 0x3d, 0xf0, 0x08, 0xd1, + 0x16, 0x16, 0x14, 0xce, 0x08, 0xfa, 0x25, 0xfb, 0xe6, 0x26, 0xd2, 0xfa, 0xff, + 0x04, 0xf4, 0x19, 0x0b, 0x01, 0x07, 0x17, 0xf4, 0x08, 0xdc, 0xc5, 0x08, 0xe0, + 0x4f, 0x24, 0xe6, 0xd5, 0x16, 0x19, 0xf9, 0xe8, 0xc6, 0xc9, 0xeb, 0x21, 0x06, + 0x2d, 0x15, 0xf2, 0x1a, 0xfa, 0xff, 0x0a, 0xf2, 0xfa, 0xeb, 0xa8, 0x03, 0xbe, + 0xd8, 0xf4, 0xf1, 0xfa, 0x35, 0x33, 0x46, 0xc1, 0xf7, 0x2b, 0xc3, 0xcb, 0xf6, + 0xd7, 0xf5, 0xf5, 0x34, 0x06, 0xde, 0x1c, 0x2c, 0xd7, 0xbf, 0xe8, 0xca, 0x22, + 0xff, 0x58, 0x14, 0xe0, 0xd9, 0xef, 0xd4, 0x33, 0x13, 0xff, 0x08, 0x19, 0xd7, + 0x81, 0x01, 0xf8, 0xea, 0xfb, 0x2b, 0x05, 0x16, 0x1b, 0x0e, 0xd8, 0xdf, 0x0f, + 0x1a, 0xfe, 0x15, 0x03, 0x2c, 0x07, 0x1c, 0xf4, 0xe5, 0xe0, 0xd9, 0x03, 0x03, + 0xff, 0xc4, 0x2f, 0x49, 0x12, 0xde, 0xd7, 0xc9, 0xf5, 0xfb, 0xfd, 0x23, 0x1e, + 0xf1, 0x20, 0xd7, 0xd1, 0x34, 0x1e, 0x29, 0xf3, 0x16, 0xf7, 0x34, 0x21, 0xd4, + 0x0c, 0xe0, 0xf8, 0xec, 0x2c, 0x06, 0xd0, 0x2d, 0x22, 0x09, 0x33, 0x64, 0xf2, + 0x32, 0xef, 0x1f, 0xea, 0xfd, 0xaf, 0xfd, 0xf7, 0xf0, 0x02, 0x2e, 0xfa, 0xcd, + 0xf0, 0xec, 0xea, 0xf8, 0xe7, 0x07, 0xe7, 0xe1, 0xde, 0xfb, 0x04, 0xe6, 0x00, + 0x00, 0xe9, 0x2a, 0x51, 0xdd, 0x2d, 0xf9, 0xfe, 0xdf, 0xed, 0xf3, 0x12, 0xba, + 0x81, 0x1f, 0x07, 0xe2, 0xe2, 0x08, 0xff, 0x00, 0x20, 0xe3, 0x28, 0xf9, 0xee, + 0xf2, 0x01, 0xfa, 0x3c, 0x1a, 0x11, 0xec, 0xff, 0x25, 0x1e, 0x29, 0xfb, 0x17, + 0xcb, 0xcd, 0x40, 0xf2, 0x03, 0xeb, 0xdf, 0xce, 0x07, 0x0f, 0x2d, 0xec, 0xe2, + 0x03, 0x17, 0x10, 0xf8, 0x16, 0xf3, 0xf2, 0x0a, 0xd4, 0xee, 0x3f, 0xfd, 0x1e, + 0x10, 0x46, 0xe7, 0xe5, 0xd5, 0xba, 0xed, 0xff, 0xf6, 0x58, 0x13, 0xda, 0x35, + 0xba, 0xe2, 0x1b, 0x25, 0xe7, 0xf1, 0xcc, 0xb3, 0x1e, 0x44, 0xed, 0x0e, 0xcc, + 0xe7, 0xe5, 0xeb, 0x36, 0xcb, 0x57, 0x0b, 0xc7, 0x32, 0x1d, 0x3c, 0x18, 0xd1, + 0xfd, 0x06, 0xdf, 0x07, 0xcf, 0xe0, 0x02, 0x1d, 0xed, 0x2e, 0xbf, 0x0d, 0xff, + 0x07, 0xc7, 0xf5, 0xe6, 0xd0, 0xf5, 0x00, 0xf8, 0x17, 0xfe, 0xfd, 0xe8, 0x3a, + 0xe7, 0x2b, 0x18, 0x4f, 0xf8, 0x2e, 0xfb, 0x2d, 0xa1, 0x01, 0xe9, 0x81, 0xe2, + 0xbb, 0x00, 0xcf, 0xf3, 0xc8, 0xf9, 0x57, 0xc9, 0x16, 0xd2, 0x22, 0xe9, 0x06, + 0xf2, 0x14, 0x15, 0x4a, 0xe9, 0xf4, 0x09, 0xef, 0x1a, 0x97, 0x20, 0xdf, 0xde, + 0x21, 0xfc, 0x0a, 0xdb, 0xd9, 0x02, 0xe9, 0xf5, 0xf9, 0xf4, 0x0f, 0x2b, 0x25, + 0x39, 0x0a, 0x36, 0x20, 0xf0, 0xef, 0x27, 0xfd, 0xeb, 0x5d, 0x08, 0xe1, 0xfe, + 0x46, 0xea, 0x50, 0x11, 0x0f, 0x23, 0xf2, 0xd1, 0x2d, 0x0c, 0x32, 0xed, 0x0b, + 0xd6, 0x25, 0xbc, 0x7f, 0x0e, 0xe6, 0xfc, 0x17, 0x47, 0xe7, 0x13, 0x3e, 0x15, + 0x1a, 0x13, 0xde, 0x12, 0x1d, 0x31, 0xee, 0xe9, 0x36, 0xe8, 0x24, 0xe7, 0x15, + 0x03, 0x03, 0x48, 0x24, 0xe3, 0xeb, 0x08, 0x09, 0xf9, 0x20, 0x17, 0xe5, 0xf7, + 0xec, 0xf7, 0x3b, 0x17, 0xaf, 0xfd, 0x02, 0x77, 0x22, 0x14, 0xe2, 0xe8, 0x1b, + 0xf0, 0xe4, 0x21, 0xb1, 0xcc, 0xfe, 0xec, 0xac, 0xc4, 0xc7, 0xc9, 0x03, 0xf8, + 0xde, 0xd9, 0xf3, 0xc3, 0xea, 0xed, 0xfb, 0x0c, 0x35, 0x22, 0x00, 0x64, 0x3b, + 0x09, 0x0b, 0x4e, 0x16, 0x22, 0x06, 0xf7, 0x6d, 0x09, 0xab, 0xed, 0xf6, 0x00, + 0x11, 0xb4, 0x0c, 0xf6, 0xf1, 0x26, 0xb2, 0x2b, 0x05, 0x04, 0x01, 0xa3, 0xd6, + 0x0c, 0x57, 0xe5, 0x07, 0x32, 0xf2, 0xf1, 0x00, 0xed, 0x24, 0xc1, 0xed, 0x12, + 0x45, 0xce, 0x35, 0xfd, 0xec, 0x2f, 0xd0, 0xed, 0xe8, 0xe5, 0x21, 0x0e, 0x0d, + 0x6c, 0x68, 0xcb, 0xdd, 0x20, 0x23, 0x30, 0xea, 0x20, 0x18, 0x1a, 0xee, 0xf1, + 0xaf, 0xef, 0xfb, 0xe2, 0xa3, 0xc0, 0xee, 0xf2, 0x7f, 0x82, 0x28, 0x36, 0x2e, + 0xf7, 0x12, 0x07, 0xc3, 0xee, 0xe2, 0x16, 0xea, 0x2f, 0x0a, 0xfc, 0x0b, 0xef, + 0x11, 0xb6, 0xcb, 0x18, 0xdc, 0x0c, 0x30, 0x3c, 0x0b, 0x39, 0x41, 0xe3, 0xe3, + 0x08, 0xff, 0x4c, 0xbb, 0xaf, 0x09, 0x6a, 0x0a, 0xd0, 0xe6, 0x1a, 0x1b, 0xea, + 0x29, 0x27, 0xdc, 0xe2, 0xc0, 0x1e, 0xff, 0xcf, 0x2c, 0x37, 0x3b, 0x05, 0xe8, + 0xb9, 0x33, 0xd0, 0x00, 0xdb, 0x20, 0xc7, 0x41, 0xc3, 0x0a, 0xf0, 0x20, 0x54, + 0x01, 0x0b, 0xd6, 0xef, 0x07, 0x18, 0x42, 0xcf, 0x26, 0x5b, 0xce, 0xf2, 0xea, + 0xfb, 0x0a, 0x2d, 0xf8, 0x02, 0xe2, 0xcd, 0xd2, 0x36, 0x02, 0x10, 0x27, 0x1b, + 0xca, 0x33, 0x34, 0xdb, 0xf5, 0x33, 0xdd, 0x1a, 0x0e, 0x3c, 0xd5, 0xd9, 0x16, + 0x15, 0x15, 0x0c, 0xe4, 0x15, 0x1d, 0x21, 0x20, 0x02, 0xf0, 0xe2, 0x3f, 0xd2, + 0x28, 0x16, 0xf7, 0x3d, 0xca, 0xca, 0x1e, 0xc9, 0xdf, 0x2d, 0xe4, 0x21, 0xe8, + 0xbe, 0x21, 0x2d, 0x06, 0xe5, 0xfc, 0x11, 0xf9, 0xfb, 0x2c, 0xeb, 0x39, 0x33, + 0x07, 0x06, 0x08, 0xc0, 0xee, 0xe9, 0xe5, 0x81, 0xf7, 0x04, 0x1c, 0x39, 0xff, + 0xf2, 0x13, 0x13, 0xf7, 0xc6, 0x46, 0xdc, 0xad, 0x04, 0xf7, 0x0b, 0x09, 0x04, + 0xde, 0x20, 0xdc, 0x00, 0xe3, 0x16, 0xd4, 0xde, 0xbf, 0xba, 0xe5, 0x62, 0xe7, + 0xf6, 0xde, 0xde, 0xd9, 0x30, 0xee, 0xf8, 0x00, 0x01, 0xdf, 0x05, 0xdf, 0xef, + 0x31, 0xec, 0xda, 0x1c, 0xf0, 0x00, 0x1b, 0xbf, 0xdc, 0xc1, 0x19, 0xe4, 0x2e, + 0xef, 0x15, 0x03, 0xd8, 0x1d, 0xdd, 0x02, 0x2b, 0x2b, 0xf1, 0xf8, 0x3d, 0x1d, + 0xfe, 0x1f, 0xce, 0x37, 0x35, 0xd6, 0x0f, 0xfb, 0x20, 0xb3, 0xe3, 0x33, 0xf7, + 0xc9, 0xd3, 0x0e, 0xe8, 0x07, 0x1a, 0xea, 0x04, 0xf4, 0xf7, 0x0c, 0x13, 0x4c, + 0x04, 0xe2, 0xd5, 0x0e, 0xbb, 0x1f, 0xde, 0xfb, 0x9e, 0x99, 0x12, 0x8c, 0xeb, + 0x43, 0xe3, 0xf8, 0x09, 0xe0, 0x1a, 0xe1, 0xdc, 0x16, 0x0d, 0x15, 0x09, 0x0b, + 0xbc, 0xf5, 0xfe, 0x23, 0x2f, 0xe6, 0x27, 0xed, 0xe1, 0x21, 0xd5, 0x44, 0xf1, + 0xe3, 0xed, 0xff, 0xb1, 0xeb, 0xf6, 0xe0, 0x13, 0xfe, 0x41, 0x08, 0xf9, 0x12, + 0xfb, 0x1a, 0xf7, 0x3c, 0x01, 0xdf, 0x7f, 0x12, 0xe2, 0x76, 0x24, 0x19, 0xf0, + 0xd3, 0x5e, 0xe8, 0xeb, 0x13, 0xda, 0x07, 0x17, 0xe6, 0x0a, 0x05, 0xf6, 0x17, + 0xd5, 0xcf, 0xe5, 0x0e, 0xc6, 0x3e, 0xd9, 0x00, 0xb1, 0x16, 0xec, 0xce, 0x23, + 0x6e, 0xdd, 0xdc, 0x3c, 0xd9, 0xd8, 0x13, 0xde, 0xf8, 0x19, 0xf8, 0x63, 0xca, + 0x11, 0xa3, 0xf3, 0x86, 0x0c, 0x31, 0x12, 0x16, 0x9f, 0xe1, 0xf0, 0xb9, 0x04, + 0xa3, 0xea, 0x01, 0x12, 0x19, 0x38, 0xd1, 0x2e, 0x44, 0x01, 0xfa, 0xb8, 0xcd, + 0xf1, 0x02, 0xd8, 0x66, 0xeb, 0x45, 0xea, 0xca, 0xf1, 0xb7, 0xe9, 0xf2, 0xe4, + 0xc5, 0x08, 0x02, 0xf9, 0x14, 0xfe, 0x11, 0x33, 0x2e, 0xe1, 0x21, 0x34, 0x13, + 0x2a, 0xf0, 0x24, 0xcc, 0xb9, 0x36, 0xd1, 0xbf, 0xbf, 0xcf, 0x59, 0xc7, 0x81, + 0x13, 0xa2, 0xfb, 0x0d, 0xf3, 0xdc, 0x0d, 0xc7, 0xf5, 0xd8, 0xbe, 0x05, 0xd5, + 0xe6, 0x23, 0x76, 0xda, 0xf3, 0x19, 0x26, 0xfb, 0x34, 0xd9, 0x13, 0x40, 0x0d, + 0x9f, 0x41, 0x7b, 0xfb, 0x04, 0x1b, 0xcc, 0x32, 0x21, 0x1c, 0x15, 0x1b, 0xee, + 0x4e, 0xe5, 0x0c, 0x04, 0x46, 0xe4, 0xfd, 0xd8, 0xf1, 0xf3, 0xe8, 0x14, 0x21, + 0xed, 0xfc, 0x0f, 0x2e, 0xf3, 0xf1, 0xcc, 0xd5, 0xfa, 0xeb, 0xe6, 0x25, 0x7f, + 0x0f, 0x15, 0xf5, 0x1a, 0x24, 0x53, 0x1a, 0x5b, 0xee, 0xde, 0x00, 0x55, 0xf4, + 0xf9, 0xe1, 0xd9, 0x05, 0x27, 0xd3, 0x46, 0x22, 0x0a, 0x05, 0x39, 0xe0, 0x0c, + 0x2f, 0xdb, 0xfd, 0xfe, 0x13, 0xcf, 0xb3, 0xc1, 0x0c, 0xe3, 0x08, 0xde, 0xe5, + 0x24, 0xe7, 0xd3, 0x34, 0xfa, 0x0b, 0x10, 0x33, 0xe3, 0xd9, 0x01, 0x09, 0x14, + 0xed, 0x21, 0xdc, 0xf4, 0xc0, 0x1f, 0x54, 0xcc, 0x2b, 0x15, 0xf3, 0xf4, 0xc1, + 0x12, 0x14, 0xfd, 0xe0, 0xee, 0x08, 0x0c, 0xdc, 0xdf, 0xe0, 0x03, 0x04, 0x0e, + 0xe9, 0xd7, 0xfd, 0xfc, 0xee, 0x00, 0xf3, 0xfc, 0xfb, 0xf6, 0x07, 0xee, 0x16, + 0xf4, 0xfa, 0xfc, 0xff, 0xf2, 0xda, 0x03, 0x03, 0x05, 0xdf, 0xfa, 0xef, 0x66, + 0x26, 0xb2, 0x14, 0x0a, 0x13, 0x05, 0xff, 0x0b, 0x3e, 0x19, 0x1a, 0x13, 0x0f, + 0x4a, 0x18, 0x0d, 0x33, 0x0e, 0x04, 0x01, 0x42, 0x3b, 0x35, 0x1d, 0xeb, 0x18, + 0x16, 0x1f, 0x0d, 0x0b, 0x36, 0x16, 0x21, 0x15, 0x19, 0xcd, 0x13, 0x23, 0xf8, + 0x14, 0x02, 0x19, 0x3e, 0x1e, 0x10, 0x2a, 0x0d, 0x41, 0xfa, 0x0c, 0x00, 0x07, + 0x21, 0x19, 0x2f, 0x18, 0x04, 0x24, 0xf4, 0x06, 0x11, 0x1e, 0x02, 0x25, 0x3b, + 0x16, 0x08, 0x0c, 0xfc, 0xd6, 0x07, 0xe8, 0x1e, 0xea, 0x08, 0x10, 0xf6, 0x10, + 0x7f, 0x1a, 0x01, 0x1b, 0x2f, 0xf9, 0x26, 0xf6, 0x13, 0xe7, 0xe6, 0xef, 0x33, + 0xfa, 0x22, 0xe3, 0x19, 0xf9, 0x14, 0x20, 0x11, 0x24, 0xee, 0xf9, 0xfa, 0xeb, + 0xec, 0xf6, 0xf8, 0x23, 0xdc, 0x05, 0x15, 0x0c, 0xf3, 0xfd, 0xde, 0x3c, 0xfb, + 0xe0, 0xf3, 0x2c, 0x1e, 0x08, 0xf7, 0x0e, 0xe9, 0xeb, 0x06, 0x3c, 0x11, 0xf3, + 0x39, 0xf7, 0xf2, 0x16, 0xe8, 0xdc, 0xe5, 0x18, 0x3b, 0xbc, 0x07, 0x24, 0x06, + 0xed, 0xe6, 0xcb, 0x12, 0x06, 0xef, 0x25, 0x1e, 0x0b, 0x1f, 0xb3, 0x08, 0x50, + 0x1b, 0x14, 0x02, 0x1e, 0x11, 0x8b, 0x13, 0xf2, 0x18, 0xbe, 0xba, 0xda, 0x20, + 0x3f, 0xdc, 0x38, 0xe7, 0xea, 0x2a, 0x69, 0xd3, 0x26, 0x07, 0x11, 0x04, 0xd2, + 0x10, 0xdd, 0xe8, 0x3c, 0x0c, 0x0c, 0xec, 0xe7, 0x19, 0x02, 0xbe, 0xbc, 0xf8, + 0xed, 0xe7, 0xfd, 0xf4, 0xdb, 0x33, 0x18, 0x00, 0xda, 0xd6, 0x7f, 0x3c, 0x17, + 0xb1, 0xcb, 0x67, 0x2f, 0xc0, 0x28, 0x48, 0xaf, 0xe2, 0x1e, 0xf7, 0xe7, 0xdd, + 0x1f, 0xdf, 0x27, 0x09, 0x09, 0xf8, 0xd0, 0x3e, 0x19, 0x32, 0x13, 0xd5, 0xe7, + 0xdb, 0x1b, 0x28, 0x95, 0x17, 0xf1, 0xcf, 0xb5, 0x20, 0x00, 0xf5, 0xf6, 0xd3, + 0x3f, 0xdc, 0xe1, 0x0d, 0xfb, 0x32, 0xe0, 0x09, 0x1e, 0xe2, 0x31, 0xdd, 0x02, + 0x1c, 0xc7, 0x0b, 0xf2, 0xdb, 0x48, 0xf4, 0x20, 0xf0, 0x14, 0x3a, 0x1b, 0xcd, + 0xd4, 0xf5, 0xf0, 0xc1, 0x81, 0xef, 0xf1, 0xd8, 0xf3, 0xac, 0xce, 0x01, 0xa9, + 0x39, 0x24, 0xea, 0xe0, 0x13, 0xf1, 0x3d, 0xc0, 0xe2, 0xd8, 0xce, 0x2d, 0x21, + 0xe9, 0xde, 0xc0, 0x70, 0xd3, 0xd8, 0x03, 0xf6, 0xc2, 0x24, 0x04, 0xd1, 0x07, + 0x1b, 0x06, 0xfb, 0x06, 0xfb, 0x15, 0xb9, 0x1d, 0xd4, 0xd3, 0xce, 0x0a, 0x0e, + 0x0b, 0x35, 0xc5, 0x1a, 0x11, 0xd7, 0xf4, 0xfd, 0xfe, 0xe1, 0xec, 0x2b, 0x26, + 0xac, 0x76, 0x25, 0x40, 0xe4, 0x03, 0xa9, 0xb6, 0xf6, 0xf1, 0x07, 0x2e, 0x1f, + 0xf2, 0xf7, 0x28, 0x07, 0xf2, 0x37, 0xd6, 0xef, 0xf2, 0x21, 0xe8, 0xe9, 0xed, + 0x3e, 0xfb, 0x2b, 0x01, 0xf2, 0x06, 0xe3, 0xb2, 0xed, 0x08, 0xe1, 0xee, 0xd8, + 0x0d, 0xe8, 0xd9, 0x17, 0x3c, 0xfd, 0xd4, 0xb2, 0x24, 0x27, 0x18, 0x18, 0xf6, + 0xdf, 0xf4, 0xd9, 0xf7, 0xfa, 0x18, 0x66, 0x13, 0x22, 0xf9, 0xd8, 0xcc, 0x3b, + 0x22, 0xc8, 0x03, 0xe1, 0x71, 0x4a, 0x09, 0xf5, 0x12, 0x03, 0x0d, 0x26, 0x0d, + 0xea, 0xf5, 0xcc, 0xe4, 0xf4, 0x22, 0xab, 0x08, 0x1b, 0x5d, 0xbf, 0x6b, 0xe4, + 0xfb, 0x21, 0xde, 0xe2, 0x53, 0x24, 0x33, 0x06, 0x11, 0xc8, 0x0c, 0x0f, 0x12, + 0x05, 0xfd, 0xe3, 0xf5, 0x1e, 0xdd, 0x41, 0x07, 0xd0, 0xe1, 0xcd, 0xbf, 0x17, + 0x24, 0x2e, 0xe8, 0x20, 0x08, 0x01, 0xb9, 0x4b, 0xd1, 0x2e, 0xf8, 0xf5, 0x2a, + 0xf6, 0xfd, 0x1d, 0x10, 0xc0, 0xd9, 0xda, 0x1d, 0x2d, 0x18, 0x28, 0xfb, 0x5d, + 0x32, 0xbc, 0xf7, 0x41, 0x03, 0xe6, 0xdc, 0x3a, 0x1d, 0x14, 0xb2, 0x04, 0x7f, + 0xec, 0xf1, 0x26, 0xea, 0x2b, 0xe4, 0xed, 0x13, 0x0e, 0xe0, 0x04, 0x08, 0x0a, + 0x1a, 0xf7, 0xf4, 0x2c, 0xcc, 0x27, 0x3c, 0xe8, 0x37, 0xbb, 0x2f, 0x35, 0x18, + 0x32, 0x11, 0x41, 0xa4, 0xe4, 0xff, 0xeb, 0xea, 0xfc, 0xde, 0x00, 0xda, 0xc1, + 0x4a, 0xd4, 0xd7, 0xc4, 0x33, 0xcf, 0x27, 0x20, 0xcb, 0x34, 0x06, 0x08, 0xca, + 0xcb, 0x47, 0xdc, 0xea, 0x28, 0xd0, 0xdd, 0xe1, 0x24, 0xd6, 0x04, 0xbf, 0x0a, + 0x30, 0x23, 0x00, 0xdb, 0x14, 0xf9, 0xf3, 0xf3, 0x52, 0xdd, 0xd5, 0xc7, 0xa9, + 0x19, 0xc8, 0xff, 0x19, 0x20, 0xdc, 0x43, 0xf4, 0xd2, 0x0b, 0xcf, 0x20, 0xd0, + 0x22, 0x3b, 0x17, 0x31, 0xa6, 0x7f, 0xe0, 0x57, 0x08, 0x61, 0x1a, 0x25, 0xe7, + 0x27, 0x27, 0x20, 0x0d, 0xc0, 0x0e, 0xe2, 0x2e, 0xf0, 0x06, 0xf1, 0x0f, 0xe5, + 0x09, 0x11, 0xd9, 0xdd, 0x25, 0x96, 0x27, 0xde, 0x03, 0x1f, 0xff, 0x1d, 0xfa, + 0xe6, 0x02, 0x35, 0xf9, 0xfa, 0x43, 0x29, 0x33, 0xf8, 0xf1, 0xc1, 0x3e, 0xe6, + 0x26, 0x2a, 0x1b, 0xd4, 0x1c, 0x2d, 0x00, 0x8f, 0xe5, 0xdb, 0x14, 0xfc, 0x96, + 0x41, 0xf7, 0x04, 0x16, 0x1a, 0xc3, 0xfb, 0xec, 0x4b, 0x01, 0xa3, 0x07, 0xe3, + 0xca, 0x15, 0xa4, 0x2f, 0x01, 0x25, 0x7f, 0xee, 0xe6, 0x21, 0x53, 0xde, 0x35, + 0x01, 0x08, 0x13, 0x05, 0xd2, 0x3f, 0xd5, 0xf8, 0x2b, 0x18, 0xaf, 0xe5, 0xd0, + 0xfc, 0x66, 0xf2, 0xd8, 0xfc, 0x14, 0xbf, 0x0c, 0xe6, 0x53, 0x17, 0x26, 0x24, + 0x46, 0x2b, 0xe5, 0x14, 0xf5, 0xde, 0x1a, 0xdf, 0xe2, 0xf9, 0x46, 0x22, 0x02, + 0xf2, 0xc7, 0xa6, 0xcb, 0xbc, 0xf9, 0xe9, 0x4c, 0xc6, 0x33, 0xe7, 0xab, 0xd8, + 0x07, 0x09, 0x4f, 0x0c, 0x1e, 0xe6, 0xd2, 0x2c, 0xca, 0xf1, 0x41, 0xca, 0xf8, + 0x17, 0xf6, 0x31, 0x34, 0x01, 0xdd, 0x2a, 0xed, 0xf1, 0xb9, 0xe1, 0xfe, 0x26, + 0x42, 0x2d, 0x1b, 0x3f, 0xf7, 0x14, 0xec, 0x08, 0xf1, 0xea, 0x12, 0xcc, 0xd3, + 0x24, 0xf9, 0xc0, 0xe0, 0xea, 0xfb, 0x26, 0xfb, 0x1c, 0x20, 0x1b, 0xc4, 0x37, + 0xfc, 0x1e, 0x15, 0xfb, 0x09, 0x2d, 0x14, 0x0d, 0x3d, 0x1e, 0x03, 0xf2, 0xf2, + 0xd4, 0xf4, 0x35, 0xf7, 0x0f, 0xf2, 0xe7, 0x35, 0x21, 0xf2, 0xc6, 0x0a, 0x31, + 0xee, 0xf4, 0x2d, 0x0a, 0x14, 0x15, 0x0a, 0x1d, 0x01, 0x14, 0xf6, 0xfb, 0x2a, + 0x2e, 0x3d, 0x30, 0x03, 0x0c, 0x2a, 0x2d, 0x04, 0xf0, 0x1e, 0x0f, 0xee, 0x05, + 0x3e, 0xe5, 0x4d, 0xfe, 0xe1, 0xea, 0x2c, 0x47, 0xe8, 0x4d, 0x7f, 0xd4, 0x2d, + 0xae, 0xe6, 0x00, 0x0a, 0x28, 0xf2, 0xe9, 0x34, 0x0b, 0xd8, 0x59, 0x2b, 0xfe, + 0x23, 0x14, 0x3c, 0x01, 0x28, 0xe2, 0xfd, 0x0c, 0x21, 0xef, 0x21, 0xc3, 0x35, + 0x2e, 0x32, 0xe5, 0x0d, 0xf7, 0xf2, 0x3c, 0xfd, 0x68, 0xc8, 0x23, 0x19, 0x73, + 0x06, 0xe2, 0x23, 0x24, 0x2f, 0xf2, 0xff, 0x1d, 0x0b, 0x24, 0x31, 0x1b, 0x1a, + 0x14, 0x07, 0xe8, 0xeb, 0x34, 0x00, 0xf7, 0x2b, 0xea, 0x12, 0x35, 0x58, 0xc8, + 0xfe, 0xf5, 0x24, 0xfa, 0x23, 0x15, 0x0d, 0xde, 0xfe, 0x52, 0xf5, 0xfd, 0x21, + 0x32, 0x11, 0x18, 0xd2, 0x0b, 0x0d, 0x3a, 0xd2, 0xba, 0xb1, 0x04, 0xe7, 0x02, + 0x29, 0x64, 0xa5, 0x2d, 0x4e, 0x0f, 0x99, 0xfe, 0x0f, 0xc2, 0x00, 0xdd, 0xec, + 0xf6, 0xab, 0x15, 0x0a, 0xd1, 0xe3, 0x4d, 0xe5, 0xda, 0x16, 0x0c, 0x12, 0xe9, + 0x93, 0x29, 0xe4, 0xf1, 0x09, 0x55, 0xfb, 0xe3, 0x07, 0x10, 0xea, 0xcf, 0x28, + 0xde, 0x00, 0x41, 0xeb, 0x26, 0xd4, 0xcb, 0xfc, 0x35, 0xe7, 0xb8, 0xce, 0xeb, + 0xd0, 0xf8, 0x01, 0x00, 0x07, 0xfe, 0xc4, 0xea, 0x39, 0x07, 0x21, 0x28, 0x24, + 0x0d, 0xe9, 0xb9, 0xfc, 0x23, 0x0e, 0xe2, 0x5f, 0x11, 0x21, 0xc7, 0xee, 0xcd, + 0x36, 0x03, 0xf9, 0xe7, 0xf5, 0xee, 0xec, 0xf9, 0x7f, 0xcf, 0xfc, 0xed, 0xff, + 0xea, 0x0a, 0xd9, 0x01, 0x28, 0xda, 0xff, 0x0a, 0xff, 0xdc, 0xcf, 0x2e, 0x03, + 0x40, 0x01, 0x1c, 0x16, 0xdb, 0xd8, 0xe1, 0x1a, 0x23, 0x1d, 0xf0, 0xf3, 0xe3, + 0x7f, 0x33, 0xea, 0xed, 0xfd, 0x05, 0x2f, 0xe7, 0x09, 0x09, 0xf1, 0xe0, 0x1c, + 0xf7, 0x27, 0xf3, 0xb3, 0x70, 0xd2, 0xee, 0x1c, 0x4b, 0xdd, 0x3d, 0x05, 0xd0, + 0xf1, 0xe6, 0xe2, 0x0c, 0x03, 0xd3, 0xe7, 0x09, 0x17, 0xfd, 0x0f, 0x22, 0x07, + 0x22, 0xbf, 0x40, 0x0d, 0xe7, 0x3b, 0x39, 0x1d, 0xf8, 0xc5, 0xcd, 0xb0, 0xf6, + 0x30, 0xc2, 0x12, 0x2d, 0xf7, 0xd8, 0xf9, 0xd8, 0xdc, 0x01, 0xee, 0xd4, 0xd7, + 0xdc, 0xff, 0xe8, 0x05, 0xf2, 0xe1, 0x0a, 0xf4, 0x64, 0x1f, 0xf1, 0xf3, 0xd4, + 0x2a, 0xda, 0x29, 0xde, 0x04, 0x40, 0x15, 0x0b, 0x2a, 0xf8, 0xea, 0x02, 0x9a, + 0xf6, 0x22, 0x01, 0x12, 0xc4, 0x1d, 0x2d, 0x41, 0x1c, 0xcd, 0x77, 0xaf, 0xeb, + 0xee, 0xf0, 0x04, 0xf5, 0x20, 0x35, 0x12, 0xe8, 0x7f, 0xf6, 0x1e, 0xc4, 0xca, + 0x1e, 0x15, 0x4c, 0xd1, 0xf2, 0xea, 0x73, 0x00, 0xe7, 0xfd, 0x07, 0x1b, 0xea, + 0xb2, 0xdf, 0xf9, 0x0d, 0xd6, 0x3e, 0xa3, 0xc8, 0x0b, 0x20, 0xe7, 0xfa, 0xf7, + 0x0a, 0x22, 0x69, 0xc4, 0xc7, 0xd2, 0x22, 0xc0, 0xcc, 0x29, 0xad, 0xef, 0xe7, + 0x35, 0x27, 0x3b, 0x1a, 0x07, 0xd2, 0x0d, 0xd3, 0xc9, 0x1d, 0x31, 0x02, 0x0d, + 0x22, 0x31, 0x06, 0xfd, 0x14, 0x2c, 0x0c, 0x20, 0x93, 0xf0, 0xaa, 0xe8, 0xfb, + 0x01, 0x07, 0x2a, 0x1c, 0x1a, 0x06, 0xec, 0xff, 0xe5, 0x4a, 0x14, 0xba, 0x08, + 0xbd, 0x79, 0xd2, 0xf9, 0x0a, 0x24, 0x14, 0x12, 0xe1, 0xa9, 0x24, 0xc9, 0xdc, + 0xe3, 0x27, 0x28, 0x20, 0x18, 0x34, 0x25, 0x27, 0xb7, 0x93, 0x12, 0xf7, 0x06, + 0x15, 0xf0, 0x20, 0x30, 0x00, 0xf2, 0x6c, 0xd9, 0xfd, 0x14, 0x3c, 0x03, 0xf6, + 0x09, 0xe3, 0xfc, 0xe5, 0xd3, 0x02, 0xde, 0xc4, 0xe3, 0xe2, 0x2b, 0x27, 0x38, + 0xe1, 0xe8, 0x16, 0x26, 0xd8, 0xd0, 0xdf, 0xcd, 0xc9, 0x1e, 0xc4, 0x33, 0xf8, + 0x58, 0xd4, 0x2e, 0x2e, 0xfd, 0xd2, 0x02, 0x41, 0xd6, 0x09, 0xf0, 0x0c, 0x5e, + 0xf0, 0xf4, 0xed, 0xea, 0xf8, 0x41, 0x09, 0xe6, 0xd0, 0xfe, 0xf4, 0xda, 0x32, + 0xda, 0x3d, 0xe6, 0xfc, 0x36, 0x37, 0xea, 0x12, 0xf7, 0x0b, 0x33, 0x08, 0x1b, + 0x01, 0x2a, 0xe1, 0xda, 0xf5, 0x1d, 0x11, 0x11, 0xfe, 0xff, 0xef, 0xcf, 0x3d, + 0x7f, 0xe3, 0xf1, 0xdc, 0x06, 0xe0, 0x1d, 0xe2, 0x09, 0x23, 0x18, 0xf0, 0x2e, + 0x0e, 0xfb, 0xfd, 0x0b, 0x29, 0xf1, 0xf2, 0x18, 0xf2, 0x09, 0xf3, 0x09, 0x20, + 0x3f, 0xd2, 0xce, 0x29, 0x54, 0xe3, 0x31, 0xd2, 0x1a, 0x1d, 0x0b, 0x17, 0x0e, + 0xd2, 0xe9, 0x08, 0x39, 0x16, 0xde, 0x09, 0x1d, 0x22, 0x0c, 0xd0, 0x17, 0xf1, + 0xea, 0x19, 0x3d, 0x60, 0x16, 0x45, 0x23, 0x0b, 0xc9, 0xce, 0xdc, 0xce, 0xf7, + 0x1b, 0xe4, 0x15, 0xf3, 0x02, 0x11, 0x04, 0x5b, 0x2a, 0x0d, 0x52, 0x55, 0xf4, + 0xc4, 0x26, 0x07, 0xef, 0x2d, 0x7a, 0x0b, 0x31, 0x6f, 0x15, 0xf3, 0xf0, 0x38, + 0x28, 0xfa, 0x26, 0xd3, 0x08, 0xf0, 0xe1, 0x02, 0xe5, 0x23, 0x0e, 0xfc, 0xdf, + 0xfa, 0x23, 0xff, 0x7e, 0x04, 0x2c, 0x08, 0xe8, 0xe9, 0x11, 0x51, 0x61, 0x1e, + 0x24, 0x21, 0x57, 0xcf, 0x29, 0xfc, 0x1c, 0xdb, 0x23, 0x3f, 0x25, 0xf5, 0x07, + 0xfd, 0xf7, 0xeb, 0x0e, 0xf8, 0x0e, 0x20, 0xe9, 0xf6, 0x04, 0x25, 0xe5, 0x1a, + 0xe8, 0x23, 0x60, 0xe6, 0x32, 0xf0, 0xec, 0xf8, 0xec, 0x7f, 0x00, 0x20, 0x6b, + 0xd7, 0xf6, 0x6f, 0x10, 0x05, 0x3d, 0xec, 0xf0, 0x24, 0x21, 0xdb, 0xe0, 0xcd, + 0x38, 0x15, 0x31, 0x46, 0xd3, 0xf4, 0x0f, 0x12, 0x00, 0x1e, 0x12, 0x17, 0xdd, + 0xfa, 0x10, 0xf0, 0xfb, 0x28, 0xda, 0x1b, 0xfb, 0x27, 0x01, 0x04, 0xe4, 0xcc, + 0xec, 0x0b, 0x18, 0x26, 0xe0, 0x48, 0xe5, 0xcd, 0x16, 0x12, 0x0c, 0x24, 0xea, + 0x1a, 0xee, 0x25, 0x38, 0x1a, 0x0e, 0x29, 0x0c, 0x26, 0x02, 0x28, 0xf4, 0x06, + 0x3a, 0x11, 0xf4, 0xfb, 0x00, 0x08, 0x02, 0x15, 0xe4, 0xf0, 0xf9, 0x0b, 0xfc, + 0x36, 0x33, 0x0f, 0x04, 0xf9, 0x20, 0x19, 0x01, 0x5a, 0x10, 0x25, 0x43, 0x11, + 0x08, 0xe3, 0x22, 0x2e, 0xf2, 0x26, 0xfc, 0xd6, 0x34, 0x16, 0x00, 0x2e, 0x19, + 0xdb, 0x01, 0x21, 0xf1, 0xdf, 0x1d, 0x16, 0xfa, 0x26, 0xce, 0xe9, 0xe3, 0xd6, + 0x22, 0x35, 0x06, 0xf4, 0x1d, 0x06, 0x2c, 0xfd, 0x1e, 0x52, 0x0e, 0x0f, 0x19, + 0x7f, 0xfc, 0xe5, 0x07, 0x20, 0xe3, 0x22, 0x01, 0x03, 0x1c, 0x0a, 0x2a, 0x0d, + 0x32, 0x26, 0x01, 0xdd, 0xf1, 0xb2, 0xfb, 0x05, 0xc6, 0xf4, 0xc9, 0x03, 0x0c, + 0xf5, 0xf0, 0xdc, 0xf2, 0xf6, 0xef, 0x0d, 0xb7, 0xf0, 0x11, 0xc2, 0x36, 0xd2, + 0x15, 0xd9, 0xd2, 0x7f, 0xdf, 0xd2, 0x1d, 0xec, 0x18, 0x01, 0xc3, 0x0a, 0xfe, + 0xfc, 0xda, 0x17, 0x37, 0xeb, 0x56, 0xd7, 0x0f, 0xa8, 0xfb, 0xb4, 0x35, 0xde, + 0x38, 0x2a, 0xa3, 0xf1, 0xd7, 0xe5, 0x2b, 0x0b, 0x02, 0xcd, 0x2a, 0x42, 0xd5, + 0xf0, 0xed, 0xfc, 0x10, 0x2c, 0x0f, 0x0a, 0x18, 0xe0, 0x45, 0x27, 0xde, 0xfd, + 0xe6, 0xdf, 0xf1, 0xfd, 0xea, 0xaf, 0x26, 0xfe, 0x0f, 0x09, 0x4c, 0xbc, 0x33, + 0x0f, 0xf6, 0x13, 0xec, 0x2e, 0xf3, 0xf8, 0xe7, 0xf9, 0xea, 0x04, 0x42, 0x10, + 0x09, 0xdf, 0xdf, 0xfe, 0xfb, 0xac, 0xe9, 0xb3, 0xc9, 0x18, 0xe9, 0x07, 0xf4, + 0xdd, 0xeb, 0x0a, 0xf3, 0x1f, 0xde, 0xad, 0xf5, 0x19, 0x60, 0x1a, 0xdc, 0xb6, + 0xe1, 0x14, 0xf2, 0xba, 0x3c, 0x0c, 0x20, 0x0f, 0x38, 0xe5, 0xe5, 0xe9, 0x34, + 0xfa, 0xbf, 0x48, 0xa3, 0xc3, 0x0a, 0x28, 0x13, 0xfe, 0x17, 0xf6, 0x3a, 0x59, + 0x34, 0xf1, 0x0a, 0x1e, 0xe8, 0x9d, 0xf8, 0x1c, 0xdb, 0xdb, 0x50, 0xc6, 0xdd, + 0x31, 0xcc, 0xc4, 0x0d, 0xb1, 0xb3, 0x48, 0x1b, 0x35, 0xca, 0x30, 0xce, 0xd1, + 0x81, 0x64, 0x95, 0x4f, 0x31, 0xd1, 0xe5, 0xe1, 0xf2, 0x05, 0xda, 0xc1, 0x20, + 0xf6, 0xa4, 0x02, 0x12, 0xe5, 0xa1, 0xd0, 0xf6, 0x2f, 0x23, 0xdc, 0x28, 0x35, + 0x4c, 0x28, 0xe0, 0x05, 0x07, 0xc7, 0x18, 0xc3, 0x01, 0xc4, 0xf3, 0xdc, 0xec, + 0x2d, 0x02, 0x12, 0x0e, 0x18, 0xe0, 0x08, 0xe1, 0x0b, 0xcf, 0x0d, 0xe1, 0xb5, + 0x34, 0xbb, 0xf3, 0x07, 0x2f, 0x11, 0xfc, 0xfc, 0x42, 0xf2, 0x15, 0x3a, 0x55, + 0xf2, 0xf2, 0xd9, 0xfb, 0xcc, 0xdc, 0x35, 0x13, 0x11, 0x0a, 0x03, 0xe9, 0xf7, + 0xf9, 0x5c, 0xe3, 0xee, 0xd4, 0x19, 0x34, 0xec, 0x49, 0x16, 0x29, 0x0e, 0xd7, + 0xe0, 0xcf, 0xef, 0x21, 0xfc, 0xf2, 0x11, 0x0c, 0xf5, 0x14, 0x1b, 0x17, 0xbd, + 0x08, 0x2c, 0xfa, 0xf3, 0x41, 0xc2, 0x00, 0xef, 0xd7, 0x25, 0xf6, 0x03, 0x00, + 0xd6, 0x10, 0xfc, 0x59, 0x08, 0xeb, 0x32, 0xbf, 0x1a, 0xb9, 0x22, 0x40, 0x2f, + 0x6a, 0x1f, 0xff, 0x11, 0xf8, 0xe9, 0xf0, 0xd9, 0xcd, 0x00, 0xdd, 0xe1, 0xcd, + 0x58, 0x06, 0xd2, 0xf2, 0xa8, 0xf3, 0x06, 0x21, 0x18, 0x1a, 0x06, 0x14, 0xe0, + 0xf5, 0x2c, 0x1f, 0x24, 0x0f, 0xc5, 0xf9, 0x05, 0x28, 0xcd, 0x06, 0xe0, 0xc3, + 0x22, 0x16, 0x16, 0x0f, 0x32, 0x2d, 0xfe, 0x1a, 0xf8, 0xf7, 0x29, 0x28, 0xd7, + 0x19, 0xeb, 0x4b, 0xe6, 0x07, 0x19, 0xd9, 0xf6, 0x05, 0x03, 0x08, 0xc3, 0xea, + 0xfb, 0x2d, 0xb6, 0xe8, 0x02, 0x31, 0xcd, 0xdf, 0x7f, 0xf3, 0xfc, 0x17, 0x04, + 0x12, 0x3c, 0xf3, 0x6b, 0x05, 0x02, 0xeb, 0x4a, 0xf8, 0x33, 0xe8, 0x23, 0x3b, + 0x07, 0x35, 0x4a, 0xf3, 0x81, 0xf7, 0x21, 0x0e, 0x49, 0x1b, 0x05, 0x30, 0xb7, + 0x37, 0x21, 0xf1, 0xee, 0x16, 0x2b, 0x10, 0x0c, 0x0c, 0xdc, 0x30, 0x02, 0xe9, + 0x29, 0xcc, 0x2d, 0xea, 0xfd, 0x21, 0x02, 0x15, 0x2a, 0x10, 0xff, 0xf4, 0x0b, + 0x10, 0xf8, 0x21, 0x35, 0xfc, 0x0c, 0xef, 0xed, 0x18, 0xfb, 0x02, 0x22, 0x02, + 0x2e, 0xda, 0x35, 0x00, 0x11, 0xe1, 0x26, 0x09, 0x4b, 0x12, 0x00, 0x03, 0x13, + 0x1d, 0x2c, 0x25, 0x36, 0xf5, 0x0f, 0xf6, 0xfe, 0x05, 0x0e, 0x31, 0x06, 0xe4, + 0x0f, 0xe9, 0x2a, 0x1e, 0x09, 0x35, 0x07, 0xfb, 0xd1, 0xd3, 0x04, 0x2a, 0xfc, + 0xfc, 0x28, 0xfd, 0x20, 0x34, 0x27, 0x03, 0xef, 0x1e, 0x2b, 0x0c, 0xfc, 0x13, + 0x2f, 0xdc, 0xfc, 0x0a, 0xe0, 0x1b, 0x6d, 0x08, 0xfe, 0x35, 0xd3, 0xec, 0xd8, + 0xf2, 0xd7, 0x07, 0x1e, 0xd5, 0x06, 0xf4, 0xe8, 0xec, 0x0e, 0xf9, 0xdc, 0xec, + 0x0c, 0xf8, 0xfc, 0x64, 0x2c, 0xd0, 0xf8, 0x1a, 0x2b, 0xcf, 0xaf, 0x1d, 0x3c, + 0x04, 0x22, 0x0b, 0x2a, 0xe4, 0x3d, 0x09, 0xf8, 0xcf, 0xde, 0xf9, 0xb8, 0xae, + 0xc9, 0xea, 0xd7, 0xd4, 0x1a, 0xec, 0x40, 0x20, 0xe4, 0xdc, 0x22, 0xda, 0x0a, + 0xe4, 0x5b, 0xaf, 0xd6, 0xf2, 0x1f, 0x1a, 0x1a, 0x04, 0xf0, 0xf2, 0x0f, 0x1f, + 0xfe, 0x22, 0x4d, 0xea, 0xcb, 0xec, 0xfe, 0xef, 0x3a, 0xf2, 0x2c, 0x26, 0xd5, + 0xfc, 0x7f, 0x79, 0xd4, 0xb3, 0xf9, 0x0b, 0x05, 0x32, 0xdf, 0xd5, 0xce, 0xbe, + 0x12, 0xe1, 0xfc, 0xfe, 0xf2, 0xe8, 0x2f, 0x24, 0xfa, 0xf3, 0xfd, 0x1a, 0xc8, + 0xfe, 0xea, 0x18, 0x09, 0x12, 0xca, 0xe7, 0x62, 0xf8, 0xe6, 0xfc, 0xf6, 0xce, + 0xe6, 0x16, 0xf4, 0x7b, 0x20, 0x08, 0xf4, 0xf3, 0xf3, 0xdf, 0xfa, 0xfa, 0x22, + 0x01, 0x30, 0x42, 0x2d, 0x0f, 0x3c, 0xe7, 0xdf, 0x1b, 0xfb, 0xe7, 0x05, 0x2b, + 0xd2, 0xe2, 0x07, 0xd2, 0x0b, 0x0d, 0x16, 0x3f, 0x9a, 0x14, 0x0b, 0xf6, 0xd4, + 0xfa, 0xfc, 0xc8, 0x47, 0x1f, 0xe1, 0x7f, 0x3e, 0xd5, 0x02, 0xec, 0x19, 0xf6, + 0x23, 0x13, 0x1c, 0xf7, 0xea, 0xe9, 0x19, 0x1b, 0x57, 0xe0, 0xe8, 0x16, 0x2e, + 0x10, 0x0a, 0x1e, 0x24, 0x1d, 0x1f, 0x23, 0xe4, 0x26, 0x20, 0x2f, 0xf9, 0x3f, + 0xe2, 0xe2, 0xca, 0x2e, 0xfe, 0xfe, 0xfe, 0x07, 0xbb, 0x07, 0x0f, 0x01, 0xf9, + 0x62, 0xf0, 0x09, 0x19, 0xfd, 0xee, 0x16, 0xfa, 0x26, 0x28, 0x01, 0x24, 0x05, + 0x10, 0x4a, 0xeb, 0xf2, 0xf1, 0x02, 0x17, 0xfc, 0xf8, 0xfe, 0x05, 0xe7, 0xff, + 0x31, 0x32, 0x03, 0xfc, 0x01, 0xfb, 0xfb, 0x19, 0x15, 0x21, 0x03, 0x11, 0x57, + 0x22, 0xf5, 0xde, 0xe3, 0xc1, 0x35, 0x06, 0x25, 0x37, 0x27, 0xe9, 0x81, 0x19, + 0xfc, 0xed, 0x16, 0xee, 0xe4, 0xd2, 0x5b, 0x36, 0xbc, 0xe1, 0xf3, 0x42, 0x0d, + 0x10, 0xf5, 0xf3, 0xf6, 0x06, 0x3a, 0xfc, 0xe1, 0x0e, 0xc4, 0xfc, 0xf9, 0x49, + 0xc0, 0x24, 0x09, 0x0a, 0x35, 0xfb, 0xb7, 0x2d, 0x20, 0xd0, 0xc6, 0xe0, 0xfd, + 0xc2, 0x28, 0x04, 0x07, 0xc3, 0xd8, 0xfa, 0x07, 0x32, 0x25, 0xbd, 0x26, 0xda, + 0x13, 0x2c, 0x1f, 0x06, 0x2d, 0x12, 0x07, 0x2d, 0xea, 0x04, 0xef, 0xc5, 0xb2, + 0xed, 0x03, 0xaa, 0xd7, 0x14, 0xf0, 0xf5, 0x0f, 0xde, 0x00, 0x19, 0x3a, 0xf1, + 0x1b, 0x20, 0x16, 0xf5, 0xc4, 0xe5, 0xb3, 0xd3, 0xb0, 0xf3, 0xec, 0x10, 0x0f, + 0xd4, 0x14, 0x13, 0xea, 0x19, 0xe6, 0x0d, 0xef, 0xe5, 0xf1, 0x14, 0xfd, 0x31, + 0xeb, 0xce, 0xaa, 0xb7, 0x0e, 0x1f, 0x02, 0xfc, 0x21, 0xbd, 0xf6, 0xf3, 0x0a, + 0xfb, 0x1d, 0xdb, 0xb8, 0xef, 0xd2, 0x28, 0xee, 0x0f, 0x29, 0xf1, 0x14, 0x23, + 0x0e, 0xf7, 0x4b, 0x2b, 0xfa, 0x1f, 0x0b, 0x21, 0x01, 0x11, 0xfc, 0x14, 0x3a, + 0x60, 0x16, 0xe5, 0xf4, 0x19, 0x06, 0x14, 0x55, 0x5d, 0xd5, 0xf7, 0xfe, 0x11, + 0x6a, 0xe9, 0x2a, 0xe8, 0x36, 0x67, 0x04, 0x24, 0xef, 0x13, 0x39, 0xe7, 0xf7, + 0xf6, 0xea, 0xf3, 0xfc, 0xfd, 0xe6, 0xf9, 0xe0, 0x53, 0x1d, 0xf2, 0x13, 0x25, + 0x69, 0xf0, 0x3c, 0x10, 0x3a, 0xf2, 0xff, 0x40, 0x1c, 0x17, 0x08, 0x28, 0x3a, + 0x18, 0x00, 0x27, 0xd6, 0xbf, 0xff, 0xb3, 0x23, 0xd0, 0xd3, 0xdb, 0x12, 0xff, + 0xf0, 0xe8, 0x21, 0xe7, 0xcd, 0x33, 0xff, 0x20, 0x06, 0x03, 0xef, 0x25, 0x52, + 0x01, 0xcb, 0x4a, 0x05, 0x0f, 0xd4, 0x09, 0xec, 0xfc, 0x36, 0x33, 0x05, 0xfc, + 0xcc, 0x2e, 0xe4, 0xe3, 0xc5, 0x39, 0xd1, 0x40, 0x7f, 0x23, 0xd3, 0xc5, 0xdd, + 0x12, 0x3e, 0x2b, 0xe3, 0xef, 0x56, 0xaa, 0xc7, 0x24, 0x06, 0xe6, 0xc3, 0xed, + 0xb1, 0xb2, 0x4a, 0x50, 0xf1, 0x2c, 0xd1, 0xdf, 0xc9, 0xf0, 0xdf, 0xe6, 0x02, + 0x03, 0x08, 0xe3, 0xd0, 0x40, 0xf0, 0xd6, 0x2d, 0x0c, 0xcc, 0xde, 0x49, 0x4a, + 0xd7, 0x1d, 0x81, 0x39, 0xdd, 0xb3, 0x33, 0xdd, 0xde, 0xc8, 0xd6, 0xda, 0xfe, + 0xfd, 0xcd, 0x1b, 0x12, 0x34, 0xfa, 0xf6, 0x17, 0x13, 0x0c, 0xfe, 0xba, 0xe4, + 0x08, 0x47, 0xee, 0xf7, 0xf1, 0xe0, 0x16, 0x9e, 0x13, 0x68, 0x39, 0xb1, 0x07, + 0xb5, 0x0e, 0xda, 0xc7, 0xcb, 0x0e, 0x11, 0xfa, 0x6b, 0x10, 0xf5, 0xd9, 0xfc, + 0xcf, 0xea, 0x08, 0xf7, 0xe6, 0xf7, 0x4f, 0xde, 0x1f, 0x19, 0x0c, 0xb9, 0x2a, + 0xf9, 0x1e, 0xe4, 0xf6, 0xc1, 0xb8, 0xea, 0x32, 0xd1, 0xff, 0x14, 0xd4, 0x67, + 0x10, 0x06, 0xe3, 0xd8, 0x5c, 0x1b, 0xd5, 0x0b, 0x65, 0xf6, 0x3b, 0x24, 0xd8, + 0x1b, 0xfc, 0x0b, 0xed, 0xde, 0x71, 0xb2, 0x3b, 0x46, 0x1e, 0xfa, 0xe3, 0x10, + 0x15, 0xf0, 0x3e, 0xfb, 0xb8, 0xf4, 0x07, 0xcd, 0x4e, 0x5c, 0xed, 0xc7, 0x38, + 0x02, 0x55, 0xfd, 0xe5, 0xae, 0xcb, 0xd6, 0xfb, 0xac, 0x6f, 0xf7, 0xcd, 0x14, + 0xea, 0x16, 0x03, 0x25, 0x15, 0x3e, 0xe0, 0x20, 0x17, 0xa8, 0xe9, 0xf1, 0x26, + 0xe3, 0x0d, 0x27, 0x02, 0xb8, 0x3d, 0x4b, 0xd6, 0xdc, 0x02, 0xe0, 0xd4, 0xfb, + 0xd2, 0x3b, 0x51, 0xd5, 0x28, 0xdd, 0x1e, 0xc5, 0xb6, 0x72, 0xed, 0x0b, 0x3a, + 0xba, 0x0c, 0xd1, 0x02, 0xdf, 0xf1, 0x02, 0xe1, 0xe4, 0xe4, 0xe4, 0xf3, 0x26, + 0xf7, 0x40, 0x09, 0x05, 0xe4, 0x23, 0x19, 0xc1, 0xf3, 0xc4, 0x0f, 0xc6, 0x21, + 0x0f, 0x39, 0x4b, 0x17, 0xce, 0x5f, 0xfd, 0x12, 0x0d, 0xd2, 0x7f, 0xf6, 0xfd, + 0x2a, 0xe2, 0x17, 0xc2, 0x41, 0x0d, 0x29, 0xed, 0x10, 0x38, 0xf0, 0xf8, 0xd2, + 0x15, 0x1c, 0x39, 0x4e, 0xed, 0x0d, 0xaa, 0xd5, 0xe2, 0x17, 0x7f, 0xa5, 0x14, + 0xde, 0x3b, 0x69, 0x06, 0x0a, 0xfc, 0xff, 0x2e, 0x12, 0x39, 0x05, 0xee, 0x6f, + 0xee, 0x26, 0x06, 0xbb, 0x01, 0xf5, 0xaa, 0x3c, 0xe7, 0xb9, 0x1b, 0xe7, 0x90, + 0xd2, 0x41, 0x37, 0x0e, 0x38, 0xf2, 0x2e, 0x16, 0xdb, 0x0f, 0x03, 0xc2, 0x05, + 0x12, 0xe1, 0xe0, 0x25, 0x23, 0xd7, 0xd6, 0xef, 0xf8, 0xf7, 0xf9, 0xb6, 0x0a, + 0x2a, 0x0c, 0x05, 0xe9, 0xd9, 0xdf, 0x25, 0x08, 0x2a, 0x24, 0x30, 0xdb, 0x2e, + 0xf4, 0x2a, 0x0a, 0xd0, 0xc5, 0x32, 0xd8, 0xf3, 0xef, 0x11, 0xf1, 0x25, 0xc8, + 0x2d, 0x02, 0x1f, 0xca, 0x12, 0x1f, 0x14, 0xe9, 0x26, 0xec, 0x0e, 0x09, 0x06, + 0x07, 0xf3, 0x18, 0x24, 0x1d, 0xfc, 0x1c, 0xf8, 0xe5, 0xd1, 0xde, 0xea, 0xa5, + 0x14, 0x34, 0xd1, 0x6a, 0x1a, 0xbf, 0xfe, 0xdf, 0xe7, 0xda, 0xf4, 0xe9, 0x03, + 0x04, 0x81, 0x1f, 0xdd, 0xdb, 0xf5, 0x19, 0xbe, 0xdd, 0x0a, 0x1b, 0xfa, 0xee, + 0xde, 0xef, 0x04, 0x16, 0x1e, 0xe6, 0xf2, 0xc9, 0xaf, 0xf6, 0xe7, 0x43, 0xe7, + 0xfe, 0x3b, 0x1b, 0x0a, 0x10, 0xce, 0x00, 0xf8, 0xf8, 0xc6, 0x24, 0x21, 0xce, + 0xe0, 0x02, 0xb6, 0xd2, 0xe0, 0xe6, 0xe8, 0xfd, 0x24, 0x21, 0x14, 0xe5, 0xf4, + 0x07, 0xfb, 0xd6, 0xda, 0x10, 0xe9, 0x0e, 0x4c, 0x0a, 0xee, 0x19, 0x0d, 0x03, + 0xcf, 0xe9, 0x0b, 0x0d, 0xd4, 0xd9, 0x06, 0xc6, 0xd1, 0x08, 0xef, 0xc2, 0xe6, + 0x24, 0xf0, 0x4a, 0xfa, 0x0d, 0x0c, 0xf4, 0x13, 0x38, 0xf0, 0x27, 0x28, 0xfb, + 0xdb, 0x34, 0xf2, 0xc5, 0x14, 0x0e, 0xfd, 0x44, 0xef, 0x17, 0xfd, 0xf6, 0x0b, + 0xc8, 0xe2, 0x09, 0xf9, 0x22, 0xde, 0xd4, 0x10, 0x27, 0xdc, 0x05, 0xea, 0xc8, + 0x08, 0x01, 0xfc, 0xfa, 0xef, 0x23, 0x71, 0xd6, 0xda, 0x15, 0x08, 0xeb, 0x22, + 0xcb, 0xf3, 0xea, 0x4f, 0xff, 0xf5, 0x5d, 0xc5, 0xfa, 0x15, 0x5b, 0x0b, 0x03, + 0xbe, 0xfe, 0x38, 0xeb, 0x04, 0xb7, 0x2a, 0xe9, 0x7f, 0xe5, 0x1d, 0xda, 0xb0, + 0x0a, 0x20, 0xb8, 0x51, 0x00, 0xd7, 0xce, 0x3a, 0xe0, 0xab, 0xe7, 0xd5, 0xed, + 0xd6, 0xf4, 0xef, 0xda, 0xbe, 0xe6, 0xde, 0xb9, 0xe8, 0x6b, 0x21, 0xd1, 0x12, + 0x2f, 0x0e, 0xd1, 0xc1, 0x19, 0x15, 0xe1, 0xc9, 0xea, 0x40, 0xdc, 0xcd, 0x09, + 0x0a, 0x7f, 0xfb, 0xed, 0xa5, 0x00, 0xe2, 0xe2, 0xe5, 0x8a, 0xb3, 0xf8, 0x3c, + 0x17, 0xfc, 0x25, 0xe1, 0x10, 0x05, 0x14, 0xf5, 0xa2, 0x31, 0xed, 0xff, 0x06, + 0xd0, 0x10, 0x0f, 0xc3, 0x20, 0x07, 0x1c, 0x1d, 0x36, 0x00, 0xaf, 0x18, 0x4e, + 0xdd, 0xd3, 0x51, 0x1a, 0x09, 0x06, 0x12, 0xf1, 0xa5, 0xc9, 0xf6, 0xdf, 0xfa, + 0xfc, 0xe7, 0x11, 0x2c, 0x03, 0xe4, 0x1f, 0x05, 0x27, 0x28, 0xf6, 0x27, 0x35, + 0xf4, 0x3d, 0x2a, 0x1b, 0xea, 0x25, 0x49, 0xe5, 0xa6, 0x0c, 0xc2, 0xd6, 0xe1, + 0x22, 0x0f, 0x38, 0x59, 0xfb, 0xda, 0xdf, 0x28, 0xde, 0xec, 0xf6, 0xd0, 0x25, + 0x1d, 0x47, 0xf9, 0xed, 0x5f, 0xb0, 0x5c, 0xc0, 0xeb, 0x18, 0x2c, 0x10, 0x39, + 0x1f, 0x5a, 0xe8, 0xbf, 0x10, 0xf3, 0xf1, 0xf9, 0x02, 0x1c, 0x17, 0xf9, 0xfa, + 0xf8, 0x37, 0xe5, 0xfb, 0xfd, 0xcb, 0x77, 0xfd, 0x52, 0x41, 0x62, 0xac, 0xbb, + 0x2c, 0x21, 0x3d, 0xea, 0xd4, 0xb8, 0x12, 0x05, 0x03, 0xcc, 0xf9, 0x0a, 0xfc, + 0xc7, 0x1e, 0xea, 0x6b, 0xf5, 0x0c, 0xf9, 0xcc, 0x0e, 0xbf, 0xea, 0x2a, 0x31, + 0x26, 0xe8, 0xf9, 0x52, 0xee, 0x0c, 0xf0, 0x7f, 0x28, 0x4f, 0x14, 0x67, 0x07, + 0xb4, 0x52, 0x05, 0xda, 0x22, 0xf0, 0x05, 0x0c, 0x2b, 0x6c, 0x19, 0x07, 0x23, + 0x2c, 0xde, 0xed, 0x26, 0xdc, 0x40, 0x42, 0xbf, 0xc2, 0x05, 0x53, 0xe1, 0xf5, + 0x18, 0xb0, 0xaf, 0x30, 0x0b, 0xf9, 0xbe, 0x03, 0xeb, 0xf6, 0x01, 0xf9, 0x09, + 0x2a, 0x11, 0xd6, 0xae, 0x27, 0x47, 0x12, 0xdc, 0x40, 0xdd, 0x04, 0x2d, 0xe5, + 0xcb, 0xca, 0x73, 0xa3, 0x3a, 0x06, 0xd7, 0xde, 0x3b, 0xeb, 0xed, 0x0e, 0x40, + 0xf8, 0xdf, 0x09, 0x19, 0xd9, 0x52, 0xd9, 0x25, 0xfa, 0xd9, 0x00, 0x29, 0xfa, + 0x0f, 0x24, 0xdf, 0xee, 0x7f, 0xd2, 0x2e, 0x34, 0x1f, 0xf1, 0xea, 0xb6, 0xe7, + 0xd4, 0x1e, 0xd6, 0xd3, 0xd4, 0xb9, 0xa8, 0xea, 0xba, 0xd6, 0xa2, 0x31, 0x3f, + 0x10, 0xf2, 0x23, 0x13, 0x31, 0xda, 0x23, 0x0b, 0x16, 0x4c, 0xe6, 0x04, 0x03, + 0x22, 0xf2, 0x2f, 0x25, 0xbb, 0xe8, 0x15, 0xef, 0xed, 0x07, 0x2b, 0xb4, 0xfa, + 0xe4, 0x23, 0x18, 0x25, 0x03, 0x3b, 0xb3, 0x68, 0xf3, 0x4e, 0xe9, 0xed, 0xf0, + 0x4a, 0xfb, 0x10, 0x0a, 0x1d, 0x20, 0xef, 0x1f, 0x06, 0xfa, 0xe8, 0xf7, 0x1e, + 0xb6, 0xd3, 0x0e, 0x02, 0xf9, 0x19, 0x2c, 0x2b, 0x1e, 0x10, 0x62, 0xc8, 0xc7, + 0xe8, 0xd8, 0xb9, 0x0a, 0xf3, 0x10, 0x16, 0x07, 0x1a, 0x15, 0xf0, 0x15, 0x24, + 0x37, 0xdb, 0xfc, 0x1c, 0x30, 0x07, 0x14, 0xec, 0x26, 0xee, 0xd4, 0xea, 0xd8, + 0xf9, 0x0d, 0x2c, 0x04, 0x12, 0x33, 0xda, 0xe0, 0xff, 0x3f, 0x42, 0xec, 0xe3, + 0x25, 0xd9, 0xf1, 0x22, 0xc9, 0xe8, 0xf1, 0x27, 0x7f, 0x34, 0xa1, 0x0d, 0x25, + 0xfd, 0xd8, 0xce, 0xfe, 0xcd, 0x9e, 0xc8, 0x36, 0xa6, 0xc7, 0xf3, 0xd5, 0xc5, + 0x20, 0x36, 0xea, 0xa7, 0x2e, 0x27, 0x3a, 0x33, 0xdd, 0xa0, 0xd4, 0xf3, 0xff, + 0xfd, 0x16, 0x0a, 0xf8, 0xb2, 0x06, 0xf5, 0xcb, 0x2d, 0x20, 0x03, 0x31, 0x0a, + 0xe9, 0xde, 0x4c, 0x17, 0xf7, 0xe0, 0xe8, 0xe3, 0xb9, 0xf2, 0xe9, 0xd5, 0xf0, + 0xe5, 0xdc, 0x0c, 0xd6, 0xb2, 0xbc, 0x7f, 0x44, 0x79, 0xca, 0xc9, 0xa6, 0x2a, + 0x36, 0xd0, 0xc0, 0x19, 0x4d, 0xf0, 0xf9, 0x04, 0x43, 0xf9, 0xf2, 0xd8, 0x49, + 0x55, 0xd2, 0xeb, 0xb5, 0xf6, 0xda, 0x10, 0xd7, 0xfc, 0x41, 0xbf, 0x1f, 0x34, + 0xf7, 0xf3, 0x1e, 0xfb, 0xf8, 0xf7, 0xf0, 0x0c, 0xde, 0xe7, 0x6b, 0xe8, 0xf4, + 0xee, 0xf0, 0xd5, 0xfd, 0x0d, 0x44, 0xe5, 0xd8, 0xf1, 0xfe, 0x07, 0xd1, 0xd7, + 0x15, 0x01, 0xf1, 0x50, 0xfc, 0x27, 0xe5, 0x51, 0xcc, 0x4c, 0xd9, 0xf1, 0x0b, + 0xcf, 0x14, 0xf9, 0xd7, 0xf7, 0xe2, 0xe7, 0x15, 0x22, 0xf3, 0xd2, 0xed, 0xe1, + 0x0b, 0x1c, 0xc9, 0x07, 0x23, 0x0e, 0xce, 0xf1, 0x26, 0x0d, 0xc8, 0x09, 0x27, + 0xef, 0x06, 0x1c, 0xee, 0xc4, 0xe4, 0x4c, 0xf2, 0x2d, 0xf9, 0xdc, 0x23, 0x34, + 0x06, 0xf6, 0xf1, 0x3e, 0x0e, 0xea, 0xeb, 0x54, 0x00, 0x18, 0x12, 0x0c, 0xe9, + 0x14, 0x0f, 0xef, 0x09, 0x02, 0x37, 0xd2, 0xf3, 0xe1, 0x2e, 0x15, 0x08, 0xa6, + 0x0e, 0x23, 0xe3, 0xf7, 0x13, 0xf7, 0xf0, 0x21, 0x45, 0xd2, 0xf7, 0x03, 0x17, + 0x1a, 0x3d, 0xe6, 0x24, 0x42, 0xd4, 0x09, 0x2f, 0xfe, 0x2a, 0xd2, 0x11, 0x2a, + 0x2f, 0xdb, 0xe0, 0xbc, 0x12, 0xe1, 0xd7, 0x57, 0x04, 0x11, 0x07, 0x2d, 0x2a, + 0x37, 0xce, 0xd8, 0x3a, 0xf1, 0xb9, 0x1b, 0x13, 0xe8, 0xba, 0xe7, 0x7f, 0x01, + 0xe9, 0xf6, 0xd3, 0xb8, 0x3b, 0xbf, 0x12, 0x0c, 0xdb, 0x2f, 0xf2, 0xdf, 0xa3, + 0x0a, 0x5a, 0x7c, 0x21, 0xdf, 0x0d, 0xca, 0x4d, 0xdf, 0x13, 0xd9, 0xd0, 0x14, + 0xf8, 0x14, 0x0c, 0xe5, 0x24, 0xfb, 0xaa, 0xee, 0x8f, 0x0e, 0xe4, 0x06, 0x05, + 0xbf, 0x25, 0x65, 0x33, 0xd8, 0xf1, 0xfd, 0x65, 0x0e, 0xdf, 0x26, 0xd5, 0xf4, + 0xdd, 0x05, 0xd4, 0x15, 0x0e, 0x25, 0xf3, 0xed, 0xce, 0xdf, 0x19, 0x20, 0x38, + 0x13, 0xda, 0x05, 0x1a, 0x00, 0xdb, 0x21, 0x14, 0xff, 0xf9, 0x16, 0x1c, 0x04, + 0xec, 0x07, 0xe9, 0xe5, 0x1d, 0x14, 0xf6, 0xff, 0x35, 0x3b, 0x24, 0x25, 0xea, + 0xee, 0xee, 0x2b, 0xd1, 0x35, 0xff, 0x15, 0x1e, 0x0b, 0xef, 0xfe, 0x34, 0xf8, + 0xf6, 0xe9, 0x0c, 0x19, 0xe9, 0x11, 0x20, 0xdb, 0xaa, 0xda, 0xee, 0x05, 0xba, + 0x19, 0xe8, 0x22, 0xe4, 0xd4, 0xfa, 0x02, 0xe8, 0xf2, 0x5d, 0xe8, 0xd3, 0x12, + 0xf3, 0x0d, 0x0a, 0x2e, 0xe8, 0xd3, 0xc6, 0x64, 0xd2, 0xd8, 0xb5, 0xf1, 0x07, + 0xf3, 0xd8, 0xe7, 0xf5, 0x08, 0x12, 0x04, 0xe0, 0xee, 0xf6, 0x0c, 0xe5, 0xea, + 0x19, 0x21, 0xbe, 0x7f, 0x00, 0xef, 0xbf, 0x09, 0xcd, 0xdf, 0x16, 0x00, 0xd6, + 0x0d, 0xe8, 0x2e, 0xf1, 0xdc, 0x17, 0x18, 0xe4, 0xf4, 0xf5, 0xf3, 0x2e, 0x2f, + 0x16, 0xe2, 0xdd, 0x4d, 0x27, 0xf3, 0xba, 0xfe, 0x2d, 0x31, 0x03, 0xfb, 0xc6, + 0x3c, 0x19, 0x4b, 0xe3, 0xbc, 0x08, 0xeb, 0x26, 0xd1, 0x03, 0x3a, 0x01, 0xf1, + 0xe6, 0xb6, 0x37, 0x26, 0x14, 0x3c, 0x2a, 0x4a, 0xe1, 0xe2, 0x2a, 0xf1, 0xff, + 0x34, 0xb8, 0xf9, 0xe6, 0xba, 0x2a, 0xf9, 0x0a, 0xe4, 0x6f, 0xf0, 0x4b, 0xcc, + 0x1f, 0xd2, 0xd1, 0xc6, 0x5e, 0xba, 0xe9, 0xd6, 0xc3, 0xf7, 0xf1, 0xf4, 0x0c, + 0xe7, 0xc8, 0xce, 0xe7, 0x2b, 0xdc, 0xfa, 0xe9, 0xd3, 0xf2, 0x02, 0x2f, 0x11, + 0x2a, 0x51, 0xba, 0x2b, 0xec, 0x49, 0x06, 0xfb, 0xbf, 0xf4, 0xe4, 0xa0, 0xdf, + 0xab, 0x81, 0xe9, 0x22, 0x0b, 0x1a, 0x78, 0x24, 0xf2, 0x0d, 0x0f, 0xe4, 0xe4, + 0xea, 0xdd, 0x1c, 0x13, 0xd2, 0xe2, 0x04, 0x10, 0x22, 0x14, 0xc6, 0xc3, 0xe3, + 0x2c, 0xef, 0x64, 0xbe, 0x03, 0x02, 0x0f, 0x01, 0x25, 0x3e, 0xf3, 0xf9, 0xdd, + 0x32, 0x1e, 0x3d, 0x1c, 0x1e, 0x10, 0x02, 0x3e, 0x1d, 0x3f, 0xa6, 0x28, 0x68, + 0x08, 0xeb, 0xfb, 0x56, 0xe6, 0xdf, 0x25, 0x46, 0xcf, 0xa5, 0xf4, 0xf6, 0x15, + 0x2f, 0x1b, 0xdc, 0x4a, 0x10, 0x28, 0xd9, 0xfd, 0xd7, 0xdb, 0x0f, 0xe7, 0xed, + 0xff, 0xdb, 0x14, 0x2b, 0xe8, 0xa2, 0x92, 0x35, 0x46, 0xda, 0xb7, 0x0e, 0xf2, + 0x16, 0x51, 0x16, 0xf2, 0xff, 0x06, 0x1f, 0x04, 0xf0, 0x0c, 0xd4, 0xfa, 0x08, + 0xbb, 0xed, 0x06, 0xfc, 0xd8, 0xfc, 0x26, 0xd9, 0x09, 0xf6, 0xe2, 0x7f, 0x11, + 0x73, 0xd9, 0x09, 0x43, 0xa9, 0xe2, 0xb6, 0xf4, 0xeb, 0x5a, 0x1a, 0xf3, 0x12, + 0xfe, 0xf8, 0x0f, 0x14, 0x14, 0xe9, 0x2e, 0xee, 0x2c, 0xe8, 0xff, 0x0c, 0xb0, + 0xe0, 0x18, 0xba, 0x1d, 0xe9, 0x12, 0xec, 0xeb, 0xe2, 0xe2, 0xe4, 0x27, 0x1b, + 0xd1, 0xc5, 0xe3, 0xeb, 0x1a, 0xf1, 0x06, 0xe2, 0xf6, 0xe2, 0x30, 0xf2, 0xdd, + 0x0b, 0xb5, 0x6e, 0x07, 0xdf, 0xbc, 0x5f, 0x0c, 0x4f, 0xc7, 0xbd, 0xf1, 0xe1, + 0x18, 0xdd, 0x67, 0x29, 0x3a, 0xf9, 0xce, 0x39, 0x06, 0xba, 0xf6, 0xdb, 0xf7, + 0x21, 0xa4, 0xf9, 0xd6, 0x25, 0xdb, 0x1c, 0xe6, 0x03, 0xd4, 0x00, 0x2b, 0x02, + 0x2d, 0x02, 0xd5, 0x43, 0xb0, 0x8f, 0x12, 0xf7, 0x18, 0x15, 0x2f, 0x25, 0x19, + 0xfe, 0x1a, 0x27, 0xf6, 0x04, 0x0d, 0xd7, 0xe1, 0xf7, 0x3d, 0x02, 0xde, 0x27, + 0xf6, 0x27, 0x25, 0x1a, 0x48, 0xf4, 0xfb, 0xe7, 0x52, 0xf2, 0x24, 0x4c, 0xea, + 0x10, 0x02, 0x48, 0x6d, 0xea, 0xda, 0x6c, 0xb6, 0xb7, 0x7f, 0x12, 0xef, 0x38, + 0xc6, 0xf7, 0xf4, 0xc6, 0x1b, 0x0b, 0x0c, 0x05, 0x12, 0xf1, 0xe5, 0x18, 0x2e, + 0x96, 0xec, 0x0f, 0xea, 0x3a, 0x33, 0xf6, 0xd9, 0x77, 0xd9, 0xf4, 0xd2, 0x03, + 0xf6, 0x5d, 0x05, 0xb2, 0x25, 0x18, 0xf4, 0xfc, 0xdb, 0x61, 0x12, 0x0d, 0xd7, + 0xcd, 0xe9, 0xdb, 0x19, 0xf7, 0x36, 0x02, 0x90, 0xdc, 0xfe, 0x21, 0x3e, 0xfb, + 0xf2, 0x35, 0xf4, 0xf9, 0xf0, 0x50, 0xe9, 0xd2, 0xee, 0x3c, 0xfd, 0x4d, 0x31, + 0x59, 0x02, 0x23, 0x45, 0x10, 0x02, 0xc1, 0x2b, 0xd4, 0xfd, 0x2d, 0x18, 0xc9, + 0x00, 0x38, 0xda, 0xd6, 0x02, 0x61, 0x0e, 0xe1, 0x1b, 0xde, 0xcc, 0xf7, 0xf6, + 0x82, 0x0b, 0x34, 0x03, 0xdf, 0xfd, 0xbc, 0xd4, 0xc7, 0xe6, 0xd0, 0xf5, 0x1c, + 0xfa, 0xf3, 0x1e, 0xda, 0x30, 0x17, 0x24, 0xa3, 0xe6, 0xe6, 0x4c, 0xd3, 0xa8, + 0x7f, 0x02, 0xf5, 0xc9, 0x33, 0xc6, 0x26, 0x82, 0x0c, 0x20, 0xf0, 0xdb, 0x40, + 0xe9, 0x18, 0x96, 0xb5, 0xcb, 0x3f, 0xfd, 0x00, 0x67, 0xea, 0x26, 0x53, 0xcf, + 0x0f, 0x1f, 0x11, 0x07, 0x08, 0xff, 0xc7, 0xfe, 0xec, 0x85, 0x45, 0xe8, 0x0f, + 0xe9, 0xf6, 0xf6, 0x42, 0x2b, 0x2a, 0x55, 0xde, 0x00, 0xf5, 0x4f, 0x00, 0x40, + 0x0b, 0x10, 0xf6, 0x97, 0x14, 0xc0, 0xe8, 0xcc, 0xf7, 0xf6, 0x11, 0x27, 0x07, + 0xda, 0xf0, 0x0f, 0xe9, 0xf9, 0x58, 0xc4, 0x1a, 0xde, 0x37, 0xa8, 0x03, 0x13, + 0xe9, 0xcd, 0x01, 0xd3, 0x12, 0xff, 0x0d, 0xc8, 0xf1, 0x7f, 0xf2, 0xf4, 0x0c, + 0x31, 0x17, 0xc9, 0xbb, 0x1c, 0x9f, 0xf8, 0x10, 0x23, 0xe5, 0xce, 0x00, 0xf6, + 0xf1, 0xff, 0x00, 0x00, 0xc4, 0x22, 0x1e, 0x0d, 0x37, 0xf8, 0x12, 0xfd, 0x1f, + 0xc0, 0x0b, 0xd6, 0xd9, 0xf7, 0x1d, 0x33, 0xcf, 0xfd, 0x37, 0x10, 0x10, 0x1e, + 0xd7, 0xeb, 0x10, 0x6a, 0x1e, 0x46, 0xf0, 0xfe, 0xc5, 0xe8, 0x4a, 0xf9, 0xe2, + 0xc4, 0xe9, 0x08, 0xf1, 0x35, 0xf2, 0xec, 0xd9, 0xfe, 0x10, 0xf3, 0x22, 0x13, + 0xec, 0xd1, 0xf1, 0x21, 0x18, 0xe0, 0x2d, 0xee, 0x06, 0x1b, 0x27, 0xec, 0x00, + 0xf4, 0xf2, 0xdb, 0xd2, 0x03, 0xc4, 0xf0, 0xe6, 0xc0, 0x74, 0xd5, 0x0b, 0x1e, + 0x31, 0x21, 0x04, 0x15, 0x18, 0x30, 0xc3, 0xe4, 0xbc, 0xcd, 0x39, 0x38, 0x2e, + 0xba, 0x0b, 0x2b, 0x11, 0x1a, 0x30, 0x54, 0x0b, 0x44, 0xd2, 0xf3, 0xfd, 0x43, + 0x48, 0xfd, 0x02, 0xc8, 0xd9, 0xc6, 0xda, 0xfb, 0x19, 0xd1, 0xd4, 0x0b, 0xee, + 0xd1, 0x22, 0x2c, 0x6f, 0x2f, 0xde, 0x34, 0xdc, 0x3f, 0xf5, 0x2a, 0xf5, 0xed, + 0xff, 0xd8, 0xa9, 0x08, 0xc8, 0x1b, 0xde, 0xca, 0xdd, 0xfc, 0xae, 0x78, 0x59, + 0xf7, 0xd0, 0xf4, 0xe9, 0x2c, 0x81, 0x05, 0xed, 0x1d, 0x14, 0xdc, 0x03, 0x5f, + 0x53, 0x04, 0x17, 0x09, 0x12, 0x34, 0xce, 0xe7, 0x26, 0x32, 0x1d, 0x10, 0xd2, + 0xd3, 0x0d, 0x2f, 0xec, 0xfe, 0x38, 0x1f, 0x1e, 0xfd, 0x69, 0x14, 0x45, 0xf9, + 0xef, 0xe4, 0x14, 0xfe, 0x09, 0xa8, 0x27, 0xdf, 0xce, 0xed, 0xe6, 0x09, 0xea, + 0xb8, 0xb4, 0xef, 0x6c, 0x49, 0x02, 0x17, 0x4f, 0xb0, 0xd7, 0x0a, 0x2c, 0x13, + 0xeb, 0x40, 0x77, 0x15, 0xf4, 0x9e, 0xad, 0xff, 0x31, 0x1a, 0x5f, 0xed, 0xee, + 0x34, 0xe0, 0xfc, 0xf2, 0x34, 0xa0, 0x27, 0xef, 0x07, 0x08, 0x18, 0x0c, 0x3f, + 0xa5, 0xe0, 0xda, 0xfd, 0x13, 0xd2, 0xf3, 0xc4, 0x25, 0xe2, 0x0d, 0x09, 0x15, + 0xa1, 0xef, 0xdf, 0xf4, 0x40, 0xde, 0x1d, 0x5f, 0xfe, 0x16, 0x31, 0xf6, 0x0f, + 0x64, 0xd8, 0xd4, 0xda, 0xd7, 0xce, 0x4b, 0xd2, 0xd5, 0xe0, 0xdd, 0x03, 0xd0, + 0x1f, 0x20, 0x3d, 0x04, 0x06, 0xeb, 0x7f, 0x39, 0xfe, 0x46, 0x7a, 0x03, 0x33, + 0x01, 0x12, 0xc2, 0xbe, 0xd3, 0xe2, 0xcf, 0xef, 0x13, 0x25, 0xf1, 0x04, 0xd2, + 0xe9, 0xc5, 0xd0, 0x00, 0x33, 0x00, 0x4e, 0x0d, 0x59, 0xbc, 0x07, 0xf3, 0xea, + 0xe0, 0x56, 0x40, 0xf9, 0x3f, 0x14, 0x28, 0x4a, 0xd2, 0x15, 0x15, 0x0c, 0x36, + 0x0c, 0x22, 0xe4, 0x2d, 0xff, 0x09, 0xdd, 0x20, 0xfd, 0x3d, 0x7f, 0xc0, 0x07, + 0x47, 0x1f, 0x40, 0x0e, 0x33, 0x0f, 0xe9, 0x2f, 0x01, 0xdd, 0xdd, 0xfb, 0xe0, + 0x47, 0xea, 0xf7, 0xc8, 0x1e, 0x0d, 0x27, 0xe8, 0xe0, 0x0d, 0x0a, 0x10, 0x66, + 0x08, 0x2d, 0x2e, 0x02, 0xee, 0x09, 0xee, 0x14, 0x52, 0x0e, 0xef, 0xfd, 0xd9, + 0xf2, 0x21, 0xea, 0xf0, 0xe7, 0x10, 0xeb, 0xc8, 0x05, 0xed, 0xfb, 0x16, 0xbd, + 0xfa, 0xdf, 0xe0, 0xe2, 0xf2, 0xa6, 0xfe, 0x23, 0xfb, 0xff, 0xd2, 0xd8, 0x07, + 0x73, 0x32, 0xc2, 0x1e, 0x30, 0x11, 0x0b, 0xa1, 0x0e, 0x04, 0x1a, 0x27, 0x1a, + 0xd6, 0xf5, 0x00, 0xf7, 0xf6, 0xed, 0x04, 0xf3, 0x1c, 0x3d, 0x14, 0xe4, 0xcd, + 0x0f, 0x9a, 0x0e, 0x0d, 0x15, 0xd9, 0x06, 0xe8, 0x07, 0xdf, 0x0c, 0xf4, 0x17, + 0x12, 0xe6, 0x18, 0x1e, 0xf0, 0xf4, 0x2c, 0x2f, 0xc3, 0xed, 0x1c, 0xef, 0x0f, + 0xca, 0x13, 0xfd, 0x0b, 0xfc, 0x12, 0x2f, 0x0a, 0x55, 0x09, 0x25, 0x36, 0xf9, + 0xf0, 0x02, 0xad, 0xd4, 0x17, 0x04, 0xda, 0x22, 0x7f, 0x11, 0xd7, 0x12, 0x1d, + 0xf8, 0xfa, 0xf5, 0x6a, 0x3c, 0xf7, 0xec, 0xe5, 0x0a, 0xd8, 0x0d, 0xd7, 0xea, + 0x04, 0x06, 0x19, 0x0f, 0x40, 0x28, 0x16, 0x07, 0xf7, 0xde, 0xf5, 0x1a, 0xc7, + 0xd9, 0x23, 0xfe, 0xc0, 0x22, 0xf5, 0xf8, 0xe8, 0x12, 0xdc, 0xdc, 0xf9, 0xf9, + 0x1d, 0xc8, 0x1a, 0x11, 0x07, 0xf4, 0x08, 0xf6, 0xf9, 0x10, 0xf2, 0x12, 0x00, + 0x41, 0xf9, 0x2e, 0xf1, 0xd2, 0xc3, 0xc5, 0xf6, 0xdc, 0x06, 0x09, 0x16, 0xf1, + 0x22, 0x22, 0x14, 0x11, 0xff, 0x01, 0x02, 0x16, 0x14, 0x12, 0xf1, 0xdd, 0x2e, + 0xf6, 0x1d, 0xf0, 0xef, 0x07, 0xe7, 0x48, 0x0b, 0x20, 0x1d, 0x11, 0x3a, 0x01, + 0xd4, 0xcb, 0xd3, 0xf0, 0x0b, 0x03, 0x2e, 0xd5, 0x42, 0x0c, 0xeb, 0x17, 0x09, + 0x0e, 0x07, 0xc7, 0x01, 0x2d, 0x02, 0x43, 0x9e, 0xeb, 0x1d, 0xf5, 0xca, 0xa5, + 0x7f, 0xbc, 0x2d, 0xf3, 0x35, 0xe5, 0x33, 0x08, 0xf8, 0xf9, 0x42, 0xcc, 0x10, + 0x35, 0xce, 0x54, 0x00, 0x30, 0xef, 0x9e, 0xf4, 0xfd, 0xe8, 0x49, 0xef, 0xa3, + 0x3a, 0x2d, 0xd4, 0xe3, 0x13, 0xdb, 0xe0, 0xcf, 0x15, 0xe7, 0xf3, 0xd7, 0x28, + 0xe1, 0xfb, 0x15, 0x03, 0xf6, 0xde, 0x3c, 0xe5, 0xd9, 0xbb, 0xf4, 0xec, 0xda, + 0x0f, 0x04, 0x3a, 0x16, 0xf0, 0x33, 0x07, 0xd7, 0x09, 0xde, 0x25, 0xf0, 0xdd, + 0x11, 0x94, 0x1b, 0xcf, 0xda, 0x31, 0xa7, 0x0a, 0xde, 0x09, 0x21, 0x17, 0x0a, + 0x0c, 0x19, 0xf3, 0x2a, 0xdb, 0xdb, 0xec, 0x0b, 0x2b, 0xf2, 0xd4, 0x2c, 0xa8, + 0xed, 0xeb, 0x38, 0xec, 0xd8, 0x3a, 0x5f, 0xcd, 0xec, 0x1b, 0xe6, 0x38, 0xeb, + 0x18, 0x1e, 0x83, 0xe6, 0xcd, 0x00, 0x63, 0x0b, 0x95, 0xcc, 0xf6, 0xd1, 0x2d, + 0xd5, 0x35, 0xea, 0x17, 0xf5, 0x01, 0xe5, 0x1c, 0x13, 0xef, 0xe2, 0x1d, 0x3a, + 0x0a, 0x06, 0x08, 0xd8, 0xf2, 0x44, 0xf7, 0x1e, 0x15, 0x42, 0x16, 0xe6, 0xe5, + 0xfc, 0xd5, 0xe6, 0x34, 0x10, 0x02, 0x1f, 0x19, 0xeb, 0xff, 0xc4, 0xe9, 0x01, + 0xe3, 0xda, 0xcb, 0xea, 0x04, 0xf7, 0xc7, 0x24, 0xf6, 0x19, 0x1f, 0x55, 0xdd, + 0x3e, 0x0d, 0x1b, 0xf7, 0xf1, 0xfc, 0xe7, 0x3a, 0x17, 0xff, 0xeb, 0xf3, 0x00, + 0xed, 0x0a, 0xd0, 0xd6, 0x0d, 0xb2, 0xdf, 0xf2, 0xe2, 0x11, 0x24, 0xd4, 0x23, + 0x08, 0x1d, 0xb9, 0x32, 0x2b, 0xde, 0x29, 0x1e, 0xff, 0x08, 0xf5, 0x1b, 0x00, + 0x36, 0x28, 0xe8, 0xd5, 0xfd, 0xce, 0x7f, 0xe7, 0x23, 0xf8, 0x59, 0x23, 0x3c, + 0xea, 0xcf, 0x2e, 0x03, 0x95, 0xdf, 0x16, 0xf3, 0xb2, 0xda, 0xda, 0x1e, 0x3b, + 0x4b, 0x08, 0xe5, 0xea, 0xbe, 0xe9, 0xe5, 0x0e, 0x25, 0x60, 0xf5, 0xab, 0xbc, + 0x0f, 0x22, 0x59, 0x0f, 0x0b, 0x02, 0xed, 0xdd, 0x01, 0x57, 0x09, 0x0d, 0xff, + 0x26, 0x1b, 0x35, 0xd8, 0x17, 0xfb, 0xd2, 0x1b, 0xc9, 0xff, 0x0b, 0x7f, 0xaf, + 0x07, 0x31, 0xd9, 0xef, 0x35, 0xbf, 0x05, 0x29, 0xea, 0xb6, 0xde, 0xac, 0xe4, + 0x05, 0xe5, 0x08, 0xfd, 0xe8, 0xf2, 0xb7, 0xad, 0xb4, 0xc7, 0xe8, 0xea, 0x1b, + 0x02, 0x31, 0xd8, 0x33, 0xbb, 0xe1, 0xbd, 0xfd, 0x8f, 0xd4, 0xeb, 0x46, 0x30, + 0xd0, 0x05, 0xbc, 0xfb, 0x0c, 0xf5, 0x58, 0xba, 0xd1, 0x53, 0x24, 0xf0, 0xca, + 0xc8, 0xe9, 0x46, 0x1d, 0xf2, 0x02, 0x0a, 0xeb, 0xd3, 0x19, 0x44, 0xfa, 0x07, + 0xef, 0xe1, 0x13, 0x33, 0xb5, 0x0b, 0xdc, 0x3f, 0x2d, 0xd0, 0x1c, 0xfd, 0x1c, + 0xcd, 0x15, 0x3d, 0xd7, 0xf9, 0x5e, 0x12, 0x15, 0xf8, 0xfc, 0x0a, 0xfc, 0x19, + 0xe0, 0xce, 0x28, 0xfc, 0xe7, 0xee, 0xec, 0xc7, 0xf5, 0xf0, 0x49, 0x23, 0xd8, + 0x03, 0x52, 0x66, 0x3a, 0xe9, 0x25, 0x3c, 0xf9, 0x14, 0xcb, 0xe8, 0x20, 0xe9, + 0x8f, 0xeb, 0xe1, 0x3a, 0xf1, 0xdb, 0x14, 0x15, 0x8c, 0x14, 0x58, 0x3e, 0x90, + 0x20, 0x22, 0xed, 0xef, 0x21, 0xce, 0x25, 0x29, 0xd2, 0x0c, 0xe8, 0x9a, 0xc8, + 0x39, 0x06, 0x2e, 0xf9, 0xea, 0xa3, 0xca, 0xdc, 0xd5, 0xfa, 0x20, 0x44, 0x27, + 0x02, 0x45, 0xdf, 0x1d, 0x15, 0x32, 0x1c, 0xe5, 0x2c, 0x3a, 0x55, 0xe6, 0x39, + 0xfe, 0x25, 0xf3, 0x26, 0x08, 0xec, 0xec, 0x00, 0xef, 0xfe, 0xee, 0xed, 0x26, + 0x36, 0xef, 0xb0, 0xf5, 0x1d, 0x18, 0x1b, 0x1c, 0xed, 0xf3, 0x1c, 0xe8, 0x01, + 0x21, 0x68, 0xd5, 0x45, 0xc7, 0xd7, 0x10, 0x3d, 0xcf, 0x09, 0x10, 0xee, 0x4b, + 0xfd, 0x45, 0xda, 0x19, 0xd1, 0x78, 0x08, 0xe9, 0xe0, 0x2a, 0xeb, 0xc8, 0x7f, + 0x36, 0x22, 0x27, 0xc2, 0xe9, 0xf7, 0x01, 0x0e, 0xec, 0x37, 0xfb, 0xd6, 0x5b, + 0x38, 0xec, 0x1c, 0xf8, 0x2b, 0xce, 0x29, 0x07, 0x32, 0xeb, 0x0c, 0xc4, 0xff, + 0xe4, 0xfe, 0xce, 0xf7, 0xf1, 0x01, 0xe0, 0x11, 0xdd, 0x1e, 0xde, 0x20, 0x1e, + 0xe6, 0x10, 0x11, 0x0e, 0x7f, 0x2f, 0xc3, 0x5d, 0x02, 0x13, 0xf5, 0x1e, 0x4e, + 0x45, 0xfe, 0x20, 0x26, 0xe3, 0x1d, 0x02, 0xfa, 0x1f, 0x14, 0x3d, 0xc6, 0xef, + 0x42, 0xf6, 0x20, 0x10, 0x18, 0x27, 0x0c, 0x15, 0x3b, 0x1c, 0x34, 0x46, 0x11, + 0xa3, 0x2c, 0x29, 0x06, 0x13, 0x0e, 0xdb, 0x16, 0x4c, 0x28, 0x4c, 0xd1, 0xe3, + 0x4e, 0x1a, 0xf1, 0xf7, 0x10, 0xf1, 0xf0, 0x14, 0xf4, 0x02, 0x1f, 0xec, 0x41, + 0x2e, 0x26, 0xf6, 0xea, 0x35, 0x15, 0xf2, 0xf2, 0xe3, 0xc3, 0xfc, 0x03, 0x21, + 0xe9, 0xf4, 0xda, 0x2e, 0xf2, 0x11, 0xd0, 0x33, 0x12, 0xd7, 0x41, 0x01, 0x14, + 0x15, 0xf0, 0x10, 0xeb, 0x1c, 0x05, 0x15, 0x03, 0xf6, 0xe2, 0xef, 0x62, 0x26, + 0x0b, 0xeb, 0x08, 0xff, 0x1b, 0xed, 0xcf, 0x15, 0xd0, 0xd2, 0xfa, 0xf8, 0xe6, + 0xff, 0x19, 0x1d, 0x01, 0xd3, 0x18, 0xfd, 0xfd, 0xcd, 0x04, 0xdb, 0xdd, 0x14, + 0x12, 0xe4, 0x6d, 0x7f, 0xc8, 0xfc, 0x1b, 0xe5, 0x0d, 0x18, 0x10, 0x34, 0x38, + 0xfb, 0x02, 0x12, 0x11, 0x12, 0x01, 0x33, 0x0d, 0xc3, 0x07, 0x18, 0x0b, 0xce, + 0x0a, 0x1f, 0x00, 0xfa, 0x3d, 0x40, 0x27, 0x30, 0x19, 0xed, 0xef, 0xfe, 0xfc, + 0xe7, 0xde, 0xe7, 0xff, 0xf9, 0xcf, 0xe2, 0xfa, 0x28, 0x35, 0xd5, 0x17, 0x17, + 0x17, 0x1b, 0x1c, 0x11, 0x07, 0x17, 0xf2, 0xf1, 0xfc, 0x0f, 0x16, 0xdb, 0x05, + 0xf4, 0xec, 0xe6, 0xdf, 0x47, 0xd7, 0xe8, 0x10, 0xd1, 0x4c, 0x40, 0x0b, 0xe4, + 0xe0, 0xd9, 0xe7, 0xff, 0x14, 0xfa, 0xe9, 0xdc, 0x1a, 0xdf, 0x17, 0x33, 0x0c, + 0x29, 0xa9, 0x53, 0x1c, 0xd6, 0xc4, 0x13, 0x74, 0xf8, 0xf8, 0x1d, 0xfd, 0x2f, + 0x09, 0xb0, 0x2d, 0x15, 0x1a, 0xcc, 0xcd, 0x2c, 0xdd, 0x19, 0x4d, 0xeb, 0x04, + 0x89, 0xe1, 0x28, 0xff, 0xf6, 0xf8, 0x1e, 0xd9, 0x00, 0x1f, 0xf3, 0xfb, 0xe3, + 0x56, 0x06, 0xfd, 0xe3, 0xfb, 0x0d, 0x1e, 0xc5, 0xdc, 0xe6, 0x09, 0x39, 0xdf, + 0x2f, 0x1e, 0xb8, 0x09, 0x36, 0xfb, 0x43, 0x41, 0xa4, 0xfa, 0xd9, 0xd7, 0x1c, + 0xda, 0x24, 0xcf, 0x14, 0x1a, 0xc3, 0xce, 0xb3, 0xc5, 0x9a, 0x8a, 0x04, 0xc5, + 0xdf, 0x6c, 0xef, 0x16, 0xe7, 0xe9, 0xfe, 0xd1, 0xee, 0xd4, 0x25, 0xf1, 0x0b, + 0xf3, 0xe5, 0xc2, 0xa7, 0xdd, 0xef, 0x44, 0x0d, 0x0d, 0xf5, 0xe0, 0x11, 0x20, + 0xc8, 0xbe, 0xf8, 0x1a, 0xe7, 0x49, 0x13, 0xd0, 0xe6, 0x03, 0x32, 0x4c, 0x81, + 0x06, 0xea, 0xcf, 0x17, 0x01, 0x44, 0xd8, 0x39, 0xf5, 0xcd, 0x52, 0x11, 0xfe, + 0x03, 0xd3, 0x0a, 0xe8, 0x18, 0xe2, 0x08, 0x18, 0xf8, 0x54, 0x26, 0xea, 0xc1, + 0xf8, 0xf5, 0xd4, 0xe1, 0x37, 0x66, 0x0c, 0x1c, 0xf4, 0x32, 0x0d, 0x6c, 0x12, + 0xf8, 0xe5, 0x11, 0xd7, 0x02, 0x5b, 0x0a, 0xe3, 0x23, 0x41, 0xa5, 0x57, 0x1b, + 0x47, 0xf3, 0xf9, 0x58, 0xe3, 0x3d, 0x24, 0x15, 0x1d, 0xfd, 0xb3, 0xc4, 0xfd, + 0xf4, 0xdf, 0x16, 0xf0, 0x38, 0xf7, 0x18, 0x19, 0x19, 0x63, 0x0e, 0x36, 0x40, + 0x2d, 0x17, 0xed, 0x30, 0x4c, 0x04, 0xf0, 0xb5, 0x42, 0x16, 0x04, 0x07, 0xfe, + 0x37, 0x70, 0x24, 0xe6, 0xfe, 0x7f, 0x03, 0xd4, 0x29, 0x41, 0x09, 0xe0, 0x0b, + 0x31, 0xda, 0x35, 0x02, 0xe9, 0xee, 0x0b, 0x02, 0xfb, 0x01, 0xfc, 0x12, 0x08, + 0xec, 0xdd, 0x40, 0xea, 0xea, 0xd4, 0x4a, 0xf7, 0xde, 0xf4, 0xe6, 0x23, 0x57, + 0x0a, 0x31, 0xe2, 0x09, 0x07, 0x2f, 0xe2, 0xca, 0x50, 0x12, 0x37, 0x19, 0x28, + 0xe2, 0x04, 0x7f, 0x4d, 0x3c, 0xad, 0x28, 0xf0, 0xea, 0xe0, 0xac, 0x01, 0x06, + 0x37, 0x5c, 0x08, 0xb8, 0xe9, 0x09, 0xd1, 0x35, 0x16, 0xdf, 0x22, 0xf9, 0x10, + 0x18, 0x22, 0x1b, 0xec, 0x00, 0xf6, 0xd4, 0x41, 0x16, 0x1f, 0xf9, 0xf9, 0x19, + 0x40, 0x45, 0x52, 0xf9, 0x1c, 0x17, 0xed, 0xd9, 0x2f, 0x1f, 0x71, 0x61, 0xca, + 0x0c, 0xfc, 0xf6, 0xf8, 0x29, 0x02, 0xd8, 0x16, 0xfa, 0xc5, 0x18, 0x28, 0x14, + 0x26, 0x03, 0xcd, 0xc0, 0x2e, 0x1b, 0x15, 0x31, 0xec, 0xf5, 0xda, 0x30, 0x0c, + 0x54, 0x5e, 0x18, 0x30, 0x1e, 0xeb, 0xe4, 0x08, 0x17, 0x29, 0x15, 0xfc, 0xdd, + 0xd8, 0x1b, 0x3e, 0xc8, 0x28, 0x31, 0x0e, 0xe6, 0x11, 0x06, 0x3a, 0xa8, 0xe6, + 0x1c, 0xe7, 0xd9, 0x66, 0x3d, 0x0b, 0xda, 0x30, 0x37, 0x0e, 0xc6, 0x22, 0xe6, + 0x1e, 0x28, 0xeb, 0xe9, 0x9a, 0x29, 0x37, 0x19, 0xec, 0xd4, 0xfd, 0xe5, 0xed, + 0xfb, 0x59, 0xde, 0x29, 0xce, 0x25, 0xfd, 0xe2, 0xea, 0x13, 0xde, 0xcd, 0xee, + 0x3d, 0x38, 0xef, 0x1f, 0x1b, 0x7f, 0xee, 0xef, 0x37, 0xca, 0x29, 0x0a, 0xff, + 0xe5, 0xec, 0x0c, 0xf7, 0xdb, 0x2a, 0x12, 0xd2, 0x29, 0x16, 0xbc, 0xef, 0x19, + 0xf9, 0x34, 0xee, 0x07, 0xec, 0xe4, 0xee, 0x42, 0xd6, 0xfa, 0x17, 0xd6, 0xdd, + 0xc7, 0x02, 0xdc, 0xe8, 0xcc, 0xd8, 0xe3, 0xd8, 0x0a, 0x0a, 0x20, 0x08, 0xeb, + 0x2d, 0xfe, 0x1f, 0xee, 0x05, 0xe2, 0x3a, 0xe7, 0xe9, 0xe4, 0xe2, 0xfd, 0xc3, + 0xbe, 0xec, 0xd6, 0xdc, 0xe1, 0xee, 0xee, 0x17, 0x16, 0x3e, 0xee, 0x32, 0xf4, + 0x02, 0xf8, 0x25, 0xdc, 0x05, 0xf5, 0x1b, 0xf0, 0xfe, 0xe7, 0x00, 0x15, 0xd9, + 0x0d, 0x05, 0xe6, 0xd7, 0x1f, 0x1d, 0x02, 0xe5, 0xcb, 0xeb, 0xd8, 0x13, 0xee, + 0x46, 0xe6, 0x10, 0xc1, 0xee, 0x11, 0xef, 0xec, 0xfe, 0x1a, 0xd6, 0x27, 0xf9, + 0xf9, 0x07, 0x06, 0xee, 0x30, 0x0c, 0x3a, 0x1b, 0x1a, 0x31, 0x0b, 0xf1, 0x20, + 0x10, 0x25, 0x2b, 0x15, 0xd3, 0xf7, 0x1e, 0x38, 0xe8, 0x7f, 0x04, 0x29, 0x18, + 0x0b, 0xe9, 0xf7, 0xea, 0x16, 0xe8, 0xe9, 0x06, 0xfa, 0xe1, 0x0b, 0xdd, 0xdb, + 0x02, 0x0e, 0xfc, 0x01, 0x50, 0xe6, 0x01, 0xca, 0xea, 0x08, 0x05, 0x38, 0x05, + 0xe0, 0x0e, 0x13, 0x1d, 0xd2, 0x02, 0xe8, 0x00, 0xf8, 0xe9, 0x13, 0x07, 0x0e, + 0x2e, 0x10, 0x4a, 0x0c, 0x07, 0x41, 0x18, 0x07, 0x34, 0x03, 0xf1, 0x27, 0xde, + 0xff, 0xc5, 0x16, 0xe7, 0xd8, 0x0b, 0xf9, 0xd2, 0x3a, 0x24, 0x21, 0x15, 0xf3, + 0xed, 0xf5, 0xf6, 0x2d, 0xe5, 0x4a, 0xc9, 0xe0, 0x0f, 0x20, 0xf2, 0x1a, 0x28, + 0x3c, 0x1a, 0xf6, 0xfa, 0x3a, 0xe4, 0x3f, 0x0d, 0x05, 0xde, 0xe9, 0x1e, 0x17, + 0x3a, 0x21, 0xbf, 0xbb, 0x0b, 0xed, 0xfc, 0x15, 0xe8, 0xfe, 0x81, 0x2b, 0xd8, + 0x2e, 0x14, 0x2f, 0xd9, 0xeb, 0x22, 0x0f, 0x0a, 0xf4, 0xf1, 0x01, 0x17, 0x0a, + 0x20, 0xe9, 0x29, 0xf7, 0xea, 0xfb, 0xf9, 0xfb, 0xd0, 0x48, 0xef, 0x05, 0xce, + 0xf5, 0xf8, 0xc7, 0x52, 0xd5, 0x07, 0xd3, 0xfc, 0xf4, 0xa8, 0x2d, 0x14, 0xdb, + 0x3b, 0xdd, 0xd1, 0xfb, 0x1e, 0xd3, 0x09, 0xc4, 0xce, 0x12, 0xcd, 0xce, 0xe2, + 0x07, 0x43, 0xfb, 0xf2, 0xd7, 0x1a, 0xe8, 0x1c, 0xf4, 0x16, 0x1a, 0xb7, 0xe8, + 0xec, 0xe7, 0xe6, 0x04, 0xfc, 0x3c, 0x3c, 0xf7, 0xc3, 0xec, 0x58, 0xe0, 0x24, + 0xdf, 0x1a, 0x40, 0x41, 0xfa, 0x25, 0xf5, 0x00, 0xc5, 0x3f, 0xfc, 0xd5, 0x24, + 0x1a, 0xfc, 0xf6, 0xd6, 0xb2, 0x10, 0x0c, 0xeb, 0x02, 0x01, 0x33, 0xd7, 0x06, + 0xe2, 0x13, 0xff, 0x11, 0x38, 0xc9, 0xd7, 0xd7, 0xeb, 0xf4, 0x15, 0xfa, 0xda, + 0x32, 0x3d, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xb5, + 0x79, 0x9c, 0x67, 0xe0, 0x3a, 0x57, 0xa7, 0x81, 0x58, 0x81, 0x7f, 0x5f, 0xe6, + 0xfe, 0xb2, 0xc5, 0xdb, 0x8a, 0x3c, 0xec, 0xc7, 0xaf, 0xa8, 0xf2, 0x09, 0x08, + 0x2f, 0xdd, 0x81, 0x7b, 0xb7, 0x0a, 0x0e, 0x24, 0x6b, 0x7f, 0xa3, 0x01, 0xdd, + 0x10, 0x04, 0x8c, 0x26, 0xe6, 0x4e, 0x81, 0x81, 0x39, 0x81, 0x04, 0x4f, 0xf1, + 0x46, 0x28, 0xc0, 0x6a, 0x9c, 0x3e, 0xb7, 0x2e, 0x77, 0x06, 0xfa, 0x46, 0x1d, + 0x63, 0x4c, 0xf2, 0xec, 0xd1, 0x91, 0x5c, 0x95, 0xfc, 0xff, 0x60, 0x95, 0xfc, + 0xff, 0x64, 0x95, 0xfc, 0xff, 0x68, 0x95, 0xfc, 0xff, 0x96, 0x3d, 0xfd, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0xf9, 0xf0, 0x0f, 0x05, + 0x06, 0x81, 0x04, 0xff, 0x74, 0xef, 0xfe, 0xf9, 0x81, 0x18, 0x16, 0x7f, 0xeb, + 0xf7, 0x04, 0x00, 0x12, 0xf5, 0xf7, 0x20, 0xec, 0x06, 0xf4, 0x7f, 0x5a, 0x7a, + 0xf7, 0x07, 0xfa, 0x2a, 0xef, 0x60, 0x0a, 0x7f, 0xee, 0x81, 0x55, 0x0a, 0xfa, + 0xfc, 0xbb, 0x0b, 0xfe, 0xdf, 0x19, 0xec, 0xfb, 0x1f, 0x04, 0x81, 0xef, 0x7f, + 0x3e, 0xea, 0xf8, 0xce, 0x31, 0x4d, 0x11, 0xfc, 0x81, 0x0b, 0x00, 0xfd, 0x15, + 0xf9, 0xf8, 0x01, 0x0d, 0x0f, 0x01, 0x03, 0xe6, 0x81, 0x03, 0x81, 0xdb, 0x0c, + 0xfa, 0x0a, 0x0d, 0xc9, 0xf8, 0x49, 0x5a, 0x15, 0xf1, 0xfd, 0x60, 0x81, 0xfd, + 0x04, 0xf1, 0x01, 0x07, 0xa2, 0x0b, 0x81, 0xf9, 0xb4, 0xc8, 0x07, 0x02, 0xaa, + 0x17, 0x7f, 0x02, 0x05, 0xd9, 0xd7, 0xf0, 0x7f, 0x23, 0xd8, 0x1d, 0x0d, 0x0a, + 0x09, 0xf1, 0xf5, 0xea, 0x7f, 0x00, 0x22, 0x3e, 0xfd, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xe2, 0xff, 0xff, 0xff, 0x2f, 0x00, 0x00, + 0xaf, 0xee, 0xff, 0xff, 0xdb, 0x16, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff, 0x16, + 0x54, 0x00, 0x00, 0x34, 0x17, 0x00, 0x00, 0xd5, 0x0c, 0x00, 0x00, 0xf6, 0x22, + 0x00, 0x00, 0xcd, 0x20, 0x00, 0x00, 0xdf, 0x8f, 0x00, 0x00, 0x64, 0x25, 0x00, + 0x00, 0x83, 0x1d, 0x00, 0x00, 0x53, 0x42, 0x00, 0x00, 0xe6, 0x19, 0x00, 0x00, + 0x9f, 0x0d, 0x00, 0x00, 0x03, 0xde, 0xff, 0xff, 0x52, 0x23, 0x00, 0x00, 0x71, + 0x3f, 0x00, 0x00, 0x92, 0x19, 0x00, 0x00, 0xb0, 0xd9, 0xff, 0xff, 0xa0, 0x23, + 0x00, 0x00, 0xaf, 0x03, 0x00, 0x00, 0x30, 0xf9, 0xff, 0xff, 0x2b, 0x28, 0x00, + 0x00, 0xfc, 0x97, 0x00, 0x00, 0xcc, 0x09, 0x00, 0x00, 0xb9, 0x24, 0x00, 0x00, + 0x6b, 0xb9, 0xff, 0xff, 0x68, 0x56, 0x00, 0x00, 0x43, 0x2c, 0x00, 0x00, 0xce, + 0xef, 0xff, 0xff, 0xae, 0x3e, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x03, 0x34, 0xee, 0xd9, 0x38, 0x14, 0x0d, 0xc6, 0xdc, 0x0d, 0x1d, + 0xf3, 0x7f, 0x3a, 0x01, 0x13, 0x0f, 0x3c, 0xfd, 0x0d, 0xe3, 0xd9, 0xc3, 0xaf, + 0xad, 0xfc, 0x1a, 0xff, 0xf2, 0x7f, 0xe4, 0xdc, 0x0d, 0x74, 0x0d, 0x0a, 0xdb, + 0xdb, 0xd6, 0xac, 0xe4, 0x1f, 0xfc, 0x43, 0xff, 0x7f, 0xf9, 0x04, 0xf8, 0x48, + 0xf0, 0x85, 0x56, 0x81, 0xbc, 0xc9, 0xd4, 0x04, 0x31, 0xf8, 0x64, 0xe4, 0x16, + 0xec, 0x40, 0xed, 0xbe, 0xf2, 0x0c, 0x0b, 0x19, 0x0c, 0x38, 0x07, 0xc8, 0xe4, + 0x2d, 0x81, 0xe4, 0x77, 0xab, 0xf6, 0x2a, 0xe2, 0x27, 0xe8, 0x0a, 0xa3, 0x49, + 0xad, 0x7f, 0x1c, 0xf4, 0x39, 0x17, 0xa1, 0xa7, 0x1b, 0x0b, 0xef, 0x17, 0xd9, + 0xff, 0xf1, 0x02, 0x49, 0x2b, 0xe3, 0xcf, 0x2f, 0x7f, 0xa2, 0xff, 0xe4, 0x0f, + 0xe8, 0xe4, 0x01, 0x7f, 0xa3, 0xfa, 0xdd, 0xff, 0xce, 0x0d, 0xf6, 0xea, 0x0d, + 0xaa, 0xf6, 0xc2, 0x32, 0x02, 0xeb, 0x29, 0x1b, 0x7f, 0xe6, 0xee, 0x0c, 0xf3, + 0xc2, 0x25, 0x35, 0xde, 0xfc, 0xdc, 0xc9, 0x7f, 0x2b, 0xd7, 0x17, 0x20, 0x22, + 0x2b, 0x09, 0x59, 0xba, 0x38, 0x35, 0x16, 0x5d, 0x4d, 0x3c, 0xad, 0x95, 0x09, + 0xbd, 0x81, 0xe2, 0x22, 0xc8, 0x9f, 0x33, 0xec, 0xab, 0x70, 0x16, 0xeb, 0x24, + 0x20, 0xce, 0x2f, 0xc2, 0xb8, 0xe5, 0xf7, 0x14, 0x1e, 0x22, 0x81, 0x2f, 0xda, + 0x7f, 0xc3, 0xce, 0x5a, 0xcc, 0x70, 0xfa, 0x4d, 0x06, 0xa7, 0x8e, 0x06, 0xbc, + 0x1d, 0x35, 0x15, 0x0b, 0xd6, 0xed, 0x1f, 0xef, 0xc2, 0xca, 0xd1, 0xe1, 0xf7, + 0x23, 0xff, 0x81, 0xd2, 0x39, 0xe3, 0xee, 0x15, 0x06, 0xe2, 0xf6, 0x48, 0xc0, + 0x13, 0xeb, 0x81, 0xbd, 0x13, 0x37, 0xf5, 0x38, 0x29, 0xfc, 0x7f, 0xf4, 0xee, + 0x0a, 0x08, 0x1e, 0xac, 0x1f, 0xd0, 0x43, 0xe4, 0xd3, 0xf1, 0xfd, 0x2e, 0xe6, + 0xd4, 0x2f, 0x2b, 0x3e, 0x0a, 0x5a, 0x7f, 0x08, 0xd4, 0xe3, 0x18, 0x24, 0xb1, + 0x00, 0x11, 0x85, 0xed, 0xfc, 0x22, 0x3c, 0x0e, 0x19, 0xc7, 0x78, 0xfa, 0xbc, + 0x27, 0xfb, 0x2f, 0x81, 0x5f, 0x35, 0x0c, 0x1a, 0xe8, 0x96, 0xbd, 0x7f, 0x95, + 0x0e, 0x32, 0x62, 0xe7, 0xf6, 0xcf, 0xb3, 0xb3, 0xef, 0x55, 0xf5, 0xf2, 0xf2, + 0x24, 0xbf, 0x55, 0x79, 0xfe, 0xcc, 0xf4, 0x61, 0x58, 0x81, 0x69, 0x81, 0x11, + 0xb0, 0x4d, 0xee, 0x2d, 0x7f, 0x39, 0xdc, 0xde, 0xf7, 0x76, 0x52, 0xb6, 0xdf, + 0x7f, 0x0e, 0x68, 0x18, 0x1d, 0xe3, 0xc7, 0xb9, 0x25, 0xb6, 0x48, 0x15, 0x2b, + 0xe8, 0xc5, 0x0b, 0x11, 0x03, 0xe4, 0xc9, 0xf5, 0x19, 0xe1, 0x7f, 0x05, 0x25, + 0xd7, 0x3f, 0x08, 0x0b, 0x00, 0xba, 0x29, 0x7f, 0x1f, 0xe7, 0x18, 0xf3, 0x04, + 0x26, 0xf1, 0x1a, 0xe6, 0x11, 0x19, 0xe7, 0xfa, 0xf0, 0xa7, 0x0c, 0xf6, 0x7f, + 0xc3, 0x09, 0xec, 0xe0, 0x14, 0xe2, 0x23, 0xf0, 0x97, 0x04, 0x38, 0x10, 0x7f, + 0xd3, 0x08, 0x5d, 0xb5, 0x25, 0x20, 0x46, 0x95, 0x30, 0xa6, 0x09, 0xde, 0x64, + 0xcc, 0xf6, 0xa8, 0x03, 0xfe, 0x01, 0x10, 0xf1, 0x38, 0xfb, 0xeb, 0xfc, 0x7f, + 0x06, 0x00, 0x06, 0xf1, 0x1a, 0x3d, 0xf4, 0xf1, 0xec, 0xef, 0x7f, 0xdf, 0x2d, + 0x99, 0x12, 0xa9, 0x40, 0xef, 0x94, 0xf3, 0x0f, 0x7f, 0xe8, 0x29, 0x07, 0xf8, + 0xd9, 0xca, 0x23, 0x71, 0x36, 0x06, 0x0b, 0x2c, 0x1a, 0xdb, 0xf4, 0xec, 0x7f, + 0xe4, 0xdf, 0x03, 0xa3, 0xde, 0xb6, 0xa8, 0x08, 0x0f, 0xda, 0xfe, 0xc5, 0x1a, + 0xd2, 0xe4, 0x3a, 0xca, 0xf3, 0xfa, 0x81, 0xd0, 0xd3, 0xf2, 0x08, 0x10, 0xda, + 0x17, 0x02, 0x1a, 0x11, 0x81, 0x81, 0x76, 0xf9, 0xd7, 0xe3, 0xda, 0xbc, 0x51, + 0x3e, 0x65, 0xbe, 0x37, 0x71, 0x43, 0xca, 0xba, 0x40, 0xfd, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x14, 0xfd, 0x8d, 0x2e, 0x0c, 0x0c, 0xff, + 0x1a, 0x0e, 0x00, 0x85, 0xbe, 0xff, 0x00, 0xf9, 0xf0, 0x11, 0xf9, 0x81, 0x90, + 0xf7, 0x01, 0x00, 0x01, 0xe0, 0xf0, 0xf2, 0x9f, 0xe1, 0xe9, 0x00, 0x22, 0x81, + 0x1b, 0x0c, 0x18, 0xfe, 0xcb, 0x13, 0x5e, 0xd9, 0xeb, 0x42, 0x3e, 0x0a, 0xec, + 0x00, 0x7f, 0x24, 0xf9, 0xdf, 0xcc, 0x81, 0xbc, 0x01, 0x66, 0xb4, 0x7f, 0xfe, + 0x81, 0x1c, 0x81, 0x7f, 0x63, 0x25, 0x3b, 0xc3, 0xa5, 0x78, 0x8f, 0x01, 0x03, + 0x0e, 0x41, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x7a, + 0xed, 0xff, 0xff, 0xc0, 0xef, 0xff, 0xff, 0x49, 0x1b, 0x00, 0x00, 0xc7, 0x21, + 0x00, 0x00, 0x4d, 0x74, 0x00, 0x00, 0x26, 0x7a, 0x00, 0x00, 0x85, 0xc4, 0xff, + 0xff, 0x41, 0x95, 0xff, 0xff, 0x1b, 0xf2, 0xff, 0xff, 0x05, 0x33, 0x00, 0x00, + 0xcb, 0xf5, 0xff, 0xff, 0x4d, 0x6c, 0x00, 0x00, 0xb1, 0x08, 0x00, 0x00, 0x01, + 0xd2, 0xff, 0xff, 0x47, 0x05, 0x00, 0x00, 0x59, 0x3e, 0x00, 0x00, 0x13, 0xd9, + 0xff, 0xff, 0x62, 0x2f, 0x00, 0x00, 0x79, 0xcd, 0xff, 0xff, 0x86, 0xd7, 0xff, + 0xff, 0x99, 0x0a, 0x00, 0x00, 0x7f, 0x21, 0x00, 0x00, 0x27, 0xf4, 0xff, 0xff, + 0xc2, 0xec, 0xff, 0xff, 0xc1, 0xf3, 0xff, 0xff, 0x04, 0xff, 0xff, 0xff, 0x0f, + 0xf5, 0xff, 0xff, 0x51, 0xed, 0xff, 0xff, 0x3c, 0x2a, 0x00, 0x00, 0xec, 0xe8, + 0xff, 0xff, 0x24, 0xc3, 0xff, 0xff, 0x99, 0x32, 0x00, 0x00, 0x9a, 0x41, 0xfd, + 0xff, 0x04, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x4f, 0x2a, 0xde, 0x21, + 0xa6, 0xcc, 0x33, 0x25, 0x47, 0xe7, 0x16, 0xe6, 0xc7, 0x59, 0xb9, 0x94, 0x7f, + 0x3d, 0xd7, 0x5e, 0x81, 0x9f, 0x61, 0x50, 0x6a, 0xb5, 0x40, 0xa7, 0xa3, 0x7f, + 0xa2, 0xac, 0x4f, 0x1a, 0xde, 0x32, 0xbb, 0xe6, 0x3d, 0x37, 0x2e, 0xd2, 0x37, + 0x88, 0xcc, 0x3a, 0xda, 0xe7, 0x4e, 0x52, 0xbd, 0x30, 0xa1, 0x98, 0x3d, 0x7f, + 0x53, 0xdb, 0x53, 0xb1, 0xb7, 0x3b, 0xa0, 0xc6, 0x69, 0x7f, 0x81, 0x7f, 0x83, + 0x81, 0x7f, 0x7f, 0x7f, 0x81, 0x7f, 0x81, 0x81, 0x69, 0x81, 0x81, 0x38, 0x40, + 0xc8, 0x43, 0xb5, 0xe8, 0x56, 0x2f, 0x3d, 0xd3, 0x4b, 0xa6, 0xb8, 0x4f, 0xbb, + 0xc4, 0x16, 0x20, 0xd6, 0x01, 0xe1, 0xe3, 0x18, 0x63, 0x1d, 0xf3, 0x41, 0xdf, + 0xeb, 0x04, 0xe9, 0x18, 0x1d, 0x4c, 0xa4, 0x23, 0xc5, 0xd1, 0x2d, 0x58, 0x2b, + 0xeb, 0x53, 0xc8, 0xc9, 0x07, 0xe0, 0xfd, 0x13, 0x26, 0xeb, 0x24, 0xf9, 0x01, + 0x1c, 0x12, 0x12, 0x00, 0x23, 0xf0, 0xe3, 0x0e, 0xf8, 0xfc, 0x0c, 0x9a, 0xfc, + 0xff, 0x3a, 0x42, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x9c, 0x79, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x7c, + 0xf5, 0xff, 0xff, 0xf1, 0x1c, 0x00, 0x00, 0xcc, 0x3d, 0x00, 0x00, 0xdb, 0x02, + 0x00, 0x00, 0xc2, 0xff, 0xff, 0xff, 0x66, 0x42, 0xfd, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0xe7, 0xe7, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, + 0x1c, 0xf5, 0xff, 0xff, 0x54, 0x38, 0x00, 0x00, 0xdf, 0xe2, 0xff, 0xff, 0xbe, + 0x0b, 0x00, 0x00, 0xbe, 0x02, 0x00, 0x00, 0xc9, 0xed, 0xff, 0xff, 0xa7, 0x31, + 0x00, 0x00, 0x86, 0x2a, 0x00, 0x00, 0x48, 0x2b, 0x00, 0x00, 0x9d, 0xf3, 0xff, + 0xff, 0x00, 0xec, 0xff, 0xff, 0x2f, 0xe0, 0xff, 0xff, 0x94, 0x39, 0x00, 0x00, + 0x83, 0xd9, 0xff, 0xff, 0x50, 0x06, 0x00, 0x00, 0xd1, 0xfc, 0xff, 0xff, 0x1f, + 0xfd, 0xff, 0xff, 0x33, 0x2b, 0x00, 0x00, 0xa6, 0xf8, 0xff, 0xff, 0x8e, 0xde, + 0xff, 0xff, 0x78, 0x1c, 0x00, 0x00, 0xcc, 0x24, 0x00, 0x00, 0xfd, 0xed, 0xff, + 0xff, 0x55, 0x06, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0xb6, 0xe8, 0xff, 0xff, + 0x06, 0xf2, 0xff, 0xff, 0x6b, 0xf5, 0xff, 0xff, 0x83, 0xfc, 0xff, 0xff, 0x6b, + 0xf6, 0xff, 0xff, 0x99, 0xf9, 0xff, 0xff, 0xdd, 0xf0, 0xff, 0xff, 0x68, 0x38, + 0x00, 0x00, 0x22, 0xf1, 0xff, 0xff, 0xe3, 0xeb, 0xff, 0xff, 0x2a, 0xf3, 0xff, + 0xff, 0xc1, 0x32, 0x00, 0x00, 0xe5, 0xe5, 0xff, 0xff, 0x26, 0x26, 0x00, 0x00, + 0xfb, 0x08, 0x00, 0x00, 0x31, 0xf9, 0xff, 0xff, 0x56, 0xe6, 0xff, 0xff, 0xd5, + 0xe0, 0xff, 0xff, 0x40, 0xe8, 0xff, 0xff, 0xdf, 0xf1, 0xff, 0xff, 0x76, 0xf5, + 0xff, 0xff, 0x2e, 0xe4, 0xff, 0xff, 0xec, 0xf1, 0xff, 0xff, 0x19, 0xf5, 0xff, + 0xff, 0x03, 0x2c, 0x00, 0x00, 0xb4, 0xec, 0xff, 0xff, 0x57, 0xe2, 0xff, 0xff, + 0x26, 0xe7, 0xff, 0xff, 0xff, 0xfa, 0xff, 0xff, 0x2a, 0xf9, 0xff, 0xff, 0x91, + 0xf3, 0xff, 0xff, 0x2a, 0xec, 0xff, 0xff, 0xb1, 0xe3, 0xff, 0xff, 0xa0, 0xf7, + 0xff, 0xff, 0x0a, 0x28, 0x00, 0x00, 0xfb, 0xeb, 0xff, 0xff, 0xa2, 0xfb, 0xff, + 0xff, 0x62, 0x26, 0x00, 0x00, 0x82, 0xf0, 0xff, 0xff, 0x5e, 0x29, 0x00, 0x00, + 0xe7, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xf7, 0xff, 0xff, 0x40, + 0xfa, 0xff, 0xff, 0x70, 0x0a, 0x00, 0x00, 0xeb, 0xf5, 0xff, 0xff, 0x15, 0x2b, + 0x00, 0x00, 0xf0, 0xf2, 0xff, 0xff, 0x6f, 0x24, 0x00, 0x00, 0xd8, 0x11, 0x00, + 0x00, 0x79, 0x28, 0x00, 0x00, 0x1e, 0xf8, 0xff, 0xff, 0x76, 0xf9, 0xff, 0xff, + 0x12, 0xe8, 0xff, 0xff, 0xa4, 0x31, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, 0x89, + 0xea, 0xff, 0xff, 0xfe, 0xe3, 0xff, 0xff, 0xf5, 0x28, 0x00, 0x00, 0xf9, 0x1b, + 0x00, 0x00, 0xdd, 0xf8, 0xff, 0xff, 0xb1, 0x04, 0x00, 0x00, 0xb8, 0xf3, 0xff, + 0xff, 0x9f, 0x03, 0x00, 0x00, 0x92, 0xe7, 0xff, 0xff, 0x93, 0xfe, 0xff, 0xff, + 0xe6, 0x2d, 0x00, 0x00, 0xf7, 0x30, 0x00, 0x00, 0x6c, 0x36, 0x00, 0x00, 0x4a, + 0x0c, 0x00, 0x00, 0x4c, 0xf8, 0xff, 0xff, 0x12, 0xed, 0xff, 0xff, 0x67, 0xf8, + 0xff, 0xff, 0x29, 0x33, 0x00, 0x00, 0x08, 0xef, 0xff, 0xff, 0x72, 0x2b, 0x00, + 0x00, 0xed, 0xf4, 0xff, 0xff, 0x0b, 0x29, 0x00, 0x00, 0xf4, 0x2e, 0x00, 0x00, + 0x48, 0xfe, 0xff, 0xff, 0xd3, 0xf2, 0xff, 0xff, 0xde, 0xfd, 0xff, 0xff, 0xd9, + 0x08, 0x00, 0x00, 0x6e, 0x25, 0x00, 0x00, 0x9b, 0xf6, 0xff, 0xff, 0xf7, 0xea, + 0xff, 0xff, 0x82, 0x0a, 0x00, 0x00, 0x7d, 0x0e, 0x00, 0x00, 0x68, 0xee, 0xff, + 0xff, 0x0c, 0x27, 0x00, 0x00, 0xeb, 0x2e, 0x00, 0x00, 0xc9, 0xfe, 0xff, 0xff, + 0xda, 0x39, 0x00, 0x00, 0xd4, 0x32, 0x00, 0x00, 0x1e, 0x03, 0x00, 0x00, 0x1d, + 0xdf, 0xff, 0xff, 0xe8, 0xfb, 0xff, 0xff, 0x89, 0x07, 0x00, 0x00, 0xcd, 0x28, + 0x00, 0x00, 0x22, 0x1e, 0x00, 0x00, 0xe5, 0xf8, 0xff, 0xff, 0x48, 0x9c, 0xfc, + 0xff, 0x4c, 0x9c, 0xfc, 0xff, 0x50, 0x9c, 0xfc, 0xff, 0x54, 0x9c, 0xfc, 0xff, + 0x58, 0x9c, 0xfc, 0xff, 0x5c, 0x9c, 0xfc, 0xff, 0x8a, 0x44, 0xfd, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x62, 0xff, + 0xff, 0xff, 0xed, 0x4a, 0x00, 0x00, 0x94, 0xfe, 0xff, 0xff, 0x5d, 0x18, 0x00, + 0x00, 0x82, 0x2f, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, + 0x79, 0x01, 0x00, 0x00, 0x7d, 0x2c, 0x00, 0x00, 0xc2, 0x15, 0x00, 0x00, 0x74, + 0x36, 0x00, 0x00, 0x1a, 0x56, 0x00, 0x00, 0xa2, 0x11, 0x00, 0x00, 0x6c, 0x1d, + 0x00, 0x00, 0x29, 0x1e, 0x00, 0x00, 0xac, 0x9c, 0xfc, 0xff, 0xb0, 0x9c, 0xfc, + 0xff, 0xb4, 0x9c, 0xfc, 0xff, 0xb8, 0x9c, 0xfc, 0xff, 0xbc, 0x9c, 0xfc, 0xff, + 0xc0, 0x9c, 0xfc, 0xff, 0xc4, 0x9c, 0xfc, 0xff, 0xc8, 0x9c, 0xfc, 0xff, 0xcc, + 0x9c, 0xfc, 0xff, 0xd0, 0x9c, 0xfc, 0xff, 0xd4, 0x9c, 0xfc, 0xff, 0x02, 0x45, + 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x27, 0x00, + 0x00, 0x6a, 0x04, 0x00, 0x00, 0x00, 0xcd, 0xff, 0xff, 0xb4, 0x89, 0xff, 0xff, + 0xcb, 0xa4, 0xff, 0xff, 0x2a, 0x40, 0x00, 0x00, 0x76, 0x19, 0x00, 0x00, 0xd1, + 0xbd, 0xff, 0xff, 0x57, 0x0b, 0x00, 0x00, 0x4e, 0x32, 0x00, 0x00, 0x17, 0x46, + 0x00, 0x00, 0x15, 0xed, 0xff, 0xff, 0x10, 0x4a, 0x00, 0x00, 0x2c, 0x21, 0x00, + 0x00, 0xd1, 0xd7, 0xff, 0xff, 0x07, 0xdc, 0xff, 0xff, 0x4e, 0x45, 0xfd, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x1b, 0x31, 0x3b, 0x4d, 0x2e, + 0xfe, 0xe7, 0xae, 0xcf, 0x14, 0x7f, 0xfc, 0xe6, 0x08, 0x36, 0xa9, 0x01, 0x7a, + 0xdf, 0xf7, 0xf8, 0x0b, 0xed, 0x0e, 0xfe, 0xfc, 0xd3, 0x81, 0xf5, 0xbc, 0x02, + 0xf4, 0xa4, 0x81, 0x9a, 0xfa, 0xcd, 0xf0, 0x46, 0xd4, 0xd4, 0xcd, 0xa8, 0x37, + 0xb3, 0xb8, 0x2e, 0xe1, 0x51, 0x4e, 0xfa, 0x1f, 0xf2, 0xc3, 0xd9, 0x7f, 0x3c, + 0x0f, 0x4e, 0xe4, 0x7f, 0x81, 0x81, 0xb8, 0x16, 0x0a, 0x06, 0xb1, 0xbe, 0xf5, + 0x2a, 0xd4, 0x2f, 0x25, 0xd5, 0xac, 0x57, 0x29, 0xd3, 0xa5, 0xf0, 0x8d, 0x19, + 0x07, 0x81, 0x1b, 0xbe, 0x01, 0xe1, 0xea, 0xf6, 0xcc, 0xe9, 0x31, 0x2a, 0x12, + 0xf1, 0x46, 0x7f, 0x7f, 0x7f, 0xe0, 0x61, 0xbb, 0xdd, 0x0a, 0xe8, 0x04, 0xb7, + 0x11, 0x0c, 0xcd, 0x0a, 0x7f, 0xf6, 0x1e, 0xfe, 0xa6, 0xa4, 0x01, 0x64, 0xc9, + 0x4a, 0xa8, 0x43, 0xba, 0xc3, 0x7f, 0x81, 0x63, 0xbb, 0x00, 0xc6, 0x81, 0x7f, + 0x9e, 0x81, 0x81, 0xf7, 0x7f, 0x81, 0x81, 0x7f, 0x1d, 0x7f, 0xed, 0x7f, 0x81, + 0xe3, 0x7f, 0x9f, 0x3c, 0x7f, 0x81, 0x7f, 0x49, 0x61, 0x9f, 0xa2, 0x00, 0x13, + 0xa9, 0x55, 0xa7, 0xcf, 0xfa, 0x7e, 0x81, 0xf9, 0x16, 0x07, 0xac, 0xe6, 0x42, + 0xfa, 0xf0, 0x13, 0xa0, 0xbb, 0x30, 0x81, 0xf9, 0x81, 0xe7, 0xfc, 0xe6, 0xc0, + 0xc1, 0x2c, 0x78, 0xdf, 0xca, 0x0b, 0x97, 0x0f, 0x1e, 0xe8, 0x0e, 0xc8, 0xf6, + 0xf6, 0x14, 0x99, 0x09, 0xd9, 0x19, 0xd9, 0x81, 0xce, 0x24, 0x16, 0xf6, 0x42, + 0x40, 0xd6, 0xd9, 0xe4, 0x2b, 0x06, 0x9b, 0xea, 0xf5, 0x19, 0x0d, 0xfd, 0x68, + 0xc6, 0xef, 0xed, 0xee, 0xf7, 0x08, 0xe4, 0x09, 0x3b, 0x11, 0xaa, 0xe4, 0x08, + 0xff, 0x08, 0xb8, 0xde, 0x58, 0xed, 0xe2, 0x06, 0x07, 0x15, 0x62, 0x08, 0x83, + 0xe5, 0x14, 0xc7, 0x26, 0x16, 0x12, 0xc4, 0xf2, 0xf8, 0xf5, 0x03, 0x17, 0xee, + 0x0c, 0x28, 0x01, 0x1e, 0x15, 0x17, 0xd5, 0xc6, 0xb6, 0x00, 0xcf, 0xae, 0xed, + 0xdb, 0xfc, 0xe2, 0x2d, 0xf9, 0xdb, 0xe3, 0x37, 0xe7, 0x10, 0x7a, 0x46, 0xfd, + 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x81, 0x1c, 0x00, 0x00, + 0x0e, 0xfe, 0xff, 0xff, 0x07, 0x01, 0x00, 0x00, 0x49, 0xf8, 0xff, 0xff, 0xd4, + 0x08, 0x00, 0x00, 0x93, 0x25, 0x00, 0x00, 0x1f, 0xe7, 0xff, 0xff, 0xa9, 0x1c, + 0x00, 0x00, 0xc2, 0x3a, 0x00, 0x00, 0xe4, 0x1b, 0x00, 0x00, 0x9f, 0x06, 0x00, + 0x00, 0x37, 0xf8, 0xff, 0xff, 0x90, 0x5b, 0x00, 0x00, 0x57, 0x08, 0x00, 0x00, + 0x72, 0xfb, 0xff, 0xff, 0xc9, 0x7e, 0x00, 0x00, 0x19, 0x07, 0x00, 0x00, 0x67, + 0xff, 0xff, 0xff, 0x74, 0xff, 0xff, 0xff, 0x37, 0xff, 0xff, 0xff, 0x96, 0x30, + 0x00, 0x00, 0xb3, 0xfc, 0xff, 0xff, 0x52, 0x5d, 0x00, 0x00, 0x32, 0x03, 0x00, + 0x00, 0xdb, 0x04, 0x00, 0x00, 0x3f, 0x05, 0x00, 0x00, 0xa4, 0xfe, 0xff, 0xff, + 0xc1, 0x36, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x00, 0x00, 0x83, + 0x32, 0x00, 0x00, 0x09, 0xfa, 0xff, 0xff, 0x06, 0x47, 0xfd, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x13, 0xe9, 0xd2, 0x14, 0x97, 0x41, 0xa4, + 0xeb, 0x07, 0x1d, 0x32, 0xfb, 0xf7, 0x0a, 0xe6, 0xfe, 0xbd, 0x6c, 0x2d, 0x1c, + 0xd1, 0x3a, 0x16, 0x2d, 0x1e, 0xf8, 0x7f, 0x13, 0x1b, 0xc3, 0x50, 0x2b, 0xf9, + 0x17, 0xfd, 0xe6, 0x16, 0xea, 0xe0, 0x98, 0xcd, 0x32, 0xeb, 0x3c, 0x10, 0xf8, + 0x1b, 0xef, 0xf1, 0x10, 0x35, 0x00, 0x0b, 0x13, 0x03, 0xb3, 0xdf, 0x05, 0x7f, + 0xdd, 0xae, 0x3d, 0x3b, 0xf7, 0x62, 0xbe, 0xf2, 0xba, 0x28, 0x10, 0xfb, 0x98, + 0xa5, 0x21, 0x31, 0x27, 0xec, 0xfd, 0xe4, 0x1c, 0x09, 0xe2, 0x44, 0x0d, 0x28, + 0x28, 0xf9, 0xd5, 0x43, 0xe8, 0xcc, 0x27, 0xbe, 0x81, 0xa7, 0xd8, 0x1d, 0xe1, + 0x00, 0xe9, 0x33, 0x5a, 0x59, 0xf8, 0x81, 0xa4, 0x12, 0x00, 0xa1, 0x01, 0x26, + 0x29, 0x37, 0x27, 0xe7, 0xfd, 0x12, 0xcc, 0xe1, 0xd7, 0x01, 0x5f, 0x1b, 0xf5, + 0x5c, 0x1c, 0xc2, 0xb4, 0xe3, 0xed, 0xee, 0x03, 0xdc, 0xbb, 0xdc, 0x71, 0xb4, + 0xb9, 0xf2, 0xf3, 0xba, 0xc9, 0x18, 0x25, 0xd3, 0xe0, 0x89, 0xdd, 0x30, 0xc3, + 0x7f, 0xfb, 0x3e, 0x58, 0xca, 0x55, 0xa7, 0xec, 0xcc, 0xf0, 0xfb, 0x01, 0xf4, + 0xb8, 0xe8, 0x09, 0x04, 0x39, 0x02, 0x81, 0xcc, 0xbe, 0xc9, 0x06, 0xd1, 0x11, + 0xbe, 0xde, 0xe4, 0xf7, 0x2f, 0xf2, 0x38, 0x04, 0xd2, 0x52, 0xf2, 0x07, 0x24, + 0xd5, 0xbf, 0x06, 0x14, 0xf7, 0x49, 0x08, 0xd8, 0xc9, 0xae, 0x1b, 0x6e, 0x40, + 0xca, 0x7f, 0x51, 0x1f, 0xf0, 0xf8, 0x2b, 0x2b, 0xff, 0xf9, 0x0a, 0xe4, 0x1e, + 0x14, 0xc6, 0xf9, 0x27, 0x42, 0x0e, 0x38, 0x14, 0x01, 0xde, 0xea, 0x3b, 0x35, + 0x60, 0xf5, 0x2d, 0xea, 0xab, 0x4e, 0x33, 0x73, 0x58, 0x6f, 0x02, 0x20, 0x7d, + 0x30, 0x1e, 0x0d, 0xd6, 0x1a, 0xe9, 0x60, 0xb7, 0x0f, 0x11, 0x8e, 0x26, 0x29, + 0x1f, 0x7f, 0x16, 0xe3, 0x23, 0x75, 0x11, 0x81, 0xf0, 0xc4, 0xef, 0x13, 0x0b, + 0x43, 0xaf, 0x20, 0x1a, 0x01, 0x49, 0xa6, 0xff, 0x0f, 0x24, 0xfe, 0x05, 0x2f, + 0x4b, 0xbb, 0xce, 0x4a, 0x12, 0x50, 0x22, 0xf4, 0xc5, 0x08, 0x0c, 0x1f, 0x2a, + 0x58, 0xfa, 0xf7, 0x30, 0x30, 0xde, 0x4a, 0xa8, 0xf3, 0x21, 0x59, 0x19, 0x1e, + 0xdb, 0x0c, 0x17, 0x03, 0xb5, 0x91, 0xdc, 0xed, 0x09, 0xbe, 0x81, 0xfb, 0xe6, + 0xcc, 0x2b, 0x76, 0x55, 0xca, 0xf0, 0xe6, 0xef, 0xee, 0x19, 0xc7, 0xba, 0xb4, + 0x28, 0x20, 0xd1, 0x7f, 0x0a, 0xf4, 0x10, 0xf9, 0xe4, 0x01, 0xfe, 0xdb, 0x1e, + 0x36, 0x28, 0xd4, 0x21, 0xef, 0xdc, 0x00, 0xe7, 0x3e, 0x52, 0x12, 0xa5, 0x29, + 0x09, 0xad, 0x87, 0x81, 0x10, 0x9f, 0x49, 0xca, 0x1c, 0xb0, 0xe4, 0x23, 0xbe, + 0xde, 0x28, 0x0e, 0x22, 0xcf, 0xe9, 0xaf, 0x10, 0xf7, 0xdf, 0x10, 0x0a, 0xf6, + 0x04, 0xe5, 0xfd, 0x00, 0xe5, 0xfe, 0x81, 0x09, 0xc6, 0x1f, 0x10, 0x15, 0xcf, + 0xe7, 0x05, 0xc2, 0xd2, 0x09, 0x04, 0x15, 0xf6, 0x37, 0x65, 0x18, 0xd5, 0x06, + 0x4a, 0xcf, 0x1d, 0xfe, 0x0b, 0xe0, 0xed, 0x02, 0x15, 0x09, 0x03, 0xd4, 0xd7, + 0xec, 0x53, 0xe0, 0x03, 0x21, 0x7f, 0xfa, 0xf9, 0xf8, 0xed, 0x1a, 0x11, 0xf6, + 0xeb, 0xfe, 0x46, 0x2a, 0x3a, 0xd3, 0x5b, 0x1b, 0x0d, 0x08, 0x3d, 0x14, 0x3a, + 0xdf, 0x14, 0x16, 0xea, 0x25, 0xf7, 0x14, 0xfa, 0x3a, 0xe7, 0x05, 0x0f, 0x0b, + 0xe1, 0xeb, 0x13, 0x1a, 0xf4, 0xe1, 0x0d, 0xe9, 0x0f, 0xde, 0x7f, 0xfd, 0xfc, + 0xe9, 0x0d, 0x0d, 0x03, 0xf9, 0xc0, 0x28, 0xdd, 0x07, 0x04, 0xe5, 0xf9, 0x0c, + 0xe8, 0x87, 0x07, 0x06, 0xe7, 0xb2, 0x10, 0x1c, 0x81, 0xf1, 0x12, 0xf9, 0x12, + 0xf6, 0x11, 0x70, 0x24, 0x2e, 0x55, 0xda, 0xe4, 0xe8, 0x9e, 0x00, 0xf1, 0x60, + 0x0f, 0x03, 0xb9, 0xa3, 0x2f, 0x29, 0x34, 0xe5, 0xf8, 0x0f, 0x22, 0xec, 0x31, + 0xec, 0xea, 0xf1, 0xf5, 0xfd, 0x05, 0x18, 0x65, 0xda, 0x2e, 0x14, 0x3d, 0xcc, + 0x4e, 0x1f, 0x1f, 0x7f, 0xba, 0xc6, 0xfb, 0x22, 0x23, 0x61, 0x48, 0x32, 0x73, + 0x81, 0xf5, 0xfc, 0x50, 0xdd, 0xd7, 0x05, 0xe4, 0x0a, 0xa0, 0xf5, 0xe7, 0xce, + 0x3b, 0xce, 0xaa, 0xc1, 0xda, 0xd1, 0x2d, 0x08, 0xcb, 0xea, 0xfd, 0x07, 0xfd, + 0x02, 0x06, 0xf4, 0xed, 0xfb, 0xcc, 0x7f, 0xf1, 0x29, 0x01, 0x2a, 0xd5, 0x2b, + 0x4b, 0x01, 0x2f, 0x01, 0xde, 0x12, 0xf7, 0xe6, 0x13, 0xea, 0x06, 0x1c, 0xe8, + 0x05, 0x0a, 0x13, 0xf7, 0xfa, 0x07, 0x0a, 0xf0, 0xf8, 0xcf, 0x0c, 0x57, 0x3d, + 0x29, 0x2c, 0x06, 0x13, 0x7f, 0xbd, 0xe2, 0xf8, 0x09, 0x19, 0xf6, 0x13, 0x44, + 0x24, 0xf5, 0xed, 0xc4, 0x3c, 0xa0, 0xff, 0x22, 0x50, 0x04, 0xf7, 0xf5, 0xf0, + 0x03, 0x07, 0xc1, 0x04, 0x12, 0x07, 0x17, 0x08, 0x09, 0xff, 0xf3, 0xfd, 0xeb, + 0xff, 0xf4, 0xf9, 0xd8, 0x7f, 0xdb, 0xed, 0xec, 0x3d, 0x32, 0xf9, 0xea, 0x0b, + 0xe4, 0xfa, 0x28, 0xb0, 0xb8, 0xeb, 0x08, 0x3d, 0xda, 0x41, 0x34, 0xcf, 0x27, + 0xf3, 0x21, 0x03, 0xba, 0x17, 0xe2, 0xc6, 0xa2, 0xe1, 0x4d, 0xdd, 0xd6, 0x81, + 0x17, 0xfd, 0xf5, 0xf0, 0x19, 0xe9, 0x58, 0xd3, 0x30, 0xfa, 0x31, 0xe1, 0xfe, + 0x35, 0x6e, 0xfd, 0x6d, 0x04, 0x9e, 0xec, 0x58, 0x2f, 0xa4, 0x1d, 0x81, 0x01, + 0x0b, 0xf1, 0x01, 0xfb, 0xff, 0x25, 0xed, 0xc6, 0xe4, 0x5c, 0xde, 0xfb, 0xd1, + 0x40, 0xea, 0x7f, 0x2a, 0xe3, 0x05, 0xd8, 0xf4, 0x07, 0xf9, 0x33, 0x60, 0xdf, + 0x16, 0x02, 0x05, 0xf0, 0xe8, 0xe0, 0x41, 0x14, 0x01, 0x06, 0xda, 0x08, 0x0c, + 0x01, 0x21, 0xef, 0xdd, 0x00, 0x20, 0xf4, 0x0a, 0xed, 0xde, 0x20, 0xf2, 0xdf, + 0xe7, 0x0b, 0xfd, 0x06, 0xf9, 0x04, 0xe5, 0xfa, 0xf6, 0x1d, 0x0b, 0xfc, 0x22, + 0x7f, 0x07, 0x71, 0x02, 0x03, 0x18, 0x02, 0xd6, 0x06, 0xe4, 0x02, 0x02, 0xfe, + 0x1f, 0xd1, 0xf9, 0x0f, 0xfe, 0xf2, 0xf2, 0x0a, 0xe0, 0xf9, 0x11, 0xfa, 0x34, + 0xf5, 0xe4, 0xbd, 0xf8, 0x0c, 0x7f, 0xeb, 0xe0, 0x2f, 0xc5, 0x14, 0xd2, 0xf9, + 0x11, 0x09, 0xd8, 0x14, 0x34, 0xf2, 0xf3, 0xfe, 0xe8, 0xff, 0xea, 0xf2, 0x3b, + 0x18, 0x0b, 0xdd, 0x0d, 0xfe, 0xd0, 0x03, 0x1c, 0xe3, 0x7f, 0x18, 0xcc, 0xd5, + 0x23, 0x25, 0x20, 0xb8, 0x0a, 0x36, 0xef, 0x2e, 0x2c, 0x03, 0xf8, 0x03, 0xff, + 0xf4, 0xd6, 0xf2, 0x1b, 0x7f, 0x39, 0x1f, 0xe1, 0x1a, 0x03, 0x17, 0x02, 0xd5, + 0xe2, 0xff, 0xdb, 0xbf, 0x1b, 0xff, 0x09, 0xdc, 0xf5, 0x65, 0xf4, 0x12, 0x02, + 0xe0, 0x3a, 0x0c, 0xee, 0xd2, 0xfe, 0xf7, 0x12, 0x1b, 0x01, 0xb8, 0xe0, 0xee, + 0xc6, 0x1c, 0x07, 0x06, 0x9d, 0xfd, 0xcc, 0x53, 0x1c, 0xff, 0x1a, 0xe4, 0x1c, + 0xf2, 0xf1, 0x48, 0x21, 0x1c, 0x7f, 0x20, 0xf0, 0xe2, 0x9c, 0x0b, 0x22, 0xda, + 0x13, 0x41, 0x3d, 0x1b, 0xfc, 0xf5, 0xf2, 0x19, 0x09, 0x7f, 0x15, 0x5a, 0xfc, + 0x20, 0x3b, 0x63, 0x1a, 0xf6, 0xe2, 0x00, 0xe8, 0xed, 0xd0, 0xf4, 0xbb, 0x03, + 0x41, 0x2c, 0x32, 0x39, 0xf8, 0x62, 0xf7, 0xfb, 0xda, 0x16, 0x21, 0xfe, 0x35, + 0x2b, 0x41, 0x13, 0xd1, 0x0f, 0x78, 0x50, 0xfe, 0x04, 0x2f, 0x1e, 0xe1, 0x09, + 0x31, 0x0d, 0xf2, 0xf5, 0x0b, 0xee, 0x08, 0xe8, 0xf8, 0x7f, 0x95, 0xb5, 0x00, + 0x29, 0x04, 0x12, 0x01, 0x20, 0x42, 0x81, 0x19, 0x09, 0xeb, 0xe6, 0xe6, 0xe1, + 0x1a, 0xca, 0xf8, 0x01, 0xf5, 0xc9, 0xec, 0xa8, 0xe7, 0xba, 0xd2, 0x27, 0x00, + 0x3f, 0x22, 0xba, 0x12, 0x4b, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x20, 0x01, + 0x00, 0x00, 0xb2, 0x3b, 0xbe, 0xc6, 0x7f, 0xe4, 0x20, 0x29, 0xa7, 0x18, 0xe5, + 0xfe, 0x3c, 0xcf, 0x64, 0x43, 0x27, 0xa0, 0xd5, 0x52, 0xbb, 0x59, 0xc8, 0x39, + 0xcc, 0x50, 0x68, 0x54, 0xaa, 0x81, 0x05, 0x15, 0xab, 0x52, 0x9e, 0x96, 0x1f, + 0xae, 0x36, 0x31, 0x81, 0xd7, 0xa7, 0xe6, 0x64, 0x81, 0x7f, 0x5a, 0x5c, 0x93, + 0xaa, 0x64, 0xb4, 0x7f, 0xb9, 0x5b, 0xac, 0x67, 0x7f, 0x52, 0x88, 0x96, 0xb5, + 0x41, 0xf3, 0x33, 0xe1, 0xbf, 0xb8, 0xc5, 0x19, 0x0e, 0xb8, 0xcc, 0xcf, 0xe2, + 0x47, 0xaf, 0x27, 0x28, 0x33, 0xc4, 0xc8, 0x2a, 0xf0, 0x36, 0xf7, 0x2b, 0xd4, + 0x35, 0x21, 0x07, 0xd1, 0xe5, 0xb1, 0x2c, 0xca, 0x70, 0xbc, 0xa3, 0x6a, 0xb9, + 0x50, 0x53, 0xaf, 0xc1, 0xad, 0xb4, 0x65, 0x23, 0x60, 0x63, 0x3d, 0x8e, 0x9e, + 0x66, 0xba, 0x58, 0xa4, 0x46, 0xa6, 0x5f, 0x73, 0x71, 0xaf, 0xcd, 0xaf, 0x43, + 0x81, 0x7f, 0x81, 0x81, 0xfe, 0x81, 0x7f, 0x7f, 0xa7, 0x81, 0x81, 0x81, 0x7f, + 0x2c, 0x7c, 0x7f, 0x7f, 0x81, 0x81, 0x7f, 0x81, 0x66, 0x81, 0x7f, 0x81, 0x7f, + 0x7d, 0x7f, 0x81, 0xa4, 0x81, 0x7f, 0xb5, 0x37, 0xba, 0xb4, 0xad, 0xb3, 0x47, + 0x4a, 0xe3, 0xb2, 0xc5, 0xaf, 0x3c, 0xfe, 0x2f, 0x2a, 0x36, 0xc8, 0xcf, 0x3a, + 0xc6, 0x0f, 0xc2, 0x41, 0xca, 0x3d, 0x1f, 0x21, 0xcc, 0xc2, 0xc1, 0x44, 0x04, + 0x45, 0xdc, 0xd5, 0x23, 0xc8, 0x38, 0x49, 0xfd, 0xc0, 0xd2, 0xa9, 0x47, 0x2e, + 0x11, 0x28, 0x23, 0xd1, 0xc6, 0x23, 0xef, 0xf9, 0xc9, 0x18, 0xd6, 0x2d, 0x1f, + 0x2f, 0xdf, 0xf8, 0xa8, 0x2e, 0xab, 0x3b, 0xbb, 0xc5, 0xdf, 0xbf, 0x59, 0x63, + 0xfc, 0xaa, 0xc6, 0x84, 0x46, 0x59, 0x10, 0x36, 0x39, 0xd8, 0xc2, 0x32, 0xcd, + 0xcc, 0xb2, 0x32, 0xcc, 0x31, 0x1b, 0x46, 0xd6, 0xd7, 0xcb, 0x46, 0xa7, 0x09, + 0xc8, 0xe3, 0xd8, 0xe8, 0x3b, 0x23, 0x0d, 0xd3, 0xe3, 0xd3, 0xfe, 0x30, 0x0b, + 0x13, 0x16, 0x03, 0x02, 0x13, 0xdd, 0xd5, 0xd6, 0x19, 0xf0, 0x0b, 0x04, 0x2d, + 0xed, 0xd0, 0x08, 0x1f, 0x3e, 0x4c, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0xac, 0x6f, 0x00, 0x00, 0x6b, 0x01, 0x00, 0x00, 0xc8, 0x6b, + 0x00, 0x00, 0x16, 0x57, 0x00, 0x00, 0x08, 0xef, 0xff, 0xff, 0xb3, 0x6a, 0x00, + 0x00, 0x5d, 0x04, 0x00, 0x00, 0xef, 0xfb, 0xff, 0xff, 0x67, 0x65, 0x00, 0x00, + 0x6a, 0xa4, 0x00, 0x00, 0xb1, 0x56, 0x00, 0x00, 0x6b, 0x6f, 0x00, 0x00, 0xde, + 0xf9, 0xff, 0xff, 0xa9, 0xff, 0xff, 0xff, 0xb7, 0xe7, 0xff, 0xff, 0xe4, 0xff, + 0xff, 0xff, 0xd3, 0x00, 0x00, 0x00, 0x87, 0x91, 0x00, 0x00, 0x8e, 0x43, 0x00, + 0x00, 0x32, 0xff, 0xff, 0xff, 0xd6, 0x42, 0x00, 0x00, 0xe5, 0xfd, 0xff, 0xff, + 0xf1, 0xa7, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0xcf, 0x2b, 0x00, 0x00, 0x24, + 0xff, 0xff, 0xff, 0x0e, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf8, 0x74, + 0x00, 0x00, 0x5c, 0x6c, 0x00, 0x00, 0xd0, 0x3f, 0x00, 0x00, 0xdb, 0x03, 0x00, + 0x00, 0xca, 0x4c, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0xf7, 0xee, 0xf3, 0x35, 0xfa, 0xb2, 0xf7, 0x5f, 0x50, 0xfe, 0xd6, 0xfc, 0x11, + 0x20, 0xd5, 0x97, 0x20, 0x00, 0xe1, 0xf7, 0xb7, 0x33, 0xec, 0xf1, 0xd1, 0x13, + 0xfb, 0x4f, 0x7f, 0xa5, 0xfa, 0x8e, 0xe5, 0xe7, 0xfa, 0x34, 0x03, 0xf4, 0xee, + 0x21, 0x01, 0x95, 0x0f, 0x8b, 0x07, 0x03, 0xa3, 0xc8, 0xf1, 0xd3, 0x0e, 0xd7, + 0x1a, 0xeb, 0xe4, 0x0d, 0x28, 0xf5, 0xa1, 0x7f, 0x36, 0xfb, 0x10, 0x1d, 0x0e, + 0x7f, 0x0b, 0xf1, 0x39, 0x04, 0x1e, 0xdb, 0xb1, 0xf6, 0xd4, 0x13, 0xf3, 0x35, + 0xef, 0x0d, 0x2a, 0xb5, 0x0e, 0xc8, 0xf0, 0xdf, 0x25, 0x6e, 0xe2, 0xf7, 0x10, + 0x3c, 0xcf, 0x07, 0x0f, 0xe6, 0x45, 0xdd, 0x17, 0xef, 0x33, 0xcf, 0xe1, 0x34, + 0x08, 0x34, 0xf6, 0x0e, 0xfa, 0xfb, 0xfc, 0x7f, 0xf7, 0xe5, 0x1a, 0xea, 0x11, + 0x1b, 0xfb, 0x95, 0x17, 0xfe, 0xc7, 0xb3, 0xde, 0x22, 0xe7, 0xea, 0xdc, 0x53, + 0x2a, 0x12, 0xdb, 0x6c, 0x16, 0xbc, 0x01, 0x46, 0xef, 0xdc, 0x27, 0xf8, 0xbe, + 0x99, 0x43, 0xe8, 0x9a, 0xc0, 0x93, 0xc0, 0xfe, 0xf6, 0xc8, 0x7f, 0xfd, 0x07, + 0xd8, 0xe8, 0x20, 0x35, 0xe5, 0xd2, 0x71, 0xf5, 0xdf, 0xc7, 0xb0, 0x1d, 0x12, + 0xde, 0xef, 0x17, 0x01, 0x3a, 0x11, 0x6d, 0x04, 0x1b, 0x68, 0x7f, 0x1b, 0xce, + 0x1d, 0xef, 0xe8, 0xd5, 0xeb, 0x35, 0xda, 0x11, 0xb5, 0xfb, 0xf9, 0xe4, 0xe3, + 0x24, 0x17, 0x02, 0x20, 0xac, 0xf2, 0x48, 0x11, 0xe2, 0xfe, 0xbe, 0xd4, 0x81, + 0x67, 0xbd, 0x2d, 0xea, 0xe8, 0xec, 0xcf, 0xf7, 0xd9, 0x44, 0x95, 0xea, 0x01, + 0xd2, 0x08, 0xf5, 0x1a, 0xb5, 0x4d, 0xe1, 0x15, 0xe9, 0x01, 0xea, 0xaa, 0xda, + 0x1f, 0xd1, 0xf8, 0x11, 0xbd, 0x3b, 0x81, 0xdb, 0xf5, 0xfb, 0xe0, 0xf8, 0xe5, + 0x1e, 0xf7, 0xf7, 0x6d, 0x0d, 0xf3, 0xeb, 0x00, 0x7d, 0x2e, 0xf5, 0x20, 0xe6, + 0xcb, 0xf3, 0x09, 0x09, 0x13, 0x1f, 0xeb, 0xfb, 0xc0, 0x02, 0x27, 0x7f, 0xff, + 0x2b, 0x26, 0x27, 0xea, 0x30, 0x73, 0xbd, 0xfa, 0xc7, 0x16, 0xb0, 0x2c, 0xfd, + 0x20, 0xf0, 0xce, 0x1c, 0x16, 0xe7, 0xf2, 0xd9, 0x00, 0xf9, 0x19, 0xe4, 0xe5, + 0xf1, 0x11, 0x3b, 0xbd, 0xf0, 0x2e, 0x0c, 0x2c, 0xe3, 0xd5, 0x01, 0xf3, 0xfc, + 0xef, 0x7f, 0x08, 0x10, 0xf3, 0xff, 0xff, 0xf9, 0x20, 0xff, 0x09, 0x81, 0x51, + 0x0d, 0xc6, 0x32, 0xf5, 0x07, 0x12, 0xc4, 0xe4, 0xf4, 0x24, 0x22, 0x06, 0x1d, + 0xe8, 0x0b, 0xf3, 0xf5, 0x61, 0x00, 0x1b, 0x4f, 0x13, 0xd9, 0x0f, 0x16, 0x03, + 0x4f, 0xc6, 0x35, 0x5b, 0x38, 0xd7, 0x0d, 0xf9, 0xce, 0xd0, 0xad, 0x1b, 0xfb, + 0xf8, 0xd4, 0x0f, 0xf6, 0xfb, 0x13, 0x23, 0x3a, 0x52, 0x6a, 0x09, 0x81, 0xfe, + 0x36, 0x0d, 0xf8, 0x29, 0xc6, 0xec, 0xf8, 0xf6, 0x54, 0x31, 0x02, 0x09, 0x5d, + 0x7f, 0x1d, 0xed, 0xed, 0xcf, 0xe5, 0xb1, 0xe4, 0x40, 0x17, 0x90, 0xab, 0xa0, + 0xc9, 0x13, 0xd2, 0x3b, 0x13, 0x0a, 0x18, 0x55, 0xfc, 0x6b, 0x95, 0x2a, 0xfb, + 0xa0, 0x16, 0x0b, 0xa7, 0x01, 0x09, 0x1e, 0x0f, 0x22, 0x61, 0x24, 0x51, 0xdc, + 0x27, 0x38, 0xdc, 0xd8, 0xdf, 0xce, 0x56, 0xe3, 0xf1, 0x7f, 0x66, 0xbb, 0x31, + 0xf8, 0xba, 0xe9, 0x02, 0xbb, 0x45, 0x0c, 0x23, 0x32, 0xef, 0x0e, 0x1a, 0xd6, + 0x00, 0xf0, 0xd7, 0xb9, 0xe0, 0xd7, 0x07, 0xd6, 0xf9, 0x25, 0xee, 0xe8, 0x43, + 0x35, 0xe0, 0x7f, 0x4f, 0xde, 0xf0, 0xe3, 0xda, 0x32, 0xfe, 0xa4, 0x23, 0x0c, + 0xf7, 0xd2, 0x04, 0xf4, 0x0d, 0xe3, 0x10, 0xef, 0xd9, 0xe9, 0xc3, 0xf8, 0xe2, + 0xf5, 0xd1, 0xf9, 0xe7, 0x00, 0xdb, 0x09, 0xbd, 0x2d, 0x16, 0x0f, 0x05, 0xf4, + 0x7f, 0x04, 0xe4, 0x09, 0xf5, 0xf8, 0xda, 0x0f, 0xd9, 0xef, 0x10, 0x0c, 0x12, + 0xc4, 0xec, 0xa7, 0x16, 0xb6, 0x00, 0x3f, 0x6c, 0xf2, 0x11, 0xab, 0x81, 0x14, + 0xc3, 0x52, 0xa4, 0x09, 0x93, 0x36, 0x0b, 0xc8, 0xa9, 0xf4, 0xf0, 0xe3, 0xf4, + 0x00, 0x20, 0x11, 0xec, 0x71, 0x15, 0x0b, 0x28, 0x13, 0xfd, 0xc4, 0x11, 0x7f, + 0x0d, 0x14, 0xad, 0x98, 0xf5, 0xdc, 0x43, 0x0b, 0xb6, 0xf4, 0xe1, 0xe9, 0xb8, + 0xdf, 0x82, 0xb4, 0x17, 0xd9, 0xd6, 0x06, 0x28, 0xfa, 0x1d, 0x46, 0x98, 0x28, + 0x7f, 0x34, 0x47, 0x34, 0x06, 0x53, 0xfb, 0xeb, 0x25, 0x23, 0x51, 0xea, 0x16, + 0xc8, 0xf9, 0xfc, 0x14, 0xf5, 0x57, 0x1c, 0x46, 0x60, 0xda, 0x0f, 0x39, 0xc2, + 0x9a, 0xc3, 0xa9, 0x1d, 0xda, 0x68, 0xe6, 0xdc, 0xec, 0x08, 0xc6, 0x9a, 0x3d, + 0x07, 0x1c, 0xd7, 0xf0, 0xfc, 0x7f, 0x43, 0x54, 0x31, 0x09, 0x6e, 0x1d, 0xd3, + 0x5e, 0x22, 0xb7, 0xda, 0x46, 0x1a, 0x55, 0x14, 0xf4, 0x0a, 0x3f, 0xdf, 0xf6, + 0x24, 0xd7, 0x00, 0x01, 0x0a, 0x4a, 0xed, 0x81, 0x36, 0x27, 0x06, 0x5f, 0xf2, + 0x01, 0xf2, 0x0d, 0xac, 0xf0, 0xf2, 0x12, 0xe2, 0xeb, 0xcd, 0xb4, 0xdf, 0x36, + 0xc6, 0xd1, 0x47, 0xe2, 0xe3, 0xe7, 0xf6, 0x7f, 0x04, 0x0d, 0xef, 0x51, 0xe0, + 0x0c, 0xdf, 0x14, 0xf8, 0xad, 0xfc, 0x17, 0xf8, 0xbd, 0xe1, 0x49, 0xf1, 0x2a, + 0x07, 0xe4, 0xf7, 0xf3, 0x05, 0x07, 0xe7, 0x4c, 0x55, 0xef, 0x10, 0x21, 0x05, + 0x1f, 0xdf, 0xfa, 0x72, 0xf8, 0xd8, 0x33, 0xf3, 0xc4, 0x08, 0x19, 0x59, 0xe3, + 0xfb, 0x14, 0x33, 0xff, 0x7f, 0xe5, 0x1a, 0x08, 0xd3, 0xca, 0x3b, 0xdd, 0x0f, + 0x22, 0xd1, 0x28, 0x0f, 0x06, 0xf3, 0xd6, 0x14, 0x12, 0x3b, 0x24, 0x7f, 0xab, + 0xd6, 0xf2, 0xef, 0xd2, 0xb9, 0x41, 0x16, 0xfc, 0xd8, 0xfe, 0xfa, 0xe0, 0x11, + 0x30, 0x4c, 0x34, 0xff, 0xf8, 0x1d, 0x47, 0x7f, 0xe0, 0xee, 0xd6, 0x20, 0xe0, + 0xbb, 0xee, 0x3c, 0x15, 0xd8, 0xcd, 0x04, 0x17, 0x1b, 0xbd, 0x4c, 0x39, 0x47, + 0x50, 0xcb, 0xe2, 0xfa, 0xd0, 0x28, 0xf3, 0xb9, 0xcb, 0xd4, 0x1c, 0xe8, 0x7e, + 0x60, 0xcb, 0xc7, 0xd3, 0xdf, 0x3c, 0x06, 0xff, 0xaf, 0xcc, 0x02, 0x4a, 0xe4, + 0x1e, 0xd9, 0xe2, 0x81, 0x2e, 0xdf, 0x24, 0xeb, 0x50, 0xd3, 0x00, 0xb3, 0xd1, + 0xc5, 0x20, 0xda, 0x18, 0x13, 0x37, 0x7f, 0x1e, 0x12, 0x12, 0x14, 0xdf, 0x03, + 0xed, 0x31, 0xc1, 0xd4, 0x29, 0xc1, 0xdf, 0xeb, 0xd1, 0xea, 0x1b, 0x1a, 0x01, + 0xf4, 0x08, 0x03, 0xed, 0xf7, 0x23, 0xea, 0x16, 0xf8, 0xf8, 0xfb, 0x08, 0xc9, + 0xc7, 0xf8, 0x12, 0x25, 0x0b, 0x0f, 0xf5, 0x7f, 0x19, 0x1f, 0xd8, 0xaf, 0x19, + 0x06, 0x12, 0xff, 0x21, 0xe3, 0xfd, 0xee, 0xf8, 0xed, 0x00, 0xea, 0x30, 0x11, + 0xfb, 0x41, 0x41, 0x04, 0xf5, 0xad, 0xe3, 0xe4, 0x11, 0x33, 0x05, 0xd5, 0xfe, + 0x5a, 0x59, 0x1a, 0x0a, 0xdd, 0x72, 0x20, 0xbc, 0x07, 0xe3, 0xf5, 0xf6, 0xd7, + 0x2e, 0x7f, 0x0c, 0xba, 0xe6, 0xb0, 0x15, 0x32, 0x12, 0x8e, 0xee, 0xc4, 0x16, + 0x29, 0xf5, 0xc7, 0x3a, 0xd3, 0x7f, 0xfd, 0xea, 0x74, 0xbd, 0xbf, 0xe8, 0xcf, + 0x00, 0x1c, 0xff, 0xf9, 0xde, 0x7d, 0xfe, 0xfe, 0xfa, 0xdd, 0xee, 0xd4, 0xa6, + 0x24, 0xc6, 0xe9, 0x99, 0x81, 0xfa, 0x4d, 0xa9, 0x4e, 0x4f, 0xd7, 0x30, 0xe8, + 0xe4, 0x19, 0x00, 0x0f, 0x2a, 0x1e, 0x08, 0xa3, 0x05, 0xb9, 0x10, 0x59, 0x54, + 0xf2, 0xdc, 0xaf, 0xe0, 0x17, 0x7f, 0xba, 0xfd, 0x13, 0xe6, 0x2e, 0xdd, 0xce, + 0x13, 0xed, 0xd4, 0xef, 0x1a, 0xe8, 0xf4, 0x17, 0x3a, 0x01, 0x4c, 0xe8, 0xf7, + 0x77, 0xc0, 0x15, 0xbb, 0x04, 0x51, 0x06, 0xe6, 0xf1, 0xee, 0xfa, 0x18, 0x3e, + 0x24, 0xd3, 0x07, 0xcd, 0xd0, 0xf1, 0xf3, 0x21, 0xd9, 0x0f, 0xdf, 0x9e, 0x16, + 0xea, 0xde, 0x31, 0x32, 0xed, 0xf4, 0x03, 0x1a, 0xd2, 0x7f, 0xdc, 0x0b, 0xee, + 0x1c, 0x0c, 0x0d, 0x22, 0xdd, 0xbc, 0x96, 0x46, 0xde, 0xc5, 0x4c, 0x22, 0xbc, + 0x0e, 0x57, 0x1c, 0x23, 0x74, 0xf8, 0x81, 0x87, 0x22, 0x2a, 0x28, 0x31, 0xc8, + 0xdb, 0x12, 0x47, 0x13, 0xf1, 0x35, 0x37, 0xb7, 0xd6, 0xb7, 0x15, 0x01, 0xf2, + 0x0d, 0x60, 0xdf, 0x04, 0x06, 0x27, 0x77, 0x04, 0x5f, 0xf5, 0xcd, 0xea, 0xf3, + 0xb1, 0x56, 0xae, 0x81, 0xef, 0xeb, 0x12, 0x1a, 0x74, 0x4a, 0x25, 0x14, 0x8e, + 0x46, 0x22, 0x13, 0xfc, 0x23, 0xee, 0xf1, 0x0c, 0xd2, 0xf0, 0xfb, 0xf3, 0xeb, + 0xf4, 0x09, 0xdf, 0xcc, 0xdf, 0xf9, 0x2e, 0x03, 0x7f, 0x21, 0xf0, 0x1f, 0xfc, + 0x9a, 0x2f, 0xd9, 0x03, 0xfa, 0x0a, 0xbf, 0x56, 0x1b, 0x0e, 0xfd, 0xda, 0xf8, + 0x19, 0xb6, 0x36, 0xdc, 0xa4, 0xda, 0xe2, 0xf1, 0x33, 0xe8, 0xa1, 0x29, 0xe9, + 0xf8, 0xcd, 0x1e, 0x6a, 0x7f, 0x0a, 0xfe, 0xee, 0x35, 0xed, 0x51, 0x0a, 0xec, + 0xf2, 0xed, 0xfc, 0xf9, 0xe4, 0xff, 0x19, 0x1f, 0x12, 0xb0, 0x24, 0xfb, 0xe6, + 0xe4, 0x03, 0x24, 0xbc, 0x01, 0xf3, 0xdd, 0xea, 0x03, 0xd5, 0x1a, 0x0c, 0x10, + 0xd4, 0x4c, 0x02, 0x7f, 0xc3, 0x05, 0x21, 0xdd, 0x00, 0x1d, 0xc9, 0x01, 0x02, + 0x14, 0xfa, 0x21, 0x4c, 0xeb, 0xa4, 0xe0, 0x20, 0x81, 0x12, 0x45, 0x8f, 0x11, + 0xc2, 0xf0, 0xe9, 0x23, 0xb2, 0x01, 0x12, 0x45, 0xf6, 0x09, 0x82, 0x2b, 0xec, + 0x2e, 0x27, 0x8d, 0x2f, 0x93, 0xb8, 0x3c, 0xa5, 0x45, 0x41, 0xdc, 0x5f, 0x1a, + 0x1f, 0xd3, 0x7f, 0x66, 0xdd, 0xfe, 0xfa, 0x37, 0x3e, 0xdb, 0x04, 0xd7, 0xfa, + 0xdf, 0xc2, 0x99, 0x17, 0x0a, 0xba, 0x55, 0xdd, 0xe2, 0x6e, 0xc0, 0xce, 0xd5, + 0xbf, 0x13, 0xc3, 0xbb, 0x4f, 0xb3, 0xfb, 0xb8, 0xbc, 0x0b, 0x42, 0x2d, 0x53, + 0x23, 0x92, 0x0a, 0xc3, 0xe6, 0xb7, 0xaf, 0xf1, 0x25, 0x32, 0x0e, 0x81, 0x38, + 0xf1, 0x0c, 0xff, 0xd0, 0x46, 0x33, 0xc4, 0xf7, 0xb8, 0xb2, 0xfb, 0x0e, 0x0f, + 0xf2, 0xd7, 0x5e, 0xcc, 0x11, 0xc0, 0x1c, 0xeb, 0x09, 0x7f, 0xf8, 0xf6, 0xf3, + 0xff, 0x2c, 0x0d, 0xc7, 0xf3, 0x27, 0xd0, 0x11, 0x2e, 0x47, 0x4b, 0xba, 0xd7, + 0x05, 0xe5, 0xfd, 0x59, 0xe5, 0x1d, 0xdc, 0x19, 0xd0, 0x2d, 0xb9, 0xa4, 0xe1, + 0xc4, 0x97, 0x28, 0xee, 0x0f, 0xf1, 0x7f, 0xdb, 0x07, 0xf3, 0xdf, 0xc4, 0xcd, + 0x34, 0xfa, 0xce, 0xb3, 0xd8, 0x13, 0xe4, 0xad, 0xef, 0x7f, 0xe6, 0x1c, 0x44, + 0xea, 0xe2, 0x19, 0x71, 0x93, 0xd5, 0x5a, 0xe2, 0x82, 0xb5, 0xac, 0x8d, 0x09, + 0xef, 0xbf, 0xdd, 0xef, 0xfd, 0xd9, 0xe3, 0xcf, 0xfc, 0xe0, 0xf1, 0x42, 0xfa, + 0x4a, 0xe9, 0x0c, 0xf3, 0x14, 0x02, 0x7f, 0x07, 0xc0, 0xf6, 0x06, 0xdc, 0xd8, + 0x23, 0xef, 0xfb, 0x15, 0xd6, 0xe0, 0xd6, 0xf6, 0xdf, 0x24, 0xed, 0xe6, 0xd6, + 0x2a, 0x08, 0x2e, 0xed, 0xf9, 0x61, 0xbd, 0xf3, 0x03, 0x23, 0xf6, 0x0e, 0xb2, + 0xea, 0x81, 0xfb, 0xcc, 0xe1, 0xe8, 0x9c, 0xe4, 0xf5, 0xfc, 0xe3, 0xf7, 0x20, + 0xd8, 0xe2, 0x01, 0xa7, 0x2f, 0x8a, 0x15, 0xd4, 0x3f, 0x4c, 0x81, 0x8c, 0x97, + 0xd7, 0xdb, 0x3f, 0x52, 0x84, 0xee, 0xfa, 0xd4, 0x04, 0x14, 0x07, 0xca, 0xc7, + 0xec, 0xe9, 0xce, 0xd8, 0x3b, 0x04, 0xee, 0x92, 0xe9, 0x04, 0xd2, 0x40, 0x66, + 0xcd, 0xc8, 0xff, 0xe5, 0xf3, 0xad, 0xbf, 0x46, 0xc4, 0xf4, 0x47, 0xf6, 0x00, + 0x58, 0x7f, 0xd9, 0xe8, 0x25, 0xf2, 0x04, 0xe4, 0xc1, 0xc3, 0xff, 0x10, 0xe8, + 0x55, 0x07, 0x2b, 0xf6, 0x13, 0x3b, 0xf9, 0xe9, 0xfd, 0x21, 0xd4, 0x1d, 0xf8, + 0x04, 0xcd, 0xff, 0x7f, 0x1d, 0x14, 0x01, 0x14, 0x1f, 0x0c, 0x5d, 0x17, 0xa9, + 0x49, 0x08, 0xfa, 0x16, 0x03, 0x50, 0x19, 0x04, 0xdb, 0xde, 0x31, 0x2c, 0xe3, + 0xfd, 0x1c, 0x18, 0x00, 0xf2, 0x13, 0x2f, 0xf5, 0xef, 0xb4, 0xde, 0xdb, 0x81, + 0x14, 0xe9, 0xdf, 0xeb, 0xf2, 0xf7, 0xe4, 0xfe, 0xfc, 0xec, 0xf7, 0x04, 0xf5, + 0x27, 0xd2, 0x7f, 0x0d, 0x1c, 0x2e, 0x0d, 0xee, 0xda, 0xfc, 0xec, 0x12, 0xfc, + 0x22, 0xf2, 0xf1, 0xe1, 0xde, 0xdf, 0x0c, 0xe9, 0xce, 0xf5, 0xe6, 0xfe, 0xe8, + 0xc2, 0x0c, 0x15, 0xeb, 0x07, 0x09, 0xf5, 0xc2, 0x1d, 0x07, 0x21, 0x10, 0xee, + 0x29, 0xc1, 0x00, 0x62, 0xf3, 0xe5, 0xd1, 0x06, 0xf3, 0x13, 0x7f, 0x2a, 0x12, + 0x01, 0xe5, 0x00, 0xf0, 0xf5, 0x06, 0x09, 0xc3, 0xb9, 0xd5, 0x03, 0x0e, 0xf9, + 0x01, 0x39, 0x0d, 0x10, 0x05, 0x46, 0x7f, 0xc6, 0xee, 0x25, 0xe3, 0x4d, 0xeb, + 0xfd, 0xf4, 0x09, 0x28, 0xb0, 0xea, 0xb0, 0xdf, 0xd4, 0x03, 0x04, 0xed, 0xdf, + 0xe0, 0x01, 0x18, 0xdd, 0x08, 0xfa, 0x14, 0x08, 0xf4, 0xff, 0x1e, 0xc8, 0x7f, + 0x1c, 0xdc, 0x02, 0x1b, 0xbd, 0x46, 0xea, 0x10, 0x1a, 0x2d, 0x0b, 0x21, 0x08, + 0x1d, 0x10, 0xaf, 0xc3, 0x2c, 0xd8, 0xc2, 0x1d, 0x03, 0xcf, 0xe8, 0x17, 0x20, + 0x09, 0xe5, 0x26, 0x3d, 0x1a, 0xdc, 0xf4, 0xfd, 0xcc, 0xdc, 0xb1, 0xc9, 0x02, + 0xff, 0x12, 0xda, 0x36, 0xd2, 0xcc, 0x01, 0xfe, 0x20, 0x7f, 0x11, 0x21, 0x0a, + 0x6c, 0xef, 0x1b, 0xd9, 0x20, 0x19, 0x18, 0x05, 0x23, 0x0d, 0xbe, 0x3c, 0xf6, + 0xcc, 0xec, 0xc4, 0xd6, 0xd5, 0xd0, 0x81, 0xd2, 0xd4, 0x37, 0xca, 0x1d, 0xc3, + 0xd4, 0x0e, 0x23, 0xee, 0x4f, 0xd4, 0x09, 0xe1, 0x92, 0xfc, 0xf4, 0x0f, 0x18, + 0xfc, 0xf4, 0x07, 0x28, 0x3a, 0xfd, 0xee, 0xd9, 0xc8, 0x02, 0xb7, 0x05, 0x1a, + 0xd7, 0x2c, 0xb8, 0xd5, 0x52, 0x1c, 0xc7, 0x1a, 0xe0, 0x01, 0x81, 0xe1, 0xd9, + 0x3c, 0xdb, 0xde, 0x10, 0x2d, 0xd2, 0xed, 0x00, 0xfe, 0xf9, 0xec, 0xec, 0xf6, + 0xa6, 0x01, 0x1f, 0x11, 0x03, 0x81, 0xde, 0x4d, 0xe3, 0x18, 0x34, 0xe0, 0xe9, + 0x14, 0x0c, 0xfa, 0xdb, 0x0e, 0xe1, 0x0a, 0xf6, 0xe2, 0xb9, 0xb2, 0x45, 0x5b, + 0xa8, 0x98, 0x2a, 0x43, 0x81, 0x54, 0x84, 0xd9, 0x06, 0xdf, 0x05, 0xec, 0xc9, + 0xc6, 0xd8, 0xd0, 0x3f, 0x24, 0x5e, 0xeb, 0xf9, 0x01, 0x0c, 0xa4, 0xa1, 0x12, + 0xd3, 0xd6, 0x3f, 0x3b, 0x01, 0x03, 0xdd, 0xf6, 0xc7, 0xc0, 0xdf, 0x01, 0xf1, + 0xfe, 0xeb, 0x28, 0x1d, 0xf1, 0x07, 0x3c, 0xc6, 0x16, 0x5c, 0x7f, 0xe3, 0x1f, + 0x26, 0xf8, 0xd6, 0x33, 0xe7, 0x6f, 0xe7, 0x9a, 0xbb, 0xe8, 0xf6, 0x01, 0xcc, + 0xf8, 0x03, 0xcd, 0x1c, 0x16, 0xda, 0xe1, 0xed, 0x17, 0x27, 0xc3, 0x2b, 0x26, + 0xf8, 0x18, 0xf6, 0x02, 0xf5, 0xe6, 0xfa, 0x09, 0xf5, 0xeb, 0x26, 0x81, 0x27, + 0xf2, 0xe2, 0x00, 0x0f, 0xe6, 0xce, 0xef, 0xf0, 0xfb, 0x25, 0x18, 0xe0, 0xee, + 0xf1, 0x7f, 0x1e, 0x11, 0xd9, 0xd8, 0xfa, 0x15, 0xd3, 0x02, 0xee, 0xfc, 0xe8, + 0x2d, 0x06, 0x0f, 0x4f, 0x02, 0xe9, 0xf6, 0x04, 0x0d, 0xdd, 0xed, 0x05, 0xe3, + 0xe7, 0xca, 0x02, 0xfa, 0xe8, 0x22, 0x1b, 0x55, 0xf0, 0xc9, 0xe2, 0x0f, 0x0e, + 0xf1, 0xa2, 0xc1, 0xbd, 0xcf, 0x16, 0xc9, 0x7f, 0x24, 0xfc, 0xf1, 0xda, 0x18, + 0x10, 0x18, 0xfa, 0x11, 0x33, 0x03, 0xdc, 0xe6, 0xe1, 0x1b, 0xa2, 0xd5, 0x23, + 0xdb, 0xf6, 0xdf, 0xcf, 0x24, 0xff, 0xdf, 0x7f, 0x16, 0xd3, 0xf7, 0xf5, 0xd0, + 0xb0, 0x05, 0x0d, 0x0b, 0x15, 0xb2, 0xed, 0xd6, 0x54, 0xfd, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2f, 0xe7, 0xff, 0xff, 0x82, 0x23, 0x00, + 0x00, 0xe2, 0xff, 0xff, 0xff, 0x05, 0xfc, 0xff, 0xff, 0x10, 0xfe, 0xff, 0xff, + 0xcb, 0x05, 0x00, 0x00, 0x3c, 0x2d, 0x00, 0x00, 0x97, 0x48, 0x00, 0x00, 0xb1, + 0xfb, 0xff, 0xff, 0x0d, 0xfc, 0xff, 0xff, 0xc7, 0xfe, 0xff, 0xff, 0x9c, 0xfa, + 0xff, 0xff, 0x73, 0xff, 0xff, 0xff, 0x5d, 0xf4, 0xff, 0xff, 0xe8, 0xfb, 0xff, + 0xff, 0xe8, 0xfc, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x68, 0x30, 0x00, 0x00, + 0x88, 0xfc, 0xff, 0xff, 0x88, 0x3f, 0x00, 0x00, 0x2f, 0x35, 0x00, 0x00, 0x29, + 0x2b, 0x00, 0x00, 0x37, 0xff, 0xff, 0xff, 0xf2, 0x27, 0x00, 0x00, 0xae, 0xf3, + 0xff, 0xff, 0x8c, 0xfd, 0xff, 0xff, 0xdf, 0x16, 0x00, 0x00, 0x5d, 0x42, 0x00, + 0x00, 0x87, 0xec, 0xff, 0xff, 0xb2, 0x29, 0x00, 0x00, 0x7d, 0x23, 0x00, 0x00, + 0x5e, 0xfb, 0xff, 0xff, 0x31, 0xfb, 0xff, 0xff, 0x11, 0x3d, 0x00, 0x00, 0x69, + 0x05, 0x00, 0x00, 0xd5, 0x41, 0x00, 0x00, 0x35, 0xff, 0xff, 0xff, 0xca, 0x0c, + 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x19, 0xe9, 0xff, + 0xff, 0xc0, 0xf7, 0xff, 0xff, 0x11, 0x07, 0x00, 0x00, 0x05, 0xfe, 0xff, 0xff, + 0x3c, 0x34, 0x00, 0x00, 0x48, 0x3f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x58, + 0x4a, 0x00, 0x00, 0xe3, 0xf2, 0xff, 0xff, 0x61, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf2, 0xf4, 0xff, 0xff, 0xd6, 0xff, 0xff, 0xff, 0x66, 0xef, 0xff, + 0xff, 0x7b, 0x3c, 0x00, 0x00, 0xa2, 0x2e, 0x00, 0x00, 0xb3, 0x12, 0x00, 0x00, + 0x59, 0x1f, 0x00, 0x00, 0x3f, 0x33, 0x00, 0x00, 0x3c, 0xfe, 0xff, 0xff, 0x1c, + 0x15, 0x00, 0x00, 0x14, 0x34, 0x00, 0x00, 0x09, 0x26, 0x00, 0x00, 0x64, 0x20, + 0x00, 0x00, 0xe2, 0x55, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0xf3, 0x32, 0x0b, 0x24, 0xff, 0x39, 0x14, 0xfe, 0x1c, 0x2f, 0xe1, 0x1e, + 0x0b, 0xd4, 0xb6, 0xcf, 0x31, 0xf6, 0x7f, 0xec, 0x48, 0xd7, 0x4a, 0xdd, 0x34, + 0x48, 0xe2, 0xcb, 0x26, 0x1f, 0x01, 0xbb, 0xe2, 0x1a, 0x1e, 0xd3, 0xfd, 0xc7, + 0xa4, 0xe3, 0x10, 0x12, 0xdf, 0x45, 0xf6, 0xe0, 0x29, 0xe0, 0x71, 0xa6, 0x03, + 0x18, 0xb5, 0x21, 0xac, 0xf5, 0x12, 0x1e, 0x0e, 0x00, 0xf1, 0x0b, 0x0d, 0x25, + 0x7f, 0xe0, 0x2d, 0x0b, 0xc3, 0xf7, 0xd3, 0x48, 0x06, 0x07, 0xda, 0x09, 0xf3, + 0xc9, 0xba, 0x10, 0xcf, 0x00, 0xfc, 0x1c, 0x13, 0x1e, 0x08, 0x47, 0xe2, 0xd3, + 0xee, 0x11, 0x3a, 0xbd, 0x10, 0x43, 0xd7, 0x5d, 0x11, 0x15, 0xe7, 0x0d, 0x17, + 0xf9, 0x17, 0x23, 0x18, 0xf1, 0x1e, 0xfd, 0xe2, 0xcc, 0xf6, 0xf6, 0x1c, 0x01, + 0x26, 0xec, 0xf0, 0xec, 0xeb, 0xe2, 0x56, 0xf5, 0x21, 0x00, 0xf6, 0xc5, 0xf3, + 0x03, 0xf2, 0x19, 0xf4, 0x01, 0x0f, 0x31, 0xdc, 0xf4, 0x01, 0xdb, 0x3a, 0x81, + 0xd6, 0x17, 0x79, 0xec, 0xee, 0xfd, 0xe7, 0xe8, 0xfa, 0xf5, 0x06, 0xf7, 0x16, + 0x37, 0x04, 0xed, 0x1f, 0x21, 0xbd, 0x24, 0xf3, 0x44, 0xe6, 0x0d, 0x09, 0x24, + 0x01, 0xdc, 0x1a, 0x2a, 0xe3, 0xef, 0xee, 0x38, 0x10, 0x25, 0xed, 0x02, 0xe7, + 0x11, 0x08, 0xfd, 0xf1, 0x18, 0xf5, 0xe3, 0x26, 0x14, 0x2d, 0xf0, 0xe8, 0xfb, + 0x21, 0xff, 0x02, 0xf0, 0xf0, 0xfc, 0xe4, 0x07, 0x02, 0x1f, 0x17, 0xfd, 0x15, + 0x29, 0xd9, 0x1a, 0x16, 0x09, 0x09, 0x1f, 0x24, 0x19, 0xe8, 0x81, 0xed, 0xcd, + 0x29, 0x34, 0x12, 0xfb, 0x40, 0xd8, 0x11, 0x07, 0xd6, 0xf3, 0xfa, 0x06, 0xfe, + 0x3d, 0x2c, 0xdc, 0x1f, 0xee, 0xdc, 0x12, 0x38, 0x2f, 0x2a, 0xee, 0x02, 0xf5, + 0x05, 0x2e, 0x0d, 0x20, 0xf6, 0x0c, 0xe2, 0x20, 0x14, 0x00, 0xce, 0x12, 0xf3, + 0x1f, 0xd8, 0xc5, 0xce, 0x34, 0xfb, 0xe7, 0x0d, 0x1d, 0xa0, 0xe5, 0x4b, 0xf0, + 0x0c, 0x3c, 0xdf, 0x39, 0xfd, 0x28, 0x04, 0x0a, 0xff, 0x0b, 0x43, 0xf7, 0x40, + 0xe2, 0x17, 0x24, 0x48, 0xc6, 0x2f, 0xbd, 0x01, 0xdf, 0xe5, 0xee, 0x12, 0x52, + 0xc7, 0xab, 0x0b, 0x0d, 0x2b, 0x1a, 0xf2, 0x03, 0xd8, 0xe7, 0xfe, 0x27, 0xf4, + 0x2d, 0xfa, 0xc7, 0x25, 0x7f, 0xe7, 0x01, 0x2b, 0x9a, 0xfb, 0x5d, 0x32, 0xed, + 0xf9, 0xff, 0x7f, 0xf9, 0xf0, 0x2d, 0xd4, 0x07, 0xe5, 0x06, 0x15, 0x69, 0xf5, + 0xe1, 0xfe, 0x98, 0x95, 0x85, 0x75, 0xfc, 0xe9, 0x29, 0x7c, 0xe6, 0x0b, 0xd5, + 0x14, 0xfa, 0xd4, 0x12, 0x61, 0x39, 0xe9, 0x10, 0x24, 0x19, 0xcc, 0x1c, 0xf3, + 0xee, 0xa7, 0x59, 0xf1, 0x49, 0xe8, 0x15, 0xe5, 0x0a, 0x12, 0xca, 0x9f, 0x0a, + 0x0f, 0x23, 0x16, 0x24, 0xc3, 0x00, 0x17, 0xe4, 0xd0, 0xc4, 0x0f, 0x16, 0xf7, + 0xda, 0x13, 0xdf, 0x2e, 0xf4, 0x1e, 0xe7, 0xf3, 0x12, 0xe0, 0x27, 0xf4, 0xe8, + 0xff, 0x1c, 0x06, 0xf0, 0x04, 0x03, 0xf8, 0x7f, 0xe7, 0x51, 0xe3, 0xee, 0x08, + 0x20, 0xca, 0x05, 0xd1, 0xfd, 0xf0, 0xfa, 0xdb, 0xae, 0xca, 0x2a, 0x28, 0x0f, + 0x00, 0x92, 0x35, 0x2c, 0xe2, 0xfe, 0x02, 0xb0, 0x0d, 0x05, 0xce, 0xe7, 0xdb, + 0x02, 0xcf, 0xd9, 0xf1, 0xf9, 0x07, 0xf4, 0xe5, 0x1b, 0x40, 0xed, 0xd9, 0x21, + 0xce, 0xa6, 0xd3, 0x22, 0xf0, 0xf2, 0x1a, 0x40, 0xf7, 0x49, 0xdf, 0x17, 0xe3, + 0x28, 0x0a, 0x0f, 0xfa, 0xc6, 0xd0, 0x97, 0x12, 0x1d, 0xae, 0xd4, 0x37, 0x5e, + 0xa2, 0x03, 0x53, 0xc6, 0xdf, 0x9f, 0x3e, 0xe8, 0xb5, 0xf4, 0x14, 0x49, 0xf7, + 0x01, 0xe6, 0xec, 0xc4, 0x7f, 0x02, 0xee, 0x44, 0x4c, 0x2c, 0x25, 0xe5, 0xd2, + 0x20, 0x16, 0xeb, 0xee, 0xe1, 0xc3, 0x42, 0xde, 0x09, 0x27, 0xec, 0xf4, 0xf2, + 0xf0, 0x22, 0x13, 0x03, 0xfb, 0xd5, 0xca, 0x27, 0x28, 0xc9, 0x29, 0xf4, 0x06, + 0xf0, 0x11, 0xe4, 0xed, 0x01, 0x21, 0x06, 0xfe, 0xe4, 0xfa, 0x0c, 0x1f, 0xb6, + 0xf5, 0xda, 0x03, 0x02, 0x00, 0x05, 0xfc, 0xf4, 0x7f, 0x1e, 0xff, 0x0b, 0xfd, + 0xe4, 0xb8, 0xde, 0xbc, 0xe0, 0x4a, 0x2e, 0x01, 0xbf, 0x15, 0x20, 0x10, 0x20, + 0x11, 0x20, 0x1b, 0x28, 0xb9, 0x0b, 0xe9, 0xf1, 0xcf, 0x2c, 0x00, 0xdc, 0x4a, + 0x3e, 0x33, 0x0b, 0xdf, 0xa4, 0xe6, 0x14, 0xf4, 0xc4, 0xd1, 0xd4, 0x17, 0xec, + 0x16, 0x06, 0xda, 0xca, 0x7f, 0x15, 0xf9, 0xc8, 0xba, 0x33, 0xee, 0xae, 0xfc, + 0xe8, 0xbb, 0xfc, 0xe6, 0x24, 0x12, 0xe6, 0x05, 0xf5, 0xfb, 0x05, 0x0e, 0xc5, + 0x32, 0xe8, 0x04, 0xd1, 0x0a, 0xf2, 0xbc, 0x1b, 0x14, 0x15, 0xc5, 0xf9, 0xce, + 0xfd, 0x38, 0xfd, 0xeb, 0xe6, 0x7f, 0x23, 0x45, 0x08, 0xeb, 0xee, 0x3e, 0x26, + 0xf6, 0xd9, 0xbb, 0x0a, 0xa6, 0x1e, 0xd3, 0xea, 0x08, 0xf6, 0xcc, 0x0c, 0xe9, + 0x39, 0xea, 0x08, 0xe4, 0x04, 0x13, 0xfc, 0xf5, 0xe8, 0xe4, 0x05, 0xeb, 0x91, + 0xea, 0x19, 0x3c, 0xd0, 0xdd, 0xe0, 0x13, 0xfb, 0xf0, 0xe6, 0xc8, 0x3e, 0xef, + 0xeb, 0x13, 0x42, 0xc2, 0xf0, 0xdf, 0xe1, 0xe0, 0x0f, 0xf8, 0xfa, 0xc8, 0xc5, + 0xfb, 0x2a, 0x14, 0xee, 0x36, 0xdd, 0x0d, 0x01, 0xd2, 0xe5, 0xb1, 0x11, 0x09, + 0x59, 0x03, 0x16, 0xeb, 0x81, 0x24, 0xb4, 0xd6, 0x27, 0x02, 0x1d, 0x29, 0x66, + 0x0f, 0xa9, 0x35, 0x36, 0x99, 0x2a, 0x33, 0xfa, 0xce, 0xd7, 0xe1, 0xff, 0x06, + 0xfa, 0x2b, 0x05, 0xe9, 0xc4, 0xdf, 0x19, 0xee, 0xd1, 0xca, 0x0a, 0x44, 0x9e, + 0x09, 0xd4, 0x5d, 0x26, 0x26, 0xec, 0x6a, 0x32, 0x00, 0xf7, 0x59, 0xf9, 0x37, + 0xfb, 0xc9, 0x93, 0xe0, 0xf6, 0x03, 0xdd, 0x3f, 0x17, 0xf6, 0x10, 0xed, 0x00, + 0xcd, 0xf6, 0x90, 0xcb, 0x12, 0xe3, 0x3f, 0x01, 0x7f, 0x20, 0xfa, 0xfc, 0x15, + 0x02, 0x7d, 0xce, 0xe4, 0x04, 0x12, 0x04, 0x13, 0xcf, 0x1a, 0x21, 0xdf, 0x70, + 0xef, 0xf4, 0x12, 0xe1, 0x01, 0x29, 0x04, 0x37, 0xf1, 0x42, 0xf1, 0x9a, 0x0d, + 0x1e, 0x14, 0x05, 0x1d, 0x18, 0xde, 0x03, 0x06, 0xef, 0xed, 0xb3, 0xdf, 0x0d, + 0xec, 0x08, 0xb4, 0x01, 0x12, 0x0a, 0x48, 0xec, 0xd7, 0x7f, 0x04, 0x37, 0xde, + 0x4f, 0xd7, 0xd9, 0x21, 0xa5, 0x19, 0x0f, 0x0d, 0x16, 0xde, 0xe3, 0x3f, 0xcd, + 0x36, 0x2f, 0x34, 0x05, 0x4a, 0xb7, 0x22, 0x47, 0xf0, 0xeb, 0x07, 0x0a, 0x25, + 0xcc, 0x8d, 0xd5, 0xed, 0xc6, 0xce, 0xf1, 0xf9, 0x37, 0xbc, 0xed, 0x32, 0x08, + 0xbf, 0xe9, 0x0e, 0x9a, 0xe3, 0x0e, 0xe5, 0xe0, 0xd4, 0xca, 0xc8, 0xd5, 0xb2, + 0x3c, 0xd6, 0xe0, 0x0f, 0x19, 0x01, 0x02, 0xf1, 0xfc, 0xef, 0x22, 0xff, 0x1f, + 0xdf, 0x05, 0x23, 0x2a, 0xf2, 0x00, 0x48, 0xf9, 0x00, 0xf4, 0x69, 0x27, 0xef, + 0x00, 0x7f, 0x04, 0x2e, 0x2a, 0x2b, 0x0d, 0x35, 0xfa, 0xf1, 0x0b, 0xdd, 0x14, + 0x24, 0x17, 0x03, 0xfe, 0x27, 0x1f, 0x07, 0xe9, 0x13, 0xea, 0x5e, 0x05, 0xd5, + 0x04, 0xf1, 0x16, 0xf0, 0xf9, 0xd6, 0xe8, 0xe0, 0x00, 0x53, 0xec, 0xf7, 0x22, + 0xeb, 0xfd, 0x0a, 0xd3, 0x05, 0xf2, 0x43, 0x9c, 0xdf, 0xcc, 0x01, 0x00, 0x14, + 0xe4, 0xfa, 0xe3, 0x40, 0x0b, 0xa5, 0x05, 0xdb, 0x11, 0x26, 0x8b, 0x8f, 0x1d, + 0x6d, 0x01, 0xc9, 0xdb, 0xc0, 0x44, 0x19, 0x81, 0x14, 0xd1, 0x44, 0xfe, 0xcf, + 0x36, 0xed, 0xde, 0x19, 0xeb, 0xeb, 0xf8, 0x05, 0x3d, 0xf7, 0xd4, 0xcd, 0x3e, + 0x1b, 0x65, 0x72, 0x13, 0xd1, 0x59, 0x1a, 0x11, 0x28, 0x00, 0xd9, 0xd3, 0x12, + 0x08, 0x20, 0xd4, 0xf2, 0x17, 0x02, 0xf8, 0xf1, 0x06, 0x03, 0x36, 0xe4, 0xc5, + 0x16, 0x7d, 0xaf, 0x35, 0x2e, 0x19, 0xf2, 0x7f, 0x0e, 0x0e, 0xe4, 0xf8, 0xd9, + 0xf9, 0xf2, 0x0f, 0xfe, 0xc4, 0x41, 0x08, 0x07, 0xde, 0x42, 0xfe, 0xdd, 0x00, + 0x04, 0xfd, 0xe5, 0xda, 0x04, 0xea, 0x0b, 0x0f, 0x48, 0xf9, 0x07, 0x1c, 0x0e, + 0x16, 0xfc, 0xfb, 0x25, 0xf0, 0xcd, 0xfa, 0x03, 0x22, 0xec, 0x1b, 0xee, 0x20, + 0x13, 0xea, 0x00, 0xfc, 0xf8, 0x1d, 0x08, 0x1c, 0x7f, 0x37, 0x2f, 0x11, 0x03, + 0x36, 0xc8, 0xe2, 0xe8, 0x1b, 0x66, 0x12, 0x0c, 0x26, 0x91, 0x20, 0xe6, 0xff, + 0x2b, 0x5c, 0x02, 0xcb, 0x06, 0x28, 0x21, 0xfc, 0xee, 0x17, 0x18, 0xfd, 0xf6, + 0xde, 0x17, 0x44, 0x61, 0xfb, 0xf8, 0x20, 0xc2, 0x07, 0x1a, 0xfe, 0xe5, 0xd4, + 0x0b, 0x16, 0x29, 0x04, 0xec, 0x6b, 0x42, 0x1a, 0x22, 0x7f, 0x90, 0x00, 0xca, + 0x33, 0xd1, 0xa4, 0x09, 0xe9, 0x59, 0xbe, 0x01, 0x1b, 0xf3, 0x7d, 0x1a, 0xd2, + 0x2b, 0x0c, 0x04, 0x38, 0xca, 0x26, 0x38, 0x30, 0xc9, 0x2a, 0x7c, 0x12, 0xe5, + 0x02, 0x1e, 0x03, 0xe2, 0x07, 0xfd, 0xca, 0xf4, 0xd3, 0xc2, 0x4c, 0xeb, 0xca, + 0x47, 0x64, 0xe7, 0x0e, 0xfa, 0xc2, 0xf0, 0xfd, 0x9f, 0x3f, 0xca, 0x0c, 0xa7, + 0x47, 0x05, 0xee, 0x17, 0x0a, 0x0f, 0xf7, 0xcb, 0xfc, 0x3c, 0x58, 0x07, 0x18, + 0x36, 0xf6, 0x24, 0xeb, 0xf7, 0x17, 0xfc, 0xf4, 0xe9, 0xfb, 0x7f, 0x13, 0xf2, + 0xf9, 0xee, 0x06, 0xe6, 0xf9, 0xe9, 0xdb, 0xdb, 0x3a, 0xda, 0xd8, 0x0e, 0x0e, + 0x44, 0xd9, 0x10, 0x02, 0xfc, 0xfd, 0x2e, 0x15, 0xc2, 0x0e, 0x00, 0xf1, 0xdb, + 0xfe, 0x15, 0xfd, 0x0a, 0x00, 0xe7, 0x2d, 0x04, 0x19, 0xeb, 0xd1, 0xee, 0x28, + 0x22, 0xe3, 0xd9, 0xbc, 0xe1, 0x27, 0x05, 0xf4, 0x25, 0x2c, 0x0f, 0x31, 0x45, + 0x0d, 0x00, 0x13, 0xe6, 0x05, 0x0c, 0xe9, 0x16, 0xe3, 0xde, 0xaa, 0xfe, 0x76, + 0x1c, 0x26, 0xdb, 0x12, 0xf9, 0x18, 0xa3, 0x1d, 0x14, 0xdb, 0x0d, 0x03, 0xed, + 0x0c, 0x0a, 0x4c, 0x18, 0x2a, 0x38, 0x52, 0x33, 0xd3, 0xfe, 0xff, 0xd8, 0xfa, + 0xf2, 0x0f, 0x06, 0xee, 0x22, 0xee, 0x5b, 0x22, 0x07, 0xf8, 0x02, 0x63, 0x08, + 0xe0, 0x4e, 0xf6, 0xd7, 0x81, 0x59, 0xde, 0x08, 0x40, 0x0d, 0xd9, 0xf2, 0xf0, + 0x26, 0x81, 0x4c, 0x24, 0x34, 0xd1, 0x10, 0xd9, 0x13, 0x96, 0xda, 0xdb, 0x2e, + 0x07, 0xd4, 0xfd, 0x36, 0xcf, 0xcd, 0xd1, 0xd9, 0x06, 0xb7, 0xf1, 0x00, 0xeb, + 0x18, 0xd5, 0xdf, 0xf0, 0xd9, 0x3d, 0xd3, 0xaa, 0x10, 0x47, 0xf5, 0xfb, 0xde, + 0x59, 0xd3, 0x0c, 0x42, 0x1a, 0xf1, 0x28, 0xf7, 0x1e, 0xb8, 0xfc, 0xc0, 0xf0, + 0xea, 0xe2, 0x1e, 0xf4, 0xd4, 0xf2, 0x1b, 0xd6, 0xf5, 0xdd, 0xcf, 0x35, 0xd2, + 0xf8, 0x17, 0xf3, 0xd8, 0x3b, 0x25, 0x11, 0x0c, 0xb2, 0x2f, 0x07, 0xad, 0xff, + 0x28, 0xd2, 0x40, 0xf2, 0x99, 0xfe, 0xef, 0x22, 0xd5, 0x93, 0xca, 0x05, 0xe8, + 0xf9, 0x0d, 0x21, 0x0b, 0x0a, 0xdf, 0xde, 0xcc, 0x04, 0x81, 0x46, 0x25, 0x18, + 0x34, 0x0b, 0xfe, 0xe9, 0xec, 0xdd, 0xef, 0xe0, 0x3e, 0xf8, 0xcb, 0x1c, 0xe8, + 0xd0, 0xab, 0xcf, 0x29, 0xdd, 0x00, 0x12, 0x53, 0x03, 0x02, 0x1e, 0x14, 0x08, + 0x0a, 0x09, 0x75, 0x01, 0x21, 0x21, 0x34, 0x05, 0xce, 0x1e, 0xf8, 0xcf, 0x44, + 0x4c, 0x14, 0xed, 0xe0, 0x25, 0x26, 0x13, 0xfb, 0xd9, 0xf5, 0x0e, 0xf7, 0x47, + 0x3d, 0x27, 0x24, 0x3e, 0x07, 0x15, 0x27, 0x52, 0xfe, 0xfc, 0x0d, 0xee, 0xd1, + 0xea, 0xca, 0xc4, 0x4b, 0xee, 0xfb, 0x0f, 0x3a, 0x37, 0xa9, 0x0a, 0x55, 0x57, + 0xee, 0xec, 0x7f, 0x1e, 0x19, 0x32, 0x97, 0xdb, 0x1f, 0xb2, 0x3b, 0xe4, 0x7f, + 0x03, 0xe7, 0xec, 0xc4, 0xf6, 0xfc, 0x27, 0x51, 0x43, 0x02, 0xd0, 0xbb, 0x0b, + 0x2b, 0x9a, 0xf5, 0x44, 0xfe, 0xb5, 0x23, 0x35, 0xd2, 0x47, 0xca, 0x7b, 0xda, + 0xee, 0x0a, 0x35, 0x65, 0xb9, 0xb6, 0xdc, 0x41, 0xef, 0x1c, 0xed, 0x13, 0x50, + 0x03, 0xe8, 0x18, 0xef, 0xfe, 0x04, 0x16, 0xfc, 0x1f, 0x00, 0xf1, 0xbb, 0xf8, + 0x0f, 0x59, 0xc8, 0x09, 0xf0, 0x5a, 0x10, 0xbe, 0xf5, 0x16, 0x2c, 0xc7, 0x4d, + 0x15, 0x2b, 0xd6, 0xf2, 0x28, 0x38, 0xc9, 0x09, 0x27, 0xff, 0x26, 0xfa, 0xde, + 0x3c, 0x22, 0xf2, 0x07, 0xec, 0x0c, 0x43, 0x1a, 0x02, 0x1e, 0x3c, 0x03, 0xca, + 0xe3, 0xf2, 0xbe, 0xdc, 0x29, 0x0d, 0x81, 0x27, 0x02, 0x5b, 0x3d, 0xd6, 0xff, + 0x46, 0x47, 0xe8, 0x2b, 0xc3, 0xd7, 0xfd, 0xee, 0x5c, 0xe9, 0x3a, 0x12, 0x04, + 0xfb, 0xf1, 0x1b, 0x39, 0xf2, 0x20, 0xfe, 0xd7, 0xef, 0x0d, 0xf9, 0x13, 0xed, + 0x06, 0xf0, 0x31, 0xef, 0x0e, 0x0d, 0xdc, 0xe8, 0x12, 0x31, 0x02, 0xc5, 0xe7, + 0xda, 0x14, 0x10, 0xc5, 0xcb, 0xf3, 0xfb, 0xe3, 0x26, 0xf1, 0x03, 0xfe, 0x14, + 0xd0, 0xef, 0xe7, 0x7f, 0x0e, 0x03, 0x10, 0xd5, 0x01, 0xf6, 0xef, 0x02, 0x00, + 0x04, 0x36, 0xef, 0xd4, 0x0c, 0x16, 0x1f, 0xfe, 0xe7, 0xf2, 0xef, 0x0b, 0x07, + 0xef, 0xfa, 0xd9, 0x49, 0x11, 0x4c, 0xf3, 0x4e, 0x7f, 0xe9, 0xb6, 0xcc, 0xf8, + 0xe1, 0x19, 0xc1, 0x15, 0xbf, 0xc4, 0x14, 0xc0, 0x07, 0xcb, 0xbe, 0x70, 0xc2, + 0x3c, 0x12, 0xdd, 0x4f, 0x04, 0x06, 0xe1, 0xd2, 0x23, 0xdb, 0x22, 0xf9, 0xb4, + 0x00, 0x12, 0xd1, 0xae, 0x57, 0xf8, 0xf4, 0x37, 0x32, 0xea, 0xcd, 0xd6, 0xdd, + 0xd8, 0x1b, 0x0b, 0xbd, 0x41, 0x42, 0x35, 0xda, 0xd6, 0x10, 0x26, 0x22, 0xf5, + 0x0c, 0xe7, 0x02, 0x0a, 0xfc, 0xea, 0xfe, 0x56, 0xf8, 0x3b, 0xe6, 0x16, 0xbc, + 0x0c, 0x12, 0x08, 0x4a, 0xf7, 0x2e, 0xd5, 0x4c, 0x1c, 0xdc, 0xeb, 0x7f, 0xe7, + 0x1a, 0x05, 0x0b, 0xff, 0x0c, 0xf8, 0xab, 0x1b, 0xee, 0xcd, 0x00, 0x06, 0xd7, + 0x21, 0x1e, 0x50, 0xf0, 0x0f, 0x0b, 0xb7, 0x21, 0x12, 0xec, 0x0e, 0x19, 0x2e, + 0xf4, 0xd4, 0xe0, 0x4c, 0xfc, 0x26, 0xeb, 0xf0, 0x44, 0xb0, 0x43, 0xe3, 0xfc, + 0xf2, 0xf9, 0x19, 0xb7, 0xc9, 0x39, 0xd5, 0x1e, 0x06, 0x07, 0xeb, 0x02, 0xf3, + 0x1f, 0x81, 0x05, 0xb9, 0x30, 0xe4, 0xf2, 0xd3, 0x02, 0xdf, 0x10, 0x0e, 0xf9, + 0xf1, 0xd6, 0x05, 0x24, 0xe3, 0x03, 0xfa, 0xc7, 0x0f, 0xed, 0xff, 0xd0, 0xc3, + 0x05, 0x2b, 0xfa, 0x0b, 0xd4, 0x19, 0x4a, 0xe6, 0x4c, 0x16, 0xee, 0x14, 0xe9, + 0x0c, 0xae, 0xe9, 0xd8, 0xd1, 0xdc, 0xd4, 0x1a, 0xdf, 0xf5, 0xd5, 0x0e, 0xde, + 0xf6, 0xf7, 0xea, 0x05, 0x18, 0xef, 0xd5, 0x03, 0xce, 0xf3, 0x1b, 0xdb, 0x2d, + 0x10, 0x21, 0x3f, 0xf9, 0xdd, 0xd8, 0xe6, 0x0e, 0x12, 0x09, 0x07, 0xed, 0x0f, + 0x2c, 0x1b, 0x12, 0xee, 0x00, 0x05, 0x7f, 0xd6, 0x39, 0xd5, 0x4d, 0x38, 0x05, + 0xfe, 0x39, 0x21, 0x05, 0xfc, 0x48, 0x27, 0x04, 0xfc, 0xec, 0xf4, 0x0c, 0xce, + 0x26, 0xf6, 0xf8, 0xf7, 0x2b, 0x49, 0x18, 0x25, 0x1e, 0xff, 0xda, 0x2f, 0x56, + 0x0f, 0x2a, 0x4a, 0x24, 0xf0, 0xe4, 0x37, 0xe8, 0x0a, 0xa0, 0x21, 0xe5, 0x93, + 0xaa, 0x08, 0x0b, 0xa5, 0xff, 0xf1, 0x0f, 0xd4, 0x64, 0xe0, 0xd2, 0xbd, 0xf9, + 0x44, 0x43, 0xeb, 0xe5, 0x0e, 0x08, 0xdd, 0xe1, 0x2c, 0xee, 0x81, 0x45, 0xe6, + 0xdf, 0xd1, 0xa5, 0x65, 0xe1, 0x03, 0xeb, 0xfc, 0xf8, 0xe6, 0x0a, 0xed, 0xb5, + 0x20, 0xd5, 0xca, 0x3a, 0x2d, 0xf3, 0x1a, 0xf1, 0x3b, 0xd9, 0x9e, 0x0d, 0x4a, + 0xe3, 0xa9, 0xc8, 0x0c, 0x85, 0x25, 0xf0, 0x2b, 0xb5, 0xb7, 0xf3, 0xad, 0x2c, + 0x45, 0x57, 0xf8, 0x4a, 0xa0, 0xe3, 0x32, 0x22, 0xfc, 0x10, 0x03, 0x40, 0xe2, + 0xd4, 0xea, 0x05, 0xf2, 0x2f, 0x34, 0x81, 0xba, 0xbf, 0xef, 0xe8, 0x2b, 0x0e, + 0x3e, 0xb0, 0x44, 0x04, 0xa7, 0x2f, 0x20, 0x33, 0xfe, 0x3c, 0x41, 0x21, 0xbe, + 0xdc, 0xf9, 0x10, 0x15, 0xd8, 0x19, 0x47, 0xad, 0x2c, 0x0d, 0x2b, 0xf4, 0xfc, + 0x35, 0xbd, 0x2d, 0x0d, 0x36, 0x58, 0x22, 0x07, 0xee, 0x05, 0x7f, 0x15, 0xc5, + 0x17, 0x0c, 0xfd, 0xf6, 0xe3, 0x1d, 0x2f, 0xcc, 0x9a, 0x5a, 0x0d, 0x31, 0xc9, + 0x65, 0x0c, 0xdc, 0x2c, 0x3b, 0xe4, 0xfd, 0xe1, 0xa4, 0xf4, 0xfc, 0xeb, 0xc4, + 0xcc, 0xf3, 0x0c, 0x32, 0x33, 0x12, 0xf0, 0x27, 0xaf, 0xfa, 0xd6, 0xdd, 0x1b, + 0xcc, 0xcf, 0x41, 0x32, 0xef, 0xde, 0x18, 0x08, 0xe9, 0xc2, 0xaa, 0xbc, 0xf3, + 0xaa, 0x03, 0x2f, 0xf3, 0xc9, 0x81, 0xbb, 0x91, 0x19, 0x26, 0xfe, 0x07, 0xfc, + 0x17, 0xcb, 0xb3, 0x0d, 0xd6, 0x15, 0xa5, 0xf0, 0xc2, 0xbd, 0x34, 0x1e, 0xcf, + 0xf8, 0xdf, 0x19, 0xdc, 0xb4, 0xe8, 0xde, 0x8c, 0x10, 0xfa, 0x05, 0x3a, 0xe5, + 0xe5, 0x04, 0xce, 0x0e, 0xf2, 0xf5, 0x2d, 0x12, 0xf3, 0x00, 0x8a, 0x37, 0x15, + 0xd8, 0xa3, 0x35, 0x0a, 0x81, 0xbe, 0xfd, 0xfe, 0x2c, 0x35, 0xdd, 0xed, 0x32, + 0xb5, 0xed, 0x0d, 0x14, 0xe8, 0xd9, 0x3c, 0x31, 0x18, 0x09, 0xfe, 0x3a, 0x0b, + 0x1b, 0xfa, 0xe5, 0x22, 0x07, 0xcd, 0x38, 0xc6, 0xeb, 0x08, 0x7f, 0x0c, 0x5c, + 0xf5, 0x1a, 0xe5, 0xd2, 0xcf, 0xdb, 0x04, 0x5a, 0x0e, 0xe9, 0x35, 0x1b, 0xd1, + 0x23, 0xe6, 0xf8, 0xfc, 0xeb, 0x34, 0xdd, 0x49, 0xd6, 0x00, 0x47, 0xd4, 0x11, + 0x0b, 0xfa, 0x1d, 0x37, 0x18, 0xe8, 0x28, 0xeb, 0x47, 0xb3, 0xe4, 0x4c, 0x28, + 0xf9, 0x28, 0x3c, 0xea, 0xf9, 0xf2, 0xda, 0x1e, 0xc4, 0xfd, 0xc1, 0xd8, 0xf8, + 0xfd, 0x7f, 0xf1, 0x2d, 0xaf, 0xe2, 0x08, 0xe1, 0x33, 0x34, 0xe8, 0x1a, 0x3b, + 0xd5, 0xf7, 0xbd, 0x3b, 0x0e, 0x31, 0x03, 0x01, 0xbf, 0xe1, 0x51, 0x07, 0x08, + 0x49, 0xf8, 0x4b, 0xa5, 0x4b, 0x25, 0x27, 0xfe, 0xee, 0x07, 0xd7, 0xb5, 0xf3, + 0xd4, 0x51, 0xc3, 0x34, 0xd8, 0x29, 0xe4, 0x1a, 0xca, 0xbe, 0x1d, 0x14, 0x55, + 0x0f, 0xa0, 0xd0, 0xd7, 0x14, 0xa1, 0xc4, 0x61, 0xb4, 0xf0, 0xbd, 0xf3, 0xd6, + 0xf0, 0x81, 0x43, 0x2b, 0x20, 0xdf, 0xfc, 0x52, 0x2d, 0x35, 0xec, 0xd5, 0xe2, + 0x51, 0x4b, 0x29, 0xfc, 0x1c, 0xd7, 0x36, 0x12, 0xcc, 0x04, 0xee, 0xd5, 0xac, + 0x30, 0xd5, 0xe8, 0xfb, 0x18, 0xf1, 0xf2, 0x1a, 0xc2, 0x2b, 0x18, 0xae, 0xe0, + 0x9f, 0xcd, 0xbb, 0xec, 0x4d, 0x18, 0xc3, 0x7a, 0x3e, 0xba, 0x20, 0xf8, 0xe7, + 0xde, 0xd9, 0xbd, 0xe1, 0xc6, 0x73, 0x5b, 0x7e, 0xd5, 0x1e, 0xe9, 0xcd, 0xcd, + 0xd4, 0xc7, 0x00, 0x0e, 0x6a, 0xf7, 0x3d, 0xff, 0x11, 0x7f, 0x0e, 0x18, 0xcd, + 0x0b, 0x31, 0x3a, 0x49, 0x0a, 0xed, 0xdd, 0xf5, 0x1d, 0xbd, 0x3f, 0x29, 0x0b, + 0x0c, 0x07, 0xf6, 0x46, 0x15, 0xb6, 0xd2, 0x40, 0x4b, 0xc9, 0xee, 0x67, 0x40, + 0x44, 0x56, 0x4d, 0x0e, 0xda, 0xfc, 0xf3, 0xea, 0xf6, 0xfd, 0xff, 0x17, 0xf9, + 0xf9, 0x05, 0xd8, 0xf9, 0x05, 0x07, 0xee, 0xe0, 0x13, 0xf3, 0xc8, 0xf0, 0xab, + 0x0a, 0x41, 0x3d, 0xda, 0x9f, 0xf5, 0x04, 0x81, 0x14, 0x07, 0x09, 0xff, 0x24, + 0x0b, 0x0d, 0xee, 0xce, 0xf3, 0x0b, 0xfb, 0x02, 0x2d, 0xf0, 0x18, 0x1e, 0xf8, + 0xfb, 0xf4, 0xf5, 0x3c, 0x06, 0x15, 0xfd, 0xfb, 0xbe, 0x12, 0x01, 0x06, 0x10, + 0x0c, 0x29, 0xea, 0xf2, 0xf6, 0xfd, 0x1e, 0x2a, 0x15, 0xf7, 0xed, 0xbd, 0xd6, + 0x34, 0xe9, 0xfe, 0xc4, 0x43, 0x3a, 0xb2, 0x4f, 0xe7, 0xeb, 0x3d, 0xbc, 0x7f, + 0xe0, 0x33, 0x0e, 0x28, 0x27, 0xe5, 0xf0, 0x35, 0x19, 0xca, 0x10, 0xdc, 0xdc, + 0xb3, 0xf2, 0x06, 0x0a, 0xdf, 0x45, 0x31, 0x15, 0xf4, 0xb7, 0xf7, 0x10, 0xff, + 0xff, 0xd9, 0xe1, 0xe1, 0xd0, 0x0f, 0x03, 0x03, 0xfc, 0xfe, 0x0e, 0xc9, 0x17, + 0x21, 0xc9, 0xe4, 0xf8, 0x98, 0x08, 0xfe, 0x20, 0x5a, 0x1c, 0x3b, 0xfd, 0x00, + 0xe5, 0x27, 0x13, 0xc0, 0x45, 0x1f, 0xeb, 0xfb, 0xe2, 0x23, 0x0d, 0xd4, 0xeb, + 0xf4, 0x1a, 0x1b, 0x06, 0xe4, 0x1a, 0x2e, 0x4c, 0x1d, 0xea, 0x1e, 0xd8, 0x8f, + 0xfa, 0x3b, 0xdd, 0xe4, 0x2a, 0x0d, 0xf9, 0x02, 0xce, 0x07, 0x11, 0x18, 0xeb, + 0x1b, 0x21, 0xfd, 0x81, 0x09, 0x02, 0xf3, 0x0e, 0x19, 0xf0, 0x3d, 0xd0, 0xc9, + 0xfb, 0x72, 0x36, 0x24, 0x32, 0x15, 0x04, 0x12, 0x7f, 0x3a, 0x0d, 0x1a, 0x1d, + 0xe4, 0xf0, 0x07, 0x09, 0x0a, 0xff, 0x59, 0x18, 0xbf, 0xe9, 0x2b, 0xf2, 0xf0, + 0x29, 0x1e, 0xf1, 0x31, 0xc8, 0xe2, 0x4c, 0xf7, 0x6c, 0xf6, 0x51, 0x1c, 0xec, + 0x1b, 0x3a, 0x17, 0x08, 0xf7, 0x43, 0xec, 0xc4, 0xeb, 0x20, 0x2f, 0xe4, 0x26, + 0xf1, 0xfe, 0xd1, 0xfe, 0xe4, 0x69, 0xfb, 0x03, 0xd4, 0xf3, 0xbf, 0x44, 0xed, + 0x4c, 0xec, 0x10, 0x52, 0x0f, 0xc6, 0xf5, 0x24, 0x1c, 0xe7, 0xf3, 0xbc, 0x19, + 0x7f, 0xe4, 0x4c, 0x0d, 0x11, 0xf4, 0xeb, 0x14, 0xbb, 0x45, 0xe9, 0xce, 0x0d, + 0x0f, 0xc7, 0x1c, 0x12, 0xf0, 0x18, 0x06, 0x0f, 0xc2, 0xd6, 0xd0, 0xb9, 0x03, + 0x15, 0xe2, 0x18, 0x4f, 0x4d, 0x3b, 0x02, 0xd4, 0xe2, 0xfb, 0x2c, 0xe0, 0x1d, + 0x18, 0xc8, 0xf6, 0x29, 0x1c, 0xf1, 0xea, 0x20, 0x24, 0x8c, 0x1e, 0x05, 0x22, + 0x2a, 0x00, 0x11, 0xe4, 0x00, 0x17, 0x1d, 0xc5, 0x0e, 0x7f, 0xe6, 0xd0, 0xd4, + 0xee, 0x45, 0xd5, 0x26, 0xd7, 0xe4, 0xeb, 0x47, 0xf1, 0x6a, 0x1c, 0x26, 0x45, + 0x42, 0xeb, 0x06, 0x2e, 0xfc, 0xd5, 0xfa, 0xcb, 0x01, 0xf4, 0xc2, 0xe3, 0x0b, + 0x0a, 0xcd, 0x49, 0x01, 0x28, 0x19, 0xde, 0x86, 0xd8, 0x11, 0xfd, 0x1c, 0x25, + 0x2a, 0x1a, 0x05, 0x1c, 0xf5, 0x78, 0x34, 0x1e, 0xe7, 0x06, 0x1d, 0xe7, 0xcc, + 0xde, 0xfb, 0x02, 0xf2, 0x7f, 0x26, 0x08, 0xb7, 0xd6, 0xaa, 0x0c, 0xe8, 0x23, + 0x28, 0xfb, 0xef, 0x04, 0x0b, 0xd8, 0x02, 0xc1, 0xf0, 0x31, 0x2b, 0xe6, 0x1b, + 0xfe, 0x0c, 0x1a, 0xbe, 0xf9, 0x14, 0xef, 0xe2, 0xc8, 0xe0, 0xf2, 0x2a, 0x6d, + 0x0d, 0x15, 0xc3, 0xfe, 0x43, 0x2c, 0x12, 0xf4, 0x6a, 0x10, 0x1c, 0x28, 0xdf, + 0xf5, 0x15, 0xb1, 0xd7, 0x03, 0xea, 0xf3, 0x42, 0x9a, 0xec, 0xcb, 0x3e, 0xf3, + 0xc6, 0x69, 0x10, 0xf0, 0x14, 0xea, 0x17, 0x00, 0x6f, 0xe7, 0x81, 0xe9, 0x8b, + 0x0a, 0xd5, 0x62, 0x4c, 0x38, 0x57, 0x92, 0xb6, 0xeb, 0xe9, 0xe4, 0x63, 0xb3, + 0xfd, 0x00, 0x2e, 0x3f, 0x11, 0xee, 0xf3, 0x05, 0xdc, 0x88, 0x0c, 0x2c, 0x4c, + 0xd6, 0xf2, 0x06, 0x1c, 0xdc, 0x55, 0xeb, 0xfe, 0xb5, 0x0d, 0xa3, 0x07, 0x22, + 0xae, 0x3a, 0xd2, 0x79, 0x26, 0xf8, 0x3f, 0x26, 0x31, 0x2c, 0x29, 0x45, 0xfb, + 0x34, 0xfa, 0x6a, 0x38, 0xbc, 0xe0, 0x55, 0xfe, 0xf8, 0x21, 0xfb, 0xe9, 0xec, + 0x0b, 0xca, 0xd7, 0xbb, 0xff, 0x7f, 0xfc, 0x1b, 0xcf, 0xd5, 0x33, 0x54, 0xfc, + 0x0e, 0xd3, 0x25, 0xfc, 0x31, 0xc0, 0x4d, 0xe9, 0x09, 0x39, 0xc9, 0xe5, 0xf3, + 0xe3, 0x22, 0xf9, 0xf1, 0xb5, 0xff, 0x7f, 0xec, 0x46, 0x09, 0xfb, 0xdf, 0xc8, + 0xcf, 0x37, 0x35, 0x56, 0x17, 0xf2, 0xf9, 0xee, 0xe1, 0x04, 0xf6, 0xf9, 0xf0, + 0xc6, 0x1e, 0x04, 0xd9, 0x04, 0x31, 0x1d, 0xc3, 0x75, 0x58, 0x8a, 0x31, 0x2d, + 0x10, 0xa5, 0xd6, 0xee, 0x29, 0x8b, 0x39, 0xef, 0x24, 0x39, 0x01, 0x02, 0x44, + 0x21, 0xfa, 0xb2, 0x8a, 0x95, 0xe4, 0xde, 0xdd, 0xf4, 0xc8, 0xf1, 0x28, 0x23, + 0x64, 0xff, 0x3f, 0xcf, 0x81, 0x32, 0x01, 0x0f, 0xc6, 0xef, 0xc4, 0x0e, 0x01, + 0x3a, 0x29, 0xb0, 0xf4, 0xf9, 0x22, 0x16, 0xb9, 0x00, 0xd0, 0xf3, 0x1e, 0x57, + 0x03, 0x10, 0xea, 0x56, 0x22, 0xf1, 0x3d, 0x0a, 0x06, 0xd2, 0x9a, 0x67, 0x14, + 0xd6, 0x3e, 0xd7, 0xbf, 0xea, 0xf0, 0xd5, 0x32, 0xbe, 0x24, 0x01, 0x9e, 0x11, + 0xd0, 0x1e, 0x8e, 0xaa, 0xd1, 0xfa, 0xe8, 0xf4, 0x1d, 0x3b, 0x7f, 0x14, 0xe8, + 0xe0, 0xba, 0x06, 0xc1, 0xf7, 0x14, 0x98, 0x18, 0xa5, 0x0e, 0x48, 0x2f, 0xf5, + 0xc3, 0xca, 0xce, 0xf9, 0x3f, 0x28, 0xd5, 0x27, 0x2e, 0x19, 0xdd, 0x68, 0x1e, + 0x44, 0x03, 0x07, 0xe4, 0xe0, 0xf5, 0x40, 0xf7, 0x5f, 0xfc, 0xbf, 0x41, 0xf7, + 0x0a, 0x9e, 0x18, 0xda, 0xc8, 0x19, 0xdf, 0xfa, 0x2f, 0xe8, 0x07, 0xfa, 0xf0, + 0xee, 0xfa, 0xb9, 0x29, 0x06, 0xb1, 0xae, 0x08, 0x2f, 0xec, 0xf9, 0xfc, 0xdf, + 0xbe, 0x7f, 0xc3, 0x1b, 0x0f, 0x11, 0xd8, 0x32, 0xfd, 0xe8, 0xed, 0x0d, 0xbf, + 0xef, 0xee, 0x48, 0xf7, 0x02, 0xf8, 0xd9, 0xef, 0xf2, 0x2e, 0xee, 0x11, 0xea, + 0xfe, 0xd8, 0xf6, 0xc0, 0x30, 0xb4, 0x20, 0x12, 0x09, 0xf9, 0xcf, 0xe9, 0x09, + 0xca, 0xd6, 0x4e, 0x30, 0xf8, 0xea, 0xeb, 0x03, 0x81, 0xee, 0x34, 0xf6, 0xf8, + 0xf5, 0xda, 0x30, 0x05, 0x04, 0xf6, 0x11, 0x40, 0xee, 0xfc, 0x0a, 0xda, 0xea, + 0x13, 0x0d, 0x1e, 0x3e, 0x11, 0x2a, 0x0e, 0x09, 0x18, 0x31, 0xd9, 0xd1, 0x0a, + 0xe5, 0xd1, 0x53, 0x3a, 0xd5, 0xd5, 0x4c, 0x6d, 0x03, 0xde, 0x3a, 0xd3, 0x21, + 0x11, 0x81, 0x15, 0x40, 0x5b, 0xfc, 0x15, 0xb3, 0x14, 0x8e, 0x47, 0x3e, 0x8a, + 0xb0, 0x2a, 0x57, 0x40, 0xee, 0xc1, 0xf4, 0x2a, 0x0c, 0xef, 0xc0, 0xb6, 0x2e, + 0x74, 0x73, 0x1e, 0xf8, 0xe7, 0x1d, 0x8c, 0x6d, 0xf6, 0xec, 0x35, 0xc6, 0xf2, + 0xde, 0x0a, 0xc9, 0xcb, 0x07, 0x15, 0xe1, 0x1b, 0x47, 0x0f, 0xf0, 0xf1, 0xf9, + 0x0d, 0x1a, 0x41, 0x08, 0x58, 0x29, 0xf7, 0x0e, 0x1f, 0x50, 0xeb, 0xe7, 0x19, + 0x47, 0xf3, 0x3d, 0x0c, 0x21, 0xfd, 0x08, 0x09, 0xde, 0x7f, 0x15, 0xfd, 0xe5, + 0x29, 0x0c, 0x15, 0x02, 0xfa, 0xdd, 0xeb, 0x07, 0x26, 0x01, 0x16, 0x3e, 0x3d, + 0xda, 0xe0, 0xda, 0x1c, 0xde, 0xe1, 0x2b, 0xe7, 0xf8, 0x04, 0xc3, 0x21, 0xf7, + 0x6f, 0xd2, 0xf7, 0xd2, 0x55, 0xb7, 0xe6, 0x20, 0xf6, 0xf8, 0xd4, 0x3e, 0xe7, + 0x2e, 0x3b, 0xd7, 0xd8, 0xb3, 0x9e, 0xc1, 0xde, 0x37, 0x2f, 0xcb, 0xb9, 0x25, + 0xb1, 0xb7, 0xc9, 0x0a, 0xa2, 0x5f, 0x17, 0x82, 0xb1, 0xce, 0x19, 0x36, 0x26, + 0xba, 0x0c, 0x09, 0xea, 0xf1, 0xea, 0xda, 0x04, 0xf9, 0x18, 0xee, 0xb5, 0x9f, + 0xb4, 0xfc, 0xc9, 0x7f, 0x15, 0xe8, 0x05, 0xe4, 0x24, 0x22, 0xf0, 0xd7, 0xda, + 0x14, 0xde, 0x2b, 0x0e, 0x08, 0x9c, 0x4a, 0x03, 0xec, 0xea, 0xe4, 0xd1, 0x2f, + 0xc6, 0x4b, 0xd1, 0x7f, 0xf9, 0x0e, 0xe6, 0xd8, 0x2f, 0xe2, 0x7a, 0xb0, 0x2c, + 0xdf, 0xd2, 0xd2, 0xe3, 0x17, 0x21, 0xd4, 0x35, 0x1b, 0xf9, 0x26, 0xfb, 0x13, + 0x4e, 0xff, 0x01, 0x42, 0x07, 0xea, 0xc9, 0xe5, 0x34, 0x30, 0x20, 0xf6, 0xd2, + 0x13, 0x2c, 0xcb, 0x3d, 0xf8, 0x42, 0xcc, 0x1a, 0xf3, 0xeb, 0xe9, 0x37, 0x1c, + 0x17, 0x41, 0x03, 0xa7, 0x1a, 0x31, 0x35, 0xd2, 0xf7, 0xdb, 0xa2, 0x2b, 0x09, + 0xcd, 0xdc, 0x20, 0xfa, 0x0f, 0xed, 0x39, 0x11, 0x27, 0x12, 0xeb, 0x1b, 0x20, + 0xad, 0x19, 0xa5, 0x0c, 0xff, 0x64, 0xd3, 0xc7, 0xef, 0x1f, 0xe5, 0x44, 0xc1, + 0xdc, 0x10, 0x2e, 0xa8, 0x2e, 0xdf, 0xc7, 0xd2, 0xfb, 0x26, 0xc0, 0xe2, 0xf2, + 0x52, 0x28, 0xea, 0xfc, 0x8b, 0x3c, 0x29, 0x4b, 0x38, 0xaa, 0x7f, 0x0a, 0x3f, + 0x4b, 0xf3, 0xe0, 0xc9, 0xe4, 0x06, 0x16, 0xdf, 0xaa, 0xd1, 0xec, 0xf2, 0x28, + 0x23, 0x00, 0x1a, 0xeb, 0xe3, 0xb3, 0x3d, 0x49, 0x2a, 0xac, 0x1e, 0xea, 0x29, + 0xcb, 0xbe, 0x52, 0xe2, 0x07, 0xd8, 0xf1, 0x20, 0x32, 0xc4, 0x39, 0x12, 0x02, + 0xd5, 0xd2, 0xf3, 0xeb, 0xe9, 0x13, 0x3d, 0xec, 0x6c, 0x13, 0xf9, 0x10, 0x73, + 0xe0, 0xd9, 0xe0, 0xf7, 0x19, 0xec, 0xfd, 0xe7, 0x08, 0xca, 0x37, 0xe9, 0xfd, + 0xf5, 0x03, 0x23, 0x05, 0x7f, 0xd2, 0xf1, 0x02, 0xdd, 0xf8, 0xc4, 0xce, 0xd6, + 0xeb, 0xb1, 0x1e, 0x21, 0xfe, 0x1a, 0xfd, 0xd9, 0x0d, 0x0f, 0x7f, 0xcc, 0x51, + 0x0a, 0xfb, 0xf3, 0x21, 0xdf, 0x41, 0xf8, 0x04, 0x18, 0x08, 0x03, 0x05, 0x31, + 0x39, 0x1c, 0x74, 0xf5, 0x1a, 0x03, 0xe6, 0x35, 0x5c, 0x03, 0xee, 0x55, 0xbf, + 0xff, 0x3c, 0xe1, 0x1f, 0x0e, 0xf7, 0x2c, 0xec, 0x51, 0xbe, 0xc2, 0xee, 0xf3, + 0x15, 0x11, 0xeb, 0xf1, 0x37, 0x1d, 0x21, 0x7f, 0x01, 0x69, 0xe8, 0x0f, 0x20, + 0x1e, 0x57, 0x10, 0x54, 0xbf, 0xf8, 0xe4, 0x27, 0x22, 0x0e, 0xe2, 0xc7, 0x42, + 0x09, 0x07, 0xe7, 0x01, 0xbe, 0x10, 0x41, 0xdb, 0xdf, 0x39, 0xc9, 0x11, 0xde, + 0xd7, 0xf7, 0x0c, 0x1b, 0xd9, 0x1b, 0xe7, 0xde, 0xf9, 0xf6, 0xe8, 0x22, 0x3d, + 0xf8, 0x15, 0xfb, 0x79, 0xf3, 0x1c, 0xfc, 0x06, 0xcb, 0x09, 0x52, 0xfe, 0x2d, + 0x16, 0xf7, 0x09, 0xe5, 0x43, 0xe0, 0x48, 0xce, 0xed, 0x0e, 0xc1, 0xea, 0x32, + 0xc0, 0xe0, 0xd7, 0xf2, 0x77, 0x0d, 0x76, 0x18, 0xd6, 0xb5, 0x2a, 0xca, 0x61, + 0xe4, 0xe0, 0x01, 0xd9, 0xd1, 0xec, 0x19, 0xc4, 0x0d, 0x22, 0x00, 0xac, 0x25, + 0xb8, 0xe0, 0xea, 0x37, 0xc5, 0x07, 0xc5, 0xe0, 0xe1, 0x19, 0x7f, 0xaf, 0x23, + 0xf5, 0xed, 0xb7, 0x69, 0x26, 0xf1, 0x07, 0x32, 0xe8, 0x2d, 0xf1, 0x3e, 0x0b, + 0xdc, 0xf3, 0xff, 0x1b, 0x10, 0xee, 0x2f, 0x16, 0x2b, 0xc9, 0x37, 0xff, 0xec, + 0xcc, 0xcb, 0xf2, 0x23, 0xeb, 0x06, 0x1c, 0xc9, 0xf1, 0x33, 0xf2, 0x0a, 0x06, + 0xaf, 0xf6, 0x27, 0x09, 0x98, 0x06, 0xeb, 0xfa, 0x11, 0x02, 0xf6, 0x03, 0x24, + 0x66, 0xe1, 0x43, 0xcf, 0xdd, 0xf9, 0xd2, 0x1d, 0x49, 0xdc, 0xf9, 0x05, 0x7f, + 0xe6, 0x22, 0x0e, 0xe5, 0x10, 0xfa, 0xcc, 0x16, 0xda, 0x03, 0xcd, 0x05, 0x0a, + 0xdc, 0x0d, 0x1e, 0x0b, 0x00, 0x15, 0x08, 0x24, 0xf8, 0xfb, 0x2e, 0xac, 0x08, + 0xed, 0xd5, 0x4e, 0x2b, 0xd2, 0x20, 0x38, 0x31, 0x2b, 0xb9, 0xc9, 0xf1, 0x56, + 0xd2, 0xa7, 0xfd, 0x95, 0x55, 0x4d, 0xef, 0xe4, 0xce, 0xb3, 0xd6, 0xd2, 0x2b, + 0x19, 0xd2, 0xe8, 0x29, 0x1c, 0x05, 0xad, 0xd8, 0x81, 0x34, 0x2a, 0x39, 0x6e, + 0x7a, 0x30, 0x04, 0x05, 0xd5, 0x2c, 0xac, 0x0d, 0x1b, 0xb2, 0x06, 0x11, 0x06, + 0xc8, 0xe5, 0x3c, 0x29, 0x2c, 0xc9, 0xfb, 0x2d, 0x97, 0x2f, 0xc6, 0x40, 0x25, + 0x16, 0x2c, 0x1b, 0x1e, 0xd1, 0x1d, 0xdf, 0xf8, 0x6c, 0xd9, 0x16, 0x4a, 0x1c, + 0x1a, 0xea, 0xd5, 0xcb, 0xdd, 0x00, 0x04, 0xf0, 0xc0, 0x02, 0xfe, 0xf4, 0x2e, + 0x02, 0x46, 0xe0, 0xdf, 0xb2, 0x29, 0x17, 0xd4, 0xd7, 0x44, 0xdf, 0xfc, 0x07, + 0xee, 0x23, 0xff, 0x14, 0x1f, 0xdb, 0xb9, 0xa1, 0x04, 0xf1, 0x93, 0x01, 0xd9, + 0x82, 0x7f, 0xee, 0x65, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0xd8, 0x31, 0x7a, 0xbf, 0x55, 0x3c, 0x49, 0x68, 0xb3, 0xbd, 0x56, 0xe8, + 0xa8, 0xeb, 0x48, 0x81, 0xac, 0xd2, 0xdd, 0xbe, 0x4c, 0x93, 0x67, 0x4d, 0x48, + 0x95, 0x3b, 0x17, 0x3d, 0x7f, 0xe3, 0x22, 0x48, 0xe3, 0xbd, 0x52, 0xf6, 0x08, + 0x4e, 0xb2, 0x48, 0x36, 0xd1, 0x5b, 0x67, 0xab, 0xdd, 0xd9, 0x44, 0xdd, 0xe4, + 0x41, 0x29, 0xa9, 0x1b, 0x46, 0x81, 0x43, 0x60, 0x4a, 0x0f, 0x50, 0x61, 0x7f, + 0xcf, 0x5b, 0x7f, 0xb6, 0x74, 0x5b, 0x5e, 0x7f, 0x9b, 0x8e, 0x46, 0xb3, 0x91, + 0xe5, 0x7f, 0xca, 0xb0, 0x81, 0xc4, 0xbb, 0x73, 0xe7, 0x7f, 0x69, 0x6e, 0x81, + 0x5b, 0x32, 0x6f, 0x7e, 0xa6, 0x7f, 0x68, 0x97, 0xac, 0x61, 0xc6, 0xd1, 0x65, + 0xae, 0x66, 0xe8, 0x96, 0x7f, 0x72, 0x91, 0xb5, 0xd9, 0x4e, 0xb4, 0x43, 0x4c, + 0x7f, 0xd2, 0xe1, 0x5d, 0x12, 0x7f, 0x6b, 0x65, 0x27, 0x68, 0x74, 0xfa, 0xf6, + 0x35, 0x1f, 0xd8, 0x41, 0x13, 0x2c, 0x37, 0xf4, 0xb7, 0x0e, 0xc6, 0xd9, 0x1a, + 0x4b, 0x1a, 0xe9, 0xaf, 0xea, 0xd4, 0x3b, 0x52, 0x1b, 0x2c, 0x2b, 0xbd, 0x1c, + 0x2f, 0x2e, 0x18, 0xc1, 0x6d, 0x3a, 0xa3, 0xe3, 0x27, 0xc7, 0xca, 0x32, 0xd3, + 0x25, 0xdc, 0xad, 0x20, 0x17, 0xc9, 0xd4, 0xf8, 0x19, 0xea, 0x6b, 0x18, 0x40, + 0x0a, 0xd4, 0x23, 0x59, 0x51, 0x22, 0x2c, 0x20, 0x20, 0x29, 0x85, 0xaa, 0x60, + 0x73, 0x9e, 0x4d, 0x72, 0x5f, 0x6a, 0x86, 0xbe, 0x70, 0xc0, 0xb4, 0xa3, 0x5c, + 0xa7, 0x81, 0x25, 0x95, 0x81, 0x51, 0x99, 0x26, 0x5e, 0x7f, 0xb7, 0x48, 0x53, + 0x46, 0x6e, 0xbf, 0x35, 0x6c, 0xba, 0xa7, 0x7d, 0xbf, 0xc4, 0x51, 0x8d, 0x5e, + 0x7f, 0x97, 0x12, 0x6e, 0x87, 0xa1, 0x43, 0x59, 0xa7, 0x25, 0x59, 0xbe, 0x9a, + 0x60, 0x63, 0xb9, 0x0a, 0x5d, 0x4e, 0x46, 0x51, 0x69, 0x2e, 0x81, 0x7f, 0x7d, + 0x81, 0x7f, 0x7f, 0x7f, 0x64, 0x81, 0x81, 0x7f, 0x81, 0x81, 0x81, 0x69, 0x14, + 0x81, 0x27, 0x81, 0x91, 0x7f, 0x78, 0x1e, 0x7f, 0x5e, 0x91, 0x7f, 0x7f, 0x7f, + 0x58, 0x81, 0x77, 0x7f, 0x81, 0x81, 0x7f, 0x81, 0x9a, 0x7f, 0x81, 0x7f, 0x41, + 0x81, 0x63, 0x7f, 0x81, 0x81, 0x6a, 0x7f, 0x81, 0x78, 0x7f, 0x22, 0x81, 0x5b, + 0x7f, 0x48, 0x4c, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xd3, 0xcd, 0x40, 0x3d, 0xc6, + 0x4c, 0x1c, 0x3e, 0x20, 0xbe, 0xb5, 0x1a, 0xad, 0xb5, 0xda, 0x37, 0x4d, 0xda, + 0x07, 0xc3, 0xdd, 0x44, 0x7f, 0x0a, 0x3e, 0x19, 0xb3, 0x44, 0x45, 0x3c, 0xff, + 0xab, 0x4f, 0x3b, 0x91, 0xb1, 0x32, 0xba, 0xbc, 0x35, 0xc8, 0x2e, 0xab, 0xc9, + 0x46, 0x26, 0xbb, 0xcb, 0x3e, 0x39, 0xd5, 0x7f, 0x2c, 0xf4, 0xd5, 0x10, 0x2f, + 0x4f, 0x43, 0x3e, 0x43, 0x51, 0x33, 0x1f, 0xd4, 0xc5, 0x59, 0x16, 0xd0, 0x20, + 0x48, 0x18, 0x1b, 0xc6, 0xd8, 0x3c, 0xc2, 0xf8, 0xc6, 0x41, 0xfd, 0xc6, 0x2b, + 0xb9, 0xc5, 0x13, 0x95, 0xe2, 0x22, 0x32, 0x10, 0x1c, 0x3f, 0x1c, 0x09, 0xc3, + 0x12, 0x36, 0xf2, 0xcc, 0x4d, 0xaa, 0x81, 0x23, 0xbb, 0x28, 0x51, 0xc2, 0xbd, + 0xfe, 0xb7, 0xa6, 0x5c, 0x28, 0xcd, 0x3c, 0x24, 0xa7, 0xdd, 0x57, 0x25, 0xe8, + 0xbf, 0x23, 0x1c, 0x53, 0x18, 0x11, 0xc7, 0xaf, 0x57, 0x25, 0xb5, 0x2a, 0x35, + 0x2e, 0x02, 0xa9, 0xb4, 0x56, 0xaa, 0xaf, 0xa6, 0x2d, 0x2e, 0xb6, 0x43, 0xa7, + 0xd8, 0x1f, 0x65, 0xd6, 0x39, 0xf5, 0xf6, 0x36, 0x58, 0x25, 0xe9, 0xb1, 0x07, + 0x44, 0xb8, 0xae, 0x4c, 0xaa, 0xbe, 0x3e, 0xb4, 0x33, 0x40, 0xdd, 0xdb, 0xf1, + 0xc6, 0xb0, 0x7f, 0x39, 0xbf, 0x59, 0x40, 0xb8, 0x9e, 0x7f, 0x3e, 0x2d, 0xe4, + 0x3e, 0x4b, 0x61, 0x29, 0x19, 0xc7, 0xe3, 0x22, 0x0b, 0xeb, 0x12, 0x06, 0x1a, + 0x06, 0xca, 0xec, 0x1e, 0xea, 0xca, 0xc7, 0xf9, 0x30, 0xe7, 0x20, 0xc9, 0xfa, + 0x15, 0x28, 0x08, 0x20, 0xcc, 0x03, 0x23, 0x2e, 0x13, 0xfc, 0xe0, 0x06, 0x16, + 0xe1, 0xce, 0x2a, 0xe1, 0xdf, 0x2b, 0xf1, 0x14, 0xc8, 0x06, 0xf6, 0xf2, 0xe7, + 0xde, 0x44, 0x2b, 0xec, 0x38, 0x15, 0xcc, 0xda, 0x28, 0x1d, 0x0a, 0x07, 0x2e, + 0x26, 0x29, 0x14, 0x05, 0x22, 0x3a, 0x68, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xd5, 0x4f, 0x00, 0x00, 0x93, 0xfe, 0xff, 0xff, 0x2a, + 0xf6, 0xff, 0xff, 0x5b, 0x51, 0x00, 0x00, 0x78, 0xfc, 0xff, 0xff, 0x1e, 0x01, + 0x00, 0x00, 0x43, 0xfe, 0xff, 0xff, 0xd9, 0xff, 0xff, 0xff, 0x2b, 0x3c, 0x00, + 0x00, 0xac, 0x31, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x43, 0x57, 0x00, 0x00, + 0xdf, 0x40, 0x00, 0x00, 0xe9, 0x56, 0x00, 0x00, 0x52, 0xe8, 0xff, 0xff, 0x43, + 0x14, 0x00, 0x00, 0xc8, 0x57, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x2f, 0x59, + 0x00, 0x00, 0xd4, 0x3f, 0x00, 0x00, 0x9f, 0xfe, 0xff, 0xff, 0x3c, 0xf5, 0xff, + 0xff, 0x2b, 0xf0, 0xff, 0xff, 0xac, 0xfb, 0xff, 0xff, 0x72, 0xea, 0xff, 0xff, + 0xeb, 0x65, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xc3, 0xff, 0xff, 0xff, 0x2a, + 0x01, 0x00, 0x00, 0x2b, 0x0f, 0x00, 0x00, 0x7f, 0x53, 0x00, 0x00, 0x43, 0x01, + 0x00, 0x00, 0x4f, 0xee, 0xff, 0xff, 0x26, 0x46, 0x00, 0x00, 0x18, 0x26, 0x00, + 0x00, 0x11, 0x02, 0x00, 0x00, 0xb7, 0x3c, 0x00, 0x00, 0xea, 0x34, 0x00, 0x00, + 0xcb, 0xfe, 0xff, 0xff, 0x20, 0x6c, 0x00, 0x00, 0x7a, 0xff, 0xff, 0xff, 0xdb, + 0xf7, 0xff, 0xff, 0xc3, 0x57, 0x00, 0x00, 0xde, 0xff, 0xff, 0xff, 0x46, 0xfd, + 0xff, 0xff, 0xd4, 0x40, 0x00, 0x00, 0xbf, 0x58, 0x00, 0x00, 0x62, 0x00, 0x00, + 0x00, 0x55, 0xf7, 0xff, 0xff, 0xe7, 0x65, 0x00, 0x00, 0x0b, 0xe4, 0xff, 0xff, + 0x36, 0x00, 0x00, 0x00, 0x95, 0x08, 0x00, 0x00, 0x4d, 0x56, 0x00, 0x00, 0x0c, + 0xf5, 0xff, 0xff, 0xac, 0xff, 0xff, 0xff, 0x58, 0xfb, 0xff, 0xff, 0xec, 0xf8, + 0xff, 0xff, 0x83, 0xf0, 0xff, 0xff, 0xa1, 0xe1, 0xff, 0xff, 0x43, 0xf8, 0xff, + 0xff, 0xfa, 0xff, 0xff, 0xff, 0x14, 0x02, 0x00, 0x00, 0x9f, 0x11, 0x00, 0x00, + 0x46, 0x69, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x35, + 0x0c, 0xc2, 0x04, 0x56, 0x1a, 0x14, 0x2f, 0x49, 0xe0, 0x11, 0x00, 0x14, 0xdf, + 0xfb, 0x14, 0x07, 0xed, 0x61, 0x4f, 0x08, 0x00, 0x29, 0xf1, 0xd7, 0x0d, 0x9d, + 0xb3, 0x0a, 0x36, 0x00, 0x81, 0x95, 0x0e, 0x01, 0x08, 0x18, 0xda, 0xeb, 0x46, + 0x21, 0x46, 0xc0, 0xe6, 0x35, 0x28, 0x2c, 0x00, 0x1d, 0xe5, 0xc1, 0xfa, 0x3f, + 0xd3, 0x0a, 0x12, 0x04, 0xf0, 0xd8, 0xe6, 0xce, 0x42, 0xfa, 0x0f, 0xe3, 0x04, + 0x7f, 0x1c, 0xea, 0xda, 0xbb, 0xde, 0xdb, 0xe1, 0x41, 0x33, 0xfd, 0x27, 0x42, + 0xd1, 0xc6, 0xe0, 0xe1, 0xed, 0x25, 0x0e, 0xf0, 0xfb, 0x13, 0x0c, 0x41, 0x15, + 0x4b, 0x20, 0x16, 0xae, 0x1a, 0xe9, 0xee, 0xf8, 0x17, 0xfc, 0x24, 0xb2, 0x0d, + 0xfd, 0x2a, 0x12, 0xbf, 0xf4, 0xe6, 0x41, 0xba, 0xe8, 0x4d, 0x0c, 0x61, 0xdd, + 0xff, 0xb4, 0xe5, 0xc5, 0x1f, 0xeb, 0xf8, 0xe1, 0xaf, 0x01, 0xf7, 0x15, 0xee, + 0xeb, 0xec, 0x08, 0xf5, 0xe4, 0xfe, 0xe1, 0xe8, 0xf2, 0x06, 0xd9, 0x11, 0xfa, + 0x17, 0x03, 0xea, 0x14, 0xef, 0x1b, 0xeb, 0x0b, 0xdb, 0xd0, 0x1b, 0x0d, 0x7f, + 0x13, 0x16, 0xf7, 0xcb, 0xe0, 0x16, 0x0d, 0xcb, 0xd6, 0x04, 0xdf, 0x31, 0x24, + 0xf8, 0x16, 0x51, 0xd1, 0xf5, 0x13, 0x09, 0xd7, 0xea, 0xf4, 0x10, 0x09, 0x12, + 0x21, 0x0d, 0xf7, 0xcd, 0xe8, 0xd6, 0x23, 0x1d, 0x2b, 0xd9, 0x01, 0x1d, 0x11, + 0xf3, 0x7f, 0x08, 0xf4, 0x06, 0x0d, 0x02, 0x09, 0xd8, 0xf1, 0x1b, 0x02, 0xe7, + 0x26, 0x14, 0xe3, 0xe3, 0xfd, 0x03, 0xf1, 0xf0, 0x1a, 0x25, 0xec, 0x07, 0xe7, + 0x1f, 0xf4, 0xd1, 0xb1, 0xea, 0x12, 0x06, 0x19, 0x30, 0xd5, 0x1e, 0xf5, 0xef, + 0x22, 0x09, 0xea, 0x1f, 0xff, 0xf4, 0xf7, 0x01, 0xf2, 0x1b, 0x0c, 0x16, 0x17, + 0x0e, 0xf7, 0xe2, 0xd4, 0x0e, 0xda, 0xd4, 0x1c, 0x01, 0x30, 0xe8, 0x14, 0xfb, + 0x1f, 0xc0, 0x2f, 0x2b, 0xf7, 0xd4, 0x4e, 0x81, 0x3d, 0x9f, 0x3d, 0x0f, 0x5c, + 0x0a, 0xdb, 0x28, 0xf6, 0xd3, 0x10, 0xd5, 0x03, 0x07, 0x8f, 0xba, 0x4b, 0x12, + 0xd6, 0xed, 0xdb, 0xfa, 0xe6, 0xea, 0xbf, 0x17, 0xd0, 0xde, 0x2a, 0x03, 0x10, + 0xeb, 0xea, 0x35, 0xeb, 0x1b, 0x08, 0x0a, 0x26, 0x23, 0xb9, 0x3c, 0x21, 0x0c, + 0xee, 0x00, 0x39, 0x09, 0x22, 0x92, 0xc8, 0xe7, 0xfe, 0x3d, 0xf7, 0x13, 0xf5, + 0xf1, 0x19, 0xfd, 0x16, 0xeb, 0x07, 0x0e, 0xdc, 0x24, 0x0f, 0xa6, 0x1d, 0xeb, + 0xd2, 0x39, 0x03, 0xd4, 0xf2, 0xdb, 0xdf, 0x1f, 0xd6, 0xf6, 0xf8, 0x0c, 0xb0, + 0xee, 0xfc, 0xee, 0xb3, 0xf3, 0xd4, 0xd4, 0xe5, 0xeb, 0x23, 0x19, 0xf4, 0x02, + 0xc4, 0x64, 0xee, 0x7f, 0x20, 0x0e, 0xf6, 0xfc, 0x0d, 0xde, 0x54, 0x13, 0x1c, + 0xf5, 0x05, 0x07, 0xe1, 0xf9, 0xfe, 0x1d, 0xeb, 0xb1, 0x31, 0xd3, 0x12, 0xbc, + 0x72, 0xe3, 0xd9, 0xbc, 0x2b, 0x04, 0x03, 0x69, 0x23, 0x38, 0xf5, 0xb1, 0x40, + 0x1b, 0x0c, 0xa8, 0xf9, 0xe6, 0xc6, 0xe6, 0x08, 0xe4, 0x74, 0x42, 0x1b, 0xcb, + 0xf0, 0x26, 0xf4, 0xed, 0x19, 0xf8, 0x0c, 0x12, 0x1d, 0xbf, 0xfa, 0x12, 0x50, + 0xeb, 0x22, 0x2e, 0x1e, 0x02, 0xeb, 0x7f, 0x91, 0xd6, 0xe6, 0xff, 0x15, 0x08, + 0xe2, 0xf7, 0x0a, 0x09, 0xfa, 0x12, 0x19, 0x02, 0xd3, 0xb4, 0xd9, 0xeb, 0xba, + 0x22, 0xe0, 0x05, 0x25, 0xec, 0xd9, 0xc4, 0xe7, 0xce, 0xea, 0xf0, 0x03, 0x42, + 0x58, 0x3a, 0xfb, 0xf9, 0x12, 0x2c, 0xdd, 0x4d, 0x5c, 0x2d, 0x32, 0xde, 0xe8, + 0x01, 0xfb, 0xcf, 0x14, 0xd1, 0xec, 0xe4, 0xf7, 0x23, 0xbc, 0xb4, 0xd6, 0xe7, + 0xef, 0x7f, 0xef, 0xa2, 0xc0, 0x2c, 0xe4, 0x07, 0xf7, 0x3e, 0xc0, 0x42, 0x3f, + 0x7b, 0xc6, 0xd4, 0x43, 0x15, 0x06, 0x30, 0xf4, 0x58, 0x16, 0x14, 0xd0, 0x28, + 0x16, 0xd1, 0x22, 0x0a, 0x1a, 0xfa, 0x08, 0xf0, 0x2c, 0x18, 0xee, 0xc7, 0xf5, + 0xe1, 0xfa, 0xfa, 0xfb, 0xfa, 0xbe, 0xe9, 0x0d, 0x15, 0xe7, 0xc6, 0xfc, 0xfd, + 0x09, 0xee, 0xe3, 0xf7, 0x2a, 0x1a, 0x03, 0x23, 0x19, 0x00, 0xea, 0x13, 0xec, + 0x3f, 0x10, 0xf6, 0x1f, 0x48, 0x7f, 0x10, 0x11, 0xf4, 0x21, 0x04, 0x0d, 0x13, + 0x04, 0xd8, 0xf5, 0x21, 0x2c, 0xb6, 0x28, 0x3a, 0xe9, 0xeb, 0x57, 0x2a, 0x59, + 0x28, 0x19, 0x29, 0xb5, 0x4c, 0xd1, 0xf8, 0xd5, 0xfa, 0x01, 0xff, 0xeb, 0x18, + 0x81, 0xfc, 0xe2, 0xfd, 0xea, 0xde, 0x16, 0x1c, 0xed, 0x5e, 0x27, 0x07, 0xd2, + 0x2e, 0xe4, 0x0e, 0x24, 0xf9, 0xc5, 0x3b, 0xde, 0xfc, 0x13, 0x37, 0x9f, 0xfc, + 0xe1, 0xee, 0x12, 0x0f, 0x07, 0x1a, 0xe1, 0xe7, 0xf8, 0x33, 0xda, 0x23, 0xb6, + 0xcd, 0xde, 0xdf, 0x01, 0x65, 0xab, 0x15, 0xf5, 0x26, 0xff, 0xe5, 0xbd, 0x1d, + 0x39, 0x23, 0x11, 0xd5, 0xb3, 0x27, 0xed, 0x17, 0x21, 0xd9, 0x22, 0xd5, 0x01, + 0x3c, 0xf8, 0xf7, 0x2a, 0x7f, 0xf7, 0xdd, 0xeb, 0x23, 0x0f, 0x0e, 0x45, 0xd2, + 0x25, 0x75, 0xe2, 0xb0, 0xe7, 0x04, 0x14, 0x1a, 0xe0, 0x95, 0xec, 0xef, 0xad, + 0xde, 0x4c, 0x03, 0x05, 0x3a, 0xce, 0x21, 0xdc, 0xbc, 0x4c, 0x9b, 0xf2, 0x23, + 0x02, 0x15, 0x17, 0xfd, 0xea, 0x0e, 0x0e, 0xc0, 0x54, 0xfb, 0x05, 0x02, 0xd2, + 0xdc, 0xf3, 0x25, 0xe1, 0x1e, 0x22, 0xf3, 0x04, 0x9d, 0xe7, 0xfd, 0x19, 0x05, + 0x37, 0x05, 0xd4, 0xc2, 0xc3, 0x1a, 0x40, 0xee, 0xe0, 0xfb, 0xdb, 0xe3, 0x11, + 0x4e, 0x2c, 0x26, 0x10, 0xdc, 0x2e, 0xfb, 0xed, 0x06, 0x17, 0xeb, 0xda, 0x11, + 0xd1, 0xef, 0x37, 0x10, 0x7f, 0x01, 0x12, 0x09, 0xde, 0xe0, 0x14, 0x04, 0x0d, + 0x21, 0xea, 0x2e, 0xb7, 0x1b, 0x00, 0xeb, 0xf0, 0xe7, 0x2c, 0x24, 0x79, 0x1f, + 0xf0, 0xe0, 0xdc, 0x18, 0xd3, 0xdd, 0x03, 0x1c, 0x05, 0xd7, 0xe9, 0x21, 0xd4, + 0xe0, 0x43, 0x2e, 0x0a, 0xf3, 0x09, 0x1a, 0x30, 0x65, 0xe8, 0x3c, 0x20, 0x1d, + 0x0f, 0xf2, 0xb7, 0xfc, 0xd5, 0x7f, 0xbb, 0xff, 0xa9, 0xe9, 0xd4, 0x3b, 0x36, + 0x18, 0x30, 0xd7, 0xe2, 0xfd, 0x01, 0x9d, 0x39, 0x08, 0xfb, 0xa9, 0x32, 0xb6, + 0xff, 0xe8, 0x2f, 0xb9, 0x58, 0x5c, 0x15, 0xd3, 0xb9, 0x02, 0x19, 0x81, 0xe9, + 0xc3, 0x18, 0x4e, 0xeb, 0x57, 0xbf, 0xb5, 0x2a, 0xdc, 0xc6, 0xe6, 0xff, 0xe6, + 0xed, 0x67, 0x30, 0xa6, 0x5f, 0xad, 0x09, 0xce, 0xd8, 0x17, 0xc7, 0x0e, 0x06, + 0xc2, 0xff, 0x0f, 0x1e, 0x01, 0xb0, 0x37, 0xff, 0xdd, 0x29, 0xec, 0xf2, 0x06, + 0xd4, 0x0c, 0xe1, 0xfb, 0xda, 0x24, 0xfd, 0x08, 0x5a, 0xfd, 0x14, 0xff, 0x0c, + 0xf4, 0xe7, 0xa4, 0xe4, 0x07, 0xed, 0xed, 0xbe, 0x2d, 0x2f, 0xad, 0xeb, 0x11, + 0xde, 0x0d, 0x2d, 0x58, 0x0d, 0xa2, 0x01, 0xf9, 0x06, 0xb7, 0xd6, 0xcf, 0x99, + 0xfd, 0x62, 0xfb, 0x38, 0xbe, 0x88, 0x35, 0x39, 0xf5, 0xf6, 0xec, 0xff, 0xfa, + 0xfb, 0xbd, 0x36, 0xba, 0x0d, 0x30, 0x50, 0x12, 0x28, 0x22, 0x81, 0x00, 0xd7, + 0xff, 0xfd, 0xf1, 0xb6, 0xf1, 0xb1, 0xf3, 0x38, 0xdb, 0x30, 0x48, 0x1b, 0x1a, + 0xd4, 0xd8, 0x22, 0xfb, 0x13, 0xdd, 0xec, 0xe6, 0xf0, 0xf6, 0x56, 0x08, 0xc8, + 0x0a, 0x1e, 0x4e, 0x1e, 0xac, 0x07, 0x02, 0x52, 0xf6, 0xd6, 0x59, 0xb5, 0x01, + 0xf0, 0x18, 0xcf, 0xfa, 0x1f, 0x22, 0x7f, 0x1b, 0xee, 0x79, 0x00, 0x00, 0x03, + 0xe8, 0xca, 0x14, 0xf7, 0xf4, 0xc5, 0xf7, 0x2e, 0x31, 0xd8, 0x03, 0xe9, 0x0c, + 0xf9, 0x1a, 0x32, 0x7c, 0xc5, 0xd7, 0x1c, 0xf7, 0x1c, 0xa8, 0x19, 0xbc, 0x0f, + 0x08, 0x3b, 0x0a, 0xa6, 0x2a, 0x0a, 0x0d, 0xd0, 0xb0, 0xf6, 0xfc, 0x14, 0xa7, + 0xe4, 0x1b, 0x34, 0x1d, 0x00, 0x06, 0x5f, 0xb6, 0x13, 0x38, 0xfc, 0x16, 0xed, + 0xff, 0xb3, 0x81, 0xf4, 0x2e, 0x2f, 0xc1, 0xeb, 0x03, 0x36, 0x2c, 0xd6, 0xf4, + 0x64, 0x5c, 0xe2, 0x48, 0xb6, 0xe3, 0x2d, 0xf9, 0xce, 0xe0, 0x11, 0x1f, 0x1f, + 0xaf, 0xe9, 0x1b, 0x43, 0xe3, 0x35, 0x4c, 0xf9, 0x68, 0xda, 0x24, 0xfa, 0x0b, + 0x50, 0xf9, 0xca, 0x16, 0xdd, 0x28, 0x0b, 0xf6, 0x49, 0x10, 0x0d, 0xdb, 0x0e, + 0x0c, 0x0c, 0xec, 0xfb, 0xfc, 0x0c, 0x1e, 0xef, 0xd7, 0xca, 0xb8, 0xea, 0x0b, + 0x0e, 0xc1, 0xed, 0xf5, 0xc6, 0xeb, 0x04, 0x7f, 0x01, 0xcb, 0x17, 0xff, 0xe1, + 0x7e, 0xfd, 0xed, 0x19, 0x0e, 0x17, 0x1c, 0x09, 0x2a, 0xe7, 0xe9, 0x10, 0xe5, + 0xe6, 0x25, 0xc7, 0xe6, 0xeb, 0xd0, 0xe4, 0xec, 0xdb, 0xd7, 0xf4, 0xfb, 0xd2, + 0x08, 0xfa, 0xf0, 0xe9, 0xf6, 0xd9, 0xf0, 0x12, 0xea, 0x1a, 0x11, 0x04, 0xef, + 0xed, 0x08, 0xfe, 0x00, 0xca, 0xe5, 0xd5, 0x1f, 0xef, 0x18, 0x7f, 0x2e, 0x13, + 0x10, 0x13, 0xf8, 0xf5, 0xed, 0x0c, 0xf6, 0xd8, 0xe7, 0x02, 0xd0, 0x12, 0xdd, + 0xf1, 0xda, 0xfc, 0xe8, 0xfa, 0xd4, 0xeb, 0xe8, 0xd8, 0xe3, 0xe2, 0x16, 0xed, + 0x2f, 0x07, 0x22, 0xfd, 0xfa, 0xf3, 0xee, 0xfb, 0xfe, 0xed, 0x47, 0xac, 0xe7, + 0xc6, 0x05, 0x01, 0xcc, 0x1e, 0x03, 0x09, 0x1a, 0x4a, 0xea, 0xef, 0xe5, 0xf4, + 0xe6, 0x19, 0x2c, 0x36, 0x07, 0x81, 0x34, 0xde, 0x1e, 0xfa, 0x2f, 0xe7, 0xfb, + 0xeb, 0x0d, 0x18, 0x1c, 0xee, 0xcf, 0xec, 0xe6, 0x20, 0xca, 0x12, 0xf3, 0xea, + 0x22, 0xe7, 0xee, 0xdb, 0x0e, 0xec, 0xfb, 0x0a, 0xf1, 0x0a, 0xdd, 0x3b, 0xe9, + 0xf2, 0x15, 0xf3, 0x29, 0xfd, 0xe7, 0x14, 0xf8, 0xfe, 0xe9, 0xd7, 0x1c, 0x7f, + 0xe6, 0xe1, 0xfa, 0xf3, 0x17, 0xff, 0xf5, 0xda, 0xe6, 0x21, 0xe9, 0x22, 0xd3, + 0xb4, 0x0f, 0xff, 0x04, 0x07, 0xff, 0xf0, 0xe3, 0xf1, 0x26, 0x45, 0xf0, 0xf9, + 0xf8, 0xe6, 0x0c, 0x26, 0xc4, 0xcb, 0xd5, 0xfe, 0xf3, 0x0b, 0xcd, 0xf7, 0xea, + 0xf2, 0x04, 0x15, 0xde, 0xf1, 0x1b, 0xfb, 0x26, 0x18, 0x12, 0xff, 0xfa, 0x10, + 0x38, 0x14, 0xf4, 0x0b, 0xc0, 0xe8, 0xf8, 0x30, 0xbd, 0x28, 0xc0, 0x3f, 0xde, + 0xe2, 0xec, 0x13, 0xde, 0x32, 0xd7, 0xf4, 0x1c, 0xd7, 0xf2, 0xf7, 0xf2, 0xdc, + 0xd5, 0xc1, 0xef, 0xaa, 0x3f, 0x0b, 0x13, 0x1b, 0xbb, 0x19, 0xd1, 0x04, 0xf5, + 0x7f, 0xd3, 0x03, 0x03, 0x3c, 0x1b, 0x12, 0x1e, 0x14, 0xcd, 0x0a, 0xd9, 0x31, + 0x3e, 0x47, 0xf1, 0xfe, 0x04, 0x04, 0xe2, 0x23, 0x00, 0xe8, 0x41, 0x08, 0xbf, + 0xa7, 0xf1, 0xe7, 0x12, 0xc9, 0x33, 0xe3, 0x0e, 0xeb, 0x98, 0xaa, 0xec, 0xf5, + 0x7f, 0x01, 0x01, 0xdc, 0xed, 0xee, 0x36, 0x20, 0xfd, 0xe4, 0xf6, 0x05, 0xed, + 0x14, 0xe2, 0xec, 0xe9, 0xec, 0xf4, 0x3b, 0xee, 0x22, 0x00, 0x1f, 0xe5, 0xed, + 0xe2, 0x03, 0x08, 0xdd, 0x00, 0x56, 0x28, 0xdc, 0x09, 0xc0, 0xef, 0xdd, 0xec, + 0xf8, 0xe2, 0xdb, 0x10, 0xf6, 0x05, 0xfe, 0x18, 0xdd, 0x1a, 0x02, 0xf8, 0x93, + 0xbc, 0x0e, 0x3e, 0x0d, 0xe4, 0xaa, 0x03, 0xdd, 0xe3, 0x44, 0xe4, 0x39, 0x07, + 0xdd, 0xe8, 0xfc, 0x33, 0x12, 0xfd, 0xf4, 0x2c, 0xda, 0xf7, 0x02, 0xe9, 0x1c, + 0x0c, 0x31, 0x22, 0x1d, 0x15, 0x30, 0xf1, 0xc6, 0xfc, 0xe7, 0x7f, 0xf3, 0x02, + 0xef, 0x1d, 0x31, 0xf9, 0xe2, 0xc3, 0xf9, 0x1f, 0x0f, 0x22, 0x12, 0xf5, 0x3a, + 0xe4, 0x07, 0x0b, 0xea, 0xdf, 0xe3, 0x1b, 0xe2, 0x24, 0x04, 0x74, 0x22, 0xb9, + 0x34, 0x18, 0xe2, 0xcd, 0xf4, 0x46, 0xd4, 0xf2, 0x1d, 0xf7, 0xe6, 0xea, 0x1a, + 0xfd, 0x17, 0xfb, 0x28, 0xee, 0xf7, 0x03, 0xfa, 0xea, 0x0b, 0xde, 0xef, 0xf1, + 0xdf, 0xf7, 0x0e, 0xff, 0x00, 0x0e, 0x1f, 0x02, 0x36, 0x1b, 0x7f, 0x14, 0xf3, + 0x1e, 0xf7, 0xd7, 0x26, 0xe5, 0xfc, 0xfb, 0xea, 0xce, 0xd8, 0xe9, 0x00, 0xc5, + 0x2e, 0xea, 0x30, 0xe3, 0xfc, 0xf9, 0xfc, 0xa2, 0xfa, 0xcb, 0x3f, 0xfa, 0x0f, + 0x08, 0xa1, 0x20, 0x05, 0x21, 0x81, 0x2d, 0xd4, 0x04, 0x82, 0xc1, 0xa9, 0xa6, + 0xbd, 0xfe, 0xcb, 0xf9, 0x01, 0x18, 0x2b, 0x17, 0x0a, 0xc1, 0xf2, 0x37, 0xdc, + 0xb3, 0xf0, 0xd2, 0x4a, 0x37, 0xfe, 0xa4, 0xc1, 0xe1, 0xc6, 0x36, 0xed, 0x04, + 0xdf, 0x18, 0x01, 0xc4, 0x13, 0xfd, 0x39, 0x1f, 0xb5, 0xe0, 0x44, 0x07, 0x9f, + 0xe2, 0x81, 0x60, 0xbe, 0xd5, 0x15, 0xd6, 0xb5, 0xf0, 0x3b, 0xbb, 0x00, 0x06, + 0x03, 0x57, 0x08, 0x13, 0x10, 0x1f, 0x2d, 0x09, 0x13, 0x17, 0xd8, 0xac, 0xd4, + 0x0f, 0xf8, 0x0a, 0xdf, 0xc0, 0x14, 0xc3, 0xf6, 0xcd, 0xfb, 0x25, 0xf2, 0x0f, + 0xf4, 0x03, 0xf2, 0xc0, 0xf0, 0xeb, 0x24, 0xf6, 0xf8, 0x2c, 0xdb, 0x16, 0xf9, + 0x23, 0x15, 0x36, 0x05, 0xbf, 0x06, 0x58, 0xb3, 0x05, 0x65, 0x28, 0x7f, 0xfa, + 0xe0, 0x1b, 0xe2, 0xf8, 0x35, 0x1d, 0x62, 0x29, 0xc8, 0x0f, 0x06, 0x06, 0xfa, + 0x22, 0x07, 0xb3, 0xe0, 0x1b, 0xcc, 0x14, 0xe3, 0xdd, 0xfa, 0xf6, 0x0a, 0xe8, + 0xe5, 0xec, 0xfa, 0x2a, 0x17, 0xd2, 0x47, 0x11, 0xf2, 0x13, 0xe8, 0x1d, 0x3c, + 0x7c, 0xc6, 0xbc, 0x0f, 0xfb, 0xec, 0xfd, 0x18, 0x81, 0xc9, 0xe9, 0x0e, 0xee, + 0x06, 0xf3, 0x1f, 0x25, 0xfc, 0x11, 0x74, 0x06, 0xe4, 0xd7, 0x04, 0x0b, 0x1e, + 0x0a, 0xfc, 0x55, 0xc9, 0xdc, 0x12, 0xe1, 0xfe, 0x19, 0xd2, 0xda, 0xd2, 0xa2, + 0xea, 0x34, 0x20, 0x0d, 0x42, 0x05, 0x0a, 0xc1, 0xb1, 0xce, 0x11, 0xb6, 0x02, + 0x01, 0x29, 0x1f, 0xd8, 0x40, 0xe3, 0x62, 0xc7, 0x14, 0x09, 0xd1, 0xef, 0x11, + 0x3d, 0xed, 0xc0, 0xc1, 0xe9, 0xe9, 0x13, 0x3f, 0x23, 0x81, 0x16, 0xd3, 0x0c, + 0xde, 0x40, 0xf2, 0x1e, 0x3e, 0x13, 0xfe, 0xd2, 0xeb, 0xdf, 0x10, 0xda, 0xdb, + 0x13, 0x03, 0x11, 0xad, 0xdf, 0xf6, 0x06, 0x56, 0x10, 0x10, 0xd7, 0xfa, 0xbe, + 0xf9, 0x12, 0xfb, 0x31, 0xe0, 0x0b, 0x30, 0xd9, 0xe9, 0x08, 0xea, 0x0d, 0xce, + 0x0f, 0x23, 0xf1, 0x03, 0xf8, 0xe8, 0xfe, 0xdf, 0xce, 0x29, 0xfb, 0xec, 0xcc, + 0x2c, 0xc0, 0xcd, 0xec, 0x13, 0x7f, 0xf4, 0x18, 0xd1, 0x0a, 0xc1, 0xfb, 0xfe, + 0x05, 0xe6, 0x0f, 0x0c, 0xfb, 0x0f, 0x30, 0x13, 0xe1, 0xd4, 0xf2, 0xea, 0xde, + 0xfe, 0x2c, 0xf9, 0xde, 0x18, 0x16, 0xf9, 0xea, 0xe1, 0x2e, 0x1e, 0xdc, 0xed, + 0x3c, 0x07, 0xfa, 0x06, 0x13, 0xfd, 0xcf, 0x04, 0xf3, 0x15, 0x0d, 0x81, 0xe5, + 0x08, 0xb8, 0xc8, 0xf6, 0xea, 0x14, 0xf7, 0xef, 0xea, 0x43, 0x19, 0xeb, 0x3d, + 0xf9, 0x1b, 0xb7, 0x0b, 0x14, 0x0e, 0xed, 0xd5, 0xf9, 0xb7, 0x10, 0xe5, 0x4b, + 0xee, 0xd2, 0x17, 0xf2, 0x14, 0x25, 0xfa, 0xd8, 0x05, 0x06, 0xd1, 0x17, 0xf8, + 0xf7, 0xc6, 0xc9, 0xbc, 0xfd, 0xe5, 0xf9, 0xd3, 0xd2, 0xcb, 0xd4, 0xce, 0x0a, + 0xc9, 0xd3, 0xfe, 0xb3, 0x5e, 0x0d, 0xf5, 0x0c, 0xcd, 0x1c, 0x7f, 0xe8, 0x9a, + 0x15, 0x63, 0x30, 0x08, 0x3b, 0x0a, 0x26, 0x9e, 0x26, 0x5c, 0x6e, 0xe5, 0x6a, + 0xcd, 0xdc, 0x04, 0xf0, 0xe9, 0xeb, 0xf8, 0x20, 0xbe, 0x2e, 0xdc, 0x11, 0x01, + 0xb0, 0xce, 0x2f, 0x1f, 0xe0, 0xf6, 0xa3, 0xf2, 0xb4, 0xe2, 0x1a, 0x32, 0x16, + 0xdf, 0x42, 0xe7, 0x07, 0xd6, 0x38, 0xda, 0xc7, 0xcd, 0xeb, 0xf5, 0xdc, 0xff, + 0xed, 0x2d, 0x15, 0x17, 0x17, 0x27, 0x02, 0x03, 0x2e, 0x04, 0xea, 0x2e, 0xf4, + 0x7f, 0xdd, 0x04, 0x1c, 0x5d, 0xce, 0xd0, 0x00, 0x1f, 0xf5, 0xf2, 0x16, 0x72, + 0x07, 0xe0, 0x11, 0x30, 0x1d, 0xd6, 0x0e, 0x2d, 0x22, 0x7d, 0x0e, 0x00, 0xf0, + 0xff, 0xcc, 0x5a, 0xcb, 0x19, 0xfc, 0xd2, 0x9d, 0xe3, 0xce, 0x14, 0xfb, 0x4b, + 0x0e, 0xd4, 0xd9, 0xde, 0x1b, 0xa2, 0x00, 0xbc, 0xcf, 0xbf, 0x0a, 0xfc, 0xef, + 0x3f, 0x46, 0x40, 0x41, 0x10, 0x1e, 0xfe, 0x46, 0xe7, 0xce, 0xf8, 0xc3, 0x54, + 0x12, 0x60, 0xd2, 0xf3, 0xeb, 0xc2, 0xfb, 0x32, 0x63, 0x42, 0xd4, 0x41, 0xbf, + 0x41, 0x38, 0xe5, 0x38, 0xea, 0xdf, 0xf8, 0x07, 0x84, 0xb9, 0xf3, 0xe3, 0xcf, + 0xef, 0xcd, 0xc6, 0x34, 0xbd, 0x2c, 0x97, 0xc9, 0x81, 0x07, 0xd0, 0x2e, 0x10, + 0x13, 0xc3, 0xb0, 0x07, 0x05, 0xcb, 0xf0, 0xf8, 0x17, 0x19, 0x15, 0xe9, 0xfe, + 0xe2, 0x29, 0xfa, 0x3d, 0xb8, 0x01, 0xcd, 0x2f, 0xee, 0x04, 0xd8, 0xf6, 0xf8, + 0x5f, 0x98, 0xff, 0xd8, 0xd4, 0x54, 0x6a, 0xe9, 0x2c, 0x39, 0xee, 0x10, 0x19, + 0x19, 0xf8, 0xe8, 0xce, 0xf7, 0xfc, 0xb8, 0x14, 0xd8, 0x6c, 0x19, 0x30, 0x2c, + 0xf5, 0xbe, 0x24, 0xf2, 0xfb, 0xf2, 0xfc, 0xe3, 0xe2, 0xc3, 0xc1, 0xba, 0xaa, + 0x7f, 0x53, 0x08, 0x47, 0xf5, 0x2f, 0xfe, 0x54, 0x14, 0xba, 0x17, 0xea, 0x1c, + 0xff, 0xb6, 0x0e, 0xec, 0x1c, 0xf8, 0x32, 0xd8, 0xce, 0x24, 0x51, 0xe7, 0x1b, + 0x62, 0x60, 0x00, 0xc4, 0xd1, 0xc5, 0xcb, 0xca, 0xba, 0xc0, 0x00, 0x02, 0xfc, + 0x25, 0x9e, 0xff, 0x3f, 0xf6, 0x11, 0x41, 0xf0, 0xf4, 0x26, 0x10, 0x0b, 0xd2, + 0xfc, 0x00, 0x7f, 0x5b, 0x1d, 0xc3, 0x36, 0xc5, 0x3d, 0xfe, 0x10, 0x49, 0x48, + 0xdb, 0xc0, 0x0f, 0xa4, 0x42, 0x96, 0x31, 0xbc, 0xd2, 0x2d, 0x2e, 0x59, 0x24, + 0xe4, 0x0c, 0x22, 0x4d, 0x0b, 0xae, 0xf6, 0xeb, 0xc8, 0x09, 0x02, 0xde, 0x30, + 0x08, 0xbb, 0x3f, 0x3e, 0xbe, 0x0f, 0x09, 0x1b, 0xe8, 0x01, 0x3a, 0x73, 0xe9, + 0x2b, 0xe4, 0x25, 0xec, 0x05, 0x1a, 0x20, 0x13, 0xe9, 0xf8, 0xca, 0xfb, 0x0e, + 0xe7, 0x30, 0xe7, 0x22, 0x1b, 0xd6, 0xe7, 0x5d, 0x7f, 0xce, 0xc2, 0xcf, 0xc8, + 0xfd, 0xe9, 0x6e, 0x00, 0xe9, 0x4b, 0x2b, 0x91, 0xd6, 0xf4, 0xf4, 0x21, 0xbd, + 0xa6, 0x2c, 0xe6, 0xf3, 0xea, 0x1c, 0x0e, 0x07, 0x69, 0xee, 0xd7, 0xf4, 0xf3, + 0xed, 0x14, 0xc5, 0xf0, 0xea, 0xf5, 0xed, 0x0b, 0x35, 0x22, 0xd6, 0x0b, 0xd6, + 0xcc, 0x1c, 0x21, 0x37, 0x05, 0x1c, 0xdd, 0xd0, 0x18, 0xe8, 0x9d, 0x6b, 0x12, + 0x1c, 0x13, 0x4c, 0xdb, 0x3a, 0xee, 0xcb, 0x7f, 0x07, 0xf6, 0xe0, 0x98, 0x01, + 0x0d, 0x31, 0xdb, 0x1c, 0xb9, 0x0c, 0xe0, 0x14, 0xd0, 0x00, 0xe4, 0xda, 0xe8, + 0x3b, 0xcc, 0x04, 0xe3, 0x0d, 0x38, 0xf3, 0xfe, 0xf5, 0xe5, 0x3f, 0xc6, 0xcc, + 0x1c, 0x35, 0xe2, 0xf9, 0x14, 0x1e, 0xb7, 0x03, 0xd5, 0x7f, 0x0a, 0x25, 0x21, + 0x41, 0x32, 0x1d, 0xed, 0x24, 0xfc, 0x22, 0x3a, 0x19, 0xef, 0x11, 0xf5, 0xf7, + 0x0e, 0x30, 0xf6, 0xed, 0x25, 0x1d, 0x77, 0x00, 0xf0, 0xe2, 0x08, 0xf5, 0x28, + 0x7f, 0x16, 0x3d, 0xc9, 0x1b, 0xf3, 0xf0, 0xf1, 0x16, 0x82, 0x10, 0xcb, 0xf2, + 0x2f, 0xef, 0xd9, 0xdd, 0x02, 0xfd, 0xeb, 0x08, 0xf7, 0x21, 0xfd, 0xf6, 0xf1, + 0x0f, 0xd2, 0xd8, 0x10, 0xf0, 0xe1, 0xe5, 0xd3, 0xf1, 0x0a, 0xfd, 0x19, 0x58, + 0xf5, 0x27, 0xf5, 0x32, 0xd2, 0xe5, 0x34, 0xeb, 0x23, 0x5a, 0xf8, 0x23, 0x03, + 0xda, 0x00, 0x15, 0x15, 0x27, 0x33, 0xf7, 0x04, 0xe7, 0xe5, 0x10, 0xf1, 0x2f, + 0x06, 0x0e, 0xcc, 0xd9, 0x09, 0x0d, 0xb7, 0x26, 0x20, 0xfb, 0x0e, 0xc6, 0x01, + 0xf2, 0xe2, 0xee, 0xc6, 0x2b, 0x9f, 0xd2, 0x20, 0x02, 0xed, 0xda, 0x2f, 0xe0, + 0xf1, 0xf8, 0x11, 0x4e, 0xb8, 0x1d, 0xea, 0xf2, 0xee, 0xf8, 0x05, 0x23, 0xf8, + 0xdc, 0xa0, 0x59, 0x24, 0xe1, 0xe9, 0xd9, 0x0e, 0xf8, 0xe7, 0xe4, 0x4e, 0x35, + 0x0c, 0x7f, 0xdd, 0xba, 0xe0, 0xc6, 0xb6, 0x44, 0x16, 0xe1, 0x13, 0xe3, 0x38, + 0xf8, 0xe7, 0x16, 0xae, 0xdc, 0xdf, 0xcd, 0x45, 0xde, 0xfb, 0x3f, 0xd3, 0x06, + 0x22, 0xeb, 0x16, 0x06, 0xe3, 0xf6, 0xd0, 0x08, 0x08, 0xf0, 0x08, 0x1d, 0xda, + 0xba, 0xdd, 0xf7, 0x08, 0xf5, 0xf4, 0x17, 0xec, 0xef, 0x81, 0x37, 0xbd, 0x06, + 0x2a, 0x1f, 0xca, 0xfc, 0xf8, 0xef, 0x12, 0x69, 0x09, 0xfe, 0x06, 0x04, 0xde, + 0x0c, 0xe4, 0x12, 0xe4, 0x0d, 0xec, 0xdb, 0x88, 0xf4, 0xf0, 0x28, 0xeb, 0xe0, + 0x3a, 0xa3, 0xf1, 0xa5, 0x15, 0x0e, 0xea, 0xf9, 0x0a, 0x16, 0x15, 0x19, 0x10, + 0xad, 0x06, 0xf1, 0x06, 0xae, 0x08, 0x24, 0x35, 0xe1, 0xc4, 0x9f, 0xd7, 0xa2, + 0xda, 0xdd, 0x45, 0x19, 0x39, 0x14, 0xf3, 0x3c, 0xf1, 0xdb, 0x34, 0xf2, 0x07, + 0x27, 0xc1, 0x11, 0xdf, 0xd9, 0xb0, 0x1d, 0x5c, 0xfe, 0xe4, 0x0b, 0xe7, 0xf4, + 0x32, 0x1c, 0x7f, 0x35, 0x05, 0xef, 0xf5, 0x03, 0xeb, 0xa3, 0xdd, 0x20, 0x07, + 0x11, 0x2a, 0x13, 0xd8, 0xd9, 0xd3, 0xc0, 0xe3, 0xcc, 0xed, 0xcd, 0xfc, 0xcd, + 0xde, 0x31, 0xda, 0x07, 0xe9, 0xe9, 0xf9, 0x25, 0x42, 0xcb, 0x1b, 0x43, 0xec, + 0x39, 0xd7, 0x32, 0x17, 0xdb, 0xf3, 0x10, 0xf1, 0x3c, 0xc0, 0x07, 0xd6, 0x1d, + 0x81, 0xfa, 0xc3, 0x0d, 0xfc, 0x1c, 0xff, 0xc8, 0x05, 0xf0, 0xc9, 0x1c, 0x18, + 0xe5, 0x3b, 0xf3, 0xe9, 0xf6, 0xc8, 0xdd, 0x3b, 0xd4, 0x46, 0xe5, 0x0c, 0x10, + 0x03, 0x0b, 0x1b, 0x07, 0x44, 0x31, 0x34, 0x03, 0xe9, 0x44, 0xcf, 0x22, 0xe5, + 0xb5, 0x0e, 0x21, 0x66, 0xd7, 0x0c, 0xbd, 0xae, 0xf5, 0xe0, 0x63, 0xef, 0x7f, + 0xec, 0xf1, 0x21, 0xd1, 0xbd, 0x00, 0x32, 0xdf, 0xe6, 0xe0, 0xd3, 0xfc, 0xfa, + 0x2e, 0xe7, 0xf4, 0xf0, 0xaa, 0xde, 0xf5, 0x3a, 0xf8, 0xd8, 0x19, 0xfd, 0xe6, + 0xd1, 0xee, 0xe9, 0xf4, 0xe5, 0xf4, 0x42, 0x20, 0xc3, 0x4f, 0xd5, 0x49, 0x3b, + 0x5c, 0xe2, 0x0d, 0x69, 0x2b, 0x10, 0xea, 0x44, 0x06, 0x7f, 0x17, 0xe7, 0xcc, + 0xcb, 0x21, 0x4a, 0x45, 0xdf, 0x6e, 0x2c, 0xe2, 0x18, 0xc2, 0xd7, 0x3b, 0xa5, + 0x5b, 0x1f, 0x00, 0xfc, 0x1c, 0xa9, 0x9c, 0x9a, 0xee, 0xe3, 0xc1, 0xdd, 0xe3, + 0x4c, 0x45, 0x92, 0xba, 0xfe, 0x08, 0x32, 0xb5, 0x16, 0xf2, 0x0c, 0x2a, 0xce, + 0xad, 0xda, 0xa0, 0x60, 0x12, 0xc0, 0xec, 0x12, 0x06, 0x1e, 0x7f, 0x1c, 0xf3, + 0x10, 0xdc, 0xed, 0xcb, 0xec, 0x0e, 0xff, 0x08, 0xde, 0x0f, 0xf6, 0xf6, 0x0b, + 0xe9, 0x11, 0x0b, 0xf2, 0xf7, 0xce, 0x09, 0x06, 0xe8, 0xe3, 0xf1, 0x22, 0xd7, + 0xff, 0x0b, 0x04, 0x32, 0xe7, 0xe8, 0xed, 0xcf, 0x0a, 0x3b, 0xf5, 0xe9, 0x28, + 0x00, 0x08, 0xda, 0x05, 0x1c, 0xee, 0x01, 0x0b, 0x07, 0xf4, 0xfd, 0xb6, 0x14, + 0x2b, 0xd6, 0xb2, 0x08, 0xe8, 0x2e, 0xff, 0x17, 0x5a, 0x3b, 0x09, 0x24, 0xe0, + 0xdd, 0x55, 0x3b, 0xde, 0x05, 0x11, 0xbe, 0x12, 0x02, 0xe6, 0xde, 0x81, 0x0b, + 0x03, 0xf2, 0xf2, 0x5b, 0x08, 0xce, 0xef, 0x3b, 0xdb, 0x73, 0x08, 0x2c, 0x04, + 0x34, 0x0c, 0x29, 0xf7, 0xea, 0xf9, 0x02, 0xe8, 0x52, 0x02, 0x03, 0xf0, 0x40, + 0xec, 0xe6, 0xf8, 0xb6, 0x48, 0xf1, 0x22, 0x35, 0x12, 0xd7, 0x09, 0x0e, 0xc0, + 0xfd, 0x3c, 0x1b, 0x35, 0x46, 0x6c, 0xdc, 0x22, 0x8d, 0x39, 0xc0, 0x15, 0x2b, + 0x84, 0x29, 0x38, 0x69, 0x07, 0x08, 0x20, 0xff, 0x2f, 0xf4, 0x12, 0xe4, 0xfe, + 0x33, 0xed, 0xe9, 0xe3, 0x04, 0xd9, 0xe0, 0xa1, 0xae, 0x7f, 0x10, 0x12, 0x38, + 0xf0, 0xb3, 0xcd, 0x4d, 0xd5, 0x04, 0xdc, 0x18, 0x23, 0x16, 0x1d, 0x93, 0x0e, + 0xcf, 0x07, 0x1c, 0xa7, 0x61, 0x02, 0x29, 0x14, 0xdd, 0xdc, 0x31, 0xe8, 0xf8, + 0x0e, 0xbc, 0xf2, 0x3f, 0xa7, 0xa2, 0xe2, 0x81, 0x0e, 0xce, 0xf8, 0xfb, 0x08, + 0xe3, 0x1e, 0x13, 0xdf, 0xde, 0xef, 0xe5, 0xd0, 0x1a, 0xee, 0xf8, 0xee, 0x17, + 0xee, 0xe5, 0x3e, 0xf3, 0xde, 0x03, 0x19, 0x2b, 0x54, 0xcb, 0x22, 0x05, 0xf1, + 0x42, 0x22, 0x32, 0x40, 0x39, 0xe2, 0xe4, 0xb9, 0x30, 0xcb, 0x16, 0x2d, 0x19, + 0xf8, 0x89, 0x14, 0x0f, 0x14, 0xe8, 0xe0, 0x0e, 0xc7, 0x50, 0x1e, 0x1e, 0xaa, + 0xf0, 0x1a, 0x0b, 0xc5, 0x17, 0x91, 0xe6, 0x4d, 0xf5, 0xbf, 0xd0, 0xe7, 0xf7, + 0xe9, 0x09, 0x19, 0xef, 0xc6, 0x05, 0x2d, 0xec, 0xab, 0x16, 0x13, 0x01, 0xfd, + 0x10, 0xfd, 0x2c, 0xed, 0x48, 0x12, 0x12, 0x9e, 0x09, 0xf1, 0xfe, 0xd9, 0x1e, + 0xb2, 0xe4, 0x7f, 0x03, 0x0f, 0x2f, 0xd8, 0x3e, 0x19, 0x0e, 0xa6, 0x11, 0x00, + 0x02, 0x1d, 0xfb, 0xc3, 0xb2, 0x0b, 0xf5, 0xfa, 0x30, 0xdd, 0xe4, 0x51, 0xe3, + 0xe4, 0xe4, 0x2a, 0x14, 0xd8, 0x81, 0x60, 0x03, 0x17, 0xa9, 0xef, 0x08, 0x03, + 0xc9, 0xeb, 0xb6, 0xe2, 0xa8, 0x0d, 0x26, 0xcc, 0x0f, 0xf8, 0x77, 0xf8, 0x20, + 0x0b, 0xf9, 0x1d, 0x3b, 0xcd, 0x13, 0xc3, 0x00, 0xa9, 0x36, 0x94, 0x07, 0x24, + 0x1e, 0x1b, 0x11, 0x07, 0x0f, 0xf5, 0xba, 0xfb, 0xf7, 0x7d, 0xf0, 0x0b, 0xc2, + 0x4f, 0x10, 0x23, 0xfc, 0x1c, 0x1e, 0x05, 0xdf, 0xea, 0x10, 0xef, 0x2f, 0xf5, + 0xdd, 0xd2, 0x23, 0x00, 0x40, 0x0f, 0xd6, 0xec, 0x1e, 0x07, 0x05, 0xf9, 0xe6, + 0xd4, 0xeb, 0xfb, 0x14, 0x48, 0x00, 0x32, 0xf3, 0xe4, 0xdc, 0x12, 0xfd, 0xcc, + 0xf4, 0x43, 0x3f, 0x14, 0x1b, 0xeb, 0xd8, 0x0d, 0x02, 0xed, 0xe4, 0xfb, 0x24, + 0x33, 0x1f, 0xf1, 0xf6, 0x3a, 0xf9, 0x09, 0x7f, 0xf9, 0x2c, 0x17, 0xe2, 0x21, + 0xf8, 0xea, 0x03, 0x09, 0xc7, 0x38, 0x3b, 0xef, 0x08, 0xfa, 0x07, 0xa3, 0xd2, + 0xc9, 0xa0, 0x28, 0x57, 0xf1, 0x16, 0x06, 0xd7, 0x34, 0xe5, 0xec, 0xe7, 0x37, + 0x0d, 0xf5, 0x56, 0x2c, 0xcc, 0x2b, 0xf3, 0xf5, 0x0e, 0xc7, 0xde, 0x4d, 0x0a, + 0xe0, 0x47, 0x14, 0x17, 0x11, 0x0f, 0x15, 0xf6, 0x11, 0x0f, 0x27, 0xf9, 0x7f, + 0xe6, 0x22, 0x29, 0x4a, 0xfa, 0xe8, 0xd8, 0x0b, 0x31, 0x02, 0xd0, 0x0a, 0xfb, + 0x29, 0x17, 0x09, 0xd4, 0x3c, 0x51, 0x51, 0x0e, 0xcd, 0xff, 0x0d, 0x19, 0xf8, + 0xd4, 0x7f, 0x0d, 0xb9, 0xca, 0xff, 0xe4, 0xff, 0x28, 0xfd, 0xd2, 0xf7, 0x02, + 0x0f, 0xd9, 0xde, 0xf3, 0x2a, 0x29, 0xd5, 0x05, 0x3b, 0xf1, 0x0a, 0xd5, 0x46, + 0x20, 0xdc, 0x48, 0xd8, 0xe4, 0xf5, 0x42, 0xd2, 0x18, 0xfd, 0x51, 0x32, 0x39, + 0xde, 0xd7, 0x08, 0xe1, 0xb9, 0xe9, 0x4d, 0xeb, 0xf3, 0xde, 0xf7, 0xed, 0xc9, + 0x4b, 0x25, 0xe5, 0xf5, 0x13, 0xe3, 0x0e, 0x0f, 0xd6, 0xe7, 0x37, 0xd2, 0x26, + 0xf9, 0xed, 0xf6, 0x0c, 0x06, 0xf8, 0xed, 0x41, 0x11, 0xe6, 0x33, 0xcb, 0x01, + 0xf6, 0xea, 0x12, 0xeb, 0x08, 0xcd, 0xb1, 0x00, 0x22, 0x4d, 0x7e, 0x10, 0x4d, + 0x45, 0x26, 0xf4, 0x29, 0x43, 0xe3, 0xf1, 0x24, 0x81, 0xd0, 0xa5, 0xe4, 0xed, + 0xf2, 0x1d, 0xcc, 0xdf, 0xfe, 0xe5, 0x09, 0xd8, 0xec, 0x0d, 0x27, 0xf2, 0xd4, + 0x0c, 0xfe, 0x13, 0xd4, 0x51, 0xc4, 0xa3, 0xf5, 0x48, 0xc8, 0x32, 0xa3, 0x8f, + 0x30, 0x0b, 0x15, 0xd4, 0xc1, 0x02, 0xca, 0x02, 0x2f, 0xce, 0xbe, 0x71, 0x0e, + 0x1b, 0xb1, 0xf9, 0x13, 0x4b, 0x1a, 0x29, 0xc6, 0xe9, 0x40, 0xcb, 0xfa, 0xa8, + 0x67, 0xc8, 0xd0, 0x81, 0xf5, 0xf8, 0x29, 0xd7, 0x1c, 0xe1, 0x3b, 0x02, 0xfc, + 0x50, 0x16, 0xc8, 0x09, 0x95, 0x0f, 0x9f, 0x64, 0xf4, 0xf0, 0xdf, 0xfc, 0xf8, + 0x38, 0xa6, 0xfe, 0x1b, 0x0f, 0x67, 0x21, 0x5c, 0x19, 0xda, 0x29, 0xea, 0x05, + 0xec, 0x32, 0x04, 0xd7, 0x81, 0x00, 0xd2, 0x03, 0xe6, 0xef, 0x0a, 0xbe, 0x2d, + 0x24, 0xec, 0x55, 0xf0, 0x4a, 0x1c, 0xd4, 0x09, 0x06, 0x5d, 0x37, 0x2a, 0x31, + 0xc8, 0xf3, 0xbc, 0x1b, 0x05, 0xe8, 0x05, 0x04, 0xd1, 0xe4, 0xd2, 0x13, 0xf5, + 0x93, 0x0f, 0xc5, 0x16, 0x56, 0xfa, 0x14, 0x0d, 0xff, 0x10, 0x10, 0x39, 0xf8, + 0xdf, 0xd1, 0xbe, 0x1c, 0xcd, 0x32, 0x16, 0x28, 0xc8, 0x55, 0x0b, 0xfe, 0x25, + 0x2a, 0xef, 0xdc, 0x9a, 0xd4, 0xf7, 0x05, 0x17, 0xe0, 0xc1, 0x1c, 0x0d, 0x23, + 0x13, 0x07, 0x28, 0xf5, 0x06, 0xc8, 0xc2, 0xbd, 0xf4, 0xc7, 0xfa, 0x2b, 0x7f, + 0x14, 0x24, 0x4e, 0x09, 0x5f, 0x26, 0x08, 0x36, 0x46, 0x24, 0xd7, 0xc2, 0x1f, + 0xf8, 0x11, 0x23, 0x07, 0xbb, 0xdb, 0x11, 0xda, 0xc5, 0x45, 0xde, 0x32, 0x09, + 0x32, 0xbe, 0xc2, 0xf2, 0xd2, 0x5a, 0xb6, 0xfe, 0xe4, 0x47, 0xa0, 0xef, 0xf4, + 0x16, 0x33, 0xf2, 0x23, 0x3d, 0xea, 0xde, 0xe2, 0x52, 0x07, 0xb4, 0x18, 0x31, + 0xe5, 0xff, 0x50, 0x05, 0xe7, 0xf8, 0xf3, 0xe7, 0xd4, 0x41, 0xd0, 0x4e, 0x44, + 0x27, 0xff, 0x2a, 0xd4, 0x41, 0xf3, 0xe1, 0xc8, 0xeb, 0xd7, 0x31, 0x2e, 0x20, + 0xb9, 0xe5, 0x05, 0xf2, 0x36, 0xe3, 0x10, 0xb5, 0xda, 0xff, 0x1c, 0xb1, 0xf0, + 0x27, 0x02, 0x7f, 0xe1, 0xb9, 0x3b, 0xab, 0x25, 0x37, 0x75, 0xa6, 0x46, 0xe8, + 0xcf, 0xb7, 0xf8, 0x1c, 0x48, 0xec, 0x06, 0x2c, 0xf2, 0x9b, 0x18, 0x48, 0xcd, + 0xde, 0x0f, 0xf2, 0xe1, 0x5c, 0xfa, 0xdf, 0xf7, 0xe9, 0x29, 0xd0, 0x13, 0xe5, + 0xe2, 0xe6, 0x0e, 0xd4, 0xf4, 0xf8, 0x1f, 0xc6, 0xe3, 0x40, 0x26, 0xed, 0x33, + 0xfa, 0xce, 0x24, 0x7f, 0xe4, 0xcf, 0x0a, 0xef, 0xe7, 0x02, 0x28, 0x4f, 0xd2, + 0x00, 0x2f, 0x13, 0xfb, 0xe7, 0x22, 0x1b, 0x9f, 0x65, 0xc4, 0x0f, 0xe8, 0x04, + 0x1c, 0x2a, 0x36, 0xe9, 0x6a, 0xbc, 0x27, 0xc4, 0xb6, 0xd3, 0x85, 0xe9, 0xc3, + 0x29, 0xe3, 0x35, 0x00, 0x79, 0x0f, 0x06, 0xb8, 0x0b, 0x2b, 0x25, 0xe4, 0xc7, + 0x1c, 0x02, 0x47, 0xe1, 0x5e, 0xf9, 0x0f, 0xd3, 0x29, 0xdf, 0xcb, 0x20, 0x1d, + 0xaf, 0x2d, 0x7f, 0x1a, 0x18, 0x3f, 0xf9, 0xe8, 0x7c, 0x04, 0x08, 0xfc, 0xd0, + 0xb1, 0x49, 0xf5, 0xc5, 0x09, 0x0f, 0x6b, 0x18, 0xda, 0xef, 0x2c, 0x97, 0xc2, + 0xc6, 0xea, 0xdf, 0xb7, 0xc6, 0x44, 0x23, 0xd2, 0xf6, 0x99, 0x2f, 0x4e, 0x8e, + 0x1f, 0xde, 0x3b, 0x47, 0x33, 0xbb, 0x16, 0x65, 0xca, 0xac, 0x0d, 0xf0, 0xee, + 0xe5, 0x1b, 0xe4, 0xfb, 0x81, 0xa3, 0x05, 0x03, 0xe1, 0x11, 0x0d, 0xfb, 0xa6, + 0x10, 0xf0, 0xd1, 0x2e, 0x0d, 0x2e, 0xe5, 0x2b, 0xd6, 0xd3, 0xf9, 0xee, 0x68, + 0xe9, 0x0a, 0xc8, 0x6c, 0xe3, 0xfa, 0x00, 0x04, 0xfc, 0x0c, 0x01, 0xe1, 0xff, + 0xe5, 0xf3, 0x14, 0xfb, 0xdf, 0x2d, 0x28, 0xde, 0x12, 0xcd, 0xa8, 0xe1, 0xff, + 0x1a, 0xff, 0x4d, 0xc8, 0xf3, 0x0a, 0x05, 0x0c, 0x4e, 0xf2, 0x0b, 0xea, 0xec, + 0x0c, 0xdd, 0x4f, 0xcd, 0x5a, 0x0d, 0x1f, 0x36, 0x37, 0xea, 0xf3, 0x7f, 0x2e, + 0x46, 0xfa, 0xda, 0xd4, 0xc6, 0xf7, 0xd9, 0xf9, 0xf3, 0xd5, 0xca, 0xf4, 0x05, + 0x81, 0x25, 0xd3, 0xf1, 0x78, 0xcc, 0xc8, 0xd4, 0x04, 0x00, 0x35, 0xd0, 0xdc, + 0xbd, 0x17, 0xf0, 0x16, 0x19, 0xa5, 0xee, 0xf3, 0xdd, 0xf4, 0x0b, 0xdd, 0x0c, + 0x01, 0x03, 0xeb, 0x16, 0x27, 0xf7, 0xd6, 0x0b, 0x0e, 0x40, 0x15, 0x20, 0xf7, + 0x14, 0x60, 0x01, 0x09, 0x0d, 0xed, 0x15, 0x1c, 0xbf, 0xe3, 0x13, 0x0f, 0xef, + 0x16, 0xfb, 0x10, 0x12, 0xf4, 0xef, 0x21, 0x1d, 0xf7, 0x17, 0xc4, 0x01, 0xf2, + 0xdc, 0xcf, 0xe6, 0x2d, 0xd0, 0xda, 0x14, 0x32, 0xe9, 0xd1, 0xed, 0x1c, 0x39, + 0x81, 0x0f, 0xd8, 0xef, 0x24, 0xda, 0x18, 0x1c, 0x11, 0xfc, 0x02, 0x9f, 0xed, + 0x2b, 0xfe, 0x12, 0xfa, 0xf6, 0x3b, 0x15, 0x04, 0xf0, 0x0e, 0x1a, 0xc3, 0x09, + 0xc2, 0x0b, 0xcc, 0x4f, 0x04, 0xeb, 0x16, 0xe6, 0x0c, 0xc6, 0xe3, 0x54, 0xfc, + 0xfa, 0xf3, 0x3a, 0xe1, 0x2e, 0xcf, 0x48, 0x36, 0xf4, 0xed, 0x10, 0xd0, 0xc1, + 0xff, 0x09, 0x04, 0x38, 0xfa, 0xef, 0x0c, 0x03, 0xd2, 0xe0, 0x13, 0xf3, 0xf1, + 0xda, 0xd6, 0xec, 0xf9, 0xe7, 0x02, 0xfb, 0x43, 0x49, 0x00, 0x2f, 0x09, 0xf5, + 0xf7, 0x81, 0xcd, 0x98, 0x2f, 0xff, 0xfc, 0x08, 0xd6, 0x05, 0x81, 0xb4, 0x03, + 0xf1, 0x22, 0x26, 0x3c, 0xef, 0x0b, 0x13, 0xf5, 0xde, 0xf9, 0x76, 0xf6, 0xe6, + 0xf2, 0x3b, 0xfd, 0xe4, 0xd5, 0xd6, 0xc2, 0x15, 0x60, 0xe1, 0x02, 0xc3, 0x04, + 0x3b, 0xa8, 0xd6, 0x04, 0x2c, 0x1b, 0x03, 0xf0, 0x24, 0x98, 0xd6, 0xf9, 0x07, + 0x18, 0x29, 0x0e, 0x17, 0x0c, 0x0a, 0x05, 0xec, 0xfb, 0x0a, 0xfd, 0xfe, 0x00, + 0x26, 0x2e, 0x04, 0x11, 0xe8, 0x13, 0xf8, 0x39, 0xf5, 0xfa, 0xcf, 0xe6, 0xdf, + 0xae, 0x08, 0x36, 0xfe, 0x0d, 0xfb, 0xf1, 0x07, 0x3e, 0x18, 0xeb, 0xfa, 0x13, + 0xf5, 0x03, 0x0f, 0x0d, 0xd9, 0x06, 0x7f, 0xe8, 0x17, 0xf4, 0x14, 0x89, 0xd0, + 0xa2, 0xe1, 0xac, 0xfc, 0xff, 0x6b, 0x17, 0x99, 0xfb, 0xdb, 0xf9, 0xe8, 0xca, + 0xe3, 0x14, 0xf5, 0x3b, 0x10, 0x63, 0x57, 0xc5, 0x0f, 0xf1, 0xcd, 0x1c, 0x0e, + 0x0c, 0xd9, 0x0a, 0x04, 0xfb, 0xfb, 0x4e, 0x24, 0xed, 0x0d, 0x12, 0x3e, 0xd5, + 0x1e, 0xd6, 0x81, 0x3f, 0x08, 0xac, 0x13, 0x3c, 0xec, 0x35, 0xb7, 0xe0, 0x1d, + 0x37, 0xdc, 0x10, 0x62, 0x1c, 0xb2, 0xef, 0x41, 0x2a, 0x3c, 0x17, 0x10, 0xe8, + 0xb9, 0x3c, 0x72, 0xdd, 0xdf, 0x2c, 0xe3, 0x1a, 0x0b, 0x6f, 0xc6, 0xd6, 0xef, + 0xde, 0x3f, 0xe8, 0xe6, 0xb6, 0x19, 0xd9, 0xd4, 0xef, 0x15, 0xcc, 0x0a, 0x55, + 0xdd, 0xfa, 0x24, 0xe8, 0xce, 0x08, 0x2e, 0xf1, 0xbb, 0x4e, 0xfb, 0x1d, 0xfd, + 0xfd, 0x06, 0xe8, 0x18, 0x10, 0x7f, 0xd6, 0x31, 0xf8, 0xc6, 0xe9, 0xc7, 0xf2, + 0x47, 0xe7, 0xfd, 0xe3, 0xc1, 0xdd, 0x0f, 0x3a, 0xb7, 0xba, 0x28, 0xe7, 0x16, + 0x8b, 0xf9, 0x1f, 0x9d, 0xfa, 0x0a, 0x28, 0xe5, 0xca, 0xec, 0x3d, 0x29, 0xb6, + 0x16, 0x0a, 0xfb, 0x17, 0xbf, 0x02, 0x24, 0xce, 0xde, 0x36, 0x7f, 0x13, 0xf0, + 0x83, 0x35, 0x25, 0xe6, 0xfb, 0xf1, 0xd0, 0x05, 0x39, 0x26, 0x02, 0xc8, 0xd6, + 0x5f, 0xde, 0xb9, 0x3c, 0x13, 0xbc, 0x2a, 0x10, 0xd5, 0xad, 0xf2, 0xef, 0x0a, + 0xf6, 0x35, 0xd2, 0xad, 0xd5, 0x0a, 0xf6, 0x0c, 0xb6, 0x7f, 0xd4, 0x24, 0x5a, + 0x93, 0xa6, 0xf7, 0x11, 0x00, 0xf1, 0x35, 0x57, 0x17, 0xc7, 0x3b, 0xc9, 0xdb, + 0x1f, 0xbd, 0xc7, 0x81, 0xf9, 0xb1, 0xd2, 0x2c, 0xec, 0x5b, 0xf0, 0xed, 0x83, + 0x27, 0x26, 0x7d, 0xd5, 0x12, 0xab, 0xd5, 0x36, 0xdf, 0x60, 0x44, 0x3a, 0x47, + 0xdc, 0x25, 0x1b, 0x48, 0xc1, 0xec, 0x02, 0xdd, 0x30, 0x06, 0xfd, 0xf4, 0x1f, + 0x2c, 0xc1, 0xe9, 0xfe, 0xf8, 0x15, 0x12, 0x16, 0x44, 0x11, 0xa5, 0x39, 0xb3, + 0x23, 0x0f, 0xde, 0x1f, 0x25, 0xeb, 0x05, 0xfb, 0x15, 0xe1, 0x71, 0x3b, 0xdc, + 0xf0, 0x32, 0xc9, 0xf4, 0xe1, 0xb3, 0x02, 0x46, 0x36, 0x07, 0x40, 0x6b, 0x1b, + 0xd0, 0x36, 0x1a, 0xe3, 0xa8, 0xc9, 0x77, 0x03, 0xd0, 0xe5, 0x2a, 0x36, 0x31, + 0xc5, 0x0e, 0xe5, 0xf1, 0xc7, 0xfa, 0x7f, 0x2e, 0xe6, 0x0a, 0x16, 0x32, 0xd7, + 0x17, 0x2d, 0xd4, 0xf3, 0xee, 0xe1, 0xc3, 0x29, 0x3e, 0x04, 0xc7, 0xe8, 0xe8, + 0xf8, 0xee, 0xfa, 0xf5, 0xd0, 0xfd, 0xfa, 0xf7, 0xe1, 0x93, 0x16, 0x7f, 0xd8, + 0xcf, 0x06, 0x1a, 0x06, 0xdf, 0xfc, 0x08, 0xfe, 0x22, 0x0a, 0xdd, 0xdf, 0xfe, + 0x19, 0xf5, 0x14, 0x13, 0x5c, 0x08, 0x2c, 0xd3, 0x02, 0xe2, 0x0e, 0xec, 0x23, + 0x0a, 0x19, 0xed, 0xcc, 0x33, 0xe0, 0xff, 0x50, 0xeb, 0x3d, 0x06, 0xe1, 0x06, + 0xad, 0xd5, 0x10, 0x12, 0xec, 0xcf, 0x06, 0x12, 0x5e, 0x1c, 0xd5, 0x1d, 0x0d, + 0x07, 0x12, 0xa6, 0xb9, 0xf4, 0xf8, 0xf6, 0x3f, 0xfd, 0xdd, 0x3a, 0x1a, 0x12, + 0xbc, 0x1b, 0xe6, 0xd7, 0x0f, 0xfb, 0x1f, 0x27, 0x1f, 0xd6, 0xee, 0x27, 0xbb, + 0x42, 0xec, 0x3a, 0x0b, 0xc0, 0xfd, 0x04, 0xe0, 0xe4, 0x22, 0x27, 0xe8, 0x06, + 0x39, 0xdf, 0xfb, 0x17, 0xda, 0xfb, 0xed, 0xea, 0xf6, 0xcb, 0xce, 0x7f, 0x21, + 0xdb, 0x10, 0xf6, 0x47, 0xba, 0xbf, 0x08, 0xc6, 0xdc, 0x2c, 0xeb, 0xdd, 0x03, + 0xdb, 0x27, 0x22, 0x1a, 0xe4, 0x49, 0x23, 0xe8, 0xf5, 0xeb, 0x12, 0xfd, 0x21, + 0xf3, 0xf4, 0xe8, 0xdd, 0xdb, 0x3c, 0xf2, 0x26, 0x30, 0xfd, 0xd5, 0xcc, 0x00, + 0x2b, 0xb9, 0xf0, 0x25, 0x0f, 0xeb, 0xe6, 0xc9, 0x01, 0xf4, 0x07, 0xa1, 0x0e, + 0xfb, 0xe7, 0x11, 0xef, 0x0e, 0xdf, 0x19, 0xec, 0x26, 0x3d, 0x18, 0xd5, 0x81, + 0x28, 0xae, 0x29, 0xa8, 0xf9, 0x4d, 0x0e, 0x0f, 0x21, 0x0b, 0x12, 0xdd, 0xb1, + 0xf1, 0x0e, 0x1e, 0x0e, 0x81, 0xd7, 0xbc, 0x10, 0x0a, 0xf6, 0xe9, 0x05, 0xdd, + 0xe9, 0xe6, 0xf1, 0xfb, 0x55, 0x04, 0xd0, 0xfd, 0xd3, 0xe2, 0x21, 0xc2, 0x19, + 0x13, 0xe1, 0x56, 0xe1, 0x27, 0x0e, 0xf0, 0x09, 0xf8, 0x13, 0x23, 0x58, 0xf7, + 0x1d, 0x08, 0xde, 0x08, 0xfa, 0xfd, 0xbf, 0x1e, 0x51, 0x0a, 0x10, 0xa6, 0xfe, + 0x7f, 0x2d, 0x4c, 0x1c, 0xe6, 0xa3, 0xcf, 0xa5, 0x30, 0xe9, 0xc8, 0xf5, 0x30, + 0xfd, 0x3f, 0xad, 0xcc, 0x12, 0xdb, 0x33, 0xfd, 0xe5, 0xfc, 0x4a, 0x1f, 0x12, + 0x9b, 0xe8, 0xcc, 0xcd, 0x06, 0xd6, 0x0a, 0x42, 0x2e, 0x24, 0xe4, 0xcb, 0x58, + 0xb7, 0x15, 0x2f, 0x01, 0x29, 0xf9, 0xe0, 0x0a, 0x08, 0xeb, 0x1c, 0xa5, 0xf7, + 0xee, 0x9e, 0xd5, 0x43, 0x17, 0x78, 0xfe, 0xf1, 0xa8, 0xd8, 0xdd, 0xed, 0x47, + 0xca, 0xb2, 0xd9, 0x02, 0x7f, 0x08, 0x36, 0xd5, 0xe5, 0x45, 0x13, 0xcf, 0x12, + 0x07, 0xe1, 0x5e, 0x35, 0x48, 0xb5, 0xf8, 0x06, 0xed, 0x63, 0x36, 0x6d, 0x27, + 0xd1, 0xb8, 0x21, 0xde, 0xbd, 0xcd, 0xc9, 0x00, 0xd5, 0x12, 0xf6, 0x17, 0x2e, + 0x8f, 0x21, 0xad, 0x0f, 0xa8, 0xef, 0x20, 0x2f, 0xe2, 0x5d, 0x16, 0x31, 0x51, + 0xcb, 0x19, 0xdd, 0x0b, 0x52, 0xf9, 0xe8, 0xae, 0xdf, 0x4e, 0xd7, 0xe5, 0xd5, + 0x71, 0x68, 0x07, 0x64, 0xd0, 0xfc, 0x27, 0xbe, 0x6a, 0xce, 0x1a, 0xef, 0xe0, + 0x04, 0x15, 0xb1, 0x1e, 0x48, 0x1f, 0xfe, 0xd2, 0x3f, 0x22, 0xb0, 0xb5, 0xd8, + 0x35, 0x2d, 0x81, 0x07, 0xa6, 0xfd, 0x0d, 0x1a, 0xbb, 0xd2, 0x17, 0xec, 0xd7, + 0xf5, 0x12, 0x33, 0x50, 0x58, 0xfe, 0xc7, 0x2b, 0x41, 0xb3, 0x39, 0x27, 0x05, + 0xd3, 0x27, 0xe7, 0x30, 0xb6, 0xb6, 0xe8, 0xb3, 0xe9, 0xd9, 0x22, 0xfb, 0xdb, + 0x05, 0x9c, 0xe0, 0xfd, 0x24, 0x16, 0x1f, 0x05, 0xfe, 0x02, 0x11, 0xe7, 0x09, + 0x09, 0x13, 0x19, 0xfe, 0x7f, 0x11, 0x32, 0xf4, 0xc2, 0x3f, 0x15, 0xff, 0xfb, + 0x3e, 0x0c, 0x13, 0xff, 0x0d, 0xfe, 0xbc, 0x17, 0xe2, 0x05, 0xc2, 0xe7, 0x57, + 0x16, 0xed, 0x19, 0xdd, 0xe6, 0xfb, 0xfb, 0x06, 0x2c, 0xc3, 0x3a, 0xc1, 0xf4, + 0xc8, 0xf4, 0xbe, 0x11, 0xdd, 0x1a, 0xff, 0x02, 0xff, 0x77, 0xb5, 0x1e, 0xef, + 0xfd, 0xa1, 0x4f, 0x5e, 0x23, 0x08, 0xb4, 0xf8, 0xef, 0xbd, 0x01, 0xc9, 0xe8, + 0xe2, 0xfd, 0x4a, 0x1c, 0xfe, 0x1b, 0x06, 0x00, 0xfb, 0x07, 0x0f, 0x00, 0x2d, + 0x46, 0xd3, 0xe9, 0xda, 0xf6, 0xea, 0x30, 0xf4, 0x13, 0x15, 0xce, 0xe2, 0xd5, + 0xba, 0xfb, 0x27, 0xf6, 0xe8, 0x05, 0x7f, 0x0f, 0xd7, 0x03, 0xed, 0xe3, 0xa9, + 0xec, 0xea, 0xc8, 0xce, 0x30, 0x56, 0xc4, 0x0a, 0x35, 0xde, 0xd5, 0x04, 0xd2, + 0x23, 0xee, 0x3d, 0x27, 0xeb, 0xb2, 0x15, 0xf7, 0xf8, 0x91, 0x02, 0xfd, 0x16, + 0x14, 0xd6, 0x22, 0x14, 0xf6, 0xe0, 0xf6, 0xb4, 0x20, 0x0e, 0x0f, 0x38, 0x15, + 0x2e, 0xc3, 0x24, 0xf9, 0xba, 0x21, 0x13, 0x29, 0xe4, 0x1e, 0xf0, 0xd8, 0x23, + 0xe8, 0x23, 0x43, 0xf5, 0xe3, 0x19, 0xc9, 0x45, 0xe1, 0xe4, 0xeb, 0xfa, 0xd8, + 0xfd, 0xae, 0xfd, 0x1d, 0xf5, 0x7f, 0xed, 0x00, 0xd6, 0xd9, 0x3d, 0xc4, 0xb9, + 0x1c, 0x56, 0xe8, 0xbb, 0x40, 0xde, 0xf5, 0x50, 0xfa, 0xf5, 0x04, 0xe4, 0xfe, + 0xfb, 0xfe, 0x3b, 0x20, 0xe0, 0xca, 0x1f, 0xb5, 0xf3, 0xcf, 0xfb, 0xe2, 0x0e, + 0xba, 0xd9, 0x81, 0xbe, 0xf9, 0xcf, 0xc7, 0xb5, 0x4a, 0x19, 0xf9, 0x14, 0xf3, + 0x02, 0x17, 0xf8, 0xfd, 0x34, 0x07, 0xdd, 0xff, 0xf1, 0x0f, 0xfa, 0x01, 0x01, + 0x24, 0x25, 0xc3, 0xf5, 0xd3, 0x06, 0xd5, 0x73, 0x07, 0xb8, 0x23, 0x0b, 0x0f, + 0x1d, 0xc5, 0xef, 0x64, 0x24, 0xde, 0xcc, 0x36, 0xd2, 0x7f, 0x1c, 0x09, 0x9a, + 0xe1, 0xf8, 0xbe, 0xb7, 0xe0, 0x8e, 0x70, 0xde, 0x2c, 0xf8, 0x27, 0xc3, 0xe4, + 0x27, 0xf6, 0x7b, 0x10, 0x02, 0x01, 0x23, 0x52, 0xe8, 0xfc, 0xf5, 0x02, 0x25, + 0x0f, 0xc4, 0xba, 0xd3, 0x3d, 0x15, 0xe0, 0xd6, 0xf8, 0x93, 0x14, 0x0c, 0x4d, + 0x40, 0xf2, 0x2b, 0x19, 0xcd, 0x47, 0x08, 0x08, 0x18, 0x7f, 0x0c, 0xbb, 0x3f, + 0xfa, 0xdf, 0xbc, 0x18, 0x05, 0x3f, 0x1c, 0xc0, 0xea, 0x0d, 0x01, 0xcf, 0xd7, + 0x29, 0xf6, 0x12, 0x13, 0xec, 0x24, 0xc9, 0xc5, 0xf9, 0x15, 0x1e, 0x12, 0xe9, + 0x21, 0x2d, 0xfc, 0x02, 0xfd, 0xf7, 0x07, 0x12, 0xb1, 0xe9, 0xc6, 0x34, 0x2b, + 0x01, 0x0c, 0xb2, 0xf6, 0xfc, 0x0a, 0x11, 0xc6, 0xfc, 0xf3, 0xfd, 0xf5, 0xc6, + 0xe6, 0x39, 0x1c, 0xe3, 0x81, 0xc8, 0xd1, 0x0a, 0xb2, 0xf0, 0xd4, 0xdd, 0x01, + 0xd9, 0x0c, 0xd8, 0xb1, 0x13, 0x0c, 0xcc, 0x29, 0x41, 0x2d, 0x18, 0x09, 0x1c, + 0xfa, 0xdd, 0x15, 0x65, 0xff, 0xf5, 0x0c, 0x4d, 0xa9, 0x32, 0x54, 0x6d, 0x0f, + 0xdd, 0xf9, 0xd4, 0xe0, 0xe5, 0x06, 0xca, 0x0f, 0x38, 0xec, 0xb8, 0x4c, 0x6d, + 0xa4, 0x72, 0x27, 0x5f, 0xfb, 0x2c, 0x28, 0x4d, 0xfa, 0x0d, 0xc2, 0x16, 0xf3, + 0xf6, 0xc8, 0x1b, 0x11, 0xde, 0x18, 0xee, 0x91, 0x98, 0x1e, 0xda, 0x0f, 0x7f, + 0xf6, 0xd3, 0x0d, 0xbd, 0xd8, 0x12, 0xaf, 0x0c, 0x05, 0xf9, 0x3a, 0x30, 0x45, + 0x08, 0xd9, 0xcf, 0xee, 0x1f, 0x7e, 0xe2, 0x18, 0xbd, 0x26, 0xde, 0xf6, 0xfb, + 0x24, 0x1a, 0xdd, 0x0d, 0xe9, 0x08, 0xe5, 0xee, 0x08, 0xd7, 0xd0, 0xc6, 0x14, + 0xf6, 0x19, 0xfc, 0xf4, 0xed, 0x12, 0xfc, 0x0b, 0x02, 0x12, 0xce, 0x1a, 0xca, + 0xd4, 0xe4, 0xcc, 0xdc, 0xb7, 0xfa, 0xa1, 0xb0, 0xca, 0x22, 0x26, 0x3e, 0xe8, + 0xd7, 0x14, 0xe9, 0xeb, 0x16, 0xb0, 0xf9, 0x1e, 0x34, 0xf8, 0xe1, 0x0c, 0x08, + 0xd5, 0x01, 0xf6, 0x47, 0xda, 0x1d, 0x9b, 0xf4, 0x37, 0xe0, 0xf8, 0xbd, 0x0f, + 0x30, 0x44, 0x18, 0x3f, 0x13, 0xfd, 0x0e, 0x1e, 0x09, 0x2e, 0x1b, 0x5d, 0x2b, + 0x04, 0x95, 0xc9, 0x43, 0xfd, 0x34, 0xfa, 0xf8, 0xfe, 0x7f, 0xfa, 0xef, 0xaa, + 0x19, 0xeb, 0xe6, 0xc4, 0xfd, 0xdf, 0xde, 0x2f, 0x43, 0xce, 0x3f, 0xfc, 0xf0, + 0xe0, 0xe2, 0xcd, 0x27, 0xfd, 0xfb, 0x40, 0xe5, 0x04, 0xf0, 0xee, 0xe0, 0x17, + 0x89, 0x0c, 0x2f, 0x19, 0x17, 0xc8, 0x26, 0x0b, 0xfa, 0xfd, 0x7f, 0x06, 0x0b, + 0xe4, 0x47, 0x4c, 0x00, 0x8e, 0xf9, 0xe9, 0x0a, 0x39, 0x1a, 0xe5, 0xea, 0x20, + 0xf2, 0x23, 0x4c, 0x01, 0x0c, 0x09, 0x27, 0xe2, 0xfc, 0x08, 0x15, 0x19, 0x16, + 0x1e, 0xe5, 0xf0, 0xd0, 0xa7, 0xf5, 0xdd, 0x3e, 0x04, 0xf5, 0x3d, 0x24, 0x15, + 0x1b, 0xbf, 0xf4, 0x32, 0x02, 0xed, 0xf3, 0xd5, 0x32, 0xfc, 0x59, 0x81, 0xaa, + 0x3e, 0xf6, 0x21, 0x23, 0xf3, 0x24, 0xcf, 0x33, 0x97, 0xe9, 0x0e, 0xf5, 0xd4, + 0x03, 0xca, 0x49, 0xf9, 0x46, 0xc3, 0xcb, 0xed, 0xef, 0x19, 0xc2, 0x00, 0xff, + 0x01, 0xb3, 0x10, 0x20, 0x17, 0x03, 0xf6, 0xd0, 0xcc, 0x12, 0xf7, 0x26, 0x2f, + 0xd4, 0x66, 0xea, 0x01, 0xba, 0xd7, 0x5f, 0x0d, 0xff, 0x31, 0xe9, 0x20, 0xf6, + 0x7f, 0xe5, 0x15, 0x26, 0xf2, 0xef, 0x05, 0x0f, 0xf8, 0xd9, 0xf7, 0x5e, 0x34, + 0xcb, 0xae, 0x92, 0x5d, 0xe1, 0x0c, 0x16, 0x3b, 0xa1, 0x0f, 0x04, 0xce, 0xb8, + 0x28, 0xd8, 0x54, 0xe1, 0x49, 0x01, 0xed, 0x09, 0xe0, 0x1e, 0xf7, 0xe2, 0x0b, + 0xf3, 0xf3, 0xe1, 0x27, 0xb9, 0x39, 0x17, 0x3e, 0xf1, 0x02, 0x1d, 0x0e, 0x67, + 0x19, 0xbc, 0x17, 0xb3, 0x0d, 0xb4, 0xe0, 0x36, 0xc9, 0x1f, 0x11, 0xe3, 0x2f, + 0xd3, 0xdb, 0xf4, 0x26, 0x0b, 0x13, 0xf1, 0x01, 0xd5, 0x04, 0xd0, 0xdf, 0x26, + 0xc4, 0xb2, 0x2b, 0x33, 0x38, 0xde, 0x41, 0xc2, 0xb6, 0xf4, 0x7f, 0x4f, 0xf0, + 0x00, 0x04, 0xfc, 0x00, 0xbd, 0xed, 0xfc, 0xdb, 0x3b, 0xf9, 0x16, 0xf3, 0xff, + 0x02, 0xfb, 0xf0, 0x1d, 0x2f, 0x10, 0xdf, 0x5f, 0xd9, 0x01, 0xfb, 0xe5, 0x29, + 0x38, 0xde, 0x05, 0xd9, 0xc1, 0xf8, 0xe9, 0x1e, 0xa7, 0x13, 0x01, 0xb8, 0xeb, + 0xb5, 0x2b, 0x29, 0xa7, 0xad, 0xf2, 0xdd, 0xe5, 0x0c, 0x1b, 0xee, 0x58, 0xae, + 0x05, 0x62, 0xd9, 0x12, 0xf2, 0x0f, 0x03, 0x27, 0x00, 0x39, 0xac, 0xb8, 0xef, + 0xcd, 0x02, 0x5f, 0x11, 0x1f, 0xfe, 0xa6, 0x02, 0x13, 0xde, 0x35, 0x18, 0x04, + 0xd0, 0xeb, 0x14, 0xdf, 0x81, 0xed, 0xfb, 0x8c, 0x14, 0xfa, 0xe9, 0x1f, 0x01, + 0x12, 0xe7, 0xc2, 0xd2, 0xea, 0xf0, 0xde, 0xf1, 0xfd, 0x01, 0x14, 0xd7, 0x0d, + 0x08, 0x16, 0x1e, 0xab, 0x3a, 0x0e, 0xe0, 0xf6, 0xf5, 0x1c, 0x50, 0x7f, 0xea, + 0x20, 0x0c, 0xdd, 0xc9, 0xfc, 0xe3, 0x0d, 0xee, 0x15, 0xc7, 0xde, 0x0a, 0x0c, + 0xf9, 0x20, 0xe8, 0xff, 0xda, 0xf9, 0xf0, 0x6a, 0xf2, 0xf7, 0x1d, 0xf6, 0xee, + 0xf0, 0x23, 0xe5, 0x0c, 0xde, 0xd6, 0x4c, 0xe8, 0x0e, 0x91, 0xdf, 0xc9, 0x7f, + 0x3c, 0xa9, 0x3b, 0xcb, 0x38, 0xe2, 0x38, 0x5a, 0xea, 0x16, 0xec, 0x2a, 0x5a, + 0xe1, 0x04, 0x00, 0x13, 0xf8, 0xce, 0x15, 0x38, 0x1a, 0xc8, 0x10, 0x4c, 0x2d, + 0x0c, 0xfa, 0xdb, 0x59, 0x2a, 0xee, 0x0c, 0x9d, 0x47, 0x13, 0x22, 0xa1, 0x5c, + 0xdf, 0xff, 0x97, 0xcb, 0x3d, 0xcc, 0x85, 0xd0, 0x76, 0xf2, 0x9f, 0xe7, 0x04, + 0xd4, 0x32, 0x14, 0x1c, 0x0a, 0x14, 0xe9, 0x2b, 0x9d, 0x66, 0xc4, 0xd5, 0xf0, + 0xda, 0x40, 0x4d, 0x0a, 0xb1, 0x51, 0xf9, 0x29, 0x19, 0x03, 0xb1, 0x1b, 0x4f, + 0xcd, 0x0c, 0xe1, 0x1d, 0x3c, 0x0b, 0x96, 0x43, 0xf6, 0xe4, 0xe3, 0x57, 0xa0, + 0xf8, 0xdd, 0x2d, 0x00, 0xa9, 0x35, 0xdb, 0x5a, 0x56, 0xe2, 0xfb, 0x0a, 0xd6, + 0x23, 0x3b, 0xc5, 0x06, 0xf9, 0xe8, 0x03, 0x01, 0x21, 0xee, 0xe7, 0x0b, 0x7f, + 0xf5, 0x2f, 0x11, 0xf7, 0x7d, 0x0c, 0x53, 0xb4, 0xd4, 0xcd, 0xe6, 0x11, 0x2a, + 0x0d, 0xdc, 0xc6, 0x7f, 0x2a, 0x1a, 0xd6, 0xe8, 0xba, 0xe5, 0x03, 0x14, 0xfc, + 0x00, 0x17, 0x0e, 0x16, 0xed, 0x47, 0x6e, 0xbd, 0xd4, 0xfd, 0x10, 0xfe, 0xcb, + 0xd6, 0x09, 0xeb, 0xe8, 0xea, 0xd9, 0xdb, 0x25, 0x20, 0xcf, 0x15, 0x2e, 0x32, + 0xbf, 0x03, 0xe2, 0xf2, 0xe9, 0xdb, 0x2c, 0xd3, 0xe1, 0xe1, 0xf4, 0xd9, 0xee, + 0x12, 0x18, 0xdf, 0xd8, 0xd8, 0x38, 0xf0, 0x13, 0x59, 0xc6, 0x1a, 0xc6, 0x0f, + 0x0a, 0xe6, 0x04, 0x0b, 0xc4, 0x89, 0xb0, 0xcb, 0x45, 0x1a, 0xf6, 0xfa, 0xd7, + 0x12, 0x19, 0x27, 0xad, 0x33, 0xb0, 0x25, 0x41, 0x33, 0xfc, 0x09, 0x0f, 0x3b, + 0xc1, 0xf2, 0x58, 0xd3, 0xfa, 0xcc, 0xf8, 0x7f, 0x0b, 0xd1, 0xe6, 0x94, 0x12, + 0x1d, 0x78, 0xfe, 0xb6, 0x3c, 0x45, 0xe5, 0x5a, 0x22, 0x2d, 0x05, 0x32, 0xd8, + 0xdc, 0xc5, 0x18, 0x65, 0x0f, 0xc7, 0xdb, 0xf3, 0xa0, 0xdd, 0xf9, 0x31, 0xfe, + 0xe9, 0x08, 0xd0, 0x25, 0xdc, 0x07, 0x1d, 0x1d, 0x00, 0x24, 0x26, 0x7f, 0xf6, + 0x10, 0xdf, 0x3c, 0xf9, 0x0f, 0x13, 0x2e, 0xe4, 0x12, 0xf3, 0xfe, 0x19, 0x00, + 0xf1, 0x43, 0xea, 0x02, 0xd8, 0x1a, 0x08, 0x0f, 0xdd, 0x1c, 0xe1, 0x14, 0xe0, + 0xe2, 0x0f, 0x06, 0xea, 0x05, 0xd7, 0xce, 0xbd, 0xe8, 0x3b, 0xea, 0x22, 0xcc, + 0xf0, 0x18, 0x1a, 0xfd, 0xed, 0xfd, 0xee, 0x81, 0xbe, 0xf7, 0x13, 0xfa, 0xfb, + 0xf5, 0xe8, 0x02, 0xf8, 0x1c, 0x0f, 0x01, 0xf2, 0x13, 0x18, 0x42, 0x08, 0x13, + 0x22, 0x3a, 0xc7, 0xef, 0x07, 0x20, 0xdb, 0xea, 0x0a, 0x19, 0xf9, 0x09, 0x01, + 0x13, 0xfd, 0xe9, 0xdb, 0xf2, 0xfc, 0x0a, 0xf6, 0x04, 0xfd, 0xdf, 0x19, 0xca, + 0xee, 0x1c, 0x05, 0xf2, 0xbb, 0xe8, 0xc1, 0xef, 0x18, 0x16, 0xfe, 0xef, 0x01, + 0xe1, 0xff, 0x19, 0xe4, 0x3e, 0x34, 0xe6, 0x1a, 0xe9, 0x29, 0xe5, 0xdf, 0x1c, + 0x2c, 0xf5, 0x0b, 0x13, 0x20, 0x0a, 0x2c, 0xd9, 0xc7, 0xbb, 0x0b, 0xd6, 0x03, + 0x01, 0xc5, 0xea, 0x57, 0xcd, 0xe7, 0x6b, 0x27, 0xf6, 0x3c, 0x29, 0xf4, 0x30, + 0xf1, 0xd8, 0xc1, 0x02, 0xf7, 0x35, 0xde, 0x7f, 0xec, 0x1f, 0xd0, 0xf5, 0x15, + 0xca, 0x05, 0xdb, 0xd0, 0xf7, 0x16, 0xf1, 0x0a, 0x06, 0x25, 0x07, 0x08, 0xff, + 0x35, 0xce, 0xd1, 0x2c, 0xf5, 0x0c, 0x13, 0xf1, 0x97, 0xe2, 0x13, 0xd9, 0x1b, + 0xf0, 0xf8, 0x18, 0xe6, 0xac, 0x24, 0xf0, 0xa1, 0x37, 0x0c, 0x09, 0x02, 0x31, + 0x40, 0xf5, 0xf9, 0xfa, 0x0e, 0xcd, 0x13, 0xc8, 0x09, 0xeb, 0xd9, 0xe5, 0xe0, + 0x34, 0xf9, 0x81, 0xed, 0xd9, 0xf3, 0xf4, 0x1c, 0x47, 0xf6, 0x08, 0xda, 0xff, + 0x00, 0x19, 0xb9, 0xf7, 0x30, 0xe8, 0xc6, 0xd8, 0xda, 0x01, 0xf5, 0x2b, 0xb1, + 0x57, 0x09, 0xce, 0x09, 0x3f, 0xdb, 0xad, 0xf5, 0xf6, 0xf9, 0x02, 0xdd, 0x21, + 0x3a, 0x81, 0xdf, 0x0d, 0x06, 0x2f, 0xd4, 0x34, 0xdd, 0xf5, 0x45, 0x02, 0xd6, + 0xf5, 0xd8, 0xfa, 0xe1, 0x10, 0xcd, 0x10, 0x2b, 0x09, 0x02, 0xff, 0x07, 0x00, + 0xd7, 0x0d, 0x22, 0xe9, 0x1c, 0xfb, 0x1a, 0xf3, 0x0b, 0xed, 0xa2, 0x1d, 0xd9, + 0xea, 0xfb, 0x33, 0x1d, 0xe3, 0x12, 0x66, 0x98, 0xee, 0x1e, 0x97, 0x10, 0xfb, + 0xc2, 0xef, 0x21, 0x03, 0x57, 0xbc, 0x06, 0x1d, 0x15, 0xee, 0xec, 0xf1, 0xe0, + 0xef, 0xe7, 0x08, 0x10, 0xf8, 0xe7, 0x2c, 0xfa, 0xff, 0x03, 0x37, 0x43, 0x14, + 0x22, 0x09, 0x01, 0xe9, 0x18, 0xd9, 0xf4, 0x0a, 0x1e, 0x13, 0xdf, 0x08, 0x2e, + 0xfa, 0x1e, 0x12, 0x1d, 0xe4, 0xc5, 0x2a, 0x5d, 0xed, 0xff, 0x22, 0xe7, 0x3b, + 0x0b, 0x3b, 0xf8, 0x12, 0x21, 0xf5, 0x0f, 0x31, 0xf0, 0x81, 0xfd, 0xbf, 0x0a, + 0x07, 0x3e, 0x03, 0x25, 0x35, 0xdf, 0xe4, 0xd8, 0xf0, 0xda, 0xa5, 0xc2, 0xc5, + 0xe8, 0xe5, 0x15, 0x2b, 0x0c, 0xf1, 0x0a, 0x22, 0xe6, 0xe2, 0xe5, 0x31, 0xef, + 0x17, 0x40, 0xfa, 0x3b, 0xf6, 0x3e, 0xc1, 0xd1, 0xdf, 0x00, 0x6e, 0x04, 0x7f, + 0xde, 0x13, 0xf7, 0x0e, 0x11, 0x37, 0xed, 0xa8, 0x23, 0x3e, 0x13, 0xe2, 0xec, + 0xfb, 0xf1, 0xef, 0xee, 0x0e, 0x0a, 0xfd, 0x02, 0xfd, 0x1b, 0x8d, 0x81, 0xf8, + 0x42, 0xf8, 0x30, 0x0a, 0xc8, 0xe0, 0x35, 0xe3, 0x20, 0x91, 0xc1, 0x03, 0x16, + 0x12, 0xec, 0xf5, 0xdd, 0x10, 0x04, 0xf4, 0x03, 0xf6, 0x2e, 0x29, 0xfc, 0x0f, + 0x15, 0x3d, 0x27, 0xe5, 0xd1, 0xd8, 0xdc, 0x70, 0xde, 0x12, 0x2e, 0x23, 0x05, + 0x09, 0xe2, 0xb8, 0x1b, 0x62, 0x18, 0x4f, 0x14, 0xfb, 0xd4, 0x12, 0x0c, 0x03, + 0xf3, 0xce, 0x43, 0xef, 0xed, 0x50, 0x3d, 0xb5, 0x1b, 0x09, 0x05, 0x00, 0x81, + 0xfd, 0x13, 0x42, 0xdc, 0xc5, 0x34, 0x1f, 0xf5, 0xe5, 0xc0, 0x47, 0x3f, 0xb7, + 0x29, 0x25, 0xb3, 0xed, 0x1c, 0x34, 0xc2, 0xdf, 0x97, 0xfd, 0xcd, 0xea, 0x2c, + 0x22, 0x1d, 0xc2, 0xd7, 0x95, 0x88, 0x26, 0xe0, 0xe3, 0x31, 0x32, 0x17, 0xe1, + 0x72, 0xcc, 0xfc, 0x93, 0xa9, 0xbf, 0xca, 0xc3, 0xcb, 0xf6, 0x29, 0x85, 0xfe, + 0x36, 0x15, 0x24, 0xac, 0x10, 0x28, 0xdf, 0x01, 0x10, 0x05, 0x0b, 0x0c, 0x74, + 0x2b, 0x09, 0x5d, 0xe9, 0xc6, 0xb5, 0xe7, 0x0f, 0xd5, 0xd9, 0x06, 0x01, 0xfd, + 0xc5, 0x1f, 0xc1, 0x03, 0xc4, 0x0b, 0xb4, 0x59, 0x3a, 0xe2, 0x09, 0xdf, 0xb6, + 0xe7, 0x81, 0xff, 0xdb, 0xcb, 0x4c, 0xdf, 0x0b, 0x28, 0x18, 0xfb, 0xf8, 0x13, + 0xdc, 0x02, 0xfe, 0xee, 0xde, 0xfe, 0xea, 0x19, 0x36, 0xe8, 0xe8, 0x02, 0x0d, + 0xa4, 0xa9, 0x27, 0x0f, 0x01, 0xe3, 0xd9, 0x1f, 0x26, 0xee, 0x17, 0xaa, 0xf9, + 0xff, 0x47, 0xf7, 0x23, 0xde, 0xbe, 0xfb, 0x11, 0xeb, 0xc8, 0x15, 0xce, 0xd5, + 0x0d, 0xe6, 0xe8, 0x15, 0x1b, 0xe7, 0x29, 0x59, 0xbb, 0xc0, 0xef, 0x3c, 0xfb, + 0x28, 0x15, 0x03, 0x27, 0x05, 0x7f, 0xf6, 0xb5, 0xcb, 0x05, 0xae, 0xe4, 0xb7, + 0x0f, 0x0b, 0x5f, 0x4c, 0xcd, 0xd6, 0x36, 0x27, 0x00, 0xc5, 0xfe, 0x13, 0xeb, + 0x07, 0x36, 0x4a, 0xb0, 0xdf, 0xfb, 0xef, 0xff, 0x03, 0x38, 0xb3, 0xaf, 0x0b, + 0x20, 0x0f, 0x01, 0x02, 0xea, 0xe9, 0x2d, 0xc7, 0x17, 0xd7, 0xe3, 0xfe, 0xe8, + 0xc2, 0x06, 0xfc, 0x3f, 0xf9, 0xc2, 0xf4, 0x1a, 0x12, 0x17, 0xf3, 0xe2, 0x32, + 0x07, 0xf5, 0x2d, 0xe3, 0xe5, 0xdc, 0x0a, 0x81, 0x03, 0xf7, 0x17, 0x09, 0xb9, + 0x08, 0x39, 0x6d, 0x2d, 0xe9, 0xef, 0x22, 0xec, 0x2f, 0x52, 0x28, 0xf8, 0xb8, + 0xfe, 0xe2, 0xfc, 0xf7, 0x07, 0x05, 0xff, 0x08, 0x41, 0x30, 0x0f, 0xc8, 0x2e, + 0x05, 0xcf, 0xdb, 0xf2, 0x06, 0xaf, 0xd4, 0xb2, 0x56, 0x30, 0xcd, 0xf5, 0x75, + 0xc5, 0xbc, 0x2a, 0x3f, 0xf9, 0xf9, 0xf4, 0x00, 0x6e, 0x16, 0xec, 0xea, 0x12, + 0xfd, 0x02, 0xf9, 0x93, 0x16, 0xd3, 0xf1, 0xbc, 0x9b, 0xe8, 0xdb, 0x29, 0xea, + 0x2b, 0x13, 0x07, 0xdb, 0x4f, 0xd4, 0x83, 0x0e, 0xdf, 0xfd, 0x7f, 0xd8, 0x1d, + 0xab, 0x08, 0xee, 0xc8, 0xe3, 0x28, 0xc3, 0x25, 0x0a, 0x48, 0x81, 0xf1, 0x02, + 0xcd, 0xea, 0xba, 0xd3, 0xde, 0x02, 0xe2, 0x0d, 0xe8, 0x3e, 0x03, 0x1a, 0xec, + 0x37, 0xcd, 0x03, 0x0f, 0xe8, 0xc5, 0x16, 0x34, 0xc8, 0xf8, 0xf9, 0x1b, 0x92, + 0x1b, 0xfa, 0xca, 0xe6, 0xda, 0x52, 0x08, 0x23, 0x3d, 0x03, 0x30, 0x2b, 0xfd, + 0xe8, 0x5c, 0xe5, 0x22, 0x0d, 0x18, 0xdb, 0x0e, 0x15, 0xb8, 0x1b, 0xe0, 0xd5, + 0xf1, 0xda, 0x15, 0xf4, 0xd2, 0x25, 0xe1, 0xde, 0xbd, 0xcd, 0xd1, 0x0f, 0x1a, + 0x5d, 0x40, 0xd7, 0xf2, 0xe8, 0x45, 0x2a, 0xe8, 0x21, 0x97, 0xe5, 0x22, 0x32, + 0xcd, 0x16, 0xce, 0xb9, 0x2d, 0x12, 0x23, 0x2c, 0x30, 0xc7, 0x4b, 0x33, 0x10, + 0xc1, 0xe5, 0x02, 0xeb, 0xdf, 0xf3, 0xff, 0xf1, 0x2c, 0xff, 0xe6, 0x09, 0x3e, + 0xc6, 0x2c, 0x06, 0xf7, 0x12, 0xdb, 0xe1, 0x04, 0xe0, 0xda, 0xc2, 0xd6, 0xfc, + 0x7f, 0x30, 0xf1, 0x34, 0x05, 0xec, 0x25, 0xdc, 0x2c, 0xf3, 0x2a, 0xf1, 0xf4, + 0xe6, 0xf5, 0x1f, 0xeb, 0x07, 0xd3, 0xf5, 0x11, 0x19, 0x17, 0xef, 0xc3, 0x7f, + 0xf8, 0xd6, 0xf5, 0xf0, 0xd0, 0xe4, 0x19, 0xb8, 0xe6, 0xbb, 0x1b, 0x34, 0xff, + 0xf5, 0xc6, 0xf8, 0x35, 0x46, 0x89, 0x52, 0xe6, 0xf5, 0x08, 0x05, 0x0a, 0x41, + 0x3a, 0xe2, 0xd8, 0xb5, 0xdc, 0xf2, 0xf6, 0x44, 0xc8, 0xca, 0x4e, 0x13, 0xa8, + 0x2f, 0x14, 0x26, 0xef, 0xf1, 0x14, 0x3a, 0xc4, 0x19, 0xef, 0x03, 0x01, 0x2f, + 0x03, 0x13, 0xcf, 0xd1, 0xbb, 0x22, 0xe2, 0xfc, 0x56, 0xee, 0x3d, 0xe9, 0x03, + 0x37, 0x4c, 0xb5, 0xc8, 0x22, 0x22, 0x00, 0xe0, 0xf7, 0x07, 0xcd, 0xcf, 0x14, + 0x01, 0x13, 0xcf, 0x15, 0x1e, 0xd4, 0xf8, 0xdd, 0xfc, 0x27, 0x32, 0x2a, 0xf0, + 0xcb, 0x2b, 0xcc, 0xdd, 0x13, 0x29, 0x09, 0x7f, 0x0f, 0x5d, 0xd7, 0xd5, 0x38, + 0xe0, 0x08, 0xfb, 0x24, 0x88, 0x81, 0xfd, 0xdf, 0x01, 0x00, 0x2e, 0xd8, 0xde, + 0xe9, 0xfa, 0x38, 0xd4, 0x9a, 0x4a, 0x32, 0xfc, 0xf7, 0xe1, 0x10, 0xab, 0xdd, + 0xdb, 0xd8, 0x5f, 0x33, 0xd9, 0x03, 0x1f, 0x1f, 0x25, 0x35, 0xd7, 0xcd, 0xea, + 0x39, 0xf1, 0xd5, 0xc3, 0x2a, 0xa6, 0xf7, 0x38, 0x06, 0xda, 0x19, 0xfc, 0xda, + 0x1b, 0xe1, 0x0b, 0x9b, 0x0b, 0x16, 0x26, 0xa1, 0xb2, 0x0f, 0x02, 0x04, 0x08, + 0x0d, 0x2a, 0x1d, 0xbc, 0x7f, 0xea, 0x14, 0x01, 0x19, 0x0b, 0x2e, 0xd5, 0xf7, + 0xe5, 0x1d, 0xc8, 0x3b, 0x25, 0xfa, 0x5d, 0x17, 0xf2, 0x2e, 0xfe, 0x12, 0xeb, + 0xca, 0xdb, 0xe2, 0x03, 0x2e, 0xcd, 0xfd, 0xfb, 0x11, 0x1a, 0xf2, 0x5b, 0xff, + 0x06, 0xfe, 0xd1, 0x36, 0xe4, 0xf6, 0x14, 0xe8, 0x22, 0x2c, 0x47, 0x21, 0x1f, + 0xd4, 0x26, 0xda, 0x09, 0xf4, 0x58, 0xf3, 0xd5, 0xf4, 0xdb, 0x2a, 0x36, 0x3b, + 0xe5, 0x0a, 0xdf, 0xd5, 0xe8, 0xed, 0x2e, 0x06, 0xc6, 0xd8, 0xf2, 0xfb, 0xfa, + 0xf0, 0xbb, 0x03, 0xf2, 0x02, 0xf7, 0xe3, 0xaa, 0x9f, 0x01, 0x17, 0xf4, 0xb7, + 0xbb, 0x55, 0xe1, 0xba, 0xc4, 0xf7, 0x07, 0xb7, 0x09, 0x08, 0xc7, 0xf6, 0x56, + 0xde, 0x7f, 0x09, 0xd3, 0x5f, 0x48, 0x1d, 0x59, 0x4b, 0xc4, 0x11, 0x03, 0xe7, + 0xb1, 0xab, 0xed, 0xed, 0x48, 0xe1, 0x05, 0xb6, 0x9f, 0xde, 0x1a, 0xac, 0xc9, + 0xeb, 0x04, 0xb4, 0xbd, 0xeb, 0x03, 0xe5, 0xc0, 0x20, 0x1c, 0xe9, 0x46, 0xf6, + 0x37, 0x60, 0xb2, 0x09, 0xc9, 0x2d, 0x1d, 0x79, 0x1a, 0xe4, 0x5d, 0xae, 0x30, + 0x41, 0x26, 0xe9, 0x09, 0xd5, 0x34, 0xe7, 0x15, 0xf3, 0x81, 0xbf, 0x26, 0xb5, + 0x93, 0x5b, 0xdb, 0x1d, 0x0c, 0xd9, 0xf8, 0xac, 0xeb, 0xa9, 0x45, 0x91, 0xa3, + 0x63, 0x01, 0x36, 0xb0, 0xc9, 0x33, 0x15, 0x4e, 0xfd, 0x21, 0xd0, 0x9e, 0xca, + 0xea, 0x44, 0xd9, 0x0b, 0x41, 0xe8, 0x1d, 0xe9, 0xdc, 0x28, 0x1b, 0xe2, 0xc5, + 0x10, 0x33, 0xc9, 0x08, 0x1b, 0x1f, 0x81, 0xed, 0xd8, 0x69, 0xd6, 0x08, 0xbd, + 0x3b, 0x07, 0x98, 0xf8, 0xd6, 0x63, 0x00, 0x1f, 0x0a, 0xbd, 0xf1, 0xf7, 0x00, + 0x21, 0x36, 0x10, 0xc1, 0x21, 0x22, 0x10, 0x5c, 0xd0, 0xf8, 0xbf, 0xd9, 0xf2, + 0x07, 0xe3, 0xf6, 0xca, 0xd6, 0x04, 0x05, 0xe3, 0xdd, 0x4e, 0xf8, 0xb4, 0xef, + 0x9d, 0xfc, 0x31, 0xd1, 0xdc, 0xe7, 0xd0, 0xc9, 0x7f, 0xea, 0xde, 0x21, 0x28, + 0x32, 0x10, 0xff, 0xe8, 0xc1, 0x1c, 0x1a, 0x0f, 0x51, 0xae, 0xcf, 0x0d, 0xbe, + 0x0a, 0xf2, 0x28, 0x02, 0xfe, 0xfb, 0xca, 0xb8, 0xdb, 0x9c, 0x0a, 0xcc, 0xdc, + 0x9a, 0xfb, 0x8d, 0x8c, 0xef, 0x0b, 0x1f, 0x48, 0xc8, 0x27, 0x10, 0xaf, 0x26, + 0x1a, 0x31, 0x88, 0xae, 0x1f, 0x1a, 0x07, 0x09, 0xbb, 0xc0, 0xd5, 0x7f, 0x02, + 0xdd, 0xac, 0x6b, 0x10, 0xfc, 0x2a, 0x2a, 0xf2, 0x21, 0xe2, 0xc7, 0x9c, 0x1d, + 0x15, 0xfd, 0xf1, 0x37, 0xa4, 0x41, 0xe6, 0x1e, 0xf5, 0x42, 0x03, 0xf9, 0x14, + 0xee, 0xb9, 0x44, 0x7c, 0xfa, 0x16, 0xf8, 0x78, 0xff, 0x10, 0xa1, 0xd1, 0x40, + 0x11, 0xc6, 0xd2, 0x08, 0x10, 0xe3, 0xef, 0x16, 0x26, 0xe1, 0x1e, 0x1c, 0x46, + 0x31, 0x0b, 0x3a, 0x10, 0x93, 0x0a, 0xe6, 0x33, 0x26, 0x10, 0xef, 0x07, 0xf5, + 0xf1, 0x03, 0x12, 0xc1, 0xcc, 0x25, 0x0a, 0x1f, 0xe8, 0x1b, 0xce, 0x17, 0x28, + 0x0f, 0x0a, 0x33, 0xd0, 0x06, 0x2f, 0xf2, 0x01, 0xf2, 0xe8, 0xdd, 0xd8, 0xff, + 0x02, 0xfe, 0xd2, 0x09, 0xf3, 0x81, 0xe5, 0xf8, 0xf8, 0x1e, 0x35, 0xd4, 0xf5, + 0xf0, 0x42, 0xed, 0xc3, 0x04, 0x00, 0x17, 0xef, 0x2d, 0x1d, 0xdf, 0xc6, 0xfe, + 0xf4, 0xf7, 0x46, 0x08, 0xe2, 0xee, 0xf1, 0xd2, 0x04, 0xf7, 0x24, 0xd5, 0xdf, + 0xf6, 0xd8, 0xeb, 0xd6, 0x08, 0xec, 0x0e, 0xc8, 0x1e, 0xe8, 0x09, 0x05, 0xb3, + 0xf9, 0xfe, 0xe8, 0xe8, 0xe5, 0xe5, 0x39, 0x7f, 0xa4, 0x34, 0x45, 0xc3, 0xcc, + 0xfc, 0xec, 0xe5, 0xf0, 0xf7, 0xf2, 0x05, 0x00, 0x29, 0x0a, 0x09, 0x01, 0x38, + 0x02, 0xdd, 0xdc, 0x32, 0xe1, 0xd3, 0xe7, 0xf5, 0xbc, 0xf3, 0xf9, 0xe5, 0x2e, + 0xeb, 0xeb, 0xee, 0xe9, 0x34, 0xd5, 0x01, 0xda, 0xe3, 0xc3, 0xae, 0x38, 0xbf, + 0xde, 0xeb, 0x0a, 0x6c, 0x23, 0x72, 0x01, 0xfd, 0xc5, 0x41, 0x35, 0x18, 0x01, + 0x7f, 0x15, 0xe5, 0xbb, 0x3d, 0xd6, 0xe9, 0xd2, 0x26, 0xc1, 0xef, 0xf9, 0x37, + 0xbc, 0xb8, 0x31, 0x4d, 0x0e, 0x42, 0xef, 0x46, 0x0d, 0x3f, 0x23, 0xfd, 0xc0, + 0xd6, 0xeb, 0x24, 0xf3, 0x45, 0x63, 0x15, 0xdc, 0xe5, 0x1a, 0xe4, 0x17, 0xfe, + 0x15, 0x0f, 0x03, 0xf1, 0xee, 0xfd, 0xec, 0x1b, 0x3a, 0xbc, 0xb4, 0xfd, 0x23, + 0x25, 0x01, 0xe5, 0x81, 0x10, 0xf0, 0xe9, 0x32, 0xf4, 0x15, 0x0e, 0xd9, 0x23, + 0xbb, 0xfd, 0x3d, 0x06, 0x0e, 0x12, 0xa4, 0x0f, 0xcb, 0xfd, 0x0c, 0x0a, 0x0c, + 0xee, 0x06, 0xa3, 0x00, 0x08, 0x20, 0x2e, 0x4f, 0xee, 0x0f, 0x41, 0x38, 0xe6, + 0xcc, 0x16, 0x42, 0xc0, 0xcc, 0x20, 0x1c, 0x0b, 0x00, 0x1b, 0xde, 0x47, 0xd8, + 0x08, 0xe3, 0x37, 0xfb, 0xfd, 0xdb, 0xc9, 0x08, 0xe9, 0x06, 0xc4, 0x10, 0xf2, + 0xe9, 0xe0, 0xcd, 0xda, 0x04, 0x01, 0x1e, 0x11, 0xd1, 0xb9, 0xff, 0x1c, 0xde, + 0x14, 0xdd, 0xe7, 0x4e, 0x01, 0xeb, 0xb2, 0x61, 0x2c, 0x4b, 0x02, 0xd9, 0x09, + 0xde, 0xc8, 0x06, 0x22, 0x0e, 0x03, 0xe2, 0xf7, 0x18, 0xf0, 0xfe, 0xd2, 0xf7, + 0xe2, 0x2c, 0x1b, 0x2e, 0xf9, 0xf1, 0xdc, 0x18, 0x02, 0x81, 0xe9, 0x06, 0xc5, + 0x22, 0x52, 0x89, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x78, 0xd8, 0xff, 0xff, 0x28, 0x26, 0x00, 0x00, 0xc4, 0x0d, 0x00, 0x00, 0xd4, + 0x0e, 0x00, 0x00, 0xf0, 0x1a, 0x00, 0x00, 0x24, 0x27, 0x00, 0x00, 0x00, 0xd6, + 0xff, 0xff, 0x08, 0x24, 0x00, 0x00, 0xbd, 0xd6, 0xff, 0xff, 0x0c, 0xf2, 0xff, + 0xff, 0xbd, 0x01, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x00, 0xce, 0xe2, 0xff, 0xff, + 0x78, 0x5d, 0x00, 0x00, 0x93, 0x50, 0x00, 0x00, 0xb4, 0xd4, 0xff, 0xff, 0x18, + 0xfb, 0xff, 0xff, 0x2c, 0x06, 0x00, 0x00, 0xa4, 0x4b, 0x00, 0x00, 0x3e, 0x59, + 0x00, 0x00, 0x9f, 0x3f, 0x00, 0x00, 0x71, 0x21, 0x00, 0x00, 0xc5, 0x3e, 0x00, + 0x00, 0xc6, 0xc0, 0xff, 0xff, 0x21, 0x18, 0x00, 0x00, 0xd1, 0x7a, 0x00, 0x00, + 0xe1, 0xe7, 0xff, 0xff, 0x83, 0x29, 0x00, 0x00, 0xb5, 0x26, 0x00, 0x00, 0xf0, + 0x33, 0x00, 0x00, 0x96, 0x5a, 0x00, 0x00, 0x15, 0x1d, 0x00, 0x00, 0x21, 0xf2, + 0xff, 0xff, 0xd9, 0x3e, 0x00, 0x00, 0xec, 0x04, 0x00, 0x00, 0x8c, 0xe4, 0xff, + 0xff, 0xa8, 0xf6, 0xff, 0xff, 0x16, 0x43, 0x00, 0x00, 0xdf, 0xd2, 0xff, 0xff, + 0xf7, 0x06, 0x00, 0x00, 0x3a, 0x2d, 0x00, 0x00, 0x3f, 0x34, 0x00, 0x00, 0x1d, + 0x27, 0x00, 0x00, 0x16, 0x4e, 0x00, 0x00, 0x28, 0x11, 0x00, 0x00, 0x8c, 0x03, + 0x00, 0x00, 0x1f, 0x43, 0x00, 0x00, 0x1c, 0xd5, 0xff, 0xff, 0x3a, 0x11, 0x00, + 0x00, 0x4b, 0x3e, 0x00, 0x00, 0x43, 0x1d, 0x00, 0x00, 0xcf, 0x27, 0x00, 0x00, + 0x60, 0xc6, 0xff, 0xff, 0xc1, 0xcd, 0xff, 0xff, 0x97, 0x18, 0x00, 0x00, 0x57, + 0x22, 0x00, 0x00, 0x05, 0x24, 0x00, 0x00, 0x85, 0x15, 0x00, 0x00, 0x16, 0x10, + 0x00, 0x00, 0x50, 0xd2, 0xff, 0xff, 0x04, 0xff, 0xff, 0xff, 0x9f, 0xf9, 0xff, + 0xff, 0x9a, 0x58, 0x00, 0x00, 0x1c, 0xed, 0xff, 0xff, 0x8d, 0x21, 0x00, 0x00, + 0xd1, 0x34, 0x00, 0x00, 0x54, 0x5c, 0x00, 0x00, 0x29, 0xf5, 0xff, 0xff, 0x91, + 0x2b, 0x00, 0x00, 0x27, 0x0d, 0x00, 0x00, 0x72, 0x15, 0x00, 0x00, 0xc2, 0x15, + 0x00, 0x00, 0xcf, 0xce, 0xff, 0xff, 0x34, 0x20, 0x00, 0x00, 0xb3, 0x07, 0x00, + 0x00, 0x02, 0x6c, 0x00, 0x00, 0x86, 0x41, 0x00, 0x00, 0xf2, 0x2e, 0x00, 0x00, + 0x32, 0xc9, 0xff, 0xff, 0x1d, 0xf4, 0xff, 0xff, 0x1d, 0xfc, 0xff, 0xff, 0xf9, + 0x1c, 0x00, 0x00, 0x40, 0xfa, 0xff, 0xff, 0x1d, 0x59, 0x00, 0x00, 0x26, 0x0e, + 0x00, 0x00, 0x5b, 0x0e, 0x00, 0x00, 0x68, 0x08, 0x00, 0x00, 0xed, 0x54, 0x00, + 0x00, 0x83, 0x07, 0x00, 0x00, 0xf2, 0x1f, 0x00, 0x00, 0x1b, 0x32, 0x00, 0x00, + 0xd0, 0xf1, 0xff, 0xff, 0x33, 0x0f, 0x00, 0x00, 0x37, 0x54, 0x00, 0x00, 0x66, + 0x15, 0x00, 0x00, 0x0d, 0xea, 0xff, 0xff, 0x82, 0xdc, 0xff, 0xff, 0xd7, 0x34, + 0x00, 0x00, 0x98, 0xf7, 0xff, 0xff, 0x6c, 0x13, 0x00, 0x00, 0xfd, 0x46, 0x00, + 0x00, 0x82, 0xe1, 0xff, 0xff, 0xca, 0x54, 0x00, 0x00, 0xaf, 0x29, 0x00, 0x00, + 0x22, 0xf5, 0xff, 0xff, 0x89, 0x13, 0x00, 0x00, 0x9c, 0xf1, 0xff, 0xff, 0xcd, + 0x8d, 0x00, 0x00, 0x2a, 0x41, 0x00, 0x00, 0x86, 0x0d, 0x00, 0x00, 0x44, 0x2a, + 0x00, 0x00, 0x7d, 0x3f, 0x00, 0x00, 0x6c, 0x25, 0x00, 0x00, 0x7f, 0x0e, 0x00, + 0x00, 0xbd, 0x2b, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x00, 0xf2, 0x4b, 0x00, 0x00, + 0x11, 0xee, 0xff, 0xff, 0x0c, 0x3c, 0x00, 0x00, 0x42, 0x45, 0x00, 0x00, 0x10, + 0x45, 0x00, 0x00, 0xa7, 0x7f, 0x00, 0x00, 0x3b, 0xf5, 0xff, 0xff, 0x19, 0x2e, + 0x00, 0x00, 0xbd, 0x41, 0x00, 0x00, 0xd7, 0xd8, 0xff, 0xff, 0xbd, 0x30, 0x00, + 0x00, 0x77, 0x55, 0x00, 0x00, 0x5e, 0x8b, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x80, 0x04, 0x00, 0x00, 0xa6, 0xde, 0xf3, 0xa5, 0xde, 0xdb, 0xc4, 0xf3, 0x2a, + 0xd5, 0xdf, 0x81, 0x02, 0xe1, 0xd8, 0x0c, 0xc8, 0x19, 0xca, 0x11, 0xc6, 0xd7, + 0x37, 0x7f, 0x23, 0xd5, 0x0a, 0x10, 0x81, 0x15, 0xab, 0x9c, 0xef, 0x9b, 0x94, + 0xe8, 0xb2, 0x3f, 0x51, 0xe5, 0x0c, 0x23, 0xed, 0x32, 0xb7, 0x81, 0x85, 0x17, + 0x03, 0x0c, 0xb9, 0xba, 0x81, 0xfb, 0x0d, 0xeb, 0x10, 0x7f, 0x35, 0xee, 0x00, + 0xbb, 0x08, 0xe8, 0xe6, 0xe3, 0xe4, 0xd9, 0x32, 0x7f, 0x36, 0xe2, 0x28, 0x48, + 0xdc, 0xe6, 0x8c, 0xc4, 0x49, 0xae, 0xc9, 0xf4, 0xf2, 0xe8, 0xee, 0x7f, 0xf3, + 0xa1, 0xa6, 0xec, 0x07, 0x56, 0x7f, 0xf8, 0x39, 0xb6, 0xdf, 0x05, 0x64, 0xdd, + 0x63, 0x18, 0xea, 0xba, 0xea, 0x73, 0x32, 0x99, 0x41, 0x02, 0x09, 0xee, 0xe2, + 0x05, 0xeb, 0xde, 0xed, 0xfe, 0x04, 0xcd, 0xf8, 0x99, 0x5a, 0xe1, 0xcb, 0x32, + 0x33, 0xae, 0x3b, 0x41, 0x03, 0x3a, 0x84, 0x42, 0x81, 0xb6, 0x57, 0x0e, 0xa6, + 0x4a, 0x0d, 0xcd, 0x34, 0x8e, 0x7f, 0x7f, 0x57, 0xe8, 0x16, 0xcb, 0x7f, 0x35, + 0xd5, 0xb4, 0x27, 0x5d, 0xad, 0x8f, 0xe4, 0xb9, 0x35, 0xcd, 0xc9, 0xfb, 0x9f, + 0x7f, 0x7f, 0xb4, 0x69, 0xd2, 0x62, 0x7f, 0xb1, 0xd6, 0xd4, 0xd0, 0x7f, 0x29, + 0xed, 0xd9, 0x70, 0x03, 0xad, 0xc7, 0x17, 0x5a, 0x2e, 0xe1, 0x01, 0x24, 0xb8, + 0x17, 0xd1, 0xf4, 0xe5, 0x61, 0x59, 0xed, 0xf0, 0x11, 0x7f, 0xe5, 0x1d, 0xb7, + 0xf9, 0x91, 0x43, 0xf8, 0xe9, 0xac, 0xf4, 0x9c, 0xab, 0x65, 0x23, 0x53, 0xd4, + 0xfb, 0x4c, 0xdc, 0x65, 0xa5, 0x49, 0xd6, 0x22, 0x7f, 0x7f, 0xd0, 0xbb, 0xd4, + 0x0f, 0x81, 0x81, 0x7f, 0xe2, 0x81, 0x26, 0xcc, 0x7f, 0x10, 0xc4, 0xf9, 0x8c, + 0xff, 0xd2, 0xd8, 0x7f, 0xcf, 0xd3, 0x81, 0x7f, 0x81, 0xcb, 0x7f, 0x7f, 0x81, + 0x0a, 0x18, 0xe2, 0x17, 0x81, 0x14, 0xb5, 0x44, 0xe3, 0xc4, 0xdd, 0x4b, 0xf0, + 0xe7, 0xd3, 0x83, 0x39, 0x20, 0x20, 0xf1, 0x04, 0xf3, 0x11, 0x2d, 0xe8, 0x81, + 0xd5, 0xf4, 0xa0, 0x04, 0xb1, 0x0a, 0x10, 0xc4, 0x9d, 0xfe, 0xbc, 0x24, 0x65, + 0xe8, 0x8a, 0x15, 0xc9, 0xa4, 0xbc, 0x81, 0x81, 0xe7, 0xcc, 0xe1, 0xda, 0xc3, + 0x56, 0x0c, 0x9b, 0xd8, 0xfa, 0xc3, 0x03, 0xe7, 0x07, 0x28, 0xff, 0xf1, 0xfd, + 0xc1, 0xf0, 0x3a, 0xae, 0x7c, 0xff, 0xe0, 0x0f, 0xd8, 0x08, 0xdc, 0x6e, 0xd4, + 0x26, 0xe0, 0x7f, 0xf7, 0x00, 0x2e, 0xdf, 0x00, 0xf8, 0x48, 0xa4, 0xf8, 0xea, + 0xbd, 0x2b, 0xd6, 0x11, 0xe0, 0xe1, 0x1a, 0x03, 0x0d, 0xba, 0x23, 0xe7, 0xc3, + 0xe9, 0x5a, 0xd0, 0xa2, 0x2b, 0xff, 0xe8, 0xee, 0xdb, 0x01, 0xe1, 0xc1, 0xe9, + 0x13, 0xfd, 0x53, 0x67, 0xb2, 0xe2, 0xe3, 0x38, 0x5b, 0x04, 0xb9, 0xbb, 0x17, + 0x17, 0x81, 0xce, 0x32, 0xe6, 0x48, 0x19, 0x3b, 0x35, 0xb7, 0x0b, 0x00, 0xa9, + 0xb2, 0xe5, 0xcb, 0xec, 0x7f, 0xe1, 0xd6, 0xd3, 0x37, 0xe1, 0xc0, 0xa5, 0xbd, + 0xc6, 0x0b, 0xbd, 0xaa, 0x6a, 0x7f, 0x35, 0xe2, 0xaf, 0xf1, 0xea, 0xb1, 0xf9, + 0x7f, 0x7f, 0x4d, 0xbc, 0xa7, 0x29, 0x7f, 0xd4, 0xff, 0x20, 0x32, 0x8b, 0x78, + 0xa7, 0xc6, 0x17, 0xe8, 0xa8, 0xcf, 0xbf, 0xbb, 0x7f, 0x7f, 0xc3, 0xaa, 0x35, + 0xf2, 0x54, 0xda, 0x7f, 0xfb, 0x15, 0xdc, 0xaf, 0xff, 0x91, 0xb2, 0x08, 0xf1, + 0xf1, 0x1f, 0xe3, 0xa2, 0xbc, 0xdc, 0x01, 0xec, 0x07, 0xf1, 0x33, 0x7a, 0x28, + 0xeb, 0x7f, 0x32, 0x0b, 0xe4, 0xe3, 0x7f, 0x98, 0xc8, 0xda, 0x90, 0xce, 0xde, + 0x3d, 0x92, 0x85, 0xf8, 0xe6, 0x0d, 0xcd, 0xcb, 0xb7, 0xeb, 0xb8, 0x7f, 0x24, + 0xe8, 0xfb, 0x92, 0x11, 0x96, 0x47, 0xca, 0xe0, 0xac, 0x7f, 0x7f, 0x4e, 0x11, + 0xdc, 0x7f, 0xa4, 0x81, 0x7f, 0x7f, 0xf2, 0x3f, 0x7f, 0x7f, 0x81, 0x01, 0xdd, + 0xe3, 0x7f, 0xd5, 0x7f, 0xca, 0xed, 0x4c, 0x07, 0xaa, 0x06, 0x7f, 0xd2, 0x7f, + 0x81, 0x81, 0x7f, 0x30, 0x7f, 0xaf, 0xca, 0xc9, 0xfd, 0x81, 0x7f, 0x2c, 0x1d, + 0x7e, 0x81, 0x95, 0x48, 0xe3, 0x1f, 0x58, 0x7f, 0x7f, 0x24, 0x7f, 0x81, 0x81, + 0x7f, 0xdd, 0xf1, 0x93, 0xef, 0x8e, 0xb0, 0xfb, 0x81, 0x81, 0x7f, 0x7f, 0x7f, + 0xe9, 0x1d, 0x7f, 0x36, 0x81, 0x7f, 0x7f, 0xa6, 0x81, 0x7f, 0x81, 0xa2, 0x7f, + 0x22, 0x81, 0x81, 0xa3, 0x7f, 0x7f, 0x6e, 0x7f, 0x7f, 0xe4, 0x04, 0x81, 0xfb, + 0xff, 0x7f, 0x02, 0x72, 0xdb, 0x16, 0xc2, 0xed, 0xdf, 0x9d, 0xb4, 0x34, 0xaa, + 0x81, 0x7f, 0xea, 0x7f, 0x81, 0xcc, 0x81, 0x7f, 0x81, 0xfd, 0x5c, 0xd2, 0x7f, + 0x15, 0x55, 0xbc, 0x04, 0xf4, 0xe7, 0xb3, 0x67, 0x1e, 0x1e, 0x6f, 0x4c, 0x39, + 0xe6, 0x56, 0x39, 0x1c, 0x51, 0xf4, 0x09, 0xe8, 0xa8, 0x53, 0x29, 0xc6, 0xfa, + 0x13, 0xe3, 0xf6, 0xbd, 0xf6, 0x75, 0xa9, 0x81, 0xc9, 0xbf, 0xf3, 0xc1, 0x17, + 0xd3, 0x1c, 0x2a, 0x03, 0xd2, 0x1c, 0xc8, 0xd2, 0x0f, 0x6c, 0xa7, 0xea, 0x33, + 0xab, 0x3a, 0xe6, 0xe3, 0xe4, 0xf9, 0x26, 0x65, 0x19, 0xb2, 0xd0, 0x23, 0xfe, + 0x1c, 0x11, 0xe2, 0xee, 0xf4, 0xcb, 0xb0, 0xd2, 0x0f, 0x23, 0xc3, 0xfd, 0x63, + 0x0e, 0x04, 0xb7, 0x35, 0xfe, 0x7f, 0x84, 0x4d, 0x05, 0x64, 0xe2, 0xf0, 0x26, + 0xa9, 0xbc, 0x2f, 0xf6, 0xe8, 0xef, 0x1c, 0xcd, 0xc6, 0xc0, 0xab, 0x8f, 0x16, + 0xec, 0xe6, 0xe3, 0x7f, 0x40, 0xe9, 0x9d, 0xb6, 0xdb, 0xaa, 0xad, 0x83, 0xf8, + 0x08, 0xf3, 0xd9, 0x7f, 0xd4, 0xc4, 0x19, 0x8c, 0x0f, 0x7f, 0xb9, 0x92, 0x10, + 0x97, 0x7f, 0xce, 0xd6, 0x9d, 0x06, 0x0c, 0xfb, 0xd9, 0xf2, 0x1b, 0xe2, 0xf0, + 0xcc, 0x34, 0x7f, 0xd6, 0xe1, 0x03, 0xf2, 0xb1, 0xf0, 0xdf, 0x09, 0x21, 0xf7, + 0x4e, 0xff, 0x24, 0xfa, 0xe1, 0xcb, 0xf5, 0xcc, 0xdc, 0xc4, 0xf7, 0xf5, 0x4b, + 0xfb, 0x3f, 0xef, 0xab, 0xe4, 0xf8, 0x08, 0xea, 0x64, 0xfc, 0x2d, 0x17, 0x0c, + 0x19, 0xdd, 0xa7, 0x35, 0x08, 0xa6, 0x09, 0xfa, 0xfc, 0x02, 0xef, 0xb2, 0x72, + 0x31, 0xc9, 0xff, 0x1c, 0xde, 0xa8, 0x05, 0xfe, 0xb5, 0xc9, 0x0a, 0xdd, 0xfd, + 0x17, 0x2d, 0xfd, 0xe4, 0xe0, 0xe9, 0x06, 0xf2, 0xf8, 0x10, 0xc2, 0xed, 0xde, + 0xc7, 0x0d, 0x4c, 0xf1, 0xf3, 0x7f, 0xd2, 0x08, 0x23, 0x1e, 0xdc, 0xf6, 0xfb, + 0x5c, 0x95, 0x2a, 0x16, 0xe4, 0xc9, 0xdb, 0x7f, 0xed, 0x55, 0xff, 0x06, 0xdb, + 0xe3, 0xe6, 0xda, 0xe9, 0xb2, 0x3d, 0xc9, 0xef, 0x43, 0x9d, 0xf5, 0xdc, 0x12, + 0x06, 0xd8, 0xc7, 0x5f, 0xf4, 0x7f, 0x29, 0x43, 0x4e, 0xd3, 0x12, 0x4a, 0x5a, + 0x06, 0xe9, 0x31, 0xf3, 0x90, 0x7f, 0xac, 0xf8, 0xd1, 0xce, 0xf4, 0x7f, 0xe1, + 0x34, 0x7f, 0xdf, 0xa9, 0xfc, 0x01, 0x39, 0xc5, 0xff, 0x52, 0x06, 0x57, 0x7f, + 0x81, 0xb5, 0x92, 0xae, 0xed, 0x0a, 0x03, 0xeb, 0xb7, 0xbb, 0x63, 0x0f, 0x52, + 0x7f, 0x46, 0x46, 0xe1, 0xd7, 0x5f, 0xb4, 0x10, 0xee, 0x81, 0x52, 0x7f, 0x81, + 0xeb, 0xc3, 0xa3, 0xc2, 0xfd, 0xfc, 0x9d, 0x00, 0x5a, 0x0f, 0x20, 0xae, 0xae, + 0xfa, 0xdb, 0x2e, 0xd2, 0xa4, 0x0c, 0x1d, 0x7f, 0xb3, 0xd5, 0xc3, 0x0c, 0xef, + 0x7f, 0xf2, 0xf4, 0xd1, 0xbb, 0xab, 0x23, 0x7f, 0x43, 0x0d, 0xf8, 0xec, 0x40, + 0x7f, 0x7f, 0xdf, 0xf0, 0xf3, 0x1b, 0xd9, 0xe3, 0x59, 0xbc, 0xe5, 0xc4, 0xed, + 0x0b, 0x08, 0xc4, 0x02, 0xf3, 0xe3, 0x3f, 0xbd, 0xc8, 0xf1, 0xbf, 0xc5, 0xdb, + 0xdf, 0x4d, 0xd9, 0x05, 0xf1, 0x29, 0x3e, 0xe3, 0xf7, 0xfe, 0x19, 0x15, 0x0c, + 0xe2, 0x02, 0x00, 0x63, 0xda, 0xd6, 0xf9, 0xe7, 0x01, 0x2a, 0x0d, 0xe7, 0x77, + 0xee, 0xae, 0xeb, 0xcb, 0xf3, 0xe0, 0xfc, 0x2d, 0xfb, 0xfe, 0x04, 0x1a, 0xc5, + 0xbd, 0xf0, 0x46, 0xfa, 0x93, 0x02, 0x1d, 0xfd, 0xfe, 0xf4, 0xd2, 0x0c, 0x23, + 0x01, 0x0b, 0xc9, 0x20, 0xf0, 0xfe, 0xff, 0x99, 0x7f, 0xfb, 0xeb, 0xea, 0xef, + 0xfe, 0xb6, 0xf9, 0x11, 0xca, 0xa1, 0xd9, 0xe6, 0xf2, 0xc4, 0xd9, 0xf8, 0x12, + 0xa3, 0xfc, 0x1c, 0x03, 0xdf, 0x1e, 0xc5, 0xe3, 0xce, 0xd6, 0xf8, 0x23, 0xe9, + 0x02, 0x91, 0xd2, 0xee, 0xee, 0x3c, 0x0b, 0xec, 0xde, 0xd5, 0x4d, 0x13, 0x25, + 0xf7, 0xa1, 0xd1, 0xca, 0xfb, 0xd1, 0xf6, 0x07, 0xea, 0xd6, 0x28, 0xf0, 0xd6, + 0x0b, 0xca, 0xc3, 0xfd, 0xb4, 0xb1, 0xf7, 0xc8, 0xda, 0x05, 0xf6, 0xd0, 0xea, + 0x8f, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xab, 0xe6, + 0xff, 0xff, 0x26, 0x01, 0x00, 0x00, 0xae, 0x02, 0x00, 0x00, 0x85, 0xe8, 0xff, + 0xff, 0xb4, 0xeb, 0xff, 0xff, 0xd0, 0xf5, 0xff, 0xff, 0x1e, 0x0f, 0x00, 0x00, + 0x6b, 0xeb, 0xff, 0xff, 0x4b, 0xe6, 0xff, 0xff, 0xe5, 0xe6, 0xff, 0xff, 0x2e, + 0xf1, 0xff, 0xff, 0x46, 0x01, 0x00, 0x00, 0xa6, 0x15, 0x00, 0x00, 0x32, 0xfe, + 0xff, 0xff, 0x8a, 0x09, 0x00, 0x00, 0xf4, 0xeb, 0xff, 0xff, 0xa7, 0xf8, 0xff, + 0xff, 0xeb, 0xfa, 0xff, 0xff, 0xd0, 0x1f, 0x00, 0x00, 0x0c, 0x24, 0x00, 0x00, + 0x9b, 0xfc, 0xff, 0xff, 0x0c, 0xff, 0xff, 0xff, 0x77, 0xe0, 0xff, 0xff, 0x9a, + 0xef, 0xff, 0xff, 0x19, 0x08, 0x00, 0x00, 0x67, 0x22, 0x00, 0x00, 0xe0, 0x17, + 0x00, 0x00, 0xb6, 0xe9, 0xff, 0xff, 0xbc, 0xef, 0xff, 0xff, 0x33, 0xff, 0xff, + 0xff, 0x8b, 0xf9, 0xff, 0xff, 0x52, 0xdb, 0xff, 0xff, 0x91, 0x0c, 0x00, 0x00, + 0x14, 0xff, 0xff, 0xff, 0x1e, 0xf4, 0xff, 0xff, 0xbf, 0xfd, 0xff, 0xff, 0xf3, + 0xe5, 0xff, 0xff, 0x29, 0xf1, 0xff, 0xff, 0x15, 0x14, 0x00, 0x00, 0x10, 0x23, + 0x00, 0x00, 0xd7, 0x17, 0x00, 0x00, 0xfc, 0x29, 0x00, 0x00, 0x12, 0x15, 0x00, + 0x00, 0x92, 0xf9, 0xff, 0xff, 0xbb, 0x13, 0x00, 0x00, 0x45, 0xe5, 0xff, 0xff, + 0x26, 0xf6, 0xff, 0xff, 0x32, 0xf9, 0xff, 0xff, 0x46, 0x0c, 0x00, 0x00, 0x0e, + 0x2a, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x78, 0xf5, 0xff, 0xff, 0xaa, 0xf0, + 0xff, 0xff, 0x22, 0xec, 0xff, 0xff, 0xbe, 0x21, 0x00, 0x00, 0x5d, 0xf9, 0xff, + 0xff, 0xea, 0xe7, 0xff, 0xff, 0xb7, 0x2f, 0x00, 0x00, 0xce, 0xf8, 0xff, 0xff, + 0x90, 0x2e, 0x00, 0x00, 0xe5, 0x26, 0x00, 0x00, 0xe1, 0xf2, 0xff, 0xff, 0x33, + 0xf9, 0xff, 0xff, 0x9f, 0x14, 0x00, 0x00, 0x99, 0x1e, 0x00, 0x00, 0x9d, 0xf9, + 0xff, 0xff, 0xef, 0xdb, 0xff, 0xff, 0x45, 0xf0, 0xff, 0xff, 0x08, 0xf4, 0xff, + 0xff, 0x3f, 0xf2, 0xff, 0xff, 0x12, 0xf1, 0xff, 0xff, 0x69, 0xf0, 0xff, 0xff, + 0xd7, 0xeb, 0xff, 0xff, 0xac, 0xcf, 0xff, 0xff, 0xca, 0xe7, 0xff, 0xff, 0x89, + 0xf2, 0xff, 0xff, 0xe6, 0x26, 0x00, 0x00, 0x6d, 0xf1, 0xff, 0xff, 0xee, 0xd4, + 0xff, 0xff, 0xca, 0xfa, 0xff, 0xff, 0x42, 0xec, 0xff, 0xff, 0x20, 0x22, 0x00, + 0x00, 0x71, 0x03, 0x00, 0x00, 0xcd, 0xeb, 0xff, 0xff, 0x15, 0x2a, 0x00, 0x00, + 0xe0, 0xec, 0xff, 0xff, 0x3f, 0xf9, 0xff, 0xff, 0x2c, 0xff, 0xff, 0xff, 0x06, + 0xfa, 0xff, 0xff, 0x72, 0xfe, 0xff, 0xff, 0xf7, 0xfd, 0xff, 0xff, 0xe9, 0xfd, + 0xff, 0xff, 0xcb, 0xf1, 0xff, 0xff, 0xe7, 0xe4, 0xff, 0xff, 0xef, 0xfd, 0xff, + 0xff, 0x80, 0xf6, 0xff, 0xff, 0x1e, 0x06, 0x00, 0x00, 0xdb, 0xfa, 0xff, 0xff, + 0x1c, 0xe5, 0xff, 0xff, 0x24, 0xf5, 0xff, 0xff, 0xfb, 0x1a, 0x00, 0x00, 0xb4, + 0x1c, 0x00, 0x00, 0x18, 0x3a, 0x00, 0x00, 0x02, 0xef, 0xff, 0xff, 0x71, 0x22, + 0x00, 0x00, 0xe1, 0xf2, 0xff, 0xff, 0x7f, 0xef, 0xff, 0xff, 0xd6, 0x02, 0x00, + 0x00, 0x16, 0xf8, 0xff, 0xff, 0x87, 0xf5, 0xff, 0xff, 0x33, 0xff, 0xff, 0xff, + 0x62, 0xfb, 0xff, 0xff, 0x1d, 0x22, 0x00, 0x00, 0x5d, 0xf4, 0xff, 0xff, 0x09, + 0x0b, 0x00, 0x00, 0xd5, 0xd6, 0xff, 0xff, 0x5a, 0xf3, 0xff, 0xff, 0x6c, 0xfe, + 0xff, 0xff, 0x7c, 0xff, 0xff, 0xff, 0x6b, 0x25, 0x00, 0x00, 0x0a, 0xda, 0xff, + 0xff, 0x7d, 0xf8, 0xff, 0xff, 0xac, 0xf3, 0xff, 0xff, 0x71, 0xf9, 0xff, 0xff, + 0x39, 0xf3, 0xff, 0xff, 0x2d, 0xd4, 0xff, 0xff, 0x33, 0xfc, 0xff, 0xff, 0xff, + 0xf2, 0xff, 0xff, 0xf6, 0x91, 0xfd, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0xba, 0xcf, 0x85, 0xce, 0x0c, 0x9f, 0xff, 0xeb, 0x0c, 0xa5, 0xda, + 0xeb, 0x12, 0xda, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x9f, 0xe6, 0x09, 0xef, 0xed, + 0x02, 0xf9, 0x4f, 0xe9, 0x44, 0xae, 0x5c, 0x4d, 0xf2, 0xe7, 0xd9, 0x31, 0xf8, + 0xd0, 0xd3, 0x2d, 0x03, 0xdc, 0x00, 0x36, 0x0e, 0xff, 0xfb, 0x1a, 0x5d, 0x7c, + 0xbe, 0xf5, 0xd1, 0x1e, 0x32, 0x50, 0x2b, 0x1c, 0x02, 0xdf, 0x49, 0x3c, 0x21, + 0x1a, 0xf7, 0xfc, 0x48, 0x03, 0xda, 0xfd, 0x01, 0xf7, 0x58, 0x19, 0x22, 0x2e, + 0x0f, 0xd8, 0xb0, 0x3f, 0x25, 0x06, 0x81, 0xf7, 0xcf, 0x22, 0x28, 0x34, 0xc8, + 0xf4, 0xe5, 0xff, 0xc1, 0x32, 0xfa, 0x0c, 0x62, 0x20, 0x0a, 0xf5, 0x4c, 0xcc, + 0xcc, 0xd5, 0xe9, 0x05, 0x45, 0x41, 0x17, 0x3c, 0xe1, 0xfe, 0x1a, 0x25, 0x2c, + 0x03, 0xfa, 0x21, 0xdb, 0xdc, 0x02, 0xec, 0xf9, 0x14, 0x09, 0x0d, 0x23, 0xbe, + 0xe5, 0x00, 0x23, 0x2b, 0x02, 0x0c, 0xf6, 0x1c, 0xc5, 0xec, 0x36, 0x5e, 0x1e, + 0x09, 0x00, 0xff, 0xb3, 0x43, 0xa2, 0x04, 0x3b, 0xf5, 0xd3, 0xd4, 0x39, 0x0a, + 0xdd, 0x00, 0xf1, 0xfe, 0x0d, 0xd2, 0xf5, 0xf1, 0x24, 0xcd, 0xe7, 0x62, 0x03, + 0x07, 0xec, 0x04, 0xcf, 0x16, 0xf0, 0xbd, 0x37, 0xf4, 0xf5, 0xdf, 0x81, 0x15, + 0xf7, 0xf8, 0xbe, 0xda, 0xd2, 0xdd, 0xd6, 0xd5, 0xe2, 0xfa, 0xf6, 0x10, 0x21, + 0xe0, 0x30, 0xd1, 0x18, 0xfd, 0x0b, 0xd7, 0xde, 0xd9, 0xde, 0xc3, 0x2e, 0xf8, + 0xdd, 0xcd, 0x13, 0x12, 0x0b, 0x0f, 0xed, 0x0e, 0xe6, 0xe4, 0xd3, 0x32, 0x02, + 0x29, 0x1e, 0xd8, 0xe6, 0xca, 0xf4, 0x07, 0x2b, 0x1e, 0x11, 0x0a, 0xf9, 0xce, + 0x4c, 0xd1, 0x1c, 0x24, 0xea, 0x11, 0xf1, 0x0f, 0xc4, 0x12, 0xf8, 0x49, 0x06, + 0x41, 0x01, 0x1c, 0xec, 0xe5, 0xe5, 0x1d, 0xfd, 0x2c, 0xde, 0xdb, 0x2f, 0x10, + 0x78, 0x68, 0x04, 0x45, 0xd0, 0xf3, 0xfb, 0x1e, 0x2e, 0xf5, 0xad, 0xd1, 0xf3, + 0xf8, 0x05, 0x0b, 0x19, 0xee, 0xf7, 0xec, 0x14, 0xee, 0xf0, 0x17, 0x2f, 0x16, + 0xa7, 0xe1, 0xb8, 0x11, 0x32, 0xf5, 0x26, 0x1d, 0x26, 0x18, 0xd9, 0x03, 0xfc, + 0x05, 0x45, 0x24, 0xe0, 0xff, 0x0d, 0xfe, 0xf6, 0x19, 0xe5, 0x07, 0x05, 0x10, + 0x0f, 0x2b, 0x29, 0x2b, 0x0c, 0x12, 0xdf, 0x56, 0x00, 0x38, 0x14, 0xe4, 0x0f, + 0xdc, 0x16, 0x58, 0x09, 0x14, 0x01, 0xf9, 0x0f, 0xd2, 0x25, 0x02, 0x13, 0xfc, + 0xe7, 0x1d, 0x27, 0xf8, 0x0c, 0xee, 0xae, 0xe0, 0x07, 0x10, 0xc3, 0x16, 0x04, + 0xd0, 0x11, 0x13, 0xcf, 0x7f, 0xe4, 0x0b, 0xda, 0x05, 0x0f, 0xe6, 0xdc, 0xba, + 0xe4, 0x0f, 0xf3, 0x16, 0xdc, 0x0f, 0xb2, 0x3c, 0xee, 0xf2, 0x21, 0x1c, 0xf1, + 0x1a, 0x39, 0xd6, 0xfc, 0xfe, 0x11, 0xf2, 0x2c, 0x36, 0xfc, 0x9c, 0xfd, 0x3a, + 0x01, 0x90, 0x36, 0xef, 0xf4, 0xc5, 0xfd, 0xfd, 0xa5, 0x35, 0x0f, 0x36, 0x0f, + 0xba, 0xd1, 0x17, 0xe0, 0x4d, 0xb6, 0xbd, 0x1a, 0x15, 0xf5, 0x20, 0xd0, 0x23, + 0x1f, 0xff, 0xe5, 0xfd, 0xae, 0x7f, 0x12, 0xa0, 0xef, 0xf6, 0xed, 0xf2, 0x20, + 0xe4, 0x25, 0xab, 0x23, 0xee, 0x15, 0xe2, 0xbf, 0x03, 0xf2, 0xbd, 0x1a, 0xfe, + 0xed, 0xd3, 0x24, 0x26, 0x22, 0xd6, 0x11, 0xfc, 0x19, 0x10, 0x11, 0xfb, 0xff, + 0xdf, 0xe6, 0x2e, 0xee, 0xf4, 0x1b, 0xf2, 0xf2, 0xf5, 0x4d, 0xbf, 0xfc, 0xf2, + 0xe7, 0xd1, 0x41, 0xe8, 0x45, 0xf2, 0x07, 0x0c, 0x19, 0x01, 0xf3, 0xe2, 0xe9, + 0xfa, 0xe3, 0xfd, 0xfb, 0x3b, 0x42, 0xc7, 0xaa, 0xef, 0x01, 0x27, 0xdf, 0xec, + 0xf6, 0x1b, 0xf7, 0x1c, 0xd9, 0x22, 0x0a, 0x0a, 0xe6, 0x4d, 0xb6, 0x24, 0x03, + 0xd6, 0x08, 0xb6, 0xeb, 0xf6, 0x48, 0x9e, 0xbb, 0x9a, 0x26, 0xd4, 0x2b, 0x9d, + 0xd0, 0xc1, 0xe7, 0xfc, 0x17, 0x06, 0xab, 0x1a, 0x5e, 0x2e, 0x53, 0xc5, 0x08, + 0x3e, 0x20, 0x24, 0xe3, 0xb6, 0xcf, 0x2b, 0x1a, 0x08, 0xe9, 0xc6, 0x19, 0x16, + 0xd4, 0xc7, 0x51, 0x0c, 0x01, 0xf3, 0x4f, 0x2d, 0x07, 0xa5, 0x1c, 0x26, 0x13, + 0xd4, 0xc1, 0xe3, 0xe0, 0xd7, 0x06, 0xb7, 0xef, 0xc1, 0xfe, 0x11, 0xfc, 0x00, + 0x0b, 0x21, 0x62, 0x02, 0x0a, 0x06, 0xf6, 0x15, 0xea, 0xe0, 0x22, 0xcb, 0xe4, + 0x43, 0xf9, 0xf0, 0x11, 0x45, 0xfc, 0xb8, 0x9e, 0x1d, 0xd6, 0x0b, 0x45, 0x15, + 0x35, 0xe2, 0x4c, 0xd7, 0xdd, 0x14, 0x01, 0xe0, 0x2b, 0x49, 0xf4, 0xe0, 0xbb, + 0x18, 0x10, 0xfc, 0x72, 0x30, 0x62, 0xcc, 0xe9, 0x09, 0xd3, 0xe1, 0x30, 0x53, + 0xe7, 0x54, 0xd1, 0x23, 0x1b, 0xd6, 0x09, 0x0f, 0xd9, 0x29, 0xef, 0xd8, 0xaf, + 0xeb, 0xec, 0x11, 0x68, 0x81, 0x3f, 0xef, 0x29, 0x2d, 0x35, 0xc3, 0x69, 0xd0, + 0x05, 0x05, 0x23, 0xe7, 0x0b, 0x2a, 0xf7, 0x34, 0xcc, 0x2a, 0x0c, 0xd7, 0xdb, + 0xdf, 0x35, 0x12, 0xf8, 0xd9, 0x1a, 0x2f, 0xa5, 0xc2, 0x29, 0x10, 0xe6, 0x17, + 0xf2, 0x31, 0x36, 0x23, 0xfa, 0x2c, 0xcd, 0xdc, 0xa6, 0xa6, 0x12, 0x49, 0xff, + 0x16, 0xc6, 0xd8, 0xc3, 0x0f, 0xf4, 0xd8, 0xfe, 0xe3, 0xf0, 0xdd, 0x4c, 0xd9, + 0xe2, 0xe0, 0x0e, 0xfd, 0xfa, 0xe7, 0x3d, 0xdf, 0xb6, 0xf2, 0xf5, 0x83, 0xdb, + 0xff, 0x1c, 0x3d, 0x21, 0x20, 0x96, 0xc6, 0xc8, 0x42, 0x3a, 0x1b, 0x3c, 0x27, + 0xcf, 0x57, 0x0f, 0x1c, 0xc4, 0x3c, 0xc7, 0xe2, 0xda, 0xe8, 0xc5, 0xfb, 0xf7, + 0xd7, 0x03, 0x08, 0xd0, 0xfe, 0xf4, 0xfa, 0x11, 0xaa, 0xe5, 0xdd, 0xa4, 0xdc, + 0x81, 0x19, 0x44, 0x0e, 0xea, 0xfc, 0xf5, 0xd4, 0xe3, 0x13, 0x2c, 0x9c, 0xef, + 0x04, 0x10, 0xa1, 0x51, 0x41, 0xd4, 0xec, 0x23, 0x67, 0x22, 0x0d, 0x0d, 0x34, + 0xca, 0xd2, 0xb6, 0xca, 0x3a, 0xf9, 0xc0, 0x16, 0xa6, 0x22, 0xeb, 0xc3, 0x10, + 0xd4, 0xa1, 0x35, 0xc4, 0x23, 0x52, 0xe6, 0x30, 0x30, 0xe2, 0xc8, 0x26, 0x21, + 0x20, 0x00, 0x66, 0x46, 0xfe, 0x00, 0xdd, 0xaf, 0x4f, 0x4a, 0xdf, 0x16, 0x05, + 0x02, 0xe2, 0x0b, 0xf5, 0xf5, 0x0c, 0xe6, 0x45, 0xeb, 0x46, 0x0a, 0x3d, 0x81, + 0x2a, 0xf6, 0xdb, 0x38, 0xb8, 0xe9, 0x06, 0x1a, 0x27, 0xf3, 0x1d, 0x13, 0xda, + 0x25, 0x07, 0x37, 0xa4, 0x23, 0x0d, 0x1f, 0xd4, 0xf1, 0xdc, 0x43, 0x28, 0x4f, + 0x36, 0xa6, 0x0b, 0x13, 0xf4, 0xf3, 0xe4, 0xe8, 0xe3, 0x01, 0x35, 0x98, 0x2b, + 0x00, 0xc9, 0x26, 0x20, 0xd4, 0x5a, 0x3b, 0x0d, 0xfb, 0x03, 0x28, 0xe6, 0xfe, + 0x12, 0xe1, 0x0c, 0xef, 0x72, 0x1c, 0xd6, 0xa1, 0x51, 0xcf, 0x1e, 0x0c, 0xed, + 0x5c, 0xe2, 0xd1, 0x13, 0xf7, 0xe4, 0xff, 0xf2, 0xe5, 0xf2, 0x10, 0xf9, 0xd2, + 0xdf, 0x1f, 0xff, 0xee, 0x1d, 0x51, 0x02, 0xcc, 0xf0, 0xe3, 0x0f, 0xc4, 0x45, + 0x02, 0x2e, 0x3e, 0x13, 0x34, 0x00, 0xf4, 0xdc, 0x3b, 0x13, 0x0f, 0xe0, 0x4e, + 0x02, 0x55, 0x17, 0xfa, 0xf7, 0x07, 0xcd, 0x04, 0xf6, 0x9f, 0x03, 0xf4, 0xf0, + 0xe4, 0xdf, 0xce, 0x1c, 0x0e, 0x14, 0x03, 0x0c, 0xf8, 0x0d, 0xe4, 0xe1, 0xea, + 0x2f, 0xd8, 0xdf, 0x15, 0xf1, 0xcf, 0xfc, 0x16, 0x3e, 0x08, 0x0c, 0x00, 0xfc, + 0xf0, 0xc6, 0xd6, 0xf1, 0x20, 0x7f, 0x07, 0x43, 0xce, 0x00, 0x06, 0x12, 0x18, + 0x11, 0x11, 0x1b, 0xdb, 0x13, 0x1e, 0xb5, 0x49, 0xdf, 0xee, 0xd4, 0x39, 0xd7, + 0x0e, 0xfe, 0x25, 0xe8, 0x18, 0xc4, 0xf2, 0xd8, 0x07, 0x4d, 0xe6, 0xf6, 0xf9, + 0xf7, 0x05, 0x31, 0xda, 0xea, 0xfe, 0xfd, 0x15, 0xfc, 0x10, 0xea, 0x0f, 0xc8, + 0x35, 0xcb, 0xc9, 0x27, 0xd5, 0x33, 0x24, 0xf9, 0x12, 0x1b, 0xc6, 0x81, 0x1c, + 0xfa, 0x35, 0xee, 0xb0, 0x01, 0xd9, 0x06, 0x20, 0x06, 0x0b, 0x14, 0xb8, 0xf6, + 0x1e, 0x17, 0xf3, 0xf3, 0x1c, 0xbb, 0xcb, 0xa7, 0xc0, 0x35, 0x04, 0xfa, 0x11, + 0x21, 0x7a, 0xaa, 0xe1, 0x12, 0x14, 0x12, 0xd5, 0x0c, 0x11, 0xc2, 0x2c, 0xfb, + 0xb6, 0x2e, 0x3a, 0xfb, 0xd3, 0xed, 0xf4, 0xd0, 0x1d, 0x1c, 0x04, 0xd1, 0x1d, + 0xb7, 0xdd, 0xd6, 0xf1, 0xf4, 0xf0, 0x09, 0x0e, 0xee, 0x39, 0x0a, 0x16, 0xe3, + 0xcb, 0x27, 0x1f, 0xc8, 0xf0, 0x21, 0x49, 0x27, 0x48, 0xfb, 0xe5, 0xee, 0xff, + 0x14, 0xe6, 0xf4, 0xc9, 0xdb, 0x56, 0xff, 0xda, 0xe9, 0xee, 0x1f, 0x1b, 0x0b, + 0xb5, 0xe5, 0x99, 0xdc, 0xdf, 0xdb, 0xdf, 0xc1, 0x07, 0x52, 0x18, 0xd8, 0xfc, + 0x00, 0x0b, 0xcd, 0xe4, 0x0f, 0x38, 0xf0, 0xe5, 0x28, 0x93, 0x26, 0x10, 0x49, + 0x16, 0xf9, 0x18, 0x37, 0xc8, 0x9e, 0x25, 0xf0, 0x16, 0xb2, 0xf5, 0xed, 0xdc, + 0xe4, 0x20, 0xf7, 0x35, 0x1b, 0x40, 0x22, 0xd0, 0xa4, 0xdf, 0x03, 0xd0, 0x39, + 0xd3, 0x5e, 0x10, 0xb8, 0xd8, 0x47, 0x41, 0x1e, 0xf3, 0xe9, 0x29, 0xcd, 0xee, + 0x0a, 0xab, 0x05, 0xd3, 0xe3, 0x07, 0xc9, 0xd2, 0x11, 0xf2, 0x36, 0xef, 0x62, + 0x10, 0xd1, 0xf2, 0xea, 0xb6, 0x14, 0xc8, 0x24, 0x03, 0x1a, 0xce, 0x7f, 0x43, + 0x39, 0x0c, 0xd3, 0xb0, 0x2e, 0x1a, 0x00, 0xf9, 0xed, 0x00, 0xf4, 0xd7, 0xad, + 0x03, 0x01, 0xaf, 0x5a, 0x16, 0x10, 0x30, 0x16, 0x04, 0x3c, 0x19, 0x17, 0x10, + 0xe8, 0xdb, 0xc9, 0xe5, 0x3e, 0xf4, 0x06, 0xe2, 0x16, 0xe5, 0x36, 0x06, 0xdb, + 0x2f, 0xe0, 0xf2, 0x01, 0xee, 0xdf, 0x08, 0x15, 0x5e, 0x0d, 0x5b, 0x25, 0x1a, + 0x41, 0x09, 0xac, 0xe7, 0x02, 0x01, 0xc2, 0xed, 0xf9, 0x1b, 0x7f, 0xd5, 0xfe, + 0x28, 0x12, 0xed, 0xf8, 0x2c, 0x12, 0x04, 0x1b, 0xf8, 0x13, 0xd2, 0x0b, 0xe0, + 0x04, 0xf0, 0x02, 0xc9, 0xc7, 0xdb, 0xd5, 0xfe, 0xe0, 0xfa, 0x13, 0xdd, 0xfa, + 0x12, 0x1c, 0xe2, 0xfa, 0xfd, 0xf2, 0x22, 0xe5, 0x0b, 0x2a, 0x4f, 0xe2, 0xfc, + 0xf3, 0xdd, 0x1d, 0x2c, 0x23, 0xe1, 0x2c, 0xd5, 0x10, 0x05, 0xf5, 0x15, 0x07, + 0x0f, 0x0c, 0x1e, 0x1e, 0xfa, 0x17, 0xf0, 0xfa, 0x03, 0x22, 0x1f, 0x11, 0x03, + 0xe8, 0xf9, 0x14, 0x15, 0x1d, 0xfe, 0x16, 0xe8, 0xd3, 0x0d, 0x19, 0xdd, 0x26, + 0xfa, 0xc7, 0x2e, 0x1e, 0x15, 0xdc, 0xeb, 0xf8, 0x14, 0xfd, 0x15, 0x18, 0xf5, + 0x2e, 0x0b, 0x20, 0xf1, 0x1a, 0x1a, 0x07, 0x0e, 0x18, 0x2f, 0x13, 0xfe, 0xf2, + 0xc7, 0xd1, 0xfe, 0x00, 0xfd, 0x0f, 0x1e, 0x1c, 0x04, 0x28, 0x12, 0xec, 0x0c, + 0xe4, 0xe1, 0xf6, 0xfd, 0xd5, 0x2e, 0x0f, 0x13, 0x19, 0xf6, 0x0a, 0xd9, 0xfa, + 0x01, 0xeb, 0xdc, 0xef, 0x22, 0xfc, 0x24, 0x08, 0x0b, 0xbe, 0xe6, 0xcc, 0x2c, + 0x2a, 0xec, 0x0c, 0x3a, 0xf5, 0xd5, 0xf1, 0xf1, 0x07, 0xec, 0x0c, 0x2b, 0xdf, + 0xdd, 0x01, 0x0e, 0x1e, 0x21, 0x0c, 0xf6, 0xb8, 0x05, 0x20, 0xea, 0x53, 0x1b, + 0xfb, 0xf1, 0x16, 0xe8, 0x06, 0x2d, 0x0f, 0xdc, 0x01, 0xba, 0x0b, 0xc8, 0x05, + 0x15, 0x0f, 0xf2, 0x07, 0xdb, 0x24, 0xd2, 0x3e, 0x30, 0x22, 0xfd, 0xc5, 0x02, + 0xca, 0x18, 0xf1, 0xea, 0x11, 0x1a, 0xef, 0x1e, 0xdd, 0x7f, 0xdf, 0x08, 0x11, + 0xe1, 0xe0, 0xd7, 0xed, 0xcd, 0xcf, 0xf4, 0x0a, 0x1b, 0xd8, 0xdd, 0xfe, 0xef, + 0x3f, 0xf7, 0x34, 0xef, 0x05, 0xdf, 0xe7, 0xe7, 0x21, 0x38, 0xef, 0xfd, 0xec, + 0xe8, 0x12, 0xd9, 0xe0, 0xf3, 0x2c, 0xc3, 0xe0, 0xeb, 0xe6, 0x1e, 0x1f, 0x1b, + 0xf2, 0xbb, 0xfb, 0xf1, 0x44, 0xe4, 0x0e, 0x08, 0x08, 0xd9, 0x3d, 0x39, 0x16, + 0x09, 0x30, 0xd1, 0x4f, 0x33, 0x15, 0xdf, 0x07, 0xf6, 0xf0, 0x20, 0x14, 0x39, + 0x0d, 0xc2, 0xef, 0x81, 0xf4, 0x13, 0x1b, 0xee, 0xc3, 0xba, 0xd7, 0xe6, 0x55, + 0xfa, 0xeb, 0xe0, 0x3a, 0x43, 0x03, 0x01, 0xcc, 0x11, 0xa8, 0x4d, 0x33, 0xe1, + 0x00, 0x00, 0x4a, 0x58, 0xd6, 0xc1, 0xdf, 0x42, 0xf2, 0xb9, 0x33, 0xb7, 0xd0, + 0x20, 0x41, 0xd8, 0x3d, 0xe2, 0x5e, 0x17, 0xcd, 0xe1, 0xd6, 0x14, 0xee, 0x1b, + 0xff, 0xf0, 0xd9, 0xfc, 0xb2, 0xdb, 0xcf, 0xf8, 0xba, 0x3b, 0xfd, 0x1c, 0xc7, + 0xd6, 0x34, 0x29, 0xe2, 0xe1, 0xf8, 0xab, 0xdc, 0x62, 0x4f, 0x17, 0xdf, 0xc7, + 0xef, 0xda, 0x44, 0xfe, 0xd3, 0x4f, 0x45, 0xe1, 0x3c, 0x08, 0xec, 0xdb, 0x3d, + 0xfc, 0x1f, 0xc8, 0xec, 0xb2, 0x2b, 0x20, 0x22, 0x1a, 0xf7, 0xcc, 0xfb, 0x03, + 0x15, 0x58, 0x20, 0xf3, 0xe4, 0x19, 0xf1, 0xce, 0x11, 0xbd, 0x1c, 0x05, 0xcd, + 0x1b, 0xc0, 0xfe, 0x20, 0xf4, 0xf1, 0x18, 0x58, 0xd5, 0x28, 0xec, 0x29, 0x0d, + 0x2b, 0x1f, 0xb3, 0xf1, 0x23, 0xfe, 0x7f, 0x6a, 0x47, 0x2d, 0xdf, 0x04, 0xf2, + 0xc3, 0x01, 0x1e, 0x22, 0x8e, 0x08, 0xfb, 0x44, 0x0f, 0x5b, 0xf7, 0xe0, 0x0c, + 0xf6, 0xb6, 0x34, 0x0b, 0x3e, 0x0d, 0xdd, 0x41, 0xf5, 0xd7, 0xf4, 0x2b, 0x14, + 0xec, 0x0c, 0xca, 0x37, 0x14, 0x2f, 0xda, 0x3d, 0x12, 0x04, 0x12, 0x08, 0xef, + 0xfc, 0x71, 0x21, 0x4d, 0xf6, 0xe0, 0xec, 0xf3, 0xcb, 0x2c, 0x23, 0x11, 0x91, + 0x06, 0xf7, 0x01, 0xd7, 0x2c, 0x16, 0xfe, 0x1b, 0xc8, 0x1b, 0x15, 0xd6, 0x04, + 0x2d, 0x82, 0x44, 0x0e, 0x08, 0xff, 0x3d, 0x06, 0x62, 0x17, 0xb2, 0xee, 0x4b, + 0x19, 0x26, 0x07, 0x86, 0xc7, 0xff, 0xf0, 0x55, 0xd6, 0x04, 0x4a, 0xef, 0xe6, + 0x33, 0x15, 0xe4, 0x03, 0x10, 0xc1, 0xc0, 0xf5, 0xed, 0x1f, 0x09, 0x1d, 0x21, + 0xaf, 0xf9, 0xd5, 0x02, 0x59, 0x06, 0xcc, 0xfd, 0xab, 0xec, 0x27, 0x49, 0xf1, + 0x10, 0xe8, 0xd1, 0x1a, 0xae, 0xf7, 0x14, 0x2a, 0x12, 0x1f, 0xfc, 0xc3, 0x3f, + 0xf3, 0x08, 0xe2, 0xea, 0xb3, 0xef, 0x10, 0xed, 0x04, 0xf8, 0x2b, 0xce, 0xeb, + 0xf4, 0xf9, 0x16, 0xf0, 0xf5, 0x29, 0x2c, 0xcf, 0xf3, 0x15, 0xf6, 0x22, 0xea, + 0x0d, 0xf7, 0xcd, 0xf7, 0x6e, 0x0e, 0xb9, 0xea, 0xd9, 0xf0, 0x1b, 0x01, 0xc9, + 0x0e, 0xd5, 0xf1, 0x1a, 0x00, 0x1e, 0xfb, 0x0e, 0xe4, 0x05, 0x4d, 0xea, 0x81, + 0xee, 0x0e, 0xcc, 0x01, 0x19, 0xc6, 0xfb, 0xe3, 0x14, 0x34, 0xec, 0xe5, 0x39, + 0x13, 0x09, 0x2c, 0xc6, 0xfe, 0xa7, 0xe5, 0x20, 0xd1, 0x0c, 0x0a, 0x0c, 0x43, + 0xe9, 0xb0, 0xf7, 0xf3, 0x02, 0x60, 0x29, 0x1c, 0xd9, 0x28, 0x3f, 0x0d, 0x35, + 0xc2, 0x37, 0x1b, 0x0b, 0x2d, 0xe4, 0xf4, 0xa7, 0xde, 0xf0, 0xbd, 0x1d, 0x22, + 0x21, 0xc5, 0x1f, 0xe7, 0x4e, 0x28, 0xcf, 0xc2, 0xf9, 0xc3, 0xb8, 0xc9, 0xec, + 0xe2, 0xf0, 0x0a, 0x11, 0xd0, 0xc0, 0xb0, 0x25, 0x0d, 0xca, 0xbe, 0x2a, 0xf8, + 0xd7, 0x0f, 0xe5, 0xf7, 0xfa, 0xde, 0xe5, 0xe8, 0xf6, 0x42, 0x2f, 0xe3, 0xdd, + 0x2e, 0xb1, 0xb8, 0xcf, 0xf6, 0x08, 0xc6, 0x2d, 0xd4, 0xe0, 0xee, 0x34, 0xd7, + 0x21, 0x12, 0xb3, 0x48, 0x3c, 0x12, 0xd5, 0x04, 0xcf, 0xdc, 0x25, 0x05, 0x03, + 0xcf, 0x0b, 0x30, 0x9d, 0x1c, 0x30, 0x23, 0x5b, 0x36, 0x27, 0x3d, 0xdf, 0xe0, + 0xfd, 0xde, 0xdb, 0xfd, 0x41, 0x0c, 0xdb, 0xe5, 0x08, 0x1b, 0xef, 0x5c, 0x81, + 0x1d, 0x2a, 0xcb, 0x0e, 0x0b, 0x35, 0x2a, 0xcc, 0x24, 0xe8, 0x2c, 0x2e, 0x18, + 0x18, 0xe8, 0x52, 0xb7, 0x32, 0x16, 0xd7, 0xf6, 0x51, 0xdb, 0xaf, 0x39, 0xfe, + 0xec, 0xf0, 0x8c, 0xee, 0xd5, 0xc5, 0x32, 0x0e, 0xc6, 0xc9, 0xab, 0x06, 0x35, + 0xdb, 0x4d, 0x33, 0x02, 0x1d, 0x05, 0xe9, 0x27, 0xcd, 0x13, 0x00, 0xcb, 0x48, + 0x0b, 0xe1, 0x0d, 0xb3, 0xfc, 0xd9, 0x10, 0x24, 0x07, 0xf9, 0xf3, 0x1c, 0xb3, + 0xba, 0xf4, 0xdf, 0xf7, 0xf3, 0xc9, 0x2e, 0xd2, 0xf6, 0xfa, 0x2a, 0xca, 0xec, + 0xb1, 0xfd, 0xf8, 0xca, 0xc8, 0xea, 0x04, 0x38, 0x25, 0x09, 0xb3, 0xce, 0x27, + 0x1a, 0x4f, 0x11, 0x1a, 0xe3, 0x22, 0x27, 0xfd, 0x03, 0x41, 0xd7, 0x05, 0xe5, + 0x9e, 0x04, 0x0c, 0x04, 0xf5, 0xe3, 0xdf, 0x55, 0xed, 0xea, 0xd0, 0x2b, 0x16, + 0xe2, 0xf3, 0x29, 0xf4, 0x44, 0x27, 0x65, 0xda, 0x45, 0x16, 0xd5, 0xed, 0x04, + 0xf3, 0x13, 0xb9, 0xc8, 0xe6, 0xf8, 0xbc, 0x7f, 0xdc, 0xea, 0xfd, 0xed, 0x10, + 0x10, 0x29, 0x3e, 0xea, 0xf8, 0x9e, 0x11, 0xd2, 0x0d, 0x28, 0x44, 0x30, 0x2a, + 0x49, 0x2b, 0xba, 0xd4, 0x18, 0x07, 0x48, 0x12, 0x21, 0x59, 0x36, 0xea, 0x13, + 0x58, 0xe4, 0xc3, 0x37, 0xdb, 0xcb, 0x19, 0xdf, 0x21, 0x17, 0x50, 0x0d, 0xcd, + 0xbf, 0x2b, 0x0e, 0xd2, 0x06, 0xb9, 0xfe, 0x3b, 0x1d, 0xe9, 0xd8, 0x0d, 0x41, + 0xdd, 0xfe, 0xeb, 0xd5, 0x37, 0xad, 0xf3, 0x00, 0x21, 0x0f, 0xcc, 0xf0, 0xd6, + 0x5e, 0x0b, 0xf2, 0x09, 0x2b, 0x39, 0xd3, 0x1b, 0xe3, 0xb7, 0xed, 0xfb, 0xe3, + 0xd7, 0x40, 0xe3, 0x09, 0x44, 0x0f, 0x26, 0xf5, 0xf9, 0x4b, 0x98, 0xf1, 0x09, + 0x81, 0xe8, 0xcd, 0x34, 0xdc, 0x19, 0x2a, 0x5b, 0xe8, 0xf5, 0xfd, 0x2c, 0xc2, + 0xd4, 0xe1, 0x0c, 0xda, 0xe7, 0xfe, 0xcd, 0x1d, 0xf8, 0x00, 0x08, 0xe5, 0xf1, + 0x51, 0x10, 0x11, 0xa9, 0xc9, 0x28, 0x10, 0xfd, 0x4e, 0x0c, 0x1e, 0x21, 0x28, + 0x0b, 0x0e, 0xe8, 0xcd, 0xff, 0xe3, 0x20, 0xbd, 0xe6, 0x05, 0xef, 0x31, 0xf6, + 0xe4, 0x25, 0x0d, 0xf0, 0xf0, 0x1f, 0x14, 0xe0, 0xf5, 0x15, 0x19, 0xeb, 0x0a, + 0x02, 0xe9, 0xbd, 0x24, 0x0c, 0x0d, 0x44, 0xe9, 0xf7, 0xdf, 0x42, 0xce, 0xf6, + 0x16, 0x12, 0x02, 0xca, 0x28, 0x0f, 0x1c, 0x1c, 0xf5, 0x32, 0xfd, 0x24, 0x43, + 0xdf, 0xe6, 0xea, 0x1c, 0x0a, 0x11, 0xfe, 0xfd, 0x12, 0x19, 0xf5, 0xd2, 0x47, + 0xc4, 0x1f, 0x0c, 0xfe, 0x07, 0xf4, 0x0c, 0xd3, 0xe6, 0xd8, 0x81, 0x6d, 0xff, + 0xf6, 0x05, 0x29, 0xe1, 0x04, 0xd9, 0xf7, 0xf7, 0xea, 0xec, 0xf5, 0xbd, 0x10, + 0x08, 0xf5, 0xd1, 0x47, 0x17, 0x36, 0xe0, 0xf5, 0xf2, 0xe2, 0xd9, 0x10, 0xd9, + 0xdb, 0xe8, 0x47, 0xfd, 0x30, 0x41, 0xfc, 0xdf, 0x10, 0xf4, 0x27, 0x05, 0xea, + 0xed, 0xdb, 0x1b, 0x12, 0x0f, 0xd3, 0x09, 0xfe, 0xf4, 0x08, 0xea, 0xf4, 0x0e, + 0x4e, 0x0f, 0xf3, 0x53, 0x35, 0xc1, 0xd3, 0x06, 0x39, 0xed, 0xc4, 0xe4, 0xd1, + 0xfb, 0xcc, 0x28, 0xeb, 0xb9, 0xfe, 0xd2, 0xfb, 0xf0, 0xc5, 0xf6, 0x48, 0xdf, + 0xb8, 0x16, 0xf4, 0x20, 0x04, 0x32, 0x3e, 0xc8, 0xe0, 0xe5, 0x0e, 0x18, 0x1c, + 0x30, 0x1d, 0xf7, 0x1f, 0x22, 0x0f, 0xb9, 0x3a, 0xa8, 0x2c, 0x55, 0x01, 0x0c, + 0xfb, 0xb5, 0xf1, 0xf5, 0xe6, 0xe5, 0x3a, 0x7f, 0xe0, 0xba, 0xcc, 0xf4, 0xfd, + 0xee, 0xde, 0x61, 0xcd, 0xf8, 0xb7, 0xd6, 0xb1, 0x10, 0x03, 0x10, 0xe6, 0xe4, + 0xf2, 0xe0, 0x2d, 0x96, 0x01, 0x0e, 0xde, 0xc2, 0x0d, 0x22, 0x06, 0xd0, 0x39, + 0xe3, 0xfc, 0x2b, 0xb5, 0xeb, 0xc6, 0xc7, 0xac, 0xe6, 0x1f, 0xf6, 0xf9, 0xbb, + 0x37, 0xec, 0xe9, 0x2d, 0xdf, 0xb9, 0x1a, 0xe4, 0xd5, 0xdb, 0xc3, 0x07, 0x19, + 0xef, 0xf5, 0xd2, 0x1d, 0x03, 0xda, 0x0e, 0x33, 0x42, 0x30, 0x19, 0x09, 0x3c, + 0xb6, 0x03, 0xea, 0x1f, 0xe7, 0xf1, 0xd4, 0x0f, 0xe5, 0xe4, 0x16, 0x05, 0xf5, + 0x05, 0x7f, 0xf3, 0xd2, 0x16, 0xe7, 0x23, 0xda, 0xd7, 0xd0, 0xfe, 0xeb, 0x2d, + 0xf4, 0x47, 0x05, 0x0c, 0xed, 0x08, 0x00, 0x11, 0x0d, 0xe6, 0xb4, 0x24, 0x13, + 0x10, 0x17, 0xf4, 0x17, 0xf5, 0x23, 0xd7, 0x3d, 0x0f, 0xef, 0xee, 0xdf, 0xf2, + 0xde, 0x1b, 0xfb, 0xe3, 0x11, 0x11, 0x1a, 0x21, 0x5a, 0xb5, 0x21, 0x05, 0xd8, + 0xed, 0x36, 0xde, 0xfb, 0xe8, 0xe4, 0xe8, 0x39, 0xd1, 0x08, 0x56, 0xc6, 0xf3, + 0x02, 0x26, 0xde, 0x14, 0xff, 0x38, 0x0a, 0xea, 0x0a, 0xc1, 0xfa, 0xf2, 0xd7, + 0xc8, 0x22, 0xcf, 0xb8, 0x28, 0x10, 0xc6, 0xf0, 0xec, 0xff, 0xdb, 0x2e, 0xf9, + 0x0d, 0x39, 0x02, 0xf0, 0xf9, 0xf9, 0x15, 0x4a, 0x02, 0xd3, 0x11, 0xfe, 0x15, + 0xdd, 0xc7, 0x19, 0xe5, 0x13, 0x08, 0x15, 0x3c, 0x05, 0xcd, 0x1a, 0xf4, 0x10, + 0x07, 0xff, 0xee, 0xed, 0x0f, 0xfc, 0x1b, 0x0a, 0xba, 0xe0, 0xf5, 0xe2, 0xb3, + 0x0c, 0x9f, 0x4d, 0xfd, 0xcd, 0x1a, 0xd8, 0xf9, 0xe3, 0x34, 0xef, 0xf3, 0xfd, + 0x40, 0x47, 0x0e, 0x20, 0x14, 0xec, 0x11, 0xe8, 0x38, 0xfb, 0x45, 0xbf, 0xed, + 0x6a, 0xcf, 0xd4, 0x3c, 0x0e, 0x40, 0x0b, 0x2d, 0x3d, 0x30, 0xd8, 0x32, 0x03, + 0xe5, 0xc5, 0x07, 0x0f, 0x03, 0xfb, 0x92, 0xe6, 0xe3, 0x3c, 0xfd, 0x39, 0xfd, + 0x12, 0x99, 0xdb, 0x0e, 0x3b, 0x31, 0x06, 0xc0, 0xc5, 0x02, 0x49, 0xe3, 0x3a, + 0xcc, 0x38, 0xef, 0xa1, 0x1e, 0x09, 0x01, 0xc4, 0x3b, 0x28, 0x41, 0xb9, 0x12, + 0xeb, 0x10, 0x43, 0xdf, 0x1e, 0xb0, 0xc8, 0x7f, 0x18, 0x05, 0x0e, 0x0e, 0xfe, + 0xde, 0x34, 0xe5, 0x29, 0xe9, 0x06, 0x00, 0x0b, 0x10, 0xd6, 0xeb, 0x1e, 0x14, + 0xe2, 0xd9, 0xba, 0x1e, 0xec, 0x26, 0x09, 0xd0, 0xc0, 0xf7, 0x8e, 0x09, 0xb6, + 0x44, 0x22, 0x29, 0xf6, 0x05, 0xc7, 0x91, 0x09, 0xd2, 0x81, 0x50, 0xdd, 0x10, + 0xf2, 0x05, 0x6b, 0x10, 0x0b, 0x26, 0xe1, 0x79, 0xd5, 0x33, 0xdc, 0x1d, 0xc8, + 0xed, 0xc3, 0x41, 0x8f, 0xca, 0xde, 0x10, 0xec, 0x01, 0xe0, 0xe5, 0xe7, 0x18, + 0x97, 0xe0, 0x09, 0xfd, 0x1b, 0x09, 0xfa, 0x05, 0x0f, 0xf2, 0xbd, 0xeb, 0x39, + 0xf5, 0xe0, 0xd9, 0xe7, 0xda, 0x22, 0x21, 0x2b, 0xf9, 0xdb, 0xf8, 0x19, 0x34, + 0xf2, 0x38, 0xdd, 0xf0, 0xfb, 0xe5, 0x04, 0xf5, 0xbd, 0x59, 0x01, 0x0f, 0x79, + 0x1c, 0xda, 0xcd, 0x1e, 0x30, 0x27, 0x0d, 0x11, 0x0a, 0x0b, 0xf0, 0x4d, 0xb3, + 0x5e, 0xf5, 0x23, 0xf6, 0xfc, 0x2f, 0xd7, 0x5b, 0xc2, 0x5f, 0x21, 0xfd, 0xdf, + 0x06, 0x3e, 0xef, 0x78, 0x5b, 0x9a, 0x3e, 0x18, 0xf0, 0xf2, 0xc4, 0xf4, 0xec, + 0xff, 0x09, 0xe7, 0x23, 0x07, 0x22, 0x1b, 0xe9, 0xdf, 0x3c, 0xe7, 0x0b, 0x01, + 0xc1, 0x07, 0xec, 0xa0, 0x0b, 0xce, 0xf9, 0x02, 0x0a, 0x57, 0x5d, 0xbc, 0x18, + 0xdb, 0x24, 0x08, 0x07, 0x37, 0xfc, 0xd2, 0x3d, 0xe0, 0x12, 0x14, 0x32, 0xe7, + 0x31, 0xf9, 0xe1, 0x5d, 0xf5, 0xc7, 0x25, 0xf8, 0xe5, 0x0a, 0x12, 0x0b, 0x29, + 0xfe, 0xd5, 0x3c, 0x32, 0xf8, 0x02, 0xed, 0x1a, 0x38, 0xdb, 0xee, 0x12, 0xdc, + 0x05, 0x1c, 0xa6, 0xff, 0xde, 0xf3, 0x07, 0x06, 0x1d, 0xb2, 0xd9, 0x03, 0x2b, + 0xa0, 0x10, 0x29, 0xee, 0x27, 0x3d, 0x2b, 0xb4, 0xdb, 0x2a, 0xca, 0xf6, 0xd4, + 0x10, 0x81, 0xff, 0xe7, 0x20, 0xb3, 0x04, 0xbb, 0xe5, 0x0c, 0xd7, 0xbe, 0xde, + 0xa9, 0xed, 0xe0, 0x02, 0xed, 0x19, 0x01, 0x0e, 0xc9, 0xee, 0x3f, 0x4a, 0x63, + 0xfa, 0xfc, 0xf8, 0x12, 0xdf, 0xbf, 0x12, 0x1f, 0x26, 0xd7, 0xfd, 0x08, 0x2d, + 0xc6, 0x38, 0xa5, 0xba, 0x42, 0xed, 0xe2, 0x04, 0x02, 0x22, 0xd2, 0x34, 0x25, + 0x29, 0xfd, 0x05, 0xe4, 0xfe, 0x9f, 0x12, 0x36, 0xb6, 0xf1, 0x3e, 0x02, 0xcf, + 0x54, 0xa5, 0x19, 0xe6, 0x59, 0xfa, 0xf9, 0x1c, 0x15, 0x02, 0xfb, 0x3c, 0x11, + 0x38, 0xed, 0x14, 0xf1, 0x0a, 0x1a, 0x14, 0x03, 0xd0, 0x4c, 0xcc, 0x1a, 0x1c, + 0x1e, 0xe8, 0xd6, 0x2e, 0xd7, 0xef, 0x60, 0xd3, 0x23, 0xfb, 0x0d, 0xe8, 0x35, + 0x7f, 0xf8, 0xde, 0xf7, 0x1b, 0xf2, 0xc9, 0x1a, 0xda, 0xe1, 0xc6, 0x33, 0xc9, + 0x37, 0xce, 0x02, 0x43, 0x05, 0x07, 0xeb, 0x12, 0xf9, 0x32, 0xea, 0xf5, 0x18, + 0x0f, 0x51, 0xd9, 0xd1, 0xdd, 0xd1, 0x02, 0x18, 0xef, 0xc1, 0x29, 0x51, 0xed, + 0xc2, 0x37, 0xee, 0x45, 0x02, 0xdc, 0xff, 0x35, 0xc4, 0x03, 0x0d, 0xc8, 0xdd, + 0x27, 0xeb, 0xb8, 0xd4, 0xdd, 0x2d, 0x2e, 0xe7, 0x26, 0xf2, 0xce, 0xe7, 0x04, + 0x1d, 0x2d, 0x05, 0x0f, 0x06, 0xfd, 0xc0, 0xff, 0xf5, 0x09, 0x21, 0xec, 0xf5, + 0xfe, 0xee, 0xf2, 0x0e, 0xea, 0x16, 0xec, 0x01, 0x14, 0x2c, 0x13, 0xfd, 0xdf, + 0x04, 0xe0, 0x0a, 0xe2, 0x9d, 0xe4, 0x54, 0xd9, 0x06, 0x0b, 0xda, 0x0b, 0xc3, + 0x0e, 0x14, 0xca, 0x13, 0xc7, 0x46, 0xfd, 0x28, 0xea, 0x2d, 0x14, 0x16, 0xd5, + 0x07, 0x0c, 0x27, 0x27, 0x07, 0x10, 0xde, 0x46, 0x02, 0x0c, 0x06, 0x1f, 0xd0, + 0x32, 0xec, 0xf9, 0xb0, 0xfe, 0xcd, 0xea, 0x18, 0x1b, 0x09, 0xcf, 0x3d, 0x01, + 0xee, 0x07, 0xeb, 0xe9, 0xe7, 0xf5, 0x00, 0x2c, 0x48, 0xf8, 0xe5, 0x25, 0xf3, + 0x0e, 0x7f, 0x0b, 0x05, 0xd5, 0xcd, 0x21, 0x0a, 0xdd, 0xc6, 0xef, 0xf0, 0xf1, + 0xfc, 0xc9, 0x29, 0xf2, 0xf9, 0x04, 0xee, 0xe6, 0x19, 0xf7, 0x1f, 0x48, 0x01, + 0xfb, 0xc3, 0xea, 0xb0, 0x0a, 0x23, 0xe5, 0xfa, 0xbc, 0x12, 0xfe, 0xec, 0x0a, + 0xdb, 0x01, 0xc1, 0xed, 0xdd, 0xfe, 0x08, 0xee, 0x8a, 0x01, 0xa4, 0x11, 0xf1, + 0x22, 0xbc, 0x00, 0x08, 0x16, 0x23, 0x02, 0x7c, 0x37, 0xf8, 0xff, 0xfb, 0xe9, + 0xcd, 0xee, 0x55, 0x15, 0x38, 0x42, 0x14, 0xac, 0xb2, 0x5d, 0x21, 0xe5, 0xfc, + 0x1a, 0xd9, 0xf9, 0xc9, 0xd3, 0xd0, 0x0d, 0xe0, 0x29, 0x4f, 0xfd, 0xd1, 0x4f, + 0xca, 0xc8, 0x05, 0xed, 0xe0, 0xfa, 0xf5, 0x36, 0x17, 0x19, 0xd6, 0x4b, 0xd5, + 0x14, 0xda, 0x51, 0xe5, 0xd6, 0xfa, 0x0f, 0xd1, 0x09, 0xe8, 0x93, 0x24, 0x75, + 0x19, 0x2a, 0x11, 0x2e, 0x30, 0x0f, 0x4d, 0xfa, 0xb9, 0xda, 0x94, 0xbe, 0xa0, + 0xf4, 0xee, 0x28, 0xe8, 0x2c, 0x44, 0xdd, 0xb4, 0x7f, 0x9e, 0xee, 0xee, 0xfd, + 0xf0, 0x12, 0xde, 0x28, 0x17, 0xc4, 0x1c, 0x27, 0x95, 0x0f, 0x18, 0x09, 0x33, + 0x3b, 0x0d, 0xe4, 0xd4, 0x14, 0x37, 0x39, 0xc3, 0x4f, 0xc6, 0x0f, 0xe8, 0x03, + 0xdb, 0x01, 0xf9, 0xf2, 0xe6, 0xe3, 0xb6, 0x07, 0xe9, 0x8a, 0x2b, 0x57, 0x10, + 0x2b, 0x21, 0x0a, 0xec, 0x06, 0xad, 0x65, 0xcc, 0x22, 0x1f, 0x35, 0x01, 0x8e, + 0x13, 0x1e, 0x19, 0xc7, 0xfd, 0xfa, 0x32, 0xc9, 0xe2, 0x4b, 0x5f, 0x36, 0xde, + 0xb5, 0xea, 0x4b, 0x1d, 0xdf, 0xf5, 0x13, 0xe4, 0xe1, 0xf7, 0x98, 0xd9, 0xef, + 0xfb, 0x13, 0x08, 0x2b, 0x08, 0xd3, 0xdf, 0xfe, 0x2d, 0x01, 0xbf, 0xef, 0x4d, + 0xe3, 0x11, 0x34, 0xf4, 0x2f, 0xcf, 0x09, 0xbc, 0xfa, 0x63, 0xdb, 0x0f, 0x3e, + 0x0f, 0xc9, 0xdb, 0x12, 0x0b, 0xf3, 0x2b, 0xf2, 0xf8, 0xf0, 0xbb, 0xd2, 0xb5, + 0xe8, 0x49, 0xef, 0x91, 0xdf, 0x07, 0x13, 0x48, 0xdd, 0x46, 0xfc, 0xf5, 0xfa, + 0xdb, 0xdf, 0x23, 0x7f, 0xe5, 0x03, 0xf2, 0x2e, 0x0e, 0xb2, 0xd8, 0x10, 0x48, + 0x03, 0x03, 0xd9, 0xe4, 0x2b, 0xc0, 0x17, 0xfe, 0xa2, 0xfb, 0xde, 0xf7, 0x05, + 0x26, 0x5b, 0xf7, 0x51, 0x0e, 0xe2, 0xcf, 0xcc, 0x58, 0xc1, 0x46, 0x41, 0xfe, + 0xf6, 0x43, 0xc8, 0x48, 0xf6, 0x0c, 0x1c, 0xb3, 0xf4, 0x45, 0xde, 0x3b, 0x38, + 0x2a, 0x5f, 0x90, 0x3e, 0xb5, 0x24, 0x73, 0x1d, 0x17, 0x1c, 0x0b, 0xe7, 0x0e, + 0xdd, 0xfa, 0x22, 0x29, 0x3f, 0x02, 0xf9, 0xe2, 0xf8, 0x59, 0xc9, 0xe7, 0xe8, + 0x14, 0x11, 0x7f, 0x10, 0xf0, 0x4c, 0xc2, 0x39, 0x67, 0x1e, 0x3b, 0x29, 0xa2, + 0x14, 0xc1, 0x45, 0xc4, 0x5a, 0x97, 0x3c, 0x61, 0x13, 0x2e, 0xb4, 0xe8, 0x2b, + 0x26, 0x19, 0xe9, 0xc2, 0xcf, 0xf7, 0xdb, 0xee, 0xfe, 0x61, 0xd7, 0x34, 0xed, + 0xcc, 0xdf, 0x4b, 0x54, 0x02, 0x23, 0x55, 0xff, 0xfd, 0xc2, 0x50, 0x28, 0x31, + 0x03, 0xac, 0x0c, 0x44, 0xe0, 0xdb, 0x20, 0x16, 0x23, 0x10, 0xd5, 0x41, 0x0a, + 0x2c, 0x0b, 0xe5, 0xe7, 0x65, 0xfe, 0xea, 0xe9, 0x4d, 0xad, 0x70, 0xee, 0x19, + 0xab, 0xcb, 0x22, 0x20, 0xc7, 0xf7, 0xe1, 0x2a, 0xa5, 0xf3, 0x20, 0xf8, 0x19, + 0x1c, 0x0b, 0x33, 0x50, 0x1e, 0x3d, 0xf3, 0xce, 0xf3, 0x16, 0x36, 0x19, 0xdb, + 0xf8, 0xdf, 0x1f, 0xe4, 0xe0, 0x19, 0x30, 0x0a, 0xa1, 0xeb, 0xba, 0x0e, 0xf8, + 0xa4, 0xf6, 0x22, 0xdd, 0xb3, 0xf8, 0xeb, 0xbc, 0x22, 0xfa, 0xff, 0xe5, 0x51, + 0xef, 0xf7, 0x08, 0xe3, 0x7f, 0x0a, 0x0a, 0xd5, 0x29, 0xf0, 0x02, 0xc9, 0x28, + 0x30, 0xc3, 0x19, 0xd2, 0x23, 0x0f, 0x6a, 0xd3, 0xb4, 0xf1, 0x12, 0xd5, 0xf3, + 0x19, 0xc8, 0xc6, 0xcd, 0xcd, 0xf5, 0xf9, 0x10, 0x36, 0xf6, 0x26, 0x2b, 0x50, + 0xe4, 0x9b, 0x47, 0x43, 0xee, 0x2f, 0x0a, 0x19, 0xf6, 0x15, 0xff, 0x0b, 0x14, + 0x13, 0x37, 0x27, 0x18, 0x23, 0xfc, 0x13, 0x36, 0x3a, 0xf3, 0xf5, 0xfe, 0xff, + 0x1f, 0xdb, 0x01, 0x15, 0xf2, 0x5f, 0x0e, 0x12, 0xd4, 0xe9, 0x07, 0xdf, 0x32, + 0xc5, 0xcf, 0xf5, 0x28, 0xf8, 0x2e, 0x2d, 0xf0, 0x7f, 0xf1, 0xf0, 0xd9, 0x04, + 0xd2, 0x39, 0x2d, 0xb6, 0xcf, 0xd9, 0x0d, 0x08, 0x6f, 0xfd, 0x2d, 0xfb, 0xd3, + 0xf8, 0x0b, 0x02, 0xdf, 0xf0, 0xc7, 0x52, 0x34, 0xf6, 0x1f, 0xf1, 0xcf, 0xec, + 0x48, 0x1e, 0xfd, 0xed, 0xe2, 0xb4, 0x20, 0x3e, 0xe2, 0xfc, 0xb4, 0xfa, 0xea, + 0x16, 0xf4, 0xd1, 0x04, 0xea, 0x17, 0x51, 0x18, 0x6e, 0x23, 0xec, 0x06, 0xec, + 0x62, 0x04, 0x5f, 0xe4, 0xbd, 0x20, 0x1a, 0xa6, 0xea, 0x19, 0xdf, 0xf1, 0xbf, + 0xf9, 0xfe, 0x8f, 0x05, 0xf7, 0xe9, 0xdd, 0xfb, 0x07, 0xec, 0x12, 0x00, 0x1b, + 0x49, 0x14, 0x2f, 0xd4, 0x06, 0x15, 0x12, 0x19, 0xeb, 0x12, 0xdf, 0xea, 0x44, + 0x07, 0xe1, 0x47, 0xfe, 0x46, 0xe0, 0x39, 0xe5, 0xe2, 0xcd, 0xee, 0x24, 0xde, + 0xe9, 0xfd, 0xb6, 0x2c, 0xc1, 0xed, 0xde, 0xc9, 0x28, 0xef, 0xdf, 0x06, 0x01, + 0xc7, 0xf4, 0xf3, 0x22, 0xde, 0x14, 0x0e, 0x00, 0x0f, 0x0f, 0xf2, 0xcf, 0x55, + 0xe2, 0xf4, 0xe5, 0x0a, 0x05, 0xeb, 0xd2, 0x28, 0xdf, 0x14, 0xc8, 0xcd, 0xda, + 0xfb, 0xf8, 0xed, 0xf3, 0x05, 0xd9, 0x7f, 0xfd, 0x2c, 0x20, 0xf0, 0x10, 0x0f, + 0xc8, 0xd8, 0x23, 0xba, 0xdb, 0xfb, 0x0f, 0x04, 0xca, 0xe8, 0x30, 0xff, 0xea, + 0x03, 0x4f, 0x03, 0xd3, 0xda, 0x20, 0xf0, 0xbe, 0xfd, 0x26, 0xca, 0x03, 0xc9, + 0xdf, 0x03, 0x48, 0xf9, 0x37, 0xf6, 0x13, 0x01, 0x21, 0xf3, 0x21, 0xc7, 0xd8, + 0xff, 0xaa, 0x36, 0x39, 0xef, 0x36, 0x03, 0x00, 0xe5, 0x3b, 0xe4, 0xf8, 0x32, + 0x3d, 0x17, 0x10, 0xe7, 0x28, 0x32, 0xbb, 0x10, 0xd0, 0xc3, 0x1b, 0x0a, 0xed, + 0xed, 0x11, 0x2d, 0x01, 0xd0, 0xf4, 0xf7, 0x03, 0x01, 0x12, 0xb5, 0x0a, 0xf5, + 0x04, 0x02, 0xf6, 0x17, 0x15, 0xf6, 0xaa, 0xea, 0xb3, 0x3a, 0x0d, 0x19, 0x43, + 0xdf, 0xf3, 0xdb, 0xcd, 0x4c, 0xd0, 0xf8, 0x0a, 0xeb, 0x36, 0xd6, 0x8e, 0x65, + 0x3c, 0xc1, 0x0e, 0x04, 0x1d, 0x40, 0xdb, 0x04, 0x27, 0x27, 0xbb, 0x2b, 0xc2, + 0xca, 0x0f, 0xf8, 0x1b, 0x27, 0xe2, 0x12, 0x8f, 0x15, 0xfe, 0xbc, 0xea, 0x4b, + 0xef, 0xe7, 0xfe, 0xbb, 0xc2, 0xe6, 0x08, 0xe3, 0xcc, 0x38, 0x36, 0xdb, 0x10, + 0x1a, 0x11, 0xe1, 0x10, 0xd3, 0xe5, 0xc1, 0xec, 0xd6, 0xe8, 0x30, 0xce, 0x2e, + 0x3b, 0xe7, 0xb9, 0xce, 0x01, 0x39, 0x3a, 0x04, 0x0c, 0x3b, 0xbe, 0xec, 0x2d, + 0xff, 0x07, 0x02, 0xf4, 0x61, 0x81, 0xf0, 0x39, 0x0c, 0xf3, 0xe4, 0xca, 0xc5, + 0xea, 0x21, 0xe5, 0x12, 0xef, 0xe2, 0xef, 0xeb, 0x13, 0xde, 0x21, 0x18, 0xf5, + 0xee, 0x02, 0x04, 0x43, 0xf4, 0xd7, 0xe9, 0x25, 0xd6, 0x4b, 0xff, 0x4e, 0xe1, + 0xe8, 0xd4, 0xfd, 0xe5, 0xfd, 0xf0, 0xde, 0xe7, 0x0e, 0xe9, 0xd3, 0xd0, 0x2f, + 0x25, 0xe1, 0x06, 0xfc, 0x21, 0xd7, 0xdf, 0x25, 0x7f, 0x1b, 0xee, 0x01, 0xed, + 0xf4, 0x29, 0xf3, 0x3e, 0x09, 0x22, 0xd8, 0xd9, 0x0e, 0xc5, 0x2e, 0xe5, 0x16, + 0x15, 0x3d, 0xb9, 0x0d, 0xff, 0xc5, 0xe0, 0xff, 0xfe, 0x33, 0xe3, 0x19, 0x61, + 0xe4, 0xfb, 0xfc, 0x32, 0xbf, 0xea, 0x00, 0x38, 0x45, 0x2b, 0xc5, 0x25, 0xec, + 0xd7, 0x0c, 0xf0, 0x30, 0xd0, 0xc1, 0x02, 0x20, 0xd9, 0xf4, 0x23, 0x5e, 0x21, + 0x45, 0x0f, 0x28, 0xe6, 0x4d, 0x02, 0x39, 0x08, 0xf1, 0xe4, 0xbd, 0x16, 0xff, + 0x02, 0xfe, 0xee, 0xe2, 0xd3, 0xcb, 0x35, 0x6c, 0x65, 0xfe, 0x03, 0x00, 0xf3, + 0xf0, 0xb9, 0x51, 0x0a, 0x4d, 0x01, 0x48, 0xd7, 0x12, 0x17, 0x1a, 0x0a, 0xf2, + 0x2f, 0x07, 0xf8, 0x02, 0xf5, 0x47, 0xca, 0x17, 0x09, 0xd3, 0x57, 0xfd, 0xe1, + 0xec, 0x05, 0xf9, 0x03, 0xfa, 0xdd, 0xf4, 0x3f, 0xb6, 0x00, 0x1c, 0xd9, 0x4a, + 0xea, 0x23, 0x03, 0xf8, 0xf5, 0x11, 0xfc, 0x13, 0x2f, 0x09, 0xb3, 0x0b, 0xeb, + 0x0d, 0x19, 0xf3, 0x27, 0xff, 0x03, 0xcb, 0x18, 0x56, 0xd9, 0x1d, 0xec, 0xbb, + 0xe5, 0x22, 0xf9, 0xf6, 0x14, 0x13, 0x7f, 0x0c, 0x1b, 0xb0, 0x0e, 0x19, 0x2c, + 0x2e, 0x03, 0x31, 0x0c, 0xff, 0x31, 0x11, 0x18, 0x03, 0x28, 0xde, 0x1b, 0xe4, + 0x1e, 0x1b, 0xfb, 0x10, 0xed, 0x0f, 0xff, 0x18, 0xd9, 0x1a, 0xde, 0xfa, 0xe7, + 0xb4, 0x30, 0xbe, 0x4f, 0x01, 0x20, 0x1a, 0x02, 0xfe, 0x61, 0x0e, 0x22, 0x1d, + 0x0e, 0x30, 0x38, 0xc0, 0xdd, 0x2c, 0xf5, 0xd1, 0x03, 0x2f, 0x51, 0x3f, 0xdd, + 0xdb, 0xfc, 0x13, 0x23, 0xc5, 0x07, 0x02, 0xa5, 0x20, 0x35, 0xf9, 0x0b, 0xdd, + 0xf9, 0x1a, 0xfc, 0x0e, 0xfb, 0x23, 0x20, 0x3f, 0x12, 0x1c, 0xe2, 0xff, 0xec, + 0xdf, 0xe5, 0xdb, 0x0a, 0x03, 0x16, 0xc1, 0x0e, 0xe0, 0xf3, 0x09, 0xfc, 0x0a, + 0xd9, 0x03, 0x7f, 0x06, 0x26, 0xfe, 0xfb, 0x06, 0xcd, 0xe9, 0x0f, 0x1e, 0xfa, + 0xe8, 0x18, 0xd5, 0xdf, 0x1b, 0x12, 0xe0, 0x1c, 0xe7, 0x16, 0x15, 0xb4, 0x03, + 0xf5, 0xca, 0xd4, 0x33, 0x0a, 0xf7, 0xfc, 0x31, 0xb2, 0xef, 0xf2, 0xf1, 0xf2, + 0xfe, 0xf3, 0xf9, 0xfd, 0xf6, 0xd4, 0x05, 0x10, 0x60, 0x48, 0x11, 0xd8, 0xf4, + 0x23, 0x08, 0xf4, 0xee, 0xe4, 0xc6, 0x22, 0x14, 0xdc, 0xfc, 0x06, 0xff, 0x18, + 0x0f, 0x1c, 0xf2, 0xdd, 0x30, 0x35, 0x53, 0x01, 0xd0, 0xfa, 0xdd, 0x1a, 0x0d, + 0x54, 0x09, 0xcf, 0x1e, 0xf4, 0x0d, 0xef, 0x02, 0x1a, 0xf0, 0x10, 0xef, 0x18, + 0xfc, 0x0a, 0x1a, 0xfc, 0x0a, 0xec, 0x0f, 0x2e, 0x01, 0xfa, 0x27, 0x19, 0xfd, + 0xef, 0x0f, 0xef, 0x3f, 0xf3, 0x04, 0xf7, 0x0b, 0x3d, 0x2e, 0xef, 0x02, 0xea, + 0xf8, 0xf1, 0xb5, 0x02, 0x3d, 0xb7, 0x0c, 0xc2, 0xf2, 0x24, 0x02, 0xc8, 0x4d, + 0xd7, 0x16, 0xee, 0x2c, 0x22, 0xa4, 0x21, 0x00, 0x0d, 0xe4, 0xc1, 0xff, 0x3b, + 0xf2, 0x18, 0x10, 0x7f, 0x27, 0xd9, 0xfd, 0x0b, 0x11, 0xfa, 0xac, 0xd7, 0x0e, + 0xd2, 0xc8, 0xbd, 0xf9, 0xd4, 0x1c, 0x4f, 0x48, 0xe4, 0xf1, 0x02, 0x2c, 0xab, + 0x3c, 0x0d, 0x97, 0xc9, 0xc2, 0xdb, 0xeb, 0xf6, 0x17, 0x36, 0xb7, 0x09, 0xfb, + 0xea, 0xfa, 0xad, 0xcf, 0xf9, 0xee, 0x2c, 0x38, 0x64, 0xb2, 0xb7, 0xe7, 0xf7, + 0xe4, 0xf6, 0x1b, 0x0f, 0xfb, 0x0a, 0xf4, 0x11, 0xc6, 0x0c, 0xfa, 0xa0, 0xec, + 0xf7, 0xe6, 0xc3, 0x21, 0xd7, 0xe1, 0xfe, 0x9e, 0xc9, 0x01, 0xef, 0x05, 0xbc, + 0xb4, 0x2a, 0x46, 0x42, 0xbc, 0xd7, 0xe9, 0xec, 0x17, 0xfc, 0x24, 0xff, 0x47, + 0x8f, 0x4f, 0xfc, 0xeb, 0xcd, 0xdc, 0xea, 0xec, 0x91, 0xe6, 0xee, 0x26, 0x9f, + 0xf3, 0x0e, 0xe2, 0x1e, 0x18, 0xa9, 0x56, 0xe2, 0x96, 0x3a, 0x02, 0xf9, 0xa0, + 0x21, 0x47, 0x51, 0x28, 0xd2, 0x0f, 0xa6, 0x86, 0x16, 0xf7, 0xec, 0xea, 0xa5, + 0xcf, 0x4b, 0x24, 0x4f, 0xfb, 0xc4, 0x43, 0x47, 0xf2, 0xd5, 0x31, 0xa4, 0x48, + 0xc0, 0xe5, 0xc5, 0xe9, 0x97, 0xa3, 0xbf, 0xe6, 0xed, 0x66, 0xf1, 0xff, 0x0e, + 0x6c, 0x42, 0x5c, 0xef, 0xe3, 0x25, 0x4e, 0xd3, 0xac, 0xc3, 0xf7, 0x25, 0x09, + 0xd3, 0x13, 0x02, 0xea, 0xd6, 0x29, 0x4e, 0xd5, 0x23, 0x35, 0xd0, 0xd8, 0xe8, + 0xc5, 0x3c, 0x81, 0xad, 0x38, 0x02, 0xa9, 0x98, 0xe8, 0xcd, 0x2e, 0xd7, 0xd5, + 0xb7, 0x0e, 0x48, 0x2b, 0x5a, 0x41, 0x57, 0x14, 0xc4, 0x10, 0xeb, 0x61, 0x16, + 0x1b, 0xa3, 0xfc, 0x33, 0xf7, 0xeb, 0x96, 0x24, 0xe9, 0xdf, 0x26, 0x05, 0x19, + 0xe3, 0xf2, 0x08, 0x4a, 0xdb, 0xbc, 0x08, 0x13, 0x0b, 0x81, 0x09, 0xf1, 0x04, + 0x05, 0x09, 0x1c, 0x56, 0xe2, 0x11, 0x0a, 0x0f, 0xc6, 0x54, 0xfd, 0x15, 0xcc, + 0x20, 0xfc, 0x18, 0xfb, 0x0a, 0xee, 0x39, 0x21, 0x35, 0xd4, 0xeb, 0x2b, 0xe1, + 0x2b, 0x11, 0x2e, 0xd9, 0x26, 0xdd, 0xc0, 0x11, 0xf3, 0x31, 0xe2, 0xeb, 0xf0, + 0xf1, 0xf9, 0xe7, 0xfa, 0x14, 0xd2, 0xe7, 0xf3, 0x1f, 0x28, 0x46, 0xf5, 0x36, + 0xcf, 0x14, 0xea, 0x01, 0x10, 0xb8, 0xcb, 0x0b, 0x17, 0xc6, 0xf2, 0xf0, 0xe2, + 0xf4, 0x31, 0xdf, 0x2d, 0x23, 0xf2, 0x02, 0x12, 0x0f, 0x44, 0x1f, 0xfa, 0x2f, + 0x08, 0x39, 0x22, 0xc6, 0xe3, 0xc5, 0x0b, 0x13, 0x02, 0xcf, 0xd8, 0x09, 0x12, + 0xc9, 0xd3, 0xec, 0x0c, 0xe3, 0xe7, 0x17, 0x39, 0x10, 0x27, 0x05, 0x1b, 0x1b, + 0x1c, 0xe8, 0x12, 0x13, 0x2a, 0xde, 0xec, 0xfb, 0xe5, 0xfd, 0x37, 0xe3, 0xcb, + 0x20, 0xe1, 0x2f, 0xc5, 0x20, 0xc2, 0x06, 0x29, 0x0e, 0xdf, 0x5b, 0xf6, 0xfc, + 0xcf, 0x55, 0xf3, 0x7e, 0xca, 0x0d, 0xfd, 0xd3, 0xbd, 0xd0, 0x04, 0x09, 0x99, + 0x30, 0xd9, 0x24, 0xc0, 0xf1, 0xe7, 0x4a, 0xfc, 0x6c, 0xf3, 0x01, 0xd4, 0xfa, + 0x1c, 0x5e, 0x20, 0xea, 0xc3, 0x06, 0xc9, 0x0a, 0x8a, 0x32, 0xe2, 0x2f, 0xf3, + 0x1f, 0x12, 0x39, 0x12, 0x12, 0xaa, 0x02, 0x3f, 0x51, 0xb5, 0x59, 0x1f, 0x32, + 0x13, 0x1a, 0x22, 0xc9, 0xf0, 0xff, 0xef, 0xb1, 0xd9, 0xc6, 0xdd, 0xf2, 0xfa, + 0x2e, 0x3a, 0x4f, 0xd4, 0x02, 0xc7, 0xcf, 0xf7, 0xcb, 0x12, 0x8f, 0x0a, 0x14, + 0xe5, 0x85, 0x0d, 0xbe, 0xd1, 0xa3, 0x22, 0x50, 0xa7, 0x4d, 0xec, 0xe0, 0x0b, + 0x24, 0xb0, 0x31, 0x4c, 0x17, 0xf7, 0x00, 0x8c, 0xe0, 0x7f, 0x1b, 0xe6, 0xdd, + 0xf5, 0x36, 0x04, 0xf7, 0x93, 0xef, 0x38, 0x4c, 0x03, 0x1b, 0x5f, 0xe9, 0x26, + 0x20, 0x14, 0xfb, 0xf1, 0x0a, 0xcf, 0xfe, 0x09, 0x05, 0xaa, 0x34, 0x21, 0xc4, + 0xcb, 0x09, 0xf3, 0xdc, 0xff, 0x7f, 0x0f, 0xda, 0x0e, 0x22, 0x23, 0x2f, 0xf7, + 0x11, 0xf9, 0x13, 0x18, 0x2d, 0xe0, 0x34, 0x34, 0x19, 0xe4, 0x0c, 0x27, 0xbd, + 0x08, 0xe0, 0xe8, 0xeb, 0x19, 0xff, 0x1e, 0x0c, 0xe9, 0xfc, 0x49, 0x07, 0x0c, + 0x10, 0x15, 0xdb, 0x20, 0x02, 0x26, 0x07, 0x1c, 0x25, 0x23, 0xd0, 0x10, 0x12, + 0x46, 0xe4, 0xc8, 0x02, 0xdf, 0x0e, 0x14, 0xfb, 0xe9, 0xf7, 0x1a, 0x0b, 0x0b, + 0x22, 0x02, 0xf9, 0x0f, 0xf9, 0x24, 0x0a, 0x27, 0x10, 0x0f, 0x23, 0x1a, 0x87, + 0x01, 0xf4, 0xde, 0x10, 0x06, 0x04, 0x1b, 0xe9, 0xdd, 0xe2, 0x0c, 0x19, 0xc5, + 0x0a, 0x0b, 0x19, 0xe6, 0x20, 0x35, 0xf3, 0x22, 0xf7, 0xff, 0x39, 0x1a, 0x06, + 0xed, 0x21, 0xf7, 0xd3, 0x09, 0x22, 0x05, 0xe5, 0xf0, 0x0a, 0xf6, 0xfe, 0x0a, + 0x13, 0x05, 0x51, 0x19, 0x10, 0x34, 0xfd, 0x44, 0xf4, 0xe3, 0xf8, 0xf2, 0xf4, + 0x30, 0xe9, 0xf8, 0x19, 0xfa, 0x0a, 0xdb, 0x0e, 0x0a, 0xc9, 0xff, 0xe7, 0xdd, + 0x28, 0xf3, 0x05, 0x42, 0xe6, 0xf3, 0x18, 0xf9, 0xe9, 0xf4, 0x08, 0x20, 0x1d, + 0x20, 0x39, 0xe8, 0x11, 0x07, 0xf7, 0xd1, 0x3a, 0xee, 0xdc, 0xfa, 0x35, 0xf3, + 0x0d, 0x17, 0x12, 0xf9, 0x1c, 0xfa, 0x09, 0x06, 0x05, 0x17, 0x27, 0x00, 0x21, + 0xcb, 0x0c, 0xff, 0x20, 0xc7, 0x03, 0xf4, 0x0a, 0x20, 0x15, 0xe1, 0x26, 0x02, + 0xd9, 0x12, 0x0e, 0x41, 0xfc, 0x24, 0x01, 0xe9, 0x24, 0xeb, 0x05, 0x19, 0x1b, + 0x11, 0xd4, 0x27, 0xe1, 0x08, 0x07, 0xfb, 0xe3, 0xe1, 0x20, 0x1e, 0xfd, 0xe6, + 0xc1, 0x1d, 0xda, 0xe9, 0xd8, 0x03, 0x08, 0xc1, 0x19, 0x0f, 0x33, 0xde, 0xf3, + 0x17, 0xe9, 0x0b, 0x0d, 0x04, 0x7f, 0x1d, 0xfd, 0x05, 0x36, 0xb6, 0xd1, 0x22, + 0x07, 0x5e, 0x1e, 0xeb, 0xfc, 0x3c, 0xd1, 0x15, 0x0a, 0x1b, 0x11, 0xd7, 0x29, + 0x19, 0x3d, 0xa9, 0x20, 0xda, 0xc0, 0xeb, 0xa3, 0x20, 0xdf, 0xe0, 0x8f, 0xee, + 0x0e, 0xf8, 0xf0, 0xfb, 0x16, 0xed, 0x43, 0x0b, 0xb0, 0x1c, 0x06, 0x85, 0x26, + 0xe8, 0x23, 0xc4, 0x65, 0x11, 0x26, 0xf4, 0x2d, 0xfa, 0x11, 0xd1, 0xc9, 0x42, + 0xdd, 0x1f, 0xbe, 0xae, 0x0b, 0x03, 0x52, 0x07, 0xc1, 0xd7, 0x25, 0x23, 0x07, + 0x2c, 0xd5, 0x0b, 0x1a, 0x14, 0x3b, 0xd8, 0x13, 0x31, 0x37, 0x0d, 0x1d, 0x25, + 0xda, 0xe8, 0x03, 0x17, 0xf9, 0x7f, 0x03, 0x01, 0x30, 0x29, 0x53, 0x56, 0xf6, + 0x18, 0x9b, 0xde, 0xe9, 0xc3, 0xed, 0xe6, 0x1a, 0x9e, 0x37, 0xda, 0x0f, 0xcb, + 0x2c, 0x21, 0xd8, 0x42, 0x16, 0x00, 0x22, 0x36, 0x45, 0x18, 0xbf, 0xff, 0x0d, + 0x25, 0xff, 0xaf, 0xf8, 0xef, 0xdc, 0x1c, 0x9f, 0x05, 0xeb, 0x26, 0xe2, 0xdd, + 0x3c, 0x02, 0x06, 0xfa, 0xe9, 0xf7, 0xa9, 0x15, 0x07, 0xf8, 0xf7, 0x0c, 0xfe, + 0xe1, 0xff, 0x24, 0x9e, 0xd7, 0xbe, 0xdf, 0x0a, 0xf6, 0xca, 0x05, 0xf6, 0x15, + 0xe7, 0xf2, 0x3b, 0x0f, 0xdb, 0x2c, 0x27, 0x98, 0x13, 0x74, 0xff, 0xf7, 0x11, + 0xde, 0x40, 0x2d, 0xeb, 0x02, 0xe2, 0xe7, 0xea, 0xdf, 0x00, 0x32, 0xea, 0xd9, + 0xfc, 0xc6, 0xfc, 0xf5, 0xdd, 0x02, 0xd7, 0xd7, 0xe1, 0x23, 0xe5, 0xbf, 0xcd, + 0x64, 0x4a, 0xe4, 0xf3, 0x7f, 0x1d, 0x05, 0x96, 0x53, 0x22, 0xe8, 0xb6, 0xc2, + 0x18, 0x23, 0x1a, 0x64, 0xec, 0x03, 0xe5, 0xcc, 0x4e, 0x6d, 0xf5, 0x5f, 0xf0, + 0x86, 0x00, 0xc0, 0xdd, 0x28, 0x15, 0x47, 0x1a, 0x21, 0x00, 0xdf, 0x0c, 0xd2, + 0xf5, 0x0b, 0xd8, 0xd5, 0x37, 0x2c, 0xf6, 0x1a, 0x15, 0xce, 0xe4, 0xef, 0xf9, + 0x1f, 0x08, 0xd1, 0x41, 0x0f, 0xd1, 0x44, 0xe5, 0x25, 0x36, 0x0e, 0x0c, 0xf6, + 0xf6, 0xf2, 0x2c, 0x22, 0xb1, 0x1d, 0x15, 0x21, 0x5b, 0x25, 0x11, 0x75, 0xba, + 0xd9, 0x10, 0x1e, 0xf7, 0x01, 0xdd, 0xf6, 0x7f, 0xb7, 0xfc, 0x12, 0x1e, 0x02, + 0xcb, 0xeb, 0xf0, 0x00, 0xea, 0xbd, 0x35, 0xbc, 0x1f, 0x10, 0x14, 0xd2, 0x07, + 0xdc, 0xce, 0xc6, 0x02, 0x01, 0x21, 0x50, 0xc8, 0xb7, 0xf2, 0x23, 0xcd, 0xce, + 0x02, 0xb8, 0x4c, 0x01, 0xbf, 0x2e, 0xea, 0x1e, 0x52, 0x3e, 0xc5, 0xfd, 0x37, + 0x07, 0x2b, 0x0f, 0x14, 0xaf, 0xfd, 0x26, 0xdc, 0xe4, 0xf8, 0x1a, 0x0b, 0xff, + 0x65, 0x02, 0x00, 0x35, 0xaf, 0x33, 0xd5, 0x30, 0x62, 0x11, 0x04, 0xe2, 0xe3, + 0xda, 0x39, 0x3b, 0x2e, 0x1f, 0x47, 0x55, 0x39, 0x0c, 0xf8, 0x22, 0x1e, 0x2d, + 0xce, 0x75, 0x07, 0x02, 0x0a, 0xfa, 0x43, 0x58, 0x15, 0xcb, 0xf9, 0x3f, 0xcb, + 0xdc, 0xe0, 0xf0, 0x04, 0x46, 0xbc, 0xca, 0x0f, 0xf9, 0x04, 0xe7, 0x25, 0x15, + 0xb8, 0xe1, 0xd8, 0x14, 0x24, 0x49, 0x0e, 0x2c, 0xe1, 0x98, 0x1c, 0xdb, 0xfe, + 0x34, 0xe8, 0xe7, 0xea, 0x16, 0x0f, 0x00, 0x49, 0x7f, 0x34, 0x41, 0xe3, 0x0b, + 0x0e, 0x49, 0x63, 0x45, 0xf3, 0xe8, 0xe1, 0xcc, 0xcc, 0xbd, 0x49, 0x07, 0xcc, + 0xee, 0xf4, 0x53, 0x02, 0x5e, 0x23, 0x31, 0xe0, 0xf8, 0xfb, 0xf5, 0xe1, 0xeb, + 0xd7, 0xe8, 0x02, 0x2c, 0x30, 0xcd, 0x27, 0x31, 0xcb, 0xf0, 0xe6, 0x03, 0xf9, + 0x67, 0xee, 0xd8, 0x36, 0xb9, 0x02, 0x4c, 0xdf, 0xae, 0xd0, 0xfc, 0xf8, 0xc5, + 0x50, 0xde, 0x46, 0x00, 0xf9, 0xdd, 0xc5, 0x68, 0x12, 0xfc, 0xe2, 0xff, 0xee, + 0xe4, 0xf2, 0xec, 0xf9, 0x77, 0xc7, 0x7f, 0x2a, 0x1e, 0xf2, 0xd0, 0x45, 0x9b, + 0x61, 0xff, 0x33, 0xdd, 0x20, 0xaf, 0xed, 0x6a, 0x03, 0x1a, 0xe2, 0x5a, 0x08, + 0x07, 0x50, 0xc6, 0xd8, 0x1f, 0x02, 0xc5, 0xe6, 0xe4, 0xb3, 0xfe, 0x0f, 0x1f, + 0xe0, 0x02, 0xf5, 0xd1, 0x1e, 0xfb, 0xa4, 0x07, 0x1a, 0xcb, 0x34, 0xcf, 0xf6, + 0x16, 0x38, 0x1b, 0x19, 0x2e, 0x2d, 0xe7, 0xc5, 0xca, 0xe3, 0x19, 0x10, 0x03, + 0xdc, 0xd1, 0xfd, 0x35, 0x0e, 0x0c, 0xb0, 0xe2, 0x5a, 0xdd, 0xf3, 0x81, 0xee, + 0xe0, 0x18, 0xea, 0xe5, 0x42, 0x6f, 0x07, 0xf9, 0xa2, 0x6e, 0xd4, 0x36, 0x14, + 0x49, 0xd0, 0x4f, 0x0b, 0xe6, 0xd6, 0xbf, 0x0b, 0xea, 0x13, 0x1a, 0xc6, 0x08, + 0x1c, 0x1d, 0xb3, 0xfe, 0x0a, 0xe7, 0x23, 0xe6, 0xd0, 0xc7, 0xc9, 0xe7, 0xf3, + 0x43, 0x1b, 0x02, 0x66, 0xee, 0x02, 0x5b, 0xf3, 0x31, 0x0a, 0x5b, 0xc6, 0xef, + 0xdb, 0xd5, 0x35, 0xec, 0xf8, 0x3a, 0xb5, 0xf9, 0x25, 0xfc, 0x40, 0xa3, 0x24, + 0x0f, 0xfb, 0xd4, 0x13, 0xf6, 0xee, 0xb2, 0x2f, 0xef, 0x8b, 0xf5, 0x28, 0x69, + 0xef, 0xc4, 0xdb, 0x03, 0xfe, 0xe8, 0x00, 0x01, 0x3e, 0x1b, 0x2a, 0x3f, 0x2a, + 0x11, 0x0b, 0x03, 0xfa, 0xdc, 0xef, 0x1d, 0x47, 0xd1, 0xfe, 0x23, 0x14, 0x0b, + 0x0e, 0x2c, 0xd5, 0x4d, 0x0e, 0xcc, 0xd0, 0xed, 0x2e, 0x1d, 0x0e, 0x11, 0xfa, + 0xfb, 0xc4, 0xea, 0x33, 0x02, 0x36, 0x1e, 0xd4, 0xc5, 0x0c, 0xdf, 0xd8, 0x25, + 0xc3, 0xfa, 0xcc, 0x2c, 0x39, 0xc0, 0xea, 0xee, 0x06, 0xda, 0x27, 0x31, 0x1e, + 0x19, 0xff, 0x00, 0x0c, 0xf5, 0x12, 0xbe, 0x06, 0xd1, 0x5d, 0x13, 0xe6, 0xcc, + 0xc9, 0xf9, 0x6c, 0xf7, 0xe7, 0x57, 0xcc, 0x03, 0xd8, 0x3a, 0xb4, 0x7f, 0x1b, + 0xf7, 0xd3, 0x1f, 0xfe, 0xcc, 0xeb, 0xf6, 0x34, 0x12, 0xd0, 0xcd, 0x4b, 0xd8, + 0xeb, 0x11, 0x0d, 0xfd, 0x21, 0xf9, 0xd2, 0x90, 0x25, 0x03, 0xe8, 0x01, 0x1a, + 0x0c, 0x22, 0x29, 0x5e, 0xdd, 0xf0, 0xc4, 0x3e, 0xe1, 0xaf, 0x09, 0x1c, 0x03, + 0x4a, 0x1e, 0x27, 0x17, 0xe9, 0x35, 0xe4, 0xfb, 0xe9, 0x11, 0xc6, 0xcf, 0x02, + 0xb8, 0x35, 0x4d, 0x5f, 0xe2, 0xd9, 0x13, 0xff, 0x5a, 0x14, 0x15, 0x0f, 0xd3, + 0xca, 0xdc, 0xf9, 0x21, 0x1d, 0x48, 0xe4, 0x40, 0x20, 0xda, 0xce, 0xf0, 0x38, + 0xfe, 0xc9, 0x08, 0xdf, 0x13, 0x16, 0x27, 0xfe, 0xb1, 0xf0, 0xde, 0xa1, 0x1c, + 0xd9, 0x04, 0xf2, 0xe0, 0xf7, 0xe9, 0xd9, 0x30, 0x1b, 0x01, 0xde, 0xc4, 0xf8, + 0xe2, 0xd2, 0x13, 0xf5, 0x47, 0x07, 0xec, 0x57, 0xe7, 0xd2, 0xf6, 0xe3, 0xb5, + 0xfc, 0xbc, 0x00, 0x36, 0xef, 0x7f, 0x27, 0x43, 0xc8, 0xb1, 0x3a, 0xed, 0xd8, + 0xf0, 0x1b, 0x2e, 0xe4, 0x34, 0x4c, 0xfd, 0xf0, 0x0e, 0x48, 0xd9, 0x18, 0x26, + 0x2d, 0x04, 0xbd, 0xad, 0xd7, 0xbf, 0x08, 0xe4, 0x1e, 0x0c, 0xff, 0x6b, 0x39, + 0xe9, 0x25, 0x25, 0xf6, 0xf2, 0xe2, 0x00, 0x1f, 0xce, 0x53, 0xf6, 0x02, 0xf5, + 0xd2, 0x0b, 0xf9, 0x19, 0xfb, 0x10, 0xfa, 0xdc, 0xd7, 0xfa, 0xf9, 0x0e, 0xf8, + 0xdc, 0x05, 0x0a, 0x20, 0x12, 0x12, 0xf8, 0x1b, 0x39, 0x36, 0x0b, 0xc5, 0xf9, + 0x12, 0x01, 0xb0, 0xa3, 0xd3, 0xcc, 0x03, 0xef, 0x3e, 0x10, 0x28, 0x35, 0x14, + 0x34, 0x17, 0x10, 0xe5, 0x59, 0x2b, 0xfb, 0xcb, 0xe8, 0x06, 0xe6, 0xf9, 0xd8, + 0xd2, 0xf9, 0xa0, 0xe6, 0x99, 0x16, 0xf5, 0x59, 0x47, 0xbd, 0x3c, 0xd6, 0xda, + 0x02, 0xf9, 0x7f, 0xe0, 0xc6, 0xfe, 0xe4, 0x11, 0xc8, 0x0b, 0x19, 0xeb, 0x27, + 0x0a, 0x1e, 0xdd, 0x1a, 0x06, 0x0c, 0x0a, 0x10, 0xfa, 0x36, 0x1e, 0xbe, 0xb8, + 0x9b, 0x16, 0x0f, 0xcc, 0x0c, 0x00, 0x41, 0x1d, 0x44, 0x1a, 0x10, 0xf4, 0xff, + 0x51, 0xfc, 0x23, 0x37, 0xfd, 0xe0, 0x20, 0x2a, 0xe5, 0x2b, 0x4e, 0xf6, 0x09, + 0x3f, 0x1f, 0xeb, 0x0b, 0xe5, 0xe3, 0xcd, 0xd5, 0xb3, 0x15, 0x39, 0x22, 0x95, + 0xd7, 0x32, 0xb2, 0xcc, 0x19, 0xe2, 0x28, 0xd2, 0x55, 0xd7, 0x41, 0x81, 0x44, + 0x0c, 0xfa, 0x22, 0xf5, 0xd9, 0xdd, 0xe9, 0xd9, 0x1b, 0x17, 0x79, 0x96, 0x24, + 0x04, 0x16, 0x19, 0x19, 0xd2, 0x0b, 0xde, 0xce, 0xbb, 0xc9, 0xc2, 0x05, 0x20, + 0x20, 0x0b, 0xce, 0xe6, 0xe4, 0x0c, 0xdd, 0x06, 0xd1, 0x18, 0x0b, 0xfe, 0xf3, + 0xe6, 0x08, 0xf6, 0xeb, 0x92, 0x09, 0xd4, 0x01, 0x14, 0x54, 0x4c, 0x4b, 0x0f, + 0x27, 0x21, 0x32, 0xea, 0xb4, 0xc3, 0x11, 0xcc, 0xc9, 0xf9, 0x19, 0xd3, 0x6a, + 0x09, 0x2b, 0xe2, 0xf7, 0x0f, 0x09, 0x84, 0xc8, 0x64, 0xb1, 0xdb, 0xf7, 0x51, + 0x1e, 0xe5, 0x6a, 0xdf, 0x1e, 0xf4, 0xad, 0x0f, 0xb6, 0x00, 0xea, 0xde, 0x12, + 0x7b, 0xab, 0xdd, 0x39, 0x19, 0xf2, 0x90, 0x30, 0x1b, 0xe4, 0x3d, 0x39, 0x3b, + 0x3b, 0x08, 0x0a, 0xe6, 0xd0, 0x47, 0x01, 0xcf, 0xf7, 0x04, 0xd7, 0x22, 0x9f, + 0xb9, 0x34, 0xdd, 0x81, 0x33, 0x16, 0xda, 0x18, 0x2e, 0x2d, 0xec, 0x1b, 0xf3, + 0xf2, 0xfe, 0xd4, 0x00, 0xf9, 0xc1, 0x4f, 0xd7, 0xff, 0xfe, 0xa4, 0x1a, 0x05, + 0x19, 0xfb, 0xfc, 0x04, 0x15, 0xff, 0xf9, 0xe9, 0x12, 0xfe, 0x02, 0x0e, 0x0f, + 0x06, 0x2f, 0xc1, 0xe7, 0xbb, 0xbe, 0xbf, 0xd7, 0xfa, 0xff, 0xd9, 0xd9, 0xf9, + 0xfa, 0xfd, 0xf9, 0xcd, 0x09, 0xe4, 0xfc, 0xf2, 0x2a, 0x23, 0x20, 0xf6, 0xf2, + 0xb2, 0x55, 0xe5, 0xeb, 0x29, 0xf3, 0xef, 0x17, 0x08, 0xf9, 0x0a, 0x20, 0xfe, + 0x05, 0x3a, 0x43, 0x1b, 0xe0, 0x2b, 0x23, 0x00, 0x16, 0xf4, 0x2d, 0x31, 0x00, + 0x0e, 0xf7, 0x31, 0x39, 0x39, 0x39, 0xef, 0x14, 0x08, 0x32, 0x2e, 0x37, 0xf6, + 0xf9, 0xe3, 0xcb, 0xef, 0xa9, 0xcf, 0x0f, 0xd8, 0xea, 0x97, 0xfa, 0xf4, 0x14, + 0x1d, 0xd5, 0xd9, 0xef, 0xda, 0x38, 0xed, 0x0d, 0xf9, 0x2d, 0xd7, 0xf5, 0xd8, + 0x2b, 0xd4, 0x08, 0xe2, 0x32, 0xfa, 0x4a, 0x7f, 0x2a, 0x3f, 0xe1, 0x19, 0xd9, + 0xef, 0xc0, 0x02, 0x3a, 0x25, 0x2b, 0xe8, 0xc1, 0xa6, 0x30, 0x06, 0xc7, 0x22, + 0xf4, 0x07, 0xea, 0x19, 0x1c, 0x0c, 0x16, 0xe1, 0x30, 0x43, 0x1e, 0xf2, 0xfb, + 0xe2, 0xed, 0x4d, 0x49, 0xb9, 0xb9, 0x9d, 0xd2, 0x27, 0xf7, 0xfb, 0x20, 0xba, + 0x19, 0xdb, 0x22, 0xe6, 0x1f, 0x2b, 0xf2, 0x35, 0x2f, 0xd2, 0x05, 0xd3, 0x27, + 0xef, 0x12, 0xe5, 0x1b, 0xdd, 0x0e, 0xdf, 0xd6, 0xd0, 0xf6, 0xf8, 0xe4, 0xc6, + 0xd0, 0x62, 0x16, 0xd7, 0xc9, 0x1e, 0x17, 0xc9, 0x04, 0x30, 0xd7, 0x04, 0x0e, + 0x02, 0xf1, 0x06, 0x09, 0x01, 0x0d, 0x3c, 0xed, 0x05, 0x0b, 0xaf, 0xca, 0x04, + 0x09, 0xe1, 0x19, 0x06, 0x36, 0x19, 0xe0, 0xe8, 0x06, 0xcb, 0xc4, 0xf2, 0x40, + 0x08, 0xba, 0x4e, 0xfa, 0x93, 0xd6, 0x9d, 0x05, 0x24, 0xa4, 0x04, 0x50, 0x1c, + 0xe0, 0x54, 0x23, 0xd6, 0xbc, 0x66, 0xc7, 0x57, 0x71, 0xfb, 0x59, 0x1e, 0x59, + 0x0d, 0xec, 0xd3, 0xe6, 0x0a, 0x01, 0x57, 0xb5, 0x30, 0xe4, 0xd8, 0x40, 0x1a, + 0x39, 0xd8, 0x50, 0xf3, 0xe6, 0x12, 0x20, 0xea, 0x4b, 0xf9, 0x2a, 0x0a, 0xfc, + 0x29, 0xe1, 0xa1, 0x4d, 0x2b, 0x6e, 0x19, 0x22, 0x46, 0x1a, 0xc4, 0xe5, 0xf6, + 0xce, 0x43, 0xed, 0x2e, 0xe1, 0xe0, 0x2a, 0x41, 0xd4, 0xb4, 0xef, 0xe1, 0x13, + 0x2c, 0x36, 0xd4, 0xef, 0xdc, 0x46, 0x30, 0x4a, 0x03, 0xec, 0x2a, 0xdc, 0xaa, + 0xc6, 0x64, 0x4d, 0xf9, 0xa1, 0x15, 0xbb, 0x1f, 0x93, 0x01, 0x17, 0x07, 0xf7, + 0xab, 0x81, 0x65, 0x23, 0xf6, 0x58, 0x0b, 0x3e, 0x28, 0xc7, 0x92, 0x18, 0x32, + 0x4e, 0xec, 0xf1, 0x20, 0xe5, 0xb8, 0xae, 0xff, 0x5d, 0xd4, 0x57, 0x59, 0x46, + 0xca, 0x15, 0x42, 0xe5, 0x6f, 0x02, 0x40, 0xc2, 0xd1, 0xe1, 0xc7, 0xdc, 0x00, + 0x00, 0xed, 0xaf, 0xea, 0x2f, 0xc7, 0xdb, 0x37, 0xcd, 0x1a, 0x05, 0xd1, 0xe9, + 0xf5, 0x0a, 0xd1, 0x11, 0x6a, 0x2a, 0x30, 0x1e, 0xc8, 0x5c, 0xab, 0x1e, 0x6c, + 0xd1, 0x7a, 0x22, 0xfb, 0xea, 0x58, 0x08, 0x1c, 0x7f, 0x11, 0xe8, 0xdc, 0xc6, + 0xb8, 0x22, 0x98, 0x17, 0xc0, 0xd9, 0xb3, 0x07, 0x02, 0x57, 0xe0, 0xf4, 0x1b, + 0xa9, 0xfa, 0x39, 0xf4, 0xef, 0x23, 0xa9, 0x2d, 0x4e, 0x20, 0xb9, 0x0b, 0xda, + 0x38, 0xbb, 0x99, 0xf7, 0x18, 0xd7, 0xd4, 0x6a, 0x1d, 0x53, 0x89, 0x2c, 0xa7, + 0xcb, 0xf1, 0x04, 0xd9, 0x65, 0xfb, 0x64, 0x18, 0x08, 0xfc, 0xb5, 0x1e, 0x1b, + 0xda, 0x15, 0xb7, 0xe2, 0x18, 0x2f, 0x01, 0x22, 0xc8, 0x20, 0x3e, 0x5c, 0x8e, + 0x1f, 0xea, 0xcd, 0x4a, 0x3b, 0xe3, 0x74, 0x7b, 0x04, 0x93, 0xe1, 0x20, 0xf1, + 0x3a, 0xe5, 0xe8, 0xf5, 0xa6, 0x16, 0x60, 0xde, 0x27, 0xe5, 0xed, 0xf9, 0xbb, + 0x19, 0x20, 0xc6, 0x0f, 0x7c, 0x23, 0xd2, 0xe5, 0x0f, 0x03, 0xd9, 0xda, 0xf2, + 0xdc, 0xde, 0xcc, 0x26, 0x0b, 0x27, 0xdf, 0x19, 0x05, 0xff, 0x49, 0xc9, 0x10, + 0x28, 0x0b, 0xdd, 0xdd, 0x02, 0x01, 0xff, 0xbe, 0xd4, 0x34, 0x09, 0x0a, 0xd8, + 0xe3, 0x00, 0xc6, 0xf6, 0x0a, 0x1f, 0xee, 0xd9, 0xe5, 0x2c, 0x43, 0xe5, 0x14, + 0xec, 0x05, 0x9c, 0x0a, 0xd3, 0xfc, 0x0a, 0xd7, 0x26, 0x3e, 0x24, 0xda, 0xd0, + 0xe2, 0x4f, 0x0c, 0xd8, 0xb7, 0x60, 0x9e, 0xf8, 0xf9, 0xe5, 0x4a, 0xd0, 0xd1, + 0x69, 0x00, 0x9d, 0xb9, 0xb9, 0x28, 0xec, 0xd9, 0x1c, 0x19, 0xda, 0x71, 0xab, + 0x33, 0x7e, 0x41, 0x05, 0xeb, 0x03, 0x0c, 0x5c, 0xf7, 0x14, 0xa1, 0xd5, 0x7f, + 0xe6, 0xd2, 0x2b, 0x5f, 0xfe, 0xc0, 0xc7, 0xf6, 0xe9, 0xdc, 0xf8, 0x18, 0xd6, + 0x62, 0xe2, 0xd6, 0x2d, 0xcc, 0xd7, 0xc3, 0x7f, 0xf5, 0xd1, 0x0c, 0xee, 0x57, + 0xde, 0xbd, 0x09, 0xff, 0xcc, 0xb0, 0xc6, 0xfd, 0xad, 0xf8, 0x4a, 0xf8, 0xf4, + 0xe2, 0xd4, 0x73, 0x39, 0x45, 0xf4, 0x17, 0x11, 0xf4, 0x03, 0xfd, 0x3b, 0x02, + 0xf9, 0x15, 0xde, 0x9b, 0xeb, 0xe6, 0xeb, 0xdd, 0xe1, 0x4a, 0x17, 0xd7, 0x0b, + 0x2b, 0xe3, 0x08, 0xfc, 0x04, 0x36, 0xfe, 0x55, 0xa9, 0x16, 0x0f, 0x18, 0xfb, + 0x0a, 0xf6, 0x07, 0x3d, 0xec, 0x1b, 0x19, 0xfa, 0xbe, 0xf3, 0x2d, 0x36, 0x01, + 0x9a, 0x09, 0x33, 0xc2, 0xe8, 0xc6, 0x28, 0xec, 0x32, 0xac, 0xde, 0x1c, 0xbe, + 0x29, 0xcd, 0xde, 0x2d, 0x2a, 0x43, 0xe2, 0x3f, 0xe7, 0xc9, 0xf1, 0xf1, 0xcf, + 0x32, 0x00, 0x0b, 0xea, 0x39, 0x27, 0xeb, 0xd8, 0xef, 0x06, 0x32, 0xd6, 0xcc, + 0x08, 0xe6, 0xe1, 0xe8, 0xc4, 0x11, 0xe7, 0x0c, 0x0d, 0x1d, 0xe0, 0x0b, 0xe0, + 0x1f, 0x12, 0xf3, 0x47, 0xf5, 0xc2, 0x22, 0xd0, 0xea, 0x0f, 0xbd, 0x76, 0xdf, + 0x31, 0x1e, 0x00, 0xca, 0x26, 0x5c, 0xc1, 0x1f, 0x1b, 0x34, 0x08, 0x22, 0x15, + 0x00, 0x41, 0x2b, 0xb8, 0xf6, 0x42, 0xf9, 0x2b, 0xee, 0xcb, 0x03, 0x6f, 0x1d, + 0xc2, 0xd5, 0x0c, 0xe0, 0x28, 0xc1, 0x26, 0xc1, 0x2a, 0x4a, 0xc9, 0x35, 0xfe, + 0x09, 0xe2, 0xdf, 0xff, 0xe6, 0x2a, 0x08, 0xde, 0x42, 0xf1, 0x1b, 0x2b, 0x2a, + 0x19, 0xc0, 0x23, 0x08, 0x10, 0xbd, 0xe1, 0x88, 0x16, 0xee, 0xfa, 0x21, 0xce, + 0x40, 0xd0, 0xc3, 0xf2, 0x46, 0xd5, 0x05, 0x13, 0xed, 0x0b, 0x00, 0x67, 0x76, + 0xa6, 0x67, 0xfc, 0x64, 0x10, 0x23, 0xdf, 0xf7, 0x11, 0x36, 0x11, 0x0c, 0x2e, + 0xf5, 0xd7, 0x3c, 0xf6, 0x49, 0xdd, 0x58, 0x6b, 0x11, 0x7f, 0x29, 0x7c, 0xbf, + 0xe3, 0x3d, 0x27, 0xff, 0xbb, 0x1f, 0x00, 0xbb, 0xff, 0xdd, 0xdf, 0x0b, 0x7f, + 0x0c, 0x0d, 0x44, 0xfe, 0x67, 0x39, 0xec, 0xb7, 0x53, 0x54, 0xee, 0xcc, 0xde, + 0x39, 0xe9, 0x14, 0xfe, 0x69, 0x3c, 0xc0, 0xc0, 0x33, 0x26, 0xf6, 0x17, 0x11, + 0xcc, 0xcd, 0x66, 0xdd, 0xdf, 0x3f, 0x15, 0xf3, 0x02, 0x44, 0x29, 0x1d, 0x2c, + 0xa1, 0xd0, 0xc6, 0x03, 0x00, 0x0e, 0x66, 0x39, 0x13, 0x32, 0x68, 0xe5, 0x30, + 0x01, 0xfd, 0x56, 0xce, 0xfd, 0x08, 0x01, 0x18, 0x1b, 0x20, 0x08, 0x11, 0x4c, + 0xb2, 0x32, 0x01, 0xda, 0x0a, 0x00, 0x07, 0xbd, 0x2c, 0xdf, 0xe6, 0x35, 0xc7, + 0x22, 0xbd, 0xe7, 0x1c, 0xec, 0xc7, 0xe3, 0x56, 0x18, 0xd5, 0xfc, 0xe4, 0xe4, + 0xde, 0x45, 0x1f, 0x42, 0x00, 0x22, 0xf5, 0xf8, 0x9a, 0x64, 0x5c, 0x16, 0xf2, + 0xe2, 0xe4, 0x22, 0xf1, 0x23, 0x0a, 0x00, 0x31, 0x45, 0x21, 0xb8, 0x95, 0x1b, + 0xdb, 0x42, 0xf3, 0x4c, 0xa7, 0xc8, 0x16, 0xe2, 0xf6, 0xfc, 0xfa, 0xe6, 0xf7, + 0xd2, 0xe8, 0x0f, 0xcd, 0xe8, 0xff, 0x02, 0x09, 0xec, 0xe7, 0xf3, 0xe7, 0xc1, + 0xbd, 0xf6, 0xf7, 0xe0, 0xbd, 0x33, 0xf1, 0xfa, 0xc4, 0x16, 0x3e, 0x38, 0x1c, + 0x06, 0x11, 0xef, 0xd5, 0x37, 0xd5, 0x0a, 0x29, 0xd2, 0x06, 0x22, 0x3d, 0x0d, + 0x08, 0x44, 0x1e, 0x10, 0x14, 0x0f, 0xd4, 0x0e, 0x28, 0xec, 0x41, 0x0f, 0xdc, + 0xf0, 0xec, 0x0d, 0x08, 0xe8, 0xb0, 0x62, 0x0e, 0x25, 0x00, 0x1a, 0x00, 0x24, + 0xcc, 0xd7, 0xfb, 0xe6, 0x22, 0xfe, 0xd0, 0x1c, 0xde, 0xf3, 0xf5, 0xf6, 0x14, + 0xda, 0xe3, 0xfb, 0x06, 0xe4, 0x0b, 0x1d, 0x21, 0x21, 0x22, 0x3d, 0xe4, 0x15, + 0xf5, 0x34, 0x29, 0xca, 0x1a, 0xeb, 0x0b, 0xe2, 0x1b, 0xeb, 0x21, 0xd9, 0x0a, + 0x1c, 0xf7, 0x12, 0xfd, 0xe8, 0xcb, 0x15, 0xe1, 0xd3, 0x81, 0x02, 0x56, 0xe8, + 0xd4, 0x06, 0xd3, 0xf1, 0xf7, 0x09, 0xf2, 0xd6, 0xb8, 0x12, 0x43, 0x9b, 0x0d, + 0xf3, 0x04, 0x16, 0xca, 0xaf, 0xf8, 0x44, 0x23, 0x35, 0xf8, 0xe8, 0xea, 0x3d, + 0x00, 0x07, 0xf7, 0xe5, 0xed, 0xd4, 0xf7, 0xf8, 0x13, 0x0f, 0x2f, 0x0e, 0xd8, + 0x14, 0xe7, 0x0d, 0xd6, 0x2f, 0x3d, 0x37, 0xe8, 0xec, 0xe8, 0xb2, 0x0e, 0xf5, + 0x24, 0xe0, 0x07, 0x08, 0xe8, 0x18, 0x01, 0x10, 0x51, 0x23, 0xde, 0xe8, 0xf9, + 0x02, 0x12, 0x69, 0x05, 0x96, 0xdd, 0xda, 0xdf, 0xe2, 0x1e, 0xc4, 0xd3, 0xf1, + 0xe0, 0xd9, 0x7f, 0x23, 0x07, 0xf2, 0x14, 0x16, 0x28, 0x3d, 0x28, 0xff, 0x01, + 0x19, 0xef, 0x32, 0xf2, 0xd8, 0xde, 0x30, 0xd3, 0x08, 0x2f, 0xf2, 0xd6, 0x2f, + 0xdc, 0xfa, 0xef, 0x05, 0x18, 0xcc, 0xf1, 0x09, 0x43, 0x0f, 0x38, 0xfe, 0xe3, + 0xd5, 0xec, 0x07, 0x11, 0x0b, 0x1c, 0xed, 0x07, 0x1d, 0xdf, 0x07, 0x4d, 0xc9, + 0x21, 0xf7, 0xad, 0x4f, 0x05, 0x20, 0x0f, 0x25, 0xe5, 0xee, 0xf4, 0x1b, 0xe4, + 0x27, 0x5a, 0xd0, 0x09, 0xe0, 0xe5, 0xfd, 0xb3, 0xf8, 0x02, 0x47, 0xad, 0xf7, + 0xd2, 0x55, 0x28, 0x26, 0xd5, 0x3a, 0x12, 0xd7, 0xd0, 0x02, 0x00, 0x51, 0x81, + 0xec, 0xe5, 0xc4, 0xe4, 0xf8, 0x2f, 0x3c, 0xc9, 0xf7, 0x2b, 0xf9, 0xed, 0x30, + 0xf1, 0x6b, 0x06, 0x47, 0xee, 0xbc, 0x27, 0xc5, 0x0e, 0x1e, 0xf9, 0x6c, 0x14, + 0xf6, 0xee, 0x00, 0xd1, 0xde, 0x27, 0xf7, 0x17, 0xec, 0xee, 0x17, 0xfc, 0xe8, + 0xdf, 0xd0, 0xf6, 0xe6, 0x17, 0x0d, 0x09, 0xf5, 0xc5, 0xce, 0xe5, 0xd6, 0xc5, + 0xf3, 0x53, 0xff, 0xd4, 0x13, 0xb4, 0x0b, 0xd4, 0xec, 0xd4, 0x5d, 0x11, 0xe6, + 0xd8, 0x1b, 0xe8, 0xda, 0xab, 0xa3, 0xbb, 0x51, 0x1d, 0xf8, 0x1e, 0xd2, 0x13, + 0xca, 0x01, 0xea, 0xcc, 0xfc, 0xe8, 0x0d, 0xed, 0xa6, 0x16, 0x03, 0x2a, 0xf2, + 0xe1, 0x19, 0x15, 0xe9, 0x0a, 0x0d, 0xe7, 0x1e, 0x20, 0x22, 0xf7, 0xd2, 0x5f, + 0x17, 0x41, 0x07, 0x57, 0xdc, 0xf0, 0xe9, 0xfe, 0xbb, 0xef, 0x0e, 0x26, 0x81, + 0x25, 0x94, 0x95, 0xff, 0x0f, 0xe5, 0xfe, 0xe2, 0xef, 0xf6, 0x02, 0xb2, 0x10, + 0xc8, 0x4e, 0x6f, 0xe0, 0xec, 0xf9, 0x5c, 0x47, 0xe7, 0xa6, 0x45, 0xd7, 0xfb, + 0xfb, 0xc9, 0xf7, 0x1a, 0xd3, 0x17, 0x06, 0xfd, 0xcd, 0xf9, 0x02, 0xf6, 0xed, + 0xa7, 0x15, 0xea, 0xf2, 0x2c, 0xf1, 0xf4, 0x0c, 0x20, 0xf7, 0x38, 0xae, 0x09, + 0xf8, 0x0c, 0x30, 0xe7, 0x45, 0x38, 0x09, 0x16, 0xf2, 0x15, 0x24, 0xa3, 0x0c, + 0x13, 0x42, 0x0a, 0xeb, 0xfd, 0xf1, 0x0f, 0xdd, 0xdf, 0xc7, 0xe2, 0xb4, 0x08, + 0x46, 0x6e, 0xd8, 0x0a, 0xeb, 0xf5, 0x1e, 0xf5, 0x38, 0x04, 0x20, 0x19, 0xdd, + 0xf6, 0xd5, 0xfb, 0x8a, 0xc8, 0x1d, 0xd9, 0xa5, 0xdf, 0xf3, 0xf5, 0xcc, 0xc5, + 0x11, 0xba, 0xa1, 0x10, 0x36, 0xe4, 0xf1, 0xe1, 0xd2, 0x1b, 0x28, 0x93, 0xd2, + 0x50, 0x15, 0x6c, 0x10, 0x2e, 0x5a, 0x12, 0xc4, 0xe9, 0x2c, 0xf6, 0xff, 0xc4, + 0x3f, 0x10, 0xc6, 0xd1, 0x07, 0x0a, 0x15, 0xf7, 0x15, 0xf9, 0x07, 0xb6, 0x16, + 0xd8, 0x02, 0xe9, 0x45, 0xd0, 0x30, 0xbf, 0x1f, 0x39, 0x9f, 0xda, 0xf2, 0x14, + 0xe9, 0xe9, 0x1b, 0xf8, 0x60, 0xc7, 0xce, 0xe9, 0xce, 0x3d, 0x14, 0xc0, 0xad, + 0xd2, 0xa3, 0x2c, 0x4d, 0xd6, 0xf6, 0xcc, 0xf8, 0x11, 0x2d, 0x28, 0x26, 0x01, + 0xdd, 0xcd, 0x7f, 0xc9, 0xfe, 0xf0, 0xf6, 0xff, 0x0d, 0x4a, 0xd5, 0x1d, 0x2a, + 0x14, 0xe4, 0xda, 0xa3, 0xdc, 0xe0, 0xf8, 0xe7, 0xd1, 0xee, 0x2d, 0x3a, 0x09, + 0xbe, 0x52, 0x1b, 0xfa, 0x45, 0xfb, 0x2a, 0xae, 0x1f, 0x35, 0x1d, 0xf7, 0x41, + 0x08, 0xe7, 0x1d, 0x08, 0xd9, 0x04, 0xe0, 0xe3, 0x1f, 0xfb, 0xe8, 0x22, 0xfa, + 0x03, 0xc4, 0x28, 0xa5, 0xee, 0x26, 0x4c, 0x21, 0x36, 0xea, 0x2c, 0x28, 0xee, + 0x1a, 0x0a, 0xd4, 0xea, 0xdc, 0x36, 0x1d, 0xfe, 0xe8, 0xf7, 0xcd, 0xf5, 0xbf, + 0x0b, 0xba, 0xe6, 0xcb, 0xd7, 0x13, 0xee, 0xff, 0xe8, 0xef, 0xf3, 0x0e, 0x0d, + 0xfd, 0xf8, 0xd5, 0x1a, 0x2a, 0x05, 0xf6, 0x1f, 0xa4, 0xde, 0x02, 0x36, 0xfb, + 0xbe, 0x04, 0x23, 0xe7, 0x24, 0xca, 0x11, 0x50, 0x11, 0x18, 0x65, 0x11, 0xdb, + 0xdb, 0x5c, 0xf6, 0xe0, 0xd3, 0xd3, 0x07, 0x0d, 0x04, 0x01, 0x31, 0x10, 0x06, + 0xf8, 0xfa, 0xef, 0xbd, 0x29, 0x05, 0xea, 0xe0, 0xef, 0x20, 0x10, 0x51, 0xd4, + 0x43, 0x05, 0x48, 0x2a, 0xfd, 0x81, 0xfa, 0x2f, 0x23, 0xfb, 0x0f, 0xd0, 0x04, + 0xee, 0xbf, 0x0a, 0xf0, 0x16, 0xf5, 0x18, 0xf3, 0xee, 0xc8, 0xdc, 0x20, 0x12, + 0x40, 0xba, 0x1a, 0xf3, 0xfe, 0x3d, 0xe2, 0xdc, 0xdf, 0xec, 0x00, 0xfc, 0x08, + 0x0e, 0x0e, 0xc4, 0x24, 0xc4, 0x03, 0x24, 0x3f, 0x11, 0x60, 0xcd, 0xd0, 0xbf, + 0xfa, 0xda, 0xac, 0xe9, 0x08, 0xed, 0x0d, 0x19, 0xd8, 0x3b, 0xe1, 0xfe, 0x36, + 0x32, 0x16, 0xf3, 0x26, 0xd7, 0x2f, 0x12, 0x08, 0xd9, 0xf8, 0xf6, 0x0a, 0x11, + 0xbe, 0xfd, 0xfd, 0xdd, 0xf8, 0xc9, 0x9b, 0x6e, 0xfa, 0xe8, 0x04, 0x14, 0x36, + 0x0f, 0xcf, 0xf7, 0xf3, 0x42, 0x07, 0x13, 0xcb, 0xf8, 0xdb, 0x1d, 0x16, 0x1b, + 0xc7, 0xf7, 0xbe, 0x2b, 0xef, 0x25, 0x03, 0xf4, 0xcf, 0xd7, 0xf9, 0x06, 0x2c, + 0x22, 0x08, 0x0a, 0x14, 0x16, 0x1c, 0x47, 0xbf, 0xaf, 0x3c, 0x26, 0x3b, 0xe6, + 0xde, 0xfc, 0x12, 0x1f, 0x11, 0x01, 0xc6, 0x1c, 0x35, 0x51, 0x1b, 0x22, 0xfd, + 0xfc, 0x1a, 0xf9, 0xf8, 0x18, 0xc9, 0xfb, 0x81, 0x08, 0xd1, 0xf2, 0xc7, 0x2c, + 0x2b, 0x1f, 0xc7, 0x15, 0x0e, 0x26, 0xf1, 0xfc, 0xf5, 0xe1, 0x0e, 0xf3, 0xfe, + 0x53, 0x01, 0x13, 0x02, 0xdb, 0x26, 0xf1, 0x03, 0xfa, 0x06, 0xf1, 0xd3, 0x03, + 0xde, 0xe6, 0x28, 0xb6, 0x1d, 0xed, 0xfa, 0xf6, 0xfa, 0xcc, 0xea, 0x13, 0xe6, + 0xe5, 0x0c, 0x2e, 0xfb, 0xf3, 0x0e, 0x25, 0x49, 0x08, 0x08, 0x08, 0x2d, 0xc9, + 0xe8, 0x19, 0x0b, 0xe4, 0x27, 0xec, 0xdd, 0x14, 0x15, 0x1c, 0x2a, 0xed, 0xe0, + 0x26, 0x00, 0x45, 0x15, 0x2a, 0x30, 0xeb, 0x31, 0xf0, 0x01, 0x16, 0xcf, 0x1d, + 0xe1, 0x16, 0x0e, 0x1d, 0xfb, 0xf1, 0x3f, 0x07, 0x1f, 0x26, 0x13, 0xf9, 0x81, + 0xfe, 0xef, 0xf5, 0x1b, 0x08, 0x02, 0xd8, 0x42, 0xe7, 0xbd, 0x0f, 0x25, 0x5a, + 0x18, 0x0d, 0x00, 0x03, 0x14, 0xd7, 0x3b, 0x36, 0xe3, 0x42, 0x17, 0xfe, 0x11, + 0xd5, 0x02, 0x11, 0xb5, 0x1e, 0x14, 0x19, 0xf8, 0x07, 0x34, 0xc2, 0xd7, 0xd7, + 0xe3, 0x27, 0x12, 0xcc, 0xd1, 0xef, 0x13, 0xdb, 0xf7, 0x06, 0xf9, 0x17, 0x0c, + 0xeb, 0x5d, 0x3c, 0x1b, 0x0b, 0x3e, 0x28, 0x01, 0x1e, 0x20, 0xcd, 0xf7, 0xcf, + 0xd0, 0x39, 0xd3, 0xd7, 0x00, 0xea, 0xda, 0xe8, 0x2c, 0xf1, 0xf8, 0x81, 0xf8, + 0xc4, 0x1c, 0xeb, 0x2a, 0xbf, 0xd9, 0xc0, 0xed, 0xe1, 0x01, 0x04, 0xab, 0xdd, + 0xf3, 0x1a, 0xe4, 0x3b, 0xdd, 0x05, 0x3c, 0xf5, 0xf9, 0x19, 0x13, 0xae, 0xcc, + 0xcf, 0x45, 0xd4, 0x21, 0x0c, 0xa7, 0xa9, 0x46, 0xe1, 0xcf, 0x60, 0x28, 0xe6, + 0xf7, 0xe9, 0x45, 0xec, 0x10, 0xc5, 0x43, 0xea, 0x10, 0x08, 0x44, 0xd9, 0xe8, + 0xe4, 0xff, 0x34, 0x04, 0xcb, 0xc7, 0x05, 0x1c, 0x1c, 0xd5, 0x0e, 0x0a, 0xf3, + 0x06, 0xd4, 0xe4, 0x50, 0x0e, 0x2c, 0xfe, 0x4b, 0x91, 0x2e, 0xe8, 0x34, 0xf9, + 0x16, 0xe4, 0xf2, 0xfa, 0x4c, 0x00, 0xbf, 0x09, 0x08, 0xe9, 0x04, 0xf5, 0xb0, + 0x45, 0x1b, 0x1a, 0xef, 0x9e, 0x49, 0x38, 0xf2, 0x02, 0xb6, 0x01, 0xb5, 0xe2, + 0xe1, 0x0b, 0xab, 0x33, 0x7f, 0x0a, 0xec, 0x04, 0xf8, 0x01, 0x0e, 0x35, 0x4a, + 0xd5, 0x4f, 0xcb, 0xd9, 0xbe, 0xea, 0xec, 0x0f, 0x14, 0xb3, 0xfb, 0x0b, 0xfc, + 0x32, 0x1c, 0x0b, 0xf1, 0xe9, 0x05, 0x05, 0xcb, 0xe7, 0x15, 0xd5, 0x15, 0x0b, + 0x11, 0xf0, 0xd6, 0xec, 0x02, 0x0f, 0x3f, 0xf0, 0x29, 0x19, 0xd2, 0xcb, 0xb9, + 0x0b, 0x4e, 0x34, 0x2a, 0x18, 0x0c, 0xca, 0xe4, 0x00, 0x23, 0xec, 0xfe, 0x2e, + 0xc1, 0x48, 0x03, 0xfd, 0xe3, 0xef, 0x12, 0x37, 0xff, 0xf5, 0xdd, 0x2a, 0x03, + 0x12, 0xec, 0xed, 0xe4, 0x20, 0x06, 0x33, 0xb5, 0x49, 0x21, 0xf7, 0xf8, 0xe8, + 0x1a, 0x68, 0xe9, 0xd3, 0x5c, 0x27, 0xc4, 0x37, 0xf2, 0xc7, 0xff, 0xd1, 0x21, + 0x2c, 0x04, 0x55, 0xf0, 0x03, 0xc7, 0x24, 0xe3, 0xd3, 0xc3, 0xcf, 0x2f, 0x0c, + 0xe7, 0xc1, 0xc7, 0x0b, 0x81, 0x39, 0x1f, 0xfd, 0x28, 0xf0, 0xe0, 0x15, 0x0c, + 0xf2, 0xfb, 0x03, 0x3d, 0x0b, 0xc7, 0xea, 0xfc, 0xe1, 0xee, 0x3d, 0x14, 0x30, + 0xba, 0xfc, 0x28, 0xfd, 0x30, 0x2c, 0xfb, 0x16, 0xe9, 0x3e, 0xd1, 0xd1, 0x05, + 0xe6, 0xc2, 0xde, 0x09, 0xdb, 0xee, 0xac, 0xe7, 0xec, 0x5f, 0x21, 0xe1, 0x12, + 0x12, 0xf4, 0x24, 0x14, 0x09, 0x13, 0x03, 0xfa, 0xf5, 0xe1, 0xff, 0x2d, 0xc0, + 0x09, 0x5a, 0xcf, 0xd2, 0x04, 0xfc, 0x42, 0xbd, 0xe2, 0x09, 0xf3, 0x02, 0xd6, + 0x2b, 0x17, 0x21, 0xf4, 0xa0, 0xc9, 0xc4, 0xf2, 0x35, 0x01, 0xc8, 0x5b, 0xb5, + 0xe2, 0x47, 0x0b, 0x16, 0xc4, 0xa6, 0xfe, 0xe1, 0x05, 0xfa, 0xce, 0xd0, 0xf3, + 0x33, 0x23, 0x03, 0xc9, 0xea, 0xd2, 0x1a, 0x04, 0x16, 0xd6, 0xbe, 0x41, 0xd8, + 0xe1, 0x18, 0xae, 0xc7, 0xed, 0x03, 0xe7, 0xd7, 0x0b, 0x17, 0x0b, 0xf2, 0x1b, + 0xb8, 0x10, 0x19, 0xd8, 0xb0, 0x30, 0xcb, 0xfa, 0xfc, 0xef, 0xbf, 0xfa, 0x39, + 0x30, 0x27, 0x1e, 0x24, 0xd9, 0x2b, 0xf4, 0xfe, 0x07, 0x14, 0x1c, 0x08, 0xec, + 0xd1, 0xdd, 0x0f, 0xd5, 0x10, 0xf2, 0xec, 0x3b, 0xc0, 0x41, 0x0c, 0x3b, 0xd9, + 0x9e, 0xd4, 0x16, 0xe4, 0x0f, 0x25, 0x31, 0x10, 0xe1, 0xcd, 0xe2, 0xf1, 0xdf, + 0xe2, 0x67, 0xe3, 0xbb, 0x31, 0xea, 0x03, 0x0d, 0x1f, 0xd5, 0xbd, 0xea, 0xf3, + 0xca, 0x13, 0x03, 0x07, 0x0d, 0x09, 0x27, 0xd0, 0x7f, 0xf9, 0x5b, 0x33, 0x00, + 0xf3, 0xff, 0xfc, 0xf7, 0xb8, 0x24, 0x0f, 0xe3, 0xde, 0xfb, 0xf0, 0x0e, 0x02, + 0x10, 0xf1, 0xef, 0x18, 0xde, 0xea, 0xff, 0xd1, 0xe7, 0x0b, 0x4c, 0xaf, 0xf6, + 0xe3, 0x11, 0x36, 0x33, 0x42, 0x03, 0xfa, 0xfe, 0x41, 0x0e, 0x4f, 0x29, 0x1f, + 0xfa, 0x15, 0xd6, 0x2b, 0xd0, 0xf8, 0x03, 0xf0, 0xdb, 0xc6, 0xd7, 0xf8, 0x0f, + 0xf5, 0x39, 0xfc, 0x07, 0x0c, 0xec, 0xf4, 0xf0, 0xfc, 0xb3, 0x05, 0xf9, 0xd8, + 0xe1, 0x29, 0xdb, 0x31, 0x03, 0xf0, 0x00, 0x03, 0xdb, 0x22, 0xe0, 0xfe, 0xed, + 0xfc, 0xe6, 0xe9, 0xfc, 0x0c, 0xdf, 0x1a, 0x2d, 0x2f, 0x07, 0xe3, 0xd4, 0x06, + 0x10, 0xfe, 0xee, 0x2a, 0x21, 0xcc, 0xf6, 0xf5, 0xd4, 0xe0, 0xf1, 0x01, 0x02, + 0xf1, 0x25, 0xeb, 0xd3, 0xf6, 0x32, 0xe8, 0xe8, 0xf4, 0x13, 0x1c, 0xa7, 0xf3, + 0x1b, 0x21, 0xfd, 0xe4, 0x09, 0xdd, 0x04, 0xe9, 0x27, 0xf2, 0xed, 0xee, 0xea, + 0xef, 0x11, 0xda, 0xf7, 0xf3, 0x26, 0x81, 0xf2, 0xe2, 0x0d, 0x0c, 0xde, 0x0e, + 0x10, 0x00, 0xd3, 0xf1, 0xe4, 0xe7, 0x0c, 0x23, 0x00, 0xfa, 0x27, 0xff, 0x33, + 0xfa, 0x17, 0x11, 0x12, 0xf7, 0x37, 0x3a, 0xd6, 0xc2, 0x0f, 0xd5, 0x0d, 0x0f, + 0x06, 0x28, 0xd4, 0xfc, 0x2a, 0x64, 0xc5, 0xf8, 0xf1, 0xc8, 0xe5, 0x2f, 0x18, + 0x05, 0x46, 0xbe, 0x12, 0xc1, 0x2a, 0xbc, 0xf8, 0x26, 0x61, 0x2c, 0xeb, 0x0b, + 0xf3, 0x29, 0x38, 0x4f, 0xfd, 0x17, 0xd8, 0xc2, 0x0f, 0xff, 0xfd, 0xe1, 0x03, + 0xed, 0xf1, 0x20, 0xfa, 0xdf, 0xd7, 0xe6, 0xca, 0x13, 0xcf, 0xd4, 0x09, 0x17, + 0xf6, 0xea, 0xe3, 0x02, 0x21, 0x27, 0x08, 0xca, 0xe7, 0xe9, 0x29, 0x13, 0xe6, + 0x47, 0xdf, 0xfe, 0xf9, 0x16, 0x5c, 0xd6, 0x33, 0xce, 0x0e, 0x3d, 0x2e, 0xd4, + 0x01, 0x11, 0xc9, 0xbe, 0xe6, 0xf2, 0xd1, 0xe0, 0xfd, 0x2e, 0xe0, 0xfc, 0x60, + 0x3e, 0x33, 0x02, 0x52, 0x0f, 0x0c, 0xe9, 0x2b, 0x7f, 0x25, 0xff, 0x0d, 0xf0, + 0xf2, 0xc0, 0xf2, 0xdc, 0xd7, 0xf1, 0xf0, 0xf1, 0xc1, 0xd9, 0x0d, 0x38, 0x1e, + 0x16, 0xf0, 0x0c, 0x02, 0x0a, 0x5a, 0xea, 0xab, 0xfb, 0x1e, 0x0f, 0xec, 0xf3, + 0xba, 0x1d, 0xed, 0xf3, 0xe4, 0xf3, 0xf0, 0x1e, 0xcb, 0x38, 0x00, 0xae, 0xf4, + 0x56, 0x56, 0x37, 0x08, 0xab, 0xfe, 0x1d, 0xef, 0x25, 0x06, 0xdc, 0x14, 0xef, + 0x0b, 0xc9, 0xf8, 0xf2, 0x02, 0xef, 0x0a, 0x35, 0x34, 0xe8, 0x93, 0xe8, 0xf7, + 0xf7, 0x69, 0xf7, 0x05, 0x5b, 0x0b, 0x43, 0xf0, 0xe4, 0x7f, 0x16, 0xeb, 0x15, + 0xdf, 0xa5, 0x09, 0x4d, 0x31, 0xea, 0xf1, 0x13, 0xe0, 0xe7, 0x0f, 0xdc, 0x2c, + 0xa2, 0xfc, 0x0a, 0x57, 0x4b, 0x1e, 0x61, 0x25, 0xd2, 0x39, 0x0a, 0x0e, 0xac, + 0xe5, 0x09, 0xfe, 0x76, 0xe4, 0xc8, 0xd8, 0x4d, 0xa7, 0xfb, 0xf6, 0xdc, 0x04, + 0xfa, 0x19, 0x05, 0x94, 0xc8, 0x28, 0x1f, 0xcc, 0xfb, 0xad, 0x0b, 0x22, 0xf5, + 0xdb, 0x26, 0x13, 0x0d, 0x0a, 0xf4, 0x09, 0xe1, 0x0b, 0x17, 0x11, 0x48, 0x1c, + 0xd1, 0xbb, 0xe3, 0xdc, 0x73, 0xe7, 0xe0, 0xed, 0x35, 0xe0, 0x09, 0x14, 0xdb, + 0x0d, 0xfb, 0xb4, 0xea, 0x09, 0xe1, 0xf1, 0x20, 0x00, 0x2d, 0xd5, 0xf9, 0xd8, + 0xe3, 0xf6, 0xc7, 0xa3, 0x40, 0xcc, 0xdf, 0x0c, 0x13, 0x02, 0xcf, 0xe3, 0x27, + 0x19, 0x00, 0x2c, 0xd3, 0x31, 0x15, 0x00, 0xdf, 0xc6, 0x26, 0xde, 0x79, 0xd6, + 0x0e, 0xff, 0x1e, 0xf3, 0xdc, 0x44, 0xf2, 0x13, 0xf2, 0x16, 0xf8, 0x17, 0xb7, + 0xbe, 0xeb, 0xd6, 0x1d, 0xaf, 0xe2, 0xc5, 0xa2, 0x39, 0x24, 0xf3, 0xf2, 0x5b, + 0xe4, 0x00, 0x9c, 0xd5, 0xe9, 0x1d, 0x04, 0xf6, 0x2a, 0x0d, 0x06, 0xf7, 0x33, + 0xdd, 0x1a, 0x16, 0xfa, 0xae, 0xe2, 0xf4, 0x23, 0x7f, 0x0b, 0x40, 0xe7, 0x1d, + 0x0c, 0xee, 0xf7, 0xe5, 0xd3, 0xfc, 0xe0, 0xff, 0xda, 0xd2, 0x07, 0xf9, 0x0b, + 0x0f, 0xde, 0xce, 0x20, 0x0c, 0x0a, 0x3a, 0xfe, 0x0d, 0x2b, 0x62, 0xda, 0x1a, + 0xda, 0x0b, 0x21, 0xff, 0xe8, 0xfe, 0xeb, 0xf4, 0x19, 0x20, 0x2b, 0x0d, 0x0a, + 0x20, 0xca, 0x0f, 0x3b, 0xfc, 0x0d, 0x1b, 0x7f, 0xe6, 0x1c, 0xdd, 0xb4, 0x00, + 0x18, 0x48, 0xe5, 0x0f, 0x1e, 0xfa, 0x1d, 0xec, 0xfa, 0x1a, 0x03, 0xea, 0x10, + 0xe4, 0xdc, 0xd5, 0xe2, 0xec, 0x1f, 0xea, 0xeb, 0xfa, 0xf0, 0xff, 0xe4, 0xc6, + 0x10, 0x21, 0x06, 0xf5, 0x1f, 0xe2, 0x01, 0x23, 0x11, 0x0a, 0x0e, 0xfe, 0xf4, + 0x0a, 0xee, 0xd8, 0xfb, 0x0b, 0x11, 0xf6, 0xfc, 0xe2, 0xd0, 0xb0, 0xcf, 0x1d, + 0xd8, 0xc2, 0x10, 0xdd, 0xb9, 0xca, 0xef, 0x16, 0x08, 0xe3, 0x27, 0xfa, 0x44, + 0x28, 0x00, 0xe8, 0x20, 0x2b, 0x49, 0xed, 0x20, 0xf5, 0xf1, 0xd8, 0x50, 0xdd, + 0xf8, 0x15, 0xed, 0x07, 0x21, 0xdb, 0xfb, 0xf2, 0xff, 0x00, 0xf5, 0xf3, 0xf2, + 0x0f, 0xe4, 0xd8, 0x03, 0xd8, 0x04, 0xe4, 0x05, 0xc9, 0x2d, 0xd7, 0x04, 0x1e, + 0x22, 0xea, 0x13, 0x0f, 0xef, 0xd2, 0xf0, 0xfd, 0xe1, 0xda, 0xd6, 0x06, 0x22, + 0xf6, 0xe9, 0x2d, 0xd8, 0x01, 0xf2, 0x1f, 0x3c, 0xe6, 0xf0, 0xf0, 0x14, 0xce, + 0x0e, 0xe0, 0x14, 0xf0, 0xf3, 0x2c, 0x01, 0xe7, 0x23, 0xd1, 0x22, 0xde, 0x7f, + 0xcb, 0xed, 0xfc, 0x16, 0xda, 0xca, 0x03, 0x00, 0xf1, 0xd9, 0xe0, 0xf7, 0xca, + 0xd8, 0xf6, 0xf9, 0x01, 0x21, 0x1d, 0xae, 0xdd, 0x03, 0xee, 0xfd, 0x03, 0x09, + 0x03, 0x09, 0xd7, 0xe0, 0x27, 0xdf, 0x10, 0x5a, 0x10, 0x26, 0xe1, 0xf7, 0xf6, + 0x2b, 0x0d, 0xfe, 0x20, 0xd1, 0x01, 0x16, 0x2e, 0xc7, 0x0e, 0xfc, 0x10, 0x29, + 0x18, 0xdf, 0xfc, 0x1a, 0xf4, 0xe1, 0xf4, 0xd6, 0x24, 0xc8, 0xcc, 0x16, 0x3a, + 0xec, 0x14, 0x04, 0x55, 0xfe, 0xf1, 0x1a, 0xf9, 0x10, 0xf8, 0x0d, 0x14, 0xf5, + 0x2b, 0x15, 0x04, 0x17, 0xfc, 0x1d, 0xe3, 0xe9, 0xe0, 0xe6, 0xf8, 0xfe, 0xf6, + 0xc0, 0x20, 0x09, 0x21, 0x1e, 0xe2, 0x0d, 0x2a, 0x21, 0x96, 0xcc, 0xfc, 0xb5, + 0xf3, 0x46, 0xc7, 0xee, 0xe0, 0x4a, 0xf9, 0x2e, 0x1f, 0x2b, 0x07, 0x07, 0xb9, + 0xab, 0xe0, 0x08, 0xf7, 0x1b, 0x08, 0x8f, 0x20, 0x2c, 0x1f, 0xb3, 0xf3, 0x18, + 0xde, 0xe5, 0x0b, 0x19, 0xfe, 0xe5, 0xe7, 0x2f, 0xcb, 0xec, 0xac, 0xe1, 0x18, + 0x21, 0xd4, 0x0b, 0xa1, 0xce, 0xcb, 0xfd, 0x14, 0x2e, 0x29, 0x14, 0x4a, 0xd9, + 0x59, 0x22, 0x05, 0x02, 0xd8, 0x19, 0xf0, 0xbf, 0xf6, 0xcd, 0xf0, 0xe1, 0x15, + 0x26, 0xe7, 0xf6, 0xa2, 0x3b, 0xdc, 0x12, 0x58, 0x21, 0xee, 0xf8, 0xe2, 0xe5, + 0x09, 0xf2, 0x1f, 0x0a, 0xda, 0xd6, 0x32, 0xde, 0x28, 0x23, 0xfb, 0xac, 0x6f, + 0x13, 0xe5, 0xe6, 0xf7, 0x38, 0x27, 0xd7, 0x02, 0xdd, 0x17, 0xaf, 0x2f, 0xa8, + 0xfd, 0xed, 0x29, 0xe9, 0x3c, 0x7f, 0xef, 0xfb, 0x8f, 0xda, 0xe5, 0x01, 0xef, + 0xfd, 0x12, 0xed, 0xc4, 0x13, 0xa5, 0x45, 0xbb, 0xf7, 0x0f, 0xb6, 0xfe, 0xdd, + 0x04, 0xd2, 0x03, 0x19, 0x1b, 0xf6, 0x07, 0x2c, 0x14, 0x0a, 0x3b, 0xf3, 0xca, + 0x79, 0x12, 0x18, 0x56, 0xe9, 0x3a, 0xe2, 0x39, 0xed, 0xff, 0x6f, 0x1b, 0x13, + 0x37, 0x3a, 0x13, 0xd6, 0xb0, 0xf9, 0x31, 0x5d, 0xec, 0x21, 0xf8, 0xcf, 0xbe, + 0xf5, 0x31, 0xe9, 0xf6, 0xc0, 0xf0, 0x25, 0xe9, 0x4c, 0xcf, 0x0b, 0xf3, 0x22, + 0x1c, 0x0b, 0x05, 0x7f, 0xf1, 0x0c, 0x23, 0x22, 0x64, 0xf7, 0xc9, 0x16, 0x14, + 0x1c, 0x1b, 0xf6, 0xe2, 0x0a, 0xe2, 0xeb, 0x3f, 0x21, 0x22, 0x04, 0x21, 0xf2, + 0x71, 0x10, 0xf5, 0xef, 0x0b, 0xd8, 0xf0, 0xd5, 0xe4, 0x1f, 0x38, 0x4f, 0x07, + 0x0a, 0x1e, 0x2a, 0x3c, 0xe6, 0x1d, 0xf2, 0x20, 0x17, 0x09, 0xf2, 0x27, 0x07, + 0xe0, 0x1e, 0x8f, 0x3e, 0x1f, 0x22, 0x03, 0x1a, 0x2d, 0xe9, 0xf4, 0xe6, 0xe3, + 0xe6, 0xf3, 0xf9, 0xc3, 0x00, 0xfa, 0x26, 0xd6, 0xff, 0x03, 0x2a, 0xca, 0xd5, + 0x7f, 0xe1, 0x01, 0x1c, 0x10, 0xa3, 0xdf, 0x1e, 0x3f, 0x24, 0xfe, 0x0c, 0x38, + 0x21, 0x71, 0x0b, 0xb0, 0x08, 0xc6, 0xb5, 0xeb, 0x43, 0xc0, 0xe8, 0x1c, 0x15, + 0x0c, 0xda, 0x2d, 0x0a, 0xf3, 0xf3, 0x51, 0xb8, 0xea, 0xf7, 0xf8, 0x3a, 0x6f, + 0xe8, 0x01, 0xdc, 0xf2, 0xea, 0xc3, 0x1c, 0xbc, 0xee, 0xf7, 0xf3, 0x34, 0x4c, + 0x21, 0x3a, 0x01, 0xd3, 0x05, 0xd2, 0xd1, 0xfe, 0xf6, 0xe7, 0x24, 0xd1, 0x07, + 0x44, 0x37, 0xf7, 0x0c, 0xf5, 0xa8, 0x2c, 0x22, 0x19, 0xf4, 0xcc, 0xdb, 0x4b, + 0x02, 0x24, 0xee, 0xa9, 0xbc, 0xad, 0xf4, 0x6e, 0xfe, 0xe8, 0xd7, 0xd3, 0xf3, + 0xc2, 0x30, 0xe3, 0x1c, 0x15, 0xe5, 0x08, 0xdb, 0xf5, 0xd8, 0x4e, 0x0d, 0xe2, + 0xb8, 0x0d, 0xc5, 0xe6, 0x19, 0x08, 0xd0, 0x28, 0x27, 0x34, 0x31, 0xe5, 0x26, + 0xfe, 0x1d, 0x3f, 0xdb, 0xb0, 0x19, 0xe0, 0xfe, 0x22, 0xd7, 0xdf, 0x2b, 0x0a, + 0x07, 0x09, 0x32, 0xe6, 0xe6, 0xee, 0x1d, 0xea, 0xda, 0x4e, 0x7f, 0x59, 0x2a, + 0xd8, 0xee, 0x06, 0x0e, 0xed, 0x1c, 0x30, 0xfe, 0x2c, 0x25, 0xf7, 0xc5, 0xfb, + 0x48, 0xe5, 0xd0, 0xe4, 0xd0, 0xe1, 0x27, 0xfc, 0x12, 0x14, 0xd2, 0x0d, 0xb9, + 0x00, 0xc0, 0xfb, 0x1b, 0xd5, 0x06, 0xfb, 0x16, 0xd3, 0xe4, 0x28, 0x1a, 0x2e, + 0xd4, 0x19, 0x0e, 0xf2, 0x10, 0xe2, 0xfa, 0x08, 0x23, 0xf4, 0xfd, 0x14, 0xd3, + 0xe1, 0xbe, 0x1d, 0x16, 0x39, 0x16, 0x1c, 0x09, 0xfb, 0xe4, 0xe9, 0xe3, 0xf3, + 0x1a, 0x16, 0x05, 0xe6, 0xd8, 0xcb, 0x2e, 0xd2, 0x0c, 0xf7, 0x44, 0xc5, 0xe7, + 0xe7, 0x28, 0xe4, 0x27, 0xe7, 0x23, 0xe5, 0xf9, 0xfe, 0x25, 0x1a, 0x13, 0xc8, + 0xe2, 0x3b, 0xf3, 0x37, 0xe7, 0xf6, 0xdf, 0x4c, 0x26, 0x36, 0xf0, 0x17, 0x25, + 0x27, 0x08, 0x50, 0xfc, 0x02, 0xdc, 0x12, 0x16, 0xf9, 0x24, 0x81, 0x00, 0x26, + 0x14, 0xd1, 0xef, 0x06, 0xe1, 0xeb, 0x09, 0x0a, 0xd5, 0x2b, 0x1e, 0xd5, 0x0c, + 0xdf, 0xfe, 0x0d, 0x0d, 0x30, 0xdc, 0xfd, 0xd8, 0xde, 0x2f, 0x1e, 0x12, 0x22, + 0xee, 0xf2, 0xef, 0x47, 0xd4, 0xd8, 0x35, 0x70, 0xf9, 0x1e, 0x44, 0x10, 0xe8, + 0x42, 0xfc, 0xeb, 0xee, 0xb5, 0x29, 0xf7, 0xfb, 0xe4, 0x28, 0x0b, 0x2e, 0x27, + 0xda, 0x23, 0x29, 0xed, 0x2a, 0x19, 0xd7, 0x37, 0xeb, 0xf9, 0x09, 0xfc, 0x58, + 0xef, 0xd1, 0xfa, 0xe9, 0xe2, 0xf9, 0x01, 0x14, 0xfe, 0x1c, 0x1d, 0x21, 0x35, + 0x28, 0x9d, 0x4b, 0xff, 0x43, 0xfe, 0xe9, 0xdf, 0x2e, 0x29, 0x54, 0x1a, 0xd7, + 0xbe, 0x2f, 0xbb, 0xbb, 0xeb, 0x31, 0x1c, 0x3e, 0xf5, 0xee, 0x16, 0x0e, 0xef, + 0xe1, 0xac, 0xc7, 0x0a, 0xfc, 0x1e, 0x37, 0xf5, 0xca, 0x02, 0x54, 0x2e, 0xed, + 0xd1, 0xfb, 0xcc, 0x4f, 0x0e, 0xee, 0xa3, 0xe8, 0xdf, 0x01, 0x14, 0xf0, 0x00, + 0x2c, 0xfe, 0x0a, 0x8c, 0x38, 0x2a, 0xa7, 0xfc, 0xf3, 0xdc, 0xe4, 0x4e, 0xc7, + 0x31, 0x3a, 0xe4, 0xdd, 0x0c, 0xd4, 0xdd, 0x59, 0xea, 0x06, 0x06, 0x49, 0xe7, + 0x20, 0xf3, 0x15, 0xe1, 0xe9, 0xb6, 0xf8, 0xf1, 0x35, 0xda, 0xea, 0x12, 0x7f, + 0x20, 0xec, 0x91, 0x2c, 0xda, 0xf1, 0xfb, 0x52, 0xf2, 0x16, 0xe4, 0x30, 0x3e, + 0x0f, 0x0b, 0x40, 0xfc, 0x10, 0xf1, 0x13, 0xd1, 0x39, 0xf0, 0x11, 0x22, 0x3a, + 0xf9, 0x3c, 0xd7, 0xd9, 0x24, 0x00, 0x19, 0x0a, 0xdf, 0x3a, 0x0b, 0xb4, 0x2d, + 0x07, 0xbc, 0xe0, 0x12, 0xee, 0xe5, 0x17, 0x32, 0xf6, 0x16, 0x35, 0x23, 0xcf, + 0x6d, 0x1f, 0x0b, 0xd5, 0x00, 0x35, 0x05, 0x38, 0xc7, 0x38, 0x0a, 0x1c, 0x03, + 0x18, 0x11, 0x00, 0xef, 0x36, 0xd6, 0x9b, 0xd5, 0x08, 0x06, 0xf2, 0xdb, 0xf8, + 0xf1, 0x81, 0x56, 0xf0, 0xec, 0xe0, 0xf1, 0xe9, 0xcf, 0xf3, 0x6f, 0xff, 0x0f, + 0x0a, 0x01, 0x4a, 0xe4, 0x22, 0xee, 0xf3, 0xe1, 0x2e, 0x05, 0xeb, 0xd6, 0xf9, + 0xcb, 0xe3, 0x2e, 0xc4, 0xc9, 0xfe, 0x03, 0x13, 0xd7, 0x1d, 0xd4, 0x34, 0x1e, + 0x13, 0xc9, 0xf4, 0x07, 0xd5, 0x56, 0x2f, 0x28, 0x07, 0xf1, 0x16, 0x11, 0xcf, + 0x20, 0xeb, 0x13, 0x27, 0xe7, 0x04, 0xe3, 0xdf, 0x25, 0xf1, 0xf6, 0xd6, 0xd4, + 0xb2, 0x50, 0x11, 0xdb, 0x04, 0xf4, 0x0e, 0x3f, 0x6f, 0x56, 0x03, 0x3e, 0x0c, + 0x11, 0x3f, 0x12, 0x24, 0x39, 0xec, 0x0d, 0x16, 0x0f, 0x4a, 0x34, 0x36, 0xe0, + 0xd5, 0x02, 0xe2, 0x23, 0x47, 0x0a, 0x43, 0x0c, 0xd3, 0x0d, 0xcb, 0x24, 0x1f, + 0xe5, 0xfd, 0x15, 0x2f, 0x02, 0xf7, 0xcc, 0xfc, 0xe1, 0x0e, 0x26, 0x2c, 0xf7, + 0xd4, 0x0b, 0x10, 0x14, 0x36, 0x3b, 0x30, 0x04, 0x4b, 0x2a, 0xe7, 0xc7, 0xda, + 0xd4, 0x38, 0xc8, 0xe2, 0xae, 0xde, 0x0f, 0x53, 0xbb, 0xe3, 0xd7, 0xd7, 0xf1, + 0x15, 0x1f, 0x21, 0x4e, 0xdc, 0x04, 0xe2, 0x81, 0x06, 0x2c, 0xd1, 0xd1, 0x1b, + 0xff, 0x3a, 0xc1, 0xd9, 0x03, 0xbf, 0xfd, 0xdb, 0x4a, 0x10, 0x5d, 0xd4, 0xf5, + 0xf1, 0xbc, 0x13, 0x14, 0x6e, 0xdd, 0x19, 0xc0, 0xf2, 0xde, 0xfd, 0xf3, 0x0c, + 0x20, 0xe1, 0xc5, 0xe4, 0x3a, 0x22, 0x1c, 0x09, 0xd4, 0x0b, 0xdb, 0xcf, 0xd4, + 0xfc, 0xda, 0x19, 0xc4, 0xa7, 0x14, 0xd0, 0xbd, 0xd6, 0xe4, 0x03, 0xd4, 0x19, + 0xf3, 0x21, 0xe1, 0x29, 0xcd, 0xfc, 0xf9, 0xf4, 0xe3, 0xe9, 0x35, 0x03, 0xe1, + 0xb1, 0x1a, 0xf1, 0xf6, 0xe3, 0x13, 0xbc, 0x19, 0xde, 0xe2, 0xfa, 0xa5, 0x0e, + 0xef, 0x2a, 0x1c, 0x18, 0xe4, 0xdf, 0xeb, 0xe8, 0x12, 0x02, 0xea, 0xbf, 0xfb, + 0x32, 0xf4, 0x12, 0x11, 0x2c, 0x17, 0x1c, 0xf0, 0xf5, 0xeb, 0xe1, 0x31, 0x25, + 0xf2, 0x05, 0x12, 0x46, 0xdf, 0xbc, 0x00, 0xf5, 0xee, 0x10, 0xe9, 0x09, 0xf9, + 0x15, 0xeb, 0x00, 0x1a, 0x23, 0x07, 0xef, 0x0b, 0x0b, 0x08, 0xfc, 0xfa, 0xc7, + 0x0f, 0xf7, 0x0b, 0x28, 0x25, 0x15, 0x02, 0x2b, 0xe3, 0xf8, 0x1a, 0x33, 0x1e, + 0x27, 0x26, 0x34, 0xdc, 0x24, 0xe7, 0xc1, 0x37, 0x21, 0xe9, 0x11, 0x18, 0x20, + 0xd6, 0x0e, 0xde, 0xd8, 0x0e, 0xf3, 0xfe, 0x24, 0xd0, 0xf5, 0x4c, 0xcd, 0xd4, + 0xfc, 0x1d, 0x15, 0xee, 0xf5, 0x1e, 0x23, 0xe0, 0x41, 0xb8, 0xd8, 0xd9, 0x1c, + 0x14, 0x01, 0xcc, 0x35, 0xca, 0x18, 0xf1, 0x31, 0xf8, 0xf1, 0x13, 0x04, 0xec, + 0x18, 0x0b, 0x1e, 0x59, 0x01, 0xff, 0xd3, 0xcf, 0x29, 0x41, 0xd7, 0xf2, 0x2b, + 0x3a, 0x0c, 0x18, 0xff, 0x27, 0x53, 0x24, 0x14, 0x24, 0xe5, 0x10, 0x7f, 0x03, + 0x4b, 0x0b, 0xc4, 0x07, 0x4f, 0xe7, 0x29, 0x46, 0x3d, 0x5d, 0x0b, 0x06, 0x0c, + 0xb1, 0xa9, 0x23, 0xf0, 0x1d, 0x85, 0x09, 0x18, 0xcd, 0x1b, 0xc8, 0xc3, 0xc5, + 0x51, 0x30, 0x9c, 0xda, 0x48, 0xed, 0xe3, 0x20, 0x12, 0xfa, 0x0d, 0x15, 0xbc, + 0x02, 0xe0, 0xc7, 0xea, 0x28, 0x2a, 0x7f, 0xab, 0xed, 0xaa, 0x50, 0x52, 0x4e, + 0xa8, 0x3d, 0x3d, 0x03, 0xe5, 0xf0, 0x02, 0x01, 0xd9, 0xa9, 0x42, 0x13, 0xf1, + 0xc8, 0x4e, 0xfd, 0x43, 0x0f, 0x20, 0xa7, 0xa7, 0xbd, 0x3c, 0xd1, 0xe7, 0x1b, + 0xb8, 0x01, 0xda, 0xc8, 0xca, 0xce, 0x5f, 0x4a, 0xf9, 0xdc, 0x16, 0xc7, 0x4e, + 0xda, 0xd8, 0x32, 0xd7, 0xd1, 0xd7, 0x06, 0xb6, 0x04, 0x07, 0xdf, 0xe9, 0x00, + 0x21, 0xae, 0xcd, 0x1f, 0x54, 0x3a, 0xfb, 0xc0, 0x01, 0xd5, 0xc2, 0x06, 0x1a, + 0x0d, 0x67, 0xbc, 0xf6, 0x09, 0x17, 0x34, 0xd1, 0x09, 0xdf, 0x27, 0xb2, 0x87, + 0x29, 0x1c, 0xd3, 0xe1, 0xbc, 0xc4, 0xa5, 0x48, 0x24, 0xf5, 0xfd, 0xd5, 0x56, + 0xfa, 0x03, 0xbf, 0x46, 0x3b, 0x13, 0xc7, 0x0d, 0xbc, 0xfd, 0xdf, 0x00, 0x36, + 0x6e, 0x86, 0x77, 0xe7, 0xf8, 0xb8, 0xbe, 0x00, 0x44, 0x00, 0x15, 0xdb, 0xda, + 0x19, 0xcd, 0x07, 0xae, 0xb3, 0xc6, 0x1a, 0x3a, 0x36, 0x97, 0xcf, 0xde, 0x6c, + 0xd7, 0xc8, 0x20, 0xe3, 0x08, 0xef, 0xd6, 0x1a, 0x25, 0x34, 0xd2, 0x41, 0x29, + 0x23, 0xf1, 0xea, 0xd3, 0xcf, 0xfa, 0x54, 0xd1, 0x26, 0xc6, 0x33, 0x45, 0xdb, + 0x18, 0x38, 0x52, 0x4f, 0xcf, 0xdc, 0xe9, 0xc5, 0x3b, 0x0f, 0x17, 0x0f, 0xe5, + 0xf1, 0x41, 0x43, 0xf3, 0x25, 0x3a, 0xf4, 0x28, 0x1a, 0xfe, 0x12, 0xad, 0x25, + 0x42, 0xe4, 0x2a, 0x22, 0x1c, 0x7f, 0x39, 0x83, 0x11, 0x23, 0x0e, 0xab, 0x08, + 0x16, 0x2a, 0xe5, 0xf4, 0xf3, 0x01, 0xbc, 0x45, 0x50, 0xb0, 0xd7, 0xb3, 0xdb, + 0x12, 0xd6, 0xf6, 0xe3, 0xec, 0xd1, 0x08, 0xdd, 0xce, 0xe8, 0x11, 0x09, 0xe3, + 0x7f, 0xf9, 0x0d, 0xff, 0xc8, 0xc4, 0xf8, 0xf1, 0x08, 0xd9, 0xc8, 0x53, 0x1f, + 0xc2, 0x31, 0x6c, 0x35, 0xf2, 0xe9, 0x08, 0x4a, 0x1d, 0x8f, 0x26, 0x43, 0xc1, + 0xe0, 0x13, 0x36, 0xe5, 0x03, 0x01, 0xe4, 0x0b, 0xc9, 0xfd, 0xe5, 0xf2, 0xd5, + 0xfa, 0x2a, 0x03, 0x29, 0xe1, 0xb9, 0x48, 0xbd, 0xf2, 0xc9, 0x48, 0x0f, 0x30, + 0xf6, 0xef, 0x41, 0xf9, 0xd6, 0xe1, 0xfe, 0x43, 0x06, 0x03, 0xbc, 0x04, 0x1a, + 0x85, 0xe2, 0x2b, 0xbf, 0x9f, 0x1c, 0x24, 0xf8, 0xf8, 0x0f, 0x30, 0x1a, 0xe4, + 0x26, 0xb6, 0xaf, 0x32, 0x16, 0x0d, 0xc6, 0xce, 0xf3, 0x05, 0x59, 0xd6, 0xdd, + 0xc1, 0x08, 0xf3, 0x40, 0x63, 0xd9, 0x2b, 0x2d, 0x15, 0xe2, 0x50, 0xc6, 0xf4, + 0x3c, 0xfa, 0xd8, 0xe6, 0xf8, 0x1a, 0x48, 0x52, 0x02, 0xee, 0x29, 0x20, 0x21, + 0x26, 0xfb, 0xe1, 0xf1, 0x0a, 0x29, 0x14, 0xfa, 0xa0, 0xed, 0x4c, 0xde, 0xe2, + 0xf0, 0x65, 0xeb, 0xc7, 0xca, 0x0d, 0x05, 0xa9, 0x11, 0xf1, 0x02, 0x11, 0xe0, + 0x01, 0x43, 0x16, 0xf4, 0x45, 0x08, 0x69, 0x01, 0xfa, 0xdb, 0x2a, 0xb2, 0x07, + 0x15, 0x42, 0xd2, 0xe9, 0xb5, 0x53, 0x1b, 0xf1, 0xda, 0x18, 0x0d, 0xea, 0xf2, + 0x42, 0xec, 0x0b, 0x5f, 0xf0, 0xce, 0x0d, 0xb4, 0x55, 0x0c, 0xf7, 0xc2, 0x43, + 0xe9, 0x52, 0xb2, 0xdc, 0xe3, 0x04, 0x81, 0xf4, 0x24, 0xe4, 0x11, 0x1a, 0xff, + 0x08, 0xe6, 0x10, 0xf4, 0x75, 0xd0, 0x56, 0x2c, 0xf4, 0xe9, 0xfb, 0xfc, 0x1a, + 0xcc, 0xd7, 0x11, 0x5e, 0x06, 0x13, 0x5c, 0x29, 0x04, 0xea, 0x0e, 0x0a, 0x02, + 0xef, 0x21, 0x02, 0x0c, 0xe4, 0x07, 0x81, 0xd1, 0xe0, 0x1a, 0x44, 0xd3, 0xd6, + 0x24, 0x30, 0xd1, 0xe2, 0xff, 0xa7, 0x30, 0xb7, 0x28, 0xd2, 0x2a, 0xc3, 0x24, + 0x11, 0x03, 0x2f, 0xe9, 0x4b, 0xe5, 0xee, 0x32, 0xb8, 0xb0, 0xe4, 0xa0, 0xfd, + 0x34, 0xaa, 0x3c, 0xd2, 0x32, 0x01, 0x08, 0xd2, 0xd1, 0xf7, 0xd1, 0xed, 0x36, + 0x00, 0x1b, 0xf5, 0xd7, 0xb1, 0x47, 0x1b, 0x0a, 0x0b, 0x39, 0x3c, 0x31, 0x25, + 0x03, 0xe7, 0x0b, 0xec, 0xf3, 0x8b, 0xed, 0xcc, 0x62, 0xcd, 0x05, 0xf9, 0xd7, + 0xa8, 0x17, 0xc1, 0xd8, 0xa4, 0x37, 0x5f, 0x34, 0xe7, 0xc5, 0xed, 0x4d, 0xce, + 0xf8, 0xd6, 0x1a, 0xff, 0xab, 0xd3, 0x0c, 0x3d, 0xda, 0xe6, 0x23, 0xcc, 0x1b, + 0x36, 0xc2, 0xf3, 0xf4, 0xf2, 0x5c, 0x26, 0xeb, 0xc8, 0x28, 0xdf, 0x5b, 0xc7, + 0x59, 0x1c, 0x7f, 0xfd, 0x07, 0x8a, 0x09, 0xd2, 0xf3, 0x2b, 0xe3, 0x47, 0xe2, + 0x61, 0xd5, 0x33, 0x37, 0xd9, 0xf4, 0x5d, 0xda, 0xf7, 0x10, 0xfd, 0xde, 0xef, + 0xb6, 0xcc, 0xfb, 0xec, 0x1a, 0x11, 0xf1, 0xc3, 0xe9, 0xcf, 0xca, 0xc7, 0xee, + 0xf1, 0xd1, 0xf2, 0x0b, 0xca, 0xdc, 0xdb, 0x0a, 0xc7, 0x28, 0xe5, 0x03, 0xfc, + 0x0b, 0x07, 0x74, 0xf1, 0xbe, 0x1a, 0xe5, 0x22, 0xd7, 0xf2, 0x1a, 0x00, 0x12, + 0x16, 0x1b, 0x27, 0xcd, 0xdd, 0xe4, 0xc6, 0x0c, 0x26, 0x2e, 0x02, 0x05, 0x12, + 0x49, 0x04, 0xe6, 0x31, 0x34, 0xce, 0x51, 0xfe, 0xec, 0xfe, 0xda, 0x1f, 0x10, + 0xf6, 0xf6, 0x42, 0x00, 0xe7, 0x10, 0x16, 0x07, 0x7f, 0xb4, 0x05, 0xd1, 0x33, + 0xfc, 0x09, 0xe4, 0x16, 0x1b, 0x0a, 0xbb, 0xa4, 0x3d, 0x36, 0x26, 0xde, 0x29, + 0x09, 0xce, 0xe5, 0xfb, 0xed, 0xfe, 0xe4, 0xbb, 0x0c, 0x15, 0xe4, 0x06, 0x40, + 0xcb, 0xf5, 0x33, 0x10, 0xee, 0x24, 0x1f, 0x62, 0xef, 0xcb, 0x08, 0xfa, 0x1d, + 0xf4, 0x37, 0xc2, 0x4d, 0xe4, 0xea, 0x2a, 0x05, 0xf2, 0x11, 0xda, 0x23, 0x2d, + 0xf8, 0xea, 0x16, 0xf0, 0x2d, 0x99, 0xb7, 0xe7, 0x22, 0x04, 0xb8, 0xe7, 0x46, + 0x29, 0x7f, 0x28, 0x37, 0xff, 0x0b, 0xab, 0xe3, 0xe8, 0xf9, 0x10, 0x20, 0x11, + 0xe2, 0xef, 0x45, 0xf8, 0x5c, 0x08, 0x51, 0x0d, 0xb2, 0xf3, 0x12, 0xd7, 0xfe, + 0xca, 0xe1, 0x1d, 0x04, 0xcc, 0x37, 0x52, 0xe7, 0xe4, 0xa8, 0xaf, 0xdd, 0xd1, + 0xd9, 0x06, 0xff, 0xd2, 0x04, 0x16, 0xe9, 0xac, 0x0f, 0x1c, 0x05, 0xec, 0xef, + 0x45, 0x00, 0xfe, 0xbf, 0x1a, 0xc6, 0xca, 0xc9, 0xe7, 0x10, 0x26, 0x0f, 0x31, + 0xda, 0xe9, 0xdd, 0xf2, 0x2f, 0x09, 0xe7, 0xf7, 0x1d, 0xd0, 0xcb, 0xc8, 0xd9, + 0xd6, 0xb7, 0xef, 0xcc, 0x1d, 0x86, 0xb0, 0xa8, 0x1f, 0xcc, 0xc6, 0xdf, 0xf4, + 0x1f, 0xd2, 0xfc, 0xfc, 0x0f, 0xe1, 0x29, 0xf9, 0xa8, 0x14, 0x0b, 0x28, 0x49, + 0x08, 0xfa, 0xef, 0x19, 0xe8, 0xe8, 0x37, 0xc2, 0x09, 0xed, 0xe2, 0x0b, 0x0f, + 0x18, 0x40, 0xff, 0xd2, 0x6c, 0x3a, 0xd8, 0x8a, 0x5d, 0xf5, 0x5f, 0xc4, 0xb7, + 0xf4, 0x1c, 0xf5, 0xde, 0x23, 0x21, 0x0c, 0xb7, 0x27, 0xcc, 0x81, 0xe1, 0xd0, + 0x19, 0x6b, 0xc8, 0x47, 0xa8, 0xea, 0xea, 0xdb, 0xc5, 0xb0, 0xf3, 0x4e, 0xe8, + 0x27, 0x3b, 0x3b, 0x3a, 0xe7, 0x98, 0x09, 0x31, 0x14, 0x36, 0x1c, 0x35, 0x2f, + 0xfe, 0x1f, 0xf1, 0xf1, 0x4f, 0xa6, 0x25, 0x29, 0x34, 0xfa, 0xb3, 0x0d, 0x26, + 0x41, 0xf4, 0xd2, 0xe3, 0xc1, 0xd8, 0x3f, 0xdc, 0x12, 0x13, 0xbb, 0x98, 0x55, + 0x41, 0x64, 0xe0, 0xc2, 0xfe, 0x03, 0xf2, 0x5a, 0x27, 0x3b, 0x3d, 0x11, 0xfd, + 0x34, 0x40, 0x1b, 0x13, 0xe1, 0x23, 0xc5, 0x2e, 0x02, 0xe0, 0x16, 0x21, 0x27, + 0x65, 0x0a, 0x11, 0xb7, 0x26, 0x18, 0xf3, 0x45, 0xb6, 0x07, 0xed, 0x19, 0xc8, + 0xe6, 0x1d, 0xc1, 0xfd, 0x35, 0x24, 0xfd, 0xb6, 0x73, 0x08, 0xfb, 0x15, 0x1a, + 0xec, 0xf3, 0x1c, 0x00, 0xef, 0xf9, 0x0c, 0x0c, 0xd6, 0xf4, 0xc9, 0x24, 0xeb, + 0xf3, 0xea, 0x0e, 0xeb, 0xdd, 0x14, 0x03, 0x08, 0xe5, 0x10, 0x00, 0xca, 0xf3, + 0xcb, 0xfc, 0xeb, 0x13, 0xf1, 0xf5, 0x02, 0x3b, 0xec, 0xf2, 0x28, 0xb2, 0x0d, + 0xf6, 0x38, 0x39, 0x2f, 0xef, 0xd6, 0xf1, 0xda, 0x12, 0x1b, 0x1b, 0xe6, 0x16, + 0xcd, 0x14, 0x21, 0x26, 0xf0, 0x2b, 0xec, 0xe1, 0xdf, 0xef, 0xc7, 0x23, 0x22, + 0xd1, 0xaa, 0x1c, 0xfd, 0xeb, 0xff, 0x22, 0xf4, 0x21, 0xf4, 0x11, 0xea, 0x1c, + 0x41, 0x0a, 0x0e, 0xc7, 0x05, 0xcb, 0xe2, 0x09, 0xb3, 0xe3, 0xff, 0x01, 0x32, + 0x10, 0xfc, 0xde, 0x1d, 0xda, 0x1d, 0x00, 0x08, 0x1d, 0xd9, 0xeb, 0x19, 0x09, + 0x0d, 0x81, 0xf8, 0x07, 0xd8, 0xfc, 0xcf, 0x12, 0xc6, 0x34, 0x1e, 0xeb, 0x0b, + 0xfe, 0x02, 0xfb, 0xfb, 0xeb, 0xe7, 0x23, 0xcf, 0x08, 0x25, 0xe3, 0x2e, 0xd4, + 0xbd, 0x06, 0xe0, 0xb7, 0x1c, 0xf7, 0xcb, 0xe7, 0xde, 0xf3, 0xf1, 0xfb, 0xf2, + 0x32, 0xe9, 0x00, 0xf4, 0xd8, 0x20, 0xe2, 0x2f, 0x35, 0xe1, 0x1d, 0xd2, 0x06, + 0xdc, 0xf4, 0x11, 0x35, 0x04, 0xe0, 0xf6, 0x07, 0x14, 0xcc, 0xf7, 0xdc, 0x08, + 0x1c, 0xc1, 0xf8, 0x0c, 0x1f, 0x9a, 0x07, 0x1d, 0xf1, 0xb5, 0xc9, 0x04, 0x2f, + 0x24, 0xdc, 0xe8, 0x0c, 0x2c, 0x11, 0x01, 0x19, 0xf7, 0xcf, 0xe5, 0xeb, 0x09, + 0x72, 0x23, 0x9f, 0x28, 0xf4, 0xf8, 0x08, 0xf2, 0xeb, 0xfb, 0x09, 0x3b, 0x1e, + 0x3f, 0xc6, 0xdc, 0x21, 0x81, 0x24, 0xec, 0xe6, 0x0b, 0xea, 0x01, 0xfb, 0xd0, + 0xca, 0x06, 0x12, 0x37, 0xed, 0x52, 0x18, 0xff, 0xf7, 0xf4, 0x1e, 0x03, 0x14, + 0x16, 0x43, 0xf9, 0x3d, 0xe6, 0xe9, 0x1e, 0xe9, 0xec, 0xfe, 0xfa, 0x21, 0x64, + 0xf0, 0x0f, 0x01, 0x0c, 0x0d, 0x38, 0x15, 0x23, 0x3e, 0xf3, 0x0e, 0xdc, 0xf5, + 0xe9, 0xe7, 0x47, 0x00, 0xe3, 0xdd, 0xd6, 0xce, 0x15, 0xf2, 0x6f, 0x41, 0xeb, + 0x15, 0xe6, 0x0f, 0x3c, 0xf1, 0x47, 0x2f, 0x00, 0x0d, 0xe3, 0xb2, 0xb0, 0xd9, + 0x13, 0xc1, 0xc9, 0xe5, 0x08, 0x16, 0xd4, 0x0c, 0xd7, 0x65, 0x0e, 0x42, 0xbc, + 0xf1, 0xfb, 0x43, 0xf4, 0x26, 0xfd, 0xfb, 0x2b, 0xf6, 0xf7, 0x25, 0x81, 0x02, + 0x03, 0x52, 0x29, 0x0d, 0xea, 0xf4, 0xbd, 0x0d, 0x3d, 0x1e, 0x0e, 0x66, 0xd5, + 0xd1, 0xda, 0xc9, 0xf1, 0xfb, 0xce, 0x1e, 0xee, 0xd1, 0xe2, 0x1d, 0xf9, 0x23, + 0xec, 0x38, 0xf4, 0x7b, 0x45, 0x16, 0x4f, 0x56, 0x06, 0x16, 0x42, 0xeb, 0x24, + 0x04, 0xed, 0x10, 0xc8, 0x5a, 0x03, 0x07, 0x19, 0xbb, 0xe6, 0xf1, 0xd2, 0xcd, + 0x1b, 0x45, 0xd2, 0x0b, 0xcf, 0xf4, 0x0b, 0x05, 0xe2, 0x0f, 0x07, 0xfb, 0xb8, + 0xfe, 0x3c, 0xc0, 0xf0, 0xf2, 0xf7, 0xb5, 0xfb, 0xd4, 0xe7, 0x3a, 0xe4, 0xf6, + 0x03, 0x09, 0xc8, 0x22, 0xc6, 0xdb, 0xc8, 0x33, 0xf3, 0xf9, 0xf5, 0x0f, 0xc5, + 0x48, 0x25, 0x23, 0x27, 0x0b, 0x0a, 0x0e, 0x50, 0xee, 0x92, 0xf8, 0x08, 0xef, + 0x11, 0xd8, 0x00, 0xf4, 0x01, 0x08, 0x05, 0x3c, 0x16, 0x37, 0xf5, 0xcd, 0x28, + 0xb9, 0x01, 0xdc, 0xf9, 0x32, 0x00, 0x11, 0x03, 0x2e, 0xc9, 0xf9, 0xb8, 0x2a, + 0x23, 0xc9, 0x07, 0x24, 0xd0, 0x1a, 0xed, 0xf7, 0x0b, 0x6e, 0xe2, 0x1d, 0xca, + 0xf2, 0xb9, 0x16, 0xb6, 0xf2, 0x20, 0xda, 0x1a, 0xd9, 0xd4, 0xf6, 0x20, 0xcc, + 0xf0, 0x7e, 0x1c, 0xe7, 0xe0, 0x6c, 0xfe, 0xfd, 0xe5, 0xfc, 0xd1, 0x44, 0xed, + 0x0f, 0xf8, 0x30, 0x0c, 0x37, 0x05, 0x9d, 0x11, 0xf0, 0xee, 0xb8, 0xe7, 0x4d, + 0xea, 0x33, 0x81, 0xb4, 0x44, 0x1b, 0xfc, 0xdc, 0xe9, 0x31, 0x01, 0xd7, 0xdd, + 0xfa, 0x10, 0xdf, 0x08, 0x7f, 0xfd, 0x14, 0x1f, 0xeb, 0xf1, 0x1d, 0x00, 0x16, + 0xe7, 0xf8, 0xff, 0x03, 0x20, 0xd1, 0x1e, 0x0c, 0x0c, 0x02, 0xe2, 0x00, 0xc5, + 0x18, 0xb0, 0xf9, 0xda, 0x03, 0xd7, 0x2c, 0xea, 0xe2, 0xd7, 0x0d, 0xfd, 0xdd, + 0xe7, 0x16, 0xfb, 0xee, 0x09, 0xfa, 0xff, 0x0e, 0x0d, 0x02, 0xe2, 0xf8, 0x0a, + 0xea, 0x08, 0x04, 0xee, 0x06, 0xcb, 0xfc, 0x0e, 0xf1, 0xeb, 0x12, 0x1d, 0xf4, + 0x0c, 0x05, 0xd8, 0xc6, 0xea, 0x12, 0x2d, 0x00, 0x19, 0x21, 0xef, 0xfb, 0x31, + 0xf1, 0xc2, 0x2a, 0x06, 0x12, 0x29, 0x0a, 0xf1, 0xf7, 0xf5, 0x0f, 0x05, 0x45, + 0x32, 0x31, 0x1f, 0x06, 0x07, 0xff, 0x1c, 0x06, 0xef, 0x06, 0xe3, 0xd7, 0xf3, + 0xd0, 0x29, 0xdf, 0x14, 0xef, 0xf2, 0xde, 0x0e, 0xf9, 0xdb, 0xe4, 0xfe, 0xfa, + 0x05, 0x25, 0xfe, 0xf3, 0x13, 0xc0, 0x0a, 0xf0, 0x00, 0x1e, 0xe2, 0x0c, 0xc8, + 0x6a, 0xeb, 0x0d, 0x49, 0x1d, 0x49, 0x32, 0x20, 0x01, 0xd8, 0x0e, 0xfc, 0x64, + 0xdd, 0xd8, 0x21, 0x08, 0xf3, 0xfd, 0xfa, 0x9c, 0xaf, 0x09, 0xd6, 0x0e, 0xb8, + 0xeb, 0xd1, 0x31, 0xc8, 0x3e, 0x04, 0xed, 0xea, 0x38, 0x16, 0xd1, 0x3c, 0x42, + 0x08, 0xed, 0xe5, 0xe0, 0xea, 0x05, 0x59, 0x16, 0x03, 0xf5, 0xab, 0xd9, 0x19, + 0x49, 0x3b, 0x32, 0xcb, 0xfa, 0x44, 0xdb, 0xf1, 0x10, 0xf4, 0xee, 0x10, 0x1a, + 0xe5, 0xf0, 0xef, 0xc6, 0xee, 0x24, 0xe7, 0x1a, 0x1b, 0xf8, 0xf3, 0x17, 0xaa, + 0xd9, 0x0f, 0x0f, 0x54, 0xef, 0xd0, 0x0c, 0x7d, 0xeb, 0xba, 0xbc, 0x09, 0x03, + 0x0e, 0x81, 0xd8, 0x42, 0xc5, 0xf5, 0x85, 0xe7, 0x03, 0x2b, 0xe9, 0x34, 0xd6, + 0x32, 0x0f, 0x2c, 0xe8, 0xf9, 0xe5, 0x0a, 0xc1, 0xde, 0x0b, 0xfe, 0x22, 0xe1, + 0xbe, 0xe4, 0x15, 0x2b, 0x28, 0x00, 0x22, 0x1c, 0xe0, 0x1b, 0x09, 0x05, 0xb6, + 0x36, 0x00, 0x0a, 0x05, 0xfa, 0xb5, 0x21, 0x29, 0x1e, 0xba, 0xd2, 0x10, 0xf6, + 0xad, 0x08, 0x41, 0x17, 0x0b, 0xfd, 0x07, 0x02, 0x10, 0x88, 0x3c, 0xee, 0x8a, + 0x29, 0x2b, 0xf1, 0xe2, 0xf5, 0x04, 0xea, 0x29, 0xfa, 0xe2, 0xec, 0x00, 0x1d, + 0x11, 0xe9, 0x25, 0x19, 0x1c, 0xe1, 0xf5, 0x07, 0xef, 0x25, 0xae, 0xbc, 0xe2, + 0x50, 0xca, 0x05, 0xf4, 0xf8, 0x01, 0x43, 0x0b, 0xe9, 0xdd, 0xe2, 0x04, 0x83, + 0xfb, 0xfa, 0x17, 0xfc, 0xe0, 0xf0, 0x05, 0xeb, 0xd7, 0xe9, 0x17, 0x05, 0x17, + 0x10, 0x1e, 0xdd, 0x44, 0xee, 0xcf, 0x00, 0xcf, 0xe6, 0xe9, 0x02, 0xeb, 0x38, + 0xf4, 0xc4, 0x0e, 0x10, 0x0b, 0x04, 0x21, 0x81, 0xda, 0xbc, 0x40, 0x03, 0xc5, + 0x27, 0x0a, 0xab, 0xd8, 0x01, 0xc7, 0xeb, 0xdc, 0x1a, 0xe6, 0x22, 0xd6, 0x3c, + 0xfa, 0x0d, 0xde, 0xfb, 0xc4, 0xe6, 0x12, 0x26, 0xc3, 0x40, 0xb1, 0x59, 0x05, + 0x0f, 0x1e, 0x00, 0xcc, 0x9d, 0x20, 0x46, 0xe7, 0x38, 0xfb, 0x1e, 0x11, 0x1a, + 0x18, 0x71, 0xff, 0x33, 0x1a, 0x27, 0xe6, 0x17, 0x19, 0xec, 0xd9, 0xd2, 0xf5, + 0x16, 0xf5, 0xd0, 0x00, 0x1a, 0x35, 0xce, 0xdb, 0xad, 0xf3, 0xbb, 0x24, 0xf3, + 0x31, 0x3b, 0xf7, 0x21, 0xf9, 0xd0, 0x0b, 0xe2, 0xcd, 0x93, 0x09, 0x67, 0x56, + 0xd9, 0xdf, 0xf7, 0xee, 0xf2, 0xce, 0xe9, 0xea, 0x5c, 0x32, 0xe8, 0x54, 0xc2, + 0xce, 0x01, 0xe9, 0x67, 0x0d, 0x14, 0xc9, 0x13, 0x1d, 0xd2, 0xd8, 0xe9, 0xce, + 0x9c, 0x08, 0x00, 0xdd, 0xc6, 0xb5, 0x13, 0x42, 0xd5, 0x06, 0xaf, 0x55, 0xc6, + 0xdd, 0xf1, 0xc6, 0xd0, 0x2e, 0x45, 0xfe, 0x21, 0x55, 0xc6, 0xf9, 0xef, 0x06, + 0x05, 0xbd, 0xdc, 0x81, 0x01, 0x19, 0x2d, 0xfb, 0x23, 0xed, 0x37, 0xd6, 0xe4, + 0xfa, 0xec, 0x19, 0xcf, 0x09, 0x13, 0xe4, 0x02, 0xe8, 0xd8, 0xde, 0x0d, 0xe5, + 0xf2, 0x05, 0xf7, 0xe3, 0x44, 0xd1, 0xfd, 0x38, 0x0f, 0x36, 0x6b, 0xeb, 0x28, + 0x0d, 0x14, 0xbe, 0xf0, 0xf2, 0xf8, 0x0d, 0xff, 0xc3, 0xf8, 0xe9, 0xf8, 0x39, + 0xc7, 0x04, 0x0b, 0x09, 0x38, 0x06, 0x4a, 0xdb, 0xa0, 0x13, 0xee, 0x1d, 0xf6, + 0x32, 0xeb, 0x1e, 0xfb, 0xc8, 0xde, 0x1d, 0x2a, 0xf0, 0x05, 0xf7, 0x20, 0x08, + 0xb3, 0xfd, 0xf7, 0xfb, 0xc7, 0xac, 0x81, 0x26, 0xee, 0x45, 0xfb, 0xe0, 0xe2, + 0x4f, 0x22, 0xaf, 0x3b, 0xe5, 0x1b, 0xec, 0x31, 0x04, 0xe7, 0x06, 0xf5, 0x18, + 0xf7, 0x34, 0xf5, 0x4b, 0x14, 0xc1, 0xda, 0x0e, 0xe4, 0x23, 0xf7, 0x12, 0xf9, + 0x1c, 0x0d, 0x10, 0xd6, 0xf5, 0xdc, 0xff, 0x26, 0xe4, 0x02, 0x10, 0x36, 0x0f, + 0x12, 0x03, 0xfd, 0xbb, 0x03, 0x02, 0x0b, 0x19, 0x28, 0x04, 0xee, 0xf6, 0xaf, + 0xdf, 0x51, 0xb3, 0xc9, 0xfb, 0xdc, 0x10, 0xe5, 0xe0, 0x0a, 0x07, 0xf0, 0xe9, + 0xdc, 0x08, 0xf2, 0xce, 0xb8, 0xdd, 0xad, 0x06, 0xed, 0x07, 0xe5, 0x37, 0xfb, + 0xf3, 0xec, 0x4b, 0xdd, 0xf7, 0x39, 0xe9, 0x62, 0xf9, 0x17, 0x20, 0x1f, 0xfb, + 0xf1, 0x0a, 0x39, 0x0d, 0x16, 0xe7, 0x16, 0x09, 0xff, 0xfd, 0x39, 0xfd, 0xc8, + 0xf4, 0x1d, 0xe4, 0xd0, 0x20, 0xa4, 0xd5, 0x41, 0xdb, 0x06, 0xf7, 0xf8, 0x81, + 0x25, 0x18, 0x1a, 0x19, 0x08, 0x20, 0xff, 0x00, 0xad, 0xd5, 0x55, 0xff, 0xe1, + 0xd8, 0xe7, 0xef, 0x39, 0xf0, 0x01, 0xe4, 0xf1, 0xf7, 0xf6, 0xda, 0x09, 0x01, + 0x06, 0xff, 0x36, 0xed, 0xdf, 0xe0, 0xf1, 0xd2, 0xdc, 0x32, 0xcb, 0xff, 0x25, + 0xe3, 0xe8, 0xe6, 0x03, 0x16, 0x2d, 0xb4, 0xf0, 0x01, 0x5f, 0xd6, 0xde, 0x26, + 0xdb, 0xdf, 0x1f, 0xfd, 0xe3, 0x12, 0xca, 0xf6, 0x1b, 0x03, 0x11, 0xf5, 0xb4, + 0x13, 0x01, 0xd0, 0x07, 0xf4, 0x0a, 0xcf, 0x31, 0x46, 0x04, 0x68, 0xce, 0xf7, + 0x13, 0xe4, 0x09, 0xf1, 0x51, 0xd7, 0xce, 0x13, 0xbf, 0x51, 0xe5, 0x1c, 0xeb, + 0xfa, 0x14, 0x2f, 0xc6, 0xe3, 0x03, 0xe8, 0x1b, 0x3b, 0x4f, 0x3d, 0xe3, 0xfa, + 0x0f, 0xf0, 0x09, 0x7f, 0x46, 0x3c, 0x21, 0xdb, 0x08, 0x45, 0x73, 0x2c, 0x8e, + 0x3a, 0x29, 0x09, 0xec, 0xe1, 0xea, 0xf9, 0xd1, 0x49, 0xed, 0x2c, 0x1d, 0x25, + 0x40, 0x55, 0xf1, 0xea, 0x13, 0xe5, 0xe7, 0xfe, 0x4a, 0x46, 0x17, 0xc7, 0xf3, + 0xbc, 0x00, 0xe5, 0x4c, 0xe0, 0xff, 0x20, 0xd7, 0x18, 0x21, 0x3a, 0x1f, 0xa8, + 0x4f, 0xd9, 0x43, 0x44, 0x39, 0x08, 0x30, 0x59, 0x33, 0x15, 0xbe, 0xf1, 0x0d, + 0x11, 0xf8, 0x0b, 0xdb, 0xd5, 0xb1, 0x36, 0xe3, 0x0b, 0x2e, 0x22, 0x30, 0xe6, + 0x00, 0x3c, 0xcc, 0x04, 0xce, 0x3c, 0x10, 0x27, 0xf8, 0xff, 0x29, 0x44, 0x02, + 0xa8, 0x21, 0x23, 0x05, 0x29, 0xd1, 0xf5, 0x02, 0xe4, 0x78, 0xd4, 0xda, 0xea, + 0x12, 0x27, 0xe4, 0xf4, 0xfa, 0x21, 0xf2, 0x0e, 0x06, 0xee, 0xde, 0x05, 0xe4, + 0xfb, 0x45, 0xc2, 0xb0, 0xaa, 0x29, 0xd5, 0x07, 0x52, 0xe3, 0x25, 0xe5, 0x04, + 0x21, 0x0d, 0x91, 0xdf, 0xfc, 0xe2, 0x04, 0x36, 0x58, 0x20, 0xf7, 0x16, 0xf6, + 0x2d, 0xbd, 0x06, 0x0f, 0x16, 0xda, 0x1f, 0x01, 0xf3, 0xf9, 0x14, 0x04, 0x5f, + 0x49, 0x20, 0x15, 0xbf, 0x04, 0xf8, 0xb8, 0x1e, 0x29, 0x0b, 0x1d, 0xfb, 0xb9, + 0xd9, 0xb8, 0xfe, 0x20, 0xf4, 0xfe, 0xdc, 0x06, 0xe2, 0x35, 0x25, 0xd5, 0x81, + 0x19, 0xf3, 0xb5, 0xe0, 0x01, 0xfa, 0xe8, 0x45, 0xf7, 0xe6, 0x19, 0xef, 0x2c, + 0x45, 0xe7, 0xf6, 0x01, 0x12, 0x15, 0x09, 0xf7, 0xfa, 0xef, 0x63, 0x06, 0x22, + 0x01, 0x0f, 0xdb, 0xd4, 0xee, 0xe7, 0x10, 0xd9, 0x05, 0x28, 0xe7, 0xc4, 0xdc, + 0xd5, 0xf4, 0xe7, 0xba, 0x03, 0xf0, 0xeb, 0xc7, 0xf8, 0x24, 0xac, 0x03, 0x56, + 0x13, 0xfc, 0xff, 0xe9, 0x2c, 0x13, 0xaf, 0x13, 0x05, 0xe6, 0x19, 0x26, 0xef, + 0x13, 0x17, 0xf6, 0x21, 0xb9, 0x0e, 0x29, 0xe6, 0xcf, 0x2e, 0xea, 0x1e, 0x2c, + 0x1a, 0x1e, 0xef, 0x0c, 0xb7, 0x19, 0xe9, 0x1f, 0x2a, 0xea, 0x2c, 0x00, 0xc5, + 0x17, 0x24, 0x05, 0xe3, 0x14, 0x2b, 0x15, 0x11, 0xf2, 0x05, 0xf3, 0xd1, 0x36, + 0xcf, 0x16, 0x02, 0xf6, 0xf2, 0x1c, 0x3b, 0xb8, 0x02, 0xe3, 0xcc, 0xe1, 0x42, + 0x41, 0xf9, 0xfa, 0xfe, 0xe5, 0x0e, 0x38, 0x47, 0xfa, 0x12, 0xc1, 0x0d, 0x0e, + 0x60, 0x13, 0xf4, 0x7f, 0x15, 0x1c, 0x25, 0x09, 0x0c, 0xd1, 0x07, 0x26, 0x28, + 0xd5, 0x1d, 0x23, 0xd7, 0x28, 0xcb, 0x52, 0x10, 0x00, 0x21, 0x1a, 0xdd, 0xda, + 0x1a, 0xfd, 0xc9, 0xf2, 0xc1, 0xf7, 0x1c, 0x3c, 0xeb, 0xad, 0x28, 0xe1, 0xcd, + 0xe0, 0x31, 0x0b, 0x13, 0x16, 0xb2, 0xfa, 0xf5, 0xfd, 0xf8, 0x23, 0x1f, 0xfb, + 0x00, 0x1a, 0xae, 0xd2, 0xba, 0x1e, 0x1e, 0xc4, 0xca, 0x42, 0xf9, 0xdf, 0xd7, + 0xd5, 0xef, 0x45, 0x1c, 0x29, 0xf5, 0x00, 0xda, 0x16, 0x36, 0xf8, 0xf2, 0x11, + 0x7f, 0xdd, 0x3a, 0xf3, 0x2f, 0x1f, 0xe1, 0x5c, 0xf7, 0xd7, 0xea, 0x00, 0x1e, + 0xf0, 0x05, 0x11, 0xe5, 0xee, 0xf7, 0x0f, 0x6c, 0x0c, 0xcc, 0xcb, 0x23, 0xdc, + 0x05, 0x40, 0x1d, 0x03, 0x0a, 0x05, 0xfc, 0xd5, 0xb4, 0xc3, 0x0e, 0xe9, 0x37, + 0x2e, 0xe4, 0x26, 0x4f, 0xe6, 0x32, 0xb0, 0xf8, 0xda, 0x15, 0x61, 0xfa, 0xf4, + 0xe1, 0x59, 0xf1, 0x0d, 0xfe, 0x0e, 0xc9, 0x6f, 0x0f, 0x14, 0xe2, 0x0a, 0x0a, + 0xdb, 0x0a, 0xff, 0x5e, 0x97, 0x2e, 0x1e, 0x14, 0x1a, 0xe5, 0x3f, 0x0b, 0xee, + 0x0a, 0xfd, 0xe7, 0xdc, 0x15, 0x0a, 0x40, 0xcd, 0x1c, 0xcf, 0x0b, 0x25, 0xf9, + 0xdb, 0x03, 0xf7, 0xea, 0x1b, 0x0e, 0x99, 0x62, 0xe3, 0x41, 0xf3, 0xd1, 0x4f, + 0x0a, 0x05, 0x2b, 0x13, 0xc1, 0x9f, 0xc3, 0xb8, 0x2a, 0x38, 0x01, 0x11, 0xf5, + 0x1f, 0x06, 0x17, 0x32, 0xd5, 0xce, 0xba, 0x1f, 0x1b, 0x13, 0x0b, 0xfb, 0xab, + 0xcf, 0x5c, 0x26, 0xf6, 0x22, 0xd8, 0x31, 0x2b, 0x2b, 0x82, 0x2c, 0xf9, 0x2b, + 0x61, 0xff, 0x0b, 0xe9, 0xf3, 0x1c, 0xdb, 0x3e, 0xf6, 0xec, 0xe4, 0x53, 0x14, + 0x31, 0xb3, 0xf4, 0xe3, 0x00, 0xb8, 0xed, 0x98, 0xe8, 0x04, 0xd6, 0xe2, 0xcb, + 0xd7, 0x0c, 0x12, 0xf3, 0x28, 0x23, 0xc4, 0x13, 0xdf, 0xed, 0x54, 0x9a, 0xf9, + 0x0f, 0xb7, 0xc7, 0x4a, 0x3c, 0xfc, 0xaf, 0xf4, 0x0c, 0x28, 0x1e, 0xe6, 0x12, + 0x2c, 0x35, 0xa1, 0x39, 0xe0, 0x55, 0x3a, 0xf5, 0x81, 0xc8, 0x2e, 0xe7, 0x18, + 0xae, 0x1a, 0xf0, 0x45, 0xd9, 0xf2, 0x15, 0xf5, 0x0f, 0x3c, 0x07, 0xb1, 0x3f, + 0xd4, 0x97, 0x45, 0xa6, 0x19, 0x0f, 0xde, 0xca, 0xdd, 0xef, 0xda, 0xfb, 0xd5, + 0xfc, 0x39, 0xf2, 0x7f, 0xeb, 0x0a, 0x3d, 0x46, 0x41, 0xdd, 0x98, 0x0f, 0xe9, + 0xf0, 0xb6, 0xef, 0x06, 0xf1, 0x54, 0xe9, 0x1d, 0x2a, 0x48, 0xee, 0x28, 0x18, + 0x2b, 0x09, 0x2f, 0xfe, 0x69, 0x3e, 0xe8, 0xf3, 0x3d, 0xe7, 0x31, 0xdc, 0xe1, + 0x04, 0xfa, 0x28, 0x08, 0x36, 0xbf, 0x34, 0xe3, 0x2a, 0x30, 0xd1, 0x43, 0xaa, + 0x63, 0x2f, 0x1d, 0xdb, 0x35, 0xf6, 0x13, 0xfe, 0xcd, 0xbd, 0x0e, 0xe1, 0xe6, + 0xec, 0x7e, 0x33, 0x4e, 0xcc, 0x2e, 0xfa, 0xe3, 0xc1, 0x18, 0x10, 0xe1, 0xc2, + 0x4e, 0xd8, 0x01, 0x00, 0x27, 0x03, 0x26, 0xcc, 0xff, 0xee, 0xe5, 0xf5, 0x2f, + 0x2e, 0xda, 0xcf, 0x1d, 0xdd, 0xff, 0x36, 0x11, 0x2a, 0x28, 0x1d, 0x14, 0xd1, + 0x0a, 0x3e, 0xf6, 0xb0, 0x05, 0x35, 0x4d, 0xf9, 0x37, 0x5e, 0x31, 0x14, 0x5c, + 0xdb, 0xf5, 0x05, 0x9b, 0xd9, 0xf5, 0x0f, 0x11, 0xc5, 0xb7, 0xa4, 0xf0, 0xe6, + 0x1a, 0xe4, 0xde, 0x05, 0x19, 0xe6, 0xcb, 0xe7, 0x1f, 0x37, 0xfc, 0xe9, 0xdd, + 0x1c, 0xb1, 0xf0, 0x20, 0x12, 0xdd, 0x1f, 0xe4, 0x06, 0x25, 0xa7, 0x3a, 0x43, + 0x20, 0x34, 0x14, 0xe6, 0xd6, 0x25, 0x70, 0x29, 0xc9, 0x18, 0xc1, 0x2d, 0xf2, + 0xe0, 0x06, 0x56, 0x0f, 0x0e, 0x00, 0xd4, 0x85, 0xdd, 0x01, 0x16, 0x43, 0x17, + 0xe3, 0x22, 0x18, 0x19, 0xb9, 0xef, 0xe5, 0x35, 0xb9, 0x37, 0x0a, 0xdd, 0x19, + 0xd4, 0xe1, 0x0e, 0x05, 0xbb, 0x13, 0xfc, 0xff, 0x20, 0xf9, 0xb2, 0xa2, 0xf8, + 0xe1, 0xc5, 0x43, 0x2f, 0x14, 0x09, 0xbb, 0xf1, 0x1a, 0xe8, 0xa2, 0xf1, 0xf3, + 0x09, 0x02, 0x22, 0x24, 0x25, 0xf4, 0xf8, 0x35, 0xf5, 0x13, 0x1f, 0x81, 0xd3, + 0x1a, 0xfa, 0xcc, 0x24, 0xf2, 0xf5, 0xdc, 0xf5, 0x0d, 0xf7, 0x2f, 0x01, 0x12, + 0xe9, 0xde, 0xe0, 0xe2, 0xe1, 0x16, 0xca, 0x29, 0xfb, 0xe4, 0xde, 0xf8, 0x2f, + 0x22, 0x38, 0xdb, 0xed, 0xbe, 0x15, 0xd3, 0x12, 0x1d, 0x3a, 0x04, 0x1b, 0xe8, + 0xc4, 0x00, 0x13, 0xdc, 0xd9, 0xfd, 0x13, 0x0b, 0xbd, 0xe9, 0x17, 0xad, 0x2f, + 0x12, 0x09, 0xd8, 0xf3, 0xe8, 0xa8, 0x08, 0xf5, 0xd8, 0x0a, 0xe4, 0xe5, 0xc8, + 0xc6, 0x1b, 0x00, 0x2c, 0xd5, 0x14, 0x3e, 0xdc, 0x01, 0xff, 0x0a, 0xeb, 0x1e, + 0x1a, 0x02, 0x24, 0xe4, 0xf4, 0xfc, 0x3c, 0x16, 0x0d, 0xc6, 0xf5, 0xf2, 0xf3, + 0xca, 0x0b, 0xc6, 0x21, 0xe6, 0xd8, 0x3f, 0x05, 0x1a, 0xfe, 0xe9, 0xd0, 0x5d, + 0x2d, 0xf2, 0xea, 0xf9, 0xe3, 0xf9, 0xcb, 0xd5, 0xeb, 0x00, 0xe7, 0x37, 0x02, + 0xcf, 0x1b, 0xf6, 0x18, 0xf1, 0x30, 0xf8, 0x2c, 0xfc, 0xcd, 0x81, 0x08, 0x27, + 0xff, 0x2e, 0x02, 0xfb, 0xe1, 0xf9, 0x06, 0x2e, 0xe9, 0x26, 0x13, 0xde, 0x02, + 0x17, 0x04, 0x03, 0x09, 0x37, 0x7f, 0x02, 0xdf, 0x29, 0xd9, 0xf3, 0xe8, 0xe5, + 0x0f, 0x03, 0xdc, 0x1c, 0x2a, 0xd3, 0xac, 0xf0, 0x44, 0x06, 0xf4, 0xe1, 0xe0, + 0x17, 0x00, 0xfd, 0xcf, 0xfa, 0x21, 0xfe, 0xb3, 0xe1, 0xe9, 0x2e, 0x14, 0xf9, + 0xe3, 0x02, 0xf3, 0x02, 0x11, 0x23, 0x29, 0x18, 0x13, 0x02, 0xf0, 0x12, 0xe9, + 0x13, 0xf7, 0x0f, 0xce, 0xcc, 0xf5, 0x06, 0x1a, 0x07, 0x0f, 0xf2, 0x15, 0xf2, + 0xe6, 0x08, 0xf3, 0xf2, 0xeb, 0xf8, 0xd6, 0x23, 0x08, 0xe5, 0x09, 0x2f, 0xe3, + 0xe5, 0xfc, 0x37, 0x00, 0x08, 0xea, 0x05, 0x31, 0xfa, 0xe9, 0x35, 0xf6, 0x1f, + 0x02, 0xfd, 0xde, 0xcf, 0xea, 0xd0, 0x30, 0xea, 0x07, 0xf3, 0x06, 0xfe, 0x2b, + 0xc4, 0x1c, 0xe4, 0xd2, 0xe6, 0x10, 0xf9, 0xdd, 0x11, 0xcb, 0x15, 0xb1, 0xfb, + 0x48, 0xf4, 0x23, 0x02, 0x15, 0x42, 0x1c, 0xef, 0x38, 0xc0, 0xe6, 0x04, 0x17, + 0x05, 0xef, 0xe8, 0x47, 0x24, 0xf6, 0x2d, 0x1b, 0xf4, 0x55, 0x3a, 0x37, 0xb9, + 0x10, 0xda, 0x96, 0xd4, 0x34, 0xba, 0xff, 0x09, 0x02, 0xf9, 0x1f, 0xcc, 0xf1, + 0x40, 0xbc, 0xeb, 0xe0, 0x47, 0xee, 0xef, 0xfc, 0x3c, 0x11, 0x7a, 0x08, 0xd7, + 0xf5, 0xf3, 0xd6, 0xb6, 0xf5, 0xf1, 0x25, 0xe8, 0xac, 0xfb, 0xc2, 0xce, 0x81, + 0x74, 0xcd, 0xf0, 0x43, 0xb2, 0xbd, 0xc2, 0xff, 0x04, 0x2e, 0x61, 0xbf, 0xec, + 0x03, 0xf8, 0xf7, 0xf1, 0x9d, 0xee, 0x1a, 0x1f, 0xd8, 0x4a, 0xe1, 0xdb, 0x4a, + 0x3c, 0xed, 0xee, 0x23, 0x4a, 0xcb, 0xce, 0x16, 0x3c, 0x3d, 0xf1, 0x05, 0xde, + 0x50, 0x01, 0x11, 0xcc, 0x92, 0xf9, 0x14, 0xd1, 0xd6, 0x08, 0xd9, 0x8d, 0x9c, + 0xcd, 0x2e, 0xc3, 0xed, 0x04, 0x05, 0x7a, 0x2b, 0x02, 0x1d, 0xa1, 0x26, 0xd4, + 0x32, 0x26, 0x96, 0x64, 0xe8, 0xdb, 0x0b, 0x2a, 0xd5, 0x04, 0x13, 0x2c, 0x5e, + 0xf1, 0x06, 0x0e, 0x9d, 0xdd, 0xd8, 0xe8, 0x2f, 0x23, 0x2f, 0xcd, 0xc5, 0xee, + 0x30, 0xed, 0x5e, 0xdb, 0xf4, 0xe9, 0x20, 0xe3, 0x1b, 0xe1, 0xf4, 0xd4, 0xed, + 0x2e, 0xd2, 0xb7, 0x5a, 0x0f, 0xc9, 0xca, 0xce, 0x9e, 0x53, 0x2f, 0x4b, 0x18, + 0x82, 0x00, 0xda, 0xe3, 0xbc, 0x1b, 0xc6, 0xfe, 0xde, 0x4b, 0x32, 0xbc, 0xef, + 0xb3, 0xf3, 0xfc, 0x61, 0x2f, 0xfa, 0xa1, 0x86, 0x5c, 0xd0, 0xdc, 0x02, 0x4b, + 0xeb, 0x1f, 0x5a, 0x24, 0x16, 0x0f, 0xd1, 0xd1, 0xbf, 0xd9, 0x8f, 0xa8, 0x11, + 0x3b, 0xd8, 0x32, 0xda, 0xe6, 0x59, 0x7f, 0x11, 0x40, 0xe4, 0x34, 0xf0, 0x06, + 0xd4, 0xf4, 0xd5, 0xc3, 0x1e, 0x2e, 0x1b, 0xe9, 0xf6, 0x12, 0xe5, 0x0b, 0xe4, + 0x3b, 0x14, 0xd0, 0x45, 0x0c, 0xdb, 0xdb, 0xf5, 0xfa, 0x06, 0x1a, 0xc8, 0xe3, + 0xe5, 0x06, 0x14, 0x28, 0xf6, 0xbf, 0xc9, 0x09, 0xb1, 0x35, 0xd8, 0x10, 0xf5, + 0x35, 0x09, 0x0c, 0x18, 0xfd, 0xfa, 0x16, 0xfc, 0x41, 0xd5, 0x27, 0xc1, 0xa4, + 0x0e, 0xdc, 0xdc, 0x48, 0x38, 0xff, 0x0e, 0x4b, 0x0a, 0xa5, 0xee, 0x30, 0x1b, + 0x0b, 0x01, 0x0f, 0x53, 0xf7, 0xd7, 0xed, 0xec, 0xf9, 0xd1, 0x2a, 0x26, 0x2d, + 0xfa, 0x35, 0x22, 0x36, 0xed, 0xfc, 0x14, 0x8e, 0xef, 0xdd, 0x0b, 0x3b, 0x29, + 0xd6, 0xf4, 0xd0, 0x51, 0x00, 0xf5, 0xc8, 0x35, 0x09, 0xf1, 0x11, 0xd2, 0x5a, + 0xf9, 0x4f, 0xdd, 0x05, 0xc8, 0x0b, 0xe8, 0xf6, 0x2a, 0x2b, 0xfe, 0x81, 0x07, + 0x45, 0xce, 0x16, 0x1b, 0xe8, 0x46, 0xef, 0x4e, 0x0e, 0x21, 0xfa, 0x2b, 0xce, + 0x18, 0xfc, 0x2e, 0x09, 0x04, 0x5b, 0xd6, 0x27, 0x0f, 0xc9, 0x21, 0x14, 0xf3, + 0xfc, 0xe3, 0x02, 0xf4, 0xec, 0xff, 0xff, 0x2c, 0x12, 0x1c, 0x03, 0x02, 0xdd, + 0xe5, 0x19, 0x0a, 0x0e, 0x2c, 0xf5, 0x23, 0xfa, 0xd0, 0x08, 0x1f, 0xe0, 0xdb, + 0x14, 0xf9, 0xe9, 0x00, 0x1c, 0x16, 0xd5, 0xf9, 0xc5, 0xfb, 0x26, 0x15, 0xfe, + 0x05, 0x07, 0xd5, 0x25, 0x1a, 0xe4, 0xf9, 0xf9, 0xea, 0x0d, 0x0b, 0x23, 0x14, + 0xf0, 0xef, 0xdb, 0xe8, 0x1f, 0x2e, 0x0f, 0x09, 0xdd, 0x22, 0x0e, 0x05, 0xee, + 0xfd, 0x03, 0xc6, 0x0b, 0x05, 0xf1, 0xd6, 0x04, 0xdd, 0xe0, 0xfb, 0xfa, 0x01, + 0x17, 0xf0, 0xf1, 0x1e, 0x09, 0xfe, 0x00, 0x11, 0x02, 0x00, 0xc7, 0x04, 0xd2, + 0xf5, 0xdd, 0xfa, 0x09, 0xdc, 0x0f, 0xe4, 0xe1, 0xfa, 0xcb, 0x27, 0xed, 0xef, + 0xfc, 0xd4, 0xea, 0x04, 0xd3, 0xe8, 0x23, 0x02, 0x08, 0xce, 0x0a, 0x19, 0xf7, + 0xe7, 0xf9, 0x15, 0x2c, 0x03, 0xf0, 0xf5, 0x3f, 0x0b, 0x7f, 0x16, 0x18, 0x21, + 0xf6, 0x38, 0xd5, 0xfe, 0x01, 0xeb, 0x3b, 0xbe, 0xdb, 0xba, 0xa2, 0xae, 0x01, + 0x2d, 0x6a, 0x46, 0x29, 0x2b, 0x29, 0x81, 0x04, 0xff, 0x23, 0x1b, 0xfd, 0xab, + 0x26, 0x37, 0x3f, 0x21, 0x20, 0x23, 0x9d, 0xc1, 0xc6, 0xcf, 0x7a, 0x49, 0xea, + 0xf4, 0xd5, 0x2f, 0xcc, 0x48, 0xd7, 0x13, 0xfd, 0x3e, 0x0f, 0xef, 0x50, 0xe0, + 0x11, 0xd2, 0x37, 0x2e, 0x3d, 0x20, 0x55, 0xe5, 0x3a, 0xe4, 0x12, 0x2a, 0x27, + 0x04, 0x57, 0x4d, 0xf4, 0x0f, 0x29, 0x27, 0xf8, 0x2c, 0xfd, 0x69, 0x2d, 0xfe, + 0x32, 0xfd, 0xa6, 0xc8, 0xe2, 0xf6, 0x31, 0xbf, 0x52, 0xf8, 0xff, 0xe1, 0xdb, + 0x50, 0xdc, 0xea, 0xf0, 0xdb, 0x18, 0x93, 0xca, 0x65, 0x8f, 0x09, 0x10, 0x62, + 0xe5, 0x3c, 0x4c, 0x03, 0xe7, 0x0d, 0xff, 0x9c, 0x4d, 0xe3, 0xe1, 0xf9, 0xce, + 0x36, 0xe7, 0x1d, 0x9f, 0x19, 0x13, 0x2f, 0x4d, 0xf5, 0xeb, 0xe4, 0x68, 0x10, + 0x2d, 0xe5, 0x17, 0xe3, 0xd0, 0xd5, 0xec, 0x13, 0x1b, 0x10, 0xd6, 0x39, 0xd4, + 0x24, 0xe3, 0xc3, 0x14, 0xee, 0xfd, 0xee, 0x45, 0x0e, 0x23, 0xf0, 0x32, 0x03, + 0xe7, 0xdc, 0x26, 0x3e, 0xec, 0xbe, 0xd9, 0x7f, 0xda, 0x0c, 0x23, 0x19, 0x17, + 0xf2, 0x52, 0x37, 0xce, 0xfd, 0xec, 0x25, 0x19, 0xf5, 0x01, 0xf1, 0xf0, 0x02, + 0xe8, 0x1b, 0xf7, 0xe1, 0xf2, 0x01, 0xd5, 0xdf, 0xe6, 0xff, 0x0d, 0xeb, 0xdc, + 0x18, 0xdc, 0xf1, 0x1f, 0xf8, 0xe7, 0xff, 0xf1, 0xe0, 0xd6, 0x2e, 0x0e, 0x09, + 0xdc, 0x25, 0xfc, 0x05, 0xdb, 0x1c, 0xdf, 0xca, 0xf3, 0xec, 0x27, 0x1c, 0x3e, + 0xc2, 0xde, 0x26, 0x37, 0xf6, 0xfe, 0x2f, 0x1a, 0x0b, 0xd9, 0xf5, 0xca, 0xf6, + 0xca, 0x1d, 0x10, 0x01, 0xfc, 0x08, 0xfd, 0xcf, 0x03, 0x1f, 0x1e, 0x32, 0xa4, + 0xe6, 0xed, 0x00, 0xd2, 0x27, 0xd7, 0xeb, 0x10, 0xe6, 0x1d, 0xe3, 0x00, 0xcf, + 0xff, 0x16, 0xdd, 0xcb, 0x09, 0x12, 0xe0, 0xf0, 0xee, 0x08, 0xf7, 0xc6, 0x24, + 0x44, 0x04, 0xaf, 0x22, 0xd7, 0x39, 0xef, 0x2c, 0xf8, 0x2b, 0xd9, 0x2b, 0xf8, + 0x0b, 0x4d, 0xca, 0xf8, 0xcb, 0x19, 0x1e, 0xfb, 0xd7, 0xf3, 0x1a, 0xf8, 0x4c, + 0x23, 0xe7, 0xf3, 0x00, 0x1d, 0x13, 0xe7, 0xf5, 0x39, 0xb3, 0x1c, 0xe8, 0x0b, + 0x27, 0xf0, 0xe6, 0x06, 0x40, 0x14, 0xd9, 0xe4, 0xce, 0x24, 0xd8, 0xc2, 0x16, + 0xdb, 0xf7, 0x29, 0xbb, 0x38, 0xf1, 0x01, 0xf9, 0x2a, 0x05, 0x07, 0xac, 0x13, + 0x0c, 0x04, 0xe9, 0xf6, 0x02, 0x04, 0x0c, 0x51, 0x07, 0xfa, 0xe0, 0x25, 0x2d, + 0x81, 0xe7, 0x0a, 0x02, 0x0c, 0xe8, 0x59, 0xd3, 0xf3, 0xf4, 0xec, 0xeb, 0x4e, + 0xef, 0xdb, 0x04, 0xf8, 0x0c, 0x13, 0x20, 0xde, 0xd4, 0x0b, 0xe1, 0x32, 0xd6, + 0xfa, 0x08, 0x02, 0xe2, 0x20, 0x2a, 0x28, 0x3a, 0xdd, 0xb2, 0x61, 0x5c, 0x21, + 0x1e, 0xf4, 0xb4, 0x0a, 0x30, 0xf2, 0x15, 0xd9, 0xd5, 0x25, 0x06, 0xbe, 0xca, + 0x04, 0xd4, 0xd6, 0x26, 0x5f, 0x02, 0xcd, 0x37, 0x54, 0x14, 0xd1, 0x35, 0x08, + 0x0e, 0x53, 0x17, 0x20, 0x35, 0x2d, 0x16, 0x61, 0x0f, 0xdb, 0xfb, 0xcd, 0xd0, + 0xee, 0x00, 0x47, 0x1c, 0x39, 0x14, 0x08, 0xe7, 0x2d, 0xcf, 0xfb, 0x13, 0x26, + 0xf5, 0xe6, 0xc4, 0xce, 0x3c, 0xe5, 0x11, 0x07, 0x37, 0x1b, 0xf6, 0x3f, 0x16, + 0x60, 0x07, 0xdf, 0x93, 0xcf, 0xd3, 0x9d, 0xbd, 0xda, 0x2d, 0x05, 0x01, 0xa1, + 0xe7, 0xe2, 0xcd, 0x1a, 0x20, 0xc5, 0xf0, 0x08, 0xd1, 0xc3, 0xa7, 0xd2, 0xbb, + 0x34, 0xf1, 0xe3, 0x7f, 0xe4, 0xe7, 0x18, 0xec, 0xf4, 0x59, 0xd9, 0xa3, 0x1c, + 0x0f, 0x41, 0xde, 0xe0, 0x09, 0xe6, 0x4d, 0xf2, 0x2c, 0xc2, 0x6a, 0x06, 0xbe, + 0xab, 0xbe, 0x36, 0x33, 0xd1, 0x1a, 0xba, 0xe1, 0xe5, 0x29, 0x37, 0x12, 0xb4, + 0xe2, 0xea, 0xd5, 0xd5, 0xfd, 0xcf, 0xde, 0xd0, 0xd0, 0x09, 0xf8, 0x19, 0x31, + 0x26, 0xcd, 0x3d, 0xcb, 0xfa, 0x00, 0x13, 0x07, 0xf4, 0x1a, 0xeb, 0x08, 0xde, + 0x04, 0xd9, 0x05, 0x3d, 0x0a, 0x0f, 0x0f, 0x37, 0x3f, 0xfe, 0xe5, 0x29, 0x16, + 0x1b, 0x15, 0xe2, 0xee, 0xfa, 0xf7, 0xb4, 0x0a, 0x12, 0x09, 0xf1, 0xf9, 0x6f, + 0xf0, 0xe5, 0x0c, 0x13, 0xe1, 0xac, 0xd0, 0xdd, 0xc1, 0x3f, 0xe8, 0xe1, 0x17, + 0x70, 0xf8, 0xb2, 0xf2, 0xf5, 0xdd, 0x45, 0xf7, 0x1e, 0xf1, 0x1c, 0x05, 0xe4, + 0x1f, 0xcb, 0x07, 0x10, 0x3a, 0xe3, 0xf6, 0xfe, 0x14, 0xed, 0x27, 0xcb, 0xdf, + 0xd4, 0x19, 0xe3, 0xdd, 0x15, 0xe6, 0x17, 0x13, 0xfe, 0xe7, 0x09, 0x0f, 0xcc, + 0x48, 0x6b, 0xfc, 0xfd, 0x17, 0xf7, 0x02, 0x11, 0xea, 0x19, 0xe9, 0xf0, 0x81, + 0xdd, 0x06, 0xea, 0x06, 0x03, 0xd8, 0x46, 0x24, 0x18, 0xb9, 0xd7, 0x1c, 0x0e, + 0x0d, 0x0a, 0xe1, 0x20, 0x26, 0x2c, 0x12, 0x94, 0x5f, 0x2c, 0x22, 0xcd, 0xe7, + 0x09, 0x1c, 0x1b, 0xd8, 0xea, 0x1e, 0x00, 0x56, 0xcf, 0x22, 0xef, 0xe3, 0xe5, + 0x31, 0x1a, 0xbe, 0xd5, 0x28, 0x2b, 0xfe, 0x27, 0xda, 0x17, 0x25, 0xdf, 0x51, + 0x22, 0xdb, 0x4d, 0x18, 0x2a, 0x4e, 0x3e, 0xec, 0xaf, 0x2f, 0x1d, 0x46, 0xcf, + 0x1f, 0x00, 0xe8, 0xfc, 0xd9, 0x04, 0x1f, 0x57, 0x72, 0x38, 0x05, 0x2f, 0xf6, + 0xfc, 0xe1, 0xf2, 0x2a, 0x0f, 0x32, 0xc7, 0x15, 0xf0, 0x0c, 0xea, 0x19, 0x7f, + 0x37, 0x0a, 0x2e, 0x47, 0xcd, 0x17, 0xee, 0x0c, 0x24, 0xf5, 0xb3, 0xfd, 0xd3, + 0xd3, 0xba, 0x11, 0xc8, 0xf2, 0xd4, 0xdb, 0x2c, 0x2f, 0xc9, 0xd3, 0x43, 0x0b, + 0xf8, 0xf6, 0x0c, 0xe7, 0x16, 0x0a, 0x84, 0xc7, 0xfc, 0xbd, 0x04, 0xe8, 0x06, + 0xf8, 0xea, 0x16, 0xf1, 0xc5, 0x02, 0x05, 0xee, 0xbf, 0xce, 0x1a, 0xe3, 0x82, + 0x01, 0x13, 0xeb, 0x57, 0xed, 0x15, 0x1e, 0xec, 0x38, 0x4b, 0x76, 0x10, 0x26, + 0xd4, 0xee, 0xf7, 0x2b, 0xe8, 0x02, 0x1b, 0x04, 0xbf, 0xcc, 0x17, 0x0a, 0x1d, + 0x13, 0x30, 0xf6, 0x19, 0x2b, 0x0a, 0xc7, 0x04, 0x47, 0x4c, 0x04, 0xdf, 0x26, + 0xd9, 0x00, 0xf7, 0xe4, 0xf5, 0x02, 0xe6, 0xc7, 0x09, 0x10, 0x96, 0x04, 0xfe, + 0x0c, 0xf3, 0xbe, 0x15, 0xba, 0x1c, 0x03, 0x10, 0xda, 0xf2, 0x81, 0xf5, 0xff, + 0x18, 0xa7, 0x1f, 0xff, 0x26, 0xd6, 0x45, 0xf3, 0x30, 0xea, 0xe2, 0xb1, 0xfe, + 0x36, 0x2f, 0x31, 0xb0, 0xfe, 0x33, 0x69, 0x1b, 0x0c, 0xe0, 0x3b, 0xbb, 0x13, + 0xfd, 0x2d, 0x25, 0x07, 0x0b, 0xd1, 0xf0, 0xc5, 0xdf, 0x4d, 0x63, 0x1e, 0x1c, + 0xf8, 0xd6, 0x15, 0xd4, 0xf8, 0x2c, 0xf9, 0x4e, 0xb4, 0x29, 0x15, 0xd0, 0x05, + 0x38, 0x2f, 0x12, 0xfe, 0x1a, 0x05, 0xee, 0xb5, 0xf9, 0xd6, 0xbd, 0x31, 0xfd, + 0xe8, 0x13, 0xc2, 0xf4, 0xad, 0xf4, 0x09, 0x12, 0xfa, 0x34, 0xf2, 0xe5, 0x0f, + 0xe8, 0xc0, 0x01, 0xc8, 0x2b, 0x01, 0xac, 0xda, 0x10, 0x35, 0x23, 0xf6, 0xfe, + 0x32, 0xe5, 0x09, 0x02, 0x1e, 0x7f, 0xbc, 0x21, 0x4b, 0x33, 0xff, 0xf7, 0xe7, + 0xe9, 0x08, 0x10, 0xed, 0x26, 0x32, 0x9f, 0xbf, 0x06, 0xf3, 0x50, 0x21, 0x1a, + 0x1b, 0x19, 0xf4, 0xbf, 0xe6, 0xf7, 0x1c, 0x12, 0xe6, 0xc0, 0x47, 0xe3, 0x13, + 0x27, 0xea, 0x0a, 0x35, 0xf8, 0x20, 0xcd, 0x92, 0x0b, 0x2c, 0xe5, 0xde, 0x11, + 0x04, 0x03, 0x0c, 0x42, 0xe0, 0xce, 0xd4, 0x20, 0xff, 0x22, 0x1f, 0xe8, 0xd2, + 0x03, 0xbd, 0x31, 0x6d, 0xf4, 0x0f, 0x06, 0x52, 0xcd, 0xc3, 0xf1, 0xc3, 0xe2, + 0x20, 0x0d, 0x10, 0x01, 0x15, 0xd1, 0x1f, 0xdc, 0x22, 0xf3, 0x2f, 0xe7, 0xf7, + 0x00, 0x0b, 0x0b, 0x12, 0x17, 0x44, 0xf5, 0xa2, 0xe5, 0x14, 0xf4, 0x0f, 0x3b, + 0xc6, 0x31, 0xf4, 0xcf, 0x2b, 0x08, 0xdf, 0xe1, 0xa3, 0x09, 0xfd, 0xf4, 0xc3, + 0xf0, 0xf0, 0x18, 0x3c, 0xf2, 0xb8, 0xf5, 0xe5, 0xe5, 0x05, 0x3a, 0xe6, 0x28, + 0xed, 0xe5, 0x2d, 0x2b, 0x17, 0xcf, 0x0e, 0xe4, 0xbd, 0x27, 0x09, 0xf8, 0x0c, + 0x15, 0xe2, 0xe9, 0xde, 0x24, 0x02, 0x08, 0xe8, 0x02, 0x04, 0x07, 0xcd, 0xf7, + 0x9a, 0xf3, 0x01, 0xec, 0xcf, 0xe1, 0xd5, 0xf8, 0x4f, 0x06, 0x1f, 0x15, 0xf5, + 0x2a, 0x0b, 0xea, 0xfc, 0x18, 0xd4, 0xf9, 0x33, 0x16, 0xf8, 0x7f, 0x39, 0x21, + 0x00, 0x13, 0x5f, 0xe3, 0xd7, 0xd6, 0xc4, 0x30, 0xf2, 0x08, 0xfd, 0xba, 0xf7, + 0x22, 0x0d, 0x1d, 0xf3, 0x31, 0xe7, 0xed, 0xd1, 0x39, 0xf5, 0x08, 0xce, 0xfa, + 0x1b, 0x01, 0x54, 0xfa, 0xb3, 0xf0, 0xc5, 0x3d, 0xfb, 0x01, 0x39, 0xd9, 0x02, + 0x1e, 0x25, 0xd1, 0xbd, 0x0a, 0x10, 0xd7, 0x24, 0x1b, 0xdd, 0xf1, 0xf7, 0xf8, + 0xf4, 0xea, 0x81, 0x27, 0x11, 0x2d, 0xfb, 0x64, 0x2c, 0x10, 0x16, 0x11, 0xed, + 0x0a, 0x09, 0xc1, 0x1b, 0x0c, 0xf3, 0x24, 0x0d, 0x39, 0x1d, 0x05, 0x18, 0xc8, + 0xde, 0x00, 0x1d, 0xf4, 0xf7, 0xea, 0xf8, 0x11, 0xcb, 0xfe, 0x11, 0x19, 0xed, + 0xea, 0xfc, 0x0f, 0xf0, 0xe3, 0xcc, 0xe0, 0xea, 0xa4, 0x25, 0x10, 0x04, 0xef, + 0x15, 0xeb, 0xc4, 0x01, 0xfe, 0x01, 0xd1, 0x01, 0xfe, 0xf9, 0x6f, 0x09, 0x17, + 0xdc, 0xe6, 0x2d, 0x08, 0xcd, 0xbe, 0x99, 0x30, 0xe4, 0x10, 0xb2, 0xaa, 0x22, + 0xc5, 0x00, 0x00, 0x06, 0xfd, 0xe3, 0xef, 0xc8, 0xf0, 0xe8, 0xb4, 0xf0, 0xf2, + 0x05, 0xe8, 0x11, 0xf9, 0x13, 0x1f, 0xf1, 0xf7, 0xe3, 0xe1, 0xc6, 0xc8, 0x00, + 0xf8, 0xf7, 0x42, 0x15, 0x19, 0xf7, 0xf5, 0xea, 0xf0, 0xbf, 0x19, 0x05, 0x13, + 0xe0, 0xc0, 0xdd, 0xd7, 0xcb, 0x13, 0xe7, 0x1d, 0x2e, 0xec, 0x08, 0xfe, 0xfc, + 0x18, 0x18, 0xdd, 0x10, 0x0b, 0xe3, 0x27, 0xe6, 0xf9, 0x11, 0x67, 0xfc, 0x1e, + 0xd4, 0x0b, 0xee, 0xf2, 0x1f, 0xfd, 0xb2, 0x02, 0x32, 0xcd, 0xc8, 0xf9, 0x0d, + 0x0c, 0xe6, 0xfd, 0x11, 0xe2, 0x0b, 0xee, 0xcd, 0x3a, 0xf3, 0xd8, 0x11, 0x10, + 0x05, 0x10, 0xf4, 0xdc, 0x0d, 0x36, 0x0a, 0xda, 0xf2, 0x38, 0x2f, 0x0c, 0x0c, + 0x05, 0x2a, 0xe4, 0xca, 0xfb, 0xd9, 0xfc, 0x05, 0xfc, 0xe1, 0xf7, 0xed, 0xcb, + 0x52, 0xfe, 0x00, 0x7f, 0xd9, 0x39, 0x32, 0xb1, 0x0d, 0xc0, 0x08, 0xfb, 0x16, + 0xb5, 0x10, 0x0e, 0x12, 0x31, 0xdb, 0x43, 0xc8, 0xca, 0xf0, 0xd1, 0xff, 0xf6, + 0x0f, 0xfe, 0x5f, 0xc2, 0x36, 0xe7, 0x0c, 0x1d, 0x15, 0xeb, 0x10, 0xf1, 0xc7, + 0x0a, 0x2b, 0xed, 0xd6, 0x2c, 0xc2, 0x02, 0xd2, 0xfd, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, 0x32, 0xf7, 0x38, 0xec, 0xf3, 0xe0, + 0x99, 0xc8, 0x0a, 0x05, 0xb2, 0x2f, 0x1c, 0xc9, 0x08, 0xe5, 0x0b, 0x19, 0x05, + 0x12, 0x05, 0x29, 0xcc, 0x12, 0xef, 0xf6, 0x37, 0xe9, 0xc1, 0xe6, 0xf2, 0xef, + 0x28, 0xe8, 0xd4, 0xf8, 0x14, 0xc6, 0x41, 0x23, 0x06, 0x59, 0x26, 0x09, 0xf3, + 0xeb, 0xdc, 0x44, 0xfa, 0xdc, 0xca, 0xd0, 0x12, 0x31, 0x37, 0xe9, 0xf5, 0x0d, + 0x03, 0x07, 0xb4, 0xe7, 0xfe, 0xf1, 0xa4, 0x62, 0xf5, 0x3c, 0x36, 0xf1, 0x27, + 0x06, 0xc6, 0x0f, 0x2c, 0xd8, 0xdd, 0xf9, 0x03, 0x4c, 0x0b, 0xb0, 0xa9, 0x24, + 0xfd, 0x81, 0x31, 0x96, 0xce, 0x63, 0xca, 0x17, 0x58, 0x33, 0x0d, 0x12, 0xca, + 0xc6, 0x48, 0xae, 0xeb, 0x49, 0xe8, 0xe0, 0x43, 0x08, 0x40, 0xb6, 0xc8, 0x8f, + 0x3d, 0x5b, 0xcc, 0xf6, 0x56, 0x63, 0xf5, 0x0a, 0x0d, 0xd9, 0x99, 0xe4, 0x06, + 0xde, 0x24, 0xd3, 0x0d, 0x21, 0x39, 0x2f, 0x81, 0x12, 0x41, 0xaf, 0x0a, 0xf2, + 0xd3, 0xcf, 0xdb, 0x1f, 0x04, 0xf1, 0x04, 0x3c, 0x1a, 0x53, 0x31, 0x16, 0xe9, + 0x1c, 0xe3, 0x26, 0x32, 0xbb, 0xf1, 0x01, 0x01, 0x34, 0xc2, 0x08, 0x12, 0x1b, + 0x67, 0xfb, 0x40, 0xde, 0xc6, 0xdd, 0x6b, 0xc5, 0x0f, 0x01, 0xb9, 0xd6, 0xfa, + 0xf5, 0x28, 0xe4, 0x15, 0xe9, 0x08, 0x35, 0x5f, 0x29, 0xbe, 0xf6, 0x03, 0x02, + 0xaa, 0x3a, 0x06, 0x09, 0xc6, 0x2c, 0xf5, 0xc7, 0x09, 0x25, 0xdf, 0xee, 0x06, + 0x3f, 0x25, 0x08, 0x20, 0xf0, 0xe6, 0x9c, 0xfc, 0xa8, 0xdf, 0x07, 0x48, 0xdd, + 0xad, 0xed, 0xfa, 0x06, 0xe5, 0xd6, 0xb6, 0x27, 0xb8, 0x1c, 0x1f, 0x40, 0x29, + 0xf5, 0x19, 0x14, 0xe8, 0xe5, 0x33, 0x9a, 0x26, 0x0e, 0x47, 0xe2, 0xcf, 0x0c, + 0x00, 0x39, 0xe8, 0x2a, 0x2b, 0x0e, 0xe1, 0x29, 0x66, 0xf5, 0xf9, 0xc3, 0xde, + 0xcf, 0x0f, 0xde, 0xdb, 0xd8, 0x22, 0x10, 0x01, 0xf2, 0xc7, 0xca, 0x10, 0x15, + 0xcf, 0xeb, 0x08, 0xf0, 0xe5, 0x23, 0x0d, 0x20, 0x05, 0x06, 0x31, 0xe7, 0x03, + 0xdd, 0x4e, 0xd5, 0xf8, 0x4c, 0x5e, 0x17, 0x40, 0x7f, 0xca, 0x46, 0xbc, 0xb7, + 0xbe, 0x25, 0x14, 0x1b, 0xc6, 0x08, 0xea, 0x22, 0x98, 0xef, 0xe9, 0x18, 0xd0, + 0xe1, 0x1d, 0x3e, 0xd8, 0x06, 0x18, 0xd8, 0x38, 0xe8, 0xef, 0x36, 0xfa, 0x06, + 0xff, 0x14, 0xe5, 0xae, 0x33, 0x68, 0xdc, 0x00, 0x41, 0xe4, 0x2e, 0x0b, 0x26, + 0x19, 0xfb, 0xfc, 0x27, 0x53, 0xcd, 0xf9, 0x97, 0xdc, 0x21, 0x00, 0xd3, 0x32, + 0xd0, 0x13, 0x33, 0xee, 0x65, 0x48, 0x13, 0x9d, 0x00, 0x19, 0x28, 0xb1, 0x2a, + 0xdd, 0xd5, 0xfa, 0x1c, 0xd2, 0x09, 0xd6, 0x18, 0x28, 0xe4, 0xf3, 0x07, 0x0a, + 0xfa, 0x16, 0x12, 0xfd, 0xd2, 0xcc, 0x15, 0xf7, 0x1a, 0xe9, 0xed, 0xdd, 0xea, + 0x18, 0x03, 0xd8, 0x12, 0x0c, 0x15, 0xf9, 0x00, 0x6a, 0x41, 0xd8, 0xf4, 0xf8, + 0x0c, 0x1a, 0x37, 0x1e, 0x01, 0xf8, 0xd8, 0xe6, 0xf8, 0xe2, 0xdf, 0xb7, 0x09, + 0xe3, 0x3a, 0x08, 0x1b, 0xb3, 0xeb, 0xd0, 0x2b, 0xd8, 0x00, 0xf1, 0x5e, 0x31, + 0xcb, 0xc8, 0x7c, 0xf9, 0x81, 0xd4, 0x2f, 0xfe, 0x97, 0xcc, 0x1c, 0x75, 0xee, + 0xed, 0x4e, 0xf8, 0x14, 0xde, 0x49, 0x02, 0xe0, 0xe3, 0x58, 0xfd, 0xfb, 0xdf, + 0xfb, 0x14, 0x72, 0x19, 0x1f, 0xe8, 0x55, 0xd5, 0x0a, 0x4a, 0xd7, 0xbb, 0x1e, + 0x11, 0xe0, 0xcc, 0xe6, 0xf2, 0x27, 0xc8, 0x15, 0xf0, 0xf4, 0xfd, 0xdd, 0x42, + 0x1b, 0x2f, 0xcb, 0x13, 0xe5, 0xb1, 0x09, 0x1a, 0xcb, 0x23, 0x02, 0xe7, 0xe1, + 0x0b, 0xf2, 0x02, 0xcc, 0xeb, 0x12, 0x20, 0x24, 0xe3, 0xe1, 0xb9, 0xff, 0xbd, + 0x1a, 0x89, 0xfc, 0x1e, 0x38, 0xec, 0x04, 0x1b, 0x22, 0xf8, 0x0e, 0xf4, 0x41, + 0x0d, 0xf9, 0xf5, 0xfe, 0xe3, 0xf4, 0xfa, 0x10, 0x0b, 0xec, 0xc4, 0x24, 0x11, + 0x15, 0x05, 0x26, 0x10, 0xf0, 0xeb, 0x10, 0x04, 0xd4, 0x00, 0x29, 0xf8, 0x14, + 0x11, 0x18, 0xf8, 0x23, 0xe4, 0x10, 0x7f, 0x02, 0x13, 0x3e, 0xf8, 0xfb, 0x2e, + 0xd4, 0x0d, 0xfc, 0xdc, 0xfb, 0x52, 0xe2, 0x1d, 0xfb, 0x05, 0x07, 0xe7, 0xed, + 0x24, 0xff, 0xf0, 0xd9, 0xe4, 0xf8, 0x3b, 0x46, 0x05, 0xec, 0xea, 0xd7, 0x0b, + 0xec, 0x08, 0xf1, 0x3a, 0x22, 0xfa, 0xe5, 0x06, 0xfb, 0xf8, 0x12, 0x11, 0xee, + 0x0d, 0xee, 0xea, 0x0b, 0xf0, 0xed, 0x12, 0xe6, 0xe0, 0x05, 0xe2, 0xf6, 0x07, + 0xe2, 0xd9, 0x05, 0xe6, 0xf2, 0x3e, 0x02, 0xce, 0x19, 0x02, 0x31, 0xfe, 0xda, + 0xfa, 0x3b, 0x19, 0xf6, 0x04, 0x07, 0x14, 0xfc, 0x52, 0xf6, 0xf9, 0x2f, 0x16, + 0x0b, 0x15, 0x04, 0x1d, 0xf3, 0xdf, 0x29, 0xbf, 0xeb, 0xf2, 0xae, 0x12, 0xe3, + 0x2a, 0x0a, 0xe1, 0xcc, 0x13, 0x34, 0x0d, 0xf1, 0xe2, 0x2e, 0xcb, 0x00, 0x1a, + 0x24, 0x0c, 0xe0, 0x08, 0x0a, 0xeb, 0xed, 0x2a, 0x0b, 0x26, 0x07, 0x27, 0xf3, + 0xee, 0xf2, 0x09, 0xf3, 0x19, 0xc8, 0x27, 0x26, 0xef, 0xef, 0xcb, 0x08, 0x25, + 0xf2, 0xdb, 0xc4, 0x05, 0xd8, 0xf5, 0x09, 0xde, 0x07, 0xe2, 0xe3, 0x11, 0xbe, + 0xce, 0xc1, 0xa0, 0x58, 0x0b, 0x09, 0x35, 0xf1, 0x81, 0xed, 0xe2, 0x2e, 0x07, + 0x34, 0xd0, 0xe5, 0x20, 0x1a, 0x01, 0x0e, 0x41, 0xd6, 0xea, 0x26, 0x3c, 0xf8, + 0xd3, 0x12, 0x1e, 0x02, 0x4e, 0x02, 0x01, 0xe0, 0x0e, 0x05, 0xfc, 0x0c, 0x07, + 0x27, 0xd9, 0x00, 0x08, 0x11, 0xfe, 0xe1, 0x11, 0xf1, 0x16, 0xe6, 0x04, 0x05, + 0xf3, 0x51, 0x3e, 0xeb, 0xfa, 0xd5, 0x0e, 0xd7, 0x00, 0xfe, 0xfa, 0xd7, 0xe9, + 0x42, 0x03, 0xdf, 0x04, 0xe6, 0x16, 0xfa, 0xb6, 0x06, 0x06, 0xd6, 0xf8, 0xa2, + 0xce, 0x2c, 0xfb, 0xb7, 0x1c, 0xef, 0xe4, 0x1e, 0x33, 0xf7, 0xa9, 0x03, 0x60, + 0x2e, 0x5e, 0x1d, 0x08, 0x28, 0x44, 0xdd, 0xf3, 0xfd, 0xd1, 0x0b, 0xbd, 0xed, + 0xfc, 0x31, 0x26, 0x20, 0x52, 0xe7, 0x07, 0xa3, 0x12, 0xfe, 0x5c, 0x01, 0xbc, + 0xd8, 0x2f, 0xfd, 0x0e, 0xc9, 0xdc, 0x28, 0xfd, 0xf1, 0xd0, 0x10, 0xa2, 0xd0, + 0x0c, 0xda, 0x0d, 0xc9, 0xea, 0x02, 0x14, 0xc6, 0xed, 0xde, 0xde, 0xc1, 0xc9, + 0xcd, 0xe2, 0xd1, 0xf6, 0xd4, 0x38, 0x08, 0x20, 0xf3, 0xb5, 0xf8, 0xbb, 0x17, + 0xc0, 0x1d, 0xd3, 0x26, 0x3f, 0xe0, 0xfc, 0x9c, 0x15, 0xec, 0x3f, 0xdf, 0x3b, + 0xd9, 0x1b, 0x56, 0x9f, 0x35, 0xfd, 0xdc, 0x18, 0xfc, 0x9e, 0xe7, 0x29, 0x01, + 0x23, 0xb7, 0xf8, 0xf0, 0x54, 0xe4, 0x05, 0x00, 0x7f, 0xd9, 0xf7, 0x5b, 0xdf, + 0x13, 0xbf, 0xe5, 0xed, 0xe6, 0xff, 0x30, 0x16, 0x5f, 0x2f, 0xde, 0x5e, 0x08, + 0x28, 0xbd, 0x1e, 0x09, 0x53, 0xb5, 0x32, 0xf6, 0xd1, 0xe2, 0x04, 0xd7, 0x64, + 0xfb, 0xe2, 0xf9, 0xfc, 0x50, 0x1a, 0x23, 0xc1, 0x09, 0x31, 0x15, 0x50, 0x29, + 0xf9, 0x38, 0xe8, 0xbe, 0x7c, 0xbc, 0xe8, 0x3c, 0x2a, 0xdb, 0x09, 0xe2, 0xd5, + 0x3a, 0x52, 0x3d, 0xb6, 0xda, 0xdd, 0x22, 0xfc, 0xfc, 0xec, 0xed, 0x40, 0xd8, + 0x17, 0xae, 0xef, 0xf6, 0xdb, 0xe6, 0x7f, 0xfa, 0x16, 0x09, 0x11, 0x04, 0xfc, + 0x22, 0xbc, 0xde, 0x4d, 0xf9, 0x15, 0x52, 0xf9, 0x0b, 0xf4, 0x38, 0x23, 0xfb, + 0xa7, 0x29, 0xde, 0x2e, 0x34, 0x0c, 0x45, 0xff, 0x2a, 0x05, 0xb8, 0xed, 0xf9, + 0x22, 0x9d, 0x02, 0x36, 0x02, 0xd6, 0xad, 0x17, 0xe0, 0x2e, 0x38, 0x7e, 0x09, + 0x1b, 0xd4, 0x41, 0xfd, 0xe5, 0x0d, 0x2c, 0xe6, 0x0b, 0xf7, 0x00, 0xb3, 0x0e, + 0xff, 0xae, 0x21, 0xad, 0xd4, 0x28, 0xc1, 0x16, 0x48, 0x75, 0x01, 0xfe, 0xe6, + 0x49, 0xf0, 0xad, 0xcf, 0xd6, 0x02, 0xee, 0xdb, 0x16, 0xa4, 0xbc, 0x01, 0xe2, + 0x22, 0x17, 0xf1, 0x0e, 0xf2, 0xdb, 0xe1, 0xe2, 0x44, 0xe4, 0x19, 0xe6, 0x2f, + 0xe2, 0xf1, 0x2e, 0x36, 0x06, 0xa8, 0x2d, 0x22, 0xef, 0xeb, 0xd4, 0x69, 0x35, + 0xc1, 0x09, 0xd4, 0xc6, 0xc3, 0xd4, 0x7f, 0x37, 0xdf, 0xd5, 0xff, 0xf1, 0x89, + 0x22, 0x49, 0xba, 0x29, 0x28, 0x09, 0x0e, 0x48, 0x00, 0xec, 0xf1, 0x08, 0xeb, + 0x32, 0xe3, 0xf4, 0x04, 0xff, 0x24, 0xff, 0x70, 0xe0, 0xea, 0x17, 0xf2, 0x22, + 0xa5, 0x0a, 0x2b, 0x02, 0x06, 0x10, 0x18, 0x0a, 0x5d, 0xef, 0x58, 0x0a, 0xd2, + 0xe3, 0xa7, 0x24, 0x5f, 0x18, 0xd3, 0x16, 0x08, 0x36, 0xd9, 0xf5, 0x0c, 0xde, + 0xbd, 0xf5, 0x0e, 0xe0, 0xae, 0x21, 0x22, 0x6e, 0x24, 0xf9, 0xdd, 0x09, 0x29, + 0x5b, 0x0f, 0xdb, 0x1a, 0xa7, 0xd8, 0x13, 0xfa, 0xf1, 0x38, 0xef, 0x1b, 0x18, + 0x37, 0x11, 0x05, 0xf5, 0x13, 0x21, 0x30, 0x11, 0xcb, 0xe5, 0xf0, 0xdd, 0xf3, + 0x09, 0x08, 0x34, 0xfa, 0xee, 0xfe, 0x0f, 0x00, 0x7f, 0xed, 0x1b, 0x98, 0xce, + 0xcd, 0xc5, 0xec, 0x23, 0xf2, 0xe0, 0xe0, 0xdb, 0xea, 0xd0, 0xf7, 0xeb, 0x1d, + 0xd2, 0x47, 0x24, 0xfe, 0x13, 0xd1, 0xfd, 0xd3, 0x31, 0xc4, 0xd9, 0x28, 0x2d, + 0x1f, 0xe8, 0x1f, 0xfe, 0xe2, 0x06, 0xcf, 0xea, 0x1b, 0xc5, 0xed, 0xe3, 0xc0, + 0x1f, 0xe8, 0x04, 0xf5, 0xde, 0xda, 0xcc, 0x03, 0x1b, 0xf8, 0x15, 0x14, 0x09, + 0xf0, 0xcb, 0xbe, 0xfb, 0xc8, 0xef, 0x0e, 0xfa, 0x1b, 0x34, 0xe1, 0x14, 0x0d, + 0xfd, 0x0c, 0x07, 0xe9, 0x52, 0xb1, 0xec, 0xf6, 0xe7, 0xcc, 0xf1, 0xb4, 0xed, + 0xdc, 0xe7, 0xd9, 0x2a, 0x14, 0xec, 0xf5, 0x0c, 0xbf, 0xef, 0xf8, 0xd6, 0xb0, + 0x46, 0xda, 0xee, 0xd9, 0x11, 0x2b, 0x48, 0x2b, 0xd3, 0xc9, 0xcd, 0x0e, 0xa7, + 0x08, 0x05, 0xe4, 0x30, 0x14, 0xcc, 0xf0, 0x61, 0x16, 0xfb, 0x87, 0x01, 0x1e, + 0x68, 0x0b, 0x38, 0xe7, 0xad, 0x0e, 0x27, 0xe1, 0xc8, 0x37, 0xe3, 0x32, 0x46, + 0xf6, 0xdd, 0x32, 0xcd, 0xbd, 0xfd, 0xd4, 0xc7, 0x0b, 0xff, 0x19, 0xb9, 0xf6, + 0x53, 0x1b, 0xf1, 0xda, 0xfb, 0xa9, 0x17, 0xce, 0x35, 0x27, 0x2f, 0xa7, 0x33, + 0xf6, 0x0c, 0x0c, 0xec, 0xcb, 0xd3, 0x22, 0xe7, 0x81, 0x2a, 0x01, 0xd6, 0x29, + 0xf6, 0xf9, 0x0d, 0xfc, 0xf5, 0xc8, 0xf0, 0x07, 0xf9, 0xdd, 0x12, 0xd4, 0x33, + 0xfc, 0x1c, 0xfc, 0xcc, 0xcb, 0xa5, 0xfa, 0x64, 0xdd, 0x44, 0xe2, 0xfc, 0xf2, + 0xd4, 0x31, 0x66, 0x05, 0x2c, 0xe2, 0x1f, 0xd4, 0x49, 0xd8, 0xf7, 0xad, 0x4c, + 0xf2, 0xe2, 0x06, 0x1a, 0x00, 0x22, 0x21, 0x10, 0xa9, 0xec, 0xdd, 0xe4, 0x11, + 0x09, 0xf2, 0xf4, 0xf3, 0xcb, 0x26, 0x55, 0xf9, 0xdd, 0xd8, 0x23, 0x2a, 0x33, + 0x2c, 0x04, 0x17, 0xb4, 0xb8, 0x0e, 0xcc, 0xf4, 0x37, 0x2f, 0xe5, 0x40, 0x04, + 0x07, 0xe3, 0x0d, 0x18, 0x17, 0x0d, 0x18, 0x39, 0x2d, 0xd8, 0xf1, 0xb5, 0xea, + 0x1a, 0xfc, 0xd3, 0xe2, 0x00, 0x13, 0xf2, 0xc5, 0xe2, 0xe6, 0xae, 0xd6, 0x13, + 0xdf, 0xc0, 0xb2, 0xd2, 0x00, 0x39, 0x09, 0x27, 0xfb, 0x81, 0x01, 0xde, 0x2b, + 0xfe, 0x33, 0x39, 0xfb, 0xfe, 0xfe, 0xf1, 0x06, 0xc3, 0xe4, 0x00, 0xd3, 0xc6, + 0x1f, 0x4b, 0x0e, 0xaf, 0x03, 0x36, 0xe7, 0xdd, 0xe4, 0xfd, 0xc8, 0xf4, 0xcb, + 0x1a, 0xf4, 0x0f, 0x03, 0x2f, 0xe5, 0xcd, 0x30, 0xbc, 0x2a, 0x2a, 0xf0, 0xfb, + 0xd7, 0x4c, 0x30, 0xdf, 0xcc, 0xcb, 0xe8, 0xe4, 0xf9, 0x07, 0x17, 0xf2, 0x02, + 0xc6, 0xf2, 0x39, 0x37, 0xfa, 0x21, 0xe5, 0xe6, 0x1d, 0xfe, 0xfc, 0x31, 0xef, + 0xd0, 0x19, 0x28, 0x0e, 0x4e, 0x1d, 0x1b, 0x46, 0xef, 0xef, 0x40, 0xd7, 0xf9, + 0x05, 0x15, 0x16, 0xf4, 0x01, 0x15, 0xa0, 0x04, 0x06, 0xaf, 0xc8, 0xe0, 0x08, + 0x00, 0xd5, 0x0d, 0x35, 0x03, 0x15, 0xdd, 0xdc, 0xe6, 0x33, 0xa0, 0xe6, 0xdf, + 0x37, 0xc6, 0x25, 0xdb, 0xde, 0xff, 0xfe, 0xfc, 0xc1, 0x24, 0x03, 0x5e, 0xe5, + 0xd7, 0xc7, 0xb2, 0xdc, 0x9c, 0x30, 0x12, 0xe9, 0xef, 0xde, 0x30, 0x11, 0xfb, + 0xff, 0xd7, 0x26, 0xfa, 0xd2, 0x52, 0x25, 0xe4, 0x24, 0x31, 0x1c, 0xf9, 0x14, + 0xec, 0x98, 0x1c, 0xeb, 0x20, 0xc5, 0xed, 0x81, 0xed, 0x08, 0xf7, 0x85, 0x0b, + 0xee, 0xb2, 0xf6, 0x1a, 0xf1, 0x04, 0x11, 0xcf, 0xea, 0xe9, 0x02, 0xf1, 0x01, + 0x29, 0x4d, 0xc9, 0xf6, 0x57, 0xdf, 0xc6, 0x3c, 0x39, 0x1c, 0xee, 0x04, 0xbd, + 0x43, 0xe5, 0xc8, 0xec, 0x03, 0xb5, 0xd1, 0x4a, 0x01, 0x51, 0x02, 0xe1, 0xb6, + 0xfb, 0x03, 0xfa, 0xde, 0xae, 0xa2, 0xff, 0xda, 0x01, 0xf5, 0xfa, 0xf1, 0x21, + 0x55, 0x28, 0x05, 0xf1, 0xe7, 0x20, 0x06, 0x15, 0x12, 0xf3, 0xe6, 0xf7, 0x6b, + 0x22, 0xfb, 0xf1, 0xef, 0x4e, 0x64, 0x28, 0x1f, 0x81, 0xc2, 0xfe, 0xbc, 0x1c, + 0xce, 0xac, 0x14, 0x99, 0x13, 0x0f, 0xd6, 0x07, 0x08, 0x1d, 0x30, 0x2c, 0xfd, + 0x1e, 0x0e, 0xda, 0xcc, 0xdc, 0xcf, 0x0d, 0xbf, 0xf7, 0x25, 0xaf, 0x3e, 0xad, + 0xe0, 0x01, 0x26, 0x0c, 0xae, 0x1f, 0x04, 0xf3, 0xbe, 0xf4, 0xc8, 0x4e, 0x02, + 0xcb, 0xf7, 0xec, 0xbb, 0x18, 0x3a, 0x44, 0xe1, 0xea, 0x05, 0xf7, 0x6f, 0x2a, + 0xa5, 0x3c, 0xf1, 0xfd, 0x7c, 0x22, 0xfa, 0xed, 0x23, 0xce, 0x0e, 0xd8, 0xee, + 0x29, 0x0f, 0xfc, 0x2d, 0x14, 0xd4, 0xe8, 0xed, 0xe6, 0xfb, 0x0d, 0xf4, 0xf9, + 0xff, 0xfc, 0x0a, 0xef, 0x2e, 0x14, 0x19, 0xe9, 0xbe, 0x7e, 0x30, 0x25, 0x6f, + 0x22, 0xd2, 0x11, 0xee, 0x10, 0xbe, 0xec, 0xdf, 0xa4, 0x28, 0xe3, 0xd0, 0xfe, + 0xe0, 0x07, 0x1d, 0x18, 0x91, 0x20, 0xf4, 0xac, 0x06, 0x0d, 0x36, 0x3f, 0x0b, + 0x15, 0x03, 0xb7, 0xce, 0x14, 0xec, 0x0f, 0xe1, 0xe1, 0x14, 0xaa, 0xda, 0x0e, + 0xeb, 0x0b, 0x06, 0xe8, 0x2b, 0x34, 0x0d, 0x2c, 0x38, 0x27, 0xb9, 0x70, 0x1d, + 0xfe, 0x4e, 0xf8, 0x16, 0x3a, 0x07, 0x4c, 0x27, 0x10, 0x45, 0xe2, 0xd9, 0x4b, + 0xec, 0xab, 0xa2, 0x02, 0xcb, 0x5d, 0xe2, 0x4d, 0x5b, 0x94, 0xf1, 0x6c, 0x20, + 0xc9, 0x00, 0xf6, 0x03, 0xfa, 0xef, 0x3a, 0x06, 0xe9, 0x30, 0xed, 0x11, 0xdd, + 0xdb, 0x15, 0xc3, 0x08, 0x4f, 0x59, 0x8e, 0xaf, 0x30, 0x29, 0x81, 0xdf, 0xe9, + 0xe6, 0xdb, 0xf8, 0x38, 0x40, 0x99, 0x5d, 0xeb, 0xc9, 0x0a, 0x17, 0x51, 0xc8, + 0x1b, 0xfb, 0x0a, 0xc1, 0xf0, 0x28, 0xf7, 0xa2, 0xf0, 0xc9, 0x34, 0xe6, 0xc0, + 0x8a, 0xf9, 0x06, 0x3c, 0xe3, 0xb9, 0xf7, 0x09, 0xec, 0xcd, 0x39, 0xd8, 0x03, + 0xc3, 0xf6, 0x0c, 0xe1, 0x04, 0xa2, 0x12, 0xc3, 0xe9, 0xd3, 0x05, 0x7f, 0x55, + 0xd0, 0xdb, 0x5c, 0x15, 0xef, 0xfc, 0x16, 0xcf, 0xc8, 0xd5, 0x1f, 0xfe, 0x5f, + 0x02, 0x51, 0x0c, 0x22, 0xff, 0xd7, 0x2c, 0xeb, 0x34, 0x19, 0x51, 0xfc, 0xe5, + 0xed, 0x37, 0xfd, 0xc5, 0x1c, 0xde, 0xd3, 0xf0, 0xd4, 0xf1, 0x07, 0xee, 0x3c, + 0xf2, 0xdc, 0xf0, 0xe3, 0x0f, 0x06, 0x32, 0x6d, 0xef, 0xc5, 0xe4, 0xda, 0x96, + 0xfe, 0xe1, 0x56, 0x00, 0xda, 0xf0, 0x2f, 0xd4, 0xe6, 0xe2, 0x15, 0xee, 0xfc, + 0xec, 0x3c, 0x25, 0xed, 0x2e, 0xcc, 0xd5, 0xe9, 0x91, 0xf8, 0xff, 0xf1, 0x59, + 0xd8, 0x0e, 0xe4, 0x18, 0xd1, 0xb6, 0x42, 0xef, 0x06, 0x02, 0x02, 0xce, 0xe3, + 0xf9, 0xe9, 0xd7, 0xe3, 0xfb, 0xd1, 0x2d, 0xf3, 0x17, 0xd5, 0x37, 0xd5, 0x2b, + 0xf4, 0xc7, 0x00, 0x1a, 0x2e, 0xff, 0xff, 0x0e, 0xce, 0x15, 0x00, 0x19, 0x2f, + 0x12, 0xf9, 0x25, 0x4a, 0xd3, 0xd6, 0xed, 0xa9, 0xe0, 0xd6, 0xff, 0x33, 0xfb, + 0x51, 0x0b, 0xe5, 0x4f, 0xda, 0x39, 0x42, 0xb4, 0x34, 0xee, 0xd2, 0x20, 0xf9, + 0x50, 0xd9, 0xff, 0xf2, 0x77, 0x12, 0xf6, 0x66, 0x1e, 0xe0, 0xb9, 0xfb, 0xb7, + 0x2a, 0xec, 0x03, 0x24, 0xdc, 0xed, 0xfa, 0xf4, 0xd2, 0xd6, 0xd6, 0xec, 0xfb, + 0xf9, 0x27, 0x54, 0xd9, 0x43, 0x0f, 0xfb, 0xfa, 0x01, 0xcf, 0xf1, 0x03, 0x0b, + 0x3b, 0xcd, 0x56, 0x14, 0x29, 0x00, 0xb6, 0x01, 0x48, 0xf9, 0xf8, 0x02, 0xf4, + 0x44, 0x7f, 0xf1, 0x1c, 0xeb, 0xac, 0x18, 0x14, 0xd0, 0x12, 0xef, 0x22, 0xf1, + 0x04, 0x09, 0xf4, 0xfa, 0xc2, 0x54, 0xdf, 0x31, 0xe1, 0x0a, 0xf3, 0xaf, 0x18, + 0x06, 0x36, 0xd8, 0x2d, 0x14, 0xbe, 0xe9, 0xe6, 0xe4, 0xfb, 0x0f, 0x2c, 0x18, + 0x01, 0x33, 0xf8, 0xeb, 0xed, 0xb8, 0xf0, 0x05, 0x05, 0xd7, 0xe3, 0xf5, 0xf6, + 0x09, 0x13, 0x0e, 0x02, 0xfb, 0xff, 0xe4, 0x08, 0x17, 0xf9, 0x1f, 0x13, 0xe6, + 0xf3, 0x7f, 0x0c, 0xae, 0xe5, 0x07, 0xf4, 0x27, 0x25, 0x45, 0x08, 0xc0, 0xa9, + 0x0f, 0x12, 0x2b, 0xe5, 0x6f, 0x26, 0x28, 0xe0, 0x1f, 0xee, 0x39, 0xeb, 0x32, + 0x0a, 0x12, 0x28, 0x16, 0x05, 0xe9, 0xe8, 0x16, 0xe9, 0x0a, 0xfc, 0x22, 0xe9, + 0x06, 0x00, 0x3d, 0x1a, 0x2b, 0x16, 0xaa, 0x0f, 0xfe, 0x01, 0x11, 0xda, 0x2b, + 0xea, 0xf3, 0xc7, 0x37, 0xea, 0xd7, 0xef, 0x2a, 0xd1, 0x26, 0x3b, 0xfa, 0xbe, + 0x04, 0xc3, 0xd5, 0xe6, 0x65, 0x4b, 0x0c, 0xfc, 0x1e, 0x32, 0x1c, 0x47, 0xe8, + 0x19, 0x05, 0xd9, 0x0e, 0xe7, 0xfc, 0xff, 0xb6, 0xe4, 0x1f, 0x15, 0x3a, 0x0d, + 0xbf, 0x07, 0xf1, 0x74, 0xef, 0x81, 0xe6, 0x38, 0x23, 0xe5, 0x24, 0xcc, 0x11, + 0x38, 0xec, 0x3d, 0xd1, 0x02, 0xdc, 0xd2, 0x0c, 0x14, 0x17, 0xff, 0xfc, 0xe7, + 0x13, 0xe1, 0x0a, 0xed, 0x28, 0x23, 0x14, 0xe5, 0x5d, 0xdd, 0x02, 0x46, 0xe0, + 0xe2, 0x2d, 0xf6, 0xfe, 0xc9, 0x0a, 0xc4, 0xe9, 0xba, 0xb2, 0x27, 0xc7, 0xfc, + 0x45, 0xc4, 0x92, 0xd0, 0xaf, 0x0e, 0xc3, 0x1a, 0xfd, 0xfa, 0x00, 0xc8, 0xfa, + 0xb0, 0xfb, 0x10, 0xd9, 0x23, 0x2a, 0xe2, 0x2c, 0x50, 0xf9, 0x2a, 0xe1, 0xf9, + 0x1a, 0xd0, 0xe5, 0xe2, 0xfe, 0xe9, 0x3e, 0x13, 0x28, 0xee, 0xe1, 0x29, 0xff, + 0xc2, 0x0d, 0xe7, 0x21, 0x47, 0xe5, 0x51, 0x0a, 0xdb, 0x8c, 0xef, 0x0e, 0x2c, + 0xf1, 0xeb, 0x15, 0x0e, 0xf2, 0x0f, 0xfa, 0xdd, 0xaf, 0x23, 0x33, 0xf0, 0x10, + 0x3d, 0x16, 0x0b, 0xff, 0x46, 0xdb, 0xe7, 0x12, 0xa4, 0x17, 0x1e, 0xbf, 0xdc, + 0x20, 0x12, 0xea, 0x1c, 0x19, 0x5d, 0x71, 0x32, 0xe2, 0xfe, 0x01, 0x35, 0x3b, + 0xf8, 0x8e, 0xfe, 0x3e, 0x4b, 0xd2, 0xfb, 0xcc, 0xd9, 0xc9, 0xf2, 0xf5, 0x04, + 0x30, 0x22, 0xe0, 0xf2, 0xc0, 0x05, 0x05, 0xd5, 0xee, 0x40, 0xa6, 0x91, 0x40, + 0x58, 0x20, 0xce, 0xa8, 0xd6, 0x61, 0xec, 0x1b, 0xec, 0xf3, 0x42, 0xb1, 0xfd, + 0xd9, 0xc3, 0x92, 0xd6, 0xcf, 0x1f, 0xfc, 0xd8, 0x59, 0x23, 0x0b, 0xc2, 0xf1, + 0x55, 0x05, 0xf0, 0x27, 0x32, 0x49, 0x62, 0x06, 0x26, 0x0d, 0xfc, 0xe0, 0xcf, + 0x1f, 0xcd, 0x81, 0xc1, 0x05, 0xeb, 0x15, 0xce, 0x54, 0x10, 0xd3, 0x57, 0xd4, + 0xf4, 0x29, 0x10, 0xe5, 0x2c, 0x3f, 0xf4, 0xa6, 0xf5, 0xed, 0x06, 0xf5, 0x0d, + 0xcc, 0xff, 0x2b, 0x0a, 0xe5, 0xe3, 0x0c, 0xe2, 0x28, 0x50, 0x22, 0x18, 0xe0, + 0x0b, 0xbf, 0x0d, 0x0e, 0xec, 0xdf, 0xf9, 0x10, 0xf6, 0x1c, 0x0a, 0xf3, 0x17, + 0xe9, 0xd2, 0x3c, 0x1c, 0x16, 0x06, 0xe7, 0x38, 0xd0, 0xed, 0x05, 0x1c, 0xc5, + 0xf8, 0xec, 0x10, 0xf7, 0xc1, 0xda, 0x1b, 0xda, 0x0d, 0xf5, 0xe3, 0x15, 0xf8, + 0xea, 0xdb, 0xd4, 0x21, 0x07, 0x10, 0x19, 0x45, 0x66, 0xd1, 0x15, 0x09, 0x1f, + 0xec, 0x19, 0xd6, 0x18, 0x0a, 0xe3, 0xee, 0xf5, 0xf9, 0xfb, 0xdd, 0x01, 0xec, + 0x33, 0xfe, 0xed, 0xd3, 0xe0, 0xf0, 0x78, 0x07, 0xe9, 0xf8, 0xc9, 0x7f, 0x2d, + 0xbe, 0xf5, 0xf0, 0x10, 0x23, 0x20, 0x08, 0xea, 0xe9, 0xb3, 0xe7, 0x0d, 0xea, + 0x2f, 0xef, 0x1d, 0xfd, 0xff, 0x01, 0x0a, 0x1c, 0x09, 0xd7, 0x0f, 0xf9, 0x00, + 0xed, 0xd0, 0xf6, 0xd4, 0xdc, 0x1b, 0x0a, 0xe9, 0x38, 0x06, 0xed, 0x32, 0xf8, + 0xee, 0x15, 0xe1, 0x13, 0x1c, 0x13, 0x0b, 0xbb, 0x21, 0x05, 0x0b, 0xcb, 0xfe, + 0xf3, 0xdb, 0xf7, 0xf5, 0xd7, 0x25, 0xfb, 0xd1, 0x07, 0x00, 0xa8, 0x12, 0x1f, + 0x0b, 0xd3, 0x41, 0x17, 0xe7, 0xfe, 0xea, 0x14, 0xfc, 0xf3, 0x45, 0xf8, 0xcd, + 0x09, 0x5b, 0xc9, 0xdb, 0x9e, 0xfd, 0x2c, 0x10, 0x04, 0x27, 0x4c, 0x08, 0x0a, + 0xb6, 0xe8, 0xc1, 0xda, 0x03, 0xaa, 0x7f, 0xfc, 0xde, 0xc1, 0x2d, 0xd9, 0x13, + 0xe6, 0x18, 0x05, 0xe8, 0xee, 0xfc, 0x4c, 0xcf, 0xe4, 0x1d, 0xcd, 0xbd, 0xaf, + 0x04, 0xda, 0xf5, 0xcc, 0xfa, 0x1e, 0xea, 0xdf, 0xb7, 0x03, 0x43, 0xfb, 0xf7, + 0x42, 0x53, 0xac, 0x09, 0x02, 0x41, 0x42, 0x04, 0x05, 0x26, 0x82, 0x98, 0xe7, + 0x2e, 0x28, 0x16, 0x01, 0x43, 0xe0, 0xd4, 0x34, 0xf2, 0xd9, 0x20, 0x60, 0x00, + 0x15, 0x1f, 0x27, 0xa9, 0x33, 0xcb, 0x08, 0x19, 0xde, 0xaf, 0x21, 0x24, 0x06, + 0xec, 0xfc, 0x05, 0x1b, 0xcf, 0xe4, 0x3d, 0x22, 0xec, 0xfa, 0xd6, 0x0b, 0xf6, + 0x15, 0xf8, 0xf4, 0x05, 0xec, 0xe9, 0x32, 0xe3, 0x19, 0x30, 0x29, 0xf8, 0x15, + 0xf4, 0xeb, 0xae, 0x4d, 0x15, 0x32, 0xf8, 0xf9, 0xe5, 0x19, 0x08, 0x2f, 0xe1, + 0x31, 0xf9, 0x17, 0xbf, 0xee, 0x11, 0x14, 0xb6, 0x08, 0x08, 0xf2, 0xd4, 0x17, + 0xfb, 0x2e, 0x7f, 0x09, 0xea, 0xdf, 0xf9, 0xff, 0x0e, 0xef, 0xbc, 0xe3, 0xc4, + 0x37, 0xf9, 0xcf, 0xca, 0x03, 0xcf, 0x06, 0x2c, 0xc0, 0x16, 0xd6, 0xc9, 0x0e, + 0xe5, 0x3c, 0x02, 0x5e, 0x02, 0x19, 0x33, 0x1c, 0x02, 0xf0, 0xf0, 0xf4, 0x03, + 0x0a, 0x6b, 0x1f, 0xf9, 0xfa, 0x06, 0xe6, 0x11, 0x10, 0x0d, 0xde, 0x22, 0x10, + 0xb5, 0x26, 0xf7, 0xfa, 0xfd, 0x16, 0x7b, 0xc1, 0xf8, 0x1c, 0x10, 0x0e, 0xf4, + 0xfb, 0xf8, 0x0b, 0xfa, 0xf9, 0x0a, 0x45, 0xcb, 0xff, 0x14, 0x42, 0xf6, 0xec, + 0xdb, 0x54, 0x09, 0x1b, 0x35, 0xd1, 0x62, 0xdf, 0xdd, 0xb4, 0x2a, 0x0b, 0x41, + 0x19, 0x2c, 0xde, 0xf1, 0xf6, 0xd6, 0x5f, 0xc0, 0xd8, 0x49, 0xeb, 0xe6, 0x2e, + 0x0b, 0xff, 0x57, 0x26, 0x3e, 0x0f, 0xfd, 0x21, 0xe0, 0x1e, 0xc9, 0x93, 0x7f, + 0x18, 0xfd, 0xe8, 0x1c, 0x23, 0x1f, 0x51, 0x17, 0xc5, 0xf1, 0x16, 0x03, 0x24, + 0xf6, 0xfa, 0x1d, 0xf1, 0xea, 0xf7, 0x38, 0x00, 0xfc, 0xc0, 0xe7, 0xfb, 0x10, + 0x11, 0xe2, 0x01, 0xe5, 0xb7, 0xfe, 0x23, 0xc7, 0x0f, 0x35, 0x0f, 0x63, 0x05, + 0x31, 0x04, 0x0d, 0xd9, 0x06, 0xdc, 0x16, 0x09, 0x36, 0x11, 0x01, 0x00, 0x3d, + 0x15, 0x11, 0xdf, 0xef, 0xd1, 0xf1, 0xf5, 0x04, 0x28, 0xd4, 0x14, 0xe5, 0x0d, + 0xd7, 0x14, 0x47, 0xfb, 0xf8, 0xd4, 0xf7, 0x39, 0x05, 0x14, 0x26, 0x19, 0x1d, + 0xff, 0x09, 0x0e, 0x02, 0xfd, 0xf9, 0xc3, 0x6f, 0xcf, 0xf7, 0x50, 0x00, 0x3d, + 0x1e, 0xed, 0x11, 0xeb, 0x31, 0x03, 0x1e, 0xf8, 0xc3, 0xe9, 0x37, 0xa6, 0x2a, + 0x81, 0xfd, 0x11, 0x1e, 0xa5, 0xbd, 0xe6, 0x06, 0xe2, 0xb9, 0x0f, 0x24, 0xf2, + 0x13, 0xca, 0xb1, 0xc8, 0x17, 0xa2, 0xc3, 0xe1, 0x30, 0xe6, 0x1c, 0x13, 0x14, + 0xf8, 0x1e, 0x25, 0x1f, 0xd6, 0x3c, 0x02, 0x04, 0x44, 0xea, 0x22, 0x22, 0xd2, + 0xee, 0xe8, 0xfa, 0x56, 0x4f, 0x6b, 0xfb, 0xf3, 0x09, 0x9a, 0xdb, 0x23, 0x02, + 0xcb, 0xc3, 0x1d, 0xd4, 0x1c, 0x02, 0xfa, 0x0a, 0xff, 0x13, 0xe8, 0x29, 0x04, + 0x1c, 0x48, 0xe8, 0x35, 0x18, 0x28, 0xfa, 0x16, 0xed, 0xeb, 0x05, 0xa0, 0xca, + 0x11, 0x4a, 0xe1, 0x25, 0xd9, 0x04, 0x10, 0x00, 0x15, 0x3c, 0x1e, 0x14, 0xc0, + 0x3a, 0x15, 0x3e, 0x1c, 0xf4, 0x0e, 0x26, 0xbe, 0x23, 0xff, 0x07, 0x24, 0xd6, + 0xee, 0xf1, 0xdf, 0x2c, 0x07, 0xe0, 0xcd, 0xee, 0x0e, 0xec, 0x02, 0xdf, 0x28, + 0xff, 0xc2, 0x20, 0x2b, 0xcc, 0x1e, 0xdd, 0xfe, 0xf3, 0x4e, 0x07, 0x1b, 0x1a, + 0xea, 0x44, 0x16, 0xc7, 0xff, 0x3c, 0xb6, 0xf4, 0xef, 0x58, 0xe0, 0xdc, 0x36, + 0x15, 0xcb, 0xfd, 0x63, 0x08, 0x04, 0x68, 0xd9, 0x94, 0xb1, 0xee, 0x49, 0xf6, + 0xb5, 0xf1, 0x28, 0xfc, 0x37, 0x84, 0x07, 0x35, 0xdd, 0x14, 0x23, 0x06, 0xff, + 0x30, 0x22, 0x48, 0xb8, 0x41, 0x0f, 0x15, 0x18, 0xef, 0xbe, 0xa2, 0xa5, 0x7d, + 0xec, 0xb9, 0xf5, 0xdd, 0x72, 0xfc, 0x06, 0x01, 0x1b, 0xda, 0xc3, 0xdb, 0x15, + 0x0b, 0x04, 0xd1, 0x05, 0xe9, 0xe2, 0xd5, 0x4a, 0xe9, 0x56, 0x47, 0x25, 0xd3, + 0x7b, 0x15, 0xf5, 0xf2, 0x32, 0x07, 0xe9, 0x7f, 0x57, 0xd5, 0x29, 0xf7, 0x45, + 0x1a, 0x17, 0x00, 0x14, 0xae, 0xd3, 0x0c, 0x19, 0x10, 0x3d, 0xdf, 0xf7, 0x15, + 0xe2, 0x0f, 0xf5, 0x02, 0xe4, 0xb3, 0xf1, 0xe4, 0xb1, 0xd7, 0x2c, 0x09, 0x38, + 0x01, 0x15, 0xfc, 0xcb, 0x06, 0x08, 0x08, 0xee, 0x1b, 0xd9, 0xb7, 0x10, 0xfc, + 0x4f, 0xc0, 0xe1, 0x1a, 0x5f, 0xad, 0x52, 0x42, 0xe8, 0xdf, 0xd8, 0xcc, 0x7f, + 0x5a, 0x3e, 0x2e, 0x14, 0x3d, 0xfd, 0x38, 0xd1, 0xd9, 0x13, 0xfe, 0x03, 0xf8, + 0x4c, 0xea, 0x31, 0x1b, 0xef, 0x16, 0x3b, 0xfc, 0xc0, 0xcc, 0x67, 0xff, 0xde, + 0x1d, 0x41, 0x52, 0xd3, 0x26, 0x10, 0x0a, 0x46, 0x08, 0x34, 0x46, 0xf1, 0x4a, + 0x07, 0x06, 0xd8, 0xdb, 0x3d, 0xf4, 0xc8, 0x65, 0xbb, 0xee, 0xe1, 0x18, 0xe3, + 0xf3, 0x11, 0x4e, 0x33, 0x4e, 0x07, 0xfc, 0xbd, 0x0c, 0x28, 0xbd, 0xfb, 0xe2, + 0xe4, 0xc4, 0x01, 0x24, 0x0a, 0xec, 0xc7, 0x09, 0xab, 0x41, 0x06, 0x0b, 0x57, + 0xed, 0x20, 0xad, 0x70, 0xab, 0x47, 0xf1, 0xb7, 0xf8, 0xab, 0x47, 0x19, 0x37, + 0xdf, 0x01, 0x21, 0x01, 0x2e, 0x2f, 0xdb, 0x1c, 0x1d, 0xce, 0xd1, 0x19, 0x21, + 0xd2, 0xfc, 0x5c, 0x52, 0xee, 0x1f, 0xfe, 0x3e, 0x1f, 0x23, 0xd2, 0xf2, 0x03, + 0x0e, 0xcc, 0xfa, 0x16, 0x06, 0x0b, 0x07, 0x0e, 0x06, 0x08, 0x16, 0xdc, 0x17, + 0x01, 0xc6, 0x01, 0x2a, 0xb5, 0xfe, 0x25, 0xe9, 0x7f, 0xe9, 0xee, 0xde, 0xad, + 0x16, 0x0d, 0x04, 0xbd, 0xf2, 0x24, 0x1d, 0x11, 0xfe, 0xb8, 0xfa, 0xd0, 0xf2, + 0xdd, 0x20, 0xe2, 0x12, 0x12, 0x0f, 0x31, 0x2d, 0xc3, 0xd3, 0x0d, 0x23, 0x24, + 0xcb, 0x19, 0x07, 0x20, 0x21, 0xdf, 0x00, 0x01, 0x3f, 0x26, 0x1e, 0x03, 0x10, + 0xff, 0x3a, 0xf0, 0xb4, 0x32, 0x11, 0xe0, 0x01, 0x07, 0xfe, 0xde, 0xeb, 0xff, + 0xd0, 0x07, 0x0f, 0xea, 0x3a, 0x02, 0xf0, 0x22, 0x1c, 0xf8, 0x0a, 0x10, 0xea, + 0xf5, 0x3b, 0xed, 0x0a, 0x24, 0xfd, 0x01, 0xd1, 0xf5, 0x07, 0xfd, 0x16, 0xa7, + 0x21, 0xd1, 0xef, 0x0d, 0x19, 0x13, 0xd6, 0x21, 0x5e, 0x10, 0xe3, 0xed, 0x07, + 0x38, 0xcf, 0x43, 0xd8, 0x0c, 0x0a, 0x31, 0xdb, 0x52, 0xc0, 0xf9, 0xcc, 0xfc, + 0xe5, 0xcc, 0xd6, 0x06, 0xfb, 0xad, 0x24, 0x2e, 0xdc, 0x9b, 0xfb, 0x35, 0xf4, + 0xf1, 0xe6, 0x10, 0xbe, 0xe4, 0x13, 0xef, 0x95, 0xc5, 0x45, 0xdb, 0x1e, 0x5a, + 0x24, 0xf5, 0x0c, 0xfa, 0xfa, 0xdf, 0x3b, 0xfe, 0x41, 0x35, 0x00, 0xd7, 0xe8, + 0xf0, 0xf1, 0xae, 0xc8, 0xe7, 0x5c, 0x7a, 0xa8, 0x0f, 0x34, 0x57, 0x29, 0xe6, + 0x2a, 0x23, 0x47, 0x25, 0x04, 0x24, 0xc9, 0x7f, 0xee, 0x29, 0xfb, 0xcd, 0x3d, + 0x2a, 0x32, 0x2b, 0xed, 0x2f, 0xe2, 0x12, 0x30, 0x23, 0xda, 0x15, 0x13, 0xed, + 0x60, 0x2e, 0xdf, 0x0d, 0xef, 0xa9, 0x08, 0xd1, 0xe4, 0x37, 0xc1, 0xfa, 0x06, + 0x41, 0x3f, 0xe2, 0x1b, 0x59, 0xdb, 0xa1, 0x20, 0xae, 0xf2, 0xdc, 0xa3, 0xd6, + 0x0f, 0xfa, 0xfb, 0xe7, 0x33, 0xff, 0xf3, 0x56, 0x01, 0x2a, 0xd8, 0x48, 0x93, + 0xc1, 0xc7, 0x00, 0xe7, 0x37, 0x06, 0x00, 0xf3, 0xa3, 0x50, 0xc0, 0xeb, 0x23, + 0xc3, 0x1f, 0xc6, 0xf9, 0xfd, 0xb8, 0xf3, 0xe3, 0xc7, 0xdc, 0xe3, 0xea, 0xdb, + 0xd4, 0xcd, 0xb2, 0x06, 0xd5, 0x22, 0xd5, 0x28, 0xee, 0x2a, 0x7f, 0x3f, 0xdb, + 0xf1, 0xea, 0xf2, 0x2a, 0xb3, 0x10, 0x1a, 0x19, 0x4d, 0xe5, 0xe5, 0xd9, 0xb9, + 0x9e, 0x12, 0xe6, 0x3e, 0xd4, 0x1c, 0xf9, 0xd2, 0xed, 0x32, 0x2e, 0x3e, 0xdc, + 0x17, 0xd5, 0xd1, 0x08, 0x02, 0x12, 0x2a, 0xeb, 0xec, 0x0c, 0x08, 0x1f, 0x1e, + 0x03, 0xd0, 0x23, 0x17, 0x9c, 0x09, 0x1d, 0xf1, 0xd7, 0x05, 0x27, 0x1e, 0x04, + 0xd9, 0xf9, 0xde, 0xe7, 0x3a, 0x37, 0xc8, 0x09, 0x50, 0x14, 0x0a, 0x05, 0x17, + 0x09, 0xb3, 0xcc, 0x20, 0x1b, 0x26, 0x11, 0x5d, 0x15, 0xf0, 0xff, 0x0d, 0x05, + 0xc7, 0xde, 0xe5, 0x09, 0xde, 0x27, 0x23, 0x0a, 0xf3, 0xb3, 0xff, 0x00, 0x42, + 0xd0, 0xe6, 0x0a, 0xee, 0xe2, 0x42, 0xc7, 0xd7, 0x37, 0x4d, 0xca, 0x03, 0x0d, + 0x12, 0xcf, 0x0f, 0xb7, 0x15, 0xf4, 0xbf, 0xea, 0x3a, 0xf3, 0x19, 0xf0, 0x28, + 0xe7, 0x0e, 0x04, 0xd4, 0xe0, 0x05, 0x02, 0xd6, 0xf9, 0x36, 0xfc, 0xe4, 0xf4, + 0x09, 0x1d, 0xbf, 0xcb, 0x06, 0xe0, 0xca, 0x00, 0xee, 0xd6, 0xea, 0xf4, 0xce, + 0x18, 0xfb, 0x32, 0x1d, 0x02, 0xf5, 0xe3, 0xe6, 0x16, 0x41, 0xe5, 0x4f, 0x38, + 0x05, 0xe4, 0xda, 0xf8, 0x81, 0x01, 0xaf, 0xfc, 0x06, 0xb4, 0x2c, 0x0c, 0x1a, + 0xda, 0xfc, 0xaf, 0x26, 0xec, 0xe6, 0xed, 0x16, 0x02, 0xf9, 0x29, 0x13, 0xda, + 0xbb, 0xe1, 0x20, 0xcf, 0x0a, 0xfc, 0x01, 0x36, 0xcd, 0x47, 0x00, 0xdb, 0xff, + 0x08, 0xf4, 0xfc, 0x2a, 0x52, 0xfb, 0xf1, 0x03, 0xd3, 0xee, 0xd3, 0xdf, 0xe0, + 0x07, 0x2e, 0xe7, 0xda, 0xfd, 0x0a, 0x27, 0xcf, 0x09, 0xf0, 0xbd, 0xec, 0xf8, + 0xea, 0x03, 0x22, 0x3f, 0xda, 0x07, 0xe8, 0x28, 0xd7, 0x12, 0x0c, 0x03, 0x11, + 0xf3, 0x2e, 0xd2, 0xe3, 0xe1, 0x4d, 0xe6, 0x06, 0xe8, 0xde, 0xed, 0xc1, 0x36, + 0xe6, 0x17, 0xd6, 0xf4, 0xd0, 0x04, 0xfe, 0xfb, 0xea, 0x02, 0x45, 0xc8, 0xb5, + 0x54, 0xfe, 0xde, 0xf6, 0xf9, 0xec, 0x0d, 0xd7, 0xf5, 0xc4, 0x81, 0xc8, 0x29, + 0x11, 0xc4, 0x1a, 0x1c, 0x19, 0x32, 0xd1, 0xbe, 0x0f, 0xfc, 0xf6, 0x50, 0xe5, + 0x4a, 0x31, 0x03, 0x06, 0xee, 0x1d, 0x54, 0x0c, 0xf6, 0x3a, 0xc2, 0xe7, 0x25, + 0x2d, 0x18, 0xf9, 0xfe, 0x07, 0xe5, 0x0d, 0xc0, 0xac, 0x4b, 0xe7, 0xa0, 0xad, + 0x34, 0x50, 0x45, 0xdc, 0xe9, 0xe3, 0x18, 0xcc, 0xb9, 0xfe, 0xc2, 0xf2, 0xf8, + 0xe7, 0x07, 0x4c, 0xea, 0x53, 0xfe, 0x14, 0xed, 0x08, 0xd2, 0x5d, 0x31, 0x0f, + 0x15, 0x05, 0x01, 0xc7, 0x03, 0x0b, 0xc6, 0xff, 0xde, 0xf5, 0x9c, 0xc5, 0x19, + 0x41, 0xf9, 0xf0, 0x0d, 0xdd, 0xdf, 0x24, 0x0c, 0x90, 0x17, 0x4e, 0xd9, 0xce, + 0xd9, 0xc8, 0xd7, 0x0e, 0x09, 0x3c, 0x0b, 0xb7, 0xea, 0xf2, 0x3f, 0xc4, 0xa8, + 0xd5, 0x02, 0xdf, 0xda, 0xe5, 0xf9, 0xfe, 0x19, 0x0c, 0xd2, 0x07, 0x0d, 0xb7, + 0x4b, 0x1e, 0x10, 0x08, 0xf5, 0x45, 0xf3, 0x04, 0x3c, 0xdc, 0xe9, 0xde, 0xec, + 0xc1, 0x05, 0x1a, 0xd4, 0xff, 0x10, 0xbf, 0x3f, 0xf7, 0x2b, 0x17, 0xea, 0xe6, + 0xdc, 0x16, 0x24, 0x0d, 0x07, 0x0e, 0x3c, 0xf4, 0x21, 0xcc, 0x09, 0xcc, 0x42, + 0x26, 0xc8, 0xcc, 0xfd, 0x19, 0xef, 0xef, 0x07, 0xf6, 0xfe, 0x0e, 0x2f, 0x31, + 0x43, 0xfe, 0x29, 0xc1, 0xcf, 0x35, 0xc1, 0x10, 0xff, 0xce, 0x22, 0x07, 0x0d, + 0x13, 0xee, 0x7f, 0x13, 0x00, 0x02, 0xef, 0x06, 0xf0, 0xde, 0x1a, 0x1c, 0xe7, + 0xfa, 0xcd, 0x17, 0x23, 0xc3, 0xba, 0xfe, 0xba, 0xea, 0x21, 0x09, 0x20, 0x00, + 0x22, 0xf7, 0x15, 0x46, 0xbd, 0xce, 0xc2, 0xfb, 0x12, 0xf2, 0xf0, 0x52, 0xd3, + 0x0f, 0x45, 0xde, 0xe9, 0xe8, 0x1f, 0x0b, 0x02, 0x2c, 0xe1, 0xea, 0x54, 0x03, + 0x0f, 0x0d, 0xd7, 0xf3, 0x13, 0x36, 0xfc, 0xd2, 0xc2, 0xe6, 0xed, 0xa1, 0x81, + 0xdd, 0x22, 0xd0, 0x31, 0xa8, 0xd2, 0xcb, 0x39, 0x10, 0xb7, 0xea, 0x99, 0xb6, + 0xde, 0xe7, 0x1c, 0x28, 0xf7, 0x07, 0x27, 0xe2, 0xf3, 0x60, 0xe9, 0x11, 0x22, + 0xfa, 0x0f, 0xe5, 0xd8, 0xe4, 0x19, 0xeb, 0x04, 0xcd, 0x0c, 0x8e, 0x63, 0x07, + 0xf0, 0xe4, 0xc6, 0xda, 0x3e, 0x31, 0xe0, 0x30, 0xcf, 0xe2, 0x04, 0xec, 0x69, + 0x4b, 0xa9, 0x0d, 0xc2, 0xf3, 0xc9, 0x25, 0xec, 0xe4, 0x25, 0x18, 0x64, 0xf4, + 0x2c, 0xea, 0xe1, 0x18, 0x33, 0x07, 0xd9, 0x22, 0x08, 0x0c, 0x26, 0x03, 0x2c, + 0x0f, 0x15, 0x0f, 0x3b, 0xc2, 0xe2, 0xf6, 0x52, 0x12, 0xcd, 0xd3, 0xda, 0x1d, + 0x35, 0x41, 0xd9, 0x2d, 0xfe, 0xe4, 0x0b, 0x0d, 0xa8, 0x15, 0x03, 0xce, 0x14, + 0xbe, 0x2c, 0x81, 0xd7, 0xfa, 0x2e, 0xaa, 0x4f, 0xe0, 0xc9, 0x0f, 0x0f, 0xde, + 0x17, 0x2f, 0x37, 0x4b, 0xf7, 0xfc, 0x07, 0xe8, 0x0c, 0x06, 0x02, 0xeb, 0xbd, + 0xb5, 0x0c, 0x2d, 0xd3, 0xc4, 0xf0, 0xd8, 0xf4, 0xe0, 0xcf, 0x1c, 0xfc, 0x3e, + 0xc6, 0xf1, 0x43, 0x30, 0xca, 0x0e, 0x0d, 0xd2, 0xdb, 0xbe, 0x4e, 0xce, 0xfb, + 0xe1, 0xed, 0x0d, 0x71, 0xe5, 0xe7, 0x42, 0xb9, 0x0a, 0x42, 0x05, 0xef, 0x27, + 0xc9, 0xe1, 0x07, 0x24, 0xff, 0x2f, 0xe9, 0xf2, 0x0e, 0xfb, 0x2a, 0xba, 0x3e, + 0xe8, 0x1e, 0xcc, 0xfd, 0xe7, 0x0f, 0x29, 0x1c, 0xba, 0xda, 0xe0, 0xea, 0xea, + 0xd6, 0x24, 0xe2, 0x2f, 0xb6, 0x1d, 0x62, 0xe9, 0x6c, 0xea, 0x05, 0xd8, 0xd9, + 0x26, 0x12, 0x0a, 0x21, 0xd7, 0xf6, 0xe2, 0x0a, 0xee, 0x0a, 0xf7, 0x0d, 0x51, + 0xdb, 0x01, 0xcc, 0xee, 0x05, 0xf6, 0xf8, 0x2c, 0x1c, 0xea, 0xdf, 0x28, 0xc8, + 0xa6, 0xa5, 0x21, 0xf9, 0xa6, 0x49, 0x1c, 0xb8, 0x2f, 0x0a, 0x81, 0xd4, 0xeb, + 0xe3, 0x17, 0x02, 0xd4, 0x0d, 0x25, 0xb0, 0x00, 0x19, 0x56, 0x7f, 0xff, 0xf9, + 0xe4, 0x33, 0x2e, 0xf3, 0x1c, 0xe3, 0xfa, 0xf3, 0xf9, 0xed, 0xe6, 0xed, 0xfb, + 0x3b, 0x29, 0x21, 0xdf, 0x0f, 0xc8, 0x1b, 0x06, 0xd1, 0x01, 0x01, 0xbb, 0x0c, + 0x25, 0x55, 0x14, 0xe0, 0x35, 0xdb, 0xd8, 0x29, 0x09, 0xd8, 0x56, 0x08, 0xfa, + 0xdd, 0xfa, 0xeb, 0xf4, 0xe9, 0xe1, 0xab, 0x08, 0xf2, 0xfc, 0xd3, 0xf8, 0x0d, + 0xf0, 0xcf, 0xe4, 0xe3, 0xf8, 0xf4, 0xba, 0x22, 0x15, 0x00, 0xe6, 0xdf, 0xf9, + 0x1a, 0x55, 0xff, 0xef, 0x41, 0xc9, 0x79, 0x19, 0xcd, 0x29, 0xc1, 0x16, 0xf1, + 0x27, 0x23, 0xe5, 0xf8, 0xf2, 0x0b, 0x43, 0xfa, 0xe1, 0x10, 0xf9, 0xed, 0x0c, + 0x27, 0x06, 0xd9, 0xd9, 0x0c, 0xde, 0xf6, 0x24, 0x0e, 0xe7, 0x21, 0x0b, 0xe6, + 0xfe, 0x2f, 0xe9, 0x0e, 0xf9, 0x3f, 0xf7, 0x26, 0xdc, 0x21, 0xe9, 0xcc, 0xf7, + 0xda, 0xda, 0xec, 0x20, 0x21, 0xe3, 0xf0, 0x3c, 0x1e, 0xcb, 0xf7, 0xf6, 0x47, + 0x15, 0xa9, 0xb9, 0xd7, 0x1a, 0xea, 0xe0, 0xd7, 0xdc, 0x30, 0xe8, 0x22, 0x12, + 0x39, 0x0f, 0x1b, 0xff, 0xf6, 0x02, 0xc5, 0x3f, 0x27, 0xdf, 0xcd, 0xe0, 0x06, + 0x36, 0x00, 0xef, 0x0f, 0xe8, 0xe2, 0x2e, 0x18, 0x24, 0xe5, 0xc6, 0x0b, 0xdf, + 0xf6, 0x0d, 0xde, 0xd6, 0xc9, 0x3f, 0xf1, 0x26, 0x0d, 0x10, 0xf2, 0x06, 0xe9, + 0xd2, 0x10, 0xe1, 0x37, 0xd8, 0x26, 0x21, 0x03, 0x0b, 0x7f, 0xfc, 0xe6, 0x0e, + 0x20, 0x19, 0xf0, 0x0e, 0x07, 0x07, 0x1f, 0x0c, 0xcb, 0xdd, 0x03, 0xa2, 0xea, + 0x23, 0xd1, 0x21, 0x07, 0xf4, 0xd0, 0xfd, 0xff, 0x22, 0x23, 0x0c, 0x28, 0xe1, + 0x03, 0x75, 0x24, 0x41, 0xd3, 0xef, 0x34, 0xfc, 0x48, 0x2a, 0xd5, 0xd8, 0xe0, + 0xe4, 0xda, 0xdd, 0xf6, 0x27, 0xc7, 0x07, 0x13, 0x17, 0x08, 0x27, 0x22, 0x19, + 0xf5, 0xf9, 0x16, 0xf8, 0xe7, 0x20, 0xdf, 0x10, 0x18, 0xe1, 0xba, 0xc5, 0xf4, + 0xee, 0x3e, 0xe1, 0x0d, 0xd7, 0xfe, 0x17, 0x01, 0x48, 0x25, 0xd3, 0x0d, 0xd4, + 0x39, 0x07, 0x0d, 0xff, 0xf5, 0xf4, 0x37, 0xf3, 0x0f, 0x36, 0x10, 0xbc, 0xea, + 0xe5, 0x22, 0xed, 0x1a, 0x0f, 0x18, 0xfa, 0xdf, 0x30, 0x04, 0x11, 0xea, 0xba, + 0xb0, 0x7f, 0x35, 0xe2, 0xea, 0x20, 0xdc, 0x10, 0x0f, 0x01, 0xcc, 0xc6, 0x31, + 0xc3, 0x07, 0x28, 0x1d, 0xfd, 0xf0, 0x03, 0x13, 0x1b, 0xc1, 0xff, 0x3c, 0xe2, + 0x01, 0xcb, 0x25, 0x2b, 0xe0, 0xf7, 0x04, 0xcf, 0xea, 0x08, 0xfb, 0x0d, 0xf3, + 0x3a, 0xea, 0x11, 0x3b, 0xe5, 0x1d, 0x1b, 0xdd, 0x23, 0x0b, 0x11, 0xe8, 0x07, + 0x01, 0x1b, 0x87, 0xfc, 0x23, 0xd7, 0x10, 0xed, 0x31, 0x0e, 0x03, 0x01, 0x0c, + 0xfe, 0xcf, 0xeb, 0x13, 0xdc, 0x22, 0x2c, 0x09, 0xd4, 0x2c, 0x04, 0xff, 0xe3, + 0xec, 0x45, 0xfb, 0xab, 0xed, 0xfb, 0xf1, 0x06, 0xf0, 0x8e, 0x13, 0x1c, 0xb2, + 0xd6, 0x7f, 0x0d, 0x25, 0xc3, 0x07, 0x6c, 0xd3, 0x4d, 0xe4, 0xf7, 0xbf, 0x5d, + 0xfb, 0xd7, 0x14, 0xde, 0x18, 0x1c, 0xd6, 0x30, 0x45, 0xb3, 0xca, 0xde, 0x56, + 0xe9, 0x20, 0x21, 0xf0, 0xea, 0xeb, 0xe7, 0xf7, 0xf2, 0xc0, 0xe7, 0x15, 0xdf, + 0x48, 0x21, 0x1a, 0xf8, 0x2c, 0x2c, 0xf3, 0xd4, 0x3e, 0x00, 0x32, 0xdb, 0xdc, + 0xea, 0xd1, 0xf6, 0xe6, 0xed, 0xef, 0x0d, 0xde, 0x17, 0x5d, 0x20, 0x19, 0xa4, + 0x00, 0xf7, 0xa6, 0x04, 0xab, 0xf2, 0xe6, 0xf7, 0x59, 0xdc, 0x1e, 0x4e, 0x32, + 0x26, 0x38, 0x3a, 0xe8, 0xe7, 0x31, 0x3e, 0xfe, 0x36, 0x04, 0x31, 0x3a, 0xe4, + 0xd8, 0xea, 0xbf, 0x21, 0x20, 0xdb, 0x01, 0x69, 0x9d, 0x3f, 0xd1, 0x4f, 0xbe, + 0x07, 0xef, 0x20, 0xa6, 0x24, 0xf6, 0x04, 0xff, 0x07, 0x11, 0xd1, 0x0d, 0xe0, + 0xfa, 0x0c, 0xaf, 0xe7, 0x00, 0x02, 0x82, 0xe2, 0xd1, 0xf3, 0x22, 0xab, 0x00, + 0xae, 0xb6, 0x19, 0x09, 0xdc, 0xce, 0xf4, 0x40, 0x3e, 0x06, 0x02, 0xac, 0xc2, + 0x40, 0x13, 0x09, 0x1f, 0x1f, 0x54, 0xe3, 0xe3, 0x0c, 0xff, 0x0c, 0xf6, 0xb3, + 0x19, 0xd5, 0x00, 0x6a, 0xd8, 0x1e, 0xf5, 0x1b, 0xf0, 0x0d, 0xfe, 0xdf, 0x0c, + 0x20, 0x7f, 0x50, 0x41, 0x0a, 0xf8, 0xed, 0xe2, 0x1c, 0xe5, 0x0d, 0xed, 0xe4, + 0xbc, 0x11, 0x4e, 0xc4, 0xd9, 0x11, 0xfa, 0x16, 0xe4, 0x1a, 0x15, 0x45, 0x1c, + 0xdb, 0x06, 0x03, 0xc3, 0xcf, 0xf5, 0xfd, 0x7f, 0xf2, 0xfa, 0x03, 0x3a, 0xe4, + 0xd2, 0x23, 0x43, 0x37, 0x16, 0x20, 0x0b, 0x1e, 0xd3, 0x2b, 0xde, 0xce, 0xc9, + 0xe7, 0x2d, 0xe7, 0x18, 0xbb, 0x09, 0x0f, 0x18, 0x08, 0xd1, 0x3c, 0xff, 0x6c, + 0xc4, 0x17, 0xa7, 0xff, 0xb4, 0x58, 0x28, 0x00, 0xfe, 0xfc, 0xc5, 0xfa, 0x07, + 0x32, 0xb1, 0xe3, 0x0c, 0x31, 0xde, 0x4d, 0xc3, 0xf1, 0xf0, 0xe0, 0xe1, 0x21, + 0x1c, 0x02, 0x0e, 0x38, 0xe8, 0x09, 0x21, 0xf2, 0x36, 0x47, 0x06, 0xd6, 0x2d, + 0x18, 0xd2, 0x12, 0x0d, 0x35, 0x13, 0x2e, 0x05, 0xcb, 0x16, 0xfc, 0x05, 0xd7, + 0xff, 0xd3, 0xe9, 0xdd, 0x01, 0x11, 0x05, 0xff, 0x03, 0xbf, 0x10, 0x26, 0x1d, + 0x59, 0xd4, 0x03, 0xca, 0xea, 0xa5, 0x3a, 0x2b, 0x07, 0x09, 0x20, 0x08, 0xd9, + 0x0a, 0x25, 0x01, 0x00, 0x26, 0x1a, 0xf2, 0xfa, 0xea, 0x1d, 0xdc, 0xe1, 0xf0, + 0xc1, 0x26, 0x18, 0xf0, 0xe1, 0x14, 0xfd, 0xe4, 0x10, 0x35, 0x00, 0x48, 0xce, + 0xeb, 0xeb, 0xe6, 0x1f, 0xfd, 0xe2, 0xfa, 0x0b, 0xd8, 0xcd, 0x08, 0x2b, 0x14, + 0xda, 0x2c, 0xdb, 0xdd, 0x05, 0xe4, 0x40, 0xc2, 0x04, 0xf1, 0xe0, 0x2a, 0x39, + 0x20, 0xe3, 0xf2, 0x12, 0xe5, 0xf5, 0xf7, 0xc2, 0xd6, 0xb5, 0x23, 0x0f, 0x1a, + 0xef, 0x1b, 0x05, 0xf6, 0xe8, 0x07, 0xd3, 0x1b, 0x34, 0x92, 0x2c, 0xec, 0xa4, + 0x09, 0xd5, 0xcc, 0x07, 0x41, 0x06, 0x1d, 0x28, 0xd0, 0x0d, 0x65, 0x01, 0xfc, + 0xfd, 0x1b, 0x0f, 0x18, 0x81, 0x2c, 0x6a, 0xf6, 0xfb, 0x04, 0x63, 0xd7, 0x24, + 0xcd, 0xa0, 0xfc, 0xd4, 0x01, 0xdb, 0x20, 0x25, 0xc8, 0xf2, 0xea, 0xb8, 0x04, + 0xe3, 0xe7, 0x27, 0xce, 0x1e, 0x30, 0x08, 0xfe, 0x04, 0x09, 0xdf, 0x1a, 0x2b, + 0xe5, 0x01, 0xe6, 0x1d, 0x1f, 0xfd, 0x34, 0x1b, 0xdd, 0xf0, 0xb8, 0x5e, 0xe3, + 0xe7, 0xb6, 0xc8, 0xe8, 0x12, 0x14, 0xa4, 0x44, 0xf8, 0xf1, 0x2c, 0xb0, 0xf7, + 0x3e, 0x2b, 0xf7, 0xf7, 0xe9, 0x59, 0xc1, 0xda, 0xbe, 0xca, 0xb3, 0xf4, 0xdb, + 0xc8, 0x8b, 0xbb, 0xc1, 0x48, 0xe7, 0xab, 0xfd, 0x9d, 0x44, 0x34, 0xef, 0x1c, + 0x33, 0xdd, 0x2c, 0x0c, 0xdf, 0x62, 0xac, 0xe2, 0xe2, 0xc8, 0x39, 0x9f, 0x38, + 0x47, 0xf8, 0x17, 0x81, 0x26, 0x46, 0x9f, 0xd6, 0x51, 0xc6, 0x11, 0xed, 0x63, + 0xc1, 0xf3, 0xe8, 0x14, 0xf3, 0x14, 0x2e, 0x23, 0x1c, 0xec, 0x41, 0x65, 0xf3, + 0xff, 0xc5, 0x36, 0x20, 0x0c, 0xd9, 0x09, 0xe7, 0xfb, 0xfc, 0xe9, 0x39, 0x8f, + 0xe1, 0xbf, 0x40, 0x1c, 0x19, 0x07, 0x0c, 0x02, 0x0f, 0xff, 0x2f, 0xac, 0x30, + 0x45, 0x1d, 0x35, 0xb1, 0xd5, 0x0d, 0xc5, 0xe3, 0x2e, 0x01, 0x28, 0x14, 0x67, + 0x29, 0x10, 0x41, 0xee, 0x01, 0x56, 0xd0, 0xd6, 0x48, 0x1a, 0xd7, 0x1d, 0xe0, + 0x07, 0x0a, 0x16, 0xe5, 0x01, 0xf6, 0xe8, 0xee, 0xf4, 0x00, 0x20, 0x02, 0xf7, + 0x03, 0x07, 0xdb, 0x07, 0xc7, 0x2d, 0x1d, 0x03, 0xf9, 0x03, 0x09, 0xf5, 0xd7, + 0xf5, 0xd6, 0xed, 0x19, 0x21, 0xfa, 0xec, 0xe4, 0xef, 0xb0, 0xcf, 0x1c, 0xc4, + 0x09, 0x0d, 0xbb, 0x23, 0x26, 0x0f, 0x0d, 0xec, 0x2f, 0x0c, 0xf0, 0xc1, 0x14, + 0xbc, 0x13, 0x45, 0x17, 0xdc, 0xf9, 0xeb, 0x14, 0x05, 0xef, 0xfe, 0xd2, 0x45, + 0x03, 0x15, 0x09, 0xd8, 0xda, 0x29, 0xe6, 0x07, 0xef, 0x12, 0xe0, 0x01, 0x2f, + 0x7f, 0xec, 0xfd, 0xd1, 0x03, 0x2f, 0xeb, 0xff, 0xba, 0xe0, 0x08, 0x12, 0x0f, + 0x4f, 0x47, 0xed, 0xc4, 0xc4, 0xdc, 0x2f, 0x09, 0x2b, 0x08, 0x1e, 0xdd, 0x35, + 0xd8, 0x09, 0xfa, 0xe6, 0x1c, 0xd8, 0xff, 0xd0, 0x04, 0xda, 0x1a, 0x37, 0x1d, + 0x2a, 0xe6, 0xc6, 0xf7, 0x32, 0x41, 0x1d, 0xd5, 0x3a, 0xde, 0x43, 0x07, 0x3d, + 0xfb, 0x0b, 0xd4, 0x22, 0xc9, 0x2f, 0xe5, 0xd5, 0x0f, 0x24, 0x0b, 0xc8, 0xe8, + 0x1f, 0x1f, 0x57, 0x9e, 0x2f, 0x30, 0x88, 0xf9, 0x2d, 0xd7, 0xb3, 0x1c, 0x84, + 0x2c, 0xc3, 0x07, 0x32, 0x3a, 0xb6, 0xd6, 0xca, 0x13, 0x02, 0xcf, 0xe1, 0xaa, + 0xd0, 0xd9, 0xed, 0xc7, 0xfe, 0x09, 0x09, 0xd0, 0x1e, 0x6d, 0x56, 0x37, 0xef, + 0xd9, 0xed, 0x1a, 0xe7, 0xbe, 0x56, 0xf3, 0x0a, 0x48, 0xda, 0xf0, 0xd3, 0x2a, + 0xe6, 0x12, 0x7b, 0xe0, 0xbe, 0x25, 0x0f, 0x1e, 0xdb, 0x58, 0xed, 0xec, 0x12, + 0xc4, 0xf4, 0xc0, 0x29, 0xee, 0x11, 0xdc, 0xd2, 0x19, 0x37, 0x1e, 0xf1, 0x4d, + 0xdd, 0xf4, 0x88, 0xa3, 0x32, 0xd8, 0xab, 0xc1, 0x0e, 0x27, 0x6c, 0x20, 0x36, + 0x29, 0x06, 0x08, 0x31, 0x1d, 0x35, 0x7f, 0xfe, 0x24, 0x4b, 0x17, 0xcb, 0x19, + 0x03, 0x21, 0x05, 0x0c, 0x34, 0x60, 0x18, 0x02, 0xd4, 0xf6, 0x0e, 0xfe, 0xdd, + 0x4f, 0x1c, 0x83, 0xe8, 0xbe, 0xba, 0x48, 0x30, 0xfa, 0xf3, 0x0d, 0x13, 0x47, + 0x36, 0x13, 0x34, 0x1c, 0x3e, 0xb4, 0x4b, 0xa1, 0xb9, 0xf4, 0xf9, 0x0a, 0xe3, + 0x2b, 0x36, 0xa2, 0xce, 0x32, 0x29, 0x11, 0x10, 0x3a, 0xa0, 0x28, 0x6f, 0xca, + 0xfc, 0xf0, 0xb0, 0xdb, 0xe9, 0x10, 0xfb, 0xf4, 0xef, 0x53, 0xc2, 0xf6, 0x45, + 0x2d, 0x14, 0xf8, 0xdf, 0xce, 0x17, 0xa7, 0xf3, 0x12, 0x81, 0x38, 0xac, 0x10, + 0xd6, 0xf9, 0xef, 0x43, 0x0d, 0x0c, 0x1c, 0xea, 0x1d, 0x3f, 0x1f, 0xc2, 0xe2, + 0xf6, 0x00, 0x1a, 0xe9, 0x2a, 0x02, 0x1c, 0xec, 0xf5, 0x04, 0xd1, 0x18, 0x21, + 0x11, 0xe7, 0x32, 0xb1, 0x1d, 0x21, 0x1c, 0xf5, 0xdc, 0xf8, 0xe7, 0xe9, 0x38, + 0x5a, 0x08, 0xf1, 0x2d, 0xbb, 0x08, 0xe6, 0x08, 0x13, 0x2e, 0x07, 0x35, 0x34, + 0xff, 0x11, 0xfb, 0x09, 0xf3, 0x0d, 0x5b, 0xef, 0x37, 0x38, 0x0c, 0xe5, 0x2b, + 0xcd, 0x11, 0x4a, 0x03, 0xf5, 0xf6, 0x01, 0xfc, 0x22, 0xc2, 0x0a, 0xd7, 0xdb, + 0xee, 0xf9, 0xe8, 0x07, 0xfa, 0xdf, 0xf9, 0xe5, 0x36, 0x1a, 0x07, 0xd9, 0xe7, + 0xd4, 0xff, 0xde, 0x02, 0x60, 0xf8, 0xeb, 0xe8, 0xc7, 0x3d, 0xf3, 0xf8, 0x0c, + 0xc9, 0xe8, 0x28, 0x2e, 0x1e, 0x15, 0xf0, 0xec, 0x32, 0x06, 0x39, 0x4c, 0x0a, + 0x36, 0xc7, 0xd8, 0xeb, 0x52, 0xe2, 0xda, 0xaf, 0xfe, 0x23, 0x0b, 0x02, 0x43, + 0x19, 0xda, 0x09, 0xed, 0x05, 0x0f, 0x0d, 0x29, 0xeb, 0xd8, 0x40, 0x0e, 0xd5, + 0x30, 0xf8, 0x46, 0x0b, 0xfe, 0x1e, 0x03, 0xe5, 0xef, 0x38, 0xd5, 0x05, 0xbd, + 0x07, 0xb0, 0xe2, 0x4a, 0xc5, 0x06, 0xa3, 0xeb, 0x7f, 0x28, 0x02, 0xba, 0x2c, + 0x1b, 0xeb, 0xe8, 0xdd, 0xfa, 0xf8, 0x1a, 0x03, 0x69, 0xfe, 0x0b, 0xcb, 0x26, + 0xf5, 0xfb, 0x33, 0xb2, 0xd9, 0x18, 0xcc, 0xe6, 0x4d, 0xde, 0x11, 0x0f, 0x10, + 0x0d, 0x26, 0xa3, 0xfc, 0x10, 0x22, 0xd9, 0xdb, 0x11, 0xec, 0x06, 0x36, 0x42, + 0x14, 0x33, 0xe8, 0x1a, 0xe2, 0xcd, 0xeb, 0x1d, 0xbc, 0xcb, 0x37, 0xc3, 0xf7, + 0xbb, 0x1c, 0x0b, 0x0c, 0x05, 0xb7, 0xb4, 0x6c, 0xc0, 0x0f, 0xf3, 0xe7, 0xf2, + 0x05, 0xff, 0xde, 0xde, 0xc9, 0xe8, 0xd2, 0xdd, 0x1a, 0x18, 0x36, 0x25, 0x27, + 0x24, 0x08, 0x18, 0xed, 0x19, 0x05, 0xdc, 0x1f, 0x19, 0xed, 0x16, 0xe5, 0x3e, + 0x04, 0xef, 0x07, 0xfa, 0xf7, 0xcf, 0x0f, 0x04, 0x7f, 0xf9, 0x1a, 0x0d, 0x23, + 0xd7, 0x33, 0xdc, 0xdf, 0xd5, 0x06, 0x05, 0xe5, 0xb1, 0x48, 0xe9, 0xfa, 0x1a, + 0x1c, 0xbe, 0x51, 0x03, 0x15, 0xf0, 0xfe, 0xfd, 0xdf, 0xb0, 0xe5, 0x0b, 0xf8, + 0xfb, 0x44, 0xac, 0xf2, 0xe0, 0x5b, 0x07, 0x6f, 0xdb, 0xfd, 0x21, 0x06, 0x24, + 0xee, 0x42, 0xe1, 0x0f, 0xb2, 0xb8, 0xea, 0xb3, 0xf7, 0xf9, 0xf7, 0x2f, 0xd2, + 0xab, 0x0c, 0x0d, 0x09, 0x21, 0x9d, 0x59, 0xc7, 0x07, 0xdb, 0x15, 0xfd, 0x21, + 0xf2, 0x49, 0xc8, 0x12, 0xdb, 0x70, 0xdb, 0x09, 0x2f, 0x6e, 0xbe, 0xc7, 0xb1, + 0xf2, 0xfd, 0x1e, 0xef, 0x0a, 0xe8, 0xcb, 0xeb, 0x39, 0xf7, 0x06, 0x9d, 0x1b, + 0x3e, 0xb0, 0xe5, 0xed, 0xe5, 0xf7, 0x13, 0x01, 0x43, 0x7f, 0xcd, 0xfd, 0xf5, + 0x6a, 0x35, 0x08, 0xdd, 0xf8, 0xf5, 0x1b, 0xe6, 0xd9, 0xd5, 0xf5, 0xef, 0xdc, + 0x12, 0x61, 0x41, 0x4b, 0x09, 0x04, 0xcb, 0x03, 0xfd, 0xc2, 0xe0, 0x85, 0xea, + 0xba, 0xf7, 0xfd, 0x6b, 0xc0, 0x26, 0xc8, 0x0a, 0xce, 0xe2, 0xfe, 0xfe, 0xb2, + 0x59, 0x08, 0xc9, 0x31, 0x2d, 0xef, 0x57, 0x06, 0xe0, 0x48, 0x95, 0x73, 0x29, + 0x49, 0xea, 0x77, 0x31, 0x3b, 0x24, 0x55, 0x34, 0x2e, 0xc1, 0x23, 0x26, 0xe7, + 0x1d, 0x50, 0x1a, 0xb7, 0xe9, 0xbd, 0x49, 0x20, 0x29, 0xe3, 0x0f, 0x7b, 0x0f, + 0xed, 0x2c, 0x64, 0xa7, 0xda, 0xfa, 0xef, 0x21, 0xbf, 0x05, 0xff, 0x99, 0xe1, + 0x5c, 0xcc, 0xd8, 0xd6, 0xea, 0xc0, 0x34, 0x1f, 0xad, 0xe1, 0xe6, 0xc9, 0xdc, + 0xbb, 0x19, 0xec, 0x31, 0x11, 0x04, 0xd8, 0x50, 0xf1, 0xdf, 0x68, 0x06, 0xca, + 0x5d, 0x1d, 0x68, 0xd5, 0x2c, 0x2f, 0xcf, 0x91, 0xbc, 0xc4, 0x0f, 0xb4, 0x5c, + 0x68, 0xd0, 0x14, 0x46, 0x42, 0x85, 0x21, 0x12, 0xf5, 0x24, 0xf6, 0xda, 0x2b, + 0xd7, 0x69, 0xc7, 0xd9, 0x42, 0xe9, 0x1e, 0x9f, 0xfd, 0x4f, 0x05, 0x0f, 0xe8, + 0x0f, 0x4e, 0x21, 0xd2, 0xc7, 0x87, 0x6e, 0x64, 0x5d, 0x3e, 0x23, 0xd9, 0xc7, + 0x05, 0xda, 0x0f, 0xec, 0xfc, 0x88, 0xb5, 0x0c, 0xec, 0xe2, 0xb1, 0x09, 0xbf, + 0x21, 0x0f, 0xfc, 0x3d, 0xb6, 0xf9, 0x29, 0x05, 0x7f, 0x28, 0xe9, 0x03, 0xf7, + 0xf1, 0x0f, 0xfa, 0xcc, 0xec, 0x01, 0xda, 0xf1, 0xc1, 0xe0, 0x5d, 0x47, 0x05, + 0xfb, 0x16, 0xe7, 0x16, 0x20, 0x1d, 0xdd, 0xdd, 0x2b, 0x5a, 0x1b, 0x45, 0x67, + 0xfb, 0x00, 0xe7, 0xd9, 0x1b, 0xed, 0xe3, 0x17, 0x1d, 0x59, 0x1c, 0xd2, 0x56, + 0x7f, 0xeb, 0xfe, 0xcc, 0xe9, 0xfc, 0x1a, 0xcc, 0x37, 0x27, 0xec, 0x30, 0x16, + 0x41, 0xc1, 0x29, 0x8c, 0xe4, 0x01, 0x36, 0xe0, 0xfe, 0x16, 0x1b, 0x17, 0xb5, + 0xfb, 0xe6, 0x8b, 0xed, 0xf9, 0xe6, 0x11, 0xe5, 0x2a, 0xec, 0xd3, 0xf1, 0xdd, + 0x0f, 0xc9, 0x38, 0xc4, 0xdf, 0xc7, 0x0a, 0xcb, 0x12, 0x32, 0x59, 0x17, 0x4b, + 0x1f, 0xe6, 0x03, 0x1a, 0xda, 0xe6, 0x3d, 0x36, 0x11, 0x14, 0xc1, 0xa6, 0x2e, + 0xd2, 0xf8, 0x1e, 0x06, 0x37, 0x16, 0xca, 0xdd, 0x3a, 0x25, 0xee, 0x42, 0xb7, + 0xe3, 0xdf, 0xfd, 0xdf, 0x29, 0xed, 0xa3, 0x20, 0xc2, 0x37, 0x95, 0x57, 0xea, + 0x0c, 0x0e, 0x08, 0xf3, 0xf9, 0xf9, 0x9a, 0x1c, 0xb6, 0x04, 0xdd, 0x14, 0xea, + 0x06, 0x96, 0xeb, 0x60, 0x26, 0xc6, 0x7f, 0x01, 0xe2, 0xb4, 0x21, 0xb9, 0x38, + 0x41, 0x1d, 0x3b, 0x22, 0x6e, 0xe0, 0xc4, 0xa3, 0x1e, 0xd5, 0xf5, 0xa8, 0x46, + 0xb8, 0xf5, 0x1f, 0x20, 0xfa, 0x73, 0xe5, 0x9a, 0xcb, 0x68, 0x06, 0x79, 0x59, + 0xf9, 0x37, 0x2f, 0x0b, 0xa9, 0xbf, 0xb9, 0x3f, 0x0b, 0xca, 0xaa, 0x1f, 0x05, + 0x1e, 0x41, 0x05, 0x08, 0x0f, 0xfb, 0xc5, 0x32, 0xb4, 0xc8, 0xf4, 0x05, 0xf1, + 0x93, 0x0a, 0x4c, 0x46, 0xfe, 0xbd, 0x3a, 0xc2, 0xc3, 0x4e, 0xbe, 0xcb, 0xd7, + 0xa9, 0xc6, 0xe5, 0xed, 0x95, 0xdf, 0xfa, 0x32, 0xf2, 0xc6, 0xfd, 0x95, 0xe9, + 0x45, 0x0c, 0x13, 0x17, 0x01, 0xcf, 0x23, 0x23, 0xd8, 0xc9, 0x05, 0xac, 0x21, + 0xac, 0xc0, 0x2e, 0xec, 0xe7, 0x3c, 0xf9, 0xdc, 0xde, 0x0f, 0xe8, 0xf9, 0x27, + 0xbe, 0xd7, 0x06, 0xfe, 0xdb, 0xa6, 0xd4, 0xc1, 0x0e, 0x07, 0xd9, 0x2b, 0xe4, + 0x07, 0xff, 0xef, 0xe5, 0xdd, 0xb6, 0x4d, 0x81, 0x06, 0xeb, 0x48, 0xe3, 0xea, + 0xd0, 0xee, 0x5f, 0x3f, 0xb8, 0x21, 0xf1, 0xb7, 0x0b, 0x2c, 0x17, 0x07, 0xcd, + 0xe7, 0xfe, 0x34, 0x0b, 0xfd, 0xc8, 0x0e, 0x66, 0x1b, 0x4a, 0xfa, 0xb1, 0xfc, + 0xee, 0x5c, 0xd1, 0xd4, 0x1e, 0x12, 0xb0, 0xcb, 0x22, 0x15, 0x03, 0x02, 0xf3, + 0x0f, 0x91, 0x0a, 0x03, 0x2f, 0xbf, 0xd4, 0x0a, 0xc3, 0xef, 0xa3, 0x0b, 0xf9, + 0xf0, 0x46, 0x06, 0xcc, 0xfd, 0x04, 0x11, 0xec, 0xd6, 0x61, 0xee, 0xd3, 0x20, + 0x60, 0xe5, 0xff, 0xc7, 0xfc, 0xf4, 0x63, 0x29, 0xd8, 0x2f, 0xff, 0xe9, 0xfd, + 0x15, 0xff, 0x0c, 0x25, 0x1a, 0x36, 0x11, 0xd3, 0xc5, 0xf1, 0x47, 0xec, 0xf4, + 0xd8, 0x11, 0x41, 0xe5, 0xf2, 0xa8, 0xea, 0x1a, 0x0e, 0xf8, 0x2b, 0xf9, 0x1d, + 0xc6, 0x3f, 0x3b, 0xb6, 0xd5, 0x95, 0x05, 0x0e, 0xe2, 0xf2, 0xb1, 0x03, 0xf2, + 0x36, 0xb3, 0x3b, 0x24, 0x1a, 0x2c, 0xe2, 0x5c, 0x37, 0xe4, 0xcb, 0x01, 0x2d, + 0xe6, 0xee, 0xe9, 0x23, 0xe5, 0x08, 0xa6, 0xb4, 0xfe, 0x90, 0xdf, 0xf0, 0x36, + 0x21, 0xbd, 0xb6, 0x08, 0x07, 0x2d, 0xe7, 0x99, 0xff, 0x29, 0xe9, 0xd2, 0xe9, + 0xc5, 0x22, 0x18, 0x4b, 0x0a, 0x01, 0x26, 0x06, 0x20, 0xed, 0xde, 0xe5, 0x0d, + 0xfd, 0xf7, 0xb3, 0x0a, 0x12, 0x3e, 0xed, 0x00, 0x0d, 0xb6, 0x3f, 0xff, 0x1a, + 0x17, 0x1d, 0xee, 0x06, 0x01, 0x04, 0x68, 0xf2, 0xd7, 0xc4, 0xf1, 0x15, 0xe6, + 0x17, 0xf2, 0x0e, 0x2b, 0xd8, 0x39, 0xf5, 0xdf, 0x18, 0x44, 0x00, 0x23, 0xf8, + 0x35, 0x21, 0x7f, 0x86, 0x37, 0xdc, 0x13, 0xdd, 0xd1, 0x14, 0x0a, 0x25, 0x14, + 0x28, 0x19, 0xed, 0xd9, 0xfd, 0xcb, 0xe8, 0x36, 0xf6, 0x3a, 0x10, 0xda, 0xe5, + 0xc6, 0x4b, 0x94, 0x04, 0x32, 0xa1, 0x57, 0xbb, 0x14, 0x21, 0x36, 0x28, 0x0f, + 0x39, 0x93, 0xd0, 0xd7, 0xc8, 0x14, 0xdc, 0x34, 0xe9, 0x43, 0x24, 0xfe, 0xda, + 0xaf, 0x10, 0x19, 0xf5, 0x1a, 0xd9, 0xeb, 0x23, 0x05, 0xe4, 0x35, 0x0d, 0x30, + 0x13, 0xc7, 0xc1, 0x19, 0xc3, 0x32, 0x8a, 0x48, 0x2c, 0xad, 0x15, 0xf8, 0x09, + 0x52, 0x0e, 0xe2, 0x03, 0xea, 0x1b, 0xa4, 0xc4, 0xc4, 0x5d, 0xca, 0x17, 0x09, + 0xca, 0x1e, 0x33, 0xab, 0x2b, 0xe6, 0x9d, 0xa9, 0xb9, 0x0e, 0x3b, 0xfa, 0xb3, + 0x21, 0xcd, 0x29, 0x52, 0x32, 0x63, 0x0c, 0xfa, 0xd0, 0x11, 0xfd, 0x81, 0x15, + 0x2b, 0xd0, 0xec, 0x09, 0xee, 0xb3, 0x3e, 0x06, 0x25, 0x30, 0xe2, 0x0e, 0x18, + 0x1c, 0xe6, 0x01, 0xf2, 0x66, 0xef, 0x33, 0xca, 0x41, 0xf1, 0x33, 0xdd, 0xfa, + 0xf3, 0x5c, 0xc8, 0x7f, 0xe3, 0x14, 0x31, 0x3f, 0xc9, 0xff, 0xf7, 0xfc, 0x20, + 0xfc, 0x0b, 0x10, 0x20, 0xf2, 0x36, 0xea, 0xd1, 0xf7, 0x2c, 0x1b, 0xfb, 0x25, + 0x0f, 0xfb, 0xdf, 0x17, 0x4e, 0xf6, 0x5e, 0xcb, 0xe3, 0xcc, 0xe1, 0xe2, 0xb3, + 0x0b, 0xf0, 0x36, 0xc0, 0xd9, 0x12, 0xe7, 0xfd, 0xfc, 0xf6, 0xdc, 0x1a, 0x0a, + 0xf1, 0x16, 0xfb, 0x1b, 0x0e, 0xfd, 0x3f, 0xf5, 0xe3, 0xb8, 0x23, 0xec, 0x46, + 0x1f, 0x28, 0xf1, 0xe1, 0xfb, 0x10, 0xfc, 0x09, 0xf4, 0x23, 0x0c, 0xf7, 0x17, + 0x2d, 0x12, 0xc3, 0xf9, 0xf7, 0xe6, 0x0d, 0x22, 0x03, 0x3b, 0xf9, 0x0b, 0xeb, + 0xb9, 0x13, 0x15, 0x2a, 0x0f, 0xc7, 0x1a, 0x1b, 0xee, 0x40, 0xe9, 0x01, 0x06, + 0xf9, 0x45, 0x06, 0xf4, 0x1c, 0x0e, 0x33, 0xcb, 0x56, 0x0f, 0x07, 0x15, 0xf5, + 0x46, 0x22, 0xe8, 0x08, 0xd5, 0x12, 0xe4, 0xe3, 0x13, 0x2b, 0x19, 0x1b, 0x73, + 0x14, 0xff, 0xd8, 0x57, 0xe7, 0x32, 0x1b, 0x02, 0x3c, 0xc9, 0x19, 0x00, 0xc7, + 0x19, 0xff, 0x12, 0xfc, 0x38, 0xfe, 0xf3, 0x11, 0xb2, 0x30, 0xe3, 0x07, 0x30, + 0xde, 0x42, 0x07, 0xd2, 0xc5, 0xe4, 0xf4, 0xd3, 0x0d, 0x9b, 0xcd, 0xcd, 0x1e, + 0x2b, 0xf9, 0xe4, 0x2d, 0x1c, 0x26, 0xe3, 0x40, 0xd2, 0x0f, 0xa4, 0x26, 0x0b, + 0xeb, 0x2a, 0xdf, 0xf2, 0xd7, 0x36, 0xd0, 0xad, 0xbe, 0x36, 0x0e, 0x21, 0xf7, + 0x1b, 0xc0, 0x1c, 0x27, 0x01, 0xe8, 0xdc, 0x18, 0x17, 0xe0, 0xf5, 0x1a, 0xf5, + 0x02, 0x02, 0xe9, 0x20, 0x07, 0x06, 0x81, 0xec, 0x42, 0x18, 0x1d, 0xd7, 0x47, + 0xaf, 0xca, 0xea, 0xfa, 0xbe, 0x35, 0x2a, 0xc7, 0x03, 0xd5, 0xf6, 0xe6, 0x20, + 0xb9, 0xb4, 0xc1, 0xec, 0x01, 0xc6, 0xc5, 0x00, 0xd0, 0x01, 0xf3, 0xd4, 0x66, + 0x08, 0x03, 0x1f, 0xeb, 0x00, 0x19, 0xb1, 0x38, 0xca, 0x0e, 0x3c, 0x81, 0xa9, + 0xe8, 0x35, 0xbb, 0x07, 0xf3, 0x3c, 0xea, 0x2a, 0x4a, 0xd3, 0x0a, 0xc7, 0xed, + 0xe4, 0x08, 0x1e, 0xd7, 0xe1, 0x42, 0x29, 0xcc, 0xda, 0x23, 0x01, 0xbb, 0x26, + 0xbf, 0x1c, 0xc3, 0xef, 0xdd, 0xd4, 0x38, 0xff, 0x0d, 0x47, 0x37, 0x44, 0xd2, + 0xe6, 0x8d, 0x47, 0x28, 0x2a, 0xf5, 0xd6, 0x4d, 0xac, 0xca, 0xe0, 0xb9, 0x2a, + 0x2d, 0x4f, 0xe1, 0x29, 0xf2, 0xe2, 0x14, 0xf4, 0xb8, 0x43, 0x2e, 0x24, 0xeb, + 0x40, 0x2f, 0xe4, 0x21, 0xf5, 0xd4, 0x21, 0x3f, 0xd4, 0x1c, 0x29, 0x25, 0x1a, + 0x93, 0x30, 0xab, 0x55, 0xf3, 0xc0, 0x14, 0xe0, 0x7f, 0xe7, 0x1a, 0xe6, 0xd5, + 0xeb, 0xe0, 0x36, 0x0d, 0x21, 0x2c, 0x58, 0xc7, 0xfa, 0x18, 0xe4, 0x4f, 0xb6, + 0x27, 0xd3, 0xe3, 0xd6, 0xff, 0xde, 0xd2, 0xe9, 0xdf, 0x00, 0x39, 0x02, 0xe7, + 0x84, 0xbb, 0x01, 0x1b, 0xd9, 0x04, 0xfb, 0x24, 0x05, 0x1d, 0xdb, 0x20, 0x1c, + 0xea, 0x3a, 0xf9, 0x1e, 0xf3, 0xe4, 0xea, 0x35, 0x04, 0x16, 0x28, 0x26, 0x3f, + 0x1e, 0xf4, 0xf2, 0x06, 0x28, 0xfa, 0x27, 0x01, 0x45, 0x02, 0xea, 0xec, 0x0e, + 0x20, 0x1f, 0xdb, 0xed, 0xdd, 0x10, 0x24, 0xfe, 0x5a, 0x0c, 0xda, 0xf2, 0xe8, + 0xda, 0xd0, 0xf9, 0xa5, 0x15, 0xdc, 0x0a, 0xe7, 0xd3, 0x3e, 0xd7, 0xfe, 0xf5, + 0x35, 0x28, 0xe5, 0xe3, 0x1b, 0xfe, 0xcd, 0x09, 0x1c, 0xcb, 0x4a, 0x0e, 0xdf, + 0xdf, 0x08, 0x18, 0x19, 0x39, 0x28, 0x2b, 0x12, 0x02, 0x14, 0x08, 0x4a, 0xcf, + 0xb3, 0xf7, 0xf8, 0x9c, 0x3e, 0x05, 0xaf, 0x6c, 0x12, 0x03, 0xeb, 0x7f, 0x31, + 0xad, 0x04, 0x4d, 0x00, 0x39, 0x31, 0x00, 0xe6, 0xe9, 0x38, 0xd8, 0xbb, 0x25, + 0xfe, 0xce, 0xd9, 0x3b, 0xe1, 0x0b, 0xfb, 0xe6, 0x06, 0xfa, 0x2d, 0x26, 0x3f, + 0xed, 0xac, 0xd7, 0x0b, 0xcc, 0xbc, 0xf9, 0xec, 0xc6, 0x1f, 0x22, 0xd9, 0x0d, + 0xef, 0xe5, 0xf6, 0x4d, 0x17, 0x7f, 0x2d, 0xbc, 0xec, 0x01, 0xf9, 0x6f, 0xb6, + 0xfb, 0x11, 0xd5, 0x0f, 0xe5, 0xdf, 0xe9, 0xd7, 0xe5, 0x23, 0xf8, 0xdf, 0x08, + 0xfd, 0xf3, 0xdf, 0x50, 0xd6, 0x2a, 0x01, 0xe8, 0x0b, 0xca, 0xfc, 0xd4, 0xe5, + 0xdf, 0xdd, 0xfc, 0x02, 0x42, 0xf0, 0xde, 0x25, 0xf3, 0xbb, 0x01, 0xd0, 0xdb, + 0xb6, 0x59, 0xeb, 0xe5, 0xdd, 0xdf, 0x20, 0xdb, 0xb4, 0xe1, 0xc3, 0xf0, 0x1f, + 0xcf, 0x01, 0xf3, 0x2a, 0x53, 0xf3, 0xb4, 0x47, 0xf1, 0x14, 0xd3, 0x33, 0xcb, + 0x16, 0xcb, 0xfc, 0x05, 0x01, 0xfb, 0xe8, 0xb1, 0x18, 0x20, 0xcf, 0xcd, 0xde, + 0x23, 0x8f, 0x32, 0x04, 0xfc, 0xba, 0x3a, 0xf5, 0x4d, 0xef, 0xd0, 0xdb, 0xd4, + 0xe0, 0xf8, 0x18, 0x28, 0x1e, 0xd7, 0x24, 0xe8, 0xd6, 0x0b, 0x5a, 0xcd, 0x40, + 0xfe, 0xb3, 0x16, 0xcb, 0xde, 0x4b, 0xe8, 0x25, 0xe0, 0x03, 0x2c, 0x20, 0x22, + 0xaa, 0xda, 0xc8, 0xf6, 0xf2, 0xe2, 0xe7, 0x17, 0xb2, 0x13, 0x6f, 0x30, 0xd3, + 0xe1, 0x2d, 0x0d, 0x00, 0x5b, 0xb1, 0x1c, 0x03, 0xfa, 0xa0, 0x0d, 0xfd, 0xb6, + 0xbf, 0xf9, 0x55, 0x3e, 0x22, 0xe3, 0x8f, 0xdb, 0x5e, 0xb3, 0xe5, 0x13, 0x14, + 0x2c, 0x33, 0xf3, 0xb6, 0xe1, 0x8a, 0x09, 0x16, 0x04, 0x15, 0x00, 0x62, 0xf8, + 0x1c, 0x36, 0x6f, 0xd6, 0xca, 0x02, 0xcd, 0x87, 0x4c, 0x85, 0x22, 0x2f, 0xbc, + 0x0a, 0x23, 0x41, 0x10, 0x08, 0x50, 0xd8, 0xa3, 0x13, 0x0d, 0xe1, 0x1f, 0x02, + 0xee, 0x26, 0xe3, 0xf4, 0x21, 0x0f, 0xe6, 0x13, 0x04, 0xff, 0x45, 0x4f, 0x89, + 0xc4, 0x7f, 0xfd, 0x29, 0xfc, 0x5b, 0xc2, 0x30, 0xe6, 0xb2, 0xee, 0xc0, 0x30, + 0xc8, 0xfb, 0xf3, 0xd8, 0xc3, 0x74, 0x0f, 0xf2, 0x41, 0x1a, 0xfe, 0x18, 0xd2, + 0xdd, 0xbc, 0xda, 0x3f, 0xfd, 0xc6, 0xb3, 0xdf, 0x0e, 0x27, 0xe1, 0xfb, 0x27, + 0x0e, 0x43, 0xaa, 0x66, 0x16, 0x29, 0x1a, 0x0c, 0x0c, 0xe7, 0x14, 0x10, 0x22, + 0x64, 0xa9, 0x16, 0xff, 0x11, 0x14, 0xdd, 0x2a, 0x42, 0x0f, 0xf0, 0x11, 0xbb, + 0xf3, 0xe9, 0x4e, 0xe2, 0x16, 0x92, 0xe0, 0xce, 0x11, 0xf2, 0xf4, 0xc6, 0xfe, + 0x7f, 0xfc, 0xbc, 0xf8, 0xd1, 0xe9, 0xe1, 0xe6, 0xe2, 0x13, 0x45, 0x1e, 0xe7, + 0xc8, 0xf8, 0x08, 0x31, 0xae, 0x13, 0xf4, 0xc2, 0xfc, 0xf5, 0x27, 0x0c, 0x2c, + 0x63, 0x3d, 0xda, 0x3b, 0xcc, 0xe4, 0xd1, 0xf8, 0x0c, 0xe0, 0xe2, 0xa5, 0xe5, + 0xf5, 0xe5, 0xff, 0x2f, 0xe9, 0x28, 0xca, 0x0e, 0xe7, 0x24, 0xb4, 0x3f, 0xdb, + 0x05, 0xc6, 0x25, 0xf2, 0x43, 0x05, 0xc5, 0xde, 0xd9, 0x26, 0xd5, 0xfe, 0xf4, + 0x1b, 0x3c, 0x25, 0x17, 0x23, 0xf2, 0xe2, 0x00, 0xe2, 0x20, 0xba, 0xdb, 0xff, + 0xdd, 0xc0, 0x11, 0xfe, 0x14, 0x03, 0x31, 0x00, 0x0c, 0x7f, 0xf8, 0x0d, 0x1c, + 0x05, 0xfe, 0x2b, 0xbe, 0x32, 0x04, 0xfd, 0xad, 0x38, 0xe9, 0x25, 0x19, 0xca, + 0xe5, 0x19, 0xe3, 0x69, 0xf3, 0x45, 0xfb, 0x42, 0x17, 0xe1, 0xe8, 0xf4, 0xf6, + 0xe2, 0xe5, 0xb1, 0xbf, 0x14, 0xd6, 0x2b, 0x3b, 0x04, 0xf1, 0xce, 0xfb, 0xbb, + 0xcd, 0xfb, 0xec, 0xfc, 0xd5, 0xf6, 0x11, 0x5e, 0xf0, 0x34, 0xc0, 0x1f, 0xbc, + 0xdb, 0x23, 0xe9, 0x21, 0x22, 0xe1, 0x04, 0x35, 0xdf, 0x0a, 0x26, 0xed, 0x05, + 0x60, 0xe9, 0x1f, 0xdf, 0x47, 0x67, 0x03, 0xf3, 0xf7, 0x4e, 0x27, 0xee, 0x01, + 0x01, 0xe6, 0x37, 0x0d, 0x0e, 0x1e, 0xfb, 0xf1, 0xfb, 0xcc, 0xb5, 0x44, 0xf8, + 0xb5, 0xee, 0x23, 0x31, 0x09, 0xce, 0xfb, 0xdc, 0x02, 0x17, 0x01, 0x6d, 0x26, + 0xe4, 0x31, 0x33, 0xc8, 0x27, 0xea, 0xfe, 0x05, 0xfc, 0x25, 0x08, 0x47, 0xe8, + 0x2b, 0xdc, 0xfb, 0xe8, 0xf3, 0x10, 0x31, 0x08, 0x23, 0x22, 0x03, 0xcb, 0x05, + 0xf9, 0x0f, 0x0e, 0x02, 0x09, 0xc9, 0x00, 0x36, 0x12, 0x05, 0xca, 0xec, 0xbd, + 0xd8, 0xf0, 0x25, 0x1c, 0x0f, 0x21, 0xdf, 0x25, 0xdc, 0x04, 0xd8, 0x1c, 0x01, + 0xde, 0xe8, 0x42, 0x04, 0xce, 0xd0, 0xe7, 0xc8, 0xb2, 0x53, 0x07, 0xfa, 0xd5, + 0x17, 0xe0, 0xe6, 0x02, 0xf6, 0xd2, 0xfc, 0x07, 0xdf, 0x05, 0x1f, 0xfd, 0xe3, + 0xdb, 0xc7, 0x22, 0x06, 0x0a, 0xfe, 0x30, 0x3a, 0x02, 0xed, 0x29, 0x2e, 0xfb, + 0x22, 0x0d, 0xee, 0x1b, 0xf6, 0xc9, 0xe9, 0xfa, 0xc0, 0xa6, 0xac, 0x09, 0xcc, + 0xd2, 0x50, 0xea, 0xdc, 0x76, 0xf6, 0x46, 0x32, 0xef, 0xd7, 0x24, 0x07, 0x7f, + 0x22, 0xda, 0xf9, 0x15, 0x0a, 0x4b, 0xc8, 0xc2, 0xc1, 0xca, 0x1c, 0x13, 0xf5, + 0x1d, 0x45, 0x25, 0x2e, 0xf0, 0xf2, 0x30, 0x07, 0x36, 0xce, 0x28, 0xeb, 0x33, + 0xde, 0xe5, 0x0b, 0x0e, 0xe6, 0xe4, 0xdc, 0x30, 0xfa, 0x8f, 0xdf, 0xd0, 0x58, + 0xcd, 0x5c, 0xf4, 0xee, 0x25, 0xdf, 0x1a, 0x36, 0x05, 0xcc, 0x24, 0xfb, 0xea, + 0xb2, 0x00, 0x53, 0x2a, 0xde, 0xa7, 0x20, 0xe2, 0x1a, 0x4b, 0xe0, 0x56, 0x24, + 0x06, 0xc8, 0x00, 0x09, 0x05, 0xf1, 0xc3, 0xa2, 0x8e, 0xfa, 0x6d, 0x12, 0xf4, + 0x22, 0xe4, 0xeb, 0x32, 0x6b, 0x19, 0x60, 0x0f, 0xa0, 0xf2, 0x88, 0xf3, 0x99, + 0xdf, 0x0f, 0xdc, 0xdc, 0x20, 0xe7, 0x41, 0x54, 0xdb, 0xf3, 0x27, 0xde, 0xcc, + 0x45, 0xe0, 0xe5, 0x21, 0xbe, 0xcc, 0x0c, 0xe8, 0x35, 0x3e, 0x3c, 0xd2, 0x76, + 0xe7, 0xc4, 0xed, 0x31, 0x00, 0x4c, 0x7f, 0xd8, 0xb2, 0xe6, 0x1b, 0x29, 0x0b, + 0x2c, 0x0b, 0x92, 0x43, 0x1b, 0x26, 0xfe, 0xce, 0x1b, 0x17, 0xb9, 0xff, 0xf7, + 0x17, 0x16, 0x2a, 0xc1, 0x06, 0xc6, 0xde, 0xd1, 0x07, 0x08, 0x18, 0x00, 0xf7, + 0xf9, 0x3a, 0x14, 0x02, 0x0f, 0x1d, 0xc8, 0xd4, 0x48, 0xf7, 0xf4, 0xe9, 0xf6, + 0x06, 0x45, 0xf0, 0xee, 0x00, 0x1f, 0x27, 0x46, 0x17, 0x41, 0x7f, 0xfd, 0xe5, + 0x06, 0x19, 0x05, 0xea, 0xf4, 0x11, 0x01, 0x15, 0xb8, 0xe0, 0xd6, 0xdd, 0xeb, + 0x30, 0xcc, 0xe8, 0x1b, 0x01, 0x0f, 0xf1, 0xd7, 0x20, 0xef, 0x04, 0x09, 0xbf, + 0x3a, 0x21, 0x01, 0xd2, 0xe3, 0x18, 0x15, 0xbe, 0x48, 0xf3, 0x1a, 0x10, 0xe0, + 0xe2, 0xed, 0x48, 0x2b, 0xe7, 0x53, 0x64, 0xd3, 0xe6, 0xdb, 0xef, 0xf5, 0xb8, + 0xfc, 0xc2, 0x4c, 0x23, 0x0d, 0x12, 0x1b, 0x04, 0x09, 0xca, 0x2c, 0xc3, 0x91, + 0xcb, 0x12, 0xd3, 0x3d, 0xc2, 0xfc, 0xf4, 0x1b, 0x04, 0x10, 0xbe, 0xf6, 0xcb, + 0xcd, 0xd9, 0x03, 0xe9, 0xf4, 0xec, 0x34, 0x05, 0xf0, 0x0d, 0x2b, 0x06, 0x2d, + 0xe4, 0xf5, 0xb9, 0xe4, 0xc1, 0x43, 0xd6, 0xd5, 0x14, 0x13, 0xe8, 0x05, 0x2f, + 0xf6, 0x2a, 0xed, 0xb8, 0xc9, 0x05, 0x0d, 0xec, 0x4d, 0x49, 0x42, 0xef, 0xce, + 0xcf, 0x27, 0x3d, 0x71, 0x02, 0x61, 0x24, 0xe5, 0xb6, 0xf5, 0xeb, 0xd3, 0x3a, + 0xca, 0x43, 0xd8, 0x47, 0x04, 0x2d, 0x1f, 0x3f, 0xc4, 0xba, 0xb1, 0xf3, 0x36, + 0xec, 0xeb, 0xdd, 0x04, 0x1c, 0xda, 0x50, 0x34, 0x95, 0x2a, 0x96, 0xf9, 0x62, + 0xd9, 0x08, 0xa2, 0xc1, 0x03, 0x9e, 0xa9, 0xe0, 0xf8, 0xd2, 0x1c, 0xf1, 0xbd, + 0x52, 0xa0, 0xc9, 0xdf, 0xfc, 0x11, 0xdf, 0x03, 0xfd, 0xd2, 0x81, 0x04, 0x03, + 0x0a, 0x8f, 0x3b, 0x0b, 0x93, 0xd5, 0x22, 0x06, 0x25, 0xc3, 0x19, 0x5c, 0xc9, + 0xed, 0x2e, 0x24, 0xda, 0xd2, 0xf5, 0xf6, 0xfc, 0xcb, 0x1a, 0xa3, 0xdd, 0x18, + 0xa0, 0x9a, 0xce, 0xec, 0x27, 0x04, 0xfc, 0xf9, 0x04, 0x50, 0x0b, 0xcd, 0x2f, + 0xc3, 0xba, 0xe0, 0x1d, 0x28, 0x37, 0x3c, 0x6f, 0xc8, 0x11, 0xb0, 0xf5, 0xb5, + 0x12, 0x6c, 0x13, 0x35, 0x92, 0x3b, 0x06, 0xff, 0x06, 0xc2, 0xa6, 0xc1, 0xaf, + 0xfa, 0xdf, 0xdc, 0x2f, 0x00, 0xc3, 0x0b, 0xf3, 0xf4, 0xd4, 0xb5, 0xd6, 0x22, + 0x1e, 0x1d, 0xe4, 0x30, 0xe9, 0xff, 0x44, 0xb9, 0xab, 0x10, 0xff, 0xee, 0xdf, + 0x07, 0x0a, 0xe8, 0xdf, 0x15, 0xbc, 0xe1, 0x03, 0xf3, 0x2d, 0x24, 0xf6, 0x51, + 0xfc, 0x81, 0xf5, 0xf9, 0xd7, 0x23, 0x2a, 0xa1, 0xd0, 0x2c, 0x11, 0xfd, 0xfc, + 0xf4, 0xfd, 0xd6, 0x30, 0x26, 0x06, 0xe8, 0xd3, 0xca, 0x79, 0x19, 0xef, 0x37, + 0xfc, 0x3d, 0xd2, 0xc5, 0xc8, 0x10, 0xc2, 0xec, 0x4c, 0xfc, 0x37, 0x11, 0xf8, + 0x12, 0x08, 0x13, 0xb6, 0x13, 0x01, 0xb4, 0x15, 0xf7, 0xca, 0x25, 0x29, 0xc6, + 0xab, 0xc0, 0xe1, 0x9f, 0x07, 0x27, 0x3c, 0xd1, 0x3f, 0xd9, 0xb1, 0xff, 0xce, + 0xee, 0xd3, 0x0b, 0x25, 0x02, 0x07, 0x27, 0x0f, 0xfb, 0x5e, 0xf7, 0x20, 0x27, + 0x10, 0xce, 0x3c, 0xf9, 0x2c, 0xc6, 0xb6, 0xa4, 0xd6, 0x9a, 0x30, 0xe4, 0x20, + 0xbe, 0x1b, 0xa2, 0xdb, 0x0f, 0x88, 0xf7, 0x0f, 0x03, 0x43, 0xc7, 0xfe, 0xd0, + 0xd2, 0x11, 0xce, 0x31, 0x25, 0xf9, 0x2f, 0xfc, 0xd4, 0xe2, 0xab, 0xc1, 0x6d, + 0x00, 0xda, 0xb0, 0xd9, 0xe2, 0x57, 0x4b, 0xe6, 0x05, 0xfe, 0xc0, 0x07, 0x40, + 0xf9, 0x22, 0x66, 0xf7, 0xe5, 0xf7, 0x11, 0x1b, 0x9a, 0xfe, 0x1e, 0x02, 0x2c, + 0x66, 0x1e, 0xf1, 0xd0, 0x2e, 0xe1, 0x11, 0x66, 0xcd, 0xe5, 0x2d, 0xf7, 0x12, + 0xe8, 0xf4, 0xd2, 0xd6, 0x30, 0x5a, 0x20, 0xc4, 0x26, 0x46, 0x27, 0x4c, 0x0f, + 0xd3, 0xe7, 0xee, 0x10, 0x1d, 0xfc, 0x81, 0xf9, 0xce, 0x06, 0xfd, 0x08, 0xf9, + 0xc3, 0xe4, 0xc4, 0x1b, 0x01, 0x01, 0x27, 0xba, 0xea, 0x3f, 0x7f, 0x74, 0x04, + 0xe9, 0xe7, 0xe5, 0x13, 0x2a, 0x34, 0x0b, 0xf4, 0x47, 0xf1, 0xd9, 0xdc, 0x10, + 0x3f, 0x40, 0x2a, 0xff, 0xbb, 0xd8, 0x4c, 0x08, 0x16, 0xbe, 0xff, 0xfd, 0xd2, + 0xfc, 0x0e, 0xd1, 0xbd, 0xfd, 0x3f, 0xd0, 0x08, 0xdc, 0xff, 0x14, 0x0a, 0xe7, + 0x1b, 0xdb, 0x08, 0xbf, 0xf2, 0x0e, 0xc8, 0xfa, 0x7c, 0x0f, 0x13, 0xc9, 0xe7, + 0xfd, 0x6a, 0x20, 0xe9, 0x59, 0x4a, 0xfa, 0x29, 0x30, 0x11, 0x37, 0x08, 0xfd, + 0xda, 0x32, 0x05, 0x04, 0x32, 0x2e, 0x10, 0x0e, 0xf5, 0xd3, 0xf8, 0xde, 0xf1, + 0xae, 0x25, 0x1d, 0x98, 0xe6, 0x43, 0x14, 0x11, 0xba, 0xd9, 0xb6, 0x06, 0xe3, + 0xf4, 0xfa, 0xce, 0xe2, 0xe5, 0xb8, 0xaa, 0x24, 0xfc, 0x1a, 0xea, 0x6b, 0xc0, + 0x8f, 0xf5, 0xb0, 0x2d, 0xe0, 0xed, 0x5b, 0x99, 0xbe, 0x12, 0xc2, 0xeb, 0xf1, + 0x6e, 0x5a, 0x20, 0x20, 0x1d, 0xdb, 0x25, 0xec, 0x03, 0x18, 0x13, 0xe2, 0xf8, + 0xfa, 0x0d, 0x08, 0x1a, 0x26, 0x09, 0x46, 0xd7, 0xdf, 0xe9, 0xaa, 0xe4, 0x08, + 0xf7, 0x36, 0xe3, 0xe6, 0xff, 0x05, 0xfe, 0x0f, 0xcf, 0xe3, 0xe1, 0xcd, 0xf7, + 0x1a, 0x00, 0x2f, 0x10, 0xd5, 0x1c, 0x02, 0xaf, 0x21, 0xea, 0xd3, 0x00, 0xef, + 0xe7, 0xf7, 0xe2, 0xed, 0xc9, 0xf3, 0x04, 0xdd, 0x21, 0x38, 0xda, 0x00, 0x20, + 0xed, 0x3c, 0xfe, 0x3f, 0x06, 0xd2, 0xdd, 0xce, 0x4e, 0xe3, 0x05, 0x0c, 0x05, + 0xdb, 0x29, 0x08, 0xf2, 0xda, 0x16, 0x23, 0xf2, 0x18, 0x28, 0xe8, 0x31, 0x0c, + 0x21, 0xd6, 0xe6, 0x04, 0xf3, 0x07, 0x25, 0xef, 0xf7, 0xfb, 0x03, 0x28, 0xf7, + 0xe0, 0xef, 0x05, 0xe5, 0xf6, 0x03, 0xf9, 0x04, 0xe6, 0xfd, 0xf8, 0xe9, 0x0e, + 0xe7, 0x03, 0x0b, 0xbe, 0x44, 0x21, 0xcd, 0x2a, 0x27, 0xdf, 0x14, 0x31, 0x7f, + 0x03, 0x63, 0x2a, 0x31, 0x17, 0x0b, 0xbc, 0xf6, 0x34, 0x25, 0x01, 0xd0, 0xd5, + 0x13, 0x0d, 0xf3, 0x1b, 0xf9, 0xfb, 0xbc, 0x18, 0x16, 0x07, 0xf4, 0x2c, 0x2c, + 0x01, 0xe5, 0xf2, 0x06, 0x34, 0x49, 0x27, 0xc8, 0x1d, 0xde, 0x57, 0xff, 0x12, + 0xbe, 0x10, 0x07, 0xe5, 0xf2, 0x1d, 0xc8, 0xce, 0x17, 0xb7, 0x03, 0xfb, 0x29, + 0xd2, 0xc5, 0xa4, 0x10, 0xd8, 0x24, 0xde, 0xfa, 0x0f, 0x27, 0xcb, 0xf8, 0x00, + 0x23, 0xfb, 0xfb, 0xe0, 0xdd, 0x2f, 0xeb, 0x47, 0x7f, 0x0e, 0x04, 0xc7, 0xfe, + 0x1e, 0xc9, 0xd4, 0x06, 0x01, 0x04, 0x3d, 0x2a, 0xf2, 0xf8, 0x36, 0xca, 0x16, + 0x28, 0x1a, 0x13, 0x0c, 0x3d, 0x04, 0x3a, 0x0e, 0x03, 0xd9, 0x3c, 0x2c, 0x14, + 0xd6, 0xe9, 0x05, 0xf2, 0xc5, 0x05, 0xe2, 0xd8, 0x1a, 0x0d, 0x04, 0xf5, 0x17, + 0xef, 0x01, 0x39, 0xff, 0x0e, 0x5b, 0xd1, 0xfd, 0xdc, 0x13, 0xf7, 0x0f, 0xd2, + 0x27, 0xde, 0x11, 0xe1, 0xdd, 0x10, 0x29, 0x46, 0xdb, 0x1c, 0xef, 0x02, 0x65, + 0xd8, 0xef, 0xd4, 0x34, 0xa8, 0xe7, 0x36, 0xf7, 0x11, 0x1d, 0xf5, 0x06, 0xdf, + 0xde, 0xeb, 0x07, 0x5c, 0x7f, 0x0d, 0xe6, 0x1f, 0xee, 0x05, 0x0f, 0x20, 0xd0, + 0x1d, 0x11, 0x29, 0x4f, 0x14, 0xfa, 0xfb, 0x9e, 0xa0, 0x4a, 0x08, 0xff, 0x15, + 0x20, 0x64, 0x02, 0xe5, 0xd7, 0x1b, 0xd2, 0x14, 0xe1, 0x2a, 0x50, 0x9b, 0x21, + 0x1d, 0x17, 0x1d, 0x28, 0x9f, 0xdb, 0x31, 0xd4, 0x14, 0xfc, 0xf8, 0xfc, 0xd7, + 0xd9, 0x46, 0x1c, 0x45, 0xdb, 0xe0, 0xa9, 0x2d, 0x0f, 0x43, 0x35, 0x46, 0x0d, + 0x2d, 0xdc, 0xef, 0xd6, 0x01, 0xb4, 0xf9, 0x22, 0x20, 0x35, 0x12, 0xf4, 0xf4, + 0x0f, 0xbb, 0x29, 0xe0, 0xfc, 0xc8, 0x08, 0xf6, 0x48, 0xaf, 0xf2, 0xbc, 0xe4, + 0x1f, 0xba, 0xc3, 0xb5, 0xdb, 0xde, 0xdc, 0xea, 0x02, 0x29, 0xf6, 0x0f, 0x12, + 0xfe, 0x3f, 0x36, 0xe3, 0xeb, 0xea, 0x0d, 0x1d, 0x1f, 0xdd, 0xf0, 0xfa, 0x15, + 0x0a, 0xfe, 0xd8, 0x06, 0x21, 0x0f, 0xf5, 0x24, 0xe0, 0xbb, 0xf7, 0x1a, 0xd8, + 0x02, 0x18, 0x20, 0xef, 0xe5, 0x02, 0x0e, 0x06, 0xf9, 0x12, 0xc4, 0x07, 0x44, + 0x07, 0xdb, 0xe0, 0xcf, 0x09, 0xce, 0x16, 0xec, 0xec, 0xe0, 0xf5, 0xec, 0x0b, + 0x1d, 0x08, 0x3a, 0xd8, 0x0b, 0xd8, 0xf9, 0x03, 0x03, 0xed, 0x0a, 0x19, 0xe9, + 0xe8, 0xe1, 0xd7, 0xe6, 0x0a, 0x40, 0xe1, 0xf2, 0x2b, 0x4c, 0xe6, 0x06, 0xf5, + 0x07, 0x1c, 0xda, 0xf5, 0x27, 0xde, 0xe3, 0xbb, 0xe3, 0xfe, 0xf4, 0xfb, 0x12, + 0xe6, 0x19, 0x7f, 0x4a, 0xf9, 0x1d, 0x2b, 0xf3, 0x19, 0x09, 0x00, 0x12, 0xd2, + 0x0d, 0x0d, 0xed, 0xf5, 0xe0, 0xed, 0x0e, 0x05, 0x06, 0x06, 0xe5, 0x19, 0x23, + 0x31, 0x33, 0x03, 0x20, 0xf5, 0xde, 0x06, 0xfa, 0xfc, 0xdd, 0xdf, 0xd6, 0x14, + 0x0e, 0xed, 0xff, 0x2c, 0x10, 0xef, 0x42, 0x25, 0xd0, 0x0f, 0x13, 0x05, 0xc4, + 0xf1, 0x28, 0xfd, 0x0f, 0xf2, 0xed, 0xd6, 0xc7, 0x1a, 0xf3, 0xfd, 0xdf, 0xd1, + 0xc9, 0xfd, 0x11, 0x08, 0x01, 0xee, 0x29, 0x3e, 0x05, 0xf8, 0xc0, 0x23, 0x27, + 0xce, 0x1c, 0x0b, 0x55, 0xe5, 0xa1, 0x09, 0x08, 0x70, 0xef, 0x22, 0xe6, 0x14, + 0x1f, 0xc7, 0x28, 0xd1, 0xf0, 0x10, 0xd2, 0x29, 0x16, 0x3a, 0xed, 0x0c, 0x29, + 0x08, 0xf6, 0x2a, 0xd9, 0xe8, 0xce, 0x04, 0xf3, 0xde, 0x20, 0x27, 0xfd, 0x0c, + 0x08, 0x01, 0xd9, 0xf0, 0xe1, 0x18, 0x4c, 0x0b, 0xf6, 0xd8, 0xfa, 0x36, 0x20, + 0x0c, 0xe1, 0xfe, 0x00, 0x4b, 0xfe, 0x7f, 0x2f, 0x0d, 0xf6, 0x25, 0xfb, 0x36, + 0x11, 0x12, 0x48, 0xf1, 0x1a, 0x26, 0xfb, 0x20, 0x08, 0x19, 0xe0, 0xd5, 0xf5, + 0x04, 0xd8, 0x06, 0x06, 0xe6, 0xac, 0x19, 0xed, 0xe5, 0x21, 0x23, 0xe1, 0xd5, + 0x29, 0x32, 0xf7, 0x0c, 0xc0, 0xf0, 0x40, 0x0c, 0xee, 0x25, 0x17, 0xec, 0xef, + 0x26, 0xe5, 0x16, 0xff, 0x19, 0x00, 0x34, 0x27, 0xfb, 0x05, 0x2f, 0x10, 0x7f, + 0x67, 0xf3, 0xf6, 0xcf, 0x42, 0x11, 0x10, 0xb4, 0x2d, 0xb9, 0xfb, 0x4d, 0xa4, + 0x12, 0x49, 0xef, 0xc5, 0x48, 0xf9, 0xe8, 0x18, 0xf9, 0x00, 0x23, 0xb2, 0xf6, + 0xcf, 0xd6, 0xfe, 0x1f, 0x22, 0x25, 0xf0, 0xb8, 0x34, 0x1c, 0x0f, 0xe2, 0x39, + 0xea, 0xf8, 0xd2, 0x37, 0xf7, 0xd1, 0x1d, 0xb0, 0x15, 0xed, 0x95, 0xfc, 0xd8, + 0x06, 0xdd, 0xb9, 0x07, 0x48, 0xd1, 0x2c, 0xdd, 0x27, 0x32, 0xe2, 0x31, 0x0a, + 0xdb, 0x0c, 0xde, 0xd0, 0x22, 0x1d, 0x17, 0x37, 0xd0, 0x04, 0x00, 0xe6, 0x11, + 0xae, 0x47, 0x19, 0xc6, 0xea, 0xc1, 0x0e, 0xdb, 0x18, 0xd4, 0xe1, 0x01, 0xec, + 0x53, 0x17, 0xd8, 0xdd, 0xff, 0xff, 0x1a, 0xa3, 0xdc, 0x08, 0xf2, 0xf0, 0xed, + 0x22, 0xee, 0xf2, 0xb4, 0xd7, 0x20, 0x09, 0x0a, 0xd1, 0xc6, 0xe5, 0xb3, 0xfc, + 0x15, 0x2c, 0xd0, 0x23, 0xc6, 0x10, 0xfa, 0x0e, 0xd8, 0xd4, 0x21, 0xf7, 0x7f, + 0x05, 0x06, 0xc1, 0x09, 0xbf, 0x16, 0xeb, 0x07, 0x0d, 0x04, 0xed, 0xd9, 0x2f, + 0x31, 0xec, 0xf8, 0x31, 0x24, 0x13, 0xdc, 0xf4, 0x26, 0x15, 0x0d, 0xf2, 0x1d, + 0x4f, 0x25, 0x09, 0x05, 0x39, 0xf2, 0xfb, 0xfa, 0xc8, 0x01, 0x15, 0xe8, 0x12, + 0x2a, 0xf2, 0x64, 0xbc, 0x0a, 0x2d, 0xe8, 0x37, 0x29, 0x01, 0xf0, 0x1e, 0x4e, + 0xc8, 0xe6, 0xec, 0xe9, 0x0d, 0xd1, 0x0b, 0xfd, 0x0a, 0xe8, 0x06, 0x31, 0x12, + 0x1b, 0x2d, 0xd0, 0x06, 0xf7, 0xf8, 0x18, 0xfc, 0xd9, 0xf8, 0xf9, 0x26, 0x23, + 0x0b, 0xf1, 0xf1, 0x1c, 0xbc, 0xbe, 0x31, 0xfa, 0xd7, 0x15, 0x10, 0xf1, 0xeb, + 0x09, 0xef, 0x0d, 0x2c, 0x08, 0xf1, 0xd8, 0xfa, 0xe4, 0xb4, 0x05, 0xac, 0xc6, + 0x95, 0xf0, 0x3a, 0x56, 0x06, 0x58, 0x12, 0x81, 0x13, 0xac, 0xf3, 0xb0, 0x14, + 0x26, 0xdb, 0x1d, 0x38, 0xf7, 0x1c, 0x5a, 0x02, 0x0a, 0x19, 0x0f, 0xf6, 0x30, + 0x14, 0x69, 0x42, 0xe0, 0xec, 0xcf, 0xae, 0xdd, 0xec, 0xd7, 0x3c, 0xc5, 0xd2, + 0x19, 0xdc, 0xc3, 0x09, 0x1d, 0xf2, 0x48, 0xee, 0x7c, 0xe9, 0x13, 0xe7, 0x58, + 0x43, 0x33, 0x13, 0x0e, 0xbc, 0xf3, 0xd5, 0xa0, 0x41, 0x50, 0x1f, 0xfe, 0xfd, + 0x28, 0xd7, 0xde, 0xc0, 0xe1, 0x12, 0x18, 0x40, 0xca, 0xf1, 0x10, 0xed, 0xcc, + 0xf9, 0xe2, 0x34, 0xa3, 0x0a, 0xe6, 0xfd, 0x14, 0xc6, 0x0a, 0xcd, 0x10, 0x25, + 0xf1, 0x0c, 0x03, 0xda, 0xfa, 0xa9, 0xd4, 0xfc, 0x2f, 0x34, 0x15, 0xfc, 0x13, + 0x0b, 0x05, 0xcf, 0xe2, 0xb2, 0xb0, 0xf6, 0x22, 0x00, 0xc5, 0x26, 0xeb, 0x09, + 0x02, 0x3c, 0x35, 0x0b, 0x6a, 0xe3, 0xe9, 0xf9, 0xca, 0x51, 0xe8, 0xf7, 0xe4, + 0x1b, 0x3c, 0x16, 0xcc, 0x02, 0xe1, 0x1c, 0x2c, 0x12, 0x2d, 0x1e, 0x58, 0x24, + 0xe6, 0xe7, 0xd6, 0xf5, 0x0d, 0xe7, 0xf9, 0xe7, 0xfd, 0xd5, 0xe1, 0x15, 0x0a, + 0x3e, 0x19, 0xc4, 0x11, 0x27, 0x9e, 0x12, 0x1c, 0xd6, 0xb6, 0x1a, 0xf2, 0xf1, + 0x45, 0x3f, 0x29, 0xbf, 0xc7, 0x21, 0xd3, 0xa1, 0x33, 0xf6, 0x06, 0x3c, 0x04, + 0x95, 0x10, 0x3d, 0x55, 0xee, 0x24, 0xf7, 0xe8, 0xf3, 0x17, 0xfa, 0x1b, 0xbc, + 0xf2, 0x0d, 0x30, 0x36, 0xff, 0x1e, 0xeb, 0xf8, 0x21, 0xff, 0x08, 0xc5, 0x26, + 0x00, 0xb0, 0xf3, 0xfe, 0xf6, 0xeb, 0xc5, 0xac, 0xcf, 0xf7, 0x3a, 0x42, 0x1c, + 0x27, 0x18, 0xe9, 0xf7, 0xd6, 0xf9, 0x2c, 0xec, 0x29, 0x25, 0xe3, 0xde, 0x3b, + 0xe1, 0xf3, 0x34, 0x05, 0x1e, 0x7f, 0x05, 0xf2, 0x1c, 0x12, 0xf1, 0x13, 0x16, + 0xbb, 0x32, 0x68, 0xb3, 0x2c, 0xda, 0xf6, 0x4a, 0xdf, 0x06, 0x3c, 0xca, 0xab, + 0x7c, 0xd8, 0xe0, 0x40, 0x18, 0xb8, 0xfc, 0xf2, 0x54, 0x38, 0xfe, 0x2f, 0x0a, + 0xbe, 0x41, 0xbf, 0xeb, 0x10, 0xab, 0x32, 0xbe, 0xe4, 0x00, 0x2c, 0x04, 0xf6, + 0x33, 0xcf, 0x07, 0x38, 0x18, 0x06, 0x88, 0xe1, 0x27, 0x70, 0x2f, 0x4d, 0x2a, + 0x15, 0xf1, 0x0a, 0xc6, 0xca, 0x35, 0xf4, 0xec, 0x45, 0xd2, 0x48, 0xb7, 0x25, + 0x48, 0xd4, 0x85, 0xd7, 0xe8, 0x22, 0x59, 0x13, 0xd7, 0x00, 0xc7, 0xf9, 0x12, + 0x3c, 0x51, 0x1c, 0x5b, 0xca, 0x06, 0x37, 0xed, 0xaf, 0xd7, 0x44, 0xd7, 0xb6, + 0x1e, 0xea, 0x01, 0x62, 0xe8, 0x2e, 0xd6, 0x16, 0x4d, 0x9c, 0x19, 0x48, 0xf3, + 0x18, 0xfa, 0x1d, 0x28, 0xe4, 0xb3, 0xcb, 0xed, 0x7f, 0x49, 0xfe, 0xce, 0xd8, + 0x12, 0x31, 0x25, 0x13, 0x04, 0x09, 0xac, 0x1c, 0x31, 0x0d, 0x4b, 0xfc, 0x12, + 0xc4, 0x0f, 0x60, 0xc1, 0x03, 0x04, 0x56, 0xc8, 0x40, 0x18, 0xfc, 0x14, 0xc2, + 0xeb, 0xc3, 0x98, 0xfb, 0x17, 0xf8, 0x22, 0xf8, 0xf8, 0x02, 0x27, 0x04, 0xc0, + 0x0b, 0x33, 0x4e, 0xf5, 0xef, 0x47, 0x02, 0xf7, 0xf2, 0xe1, 0x18, 0x36, 0x16, + 0x1e, 0x54, 0x3b, 0xfe, 0xd7, 0xec, 0xc1, 0x0d, 0x25, 0xd2, 0xad, 0xec, 0x2e, + 0x08, 0xfe, 0xec, 0x00, 0xd5, 0x36, 0x07, 0x39, 0x07, 0xe3, 0x04, 0xce, 0xeb, + 0x28, 0x23, 0x37, 0xee, 0x10, 0xf6, 0xf2, 0x12, 0xe8, 0x15, 0x00, 0x36, 0xd7, + 0x14, 0x10, 0x02, 0xff, 0xbc, 0xea, 0xcd, 0x1d, 0xf1, 0xf5, 0xe5, 0x37, 0xf9, + 0xf0, 0x0f, 0x32, 0x29, 0x11, 0x06, 0x06, 0x0a, 0xca, 0xea, 0x15, 0x4f, 0x16, + 0x4b, 0xff, 0xe0, 0xef, 0xe1, 0xfa, 0x32, 0xd9, 0xee, 0x7f, 0x06, 0x17, 0xe9, + 0xf0, 0xdc, 0x0b, 0xde, 0x5d, 0x0e, 0x35, 0x2c, 0x23, 0x29, 0x18, 0xe6, 0x23, + 0x1c, 0xe0, 0x2c, 0xf4, 0x06, 0xef, 0xec, 0x11, 0xdd, 0x07, 0xfc, 0x38, 0x35, + 0x40, 0x3d, 0xf1, 0xe4, 0xf1, 0x05, 0xfd, 0x18, 0x21, 0xd0, 0x05, 0x2c, 0xfc, + 0x26, 0xd6, 0xdb, 0xd5, 0x17, 0xeb, 0x43, 0x08, 0x2c, 0x21, 0xfb, 0xe4, 0xeb, + 0xea, 0xb9, 0xf4, 0xba, 0xe9, 0x4a, 0xf3, 0x30, 0x0c, 0xe8, 0x10, 0x5f, 0x1a, + 0x04, 0xec, 0x2b, 0xf5, 0x07, 0xcf, 0xfa, 0xd7, 0x81, 0x09, 0xf3, 0x06, 0xe7, + 0xfa, 0x13, 0xf3, 0x2a, 0xff, 0x33, 0xf3, 0x02, 0x1c, 0xe7, 0x05, 0x2d, 0x34, + 0xce, 0x10, 0x2c, 0xfc, 0x2b, 0x17, 0xfd, 0x3a, 0xdb, 0x22, 0xf1, 0x0a, 0xea, + 0xf2, 0x32, 0xf1, 0xec, 0xef, 0xf5, 0xf6, 0x1a, 0x14, 0x02, 0x07, 0x0b, 0x12, + 0xc1, 0x34, 0x38, 0xe0, 0x19, 0x4d, 0xf5, 0xfa, 0xec, 0xea, 0xd5, 0xf3, 0x54, + 0xe6, 0x1b, 0x08, 0x17, 0x14, 0xd6, 0x06, 0x00, 0xea, 0x1b, 0x2d, 0x27, 0xf4, + 0xf5, 0x07, 0xdd, 0x07, 0x1d, 0xe9, 0xde, 0x04, 0x61, 0xf2, 0xf3, 0xf4, 0xbe, + 0xba, 0xe6, 0x12, 0x14, 0x1e, 0x0c, 0xdf, 0xee, 0x0f, 0x0b, 0xd4, 0x14, 0x29, + 0xf1, 0xd8, 0x11, 0x39, 0xfd, 0x4c, 0x2b, 0xc6, 0x2e, 0xe1, 0xe9, 0x14, 0x27, + 0xc2, 0x04, 0xf3, 0xe0, 0xc5, 0x16, 0xec, 0xea, 0xfc, 0x1a, 0x18, 0xc7, 0xff, + 0xfc, 0xfa, 0xef, 0xd2, 0x01, 0x21, 0x33, 0x00, 0x7f, 0xe9, 0x2b, 0x08, 0x49, + 0xe0, 0x27, 0x2a, 0xf4, 0xdd, 0xfa, 0x21, 0x1c, 0x62, 0xd9, 0xf5, 0xcc, 0xf1, + 0x29, 0xe3, 0x8e, 0xe9, 0x19, 0x31, 0xb2, 0x67, 0xff, 0x37, 0x1a, 0xf6, 0x0c, + 0xe6, 0x0c, 0xcb, 0x08, 0x04, 0x10, 0xfb, 0xfc, 0x09, 0xde, 0x01, 0x03, 0xee, + 0xfd, 0xd1, 0x0d, 0x4a, 0xcd, 0xd0, 0x1d, 0x2d, 0xd4, 0x09, 0x2a, 0x30, 0x02, + 0x1a, 0x10, 0x0d, 0xf9, 0x4b, 0xdd, 0xf3, 0x24, 0x14, 0xe9, 0x01, 0xef, 0x17, + 0x4c, 0x1a, 0x26, 0xf3, 0x06, 0xee, 0xe3, 0x26, 0xd5, 0x36, 0x4a, 0x00, 0x08, + 0x02, 0xfb, 0xad, 0x24, 0x04, 0xf4, 0xdb, 0x0d, 0x2b, 0xe1, 0xf8, 0xe1, 0xc7, + 0x1a, 0xd0, 0x0d, 0xcb, 0x1b, 0xeb, 0x07, 0xdb, 0xe9, 0xd3, 0xdc, 0xb7, 0x41, + 0xf9, 0x0b, 0x1e, 0x17, 0xfc, 0x17, 0x09, 0xc7, 0x1b, 0x1d, 0xd9, 0xda, 0xf9, + 0x15, 0x04, 0xe7, 0xc8, 0x5a, 0xe3, 0xec, 0xfb, 0x4c, 0xe8, 0xf5, 0x49, 0x04, + 0xd5, 0x2c, 0xb8, 0x81, 0xde, 0xef, 0x0c, 0x30, 0xe8, 0xe7, 0x02, 0x1c, 0xfb, + 0x03, 0x20, 0x19, 0x07, 0xef, 0x07, 0xd7, 0x0a, 0x3c, 0xeb, 0x1d, 0x1b, 0x0c, + 0xf5, 0x05, 0xf0, 0x2d, 0x21, 0xce, 0xdf, 0xf9, 0xfb, 0x5a, 0x14, 0xf0, 0x2a, + 0x01, 0x4d, 0xf0, 0xeb, 0xf3, 0x14, 0xca, 0x0d, 0x34, 0xfb, 0x22, 0xfa, 0xe4, + 0x08, 0x16, 0xd3, 0xf1, 0x0b, 0x32, 0x18, 0x15, 0xf8, 0xe2, 0x33, 0xe1, 0x0c, + 0x1a, 0xfe, 0x03, 0xfb, 0xe6, 0xd4, 0x16, 0xe7, 0xca, 0x19, 0x1b, 0x16, 0x1a, + 0xfc, 0x1e, 0xfa, 0xcc, 0xc0, 0x44, 0xd8, 0x12, 0x30, 0xfe, 0xfd, 0xd6, 0xdb, + 0xfc, 0xf5, 0xf6, 0x2f, 0xfe, 0xcc, 0xd8, 0x12, 0x16, 0xcc, 0x81, 0x1c, 0x9a, + 0x29, 0x20, 0x13, 0x0e, 0x2e, 0x00, 0xfa, 0xfb, 0xca, 0x1d, 0x12, 0xfa, 0x15, + 0xdc, 0xe7, 0xd4, 0x03, 0xe5, 0xf7, 0x45, 0x00, 0xb9, 0x22, 0xf3, 0xde, 0x09, + 0x39, 0x0a, 0xdb, 0x00, 0xf8, 0xda, 0xe9, 0x0c, 0x15, 0x11, 0x12, 0xc7, 0x1a, + 0xff, 0x12, 0xdb, 0xfb, 0xef, 0xd7, 0xad, 0xfc, 0xff, 0xf6, 0xdc, 0x01, 0xf3, + 0x0b, 0x24, 0xf1, 0xed, 0xd1, 0xd6, 0x43, 0xd3, 0xff, 0xdd, 0x23, 0xf2, 0x28, + 0xc9, 0x03, 0x13, 0x0a, 0xee, 0xdf, 0x02, 0xcf, 0x02, 0xda, 0x0d, 0x29, 0xfc, + 0x21, 0xe5, 0xe8, 0x41, 0xef, 0xc7, 0xd3, 0xf4, 0xcd, 0x0a, 0x03, 0x06, 0xf9, + 0x26, 0xe3, 0x28, 0x20, 0x3f, 0xe2, 0xd6, 0x25, 0x44, 0x06, 0x45, 0x67, 0x21, + 0xdd, 0x21, 0x16, 0x0c, 0x2c, 0xf0, 0x1a, 0xcc, 0xc1, 0x10, 0x17, 0xf6, 0x05, + 0x2f, 0xe2, 0xe9, 0xec, 0xf3, 0xb5, 0xf2, 0x20, 0x0d, 0x11, 0xca, 0xa0, 0xff, + 0xe4, 0xe1, 0x97, 0x26, 0xc8, 0xc4, 0xe0, 0x43, 0x21, 0xd5, 0xc9, 0xca, 0x00, + 0x33, 0x32, 0x26, 0x0f, 0xef, 0xae, 0xda, 0x3c, 0xe0, 0x3f, 0x1c, 0xc3, 0x1a, + 0xf8, 0xd5, 0x11, 0x21, 0x58, 0xc8, 0x08, 0x2e, 0x23, 0x21, 0xd7, 0x08, 0xf2, + 0x31, 0xe6, 0xe7, 0xef, 0xe7, 0xca, 0xee, 0xdd, 0xe1, 0x47, 0x0b, 0x1a, 0x04, + 0xfe, 0xf2, 0xf2, 0xc9, 0xf5, 0x1d, 0xe7, 0x03, 0x11, 0x02, 0x32, 0x14, 0xf9, + 0xe2, 0xc5, 0xea, 0xdc, 0x0e, 0x45, 0xf2, 0x2d, 0xd6, 0xf2, 0x04, 0x2c, 0xe3, + 0x7f, 0x2f, 0x29, 0x59, 0xf8, 0x24, 0x52, 0x46, 0xef, 0x59, 0x73, 0x8d, 0x15, + 0xfc, 0xcc, 0x7e, 0xec, 0x0e, 0xc6, 0xe2, 0x4f, 0x15, 0x2c, 0xeb, 0x3c, 0xfa, + 0x04, 0x03, 0x5c, 0xda, 0x15, 0x35, 0xe4, 0xdf, 0xbc, 0x07, 0x1d, 0xfd, 0xfa, + 0x51, 0x3a, 0xf6, 0x54, 0x09, 0x91, 0x04, 0xe4, 0xec, 0x27, 0x15, 0xe1, 0xae, + 0x3c, 0x08, 0xf0, 0xea, 0x01, 0xe3, 0xf5, 0x7f, 0x35, 0x3f, 0x04, 0xc4, 0xdd, + 0x75, 0x28, 0x10, 0x50, 0xf4, 0xdc, 0xaa, 0x42, 0xd2, 0x9b, 0x09, 0xf4, 0x47, + 0x57, 0xf1, 0x3f, 0xe6, 0xdb, 0xec, 0x30, 0x72, 0x90, 0x96, 0x4f, 0xe6, 0xd2, + 0xf4, 0x01, 0x22, 0xea, 0x21, 0x0c, 0xa4, 0xfe, 0xf6, 0x3b, 0x6d, 0xc0, 0xf0, + 0xf5, 0xf0, 0xf5, 0x00, 0x5e, 0xce, 0x38, 0xb3, 0x27, 0x96, 0x97, 0xf9, 0xec, + 0xb8, 0xc5, 0x10, 0xf8, 0x12, 0xc5, 0xf3, 0x97, 0x20, 0xe7, 0xf3, 0xe5, 0xb4, + 0x23, 0xe4, 0x0d, 0x3f, 0xa8, 0x17, 0xcf, 0x0d, 0x4c, 0x18, 0xdd, 0x10, 0xf8, + 0x81, 0x28, 0x00, 0xeb, 0xd8, 0xfa, 0x36, 0x49, 0xfa, 0x2b, 0xdc, 0xea, 0x24, + 0xdb, 0xb8, 0x09, 0x20, 0x67, 0x12, 0x0f, 0x12, 0x07, 0x01, 0x9b, 0xba, 0x0d, + 0xc0, 0x6f, 0x07, 0xec, 0xc0, 0x20, 0x27, 0x11, 0xe1, 0x22, 0x1b, 0x0f, 0x2f, + 0xe9, 0x34, 0xc1, 0x11, 0xbf, 0xd6, 0xce, 0xad, 0x02, 0x1a, 0x2d, 0x1f, 0xe1, + 0x06, 0x2e, 0x06, 0xe6, 0x02, 0x34, 0xd2, 0xab, 0x1b, 0x71, 0x08, 0xec, 0xd7, + 0xd4, 0x2b, 0xe2, 0x26, 0xf7, 0x01, 0xfc, 0x30, 0x00, 0x57, 0xea, 0xc0, 0x0b, + 0x0a, 0xc0, 0x1b, 0xdd, 0x51, 0x1d, 0xda, 0x6d, 0xc6, 0x29, 0xfe, 0x04, 0x38, + 0xf4, 0x0f, 0x1b, 0xfc, 0xbb, 0x51, 0xd6, 0x2c, 0xf4, 0x2e, 0xa5, 0xc7, 0xe9, + 0x23, 0xec, 0x51, 0x12, 0xfb, 0xcc, 0x0c, 0xed, 0x75, 0xac, 0xe9, 0x31, 0x37, + 0x21, 0x5b, 0xcc, 0xcf, 0xde, 0xd0, 0x6c, 0x63, 0x0d, 0xc9, 0x2b, 0x4c, 0xe8, + 0xb8, 0x27, 0xe2, 0xa3, 0x47, 0xef, 0x1b, 0x26, 0xec, 0xc6, 0xfb, 0x64, 0x14, + 0xcd, 0xf3, 0x08, 0x30, 0x19, 0xbf, 0x28, 0xe4, 0x06, 0xd7, 0x84, 0xd4, 0x45, + 0x8b, 0x06, 0xe8, 0xab, 0xdc, 0x39, 0x17, 0x2c, 0xd2, 0xa8, 0x4e, 0x10, 0xd9, + 0xb0, 0xe4, 0x3d, 0xb7, 0x01, 0xce, 0xe3, 0xd5, 0x03, 0x10, 0xed, 0xe5, 0x32, + 0x4c, 0xbb, 0x1d, 0x2f, 0xbf, 0xba, 0x22, 0x08, 0x2e, 0x6f, 0x28, 0xa5, 0xbc, + 0xfa, 0xe8, 0xad, 0x8f, 0x92, 0xe3, 0xe4, 0x29, 0x14, 0xe4, 0xdd, 0xd2, 0xf6, + 0xd1, 0xd2, 0x29, 0x06, 0xc9, 0xe7, 0xe8, 0x0c, 0x6d, 0x5d, 0x27, 0x20, 0xc4, + 0xaf, 0x0b, 0xeb, 0x26, 0x91, 0xe2, 0xf2, 0x14, 0x0f, 0x81, 0x21, 0x04, 0xd0, + 0x17, 0x5e, 0x07, 0x1b, 0x62, 0x26, 0x15, 0x23, 0xfb, 0xe3, 0x2f, 0x00, 0xe3, + 0xe4, 0xcc, 0xf7, 0x9f, 0x18, 0x0b, 0x08, 0x2b, 0xf3, 0xd6, 0xfc, 0xf0, 0xf5, + 0xc2, 0xba, 0xd6, 0xa3, 0xb3, 0x0f, 0x10, 0xfb, 0x11, 0x26, 0xde, 0x18, 0x12, + 0xfa, 0x13, 0xfe, 0xb6, 0xf4, 0xf5, 0x30, 0xd1, 0xcf, 0xfc, 0xfe, 0x19, 0xd4, + 0xbf, 0x24, 0xc1, 0xc4, 0xdc, 0x2f, 0xec, 0x47, 0x49, 0xa8, 0xe4, 0x19, 0x11, + 0xfb, 0x9b, 0x1f, 0xe1, 0xd2, 0x38, 0xe3, 0xf1, 0x32, 0xff, 0xd8, 0x0a, 0x14, + 0xd6, 0x1c, 0xb9, 0x54, 0xdd, 0x37, 0xce, 0xd1, 0xfd, 0xde, 0x09, 0xbb, 0xe8, + 0x12, 0xfc, 0xf2, 0x10, 0x1e, 0xfb, 0xe5, 0xe5, 0x1d, 0xd0, 0x0a, 0xdb, 0x81, + 0xe3, 0xe8, 0xe8, 0x3f, 0xa6, 0xd9, 0xf3, 0xf3, 0x20, 0x2b, 0xf8, 0x3b, 0x19, + 0x40, 0xf1, 0xc0, 0x1d, 0x7d, 0x0e, 0x55, 0x46, 0xc1, 0xf5, 0xe3, 0x14, 0x62, + 0xf0, 0x13, 0xe5, 0x05, 0xe5, 0x0b, 0xca, 0x10, 0xf9, 0xe0, 0xde, 0x45, 0xd2, + 0x28, 0x2c, 0x3f, 0xef, 0x47, 0xd3, 0x1d, 0xd6, 0xe1, 0xb4, 0x10, 0xff, 0x29, + 0x36, 0x5d, 0xe8, 0x1b, 0x02, 0xe4, 0x0f, 0x04, 0x0e, 0xf5, 0xdd, 0x09, 0x28, + 0x0c, 0x1a, 0x26, 0x0e, 0xe6, 0xab, 0x81, 0xda, 0xdc, 0x38, 0xcc, 0xef, 0xc6, + 0xb3, 0x12, 0x01, 0xc4, 0xd1, 0xe8, 0xf2, 0xfa, 0x38, 0x0f, 0x53, 0x42, 0xfd, + 0xfc, 0xc4, 0xc0, 0x19, 0xd9, 0x30, 0x12, 0xf8, 0x23, 0xad, 0xfa, 0x19, 0xf0, + 0x27, 0x14, 0xf3, 0xb3, 0xdd, 0xf9, 0xbf, 0x42, 0xdc, 0x1f, 0x2c, 0x35, 0xe6, + 0xd3, 0xc3, 0xee, 0x0b, 0x03, 0xe1, 0x1b, 0xa0, 0x07, 0x09, 0x04, 0x8d, 0xfe, + 0x0c, 0xda, 0x34, 0xc0, 0xfa, 0x25, 0x0a, 0x2f, 0x1e, 0xe4, 0xf3, 0x13, 0xe6, + 0xf1, 0xbd, 0xd0, 0xf8, 0x43, 0xe2, 0x04, 0xce, 0x33, 0x00, 0x1e, 0xbb, 0xb3, + 0xe5, 0xf2, 0xe7, 0xed, 0xea, 0x11, 0x19, 0xfe, 0xfc, 0x19, 0x27, 0xd8, 0xc0, + 0x09, 0x75, 0xfe, 0xf2, 0xf9, 0xcf, 0xf8, 0xf7, 0x03, 0xeb, 0x10, 0x19, 0x3f, + 0x3d, 0xe0, 0x3d, 0x22, 0x23, 0xef, 0x02, 0x42, 0xe5, 0xd6, 0x32, 0xfa, 0x08, + 0x38, 0xe3, 0xca, 0x5f, 0x16, 0xc3, 0xc4, 0x02, 0x4c, 0xd5, 0x08, 0xa4, 0xfa, + 0x29, 0xf9, 0xe6, 0x37, 0xfe, 0xfd, 0xdc, 0xbd, 0x48, 0x12, 0x3c, 0xf4, 0xed, + 0x0d, 0x04, 0x04, 0xe5, 0x12, 0x04, 0xe2, 0xc7, 0x17, 0xdc, 0x40, 0x2c, 0xe5, + 0xe5, 0x31, 0x0b, 0xd3, 0xcb, 0x25, 0xf0, 0xfd, 0xff, 0x12, 0x25, 0xda, 0x18, + 0x1c, 0x0c, 0xf7, 0xd3, 0x11, 0x4c, 0xd9, 0x05, 0xd2, 0x08, 0xee, 0x3f, 0x19, + 0xd3, 0xf5, 0xd9, 0xe4, 0x12, 0x0f, 0x25, 0x30, 0xeb, 0x11, 0xe9, 0x22, 0x12, + 0x81, 0x04, 0xd9, 0xe1, 0x1a, 0x22, 0x07, 0x35, 0x01, 0xb6, 0xdf, 0xef, 0x06, + 0x15, 0xdb, 0x3e, 0x0b, 0xcb, 0x0b, 0x01, 0x3e, 0x0f, 0xbc, 0xe7, 0xf3, 0x2f, + 0x08, 0x27, 0x3a, 0xb6, 0xd3, 0x4d, 0xf8, 0xe7, 0x2e, 0x77, 0x8f, 0xed, 0x21, + 0x28, 0xe9, 0xfb, 0xee, 0x0c, 0xd1, 0xfc, 0xec, 0xfa, 0xfa, 0xf5, 0xf1, 0x1f, + 0x1d, 0xce, 0x04, 0x22, 0xb6, 0x1d, 0x1a, 0xd5, 0x72, 0x9f, 0x34, 0x01, 0xc9, + 0x03, 0x08, 0xe4, 0x39, 0xff, 0xcf, 0x13, 0xf6, 0xf0, 0x35, 0xfb, 0x79, 0xa8, + 0xe8, 0xf3, 0xee, 0x0b, 0xe9, 0x15, 0x3c, 0xf8, 0xc0, 0x44, 0xb8, 0xe2, 0xec, + 0x08, 0x24, 0xbf, 0x14, 0x2b, 0xe5, 0xe6, 0x22, 0xfc, 0x12, 0x0d, 0x1d, 0xc8, + 0xf6, 0x0c, 0xdb, 0x46, 0xfe, 0xc5, 0x8b, 0x83, 0x0e, 0x25, 0x32, 0x46, 0xbe, + 0x8f, 0xd8, 0xc4, 0xd9, 0xf6, 0x3d, 0x41, 0xed, 0x20, 0xf2, 0xd5, 0x42, 0xe0, + 0x2e, 0x20, 0xfe, 0x0e, 0x2e, 0xe3, 0xed, 0x0b, 0x7f, 0x24, 0x5b, 0xdf, 0xed, + 0xfa, 0xd1, 0xf2, 0x69, 0x29, 0x72, 0x13, 0xd0, 0x60, 0xee, 0xf9, 0xc3, 0x2d, + 0xff, 0xf8, 0xfd, 0x1b, 0xf8, 0x07, 0x3d, 0x1b, 0xbe, 0xe6, 0x02, 0xd6, 0x2f, + 0x29, 0x15, 0xe3, 0x26, 0xc7, 0xde, 0x30, 0x2f, 0xf6, 0xe9, 0x2a, 0x8f, 0x1c, + 0x0b, 0xd9, 0x1c, 0x01, 0xc8, 0x06, 0xf3, 0x31, 0xc0, 0x00, 0xf4, 0x33, 0x11, + 0xe9, 0x23, 0xdd, 0xf2, 0xfc, 0x11, 0xfb, 0x4f, 0x1f, 0xb7, 0x19, 0xc0, 0x19, + 0xf4, 0x22, 0x26, 0x0a, 0x1e, 0xd9, 0xfb, 0x18, 0x12, 0x12, 0xf5, 0x10, 0x08, + 0xf9, 0x12, 0x4e, 0x37, 0x38, 0xeb, 0xfd, 0xf0, 0x24, 0xdb, 0xc6, 0xfc, 0xeb, + 0x1f, 0xfd, 0xc6, 0x10, 0xf1, 0x36, 0xe9, 0x16, 0xfa, 0x4a, 0xf1, 0x0a, 0xf4, + 0xee, 0xe2, 0x81, 0x33, 0x47, 0xef, 0x0c, 0x30, 0xcb, 0xe4, 0x15, 0x2d, 0x3d, + 0xf6, 0x1e, 0x32, 0xfd, 0x23, 0x04, 0xbe, 0x22, 0xfe, 0x0e, 0x30, 0xff, 0x57, + 0x19, 0xf3, 0xf5, 0x12, 0xe7, 0x21, 0x0c, 0xd4, 0xf9, 0x32, 0x1f, 0x46, 0xe1, + 0x36, 0x06, 0x4f, 0xdc, 0x02, 0x4a, 0xe5, 0x29, 0xd1, 0x41, 0xfc, 0x2e, 0x58, + 0xdb, 0xee, 0xfd, 0x11, 0x34, 0xf3, 0x0e, 0xeb, 0x51, 0xd6, 0xb8, 0x12, 0xe5, + 0x1c, 0x17, 0x3e, 0x38, 0x0a, 0xd6, 0xf1, 0x28, 0x09, 0xf1, 0x1c, 0xee, 0xaf, + 0xb0, 0x10, 0xc1, 0xe9, 0x2c, 0xc8, 0xaa, 0xb0, 0x52, 0xf0, 0x4c, 0x37, 0xd1, + 0x21, 0xff, 0x24, 0xbf, 0x38, 0x0a, 0xf4, 0xa2, 0xdc, 0x28, 0xb7, 0xf5, 0xf6, + 0xf0, 0xbd, 0x09, 0xf5, 0xe6, 0x02, 0x08, 0xfe, 0xa2, 0xdb, 0x28, 0x26, 0x26, + 0xdd, 0x15, 0x38, 0xfd, 0xe6, 0xdd, 0x00, 0xdb, 0xea, 0xc7, 0x08, 0xa0, 0x08, + 0x30, 0x07, 0xf6, 0xb4, 0xf2, 0x1f, 0xf1, 0xcb, 0x91, 0x4b, 0xe4, 0x37, 0xf1, + 0x7f, 0x2f, 0x53, 0x03, 0xeb, 0x65, 0x05, 0xbe, 0xb3, 0xdb, 0xd3, 0x1c, 0xcb, + 0x4a, 0xf4, 0x23, 0xd8, 0x1a, 0x33, 0xc8, 0xd5, 0xfe, 0x21, 0x17, 0x35, 0x3f, + 0xfb, 0xcb, 0x06, 0xc8, 0x07, 0xf6, 0xde, 0xd3, 0xdc, 0x07, 0x02, 0x23, 0x4f, + 0x30, 0x08, 0xe5, 0xfb, 0x1c, 0xf8, 0xc6, 0xce, 0x07, 0x1d, 0x1f, 0x41, 0xea, + 0xf0, 0xce, 0x44, 0xee, 0x0c, 0xd6, 0xc6, 0x08, 0xe4, 0xd8, 0x2f, 0xf7, 0xf7, + 0xbc, 0xad, 0xe0, 0x32, 0xbf, 0xed, 0x86, 0x1b, 0xe4, 0xfc, 0xfc, 0x42, 0x16, + 0x2a, 0xc6, 0xca, 0xe8, 0xf8, 0x42, 0xf7, 0x0b, 0xf5, 0xfd, 0xf8, 0xe2, 0xe3, + 0x20, 0xfb, 0xee, 0x14, 0x25, 0x12, 0x3a, 0xe6, 0xd9, 0x16, 0xef, 0xbb, 0xed, + 0x3d, 0xe9, 0xe4, 0x1e, 0xe5, 0x17, 0x45, 0xa1, 0x32, 0xe2, 0xc0, 0x90, 0x17, + 0x29, 0x2a, 0xe5, 0x1f, 0x0a, 0x36, 0x1c, 0xd0, 0xed, 0x2f, 0x1b, 0xe9, 0x18, + 0x82, 0x0b, 0x81, 0x00, 0x15, 0x32, 0xd6, 0xe5, 0x2b, 0x24, 0xf2, 0xf1, 0xe6, + 0xc5, 0xf9, 0x0a, 0xec, 0x25, 0xd6, 0xe8, 0xdb, 0x21, 0xff, 0xc0, 0xee, 0xe7, + 0xee, 0x29, 0xe2, 0x40, 0x1b, 0x1f, 0xf9, 0x48, 0x10, 0xe1, 0x0b, 0xf9, 0xdd, + 0x20, 0xf5, 0x28, 0xdf, 0x02, 0xdf, 0xdb, 0xc5, 0x02, 0xfd, 0x45, 0x28, 0x38, + 0x1f, 0xf0, 0x40, 0xc7, 0xf0, 0xf5, 0x16, 0x18, 0xf7, 0xba, 0x36, 0xe7, 0xcf, + 0xd0, 0xf3, 0xeb, 0xc9, 0x14, 0x00, 0xee, 0xfc, 0x1c, 0xee, 0xe4, 0x0e, 0xdc, + 0x1d, 0xdb, 0x35, 0xe2, 0x05, 0x19, 0xc0, 0x4d, 0xe8, 0x16, 0xd9, 0x0c, 0xe5, + 0xe5, 0x1e, 0x03, 0xce, 0x19, 0x14, 0x81, 0x1f, 0xfb, 0x47, 0x0b, 0x03, 0x15, + 0xe8, 0x01, 0xf8, 0x13, 0xfc, 0x08, 0x02, 0x02, 0xf5, 0x0d, 0xf4, 0x28, 0x04, + 0xfd, 0xfd, 0xc2, 0x09, 0x15, 0xf9, 0xaa, 0x06, 0x0a, 0x0e, 0x00, 0x10, 0x04, + 0xb7, 0xb2, 0xc3, 0xee, 0xc9, 0x30, 0x48, 0x10, 0x5a, 0xd2, 0xe2, 0x08, 0xee, + 0xef, 0xdb, 0x00, 0x06, 0x53, 0xfe, 0x28, 0xeb, 0xf4, 0xb6, 0xfe, 0x0d, 0x25, + 0xe1, 0x17, 0x06, 0x00, 0xfc, 0x04, 0xdc, 0x3a, 0x33, 0x11, 0x41, 0x1b, 0xee, + 0x1b, 0x06, 0xd6, 0xdd, 0x2a, 0x03, 0x3e, 0xe4, 0xe7, 0x46, 0xf5, 0xec, 0x2d, + 0x1b, 0xe0, 0xe9, 0x02, 0xed, 0xfc, 0xd7, 0xfe, 0xe3, 0xf5, 0xbd, 0x27, 0xc5, + 0x2c, 0x07, 0x02, 0x38, 0x27, 0xd7, 0x37, 0xe3, 0x32, 0x81, 0xff, 0xf2, 0xd8, + 0x13, 0x52, 0xc4, 0x4e, 0x19, 0xe6, 0x30, 0xc2, 0xe5, 0xc6, 0x02, 0x9c, 0xf7, + 0xd9, 0xee, 0x02, 0x14, 0x98, 0xe2, 0x18, 0xee, 0x1a, 0xf8, 0x30, 0xdc, 0x0f, + 0x5e, 0x15, 0xe9, 0x09, 0xcf, 0xd2, 0xee, 0xe7, 0xdc, 0x2b, 0x1f, 0x62, 0x3b, + 0x00, 0x32, 0xd7, 0x1f, 0xcb, 0xe2, 0x13, 0x9b, 0x18, 0xd4, 0xde, 0x1a, 0xd7, + 0x69, 0x22, 0xeb, 0xc9, 0xaf, 0x1e, 0x1a, 0xff, 0xdb, 0xcd, 0xc7, 0xfe, 0xe7, + 0xce, 0xea, 0xb7, 0xf1, 0x16, 0xe1, 0xd8, 0xf0, 0xdf, 0x38, 0xe4, 0x4c, 0xdf, + 0x18, 0xd9, 0x3e, 0xc3, 0xca, 0x30, 0x27, 0x03, 0xf6, 0xec, 0x04, 0xc3, 0x16, + 0xb9, 0x2f, 0x16, 0x0d, 0x11, 0x31, 0xec, 0xc9, 0xf0, 0x1d, 0x02, 0xdf, 0xb5, + 0x4b, 0x3a, 0xaf, 0x22, 0xa0, 0xe2, 0x10, 0xf2, 0x52, 0x54, 0xe8, 0xb7, 0xe7, + 0x28, 0x3f, 0xcb, 0x06, 0xaa, 0x1e, 0xda, 0xd0, 0xcd, 0x1d, 0xf0, 0xc8, 0x05, + 0x03, 0x26, 0x0a, 0x11, 0xf5, 0xed, 0xf8, 0x5b, 0xed, 0x9e, 0xdd, 0xbd, 0xf7, + 0x7e, 0xba, 0xa1, 0x1b, 0x81, 0xd0, 0xe7, 0xa1, 0xfb, 0xed, 0xf6, 0xf3, 0x3c, + 0xc6, 0xc1, 0xfd, 0x2b, 0x28, 0x0d, 0xd9, 0xce, 0xf9, 0xf4, 0x44, 0xf0, 0x05, + 0x28, 0x06, 0x99, 0xba, 0x9c, 0xf4, 0x99, 0x06, 0xf0, 0x1f, 0xea, 0xe0, 0xd7, + 0xd4, 0xe6, 0x05, 0x3f, 0xab, 0x1d, 0x0c, 0xaa, 0xa2, 0xce, 0x48, 0xd1, 0xbb, + 0xc6, 0x1b, 0xe0, 0xfe, 0xd2, 0xcf, 0xc8, 0xff, 0xd5, 0xf2, 0xdd, 0x3a, 0xac, + 0x59, 0x11, 0x06, 0xb1, 0x3f, 0xfb, 0xe5, 0xbc, 0x50, 0x35, 0x20, 0x18, 0xea, + 0x6a, 0x26, 0xdd, 0x38, 0xdb, 0x36, 0xf3, 0x1c, 0xe3, 0x48, 0xf8, 0x60, 0x67, + 0x1e, 0xd9, 0xeb, 0xe0, 0xf2, 0xdd, 0xce, 0x1c, 0x3e, 0x18, 0x0e, 0xa6, 0xfe, + 0xdf, 0x0c, 0xd1, 0xcc, 0x2c, 0xdb, 0x0e, 0xec, 0xc0, 0x17, 0x2b, 0xe5, 0xfa, + 0x41, 0x21, 0xb0, 0xfb, 0xc2, 0x42, 0x24, 0x2b, 0x2f, 0xdb, 0xe4, 0xc8, 0x40, + 0x3f, 0x17, 0xb5, 0xd2, 0xf7, 0x15, 0x2e, 0x18, 0xc0, 0xa2, 0x3f, 0x6d, 0xe3, + 0xe1, 0xb8, 0xc3, 0xba, 0xfb, 0x2c, 0x0d, 0xea, 0x15, 0xc7, 0x06, 0xdf, 0xe0, + 0x55, 0xc5, 0xbf, 0x0a, 0xf1, 0xe3, 0xe3, 0xef, 0x1d, 0x7f, 0xef, 0xef, 0x4a, + 0xfd, 0x1a, 0x25, 0x04, 0xfe, 0x03, 0xd9, 0xf2, 0xef, 0x12, 0x28, 0xef, 0x36, + 0xcf, 0x21, 0x14, 0x0d, 0x21, 0xf6, 0xfa, 0xfc, 0xf3, 0xe7, 0xed, 0xd6, 0xdd, + 0xe2, 0xed, 0xb8, 0xf0, 0xe6, 0x1d, 0x17, 0xf3, 0x13, 0xf0, 0xd6, 0x00, 0xcc, + 0xe6, 0x00, 0x09, 0xff, 0xe5, 0xb7, 0xd8, 0xf8, 0x04, 0x07, 0xe2, 0xf6, 0xe3, + 0xf5, 0x06, 0xfd, 0xde, 0xfb, 0xb8, 0x18, 0xff, 0x02, 0xf1, 0x6d, 0xfe, 0x0d, + 0xfc, 0x21, 0xbb, 0x0b, 0xdf, 0xe1, 0xf8, 0xde, 0x27, 0xe6, 0xfa, 0x3c, 0xbb, + 0xfe, 0x17, 0x00, 0xdb, 0x1d, 0xf0, 0xd9, 0xbe, 0x12, 0x7f, 0xe9, 0xd1, 0xf7, + 0xe4, 0x08, 0xcc, 0xe6, 0xfb, 0xda, 0xe6, 0xf9, 0xf3, 0xeb, 0xf1, 0xec, 0xef, + 0x17, 0x11, 0xf0, 0xfc, 0x2d, 0xf7, 0xf9, 0xc6, 0xec, 0x43, 0xf6, 0x01, 0xfb, + 0xcc, 0xe4, 0xdb, 0x3c, 0x3e, 0xff, 0x0f, 0x15, 0xe4, 0xfb, 0xdd, 0xfe, 0x02, + 0xfa, 0xe3, 0x11, 0x24, 0x0f, 0x0a, 0x0f, 0xe4, 0x05, 0xcd, 0xa7, 0x0d, 0x8a, + 0x33, 0xe8, 0x2d, 0xfc, 0x49, 0x06, 0xb4, 0xe7, 0xe1, 0x1f, 0x0c, 0xf3, 0x3c, + 0xfc, 0xc4, 0xf7, 0xf8, 0x27, 0x2c, 0xe8, 0xcc, 0xe7, 0xa3, 0xb8, 0x44, 0xdc, + 0xf8, 0x2a, 0x54, 0x92, 0xd7, 0x04, 0xca, 0x81, 0xc5, 0xdd, 0xf7, 0xc9, 0x63, + 0x07, 0xfc, 0x00, 0x0a, 0x34, 0x2b, 0x43, 0xd8, 0xca, 0xe0, 0xc3, 0xb0, 0x12, + 0xfa, 0xf9, 0xa5, 0xd6, 0xc4, 0xe3, 0xff, 0xe7, 0xf9, 0x23, 0xbf, 0x4c, 0xbb, + 0xc5, 0xfe, 0x2b, 0x43, 0xf6, 0xbb, 0xfe, 0x39, 0xdc, 0x09, 0xc1, 0x99, 0x4f, + 0xf8, 0xe1, 0xe6, 0x38, 0xd8, 0x16, 0x11, 0xf7, 0x41, 0xd5, 0x1c, 0x02, 0x00, + 0xa9, 0x13, 0x02, 0xf1, 0x3f, 0x3a, 0x52, 0xba, 0xa1, 0x85, 0x8d, 0x25, 0xc9, + 0xdf, 0xdf, 0x01, 0x1f, 0x38, 0xea, 0x16, 0x26, 0x2c, 0x12, 0x26, 0xfd, 0x2c, + 0x13, 0xf6, 0x1e, 0x1f, 0x1c, 0xdd, 0xc9, 0x7f, 0x03, 0xcd, 0x04, 0x0a, 0xf3, + 0x15, 0xe2, 0x48, 0x0e, 0x38, 0xd6, 0x24, 0x11, 0x36, 0x05, 0x32, 0x17, 0x00, + 0x24, 0xf9, 0xd1, 0x24, 0x2b, 0xc2, 0xc0, 0xf9, 0xff, 0xcc, 0x0b, 0x34, 0xf0, + 0x27, 0xfb, 0xe4, 0x2c, 0x0a, 0xf7, 0xf3, 0xe1, 0xac, 0xfd, 0xe2, 0xf5, 0xdc, + 0xd8, 0x05, 0xa0, 0x0d, 0x5d, 0x04, 0xe5, 0xca, 0xfd, 0x35, 0xef, 0xd4, 0x1f, + 0x04, 0xb9, 0x0b, 0xd7, 0xed, 0xd8, 0x09, 0x05, 0xf4, 0x0e, 0xdd, 0xf2, 0xd5, + 0xf9, 0x37, 0xdf, 0x25, 0x20, 0xdb, 0xf5, 0x14, 0xf1, 0x12, 0xec, 0xcd, 0xd9, + 0xca, 0x2c, 0x2c, 0xe1, 0xfa, 0x5f, 0xb8, 0xf5, 0x01, 0x09, 0x26, 0x0f, 0xd5, + 0xf1, 0x14, 0x3c, 0xec, 0xd3, 0xdf, 0x41, 0x11, 0x3a, 0xf6, 0xce, 0x11, 0xd7, + 0x2a, 0x4d, 0x01, 0x0b, 0xec, 0xfb, 0x0a, 0x55, 0xd7, 0x01, 0xbc, 0x38, 0xe4, + 0xd3, 0xf6, 0xef, 0x34, 0xb8, 0xf2, 0x92, 0x2d, 0x91, 0xb8, 0x22, 0xf5, 0x2b, + 0xce, 0x1a, 0xbf, 0x70, 0x07, 0x36, 0xe9, 0x99, 0x1d, 0x0a, 0x08, 0x29, 0xce, + 0xee, 0xfc, 0x5d, 0xb7, 0xf2, 0xa2, 0xd3, 0x38, 0x2f, 0x6a, 0x31, 0x34, 0x41, + 0xc4, 0x0e, 0x1d, 0x20, 0x5d, 0x94, 0x1a, 0xbd, 0xb5, 0xc6, 0xd0, 0x43, 0xdb, + 0x3d, 0x44, 0xf8, 0xba, 0x0a, 0xe5, 0x2d, 0xf2, 0xd8, 0x03, 0xf7, 0x33, 0xbe, + 0x1d, 0x4b, 0x09, 0xd6, 0x09, 0x1c, 0xe9, 0x46, 0x0c, 0x17, 0xf5, 0xf0, 0xc9, + 0x34, 0x56, 0xb1, 0xba, 0x31, 0xcf, 0x0e, 0x22, 0x0b, 0x47, 0x4e, 0x1d, 0x05, + 0x38, 0x81, 0x73, 0x2a, 0xce, 0x01, 0x4f, 0xe4, 0xb0, 0x4e, 0x94, 0xf5, 0xac, + 0xd1, 0xe8, 0x16, 0x10, 0x0c, 0xf8, 0x3b, 0xb8, 0x12, 0xe3, 0xf5, 0x59, 0x64, + 0x1c, 0x38, 0xe6, 0x10, 0xd0, 0xcc, 0xc9, 0x23, 0xd6, 0xf8, 0xf9, 0xf8, 0xf1, + 0x19, 0x0b, 0x0f, 0x0f, 0x05, 0xc7, 0xe7, 0x0c, 0xdd, 0x0c, 0x0f, 0x17, 0xf8, + 0xf8, 0xf6, 0x09, 0xf9, 0xd6, 0x1b, 0x53, 0x5b, 0xf0, 0xde, 0xe9, 0x1b, 0x33, + 0x05, 0x37, 0xbd, 0x2d, 0x24, 0xde, 0x19, 0xac, 0x21, 0x4c, 0x0b, 0x1b, 0x14, + 0xd5, 0x36, 0x23, 0xe6, 0x20, 0x26, 0x22, 0xf7, 0xad, 0xe6, 0xd1, 0xdc, 0x97, + 0xca, 0x20, 0x3e, 0x12, 0xb4, 0x2d, 0x34, 0xe7, 0x35, 0x1c, 0x39, 0xc1, 0xb5, + 0x08, 0xc0, 0x21, 0x1d, 0xec, 0x31, 0x0a, 0x1d, 0x17, 0xd4, 0xe2, 0xff, 0xf4, + 0xdf, 0x3d, 0xf5, 0xdf, 0x02, 0x48, 0xe8, 0x06, 0xd7, 0x15, 0x17, 0xf7, 0xee, + 0x7f, 0x24, 0x07, 0xe2, 0x01, 0xc9, 0x18, 0x2e, 0xfc, 0xfe, 0x12, 0xda, 0xd8, + 0x07, 0x08, 0xfb, 0xea, 0xfa, 0x01, 0x07, 0xe5, 0x1b, 0x00, 0xd9, 0xcf, 0x32, + 0xf2, 0xef, 0xb4, 0xeb, 0xfd, 0xf9, 0x33, 0xd7, 0x07, 0xbb, 0xf4, 0x0f, 0xe9, + 0xf9, 0x66, 0xf7, 0x2c, 0x24, 0xa3, 0xef, 0xf8, 0x2a, 0x1c, 0x3e, 0x8e, 0xf0, + 0xaa, 0xd1, 0x05, 0x12, 0x9e, 0x14, 0xec, 0x47, 0x20, 0x27, 0x56, 0xe8, 0x36, + 0xa0, 0x81, 0xa5, 0xa2, 0xf7, 0x0b, 0x1b, 0xdc, 0xb0, 0xb6, 0xf6, 0xff, 0xf4, + 0x26, 0xe7, 0xce, 0xc3, 0x02, 0x95, 0x5e, 0x8f, 0xd4, 0xb3, 0xb9, 0xe2, 0x28, + 0xfa, 0x00, 0x0f, 0x1a, 0xee, 0x2a, 0x02, 0xcf, 0xb9, 0xea, 0xa8, 0x03, 0x3a, + 0xff, 0xcf, 0x07, 0xe5, 0x2d, 0x3f, 0x32, 0xc0, 0x0f, 0xdf, 0xd3, 0xd5, 0x0d, + 0xe6, 0x10, 0xe4, 0x11, 0xbd, 0xb0, 0x09, 0x12, 0x00, 0xd6, 0x37, 0x22, 0x36, + 0xd3, 0xf6, 0x8a, 0xeb, 0xd9, 0x20, 0xe2, 0xfb, 0xde, 0x14, 0x8c, 0xc0, 0xd0, + 0xe8, 0x21, 0xe9, 0xab, 0xd6, 0x0c, 0x1c, 0x03, 0x4e, 0xf7, 0x14, 0xbf, 0x0e, + 0xab, 0x03, 0x3f, 0x22, 0xcf, 0x52, 0xc6, 0x33, 0x7f, 0xc7, 0xd2, 0x14, 0x10, + 0x1d, 0x0d, 0x02, 0xae, 0xcd, 0xc8, 0xd8, 0xff, 0xfc, 0xd7, 0x1e, 0x13, 0xe0, + 0x2d, 0xff, 0x28, 0x1f, 0x00, 0x22, 0x21, 0x10, 0x0e, 0xf9, 0xc0, 0x1c, 0x28, + 0x26, 0x9d, 0x20, 0x1a, 0xd6, 0x21, 0x2a, 0x2d, 0x1a, 0xe4, 0xf3, 0xea, 0x14, + 0x0d, 0x0c, 0x19, 0x09, 0xcb, 0x4f, 0x51, 0xd0, 0x09, 0x2f, 0xdc, 0x8c, 0x23, + 0x12, 0xae, 0x29, 0xe2, 0xf6, 0x21, 0x29, 0x32, 0x22, 0x18, 0x23, 0xf9, 0x47, + 0xd0, 0x44, 0x23, 0x05, 0xe6, 0x17, 0x04, 0x07, 0x05, 0xf8, 0xff, 0x49, 0x0a, + 0x1f, 0x0b, 0xf0, 0x54, 0x23, 0x0a, 0x0a, 0x05, 0x0c, 0x01, 0x1b, 0xde, 0xf7, + 0xde, 0xe1, 0xd5, 0x08, 0x4f, 0x1b, 0xf1, 0x22, 0x27, 0xb5, 0x1e, 0x14, 0xdb, + 0x23, 0xc8, 0xfa, 0xd9, 0xf2, 0xf0, 0xd6, 0x17, 0xee, 0x38, 0xec, 0x29, 0xe2, + 0x26, 0xcf, 0xbc, 0xe3, 0xf9, 0x1b, 0xdd, 0xcf, 0x0b, 0xe8, 0xea, 0xea, 0x3d, + 0xea, 0x2c, 0xfa, 0xc5, 0x1c, 0xfa, 0xe4, 0xea, 0xfb, 0xd4, 0x31, 0xef, 0xe6, + 0xf9, 0xcd, 0xd3, 0xe4, 0xf0, 0xc2, 0xec, 0xe9, 0x08, 0xbb, 0x01, 0x4a, 0x19, + 0x1a, 0xfc, 0x22, 0x81, 0xee, 0x44, 0xf6, 0x2e, 0x2a, 0xf3, 0x04, 0x1a, 0xde, + 0xef, 0xf5, 0x22, 0x03, 0xe2, 0xf9, 0xf9, 0x0b, 0x0d, 0x4f, 0xf6, 0xd1, 0xe2, + 0xb6, 0x2e, 0x17, 0xf3, 0x0b, 0xd7, 0x47, 0xed, 0xb8, 0xf2, 0xfa, 0x29, 0xee, + 0x00, 0xf9, 0x19, 0xe2, 0xf0, 0xf6, 0xde, 0xe7, 0x2d, 0x29, 0x14, 0x0b, 0x18, + 0x37, 0xf8, 0x05, 0x1e, 0xeb, 0xe6, 0x22, 0xf7, 0x08, 0xfb, 0x05, 0x0a, 0x02, + 0x2f, 0xef, 0x0e, 0x00, 0xea, 0xfa, 0xe2, 0x07, 0x07, 0xee, 0xd1, 0xfc, 0xc9, + 0xf3, 0x19, 0x21, 0x28, 0xe5, 0x0c, 0xf0, 0xe1, 0x11, 0x3e, 0xe6, 0x4b, 0xd4, + 0x24, 0x1d, 0x1a, 0xc3, 0x94, 0x34, 0x3c, 0x1e, 0xfe, 0x3e, 0xb6, 0x43, 0x5b, + 0x33, 0xe1, 0xdc, 0x01, 0x2d, 0x25, 0x30, 0x38, 0xc6, 0xd3, 0xa1, 0x50, 0xcb, + 0x11, 0x0c, 0xc3, 0xe7, 0x2b, 0x44, 0x07, 0x11, 0x18, 0x14, 0x00, 0xf2, 0xc0, + 0x57, 0xb4, 0xae, 0xea, 0x06, 0xed, 0xb9, 0xf4, 0xe5, 0xe4, 0x36, 0x39, 0x0c, + 0xfa, 0xba, 0x05, 0x31, 0x2a, 0xc8, 0x50, 0x38, 0xde, 0xee, 0x2d, 0x3c, 0xfd, + 0x31, 0xd1, 0xff, 0x33, 0xa9, 0x2c, 0x21, 0x6d, 0x31, 0xdb, 0xd3, 0x04, 0x55, + 0x1f, 0xbe, 0x09, 0x28, 0x90, 0x0e, 0x79, 0xf5, 0xdb, 0x3a, 0xc0, 0xd9, 0x33, + 0xb5, 0xda, 0xd2, 0xb2, 0x17, 0x0a, 0xe8, 0xf9, 0x20, 0x24, 0x04, 0xf8, 0x11, + 0x1f, 0x12, 0xf5, 0x32, 0xa9, 0xfb, 0xe6, 0x08, 0xf2, 0xe7, 0x10, 0x12, 0x42, + 0x2a, 0xd3, 0xdb, 0x21, 0xd0, 0x7f, 0xab, 0x1b, 0x1f, 0x27, 0xd5, 0xad, 0x27, + 0x1c, 0xed, 0x0c, 0x31, 0xcd, 0x10, 0x17, 0xa7, 0x26, 0x56, 0x16, 0xee, 0x0f, + 0x68, 0x41, 0x1c, 0xdd, 0x0d, 0xdc, 0x19, 0x3c, 0xeb, 0x04, 0xae, 0x35, 0xe6, + 0x2f, 0xf8, 0x12, 0x08, 0xff, 0xc5, 0xd6, 0xac, 0xf1, 0x2f, 0xdd, 0xb5, 0xd5, + 0xfa, 0x37, 0x71, 0xeb, 0xf6, 0xa5, 0xe8, 0xfa, 0xda, 0x00, 0xd9, 0xf5, 0xc2, + 0xd0, 0x37, 0xee, 0x1c, 0xdd, 0x1a, 0xdb, 0xd9, 0x2a, 0x0b, 0xe3, 0xbe, 0x10, + 0xe6, 0xdf, 0xd2, 0x14, 0xcf, 0x7f, 0x4a, 0xde, 0xc8, 0xf9, 0xe1, 0x32, 0xf0, + 0x9f, 0xe2, 0xd8, 0xf8, 0x12, 0xc9, 0xf4, 0x04, 0x1b, 0x05, 0x27, 0x2f, 0x0d, + 0x21, 0x03, 0x20, 0x2f, 0xf9, 0xf5, 0xec, 0x29, 0x07, 0xd4, 0x2f, 0xea, 0xc7, + 0x02, 0x04, 0xa6, 0x16, 0xcc, 0xc5, 0xc5, 0xf9, 0xe5, 0xf8, 0xba, 0xfd, 0x1c, + 0x2e, 0xf6, 0x19, 0x10, 0xf1, 0x4c, 0x26, 0x09, 0xf1, 0xed, 0xc4, 0xc4, 0x75, + 0xde, 0xfe, 0xd7, 0x20, 0x50, 0xf3, 0xb1, 0xe1, 0xea, 0x28, 0x12, 0x05, 0xe7, + 0xe6, 0x1c, 0xe5, 0xd3, 0xea, 0xf0, 0xd8, 0x3f, 0xef, 0x09, 0xd5, 0xe4, 0x1a, + 0x40, 0xf2, 0x5f, 0xfc, 0x30, 0xd9, 0x82, 0xea, 0x29, 0xc5, 0x1b, 0xfa, 0xaf, + 0xd2, 0xf4, 0xd8, 0xec, 0x53, 0xdd, 0x2e, 0x37, 0xef, 0xf9, 0xe7, 0x1d, 0xff, + 0x16, 0x38, 0x18, 0x7f, 0xd8, 0xe0, 0xbc, 0xf8, 0x9a, 0xe0, 0xf5, 0x2a, 0x05, + 0x22, 0x15, 0x51, 0xef, 0xd0, 0x70, 0x22, 0x6b, 0x1a, 0xcd, 0xbb, 0x60, 0xc2, + 0xf3, 0xd8, 0x5f, 0x5f, 0xdd, 0x0c, 0xc1, 0xe0, 0xb9, 0x12, 0x0b, 0xed, 0x03, + 0x2b, 0x39, 0x1e, 0x4e, 0x2e, 0xfa, 0x3e, 0x18, 0xad, 0xca, 0x74, 0xcc, 0xe9, + 0x1b, 0x1e, 0xf6, 0x13, 0xe1, 0x14, 0x9f, 0x46, 0xcd, 0x05, 0x35, 0x47, 0x57, + 0xdf, 0xf0, 0x2c, 0x25, 0xde, 0x28, 0xc7, 0x11, 0xfe, 0x19, 0xe2, 0xfd, 0xfe, + 0xd8, 0x5d, 0xd5, 0xca, 0x97, 0x59, 0x21, 0x1e, 0x04, 0xff, 0x09, 0x4b, 0x17, + 0xc4, 0x1d, 0xc9, 0xda, 0x0a, 0xf5, 0xd0, 0x01, 0x30, 0xff, 0xb8, 0x3d, 0x20, + 0x38, 0xb9, 0x40, 0xf9, 0x2d, 0xf0, 0xe2, 0xbd, 0xcc, 0xc4, 0x07, 0xde, 0xf7, + 0xea, 0xfc, 0x46, 0xd4, 0xfb, 0x09, 0xc6, 0xf9, 0x43, 0x6b, 0xdd, 0xe2, 0xd3, + 0x18, 0xdc, 0x0b, 0x39, 0x93, 0x32, 0xfd, 0x22, 0x4c, 0x06, 0x72, 0xfd, 0xd0, + 0x18, 0x14, 0xeb, 0x43, 0x22, 0x08, 0xb6, 0x29, 0x00, 0x32, 0x7f, 0x13, 0x42, + 0xdc, 0xd5, 0x0d, 0x53, 0x10, 0x09, 0xfa, 0x5a, 0x0e, 0x13, 0xff, 0xc0, 0x18, + 0x34, 0x1f, 0x38, 0x38, 0x27, 0xc4, 0xf6, 0x19, 0x40, 0xdc, 0x30, 0xc5, 0xd7, + 0xad, 0xf2, 0xf5, 0x06, 0x07, 0xdc, 0x30, 0x01, 0x1c, 0xe8, 0x34, 0xb8, 0x3c, + 0xd1, 0xdd, 0x0c, 0xf9, 0x04, 0xc0, 0xb1, 0xf5, 0x35, 0xbb, 0x18, 0x26, 0xd4, + 0x00, 0x30, 0xf4, 0xde, 0xb9, 0xba, 0x0a, 0x13, 0xaa, 0x0c, 0xd6, 0xe7, 0x42, + 0x17, 0xe3, 0x19, 0xc8, 0x74, 0xe8, 0x13, 0xf8, 0x34, 0xd2, 0x1f, 0xee, 0xe9, + 0xef, 0xdd, 0x03, 0xc8, 0x4a, 0x48, 0x0a, 0xaf, 0xda, 0xe1, 0xee, 0xca, 0x75, + 0xaf, 0x31, 0xf6, 0x0a, 0x2a, 0x2a, 0xfc, 0xf1, 0x07, 0xc4, 0x9f, 0xf9, 0xba, + 0x1e, 0x2d, 0x15, 0x12, 0x5a, 0xfe, 0x16, 0xec, 0x0a, 0x36, 0xe7, 0xbf, 0xd0, + 0xe4, 0xc5, 0x0e, 0x18, 0xf7, 0x0e, 0xfe, 0x4b, 0x10, 0xb3, 0x35, 0xd7, 0x0d, + 0xe4, 0x01, 0xba, 0xe6, 0x22, 0xd4, 0x81, 0x05, 0x47, 0x3f, 0x05, 0xd7, 0xd7, + 0x12, 0xfe, 0x09, 0x0d, 0x1f, 0xd8, 0xff, 0xc2, 0xf5, 0x1a, 0x0f, 0xe9, 0xec, + 0x65, 0xb3, 0xc9, 0x06, 0xea, 0x3b, 0xe5, 0xf1, 0xf4, 0xe5, 0xd1, 0x57, 0xc0, + 0xc4, 0x34, 0x07, 0xb5, 0x05, 0x07, 0x12, 0x3a, 0xdf, 0xe6, 0xce, 0xc7, 0x1c, + 0x33, 0xe4, 0x95, 0xf7, 0x09, 0x20, 0x40, 0x54, 0xc0, 0xde, 0x17, 0x4c, 0xfa, + 0xff, 0xc0, 0x02, 0x24, 0x3a, 0xf5, 0xee, 0x0d, 0x91, 0x2c, 0x25, 0x53, 0xcf, + 0xdb, 0x4f, 0x4e, 0xfa, 0xd3, 0xff, 0xd2, 0x2c, 0xf0, 0x12, 0x18, 0xf1, 0x1e, + 0xcd, 0xee, 0xe6, 0x03, 0xe9, 0x01, 0xca, 0xed, 0xdb, 0x1d, 0x04, 0xb1, 0x7e, + 0xe6, 0xf9, 0xce, 0xcd, 0xf0, 0x01, 0xf0, 0x3e, 0x19, 0x05, 0x0e, 0x3d, 0x0a, + 0xe6, 0x2a, 0x20, 0xd4, 0xe0, 0x1e, 0x26, 0x1e, 0xbe, 0x42, 0x24, 0xc8, 0x31, + 0x22, 0x39, 0x23, 0xc2, 0x6a, 0xe7, 0x22, 0x11, 0x37, 0x26, 0x1e, 0x08, 0xb9, + 0x1f, 0x01, 0xef, 0x02, 0xef, 0xfa, 0x1d, 0x1b, 0x0e, 0x1c, 0x09, 0x22, 0xfc, + 0xdd, 0xba, 0x7f, 0xdb, 0x0f, 0xe3, 0x4f, 0x0b, 0xd9, 0x0d, 0xc6, 0xee, 0x29, + 0xfe, 0x9d, 0x10, 0xbc, 0x02, 0xe6, 0x17, 0x26, 0x20, 0x39, 0xe1, 0x1f, 0x07, + 0xdf, 0xe8, 0x16, 0x18, 0xdd, 0x26, 0xe1, 0xb2, 0x46, 0x1d, 0x04, 0xe3, 0xf8, + 0x0e, 0x38, 0x1e, 0xea, 0x0a, 0x30, 0x2a, 0x36, 0x31, 0x2d, 0x16, 0xd1, 0xd0, + 0xda, 0x03, 0x11, 0xb7, 0xc0, 0xf7, 0xd9, 0xd3, 0x2e, 0x02, 0xd7, 0x2b, 0xf9, + 0x94, 0xf6, 0xee, 0xfe, 0xdd, 0x3f, 0x61, 0xf5, 0x98, 0xf7, 0x02, 0xe9, 0x16, + 0xdb, 0x44, 0x2d, 0x4c, 0xf9, 0x0c, 0x09, 0x6b, 0x2e, 0x27, 0xba, 0x04, 0xf0, + 0xcb, 0x01, 0xd3, 0xe4, 0xbe, 0xe6, 0x22, 0xcc, 0x05, 0xe0, 0xec, 0x13, 0x0c, + 0xcd, 0xba, 0xe8, 0x16, 0xfd, 0x66, 0x7f, 0xfe, 0x49, 0xc3, 0x39, 0xd8, 0xce, + 0xe2, 0xfc, 0x0a, 0x12, 0xfd, 0xd2, 0x01, 0xb2, 0x11, 0xfa, 0xf0, 0xff, 0x06, + 0x3d, 0xde, 0xed, 0x9b, 0x08, 0xf8, 0xca, 0xd1, 0xca, 0xbe, 0xe8, 0x08, 0x63, + 0xc2, 0xa8, 0x1f, 0x5b, 0x4c, 0x11, 0xd0, 0x31, 0x19, 0x2d, 0xf5, 0xab, 0xe1, + 0xef, 0xe2, 0xfd, 0xf5, 0x1d, 0xe6, 0x38, 0x07, 0x2d, 0xf4, 0xcb, 0x0d, 0xc5, + 0x17, 0x02, 0x34, 0xb0, 0x55, 0xec, 0xca, 0xef, 0x1e, 0xd8, 0x17, 0x03, 0xd6, + 0xf1, 0x49, 0x06, 0xdc, 0xf8, 0x2f, 0xf6, 0x00, 0xeb, 0x81, 0x1e, 0xb7, 0xe4, + 0xe4, 0xc3, 0x22, 0x28, 0x03, 0x08, 0xbb, 0x56, 0x2e, 0xf4, 0xda, 0x00, 0xff, + 0xfc, 0x69, 0x14, 0x09, 0x06, 0xc9, 0x0f, 0x3f, 0x0f, 0xef, 0xbd, 0xe4, 0x58, + 0xe8, 0x1f, 0x5f, 0x14, 0xf5, 0xec, 0xe7, 0xfb, 0x1e, 0xa7, 0xd7, 0xfa, 0xf2, + 0x11, 0x27, 0x00, 0xe4, 0xed, 0x14, 0xf2, 0x04, 0x1d, 0xaf, 0x53, 0x04, 0x43, + 0x2c, 0xe5, 0xd9, 0x1f, 0xbe, 0x1c, 0xc8, 0xcf, 0xe4, 0x04, 0xa2, 0x1a, 0xdf, + 0xff, 0x20, 0xfe, 0xd9, 0xf9, 0x11, 0xf4, 0xeb, 0xe4, 0xc5, 0x95, 0x19, 0x2f, + 0x09, 0xcc, 0xc7, 0xda, 0x11, 0xd9, 0x36, 0x01, 0x67, 0xf3, 0xde, 0xfc, 0x2c, + 0xbe, 0x6e, 0xfa, 0xfa, 0x34, 0xb5, 0xf8, 0xb1, 0xac, 0x15, 0xdb, 0x12, 0xec, + 0x1a, 0xed, 0x2d, 0x31, 0xd2, 0xff, 0x70, 0x12, 0x0d, 0x0c, 0x08, 0xa9, 0x4d, + 0xf3, 0xf1, 0x1f, 0x45, 0x6c, 0xff, 0x5b, 0xc2, 0x8c, 0x0b, 0xff, 0x14, 0xce, + 0x45, 0x55, 0x0d, 0x66, 0x66, 0x13, 0x3d, 0x02, 0xf1, 0x0b, 0xe8, 0xe5, 0x54, + 0xf2, 0xc7, 0xd9, 0xda, 0x01, 0xda, 0xcc, 0xce, 0x29, 0xd0, 0x17, 0xdf, 0xbd, + 0xa6, 0x0c, 0x23, 0x19, 0x22, 0xf6, 0xf4, 0x1a, 0xec, 0xcb, 0x18, 0x57, 0xec, + 0x71, 0x18, 0x34, 0x1c, 0x0e, 0xf8, 0x19, 0xe2, 0x51, 0xa2, 0x3e, 0x90, 0xda, + 0x0d, 0xc8, 0x10, 0x0a, 0x28, 0xa7, 0x72, 0x81, 0xbd, 0x1f, 0x40, 0x1f, 0x9d, + 0x26, 0x0a, 0xdf, 0x0e, 0x1b, 0xde, 0xcf, 0xe1, 0xfe, 0xdb, 0xea, 0x09, 0xf9, + 0x30, 0x45, 0x1c, 0x0d, 0x05, 0xf1, 0xc5, 0xd5, 0x46, 0x04, 0x02, 0x3b, 0xe0, + 0xd5, 0x08, 0x1c, 0x3b, 0x07, 0x54, 0xec, 0x3c, 0xf1, 0xed, 0x7f, 0x15, 0x1d, + 0xf6, 0x2f, 0xd8, 0xc2, 0xfa, 0xd0, 0xd2, 0x34, 0x20, 0x3d, 0x04, 0xe6, 0xde, + 0xf4, 0xef, 0xe2, 0xee, 0x0b, 0xe7, 0xbb, 0xcd, 0x33, 0xf7, 0xca, 0xfd, 0xe9, + 0x42, 0x43, 0x25, 0x7e, 0xdb, 0x4e, 0x16, 0xde, 0xfb, 0xf3, 0x75, 0xfd, 0x8f, + 0xff, 0x13, 0x18, 0x2b, 0x17, 0xdc, 0x0d, 0xd6, 0x0f, 0x37, 0x73, 0xbe, 0x14, + 0xe0, 0x26, 0x38, 0x0f, 0x16, 0x11, 0x02, 0xe3, 0xed, 0x01, 0x23, 0x10, 0x26, + 0x0d, 0xe2, 0x20, 0xff, 0xfb, 0xe2, 0x3d, 0x00, 0x13, 0x01, 0xb4, 0xf3, 0xc0, + 0xfb, 0x4f, 0x56, 0xc7, 0x0a, 0xea, 0x22, 0xd7, 0x15, 0x71, 0xfb, 0x2a, 0x4c, + 0xd9, 0xf8, 0xd7, 0x2c, 0x1e, 0x06, 0xc7, 0xe6, 0xe5, 0xe8, 0x24, 0x20, 0xd6, + 0xbf, 0x1f, 0xf3, 0x08, 0x1e, 0xfb, 0xcd, 0xad, 0xf6, 0x16, 0x6a, 0x31, 0x3e, + 0x32, 0xa6, 0x0a, 0xe3, 0x90, 0x4b, 0xf8, 0x31, 0xcf, 0xc3, 0x10, 0xdf, 0xb8, + 0xfe, 0xb5, 0x0d, 0x9f, 0x2a, 0x1d, 0xf0, 0x0e, 0xd0, 0x5c, 0x0c, 0x0e, 0xd6, + 0x1a, 0xd6, 0x2a, 0xbc, 0xf7, 0x44, 0x22, 0xc4, 0xe2, 0xe4, 0x27, 0x9f, 0xda, + 0x13, 0x38, 0x20, 0x17, 0x44, 0x16, 0xb8, 0xcd, 0x0a, 0x0e, 0x09, 0x53, 0xf0, + 0x2e, 0x0b, 0xb6, 0x7f, 0xfc, 0x41, 0xe6, 0xe2, 0x34, 0xd0, 0x0c, 0x47, 0x19, + 0x4c, 0xa5, 0x0a, 0x04, 0xc5, 0x01, 0xb7, 0xed, 0x3d, 0x35, 0x63, 0xe5, 0x43, + 0xce, 0x22, 0xd1, 0x07, 0x20, 0x6e, 0xe7, 0x29, 0x16, 0x0f, 0x07, 0xf6, 0xd7, + 0xfd, 0x24, 0xf7, 0xd6, 0x16, 0x52, 0xe1, 0xe6, 0xa1, 0xe5, 0x13, 0xf2, 0xb7, + 0x0e, 0xe7, 0x05, 0xe4, 0xe0, 0x20, 0x0e, 0xf4, 0xd5, 0x1a, 0x0e, 0xea, 0xea, + 0xfe, 0xdc, 0x29, 0x30, 0xd6, 0xb7, 0xdd, 0x38, 0xea, 0x2e, 0x18, 0x62, 0x30, + 0xe4, 0xe6, 0xe5, 0xef, 0x1e, 0xf4, 0x03, 0x0e, 0x09, 0xdc, 0x4f, 0x4c, 0x17, + 0xe2, 0x33, 0xf4, 0xfd, 0xe6, 0xf2, 0x24, 0xff, 0x22, 0x50, 0x1d, 0xdd, 0xfd, + 0xc5, 0x21, 0x42, 0x11, 0xce, 0xdf, 0x3c, 0xc2, 0xc6, 0xcd, 0xea, 0xd7, 0x14, + 0x53, 0xc5, 0x02, 0xb8, 0x2b, 0x0b, 0xfc, 0x32, 0xe7, 0xe7, 0x28, 0xc8, 0xd3, + 0x8b, 0x13, 0x0a, 0x50, 0x70, 0xf5, 0x7d, 0x92, 0x45, 0x29, 0xea, 0xf8, 0xdb, + 0xdb, 0xee, 0x17, 0x56, 0x6b, 0x25, 0x08, 0xd8, 0xd7, 0xb5, 0xff, 0xb5, 0x05, + 0x0e, 0x25, 0x13, 0x4f, 0x6a, 0x81, 0x48, 0x24, 0x37, 0x72, 0xc2, 0x25, 0xf8, + 0x59, 0x19, 0xf8, 0x3c, 0xe8, 0x02, 0xff, 0x47, 0xef, 0x59, 0xeb, 0xf9, 0xe9, + 0xf9, 0x35, 0xe2, 0xb8, 0x10, 0xed, 0xb9, 0xfa, 0x2b, 0x1b, 0x0a, 0xf6, 0xb7, + 0xf2, 0xb0, 0x40, 0x1c, 0x15, 0x07, 0xd4, 0xe1, 0x2a, 0x08, 0xf0, 0x20, 0x39, + 0xd8, 0x13, 0x2b, 0x22, 0x2d, 0xdf, 0xe5, 0xf6, 0x13, 0x14, 0x99, 0xc4, 0xc5, + 0x17, 0x2e, 0xeb, 0x0e, 0xd1, 0x1e, 0x17, 0x14, 0xad, 0xdf, 0xbd, 0xf4, 0x24, + 0xef, 0xe8, 0xfa, 0xf6, 0x1c, 0xec, 0xe0, 0x15, 0x08, 0xdc, 0xcc, 0xf1, 0x26, + 0x07, 0xf0, 0x34, 0xdd, 0x21, 0x1f, 0x8f, 0x4c, 0xf3, 0xec, 0x4c, 0x2e, 0xc5, + 0x64, 0x27, 0x37, 0x04, 0xd8, 0xec, 0xe2, 0xeb, 0xa3, 0x21, 0xfa, 0x11, 0x07, + 0x0f, 0x1d, 0x57, 0x40, 0x06, 0xc3, 0xd8, 0x38, 0xd1, 0x08, 0x02, 0x22, 0x18, + 0x19, 0xcd, 0xe8, 0xf3, 0x44, 0xe9, 0xb5, 0xe4, 0xfc, 0x41, 0xd1, 0x1a, 0xf4, + 0x48, 0xe8, 0x0e, 0x6e, 0x2a, 0x7f, 0xec, 0xe3, 0x03, 0xe8, 0x17, 0xf1, 0xe6, + 0x12, 0x4f, 0xeb, 0xe6, 0x20, 0x2b, 0xea, 0x97, 0xfa, 0xda, 0xdd, 0x1c, 0x21, + 0x1c, 0x01, 0x11, 0x12, 0x03, 0xaf, 0x13, 0xd9, 0x2f, 0x10, 0xfc, 0xc4, 0x31, + 0x16, 0xbf, 0xfb, 0x30, 0x03, 0xb4, 0xeb, 0xd9, 0xc6, 0x0b, 0x50, 0x2c, 0x54, + 0xe5, 0xbf, 0x70, 0xba, 0x10, 0xe6, 0xe8, 0x23, 0x17, 0x24, 0x46, 0x18, 0xc9, + 0x2a, 0xb5, 0xec, 0xf4, 0x81, 0x85, 0x21, 0x8e, 0x1a, 0x79, 0xe8, 0x22, 0xf4, + 0xf1, 0xd1, 0xa8, 0xf9, 0x98, 0xba, 0xfe, 0xcc, 0xfb, 0xe7, 0x33, 0x1d, 0x3c, + 0x0a, 0xe5, 0x10, 0x05, 0x30, 0x17, 0xbd, 0x59, 0xe6, 0x49, 0xe2, 0xd0, 0xcf, + 0xb4, 0x35, 0x0d, 0x6e, 0x58, 0xe4, 0x58, 0xac, 0xbe, 0x07, 0x13, 0xd3, 0xf5, + 0xf5, 0x13, 0xfb, 0x35, 0xc0, 0x2d, 0xca, 0x36, 0xa2, 0xff, 0x40, 0x38, 0xef, + 0xf2, 0x1c, 0x1c, 0x05, 0x42, 0xaf, 0x45, 0x25, 0xca, 0x00, 0xdf, 0x3f, 0xb0, + 0xec, 0xd0, 0xe4, 0x1e, 0xec, 0x15, 0x15, 0xf0, 0x2b, 0xef, 0xbc, 0xfc, 0x14, + 0xfd, 0xe0, 0x36, 0x05, 0xad, 0xe2, 0xbd, 0xdc, 0x08, 0x0d, 0xfd, 0xdd, 0xdc, + 0x11, 0xf4, 0xcc, 0x1a, 0xef, 0xe2, 0x07, 0x25, 0x20, 0xd1, 0xe8, 0xd0, 0x45, + 0x7b, 0xdc, 0xee, 0x01, 0xfb, 0xfa, 0xf6, 0x11, 0xc9, 0xa5, 0xda, 0xde, 0x13, + 0xfc, 0xfe, 0xc7, 0x49, 0x08, 0xdb, 0x16, 0x2d, 0xd5, 0xe5, 0xdc, 0xc8, 0x0e, + 0xfd, 0xff, 0xe3, 0x31, 0x48, 0x9f, 0xde, 0x46, 0xdb, 0xf6, 0x0d, 0x3a, 0xf7, + 0xb5, 0x7f, 0x02, 0xc7, 0xa6, 0xdf, 0x04, 0xdc, 0x0c, 0xcb, 0x0b, 0xbb, 0xf7, + 0x4f, 0xf7, 0x46, 0x11, 0x2a, 0x64, 0x1e, 0x37, 0xec, 0xd5, 0x8c, 0xef, 0x3a, + 0x1f, 0x1d, 0x46, 0xdd, 0xeb, 0xcc, 0x1d, 0xe7, 0x99, 0x17, 0x10, 0x12, 0xb8, + 0x17, 0x00, 0xcb, 0x0f, 0x02, 0xcb, 0x10, 0x3e, 0x31, 0x04, 0x51, 0x26, 0x2d, + 0xf9, 0xfe, 0xe0, 0xd0, 0x18, 0xc9, 0x71, 0x32, 0x2a, 0x12, 0xd1, 0xed, 0x2b, + 0x43, 0xb1, 0xe2, 0xf8, 0x28, 0xc6, 0xf7, 0xd8, 0x04, 0x2c, 0xc5, 0x09, 0xf9, + 0x0c, 0xe6, 0x0b, 0xdc, 0x45, 0x31, 0x31, 0xe1, 0x15, 0x40, 0xef, 0x0c, 0x03, + 0xf9, 0xf5, 0xc5, 0x15, 0x1b, 0x05, 0x35, 0xe8, 0xc2, 0xf8, 0xe6, 0x24, 0xcf, + 0x40, 0x37, 0xfc, 0x7f, 0xf1, 0xdd, 0x02, 0x0a, 0xbb, 0xe1, 0x1e, 0x12, 0xd3, + 0xe3, 0x12, 0xd5, 0xec, 0x21, 0xf1, 0xd2, 0x2d, 0xc1, 0xe3, 0xec, 0xf5, 0xfa, + 0xf9, 0xd0, 0x96, 0x2e, 0xfb, 0xcd, 0x20, 0xd6, 0xd2, 0xe5, 0x05, 0x23, 0x23, + 0x2d, 0xff, 0x13, 0x53, 0xec, 0xc7, 0xdb, 0x03, 0xff, 0xf4, 0x2c, 0x04, 0xe6, + 0xea, 0xf2, 0xee, 0xed, 0x5f, 0x12, 0xe0, 0xf4, 0x27, 0xbb, 0xf9, 0xff, 0x14, + 0x0e, 0xcd, 0x00, 0x16, 0xc5, 0xc5, 0x4f, 0x0a, 0xb9, 0x15, 0xfc, 0xca, 0x0f, + 0xf8, 0x0f, 0xde, 0xdc, 0xdd, 0x23, 0x01, 0xf8, 0xf2, 0x2e, 0xe0, 0xf9, 0xf0, + 0x40, 0xe5, 0xf5, 0x2b, 0x1f, 0xc1, 0x02, 0x6b, 0xf4, 0xf2, 0xde, 0xcb, 0x41, + 0x1a, 0x01, 0x52, 0xf3, 0xe5, 0x06, 0xc4, 0x26, 0x21, 0xb3, 0x19, 0xd5, 0xed, + 0x0e, 0xe8, 0xe7, 0xf4, 0xef, 0x1e, 0xdc, 0xef, 0xe8, 0x0d, 0xf9, 0x06, 0xe8, + 0xe9, 0xd2, 0xbd, 0xff, 0x19, 0x1c, 0x14, 0x14, 0x00, 0xfd, 0xdc, 0x04, 0xe8, + 0x81, 0x35, 0x0b, 0x05, 0xcb, 0x00, 0xe7, 0x14, 0xea, 0xd6, 0x0f, 0xe2, 0x03, + 0xbb, 0x00, 0xc3, 0xf7, 0x01, 0xf9, 0x17, 0x0c, 0x1a, 0xe0, 0xe0, 0xcc, 0x63, + 0xf1, 0x22, 0x17, 0xfa, 0xea, 0x2e, 0xea, 0x1b, 0xf5, 0xde, 0x0f, 0xc8, 0xe9, + 0xcc, 0xe3, 0xe7, 0xf1, 0x18, 0x1a, 0x01, 0xe9, 0x15, 0xf9, 0xe2, 0xd2, 0x33, + 0x0d, 0xed, 0x1e, 0x25, 0xf8, 0xb0, 0x13, 0x0d, 0xf2, 0xdf, 0xf3, 0xcf, 0x2e, + 0x24, 0xa0, 0xe6, 0xd2, 0xf7, 0xf7, 0x1f, 0x24, 0x02, 0x2e, 0xde, 0x22, 0xa4, + 0x15, 0xcf, 0xec, 0x05, 0xc8, 0xf9, 0x25, 0x1d, 0x2e, 0x0f, 0xee, 0xc4, 0x64, + 0xaf, 0xcc, 0x38, 0x07, 0x26, 0xba, 0x36, 0x95, 0xfb, 0xbc, 0xfb, 0xf5, 0xb7, + 0xf2, 0xc1, 0x33, 0xc8, 0x44, 0xf9, 0x08, 0xc4, 0x0a, 0xd7, 0x05, 0xd7, 0x58, + 0x44, 0xdc, 0xeb, 0xd8, 0xca, 0xd1, 0x18, 0x18, 0xc3, 0x3a, 0x3c, 0x1c, 0x3f, + 0x0b, 0x1c, 0xec, 0x38, 0xf8, 0xa7, 0xec, 0xef, 0xc5, 0xda, 0xf9, 0xe1, 0x09, + 0x3c, 0x1c, 0x43, 0xfe, 0xc8, 0xef, 0xe1, 0xc1, 0x03, 0xaf, 0x60, 0x2a, 0x9f, + 0xf6, 0x0e, 0xeb, 0x1b, 0xaf, 0x04, 0x38, 0xe6, 0x3e, 0xc1, 0xb7, 0x2a, 0x0b, + 0x04, 0xd0, 0xce, 0x43, 0x81, 0xf7, 0xfc, 0x7c, 0x10, 0xe3, 0xf6, 0xdc, 0xfc, + 0x22, 0xf5, 0x0a, 0x15, 0xdc, 0xed, 0x06, 0xe5, 0xf7, 0x1d, 0x0f, 0x20, 0x51, + 0xe5, 0xe1, 0x0e, 0x3b, 0xef, 0xf4, 0xf0, 0x2f, 0xdc, 0xf1, 0xe7, 0xb6, 0xda, + 0x27, 0xf7, 0xfc, 0xe0, 0xfb, 0x38, 0xfe, 0xb5, 0x01, 0x37, 0x32, 0xf3, 0xfe, + 0xc9, 0xf4, 0x18, 0xd6, 0x39, 0xcd, 0x1b, 0xb1, 0x28, 0xd0, 0x07, 0xee, 0x11, + 0x7f, 0x18, 0xd8, 0xe9, 0xec, 0xd3, 0xd7, 0xd4, 0xdd, 0x05, 0x1e, 0xfd, 0xfb, + 0x54, 0x10, 0xf8, 0x49, 0xe4, 0x08, 0xc2, 0x24, 0x27, 0xb3, 0xe1, 0xdf, 0x47, + 0x0f, 0x3a, 0xd4, 0x02, 0x49, 0x17, 0x1b, 0x04, 0xc7, 0x9e, 0x0a, 0x11, 0x01, + 0x2d, 0x2d, 0x01, 0xf6, 0xfb, 0xfb, 0xff, 0xd8, 0xd6, 0x16, 0x06, 0x42, 0xde, + 0xf4, 0xf3, 0xd8, 0xda, 0x2c, 0xf7, 0xf2, 0xf4, 0x08, 0xc6, 0x1e, 0x2d, 0x30, + 0x05, 0x45, 0x13, 0xee, 0x32, 0xe0, 0x38, 0xfe, 0xd6, 0xdf, 0xd3, 0x19, 0x1b, + 0xd6, 0xfe, 0xe9, 0x06, 0x18, 0x3b, 0xf7, 0xa2, 0x1a, 0x19, 0x39, 0x3c, 0x1e, + 0xec, 0xf1, 0xfd, 0x20, 0xec, 0xd4, 0x52, 0xe8, 0xc7, 0xe9, 0x11, 0xfe, 0xd4, + 0xb2, 0x3e, 0xd5, 0xc1, 0xe3, 0xf4, 0xff, 0xfc, 0x5a, 0xd2, 0x30, 0xb9, 0x01, + 0x0b, 0x51, 0x3c, 0xd2, 0x49, 0x50, 0x11, 0xeb, 0x12, 0x2e, 0xed, 0x0d, 0x39, + 0xf9, 0xf1, 0xa4, 0x58, 0x81, 0xbd, 0x36, 0x30, 0x01, 0xe0, 0xf4, 0xdb, 0xdc, + 0x0e, 0xd4, 0x3a, 0xfc, 0x0c, 0x10, 0x1e, 0x79, 0xb4, 0xd2, 0x25, 0x33, 0x07, + 0xfd, 0xfc, 0x26, 0x2b, 0x00, 0xee, 0x12, 0xd8, 0x37, 0x0c, 0x3a, 0xa4, 0xf4, + 0xcc, 0x22, 0xf6, 0x18, 0x06, 0xde, 0xd8, 0xf7, 0x22, 0xc0, 0x24, 0x1b, 0x2d, + 0x52, 0x00, 0xb8, 0x46, 0xc7, 0xdd, 0x37, 0xbb, 0x18, 0xe8, 0x1c, 0x2b, 0xc4, + 0xde, 0xcd, 0x3f, 0xf9, 0x5e, 0xf5, 0x16, 0xcd, 0x0a, 0x0e, 0x12, 0xfe, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x37, 0x1e, 0x00, 0x00, 0x73, + 0x14, 0x00, 0x00, 0xee, 0x10, 0x00, 0x00, 0xab, 0xe6, 0xff, 0xff, 0xb5, 0x24, + 0x00, 0x00, 0xbc, 0x1e, 0x00, 0x00, 0x49, 0xf0, 0xff, 0xff, 0xd7, 0xfd, 0xff, + 0xff, 0x94, 0x13, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0xf8, 0xfe, 0xff, 0xff, + 0xe0, 0x04, 0x00, 0x00, 0x45, 0xfd, 0xff, 0xff, 0x28, 0xf7, 0xff, 0xff, 0x4a, + 0x16, 0x00, 0x00, 0x13, 0xe3, 0xff, 0xff, 0x3d, 0x06, 0x00, 0x00, 0xc9, 0x1a, + 0x00, 0x00, 0x2b, 0xf5, 0xff, 0xff, 0x5c, 0x31, 0x00, 0x00, 0x3d, 0x10, 0x00, + 0x00, 0xe8, 0xef, 0xff, 0xff, 0x88, 0x2e, 0x00, 0x00, 0xe6, 0x01, 0x00, 0x00, + 0x0f, 0xfe, 0xff, 0xff, 0x9c, 0xec, 0xff, 0xff, 0x7c, 0xf9, 0xff, 0xff, 0x49, + 0x03, 0x00, 0x00, 0x96, 0xf4, 0xff, 0xff, 0x87, 0xf7, 0xff, 0xff, 0x37, 0xdb, + 0xff, 0xff, 0x52, 0x10, 0x00, 0x00, 0xd3, 0xfb, 0xff, 0xff, 0x15, 0xf7, 0xff, + 0xff, 0xfa, 0xe9, 0xff, 0xff, 0x54, 0xf6, 0xff, 0xff, 0x16, 0x22, 0x00, 0x00, + 0xb7, 0xf1, 0xff, 0xff, 0x3a, 0xfe, 0xff, 0xff, 0x67, 0xe4, 0xff, 0xff, 0x84, + 0xfd, 0xff, 0xff, 0x5c, 0x09, 0x00, 0x00, 0x5d, 0xfb, 0xff, 0xff, 0x4d, 0x1c, + 0x00, 0x00, 0x40, 0x28, 0x00, 0x00, 0x5a, 0xe0, 0xff, 0xff, 0x6f, 0xf3, 0xff, + 0xff, 0xdd, 0xf8, 0xff, 0xff, 0xc4, 0x03, 0x00, 0x00, 0x71, 0x23, 0x00, 0x00, + 0xe8, 0x21, 0x00, 0x00, 0xce, 0xf2, 0xff, 0xff, 0x42, 0xed, 0xff, 0xff, 0xe7, + 0xf1, 0xff, 0xff, 0xb6, 0xf2, 0xff, 0xff, 0x66, 0xfd, 0xff, 0xff, 0xc8, 0xf0, + 0xff, 0xff, 0xba, 0xfd, 0xff, 0xff, 0xc6, 0xff, 0xff, 0xff, 0x2e, 0xfb, 0xff, + 0xff, 0x1b, 0x1b, 0x00, 0x00, 0x41, 0xe0, 0xff, 0xff, 0xfe, 0xfd, 0xff, 0xff, + 0x61, 0xf0, 0xff, 0xff, 0x50, 0xf0, 0xff, 0xff, 0x8a, 0xea, 0xff, 0xff, 0x04, + 0xe3, 0xff, 0xff, 0x5b, 0xe1, 0xff, 0xff, 0xb5, 0xeb, 0xff, 0xff, 0x90, 0xf8, + 0xff, 0xff, 0x89, 0xe8, 0xff, 0xff, 0x83, 0xfa, 0xff, 0xff, 0x0e, 0xef, 0xff, + 0xff, 0x19, 0x22, 0x00, 0x00, 0xe8, 0xf9, 0xff, 0xff, 0xfc, 0xf4, 0xff, 0xff, + 0x2f, 0xff, 0xff, 0xff, 0x62, 0x05, 0x00, 0x00, 0x93, 0xf9, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xcb, 0x1a, 0x00, 0x00, 0x2c, 0xea, 0xff, 0xff, 0x53, 0x17, + 0x00, 0x00, 0xbb, 0xdc, 0xff, 0xff, 0x77, 0x01, 0x00, 0x00, 0x5f, 0xf2, 0xff, + 0xff, 0x95, 0x03, 0x00, 0x00, 0x29, 0x04, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, + 0x4a, 0x25, 0x00, 0x00, 0xfc, 0xfd, 0xff, 0xff, 0xfd, 0x01, 0x00, 0x00, 0x49, + 0xf4, 0xff, 0xff, 0xba, 0xf9, 0xff, 0xff, 0xc2, 0xf8, 0xff, 0xff, 0xf9, 0x0d, + 0x00, 0x00, 0x88, 0x06, 0x00, 0x00, 0xbd, 0x0d, 0x00, 0x00, 0x79, 0xec, 0xff, + 0xff, 0x71, 0xed, 0xff, 0xff, 0x90, 0x15, 0x00, 0x00, 0x56, 0xeb, 0xff, 0xff, + 0x32, 0x2c, 0x00, 0x00, 0xda, 0xfd, 0xff, 0xff, 0x87, 0xf9, 0xff, 0xff, 0x0d, + 0x07, 0x00, 0x00, 0xe0, 0x12, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x7c, 0xfb, + 0xff, 0xff, 0xbb, 0x04, 0x00, 0x00, 0xdf, 0xdf, 0xff, 0xff, 0x98, 0xeb, 0xff, + 0xff, 0x2d, 0xf4, 0xff, 0xff, 0xfc, 0x09, 0x00, 0x00, 0xa9, 0x17, 0x00, 0x00, + 0x5a, 0x04, 0x00, 0x00, 0x98, 0xef, 0xff, 0xff, 0xb4, 0xec, 0xff, 0xff, 0x80, + 0x02, 0x00, 0x00, 0xc4, 0xfe, 0xff, 0xff, 0x04, 0x05, 0x00, 0x00, 0xb3, 0x09, + 0x00, 0x00, 0xc1, 0x1e, 0x00, 0x00, 0x19, 0x12, 0x00, 0x00, 0x75, 0xf7, 0xff, + 0xff, 0x02, 0x03, 0x00, 0x00, 0x1b, 0x0a, 0x00, 0x00, 0x94, 0x0b, 0x00, 0x00, + 0x1a, 0x14, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x9b, + 0x00, 0x00, 0x00, 0xff, 0xf3, 0xff, 0xff, 0x23, 0x01, 0x00, 0x00, 0x7a, 0xfc, + 0xff, 0xff, 0x2a, 0xd9, 0xff, 0xff, 0x8c, 0x05, 0x00, 0x00, 0xda, 0x38, 0x00, + 0x00, 0xc8, 0xdb, 0xff, 0xff, 0x19, 0xe9, 0xff, 0xff, 0xc0, 0x3e, 0x00, 0x00, + 0x17, 0x20, 0x00, 0x00, 0x22, 0x24, 0x00, 0x00, 0x66, 0x31, 0x00, 0x00, 0x73, + 0x21, 0x00, 0x00, 0x22, 0xe6, 0xff, 0xff, 0xfb, 0x3b, 0x00, 0x00, 0xfa, 0xe4, + 0xff, 0xff, 0x63, 0xf2, 0xff, 0xff, 0xef, 0x27, 0x00, 0x00, 0x55, 0xfe, 0xff, + 0xff, 0x92, 0x09, 0x00, 0x00, 0xa7, 0x24, 0x00, 0x00, 0x6f, 0xc0, 0xff, 0xff, + 0xe4, 0xad, 0xff, 0xff, 0x64, 0x13, 0x00, 0x00, 0xe8, 0xf3, 0xff, 0xff, 0x64, + 0xb3, 0xff, 0xff, 0xee, 0xea, 0xff, 0xff, 0xe8, 0xde, 0xff, 0xff, 0x59, 0x2a, + 0x00, 0x00, 0xaa, 0x3f, 0x00, 0x00, 0xf8, 0x12, 0x00, 0x00, 0x25, 0x0f, 0x00, + 0x00, 0x7b, 0x15, 0x00, 0x00, 0xfe, 0x0a, 0x00, 0x00, 0x1c, 0x24, 0x00, 0x00, + 0xa9, 0x05, 0x00, 0x00, 0xb3, 0xef, 0xff, 0xff, 0x75, 0xfc, 0xff, 0xff, 0x5f, + 0xec, 0xff, 0xff, 0x35, 0x06, 0x00, 0x00, 0xe6, 0x13, 0x00, 0x00, 0x33, 0xf6, + 0xff, 0xff, 0x46, 0xfe, 0xff, 0xff, 0x60, 0xef, 0xff, 0xff, 0x53, 0xee, 0xff, + 0xff, 0x80, 0xf4, 0xff, 0xff, 0xe9, 0xf3, 0xff, 0xff, 0xe5, 0xdf, 0xff, 0xff, + 0x68, 0xf8, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x01, 0x3e, 0x00, 0x00, 0xb2, + 0x28, 0x00, 0x00, 0x56, 0x14, 0x00, 0x00, 0x13, 0x09, 0x00, 0x00, 0x32, 0xd7, + 0xff, 0xff, 0x7c, 0x27, 0x00, 0x00, 0x61, 0x0d, 0x00, 0x00, 0x26, 0xd1, 0xff, + 0xff, 0xa2, 0x39, 0x00, 0x00, 0x69, 0xf4, 0xff, 0xff, 0x60, 0xf9, 0xff, 0xff, + 0x99, 0xe1, 0xff, 0xff, 0xd2, 0x02, 0x00, 0x00, 0x33, 0xe6, 0xff, 0xff, 0x1f, + 0x17, 0x00, 0x00, 0x71, 0x51, 0x00, 0x00, 0xed, 0x41, 0x00, 0x00, 0x9d, 0x26, + 0x00, 0x00, 0xa0, 0xf2, 0xff, 0xff, 0xe1, 0xf2, 0xff, 0xff, 0xee, 0xe8, 0xff, + 0xff, 0x0d, 0xe7, 0xff, 0xff, 0xef, 0x01, 0x00, 0x00, 0x11, 0xd0, 0xff, 0xff, + 0xee, 0x0e, 0x00, 0x00, 0xdc, 0xf4, 0xff, 0xff, 0xa1, 0xff, 0xff, 0xff, 0x67, + 0xdf, 0xff, 0xff, 0x4a, 0xd0, 0xff, 0xff, 0xcd, 0xd2, 0xff, 0xff, 0x10, 0xdd, + 0xff, 0xff, 0xcc, 0xdd, 0xff, 0xff, 0xd7, 0xf8, 0xff, 0xff, 0x61, 0x37, 0x00, + 0x00, 0xcb, 0xed, 0xff, 0xff, 0xb4, 0xe5, 0xff, 0xff, 0xc6, 0xe4, 0xff, 0xff, + 0x32, 0x0c, 0x00, 0x00, 0x8c, 0x3d, 0x00, 0x00, 0x03, 0x3d, 0x00, 0x00, 0x69, + 0xe8, 0xff, 0xff, 0xd6, 0x20, 0x00, 0x00, 0xc0, 0xd5, 0xff, 0xff, 0x56, 0xe8, + 0xff, 0xff, 0x41, 0x2f, 0x00, 0x00, 0xbf, 0x21, 0x00, 0x00, 0xbb, 0x02, 0x00, + 0x00, 0x4a, 0x71, 0x00, 0x00, 0x73, 0x18, 0x00, 0x00, 0x7e, 0x3b, 0x00, 0x00, + 0xc2, 0x6d, 0x00, 0x00, 0x83, 0xfc, 0xff, 0xff, 0x65, 0xfe, 0xff, 0xff, 0x67, + 0xfc, 0xff, 0xff, 0xcc, 0x8d, 0x00, 0x00, 0xf9, 0xd0, 0xff, 0xff, 0x2a, 0x14, + 0x00, 0x00, 0x33, 0xe4, 0xff, 0xff, 0x1b, 0x1e, 0x00, 0x00, 0x75, 0xf8, 0xff, + 0xff, 0xb9, 0xc9, 0xff, 0xff, 0x8a, 0x34, 0x00, 0x00, 0x78, 0xe6, 0xff, 0xff, + 0xa9, 0x27, 0x00, 0x00, 0xab, 0x04, 0x00, 0x00, 0x66, 0xe5, 0xff, 0xff, 0x70, + 0xa2, 0xff, 0xff, 0x23, 0xe8, 0xff, 0xff, 0x5f, 0xe5, 0xff, 0xff, 0x48, 0xe7, + 0xff, 0xff, 0x3e, 0x08, 0x00, 0x00, 0xa6, 0x3d, 0x00, 0x00, 0x0d, 0x11, 0x00, + 0x00, 0xe5, 0x2f, 0x00, 0x00, 0x3c, 0x55, 0x00, 0x00, 0xd9, 0xf8, 0xff, 0xff, + 0xc8, 0x00, 0x00, 0x00, 0x26, 0x16, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0xf1, 0xf7, 0xff, 0xff, 0x03, 0x2a, 0x00, 0x00, 0xfb, 0xd0, + 0xff, 0xff, 0xef, 0xe6, 0xff, 0xff, 0x63, 0x08, 0x00, 0x00, 0x6c, 0xe5, 0xff, + 0xff, 0x15, 0x20, 0x00, 0x00, 0x25, 0xf0, 0xff, 0xff, 0x94, 0x2a, 0x00, 0x00, + 0x2b, 0x29, 0x00, 0x00, 0xa3, 0xee, 0xff, 0xff, 0xb1, 0x01, 0x00, 0x00, 0xa4, + 0x27, 0x00, 0x00, 0xde, 0xdd, 0xff, 0xff, 0x9b, 0xfd, 0xff, 0xff, 0x54, 0xfb, + 0xff, 0xff, 0x8b, 0xed, 0xff, 0xff, 0x4d, 0xe5, 0xff, 0xff, 0x4b, 0xe5, 0xff, + 0xff, 0x0f, 0xc8, 0xff, 0xff, 0x31, 0xf6, 0xff, 0xff, 0xdc, 0xdb, 0xff, 0xff, + 0x92, 0xf7, 0xff, 0xff, 0xdb, 0xef, 0xff, 0xff, 0x49, 0xfe, 0xff, 0xff, 0x8d, + 0xf2, 0xff, 0xff, 0x56, 0xe5, 0xff, 0xff, 0xa5, 0x00, 0x00, 0x00, 0xbb, 0xf1, + 0xff, 0xff, 0xe3, 0x05, 0x00, 0x00, 0x51, 0xf5, 0xff, 0xff, 0x0a, 0xfb, 0xff, + 0xff, 0x6e, 0xe7, 0xff, 0xff, 0x42, 0x1c, 0x00, 0x00, 0x89, 0xeb, 0xff, 0xff, + 0x71, 0xf0, 0xff, 0xff, 0x53, 0xeb, 0xff, 0xff, 0x24, 0x05, 0x00, 0x00, 0x0b, + 0x20, 0x00, 0x00, 0x28, 0xfe, 0xff, 0xff, 0xd0, 0x2d, 0x00, 0x00, 0x49, 0x07, + 0x00, 0x00, 0xef, 0x24, 0x00, 0x00, 0xf1, 0xfb, 0xff, 0xff, 0x44, 0x0e, 0x00, + 0x00, 0x9c, 0x22, 0x00, 0x00, 0x5f, 0xe6, 0xff, 0xff, 0x39, 0xe5, 0xff, 0xff, + 0xc1, 0xff, 0xff, 0xff, 0xa8, 0xfa, 0xff, 0xff, 0x90, 0xe7, 0xff, 0xff, 0xdd, + 0xf9, 0xff, 0xff, 0x81, 0xee, 0xff, 0xff, 0xa5, 0x26, 0x00, 0x00, 0xe4, 0xeb, + 0xff, 0xff, 0xb7, 0x23, 0x00, 0x00, 0xcf, 0xe4, 0xff, 0xff, 0x39, 0xf6, 0xff, + 0xff, 0x07, 0xfd, 0xff, 0xff, 0x14, 0xfe, 0xff, 0xff, 0xf5, 0x1e, 0x00, 0x00, + 0xde, 0xf7, 0xff, 0xff, 0xad, 0xef, 0xff, 0xff, 0x2a, 0xe7, 0xff, 0xff, 0x5b, + 0xec, 0xff, 0xff, 0xba, 0xfe, 0xff, 0xff, 0x63, 0xee, 0xff, 0xff, 0x92, 0xff, + 0xff, 0xff, 0xd5, 0xf8, 0xff, 0xff, 0xda, 0xdb, 0xff, 0xff, 0x79, 0x05, 0x00, + 0x00, 0xed, 0xf2, 0xff, 0xff, 0x8c, 0xe2, 0xff, 0xff, 0x5c, 0xee, 0xff, 0xff, + 0x07, 0xe5, 0xff, 0xff, 0xee, 0x01, 0x00, 0x00, 0xe2, 0xe6, 0xff, 0xff, 0xf7, + 0xed, 0xff, 0xff, 0x8f, 0x2a, 0x00, 0x00, 0x2e, 0x28, 0x00, 0x00, 0xc1, 0x26, + 0x00, 0x00, 0x9f, 0xe5, 0xff, 0xff, 0x6a, 0x03, 0x00, 0x00, 0xc1, 0xef, 0xff, + 0xff, 0x37, 0xf8, 0xff, 0xff, 0x47, 0xf0, 0xff, 0xff, 0xfa, 0x22, 0x00, 0x00, + 0xb5, 0xf5, 0xff, 0xff, 0xd0, 0xfd, 0xff, 0xff, 0x11, 0xef, 0xff, 0xff, 0x1f, + 0x2e, 0x00, 0x00, 0x65, 0xe9, 0xff, 0xff, 0x08, 0x1d, 0x00, 0x00, 0x77, 0xdb, + 0xff, 0xff, 0x36, 0xf9, 0xff, 0xff, 0xab, 0xe2, 0xff, 0xff, 0xfb, 0x16, 0x00, + 0x00, 0x53, 0xf5, 0xff, 0xff, 0x96, 0x2c, 0x00, 0x00, 0x10, 0xe1, 0xff, 0xff, + 0xb4, 0xf8, 0xff, 0xff, 0x20, 0x1a, 0x00, 0x00, 0x98, 0xe4, 0xff, 0xff, 0x9b, + 0x27, 0x00, 0x00, 0x23, 0x2c, 0x00, 0x00, 0x07, 0x2e, 0x00, 0x00, 0xd2, 0xfb, + 0xff, 0xff, 0x15, 0xec, 0xff, 0xff, 0x52, 0x20, 0x00, 0x00, 0x9a, 0xf0, 0xff, + 0xff, 0xcc, 0x2c, 0x00, 0x00, 0x58, 0xee, 0xff, 0xff, 0x79, 0x25, 0x00, 0x00, + 0xaf, 0xea, 0xff, 0xff, 0x90, 0xf4, 0xff, 0xff, 0x4c, 0x21, 0x00, 0x00, 0x3d, + 0xf0, 0xff, 0xff, 0x56, 0xf9, 0xff, 0xff, 0x36, 0xef, 0xff, 0xff, 0x77, 0xea, + 0xff, 0xff, 0x77, 0xfc, 0xff, 0xff, 0xf0, 0xd8, 0xff, 0xff, 0x18, 0x29, 0x00, + 0x00, 0x9d, 0x0c, 0x00, 0x00, 0x0f, 0x26, 0x00, 0x00, 0xa1, 0x30, 0x00, 0x00, + 0x74, 0xea, 0xff, 0xff, 0x47, 0xf1, 0xff, 0xff, 0x32, 0x18, 0xfe, 0xff, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xdb, 0x02, 0x20, 0x9a, 0x25, 0x14, + 0x19, 0x7f, 0xc5, 0x6c, 0xfe, 0xd7, 0x27, 0xd0, 0x05, 0xef, 0x21, 0xdb, 0x5c, + 0xc6, 0x0f, 0x08, 0xf8, 0x01, 0x2a, 0xff, 0xcb, 0xf5, 0xe1, 0x28, 0xa5, 0x94, + 0x45, 0xfd, 0xdd, 0xf7, 0xd6, 0xfb, 0x18, 0xda, 0x0a, 0xf8, 0xec, 0x23, 0xe2, + 0x28, 0xd7, 0x3a, 0x11, 0x15, 0x15, 0x0d, 0xe2, 0xb6, 0x0a, 0xf1, 0x9f, 0xab, + 0xf4, 0xed, 0x18, 0x0e, 0x0f, 0xef, 0xf1, 0xea, 0xeb, 0x11, 0xf5, 0xbd, 0xfd, + 0xf0, 0x52, 0x1f, 0xdd, 0xe3, 0xcd, 0xc3, 0x10, 0xc0, 0xdd, 0xe6, 0x01, 0x33, + 0xfa, 0x1b, 0x6a, 0xb7, 0x1a, 0xeb, 0x43, 0x0e, 0x32, 0x07, 0xed, 0xe0, 0xdd, + 0x2c, 0x2c, 0xe9, 0xc9, 0x17, 0xfa, 0x1e, 0x4b, 0x7f, 0x28, 0xef, 0x51, 0xed, + 0x9d, 0x57, 0x6a, 0xe6, 0xcb, 0x1d, 0xba, 0x20, 0xb6, 0x7c, 0x1c, 0x06, 0xf2, + 0xb2, 0xfb, 0x2b, 0x13, 0x1a, 0xcd, 0x03, 0xce, 0xda, 0xb9, 0x27, 0x38, 0x05, + 0xe9, 0x33, 0x2b, 0xf9, 0x4e, 0x32, 0xbb, 0xe8, 0x15, 0xae, 0x31, 0x18, 0xce, + 0x47, 0x1e, 0xf7, 0x3b, 0xe2, 0x02, 0x23, 0xcf, 0x08, 0xf4, 0xe4, 0xf7, 0x23, + 0xe9, 0x2f, 0xbb, 0xde, 0xe9, 0xe4, 0xf7, 0x1b, 0x01, 0x19, 0xf5, 0x58, 0x42, + 0x06, 0x04, 0x12, 0x08, 0x7f, 0x0d, 0x2c, 0x06, 0x0e, 0x06, 0xee, 0xe2, 0x20, + 0xb7, 0xe0, 0xf4, 0x1e, 0xf6, 0xc9, 0x1b, 0x10, 0xf6, 0x64, 0xe0, 0xcc, 0xdc, + 0x14, 0x2d, 0x30, 0xfd, 0xc3, 0x21, 0x21, 0xcd, 0xc6, 0xf3, 0x10, 0x12, 0xec, + 0x01, 0xdc, 0xe9, 0xde, 0x23, 0xe0, 0x1a, 0x23, 0xfa, 0x24, 0xe7, 0x1b, 0x0f, + 0x11, 0x0f, 0x37, 0xdc, 0xee, 0x11, 0x0a, 0x16, 0x73, 0xf1, 0xcf, 0xd4, 0x20, + 0xf6, 0x4d, 0x1d, 0x0d, 0x25, 0x09, 0x0e, 0xc4, 0xf6, 0xd0, 0xe2, 0x34, 0xe4, + 0xf1, 0xf9, 0xe1, 0x42, 0xf6, 0xef, 0x0c, 0x67, 0x35, 0xf9, 0xe8, 0xc7, 0x03, + 0x23, 0x1e, 0x20, 0x3b, 0x3e, 0xd8, 0xf5, 0x47, 0xcb, 0xb1, 0xac, 0xcf, 0xe4, + 0xfa, 0x14, 0x07, 0x07, 0x76, 0xc3, 0xeb, 0x66, 0x1f, 0x52, 0xe5, 0xbb, 0xc5, + 0x59, 0x1a, 0xd8, 0xf7, 0x02, 0xdd, 0x2c, 0x4d, 0x96, 0x44, 0x00, 0x1a, 0x2e, + 0xd8, 0x08, 0x44, 0x1b, 0xfd, 0xfb, 0x39, 0xc1, 0xf1, 0xde, 0x4c, 0xed, 0x56, + 0x19, 0x48, 0xc3, 0xeb, 0xec, 0x08, 0xb8, 0x0d, 0x16, 0xdf, 0xdd, 0xce, 0x0b, + 0x59, 0xde, 0x99, 0xe6, 0x0c, 0xac, 0xd0, 0x43, 0x1d, 0xb2, 0xd9, 0x03, 0xd9, + 0xfc, 0xde, 0xf7, 0xa9, 0xf9, 0x33, 0xf6, 0xde, 0x1d, 0xd8, 0x3a, 0xe8, 0x43, + 0xaa, 0x8f, 0xd6, 0xb5, 0x11, 0x4f, 0x24, 0x15, 0xa2, 0xb2, 0xf6, 0xce, 0xfa, + 0xc4, 0x0b, 0x1c, 0x84, 0x65, 0xf9, 0xb1, 0x15, 0x0c, 0xf7, 0xc8, 0xca, 0x81, + 0xf0, 0xe2, 0x4c, 0xba, 0x0e, 0x23, 0xc0, 0x36, 0x11, 0xe9, 0x11, 0xf9, 0xb4, + 0xe8, 0xe8, 0xf5, 0x30, 0xb6, 0x0d, 0xc1, 0x08, 0xb6, 0xb3, 0x23, 0x9e, 0xf3, + 0xe2, 0xb0, 0x00, 0x37, 0xf5, 0xf9, 0x0b, 0xb1, 0x22, 0xc0, 0xed, 0x01, 0x23, + 0xeb, 0xec, 0x24, 0xee, 0xe2, 0x1d, 0xfb, 0xe0, 0xf9, 0xc5, 0x2a, 0xf9, 0x81, + 0x19, 0xb9, 0xf7, 0x4b, 0x28, 0x10, 0xe1, 0x34, 0x02, 0x1f, 0xd2, 0x05, 0xf9, + 0xdf, 0xf6, 0x27, 0x06, 0x16, 0xfe, 0xcf, 0xf6, 0xff, 0xfc, 0xce, 0xe8, 0xe8, + 0xf4, 0xd9, 0x13, 0xb4, 0x1b, 0x08, 0x0a, 0x40, 0xf4, 0x27, 0x0a, 0x21, 0x1e, + 0xf4, 0xdc, 0x17, 0x50, 0x0f, 0xe5, 0x36, 0xf6, 0xe8, 0xe0, 0x41, 0x22, 0xe9, + 0x24, 0x2c, 0x40, 0x18, 0xe5, 0xfa, 0xf2, 0x16, 0xf6, 0x34, 0x09, 0xfa, 0x46, + 0x01, 0xf2, 0x9d, 0x2b, 0x38, 0x2e, 0x1f, 0xd4, 0x25, 0x17, 0xf8, 0x05, 0x39, + 0xb2, 0xf3, 0x2b, 0xd6, 0xfe, 0xc6, 0xb4, 0xf0, 0x0f, 0x90, 0x45, 0xc0, 0xa4, + 0x24, 0x44, 0x13, 0x08, 0x14, 0x03, 0xa6, 0xca, 0x98, 0xa5, 0x0f, 0x47, 0xd4, + 0xef, 0x36, 0x0d, 0x9a, 0x6f, 0xbb, 0xf7, 0x0a, 0x1b, 0xd6, 0xe4, 0x07, 0x00, + 0x02, 0x27, 0xb3, 0xff, 0x6c, 0x1b, 0xd9, 0x00, 0x2e, 0xa9, 0x7f, 0xdc, 0x28, + 0x9c, 0x97, 0xc2, 0xdb, 0x30, 0xeb, 0x1c, 0x2d, 0x3b, 0x09, 0x15, 0xe9, 0x39, + 0x41, 0x63, 0xe4, 0x9a, 0x3f, 0x08, 0xf0, 0x59, 0x00, 0xf8, 0x38, 0x17, 0xdc, + 0x24, 0x31, 0xb7, 0x58, 0xe9, 0x00, 0xf7, 0xf5, 0x2a, 0x28, 0x01, 0xf5, 0xf2, + 0xf4, 0x0d, 0x49, 0xfc, 0x12, 0xd4, 0x64, 0xae, 0x35, 0x34, 0xb7, 0x2d, 0xf8, + 0x03, 0xd2, 0x06, 0x23, 0xcb, 0x09, 0xd9, 0xee, 0x54, 0xb5, 0x0a, 0xc4, 0x66, + 0x14, 0xc7, 0x17, 0xd7, 0xde, 0x23, 0xd8, 0x11, 0x16, 0x22, 0xfc, 0xff, 0xce, + 0x3f, 0x10, 0xf5, 0xf9, 0x3e, 0x13, 0xf8, 0xfc, 0xdb, 0xe3, 0x55, 0x09, 0xec, + 0xdc, 0x11, 0x04, 0x15, 0x13, 0x19, 0xfc, 0x7f, 0xef, 0x02, 0x0a, 0xee, 0xed, + 0x28, 0xe4, 0x13, 0x2d, 0x08, 0x0b, 0x21, 0xfd, 0xe4, 0x09, 0xc6, 0xc1, 0x34, + 0x04, 0x04, 0x0a, 0xe5, 0xfa, 0xd1, 0x22, 0x04, 0x0f, 0x03, 0xdc, 0xf9, 0x2c, + 0xe1, 0xd1, 0xfa, 0xdc, 0xed, 0x2a, 0x65, 0x06, 0x2e, 0xf9, 0x2f, 0x02, 0x9b, + 0xeb, 0x2f, 0xe8, 0x02, 0xe3, 0x0c, 0x10, 0x10, 0xe9, 0x02, 0xfa, 0xfe, 0x13, + 0x12, 0xd4, 0xcb, 0xd4, 0xfd, 0xe8, 0xe1, 0xf2, 0x25, 0x05, 0xc8, 0xec, 0xf7, + 0xce, 0x01, 0x3c, 0xda, 0xfb, 0xcf, 0xfd, 0xf0, 0x44, 0xf9, 0x11, 0x0a, 0xf3, + 0x04, 0x26, 0xf8, 0xdf, 0xed, 0x0e, 0xdd, 0x1c, 0x02, 0xc9, 0xd8, 0xfb, 0xdb, + 0x0d, 0xf5, 0x10, 0xd5, 0xf5, 0xea, 0x3a, 0xea, 0x03, 0xfd, 0x17, 0xf5, 0x04, + 0x16, 0xff, 0xf8, 0x09, 0xe2, 0xe9, 0x4c, 0xf8, 0x4f, 0xd5, 0x27, 0xd4, 0x4a, + 0x20, 0x40, 0x7f, 0xeb, 0xcf, 0xe4, 0x26, 0xfd, 0x18, 0x08, 0xce, 0x0c, 0x13, + 0x08, 0xda, 0x12, 0x24, 0xe2, 0x25, 0x3f, 0xeb, 0x08, 0x24, 0xb4, 0x1e, 0x03, + 0xf1, 0xcc, 0x00, 0xbe, 0xb6, 0x0d, 0x21, 0x10, 0x1a, 0xf5, 0xf7, 0x05, 0xfa, + 0x03, 0x14, 0x00, 0xe7, 0x3c, 0x28, 0xe8, 0x58, 0x1e, 0xbf, 0x12, 0x62, 0xcb, + 0x7a, 0xfb, 0x1e, 0xf5, 0x1d, 0xf1, 0xe7, 0xf7, 0xd8, 0x06, 0xcc, 0xda, 0xfc, + 0x19, 0xc5, 0xf6, 0xdd, 0x10, 0xd5, 0x24, 0xfd, 0x26, 0xf1, 0xbd, 0xbf, 0x40, + 0xf6, 0x41, 0x3e, 0x1f, 0x51, 0xdc, 0xbe, 0x39, 0x19, 0x20, 0xe0, 0xbe, 0x04, + 0x1e, 0x08, 0xfb, 0xf6, 0x26, 0x0b, 0xc2, 0xc9, 0x13, 0x2c, 0x34, 0x37, 0xfe, + 0xf2, 0x1a, 0xe6, 0xe8, 0x29, 0x1a, 0x18, 0x15, 0xe7, 0x75, 0xd2, 0xdd, 0x13, + 0xde, 0x0b, 0xec, 0x24, 0xd8, 0xd9, 0xd2, 0x06, 0x2a, 0x10, 0xbe, 0xc6, 0xf9, + 0x19, 0x22, 0x57, 0xb9, 0xef, 0x1a, 0xd2, 0xe7, 0xfe, 0x07, 0x22, 0x0c, 0x2c, + 0x26, 0x81, 0xb0, 0xcb, 0xf6, 0x34, 0x15, 0x43, 0xf2, 0x0a, 0x42, 0xdf, 0xdc, + 0xc8, 0xe7, 0xd2, 0xef, 0xf9, 0x17, 0xee, 0x0e, 0xe1, 0x19, 0x0c, 0xb0, 0x36, + 0x0e, 0x24, 0xee, 0x37, 0x24, 0x09, 0xf8, 0xb4, 0x0c, 0x38, 0xfc, 0xf5, 0x4c, + 0xc0, 0x27, 0xff, 0x19, 0xf1, 0x23, 0x0a, 0xba, 0x4a, 0x54, 0x46, 0xae, 0x00, + 0xcf, 0xe4, 0xd7, 0xd6, 0xc6, 0x05, 0x13, 0xbb, 0x08, 0xed, 0xd0, 0x05, 0x5f, + 0xcd, 0xf2, 0xdf, 0xff, 0xca, 0xc1, 0xc6, 0xfc, 0x0f, 0x7c, 0xd2, 0x17, 0x40, + 0x00, 0xed, 0x98, 0xcd, 0x23, 0xbd, 0xf2, 0xce, 0xf8, 0x07, 0x35, 0x4f, 0xed, + 0x02, 0xee, 0x14, 0x46, 0x25, 0xe9, 0xe7, 0x90, 0x38, 0x24, 0xec, 0x09, 0xa8, + 0xf5, 0x59, 0x15, 0x28, 0xf7, 0x05, 0xee, 0x0e, 0x1b, 0xe5, 0x64, 0xfe, 0x36, + 0xd4, 0x2f, 0x72, 0xe8, 0x37, 0xda, 0xd7, 0x15, 0xc1, 0x92, 0x19, 0x01, 0x21, + 0xa9, 0xb1, 0xdf, 0x46, 0x1c, 0x2e, 0x08, 0xd1, 0x48, 0xe8, 0xe3, 0x37, 0x5d, + 0x0d, 0x3c, 0xf6, 0xa3, 0xeb, 0xa5, 0xce, 0x07, 0xf5, 0xae, 0x1c, 0x0f, 0x5d, + 0x5b, 0x2d, 0xa3, 0x24, 0x4e, 0x50, 0x10, 0xe1, 0x1d, 0x2a, 0x26, 0x18, 0x4b, + 0xdc, 0x32, 0xcd, 0x20, 0xf9, 0xe0, 0xfe, 0x9a, 0xe3, 0xe2, 0xb5, 0x3f, 0xfe, + 0x35, 0xe6, 0xa9, 0x37, 0xb6, 0xf0, 0x40, 0x0a, 0xc4, 0xd7, 0xf0, 0x72, 0x03, + 0xe8, 0xeb, 0x11, 0xf3, 0xf1, 0xcd, 0x1c, 0xe2, 0x29, 0x1b, 0xe1, 0x21, 0x1b, + 0xe4, 0x25, 0x09, 0xc7, 0x37, 0xbf, 0x81, 0x33, 0x86, 0x0d, 0xcc, 0xe7, 0xce, + 0x32, 0xf7, 0x11, 0x03, 0x1c, 0xed, 0xe8, 0xea, 0x42, 0x96, 0x00, 0x3f, 0x07, + 0xf2, 0xfd, 0x19, 0x2a, 0xc7, 0x0a, 0x0e, 0x62, 0xb3, 0x1a, 0xab, 0x0f, 0xb2, + 0x28, 0x19, 0xf3, 0xdb, 0x1c, 0x26, 0xf0, 0xf5, 0x2a, 0x19, 0xad, 0xcc, 0xcf, + 0x26, 0x3a, 0x34, 0xc1, 0xff, 0x07, 0x1d, 0xec, 0x21, 0xcc, 0x1a, 0xbf, 0x11, + 0xcb, 0x0c, 0x2d, 0x3a, 0x0a, 0xcd, 0x10, 0x4c, 0x12, 0xfa, 0xd0, 0xf9, 0xe6, + 0x1b, 0xb1, 0xe5, 0xd8, 0x2b, 0x13, 0xf5, 0xe4, 0x22, 0x21, 0x01, 0x45, 0xf9, + 0x1d, 0xfb, 0x25, 0xf8, 0x35, 0x4d, 0xca, 0x19, 0x30, 0xcf, 0xee, 0x02, 0xe3, + 0xf1, 0x1b, 0x0d, 0xe2, 0x23, 0x3f, 0x26, 0x34, 0x00, 0x5a, 0x0a, 0x7f, 0xed, + 0x39, 0x1b, 0x09, 0xdd, 0x0e, 0xca, 0xbf, 0xc1, 0x1b, 0x54, 0x3c, 0x38, 0xb0, + 0xf8, 0x32, 0x24, 0x24, 0x0a, 0xe7, 0x25, 0x5c, 0xca, 0x33, 0x18, 0xdc, 0x3c, + 0xc9, 0xfa, 0x06, 0x47, 0x08, 0xfc, 0x17, 0x07, 0x10, 0xfe, 0xbe, 0xe1, 0xe5, + 0x31, 0x49, 0xdb, 0xdc, 0xab, 0x2b, 0x04, 0xe2, 0xe2, 0xc6, 0x40, 0xff, 0x02, + 0xdc, 0xe2, 0xe8, 0x21, 0x07, 0xf0, 0xf7, 0xe8, 0x32, 0xf0, 0x46, 0x36, 0x0a, + 0xe6, 0xd4, 0x04, 0xd2, 0xc1, 0x52, 0xe1, 0x13, 0x17, 0x0c, 0xca, 0x2d, 0xe3, + 0x28, 0xdc, 0xc8, 0x06, 0xf0, 0xb5, 0x0c, 0xc9, 0x47, 0x43, 0xde, 0x2b, 0x3f, + 0x23, 0x37, 0xb9, 0x09, 0x1a, 0x25, 0x57, 0x74, 0xec, 0xbe, 0x09, 0xe7, 0x54, + 0xd0, 0xf1, 0x19, 0x07, 0x3e, 0x81, 0xca, 0x21, 0xe4, 0x07, 0x10, 0x1a, 0xca, + 0x2c, 0xe9, 0xc3, 0xce, 0x4c, 0xf8, 0x1b, 0x33, 0x12, 0x26, 0x12, 0x1b, 0x09, + 0xdd, 0xe3, 0xef, 0x00, 0xdc, 0xed, 0xbb, 0xef, 0x13, 0xf9, 0x07, 0xf0, 0x14, + 0xf8, 0x1a, 0xf2, 0xf0, 0x32, 0x13, 0xf1, 0x16, 0x01, 0x25, 0xef, 0x9a, 0xc3, + 0xfa, 0x02, 0x03, 0x0e, 0xe4, 0xb7, 0x11, 0x10, 0xd3, 0xec, 0x11, 0x3c, 0x30, + 0xe5, 0xe3, 0x37, 0x0a, 0xd3, 0xf0, 0xfb, 0xf8, 0x20, 0x06, 0x14, 0xfc, 0x1d, + 0x18, 0x24, 0xfa, 0x3e, 0x6c, 0x0c, 0xce, 0xe4, 0x36, 0x38, 0xb6, 0x1b, 0xe4, + 0xf8, 0x23, 0xe8, 0x00, 0xe8, 0x06, 0x0a, 0xcf, 0xeb, 0xfb, 0xde, 0xf7, 0x44, + 0xef, 0xde, 0xee, 0x98, 0x11, 0xfe, 0x35, 0xef, 0xde, 0x23, 0x07, 0xbf, 0x35, + 0x0e, 0x02, 0xfc, 0x7f, 0xd5, 0x09, 0xd7, 0x1e, 0xf6, 0x09, 0xcb, 0xef, 0x09, + 0x24, 0xf0, 0xec, 0xf3, 0xa7, 0xea, 0x22, 0x26, 0x1b, 0x39, 0x13, 0x4d, 0xf7, + 0xc4, 0xd7, 0xe7, 0xf4, 0x07, 0xf6, 0xf8, 0x08, 0xe3, 0xd6, 0x1c, 0x60, 0xb3, + 0xbc, 0x0c, 0xf5, 0xd0, 0x05, 0x31, 0xf0, 0x60, 0xbf, 0x00, 0xbc, 0xcd, 0x4b, + 0xbc, 0xdb, 0x0d, 0xf4, 0xec, 0xf2, 0x26, 0xc9, 0x1c, 0x25, 0xae, 0x5f, 0x4f, + 0xf6, 0xea, 0xd3, 0xb9, 0x96, 0xe6, 0x3a, 0x2f, 0xff, 0x05, 0x2d, 0xa4, 0x12, + 0x56, 0x5b, 0xec, 0xcb, 0xd1, 0x29, 0x9a, 0xb9, 0x27, 0x02, 0x22, 0x3c, 0x0f, + 0x1f, 0xec, 0x9f, 0xfc, 0x97, 0xf5, 0x0c, 0xfb, 0x10, 0x03, 0xf0, 0x27, 0xb6, + 0x67, 0xe9, 0xd9, 0xa3, 0xbd, 0x3a, 0xe2, 0xe1, 0xa0, 0xcb, 0x40, 0x2f, 0x3f, + 0x01, 0xf1, 0xfe, 0x81, 0xf8, 0x4e, 0x8b, 0x06, 0x09, 0x2f, 0x46, 0x12, 0xc5, + 0x15, 0xd0, 0x14, 0x8f, 0x1a, 0xea, 0x1d, 0x14, 0x3b, 0x0c, 0x74, 0x1c, 0x87, + 0x31, 0xd4, 0xd6, 0x39, 0xac, 0xc2, 0x32, 0x3d, 0x04, 0xcd, 0xd2, 0x16, 0x6d, + 0xc3, 0x3d, 0xf7, 0x02, 0xe4, 0x02, 0xd6, 0xac, 0x2a, 0x66, 0x02, 0xa3, 0xb8, + 0xec, 0xe3, 0xea, 0x4a, 0xeb, 0xec, 0x2c, 0xf8, 0x42, 0xec, 0x2b, 0xe0, 0x2f, + 0x30, 0xfb, 0x1d, 0xe3, 0xed, 0x2a, 0x5a, 0xd7, 0x5d, 0x12, 0x9f, 0x06, 0xdd, + 0x09, 0xce, 0x09, 0xc6, 0x09, 0xf1, 0xfd, 0xe5, 0x1e, 0xe4, 0xe6, 0xab, 0x17, + 0x97, 0xe4, 0xcb, 0xdc, 0x32, 0xd6, 0xc4, 0xb6, 0x0e, 0xfe, 0x38, 0x2d, 0xc1, + 0x03, 0xe1, 0x0f, 0xf8, 0xaf, 0xf2, 0x02, 0xba, 0xfc, 0x16, 0xaf, 0xc1, 0x26, + 0x0b, 0xe7, 0x3e, 0x35, 0x0a, 0x59, 0x0e, 0x7a, 0xc4, 0x55, 0xf8, 0xe2, 0xce, + 0x7c, 0xc7, 0xb9, 0xff, 0xcb, 0xf1, 0xed, 0xf5, 0x06, 0xe3, 0xa7, 0x81, 0xec, + 0xcb, 0x04, 0xc0, 0x16, 0xf6, 0x3d, 0xcc, 0x2d, 0xe6, 0xe5, 0x09, 0x12, 0x58, + 0x24, 0x21, 0x17, 0xc7, 0xeb, 0xe8, 0xcb, 0x08, 0xd8, 0x09, 0x83, 0xdc, 0xb5, + 0x16, 0xf5, 0xf2, 0xc8, 0xa6, 0x2a, 0xe1, 0xf7, 0x37, 0xf0, 0x2a, 0xe9, 0xf5, + 0x19, 0xe8, 0x19, 0xc8, 0x2c, 0x13, 0xdb, 0x57, 0x2b, 0xd1, 0x49, 0xff, 0x0d, + 0xff, 0x0e, 0x15, 0xd9, 0x14, 0x1d, 0x05, 0x24, 0xb6, 0x6d, 0xed, 0x03, 0xaf, + 0x3d, 0x2f, 0x9b, 0xfe, 0x00, 0xed, 0xf8, 0xd9, 0x3d, 0xfc, 0x2c, 0x1f, 0xdc, + 0xa4, 0xcc, 0x1e, 0xd0, 0x32, 0x10, 0xbb, 0x09, 0xff, 0xea, 0x94, 0xf3, 0x1b, + 0xf7, 0xeb, 0xea, 0xfa, 0x30, 0xc8, 0xdf, 0xdb, 0x08, 0xea, 0x18, 0xd1, 0x41, + 0x30, 0xf6, 0xf5, 0xd3, 0xdf, 0xad, 0x1b, 0xb0, 0x0b, 0x14, 0xf9, 0xf6, 0xf3, + 0x11, 0xe7, 0xed, 0xfb, 0x35, 0x1c, 0xcf, 0x1e, 0xb9, 0xfd, 0x4b, 0xe4, 0xd8, + 0x23, 0x12, 0x05, 0x0d, 0xf5, 0x43, 0x08, 0x11, 0xed, 0x03, 0xde, 0xe7, 0x34, + 0xfe, 0xc9, 0xfa, 0xdb, 0x2a, 0x16, 0x28, 0x87, 0x1f, 0x09, 0xe2, 0x25, 0x27, + 0xdd, 0x4d, 0x1a, 0xff, 0xd9, 0x4f, 0x1e, 0x36, 0xe3, 0xde, 0x81, 0x4f, 0x53, + 0x43, 0xf3, 0x3b, 0x03, 0xeb, 0xc4, 0xe7, 0x21, 0x4b, 0x02, 0x17, 0x19, 0xff, + 0x04, 0xdb, 0xbb, 0x0d, 0xf0, 0xe3, 0x74, 0xc0, 0x15, 0xef, 0x06, 0x0a, 0xfb, + 0xfd, 0x0b, 0xc9, 0xd5, 0x28, 0x09, 0xc9, 0x2d, 0x19, 0x01, 0x27, 0x2f, 0x1d, + 0x7b, 0xde, 0xe4, 0xd9, 0xfa, 0x09, 0x2d, 0xed, 0xfd, 0xe2, 0x3d, 0x02, 0xde, + 0xaf, 0x02, 0xe5, 0x2f, 0xca, 0x66, 0xc4, 0xcd, 0x0d, 0x06, 0x06, 0xa5, 0x2b, + 0xc9, 0xe6, 0x02, 0x1f, 0xbc, 0x35, 0x04, 0xf7, 0xd8, 0x2c, 0xec, 0x20, 0x1c, + 0x0f, 0x13, 0x75, 0xed, 0x1a, 0x21, 0x23, 0x38, 0x22, 0x12, 0x08, 0xed, 0xc3, + 0xe7, 0xff, 0x32, 0xa1, 0x18, 0x46, 0xf0, 0x4c, 0xe8, 0x08, 0x7a, 0xe0, 0xe2, + 0x15, 0x81, 0xa2, 0x0f, 0xdb, 0xac, 0x1f, 0xf5, 0x14, 0x4a, 0x24, 0x3c, 0x05, + 0xe6, 0x5e, 0x3f, 0x05, 0x36, 0xef, 0xb3, 0x0d, 0x2d, 0xe4, 0xb3, 0xe7, 0x02, + 0x29, 0xf4, 0xf1, 0x6b, 0xe0, 0x02, 0x3f, 0xe3, 0x3e, 0x33, 0x21, 0xef, 0x4e, + 0xfd, 0xe9, 0x4e, 0x30, 0xe1, 0x09, 0xa6, 0xf5, 0xf3, 0xc2, 0x04, 0x9c, 0xe2, + 0xd9, 0x0d, 0xdf, 0x06, 0x9c, 0xbd, 0xf7, 0xd6, 0x0b, 0xf8, 0xda, 0xf3, 0x26, + 0xf9, 0x15, 0xeb, 0x2c, 0xc1, 0xa8, 0xcf, 0xed, 0x20, 0x92, 0x21, 0xde, 0xd0, + 0xf4, 0xc5, 0x28, 0x0c, 0x0f, 0xe1, 0x3b, 0xf9, 0xd7, 0xe4, 0x04, 0xe9, 0x84, + 0x00, 0x3a, 0xeb, 0xea, 0x04, 0x0d, 0xb2, 0xd7, 0xfb, 0x2f, 0xf8, 0x06, 0xeb, + 0xf2, 0xf9, 0x06, 0xf1, 0xc2, 0x0e, 0xf7, 0x00, 0x89, 0xd3, 0x62, 0xda, 0xed, + 0x19, 0x1a, 0xf5, 0x07, 0x15, 0xe6, 0xf5, 0x7f, 0xeb, 0x36, 0xe2, 0x5b, 0x16, + 0xdc, 0x0a, 0x00, 0xcc, 0xfd, 0xf5, 0x01, 0xe9, 0x02, 0xc7, 0x25, 0x40, 0xac, + 0xd0, 0x4a, 0xf5, 0xeb, 0xf8, 0xfb, 0x8c, 0x3d, 0x1f, 0x0b, 0x11, 0x2f, 0x3d, + 0x21, 0xb2, 0xfc, 0x36, 0xfa, 0x2f, 0x20, 0x0d, 0x26, 0x1d, 0xec, 0xca, 0x12, + 0x0d, 0x3d, 0x11, 0x2c, 0x9c, 0x1c, 0x3b, 0x25, 0x15, 0x16, 0xd4, 0x3b, 0xce, + 0x63, 0x7f, 0x50, 0xe2, 0x18, 0xdc, 0xbd, 0xd5, 0xe8, 0x42, 0xdd, 0x7c, 0xd6, + 0xce, 0x0c, 0x16, 0xf6, 0x05, 0xf7, 0x19, 0xde, 0xf8, 0xff, 0xe8, 0xf4, 0xef, + 0xd7, 0xee, 0xee, 0x02, 0x6a, 0x49, 0x57, 0xd2, 0x09, 0xdc, 0xb6, 0x4d, 0x00, + 0xfd, 0x4b, 0xf5, 0x3d, 0x01, 0x35, 0xf5, 0x1e, 0x10, 0xef, 0x35, 0x05, 0x71, + 0x23, 0x1e, 0x03, 0xfe, 0xd3, 0xe2, 0x48, 0xfa, 0x1a, 0xc5, 0x48, 0xda, 0x44, + 0xe2, 0xc3, 0x08, 0xc0, 0x16, 0xd9, 0xaa, 0x36, 0xdd, 0x1b, 0xe2, 0x40, 0xf5, + 0x09, 0x3c, 0x88, 0x1c, 0x3e, 0x15, 0x1f, 0xd2, 0x04, 0xde, 0xfd, 0xc9, 0xe4, + 0x29, 0x02, 0x0d, 0xd0, 0x1f, 0x20, 0xff, 0x7a, 0xd9, 0xd2, 0x0f, 0xed, 0x05, + 0x43, 0x38, 0x18, 0xd1, 0xf6, 0x0e, 0x18, 0x0c, 0xb4, 0xef, 0xc0, 0xfd, 0xdb, + 0x41, 0x33, 0xa3, 0x2a, 0x10, 0x57, 0x52, 0x27, 0x54, 0x06, 0x0b, 0xe6, 0xf9, + 0xf6, 0xff, 0xef, 0xa6, 0x20, 0xbc, 0x34, 0xda, 0xfa, 0x20, 0xcf, 0x1a, 0x02, + 0xd0, 0xc4, 0xc3, 0xdd, 0x47, 0xe0, 0xb6, 0xbd, 0xe5, 0x48, 0x1a, 0x38, 0xa8, + 0x26, 0x14, 0x25, 0x08, 0xdc, 0xc8, 0xa5, 0xbe, 0x71, 0xc6, 0x81, 0x13, 0xb3, + 0xee, 0xcf, 0x19, 0xe4, 0x07, 0x08, 0x19, 0xae, 0xa0, 0x92, 0xab, 0x55, 0xc0, + 0xc6, 0xf3, 0xbf, 0x0d, 0xe3, 0x6b, 0xb3, 0xe4, 0xfa, 0x82, 0x58, 0x3b, 0xd9, + 0xb7, 0xef, 0xbb, 0x22, 0xdb, 0x1c, 0xc1, 0x14, 0xec, 0x08, 0xc7, 0x29, 0xca, + 0x71, 0x8c, 0xcf, 0xef, 0x69, 0xde, 0x4a, 0x68, 0xeb, 0x13, 0x07, 0xf9, 0x19, + 0x0a, 0xa4, 0x11, 0xf8, 0x1b, 0x28, 0x25, 0xea, 0x68, 0xea, 0xb8, 0xd2, 0x12, + 0xc4, 0xff, 0x27, 0xa4, 0xf1, 0xf6, 0x26, 0x4f, 0x43, 0xf8, 0xca, 0xf1, 0xf9, + 0xcf, 0xe7, 0xec, 0xe5, 0xfd, 0xc9, 0xdf, 0x41, 0x04, 0xe5, 0xef, 0xf8, 0xa7, + 0xf0, 0x00, 0xfd, 0x1c, 0xd0, 0xa7, 0xcc, 0x05, 0xc5, 0x03, 0x18, 0x15, 0xf5, + 0x03, 0xc2, 0x7f, 0xc2, 0x25, 0xf6, 0xcf, 0x1a, 0xe5, 0xf4, 0xda, 0x2b, 0x11, + 0x09, 0x21, 0xa8, 0x09, 0xde, 0x54, 0xcf, 0xc5, 0x05, 0x48, 0xf9, 0x06, 0x36, + 0xc5, 0xde, 0xdb, 0xc2, 0xd2, 0x3e, 0x17, 0x35, 0xee, 0x00, 0x17, 0xe7, 0xf8, + 0xf5, 0x1c, 0x03, 0x48, 0x2a, 0xff, 0x35, 0x32, 0x16, 0xfb, 0x1c, 0xf8, 0xea, + 0x07, 0xdf, 0x02, 0x47, 0x33, 0x16, 0x02, 0x11, 0xda, 0xef, 0x3c, 0x04, 0x1b, + 0xd0, 0xb7, 0x03, 0xf9, 0x04, 0x57, 0x45, 0xc8, 0xae, 0xf1, 0x1b, 0xfd, 0x40, + 0xf3, 0x24, 0xae, 0x11, 0xd4, 0x1a, 0x31, 0x16, 0x0f, 0x2a, 0x9d, 0xef, 0x26, + 0x0d, 0x07, 0x10, 0xfd, 0xc0, 0x4e, 0xfd, 0xe4, 0xb0, 0x28, 0xd3, 0xc0, 0xdc, + 0xf1, 0xed, 0xe9, 0x2d, 0x04, 0xd2, 0x13, 0x65, 0xfa, 0xd8, 0xe8, 0x30, 0x7f, + 0xdd, 0xf9, 0xfb, 0x63, 0x11, 0xcd, 0x1e, 0xf1, 0xc2, 0xc9, 0x3e, 0x8f, 0xf0, + 0x32, 0xd4, 0xf4, 0xaf, 0x03, 0xe7, 0x71, 0x20, 0x32, 0xe9, 0xb6, 0xfd, 0xed, + 0x42, 0x01, 0xb2, 0xef, 0xc2, 0xf8, 0xe8, 0xe4, 0xc9, 0x1a, 0xc1, 0x27, 0x6d, + 0xe9, 0x17, 0x24, 0xd0, 0x03, 0x24, 0xca, 0xd8, 0xd3, 0xf1, 0x0a, 0x09, 0xd9, + 0xfa, 0x0b, 0xe1, 0x20, 0xce, 0xe9, 0x29, 0x3a, 0xf7, 0xe9, 0xe8, 0xec, 0xfd, + 0x16, 0xf9, 0xee, 0xf1, 0xf4, 0xee, 0xd3, 0xda, 0x9f, 0xe2, 0xbb, 0xf4, 0x06, + 0x12, 0xf5, 0x04, 0xf4, 0x1a, 0xda, 0x4c, 0x25, 0x1a, 0xdd, 0x0d, 0x18, 0xc1, + 0xc4, 0x26, 0x1a, 0xdb, 0x13, 0xf9, 0x21, 0xf8, 0xf5, 0x51, 0xd3, 0x2f, 0xf2, + 0x4b, 0xb7, 0xfb, 0x2a, 0x1e, 0x1c, 0xdd, 0xea, 0x00, 0xce, 0x33, 0x2e, 0x02, + 0xde, 0x22, 0xf0, 0xe4, 0x0b, 0x2c, 0xf2, 0x7f, 0xaa, 0x20, 0x1b, 0x0a, 0x2d, + 0xe4, 0xfe, 0x36, 0xea, 0xe8, 0x1f, 0x1e, 0xe2, 0x3c, 0x0e, 0xcc, 0xf4, 0x05, + 0x2a, 0xd9, 0x11, 0x03, 0xda, 0xf9, 0xf9, 0x24, 0x00, 0x18, 0x10, 0x22, 0x2d, + 0xcf, 0x16, 0x24, 0x0f, 0x22, 0x2a, 0x02, 0xee, 0xe3, 0xd6, 0xf5, 0x5b, 0xf5, + 0x44, 0x09, 0xc3, 0xb4, 0xf0, 0x36, 0xe2, 0xb4, 0x0a, 0xea, 0x9b, 0xbf, 0xea, + 0x07, 0xd5, 0x53, 0xf4, 0x2a, 0x06, 0x1c, 0x1c, 0xe5, 0xf2, 0xdc, 0x0b, 0x0d, + 0x5d, 0x03, 0xf7, 0xcb, 0xe6, 0x16, 0xee, 0xe1, 0x17, 0x07, 0xb8, 0xe5, 0xe5, + 0x01, 0xeb, 0xe2, 0xec, 0xd8, 0x1a, 0xe7, 0x47, 0xd0, 0x11, 0x04, 0xf7, 0x29, + 0xe1, 0xfb, 0x0f, 0x45, 0xc7, 0x19, 0x36, 0xd1, 0xc3, 0xed, 0x2f, 0xd3, 0xee, + 0xbc, 0x00, 0xf0, 0xe6, 0xc6, 0x09, 0xe1, 0x17, 0x01, 0x2d, 0x10, 0xb4, 0x39, + 0x04, 0xc0, 0xda, 0x18, 0xde, 0xc9, 0xbf, 0x7f, 0x28, 0x05, 0x0e, 0x02, 0x35, + 0xfc, 0xf4, 0x39, 0xfa, 0xea, 0x22, 0x2e, 0xee, 0x29, 0xf8, 0x3e, 0x18, 0xe7, + 0x36, 0xe0, 0xf4, 0xbd, 0x0c, 0x33, 0x04, 0x0e, 0xfd, 0x39, 0x16, 0x0f, 0x13, + 0xc8, 0xc6, 0x13, 0xd6, 0x21, 0x4e, 0x0d, 0x0c, 0x0f, 0x35, 0x2d, 0x2e, 0x11, + 0x3c, 0x4c, 0x2d, 0x9a, 0x05, 0x10, 0x1f, 0xf2, 0xb7, 0xc2, 0xca, 0xe5, 0x02, + 0xc9, 0x19, 0xec, 0x34, 0x02, 0xd5, 0x4b, 0x15, 0xe9, 0x6e, 0xea, 0xda, 0xed, + 0x04, 0xd7, 0x20, 0xfa, 0xdd, 0xde, 0x17, 0x01, 0x13, 0x05, 0x18, 0x25, 0xc9, + 0x43, 0x19, 0x09, 0xbe, 0xe6, 0xfd, 0xda, 0xc4, 0xf1, 0xe8, 0xb7, 0x21, 0x5e, + 0x2b, 0x02, 0x34, 0x1c, 0x0c, 0x39, 0xb0, 0xff, 0xe3, 0x05, 0x00, 0x60, 0xf0, + 0x16, 0xf8, 0x0e, 0x2a, 0x9f, 0x31, 0x19, 0xc8, 0xcd, 0xd6, 0xd9, 0x28, 0x23, + 0xdb, 0x4d, 0x4e, 0xd8, 0xeb, 0xec, 0xc7, 0xcf, 0x37, 0xbc, 0x51, 0x64, 0x79, + 0xf5, 0x38, 0xfa, 0xeb, 0xf8, 0xd1, 0x5a, 0xc9, 0x00, 0x50, 0xe8, 0xe9, 0x0c, + 0xec, 0x30, 0x54, 0xdf, 0xfb, 0x5e, 0x17, 0xe9, 0x6d, 0x25, 0x53, 0xe2, 0xba, + 0xfb, 0xb0, 0xee, 0xda, 0xfb, 0x33, 0xaa, 0xcc, 0xe9, 0xd1, 0xeb, 0x0a, 0xbf, + 0x10, 0xd1, 0xdd, 0x08, 0x14, 0x12, 0x91, 0x3c, 0xd3, 0x14, 0xc2, 0xf4, 0x69, + 0xc9, 0xeb, 0x22, 0xfd, 0xfd, 0xe6, 0x19, 0x52, 0xfa, 0xd5, 0xe8, 0x06, 0xe2, + 0x04, 0xce, 0x81, 0x07, 0xa0, 0x37, 0x24, 0x1a, 0x03, 0xce, 0x18, 0x21, 0x44, + 0x1d, 0x37, 0xc1, 0xce, 0x3e, 0x38, 0xc7, 0xb7, 0xe6, 0xd5, 0x1e, 0xa5, 0xf1, + 0x5b, 0xdf, 0xf0, 0x50, 0x4e, 0xf6, 0x0a, 0x2d, 0x09, 0xec, 0xf6, 0x01, 0xab, + 0xde, 0xb5, 0x1f, 0xfc, 0xfc, 0x98, 0x05, 0x32, 0xcf, 0xd3, 0xd0, 0xcd, 0xc7, + 0x02, 0xc6, 0x01, 0x17, 0x05, 0x01, 0xe6, 0xd9, 0x10, 0xc5, 0x15, 0x17, 0x72, + 0x15, 0xe8, 0xdb, 0x41, 0x43, 0xff, 0xcf, 0xc9, 0xbf, 0xce, 0xf2, 0x08, 0x1c, + 0xd8, 0xf9, 0xc8, 0x2a, 0xc3, 0xf5, 0x26, 0xd1, 0x0a, 0xae, 0x55, 0x38, 0x6c, + 0xbc, 0xd6, 0xf7, 0x83, 0x0b, 0x51, 0x69, 0xed, 0x6e, 0x50, 0xb2, 0x28, 0xbf, + 0x5c, 0x1d, 0x37, 0x1c, 0x85, 0xec, 0x18, 0xf0, 0xba, 0x65, 0xdd, 0x05, 0xfd, + 0x18, 0xd8, 0x28, 0xdc, 0x26, 0xce, 0xce, 0xe6, 0x7f, 0x29, 0xbc, 0x51, 0x2d, + 0xff, 0x04, 0xbd, 0x01, 0xa9, 0xea, 0x24, 0xca, 0x0b, 0xf7, 0xe7, 0x19, 0x5b, + 0x1f, 0x12, 0x0a, 0xb5, 0xde, 0x20, 0x30, 0x39, 0xe4, 0xec, 0xb2, 0x30, 0xd3, + 0xc2, 0xc9, 0xb0, 0x03, 0xe6, 0x30, 0xe0, 0xed, 0x43, 0xd2, 0xd8, 0xfd, 0xfd, + 0xdd, 0x14, 0xfc, 0xfc, 0xf9, 0xee, 0x16, 0x15, 0x28, 0x07, 0x16, 0x1e, 0x19, + 0x40, 0x19, 0x28, 0xf9, 0x0c, 0xeb, 0x09, 0x1e, 0xf5, 0xec, 0xdd, 0x33, 0x15, + 0xf8, 0xe9, 0x0b, 0xd9, 0x16, 0x02, 0x00, 0x24, 0xdc, 0xe8, 0xda, 0x31, 0x08, + 0xe5, 0x0f, 0x1d, 0xf0, 0xf3, 0xd9, 0xe5, 0x0b, 0x0a, 0x16, 0x02, 0x0c, 0x9b, + 0xff, 0xf5, 0xf6, 0xe6, 0x31, 0x06, 0xf4, 0xf9, 0xca, 0xe0, 0x1e, 0xfc, 0xec, + 0x27, 0x3e, 0xd1, 0xd1, 0xf0, 0xda, 0x24, 0x1d, 0xd7, 0x15, 0xf5, 0xf2, 0xfe, + 0xfd, 0xdf, 0xf1, 0xdc, 0xc5, 0xec, 0xf4, 0x02, 0xe7, 0xea, 0x04, 0xda, 0x1c, + 0x14, 0x0a, 0xf9, 0x27, 0x13, 0xee, 0xf2, 0x12, 0x03, 0x12, 0x05, 0x7f, 0x0a, + 0xf4, 0xf9, 0xe0, 0x10, 0x09, 0x20, 0xf3, 0x14, 0xe5, 0x0c, 0x17, 0x15, 0xf5, + 0xd8, 0xf1, 0x38, 0x0e, 0x00, 0xf0, 0x34, 0x06, 0x15, 0x6c, 0x55, 0x16, 0xfa, + 0xeb, 0xd9, 0xb6, 0x28, 0x2b, 0xb9, 0x1b, 0x32, 0xd1, 0x50, 0x45, 0x81, 0x05, + 0x09, 0x02, 0xb6, 0xfb, 0xa8, 0x19, 0x62, 0xe4, 0xe0, 0x0f, 0xef, 0x4e, 0x37, + 0xd0, 0xeb, 0xd5, 0xb0, 0xa6, 0x54, 0xb7, 0xf8, 0xe9, 0xfd, 0x17, 0xdd, 0x3a, + 0x0c, 0x5a, 0xf2, 0x44, 0x01, 0xe6, 0xa6, 0x9d, 0x12, 0xb3, 0x20, 0xec, 0xb8, + 0xbb, 0x02, 0xdf, 0x0b, 0x16, 0x09, 0x02, 0x38, 0x3f, 0x04, 0x28, 0x49, 0x39, + 0x1c, 0x05, 0xff, 0xe1, 0x22, 0xcd, 0x1d, 0x09, 0xea, 0xca, 0xc2, 0xf2, 0xf8, + 0x1e, 0xf9, 0x93, 0x13, 0xe4, 0x46, 0x26, 0x08, 0xac, 0xe0, 0xcb, 0x96, 0x09, + 0x01, 0xff, 0xae, 0x10, 0xf8, 0x46, 0x22, 0x2b, 0xda, 0x1a, 0xd7, 0xef, 0xf2, + 0xc0, 0x33, 0xed, 0xa4, 0x20, 0xf8, 0xd9, 0x08, 0xc8, 0xec, 0x65, 0x13, 0x1c, + 0x05, 0x1c, 0xdc, 0x1b, 0xe5, 0x0b, 0x0d, 0x02, 0x0e, 0xca, 0x2d, 0xff, 0x24, + 0x00, 0x15, 0xfc, 0xea, 0x00, 0xf4, 0xfc, 0xfa, 0xe0, 0x04, 0x3c, 0xe1, 0x0c, + 0xfa, 0x42, 0xf9, 0xf5, 0x25, 0xeb, 0xb5, 0xfa, 0x0c, 0x32, 0x35, 0xcf, 0xf2, + 0xcc, 0xf5, 0x12, 0x1f, 0x0d, 0x1b, 0xc6, 0x25, 0xdb, 0xe6, 0xfb, 0xff, 0xcc, + 0xd9, 0xe3, 0xe9, 0xd4, 0xcf, 0x3e, 0xd5, 0x2c, 0x1c, 0x12, 0xfa, 0x39, 0xde, + 0xe1, 0xd3, 0x0d, 0xe9, 0x7f, 0x0b, 0xd5, 0x0e, 0xfc, 0xdf, 0xcc, 0xef, 0xf9, + 0x5a, 0xe2, 0xfc, 0xd9, 0xe2, 0xce, 0xe6, 0xf4, 0xa5, 0x12, 0x32, 0x13, 0xf4, + 0x29, 0x04, 0xec, 0xfd, 0x24, 0x1b, 0x01, 0xd8, 0x25, 0x18, 0x1e, 0xec, 0xef, + 0xa7, 0x20, 0x10, 0xe5, 0xf7, 0x02, 0xc0, 0xe0, 0x33, 0x10, 0x20, 0x2e, 0x3e, + 0xf6, 0x0d, 0xf3, 0x2f, 0xe4, 0xe3, 0x13, 0x2f, 0xcf, 0xd3, 0x29, 0xf1, 0xf6, + 0x02, 0x3b, 0xf7, 0xf5, 0xf8, 0xfa, 0xea, 0x0e, 0x46, 0x0e, 0xfe, 0xed, 0xe1, + 0x0a, 0x09, 0xea, 0x11, 0x16, 0xe3, 0xd6, 0xfc, 0x7f, 0xf6, 0xce, 0x26, 0xe7, + 0xef, 0xf4, 0xec, 0xff, 0xf0, 0xfe, 0x25, 0x28, 0x28, 0xdc, 0xd4, 0x15, 0x04, + 0xdd, 0x40, 0xce, 0x0e, 0xf8, 0x03, 0x20, 0x0a, 0xf9, 0x01, 0x15, 0x2d, 0xeb, + 0x08, 0x03, 0xd9, 0xe4, 0xc7, 0xfb, 0x24, 0x20, 0x14, 0xe4, 0x13, 0xfd, 0xd9, + 0xfb, 0xf7, 0x20, 0xd8, 0xdf, 0x11, 0xe7, 0x0e, 0xe1, 0xf6, 0xbe, 0xfd, 0xe8, + 0xef, 0x0b, 0xee, 0x02, 0x1b, 0x11, 0x06, 0x05, 0xf5, 0x14, 0x23, 0xf5, 0xf2, + 0xe9, 0x13, 0xca, 0x2c, 0x1c, 0xeb, 0xc8, 0x02, 0x04, 0xf3, 0xcd, 0x19, 0x25, + 0xbf, 0xe4, 0xed, 0x07, 0x0b, 0xea, 0x1a, 0x09, 0xec, 0xef, 0x1c, 0xd7, 0x0b, + 0x0a, 0xef, 0x22, 0x19, 0x02, 0x1c, 0xd2, 0xf6, 0xd1, 0xed, 0x4c, 0xfb, 0xf7, + 0x28, 0x20, 0x2e, 0x0b, 0xea, 0x03, 0x2b, 0x05, 0xde, 0xed, 0x00, 0x18, 0x73, + 0x26, 0xc4, 0x1e, 0x0e, 0xd5, 0xe2, 0x05, 0x15, 0xf8, 0x40, 0xd7, 0xe9, 0x45, + 0xdb, 0x01, 0xcf, 0x06, 0xfd, 0x09, 0xff, 0x0a, 0x17, 0xec, 0x81, 0xae, 0x0e, + 0xfd, 0x04, 0x20, 0xff, 0xe8, 0x7e, 0x25, 0x4d, 0xc3, 0xe9, 0x12, 0xfa, 0x16, + 0x12, 0x07, 0x0d, 0x42, 0x98, 0x00, 0x05, 0xdd, 0x00, 0x33, 0x0d, 0xe0, 0xfe, + 0xe8, 0xab, 0xa1, 0xf4, 0x10, 0x25, 0xd4, 0xf3, 0x1b, 0x03, 0x1a, 0x07, 0xff, + 0xc8, 0xf5, 0xf1, 0xf5, 0x8d, 0xea, 0xe2, 0x12, 0xc5, 0xe9, 0x5f, 0x2c, 0xd0, + 0x0c, 0xf2, 0x23, 0x2f, 0xf7, 0x0f, 0x21, 0x13, 0x1a, 0x15, 0x5b, 0x11, 0xf8, + 0xf3, 0xfa, 0xf7, 0xf8, 0x06, 0xf2, 0x36, 0xcc, 0x3e, 0x2c, 0xff, 0x12, 0x0c, + 0xf4, 0xfa, 0xf3, 0xfd, 0xf6, 0xdd, 0x06, 0x22, 0x0a, 0xa4, 0xdf, 0x1f, 0x28, + 0xf8, 0x42, 0xdf, 0xe9, 0x36, 0x19, 0xc6, 0x14, 0x27, 0xc6, 0x00, 0xeb, 0x04, + 0x0f, 0x2e, 0x41, 0xc0, 0xea, 0xab, 0xf4, 0xc9, 0x0e, 0xf5, 0xbb, 0x7d, 0xdd, + 0xdf, 0x48, 0x0e, 0x12, 0xe3, 0x2c, 0x4e, 0xe6, 0xd6, 0xfc, 0xd8, 0x44, 0xfe, + 0x17, 0x53, 0x0b, 0x0b, 0xfa, 0x2c, 0x37, 0x38, 0xea, 0x7f, 0x9d, 0x21, 0x24, + 0x13, 0x9f, 0x0b, 0xe0, 0xff, 0xc7, 0xbf, 0x21, 0xe3, 0x05, 0x1f, 0xff, 0xeb, + 0x8e, 0x2c, 0x30, 0xb6, 0xe5, 0x0c, 0xf7, 0x3f, 0x49, 0x07, 0x0d, 0xd2, 0xf1, + 0xd4, 0xfb, 0x0d, 0x0e, 0x06, 0x1b, 0xb5, 0x21, 0xcd, 0xfa, 0xe7, 0x00, 0x2a, + 0xea, 0x50, 0x40, 0x10, 0x36, 0x04, 0x40, 0xea, 0x28, 0x08, 0xf7, 0xfd, 0x08, + 0x18, 0xec, 0x07, 0xdb, 0x04, 0x2b, 0x48, 0x45, 0xd9, 0xc9, 0xf3, 0xf7, 0x03, + 0xdc, 0xc5, 0xf1, 0x1c, 0x37, 0xde, 0x02, 0x13, 0xf7, 0xa7, 0xc1, 0xfc, 0x07, + 0x20, 0xe0, 0xdb, 0x00, 0x02, 0x0b, 0xf0, 0x08, 0x3b, 0x11, 0x00, 0x03, 0x01, + 0x2d, 0x39, 0x0a, 0x3a, 0x07, 0x33, 0xfb, 0xd5, 0xca, 0xd3, 0x05, 0xfa, 0xe9, + 0x05, 0x1e, 0xea, 0xce, 0x20, 0x1a, 0xca, 0xbf, 0xed, 0xf8, 0xfb, 0xda, 0xfb, + 0x35, 0xef, 0x08, 0x22, 0xc5, 0x15, 0xe5, 0x34, 0xcf, 0x24, 0x0c, 0xe5, 0x08, + 0x8f, 0xf3, 0xec, 0xfb, 0xdb, 0x4b, 0xf3, 0xa4, 0x2b, 0xf6, 0xde, 0xfe, 0x07, + 0xcd, 0x26, 0x2d, 0x62, 0xf6, 0xd6, 0xde, 0xf7, 0x28, 0xe1, 0x7f, 0x39, 0xf1, + 0xe6, 0x08, 0x13, 0x08, 0x37, 0xf4, 0xf5, 0x06, 0x09, 0xf4, 0x4a, 0x1e, 0xed, + 0x3b, 0xd5, 0xf9, 0xec, 0x0e, 0xda, 0x17, 0xf8, 0x39, 0xf3, 0xff, 0xf7, 0xf2, + 0x38, 0x1a, 0xe2, 0x27, 0xb6, 0x03, 0x05, 0x0e, 0x2d, 0x17, 0x06, 0x28, 0x59, + 0xe1, 0xce, 0x53, 0x19, 0x1d, 0x5e, 0xc6, 0x01, 0xe4, 0x27, 0xfb, 0xf8, 0xeb, + 0xc9, 0xfc, 0xfa, 0x04, 0x02, 0xfe, 0x13, 0xef, 0x81, 0xf8, 0xed, 0x60, 0xf7, + 0x0d, 0x18, 0xb6, 0x05, 0x24, 0x1f, 0xfa, 0x19, 0xd9, 0xef, 0xcf, 0x17, 0xc8, + 0xeb, 0xd0, 0xf8, 0x03, 0x08, 0x17, 0x15, 0x17, 0xfa, 0x09, 0xdd, 0xc7, 0xc8, + 0x3d, 0x1f, 0x46, 0xda, 0xe7, 0x38, 0xdd, 0xf7, 0x0c, 0xcf, 0x02, 0xed, 0x01, + 0xc9, 0x02, 0x0a, 0x3f, 0xf2, 0xff, 0x19, 0xe2, 0x0f, 0x12, 0x09, 0xe1, 0xee, + 0x25, 0x1a, 0xae, 0xed, 0xf4, 0xe3, 0xea, 0x43, 0x06, 0xd7, 0x25, 0xe1, 0x45, + 0x23, 0x45, 0xee, 0x06, 0x02, 0x2e, 0x38, 0x24, 0xfb, 0xf8, 0x30, 0x23, 0xe3, + 0xeb, 0xf8, 0x28, 0x11, 0xe0, 0xf0, 0x07, 0xf7, 0x06, 0xf7, 0xe1, 0xf8, 0x00, + 0x52, 0x47, 0xeb, 0xf8, 0x0c, 0x0e, 0xfe, 0xd4, 0x17, 0xd4, 0xfb, 0x4b, 0xdc, + 0x1f, 0xf4, 0x05, 0x18, 0x0f, 0x9f, 0x16, 0xf2, 0xac, 0x81, 0xaf, 0x56, 0x57, + 0x11, 0xd1, 0x0b, 0x01, 0x3b, 0x0f, 0x1b, 0xe3, 0xe2, 0x16, 0x0b, 0xe0, 0xe4, + 0x0b, 0x32, 0x05, 0xd7, 0xe4, 0xdd, 0x03, 0x05, 0xf2, 0x01, 0xfd, 0xfe, 0x5a, + 0x1a, 0xd2, 0x10, 0x14, 0x25, 0x14, 0xe7, 0xce, 0xe4, 0x1f, 0x40, 0x07, 0xe0, + 0xb5, 0xd0, 0xfb, 0x0d, 0x22, 0x10, 0x42, 0x05, 0xdd, 0xaf, 0x9b, 0x3a, 0x07, + 0xff, 0xf4, 0x1a, 0xff, 0x1c, 0xc2, 0xd1, 0x83, 0x0c, 0xe5, 0x14, 0xf2, 0xb1, + 0x3a, 0x4a, 0xee, 0x0d, 0xeb, 0xd4, 0xb5, 0xcf, 0x1e, 0xd3, 0xdd, 0x0d, 0xe5, + 0xfa, 0x5c, 0x96, 0xf6, 0xe8, 0x40, 0xf1, 0x16, 0x00, 0x33, 0xd9, 0x03, 0xd6, + 0xee, 0x2b, 0x0c, 0x4d, 0x78, 0xea, 0xe0, 0xe9, 0xdc, 0x6d, 0x5c, 0xfc, 0xac, + 0xf9, 0x0b, 0x0b, 0x8f, 0x25, 0xaf, 0xdf, 0xf3, 0x3b, 0x0c, 0xd5, 0xcd, 0xfe, + 0x1f, 0xa3, 0x8d, 0xd7, 0x2c, 0x11, 0x03, 0x69, 0xd8, 0xf0, 0x03, 0x2a, 0x13, + 0x17, 0x29, 0xfb, 0xfa, 0xfc, 0xee, 0xc9, 0x12, 0xed, 0xe3, 0x1e, 0x7f, 0xf2, + 0x5d, 0xe5, 0x4f, 0xee, 0xb7, 0xce, 0x07, 0x0f, 0xea, 0x04, 0xfc, 0x08, 0x49, + 0x54, 0x06, 0x0d, 0xf4, 0x38, 0xef, 0x11, 0x1c, 0x26, 0xe8, 0x13, 0xae, 0xf6, + 0x10, 0xfa, 0x36, 0xfe, 0xbb, 0x2b, 0x26, 0xef, 0x00, 0xfb, 0xf8, 0xf8, 0x12, + 0x0b, 0x02, 0xff, 0xe3, 0x32, 0x03, 0xef, 0x45, 0xc6, 0xf5, 0xff, 0xf5, 0x0c, + 0x1c, 0xc3, 0x01, 0xdb, 0x05, 0xe4, 0xf4, 0x25, 0x13, 0x43, 0x0c, 0x03, 0x03, + 0x0c, 0xf2, 0x0d, 0x24, 0xdc, 0xcf, 0xf1, 0x14, 0x03, 0x0d, 0x18, 0x16, 0xbe, + 0x42, 0x21, 0xe9, 0x18, 0xce, 0xc8, 0x26, 0x12, 0x1e, 0xcb, 0xfe, 0xf0, 0xf4, + 0x05, 0xb8, 0x41, 0x02, 0xf7, 0xe9, 0xe1, 0xe7, 0xf8, 0xe9, 0x54, 0x0e, 0xbe, + 0x4c, 0xfe, 0xe2, 0x0b, 0xf0, 0xd9, 0xdf, 0x1d, 0x15, 0xe2, 0xfc, 0x5b, 0xf3, + 0xde, 0x35, 0x3e, 0xf9, 0x34, 0xf7, 0xee, 0xb3, 0x81, 0xc1, 0xc8, 0xef, 0x60, + 0xda, 0x34, 0xc9, 0xf5, 0xed, 0x18, 0xcf, 0xcc, 0xed, 0x0d, 0xf0, 0x2d, 0x34, + 0xbf, 0x0a, 0x00, 0x11, 0x14, 0xe4, 0x49, 0xea, 0x52, 0x23, 0xd7, 0x1d, 0xd2, + 0x03, 0x25, 0x2f, 0x2e, 0x57, 0x1f, 0xdf, 0xf7, 0x03, 0xda, 0xc4, 0xce, 0x33, + 0xe2, 0xc8, 0xf7, 0xcc, 0x1c, 0x06, 0x28, 0x22, 0x9f, 0xe4, 0xb1, 0x10, 0xea, + 0x1f, 0xef, 0x12, 0xd7, 0x05, 0xd9, 0x28, 0x52, 0x08, 0x06, 0x15, 0x42, 0x1d, + 0x12, 0x2f, 0x37, 0xee, 0xbb, 0xe1, 0xf1, 0xc0, 0x1d, 0xe6, 0xce, 0x0e, 0xb7, + 0x1d, 0x2f, 0xd4, 0x2a, 0xf5, 0xe6, 0xd9, 0xe2, 0x41, 0xd1, 0xe9, 0xa0, 0xe5, + 0xb2, 0xc8, 0x40, 0x85, 0xe5, 0x6d, 0x5d, 0x03, 0xd8, 0xf8, 0x01, 0xd7, 0x12, + 0xce, 0xdf, 0x0f, 0xbf, 0x28, 0x1d, 0xd1, 0xdd, 0x18, 0xc2, 0xcc, 0xe9, 0xaf, + 0xf4, 0x54, 0xee, 0xed, 0x10, 0x14, 0xe2, 0x2c, 0xb9, 0x03, 0xd5, 0xdb, 0xe3, + 0x70, 0xdb, 0xbc, 0x06, 0xc1, 0xe9, 0xf1, 0xf4, 0xd0, 0x21, 0x4c, 0x04, 0xed, + 0x1d, 0xe5, 0x1d, 0xda, 0xf7, 0x10, 0x14, 0xb4, 0xea, 0x51, 0xd8, 0xf4, 0x48, + 0x35, 0xdf, 0xf0, 0x04, 0x46, 0x0b, 0xff, 0x0d, 0x1d, 0x36, 0xbe, 0x19, 0xbd, + 0xfb, 0x4b, 0xed, 0x2d, 0xf4, 0x0d, 0xc1, 0xff, 0x17, 0xed, 0x2e, 0xdb, 0x3c, + 0xfe, 0x07, 0x47, 0x53, 0x2b, 0xf5, 0xc8, 0x2a, 0x1c, 0x21, 0x0c, 0x1d, 0xcd, + 0xe7, 0xdc, 0xf4, 0xf6, 0xf7, 0x2f, 0xd1, 0xd4, 0xf5, 0x1b, 0x18, 0xc4, 0x4d, + 0x17, 0xaf, 0xd5, 0xe0, 0xfc, 0xab, 0xb4, 0x17, 0x0c, 0x5a, 0x4f, 0xe7, 0x08, + 0x01, 0x7f, 0x0b, 0xcb, 0xeb, 0xff, 0xba, 0xf3, 0xe3, 0xf1, 0xed, 0xe7, 0xfe, + 0xf6, 0x10, 0x1c, 0x2c, 0x4b, 0x00, 0xab, 0xee, 0xf8, 0x07, 0xc9, 0x1c, 0x2e, + 0x0d, 0xd1, 0x18, 0x68, 0xb9, 0xca, 0xfa, 0xbb, 0xf9, 0xe7, 0x1d, 0x44, 0xd0, + 0x01, 0xf4, 0xfb, 0x01, 0xf3, 0xae, 0xb3, 0xb8, 0x04, 0x01, 0xf7, 0xfc, 0x13, + 0x0c, 0x14, 0x1c, 0x4f, 0xef, 0xd9, 0xfc, 0xdb, 0x00, 0x1a, 0xf3, 0xbc, 0xdd, + 0x09, 0x0a, 0xf5, 0x0b, 0xd8, 0xe8, 0xbf, 0xf0, 0xce, 0xda, 0x10, 0x01, 0xe6, + 0x0d, 0xe3, 0x25, 0xfd, 0x33, 0x41, 0xf2, 0xff, 0xce, 0xd8, 0x5f, 0x29, 0x25, + 0x33, 0xe3, 0xfd, 0xf0, 0xe9, 0x3f, 0xdd, 0x20, 0x31, 0x0e, 0x2f, 0x25, 0xf6, + 0xf8, 0xf1, 0xf9, 0x44, 0xc5, 0xd7, 0x22, 0xf7, 0x08, 0x81, 0xee, 0xfc, 0x30, + 0xf7, 0xdc, 0x17, 0xea, 0x21, 0x19, 0xaf, 0xf2, 0x4d, 0xbf, 0xd6, 0x40, 0xe0, + 0xd4, 0x27, 0x49, 0xc8, 0xe4, 0x5f, 0x33, 0xd1, 0x20, 0xe0, 0x09, 0xf7, 0xcd, + 0xd4, 0x1a, 0x1d, 0x30, 0x3b, 0xf1, 0x17, 0x0f, 0x4c, 0x50, 0xe5, 0xe1, 0xdd, + 0xf9, 0xd7, 0xbf, 0x35, 0xb9, 0xc0, 0x0e, 0x93, 0xfd, 0x00, 0x67, 0xd1, 0x0c, + 0x8d, 0xb9, 0x2a, 0x35, 0xd9, 0x15, 0x29, 0x3a, 0x2c, 0xeb, 0x3a, 0xf2, 0x15, + 0xee, 0x29, 0xfe, 0xd9, 0x22, 0xb0, 0xd7, 0x21, 0x16, 0x0d, 0x2a, 0xbd, 0x0a, + 0x0a, 0xfc, 0xad, 0xbd, 0xdb, 0xef, 0xc1, 0xe5, 0x22, 0xc7, 0xe1, 0x2f, 0xd2, + 0xf8, 0x2a, 0xfe, 0xdb, 0x54, 0x81, 0xc4, 0xfd, 0x00, 0x41, 0xf5, 0xe5, 0x22, + 0xdf, 0xcb, 0x09, 0xe2, 0x2b, 0xf6, 0x53, 0xe5, 0x19, 0xd8, 0x3b, 0xb2, 0x13, + 0x0f, 0xd0, 0xc8, 0x1c, 0xe0, 0x4d, 0x0d, 0xb9, 0x04, 0x06, 0x99, 0xb4, 0xe0, + 0xe8, 0xee, 0xf0, 0xe9, 0x4e, 0x79, 0x19, 0x1a, 0x02, 0x9a, 0x18, 0xfa, 0xf2, + 0xed, 0x11, 0xaa, 0xd6, 0xa9, 0xcd, 0xc8, 0xd1, 0x17, 0x37, 0x18, 0x2a, 0x18, + 0x15, 0xf9, 0xf4, 0x3f, 0xc5, 0x0d, 0x04, 0x35, 0x0e, 0xf9, 0xef, 0x04, 0x0b, + 0xd5, 0xf9, 0xf4, 0x03, 0x0a, 0xf2, 0x2a, 0xb5, 0xde, 0x2d, 0xff, 0xb5, 0xe2, + 0x4f, 0xfa, 0xdf, 0x11, 0x05, 0xda, 0xf7, 0xeb, 0xdc, 0x2d, 0xfc, 0xee, 0x00, + 0x1a, 0xfd, 0xf8, 0x0d, 0xfd, 0x07, 0x09, 0x1c, 0xad, 0x22, 0xd2, 0x12, 0xb3, + 0x02, 0x04, 0x0b, 0x0a, 0xc5, 0x16, 0x36, 0xff, 0xf1, 0x05, 0x10, 0xe3, 0xd8, + 0xab, 0xf3, 0xee, 0xf0, 0x0a, 0xf2, 0x0c, 0x23, 0x20, 0xfd, 0xbc, 0x09, 0x0e, + 0x0c, 0x43, 0x35, 0x00, 0xef, 0x19, 0xe9, 0xf4, 0xd1, 0xfb, 0xe7, 0xab, 0x1b, + 0xe8, 0x02, 0x08, 0x1d, 0xc7, 0x2e, 0x08, 0xf2, 0x12, 0xd8, 0x7f, 0xd9, 0x13, + 0xe4, 0x17, 0x03, 0xfa, 0xff, 0x47, 0xde, 0x38, 0xd6, 0x16, 0x11, 0x06, 0x0e, + 0x0c, 0x0f, 0x2e, 0x20, 0xdb, 0xeb, 0x02, 0xfa, 0xdf, 0x01, 0x29, 0x01, 0xf3, + 0x4d, 0xf0, 0xdc, 0x1c, 0xe9, 0x3e, 0xf3, 0x1e, 0xc6, 0xc1, 0xc5, 0xbf, 0xda, + 0x3b, 0xf8, 0x3f, 0x24, 0x22, 0xe7, 0xbb, 0xc5, 0x21, 0xfd, 0xf3, 0x12, 0x01, + 0xd0, 0xa4, 0x08, 0xb7, 0x1e, 0xe7, 0x0b, 0xea, 0x07, 0x05, 0xe1, 0xf0, 0xd2, + 0x12, 0xc6, 0xf4, 0xe1, 0x17, 0x2e, 0x24, 0xb0, 0x38, 0xf6, 0x4e, 0xe6, 0x03, + 0xbc, 0x17, 0x3f, 0xe0, 0xca, 0x33, 0x10, 0xf7, 0x1d, 0xf1, 0xfb, 0x0f, 0xc4, + 0x0e, 0x3a, 0xfb, 0xf0, 0xfa, 0x25, 0xfb, 0x10, 0x7f, 0xf1, 0x03, 0x41, 0xcb, + 0x29, 0xf8, 0x14, 0x35, 0x2f, 0x25, 0xfa, 0x23, 0xc8, 0xfb, 0xc3, 0x2c, 0xf3, + 0xf8, 0xdd, 0xf3, 0x1d, 0x0a, 0xfb, 0x0a, 0x09, 0xd2, 0x06, 0x18, 0x30, 0xfb, + 0x1a, 0xfe, 0xdf, 0xfa, 0xe0, 0xe4, 0x2b, 0xfb, 0xd8, 0x75, 0xfa, 0xe3, 0x1a, + 0x04, 0xb7, 0x3a, 0xde, 0xd1, 0xd9, 0xe6, 0xfd, 0xec, 0xf5, 0xc3, 0xf9, 0xe8, + 0xcb, 0x2d, 0x19, 0x47, 0x11, 0x2b, 0x2b, 0xf9, 0xf1, 0xb0, 0xa8, 0x35, 0x28, + 0x47, 0xf4, 0xf7, 0xe6, 0x11, 0xde, 0xfd, 0xf8, 0x0e, 0xed, 0xbb, 0x42, 0xf7, + 0x24, 0xd3, 0x10, 0xd2, 0x1c, 0x09, 0xe6, 0xf3, 0x0c, 0xfe, 0x1c, 0xfd, 0x11, + 0x0d, 0x3e, 0x0c, 0x2d, 0x13, 0x12, 0x05, 0x29, 0x03, 0x00, 0xbb, 0x15, 0x0c, + 0xd0, 0xce, 0xca, 0xef, 0xf8, 0x0c, 0xfd, 0xf2, 0x10, 0xcb, 0xc9, 0xfc, 0xc6, + 0x0b, 0xf3, 0x22, 0xd5, 0xd0, 0x11, 0xe4, 0x14, 0x0b, 0xc5, 0xbe, 0xdc, 0xf4, + 0x0b, 0xc6, 0xe0, 0xe9, 0x14, 0x98, 0x29, 0x0f, 0xb6, 0x05, 0xf8, 0xfe, 0xf0, + 0x0d, 0xf5, 0x25, 0xe7, 0x1e, 0xe7, 0xd9, 0xff, 0xe8, 0xe3, 0xf3, 0x05, 0x1e, + 0xe4, 0xed, 0x31, 0x08, 0xd7, 0x29, 0x24, 0xdd, 0x29, 0x25, 0x81, 0xff, 0x01, + 0xbb, 0x36, 0x30, 0x11, 0xc7, 0xfd, 0x57, 0x1a, 0x1c, 0x4b, 0x1b, 0x8a, 0xfb, + 0xfa, 0xd9, 0xef, 0x0e, 0x23, 0xe8, 0xf6, 0x58, 0x2b, 0x19, 0xa6, 0xe4, 0x1e, + 0xca, 0x3d, 0x0d, 0x47, 0xec, 0xe1, 0xcf, 0xe3, 0x29, 0xdd, 0xb5, 0xf7, 0xfe, + 0x25, 0xeb, 0x03, 0x09, 0xfa, 0xbb, 0xf2, 0xcb, 0x90, 0x2a, 0x2c, 0x63, 0x25, + 0xf7, 0xed, 0x46, 0x9b, 0xea, 0x1e, 0xfe, 0xe9, 0x00, 0x47, 0x24, 0xfc, 0x05, + 0xf0, 0xe3, 0x4b, 0xd9, 0xeb, 0xd3, 0x2b, 0xe6, 0x21, 0xf9, 0xe1, 0xec, 0xe6, + 0x8e, 0x16, 0xe2, 0x08, 0xe8, 0xf2, 0xe5, 0xef, 0x23, 0x2e, 0x90, 0x1b, 0xc7, + 0x09, 0xe5, 0x51, 0x09, 0x26, 0xd5, 0xd6, 0xf9, 0xfe, 0x81, 0x12, 0x48, 0x08, + 0xf5, 0x04, 0xda, 0xb4, 0x0f, 0xdb, 0xdb, 0x02, 0x48, 0x12, 0x06, 0x31, 0x29, + 0xdc, 0xad, 0xee, 0xf2, 0x3c, 0xa2, 0x13, 0xbb, 0xb1, 0x16, 0x94, 0x0e, 0x98, + 0xee, 0xdc, 0xca, 0xcd, 0xfb, 0x1f, 0x21, 0x35, 0xdb, 0xe1, 0x03, 0x10, 0xc5, + 0x3d, 0xdf, 0xe1, 0xee, 0xea, 0xad, 0x25, 0x10, 0xda, 0xc7, 0x37, 0xef, 0xcc, + 0xcb, 0xe9, 0x51, 0x35, 0x92, 0x9c, 0x02, 0xec, 0x55, 0x24, 0xf8, 0x1d, 0x00, + 0x03, 0x00, 0x46, 0x13, 0x20, 0x04, 0xcf, 0x1e, 0x28, 0xfe, 0x29, 0xf1, 0x3a, + 0x27, 0x18, 0x42, 0x64, 0x81, 0xf7, 0x1a, 0xd2, 0x4a, 0xbd, 0x54, 0xe5, 0xb9, + 0xbf, 0x11, 0xbb, 0xb5, 0x0b, 0xd1, 0x1b, 0x06, 0xef, 0x0e, 0x1b, 0xfd, 0x5e, + 0xe8, 0xfe, 0x06, 0x01, 0xeb, 0xa7, 0xe5, 0xc4, 0xcb, 0xf8, 0x02, 0xf6, 0xbc, + 0xfb, 0x24, 0x26, 0xc5, 0x36, 0x2f, 0xe2, 0xc0, 0xe9, 0xd3, 0xe5, 0x6c, 0x2e, + 0x02, 0xf0, 0xd1, 0xda, 0xe3, 0xdf, 0x1a, 0x1f, 0xcf, 0x15, 0x09, 0xee, 0xc8, + 0x6d, 0x09, 0xec, 0xeb, 0x26, 0xca, 0x0b, 0x18, 0xb9, 0x23, 0xea, 0x97, 0xe9, + 0x2b, 0xda, 0xf9, 0xf4, 0x89, 0xcd, 0xa5, 0xaa, 0xe4, 0xd0, 0xfd, 0x1e, 0xda, + 0xf2, 0x1a, 0xff, 0x59, 0x11, 0x16, 0xf8, 0xaf, 0x05, 0xca, 0x37, 0x32, 0xf0, + 0xe2, 0xcb, 0x0a, 0xca, 0xad, 0xbe, 0xbb, 0xb7, 0x54, 0xc2, 0x23, 0x06, 0xdc, + 0x0d, 0xed, 0x0c, 0xea, 0xbf, 0xc4, 0xb5, 0xd3, 0x8d, 0x60, 0xb6, 0x03, 0xc8, + 0x1e, 0x54, 0xcf, 0xec, 0xfd, 0x0d, 0x1e, 0x2e, 0x04, 0x18, 0xfc, 0x45, 0x02, + 0xd5, 0x55, 0xd8, 0x10, 0x46, 0x45, 0xe6, 0xc8, 0xd2, 0x21, 0x23, 0x67, 0x14, + 0x4d, 0xb8, 0xc0, 0x4e, 0x14, 0xf5, 0xd2, 0xfa, 0xfe, 0xdf, 0x19, 0x1b, 0x3f, + 0x17, 0xac, 0x0a, 0x09, 0xee, 0x0b, 0xb9, 0xea, 0xe1, 0xc8, 0x6f, 0x81, 0xda, + 0xfb, 0x42, 0xdb, 0x25, 0xd2, 0xe9, 0x31, 0x45, 0xf7, 0x15, 0x51, 0x96, 0xe8, + 0x27, 0x0b, 0x54, 0x2b, 0x9c, 0x15, 0xed, 0xc9, 0xdf, 0xc8, 0xc7, 0xe9, 0xf7, + 0xf8, 0xdd, 0x2e, 0xd4, 0xf3, 0x1d, 0x4d, 0xdf, 0xf1, 0x04, 0xf2, 0xce, 0x14, + 0x45, 0xf9, 0x1a, 0xd6, 0x01, 0xdc, 0xf3, 0xf5, 0xf9, 0xed, 0xd4, 0x02, 0x20, + 0x25, 0xe0, 0x02, 0xf4, 0x24, 0xb7, 0x3a, 0xb5, 0x38, 0xf6, 0x13, 0xfe, 0xc6, + 0x17, 0x27, 0xe7, 0xdc, 0x3d, 0xec, 0x07, 0xe1, 0xf9, 0x04, 0xca, 0xfc, 0x12, + 0xff, 0xf2, 0x05, 0x0e, 0x00, 0xdb, 0x22, 0xf0, 0x15, 0x5d, 0x1f, 0x0f, 0xeb, + 0x64, 0x1a, 0x7f, 0x1e, 0x01, 0xee, 0xb6, 0x0f, 0x09, 0x50, 0x15, 0x90, 0x1d, + 0x1d, 0xff, 0x0a, 0x03, 0xe6, 0x12, 0x58, 0xe6, 0x12, 0xdc, 0x1a, 0x4d, 0x07, + 0xe6, 0xcd, 0xce, 0x2d, 0xd5, 0xe8, 0xd9, 0x2b, 0x04, 0x1a, 0x28, 0xd5, 0x2b, + 0x95, 0xa7, 0x01, 0xd2, 0x28, 0xa2, 0x1b, 0xe7, 0x25, 0xc6, 0xe6, 0x2d, 0x09, + 0xa9, 0x20, 0x28, 0xac, 0x5e, 0xea, 0xf0, 0xe5, 0xeb, 0x09, 0xf6, 0xfe, 0x27, + 0xcc, 0x12, 0xe5, 0x05, 0x14, 0xde, 0x14, 0xe8, 0xe0, 0xf2, 0x0c, 0x20, 0x30, + 0x2e, 0xfc, 0x0a, 0xfc, 0xfb, 0xdb, 0xbd, 0xca, 0xe5, 0x0e, 0x26, 0x24, 0x1d, + 0xfb, 0xcd, 0xa2, 0x18, 0x19, 0x09, 0xf4, 0xa3, 0x14, 0xc2, 0xec, 0x9d, 0xe5, + 0x1a, 0xdb, 0x7c, 0xec, 0xe3, 0xd7, 0x00, 0xe4, 0x22, 0x0a, 0x02, 0xb1, 0x0e, + 0xd1, 0x1d, 0x10, 0x18, 0xd0, 0x51, 0x00, 0x2e, 0x02, 0x28, 0xda, 0xe0, 0xe6, + 0xc3, 0x5c, 0xb3, 0x26, 0xde, 0x0b, 0xab, 0xf5, 0x3d, 0x97, 0xf7, 0xd6, 0xeb, + 0xc2, 0xf4, 0xca, 0xd9, 0x1e, 0x17, 0x3f, 0xde, 0xb7, 0xdb, 0x46, 0x15, 0xd1, + 0x19, 0xb4, 0xe0, 0xe9, 0xf6, 0xee, 0xf8, 0xe3, 0xdc, 0xe3, 0xfc, 0x4d, 0x01, + 0x10, 0xf1, 0x17, 0x11, 0x0a, 0xc6, 0x9f, 0x23, 0x7f, 0xf7, 0x0c, 0x25, 0xfa, + 0xe6, 0x28, 0xff, 0x0c, 0xd5, 0x01, 0x5b, 0xb7, 0x0d, 0xe3, 0x19, 0x31, 0x1d, + 0x0e, 0x04, 0xd9, 0x13, 0xd7, 0xcf, 0xc0, 0x1c, 0x01, 0x06, 0xe1, 0x56, 0x03, + 0x60, 0x61, 0xa9, 0xf5, 0xec, 0x16, 0x0c, 0xe2, 0x09, 0xfe, 0x41, 0x1b, 0x3d, + 0x2c, 0xcd, 0xb6, 0x24, 0x1c, 0xcd, 0x4b, 0xdf, 0x5d, 0xe2, 0x37, 0x3a, 0xfd, + 0x25, 0xe3, 0xa2, 0xcd, 0x22, 0xff, 0x7f, 0xb5, 0xfd, 0xfb, 0x00, 0xdf, 0x30, + 0xdd, 0x4b, 0x4e, 0x26, 0xfe, 0xda, 0x23, 0xe3, 0x37, 0x19, 0xd9, 0x1e, 0xe0, + 0x05, 0xe2, 0xda, 0xee, 0xd6, 0xef, 0xf7, 0xb7, 0x07, 0x05, 0xfa, 0xc9, 0x1e, + 0x00, 0xeb, 0xf3, 0x11, 0x12, 0xe7, 0xda, 0x28, 0x83, 0xd7, 0xf5, 0x04, 0xf8, + 0xa8, 0x14, 0x4b, 0xe6, 0x09, 0xfe, 0x34, 0xb9, 0x18, 0x49, 0xd8, 0xcf, 0xf3, + 0xdf, 0x0c, 0x07, 0xef, 0x21, 0xd3, 0xd5, 0x66, 0xd9, 0x08, 0xdc, 0x0e, 0x0c, + 0x21, 0xf2, 0xd6, 0x0c, 0xc5, 0xdd, 0x13, 0xd0, 0xff, 0x57, 0xba, 0xe5, 0x24, + 0xc3, 0xd0, 0x2e, 0x07, 0xfe, 0x5d, 0x0f, 0x14, 0x5b, 0xde, 0x11, 0x4b, 0xee, + 0xf1, 0xd5, 0xd0, 0xf9, 0x14, 0x05, 0x88, 0xf9, 0x08, 0x0d, 0xbe, 0x0f, 0xf0, + 0x17, 0x1c, 0x08, 0xf4, 0x32, 0x14, 0x93, 0xd3, 0xda, 0x94, 0x0f, 0xf6, 0x38, + 0x07, 0x1e, 0x11, 0xc1, 0xdc, 0xdb, 0xd7, 0xf3, 0x31, 0xfb, 0x22, 0x06, 0xe2, + 0x01, 0xc1, 0xf6, 0x10, 0x17, 0xb9, 0x27, 0xf8, 0xfa, 0x0c, 0xdc, 0xb7, 0xe5, + 0x05, 0x28, 0x2b, 0xce, 0xeb, 0x3b, 0x2c, 0xb7, 0xfd, 0x27, 0xf8, 0xfe, 0x9e, + 0x31, 0xf2, 0x81, 0x05, 0xf3, 0xef, 0x1e, 0x05, 0x19, 0x07, 0xb3, 0xd2, 0xf9, + 0xfe, 0xa3, 0x16, 0x07, 0xdf, 0xf7, 0x62, 0xec, 0x20, 0xee, 0xe2, 0x0f, 0xf8, + 0x12, 0xe4, 0x06, 0xd3, 0xd7, 0x44, 0x17, 0x03, 0xbb, 0x0b, 0xee, 0xff, 0xf0, + 0xfb, 0x26, 0xe8, 0x39, 0xdd, 0x0e, 0x02, 0xe1, 0x07, 0x27, 0x09, 0x03, 0x28, + 0x01, 0xe3, 0xb0, 0xf8, 0xf5, 0x30, 0x0c, 0x57, 0x02, 0x01, 0xbe, 0xb8, 0x1b, + 0x25, 0x0b, 0x53, 0x17, 0x1c, 0xeb, 0x22, 0x1a, 0xaf, 0xdf, 0xd3, 0x3f, 0x07, + 0x04, 0x2c, 0xe0, 0x15, 0x29, 0x02, 0xc4, 0xf8, 0xbc, 0xaa, 0x16, 0xf7, 0xce, + 0xfa, 0x01, 0x53, 0x0a, 0x15, 0xdb, 0x27, 0xa8, 0xfc, 0x03, 0x08, 0xc5, 0x22, + 0xeb, 0xf1, 0xfe, 0x2a, 0xf5, 0xaa, 0x41, 0xcb, 0x4a, 0x22, 0xfb, 0x38, 0xc3, + 0x2c, 0xd4, 0xec, 0xfc, 0x25, 0xfe, 0xfe, 0x32, 0xe3, 0xd4, 0x12, 0x06, 0xf7, + 0xec, 0x19, 0x63, 0x3a, 0x81, 0xf5, 0x30, 0xfe, 0xe9, 0xe5, 0x04, 0xeb, 0xd2, + 0x13, 0x3a, 0x36, 0xeb, 0x13, 0x18, 0x16, 0x16, 0x0d, 0xe4, 0xfa, 0x1e, 0xe3, + 0xe9, 0x10, 0xfd, 0x22, 0x25, 0xf2, 0xe1, 0x1d, 0xf9, 0x04, 0x10, 0xc2, 0x01, + 0x0f, 0x1a, 0x15, 0xc0, 0x04, 0x81, 0xe5, 0x44, 0x02, 0xa2, 0xe6, 0x40, 0xf3, + 0x84, 0x21, 0xff, 0xb4, 0x30, 0xde, 0x4c, 0x26, 0x12, 0x1b, 0x4b, 0xe7, 0x11, + 0x6f, 0xb5, 0x6d, 0x1e, 0xe4, 0x06, 0xf3, 0x12, 0x0a, 0xf5, 0x0a, 0xd8, 0x17, + 0x5c, 0xcd, 0x7d, 0xd5, 0xc7, 0x94, 0xf4, 0x30, 0x31, 0x02, 0x28, 0xd6, 0x22, + 0xf5, 0x07, 0xc0, 0xd6, 0x29, 0xdb, 0x2b, 0x4d, 0x3b, 0xf6, 0xf7, 0x72, 0x46, + 0xe2, 0xec, 0xd8, 0xc5, 0x3f, 0xbc, 0x30, 0xfd, 0xdd, 0x22, 0xaa, 0x15, 0xf9, + 0xb3, 0xd6, 0x3f, 0xf2, 0x07, 0x44, 0xf5, 0xf7, 0x22, 0xe5, 0x28, 0xf4, 0xf9, + 0xc9, 0x93, 0x40, 0x4b, 0xf6, 0x19, 0x54, 0xc2, 0x18, 0xde, 0xe1, 0xde, 0x7e, + 0x34, 0xbe, 0x09, 0xdf, 0x11, 0x06, 0x1b, 0xbc, 0xf8, 0x2f, 0xde, 0x50, 0xd6, + 0xa9, 0x2b, 0x17, 0x03, 0xab, 0x23, 0x3d, 0x11, 0x54, 0xd5, 0xdd, 0xb7, 0x08, + 0x23, 0x23, 0x16, 0xf4, 0x13, 0xe6, 0x39, 0xd8, 0xf7, 0x0e, 0x3b, 0xf6, 0xb0, + 0xa9, 0xfc, 0x12, 0xa6, 0xf0, 0xfe, 0x3f, 0x07, 0xfd, 0xcf, 0xd5, 0xbc, 0x18, + 0xef, 0x2b, 0x43, 0x19, 0x04, 0xb3, 0xb2, 0xf9, 0x05, 0xff, 0x0f, 0x0f, 0x01, + 0xfe, 0xeb, 0xfa, 0x1b, 0xd3, 0x0b, 0x0b, 0x02, 0xe8, 0x1d, 0x29, 0xdf, 0xfb, + 0xc4, 0x25, 0xf5, 0x02, 0x14, 0xe2, 0x0f, 0x46, 0x11, 0x0c, 0x15, 0x09, 0xf7, + 0x08, 0x0c, 0x99, 0x17, 0xe9, 0xd4, 0x1a, 0x17, 0xef, 0x02, 0x37, 0x01, 0x01, + 0xd9, 0x81, 0x0c, 0x40, 0x28, 0xeb, 0x1a, 0xf6, 0xff, 0xdb, 0xf5, 0xce, 0xd2, + 0x24, 0xc9, 0x1a, 0x17, 0x08, 0x44, 0xee, 0x2e, 0x4e, 0x0d, 0x19, 0x0d, 0xb7, + 0xfa, 0xd0, 0xda, 0xe2, 0xdb, 0x12, 0x4f, 0xe1, 0x40, 0x2d, 0x33, 0x03, 0xe2, + 0xd2, 0xe1, 0xd4, 0x2b, 0xe3, 0xc1, 0x00, 0x75, 0x02, 0x30, 0x31, 0xf9, 0x07, + 0x07, 0xe6, 0x3d, 0x3a, 0xc4, 0x13, 0x0c, 0xe1, 0x0d, 0xc2, 0xf7, 0xb5, 0xf7, + 0xc1, 0xce, 0xbb, 0x15, 0xed, 0xa3, 0xf4, 0x12, 0xd9, 0x0c, 0xeb, 0x17, 0x8d, + 0xe5, 0x2a, 0x87, 0x01, 0xae, 0xe5, 0x1a, 0xf0, 0xf1, 0x05, 0xff, 0x04, 0xfd, + 0x2d, 0xee, 0x3f, 0x04, 0x4c, 0x2b, 0xc2, 0xd3, 0x03, 0xc4, 0x20, 0x7f, 0x2b, + 0xd5, 0x1f, 0x04, 0xf6, 0x02, 0x21, 0xfc, 0xd2, 0xd8, 0xf6, 0xec, 0xeb, 0x12, + 0xcd, 0xed, 0x10, 0xd7, 0xf7, 0x24, 0xf4, 0x22, 0x0b, 0xea, 0x07, 0xf5, 0x0d, + 0x1c, 0x28, 0x0b, 0xbc, 0xe0, 0xca, 0x00, 0x39, 0x1b, 0xf8, 0x32, 0x08, 0xfd, + 0x18, 0xf4, 0xeb, 0xf0, 0xfb, 0x0d, 0xfd, 0xeb, 0x11, 0x0a, 0xd4, 0xe7, 0xc8, + 0xd1, 0x47, 0x23, 0xe7, 0x1f, 0x24, 0xaf, 0xf7, 0xff, 0xe0, 0xf8, 0xef, 0x30, + 0xbe, 0xe7, 0x05, 0x03, 0x09, 0x37, 0xef, 0xe0, 0x19, 0xd3, 0x06, 0x12, 0xa2, + 0x19, 0xf4, 0xe0, 0xe4, 0x24, 0xe9, 0x4d, 0xec, 0xfb, 0xf8, 0xe0, 0x19, 0xf4, + 0x61, 0xe3, 0x65, 0x03, 0x0d, 0x82, 0x10, 0x14, 0x16, 0x7f, 0xa3, 0x08, 0x1f, + 0x29, 0x32, 0x1f, 0x13, 0xe0, 0x08, 0xf1, 0x03, 0x14, 0x20, 0xfa, 0x1f, 0xe8, + 0xca, 0x28, 0x07, 0xdd, 0x01, 0xc2, 0x16, 0xd9, 0x0b, 0xe8, 0x43, 0x10, 0x01, + 0x24, 0x21, 0x31, 0x48, 0xd3, 0x0d, 0x07, 0xd7, 0x42, 0xfe, 0xe5, 0x41, 0xd2, + 0x04, 0x02, 0x1c, 0xb4, 0xd8, 0xb2, 0xde, 0xeb, 0x51, 0x50, 0xc5, 0xcf, 0x00, + 0xd4, 0x01, 0x2f, 0xc3, 0xdf, 0xbc, 0xfc, 0xe2, 0xf3, 0x26, 0xfc, 0x40, 0x42, + 0x2d, 0xc0, 0xbb, 0xef, 0xe1, 0xeb, 0x13, 0x15, 0xa0, 0x15, 0x5a, 0xee, 0x09, + 0xfe, 0xe6, 0x38, 0x0c, 0x97, 0xe2, 0x3b, 0xca, 0xc2, 0xf6, 0x2e, 0x17, 0xf2, + 0xf6, 0x29, 0x00, 0xe7, 0x34, 0x58, 0x26, 0xe2, 0x1f, 0x21, 0x1c, 0x14, 0x0a, + 0xe6, 0x06, 0xe6, 0xd0, 0xf4, 0x05, 0x1a, 0x1a, 0xf0, 0xc8, 0x25, 0x0e, 0xf3, + 0xee, 0xb3, 0xc7, 0xee, 0xf7, 0xe2, 0xf5, 0xfe, 0xea, 0xbb, 0x39, 0x0d, 0xf4, + 0x1f, 0x09, 0x29, 0xff, 0xde, 0xd4, 0xd1, 0x06, 0xdd, 0xf7, 0x10, 0xf3, 0x3b, + 0x21, 0xd5, 0x03, 0xf2, 0xf9, 0x00, 0xe0, 0xdc, 0xec, 0x1c, 0xf4, 0x08, 0x34, + 0x7f, 0x17, 0xee, 0x0c, 0xdd, 0x2b, 0x18, 0xb1, 0x33, 0xe1, 0xc9, 0xf4, 0xe0, + 0x07, 0xef, 0xd3, 0xd5, 0x11, 0x3d, 0x15, 0x0c, 0x3c, 0x02, 0x00, 0x25, 0xf9, + 0xf1, 0xe2, 0xd6, 0xf2, 0xff, 0x50, 0x23, 0x24, 0x0d, 0xea, 0xf0, 0x3f, 0x08, + 0xf7, 0xeb, 0x38, 0xec, 0xfe, 0xe2, 0xce, 0xdf, 0xf1, 0x10, 0x14, 0x31, 0x01, + 0xea, 0xed, 0xeb, 0x07, 0xf1, 0x3f, 0x0f, 0x0b, 0x0b, 0xea, 0x26, 0x02, 0x19, + 0x0e, 0x1d, 0x27, 0xbd, 0x39, 0x03, 0x02, 0xd4, 0xc4, 0xe0, 0x2a, 0x19, 0x08, + 0x04, 0x2e, 0xde, 0x0d, 0x2c, 0x0e, 0x01, 0x33, 0xdf, 0x1e, 0xfc, 0xeb, 0xfb, + 0x09, 0xbf, 0xf0, 0xf9, 0x1a, 0xe4, 0xd8, 0x16, 0x01, 0xc1, 0x98, 0xec, 0xeb, + 0xe7, 0x37, 0x19, 0xd3, 0x15, 0x0b, 0x11, 0x23, 0x02, 0x04, 0xef, 0x1a, 0x52, + 0xfa, 0x2a, 0x34, 0xf9, 0x0b, 0x14, 0xc0, 0xf8, 0xd9, 0xfb, 0x24, 0xba, 0x2c, + 0x09, 0x2a, 0xb0, 0xef, 0x45, 0xb4, 0x1f, 0xff, 0x3c, 0x0a, 0x08, 0xfe, 0xf7, + 0x0f, 0x32, 0xcc, 0xbd, 0xc1, 0xf0, 0x0c, 0xd0, 0x08, 0x06, 0xfe, 0xf6, 0xde, + 0x3c, 0x01, 0xb9, 0x1a, 0x35, 0x0e, 0x26, 0x00, 0xdc, 0xe9, 0xcd, 0x1d, 0xe1, + 0x11, 0x81, 0x2d, 0x20, 0xcd, 0x24, 0xc5, 0xfc, 0xe5, 0x00, 0xed, 0xe1, 0x3e, + 0xf4, 0x1c, 0x0c, 0xe0, 0xe7, 0x12, 0x17, 0x1d, 0xed, 0xe9, 0x18, 0xa9, 0xe2, + 0xe8, 0xea, 0x44, 0x49, 0x13, 0x13, 0xc1, 0x12, 0xcb, 0x2b, 0xea, 0x1a, 0x22, + 0x35, 0x28, 0x27, 0xd5, 0x2d, 0xfb, 0xfd, 0x42, 0x5c, 0xee, 0x68, 0x0e, 0xeb, + 0xea, 0x2d, 0x46, 0xee, 0x3d, 0x7d, 0x07, 0x02, 0xf8, 0xe8, 0xf1, 0xe5, 0x02, + 0x0a, 0xe5, 0xf4, 0x09, 0xed, 0x6d, 0x31, 0x89, 0xf0, 0xea, 0xf2, 0xce, 0x0e, + 0x18, 0x09, 0x10, 0x41, 0xd8, 0x12, 0x0c, 0xd4, 0x08, 0x2e, 0x81, 0x33, 0x0d, + 0x54, 0xf5, 0x25, 0xb9, 0xc2, 0x12, 0xf7, 0xe1, 0x2c, 0x0f, 0x36, 0xea, 0x28, + 0x28, 0x10, 0x19, 0xfc, 0x07, 0x2a, 0xff, 0xf5, 0x0f, 0xed, 0x04, 0x1c, 0x0c, + 0xf5, 0x2d, 0xca, 0x18, 0x14, 0x19, 0x0d, 0x39, 0xaf, 0x05, 0x0f, 0xe9, 0xf7, + 0xd6, 0xef, 0xc8, 0x4a, 0xe8, 0x55, 0x03, 0xbb, 0xff, 0xe3, 0xda, 0xf8, 0xe3, + 0x28, 0x8c, 0x1a, 0x0e, 0x15, 0x7c, 0x04, 0x0f, 0xfe, 0x34, 0xe5, 0xe9, 0xf5, + 0xfc, 0xbd, 0xe3, 0x24, 0x2a, 0x44, 0xf1, 0xb5, 0xe5, 0x10, 0xde, 0x0c, 0xe6, + 0xd7, 0xe4, 0xdc, 0x83, 0xa2, 0xe5, 0xc3, 0x41, 0xeb, 0x13, 0xc3, 0xf4, 0x1e, + 0xff, 0x25, 0xb9, 0x11, 0x54, 0x53, 0xf9, 0x36, 0xd5, 0xf6, 0xf8, 0xe7, 0x1b, + 0xe0, 0x0b, 0xeb, 0xef, 0x27, 0x16, 0x40, 0x0b, 0x11, 0x4a, 0x00, 0x2a, 0xb8, + 0x02, 0x4a, 0x71, 0x05, 0xaf, 0x01, 0x30, 0x07, 0xda, 0xe8, 0xd4, 0xd9, 0xbb, + 0xff, 0x36, 0xe5, 0xe0, 0x0c, 0xcb, 0x4e, 0x2d, 0xe5, 0xd5, 0x19, 0x0e, 0x2f, + 0x28, 0xe2, 0x3a, 0xbd, 0xbd, 0xe9, 0x13, 0xed, 0x15, 0x17, 0xdf, 0x03, 0x67, + 0xfb, 0x28, 0xd3, 0x3f, 0x1e, 0xce, 0x59, 0xf0, 0x56, 0x58, 0xdc, 0x28, 0x1a, + 0xcc, 0xb4, 0xce, 0x36, 0xf3, 0x31, 0xde, 0xe5, 0xd8, 0xf3, 0x0c, 0x1f, 0x54, + 0xe3, 0xf1, 0x7f, 0x23, 0x0a, 0x62, 0x08, 0x34, 0xd0, 0xf9, 0xc2, 0x0a, 0xf4, + 0x53, 0x0a, 0x17, 0x20, 0xf7, 0x05, 0xfa, 0x78, 0xd8, 0xc1, 0xfd, 0x1b, 0xf4, + 0x81, 0xa5, 0xe4, 0x16, 0xdc, 0xec, 0xf1, 0xff, 0x02, 0xf4, 0x1e, 0xe7, 0xc8, + 0x00, 0x13, 0x0d, 0x26, 0x24, 0xf0, 0xdd, 0x22, 0xfc, 0x2f, 0x12, 0x08, 0xe9, + 0x04, 0x02, 0xee, 0xf4, 0xe2, 0x1d, 0x24, 0xdb, 0xfc, 0x2e, 0xb7, 0x15, 0xb3, + 0x1f, 0xf6, 0x5b, 0x14, 0xc7, 0xbc, 0xcb, 0x65, 0x00, 0xd4, 0x37, 0xde, 0x1b, + 0xe3, 0x07, 0x33, 0xb6, 0x25, 0x11, 0x36, 0x48, 0x0c, 0x1f, 0x11, 0xfa, 0xf9, + 0xd2, 0xdd, 0xdc, 0x14, 0x05, 0xff, 0x3a, 0x3f, 0x18, 0x4b, 0xf3, 0xed, 0xd0, + 0xb4, 0x01, 0xde, 0xdc, 0xfb, 0x07, 0x00, 0xf6, 0x27, 0xf7, 0xd1, 0x38, 0x0b, + 0xf3, 0xbb, 0x1d, 0x1c, 0x23, 0x0e, 0xf9, 0xb9, 0xa5, 0x20, 0x0c, 0x00, 0xcb, + 0x02, 0xfe, 0xf7, 0xf7, 0xfc, 0x55, 0xd6, 0xd7, 0x4d, 0xeb, 0xfc, 0xee, 0x0c, + 0x02, 0x20, 0x05, 0xcc, 0xfb, 0xfa, 0xed, 0x23, 0xd8, 0xca, 0x08, 0xfa, 0x81, + 0xfb, 0xc2, 0xf2, 0x1f, 0xa1, 0xe1, 0x3a, 0xe7, 0x0e, 0xf9, 0xfa, 0xd2, 0xec, + 0x04, 0x37, 0x40, 0x18, 0x46, 0x13, 0xd4, 0x0e, 0x24, 0xe7, 0xfc, 0x26, 0xe1, + 0x17, 0x33, 0x21, 0x0f, 0xc4, 0xef, 0xf1, 0xde, 0xda, 0xb9, 0x2f, 0x11, 0x2c, + 0xd5, 0xef, 0xec, 0x26, 0x1a, 0xf0, 0xd9, 0xe9, 0xeb, 0xf1, 0x00, 0x05, 0xd9, + 0xdd, 0xc6, 0xaa, 0xdb, 0x0b, 0x23, 0xd8, 0x22, 0x12, 0x04, 0x0e, 0x0e, 0x10, + 0xfb, 0xd6, 0xf4, 0xd3, 0x19, 0xe4, 0x31, 0xcd, 0xeb, 0xba, 0xd9, 0xfa, 0xe0, + 0xcb, 0x0e, 0x1c, 0x11, 0x0e, 0x2f, 0xf9, 0xe9, 0xed, 0xc4, 0xcb, 0xec, 0xd9, + 0x01, 0xf3, 0x3f, 0x1d, 0x11, 0xfa, 0x52, 0x14, 0x35, 0x33, 0xee, 0x29, 0xda, + 0x18, 0x14, 0xf3, 0xcc, 0xe3, 0x10, 0x81, 0xc6, 0xd0, 0x31, 0x47, 0xe0, 0xe6, + 0xf1, 0x02, 0x54, 0x02, 0x76, 0x09, 0x05, 0x29, 0x23, 0xd3, 0xd4, 0xfb, 0x1c, + 0x4f, 0xdc, 0x45, 0xd6, 0x1b, 0xf4, 0x50, 0x17, 0x63, 0x0e, 0x40, 0x44, 0xe0, + 0xe3, 0x09, 0x1c, 0xeb, 0x2b, 0x16, 0x09, 0xc6, 0xd8, 0x31, 0x11, 0x06, 0x37, + 0x34, 0x3f, 0xde, 0x27, 0x3e, 0xd8, 0xd1, 0xd1, 0xb0, 0x9d, 0x3a, 0xed, 0x0d, + 0x23, 0x10, 0xc6, 0x0e, 0xc6, 0xf9, 0x39, 0x17, 0x65, 0x02, 0xff, 0x14, 0xd5, + 0x02, 0xff, 0x28, 0x2c, 0x0a, 0x2c, 0xf9, 0xf1, 0x0c, 0x1c, 0x13, 0xe6, 0x06, + 0x00, 0x11, 0x13, 0xf7, 0x3a, 0xc9, 0xc0, 0x1b, 0xd7, 0x10, 0x18, 0xf5, 0x1d, + 0x78, 0xfe, 0x1a, 0x26, 0x19, 0xdf, 0xf3, 0xcd, 0x02, 0xe2, 0xfa, 0x26, 0x07, + 0x13, 0x07, 0x42, 0xe8, 0x0f, 0xe2, 0xf7, 0xca, 0xdd, 0x4d, 0x49, 0x40, 0x11, + 0xc6, 0x42, 0xb8, 0xe8, 0x03, 0xdd, 0x0b, 0x14, 0x2a, 0x2a, 0x3e, 0x18, 0xac, + 0xb3, 0xef, 0x1c, 0xef, 0xfc, 0xed, 0x0e, 0xfb, 0xf8, 0x14, 0x7f, 0x39, 0x8a, + 0x03, 0xe8, 0x5e, 0xdb, 0xd4, 0x5c, 0x02, 0x02, 0x39, 0xf6, 0xa4, 0xc7, 0xd4, + 0x28, 0xf3, 0xd2, 0xf9, 0xf8, 0xf9, 0x9f, 0xff, 0xb0, 0x28, 0xdb, 0x11, 0xe3, + 0xd1, 0xf6, 0xd0, 0x0f, 0x41, 0x26, 0x11, 0xe4, 0x1b, 0xed, 0xac, 0x33, 0x42, + 0x14, 0x45, 0x16, 0x0f, 0x09, 0x3b, 0xb3, 0x45, 0xeb, 0xb3, 0x3a, 0x00, 0xe9, + 0xcc, 0x37, 0xd4, 0x26, 0x10, 0xf7, 0xfd, 0xc1, 0x0d, 0x2d, 0xe4, 0x01, 0xbb, + 0x1b, 0x2e, 0x23, 0xe5, 0xf9, 0xec, 0xda, 0xc7, 0x0c, 0xee, 0xf9, 0xd6, 0xf9, + 0xd9, 0xf4, 0x4a, 0x30, 0xd6, 0xf3, 0xe7, 0x4c, 0x3b, 0x4b, 0x02, 0x05, 0x19, + 0x24, 0x0b, 0xa8, 0x02, 0x44, 0xff, 0x22, 0x25, 0xb8, 0x3b, 0x59, 0x9c, 0x1e, + 0xc4, 0x17, 0x20, 0xff, 0x0e, 0xdf, 0xd7, 0xfb, 0x0b, 0x0d, 0x05, 0xf6, 0x4e, + 0x00, 0xeb, 0x99, 0x1a, 0x3a, 0x26, 0xa6, 0x23, 0x1b, 0x0c, 0xbb, 0x13, 0x47, + 0x27, 0xdc, 0xe6, 0xfc, 0x37, 0x18, 0xbb, 0xfa, 0xb1, 0xdb, 0x65, 0xfa, 0x16, + 0xb6, 0xf7, 0x0a, 0xd8, 0x1d, 0xb0, 0xf4, 0xf4, 0xee, 0xdf, 0xf8, 0x2c, 0xd2, + 0x31, 0xe0, 0xf9, 0xdd, 0xa5, 0xbc, 0xb0, 0x1c, 0x3f, 0xdd, 0x2f, 0xf5, 0xc2, + 0xf6, 0xe1, 0xf8, 0xf2, 0xca, 0x1b, 0xbb, 0x94, 0xf6, 0x92, 0xed, 0xd9, 0xe4, + 0x3b, 0xb0, 0xda, 0xfe, 0xf2, 0x20, 0x8e, 0xf0, 0x5b, 0xd8, 0x0a, 0xf3, 0x3d, + 0xab, 0x16, 0xf7, 0xf8, 0x21, 0x00, 0xe9, 0x39, 0x09, 0xc7, 0x78, 0x3c, 0x08, + 0x1f, 0x1f, 0x1c, 0x4e, 0x53, 0x81, 0xc8, 0x13, 0x20, 0x3b, 0xdd, 0x22, 0x21, + 0x30, 0xaa, 0x05, 0xd8, 0x6f, 0xf4, 0xe5, 0xd3, 0xd7, 0x28, 0x78, 0xbc, 0xd7, + 0xea, 0xb2, 0x15, 0x1d, 0xbf, 0x91, 0xef, 0xe0, 0x2d, 0xed, 0x0f, 0x9a, 0xbf, + 0x38, 0xf1, 0xef, 0xe8, 0x17, 0xa0, 0xff, 0x81, 0x17, 0x63, 0xfa, 0xb9, 0x19, + 0x42, 0x08, 0xd4, 0x9c, 0xfc, 0x29, 0x23, 0x5f, 0x00, 0x37, 0xf8, 0x18, 0x16, + 0xb7, 0xd7, 0xdc, 0x30, 0xd3, 0x34, 0xac, 0x04, 0xe3, 0xab, 0xd1, 0x23, 0xe1, + 0xe4, 0x2b, 0xf2, 0x44, 0xc6, 0xf0, 0x3d, 0x20, 0xab, 0x3d, 0xde, 0xde, 0x40, + 0xf8, 0xe6, 0x63, 0x4f, 0x3d, 0x2a, 0x03, 0xe0, 0x14, 0x04, 0xf7, 0x08, 0xf1, + 0xab, 0x34, 0xe2, 0xd8, 0x05, 0xee, 0xea, 0xd2, 0x1c, 0xfa, 0xe6, 0xf9, 0x00, + 0xbf, 0x05, 0xe9, 0x1b, 0x1c, 0x2a, 0xd9, 0xbf, 0x1f, 0x2d, 0x22, 0xee, 0xe6, + 0x2e, 0xc1, 0xfb, 0xed, 0xc0, 0x3a, 0xfa, 0xe0, 0xdc, 0x0e, 0xb6, 0xac, 0xe7, + 0xea, 0x11, 0x37, 0x16, 0x47, 0xff, 0x1c, 0xdc, 0x70, 0x1d, 0xce, 0xfe, 0xce, + 0xef, 0x0f, 0xfc, 0xdc, 0xd5, 0x02, 0xff, 0x13, 0xcb, 0xc0, 0x2a, 0xf4, 0x2b, + 0xf4, 0x4c, 0x28, 0xd6, 0x0f, 0x12, 0x28, 0xd2, 0xf5, 0x14, 0x0e, 0x22, 0xd5, + 0x1f, 0xfe, 0x28, 0xd2, 0xdd, 0xe3, 0xe8, 0x0c, 0x12, 0xec, 0xee, 0x0c, 0xbd, + 0xdf, 0xe4, 0xbf, 0x81, 0x53, 0xf7, 0xce, 0x37, 0x1b, 0x30, 0x04, 0xd5, 0x1d, + 0xde, 0xf7, 0x10, 0x05, 0x11, 0x32, 0x03, 0xc6, 0xfc, 0xe8, 0xda, 0xea, 0xd4, + 0x3e, 0x0b, 0xfc, 0x17, 0x34, 0xd6, 0x56, 0x96, 0x25, 0xf0, 0xfc, 0x30, 0xe0, + 0xe7, 0x16, 0xe8, 0xcf, 0xe7, 0xe6, 0xfe, 0x97, 0xe4, 0xc1, 0x09, 0xe9, 0x6c, + 0x0e, 0xf8, 0xec, 0x2a, 0x04, 0x00, 0xe4, 0x23, 0x3c, 0xea, 0xb1, 0xf8, 0xcd, + 0x25, 0xdf, 0xcf, 0xfb, 0x05, 0x01, 0xf2, 0xf2, 0xb8, 0x0e, 0xcf, 0xf0, 0xec, + 0xf2, 0x19, 0xec, 0xea, 0xda, 0xe6, 0xef, 0xee, 0xe0, 0x81, 0xfc, 0xc5, 0x46, + 0xec, 0xca, 0x00, 0xf8, 0xe6, 0x07, 0xd6, 0x07, 0x3f, 0x03, 0x01, 0x25, 0x26, + 0xf1, 0xd0, 0xea, 0x0a, 0x0f, 0xeb, 0xe4, 0xec, 0xbc, 0xe0, 0x46, 0xe7, 0xf7, + 0xf1, 0x02, 0xdf, 0xe4, 0xdc, 0x51, 0xd0, 0xd7, 0xda, 0x38, 0xf0, 0x05, 0xf9, + 0x15, 0xf7, 0x01, 0x1a, 0xe9, 0xf2, 0x07, 0x19, 0xd7, 0xee, 0xd6, 0x2c, 0x24, + 0xa4, 0x33, 0xfd, 0x22, 0x13, 0x17, 0x59, 0xf0, 0x07, 0x25, 0xd8, 0xd9, 0xdf, + 0x35, 0xd7, 0xeb, 0x06, 0x00, 0xde, 0xf9, 0xe3, 0x0f, 0x54, 0xc6, 0x01, 0xfc, + 0x1f, 0x2d, 0x20, 0xcd, 0xc1, 0xfb, 0xc3, 0xb1, 0xc8, 0xf3, 0x49, 0xd4, 0x0a, + 0xf2, 0xfc, 0xe1, 0xd7, 0x19, 0xa0, 0x4d, 0x14, 0x33, 0x25, 0xf3, 0x0f, 0xa6, + 0xe8, 0x32, 0xf2, 0xde, 0xee, 0xd3, 0xf7, 0x38, 0xf7, 0x04, 0x43, 0x0a, 0xe5, + 0x17, 0xf2, 0x15, 0x0d, 0x46, 0x0a, 0x18, 0xb3, 0xf2, 0xe9, 0xaf, 0x03, 0xe0, + 0x0d, 0x42, 0xf3, 0xef, 0x36, 0xeb, 0xdf, 0xe7, 0xeb, 0xff, 0x13, 0x30, 0xb7, + 0xeb, 0xe9, 0xf9, 0xe6, 0x12, 0x11, 0x09, 0x25, 0xef, 0xf8, 0xf8, 0xf4, 0x03, + 0xf2, 0xdb, 0x10, 0x25, 0x06, 0xe6, 0x1f, 0x24, 0x16, 0xd3, 0xde, 0x0d, 0xb1, + 0xec, 0x30, 0x06, 0xf5, 0xd9, 0xb6, 0x11, 0x03, 0x11, 0xd8, 0xc3, 0xe1, 0x0b, + 0x04, 0x13, 0x37, 0xec, 0xd5, 0xda, 0xe6, 0xed, 0xf7, 0x16, 0x0f, 0x40, 0x29, + 0xd5, 0x20, 0xf9, 0x0c, 0xe8, 0x36, 0x3a, 0xe6, 0x26, 0xfe, 0xea, 0x22, 0xd6, + 0x0a, 0xc0, 0xee, 0x14, 0x44, 0x38, 0x2e, 0xe4, 0x0c, 0xd7, 0x27, 0xd0, 0x53, + 0xdd, 0xb1, 0x35, 0xf4, 0xdf, 0xd6, 0x7f, 0xf1, 0xcb, 0x33, 0xf2, 0x0d, 0x3c, + 0xee, 0x2e, 0x11, 0x2a, 0x38, 0x0d, 0xec, 0x6d, 0xe8, 0x2e, 0x28, 0xa4, 0xd7, + 0x44, 0x0e, 0x58, 0xfd, 0xd4, 0xfb, 0x2e, 0x0c, 0xf3, 0x04, 0x4f, 0x12, 0xf3, + 0x33, 0xf2, 0xf6, 0xc5, 0xd7, 0xfe, 0xf9, 0x2a, 0xef, 0xd0, 0x02, 0xb2, 0xfd, + 0x49, 0xae, 0xd9, 0x38, 0xf4, 0x1d, 0xf2, 0x42, 0x19, 0x10, 0x43, 0xb2, 0x15, + 0x03, 0x0c, 0xcb, 0x0d, 0x02, 0xde, 0x05, 0xd4, 0x05, 0x43, 0xcd, 0xa7, 0xe7, + 0xfd, 0xf5, 0x5f, 0x81, 0x5a, 0xd3, 0x0e, 0x00, 0x21, 0x00, 0xfa, 0xbc, 0x0a, + 0xd9, 0xdb, 0x00, 0xc5, 0x14, 0xef, 0xf4, 0x1f, 0xee, 0x4d, 0x5f, 0xaa, 0x19, + 0xd5, 0x04, 0x2c, 0xde, 0xd1, 0x21, 0xf9, 0xee, 0x6e, 0xc9, 0xbb, 0x15, 0xf0, + 0x10, 0xc4, 0x7c, 0xe3, 0xe3, 0x27, 0xe0, 0x4d, 0x16, 0x27, 0xaf, 0x0f, 0xbf, + 0xf1, 0x53, 0xfb, 0xa1, 0xde, 0x04, 0xcc, 0x36, 0xf3, 0x65, 0xf3, 0x01, 0xcd, + 0xea, 0x12, 0xe2, 0xd6, 0xa1, 0xa8, 0xf1, 0x04, 0x13, 0x41, 0xc5, 0xdc, 0x65, + 0xc9, 0x21, 0xfc, 0xf9, 0xfa, 0x18, 0xba, 0x3b, 0xd0, 0x81, 0xf4, 0x30, 0x25, + 0xff, 0xe2, 0x28, 0xff, 0xe8, 0xd2, 0xc2, 0x94, 0xc2, 0xe7, 0x1d, 0x48, 0xdf, + 0xbe, 0xe1, 0xce, 0xca, 0xfa, 0x12, 0x1e, 0xe3, 0xd6, 0x20, 0x44, 0xae, 0xcc, + 0xf8, 0xec, 0xe7, 0x22, 0x10, 0xa4, 0x4f, 0x21, 0x2a, 0x0a, 0xcf, 0x1b, 0xb6, + 0xec, 0xe8, 0x02, 0x0b, 0xe6, 0x1a, 0xe4, 0xcb, 0xa6, 0x13, 0xe1, 0xbf, 0xc7, + 0x96, 0xc0, 0xee, 0xd8, 0x00, 0x2c, 0x3d, 0xda, 0xe6, 0xc0, 0xf7, 0x13, 0xf8, + 0x1a, 0x30, 0xf0, 0xe5, 0x4d, 0x07, 0x18, 0x22, 0xa1, 0x04, 0xd1, 0xbe, 0x19, + 0xff, 0xef, 0xe0, 0xaa, 0x5b, 0xe0, 0xb9, 0xf3, 0x27, 0xc5, 0xd0, 0x04, 0x62, + 0xee, 0xda, 0x7b, 0x3a, 0xf8, 0x56, 0xbf, 0x26, 0x04, 0x09, 0xcb, 0x25, 0xf9, + 0xfd, 0x68, 0x04, 0xcf, 0x4e, 0x40, 0x32, 0x72, 0x18, 0x2b, 0xf1, 0xfd, 0x16, + 0x0a, 0xe3, 0xa4, 0x3b, 0x58, 0xf3, 0xba, 0x26, 0x41, 0xc8, 0x5a, 0x07, 0x6a, + 0x22, 0x4e, 0x2e, 0xaa, 0x37, 0x3f, 0x31, 0x14, 0x03, 0xf4, 0x10, 0xef, 0x31, + 0xce, 0x1e, 0xfe, 0xdf, 0x18, 0xe8, 0x18, 0x1a, 0x1b, 0xfb, 0xc5, 0xd1, 0x1f, + 0xdb, 0x1a, 0x31, 0xdd, 0x14, 0xb5, 0x6c, 0x74, 0x6d, 0xfe, 0x32, 0xec, 0xb0, + 0x24, 0x15, 0xfb, 0xd3, 0xca, 0xc4, 0x04, 0x02, 0xf2, 0x45, 0xcd, 0xfc, 0x0c, + 0x27, 0xe4, 0xf6, 0x29, 0x18, 0xd7, 0x35, 0xda, 0x01, 0x1b, 0x52, 0x13, 0x0b, + 0xef, 0xf0, 0x9a, 0x12, 0xbb, 0xc5, 0xdb, 0xda, 0xf5, 0xd3, 0x31, 0xcf, 0x49, + 0x23, 0x9a, 0xe4, 0xea, 0xd1, 0xe5, 0x05, 0xc9, 0xd3, 0x0b, 0xf2, 0x02, 0x36, + 0x13, 0xb2, 0x18, 0x1f, 0x33, 0xca, 0x0a, 0xe7, 0xfa, 0x41, 0xe9, 0xa3, 0xc1, + 0x7f, 0x98, 0x1a, 0x0f, 0x91, 0xe6, 0xe8, 0x1e, 0x40, 0xd4, 0xc4, 0xf6, 0x27, + 0xfe, 0x0b, 0x32, 0x1b, 0xfe, 0x19, 0x31, 0xfd, 0x14, 0xc2, 0xbe, 0xc0, 0xc9, + 0x26, 0xe3, 0xa3, 0xeb, 0x73, 0x5a, 0x44, 0xe4, 0xe3, 0xf2, 0x25, 0xed, 0xee, + 0x22, 0x1f, 0x08, 0xfb, 0x2b, 0xf3, 0x2a, 0xd3, 0xbc, 0xd2, 0xeb, 0x1d, 0xdc, + 0x02, 0x39, 0x04, 0x1b, 0x1b, 0xc2, 0xd3, 0x14, 0xeb, 0x1f, 0x05, 0x43, 0x10, + 0xec, 0xcb, 0xcb, 0x00, 0x15, 0x24, 0xf2, 0x00, 0x2b, 0xda, 0xf9, 0x02, 0xf0, + 0xfc, 0xce, 0x13, 0xfa, 0x11, 0xe4, 0xea, 0xc5, 0x61, 0xee, 0xd4, 0x1d, 0x08, + 0x7f, 0x1a, 0x44, 0x12, 0xef, 0x0a, 0xe2, 0xed, 0x08, 0x02, 0x21, 0x04, 0x4f, + 0x1c, 0x21, 0x04, 0x14, 0x10, 0xf7, 0xdb, 0xc8, 0x18, 0xde, 0x0a, 0x50, 0xac, + 0x25, 0x0e, 0xc4, 0x26, 0xeb, 0x28, 0x02, 0xed, 0x17, 0x2d, 0xf5, 0x0c, 0xf9, + 0xe1, 0x72, 0xe6, 0xbc, 0x23, 0x06, 0x01, 0xda, 0x1a, 0x15, 0xb4, 0x33, 0x02, + 0xe2, 0x1c, 0xcd, 0x0d, 0xd6, 0x19, 0x72, 0x17, 0xa9, 0x0e, 0x8e, 0xc6, 0xfa, + 0xd5, 0x29, 0x03, 0xd0, 0x26, 0x7f, 0x42, 0x18, 0xa7, 0x2a, 0x0c, 0x01, 0x00, + 0xfb, 0xe1, 0x23, 0x6e, 0x2c, 0xeb, 0x2f, 0x06, 0x1b, 0xf7, 0x16, 0x16, 0x5b, + 0xf8, 0x2f, 0x0c, 0x37, 0xde, 0xfc, 0xec, 0xff, 0x58, 0x18, 0x01, 0xc4, 0x9d, + 0xe5, 0xfc, 0x05, 0x37, 0x14, 0x12, 0xb5, 0xc4, 0xe8, 0xdf, 0x21, 0x33, 0x29, + 0x2b, 0x02, 0xa4, 0x3c, 0xd6, 0xfa, 0x20, 0xf5, 0x11, 0x03, 0x07, 0xb7, 0xd8, + 0xd0, 0xc0, 0xd5, 0x0f, 0xe3, 0xf4, 0xeb, 0xf0, 0xd7, 0x0e, 0x0b, 0x39, 0x29, + 0xdc, 0x0a, 0xfc, 0xf0, 0xec, 0x4c, 0x46, 0xf2, 0xfd, 0x33, 0x19, 0x13, 0x2c, + 0xe6, 0xc3, 0xdc, 0xfe, 0x1e, 0x23, 0x3a, 0x09, 0xfe, 0xfe, 0xce, 0x0e, 0xad, + 0x37, 0x4b, 0xc5, 0xec, 0xfa, 0xc4, 0x1b, 0x09, 0xf7, 0x1d, 0xef, 0xc1, 0x11, + 0x11, 0xfc, 0xe6, 0xc4, 0x0b, 0x15, 0x1d, 0x0b, 0xc8, 0xd2, 0xf9, 0x08, 0xb2, + 0x21, 0xf5, 0xf6, 0x2d, 0x30, 0xc4, 0x04, 0x0a, 0xe4, 0xc6, 0x09, 0x0b, 0xb0, + 0xf5, 0x06, 0x2b, 0x09, 0xcb, 0xc4, 0xf1, 0xf7, 0x41, 0x05, 0x08, 0xee, 0x41, + 0xeb, 0x34, 0x19, 0x28, 0x13, 0x03, 0xc4, 0xda, 0x1a, 0x27, 0x04, 0xf3, 0xda, + 0xf7, 0x02, 0xbe, 0x00, 0x36, 0xda, 0xb2, 0x60, 0xf9, 0xbf, 0x02, 0xe2, 0xce, + 0xf3, 0xd4, 0x11, 0x20, 0xe3, 0xc2, 0xac, 0x0f, 0x02, 0xf5, 0xef, 0x33, 0x38, + 0xe8, 0x1c, 0x12, 0x0e, 0x46, 0xc0, 0xe1, 0xf8, 0xda, 0x20, 0x21, 0xf2, 0x50, + 0xd7, 0x0e, 0x20, 0x04, 0x01, 0xfe, 0xb8, 0x35, 0xfb, 0x30, 0xc5, 0xe1, 0xe9, + 0xe2, 0xdc, 0x81, 0x70, 0xe7, 0x15, 0xfc, 0x6c, 0x05, 0xf9, 0x1b, 0x28, 0x29, + 0x06, 0x1b, 0xed, 0x86, 0x07, 0x17, 0xd7, 0x1c, 0xff, 0xb1, 0x18, 0xcd, 0xc1, + 0xeb, 0x31, 0xfe, 0xf8, 0xda, 0xf7, 0x02, 0x20, 0x09, 0xd6, 0x15, 0xd7, 0xe4, + 0x06, 0xdb, 0x11, 0xdb, 0xf4, 0x11, 0x15, 0xcc, 0x19, 0xed, 0xe4, 0x41, 0x2f, + 0xef, 0xfa, 0x0c, 0xe2, 0x07, 0x31, 0xf1, 0x30, 0xee, 0xf5, 0x09, 0x10, 0xe0, + 0xcb, 0x36, 0x20, 0x0d, 0xe4, 0x27, 0x3b, 0x1c, 0x1c, 0x3f, 0x0f, 0xd6, 0xef, + 0xee, 0x81, 0x30, 0x0d, 0xd5, 0x36, 0xf9, 0xd8, 0x12, 0xe5, 0x99, 0xf9, 0xb5, + 0x00, 0x0c, 0x3c, 0x18, 0x36, 0x30, 0xc0, 0x13, 0x06, 0xd7, 0xf6, 0x19, 0xbf, + 0xd5, 0x05, 0xfb, 0xbe, 0xf5, 0x20, 0xc8, 0x01, 0xe5, 0xd7, 0xf8, 0xe7, 0xe7, + 0xf4, 0xcc, 0xbc, 0xb8, 0x08, 0x1d, 0x24, 0x2d, 0x09, 0xf6, 0x1f, 0xef, 0xf0, + 0xff, 0x16, 0xef, 0x24, 0x0f, 0xf4, 0xed, 0xe9, 0x11, 0x16, 0x0e, 0xe6, 0x27, + 0x12, 0xe1, 0x0b, 0xdd, 0x2c, 0x12, 0x4e, 0xf0, 0x01, 0x08, 0xf5, 0x27, 0xcc, + 0xeb, 0xfc, 0x20, 0xf5, 0x23, 0xff, 0x2b, 0xaf, 0x0a, 0x6a, 0x57, 0xd8, 0xd1, + 0xec, 0xe3, 0xfc, 0x1b, 0xd9, 0x0e, 0xf7, 0x05, 0x05, 0x08, 0xbf, 0x05, 0xc6, + 0x0b, 0xf5, 0xdd, 0x0b, 0x1a, 0x00, 0x03, 0xdf, 0xc6, 0xf6, 0x0a, 0xfa, 0x05, + 0x19, 0xcf, 0xe1, 0x36, 0xd7, 0xb5, 0xf9, 0xe8, 0x14, 0x00, 0x08, 0xe3, 0x00, + 0x32, 0xda, 0xf6, 0x0f, 0x01, 0xec, 0x0a, 0x13, 0x04, 0xe4, 0xf3, 0x3e, 0xed, + 0x48, 0xf3, 0xf6, 0x03, 0x1a, 0x10, 0x02, 0xe7, 0xf0, 0xf9, 0xe1, 0xc8, 0xe8, + 0xec, 0x36, 0x19, 0x1f, 0x06, 0xdd, 0xe2, 0x05, 0xfb, 0x1b, 0x07, 0xec, 0xdc, + 0x00, 0xe1, 0x2b, 0xf7, 0x0b, 0xf7, 0x00, 0x03, 0x12, 0x15, 0x24, 0x0b, 0x00, + 0x00, 0x1d, 0xe6, 0xd6, 0x0f, 0x25, 0x7f, 0xe9, 0xd0, 0x44, 0x14, 0xcc, 0xe4, + 0xd8, 0xe4, 0xd6, 0xf2, 0x24, 0xf3, 0xfc, 0xc0, 0x05, 0xf9, 0x09, 0xe3, 0x03, + 0x46, 0xf3, 0xd3, 0xea, 0xe6, 0xea, 0xe6, 0xed, 0x02, 0xe7, 0xf5, 0xb4, 0x42, + 0x2e, 0xf5, 0xe2, 0x18, 0x36, 0xf2, 0x20, 0x12, 0xd7, 0xb3, 0x02, 0x0f, 0xfe, + 0x32, 0x08, 0xee, 0xde, 0xcf, 0xe7, 0xf9, 0xbd, 0x2a, 0x17, 0xf1, 0x0f, 0xdf, + 0x42, 0xe8, 0x24, 0x0c, 0xc7, 0xf3, 0x20, 0xfe, 0xec, 0x07, 0x31, 0xd9, 0xef, + 0x1b, 0x29, 0x0a, 0x32, 0xfa, 0xf8, 0x7f, 0xd4, 0x6f, 0x16, 0x1b, 0xae, 0xf6, + 0x25, 0x11, 0x04, 0xed, 0x07, 0xbf, 0x20, 0x06, 0xfd, 0xe1, 0xf7, 0xcd, 0xec, + 0x1e, 0xeb, 0x0a, 0xe0, 0xc2, 0xee, 0x17, 0x24, 0xc9, 0xdc, 0x17, 0x1f, 0x08, + 0xe7, 0x1c, 0xf3, 0x0a, 0x22, 0x09, 0xc3, 0xf2, 0x10, 0x27, 0xed, 0x07, 0x1e, + 0x36, 0x02, 0x12, 0x0e, 0x19, 0x12, 0x09, 0xe9, 0xfc, 0x20, 0xf5, 0xf0, 0x30, + 0xfb, 0x11, 0x45, 0x7f, 0xe6, 0x23, 0xb3, 0xfe, 0xe9, 0xff, 0x02, 0x1a, 0x1b, + 0x39, 0x01, 0xe7, 0xdf, 0xd3, 0x34, 0xce, 0xe3, 0x17, 0xed, 0xe4, 0x27, 0x2b, + 0xf7, 0x25, 0xc7, 0xf2, 0x2a, 0xbd, 0x28, 0xe7, 0xfd, 0xe4, 0x11, 0x27, 0x25, + 0x11, 0xf5, 0x0d, 0x21, 0xfc, 0xec, 0x09, 0xef, 0xdc, 0xd0, 0x05, 0x0b, 0xef, + 0x4e, 0x0f, 0x21, 0x0f, 0x42, 0xfa, 0xd5, 0x25, 0xd7, 0x2f, 0x24, 0x1d, 0x50, + 0xf6, 0x04, 0x1f, 0x27, 0x0a, 0x52, 0xca, 0xfb, 0xc1, 0x14, 0x1c, 0x2d, 0x3c, + 0x06, 0x0d, 0x33, 0x1c, 0x03, 0x02, 0xf9, 0xfa, 0x21, 0xeb, 0xeb, 0xf9, 0x06, + 0xe2, 0xf0, 0x1a, 0xe7, 0x01, 0xb2, 0x15, 0x0f, 0xb8, 0x2a, 0x04, 0xfb, 0x14, + 0xda, 0xe7, 0xff, 0x5f, 0xe1, 0xf2, 0x0d, 0xd8, 0xff, 0xf7, 0xbc, 0xe8, 0xa4, + 0x28, 0x1b, 0xee, 0xeb, 0x50, 0xef, 0x06, 0x04, 0xd0, 0xfa, 0xcd, 0x00, 0xc8, + 0xe7, 0x81, 0xf0, 0xdc, 0xee, 0xfb, 0xc1, 0xa8, 0xf9, 0x38, 0x12, 0x4c, 0x14, + 0x76, 0xe3, 0xf8, 0xf2, 0x50, 0xf9, 0xe5, 0x1c, 0xd8, 0x39, 0xf5, 0x76, 0x00, + 0x32, 0xca, 0x1b, 0xfd, 0xf9, 0x00, 0xf8, 0x12, 0x10, 0xed, 0x3b, 0x0c, 0x10, + 0xe9, 0x06, 0xee, 0xe9, 0xfc, 0xf0, 0x0c, 0x13, 0x1b, 0x06, 0x14, 0x15, 0xc4, + 0xc1, 0xbf, 0xfb, 0x34, 0xfc, 0xe4, 0x3b, 0x02, 0xcd, 0x35, 0x35, 0xed, 0x33, + 0x03, 0xef, 0x04, 0x36, 0xcc, 0xf6, 0xf2, 0x21, 0xe9, 0x15, 0xe1, 0xed, 0xdb, + 0x27, 0xf7, 0xbc, 0xb4, 0x20, 0xee, 0x01, 0xac, 0x4f, 0xc2, 0xbd, 0xfe, 0xc7, + 0xe5, 0x0a, 0x08, 0xbb, 0xf3, 0xf8, 0x47, 0xeb, 0xd6, 0x19, 0xf2, 0x65, 0x21, + 0x17, 0xb6, 0x0a, 0x11, 0x0f, 0xf0, 0xf4, 0x26, 0x19, 0xce, 0xd2, 0x4d, 0x2b, + 0xfa, 0x06, 0x10, 0x06, 0xe2, 0x37, 0x20, 0x3f, 0xef, 0x44, 0x4e, 0x1a, 0x57, + 0x43, 0x81, 0xae, 0x1e, 0x46, 0x1f, 0x0b, 0x3a, 0x03, 0xae, 0x0d, 0xeb, 0xd8, + 0xcc, 0x25, 0xe2, 0x32, 0xc8, 0xe5, 0x18, 0xcd, 0x1a, 0x1e, 0xe1, 0xde, 0x20, + 0x12, 0x30, 0xcf, 0xe5, 0xe8, 0x16, 0x31, 0x0e, 0x25, 0xfe, 0x17, 0x05, 0xe9, + 0xb7, 0xa1, 0x2e, 0xc2, 0x0d, 0xb8, 0x4a, 0xf7, 0xdf, 0xd8, 0xf9, 0xcf, 0xaa, + 0x36, 0x08, 0x2f, 0x0c, 0xca, 0x99, 0x02, 0xf8, 0x04, 0x22, 0xdd, 0x2c, 0xcb, + 0xf6, 0x13, 0x20, 0xef, 0x0f, 0xe4, 0x39, 0x32, 0x17, 0xef, 0xc3, 0xe6, 0x04, + 0xc3, 0xf0, 0xde, 0xcf, 0xdc, 0x4d, 0xf8, 0xbc, 0x12, 0xd4, 0x2b, 0xbe, 0xf7, + 0xb5, 0x12, 0x05, 0x02, 0xcb, 0x2e, 0xcc, 0x03, 0xbd, 0x5c, 0x11, 0xde, 0x2a, + 0xca, 0x33, 0xfb, 0xe9, 0xd8, 0x11, 0x64, 0xf6, 0xf7, 0x2f, 0xeb, 0x09, 0x47, + 0xf5, 0x29, 0x05, 0xfc, 0x27, 0xf2, 0xe0, 0xc3, 0x3e, 0x09, 0xf7, 0xec, 0xb5, + 0x11, 0xf8, 0x0d, 0x7f, 0xfa, 0xc4, 0x0c, 0xec, 0xf0, 0xea, 0x22, 0xe7, 0xd5, + 0xb4, 0xf5, 0xac, 0x14, 0xd8, 0xfb, 0xe0, 0xee, 0x22, 0xc7, 0x1c, 0xd8, 0x02, + 0xaa, 0xd9, 0xe2, 0x1f, 0x1f, 0xff, 0x25, 0x25, 0x1a, 0x20, 0xcd, 0xfa, 0x01, + 0xee, 0xec, 0xbf, 0x2e, 0x35, 0x07, 0x25, 0x16, 0x2d, 0x01, 0xcd, 0x19, 0x49, + 0xe4, 0x57, 0xff, 0xfb, 0xf2, 0xef, 0x09, 0x28, 0xf5, 0xa9, 0xd6, 0x00, 0xcf, + 0xf3, 0xe5, 0xc2, 0xfc, 0xca, 0xfd, 0x0d, 0x18, 0xde, 0x1d, 0xf4, 0xd7, 0x27, + 0x02, 0x33, 0x1e, 0xd7, 0x0c, 0x18, 0x41, 0x03, 0x1b, 0xee, 0x05, 0x26, 0x30, + 0x09, 0xd7, 0x14, 0xbd, 0xdf, 0x0e, 0xff, 0xe5, 0xfb, 0x28, 0xf8, 0x38, 0x17, + 0x08, 0xdd, 0xda, 0x15, 0xce, 0x08, 0xe6, 0xc4, 0xdc, 0x19, 0xe9, 0xd8, 0xc4, + 0x03, 0xe6, 0xcc, 0x4b, 0x0f, 0x1f, 0xc0, 0xfe, 0x15, 0xf1, 0x04, 0xec, 0x24, + 0xf7, 0xe8, 0x1f, 0x3c, 0xe9, 0x39, 0x23, 0x81, 0xac, 0xbf, 0x35, 0x2c, 0x14, + 0x00, 0xd5, 0x3b, 0xd0, 0x09, 0x03, 0xc3, 0xd6, 0x01, 0x01, 0xa9, 0xc0, 0x07, + 0x39, 0xa9, 0x2e, 0x0f, 0x44, 0xfb, 0x0a, 0x22, 0xe2, 0xc5, 0x21, 0x02, 0x21, + 0x08, 0x88, 0x10, 0xbc, 0xec, 0x9f, 0x27, 0x0e, 0xf8, 0xcd, 0xc6, 0x33, 0xf4, + 0x28, 0xc6, 0x07, 0x0f, 0x0c, 0x03, 0xc8, 0xde, 0xb4, 0xe9, 0x30, 0x1b, 0x37, + 0xe2, 0xcb, 0xef, 0x03, 0xc8, 0xdb, 0xcc, 0x0b, 0xf1, 0xc4, 0x34, 0x16, 0xb8, + 0x24, 0x40, 0x47, 0xe2, 0x10, 0x22, 0x0d, 0xaf, 0x01, 0x00, 0x18, 0x9a, 0x08, + 0xfd, 0x12, 0xd7, 0x0c, 0x37, 0x93, 0xdc, 0xcd, 0x20, 0xf0, 0x49, 0x14, 0x11, + 0xe3, 0x0c, 0xb8, 0xf0, 0x25, 0xd3, 0x30, 0x2d, 0x16, 0x47, 0x1f, 0x3e, 0xf6, + 0xc3, 0xfa, 0xb4, 0x41, 0x1d, 0xd1, 0x11, 0xff, 0xd5, 0xf3, 0xd6, 0x00, 0xef, + 0xcd, 0xb5, 0x13, 0xd4, 0xf8, 0xbb, 0xf0, 0x34, 0x6f, 0xb7, 0x1a, 0x05, 0xde, + 0xef, 0xf0, 0x2e, 0xd1, 0x10, 0xf0, 0xf2, 0xfb, 0x04, 0x04, 0xf3, 0xfe, 0x2a, + 0x23, 0x1d, 0xfa, 0x05, 0xc8, 0xcf, 0xb8, 0xcd, 0xb2, 0xf3, 0xe1, 0xd2, 0xc9, + 0x46, 0x26, 0x15, 0x0b, 0xea, 0x0d, 0x03, 0x0e, 0xa8, 0x00, 0xf7, 0x34, 0x1e, + 0x14, 0xe9, 0xed, 0x0f, 0x06, 0x12, 0xfb, 0xbe, 0x9f, 0x4d, 0xa7, 0x14, 0xd3, + 0x2f, 0xb5, 0xf7, 0x4b, 0x06, 0x2a, 0xdb, 0x23, 0x12, 0xaf, 0x05, 0xeb, 0x1c, + 0xad, 0xf4, 0xe9, 0xfd, 0x7f, 0xe1, 0xd3, 0xf7, 0x0f, 0x31, 0x28, 0xe0, 0xd3, + 0x2c, 0x16, 0xee, 0xcb, 0xfe, 0x12, 0xf0, 0xe8, 0xe9, 0xfa, 0x02, 0xc3, 0xcc, + 0xdd, 0xe8, 0xcc, 0xe2, 0xec, 0xf2, 0x00, 0x1f, 0xf9, 0xfc, 0xe7, 0xe3, 0xc6, + 0xb9, 0xdb, 0x58, 0x19, 0x2e, 0x04, 0x2e, 0x31, 0x39, 0x2c, 0xc8, 0xd4, 0xdd, + 0x1b, 0xf7, 0x22, 0xad, 0xd8, 0x13, 0x07, 0xc2, 0x27, 0xe6, 0x04, 0xee, 0xd2, + 0x0f, 0xd8, 0x16, 0x0a, 0x1b, 0x03, 0x09, 0xe9, 0xe0, 0x0d, 0xd2, 0x04, 0x09, + 0xc8, 0x29, 0x16, 0xe3, 0xe9, 0x23, 0xf5, 0x03, 0x40, 0xda, 0x58, 0x0e, 0x13, + 0x11, 0x01, 0x0d, 0x1d, 0x0a, 0x18, 0xa1, 0x3b, 0x7f, 0x7f, 0x1b, 0x3f, 0x06, + 0xd2, 0xee, 0xf8, 0x0f, 0x18, 0xf3, 0xca, 0xed, 0xe9, 0xef, 0x03, 0x2d, 0xe6, + 0xf6, 0x3e, 0x07, 0xf9, 0xe5, 0xf5, 0x2b, 0xee, 0xed, 0x1c, 0xfa, 0xfe, 0x14, + 0x1d, 0x12, 0x2d, 0xe8, 0xd1, 0xe7, 0x59, 0x9d, 0x0f, 0x02, 0xb8, 0xf9, 0x10, + 0x19, 0x10, 0xc5, 0x08, 0x5a, 0x19, 0xe2, 0x3c, 0xeb, 0x19, 0x0c, 0xc0, 0xe3, + 0x01, 0xed, 0xed, 0xc8, 0x08, 0xfc, 0xee, 0x29, 0xfc, 0x0c, 0x1a, 0xe3, 0x01, + 0xfe, 0xe1, 0x53, 0x0d, 0xd8, 0x01, 0xe6, 0x23, 0xfc, 0xfc, 0xbf, 0xfd, 0x14, + 0x4f, 0x08, 0xf8, 0x23, 0x05, 0xe1, 0xd3, 0xd6, 0xe1, 0x56, 0xb4, 0x01, 0xff, + 0xd6, 0xe6, 0xdd, 0x14, 0x0f, 0x2a, 0xf1, 0x00, 0xca, 0x21, 0xdf, 0x16, 0x0a, + 0x1f, 0xcf, 0x2a, 0x02, 0x56, 0xf8, 0x19, 0x1e, 0x10, 0xde, 0xf9, 0x0f, 0xdd, + 0xb2, 0x3c, 0x25, 0x1a, 0x30, 0xf8, 0x12, 0xf5, 0xbc, 0x5e, 0x0c, 0x1b, 0xfe, + 0x02, 0xec, 0x58, 0x29, 0x2e, 0xda, 0x07, 0xc8, 0x16, 0x1b, 0x1a, 0x2e, 0xd9, + 0xbb, 0x03, 0x24, 0xf5, 0x2c, 0x0f, 0xcf, 0x06, 0x7f, 0xf8, 0xc7, 0x14, 0xe2, + 0xd9, 0x05, 0xe5, 0x12, 0xf8, 0xd6, 0x01, 0xf0, 0xd4, 0x0e, 0x18, 0x1b, 0xd0, + 0x4c, 0xe3, 0xf5, 0xf9, 0xf6, 0xd5, 0xe4, 0xe9, 0x1a, 0xd1, 0x0b, 0x2d, 0xea, + 0x40, 0xf7, 0x29, 0xfb, 0xfa, 0x1f, 0xf8, 0xe0, 0xff, 0x05, 0x62, 0xf8, 0x08, + 0x7f, 0xaf, 0xdb, 0xe7, 0xe2, 0x39, 0xd6, 0xf7, 0xf7, 0xff, 0xce, 0xfc, 0x24, + 0x45, 0x0e, 0xfd, 0x58, 0xf7, 0xe0, 0x25, 0xdb, 0x1b, 0x19, 0xb7, 0x17, 0x1f, + 0x21, 0x11, 0xdd, 0x29, 0x26, 0x4a, 0x0a, 0x3a, 0x26, 0x07, 0x44, 0xcc, 0xe3, + 0x22, 0x3f, 0xb9, 0xe3, 0xf5, 0xcf, 0x30, 0xec, 0x27, 0xd7, 0x2f, 0x25, 0x04, + 0x13, 0x07, 0x1c, 0x05, 0x11, 0xef, 0xd2, 0x2c, 0xd5, 0x66, 0xf3, 0xea, 0xe1, + 0xff, 0xe3, 0xd3, 0x26, 0xc0, 0xd6, 0x2a, 0x40, 0x2d, 0xeb, 0x08, 0xed, 0x18, + 0x20, 0xf0, 0xe1, 0x13, 0x04, 0x12, 0x13, 0x27, 0x03, 0x0b, 0x04, 0x11, 0xf4, + 0xfe, 0x08, 0xdf, 0x2e, 0xd3, 0x17, 0xd1, 0xcd, 0xe9, 0xf0, 0x13, 0x08, 0x22, + 0x33, 0xda, 0xd9, 0xf9, 0xe9, 0x17, 0xfd, 0xe8, 0x05, 0x8f, 0xc6, 0xeb, 0xf9, + 0xc8, 0x31, 0xce, 0xa6, 0xde, 0xb9, 0xfb, 0xe1, 0x1d, 0xff, 0x0c, 0x78, 0xff, + 0xca, 0xf2, 0xb3, 0xfa, 0x0f, 0x23, 0xcb, 0x11, 0xbb, 0x3a, 0xe9, 0xda, 0xe6, + 0x12, 0xee, 0xeb, 0x01, 0xd7, 0xf8, 0xbb, 0xe7, 0xea, 0x23, 0x30, 0xff, 0xdb, + 0x0d, 0xc2, 0x33, 0x24, 0xcf, 0x56, 0xe1, 0xb0, 0xed, 0xe4, 0xfc, 0xdf, 0x2b, + 0x8e, 0x03, 0x1e, 0xeb, 0x05, 0xc0, 0xea, 0xbc, 0x2b, 0xce, 0x34, 0xd6, 0xdd, + 0xeb, 0x08, 0xeb, 0xd8, 0xc3, 0x5a, 0xc9, 0x05, 0x26, 0xc5, 0xd4, 0x0f, 0x65, + 0x26, 0x36, 0xde, 0xdf, 0xf1, 0x37, 0x27, 0x3e, 0xf3, 0xac, 0xbf, 0xfa, 0xd6, + 0x27, 0x0a, 0xda, 0x2d, 0xbf, 0x24, 0xc4, 0xe9, 0x63, 0xd8, 0xc0, 0x10, 0xe6, + 0x4f, 0xfc, 0x91, 0xb9, 0x1b, 0xec, 0xeb, 0x96, 0xf3, 0xd7, 0x5b, 0xe8, 0x74, + 0x1b, 0xdc, 0x07, 0x1d, 0x20, 0xf8, 0xef, 0xf9, 0xe2, 0x2d, 0x07, 0x3f, 0x28, + 0xf5, 0x7f, 0xdf, 0xc7, 0x1a, 0x18, 0x16, 0xcc, 0xd4, 0xf1, 0xf4, 0x19, 0xfc, + 0x22, 0xcf, 0xe4, 0xd8, 0x20, 0xf8, 0xaa, 0x3c, 0xde, 0x73, 0x0c, 0x25, 0x04, + 0x30, 0x19, 0xb3, 0x09, 0x4c, 0x46, 0x15, 0xfc, 0xd6, 0xe6, 0xcb, 0xef, 0xd6, + 0xfd, 0x26, 0x7f, 0x40, 0xcd, 0xd9, 0xfe, 0xfd, 0x1e, 0x19, 0xb9, 0xe2, 0x4d, + 0xfe, 0xf4, 0x05, 0xcb, 0x1f, 0xd2, 0x0d, 0xcc, 0xf6, 0xaf, 0x13, 0xf8, 0x0b, + 0x68, 0xcc, 0xd2, 0x6f, 0xac, 0x04, 0x36, 0x52, 0xf7, 0xef, 0xce, 0x00, 0x3c, + 0xb9, 0xd4, 0x0f, 0xf1, 0xe3, 0xf3, 0x33, 0x34, 0xef, 0x0c, 0xce, 0x59, 0x26, + 0x1f, 0xd9, 0xe3, 0x21, 0x16, 0x15, 0xf4, 0x08, 0x24, 0x20, 0x0a, 0x29, 0x02, + 0xe5, 0xcb, 0xf9, 0xe1, 0x32, 0x01, 0xf7, 0x05, 0x16, 0xe7, 0x28, 0xfd, 0x2f, + 0xce, 0xcf, 0x15, 0xdd, 0x55, 0xdd, 0xf3, 0x4b, 0x2e, 0xf9, 0xd4, 0x1d, 0x2f, + 0x43, 0x19, 0x99, 0xde, 0x81, 0xd3, 0xcd, 0xfa, 0x26, 0xcd, 0xcf, 0xcd, 0x10, + 0xe4, 0x0d, 0x44, 0xe9, 0x14, 0x6f, 0xcb, 0x46, 0xec, 0xf8, 0x11, 0xb7, 0xc6, + 0xf1, 0xee, 0xb8, 0x06, 0x83, 0xe2, 0xf1, 0xad, 0xec, 0x2e, 0x4a, 0xbe, 0x0b, + 0xf7, 0xf9, 0x03, 0x16, 0x0a, 0x16, 0xc7, 0x21, 0xe3, 0xc0, 0xd4, 0xf7, 0x49, + 0x17, 0xb5, 0x76, 0x03, 0x26, 0xc7, 0xe0, 0x2a, 0x1e, 0xd2, 0x28, 0x0f, 0xb2, + 0xf9, 0xf6, 0xbe, 0x60, 0x06, 0x15, 0xcf, 0xbc, 0x2c, 0xef, 0x08, 0xd7, 0x0d, + 0x02, 0xe6, 0x39, 0xb1, 0xc7, 0x0b, 0x0a, 0x40, 0x51, 0xe7, 0xe6, 0xcf, 0x11, + 0xa0, 0xce, 0xf7, 0x0f, 0xac, 0x14, 0xdd, 0x22, 0xe5, 0x01, 0xd0, 0xd6, 0x33, + 0xff, 0xa2, 0x1c, 0x02, 0xee, 0x24, 0x17, 0x46, 0xf3, 0x03, 0xf4, 0x17, 0xf8, + 0x01, 0xee, 0x47, 0x78, 0xf3, 0x24, 0x95, 0x16, 0xf0, 0x18, 0xc1, 0x21, 0xe9, + 0x45, 0x02, 0xf4, 0x21, 0x03, 0x2a, 0xe1, 0x27, 0x43, 0xdb, 0x2f, 0xf4, 0x1c, + 0xf1, 0xd3, 0x2a, 0xde, 0x45, 0xbd, 0x25, 0x65, 0xea, 0x09, 0x03, 0x0a, 0x43, + 0xec, 0x27, 0x2b, 0xe1, 0x9b, 0x0e, 0xf9, 0xe4, 0xda, 0x05, 0xc1, 0xe8, 0xe4, + 0x00, 0x05, 0x0e, 0xec, 0x02, 0xf3, 0xd8, 0x40, 0x33, 0x13, 0xc7, 0x04, 0xf7, + 0x3f, 0xf5, 0xe8, 0x16, 0x1e, 0xd1, 0xec, 0x0a, 0x15, 0x11, 0xd1, 0x09, 0x0e, + 0xd7, 0xf4, 0x0b, 0xd2, 0x28, 0xdf, 0xc2, 0x29, 0xe7, 0x43, 0x31, 0xeb, 0x52, + 0x0c, 0x20, 0xf2, 0xe2, 0xea, 0x00, 0xd3, 0x02, 0x61, 0x61, 0x0c, 0xed, 0xe7, + 0x1d, 0x06, 0xa3, 0xf7, 0xf0, 0xd8, 0xd3, 0x41, 0xe0, 0xe9, 0xc0, 0xf7, 0x07, + 0x35, 0x25, 0xf5, 0xb9, 0x05, 0xd5, 0xf2, 0x12, 0x16, 0x37, 0xdc, 0x00, 0x1d, + 0xba, 0xc4, 0x13, 0xe2, 0x37, 0x10, 0x09, 0x27, 0x7f, 0x01, 0xb9, 0x0b, 0xf7, + 0xf1, 0x1f, 0xe6, 0x13, 0xbc, 0xf2, 0xd4, 0x25, 0x31, 0x30, 0xff, 0xf3, 0xcb, + 0xc9, 0xd4, 0xe9, 0xe0, 0x00, 0xcb, 0x2d, 0xcd, 0xdb, 0xfc, 0xfd, 0x05, 0xdb, + 0xe0, 0xe6, 0x7f, 0xf5, 0x27, 0x19, 0xbf, 0xce, 0xed, 0xe5, 0x19, 0x11, 0xd4, + 0xc0, 0x11, 0x1b, 0x0f, 0x00, 0xcd, 0xe8, 0x08, 0x15, 0x05, 0xd0, 0x1c, 0xe1, + 0xf6, 0x28, 0x13, 0x1d, 0xf7, 0xef, 0xe9, 0xcc, 0x13, 0x54, 0x6e, 0x18, 0xe0, + 0xfe, 0x08, 0xc1, 0xc9, 0xfd, 0xee, 0xef, 0x03, 0x30, 0x3b, 0xd9, 0x01, 0xe9, + 0x11, 0xca, 0xc1, 0xe7, 0xfd, 0x49, 0x16, 0x0d, 0xb3, 0x0d, 0xfe, 0x3c, 0xfd, + 0xec, 0x15, 0xd5, 0x1c, 0x38, 0x0e, 0x37, 0xd9, 0x00, 0x33, 0xda, 0xfd, 0x19, + 0xfc, 0x21, 0xef, 0xe4, 0x3d, 0xfb, 0xd3, 0xf4, 0xfe, 0x1f, 0x17, 0x0b, 0x0e, + 0xd6, 0xae, 0xd1, 0xf7, 0x33, 0x0a, 0xf3, 0x1d, 0x07, 0xd8, 0xef, 0x27, 0xf7, + 0xe3, 0xec, 0xeb, 0x10, 0x37, 0x32, 0xe2, 0x06, 0xe9, 0xdb, 0x02, 0xd7, 0xd6, + 0xf3, 0xf2, 0x0f, 0x18, 0xf6, 0x26, 0xda, 0x20, 0x22, 0x1e, 0x01, 0xff, 0xef, + 0x25, 0x23, 0x25, 0x7f, 0x4f, 0x18, 0xd5, 0x1c, 0x01, 0x0b, 0xe7, 0xef, 0xe4, + 0xe5, 0x0c, 0xf0, 0xf8, 0xe3, 0x28, 0xbb, 0x35, 0xea, 0xec, 0x35, 0xf3, 0xc8, + 0xf2, 0xc4, 0xe7, 0x10, 0x00, 0x10, 0x01, 0x19, 0xf2, 0x0e, 0xff, 0x07, 0x0c, + 0xce, 0x40, 0x22, 0x3d, 0x0d, 0x07, 0xee, 0xcb, 0x30, 0xf8, 0x0b, 0xd6, 0xdb, + 0x01, 0xed, 0xed, 0xd0, 0xea, 0x32, 0x05, 0xe1, 0xf2, 0x1a, 0x1d, 0xec, 0x33, + 0xd0, 0x2a, 0x08, 0x20, 0xe3, 0x30, 0x03, 0xb1, 0x0c, 0x04, 0x30, 0xe7, 0xde, + 0xf8, 0xe5, 0x1b, 0x14, 0x05, 0xe0, 0x08, 0x1a, 0xee, 0xe1, 0x10, 0x12, 0x22, + 0x19, 0x1f, 0xfa, 0xc3, 0x14, 0x1b, 0x41, 0xd5, 0x46, 0x1b, 0xea, 0xde, 0x31, + 0x18, 0xfc, 0x39, 0xf6, 0xfd, 0x02, 0x1f, 0x5e, 0xed, 0x47, 0x0d, 0x81, 0xe8, + 0xc6, 0x35, 0x04, 0x2e, 0x10, 0x0d, 0xb4, 0x17, 0xf3, 0x19, 0x0e, 0x0c, 0x0e, + 0x14, 0x01, 0x60, 0x45, 0xda, 0x09, 0xd2, 0x10, 0xe8, 0xf7, 0x12, 0x53, 0xf1, + 0xff, 0x4f, 0x01, 0xe7, 0xd2, 0x00, 0xc2, 0xb3, 0xed, 0x2b, 0xf1, 0x28, 0xc1, + 0xfe, 0x3a, 0xf9, 0x1b, 0x16, 0xeb, 0x19, 0xf9, 0xff, 0x08, 0x43, 0x25, 0xf3, + 0x1a, 0x34, 0xb5, 0x33, 0xf8, 0xea, 0x87, 0x18, 0x18, 0xec, 0xe8, 0x13, 0xd1, + 0x24, 0xea, 0x00, 0xed, 0x13, 0xf2, 0xd0, 0x02, 0x01, 0x18, 0x17, 0xf9, 0x0e, + 0x23, 0x23, 0xf2, 0x13, 0x21, 0x1e, 0x01, 0xe8, 0x22, 0xd6, 0xc9, 0xee, 0xd9, + 0x1f, 0xfd, 0x08, 0xc4, 0x56, 0x2f, 0x2d, 0x8b, 0x15, 0x1b, 0xef, 0xf8, 0x0d, + 0xe2, 0x22, 0xeb, 0x15, 0x07, 0x55, 0xf4, 0x24, 0xf6, 0xd8, 0x06, 0xd7, 0x56, + 0x2b, 0x3a, 0xe1, 0x0a, 0x10, 0xa1, 0xfd, 0x7f, 0x22, 0xc6, 0xf9, 0x0c, 0xd3, + 0xdd, 0xd6, 0x15, 0x23, 0xfe, 0x6d, 0xdf, 0xe1, 0x21, 0xe1, 0xef, 0xed, 0xf6, + 0xcc, 0x1b, 0xdb, 0xf8, 0xfa, 0xeb, 0xf6, 0xef, 0xe5, 0xf4, 0x04, 0x24, 0x30, + 0x01, 0x2d, 0xf9, 0xfc, 0xfc, 0xf8, 0x06, 0x13, 0x31, 0x2f, 0xc8, 0xc5, 0xe8, + 0x61, 0xf2, 0x03, 0x00, 0xf4, 0xcd, 0xfb, 0xf5, 0x01, 0xf1, 0x0f, 0x26, 0x06, + 0xf5, 0xe8, 0xea, 0xc6, 0x00, 0x0a, 0xf5, 0xff, 0x2e, 0x08, 0xfa, 0xdb, 0xb7, + 0x24, 0x12, 0x1d, 0xf5, 0x1c, 0xd1, 0x3c, 0x0b, 0xef, 0x10, 0xea, 0x06, 0x16, + 0xe0, 0xa8, 0xd5, 0xdb, 0x19, 0xfe, 0x18, 0xe8, 0x08, 0x1c, 0x2b, 0x25, 0x27, + 0x0b, 0x38, 0x22, 0xf8, 0x17, 0xb1, 0x5f, 0xea, 0xe0, 0xa0, 0x53, 0x60, 0xe8, + 0x17, 0x12, 0x2d, 0x10, 0x49, 0x2b, 0xc0, 0xf4, 0xf0, 0xdc, 0x08, 0xb8, 0x0c, + 0x10, 0x16, 0x2a, 0xf7, 0xe7, 0xe4, 0x06, 0xfe, 0xc5, 0x31, 0x03, 0xef, 0xf6, + 0x4a, 0x1a, 0x27, 0x4b, 0x54, 0xd8, 0xcc, 0x00, 0xfa, 0xe0, 0xf0, 0x30, 0x0f, + 0x40, 0xdf, 0x00, 0x33, 0xf4, 0xd0, 0x13, 0x15, 0xfb, 0x29, 0xc6, 0x48, 0x0d, + 0x13, 0x06, 0x43, 0xcc, 0xe7, 0x7f, 0xe9, 0xed, 0x0b, 0x1c, 0x25, 0xfe, 0xf9, + 0xf9, 0xbd, 0xc4, 0xea, 0x2c, 0xdf, 0x0d, 0xc7, 0x20, 0x20, 0xe1, 0xde, 0x68, + 0xf2, 0x22, 0xcf, 0xef, 0x13, 0xff, 0xe8, 0x27, 0x0a, 0x48, 0xd4, 0x08, 0x68, + 0x1f, 0x14, 0xff, 0x0b, 0x1b, 0x49, 0xc7, 0xea, 0x04, 0xce, 0x0d, 0xd2, 0x99, + 0xe1, 0xd4, 0xff, 0xf6, 0x0c, 0x25, 0x30, 0x03, 0x43, 0x15, 0x35, 0xfa, 0xe9, + 0x21, 0x05, 0x1f, 0x27, 0x33, 0x1b, 0xd1, 0xdc, 0xf2, 0x29, 0xd0, 0xee, 0xfa, + 0xc1, 0x06, 0x13, 0xf0, 0x4b, 0x05, 0x17, 0xcf, 0xf8, 0x08, 0x0d, 0xf9, 0x36, + 0x11, 0xdf, 0xfe, 0xc7, 0xb0, 0xda, 0xea, 0x33, 0x5f, 0x3c, 0x20, 0xff, 0xff, + 0x17, 0x08, 0xd8, 0xf5, 0x22, 0xfa, 0xd6, 0xe6, 0x43, 0x17, 0xe2, 0x91, 0xfe, + 0xf6, 0x7a, 0xe3, 0xf2, 0xf1, 0x04, 0xff, 0xda, 0xf8, 0xee, 0x0d, 0xc8, 0xea, + 0xc5, 0xeb, 0x17, 0x06, 0x11, 0xd2, 0xfd, 0x7f, 0x1b, 0x0c, 0x37, 0xe1, 0x0d, + 0x3d, 0x3c, 0x3c, 0x35, 0x15, 0xe0, 0x32, 0x03, 0x1d, 0xe3, 0x0e, 0x13, 0xdd, + 0xd9, 0x14, 0x12, 0x08, 0xc5, 0x25, 0x1b, 0xd3, 0xfd, 0xe9, 0x05, 0x22, 0x18, + 0x29, 0x0c, 0xbc, 0xe0, 0x01, 0xdb, 0xdb, 0xe8, 0x39, 0x1b, 0x2d, 0x1c, 0xdf, + 0xf0, 0xfe, 0x2c, 0xec, 0xf5, 0x3f, 0x0f, 0xed, 0xf2, 0x2f, 0xf3, 0xf7, 0x23, + 0xff, 0x4e, 0xd2, 0xe6, 0x6b, 0x0b, 0x05, 0x11, 0xf4, 0xfb, 0x15, 0xe9, 0xed, + 0x16, 0x25, 0xa5, 0xfe, 0x47, 0x2a, 0xd7, 0xf6, 0x4c, 0x0b, 0xd7, 0xc7, 0xd6, + 0xe6, 0xcb, 0xcd, 0xfb, 0xec, 0xe7, 0x00, 0xd4, 0xda, 0x52, 0xe0, 0x21, 0xbf, + 0xcf, 0x3b, 0xe3, 0x1e, 0xbb, 0xab, 0x44, 0x56, 0x7e, 0xac, 0x26, 0x25, 0xfc, + 0xdb, 0xec, 0x01, 0xe9, 0xea, 0xf9, 0x49, 0x36, 0x03, 0x32, 0x04, 0x18, 0xfe, + 0xc3, 0xb2, 0xba, 0x7f, 0xec, 0xe6, 0xbf, 0x34, 0x01, 0x25, 0x0e, 0xde, 0xe6, + 0x0e, 0x8d, 0xcc, 0x28, 0x0c, 0x1a, 0x24, 0x1f, 0xd2, 0x1f, 0x01, 0x0b, 0x28, + 0xd7, 0xc9, 0x38, 0xf3, 0xc4, 0x5f, 0xf3, 0xcb, 0xea, 0xf3, 0xcf, 0xd0, 0xdc, + 0xe6, 0xd5, 0x1f, 0xc1, 0x1d, 0xfe, 0xfd, 0x88, 0x1e, 0xf1, 0x11, 0x05, 0x1b, + 0xec, 0xb0, 0xa4, 0xf1, 0x1c, 0xb8, 0x7b, 0x29, 0x10, 0x5d, 0x16, 0xf5, 0xb4, + 0xb7, 0x0a, 0x2b, 0x1d, 0x3c, 0xc0, 0xfd, 0xde, 0xe7, 0x32, 0xc6, 0x1a, 0xd4, + 0xc6, 0x17, 0x02, 0x06, 0xc4, 0xe0, 0x35, 0xaf, 0xd9, 0x02, 0xbf, 0x22, 0x59, + 0xc8, 0x14, 0xed, 0xb6, 0xd3, 0x5b, 0xf3, 0xb3, 0xd4, 0x19, 0xfd, 0x7f, 0xde, + 0x2d, 0xd5, 0xfe, 0xe5, 0x1e, 0xf5, 0xd5, 0xf0, 0x36, 0x07, 0xe1, 0x25, 0xc9, + 0x11, 0x29, 0x8b, 0xed, 0xbd, 0x19, 0x14, 0x74, 0xb3, 0xd9, 0xf0, 0x2d, 0x11, + 0x1e, 0xd4, 0x30, 0xb6, 0xe0, 0xff, 0xc4, 0x5d, 0xf5, 0x30, 0xc0, 0x96, 0x0c, + 0x03, 0x06, 0x11, 0xe5, 0xf3, 0xa1, 0x03, 0xe6, 0xe3, 0x31, 0xb7, 0x1b, 0x3c, + 0xec, 0xff, 0xef, 0x21, 0x10, 0x21, 0xdf, 0x18, 0xf2, 0x2e, 0xdf, 0xbc, 0x23, + 0x73, 0x0f, 0x05, 0xd4, 0x26, 0x0d, 0xf3, 0x02, 0xc9, 0x0d, 0x33, 0x3e, 0xd3, + 0xda, 0x21, 0xd8, 0xe9, 0x24, 0x18, 0x03, 0xd1, 0xf1, 0xdd, 0xec, 0xf0, 0x15, + 0x29, 0x12, 0x18, 0x00, 0xf4, 0x1c, 0xc1, 0x14, 0x47, 0xf6, 0xba, 0x5e, 0x0d, + 0x46, 0x17, 0x1e, 0x15, 0x05, 0x04, 0xd5, 0x1e, 0x6b, 0xea, 0x2e, 0x21, 0xab, + 0xf7, 0xc5, 0x4c, 0xdb, 0x31, 0x0a, 0x15, 0x07, 0x4d, 0x1a, 0xcf, 0xf3, 0x24, + 0xbf, 0x0e, 0x0d, 0xdf, 0xdb, 0x14, 0x01, 0x01, 0x38, 0x2d, 0x34, 0x2f, 0x1c, + 0x09, 0xde, 0x2c, 0x0c, 0xc0, 0xf0, 0x23, 0x02, 0xb5, 0x04, 0x3c, 0xd7, 0x1c, + 0xfb, 0x20, 0xc5, 0x04, 0xdf, 0x48, 0x15, 0x3d, 0x12, 0xeb, 0xe6, 0x12, 0xd1, + 0xde, 0x39, 0x33, 0x33, 0x05, 0xfb, 0xdb, 0xf3, 0x24, 0xd4, 0x1b, 0xd1, 0x30, + 0xe8, 0xff, 0x0e, 0xea, 0xfc, 0xf9, 0xcc, 0x4b, 0xd8, 0x36, 0xcd, 0x3e, 0xdd, + 0xf9, 0x03, 0xe2, 0xf9, 0x0a, 0xd2, 0xae, 0xf0, 0x1c, 0xe9, 0xf0, 0x28, 0x15, + 0x28, 0xac, 0x63, 0x33, 0x7f, 0xc7, 0xe9, 0xc8, 0x15, 0x34, 0xcd, 0xf4, 0xbe, + 0x08, 0x23, 0x39, 0xfc, 0x22, 0xf2, 0x02, 0xf9, 0x15, 0xb2, 0x21, 0xc6, 0x24, + 0x02, 0x93, 0xf1, 0xc3, 0x1d, 0x18, 0x1e, 0xde, 0xae, 0x01, 0xee, 0xb6, 0x67, + 0xe1, 0x26, 0xc2, 0x05, 0x01, 0x06, 0x28, 0x33, 0xfe, 0xe2, 0xe5, 0xd0, 0xbc, + 0x1b, 0xcf, 0x1b, 0xdb, 0x3f, 0xe4, 0x16, 0x15, 0x2d, 0x52, 0x5e, 0xfb, 0x22, + 0xd2, 0x46, 0xec, 0x15, 0xe9, 0x2c, 0xcd, 0x24, 0x22, 0xed, 0xea, 0xfa, 0xf5, + 0xc3, 0xf5, 0xb3, 0x81, 0x04, 0xf3, 0x90, 0xcc, 0x4f, 0xcd, 0x43, 0xe5, 0xfd, + 0x22, 0x9b, 0x15, 0x01, 0xc4, 0x2a, 0x3b, 0xe5, 0x04, 0x09, 0xe5, 0xaa, 0xf8, + 0xc2, 0xcc, 0x13, 0x11, 0x8b, 0x39, 0xaf, 0x0d, 0xfc, 0xee, 0xff, 0xfd, 0x1c, + 0xfe, 0xd6, 0x5f, 0xec, 0xcf, 0xc2, 0xc1, 0x0f, 0x68, 0x22, 0xf2, 0x3c, 0xd3, + 0xba, 0x12, 0x06, 0xfe, 0x11, 0x7d, 0xd1, 0xca, 0xdd, 0xcc, 0x15, 0x10, 0xed, + 0x05, 0xb8, 0xad, 0xbf, 0x16, 0x58, 0x2b, 0xed, 0x21, 0x1b, 0xf4, 0x27, 0xe7, + 0x00, 0xe0, 0x5f, 0x12, 0xc0, 0xc1, 0x0f, 0x45, 0xfa, 0xd1, 0x44, 0xed, 0x16, + 0x22, 0x02, 0xdc, 0xca, 0x4a, 0xca, 0xfb, 0xe7, 0xd9, 0xea, 0x2b, 0x12, 0xbb, + 0xcf, 0x21, 0xca, 0x1c, 0x1d, 0x39, 0xeb, 0xc8, 0xab, 0x21, 0xd5, 0xd0, 0x03, + 0xca, 0xf6, 0xcb, 0xe4, 0xf0, 0x3e, 0xd9, 0x2d, 0x03, 0x16, 0xfb, 0xfe, 0x08, + 0xeb, 0x36, 0x12, 0x16, 0x23, 0x17, 0x1d, 0x34, 0xe4, 0xfa, 0x19, 0x1a, 0xb1, + 0xfb, 0xea, 0x2b, 0x9a, 0xfe, 0xfb, 0x3d, 0x40, 0xd1, 0x5d, 0x5b, 0xe4, 0x2d, + 0xac, 0xd0, 0xc7, 0xfd, 0xca, 0x11, 0x7e, 0x2c, 0x01, 0xf9, 0xd2, 0x2b, 0xe4, + 0x7f, 0x20, 0xdd, 0xfc, 0xe6, 0x0c, 0x8c, 0x17, 0xff, 0xf5, 0x50, 0x23, 0x10, + 0xc7, 0x0f, 0x09, 0x20, 0xb1, 0xfe, 0xfa, 0xf9, 0x3e, 0x0a, 0xf6, 0xfa, 0x36, + 0xe2, 0xca, 0xf5, 0x26, 0x97, 0x3f, 0x0a, 0xcb, 0x17, 0xf6, 0x05, 0xdd, 0x41, + 0x00, 0xdc, 0xcc, 0x28, 0xed, 0xe7, 0xcd, 0xf4, 0xe9, 0xba, 0x81, 0xcb, 0xc1, + 0xc1, 0xfc, 0xde, 0x18, 0x11, 0xfc, 0xe8, 0x02, 0xf4, 0x05, 0x22, 0xd0, 0x06, + 0x0f, 0xed, 0x2c, 0x33, 0xfc, 0xf4, 0xf7, 0xd3, 0xf5, 0xb1, 0xcf, 0x01, 0xe3, + 0xf8, 0x05, 0xc9, 0xe7, 0xfb, 0x47, 0xad, 0xfc, 0x08, 0x0e, 0xb2, 0x20, 0xcb, + 0x16, 0xf9, 0x1e, 0x22, 0xec, 0xe4, 0x46, 0xf9, 0xf2, 0x5a, 0x01, 0xc7, 0xeb, + 0xfa, 0x25, 0xf2, 0xf5, 0x06, 0x26, 0xdc, 0x09, 0x05, 0xe1, 0xbd, 0xdc, 0x15, + 0x08, 0xa9, 0x10, 0x1d, 0xf9, 0x02, 0x28, 0xe1, 0xf9, 0x19, 0x0e, 0xf0, 0xed, + 0xe1, 0xef, 0x20, 0x44, 0x43, 0xd1, 0xf1, 0xfd, 0xc0, 0x1e, 0xda, 0x95, 0xd4, + 0xe8, 0x49, 0xed, 0xb3, 0xee, 0x2f, 0xc8, 0x03, 0xe9, 0x0c, 0x14, 0xde, 0xd9, + 0x2a, 0x75, 0xe6, 0xfd, 0x0d, 0x2e, 0x47, 0xd1, 0x33, 0x16, 0x12, 0xd0, 0x3a, + 0x7e, 0x12, 0xc5, 0xc4, 0xf8, 0xa0, 0xc1, 0x3e, 0x1e, 0xe6, 0x99, 0x3d, 0x06, + 0x00, 0xf5, 0xe8, 0xea, 0x73, 0xe3, 0x18, 0x07, 0x63, 0x26, 0xf2, 0xcf, 0xcc, + 0x0a, 0x1d, 0xcc, 0x35, 0x54, 0xd6, 0x3d, 0xcc, 0x44, 0xd2, 0xf2, 0x38, 0x09, + 0x07, 0xc2, 0x7f, 0xd3, 0xfb, 0x31, 0xfa, 0xdb, 0x07, 0xf8, 0x43, 0xab, 0x63, + 0x0f, 0xd5, 0x01, 0xff, 0xfb, 0xdb, 0x08, 0xfa, 0x1b, 0x38, 0xf9, 0x0f, 0x0c, + 0x40, 0xe6, 0xa5, 0xe0, 0xc5, 0x4f, 0x20, 0xe8, 0x3c, 0x2d, 0x21, 0xe6, 0xd9, + 0xef, 0x0a, 0xd1, 0xfd, 0xc7, 0xb6, 0x08, 0xb9, 0x95, 0x39, 0x60, 0x14, 0x0f, + 0xee, 0xdd, 0x12, 0x47, 0xe7, 0xaf, 0xdb, 0x10, 0xf9, 0x5d, 0x2b, 0x16, 0x0f, + 0xf8, 0x29, 0xda, 0x12, 0x00, 0x0f, 0xdf, 0xe0, 0x00, 0x0e, 0xdb, 0x0a, 0xc1, + 0x7f, 0x07, 0xf7, 0x47, 0xa1, 0xf5, 0xcc, 0xd9, 0xf8, 0x2b, 0xed, 0xf8, 0x1b, + 0xa4, 0xd2, 0xd2, 0x6b, 0x38, 0x26, 0x49, 0xee, 0x2e, 0x21, 0x0f, 0xee, 0xfe, + 0xe9, 0x40, 0xd5, 0xee, 0xe8, 0xd6, 0x3a, 0xbc, 0xd4, 0x1c, 0xf9, 0x10, 0xfa, + 0xde, 0xd3, 0x11, 0x2a, 0x00, 0x2c, 0x00, 0x25, 0xe1, 0x2d, 0xff, 0x1a, 0xfa, + 0x23, 0xf0, 0x26, 0xd7, 0xfd, 0xe7, 0x21, 0x3e, 0x02, 0xfa, 0x05, 0x08, 0x63, + 0x15, 0xc4, 0xcd, 0x1c, 0x34, 0xd3, 0x1d, 0xee, 0xea, 0x05, 0xa7, 0xed, 0xf8, + 0xed, 0xe9, 0xd7, 0xd7, 0x00, 0x0f, 0xcd, 0xdd, 0xfc, 0xd1, 0x09, 0xcf, 0xfe, + 0x3c, 0x00, 0xf5, 0xee, 0xf3, 0x04, 0x00, 0x44, 0xcf, 0x24, 0xe8, 0xf0, 0xcc, + 0xe1, 0x08, 0x14, 0x33, 0x18, 0xf0, 0x0b, 0x48, 0x64, 0xed, 0x0c, 0x2e, 0xe1, + 0xce, 0x27, 0xef, 0xee, 0x41, 0xf7, 0xba, 0xce, 0xce, 0xfa, 0x1d, 0xda, 0x90, + 0x11, 0xb5, 0xfb, 0xf7, 0xbd, 0xfa, 0xfb, 0x1b, 0x2d, 0xc1, 0xfa, 0x4c, 0x7f, + 0x0e, 0x9f, 0xc0, 0xce, 0x0f, 0xe9, 0xcb, 0xd1, 0x2f, 0x28, 0x03, 0xc9, 0xd5, + 0x39, 0x00, 0xec, 0xfa, 0x17, 0xef, 0xcf, 0xd9, 0xee, 0x1c, 0x65, 0xf8, 0x38, + 0x02, 0xfa, 0x2f, 0x1c, 0x23, 0xed, 0x3a, 0xde, 0x0b, 0x36, 0xf3, 0x50, 0x04, + 0x05, 0x13, 0xe5, 0x13, 0xec, 0xcd, 0xc8, 0xef, 0x09, 0xa9, 0xfd, 0x00, 0x0c, + 0x26, 0xe9, 0x04, 0x98, 0x05, 0xdf, 0x25, 0x38, 0x2f, 0xfb, 0x28, 0x90, 0x11, + 0x23, 0xbf, 0xc7, 0x0d, 0xe2, 0xce, 0x09, 0x21, 0x29, 0xe8, 0xeb, 0xc1, 0x15, + 0x40, 0xd3, 0x08, 0x12, 0xe2, 0x26, 0x36, 0x15, 0xab, 0x0b, 0x70, 0x05, 0x3d, + 0xf9, 0xcb, 0x52, 0xf5, 0xfb, 0xab, 0xdf, 0x0b, 0x2b, 0xd5, 0x1a, 0xde, 0x31, + 0xaa, 0x5e, 0x33, 0x01, 0x29, 0x0c, 0xad, 0x00, 0x07, 0x3c, 0x14, 0xd2, 0x22, + 0x07, 0xd6, 0x01, 0xed, 0xef, 0x26, 0x13, 0xf8, 0xe2, 0x28, 0xd8, 0xe8, 0x0f, + 0xf9, 0x34, 0xc2, 0xbc, 0xf3, 0xb5, 0x29, 0xe1, 0xd6, 0x39, 0x24, 0x3c, 0xff, + 0x09, 0x29, 0xc7, 0x25, 0x10, 0x08, 0xfe, 0x12, 0x02, 0xf0, 0x3e, 0xd5, 0x29, + 0x10, 0xb4, 0xe3, 0xda, 0xe8, 0x4a, 0xeb, 0x21, 0x1a, 0xe9, 0xfa, 0x3b, 0xe0, + 0xd1, 0xf2, 0xd5, 0x00, 0xc0, 0x22, 0x0d, 0xe2, 0x16, 0xe3, 0xe0, 0xa9, 0x03, + 0x7f, 0x02, 0x1d, 0x1d, 0xc7, 0x1b, 0x0c, 0x2d, 0xda, 0xf3, 0xde, 0xf8, 0x50, + 0x0e, 0xea, 0x0a, 0xb1, 0x15, 0x25, 0xdf, 0xff, 0x14, 0x03, 0xfc, 0xa3, 0xf7, + 0xd5, 0x3e, 0xa1, 0xc6, 0xe8, 0x56, 0xf0, 0xde, 0xd7, 0xe5, 0xe9, 0x1b, 0x27, + 0x17, 0x40, 0xf9, 0xd6, 0xde, 0x47, 0x4a, 0xd2, 0x1b, 0x15, 0xe9, 0xd4, 0x15, + 0x1b, 0xfa, 0x0a, 0xea, 0xe9, 0xfb, 0xd5, 0xd5, 0xcf, 0xf5, 0x36, 0xfb, 0x3a, + 0xf6, 0xf8, 0xf1, 0xec, 0x05, 0xe9, 0xf2, 0xfa, 0x14, 0xba, 0xec, 0xeb, 0x7f, + 0x4a, 0xfe, 0x16, 0x46, 0xd4, 0x09, 0xfe, 0xda, 0x08, 0xf7, 0xf1, 0x19, 0x38, + 0xf7, 0x33, 0xdf, 0xd7, 0x1b, 0x15, 0x28, 0xe7, 0x1b, 0xed, 0xeb, 0xed, 0x20, + 0x1a, 0xc0, 0x4c, 0xf7, 0x45, 0x59, 0xdc, 0x02, 0xcb, 0x07, 0x42, 0xd7, 0xd1, + 0xf8, 0xfc, 0x27, 0xea, 0x0d, 0xd9, 0xd3, 0xf1, 0xcc, 0x36, 0x10, 0x49, 0x29, + 0x14, 0x06, 0x14, 0xae, 0x16, 0x35, 0xc5, 0xf9, 0x02, 0x16, 0xde, 0xd7, 0x10, + 0x41, 0xbc, 0x2a, 0xfa, 0x1b, 0xc7, 0x13, 0xc9, 0x15, 0x2e, 0xe3, 0x0f, 0x2b, + 0xc3, 0xc0, 0x2a, 0xf3, 0x0e, 0x00, 0xd7, 0x24, 0x0d, 0x2f, 0xc8, 0xc8, 0xd4, + 0x14, 0x66, 0xc5, 0xd0, 0xd9, 0xe4, 0x3e, 0x8f, 0xb5, 0xe2, 0x27, 0x04, 0x3d, + 0xe4, 0xe4, 0x58, 0x28, 0xfa, 0xe8, 0xc6, 0x20, 0xf0, 0xf3, 0xfd, 0x12, 0x1a, + 0x09, 0xd0, 0xe1, 0xcb, 0xf2, 0xce, 0xd7, 0xa6, 0x18, 0x6c, 0x2e, 0x35, 0x4c, + 0x24, 0x48, 0xe3, 0x2b, 0xfe, 0xde, 0x18, 0xf6, 0xf0, 0x14, 0x27, 0xb9, 0xe2, + 0xc8, 0x08, 0xd9, 0x03, 0xf9, 0xcd, 0x30, 0x56, 0x1c, 0x24, 0x0a, 0xd9, 0xca, + 0xe2, 0xff, 0x04, 0xcb, 0x04, 0x19, 0x05, 0x35, 0xcf, 0x54, 0x17, 0x28, 0x04, + 0x00, 0x25, 0x08, 0xe2, 0xd3, 0x33, 0xc8, 0xde, 0xb4, 0x37, 0x0d, 0xd9, 0xf8, + 0xdf, 0x14, 0x81, 0x52, 0x36, 0x03, 0xdb, 0x12, 0x1f, 0xfe, 0x4a, 0x0c, 0xfd, + 0xe2, 0xec, 0xda, 0xfd, 0x21, 0x12, 0xf4, 0xe5, 0xc8, 0x0b, 0x12, 0x41, 0xae, + 0xe6, 0xfb, 0xee, 0x1c, 0xef, 0x04, 0x41, 0x11, 0xf0, 0x11, 0xe4, 0xdb, 0x21, + 0x1f, 0x07, 0xcf, 0x0c, 0x27, 0x1e, 0x1a, 0xde, 0xee, 0xcf, 0x24, 0x1b, 0x03, + 0xd9, 0xee, 0x06, 0xd6, 0xeb, 0xd4, 0xaa, 0x1a, 0xe4, 0x0a, 0x37, 0x07, 0x40, + 0xb7, 0xa3, 0x15, 0xe2, 0xc8, 0xd4, 0x11, 0x41, 0xff, 0x20, 0x3f, 0x4d, 0x31, + 0xbd, 0x14, 0xbb, 0x09, 0xfb, 0x3a, 0x40, 0xd1, 0x00, 0xed, 0xc5, 0xe6, 0x30, + 0xdb, 0x2f, 0xb1, 0x17, 0xdc, 0x21, 0x8d, 0xf2, 0x68, 0xd4, 0x27, 0xe7, 0xc8, + 0xbc, 0x08, 0xc4, 0xf6, 0xca, 0xd3, 0xcc, 0x23, 0xfc, 0x46, 0x3c, 0x52, 0xf6, + 0x14, 0x2f, 0xda, 0xf2, 0x18, 0xee, 0x42, 0xc5, 0xff, 0x09, 0xee, 0x1c, 0xf4, + 0xb4, 0xf7, 0x07, 0x45, 0xab, 0x1a, 0xd7, 0x9f, 0x20, 0x01, 0xbe, 0x0a, 0xbe, + 0xff, 0xf6, 0x1b, 0xef, 0x10, 0xce, 0xfe, 0xf4, 0x60, 0x2d, 0xd8, 0x14, 0x1b, + 0x26, 0x7f, 0x4e, 0xe2, 0xd7, 0xfb, 0xde, 0xd5, 0xe6, 0x32, 0xe8, 0x0a, 0x32, + 0xe4, 0xf8, 0x33, 0x2d, 0x32, 0x1b, 0x3a, 0xfa, 0x56, 0x18, 0x0e, 0xda, 0x2e, + 0xed, 0x81, 0x08, 0xe5, 0x32, 0xf5, 0xfd, 0xe4, 0xf7, 0xde, 0x00, 0x29, 0x05, + 0x34, 0x47, 0xc5, 0xdc, 0xd1, 0xe5, 0x75, 0x24, 0xc0, 0xda, 0xe5, 0xde, 0x19, + 0xfe, 0x19, 0x07, 0x61, 0xe5, 0xf7, 0xf9, 0x31, 0x0f, 0x06, 0xdf, 0x50, 0xdf, + 0x09, 0x10, 0x19, 0xf1, 0xde, 0x34, 0xc1, 0x7a, 0xfd, 0xcb, 0xda, 0xdf, 0xb6, + 0xa9, 0xf4, 0x37, 0xf2, 0x1d, 0xaf, 0x17, 0x16, 0x03, 0xf2, 0xc7, 0xd4, 0xd1, + 0x5d, 0x08, 0xc7, 0xb9, 0xf7, 0x33, 0x26, 0xf5, 0xd3, 0xf5, 0xce, 0xcb, 0x17, + 0x1e, 0x0e, 0xa2, 0xfe, 0xf7, 0x18, 0xfe, 0x68, 0x31, 0x67, 0xc4, 0x23, 0xc7, + 0x2b, 0x9f, 0x13, 0x34, 0xdc, 0x30, 0xcf, 0xea, 0xd3, 0xfb, 0x1a, 0xf9, 0x62, + 0x12, 0x15, 0xdf, 0x12, 0x2b, 0xcb, 0x0a, 0xee, 0x9e, 0xc6, 0xe6, 0x52, 0xf6, + 0x1b, 0xb3, 0x9c, 0x46, 0xf3, 0x29, 0x40, 0x18, 0xc7, 0xb5, 0x48, 0x22, 0xf0, + 0xae, 0xbf, 0xda, 0xfe, 0xbe, 0x36, 0xef, 0x01, 0xfd, 0xcf, 0xc0, 0x21, 0x52, + 0xf8, 0xf9, 0xdc, 0x98, 0xec, 0xf8, 0x08, 0x54, 0x3a, 0xf5, 0xc2, 0xea, 0x0d, + 0x03, 0xbc, 0xd2, 0xa6, 0x24, 0x7d, 0x4b, 0x01, 0xc9, 0x06, 0x10, 0x0a, 0xb6, + 0xf8, 0x12, 0x4c, 0xf5, 0xcc, 0xf4, 0x3a, 0xdf, 0xf8, 0xbf, 0x14, 0xdd, 0xbb, + 0xab, 0xea, 0xe0, 0x37, 0xa8, 0x7b, 0x0a, 0xea, 0x3c, 0x8c, 0x09, 0xf8, 0xe8, + 0xfc, 0xf1, 0x0d, 0x9d, 0x25, 0x1f, 0xf9, 0x16, 0xb2, 0xbb, 0x03, 0x07, 0xed, + 0xe0, 0xff, 0xbe, 0xab, 0xdc, 0xdd, 0x36, 0x56, 0xc3, 0x32, 0xe3, 0x2b, 0x81, + 0xfa, 0x68, 0xda, 0xd8, 0x55, 0x08, 0x0a, 0x05, 0x0a, 0x16, 0x01, 0xf9, 0xde, + 0xa5, 0x21, 0x38, 0xcf, 0x8e, 0x3d, 0xcd, 0xe3, 0xdd, 0xb4, 0x21, 0x19, 0xe7, + 0x2c, 0xa3, 0x0c, 0xca, 0xe4, 0xfd, 0x3d, 0xdd, 0xf5, 0xe8, 0x30, 0x06, 0x1e, + 0xab, 0xf0, 0xef, 0xda, 0x02, 0xe1, 0xe7, 0xcf, 0xeb, 0xfc, 0x1d, 0x16, 0x15, + 0x27, 0x06, 0xe3, 0x13, 0xe3, 0xee, 0x03, 0xdd, 0x10, 0x09, 0x1e, 0x02, 0xf8, + 0xf7, 0xd5, 0xe7, 0xd7, 0x01, 0xd9, 0xdd, 0x05, 0x28, 0xfb, 0x08, 0x01, 0x07, + 0xff, 0xf7, 0xca, 0x11, 0x30, 0x06, 0x11, 0xf6, 0x19, 0x00, 0x07, 0xe0, 0xf6, + 0xf3, 0xf7, 0x0e, 0x19, 0xc9, 0x08, 0xfd, 0xe2, 0x0a, 0x15, 0x01, 0x1f, 0x17, + 0xf9, 0xec, 0x46, 0xf7, 0xe6, 0xd5, 0xe3, 0x33, 0x0e, 0x0b, 0xf1, 0xfe, 0xe7, + 0x7f, 0xe8, 0xee, 0xe8, 0x1d, 0x11, 0xdd, 0xfd, 0x16, 0xfc, 0xe0, 0x07, 0xee, + 0x1f, 0x15, 0x01, 0x42, 0xd6, 0xe9, 0x0a, 0xeb, 0xea, 0xd2, 0xe1, 0xe1, 0x27, + 0xd4, 0x15, 0x23, 0x19, 0x03, 0xf2, 0xe9, 0xfd, 0xef, 0x03, 0x07, 0xf2, 0x11, + 0x06, 0xf9, 0xf3, 0x20, 0x07, 0x02, 0x5b, 0xf0, 0xd6, 0x3b, 0xf3, 0xf0, 0xcc, + 0x1e, 0xbf, 0xcb, 0x21, 0x12, 0xe9, 0x39, 0xea, 0xcd, 0xd6, 0x09, 0x43, 0x41, + 0x25, 0x0f, 0x35, 0x38, 0xf5, 0x26, 0x3d, 0x15, 0x02, 0x0b, 0xd8, 0x13, 0x1d, + 0x29, 0x0a, 0x03, 0xf6, 0x04, 0x36, 0x1f, 0x66, 0x1a, 0x41, 0x01, 0xe2, 0x01, + 0xf5, 0x09, 0xc9, 0xcf, 0x1a, 0x58, 0x4a, 0x1d, 0xf2, 0x69, 0xf7, 0x01, 0x3b, + 0x32, 0xda, 0xde, 0x19, 0xc3, 0x11, 0x05, 0x70, 0xb9, 0x07, 0x2e, 0xc0, 0xce, + 0x21, 0x2b, 0xfb, 0x16, 0xd3, 0xb8, 0xdc, 0xed, 0x3a, 0x20, 0xd8, 0xc6, 0x20, + 0xe6, 0xcd, 0x26, 0x2a, 0xd2, 0xf9, 0xeb, 0x2c, 0x52, 0xa9, 0x39, 0x11, 0x46, + 0xa1, 0x3f, 0x2e, 0xf6, 0x96, 0xe6, 0xcc, 0xca, 0xff, 0x2f, 0x1b, 0x81, 0x15, + 0x4f, 0x1e, 0x7d, 0xd4, 0x22, 0x02, 0xf2, 0xe3, 0xba, 0xf5, 0xde, 0xeb, 0x04, + 0x9c, 0xd7, 0x29, 0xd9, 0x43, 0xe6, 0x7f, 0x19, 0xec, 0x31, 0x40, 0xeb, 0x14, + 0x04, 0xf3, 0x0d, 0x04, 0x18, 0x15, 0xe5, 0xfa, 0xfc, 0xc7, 0xf8, 0x2a, 0xed, + 0x0a, 0xfa, 0x0c, 0xf1, 0xd5, 0x31, 0xdd, 0xe3, 0xf1, 0xe2, 0xec, 0x54, 0x00, + 0xd2, 0xf1, 0x28, 0x14, 0x10, 0xfb, 0xff, 0xeb, 0x08, 0xe1, 0x17, 0x22, 0x28, + 0xfe, 0x0d, 0xf7, 0x04, 0x16, 0x06, 0x12, 0xfe, 0xb4, 0xf4, 0x1e, 0xe0, 0xf3, + 0xec, 0x1c, 0xd2, 0x0c, 0x09, 0x39, 0x1b, 0xe2, 0x2e, 0xfb, 0xba, 0x00, 0x28, + 0xf1, 0x10, 0x08, 0x2c, 0xd7, 0x05, 0x20, 0xe7, 0xf9, 0x07, 0x24, 0xfd, 0xf1, + 0xe7, 0x1c, 0x04, 0xd5, 0xc8, 0xec, 0x2f, 0xfb, 0xfc, 0x0c, 0xe4, 0xec, 0x2a, + 0x2a, 0xc9, 0xf7, 0xff, 0xe3, 0xd3, 0xf2, 0x08, 0xe1, 0x35, 0xe6, 0xe9, 0x03, + 0x04, 0x04, 0x03, 0x0c, 0xce, 0xd0, 0x01, 0x2f, 0x39, 0x13, 0x15, 0x38, 0xfa, + 0xff, 0xf9, 0x20, 0x3b, 0x04, 0xbc, 0xe3, 0xd2, 0xfd, 0x0e, 0x11, 0x19, 0xe1, + 0x11, 0x0c, 0x19, 0xfb, 0xe7, 0xdd, 0x3b, 0xd4, 0xec, 0x31, 0x5f, 0x7f, 0x30, + 0x1c, 0xc2, 0xd7, 0x01, 0xcb, 0xe5, 0xf8, 0x14, 0xd5, 0x42, 0xf8, 0xf9, 0xb8, + 0xff, 0xd7, 0x1a, 0xf9, 0x28, 0xf0, 0x05, 0xe9, 0xdf, 0x0d, 0x0d, 0xce, 0x08, + 0xd7, 0xe2, 0x00, 0x49, 0x18, 0xf4, 0xb6, 0xe9, 0x34, 0x22, 0xf1, 0x10, 0x0e, + 0x1b, 0x28, 0x09, 0x29, 0xda, 0x23, 0x3d, 0xf1, 0x14, 0x12, 0xce, 0xf8, 0x27, + 0x0b, 0x0e, 0xf9, 0x4b, 0x10, 0xde, 0x1a, 0xc3, 0xf8, 0x3a, 0x0d, 0xef, 0x0d, + 0xff, 0x06, 0xb6, 0x02, 0x20, 0x0d, 0xee, 0xd4, 0xcb, 0xf5, 0x11, 0xd2, 0xfa, + 0xd7, 0x08, 0x5c, 0x11, 0xf6, 0x29, 0x0e, 0xec, 0x06, 0xde, 0xd0, 0xc7, 0xe2, + 0xef, 0x54, 0xfa, 0xec, 0xd6, 0x1f, 0xfd, 0xf4, 0xb2, 0x2a, 0x2a, 0x15, 0xfc, + 0x1c, 0x2e, 0x04, 0x1a, 0xb4, 0xd8, 0x03, 0x00, 0x19, 0xec, 0xb7, 0xfd, 0x2c, + 0x93, 0x65, 0xaa, 0xf9, 0x1a, 0x24, 0x37, 0x55, 0x7c, 0xe0, 0x52, 0x1c, 0x0d, + 0xf8, 0x2d, 0xef, 0xef, 0x1b, 0xd4, 0x21, 0x25, 0x16, 0x48, 0xe9, 0xef, 0xf1, + 0xe9, 0x0a, 0x35, 0x64, 0x35, 0xb9, 0x03, 0xe9, 0x0c, 0xab, 0xef, 0x57, 0xf2, + 0xd1, 0x23, 0x6a, 0x46, 0xbc, 0xf2, 0xfa, 0xc5, 0xf1, 0x3b, 0x0f, 0x22, 0xec, + 0xef, 0x1e, 0xfc, 0xe8, 0x94, 0xdf, 0xf5, 0xcb, 0x41, 0xd4, 0xef, 0x1d, 0x81, + 0x15, 0x40, 0x0d, 0x32, 0xf0, 0xa5, 0xe2, 0x17, 0x15, 0xd7, 0x04, 0xfa, 0xfb, + 0x89, 0x3e, 0x4d, 0x4b, 0x1c, 0x44, 0xdf, 0x0c, 0xdd, 0xec, 0x10, 0xf6, 0x2d, + 0xd4, 0xde, 0xfd, 0x16, 0x47, 0xe1, 0xb1, 0x31, 0x0a, 0x47, 0x90, 0xed, 0xd1, + 0xd2, 0xdb, 0xf4, 0xde, 0xea, 0xb2, 0xbc, 0xdc, 0x0f, 0xf0, 0xa9, 0x27, 0x16, + 0x57, 0x1d, 0x11, 0xff, 0x43, 0xcb, 0x22, 0x07, 0x15, 0xf4, 0x43, 0xc7, 0x02, + 0xc9, 0xb2, 0xee, 0x4f, 0xe6, 0x56, 0xbf, 0x02, 0xb9, 0x20, 0xb5, 0xde, 0x3b, + 0xa3, 0x0f, 0xe2, 0xfe, 0x1c, 0xf4, 0x33, 0x52, 0x04, 0xb5, 0x2e, 0x26, 0x88, + 0xc7, 0x10, 0xfc, 0xe5, 0x5c, 0xe6, 0xbc, 0xe9, 0x1c, 0x6b, 0xf2, 0x03, 0xd0, + 0x18, 0xb6, 0x18, 0x0f, 0x00, 0xde, 0xfc, 0x02, 0x6c, 0xca, 0xf1, 0xf8, 0x4a, + 0x3f, 0xeb, 0xaf, 0x14, 0xbe, 0xe1, 0xcc, 0x50, 0x15, 0x30, 0xeb, 0x06, 0xc2, + 0xfb, 0xce, 0xf9, 0x25, 0xe4, 0x1f, 0x1d, 0x08, 0x0e, 0xeb, 0xd9, 0xad, 0x19, + 0x0e, 0x02, 0xd9, 0x03, 0xf2, 0xfb, 0x14, 0xd9, 0xe2, 0xc6, 0x07, 0x81, 0xe4, + 0x1f, 0xcf, 0xe7, 0x3c, 0xb8, 0xda, 0x02, 0x61, 0x0d, 0xfe, 0x0c, 0x41, 0xc7, + 0xed, 0xf1, 0x2a, 0xce, 0x08, 0x2c, 0xe4, 0x28, 0xe9, 0x06, 0xa0, 0x28, 0xcc, + 0x0f, 0x14, 0xea, 0x15, 0x03, 0xee, 0xb3, 0x0a, 0xe7, 0x04, 0x38, 0xeb, 0xe8, + 0x28, 0x09, 0xe7, 0x13, 0x5b, 0x0f, 0x8d, 0x01, 0xd6, 0xcd, 0xed, 0xeb, 0xf7, + 0xf3, 0x00, 0x0a, 0x21, 0x4b, 0x19, 0xb6, 0xb0, 0x01, 0xdc, 0xe6, 0x43, 0xc8, + 0xce, 0x06, 0xb8, 0x3f, 0x31, 0xe0, 0xea, 0xcf, 0xf9, 0x56, 0xec, 0xc5, 0x81, + 0x32, 0xbd, 0xc3, 0xf9, 0x22, 0x53, 0x22, 0x00, 0xf2, 0x3b, 0xef, 0x1a, 0x45, + 0x9e, 0x60, 0x09, 0x42, 0xdd, 0x2a, 0x32, 0xf3, 0x3b, 0xfd, 0x2d, 0x08, 0xde, + 0x1d, 0x41, 0xdc, 0xd7, 0xdd, 0xe1, 0xf6, 0x09, 0xc3, 0x17, 0xd6, 0x69, 0x48, + 0xb6, 0xfa, 0xe4, 0x1a, 0xfb, 0x5b, 0xfc, 0xba, 0x08, 0x01, 0xec, 0xd6, 0xe0, + 0x26, 0xd2, 0xf5, 0x0c, 0xf6, 0x1c, 0xba, 0xdb, 0xf6, 0x21, 0xf9, 0x0d, 0x12, + 0x33, 0xe8, 0x04, 0xc8, 0xc2, 0x25, 0x0c, 0x18, 0xf6, 0xae, 0xd9, 0xef, 0xb7, + 0xbf, 0x3a, 0x20, 0x0a, 0x0a, 0x48, 0x05, 0x06, 0xcb, 0x0b, 0xb3, 0x24, 0xe2, + 0x51, 0xce, 0x17, 0xfd, 0xb3, 0x2d, 0x29, 0xf2, 0x04, 0x09, 0x61, 0xcc, 0xf1, + 0xb0, 0x2e, 0x4f, 0x19, 0x81, 0x2f, 0xfe, 0x3e, 0xae, 0xca, 0x11, 0x15, 0x79, + 0xd9, 0xb2, 0xf2, 0xe0, 0xed, 0x42, 0xaf, 0xba, 0x0a, 0xee, 0x2c, 0xd1, 0xee, + 0xf1, 0xbc, 0xe8, 0xd7, 0xd5, 0xfd, 0x02, 0xfd, 0x16, 0x46, 0xcf, 0xc5, 0xe8, + 0x37, 0x2d, 0xf5, 0x23, 0xe5, 0xf1, 0xc6, 0x17, 0x23, 0x3b, 0x55, 0xe6, 0x0f, + 0xeb, 0x5f, 0x07, 0x1f, 0x20, 0x27, 0x18, 0xd6, 0x01, 0xfc, 0x58, 0x02, 0xf1, + 0xe5, 0xe9, 0x13, 0x23, 0x16, 0xa9, 0xe7, 0x16, 0xe8, 0xc0, 0xfd, 0x48, 0x9a, + 0xfc, 0x15, 0xfa, 0xde, 0xce, 0x05, 0xb6, 0x20, 0xb0, 0xf2, 0x17, 0xf8, 0xd9, + 0x0a, 0x15, 0x34, 0x20, 0xcb, 0x05, 0x0d, 0x13, 0xe4, 0xed, 0xf2, 0xeb, 0xd2, + 0xff, 0x21, 0x0a, 0x24, 0x19, 0xc5, 0xff, 0xf5, 0xd8, 0xfc, 0xe4, 0xe9, 0xdd, + 0xf0, 0x22, 0x27, 0xf9, 0xda, 0xe7, 0xbc, 0x26, 0xfd, 0xdc, 0x0a, 0xc7, 0xf2, + 0xf8, 0x44, 0xd9, 0x57, 0x2a, 0xfd, 0x02, 0xf9, 0xf4, 0x28, 0x0e, 0x29, 0x39, + 0xe4, 0x7f, 0x62, 0xd6, 0x14, 0xd4, 0xda, 0x17, 0xdd, 0x3a, 0x1e, 0xcd, 0xea, + 0xfe, 0xd4, 0x00, 0xf1, 0xf9, 0xf2, 0x13, 0xe6, 0xf5, 0xe3, 0x7e, 0xfc, 0x18, + 0xbd, 0x10, 0x11, 0xde, 0x0f, 0x01, 0xd6, 0xcc, 0xbc, 0x1a, 0xe7, 0xdb, 0x0c, + 0x01, 0x08, 0x3c, 0x07, 0xe2, 0xfe, 0xc9, 0xd1, 0x04, 0xef, 0x34, 0xfe, 0x0b, + 0x20, 0x2c, 0x41, 0x66, 0x03, 0xe3, 0x24, 0xfe, 0xfc, 0x02, 0x44, 0xeb, 0x08, + 0xf3, 0x62, 0xfe, 0xfe, 0xf5, 0x28, 0xf8, 0x05, 0x08, 0xfe, 0xf4, 0x00, 0x02, + 0x37, 0xdc, 0xe9, 0x0c, 0xfd, 0x81, 0x22, 0xfa, 0xde, 0x2e, 0x05, 0xff, 0xfc, + 0x26, 0xf0, 0xf2, 0xcf, 0xf1, 0xf0, 0xdd, 0xd5, 0xee, 0x0d, 0xf3, 0xe6, 0xe1, + 0xfd, 0x06, 0x21, 0xdb, 0xf9, 0x32, 0xff, 0x2b, 0x15, 0xfe, 0x05, 0x19, 0x03, + 0xf3, 0x45, 0x02, 0x0a, 0x0f, 0x02, 0xe5, 0xfc, 0xd7, 0x03, 0xf1, 0xc9, 0x34, + 0xf2, 0x0d, 0x38, 0xf2, 0x06, 0x28, 0x2e, 0xc5, 0xc8, 0xf1, 0x0c, 0xd8, 0xe1, + 0x0b, 0xd3, 0xe7, 0xe7, 0x0d, 0xfb, 0xe8, 0x40, 0xf4, 0x14, 0x13, 0x13, 0xd0, + 0x01, 0xff, 0x13, 0x18, 0xf9, 0xf9, 0x58, 0xeb, 0xcf, 0xd8, 0x2b, 0xd4, 0xcb, + 0xe7, 0x26, 0x0b, 0xf0, 0x0a, 0x20, 0xf0, 0x11, 0xed, 0xd9, 0xe8, 0x07, 0xd3, + 0xd0, 0xed, 0xfd, 0x0b, 0x33, 0xf2, 0x03, 0x0f, 0x0e, 0x0a, 0x22, 0xea, 0xf7, + 0x24, 0xe0, 0x0f, 0x2c, 0xc2, 0x0e, 0x2b, 0xb9, 0x10, 0x16, 0xea, 0x04, 0x0b, + 0xe4, 0xf4, 0xcb, 0x81, 0xf3, 0x0b, 0x13, 0x03, 0x13, 0x31, 0xd5, 0xde, 0xf9, + 0x01, 0x00, 0xf3, 0xfd, 0xd3, 0xfd, 0x16, 0xcd, 0xef, 0x34, 0xb8, 0x31, 0x06, + 0x1a, 0x1a, 0xdf, 0x2c, 0x11, 0x25, 0xfb, 0x4a, 0x3e, 0xf5, 0xed, 0xed, 0x1b, + 0x25, 0xf7, 0xfd, 0xed, 0xf7, 0xe5, 0xfa, 0xea, 0xef, 0x24, 0x12, 0x04, 0xeb, + 0x08, 0x1e, 0xd8, 0xd9, 0x1e, 0xfc, 0xf6, 0xde, 0xe6, 0xe1, 0x10, 0xfe, 0x48, + 0x0f, 0x0c, 0xfd, 0xdd, 0x2e, 0x1a, 0xca, 0xfe, 0x33, 0x0a, 0xe2, 0x23, 0xcf, + 0xd1, 0x15, 0xed, 0x10, 0x2b, 0x05, 0xd7, 0x00, 0xf2, 0x18, 0xce, 0xe9, 0x0c, + 0x01, 0xf4, 0xed, 0x31, 0x21, 0x01, 0x09, 0x29, 0x06, 0x09, 0x3a, 0xdc, 0x55, + 0x10, 0xf4, 0x14, 0xfc, 0xa7, 0xf8, 0xb7, 0x33, 0xec, 0x23, 0xd5, 0xf6, 0xdc, + 0x09, 0xe0, 0x2c, 0x20, 0xd9, 0xb6, 0x36, 0x0a, 0x0a, 0x33, 0xef, 0x09, 0x1f, + 0xeb, 0xf6, 0x0a, 0x2d, 0xd5, 0xe1, 0xee, 0x17, 0xc0, 0xd6, 0x08, 0x44, 0xfd, + 0xd6, 0x17, 0x31, 0x09, 0xfc, 0x39, 0x48, 0x3b, 0x32, 0x0f, 0x30, 0xd9, 0xb1, + 0x6a, 0x03, 0x08, 0xf7, 0x11, 0xce, 0x2b, 0x0e, 0x2a, 0xe7, 0x34, 0xf8, 0x41, + 0x50, 0xed, 0x03, 0x25, 0x14, 0x38, 0xcd, 0xfe, 0xfe, 0xeb, 0x1a, 0x0d, 0x07, + 0x25, 0xcf, 0x2a, 0xe5, 0xfb, 0xe7, 0x60, 0xe6, 0x05, 0xf6, 0xed, 0xf1, 0xec, + 0x65, 0x01, 0x43, 0xf8, 0x33, 0x1a, 0xef, 0xf3, 0x16, 0xf5, 0xf8, 0xde, 0x19, + 0x35, 0xc8, 0xdf, 0xfe, 0xc5, 0x0d, 0xa7, 0x0f, 0x22, 0xef, 0x02, 0x18, 0xb5, + 0x0e, 0x18, 0x13, 0x63, 0x16, 0x57, 0xfc, 0xbf, 0xc2, 0x09, 0xea, 0xda, 0xf4, + 0xf8, 0xce, 0x1b, 0x56, 0xd0, 0x1d, 0xc3, 0x0b, 0xab, 0x20, 0x05, 0xf1, 0xcc, + 0xea, 0xa6, 0xec, 0xfa, 0xf0, 0x26, 0x06, 0x0b, 0x81, 0xe5, 0x21, 0xd7, 0x10, + 0xf3, 0xff, 0xf3, 0xf1, 0xed, 0x1c, 0x09, 0x18, 0x18, 0x0a, 0xf9, 0xee, 0xbd, + 0x6f, 0x11, 0xdc, 0xac, 0xd0, 0x24, 0xf0, 0xe8, 0xf1, 0x1a, 0xc8, 0xea, 0xd1, + 0x29, 0x23, 0xc2, 0xf0, 0x21, 0xb8, 0xe7, 0xfe, 0xec, 0x2c, 0xdb, 0x07, 0x13, + 0xca, 0x2a, 0xd3, 0xe6, 0x14, 0x20, 0xf4, 0xe2, 0x13, 0x02, 0x32, 0xff, 0x0d, + 0x02, 0x0b, 0x0f, 0x0c, 0x0e, 0x17, 0xf9, 0x21, 0x1b, 0xf2, 0x08, 0xb5, 0xfc, + 0xf5, 0xe6, 0xc4, 0xf1, 0xe9, 0x0d, 0x0b, 0xf7, 0xcf, 0xc9, 0x13, 0xf8, 0x33, + 0x0a, 0x02, 0x24, 0xc3, 0xf6, 0x0d, 0xc2, 0xdb, 0xf8, 0x45, 0xfe, 0x14, 0xf3, + 0xeb, 0xe1, 0xd3, 0x15, 0x32, 0x0d, 0xd0, 0xde, 0xec, 0x19, 0x14, 0x0b, 0xfe, + 0x0f, 0xf5, 0xe0, 0xea, 0x00, 0x22, 0x17, 0xd3, 0xd2, 0xfb, 0xf1, 0x17, 0x45, + 0x16, 0x19, 0x37, 0x81, 0xea, 0x0b, 0x3a, 0xf1, 0x49, 0x4c, 0xa8, 0x0d, 0x23, + 0xe5, 0x0c, 0xda, 0xea, 0x12, 0xda, 0xe3, 0xcd, 0x7c, 0x0d, 0x53, 0x0c, 0xc5, + 0x93, 0x45, 0xc9, 0x6e, 0x4f, 0xbb, 0xb7, 0xf1, 0x4c, 0xe2, 0xd4, 0xf6, 0xaa, + 0xe3, 0xce, 0xe7, 0x36, 0x98, 0xf2, 0x2d, 0x1e, 0x51, 0x15, 0xd3, 0x19, 0x5d, + 0xdf, 0xa7, 0x0a, 0x00, 0xea, 0xc4, 0x0b, 0x07, 0xe2, 0x45, 0xe9, 0x14, 0xd7, + 0x0b, 0x77, 0xb9, 0x26, 0xfb, 0xe4, 0x4d, 0x26, 0x16, 0x01, 0x8d, 0x49, 0x9e, + 0xf0, 0x00, 0x47, 0x95, 0x01, 0x27, 0xcd, 0xd8, 0x84, 0x09, 0xff, 0xcf, 0x17, + 0x81, 0x15, 0x17, 0xcf, 0xd2, 0x25, 0x31, 0x09, 0xa0, 0x8f, 0x0e, 0x21, 0x91, + 0x00, 0x04, 0xb2, 0x40, 0x1b, 0xea, 0xa6, 0x0d, 0x41, 0x16, 0xd5, 0xe9, 0xff, + 0x76, 0x16, 0x09, 0x1b, 0x02, 0x37, 0x44, 0x48, 0xf9, 0xef, 0xed, 0x2e, 0xe9, + 0x2c, 0x20, 0x17, 0xd5, 0xbe, 0xad, 0x4f, 0xe4, 0xfb, 0xee, 0xbb, 0x04, 0x0c, + 0xda, 0x2b, 0xe7, 0x0c, 0x20, 0x03, 0x2d, 0x01, 0xff, 0xc6, 0x2c, 0x30, 0xb0, + 0x31, 0xe4, 0xe4, 0xd4, 0xf3, 0xe0, 0xce, 0xe7, 0x04, 0x9d, 0x57, 0x0e, 0xf4, + 0xe3, 0x24, 0xf1, 0xe4, 0xef, 0xc4, 0xde, 0x32, 0xea, 0xfa, 0x0d, 0xa7, 0xf4, + 0x15, 0xc8, 0x11, 0xc2, 0x58, 0x2e, 0x8e, 0x28, 0xf2, 0x32, 0xc2, 0xfa, 0x2f, + 0xfa, 0x46, 0xf0, 0x73, 0x09, 0x9a, 0xca, 0x42, 0xaf, 0xa8, 0x18, 0xe5, 0x0f, + 0x05, 0x0d, 0x0c, 0xca, 0x0e, 0xd7, 0x27, 0x05, 0xe9, 0xc6, 0x19, 0x81, 0x0e, + 0xf6, 0xfc, 0xe7, 0x41, 0xe7, 0xd5, 0xe8, 0x0a, 0x10, 0x07, 0xd4, 0x3e, 0x06, + 0xcd, 0xc2, 0x01, 0x2d, 0xcd, 0x5a, 0xb4, 0x36, 0x05, 0x31, 0xd7, 0x10, 0xca, + 0x3c, 0x17, 0x00, 0x38, 0x20, 0xf9, 0xe7, 0xdd, 0xf8, 0x18, 0xad, 0x12, 0xa5, + 0xd4, 0xe2, 0xbf, 0xfa, 0x10, 0xbd, 0x1d, 0xb0, 0x2e, 0x20, 0xd9, 0x0e, 0xee, + 0xfb, 0xa3, 0xcd, 0xc4, 0xec, 0xef, 0xf2, 0xe4, 0x9e, 0xdb, 0xae, 0x0d, 0xff, + 0xec, 0x17, 0xa2, 0x09, 0x1b, 0xfb, 0xdf, 0x29, 0x00, 0xf2, 0xab, 0xe3, 0xdf, + 0xe5, 0xe5, 0x13, 0x73, 0x0f, 0x14, 0xf3, 0xba, 0xde, 0xdc, 0xc0, 0x14, 0x24, + 0x36, 0x2c, 0xbe, 0xe4, 0x11, 0xeb, 0x0e, 0x05, 0xd0, 0xfe, 0x2d, 0xc8, 0xf1, + 0x15, 0x17, 0x05, 0x7f, 0x17, 0xe1, 0xee, 0xfa, 0xf9, 0x22, 0x02, 0xfc, 0x2d, + 0xde, 0x37, 0x07, 0x0d, 0xef, 0x10, 0xdf, 0xfc, 0xc7, 0x42, 0xf4, 0x1d, 0xfe, + 0xfe, 0x04, 0xf9, 0x04, 0x3b, 0xd3, 0xf6, 0x54, 0xd0, 0xe5, 0xef, 0x2a, 0x13, + 0xd7, 0x0a, 0xde, 0xf3, 0x1c, 0x0b, 0x07, 0xae, 0xd7, 0xf4, 0x12, 0xe6, 0x18, + 0xa5, 0x16, 0xe3, 0xc7, 0xf7, 0xfa, 0x23, 0x06, 0x1a, 0x1d, 0xf0, 0x0a, 0x35, + 0x17, 0xef, 0xf6, 0x2f, 0xb1, 0xeb, 0x3a, 0xf6, 0x18, 0xed, 0x22, 0xff, 0xf0, + 0xee, 0x1c, 0xce, 0xdd, 0xe7, 0x1f, 0x0a, 0x0a, 0x23, 0x2e, 0xf2, 0xca, 0xff, + 0xd0, 0xf7, 0xef, 0x43, 0xdd, 0xf7, 0x7f, 0xe2, 0xfe, 0xe7, 0xe0, 0x07, 0xef, + 0xe1, 0xf6, 0x10, 0xef, 0xf2, 0x03, 0x9d, 0xef, 0x07, 0xf1, 0x4f, 0xf8, 0xfe, + 0x03, 0xf2, 0xf8, 0xf8, 0x02, 0xca, 0xaa, 0x53, 0x10, 0x1b, 0xfc, 0x08, 0x22, + 0xcc, 0xc1, 0xcf, 0xff, 0x00, 0xde, 0xea, 0x20, 0xcb, 0xfd, 0x12, 0xf3, 0xee, + 0xd5, 0xd0, 0xff, 0xf6, 0xff, 0x0a, 0xeb, 0xb2, 0xe6, 0x0e, 0xf5, 0x62, 0x02, + 0xff, 0x12, 0xdf, 0x13, 0x0c, 0x0b, 0x0a, 0xe6, 0xdc, 0x0b, 0x35, 0xea, 0x0d, + 0xd5, 0x12, 0xd8, 0xdd, 0x07, 0xf7, 0x23, 0xc5, 0x26, 0xbd, 0x25, 0xe9, 0xee, + 0x09, 0x0d, 0xb5, 0x13, 0xec, 0xc5, 0xe4, 0x03, 0x2a, 0x06, 0x18, 0xd0, 0xfb, + 0xe4, 0xf4, 0x30, 0x1f, 0x0d, 0x00, 0xfd, 0xef, 0xdb, 0x0a, 0x15, 0xe3, 0x18, + 0xfb, 0xed, 0x02, 0x39, 0x1b, 0x71, 0x53, 0xbb, 0xf3, 0x15, 0x1d, 0xd6, 0x3a, + 0x1d, 0x2f, 0x03, 0xd9, 0x1a, 0x0a, 0xf2, 0xe9, 0x1d, 0x2c, 0x4b, 0x10, 0x25, + 0xb4, 0x36, 0xd3, 0x04, 0xcd, 0x05, 0x18, 0xf0, 0xa9, 0xe7, 0xec, 0xdf, 0x0f, + 0xe5, 0x17, 0x1b, 0x4f, 0x21, 0x1a, 0x09, 0x11, 0xde, 0x32, 0xf8, 0xce, 0xfc, + 0x11, 0x00, 0x15, 0xbb, 0xf0, 0x03, 0xfd, 0x3c, 0x0a, 0xf3, 0xe5, 0x36, 0x1d, + 0xff, 0xe7, 0xe9, 0x03, 0xec, 0x32, 0x19, 0xcb, 0xd9, 0xc0, 0xe5, 0x49, 0x33, + 0x1f, 0xfa, 0xfe, 0xc8, 0x48, 0x2a, 0x0f, 0xd8, 0x1b, 0xda, 0xfc, 0xda, 0xfd, + 0xd8, 0x25, 0xc5, 0x2f, 0x01, 0xd0, 0x19, 0x05, 0x0a, 0xcd, 0xff, 0xf4, 0x19, + 0xfe, 0x0f, 0xfa, 0xf3, 0xe1, 0xd6, 0x17, 0xca, 0xe2, 0x7f, 0x23, 0x3e, 0x58, + 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xb0, 0xf8, 0xff, + 0xff, 0x83, 0xe2, 0xff, 0xff, 0xaa, 0x36, 0x00, 0x00, 0x77, 0x0c, 0x00, 0x00, + 0x9a, 0xfd, 0xff, 0xff, 0x9c, 0x0c, 0x00, 0x00, 0x0e, 0xde, 0xff, 0xff, 0xc0, + 0x1b, 0x00, 0x00, 0x7c, 0x04, 0x00, 0x00, 0x2e, 0xc5, 0xff, 0xff, 0xbe, 0x01, + 0x00, 0x00, 0xb1, 0x17, 0x00, 0x00, 0xb5, 0x0f, 0x00, 0x00, 0xf8, 0x48, 0x00, + 0x00, 0xc9, 0xfc, 0xff, 0xff, 0x57, 0xe2, 0xff, 0xff, 0x4b, 0x2a, 0x00, 0x00, + 0x08, 0xc1, 0xff, 0xff, 0xb2, 0x25, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, 0xe9, + 0x24, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0xeb, 0xef, 0xff, 0xff, 0x4f, 0x0b, + 0x00, 0x00, 0xcd, 0x27, 0x00, 0x00, 0x3a, 0x07, 0x00, 0x00, 0x77, 0x25, 0x00, + 0x00, 0x61, 0x07, 0x00, 0x00, 0x54, 0x1c, 0x00, 0x00, 0x24, 0xfd, 0xff, 0xff, + 0xd9, 0xe1, 0xff, 0xff, 0xe5, 0xda, 0xff, 0xff, 0x6e, 0xf4, 0xff, 0xff, 0x9f, + 0x37, 0x00, 0x00, 0x64, 0xdf, 0xff, 0xff, 0xbb, 0x1c, 0x00, 0x00, 0xb9, 0x1d, + 0x00, 0x00, 0x8d, 0x09, 0x00, 0x00, 0x2f, 0x30, 0x00, 0x00, 0x66, 0x00, 0x00, + 0x00, 0xb2, 0xf9, 0xff, 0xff, 0x0a, 0x41, 0x00, 0x00, 0x53, 0x21, 0x00, 0x00, + 0xf0, 0x1a, 0x00, 0x00, 0x58, 0x43, 0x00, 0x00, 0xe0, 0x0d, 0x00, 0x00, 0x09, + 0x3b, 0x00, 0x00, 0xee, 0x06, 0x00, 0x00, 0xfa, 0x34, 0x00, 0x00, 0x8f, 0xff, + 0xff, 0xff, 0xa5, 0xef, 0xff, 0xff, 0xb6, 0x0f, 0x00, 0x00, 0x21, 0x1b, 0x00, + 0x00, 0x96, 0x05, 0x00, 0x00, 0xed, 0xf8, 0xff, 0xff, 0x5f, 0x15, 0x00, 0x00, + 0xa0, 0xc4, 0xff, 0xff, 0xa2, 0xe0, 0xff, 0xff, 0x52, 0x06, 0x00, 0x00, 0xbc, + 0x33, 0x00, 0x00, 0x54, 0xb9, 0xff, 0xff, 0xd5, 0xfd, 0xff, 0xff, 0xe2, 0x13, + 0x00, 0x00, 0xc4, 0x29, 0x00, 0x00, 0x09, 0x43, 0x00, 0x00, 0x25, 0x26, 0x00, + 0x00, 0xd0, 0xec, 0xff, 0xff, 0xea, 0x15, 0x00, 0x00, 0x01, 0x1a, 0x00, 0x00, + 0xa2, 0x01, 0x00, 0x00, 0xde, 0xe7, 0xff, 0xff, 0x91, 0xe7, 0xff, 0xff, 0x4a, + 0x21, 0x00, 0x00, 0xf1, 0x25, 0x00, 0x00, 0xbb, 0x07, 0x00, 0x00, 0x1e, 0x04, + 0x00, 0x00, 0x2f, 0xe6, 0xff, 0xff, 0x31, 0x08, 0x00, 0x00, 0xa6, 0x1e, 0x00, + 0x00, 0x62, 0x1a, 0x00, 0x00, 0xc0, 0x17, 0x00, 0x00, 0xa5, 0x4d, 0x00, 0x00, + 0x6a, 0xe4, 0xff, 0xff, 0x4c, 0xf2, 0xff, 0xff, 0xad, 0x01, 0x00, 0x00, 0x94, + 0x22, 0x00, 0x00, 0x32, 0xe5, 0xff, 0xff, 0xd7, 0x3f, 0x00, 0x00, 0x80, 0xed, + 0xff, 0xff, 0x4f, 0x15, 0x00, 0x00, 0x08, 0xec, 0xff, 0xff, 0xc1, 0xe8, 0xff, + 0xff, 0x7d, 0xd4, 0xff, 0xff, 0x6e, 0xe7, 0xff, 0xff, 0x51, 0xd9, 0xff, 0xff, + 0x65, 0x2b, 0x00, 0x00, 0xc3, 0x13, 0x00, 0x00, 0x3e, 0xd4, 0xff, 0xff, 0x40, + 0x3e, 0x00, 0x00, 0xd7, 0xe5, 0xff, 0xff, 0x25, 0x53, 0x00, 0x00, 0xb2, 0xef, + 0xff, 0xff, 0x57, 0x1f, 0x00, 0x00, 0x0e, 0xf3, 0xff, 0xff, 0x71, 0x0a, 0x00, + 0x00, 0x0e, 0xfc, 0xff, 0xff, 0x43, 0x00, 0x00, 0x00, 0x60, 0x11, 0x00, 0x00, + 0x95, 0x09, 0x00, 0x00, 0xf8, 0x3a, 0x00, 0x00, 0x6b, 0x16, 0x00, 0x00, 0xe2, + 0xf2, 0xff, 0xff, 0x0b, 0xf8, 0xff, 0xff, 0x5c, 0xf6, 0xff, 0xff, 0xd7, 0x09, + 0x00, 0x00, 0x94, 0x26, 0x00, 0x00, 0xaa, 0x27, 0x00, 0x00, 0x40, 0x0d, 0x00, + 0x00, 0xd7, 0xf3, 0xff, 0xff, 0xa1, 0x1a, 0x00, 0x00, 0x97, 0xfa, 0xff, 0xff, + 0xce, 0xe1, 0xff, 0xff, 0x5e, 0x1c, 0x00, 0x00, 0x36, 0x13, 0x00, 0x00, 0xa1, + 0x37, 0x00, 0x00, 0xfe, 0x32, 0x00, 0x00, 0x9a, 0x26, 0x00, 0x00, 0x12, 0xf1, + 0xff, 0xff, 0x4a, 0x5a, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x0c, 0xb1, 0x0a, 0x7f, 0x0c, 0xfe, 0xf6, 0xff, 0x9a, 0xd5, 0xc9, 0x00, + 0xf8, 0xbc, 0xe4, 0xe0, 0x21, 0x28, 0x06, 0xed, 0x30, 0x1e, 0xca, 0xcf, 0x0f, + 0x05, 0xdb, 0xe9, 0xea, 0xd4, 0x0d, 0xb5, 0x30, 0xdd, 0xe8, 0x4b, 0xa3, 0xdc, + 0x1c, 0x2b, 0xf0, 0x3b, 0xcf, 0x1f, 0xda, 0x12, 0xfd, 0xfb, 0xd0, 0x20, 0xcb, + 0xb3, 0x12, 0x36, 0xd7, 0x35, 0xde, 0x03, 0x70, 0x03, 0x39, 0x05, 0xe8, 0xce, + 0x30, 0xf3, 0x3b, 0xfd, 0x35, 0x0b, 0x36, 0xaa, 0xff, 0xc6, 0x1a, 0xfd, 0x18, + 0x01, 0xc1, 0x2b, 0xc1, 0xfe, 0x0e, 0xef, 0x13, 0xd4, 0x04, 0x17, 0xde, 0xd9, + 0x01, 0xfb, 0xd7, 0xf8, 0xff, 0x0a, 0xf9, 0xf8, 0x0b, 0x23, 0xc1, 0x34, 0x52, + 0xd7, 0x2b, 0x8f, 0xe4, 0x39, 0x37, 0x39, 0xf5, 0xe4, 0x14, 0xed, 0xe2, 0x20, + 0xf8, 0x0f, 0x02, 0xba, 0x11, 0x24, 0xf7, 0x00, 0xc2, 0xf2, 0xe7, 0xf5, 0xb3, + 0xfa, 0xfa, 0xad, 0x42, 0x3c, 0x0d, 0x02, 0x20, 0x9f, 0x21, 0xb0, 0xfc, 0x22, + 0xf8, 0x29, 0xf9, 0x32, 0x1c, 0xf7, 0xbc, 0xff, 0xee, 0xa8, 0xfd, 0x31, 0x07, + 0x2b, 0x84, 0x03, 0xf6, 0x2e, 0xcc, 0xd9, 0x1e, 0x02, 0x0b, 0x10, 0x97, 0x49, + 0xcf, 0xcd, 0xd1, 0x38, 0xc5, 0xe6, 0xed, 0xb0, 0x2d, 0xdb, 0x2b, 0xfa, 0xf8, + 0xf0, 0xf5, 0xf5, 0x04, 0x44, 0x4f, 0xf1, 0x44, 0x44, 0xd0, 0x0f, 0x30, 0x27, + 0xaa, 0x22, 0x89, 0x00, 0xe5, 0x0f, 0xcb, 0x05, 0xef, 0x9e, 0xe9, 0xe5, 0xbd, + 0xe5, 0xd5, 0xe5, 0xd4, 0xd1, 0xff, 0xa6, 0xd8, 0x3a, 0xfb, 0x08, 0x09, 0xe9, + 0xde, 0x27, 0x54, 0xf2, 0xe4, 0x73, 0xe8, 0x0a, 0xfe, 0x1c, 0x61, 0x32, 0x22, + 0x16, 0xfe, 0xaf, 0x43, 0xcc, 0x1f, 0x26, 0x21, 0x50, 0x00, 0x7f, 0x05, 0xf0, + 0xf0, 0xf1, 0xad, 0x20, 0xfa, 0xe3, 0x40, 0xdc, 0xfc, 0x97, 0xef, 0xc5, 0x07, + 0x1f, 0xaf, 0xe6, 0xf5, 0x13, 0xf6, 0x08, 0x1e, 0xfe, 0xc4, 0xc7, 0x28, 0xde, + 0xf1, 0x11, 0xcb, 0x0c, 0x23, 0x1b, 0x15, 0x05, 0xe2, 0x00, 0x1e, 0xfd, 0x19, + 0xfc, 0x53, 0xe5, 0xfe, 0xb7, 0xab, 0x21, 0x0a, 0x46, 0x07, 0xcb, 0x3a, 0x1a, + 0x51, 0xfb, 0x01, 0xcd, 0xe6, 0xf7, 0xfc, 0xc3, 0x35, 0xcb, 0xf7, 0xd7, 0x21, + 0xe0, 0xfc, 0xea, 0x25, 0x9c, 0x24, 0xec, 0xfc, 0x4e, 0x1a, 0x21, 0x28, 0xb1, + 0xfd, 0xda, 0xde, 0x81, 0xf7, 0xc8, 0xe9, 0xaa, 0x1e, 0xd5, 0x4d, 0xf5, 0x36, + 0x05, 0x13, 0x03, 0x29, 0xfe, 0x09, 0x00, 0x05, 0xf0, 0xfc, 0xeb, 0xe2, 0xb9, + 0x27, 0x19, 0xd5, 0xca, 0xf9, 0xf8, 0x03, 0xee, 0x1c, 0xd9, 0xf5, 0xca, 0xf0, + 0xe0, 0xfa, 0xdb, 0x3d, 0x1f, 0x2b, 0x34, 0xf9, 0xe6, 0xd7, 0xdc, 0xd3, 0xfd, + 0xe9, 0xf2, 0xdd, 0x22, 0xcc, 0x2d, 0xff, 0xd5, 0xec, 0xda, 0x46, 0xb9, 0x5d, + 0x32, 0xda, 0xfe, 0xc0, 0xe1, 0x28, 0x28, 0x0c, 0x39, 0xec, 0x39, 0xf7, 0x25, + 0xf2, 0x0d, 0xf4, 0xcf, 0x22, 0xfa, 0x26, 0x11, 0x00, 0xb6, 0x81, 0x1e, 0x11, + 0xc1, 0xd6, 0x14, 0x1f, 0x12, 0x4f, 0xd0, 0xc7, 0xef, 0xf2, 0xd6, 0xf6, 0xed, + 0x1b, 0xfd, 0xda, 0xf3, 0x26, 0x08, 0xd4, 0x18, 0x2c, 0xc7, 0xf8, 0x15, 0xbd, + 0xf6, 0x24, 0x29, 0x0f, 0xa5, 0x1e, 0xcd, 0xd9, 0xf5, 0xa7, 0xea, 0x02, 0xd3, + 0x82, 0xf0, 0xfc, 0xdf, 0xbd, 0x45, 0x18, 0x70, 0x99, 0x21, 0x08, 0xc1, 0x1e, + 0xef, 0xee, 0xe7, 0x13, 0xbf, 0xcd, 0xe1, 0x30, 0xe7, 0xcf, 0xf3, 0x0e, 0x58, + 0xed, 0xd2, 0xf3, 0x10, 0xf1, 0x07, 0xe1, 0x06, 0xe5, 0xf8, 0xda, 0x2c, 0x05, + 0x03, 0xc2, 0xea, 0xfd, 0xc3, 0xf4, 0xe5, 0x5c, 0xf1, 0x06, 0xcc, 0x59, 0xd7, + 0x33, 0xda, 0x58, 0xee, 0xf6, 0xdf, 0x23, 0xc3, 0xde, 0xaf, 0xf4, 0x38, 0x2b, + 0x08, 0x43, 0xd8, 0x0d, 0x55, 0x22, 0x67, 0x5b, 0x54, 0xd2, 0xf9, 0x6b, 0xdf, + 0x18, 0x01, 0x0b, 0x1f, 0x5f, 0x01, 0xfc, 0x18, 0x2e, 0x15, 0x73, 0xea, 0xec, + 0x10, 0xa3, 0x9f, 0x19, 0xe8, 0xfe, 0x81, 0xff, 0xfd, 0x2c, 0xc1, 0xd7, 0xc6, + 0xf9, 0x47, 0xfa, 0x3f, 0x03, 0xd4, 0x11, 0x2c, 0xbe, 0xd9, 0xa0, 0x1c, 0x12, + 0xfc, 0x07, 0x03, 0x0e, 0xea, 0x4a, 0xe4, 0xb9, 0xab, 0xf6, 0xf9, 0x1c, 0xfe, + 0x08, 0xe7, 0xe6, 0xe5, 0xce, 0x22, 0xe3, 0x9a, 0xd8, 0xf6, 0x25, 0xbb, 0x95, + 0x5c, 0x09, 0xd1, 0xe1, 0x10, 0xf4, 0xe0, 0xca, 0x10, 0x19, 0xb4, 0xfe, 0x34, + 0x3a, 0xc7, 0x0e, 0xc1, 0xa2, 0x7a, 0xdd, 0xef, 0x39, 0xfc, 0x13, 0xdf, 0xad, + 0xea, 0xeb, 0xd7, 0x45, 0x1d, 0xd9, 0x13, 0x6b, 0x33, 0xb3, 0x33, 0xcb, 0xdb, + 0x94, 0x0a, 0x64, 0xf7, 0xee, 0x0b, 0x04, 0xdb, 0x55, 0x37, 0x2a, 0x66, 0xeb, + 0xb6, 0x13, 0xf2, 0xdb, 0x2d, 0xe9, 0x29, 0xff, 0xe9, 0x10, 0xe5, 0xc1, 0xf7, + 0xb3, 0x4b, 0xdc, 0x24, 0x10, 0xe2, 0xcc, 0xc5, 0xd2, 0xc2, 0xd2, 0x37, 0xe9, + 0xb5, 0x4a, 0x0e, 0x46, 0xda, 0x35, 0xca, 0x40, 0xf4, 0xcf, 0xcb, 0x05, 0xe1, + 0xa6, 0x1c, 0xce, 0x89, 0xc6, 0x4c, 0xe6, 0x32, 0x85, 0x0c, 0xaa, 0x16, 0xe6, + 0xef, 0x2d, 0xf2, 0x05, 0xb6, 0x5e, 0x2a, 0x39, 0x24, 0x96, 0x4c, 0xbd, 0xc8, + 0xea, 0x22, 0xb9, 0x01, 0x2a, 0x27, 0x12, 0xe8, 0xf3, 0xaa, 0x5e, 0x24, 0x26, + 0x01, 0xe2, 0xf5, 0x61, 0x31, 0x9e, 0xc4, 0x4c, 0xb4, 0x0f, 0xbf, 0xd8, 0xf2, + 0xe4, 0x10, 0x12, 0xa1, 0x48, 0xdd, 0xec, 0x3b, 0xc0, 0x9f, 0x4a, 0xb4, 0xf0, + 0x6c, 0x4b, 0xae, 0x12, 0x2b, 0xdc, 0x02, 0x8a, 0x6f, 0x08, 0xb1, 0x81, 0xb7, + 0x23, 0x42, 0xfc, 0x4b, 0xda, 0x64, 0xe5, 0xff, 0xc3, 0x32, 0x63, 0xc0, 0xdf, + 0xb6, 0x3d, 0xfc, 0xfa, 0xec, 0xea, 0x4d, 0x28, 0xe4, 0xdc, 0x47, 0xcb, 0xf6, + 0xb9, 0xfc, 0x06, 0x2d, 0xb2, 0xc0, 0xdb, 0x40, 0xcb, 0x2d, 0x15, 0xfb, 0xf9, + 0xfd, 0x39, 0x19, 0x19, 0x1c, 0xc5, 0x05, 0x03, 0xc1, 0x49, 0xe4, 0x05, 0x40, + 0x2f, 0xb8, 0x34, 0x81, 0xf8, 0xe6, 0xa2, 0xbb, 0xf4, 0xed, 0x5d, 0x0b, 0x1b, + 0x10, 0x1a, 0xfa, 0x5b, 0x01, 0xfc, 0xf2, 0xd6, 0xdb, 0x37, 0x0d, 0x4e, 0x32, + 0x36, 0xe1, 0x2a, 0x2a, 0x37, 0x3e, 0xd8, 0x1e, 0x53, 0xe8, 0x79, 0x1d, 0x23, + 0x15, 0x0e, 0x42, 0x40, 0xed, 0xca, 0x2c, 0x03, 0xe0, 0xbd, 0xda, 0x33, 0xfd, + 0x46, 0x25, 0xfd, 0x78, 0xd0, 0xc4, 0x29, 0xc6, 0xe7, 0xd8, 0x4c, 0xd4, 0xf7, + 0x28, 0x62, 0xcc, 0xef, 0x0d, 0x4f, 0xf1, 0x12, 0xdb, 0x12, 0xc9, 0xc8, 0xe8, + 0xbe, 0x7b, 0xf3, 0xc0, 0xe4, 0x16, 0x16, 0x3c, 0xd7, 0xe9, 0x01, 0xf5, 0x2a, + 0x19, 0x41, 0x9a, 0x8e, 0xc5, 0xd8, 0xec, 0xe4, 0x1f, 0xff, 0xdb, 0xf7, 0xbd, + 0x17, 0xfa, 0xda, 0x01, 0x06, 0x48, 0xf6, 0x2e, 0xcc, 0xc9, 0xbd, 0xf5, 0xdf, + 0x55, 0xf7, 0x12, 0xcf, 0xd4, 0x78, 0xb3, 0x11, 0x43, 0x37, 0x68, 0x47, 0xc6, + 0xf4, 0x1e, 0x4d, 0xc6, 0x3c, 0xb9, 0xb8, 0x21, 0x31, 0x02, 0x25, 0xe9, 0x18, + 0xec, 0x02, 0x81, 0x09, 0xf6, 0xec, 0x04, 0xff, 0xed, 0x26, 0xa4, 0x4f, 0x9f, + 0xba, 0x0d, 0x4d, 0x42, 0x3f, 0x3a, 0x28, 0x02, 0x48, 0x59, 0xdb, 0xdb, 0xf1, + 0xe7, 0x3f, 0x41, 0xaf, 0xba, 0x32, 0x8c, 0xcb, 0x2e, 0x23, 0xca, 0x20, 0x05, + 0x53, 0x00, 0x03, 0xc2, 0x15, 0x1f, 0xa6, 0xaf, 0x21, 0xe1, 0xc0, 0xb0, 0xc8, + 0xde, 0xa9, 0x43, 0xd7, 0x33, 0x03, 0x1f, 0x43, 0xb1, 0x09, 0x9e, 0x0c, 0x14, + 0x0d, 0xbc, 0x36, 0x10, 0x0d, 0x13, 0xc6, 0xe3, 0x4f, 0x1d, 0xd1, 0xc8, 0xca, + 0x08, 0xee, 0xb1, 0x07, 0x23, 0xe7, 0x04, 0x0d, 0x04, 0x1a, 0x15, 0x00, 0x3f, + 0x06, 0xf4, 0xc9, 0xde, 0x08, 0xd3, 0x74, 0x10, 0x1d, 0x2f, 0x27, 0xa3, 0xf4, + 0xc4, 0xff, 0xe8, 0x02, 0x1f, 0x0e, 0xe7, 0xfd, 0x23, 0x08, 0xd9, 0xe5, 0xb8, + 0xba, 0xf4, 0x3e, 0xca, 0xe9, 0xc6, 0xe7, 0xaf, 0x15, 0x20, 0xed, 0x7b, 0xd8, + 0x02, 0x06, 0xf3, 0xa2, 0x39, 0xf3, 0x81, 0xeb, 0xce, 0xef, 0xf8, 0x22, 0x25, + 0xf5, 0xde, 0x12, 0xf1, 0x14, 0x47, 0xe0, 0xf0, 0xf6, 0xfe, 0xba, 0xec, 0xea, + 0xe6, 0x2e, 0x0f, 0x10, 0x1a, 0x58, 0xef, 0xf9, 0x0e, 0x0c, 0xc2, 0xe2, 0xd3, + 0xee, 0xfc, 0x12, 0x1c, 0x3d, 0xdf, 0xd9, 0x35, 0x1a, 0xe6, 0x0b, 0x21, 0xc6, + 0x0a, 0x07, 0xeb, 0xc5, 0xe2, 0x33, 0xef, 0x0b, 0xed, 0x1b, 0x23, 0x03, 0x1e, + 0xdb, 0x10, 0xde, 0xc2, 0x7f, 0x2d, 0xe8, 0xa9, 0x15, 0x03, 0xe2, 0xd0, 0x41, + 0x5c, 0x1d, 0xdf, 0xff, 0x0e, 0xea, 0xe1, 0xc6, 0xef, 0x15, 0x09, 0x1a, 0x21, + 0x14, 0xec, 0xfa, 0xe9, 0xe8, 0x1c, 0x75, 0x1b, 0xb6, 0x2c, 0x11, 0x25, 0xfd, + 0x37, 0x12, 0xc5, 0xcd, 0x1f, 0x1d, 0x24, 0xd9, 0x25, 0x1c, 0xb0, 0xfb, 0x03, + 0xca, 0x13, 0x13, 0x22, 0x09, 0x08, 0x33, 0x13, 0xfe, 0xd7, 0x4a, 0xfc, 0xcc, + 0xfa, 0x04, 0xee, 0xe8, 0xbb, 0xc7, 0xfa, 0xdf, 0x13, 0xd8, 0xed, 0x20, 0x1b, + 0xbc, 0x09, 0xf3, 0x1c, 0x05, 0x3c, 0x55, 0xef, 0x24, 0x1a, 0x18, 0x65, 0xe0, + 0x31, 0xcb, 0x21, 0x41, 0x0a, 0x18, 0xf9, 0xed, 0xf0, 0x20, 0xee, 0x01, 0x28, + 0xe0, 0xc6, 0xc7, 0xc2, 0xf6, 0xee, 0x07, 0x40, 0xe7, 0xf7, 0xfc, 0x2a, 0xf3, + 0x15, 0x53, 0x0e, 0x09, 0xd9, 0x18, 0xcf, 0x02, 0x0f, 0x21, 0xfe, 0xfe, 0x04, + 0xf1, 0xc4, 0x47, 0xd7, 0x1f, 0xf9, 0xfd, 0x08, 0x41, 0xf5, 0xe7, 0xed, 0x1b, + 0x03, 0xc8, 0xe0, 0xf6, 0xf5, 0x05, 0x23, 0x03, 0x33, 0x2a, 0x11, 0x2b, 0xfe, + 0x23, 0x03, 0xf9, 0x08, 0x20, 0xc7, 0xfd, 0xeb, 0xf9, 0xf4, 0x0b, 0x0a, 0xfa, + 0xcb, 0x33, 0x08, 0xf1, 0x26, 0xdf, 0xf8, 0x09, 0xbc, 0x03, 0x13, 0x4e, 0xfc, + 0x1e, 0xf0, 0x29, 0x0e, 0x16, 0x31, 0x1b, 0xfb, 0x0b, 0x06, 0xed, 0xcf, 0xf3, + 0xc5, 0x16, 0x05, 0x05, 0xec, 0xfd, 0x1c, 0x37, 0xd2, 0xe2, 0x1b, 0x03, 0x24, + 0xfa, 0x3f, 0x1e, 0xf9, 0xe2, 0x1f, 0x05, 0xcc, 0x02, 0x7f, 0xff, 0xfe, 0x09, + 0x4f, 0x23, 0x00, 0x18, 0x0a, 0x01, 0x42, 0x05, 0xea, 0xd1, 0xdc, 0xfb, 0x16, + 0x3f, 0x23, 0x00, 0xe6, 0xf7, 0x0a, 0x1e, 0xdd, 0x02, 0x18, 0xf9, 0x14, 0xdd, + 0xf2, 0x31, 0x19, 0xfd, 0x2e, 0xf7, 0xf4, 0xe7, 0x24, 0x9e, 0xd1, 0x05, 0x5c, + 0xde, 0xb1, 0x1a, 0xe0, 0x32, 0xb6, 0x05, 0x0b, 0x14, 0x46, 0xde, 0x3a, 0xe4, + 0xfa, 0x14, 0xe2, 0xe2, 0xdc, 0x32, 0x02, 0xd1, 0x21, 0xfd, 0x14, 0x22, 0x13, + 0x02, 0xfd, 0x08, 0x9a, 0x02, 0xd1, 0x4b, 0xf3, 0xe4, 0x13, 0xc1, 0xcb, 0x09, + 0x02, 0xec, 0xbb, 0x17, 0x25, 0x81, 0x48, 0x27, 0xea, 0xcd, 0x0e, 0x18, 0xdc, + 0x17, 0x04, 0x15, 0x38, 0x04, 0xeb, 0xd3, 0xe2, 0xf6, 0xac, 0xe8, 0xbf, 0xb9, + 0x3f, 0xed, 0xe4, 0xee, 0x2c, 0x13, 0x11, 0xee, 0xba, 0x0f, 0x14, 0x07, 0xc1, + 0x0f, 0xde, 0xea, 0xe4, 0x57, 0xfb, 0x00, 0x27, 0x3d, 0x31, 0x1e, 0x3d, 0xf0, + 0x0e, 0x0b, 0x15, 0xdc, 0xcc, 0xd5, 0x27, 0x6f, 0xf7, 0xe6, 0xfb, 0x32, 0x56, + 0xf8, 0xe0, 0xcc, 0x48, 0x06, 0x1e, 0xfb, 0x08, 0xf9, 0xff, 0x1e, 0x03, 0x1b, + 0x17, 0xa0, 0x6a, 0xc6, 0x63, 0x0d, 0x62, 0xd6, 0xd1, 0xc9, 0xea, 0x35, 0x41, + 0xe8, 0x0c, 0x12, 0x32, 0xe1, 0xe1, 0x12, 0x70, 0xff, 0x05, 0x35, 0x19, 0xf1, + 0xf3, 0x07, 0xec, 0x0e, 0xd5, 0xe6, 0xed, 0x6d, 0xd5, 0xf9, 0x32, 0xea, 0x30, + 0xb9, 0xe5, 0x3d, 0xe2, 0xe3, 0xfb, 0xd2, 0x05, 0x23, 0xcc, 0x9c, 0xa5, 0xc5, + 0xe9, 0x03, 0x1d, 0x52, 0xe0, 0x09, 0x0b, 0xe4, 0xeb, 0xd5, 0xba, 0x12, 0x1d, + 0xdd, 0x19, 0x25, 0xbb, 0xba, 0x2b, 0x4c, 0xf8, 0xbe, 0xe3, 0xf3, 0x32, 0xff, + 0xb0, 0x31, 0x0c, 0x21, 0x0f, 0x0e, 0x3b, 0x0d, 0xc1, 0x0a, 0xc9, 0x15, 0x91, + 0x17, 0xd4, 0x19, 0x99, 0xea, 0xb4, 0xdb, 0x3c, 0x10, 0xef, 0xaa, 0x04, 0xf8, + 0xfe, 0x04, 0xd3, 0xf4, 0x36, 0xf9, 0x7f, 0xc4, 0xf0, 0x29, 0xd9, 0x0d, 0x00, + 0xc1, 0x31, 0xf3, 0xee, 0x23, 0x27, 0x37, 0xe6, 0xd1, 0xcf, 0xe0, 0xfb, 0xc8, + 0x2a, 0x36, 0x17, 0xd0, 0xcf, 0xfa, 0xe1, 0x34, 0x0d, 0x1a, 0x01, 0x2a, 0xe4, + 0xf2, 0xf8, 0x10, 0x49, 0xd8, 0xff, 0x18, 0xea, 0x2c, 0xf4, 0xb5, 0x37, 0x00, + 0x14, 0x13, 0xed, 0xfe, 0xd4, 0x9f, 0xf6, 0xf3, 0xd5, 0xbc, 0x0f, 0xe8, 0xb5, + 0x1e, 0x1a, 0x48, 0x10, 0x27, 0xc7, 0xf0, 0x26, 0xea, 0x40, 0xf8, 0x0c, 0x53, + 0x00, 0xdf, 0x28, 0xdf, 0xf3, 0xbc, 0x19, 0xf5, 0x1d, 0x98, 0x33, 0xfa, 0xeb, + 0x1c, 0xeb, 0xbb, 0x03, 0xf7, 0x45, 0x11, 0x27, 0x08, 0xfd, 0x06, 0x0b, 0xe3, + 0xd9, 0xf1, 0xb0, 0xff, 0xe5, 0xf0, 0xed, 0x08, 0x29, 0xc5, 0x05, 0xf1, 0xd5, + 0x1a, 0xd7, 0xc8, 0xcb, 0x7f, 0x81, 0xea, 0xe3, 0xef, 0xb9, 0xef, 0x1a, 0x10, + 0xe0, 0x2c, 0xd0, 0x34, 0x4d, 0xf2, 0x08, 0x25, 0xff, 0xb5, 0x0d, 0xfe, 0xd8, + 0x13, 0x50, 0x2f, 0x2c, 0xee, 0x68, 0xdd, 0x3c, 0x03, 0xf1, 0xf5, 0x3b, 0xe9, + 0xc4, 0xf4, 0x33, 0x06, 0xe1, 0xfd, 0x21, 0xb7, 0xf7, 0x15, 0xf9, 0xc0, 0xf9, + 0xd2, 0x1a, 0xfb, 0xbe, 0xd5, 0x37, 0x20, 0x02, 0xe4, 0x2b, 0xef, 0xe6, 0xec, + 0xad, 0xc2, 0xf6, 0xe7, 0x08, 0x15, 0xe3, 0x5f, 0xdc, 0xff, 0xaa, 0xfa, 0x02, + 0x1c, 0xf8, 0xf9, 0x12, 0x1a, 0x42, 0xc0, 0x00, 0x34, 0x02, 0x02, 0x27, 0x3c, + 0xeb, 0x11, 0x59, 0xd4, 0xea, 0x33, 0x1e, 0xb7, 0x07, 0x32, 0x01, 0xf5, 0x28, + 0x7f, 0x09, 0x0b, 0xde, 0xe8, 0x46, 0x54, 0xa0, 0xff, 0x08, 0x15, 0x19, 0x02, + 0x12, 0xa5, 0xd4, 0x05, 0xbe, 0x1f, 0x2d, 0xae, 0xd4, 0x2c, 0x29, 0xe9, 0xe3, + 0x18, 0x9e, 0x49, 0x4a, 0xe8, 0xe5, 0xbc, 0x84, 0xbe, 0x47, 0x3f, 0xb9, 0x25, + 0xc5, 0xbe, 0x19, 0xeb, 0x36, 0xf3, 0xe2, 0x0f, 0x10, 0x32, 0xe9, 0x04, 0x1a, + 0xe9, 0xe2, 0xc2, 0xf7, 0x22, 0x02, 0xff, 0xfa, 0xff, 0xcb, 0x0b, 0xcd, 0x08, + 0xd2, 0xf2, 0x17, 0xf4, 0x30, 0x30, 0x29, 0xdd, 0xc0, 0xfa, 0xed, 0x04, 0xff, + 0xfd, 0x2c, 0x02, 0xc6, 0x09, 0x01, 0x03, 0x3b, 0x00, 0x0e, 0x01, 0xe1, 0xd8, + 0x0d, 0x2c, 0x02, 0x0c, 0xe4, 0xf6, 0x2e, 0x39, 0xe1, 0xc3, 0x33, 0xfa, 0xe0, + 0xd7, 0x17, 0x00, 0x10, 0x29, 0x2c, 0xec, 0x43, 0xfe, 0xc6, 0x19, 0xe1, 0x18, + 0x51, 0xec, 0x0e, 0x3b, 0xda, 0xf1, 0xb5, 0xd7, 0xfc, 0xb1, 0xe7, 0x4d, 0xcb, + 0xf8, 0xe1, 0xb9, 0xec, 0x09, 0xb4, 0xd5, 0x53, 0x23, 0xc5, 0x2d, 0x1b, 0xaf, + 0xd8, 0xc8, 0xf3, 0x14, 0x50, 0x03, 0xf9, 0x2d, 0x1c, 0xe0, 0x0a, 0xda, 0xd7, + 0xf4, 0x29, 0x37, 0x26, 0xec, 0xc4, 0x07, 0x17, 0x58, 0xef, 0x2f, 0xfc, 0x17, + 0x23, 0xe4, 0x55, 0x39, 0x0c, 0x32, 0x0d, 0xc1, 0x0c, 0x4a, 0x12, 0x02, 0xf7, + 0x12, 0x25, 0x03, 0xfa, 0x7f, 0x21, 0x03, 0xd2, 0x49, 0x29, 0x07, 0xa4, 0x24, + 0x11, 0xfb, 0xd2, 0x01, 0x02, 0xf7, 0x04, 0x12, 0xe0, 0x03, 0x14, 0x40, 0x11, + 0xea, 0x15, 0x03, 0x43, 0xe1, 0x23, 0xed, 0xdb, 0xe1, 0xe8, 0xe9, 0x00, 0x3e, + 0xd3, 0x6b, 0xdc, 0xe1, 0x05, 0x0a, 0xe5, 0xe8, 0xda, 0xf4, 0xcb, 0x00, 0x7f, + 0x45, 0xfc, 0x37, 0x36, 0xcd, 0x05, 0x09, 0xc8, 0x33, 0x56, 0x02, 0xd9, 0xda, + 0xfe, 0x04, 0xeb, 0x07, 0xd4, 0xdf, 0xd0, 0x07, 0xe4, 0xf7, 0x10, 0x38, 0x14, + 0xd6, 0x1b, 0x44, 0x22, 0xdf, 0xef, 0x19, 0xde, 0xf2, 0xdb, 0x04, 0x19, 0xd4, + 0x35, 0xf9, 0xd6, 0xba, 0x02, 0xe8, 0xcc, 0xec, 0x35, 0x0f, 0x2e, 0xf1, 0xf5, + 0xef, 0xdc, 0x0b, 0xcb, 0xe3, 0x16, 0x05, 0xce, 0xff, 0x07, 0xae, 0x45, 0xe9, + 0x1e, 0x0d, 0xc5, 0x33, 0x27, 0xd4, 0x21, 0x2c, 0x05, 0xed, 0xdd, 0xe6, 0xf4, + 0x29, 0xc4, 0xf0, 0xc7, 0xca, 0x21, 0x68, 0xf9, 0x09, 0x01, 0xc4, 0xf8, 0xf5, + 0x9a, 0x22, 0x0b, 0x2c, 0xf1, 0x18, 0xfa, 0x37, 0x0b, 0x03, 0x28, 0xcf, 0x05, + 0x20, 0x15, 0xe8, 0x42, 0xe7, 0xe0, 0x02, 0x98, 0xa1, 0x50, 0x1b, 0x16, 0x5a, + 0x22, 0xb6, 0x2c, 0x61, 0xea, 0xce, 0x96, 0x45, 0xfd, 0xd2, 0xfe, 0xff, 0xbd, + 0xee, 0x54, 0xff, 0xf6, 0x17, 0x20, 0xf5, 0x31, 0x22, 0xe8, 0xbd, 0xfa, 0xfc, + 0xb5, 0xe1, 0xad, 0x07, 0xe0, 0xf2, 0xf4, 0x1b, 0xb0, 0x22, 0xfd, 0x11, 0x35, + 0x38, 0xb8, 0xb9, 0xcf, 0x03, 0x2d, 0x10, 0xd8, 0x16, 0xb7, 0x04, 0x2a, 0x4f, + 0x06, 0x03, 0x1c, 0x5f, 0xfc, 0x11, 0x23, 0xe0, 0xe9, 0x33, 0x73, 0x2f, 0x40, + 0x31, 0xbe, 0x10, 0xd8, 0xd4, 0x1e, 0xea, 0xd5, 0xf4, 0x0e, 0x3c, 0x5d, 0xcb, + 0xd1, 0xef, 0x92, 0xf6, 0x2c, 0xdc, 0x03, 0x1c, 0xfa, 0x7f, 0xdd, 0xd9, 0xc0, + 0xea, 0xe6, 0xf4, 0xea, 0xf9, 0xd4, 0x01, 0xde, 0xc4, 0xfc, 0x01, 0x07, 0xd7, + 0xd3, 0xef, 0xe5, 0x1b, 0x2f, 0x29, 0x2a, 0xdb, 0x3d, 0x1a, 0xc2, 0xf7, 0xf2, + 0x12, 0xe2, 0x30, 0x3f, 0x21, 0x0d, 0xda, 0xfa, 0x0a, 0x55, 0xdd, 0xfa, 0x1f, + 0xd0, 0xfd, 0xc3, 0xfd, 0x35, 0xfb, 0x2b, 0xeb, 0xe3, 0xf9, 0x42, 0xed, 0x1a, + 0x12, 0x3a, 0x19, 0xa6, 0x4e, 0x27, 0x13, 0x1e, 0xe4, 0xf8, 0x66, 0x57, 0x70, + 0x93, 0x8a, 0xeb, 0x03, 0xb7, 0xfd, 0x64, 0x1b, 0xde, 0xfd, 0x20, 0xd2, 0x49, + 0xc8, 0x27, 0x12, 0x05, 0x24, 0x21, 0x15, 0x0e, 0x0a, 0x1a, 0xfb, 0x68, 0xcb, + 0xd1, 0x0d, 0xf3, 0xf7, 0x7f, 0x71, 0xc7, 0x0b, 0xd7, 0x35, 0xfd, 0xd0, 0xcb, + 0x1d, 0x19, 0xdc, 0x1c, 0x35, 0xe0, 0xcd, 0xfb, 0x13, 0x43, 0x32, 0x4a, 0xfa, + 0x21, 0xf8, 0x07, 0x4e, 0x1a, 0xf8, 0xe7, 0xbf, 0x06, 0xec, 0xeb, 0x29, 0x21, + 0xd4, 0x38, 0x1e, 0xd7, 0x0a, 0x81, 0xe0, 0x00, 0x12, 0xf7, 0x6b, 0xd5, 0xf9, + 0x0e, 0xee, 0x09, 0x08, 0x12, 0xee, 0x3d, 0x39, 0x0b, 0xe7, 0x12, 0x18, 0x34, + 0x19, 0x08, 0x0b, 0xfb, 0x33, 0xe2, 0x39, 0x2f, 0x01, 0xda, 0xfc, 0xde, 0x0a, + 0xfe, 0x1e, 0xf9, 0xeb, 0x2f, 0xbc, 0xed, 0xf3, 0xc1, 0x05, 0x2c, 0xea, 0xf2, + 0xfb, 0xe0, 0xf5, 0xf2, 0x11, 0x22, 0xd4, 0x67, 0x02, 0x1e, 0x14, 0xdc, 0x1b, + 0xf4, 0xc2, 0xf5, 0xcf, 0x04, 0x44, 0x36, 0xe7, 0xdd, 0xc4, 0xde, 0x10, 0xe1, + 0xf6, 0x20, 0x2f, 0x17, 0x11, 0xfe, 0xfc, 0x03, 0xd9, 0x5b, 0x16, 0xff, 0xdc, + 0xf6, 0xfb, 0xdc, 0xda, 0x0e, 0x15, 0x14, 0xfc, 0x3b, 0xe3, 0xc8, 0x6f, 0x22, + 0x9d, 0xf3, 0xf7, 0x28, 0x44, 0x0b, 0x19, 0x21, 0xf7, 0xfe, 0x0f, 0xe0, 0x36, + 0xd3, 0x32, 0xe4, 0xdf, 0x32, 0x31, 0x07, 0xdf, 0xd3, 0xe1, 0x48, 0xe6, 0xde, + 0x08, 0xda, 0xd9, 0xf2, 0x1c, 0x06, 0xbe, 0xfc, 0x19, 0xd7, 0xe8, 0x03, 0xf2, + 0x04, 0x2a, 0x06, 0x1d, 0x0b, 0x1a, 0x21, 0x20, 0x47, 0xfe, 0x32, 0xc4, 0x17, + 0x13, 0x03, 0x26, 0xc3, 0xd6, 0xff, 0xe2, 0x81, 0x2b, 0xe9, 0xfc, 0x01, 0xf0, + 0x37, 0x11, 0x16, 0xb9, 0x01, 0xf5, 0x0c, 0xdf, 0x07, 0xd6, 0xe8, 0x3d, 0xf2, + 0xeb, 0xd5, 0x09, 0xfa, 0xc6, 0xf0, 0xe5, 0xfa, 0x24, 0x0e, 0xef, 0xdc, 0x07, + 0xfb, 0x64, 0x54, 0xd4, 0xf0, 0x26, 0x5d, 0xd0, 0xd8, 0xe5, 0xe7, 0x2b, 0xe9, + 0x13, 0x1d, 0x69, 0x4c, 0x2f, 0x68, 0x18, 0xd4, 0x62, 0x31, 0x33, 0x3e, 0xf1, + 0x42, 0x25, 0x90, 0xd6, 0x6b, 0xdf, 0xef, 0xc4, 0x0d, 0x05, 0x04, 0x32, 0x20, + 0x17, 0x13, 0x0f, 0xcb, 0x09, 0x04, 0x18, 0x1f, 0x21, 0x51, 0xe9, 0xdf, 0x18, + 0xa4, 0x30, 0xfd, 0xba, 0xb9, 0xca, 0x5f, 0xe7, 0xd9, 0xc7, 0x94, 0x30, 0x23, + 0xfb, 0x1d, 0xd8, 0xf7, 0xf3, 0xb1, 0x3e, 0xfa, 0xf9, 0xcb, 0x09, 0x33, 0x34, + 0xe3, 0xf3, 0x27, 0xf6, 0xf5, 0xf7, 0xd2, 0xfa, 0xe4, 0xdf, 0xd7, 0x42, 0xca, + 0x11, 0x11, 0x2e, 0x3c, 0x12, 0x3f, 0xcf, 0x0e, 0xf4, 0xd5, 0x23, 0xf1, 0x2c, + 0x1b, 0x14, 0xdb, 0xf7, 0xfe, 0xec, 0x00, 0xc4, 0xe4, 0x01, 0x04, 0x1d, 0xe9, + 0x2c, 0xde, 0x1e, 0x28, 0xe0, 0xe9, 0x06, 0xf4, 0x34, 0xf3, 0xf5, 0xdf, 0xb1, + 0x0d, 0x20, 0xd5, 0x21, 0xf3, 0x31, 0x57, 0xfd, 0x09, 0x17, 0x2a, 0x21, 0xe3, + 0xf2, 0xf8, 0x0d, 0xcc, 0x0d, 0x45, 0x05, 0x05, 0x13, 0x05, 0x25, 0x06, 0xe5, + 0x0d, 0xd4, 0xe7, 0x1e, 0x2c, 0x1f, 0x24, 0x1f, 0xe5, 0x0f, 0x19, 0xe5, 0xfd, + 0x0b, 0xd8, 0x20, 0xd8, 0x0a, 0x30, 0x32, 0xde, 0x02, 0xc0, 0xee, 0xf5, 0x32, + 0x12, 0x7f, 0x0d, 0x0a, 0xc0, 0x01, 0x05, 0xfb, 0x05, 0x13, 0xf9, 0xf9, 0x72, + 0x09, 0x3e, 0x1f, 0xf8, 0x40, 0x28, 0x3c, 0x1a, 0x26, 0xde, 0xf6, 0xc6, 0x27, + 0x28, 0xc7, 0x28, 0x31, 0x0b, 0x28, 0x21, 0xe5, 0xd0, 0x08, 0x1e, 0x69, 0x42, + 0xf0, 0x0b, 0x21, 0x2f, 0xe3, 0xf0, 0x17, 0xd7, 0xdb, 0xc8, 0x02, 0x3b, 0x4b, + 0xe5, 0xe5, 0xe9, 0xfc, 0x0d, 0x0c, 0xf1, 0xf1, 0xd3, 0xe5, 0xc5, 0x3b, 0xd8, + 0x3d, 0xfc, 0x0f, 0x03, 0xfa, 0x1f, 0xf4, 0x1a, 0x09, 0x24, 0xf4, 0xad, 0xeb, + 0x23, 0x6a, 0xee, 0x59, 0x69, 0x1d, 0xf9, 0x3d, 0xe3, 0x11, 0x64, 0x4b, 0x15, + 0x1e, 0x7f, 0x3e, 0x14, 0x05, 0xfc, 0x0a, 0x0b, 0x70, 0xf3, 0x0f, 0x29, 0x35, + 0xec, 0x1a, 0x5b, 0x26, 0x20, 0x33, 0xb8, 0x32, 0x05, 0xf6, 0xd2, 0xfc, 0xcc, + 0x22, 0x89, 0x01, 0x43, 0x0b, 0x04, 0x41, 0x3e, 0xf6, 0x00, 0xea, 0x15, 0x2a, + 0xf1, 0xf4, 0xa8, 0x24, 0xf1, 0xe0, 0x21, 0xae, 0xd7, 0xf1, 0xe6, 0x7f, 0x51, + 0xc4, 0x46, 0x00, 0x27, 0x41, 0xb9, 0xf4, 0x20, 0xfb, 0xdf, 0xdc, 0x16, 0xfa, + 0xb7, 0xf1, 0x0c, 0x0d, 0xe2, 0x02, 0xe4, 0xf8, 0x5c, 0xfd, 0x0b, 0x25, 0xcb, + 0xb4, 0xed, 0xd8, 0x98, 0x4e, 0xf2, 0xd1, 0x00, 0x32, 0xd2, 0x45, 0x1d, 0xff, + 0x9c, 0xec, 0x65, 0x26, 0x28, 0x16, 0x32, 0x29, 0x2d, 0x11, 0x2c, 0xce, 0xef, + 0x11, 0xfe, 0xc9, 0x1e, 0xec, 0x58, 0xfd, 0x2f, 0xe8, 0xbf, 0x38, 0x4c, 0x1d, + 0x18, 0xde, 0xb2, 0xd6, 0xa0, 0xe8, 0x2c, 0xf1, 0x2f, 0xe4, 0xab, 0x61, 0x0f, + 0x36, 0xc4, 0xc3, 0x09, 0x0d, 0xd6, 0xbb, 0x03, 0xfa, 0xfd, 0x27, 0xcf, 0xc1, + 0x53, 0xdf, 0x3e, 0x02, 0x1d, 0x1e, 0xf5, 0x39, 0x0e, 0x79, 0x09, 0x13, 0xe6, + 0x47, 0xd5, 0xe8, 0x31, 0x5f, 0x03, 0x1b, 0x1a, 0x3e, 0x04, 0xfa, 0xf6, 0x41, + 0x12, 0xef, 0x5a, 0x47, 0x16, 0xed, 0xfc, 0x18, 0x11, 0x1d, 0xdc, 0xd5, 0xfd, + 0xaa, 0xc3, 0xeb, 0x3f, 0xe0, 0xcf, 0xf9, 0x41, 0xac, 0x13, 0x1c, 0x02, 0x24, + 0x1a, 0xfe, 0x81, 0x3b, 0x1a, 0x1a, 0x2a, 0xd4, 0x20, 0xdf, 0xc7, 0x37, 0xa8, + 0xe6, 0xa4, 0xdc, 0xb3, 0x17, 0xe6, 0x23, 0xd7, 0x03, 0xdb, 0xdd, 0x16, 0x14, + 0xf0, 0xf1, 0x11, 0xff, 0x4b, 0x66, 0xf4, 0x09, 0xe8, 0x00, 0x12, 0xe3, 0x12, + 0xae, 0x09, 0xbb, 0x25, 0x02, 0xd1, 0x20, 0x17, 0x05, 0x33, 0x5c, 0x34, 0xc0, + 0xb0, 0xf4, 0x0e, 0x11, 0xd9, 0xcd, 0x28, 0xbf, 0xe2, 0xfd, 0xa8, 0x05, 0xe5, + 0x1e, 0x0e, 0x0b, 0x10, 0xfd, 0x14, 0x2c, 0xd8, 0xbc, 0xcd, 0x58, 0x4d, 0xaa, + 0xc4, 0x04, 0x30, 0xea, 0x01, 0x46, 0xef, 0x60, 0x3d, 0xe8, 0x39, 0xbb, 0x21, + 0xee, 0x31, 0x41, 0xa8, 0xdc, 0x27, 0xf8, 0xe7, 0xf5, 0x0a, 0xf6, 0x3b, 0xdd, + 0xe8, 0xf8, 0xea, 0x2f, 0xc8, 0xdf, 0xe9, 0x09, 0x2a, 0x0f, 0xff, 0x06, 0x0d, + 0xdf, 0x01, 0xc4, 0xf9, 0xdc, 0x30, 0x0b, 0xe0, 0xcf, 0xf8, 0x02, 0x0c, 0xec, + 0xd6, 0x1b, 0x19, 0xee, 0xfe, 0x19, 0x0b, 0x5d, 0xd8, 0x53, 0x2b, 0xb0, 0x3f, + 0x11, 0xb5, 0xb8, 0x2f, 0xad, 0xe5, 0xfd, 0x2a, 0x00, 0xd3, 0x45, 0x0b, 0x00, + 0xba, 0xeb, 0xd1, 0x36, 0xea, 0x2f, 0x08, 0x99, 0xed, 0x7f, 0x1a, 0x2e, 0xff, + 0x29, 0x04, 0x0e, 0x1b, 0x05, 0xba, 0xd5, 0x27, 0xaf, 0xf9, 0x24, 0x5b, 0xf6, + 0x7a, 0x42, 0x12, 0xc3, 0x5c, 0xf6, 0x07, 0x21, 0x0e, 0x38, 0x15, 0x20, 0xe0, + 0xf4, 0xe5, 0xde, 0xe1, 0xc2, 0xda, 0xe0, 0xe7, 0xde, 0xcb, 0xf7, 0xfe, 0xd3, + 0x02, 0x49, 0x21, 0x02, 0x4b, 0x9d, 0x07, 0x44, 0x8f, 0x16, 0x47, 0x2b, 0xfe, + 0x17, 0x22, 0x4a, 0xff, 0xd6, 0xe7, 0x8e, 0xf7, 0x31, 0xff, 0x24, 0x17, 0x2c, + 0xdb, 0xfd, 0x4c, 0xb6, 0x40, 0xc5, 0xe6, 0x0f, 0x1f, 0xc4, 0x3c, 0xba, 0xf9, + 0x05, 0x03, 0xee, 0x09, 0x09, 0x11, 0xde, 0xfb, 0xd8, 0x06, 0xe1, 0x30, 0x0a, + 0xf5, 0x20, 0xc9, 0xd5, 0x04, 0x13, 0xe9, 0x00, 0xef, 0xfb, 0x12, 0x03, 0x09, + 0x2b, 0xbe, 0xd8, 0x02, 0x0d, 0xf4, 0x23, 0xc5, 0xfd, 0x1d, 0xe1, 0xef, 0x27, + 0xe4, 0x11, 0xcc, 0x30, 0x10, 0x36, 0xe5, 0x20, 0x1c, 0x06, 0x26, 0x1d, 0xfe, + 0x15, 0xd5, 0xe4, 0xbf, 0x18, 0xda, 0xd6, 0x10, 0x14, 0xda, 0xcb, 0xeb, 0xea, + 0x15, 0xf3, 0x08, 0x59, 0x25, 0xf5, 0x19, 0x2a, 0xf8, 0xdb, 0x00, 0x7f, 0x0c, + 0xf1, 0xe1, 0x26, 0x00, 0xfc, 0xfb, 0x05, 0xf8, 0xae, 0x05, 0xf2, 0xe5, 0xfc, + 0xf2, 0xfb, 0xfc, 0xf7, 0xf6, 0xe4, 0x17, 0x31, 0xc3, 0xf3, 0xf7, 0xd0, 0x69, + 0xef, 0xfc, 0xeb, 0x1c, 0xd0, 0xda, 0x1b, 0x09, 0x38, 0xc0, 0xfc, 0xfb, 0x03, + 0xca, 0xcf, 0x7f, 0x0b, 0xfb, 0xe1, 0xd4, 0x1d, 0xad, 0xd7, 0xe5, 0x0f, 0x12, + 0x33, 0x50, 0x01, 0x00, 0x08, 0x14, 0x30, 0x15, 0xd2, 0xdb, 0xcd, 0xe7, 0x02, + 0x2b, 0xf9, 0xfb, 0x04, 0xf9, 0x08, 0xc7, 0xca, 0xf1, 0xec, 0xd1, 0xf0, 0xde, + 0xe5, 0x0c, 0xff, 0xe9, 0x24, 0xe7, 0xfb, 0x4b, 0xc8, 0xeb, 0x2c, 0x36, 0xe1, + 0x53, 0xfb, 0xe9, 0xf3, 0xc7, 0x00, 0xe2, 0xee, 0x61, 0xea, 0x09, 0x30, 0xea, + 0xc3, 0xec, 0x0e, 0x57, 0xcd, 0xde, 0x35, 0xe4, 0xf2, 0xcd, 0x0a, 0x01, 0x56, + 0x37, 0xdc, 0xf1, 0x26, 0x0c, 0x34, 0xd2, 0x45, 0x11, 0x0e, 0xef, 0xce, 0x03, + 0xc4, 0xfd, 0x1e, 0x0e, 0xf8, 0x50, 0x07, 0x38, 0xf3, 0x00, 0x03, 0x34, 0x12, + 0xd9, 0x2b, 0x0a, 0xed, 0xdc, 0x24, 0xef, 0xcb, 0x3b, 0x10, 0x1a, 0xc9, 0xdc, + 0x28, 0x13, 0x4b, 0xd5, 0x03, 0xdb, 0xf3, 0x49, 0xff, 0xb3, 0xb3, 0xf9, 0x0a, + 0xc4, 0xf0, 0xf5, 0xf1, 0x0d, 0xda, 0x0d, 0xec, 0x0b, 0x0d, 0xdb, 0xfa, 0xcd, + 0x14, 0x0d, 0x0b, 0xce, 0x1b, 0x17, 0x01, 0xf6, 0xf1, 0x07, 0x09, 0xe4, 0x1e, + 0xe5, 0xee, 0x29, 0x10, 0xda, 0x92, 0xf1, 0x21, 0xec, 0xe5, 0x27, 0xfa, 0x14, + 0x08, 0xe8, 0x03, 0xdc, 0xfa, 0xee, 0x18, 0xeb, 0xfd, 0xf0, 0xe5, 0xf9, 0xea, + 0xf3, 0xb4, 0xff, 0xde, 0xff, 0xeb, 0xf9, 0x39, 0x03, 0x09, 0xf0, 0x0e, 0xe1, + 0xfd, 0x1c, 0x13, 0xd5, 0xff, 0xdf, 0x10, 0x10, 0x2f, 0xef, 0x08, 0x81, 0xe7, + 0xd9, 0x33, 0xe3, 0xf9, 0x2a, 0xda, 0xf7, 0xd8, 0xe1, 0xb5, 0xfb, 0x10, 0xfa, + 0xd9, 0xf1, 0xe1, 0x05, 0x0c, 0x14, 0xf3, 0x0f, 0x36, 0xfe, 0xf8, 0x26, 0x0d, + 0x05, 0x04, 0xbd, 0x2a, 0xd1, 0xf7, 0xe1, 0x08, 0xe4, 0xde, 0xfd, 0xd2, 0xe8, + 0xf1, 0x0e, 0x0d, 0x01, 0xe1, 0xdc, 0x45, 0xb3, 0x98, 0xb8, 0xe3, 0xf7, 0x05, + 0xc8, 0x19, 0xf3, 0x02, 0xe4, 0xf2, 0x13, 0xe6, 0xf8, 0xf2, 0x17, 0xc4, 0xf0, + 0xe3, 0xdc, 0x01, 0xd0, 0xe4, 0x3a, 0xcc, 0xfb, 0x04, 0x08, 0xd7, 0xfc, 0xd3, + 0x08, 0x22, 0xeb, 0x3e, 0x55, 0xa9, 0xcd, 0xf4, 0x16, 0x41, 0x17, 0x1b, 0xd4, + 0xfd, 0xfa, 0xd4, 0x4d, 0x23, 0x30, 0x42, 0x62, 0x54, 0xd9, 0xd6, 0x35, 0xf7, + 0x26, 0x65, 0x09, 0x20, 0xdb, 0x7f, 0xfa, 0xf7, 0xf4, 0x19, 0xab, 0xb5, 0x17, + 0xd4, 0x04, 0xde, 0xbd, 0xbb, 0x0b, 0x2e, 0xe8, 0x06, 0x0b, 0xf2, 0x0e, 0x0a, + 0x07, 0x21, 0x16, 0xe4, 0xda, 0x69, 0xd8, 0x1a, 0x63, 0x1d, 0xe9, 0xf3, 0xf0, + 0x09, 0xdc, 0xbf, 0xcf, 0xc9, 0x1e, 0x22, 0xdf, 0x43, 0x39, 0x20, 0x30, 0x42, + 0x20, 0xd2, 0xc3, 0x1a, 0x00, 0x1d, 0xda, 0x2b, 0x34, 0x1d, 0x18, 0xda, 0x2e, + 0xfe, 0xdc, 0x03, 0xb6, 0xee, 0x00, 0x2e, 0xe7, 0x12, 0xcd, 0xf4, 0x4d, 0x1f, + 0x19, 0x3d, 0xc9, 0xfc, 0x00, 0xfd, 0xfe, 0xf2, 0x22, 0xca, 0x2f, 0xe5, 0xff, + 0x01, 0xef, 0x2f, 0xc3, 0xf3, 0x36, 0x19, 0x31, 0x15, 0xc5, 0x07, 0x0b, 0x21, + 0x2b, 0xae, 0xe6, 0x63, 0xe4, 0x03, 0xf4, 0xe4, 0xfe, 0xd6, 0x2b, 0xdc, 0x10, + 0xfa, 0x08, 0x02, 0xd3, 0xd9, 0xc5, 0x37, 0xe4, 0x18, 0xa3, 0x45, 0xee, 0xc1, + 0xf1, 0x20, 0x03, 0xf8, 0x27, 0xfc, 0x37, 0x2e, 0x1c, 0xb2, 0xf7, 0xf4, 0xad, + 0x04, 0xb5, 0xf6, 0x11, 0x1f, 0xe2, 0x00, 0x20, 0x03, 0x0d, 0x07, 0xf7, 0x2b, + 0xf6, 0x5d, 0xc7, 0x0e, 0x55, 0xf0, 0xfc, 0x86, 0x0a, 0x4c, 0xdb, 0xfc, 0x33, + 0xa3, 0xff, 0x75, 0x26, 0x03, 0xe0, 0xc5, 0xca, 0x1d, 0x22, 0x1d, 0xed, 0xe8, + 0x96, 0x7d, 0x05, 0x3e, 0xdb, 0x4b, 0x38, 0xd3, 0x7f, 0x26, 0xfb, 0xfa, 0xf8, + 0xcc, 0x0a, 0x10, 0x40, 0x66, 0x5b, 0x27, 0x21, 0xc0, 0x0a, 0x1d, 0xeb, 0x1c, + 0x1f, 0xb9, 0xf8, 0x1f, 0xf2, 0xff, 0xc9, 0x5c, 0xd3, 0x58, 0xda, 0x02, 0xe6, + 0xdf, 0xe3, 0xf8, 0x10, 0x10, 0x37, 0xfa, 0x02, 0x58, 0xec, 0xdf, 0x28, 0xb3, + 0x40, 0xf4, 0x26, 0xd8, 0xf6, 0xad, 0x06, 0xe8, 0x0e, 0xf4, 0xa7, 0x19, 0x26, + 0xd3, 0xe5, 0x2c, 0x13, 0xa8, 0xf6, 0xbc, 0x81, 0xda, 0xea, 0xd7, 0xf9, 0xf6, + 0x60, 0x53, 0x06, 0xd8, 0xff, 0xcc, 0xf0, 0x0d, 0xe3, 0xee, 0xc0, 0xe8, 0xf8, + 0xed, 0x1f, 0x2a, 0x11, 0x26, 0xbb, 0x44, 0x07, 0x0a, 0xd9, 0xe8, 0xe6, 0x10, + 0xb8, 0x19, 0x25, 0xd6, 0xbe, 0x3d, 0x1d, 0xdd, 0xe1, 0xfd, 0xf3, 0xee, 0x38, + 0x0a, 0xe0, 0x0c, 0xeb, 0x02, 0x04, 0x00, 0x24, 0x0a, 0xdf, 0x29, 0x15, 0x0b, + 0xba, 0xf6, 0x95, 0x46, 0xc3, 0x04, 0x63, 0x4e, 0xb3, 0x12, 0xd5, 0xd5, 0x72, + 0xe1, 0xf6, 0xf1, 0x16, 0x40, 0xfd, 0xf7, 0x4e, 0x6d, 0xfc, 0xbf, 0xf2, 0xfb, + 0x18, 0x15, 0xd1, 0x00, 0x0e, 0x00, 0xea, 0xfa, 0xfd, 0x77, 0x3b, 0xe0, 0x7f, + 0xf7, 0x01, 0xf8, 0x14, 0xfc, 0x93, 0xcd, 0xcc, 0xe0, 0xe5, 0xdd, 0x03, 0xec, + 0xce, 0x1e, 0xe0, 0x1f, 0x18, 0xf9, 0xd1, 0xe5, 0xf6, 0x4c, 0xf1, 0xcb, 0x03, + 0x3a, 0xcf, 0xd7, 0xe1, 0xce, 0xc9, 0x0d, 0x37, 0xae, 0x0e, 0xd4, 0x39, 0xea, + 0xe7, 0xf2, 0xfa, 0x11, 0xf5, 0xeb, 0x17, 0xf7, 0x3b, 0x10, 0xd2, 0x32, 0x02, + 0xee, 0xe5, 0xb9, 0xf7, 0xcb, 0xfa, 0x14, 0xf7, 0x0a, 0xf3, 0x34, 0x1f, 0xf4, + 0x3c, 0xf8, 0x0b, 0xcd, 0xd3, 0x18, 0x0f, 0x21, 0x0c, 0xd8, 0xdf, 0x22, 0x09, + 0xfd, 0xdb, 0x1b, 0xe4, 0x19, 0x1e, 0x11, 0xff, 0x18, 0xbe, 0xdf, 0x26, 0x4b, + 0xe2, 0x11, 0x69, 0xfe, 0x3f, 0x26, 0x68, 0xea, 0x04, 0xae, 0xd4, 0x05, 0xfd, + 0xf9, 0x0e, 0x4e, 0xde, 0x21, 0xf0, 0x48, 0x0f, 0x2f, 0xc0, 0xc3, 0x90, 0xf6, + 0x0f, 0x1e, 0x64, 0x03, 0xb7, 0x41, 0x24, 0x7f, 0x25, 0xcd, 0xe6, 0x10, 0xdf, + 0xb9, 0xb9, 0xe3, 0xd5, 0x90, 0xc2, 0x19, 0xd9, 0x0f, 0xc5, 0xe0, 0xd6, 0x34, + 0xb5, 0xf2, 0xf6, 0x6b, 0x4e, 0x0b, 0xe1, 0xcb, 0x33, 0xf3, 0x4e, 0xf5, 0xf5, + 0xc9, 0x7b, 0xc4, 0xb6, 0xc4, 0x25, 0xc0, 0x0b, 0xc5, 0x40, 0xbb, 0x12, 0x1c, + 0x9e, 0xb5, 0x40, 0x01, 0xc3, 0x2f, 0xfc, 0x3a, 0x1a, 0xc9, 0xe0, 0xff, 0x9d, + 0x8e, 0x3e, 0xd9, 0x09, 0xc1, 0xf7, 0x12, 0xd0, 0xe3, 0x0d, 0xd9, 0xbf, 0x35, + 0x21, 0xa1, 0x8a, 0x46, 0xb7, 0xed, 0xee, 0xaa, 0xbc, 0x02, 0x13, 0x00, 0xda, + 0x51, 0x92, 0x59, 0x64, 0xfc, 0xce, 0xec, 0xd2, 0x08, 0xda, 0x22, 0xf2, 0x0d, + 0x65, 0x14, 0x06, 0x0c, 0x18, 0x4d, 0x08, 0xb8, 0xc5, 0x3b, 0x90, 0x57, 0xec, + 0xdf, 0x08, 0x32, 0xf6, 0x3a, 0x16, 0x59, 0xd1, 0x44, 0xd8, 0x03, 0x12, 0x22, + 0xe6, 0xf3, 0x1f, 0xf2, 0x16, 0x71, 0xe1, 0x0b, 0xe8, 0xeb, 0xdc, 0xdb, 0xd9, + 0x2e, 0x04, 0xe5, 0x39, 0x29, 0x5d, 0x11, 0x11, 0x18, 0x2b, 0xd5, 0xda, 0xfc, + 0x1d, 0x2b, 0x2c, 0xe6, 0xf2, 0xff, 0x0d, 0xd4, 0xfb, 0xfc, 0x66, 0x07, 0xf7, + 0x2c, 0xef, 0xf3, 0x27, 0x13, 0x0f, 0xeb, 0xdd, 0x1b, 0x9d, 0xdb, 0xf6, 0xbe, + 0xd2, 0x0f, 0xa7, 0x13, 0x41, 0x32, 0x0b, 0x1d, 0x3d, 0xd7, 0xfa, 0x1a, 0xd7, + 0xfe, 0x01, 0x0b, 0xe9, 0xd6, 0x2d, 0xfb, 0x02, 0xed, 0x12, 0xed, 0xcd, 0xd6, + 0x06, 0x7f, 0x6f, 0x01, 0x46, 0x2f, 0xf8, 0x24, 0x00, 0xa9, 0x48, 0x07, 0xff, + 0x1d, 0xe2, 0x38, 0x17, 0xf5, 0x3b, 0xfc, 0x01, 0x56, 0xbf, 0x47, 0x03, 0x19, + 0x5c, 0x16, 0x03, 0x44, 0xce, 0xe5, 0x22, 0xeb, 0xb0, 0x2a, 0x0f, 0xdb, 0x01, + 0xe0, 0x0c, 0x13, 0x18, 0xd5, 0x16, 0x57, 0x09, 0xf5, 0x4c, 0x1f, 0x3e, 0xf3, + 0xed, 0xd5, 0xfd, 0xee, 0xd8, 0xf0, 0xdd, 0xd7, 0xf9, 0x2e, 0x1d, 0xe7, 0xb3, + 0x33, 0xe1, 0x16, 0x38, 0xff, 0x17, 0x08, 0xab, 0xfa, 0xd8, 0xa7, 0xdb, 0xfa, + 0x02, 0x05, 0xb7, 0x59, 0xf0, 0xde, 0xd6, 0x12, 0xc1, 0x08, 0x00, 0x05, 0xd4, + 0xf0, 0xe7, 0x21, 0xcb, 0x0c, 0xf1, 0x34, 0x02, 0x0a, 0xfb, 0x29, 0xe4, 0xed, + 0xb9, 0xac, 0xda, 0x10, 0x2f, 0x2f, 0xf5, 0x18, 0x7f, 0xfa, 0x6f, 0x35, 0x15, + 0x4a, 0xf9, 0x20, 0x0f, 0x1e, 0x04, 0x23, 0x0c, 0x0b, 0x31, 0x3e, 0x3a, 0xfb, + 0xea, 0xfd, 0x06, 0x05, 0xd6, 0x0e, 0x13, 0x3f, 0xed, 0xf5, 0x53, 0xcc, 0xbc, + 0x21, 0xd1, 0xd8, 0x0e, 0x20, 0xc6, 0x03, 0x0d, 0x55, 0xef, 0xe7, 0xe0, 0x15, + 0xd6, 0xfb, 0x42, 0x35, 0xeb, 0x95, 0xa0, 0xd5, 0x0b, 0x07, 0x10, 0xda, 0x28, + 0x04, 0xe9, 0xdf, 0x2d, 0xed, 0x0e, 0x13, 0xc5, 0xf8, 0x09, 0xe7, 0x35, 0xc5, + 0xfc, 0x12, 0x03, 0xf9, 0xe6, 0x15, 0x03, 0xf0, 0x23, 0xe8, 0xe3, 0xed, 0xf0, + 0x10, 0xec, 0x15, 0x28, 0xf6, 0xf0, 0x1d, 0x2d, 0x2b, 0x19, 0x06, 0xf4, 0x03, + 0x1c, 0x3a, 0xe0, 0x09, 0xc6, 0xe7, 0xea, 0x24, 0xf0, 0x2a, 0x5a, 0xfb, 0xfe, + 0x13, 0x48, 0x0b, 0x14, 0xed, 0x18, 0xf5, 0xeb, 0x29, 0x24, 0xe0, 0x08, 0x3d, + 0x09, 0xc6, 0x81, 0xec, 0x29, 0xfa, 0xed, 0xe5, 0x0a, 0xfa, 0x11, 0xf9, 0xa2, + 0x1d, 0xe6, 0xf5, 0xf4, 0x05, 0xe9, 0x1d, 0x54, 0xeb, 0xcc, 0x19, 0x52, 0xea, + 0x2e, 0xf9, 0xf4, 0x04, 0x05, 0x34, 0xd2, 0x2b, 0xd6, 0x02, 0x1e, 0xfc, 0x09, + 0x07, 0x2d, 0x17, 0x3b, 0x08, 0xc2, 0x28, 0x14, 0xf0, 0x21, 0xe0, 0x20, 0xc6, + 0x40, 0xfd, 0xfb, 0x2a, 0x1f, 0xf1, 0x0b, 0x0f, 0x0f, 0x09, 0xf2, 0xf3, 0xd2, + 0x5c, 0x46, 0xdc, 0x04, 0xc8, 0x9b, 0xeb, 0xf9, 0x99, 0x33, 0xdc, 0x3a, 0x02, + 0xe1, 0xf1, 0xe6, 0xcb, 0x21, 0x0e, 0xea, 0xa8, 0x15, 0xe7, 0x41, 0xe8, 0x15, + 0xf6, 0x3f, 0x35, 0xe2, 0xe2, 0xe1, 0x44, 0x38, 0x40, 0xc1, 0xac, 0xde, 0x1f, + 0xd5, 0xd5, 0xfb, 0x01, 0x4e, 0x43, 0x2d, 0xea, 0xe4, 0xdb, 0xa9, 0xbf, 0x8b, + 0x21, 0xc2, 0x18, 0xf0, 0x30, 0x11, 0x2e, 0x11, 0xfe, 0x9d, 0xb9, 0xc2, 0x7f, + 0xbd, 0x12, 0x0f, 0x19, 0x41, 0x6f, 0xfe, 0xf9, 0xd4, 0x21, 0x0a, 0x60, 0x0b, + 0x09, 0xcb, 0xf4, 0x09, 0xe4, 0xee, 0x0e, 0x35, 0x3e, 0x08, 0x26, 0x73, 0x15, + 0x33, 0x12, 0x1b, 0xf0, 0xed, 0xdf, 0x22, 0x27, 0x0f, 0x09, 0x06, 0xc0, 0x52, + 0xfb, 0x22, 0x29, 0x39, 0x2a, 0xf6, 0xed, 0x38, 0x22, 0xe8, 0x24, 0x1e, 0xe0, + 0xbe, 0xe7, 0xec, 0x28, 0x46, 0x0f, 0x2e, 0xf6, 0x0e, 0xfb, 0xd9, 0x53, 0xef, + 0xcf, 0x18, 0x20, 0xdd, 0xb6, 0xf8, 0x3d, 0xeb, 0xd6, 0xdd, 0xe4, 0xd3, 0xd2, + 0xed, 0xdf, 0xc3, 0xd0, 0x02, 0x3b, 0xf9, 0xd7, 0xfb, 0x0f, 0xff, 0xf7, 0x19, + 0xcc, 0xfe, 0xe5, 0xe8, 0x35, 0xda, 0xf4, 0x06, 0xfc, 0x1b, 0xcd, 0xdf, 0x13, + 0xd5, 0xee, 0xdf, 0x32, 0xf6, 0x2f, 0x2c, 0xbb, 0xfc, 0xf0, 0x00, 0xe5, 0xe3, + 0x1f, 0xda, 0x10, 0xd7, 0x3d, 0x29, 0xec, 0xf0, 0xf3, 0xe9, 0x7f, 0xe3, 0xb8, + 0xdf, 0x40, 0x4e, 0xd4, 0xec, 0x1f, 0x16, 0x30, 0xe7, 0x17, 0x12, 0x0c, 0xe2, + 0xd3, 0x18, 0x04, 0x1c, 0xc8, 0x21, 0xd4, 0x11, 0xf0, 0xbd, 0xdf, 0xe1, 0xf5, + 0xd2, 0x14, 0x56, 0xeb, 0x14, 0x09, 0x04, 0xfe, 0x14, 0xfb, 0xac, 0xec, 0xc1, + 0x1e, 0x2f, 0x1e, 0xfa, 0xdd, 0x00, 0x68, 0xdd, 0xee, 0xd2, 0x31, 0x4d, 0xfe, + 0x01, 0xf3, 0x6e, 0xbc, 0xbd, 0xff, 0x0a, 0xf2, 0xc3, 0xeb, 0x12, 0xcc, 0xc2, + 0x91, 0x03, 0x0d, 0x66, 0xe2, 0xd6, 0xd3, 0xc6, 0xd1, 0xd4, 0x3c, 0xe0, 0xdb, + 0x4d, 0x0f, 0xd8, 0xa0, 0xe3, 0xd0, 0xbd, 0x01, 0x0c, 0xe6, 0xed, 0x0f, 0x3d, + 0x16, 0x26, 0x36, 0x0e, 0x0c, 0x07, 0x00, 0x68, 0x34, 0x05, 0x14, 0xf1, 0x87, + 0xea, 0x32, 0xbd, 0x5b, 0xaf, 0x42, 0x31, 0xec, 0xd4, 0x2f, 0x81, 0x65, 0x25, + 0x07, 0x3e, 0x3e, 0x30, 0x15, 0x8e, 0xcf, 0x9e, 0x13, 0xf8, 0x03, 0xc6, 0x2a, + 0x37, 0x1a, 0xfc, 0x13, 0x27, 0xe2, 0x96, 0xd2, 0x2c, 0xe6, 0xfd, 0x32, 0xca, + 0xc6, 0x1a, 0x2d, 0xa5, 0xe0, 0x05, 0xed, 0xfe, 0x2c, 0x17, 0xdb, 0x19, 0x18, + 0xf4, 0x4e, 0x10, 0xf9, 0x6b, 0x15, 0x0a, 0x30, 0x1c, 0x3e, 0x50, 0x86, 0xdf, + 0x29, 0x24, 0x13, 0xe6, 0xbe, 0x2d, 0x24, 0x1d, 0x04, 0xc5, 0xd0, 0x11, 0x1a, + 0x04, 0x04, 0xdb, 0xf6, 0xe8, 0x0f, 0x15, 0xe3, 0xc4, 0x08, 0x2d, 0xfb, 0xd7, + 0x17, 0x35, 0xc2, 0x1b, 0x23, 0xdd, 0x0f, 0x17, 0xf8, 0xf0, 0x0d, 0x1c, 0xd1, + 0x6e, 0xc5, 0xc6, 0x08, 0x13, 0xd3, 0xed, 0x56, 0x10, 0xde, 0xf5, 0x23, 0x01, + 0x06, 0x0b, 0x19, 0xee, 0xff, 0x0d, 0x5c, 0xe3, 0x07, 0x27, 0x0e, 0x35, 0xdb, + 0x14, 0xe5, 0x1f, 0x2d, 0x23, 0xf5, 0x32, 0xee, 0xc9, 0xd4, 0xe2, 0xe9, 0x18, + 0xec, 0x3b, 0xe6, 0xd0, 0x04, 0x05, 0xd9, 0xff, 0xa8, 0xf0, 0xcc, 0xd2, 0xed, + 0x09, 0x00, 0xf6, 0xeb, 0xec, 0xbe, 0x0d, 0x20, 0xf7, 0x40, 0x22, 0x0f, 0x08, + 0x30, 0xd5, 0x28, 0xb1, 0x1f, 0x1b, 0x15, 0x09, 0xf1, 0x0b, 0xd4, 0xd1, 0x17, + 0x81, 0x15, 0x01, 0x2a, 0x03, 0x3d, 0xe0, 0xce, 0x1a, 0x37, 0xd6, 0xb6, 0x14, + 0xe5, 0xe3, 0xbe, 0x18, 0xee, 0x27, 0xe0, 0xff, 0xc5, 0xf6, 0xea, 0xcb, 0x5a, + 0xdf, 0xf0, 0x49, 0xc1, 0xe9, 0xdc, 0xab, 0x3d, 0x0d, 0x17, 0xf8, 0x1c, 0xdb, + 0x02, 0xcf, 0x24, 0xe7, 0x16, 0xee, 0x20, 0x06, 0x13, 0x39, 0x30, 0x19, 0xd0, + 0xb6, 0x25, 0x01, 0xe8, 0x62, 0xc8, 0x00, 0xd5, 0x5b, 0xf5, 0x16, 0xec, 0x16, + 0x04, 0x55, 0x28, 0xf3, 0xdb, 0xde, 0xea, 0x40, 0xe1, 0x4c, 0x33, 0xca, 0xdd, + 0x0d, 0x21, 0xfc, 0x00, 0x41, 0x23, 0xec, 0x3d, 0xe0, 0xdf, 0xd2, 0x1b, 0x4b, + 0x38, 0xfd, 0xd2, 0xf1, 0xc9, 0x95, 0xfe, 0x55, 0xea, 0xdc, 0xfd, 0xcc, 0x37, + 0x26, 0x24, 0x28, 0xf3, 0x49, 0xd4, 0xdb, 0x25, 0xdf, 0x11, 0x13, 0x24, 0x19, + 0x04, 0x4e, 0x14, 0xc7, 0x0c, 0xfb, 0x0c, 0x26, 0x13, 0xf0, 0x05, 0x16, 0x81, + 0xa2, 0x22, 0xf5, 0xf9, 0xe1, 0x11, 0xc7, 0xea, 0xf4, 0xec, 0xf2, 0x1d, 0x1d, + 0x33, 0x34, 0x55, 0xaf, 0x06, 0x2d, 0xde, 0x90, 0xc1, 0x4c, 0x0a, 0x07, 0xc5, + 0xfa, 0x6f, 0x2c, 0xdf, 0x40, 0x06, 0xe6, 0xff, 0x27, 0x18, 0xab, 0x60, 0x7f, + 0xf0, 0x55, 0xf7, 0x9b, 0xdf, 0xc7, 0xe3, 0x19, 0xed, 0x20, 0xa5, 0xfe, 0xfa, + 0xdd, 0xd7, 0x0b, 0xe1, 0x7c, 0x38, 0xea, 0x00, 0x1e, 0xea, 0xd4, 0x12, 0xba, + 0xe7, 0xa3, 0x23, 0xbd, 0x5b, 0x04, 0x24, 0x3f, 0xe0, 0xbc, 0x13, 0x19, 0xf6, + 0xf4, 0xeb, 0xeb, 0x0d, 0x58, 0x52, 0x2b, 0x0d, 0x3b, 0x1f, 0xfa, 0xdf, 0xfb, + 0xb2, 0xc3, 0xe2, 0x58, 0xb0, 0xf4, 0xd2, 0xdf, 0xe5, 0xe9, 0xf9, 0xc5, 0xda, + 0xcf, 0x48, 0x0c, 0xdb, 0xe4, 0xcf, 0xd6, 0x2f, 0x2d, 0xea, 0x38, 0x34, 0x17, + 0xfd, 0x3a, 0xe9, 0xce, 0x1b, 0x00, 0x29, 0x13, 0xc4, 0xe6, 0xef, 0xc8, 0x1d, + 0xdd, 0x3f, 0x0a, 0x2a, 0xc4, 0x05, 0x0e, 0x43, 0xdb, 0xea, 0xf1, 0xe9, 0xb1, + 0x53, 0xea, 0xa5, 0x11, 0xf7, 0x2a, 0x17, 0xb4, 0x06, 0xda, 0xcc, 0xe9, 0x09, + 0xcc, 0xe2, 0x81, 0x39, 0xd4, 0xdd, 0xf6, 0x06, 0x06, 0x9c, 0xd7, 0x20, 0x60, + 0xe6, 0x2d, 0xea, 0xc8, 0x42, 0xd4, 0x26, 0xf3, 0x20, 0x18, 0xf0, 0x37, 0x56, + 0xcc, 0xe3, 0x50, 0xe8, 0xef, 0x2e, 0xe2, 0x46, 0xdd, 0x68, 0xe2, 0xfe, 0x07, + 0xa6, 0x98, 0xed, 0x4e, 0xd6, 0xe2, 0x9f, 0xd3, 0x5f, 0xc9, 0xd5, 0x1f, 0xc9, + 0x09, 0xd5, 0xa8, 0x06, 0xfe, 0xe1, 0xe1, 0xc2, 0x70, 0x25, 0xf1, 0xc4, 0x42, + 0x3c, 0x57, 0xa9, 0xce, 0xea, 0x17, 0x3f, 0x00, 0xdc, 0x1b, 0xdc, 0xd0, 0xf8, + 0xb7, 0xfe, 0xd5, 0x00, 0xcd, 0xe7, 0xe9, 0xcd, 0xbf, 0x0b, 0x46, 0x1f, 0xe4, + 0x32, 0xde, 0xbc, 0x19, 0x18, 0xd7, 0x20, 0xd2, 0xf2, 0x39, 0x4d, 0x30, 0x26, + 0x41, 0xec, 0xcd, 0xc8, 0x10, 0xeb, 0xcf, 0xe3, 0xdd, 0xeb, 0x2a, 0xfd, 0x3c, + 0x2b, 0x8e, 0xe5, 0xfa, 0xc9, 0xf0, 0x08, 0x19, 0xb0, 0xb9, 0xeb, 0x1e, 0xd0, + 0xfb, 0xf9, 0xce, 0x12, 0x50, 0x31, 0xcb, 0x5b, 0xae, 0xf5, 0xf4, 0xec, 0x08, + 0xcd, 0x37, 0xdf, 0x1b, 0xfa, 0x0d, 0xf5, 0xf4, 0xf8, 0xb2, 0xff, 0xd8, 0x3f, + 0xe6, 0xcc, 0x0c, 0xeb, 0xf3, 0x28, 0xee, 0x01, 0xf2, 0x14, 0x81, 0x22, 0x0d, + 0xfb, 0x00, 0xf0, 0xe1, 0x2b, 0xee, 0x1a, 0xec, 0xf5, 0x0b, 0xe9, 0xb6, 0x0e, + 0xdf, 0xc6, 0x21, 0x11, 0xfd, 0xdf, 0xd2, 0x15, 0xf9, 0x17, 0xf6, 0x2d, 0xfd, + 0xf9, 0xda, 0x02, 0xcf, 0x16, 0xff, 0x0e, 0x11, 0x20, 0x55, 0x29, 0xdd, 0xd1, + 0x62, 0xc9, 0xfd, 0xb5, 0x26, 0x1e, 0xc1, 0x0b, 0x22, 0xf7, 0x19, 0x0e, 0x11, + 0x08, 0xa6, 0x14, 0x02, 0xe1, 0xf8, 0xd4, 0xc8, 0x16, 0xd2, 0xf2, 0xee, 0xf2, + 0xb0, 0x05, 0xf1, 0xf9, 0x0c, 0xc1, 0x09, 0x1a, 0x0b, 0xf2, 0x45, 0xf3, 0x74, + 0xdb, 0x0e, 0x0d, 0xda, 0xf1, 0xd2, 0x19, 0xdf, 0xf4, 0xd9, 0xad, 0xf5, 0x0b, + 0x2d, 0x1a, 0xda, 0x17, 0xfd, 0x0f, 0x2f, 0x2a, 0x1a, 0xf0, 0xea, 0x06, 0xc0, + 0x00, 0x2a, 0x56, 0x0d, 0x65, 0xad, 0x37, 0xd8, 0xfa, 0xde, 0xae, 0xe8, 0x14, + 0xf2, 0xec, 0xf2, 0x23, 0x13, 0x2f, 0xcd, 0xec, 0x09, 0xf0, 0xa5, 0xee, 0x0a, + 0xee, 0xfa, 0xe0, 0xb2, 0x0f, 0xd6, 0x2a, 0x40, 0xff, 0x0d, 0xe0, 0x0a, 0xdd, + 0x1c, 0x09, 0x62, 0x07, 0x47, 0x08, 0xf9, 0xec, 0xa0, 0xbf, 0x30, 0x04, 0x10, + 0xdd, 0x39, 0x34, 0x7f, 0x1a, 0x18, 0x41, 0xc4, 0xe5, 0xf4, 0x34, 0x4d, 0xf8, + 0xde, 0xfa, 0x1d, 0x2e, 0x19, 0xff, 0xec, 0x1f, 0xff, 0xea, 0xfd, 0x0b, 0x0a, + 0x0b, 0x2d, 0x1d, 0xc5, 0xd0, 0xda, 0xe7, 0xd4, 0x3e, 0x3a, 0xff, 0x14, 0x1c, + 0xc9, 0x92, 0x21, 0x17, 0xe4, 0xfc, 0xd4, 0xc1, 0x6b, 0xe1, 0xf4, 0xd0, 0x08, + 0xc6, 0xdd, 0x5d, 0xc6, 0x61, 0x62, 0x16, 0x2a, 0xd8, 0xcd, 0x21, 0x19, 0xe0, + 0xd4, 0x1d, 0x41, 0xde, 0xdd, 0x10, 0x1d, 0x08, 0x37, 0x57, 0x06, 0x0d, 0xe9, + 0x0f, 0x67, 0x8e, 0x29, 0xf8, 0xd8, 0xba, 0xf7, 0xb9, 0xde, 0xfa, 0xaa, 0x07, + 0xa1, 0x07, 0xda, 0x02, 0x00, 0xf6, 0x18, 0x09, 0xe8, 0x1b, 0x1d, 0x07, 0x07, + 0x20, 0x54, 0xd3, 0x00, 0xc6, 0x4b, 0xb4, 0x41, 0xfb, 0xee, 0xf7, 0xf1, 0xdd, + 0xdf, 0xf7, 0x0e, 0x31, 0xc4, 0x39, 0x0e, 0x00, 0xcd, 0x06, 0xd5, 0x18, 0x1a, + 0x01, 0xf5, 0x17, 0x81, 0x3d, 0x3e, 0xd9, 0x1a, 0x3c, 0x0b, 0xf2, 0x45, 0x0d, + 0xa6, 0xd2, 0x1a, 0xb9, 0x4e, 0x0b, 0xcb, 0x3c, 0xeb, 0xfd, 0x28, 0xdc, 0xc6, + 0x12, 0xa4, 0xe5, 0xe4, 0xdd, 0xae, 0xa7, 0xe3, 0xd4, 0xe3, 0x20, 0xb9, 0xc2, + 0x01, 0x0b, 0xd4, 0x11, 0xe3, 0x44, 0xdd, 0xee, 0xcc, 0xf0, 0xb5, 0x1c, 0xf9, + 0x04, 0x52, 0xc3, 0x39, 0xf8, 0xeb, 0x03, 0x75, 0xf4, 0x17, 0x32, 0x25, 0x31, + 0xc0, 0x25, 0xf6, 0xfc, 0x58, 0xe8, 0xcf, 0xe7, 0x1e, 0xe7, 0x23, 0x04, 0x30, + 0x12, 0x1e, 0xec, 0xd6, 0x11, 0x37, 0x12, 0xdd, 0x23, 0xc4, 0xfe, 0x00, 0x05, + 0x02, 0xfc, 0xbb, 0xf4, 0xea, 0x01, 0x1c, 0x37, 0xe6, 0xd5, 0x52, 0x05, 0x13, + 0x31, 0xf7, 0xde, 0x10, 0xe9, 0xdd, 0xf2, 0xef, 0xdc, 0x01, 0x0d, 0xc9, 0x5f, + 0x09, 0xdd, 0x2f, 0x15, 0xdb, 0xe7, 0xf9, 0x97, 0x50, 0x0e, 0xf0, 0x60, 0xdd, + 0x4b, 0x54, 0xeb, 0x02, 0x1d, 0xf6, 0x1a, 0x24, 0xc4, 0xd9, 0x0f, 0x26, 0x91, + 0x7f, 0xdc, 0xf8, 0xf6, 0x3c, 0x4f, 0x32, 0x11, 0xf7, 0x3d, 0x1a, 0x26, 0xf0, + 0x0b, 0x17, 0xfa, 0xd5, 0xe2, 0x04, 0x15, 0xf3, 0xe9, 0xff, 0xba, 0xf9, 0x28, + 0xe9, 0xe9, 0xe8, 0x0a, 0xf3, 0x1f, 0x42, 0xdc, 0x0b, 0x0a, 0x08, 0x3f, 0xf5, + 0x01, 0x30, 0x10, 0xce, 0x93, 0xc9, 0x11, 0x13, 0xd9, 0xf0, 0xc2, 0xb7, 0xeb, + 0x0c, 0x0a, 0xde, 0xe3, 0x1e, 0x75, 0xc7, 0x3b, 0x32, 0xf5, 0x28, 0x1e, 0x26, + 0xf0, 0x4e, 0xfe, 0xa7, 0xeb, 0xd1, 0xf6, 0xa6, 0xf1, 0xdd, 0x2c, 0x06, 0x3c, + 0x25, 0xfc, 0x62, 0x30, 0xa0, 0x0c, 0xe2, 0x94, 0xca, 0xa4, 0x1c, 0xd7, 0xc4, + 0x32, 0x11, 0xc0, 0xe3, 0xe9, 0xce, 0xee, 0xf7, 0x02, 0x7f, 0xf3, 0xd9, 0xe1, + 0xe3, 0x46, 0x57, 0xe7, 0xa9, 0xaf, 0x14, 0x0d, 0x1a, 0x0a, 0xc3, 0xfc, 0xc8, + 0xfc, 0x18, 0xc7, 0xde, 0x17, 0x00, 0xd7, 0x59, 0x17, 0xe2, 0xed, 0x3d, 0x9e, + 0x6a, 0x1c, 0x39, 0x18, 0x43, 0x0b, 0x0f, 0xd9, 0xab, 0xed, 0x13, 0x41, 0x11, + 0xcd, 0xe4, 0x60, 0xeb, 0xee, 0xb1, 0x02, 0xe9, 0x0a, 0x05, 0xee, 0x29, 0xe5, + 0xfc, 0xe3, 0xb5, 0xd4, 0xb2, 0x0f, 0xd9, 0xf7, 0xf8, 0xf6, 0x01, 0xf5, 0xfd, + 0xf5, 0x0b, 0xe9, 0xd7, 0x10, 0x0a, 0xca, 0xd8, 0xd7, 0xf4, 0xc7, 0x12, 0xe7, + 0x34, 0xd5, 0xf9, 0xeb, 0xff, 0x1b, 0x12, 0xe7, 0xd4, 0xc3, 0xee, 0xec, 0x4d, + 0x22, 0xf2, 0xe6, 0x37, 0x1b, 0xc5, 0x06, 0x2d, 0x03, 0xd2, 0xcf, 0x0f, 0xfe, + 0x20, 0xef, 0xe1, 0x17, 0xf1, 0xdf, 0x08, 0x3b, 0xd8, 0xd8, 0x03, 0xfd, 0x2e, + 0xdf, 0x4c, 0xed, 0xb9, 0x10, 0xe3, 0xdc, 0x19, 0xff, 0xdf, 0xf5, 0x05, 0x42, + 0xb1, 0x92, 0x87, 0xd0, 0xf6, 0xe7, 0xec, 0xe7, 0xf5, 0xd0, 0xdb, 0xd5, 0xe0, + 0xc9, 0xc9, 0xf9, 0xc1, 0x16, 0xfd, 0x65, 0xeb, 0x18, 0xfc, 0xeb, 0x01, 0x07, + 0x05, 0xe9, 0x05, 0xdc, 0x18, 0xee, 0xe7, 0x3f, 0xf9, 0x23, 0x16, 0x06, 0x20, + 0xfd, 0x01, 0x0d, 0x00, 0xde, 0xfb, 0xe4, 0x27, 0xea, 0xca, 0xbb, 0xe3, 0x0a, + 0xd8, 0x27, 0x81, 0xed, 0x14, 0x1a, 0xfa, 0x15, 0x8f, 0x1d, 0xf2, 0xed, 0xf3, + 0x65, 0xe6, 0x1c, 0x52, 0xd7, 0x2b, 0xe5, 0x10, 0xaf, 0x30, 0x4b, 0xd2, 0xfd, + 0x2a, 0x22, 0x2b, 0x34, 0xe6, 0xeb, 0x07, 0x37, 0xe9, 0x1b, 0x70, 0x06, 0xe1, + 0xe5, 0x02, 0x02, 0xd9, 0x03, 0x07, 0x05, 0x19, 0xfd, 0xf4, 0xe0, 0xad, 0x07, + 0xf8, 0x2f, 0x08, 0x1c, 0x1a, 0x1e, 0xfb, 0xef, 0xf4, 0xcd, 0x00, 0x10, 0xff, + 0x1a, 0x05, 0xb1, 0xb8, 0xd7, 0x08, 0x90, 0xe7, 0xc2, 0xf6, 0xcb, 0x10, 0xce, + 0x9f, 0x91, 0x0e, 0xbc, 0x3d, 0xbb, 0xd8, 0xc9, 0xe9, 0xf7, 0xc3, 0xf8, 0x2f, + 0x09, 0xaa, 0x01, 0x20, 0xe0, 0x3b, 0x04, 0x7f, 0x5c, 0xd7, 0x11, 0x38, 0x06, + 0xe7, 0x25, 0x0f, 0x9d, 0x2f, 0x2c, 0xea, 0x32, 0x3f, 0x21, 0x1b, 0x01, 0xb4, + 0xe3, 0xf3, 0x6a, 0xce, 0xf6, 0x19, 0xbd, 0xe7, 0x0d, 0xec, 0xc8, 0xba, 0x9a, + 0x1e, 0x41, 0x18, 0x29, 0x28, 0x03, 0xef, 0x07, 0xe7, 0xf4, 0xce, 0xf5, 0xed, + 0xcb, 0x3c, 0xdd, 0x05, 0x02, 0xe1, 0x00, 0xf7, 0x14, 0x25, 0x23, 0x06, 0xe6, + 0x33, 0x13, 0x0c, 0xe4, 0xc8, 0x7f, 0xc4, 0xf8, 0x15, 0x18, 0x0b, 0xe9, 0xed, + 0x36, 0x39, 0xfe, 0xfa, 0x0c, 0x20, 0x47, 0xe2, 0x00, 0x32, 0xcc, 0xc3, 0xf3, + 0x2d, 0xef, 0x04, 0x05, 0xb6, 0x03, 0xea, 0xc4, 0xfc, 0xf7, 0xe4, 0xfe, 0xfd, + 0xfd, 0x10, 0x05, 0x0f, 0xee, 0x0d, 0x2b, 0x18, 0xe2, 0xe8, 0x17, 0xfc, 0x24, + 0xf0, 0xec, 0x1f, 0xd1, 0xa1, 0x07, 0xfb, 0x13, 0x09, 0x00, 0x00, 0x02, 0xfb, + 0x10, 0x0a, 0x27, 0x04, 0xf3, 0xf6, 0xee, 0xf5, 0x04, 0x46, 0x08, 0x07, 0xf7, + 0x0d, 0x02, 0x01, 0x20, 0x1b, 0xfc, 0x24, 0x28, 0xc9, 0x02, 0x01, 0x12, 0xe9, + 0xf8, 0x17, 0x58, 0x0f, 0xfa, 0x28, 0xed, 0xfb, 0x16, 0xc0, 0xfe, 0xd8, 0xfb, + 0x1e, 0x2e, 0xeb, 0x23, 0x7f, 0x06, 0xfc, 0x01, 0x25, 0x38, 0xcd, 0x2b, 0xed, + 0xf4, 0x1d, 0x00, 0x28, 0xe4, 0x62, 0x0e, 0x03, 0x1c, 0xc4, 0x1e, 0xce, 0xe2, + 0x0d, 0xeb, 0xf3, 0x1e, 0xfe, 0xff, 0x7a, 0x32, 0xdd, 0xb6, 0xda, 0x09, 0x3e, + 0xf1, 0xc3, 0x1b, 0x37, 0x0a, 0x13, 0xe0, 0x11, 0x22, 0xef, 0xe6, 0xfe, 0xdc, + 0xf1, 0x04, 0xbb, 0xfe, 0xe5, 0x97, 0xc8, 0x2a, 0x9d, 0xcf, 0x11, 0xea, 0xf0, + 0xfe, 0x24, 0x08, 0xb9, 0x07, 0xf4, 0x18, 0x44, 0xea, 0x36, 0x09, 0x2a, 0xfa, + 0x42, 0x5f, 0x9c, 0xe1, 0xf0, 0x06, 0x22, 0x4d, 0xaf, 0xfb, 0xfb, 0x07, 0xe5, + 0xfd, 0xf4, 0xc8, 0xe8, 0x0f, 0x0b, 0x0f, 0x52, 0x4b, 0x26, 0xfb, 0x0e, 0x31, + 0x2e, 0xdf, 0xe3, 0x31, 0x22, 0x31, 0xcd, 0x33, 0x19, 0x00, 0x06, 0x01, 0xb8, + 0xee, 0x09, 0xf7, 0x08, 0xe1, 0xd7, 0xfe, 0xf8, 0xc4, 0x38, 0xf7, 0xfc, 0xd4, + 0xe0, 0x04, 0x1a, 0x1d, 0x33, 0x12, 0x05, 0xb7, 0xd9, 0x65, 0xee, 0x1c, 0x15, + 0xe8, 0x31, 0xc9, 0xc8, 0x1a, 0x1a, 0xfd, 0x23, 0x2a, 0xe7, 0xf4, 0xc1, 0x39, + 0xd2, 0xaa, 0xd2, 0xf7, 0xe1, 0x21, 0xe6, 0x1f, 0xe4, 0x32, 0x16, 0x11, 0xbd, + 0x1b, 0x98, 0x2d, 0x0a, 0x24, 0x0c, 0x6d, 0x6a, 0xdd, 0x00, 0x23, 0x3c, 0xbb, + 0x58, 0xc9, 0x0e, 0xd6, 0xec, 0xdc, 0xc8, 0xa1, 0x2d, 0xea, 0x3a, 0xff, 0x01, + 0x99, 0xd0, 0xc0, 0x7f, 0xfc, 0x89, 0x9f, 0x2d, 0x2e, 0xf3, 0xb0, 0x2a, 0x01, + 0x1a, 0xc0, 0xde, 0x39, 0xe2, 0xe6, 0xda, 0xc5, 0x51, 0x20, 0xf9, 0x4b, 0x05, + 0xf2, 0xe2, 0xe1, 0x17, 0xbb, 0x3c, 0xff, 0xd1, 0xd4, 0x13, 0xed, 0x25, 0x1c, + 0xe6, 0x02, 0x1e, 0xf5, 0x02, 0x21, 0x27, 0xbb, 0x32, 0x06, 0xa7, 0xe5, 0xef, + 0x06, 0xbc, 0x70, 0xff, 0x17, 0x4c, 0x1e, 0xd3, 0xef, 0x17, 0xe5, 0xf4, 0x00, + 0x6a, 0x0d, 0x0e, 0x0e, 0x51, 0x03, 0xe6, 0x24, 0xf0, 0xfa, 0xee, 0x38, 0x04, + 0x62, 0x12, 0x3a, 0xde, 0x1c, 0x11, 0x5a, 0xdf, 0xe0, 0x31, 0xe6, 0xc6, 0xe3, + 0xe8, 0x51, 0xe4, 0xc4, 0xf9, 0x19, 0xf3, 0xf1, 0x53, 0x07, 0xdf, 0x25, 0x2e, + 0x10, 0xda, 0x1f, 0xb4, 0xed, 0xfd, 0xf6, 0xfb, 0x0d, 0xc1, 0x1d, 0xdd, 0xd9, + 0x27, 0xbe, 0xbc, 0x39, 0xbb, 0x11, 0xcc, 0xe2, 0xcf, 0x34, 0x00, 0x34, 0x13, + 0xe8, 0x1f, 0x11, 0x81, 0x07, 0xb0, 0x32, 0x01, 0x22, 0x07, 0xc3, 0x0a, 0x0a, + 0xfd, 0x1c, 0x34, 0x4b, 0xd4, 0xfe, 0x05, 0xab, 0x0c, 0xcf, 0x07, 0x14, 0xd1, + 0x29, 0xf3, 0xf4, 0xb6, 0xd5, 0x54, 0xf5, 0x07, 0x70, 0xfb, 0xfa, 0xe3, 0xcc, + 0x12, 0xe6, 0xfd, 0x34, 0xac, 0x00, 0xf9, 0x03, 0x48, 0x3c, 0xce, 0xbe, 0x12, + 0xe4, 0xc7, 0x04, 0x1f, 0xe3, 0x0d, 0xd9, 0x32, 0xf5, 0x48, 0x04, 0x4f, 0xf7, + 0xeb, 0x2e, 0x34, 0x18, 0x2e, 0xef, 0x15, 0x02, 0x04, 0x16, 0xbb, 0xe3, 0xdd, + 0x16, 0x18, 0xfa, 0xee, 0xe0, 0xf7, 0x28, 0x22, 0x07, 0x0c, 0x0f, 0x37, 0xe5, + 0xf2, 0xdd, 0xe3, 0xfd, 0xfb, 0xcc, 0x7c, 0xf2, 0x1d, 0xf5, 0x2d, 0x08, 0xd3, + 0xc0, 0xdb, 0xeb, 0x09, 0x0f, 0xf3, 0x08, 0x03, 0xed, 0x1e, 0x02, 0x1a, 0x42, + 0xd9, 0xf4, 0x0c, 0xfe, 0xf1, 0xe7, 0xf1, 0x15, 0x0f, 0x11, 0xc7, 0xf5, 0xc4, + 0x01, 0xf4, 0x04, 0xe0, 0x13, 0xbf, 0xd2, 0x0d, 0x40, 0xec, 0x2a, 0x21, 0xdb, + 0x5a, 0x0d, 0x5b, 0xb5, 0x17, 0xf3, 0xf3, 0x15, 0xfd, 0xea, 0xf7, 0xdd, 0x10, + 0x07, 0xfd, 0x36, 0x7f, 0xb2, 0xf6, 0x28, 0x19, 0xff, 0xc0, 0x03, 0x16, 0x17, + 0xec, 0x03, 0xec, 0xdf, 0xc7, 0xf8, 0xe8, 0xc3, 0x03, 0x2b, 0x08, 0xef, 0x0c, + 0x18, 0x22, 0xf7, 0x2b, 0xe5, 0xde, 0x9f, 0x11, 0x20, 0x0f, 0x32, 0xbd, 0xfe, + 0x1d, 0x13, 0xac, 0x3d, 0xf7, 0xdd, 0x54, 0x09, 0x5a, 0x45, 0xd1, 0x10, 0xf6, + 0x19, 0xe1, 0x07, 0x6d, 0xda, 0xf8, 0xc5, 0x17, 0x13, 0xf7, 0xb8, 0x03, 0x27, + 0xee, 0x1c, 0xc9, 0xed, 0x58, 0xdc, 0xcb, 0x12, 0x04, 0x00, 0xee, 0xda, 0xfc, + 0xfd, 0xe8, 0x00, 0xfb, 0x06, 0x23, 0xf6, 0x1d, 0xf8, 0x2b, 0xe0, 0x1e, 0x41, + 0xe4, 0xd1, 0x7f, 0x06, 0x0f, 0xf8, 0xcb, 0x33, 0x09, 0x32, 0xec, 0x23, 0xfb, + 0xf0, 0x19, 0x05, 0x17, 0xf1, 0x2a, 0x11, 0xba, 0xbc, 0xd9, 0xea, 0xf0, 0xdf, + 0x4e, 0xff, 0x1a, 0xf2, 0x12, 0x1f, 0xe9, 0xf6, 0xd6, 0x1b, 0xa9, 0xfc, 0xf3, + 0xd2, 0xc1, 0x17, 0x17, 0xe7, 0x0e, 0x13, 0xf1, 0xff, 0x21, 0xe7, 0xf8, 0xd8, + 0xf3, 0xbe, 0x3d, 0xd3, 0x9b, 0xf7, 0x2b, 0x2f, 0xe4, 0xae, 0x56, 0xd6, 0x20, + 0xd3, 0x14, 0xcf, 0x25, 0xd4, 0xd8, 0x07, 0x81, 0xee, 0x24, 0x01, 0x1a, 0x0c, + 0xd4, 0xc5, 0xf9, 0x09, 0xeb, 0xf9, 0xd4, 0xcd, 0xe3, 0x07, 0x0c, 0xd5, 0x08, + 0x03, 0xfc, 0xea, 0x0f, 0x10, 0x00, 0x4e, 0xee, 0x23, 0xda, 0xca, 0xce, 0xff, + 0x09, 0xea, 0x26, 0xd2, 0x2a, 0x06, 0xd9, 0xf5, 0x04, 0x01, 0xdc, 0xf9, 0xf9, + 0x6b, 0x01, 0xeb, 0xfe, 0x09, 0x05, 0xef, 0xd0, 0x30, 0xe8, 0xf4, 0xfa, 0xed, + 0x03, 0x29, 0xc6, 0x00, 0xe2, 0xd0, 0xf5, 0xb9, 0xf9, 0x09, 0xb3, 0xf5, 0xd7, + 0xeb, 0xee, 0x24, 0x2f, 0xf6, 0x05, 0x05, 0xfe, 0x09, 0xd7, 0xcb, 0x4a, 0xea, + 0x36, 0x17, 0xeb, 0xd0, 0x14, 0xee, 0x12, 0xb8, 0xe0, 0x0a, 0x21, 0xe8, 0x1c, + 0x13, 0x07, 0x08, 0xf2, 0x39, 0xe5, 0x0a, 0x0e, 0x4e, 0x3f, 0x2d, 0x0e, 0x11, + 0xb3, 0xdf, 0xe7, 0xf3, 0xe8, 0x0a, 0xfd, 0x19, 0x29, 0x2c, 0x2d, 0xef, 0x3f, + 0xf6, 0x51, 0x2f, 0xf8, 0x1c, 0xea, 0x1c, 0x6a, 0x3a, 0x40, 0xcf, 0x49, 0xfc, + 0x2d, 0x11, 0xd4, 0x42, 0x2b, 0x1c, 0xde, 0xfa, 0x1b, 0x2f, 0xee, 0x24, 0xfd, + 0x21, 0xff, 0x0f, 0x24, 0xe8, 0x25, 0xb6, 0xd8, 0xe0, 0xef, 0xdb, 0x25, 0xb4, + 0xc4, 0xfc, 0xb5, 0x34, 0x2f, 0x58, 0xfe, 0x3a, 0xe4, 0x1d, 0x7a, 0x3e, 0xf0, + 0x33, 0x20, 0xf2, 0x11, 0xea, 0xd6, 0xec, 0xd9, 0xa0, 0x36, 0xb9, 0x01, 0xdc, + 0x14, 0x07, 0x32, 0xc3, 0x50, 0x7f, 0x14, 0x53, 0x50, 0x11, 0xd8, 0x62, 0xe7, + 0xfa, 0x00, 0x4b, 0xe6, 0x15, 0x3b, 0x20, 0x1d, 0x27, 0xfc, 0x9f, 0x01, 0x50, + 0x15, 0x0a, 0x59, 0x60, 0x37, 0x44, 0xd3, 0xf6, 0x1c, 0xfd, 0x13, 0x02, 0x0c, + 0x3d, 0x04, 0xc2, 0xdd, 0x39, 0x1e, 0x3a, 0xbc, 0xf9, 0xcb, 0xf9, 0x20, 0x0d, + 0xdd, 0xcc, 0xfd, 0x27, 0x0c, 0xf2, 0xfa, 0x30, 0x17, 0x9a, 0xa7, 0xf6, 0xc5, + 0x0a, 0x3c, 0x22, 0xca, 0xe6, 0x17, 0x09, 0xbc, 0x5f, 0xc4, 0x22, 0xb0, 0xfe, + 0x60, 0xfb, 0x61, 0xc6, 0x0b, 0x10, 0xdb, 0xed, 0x0f, 0x4c, 0x4d, 0xf5, 0xf0, + 0xe2, 0x1a, 0xfc, 0x07, 0xe2, 0xd5, 0x29, 0x01, 0x4e, 0x08, 0xba, 0xf7, 0x05, + 0xdb, 0x13, 0x02, 0x06, 0x0b, 0x32, 0x57, 0xc0, 0x23, 0x01, 0xd8, 0x25, 0x3c, + 0x43, 0x37, 0x09, 0x36, 0x1d, 0x1d, 0x69, 0x70, 0x03, 0xb2, 0x4e, 0xea, 0xf9, + 0xce, 0x10, 0xe9, 0x7f, 0xd5, 0xe5, 0x09, 0x4a, 0xd4, 0x82, 0x43, 0x21, 0x13, + 0x9d, 0x83, 0x32, 0x11, 0xf5, 0x2f, 0xcc, 0xd9, 0xfb, 0xb6, 0x6b, 0x09, 0x4c, + 0x65, 0x30, 0xae, 0x02, 0x1e, 0x06, 0xfb, 0xc5, 0xa6, 0xbc, 0xbe, 0xf1, 0x10, + 0x27, 0xd3, 0x66, 0xc6, 0x1b, 0x08, 0x16, 0xd3, 0x11, 0xe7, 0xef, 0xf5, 0x58, + 0x1b, 0xe6, 0xaf, 0x18, 0xe5, 0x3e, 0xef, 0xd9, 0xc6, 0x2f, 0x46, 0xc2, 0x09, + 0x2b, 0x08, 0x0a, 0x08, 0x17, 0x11, 0x1c, 0x1d, 0x2c, 0xf7, 0xf8, 0x14, 0xfc, + 0x2f, 0xff, 0xe3, 0xf0, 0x35, 0x4a, 0x28, 0xe4, 0x09, 0xf8, 0xfd, 0xce, 0x36, + 0xbe, 0xf3, 0xdc, 0x9f, 0x3c, 0xdd, 0xe1, 0xe7, 0x13, 0xb2, 0xeb, 0xe9, 0xfd, + 0xb7, 0x1a, 0xf7, 0x09, 0x46, 0xf5, 0x13, 0x0d, 0x01, 0x13, 0x5d, 0x22, 0xfa, + 0xe7, 0xe4, 0x37, 0x1d, 0x14, 0xf5, 0xf4, 0xff, 0xd1, 0x1e, 0xf0, 0xff, 0x8c, + 0xf8, 0xcf, 0x0e, 0xbc, 0x24, 0x09, 0xd8, 0xc1, 0xfe, 0xca, 0x04, 0xd7, 0x09, + 0xf8, 0xc9, 0xf0, 0xaf, 0xd4, 0xb6, 0xd8, 0x2b, 0xe0, 0xfe, 0x0a, 0xf0, 0xd9, + 0x00, 0x7f, 0xf4, 0xf0, 0x2d, 0xbb, 0x18, 0xdb, 0x02, 0xed, 0xd1, 0x0c, 0xb6, + 0xcf, 0x0f, 0x16, 0xe5, 0x0a, 0xfc, 0xd7, 0x5e, 0x1d, 0xc0, 0x31, 0xe5, 0xd0, + 0x20, 0x0e, 0x5b, 0xee, 0x6a, 0xf4, 0x1c, 0xfa, 0xeb, 0xda, 0xff, 0x2a, 0x26, + 0x43, 0x04, 0x20, 0xd1, 0xfd, 0x46, 0x00, 0xf1, 0x30, 0x36, 0x63, 0xe8, 0xf1, + 0xe7, 0x4a, 0x42, 0xf4, 0xe8, 0xcc, 0x4e, 0xdc, 0xac, 0x0c, 0xb7, 0xb8, 0x1f, + 0xff, 0x27, 0xbd, 0xe1, 0x02, 0xdb, 0x2c, 0x1e, 0xe8, 0xb2, 0xea, 0xa0, 0x16, + 0x13, 0x59, 0xf0, 0xc2, 0x12, 0x1a, 0x5d, 0xea, 0xd9, 0xf5, 0x0f, 0xdc, 0xdf, + 0xdb, 0xc9, 0xff, 0xc9, 0xd7, 0xde, 0xdb, 0xf6, 0xca, 0x98, 0xed, 0xcd, 0x57, + 0xc9, 0xc8, 0xbf, 0x5d, 0xfe, 0x01, 0x99, 0xfb, 0x6d, 0x2a, 0xed, 0xe1, 0xdd, + 0x2b, 0x40, 0x19, 0xdb, 0xd5, 0x18, 0x04, 0xa1, 0x4c, 0xb6, 0x52, 0xb5, 0x10, + 0x0e, 0x07, 0x0f, 0xd1, 0xfb, 0xf6, 0x05, 0x33, 0xc6, 0xee, 0xe1, 0x91, 0xd5, + 0x0e, 0xca, 0xfd, 0xc9, 0x1b, 0xce, 0xff, 0xfb, 0x25, 0xdb, 0x7f, 0x03, 0x3c, + 0x0f, 0xcf, 0xfc, 0x49, 0x2e, 0x4e, 0xc1, 0xeb, 0xdf, 0x08, 0xc1, 0x26, 0xe7, + 0xee, 0xd0, 0xea, 0xf6, 0xf2, 0xc6, 0xe4, 0x0b, 0xef, 0x1b, 0x01, 0xa5, 0x09, + 0x24, 0xdf, 0xd7, 0xe0, 0xf7, 0xc6, 0x36, 0x44, 0xde, 0xcb, 0x1a, 0xcc, 0xe7, + 0xd0, 0xe9, 0x7f, 0x63, 0x0d, 0x21, 0x08, 0x01, 0x0f, 0x15, 0x05, 0xcc, 0x0a, + 0xcd, 0xee, 0xd5, 0x0a, 0x2b, 0xb2, 0x49, 0xf0, 0x16, 0x08, 0x2d, 0xff, 0x37, + 0x05, 0x19, 0x04, 0xcd, 0xfc, 0x1f, 0xe0, 0xd0, 0xa6, 0xf7, 0x6b, 0xcd, 0xf6, + 0x54, 0x26, 0xb8, 0xb5, 0x27, 0x0c, 0x01, 0xe1, 0x58, 0xdf, 0x15, 0xf6, 0xd2, + 0x1c, 0x21, 0xd5, 0x16, 0x07, 0xeb, 0xf2, 0x43, 0xd0, 0xbe, 0xf3, 0xca, 0xf5, + 0x0e, 0xdd, 0x0b, 0x01, 0xe2, 0xf5, 0xf5, 0xe4, 0xfa, 0xf0, 0x01, 0xe5, 0x0c, + 0xf9, 0x16, 0xfa, 0xe0, 0xf4, 0x12, 0xfb, 0x16, 0x33, 0xe7, 0xc5, 0x07, 0x25, + 0x12, 0xa6, 0xcd, 0x03, 0x08, 0xe1, 0xe1, 0xec, 0xf4, 0xe0, 0x20, 0x0c, 0x73, + 0xc2, 0x33, 0xed, 0x00, 0xf3, 0x2c, 0xed, 0x1f, 0x04, 0x24, 0x3e, 0xdd, 0x3c, + 0x15, 0x4d, 0x1b, 0x0e, 0x0a, 0xf9, 0x35, 0x29, 0xdd, 0x1b, 0xbd, 0x51, 0x32, + 0x04, 0x0d, 0xfa, 0x38, 0x6a, 0xd5, 0x2c, 0x25, 0x1c, 0x07, 0xd4, 0xf5, 0x0e, + 0xbf, 0x06, 0xfc, 0x2c, 0x0b, 0x2a, 0x3b, 0xf9, 0xab, 0x24, 0x1e, 0xf0, 0x04, + 0xe7, 0x18, 0xd9, 0xf1, 0x00, 0xeb, 0x09, 0xe1, 0xd2, 0xfc, 0xf1, 0xf4, 0xf0, + 0xf3, 0x48, 0x1b, 0x0d, 0xd7, 0xfa, 0xcf, 0xff, 0xc4, 0xf0, 0xe0, 0xc9, 0x81, + 0x70, 0x09, 0xbe, 0x17, 0xad, 0x19, 0x99, 0xea, 0xd4, 0x02, 0x1d, 0x1c, 0xd4, + 0xdb, 0xf3, 0x3c, 0xbe, 0xc9, 0x2a, 0x1f, 0xe4, 0x4a, 0xeb, 0x06, 0x04, 0x47, + 0xfd, 0xc7, 0xa7, 0xca, 0xed, 0xf0, 0xca, 0xd0, 0xc6, 0xf4, 0x16, 0xc0, 0xe4, + 0xdb, 0x0b, 0xde, 0x0d, 0xd2, 0xda, 0xbd, 0xe4, 0x09, 0x0d, 0xa3, 0x04, 0x91, + 0x06, 0xfa, 0x26, 0x00, 0xfb, 0xe1, 0xe6, 0xe4, 0x1f, 0xf7, 0x04, 0xef, 0x5a, + 0x11, 0xe2, 0x27, 0x40, 0xe7, 0x0d, 0xd4, 0x3a, 0xf9, 0xe5, 0x2f, 0xac, 0xf8, + 0x3a, 0xd7, 0xe7, 0x07, 0xda, 0xd9, 0xec, 0xd7, 0xfa, 0x25, 0xc2, 0xfd, 0xed, + 0xd9, 0x02, 0xc4, 0x4e, 0x2f, 0x48, 0x0c, 0xc5, 0x25, 0xc2, 0xf5, 0x3b, 0x0a, + 0x42, 0xe2, 0x32, 0xdd, 0xba, 0xfc, 0xe2, 0xda, 0x2a, 0xd7, 0xd0, 0x1c, 0xc2, + 0x22, 0x6b, 0xe0, 0xf1, 0x06, 0x02, 0xfe, 0xeb, 0xdb, 0x16, 0x17, 0x07, 0xc5, + 0x10, 0x00, 0xeb, 0x2f, 0x11, 0xd4, 0xfc, 0x0b, 0x1f, 0xee, 0xc1, 0xe4, 0x7f, + 0x1e, 0xe6, 0xc3, 0xe6, 0x19, 0x10, 0xd3, 0x0e, 0xea, 0x19, 0xef, 0x5c, 0xf8, + 0x2a, 0x08, 0xfe, 0x0d, 0x2a, 0x44, 0x10, 0xe3, 0xf4, 0x04, 0x4f, 0x2e, 0xd7, + 0xcb, 0x05, 0x45, 0xf6, 0xf2, 0x0f, 0x03, 0xe7, 0x0e, 0x0c, 0xf6, 0x0b, 0xf0, + 0x26, 0xe9, 0xfd, 0xc8, 0xad, 0x15, 0x25, 0xc7, 0xf6, 0x4f, 0x13, 0xed, 0x09, + 0x14, 0xe8, 0xc2, 0xfc, 0xe9, 0x0a, 0xbf, 0x48, 0x42, 0xf1, 0x53, 0x37, 0xdb, + 0x36, 0xcf, 0xdf, 0x0e, 0x11, 0x19, 0x02, 0xe7, 0x09, 0x5d, 0x0f, 0xf5, 0x2a, + 0x22, 0xd6, 0x27, 0xe2, 0xf4, 0x4e, 0x86, 0x00, 0xbc, 0xbc, 0xec, 0xca, 0xfc, + 0xf4, 0xfb, 0x24, 0xf5, 0x2b, 0x14, 0x0b, 0x31, 0x51, 0xae, 0xb8, 0x1f, 0x13, + 0xff, 0x34, 0xee, 0xd1, 0x0f, 0x19, 0x1b, 0x72, 0xfe, 0x5f, 0x15, 0x00, 0x0f, + 0xbe, 0x09, 0x1b, 0xeb, 0xf4, 0x41, 0x21, 0x73, 0xa9, 0xc3, 0x17, 0xf0, 0x27, + 0xc2, 0x06, 0x57, 0xd5, 0xf1, 0x34, 0x39, 0x1b, 0x81, 0x4a, 0x09, 0x23, 0x9e, + 0x2b, 0xee, 0xdb, 0x21, 0x65, 0x03, 0x33, 0xdd, 0x0b, 0x06, 0x1f, 0x6e, 0x2b, + 0x02, 0xe8, 0x11, 0x09, 0x16, 0xfc, 0xf0, 0xfe, 0xda, 0xf2, 0xd3, 0xfc, 0xb3, + 0xfd, 0x07, 0xea, 0x05, 0x3a, 0xc6, 0x02, 0xff, 0x5c, 0xa1, 0x42, 0x36, 0x1b, + 0x36, 0x04, 0xd2, 0xfc, 0x03, 0x2b, 0xf4, 0x08, 0xfc, 0xb0, 0x14, 0x52, 0x06, + 0x13, 0x60, 0x26, 0xde, 0xd4, 0x06, 0xfb, 0xcf, 0xd4, 0xe6, 0xf4, 0x1f, 0x02, + 0x1c, 0xfd, 0xf8, 0x04, 0x33, 0xc4, 0x07, 0xe3, 0x56, 0x47, 0x03, 0x36, 0x1a, + 0x7f, 0x19, 0xb0, 0x1c, 0x53, 0x0c, 0xb4, 0xfc, 0x44, 0x14, 0x01, 0x2e, 0x22, + 0x1a, 0xf5, 0x11, 0xf3, 0xd1, 0xe6, 0xd7, 0x37, 0xfb, 0xc8, 0x17, 0xe7, 0x2d, + 0x07, 0x36, 0xe4, 0xd4, 0x0e, 0x19, 0x10, 0x0e, 0x3c, 0x1a, 0xb8, 0x3c, 0x37, + 0x14, 0xeb, 0xf4, 0xda, 0xe0, 0xed, 0x0f, 0x04, 0x06, 0xe8, 0xc7, 0x27, 0xed, + 0xf5, 0xcf, 0xc8, 0x18, 0x4c, 0x2c, 0xf0, 0xb4, 0x28, 0x3b, 0x0e, 0xf6, 0xd9, + 0x12, 0xdd, 0xe6, 0xce, 0xf5, 0xdf, 0x01, 0xb9, 0xef, 0x08, 0x3c, 0x1b, 0xe1, + 0xcc, 0x0f, 0x18, 0xf8, 0xf0, 0xfd, 0xc3, 0xf9, 0xf4, 0xd8, 0x07, 0xe7, 0xdb, + 0xe8, 0xe2, 0x2a, 0x11, 0x0d, 0x2c, 0x3e, 0xe8, 0x14, 0x3e, 0xdf, 0x0b, 0xef, + 0x28, 0xea, 0x24, 0xd6, 0x1f, 0xf3, 0xef, 0x1c, 0x16, 0xfd, 0xcd, 0xd4, 0x42, + 0xc3, 0x7f, 0x0a, 0x07, 0x1d, 0x09, 0x28, 0x3e, 0x01, 0xec, 0xf0, 0x11, 0xd1, + 0x58, 0xf0, 0x39, 0x43, 0x1f, 0x1b, 0x48, 0x05, 0xec, 0x34, 0x0a, 0x23, 0x08, + 0x01, 0xfd, 0x08, 0x01, 0x41, 0xec, 0x12, 0xed, 0xf1, 0xed, 0xe8, 0xc3, 0x20, + 0xf2, 0xe1, 0x11, 0xce, 0xd7, 0xd8, 0xf2, 0xcf, 0x01, 0x0c, 0x0c, 0x17, 0xc9, + 0x06, 0x26, 0x27, 0x09, 0xed, 0x0d, 0x20, 0x04, 0xcf, 0xb2, 0xe4, 0xe9, 0xda, + 0x08, 0x12, 0x5b, 0xcd, 0xe9, 0xef, 0x14, 0xe2, 0x4d, 0xcc, 0xf0, 0x15, 0x06, + 0x10, 0xec, 0xd8, 0x51, 0xea, 0xce, 0x0b, 0x35, 0xcc, 0xdb, 0xcf, 0xfa, 0x0e, + 0x32, 0xe5, 0x11, 0x16, 0x05, 0x2e, 0xd0, 0xf8, 0xee, 0xf9, 0x15, 0xf7, 0x25, + 0xf4, 0xe3, 0x12, 0xe6, 0xcf, 0xdb, 0xf8, 0x06, 0x0f, 0xe3, 0x36, 0xed, 0x09, + 0xf8, 0xe4, 0x0d, 0xe0, 0xe2, 0x08, 0xe3, 0xee, 0x09, 0xe4, 0x11, 0x1c, 0x3b, + 0xaf, 0xee, 0x08, 0xfe, 0xed, 0x00, 0xf8, 0xf9, 0xe2, 0x4c, 0x0a, 0x0f, 0x0d, + 0xff, 0x07, 0xf1, 0xfc, 0x09, 0xf8, 0x21, 0xf0, 0xc6, 0x0d, 0xf5, 0xf8, 0xd8, + 0x35, 0x20, 0xeb, 0x16, 0xea, 0xfd, 0x20, 0xd1, 0xe0, 0xd6, 0xde, 0xfe, 0xe3, + 0xe1, 0x0f, 0x81, 0xf9, 0x29, 0xf5, 0x60, 0xca, 0xf8, 0x0f, 0xff, 0x0a, 0x0c, + 0xd9, 0xe2, 0xc9, 0x1e, 0xf3, 0x06, 0xfc, 0xff, 0xe6, 0xd9, 0x25, 0x1c, 0xf0, + 0x19, 0xfa, 0xef, 0xd3, 0xcb, 0xdb, 0x0b, 0x06, 0xe1, 0xfb, 0xec, 0xe8, 0x00, + 0x16, 0x11, 0xf8, 0x1d, 0xf4, 0x06, 0x1e, 0x09, 0xe6, 0x18, 0xdc, 0xe7, 0x04, + 0x0c, 0x06, 0xd2, 0x08, 0xec, 0xf6, 0xd3, 0xf2, 0xfc, 0xf7, 0xd3, 0xe8, 0xfd, + 0x0a, 0xf0, 0x07, 0x0e, 0xc6, 0xe2, 0x0e, 0x13, 0xd8, 0x04, 0x0e, 0xf2, 0xef, + 0x01, 0x03, 0xea, 0x22, 0xdd, 0x03, 0x00, 0xaa, 0x21, 0xe2, 0x23, 0xdf, 0x06, + 0xe0, 0xec, 0xe6, 0x26, 0xd6, 0xf2, 0xeb, 0x04, 0xf5, 0xcd, 0xee, 0x10, 0xfd, + 0xc9, 0x7f, 0x15, 0x0f, 0xfc, 0x16, 0x26, 0x19, 0xca, 0x10, 0x11, 0xda, 0x1f, + 0x06, 0x0b, 0x12, 0x1d, 0xfa, 0xf5, 0x04, 0xd3, 0xfe, 0xfd, 0x21, 0xee, 0x1a, + 0x05, 0x12, 0x0e, 0x0d, 0xe4, 0xe5, 0x10, 0xf5, 0xd8, 0xf2, 0x1a, 0x0c, 0x29, + 0x0f, 0xfe, 0xdd, 0xda, 0xe2, 0x02, 0xf8, 0x01, 0xf6, 0x04, 0xdf, 0x2e, 0xf2, + 0xd4, 0x40, 0xb5, 0xf4, 0xa3, 0xcb, 0x09, 0x54, 0x33, 0xea, 0xe8, 0xb3, 0x16, + 0x1a, 0x41, 0x06, 0x1e, 0x39, 0x1c, 0x09, 0xed, 0x31, 0x26, 0x69, 0xce, 0x19, + 0xba, 0x52, 0xea, 0xab, 0x21, 0xd8, 0xc9, 0xca, 0x0b, 0x3c, 0xd4, 0x7f, 0xda, + 0x01, 0x51, 0x12, 0xe7, 0x29, 0x1c, 0x9e, 0xea, 0xea, 0xea, 0xe0, 0xf4, 0xeb, + 0xf0, 0x1e, 0xed, 0x0e, 0xc8, 0x0d, 0xbb, 0xc6, 0xcc, 0xc7, 0xc6, 0xc2, 0xf3, + 0xf8, 0x2f, 0x14, 0x90, 0xe5, 0x9c, 0xcf, 0xf3, 0xb5, 0xa2, 0x8d, 0x09, 0xcc, + 0xe7, 0x00, 0xed, 0x6c, 0x83, 0xc1, 0xc6, 0xab, 0xf6, 0xef, 0x04, 0x4e, 0xe4, + 0x43, 0x12, 0xdd, 0x1a, 0xb0, 0x2e, 0xc8, 0xff, 0xe4, 0xf5, 0xce, 0xe7, 0x1d, + 0xd4, 0x18, 0x0c, 0x19, 0x18, 0x2f, 0x9c, 0x49, 0x13, 0x54, 0x1b, 0x07, 0x0f, + 0xc6, 0xb4, 0xcf, 0xd8, 0xed, 0x0f, 0xeb, 0x3b, 0xfd, 0x49, 0xf9, 0x60, 0x08, + 0x26, 0xec, 0xfe, 0x05, 0xee, 0x12, 0x76, 0xde, 0xdf, 0x0c, 0xe1, 0x18, 0xfc, + 0x24, 0xeb, 0x98, 0x20, 0x39, 0x9f, 0xfc, 0xd6, 0x2e, 0x3b, 0xee, 0xfc, 0x0e, + 0xdd, 0xd5, 0x1e, 0x18, 0xb0, 0xb3, 0xeb, 0xb3, 0xf4, 0xf9, 0x28, 0x71, 0xe2, + 0x91, 0x07, 0xe1, 0x1a, 0xd9, 0xc5, 0xfb, 0x20, 0xcb, 0x7a, 0x27, 0xe0, 0x26, + 0x38, 0xde, 0x65, 0xf7, 0xba, 0xd1, 0xe6, 0x05, 0x0b, 0x00, 0xff, 0x28, 0x9c, + 0xe9, 0xff, 0x08, 0x23, 0xca, 0xb7, 0x3b, 0xc8, 0x06, 0x64, 0xc3, 0xe0, 0xe8, + 0x33, 0xdb, 0x6d, 0x46, 0x81, 0xce, 0x21, 0x0a, 0x6e, 0x02, 0x19, 0xee, 0xbf, + 0x2a, 0x9b, 0xf0, 0x2b, 0xe9, 0x76, 0x16, 0x69, 0xfa, 0x05, 0xd5, 0xf5, 0x3d, + 0x1f, 0xc0, 0x24, 0x1e, 0x0d, 0x38, 0xe5, 0x48, 0xf9, 0xf5, 0xf9, 0x35, 0x21, + 0x9a, 0x5b, 0x1d, 0x19, 0x17, 0x18, 0xda, 0x53, 0xe1, 0xf5, 0x06, 0xf5, 0x0a, + 0xf1, 0xff, 0xf1, 0x4c, 0xe8, 0x02, 0xdd, 0x0e, 0x91, 0x56, 0xd9, 0xdb, 0xf5, + 0xea, 0x44, 0xfb, 0xe0, 0x21, 0xc9, 0xd8, 0x27, 0xc4, 0xc3, 0x0d, 0xf0, 0xd2, + 0xf3, 0xfe, 0x8d, 0x32, 0xfc, 0xf5, 0x29, 0x45, 0x40, 0x3a, 0xf5, 0x2f, 0x24, + 0xe6, 0x47, 0xef, 0x35, 0x1b, 0x07, 0x29, 0xd9, 0xe2, 0x14, 0xe0, 0x01, 0x32, + 0xf7, 0xbb, 0x20, 0xe2, 0x6b, 0x01, 0x7f, 0xed, 0xe0, 0x1c, 0xe0, 0x18, 0xe2, + 0x4a, 0x17, 0xb8, 0x22, 0xa2, 0xeb, 0x59, 0xe9, 0x1c, 0x1e, 0x99, 0x3a, 0x3b, + 0x44, 0xf8, 0xb2, 0x23, 0xe9, 0xc4, 0x0d, 0xa7, 0xe1, 0x16, 0x0b, 0xc8, 0xac, + 0xce, 0xb2, 0xcd, 0x17, 0x20, 0xd7, 0xdc, 0x15, 0x2b, 0xd7, 0x9d, 0x33, 0x8d, + 0x10, 0x43, 0x94, 0x35, 0x14, 0xd6, 0xf6, 0x3c, 0x02, 0x5e, 0xf7, 0x4a, 0xc0, + 0xfa, 0xf2, 0xfe, 0xf8, 0x28, 0x04, 0x17, 0xb8, 0xee, 0x19, 0xf1, 0xb9, 0x81, + 0xcc, 0x3a, 0xfe, 0xe4, 0x07, 0x51, 0x7a, 0x84, 0x29, 0x13, 0xb6, 0xb7, 0xf4, + 0x0c, 0x04, 0x93, 0xc4, 0x33, 0xe9, 0x38, 0xc6, 0x09, 0x0b, 0x01, 0xec, 0xec, + 0xfc, 0x3a, 0xc2, 0x4f, 0x4a, 0xc4, 0xcf, 0x1d, 0xaa, 0x27, 0xe9, 0x0a, 0x78, + 0xee, 0x1a, 0xfa, 0xc2, 0x01, 0xe7, 0xef, 0xf8, 0x10, 0x3c, 0x45, 0x43, 0xe8, + 0x24, 0x10, 0xaf, 0x60, 0x3a, 0x52, 0x17, 0xed, 0xce, 0xf5, 0xe7, 0x23, 0x3a, + 0xa3, 0xf8, 0x4f, 0x6e, 0x35, 0xd6, 0x6d, 0x23, 0xdb, 0xaf, 0xce, 0x4a, 0xfd, + 0xd8, 0xb1, 0x0f, 0xbb, 0xa3, 0x3b, 0xcf, 0xbf, 0xf6, 0xfc, 0xd1, 0xc6, 0x96, + 0xf5, 0x4f, 0xea, 0x0a, 0x0d, 0x32, 0xbd, 0xac, 0xe3, 0x9a, 0x29, 0x0b, 0xde, + 0x1a, 0x05, 0x21, 0x4c, 0x22, 0x2b, 0xbc, 0x47, 0x4e, 0xcc, 0xe1, 0x57, 0xe4, + 0xbf, 0x89, 0x36, 0xd6, 0x69, 0xf9, 0x91, 0x14, 0xc4, 0x17, 0x4c, 0xf6, 0xec, + 0xe6, 0x17, 0x02, 0xf7, 0xde, 0x0d, 0x0b, 0xd9, 0x10, 0xee, 0xcd, 0xdc, 0xf8, + 0x04, 0xbc, 0xf7, 0x00, 0xff, 0xfb, 0xd7, 0xb7, 0xd5, 0x21, 0xf1, 0xad, 0xd6, + 0xec, 0x38, 0x12, 0x7c, 0x07, 0xec, 0xc0, 0xf8, 0xeb, 0xba, 0x3f, 0xdd, 0xfb, + 0xd5, 0x2c, 0x0a, 0x01, 0xe4, 0xfe, 0xbe, 0xf5, 0x24, 0xba, 0xf2, 0x1a, 0xda, + 0xe5, 0x2e, 0xdf, 0xdc, 0xf0, 0x0f, 0x56, 0x0e, 0xf9, 0xe4, 0x03, 0x9c, 0xcb, + 0xca, 0xc9, 0xeb, 0x11, 0x15, 0x26, 0x0d, 0x1a, 0xc5, 0x2f, 0x14, 0x16, 0x04, + 0xf3, 0xfc, 0x21, 0xc8, 0xd7, 0x24, 0xe5, 0xfc, 0x81, 0xe9, 0x1c, 0xe9, 0xd6, + 0x13, 0xf9, 0x50, 0xdd, 0xe6, 0x30, 0x0d, 0xdf, 0xc9, 0xe2, 0xfd, 0x4f, 0x00, + 0x30, 0xd6, 0xf7, 0x0e, 0xee, 0xd0, 0x01, 0x12, 0x16, 0xf3, 0x17, 0x39, 0xa2, + 0xd6, 0x21, 0xf4, 0x02, 0xcf, 0xe9, 0xe6, 0x7f, 0xf6, 0x2d, 0x1b, 0x05, 0xe3, + 0x31, 0xf8, 0x4d, 0xfb, 0xa2, 0xe8, 0xef, 0x49, 0x04, 0x0d, 0xfd, 0xfc, 0x34, + 0x11, 0x37, 0xfd, 0x1c, 0x28, 0xca, 0xf3, 0xcd, 0x18, 0x2d, 0xde, 0xf9, 0xf0, + 0x19, 0x22, 0xb8, 0xab, 0xd2, 0x1e, 0x2c, 0xd0, 0x50, 0x31, 0xfa, 0xde, 0xf2, + 0x1d, 0xec, 0x5b, 0xef, 0xf2, 0x17, 0x04, 0x2a, 0x27, 0xd8, 0x87, 0x15, 0xf4, + 0xe0, 0x0a, 0xb4, 0x1a, 0xda, 0xe5, 0xf2, 0x13, 0x2f, 0x59, 0x29, 0x02, 0x66, + 0x5e, 0x00, 0xb4, 0x1e, 0x10, 0xf9, 0x9e, 0xda, 0xb0, 0x1b, 0xd2, 0xe5, 0x06, + 0x0d, 0x14, 0xff, 0x0c, 0x30, 0x3b, 0x24, 0x26, 0xd5, 0xcb, 0xcb, 0x1f, 0xf7, + 0x30, 0xf5, 0x36, 0xfa, 0x10, 0xac, 0xfb, 0x03, 0x2d, 0x4d, 0x2f, 0xe3, 0xf1, + 0x1a, 0xe4, 0xc7, 0x1d, 0x09, 0xd4, 0x5a, 0x39, 0xe5, 0xe6, 0x4b, 0x13, 0x23, + 0xcb, 0xf7, 0xde, 0x14, 0x38, 0x50, 0x2a, 0x26, 0xe1, 0xbc, 0xf4, 0x16, 0xe3, + 0x08, 0x32, 0x30, 0x75, 0x10, 0x07, 0x1d, 0xd9, 0x15, 0xa5, 0xf9, 0xc2, 0xf1, + 0xf2, 0x10, 0x18, 0xf5, 0x01, 0x4c, 0xf6, 0x6e, 0xf1, 0x0e, 0xdb, 0xc8, 0xf9, + 0x3c, 0x07, 0xe5, 0xfb, 0xea, 0xa4, 0x1c, 0x10, 0x29, 0x26, 0x27, 0x13, 0x0a, + 0x6c, 0xec, 0x0b, 0xc2, 0xd2, 0x15, 0xa3, 0xfa, 0xcd, 0x9a, 0x11, 0x08, 0x23, + 0xe1, 0xed, 0x3c, 0xf9, 0x1f, 0x00, 0xeb, 0x04, 0x47, 0x2f, 0x0f, 0x1f, 0x7f, + 0xcf, 0xd5, 0xe3, 0x5e, 0x20, 0x6e, 0x13, 0x33, 0x1c, 0xed, 0x7b, 0x18, 0xc1, + 0xeb, 0xbf, 0x38, 0x60, 0x4c, 0xd9, 0xf7, 0xee, 0xf7, 0x03, 0x49, 0xb6, 0xee, + 0xc3, 0x3d, 0x05, 0x73, 0xa3, 0x1b, 0x22, 0xfa, 0x14, 0x25, 0xc5, 0xf5, 0x9a, + 0x0b, 0x00, 0xde, 0x33, 0xff, 0x10, 0x1b, 0x3e, 0xff, 0x00, 0xea, 0xdb, 0xb4, + 0x48, 0xde, 0xe8, 0xeb, 0x0d, 0xe4, 0xfc, 0x14, 0x1c, 0x0d, 0x4d, 0xf4, 0x04, + 0x40, 0xae, 0x1e, 0x5c, 0x61, 0x66, 0xda, 0xa7, 0xed, 0xde, 0xfd, 0x21, 0xa4, + 0x3f, 0xd0, 0x04, 0x76, 0xe9, 0xfd, 0x60, 0xe3, 0xa4, 0x34, 0x00, 0x39, 0x08, + 0xce, 0xcf, 0xd3, 0x0a, 0xd7, 0xd5, 0x2d, 0x07, 0x1c, 0xe4, 0xf4, 0x6a, 0xf5, + 0x38, 0xf8, 0xf3, 0x24, 0x4b, 0x25, 0x17, 0x10, 0x01, 0x16, 0x1f, 0x17, 0x02, + 0x02, 0xf6, 0x08, 0xd6, 0xd0, 0x3e, 0x3f, 0xeb, 0x2f, 0x4d, 0x3f, 0x7f, 0x90, + 0xf4, 0xe2, 0x08, 0x23, 0x10, 0xd6, 0xf5, 0xc7, 0xb4, 0x23, 0x2e, 0xaf, 0xff, + 0xed, 0x94, 0xb6, 0xec, 0xea, 0xb7, 0x49, 0x43, 0xb6, 0x41, 0x3b, 0x0a, 0xe0, + 0xdb, 0x29, 0x0b, 0x6a, 0x9c, 0xcb, 0x15, 0x16, 0xe5, 0xd6, 0x4b, 0xb6, 0x0b, + 0x42, 0xed, 0x06, 0x04, 0x4b, 0xcb, 0x52, 0x51, 0x18, 0x41, 0x1c, 0x0c, 0xfb, + 0x12, 0xe9, 0xce, 0x0f, 0xca, 0x4d, 0x3f, 0x2e, 0x12, 0x0d, 0xd2, 0x2a, 0xf9, + 0xed, 0x3e, 0x2d, 0xd5, 0xb9, 0x75, 0xe1, 0x0a, 0x31, 0xda, 0x39, 0x42, 0xc0, + 0xda, 0x2a, 0x38, 0x12, 0xdc, 0xde, 0xc5, 0xe1, 0x28, 0x0c, 0x55, 0xd4, 0xfd, + 0xf5, 0xea, 0x38, 0xe9, 0xfe, 0x0c, 0x55, 0x51, 0x2a, 0x2f, 0x17, 0xee, 0xf6, + 0xed, 0x07, 0xb2, 0xf6, 0xf4, 0x22, 0xf9, 0x55, 0x28, 0xf5, 0xdf, 0xc9, 0xd5, + 0x09, 0x2f, 0xd6, 0xae, 0x3b, 0xc3, 0xf1, 0x44, 0xd4, 0x0b, 0xb8, 0x46, 0x18, + 0xc5, 0xdb, 0xf4, 0x1e, 0xe9, 0x4a, 0x64, 0x00, 0x33, 0xbc, 0x03, 0xe6, 0x3e, + 0x2a, 0x20, 0xf9, 0xb8, 0x2a, 0xec, 0xc9, 0x11, 0xcc, 0xea, 0x2f, 0x1b, 0x1d, + 0xe6, 0x1c, 0xd9, 0xd9, 0xd7, 0x22, 0xd8, 0x17, 0xd7, 0x0c, 0x45, 0xbb, 0xed, + 0xb8, 0x74, 0x0d, 0x20, 0xd1, 0x19, 0x1d, 0xf0, 0xf9, 0x7f, 0x2f, 0xee, 0x30, + 0x2c, 0xf4, 0xf6, 0x1a, 0x05, 0x10, 0xfe, 0xca, 0xff, 0xf6, 0xdb, 0x0c, 0xde, + 0x23, 0xcc, 0xec, 0x08, 0x09, 0xf4, 0xd8, 0xda, 0xd6, 0xf7, 0xfd, 0x0c, 0x3c, + 0xfe, 0xdb, 0xdd, 0x00, 0x20, 0xfa, 0x32, 0xdb, 0x11, 0xee, 0xc7, 0xf6, 0x0c, + 0xe9, 0xe8, 0xf2, 0x3d, 0x18, 0xf3, 0x28, 0xba, 0x08, 0xdc, 0x04, 0xca, 0x04, + 0xbb, 0xfe, 0x24, 0x8f, 0xf1, 0xc3, 0x1c, 0x48, 0x0b, 0x13, 0x08, 0xd1, 0x05, + 0x5c, 0xf2, 0xfd, 0x0d, 0xee, 0xf8, 0x27, 0xc2, 0x3d, 0xd6, 0x1e, 0x2c, 0x03, + 0xef, 0x55, 0xfd, 0xef, 0xe2, 0x18, 0x08, 0xee, 0x04, 0x0b, 0xdd, 0xfe, 0x0c, + 0x5a, 0xd3, 0xf9, 0xec, 0x05, 0x2e, 0x02, 0x5a, 0x2f, 0xf0, 0x3c, 0xe4, 0xee, + 0x28, 0xe1, 0x15, 0xda, 0xbd, 0xda, 0x22, 0x4d, 0xe2, 0x6e, 0xab, 0x22, 0xec, + 0xfd, 0x12, 0xfb, 0xec, 0x20, 0x12, 0x81, 0xf8, 0xe9, 0xef, 0x11, 0x17, 0x28, + 0x45, 0x92, 0x0a, 0xb5, 0x10, 0x35, 0xbe, 0xf3, 0xdb, 0x31, 0xea, 0xf1, 0xeb, + 0xe4, 0x2c, 0xfe, 0xe1, 0x1c, 0xf4, 0x20, 0xd9, 0x23, 0xfc, 0x07, 0x2b, 0xab, + 0x13, 0x2d, 0x2b, 0xdf, 0x2b, 0xf6, 0x31, 0xe7, 0x06, 0xef, 0x06, 0xfb, 0x02, + 0xec, 0x18, 0x33, 0x81, 0x23, 0x0c, 0x01, 0xba, 0x09, 0x3e, 0x6a, 0x67, 0x1b, + 0xe1, 0x0e, 0x07, 0xfd, 0xd9, 0xd7, 0x04, 0xff, 0xd2, 0x2b, 0x08, 0x2c, 0xad, + 0xc6, 0x10, 0x2f, 0x11, 0xf0, 0xde, 0x03, 0xd6, 0x40, 0xe7, 0x38, 0x04, 0xfa, + 0xfb, 0xfa, 0x40, 0x14, 0x0f, 0xe8, 0xea, 0xdb, 0xf9, 0xc7, 0x35, 0x27, 0xe3, + 0x16, 0x45, 0x1c, 0xe8, 0x2c, 0x2a, 0x36, 0xc3, 0xf2, 0x2e, 0xee, 0x6f, 0x5b, + 0xe8, 0x27, 0x27, 0xf5, 0xa3, 0x1b, 0x00, 0x44, 0xec, 0xcf, 0xd9, 0x2b, 0x53, + 0x12, 0xeb, 0xd8, 0xeb, 0xbf, 0x0e, 0x43, 0xa8, 0x0f, 0xd3, 0x17, 0xcf, 0x10, + 0x2e, 0x0d, 0xe8, 0xff, 0xe2, 0xf6, 0x1a, 0xd6, 0x08, 0x24, 0x4a, 0xa8, 0x0d, + 0x13, 0x28, 0x3a, 0x1c, 0x69, 0x25, 0x08, 0xfc, 0x15, 0x0a, 0x17, 0x14, 0xe4, + 0xb7, 0xe9, 0xdc, 0x06, 0xd8, 0xf9, 0x3a, 0x02, 0xe4, 0x16, 0x35, 0x3f, 0xfb, + 0x11, 0x7f, 0x0b, 0x1e, 0x10, 0x4b, 0x10, 0x48, 0xe5, 0x20, 0xe3, 0xe4, 0x3f, + 0x28, 0xd9, 0x0b, 0xe4, 0xec, 0xe3, 0x0b, 0xbd, 0xe3, 0xe2, 0x77, 0x1e, 0xdd, + 0x07, 0x30, 0x1e, 0xd6, 0xe9, 0x0d, 0xeb, 0xc4, 0xfd, 0x14, 0xed, 0xe1, 0x21, + 0xfc, 0xe8, 0xcb, 0x31, 0xd4, 0x2b, 0xff, 0x4e, 0xff, 0xf3, 0xe6, 0x32, 0xff, + 0x16, 0x10, 0xfe, 0xce, 0xc4, 0x04, 0xf6, 0xe6, 0x25, 0xa6, 0x1a, 0x15, 0x08, + 0x1c, 0x21, 0xd2, 0xd2, 0xd9, 0x1f, 0xd3, 0x09, 0xff, 0x1c, 0xeb, 0xf1, 0x08, + 0xda, 0xc6, 0xff, 0xd7, 0x3c, 0x38, 0x29, 0xf2, 0x22, 0x01, 0xf8, 0x00, 0xec, + 0xd1, 0xe6, 0x34, 0x1d, 0xe9, 0xe4, 0x03, 0xda, 0xfe, 0x11, 0x09, 0xf9, 0xef, + 0x38, 0x0c, 0xe1, 0x59, 0xc6, 0xbe, 0xff, 0xcf, 0x1b, 0xe6, 0xf5, 0xf4, 0x2d, + 0x15, 0xe5, 0xca, 0x32, 0x3a, 0x09, 0xa1, 0x0e, 0x17, 0xd9, 0xe4, 0x02, 0xee, + 0xeb, 0x19, 0xcd, 0xcd, 0xf0, 0xe0, 0xdc, 0x1f, 0xec, 0xcc, 0xd3, 0x16, 0xfb, + 0xbf, 0xa6, 0x0f, 0xf0, 0x17, 0xd6, 0xcd, 0x18, 0xcc, 0xca, 0x56, 0x1e, 0xe9, + 0x1f, 0xb8, 0x7f, 0xc6, 0x30, 0xe2, 0xf3, 0xba, 0x0b, 0xf8, 0xcd, 0xf8, 0x1e, + 0xc8, 0x01, 0xeb, 0xec, 0xe4, 0x1a, 0x21, 0x27, 0xab, 0xe5, 0xe9, 0xed, 0x0a, + 0xfd, 0xe5, 0x1f, 0x02, 0xee, 0xfa, 0xef, 0x14, 0x61, 0x39, 0xf6, 0xf0, 0xeb, + 0x01, 0x15, 0xee, 0x1b, 0xf0, 0xe2, 0xb0, 0x0a, 0x33, 0x58, 0xc4, 0xd4, 0x02, + 0xe1, 0x0e, 0xb6, 0xce, 0x4e, 0xd5, 0x2b, 0x13, 0x11, 0x0e, 0x18, 0xce, 0xf6, + 0x49, 0x01, 0x5a, 0xc9, 0x27, 0x00, 0x38, 0xfd, 0x06, 0x2a, 0x3b, 0xd6, 0x29, + 0xe7, 0x34, 0xc6, 0x0b, 0xe4, 0xf5, 0x5b, 0xe3, 0x04, 0xbb, 0xb3, 0x2f, 0xac, + 0xd9, 0x35, 0x53, 0x2f, 0xb3, 0xf6, 0x18, 0x38, 0xb0, 0x05, 0x12, 0x37, 0x1d, + 0x00, 0x0b, 0xda, 0x42, 0xd7, 0xb3, 0xda, 0xd9, 0x00, 0xf7, 0xe8, 0xdc, 0x01, + 0xd4, 0x20, 0x18, 0xe0, 0x6e, 0xf5, 0x44, 0x28, 0xdb, 0xcd, 0xe3, 0x2f, 0xc3, + 0x25, 0x32, 0xef, 0x39, 0x0c, 0x0e, 0xf0, 0xd4, 0x0c, 0xe0, 0xee, 0x12, 0x49, + 0x2b, 0xbe, 0x1f, 0x38, 0xe4, 0xec, 0x8e, 0x01, 0xf5, 0xf2, 0xc8, 0xad, 0xfe, + 0xe8, 0x03, 0xd3, 0xc9, 0x3d, 0x18, 0x13, 0x26, 0xd4, 0xd5, 0x26, 0xcf, 0xef, + 0xf8, 0xec, 0xea, 0x5e, 0x17, 0x32, 0xf0, 0x0b, 0xe1, 0x68, 0x81, 0x31, 0xe6, + 0xc0, 0x09, 0x06, 0xe9, 0xf0, 0x1b, 0xef, 0x51, 0x4f, 0x50, 0xfa, 0xdb, 0xe0, + 0x0b, 0xf5, 0xe8, 0xd4, 0xd8, 0x1d, 0x06, 0x15, 0xf0, 0x05, 0xfd, 0xd6, 0x01, + 0xff, 0x3b, 0xd7, 0x07, 0xf2, 0xa4, 0xd4, 0x06, 0xfa, 0x10, 0xf9, 0xe9, 0xf0, + 0x17, 0x28, 0xff, 0x0b, 0x1b, 0xe2, 0x1f, 0xfa, 0xf9, 0x2b, 0x19, 0xd1, 0xe8, + 0xe2, 0xcd, 0x25, 0xd6, 0xf5, 0xcf, 0x4a, 0xff, 0xec, 0x09, 0x1f, 0xee, 0xfd, + 0x1c, 0xde, 0x7f, 0x4d, 0x50, 0xd1, 0xef, 0x25, 0xe1, 0xc5, 0xcc, 0xae, 0x1a, + 0xc9, 0x11, 0xf9, 0x13, 0x1b, 0x0f, 0xf5, 0xef, 0x23, 0x0f, 0x09, 0x22, 0x18, + 0x3c, 0x2b, 0xcc, 0xdf, 0xf1, 0x12, 0x17, 0xdc, 0x39, 0xe1, 0xf0, 0xee, 0x1a, + 0x04, 0xf3, 0x1a, 0x0e, 0x14, 0xe5, 0xf2, 0x41, 0x1f, 0xeb, 0x39, 0xe7, 0xfa, + 0x0b, 0x26, 0xc7, 0xe9, 0xd8, 0xde, 0xfa, 0x17, 0x55, 0x08, 0xe7, 0xe4, 0xba, + 0xf5, 0xfe, 0xf6, 0x40, 0x10, 0x0c, 0xda, 0x02, 0x19, 0xe3, 0x19, 0xe5, 0xf0, + 0xaf, 0xe7, 0xd1, 0x34, 0x2b, 0xfa, 0x07, 0xec, 0xd4, 0xcc, 0x15, 0xdb, 0xf9, + 0x20, 0x1b, 0xc8, 0x08, 0xf0, 0xda, 0xe0, 0xef, 0x30, 0x19, 0xe1, 0xfa, 0xf1, + 0x1b, 0xe7, 0xd1, 0x00, 0xbc, 0xc7, 0x1a, 0xcd, 0xfb, 0x1a, 0xf5, 0x3b, 0xde, + 0xd0, 0x81, 0xf1, 0xe5, 0x08, 0xe8, 0xe6, 0xdf, 0x03, 0x42, 0xff, 0x41, 0x14, + 0x15, 0xde, 0xc1, 0x01, 0xfc, 0x93, 0xe2, 0x02, 0xae, 0x55, 0xfc, 0xbf, 0xd9, + 0x0a, 0xff, 0x3a, 0xc5, 0xf3, 0xf5, 0x36, 0xeb, 0x25, 0x01, 0xd1, 0xeb, 0xcc, + 0xeb, 0x29, 0x73, 0x11, 0xd5, 0xed, 0x1f, 0x19, 0x07, 0xf5, 0xe3, 0x6e, 0xe2, + 0x0e, 0x09, 0x02, 0x32, 0xf7, 0x96, 0xdd, 0x2a, 0x34, 0x06, 0x25, 0x4a, 0xf6, + 0xef, 0xd7, 0x22, 0x1f, 0xe1, 0x15, 0x16, 0x05, 0x69, 0xe4, 0x10, 0x11, 0x5a, + 0x10, 0xd5, 0xf4, 0xce, 0xb4, 0xd1, 0x2f, 0xbf, 0x0f, 0x38, 0xfc, 0xbe, 0xf2, + 0xb4, 0xee, 0x99, 0xeb, 0x10, 0xf4, 0x25, 0xf9, 0x05, 0x04, 0xec, 0xff, 0x2b, + 0x4f, 0x16, 0xc3, 0xe7, 0xfb, 0xed, 0xf6, 0xe4, 0xfd, 0xbf, 0xf7, 0x1b, 0x43, + 0x11, 0xd2, 0x37, 0x49, 0xe6, 0x11, 0xd6, 0x10, 0xdc, 0xed, 0x21, 0xf2, 0xcd, + 0x14, 0x1f, 0x04, 0x2e, 0x02, 0xf3, 0xf4, 0x18, 0xe3, 0x0b, 0x36, 0xeb, 0xe5, + 0xec, 0xc3, 0x17, 0xac, 0xd1, 0xce, 0x99, 0xdd, 0x00, 0x0e, 0x33, 0xe1, 0x7c, + 0xff, 0x50, 0x19, 0x02, 0x3c, 0xe9, 0x0d, 0x59, 0xf5, 0x23, 0xd4, 0x2a, 0x37, + 0xf3, 0x7f, 0xb9, 0xef, 0x0d, 0xe0, 0x00, 0x37, 0x0f, 0xf7, 0x07, 0x1e, 0x43, + 0xb6, 0x15, 0x0e, 0xce, 0xf8, 0x24, 0x50, 0x00, 0x13, 0x99, 0xe1, 0x10, 0x17, + 0x44, 0xd7, 0x23, 0xe2, 0x65, 0xbe, 0xed, 0x0e, 0x30, 0x08, 0x59, 0xa0, 0x48, + 0xf4, 0x06, 0xf4, 0x9e, 0xb8, 0xfb, 0x09, 0xfb, 0x18, 0x2f, 0x1a, 0x24, 0xdc, + 0xa5, 0xd1, 0xda, 0xc6, 0xb2, 0xea, 0xd4, 0xc8, 0x2e, 0x3c, 0xd5, 0xf8, 0x1d, + 0xa2, 0xdb, 0x29, 0xf3, 0xb9, 0x95, 0x04, 0x09, 0xa0, 0x38, 0x14, 0xba, 0xfb, + 0xfc, 0x2a, 0xa7, 0xb9, 0xd0, 0x35, 0xfb, 0x47, 0xf4, 0xa3, 0xb4, 0x33, 0x9d, + 0xa5, 0x06, 0x55, 0xbc, 0xe3, 0x54, 0x43, 0x18, 0xff, 0xdd, 0xce, 0x3f, 0xca, + 0xa4, 0x3c, 0x1b, 0x3a, 0x09, 0xe9, 0xb6, 0xd9, 0x1b, 0xf9, 0x31, 0x99, 0x06, + 0x23, 0x59, 0x61, 0xef, 0xeb, 0x33, 0xb6, 0x8b, 0xd7, 0x96, 0x4e, 0xfe, 0x23, + 0x81, 0x09, 0xf5, 0x61, 0xb0, 0x2d, 0x21, 0x56, 0x54, 0xfe, 0xf9, 0x22, 0x32, + 0x63, 0xfa, 0xd4, 0x59, 0x53, 0x72, 0x26, 0xf9, 0xfa, 0x0a, 0xda, 0x08, 0xfa, + 0x4d, 0x52, 0x2e, 0xac, 0x10, 0xc9, 0x0a, 0x27, 0x14, 0xff, 0xcf, 0xf8, 0x10, + 0x18, 0x24, 0xa9, 0x1d, 0xe8, 0xf1, 0x22, 0x18, 0xde, 0xd3, 0xd7, 0x1b, 0xdd, + 0xf5, 0x22, 0xae, 0x17, 0xea, 0xf3, 0x00, 0xf5, 0xd4, 0x2a, 0xe3, 0xf7, 0x1c, + 0xf2, 0x29, 0x1f, 0x96, 0xc9, 0x08, 0x19, 0x1d, 0x40, 0xe4, 0x90, 0x0b, 0xff, + 0x5c, 0xe7, 0x81, 0x08, 0xf1, 0x09, 0xe4, 0xf3, 0x26, 0xe0, 0x1d, 0xee, 0xfa, + 0x41, 0x1e, 0x32, 0xcd, 0xec, 0x27, 0x2f, 0xe1, 0x6d, 0x0f, 0xac, 0xcf, 0x24, + 0xd4, 0x09, 0xde, 0xeb, 0x05, 0x22, 0x35, 0xb9, 0x36, 0xd9, 0x02, 0x02, 0x99, + 0x06, 0x0e, 0x41, 0xd1, 0xc6, 0xb8, 0xb5, 0x48, 0xed, 0x49, 0x3b, 0xea, 0xaa, + 0xff, 0x32, 0x20, 0xdc, 0xf9, 0xee, 0x4b, 0xe8, 0xcd, 0x07, 0xfd, 0xa3, 0xf7, + 0x7b, 0xea, 0x13, 0xe4, 0x0c, 0x0c, 0x58, 0x45, 0xf5, 0xf3, 0x39, 0x2b, 0xff, + 0xab, 0xdc, 0x16, 0x2f, 0xf2, 0x26, 0x49, 0xf7, 0x37, 0x00, 0xcc, 0xc6, 0xd3, + 0x09, 0xe9, 0x05, 0xea, 0x12, 0x49, 0x11, 0xe9, 0x17, 0x01, 0xdd, 0x13, 0xf3, + 0x0a, 0x84, 0xdf, 0x0a, 0x23, 0xc9, 0x22, 0xef, 0xd8, 0x12, 0xd5, 0x28, 0x07, + 0x01, 0xb6, 0xd9, 0xcf, 0x0a, 0xc6, 0xef, 0xe3, 0x11, 0xcb, 0xf6, 0x1c, 0x06, + 0xe7, 0xfd, 0xe9, 0x08, 0xfc, 0x58, 0xb7, 0x25, 0x0c, 0x6c, 0xc0, 0x25, 0xb6, + 0xef, 0x1c, 0x04, 0x5c, 0x1f, 0xef, 0xf4, 0xd1, 0xe1, 0x0e, 0xf9, 0xd1, 0xe1, + 0x2c, 0xff, 0x45, 0xe5, 0xf1, 0x4b, 0x01, 0xcb, 0x1e, 0xfd, 0xf0, 0x21, 0xcd, + 0x25, 0x26, 0x12, 0xe0, 0xfb, 0x20, 0xd5, 0xf1, 0xf7, 0x19, 0x0e, 0x18, 0x3b, + 0xde, 0xca, 0xaf, 0x41, 0x20, 0xbf, 0x93, 0x81, 0x09, 0xf9, 0xba, 0xe6, 0xff, + 0xf1, 0xb8, 0x09, 0x4b, 0xf3, 0xe7, 0xdd, 0xe6, 0x07, 0xfd, 0xf4, 0xf1, 0x60, + 0x63, 0xf6, 0x0c, 0xd1, 0x12, 0xf9, 0xf6, 0x01, 0xdf, 0xf0, 0x81, 0xd9, 0xfb, + 0xdd, 0x01, 0xbf, 0x47, 0x25, 0xdd, 0xd8, 0x84, 0x00, 0x1d, 0x26, 0x0f, 0xf4, + 0x3a, 0x26, 0xeb, 0x18, 0x02, 0xf6, 0xfd, 0xf3, 0x01, 0xf8, 0x24, 0xb8, 0xbf, + 0xf1, 0xdc, 0x23, 0xfb, 0x0b, 0xbb, 0x09, 0x48, 0x3b, 0xfc, 0x0d, 0x1b, 0x06, + 0x4d, 0xfe, 0xa7, 0xf6, 0x23, 0xf8, 0xb9, 0x4b, 0x02, 0x75, 0xf5, 0xf5, 0x16, + 0x06, 0x14, 0xcc, 0xf4, 0xfa, 0x7d, 0x03, 0xc3, 0x0e, 0x01, 0x13, 0x1a, 0xcd, + 0xed, 0x20, 0xef, 0x25, 0xa7, 0xf4, 0xea, 0x11, 0x55, 0xe6, 0x14, 0xe1, 0x09, + 0xe1, 0xdd, 0xfb, 0xc5, 0x62, 0x2a, 0xfb, 0xfa, 0xea, 0xfb, 0x24, 0xac, 0xec, + 0xd8, 0xe0, 0xf2, 0xea, 0xda, 0xda, 0xe2, 0x73, 0xc8, 0x0f, 0x96, 0xdb, 0xe4, + 0xc7, 0xd0, 0xf6, 0x47, 0xd4, 0x08, 0xbe, 0x5b, 0xe7, 0xfc, 0x2e, 0x43, 0x24, + 0xbb, 0x2d, 0xff, 0xe7, 0x3a, 0xf9, 0x06, 0xf7, 0xeb, 0xf4, 0xf3, 0xc3, 0xd2, + 0xe3, 0x0c, 0xd3, 0xe2, 0xee, 0x0a, 0x04, 0xef, 0xf6, 0x30, 0x26, 0x0f, 0xec, + 0xbb, 0xc8, 0x0a, 0xd0, 0x14, 0xe1, 0xf1, 0x27, 0x00, 0xe9, 0xe8, 0xdd, 0x01, + 0x20, 0xd8, 0x47, 0x16, 0xf0, 0xe6, 0x0a, 0xd6, 0x1b, 0x34, 0xe7, 0x26, 0x14, + 0xf6, 0xfe, 0x2d, 0xdc, 0xec, 0xdf, 0xed, 0xea, 0xea, 0x10, 0x30, 0x0a, 0xdb, + 0xe6, 0x35, 0x24, 0xf7, 0xf9, 0x44, 0xfd, 0x1b, 0xac, 0xc1, 0x2e, 0xc7, 0x15, + 0xd4, 0xd4, 0xd4, 0x1a, 0xeb, 0xe7, 0x21, 0x2f, 0xe6, 0x0c, 0xe8, 0x38, 0x3e, + 0xd9, 0x05, 0x38, 0xac, 0xf2, 0xe0, 0xeb, 0xd7, 0x0b, 0xf9, 0xfb, 0xf7, 0x08, + 0x02, 0x24, 0x10, 0x7f, 0xe9, 0xe1, 0x1c, 0x2b, 0x0f, 0x10, 0x05, 0xec, 0x4e, + 0xc7, 0xf6, 0xd4, 0xf6, 0x1e, 0xd8, 0x0a, 0xdc, 0x1b, 0xbb, 0xc6, 0xde, 0x1a, + 0xfe, 0x30, 0xae, 0x1b, 0x29, 0x53, 0x06, 0xed, 0xd9, 0x08, 0xf4, 0xd2, 0x1c, + 0x19, 0x14, 0x14, 0xc1, 0x20, 0x11, 0x14, 0x31, 0x00, 0x0c, 0x26, 0xe7, 0x1c, + 0xbf, 0x1a, 0xe5, 0xcf, 0xb5, 0xe9, 0x00, 0xec, 0x1d, 0xc0, 0x7f, 0x33, 0xd1, + 0xfb, 0x1b, 0x30, 0x02, 0xf5, 0x25, 0x00, 0xe9, 0xcd, 0x4a, 0x21, 0x16, 0xc2, + 0x49, 0xe2, 0xfc, 0xc4, 0x39, 0xbc, 0x11, 0xce, 0x4e, 0xf2, 0xff, 0xfe, 0x01, + 0xe9, 0x23, 0x30, 0xfa, 0x27, 0xd8, 0x24, 0xeb, 0x52, 0xd5, 0xec, 0xce, 0x09, + 0xcf, 0xe6, 0xe9, 0x12, 0xe8, 0xe0, 0x06, 0x0a, 0x46, 0xfe, 0x09, 0x29, 0xcf, + 0xc1, 0x10, 0x42, 0x27, 0xec, 0xf8, 0x30, 0x00, 0x21, 0x2b, 0x02, 0xc4, 0x21, + 0xbe, 0x2a, 0xfc, 0xe6, 0xf9, 0xf3, 0xdd, 0xf7, 0x05, 0xd6, 0xc8, 0xd8, 0x23, + 0x1b, 0xeb, 0x20, 0x11, 0x2f, 0x11, 0xe2, 0xf6, 0xe7, 0xb6, 0x26, 0xec, 0xfb, + 0x02, 0xef, 0x01, 0xec, 0x08, 0xed, 0xe3, 0xc8, 0x2c, 0x13, 0x37, 0x14, 0x3e, + 0xd3, 0xe0, 0x0b, 0xdc, 0x14, 0xee, 0xcf, 0x2b, 0xe4, 0xf2, 0xf3, 0xbc, 0xdd, + 0xfa, 0xfa, 0xd2, 0xf0, 0x26, 0xb7, 0x31, 0xd0, 0x07, 0x0e, 0x03, 0x4a, 0x43, + 0x0a, 0x1a, 0xf1, 0x25, 0xf4, 0x4b, 0x06, 0xef, 0x37, 0xf0, 0x13, 0x1c, 0xe2, + 0xe1, 0xd7, 0x1d, 0xe1, 0xe6, 0xf6, 0x44, 0xe9, 0xd1, 0x05, 0xf2, 0x36, 0x2e, + 0xfd, 0x34, 0x0a, 0xc2, 0x43, 0xd2, 0x15, 0xfc, 0x20, 0x0a, 0xd5, 0xe7, 0xcb, + 0xf6, 0x0f, 0xe5, 0xf8, 0xfd, 0x06, 0x0a, 0xdf, 0xe5, 0x14, 0x1b, 0x24, 0xb8, + 0x00, 0xc9, 0x16, 0x0b, 0x0b, 0xdd, 0x03, 0x34, 0xfa, 0x10, 0x2b, 0x08, 0x2a, + 0x5e, 0xdd, 0x7f, 0xf4, 0xe6, 0xcf, 0xd6, 0xfb, 0x06, 0xe3, 0xcb, 0x06, 0xf3, + 0x2b, 0x15, 0xee, 0xa3, 0xc6, 0xee, 0x06, 0xf2, 0x2f, 0xef, 0x20, 0xee, 0x0d, + 0x0f, 0x05, 0xf5, 0xf6, 0xe0, 0xcf, 0xde, 0xfc, 0x17, 0xea, 0xec, 0xd0, 0x17, + 0xf2, 0x1e, 0x02, 0x1c, 0xe8, 0x0a, 0x47, 0xd8, 0xdf, 0xed, 0xfb, 0xf1, 0xf4, + 0x0b, 0x3b, 0x08, 0xf0, 0x13, 0xf3, 0xe3, 0xcd, 0x3f, 0xc4, 0x15, 0x00, 0x7a, + 0x35, 0x05, 0x0a, 0xda, 0x09, 0xf3, 0x06, 0xfb, 0x1d, 0x23, 0xf8, 0xe1, 0xda, + 0xe6, 0xfd, 0x4b, 0x26, 0x20, 0x50, 0xe5, 0xf1, 0x30, 0xbf, 0xfd, 0xf3, 0x25, + 0xf3, 0xc1, 0x0a, 0x23, 0xb9, 0x51, 0x11, 0xde, 0xbf, 0x1f, 0x0c, 0x08, 0xf7, + 0x00, 0x1a, 0xe2, 0x0b, 0xe5, 0xed, 0xea, 0x10, 0xda, 0x0e, 0x16, 0xfa, 0xf7, + 0xf3, 0xfc, 0xa2, 0xde, 0xe8, 0x29, 0x44, 0xa0, 0x16, 0xcf, 0x81, 0x34, 0xf7, + 0xea, 0xf6, 0xe9, 0x3f, 0x30, 0x17, 0x1a, 0xe9, 0x06, 0xfc, 0xd4, 0xd6, 0xf8, + 0x30, 0x0c, 0x4c, 0xe9, 0x07, 0x02, 0xf8, 0xe4, 0xf5, 0xdd, 0xea, 0xfa, 0x1a, + 0xad, 0xbb, 0x41, 0x60, 0x0f, 0x31, 0x18, 0x43, 0xdd, 0x1f, 0x04, 0x0a, 0x1f, + 0x06, 0xb0, 0xd2, 0xbd, 0x38, 0x15, 0x1e, 0xfe, 0xf4, 0xc1, 0x27, 0xeb, 0xe8, + 0x05, 0x18, 0xea, 0x39, 0xf1, 0xdd, 0x44, 0xc6, 0xda, 0x12, 0xef, 0xe9, 0x36, + 0x0e, 0x1b, 0x23, 0x17, 0x07, 0xf9, 0xfd, 0x81, 0x28, 0x2e, 0x26, 0xf3, 0xae, + 0xf5, 0x19, 0x35, 0x2c, 0x1b, 0x05, 0xda, 0xd2, 0x0a, 0xe0, 0x0b, 0xb3, 0xf5, + 0xd6, 0xcd, 0xf1, 0x0f, 0xf9, 0xf8, 0xed, 0xb9, 0x22, 0x23, 0xbf, 0x19, 0x07, + 0xec, 0xd9, 0x06, 0xce, 0xbd, 0xfd, 0xdf, 0xfb, 0xdc, 0x03, 0xb6, 0xdd, 0xd3, + 0xb3, 0x01, 0xe4, 0x0f, 0x3c, 0xa9, 0xd8, 0xc8, 0x8f, 0x0c, 0x39, 0xce, 0x22, + 0x00, 0x1e, 0xb2, 0xf3, 0xec, 0x1f, 0xfb, 0x0b, 0xf8, 0x26, 0xfc, 0x47, 0x34, + 0x33, 0x08, 0x16, 0xe5, 0x0a, 0x05, 0xd4, 0xe5, 0xdd, 0xe9, 0x0d, 0xc7, 0xdf, + 0x11, 0xf9, 0x05, 0x21, 0x01, 0x27, 0xf3, 0xdb, 0xfa, 0xd4, 0x07, 0xc8, 0xd9, + 0xf8, 0x05, 0xd6, 0xdb, 0xf0, 0xbd, 0x21, 0xec, 0xfd, 0x04, 0x39, 0x4d, 0xc9, + 0x29, 0x7f, 0xea, 0xf1, 0xfb, 0xd0, 0xdb, 0x25, 0xda, 0x19, 0xd2, 0x0c, 0xec, + 0xa8, 0xe2, 0xf5, 0x13, 0xcc, 0x05, 0x0a, 0xa0, 0xee, 0xe4, 0x0a, 0x1e, 0x06, + 0x0c, 0xf1, 0xd0, 0xef, 0x02, 0xde, 0x30, 0x06, 0x03, 0x10, 0xda, 0x31, 0x74, + 0x21, 0xd1, 0xff, 0xe9, 0xf6, 0xd8, 0xf9, 0x25, 0x56, 0xf3, 0xe7, 0x06, 0x25, + 0x06, 0xf3, 0xf7, 0x03, 0xd6, 0x08, 0xeb, 0xf7, 0xea, 0xf0, 0x1d, 0x64, 0x0b, + 0xcf, 0xf5, 0x30, 0x48, 0xce, 0x2e, 0xc1, 0xe5, 0xd9, 0xf2, 0xdc, 0x3c, 0x0d, + 0xf3, 0x07, 0xfa, 0xf3, 0xc5, 0xc0, 0xd9, 0x11, 0xd3, 0x02, 0xe6, 0x32, 0xba, + 0x43, 0x31, 0x07, 0xfd, 0xc1, 0xed, 0xfe, 0xef, 0x43, 0xd7, 0x06, 0x52, 0xf8, + 0x2c, 0xf1, 0x51, 0x1a, 0xd8, 0x23, 0x03, 0x1e, 0x23, 0x21, 0xb8, 0xf7, 0x1e, + 0xf7, 0xff, 0x04, 0x28, 0xfc, 0xff, 0x14, 0x6c, 0x13, 0x1c, 0xbb, 0xca, 0x13, + 0x47, 0x19, 0x29, 0xff, 0xde, 0x1d, 0xfe, 0xee, 0xb6, 0x18, 0xc3, 0xf1, 0x1a, + 0xd5, 0x11, 0xc7, 0xd7, 0x2c, 0xc5, 0x27, 0x24, 0x07, 0x19, 0x02, 0xb3, 0xe0, + 0xfc, 0x0a, 0x3d, 0xc0, 0x13, 0x04, 0x37, 0xca, 0x1f, 0x02, 0x32, 0xd3, 0xdf, + 0x0b, 0xf7, 0x1c, 0xd1, 0x39, 0x14, 0xe4, 0xec, 0xf2, 0xef, 0x02, 0x12, 0x1a, + 0xf1, 0xce, 0x15, 0xe5, 0xef, 0xdd, 0x1b, 0x15, 0x26, 0x48, 0x1b, 0xd1, 0x28, + 0x1e, 0x4a, 0x38, 0xc6, 0x81, 0xb2, 0x42, 0x1c, 0xa6, 0x16, 0xd5, 0xee, 0xc5, + 0x00, 0xd8, 0x09, 0xda, 0x18, 0xde, 0xdb, 0xfa, 0xec, 0x34, 0xd2, 0x15, 0x34, + 0x0d, 0x61, 0x1b, 0xc2, 0xe0, 0xe2, 0xef, 0xec, 0xf4, 0x13, 0xe7, 0x13, 0xde, + 0xf3, 0x4d, 0xe5, 0xdf, 0x22, 0xde, 0x13, 0x40, 0x06, 0x1d, 0xe2, 0xf6, 0xad, + 0x6f, 0xaf, 0x23, 0x3f, 0xda, 0xf1, 0xfd, 0xf8, 0xae, 0xdd, 0xf9, 0xc1, 0x0a, + 0xfa, 0x42, 0x81, 0x23, 0xf9, 0xf8, 0x54, 0xcb, 0xbb, 0x21, 0xfa, 0xbd, 0xe8, + 0xca, 0x38, 0x51, 0xe0, 0xdd, 0x10, 0x69, 0xf0, 0x2b, 0x0d, 0x23, 0xf3, 0x0e, + 0xd3, 0xa8, 0xe9, 0x22, 0xf4, 0xec, 0x3b, 0x6b, 0x0e, 0xce, 0xfb, 0x50, 0xe1, + 0x1d, 0x60, 0x2d, 0x2f, 0x0d, 0x16, 0xe2, 0x67, 0xa3, 0x09, 0x2b, 0xed, 0x06, + 0x02, 0x7c, 0x29, 0xc7, 0xc6, 0x1a, 0xe6, 0x4e, 0xc6, 0x3a, 0xdc, 0xb9, 0x2e, + 0xaf, 0x31, 0x51, 0x94, 0x39, 0x12, 0xd6, 0x2a, 0x0d, 0xd9, 0xd8, 0x35, 0x3e, + 0x15, 0x26, 0x17, 0xd8, 0x33, 0x0e, 0x93, 0x76, 0x01, 0x01, 0xdf, 0x11, 0x07, + 0xda, 0xa0, 0xa9, 0x46, 0x36, 0x3f, 0xe2, 0xa4, 0xd2, 0x0a, 0xf9, 0xae, 0x0f, + 0xad, 0x09, 0x20, 0xec, 0x9c, 0x6a, 0x6e, 0xee, 0xba, 0x08, 0x47, 0xd2, 0x03, + 0xf2, 0xc0, 0x4f, 0x34, 0xfb, 0xa3, 0x62, 0x5a, 0xdf, 0xfd, 0x1e, 0xfe, 0xf5, + 0x6f, 0xe6, 0x12, 0x08, 0x30, 0x20, 0xbd, 0xcd, 0x0f, 0xe6, 0xde, 0x01, 0xad, + 0x1d, 0x62, 0xef, 0x20, 0x4c, 0x61, 0x10, 0xba, 0x2b, 0x19, 0x08, 0xcf, 0x50, + 0xf7, 0xdc, 0xc6, 0x4e, 0xe5, 0xee, 0x2b, 0xd7, 0x03, 0x1a, 0xf6, 0xe8, 0xe5, + 0xbd, 0x33, 0x1c, 0xe4, 0xf1, 0x95, 0xcd, 0xce, 0x58, 0x1b, 0x00, 0x42, 0x7f, + 0x84, 0x6e, 0xce, 0x0f, 0xbd, 0x20, 0xe9, 0x18, 0x1b, 0x1e, 0xfd, 0x14, 0x32, + 0x2b, 0xfd, 0xd3, 0x25, 0xe2, 0x13, 0xfb, 0x02, 0x57, 0xfd, 0x58, 0x20, 0xfc, + 0xf1, 0x9d, 0xfc, 0x02, 0xf5, 0xf4, 0xfc, 0xba, 0xcd, 0x77, 0xfe, 0x04, 0x7a, + 0xa9, 0x01, 0x19, 0xc0, 0xef, 0xeb, 0xd4, 0xe3, 0x19, 0x22, 0x54, 0xe5, 0xd7, + 0x06, 0xfe, 0xb5, 0xe7, 0xdc, 0xa0, 0x15, 0xc1, 0xfc, 0x23, 0xf5, 0xd9, 0x29, + 0x23, 0x47, 0xfe, 0x3c, 0x8c, 0xe8, 0xd6, 0xb7, 0xff, 0x04, 0xdb, 0xf9, 0xe3, + 0xe7, 0x20, 0x90, 0x10, 0xed, 0x11, 0xde, 0xff, 0xfc, 0xf6, 0xf1, 0x0c, 0xa8, + 0x6b, 0xc3, 0x12, 0x0f, 0x26, 0x1e, 0x07, 0x5b, 0x3f, 0xc4, 0xee, 0xf0, 0x40, + 0xdb, 0x7f, 0xba, 0x23, 0x5d, 0xac, 0xcf, 0x15, 0x42, 0x32, 0x0f, 0x51, 0x32, + 0x06, 0xc3, 0x23, 0xe3, 0xfa, 0x24, 0x2d, 0xf8, 0x35, 0xdf, 0x4c, 0x34, 0xb1, + 0x88, 0x08, 0x16, 0x2a, 0x3d, 0x15, 0x95, 0x3c, 0x4e, 0xe4, 0xdc, 0xb4, 0x1b, + 0xdb, 0xc0, 0x14, 0x5e, 0xd5, 0xe5, 0xc8, 0xb7, 0x0f, 0xe4, 0xdd, 0x40, 0x22, + 0xde, 0xfb, 0x1d, 0x38, 0xe5, 0xf7, 0xd4, 0xeb, 0xfe, 0x0d, 0xed, 0x63, 0x30, + 0x43, 0x5d, 0xd5, 0xf9, 0xe3, 0x09, 0xf5, 0xee, 0x13, 0x07, 0xd0, 0x03, 0xf3, + 0xe1, 0x48, 0x1f, 0x41, 0x29, 0xdf, 0x02, 0x1b, 0x1f, 0x0d, 0x10, 0xf1, 0xc2, + 0x00, 0x2a, 0x9b, 0x08, 0xcd, 0x30, 0x01, 0xd9, 0x06, 0x1b, 0x07, 0xee, 0xf3, + 0x06, 0x2d, 0x4a, 0xf4, 0xfd, 0x1b, 0x2f, 0xc9, 0x1b, 0xda, 0xc8, 0x19, 0x1b, + 0xcd, 0x19, 0xf9, 0x00, 0x13, 0xf5, 0xe7, 0x09, 0x22, 0x7f, 0x0d, 0xed, 0x11, + 0x71, 0x01, 0x1e, 0x02, 0x09, 0x08, 0x27, 0xe0, 0x4b, 0xec, 0xe8, 0x0a, 0x2c, + 0xe4, 0x2c, 0x00, 0xff, 0xf6, 0x20, 0x14, 0xe7, 0xcb, 0xc5, 0xf8, 0xf1, 0x04, + 0x26, 0x17, 0x18, 0xff, 0x10, 0xd1, 0x0d, 0x2b, 0xe8, 0x06, 0x19, 0xcf, 0xf3, + 0xe0, 0xc5, 0xcd, 0x31, 0x27, 0xe3, 0x52, 0x0c, 0x0f, 0xcf, 0x0a, 0x18, 0x20, + 0xe7, 0xf1, 0xa9, 0xdb, 0x13, 0xf4, 0x02, 0x16, 0xf2, 0xfb, 0x36, 0xea, 0xf9, + 0x2c, 0x1f, 0x13, 0x3e, 0x2a, 0x5f, 0xb2, 0x3e, 0xd9, 0xee, 0xdf, 0x1d, 0x32, + 0x2d, 0xf4, 0x30, 0x1b, 0xfc, 0xf1, 0xee, 0xca, 0xf9, 0x20, 0xb4, 0xfc, 0x18, + 0x3f, 0x4b, 0xb2, 0xa4, 0x17, 0xeb, 0x39, 0xc9, 0xe1, 0xef, 0x1a, 0x4e, 0xea, + 0x50, 0xf5, 0x00, 0x1f, 0x05, 0x20, 0x70, 0x08, 0x28, 0x08, 0xd1, 0xc0, 0xf1, + 0xfe, 0xc6, 0xbc, 0xdf, 0x1c, 0xca, 0x75, 0x42, 0x1f, 0x5a, 0xda, 0x44, 0x38, + 0x0f, 0xde, 0x81, 0x10, 0xea, 0x39, 0xec, 0xf5, 0x1b, 0xfc, 0x12, 0x2a, 0xdf, + 0xa4, 0xee, 0xf0, 0xed, 0xaa, 0xf3, 0xaf, 0xfc, 0x03, 0x7d, 0x17, 0xe2, 0x01, + 0xf2, 0x07, 0xcd, 0x14, 0x02, 0xc5, 0xf7, 0xaa, 0x21, 0xe9, 0x7e, 0xe0, 0xdd, + 0xf6, 0xec, 0xfa, 0x0a, 0x52, 0x15, 0x0a, 0xef, 0x3a, 0x33, 0xe1, 0xfa, 0x4f, + 0x28, 0x7b, 0xc6, 0x9f, 0xe6, 0x42, 0x18, 0x68, 0xdf, 0x0f, 0x5d, 0xef, 0xda, + 0x3d, 0x0f, 0xad, 0xb0, 0x40, 0xee, 0xbc, 0xcd, 0xdf, 0x09, 0x01, 0xdf, 0x54, + 0xe7, 0x18, 0x00, 0xd6, 0x26, 0xf7, 0x41, 0xc3, 0xa7, 0x0f, 0x0b, 0xc4, 0x02, + 0x13, 0x14, 0x2a, 0xc6, 0x5c, 0xf6, 0x33, 0xb5, 0x09, 0x22, 0x66, 0xbe, 0xdd, + 0x3e, 0xe8, 0x7a, 0xfc, 0xec, 0xbd, 0xb5, 0x23, 0x35, 0xd7, 0x20, 0x98, 0x2b, + 0x03, 0xe9, 0xef, 0x0e, 0x13, 0x0c, 0xcf, 0xb3, 0x26, 0x53, 0x0f, 0xca, 0x00, + 0x2c, 0xf6, 0x9b, 0x30, 0xf7, 0xfd, 0xa8, 0x4e, 0xb6, 0xe1, 0x49, 0x1b, 0x21, + 0x02, 0x29, 0xff, 0xe9, 0xc4, 0xc5, 0x20, 0x73, 0x3a, 0xd1, 0x56, 0x00, 0xc4, + 0x30, 0xcd, 0xc6, 0x18, 0xe8, 0x64, 0x6f, 0xd5, 0x22, 0xec, 0x17, 0x81, 0xff, + 0x06, 0xad, 0xa8, 0xe0, 0x04, 0xe1, 0xfd, 0xfc, 0x23, 0x46, 0x20, 0xb9, 0xe6, + 0xf5, 0x3b, 0x0d, 0x15, 0x2f, 0xfd, 0x0a, 0x43, 0xe4, 0x26, 0x12, 0x30, 0x07, + 0x36, 0x2d, 0x0e, 0xca, 0xf4, 0x22, 0xf7, 0x01, 0x2a, 0xf1, 0x25, 0xdf, 0x72, + 0x27, 0x27, 0x2d, 0x38, 0x41, 0xb9, 0xcb, 0xb3, 0xff, 0x1d, 0x09, 0x20, 0x23, + 0xdf, 0x29, 0xfe, 0x16, 0x20, 0xb1, 0x31, 0xfe, 0xf2, 0xe6, 0xf8, 0x1f, 0xf4, + 0xe8, 0xe1, 0xa7, 0xe4, 0x30, 0x12, 0xe1, 0xdf, 0xf5, 0x49, 0xf7, 0xe8, 0xf7, + 0x09, 0xc3, 0xf4, 0x5b, 0xf2, 0xb3, 0x90, 0xb9, 0xfe, 0x25, 0xe6, 0xff, 0xde, + 0x91, 0xcf, 0xe2, 0xfa, 0x7f, 0xeb, 0x15, 0xcf, 0x1d, 0xc7, 0x08, 0x24, 0xf2, + 0xd9, 0xe8, 0x19, 0xf2, 0xf5, 0x07, 0x18, 0xfc, 0x17, 0xfb, 0xfc, 0x1c, 0x1a, + 0x7b, 0xf0, 0x1d, 0x06, 0x10, 0x42, 0x3b, 0xdb, 0x09, 0xf2, 0xbc, 0x8c, 0x38, + 0xfa, 0xd4, 0x5c, 0x2e, 0xfc, 0x23, 0x13, 0x22, 0xfe, 0x24, 0xeb, 0x5a, 0xe1, + 0xe9, 0x0e, 0x81, 0xee, 0x63, 0xf3, 0xf7, 0xfe, 0xd6, 0x29, 0xec, 0x15, 0xe4, + 0x0e, 0xe7, 0xe1, 0xd0, 0xe2, 0xf1, 0xc8, 0x22, 0x29, 0xf3, 0x25, 0x39, 0x3a, + 0xfe, 0x1c, 0xdf, 0x05, 0x31, 0x12, 0x13, 0xc7, 0xea, 0xd5, 0x1e, 0xc8, 0xf2, + 0x14, 0xef, 0xd0, 0x26, 0x59, 0xb4, 0x1d, 0xf2, 0xeb, 0x07, 0xfe, 0x20, 0xf3, + 0xb6, 0x21, 0xac, 0xd0, 0xda, 0xe8, 0xfa, 0x3f, 0x10, 0xf7, 0x04, 0x1b, 0x40, + 0x11, 0x33, 0xeb, 0xfe, 0x25, 0xda, 0xbd, 0xe9, 0x22, 0xe0, 0x39, 0xf0, 0xb0, + 0xf1, 0x68, 0x15, 0x0b, 0xe2, 0x09, 0xc0, 0xac, 0x06, 0xdf, 0x13, 0xc9, 0xcb, + 0x36, 0xe1, 0x22, 0xde, 0x0d, 0x25, 0x1d, 0xf7, 0x07, 0xcf, 0x39, 0x47, 0x1f, + 0x7b, 0x2f, 0xf9, 0x4a, 0xea, 0x1b, 0x14, 0x11, 0xef, 0x10, 0x27, 0x07, 0x0a, + 0xec, 0x33, 0x07, 0x1a, 0xed, 0x32, 0xff, 0x28, 0xe0, 0xe1, 0xfe, 0xe8, 0x11, + 0xdf, 0x28, 0xba, 0x10, 0x20, 0xb6, 0xfb, 0x0a, 0xf3, 0x00, 0xe2, 0x0d, 0xfb, + 0xf0, 0xda, 0xe8, 0x15, 0xe1, 0x2d, 0xdb, 0x27, 0xfe, 0xe2, 0xfb, 0xfb, 0xcd, + 0x0a, 0x0d, 0xe2, 0x1a, 0xfd, 0xf0, 0x42, 0x29, 0x03, 0xe9, 0x0d, 0xf7, 0xf3, + 0xed, 0xf0, 0xeb, 0x16, 0xf0, 0xde, 0x18, 0x0b, 0x15, 0xed, 0x54, 0xbc, 0x07, + 0xe1, 0xff, 0xf9, 0x14, 0xf9, 0xe1, 0xf3, 0xfe, 0xdd, 0x00, 0xe8, 0xe4, 0xe0, + 0xe6, 0x0a, 0xcc, 0x01, 0xd0, 0xe6, 0xd7, 0x0b, 0xe4, 0x02, 0x40, 0x2d, 0xcb, + 0xe4, 0x15, 0xd8, 0xfb, 0xf9, 0xf2, 0x10, 0xd4, 0xef, 0x18, 0xcd, 0xcd, 0xda, + 0x7f, 0xfe, 0x05, 0x2b, 0xea, 0xf7, 0xe6, 0x0e, 0x2d, 0xed, 0x01, 0xd4, 0xfa, + 0xe5, 0x02, 0x07, 0x29, 0x03, 0xf7, 0x1b, 0x1a, 0x06, 0xdf, 0x27, 0xef, 0xec, + 0xdf, 0x26, 0x03, 0xf5, 0xee, 0xfc, 0xda, 0xd2, 0xf9, 0x0a, 0x4a, 0xf7, 0xcc, + 0x63, 0x39, 0x36, 0xcb, 0x2c, 0x05, 0xdd, 0x36, 0xe4, 0xbd, 0xdc, 0xb2, 0x0a, + 0xc5, 0xb9, 0x17, 0x7f, 0x02, 0xd4, 0xf7, 0x07, 0x19, 0x3d, 0x0e, 0xc6, 0xc8, + 0xcd, 0xc9, 0x06, 0xe3, 0xb2, 0xac, 0xd3, 0x25, 0xdb, 0xfb, 0x21, 0x33, 0xe9, + 0x30, 0x8c, 0x21, 0xc4, 0xbc, 0xa1, 0x24, 0xaa, 0xc3, 0x06, 0xec, 0xe3, 0x36, + 0x32, 0xa2, 0x62, 0xf9, 0xa2, 0x17, 0x25, 0x0e, 0xee, 0x06, 0x32, 0xdb, 0xfd, + 0x00, 0x77, 0xf4, 0xc2, 0x1c, 0x47, 0xee, 0x06, 0xb0, 0x4a, 0xaf, 0xe8, 0x03, + 0xc2, 0x1f, 0xc9, 0xe7, 0xd9, 0xea, 0xf7, 0x00, 0xe5, 0xc7, 0x10, 0x39, 0x6c, + 0xd7, 0x19, 0xf8, 0x0d, 0x12, 0xd1, 0x0d, 0x2b, 0x01, 0xfe, 0x50, 0xc4, 0xb5, + 0xe8, 0x06, 0x0c, 0xe7, 0x38, 0x77, 0xe9, 0xec, 0x0e, 0x0c, 0xf0, 0xff, 0xef, + 0x02, 0x0b, 0x05, 0xa3, 0x27, 0xc5, 0x2a, 0x20, 0x14, 0xed, 0x26, 0xbf, 0x20, + 0x04, 0xd0, 0x19, 0x30, 0x06, 0x2e, 0x43, 0x1a, 0xe5, 0xef, 0xd5, 0xf2, 0xe7, + 0xf4, 0xc4, 0x24, 0xee, 0x4b, 0xf1, 0x2d, 0x00, 0xe4, 0xe9, 0x16, 0x3c, 0x34, + 0x1a, 0x9d, 0xf4, 0xe1, 0xc8, 0xf9, 0x38, 0x0d, 0xff, 0x26, 0x10, 0x24, 0xf9, + 0x97, 0xa9, 0x3c, 0x34, 0xd8, 0xcd, 0xf8, 0x21, 0x0c, 0xc9, 0xe8, 0x07, 0xc2, + 0xfc, 0x3c, 0xb3, 0xe1, 0xdc, 0x13, 0xed, 0xa4, 0x59, 0xe6, 0x11, 0xfa, 0x22, + 0xd5, 0x0c, 0x1d, 0x27, 0x1e, 0x25, 0xb9, 0x03, 0xe8, 0xfe, 0x36, 0xf1, 0xd9, + 0x3f, 0x1d, 0xe5, 0x32, 0xca, 0xf7, 0x0d, 0x28, 0x37, 0xe3, 0xf2, 0xf3, 0xef, + 0xe9, 0xf8, 0xfa, 0x22, 0xd9, 0x5f, 0x06, 0x55, 0xf8, 0xd3, 0x05, 0x17, 0x37, + 0x72, 0xf6, 0xb3, 0x12, 0x2b, 0x06, 0xd3, 0xee, 0x17, 0x13, 0x3b, 0x29, 0x81, + 0x87, 0xe5, 0x40, 0x4c, 0x06, 0xd2, 0x3f, 0x7f, 0x0b, 0x4c, 0x48, 0x3e, 0xc6, + 0xf4, 0x36, 0xc2, 0xde, 0x28, 0x02, 0x2d, 0xef, 0x08, 0x06, 0x27, 0x48, 0x62, + 0x19, 0x3c, 0x0f, 0xe7, 0x10, 0x1f, 0xd4, 0xcb, 0x87, 0xff, 0xd0, 0xfb, 0xe4, + 0xfd, 0x13, 0x21, 0xff, 0xcb, 0x1f, 0xe4, 0x4e, 0x0d, 0x18, 0xf8, 0x6b, 0x30, + 0xeb, 0xfe, 0x35, 0x34, 0xd3, 0x33, 0xe3, 0xb8, 0x57, 0xd8, 0xee, 0xc0, 0xbd, + 0xa8, 0xea, 0xfd, 0xc5, 0x02, 0x1b, 0xda, 0x61, 0xf2, 0xe5, 0xf7, 0x15, 0x05, + 0x13, 0xda, 0xda, 0xc0, 0x06, 0xaf, 0x1c, 0xd7, 0xd0, 0x58, 0x45, 0x2e, 0xdd, + 0xfa, 0xd6, 0x5b, 0xec, 0xbd, 0x14, 0xc5, 0x26, 0xd7, 0x18, 0x0c, 0x19, 0xba, + 0xf1, 0x08, 0x13, 0x22, 0x1c, 0xda, 0x68, 0x44, 0x0d, 0x30, 0x2c, 0xf3, 0xdc, + 0x4a, 0x19, 0x1d, 0x2d, 0x1c, 0x21, 0x30, 0x00, 0xf3, 0x1f, 0x01, 0xed, 0xea, + 0xc2, 0x56, 0xe7, 0xe6, 0xce, 0xf1, 0xfc, 0x15, 0x19, 0x7f, 0x9a, 0x9c, 0xa4, + 0x47, 0xf6, 0x08, 0xe9, 0x8c, 0x11, 0xaa, 0x12, 0xcc, 0x22, 0xea, 0xb8, 0xe5, + 0xea, 0x16, 0x01, 0xdf, 0x9f, 0x96, 0xfd, 0x46, 0x22, 0x0e, 0xc1, 0x11, 0x04, + 0xa9, 0xf6, 0xc7, 0xf0, 0x04, 0x4e, 0xea, 0xdb, 0x8e, 0x39, 0x05, 0xdb, 0xe4, + 0xf4, 0x8d, 0xd7, 0x15, 0x27, 0xb0, 0x18, 0xf3, 0xe0, 0xd8, 0xf1, 0x3b, 0x1b, + 0x17, 0x5c, 0xd4, 0x31, 0x13, 0xc9, 0x08, 0x00, 0xbf, 0x2a, 0x5e, 0x4e, 0x03, + 0x1b, 0xe1, 0x32, 0x20, 0xfa, 0x38, 0x2e, 0x26, 0x4d, 0xe0, 0x0c, 0x28, 0x00, + 0x54, 0x99, 0xd7, 0x10, 0x2f, 0x27, 0xef, 0x0c, 0x14, 0xd4, 0xa5, 0x45, 0x18, + 0xf1, 0x10, 0xec, 0x43, 0x9f, 0xdc, 0xe7, 0xce, 0xbb, 0x13, 0x32, 0xdd, 0x29, + 0x91, 0x3f, 0xdc, 0x02, 0x02, 0xf8, 0xcf, 0x2b, 0x47, 0xa4, 0x48, 0xdb, 0x29, + 0x2b, 0xe8, 0xfd, 0x08, 0x0d, 0xf6, 0x4a, 0x02, 0xf4, 0x13, 0x28, 0x17, 0xd9, + 0x2f, 0x0b, 0x3a, 0xd5, 0x0e, 0xee, 0x00, 0x0a, 0x0e, 0x26, 0xf8, 0xf1, 0x1a, + 0x0a, 0x13, 0x53, 0x01, 0xda, 0xac, 0x50, 0xfb, 0xe0, 0xe0, 0x14, 0xf8, 0x02, + 0xdd, 0xe6, 0x10, 0x3f, 0xc6, 0xff, 0x33, 0x0f, 0x32, 0xf7, 0x2f, 0x09, 0x69, + 0xeb, 0xd9, 0xe3, 0x36, 0xec, 0xeb, 0x25, 0x11, 0xed, 0xdc, 0x3d, 0x0c, 0x02, + 0x41, 0xd1, 0xe4, 0xff, 0xc5, 0x1a, 0xf3, 0x08, 0x14, 0xd9, 0x7f, 0xee, 0x12, + 0xda, 0x2e, 0xd4, 0xfd, 0xe2, 0xcf, 0xe9, 0xc1, 0x34, 0xcc, 0xe1, 0x1d, 0x15, + 0x24, 0xcf, 0x22, 0x5b, 0xa4, 0x09, 0x11, 0xca, 0xd6, 0xdf, 0xea, 0x18, 0x0e, + 0x58, 0xce, 0x0b, 0x1c, 0x02, 0x08, 0xce, 0x26, 0xca, 0x27, 0x45, 0xce, 0x2b, + 0x13, 0xcf, 0xea, 0xdf, 0x5f, 0x54, 0xcf, 0xe5, 0x88, 0x0d, 0x13, 0xfb, 0xf6, + 0xcf, 0xe3, 0xf1, 0xfb, 0xd1, 0x03, 0x21, 0x41, 0xd5, 0x09, 0x0c, 0xd7, 0xda, + 0x0e, 0xcb, 0xf8, 0xe4, 0xe8, 0x02, 0xee, 0xbc, 0x2b, 0x08, 0x2c, 0xf8, 0xdc, + 0xdb, 0xcc, 0x2f, 0x14, 0x19, 0x3f, 0x14, 0x3f, 0xe1, 0xde, 0xfc, 0x0c, 0xc7, + 0xea, 0x30, 0x07, 0xfc, 0xe4, 0x18, 0xe9, 0xe8, 0xdb, 0xf4, 0xae, 0xeb, 0xf9, + 0x3b, 0xb2, 0xf2, 0xe4, 0xf9, 0x01, 0x28, 0xd9, 0x49, 0x03, 0xc5, 0xdb, 0xd5, + 0x1e, 0x1b, 0x10, 0xfe, 0xea, 0xef, 0x23, 0x40, 0x45, 0x13, 0xe3, 0x27, 0xeb, + 0x29, 0x1e, 0xfe, 0xf8, 0x4f, 0x1a, 0x2f, 0xea, 0x0b, 0x09, 0x1f, 0x10, 0xda, + 0xed, 0xe7, 0xfa, 0xee, 0x3e, 0xee, 0xcd, 0x10, 0xed, 0x51, 0xe6, 0x1b, 0x21, + 0xca, 0x1a, 0x7f, 0xed, 0x1b, 0xbd, 0xfc, 0x28, 0xf2, 0xe2, 0x2f, 0xec, 0xd1, + 0x2b, 0xf8, 0xdc, 0x6a, 0x16, 0x35, 0x44, 0x42, 0xf9, 0x24, 0xf3, 0xf1, 0xb8, + 0x39, 0xd9, 0xeb, 0xfe, 0x46, 0x0b, 0xd4, 0xf6, 0xf8, 0x3c, 0xf8, 0x27, 0x22, + 0x16, 0x1b, 0x10, 0x37, 0x28, 0xfa, 0x02, 0x05, 0xc5, 0xdd, 0x27, 0xdb, 0x46, + 0xe4, 0xb9, 0x0d, 0xfc, 0x0b, 0xc8, 0xf6, 0xeb, 0xf9, 0x0b, 0x16, 0xfc, 0xf7, + 0xd6, 0xd3, 0x00, 0xdc, 0x11, 0xe3, 0x35, 0xf9, 0xf1, 0xea, 0xde, 0x11, 0x15, + 0x5b, 0x29, 0xeb, 0xeb, 0xfe, 0x0e, 0xcf, 0xe1, 0xe6, 0xf7, 0xe7, 0xf7, 0xda, + 0x0a, 0xed, 0x16, 0x66, 0xcc, 0xd2, 0x24, 0xf8, 0x35, 0x10, 0xc9, 0xdb, 0xe3, + 0x26, 0x1d, 0xdc, 0xd7, 0x1c, 0x26, 0x58, 0x0d, 0x0f, 0x15, 0x41, 0x02, 0x09, + 0xc6, 0x15, 0x1e, 0xff, 0xf8, 0xe2, 0x19, 0xdd, 0xeb, 0x12, 0x81, 0x1b, 0xe6, + 0x41, 0xe2, 0x1f, 0xe5, 0xfc, 0xa1, 0xe8, 0xe5, 0x06, 0x1c, 0xd8, 0xf7, 0x23, + 0x30, 0xd3, 0xd1, 0x5c, 0xa7, 0xcb, 0x35, 0x01, 0x07, 0x67, 0xe0, 0x15, 0x1b, + 0x0f, 0xf9, 0x17, 0x4b, 0xe9, 0xfc, 0xf9, 0xad, 0xe6, 0x0d, 0x12, 0x07, 0x23, + 0xd3, 0x0d, 0xef, 0x0a, 0x42, 0xff, 0xe6, 0x17, 0xe4, 0x19, 0xd5, 0x24, 0x43, + 0xde, 0x4a, 0xc7, 0xca, 0xde, 0xeb, 0x28, 0xbe, 0x27, 0x10, 0xe3, 0x0e, 0x0c, + 0xc6, 0xaf, 0x34, 0xc5, 0xc5, 0xa9, 0xdd, 0xde, 0x10, 0xfc, 0xdd, 0x3a, 0x20, + 0x2e, 0x05, 0xbb, 0xe3, 0xfe, 0xca, 0x10, 0x09, 0x4e, 0x0b, 0x7f, 0xf5, 0xf3, + 0x08, 0x0b, 0x27, 0xc9, 0xdb, 0x1d, 0xe0, 0xd7, 0xf4, 0xfb, 0x0c, 0x05, 0xf7, + 0x1f, 0xe5, 0xce, 0xd9, 0xda, 0x4a, 0xd6, 0xd6, 0x4e, 0x88, 0x31, 0xee, 0xfb, + 0xd5, 0x36, 0xc7, 0x1d, 0xee, 0xef, 0x08, 0xdd, 0x34, 0x34, 0x31, 0xce, 0xf1, + 0xda, 0xdf, 0x0e, 0xda, 0xd6, 0x18, 0xdf, 0xdf, 0xfd, 0x1b, 0xde, 0xfc, 0xde, + 0xc0, 0x9d, 0xfe, 0xde, 0xf2, 0x1c, 0x04, 0xbf, 0x0a, 0x05, 0x8b, 0x11, 0xb2, + 0x1e, 0x1d, 0xa5, 0xea, 0x1d, 0xe9, 0xe4, 0x19, 0xcc, 0x13, 0xcb, 0x19, 0x0f, + 0xf1, 0xb0, 0xcf, 0xe6, 0xec, 0x01, 0xdb, 0x11, 0xf4, 0x3e, 0x33, 0x16, 0xcc, + 0x1a, 0xf2, 0xff, 0xa5, 0xef, 0xce, 0x13, 0x12, 0x18, 0x12, 0xf0, 0xe4, 0xf3, + 0xea, 0x06, 0xbf, 0xc4, 0xf9, 0x33, 0xc1, 0x06, 0x1f, 0xe1, 0xd0, 0x27, 0xef, + 0xfb, 0xfa, 0xdb, 0x06, 0x2b, 0xff, 0xe2, 0xbe, 0x17, 0xdb, 0x1b, 0x09, 0xf7, + 0x2d, 0x0d, 0x4a, 0x2c, 0x0c, 0x33, 0xfd, 0x03, 0x01, 0xe1, 0xf4, 0x4b, 0x05, + 0x0b, 0xcf, 0x36, 0x33, 0xed, 0x26, 0x09, 0xe1, 0x13, 0x09, 0x04, 0x35, 0x17, + 0xf2, 0x35, 0xd3, 0xfe, 0x2b, 0xdc, 0x56, 0x3a, 0xdc, 0x1c, 0xd2, 0x2f, 0x01, + 0xe4, 0x9f, 0x36, 0x71, 0xd5, 0x30, 0xe3, 0x12, 0x44, 0x25, 0xec, 0x81, 0xfb, + 0x4a, 0x08, 0xe3, 0x4a, 0x22, 0xd4, 0x37, 0xd4, 0x37, 0x1f, 0x37, 0xd1, 0x07, + 0x1d, 0xdd, 0x06, 0xfb, 0x10, 0x0c, 0xd8, 0x74, 0x07, 0xa3, 0xe4, 0x31, 0xe8, + 0xd0, 0xce, 0x21, 0x1b, 0xea, 0xb1, 0x0b, 0x5e, 0xef, 0x1c, 0x3d, 0xab, 0x42, + 0xfe, 0xf0, 0x43, 0x02, 0xd9, 0x3e, 0xe1, 0x36, 0x08, 0x89, 0x0a, 0xeb, 0xf9, + 0xdb, 0x3d, 0xca, 0xfa, 0x15, 0xed, 0x31, 0xab, 0xef, 0x41, 0xe8, 0x1a, 0xb3, + 0x4d, 0x18, 0x25, 0x39, 0x2d, 0x3e, 0xd9, 0xf9, 0x69, 0xd5, 0x30, 0x44, 0x0c, + 0x12, 0x31, 0x19, 0x51, 0x4b, 0x41, 0x26, 0x09, 0x38, 0x09, 0xcc, 0xe1, 0xed, + 0xd2, 0xf5, 0xe1, 0xe5, 0x0f, 0x0b, 0x04, 0xe0, 0xcc, 0xbe, 0x3b, 0x40, 0x18, + 0xfa, 0x10, 0xde, 0xf8, 0x2b, 0x81, 0xf7, 0x16, 0x87, 0x31, 0x47, 0x23, 0x38, + 0x12, 0x69, 0x5b, 0xd9, 0xff, 0xe7, 0xf3, 0xcb, 0x63, 0xfb, 0x48, 0x17, 0xfc, + 0x06, 0xf2, 0x15, 0xde, 0x20, 0xc8, 0x03, 0xd8, 0xe7, 0xfe, 0x31, 0xd3, 0xa7, + 0x0d, 0xf3, 0x1c, 0xf4, 0x7e, 0xd6, 0x28, 0x35, 0x13, 0x23, 0x0b, 0x00, 0xd9, + 0x09, 0x1d, 0xe0, 0x81, 0xb9, 0x45, 0xd1, 0x05, 0xe7, 0x32, 0xe5, 0x5e, 0x76, + 0xd4, 0x1a, 0x05, 0xfb, 0xef, 0xe5, 0xd3, 0x04, 0xbe, 0xea, 0xd3, 0xd7, 0xcd, + 0x43, 0xad, 0x0f, 0x0e, 0xf2, 0xed, 0x5c, 0x0a, 0x27, 0xe7, 0x08, 0xa2, 0x1f, + 0x18, 0x13, 0x12, 0x1d, 0xcc, 0x15, 0x12, 0xbc, 0xf5, 0xc1, 0x08, 0x00, 0x07, + 0xc9, 0xd6, 0xda, 0xf6, 0xcf, 0x2a, 0x14, 0xe2, 0xf8, 0xad, 0x37, 0xee, 0xfc, + 0xdd, 0xdb, 0x2b, 0x0f, 0x07, 0xf7, 0xdb, 0x26, 0xf8, 0x28, 0xf9, 0x1d, 0xf3, + 0x30, 0xed, 0x75, 0xff, 0xf7, 0x29, 0xf8, 0x16, 0x64, 0x15, 0xe1, 0xf9, 0x09, + 0xd9, 0xb8, 0xd9, 0xed, 0x47, 0xd6, 0xdd, 0x2c, 0x1c, 0xca, 0xe8, 0x94, 0x37, + 0x04, 0x20, 0x7f, 0x3d, 0x60, 0xfa, 0x1a, 0xdf, 0xc4, 0x1e, 0xf5, 0x02, 0xee, + 0x22, 0x2b, 0xfe, 0x15, 0xcf, 0x0f, 0x51, 0xfd, 0xf7, 0xdc, 0xd3, 0xf3, 0xf0, + 0xf4, 0xd8, 0xb6, 0xd2, 0x01, 0xed, 0x17, 0x1b, 0xdf, 0xf7, 0xc6, 0xf0, 0xd0, + 0x06, 0xdf, 0xd0, 0xd1, 0x22, 0x1c, 0x08, 0x28, 0x08, 0x20, 0xff, 0x64, 0x1b, + 0xa8, 0x05, 0x44, 0xdf, 0xe6, 0xca, 0xed, 0x08, 0x1f, 0xd7, 0x21, 0xff, 0xb5, + 0x6a, 0xa8, 0x45, 0x15, 0x06, 0x46, 0xa7, 0xe2, 0x10, 0xfa, 0x0e, 0xfe, 0xc2, + 0x27, 0xc3, 0x21, 0xd2, 0xef, 0x13, 0xa9, 0xed, 0x05, 0xac, 0x2d, 0xf4, 0x16, + 0xdc, 0xae, 0x3b, 0x15, 0xdf, 0xdc, 0xcc, 0x19, 0xfa, 0xfd, 0x21, 0xb0, 0xe3, + 0xe3, 0x46, 0xbd, 0xf8, 0xae, 0xd8, 0xed, 0x1f, 0x5b, 0xe4, 0xdc, 0x26, 0xff, + 0x01, 0xdb, 0x4f, 0x2d, 0x4c, 0xe1, 0xf9, 0xcc, 0xef, 0xbc, 0xb1, 0x0a, 0x20, + 0x0e, 0xef, 0x23, 0x18, 0x26, 0xaa, 0xea, 0xce, 0x0b, 0xc3, 0xb3, 0xf9, 0xf0, + 0xe3, 0xf4, 0xf0, 0xf9, 0xf2, 0x35, 0xda, 0xe8, 0x1b, 0xe0, 0xbc, 0x1e, 0xf2, + 0xbe, 0x1a, 0x28, 0x07, 0x10, 0xfb, 0xca, 0xe5, 0x19, 0xe9, 0x1f, 0x07, 0x1e, + 0xee, 0x58, 0xde, 0x05, 0xfe, 0xd2, 0xc1, 0xfc, 0x38, 0x2f, 0xdb, 0x09, 0x37, + 0xea, 0xd2, 0x23, 0x38, 0xe3, 0xde, 0xbe, 0x24, 0xd3, 0x06, 0x33, 0xda, 0xea, + 0xea, 0x1e, 0x2a, 0x23, 0x38, 0x1c, 0x13, 0x10, 0x24, 0xed, 0x7f, 0x01, 0xb5, + 0xad, 0xe0, 0x03, 0x04, 0xb3, 0xf4, 0xfe, 0xfe, 0x1e, 0xb9, 0xe3, 0xd2, 0x15, + 0xfe, 0x22, 0xf5, 0x26, 0x71, 0xe5, 0xa6, 0x0f, 0x14, 0x6f, 0xe2, 0xca, 0xbb, + 0x10, 0x97, 0xed, 0xea, 0x3f, 0xcf, 0x3b, 0xe6, 0xbe, 0xdf, 0x10, 0xbc, 0xa9, + 0x15, 0xea, 0x20, 0x09, 0x30, 0x95, 0x2f, 0xa0, 0x27, 0x17, 0xb8, 0xd6, 0x2c, + 0x25, 0x3f, 0xec, 0xb4, 0x76, 0xf3, 0xf9, 0x36, 0x45, 0x0d, 0xc6, 0x55, 0x39, + 0x3b, 0xe9, 0x13, 0x20, 0xa0, 0x36, 0xdc, 0x07, 0x26, 0xb2, 0xcc, 0x81, 0x02, + 0xba, 0x24, 0xc5, 0xf2, 0x01, 0xdf, 0xc9, 0x5f, 0x26, 0x04, 0x18, 0x2f, 0xdb, + 0x27, 0x2c, 0x53, 0xc1, 0x9a, 0xe2, 0x65, 0xcd, 0x0b, 0xd8, 0xbe, 0x15, 0x41, + 0x35, 0x24, 0x36, 0xf2, 0xb1, 0x07, 0xfc, 0xfb, 0x44, 0x58, 0x3c, 0x2a, 0x24, + 0xf4, 0xd9, 0xe8, 0xd1, 0xb5, 0x28, 0xed, 0xcf, 0xb6, 0xc6, 0xd4, 0x09, 0x09, + 0xdd, 0x0e, 0xc5, 0xeb, 0xf5, 0x17, 0xfe, 0xbf, 0x25, 0xc4, 0x15, 0x00, 0x3c, + 0xf8, 0xe4, 0xea, 0x16, 0xe6, 0xf7, 0xfd, 0xb1, 0x19, 0xe1, 0xf2, 0xfd, 0xcc, + 0x33, 0x18, 0x5e, 0x00, 0xc1, 0xfe, 0x51, 0x1c, 0x5b, 0x0e, 0xde, 0x05, 0xe5, + 0xef, 0xee, 0xef, 0xbe, 0x5b, 0xf2, 0xbb, 0xb6, 0x0d, 0x20, 0xef, 0xd9, 0x1a, + 0x50, 0x04, 0x32, 0xe8, 0xf6, 0x04, 0xe9, 0x12, 0xd0, 0xf7, 0x20, 0xe6, 0xd9, + 0xb7, 0xe4, 0xd6, 0xc9, 0x4a, 0x0e, 0x4f, 0xbf, 0xf1, 0x19, 0x2e, 0x5b, 0xbe, + 0xec, 0xac, 0x2a, 0x19, 0xb3, 0xef, 0x21, 0xe0, 0x1a, 0xf0, 0x33, 0x16, 0x12, + 0xe1, 0xe0, 0xeb, 0xec, 0xd2, 0xdf, 0xf3, 0xb0, 0x2e, 0x2a, 0x53, 0xef, 0xf5, + 0x1c, 0x2b, 0xbd, 0x8a, 0xea, 0x2c, 0xd0, 0x24, 0x27, 0xef, 0x1e, 0xf9, 0x81, + 0xcf, 0x00, 0x3b, 0x0d, 0xfe, 0x20, 0x23, 0xf0, 0x0e, 0x1a, 0x2b, 0x02, 0xdc, + 0x46, 0xcb, 0xf4, 0x1e, 0xfb, 0x1e, 0xdf, 0x6c, 0xd3, 0xe8, 0xfd, 0x06, 0x53, + 0x0d, 0x2f, 0x26, 0x11, 0x22, 0xc0, 0xcf, 0x7e, 0xff, 0xc4, 0xfe, 0x14, 0xf9, + 0x06, 0x35, 0xed, 0xd5, 0x3e, 0xdf, 0xf9, 0xe9, 0x0d, 0xe6, 0x36, 0xa0, 0xe2, + 0x24, 0xc9, 0x25, 0xab, 0xf7, 0xec, 0x15, 0x33, 0x98, 0xd7, 0x22, 0xb0, 0xdd, + 0x5d, 0x1f, 0xda, 0x01, 0xe5, 0x0d, 0xe7, 0xdf, 0xee, 0x9c, 0x33, 0xc4, 0xf0, + 0xfc, 0x3d, 0x1d, 0xea, 0x1b, 0x2c, 0xcf, 0x37, 0x32, 0xdc, 0xc2, 0x0c, 0xc0, + 0x53, 0x0b, 0xc8, 0xd6, 0x2f, 0xeb, 0xfc, 0xb7, 0x1e, 0x26, 0xaf, 0x25, 0x0e, + 0x2b, 0x05, 0x2f, 0x05, 0x20, 0x93, 0x0c, 0xd1, 0xa7, 0x0f, 0x6e, 0xf2, 0x01, + 0xc1, 0x32, 0xdd, 0x00, 0xea, 0xef, 0xcc, 0xc7, 0xf8, 0xec, 0xa3, 0x25, 0x0a, + 0xb6, 0xb1, 0x00, 0x26, 0xa6, 0x22, 0x34, 0x11, 0x07, 0x1b, 0xd1, 0xf1, 0xba, + 0x46, 0x08, 0xe0, 0xcf, 0x81, 0x36, 0xd9, 0x24, 0xf8, 0xff, 0x54, 0x39, 0x25, + 0xf2, 0x17, 0x3a, 0xd5, 0x15, 0xfd, 0xd8, 0x12, 0x19, 0x24, 0x08, 0x22, 0x0a, + 0x01, 0xd7, 0x24, 0xbb, 0x00, 0xbf, 0x0c, 0xcf, 0xd8, 0xde, 0x25, 0x2c, 0x68, + 0xf3, 0xf5, 0xd8, 0xab, 0x18, 0x17, 0x46, 0x0a, 0xd9, 0x31, 0xaa, 0x30, 0x68, + 0xe8, 0x08, 0xc7, 0xf2, 0x01, 0x90, 0xf7, 0xca, 0x76, 0xba, 0x53, 0xe9, 0xef, + 0x0a, 0xb3, 0x1f, 0xe9, 0x27, 0x1a, 0x7b, 0xff, 0xef, 0x3f, 0x08, 0xb2, 0x24, + 0x85, 0x03, 0xbf, 0x44, 0xdc, 0xe2, 0x00, 0xf7, 0xe7, 0x9a, 0x3d, 0xf6, 0xbc, + 0x99, 0xff, 0x1f, 0x3c, 0xca, 0x8c, 0x85, 0xef, 0x18, 0xf3, 0xfd, 0xbc, 0xcd, + 0x14, 0x3c, 0x27, 0xf8, 0x23, 0xcc, 0xfc, 0x81, 0xa6, 0x28, 0x1b, 0x48, 0xd8, + 0x16, 0xfe, 0x0b, 0x13, 0xbb, 0xdb, 0xdd, 0x04, 0xd0, 0xda, 0x05, 0xf9, 0x0f, + 0xd7, 0xfe, 0xce, 0x38, 0x33, 0x25, 0x26, 0xfb, 0x3f, 0x46, 0xe4, 0xb9, 0xe4, + 0x97, 0xb3, 0xfa, 0x15, 0x31, 0x00, 0x06, 0xa0, 0x04, 0xdf, 0xb4, 0x1e, 0x1c, + 0x0b, 0xd6, 0xcc, 0xc4, 0x10, 0xc7, 0xf6, 0xde, 0x07, 0x3e, 0x87, 0xef, 0x49, + 0x13, 0xf5, 0xfe, 0xdf, 0x29, 0x69, 0x0c, 0xf9, 0x13, 0x2d, 0x7f, 0x33, 0xdc, + 0x36, 0xfe, 0x03, 0xd7, 0x09, 0x0c, 0x2c, 0x1c, 0x2f, 0x73, 0x00, 0x25, 0xff, + 0xd5, 0x52, 0xd9, 0xe2, 0x5e, 0xa6, 0x00, 0x12, 0x12, 0x0a, 0xe5, 0x07, 0x33, + 0xbc, 0x21, 0x00, 0xf2, 0xe5, 0xf4, 0x22, 0xfd, 0x07, 0xf7, 0x33, 0xef, 0x52, + 0x14, 0xf3, 0xdd, 0xd8, 0x43, 0xf7, 0xbe, 0xf6, 0xf0, 0xd9, 0x35, 0x00, 0xe3, + 0x4b, 0xf0, 0x0f, 0xfa, 0xfe, 0x2c, 0x3e, 0xe0, 0xf7, 0xcf, 0x1e, 0xf1, 0x3b, + 0xf3, 0xd3, 0x35, 0xbd, 0x51, 0x15, 0xed, 0xdd, 0x00, 0xec, 0x24, 0x1e, 0x3f, + 0x1e, 0xdf, 0xed, 0xfb, 0x58, 0x0a, 0xf9, 0x28, 0xeb, 0xc6, 0xda, 0xd9, 0x0a, + 0x01, 0xc4, 0x1d, 0xe4, 0xfc, 0xcb, 0xc6, 0xba, 0xc7, 0xef, 0x0e, 0xca, 0x40, + 0xe5, 0x02, 0xce, 0x30, 0xcd, 0x47, 0xe3, 0x10, 0x02, 0x16, 0x07, 0xf2, 0x03, + 0xf1, 0xec, 0x0a, 0x32, 0x19, 0xf3, 0x03, 0xe0, 0x26, 0x1e, 0xc8, 0x00, 0xf4, + 0x11, 0x14, 0xd8, 0xe4, 0x0e, 0x0a, 0x27, 0x16, 0x26, 0x0b, 0x04, 0x2f, 0x12, + 0x67, 0x10, 0xce, 0xf5, 0xb7, 0xf4, 0xe1, 0xed, 0xcf, 0xed, 0xfa, 0x12, 0xf0, + 0x0b, 0xf7, 0xe9, 0x0d, 0xe7, 0x25, 0xdf, 0xe9, 0xe9, 0x3d, 0xea, 0xe6, 0x1e, + 0x20, 0xee, 0x15, 0x02, 0x2f, 0x11, 0x07, 0xb0, 0x1a, 0xce, 0xf0, 0x61, 0xae, + 0x0c, 0xe5, 0xdf, 0x06, 0x15, 0xed, 0xe2, 0x12, 0x27, 0xfe, 0x03, 0xf7, 0x0a, + 0xf8, 0x06, 0x38, 0xfe, 0xfd, 0x26, 0xfa, 0xf2, 0xf9, 0x2d, 0xea, 0xb2, 0x11, + 0xd7, 0x19, 0x7f, 0xcf, 0x17, 0x29, 0x03, 0x35, 0xfb, 0xe1, 0xd1, 0xf7, 0xdd, + 0x7c, 0xfb, 0x16, 0x31, 0x14, 0x16, 0xe4, 0xcf, 0xe4, 0xc3, 0x4e, 0x1e, 0x10, + 0xf5, 0x07, 0xe7, 0xe8, 0xf1, 0x05, 0x21, 0xe3, 0xb3, 0x18, 0x07, 0x12, 0x45, + 0x04, 0xaf, 0x0a, 0xca, 0x16, 0x7a, 0xf6, 0x09, 0x04, 0xf8, 0x09, 0x1e, 0xe9, + 0x4b, 0xbf, 0x14, 0xe9, 0x0d, 0xbc, 0x0d, 0x23, 0x01, 0xd1, 0xfe, 0x1f, 0xce, + 0x4c, 0x17, 0xc1, 0x2e, 0xdc, 0x07, 0x09, 0x5a, 0x06, 0x23, 0x03, 0x2d, 0x18, + 0x33, 0xf5, 0xfe, 0xc6, 0xbe, 0x07, 0xd4, 0x5d, 0x0a, 0x0a, 0x29, 0x28, 0xf6, + 0x53, 0x19, 0xea, 0x15, 0xcf, 0x2b, 0xe9, 0x28, 0xda, 0x96, 0xf2, 0x36, 0x7e, + 0xe7, 0xfc, 0x42, 0xe6, 0x81, 0x2a, 0x4f, 0xec, 0xe6, 0xe2, 0x1f, 0x96, 0xe2, + 0xc7, 0xe1, 0xfe, 0x19, 0xe4, 0x04, 0x29, 0xb7, 0x2c, 0x2c, 0xde, 0xa7, 0x1d, + 0x94, 0x56, 0xe2, 0x0d, 0xc1, 0xe0, 0xc5, 0x72, 0xf6, 0x20, 0x40, 0xd1, 0x7c, + 0xce, 0xb8, 0x54, 0xe4, 0x4d, 0x0c, 0xfb, 0xad, 0xf0, 0x45, 0x3f, 0x18, 0xef, + 0xf3, 0x19, 0xfe, 0x14, 0x92, 0x61, 0xf8, 0x31, 0xe5, 0x1a, 0xd4, 0x0a, 0xe8, + 0x19, 0xe9, 0xd7, 0x0e, 0x6d, 0x00, 0x0e, 0x32, 0x22, 0xc5, 0xe7, 0x07, 0x2d, + 0xfe, 0xd0, 0x5b, 0x35, 0xf5, 0xc2, 0xef, 0xd6, 0xd0, 0xca, 0xc1, 0x20, 0xcd, + 0x11, 0xce, 0xee, 0xf7, 0x7f, 0x2b, 0x39, 0x98, 0xfe, 0x1b, 0xc4, 0x28, 0xd1, + 0x1a, 0x03, 0x0c, 0xd8, 0x25, 0x11, 0xf5, 0x41, 0xfd, 0xe6, 0x20, 0x37, 0x0a, + 0x08, 0xe8, 0xbb, 0xbe, 0x96, 0xe5, 0x0b, 0x06, 0xf0, 0x14, 0x25, 0x3a, 0x61, + 0xe6, 0x63, 0x22, 0x3c, 0xe8, 0xd9, 0xf6, 0xf1, 0xa2, 0x1e, 0xf7, 0x19, 0x1d, + 0xfb, 0xbf, 0x32, 0x0f, 0xdf, 0x11, 0x37, 0x2f, 0xf2, 0x6c, 0x4a, 0xf3, 0x1d, + 0x1f, 0xa1, 0xde, 0x3a, 0x3f, 0xd4, 0xdf, 0xea, 0xd1, 0x03, 0xe3, 0xb9, 0x16, + 0x44, 0xb3, 0xd1, 0xda, 0xfc, 0x44, 0x42, 0xea, 0x27, 0x58, 0xd8, 0x08, 0xe0, + 0xea, 0x02, 0xf9, 0x25, 0x26, 0x56, 0x9a, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, + 0x80, 0x04, 0x00, 0x00, 0x81, 0x60, 0xec, 0x3a, 0xec, 0xce, 0xe9, 0xca, 0x06, + 0xcc, 0xe2, 0x3f, 0xee, 0x7f, 0x81, 0x6d, 0xe5, 0xaa, 0x7f, 0x89, 0x78, 0x19, + 0xbb, 0xcc, 0x3e, 0x59, 0x17, 0x4d, 0x3b, 0xc4, 0x54, 0xf7, 0x98, 0xf1, 0xe8, + 0xc3, 0xa9, 0xcb, 0xe8, 0xf1, 0x51, 0xe5, 0x50, 0xb1, 0xcb, 0x5f, 0x3d, 0x7f, + 0x01, 0xb4, 0xab, 0xe4, 0x42, 0xf5, 0x3e, 0x7f, 0xfe, 0xad, 0x60, 0x71, 0x96, + 0x47, 0xd3, 0x08, 0xf2, 0xf9, 0x4d, 0x34, 0x60, 0x7f, 0x71, 0x7f, 0xba, 0xc9, + 0xd9, 0xac, 0x9c, 0x5c, 0x31, 0x70, 0x81, 0xfb, 0xc7, 0x21, 0x88, 0x57, 0x7f, + 0xf8, 0x99, 0xa6, 0x2f, 0xdd, 0xf5, 0x7f, 0x18, 0x0d, 0x59, 0x96, 0xb0, 0xd1, + 0xf2, 0xad, 0xc6, 0x5e, 0x84, 0xb4, 0x81, 0xd1, 0xf3, 0xae, 0x7f, 0x77, 0x0b, + 0xd7, 0xbc, 0x27, 0x04, 0xd0, 0xcf, 0xae, 0xd1, 0x5a, 0xd6, 0xfe, 0x7f, 0x1d, + 0xc8, 0x21, 0xb2, 0xfa, 0xcf, 0x04, 0xc6, 0x32, 0xf6, 0xd6, 0x10, 0xcc, 0xce, + 0x60, 0x32, 0x4b, 0x14, 0x73, 0x81, 0xd5, 0x33, 0x83, 0xeb, 0x3c, 0x85, 0xa4, + 0x7f, 0xc9, 0xdd, 0xcb, 0x7f, 0x0a, 0x52, 0xec, 0x42, 0xcc, 0x20, 0xd2, 0x81, + 0xd9, 0xe4, 0x4a, 0x7f, 0x45, 0xf5, 0x30, 0xc4, 0xff, 0x35, 0x69, 0xc2, 0xdc, + 0xc5, 0xd0, 0x4e, 0x31, 0x69, 0xd8, 0x15, 0x5f, 0x59, 0x35, 0x31, 0x13, 0xbf, + 0xf7, 0x33, 0x1c, 0xd6, 0x51, 0x7f, 0x50, 0xf7, 0x4c, 0x1e, 0xed, 0x81, 0xf5, + 0xec, 0x1e, 0x3a, 0x21, 0x9e, 0xf2, 0xf7, 0x7c, 0x36, 0xbd, 0xe8, 0xb8, 0x86, + 0xe1, 0xd9, 0x7f, 0x5e, 0x2f, 0xb0, 0xdc, 0x89, 0x15, 0xd3, 0x38, 0x81, 0xd5, + 0x8e, 0x16, 0x18, 0x2d, 0xc1, 0xf7, 0x31, 0xc5, 0x70, 0x3c, 0xf3, 0xae, 0x81, + 0xb7, 0xcf, 0xcf, 0xc3, 0x37, 0xab, 0x7f, 0x39, 0x97, 0x0b, 0xde, 0xe3, 0x81, + 0x8b, 0xb9, 0x02, 0x0b, 0xb0, 0xac, 0x4d, 0xaa, 0x01, 0x56, 0x56, 0x36, 0x74, + 0x84, 0x94, 0x7f, 0xd6, 0xd8, 0x47, 0xad, 0xbc, 0xbf, 0xe0, 0x81, 0x9e, 0x2b, + 0xf0, 0xcc, 0x42, 0xbb, 0xdc, 0x11, 0xbc, 0x83, 0xd0, 0xe5, 0xd5, 0x04, 0xd6, + 0x5b, 0x02, 0x51, 0xbe, 0x87, 0xc6, 0x31, 0x2a, 0xe5, 0xf6, 0xe8, 0x81, 0x02, + 0x7f, 0x32, 0x3d, 0xc8, 0x7f, 0xcd, 0x4c, 0x7f, 0x81, 0x25, 0x1a, 0x0d, 0x1a, + 0x6c, 0x7f, 0x22, 0x48, 0x70, 0x63, 0x58, 0x18, 0x81, 0xcf, 0xdc, 0x96, 0x7d, + 0xb0, 0x74, 0xd1, 0xdf, 0x81, 0x46, 0x3a, 0xe3, 0x52, 0x28, 0x7f, 0x81, 0xcd, + 0x56, 0xf2, 0xd9, 0xfb, 0x81, 0xd8, 0x1c, 0xad, 0xf9, 0xcc, 0x46, 0x95, 0xd2, + 0x92, 0xca, 0xe3, 0xdd, 0x6d, 0x2e, 0x3c, 0xfb, 0xd0, 0xc1, 0xde, 0x96, 0xe5, + 0x3a, 0x7f, 0x40, 0xaf, 0x6b, 0xde, 0xb4, 0xf9, 0xfb, 0xce, 0x1e, 0xee, 0xc7, + 0x03, 0x30, 0x14, 0xc5, 0xed, 0xe6, 0x81, 0x7f, 0x89, 0xee, 0xb9, 0xf9, 0xcd, + 0x1b, 0x66, 0xb9, 0x5a, 0x86, 0x34, 0x4c, 0x9f, 0xf0, 0x54, 0x23, 0x0c, 0x7f, + 0xf6, 0x7f, 0x00, 0x81, 0x5f, 0x46, 0x0a, 0x3b, 0xc5, 0x19, 0x2c, 0x12, 0x19, + 0xb4, 0x7f, 0x81, 0x81, 0x53, 0xdd, 0x29, 0x3a, 0x81, 0xf5, 0x7f, 0x1d, 0x09, + 0x0c, 0x2b, 0x2d, 0x13, 0x8f, 0xe0, 0x12, 0x04, 0xef, 0x4c, 0x7f, 0x0f, 0x04, + 0x4a, 0x35, 0xdf, 0x7f, 0xb4, 0xff, 0x85, 0x38, 0xfa, 0x40, 0x05, 0x7f, 0x32, + 0xd5, 0x7f, 0xc7, 0x12, 0x81, 0x53, 0x99, 0xc2, 0xb6, 0xd9, 0xea, 0x27, 0x20, + 0xe9, 0xf4, 0xff, 0x3c, 0x99, 0x7d, 0x62, 0x0b, 0x7f, 0x81, 0x7f, 0x34, 0xa2, + 0xd4, 0x19, 0xcf, 0xb0, 0x1f, 0x7b, 0x1e, 0xcb, 0xd7, 0x4c, 0x34, 0xc0, 0xb3, + 0xb6, 0xcf, 0x9c, 0xf8, 0xb0, 0x04, 0xd7, 0x07, 0xbf, 0x00, 0xb0, 0x4a, 0x7f, + 0x81, 0x81, 0x13, 0x11, 0xd8, 0x88, 0xba, 0x0d, 0x81, 0xe8, 0xc2, 0x2c, 0x1b, + 0x36, 0x0d, 0x24, 0x81, 0x7f, 0xbd, 0x78, 0x3c, 0x04, 0x05, 0xe0, 0x2f, 0x08, + 0x44, 0xaf, 0x57, 0x7f, 0x48, 0xe5, 0xc1, 0x03, 0x03, 0x49, 0xf9, 0xf2, 0xf4, + 0xad, 0xd8, 0x02, 0x58, 0x41, 0x81, 0xc2, 0xaa, 0x0b, 0x1b, 0x01, 0x64, 0x19, + 0xee, 0x7f, 0xf0, 0xe7, 0xd0, 0x19, 0xe5, 0x2f, 0x01, 0x25, 0x17, 0x7f, 0xf0, + 0x06, 0xdd, 0xc1, 0x1d, 0x03, 0x66, 0x39, 0x52, 0xcc, 0x4a, 0x81, 0xde, 0x35, + 0x45, 0x7f, 0x44, 0xef, 0xa4, 0x21, 0xc0, 0xe1, 0x18, 0xfd, 0x7f, 0x42, 0xf6, + 0x9e, 0x81, 0x81, 0x5c, 0x7f, 0xa9, 0x6f, 0x9e, 0x0a, 0x73, 0xe5, 0xdd, 0xd1, + 0xf1, 0x38, 0x4a, 0x1e, 0xf0, 0xb6, 0xde, 0xfc, 0xf6, 0x39, 0xe0, 0xf8, 0x5a, + 0x9e, 0x81, 0xaa, 0xb5, 0xd9, 0xe5, 0xe2, 0xe8, 0xd3, 0xa4, 0x24, 0xc7, 0xc3, + 0x7f, 0x1a, 0xdc, 0xeb, 0x2e, 0x16, 0x0a, 0x30, 0xf0, 0xf2, 0xab, 0xb8, 0x66, + 0x81, 0x95, 0x17, 0x81, 0x7f, 0xba, 0x1a, 0xe9, 0xdd, 0x09, 0x2d, 0x7f, 0x35, + 0xab, 0x04, 0x13, 0x7f, 0xc7, 0x45, 0x09, 0x7f, 0x56, 0x0c, 0x09, 0xea, 0xc4, + 0x19, 0x7f, 0x08, 0x0e, 0xcf, 0xcd, 0x33, 0x28, 0x06, 0x3c, 0xe6, 0x75, 0x08, + 0xd8, 0xf1, 0xb4, 0x2e, 0xff, 0x7f, 0x3d, 0x7f, 0x6f, 0x17, 0x0f, 0x2a, 0x09, + 0x04, 0x1c, 0x96, 0x33, 0x2c, 0x7f, 0xf6, 0x89, 0xe9, 0x09, 0x65, 0xa8, 0x2c, + 0x42, 0xe4, 0xb9, 0xd5, 0xef, 0xed, 0x81, 0x00, 0x45, 0xe5, 0x7f, 0x20, 0x13, + 0x6c, 0x4f, 0x02, 0xbd, 0x59, 0x8c, 0xbc, 0xdd, 0xe1, 0x57, 0xe5, 0x6e, 0x7f, + 0x7e, 0x27, 0x3f, 0xa7, 0x0a, 0x9f, 0x7f, 0x7f, 0x51, 0x16, 0xed, 0xba, 0x91, + 0x06, 0x69, 0xf2, 0xc3, 0x46, 0xb4, 0x81, 0xd7, 0x54, 0xa1, 0x83, 0x20, 0x3f, + 0xef, 0x58, 0x7f, 0xb7, 0x37, 0xd0, 0xf5, 0x23, 0x50, 0xa0, 0xb3, 0x85, 0x4a, + 0x1f, 0xf4, 0x89, 0x3d, 0x7f, 0x7f, 0x96, 0xdb, 0x51, 0x5f, 0xf0, 0x7f, 0xdf, + 0x64, 0x3a, 0x87, 0x7f, 0x7f, 0x25, 0x99, 0xaa, 0xdc, 0xda, 0xd2, 0x67, 0xd9, + 0xab, 0x5c, 0x82, 0xc9, 0x20, 0xe2, 0xfd, 0xdf, 0xf9, 0x09, 0xaa, 0x81, 0xf4, + 0x89, 0x7f, 0x14, 0xf2, 0x0e, 0x24, 0x6b, 0x31, 0x23, 0xd6, 0x00, 0xe2, 0x4a, + 0xac, 0x31, 0x1c, 0xfb, 0xc4, 0x98, 0xd0, 0xcc, 0x66, 0x13, 0x13, 0xcf, 0x5a, + 0x38, 0x81, 0xfc, 0x98, 0x08, 0xaa, 0xc1, 0xbe, 0x33, 0x99, 0x4a, 0xd7, 0x7f, + 0x3f, 0x09, 0x2c, 0xfc, 0xf9, 0x11, 0xcd, 0xa1, 0x30, 0x81, 0xde, 0x7d, 0x7f, + 0x7f, 0x3b, 0xcd, 0x4d, 0x1e, 0x3c, 0x39, 0x83, 0x86, 0xad, 0xb6, 0x7f, 0xd8, + 0x7f, 0x7f, 0xa5, 0xf5, 0xb6, 0xbf, 0x16, 0xfc, 0xc0, 0x18, 0x7f, 0xad, 0x97, + 0x23, 0x81, 0xf2, 0x5f, 0xe8, 0x04, 0xf9, 0x81, 0x89, 0x8c, 0xbd, 0xe9, 0xb6, + 0xd9, 0xbb, 0x3e, 0x26, 0xd2, 0xce, 0x15, 0x6d, 0xe7, 0xd7, 0x62, 0x7f, 0x50, + 0xc3, 0x3d, 0xd4, 0x54, 0xc6, 0x81, 0xe2, 0xd0, 0x8b, 0x5f, 0x92, 0xd2, 0xbc, + 0xdc, 0x93, 0x22, 0x04, 0x7f, 0xc8, 0xf2, 0xa1, 0xe6, 0x3a, 0xba, 0xb1, 0x6c, + 0x31, 0xea, 0xff, 0xfb, 0x19, 0x19, 0x23, 0xf7, 0xfc, 0xf5, 0x35, 0xd1, 0x1e, + 0x4e, 0xd9, 0x81, 0x21, 0xb7, 0xa0, 0xf6, 0xf6, 0x34, 0xfd, 0x17, 0x34, 0x1c, + 0x00, 0xbf, 0x43, 0x9b, 0x07, 0x0e, 0x0f, 0xf2, 0xda, 0xd1, 0x42, 0x2a, 0xb3, + 0x32, 0x89, 0xf3, 0x7f, 0x7f, 0xd7, 0x7f, 0xab, 0x13, 0xd5, 0xea, 0x68, 0x54, + 0xc8, 0x7f, 0x2d, 0x4a, 0xde, 0x14, 0x7f, 0xbe, 0x84, 0xe3, 0x0f, 0xba, 0xee, + 0xff, 0xc0, 0x1f, 0x81, 0x29, 0x88, 0xc1, 0x64, 0x31, 0xd8, 0xdc, 0x20, 0x9d, + 0x70, 0x14, 0xf3, 0x49, 0xee, 0xf1, 0xe0, 0xb5, 0xa0, 0xf3, 0x94, 0x4c, 0xb0, + 0x1c, 0xf8, 0x3c, 0xed, 0x1e, 0x4e, 0xb8, 0x99, 0xfa, 0x4e, 0x16, 0x18, 0x6a, + 0x08, 0x57, 0xa6, 0x4b, 0xe4, 0x94, 0x9e, 0x7f, 0x31, 0xb9, 0x50, 0xab, 0x11, + 0x3a, 0xd5, 0x18, 0x81, 0xf0, 0x50, 0xbf, 0x46, 0xda, 0xae, 0x3e, 0x7f, 0x11, + 0x02, 0x26, 0x07, 0x2a, 0xa6, 0xb6, 0x7f, 0xc1, 0x7f, 0xb6, 0x4f, 0x7f, 0xbe, + 0x05, 0xd6, 0x35, 0x01, 0x2f, 0x9f, 0x68, 0x49, 0x7f, 0x1e, 0x75, 0x3c, 0xb7, + 0x6f, 0xac, 0xfd, 0x07, 0x48, 0x15, 0x05, 0x6d, 0x15, 0xd5, 0x3d, 0x00, 0xf3, + 0xa4, 0x10, 0xf9, 0xa1, 0xdf, 0x6d, 0xaf, 0x03, 0xa9, 0x37, 0x7f, 0xbb, 0x91, + 0x75, 0x5e, 0xc1, 0x7f, 0x3c, 0x07, 0xb5, 0xd2, 0x34, 0xda, 0xe3, 0xf1, 0xe2, + 0x9e, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x12, 0xd3, + 0xfd, 0xe4, 0x0c, 0x1f, 0x00, 0x20, 0xd0, 0xd2, 0xbf, 0x02, 0x26, 0x05, 0x27, + 0xdf, 0x04, 0x17, 0x3b, 0xf9, 0xde, 0xdc, 0x14, 0x32, 0xce, 0xc8, 0x26, 0x11, + 0x0d, 0xd0, 0xda, 0xfd, 0x0e, 0x33, 0x3c, 0x29, 0xdf, 0xe9, 0xea, 0x03, 0xc2, + 0xe8, 0x1c, 0xca, 0xdb, 0x7f, 0xbb, 0xeb, 0xcb, 0x29, 0x16, 0x1d, 0xbb, 0x1b, + 0xeb, 0xf4, 0x05, 0xf2, 0x23, 0xff, 0xc1, 0x1b, 0xdf, 0x58, 0x03, 0x22, 0xa7, + 0xdf, 0x2e, 0x06, 0x90, 0x1d, 0xf7, 0x04, 0x06, 0x28, 0x2c, 0x21, 0xff, 0xf1, + 0x12, 0x9f, 0x06, 0x2a, 0xce, 0xd6, 0xdd, 0x0e, 0xf2, 0x1e, 0x05, 0xfd, 0x38, + 0xdd, 0x38, 0xff, 0x43, 0xfb, 0xc4, 0x1e, 0x2f, 0xee, 0x53, 0xcb, 0xdd, 0xf8, + 0xf4, 0x47, 0xbb, 0x16, 0x3e, 0xc4, 0xf8, 0x0f, 0xeb, 0xfa, 0x0a, 0x36, 0xcf, + 0xe7, 0xe5, 0x0a, 0x0e, 0xe4, 0x9a, 0x14, 0xcc, 0x01, 0xf5, 0x07, 0xd5, 0xba, + 0xe2, 0xef, 0xfc, 0xc5, 0xe4, 0x17, 0x25, 0xed, 0x11, 0xf8, 0xf3, 0xd7, 0xdf, + 0xe7, 0xef, 0x42, 0xed, 0xcc, 0xd0, 0x05, 0xb8, 0xf1, 0xdc, 0x23, 0x63, 0x2e, + 0x16, 0xf0, 0x02, 0xd5, 0x23, 0xfc, 0x43, 0xf9, 0xe4, 0x31, 0xce, 0x0d, 0xdd, + 0x36, 0xed, 0x02, 0xcf, 0xd1, 0xc6, 0x0b, 0x29, 0x7f, 0x33, 0xda, 0x3c, 0xbc, + 0xed, 0xed, 0x18, 0xb3, 0xfc, 0x11, 0x19, 0x55, 0x0f, 0x16, 0xbd, 0x2c, 0xec, + 0x25, 0xf0, 0xe4, 0x08, 0x35, 0x38, 0x05, 0x2a, 0xd1, 0xdc, 0xd9, 0x0c, 0xe2, + 0xda, 0xee, 0x24, 0xd1, 0x01, 0x02, 0x2e, 0xd1, 0x0f, 0x35, 0xcf, 0xd4, 0xe6, + 0x13, 0x19, 0xff, 0x36, 0x02, 0x0f, 0xe5, 0x14, 0xe4, 0xf6, 0xee, 0xed, 0xdd, + 0xd4, 0xcd, 0xc3, 0xff, 0xfb, 0x49, 0xe4, 0xe2, 0xc9, 0xf7, 0xb6, 0xf0, 0xed, + 0x0d, 0x23, 0xf8, 0xdd, 0xff, 0xd8, 0xcf, 0x03, 0x0a, 0x16, 0xdc, 0xf3, 0x0c, + 0x27, 0xfa, 0x00, 0x0d, 0x24, 0x0a, 0xea, 0x2d, 0x11, 0x1c, 0x06, 0xef, 0x75, + 0xfb, 0x0e, 0x10, 0xf0, 0x29, 0xc6, 0xff, 0xe1, 0xfb, 0xf0, 0xeb, 0xee, 0x0c, + 0x35, 0x31, 0x4e, 0x3b, 0x16, 0x09, 0xb2, 0x05, 0x31, 0x28, 0xba, 0x33, 0xd9, + 0x18, 0x3a, 0xb7, 0xf0, 0xe5, 0x17, 0xd8, 0x0d, 0x2f, 0xf8, 0xdc, 0xbc, 0xdd, + 0xf4, 0x3c, 0x20, 0xf4, 0x12, 0x11, 0x1d, 0x3f, 0xee, 0x0d, 0x16, 0x17, 0xaf, + 0xfd, 0xd8, 0xdd, 0x16, 0xf8, 0x1c, 0xc0, 0xff, 0xe7, 0xfa, 0xef, 0x18, 0x03, + 0x0a, 0xdd, 0xfe, 0x18, 0x19, 0xed, 0xec, 0x7f, 0xf2, 0x06, 0xf4, 0x30, 0x04, + 0x10, 0x0a, 0xfb, 0x15, 0xd6, 0x25, 0xd2, 0xe2, 0x02, 0xd8, 0x16, 0x1b, 0x47, + 0x1a, 0x0b, 0xe9, 0xc9, 0x27, 0xd1, 0xc7, 0xfc, 0x06, 0x04, 0x25, 0xd7, 0xe8, + 0xfa, 0x17, 0x07, 0x4d, 0xe8, 0x1d, 0xe3, 0x20, 0xfb, 0xc4, 0xd4, 0xbe, 0x81, + 0xd0, 0xf0, 0x03, 0x0a, 0x0b, 0x5b, 0x00, 0x3c, 0x31, 0x43, 0x3c, 0xfa, 0x23, + 0xcf, 0x2b, 0xdf, 0x3e, 0x5a, 0xed, 0x05, 0xab, 0x5f, 0xcb, 0x05, 0xfb, 0x0b, + 0xd5, 0xed, 0xe9, 0xca, 0x18, 0x2e, 0x39, 0x49, 0xca, 0x0f, 0x44, 0xf4, 0x9c, + 0xa9, 0x14, 0xef, 0xd3, 0x04, 0xed, 0xd0, 0x13, 0xe4, 0x05, 0x2d, 0xb2, 0x11, + 0xff, 0xcb, 0x06, 0xd4, 0x15, 0xad, 0x19, 0x43, 0x0b, 0xf9, 0xec, 0xd8, 0x1f, + 0xcf, 0xd7, 0x03, 0xe3, 0x11, 0x29, 0x1a, 0x24, 0x00, 0x1a, 0xdc, 0x2b, 0x1d, + 0x48, 0xfb, 0xdb, 0xe4, 0xe9, 0xb8, 0x0b, 0x2c, 0x2a, 0x1a, 0xc4, 0x12, 0xc2, + 0xbf, 0xeb, 0xdb, 0x17, 0x7c, 0xfa, 0xe6, 0xfe, 0xe5, 0x0a, 0xdc, 0x11, 0x49, + 0xe3, 0x08, 0x21, 0xf3, 0x39, 0xe7, 0x50, 0x44, 0x03, 0x11, 0xf9, 0x51, 0xfc, + 0xff, 0x2b, 0x2c, 0x12, 0xf5, 0xde, 0x15, 0x12, 0xa7, 0x18, 0xea, 0x12, 0xba, + 0xf2, 0x01, 0xe1, 0x0e, 0x2c, 0xf3, 0xff, 0x10, 0xbd, 0xcc, 0x34, 0xf0, 0x0c, + 0x0b, 0xf3, 0x1b, 0xf9, 0xf9, 0xbf, 0x7f, 0xf0, 0x06, 0x58, 0x4b, 0xcb, 0xf7, + 0x0d, 0xa3, 0x0e, 0x06, 0xe1, 0x17, 0x0d, 0xe4, 0x1d, 0x46, 0x0f, 0xd5, 0xdf, + 0x27, 0xfc, 0x2e, 0xec, 0x30, 0x09, 0xf2, 0x10, 0xc6, 0xd9, 0x00, 0xde, 0x68, + 0x3e, 0x73, 0xea, 0x12, 0xf9, 0xc5, 0xdf, 0x3c, 0x4c, 0x42, 0xe1, 0x08, 0x22, + 0x1f, 0x11, 0x10, 0xcc, 0x22, 0x18, 0x02, 0x51, 0x11, 0x03, 0xee, 0xd6, 0xf1, + 0x31, 0x02, 0xd8, 0x10, 0x0e, 0xf5, 0xd5, 0x3f, 0x0e, 0xea, 0xbf, 0x1d, 0x26, + 0x3a, 0x36, 0x0e, 0x2d, 0x10, 0xf8, 0x4c, 0x5a, 0x2c, 0x16, 0x52, 0xe4, 0x1a, + 0x29, 0xf7, 0x96, 0xcc, 0x38, 0xf2, 0xe3, 0x13, 0x4f, 0x13, 0xc0, 0xfb, 0x14, + 0xe9, 0xf3, 0x01, 0x00, 0x25, 0xce, 0xe7, 0xd4, 0xde, 0xe0, 0xe0, 0x10, 0xd0, + 0x04, 0xfe, 0xce, 0x10, 0xd6, 0xf3, 0x18, 0xaa, 0x07, 0xe4, 0x38, 0x15, 0xe0, + 0xd6, 0xb8, 0xf3, 0x12, 0xc6, 0xf6, 0x3b, 0xfe, 0x6f, 0xfe, 0xe3, 0x13, 0xdd, + 0xcd, 0xf8, 0x12, 0x42, 0x15, 0xf2, 0x4f, 0x04, 0x14, 0xc7, 0xf5, 0xc8, 0xd8, + 0xec, 0xe4, 0x0b, 0xfa, 0xe2, 0x21, 0x1e, 0xdd, 0x3b, 0xd7, 0xf8, 0xe8, 0x44, + 0xc2, 0x10, 0xb0, 0xc8, 0x01, 0xfc, 0x1c, 0xf0, 0xec, 0x00, 0xd2, 0x1f, 0xeb, + 0xe0, 0x07, 0xeb, 0x2d, 0x4c, 0x33, 0x2a, 0x21, 0x99, 0xea, 0x17, 0xe9, 0x2c, + 0xe2, 0xee, 0x11, 0xd3, 0x3a, 0x11, 0x25, 0xd7, 0x89, 0x25, 0x33, 0x43, 0x0e, + 0x24, 0x21, 0x0b, 0xe5, 0x0f, 0x20, 0x0e, 0xc8, 0x39, 0xaa, 0xd8, 0x21, 0x81, + 0xca, 0xed, 0x22, 0x46, 0xf5, 0x0e, 0x20, 0x06, 0xf1, 0x10, 0xce, 0xec, 0xe8, + 0xd8, 0x34, 0x01, 0x13, 0x03, 0x19, 0x18, 0x29, 0xde, 0xbc, 0x0f, 0x3c, 0xcc, + 0xf8, 0x7f, 0xf4, 0xd2, 0x63, 0x00, 0xf0, 0x27, 0xfc, 0xd4, 0xe6, 0x03, 0x32, + 0xf7, 0x4b, 0xc4, 0x0e, 0xdc, 0x0a, 0x05, 0xb4, 0xec, 0xe2, 0xce, 0x04, 0xe4, + 0x0a, 0xb6, 0x1b, 0x12, 0xea, 0x40, 0x0f, 0x56, 0x0a, 0xe5, 0x00, 0x30, 0x25, + 0x04, 0x34, 0x0a, 0xe7, 0xf3, 0xed, 0x07, 0x1d, 0x19, 0x18, 0xf4, 0x11, 0xe6, + 0x01, 0xe4, 0x3e, 0x44, 0xd8, 0xc3, 0x89, 0x05, 0xdb, 0xd0, 0x13, 0x1a, 0xe1, + 0xd0, 0xdf, 0x30, 0x21, 0xd5, 0xf5, 0xcf, 0x24, 0xea, 0xe7, 0x07, 0xd5, 0x15, + 0xfc, 0x18, 0x70, 0xea, 0x27, 0xf8, 0x12, 0x18, 0xe9, 0xb6, 0xeb, 0xeb, 0xdb, + 0x1d, 0xe0, 0x05, 0xc1, 0xef, 0xdc, 0xc3, 0x2c, 0x1d, 0x37, 0xeb, 0xf4, 0x6f, + 0xd8, 0xe9, 0x20, 0xf5, 0xff, 0x15, 0xbd, 0x2a, 0x0f, 0x02, 0xee, 0x02, 0x1a, + 0x4b, 0xeb, 0xd3, 0x03, 0xd0, 0xf0, 0xf3, 0x1b, 0xf3, 0x29, 0x10, 0x06, 0x72, + 0xf6, 0xfa, 0xec, 0xec, 0x30, 0xed, 0xff, 0x3e, 0xdb, 0x1b, 0x17, 0x32, 0xa2, + 0xee, 0x03, 0xe8, 0x7f, 0x1b, 0xdf, 0x5d, 0xea, 0xa0, 0x20, 0x2d, 0x15, 0x0e, + 0xdb, 0x0f, 0xf9, 0x0d, 0x1b, 0xe0, 0x55, 0xce, 0xd9, 0xc2, 0xa5, 0xb6, 0xfa, + 0xf0, 0xbb, 0xe6, 0xea, 0x5c, 0x31, 0x76, 0xa8, 0xc6, 0xd1, 0x47, 0xfa, 0x21, + 0xdd, 0x10, 0x0d, 0x35, 0xd2, 0xfe, 0xe4, 0xe4, 0xf4, 0xcc, 0x3d, 0x67, 0x0a, + 0x12, 0x4c, 0x2b, 0xfa, 0xc8, 0x58, 0xe9, 0x2e, 0xfe, 0x2b, 0xc7, 0x09, 0x5f, + 0x35, 0x34, 0x21, 0x14, 0xe7, 0x3e, 0x19, 0x00, 0x15, 0x6b, 0x21, 0x0c, 0xf8, + 0x5a, 0x27, 0x78, 0x0b, 0x45, 0xf8, 0x21, 0xe1, 0x2e, 0x2d, 0xd5, 0x19, 0xf8, + 0xcf, 0x5e, 0xfd, 0xe1, 0x36, 0x20, 0xcd, 0xef, 0xfa, 0x2a, 0xcf, 0x5d, 0x2a, + 0xda, 0xe5, 0xe1, 0xf5, 0xd9, 0xe1, 0xb5, 0x0e, 0x03, 0xb5, 0xe5, 0xea, 0xbb, + 0xeb, 0x06, 0xf9, 0xe7, 0x16, 0x0d, 0xfe, 0xbe, 0x23, 0xd5, 0x14, 0x1d, 0xf7, + 0xd5, 0xdf, 0xef, 0xec, 0xd4, 0x2d, 0xda, 0xce, 0x3c, 0x98, 0x24, 0x02, 0xfe, + 0xac, 0xd4, 0x53, 0x26, 0xcf, 0xfa, 0xd0, 0xeb, 0x5c, 0xcb, 0x19, 0xd2, 0x21, + 0xde, 0x18, 0x4f, 0xfd, 0x35, 0x16, 0xd7, 0x1e, 0x13, 0x92, 0x1d, 0x1f, 0x00, + 0x54, 0x24, 0x37, 0xf0, 0xd1, 0xe3, 0xba, 0xd5, 0x21, 0xd9, 0xf6, 0xfd, 0xb7, + 0x08, 0xb4, 0xd5, 0x43, 0xe3, 0x1e, 0x05, 0x56, 0xc5, 0x56, 0xd8, 0x3e, 0xef, + 0xe2, 0x08, 0xd4, 0xc5, 0xed, 0x13, 0x2e, 0x25, 0xd1, 0x20, 0xd4, 0xe0, 0xfd, + 0xfb, 0x81, 0xe7, 0xf0, 0xb2, 0xde, 0x00, 0xe5, 0xef, 0xec, 0xd1, 0x08, 0xee, + 0xed, 0xe1, 0x4e, 0xd2, 0xd2, 0xee, 0x25, 0x25, 0x39, 0x8f, 0x05, 0xfa, 0x52, + 0x0f, 0x27, 0x01, 0x07, 0x06, 0xc8, 0x81, 0x11, 0x2d, 0x17, 0xc3, 0xe2, 0x00, + 0x34, 0x6e, 0xf5, 0xe3, 0x36, 0x19, 0x2b, 0xed, 0xe9, 0xc5, 0x61, 0xdb, 0x16, + 0xe3, 0xfe, 0xfe, 0x0f, 0x5c, 0xe7, 0xd4, 0xe0, 0xdb, 0xe9, 0x3a, 0x04, 0xed, + 0xbe, 0xb6, 0x28, 0x25, 0x1a, 0x3e, 0x27, 0xb7, 0xc7, 0x11, 0xb2, 0x1d, 0xbc, + 0x1f, 0x5a, 0x03, 0xa7, 0xeb, 0x4c, 0x47, 0x38, 0x55, 0xf8, 0x0e, 0xff, 0xf8, + 0xc5, 0x19, 0xca, 0xe0, 0x34, 0xed, 0x20, 0x17, 0xc5, 0xc7, 0x09, 0x18, 0xd3, + 0x95, 0xdc, 0xb3, 0x0f, 0xf7, 0xf8, 0x78, 0xc3, 0x29, 0xeb, 0x16, 0xf0, 0x16, + 0x09, 0xf9, 0xe2, 0xdf, 0xe9, 0xa4, 0x15, 0x39, 0x25, 0xf1, 0xe6, 0xf6, 0x1a, + 0xc1, 0x12, 0xd6, 0xd0, 0x0c, 0xfa, 0x00, 0xe6, 0xe5, 0xd6, 0xb9, 0x29, 0x64, + 0x07, 0x10, 0xc9, 0x0c, 0x17, 0xfc, 0xf9, 0x3a, 0xe4, 0xc1, 0x15, 0xdb, 0x01, + 0xcd, 0x4f, 0xc8, 0xbf, 0xda, 0x2a, 0x28, 0x0c, 0x14, 0x0a, 0xbb, 0x15, 0xda, + 0xe8, 0x23, 0xfa, 0x36, 0xf4, 0xe7, 0xd1, 0xe1, 0x27, 0x05, 0x5e, 0x1c, 0x39, + 0x49, 0xf4, 0x0d, 0x12, 0x09, 0x37, 0xcc, 0xc2, 0xcc, 0xff, 0x5e, 0xce, 0xd1, + 0x32, 0x19, 0xf7, 0x02, 0xde, 0x27, 0x0d, 0xcb, 0xf9, 0xf1, 0x16, 0x0d, 0xf9, + 0x16, 0xfe, 0x7f, 0xf7, 0x0b, 0x7a, 0xc7, 0xdf, 0xbd, 0x01, 0x0e, 0x07, 0xe6, + 0xe7, 0x3d, 0x10, 0x04, 0xd3, 0xf7, 0x08, 0xd8, 0x29, 0x76, 0xca, 0xea, 0xf9, + 0x0a, 0x0a, 0x33, 0xe9, 0x15, 0x40, 0xce, 0xd7, 0x28, 0x12, 0xfe, 0xd8, 0xba, + 0xe6, 0x05, 0x3f, 0x43, 0x13, 0xce, 0xf3, 0x2a, 0x30, 0x23, 0x70, 0x1c, 0x11, + 0xca, 0xf1, 0x08, 0x21, 0x1b, 0x05, 0x9f, 0xcc, 0xe4, 0x24, 0xf9, 0x0e, 0x15, + 0x04, 0xfa, 0x0d, 0x17, 0x17, 0x26, 0xe5, 0xf9, 0xbd, 0xea, 0xf8, 0xe2, 0x10, + 0xe1, 0xf4, 0x39, 0xfd, 0x05, 0x0c, 0x10, 0x11, 0xd2, 0x27, 0xf2, 0xf3, 0x01, + 0x21, 0x0c, 0xdd, 0x24, 0x09, 0xf2, 0xf4, 0x02, 0x3f, 0x51, 0xfd, 0x1f, 0xfc, + 0x0f, 0xf3, 0x28, 0xf0, 0xfc, 0xd4, 0xcb, 0xee, 0x50, 0xd6, 0xff, 0x31, 0x22, + 0x06, 0x2a, 0xd5, 0x2b, 0x02, 0xee, 0xd3, 0x0f, 0xf7, 0x0c, 0xef, 0x7f, 0xdb, + 0x36, 0xec, 0xcf, 0x0e, 0xf0, 0x1a, 0xf5, 0x41, 0x2f, 0x10, 0xdd, 0x13, 0xe5, + 0xf5, 0x06, 0x2a, 0x02, 0x13, 0x00, 0x1a, 0x10, 0xea, 0x05, 0x13, 0x12, 0x15, + 0x08, 0x1e, 0x07, 0x2d, 0x5e, 0x2c, 0x14, 0x09, 0x4c, 0xe5, 0x31, 0xf1, 0xff, + 0x24, 0x33, 0xb9, 0x08, 0xfb, 0x03, 0x28, 0xf0, 0x08, 0x4f, 0xde, 0x18, 0xe2, + 0xea, 0x19, 0xf1, 0xfc, 0x33, 0x36, 0x2a, 0x04, 0xf8, 0x21, 0x3f, 0xd7, 0x0d, + 0xdf, 0xf4, 0x26, 0xe0, 0xfc, 0xf9, 0xe4, 0xff, 0x07, 0x00, 0xe1, 0x12, 0xfe, + 0x55, 0xd4, 0x51, 0x10, 0x1a, 0x4b, 0x0c, 0x26, 0xf9, 0xfe, 0x28, 0x05, 0x20, + 0xfe, 0x0e, 0xb8, 0xc2, 0x18, 0xe5, 0x19, 0x3a, 0xce, 0xf7, 0x06, 0x06, 0xb3, + 0xea, 0xfc, 0xf6, 0xf1, 0xe9, 0xfa, 0xf4, 0xe7, 0xd7, 0x1b, 0x10, 0xd9, 0x28, + 0xc7, 0xfe, 0xfa, 0x20, 0x23, 0x03, 0x0c, 0xfc, 0xdc, 0xf2, 0xe0, 0xf0, 0xf0, + 0x15, 0x3e, 0xb7, 0xd5, 0x04, 0xf6, 0x7f, 0x14, 0xdb, 0xef, 0x56, 0xe2, 0x07, + 0x29, 0x06, 0x0d, 0xe7, 0x13, 0x43, 0xef, 0xee, 0xf6, 0x26, 0xec, 0xfb, 0xdf, + 0xb5, 0x08, 0x1c, 0xde, 0x07, 0x37, 0xe0, 0xa4, 0x1a, 0x17, 0xe7, 0x20, 0xdf, + 0xce, 0x07, 0x1e, 0x4a, 0x00, 0xf9, 0x0e, 0xb7, 0x1d, 0xf5, 0xe8, 0xd7, 0x3e, + 0xc0, 0xd6, 0xf7, 0x01, 0x25, 0x0d, 0xec, 0x05, 0x13, 0x0d, 0xf4, 0xa2, 0x14, + 0x26, 0xe8, 0x22, 0xcd, 0x15, 0x1d, 0xe2, 0xf1, 0x3e, 0xf5, 0x05, 0xfa, 0xc4, + 0x11, 0x30, 0x32, 0xd7, 0xd4, 0x04, 0x12, 0x0d, 0x48, 0xe3, 0xa7, 0x07, 0xf0, + 0x87, 0x7a, 0xe9, 0x60, 0x5b, 0x00, 0xcb, 0xd4, 0xb6, 0x9d, 0x4a, 0x51, 0xf4, + 0xd5, 0xc5, 0xe2, 0x7f, 0xf6, 0x33, 0xc8, 0x6b, 0x06, 0x37, 0xdc, 0xdf, 0x26, + 0x0a, 0x50, 0x00, 0x1c, 0x3f, 0xc1, 0x0d, 0x33, 0xd7, 0x1f, 0x90, 0xf9, 0xf3, + 0xe7, 0x15, 0xac, 0xe6, 0x11, 0x12, 0xfe, 0x26, 0x22, 0x22, 0x63, 0xf8, 0xa5, + 0x4d, 0xeb, 0xc5, 0x54, 0x34, 0xc2, 0xec, 0x33, 0x33, 0x65, 0x0d, 0x3a, 0x4e, + 0x1a, 0x05, 0xcf, 0x11, 0x1c, 0xbf, 0x46, 0x6a, 0xe1, 0xfc, 0x34, 0x89, 0x42, + 0x2a, 0xea, 0xc4, 0xdb, 0xcc, 0x40, 0xe7, 0xf7, 0xf2, 0x92, 0xdc, 0x0d, 0x55, + 0x0e, 0x0a, 0xfc, 0x14, 0x06, 0xf5, 0x1a, 0xb6, 0x0e, 0xd1, 0x53, 0xdb, 0x36, + 0x12, 0x16, 0x08, 0xd4, 0x16, 0x0f, 0x33, 0xef, 0xc4, 0x4b, 0xb1, 0x1e, 0xf6, + 0xe5, 0x47, 0x0a, 0xfe, 0xc4, 0xfd, 0x04, 0x35, 0xfc, 0x15, 0x2b, 0xe2, 0x23, + 0x0c, 0x2a, 0x17, 0x7f, 0xc5, 0xe2, 0xb6, 0xb3, 0x23, 0xf3, 0xd0, 0xac, 0xe5, + 0xd0, 0xc5, 0xf7, 0xe2, 0xf4, 0x06, 0x1b, 0x0d, 0x1e, 0xe8, 0x10, 0x0b, 0xe8, + 0x1d, 0xe3, 0xdd, 0xc0, 0xe2, 0x15, 0xc7, 0x3f, 0xe9, 0xf5, 0xca, 0x0b, 0xf1, + 0x5e, 0x4c, 0x6e, 0xf3, 0xce, 0xde, 0xf9, 0xec, 0x33, 0xe8, 0xf3, 0x13, 0xe1, + 0x1a, 0xf5, 0x08, 0xf3, 0x1b, 0x3c, 0x1e, 0xf0, 0xd7, 0x18, 0xfe, 0x2e, 0x24, + 0xff, 0x08, 0x3f, 0xa6, 0x36, 0x31, 0xe0, 0x12, 0x0d, 0xd1, 0x49, 0xeb, 0x6e, + 0xdb, 0x3e, 0xea, 0x08, 0xe0, 0xc0, 0x19, 0xd8, 0x04, 0xcc, 0xd9, 0x02, 0xff, + 0x0d, 0x31, 0x00, 0xcb, 0x0e, 0xed, 0x57, 0x1d, 0xe0, 0xdb, 0x6a, 0xf0, 0xf3, + 0xee, 0xbd, 0xc2, 0x27, 0x06, 0xe4, 0xf0, 0x15, 0xcb, 0x09, 0xdf, 0x10, 0xe4, + 0xdf, 0xbb, 0xe2, 0x1b, 0x1b, 0x19, 0x14, 0xb6, 0x1a, 0x95, 0x50, 0xdf, 0x32, + 0xfd, 0xd6, 0x20, 0x1e, 0x00, 0x20, 0x14, 0x3f, 0x3d, 0x38, 0x09, 0x10, 0x31, + 0x28, 0x0f, 0xeb, 0xfb, 0xda, 0xd2, 0x0c, 0xe7, 0x31, 0xe8, 0x0f, 0x1e, 0xdb, + 0x30, 0x27, 0xa2, 0x00, 0x03, 0xfe, 0x01, 0x08, 0xe7, 0x89, 0xdd, 0x9b, 0x7f, + 0x0b, 0x01, 0xf1, 0xea, 0xf5, 0xdc, 0xae, 0xf5, 0x28, 0x02, 0x42, 0xfb, 0x53, + 0xea, 0x25, 0x13, 0x18, 0xfc, 0x19, 0x10, 0x3a, 0xe5, 0x04, 0xe5, 0xf4, 0x0b, + 0xf8, 0xfa, 0xff, 0x29, 0x3e, 0x0b, 0x15, 0x00, 0x26, 0xfb, 0x2f, 0x08, 0x2c, + 0xc9, 0x12, 0xda, 0xe2, 0x1f, 0xe1, 0x2c, 0x4f, 0x69, 0x13, 0x07, 0xcb, 0xd6, + 0xe6, 0x1c, 0xf7, 0x15, 0x04, 0x19, 0xd8, 0x06, 0x24, 0x03, 0x04, 0x0b, 0xe3, + 0xf8, 0x1b, 0xce, 0xeb, 0x01, 0x05, 0xf9, 0x05, 0xff, 0xdd, 0xe9, 0x16, 0x1f, + 0x0b, 0x0f, 0xed, 0xd8, 0x32, 0x27, 0xda, 0xe4, 0x2a, 0xfb, 0xd1, 0xed, 0x07, + 0xd9, 0xfd, 0x13, 0xe9, 0x11, 0x0d, 0xd3, 0xf9, 0x11, 0xf8, 0xfa, 0xc4, 0xe6, + 0xe5, 0x0c, 0xd8, 0xed, 0x10, 0xcf, 0xf9, 0xd9, 0x50, 0x0b, 0x18, 0xf8, 0xe2, + 0xf5, 0xe9, 0xee, 0xea, 0xe3, 0x10, 0x2f, 0xd5, 0xf4, 0xe5, 0xdf, 0xd3, 0xde, + 0x22, 0x09, 0xf2, 0x02, 0xe1, 0xfc, 0xf2, 0xe3, 0xb7, 0x25, 0x05, 0x22, 0xd0, + 0x1d, 0x10, 0x39, 0xf4, 0xf8, 0xd2, 0x09, 0x20, 0x7f, 0xe8, 0x1a, 0x13, 0x0c, + 0x11, 0xf6, 0x10, 0xe9, 0xf0, 0x17, 0x33, 0xd2, 0xf7, 0xde, 0x0a, 0xe3, 0xd6, + 0xf8, 0x12, 0x00, 0xb4, 0x05, 0xe0, 0x00, 0x1a, 0xef, 0xdc, 0xd0, 0x11, 0xe0, + 0x41, 0xdf, 0x06, 0x13, 0x15, 0x1e, 0xe8, 0xc2, 0xc0, 0xe7, 0x16, 0x19, 0xed, + 0x50, 0xd5, 0xe2, 0x04, 0xcb, 0x17, 0x04, 0x0c, 0xa6, 0xa6, 0x06, 0xee, 0x33, + 0x1a, 0x44, 0x30, 0x12, 0xda, 0x39, 0x15, 0x9a, 0xea, 0x22, 0x1a, 0xc8, 0x21, + 0xd2, 0xcb, 0x37, 0xcb, 0x04, 0xe6, 0x48, 0x03, 0x28, 0x13, 0x0a, 0xf4, 0xdd, + 0xea, 0xd8, 0xed, 0x99, 0xfa, 0xb7, 0xce, 0xec, 0x26, 0xfb, 0x2e, 0x23, 0x3e, + 0xfa, 0x9e, 0xb7, 0xc7, 0x3d, 0x36, 0xdc, 0xf3, 0x32, 0x33, 0xe3, 0xf3, 0xe4, + 0xfd, 0x0e, 0xef, 0xef, 0xc8, 0xe1, 0xeb, 0x52, 0x11, 0xd7, 0xf2, 0xd3, 0x30, + 0xec, 0x53, 0xe4, 0xe8, 0x7f, 0x01, 0xf3, 0x28, 0xdb, 0x45, 0x2c, 0xf7, 0x33, + 0x0b, 0x20, 0x00, 0x5d, 0xf6, 0x25, 0xd4, 0x04, 0xf7, 0x1b, 0x1a, 0x03, 0x14, + 0xb8, 0x10, 0xdd, 0xe9, 0x31, 0x3c, 0xd5, 0x01, 0xfb, 0xfd, 0xd2, 0xd7, 0x37, + 0xdf, 0x0a, 0x40, 0x1f, 0xe5, 0xd8, 0xd7, 0x9f, 0xcd, 0xe6, 0x1f, 0x02, 0xf9, + 0xe2, 0x7b, 0x2f, 0x2f, 0x22, 0x03, 0xf1, 0xfc, 0x19, 0xd5, 0x41, 0x03, 0x4d, + 0xf7, 0xd1, 0x19, 0x30, 0x04, 0xae, 0x25, 0x59, 0x7f, 0xc4, 0x09, 0x28, 0x31, + 0x0b, 0x24, 0xb8, 0x6e, 0xbd, 0xe7, 0x33, 0xd4, 0xfa, 0xda, 0x1e, 0xe3, 0xe6, + 0x2a, 0xb5, 0x2d, 0x1f, 0xf8, 0xbc, 0x48, 0x09, 0x2e, 0xfe, 0x4a, 0x24, 0x13, + 0xd1, 0xde, 0x52, 0xb8, 0x34, 0x9f, 0x12, 0xd2, 0xd5, 0xf5, 0xd6, 0x03, 0x14, + 0x1f, 0x11, 0x15, 0x47, 0x71, 0x13, 0x02, 0xde, 0xdc, 0xd9, 0x01, 0x64, 0x51, + 0x04, 0xb0, 0x1d, 0x22, 0x03, 0xc7, 0xbc, 0x24, 0xc1, 0xca, 0x0d, 0x04, 0x41, + 0x1c, 0x3b, 0xcc, 0x11, 0xdd, 0x0b, 0xe8, 0x34, 0x30, 0xf9, 0xf1, 0x30, 0xba, + 0xde, 0x94, 0x07, 0x4a, 0x30, 0x4d, 0x20, 0x13, 0x04, 0xf5, 0xda, 0xf1, 0xe4, + 0xfe, 0x24, 0x43, 0xf2, 0xfc, 0x0a, 0xd3, 0x1b, 0x14, 0x0f, 0xd6, 0xf4, 0xfa, + 0xf4, 0x15, 0xed, 0x41, 0x37, 0xdc, 0xe3, 0xe6, 0xe9, 0x0d, 0xff, 0x11, 0xcc, + 0x1b, 0x66, 0x44, 0x9e, 0x27, 0x1a, 0x33, 0xf7, 0x18, 0xc2, 0xdf, 0xea, 0x28, + 0x0f, 0xf5, 0x02, 0x06, 0x1c, 0xe7, 0x09, 0xf2, 0x35, 0xf1, 0x05, 0x1d, 0x9d, + 0x3a, 0x03, 0x1c, 0x41, 0xd4, 0xfb, 0x56, 0x12, 0x1d, 0x15, 0xf6, 0x09, 0x0e, + 0xe4, 0xee, 0x05, 0x0c, 0xb3, 0xee, 0xc9, 0xea, 0xe2, 0x41, 0xe0, 0xdb, 0x19, + 0x35, 0xf7, 0x6b, 0x2f, 0xdf, 0xc2, 0xff, 0x03, 0xeb, 0xf2, 0x3e, 0x19, 0xcf, + 0x32, 0xfa, 0xb8, 0x2f, 0x04, 0x25, 0xca, 0x1f, 0x09, 0x68, 0x3e, 0x13, 0x07, + 0xdc, 0x07, 0x01, 0xe4, 0x1b, 0x7f, 0x38, 0xf5, 0xff, 0xf8, 0xe0, 0xf3, 0x05, + 0x04, 0xdb, 0xdf, 0x33, 0x31, 0x1d, 0xf6, 0x1e, 0xe2, 0x0b, 0x10, 0xf9, 0x0a, + 0x0d, 0xaf, 0xdb, 0xe6, 0xde, 0x10, 0x04, 0x11, 0xb5, 0xd3, 0x37, 0xd0, 0xe7, + 0x0f, 0x16, 0xd5, 0xd1, 0x13, 0xd0, 0x1e, 0x18, 0x3b, 0xda, 0x01, 0x35, 0x1c, + 0xe7, 0xba, 0xfd, 0xe3, 0x2d, 0x8e, 0x18, 0x3c, 0xf1, 0x05, 0x29, 0x05, 0x30, + 0xa6, 0xd5, 0x09, 0xf0, 0x7f, 0xe2, 0xe0, 0xdf, 0xe6, 0xd6, 0xef, 0x0d, 0xb9, + 0x16, 0x3f, 0x06, 0x0c, 0x2a, 0xdf, 0x2f, 0x16, 0xeb, 0xe8, 0xbf, 0x6e, 0xf2, + 0xe8, 0xc9, 0x7c, 0x30, 0xf4, 0xdd, 0xef, 0xeb, 0xd2, 0xbb, 0x1e, 0x01, 0x01, + 0x3c, 0xdf, 0xe1, 0xff, 0xc1, 0x28, 0xde, 0x07, 0x2b, 0x0a, 0x14, 0xb9, 0x13, + 0xcc, 0x23, 0xfe, 0x57, 0xfb, 0xbb, 0xed, 0x05, 0x20, 0x36, 0xc1, 0x52, 0xf7, + 0xb6, 0x59, 0x0e, 0xf0, 0xe8, 0xe1, 0xf9, 0xee, 0xf6, 0x30, 0x07, 0x0a, 0x52, + 0x3d, 0xf4, 0xe8, 0xe0, 0x06, 0xdb, 0xe8, 0x0a, 0x45, 0x18, 0x2d, 0xd2, 0xb4, + 0xef, 0xc7, 0xb6, 0xe9, 0xc8, 0x5f, 0x0d, 0xc9, 0x05, 0xef, 0x4a, 0xd9, 0xb1, + 0x32, 0x0d, 0x44, 0x18, 0x90, 0x0a, 0x1f, 0xf4, 0xe8, 0xf2, 0x86, 0xec, 0x66, + 0x19, 0x1e, 0x04, 0x6f, 0xb0, 0xda, 0x1f, 0x07, 0x00, 0xde, 0x41, 0xc9, 0xeb, + 0x41, 0xeb, 0x14, 0xa1, 0x0a, 0xec, 0xb1, 0x62, 0xae, 0x0d, 0x9b, 0xd7, 0x14, + 0xeb, 0x0e, 0x13, 0xff, 0x47, 0xcc, 0xfc, 0x49, 0xca, 0x58, 0xc2, 0x26, 0xb8, + 0x1d, 0x45, 0xa7, 0xec, 0xe5, 0x33, 0x0f, 0x01, 0xc7, 0x06, 0xca, 0xf3, 0xd3, + 0x2a, 0xfc, 0xda, 0x0c, 0x05, 0xc4, 0x03, 0xda, 0x44, 0xd1, 0xed, 0xd8, 0x2a, + 0x0f, 0x2e, 0x19, 0xf1, 0x06, 0x2f, 0xee, 0xcd, 0xe9, 0xda, 0x30, 0x03, 0x19, + 0x04, 0x62, 0xf6, 0x19, 0xdc, 0xe5, 0x61, 0xb4, 0xef, 0xf6, 0x81, 0xa6, 0xdb, + 0x59, 0xdf, 0xf1, 0x00, 0xdb, 0x08, 0xf0, 0x2c, 0xc7, 0xef, 0xc0, 0xe0, 0xe5, + 0x0a, 0x01, 0x2b, 0x2d, 0x09, 0xff, 0x82, 0xf4, 0xe0, 0xf0, 0xd0, 0xd2, 0x59, + 0x7d, 0x20, 0xc5, 0x34, 0xa9, 0x3f, 0x4b, 0xd5, 0x02, 0xe3, 0x1a, 0xf0, 0xbb, + 0xe6, 0xd9, 0xe7, 0xfa, 0x0f, 0x35, 0xef, 0xd7, 0xdb, 0x06, 0x40, 0xf0, 0xa9, + 0xff, 0xf0, 0x22, 0x37, 0xfe, 0xe7, 0x25, 0xa3, 0x34, 0xd4, 0x2d, 0xdf, 0x14, + 0x90, 0x29, 0x2a, 0x1c, 0xc5, 0x3f, 0xd3, 0xdc, 0x06, 0x0c, 0xb6, 0x7f, 0x69, + 0x52, 0x10, 0xca, 0x10, 0x27, 0xc2, 0xc1, 0xdc, 0xc1, 0x02, 0xe8, 0x21, 0xff, + 0xf6, 0x15, 0x17, 0xf7, 0xcb, 0x1f, 0x14, 0xa2, 0xe3, 0xcc, 0x5a, 0x0e, 0x46, + 0x10, 0xcd, 0x00, 0x12, 0xd5, 0x0e, 0xf4, 0xc9, 0x28, 0xc3, 0xb8, 0xf0, 0x01, + 0xb4, 0xf4, 0x1d, 0x8a, 0x33, 0x1a, 0xde, 0xdb, 0x37, 0x11, 0xf1, 0x1a, 0x14, + 0xfd, 0x4f, 0xd4, 0xc2, 0x09, 0xed, 0x3a, 0xf8, 0xb3, 0xc3, 0xec, 0x34, 0x05, + 0xe0, 0x35, 0x11, 0xd6, 0x08, 0xe8, 0xc4, 0x2b, 0x22, 0xf6, 0xf8, 0x02, 0x24, + 0x19, 0x46, 0xde, 0xaf, 0x34, 0xff, 0x04, 0xe7, 0x11, 0x16, 0xe5, 0xbd, 0xe5, + 0x1a, 0x1a, 0xf9, 0xe1, 0x16, 0x16, 0x5d, 0xf1, 0xbe, 0x32, 0xd7, 0x05, 0x01, + 0xd5, 0xee, 0xd2, 0x39, 0xd2, 0x1a, 0xe3, 0xea, 0x57, 0x6a, 0x31, 0xa5, 0xe4, + 0xc9, 0xf8, 0x05, 0xa4, 0xc8, 0x25, 0xde, 0xaf, 0x13, 0x7f, 0x16, 0xb7, 0xb2, + 0xfa, 0x32, 0xe2, 0x4e, 0x11, 0xa5, 0x3b, 0x06, 0xee, 0x42, 0xd8, 0x3a, 0xfd, + 0xc6, 0x1f, 0x50, 0x11, 0xf8, 0x30, 0xf6, 0xeb, 0xfd, 0xf4, 0xfa, 0xf7, 0x38, + 0x0b, 0x3a, 0x34, 0x47, 0xf8, 0x25, 0xfc, 0xe4, 0x19, 0x35, 0x2e, 0xd2, 0xcb, + 0xd5, 0xe8, 0x24, 0xcb, 0x05, 0x21, 0x12, 0xf2, 0xfb, 0x1e, 0x34, 0xed, 0xfe, + 0xf6, 0x39, 0xde, 0x27, 0x0a, 0x28, 0x1a, 0x21, 0x0b, 0x11, 0x00, 0xf5, 0xf7, + 0x02, 0x35, 0x0f, 0xe0, 0x1f, 0xe5, 0xd9, 0x70, 0x2e, 0x08, 0xd6, 0x3a, 0x1f, + 0xda, 0x0f, 0x0a, 0xf0, 0xdb, 0xe3, 0x01, 0xe6, 0xe2, 0xdb, 0xec, 0xf5, 0xf6, + 0x0a, 0x8e, 0xd8, 0xf7, 0xb1, 0xef, 0x26, 0x0a, 0x1a, 0x19, 0xc2, 0x09, 0xe1, + 0xe4, 0x44, 0xdc, 0x35, 0x19, 0x16, 0xea, 0xb9, 0x27, 0x05, 0x24, 0x25, 0xda, + 0xfa, 0xe7, 0x0e, 0x0c, 0xfc, 0x42, 0xa9, 0xd8, 0x1c, 0x23, 0x4a, 0x4c, 0xf8, + 0x40, 0x11, 0xf4, 0x26, 0xf2, 0xeb, 0xca, 0x0b, 0xe7, 0xfc, 0x2a, 0xd2, 0x08, + 0xd0, 0xf5, 0xb8, 0xf9, 0x61, 0x0e, 0xf6, 0xdc, 0xe4, 0xdb, 0xd5, 0xfd, 0xb2, + 0x07, 0x0f, 0xc0, 0x81, 0x00, 0x22, 0xfe, 0xdb, 0x0c, 0xc6, 0xff, 0x15, 0x20, + 0xfa, 0xbc, 0xd2, 0xc6, 0xb9, 0xf6, 0xf2, 0xfa, 0x19, 0x28, 0xef, 0x32, 0xe3, + 0xec, 0x28, 0x1a, 0x59, 0xc9, 0xf8, 0x08, 0xc6, 0x20, 0xf3, 0x22, 0xcd, 0xbe, + 0x20, 0x29, 0xd4, 0x0f, 0x30, 0x36, 0xc2, 0x1f, 0x0e, 0xdc, 0x4f, 0xf9, 0x03, + 0xd6, 0x1c, 0x42, 0xed, 0xee, 0x15, 0x24, 0x33, 0xe7, 0x61, 0x05, 0xc8, 0x0d, + 0x3c, 0xc8, 0x00, 0xdd, 0xe1, 0x15, 0x4e, 0x22, 0xfe, 0x2d, 0x04, 0x00, 0x44, + 0xc3, 0xee, 0x17, 0xf8, 0x36, 0xee, 0x2c, 0x3c, 0xec, 0x7f, 0x04, 0x18, 0xc6, + 0xc3, 0x1f, 0xd6, 0x1f, 0xcb, 0xfe, 0x26, 0xeb, 0x09, 0x4a, 0x33, 0x15, 0x41, + 0x27, 0x05, 0x18, 0x5d, 0x06, 0xf7, 0xf9, 0x04, 0xd5, 0xf3, 0xff, 0x2d, 0xea, + 0xd7, 0x5c, 0x1c, 0xcb, 0x1c, 0x1d, 0x0d, 0xd6, 0x42, 0x15, 0x6f, 0x6f, 0x27, + 0xdf, 0x02, 0x1b, 0x03, 0x21, 0x2d, 0x43, 0x0a, 0x14, 0xf5, 0xe8, 0xef, 0x49, + 0x10, 0x1e, 0x1e, 0xf6, 0x52, 0x33, 0xfe, 0x21, 0x23, 0xd3, 0xed, 0xd6, 0x15, + 0xed, 0xdb, 0x27, 0x02, 0xb8, 0x30, 0x2c, 0xf7, 0xe4, 0xf4, 0x35, 0xc2, 0xbf, + 0xd7, 0xdd, 0xf9, 0x42, 0xfe, 0xd7, 0x20, 0xd8, 0x7f, 0xf7, 0xc2, 0x2b, 0x28, + 0xee, 0x00, 0xce, 0x09, 0xe3, 0x23, 0x23, 0xc9, 0x13, 0xf7, 0x14, 0xe7, 0xd4, + 0xf8, 0xf3, 0x22, 0xf3, 0xf4, 0x07, 0xa1, 0xf4, 0xbb, 0x03, 0xb3, 0x29, 0x17, + 0x20, 0xff, 0xe8, 0x05, 0x56, 0x72, 0x2a, 0x3b, 0x3c, 0xf6, 0x03, 0x27, 0xb6, + 0xf5, 0x15, 0xdc, 0x7f, 0x56, 0x0c, 0xd7, 0xed, 0x76, 0xb2, 0x15, 0x49, 0xf5, + 0x03, 0xde, 0xd6, 0x09, 0xc6, 0xe2, 0x28, 0x32, 0xe1, 0x29, 0x53, 0xfe, 0x34, + 0xf8, 0xe5, 0x05, 0x29, 0x09, 0xed, 0x51, 0x0a, 0x33, 0xf6, 0xf1, 0xfa, 0x0c, + 0xf4, 0x24, 0xad, 0x42, 0xe0, 0xa7, 0xfc, 0xc9, 0xad, 0x04, 0xeb, 0x31, 0x22, + 0xdd, 0x14, 0xf7, 0x0b, 0x9e, 0x0d, 0xd2, 0xee, 0xdd, 0xfb, 0x03, 0xca, 0x0a, + 0x0c, 0xdf, 0xd8, 0x16, 0xf3, 0xcb, 0x5a, 0x38, 0xe7, 0xd9, 0xee, 0xd6, 0x01, + 0x0c, 0xc4, 0x5d, 0xfd, 0xe7, 0xee, 0x0a, 0xf7, 0x25, 0x5d, 0x0b, 0xd9, 0x10, + 0xda, 0xd4, 0xfb, 0xc3, 0x06, 0x2f, 0x1f, 0x20, 0xe1, 0x09, 0xf6, 0x19, 0x0a, + 0x2c, 0xda, 0xa2, 0xec, 0xda, 0x21, 0x0f, 0x25, 0xc3, 0xf3, 0xeb, 0x40, 0xe5, + 0x01, 0xe9, 0x04, 0xf8, 0x05, 0xcf, 0xe4, 0x51, 0x35, 0x0c, 0xea, 0xe3, 0xc0, + 0xdc, 0xd6, 0xec, 0x64, 0x38, 0x7f, 0xd3, 0x5f, 0xde, 0x08, 0xe7, 0x2e, 0xfe, + 0xec, 0xd5, 0xeb, 0x33, 0xe0, 0xcf, 0x19, 0xde, 0x36, 0xf4, 0xe8, 0x19, 0xdb, + 0xee, 0xf3, 0xf4, 0x27, 0x22, 0x12, 0xf4, 0xd8, 0xe3, 0xd0, 0xe2, 0x14, 0x3e, + 0xfa, 0xed, 0xeb, 0x03, 0xfb, 0x49, 0x0a, 0x31, 0xec, 0x22, 0xe4, 0x8e, 0xf7, + 0xed, 0xd5, 0xf2, 0x09, 0xe0, 0x0f, 0xea, 0xa8, 0xec, 0x3a, 0x11, 0xd7, 0xc9, + 0x14, 0x93, 0x17, 0xff, 0x01, 0xeb, 0x0e, 0x02, 0xe8, 0x6a, 0xe1, 0x3d, 0x3a, + 0xb7, 0xd2, 0xdd, 0x18, 0x3f, 0xf2, 0x4a, 0xc6, 0x08, 0x7f, 0x56, 0xe5, 0xe5, + 0x36, 0xe7, 0xee, 0xe4, 0xa1, 0x95, 0xb0, 0x47, 0x04, 0x19, 0xfd, 0xdd, 0x28, + 0xd6, 0x4a, 0xd1, 0x04, 0xcf, 0xbd, 0xf1, 0x9b, 0xfc, 0xe5, 0x2a, 0x2c, 0x29, + 0xfc, 0xcd, 0x2a, 0xb3, 0x0a, 0xe9, 0x0f, 0x94, 0x6d, 0x20, 0x2b, 0xff, 0xc3, + 0xe9, 0x12, 0xb3, 0xa6, 0x5a, 0xbf, 0xfb, 0x14, 0x36, 0x2a, 0x05, 0x3b, 0x51, + 0x0f, 0xf9, 0xc7, 0xdd, 0xdb, 0x30, 0x9d, 0xbc, 0x2f, 0x07, 0x0b, 0x28, 0x1a, + 0xb4, 0xbd, 0x1c, 0x0a, 0x5c, 0x32, 0xe0, 0xee, 0x1a, 0x15, 0x22, 0x13, 0x03, + 0x1d, 0xfb, 0x02, 0x6c, 0xcb, 0x01, 0x62, 0xc2, 0x1f, 0x4d, 0x19, 0x3d, 0x31, + 0xf5, 0x04, 0xee, 0xf9, 0x45, 0x38, 0x05, 0x08, 0xe9, 0xdd, 0x2a, 0xe4, 0xc3, + 0xfc, 0x13, 0x02, 0xe5, 0x30, 0xf0, 0x12, 0xe9, 0x4a, 0xda, 0x21, 0x29, 0x30, + 0x2e, 0xc0, 0x36, 0x05, 0xe0, 0xaa, 0xda, 0x10, 0xd2, 0x32, 0xeb, 0xf3, 0xf0, + 0x7f, 0x22, 0x36, 0x08, 0xec, 0x9b, 0xb6, 0xdb, 0xe1, 0xfe, 0x07, 0xd7, 0xf2, + 0xb3, 0x0e, 0x1e, 0xec, 0x25, 0x32, 0x1d, 0x2d, 0x11, 0x1e, 0xe1, 0x69, 0x35, + 0x23, 0x51, 0x00, 0xf1, 0x64, 0xfd, 0xba, 0x51, 0xdb, 0xfb, 0xcb, 0xfa, 0x4f, + 0x01, 0x22, 0x37, 0x3c, 0x2d, 0x47, 0xc9, 0xe4, 0x0e, 0x0a, 0xc2, 0x6b, 0xa4, + 0x01, 0xbd, 0xe4, 0xd4, 0xde, 0x60, 0x0e, 0x00, 0xc6, 0x39, 0x06, 0xed, 0xf3, + 0xcf, 0xfb, 0x3a, 0xf4, 0xdd, 0xf4, 0xd5, 0x22, 0x2f, 0x10, 0x57, 0x25, 0x09, + 0xdc, 0x37, 0xb7, 0x09, 0xf5, 0x18, 0xfe, 0x28, 0x27, 0x10, 0x49, 0x18, 0xde, + 0x08, 0xd3, 0x1b, 0x1d, 0xee, 0xc6, 0x55, 0xde, 0xd0, 0xf1, 0xff, 0xeb, 0x18, + 0x79, 0xfd, 0xbf, 0xf3, 0x05, 0x09, 0x1e, 0x24, 0xec, 0xc7, 0xe5, 0xfe, 0x0c, + 0x25, 0x3a, 0x7f, 0xf9, 0x0a, 0xd2, 0x3a, 0xc1, 0x01, 0x50, 0x05, 0xe9, 0x37, + 0x20, 0xfc, 0xe7, 0x1b, 0xf8, 0xeb, 0xdc, 0x13, 0xec, 0x1e, 0x0f, 0xef, 0x29, + 0xe7, 0xbf, 0x03, 0xda, 0x02, 0xdf, 0xea, 0x10, 0xe9, 0xfa, 0x77, 0xed, 0x47, + 0xe2, 0x1d, 0x1d, 0x0c, 0x66, 0xe4, 0xca, 0xc0, 0x1d, 0x6f, 0xfa, 0xeb, 0x0f, + 0xb3, 0xfb, 0xec, 0xff, 0x04, 0xd4, 0xe1, 0x08, 0x34, 0xc3, 0xe3, 0xe2, 0x03, + 0xde, 0x0c, 0xeb, 0xfb, 0x1a, 0x12, 0xe6, 0xdc, 0x19, 0x31, 0xfe, 0xe0, 0x16, + 0x4d, 0x32, 0x51, 0xe7, 0xdf, 0x13, 0xcf, 0x41, 0xf9, 0x4b, 0x28, 0xf9, 0xea, + 0xe9, 0xbd, 0x15, 0xcc, 0x28, 0x18, 0xef, 0xba, 0xdf, 0x26, 0x2c, 0x1b, 0xde, + 0x09, 0xeb, 0xe9, 0x0d, 0xb4, 0x6e, 0xcc, 0x43, 0x1a, 0x2b, 0xf1, 0xf9, 0x3c, + 0xe5, 0x30, 0x28, 0x05, 0xd8, 0x3e, 0x45, 0x17, 0xe2, 0xde, 0x1f, 0x2e, 0x30, + 0x34, 0xcc, 0xb2, 0xda, 0xd8, 0xf7, 0xe0, 0x0f, 0xf4, 0x94, 0x03, 0xc4, 0xcf, + 0x46, 0x3f, 0x18, 0xd8, 0x7f, 0x29, 0x0a, 0xa1, 0x27, 0x48, 0xfa, 0xe3, 0xf4, + 0xbe, 0xcf, 0x29, 0x0a, 0xf5, 0xf7, 0x39, 0x00, 0xc7, 0x47, 0x08, 0xeb, 0xa8, + 0xb7, 0xc6, 0x07, 0xf2, 0xf3, 0x37, 0x53, 0x4b, 0x0c, 0x19, 0xc4, 0xff, 0xe3, + 0x2a, 0x18, 0x17, 0x12, 0x9a, 0x25, 0x06, 0x21, 0x3e, 0xd0, 0xb5, 0x11, 0x0d, + 0x0b, 0x8e, 0x51, 0xdc, 0xed, 0x9f, 0x13, 0xa6, 0x25, 0x23, 0x07, 0xf5, 0xcc, + 0xf9, 0xf0, 0x76, 0x08, 0xd0, 0xe5, 0x0d, 0xf0, 0xf2, 0xd7, 0xeb, 0x74, 0xe0, + 0x29, 0xd7, 0xdb, 0xcb, 0xc1, 0x2a, 0xb6, 0x12, 0xd7, 0x17, 0x2e, 0x3a, 0x38, + 0xd9, 0x34, 0xe3, 0x11, 0x19, 0x03, 0x05, 0x1f, 0xd5, 0xe4, 0x4a, 0x24, 0xdf, + 0x16, 0xf2, 0x21, 0x08, 0xcd, 0x2c, 0xdb, 0x21, 0xbd, 0x3a, 0xf7, 0xf9, 0xba, + 0xfb, 0x8a, 0x88, 0x23, 0xd3, 0xc6, 0xcd, 0x34, 0xd8, 0x0c, 0xed, 0xc3, 0xee, + 0x1b, 0xbe, 0xf2, 0x40, 0xe0, 0xc3, 0x03, 0x1b, 0xe9, 0x36, 0x02, 0xf1, 0xf5, + 0xb3, 0x31, 0x2f, 0xf7, 0xdf, 0xf4, 0x6c, 0x0d, 0x81, 0xf8, 0x15, 0x0e, 0x10, + 0xf7, 0x45, 0xc4, 0xdf, 0xb6, 0xdf, 0x34, 0x02, 0xe5, 0xff, 0xfd, 0xfe, 0x19, + 0xfa, 0x15, 0xe7, 0x27, 0xfb, 0x6d, 0xcd, 0xea, 0xa7, 0x07, 0x85, 0x37, 0x07, + 0xd7, 0xf5, 0x07, 0xf5, 0xee, 0xc8, 0x37, 0xd1, 0xd7, 0x03, 0xe5, 0xe8, 0x11, + 0xf7, 0x3c, 0xe4, 0x29, 0x40, 0x20, 0xd6, 0x07, 0xaf, 0x35, 0xb7, 0xe6, 0xeb, + 0x2e, 0x2d, 0x0b, 0xfd, 0xf2, 0xeb, 0xe8, 0xf0, 0x4d, 0xf8, 0x28, 0xf8, 0xf1, + 0xf2, 0x0e, 0xd8, 0x18, 0xf7, 0xe9, 0x0b, 0xdb, 0x29, 0xf7, 0xed, 0xfb, 0x0e, + 0x5b, 0x10, 0xd6, 0x45, 0xf3, 0xae, 0xd6, 0xdc, 0x3a, 0x3c, 0xbc, 0xed, 0xb7, + 0xed, 0x1e, 0xe7, 0xe6, 0x05, 0x1a, 0x04, 0x20, 0xe4, 0xdd, 0xd8, 0xfb, 0x00, + 0xe1, 0xfb, 0xe4, 0xdc, 0x04, 0xc3, 0xf6, 0x37, 0x14, 0x02, 0x26, 0xe7, 0xe3, + 0xe8, 0xbd, 0xea, 0x23, 0xbe, 0x0e, 0xe6, 0x3f, 0x1c, 0x3a, 0x74, 0xcf, 0x38, + 0xc2, 0xf6, 0xc2, 0x12, 0x41, 0xfd, 0x35, 0x45, 0x35, 0xf8, 0x20, 0x0c, 0x07, + 0xad, 0xfa, 0x10, 0x0b, 0xd3, 0xf3, 0xd4, 0xdd, 0xf4, 0x03, 0x0b, 0xd7, 0x2a, + 0x3a, 0x07, 0x26, 0x14, 0xd9, 0xb3, 0x01, 0xdf, 0xdb, 0xf3, 0xdf, 0xd6, 0xfa, + 0x3e, 0xb8, 0xea, 0x37, 0xe8, 0x03, 0x1e, 0xe0, 0x0c, 0x3e, 0xf9, 0xca, 0xbe, + 0x7f, 0xfe, 0x4a, 0x17, 0x3d, 0x01, 0xcc, 0xf9, 0x4e, 0xdb, 0xd6, 0xd5, 0xdc, + 0xd2, 0xfe, 0x2b, 0x03, 0xdb, 0xd9, 0x40, 0xf2, 0xf3, 0x2a, 0xb8, 0x0e, 0xff, + 0xc0, 0x02, 0xad, 0xed, 0xf2, 0xed, 0x25, 0xf8, 0x8f, 0xec, 0xfa, 0x20, 0xe6, + 0xf0, 0x0b, 0xcd, 0x3d, 0x03, 0x11, 0x15, 0x18, 0x09, 0x0a, 0x46, 0x14, 0xff, + 0xfd, 0xb1, 0x1f, 0x30, 0xf7, 0x1d, 0xf5, 0x04, 0x23, 0x2c, 0xf6, 0x33, 0x4b, + 0xc1, 0x0a, 0x33, 0xb6, 0xc2, 0x1c, 0xac, 0x04, 0x45, 0xee, 0xfc, 0xa2, 0x16, + 0xfc, 0x00, 0x16, 0xee, 0x16, 0xf3, 0x26, 0xcc, 0x05, 0xea, 0xca, 0x34, 0xba, + 0x0f, 0x2e, 0x16, 0xd9, 0xcc, 0x06, 0x0c, 0x06, 0x29, 0x30, 0x14, 0xfb, 0xe3, + 0xfc, 0xfe, 0x37, 0x52, 0xdd, 0xfd, 0xea, 0xc2, 0x1e, 0xdf, 0x2a, 0x3b, 0x0d, + 0xf2, 0xed, 0x1c, 0xf2, 0x81, 0xd9, 0xe8, 0x25, 0x78, 0x2e, 0x20, 0xe8, 0xa8, + 0x12, 0x29, 0x26, 0xf8, 0x3c, 0xfb, 0x3f, 0x14, 0x75, 0xfd, 0xb5, 0x06, 0x65, + 0x92, 0xe5, 0x44, 0x0a, 0xc7, 0xba, 0x28, 0xff, 0xde, 0x0c, 0x20, 0x35, 0xd1, + 0x21, 0x1a, 0x69, 0x33, 0x50, 0x1d, 0x27, 0xda, 0x8d, 0x1c, 0xea, 0x31, 0x12, + 0x57, 0x11, 0x1f, 0xfc, 0xa4, 0xfd, 0xe3, 0xea, 0x09, 0xef, 0xce, 0x27, 0x09, + 0x4a, 0xe7, 0xea, 0x0c, 0xcc, 0xef, 0x3c, 0x56, 0xee, 0xfa, 0x3b, 0x1b, 0xdb, + 0x23, 0xec, 0x23, 0xb4, 0xc9, 0xdd, 0xfd, 0x56, 0xe1, 0x44, 0xbd, 0xb8, 0x3f, + 0xc5, 0xc6, 0xef, 0xe1, 0x1e, 0xea, 0xe7, 0xd4, 0x0d, 0x3b, 0x5d, 0x73, 0x29, + 0x0b, 0xdd, 0xfb, 0xf0, 0x53, 0xc7, 0xb3, 0x21, 0x3d, 0x81, 0xb6, 0x11, 0xbb, + 0xb9, 0x0d, 0x14, 0x6a, 0x65, 0xfe, 0x9e, 0x0d, 0x2a, 0x45, 0x9d, 0x29, 0x31, + 0x04, 0xe5, 0xf5, 0x37, 0x40, 0x25, 0xca, 0xfc, 0x57, 0x1f, 0xde, 0x37, 0x50, + 0x33, 0x1b, 0x04, 0xfd, 0x14, 0xef, 0x37, 0x34, 0x3f, 0xf3, 0xd3, 0xc3, 0xa8, + 0xf4, 0x1d, 0xd7, 0x91, 0x2d, 0xe1, 0x02, 0xb9, 0xf9, 0xb9, 0xcb, 0x2b, 0xd3, + 0x04, 0xe0, 0x34, 0x17, 0xec, 0x0a, 0xda, 0xe3, 0x14, 0xd4, 0x25, 0x24, 0x97, + 0xfe, 0xe4, 0x0e, 0x35, 0xe9, 0xb5, 0xdd, 0x1b, 0x2b, 0x24, 0xc0, 0xdf, 0x0a, + 0xd6, 0xf6, 0xf3, 0x12, 0xe0, 0xe8, 0xf8, 0xdb, 0xdf, 0x26, 0xdd, 0xaf, 0x1b, + 0xf4, 0x0c, 0x15, 0x54, 0x0c, 0x06, 0xea, 0x11, 0xe1, 0x3b, 0xbc, 0xc0, 0x3a, + 0xf7, 0xb6, 0x1b, 0xc9, 0xea, 0x6c, 0xd3, 0xe4, 0x06, 0xcc, 0xfd, 0x5e, 0x11, + 0x3d, 0xfb, 0xea, 0x08, 0xd5, 0xad, 0xe3, 0x31, 0xd5, 0xd4, 0x17, 0x02, 0x09, + 0x24, 0xcb, 0x04, 0xed, 0x10, 0xf5, 0x06, 0xcf, 0xe1, 0x17, 0x17, 0xc2, 0x23, + 0xeb, 0x17, 0x1e, 0xff, 0x81, 0xd6, 0xe5, 0xea, 0xea, 0xf2, 0x05, 0x11, 0xe5, + 0xd5, 0xe8, 0x6d, 0x14, 0x15, 0x12, 0xdd, 0x99, 0x55, 0x96, 0xb2, 0xfc, 0xe4, + 0xb3, 0xba, 0x22, 0xee, 0x0b, 0xe3, 0x32, 0xfb, 0xe0, 0x20, 0xfb, 0x09, 0x39, + 0xde, 0xe6, 0xe0, 0x09, 0xc3, 0xf6, 0x25, 0x18, 0x01, 0x20, 0x38, 0x30, 0x0a, + 0x16, 0xeb, 0x29, 0xdc, 0x18, 0x09, 0xf2, 0x7e, 0xed, 0x5e, 0xcb, 0x1c, 0xf9, + 0xec, 0x21, 0x2b, 0x20, 0xe9, 0x38, 0x42, 0x04, 0x06, 0x21, 0xb6, 0xf7, 0x15, + 0xda, 0xd7, 0xd8, 0x53, 0xb7, 0x00, 0xc8, 0xef, 0x28, 0x56, 0x10, 0x13, 0x14, + 0x14, 0xe2, 0x28, 0xc1, 0x50, 0xb7, 0x28, 0x42, 0xd5, 0x48, 0xf2, 0x2a, 0xef, + 0x0c, 0xeb, 0x00, 0xfd, 0xeb, 0xe0, 0x54, 0x4a, 0xdb, 0xcc, 0x0b, 0x22, 0x35, + 0x16, 0x18, 0xf5, 0x01, 0xfa, 0x7f, 0xfb, 0xa9, 0x44, 0x2c, 0x1e, 0xff, 0x30, + 0xb6, 0x2c, 0x92, 0x22, 0xcb, 0x64, 0xf0, 0x64, 0x11, 0x29, 0x0a, 0xdb, 0xfe, + 0x0f, 0xdc, 0xf0, 0x70, 0xcf, 0x1e, 0x0d, 0x00, 0x2c, 0xe3, 0x15, 0x1e, 0xc0, + 0xd1, 0x6c, 0xed, 0x14, 0x36, 0xcb, 0xc0, 0xe2, 0x14, 0xc7, 0x26, 0x0d, 0x10, + 0xc6, 0x0d, 0xab, 0x19, 0xfa, 0xf4, 0x0b, 0x01, 0xeb, 0x40, 0x1d, 0xee, 0x0b, + 0xeb, 0x76, 0xeb, 0xd8, 0xe7, 0x03, 0x2f, 0xca, 0x11, 0xf1, 0x08, 0xec, 0xc8, + 0x07, 0xf5, 0xdc, 0x05, 0xfd, 0x61, 0x43, 0xcf, 0xe9, 0xa4, 0x0e, 0x4c, 0xe7, + 0xe5, 0x59, 0xc0, 0xe0, 0xd0, 0xd9, 0xdc, 0xd9, 0xee, 0x23, 0xd0, 0x01, 0xed, + 0x14, 0xa4, 0xd9, 0x02, 0x0c, 0x4c, 0x47, 0x4b, 0x33, 0x23, 0x2a, 0x25, 0xd1, + 0x17, 0x16, 0xf3, 0x10, 0x04, 0x09, 0xde, 0x17, 0x0e, 0xff, 0x60, 0x11, 0xf2, + 0xd7, 0x07, 0x05, 0xe4, 0xe1, 0x15, 0x7f, 0x2c, 0x06, 0xe6, 0x22, 0xdb, 0x17, + 0x11, 0x03, 0x33, 0x2c, 0xbc, 0x15, 0xfe, 0xcc, 0x21, 0x23, 0x08, 0xd9, 0xf7, + 0xfd, 0xc3, 0x10, 0x27, 0xf2, 0x37, 0x4c, 0xd0, 0xec, 0x12, 0xeb, 0x55, 0x07, + 0xcd, 0xf6, 0x07, 0x3f, 0xe8, 0x09, 0xe6, 0x36, 0xf3, 0xe5, 0x19, 0x12, 0x18, + 0xdc, 0xd7, 0xc6, 0xe5, 0xc5, 0x2e, 0xc8, 0x14, 0x07, 0xc8, 0x01, 0x04, 0x7f, + 0x03, 0x47, 0x2a, 0xc2, 0xaf, 0x6a, 0x1b, 0xe9, 0xe3, 0x00, 0xfb, 0xe3, 0x08, + 0x29, 0x3f, 0xf7, 0xe4, 0x27, 0x9b, 0x2c, 0xa4, 0xb5, 0xe3, 0xc9, 0xc3, 0xd2, + 0x10, 0xe6, 0x7f, 0x87, 0x0e, 0xde, 0xf3, 0xd9, 0xde, 0xb7, 0xd7, 0xed, 0x41, + 0xc8, 0x1a, 0xdf, 0xae, 0xe8, 0xbb, 0x11, 0xd0, 0xfa, 0xe9, 0x71, 0xe3, 0x2d, + 0xa5, 0x35, 0xf4, 0xed, 0xf1, 0xea, 0x13, 0x31, 0x3b, 0x08, 0x33, 0x39, 0x27, + 0x18, 0xb6, 0xcb, 0xc3, 0x18, 0xfc, 0x1d, 0x0a, 0x27, 0xa2, 0x1e, 0xa5, 0xdb, + 0xfb, 0xcf, 0xda, 0xa7, 0xd2, 0xa3, 0xe5, 0xf6, 0xf6, 0xdd, 0xfb, 0x10, 0x05, + 0xf0, 0x44, 0xe1, 0xb1, 0x1c, 0xec, 0xe0, 0x16, 0x05, 0xdb, 0x68, 0xc9, 0x0a, + 0xf2, 0xf2, 0x1f, 0x21, 0x3c, 0xd0, 0xca, 0xe9, 0x2a, 0xd8, 0xe1, 0x76, 0xb3, + 0x61, 0xef, 0xd0, 0xf2, 0x2d, 0xf8, 0x4a, 0xfd, 0xf1, 0x01, 0xba, 0xfd, 0x02, + 0x41, 0xba, 0x3b, 0xe9, 0xd4, 0xe6, 0x53, 0x1a, 0x04, 0xba, 0xe6, 0x46, 0xb5, + 0xfa, 0x1b, 0xcc, 0x2f, 0xeb, 0x0f, 0xe9, 0xdc, 0x61, 0xbe, 0xed, 0x20, 0x27, + 0x9e, 0xed, 0x94, 0x34, 0x24, 0x14, 0xaa, 0xf9, 0xf2, 0x1f, 0x2a, 0x24, 0x22, + 0xe8, 0xb5, 0x0d, 0xbd, 0xda, 0xef, 0xd3, 0xca, 0x7f, 0x56, 0xd4, 0x02, 0x06, + 0xf3, 0xe6, 0xe0, 0x6c, 0xc8, 0xa0, 0xd8, 0xd0, 0xef, 0x3a, 0xbe, 0x42, 0xd7, + 0x22, 0xfe, 0x36, 0xe6, 0x06, 0x1a, 0xf3, 0x0d, 0x1c, 0x10, 0xe9, 0xce, 0xde, + 0x19, 0x20, 0x0b, 0xc8, 0xfc, 0x0a, 0xd4, 0xf3, 0xe0, 0x0a, 0xe0, 0xe0, 0xd2, + 0x0c, 0xf6, 0xfc, 0xf8, 0x22, 0xe6, 0xee, 0x65, 0x0a, 0x7f, 0x35, 0x0b, 0x2f, + 0xee, 0x08, 0xeb, 0xf7, 0xdd, 0xf8, 0x1d, 0x25, 0x21, 0xf1, 0x07, 0xe5, 0xf5, + 0x3c, 0x66, 0xf6, 0x0d, 0xe9, 0x0e, 0xe0, 0x17, 0xe5, 0xf5, 0xee, 0x0b, 0x14, + 0x06, 0xfa, 0x00, 0x23, 0x17, 0xd0, 0x00, 0xe4, 0xcc, 0x38, 0xf2, 0xd1, 0x12, + 0xf0, 0x12, 0xe5, 0xed, 0x0b, 0xe6, 0x38, 0x42, 0x2e, 0xb9, 0xfd, 0x14, 0xd3, + 0x09, 0xf4, 0xe4, 0x1e, 0x45, 0xd8, 0xc4, 0xff, 0x3d, 0xea, 0xf7, 0x01, 0x0d, + 0xea, 0x0c, 0xf2, 0x06, 0x07, 0x0c, 0xd0, 0x05, 0xda, 0x3b, 0xfb, 0x19, 0x0e, + 0x70, 0xc2, 0xfb, 0xdc, 0x2a, 0x22, 0x10, 0xe6, 0xd3, 0xf0, 0x1d, 0x4b, 0xb1, + 0x36, 0xf5, 0x1f, 0xdb, 0xf5, 0x03, 0x15, 0xe6, 0xe9, 0xee, 0xf8, 0x0f, 0x18, + 0x2e, 0x02, 0x0e, 0x23, 0xfe, 0x1a, 0x33, 0x1c, 0xa6, 0x0f, 0xf7, 0x67, 0x0e, + 0x0b, 0x33, 0xc7, 0x0a, 0x92, 0x19, 0x1c, 0x35, 0x17, 0xe6, 0xf8, 0x05, 0xd5, + 0x0b, 0x11, 0x13, 0xfa, 0x63, 0x15, 0xee, 0xcd, 0xdc, 0x2c, 0xe5, 0xed, 0x17, + 0x14, 0xdb, 0xcd, 0xec, 0x09, 0x37, 0x3b, 0x71, 0xfe, 0xed, 0x44, 0xc5, 0x4a, + 0xbb, 0xaa, 0x12, 0xec, 0x06, 0x20, 0xde, 0x88, 0xac, 0xfc, 0x7d, 0x08, 0xf8, + 0x0e, 0xb1, 0xef, 0xd2, 0xea, 0xf8, 0x5e, 0xfa, 0xd8, 0xb1, 0x2d, 0xf0, 0x0f, + 0x2b, 0xfe, 0x21, 0x0a, 0xc2, 0xe4, 0x0a, 0xe2, 0xa3, 0x2b, 0x40, 0x3c, 0xa7, + 0xcb, 0x28, 0x21, 0xd4, 0xa2, 0xd8, 0xdd, 0x28, 0xbc, 0xdd, 0x2f, 0x7f, 0x29, + 0xd4, 0x20, 0xa9, 0x32, 0xb9, 0x3a, 0x2d, 0x06, 0x12, 0x00, 0x82, 0xfe, 0xd2, + 0x4b, 0x5d, 0x12, 0xf4, 0x42, 0xae, 0xbd, 0x62, 0xbc, 0xfe, 0x29, 0x04, 0x10, + 0xe9, 0xd0, 0x00, 0x40, 0x28, 0x3f, 0xd9, 0x0b, 0x01, 0x1a, 0x10, 0x21, 0x01, + 0xe5, 0x5f, 0x26, 0x06, 0x26, 0x15, 0x25, 0xbc, 0x32, 0x19, 0x07, 0x44, 0xba, + 0x07, 0xe7, 0xf4, 0x06, 0x14, 0x33, 0xf4, 0x15, 0xf9, 0xd2, 0xe5, 0x27, 0x1e, + 0x15, 0x57, 0x00, 0xfb, 0xe3, 0x12, 0xf1, 0x36, 0x02, 0x38, 0x03, 0x1b, 0xda, + 0x42, 0x0a, 0x31, 0x66, 0x19, 0x16, 0xc4, 0xf1, 0x1d, 0xf9, 0x36, 0x52, 0xea, + 0x4d, 0x2b, 0x20, 0xdd, 0xfd, 0x3a, 0x4a, 0x7f, 0xd5, 0xf9, 0xc5, 0x2e, 0x40, + 0xe9, 0x19, 0xe7, 0x16, 0xd0, 0xd1, 0xf4, 0xdb, 0xd4, 0xe4, 0xe0, 0x06, 0x09, + 0xee, 0xe5, 0xe6, 0x5d, 0xd9, 0x49, 0xcf, 0x25, 0xef, 0x17, 0x13, 0xea, 0xd5, + 0xe1, 0xe4, 0xf2, 0x39, 0x14, 0x22, 0xe6, 0x37, 0xf6, 0x08, 0x0a, 0x17, 0x09, + 0xfc, 0x12, 0xef, 0xf0, 0xfe, 0xdb, 0x0f, 0x29, 0x2e, 0x03, 0xeb, 0xfa, 0x00, + 0xf9, 0x0c, 0x3a, 0xf2, 0xdf, 0xe8, 0xe4, 0xfa, 0xfa, 0xdd, 0x11, 0x01, 0xe7, + 0x0a, 0x0c, 0xde, 0x02, 0xf8, 0xe9, 0x25, 0x28, 0x08, 0x0c, 0x03, 0x0c, 0xe2, + 0xdb, 0xe1, 0x17, 0xfe, 0x06, 0xdb, 0x19, 0x19, 0x0e, 0x21, 0x3f, 0x12, 0x19, + 0xa7, 0x04, 0x96, 0x01, 0x12, 0xfe, 0xfb, 0xd7, 0xfc, 0xe8, 0x2b, 0xfc, 0x0d, + 0x00, 0xfe, 0xf6, 0x49, 0x02, 0xeb, 0xf0, 0x22, 0x5b, 0x09, 0x7f, 0x07, 0x02, + 0xc5, 0x24, 0xbe, 0x13, 0x3a, 0x02, 0x1f, 0x32, 0x45, 0xe9, 0xf9, 0xee, 0xea, + 0x0a, 0x11, 0xeb, 0xf0, 0xeb, 0xfc, 0xe2, 0x0b, 0xc4, 0xfe, 0xf2, 0x14, 0xe2, + 0x01, 0xf3, 0xde, 0x1c, 0xd3, 0x11, 0x17, 0x25, 0xc9, 0xfa, 0x06, 0xdf, 0xc6, + 0xf3, 0x0b, 0xef, 0x18, 0x0e, 0xf9, 0xff, 0x0c, 0xec, 0xff, 0xf7, 0xed, 0xe9, + 0x02, 0xc1, 0xd1, 0x12, 0xdd, 0xe3, 0x18, 0x17, 0x07, 0x33, 0x1b, 0xf3, 0x06, + 0x1a, 0x0c, 0x2d, 0xe0, 0xe9, 0xf2, 0xd0, 0xf2, 0xec, 0x1d, 0xdf, 0x03, 0xfc, + 0x06, 0x05, 0xea, 0x20, 0x20, 0xd8, 0x1d, 0xf4, 0xff, 0x13, 0xf2, 0x19, 0xec, + 0xf3, 0xe2, 0xeb, 0xd9, 0x04, 0x2d, 0x15, 0x13, 0x2e, 0xfd, 0xd0, 0xed, 0x20, + 0xfd, 0x06, 0xf1, 0xdd, 0x1c, 0x4d, 0x08, 0xf1, 0x13, 0x01, 0xfc, 0x1a, 0xf4, + 0x0d, 0xff, 0xf6, 0x14, 0x03, 0x1c, 0x3a, 0xf0, 0x7f, 0xe9, 0xff, 0xec, 0xec, + 0x2a, 0xfa, 0x04, 0xd9, 0x27, 0x23, 0xd0, 0xec, 0xff, 0x14, 0xf8, 0x07, 0x08, + 0xe6, 0x0c, 0x29, 0x0e, 0x18, 0xeb, 0xdf, 0x0d, 0x18, 0xe5, 0x21, 0x01, 0x18, + 0x3a, 0xf9, 0xf2, 0x2a, 0x25, 0x11, 0xd6, 0x1f, 0x0b, 0x29, 0x4a, 0x03, 0xee, + 0x00, 0xf8, 0x15, 0x07, 0x27, 0x05, 0xff, 0x06, 0x05, 0xe9, 0xd9, 0x2f, 0x0b, + 0x13, 0x06, 0xff, 0x0b, 0x1e, 0xed, 0x22, 0x17, 0x0b, 0xfd, 0xea, 0x38, 0xd1, + 0x23, 0x08, 0x1b, 0xce, 0xaa, 0x34, 0x09, 0x3a, 0xd8, 0xe0, 0x15, 0x10, 0xf8, + 0x29, 0xec, 0xf3, 0xf4, 0x23, 0x21, 0xba, 0xf9, 0x0d, 0x12, 0x30, 0x03, 0xbb, + 0xfa, 0xfb, 0xd2, 0xd4, 0x06, 0x16, 0x07, 0xff, 0xfc, 0x0d, 0xfe, 0xd9, 0xc8, + 0xe1, 0x46, 0xc0, 0x13, 0xe3, 0xe5, 0xed, 0xf2, 0x31, 0xae, 0x29, 0x98, 0xfb, + 0xca, 0xdc, 0xea, 0x08, 0xdb, 0x2b, 0x2d, 0xf3, 0x16, 0x67, 0xe0, 0xef, 0x13, + 0x40, 0xfb, 0xe2, 0x35, 0x62, 0x30, 0x57, 0xa1, 0x12, 0xf1, 0xc1, 0xed, 0xe5, + 0xe2, 0x1e, 0xc3, 0xd9, 0xf2, 0x3f, 0x4a, 0x05, 0xba, 0x24, 0x81, 0xb0, 0x18, + 0x01, 0xea, 0x04, 0x5b, 0x36, 0xcc, 0xab, 0xe0, 0xe9, 0xc8, 0xc8, 0x50, 0xdd, + 0xde, 0x42, 0x02, 0xd3, 0xe3, 0xdd, 0x10, 0xef, 0x63, 0xf8, 0xdd, 0xba, 0xdf, + 0xd4, 0xe1, 0xff, 0xfc, 0xc6, 0x26, 0xfa, 0xc5, 0x39, 0x11, 0x2d, 0x29, 0xfd, + 0xaa, 0x2d, 0xbd, 0xbe, 0x04, 0xde, 0xea, 0xe6, 0xd1, 0xf0, 0xfd, 0x62, 0x0c, + 0xf7, 0x15, 0x0e, 0xc0, 0x33, 0xff, 0xe9, 0x33, 0xee, 0xdc, 0xc8, 0xdd, 0x11, + 0x04, 0xe3, 0x24, 0xe7, 0x0f, 0x27, 0xf3, 0x07, 0x0d, 0xc3, 0x05, 0x15, 0xde, + 0x2e, 0xfc, 0xf9, 0x17, 0x41, 0x01, 0xf5, 0x7f, 0x38, 0xd6, 0xff, 0xfd, 0xef, + 0x02, 0xd1, 0xca, 0xe4, 0xfc, 0xfe, 0x5b, 0xeb, 0xfb, 0x16, 0xda, 0xda, 0xd3, + 0x00, 0x16, 0xcf, 0xe3, 0x1b, 0x52, 0x08, 0x3f, 0x1e, 0xe0, 0x3c, 0xc5, 0x1c, + 0x6a, 0xf5, 0xf6, 0xff, 0x0c, 0xf6, 0x04, 0xc6, 0xa2, 0x1f, 0xf1, 0xe9, 0x25, + 0x1e, 0x0b, 0xc6, 0x0b, 0x1c, 0xca, 0x00, 0xf8, 0xb6, 0xda, 0xe2, 0x19, 0xd7, + 0xd1, 0x00, 0xe7, 0x0c, 0x1b, 0x1a, 0xc7, 0x04, 0xd8, 0xee, 0xd2, 0xdf, 0xf0, + 0x3b, 0xff, 0xc0, 0x6c, 0x20, 0xed, 0x24, 0x07, 0x0f, 0x18, 0x3c, 0xd9, 0x2d, + 0x29, 0x05, 0xf3, 0xf3, 0x06, 0xe0, 0xde, 0x13, 0xdc, 0xf9, 0x38, 0xb0, 0x22, + 0x24, 0x02, 0x56, 0x1e, 0xf1, 0xf1, 0x02, 0xe0, 0xd7, 0xf4, 0x22, 0xdb, 0xf3, + 0xf6, 0xc3, 0x0d, 0xda, 0xc8, 0xf4, 0x21, 0xd8, 0xf5, 0x2f, 0x24, 0x37, 0xfc, + 0x23, 0x28, 0xd5, 0x16, 0x1f, 0xb9, 0x0b, 0xfa, 0xd6, 0xf9, 0xe1, 0xdd, 0xe1, + 0xe1, 0xf5, 0xd3, 0xd8, 0x39, 0x04, 0x19, 0x2f, 0xc1, 0x04, 0xe3, 0xb8, 0x10, + 0xc7, 0x36, 0x56, 0xf1, 0xf4, 0xea, 0xf4, 0x60, 0x1e, 0xe3, 0x05, 0x40, 0xe8, + 0x98, 0xed, 0xed, 0x01, 0x2b, 0x0d, 0xea, 0xc0, 0xee, 0x7f, 0xee, 0x03, 0x03, + 0x14, 0xa6, 0xf7, 0x2d, 0xdf, 0xf9, 0xd7, 0x29, 0x01, 0xe8, 0x06, 0x04, 0xeb, + 0xe0, 0x0e, 0x1d, 0x3e, 0x26, 0x14, 0x9c, 0xf3, 0xc9, 0x02, 0xc1, 0x13, 0x1b, + 0x03, 0x0c, 0xfa, 0xf7, 0xe6, 0xf9, 0xfc, 0xfd, 0xc9, 0xc8, 0x5f, 0xc9, 0xfb, + 0xd9, 0x10, 0xb6, 0xd9, 0xc4, 0xd0, 0xcd, 0xf6, 0x14, 0x3e, 0xc1, 0xff, 0xef, + 0x1c, 0x0f, 0xe2, 0xab, 0x03, 0xf1, 0x02, 0xd6, 0x2b, 0x17, 0x16, 0xfd, 0xdb, + 0x1b, 0xda, 0xee, 0xc4, 0x34, 0x2a, 0xf2, 0xcd, 0xfc, 0x24, 0xdb, 0x14, 0xbc, + 0x28, 0xc3, 0xc0, 0xce, 0xbd, 0x25, 0x08, 0xe0, 0x21, 0xf9, 0x48, 0xeb, 0xdd, + 0x9e, 0xe1, 0xb7, 0x14, 0xbd, 0xd1, 0x17, 0x03, 0xbc, 0xe4, 0x2f, 0x29, 0x05, + 0x13, 0x7f, 0x0e, 0x04, 0xf4, 0x18, 0x05, 0x05, 0x3e, 0x55, 0x3f, 0xeb, 0x0d, + 0x17, 0xe9, 0x44, 0xfc, 0x84, 0xdc, 0x1f, 0xc0, 0x48, 0xe3, 0x01, 0xb5, 0xe7, + 0xfb, 0x2b, 0xf9, 0xdc, 0x1f, 0xdd, 0x15, 0x55, 0xfa, 0xfa, 0xc3, 0xdd, 0x09, + 0x20, 0xe8, 0xf3, 0x0b, 0xda, 0xf3, 0xf3, 0x15, 0x1d, 0x1d, 0x18, 0x07, 0x20, + 0x35, 0x32, 0xf7, 0x2b, 0x17, 0x59, 0xc7, 0xc2, 0xec, 0xd6, 0xfc, 0xfc, 0x2f, + 0xec, 0xea, 0x37, 0xb9, 0x0d, 0x2e, 0xf4, 0x55, 0xb2, 0xd6, 0xbb, 0x0b, 0xca, + 0x35, 0xdc, 0x12, 0xfe, 0x09, 0x45, 0xec, 0xfb, 0xe8, 0x23, 0x0c, 0xda, 0xe6, + 0xf8, 0x40, 0xf9, 0x12, 0xd0, 0x17, 0xc8, 0xe8, 0x7f, 0x1e, 0xe3, 0x21, 0x18, + 0x08, 0x16, 0xc8, 0x3c, 0x31, 0xdc, 0x78, 0xc4, 0x01, 0x52, 0xeb, 0x69, 0x0b, + 0xf9, 0x0b, 0xce, 0x36, 0xcf, 0x3b, 0xd8, 0xe4, 0x1d, 0xcc, 0xea, 0x04, 0x0d, + 0x18, 0x2f, 0x05, 0xe5, 0x15, 0x01, 0x10, 0x37, 0xde, 0xe6, 0x24, 0x03, 0xcf, + 0x11, 0xb5, 0xeb, 0x4c, 0x3d, 0x17, 0xfc, 0x18, 0x4d, 0xb8, 0x72, 0x32, 0xc8, + 0x04, 0x12, 0xed, 0xe8, 0xc0, 0x30, 0x3c, 0x12, 0xdb, 0x18, 0xd9, 0xd5, 0xd8, + 0x05, 0xbb, 0xb9, 0x4d, 0x04, 0xd9, 0x37, 0xed, 0xfa, 0xf2, 0xf6, 0xed, 0xbd, + 0x4e, 0x8d, 0xf4, 0x2d, 0x09, 0xd8, 0x83, 0xed, 0xad, 0xec, 0x37, 0xe7, 0x21, + 0xdd, 0xd3, 0x23, 0xc7, 0x07, 0xe8, 0xc7, 0x18, 0xd3, 0x5f, 0x13, 0xe4, 0x00, + 0xdc, 0xff, 0x02, 0x28, 0x4a, 0x5f, 0xf3, 0x1a, 0x4b, 0xe8, 0xc5, 0x3e, 0x17, + 0x1d, 0x42, 0x02, 0x20, 0x01, 0x2c, 0x1d, 0xf7, 0x04, 0xe3, 0x29, 0x09, 0x45, + 0x11, 0x11, 0xe3, 0x09, 0x2c, 0xe0, 0x19, 0x17, 0xd7, 0x65, 0x0e, 0x05, 0x14, + 0x4b, 0xc9, 0xfa, 0xed, 0x0b, 0xe4, 0x13, 0xe6, 0xce, 0xad, 0xc3, 0xdb, 0xf8, + 0x1f, 0x20, 0x25, 0x01, 0xd7, 0x47, 0xb7, 0xfe, 0x29, 0x0a, 0xd5, 0x24, 0xfe, + 0x7f, 0xbe, 0xe1, 0xd7, 0x05, 0xd5, 0xae, 0x7c, 0x5c, 0x3c, 0xaf, 0xd7, 0x57, + 0xb7, 0x16, 0xaf, 0x28, 0xdd, 0xef, 0x23, 0x0d, 0xc6, 0x0b, 0x0c, 0x22, 0x96, + 0xc8, 0x1d, 0x9b, 0xdd, 0xe7, 0x01, 0xea, 0x2d, 0x0f, 0xc9, 0xff, 0x45, 0x13, + 0x26, 0x29, 0x08, 0x31, 0x98, 0xcf, 0xd2, 0xdc, 0x07, 0xd4, 0xeb, 0x0b, 0xd1, + 0x3c, 0x74, 0xc8, 0xe4, 0xef, 0x0c, 0xc4, 0xc8, 0x11, 0xa6, 0x64, 0xf9, 0xf9, + 0xf5, 0x4a, 0xc7, 0x2c, 0x19, 0x30, 0x27, 0x0d, 0xff, 0x44, 0x56, 0xc6, 0xc7, + 0xe8, 0xf5, 0xe8, 0xf7, 0xf6, 0x9e, 0x20, 0xf9, 0x19, 0x0b, 0x30, 0xe3, 0x0b, + 0xb4, 0x14, 0xd6, 0x57, 0xef, 0xb7, 0x06, 0xfd, 0xf7, 0xc7, 0x05, 0xf9, 0xfb, + 0x00, 0x29, 0x23, 0xbf, 0x99, 0x26, 0x16, 0xd6, 0x03, 0xa5, 0x46, 0x49, 0xd2, + 0x37, 0x7f, 0x24, 0xe7, 0xfc, 0xa2, 0x38, 0x43, 0x53, 0xd9, 0xdb, 0xf5, 0xe9, + 0xdb, 0x78, 0xd2, 0xd9, 0x4e, 0xec, 0x0c, 0x1b, 0xb5, 0xc5, 0xa7, 0xe6, 0x2e, + 0xf4, 0x0a, 0xf5, 0x18, 0xa6, 0x23, 0x0f, 0xc0, 0xfe, 0xf3, 0x16, 0xd4, 0xfa, + 0x74, 0x11, 0x16, 0xda, 0x13, 0xc1, 0x2a, 0xd7, 0x0c, 0xf8, 0x0e, 0xe1, 0xcb, + 0x12, 0x28, 0xb4, 0x43, 0x0e, 0xe0, 0x27, 0xd0, 0xd0, 0xc1, 0x0c, 0x12, 0xd7, + 0xe1, 0xc8, 0x40, 0xf3, 0x7d, 0xa7, 0x14, 0xd0, 0x38, 0xdb, 0x1d, 0x2b, 0xc2, + 0x3a, 0xd1, 0xa3, 0xbf, 0x50, 0xea, 0xf7, 0x32, 0xe9, 0xfd, 0x01, 0x1d, 0x15, + 0x06, 0x1f, 0x9a, 0xe4, 0xf7, 0x32, 0x29, 0xff, 0xc5, 0x02, 0xb3, 0xd8, 0x61, + 0x0a, 0x10, 0xf8, 0xfb, 0xf5, 0xfe, 0xd6, 0x06, 0x05, 0xe4, 0xc4, 0x0a, 0x7f, + 0x90, 0xa0, 0x05, 0xce, 0x2e, 0xe3, 0xab, 0x24, 0xe9, 0x17, 0x10, 0xc2, 0xf8, + 0xcc, 0x00, 0xf5, 0x11, 0xf0, 0x24, 0xd5, 0xe5, 0x08, 0x07, 0xc8, 0xf3, 0x00, + 0x23, 0xb0, 0x28, 0x54, 0xd0, 0x45, 0xe9, 0x03, 0xdf, 0xf3, 0xf5, 0x21, 0xcc, + 0x14, 0xfb, 0xfa, 0xbc, 0x1d, 0x04, 0xe3, 0xf9, 0x26, 0x03, 0x08, 0xf8, 0xfd, + 0x2e, 0xc9, 0xd6, 0x0f, 0xe2, 0x37, 0x4a, 0x14, 0xec, 0x1d, 0x61, 0xb6, 0x1c, + 0xdc, 0xbe, 0x09, 0x04, 0x2e, 0x02, 0xa8, 0xe2, 0xeb, 0x0b, 0x64, 0x20, 0x5a, + 0xe9, 0x16, 0xbd, 0xf3, 0xba, 0x19, 0x22, 0xe5, 0x18, 0xfc, 0xd6, 0xa2, 0x29, + 0x2e, 0x23, 0x1d, 0xdd, 0x16, 0x19, 0x01, 0xcf, 0x5a, 0x1e, 0xfe, 0xe5, 0xf5, + 0x7f, 0xee, 0xb4, 0x1c, 0xf6, 0xbf, 0xe0, 0xfb, 0xd1, 0x01, 0xf7, 0xef, 0xdf, + 0xd9, 0x56, 0xe0, 0x35, 0xc6, 0xd2, 0xd0, 0xc5, 0x2d, 0xc8, 0xf6, 0x93, 0x6c, + 0xf9, 0xe4, 0x0b, 0xe6, 0xf6, 0x9c, 0xfd, 0x67, 0xb7, 0xfb, 0x2b, 0x25, 0xff, + 0xf5, 0x1f, 0xe2, 0x03, 0x04, 0x03, 0xf3, 0xb8, 0x40, 0x6b, 0x09, 0xee, 0x7e, + 0xeb, 0xa1, 0x0a, 0x38, 0xe3, 0x0a, 0x73, 0xfd, 0xbc, 0xcb, 0x4e, 0x9f, 0xe3, + 0xd1, 0xfe, 0x00, 0xd9, 0xfa, 0x0f, 0x00, 0x36, 0x86, 0x50, 0x33, 0x0d, 0xfe, + 0xff, 0x17, 0xd4, 0x70, 0xd9, 0xc9, 0xc6, 0x10, 0xeb, 0x36, 0x16, 0x15, 0xe2, + 0x41, 0xf1, 0xe8, 0xdb, 0xfb, 0x00, 0xed, 0x44, 0x51, 0x2d, 0xf7, 0xe8, 0xe3, + 0x27, 0x38, 0x22, 0x16, 0xfa, 0x30, 0xe9, 0x4f, 0x5c, 0xe3, 0x30, 0x46, 0xd2, + 0xeb, 0xd2, 0xac, 0xc3, 0xf4, 0xb9, 0x02, 0xb6, 0xd8, 0xea, 0x4a, 0xa3, 0xf8, + 0xbf, 0xcb, 0xc2, 0x1e, 0xfa, 0xb5, 0x35, 0xdf, 0xf6, 0xfb, 0xe8, 0xf8, 0x2d, + 0x39, 0x81, 0xd7, 0xea, 0xc4, 0x67, 0x9b, 0xb2, 0x3d, 0xe1, 0xdb, 0xf0, 0x12, + 0xd9, 0xea, 0xda, 0xca, 0xa9, 0xf5, 0xdc, 0x0d, 0xf9, 0x13, 0xc7, 0xe7, 0xc2, + 0x1d, 0xed, 0xc0, 0x5a, 0xcf, 0x67, 0x26, 0xce, 0x04, 0x16, 0x2f, 0xdd, 0xee, + 0x3a, 0x1c, 0xe5, 0x25, 0x20, 0xd1, 0xd7, 0x14, 0x77, 0xff, 0xea, 0xc1, 0xca, + 0xbc, 0x06, 0x13, 0xff, 0x21, 0xc2, 0x03, 0xff, 0x03, 0x03, 0x0c, 0x60, 0x06, + 0x26, 0xc5, 0x24, 0x3b, 0x0b, 0x2e, 0x14, 0xf4, 0x06, 0x14, 0x00, 0x12, 0xeb, + 0xe6, 0x29, 0xe1, 0x18, 0x16, 0x27, 0x15, 0xde, 0x28, 0xe6, 0xef, 0x26, 0xd2, + 0xe9, 0xaf, 0xf6, 0xfd, 0x3f, 0x2c, 0x18, 0x0e, 0xfe, 0xd1, 0xc0, 0x22, 0x0e, + 0x37, 0x00, 0xfb, 0xf6, 0xf1, 0xdf, 0x0f, 0x27, 0xfb, 0x34, 0xf9, 0x24, 0xdd, + 0xec, 0xf7, 0x01, 0xff, 0x1b, 0x3e, 0x29, 0xc5, 0xf4, 0x43, 0x27, 0x3c, 0xed, + 0x17, 0x0d, 0x04, 0x22, 0xcc, 0xff, 0x39, 0x08, 0x81, 0xc8, 0x44, 0x13, 0x0e, + 0xe7, 0x15, 0x2d, 0xda, 0xef, 0xed, 0x17, 0x1e, 0xc5, 0x01, 0x03, 0x08, 0x0a, + 0x15, 0x1b, 0x03, 0xfa, 0x04, 0xed, 0xf0, 0xd8, 0xfc, 0xe7, 0x24, 0x12, 0xcb, + 0x17, 0x18, 0x10, 0x4d, 0xe7, 0x0a, 0x10, 0x12, 0xf8, 0xa0, 0x02, 0xfb, 0x35, + 0x0f, 0xe6, 0x17, 0x21, 0xe1, 0x1e, 0x02, 0x13, 0x15, 0x0f, 0x12, 0x0b, 0xe6, + 0x06, 0x62, 0x40, 0xdd, 0x72, 0xe8, 0x00, 0xb4, 0xef, 0x2b, 0x02, 0xe9, 0xd5, + 0x02, 0x99, 0x1c, 0xc4, 0x2b, 0xf6, 0xf8, 0x04, 0xeb, 0x1b, 0xfd, 0xe3, 0xa1, + 0x49, 0x95, 0xe8, 0x0a, 0x14, 0xc8, 0xaf, 0xb1, 0x8f, 0xf3, 0x1f, 0x0b, 0xda, + 0x10, 0x9f, 0xdc, 0x02, 0xd8, 0xce, 0x3d, 0xf5, 0x02, 0x0d, 0x1b, 0x16, 0x17, + 0x29, 0xf2, 0xeb, 0x3e, 0x54, 0xba, 0x96, 0xcf, 0xbf, 0x2d, 0x2d, 0x00, 0x1c, + 0xcd, 0x2e, 0xe3, 0xce, 0x0c, 0x9c, 0x3d, 0x36, 0xa5, 0x3b, 0xdd, 0xb2, 0x30, + 0x07, 0xfd, 0x39, 0x00, 0x09, 0x03, 0x11, 0xa0, 0xfc, 0x66, 0xfd, 0xe8, 0xec, + 0xf3, 0xac, 0xb9, 0xcf, 0x1a, 0x98, 0xfe, 0x9a, 0xbc, 0x17, 0x1e, 0xe0, 0x0f, + 0x0d, 0x59, 0xbd, 0xfd, 0xeb, 0x27, 0xec, 0xda, 0x0e, 0x44, 0xd4, 0x3c, 0xb9, + 0x27, 0xbd, 0x07, 0xd8, 0x34, 0xa1, 0xf5, 0x24, 0x7f, 0x41, 0x15, 0x17, 0x69, + 0x43, 0x08, 0x09, 0x18, 0xe6, 0xd0, 0xf1, 0xf4, 0x10, 0x06, 0xd1, 0xda, 0xeb, + 0xcb, 0x55, 0x24, 0xd9, 0xe1, 0x22, 0x09, 0xbd, 0x11, 0xe8, 0x00, 0xe6, 0x3a, + 0xfd, 0x27, 0x31, 0x03, 0x00, 0x1a, 0x33, 0x76, 0x5a, 0x40, 0x7f, 0x44, 0x33, + 0x00, 0xff, 0xc3, 0x18, 0xca, 0x9b, 0xfe, 0xf5, 0x3b, 0x02, 0xf6, 0x1d, 0xef, + 0xe4, 0xf9, 0x1a, 0xc6, 0x1f, 0x1c, 0xff, 0x12, 0x0c, 0xed, 0x0e, 0xf9, 0x05, + 0x30, 0xfe, 0x3a, 0xd7, 0xba, 0xbc, 0x3c, 0x1d, 0xe9, 0x0d, 0x13, 0xc8, 0x5a, + 0x3d, 0xdd, 0xef, 0x23, 0x07, 0xf1, 0x12, 0x00, 0xd5, 0x01, 0xff, 0xde, 0xd3, + 0x06, 0x05, 0xce, 0x26, 0x19, 0xcc, 0xf6, 0xf2, 0x08, 0xe3, 0xbb, 0xf3, 0xe9, + 0x04, 0x08, 0x25, 0x51, 0xe8, 0xd3, 0x54, 0x0f, 0x1a, 0xf3, 0x68, 0x1f, 0x61, + 0x1a, 0xdf, 0xff, 0xfa, 0x1b, 0xb9, 0x59, 0x33, 0xd7, 0x03, 0x0c, 0x35, 0x1d, + 0x14, 0xcf, 0x81, 0x96, 0xce, 0x91, 0xf0, 0x20, 0xc3, 0xe5, 0x3e, 0xb8, 0x05, + 0x03, 0xfd, 0x19, 0xac, 0xee, 0xcc, 0x60, 0x55, 0xe8, 0x52, 0x0a, 0x25, 0xb8, + 0x28, 0xd4, 0xcc, 0x00, 0xc4, 0x29, 0x1c, 0x26, 0xf6, 0x1b, 0x0e, 0xdd, 0x0d, + 0x36, 0x0b, 0x41, 0xe6, 0x49, 0xec, 0x04, 0x0d, 0xe4, 0xea, 0xad, 0xdf, 0xc7, + 0x06, 0x6a, 0xf9, 0x1d, 0xfc, 0x31, 0xf4, 0xfb, 0x59, 0x00, 0x97, 0x72, 0x00, + 0xb7, 0xc8, 0x47, 0x48, 0xff, 0xdc, 0xe8, 0xf0, 0x21, 0xee, 0x27, 0xf6, 0x26, + 0x2b, 0xf0, 0x3f, 0xac, 0x40, 0x4b, 0x11, 0x06, 0x21, 0x0a, 0x32, 0x12, 0x54, + 0xf5, 0x1c, 0xe1, 0x1c, 0x64, 0x4e, 0x65, 0x45, 0xfd, 0xcf, 0xeb, 0xff, 0xf3, + 0xe1, 0x28, 0x25, 0x11, 0xeb, 0xe8, 0xbc, 0xf3, 0x59, 0xe1, 0xa3, 0xc5, 0xc0, + 0xc0, 0xea, 0x48, 0xaf, 0xb6, 0x0f, 0xc7, 0x06, 0xe6, 0x0e, 0x32, 0xfe, 0xf8, + 0x14, 0xde, 0x58, 0x27, 0x49, 0x1f, 0xe9, 0x3b, 0x5d, 0xde, 0x09, 0xe8, 0x04, + 0x20, 0xec, 0xf9, 0xc2, 0x25, 0x62, 0x1b, 0xbf, 0x28, 0x23, 0x09, 0x3d, 0x06, + 0xf9, 0x52, 0x3b, 0xdd, 0xf9, 0xbd, 0x8a, 0x4a, 0x1b, 0xe5, 0xfb, 0xec, 0x0e, + 0x13, 0xdd, 0xa7, 0xc3, 0xeb, 0xd4, 0x24, 0xb7, 0xc9, 0xc4, 0xe5, 0xd4, 0xc8, + 0x4d, 0x2f, 0xf9, 0x1e, 0x4a, 0xf6, 0x12, 0xf4, 0x47, 0x1d, 0xff, 0xf3, 0xfb, + 0xa2, 0xda, 0xf2, 0xfe, 0x2c, 0xf5, 0x0d, 0xbb, 0x2d, 0x07, 0x0a, 0xcd, 0x41, + 0xd7, 0xcd, 0xec, 0xbf, 0x13, 0x12, 0xf0, 0x05, 0xf3, 0xe7, 0x7f, 0x06, 0x1c, + 0x0e, 0x1c, 0xf8, 0x55, 0xd2, 0xd1, 0x16, 0x36, 0xd9, 0x1a, 0x19, 0x39, 0x34, + 0x01, 0xe4, 0xfa, 0xb7, 0x2c, 0x29, 0xf3, 0x06, 0xe8, 0xac, 0x12, 0xcc, 0x05, + 0x13, 0xee, 0x14, 0x10, 0xda, 0xf8, 0xe4, 0xc9, 0xed, 0x10, 0x0a, 0xce, 0x66, + 0xbf, 0x0a, 0x11, 0x0a, 0xdd, 0xf2, 0x1c, 0x0f, 0x26, 0xd6, 0x2b, 0x25, 0xef, + 0x01, 0xcc, 0x24, 0xfa, 0x7f, 0xe8, 0xff, 0x1b, 0xf4, 0x40, 0xd1, 0xf5, 0xf2, + 0xcf, 0xae, 0xd3, 0x01, 0xec, 0xda, 0x34, 0x11, 0x0d, 0x17, 0xe3, 0x09, 0xe3, + 0xfb, 0xe9, 0xe4, 0xf1, 0xdc, 0xaa, 0x9c, 0x58, 0x02, 0xcf, 0xff, 0xfc, 0x30, + 0x3e, 0xdc, 0xc0, 0xf9, 0x23, 0xee, 0xed, 0x15, 0xcb, 0xc6, 0xe3, 0x30, 0x36, + 0x6f, 0xc6, 0x27, 0xe3, 0xf0, 0xcc, 0xee, 0x0a, 0xe0, 0x32, 0xfd, 0x39, 0x0b, + 0x16, 0x04, 0x06, 0x58, 0x1d, 0xd8, 0x6b, 0xe8, 0x20, 0x1b, 0x08, 0x68, 0x0b, + 0xd6, 0xe5, 0x0a, 0xee, 0x2f, 0x26, 0xbf, 0xee, 0xe8, 0xc7, 0x23, 0xcc, 0x54, + 0x12, 0xef, 0x06, 0x18, 0xb7, 0x17, 0xb5, 0x2a, 0xd5, 0xed, 0xe8, 0x31, 0x39, + 0x0b, 0x07, 0xb1, 0xf1, 0x15, 0x18, 0x32, 0xe1, 0xf3, 0xda, 0x00, 0x14, 0x1c, + 0xe4, 0xf3, 0x19, 0x1b, 0x0a, 0x56, 0x09, 0x24, 0xf8, 0x19, 0x07, 0x14, 0x3c, + 0xd3, 0xa6, 0xbb, 0xe5, 0x4e, 0xfe, 0xb6, 0xc1, 0x16, 0xea, 0xcd, 0xf6, 0xf6, + 0xf2, 0x45, 0x23, 0xd8, 0xe8, 0xf4, 0xf9, 0x41, 0x2f, 0xd8, 0x0c, 0x0e, 0xb4, + 0x1c, 0xee, 0x3c, 0xbb, 0xd8, 0xe9, 0x7f, 0xe2, 0x11, 0x0d, 0x87, 0x4a, 0x58, + 0x19, 0x1f, 0xf6, 0xeb, 0xdf, 0xc0, 0xda, 0x30, 0xd6, 0xe6, 0xe6, 0x9c, 0x41, + 0x1a, 0x19, 0x1c, 0xbc, 0x6d, 0x02, 0x1b, 0x01, 0x20, 0xb7, 0x00, 0xdc, 0x0d, + 0xf0, 0xfe, 0xf9, 0x05, 0x14, 0x06, 0x20, 0xdc, 0xf7, 0x04, 0xec, 0x19, 0xf5, + 0xd6, 0xeb, 0x25, 0xd0, 0x49, 0xcc, 0x15, 0x00, 0xfe, 0xce, 0xfe, 0xe3, 0x0d, + 0x41, 0x1b, 0x0c, 0x0e, 0xec, 0xdf, 0xdc, 0x1b, 0xb8, 0x0f, 0x4a, 0xd4, 0xee, + 0x2d, 0xcf, 0x61, 0x14, 0xed, 0x28, 0xe6, 0xc1, 0x25, 0x35, 0xc1, 0x21, 0xe3, + 0x38, 0x0e, 0xe1, 0xf6, 0xe9, 0xe9, 0x08, 0xe8, 0xf7, 0xd3, 0xf0, 0x02, 0xeb, + 0x08, 0x07, 0x32, 0xf6, 0xd6, 0xfd, 0x27, 0x05, 0xf1, 0xea, 0x2d, 0xff, 0xeb, + 0xd0, 0xeb, 0xec, 0xed, 0x06, 0xfe, 0xec, 0x3a, 0x7f, 0x37, 0x23, 0xee, 0x17, + 0xd4, 0x14, 0xed, 0x48, 0x21, 0x08, 0x12, 0x17, 0x0b, 0x38, 0xca, 0xdf, 0x48, + 0x2d, 0xcb, 0x29, 0x2e, 0xf6, 0x33, 0xf7, 0xe8, 0xc6, 0xf1, 0xc9, 0xf5, 0x35, + 0x0e, 0xf6, 0xbc, 0x03, 0xf9, 0x1a, 0xfa, 0x3c, 0x07, 0x13, 0x29, 0x13, 0xe4, + 0x0f, 0x2e, 0x49, 0xec, 0xeb, 0x08, 0x07, 0x0f, 0x0e, 0xb8, 0x2e, 0xf1, 0xfb, + 0x06, 0xcb, 0x4f, 0x2d, 0xec, 0x5a, 0x00, 0x03, 0x17, 0xba, 0xe3, 0xcd, 0x01, + 0x98, 0xe3, 0x65, 0x29, 0xb4, 0x0b, 0x53, 0x3a, 0xed, 0x0f, 0x02, 0xee, 0xd0, + 0x12, 0x39, 0xda, 0x11, 0x09, 0xe0, 0x1e, 0x13, 0x08, 0x0a, 0xf4, 0xd5, 0x20, + 0xb8, 0x06, 0x29, 0x3b, 0xc3, 0xd8, 0x3d, 0x2e, 0x08, 0xe5, 0x0f, 0x02, 0xb1, + 0xf9, 0xe2, 0xef, 0x14, 0x4a, 0x09, 0xe7, 0xdf, 0x21, 0x2b, 0x2c, 0xd2, 0x39, + 0xef, 0xd5, 0x05, 0xd0, 0xff, 0xde, 0xbb, 0x0e, 0x1b, 0x0f, 0xf8, 0x01, 0x0a, + 0x4e, 0xe8, 0xd8, 0xfb, 0xf6, 0xe6, 0x01, 0x13, 0x4b, 0x00, 0xfa, 0xe6, 0xd1, + 0x11, 0x18, 0x56, 0x06, 0xf0, 0xd6, 0xf5, 0x6f, 0x09, 0x04, 0xcc, 0x01, 0xf7, + 0x2a, 0x57, 0xfc, 0xd3, 0x19, 0xfd, 0x3f, 0xc4, 0xf2, 0xe3, 0x03, 0xff, 0xff, + 0xc7, 0xc9, 0xf4, 0x0a, 0x18, 0xf0, 0x03, 0xfa, 0x06, 0xdd, 0x23, 0xc6, 0xfe, + 0xfb, 0x2d, 0x22, 0x0d, 0xd7, 0x39, 0x38, 0x11, 0xfc, 0xc5, 0x01, 0x0e, 0x58, + 0x81, 0xd7, 0xe5, 0xf7, 0x06, 0xfc, 0xfe, 0x13, 0x11, 0xe1, 0x09, 0xf1, 0xc0, + 0x39, 0x17, 0xc3, 0xcd, 0xf1, 0xf2, 0x19, 0xf2, 0xc0, 0xf5, 0x06, 0xe9, 0xeb, + 0x36, 0xe5, 0x22, 0x54, 0x08, 0xea, 0xd5, 0x4f, 0xd3, 0x0b, 0x12, 0xd2, 0x2d, + 0xf0, 0xea, 0x44, 0xec, 0xe1, 0xa5, 0x1c, 0x29, 0x0b, 0xd4, 0xd2, 0x0a, 0x50, + 0xed, 0x1a, 0x0c, 0x75, 0xfc, 0x63, 0x13, 0x09, 0x32, 0xd9, 0x03, 0x0d, 0x11, + 0xb0, 0xb5, 0x54, 0x2d, 0xd8, 0xff, 0xb2, 0x0b, 0x24, 0xf9, 0xf4, 0xc0, 0x18, + 0xf2, 0x19, 0xb8, 0x26, 0x08, 0xd1, 0xda, 0xd9, 0xf9, 0xc5, 0x22, 0xef, 0xcb, + 0x00, 0x1e, 0x06, 0x71, 0xf2, 0x7f, 0xa4, 0xfc, 0xff, 0x04, 0xd1, 0xeb, 0x04, + 0xd8, 0x48, 0xf5, 0x0e, 0xd0, 0xe9, 0x12, 0x1a, 0x07, 0xf0, 0xee, 0xb3, 0x20, + 0x19, 0x8a, 0xc8, 0xf1, 0x2d, 0x09, 0x2e, 0x19, 0x3d, 0x0b, 0x56, 0x11, 0x54, + 0x50, 0x0b, 0x00, 0x1e, 0x43, 0x19, 0x1e, 0xfa, 0x1e, 0xff, 0xde, 0x38, 0x19, + 0xf6, 0xee, 0x0f, 0x13, 0xd6, 0x04, 0x01, 0x00, 0xf2, 0x32, 0x03, 0x1b, 0x29, + 0x56, 0x23, 0xd7, 0xce, 0x44, 0x0a, 0x09, 0x04, 0x1d, 0x00, 0xf9, 0xc8, 0x3a, + 0xec, 0x36, 0x28, 0x4f, 0x2e, 0x03, 0xf3, 0xe7, 0xdb, 0xf9, 0xdd, 0x3e, 0xd1, + 0xd9, 0x60, 0xaa, 0x3d, 0xe0, 0x16, 0xe1, 0x01, 0xfe, 0xb1, 0xe4, 0x03, 0x26, + 0xb2, 0xf3, 0x2a, 0x7f, 0xbc, 0x07, 0x42, 0xa5, 0xf4, 0x09, 0x51, 0x31, 0x2f, + 0xbb, 0xe6, 0x01, 0xec, 0xf0, 0xb2, 0x38, 0x11, 0x65, 0x1b, 0x1f, 0x1d, 0xc9, + 0x36, 0xf2, 0xed, 0xd0, 0x06, 0x0a, 0xdf, 0x1d, 0x58, 0x44, 0xe7, 0x0a, 0x0f, + 0x20, 0x04, 0xde, 0x35, 0x3d, 0x04, 0x27, 0x5d, 0xfd, 0x44, 0x0c, 0x03, 0x3d, + 0x2a, 0xf9, 0xdd, 0x0a, 0xca, 0x06, 0xfc, 0xc5, 0x19, 0xd7, 0x44, 0x47, 0x17, + 0x3d, 0x31, 0x09, 0x16, 0x0e, 0xfb, 0x00, 0xdb, 0xf4, 0x17, 0x59, 0x08, 0xe9, + 0x30, 0xe0, 0x28, 0x03, 0xfe, 0x16, 0x04, 0xd0, 0x26, 0xed, 0x20, 0x34, 0xbd, + 0xc6, 0x02, 0xd9, 0xfe, 0x09, 0xf9, 0x36, 0x5f, 0x24, 0xba, 0xea, 0x2a, 0xde, + 0xd2, 0x9d, 0x9f, 0xf9, 0x02, 0x9d, 0x29, 0xb0, 0x2c, 0xca, 0x11, 0x15, 0x2c, + 0x04, 0xe4, 0xc4, 0x03, 0xba, 0x1a, 0xdd, 0x0f, 0x1b, 0x7f, 0xfb, 0x51, 0x18, + 0x10, 0x31, 0x18, 0x4b, 0x07, 0xe3, 0x22, 0xb7, 0xf5, 0xba, 0xed, 0x3e, 0x2d, + 0x16, 0xf7, 0xeb, 0x48, 0xdd, 0x1a, 0xe0, 0xdf, 0xee, 0x20, 0xca, 0xf9, 0x1b, + 0x23, 0x3e, 0xd1, 0xcd, 0xc7, 0xde, 0x62, 0x44, 0xce, 0x0d, 0xc4, 0xee, 0x17, + 0xda, 0x03, 0x35, 0xed, 0xd2, 0x4c, 0xfc, 0x5a, 0x09, 0x33, 0x5f, 0xdc, 0xe6, + 0xdc, 0x45, 0xab, 0x4b, 0x1c, 0x0b, 0xac, 0xf6, 0x2f, 0xb9, 0x4d, 0x18, 0xd5, + 0x59, 0xb1, 0x20, 0x58, 0xe4, 0xc2, 0x2c, 0x02, 0x24, 0xfd, 0x31, 0x04, 0xd4, + 0xcd, 0xe0, 0x26, 0x05, 0xe5, 0xe3, 0xef, 0xf2, 0xd3, 0x22, 0x7f, 0xdf, 0xf2, + 0xd3, 0x02, 0x08, 0xc0, 0xe3, 0xd5, 0xfc, 0xf8, 0xf4, 0xc4, 0x30, 0xd5, 0x22, + 0x0c, 0xea, 0x1c, 0xde, 0xc4, 0xf2, 0xdc, 0xe5, 0x0b, 0xbe, 0xf9, 0x66, 0x0c, + 0x05, 0xfa, 0xe1, 0xdc, 0x31, 0xdc, 0xe6, 0x13, 0x30, 0x1e, 0x1b, 0xf8, 0x01, + 0x10, 0x5f, 0x16, 0x07, 0xcd, 0x2a, 0x24, 0xec, 0xc6, 0x2d, 0x1e, 0x00, 0xf6, + 0xdd, 0xb9, 0xf3, 0xf9, 0x14, 0x35, 0xd8, 0x53, 0x07, 0x1c, 0xec, 0x52, 0xc6, + 0x14, 0xe0, 0x0e, 0x1f, 0xe7, 0x12, 0x05, 0xf1, 0x2d, 0xcf, 0xf9, 0xef, 0xf4, + 0xeb, 0xfd, 0xfc, 0x0e, 0xf7, 0xd3, 0x1a, 0xf0, 0xee, 0xd6, 0xe9, 0xf9, 0xea, + 0xc6, 0xce, 0x16, 0xd8, 0xe7, 0x01, 0x2f, 0x3d, 0x00, 0xfe, 0xee, 0xf7, 0xfb, + 0xd7, 0x1d, 0xdc, 0x4f, 0xed, 0xf8, 0x2d, 0x1d, 0xd6, 0x50, 0xd3, 0x07, 0x36, + 0x35, 0xcb, 0xde, 0xe0, 0x14, 0x03, 0xfd, 0xd4, 0xe5, 0x5b, 0xdc, 0xee, 0xf9, + 0xda, 0x23, 0x34, 0x0e, 0xee, 0xe6, 0xdd, 0x2c, 0xd8, 0xec, 0xe8, 0xd4, 0x61, + 0xf4, 0x36, 0xfc, 0x1f, 0x29, 0xeb, 0x05, 0x11, 0xe7, 0xa6, 0x14, 0x03, 0x08, + 0x0e, 0x02, 0xe3, 0xd1, 0xcd, 0x34, 0x14, 0x05, 0xf7, 0xd0, 0xce, 0x32, 0x81, + 0xff, 0xc6, 0xf7, 0x14, 0x00, 0x5b, 0xfb, 0xf6, 0x43, 0x30, 0x0e, 0x1d, 0x14, + 0x43, 0xe1, 0xcf, 0x05, 0x45, 0xe9, 0xa7, 0x0c, 0x55, 0xe7, 0x1c, 0x17, 0xc7, + 0x18, 0xd9, 0x97, 0xd0, 0xbf, 0xe3, 0x0f, 0xe0, 0xc9, 0x26, 0xe3, 0xb5, 0xc3, + 0xe8, 0x29, 0x27, 0xfa, 0xb4, 0x1d, 0xd4, 0x35, 0xce, 0x28, 0xf9, 0x30, 0xc0, + 0x24, 0xf0, 0x58, 0x08, 0xf6, 0x28, 0xe7, 0xe2, 0x19, 0x0d, 0x00, 0xd5, 0x01, + 0x26, 0xfb, 0x7f, 0xf7, 0xeb, 0xc0, 0xcc, 0xe3, 0xc3, 0xc9, 0xf8, 0x2d, 0xae, + 0x17, 0x25, 0x25, 0xbe, 0xc9, 0x2e, 0x3f, 0x94, 0x39, 0xbe, 0x01, 0xf9, 0x1d, + 0x9a, 0xb7, 0x03, 0xdd, 0xdb, 0x1a, 0xfd, 0x32, 0x0d, 0x0d, 0xf2, 0x38, 0xca, + 0x42, 0x67, 0xfc, 0x0b, 0xa9, 0xf4, 0xd4, 0x35, 0xee, 0xfa, 0x20, 0x12, 0xea, + 0x2d, 0xcb, 0xdd, 0xe3, 0xec, 0xe2, 0xf5, 0x44, 0x18, 0xef, 0x66, 0xdd, 0xfa, + 0xe2, 0xaf, 0x3e, 0xdc, 0xbc, 0xf2, 0x95, 0x4a, 0xa9, 0xed, 0x08, 0x4f, 0x0d, + 0x3d, 0x3b, 0x32, 0x3b, 0xf8, 0xda, 0x28, 0x77, 0xff, 0x00, 0x26, 0x46, 0x49, + 0xfc, 0xc8, 0xf9, 0x41, 0xd6, 0x02, 0x3e, 0xf3, 0xb4, 0xee, 0x0f, 0x3b, 0x28, + 0x2e, 0x1e, 0x0b, 0xc9, 0x37, 0x20, 0xf2, 0xed, 0x20, 0xa1, 0x06, 0xfa, 0xe0, + 0xc6, 0xca, 0x1f, 0x04, 0x23, 0x2b, 0x0f, 0x3d, 0xc7, 0x20, 0xf6, 0xd2, 0x5e, + 0xcc, 0xf7, 0xcf, 0x20, 0xca, 0xe2, 0x17, 0xba, 0x1b, 0x13, 0x01, 0xc3, 0xa7, + 0xe2, 0x66, 0xe8, 0xd6, 0xa1, 0x1f, 0x20, 0x98, 0x39, 0x1f, 0x6f, 0xeb, 0xc1, + 0x18, 0xec, 0xc6, 0x41, 0x13, 0x10, 0xff, 0xe1, 0x17, 0xe7, 0x53, 0xc9, 0x1a, + 0xd5, 0x03, 0x0e, 0x20, 0x29, 0xaf, 0x0f, 0xfc, 0x06, 0xe6, 0x1a, 0xfe, 0x47, + 0xee, 0x82, 0xa3, 0xc9, 0xfc, 0xaa, 0x9d, 0xff, 0xef, 0xd2, 0x1c, 0xff, 0x16, + 0x17, 0x9e, 0x44, 0x7f, 0x9e, 0x4c, 0xba, 0x17, 0x4c, 0xe0, 0x09, 0xca, 0xa8, + 0x45, 0x27, 0xcb, 0xdb, 0x55, 0x16, 0xf8, 0x13, 0xf2, 0xd5, 0xf8, 0xf2, 0x43, + 0x9e, 0xa4, 0x4e, 0xe7, 0x05, 0x38, 0xdd, 0x33, 0x62, 0xf9, 0xdf, 0xd6, 0x88, + 0xd1, 0xf8, 0x05, 0xcf, 0xe8, 0x57, 0xe8, 0x17, 0xe1, 0xef, 0x1d, 0x2c, 0xc7, + 0xb0, 0xcd, 0x2b, 0x88, 0x0e, 0xc5, 0xc1, 0x07, 0xff, 0xdc, 0x0f, 0x07, 0x17, + 0x49, 0xd9, 0xe5, 0x34, 0xe1, 0xe6, 0xef, 0xf2, 0xcb, 0xdd, 0x1c, 0xf6, 0x38, + 0xfe, 0xf4, 0xe5, 0x14, 0x21, 0xcc, 0x36, 0x28, 0x07, 0x4c, 0xfc, 0x03, 0xbe, + 0x2f, 0xe3, 0xf6, 0xfb, 0xfb, 0x1a, 0x1c, 0x20, 0x11, 0xe2, 0x1b, 0xc8, 0x01, + 0xf8, 0xc6, 0x1a, 0x81, 0x69, 0xd5, 0x3d, 0xfa, 0xe3, 0xef, 0xb2, 0x29, 0xe6, + 0xdd, 0x1b, 0xf8, 0xf6, 0x37, 0xf6, 0x3a, 0x5f, 0xca, 0xdc, 0x49, 0x0a, 0xcf, + 0xd3, 0xd6, 0x29, 0x6a, 0xf6, 0xeb, 0x00, 0x31, 0x2e, 0x4d, 0xf2, 0x15, 0xec, + 0xf8, 0xf0, 0x2f, 0xd3, 0xf0, 0xd6, 0x22, 0x27, 0x24, 0xf2, 0xe2, 0x20, 0x12, + 0x25, 0xfb, 0x2c, 0xec, 0xd0, 0xdc, 0x0f, 0x37, 0x09, 0xfd, 0xe6, 0xfd, 0x25, + 0xe0, 0xfe, 0x38, 0x09, 0xde, 0xf8, 0xe6, 0xed, 0xe6, 0x0f, 0xe4, 0x12, 0xd2, + 0xbf, 0xef, 0x09, 0x33, 0x1a, 0x2d, 0xe8, 0xdb, 0xd5, 0xe8, 0x2d, 0x12, 0x01, + 0x2a, 0xe3, 0x81, 0xf9, 0xd0, 0x0e, 0xd7, 0xfc, 0x1d, 0xea, 0x17, 0xf1, 0x00, + 0x4b, 0xd0, 0x0b, 0xe4, 0x10, 0xfa, 0x19, 0xd2, 0xf1, 0x11, 0xe9, 0xcf, 0xc6, + 0x16, 0x20, 0x1d, 0x04, 0x15, 0x04, 0xe5, 0xc6, 0x14, 0x2b, 0x03, 0xd4, 0xc2, + 0xfd, 0xfb, 0x10, 0xc2, 0x0b, 0xd3, 0xfe, 0x2f, 0xec, 0x16, 0xfc, 0x32, 0xdf, + 0xfe, 0xe1, 0x0b, 0xf7, 0x42, 0xfc, 0xf7, 0xc8, 0xc0, 0x38, 0xed, 0xc9, 0xd5, + 0x43, 0xf6, 0xd6, 0xc5, 0xcc, 0xf8, 0xd0, 0x20, 0xf9, 0xe2, 0x30, 0xf4, 0x27, + 0x20, 0x0d, 0x5b, 0x13, 0xe0, 0x01, 0x18, 0xe9, 0xff, 0xde, 0x00, 0x44, 0xea, + 0xdd, 0x11, 0xf8, 0x05, 0x01, 0xfb, 0x3c, 0x0e, 0xe6, 0xf2, 0xba, 0x00, 0xfa, + 0x09, 0x0d, 0x03, 0xcf, 0xec, 0x3c, 0x12, 0x05, 0xc5, 0x07, 0xd6, 0xf7, 0x2c, + 0xf3, 0x2a, 0xe9, 0x18, 0xef, 0xe4, 0x0e, 0xd0, 0x8e, 0x1c, 0xb9, 0x2b, 0xa7, + 0x1f, 0xe6, 0xfc, 0xb9, 0x54, 0xda, 0x2b, 0xd8, 0xd2, 0xee, 0xfd, 0x7f, 0x0f, + 0xfc, 0xae, 0xc7, 0xd8, 0xfd, 0x0a, 0xa7, 0xdf, 0xc9, 0x0d, 0xf8, 0xe6, 0x21, + 0x01, 0x23, 0x0b, 0x28, 0xb5, 0x30, 0xdf, 0x4e, 0xc1, 0x42, 0x37, 0xd0, 0xd1, + 0x15, 0xfc, 0xfd, 0x48, 0x24, 0xd8, 0xd3, 0x46, 0x0f, 0x2e, 0x37, 0xb9, 0xde, + 0xc3, 0x9f, 0x4b, 0x29, 0x13, 0x04, 0xc8, 0x0c, 0xdc, 0x8d, 0x47, 0x18, 0x0d, + 0x3f, 0xb9, 0x42, 0xfe, 0x17, 0x40, 0xcb, 0xd0, 0x4a, 0x0d, 0xcc, 0x05, 0x0f, + 0xd5, 0x74, 0x5f, 0x3e, 0xba, 0xcf, 0xe9, 0xf9, 0x92, 0xd7, 0xf3, 0x13, 0x28, + 0x1a, 0xbf, 0xf7, 0xcd, 0xeb, 0x32, 0x48, 0x0f, 0xcf, 0x2e, 0xec, 0x4d, 0x04, + 0x3a, 0xe1, 0xff, 0x1f, 0x29, 0xb4, 0xf6, 0xe6, 0x26, 0x0d, 0x99, 0xae, 0xbb, + 0xed, 0xfa, 0xbd, 0xea, 0xd3, 0x09, 0x57, 0x1b, 0x0f, 0x10, 0x00, 0xb0, 0x38, + 0xf8, 0xfe, 0xdf, 0xff, 0x1a, 0xd2, 0x66, 0xe5, 0x22, 0x22, 0xfe, 0xe7, 0xe2, + 0xfb, 0x7f, 0x10, 0xd2, 0xf4, 0x42, 0x59, 0x63, 0xc7, 0x52, 0x0b, 0x0c, 0xf5, + 0xda, 0x04, 0xc7, 0x09, 0xe2, 0xfb, 0xf0, 0xf7, 0x23, 0x1e, 0xb7, 0x65, 0xf2, + 0xec, 0xf5, 0x10, 0xd6, 0xae, 0xff, 0x30, 0xd0, 0x2e, 0x14, 0xc9, 0x30, 0xec, + 0x2f, 0xdd, 0xea, 0xf2, 0x39, 0x0d, 0xf0, 0xfd, 0x0e, 0x08, 0x33, 0x00, 0x05, + 0xe3, 0x01, 0x21, 0xba, 0x1f, 0xf3, 0xea, 0xe1, 0x19, 0xa8, 0xea, 0xbf, 0xf6, + 0xb2, 0x17, 0x39, 0x0f, 0x25, 0x29, 0x3f, 0x2f, 0x12, 0x0a, 0x3a, 0xdd, 0x37, + 0x26, 0xed, 0x51, 0xeb, 0xdc, 0xdd, 0x27, 0x02, 0xfe, 0x38, 0x31, 0xcc, 0xb3, + 0x17, 0x15, 0xc9, 0xea, 0xea, 0x19, 0x08, 0xf7, 0x25, 0x02, 0xdc, 0xc6, 0xd2, + 0xe8, 0x32, 0xe9, 0xe8, 0x01, 0x38, 0xc8, 0xea, 0x30, 0xdb, 0x1c, 0x05, 0x21, + 0xca, 0x9d, 0x2c, 0x1e, 0xe2, 0xa6, 0x5e, 0x68, 0xb6, 0x14, 0xee, 0xe5, 0x05, + 0x1a, 0xf7, 0xb0, 0x1c, 0xd5, 0x16, 0xcb, 0x29, 0x23, 0xe4, 0x03, 0x03, 0xd9, + 0xee, 0xb8, 0xf7, 0x4a, 0x1d, 0xc8, 0xd1, 0x70, 0x14, 0x1d, 0xf0, 0x35, 0xb7, + 0x97, 0xfd, 0x81, 0x28, 0xb7, 0x46, 0xe7, 0x10, 0x42, 0xf5, 0x2b, 0x17, 0xd5, + 0x2b, 0xb7, 0xcf, 0x60, 0xfa, 0xe4, 0xf3, 0xf2, 0xd3, 0x19, 0xc8, 0xb5, 0xda, + 0xea, 0x4f, 0x04, 0xd5, 0xe0, 0x47, 0x69, 0x4c, 0x3c, 0xe8, 0x40, 0x00, 0xc2, + 0x40, 0x99, 0xf4, 0x0a, 0x2e, 0xe6, 0xdb, 0x1d, 0x00, 0x8b, 0x0f, 0xd8, 0xfb, + 0x1d, 0x13, 0xf8, 0x36, 0x2b, 0x28, 0xfe, 0xe6, 0xc6, 0x78, 0xbc, 0x12, 0xea, + 0xa2, 0xf7, 0x26, 0x0d, 0x15, 0x31, 0x2e, 0x0a, 0xd4, 0x0f, 0xf2, 0x64, 0x37, + 0x45, 0xa7, 0xf1, 0x2a, 0xdf, 0xe8, 0x0e, 0xd8, 0xac, 0x33, 0x1f, 0xe1, 0xc3, + 0x06, 0xf5, 0x27, 0x00, 0x27, 0xd7, 0xc6, 0x23, 0xbc, 0x29, 0x31, 0xe2, 0x29, + 0xe6, 0x3f, 0xda, 0x35, 0xb8, 0x18, 0x46, 0x4b, 0x78, 0x4b, 0x24, 0xfd, 0xf8, + 0x2e, 0x11, 0x50, 0xb0, 0xe1, 0xf8, 0x5b, 0x0a, 0xf5, 0x0e, 0x18, 0xba, 0xce, + 0x1a, 0x72, 0xc4, 0x06, 0xf2, 0x0c, 0x10, 0x7e, 0xc5, 0x28, 0x55, 0xfe, 0x08, + 0xe8, 0x22, 0x9d, 0x0c, 0xcb, 0x7f, 0xb3, 0xe5, 0xe6, 0xd3, 0xa0, 0xab, 0xc6, + 0xbd, 0xfe, 0x1a, 0x15, 0xf1, 0x44, 0xfe, 0xe8, 0x1e, 0x13, 0xef, 0x11, 0xc6, + 0x4d, 0x66, 0x0d, 0xde, 0xd5, 0x41, 0xf5, 0x9b, 0x7c, 0x2c, 0x1a, 0x51, 0x08, + 0xce, 0xdf, 0xec, 0x4e, 0x4b, 0x2c, 0xfa, 0x3c, 0x09, 0xac, 0xea, 0xd0, 0x2c, + 0xfc, 0x06, 0x0f, 0x0d, 0x3b, 0xd1, 0x10, 0x12, 0x5f, 0xdb, 0x12, 0xfe, 0x01, + 0xeb, 0xcb, 0xe7, 0xb3, 0x29, 0xdd, 0xf7, 0x14, 0x0b, 0x02, 0x12, 0xe1, 0xf9, + 0x05, 0x5f, 0xfb, 0x0a, 0xed, 0xe9, 0xcd, 0x04, 0x14, 0x1a, 0xe7, 0x40, 0x1c, + 0xab, 0xfc, 0x48, 0xf4, 0x0c, 0xfc, 0xfd, 0x00, 0x0e, 0x27, 0x1c, 0x2f, 0x29, + 0x09, 0x08, 0x08, 0xf9, 0xea, 0x2e, 0x0b, 0x1f, 0x06, 0xe8, 0xe2, 0xdd, 0xff, + 0x19, 0x21, 0x55, 0x03, 0xed, 0x4d, 0xcc, 0x64, 0x09, 0x64, 0x06, 0x57, 0x11, + 0xcb, 0x08, 0xd1, 0x7d, 0x28, 0x23, 0xf9, 0x39, 0x17, 0xed, 0x0c, 0xda, 0xe0, + 0x08, 0xf4, 0x06, 0xed, 0x21, 0x06, 0xda, 0x3d, 0x1d, 0x01, 0x28, 0xec, 0xc7, + 0x2a, 0x1d, 0x1a, 0x4d, 0x2f, 0xb4, 0xf8, 0x0c, 0xe2, 0x07, 0x02, 0xd5, 0x0c, + 0xe3, 0x25, 0x03, 0x31, 0x41, 0xf8, 0xeb, 0xed, 0xe8, 0xd3, 0x1c, 0xb0, 0x12, + 0x05, 0x81, 0x26, 0x10, 0x02, 0x3d, 0x4a, 0xf3, 0xdf, 0x4e, 0xf4, 0x16, 0x27, + 0xf3, 0xee, 0xe1, 0xac, 0xd4, 0xbe, 0x1c, 0x18, 0xe9, 0x4d, 0xf9, 0xd4, 0xca, + 0x3b, 0xe7, 0xde, 0x20, 0xf3, 0x07, 0x0f, 0x07, 0xe6, 0xfe, 0xf1, 0xc5, 0x64, + 0xe4, 0x01, 0x06, 0x10, 0xff, 0xe8, 0x22, 0x1e, 0x34, 0xee, 0x47, 0x15, 0x25, + 0xbc, 0xee, 0x4d, 0x2b, 0xf6, 0xe5, 0x17, 0xc6, 0x37, 0x05, 0x13, 0x84, 0x05, + 0x1e, 0x0d, 0x0d, 0xee, 0xcf, 0x4e, 0x4a, 0xdf, 0xd7, 0xf2, 0x06, 0xfa, 0x90, + 0xd0, 0x72, 0xdc, 0xcc, 0xbc, 0x08, 0x0a, 0xa6, 0xb7, 0xf0, 0xcc, 0x13, 0xbe, + 0x5c, 0x3e, 0x08, 0x0e, 0x14, 0x02, 0x30, 0xdf, 0x3b, 0x4a, 0x13, 0xf0, 0x2f, + 0x27, 0x02, 0xdf, 0x27, 0x24, 0x23, 0xfe, 0x10, 0x08, 0x69, 0x3f, 0xbb, 0xfc, + 0x6d, 0x3d, 0x28, 0xed, 0xed, 0xed, 0x3a, 0xe3, 0xda, 0x81, 0x14, 0xd6, 0xe3, + 0xd6, 0xc5, 0xec, 0x37, 0x38, 0x25, 0x1c, 0xe7, 0x0a, 0x1b, 0x16, 0xe9, 0xfa, + 0xf4, 0xe6, 0x0b, 0x07, 0x22, 0x12, 0x16, 0xf4, 0x0a, 0xd1, 0xfe, 0x06, 0xdd, + 0xe3, 0xfa, 0x0e, 0x14, 0x25, 0x05, 0xed, 0x44, 0xf6, 0xd1, 0xeb, 0xfd, 0xf5, + 0x19, 0xe9, 0xe8, 0x1b, 0x0d, 0xed, 0x0b, 0x1c, 0x33, 0xec, 0xeb, 0xe5, 0x08, + 0x09, 0x25, 0x09, 0xe6, 0xf3, 0x01, 0x38, 0x00, 0x0d, 0x11, 0x05, 0x17, 0x0a, + 0x08, 0x08, 0xfb, 0x7f, 0xe8, 0x02, 0xff, 0x1c, 0x4d, 0xe8, 0xf9, 0xd3, 0x0f, + 0x21, 0xdb, 0xda, 0x17, 0xca, 0xf6, 0x1f, 0x07, 0x00, 0x09, 0x0d, 0xfb, 0x34, + 0x0e, 0x01, 0xfa, 0xd8, 0xf5, 0x23, 0x00, 0x48, 0x14, 0xfd, 0x0d, 0x20, 0x0d, + 0xf3, 0x03, 0x01, 0x1b, 0xf5, 0x2f, 0xf4, 0xe7, 0xe9, 0xdf, 0xb7, 0xd3, 0x1e, + 0x41, 0x0a, 0xe6, 0x18, 0xe6, 0xf7, 0xfa, 0x0f, 0x2b, 0x01, 0xe5, 0xcb, 0x27, + 0xfc, 0xf6, 0x07, 0xe0, 0xed, 0xe6, 0x12, 0xe1, 0xd9, 0xf2, 0xec, 0x19, 0x18, + 0xf3, 0xf9, 0x16, 0xd3, 0x00, 0x0b, 0x19, 0xee, 0x23, 0x02, 0x1e, 0xec, 0xfe, + 0xfd, 0xee, 0x07, 0x03, 0xe6, 0x00, 0xd9, 0xe4, 0x19, 0x07, 0x02, 0xfb, 0xf1, + 0xda, 0xbf, 0xe6, 0xd1, 0xf7, 0xf5, 0xc8, 0x14, 0x08, 0x04, 0xed, 0x7f, 0x01, + 0xd7, 0x48, 0x02, 0x0a, 0x4f, 0x05, 0xdb, 0x0d, 0x39, 0x1d, 0x00, 0xf0, 0xe6, + 0x02, 0x17, 0xd9, 0x21, 0xf4, 0xf1, 0x36, 0xe8, 0xe1, 0x07, 0xa2, 0xfc, 0xe3, + 0xf7, 0x05, 0x1c, 0x19, 0xf0, 0x19, 0x19, 0xe6, 0xe3, 0x03, 0x08, 0x1e, 0xe2, + 0x26, 0x17, 0xeb, 0x0e, 0x17, 0x33, 0xe3, 0x14, 0xef, 0xf3, 0xd6, 0xfb, 0xe3, + 0x2a, 0xd7, 0x0d, 0x16, 0x0b, 0x05, 0xf4, 0xe7, 0xf6, 0x28, 0xf3, 0x05, 0xde, + 0xab, 0xf3, 0xeb, 0xf7, 0xd2, 0xd0, 0x14, 0xfb, 0xfc, 0x0b, 0x1b, 0x18, 0xe8, + 0x14, 0x27, 0xfe, 0x3b, 0x19, 0x0a, 0xc0, 0x18, 0xef, 0x01, 0x2d, 0x04, 0x10, + 0x26, 0x33, 0x3b, 0xef, 0x20, 0xeb, 0xfc, 0x0e, 0xc7, 0x1c, 0x12, 0x22, 0xeb, + 0x23, 0xe2, 0x4f, 0x00, 0x32, 0xc3, 0x0d, 0x27, 0xb4, 0xf5, 0xca, 0xd1, 0xdf, + 0x2b, 0x8e, 0xc5, 0xe7, 0xf2, 0x15, 0xf7, 0x3c, 0xac, 0xba, 0x17, 0xec, 0xfb, + 0x0a, 0x0a, 0xc5, 0x3f, 0x93, 0x3e, 0x1c, 0xe9, 0xf3, 0xff, 0xd7, 0x2e, 0xcb, + 0x04, 0x1a, 0x1e, 0x18, 0xfa, 0x0d, 0x18, 0xdd, 0xf1, 0x55, 0x15, 0x60, 0xb8, + 0x2e, 0xd1, 0x11, 0x0b, 0x64, 0x02, 0xa6, 0x0f, 0x12, 0x06, 0x19, 0x08, 0xd9, + 0xec, 0xf5, 0xee, 0x05, 0x81, 0x5e, 0xc6, 0x16, 0x0b, 0x08, 0xf0, 0xec, 0xde, + 0x12, 0xf4, 0xe6, 0x63, 0xff, 0x22, 0xd8, 0xf3, 0xfb, 0x1c, 0xe6, 0x2d, 0x14, + 0x0b, 0x1c, 0x08, 0xb7, 0xee, 0xe9, 0x1f, 0xe4, 0x12, 0x19, 0x18, 0x09, 0xcf, + 0xcc, 0xb0, 0x21, 0xf9, 0xda, 0x08, 0x01, 0x38, 0xe7, 0x37, 0xe5, 0x04, 0xfc, + 0x30, 0x05, 0xec, 0x58, 0x12, 0x20, 0xfd, 0x11, 0x0a, 0xe7, 0x28, 0xfb, 0x01, + 0xe7, 0xec, 0xde, 0x49, 0x21, 0xf4, 0xfc, 0x19, 0x0f, 0xa5, 0xf2, 0xd2, 0xec, + 0xf4, 0x47, 0xd6, 0xc7, 0xb6, 0x5d, 0xf7, 0x0e, 0xc1, 0x36, 0xed, 0x16, 0x25, + 0xd7, 0xe6, 0x05, 0x14, 0x40, 0x3d, 0x01, 0xee, 0xdf, 0x35, 0x5c, 0xe2, 0x0a, + 0x3c, 0xf5, 0xe8, 0x0a, 0x33, 0x09, 0x2b, 0xc2, 0x03, 0x3c, 0xfe, 0xfd, 0x39, + 0xdc, 0x03, 0x12, 0xf6, 0x14, 0x07, 0xf0, 0xd8, 0x2a, 0xe0, 0x34, 0x0e, 0x13, + 0x0e, 0xfc, 0x0d, 0x39, 0x1c, 0xe3, 0x04, 0x25, 0xfd, 0x1c, 0x1d, 0xdb, 0x25, + 0xdd, 0x4a, 0x06, 0x0f, 0x0e, 0x11, 0xe4, 0x1f, 0xd6, 0xf0, 0x23, 0xec, 0x10, + 0xf5, 0x87, 0xb0, 0x36, 0xf7, 0x19, 0x2b, 0x1a, 0xbc, 0x04, 0x81, 0xdc, 0xd0, + 0xd4, 0xd7, 0x37, 0x09, 0xe8, 0xc0, 0xcc, 0x30, 0xf9, 0x25, 0xd4, 0x9f, 0x09, + 0x2c, 0xf8, 0x15, 0x71, 0x01, 0xfe, 0x20, 0xeb, 0x0a, 0xd9, 0x22, 0xe4, 0xfc, + 0x4e, 0x15, 0xef, 0xfe, 0x11, 0x3b, 0xf9, 0x1c, 0xc8, 0xec, 0xf2, 0x08, 0xf3, + 0xda, 0x24, 0xdf, 0xe4, 0x1e, 0x56, 0xfd, 0xc8, 0xf9, 0x1a, 0xec, 0xcb, 0xbb, + 0x3e, 0xfe, 0xdf, 0x4e, 0x12, 0x1d, 0x6f, 0xac, 0x01, 0x2e, 0x2f, 0xe2, 0xd3, + 0xf1, 0x05, 0xdd, 0xc4, 0xdc, 0xdd, 0xf1, 0x03, 0x0e, 0xd0, 0xdb, 0xbb, 0xb6, + 0x13, 0x42, 0x2b, 0x1b, 0x45, 0xf5, 0x16, 0xad, 0xc7, 0xf6, 0x28, 0xc5, 0xe9, + 0x45, 0x3d, 0xbd, 0x08, 0x03, 0x02, 0x86, 0x26, 0x1c, 0x2b, 0x7f, 0xf2, 0xcb, + 0xf9, 0xbd, 0x60, 0x04, 0x37, 0x37, 0xdf, 0xd6, 0x00, 0x09, 0x22, 0x17, 0x01, + 0x32, 0xd0, 0xcf, 0x3f, 0x35, 0x7b, 0x36, 0x1e, 0xcb, 0x08, 0xe9, 0x20, 0xd9, + 0x39, 0x3c, 0x20, 0x4d, 0xa2, 0x1c, 0xe4, 0xef, 0xf7, 0xd7, 0x05, 0xfe, 0xc0, + 0xe8, 0x3a, 0xff, 0x0f, 0xf2, 0xec, 0x0a, 0xe6, 0x00, 0x2f, 0xe5, 0x19, 0xa6, + 0xf1, 0xd4, 0xef, 0xd5, 0x29, 0xa5, 0x31, 0x02, 0x9c, 0xf9, 0x04, 0x08, 0xac, + 0xfb, 0xf9, 0xe1, 0xea, 0xe8, 0xd1, 0xe8, 0xe0, 0x2d, 0xb8, 0xd7, 0xde, 0x2f, + 0xc1, 0xf7, 0x0e, 0x07, 0xe8, 0x06, 0xb1, 0x4a, 0x42, 0xd1, 0x9e, 0xcf, 0x21, + 0x98, 0x7f, 0xef, 0x23, 0x30, 0xff, 0xee, 0xc5, 0xc3, 0x2d, 0x06, 0xc4, 0x34, + 0x00, 0x41, 0xb3, 0x07, 0x52, 0xf7, 0x24, 0x14, 0xee, 0xfe, 0xde, 0xf2, 0xae, + 0x11, 0xef, 0xe7, 0x21, 0xde, 0x26, 0x19, 0x1a, 0x14, 0xfb, 0xb5, 0x36, 0xcc, + 0x36, 0xf8, 0x01, 0xb9, 0xe7, 0x07, 0xe2, 0x61, 0x02, 0x3e, 0x14, 0x20, 0xd4, + 0x09, 0xf9, 0xc8, 0xe2, 0xf6, 0x11, 0x1f, 0x30, 0xd0, 0xfb, 0xfa, 0x31, 0x50, + 0x6b, 0xdb, 0xf3, 0x2d, 0xf5, 0xf1, 0xb1, 0x36, 0x00, 0xf9, 0xee, 0x01, 0x14, + 0x36, 0xe1, 0x19, 0xea, 0xea, 0xeb, 0x2d, 0x25, 0x06, 0xb4, 0x47, 0x48, 0xcf, + 0x2f, 0x00, 0xdc, 0x14, 0xd3, 0x95, 0xe1, 0x1f, 0x1b, 0xb6, 0xfe, 0xc8, 0xdf, + 0xa8, 0xc0, 0xff, 0x06, 0xca, 0xd4, 0x05, 0x07, 0x07, 0xcc, 0xa7, 0xb2, 0xca, + 0x5a, 0x7f, 0x22, 0x09, 0xc1, 0xaf, 0xaf, 0xf9, 0xf2, 0xcb, 0xde, 0x04, 0x07, + 0x91, 0x95, 0x6c, 0xd8, 0xc7, 0xaf, 0xba, 0x0a, 0xe8, 0x33, 0x35, 0x0c, 0x06, + 0xaf, 0xf7, 0xd6, 0x46, 0x39, 0xeb, 0xf2, 0x62, 0x26, 0x02, 0xec, 0x14, 0x17, + 0xee, 0x52, 0x5a, 0x1e, 0xe8, 0xe4, 0x06, 0x18, 0x12, 0x42, 0x0d, 0x42, 0xdb, + 0x23, 0xca, 0x0e, 0xfe, 0x0a, 0xfe, 0xd6, 0x23, 0xf1, 0x2c, 0x7e, 0xee, 0xae, + 0xa2, 0x33, 0x82, 0xc3, 0xe3, 0x00, 0xf0, 0xff, 0xd7, 0xd0, 0xd3, 0xf1, 0xbe, + 0x4c, 0x4f, 0xe8, 0x48, 0x0c, 0xa2, 0xdd, 0x42, 0x21, 0xc9, 0x2b, 0x8c, 0x11, + 0xf6, 0x1b, 0xcf, 0x5a, 0xd0, 0x30, 0xd4, 0x1d, 0x34, 0xf0, 0xf9, 0xcb, 0xef, + 0xb7, 0xda, 0xf5, 0x2a, 0xeb, 0xce, 0x1a, 0x8a, 0xda, 0xff, 0x78, 0xd3, 0x01, + 0x3c, 0xea, 0xf4, 0xe2, 0x34, 0x81, 0x04, 0xa4, 0x1c, 0x1a, 0x12, 0xb6, 0x62, + 0xbd, 0x11, 0xa1, 0xf3, 0x37, 0x51, 0xb7, 0x2f, 0x05, 0xd2, 0xed, 0xac, 0x44, + 0x07, 0xdf, 0x1c, 0x0f, 0xf3, 0xcf, 0xf1, 0x2d, 0xc1, 0xc0, 0xd8, 0x0b, 0x47, + 0xf9, 0x42, 0xde, 0x1d, 0x05, 0x02, 0xfd, 0x02, 0x0a, 0xae, 0x45, 0x12, 0x0f, + 0xc8, 0x29, 0xbb, 0xc0, 0x07, 0xe3, 0xd3, 0x32, 0xeb, 0x4f, 0xc7, 0x58, 0x63, + 0x96, 0xe3, 0x7b, 0xc6, 0xff, 0xe2, 0xf4, 0x48, 0x53, 0xf0, 0xda, 0x0a, 0xd4, + 0xd4, 0x19, 0x63, 0xf9, 0x0f, 0x16, 0x26, 0x1f, 0xec, 0xff, 0x18, 0x7f, 0x1e, + 0x0b, 0x13, 0x31, 0xfe, 0xf8, 0x1a, 0xec, 0x28, 0xe7, 0xcc, 0xf1, 0xe1, 0xd3, + 0xfd, 0x0e, 0xdd, 0xef, 0xeb, 0xf0, 0xae, 0x00, 0xc9, 0x10, 0xf1, 0xf4, 0xc7, + 0x16, 0x51, 0xdf, 0xe1, 0x0e, 0xef, 0x0e, 0x0b, 0x1b, 0xd4, 0xd8, 0xdb, 0xc4, + 0x21, 0xdf, 0xe5, 0xea, 0x5a, 0xe9, 0x26, 0x4f, 0x1e, 0x1e, 0x13, 0x24, 0x34, + 0x3f, 0xb9, 0xfb, 0xf3, 0xe8, 0x3d, 0x40, 0x06, 0x0b, 0x1c, 0xf0, 0x2b, 0x26, + 0xe7, 0x14, 0x18, 0xff, 0x40, 0xeb, 0x0b, 0xd6, 0x12, 0xc1, 0x45, 0xda, 0xfc, + 0x0b, 0x25, 0x14, 0x3d, 0xe9, 0xf8, 0x08, 0x52, 0x15, 0xf9, 0x01, 0xa7, 0xe4, + 0xc3, 0xee, 0xfa, 0xe3, 0x10, 0x17, 0xef, 0xea, 0x05, 0x1b, 0x0c, 0xec, 0x0a, + 0x39, 0xf1, 0xdf, 0xe3, 0xb8, 0xdb, 0xfb, 0x2a, 0xd9, 0xc8, 0x39, 0x0b, 0x1b, + 0xe0, 0xf4, 0x0e, 0xf0, 0x43, 0xb3, 0x13, 0xcd, 0xfd, 0xd0, 0xdb, 0x03, 0xe6, + 0xe4, 0xf4, 0xf1, 0xf8, 0x36, 0x01, 0x0f, 0xfe, 0x15, 0x0f, 0xf3, 0x0e, 0x35, + 0xfe, 0x04, 0xd3, 0xca, 0x00, 0xd4, 0xd9, 0x2e, 0x16, 0x48, 0x33, 0x25, 0xbc, + 0x14, 0x23, 0xf3, 0xaa, 0xec, 0xc6, 0xea, 0x08, 0x7f, 0xc1, 0x04, 0x27, 0x0e, + 0xfb, 0x54, 0xad, 0x08, 0xea, 0x1a, 0xfb, 0xe0, 0xcc, 0xf3, 0xd6, 0xd6, 0x50, + 0x20, 0xe7, 0x0a, 0xdc, 0x24, 0x05, 0xeb, 0xd4, 0xbe, 0xdf, 0xe6, 0x12, 0x0a, + 0xfc, 0x1d, 0xe7, 0xca, 0x10, 0xf9, 0x02, 0xde, 0xe9, 0xc1, 0xe3, 0xd6, 0x1f, + 0x02, 0xec, 0xda, 0x1f, 0xd3, 0x05, 0x21, 0xd8, 0x22, 0xfb, 0x11, 0x0e, 0x32, + 0x40, 0xdc, 0x05, 0xeb, 0xca, 0x31, 0x26, 0xd4, 0xf8, 0xfa, 0xf6, 0x0f, 0xcd, + 0xd3, 0x1c, 0x5f, 0xd7, 0xda, 0xee, 0x3a, 0x26, 0x14, 0xe5, 0xe0, 0xeb, 0xfa, + 0xf6, 0x0e, 0x17, 0x2d, 0xca, 0xad, 0x4d, 0x32, 0xe2, 0xfe, 0x3a, 0xed, 0xda, + 0x17, 0xde, 0xba, 0xf2, 0x2b, 0xf0, 0x0c, 0xe0, 0xca, 0x0a, 0x38, 0x04, 0x25, + 0xe9, 0x0e, 0xd2, 0x52, 0xd5, 0x20, 0x2f, 0xe5, 0x4c, 0x1d, 0x1f, 0x11, 0xdc, + 0x34, 0x3c, 0x34, 0x1f, 0xe2, 0x24, 0x0b, 0xf8, 0x25, 0x35, 0xe0, 0xf1, 0x97, + 0xf3, 0x1a, 0xfb, 0x02, 0x4b, 0xeb, 0x2c, 0x32, 0xea, 0x3e, 0xdd, 0x14, 0x2c, + 0xf2, 0x12, 0x24, 0xc7, 0xe4, 0x47, 0x67, 0x32, 0x81, 0x0e, 0x03, 0x40, 0x39, + 0x4f, 0x33, 0x15, 0x12, 0xe2, 0x26, 0xc7, 0xf9, 0x09, 0xff, 0x22, 0x3f, 0xf3, + 0x01, 0xab, 0x15, 0xd1, 0x31, 0xdf, 0xd6, 0xdf, 0x24, 0xe4, 0x10, 0x04, 0x5e, + 0x19, 0xe0, 0x09, 0xfe, 0x39, 0x10, 0x23, 0x7e, 0x17, 0x1e, 0xc7, 0xa6, 0x22, + 0x0b, 0x3f, 0x11, 0xf3, 0x05, 0x3c, 0x1b, 0x40, 0x0e, 0x44, 0xf4, 0x0d, 0x1c, + 0x0d, 0xdb, 0xe0, 0xe0, 0x30, 0x1a, 0xf6, 0xf4, 0x20, 0x4d, 0x3c, 0x01, 0xff, + 0x09, 0xd6, 0x02, 0xe8, 0x12, 0xe7, 0xde, 0xc6, 0x19, 0xe3, 0x15, 0x1e, 0x11, + 0xda, 0xca, 0x46, 0x07, 0xe9, 0xba, 0x1a, 0x1d, 0xec, 0xd5, 0xfc, 0x31, 0x18, + 0x0e, 0x55, 0x04, 0xe5, 0xd4, 0x02, 0x0c, 0xfe, 0xfe, 0xc6, 0x2c, 0xfe, 0xa2, + 0xed, 0xe7, 0x25, 0xe4, 0xfe, 0xf5, 0x55, 0x1d, 0xe7, 0x7f, 0xe6, 0x00, 0xeb, + 0x00, 0xfb, 0xde, 0xe5, 0x0a, 0xa8, 0x36, 0xe7, 0x26, 0xf4, 0xb7, 0xf7, 0x4d, + 0x05, 0xfc, 0xc3, 0xfd, 0xec, 0xfb, 0xe4, 0xfc, 0xfe, 0xe4, 0xfc, 0x20, 0xe3, + 0xd6, 0x1b, 0xf2, 0x46, 0xe8, 0x3b, 0x03, 0xe2, 0x4b, 0xec, 0x0e, 0x37, 0x14, + 0xf9, 0x2e, 0xde, 0xd6, 0x3b, 0xdf, 0x14, 0xd6, 0xec, 0x3e, 0x24, 0xeb, 0xd3, + 0xc8, 0xd6, 0x3c, 0xfd, 0xf8, 0xe9, 0xde, 0x11, 0xed, 0x08, 0x16, 0x08, 0xe4, + 0xd4, 0x0f, 0xbb, 0xe4, 0x1e, 0x1f, 0xe5, 0xd9, 0xdb, 0x31, 0x03, 0xff, 0x0d, + 0xf8, 0x3e, 0x0a, 0x7f, 0x67, 0xe0, 0xdb, 0xf6, 0x09, 0x01, 0x57, 0xf5, 0xe8, + 0x04, 0x0f, 0xed, 0x11, 0xfe, 0xe0, 0x24, 0x04, 0xfb, 0xe0, 0x28, 0xc3, 0xe0, + 0x09, 0x03, 0x41, 0xf3, 0xd7, 0xde, 0x2b, 0x21, 0xc6, 0xe7, 0x1c, 0x38, 0xe3, + 0xb8, 0xed, 0x18, 0x3b, 0x25, 0xaf, 0xfb, 0xe1, 0xd0, 0xd5, 0xf7, 0x25, 0x16, + 0xfb, 0xbf, 0xed, 0x29, 0xf4, 0x1e, 0xdc, 0xf4, 0xb8, 0x20, 0x32, 0xe6, 0xe7, + 0x11, 0xec, 0xe7, 0xff, 0x43, 0x12, 0x01, 0xf5, 0x92, 0x0e, 0xef, 0x10, 0xd3, + 0x19, 0xdf, 0xfe, 0x32, 0xf5, 0xf1, 0xf7, 0x21, 0xc6, 0x36, 0x1a, 0xf4, 0x1f, + 0xd6, 0xf4, 0xf4, 0xf4, 0xd4, 0x01, 0x17, 0x17, 0x07, 0xf6, 0x1f, 0x33, 0xf9, + 0xd2, 0x0f, 0xe7, 0x13, 0x15, 0x2f, 0xd4, 0x1c, 0xe2, 0xf0, 0x38, 0x1f, 0xfd, + 0x39, 0xee, 0xe4, 0x18, 0x14, 0xdc, 0xc0, 0xe1, 0xea, 0x20, 0xbf, 0x06, 0xda, + 0x38, 0x0c, 0xb9, 0x15, 0x0c, 0xf3, 0x27, 0xde, 0xc2, 0x18, 0xee, 0xf6, 0x1a, + 0xdf, 0x1b, 0xbc, 0x3b, 0x01, 0x6a, 0xdf, 0xeb, 0xd3, 0xc7, 0x06, 0xff, 0x58, + 0xf5, 0xbd, 0x32, 0x0c, 0xcc, 0xe2, 0x2c, 0x37, 0x9d, 0x1e, 0x0d, 0x91, 0x4a, + 0xc9, 0xb6, 0x4a, 0xc4, 0x12, 0xbd, 0xce, 0xed, 0x43, 0x15, 0x22, 0x10, 0x54, + 0xe5, 0xd2, 0x57, 0xd3, 0xe7, 0xb9, 0x18, 0x2a, 0x13, 0x43, 0xa2, 0x39, 0xec, + 0x01, 0xb0, 0x03, 0x56, 0x10, 0xf8, 0xb5, 0xfb, 0x2a, 0xbb, 0x58, 0xc4, 0x18, + 0x2f, 0xd0, 0xac, 0xfa, 0xeb, 0x04, 0xf4, 0x66, 0xfb, 0x00, 0xae, 0xb8, 0xef, + 0x52, 0x81, 0x1d, 0xef, 0xcc, 0x1a, 0x16, 0x26, 0xce, 0x20, 0x0b, 0x3f, 0x01, + 0x2c, 0xf5, 0xf1, 0xf8, 0x12, 0xec, 0xfd, 0x55, 0xf9, 0x90, 0xdd, 0x35, 0xf9, + 0xf2, 0xe2, 0x12, 0xc9, 0x0c, 0xe2, 0x0c, 0xfe, 0xd6, 0x16, 0x41, 0xe4, 0xea, + 0xce, 0x07, 0xff, 0xdb, 0x37, 0xd6, 0xd3, 0xc7, 0xd9, 0x0c, 0x11, 0x06, 0x3c, + 0x4b, 0xfc, 0x09, 0x8f, 0xd1, 0x19, 0x28, 0xfa, 0x26, 0xcc, 0xf5, 0x1b, 0x7f, + 0x08, 0x12, 0xde, 0xce, 0xd0, 0xc8, 0xc3, 0xf8, 0x1f, 0x27, 0xd2, 0x09, 0x55, + 0xbc, 0x3e, 0xc6, 0x0e, 0xcf, 0x43, 0x34, 0xbf, 0xb3, 0xe4, 0xdd, 0x0b, 0xa6, + 0x9a, 0x93, 0x7b, 0x13, 0x68, 0xff, 0x15, 0x14, 0xfe, 0x1c, 0x49, 0x38, 0xaf, + 0x46, 0xd6, 0x1c, 0x12, 0x18, 0x34, 0x10, 0xff, 0xc5, 0xe8, 0x37, 0xfe, 0xa2, + 0x00, 0x0e, 0xfe, 0x1d, 0x29, 0x15, 0xd6, 0xb3, 0x11, 0x06, 0x24, 0x16, 0x23, + 0x97, 0xbf, 0xf2, 0x89, 0x09, 0xe1, 0xf5, 0x20, 0xc7, 0x01, 0xfc, 0xa3, 0x03, + 0x28, 0xf3, 0x10, 0x30, 0x34, 0x7f, 0xce, 0x54, 0xdf, 0x42, 0x29, 0xcc, 0x0d, + 0xb7, 0x03, 0xd3, 0xec, 0xe2, 0xf1, 0x03, 0xed, 0xd4, 0x30, 0x76, 0xe5, 0x24, + 0xe8, 0x3e, 0xfd, 0x65, 0x2d, 0xe5, 0xe8, 0xea, 0x13, 0x0e, 0x45, 0xf7, 0x1d, + 0xd6, 0x34, 0x23, 0x06, 0xb4, 0x25, 0x26, 0x53, 0xac, 0x18, 0xdf, 0xf4, 0x32, + 0x1a, 0x3f, 0xf6, 0x07, 0x18, 0x00, 0xf8, 0xa5, 0x0c, 0xfa, 0xf3, 0x3b, 0xd7, + 0x22, 0xb6, 0x65, 0xe4, 0xf9, 0x4c, 0x06, 0xc4, 0xf2, 0x05, 0x45, 0xe7, 0x3f, + 0x07, 0xf7, 0xea, 0x4b, 0xff, 0xb5, 0xbd, 0x53, 0xfa, 0xe9, 0xc5, 0xde, 0x6d, + 0x50, 0xc3, 0xfb, 0xc8, 0x06, 0x04, 0xcc, 0x13, 0x16, 0x14, 0xbd, 0xce, 0x18, + 0xc4, 0xee, 0xc0, 0xe4, 0xe2, 0xe5, 0xf9, 0x17, 0xb4, 0x25, 0x82, 0x1e, 0x3b, + 0x15, 0x13, 0x2e, 0xd8, 0x00, 0x3a, 0x18, 0xfc, 0xe6, 0xf7, 0xf2, 0xf0, 0xec, + 0x1b, 0x19, 0xf5, 0x3e, 0x86, 0x1e, 0x1a, 0x31, 0xc6, 0xf7, 0x01, 0x00, 0xf9, + 0x3d, 0x27, 0xfa, 0xd5, 0x0b, 0xef, 0x7f, 0x06, 0x26, 0xc3, 0xf5, 0xad, 0xe9, + 0x2a, 0x8b, 0x09, 0x7f, 0x21, 0x4f, 0x1d, 0xf0, 0x5e, 0x5b, 0xe0, 0xf7, 0x53, + 0x2a, 0x1e, 0xd7, 0xed, 0x09, 0x55, 0xda, 0xed, 0xcd, 0x25, 0x06, 0x05, 0x57, + 0xd8, 0xc8, 0x99, 0x01, 0xc7, 0xd3, 0x16, 0x20, 0x0f, 0x20, 0x03, 0xb3, 0xd2, + 0x28, 0x54, 0x0b, 0x5d, 0x25, 0xaa, 0x83, 0xa2, 0x71, 0x14, 0xdc, 0x63, 0x50, + 0xee, 0xf4, 0x33, 0x12, 0x06, 0x0d, 0x8e, 0xce, 0xd3, 0xbc, 0xf3, 0x08, 0x07, + 0xf0, 0x0c, 0xd3, 0x1d, 0xba, 0x0b, 0xd8, 0x30, 0x37, 0xdc, 0xc5, 0xce, 0xfe, + 0xbc, 0xee, 0xd0, 0xf2, 0xec, 0x38, 0xbf, 0xee, 0xcb, 0x2b, 0x78, 0xfb, 0x1b, + 0x19, 0xd6, 0xce, 0xdd, 0xfe, 0x34, 0x31, 0xf5, 0xd2, 0xfd, 0xc9, 0xf4, 0x0b, + 0xff, 0xf2, 0x52, 0xee, 0xd4, 0xbd, 0x91, 0xdc, 0xf9, 0x81, 0xf4, 0xbd, 0xcc, + 0xea, 0xe6, 0xe6, 0x12, 0x45, 0xcf, 0xef, 0xcc, 0x0c, 0xe2, 0x2d, 0x32, 0xca, + 0x36, 0xdd, 0x2c, 0x0e, 0x18, 0x18, 0x2b, 0x02, 0x14, 0x19, 0x1a, 0xf9, 0xfe, + 0x46, 0xf3, 0xb3, 0xd1, 0xed, 0xe6, 0x1e, 0xee, 0x35, 0x3e, 0xbb, 0x31, 0x91, + 0xdd, 0xd3, 0x40, 0x3a, 0x2d, 0xb9, 0x24, 0xb3, 0x49, 0xe4, 0xf2, 0xef, 0x32, + 0x27, 0xcb, 0xd3, 0x09, 0x12, 0x18, 0x08, 0xc3, 0xc0, 0x0b, 0xd3, 0xe0, 0x08, + 0xfa, 0x1a, 0xfe, 0xf0, 0x2b, 0xc1, 0x2b, 0x51, 0x23, 0x04, 0xc9, 0xed, 0xa8, + 0x10, 0xfe, 0x11, 0x07, 0x33, 0x12, 0xf6, 0x09, 0x40, 0x28, 0xf7, 0x05, 0xe9, + 0xe5, 0xeb, 0x49, 0x45, 0x08, 0x43, 0x26, 0xf9, 0xa9, 0x77, 0x00, 0x07, 0xaa, + 0xdd, 0xd1, 0xe4, 0xbe, 0xf0, 0x17, 0xfd, 0x47, 0xee, 0xf4, 0x19, 0x4e, 0xd5, + 0xb5, 0x24, 0xfa, 0x04, 0xfd, 0x2b, 0x04, 0xc2, 0x4b, 0x25, 0xed, 0x1f, 0xe1, + 0xfc, 0xb6, 0xeb, 0x30, 0xfa, 0x03, 0xf7, 0x33, 0x03, 0xd6, 0x1d, 0x10, 0x90, + 0xd2, 0xb8, 0x04, 0x17, 0xb6, 0x14, 0xe0, 0x27, 0xf4, 0x28, 0x15, 0xd3, 0xeb, + 0x24, 0x0b, 0x98, 0xb7, 0xc5, 0x63, 0xef, 0x1d, 0x02, 0xc1, 0x23, 0xaf, 0x75, + 0x24, 0xca, 0x17, 0xb6, 0xb8, 0x34, 0xcf, 0x2e, 0x1b, 0xd6, 0x47, 0xbe, 0x45, + 0xff, 0xdb, 0xff, 0xea, 0x45, 0xf3, 0x27, 0xb8, 0xff, 0xd2, 0xdc, 0x18, 0xb4, + 0xbe, 0xe5, 0xe3, 0xdf, 0xa9, 0xd6, 0xf6, 0xfb, 0xc1, 0xee, 0x09, 0x00, 0x28, + 0x8a, 0x24, 0x00, 0xe3, 0x81, 0xd7, 0x1d, 0xc1, 0xd6, 0x23, 0xad, 0x2c, 0xd1, + 0xa7, 0x01, 0xe6, 0x0b, 0xb0, 0x07, 0x00, 0x29, 0xfa, 0xc5, 0xd3, 0xd1, 0xcb, + 0xc6, 0x28, 0xe7, 0xb6, 0x20, 0x2d, 0xee, 0x00, 0x07, 0xc3, 0xf8, 0xf5, 0xf2, + 0xc3, 0x28, 0x2f, 0x1e, 0x34, 0xe3, 0xf0, 0xcf, 0xe1, 0xec, 0x2c, 0xdb, 0x0c, + 0x17, 0xe4, 0xfa, 0xd0, 0xfe, 0xed, 0x32, 0x0c, 0xdc, 0xdd, 0xe8, 0x4d, 0x10, + 0xfe, 0xe4, 0xfd, 0xf1, 0x03, 0xf7, 0xdd, 0xf6, 0xe5, 0xe7, 0x14, 0xc7, 0xfe, + 0x09, 0xc4, 0x33, 0x19, 0x15, 0x39, 0x07, 0x2e, 0xca, 0x06, 0xcb, 0x7f, 0x07, + 0x07, 0xf8, 0xf3, 0xe8, 0xd9, 0x29, 0xec, 0xf6, 0xe1, 0x06, 0xca, 0x0b, 0xfe, + 0xce, 0x05, 0xe6, 0x22, 0xfb, 0xe5, 0xd5, 0xd1, 0xbe, 0x03, 0x06, 0x20, 0x24, + 0x18, 0xe8, 0x11, 0xc7, 0xed, 0xf0, 0x1e, 0xfc, 0x10, 0xcb, 0x17, 0x00, 0x1f, + 0x20, 0x04, 0xdd, 0xe9, 0x0a, 0x45, 0x35, 0x2b, 0x08, 0xfa, 0x4d, 0xcb, 0xd6, + 0xd9, 0x0d, 0xd1, 0x1e, 0xee, 0xda, 0x09, 0x60, 0xfd, 0xf1, 0x3d, 0xf2, 0xfa, + 0x0f, 0x27, 0x73, 0xd7, 0x78, 0x21, 0xeb, 0xc7, 0xec, 0x1f, 0x40, 0x04, 0x52, + 0xdb, 0x13, 0xe5, 0xf6, 0x09, 0xef, 0xc2, 0xef, 0x0d, 0x45, 0xd5, 0x06, 0x41, + 0x14, 0xee, 0xe8, 0x0a, 0x15, 0xf1, 0x62, 0xe0, 0x05, 0xe7, 0x14, 0xff, 0x11, + 0xf1, 0xf7, 0x7f, 0x02, 0x41, 0xd9, 0x12, 0xf7, 0xe7, 0xdb, 0x03, 0xf0, 0xc7, + 0xc0, 0xe2, 0x0b, 0xf1, 0x33, 0xf1, 0x29, 0xe0, 0xf1, 0xe9, 0xc3, 0x37, 0xd0, + 0xf1, 0x18, 0xe7, 0xbb, 0x0a, 0xf5, 0xf8, 0x27, 0x19, 0xdd, 0x25, 0x0f, 0x25, + 0x2d, 0xff, 0x2b, 0xcf, 0x02, 0x0e, 0x00, 0x19, 0xc8, 0xee, 0x12, 0x15, 0xd6, + 0x09, 0xf6, 0xcf, 0x10, 0xfd, 0x0f, 0xe1, 0xba, 0xfe, 0x09, 0x0d, 0x2a, 0xdf, + 0x34, 0xeb, 0xfc, 0x3b, 0xf4, 0x24, 0xf9, 0xf4, 0xfb, 0xe7, 0xdc, 0xeb, 0x1c, + 0xf0, 0x5c, 0xe6, 0x0f, 0x0b, 0x41, 0xce, 0xec, 0xe1, 0xad, 0x10, 0x19, 0x10, + 0x02, 0x28, 0x15, 0xdc, 0x10, 0xf8, 0xdb, 0x3e, 0x43, 0xec, 0x27, 0xfd, 0x1c, + 0xc2, 0x49, 0xee, 0xed, 0x06, 0x09, 0xfb, 0x3e, 0x4d, 0xd2, 0x25, 0x1d, 0x01, + 0x09, 0x01, 0xfd, 0xef, 0x3e, 0xe1, 0xd6, 0x05, 0x0e, 0xfc, 0x1c, 0xd2, 0xd6, + 0x3f, 0xe3, 0xff, 0xfb, 0xf8, 0x5a, 0xe8, 0x2d, 0x0a, 0x10, 0xb0, 0x1b, 0x70, + 0xa0, 0xbc, 0xdc, 0xb8, 0xb6, 0x23, 0xde, 0x42, 0xe7, 0x64, 0x51, 0xe8, 0x1b, + 0xa1, 0x07, 0x3f, 0xc3, 0xcd, 0x4a, 0xdb, 0xa0, 0xb4, 0x2e, 0x19, 0x35, 0x23, + 0x55, 0xf4, 0x07, 0xf7, 0x1c, 0xb8, 0x07, 0x09, 0x2d, 0x25, 0x56, 0xe9, 0xed, + 0x0d, 0x19, 0x25, 0xf2, 0xfa, 0xe4, 0x08, 0xa0, 0xed, 0xe8, 0x2e, 0x07, 0xdd, + 0x47, 0x7f, 0x12, 0xdb, 0xd0, 0x18, 0x37, 0x32, 0x07, 0xe2, 0xc6, 0xfa, 0xf6, + 0x1e, 0x43, 0x34, 0x0d, 0x5e, 0xce, 0xd7, 0xc8, 0xc0, 0xe2, 0xee, 0xf9, 0x1b, + 0x4c, 0x15, 0xfd, 0xf7, 0x19, 0xe7, 0x0e, 0x19, 0xb0, 0x0b, 0x25, 0x81, 0xf3, + 0x04, 0xe3, 0xe8, 0x1a, 0xd9, 0xdb, 0xee, 0xee, 0x3b, 0x10, 0xe1, 0xce, 0x0f, + 0xca, 0xec, 0x75, 0x48, 0x31, 0xcd, 0xef, 0xf9, 0xcb, 0xee, 0x07, 0xe5, 0x56, + 0xf3, 0x0f, 0x3e, 0xc9, 0x65, 0xe5, 0x3c, 0x0f, 0xd5, 0xd8, 0xf7, 0xfc, 0xf7, + 0xea, 0xdb, 0x09, 0xce, 0xfb, 0xc9, 0xb9, 0x5d, 0xf7, 0xdb, 0x13, 0xd7, 0x09, + 0x1d, 0x24, 0xec, 0xed, 0xe4, 0x5e, 0xdd, 0xc7, 0x1d, 0x0c, 0x25, 0xe2, 0xed, + 0x18, 0xbc, 0x1f, 0xfe, 0x23, 0xfe, 0xe5, 0xf2, 0xae, 0x17, 0xb3, 0x23, 0x62, + 0xef, 0xd5, 0xfc, 0xe0, 0xe0, 0xe0, 0xc1, 0xfd, 0xf6, 0x0f, 0xd1, 0x07, 0x08, + 0x03, 0xe2, 0xe2, 0x05, 0x18, 0x00, 0x2b, 0xfe, 0x00, 0xa6, 0xdf, 0x30, 0x11, + 0xf5, 0x17, 0x0b, 0xd7, 0xf0, 0xc3, 0x29, 0xfc, 0xd0, 0xe9, 0xe9, 0x0a, 0xce, + 0x35, 0xdb, 0x2b, 0xee, 0xc5, 0x0b, 0x10, 0xa7, 0x15, 0x18, 0x0f, 0xb5, 0xf4, + 0x2e, 0x0a, 0x22, 0xe9, 0x2c, 0x2f, 0xcd, 0x09, 0x63, 0xcb, 0x06, 0xeb, 0x28, + 0xdc, 0x40, 0x7f, 0xeb, 0x47, 0x25, 0xf8, 0x06, 0x76, 0x10, 0x24, 0x68, 0xa0, + 0x05, 0x2a, 0x02, 0xbf, 0xf3, 0x09, 0x5f, 0x2c, 0xe4, 0xd7, 0x01, 0xdb, 0x1b, + 0x25, 0x1e, 0xeb, 0xe4, 0xcb, 0x21, 0xe2, 0x06, 0xcf, 0xc3, 0x58, 0x03, 0x61, + 0x1b, 0x4b, 0xcf, 0x05, 0x29, 0xe4, 0xca, 0xe3, 0xe3, 0xdd, 0xfc, 0xe3, 0xba, + 0xd8, 0x0c, 0x0c, 0xe4, 0xfc, 0x0e, 0x1a, 0xf2, 0x16, 0x2d, 0x14, 0x06, 0xda, + 0x52, 0xee, 0xdc, 0xf4, 0xf7, 0xfe, 0x07, 0x2c, 0xd5, 0xd7, 0xfd, 0x03, 0x05, + 0xc4, 0x12, 0xeb, 0xdd, 0x0d, 0x0b, 0x4a, 0xd1, 0xf8, 0xc4, 0x22, 0x15, 0x02, + 0xf8, 0xf8, 0x12, 0x13, 0xf9, 0x17, 0xb0, 0x06, 0xc4, 0x1a, 0x23, 0x3b, 0xfd, + 0xee, 0xb7, 0x03, 0x14, 0x3a, 0x1b, 0x48, 0xd6, 0x2c, 0x36, 0x3c, 0xb3, 0x18, + 0x09, 0x0c, 0x08, 0x01, 0x5a, 0xf0, 0x21, 0xc3, 0x2b, 0x08, 0xce, 0xbb, 0xec, + 0x21, 0xa5, 0x20, 0xbd, 0xe0, 0xe9, 0x1d, 0x2d, 0x06, 0x55, 0x50, 0x14, 0x92, + 0xcd, 0x3b, 0x76, 0xdc, 0xfc, 0xf0, 0x69, 0x0a, 0x36, 0x35, 0xc5, 0x7b, 0x06, + 0x73, 0x0a, 0xfb, 0x11, 0xcb, 0xdf, 0x47, 0xd9, 0x0f, 0xc1, 0x30, 0x23, 0xc1, + 0xf8, 0x15, 0x3d, 0x2c, 0x05, 0x63, 0x35, 0xfa, 0x15, 0x0e, 0xe4, 0xea, 0x2c, + 0xb2, 0x19, 0xd9, 0x81, 0xf4, 0x33, 0x35, 0xfc, 0xc6, 0xec, 0x0c, 0xcc, 0x89, + 0x5d, 0xcd, 0x02, 0xf5, 0x27, 0x2b, 0xcf, 0xb7, 0xf0, 0xb6, 0x03, 0x29, 0x2b, + 0x71, 0x1c, 0xe9, 0x11, 0x23, 0xeb, 0x1b, 0x40, 0xed, 0x27, 0x6d, 0x56, 0xdb, + 0xac, 0xf9, 0xaf, 0x08, 0x22, 0xf0, 0x15, 0x13, 0x00, 0x2d, 0x29, 0xf2, 0xa7, + 0x16, 0xee, 0x28, 0x3a, 0x21, 0x17, 0xef, 0x10, 0xfc, 0xde, 0x12, 0x1f, 0x32, + 0xc9, 0x09, 0x5c, 0x0f, 0xe9, 0xc9, 0x0a, 0x11, 0x29, 0x1f, 0x1f, 0xb0, 0xd7, + 0x34, 0xd6, 0xe5, 0xe9, 0xe6, 0x48, 0x0c, 0xe7, 0xdd, 0x0c, 0x12, 0xfb, 0xdc, + 0x49, 0xec, 0xd8, 0x00, 0xd8, 0xe7, 0x38, 0xff, 0xf6, 0x47, 0xe0, 0xfe, 0xfc, + 0x28, 0xdf, 0x09, 0xcf, 0x2b, 0xdc, 0xe7, 0xc3, 0x2c, 0x3b, 0xe3, 0x21, 0x14, + 0x3b, 0xec, 0x1a, 0x23, 0x0a, 0x0e, 0xd6, 0x1a, 0x2b, 0x23, 0xfb, 0xff, 0xdf, + 0xe5, 0xf2, 0x1d, 0x16, 0x04, 0xf2, 0x44, 0xbf, 0xd8, 0xe2, 0xd5, 0x14, 0x00, + 0x23, 0x03, 0x0f, 0x81, 0xd1, 0xda, 0xb4, 0xc3, 0x08, 0xfd, 0xf6, 0xfc, 0xee, + 0xef, 0x10, 0x41, 0xc5, 0x44, 0x12, 0xff, 0xf4, 0xf8, 0xc1, 0xdc, 0xf2, 0x27, + 0x0a, 0x0c, 0x04, 0x0b, 0xe7, 0x0d, 0x05, 0x20, 0x34, 0xed, 0xe4, 0x3e, 0xfe, + 0x01, 0xfd, 0x08, 0xd1, 0x04, 0xf2, 0x22, 0xe3, 0x1c, 0x09, 0x26, 0xf6, 0xe2, + 0x47, 0xee, 0xf4, 0xc9, 0xe8, 0xd1, 0xf7, 0x5d, 0xed, 0x9d, 0x2a, 0x34, 0xee, + 0xc9, 0xd7, 0xcf, 0xf6, 0xff, 0x0d, 0x10, 0xfb, 0xb6, 0x0d, 0x18, 0x29, 0xde, + 0x9d, 0xd3, 0x35, 0xeb, 0xe0, 0x34, 0xe8, 0x53, 0x02, 0x1a, 0xd5, 0xda, 0x10, + 0xad, 0xc4, 0x10, 0x81, 0xe8, 0x39, 0x43, 0x05, 0xe7, 0xfb, 0x0c, 0xe1, 0xc8, + 0xe9, 0x13, 0x28, 0x54, 0xf9, 0xcb, 0xcf, 0xe3, 0x02, 0xd9, 0x16, 0xe7, 0xce, + 0xf3, 0x12, 0xe2, 0x19, 0xff, 0xcb, 0x26, 0xc0, 0xa8, 0xa7, 0x3e, 0x15, 0x03, + 0xdf, 0x41, 0xf2, 0xf2, 0x07, 0xbb, 0xe1, 0xbb, 0x00, 0xde, 0x1c, 0xf6, 0x06, + 0xcf, 0xdb, 0xd8, 0xf4, 0x21, 0x1f, 0x30, 0xeb, 0xc7, 0xf1, 0xd4, 0x25, 0x2a, + 0x0d, 0xad, 0x03, 0x0a, 0x02, 0x14, 0x2c, 0x12, 0x0a, 0x32, 0x0b, 0x36, 0xb4, + 0xf6, 0xf3, 0xfa, 0x72, 0xf9, 0xd0, 0x32, 0xaa, 0xd0, 0x0b, 0xbc, 0x2f, 0x29, + 0x3e, 0xea, 0xf1, 0xd8, 0xb4, 0x64, 0x2e, 0xc6, 0xcb, 0x18, 0x11, 0xe9, 0xd8, + 0xdd, 0xe7, 0x0c, 0x36, 0x0c, 0x1c, 0x16, 0xe0, 0x17, 0x1d, 0x0e, 0xd3, 0x99, + 0xb9, 0xee, 0xf7, 0xe7, 0xe0, 0xf2, 0xd2, 0x68, 0xc9, 0xe7, 0xe6, 0x17, 0x27, + 0x37, 0xf4, 0x7f, 0x16, 0xea, 0x3c, 0xc3, 0x20, 0x15, 0xf4, 0xf4, 0x09, 0x3e, + 0x39, 0x23, 0xd6, 0xdf, 0x18, 0x35, 0xd0, 0xd9, 0xb9, 0x2a, 0xd6, 0x23, 0xe4, + 0xbb, 0xe1, 0xd1, 0x0e, 0xae, 0x3f, 0xff, 0xa7, 0x0f, 0x26, 0x0c, 0x04, 0x03, + 0xcb, 0xe1, 0xff, 0xff, 0xf8, 0xd4, 0xe9, 0x14, 0xd7, 0x09, 0xee, 0x44, 0xe3, + 0xeb, 0xee, 0xfe, 0x0a, 0xf5, 0xf0, 0x20, 0xe5, 0x4c, 0xf1, 0x10, 0xf1, 0xf5, + 0xce, 0x23, 0xe0, 0xfe, 0xe7, 0xe5, 0x0b, 0x0d, 0x20, 0xe0, 0x0e, 0xdf, 0xf5, + 0xed, 0x7f, 0xf7, 0xf4, 0x33, 0x09, 0x45, 0xf2, 0xf3, 0x1f, 0x0d, 0x0f, 0x1c, + 0x32, 0x03, 0x04, 0x69, 0xff, 0x6e, 0x5a, 0xf1, 0xfc, 0x07, 0xf5, 0x07, 0xcd, + 0xdc, 0x0c, 0x4e, 0x2a, 0x2b, 0x28, 0x21, 0x20, 0xf3, 0x9e, 0xe3, 0x1d, 0x17, + 0xfe, 0x03, 0xa3, 0x07, 0x17, 0x14, 0xee, 0xed, 0x34, 0x10, 0xaa, 0x3c, 0x23, + 0xe8, 0x02, 0x28, 0x1c, 0xb9, 0xad, 0xe6, 0x4c, 0xaa, 0xb2, 0xfa, 0x1c, 0xfa, + 0x23, 0x62, 0x00, 0xf3, 0x32, 0xd2, 0x1f, 0xf0, 0xaa, 0x06, 0xf8, 0x9f, 0x2b, + 0x2c, 0xdc, 0xd7, 0xdb, 0xa9, 0xd6, 0xef, 0x0e, 0xe1, 0x08, 0xfe, 0x3d, 0x02, + 0xfa, 0xf7, 0x0b, 0x0f, 0xdf, 0x4d, 0x38, 0xf5, 0xea, 0x07, 0xea, 0xfa, 0x22, + 0xf0, 0xfb, 0x22, 0xe6, 0xd7, 0xdc, 0xdc, 0x65, 0x25, 0xf5, 0xdf, 0xc9, 0x09, + 0xe3, 0x4d, 0x0f, 0xee, 0xcb, 0x00, 0xf8, 0x5e, 0xd2, 0xc1, 0xfb, 0xd9, 0x2d, + 0x17, 0x93, 0x29, 0xf2, 0xfe, 0xe9, 0x8d, 0xba, 0xd8, 0xda, 0x39, 0x1b, 0xec, + 0xe7, 0xdc, 0xcb, 0xc4, 0xe7, 0x14, 0xdf, 0xd5, 0xce, 0xf2, 0x24, 0x2f, 0x3d, + 0xc0, 0xc9, 0x08, 0xa8, 0xf7, 0x2c, 0xf2, 0xce, 0x33, 0xcb, 0x39, 0x2d, 0x0c, + 0xdf, 0xaf, 0xd2, 0xda, 0xb9, 0x9e, 0x25, 0xbe, 0xa7, 0x12, 0x8e, 0x0b, 0xdc, + 0xe9, 0x23, 0xdd, 0xea, 0xb0, 0x4c, 0xdd, 0x1d, 0xc3, 0x0e, 0xd8, 0x37, 0xf2, + 0x0a, 0x01, 0x36, 0x00, 0x81, 0xeb, 0x40, 0xee, 0xb7, 0xee, 0xf3, 0x49, 0x35, + 0xdc, 0xbc, 0xd3, 0xe3, 0xf2, 0x0c, 0x19, 0xfd, 0xb0, 0xb7, 0x37, 0xe2, 0xda, + 0x32, 0x22, 0xe4, 0xe7, 0xc6, 0xeb, 0x01, 0x38, 0xc5, 0x2a, 0x34, 0x57, 0x52, + 0x34, 0xec, 0x09, 0xfc, 0x0e, 0x03, 0xcc, 0xde, 0xb4, 0xe9, 0x19, 0x16, 0x38, + 0x31, 0xff, 0xf1, 0xc2, 0xf6, 0xbb, 0x06, 0x22, 0x0e, 0x3e, 0xfc, 0xae, 0x12, + 0xf5, 0xe9, 0xc3, 0xed, 0x21, 0x58, 0x74, 0x3e, 0x00, 0xf9, 0xc3, 0x21, 0x29, + 0xfd, 0x0e, 0xdb, 0x17, 0xdb, 0xe4, 0xe6, 0xfc, 0xe9, 0xfa, 0x35, 0x11, 0xf2, + 0xdc, 0x2e, 0x3a, 0xf5, 0x1e, 0xf7, 0xd5, 0x05, 0xe3, 0x3c, 0xec, 0x0a, 0xbf, + 0xc6, 0xf2, 0x08, 0xf0, 0x04, 0xdf, 0x04, 0x23, 0xf6, 0xfb, 0xef, 0x45, 0xaf, + 0x06, 0x35, 0xec, 0xfd, 0x04, 0xe4, 0xeb, 0xf6, 0x06, 0xe0, 0x0e, 0x12, 0xf2, + 0xfc, 0xda, 0x13, 0x66, 0xe9, 0xde, 0xfe, 0xdd, 0x24, 0xf5, 0xd1, 0xed, 0xf3, + 0xc4, 0x33, 0xcb, 0x28, 0xe0, 0xfb, 0x19, 0xf2, 0xf3, 0xed, 0xe9, 0xdc, 0xf8, + 0x01, 0x0a, 0xf3, 0x01, 0xd7, 0xf6, 0xf6, 0x16, 0xea, 0xcb, 0x7f, 0xdf, 0xee, + 0xca, 0xbd, 0x1e, 0xe9, 0xe3, 0xd3, 0xf0, 0x49, 0xd5, 0xee, 0x0b, 0xed, 0xf5, + 0x24, 0xd7, 0x20, 0xf2, 0xcc, 0x21, 0xf2, 0x2e, 0xd7, 0xde, 0xe6, 0x02, 0xcc, + 0x37, 0xd1, 0xd5, 0x0e, 0x32, 0x42, 0x0c, 0xff, 0xd8, 0x5e, 0x46, 0xe6, 0xe5, + 0xec, 0xfa, 0xe3, 0xd1, 0xdf, 0x2d, 0x30, 0x1f, 0xde, 0xf9, 0xe6, 0xef, 0xdc, + 0x09, 0xdc, 0xe9, 0xcf, 0x2a, 0x03, 0xbc, 0xd0, 0x2e, 0x77, 0x30, 0xe5, 0xe7, + 0x2d, 0xc2, 0xf5, 0xcb, 0x0f, 0x1e, 0x7f, 0xf8, 0x2d, 0x07, 0x24, 0xf6, 0x24, + 0xc3, 0x14, 0x76, 0x0e, 0xee, 0x04, 0x05, 0xf0, 0x31, 0xed, 0xa1, 0xe1, 0x30, + 0x13, 0x26, 0xf4, 0xe4, 0xa4, 0xca, 0xbf, 0x22, 0xd9, 0x58, 0xd1, 0xde, 0xd3, + 0xff, 0x2f, 0xca, 0xf4, 0x72, 0xe8, 0xd3, 0xe0, 0xfb, 0x0a, 0xf7, 0x26, 0x07, + 0xdb, 0x3e, 0xe7, 0x45, 0xf1, 0x19, 0x09, 0xdf, 0xcd, 0x3d, 0x0c, 0x25, 0x16, + 0x0e, 0xe6, 0xd8, 0xe4, 0x2b, 0x06, 0x1d, 0x37, 0x12, 0xee, 0x0e, 0x49, 0x0f, + 0x1d, 0x29, 0xe2, 0x11, 0xec, 0xb7, 0xff, 0x3a, 0xce, 0x07, 0xd5, 0x14, 0xfb, + 0xfa, 0xc2, 0x06, 0x7f, 0x19, 0x0d, 0x06, 0xf7, 0x3c, 0xcb, 0xf0, 0x68, 0x1a, + 0xf1, 0xdf, 0xf3, 0x22, 0x1e, 0xe5, 0x0d, 0xde, 0x1c, 0xcd, 0xda, 0x09, 0xe4, + 0xf9, 0xed, 0xd5, 0xf7, 0xe4, 0xaa, 0xe6, 0x99, 0xe3, 0x1a, 0x02, 0x16, 0xa8, + 0x22, 0xee, 0x37, 0x03, 0xf0, 0x3c, 0xd7, 0xe4, 0xbf, 0xb1, 0xd2, 0x1b, 0x69, + 0x51, 0xe5, 0x16, 0xf7, 0x03, 0xb2, 0x9a, 0xbe, 0x04, 0xe6, 0xe3, 0x1b, 0x05, + 0x0a, 0x07, 0x08, 0x21, 0xd5, 0xf7, 0x0a, 0x0e, 0x1a, 0xda, 0x12, 0x33, 0xf8, + 0x24, 0xf2, 0x4d, 0x01, 0x0c, 0x31, 0xe6, 0xd7, 0xcb, 0xf9, 0x09, 0x1a, 0xdf, + 0x02, 0xb3, 0xd2, 0x13, 0xe8, 0x0e, 0x1b, 0x42, 0xcd, 0x00, 0x2a, 0x34, 0x73, + 0xca, 0xc5, 0x25, 0x07, 0x08, 0xf6, 0x3b, 0xcb, 0x0e, 0xbf, 0x07, 0xf0, 0xc7, + 0x33, 0xf0, 0xdc, 0x40, 0x09, 0x5b, 0xc3, 0x00, 0x5f, 0xcd, 0xf0, 0xf3, 0x38, + 0xf9, 0x42, 0xe1, 0x07, 0x04, 0x36, 0x2a, 0xd1, 0xba, 0xfc, 0x62, 0xd4, 0x0f, + 0xe3, 0x7f, 0x2e, 0xee, 0x65, 0xd1, 0xdb, 0xbd, 0x35, 0x03, 0x47, 0xfd, 0x9c, + 0x37, 0x30, 0xce, 0x3a, 0x18, 0xe6, 0x35, 0xb2, 0x11, 0x97, 0xa7, 0xf9, 0xe4, + 0xea, 0x3a, 0x07, 0xf6, 0xe7, 0x57, 0x1a, 0xf4, 0xe6, 0x56, 0xdc, 0x96, 0x30, + 0x58, 0x35, 0xe8, 0x0e, 0x05, 0xfa, 0x0b, 0x36, 0x0a, 0xaa, 0xdc, 0x14, 0x01, + 0x06, 0x2c, 0xe7, 0x23, 0xda, 0x08, 0x23, 0xbd, 0xa4, 0x19, 0x24, 0xfb, 0x1f, + 0x25, 0xe2, 0x1a, 0x1b, 0xf6, 0x0b, 0x23, 0xcf, 0x30, 0xc5, 0xfd, 0xe9, 0x2d, + 0xdf, 0x64, 0xe2, 0x05, 0x50, 0x08, 0xcc, 0xd1, 0xbc, 0xe0, 0x93, 0xfe, 0x09, + 0xa5, 0x04, 0xf4, 0xec, 0x03, 0x28, 0xbe, 0x38, 0x24, 0x11, 0x0b, 0x2d, 0xdd, + 0x1c, 0xc9, 0x0f, 0x40, 0xfd, 0x03, 0x06, 0xe8, 0x11, 0xa0, 0x07, 0xe1, 0x0a, + 0xf9, 0xcc, 0xbb, 0x43, 0x0b, 0x32, 0xcf, 0xbe, 0x2c, 0xbc, 0xb0, 0xe8, 0x05, + 0x1b, 0x21, 0xb5, 0xfe, 0xd7, 0x4a, 0xa6, 0x08, 0x0c, 0x0c, 0x83, 0xea, 0x11, + 0xfe, 0x45, 0xdb, 0xe8, 0x22, 0xc5, 0xfe, 0xee, 0x11, 0x0a, 0x13, 0xdb, 0xf1, + 0x81, 0xf7, 0x29, 0x1b, 0xd1, 0xfc, 0xd6, 0x22, 0xb5, 0x9b, 0x36, 0x17, 0x1e, + 0x45, 0xa9, 0x4f, 0x13, 0x29, 0x04, 0xae, 0xee, 0x0b, 0xe4, 0x03, 0x64, 0x20, + 0xf2, 0x1a, 0x04, 0xf1, 0x48, 0xd9, 0xd0, 0x2d, 0xf2, 0xd7, 0x13, 0x37, 0x1c, + 0xe0, 0xc6, 0xd3, 0xd7, 0x17, 0x37, 0xba, 0xb2, 0xa0, 0xce, 0x2b, 0xb1, 0xf8, + 0xd6, 0x14, 0xf3, 0xea, 0x23, 0xff, 0xdb, 0x20, 0xba, 0xdf, 0xff, 0xd7, 0xfd, + 0x0e, 0xe0, 0x11, 0xec, 0xfd, 0xcc, 0x02, 0x2a, 0xfb, 0x28, 0x2e, 0xf2, 0xe4, + 0x2c, 0x44, 0xf1, 0x36, 0xc6, 0xeb, 0x19, 0xbd, 0x30, 0x07, 0xf3, 0xe9, 0x15, + 0xe6, 0xef, 0xf4, 0x01, 0x08, 0x3a, 0x00, 0xdf, 0x02, 0xeb, 0xfc, 0xf4, 0x21, + 0xa2, 0x5d, 0x06, 0xd1, 0x10, 0x03, 0x12, 0xcb, 0xf5, 0xb2, 0x05, 0xdf, 0xd0, + 0x1a, 0x1b, 0x15, 0x18, 0x05, 0xe1, 0xf1, 0xee, 0xf5, 0xdc, 0xff, 0x81, 0x1e, + 0x02, 0x25, 0xc9, 0xe5, 0xfd, 0xd2, 0xf2, 0xfb, 0xcb, 0x13, 0x29, 0x79, 0x1a, + 0x07, 0xb1, 0xea, 0xed, 0xf6, 0xdf, 0xeb, 0xd2, 0xdf, 0x35, 0xea, 0xed, 0x48, + 0xb2, 0xc3, 0xe1, 0xb6, 0xdb, 0x13, 0x01, 0x16, 0x10, 0xcd, 0xfb, 0xeb, 0x10, + 0xe5, 0x0e, 0x11, 0xfa, 0x2d, 0x0b, 0xf4, 0xd6, 0xf6, 0xbf, 0x2a, 0xda, 0x17, + 0xfd, 0xde, 0xfd, 0xf2, 0xce, 0xdb, 0x36, 0xe9, 0x1e, 0xcc, 0x20, 0xed, 0x15, + 0x13, 0xe1, 0x1f, 0xec, 0xdb, 0x21, 0xc5, 0x1d, 0xf3, 0xf7, 0x09, 0x1f, 0xd5, + 0x01, 0x25, 0xc7, 0xfc, 0x11, 0xc2, 0x2f, 0xff, 0x34, 0x10, 0x15, 0xf3, 0x0e, + 0x33, 0x24, 0x37, 0xea, 0x04, 0x10, 0xff, 0x16, 0xcf, 0x0e, 0x07, 0x17, 0xb5, + 0xfe, 0xb2, 0x49, 0xe6, 0xda, 0xff, 0x12, 0x05, 0x1e, 0xdc, 0xea, 0x21, 0x0b, + 0xde, 0xe8, 0xeb, 0x4f, 0xe3, 0xf7, 0xe3, 0x1e, 0x04, 0xdf, 0x1d, 0x00, 0xfa, + 0xcd, 0xe2, 0x0d, 0xd7, 0x1a, 0x00, 0xf1, 0xd8, 0xf1, 0xf8, 0xe2, 0xf9, 0xdc, + 0xe5, 0xc7, 0xfd, 0x09, 0x0c, 0xe7, 0x05, 0x10, 0xc8, 0xd6, 0x0f, 0x11, 0xb9, + 0x45, 0xdc, 0x09, 0xd3, 0xfc, 0xba, 0xe7, 0x5c, 0xda, 0x0e, 0xfb, 0x24, 0xf3, + 0x6a, 0xc1, 0x04, 0xd4, 0x13, 0xb9, 0x02, 0xd9, 0xf0, 0x16, 0xf1, 0x18, 0x03, + 0x06, 0x20, 0x0f, 0xe6, 0xee, 0xef, 0xc1, 0xe5, 0xe2, 0x7f, 0x28, 0xf9, 0x06, + 0xed, 0x7e, 0xa6, 0x2f, 0x1d, 0xc2, 0xf6, 0xdd, 0x03, 0xed, 0x05, 0x1c, 0x1d, + 0x8c, 0xe5, 0x0f, 0xe2, 0x9b, 0x1d, 0xf3, 0x14, 0xdf, 0x2d, 0x22, 0x08, 0x48, + 0xed, 0xef, 0xf2, 0x05, 0xc2, 0xd4, 0xd9, 0x1a, 0x59, 0x01, 0xeb, 0x9c, 0xdc, + 0xe0, 0x01, 0xce, 0x09, 0x16, 0xd6, 0xed, 0xe6, 0xda, 0xbf, 0xbe, 0x0a, 0x03, + 0xf5, 0xd7, 0xdd, 0x3c, 0x22, 0x66, 0xf2, 0x4b, 0x2c, 0x7f, 0x0c, 0xa9, 0x62, + 0x8f, 0xb3, 0x6b, 0x2f, 0x13, 0x0b, 0xff, 0xbf, 0x01, 0xa8, 0xd2, 0xe4, 0x8e, + 0x39, 0x59, 0xc7, 0x4c, 0xff, 0x1e, 0xeb, 0x32, 0xf9, 0x0e, 0xf2, 0x50, 0x56, + 0x2b, 0xe5, 0x0c, 0x25, 0xf8, 0xe9, 0xf0, 0x30, 0xf7, 0x17, 0x47, 0xaf, 0xfa, + 0xd8, 0x22, 0x2b, 0xd1, 0xca, 0x3e, 0xda, 0x01, 0x21, 0xf5, 0x63, 0x0d, 0xfa, + 0xed, 0x33, 0x7c, 0xc8, 0xd5, 0x49, 0x28, 0x0d, 0xe1, 0xe4, 0x1c, 0x41, 0xfb, + 0x12, 0xec, 0xae, 0x5f, 0x1b, 0xe8, 0x3b, 0x05, 0xb7, 0xe8, 0x04, 0x1d, 0xd1, + 0xfe, 0xbd, 0x10, 0xe9, 0x2b, 0xc9, 0x35, 0x04, 0x0e, 0x3e, 0xe7, 0xe8, 0xd0, + 0x76, 0xe3, 0xec, 0xd8, 0x43, 0xf8, 0xbe, 0x12, 0x0a, 0x21, 0xd0, 0xfc, 0x3a, + 0xd7, 0xf5, 0xe2, 0x4b, 0xea, 0xda, 0x1c, 0xce, 0x05, 0x37, 0xff, 0x2f, 0xda, + 0x40, 0x0f, 0x22, 0xfa, 0xd8, 0x01, 0xcc, 0xd2, 0x2c, 0xf7, 0x1d, 0x4e, 0x7f, + 0xdd, 0xe6, 0x0f, 0xcc, 0xe2, 0xe7, 0x12, 0xa9, 0xda, 0xcb, 0xe9, 0x06, 0x0e, + 0x04, 0x3e, 0xf7, 0xed, 0x06, 0xc4, 0xd3, 0xdf, 0xcf, 0xbe, 0xa9, 0xd8, 0xf2, + 0x2d, 0x21, 0x54, 0xc1, 0x19, 0xfa, 0x1f, 0xfa, 0xbb, 0xed, 0x48, 0x29, 0x04, + 0x41, 0x0e, 0x72, 0x06, 0x19, 0x2a, 0x16, 0x05, 0x25, 0xf1, 0x35, 0x1f, 0xfc, + 0x0e, 0x06, 0xc1, 0x0e, 0xf6, 0x2b, 0xad, 0x1e, 0xfe, 0x26, 0xf3, 0x81, 0x27, + 0xaf, 0x9b, 0x08, 0xf9, 0x38, 0xf2, 0x9a, 0x92, 0x21, 0xe5, 0x3b, 0x3b, 0x5b, + 0xa0, 0xf8, 0x07, 0x1e, 0x39, 0xe7, 0x0c, 0xbf, 0x33, 0x41, 0xed, 0xb0, 0x27, + 0x42, 0x02, 0x2a, 0xf8, 0x15, 0xd1, 0x10, 0xbe, 0xfd, 0x04, 0xfc, 0xb9, 0x4a, + 0x2f, 0x0f, 0xfc, 0xfe, 0xbf, 0xae, 0x47, 0xc9, 0x12, 0xa2, 0xe0, 0xea, 0x41, + 0x47, 0x59, 0xdb, 0x21, 0x09, 0x15, 0x1a, 0xf1, 0x23, 0xcb, 0xab, 0x53, 0x35, + 0x0d, 0x8a, 0xcf, 0x06, 0xf1, 0x28, 0xe3, 0xfd, 0x2f, 0xe8, 0x2c, 0x0c, 0xe8, + 0x3d, 0xed, 0x5a, 0xe1, 0xb1, 0x18, 0x1b, 0x4e, 0xf4, 0x2e, 0xd3, 0x0c, 0x20, + 0x23, 0x3c, 0xd6, 0xbc, 0x25, 0x1c, 0x26, 0x33, 0xe9, 0x0f, 0xcb, 0x2c, 0x2b, + 0x13, 0xda, 0xb5, 0x08, 0xeb, 0xc2, 0xd1, 0x1b, 0xd5, 0x26, 0xf0, 0x33, 0xf6, + 0xec, 0x00, 0xf1, 0x14, 0x23, 0x02, 0x0d, 0xf8, 0x26, 0x2a, 0xef, 0xdf, 0xc6, + 0xdd, 0xd5, 0xeb, 0xf3, 0x09, 0x0d, 0x4f, 0x06, 0x39, 0xf5, 0xea, 0x05, 0x3d, + 0x15, 0xb7, 0x27, 0xa0, 0xed, 0xdb, 0xe7, 0x02, 0xa3, 0x17, 0xdf, 0xdf, 0xc0, + 0x07, 0x13, 0xef, 0x39, 0xd9, 0xe5, 0x92, 0x2f, 0xf1, 0x3b, 0x29, 0x7f, 0x78, + 0xdb, 0xea, 0xf1, 0x3d, 0x4d, 0x5f, 0x17, 0x52, 0xcf, 0x1b, 0xdc, 0x24, 0x40, + 0x0a, 0x03, 0x21, 0xea, 0x01, 0xd9, 0x4c, 0xfa, 0x08, 0x35, 0xe5, 0xfe, 0xf6, + 0x0f, 0x46, 0xf5, 0x17, 0x15, 0x24, 0xed, 0x09, 0x15, 0x0c, 0x23, 0xe9, 0x3f, + 0x14, 0xf7, 0xc0, 0xfb, 0x13, 0x41, 0xd5, 0xe5, 0xd1, 0xe2, 0xb0, 0xee, 0x1f, + 0x20, 0xec, 0x23, 0xf9, 0xe9, 0x75, 0xfb, 0x1c, 0x5b, 0x0e, 0x28, 0x01, 0xea, + 0xf6, 0xe0, 0x0f, 0xfc, 0xe5, 0x25, 0x47, 0xaa, 0x1e, 0xf2, 0x3f, 0xf9, 0x0f, + 0x07, 0x12, 0xd3, 0xb2, 0xc5, 0xd3, 0x3d, 0xd7, 0x07, 0x2c, 0xc7, 0xcb, 0x39, + 0x16, 0xf7, 0xdf, 0x4f, 0xc7, 0x21, 0x22, 0x30, 0xaa, 0xb5, 0x18, 0xbf, 0x2d, + 0xf3, 0x0d, 0xf8, 0x46, 0x10, 0x86, 0x3d, 0xef, 0x3c, 0x4f, 0x29, 0xfc, 0xe4, + 0xd3, 0x27, 0xf7, 0x1f, 0x26, 0x29, 0xf1, 0xd0, 0x29, 0xe6, 0xf0, 0xd1, 0x04, + 0xac, 0xdd, 0xd9, 0xa6, 0xfc, 0xd0, 0xd4, 0x09, 0x11, 0x4a, 0x32, 0xe2, 0xf9, + 0xeb, 0xfc, 0xcb, 0xf9, 0x3b, 0xc5, 0xd3, 0x95, 0x50, 0x3e, 0x16, 0x94, 0xe7, + 0xcb, 0xcb, 0xda, 0x3e, 0xd5, 0x0a, 0xc7, 0x1d, 0x06, 0xe0, 0x7f, 0x31, 0x62, + 0x01, 0x1d, 0x37, 0x4e, 0xeb, 0x14, 0x04, 0xf2, 0x2a, 0x05, 0xd9, 0x4a, 0x34, + 0xec, 0x1f, 0x32, 0x89, 0xf6, 0xcd, 0x5e, 0x1e, 0x28, 0x1a, 0x3e, 0xea, 0xdd, + 0x1a, 0x49, 0xfd, 0x25, 0x26, 0x2d, 0xde, 0xe5, 0xdb, 0xd9, 0x33, 0x42, 0xda, + 0x0b, 0x21, 0xf3, 0xd6, 0xe5, 0x13, 0x1e, 0x12, 0xcb, 0x45, 0x12, 0x2c, 0x1f, + 0x3b, 0xba, 0x1c, 0x0d, 0xfe, 0x9e, 0xe5, 0x3d, 0x17, 0x47, 0x81, 0xe8, 0xd8, + 0x28, 0xe5, 0xf9, 0x0e, 0xc2, 0x2b, 0xe2, 0xb7, 0xf2, 0x2c, 0x02, 0x04, 0x51, + 0xfa, 0x07, 0xb7, 0x25, 0x05, 0x10, 0xb0, 0xe3, 0xd9, 0x0f, 0x03, 0x0f, 0x03, + 0x15, 0xeb, 0xea, 0xdf, 0xe6, 0x96, 0xfe, 0xf0, 0x0d, 0x19, 0xdd, 0xea, 0xfd, + 0xf3, 0x4a, 0xb3, 0xc6, 0x0e, 0x19, 0xe7, 0xf9, 0x0d, 0x1c, 0x22, 0xff, 0xd7, + 0x15, 0xce, 0x31, 0xde, 0xd4, 0xe1, 0xee, 0x16, 0x04, 0x2d, 0x01, 0xe6, 0xd2, + 0x22, 0x1b, 0x9c, 0xc9, 0xdc, 0xef, 0xf4, 0x2d, 0x0f, 0xaf, 0xb0, 0x0c, 0xde, + 0xf4, 0x2c, 0x32, 0x19, 0x99, 0x10, 0xe2, 0x08, 0xbe, 0x0a, 0xe3, 0x13, 0x4c, + 0x08, 0x0b, 0xeb, 0x03, 0xfb, 0x3d, 0xc4, 0xcb, 0xf5, 0xff, 0x22, 0xd6, 0xe8, + 0x0e, 0xd3, 0xc0, 0x55, 0xbc, 0x2b, 0x3c, 0xe4, 0x18, 0x0e, 0xd5, 0xe5, 0xd0, + 0xe3, 0x2e, 0x27, 0x18, 0x2a, 0x02, 0x09, 0xf2, 0xf1, 0x12, 0x32, 0x14, 0xbd, + 0xe9, 0x46, 0x0b, 0xe5, 0xf4, 0x1b, 0xf7, 0xde, 0xf9, 0xf4, 0xcd, 0xe9, 0xbe, + 0x05, 0xc8, 0x4c, 0xd7, 0x0e, 0x1c, 0xec, 0xca, 0x23, 0xe4, 0xf1, 0xf0, 0xf6, + 0xfe, 0x27, 0xcf, 0x9f, 0xda, 0xd6, 0x3a, 0xfe, 0xd3, 0xd8, 0xf2, 0xb3, 0x77, + 0x08, 0xba, 0xc9, 0xbb, 0x8e, 0x14, 0xed, 0x1d, 0x17, 0xe3, 0xfd, 0xcf, 0xef, + 0x7f, 0x1a, 0xde, 0x0a, 0x38, 0x15, 0xc5, 0xef, 0xbf, 0xf5, 0x32, 0xd4, 0x08, + 0xcc, 0xcb, 0x05, 0xfc, 0x1e, 0xf3, 0xda, 0xdb, 0x2c, 0x19, 0x14, 0xf0, 0x1a, + 0x38, 0x23, 0xa8, 0xa2, 0x09, 0x1f, 0x1c, 0x22, 0xe2, 0xe1, 0x04, 0x53, 0x1d, + 0xf7, 0x50, 0x0f, 0xf3, 0x2d, 0x1b, 0x2e, 0xe3, 0xfb, 0x25, 0x17, 0xe2, 0xef, + 0x68, 0xfe, 0xff, 0x3d, 0xdb, 0xed, 0xdd, 0xe2, 0xbe, 0x07, 0xfd, 0x41, 0x1c, + 0x1e, 0xed, 0xca, 0xf0, 0x1b, 0xe6, 0x0b, 0xe4, 0x1e, 0x30, 0xf0, 0xfd, 0x1a, + 0x5c, 0xa1, 0xc4, 0x16, 0x15, 0xfa, 0x15, 0x11, 0xe4, 0xdb, 0x28, 0xd5, 0xfa, + 0xf7, 0xdd, 0xf3, 0x9a, 0x67, 0xc6, 0xfc, 0xf8, 0x0b, 0x07, 0xaf, 0x38, 0xaa, + 0xea, 0xf1, 0x10, 0x49, 0x3c, 0x19, 0x7f, 0x33, 0xc8, 0xeb, 0x59, 0x12, 0xc7, + 0xe4, 0xea, 0x24, 0x4c, 0x07, 0x44, 0x1a, 0x0b, 0x00, 0x61, 0x0f, 0x10, 0xef, + 0x20, 0xd9, 0x69, 0x4c, 0xc5, 0xd1, 0xe1, 0x1e, 0x0a, 0xf2, 0xe9, 0xef, 0x4c, + 0x4a, 0xf5, 0x35, 0x00, 0xcd, 0xd8, 0xe9, 0x71, 0x53, 0x1a, 0xff, 0xfb, 0x22, + 0x16, 0xf0, 0x1d, 0xdf, 0xb1, 0xc3, 0xef, 0xf9, 0xe5, 0x10, 0xde, 0x02, 0x4f, + 0xe4, 0x12, 0xfd, 0x0c, 0x66, 0x28, 0xc7, 0xf6, 0x5d, 0x06, 0xfe, 0xcd, 0x99, + 0x03, 0xc8, 0xc8, 0x06, 0xc5, 0xcf, 0x06, 0x4f, 0xb1, 0x50, 0x1b, 0xf4, 0xbd, + 0xb1, 0x40, 0x5f, 0x23, 0x9e, 0x27, 0x16, 0xd3, 0x4e, 0x2c, 0xe7, 0xaf, 0xe0, + 0xf3, 0xed, 0xc9, 0x35, 0x0a, 0x15, 0x2b, 0xea, 0x81, 0x9f, 0x08, 0x0c, 0x25, + 0x14, 0x12, 0xb0, 0xc3, 0x2c, 0x5a, 0xe9, 0x3f, 0x70, 0xf0, 0x00, 0xdb, 0xd1, + 0xeb, 0xf8, 0x08, 0x33, 0xf6, 0xfb, 0x51, 0xde, 0xd6, 0xc4, 0x46, 0x36, 0xf0, + 0x8f, 0x0c, 0x5a, 0x44, 0xf6, 0x15, 0xfa, 0xf2, 0xf7, 0xcb, 0x01, 0xa2, 0xe0, + 0x3d, 0xeb, 0x43, 0x12, 0xf7, 0xfd, 0xe8, 0x64, 0x12, 0xe5, 0xd7, 0xcb, 0xf1, + 0x32, 0xfb, 0x0a, 0x81, 0x13, 0xf8, 0xf9, 0xc9, 0xab, 0xec, 0x09, 0xe6, 0xdf, + 0xf1, 0x10, 0x0c, 0xe8, 0xcd, 0xf2, 0xfe, 0x34, 0x05, 0xf7, 0x9d, 0xfb, 0xeb, + 0x55, 0x06, 0xe5, 0x1f, 0xc0, 0xa1, 0xb8, 0xd0, 0x21, 0xdd, 0x5a, 0xd1, 0x14, + 0x09, 0xfb, 0xfa, 0x24, 0xf5, 0x7f, 0x06, 0xe1, 0x38, 0xd2, 0x0f, 0x14, 0x07, + 0xf4, 0x10, 0x16, 0x20, 0x09, 0x16, 0x2f, 0xff, 0x2a, 0xdf, 0xd8, 0xea, 0x0d, + 0xe1, 0xd2, 0xe8, 0xda, 0xba, 0xd8, 0x24, 0x15, 0xc4, 0x14, 0xc7, 0x08, 0x00, + 0x1e, 0xc3, 0xe0, 0xaf, 0xf9, 0x05, 0x0f, 0xe9, 0x2c, 0xc9, 0x36, 0xff, 0xcc, + 0xf2, 0xec, 0xdb, 0xda, 0x2f, 0x26, 0xe4, 0x11, 0xeb, 0x56, 0x1c, 0x62, 0xd2, + 0x03, 0xd1, 0x26, 0xc6, 0xe0, 0xc0, 0xef, 0xe3, 0x30, 0xe4, 0xc1, 0x35, 0x1c, + 0x1d, 0xc9, 0x0b, 0xd2, 0xe0, 0x14, 0x2e, 0xf2, 0xd9, 0x0d, 0xd9, 0xea, 0x33, + 0xeb, 0x09, 0x15, 0xfb, 0x11, 0xb0, 0xe7, 0xe7, 0x0c, 0xdd, 0xca, 0x16, 0xe1, + 0xfe, 0xd9, 0x06, 0x04, 0x1e, 0x06, 0xe3, 0x0d, 0xeb, 0x02, 0xe7, 0x05, 0xfd, + 0xb0, 0xee, 0xd1, 0xf3, 0xa5, 0xee, 0xf1, 0xd2, 0xf3, 0xd6, 0x07, 0x12, 0xf3, + 0x0a, 0xf5, 0x0b, 0xd9, 0x13, 0xbd, 0x10, 0x1a, 0x4d, 0x04, 0xcf, 0x02, 0x00, + 0x0e, 0x2f, 0xfc, 0xec, 0x2d, 0x2c, 0x50, 0x12, 0xdf, 0xf0, 0x23, 0xdc, 0xb8, + 0xf0, 0xcf, 0xcd, 0x06, 0x63, 0x04, 0x42, 0x12, 0x2b, 0x3f, 0x29, 0x48, 0xdd, + 0xd9, 0xcc, 0xc6, 0xf8, 0xb5, 0xff, 0xeb, 0xc6, 0x51, 0xfd, 0x3b, 0xf0, 0x12, + 0x8e, 0x03, 0xea, 0x38, 0x81, 0xea, 0x18, 0x06, 0xcd, 0xc3, 0xfb, 0x08, 0xff, + 0xd5, 0x17, 0xc5, 0xa1, 0xfd, 0x12, 0x08, 0xfb, 0x3c, 0x0a, 0x12, 0xf9, 0xd9, + 0xe5, 0xc8, 0x25, 0x2e, 0xba, 0x1f, 0xfd, 0xf7, 0x03, 0x41, 0xd9, 0x9d, 0x34, + 0xde, 0x39, 0x5c, 0x2b, 0x05, 0x2d, 0x00, 0x34, 0x28, 0xe6, 0x21, 0x38, 0xd2, + 0x09, 0x06, 0xb9, 0x47, 0xdf, 0x07, 0xc7, 0x23, 0xfc, 0x27, 0x32, 0xf5, 0xe0, + 0x24, 0x22, 0xee, 0xde, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x83, 0x0b, 0x00, 0x00, 0xa8, 0x27, 0x00, 0x00, 0x47, 0xe1, 0xff, 0xff, + 0xd6, 0xfd, 0xff, 0xff, 0x40, 0xca, 0xff, 0xff, 0xd3, 0x25, 0x00, 0x00, 0xc2, + 0xff, 0xff, 0xff, 0xeb, 0xc2, 0xff, 0xff, 0xb1, 0x52, 0x00, 0x00, 0x51, 0x09, + 0x00, 0x00, 0x31, 0xea, 0xff, 0xff, 0x65, 0xc3, 0xff, 0xff, 0x59, 0x09, 0x00, + 0x00, 0x6a, 0xe3, 0xff, 0xff, 0x33, 0x02, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, + 0x2f, 0x23, 0x00, 0x00, 0x26, 0x02, 0x00, 0x00, 0x66, 0xd9, 0xff, 0xff, 0x7a, + 0xd8, 0xff, 0xff, 0x0b, 0x15, 0x00, 0x00, 0xfd, 0x2e, 0x00, 0x00, 0xd7, 0x2c, + 0x00, 0x00, 0x87, 0xef, 0xff, 0xff, 0x41, 0x23, 0x00, 0x00, 0x3a, 0x9e, 0xff, + 0xff, 0x43, 0xfe, 0xff, 0xff, 0x16, 0x10, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, + 0x72, 0xda, 0xff, 0xff, 0x66, 0xfa, 0xff, 0xff, 0x64, 0xfe, 0xff, 0xff, 0x34, + 0x2d, 0x00, 0x00, 0x62, 0x0b, 0x00, 0x00, 0xa6, 0x08, 0x00, 0x00, 0xf3, 0xd2, + 0xff, 0xff, 0x7d, 0x49, 0x00, 0x00, 0x8a, 0xd6, 0xff, 0xff, 0x06, 0xf0, 0xff, + 0xff, 0x90, 0x3d, 0x00, 0x00, 0xfd, 0x18, 0x00, 0x00, 0xe3, 0xee, 0xff, 0xff, + 0x05, 0x01, 0x00, 0x00, 0x6e, 0xb2, 0xff, 0xff, 0xb3, 0x0a, 0x00, 0x00, 0xaa, + 0xdd, 0xff, 0xff, 0x1c, 0x39, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x90, 0x05, + 0x00, 0x00, 0x95, 0x29, 0x00, 0x00, 0x4f, 0xfc, 0xff, 0xff, 0x92, 0x0a, 0x00, + 0x00, 0xb0, 0x0a, 0x00, 0x00, 0x3d, 0x2d, 0x00, 0x00, 0x52, 0x0c, 0x00, 0x00, + 0xdc, 0x25, 0x00, 0x00, 0x4a, 0xdb, 0xff, 0xff, 0x9c, 0x36, 0x00, 0x00, 0xff, + 0xd2, 0xff, 0xff, 0xa3, 0xff, 0xff, 0xff, 0x14, 0xf2, 0xff, 0xff, 0x3d, 0x0d, + 0x00, 0x00, 0x45, 0x03, 0x00, 0x00, 0x39, 0xe4, 0xff, 0xff, 0xdb, 0x02, 0x00, + 0x00, 0xf0, 0xed, 0xff, 0xff, 0xfb, 0xbf, 0xff, 0xff, 0xd1, 0xee, 0xff, 0xff, + 0x42, 0x1d, 0x00, 0x00, 0x27, 0x0f, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00, 0xd1, + 0x39, 0x00, 0x00, 0x96, 0xf2, 0xff, 0xff, 0xe6, 0x2b, 0x00, 0x00, 0x0a, 0x27, + 0x00, 0x00, 0x06, 0xe2, 0xff, 0xff, 0x10, 0x0b, 0x00, 0x00, 0x6e, 0xdf, 0xff, + 0xff, 0x57, 0xde, 0xff, 0xff, 0x74, 0xf7, 0xff, 0xff, 0x30, 0xf3, 0xff, 0xff, + 0xbf, 0x13, 0x00, 0x00, 0x3f, 0x05, 0x00, 0x00, 0x0c, 0xe5, 0xff, 0xff, 0xe7, + 0xf8, 0xff, 0xff, 0xd3, 0x1e, 0x00, 0x00, 0xa7, 0x1f, 0x00, 0x00, 0x44, 0x21, + 0x00, 0x00, 0xf1, 0xf6, 0xff, 0xff, 0xe1, 0x1a, 0x00, 0x00, 0x60, 0xbc, 0xff, + 0xff, 0x73, 0x09, 0x00, 0x00, 0x71, 0x06, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, + 0x9e, 0x31, 0x00, 0x00, 0xac, 0xe8, 0xff, 0xff, 0xff, 0x06, 0x00, 0x00, 0xff, + 0x21, 0x00, 0x00, 0xa2, 0x5b, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0xff, 0x56, 0x04, + 0x00, 0x00, 0xf1, 0xd9, 0xff, 0xff, 0xca, 0x27, 0x00, 0x00, 0x21, 0xf1, 0xff, + 0xff, 0x40, 0xd0, 0xff, 0xff, 0xdb, 0x06, 0x00, 0x00, 0xec, 0x3e, 0x00, 0x00, + 0x9e, 0x0e, 0x00, 0x00, 0x0b, 0xe9, 0xff, 0xff, 0x7e, 0x4a, 0x00, 0x00, 0x0a, + 0x1e, 0x00, 0x00, 0x30, 0xfe, 0xff, 0xff, 0x95, 0x0b, 0x00, 0x00, 0x06, 0xf8, + 0xff, 0xff, 0x74, 0x43, 0x00, 0x00, 0x71, 0x2a, 0x00, 0x00, 0x8a, 0x16, 0x00, + 0x00, 0x65, 0xf5, 0xff, 0xff, 0x23, 0x02, 0x00, 0x00, 0xc6, 0x01, 0x00, 0x00, + 0x4f, 0xd5, 0xff, 0xff, 0x5e, 0x0a, 0x00, 0x00, 0x88, 0x32, 0x00, 0x00, 0x7a, + 0x18, 0x00, 0x00, 0x51, 0xd4, 0xff, 0xff, 0xc7, 0x25, 0x00, 0x00, 0xc8, 0x2f, + 0x00, 0x00, 0x01, 0x0b, 0x00, 0x00, 0xfa, 0xe0, 0xfe, 0xff, 0x04, 0x00, 0x00, + 0x00, 0x80, 0x04, 0x00, 0x00, 0x7a, 0x88, 0xba, 0x3f, 0xcb, 0xb5, 0x1d, 0xad, + 0x81, 0xb9, 0xc1, 0x77, 0x18, 0xa7, 0xd0, 0x76, 0xe0, 0xc9, 0x65, 0x02, 0x04, + 0x58, 0xcb, 0x92, 0x70, 0x2b, 0x7f, 0x0d, 0x7f, 0x0f, 0xfd, 0xf2, 0xe0, 0x7f, + 0xc6, 0xe5, 0xd2, 0x81, 0xe6, 0xe8, 0x7f, 0xd1, 0xf3, 0x34, 0xc3, 0x2c, 0x86, + 0x8f, 0x7f, 0xdf, 0x81, 0xa4, 0x7f, 0x19, 0x0d, 0x08, 0x1e, 0x8b, 0xff, 0xbf, + 0x04, 0x2c, 0x70, 0xff, 0x7f, 0xc1, 0xe3, 0xe3, 0xac, 0xd1, 0x71, 0xf6, 0xe3, + 0xb3, 0x8f, 0x22, 0x5a, 0x1b, 0x81, 0x87, 0x3a, 0xd1, 0x12, 0x05, 0x1a, 0x4e, + 0x7d, 0xba, 0x7f, 0xfe, 0xf9, 0x65, 0x0e, 0xbe, 0x90, 0xb0, 0x91, 0xcc, 0xb0, + 0x84, 0xbd, 0x7f, 0x1e, 0x81, 0xec, 0x7f, 0x9e, 0x6f, 0x9e, 0x0a, 0xe9, 0x81, + 0x3f, 0xe3, 0x81, 0x81, 0x34, 0x46, 0xc9, 0xc9, 0x06, 0x96, 0x09, 0x27, 0xbe, + 0x2a, 0xdb, 0x46, 0x74, 0xef, 0xe6, 0xe0, 0x81, 0xa7, 0x58, 0x06, 0xd8, 0x7f, + 0xf5, 0x7c, 0x4c, 0xaa, 0xb5, 0x18, 0x7f, 0xea, 0x7f, 0xf0, 0x19, 0x7f, 0x11, + 0xed, 0xbf, 0x7f, 0x95, 0x77, 0x46, 0x18, 0x62, 0xf5, 0xe2, 0x27, 0x9a, 0x81, + 0xf6, 0xf1, 0x42, 0x00, 0x5c, 0xf9, 0xc1, 0x7f, 0xb7, 0x6b, 0x81, 0x47, 0x68, + 0x23, 0xad, 0xb4, 0x38, 0xf8, 0xfa, 0x37, 0x96, 0x5f, 0x81, 0x16, 0x74, 0x7f, + 0x47, 0x19, 0x2b, 0xb0, 0xa7, 0x8f, 0xb8, 0xd1, 0xca, 0x69, 0x11, 0xf8, 0x81, + 0x81, 0x2e, 0x7f, 0xfe, 0x81, 0x2d, 0xdb, 0xe0, 0xf9, 0x1b, 0x41, 0xeb, 0x06, + 0x24, 0x81, 0x8d, 0x81, 0x19, 0xab, 0x8c, 0x33, 0xa2, 0x81, 0xc8, 0xd3, 0x55, + 0x29, 0x03, 0xe4, 0xdd, 0x26, 0x0b, 0x52, 0x12, 0x07, 0x5a, 0x91, 0x67, 0x0e, + 0x99, 0xbf, 0x7f, 0x3c, 0x50, 0xbe, 0x81, 0x99, 0xac, 0x03, 0x78, 0x0f, 0xbc, + 0xdc, 0x81, 0x81, 0xbc, 0x95, 0x15, 0xc7, 0x7f, 0xe8, 0xc8, 0x76, 0x19, 0xb4, + 0x6b, 0xd6, 0x81, 0x3f, 0xf5, 0x1b, 0xd0, 0xfd, 0x42, 0x58, 0x81, 0x16, 0x95, + 0x7e, 0xe2, 0x7f, 0x18, 0xd9, 0x20, 0xe2, 0x15, 0xde, 0xdd, 0x2b, 0x93, 0x8e, + 0x7f, 0xe1, 0x2c, 0x15, 0x1a, 0x12, 0xc0, 0xfc, 0xfc, 0x20, 0x20, 0x00, 0x24, + 0x52, 0xd6, 0x9b, 0x8f, 0xec, 0x11, 0x2b, 0xaf, 0xda, 0xd6, 0x09, 0x2e, 0x2d, + 0xe9, 0x22, 0x0c, 0x81, 0xf4, 0x1c, 0x81, 0x4e, 0x02, 0x9b, 0xa4, 0x99, 0x48, + 0xe7, 0x17, 0x52, 0x07, 0xd3, 0xd8, 0xc8, 0xeb, 0x7f, 0xfe, 0x01, 0xff, 0xbd, + 0x1f, 0x89, 0xb2, 0xef, 0x8a, 0x83, 0xe1, 0xcd, 0x1c, 0x19, 0x36, 0x8d, 0xdf, + 0x9b, 0xfb, 0x5a, 0xf5, 0x09, 0x97, 0x03, 0xbd, 0x63, 0x14, 0x16, 0xbe, 0xc0, + 0xe8, 0x7f, 0x8c, 0xf0, 0x47, 0xab, 0xf6, 0xc4, 0x7f, 0x2f, 0xb1, 0xdd, 0x75, + 0xd0, 0x7f, 0x1e, 0x30, 0xa4, 0x07, 0x79, 0xb2, 0x0b, 0xce, 0x23, 0xb7, 0x81, + 0xb9, 0xcc, 0xf1, 0xea, 0x03, 0x7e, 0x18, 0x01, 0x36, 0x81, 0xc4, 0xf5, 0xe2, + 0xe5, 0x17, 0x7f, 0xb9, 0x2f, 0x81, 0x41, 0xb9, 0xdb, 0x44, 0x22, 0x76, 0xbc, + 0x71, 0xe7, 0x78, 0x6a, 0x37, 0x40, 0xf8, 0x0d, 0x08, 0xf7, 0xc1, 0x84, 0x0b, + 0x63, 0x5c, 0x27, 0x81, 0x81, 0xdb, 0xa3, 0xb3, 0xe8, 0x41, 0xbb, 0x3a, 0x37, + 0xb5, 0xc1, 0x81, 0xb7, 0x7b, 0x53, 0xe7, 0xce, 0x77, 0x72, 0x7f, 0x4f, 0xd2, + 0xb9, 0x7f, 0xeb, 0x69, 0x7f, 0x09, 0x5a, 0x1b, 0xd4, 0xca, 0xd5, 0xce, 0x1b, + 0x18, 0xb5, 0x1b, 0x1e, 0x82, 0x78, 0xf0, 0xc1, 0xe6, 0x18, 0x7f, 0x22, 0x81, + 0x71, 0x06, 0x60, 0xbf, 0x03, 0x2f, 0x9c, 0x17, 0x5d, 0x52, 0xa2, 0x03, 0x40, + 0x81, 0xa1, 0xf8, 0xdd, 0xe2, 0x7f, 0x34, 0x2e, 0x7f, 0x20, 0x05, 0x8d, 0x3b, + 0x7f, 0x02, 0xbb, 0xcd, 0x7f, 0xfb, 0x2f, 0x57, 0x7f, 0x3d, 0x07, 0xaf, 0x42, + 0x04, 0x81, 0x04, 0xe5, 0x38, 0x26, 0x40, 0x0c, 0x81, 0x21, 0xdd, 0x33, 0xee, + 0x39, 0x3c, 0x4c, 0xb4, 0x1a, 0xf8, 0xd5, 0x81, 0xb2, 0x63, 0xe8, 0x25, 0x2a, + 0x1e, 0x10, 0x2a, 0x7f, 0xdf, 0xe6, 0x36, 0x38, 0x90, 0xc6, 0x12, 0xcf, 0x0b, + 0x35, 0x8c, 0xd9, 0x88, 0x81, 0x94, 0x2f, 0x09, 0x07, 0x43, 0xd2, 0x81, 0x2e, + 0xc2, 0x19, 0x8b, 0x7f, 0x53, 0x81, 0x71, 0x4c, 0x2a, 0x16, 0x31, 0x02, 0x09, + 0xfb, 0x39, 0x40, 0x1b, 0xe4, 0x15, 0x81, 0xe9, 0xcb, 0x81, 0xb3, 0x44, 0xdf, + 0x7f, 0x7f, 0xfb, 0xc7, 0x81, 0x81, 0x31, 0xfd, 0xdc, 0x1b, 0xb1, 0x47, 0x81, + 0xdb, 0x82, 0x25, 0x7f, 0x14, 0x21, 0x2d, 0x01, 0xd2, 0xd4, 0x06, 0xa5, 0xc4, + 0xd8, 0xb2, 0x86, 0x2e, 0x57, 0x2d, 0x4e, 0x0b, 0xb1, 0xfe, 0x00, 0xa3, 0x20, + 0xe1, 0x3f, 0xef, 0xa2, 0xfa, 0x6f, 0xc5, 0x2e, 0xb2, 0xea, 0x3a, 0x32, 0xb7, + 0xef, 0x7f, 0x7f, 0x39, 0xa9, 0xdd, 0xbb, 0x1f, 0xa9, 0x20, 0x24, 0x15, 0x4e, + 0x20, 0xf1, 0xd2, 0x0d, 0x11, 0x47, 0x88, 0x32, 0xc1, 0x75, 0x1b, 0xbb, 0xe9, + 0xe2, 0x0d, 0x1c, 0xe3, 0x21, 0x7f, 0xe5, 0x81, 0x0f, 0xa2, 0xaa, 0xd1, 0xeb, + 0x12, 0xa6, 0xc4, 0xbe, 0x41, 0x16, 0xc3, 0x29, 0x1d, 0xf7, 0x12, 0xd8, 0x6f, + 0x89, 0x6c, 0x30, 0xb6, 0xea, 0x59, 0x45, 0x09, 0x2b, 0x17, 0xf4, 0xd5, 0x33, + 0xd7, 0xe7, 0xe7, 0xe6, 0xb4, 0xd9, 0xff, 0xc2, 0x7c, 0x81, 0x81, 0x65, 0xdb, + 0x81, 0xfa, 0xfe, 0x46, 0xf2, 0xc2, 0xb9, 0xb0, 0xfc, 0xef, 0xc8, 0x9f, 0xb1, + 0x16, 0xd4, 0x6f, 0x7f, 0x46, 0xd7, 0xb0, 0x9b, 0xde, 0xc0, 0x20, 0xd7, 0x81, + 0x0c, 0xc9, 0x71, 0x08, 0xf4, 0xff, 0x21, 0xd8, 0xc4, 0x3f, 0xef, 0x81, 0x8c, + 0xaf, 0xa5, 0xd0, 0xc4, 0xdc, 0xfe, 0x2f, 0xb4, 0x81, 0x0d, 0x06, 0x76, 0x53, + 0xeb, 0xc9, 0x6c, 0xa9, 0xbf, 0xea, 0xe6, 0x08, 0xe5, 0x27, 0x81, 0x7f, 0xac, + 0xf6, 0xd0, 0xf9, 0xd5, 0x8c, 0xf2, 0xd8, 0x41, 0xe9, 0x7f, 0xfe, 0x7f, 0xed, + 0xb2, 0x06, 0xe3, 0x7b, 0xe7, 0xba, 0xfc, 0x7f, 0xfc, 0xf4, 0x9c, 0xb9, 0xcf, + 0x4f, 0x81, 0xe2, 0x81, 0x9a, 0xf7, 0x06, 0xfe, 0x29, 0xdf, 0xfd, 0x78, 0x5f, + 0x1d, 0x94, 0xd2, 0x54, 0x49, 0x9c, 0xb8, 0xbc, 0xc2, 0x21, 0x08, 0x30, 0x1e, + 0xcc, 0x1c, 0x88, 0xd9, 0xf7, 0x03, 0xd9, 0x9d, 0x90, 0x07, 0xc3, 0xd9, 0x98, + 0xc7, 0xb3, 0x81, 0xd2, 0x0c, 0xd3, 0xc7, 0xab, 0x38, 0xab, 0x51, 0x1b, 0xfe, + 0xdc, 0x1e, 0x7f, 0x4f, 0x00, 0x2c, 0x0f, 0xe1, 0xb9, 0xb7, 0xe7, 0xc2, 0xfe, + 0x0d, 0x7f, 0xf2, 0x7f, 0xff, 0xbd, 0xb0, 0x45, 0x16, 0x16, 0xb6, 0x03, 0xf5, + 0xd4, 0x02, 0xf2, 0x81, 0x04, 0xbd, 0xe3, 0x39, 0xae, 0x2b, 0xff, 0x58, 0x07, + 0x39, 0x4a, 0xa2, 0xf0, 0xb2, 0x2d, 0xe7, 0x0f, 0xc4, 0x78, 0x43, 0xe8, 0xae, + 0xe0, 0x88, 0xc5, 0x11, 0x81, 0x8e, 0x1e, 0x06, 0xad, 0x74, 0xe4, 0x8a, 0x59, + 0x18, 0x6e, 0x61, 0xff, 0x47, 0xe9, 0x7f, 0x7f, 0x86, 0xda, 0xda, 0xc1, 0x99, + 0x0b, 0xc2, 0xa0, 0xf8, 0x81, 0xb4, 0x2b, 0xff, 0x7f, 0x38, 0x2f, 0x7f, 0xbc, + 0xcd, 0x4a, 0x21, 0xc1, 0x18, 0x84, 0xd6, 0x7f, 0x7f, 0x6e, 0x7f, 0x09, 0x7f, + 0xbc, 0xdc, 0x3a, 0x8e, 0xa6, 0xd4, 0x50, 0x5a, 0xfd, 0x67, 0xf0, 0x83, 0xa1, + 0x56, 0x0c, 0x08, 0xb5, 0x2b, 0xb4, 0xa8, 0x81, 0x7f, 0x7f, 0x10, 0xc1, 0x1b, + 0x1d, 0xa1, 0x16, 0xde, 0xfd, 0x01, 0x81, 0xad, 0x92, 0x81, 0xf5, 0x70, 0x51, + 0x16, 0x33, 0x09, 0x0e, 0x1b, 0xf7, 0x40, 0x20, 0xf2, 0x88, 0xde, 0xf3, 0x7f, + 0xea, 0xc2, 0xe6, 0xff, 0x93, 0x43, 0x1e, 0xb8, 0x50, 0x06, 0x3d, 0xa5, 0x4d, + 0x92, 0xe3, 0xc6, 0xf8, 0x0e, 0x21, 0xb3, 0xe4, 0x65, 0xe7, 0x81, 0xd6, 0xb5, + 0x2a, 0x0a, 0x24, 0x3d, 0x7f, 0xe5, 0xdd, 0xe5, 0xcf, 0x30, 0x7f, 0xeb, 0x56, + 0x35, 0xa5, 0x36, 0xd0, 0x98, 0x62, 0xec, 0xbd, 0xe4, 0xdd, 0x0d, 0xe7, 0xb9, + 0x81, 0x32, 0x87, 0xb6, 0x3d, 0x23, 0x62, 0xb7, 0x08, 0x4f, 0xba, 0xa0, 0x27, + 0x17, 0x85, 0x78, 0xd1, 0xf7, 0x26, 0x58, 0xe9, 0x1c, 0xf8, 0x41, 0x2c, 0xed, + 0x19, 0xd6, 0x37, 0x0b, 0xe4, 0x1c, 0xf6, 0xfb, 0xd0, 0xb6, 0x3a, 0x56, 0xc1, + 0xfa, 0xac, 0x2d, 0x85, 0x10, 0xa9, 0x4d, 0x58, 0xe1, 0x5f, 0xdf, 0x43, 0xc4, + 0x4d, 0xcb, 0x05, 0x84, 0x8b, 0x0f, 0x3c, 0xf5, 0x11, 0xec, 0x42, 0x1f, 0x07, + 0x86, 0xe5, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x6d, + 0xed, 0xff, 0xff, 0xdb, 0x1e, 0x00, 0x00, 0x18, 0xfe, 0xff, 0xff, 0x76, 0xf4, + 0xff, 0xff, 0xae, 0x0b, 0x00, 0x00, 0x99, 0x20, 0x00, 0x00, 0xc0, 0xfa, 0xff, + 0xff, 0xb1, 0xf6, 0xff, 0xff, 0xed, 0x27, 0x00, 0x00, 0xa2, 0xf4, 0xff, 0xff, + 0xd0, 0xf9, 0xff, 0xff, 0x66, 0xee, 0xff, 0xff, 0xfc, 0xfa, 0xff, 0xff, 0xed, + 0x18, 0x00, 0x00, 0x3a, 0x25, 0x00, 0x00, 0x7f, 0xfb, 0xff, 0xff, 0xd1, 0xf3, + 0xff, 0xff, 0xcf, 0x13, 0x00, 0x00, 0x83, 0xf0, 0xff, 0xff, 0x7d, 0xf0, 0xff, + 0xff, 0xd8, 0xeb, 0xff, 0xff, 0x9a, 0xe8, 0xff, 0xff, 0x66, 0x05, 0x00, 0x00, + 0xe2, 0x15, 0x00, 0x00, 0x28, 0x22, 0x00, 0x00, 0xcf, 0xf4, 0xff, 0xff, 0xca, + 0x0a, 0x00, 0x00, 0xb4, 0xe9, 0xff, 0xff, 0xf8, 0xf3, 0xff, 0xff, 0x63, 0xee, + 0xff, 0xff, 0x31, 0xfd, 0xff, 0xff, 0xd9, 0xed, 0xff, 0xff, 0x3f, 0x15, 0x00, + 0x00, 0x93, 0xf1, 0xff, 0xff, 0x87, 0x1b, 0x00, 0x00, 0x27, 0x12, 0x00, 0x00, + 0x04, 0x16, 0x00, 0x00, 0xfb, 0x1f, 0x00, 0x00, 0x8f, 0xe9, 0xff, 0xff, 0x89, + 0x12, 0x00, 0x00, 0x49, 0xde, 0xff, 0xff, 0x40, 0xfa, 0xff, 0xff, 0xaa, 0xf6, + 0xff, 0xff, 0x6a, 0xf2, 0xff, 0xff, 0xe6, 0xfb, 0xff, 0xff, 0x08, 0xf5, 0xff, + 0xff, 0x5c, 0x23, 0x00, 0x00, 0xdd, 0xf9, 0xff, 0xff, 0xd2, 0xe6, 0xff, 0xff, + 0x41, 0xee, 0xff, 0xff, 0x23, 0x13, 0x00, 0x00, 0xb0, 0x1e, 0x00, 0x00, 0xfb, + 0xed, 0xff, 0xff, 0x8e, 0x00, 0x00, 0x00, 0x5b, 0xfe, 0xff, 0xff, 0xe9, 0xf1, + 0xff, 0xff, 0xed, 0x21, 0x00, 0x00, 0x71, 0x0e, 0x00, 0x00, 0xab, 0x1e, 0x00, + 0x00, 0x1a, 0x18, 0x00, 0x00, 0x09, 0x0f, 0x00, 0x00, 0xc1, 0xf1, 0xff, 0xff, + 0xe8, 0xf4, 0xff, 0xff, 0x88, 0x15, 0x00, 0x00, 0xc7, 0xe9, 0xff, 0xff, 0xbc, + 0x09, 0x00, 0x00, 0x67, 0x1e, 0x00, 0x00, 0xe3, 0x0b, 0x00, 0x00, 0x99, 0x1e, + 0x00, 0x00, 0xda, 0xfc, 0xff, 0xff, 0x18, 0xf8, 0xff, 0xff, 0x84, 0xe0, 0xff, + 0xff, 0x9f, 0xf1, 0xff, 0xff, 0xb7, 0x2b, 0x00, 0x00, 0xc3, 0x15, 0x00, 0x00, + 0x48, 0xe7, 0xff, 0xff, 0x39, 0xdd, 0xff, 0xff, 0x72, 0xfe, 0xff, 0xff, 0x52, + 0x02, 0x00, 0x00, 0xcd, 0x24, 0x00, 0x00, 0x7b, 0xf6, 0xff, 0xff, 0x4f, 0xff, + 0xff, 0xff, 0xa7, 0xea, 0xff, 0xff, 0x04, 0xf1, 0xff, 0xff, 0xd9, 0xf1, 0xff, + 0xff, 0xb5, 0xee, 0xff, 0xff, 0xc0, 0xec, 0xff, 0xff, 0x99, 0x1b, 0x00, 0x00, + 0x8e, 0xfd, 0xff, 0xff, 0xb7, 0x10, 0x00, 0x00, 0x9d, 0x1d, 0x00, 0x00, 0x75, + 0x09, 0x00, 0x00, 0x62, 0x06, 0x00, 0x00, 0xf7, 0x15, 0x00, 0x00, 0x17, 0xfc, + 0xff, 0xff, 0x5a, 0x01, 0x00, 0x00, 0xe4, 0x1d, 0x00, 0x00, 0xe8, 0x14, 0x00, + 0x00, 0x56, 0x1a, 0x00, 0x00, 0xa1, 0x15, 0x00, 0x00, 0x35, 0xf8, 0xff, 0xff, + 0x02, 0xfb, 0xff, 0xff, 0x84, 0xf9, 0xff, 0xff, 0xf8, 0x1c, 0x00, 0x00, 0x3d, + 0x12, 0x00, 0x00, 0xa0, 0xef, 0xff, 0xff, 0xff, 0x11, 0x00, 0x00, 0x81, 0xfc, + 0xff, 0xff, 0x4e, 0x12, 0x00, 0x00, 0x17, 0xf6, 0xff, 0xff, 0x27, 0xf4, 0xff, + 0xff, 0xae, 0x09, 0x00, 0x00, 0x51, 0xe8, 0xff, 0xff, 0x5d, 0xed, 0xff, 0xff, + 0x5d, 0x14, 0x00, 0x00, 0xb7, 0x1a, 0x00, 0x00, 0xdd, 0xfd, 0xff, 0xff, 0xf6, + 0xeb, 0xff, 0xff, 0x0c, 0x18, 0x00, 0x00, 0x21, 0x1f, 0x00, 0x00, 0xfe, 0x10, + 0x00, 0x00, 0xdd, 0x26, 0x00, 0x00, 0xe9, 0x19, 0x00, 0x00, 0x75, 0xf6, 0xff, + 0xff, 0x11, 0xe2, 0xff, 0xff, 0x66, 0xe5, 0xff, 0xff, 0x5d, 0xf3, 0xff, 0xff, + 0x38, 0xf3, 0xff, 0xff, 0x92, 0xe7, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x83, 0xe7, 0xff, 0xff, 0x46, 0xa8, 0xff, 0xff, 0x14, 0x34, + 0x00, 0x00, 0x10, 0xc0, 0xff, 0xff, 0x53, 0x11, 0x00, 0x00, 0xdd, 0x11, 0x00, + 0x00, 0xc2, 0xfc, 0xff, 0xff, 0xbe, 0xe0, 0xff, 0xff, 0x50, 0xa6, 0xff, 0xff, + 0x1a, 0xdd, 0xff, 0xff, 0xfa, 0x08, 0x00, 0x00, 0xb3, 0xff, 0xff, 0xff, 0x51, + 0x9b, 0xff, 0xff, 0x87, 0x11, 0x00, 0x00, 0x50, 0xc7, 0xff, 0xff, 0x3a, 0xe3, + 0xff, 0xff, 0xa8, 0xd9, 0xff, 0xff, 0x4d, 0xac, 0xff, 0xff, 0x4d, 0x2b, 0x00, + 0x00, 0x07, 0x05, 0x00, 0x00, 0x9f, 0xf2, 0xff, 0xff, 0x4b, 0xb8, 0xff, 0xff, + 0x71, 0xf0, 0xff, 0xff, 0xa4, 0x2b, 0x00, 0x00, 0xfc, 0xd5, 0xff, 0xff, 0x24, + 0x0d, 0x00, 0x00, 0xc8, 0xd9, 0xff, 0xff, 0x6e, 0xff, 0xff, 0xff, 0x1b, 0x38, + 0x00, 0x00, 0x4e, 0xbf, 0xff, 0xff, 0x3e, 0x9b, 0x00, 0x00, 0xb4, 0xf5, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xff, 0x2a, 0xd5, 0xff, 0xff, 0x56, 0xc7, 0xff, 0xff, + 0x6d, 0x11, 0x00, 0x00, 0x3c, 0xda, 0xff, 0xff, 0x5a, 0x32, 0x00, 0x00, 0x0a, + 0xf8, 0xff, 0xff, 0x47, 0x00, 0x00, 0x00, 0x86, 0xf1, 0xff, 0xff, 0x1d, 0x04, + 0x00, 0x00, 0x4a, 0xe3, 0xff, 0xff, 0xe1, 0xa5, 0xff, 0xff, 0xef, 0x3e, 0x00, + 0x00, 0x27, 0xb7, 0xff, 0xff, 0xf4, 0x28, 0x00, 0x00, 0x86, 0x27, 0x00, 0x00, + 0xb4, 0xed, 0xff, 0xff, 0x29, 0xf4, 0xff, 0xff, 0x5f, 0xe3, 0xff, 0xff, 0x46, + 0x14, 0x00, 0x00, 0xa7, 0x1c, 0x00, 0x00, 0x83, 0x1f, 0x00, 0x00, 0xc6, 0x24, + 0x00, 0x00, 0x63, 0x1c, 0x00, 0x00, 0xf9, 0xf6, 0xff, 0xff, 0xad, 0x0f, 0x00, + 0x00, 0x8a, 0xbb, 0xff, 0xff, 0xf0, 0xe4, 0xff, 0xff, 0xcf, 0xce, 0xff, 0xff, + 0x15, 0xe9, 0xff, 0xff, 0xf4, 0xbf, 0xff, 0xff, 0x77, 0xbf, 0xff, 0xff, 0x01, + 0x0e, 0x00, 0x00, 0xf9, 0x16, 0x00, 0x00, 0x06, 0xd7, 0xff, 0xff, 0x6b, 0xe6, + 0xff, 0xff, 0x34, 0xd2, 0xff, 0xff, 0xb6, 0x2d, 0x00, 0x00, 0xf8, 0x95, 0xff, + 0xff, 0xaa, 0x16, 0x00, 0x00, 0xba, 0x02, 0x00, 0x00, 0x49, 0xe0, 0xff, 0xff, + 0x48, 0x14, 0x00, 0x00, 0x9d, 0x09, 0x00, 0x00, 0x7e, 0x89, 0xff, 0xff, 0x6b, + 0xfb, 0xff, 0xff, 0x66, 0xc7, 0xff, 0xff, 0xe1, 0xe6, 0xff, 0xff, 0x27, 0x2c, + 0x00, 0x00, 0x08, 0xf3, 0xff, 0xff, 0x31, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0xf6, 0xec, 0xff, 0xff, 0x0c, 0x25, 0x00, 0x00, 0x1d, 0x0c, 0x00, 0x00, + 0xd1, 0xc1, 0xff, 0xff, 0x73, 0x87, 0xff, 0xff, 0x65, 0xf8, 0xff, 0xff, 0x79, + 0xbe, 0xff, 0xff, 0xb1, 0xcf, 0xff, 0xff, 0x37, 0xf7, 0xff, 0xff, 0xe6, 0xc0, + 0xff, 0xff, 0x7b, 0xef, 0xff, 0xff, 0x52, 0xe0, 0xff, 0xff, 0x24, 0xa5, 0xff, + 0xff, 0x72, 0xad, 0xff, 0xff, 0x4e, 0x25, 0x00, 0x00, 0x2c, 0xfd, 0xff, 0xff, + 0x52, 0x29, 0x00, 0x00, 0x42, 0xf8, 0xff, 0xff, 0xde, 0xe4, 0xff, 0xff, 0x79, + 0x04, 0x00, 0x00, 0xe1, 0x1b, 0x00, 0x00, 0x5c, 0x10, 0x00, 0x00, 0x2b, 0x2a, + 0x00, 0x00, 0x45, 0x0b, 0x00, 0x00, 0x04, 0xc5, 0xff, 0xff, 0x5c, 0x39, 0x00, + 0x00, 0x50, 0xf1, 0xff, 0xff, 0x17, 0xb8, 0xff, 0xff, 0xf4, 0xf8, 0xff, 0xff, + 0x1b, 0xe6, 0xff, 0xff, 0xb2, 0x0d, 0x00, 0x00, 0xd2, 0xae, 0xff, 0xff, 0x4a, + 0xee, 0xff, 0xff, 0x7d, 0x2e, 0x00, 0x00, 0x8d, 0xe7, 0xff, 0xff, 0x92, 0x03, + 0x00, 0x00, 0xd6, 0x34, 0x00, 0x00, 0x1c, 0xdf, 0xff, 0xff, 0x85, 0xab, 0xff, + 0xff, 0xbf, 0x4b, 0x00, 0x00, 0x9b, 0x3e, 0x00, 0x00, 0x09, 0xd6, 0xff, 0xff, + 0x7a, 0x00, 0x00, 0x00, 0x1c, 0x18, 0x00, 0x00, 0x76, 0x36, 0x00, 0x00, 0x80, + 0x94, 0xff, 0xff, 0x6b, 0xf7, 0xff, 0xff, 0x0c, 0x1b, 0x00, 0x00, 0xa6, 0x95, + 0xff, 0xff, 0x64, 0xd4, 0xff, 0xff, 0xc0, 0x0f, 0x00, 0x00, 0xea, 0x1c, 0x00, + 0x00, 0x41, 0x01, 0x00, 0x00, 0xba, 0x1d, 0x00, 0x00, 0x80, 0x2a, 0x00, 0x00, + 0x9a, 0x13, 0x00, 0x00, 0xf0, 0x27, 0x00, 0x00, 0x31, 0x0d, 0x00, 0x00, 0x9f, + 0x13, 0x00, 0x00, 0xde, 0xf1, 0xff, 0xff, 0x9b, 0xcf, 0xff, 0xff, 0xe5, 0xf4, + 0xff, 0xff, 0xbc, 0xc5, 0xff, 0xff, 0xea, 0xf1, 0xff, 0xff, 0x32, 0xf6, 0xff, + 0xff, 0x12, 0xf2, 0xff, 0xff, 0x6e, 0xdf, 0xff, 0xff, 0x44, 0xd2, 0xff, 0xff, + 0xa6, 0x54, 0x00, 0x00, 0x6b, 0x31, 0x00, 0x00, 0x48, 0x09, 0x00, 0x00, 0x77, + 0xee, 0xff, 0xff, 0xbb, 0xbc, 0xff, 0xff, 0x7c, 0xb5, 0xff, 0xff, 0x87, 0x1c, + 0x00, 0x00, 0xba, 0xda, 0xff, 0xff, 0x2e, 0xe9, 0xff, 0xff, 0xd0, 0xff, 0xff, + 0xff, 0x8a, 0xc1, 0xff, 0xff, 0x23, 0x42, 0xff, 0xff, 0xdf, 0xe8, 0xff, 0xff, + 0x13, 0x12, 0x00, 0x00, 0x63, 0xe5, 0xff, 0xff, 0xdf, 0xe9, 0xff, 0xff, 0xcc, + 0xc5, 0xff, 0xff, 0xfd, 0xe2, 0xff, 0xff, 0x43, 0xf5, 0xff, 0xff, 0x30, 0xf5, + 0xff, 0xff, 0x60, 0x1e, 0x00, 0x00, 0x62, 0x9f, 0xff, 0xff, 0xcb, 0x0b, 0x00, + 0x00, 0xd1, 0x5c, 0x00, 0x00, 0xe9, 0xdf, 0xff, 0xff, 0xec, 0x20, 0x00, 0x00, + 0x47, 0xfb, 0xff, 0xff, 0x94, 0x9e, 0xff, 0xff, 0x45, 0x0e, 0x00, 0x00, 0x27, + 0x0b, 0x00, 0x00, 0x26, 0xdb, 0xff, 0xff, 0xdf, 0xbb, 0xff, 0xff, 0x61, 0x51, + 0x00, 0x00, 0xd9, 0x1d, 0x00, 0x00, 0xa9, 0xb5, 0xff, 0xff, 0xb9, 0x5a, 0x00, + 0x00, 0xea, 0xd7, 0xff, 0xff, 0x02, 0xfb, 0xff, 0xff, 0x0c, 0x48, 0x00, 0x00, + 0x29, 0xea, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x00, 0xf5, 0x1a, 0x00, 0x00, 0x14, + 0x14, 0x00, 0x00, 0x22, 0x0b, 0x00, 0x00, 0xbc, 0x24, 0x00, 0x00, 0xeb, 0xda, + 0xff, 0xff, 0xed, 0xe8, 0xff, 0xff, 0x13, 0x12, 0x00, 0x00, 0xcd, 0x0a, 0x00, + 0x00, 0x8a, 0x28, 0x00, 0x00, 0x62, 0x03, 0x00, 0x00, 0xd2, 0x8f, 0xff, 0xff, + 0x0f, 0x08, 0x00, 0x00, 0x4c, 0x41, 0x00, 0x00, 0x95, 0xd9, 0xff, 0xff, 0xea, + 0xfc, 0xff, 0xff, 0x6a, 0x01, 0x00, 0x00, 0x4b, 0x95, 0xff, 0xff, 0x6e, 0x0f, + 0x00, 0x00, 0x41, 0x0f, 0x00, 0x00, 0xea, 0xfc, 0xff, 0xff, 0x55, 0xe8, 0xff, + 0xff, 0xab, 0x8a, 0xff, 0xff, 0x77, 0xa9, 0xff, 0xff, 0x6e, 0x38, 0x00, 0x00, + 0xc8, 0x1e, 0x00, 0x00, 0x31, 0xf0, 0xff, 0xff, 0x41, 0x99, 0xff, 0xff, 0x0c, + 0x0a, 0x00, 0x00, 0x51, 0xc6, 0xff, 0xff, 0xdc, 0x28, 0x00, 0x00, 0x22, 0xad, + 0xff, 0xff, 0xee, 0x2b, 0x00, 0x00, 0x99, 0xf0, 0xff, 0xff, 0x0b, 0xf2, 0xff, + 0xff, 0xba, 0x32, 0x00, 0x00, 0xc4, 0x3c, 0x00, 0x00, 0x7c, 0xb2, 0xff, 0xff, + 0xac, 0x07, 0x00, 0x00, 0x6d, 0x0d, 0x00, 0x00, 0xef, 0x15, 0x00, 0x00, 0xce, + 0xf9, 0xff, 0xff, 0x2f, 0x11, 0x00, 0x00, 0x8f, 0x10, 0x00, 0x00, 0xe2, 0x05, + 0x00, 0x00, 0xda, 0xdc, 0xff, 0xff, 0xff, 0x06, 0x00, 0x00, 0xc1, 0x10, 0x00, + 0x00, 0xc0, 0xeb, 0xff, 0xff, 0x4b, 0xe1, 0xff, 0xff, 0x72, 0xec, 0xff, 0xff, + 0xeb, 0xe4, 0xff, 0xff, 0x34, 0x31, 0x00, 0x00, 0xe0, 0xf9, 0xff, 0xff, 0x9b, + 0x23, 0x00, 0x00, 0xa3, 0xd8, 0xff, 0xff, 0xb1, 0xb6, 0xff, 0xff, 0xa7, 0xec, + 0xff, 0xff, 0x15, 0x23, 0x00, 0x00, 0xd3, 0xa3, 0xff, 0xff, 0xa2, 0xb1, 0xff, + 0xff, 0x3d, 0x29, 0x00, 0x00, 0xfb, 0xbc, 0xff, 0xff, 0x77, 0x29, 0x00, 0x00, + 0x9e, 0xeb, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x95, + 0xe3, 0x77, 0xf4, 0x7f, 0x81, 0x9d, 0xe6, 0x15, 0xa6, 0xc2, 0xba, 0xf5, 0xf3, + 0xe8, 0x03, 0xf1, 0xfb, 0x0d, 0xf2, 0x23, 0xfb, 0xef, 0x4c, 0xfd, 0xab, 0xd0, + 0x0e, 0xcf, 0xb8, 0x81, 0x84, 0xf1, 0xdf, 0xfb, 0xdb, 0xf8, 0xed, 0xe9, 0x07, + 0x2a, 0xac, 0xd3, 0xee, 0x40, 0x81, 0xc6, 0x20, 0xe7, 0xe4, 0xdd, 0x7f, 0xf8, + 0xe1, 0x24, 0x7f, 0xe7, 0x4f, 0xd3, 0x0c, 0xbc, 0x16, 0xc7, 0xc7, 0xec, 0xca, + 0xa6, 0x84, 0xae, 0xe2, 0x1d, 0x19, 0xb8, 0xe5, 0xc8, 0x89, 0xfb, 0xca, 0xf3, + 0xf9, 0xd6, 0xd1, 0xdf, 0xca, 0x2a, 0x46, 0x81, 0x2a, 0xf8, 0xc2, 0x09, 0xb0, + 0xa9, 0xf4, 0x0b, 0xb7, 0xfd, 0xdf, 0x74, 0xa9, 0xda, 0xed, 0x19, 0xba, 0xa3, + 0x01, 0xf1, 0x9e, 0xec, 0x17, 0x10, 0xf8, 0x95, 0x09, 0x20, 0xc7, 0xa0, 0xb3, + 0xc9, 0x1f, 0xd1, 0xcf, 0xe7, 0xf3, 0x7f, 0xe4, 0xcc, 0xbc, 0x81, 0xe9, 0xd9, + 0xc9, 0xf3, 0x02, 0xd3, 0x46, 0x3c, 0x81, 0xbc, 0xdf, 0xee, 0xe3, 0xdf, 0x02, + 0x23, 0xfe, 0xf8, 0xd4, 0x19, 0xd4, 0xa0, 0x7f, 0x0a, 0x0e, 0x26, 0xe4, 0x16, + 0x8b, 0x81, 0xee, 0xf8, 0xf1, 0xe8, 0xdb, 0xeb, 0x90, 0xc4, 0x2c, 0x9b, 0xf2, + 0xe9, 0x7f, 0x81, 0xb4, 0xf6, 0xaf, 0x8a, 0x51, 0xee, 0xee, 0x21, 0xe1, 0xa7, + 0xfb, 0x89, 0xd3, 0xce, 0x25, 0xcf, 0xa4, 0xb1, 0xe2, 0x6b, 0x14, 0x56, 0x81, + 0xa5, 0x20, 0xe2, 0xd1, 0xe2, 0xb6, 0x7f, 0x35, 0xff, 0xb6, 0xdd, 0x37, 0xf1, + 0x06, 0x18, 0x56, 0x02, 0xfd, 0xdd, 0xd1, 0x8c, 0x93, 0xfc, 0xee, 0xeb, 0xf8, + 0xf1, 0xbb, 0xa8, 0x2c, 0xbb, 0xdf, 0xeb, 0xf2, 0x13, 0xd8, 0xe1, 0x18, 0xfa, + 0x86, 0xd4, 0xb5, 0x81, 0xa2, 0xdb, 0xd5, 0x0a, 0xe0, 0x15, 0x2c, 0xca, 0xe9, + 0x05, 0xec, 0xc6, 0xf0, 0xa5, 0xe2, 0x0e, 0x0b, 0xed, 0x2e, 0x1e, 0xf8, 0x35, + 0xc5, 0xb3, 0x35, 0x33, 0x1f, 0xe4, 0x92, 0x2a, 0xcc, 0xf7, 0x8c, 0x02, 0x23, + 0x81, 0x0b, 0x41, 0xfa, 0x53, 0x0a, 0xfb, 0xe1, 0xd0, 0xd8, 0xf2, 0x8d, 0xc0, + 0x5d, 0xc2, 0xe0, 0x81, 0x81, 0xfd, 0x10, 0xbc, 0x1b, 0x81, 0xef, 0x38, 0x09, + 0xe8, 0x47, 0x9b, 0x35, 0x7f, 0x84, 0xcd, 0x60, 0xce, 0x81, 0x12, 0xb2, 0xa0, + 0x7f, 0xbe, 0x74, 0x7f, 0x81, 0x36, 0x25, 0x25, 0xfd, 0x92, 0x1e, 0xf9, 0xb9, + 0x1d, 0x12, 0xc7, 0xf2, 0x72, 0xfd, 0x74, 0xe0, 0x05, 0xf6, 0xad, 0xd1, 0xec, + 0xe8, 0x1c, 0x15, 0x0c, 0x1d, 0xf1, 0x81, 0xe7, 0x4a, 0x81, 0x0d, 0x0d, 0xbf, + 0xf5, 0x27, 0x0b, 0x44, 0xff, 0x19, 0x81, 0x53, 0xb8, 0x1e, 0xcb, 0x39, 0xeb, + 0x81, 0x7f, 0xfd, 0xd0, 0xd0, 0x81, 0x24, 0x7f, 0xa6, 0xf1, 0x81, 0xcb, 0x46, + 0xc7, 0x88, 0xe6, 0x81, 0x09, 0xff, 0x3c, 0x2a, 0xb1, 0x81, 0xf9, 0xe2, 0x81, + 0xa4, 0x04, 0x8f, 0xcc, 0x7f, 0xd0, 0x47, 0xf2, 0x45, 0xef, 0xd9, 0xa9, 0xec, + 0xf1, 0xc7, 0x68, 0xf4, 0xd0, 0xdf, 0xa0, 0xe1, 0xfd, 0x85, 0x6a, 0xda, 0x45, + 0x97, 0x6c, 0x7f, 0x00, 0xb0, 0x42, 0xf9, 0x7f, 0xe0, 0x16, 0xb7, 0xb1, 0xe7, + 0x89, 0x1e, 0x0a, 0x81, 0x20, 0x08, 0x81, 0xdd, 0x32, 0x3a, 0x9c, 0x03, 0x7f, + 0x08, 0xfb, 0xd2, 0x81, 0x10, 0xfa, 0x1c, 0xa0, 0x9b, 0x81, 0x3a, 0xd7, 0xb5, + 0x43, 0x73, 0x90, 0x36, 0x53, 0x88, 0x15, 0x9d, 0x9b, 0xdf, 0xc3, 0x7f, 0x8e, + 0x42, 0xdf, 0x1e, 0xf0, 0x37, 0x81, 0x60, 0xdc, 0x2f, 0xc5, 0x0e, 0x22, 0x2e, + 0x1b, 0xa9, 0x06, 0x01, 0xd9, 0xbd, 0xf7, 0x7f, 0x7f, 0x81, 0xef, 0x81, 0xc8, + 0x81, 0x06, 0xb1, 0xcb, 0x81, 0xf7, 0x14, 0x4b, 0x0e, 0x11, 0xe4, 0xdb, 0xf4, + 0x34, 0xb9, 0x91, 0xda, 0x0e, 0x30, 0x7f, 0x06, 0x37, 0x41, 0xe4, 0x7f, 0x7e, + 0x7f, 0xe3, 0x81, 0xe2, 0xb8, 0x04, 0x25, 0x7b, 0x00, 0x1d, 0x74, 0xb6, 0x0f, + 0x40, 0xbb, 0xcb, 0xa5, 0x81, 0xc0, 0xef, 0x0e, 0x28, 0x27, 0xdb, 0x56, 0xdd, + 0x2e, 0xd9, 0xed, 0x4b, 0xec, 0x20, 0x5e, 0x32, 0x1f, 0xc3, 0xd6, 0xb1, 0xe4, + 0x3f, 0xe6, 0xff, 0x1c, 0xd6, 0xbc, 0x12, 0xe8, 0x81, 0x20, 0x11, 0x7f, 0x42, + 0x42, 0x3f, 0x08, 0x81, 0x97, 0xd0, 0x7f, 0x81, 0xeb, 0x58, 0xda, 0x57, 0x1d, + 0x08, 0x81, 0x38, 0x81, 0xef, 0xe1, 0x03, 0xa3, 0x32, 0x14, 0x90, 0xf8, 0x48, + 0xe3, 0x09, 0xb1, 0xd1, 0x10, 0x22, 0x26, 0x89, 0xe3, 0x15, 0xc9, 0x08, 0x44, + 0xc1, 0x9f, 0xde, 0x7f, 0xec, 0x7f, 0xdf, 0xfe, 0xf4, 0x21, 0x6e, 0x05, 0xe6, + 0xf1, 0xda, 0x7f, 0xb4, 0x56, 0x47, 0xe7, 0x9d, 0x7f, 0x91, 0x67, 0x03, 0xc2, + 0xed, 0x01, 0xe2, 0xee, 0x81, 0xcc, 0xea, 0xed, 0x8b, 0xbb, 0xad, 0xcf, 0x98, + 0x1d, 0xe1, 0xfa, 0xf4, 0x01, 0x7f, 0x00, 0x7f, 0x6b, 0xc7, 0xfb, 0x7f, 0x97, + 0x16, 0xd8, 0x19, 0x10, 0xf8, 0x60, 0x4d, 0xb2, 0x8c, 0xe6, 0x32, 0x2d, 0x18, + 0x25, 0xc9, 0xa2, 0x7d, 0x61, 0x7f, 0x3d, 0x0d, 0xd8, 0xcd, 0xe6, 0x11, 0x0c, + 0x17, 0xd4, 0x4d, 0xde, 0xf9, 0x79, 0x49, 0x7f, 0xec, 0x81, 0xc4, 0xb0, 0xca, + 0xfd, 0xc2, 0x63, 0xa0, 0xf5, 0xbe, 0x43, 0x12, 0x45, 0xc6, 0x7f, 0xb2, 0x7f, + 0xe6, 0x94, 0x24, 0x1c, 0xda, 0x1b, 0x5a, 0xa8, 0x2d, 0x1d, 0x35, 0xde, 0x36, + 0x4a, 0x0f, 0x22, 0x11, 0xc5, 0x7e, 0xff, 0x5c, 0xbb, 0xd3, 0xa8, 0xd9, 0xb4, + 0x09, 0xdc, 0xbf, 0xed, 0x23, 0xdd, 0xd1, 0xdd, 0x0a, 0x1c, 0x05, 0x81, 0x91, + 0xd3, 0xd0, 0xa3, 0x33, 0xe4, 0x0e, 0x0c, 0x81, 0x15, 0x89, 0xd7, 0x81, 0x39, + 0x0c, 0x3f, 0xef, 0xff, 0xcc, 0xe8, 0x78, 0x48, 0x5c, 0xec, 0x2c, 0x78, 0xed, + 0x7f, 0x7f, 0xd2, 0xca, 0x34, 0xfe, 0x10, 0x9d, 0xcd, 0x0a, 0xb0, 0xed, 0xa3, + 0x86, 0xe5, 0x51, 0x81, 0xa6, 0x0c, 0x46, 0x35, 0x57, 0x88, 0xed, 0x81, 0xb8, + 0xfb, 0x13, 0xa7, 0x2b, 0x2e, 0x0c, 0xae, 0x7f, 0x81, 0x81, 0x7f, 0x7f, 0xed, + 0x84, 0xd9, 0x0f, 0xb2, 0x76, 0x00, 0xc9, 0x19, 0xdb, 0xf1, 0xf1, 0xf2, 0x41, + 0x27, 0x7f, 0x0c, 0x15, 0xfa, 0x36, 0x29, 0x92, 0x1f, 0xe5, 0x19, 0x7f, 0x33, + 0x7f, 0x7f, 0x81, 0x3a, 0x55, 0x8e, 0xa9, 0x7f, 0x25, 0xaa, 0xde, 0x25, 0xa7, + 0xaa, 0x58, 0x00, 0x20, 0x41, 0x0d, 0x08, 0x81, 0x1e, 0x7f, 0xe2, 0xb8, 0xc9, + 0x35, 0xca, 0xb9, 0xa6, 0x31, 0x66, 0x25, 0xdc, 0x54, 0xbc, 0x63, 0x35, 0xa7, + 0xe1, 0x0c, 0xc6, 0xbf, 0xee, 0xd8, 0xb7, 0xe2, 0x0d, 0xf5, 0xe5, 0x00, 0x28, + 0x72, 0x6f, 0xd9, 0xdb, 0xf6, 0x54, 0xe2, 0x8a, 0xe8, 0x0a, 0x70, 0x16, 0xdc, + 0x60, 0xb8, 0xe0, 0x25, 0x73, 0x7f, 0x2c, 0xe6, 0xf3, 0xbd, 0x7f, 0x7f, 0x1e, + 0xcb, 0xc5, 0xdc, 0xdf, 0xaa, 0x1e, 0x69, 0x72, 0xdb, 0x9e, 0xc8, 0xf2, 0xc5, + 0x1e, 0xf0, 0x6e, 0x5c, 0x98, 0x03, 0x54, 0x30, 0x41, 0x7f, 0x7f, 0xe8, 0xc2, + 0x81, 0x32, 0x81, 0xcc, 0xea, 0xf7, 0xb6, 0x7f, 0x04, 0x03, 0x02, 0x83, 0x28, + 0x62, 0x22, 0xd1, 0xbe, 0xd9, 0xf1, 0xfb, 0x5c, 0x3b, 0x81, 0x60, 0x3e, 0x81, + 0xdd, 0xde, 0x7f, 0xe4, 0xa6, 0xe0, 0x54, 0xdc, 0x7f, 0xd7, 0x2b, 0x6d, 0x1b, + 0x7f, 0x81, 0x33, 0xad, 0x7f, 0x9b, 0x83, 0x7f, 0xdc, 0x7f, 0x4c, 0x4b, 0x04, + 0x01, 0x49, 0xef, 0xe5, 0xfe, 0xbf, 0xfc, 0xa5, 0x2f, 0x08, 0x5e, 0xa2, 0xb8, + 0x7f, 0x61, 0x7f, 0xbd, 0x65, 0x0f, 0x7f, 0x3b, 0xd9, 0x53, 0x2d, 0xd8, 0x7f, + 0x89, 0xdf, 0x34, 0x3f, 0x51, 0x0a, 0x7f, 0xb7, 0x68, 0xd3, 0x2a, 0x7f, 0x7f, + 0x38, 0xa5, 0xf4, 0xff, 0x7f, 0x7f, 0xb2, 0x7f, 0xaa, 0xe1, 0x81, 0xfc, 0xe4, + 0x92, 0x7f, 0x7f, 0x7f, 0x0e, 0x38, 0x71, 0xb0, 0x7f, 0x81, 0x98, 0xbe, 0x7f, + 0x7f, 0x81, 0xef, 0xee, 0x1f, 0xf8, 0x3f, 0x4e, 0x14, 0x1d, 0x31, 0x81, 0x9c, + 0xe3, 0xa9, 0xc2, 0x7d, 0x6d, 0x00, 0x28, 0x04, 0x06, 0xc3, 0xb8, 0xeb, 0x53, + 0x12, 0x65, 0x81, 0xdd, 0x7f, 0xe9, 0xaf, 0x75, 0xbb, 0x2e, 0x55, 0xf8, 0x1d, + 0xdd, 0x7f, 0x81, 0x2f, 0xbe, 0x81, 0x64, 0x0f, 0x81, 0x7f, 0x0f, 0x14, 0xc1, + 0x7f, 0x6b, 0x7f, 0xb3, 0x15, 0x10, 0x54, 0xf8, 0x1d, 0x6f, 0xce, 0xa2, 0x81, + 0x33, 0x10, 0x79, 0x77, 0x1a, 0x7f, 0x10, 0x51, 0xd2, 0xd9, 0x38, 0xe8, 0xfc, + 0x35, 0x09, 0x5b, 0xc8, 0x20, 0x7f, 0x7f, 0x33, 0x72, 0xd2, 0xaf, 0x4c, 0x7f, + 0x3f, 0x81, 0x81, 0xa8, 0x71, 0xd5, 0x7f, 0x57, 0x10, 0x43, 0xce, 0x7f, 0xe1, + 0xf3, 0x10, 0xf3, 0xf9, 0xab, 0xd9, 0xdf, 0xa4, 0x7f, 0x76, 0x1a, 0xe4, 0x7f, + 0xac, 0xb8, 0x7f, 0x0b, 0x7f, 0xb0, 0x7f, 0x81, 0x17, 0x9f, 0xf5, 0x9a, 0xd4, + 0x4f, 0x66, 0xea, 0x7f, 0x97, 0x0f, 0x16, 0xdf, 0x52, 0xd3, 0x7f, 0xf0, 0x0f, + 0x20, 0xee, 0x00, 0x23, 0x50, 0x2d, 0x19, 0x48, 0xbd, 0xf2, 0x13, 0x81, 0xdb, + 0x81, 0x51, 0xfe, 0x1e, 0x17, 0x1d, 0x28, 0x7f, 0xd1, 0x11, 0x3d, 0x73, 0x90, + 0xdf, 0x7f, 0x4a, 0x2f, 0x35, 0x0c, 0x97, 0x7f, 0x7f, 0x13, 0xad, 0xdf, 0x86, + 0x14, 0x29, 0xbb, 0x19, 0x7f, 0x05, 0x23, 0x20, 0xfb, 0xf5, 0x10, 0x7f, 0xa5, + 0xfe, 0xf7, 0x1b, 0xfd, 0x0e, 0xbb, 0x20, 0xac, 0x81, 0x00, 0x14, 0x26, 0xd0, + 0x7f, 0x7f, 0x06, 0x16, 0xd3, 0xfe, 0x7f, 0xd6, 0x6c, 0x99, 0xba, 0x0d, 0xf7, + 0x13, 0x39, 0x30, 0xb7, 0x7f, 0xaf, 0x1a, 0x30, 0x59, 0x78, 0x0d, 0x7d, 0x4a, + 0x67, 0xfc, 0x45, 0x32, 0x40, 0xea, 0xd5, 0xf2, 0xf6, 0xa0, 0x75, 0xe0, 0x03, + 0xc8, 0x43, 0xe7, 0x23, 0xee, 0x4e, 0x09, 0x39, 0x45, 0x18, 0xc8, 0xd9, 0x40, + 0xe7, 0xde, 0xe3, 0x03, 0xcf, 0xf8, 0xcb, 0x08, 0x37, 0xc6, 0xc7, 0x7f, 0x19, + 0x6c, 0x0e, 0x7f, 0x17, 0xc1, 0xf8, 0x21, 0xc3, 0xaf, 0x7f, 0x7f, 0xa9, 0x7f, + 0x24, 0x81, 0x40, 0x16, 0x1e, 0x0e, 0x63, 0x56, 0x08, 0xee, 0x52, 0xb4, 0xf3, + 0xf2, 0xb1, 0x44, 0x07, 0xe8, 0x4d, 0xf7, 0x7f, 0xe9, 0xed, 0x7f, 0x1b, 0xcc, + 0x09, 0x0f, 0x7f, 0xc7, 0x15, 0x81, 0x1c, 0x81, 0xa6, 0x37, 0x22, 0x98, 0x7f, + 0x7f, 0x56, 0xca, 0x72, 0xf8, 0x81, 0xab, 0x3a, 0xf5, 0x3b, 0x07, 0xe5, 0xd2, + 0x2b, 0xf6, 0xaf, 0x23, 0x0d, 0x89, 0x7c, 0x7f, 0x77, 0x7c, 0xb7, 0xae, 0x4b, + 0x81, 0x4e, 0xda, 0x7f, 0x4b, 0x42, 0xd3, 0x05, 0x2d, 0x25, 0xf5, 0xdc, 0x4c, + 0x06, 0x7f, 0x0d, 0x5b, 0x20, 0x7f, 0xad, 0x84, 0x06, 0x9b, 0xd6, 0x6e, 0x05, + 0x58, 0x06, 0xeb, 0xe6, 0xa9, 0xd2, 0x01, 0xce, 0xcb, 0x81, 0x7f, 0xb7, 0x89, + 0xd3, 0x0d, 0x36, 0x19, 0xd7, 0x90, 0x55, 0xb2, 0x13, 0xd0, 0x2a, 0x81, 0xe9, + 0xeb, 0x78, 0x31, 0x1b, 0xc2, 0xf5, 0x0f, 0x40, 0xa1, 0x0e, 0x81, 0xd7, 0xeb, + 0xfd, 0xf6, 0x3d, 0xf8, 0xde, 0xdd, 0x7f, 0xb1, 0xff, 0x7f, 0x06, 0x81, 0x7f, + 0xd7, 0x54, 0xfc, 0x38, 0x3d, 0xd4, 0x41, 0xdb, 0xf9, 0xce, 0x64, 0xcf, 0xfd, + 0x6c, 0xd9, 0x81, 0xcd, 0xa5, 0x0a, 0xd0, 0xf7, 0xf6, 0x90, 0x60, 0x7f, 0xfa, + 0xa6, 0x0f, 0xf1, 0x7f, 0xf9, 0xc6, 0x37, 0xd3, 0x25, 0x0b, 0x4a, 0x0d, 0xae, + 0x81, 0x0f, 0x47, 0xf5, 0x38, 0xe7, 0x48, 0x38, 0xae, 0x7f, 0x0d, 0xef, 0x1b, + 0xcd, 0xbc, 0xfd, 0x35, 0xfd, 0x41, 0x20, 0xc9, 0x81, 0x15, 0xe6, 0xfe, 0x08, + 0x25, 0x23, 0x14, 0x7f, 0xb8, 0x1c, 0xf7, 0x6c, 0xf2, 0xe0, 0x1f, 0xca, 0x97, + 0xe6, 0x0d, 0x41, 0xfb, 0x28, 0x57, 0x9d, 0xa0, 0xfe, 0x07, 0xe3, 0x0f, 0xeb, + 0x11, 0x69, 0x3e, 0x0e, 0xf1, 0xcb, 0x1d, 0xef, 0xd2, 0xd3, 0x7f, 0x52, 0x7f, + 0x56, 0x71, 0xdc, 0x4d, 0xf3, 0x22, 0xf5, 0xb0, 0x0f, 0x2c, 0x0a, 0x9d, 0x65, + 0x5d, 0xff, 0x09, 0xde, 0x7f, 0xe1, 0xc2, 0x48, 0xd2, 0x02, 0x0f, 0xfe, 0xe7, + 0xf0, 0xfe, 0xd4, 0x10, 0x3d, 0xd9, 0x0f, 0xdf, 0x4b, 0x97, 0x32, 0xcf, 0xc3, + 0xc2, 0xb2, 0xe8, 0x27, 0xb5, 0x7f, 0xea, 0x05, 0xf3, 0xee, 0x10, 0x71, 0xa7, + 0xa9, 0x1b, 0x7f, 0x93, 0xc4, 0x12, 0x95, 0xb0, 0xe2, 0xd1, 0x10, 0x8e, 0xb7, + 0x7f, 0x43, 0xc0, 0x01, 0xba, 0xf4, 0x2a, 0xa5, 0xd8, 0x4f, 0xc1, 0xc6, 0xf9, + 0x1a, 0xc1, 0xc9, 0xb6, 0x16, 0xd9, 0x2d, 0x7f, 0xcb, 0xd0, 0x52, 0xbc, 0x3a, + 0x2a, 0xe3, 0x23, 0xd0, 0xcd, 0x43, 0x04, 0xc8, 0x2f, 0xf7, 0x50, 0x20, 0x53, + 0x11, 0xc9, 0xfe, 0x04, 0xf8, 0xd0, 0x09, 0x81, 0xbf, 0xaf, 0x12, 0x53, 0x1f, + 0xda, 0x4a, 0xf4, 0xfa, 0x0f, 0x0f, 0x18, 0xd6, 0x50, 0xc9, 0x2b, 0x7f, 0xfe, + 0x85, 0x58, 0x67, 0x1b, 0x7f, 0xfd, 0xf1, 0x05, 0x9f, 0x7f, 0x29, 0x4c, 0x2b, + 0xde, 0x4d, 0xe4, 0x17, 0x32, 0xd2, 0xee, 0x7b, 0xe8, 0x28, 0x81, 0x24, 0x6f, + 0x16, 0x2d, 0x21, 0xb6, 0x11, 0xa9, 0xd2, 0xaf, 0xc0, 0xed, 0xf4, 0x05, 0x7f, + 0xaf, 0x06, 0x2b, 0xb9, 0xb8, 0x38, 0xad, 0x13, 0xf8, 0xfb, 0xeb, 0x81, 0x1e, + 0xca, 0x5b, 0x4b, 0x09, 0x39, 0x01, 0x6d, 0xd9, 0x32, 0xfe, 0x81, 0xec, 0xf8, + 0x36, 0xaf, 0xe4, 0x7f, 0xe8, 0xa3, 0xc1, 0x08, 0xad, 0x43, 0xd7, 0xf1, 0xf7, + 0xde, 0x40, 0x00, 0x81, 0x46, 0xa5, 0xac, 0x8f, 0x1f, 0xc9, 0x5c, 0xe2, 0xe6, + 0xf8, 0xf9, 0xf9, 0x6e, 0x1f, 0x89, 0x52, 0x7f, 0xb9, 0xeb, 0xbd, 0x0d, 0xe7, + 0x0e, 0x0e, 0xfc, 0xe9, 0x95, 0x43, 0x16, 0x2a, 0x24, 0xed, 0x7f, 0x25, 0xf4, + 0x09, 0x49, 0x08, 0x30, 0x70, 0xf0, 0x84, 0x5b, 0x35, 0xa8, 0x81, 0x7e, 0x95, + 0x1d, 0xcd, 0xbb, 0xfd, 0xcf, 0x24, 0xd4, 0xe0, 0xff, 0x57, 0x17, 0xfc, 0xd2, + 0x0f, 0x81, 0xbf, 0x8c, 0xef, 0xbe, 0x6a, 0x7f, 0x61, 0xcb, 0xe6, 0x2e, 0xf3, + 0x2a, 0xb9, 0x22, 0xef, 0x4d, 0x81, 0x0a, 0xee, 0x1e, 0x9d, 0xc9, 0xcb, 0x2e, + 0xe5, 0x0c, 0xee, 0xd7, 0xe6, 0x13, 0x43, 0x7c, 0x1f, 0x00, 0x09, 0x22, 0x28, + 0x07, 0xd4, 0x81, 0x81, 0xd0, 0xad, 0xf3, 0xd9, 0xec, 0x61, 0xa0, 0xab, 0x1d, + 0xd6, 0x43, 0xe3, 0xe9, 0xd7, 0x29, 0xd1, 0xc2, 0xeb, 0xf4, 0x81, 0xdf, 0xf9, + 0x0e, 0x81, 0x11, 0x0d, 0xe4, 0x81, 0xff, 0xfb, 0xe2, 0xd5, 0x2a, 0x5d, 0x5d, + 0x0c, 0xef, 0x99, 0x1e, 0x46, 0xd8, 0x81, 0xb1, 0xfb, 0x48, 0x22, 0xd8, 0xf3, + 0xf0, 0x00, 0xb2, 0xb1, 0xf3, 0xcf, 0xe5, 0xc8, 0x8d, 0x26, 0xba, 0xe9, 0xa2, + 0xba, 0xe0, 0x43, 0xce, 0xb4, 0xfb, 0x7f, 0x7f, 0x81, 0xc1, 0x06, 0x2f, 0x41, + 0x59, 0xe5, 0x17, 0x00, 0x2b, 0x46, 0xc1, 0x7f, 0x09, 0x5c, 0x11, 0xe9, 0x1e, + 0x0f, 0xab, 0xf9, 0x2b, 0x21, 0x59, 0x35, 0xf5, 0x36, 0xc8, 0x1a, 0xb3, 0x81, + 0x81, 0xb3, 0x81, 0x81, 0xbe, 0xdd, 0xce, 0xe1, 0x25, 0x16, 0xfd, 0x22, 0xe6, + 0x91, 0x4f, 0x2d, 0x05, 0xdd, 0x9b, 0xf0, 0xdd, 0xf4, 0x1b, 0x0f, 0xe7, 0x02, + 0x41, 0x19, 0x75, 0xce, 0xb0, 0x97, 0x16, 0x63, 0xe2, 0x36, 0x9a, 0xf4, 0xf6, + 0xb8, 0x75, 0x16, 0x14, 0x1e, 0xfe, 0xcc, 0xcb, 0xd7, 0x42, 0x7f, 0x20, 0xdf, + 0x1f, 0x2a, 0x1f, 0x81, 0x51, 0x7f, 0xec, 0x2e, 0xdf, 0xf0, 0x16, 0xb3, 0x28, + 0x75, 0x40, 0x9f, 0x3a, 0x58, 0x0c, 0x2f, 0x56, 0x81, 0xe7, 0xe5, 0x3e, 0xbe, + 0xdb, 0xfc, 0x09, 0x22, 0xf4, 0xf1, 0x72, 0x0c, 0xf2, 0x8d, 0x32, 0xc2, 0xb8, + 0xbb, 0x9c, 0xd8, 0xa0, 0xf0, 0x10, 0x16, 0xf5, 0xd0, 0x9b, 0x7f, 0xda, 0x14, + 0xce, 0x13, 0xcd, 0xed, 0xc3, 0x5d, 0x1e, 0xf6, 0x13, 0xdb, 0xf0, 0xdb, 0xde, + 0x18, 0xfa, 0x24, 0x5a, 0xe8, 0x3f, 0xee, 0xb1, 0x0c, 0x81, 0x41, 0xea, 0x4a, + 0x4c, 0xe9, 0x1c, 0xff, 0x29, 0xf5, 0xa7, 0xaf, 0xbf, 0xe7, 0xe3, 0xbf, 0x04, + 0x23, 0xd8, 0x23, 0xba, 0xc8, 0xda, 0x31, 0xac, 0x5d, 0x7f, 0x28, 0xcf, 0xb8, + 0x07, 0xf2, 0xfa, 0x91, 0x2b, 0xd0, 0x36, 0xb2, 0x6c, 0x54, 0xce, 0xf4, 0x32, + 0xc8, 0x88, 0x07, 0xe3, 0x07, 0x7f, 0xc0, 0xd6, 0x1d, 0x40, 0x14, 0xcf, 0xf6, + 0xec, 0x97, 0xf7, 0xc5, 0x0f, 0xe1, 0x0e, 0x81, 0xcd, 0xbc, 0x7f, 0x7f, 0xdd, + 0x18, 0x52, 0xa3, 0xe7, 0xba, 0xf1, 0x81, 0x21, 0x18, 0xbb, 0xbd, 0xf6, 0x20, + 0xed, 0x0a, 0x06, 0x04, 0xbb, 0x7f, 0x15, 0xf5, 0xa0, 0x23, 0x2e, 0x3d, 0xdf, + 0x1e, 0xba, 0x4a, 0x5e, 0x40, 0x81, 0x10, 0x10, 0x2d, 0x24, 0xf4, 0x23, 0x29, + 0x85, 0x60, 0xd0, 0x79, 0x19, 0xc9, 0x81, 0x4a, 0x36, 0x3a, 0xf3, 0x5f, 0xaa, + 0xf7, 0xd7, 0xb9, 0x31, 0xca, 0xb9, 0xee, 0xe1, 0x55, 0xed, 0x13, 0xc2, 0x6d, + 0x0a, 0x0d, 0xee, 0xe3, 0xcd, 0x9f, 0x12, 0xa3, 0xd0, 0x28, 0xc3, 0x29, 0x27, + 0xbc, 0x81, 0xbd, 0xd4, 0x4c, 0xf1, 0xe6, 0x7f, 0xc2, 0x34, 0xf5, 0xda, 0xbb, + 0x05, 0xe1, 0xaa, 0xf4, 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x4d, 0x01, 0x00, 0x00, 0x79, 0xed, 0xff, 0xff, 0xca, 0xfe, 0xff, 0xff, + 0x59, 0xf6, 0xff, 0xff, 0xc4, 0x12, 0x00, 0x00, 0xf6, 0x08, 0x00, 0x00, 0x87, + 0xf9, 0xff, 0xff, 0x54, 0xf8, 0xff, 0xff, 0x99, 0xeb, 0xff, 0xff, 0x08, 0xfd, + 0xff, 0xff, 0x78, 0xf8, 0xff, 0xff, 0xa9, 0x0a, 0x00, 0x00, 0xf6, 0xf3, 0xff, + 0xff, 0xaa, 0x06, 0x00, 0x00, 0x1e, 0xf9, 0xff, 0xff, 0x54, 0xfd, 0xff, 0xff, + 0x55, 0xf5, 0xff, 0xff, 0x0b, 0xed, 0xff, 0xff, 0x00, 0x09, 0x00, 0x00, 0xa0, + 0xfe, 0xff, 0xff, 0x26, 0x00, 0x00, 0x00, 0x06, 0xfb, 0xff, 0xff, 0x4b, 0xf5, + 0xff, 0xff, 0xa6, 0x0d, 0x00, 0x00, 0x49, 0xf8, 0xff, 0xff, 0xef, 0x09, 0x00, + 0x00, 0x42, 0x0b, 0x00, 0x00, 0x1f, 0x0a, 0x00, 0x00, 0xb6, 0xfc, 0xff, 0xff, + 0x5e, 0x12, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x5d, 0xf5, 0xff, 0xff, 0x5f, + 0xf4, 0xff, 0xff, 0x81, 0xf5, 0xff, 0xff, 0xec, 0x07, 0x00, 0x00, 0x86, 0x06, + 0x00, 0x00, 0x1f, 0xfb, 0xff, 0xff, 0x94, 0x0d, 0x00, 0x00, 0x0d, 0xfe, 0xff, + 0xff, 0x7f, 0x04, 0x00, 0x00, 0x48, 0x04, 0x00, 0x00, 0xdb, 0x0d, 0x00, 0x00, + 0xad, 0xef, 0xff, 0xff, 0xc9, 0xf1, 0xff, 0xff, 0x9e, 0x0b, 0x00, 0x00, 0x30, + 0x0c, 0x00, 0x00, 0x0c, 0x07, 0x00, 0x00, 0x51, 0xfe, 0xff, 0xff, 0x76, 0xfe, + 0xff, 0xff, 0x12, 0xfd, 0xff, 0xff, 0x1c, 0xf9, 0xff, 0xff, 0x44, 0xf8, 0xff, + 0xff, 0xdf, 0xf9, 0xff, 0xff, 0x12, 0x07, 0x00, 0x00, 0x6c, 0x03, 0x00, 0x00, + 0xbf, 0x07, 0x00, 0x00, 0x15, 0x07, 0x00, 0x00, 0x81, 0xf9, 0xff, 0xff, 0xd3, + 0x07, 0x00, 0x00, 0xd5, 0xee, 0xff, 0xff, 0xb3, 0xfb, 0xff, 0xff, 0x80, 0x05, + 0x00, 0x00, 0xb4, 0xf6, 0xff, 0xff, 0xe6, 0xf9, 0xff, 0xff, 0xe5, 0x03, 0x00, + 0x00, 0xc2, 0x07, 0x00, 0x00, 0xbc, 0x05, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, + 0xc9, 0x04, 0x00, 0x00, 0xfb, 0xfc, 0xff, 0xff, 0x8e, 0xee, 0xff, 0xff, 0x1c, + 0x0a, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0xfa, 0xf4, 0xff, 0xff, 0xb5, 0x06, + 0x00, 0x00, 0x65, 0x0d, 0x00, 0x00, 0x82, 0xe8, 0xff, 0xff, 0x20, 0x03, 0x00, + 0x00, 0x2a, 0xf7, 0xff, 0xff, 0x60, 0xf3, 0xff, 0xff, 0xaf, 0x09, 0x00, 0x00, + 0xcd, 0xfb, 0xff, 0xff, 0x43, 0x05, 0x00, 0x00, 0x77, 0x04, 0x00, 0x00, 0x70, + 0x0c, 0x00, 0x00, 0x85, 0xf3, 0xff, 0xff, 0x78, 0x05, 0x00, 0x00, 0x62, 0x06, + 0x00, 0x00, 0x8b, 0xf8, 0xff, 0xff, 0xd1, 0x06, 0x00, 0x00, 0x1b, 0x0f, 0x00, + 0x00, 0x16, 0xfb, 0xff, 0xff, 0x22, 0x06, 0x00, 0x00, 0x1b, 0xf8, 0xff, 0xff, + 0x7a, 0x08, 0x00, 0x00, 0xee, 0xff, 0xff, 0xff, 0xe4, 0xf4, 0xff, 0xff, 0xc0, + 0xf7, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 0x5b, 0x05, 0x00, 0x00, 0xed, 0xf7, + 0xff, 0xff, 0x4f, 0xfc, 0xff, 0xff, 0x31, 0x09, 0x00, 0x00, 0x78, 0x03, 0x00, + 0x00, 0x5c, 0x09, 0x00, 0x00, 0x1d, 0x03, 0x00, 0x00, 0x9b, 0x0d, 0x00, 0x00, + 0xeb, 0x12, 0x00, 0x00, 0xdd, 0xf8, 0xff, 0xff, 0x4b, 0xff, 0xff, 0xff, 0xe7, + 0xee, 0xff, 0xff, 0xf4, 0xf7, 0xff, 0xff, 0x40, 0xfe, 0xff, 0xff, 0xc6, 0xfa, + 0xff, 0xff, 0x2e, 0xfa, 0xff, 0xff, 0x1b, 0xf1, 0xff, 0xff, 0x72, 0x07, 0x00, + 0x00, 0xb3, 0x09, 0x00, 0x00, 0x77, 0xfc, 0xff, 0xff, 0x35, 0x08, 0x00, 0x00, + 0x47, 0x06, 0x00, 0x00, 0x2b, 0xf9, 0xff, 0xff, 0x4e, 0x0f, 0x00, 0x00, 0x78, + 0x0a, 0x00, 0x00, 0xf9, 0x03, 0x00, 0x00, 0x76, 0x0a, 0x00, 0x00, 0xa6, 0xfc, + 0xff, 0xff, 0xfa, 0x03, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x2c, 0xee, 0xff, + 0xff, 0x86, 0x0b, 0x00, 0x00, 0xba, 0x09, 0x00, 0x00, 0x40, 0xfb, 0xff, 0xff, + 0x11, 0xfc, 0xff, 0xff, 0x17, 0x06, 0x00, 0x00, 0xf2, 0x08, 0x00, 0x00, 0x52, + 0x0e, 0x00, 0x00, 0xe3, 0x18, 0x00, 0x00, 0x92, 0x05, 0x00, 0x00, 0x90, 0xfb, + 0xff, 0xff, 0xc9, 0xff, 0xff, 0xff, 0x6c, 0xf4, 0xff, 0xff, 0x8e, 0xfe, 0xff, + 0xff, 0x44, 0xf9, 0xff, 0xff, 0xe7, 0x05, 0x00, 0x00, 0xb1, 0xfc, 0xff, 0xff, + 0x7e, 0xfb, 0xff, 0xff, 0x3f, 0xfe, 0xff, 0xff, 0xbe, 0xfa, 0xff, 0xff, 0x00, + 0x02, 0x00, 0x00, 0xf3, 0xfd, 0xff, 0xff, 0x0a, 0x0f, 0x00, 0x00, 0xca, 0xfc, + 0xff, 0xff, 0x10, 0x03, 0x00, 0x00, 0x6f, 0xfd, 0xff, 0xff, 0x0f, 0xf9, 0xff, + 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x32, 0x0a, 0x00, 0x00, 0x70, 0x03, 0x00, 0x00, + 0x74, 0xff, 0xff, 0xff, 0x8d, 0x09, 0x00, 0x00, 0x7b, 0x0a, 0x00, 0x00, 0x20, + 0xe9, 0xff, 0xff, 0x2b, 0xef, 0xff, 0xff, 0x82, 0xfa, 0xff, 0xff, 0xeb, 0x12, + 0x00, 0x00, 0xd2, 0xfc, 0xff, 0xff, 0x88, 0x08, 0x00, 0x00, 0xd6, 0xfa, 0xff, + 0xff, 0x3a, 0x08, 0x00, 0x00, 0x8d, 0xfe, 0xff, 0xff, 0xbd, 0x01, 0x00, 0x00, + 0x51, 0x09, 0x00, 0x00, 0x98, 0x0b, 0x00, 0x00, 0x40, 0xfe, 0xff, 0xff, 0x66, + 0x09, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 0x20, 0x0c, 0x00, 0x00, 0x9b, 0xf8, + 0xff, 0xff, 0x6c, 0xf8, 0xff, 0xff, 0x6d, 0x08, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0xb7, 0x0c, 0x00, 0x00, 0x88, 0xeb, 0xff, 0xff, 0xe2, 0x12, 0x00, 0x00, + 0xa7, 0x01, 0x00, 0x00, 0xf0, 0xfb, 0xff, 0xff, 0xfc, 0xfb, 0xff, 0xff, 0x29, + 0x0e, 0x00, 0x00, 0x89, 0xff, 0xff, 0xff, 0xef, 0x09, 0x00, 0x00, 0xdb, 0xf5, + 0xff, 0xff, 0xba, 0xec, 0xff, 0xff, 0xc1, 0x01, 0x00, 0x00, 0x5a, 0x12, 0x00, + 0x00, 0xc6, 0x04, 0x00, 0x00, 0x26, 0x06, 0x00, 0x00, 0x85, 0xfb, 0xff, 0xff, + 0xf6, 0x05, 0x00, 0x00, 0x98, 0x0d, 0x00, 0x00, 0x15, 0xfe, 0xff, 0xff, 0xc3, + 0xfc, 0xff, 0xff, 0xa9, 0xff, 0xff, 0xff, 0x9d, 0xe8, 0xff, 0xff, 0x22, 0x03, + 0x00, 0x00, 0x77, 0xf8, 0xff, 0xff, 0x3b, 0xf3, 0xff, 0xff, 0x0c, 0x0b, 0x00, + 0x00, 0x48, 0x07, 0x00, 0x00, 0x20, 0xfc, 0xff, 0xff, 0xcd, 0xf0, 0xff, 0xff, + 0x0b, 0x01, 0x00, 0x00, 0xb4, 0x04, 0x00, 0x00, 0xb8, 0xf3, 0xff, 0xff, 0x65, + 0xfa, 0xff, 0xff, 0x14, 0xfd, 0xff, 0xff, 0x8f, 0xf8, 0xff, 0xff, 0x02, 0x02, + 0x00, 0x00, 0x76, 0x0a, 0x00, 0x00, 0xc9, 0xeb, 0xff, 0xff, 0x2f, 0xf9, 0xff, + 0xff, 0xd3, 0xf6, 0xff, 0xff, 0xe9, 0x0b, 0x00, 0x00, 0x6e, 0x06, 0x00, 0x00, + 0x04, 0x12, 0x00, 0x00, 0x8c, 0xfc, 0xff, 0xff, 0xa1, 0x09, 0x00, 0x00, 0x8f, + 0x13, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff, 0x7f, 0xfa, 0xff, 0xff, 0x26, 0xff, + 0xff, 0xff, 0x99, 0x05, 0x00, 0x00, 0x81, 0xf9, 0xff, 0xff, 0x40, 0x00, 0x00, + 0x00, 0xf5, 0xf9, 0xff, 0xff, 0x6f, 0x06, 0x00, 0x00, 0xbf, 0xff, 0xff, 0xff, + 0x86, 0x14, 0x00, 0x00, 0xde, 0x09, 0x00, 0x00, 0xed, 0x08, 0x00, 0x00, 0xc3, + 0xf8, 0xff, 0xff, 0x97, 0x11, 0x00, 0x00, 0x2c, 0x0e, 0x00, 0x00, 0xe1, 0x0e, + 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1a, 0x0b, 0x00, + 0x00, 0xef, 0xf8, 0xff, 0xff, 0x6b, 0xf2, 0xff, 0xff, 0x84, 0xfa, 0xff, 0xff, + 0xf4, 0x03, 0x00, 0x00, 0xa0, 0xf2, 0xff, 0xff, 0x09, 0xf4, 0xff, 0xff, 0xe5, + 0x01, 0x00, 0x00, 0xcf, 0x07, 0x00, 0x00, 0x03, 0x0b, 0x00, 0x00, 0xb6, 0xf8, + 0xfe, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x26, 0xe0, 0xe1, + 0x99, 0x03, 0x3c, 0xd2, 0xd9, 0xe7, 0x1b, 0xd9, 0xfc, 0x13, 0xfd, 0xc8, 0xf4, + 0xf1, 0xd0, 0xde, 0x12, 0x10, 0x00, 0x1b, 0xf6, 0xcc, 0xb8, 0xb2, 0x38, 0x35, + 0xf0, 0xfa, 0x07, 0xfe, 0xe4, 0x1b, 0x21, 0x2b, 0xdd, 0xee, 0x36, 0xe1, 0xe5, + 0xc3, 0xfd, 0xff, 0xfe, 0xe7, 0xdb, 0xeb, 0x08, 0xc4, 0xcf, 0xb6, 0xe8, 0xff, + 0x1d, 0x2c, 0xf2, 0xe8, 0xfd, 0x1e, 0x51, 0x30, 0xca, 0x11, 0x30, 0xde, 0xb4, + 0x00, 0xf1, 0xed, 0x25, 0xfc, 0x8b, 0xfd, 0x26, 0xe2, 0xfb, 0x9e, 0xe3, 0xde, + 0xbb, 0x08, 0xf7, 0xef, 0x01, 0x0d, 0xca, 0xde, 0x01, 0xe6, 0x00, 0x34, 0xfa, + 0x31, 0x0b, 0xa5, 0xe9, 0x02, 0x4a, 0x28, 0xf1, 0xaa, 0x08, 0xdf, 0x36, 0xce, + 0xbe, 0xf6, 0x14, 0xf4, 0xd9, 0x2d, 0xbf, 0xe0, 0x25, 0x04, 0xeb, 0xd0, 0xf7, + 0xca, 0xfb, 0x12, 0x25, 0x3b, 0x14, 0xf2, 0xf9, 0x08, 0xf9, 0x00, 0xc4, 0x3c, + 0x0f, 0x23, 0xe8, 0xc8, 0xec, 0x0b, 0xd0, 0x05, 0xbc, 0xeb, 0xfd, 0xb8, 0xfb, + 0x26, 0xe7, 0xea, 0xfb, 0x12, 0x43, 0xf6, 0xc2, 0x10, 0x81, 0xcb, 0xc3, 0x12, + 0xfe, 0x1b, 0xfc, 0xea, 0x12, 0x1c, 0x04, 0xea, 0x46, 0x12, 0x37, 0x28, 0x12, + 0x32, 0x1a, 0xdd, 0x23, 0xe5, 0x01, 0xff, 0xfa, 0x25, 0x33, 0x03, 0x10, 0xed, + 0x0a, 0xde, 0xff, 0x19, 0xcf, 0xd6, 0xdc, 0x2c, 0xf7, 0x09, 0x1a, 0xf1, 0xed, + 0xde, 0xee, 0xe8, 0x14, 0x0e, 0x33, 0xe8, 0xd9, 0xa7, 0xec, 0x45, 0x2f, 0x06, + 0xd9, 0x19, 0xed, 0xd0, 0x2d, 0xcd, 0x1d, 0xe4, 0xc8, 0xee, 0xc4, 0xf2, 0xcb, + 0xff, 0xda, 0x41, 0x4a, 0xd5, 0xe1, 0x15, 0xed, 0xc4, 0x1b, 0x11, 0xdd, 0x24, + 0x30, 0x0a, 0x23, 0xbe, 0xfc, 0x23, 0xf0, 0x56, 0xd1, 0xdd, 0xf4, 0xd8, 0xd1, + 0x19, 0xd5, 0x27, 0x2e, 0xb0, 0xd2, 0x23, 0xe4, 0x30, 0x01, 0xe8, 0xef, 0x41, + 0x23, 0x12, 0xfd, 0xe8, 0xd8, 0xec, 0x4b, 0xdd, 0x02, 0xb9, 0xae, 0x0f, 0xe0, + 0x14, 0xf1, 0x18, 0x33, 0xf8, 0xf7, 0x43, 0xf4, 0x27, 0xf8, 0xed, 0x18, 0xe0, + 0x5b, 0xc4, 0xed, 0xde, 0x17, 0xf0, 0x2f, 0xc5, 0x1a, 0xda, 0xe6, 0xc5, 0xfa, + 0x34, 0xe0, 0xe6, 0xaf, 0xc0, 0xcf, 0x25, 0xe4, 0xed, 0xf4, 0xd6, 0x18, 0x1a, + 0xbb, 0xf4, 0xd3, 0xa8, 0x81, 0xef, 0xd0, 0x27, 0x28, 0xda, 0x45, 0xe8, 0x4f, + 0x0e, 0xd9, 0x20, 0x0a, 0xdc, 0xe0, 0x03, 0x2a, 0xfb, 0xd6, 0x1a, 0x2d, 0x42, + 0xef, 0x1e, 0x20, 0x12, 0xda, 0x2c, 0x02, 0xd8, 0xb6, 0x21, 0x56, 0xd5, 0x9a, + 0x1d, 0x18, 0x02, 0x1c, 0xd3, 0xe4, 0x07, 0x19, 0xfe, 0xd5, 0xfe, 0x02, 0xf1, + 0xf2, 0x20, 0x2f, 0x17, 0x21, 0xc3, 0xdf, 0x27, 0xf6, 0x18, 0x11, 0x9b, 0xe4, + 0x3d, 0x03, 0xe9, 0x31, 0x0d, 0xce, 0x0b, 0x0f, 0xb0, 0xfa, 0x08, 0xe3, 0xf2, + 0x1e, 0x2a, 0xff, 0x50, 0xc1, 0x13, 0x09, 0xf3, 0xea, 0xe8, 0x3f, 0x19, 0x22, + 0xc2, 0x14, 0xfd, 0x2c, 0x0c, 0xb9, 0x09, 0x30, 0x1a, 0xf8, 0xe7, 0xde, 0xbc, + 0x9a, 0xfd, 0xc0, 0x1c, 0x22, 0xee, 0x00, 0x30, 0xc9, 0xf5, 0x3d, 0xdd, 0x32, + 0x13, 0x36, 0xc0, 0xf1, 0x3a, 0x16, 0x0e, 0xd6, 0xb1, 0x12, 0x08, 0x03, 0x03, + 0xfa, 0xf1, 0x24, 0xfc, 0x1c, 0xd5, 0x2b, 0xd0, 0xc2, 0xcc, 0xe9, 0x17, 0x30, + 0x0b, 0xb2, 0x15, 0x6e, 0xeb, 0xf4, 0xf2, 0x2a, 0xb6, 0x2f, 0x17, 0xd8, 0x24, + 0xf3, 0x04, 0x04, 0xd8, 0xc2, 0x02, 0x2d, 0xd9, 0xf0, 0xe8, 0xe0, 0x2c, 0x06, + 0x11, 0xd4, 0xe2, 0x1e, 0x32, 0x2c, 0xf1, 0xc2, 0x10, 0xca, 0xfa, 0xe6, 0x35, + 0xc3, 0xee, 0x14, 0x39, 0x29, 0x1b, 0xf5, 0xc8, 0x24, 0xfa, 0x2b, 0x08, 0x4f, + 0x37, 0xcb, 0x1e, 0x1a, 0xb0, 0xf4, 0xbd, 0xfa, 0xe7, 0xda, 0x06, 0x11, 0xdd, + 0xfd, 0xee, 0xf7, 0x04, 0xce, 0xfe, 0x07, 0x25, 0xd4, 0xec, 0xf6, 0xe7, 0x2e, + 0xec, 0x17, 0xed, 0x1b, 0xe7, 0xdf, 0xf3, 0x0d, 0xdf, 0x16, 0x3a, 0x6a, 0x10, + 0x1e, 0x0f, 0x03, 0xfa, 0xfd, 0x09, 0xcf, 0xde, 0xfc, 0x08, 0xfd, 0xf3, 0x16, + 0xe6, 0x11, 0x04, 0x1d, 0xf9, 0xba, 0xf2, 0x06, 0xfa, 0x21, 0xae, 0x29, 0x0f, + 0xc7, 0xed, 0x09, 0x44, 0xfd, 0x20, 0xe5, 0xf5, 0x2a, 0xcd, 0xd6, 0xec, 0x01, + 0x27, 0xd9, 0xff, 0x02, 0x34, 0xde, 0x31, 0xbc, 0xd6, 0xfc, 0xf5, 0xfd, 0xe2, + 0xf4, 0xe9, 0xbb, 0xfc, 0x37, 0xe9, 0x06, 0xfc, 0xeb, 0xdc, 0xf5, 0xd6, 0xe8, + 0x07, 0x23, 0x15, 0x10, 0xe7, 0xcb, 0xcb, 0x2f, 0x04, 0xe2, 0xff, 0xf1, 0x0d, + 0x3a, 0xfb, 0x01, 0xf9, 0xfe, 0x48, 0xef, 0xf1, 0xea, 0xc9, 0xe4, 0xcc, 0xd9, + 0x06, 0xdd, 0xf1, 0xfe, 0xdd, 0xd0, 0x00, 0x03, 0xce, 0xf8, 0x25, 0xfe, 0xf1, + 0x00, 0xd7, 0xe7, 0x1c, 0xce, 0x16, 0xec, 0x26, 0xdd, 0x23, 0xe1, 0xf0, 0xee, + 0xd0, 0x04, 0xb5, 0xfc, 0xcc, 0x49, 0xfc, 0xf0, 0x01, 0xff, 0xb8, 0xfc, 0x24, + 0x16, 0xde, 0x16, 0x14, 0x31, 0x0a, 0xf2, 0x1d, 0xe4, 0x08, 0xfd, 0xfd, 0x00, + 0xd2, 0x1b, 0x11, 0xf3, 0x37, 0xee, 0x39, 0xfc, 0xde, 0xd6, 0x04, 0xe4, 0xd7, + 0xc6, 0xc8, 0x0f, 0x25, 0x25, 0xdb, 0x14, 0x04, 0x1c, 0xf1, 0xcf, 0xab, 0x66, + 0xe4, 0x1a, 0x03, 0xe8, 0xed, 0x20, 0x1a, 0x0d, 0xfc, 0xd3, 0xd8, 0xc3, 0xf3, + 0x12, 0xaa, 0x2b, 0x0e, 0x11, 0xea, 0xd5, 0xfc, 0xf0, 0xd7, 0xe7, 0x08, 0x33, + 0xcd, 0xec, 0xfe, 0x10, 0xf2, 0xf8, 0x18, 0x17, 0x01, 0xf8, 0xfb, 0x33, 0xaf, + 0x21, 0xdd, 0xef, 0x00, 0xe7, 0x7f, 0xf4, 0x10, 0xf7, 0x09, 0x13, 0xfc, 0x06, + 0x3d, 0xbf, 0x39, 0x9c, 0xd6, 0xd2, 0xf8, 0xfa, 0xc4, 0xdb, 0x01, 0x2b, 0xb8, + 0xef, 0x12, 0x15, 0xf3, 0xd8, 0xca, 0xe4, 0xfc, 0xda, 0x03, 0xaf, 0x0b, 0xff, + 0xcf, 0xfc, 0xca, 0xd1, 0xcf, 0xe5, 0x10, 0xb0, 0xf4, 0x26, 0xf2, 0x04, 0x1f, + 0xcd, 0xca, 0x02, 0x00, 0xe4, 0xd1, 0x2d, 0x01, 0xe5, 0xc1, 0xfa, 0x82, 0xfb, + 0x0d, 0x1e, 0x2f, 0xfa, 0x16, 0x02, 0xd3, 0x12, 0xef, 0xfc, 0x3f, 0xfa, 0x0c, + 0x91, 0xf5, 0x02, 0x0f, 0xf3, 0xb5, 0xcc, 0xc6, 0xc9, 0xee, 0x24, 0xaa, 0xc7, + 0xf8, 0xd9, 0xc4, 0x9d, 0xe8, 0x0c, 0xf1, 0x25, 0xe6, 0x17, 0xdf, 0xaa, 0xf8, + 0x20, 0x02, 0xb2, 0xca, 0xee, 0xdf, 0x07, 0x0d, 0x1a, 0xda, 0xd4, 0xa5, 0xe5, + 0xbb, 0xb2, 0xe0, 0x2b, 0xe9, 0xb1, 0x2a, 0xdb, 0xd1, 0xeb, 0xf1, 0xde, 0xe3, + 0x00, 0xbc, 0x10, 0xd7, 0xc1, 0x2d, 0x9e, 0xe8, 0xf2, 0x09, 0xbd, 0xe6, 0xc0, + 0xea, 0xed, 0xde, 0x3e, 0xf7, 0xc2, 0xdd, 0x24, 0xe0, 0xf5, 0xb1, 0x2c, 0x1a, + 0xd7, 0x2d, 0x2b, 0xe6, 0xd9, 0x0e, 0xdc, 0x19, 0x3e, 0x02, 0xb9, 0xd1, 0xec, + 0xb0, 0x03, 0x09, 0xcc, 0x24, 0xf0, 0xc6, 0xf2, 0xf5, 0x30, 0xb5, 0x03, 0x06, + 0x1f, 0xe2, 0xc8, 0xb4, 0xe8, 0xfd, 0x38, 0xf9, 0xfa, 0x09, 0xf5, 0xf4, 0xd0, + 0xec, 0xde, 0x05, 0xed, 0xcc, 0xf4, 0xee, 0xde, 0xfb, 0xd7, 0x06, 0xba, 0x07, + 0xd3, 0xf3, 0xeb, 0x1a, 0x43, 0x29, 0x04, 0x22, 0xaa, 0xbb, 0xea, 0xf4, 0xbe, + 0x1d, 0xf9, 0x11, 0xf9, 0xeb, 0xc4, 0x0a, 0xa0, 0xfd, 0xfb, 0x16, 0xd7, 0x12, + 0x07, 0xe8, 0x46, 0xef, 0xed, 0x5a, 0xd0, 0x10, 0xd6, 0xbc, 0x08, 0x27, 0x08, + 0x5a, 0x00, 0xe7, 0x1a, 0xbb, 0x81, 0x11, 0xd4, 0x3f, 0xe7, 0xfb, 0xef, 0xce, + 0xd0, 0x21, 0xd5, 0xfb, 0x65, 0xf8, 0x0f, 0x16, 0x4f, 0xdb, 0xf4, 0xde, 0xfe, + 0x2c, 0xc5, 0xf7, 0x06, 0xd0, 0x2d, 0xf5, 0xe1, 0x92, 0x27, 0x28, 0xea, 0xfe, + 0xf3, 0x0c, 0xc6, 0xd9, 0xeb, 0xd9, 0xef, 0xf5, 0x23, 0x00, 0x06, 0x1b, 0x24, + 0xd1, 0xff, 0xdf, 0x57, 0xb7, 0x17, 0xd8, 0x0c, 0x12, 0x48, 0xf0, 0xbe, 0x18, + 0x1a, 0x58, 0xf0, 0xc6, 0xd3, 0xc2, 0x1d, 0x17, 0xfa, 0x42, 0xdf, 0x20, 0xe8, + 0xdb, 0xf1, 0xdf, 0x04, 0xcf, 0x0b, 0xdd, 0xe0, 0x00, 0x5e, 0x02, 0x68, 0xc4, + 0x0c, 0x1b, 0x14, 0x11, 0x35, 0xf9, 0x4a, 0xb3, 0xf0, 0xb9, 0x91, 0x1e, 0xff, + 0xe3, 0x2f, 0x0f, 0xf0, 0xed, 0xd1, 0xe9, 0x21, 0xd5, 0x06, 0x1f, 0xef, 0xad, + 0x18, 0xf2, 0x99, 0xc5, 0xea, 0xf2, 0x71, 0xef, 0xe5, 0x2a, 0x2a, 0x4e, 0x7f, + 0x40, 0x44, 0xc9, 0x2b, 0xde, 0x2e, 0x0e, 0xf3, 0x61, 0x45, 0xd0, 0xe7, 0x3a, + 0xac, 0x21, 0x5a, 0xe2, 0x0f, 0xe5, 0x18, 0xdf, 0xd5, 0xd9, 0x1e, 0xe9, 0xe7, + 0x2d, 0x29, 0xe5, 0xa1, 0x06, 0x00, 0xcc, 0x02, 0x01, 0xc8, 0x05, 0xd5, 0x4f, + 0xbc, 0xee, 0xfd, 0x5f, 0xbf, 0x34, 0xd1, 0x10, 0xf1, 0xe6, 0x64, 0xf2, 0x1f, + 0x08, 0x3c, 0xb6, 0x05, 0x4d, 0x00, 0x0c, 0xe5, 0x0d, 0xde, 0xf3, 0x06, 0x7e, + 0x44, 0xc2, 0xae, 0xe4, 0xef, 0xd2, 0xe9, 0xfd, 0xff, 0x34, 0x9a, 0xd8, 0x28, + 0x24, 0x0a, 0xe8, 0xe8, 0xa2, 0xd9, 0xed, 0x06, 0xee, 0xd9, 0xfc, 0xf7, 0x0d, + 0xa6, 0xfb, 0x2c, 0xfd, 0xb2, 0xcc, 0xfc, 0xd8, 0x13, 0xdd, 0xde, 0xe8, 0xe4, + 0x17, 0xee, 0x20, 0x49, 0xd6, 0x41, 0x30, 0xe7, 0xfc, 0x05, 0xdb, 0xe0, 0x21, + 0xe4, 0xcc, 0xcc, 0xee, 0xcc, 0xf2, 0xb3, 0xed, 0x04, 0xf8, 0xc2, 0x72, 0x0c, + 0xea, 0x4d, 0x31, 0x2c, 0xb7, 0x37, 0xdd, 0xbe, 0xfe, 0xe6, 0x22, 0x20, 0xf6, + 0xea, 0x02, 0x05, 0x65, 0xda, 0xd1, 0xff, 0xee, 0x34, 0x0c, 0x92, 0x85, 0xed, + 0xde, 0x1b, 0xd3, 0x65, 0xe1, 0xb2, 0x25, 0x23, 0x02, 0xb0, 0xbf, 0x41, 0xb2, + 0xc7, 0xfb, 0x10, 0x04, 0x1b, 0xc1, 0xe6, 0xde, 0xaf, 0x0d, 0x01, 0x8f, 0xff, + 0xd8, 0xf6, 0xa0, 0x1d, 0xd5, 0x03, 0xdd, 0xc6, 0xf8, 0x05, 0xc6, 0x25, 0x3f, + 0x05, 0x9f, 0xfd, 0x1c, 0xd0, 0x0c, 0xc2, 0xe0, 0x09, 0xec, 0x1e, 0xcf, 0x30, + 0x18, 0xdb, 0x5a, 0x09, 0x87, 0xda, 0xd8, 0xc8, 0x00, 0x47, 0x2d, 0x09, 0x09, + 0xf0, 0x1e, 0x0d, 0xfa, 0xfd, 0xc3, 0xbd, 0xfe, 0x4f, 0x3b, 0x03, 0x1e, 0xe0, + 0x8f, 0xcb, 0x97, 0x05, 0xbc, 0xea, 0xec, 0x2b, 0xfd, 0x1b, 0xb2, 0x04, 0x9e, + 0xe7, 0xf3, 0x38, 0xe7, 0x46, 0x37, 0x24, 0x1c, 0x44, 0xa7, 0xeb, 0x03, 0xd7, + 0x27, 0xed, 0x0d, 0x14, 0xbd, 0xbf, 0xea, 0x11, 0x0b, 0xd6, 0x33, 0x2f, 0x62, + 0xdd, 0x3e, 0xf9, 0x3e, 0x23, 0x10, 0xf3, 0x30, 0xf3, 0x3f, 0xe2, 0xe4, 0x14, + 0xf9, 0x3f, 0x13, 0xd3, 0xfe, 0xd0, 0x27, 0x0f, 0x81, 0xd5, 0xf6, 0xf9, 0xe0, + 0xec, 0x19, 0x92, 0x50, 0x90, 0x27, 0x48, 0xf8, 0x13, 0xd6, 0x90, 0x4b, 0x07, + 0x25, 0x07, 0x08, 0xd0, 0x23, 0xdc, 0xfe, 0xe9, 0xe1, 0x12, 0x23, 0x2f, 0x85, + 0xdd, 0xc6, 0x32, 0x30, 0xea, 0x28, 0x0b, 0xd7, 0xf5, 0xe8, 0xa1, 0x0f, 0xe2, + 0x18, 0x38, 0xed, 0xda, 0x1a, 0xe6, 0x1f, 0xb7, 0x06, 0xdc, 0xe5, 0xda, 0xbc, + 0x15, 0x83, 0x18, 0xfa, 0xbd, 0xc6, 0xe7, 0xf0, 0x53, 0xe9, 0x07, 0x2a, 0x38, + 0xfe, 0x16, 0xd7, 0xe4, 0xfa, 0x2b, 0xfc, 0x9b, 0x17, 0x3b, 0x1d, 0x13, 0xa9, + 0x16, 0xb6, 0x57, 0xcf, 0xff, 0x21, 0xde, 0x45, 0x30, 0x81, 0x0f, 0x14, 0xe7, + 0xec, 0xf7, 0xeb, 0xc8, 0xb7, 0xed, 0xda, 0xbb, 0xa2, 0x06, 0x03, 0xfa, 0x59, + 0xfa, 0xf8, 0xa5, 0xf2, 0x06, 0xf0, 0xd2, 0xdb, 0x38, 0xaf, 0xf1, 0x29, 0x39, + 0xf9, 0xe8, 0xfb, 0xcf, 0x1a, 0xe5, 0xff, 0xab, 0xb8, 0xf5, 0x13, 0xba, 0xb9, + 0xe6, 0xd6, 0xe5, 0xeb, 0x11, 0x9b, 0xc4, 0x1c, 0x36, 0x26, 0x2c, 0x15, 0xf7, + 0x17, 0xf9, 0xf1, 0x0b, 0x07, 0x9c, 0x23, 0xfd, 0xbd, 0xe0, 0xb8, 0xfb, 0x33, + 0xc9, 0x08, 0xd7, 0xf4, 0x29, 0xeb, 0xf9, 0x22, 0xe4, 0x0f, 0xd3, 0x4a, 0xe3, + 0x31, 0x12, 0x3d, 0x39, 0xfc, 0xba, 0xe6, 0xaf, 0xd5, 0x1d, 0x15, 0xe4, 0xed, + 0xfa, 0xe1, 0xf3, 0x65, 0xa2, 0xc9, 0xca, 0xf3, 0x32, 0xc4, 0xf8, 0xb6, 0xf3, + 0x25, 0x2f, 0x1e, 0xc3, 0xc3, 0xdb, 0x06, 0xe0, 0x31, 0xe7, 0x2c, 0x3d, 0xfd, + 0xde, 0xdd, 0x34, 0xd1, 0x17, 0xcf, 0x0a, 0xc6, 0xfe, 0x04, 0xdd, 0x25, 0x10, + 0xde, 0x08, 0xe9, 0x28, 0xc8, 0xe7, 0x25, 0x81, 0xad, 0xe6, 0x12, 0xfe, 0x61, + 0x19, 0xb1, 0x05, 0x55, 0x75, 0x29, 0xc9, 0xe3, 0xe7, 0xf6, 0xc8, 0x95, 0x01, + 0x19, 0xe1, 0x06, 0xe2, 0x02, 0x4a, 0x59, 0x28, 0xe8, 0x16, 0x19, 0x21, 0xe8, + 0xd6, 0x89, 0x61, 0xb7, 0xe7, 0xcf, 0xbb, 0xcd, 0xe2, 0xbe, 0x70, 0x09, 0xf8, + 0x3b, 0xd4, 0x15, 0xee, 0x1a, 0x3c, 0x15, 0x3d, 0xff, 0xcc, 0xb9, 0x9e, 0x3d, + 0xcc, 0xe9, 0x0e, 0xf6, 0x01, 0x94, 0xf0, 0xf7, 0x0c, 0xb6, 0x14, 0x12, 0x26, + 0xe8, 0x2c, 0xd6, 0xce, 0xee, 0xd7, 0x4a, 0xae, 0x37, 0xa9, 0x12, 0x0c, 0x09, + 0xb0, 0x17, 0x0b, 0xce, 0xc6, 0x11, 0xd6, 0x40, 0x0e, 0x13, 0x1e, 0x07, 0x1a, + 0xf3, 0xdb, 0x26, 0x12, 0xc6, 0xf7, 0xff, 0xf3, 0x05, 0x2d, 0xc9, 0xe4, 0xf4, + 0xf8, 0x45, 0x12, 0x03, 0x23, 0x16, 0xc0, 0xeb, 0x25, 0x1a, 0xe4, 0xf0, 0x06, + 0x07, 0x04, 0x56, 0xaa, 0x0f, 0x20, 0x07, 0xba, 0x12, 0xcb, 0x0d, 0x1b, 0x46, + 0xd7, 0xf1, 0x29, 0xf6, 0xe6, 0x3d, 0xf5, 0xd0, 0x2f, 0xe6, 0x0f, 0x96, 0xe0, + 0x0c, 0xde, 0x34, 0xd1, 0x1c, 0xa5, 0xb3, 0x03, 0x5e, 0xd2, 0xd5, 0xaf, 0xf4, + 0xed, 0x25, 0xd2, 0x0d, 0x18, 0xdc, 0xa4, 0x09, 0x05, 0xcb, 0x2e, 0x1c, 0xe6, + 0xd0, 0xc2, 0xba, 0x22, 0xc6, 0xb9, 0xf4, 0xd2, 0x37, 0x17, 0x4b, 0xf7, 0x16, + 0xe8, 0xe6, 0x0e, 0x32, 0x5d, 0x0c, 0x6b, 0x3b, 0x1d, 0x68, 0xf7, 0xf1, 0xd0, + 0xaa, 0x25, 0x10, 0x0a, 0x36, 0xe9, 0xd0, 0x2a, 0xf8, 0xb5, 0x06, 0xe6, 0x54, + 0xec, 0xe8, 0x40, 0xfc, 0x1d, 0xcc, 0xd3, 0x0b, 0x17, 0x46, 0xc6, 0x54, 0xf9, + 0xec, 0xee, 0x07, 0x2f, 0xf5, 0x2b, 0xf7, 0x0f, 0xeb, 0x0d, 0xe9, 0xe2, 0xea, + 0xdb, 0xf0, 0xbf, 0x24, 0xe7, 0xd9, 0x22, 0x11, 0xed, 0x32, 0xff, 0xe8, 0x3a, + 0xec, 0x0a, 0xf6, 0xe8, 0xc9, 0xf1, 0xca, 0xee, 0x1b, 0x0d, 0xf2, 0xf4, 0x1a, + 0x57, 0x1a, 0x01, 0xcc, 0xcb, 0xb5, 0xcc, 0x2a, 0xcd, 0xf1, 0xd4, 0x24, 0x19, + 0xa6, 0xf6, 0x2a, 0x15, 0x3a, 0x07, 0x28, 0xcf, 0xdf, 0x24, 0x20, 0x0e, 0xe7, + 0x1e, 0xf1, 0x00, 0x0a, 0x4f, 0xfb, 0x0f, 0x19, 0x13, 0xbd, 0xc8, 0x1a, 0xdb, + 0x11, 0xf8, 0x01, 0xd1, 0x12, 0xb8, 0x3d, 0x31, 0x24, 0xd9, 0xf0, 0x2a, 0xfb, + 0xf2, 0x32, 0xf3, 0x07, 0x25, 0xd6, 0x09, 0x29, 0x2d, 0x22, 0xe2, 0x1a, 0x08, + 0x62, 0x1d, 0x7f, 0x18, 0x0e, 0x0a, 0x40, 0x0b, 0xd2, 0xac, 0x31, 0x47, 0xe9, + 0xf1, 0xf6, 0xff, 0x25, 0x06, 0x17, 0xce, 0xd9, 0xc2, 0xfe, 0xf8, 0x26, 0x23, + 0xc0, 0xfd, 0xca, 0xd1, 0xbf, 0x02, 0xe4, 0x15, 0xf1, 0xc7, 0xf9, 0xeb, 0x60, + 0xdc, 0x47, 0xe0, 0xdf, 0xe2, 0x16, 0xf5, 0xe4, 0xda, 0x42, 0x51, 0x37, 0xf0, + 0xeb, 0xdc, 0x27, 0xb1, 0x1a, 0xf8, 0xeb, 0xb9, 0xee, 0x33, 0xef, 0xdd, 0x90, + 0xd3, 0x22, 0xc8, 0xb8, 0xe5, 0xf5, 0x13, 0x06, 0x07, 0xda, 0xfa, 0x04, 0xf0, + 0xaf, 0x35, 0xd0, 0xd0, 0x14, 0x08, 0x2d, 0xf6, 0xed, 0x27, 0x27, 0xf8, 0xcb, + 0x23, 0xfb, 0x07, 0x2a, 0x27, 0x0c, 0xfc, 0xd9, 0xd4, 0x1f, 0xde, 0x0b, 0x0d, + 0x12, 0xd1, 0x08, 0x2b, 0xd1, 0x11, 0x03, 0xf3, 0x04, 0x45, 0xff, 0xd9, 0xef, + 0x19, 0x01, 0xec, 0x3d, 0xf3, 0x1a, 0xb7, 0xd8, 0xc2, 0xca, 0x18, 0x27, 0x01, + 0x29, 0x09, 0xd8, 0x14, 0xda, 0x11, 0x2d, 0x63, 0x40, 0xd6, 0xd0, 0xd4, 0xf7, + 0x1d, 0xde, 0xe1, 0xdc, 0xa6, 0x24, 0x13, 0xbb, 0xe4, 0x27, 0x3d, 0xf1, 0xd4, + 0x44, 0xd6, 0x17, 0xc4, 0xc5, 0xf8, 0xda, 0xc9, 0x4f, 0xe2, 0x13, 0x10, 0xf8, + 0xd0, 0x23, 0xdc, 0xf2, 0x26, 0x61, 0x1f, 0x02, 0xd1, 0xe0, 0xe6, 0xfb, 0xfe, + 0x1d, 0xac, 0xfb, 0xbd, 0x0d, 0x08, 0xe0, 0xb6, 0x2f, 0x11, 0xb5, 0x04, 0x4d, + 0xc0, 0xc9, 0xdf, 0xd8, 0xfe, 0xd5, 0xbb, 0xbf, 0x15, 0x0f, 0xf4, 0xf8, 0xd5, + 0xa2, 0xda, 0xbb, 0xd0, 0xae, 0xb9, 0xec, 0x07, 0xe2, 0x23, 0x16, 0x21, 0x0a, + 0x42, 0xae, 0xba, 0xb1, 0xea, 0x1b, 0x6b, 0x31, 0xb1, 0x0a, 0x17, 0x3a, 0xdc, + 0xae, 0x12, 0x03, 0xcf, 0xd2, 0xf6, 0xd4, 0xdf, 0x3a, 0xb6, 0xf8, 0x2d, 0xe2, + 0xa4, 0xe3, 0xf7, 0xfb, 0xd7, 0x0b, 0x9d, 0xde, 0xd7, 0xc9, 0x56, 0xee, 0x98, + 0x1c, 0x08, 0xab, 0xc2, 0x59, 0xa3, 0x30, 0x3f, 0x2d, 0xd0, 0x08, 0x1e, 0xed, + 0xdc, 0x1e, 0xc0, 0x64, 0xc9, 0x4e, 0xd7, 0xe7, 0xeb, 0xe2, 0xe8, 0x20, 0xe2, + 0xcd, 0xfc, 0x37, 0xc9, 0x5a, 0x1f, 0x23, 0x14, 0x0c, 0xee, 0xe7, 0x06, 0xc8, + 0xc7, 0x12, 0x9a, 0xfa, 0xd9, 0xff, 0xe9, 0x3c, 0xff, 0xff, 0x7f, 0xc3, 0xe8, + 0xe3, 0x01, 0xa0, 0x19, 0x3e, 0x16, 0xce, 0x1b, 0xe8, 0x27, 0x52, 0xec, 0x49, + 0xf5, 0xe9, 0x3c, 0xc3, 0xab, 0x3f, 0xfc, 0x02, 0x05, 0xbe, 0x49, 0x08, 0xd7, + 0x20, 0xea, 0x0f, 0x43, 0xd3, 0xf6, 0x03, 0x43, 0x2f, 0x07, 0x0e, 0xdb, 0xb5, + 0x1c, 0x3e, 0x19, 0xbe, 0xe8, 0xe9, 0x12, 0xed, 0xd5, 0x08, 0x02, 0xf6, 0xf9, + 0x01, 0xde, 0x01, 0xcf, 0xe6, 0x83, 0x35, 0x9d, 0xc9, 0xbf, 0x8a, 0xbe, 0xf2, + 0xf4, 0x11, 0xd1, 0x0e, 0xa4, 0xdd, 0x0d, 0xb4, 0xd2, 0x95, 0xf4, 0xb4, 0x2a, + 0xa3, 0xc9, 0xe0, 0x25, 0xbd, 0xf9, 0xaf, 0xba, 0x2f, 0xf4, 0xeb, 0x03, 0xf3, + 0x37, 0xd9, 0xaf, 0xd7, 0x0c, 0xcb, 0x19, 0xd1, 0x0c, 0xeb, 0x1e, 0x0a, 0x2b, + 0xf1, 0x16, 0x0f, 0x11, 0xea, 0x00, 0x81, 0xfe, 0xc5, 0x31, 0xe8, 0x8c, 0xb9, + 0x21, 0xfe, 0xd8, 0xfa, 0x9e, 0xf9, 0x23, 0x16, 0x15, 0x1c, 0x10, 0xe3, 0xf2, + 0x23, 0x15, 0xe3, 0x0e, 0xdf, 0x47, 0x42, 0x2e, 0x28, 0x0d, 0xc1, 0x28, 0x25, + 0xe6, 0xd2, 0xe9, 0xe9, 0xe2, 0xf4, 0xef, 0x38, 0x04, 0xc6, 0x0d, 0x25, 0xff, + 0xc7, 0x15, 0xe2, 0x06, 0xe5, 0x0b, 0x99, 0xb8, 0x2c, 0xf6, 0x56, 0x19, 0x14, + 0x1b, 0x05, 0x07, 0xec, 0xed, 0xfe, 0x4a, 0x0b, 0x18, 0x29, 0xeb, 0xda, 0xd8, + 0x68, 0xe0, 0xfe, 0xec, 0xc1, 0x01, 0xd8, 0xe7, 0x48, 0x12, 0x1f, 0x1c, 0x33, + 0x05, 0xb5, 0x16, 0x08, 0x90, 0xc7, 0x3b, 0xc8, 0xf1, 0x16, 0x26, 0xa2, 0xb9, + 0xc0, 0x0b, 0xba, 0xe4, 0xd9, 0x0f, 0xb3, 0x17, 0xdc, 0xea, 0x2c, 0xf8, 0xe7, + 0x18, 0xec, 0x1b, 0xaa, 0xf3, 0x50, 0x0a, 0x34, 0x30, 0xca, 0xf0, 0xfe, 0xb3, + 0x3b, 0x22, 0xde, 0x20, 0x14, 0x0f, 0x41, 0xe9, 0x29, 0xf9, 0x2a, 0x0b, 0x05, + 0x34, 0x00, 0xa9, 0xff, 0x06, 0xdf, 0x3f, 0xed, 0x37, 0xfe, 0x07, 0xc9, 0x12, + 0xfd, 0x02, 0x42, 0xbc, 0xe7, 0xc7, 0x03, 0xdc, 0xe6, 0x1d, 0xd8, 0x34, 0x07, + 0xa0, 0xd9, 0xf6, 0xe6, 0xe5, 0xb0, 0xe7, 0xa4, 0xfc, 0x02, 0xed, 0xf0, 0xaa, + 0xed, 0xff, 0x05, 0xca, 0x3a, 0xc7, 0x10, 0xed, 0x1d, 0x48, 0xe8, 0x16, 0xe1, + 0xdc, 0x13, 0x24, 0xfa, 0x2a, 0x3d, 0xdd, 0x0a, 0xeb, 0xe0, 0x22, 0xe5, 0x03, + 0xe9, 0x2a, 0x06, 0x2e, 0x3d, 0x07, 0xd4, 0x05, 0x55, 0xea, 0x38, 0x12, 0xcd, + 0xff, 0xb7, 0x11, 0x06, 0xb2, 0x12, 0xb7, 0xc6, 0x09, 0x06, 0xc6, 0xfe, 0xdb, + 0xe5, 0xbc, 0xd3, 0xcc, 0x06, 0xe9, 0xd1, 0xdf, 0xda, 0x2f, 0x2f, 0xf8, 0x10, + 0xd8, 0xc4, 0x04, 0xf8, 0xe7, 0x40, 0xcc, 0xbe, 0xc6, 0xe7, 0xea, 0xd6, 0xd3, + 0xff, 0xed, 0x01, 0xec, 0x00, 0x05, 0x16, 0xfe, 0xc6, 0xe6, 0x14, 0xea, 0xd7, + 0xcc, 0xd4, 0xfc, 0x4e, 0xbf, 0xd6, 0xce, 0x35, 0xbc, 0x29, 0xed, 0x12, 0xcc, + 0xf5, 0x0f, 0xee, 0xc4, 0xd0, 0xaf, 0x0b, 0x1d, 0xfa, 0xbb, 0xfc, 0xde, 0x2f, + 0x11, 0xf7, 0x36, 0xe2, 0xdc, 0x02, 0xfd, 0x05, 0xfe, 0xf4, 0x1c, 0xd5, 0x24, + 0x28, 0xca, 0x14, 0xf7, 0xdf, 0x0a, 0xe0, 0x0f, 0x7f, 0xbe, 0x2e, 0xf7, 0x0f, + 0x0d, 0xd5, 0xf6, 0x12, 0xdc, 0x02, 0x16, 0x03, 0xc8, 0xe8, 0xfe, 0xe1, 0xf9, + 0xc7, 0xfa, 0xa9, 0x1c, 0x20, 0x18, 0xe2, 0xde, 0x11, 0xf6, 0xbf, 0xd3, 0xdc, + 0x09, 0x20, 0xe4, 0x06, 0xdb, 0x49, 0xd2, 0xcf, 0xd8, 0xf7, 0xea, 0xee, 0xdd, + 0xf6, 0x03, 0xc5, 0xd8, 0xf8, 0xd5, 0xf1, 0xbe, 0x0e, 0x14, 0xfb, 0x50, 0x28, + 0x17, 0xfa, 0x10, 0xc9, 0xda, 0xff, 0xdb, 0x14, 0x03, 0xf1, 0xd8, 0x4e, 0x1c, + 0x00, 0xfb, 0xef, 0xbb, 0x0b, 0xf9, 0xcd, 0xf9, 0xd9, 0xff, 0x12, 0xf1, 0x16, + 0xea, 0xf6, 0x5b, 0xd7, 0xf6, 0xe7, 0xd1, 0x9f, 0x97, 0x0f, 0x59, 0xfe, 0xb6, + 0xdc, 0x84, 0xa7, 0x1c, 0x19, 0x0a, 0xba, 0xe9, 0x05, 0xfd, 0x30, 0xc8, 0xc5, + 0xd1, 0x90, 0xc1, 0xda, 0x07, 0x09, 0x14, 0x40, 0xf7, 0xe3, 0xd6, 0x32, 0xe0, + 0x0d, 0xda, 0x59, 0xf9, 0xf5, 0xd1, 0xff, 0xf9, 0xb8, 0x88, 0xfe, 0x34, 0xff, + 0xdd, 0xf3, 0x14, 0x30, 0x25, 0x1a, 0x14, 0x23, 0x51, 0xc3, 0xfa, 0x0c, 0x81, + 0x29, 0x24, 0x89, 0x18, 0x52, 0x44, 0xa0, 0x1a, 0xfd, 0xf3, 0xfa, 0x66, 0x1a, + 0x27, 0xd1, 0xd6, 0xa8, 0xcf, 0xf5, 0xbb, 0xeb, 0xd7, 0x1c, 0xcb, 0x71, 0xd1, + 0x10, 0xd9, 0x38, 0x40, 0x24, 0x0c, 0x2f, 0xed, 0x22, 0x1f, 0xd8, 0xdb, 0x5b, + 0xf5, 0xe2, 0x87, 0xf1, 0x04, 0xcb, 0xd6, 0x05, 0x17, 0xef, 0x4e, 0xe0, 0x8b, + 0xa5, 0x3a, 0xf0, 0xfc, 0xff, 0x62, 0x14, 0x18, 0xcb, 0xa1, 0x03, 0x1a, 0x0f, + 0x2b, 0x0a, 0x06, 0x27, 0x23, 0x1f, 0xf0, 0x50, 0xd7, 0x09, 0xb2, 0x05, 0xeb, + 0x42, 0x16, 0x43, 0xea, 0xb0, 0x08, 0x0f, 0x5a, 0x91, 0xdc, 0xdc, 0x54, 0xa6, + 0xc4, 0xdc, 0xed, 0x1d, 0xa3, 0x33, 0xf4, 0xff, 0xd8, 0xef, 0x10, 0xf3, 0x35, + 0xd0, 0x24, 0xff, 0x25, 0xf3, 0x07, 0xe9, 0xf7, 0x44, 0xf3, 0x03, 0x20, 0x09, + 0xc4, 0x48, 0x36, 0x69, 0x31, 0x29, 0xb2, 0xea, 0x0c, 0xc5, 0xbe, 0x09, 0x10, + 0xfd, 0xb7, 0x93, 0x1d, 0x1d, 0x04, 0xf4, 0x47, 0xea, 0x19, 0xcf, 0xd0, 0x1d, + 0xd3, 0x04, 0x1c, 0xf0, 0x66, 0x12, 0x03, 0xad, 0xcf, 0xc1, 0xdf, 0xb0, 0x08, + 0xee, 0xf6, 0xf1, 0xef, 0xcf, 0xfe, 0xfb, 0xe0, 0x06, 0x28, 0xc8, 0x10, 0xe5, + 0xac, 0xa3, 0xd4, 0xce, 0x22, 0xe6, 0xa8, 0x1c, 0x3b, 0x3b, 0x14, 0xe8, 0x0c, + 0xf4, 0xb3, 0xee, 0x1d, 0x92, 0x27, 0x57, 0x04, 0x27, 0xf3, 0x4c, 0xdb, 0xfa, + 0xf5, 0xc4, 0xd5, 0xc7, 0xdf, 0xf5, 0xd3, 0x14, 0xd4, 0xd6, 0xf3, 0x42, 0xed, + 0x15, 0xf1, 0xee, 0xd3, 0x5d, 0xed, 0xc6, 0x6b, 0x08, 0xd3, 0xdc, 0x88, 0xd4, + 0xe2, 0xf6, 0xc7, 0xfb, 0xd9, 0xf7, 0xc5, 0x2d, 0xd4, 0xec, 0xf8, 0xd6, 0x4a, + 0xff, 0xc6, 0x0a, 0xf7, 0xdc, 0xc3, 0xcf, 0x13, 0x0f, 0x01, 0xe6, 0x08, 0xfa, + 0xfd, 0x03, 0x07, 0xf4, 0x0d, 0xf5, 0x37, 0xc2, 0xc1, 0xf4, 0xf7, 0x2d, 0x01, + 0x2d, 0x15, 0xfc, 0xc5, 0x09, 0x3b, 0xf1, 0xac, 0x3c, 0x05, 0xe2, 0xd3, 0x17, + 0xfd, 0xd5, 0xe1, 0x2f, 0x13, 0x17, 0x1a, 0xec, 0xf0, 0xfb, 0xf0, 0xc3, 0x2c, + 0x01, 0x5b, 0xf5, 0x05, 0x31, 0x53, 0xc1, 0xc9, 0xf4, 0x1c, 0xef, 0xef, 0xd1, + 0x19, 0xf7, 0x06, 0x1d, 0x11, 0xdb, 0x04, 0x1d, 0xbc, 0xd1, 0xfb, 0x0c, 0x09, + 0x25, 0xf8, 0x33, 0x3c, 0x0c, 0x27, 0xf1, 0x12, 0xbd, 0x1d, 0xdf, 0x2e, 0x7f, + 0xde, 0x17, 0x03, 0xcf, 0xfd, 0x06, 0xf0, 0xe3, 0xe7, 0xfd, 0xc5, 0xfa, 0x1e, + 0xd0, 0x23, 0x32, 0x10, 0x14, 0x2d, 0xe7, 0x14, 0xf6, 0x19, 0xdb, 0x31, 0x14, + 0xe0, 0x02, 0xdc, 0x05, 0xf8, 0xf3, 0x0a, 0xe3, 0xe5, 0xbe, 0x17, 0xcf, 0x3a, + 0xc8, 0xd4, 0xc5, 0xdf, 0x10, 0xc1, 0xf7, 0xf0, 0xbd, 0xf7, 0xf1, 0xc3, 0xd3, + 0xb7, 0x17, 0xe0, 0x22, 0xe6, 0x38, 0xcc, 0x00, 0xba, 0xd0, 0x23, 0xfe, 0xe4, + 0x17, 0x1a, 0xed, 0x28, 0xee, 0x09, 0xee, 0x4e, 0xc8, 0xfa, 0x34, 0xf5, 0x32, + 0xe9, 0x1d, 0x14, 0x02, 0xf7, 0x23, 0xfb, 0xf7, 0x0a, 0x04, 0xf6, 0xde, 0x8e, + 0xdb, 0xe8, 0x4d, 0x1c, 0xf8, 0xf6, 0x03, 0x53, 0xf2, 0x11, 0xc1, 0xd6, 0xe3, + 0x28, 0xba, 0xde, 0xff, 0xcc, 0xd1, 0x68, 0xfb, 0xd5, 0xd9, 0xe7, 0xf8, 0xfe, + 0xec, 0x3e, 0xea, 0xc5, 0x01, 0xed, 0xe4, 0x2d, 0xd8, 0xd7, 0xd5, 0xed, 0x17, + 0xe9, 0x25, 0xfe, 0xdf, 0xcc, 0x01, 0xe3, 0x0c, 0xf9, 0xb7, 0xb8, 0xfc, 0xf7, + 0x89, 0x1c, 0x13, 0xab, 0x14, 0xc6, 0xde, 0x1d, 0xb0, 0x3c, 0xb0, 0x05, 0x04, + 0x0a, 0x18, 0x16, 0xff, 0xda, 0xf7, 0xe1, 0xe6, 0x17, 0xee, 0x4e, 0x9d, 0x45, + 0xd0, 0xf4, 0x3b, 0xe9, 0x0a, 0x14, 0xbe, 0x04, 0x23, 0x38, 0x0d, 0x2a, 0xf9, + 0xe9, 0x29, 0xee, 0xc4, 0xf8, 0x0c, 0xaa, 0x13, 0xb4, 0x4c, 0xe2, 0xf5, 0x26, + 0xf6, 0x0c, 0x26, 0x06, 0xdc, 0xf0, 0xde, 0xf1, 0xff, 0x1b, 0xb3, 0xd6, 0xf5, + 0xf2, 0x2d, 0xdc, 0x28, 0x45, 0x0e, 0x18, 0xfb, 0x27, 0xd2, 0x39, 0x0e, 0x9d, + 0x48, 0x2c, 0xd0, 0x06, 0x3c, 0x3a, 0x5b, 0xa6, 0xcf, 0xea, 0x7f, 0xcd, 0x31, + 0xe4, 0x1a, 0x1a, 0xf9, 0x05, 0xaa, 0xca, 0x11, 0xee, 0x40, 0xaf, 0xce, 0xc8, + 0x3b, 0x1a, 0x4c, 0xd8, 0x32, 0x37, 0xc9, 0xfb, 0x95, 0xf6, 0x05, 0xdc, 0xb5, + 0x1b, 0xf2, 0x4b, 0xf1, 0x03, 0x0b, 0x3b, 0x29, 0xd0, 0x24, 0x40, 0x2e, 0xdd, + 0xca, 0xc5, 0xfe, 0x07, 0x0b, 0xe8, 0x99, 0xc8, 0x09, 0xd8, 0xdd, 0x63, 0x50, + 0xf5, 0x3e, 0x47, 0xb9, 0xea, 0xf0, 0xed, 0x40, 0xfe, 0x4d, 0x0e, 0xce, 0xfc, + 0xed, 0xbf, 0xde, 0xeb, 0x01, 0x13, 0x01, 0xcd, 0x44, 0xdb, 0x3e, 0xc0, 0x07, + 0xc0, 0x39, 0x0d, 0xfb, 0xf2, 0x04, 0xa8, 0xbc, 0xf3, 0x2d, 0xc3, 0x3c, 0x01, + 0x41, 0x1b, 0x1a, 0xf0, 0x65, 0x14, 0x0c, 0xf5, 0x01, 0x5e, 0x04, 0xb4, 0xf8, + 0x3b, 0x19, 0x13, 0x19, 0xbe, 0xa0, 0x12, 0xe2, 0x0f, 0xab, 0xcf, 0xb0, 0xd5, + 0xf2, 0x12, 0xf0, 0x18, 0x1d, 0xa0, 0x07, 0xe1, 0xf6, 0x08, 0x08, 0x0a, 0x0f, + 0x57, 0x00, 0xd9, 0x1f, 0x88, 0xf5, 0x1f, 0xd7, 0x07, 0x1e, 0xe3, 0xe3, 0x00, + 0x12, 0xe4, 0x08, 0xf2, 0x11, 0x29, 0xd3, 0x98, 0xd0, 0xed, 0xd9, 0xe1, 0x24, + 0x43, 0xfa, 0xd3, 0x0e, 0xed, 0xc2, 0x20, 0xaf, 0xfc, 0xaf, 0x1b, 0xf9, 0xb8, + 0xbd, 0xb2, 0xac, 0xf1, 0x05, 0xf6, 0xc5, 0x2a, 0x16, 0xa0, 0x2d, 0xc9, 0x20, + 0xff, 0x16, 0x22, 0x06, 0xd5, 0xea, 0xf9, 0xa2, 0x1e, 0xe8, 0xb1, 0x1f, 0xd8, + 0xca, 0xc7, 0xf4, 0xa3, 0x24, 0x0b, 0xff, 0xdf, 0x03, 0x10, 0xd6, 0xf3, 0xcf, + 0xbe, 0x25, 0x18, 0x17, 0x41, 0x04, 0x01, 0x41, 0x40, 0xdf, 0xe8, 0xb3, 0x29, + 0x0f, 0x15, 0x64, 0xca, 0x1b, 0x2f, 0xf2, 0x04, 0xe4, 0xd3, 0x51, 0xf2, 0x48, + 0x33, 0x06, 0x27, 0xbc, 0x1e, 0x26, 0x0f, 0x10, 0xc5, 0xd3, 0x0a, 0xe2, 0xc1, + 0x3b, 0xd1, 0x9f, 0xed, 0xc4, 0xec, 0x45, 0xd4, 0x08, 0x1b, 0xf3, 0xf9, 0xf6, + 0xa4, 0xd0, 0xf8, 0xdd, 0xd7, 0x24, 0xf2, 0xc4, 0xf8, 0xe0, 0xe8, 0x1a, 0x13, + 0x3d, 0x07, 0x34, 0x1e, 0x98, 0x0b, 0x1a, 0xb8, 0xdc, 0xf3, 0x10, 0x79, 0xca, + 0xfe, 0x04, 0xf7, 0x44, 0xb0, 0x27, 0x31, 0x23, 0xf2, 0xed, 0x14, 0xd2, 0xe1, + 0xf8, 0xfe, 0xf7, 0xf6, 0x9e, 0xf8, 0xe5, 0xe4, 0x35, 0xe4, 0x24, 0xc7, 0x84, + 0xf4, 0xe6, 0x3a, 0x01, 0xcc, 0xc5, 0xe5, 0xd5, 0xd9, 0x02, 0x3f, 0x05, 0xef, + 0x42, 0xba, 0x23, 0xdd, 0x13, 0x37, 0x42, 0xce, 0xff, 0xd1, 0xfe, 0xe8, 0x28, + 0xd5, 0xc2, 0x14, 0xe2, 0x17, 0xbf, 0x10, 0x0a, 0xe9, 0x0f, 0xdd, 0x7f, 0x44, + 0x58, 0xe3, 0x28, 0xdf, 0x49, 0x3f, 0xe2, 0xd4, 0x2d, 0x2f, 0x07, 0xc1, 0x22, + 0xf3, 0xc2, 0x00, 0xda, 0x99, 0xff, 0xea, 0xb5, 0xf4, 0x35, 0xbe, 0xf1, 0xf3, + 0x12, 0xf2, 0x1e, 0x2e, 0xfd, 0xf0, 0xb2, 0xcf, 0xf7, 0xb4, 0x3f, 0x8a, 0xd8, + 0xd4, 0xe8, 0xf4, 0x14, 0xc6, 0x08, 0xf8, 0xf4, 0x0b, 0xdd, 0xf1, 0xef, 0x07, + 0x07, 0xf5, 0x08, 0x15, 0xe0, 0xdd, 0x37, 0x01, 0xf8, 0xcd, 0xac, 0x19, 0x2e, + 0xd5, 0x14, 0x1f, 0xaa, 0x15, 0x0d, 0x29, 0x1b, 0x28, 0xd2, 0xe0, 0xe6, 0x19, + 0x29, 0xd7, 0x16, 0x1e, 0x1c, 0x5b, 0x40, 0x2e, 0x18, 0x36, 0x02, 0x07, 0x58, + 0x31, 0x81, 0xb7, 0x20, 0xd4, 0x01, 0xe2, 0xaf, 0x44, 0xfd, 0x38, 0x98, 0x46, + 0xa7, 0x50, 0xf4, 0xe0, 0x31, 0xf4, 0xd9, 0x24, 0x26, 0x17, 0x59, 0x30, 0xaa, + 0xc3, 0xf5, 0xf2, 0xf2, 0xe6, 0x32, 0xfe, 0x45, 0x38, 0xa1, 0xc8, 0xee, 0xf2, + 0xce, 0x10, 0xc5, 0x0f, 0xc1, 0xcf, 0x08, 0xd9, 0x3b, 0x2a, 0xb8, 0x3b, 0x0d, + 0xff, 0x3d, 0x08, 0x12, 0x37, 0xed, 0xae, 0x1d, 0x0d, 0xd3, 0xa8, 0x0c, 0x19, + 0xa6, 0x1a, 0x07, 0xe5, 0xdc, 0xf2, 0xd6, 0x67, 0x1d, 0xed, 0x44, 0xe3, 0x1e, + 0xf5, 0xcf, 0x06, 0xfa, 0xff, 0xc3, 0x26, 0xe0, 0xe2, 0xd2, 0xf5, 0x01, 0x38, + 0xf8, 0x20, 0x47, 0xc9, 0xfe, 0x2f, 0xb0, 0xcc, 0xf2, 0x22, 0x60, 0x95, 0x0f, + 0x26, 0xa1, 0x00, 0xdd, 0xfc, 0xf2, 0xff, 0xd1, 0x0e, 0xe5, 0x08, 0xc6, 0xdc, + 0x1a, 0xec, 0x35, 0xdc, 0xe5, 0x01, 0xba, 0xdb, 0xf3, 0xde, 0x07, 0x26, 0x0b, + 0xf0, 0x02, 0x10, 0x08, 0xe1, 0x1b, 0x0c, 0xac, 0xc9, 0xfb, 0xef, 0xd8, 0x92, + 0x07, 0x1b, 0x38, 0xf3, 0xdc, 0xb6, 0xc4, 0xe5, 0x13, 0xc0, 0xc4, 0x3e, 0xd3, + 0xdd, 0xf0, 0xdd, 0xdc, 0x01, 0x1a, 0xd6, 0x15, 0x9a, 0x19, 0x19, 0xe7, 0x32, + 0xb3, 0x0a, 0xe4, 0x04, 0xc9, 0x1b, 0x05, 0xf9, 0xdd, 0xd7, 0xf0, 0x09, 0x02, + 0xb1, 0xaf, 0xad, 0xca, 0xfd, 0x10, 0x90, 0x1b, 0xc8, 0x37, 0x05, 0xcf, 0xb2, + 0x97, 0xec, 0xf4, 0x38, 0xd6, 0xeb, 0xe2, 0xf0, 0x0c, 0x53, 0x1e, 0xec, 0xbc, + 0x2d, 0x27, 0xa9, 0xec, 0xe1, 0xff, 0x8a, 0xe0, 0xf9, 0x07, 0xcc, 0xda, 0xd6, + 0xdf, 0x00, 0xec, 0xef, 0x01, 0x0d, 0x00, 0xed, 0xe8, 0xe6, 0xd4, 0x12, 0x0f, + 0xfa, 0xcb, 0xfe, 0x31, 0xdc, 0x30, 0xce, 0x17, 0x02, 0xd0, 0xf1, 0xe2, 0xfb, + 0xff, 0xe3, 0x14, 0xf7, 0x0c, 0x07, 0x1f, 0xf4, 0xd4, 0xd2, 0xf4, 0x11, 0x06, + 0x1d, 0x05, 0xd6, 0x37, 0xeb, 0x10, 0xd9, 0xfa, 0xd4, 0xfe, 0x6d, 0x18, 0xf8, + 0xf9, 0x23, 0xcc, 0x35, 0xce, 0x07, 0xeb, 0xf2, 0xf6, 0x1e, 0x12, 0x06, 0x0e, + 0x07, 0x05, 0xe9, 0x01, 0x06, 0x36, 0xfb, 0x4c, 0xd9, 0x07, 0xd7, 0x22, 0xc9, + 0xcd, 0xff, 0x0a, 0x07, 0xfa, 0x3d, 0xd4, 0x08, 0xbd, 0xf1, 0x01, 0x06, 0xd8, + 0xdf, 0x07, 0x0f, 0xeb, 0xe7, 0x7b, 0xf2, 0xd7, 0xdd, 0xf0, 0xf3, 0x1e, 0x15, + 0x1d, 0xf9, 0xf1, 0xf1, 0x1f, 0xd1, 0xc5, 0xe7, 0xea, 0xcb, 0xe9, 0xd1, 0xed, + 0xf3, 0x14, 0x05, 0xee, 0x1f, 0x46, 0xf9, 0xeb, 0x1e, 0xc3, 0xea, 0x03, 0x10, + 0xc2, 0xe0, 0xbe, 0x13, 0xe3, 0x0e, 0xe4, 0xdd, 0x54, 0x12, 0x16, 0x07, 0x1e, + 0x04, 0x2d, 0x19, 0xf7, 0xf2, 0x12, 0xed, 0x1a, 0xda, 0x21, 0xf6, 0xfd, 0x11, + 0xeb, 0x02, 0xfe, 0x04, 0xef, 0xe3, 0x07, 0xf9, 0x33, 0xf0, 0xe6, 0xfc, 0x1f, + 0x0d, 0x2f, 0x02, 0x12, 0x2c, 0x22, 0x00, 0x1e, 0x01, 0x1c, 0xf7, 0x00, 0xdd, + 0xf3, 0x03, 0xf3, 0x0b, 0x02, 0xf3, 0xc5, 0x13, 0xd8, 0x1f, 0xf7, 0xe2, 0xf5, + 0x13, 0xfe, 0xd3, 0x22, 0xfa, 0x16, 0x07, 0x01, 0x05, 0x1e, 0xf3, 0xfd, 0xcd, + 0x14, 0x7f, 0x25, 0xf8, 0x50, 0xec, 0xcc, 0xef, 0xea, 0xda, 0xeb, 0x1f, 0xfa, + 0xe5, 0x12, 0xd1, 0x0f, 0xec, 0xc6, 0xd8, 0x36, 0x14, 0x16, 0x13, 0x03, 0xf8, + 0x04, 0xf8, 0xf6, 0xae, 0xe3, 0xeb, 0x05, 0xd3, 0x01, 0xf4, 0xf0, 0x07, 0xf7, + 0x2a, 0xd2, 0xf4, 0xe7, 0xee, 0x0a, 0xf9, 0x38, 0x47, 0xab, 0xc3, 0xad, 0xd0, + 0xc9, 0xb8, 0xc6, 0xd7, 0xdd, 0xfb, 0xe3, 0x28, 0xcf, 0xb6, 0xfb, 0x0d, 0x11, + 0x05, 0xd1, 0xdb, 0xf2, 0xe9, 0xf1, 0x1f, 0xf4, 0xe4, 0xfa, 0xe3, 0xeb, 0xc2, + 0x87, 0xef, 0xf8, 0x1d, 0xec, 0x08, 0x41, 0xaf, 0xff, 0xee, 0x1a, 0x13, 0x00, + 0xed, 0x2b, 0x1f, 0x00, 0x3a, 0xd1, 0x12, 0x0b, 0xfe, 0xff, 0xf8, 0x13, 0x77, + 0x17, 0x35, 0x90, 0xe0, 0x0c, 0x06, 0x62, 0x11, 0x68, 0xad, 0x17, 0xd2, 0x1e, + 0x06, 0xd8, 0xe8, 0x11, 0xf5, 0x14, 0xf1, 0xd0, 0xbd, 0xcb, 0xfd, 0x17, 0x81, + 0xeb, 0xcd, 0xc1, 0x01, 0xda, 0xae, 0x15, 0xd1, 0x58, 0xe3, 0x5e, 0x07, 0xa0, + 0xf1, 0xf6, 0x05, 0x03, 0xd9, 0xc2, 0xe5, 0xb7, 0xeb, 0xfc, 0xc1, 0xe5, 0x0e, + 0x0e, 0xc0, 0xd4, 0xc1, 0x0e, 0x1b, 0x1d, 0xf7, 0xe8, 0x07, 0xca, 0xd9, 0xf7, + 0xcb, 0x1a, 0xea, 0xd5, 0xec, 0x0f, 0xe1, 0xfb, 0xc0, 0xd5, 0xe7, 0xe8, 0x2f, + 0x06, 0xc2, 0xc8, 0x0d, 0xd6, 0xe9, 0xb3, 0x11, 0x14, 0xd4, 0x2a, 0xb6, 0x00, + 0x11, 0xbf, 0x1a, 0xb4, 0xfc, 0x37, 0xc8, 0xc4, 0xba, 0xab, 0x4f, 0x24, 0xcd, + 0x17, 0x29, 0xca, 0xc4, 0xcf, 0x31, 0xe7, 0xe7, 0x24, 0xe4, 0x19, 0xe6, 0xdf, + 0xe1, 0xeb, 0x2d, 0x09, 0xfa, 0xe4, 0xbd, 0xea, 0x03, 0x51, 0xff, 0x13, 0xbd, + 0xb2, 0x1e, 0x2b, 0xd0, 0xcd, 0xe9, 0x1e, 0x0b, 0x09, 0x1f, 0xd0, 0x2f, 0x0e, + 0x07, 0x1a, 0xd5, 0x09, 0x17, 0xbf, 0xc6, 0x23, 0xcf, 0x0d, 0x21, 0x90, 0x25, + 0x0b, 0x06, 0x12, 0xbd, 0xaf, 0x24, 0xd8, 0x1c, 0x08, 0x1f, 0x27, 0x0f, 0xf5, + 0x1d, 0xfa, 0xcc, 0x30, 0x27, 0xdf, 0xe2, 0x35, 0x0d, 0xce, 0xfb, 0x0f, 0x2f, + 0xf7, 0x9e, 0x38, 0xec, 0xf8, 0xde, 0xed, 0xf7, 0xfa, 0xf8, 0x51, 0xdc, 0x10, + 0x07, 0xe0, 0x16, 0xf1, 0xc8, 0xfa, 0x18, 0x29, 0x14, 0xce, 0xeb, 0xff, 0x04, + 0xde, 0xf0, 0x03, 0x9d, 0xf5, 0x92, 0x2a, 0x29, 0xe5, 0xe0, 0x1c, 0xf5, 0x21, + 0x67, 0x0a, 0x23, 0xed, 0x13, 0xd2, 0x28, 0x23, 0xe7, 0xbd, 0xf9, 0xfd, 0x10, + 0x3b, 0x14, 0xe5, 0x0d, 0x07, 0x31, 0x8c, 0x13, 0xfa, 0x49, 0x9a, 0xf8, 0x0e, + 0x22, 0xd3, 0xd6, 0xe4, 0x46, 0x01, 0x18, 0xfe, 0x0d, 0xd9, 0x21, 0x14, 0x1f, + 0xde, 0x90, 0xce, 0xfb, 0xe9, 0xf0, 0x18, 0xfb, 0xdc, 0x28, 0x02, 0xfc, 0x0b, + 0x06, 0xf6, 0xf1, 0x96, 0x15, 0x45, 0xc6, 0xd6, 0x12, 0x3f, 0xf6, 0xeb, 0xd8, + 0xda, 0xf4, 0x35, 0x18, 0xce, 0xc3, 0xeb, 0xa1, 0x93, 0x34, 0xf9, 0x14, 0x81, + 0x25, 0xdf, 0x2a, 0xe5, 0xd2, 0x1c, 0x24, 0xe4, 0x29, 0x28, 0xe8, 0xdc, 0x11, + 0xc3, 0xe8, 0x10, 0xee, 0xb8, 0xf8, 0xd0, 0x2d, 0xf0, 0x4a, 0x92, 0x2d, 0x01, + 0xf0, 0xd0, 0xf2, 0xce, 0x0f, 0x18, 0xe5, 0xbc, 0xbc, 0x2e, 0x48, 0xf9, 0xeb, + 0x35, 0x95, 0x2f, 0xef, 0xd9, 0x1e, 0xe3, 0x22, 0xca, 0xd5, 0x13, 0x31, 0xcc, + 0xa5, 0xbf, 0xaf, 0xf4, 0xdb, 0x2f, 0x50, 0x0b, 0x2d, 0x07, 0x3f, 0x54, 0x1a, + 0x31, 0xf5, 0x1a, 0xf8, 0xdc, 0xee, 0xe2, 0x20, 0xcb, 0x08, 0x01, 0xfe, 0xae, + 0xd5, 0x30, 0xec, 0xc2, 0xbd, 0xd0, 0x3f, 0xdd, 0x29, 0x14, 0xf2, 0x3d, 0xf0, + 0xe2, 0x1e, 0xfe, 0xaa, 0x20, 0x05, 0x09, 0xea, 0x2a, 0xfb, 0xee, 0xd8, 0x07, + 0xe8, 0x3a, 0xf0, 0x36, 0xed, 0xda, 0x1a, 0x17, 0x0c, 0x90, 0x0b, 0x07, 0x17, + 0xcc, 0xaa, 0x57, 0xda, 0xff, 0x37, 0x14, 0xf6, 0x4a, 0xd8, 0xe8, 0x3d, 0xef, + 0x0c, 0x87, 0x35, 0xb3, 0x01, 0x43, 0xfb, 0x19, 0x02, 0xd6, 0x4e, 0x02, 0x37, + 0x01, 0x04, 0x23, 0xb9, 0xcc, 0x83, 0x4d, 0xe6, 0xe4, 0xf1, 0x4d, 0xd1, 0xf5, + 0xd1, 0xcf, 0xe3, 0x0f, 0xd5, 0x05, 0x1c, 0xd8, 0x03, 0x2e, 0xf3, 0xd6, 0xfb, + 0x15, 0x09, 0xdd, 0xc2, 0xd6, 0x0b, 0x24, 0xe2, 0x1d, 0xc1, 0xdd, 0xfa, 0xee, + 0xc5, 0x30, 0xda, 0x15, 0xe3, 0xf5, 0x28, 0x12, 0xeb, 0xce, 0x96, 0xd4, 0x47, + 0x1d, 0x10, 0xc3, 0xd6, 0x00, 0xf5, 0xf7, 0xd5, 0x10, 0xe3, 0x0d, 0xd8, 0x08, + 0xee, 0x28, 0x0a, 0x23, 0xa6, 0x0f, 0xdf, 0x11, 0x3a, 0x1d, 0x25, 0x17, 0x4a, + 0x43, 0xea, 0xef, 0xfd, 0xcb, 0xfb, 0xce, 0x16, 0x19, 0x03, 0xf6, 0x47, 0xdf, + 0xd5, 0xd1, 0x08, 0x0a, 0xe8, 0x06, 0x11, 0x30, 0xdf, 0xdb, 0x14, 0x19, 0x1e, + 0x7f, 0xb2, 0xe7, 0x11, 0xe1, 0xfc, 0xf4, 0xf9, 0xdd, 0x09, 0x1e, 0xfa, 0xf0, + 0xee, 0xd4, 0xec, 0x0e, 0xb4, 0xe0, 0xea, 0x32, 0xbc, 0xff, 0xcb, 0x15, 0x4d, + 0x3e, 0xd5, 0x05, 0x12, 0x0c, 0x37, 0x91, 0xe3, 0x2d, 0x10, 0xdb, 0xe1, 0x40, + 0xf7, 0xf2, 0xf3, 0x11, 0x70, 0x07, 0x10, 0xe7, 0xcd, 0xd1, 0x05, 0x0e, 0x9f, + 0xc9, 0x1d, 0xf5, 0xf6, 0xe6, 0xfb, 0xe7, 0x2a, 0xde, 0x08, 0xff, 0xc5, 0xd0, + 0xd4, 0x1e, 0xe8, 0xe1, 0xd7, 0x9e, 0x0a, 0xd7, 0x5f, 0xf5, 0xec, 0xd7, 0xe5, + 0x2e, 0xea, 0xd6, 0x0f, 0xea, 0xe7, 0xd9, 0xf3, 0x0f, 0xbe, 0x1a, 0xea, 0xdf, + 0xce, 0xe0, 0xe3, 0xe7, 0x12, 0x02, 0x16, 0xff, 0x2e, 0xe2, 0x39, 0x56, 0xb8, + 0xdb, 0x24, 0xfe, 0x0f, 0x26, 0xda, 0x33, 0xe9, 0x19, 0xee, 0x0f, 0x2a, 0xe8, + 0xdf, 0x1e, 0xff, 0xb6, 0xed, 0x24, 0xa7, 0x54, 0x05, 0xfe, 0x0f, 0xc1, 0xfe, + 0x09, 0xc7, 0x10, 0x1c, 0xe5, 0xfb, 0x24, 0xf9, 0x1d, 0x31, 0xe0, 0xca, 0x16, + 0xec, 0xe9, 0x09, 0x55, 0xc1, 0xbf, 0xfc, 0x05, 0xf4, 0xf2, 0xe1, 0xe9, 0x01, + 0xf7, 0x47, 0x3d, 0x1f, 0xcc, 0x28, 0x00, 0xc9, 0xfc, 0xec, 0x41, 0xce, 0x41, + 0xf7, 0xc9, 0xd0, 0x12, 0x0a, 0x14, 0xff, 0x34, 0xd9, 0xe7, 0xe2, 0xea, 0x1b, + 0x24, 0x0f, 0xdc, 0x2b, 0x0b, 0xbb, 0xb4, 0x02, 0x18, 0x2c, 0xef, 0xe6, 0x0b, + 0xfd, 0xe1, 0xa6, 0x21, 0x81, 0xcd, 0x1a, 0xfc, 0xe1, 0x51, 0xfb, 0xf8, 0xbd, + 0x25, 0xcc, 0xce, 0x48, 0xdd, 0x27, 0xe4, 0xfc, 0x1a, 0xc0, 0xd5, 0x1b, 0x26, + 0x40, 0x24, 0xf0, 0xcf, 0x45, 0xe7, 0x0d, 0xbf, 0xae, 0xbc, 0xa9, 0xc1, 0xba, + 0xea, 0xdc, 0xdc, 0xca, 0xd3, 0x2e, 0xae, 0x68, 0x3a, 0x07, 0xe6, 0x1a, 0x10, + 0xe8, 0xd4, 0xc0, 0xbf, 0x70, 0xee, 0x2a, 0x1a, 0xd7, 0x4c, 0xb9, 0xdb, 0xa5, + 0x16, 0xee, 0x01, 0x07, 0xe9, 0x14, 0xd0, 0xc1, 0xff, 0xd4, 0x11, 0x46, 0xf5, + 0xe7, 0x06, 0x9c, 0xb3, 0x85, 0xcd, 0x14, 0xc3, 0xf2, 0xca, 0x35, 0xaa, 0xd5, + 0x66, 0xcf, 0xe6, 0xf1, 0xc7, 0xf2, 0x13, 0x28, 0xf3, 0x04, 0x27, 0x13, 0xff, + 0xef, 0x24, 0x10, 0xaa, 0x62, 0x0a, 0x9b, 0x11, 0x23, 0x04, 0xca, 0xdc, 0xf0, + 0xf3, 0xd0, 0x0c, 0x1f, 0xd0, 0x47, 0x03, 0xd6, 0xd3, 0x9b, 0x33, 0x1f, 0x1a, + 0xcf, 0xa9, 0x06, 0xe9, 0x3e, 0xf8, 0xf4, 0xf9, 0x38, 0x20, 0xff, 0x30, 0xdd, + 0xc5, 0xcb, 0xfe, 0x22, 0xe4, 0xfa, 0x13, 0x07, 0x2b, 0xfa, 0x38, 0x38, 0x32, + 0xb8, 0x0e, 0x33, 0x12, 0x06, 0x83, 0x02, 0x15, 0x16, 0xb3, 0xbe, 0xa6, 0xd4, + 0x11, 0x11, 0x42, 0xce, 0x06, 0xad, 0x13, 0xec, 0xf3, 0xd6, 0xf3, 0xf6, 0xe0, + 0xb5, 0xc2, 0xcf, 0xeb, 0xc0, 0x2b, 0xde, 0xcd, 0xff, 0xda, 0xfd, 0xed, 0x01, + 0xc6, 0xd1, 0x02, 0x83, 0xef, 0xeb, 0xdb, 0x00, 0xe2, 0xa6, 0x1e, 0xb9, 0xd1, + 0xe6, 0xe4, 0xd2, 0xa5, 0xea, 0xf6, 0xc5, 0x07, 0x26, 0x09, 0xfb, 0xef, 0xbc, + 0xb8, 0xcf, 0x19, 0xc1, 0x37, 0xf9, 0xb6, 0xd2, 0xa6, 0x24, 0xdf, 0xcf, 0xfc, + 0xac, 0xf6, 0xd5, 0x2d, 0x09, 0x1a, 0x1b, 0x10, 0xed, 0x09, 0xf4, 0xee, 0xfc, + 0xb0, 0x1b, 0xe4, 0x28, 0xed, 0xec, 0xcb, 0xc7, 0xf0, 0xd7, 0x4b, 0xda, 0x02, + 0x1e, 0x31, 0x03, 0xb7, 0xe7, 0xe6, 0xcf, 0xf1, 0x13, 0xf9, 0x9c, 0x0d, 0x20, + 0xe1, 0x6c, 0xf6, 0xe8, 0x53, 0x6e, 0x03, 0xf9, 0x04, 0x17, 0x1d, 0x01, 0xe7, + 0xee, 0xcb, 0xc1, 0x09, 0x0c, 0x19, 0xf1, 0x21, 0xe3, 0xdd, 0x1f, 0xea, 0xef, + 0x15, 0xdb, 0x1b, 0xf4, 0x38, 0x3d, 0x04, 0x3e, 0x21, 0xf4, 0xff, 0xe3, 0xe1, + 0xed, 0x4b, 0x07, 0xfc, 0x00, 0xfe, 0x22, 0x2f, 0x07, 0x32, 0xea, 0xd9, 0xcb, + 0xf7, 0xfd, 0xf7, 0xb0, 0x09, 0xed, 0xe1, 0xfc, 0x2b, 0x35, 0xf2, 0x08, 0xfd, + 0x0c, 0x4b, 0x07, 0xd1, 0x39, 0xdf, 0xf0, 0x2b, 0xd3, 0x06, 0xd0, 0xd6, 0xde, + 0xef, 0x08, 0x0f, 0x18, 0xa1, 0xed, 0xe9, 0xff, 0xf5, 0xf4, 0xd0, 0xba, 0x57, + 0xc5, 0xe9, 0xd1, 0xe9, 0x22, 0x14, 0xfd, 0x04, 0xec, 0x0f, 0xfb, 0xe9, 0xdd, + 0xd2, 0xc4, 0xe2, 0xde, 0xfd, 0x0d, 0xf8, 0x6f, 0xf9, 0xf8, 0x02, 0xd6, 0xb6, + 0xf1, 0xeb, 0xe5, 0xf9, 0x0b, 0xe7, 0x48, 0x11, 0x02, 0x3d, 0xf4, 0x2c, 0xf4, + 0xf8, 0x49, 0xf3, 0xf1, 0x06, 0xf6, 0x3b, 0xe1, 0xd3, 0xdb, 0xc5, 0xb3, 0xee, + 0x54, 0x33, 0x04, 0xdf, 0x4f, 0x5e, 0xfe, 0x49, 0xf0, 0x17, 0xa7, 0xe8, 0x0b, + 0xe3, 0x3c, 0xed, 0x25, 0x03, 0xfc, 0x17, 0x09, 0xf0, 0xe3, 0x12, 0xf5, 0xe1, + 0xd7, 0x1a, 0x1d, 0xfe, 0x11, 0xf2, 0x11, 0x06, 0xca, 0x13, 0xdb, 0xed, 0xe7, + 0x22, 0x24, 0x1d, 0xed, 0xdb, 0x11, 0x13, 0xfe, 0x15, 0x0c, 0xf8, 0xc6, 0xf5, + 0x16, 0x99, 0xe5, 0xf3, 0x09, 0x22, 0x42, 0x3d, 0x0c, 0x7f, 0xe2, 0xfc, 0x14, + 0xda, 0xeb, 0x01, 0xf4, 0x0c, 0x0d, 0x03, 0x22, 0x04, 0x04, 0xed, 0xef, 0xda, + 0x1c, 0xd4, 0xe2, 0xd9, 0xf2, 0x24, 0xde, 0x11, 0xef, 0x11, 0xf9, 0xf4, 0xff, + 0xd3, 0xee, 0x0e, 0xe5, 0x08, 0x0e, 0xe3, 0x17, 0x05, 0xfd, 0xde, 0xf9, 0xfc, + 0x09, 0xe5, 0x21, 0xce, 0xe2, 0x26, 0xfa, 0x23, 0xec, 0x04, 0x02, 0x09, 0x41, + 0x20, 0x0e, 0x1e, 0xf2, 0xf0, 0x12, 0x08, 0x08, 0x04, 0x00, 0xf8, 0xe0, 0x0b, + 0xe3, 0xf5, 0x15, 0xfa, 0xf9, 0x1d, 0x1e, 0x02, 0xf6, 0x44, 0xe6, 0xe3, 0xce, + 0xf6, 0xd4, 0xc8, 0xf5, 0x27, 0x29, 0xfd, 0x3f, 0x08, 0x0b, 0xe4, 0x17, 0xf9, + 0x11, 0xd5, 0xee, 0x2f, 0x13, 0xce, 0xd2, 0x34, 0x00, 0xed, 0xe0, 0xf5, 0xf8, + 0x38, 0x0a, 0x15, 0xf6, 0xde, 0xfd, 0x0d, 0xe5, 0xe0, 0xe4, 0x0f, 0xe1, 0xe7, + 0xd8, 0xfd, 0xf6, 0x15, 0x0f, 0xf9, 0x00, 0x49, 0x06, 0xd2, 0x04, 0xc8, 0xed, + 0xfc, 0x18, 0xf1, 0xef, 0xf6, 0x2a, 0xe7, 0x04, 0xeb, 0xe5, 0x51, 0x20, 0x1c, + 0x08, 0xed, 0xfb, 0xfd, 0x33, 0xf8, 0xfb, 0xf9, 0x15, 0xfa, 0xf6, 0xf6, 0x04, + 0xdf, 0x1d, 0xfd, 0xf0, 0x19, 0xf0, 0xfa, 0x0f, 0x0e, 0x1b, 0x22, 0x12, 0xeb, + 0x02, 0xf5, 0xde, 0x12, 0x07, 0x07, 0x24, 0x38, 0xf6, 0xef, 0xe5, 0x21, 0xe8, + 0xe6, 0xce, 0xe1, 0xf8, 0x00, 0x24, 0xe5, 0xe5, 0xdf, 0x0d, 0xf6, 0xfc, 0x19, + 0xfb, 0x15, 0xe8, 0xf9, 0xfa, 0x32, 0x04, 0x0e, 0x02, 0x06, 0x07, 0xf6, 0xfc, + 0xef, 0x01, 0x1f, 0x7f, 0x1f, 0xe8, 0xfd, 0x0e, 0xe6, 0x0c, 0xf9, 0xe0, 0xe4, + 0xef, 0xe7, 0xeb, 0xed, 0xf4, 0x08, 0xe8, 0xda, 0xd1, 0x16, 0x11, 0x04, 0x00, + 0x16, 0xf6, 0x19, 0xf9, 0xf0, 0xc6, 0xf0, 0xff, 0xff, 0xf1, 0x17, 0xf1, 0xf6, + 0xde, 0xf5, 0x10, 0xbc, 0xe7, 0xdc, 0x21, 0x09, 0xec, 0xc0, 0xea, 0x93, 0xaf, + 0xc2, 0x0a, 0x9c, 0xdf, 0xe9, 0x15, 0x93, 0xbc, 0x1f, 0x94, 0xaf, 0x0c, 0xe2, + 0x4d, 0xe1, 0x1a, 0x0d, 0xd9, 0xd2, 0xf8, 0xd1, 0xe5, 0xf1, 0x1c, 0xc5, 0xc3, + 0x96, 0xc2, 0x05, 0xbe, 0x1f, 0xee, 0xee, 0x02, 0xac, 0xd3, 0x3c, 0x10, 0xe0, + 0x51, 0x08, 0xdd, 0x19, 0x3e, 0xde, 0xd5, 0xb6, 0xf2, 0xf3, 0xf1, 0xf1, 0x92, + 0x1c, 0x12, 0x59, 0x63, 0x3e, 0x34, 0xc6, 0xc6, 0xaf, 0x24, 0xf8, 0x23, 0x45, + 0x22, 0x30, 0xde, 0x2b, 0xeb, 0xea, 0xe5, 0x13, 0x0d, 0xbd, 0xac, 0xb4, 0xc3, + 0x4a, 0x58, 0xd7, 0x6c, 0xd3, 0xcd, 0x0a, 0xb8, 0xe7, 0x33, 0xd8, 0xce, 0xfa, + 0xc1, 0x05, 0xe8, 0x3d, 0xf4, 0xa1, 0x14, 0xe0, 0xf3, 0xb4, 0xf8, 0x12, 0xf3, + 0xa3, 0x26, 0x50, 0xd4, 0xf5, 0xb4, 0xed, 0x09, 0xda, 0xfc, 0xbc, 0xd0, 0xa8, + 0x0a, 0x11, 0xe6, 0xed, 0xfb, 0xf7, 0x30, 0xab, 0x00, 0x81, 0x33, 0x16, 0x47, + 0xee, 0x01, 0x0d, 0x14, 0x14, 0x17, 0xe7, 0xc0, 0xd0, 0xc8, 0x1c, 0x2c, 0x15, + 0xab, 0x4b, 0xb3, 0xdf, 0xd5, 0x6d, 0xe1, 0xb7, 0xa5, 0x56, 0xfa, 0x2a, 0xb3, + 0x06, 0xae, 0x33, 0xf5, 0xde, 0xe1, 0x03, 0x25, 0x13, 0xb8, 0xda, 0xcf, 0xfe, + 0x4c, 0x85, 0x97, 0x1d, 0xd1, 0xd6, 0xba, 0xd2, 0x11, 0xe2, 0x20, 0xe2, 0xb1, + 0xf9, 0x15, 0x08, 0xfa, 0x27, 0xfc, 0x9e, 0xc0, 0xb6, 0x3a, 0xdf, 0x60, 0xcd, + 0x16, 0xec, 0x3c, 0xb4, 0xda, 0xd3, 0x64, 0xca, 0xf7, 0x3d, 0x10, 0x9a, 0x46, + 0xdd, 0x52, 0x38, 0xda, 0xe0, 0xd6, 0xc7, 0xeb, 0xf6, 0x11, 0x1a, 0x57, 0x37, + 0x1e, 0x4e, 0xf9, 0xdd, 0xea, 0xc1, 0x25, 0xd9, 0xf1, 0x04, 0x12, 0x30, 0xed, + 0x08, 0x01, 0x0f, 0xa7, 0x00, 0xe3, 0x93, 0x5a, 0x10, 0xca, 0xd3, 0xca, 0x0f, + 0x1f, 0xc8, 0xe9, 0x1b, 0x95, 0xd3, 0xe3, 0x04, 0xed, 0x06, 0xf7, 0x03, 0x22, + 0x06, 0x0e, 0xda, 0xee, 0xed, 0x49, 0xca, 0xe0, 0xa3, 0xf4, 0xfb, 0xe2, 0x35, + 0xa2, 0x11, 0xca, 0x14, 0xf2, 0xec, 0x23, 0x31, 0xba, 0x01, 0x10, 0x0e, 0x66, + 0x15, 0x0f, 0x18, 0x20, 0xe0, 0x20, 0x07, 0x0e, 0xb4, 0xf3, 0x1f, 0xd4, 0x12, + 0xb1, 0x2f, 0xaa, 0xed, 0xf9, 0x2c, 0xdb, 0x1f, 0x26, 0xe4, 0x48, 0xf2, 0x0c, + 0x3b, 0xd1, 0x20, 0xb8, 0x15, 0xc5, 0xda, 0x11, 0xf4, 0xfd, 0x04, 0xef, 0x2f, + 0x26, 0x25, 0xd7, 0xfe, 0xd6, 0x02, 0xd4, 0xdd, 0xd5, 0x37, 0x08, 0x07, 0xb6, + 0x01, 0x16, 0xe7, 0x16, 0x10, 0x1c, 0xf2, 0xbb, 0xfc, 0x77, 0x01, 0xc2, 0x31, + 0xe8, 0xdb, 0xfb, 0xd8, 0xe0, 0x50, 0x1e, 0x47, 0xe4, 0x02, 0x1c, 0x15, 0x10, + 0xba, 0xf0, 0xcc, 0x22, 0xc3, 0xb8, 0xd0, 0xd3, 0x0e, 0x00, 0xb7, 0x13, 0x7b, + 0xf8, 0xf7, 0xfe, 0xf4, 0x0d, 0xd1, 0x25, 0xec, 0xd2, 0xbc, 0x2c, 0xe5, 0x43, + 0x22, 0x09, 0x0e, 0xce, 0xe1, 0xfe, 0x08, 0xf3, 0x0c, 0x09, 0x22, 0x03, 0xce, + 0x0e, 0xd9, 0x2e, 0x2c, 0xfb, 0xf4, 0x16, 0xe9, 0xfa, 0xd5, 0xeb, 0xe6, 0x22, + 0x38, 0x02, 0x59, 0x23, 0xd9, 0x17, 0xf9, 0xe1, 0x2d, 0x2b, 0xef, 0x37, 0x01, + 0xe8, 0x07, 0xf3, 0x17, 0x21, 0x07, 0x93, 0xe7, 0xe4, 0xff, 0x0c, 0xeb, 0xf6, + 0x96, 0x11, 0x0c, 0x49, 0xf7, 0xed, 0xfd, 0xeb, 0xd9, 0xbc, 0x24, 0xeb, 0xe3, + 0xb1, 0xf7, 0x67, 0xd0, 0xfa, 0x25, 0xc1, 0x28, 0x5b, 0x7f, 0xd1, 0xfa, 0xd8, + 0xc7, 0xe9, 0x42, 0xb6, 0xde, 0x23, 0xe6, 0xe5, 0x24, 0xe2, 0x11, 0xe7, 0xda, + 0x09, 0x3b, 0xed, 0x00, 0x38, 0xe6, 0xc3, 0xdc, 0xe3, 0xd9, 0xb5, 0xfd, 0x06, + 0x03, 0xde, 0x04, 0x0e, 0xf2, 0x1d, 0xe6, 0xfc, 0x98, 0xfc, 0xd8, 0x36, 0x16, + 0x00, 0x13, 0xd8, 0xf0, 0x10, 0x23, 0x3a, 0xf4, 0xe9, 0x02, 0xdc, 0xf8, 0x13, + 0xba, 0x1c, 0xd7, 0x19, 0x2e, 0x13, 0x09, 0x11, 0xeb, 0xce, 0xd0, 0xf5, 0x9e, + 0xf3, 0xfc, 0x3d, 0x2b, 0xf5, 0xdf, 0xf8, 0xcf, 0xd4, 0xf9, 0xea, 0xc8, 0x39, + 0x0d, 0xf8, 0x00, 0x4a, 0x13, 0xbe, 0x29, 0x1b, 0xb0, 0x14, 0x0e, 0xfd, 0xfc, + 0xd9, 0x03, 0xa4, 0xed, 0xf3, 0x03, 0x01, 0xda, 0x13, 0xf2, 0xd4, 0xf8, 0x1b, + 0x32, 0x18, 0xe1, 0x3d, 0xc7, 0xdd, 0xd3, 0x2f, 0x07, 0xa9, 0xe8, 0x19, 0xd4, + 0xf5, 0xfd, 0xf2, 0xe1, 0xbc, 0x0b, 0xa7, 0x06, 0xd7, 0x0a, 0xe9, 0x20, 0xfc, + 0x0f, 0x04, 0xfb, 0xbd, 0xdb, 0xf5, 0x05, 0x03, 0x51, 0x62, 0xee, 0xe4, 0x23, + 0xfb, 0xf6, 0x03, 0xfb, 0x4a, 0x2a, 0xde, 0xe2, 0xb3, 0xfc, 0xcf, 0xfa, 0xfc, + 0xc3, 0xea, 0xf9, 0xf5, 0xfc, 0xf1, 0xf1, 0x21, 0x38, 0x08, 0xbd, 0xf6, 0x55, + 0x09, 0xd2, 0xf7, 0xde, 0xe7, 0x1e, 0xf7, 0x56, 0x15, 0xda, 0x81, 0x30, 0xef, + 0x9f, 0xe8, 0xdf, 0xbc, 0x03, 0x08, 0x08, 0xfb, 0x10, 0xdd, 0xf9, 0x27, 0xd5, + 0xc0, 0xbc, 0xda, 0x04, 0xff, 0x2a, 0x2b, 0xe4, 0x20, 0xd4, 0x4e, 0xf3, 0xf2, + 0x53, 0xf7, 0xde, 0xea, 0x01, 0xe9, 0xe9, 0x08, 0xee, 0xd0, 0x11, 0x17, 0x23, + 0xcf, 0xf8, 0xd2, 0x00, 0xdb, 0xe1, 0xf7, 0x06, 0x0c, 0xf1, 0xdf, 0xe7, 0xfc, + 0xb6, 0xe3, 0xef, 0xe0, 0x41, 0xd9, 0x13, 0xcc, 0xda, 0xe9, 0xf8, 0x1f, 0xdc, + 0x03, 0xf3, 0xb3, 0xe9, 0xb8, 0xca, 0xe0, 0x1c, 0xaf, 0x1b, 0x21, 0x23, 0x1b, + 0xf0, 0xfa, 0x06, 0xec, 0x0f, 0x12, 0x18, 0xd4, 0xfe, 0xf8, 0x29, 0xdc, 0xed, + 0xf8, 0xf7, 0xdc, 0x32, 0x07, 0x22, 0xe8, 0xf3, 0xc4, 0xef, 0xe9, 0x34, 0xfe, + 0xe8, 0x4d, 0x0b, 0xf7, 0x14, 0xda, 0xef, 0xb3, 0x11, 0x24, 0xf0, 0xa9, 0xba, + 0xf9, 0xf6, 0x0a, 0xd5, 0x13, 0xf4, 0x2a, 0x2c, 0x1c, 0x05, 0xe7, 0x30, 0xd6, + 0x3f, 0xe2, 0xe6, 0x78, 0x4d, 0xd0, 0xd9, 0x2b, 0x1a, 0xd7, 0x14, 0x17, 0xe9, + 0x81, 0x13, 0x2e, 0xf9, 0xcb, 0xd2, 0xe6, 0x0b, 0xb2, 0x0a, 0xc8, 0xb1, 0xf2, + 0xb2, 0xd8, 0xe6, 0xf8, 0x0f, 0xad, 0xcb, 0xc6, 0xc6, 0xad, 0x56, 0x3b, 0x27, + 0xdc, 0xd6, 0x39, 0xf5, 0xf8, 0x34, 0x1d, 0xdd, 0x3b, 0xd4, 0xeb, 0x15, 0xbe, + 0xf4, 0x1b, 0x08, 0xf0, 0xe6, 0xc7, 0x29, 0x1e, 0x18, 0xc0, 0x10, 0xac, 0xf2, + 0xae, 0x24, 0xeb, 0xfc, 0xfd, 0x06, 0xfa, 0xe1, 0x08, 0xae, 0x26, 0xd4, 0xf9, + 0x41, 0xd4, 0xcd, 0xff, 0x64, 0xff, 0xce, 0xdd, 0xe4, 0xeb, 0xde, 0xf5, 0x4c, + 0x28, 0x02, 0xe2, 0x7a, 0x0d, 0xa5, 0x35, 0x46, 0xa5, 0xfa, 0x07, 0x11, 0x07, + 0x54, 0x0c, 0x05, 0x00, 0x11, 0x01, 0xfa, 0x0b, 0x09, 0xa1, 0x16, 0xfc, 0xa9, + 0xf4, 0x01, 0x35, 0xee, 0x05, 0x3d, 0xec, 0x0e, 0x0c, 0xf6, 0x1b, 0x3a, 0x1c, + 0x17, 0x58, 0xf2, 0x1a, 0x16, 0xea, 0x08, 0x20, 0xfa, 0x3c, 0xef, 0x0d, 0x0b, + 0xf9, 0x0a, 0xef, 0x87, 0xff, 0xeb, 0x07, 0xfd, 0x24, 0x0b, 0xc2, 0xfd, 0x1d, + 0xc0, 0x0f, 0xe7, 0x5d, 0x08, 0x00, 0xc9, 0x1a, 0xea, 0xe8, 0xda, 0xca, 0xe5, + 0x24, 0x3b, 0x18, 0xf8, 0xa4, 0xd0, 0x15, 0x0c, 0xeb, 0x11, 0xfc, 0xfc, 0x11, + 0xf2, 0x28, 0x0c, 0xd6, 0x40, 0x2b, 0xf8, 0x0d, 0x66, 0x1c, 0x0a, 0xf1, 0xf7, + 0x29, 0xf6, 0x05, 0x32, 0xd2, 0xec, 0x07, 0xff, 0xa3, 0x1b, 0x36, 0x5b, 0xd3, + 0x36, 0xd1, 0x07, 0xdd, 0xde, 0x29, 0x1e, 0x22, 0x18, 0xb5, 0xd7, 0xd9, 0x08, + 0xe8, 0x15, 0x90, 0xc3, 0x18, 0x11, 0xcc, 0x1f, 0x29, 0xd5, 0xf7, 0xbd, 0x22, + 0xcc, 0xbd, 0xc2, 0x0e, 0x09, 0x47, 0xcd, 0xa6, 0xc6, 0xbf, 0xd2, 0x1d, 0xee, + 0x36, 0xf7, 0xd4, 0xc2, 0x0d, 0x1b, 0x1f, 0x05, 0xfe, 0x0e, 0xb9, 0xe3, 0x1b, + 0x34, 0x44, 0xe1, 0xeb, 0xbc, 0x3c, 0xec, 0x25, 0x1b, 0xb4, 0x26, 0xc3, 0xdf, + 0x27, 0x1d, 0xed, 0xfc, 0xf9, 0x31, 0x2c, 0xee, 0x09, 0xea, 0xef, 0x02, 0xeb, + 0x0e, 0xe2, 0xc0, 0x09, 0xf0, 0x0f, 0xff, 0xf1, 0x50, 0x11, 0xf7, 0x54, 0xe9, + 0xc5, 0x34, 0xbf, 0x21, 0x01, 0xc5, 0x99, 0x14, 0xe1, 0x0a, 0xeb, 0x03, 0xbb, + 0xe7, 0xd1, 0xf7, 0xe7, 0x03, 0xd9, 0xff, 0x9e, 0x33, 0x17, 0x05, 0x1a, 0x30, + 0xfd, 0x3f, 0x0d, 0xdf, 0xe6, 0x18, 0x15, 0x21, 0xcb, 0x0f, 0x06, 0xcf, 0x9f, + 0x5b, 0x0f, 0x13, 0xf9, 0xcf, 0x67, 0x45, 0x0d, 0xf8, 0xc0, 0xd6, 0x02, 0x19, + 0x03, 0xa6, 0xbc, 0xfe, 0xe7, 0xea, 0x03, 0xb7, 0xba, 0x63, 0x16, 0xcb, 0x06, + 0x50, 0x1a, 0x09, 0x1a, 0x0d, 0x0d, 0xf0, 0xc5, 0xce, 0xfd, 0x9f, 0xbb, 0x12, + 0xfb, 0x08, 0xfe, 0x11, 0x08, 0xe5, 0x7f, 0x5c, 0x1e, 0x29, 0x20, 0x05, 0x21, + 0xfb, 0xcd, 0xe8, 0x2e, 0x24, 0xe7, 0x1b, 0x32, 0xd1, 0x05, 0xeb, 0xce, 0xdc, + 0x0e, 0xfb, 0xec, 0xf0, 0x15, 0xc2, 0xe6, 0xdc, 0xe0, 0x33, 0x2a, 0xd1, 0x37, + 0x0b, 0x4a, 0x01, 0xb8, 0xb0, 0xe6, 0xd6, 0xf5, 0x05, 0x0c, 0x11, 0xcd, 0xcc, + 0xd1, 0xb0, 0xfa, 0x14, 0x2e, 0x2e, 0x02, 0xe4, 0x01, 0xd0, 0xf7, 0xca, 0x60, + 0xa9, 0xe4, 0x1f, 0xe3, 0x4f, 0x2c, 0xfe, 0xfc, 0xbb, 0xe6, 0xcb, 0x00, 0xf4, + 0xe6, 0xdd, 0x21, 0xf0, 0xcb, 0xa5, 0x10, 0x3f, 0xe3, 0xf8, 0xaa, 0x26, 0x06, + 0xd1, 0xee, 0xda, 0xfd, 0x3b, 0xf4, 0xb9, 0xe0, 0xf4, 0xbd, 0xf0, 0xe5, 0xdd, + 0xb2, 0xf9, 0xfb, 0xce, 0xfa, 0x2a, 0xe3, 0x13, 0xd3, 0x07, 0xe1, 0xcb, 0xf8, + 0xd9, 0xed, 0xff, 0xb0, 0xc4, 0xc6, 0x1e, 0xdf, 0xe5, 0x14, 0xbf, 0xe0, 0xe4, + 0xf6, 0x04, 0xbd, 0xd4, 0x1f, 0xc9, 0xd0, 0xdd, 0xf3, 0xe9, 0x32, 0x23, 0x20, + 0xd3, 0x15, 0x25, 0x11, 0xa9, 0x2a, 0xcb, 0x29, 0xde, 0xfe, 0x03, 0xe2, 0x1c, + 0x24, 0xbe, 0xfb, 0x2f, 0x26, 0x06, 0xb9, 0x28, 0x3a, 0xd8, 0x3b, 0x1c, 0xe7, + 0x05, 0x06, 0xf9, 0xd7, 0x0c, 0xf9, 0xe5, 0x17, 0xf7, 0x36, 0x48, 0xfc, 0x12, + 0xe9, 0x9e, 0x09, 0xb8, 0x01, 0xf5, 0x1f, 0xd4, 0x3b, 0x12, 0x00, 0xd1, 0x09, + 0xeb, 0x32, 0xfb, 0xb0, 0x3c, 0x81, 0x17, 0x4c, 0x15, 0xfd, 0x0c, 0x2e, 0xcd, + 0x1f, 0x0f, 0x48, 0x20, 0x48, 0xda, 0xd0, 0xeb, 0xe6, 0x1a, 0xf6, 0xb2, 0xfd, + 0xc3, 0xd4, 0x01, 0x2c, 0xe2, 0xeb, 0xbc, 0x3c, 0xc7, 0xee, 0x0d, 0x21, 0xbb, + 0x0d, 0xf6, 0xda, 0x0a, 0xc5, 0x0d, 0x21, 0x10, 0xeb, 0xdc, 0x06, 0xf0, 0xd8, + 0xc5, 0x1a, 0x1a, 0xc5, 0x1f, 0xf4, 0xe3, 0x24, 0x9c, 0xb1, 0xcb, 0xc3, 0xe4, + 0xcd, 0xe4, 0xe7, 0x2c, 0x23, 0x30, 0xcb, 0xba, 0xc1, 0xf6, 0xab, 0x0b, 0xdc, + 0xaf, 0xd1, 0x13, 0x1f, 0x2c, 0x22, 0x22, 0xb9, 0xfd, 0x0b, 0x10, 0x22, 0x42, + 0xf9, 0x22, 0x02, 0xcf, 0xea, 0xe1, 0x35, 0x6a, 0x05, 0xd9, 0xb7, 0xfa, 0xb2, + 0xff, 0xf0, 0xd2, 0xcf, 0x12, 0xe9, 0xf8, 0x59, 0xd7, 0xcc, 0xbf, 0xc2, 0x82, + 0xc8, 0xd7, 0xe7, 0xa6, 0x3a, 0x22, 0xc4, 0x0e, 0x23, 0xf1, 0xd6, 0x29, 0xf4, + 0xda, 0xd6, 0xfe, 0x08, 0x00, 0x17, 0x06, 0x2a, 0x17, 0xca, 0xe2, 0x37, 0xde, + 0x10, 0x19, 0xe4, 0x38, 0x06, 0x07, 0xce, 0xfc, 0x1b, 0x43, 0xe0, 0xcf, 0xb9, + 0xa3, 0x20, 0x4d, 0xd8, 0x4a, 0xcc, 0x19, 0xe2, 0xb7, 0x18, 0xce, 0xd5, 0xeb, + 0xda, 0x11, 0x9c, 0xdc, 0xe9, 0x29, 0xca, 0xa6, 0xf5, 0x14, 0xe1, 0x1d, 0x1c, + 0xcb, 0xe3, 0x59, 0xf8, 0xcc, 0x4f, 0xd1, 0x4b, 0x16, 0xad, 0x14, 0xaf, 0x95, + 0xcf, 0x39, 0xfc, 0x1e, 0xb2, 0x1f, 0xeb, 0xfb, 0x3d, 0xff, 0xf8, 0xfd, 0xec, + 0x8b, 0x40, 0x2b, 0x10, 0xbf, 0xf6, 0xf5, 0xcc, 0x2f, 0xca, 0x2a, 0xf8, 0x9b, + 0x1a, 0xf5, 0xce, 0x1e, 0xf6, 0x25, 0xc5, 0x25, 0xe7, 0x84, 0xda, 0xc3, 0x1b, + 0xb5, 0xd6, 0x29, 0x36, 0x23, 0xaf, 0x00, 0x30, 0xe6, 0xa3, 0xd4, 0xbb, 0xc6, + 0xb5, 0xd3, 0x14, 0x14, 0x18, 0x1f, 0x30, 0x16, 0x37, 0xcf, 0xd9, 0xe6, 0xf8, + 0xda, 0xa2, 0x39, 0x14, 0x09, 0x33, 0x08, 0xeb, 0xac, 0xcd, 0x04, 0xcd, 0x49, + 0x89, 0xf9, 0xc1, 0xc2, 0xc6, 0x37, 0xdf, 0xdd, 0x01, 0xbf, 0x27, 0xec, 0x1f, + 0xe4, 0x05, 0xed, 0xe7, 0xec, 0x0d, 0x03, 0x4e, 0x2d, 0xc3, 0xe6, 0xf4, 0x07, + 0xeb, 0x23, 0xc8, 0xa5, 0xfc, 0xc4, 0x09, 0xda, 0xf0, 0x3e, 0xbb, 0xf9, 0x06, + 0x05, 0xd6, 0x1c, 0xd0, 0x20, 0xf3, 0x34, 0x00, 0xab, 0xff, 0xfe, 0xdb, 0xdb, + 0xd1, 0xd5, 0xe7, 0xed, 0xf5, 0xec, 0xf2, 0x2b, 0x32, 0xa4, 0xf3, 0x4c, 0x21, + 0xca, 0x2c, 0xb5, 0xe7, 0xd4, 0xc3, 0xfa, 0x56, 0x52, 0x0c, 0x0b, 0xd0, 0xd1, + 0xf5, 0x14, 0xf7, 0xc3, 0xdd, 0x20, 0x05, 0xac, 0x13, 0x56, 0x08, 0xc2, 0xd1, + 0xe1, 0x11, 0x00, 0xfa, 0xe8, 0x84, 0xff, 0x06, 0xf8, 0x09, 0xf8, 0xf3, 0xc1, + 0xde, 0xef, 0xec, 0x26, 0xf2, 0xfe, 0x24, 0xf2, 0x0c, 0xd5, 0xd7, 0x05, 0x01, + 0xce, 0x2d, 0x0c, 0x03, 0x23, 0xf7, 0xeb, 0x01, 0x08, 0x32, 0x81, 0xcb, 0xc2, + 0xd0, 0x2b, 0xda, 0xf1, 0x63, 0x03, 0xde, 0xf4, 0x20, 0xcc, 0xe2, 0x28, 0xdf, + 0x6d, 0xf9, 0xb6, 0x19, 0x9d, 0xfc, 0xf6, 0xe4, 0xc5, 0xdb, 0x06, 0xa6, 0x08, + 0xf0, 0x48, 0xf4, 0xfd, 0x20, 0xf7, 0x08, 0xb2, 0xc2, 0x00, 0xe8, 0xec, 0xbe, + 0xad, 0xf2, 0x4e, 0xf4, 0xf8, 0xe0, 0x17, 0xd8, 0xa7, 0x0f, 0x01, 0x00, 0xe8, + 0xe7, 0x0e, 0xe9, 0xff, 0x2e, 0x17, 0xa4, 0x15, 0xdd, 0xfe, 0x25, 0xf1, 0x1b, + 0xe0, 0xf9, 0xb7, 0xdd, 0x11, 0xd5, 0xb8, 0xe5, 0xfb, 0x0a, 0xb1, 0xe2, 0x48, + 0x3d, 0xa4, 0x1e, 0xc9, 0x48, 0xbb, 0xe0, 0xd7, 0x28, 0xe5, 0x00, 0xca, 0x24, + 0x2c, 0xe1, 0xb2, 0x49, 0x17, 0xe3, 0xc7, 0x05, 0xf1, 0xcd, 0x5e, 0xf5, 0xf1, + 0xc2, 0xf2, 0x2a, 0xd6, 0x03, 0xd9, 0x2b, 0xf8, 0xe0, 0xbb, 0x04, 0xc5, 0xd8, + 0x1f, 0x0a, 0xf8, 0x34, 0x46, 0x19, 0x14, 0xc4, 0xde, 0xfb, 0xeb, 0xe7, 0x4b, + 0xe7, 0xd9, 0x07, 0xc3, 0x1f, 0xe7, 0xe2, 0xe8, 0x7b, 0x07, 0x0d, 0xf2, 0x20, + 0xfc, 0x24, 0xe8, 0xde, 0xfe, 0xe5, 0xf1, 0xe9, 0xdb, 0xcd, 0xbc, 0x00, 0x03, + 0xfd, 0xf5, 0xb2, 0xe6, 0xe6, 0xf5, 0x02, 0x93, 0xc8, 0x2f, 0x0d, 0xfb, 0x25, + 0xe7, 0xc2, 0x24, 0x40, 0xce, 0x95, 0xd3, 0xeb, 0xc8, 0x03, 0x0f, 0x5d, 0xdf, + 0xd8, 0xf3, 0xa6, 0x59, 0x08, 0xde, 0xd2, 0xfc, 0xc9, 0xe5, 0x07, 0x09, 0xe1, + 0xff, 0xf0, 0x0f, 0xf0, 0xc6, 0xe1, 0xb9, 0xe3, 0x1a, 0x01, 0xde, 0x3d, 0x96, + 0xc3, 0x57, 0xb8, 0xc1, 0xa8, 0x14, 0x51, 0x16, 0x0e, 0xfc, 0x17, 0xd8, 0xd0, + 0x27, 0x02, 0x17, 0x36, 0xd0, 0x95, 0xc8, 0xc4, 0xe7, 0x06, 0x2a, 0x14, 0xfc, + 0x36, 0xfa, 0x3c, 0x21, 0x59, 0xd7, 0x10, 0x0b, 0x1e, 0xde, 0x22, 0x19, 0xc9, + 0xd5, 0xf2, 0xe5, 0xd6, 0xeb, 0x06, 0xdd, 0xf1, 0xfc, 0x06, 0xdb, 0x81, 0xeb, + 0xd5, 0xdc, 0x12, 0xd4, 0xee, 0xfd, 0x96, 0xc9, 0x4e, 0xef, 0xf2, 0x9e, 0x20, + 0xe6, 0xbd, 0x04, 0xdc, 0xe3, 0x0b, 0x3c, 0xa8, 0x37, 0xd7, 0xe9, 0xc8, 0x48, + 0xb9, 0xf7, 0xd5, 0x32, 0x02, 0x15, 0xad, 0x30, 0xc2, 0xbf, 0x51, 0xe8, 0x40, + 0x1c, 0xf2, 0x47, 0xe9, 0xbd, 0xb0, 0xc9, 0xfc, 0x36, 0x00, 0x06, 0x1d, 0xe7, + 0xcb, 0xdb, 0x1c, 0x2a, 0xfd, 0xb3, 0x1e, 0x0c, 0x92, 0xef, 0xe8, 0x1a, 0x22, + 0x05, 0xdb, 0x0c, 0x06, 0xf3, 0x22, 0xe8, 0x3c, 0xfc, 0x4d, 0x02, 0x2b, 0x17, + 0x09, 0xde, 0xe8, 0x41, 0x01, 0x2a, 0xb9, 0x0e, 0xc4, 0xc5, 0xdf, 0x0c, 0xcc, + 0xaf, 0xd9, 0xb6, 0xf3, 0x4f, 0xe0, 0xf0, 0xd0, 0xef, 0xc5, 0x15, 0xb3, 0x2e, + 0xd9, 0xd7, 0x54, 0x08, 0x49, 0xff, 0x2a, 0x0d, 0xe7, 0xd2, 0xfd, 0xe0, 0x0b, + 0xbd, 0xea, 0xbc, 0x13, 0xde, 0xad, 0x14, 0x2a, 0xa6, 0x81, 0x32, 0x29, 0x25, + 0xed, 0x49, 0xa3, 0x04, 0x0e, 0x06, 0x1d, 0x08, 0x22, 0x24, 0x01, 0xd0, 0xb5, + 0xe7, 0xe3, 0x2e, 0xf4, 0x1f, 0x25, 0x03, 0xc7, 0xe3, 0x2e, 0x00, 0x36, 0xf8, + 0xf5, 0x28, 0xdb, 0x40, 0xda, 0x0b, 0x2e, 0xe8, 0xfb, 0xf9, 0xca, 0x45, 0xcf, + 0xc9, 0x0e, 0xea, 0xf1, 0x25, 0xd7, 0x1d, 0xe2, 0x0a, 0xf3, 0xfe, 0x3c, 0xe7, + 0x00, 0xf4, 0x17, 0x35, 0xe4, 0x2d, 0xf8, 0x45, 0x10, 0xe2, 0xfd, 0xe6, 0x0a, + 0xaf, 0x05, 0x35, 0xc6, 0xdc, 0xf7, 0xb4, 0x97, 0x0b, 0x26, 0x01, 0xfb, 0xb5, + 0xfc, 0xbf, 0xc2, 0x29, 0xe0, 0x16, 0x54, 0xbf, 0x1a, 0xeb, 0x26, 0xd2, 0xf6, + 0xb2, 0xed, 0x31, 0x4b, 0x35, 0xd1, 0x0e, 0xc5, 0xeb, 0xf8, 0x09, 0x04, 0x62, + 0x1c, 0x07, 0xec, 0xf5, 0xd3, 0xbc, 0xdd, 0x17, 0xed, 0x92, 0xe9, 0xe5, 0x23, + 0xf0, 0xe9, 0xa0, 0xe0, 0x53, 0x33, 0xc8, 0xe6, 0x9e, 0x01, 0xf7, 0xfb, 0xd4, + 0x10, 0x35, 0xc3, 0xf9, 0xf1, 0xf4, 0xf1, 0xeb, 0x2f, 0xbe, 0x1d, 0x14, 0xd5, + 0xd6, 0x13, 0x1d, 0xe6, 0x2e, 0xe1, 0x3c, 0xe4, 0x12, 0xe0, 0xc7, 0x27, 0xec, + 0xfb, 0xda, 0xdc, 0xe7, 0xf8, 0x11, 0x1b, 0xe7, 0xea, 0xef, 0x0c, 0xee, 0xf4, + 0x05, 0x20, 0x81, 0xb3, 0x36, 0x12, 0xf5, 0xe3, 0x00, 0x1d, 0xb5, 0x15, 0xd0, + 0x04, 0x1b, 0xf8, 0xe6, 0xf7, 0x32, 0x0f, 0x27, 0xf9, 0xfe, 0x1b, 0xe8, 0x21, + 0xda, 0x29, 0xf3, 0x0d, 0x45, 0xc8, 0xee, 0xf9, 0x02, 0xfc, 0x04, 0x1c, 0xe2, + 0xf8, 0xfe, 0xf3, 0xfe, 0xfb, 0xc0, 0xd8, 0xd6, 0xd1, 0x12, 0x13, 0xfb, 0x19, + 0x26, 0x1b, 0x00, 0x31, 0xb1, 0xd4, 0x17, 0x36, 0x1f, 0x0c, 0x18, 0xe0, 0xf6, + 0xdb, 0xd0, 0x04, 0x14, 0x0c, 0x1c, 0x0e, 0x0c, 0x17, 0xe9, 0x02, 0xe7, 0x47, + 0x26, 0xc7, 0xd4, 0x1a, 0x0e, 0xff, 0x52, 0xf6, 0xb2, 0xcb, 0x22, 0xf7, 0x22, + 0xea, 0xd7, 0xec, 0xdf, 0xca, 0xe0, 0xbb, 0xc1, 0xf1, 0xd8, 0x0d, 0x39, 0x01, + 0x13, 0xeb, 0xd8, 0xd0, 0xf1, 0xf0, 0x3f, 0x17, 0xee, 0x07, 0xf5, 0xb8, 0x27, + 0xe9, 0xef, 0x06, 0xce, 0x2b, 0xf3, 0xe4, 0x3b, 0x04, 0x3a, 0xc7, 0x08, 0xc4, + 0x14, 0xc0, 0x47, 0x0d, 0x00, 0x24, 0x43, 0xd0, 0xaa, 0xa4, 0xb0, 0xe9, 0x1f, + 0x2d, 0x1a, 0xda, 0xf1, 0xd9, 0x13, 0xd1, 0xa9, 0x4c, 0x0d, 0xcf, 0x0c, 0x3b, + 0xfa, 0xef, 0x0f, 0x32, 0x31, 0xfa, 0x27, 0xe7, 0xed, 0x56, 0xd7, 0x05, 0x23, + 0xe1, 0x2a, 0x2b, 0xeb, 0xf3, 0x02, 0x0d, 0x1d, 0xc9, 0xde, 0x06, 0x26, 0xfa, + 0x13, 0xf6, 0xed, 0xec, 0x1e, 0xea, 0x4a, 0x2f, 0xf0, 0xda, 0x45, 0xf6, 0x1c, + 0xc4, 0x25, 0x18, 0xed, 0xfc, 0x44, 0xbd, 0x1d, 0xe0, 0xff, 0x00, 0xde, 0x33, + 0x31, 0xe6, 0x11, 0xe0, 0xcd, 0x37, 0xde, 0xe0, 0xf9, 0xfe, 0x01, 0xfe, 0xed, + 0x12, 0xf1, 0xf3, 0xe0, 0xa8, 0xeb, 0xc8, 0xe2, 0xf5, 0x0a, 0x22, 0x1f, 0x12, + 0xdd, 0x1b, 0xd8, 0xcd, 0xa4, 0xde, 0xe2, 0x18, 0xf3, 0x5a, 0xb7, 0xde, 0xb1, + 0x00, 0xd4, 0xf4, 0x1f, 0xe5, 0xc7, 0x2a, 0xf8, 0x22, 0x36, 0xb9, 0x0c, 0xf4, + 0x1f, 0xfa, 0xf5, 0xbc, 0xb4, 0x1b, 0xe6, 0x41, 0xdc, 0x32, 0x04, 0x11, 0xf5, + 0xe7, 0xcc, 0x1d, 0x72, 0x50, 0xd3, 0x16, 0x24, 0x8f, 0x29, 0xf3, 0xf9, 0xcc, + 0xdc, 0xdd, 0x4e, 0xff, 0xe1, 0xc9, 0xe0, 0x41, 0x22, 0x4d, 0xee, 0xc9, 0xc0, + 0x14, 0x23, 0xf9, 0xe6, 0xf9, 0x08, 0x10, 0xdb, 0x0a, 0x37, 0x02, 0x3a, 0xd0, + 0x04, 0xff, 0xa4, 0xcf, 0xda, 0x18, 0x1d, 0xe5, 0xe9, 0xfb, 0x22, 0xf8, 0x44, + 0x83, 0xd7, 0xfd, 0xf0, 0xf9, 0xc6, 0x09, 0xdb, 0xee, 0x11, 0xe2, 0x3d, 0xfc, + 0xdf, 0xd0, 0x1c, 0xe0, 0xf5, 0x13, 0x25, 0xcb, 0x07, 0x13, 0xcf, 0xff, 0xc5, + 0x35, 0x2a, 0xf7, 0xe9, 0xff, 0x0d, 0x4d, 0x12, 0xf9, 0x1f, 0x10, 0x16, 0x00, + 0x1d, 0xde, 0x15, 0x15, 0xa3, 0x03, 0xd5, 0xfc, 0x21, 0x01, 0xdb, 0xbf, 0xbf, + 0x09, 0xe0, 0xfc, 0x00, 0x10, 0xd2, 0xc8, 0xae, 0x08, 0x22, 0xf2, 0x51, 0x05, + 0x24, 0xfa, 0xe4, 0x10, 0xb5, 0xcb, 0x3f, 0xfc, 0xf9, 0x01, 0xf1, 0x64, 0xdd, + 0xf3, 0x20, 0xe8, 0xa5, 0xf1, 0x28, 0x44, 0xed, 0x28, 0x28, 0xa6, 0xe0, 0xff, + 0x41, 0xf1, 0x19, 0x0d, 0xfb, 0x0a, 0xe7, 0x15, 0x2c, 0x2b, 0x32, 0x0f, 0x4f, + 0x08, 0xf0, 0xd0, 0x2b, 0xea, 0xb0, 0xfc, 0xec, 0xd9, 0x43, 0x7e, 0xce, 0x0c, + 0xfa, 0x0b, 0x44, 0xc2, 0xc5, 0x18, 0xca, 0xe2, 0x01, 0xea, 0xa7, 0x36, 0xbd, + 0x24, 0xc8, 0xcd, 0xea, 0x1f, 0xd0, 0x14, 0xc0, 0xd3, 0xdc, 0x2b, 0xc9, 0xee, + 0xdd, 0xee, 0xfd, 0xb9, 0x0d, 0x26, 0x18, 0x25, 0xf7, 0x2f, 0xf8, 0xf1, 0x0e, + 0x16, 0xbd, 0xeb, 0xd2, 0x32, 0xc8, 0x10, 0xee, 0xa8, 0x07, 0x1e, 0x7f, 0xbc, + 0xf8, 0x0b, 0x0a, 0x24, 0x13, 0xd4, 0x1f, 0x02, 0xee, 0xd8, 0x1a, 0x00, 0xdb, + 0xc3, 0xe3, 0xf8, 0x09, 0x13, 0xdf, 0x08, 0xb4, 0x01, 0x2b, 0xc5, 0x0e, 0x04, + 0xdc, 0xe4, 0x05, 0x14, 0xc2, 0x0e, 0xf1, 0xda, 0x0c, 0xcf, 0x3e, 0x2d, 0x0b, + 0xf0, 0x0f, 0xea, 0xb3, 0xb6, 0xed, 0x1c, 0xe6, 0xe3, 0x43, 0xf0, 0x1b, 0xc2, + 0xd3, 0xfe, 0xb2, 0x30, 0x0d, 0xe9, 0x3c, 0x11, 0xd9, 0x20, 0xf7, 0xf8, 0x1a, + 0xf9, 0x16, 0xbf, 0xfb, 0xc9, 0x20, 0x1b, 0xc1, 0xd5, 0x92, 0x0e, 0x07, 0x04, + 0x4c, 0xbe, 0xe9, 0xc4, 0x05, 0xfc, 0x0d, 0xea, 0x6a, 0xd6, 0xea, 0xcc, 0x11, + 0xf9, 0xd8, 0x1f, 0xe9, 0x37, 0xcb, 0xb5, 0xf8, 0x69, 0xfd, 0xcb, 0x7f, 0xe7, + 0x20, 0xff, 0x00, 0xe1, 0x1a, 0x11, 0xe3, 0xc6, 0xf2, 0x02, 0x20, 0xd4, 0xe3, + 0xeb, 0xfe, 0xcd, 0xd1, 0x03, 0xdc, 0xfb, 0x05, 0xd9, 0xe7, 0x0c, 0x3f, 0xe7, + 0x22, 0x09, 0xbb, 0xe3, 0xfd, 0xe3, 0xd7, 0xda, 0xaa, 0x1e, 0xdc, 0xc4, 0xd0, + 0xc9, 0x64, 0xca, 0x3f, 0xe8, 0x18, 0xe2, 0x38, 0x28, 0xf1, 0x06, 0x0f, 0x18, + 0xd3, 0xf3, 0xff, 0xe1, 0xbe, 0x41, 0x02, 0x1e, 0x38, 0x15, 0xa3, 0x19, 0xe4, + 0x2c, 0x10, 0x31, 0xe6, 0xf9, 0xd6, 0xcb, 0xf2, 0xde, 0x03, 0x2a, 0x39, 0xf4, + 0xcf, 0x05, 0xf8, 0x51, 0xe2, 0xdc, 0xd8, 0xd3, 0xe5, 0x01, 0xdc, 0x0f, 0xc3, + 0xfb, 0xb8, 0x11, 0xfc, 0x10, 0x04, 0xd0, 0xfa, 0xea, 0x30, 0xa8, 0x13, 0xd9, + 0x2d, 0x00, 0xe0, 0xff, 0x3a, 0xf8, 0x39, 0x7d, 0x2a, 0x92, 0x16, 0xdc, 0xe3, + 0x1e, 0xe1, 0xde, 0xf1, 0x0b, 0xc8, 0xdf, 0xc7, 0xf1, 0xdd, 0xa4, 0xe6, 0xe0, + 0xee, 0x02, 0x0e, 0xfe, 0xcf, 0xb8, 0xe5, 0xde, 0x1f, 0x91, 0xf6, 0xd9, 0xf2, + 0xe0, 0xcb, 0xfe, 0xf5, 0x01, 0xf3, 0x43, 0x99, 0x1b, 0xd1, 0xbd, 0x35, 0xe4, + 0xd0, 0x87, 0xa8, 0xb8, 0x59, 0xf0, 0xa9, 0xd0, 0x88, 0x2e, 0x37, 0xb5, 0x02, + 0x42, 0xbb, 0x57, 0x5e, 0x07, 0xd3, 0x19, 0x4e, 0x1e, 0xe9, 0x20, 0xf9, 0xb5, + 0x27, 0xd6, 0xfe, 0xf6, 0x4b, 0xf7, 0xf1, 0xba, 0x43, 0xe2, 0x2f, 0x09, 0x91, + 0xf6, 0x14, 0xb5, 0x19, 0xa5, 0xe3, 0xda, 0xf4, 0x26, 0xe0, 0xdb, 0x1e, 0xbd, + 0x12, 0xbb, 0x16, 0xec, 0xc7, 0xa5, 0xd1, 0xea, 0xcf, 0x46, 0xb1, 0xc9, 0xde, + 0xdf, 0xd3, 0x07, 0x31, 0x4c, 0xdf, 0x2a, 0xe0, 0x3b, 0xbd, 0x1b, 0xec, 0x35, + 0x94, 0xe1, 0x20, 0xa8, 0x1b, 0x00, 0xd0, 0x1e, 0x29, 0xe8, 0xe7, 0x35, 0x0a, + 0x29, 0x47, 0xbe, 0x14, 0x48, 0xbc, 0x26, 0xdb, 0xdf, 0xec, 0x03, 0x5f, 0x0a, + 0x28, 0xf8, 0x4b, 0xe7, 0x8e, 0xfe, 0x91, 0xc5, 0x9f, 0x49, 0xed, 0xbc, 0x41, + 0x20, 0x9d, 0xc9, 0xcd, 0xf2, 0xf7, 0x34, 0x0e, 0xda, 0x2a, 0x98, 0xe0, 0x81, + 0x9e, 0x5c, 0x29, 0xd0, 0xcb, 0x3b, 0xef, 0x5c, 0x1c, 0xbc, 0xef, 0x03, 0xfe, + 0x42, 0x3f, 0xc2, 0xd6, 0xea, 0xd1, 0x8a, 0xe3, 0x04, 0xc0, 0x15, 0x38, 0x0d, + 0xfa, 0xb9, 0xb4, 0x1a, 0xd1, 0x47, 0xa0, 0x20, 0x40, 0xf1, 0xd0, 0xbb, 0x06, + 0x19, 0x2a, 0x48, 0xd3, 0x27, 0xf0, 0xf2, 0x1e, 0x0f, 0x19, 0x09, 0x3c, 0xe2, + 0xc2, 0xba, 0x31, 0xf3, 0xf6, 0x30, 0xb5, 0xd6, 0xe4, 0x30, 0x50, 0x14, 0x13, + 0x5a, 0x0e, 0x44, 0xfe, 0xd5, 0xf2, 0xb6, 0xde, 0x28, 0x55, 0x10, 0xfd, 0x0e, + 0xc0, 0xf4, 0xfd, 0x2a, 0x11, 0xae, 0xbe, 0x05, 0xd3, 0x33, 0xc2, 0xcd, 0xc5, + 0xc3, 0xad, 0x26, 0xea, 0x29, 0x6d, 0x17, 0xed, 0x4d, 0xe7, 0xed, 0xdc, 0xcf, + 0xc8, 0x49, 0xfb, 0xe5, 0x07, 0x20, 0xbf, 0x28, 0xd9, 0xef, 0xca, 0xe9, 0xc4, + 0x8f, 0xd7, 0xc3, 0xde, 0xb5, 0xf3, 0xeb, 0x99, 0xac, 0xf4, 0xf3, 0xe4, 0xfd, + 0xfc, 0x15, 0xf6, 0x09, 0xc4, 0xf0, 0xf5, 0xd0, 0xf8, 0xf7, 0xb1, 0xf9, 0x0a, + 0xf8, 0x2e, 0xe6, 0xf9, 0xfb, 0x15, 0x15, 0x0c, 0x1b, 0xf7, 0xe8, 0x08, 0xd5, + 0x1b, 0xfd, 0xeb, 0xfb, 0xf4, 0xe0, 0xeb, 0x10, 0x00, 0xf5, 0xcf, 0x1e, 0xfb, + 0xd8, 0x5a, 0xf1, 0x08, 0xe0, 0xd9, 0x95, 0xd4, 0x47, 0x0d, 0x06, 0x18, 0xde, + 0x03, 0xfd, 0xfb, 0xd3, 0xed, 0xe7, 0x0c, 0xeb, 0x2c, 0xe4, 0x2f, 0xfd, 0xf0, + 0xf0, 0xf9, 0x08, 0xdf, 0xec, 0x38, 0xff, 0xe9, 0xc7, 0xe0, 0xc8, 0xd1, 0xcc, + 0x14, 0x0e, 0x03, 0x78, 0xd6, 0xfc, 0xf9, 0xf1, 0xed, 0xf7, 0xda, 0x07, 0x04, + 0x07, 0xf0, 0xee, 0x26, 0xef, 0xd1, 0xff, 0x23, 0x13, 0xdf, 0xfa, 0x18, 0xf4, + 0xe2, 0xe5, 0x17, 0xfe, 0xc6, 0x25, 0xf6, 0xd2, 0xe4, 0xd0, 0x19, 0xf1, 0x11, + 0xfe, 0x02, 0x09, 0x3b, 0x04, 0xf1, 0x13, 0xbe, 0xb8, 0xf2, 0xfb, 0xf8, 0x24, + 0x12, 0x1b, 0xfb, 0x10, 0xe1, 0xf2, 0x60, 0xfd, 0xed, 0x30, 0x2b, 0x27, 0x08, + 0x20, 0xae, 0xf7, 0x06, 0x13, 0xee, 0x00, 0xfe, 0x11, 0x06, 0x1b, 0xe0, 0xfb, + 0x0e, 0x1a, 0xc4, 0xdf, 0x1a, 0xff, 0xfd, 0x15, 0xfe, 0xf3, 0xfe, 0x0b, 0xea, + 0xfa, 0x0e, 0x0e, 0x27, 0xff, 0x03, 0xf4, 0x22, 0xff, 0x02, 0xf0, 0xf9, 0xf5, + 0xf4, 0x39, 0xf2, 0xd4, 0x07, 0x00, 0xf1, 0xff, 0xe8, 0xf4, 0xea, 0x15, 0x18, + 0xe1, 0x25, 0x05, 0x2b, 0xd3, 0x05, 0xf6, 0x01, 0xff, 0x34, 0x05, 0x0e, 0x7f, + 0x1d, 0x02, 0xee, 0x0e, 0xf8, 0x16, 0xdc, 0xc7, 0x12, 0xbc, 0xda, 0xda, 0x16, + 0x02, 0xdd, 0xd8, 0xc7, 0x10, 0xe2, 0x34, 0x03, 0xfc, 0xfe, 0xf1, 0x15, 0xe7, + 0xca, 0xe0, 0x10, 0x07, 0x02, 0x16, 0xfa, 0xf9, 0x05, 0xb5, 0xed, 0xc8, 0xc5, + 0xe5, 0xe4, 0x14, 0xf9, 0x0b, 0x30, 0xee, 0xf5, 0xbf, 0x17, 0xe2, 0x19, 0xc7, + 0xa5, 0xc7, 0xd5, 0x3d, 0xbe, 0x1b, 0xaa, 0xc8, 0x44, 0x09, 0xdb, 0xf2, 0x31, + 0xec, 0xca, 0x11, 0xfb, 0x5d, 0xfe, 0x0d, 0x58, 0x3c, 0xb8, 0xe9, 0x3f, 0xde, + 0xbb, 0xeb, 0x28, 0xd5, 0xff, 0xce, 0x06, 0xb4, 0xbb, 0x81, 0xdf, 0x5e, 0xff, + 0xe6, 0xed, 0x5f, 0xae, 0xe1, 0x0a, 0x23, 0xcd, 0x37, 0x40, 0x32, 0x44, 0x47, + 0xc2, 0x9e, 0x18, 0xdb, 0x49, 0x4f, 0x21, 0xd3, 0x10, 0xd1, 0x08, 0xec, 0xe8, + 0xa6, 0x39, 0x9e, 0xad, 0x23, 0x37, 0x88, 0x16, 0xc7, 0x3e, 0xa6, 0xf4, 0x10, + 0xe6, 0xbc, 0xf3, 0x1d, 0xc7, 0x13, 0x34, 0xaa, 0xc6, 0xec, 0xd4, 0xb6, 0x27, + 0xfa, 0xf0, 0x8e, 0xe4, 0xdb, 0x0d, 0x30, 0xd3, 0x3f, 0xe3, 0xef, 0x2c, 0xd6, + 0xa9, 0xca, 0xaa, 0x27, 0x55, 0x21, 0x1e, 0xb4, 0xf0, 0xf0, 0x00, 0x08, 0x0a, + 0xff, 0xef, 0xd7, 0x36, 0xd5, 0xe2, 0xee, 0xca, 0xf1, 0x42, 0xe6, 0xfd, 0x37, + 0xe8, 0xde, 0xe8, 0xdf, 0x21, 0x17, 0x4c, 0x21, 0xee, 0x12, 0xca, 0x12, 0xab, + 0xde, 0xf4, 0xe2, 0xbd, 0x8b, 0x12, 0xf2, 0x21, 0x28, 0xd5, 0x55, 0xdb, 0x41, + 0xad, 0x48, 0x33, 0x21, 0x4a, 0x20, 0xfb, 0xf4, 0x31, 0x38, 0x1c, 0x08, 0x5d, + 0x43, 0x98, 0xa6, 0x3f, 0xc6, 0xe5, 0xf9, 0x3e, 0x07, 0xef, 0x2e, 0xed, 0x1d, + 0x0d, 0xe9, 0xf1, 0x26, 0x16, 0x12, 0x10, 0x01, 0x3b, 0x32, 0xdf, 0xc9, 0x69, + 0x98, 0x33, 0x25, 0x81, 0xe2, 0x02, 0xff, 0xc7, 0x1f, 0xe6, 0x03, 0xe1, 0xc8, + 0x2d, 0xe6, 0x38, 0xec, 0x12, 0x56, 0x16, 0xea, 0x54, 0xf4, 0xd0, 0x03, 0x1e, + 0xf6, 0xe8, 0xe3, 0x11, 0xed, 0x14, 0xcb, 0xf7, 0xb8, 0xcf, 0xfb, 0xa9, 0xe9, + 0x00, 0xdd, 0xdd, 0xfc, 0xb6, 0xae, 0x0a, 0x12, 0xcd, 0x06, 0xa2, 0xb9, 0x0a, + 0x04, 0xb1, 0x4b, 0xd5, 0xe9, 0x39, 0x23, 0x6e, 0xa5, 0xc3, 0xd5, 0xf4, 0xb3, + 0xf1, 0x08, 0x16, 0x64, 0x3f, 0xde, 0xe2, 0xba, 0x09, 0xe6, 0xee, 0xce, 0xf5, + 0xab, 0xd9, 0x35, 0xcc, 0x0e, 0xfe, 0xe4, 0x21, 0x21, 0x39, 0x04, 0x26, 0x44, + 0xa5, 0x2d, 0x39, 0xe0, 0xfb, 0x25, 0x09, 0x09, 0xb7, 0xf6, 0xde, 0x14, 0x04, + 0x4a, 0xcc, 0x38, 0xfc, 0x12, 0x36, 0x93, 0x36, 0xd3, 0xea, 0xfe, 0xf8, 0xa2, + 0xd0, 0x1e, 0x03, 0xc5, 0xba, 0xe8, 0xf5, 0x28, 0xe8, 0x18, 0x2f, 0xfe, 0xf0, + 0xdc, 0x4d, 0x3b, 0xdf, 0x31, 0x07, 0x0e, 0xd0, 0xfd, 0x24, 0x1a, 0xd9, 0x26, + 0xcc, 0x4a, 0xd2, 0xbf, 0xdb, 0xfc, 0xe4, 0x34, 0x12, 0xf4, 0x26, 0x59, 0x15, + 0xce, 0x3b, 0xbe, 0xe3, 0xdf, 0xf5, 0x03, 0xbc, 0x20, 0x73, 0xfe, 0xc9, 0xe0, + 0x08, 0xeb, 0xc0, 0x31, 0xd1, 0xab, 0x08, 0xd9, 0xa5, 0xda, 0x3d, 0xfc, 0x39, + 0x28, 0xdd, 0xff, 0xc0, 0xd8, 0x6c, 0xf5, 0xff, 0x2d, 0xd7, 0x9e, 0x1e, 0xbc, + 0x1f, 0xc6, 0xf0, 0x28, 0xf2, 0xad, 0x25, 0xbf, 0x8a, 0x37, 0x34, 0xf0, 0x56, + 0xf2, 0x4f, 0x0d, 0x30, 0x0e, 0x1d, 0x17, 0xf2, 0xaa, 0xea, 0x18, 0x29, 0x06, + 0x06, 0xf2, 0x26, 0x64, 0x1c, 0x01, 0xcc, 0x0d, 0x0d, 0x09, 0x02, 0xa4, 0x08, + 0xdd, 0x02, 0xd2, 0x36, 0xe6, 0x8c, 0x2f, 0x0d, 0xdb, 0xfe, 0x3d, 0x10, 0x20, + 0x07, 0xd6, 0x0e, 0x47, 0x34, 0x05, 0xd3, 0x8f, 0x1d, 0x12, 0x29, 0xcf, 0xf8, + 0x1e, 0xbd, 0x50, 0x4d, 0xbf, 0xdc, 0xef, 0xf2, 0xeb, 0x21, 0x1c, 0x08, 0x02, + 0x0f, 0xb3, 0xce, 0xcb, 0xd8, 0x04, 0x2f, 0x02, 0x02, 0xe4, 0xa2, 0xfa, 0xed, + 0xca, 0x81, 0x08, 0xd6, 0xfb, 0xd1, 0x4f, 0xd9, 0x21, 0x4b, 0xe6, 0x2d, 0xeb, + 0xe0, 0xb1, 0x34, 0xfb, 0x2f, 0x46, 0xdd, 0x39, 0xed, 0xd5, 0xfb, 0xe0, 0x11, + 0xe9, 0x0e, 0xc2, 0x39, 0x22, 0xce, 0xd5, 0xdd, 0x28, 0x99, 0xe2, 0xc0, 0x99, + 0xea, 0x0b, 0x4a, 0x0a, 0x20, 0xc2, 0xb5, 0xed, 0xb2, 0x52, 0xba, 0xe5, 0xf9, + 0x1f, 0xcd, 0xc2, 0xca, 0xd5, 0x18, 0xd1, 0xe7, 0x44, 0x25, 0xaa, 0xde, 0x3c, + 0x8e, 0xc6, 0xf0, 0x1a, 0xe5, 0x02, 0xfd, 0xf7, 0x1a, 0xf6, 0x5f, 0xc8, 0xd8, + 0xf9, 0x1d, 0x06, 0x8d, 0xbd, 0x5c, 0xc7, 0xb4, 0xc6, 0x25, 0xd4, 0x5a, 0x34, + 0x11, 0x9f, 0x87, 0xdd, 0x1a, 0x9b, 0xe8, 0x24, 0xdf, 0x1d, 0x2d, 0xce, 0xf8, + 0x40, 0x3a, 0x16, 0xd5, 0xf8, 0xcb, 0xe6, 0x09, 0xf6, 0xce, 0x2f, 0x06, 0xd2, + 0x1b, 0x25, 0xaa, 0xeb, 0xd6, 0xbc, 0xf5, 0x05, 0x57, 0x05, 0x07, 0xf8, 0xbb, + 0x0a, 0xab, 0xe1, 0x4a, 0xb9, 0xf4, 0xc0, 0xea, 0xe0, 0xc3, 0xee, 0x2c, 0xe7, + 0xf9, 0xdd, 0x03, 0xdd, 0x58, 0xf0, 0xf0, 0xd3, 0xda, 0x54, 0x09, 0xe0, 0xc4, + 0xdc, 0xc7, 0xc7, 0x3a, 0x0a, 0xb0, 0xc6, 0x06, 0xe7, 0x1b, 0x00, 0xc2, 0x25, + 0xc5, 0x0f, 0xe9, 0x2f, 0xe0, 0x16, 0x17, 0x16, 0x14, 0x25, 0xd2, 0x12, 0xef, + 0x27, 0x19, 0xc5, 0x0a, 0xe7, 0x10, 0x08, 0x96, 0x41, 0xfe, 0x06, 0x16, 0x0c, + 0x20, 0x3b, 0xb2, 0x0b, 0xd9, 0xe7, 0xe5, 0x09, 0xf8, 0xb8, 0xec, 0xe4, 0x59, + 0xbf, 0x2d, 0x0c, 0x49, 0xff, 0x58, 0xca, 0x00, 0x05, 0x2a, 0x36, 0xa7, 0xf1, + 0x07, 0xa0, 0xb6, 0x17, 0x19, 0xc6, 0x1f, 0x3b, 0xe8, 0x12, 0x46, 0xf9, 0x29, + 0xeb, 0x47, 0x81, 0x07, 0x1a, 0xfc, 0x44, 0x5f, 0xe1, 0xf0, 0xba, 0x40, 0xeb, + 0x42, 0xfa, 0x1b, 0xe8, 0xe7, 0xee, 0xe9, 0xf8, 0x38, 0xf9, 0x4b, 0x11, 0x0e, + 0x03, 0x26, 0x06, 0x19, 0x0e, 0xdc, 0xc3, 0x10, 0x12, 0x01, 0xf1, 0x3e, 0xcd, + 0x06, 0xdf, 0xf3, 0xb4, 0x15, 0x00, 0x13, 0xbf, 0x56, 0x9a, 0xdb, 0xf8, 0xd8, + 0x37, 0xcf, 0xf5, 0x22, 0xd0, 0x21, 0x3f, 0xd8, 0x31, 0xdd, 0xfd, 0xf7, 0xe5, + 0x0a, 0xc3, 0xdd, 0xe9, 0xe9, 0x1f, 0x10, 0x3f, 0x81, 0xfb, 0x27, 0xb4, 0xa3, + 0xd7, 0xf1, 0xfc, 0x12, 0x61, 0xff, 0xfb, 0x37, 0x08, 0xd7, 0x32, 0xf8, 0xa0, + 0xfe, 0x0d, 0xeb, 0xff, 0xef, 0xec, 0xdf, 0xc0, 0x1a, 0x3c, 0xd1, 0xe3, 0xf4, + 0x3c, 0xbe, 0x1c, 0xf2, 0xed, 0x0f, 0xf2, 0x36, 0xd7, 0x1d, 0xfd, 0x12, 0x0a, + 0xf1, 0x06, 0xf9, 0xb8, 0xa5, 0xf8, 0xf5, 0xbd, 0x36, 0x99, 0xc6, 0xf4, 0x0b, + 0x56, 0x17, 0x61, 0x21, 0xa4, 0xc0, 0x43, 0xe9, 0x01, 0xe6, 0xcf, 0xb2, 0xe4, + 0x14, 0x03, 0xde, 0xcc, 0xf5, 0x03, 0xd5, 0xa6, 0x10, 0xc0, 0xe0, 0xfa, 0x19, + 0xbd, 0xe2, 0x29, 0xd2, 0xfa, 0x4c, 0x19, 0xc4, 0x3f, 0x1d, 0xf2, 0x2a, 0xde, + 0xd5, 0x37, 0xde, 0xc8, 0xbc, 0x22, 0x5c, 0xf2, 0x15, 0xd2, 0xde, 0x32, 0x24, + 0xbe, 0xc9, 0x23, 0xe7, 0x90, 0x34, 0x1b, 0xf4, 0xa4, 0x45, 0xe6, 0x11, 0x09, + 0xe7, 0x22, 0xf5, 0x53, 0x4e, 0xc9, 0xe3, 0x26, 0xe4, 0x49, 0x3a, 0xd2, 0x26, + 0xc1, 0xff, 0xd8, 0x23, 0x23, 0x30, 0xc4, 0x04, 0xc8, 0xa0, 0x3b, 0x9b, 0xfb, + 0x4a, 0xdf, 0x17, 0x11, 0xa9, 0x08, 0x0d, 0x21, 0x63, 0x0e, 0x3e, 0x53, 0x28, + 0xdc, 0x1d, 0x06, 0xc6, 0xb1, 0xd3, 0x22, 0xf8, 0x2c, 0x03, 0xcb, 0x28, 0xf7, + 0x0b, 0x00, 0xff, 0xba, 0xfb, 0xf3, 0x0e, 0x2e, 0xaa, 0xe1, 0x29, 0x2c, 0xd6, + 0xfc, 0xc9, 0xd9, 0x23, 0x27, 0x04, 0xeb, 0x45, 0x26, 0xfc, 0x11, 0x81, 0x3c, + 0x2b, 0xf4, 0x54, 0xf9, 0xd4, 0x20, 0x1c, 0xf3, 0xcd, 0x0a, 0x24, 0xda, 0x11, + 0xfb, 0xfa, 0xec, 0xc3, 0x69, 0x17, 0xff, 0xcb, 0xec, 0x2b, 0xde, 0x3b, 0x2a, + 0x2c, 0x32, 0xe5, 0xa7, 0x01, 0xdf, 0xe8, 0xfe, 0x2a, 0x3f, 0x50, 0xe3, 0xf1, + 0xfd, 0x1b, 0xb6, 0xc8, 0xd5, 0x07, 0x07, 0xf9, 0xeb, 0x44, 0xb8, 0xf2, 0x3a, + 0xe0, 0x0e, 0xb9, 0xee, 0xe2, 0x08, 0xdc, 0xd3, 0xd7, 0xdd, 0xf1, 0xea, 0xc9, + 0x24, 0xe0, 0x37, 0xb8, 0x39, 0x3d, 0x28, 0x2d, 0xcf, 0xe9, 0xad, 0xbf, 0x0b, + 0xf8, 0xf0, 0x20, 0x0c, 0xe5, 0xa8, 0xae, 0x14, 0x0c, 0xe0, 0x2e, 0x24, 0x18, + 0xa5, 0x5f, 0xca, 0x24, 0x12, 0xdf, 0x09, 0xf2, 0x1e, 0xde, 0xcc, 0xe8, 0xfc, + 0xe0, 0xdf, 0xa5, 0xad, 0xdd, 0x3a, 0x14, 0x07, 0x25, 0x2c, 0xf5, 0x41, 0xcd, + 0xdf, 0x20, 0x1e, 0x04, 0xe0, 0x53, 0x4d, 0xf2, 0x82, 0xde, 0xfc, 0xca, 0xf4, + 0xd8, 0x3c, 0x36, 0xd6, 0xb3, 0x1e, 0xff, 0x07, 0x2a, 0xdc, 0xb3, 0xe3, 0x17, + 0x13, 0xdf, 0x25, 0xa7, 0xd5, 0x16, 0x23, 0x1b, 0x1c, 0x53, 0xa1, 0xb7, 0x05, + 0x81, 0xec, 0xf7, 0x5d, 0xa0, 0x5b, 0x04, 0x3e, 0xbd, 0x2d, 0xaa, 0xd3, 0x00, + 0xa5, 0x11, 0x2e, 0xe1, 0x0a, 0x83, 0x27, 0x37, 0xb5, 0xce, 0x0d, 0xd4, 0x49, + 0xfe, 0x3f, 0xeb, 0x17, 0xfc, 0x2e, 0x0b, 0x03, 0xfd, 0xc0, 0x91, 0xf1, 0x51, + 0xc6, 0xfb, 0xd5, 0xf6, 0x02, 0x05, 0xd0, 0x08, 0xee, 0x3a, 0x05, 0xaa, 0x42, + 0xbb, 0x09, 0x22, 0x13, 0xd6, 0xd0, 0x57, 0x2e, 0x02, 0x4a, 0xc0, 0xef, 0x1b, + 0xdd, 0xf1, 0xe8, 0x15, 0x18, 0xe6, 0x35, 0x17, 0xad, 0xf5, 0x05, 0x14, 0x03, + 0x02, 0x4a, 0xda, 0x09, 0xea, 0xfc, 0x46, 0x86, 0xe8, 0xcd, 0xc9, 0x1a, 0x42, + 0xbb, 0xca, 0xd6, 0xaf, 0x34, 0x3f, 0xc3, 0xd4, 0xeb, 0x1b, 0x2e, 0xdf, 0x08, + 0x4c, 0x03, 0xed, 0xd5, 0xd5, 0xe7, 0x00, 0x13, 0x1c, 0x04, 0xe0, 0x23, 0x27, + 0xaf, 0x36, 0x86, 0xa3, 0xa3, 0xed, 0x2a, 0x22, 0x4a, 0x07, 0x15, 0xe5, 0xb4, + 0xef, 0xe1, 0x4c, 0x26, 0xfb, 0x15, 0x7d, 0xdb, 0xde, 0x12, 0x11, 0xe8, 0xbf, + 0xf3, 0xa7, 0x56, 0xfb, 0xbc, 0x32, 0xd0, 0x05, 0xfe, 0xfd, 0xca, 0xef, 0x0a, + 0x0f, 0xc3, 0xf7, 0xfd, 0xf8, 0x13, 0x16, 0x1b, 0x0d, 0xc9, 0xc0, 0xeb, 0xbb, + 0x43, 0xd1, 0xef, 0x48, 0xe9, 0xd5, 0xeb, 0xee, 0xd8, 0x24, 0x2c, 0xfe, 0x01, + 0x19, 0xd7, 0x05, 0xe8, 0x2c, 0xcb, 0x01, 0x1b, 0xf7, 0xe1, 0x0a, 0xea, 0x4f, + 0x27, 0xdc, 0xca, 0x1d, 0x41, 0xdb, 0x01, 0x5d, 0xd5, 0xda, 0x14, 0xfd, 0xf5, + 0xe0, 0xdf, 0x13, 0x08, 0x38, 0x4b, 0xef, 0xd3, 0xc7, 0x14, 0x00, 0x24, 0xe4, + 0xb3, 0x38, 0x3e, 0xe7, 0x11, 0x1e, 0x20, 0x13, 0x15, 0xd7, 0x06, 0xf1, 0xb7, + 0xfc, 0xda, 0xd8, 0x02, 0x09, 0xc7, 0xfa, 0xc2, 0xfe, 0x1b, 0xfd, 0xe3, 0xba, + 0x15, 0xf6, 0x02, 0x08, 0x03, 0x7f, 0x01, 0xf7, 0x1c, 0xc2, 0x05, 0xe8, 0xfe, + 0xf9, 0x0e, 0xd1, 0x50, 0xe4, 0xe1, 0x02, 0xc8, 0x3d, 0xec, 0x56, 0x0b, 0x16, + 0x09, 0x19, 0x19, 0x33, 0x10, 0x0f, 0xee, 0xcb, 0xe9, 0xd5, 0x07, 0xe3, 0x3b, + 0xef, 0x05, 0x1f, 0x2f, 0x19, 0x44, 0x2d, 0xee, 0x25, 0x06, 0x0e, 0x00, 0x11, + 0x1a, 0x46, 0x07, 0x26, 0x1b, 0x1f, 0xbe, 0xf2, 0x25, 0xcb, 0xe2, 0xee, 0xeb, + 0xe2, 0x08, 0x0b, 0x17, 0xfc, 0xe5, 0xc6, 0xfe, 0xd3, 0x1b, 0xc2, 0x19, 0x19, + 0x14, 0x3a, 0x10, 0x35, 0x1a, 0x7a, 0xfe, 0x1d, 0xfe, 0xfb, 0x09, 0x0f, 0xca, + 0x25, 0x49, 0x2c, 0xb0, 0xf9, 0xd3, 0xcb, 0xdb, 0x19, 0x4e, 0xd5, 0xed, 0xe0, + 0xec, 0x4a, 0xfe, 0xee, 0xcf, 0xec, 0x03, 0xf6, 0x2b, 0xcc, 0x18, 0x1a, 0xe6, + 0xf2, 0x09, 0xdc, 0xcf, 0xe2, 0x07, 0x01, 0xf6, 0xe7, 0x00, 0xdb, 0xb4, 0xc0, + 0x19, 0xdf, 0x07, 0x59, 0xd0, 0x43, 0xea, 0xc8, 0xd2, 0x81, 0xf3, 0xec, 0x08, + 0xed, 0x0f, 0xd9, 0xe4, 0xf5, 0xd7, 0xcd, 0x3d, 0x0d, 0xe6, 0x60, 0xf6, 0xd7, + 0x60, 0xf6, 0x04, 0x0b, 0xfb, 0xfb, 0x17, 0xf5, 0xec, 0xef, 0xe6, 0x10, 0xe0, + 0xc2, 0x00, 0x2a, 0xd4, 0xfe, 0x11, 0x20, 0xd9, 0xe8, 0xf5, 0x0c, 0xde, 0x22, + 0x05, 0x36, 0xb1, 0xd5, 0x0e, 0xcd, 0x1d, 0xda, 0x02, 0xfc, 0x03, 0xdd, 0x51, + 0xdd, 0x0a, 0xf9, 0xe9, 0x0e, 0xf9, 0xf3, 0xcd, 0xcc, 0xf4, 0x24, 0x1a, 0x08, + 0xf2, 0x23, 0xeb, 0xed, 0xce, 0xff, 0xdf, 0x0f, 0xf3, 0xc4, 0xeb, 0x12, 0xef, + 0x1b, 0x47, 0xca, 0xc6, 0xd0, 0x01, 0xfd, 0x32, 0xea, 0x1e, 0xfc, 0xba, 0xdd, + 0x14, 0x0f, 0xe3, 0xef, 0xe8, 0xca, 0x19, 0xfb, 0xdd, 0x12, 0x15, 0xf6, 0x02, + 0x1f, 0x20, 0x0e, 0xe5, 0x0e, 0x03, 0xf7, 0xe9, 0x06, 0xf4, 0xde, 0x22, 0xee, + 0x50, 0x50, 0x14, 0xef, 0x16, 0xd7, 0xce, 0x15, 0xf3, 0xfe, 0x2d, 0xe2, 0xf8, + 0xdf, 0x1d, 0xfa, 0x0a, 0x5d, 0xf1, 0x0c, 0x1f, 0x3e, 0xfe, 0x4b, 0x00, 0xc0, + 0xbf, 0x02, 0x04, 0x10, 0x1f, 0x37, 0xd9, 0x2a, 0x08, 0xe4, 0xfb, 0x27, 0x1b, + 0xe9, 0xdc, 0xde, 0x33, 0xf7, 0x10, 0xd9, 0xf0, 0xff, 0x50, 0x27, 0xf1, 0x1e, + 0x24, 0x40, 0xd2, 0x06, 0x17, 0x11, 0x17, 0xf3, 0xdf, 0x11, 0xe6, 0x18, 0x29, + 0xff, 0xe3, 0xd2, 0xd6, 0xcd, 0xf4, 0x0a, 0xf1, 0x0d, 0x6d, 0x08, 0x11, 0xfc, + 0x07, 0xd6, 0xc8, 0x25, 0xbe, 0x04, 0x02, 0x1c, 0xf5, 0x01, 0x2f, 0x0a, 0x0e, + 0xd9, 0xf4, 0xdf, 0x1d, 0xe6, 0xd2, 0x02, 0xda, 0x2c, 0xc4, 0x00, 0xed, 0x21, + 0xeb, 0xcf, 0x2a, 0xf4, 0xb5, 0xfc, 0xb4, 0xc9, 0x03, 0xeb, 0xf4, 0xdd, 0x04, + 0xf4, 0x07, 0xdd, 0x10, 0xf8, 0xea, 0xdd, 0xf5, 0x06, 0xad, 0xce, 0xd6, 0xf7, + 0x1a, 0x21, 0xdc, 0x3d, 0xd7, 0x29, 0xf8, 0xed, 0x1b, 0x0d, 0xc7, 0x08, 0xcf, + 0xc4, 0x2a, 0xe3, 0x2c, 0xec, 0x27, 0x1f, 0xbe, 0x28, 0xd8, 0xe0, 0xab, 0xb5, + 0xf0, 0xd1, 0xd0, 0xeb, 0x41, 0xeb, 0x11, 0x06, 0xd8, 0xb9, 0xd4, 0x37, 0xce, + 0x09, 0x1b, 0x07, 0xf0, 0x0b, 0xde, 0xe4, 0xf4, 0x04, 0xd9, 0x2d, 0x1d, 0xf0, + 0xf9, 0x03, 0xf1, 0xb5, 0xe2, 0xd1, 0xf2, 0x38, 0xf0, 0x04, 0xc8, 0xb4, 0xf8, + 0x18, 0xc7, 0x56, 0xfe, 0x0a, 0xe3, 0x16, 0xfd, 0x26, 0xfd, 0xeb, 0xdf, 0x09, + 0xf5, 0xdc, 0x15, 0x04, 0xd6, 0xd1, 0x22, 0x18, 0x81, 0x0c, 0xdd, 0xb7, 0x05, + 0xda, 0xec, 0x25, 0xed, 0x12, 0x18, 0x56, 0xc9, 0xab, 0xd2, 0x06, 0xe2, 0xeb, + 0xe5, 0xb3, 0xc6, 0xec, 0xf3, 0x22, 0xaa, 0xfb, 0x09, 0x10, 0xe8, 0xd9, 0xfe, + 0xdc, 0x03, 0x45, 0xed, 0x18, 0x0f, 0xab, 0xfd, 0xdf, 0xeb, 0xe1, 0x19, 0xb3, + 0xd1, 0xfc, 0xd5, 0x3f, 0x1a, 0x04, 0x9e, 0xfc, 0x1c, 0x28, 0xb4, 0xd7, 0xf4, + 0xe2, 0xcc, 0xf3, 0x48, 0x24, 0xcb, 0x41, 0xf1, 0x02, 0xf1, 0xbf, 0x07, 0xf3, + 0x5c, 0xff, 0xcb, 0xd0, 0xe8, 0xc6, 0x65, 0xf3, 0xb2, 0x27, 0x2a, 0xe7, 0xc4, + 0xd0, 0x0d, 0x93, 0x06, 0xdc, 0xe7, 0x0d, 0x30, 0x34, 0xf8, 0x03, 0x23, 0xf5, + 0x07, 0xc1, 0xfa, 0x2f, 0xe8, 0x05, 0x10, 0xd0, 0x36, 0x31, 0xe6, 0xfa, 0x9a, + 0x99, 0xd7, 0x01, 0x0b, 0x23, 0xee, 0xea, 0x1f, 0x02, 0xd3, 0x40, 0xb5, 0xb6, + 0x9f, 0xfb, 0xd8, 0x11, 0xce, 0x01, 0xf9, 0xe4, 0xf3, 0xcb, 0xb2, 0xfb, 0xd6, + 0xf0, 0x1b, 0x25, 0xe4, 0x14, 0xea, 0xa6, 0x2b, 0xee, 0xe5, 0x08, 0xff, 0x54, + 0x13, 0xc7, 0xd9, 0xda, 0x31, 0xeb, 0x18, 0x0a, 0x01, 0xca, 0x0d, 0x57, 0x2d, + 0x05, 0x02, 0xe8, 0x06, 0xfc, 0xee, 0x22, 0xcc, 0xfd, 0x5e, 0x18, 0xfe, 0xf8, + 0xef, 0x3a, 0x9d, 0x09, 0x1e, 0xd5, 0xa7, 0xce, 0x4d, 0x0e, 0xf7, 0xd0, 0xfc, + 0xd0, 0xcf, 0xb5, 0xf6, 0x3d, 0x15, 0x18, 0xe1, 0x9a, 0xe1, 0xdc, 0x09, 0x15, + 0x21, 0x4e, 0xf5, 0x50, 0x30, 0xce, 0xc2, 0x11, 0xe2, 0xe1, 0x2e, 0xe1, 0x2d, + 0xd7, 0x11, 0xd4, 0xf3, 0x3f, 0x17, 0xa1, 0xc1, 0xce, 0xf4, 0x47, 0xdc, 0x4e, + 0xf6, 0xf3, 0x30, 0x61, 0xd6, 0xc4, 0x11, 0xe2, 0xe7, 0x9e, 0x07, 0xee, 0xda, + 0x4c, 0x41, 0xb8, 0x22, 0x47, 0xa9, 0xea, 0x10, 0xc4, 0x59, 0x91, 0xed, 0x8e, + 0x38, 0xe5, 0x5a, 0x22, 0xe6, 0x3b, 0x7f, 0x34, 0xeb, 0xbf, 0x08, 0xb4, 0x05, + 0x46, 0xa8, 0xe8, 0xc5, 0x1d, 0x23, 0xed, 0xcc, 0x4f, 0xf0, 0x11, 0x20, 0x20, + 0x33, 0xeb, 0xf6, 0x77, 0xf6, 0x0d, 0xa0, 0xfa, 0x8d, 0x49, 0xcc, 0x15, 0x09, + 0x0a, 0x35, 0xdc, 0xb3, 0x4e, 0xdc, 0x31, 0x0b, 0xd6, 0xb0, 0x0c, 0xff, 0x64, + 0xf9, 0xc8, 0xe8, 0x3c, 0xea, 0x46, 0x11, 0x26, 0xf6, 0x9a, 0x1f, 0xe5, 0x36, + 0x32, 0xf5, 0x0f, 0x4f, 0xdb, 0x0d, 0xd2, 0x0e, 0xff, 0x2b, 0xda, 0xca, 0xa8, + 0x26, 0xeb, 0xdd, 0x05, 0x1b, 0xa0, 0x07, 0x8a, 0x38, 0x27, 0x3a, 0x18, 0x01, + 0xbe, 0xbe, 0x3e, 0xd9, 0x01, 0xc6, 0x44, 0xb4, 0xdf, 0x1f, 0x16, 0xb9, 0x21, + 0xfb, 0xd8, 0xf2, 0xa3, 0xd5, 0xf5, 0xf2, 0x06, 0xc5, 0xc5, 0xf7, 0x3f, 0xd3, + 0x41, 0xf8, 0xd1, 0xf9, 0xe0, 0xbf, 0x0e, 0xdb, 0x94, 0xe5, 0x05, 0x03, 0xfe, + 0xd2, 0x3b, 0xf0, 0x01, 0xcc, 0x04, 0x98, 0x15, 0x09, 0xae, 0xa4, 0x22, 0x2b, + 0xab, 0x03, 0x21, 0x2c, 0x30, 0x38, 0x44, 0xee, 0x12, 0xf9, 0xfe, 0x15, 0xb1, + 0x49, 0x5d, 0x01, 0x9c, 0x31, 0x91, 0x3d, 0xeb, 0x1d, 0xa9, 0xe0, 0xe7, 0xcf, + 0xde, 0x26, 0xcf, 0xef, 0x14, 0x0f, 0xbc, 0x0d, 0xe9, 0x96, 0xe0, 0xec, 0xe8, + 0xc7, 0x1c, 0x06, 0xe1, 0xc2, 0xe0, 0xff, 0xdc, 0xfc, 0xf3, 0xe2, 0xe2, 0x01, + 0x21, 0xd3, 0x3b, 0xf3, 0x18, 0x19, 0xff, 0xe4, 0xcf, 0xbf, 0xe9, 0xd0, 0x39, + 0xe2, 0x12, 0xe6, 0xf2, 0xf3, 0xf9, 0xe8, 0xe2, 0xf5, 0xf6, 0x29, 0x9b, 0xa9, + 0x74, 0xb8, 0xef, 0xb4, 0xef, 0xc4, 0xfe, 0x35, 0x27, 0x0a, 0x05, 0xf9, 0x03, + 0x15, 0x15, 0xd9, 0x12, 0x29, 0xf6, 0xeb, 0x2d, 0x0c, 0x16, 0xf7, 0xee, 0xc2, + 0xb9, 0x1d, 0xd5, 0xef, 0x46, 0xf1, 0x0f, 0xe0, 0x07, 0xcf, 0xc6, 0x1d, 0xec, + 0x07, 0x11, 0x26, 0xf4, 0xde, 0xc1, 0xf0, 0xea, 0x1a, 0xda, 0xe5, 0x3b, 0x34, + 0xd4, 0xd6, 0x0a, 0xf9, 0xc6, 0xe0, 0x0b, 0xdf, 0x1b, 0xb4, 0xfa, 0xf0, 0xf7, + 0x0a, 0x0e, 0xcc, 0xcd, 0x01, 0xd6, 0x9f, 0xbf, 0xdc, 0xe0, 0xee, 0xe8, 0xf7, + 0xd9, 0x50, 0x25, 0x13, 0xfb, 0xe9, 0xb0, 0xe5, 0xfb, 0x4a, 0xd3, 0x02, 0xad, + 0x34, 0xc4, 0xf8, 0xf9, 0xe3, 0x5f, 0xfa, 0x01, 0xf0, 0xff, 0xf7, 0x0e, 0xf2, + 0xca, 0xe6, 0xfb, 0x0f, 0x08, 0xf2, 0xfb, 0x11, 0xe2, 0x15, 0xcc, 0xd5, 0x19, + 0x08, 0xad, 0xeb, 0x1a, 0xe5, 0x14, 0xd4, 0xf0, 0xf3, 0x0a, 0x1f, 0x1a, 0xf0, + 0xf7, 0x17, 0x19, 0xda, 0x1e, 0xf4, 0x20, 0x07, 0xdb, 0xe0, 0xb4, 0xef, 0x3c, + 0x03, 0xe2, 0xf0, 0xca, 0x44, 0xfa, 0xea, 0xf2, 0xec, 0xef, 0xfa, 0x14, 0xc5, + 0x3e, 0x1b, 0x2f, 0xfc, 0x07, 0xe3, 0x05, 0x24, 0xf3, 0xec, 0x10, 0x7f, 0xfe, + 0xed, 0x28, 0xee, 0x98, 0x1e, 0xe1, 0xb4, 0xee, 0x0d, 0xbe, 0x04, 0x3a, 0xcf, + 0xdb, 0xa5, 0xda, 0xd9, 0xed, 0x2a, 0x31, 0x00, 0xfe, 0xfb, 0xf9, 0xe7, 0xfa, + 0xa4, 0xc6, 0xe2, 0x02, 0xea, 0xfc, 0xeb, 0x14, 0xed, 0x11, 0x28, 0xd6, 0xd7, + 0xed, 0xef, 0xf1, 0xef, 0xc9, 0xe4, 0xf6, 0xe5, 0x47, 0x21, 0x0e, 0xcf, 0xa0, + 0x40, 0xce, 0xe1, 0x3c, 0xe9, 0xd9, 0xbd, 0x13, 0x14, 0x01, 0xe0, 0xc7, 0xef, + 0x39, 0xf1, 0x06, 0x09, 0x32, 0x30, 0x95, 0x10, 0xf4, 0x45, 0xd0, 0x1c, 0xe1, + 0xaa, 0x2f, 0x18, 0xeb, 0xc9, 0xf3, 0xa4, 0x1f, 0xd4, 0xda, 0x0e, 0xd0, 0x3a, + 0xfc, 0xf6, 0xa3, 0x20, 0xe2, 0xfa, 0x09, 0x5b, 0x17, 0x26, 0x25, 0x08, 0xf7, + 0xed, 0x2d, 0x18, 0xc9, 0xfb, 0xc0, 0xe0, 0x09, 0xdb, 0x02, 0x0f, 0xf1, 0xdd, + 0xbd, 0xba, 0xd8, 0xbd, 0x12, 0xca, 0xbb, 0xcf, 0xf5, 0x3a, 0x34, 0xf9, 0xfe, + 0xd7, 0x10, 0xfa, 0x0c, 0xfa, 0xe5, 0x23, 0x04, 0xf7, 0xf1, 0x0f, 0xde, 0xcf, + 0x90, 0x31, 0x05, 0x4b, 0xfa, 0xe6, 0xef, 0xf4, 0xd9, 0x01, 0x03, 0x39, 0x02, + 0xa8, 0xe7, 0xf5, 0x13, 0x36, 0xd9, 0xff, 0x90, 0xbe, 0xf0, 0x02, 0x45, 0xb4, + 0xc2, 0x22, 0x28, 0x9f, 0xed, 0xf5, 0x13, 0x15, 0xfd, 0x18, 0xeb, 0x3b, 0x22, + 0x00, 0xfa, 0xdd, 0xe4, 0xcc, 0xd1, 0x25, 0x28, 0xf2, 0xb8, 0xde, 0x16, 0x25, + 0x0f, 0x0e, 0xe5, 0xcd, 0xf1, 0x1e, 0x29, 0xe1, 0xfb, 0x2b, 0xb6, 0xe4, 0x02, + 0x00, 0xe3, 0x29, 0xe1, 0xda, 0x4d, 0xf2, 0xf7, 0x03, 0xc3, 0xed, 0xc8, 0x28, + 0xf8, 0xdd, 0xfe, 0x45, 0xf2, 0xb0, 0xe7, 0x31, 0xd0, 0xf7, 0xf5, 0xdd, 0x2e, + 0x18, 0xc7, 0x03, 0xeb, 0xbb, 0xd4, 0xb9, 0x2c, 0xd6, 0xef, 0xea, 0x29, 0xf2, + 0xfb, 0x0f, 0xa6, 0xcd, 0x32, 0xe9, 0xf5, 0xed, 0x2c, 0xe3, 0xe6, 0x10, 0xb0, + 0xd0, 0x49, 0xef, 0xfb, 0xab, 0xeb, 0xf7, 0xfd, 0x31, 0xef, 0xdf, 0xec, 0x08, + 0xd9, 0x35, 0x81, 0xc6, 0x24, 0xf0, 0x5a, 0xb0, 0x30, 0x3d, 0xe9, 0xbc, 0xdc, + 0xd8, 0x1b, 0xf2, 0xcc, 0x1c, 0xaf, 0x98, 0x09, 0xac, 0x38, 0xda, 0x05, 0x0a, + 0x3b, 0xcf, 0x28, 0xff, 0x35, 0xdc, 0x07, 0x20, 0x27, 0x57, 0xe3, 0xc4, 0x08, + 0x16, 0x0d, 0x30, 0x81, 0xab, 0x15, 0xe1, 0x10, 0x27, 0xa8, 0xd1, 0xcd, 0x42, + 0x0a, 0xf0, 0xed, 0x0d, 0x08, 0xc7, 0x30, 0xe3, 0x38, 0x0b, 0x24, 0xe6, 0x26, + 0x30, 0x59, 0x1b, 0xac, 0xf4, 0xc6, 0xb0, 0xdd, 0x52, 0x15, 0xb3, 0x2f, 0x8b, + 0x0a, 0xb8, 0xc2, 0x53, 0x1f, 0xae, 0x05, 0xf7, 0x45, 0x9e, 0xb9, 0xb4, 0x2d, + 0xe0, 0x10, 0xe3, 0x07, 0x1e, 0xef, 0xd1, 0x39, 0x9b, 0x34, 0xe6, 0x17, 0x5c, + 0xec, 0xc4, 0xe4, 0xf8, 0x42, 0xf9, 0xdd, 0x2a, 0x10, 0xb8, 0xa4, 0x24, 0xf8, + 0x00, 0x53, 0xd0, 0x0e, 0xdc, 0x9b, 0x26, 0x7d, 0xfa, 0x1f, 0x3d, 0xe7, 0xeb, + 0xc5, 0xf1, 0xc3, 0x0d, 0xeb, 0xc6, 0x27, 0x11, 0x4b, 0xd0, 0x13, 0xf3, 0xc5, + 0x05, 0x35, 0x2f, 0x06, 0xcc, 0xb9, 0x2a, 0xc4, 0x24, 0xef, 0x39, 0xf7, 0xa9, + 0xcf, 0xdf, 0xb0, 0xfd, 0xa3, 0x16, 0x23, 0x16, 0x00, 0xe5, 0xbd, 0xc8, 0xed, + 0xdf, 0x84, 0x03, 0xc2, 0x03, 0x27, 0xee, 0xf5, 0xf0, 0xde, 0x2a, 0x16, 0x01, + 0xba, 0xd6, 0xe0, 0x08, 0xf6, 0x10, 0xd0, 0x13, 0xeb, 0x31, 0x17, 0x2b, 0xc1, + 0x20, 0xfa, 0xeb, 0xf1, 0x21, 0x11, 0xe4, 0xc4, 0xf8, 0xfd, 0xf3, 0x46, 0x25, + 0x17, 0xfd, 0xe0, 0xfb, 0x00, 0xd9, 0xdb, 0xa4, 0xdc, 0x02, 0xae, 0xfa, 0xe0, + 0xd8, 0xe2, 0xf0, 0x11, 0xf2, 0x1d, 0x2f, 0x44, 0x0d, 0x28, 0x14, 0xb4, 0x06, + 0xe0, 0xe2, 0x36, 0x41, 0xf0, 0xc9, 0xf5, 0xd5, 0x47, 0x54, 0xda, 0xdd, 0x8a, + 0x04, 0xed, 0xae, 0x08, 0x64, 0xba, 0x60, 0xfc, 0x11, 0xe2, 0x05, 0x01, 0x6b, + 0x07, 0xf5, 0xc9, 0x14, 0xd5, 0xfd, 0x18, 0xf0, 0x2f, 0x06, 0xf9, 0x19, 0xf2, + 0x2c, 0x52, 0xa9, 0x76, 0xe0, 0xd4, 0xae, 0xc2, 0xdb, 0xd4, 0xef, 0xb9, 0xee, + 0x44, 0x1c, 0x13, 0xf2, 0xdc, 0xfb, 0xfc, 0xb2, 0xed, 0xed, 0xf4, 0x0a, 0xbd, + 0xee, 0xfa, 0xdd, 0xf6, 0xec, 0xfb, 0xda, 0xb2, 0xf9, 0x0e, 0xf1, 0x2c, 0x1d, + 0x08, 0xde, 0xcd, 0xf0, 0x0d, 0x0a, 0xfe, 0xbc, 0xdd, 0xfa, 0x30, 0x18, 0xd7, + 0x08, 0xcc, 0xd3, 0xf7, 0x03, 0x09, 0x15, 0x00, 0xfe, 0x0e, 0xd0, 0xed, 0x35, + 0x0c, 0xb6, 0xf3, 0xbb, 0x3d, 0xec, 0xf5, 0x23, 0xfe, 0x26, 0x5c, 0xed, 0x06, + 0xd1, 0xaf, 0xe7, 0x21, 0x37, 0xde, 0xd9, 0x28, 0x7f, 0x0d, 0x17, 0x16, 0x13, + 0xa0, 0xfc, 0xf2, 0xd5, 0x26, 0xbb, 0xdc, 0x19, 0x1d, 0x3f, 0x43, 0xd7, 0xed, + 0xfa, 0xcd, 0x0f, 0x94, 0x22, 0xfd, 0x1c, 0xfd, 0xe2, 0xf6, 0xde, 0x03, 0x04, + 0x20, 0xcd, 0xc7, 0x9d, 0x29, 0x0b, 0xf5, 0xec, 0xfc, 0x48, 0xfb, 0x70, 0xef, + 0xbc, 0xd8, 0x13, 0xc8, 0x48, 0xfc, 0xdf, 0x31, 0xeb, 0x42, 0xcd, 0xee, 0xcf, + 0x28, 0x1f, 0xf7, 0xaa, 0x0f, 0xd6, 0xd9, 0xd0, 0xfa, 0xda, 0xb7, 0xfc, 0x01, + 0xbb, 0x22, 0xe5, 0xe2, 0x1e, 0xf0, 0x00, 0x0d, 0x06, 0xc9, 0xd7, 0xea, 0xef, + 0x20, 0x02, 0xbd, 0x0e, 0xec, 0x19, 0xed, 0x12, 0xff, 0xdb, 0x00, 0x40, 0xed, + 0xec, 0xb7, 0xd5, 0xd5, 0x02, 0xd2, 0xdc, 0x17, 0xcb, 0x0c, 0xed, 0xe7, 0x01, + 0x0c, 0xe0, 0xd5, 0xf0, 0x23, 0xdb, 0xe0, 0xfc, 0x0f, 0xf6, 0x25, 0x21, 0xfd, + 0xf3, 0x45, 0x05, 0x19, 0x10, 0x12, 0xcb, 0xf6, 0x2d, 0x99, 0xdf, 0x36, 0xfd, + 0xb5, 0xee, 0xe3, 0xdf, 0x41, 0xf3, 0x03, 0xea, 0xd0, 0x03, 0xdb, 0x20, 0x1f, + 0x30, 0xf8, 0x3b, 0x15, 0x08, 0xc0, 0xe1, 0xff, 0xf2, 0xf0, 0x0b, 0xf0, 0x19, + 0x71, 0x0d, 0xe8, 0xcb, 0xd2, 0xf1, 0x27, 0xed, 0xeb, 0x12, 0xd6, 0xfd, 0x5a, + 0xf4, 0x37, 0x17, 0xd6, 0xb9, 0x23, 0xdc, 0x02, 0xad, 0x0d, 0xf7, 0xcb, 0xc4, + 0xb8, 0x3e, 0x15, 0xf8, 0xec, 0xfd, 0x06, 0xd1, 0xa0, 0xe0, 0x4c, 0x34, 0xef, + 0xb7, 0xef, 0xdc, 0x27, 0xbd, 0x01, 0xc3, 0x3e, 0xf1, 0xda, 0xd7, 0xa1, 0xde, + 0xfe, 0x39, 0xee, 0xaa, 0x09, 0xdd, 0xf4, 0xc8, 0x00, 0xaa, 0xc7, 0xc3, 0x19, + 0x08, 0x33, 0xf0, 0xe5, 0x24, 0x3b, 0x14, 0xf1, 0xc2, 0xcc, 0xcd, 0xea, 0xe0, + 0x44, 0xdd, 0xca, 0xbd, 0xf3, 0xd1, 0x01, 0xfe, 0x45, 0x26, 0x0c, 0xe3, 0x10, + 0x2d, 0x0e, 0x24, 0xd0, 0xd7, 0x32, 0xcf, 0x25, 0xf3, 0x2b, 0xe1, 0x04, 0xfe, + 0xf7, 0x2b, 0xdb, 0x02, 0x37, 0x11, 0xce, 0xcb, 0x39, 0x12, 0xbc, 0xf1, 0x0d, + 0x1e, 0xf8, 0x04, 0x49, 0x00, 0xd7, 0xe3, 0xd6, 0xf8, 0xe5, 0xf2, 0x38, 0x16, + 0x11, 0xde, 0xd4, 0xee, 0x29, 0xee, 0x14, 0x1a, 0xfc, 0x1f, 0xc2, 0xfc, 0x51, + 0xaf, 0xe2, 0x1f, 0xbf, 0xf5, 0xdf, 0x23, 0xcd, 0xc7, 0x05, 0xce, 0xd3, 0xf8, + 0x0e, 0xfa, 0x56, 0xef, 0xcf, 0x4d, 0xfb, 0xa6, 0xd2, 0x08, 0xe2, 0xe6, 0xde, + 0x2c, 0xe8, 0xc7, 0x27, 0xa8, 0xf1, 0xd2, 0xe6, 0x15, 0x0d, 0xf9, 0xfc, 0xd8, + 0x49, 0x2c, 0x2a, 0xd5, 0x0d, 0xf6, 0x13, 0x1c, 0x14, 0xe3, 0x15, 0x0a, 0x06, + 0xf1, 0x2e, 0x08, 0xfd, 0x2b, 0xf2, 0x81, 0x02, 0xcd, 0x3e, 0xd5, 0xe3, 0xb0, + 0xd3, 0x22, 0x13, 0x09, 0xd5, 0xc8, 0x25, 0xe0, 0x20, 0x21, 0xde, 0xf8, 0xf1, + 0xc1, 0x0b, 0xf8, 0xbd, 0xd7, 0x0b, 0x2e, 0xeb, 0xe5, 0xeb, 0xa5, 0xee, 0x01, + 0x17, 0xe7, 0xe7, 0xbd, 0xcf, 0xdd, 0xff, 0x19, 0xea, 0xec, 0xe7, 0xf3, 0x35, + 0xd0, 0x11, 0xb8, 0xae, 0x19, 0xef, 0x4e, 0xd7, 0xaf, 0xde, 0xf9, 0xa7, 0x14, + 0xf3, 0xed, 0xe8, 0x14, 0xeb, 0xd1, 0xad, 0xce, 0xff, 0xd3, 0xff, 0x2d, 0x56, + 0xbe, 0xee, 0xba, 0xc1, 0xae, 0x44, 0xe9, 0xe5, 0xc0, 0x21, 0xf2, 0xc6, 0xf7, + 0xce, 0x02, 0xfb, 0xa6, 0x47, 0x1f, 0x30, 0x05, 0x03, 0xf6, 0xd9, 0xdf, 0xc0, + 0xdb, 0x11, 0xf3, 0xa8, 0xd9, 0x12, 0xcc, 0x93, 0xe3, 0x37, 0xff, 0xd1, 0xe0, + 0xeb, 0xdf, 0xdb, 0x11, 0xcf, 0xdf, 0x36, 0xe9, 0xb7, 0x00, 0xf7, 0x1b, 0xad, + 0xd6, 0xe6, 0x24, 0x31, 0x19, 0x06, 0x03, 0xcd, 0xe7, 0x01, 0x19, 0xf6, 0xf9, + 0xf9, 0x2b, 0xfc, 0xed, 0x18, 0xb6, 0x5a, 0xe3, 0x0c, 0xd8, 0x07, 0x32, 0x15, + 0x1b, 0xf5, 0xc1, 0xe0, 0x37, 0xcd, 0x25, 0xd2, 0xcb, 0x43, 0x4d, 0xd6, 0x0f, + 0x17, 0xcc, 0xe4, 0x1f, 0xcd, 0x9a, 0x3e, 0x1b, 0x0a, 0x30, 0xed, 0xcd, 0x2a, + 0x44, 0xc7, 0xfa, 0xf9, 0x0f, 0xd0, 0xe3, 0xf5, 0x8b, 0xf6, 0xa7, 0xc4, 0x9f, + 0xdf, 0xe4, 0x12, 0x22, 0xd2, 0x26, 0x12, 0xfa, 0x19, 0xdc, 0xb9, 0x1b, 0x2b, + 0x09, 0x09, 0x57, 0x93, 0x95, 0x02, 0xea, 0xef, 0x16, 0xf3, 0x3e, 0x04, 0xf1, + 0xe3, 0xf2, 0x32, 0xc4, 0x43, 0x29, 0xd1, 0x33, 0xfa, 0xcd, 0x05, 0x4d, 0x24, + 0xe0, 0xd1, 0x1e, 0x28, 0x14, 0x50, 0xfb, 0x1e, 0x0e, 0xe7, 0x09, 0xc4, 0x0c, + 0xed, 0x08, 0x09, 0xbc, 0xf7, 0xe4, 0x00, 0xf4, 0xeb, 0x0e, 0x08, 0xf2, 0xfd, + 0x05, 0x07, 0x19, 0xba, 0x3e, 0xcc, 0xcb, 0x40, 0xea, 0x01, 0xf4, 0xb8, 0xee, + 0x21, 0xa5, 0xf6, 0x25, 0xf8, 0xe0, 0xeb, 0xe9, 0x34, 0xf3, 0x0f, 0xb2, 0x1e, + 0xca, 0xf1, 0xb1, 0xd4, 0xed, 0x04, 0x1c, 0xff, 0xe0, 0x2f, 0xa0, 0xe4, 0x03, + 0xa0, 0xf3, 0xd8, 0xf3, 0xfe, 0x23, 0xcf, 0xe7, 0x1a, 0x07, 0x0a, 0xdb, 0x81, + 0x75, 0x3f, 0xf1, 0x3f, 0x00, 0x0d, 0x0e, 0xaf, 0xf7, 0x2e, 0xfc, 0x01, 0x01, + 0xe5, 0x30, 0x21, 0xfd, 0xd3, 0xd8, 0xf0, 0xfc, 0x27, 0x00, 0x04, 0xfc, 0x3b, + 0xef, 0x10, 0xe8, 0x16, 0xfd, 0x15, 0xef, 0x07, 0x03, 0x06, 0x18, 0xe2, 0xd4, + 0xf1, 0x2d, 0x0f, 0xe1, 0xd6, 0xc2, 0xeb, 0xf7, 0xae, 0xcd, 0xfa, 0xf1, 0x11, + 0xed, 0x00, 0xf3, 0xd2, 0xe0, 0xf8, 0xbe, 0x00, 0x15, 0x23, 0x03, 0x1d, 0xbb, + 0xeb, 0x03, 0x05, 0x12, 0x26, 0x0e, 0xdc, 0xef, 0xce, 0xe4, 0xe3, 0x06, 0xef, + 0x35, 0x3c, 0x11, 0xeb, 0xfc, 0x0c, 0xf9, 0xde, 0xec, 0x3f, 0xf2, 0x1a, 0xc1, + 0xed, 0x06, 0x2d, 0xef, 0xc8, 0xe2, 0xf3, 0xb4, 0xf6, 0x23, 0x03, 0xdd, 0xd0, + 0x28, 0x10, 0xca, 0xed, 0xe9, 0x1d, 0x0a, 0xed, 0xd9, 0xfe, 0xd7, 0xe6, 0x21, + 0x02, 0xca, 0xda, 0xe2, 0xed, 0x07, 0x3a, 0xf5, 0xd3, 0xe7, 0xd9, 0xed, 0xcf, + 0xca, 0x0b, 0x07, 0xee, 0xfe, 0xe6, 0xf2, 0xff, 0xfb, 0x08, 0x0b, 0xe9, 0xf2, + 0xf5, 0xda, 0x02, 0xce, 0x33, 0xf4, 0xd1, 0xd7, 0xe1, 0x1b, 0x43, 0xfb, 0xfd, + 0xb3, 0xec, 0x19, 0xe5, 0xe1, 0xfc, 0x02, 0xf4, 0x1a, 0xbb, 0x28, 0x06, 0xcc, + 0x41, 0x22, 0xd2, 0xf5, 0xf4, 0x0a, 0x02, 0x7f, 0x16, 0xb8, 0xbd, 0xe6, 0xea, + 0xf0, 0x0e, 0xf5, 0xf8, 0x01, 0xc0, 0x15, 0xd1, 0xfb, 0xd3, 0xed, 0x13, 0xce, + 0xd2, 0xe8, 0x07, 0xf6, 0x00, 0x2c, 0xe3, 0x09, 0xf6, 0xf4, 0x09, 0x11, 0x1e, + 0x0d, 0x09, 0x35, 0xf5, 0x18, 0x13, 0xd2, 0xc0, 0xd4, 0x0e, 0xf1, 0x00, 0x17, + 0x2d, 0xce, 0xf2, 0x37, 0x33, 0xfe, 0x0f, 0x99, 0xe5, 0xe9, 0x10, 0xd6, 0x05, + 0xf9, 0xd5, 0xd8, 0xc6, 0xce, 0x07, 0xd1, 0xbc, 0x15, 0xf9, 0x0c, 0x1c, 0x2a, + 0xf1, 0x3d, 0xb9, 0x12, 0x76, 0xba, 0xf4, 0xe8, 0x27, 0x19, 0x1d, 0xf4, 0x15, + 0x37, 0x10, 0x06, 0xf3, 0xc3, 0x06, 0xfb, 0x39, 0xdb, 0xee, 0x11, 0xeb, 0x18, + 0xf9, 0xe4, 0xe7, 0x55, 0xec, 0xff, 0xd4, 0x14, 0xe4, 0xd3, 0xfa, 0xea, 0xdf, + 0x0d, 0xbd, 0xe4, 0xf2, 0x3b, 0x00, 0x06, 0xc7, 0x33, 0xbc, 0xde, 0xf8, 0xe6, + 0x01, 0xe6, 0xd7, 0xd7, 0xd8, 0x3c, 0xd7, 0xf8, 0xd0, 0xd5, 0xe7, 0xf3, 0xfe, + 0x16, 0xfc, 0xfa, 0xf4, 0x02, 0xd3, 0xfd, 0x37, 0x04, 0xc2, 0x0d, 0xde, 0xed, + 0x11, 0x24, 0x0d, 0x1c, 0xf7, 0x01, 0xfd, 0xed, 0xda, 0xd6, 0x3a, 0xb1, 0xda, + 0x04, 0xf9, 0xeb, 0xd8, 0xf0, 0xe5, 0x00, 0xe4, 0x0a, 0x3b, 0x05, 0xdc, 0xc9, + 0x40, 0xae, 0xdf, 0x12, 0x04, 0x52, 0xf8, 0x3c, 0x29, 0xfe, 0xe3, 0x28, 0xff, + 0x03, 0x10, 0xe4, 0x0e, 0x14, 0xec, 0x0c, 0xd0, 0xc5, 0x09, 0xfe, 0xb9, 0xf8, + 0xf6, 0x19, 0xdf, 0x29, 0x0d, 0xf4, 0x31, 0xf0, 0xfa, 0x32, 0x0e, 0xd0, 0xd4, + 0xf6, 0xfb, 0xf3, 0x2a, 0x08, 0xfe, 0xc4, 0x0e, 0x32, 0xc7, 0xd4, 0xf3, 0x0a, + 0xdc, 0xf6, 0xec, 0x10, 0x7f, 0xfa, 0x11, 0xd2, 0xe0, 0x3f, 0x1b, 0xb4, 0x2b, + 0x01, 0xd5, 0xeb, 0xe1, 0xef, 0x0c, 0xc1, 0xd0, 0xd3, 0xfe, 0xe8, 0xee, 0x29, + 0x11, 0x05, 0xe0, 0x17, 0xc7, 0xf0, 0xe3, 0xe9, 0xd6, 0x05, 0xeb, 0xeb, 0xa2, + 0xdc, 0xfd, 0x04, 0x18, 0x03, 0xe8, 0xd1, 0x3a, 0xd0, 0x08, 0xea, 0x11, 0x1b, + 0x1e, 0x1c, 0x23, 0xf2, 0xf5, 0x00, 0xf2, 0x1d, 0xf0, 0x01, 0xf5, 0xf0, 0xe2, + 0xfe, 0xfc, 0xf7, 0x0b, 0x03, 0xf3, 0x28, 0x04, 0xfc, 0xb4, 0xf6, 0xf5, 0x1f, + 0xe3, 0xd9, 0x23, 0x11, 0xb0, 0xe3, 0xe8, 0xe0, 0xe3, 0x0e, 0x23, 0xf0, 0x07, + 0x08, 0xc8, 0x0b, 0x1c, 0xe1, 0xd8, 0x0f, 0x1d, 0xf1, 0xf0, 0x24, 0xdb, 0x4d, + 0x06, 0x1e, 0x1e, 0xd5, 0x0d, 0x01, 0x0b, 0x03, 0xff, 0xc7, 0xf9, 0x25, 0x04, + 0xd5, 0x20, 0x0c, 0x0c, 0xee, 0x26, 0xfc, 0x23, 0x11, 0xfc, 0xd3, 0x06, 0x3c, + 0xc4, 0xaf, 0xed, 0xd5, 0xfc, 0xe7, 0x2e, 0xea, 0xf1, 0xf9, 0xfb, 0x03, 0x30, + 0xfb, 0xe4, 0xf7, 0xe3, 0x0e, 0xfd, 0xe0, 0xf9, 0x07, 0xf7, 0xcc, 0xfc, 0xe3, + 0xe6, 0xd4, 0xe8, 0x1c, 0xff, 0xb3, 0x28, 0xf5, 0xe6, 0xfc, 0x08, 0xd8, 0xe2, + 0x0c, 0x0c, 0x4c, 0x10, 0x19, 0x0a, 0xc7, 0x12, 0x14, 0x04, 0x22, 0x0d, 0xdb, + 0xe0, 0xe5, 0x26, 0xe5, 0x0e, 0x1b, 0xed, 0x16, 0xc3, 0xd1, 0x7f, 0x07, 0xc1, + 0x02, 0x0c, 0x13, 0x2d, 0x11, 0xcc, 0x15, 0xf3, 0x02, 0xed, 0xc4, 0x10, 0xce, + 0xc8, 0x1a, 0xeb, 0xf7, 0x19, 0x25, 0xe5, 0x12, 0x20, 0xfe, 0x22, 0xfa, 0xb5, + 0xd6, 0xed, 0x1b, 0x0b, 0xd7, 0xfb, 0xb1, 0xdc, 0xff, 0xef, 0x40, 0x2f, 0xf9, + 0xf0, 0xd1, 0xd7, 0xe6, 0xe9, 0xf6, 0xe1, 0xeb, 0xe2, 0xea, 0xf0, 0xe0, 0xce, + 0xbf, 0x0d, 0xdd, 0xd2, 0x07, 0x09, 0xd0, 0xa1, 0x18, 0x11, 0xdf, 0x0f, 0xcc, + 0x2f, 0xe1, 0x3e, 0xf2, 0xfe, 0xbd, 0x05, 0x00, 0xbc, 0xba, 0xb9, 0xf4, 0x03, + 0xd4, 0xc6, 0x01, 0xfa, 0xfb, 0x27, 0xfd, 0xef, 0x25, 0xe2, 0x03, 0xf7, 0x30, + 0x06, 0xc4, 0x94, 0xf7, 0xe2, 0x0c, 0xeb, 0xd9, 0xf5, 0x14, 0xc6, 0x0b, 0xff, + 0x0b, 0x2b, 0xf3, 0x11, 0x24, 0xe5, 0xd8, 0xf6, 0x04, 0x2d, 0x19, 0x1a, 0x0e, + 0x18, 0xcd, 0xf8, 0x11, 0x0f, 0x08, 0x2e, 0xdb, 0xe1, 0x3d, 0x05, 0xbd, 0xde, + 0x13, 0xf4, 0xd4, 0x0e, 0xd6, 0xe1, 0xcd, 0xfd, 0xde, 0x3a, 0xd0, 0x34, 0xf2, + 0xe1, 0xd8, 0x34, 0xc4, 0xdd, 0x11, 0xd2, 0xff, 0xda, 0xf6, 0xec, 0xd1, 0xbd, + 0xe4, 0xdd, 0xfc, 0x22, 0x13, 0x1f, 0x38, 0xd0, 0x24, 0x0f, 0xfe, 0x1a, 0xdf, + 0xde, 0x2b, 0x35, 0xe8, 0x34, 0x1e, 0x13, 0xf2, 0xfb, 0xac, 0xf1, 0xe6, 0x3d, + 0xe7, 0x20, 0xf6, 0x14, 0x0f, 0xe8, 0xfe, 0x26, 0x21, 0xf2, 0xc9, 0x20, 0xc4, + 0x2f, 0xc4, 0x33, 0xc9, 0xed, 0xfa, 0xcf, 0x10, 0xe1, 0xd0, 0xa9, 0xcd, 0xe1, + 0xfb, 0xf3, 0xfc, 0x4e, 0xcc, 0x2f, 0x19, 0x10, 0x84, 0x18, 0xdf, 0x44, 0x19, + 0xf7, 0xb5, 0xc7, 0xdb, 0xca, 0xef, 0x0d, 0x08, 0xf7, 0x81, 0xb1, 0xef, 0xd4, + 0x3c, 0xab, 0xc6, 0xbc, 0xef, 0xfd, 0x0c, 0x1e, 0xd6, 0x0a, 0xfa, 0x4f, 0x09, + 0xec, 0x39, 0x2c, 0x25, 0xe0, 0xca, 0xf2, 0xff, 0xd1, 0xf8, 0xf7, 0x2e, 0xfd, + 0x13, 0x14, 0x09, 0xef, 0x04, 0x01, 0xa9, 0x39, 0x1b, 0xd1, 0x14, 0xdb, 0xc2, + 0x08, 0x01, 0x40, 0xd3, 0xff, 0x2b, 0x09, 0xb2, 0xeb, 0x03, 0x01, 0x0c, 0x2b, + 0x25, 0xf3, 0xe1, 0xe5, 0xe2, 0x71, 0xf0, 0xfc, 0x0d, 0x04, 0xe7, 0xaf, 0x11, + 0xb7, 0x16, 0xf0, 0xf1, 0x40, 0xaf, 0xe5, 0xf0, 0x0d, 0xf7, 0xd3, 0xff, 0x2b, + 0xa6, 0x2c, 0xc8, 0x1b, 0xff, 0xb5, 0x03, 0xe1, 0x10, 0xd2, 0xf8, 0x00, 0x15, + 0xe0, 0xfd, 0xed, 0x5a, 0xeb, 0x16, 0xed, 0x0b, 0xc2, 0xf6, 0x03, 0x0a, 0xf1, + 0xd5, 0x01, 0x24, 0x0e, 0xbe, 0xfa, 0xf1, 0x01, 0x02, 0x28, 0x19, 0xee, 0x1d, + 0x15, 0x0e, 0xf2, 0x12, 0xa8, 0x01, 0xee, 0xff, 0x34, 0x11, 0xf0, 0x2f, 0x27, + 0xee, 0xf6, 0xeb, 0xfb, 0x09, 0xcb, 0x21, 0x1c, 0x2b, 0x29, 0x10, 0x1e, 0x06, + 0x07, 0x20, 0x3c, 0xfa, 0xd9, 0xb6, 0x04, 0x42, 0x30, 0xdd, 0x2d, 0xe8, 0xf6, + 0xcd, 0xfb, 0x0a, 0x1d, 0xf2, 0x5f, 0xe6, 0x05, 0x2c, 0x0d, 0xdc, 0x28, 0xec, + 0xe6, 0x08, 0xf9, 0x28, 0xca, 0x1b, 0x0e, 0xdd, 0x12, 0xc1, 0xdf, 0x06, 0xe8, + 0xeb, 0x3e, 0x25, 0xea, 0xf7, 0xbd, 0xf5, 0xdb, 0xdf, 0xdc, 0x4a, 0x27, 0xff, + 0xff, 0x08, 0x19, 0x90, 0x1c, 0xe5, 0x3d, 0xe6, 0xf8, 0xf8, 0xcc, 0x0e, 0xd7, + 0xf3, 0x1e, 0xd7, 0xae, 0xd1, 0x14, 0xd2, 0xfa, 0xa2, 0xe6, 0x25, 0x41, 0x39, + 0xff, 0x17, 0xef, 0x0e, 0x19, 0xac, 0x11, 0xd1, 0x08, 0x08, 0xc5, 0xf3, 0x27, + 0xbb, 0xfd, 0xe9, 0xd5, 0x8e, 0xdf, 0x15, 0xcf, 0xe0, 0xd9, 0xfd, 0x10, 0xe6, + 0x28, 0xee, 0x1a, 0xe9, 0xed, 0x81, 0xca, 0x0d, 0xba, 0x0a, 0xc4, 0xd5, 0xe4, + 0xe9, 0xd0, 0xdc, 0xf7, 0xa9, 0xe7, 0xbc, 0x40, 0x0b, 0x09, 0xe4, 0xf6, 0xb2, + 0x12, 0xf0, 0x69, 0x44, 0x06, 0xef, 0x11, 0x16, 0x54, 0x2f, 0xe8, 0xb4, 0x9d, + 0x25, 0xdb, 0x0e, 0x0f, 0xee, 0x17, 0x18, 0x14, 0xbc, 0xfc, 0x0b, 0x27, 0xd5, + 0xef, 0xbb, 0x19, 0xd9, 0x01, 0x07, 0xf4, 0x13, 0x45, 0xb3, 0x0d, 0x0b, 0xb2, + 0xbb, 0x25, 0x0a, 0x25, 0x00, 0xe2, 0x13, 0xfb, 0xff, 0xb8, 0xe4, 0xf5, 0xdd, + 0xbb, 0xff, 0x3a, 0xcb, 0xd6, 0xf5, 0x09, 0x41, 0x10, 0xd5, 0xef, 0xca, 0xf2, + 0x31, 0x90, 0x0e, 0x28, 0xed, 0x00, 0xd8, 0x3f, 0xc5, 0xe5, 0xf8, 0x42, 0x3a, + 0x30, 0x2a, 0xee, 0xff, 0xd0, 0x2f, 0x0d, 0xb1, 0xe2, 0x07, 0xe3, 0x3a, 0xdb, + 0xa2, 0xe7, 0x3d, 0xf5, 0xcf, 0xf7, 0xec, 0x08, 0x3d, 0x29, 0x0d, 0x04, 0xe8, + 0x8a, 0xe8, 0xd4, 0x40, 0xdc, 0xf6, 0xeb, 0xc9, 0xd0, 0xdf, 0xeb, 0xec, 0xf9, + 0xff, 0xcb, 0x43, 0xef, 0xe3, 0x25, 0x03, 0x19, 0x01, 0x01, 0xd3, 0x21, 0x36, + 0x1f, 0x2d, 0x08, 0x2d, 0xce, 0xff, 0xf3, 0xe3, 0x08, 0xeb, 0xf1, 0x02, 0x35, + 0x19, 0x62, 0x26, 0xd6, 0xd3, 0x18, 0x37, 0xd9, 0xc5, 0x36, 0x32, 0xf1, 0xb8, + 0x59, 0xe3, 0x48, 0xf7, 0xdf, 0xd6, 0xea, 0xd4, 0x30, 0xfb, 0x33, 0x5f, 0xbc, + 0xc1, 0xf6, 0xe5, 0xb5, 0x31, 0x02, 0x1f, 0x24, 0xee, 0xe8, 0xe5, 0x6a, 0x9b, + 0x02, 0xdd, 0x2f, 0xf5, 0x21, 0x2d, 0x1e, 0xc9, 0x2c, 0x15, 0x08, 0xc5, 0xbe, + 0xd5, 0x2d, 0xfc, 0xe3, 0x8b, 0x13, 0xd0, 0xee, 0x0d, 0x1e, 0x66, 0xec, 0x10, + 0xe8, 0x1e, 0x2e, 0xeb, 0xdd, 0x45, 0xca, 0xc1, 0xfe, 0xcc, 0xfe, 0xb7, 0xbd, + 0xc9, 0xc3, 0x1f, 0xc2, 0xb1, 0x14, 0xae, 0x31, 0xe1, 0xd1, 0x30, 0x07, 0xf3, + 0xa8, 0x3e, 0x93, 0x45, 0x2c, 0xed, 0x8f, 0xd1, 0xb8, 0xd0, 0x1a, 0x27, 0xc4, + 0xa3, 0xdd, 0x0d, 0x7f, 0x2b, 0x07, 0xde, 0xf9, 0x3b, 0x2f, 0xc2, 0xfd, 0xa0, + 0xcb, 0xbb, 0x3a, 0xf7, 0xe7, 0xe0, 0x03, 0x04, 0x06, 0xbc, 0xbc, 0xbf, 0x11, + 0x05, 0xda, 0xd6, 0x4e, 0xb7, 0x35, 0xd2, 0x68, 0x1b, 0x39, 0xe1, 0xd0, 0x0d, + 0x11, 0x26, 0xcf, 0xeb, 0xef, 0xc7, 0xfd, 0x19, 0xdf, 0xca, 0x43, 0xd1, 0xa5, + 0x2c, 0x55, 0x0b, 0x17, 0x31, 0xd7, 0xc9, 0xe7, 0xf3, 0xe2, 0xfe, 0xc4, 0xdd, + 0x5c, 0xd5, 0xfe, 0xc6, 0xce, 0x5a, 0x06, 0xbc, 0xa7, 0x55, 0xf4, 0xbf, 0xf0, + 0x44, 0x29, 0xe6, 0x2c, 0xd2, 0xa4, 0x27, 0xbb, 0x24, 0xc4, 0xd1, 0xd9, 0xaa, + 0xb7, 0xbc, 0xaf, 0xe1, 0x30, 0xa9, 0x9b, 0x13, 0xf1, 0x54, 0x45, 0x21, 0xe8, + 0x0d, 0xf0, 0xf3, 0xc5, 0x56, 0x01, 0xf4, 0xee, 0xfa, 0x11, 0x0d, 0x1b, 0xb8, + 0xe2, 0xc1, 0xf7, 0xc7, 0xb0, 0xd0, 0x23, 0xfa, 0xec, 0xe2, 0xfb, 0x23, 0xd3, + 0x02, 0x44, 0x2f, 0x4b, 0x95, 0x0c, 0x03, 0x41, 0xed, 0x35, 0x14, 0xfb, 0x45, + 0xd4, 0xf0, 0xf0, 0xf2, 0x13, 0xc5, 0x25, 0xb4, 0xdb, 0x1b, 0xc2, 0xda, 0xf0, + 0x18, 0xd7, 0xdc, 0xcb, 0xac, 0xe2, 0xc8, 0xfe, 0xff, 0x14, 0xee, 0xb4, 0x12, + 0xf0, 0xd8, 0xd3, 0xc6, 0xd2, 0xbd, 0x9f, 0xbb, 0x6b, 0xe9, 0x39, 0xbf, 0x14, + 0xe5, 0xed, 0x0d, 0xcd, 0xfb, 0xee, 0x57, 0x94, 0xbf, 0x0f, 0x0a, 0xcf, 0x00, + 0xf1, 0xdb, 0x0e, 0x2b, 0x05, 0xc0, 0xeb, 0x07, 0xe6, 0x5e, 0x56, 0x11, 0xd9, + 0x29, 0x1a, 0x17, 0x0f, 0x3a, 0x04, 0xb4, 0x22, 0x06, 0xf9, 0x0c, 0xe8, 0x33, + 0xe1, 0x8c, 0x30, 0xf4, 0xcf, 0x50, 0x32, 0xa6, 0xb1, 0x2c, 0xb1, 0x0a, 0xc0, + 0x2f, 0xe4, 0x08, 0xbf, 0xea, 0xff, 0xda, 0xf5, 0x81, 0xc7, 0x0f, 0xeb, 0xe2, + 0x53, 0x56, 0xd8, 0xb2, 0xe0, 0xdf, 0x2d, 0x20, 0xf2, 0xec, 0xf0, 0x22, 0xe6, + 0x3d, 0x0d, 0x2c, 0x34, 0x05, 0x0c, 0x1b, 0xe7, 0x35, 0x25, 0x41, 0x3e, 0xeb, + 0x08, 0x21, 0xc5, 0x22, 0xd8, 0x1a, 0xc0, 0xce, 0x9e, 0x05, 0xc4, 0xf4, 0xa5, + 0x23, 0x40, 0x0f, 0xce, 0xc4, 0xf2, 0x49, 0x01, 0xd8, 0x07, 0x27, 0x36, 0xcf, + 0x15, 0xf7, 0x02, 0xbf, 0x96, 0xe5, 0xd7, 0x17, 0x59, 0x49, 0x1f, 0x97, 0xe7, + 0xdb, 0xd3, 0xea, 0xdb, 0xf7, 0x0a, 0x09, 0x0e, 0xa9, 0xc6, 0x0c, 0xb9, 0xcc, + 0x31, 0xd1, 0xd5, 0xc9, 0x01, 0x6d, 0x2d, 0xc6, 0xed, 0xc3, 0xa5, 0xca, 0xdc, + 0xdd, 0x97, 0xc1, 0xf8, 0x28, 0xc5, 0x06, 0x1b, 0x3b, 0xdd, 0xc0, 0xf3, 0xc4, + 0x2e, 0xf7, 0xf1, 0xeb, 0x20, 0xe8, 0xfe, 0xb6, 0x6b, 0xcf, 0x2c, 0x03, 0xb4, + 0xdb, 0x54, 0x05, 0xe3, 0xae, 0x1b, 0x32, 0xc8, 0x0d, 0xa1, 0x15, 0xdf, 0x32, + 0x29, 0x17, 0xfc, 0xf5, 0x0b, 0x18, 0x2a, 0x1f, 0x13, 0xbe, 0x09, 0xf5, 0xb8, + 0xac, 0xf2, 0x55, 0xd9, 0xbd, 0xca, 0x27, 0x4d, 0xdd, 0xc3, 0x1c, 0xdb, 0x09, + 0xe9, 0xd4, 0x0a, 0xae, 0xf3, 0x61, 0x19, 0xb7, 0xff, 0x00, 0xec, 0xfe, 0xf7, + 0xbe, 0xf8, 0x61, 0xda, 0xf8, 0x27, 0x2c, 0xd4, 0xfc, 0xf5, 0x42, 0xde, 0xdc, + 0x47, 0x65, 0x40, 0xbc, 0xf6, 0xdb, 0xf3, 0xc6, 0xa4, 0x00, 0xea, 0x21, 0x00, + 0x15, 0x48, 0x09, 0xbf, 0x2f, 0xec, 0xd9, 0xb9, 0xde, 0x9e, 0x28, 0xe1, 0xec, + 0x5d, 0xea, 0x27, 0x35, 0xc3, 0x46, 0xfd, 0xef, 0x1d, 0xf2, 0x9c, 0xd4, 0xf0, + 0x04, 0xe1, 0xcf, 0xb5, 0xd8, 0xf9, 0xef, 0xed, 0xf8, 0x21, 0xdc, 0x17, 0xd8, + 0x20, 0xf0, 0xeb, 0xbc, 0x06, 0x0d, 0xe6, 0xe6, 0xc2, 0x0c, 0x03, 0xc8, 0xf6, + 0xcb, 0xc3, 0xf8, 0xfd, 0x14, 0x17, 0xf3, 0x11, 0x13, 0xfe, 0xea, 0xf8, 0xd9, + 0xcd, 0xfa, 0x22, 0xf6, 0x03, 0x25, 0x02, 0x14, 0x20, 0x02, 0xfe, 0xad, 0xe2, + 0x3c, 0x07, 0xfb, 0x40, 0x13, 0xef, 0xea, 0x08, 0x1a, 0x1f, 0x36, 0xe6, 0xe0, + 0xde, 0xf9, 0xfa, 0xcd, 0x04, 0xce, 0x1c, 0xe3, 0xf3, 0x1d, 0x31, 0xdf, 0x15, + 0xe7, 0xfd, 0xcd, 0x03, 0xf2, 0xfb, 0xa8, 0xf4, 0x0b, 0x26, 0xff, 0x23, 0xb5, + 0x9d, 0xee, 0xf6, 0xeb, 0x23, 0xcd, 0xe8, 0xeb, 0xfe, 0x1b, 0xde, 0x00, 0xe0, + 0x28, 0x00, 0xca, 0x22, 0xdf, 0xfa, 0x05, 0xe5, 0x3e, 0xf9, 0xfc, 0x2b, 0xe4, + 0xf5, 0xee, 0xed, 0xdf, 0xb5, 0xd2, 0x00, 0xe0, 0xd6, 0x03, 0xfb, 0xe0, 0xe1, + 0xf7, 0xc2, 0xc2, 0x1b, 0xcd, 0xcd, 0xb8, 0x07, 0xe6, 0x00, 0xf1, 0x02, 0xd2, + 0xea, 0x3b, 0x04, 0x08, 0xba, 0xe2, 0xc1, 0xb9, 0xc0, 0xf8, 0x19, 0x65, 0x2c, + 0xd9, 0xf2, 0xfe, 0xd2, 0xdd, 0xd4, 0x17, 0x2e, 0x2c, 0x0a, 0x59, 0x4c, 0x14, + 0xf3, 0xd7, 0x40, 0xc7, 0x36, 0x3c, 0x01, 0xdd, 0x24, 0xf6, 0x1d, 0xdd, 0x31, + 0xf9, 0xdb, 0xd7, 0xfa, 0xd9, 0xf9, 0xf7, 0xbb, 0x25, 0x1a, 0xea, 0x21, 0xe4, + 0xf3, 0xfb, 0xef, 0x81, 0xf6, 0x55, 0xd7, 0xf4, 0x4d, 0xf2, 0x09, 0x1e, 0x36, + 0xfa, 0xec, 0xdc, 0xdd, 0xe6, 0xe1, 0x11, 0xca, 0x18, 0xe0, 0xff, 0xf0, 0xd0, + 0xe1, 0x12, 0xaa, 0xba, 0x22, 0x34, 0x0c, 0x05, 0x1a, 0x00, 0xd2, 0xec, 0x2b, + 0x37, 0xe8, 0xdd, 0x0b, 0x1f, 0xb9, 0xdd, 0xd3, 0x08, 0x22, 0xd7, 0x4e, 0xeb, + 0x14, 0x26, 0x0e, 0xfc, 0xdc, 0xe7, 0x2b, 0xf2, 0x3c, 0x12, 0xdd, 0xf9, 0xe9, + 0xf7, 0xdb, 0xff, 0xee, 0xda, 0xe5, 0x15, 0xe7, 0xe4, 0xdf, 0x0f, 0x0a, 0x1b, + 0xf2, 0x04, 0x04, 0xfa, 0x0d, 0xeb, 0xe7, 0xd2, 0x31, 0xfa, 0xf1, 0xca, 0x15, + 0xf7, 0xf8, 0xf2, 0xf4, 0x19, 0x10, 0x38, 0xef, 0x14, 0xf4, 0xe6, 0x10, 0x04, + 0xeb, 0x10, 0xdc, 0xfb, 0x07, 0xf1, 0x0f, 0xd7, 0xf4, 0xeb, 0xfd, 0x02, 0x7f, + 0x26, 0xe8, 0xf3, 0xcf, 0x21, 0x0d, 0xf9, 0xeb, 0xe4, 0xd5, 0x14, 0xda, 0xe0, + 0xe9, 0xf8, 0xcf, 0x04, 0xd1, 0xc8, 0xe4, 0xe5, 0x29, 0x5c, 0xcc, 0x19, 0xf9, + 0xe0, 0x0d, 0x09, 0x04, 0x2e, 0x0b, 0x04, 0xfd, 0xda, 0x09, 0xf0, 0xcd, 0x1f, + 0xd7, 0xdb, 0x05, 0x1d, 0xe0, 0x0f, 0x02, 0x04, 0xf7, 0xee, 0xde, 0xd5, 0x0f, + 0x05, 0xeb, 0xe1, 0xed, 0x13, 0xdc, 0x10, 0xe9, 0x14, 0xd1, 0xf8, 0xfe, 0xed, + 0xf3, 0xec, 0xfb, 0xfd, 0xd6, 0x19, 0x21, 0x04, 0xfc, 0xe2, 0xf2, 0xeb, 0xd0, + 0xf9, 0x23, 0x02, 0x38, 0x05, 0x0d, 0xfe, 0xf6, 0xde, 0xca, 0xc3, 0x28, 0x0a, + 0xfa, 0xed, 0x07, 0xdb, 0xf3, 0x12, 0x30, 0x2a, 0xf9, 0xe1, 0xe6, 0x09, 0xd5, + 0xff, 0x30, 0x09, 0x3e, 0xfa, 0xfe, 0x2d, 0xf0, 0xf8, 0xfd, 0xda, 0x27, 0xfd, + 0xf1, 0xc7, 0xff, 0xd6, 0xe9, 0x02, 0xf2, 0xfc, 0xfa, 0x08, 0xde, 0xd4, 0x00, + 0xe4, 0xc7, 0x2d, 0xf4, 0x16, 0x05, 0x01, 0xf9, 0xd4, 0x01, 0x07, 0xcd, 0xf0, + 0x32, 0xde, 0xc8, 0xfe, 0x08, 0x16, 0xe2, 0x1e, 0xfd, 0xf6, 0xeb, 0x00, 0x13, + 0x31, 0xfa, 0x08, 0x14, 0xb7, 0x13, 0xff, 0x1b, 0xcf, 0x16, 0x0d, 0xe6, 0x08, + 0xf7, 0xf6, 0xc8, 0x24, 0xdf, 0xf0, 0x0a, 0x01, 0xfc, 0xf3, 0x04, 0xdc, 0xc0, + 0xc3, 0xe8, 0x14, 0x23, 0xd2, 0xe4, 0xe7, 0x08, 0xc6, 0xfe, 0xe8, 0x0d, 0xea, + 0x07, 0x03, 0xdb, 0x03, 0xf4, 0xf9, 0xb8, 0x1d, 0xea, 0x35, 0xc7, 0x41, 0x27, + 0xcf, 0xea, 0xf3, 0xd4, 0xd5, 0x22, 0xd4, 0xe5, 0x07, 0xb6, 0xe7, 0xe6, 0xe9, + 0xd7, 0x04, 0xbd, 0xf7, 0xed, 0xf9, 0xcf, 0x00, 0xc9, 0x18, 0x3b, 0xf5, 0xd5, + 0x43, 0xea, 0x37, 0x02, 0xe4, 0xf8, 0xd2, 0x17, 0x07, 0xfe, 0x0d, 0xe4, 0x0e, + 0xa1, 0xff, 0x3b, 0xf9, 0xf3, 0xdd, 0x2f, 0x1e, 0x7f, 0x00, 0xdd, 0xf1, 0xb5, + 0x17, 0xd3, 0x5b, 0xdd, 0xc9, 0xe5, 0x33, 0x0b, 0xe2, 0x31, 0xa1, 0x09, 0xf5, + 0xb7, 0xf7, 0xd5, 0x9f, 0x4a, 0x3e, 0xd0, 0xd4, 0xe6, 0xb9, 0xef, 0xed, 0xd0, + 0x61, 0xf2, 0x34, 0x2f, 0x0a, 0xff, 0x19, 0xf1, 0x36, 0xc0, 0xf0, 0xce, 0x6c, + 0x08, 0xb9, 0xce, 0xd8, 0xbb, 0x63, 0xe2, 0x20, 0x3f, 0x24, 0xcb, 0xdb, 0xd2, + 0xf9, 0x0a, 0xea, 0xdf, 0x2d, 0xca, 0x13, 0x14, 0xb0, 0xea, 0xff, 0x22, 0xcf, + 0x06, 0x07, 0xf7, 0xef, 0x32, 0xf3, 0x0b, 0x0d, 0xa1, 0x98, 0xfb, 0xd9, 0x29, + 0xec, 0x40, 0x01, 0x20, 0xc8, 0xfe, 0xf1, 0x2b, 0x07, 0xff, 0x06, 0xe6, 0x05, + 0xce, 0x1d, 0x56, 0xe1, 0xe1, 0x00, 0x13, 0xe0, 0xfd, 0x0e, 0xff, 0xfc, 0x51, + 0x0b, 0x25, 0x01, 0xef, 0x39, 0x34, 0x38, 0xe6, 0xf3, 0xdc, 0xf3, 0x42, 0xe3, + 0x13, 0x04, 0x07, 0xef, 0xd1, 0xea, 0xfe, 0xe1, 0xd0, 0xd8, 0xf4, 0x2f, 0xee, + 0xef, 0xeb, 0x14, 0xfe, 0xf2, 0x0d, 0xb1, 0x17, 0x00, 0x24, 0xad, 0xb8, 0xb8, + 0x0f, 0xd9, 0x09, 0xf6, 0xbf, 0x19, 0xf4, 0x0e, 0xf4, 0x2a, 0x1a, 0xfe, 0x22, + 0xf5, 0xfa, 0x3b, 0x22, 0xb9, 0x67, 0x10, 0x10, 0xc4, 0x0b, 0x00, 0xcf, 0x45, + 0xdd, 0xbc, 0x4c, 0xf2, 0x43, 0xb9, 0x07, 0xe2, 0xc9, 0xf9, 0x0b, 0xf0, 0xee, + 0xd4, 0xe0, 0xe7, 0x2b, 0xe2, 0xc6, 0xd8, 0xeb, 0xc7, 0x1d, 0xd9, 0xf9, 0x00, + 0x15, 0xfe, 0xdf, 0x06, 0xd8, 0x04, 0x05, 0xeb, 0x1c, 0xdb, 0xcf, 0x35, 0xe2, + 0x0a, 0xf4, 0xf7, 0x09, 0x13, 0xfd, 0xfe, 0xe0, 0xe9, 0xf8, 0xfd, 0xc0, 0xdd, + 0xf4, 0x1a, 0xff, 0xf1, 0xcf, 0x15, 0x34, 0xf5, 0xea, 0x14, 0x11, 0x04, 0xf9, + 0xeb, 0x0d, 0xe2, 0xc8, 0x0c, 0x09, 0x04, 0xc5, 0xe4, 0xfd, 0x0b, 0x15, 0x2f, + 0xf5, 0x11, 0x18, 0x08, 0x7f, 0x01, 0x05, 0xfc, 0xf9, 0xf9, 0x0d, 0x0b, 0xe1, + 0xd0, 0xef, 0x14, 0x23, 0xf6, 0x0d, 0xba, 0xe8, 0x0f, 0xd8, 0xe3, 0x09, 0xd9, + 0x06, 0x3d, 0x08, 0x05, 0xfa, 0xf7, 0x02, 0xf5, 0xd1, 0x4e, 0xf1, 0x14, 0xfd, + 0xc8, 0xec, 0xe5, 0xf3, 0x15, 0xd2, 0xd8, 0xda, 0x08, 0xeb, 0xe9, 0xdf, 0xdf, + 0xec, 0xf2, 0x09, 0x04, 0x07, 0x1f, 0xec, 0x0c, 0xcf, 0x10, 0x06, 0xf7, 0xfb, + 0xe8, 0xcb, 0xff, 0x15, 0xc3, 0xf4, 0xe6, 0xf3, 0xf5, 0xef, 0xea, 0x0c, 0x19, + 0xe9, 0x1f, 0xed, 0xc9, 0xef, 0xde, 0xec, 0x07, 0x27, 0xd5, 0x08, 0xec, 0xec, + 0xe8, 0xcc, 0xe0, 0xfc, 0xca, 0xf4, 0xc4, 0xf2, 0xdd, 0x13, 0x20, 0x20, 0x2a, + 0xf4, 0xea, 0xfb, 0xe8, 0x19, 0x16, 0xfc, 0xe2, 0x1d, 0xea, 0xfb, 0x35, 0x14, + 0x14, 0xbe, 0x0a, 0x2c, 0x0f, 0xe1, 0xe5, 0xf8, 0xcd, 0xf4, 0x03, 0xff, 0xeb, + 0x09, 0x09, 0xbd, 0xdf, 0xf9, 0xea, 0xf2, 0x0b, 0x06, 0xf1, 0xf8, 0xec, 0xf7, + 0xf3, 0xe5, 0xf3, 0xf6, 0xf8, 0x25, 0xe9, 0xe9, 0xc7, 0x1a, 0x05, 0x05, 0x0e, + 0x0c, 0x05, 0xec, 0x19, 0xfa, 0x28, 0xe2, 0x06, 0x13, 0xe1, 0x18, 0xe9, 0x06, + 0xf9, 0xfe, 0x09, 0x06, 0x00, 0xe9, 0xef, 0xf1, 0xf8, 0xf5, 0xed, 0x2c, 0x15, + 0xef, 0xdd, 0x08, 0xcd, 0xd0, 0xdf, 0xfc, 0xf5, 0xf9, 0xdc, 0xdc, 0xdb, 0xff, + 0xe0, 0x2e, 0xed, 0x02, 0xfb, 0xfd, 0xeb, 0xf5, 0xe3, 0x2d, 0xc6, 0xd6, 0x1b, + 0xe9, 0xfb, 0x16, 0x09, 0x0b, 0xc1, 0xea, 0xe6, 0x09, 0xff, 0xf5, 0xfc, 0x34, + 0xf6, 0x1c, 0xfd, 0x0a, 0x02, 0x04, 0x12, 0xf5, 0x12, 0xe0, 0xf5, 0xc2, 0xf2, + 0xf0, 0x0d, 0x0f, 0xf7, 0xe8, 0xec, 0x2e, 0x34, 0xe2, 0xe1, 0x18, 0xfd, 0xba, + 0x08, 0x14, 0xf2, 0xea, 0x15, 0x1d, 0xda, 0x0c, 0x1a, 0xfe, 0xe6, 0x0b, 0x01, + 0x32, 0x25, 0x22, 0xec, 0xca, 0x11, 0xed, 0x22, 0xde, 0xf9, 0xf8, 0x0f, 0xd1, + 0x03, 0xfc, 0x04, 0xf5, 0x0d, 0xb3, 0xe6, 0x2e, 0xe9, 0xf0, 0x22, 0x15, 0x52, + 0x14, 0xf0, 0xe6, 0x27, 0xfb, 0x19, 0xe9, 0x28, 0xe6, 0xff, 0xba, 0xf5, 0x07, + 0x04, 0xbd, 0x07, 0xe1, 0x05, 0xea, 0x08, 0xec, 0xda, 0xb9, 0x32, 0xe7, 0xec, + 0x0e, 0x05, 0xad, 0xef, 0xf0, 0xe7, 0xe9, 0x27, 0xd6, 0xe4, 0x26, 0x05, 0x07, + 0xc4, 0xd5, 0xf7, 0xfd, 0xcb, 0xf4, 0x21, 0xe6, 0x0c, 0x25, 0x0b, 0xcc, 0x1f, + 0xc1, 0x2d, 0x04, 0x1e, 0x49, 0x1f, 0x3c, 0x19, 0x00, 0xe5, 0xaa, 0xcf, 0xd5, + 0xc9, 0x03, 0xd6, 0xcf, 0xe4, 0xf0, 0x05, 0x2f, 0x07, 0xf1, 0xc5, 0x2a, 0x25, + 0xfd, 0x30, 0x42, 0xf2, 0x01, 0xfd, 0xe1, 0x0c, 0xf7, 0x1e, 0x7f, 0x04, 0x16, + 0xc3, 0xde, 0xd8, 0x00, 0xc9, 0xe0, 0x35, 0xfc, 0xf0, 0x06, 0x31, 0xec, 0x0d, + 0xd6, 0xe0, 0xd1, 0x2c, 0xcd, 0xc8, 0xf9, 0xf9, 0xfd, 0xe9, 0xf4, 0x0d, 0xc5, + 0xe2, 0x29, 0xce, 0xdf, 0xe4, 0xf3, 0x07, 0x1c, 0x0b, 0xf6, 0x13, 0xe3, 0x06, + 0x00, 0x36, 0x09, 0xd7, 0xce, 0xdc, 0x19, 0xff, 0x14, 0xe2, 0x09, 0xdd, 0x09, + 0xf6, 0xc6, 0xf7, 0x9f, 0x0b, 0xeb, 0xd4, 0x0a, 0x22, 0x28, 0xd8, 0xcc, 0xcf, + 0xdc, 0xd6, 0xc1, 0x02, 0xf8, 0xdd, 0x0c, 0xef, 0x40, 0xd9, 0xd1, 0xc9, 0x07, + 0xee, 0xea, 0xda, 0xac, 0xeb, 0x37, 0xe1, 0xd7, 0x07, 0xc3, 0x1f, 0xfe, 0x12, + 0xe6, 0xe1, 0xf7, 0x1d, 0xb7, 0x29, 0x18, 0xd1, 0x3f, 0x00, 0xb6, 0x1a, 0xd5, + 0xf4, 0x0d, 0xeb, 0xab, 0xe4, 0xe1, 0x14, 0xf1, 0xdd, 0xcb, 0xf2, 0x0e, 0x03, + 0xe6, 0xd5, 0x21, 0x4e, 0xe0, 0xcc, 0x07, 0x20, 0xce, 0x12, 0xb1, 0xe5, 0xd8, + 0x13, 0xb8, 0x0c, 0xeb, 0xda, 0xfb, 0x0a, 0xd5, 0xe8, 0x66, 0x28, 0xfb, 0xee, + 0x94, 0x35, 0xc4, 0x24, 0xc8, 0x29, 0x12, 0x0c, 0xf3, 0xee, 0x28, 0x96, 0x03, + 0x22, 0xf2, 0xf2, 0xe3, 0x95, 0xf2, 0x7f, 0xf6, 0xeb, 0x03, 0x29, 0xe9, 0xd7, + 0xe4, 0x33, 0xeb, 0x49, 0xfd, 0xdc, 0xc5, 0x1b, 0xf0, 0x2c, 0x87, 0xf4, 0x04, + 0x10, 0xe9, 0xf5, 0xc8, 0xef, 0x06, 0x13, 0xfe, 0x26, 0xf0, 0x32, 0x11, 0xf0, + 0x05, 0x21, 0xfc, 0xe8, 0xcf, 0xf8, 0x9c, 0x31, 0xf4, 0xc6, 0xf0, 0x13, 0x0e, + 0xe8, 0xe0, 0x2e, 0x32, 0xfe, 0xf6, 0x17, 0xce, 0xe9, 0xcd, 0x06, 0x06, 0xcf, + 0x33, 0x09, 0x1d, 0x07, 0xd9, 0xcb, 0xcc, 0xd9, 0x4d, 0xf5, 0xd1, 0xba, 0xe7, + 0xc2, 0xe1, 0x03, 0x20, 0x0a, 0x0e, 0xc4, 0x00, 0xb1, 0x5a, 0xf0, 0x3e, 0xcf, + 0x26, 0x0a, 0x33, 0x0e, 0xee, 0xfe, 0xbb, 0xe0, 0x21, 0xd9, 0xa1, 0xb4, 0x58, + 0xc8, 0xd4, 0xff, 0xed, 0xaf, 0x1a, 0x0f, 0xca, 0xd2, 0xfd, 0x09, 0xc4, 0x1b, + 0x97, 0xdf, 0xf3, 0x32, 0xe3, 0xc2, 0xf1, 0x1d, 0xf1, 0xc3, 0xf4, 0x9d, 0x00, + 0xeb, 0x0b, 0x0f, 0x03, 0x17, 0xc4, 0x09, 0xe5, 0x14, 0xfb, 0x1a, 0xc8, 0xfe, + 0x11, 0xb6, 0x21, 0xeb, 0x19, 0xb6, 0x0c, 0xfd, 0xca, 0xc8, 0xde, 0x00, 0xa4, + 0xc4, 0xe6, 0xeb, 0x03, 0x0b, 0x10, 0xe5, 0xf6, 0xc6, 0xd0, 0xb9, 0xd2, 0xd0, + 0x23, 0xb3, 0xa0, 0xdf, 0x32, 0xd7, 0x17, 0x95, 0xe2, 0x01, 0x06, 0xa7, 0xec, + 0xa0, 0x33, 0x0f, 0xca, 0xfc, 0xc1, 0xd9, 0xa2, 0x14, 0xf4, 0xc9, 0xff, 0x21, + 0x03, 0x84, 0xf7, 0xfd, 0x2d, 0xc4, 0x08, 0xce, 0xa9, 0xf7, 0x35, 0xcc, 0x24, + 0x44, 0xe4, 0xbf, 0xbb, 0xe6, 0x22, 0x0a, 0xf3, 0xe2, 0xdb, 0x1d, 0xea, 0xd9, + 0xac, 0xff, 0x25, 0xfb, 0x3c, 0x05, 0xe8, 0xb0, 0xf0, 0x01, 0x05, 0x01, 0x31, + 0x1f, 0x34, 0xab, 0xde, 0x8d, 0x18, 0xe8, 0xb9, 0xe2, 0x01, 0x24, 0x06, 0xde, + 0xef, 0xf4, 0xa2, 0xc0, 0xec, 0x2d, 0xf4, 0xa5, 0xda, 0x0a, 0x37, 0x0f, 0x18, + 0x18, 0xbc, 0xe5, 0xed, 0x0b, 0xf5, 0xed, 0xf3, 0x28, 0x11, 0x3e, 0x2f, 0x99, + 0xd0, 0x00, 0xb7, 0x18, 0xb9, 0x3b, 0x31, 0x16, 0xf2, 0xb3, 0x5f, 0xf9, 0x06, + 0x18, 0xd3, 0xfb, 0x81, 0xae, 0xcf, 0xe0, 0xe5, 0xe4, 0xee, 0x09, 0x24, 0xac, + 0xf9, 0xcf, 0xa3, 0x53, 0xe2, 0x1d, 0x4e, 0xb9, 0xc1, 0xcb, 0x41, 0xdf, 0x09, + 0x22, 0xf1, 0xe7, 0xe6, 0x20, 0xdb, 0x49, 0xbf, 0x00, 0xee, 0xd5, 0xd2, 0xdf, + 0x2a, 0xe9, 0x3b, 0xd1, 0xdf, 0xf8, 0xdb, 0x05, 0x31, 0xef, 0xd4, 0x0d, 0x03, + 0x2f, 0x1f, 0xd4, 0xa2, 0xfc, 0xf2, 0x2b, 0x0d, 0x22, 0x1b, 0x07, 0xf0, 0x3f, + 0xf5, 0x13, 0x07, 0x01, 0xd4, 0x41, 0xd0, 0xc4, 0xfa, 0x1d, 0x26, 0xe8, 0xa7, + 0x0c, 0x0e, 0xc6, 0x0b, 0x3a, 0x55, 0x13, 0x2f, 0x10, 0x60, 0xf7, 0x11, 0xcf, + 0x12, 0xf2, 0x0d, 0x2c, 0xf9, 0xd8, 0x15, 0x21, 0xf5, 0x00, 0x0e, 0xd1, 0xcc, + 0xfb, 0xaa, 0xe6, 0xd3, 0x33, 0x5b, 0x24, 0xfc, 0xc2, 0xcc, 0x31, 0xda, 0x40, + 0x57, 0xf2, 0xfb, 0xf6, 0xdd, 0x27, 0x32, 0xc9, 0x44, 0xdc, 0xd4, 0xe3, 0xed, + 0xc3, 0x32, 0xd2, 0xd2, 0x42, 0x10, 0x27, 0x0a, 0xd7, 0x10, 0x37, 0xe4, 0x3b, + 0x44, 0xd1, 0xd6, 0xe3, 0xdd, 0xf8, 0xcf, 0x0f, 0x02, 0xed, 0xca, 0xb0, 0xf4, + 0xd8, 0xd4, 0xf8, 0x11, 0x0c, 0xfc, 0x19, 0xd2, 0xe7, 0xdc, 0xed, 0x14, 0xfc, + 0xda, 0xb0, 0xc6, 0x03, 0xce, 0xb3, 0x26, 0x0e, 0x21, 0xfa, 0xe4, 0xeb, 0x07, + 0xb6, 0x2d, 0xa3, 0xcc, 0x33, 0x14, 0xe1, 0x12, 0xb9, 0xfb, 0xe9, 0x27, 0xbb, + 0x3d, 0x06, 0xbe, 0xe3, 0x03, 0xf8, 0xe1, 0xf5, 0x2d, 0x07, 0x56, 0x1b, 0x05, + 0x1d, 0xc8, 0x01, 0xfc, 0xcf, 0xf6, 0xb4, 0x24, 0xea, 0x0d, 0xd6, 0xfe, 0xf0, + 0xf0, 0xef, 0xd2, 0xe4, 0xe2, 0x1c, 0x06, 0xfd, 0xd1, 0x24, 0xf5, 0x81, 0x09, + 0xee, 0xd9, 0x33, 0x03, 0xeb, 0x13, 0xe7, 0x22, 0xe9, 0x21, 0xbf, 0xee, 0x1c, + 0xe3, 0xd8, 0x0d, 0xe0, 0xcb, 0xac, 0xbf, 0xe2, 0xfc, 0xba, 0x2f, 0x35, 0x17, + 0xf2, 0xce, 0x11, 0xd8, 0xed, 0xf6, 0xd6, 0x0e, 0xfb, 0xe8, 0xe8, 0xf6, 0xb8, + 0xe4, 0xfd, 0xf0, 0xe2, 0xf5, 0xc7, 0x14, 0xe3, 0x03, 0xc0, 0xe4, 0x11, 0xef, + 0xf2, 0xe1, 0xf6, 0xe6, 0xef, 0xed, 0x22, 0x18, 0xe0, 0xf5, 0x34, 0x1b, 0x1b, + 0xb7, 0x0c, 0xfe, 0x2d, 0x0e, 0xad, 0xc8, 0xd6, 0xc9, 0x0c, 0x06, 0xe6, 0xf3, + 0x14, 0xc6, 0xf9, 0xc0, 0x1b, 0xd3, 0x23, 0x22, 0xe9, 0x15, 0xf1, 0xff, 0xee, + 0x18, 0x14, 0xcb, 0xe6, 0xd6, 0xea, 0x08, 0xf0, 0x39, 0xe7, 0x06, 0x2e, 0x13, + 0x0f, 0x0c, 0xd4, 0xc9, 0xe5, 0xdf, 0x0f, 0x0e, 0xf4, 0x0c, 0xf5, 0xff, 0x1e, + 0x27, 0xf0, 0x0a, 0xa0, 0xfe, 0xd7, 0x29, 0xd4, 0xea, 0x18, 0xfb, 0x00, 0xb8, + 0xb0, 0xf6, 0x93, 0x0c, 0xde, 0x25, 0x08, 0x0d, 0xe9, 0xdd, 0x30, 0xc3, 0xff, + 0x1c, 0xae, 0xdc, 0xee, 0x1c, 0x03, 0x15, 0xea, 0x1d, 0xf1, 0x15, 0x1e, 0xf5, + 0x9c, 0x12, 0xec, 0x12, 0xd9, 0xea, 0x13, 0xfe, 0xea, 0x20, 0xf9, 0x0b, 0x6e, + 0x08, 0xe7, 0x11, 0xc1, 0x0d, 0xdd, 0x1a, 0x1a, 0xd7, 0x2a, 0xfe, 0xe0, 0x2e, + 0xdb, 0xdf, 0xea, 0xfc, 0xe6, 0xb0, 0xdf, 0xbb, 0x07, 0xeb, 0xac, 0x09, 0xf1, + 0x3c, 0x07, 0xe2, 0xcd, 0x0c, 0xed, 0x02, 0xee, 0x01, 0x93, 0x44, 0xda, 0x06, + 0xe3, 0x12, 0x05, 0xf1, 0x49, 0x1a, 0xe0, 0xfd, 0x02, 0xd8, 0xed, 0xfe, 0x36, + 0xda, 0xd0, 0x15, 0x24, 0x01, 0x0b, 0x07, 0x44, 0x23, 0x31, 0xef, 0x46, 0x24, + 0x9e, 0xe4, 0xd1, 0xf9, 0xb6, 0x34, 0x3f, 0xf3, 0xe7, 0xe9, 0x9d, 0xf3, 0xd7, + 0xcf, 0xf0, 0x36, 0xe4, 0x1c, 0x0b, 0xc9, 0xe4, 0x04, 0x28, 0xf3, 0x22, 0xf7, + 0xe3, 0xe1, 0x15, 0xef, 0xab, 0x0d, 0xbd, 0x99, 0xb1, 0xdc, 0xc6, 0xd1, 0x16, + 0xf8, 0x41, 0x13, 0x2a, 0x2e, 0xce, 0xe0, 0x32, 0x34, 0x04, 0xdf, 0xff, 0x1f, + 0xba, 0xe6, 0xfc, 0xc5, 0x22, 0x08, 0xe8, 0xff, 0xf4, 0xcf, 0x04, 0x16, 0xe8, + 0x32, 0xe5, 0x34, 0xe7, 0xcc, 0xd4, 0xdf, 0x1c, 0xf4, 0xf5, 0xf4, 0x0f, 0x36, + 0xb1, 0xd5, 0xd5, 0xcd, 0xfa, 0xec, 0x12, 0xef, 0xa2, 0xfc, 0xdd, 0xd6, 0xf3, + 0x06, 0xd0, 0xaf, 0xd2, 0xfc, 0xf4, 0x21, 0x08, 0xd3, 0x3c, 0xbb, 0xfe, 0x3c, + 0x3b, 0xf6, 0xfc, 0xc7, 0x0a, 0xe2, 0xbf, 0xcb, 0x03, 0xf9, 0x29, 0x9f, 0xf6, + 0xfc, 0x3e, 0x00, 0x10, 0x44, 0x29, 0x2f, 0xc8, 0xf5, 0xc2, 0x2f, 0xe5, 0x0c, + 0x20, 0xff, 0x14, 0xe4, 0xff, 0xc3, 0x07, 0xf1, 0xda, 0x2b, 0x02, 0xb9, 0xe9, + 0xfe, 0xd8, 0x01, 0x96, 0x19, 0x02, 0x06, 0xc9, 0xd4, 0xe8, 0xfc, 0x17, 0xb7, + 0xd7, 0x22, 0x18, 0x0a, 0x1b, 0x47, 0xff, 0x23, 0x0a, 0x2c, 0x14, 0x0f, 0x32, + 0xea, 0x0c, 0xa1, 0x1d, 0xf5, 0xff, 0xf3, 0x11, 0x2d, 0xf5, 0x2f, 0x29, 0xcf, + 0x11, 0x20, 0x81, 0xd2, 0x81, 0x13, 0xad, 0xd2, 0xf8, 0x60, 0x1f, 0x12, 0xbc, + 0xe3, 0xad, 0x2c, 0x22, 0x9e, 0xfd, 0xc5, 0x12, 0xc0, 0xd5, 0x03, 0xea, 0xc8, + 0xc5, 0xe7, 0xd6, 0xdf, 0x33, 0x06, 0x3f, 0x28, 0x21, 0xfb, 0xce, 0x2f, 0xcf, + 0xc3, 0xc8, 0xe7, 0xd1, 0xef, 0xc6, 0xff, 0xdb, 0x38, 0xeb, 0x02, 0x1c, 0x01, + 0x12, 0x1a, 0x0e, 0x25, 0xe8, 0xf0, 0xfb, 0x97, 0xf6, 0xb5, 0xc0, 0xf4, 0xff, + 0xfd, 0xe2, 0xf3, 0xd2, 0xbe, 0xfe, 0x49, 0xe8, 0x2c, 0xf3, 0xe4, 0x16, 0xd7, + 0x02, 0x0f, 0x46, 0x1f, 0xf4, 0x01, 0xc4, 0x0d, 0xd5, 0xed, 0xec, 0xe3, 0xc7, + 0xec, 0xb8, 0xe9, 0x70, 0xd5, 0x10, 0x1c, 0x15, 0xcf, 0x21, 0xb1, 0x45, 0xf6, + 0xe9, 0xd2, 0xf8, 0xa8, 0xfd, 0xec, 0x16, 0x81, 0xd6, 0xe4, 0xfd, 0xf2, 0x1b, + 0x01, 0x0d, 0xf6, 0xb9, 0x12, 0x00, 0x33, 0x29, 0xac, 0xd6, 0xcd, 0x11, 0xfb, + 0xfc, 0xe7, 0xd8, 0xf1, 0x40, 0x29, 0x38, 0xee, 0x12, 0x34, 0xe3, 0xd7, 0x28, + 0xf0, 0xf1, 0x06, 0x23, 0xd4, 0xe0, 0xbe, 0x13, 0x10, 0xf4, 0x29, 0xd8, 0xe9, + 0xe3, 0xe6, 0xf6, 0xe2, 0x17, 0x29, 0x06, 0xc4, 0x1a, 0x45, 0xd4, 0x15, 0x17, + 0x63, 0x3d, 0xff, 0xcd, 0x16, 0x17, 0x2b, 0x14, 0x39, 0x09, 0xd5, 0xf4, 0xfb, + 0xff, 0xeb, 0xed, 0xd1, 0xd1, 0x07, 0xf9, 0xdc, 0xac, 0xef, 0x00, 0xd4, 0xc9, + 0x11, 0x22, 0xf0, 0xe3, 0x00, 0xe1, 0x19, 0xd7, 0xf3, 0x67, 0xa5, 0xc7, 0xd4, + 0x0a, 0x10, 0x06, 0xe4, 0x87, 0xe5, 0xe6, 0x1b, 0xda, 0xe3, 0xe5, 0xe1, 0xe7, + 0xcf, 0xf9, 0x03, 0xf3, 0x1a, 0xc5, 0xfc, 0x23, 0x1f, 0x05, 0x15, 0xca, 0xd3, + 0xcb, 0x62, 0xb0, 0x5f, 0x17, 0xd5, 0x1f, 0xc6, 0xfe, 0xcc, 0x31, 0xd2, 0x0b, + 0x20, 0x01, 0xe2, 0xf7, 0x25, 0xc9, 0xad, 0xfa, 0xb7, 0xd7, 0x5d, 0xfe, 0xc1, + 0x04, 0xe6, 0xea, 0xda, 0xad, 0x1b, 0xf4, 0xe7, 0xdc, 0xfb, 0x1a, 0xf3, 0x2e, + 0x1e, 0x23, 0x1c, 0xea, 0xeb, 0xe6, 0xce, 0xef, 0xf1, 0xfa, 0xc9, 0x21, 0x27, + 0xf0, 0xfe, 0x08, 0xe3, 0xc7, 0xfd, 0x20, 0x2c, 0x1b, 0x07, 0xc3, 0xe0, 0xce, + 0xe6, 0x04, 0xd4, 0xef, 0xf4, 0xb1, 0x46, 0xf7, 0x06, 0xd3, 0x34, 0x0b, 0x49, + 0xcd, 0xea, 0xea, 0x1e, 0xd5, 0x1b, 0xc9, 0x02, 0xe7, 0x01, 0xed, 0x2b, 0xdd, + 0x06, 0xb6, 0xe2, 0x0a, 0x2f, 0x0c, 0x25, 0x20, 0xda, 0x24, 0xf2, 0xfc, 0x01, + 0x17, 0xf5, 0xf4, 0x3c, 0xfd, 0x18, 0xd6, 0xe2, 0x34, 0xf4, 0xdf, 0xf0, 0x31, + 0xea, 0xf7, 0x20, 0xf4, 0x81, 0x0d, 0xe9, 0x12, 0xf5, 0xb4, 0xd8, 0xaf, 0xbc, + 0xd2, 0x12, 0x1e, 0xf0, 0xa6, 0xd0, 0xea, 0x01, 0x1b, 0xf1, 0x3a, 0xd7, 0xf8, + 0x3e, 0x93, 0xee, 0xbd, 0x1e, 0xcb, 0x14, 0xf4, 0x03, 0xeb, 0x00, 0xb8, 0xee, + 0x04, 0xe5, 0x2d, 0xb8, 0x0c, 0xaf, 0x26, 0xdc, 0x31, 0xb6, 0xf4, 0x1f, 0x31, + 0xa7, 0xeb, 0x22, 0xf6, 0xfc, 0xfc, 0xc0, 0x24, 0xec, 0xf6, 0xe6, 0x1e, 0xb4, + 0xef, 0x18, 0xe7, 0xf1, 0xfb, 0xcf, 0xdf, 0xcd, 0x0b, 0xee, 0x26, 0x10, 0xd1, + 0x11, 0xf3, 0x0f, 0x1c, 0x42, 0xed, 0x34, 0xf8, 0xf7, 0xff, 0xdc, 0xf4, 0x2e, + 0x23, 0x18, 0xf4, 0xc1, 0x18, 0x19, 0xfc, 0xbb, 0xad, 0x10, 0x02, 0xfd, 0xe8, + 0x09, 0xf2, 0x2b, 0x07, 0x2d, 0xd8, 0x23, 0x2e, 0x31, 0x0a, 0x1a, 0x1f, 0x10, + 0x20, 0x10, 0xa5, 0xf8, 0xdd, 0x32, 0xf0, 0xda, 0xb7, 0x20, 0x13, 0x0e, 0xfc, + 0xfb, 0xc6, 0x00, 0x0d, 0xc9, 0xbf, 0x95, 0xe5, 0x03, 0xd4, 0xf3, 0xf2, 0xf2, + 0x3c, 0xf5, 0x99, 0xbc, 0x0b, 0xf1, 0x1a, 0xd2, 0x1d, 0xba, 0xbb, 0xdf, 0xf6, + 0xbd, 0x2e, 0x29, 0x20, 0x01, 0x0b, 0xeb, 0xa8, 0xed, 0x40, 0xe6, 0x23, 0xc6, + 0x0c, 0x3a, 0xf8, 0xff, 0xf4, 0xed, 0x05, 0xea, 0x0e, 0xfb, 0xbf, 0xeb, 0xd7, + 0xf0, 0x09, 0xea, 0x26, 0x11, 0xd9, 0xfc, 0xc0, 0x14, 0xfc, 0xff, 0xf9, 0xd8, + 0x03, 0xb8, 0xf1, 0xf4, 0xf2, 0xfc, 0xd3, 0xd0, 0xf7, 0xed, 0xf1, 0x28, 0xfc, + 0x22, 0x07, 0x36, 0xef, 0x07, 0x04, 0x0b, 0xec, 0x01, 0xee, 0x25, 0xe5, 0xf0, + 0x1f, 0x01, 0xea, 0x10, 0x1d, 0x0e, 0xde, 0xed, 0x24, 0x11, 0x06, 0xd7, 0xdd, + 0x01, 0xc2, 0x48, 0x28, 0x4f, 0xe3, 0x3c, 0xd7, 0xe4, 0xe1, 0xcd, 0xf9, 0xf4, + 0xe9, 0xc2, 0xf5, 0x07, 0xef, 0x05, 0x1d, 0x0e, 0xdf, 0x04, 0xd9, 0xf0, 0x17, + 0x01, 0xeb, 0xe8, 0xd0, 0x2f, 0x2c, 0x52, 0xf9, 0xc3, 0xfe, 0xf7, 0xf5, 0x3a, + 0xb5, 0xed, 0xd1, 0x0a, 0xec, 0xfa, 0xd4, 0xfd, 0x35, 0x14, 0xf3, 0xba, 0xe5, + 0xff, 0x29, 0xe8, 0x45, 0xf7, 0x09, 0xe5, 0xcf, 0xd9, 0xd7, 0x01, 0xf2, 0xf6, + 0xf6, 0x1d, 0xd2, 0xfe, 0xeb, 0xdd, 0xdb, 0x1b, 0x2b, 0xe4, 0xd9, 0x43, 0xed, + 0xd6, 0x0f, 0xc2, 0x1d, 0x21, 0xc1, 0xd5, 0x0d, 0x28, 0x27, 0xee, 0xce, 0xbb, + 0xe4, 0x36, 0xe8, 0xd1, 0xe3, 0xf4, 0x7f, 0xd4, 0xf5, 0x0a, 0xf9, 0xc0, 0xef, + 0xe3, 0xff, 0xe5, 0x11, 0xf3, 0x3f, 0x2b, 0x03, 0xe3, 0xcd, 0x2a, 0xe9, 0xfb, + 0xfe, 0xfb, 0xeb, 0x34, 0xdf, 0x2f, 0xe7, 0xd3, 0xe7, 0xe9, 0x16, 0x1f, 0xd6, + 0xc2, 0xeb, 0x0b, 0x1f, 0x02, 0xf8, 0xea, 0xfa, 0xd9, 0xf6, 0xf4, 0xf3, 0xaa, + 0x10, 0xc6, 0xd2, 0x25, 0xf4, 0x02, 0x31, 0xf5, 0x04, 0xcd, 0xd9, 0xf2, 0xed, + 0xf5, 0x19, 0x30, 0x13, 0x11, 0x14, 0xed, 0x1c, 0x1d, 0xf7, 0xbc, 0xcc, 0x24, + 0x3b, 0x0d, 0xd4, 0xf6, 0xf5, 0xe4, 0xe0, 0xf5, 0x0c, 0xe0, 0xcf, 0xf4, 0x0d, + 0xb7, 0xe2, 0x00, 0xfd, 0x10, 0x13, 0x43, 0x22, 0x2d, 0x36, 0x0f, 0x06, 0x08, + 0xca, 0xd9, 0xf0, 0x2e, 0x04, 0xbd, 0xe5, 0xbd, 0x0e, 0xde, 0x02, 0xee, 0xdc, + 0xc6, 0x0e, 0xe5, 0xcd, 0xff, 0xf6, 0x13, 0x0f, 0xf8, 0xf0, 0xf5, 0xf0, 0xea, + 0x27, 0xa5, 0xe1, 0xf9, 0x0c, 0xd7, 0x07, 0xab, 0xe0, 0x36, 0x12, 0xdb, 0x32, + 0xf6, 0x16, 0xf6, 0x10, 0xfd, 0x12, 0xd1, 0xfb, 0xf4, 0xf9, 0xdb, 0xe4, 0xcf, + 0x02, 0x09, 0x3b, 0xe7, 0x15, 0xfe, 0x19, 0x7f, 0x29, 0xfa, 0xfd, 0xcd, 0x13, + 0xea, 0x0b, 0xdf, 0x17, 0xfa, 0x18, 0x03, 0xeb, 0xed, 0x01, 0xc6, 0x15, 0xd0, + 0xb5, 0x16, 0xbe, 0x1c, 0x1a, 0x0f, 0x0b, 0x07, 0xe8, 0x19, 0x07, 0x12, 0x3d, + 0xf0, 0xf1, 0xf2, 0xb5, 0xc3, 0xe3, 0xfa, 0xff, 0xd8, 0xd3, 0xb4, 0x00, 0xc5, + 0xd3, 0xea, 0xc4, 0xd5, 0xfd, 0xe3, 0x44, 0x0d, 0x1e, 0xee, 0xf7, 0xbc, 0xdd, + 0xe5, 0xde, 0xda, 0x12, 0xd3, 0xc9, 0x05, 0xc3, 0xed, 0xd5, 0xf5, 0xbf, 0xc8, + 0x01, 0x0a, 0x00, 0x25, 0x28, 0x03, 0xc6, 0x00, 0xe4, 0xd3, 0xf2, 0xfd, 0xf3, + 0x0c, 0xfb, 0x0f, 0x17, 0xb0, 0xdc, 0x02, 0xb7, 0xef, 0xd3, 0xf7, 0xce, 0xf6, + 0x27, 0x23, 0x0d, 0x11, 0xcc, 0xfb, 0xf9, 0xf2, 0x22, 0xd8, 0xc4, 0x33, 0xf0, + 0x14, 0x42, 0x05, 0xe4, 0xed, 0xf7, 0x1e, 0xbe, 0xc2, 0xea, 0x11, 0xeb, 0xdf, + 0x0c, 0xf9, 0xc6, 0x07, 0x13, 0xb1, 0xd6, 0xf9, 0xb8, 0xd1, 0xf5, 0xd2, 0xcf, + 0x02, 0xba, 0x10, 0x02, 0xe4, 0x16, 0xeb, 0xd0, 0x3f, 0xda, 0xec, 0xe1, 0x1a, + 0x39, 0x1a, 0x06, 0x2e, 0x17, 0xdb, 0x09, 0xf8, 0xe9, 0xf7, 0x18, 0x12, 0xb1, + 0x0a, 0xf2, 0xef, 0xfd, 0xe6, 0x24, 0xfd, 0x1b, 0xe1, 0x07, 0xb9, 0xf8, 0xf2, + 0xcb, 0x49, 0xec, 0xe2, 0x04, 0x1d, 0xd1, 0xd5, 0xe8, 0x09, 0xec, 0xe0, 0xb8, + 0xc8, 0xfc, 0xf4, 0xf5, 0x08, 0xe9, 0xfb, 0xf5, 0x13, 0xad, 0x14, 0xdb, 0x01, + 0x09, 0xbe, 0x10, 0xe8, 0x19, 0xfc, 0xec, 0x1e, 0xbe, 0xb1, 0x2d, 0xbb, 0x01, + 0xf8, 0x0a, 0x4c, 0x1e, 0x17, 0xec, 0xf0, 0xc8, 0x1f, 0x18, 0x9b, 0xe9, 0xf1, + 0x0c, 0xf2, 0xca, 0xa2, 0xd0, 0xef, 0xee, 0xcb, 0xee, 0x09, 0xff, 0xce, 0xf0, + 0xff, 0x1e, 0xd0, 0x0b, 0xd2, 0xe4, 0xa4, 0xd8, 0xfc, 0xd8, 0xe3, 0x36, 0xfc, + 0x12, 0x2d, 0x22, 0x74, 0x14, 0xed, 0xdb, 0xbc, 0x08, 0xd3, 0x2a, 0xd0, 0x96, + 0x17, 0xf2, 0x26, 0xfd, 0x05, 0xd3, 0xd7, 0x56, 0xbc, 0xdc, 0x14, 0xe4, 0xf7, + 0x6c, 0x05, 0x21, 0x30, 0x25, 0x11, 0x00, 0xb5, 0x50, 0xcb, 0x05, 0xea, 0xf1, + 0x27, 0x32, 0xf7, 0x22, 0xc5, 0xd5, 0xcd, 0xf0, 0xed, 0x37, 0xc3, 0x1b, 0xe7, + 0x48, 0xee, 0xc9, 0xf3, 0xf4, 0xdb, 0xc7, 0xbc, 0xfe, 0xdd, 0xe9, 0x87, 0x01, + 0xf6, 0x1d, 0xf0, 0xba, 0xe4, 0xf6, 0xcd, 0x21, 0xf6, 0xbf, 0x1f, 0xf4, 0x0b, + 0xe4, 0xc1, 0xe7, 0xdd, 0x45, 0x03, 0x06, 0x09, 0x04, 0x1e, 0x1a, 0x0a, 0x19, + 0xcc, 0x93, 0x06, 0xc6, 0x1c, 0xbe, 0xef, 0xa5, 0x19, 0x2e, 0x41, 0x3a, 0xf2, + 0xcb, 0xf3, 0xc5, 0x17, 0x36, 0x4d, 0xbf, 0xdc, 0x02, 0x04, 0xfb, 0xe5, 0x36, + 0xf9, 0xdd, 0x0a, 0x9b, 0xa5, 0xb4, 0x57, 0xce, 0xea, 0xfe, 0xd4, 0x4c, 0xd3, + 0xce, 0x0d, 0xdb, 0xf7, 0xf0, 0x97, 0x3a, 0xbc, 0xe0, 0xab, 0xe8, 0x1d, 0xe1, + 0xfa, 0xea, 0xec, 0xe0, 0x1d, 0xa9, 0xe8, 0xcd, 0xc8, 0x11, 0x01, 0x0d, 0x28, + 0x0f, 0xbc, 0x20, 0xec, 0x13, 0x01, 0xfd, 0x44, 0xd3, 0x24, 0xe6, 0x26, 0xb3, + 0x04, 0x23, 0x11, 0x0b, 0xca, 0x04, 0xc4, 0x08, 0x02, 0xe7, 0x7f, 0x25, 0x26, + 0xf1, 0xc7, 0xe2, 0xf1, 0x0c, 0xe6, 0xac, 0x38, 0xbe, 0xd0, 0xda, 0xe7, 0xbd, + 0x13, 0xc4, 0x03, 0x14, 0x12, 0x9c, 0xc5, 0xdf, 0xea, 0xfe, 0xdc, 0xcc, 0xc2, + 0x96, 0x2a, 0xe3, 0x28, 0xbe, 0xba, 0x38, 0xc1, 0x95, 0x2e, 0x1f, 0xda, 0xaf, + 0x08, 0x39, 0xa8, 0x51, 0x11, 0xe6, 0x28, 0x16, 0x32, 0xe9, 0x2b, 0xeb, 0xdd, + 0x17, 0x39, 0xd1, 0x3e, 0x07, 0x3c, 0x05, 0xbe, 0xfe, 0x32, 0xb0, 0x0f, 0xda, + 0xee, 0x26, 0xd4, 0x14, 0xeb, 0xf6, 0x06, 0x2f, 0x19, 0xdd, 0xe7, 0xbe, 0x2a, + 0xd3, 0xcb, 0xff, 0x35, 0xf0, 0xb4, 0x23, 0x05, 0xd5, 0xaa, 0x2a, 0x16, 0xfe, + 0xd1, 0xd7, 0x29, 0xa9, 0x17, 0xfa, 0x2b, 0x02, 0xbf, 0x3a, 0xaa, 0xe4, 0x0d, + 0xed, 0xdc, 0xcc, 0xee, 0x2b, 0xd3, 0xcf, 0xd4, 0xfe, 0xcc, 0xe4, 0x10, 0xbb, + 0x30, 0xc2, 0xe9, 0xd3, 0x2e, 0xaf, 0x10, 0xf5, 0xef, 0x30, 0xf3, 0x01, 0xfb, + 0xa9, 0xe8, 0x05, 0x50, 0x10, 0xe2, 0xe2, 0x30, 0x19, 0xed, 0x67, 0xea, 0x1f, + 0x3b, 0x5b, 0x10, 0xf8, 0x04, 0x57, 0x0e, 0x01, 0x81, 0xd6, 0x2e, 0xe4, 0xe8, + 0x9a, 0xfc, 0xa1, 0xe1, 0x3f, 0xc7, 0xfe, 0x2d, 0x50, 0x40, 0x2a, 0x54, 0xcf, + 0xd6, 0xac, 0xec, 0x12, 0xfc, 0x23, 0x0b, 0xb0, 0xee, 0xee, 0x07, 0x17, 0xee, + 0xd3, 0xdb, 0xf3, 0x04, 0xbf, 0xef, 0xf9, 0xc2, 0x2b, 0x0b, 0x0f, 0x4e, 0x44, + 0x97, 0x35, 0x26, 0x03, 0xe2, 0x03, 0x33, 0xd1, 0xd7, 0x2f, 0x2b, 0x06, 0x1a, + 0xf5, 0xe7, 0xe7, 0xf0, 0xfe, 0xfb, 0x1b, 0xcf, 0x44, 0xd0, 0x16, 0x9f, 0xb7, + 0xd2, 0xd1, 0xe4, 0xa8, 0xf0, 0xe8, 0xed, 0xd6, 0xb5, 0xb0, 0xb8, 0x96, 0xd8, + 0xc8, 0x02, 0x9d, 0xeb, 0x27, 0x08, 0xf1, 0xeb, 0xe9, 0xbf, 0xbf, 0x2e, 0xe8, + 0xae, 0xc7, 0xd6, 0xbe, 0xd8, 0xd5, 0xf8, 0x27, 0xb1, 0xdf, 0xd3, 0xfb, 0xca, + 0x20, 0xee, 0xf6, 0xa2, 0xe6, 0xf3, 0x4b, 0xd9, 0xb9, 0x23, 0x47, 0x19, 0x50, + 0xc3, 0xd7, 0xbe, 0x28, 0xf1, 0xf7, 0xf9, 0xd9, 0x0c, 0xc2, 0xe2, 0x21, 0xd3, + 0xf2, 0xde, 0x0b, 0xad, 0xbd, 0x17, 0xd8, 0xfa, 0xb8, 0xe5, 0x25, 0xd2, 0xe5, + 0xb1, 0xe7, 0x24, 0xbd, 0x4b, 0xa7, 0x08, 0x25, 0x11, 0xbc, 0xce, 0x0e, 0xb8, + 0xcf, 0xda, 0x05, 0xff, 0xd1, 0x48, 0xd8, 0xca, 0xf2, 0x9c, 0xfe, 0x14, 0x16, + 0xcb, 0x0e, 0x2c, 0xf3, 0xcc, 0x57, 0xb2, 0xf9, 0xf5, 0xd0, 0x1a, 0xc7, 0x1c, + 0x0c, 0x34, 0x05, 0x0a, 0xd9, 0xbe, 0x44, 0x05, 0x23, 0x35, 0xeb, 0x00, 0xa4, + 0x07, 0xb5, 0xd1, 0xda, 0x2b, 0x1c, 0x16, 0x27, 0xec, 0xf9, 0xcf, 0x33, 0xa7, + 0x1b, 0xee, 0xbc, 0x14, 0x25, 0xcb, 0xa0, 0xfe, 0xf0, 0xe4, 0xa3, 0xed, 0xf7, + 0xfd, 0x05, 0x2e, 0xe6, 0xe6, 0xb4, 0x40, 0xb2, 0xc5, 0xc6, 0xde, 0xad, 0xfd, + 0xac, 0xd6, 0xe5, 0xce, 0xbc, 0xee, 0x39, 0x4f, 0x10, 0xda, 0x3c, 0xae, 0xea, + 0x12, 0x21, 0xca, 0x1d, 0x97, 0xfc, 0xc9, 0xe7, 0xe9, 0xf3, 0x7d, 0xec, 0x11, + 0x59, 0x53, 0x06, 0x2b, 0x4c, 0xbc, 0x06, 0xf3, 0x09, 0xd9, 0xd5, 0xbd, 0x0e, + 0xf0, 0x02, 0x21, 0xda, 0x17, 0x13, 0xb9, 0xfa, 0xfe, 0x20, 0x01, 0xf9, 0xf3, + 0x08, 0xbf, 0xaf, 0x16, 0xf6, 0x2d, 0x4e, 0xfb, 0x1b, 0x47, 0xea, 0x13, 0x35, + 0x03, 0x11, 0x03, 0xe5, 0x15, 0xf7, 0xfe, 0xc6, 0xe2, 0x2f, 0xd5, 0x04, 0xcb, + 0x1e, 0x3a, 0x0e, 0x23, 0xe2, 0x48, 0xf6, 0x1f, 0xe0, 0xfd, 0xc6, 0x48, 0xd1, + 0x45, 0xf4, 0x2b, 0x35, 0x41, 0xc9, 0x51, 0xf6, 0xbd, 0xb4, 0xf9, 0xda, 0xae, + 0x20, 0xeb, 0xbe, 0xe0, 0x81, 0x28, 0xaf, 0x0f, 0xd6, 0x16, 0xf6, 0xf9, 0xc8, + 0xf5, 0xfc, 0xe9, 0xb6, 0xe2, 0xdd, 0xfa, 0x15, 0xdc, 0xcc, 0xe2, 0xc1, 0xd5, + 0x2c, 0xde, 0x1d, 0xb2, 0xe6, 0xf7, 0xf7, 0xf2, 0xfe, 0xff, 0xa6, 0xb1, 0x0d, + 0x08, 0xf8, 0xb8, 0x03, 0xcc, 0x0f, 0x10, 0x17, 0x1b, 0xcd, 0xec, 0x46, 0xd9, + 0xe5, 0xed, 0xd6, 0xf2, 0xe2, 0xf4, 0xe4, 0xdf, 0xda, 0xe8, 0xee, 0xb9, 0xe3, + 0xf9, 0x2c, 0xe7, 0x2d, 0xf9, 0xec, 0x14, 0xe2, 0xd5, 0xeb, 0x17, 0x50, 0x11, + 0xee, 0xfb, 0x25, 0xc0, 0xf2, 0xfe, 0x1f, 0xe2, 0xf1, 0xc7, 0xf3, 0x02, 0xeb, + 0xd2, 0xfe, 0x14, 0x2b, 0x56, 0x20, 0x29, 0x29, 0xca, 0xf2, 0xb3, 0x5e, 0xf3, + 0xcb, 0xdc, 0xf5, 0x4f, 0xf2, 0x4b, 0xe3, 0xd1, 0xe5, 0xbe, 0xce, 0xef, 0x0a, + 0x34, 0x5a, 0xd7, 0x00, 0x08, 0xeb, 0xe0, 0x07, 0xf6, 0x30, 0xe8, 0x11, 0xe1, + 0xc7, 0x07, 0xf1, 0xf6, 0xb4, 0x81, 0xe1, 0xeb, 0x1d, 0xde, 0xdd, 0xdc, 0xf5, + 0xfa, 0xaa, 0x09, 0xdf, 0x09, 0x30, 0xc3, 0xdc, 0xe3, 0xee, 0xf2, 0xfe, 0x17, + 0xe7, 0xbf, 0x3b, 0xfb, 0xe3, 0xff, 0xda, 0xf8, 0x15, 0x94, 0x0e, 0xf5, 0x02, + 0xed, 0x02, 0xee, 0xf2, 0xc6, 0xcc, 0xfd, 0xfc, 0x2d, 0xf9, 0x51, 0x46, 0xc6, + 0xcc, 0xce, 0xc7, 0x23, 0xa1, 0x06, 0xb9, 0xfe, 0xee, 0x13, 0x4e, 0x49, 0x01, + 0xea, 0xc5, 0x3c, 0xc4, 0x25, 0xf0, 0x5e, 0xf6, 0x18, 0x12, 0x34, 0xe7, 0xf2, + 0x0b, 0xc9, 0xdc, 0x33, 0xb5, 0xc1, 0xb2, 0x26, 0xdc, 0x15, 0xd6, 0xf9, 0xe3, + 0x42, 0xe7, 0xe6, 0x12, 0xf7, 0xef, 0xcb, 0x39, 0xdb, 0xb5, 0xf7, 0x18, 0xfb, + 0x0a, 0xae, 0xda, 0xfc, 0xdd, 0x04, 0xc3, 0xff, 0x10, 0xdb, 0x02, 0x06, 0x11, + 0x04, 0x1a, 0xfe, 0x13, 0x07, 0x57, 0x07, 0x25, 0xb6, 0xc2, 0xe5, 0xf1, 0x5a, + 0xa1, 0x35, 0x2a, 0xde, 0x2e, 0xd6, 0xe9, 0xc4, 0x03, 0xdf, 0xc2, 0x1a, 0x2f, + 0x23, 0xc8, 0xa8, 0xf6, 0xd6, 0xb6, 0xa1, 0x09, 0x1c, 0xa9, 0xb7, 0xe3, 0xed, + 0xf8, 0x03, 0xb1, 0x40, 0x02, 0xe7, 0xc1, 0x9c, 0xc5, 0xda, 0xf5, 0xed, 0xe4, + 0x04, 0x36, 0xf0, 0xe0, 0xd5, 0x07, 0xf3, 0x08, 0x5c, 0xa4, 0x07, 0x37, 0xc8, + 0xcd, 0x12, 0x1c, 0x3c, 0xf9, 0xed, 0xe5, 0x0d, 0xea, 0x15, 0xdc, 0x15, 0xf6, + 0xf2, 0x37, 0x15, 0x1a, 0x27, 0xd1, 0x2a, 0xfa, 0xe2, 0xba, 0x22, 0xd6, 0x19, + 0xd0, 0xd0, 0x0e, 0x08, 0x0e, 0x02, 0x30, 0x04, 0xee, 0xff, 0x33, 0xc2, 0xdd, + 0xea, 0xca, 0xe9, 0xdf, 0x06, 0xca, 0xe5, 0xfb, 0x39, 0x0e, 0xb8, 0xc2, 0x02, + 0x0c, 0x05, 0xe7, 0x37, 0xd8, 0x1b, 0xe6, 0x07, 0x02, 0xff, 0x03, 0x09, 0xec, + 0xf3, 0x01, 0xdb, 0xde, 0xf4, 0x50, 0xee, 0x21, 0xf4, 0xdc, 0x9f, 0xf1, 0xf7, + 0xf4, 0xc6, 0xd2, 0xf1, 0x30, 0x42, 0xed, 0x25, 0x2f, 0xf5, 0x08, 0x27, 0xc1, + 0xdb, 0x22, 0x23, 0xd6, 0x27, 0xeb, 0x0f, 0xf1, 0x28, 0x06, 0x20, 0x21, 0x55, + 0xf9, 0xed, 0x20, 0xbb, 0xf4, 0x29, 0x16, 0xea, 0xfc, 0xed, 0x0f, 0x0d, 0xce, + 0xfa, 0xf3, 0x38, 0x09, 0xca, 0x56, 0x7f, 0xf4, 0x26, 0x27, 0xef, 0x04, 0xf6, + 0xf5, 0xe3, 0xea, 0x16, 0xf5, 0x00, 0x35, 0x16, 0xc9, 0xff, 0x36, 0xfe, 0xbe, + 0xfc, 0x37, 0xef, 0xd5, 0xf8, 0x0a, 0x20, 0x1a, 0xfa, 0xd6, 0x01, 0x3e, 0x3f, + 0xc8, 0x16, 0x27, 0xdc, 0xc9, 0xdd, 0xb1, 0x38, 0x17, 0x0f, 0xde, 0xf7, 0xc0, + 0xfe, 0x09, 0xcb, 0xf3, 0x13, 0x21, 0x19, 0x46, 0xf5, 0x1b, 0xf4, 0x2b, 0xe7, + 0xb6, 0x0f, 0xec, 0x59, 0xec, 0xfa, 0x12, 0x1d, 0x09, 0xee, 0xee, 0x25, 0xef, + 0x07, 0xf1, 0xfa, 0xcf, 0xfc, 0x32, 0x2a, 0xf6, 0xf7, 0xe4, 0xf6, 0xac, 0xff, + 0x27, 0x03, 0xc8, 0xf2, 0xb3, 0xc7, 0xdf, 0xe5, 0xec, 0xde, 0x2c, 0x03, 0xf8, + 0xda, 0x00, 0xde, 0x23, 0xfb, 0xf8, 0xb7, 0x04, 0xdc, 0xfa, 0xe3, 0xe9, 0x29, + 0x16, 0x1c, 0x05, 0xd2, 0xbe, 0xcb, 0x10, 0xd4, 0x41, 0x2f, 0xdf, 0xc5, 0x2d, + 0xfc, 0x29, 0x1d, 0xa5, 0x21, 0x2b, 0xde, 0x12, 0x10, 0xbd, 0x0d, 0xf9, 0xb9, + 0x0d, 0xf2, 0x2c, 0xf1, 0x50, 0x36, 0x36, 0xe9, 0xb0, 0x48, 0x23, 0xef, 0xfe, + 0x1c, 0xf3, 0xe5, 0x0e, 0x46, 0x0d, 0x12, 0xfd, 0xe1, 0x0d, 0xef, 0x32, 0x1d, + 0xe7, 0x00, 0x23, 0x0c, 0xca, 0x25, 0x24, 0x00, 0xf5, 0xad, 0xcb, 0x0b, 0x09, + 0x1e, 0xd0, 0xfb, 0xd3, 0xdc, 0xee, 0xed, 0x36, 0xe3, 0xdb, 0x02, 0x6f, 0xda, + 0xc7, 0xd0, 0xd2, 0xd8, 0xa1, 0xc1, 0x04, 0x5d, 0xbd, 0x0d, 0x35, 0xf5, 0x09, + 0x59, 0xad, 0xe0, 0x00, 0xe7, 0xa3, 0x13, 0xa0, 0xfc, 0x27, 0xf1, 0x10, 0x06, + 0xd1, 0x22, 0x21, 0x43, 0x0e, 0xd8, 0xbc, 0x1d, 0xad, 0x05, 0xc2, 0xe7, 0x23, + 0xed, 0xfd, 0x0c, 0x0c, 0x08, 0xf9, 0x2f, 0x3b, 0x10, 0xf1, 0xd3, 0x10, 0xfa, + 0xe0, 0xe4, 0xb0, 0xc4, 0xf1, 0xd5, 0xd5, 0x2f, 0x14, 0xca, 0xf3, 0xea, 0xd9, + 0xde, 0xe6, 0x01, 0xec, 0xee, 0x0b, 0x1f, 0x28, 0x81, 0xfe, 0x02, 0xc0, 0xcc, + 0xce, 0xb1, 0xfd, 0x04, 0xdd, 0x18, 0xfa, 0x26, 0xe3, 0xe9, 0xca, 0xdc, 0xc6, + 0xef, 0xf6, 0x12, 0x08, 0xf0, 0x5f, 0xe6, 0xfd, 0xf8, 0x15, 0x2e, 0x0b, 0xcb, + 0x1b, 0x14, 0x43, 0x17, 0x58, 0xee, 0xb7, 0x5d, 0xd6, 0x15, 0x05, 0xa4, 0x10, + 0xe1, 0xd6, 0x12, 0x24, 0x2c, 0x33, 0x29, 0xce, 0xf4, 0x01, 0xb1, 0x48, 0xf2, + 0x29, 0x14, 0xc3, 0x1f, 0xf2, 0xd1, 0xd4, 0x46, 0xd3, 0x16, 0xef, 0xfe, 0xed, + 0xe5, 0x1d, 0x07, 0x2f, 0x29, 0xf0, 0x17, 0x18, 0xd0, 0x18, 0xdd, 0x53, 0xcb, + 0x0b, 0xd4, 0x09, 0x54, 0x08, 0xf4, 0x30, 0xd8, 0x3f, 0x44, 0x2c, 0xf2, 0x08, + 0x2c, 0x15, 0xe7, 0xe0, 0xdd, 0xe8, 0xcc, 0xce, 0xea, 0x2c, 0x06, 0xd3, 0x25, + 0x09, 0x2e, 0xb9, 0xa7, 0xe9, 0xcf, 0x11, 0xc5, 0xe9, 0x17, 0xc0, 0x01, 0xe2, + 0xe8, 0xe4, 0xef, 0xee, 0xd5, 0x55, 0x20, 0xf6, 0x17, 0xad, 0x15, 0xdc, 0x81, + 0xed, 0xcc, 0xe2, 0x20, 0x1c, 0xd0, 0xe6, 0x22, 0x02, 0x95, 0xf4, 0xd7, 0xd6, + 0x38, 0x2f, 0x0f, 0xc5, 0xa9, 0x0b, 0xd6, 0xef, 0x02, 0xde, 0x98, 0xaa, 0x29, + 0x4c, 0x2a, 0x3c, 0xca, 0x5f, 0x39, 0x06, 0x2e, 0xc6, 0xde, 0xf0, 0x0d, 0x9d, + 0xe1, 0x16, 0xe7, 0x1e, 0xdc, 0xd3, 0xf9, 0x09, 0xb4, 0x31, 0x9a, 0x87, 0xfe, + 0xb5, 0xc2, 0xeb, 0x0f, 0xe7, 0xf6, 0x47, 0x23, 0x12, 0xc0, 0xc9, 0x23, 0x17, + 0xec, 0xd6, 0xb1, 0xca, 0xee, 0x2c, 0xed, 0xf2, 0xc9, 0xf4, 0x1b, 0xc7, 0xcb, + 0xd4, 0xff, 0xe8, 0x08, 0xfc, 0xe9, 0x62, 0xe2, 0xe6, 0x0e, 0xf2, 0xbc, 0xe2, + 0xc1, 0xd9, 0x16, 0x12, 0x43, 0xb9, 0xee, 0xc0, 0xef, 0xfc, 0x37, 0xf5, 0xf0, + 0xca, 0xe9, 0x63, 0x18, 0xe9, 0x12, 0xcd, 0x0b, 0xdc, 0xf1, 0xc3, 0x05, 0x25, + 0x31, 0x10, 0x99, 0xcb, 0x24, 0xff, 0x4a, 0x0d, 0x2b, 0x02, 0xf9, 0x3e, 0x03, + 0x0b, 0x62, 0xdb, 0xf5, 0xd8, 0xf1, 0xd1, 0xf8, 0xe2, 0xdb, 0xf4, 0x21, 0xe6, + 0xac, 0x18, 0xdf, 0x21, 0xf4, 0x1b, 0xcd, 0xa9, 0x10, 0x6e, 0xe9, 0xfb, 0x17, + 0xd2, 0xf4, 0x0d, 0xf8, 0xf9, 0x30, 0x0a, 0x96, 0x00, 0xf9, 0xbf, 0xcf, 0xf4, + 0x3f, 0xf5, 0xec, 0x1d, 0x16, 0xa9, 0x0c, 0xe2, 0xb5, 0xf3, 0x1f, 0x3f, 0xf5, + 0x11, 0xf3, 0x17, 0x04, 0x0c, 0xd2, 0x9d, 0xb4, 0xdd, 0xec, 0xc4, 0x37, 0x13, + 0x06, 0x0c, 0xba, 0x2a, 0x15, 0xf7, 0xd4, 0xd0, 0xe6, 0x10, 0x19, 0xfa, 0x6d, + 0x49, 0xd8, 0xde, 0xcd, 0x00, 0xf9, 0xbf, 0xf6, 0xd5, 0x16, 0xb5, 0xbd, 0xde, + 0x21, 0xcb, 0x43, 0xf7, 0x1e, 0xdf, 0x2f, 0x0f, 0x23, 0xa7, 0x55, 0xe7, 0xf5, + 0xe4, 0xe0, 0x0e, 0xba, 0x41, 0xdb, 0xfc, 0xe8, 0x05, 0xcc, 0x0f, 0xb6, 0xf5, + 0xe3, 0xad, 0xeb, 0xf3, 0xba, 0x19, 0xfe, 0xe2, 0xf8, 0xaa, 0xd1, 0xfd, 0x9f, + 0xb3, 0x1f, 0xbb, 0xdf, 0xd2, 0x0b, 0x00, 0x2f, 0xd6, 0x03, 0xf4, 0xf1, 0x14, + 0xf6, 0x47, 0xfa, 0xca, 0xff, 0x08, 0xe2, 0xdc, 0x49, 0x44, 0x37, 0x2d, 0xfd, + 0xdc, 0xf8, 0xe3, 0x00, 0xd3, 0x78, 0xee, 0xf5, 0xe9, 0x07, 0xda, 0xd4, 0x34, + 0xca, 0xdc, 0x2a, 0x04, 0xe2, 0x08, 0x2e, 0x0c, 0xbb, 0x0c, 0xdf, 0x8b, 0xf6, + 0xe1, 0xf8, 0xfa, 0xdb, 0xe2, 0xfa, 0xc4, 0x09, 0x17, 0xf5, 0xed, 0xcd, 0x1b, + 0xda, 0x0b, 0x2c, 0x0c, 0xee, 0xf4, 0x09, 0xc9, 0xc9, 0xd8, 0xe3, 0x34, 0x49, + 0xef, 0x04, 0xc7, 0xfc, 0xf4, 0x01, 0xe0, 0xc6, 0x27, 0xdf, 0xf2, 0xe6, 0xf8, + 0x58, 0xd8, 0xf1, 0xb7, 0x14, 0xbd, 0x07, 0xfd, 0xd1, 0x8d, 0xdc, 0x25, 0x06, + 0xd5, 0xf1, 0xbb, 0xcd, 0x20, 0xb1, 0xd7, 0xec, 0x9d, 0x09, 0xdd, 0x07, 0xf5, + 0xfe, 0x35, 0xea, 0x6b, 0x3f, 0xce, 0xca, 0xf3, 0xd1, 0xe4, 0x19, 0x03, 0x0f, + 0x0e, 0xda, 0xdf, 0xe2, 0x18, 0xd2, 0x2f, 0x49, 0xe1, 0xe3, 0xa7, 0xf4, 0x11, + 0x03, 0xf1, 0xe2, 0x25, 0xf5, 0x03, 0xf3, 0xe2, 0xfe, 0xf9, 0x01, 0xed, 0xe6, + 0x2b, 0x02, 0xc0, 0xe4, 0xe0, 0x21, 0xda, 0xb7, 0xe0, 0x18, 0xe2, 0x01, 0xfe, + 0x0b, 0xe9, 0x3d, 0x8f, 0xaf, 0xf9, 0x0d, 0xdc, 0xf6, 0xff, 0xc5, 0xc7, 0xe7, + 0xe0, 0x15, 0xba, 0xd2, 0x16, 0xe4, 0x02, 0x1e, 0xf5, 0x0c, 0x56, 0xe0, 0x27, + 0x4b, 0xc0, 0x13, 0x05, 0x08, 0x2e, 0x02, 0x06, 0x19, 0xff, 0x21, 0x2b, 0xf6, + 0xfe, 0x38, 0xff, 0x7f, 0xda, 0xc2, 0x43, 0x07, 0xdf, 0xdb, 0xb6, 0x03, 0x0a, + 0xd3, 0x1e, 0xe6, 0xeb, 0xe6, 0xdf, 0xd7, 0x05, 0xda, 0xe2, 0x2e, 0xf9, 0xe6, + 0x24, 0x28, 0xfa, 0xfd, 0x09, 0x0a, 0xfb, 0xe3, 0x18, 0x0f, 0xcf, 0x15, 0x13, + 0xe5, 0xf2, 0x00, 0xef, 0xee, 0xd6, 0x0b, 0xd7, 0xf1, 0xfc, 0xf5, 0x1c, 0xcf, + 0x10, 0xfa, 0x2c, 0xcf, 0x35, 0x0a, 0xe6, 0xf8, 0xe7, 0x0f, 0xd6, 0xd6, 0x39, + 0xe4, 0xfb, 0x04, 0x1c, 0x1f, 0xc3, 0x1f, 0x23, 0x07, 0xee, 0x1e, 0x21, 0x20, + 0xec, 0xf9, 0xfb, 0x0d, 0xf5, 0xef, 0xdf, 0x26, 0x07, 0x00, 0xc8, 0x26, 0x2e, + 0x00, 0x0e, 0xb5, 0xe3, 0x4a, 0xdb, 0xfd, 0xb0, 0x2a, 0x0b, 0xe7, 0x23, 0xee, + 0xf9, 0xe5, 0xfe, 0x0c, 0xd3, 0xc1, 0xf5, 0xe7, 0xf7, 0x00, 0xf1, 0xde, 0x1d, + 0xec, 0x05, 0xd0, 0x0c, 0xde, 0x28, 0x04, 0x26, 0xee, 0xe4, 0xfd, 0xfb, 0x0e, + 0xe4, 0xfd, 0x14, 0x0d, 0x0d, 0x27, 0x29, 0xfa, 0xfd, 0xda, 0x0b, 0xe2, 0x12, + 0x04, 0x28, 0xeb, 0xee, 0xf7, 0xbf, 0xfa, 0xc2, 0x1c, 0xf8, 0xd8, 0xc5, 0xfd, + 0xe8, 0x12, 0xef, 0xfe, 0xe9, 0x0a, 0x11, 0x1b, 0xf2, 0xe2, 0xc4, 0xaa, 0xd5, + 0xce, 0x23, 0xf2, 0xe4, 0x1f, 0xcf, 0x07, 0x06, 0x17, 0x28, 0xd6, 0x24, 0x1b, + 0xc5, 0x07, 0x05, 0xf2, 0x52, 0x41, 0xe6, 0x7f, 0xfb, 0xd9, 0xec, 0xfb, 0x1b, + 0xe5, 0xf3, 0x02, 0xdc, 0x1b, 0x16, 0x16, 0x03, 0xf5, 0x12, 0x0c, 0xee, 0xef, + 0x05, 0x0f, 0xed, 0x21, 0xc2, 0xfb, 0x31, 0x04, 0xe4, 0xfb, 0xe7, 0xbd, 0x37, + 0xff, 0x07, 0x21, 0xd8, 0x0d, 0x39, 0x0a, 0xf3, 0x02, 0xe7, 0x0c, 0x13, 0xd0, + 0x0e, 0x1f, 0x15, 0xff, 0x06, 0xfc, 0x22, 0xfa, 0x1d, 0x08, 0xc5, 0xeb, 0xfa, + 0xe1, 0xd3, 0xfa, 0xf2, 0xf2, 0xd7, 0x2b, 0xf8, 0x13, 0xe6, 0xfe, 0xd2, 0xfc, + 0xe9, 0x11, 0x4e, 0x14, 0xe8, 0x36, 0xed, 0xdb, 0x12, 0x14, 0x23, 0x0f, 0xb5, + 0xdf, 0x3f, 0x0c, 0xee, 0xf3, 0xcb, 0xcb, 0xec, 0x2f, 0xad, 0x18, 0xeb, 0xc3, + 0xfd, 0x64, 0x08, 0x20, 0x2c, 0x27, 0xfb, 0xcf, 0xd3, 0xfe, 0x49, 0xeb, 0xcc, + 0xe9, 0xc6, 0x27, 0xfc, 0xac, 0xe0, 0xe0, 0xb7, 0x4c, 0xd0, 0xdd, 0xfa, 0x43, + 0xee, 0xa0, 0xa1, 0xb5, 0x0c, 0xd5, 0xd7, 0xa6, 0x06, 0xe8, 0xf4, 0xce, 0x1e, + 0xd5, 0xfb, 0xc5, 0x0f, 0xb3, 0xc2, 0x1a, 0x08, 0xb8, 0xff, 0x44, 0x23, 0x0c, + 0x14, 0xe9, 0x2d, 0xe7, 0x97, 0xd7, 0x2b, 0xe7, 0xac, 0xdc, 0xcb, 0x94, 0xee, + 0x0b, 0x1e, 0x00, 0x50, 0x26, 0x17, 0xf1, 0x2c, 0x38, 0xda, 0x0a, 0x6f, 0xd8, + 0xc9, 0x10, 0x26, 0xe3, 0x0d, 0x19, 0x1a, 0xf1, 0x15, 0xe6, 0xf9, 0xdd, 0xee, + 0xab, 0x20, 0xee, 0xfc, 0xde, 0xdd, 0x16, 0x23, 0x1f, 0x9f, 0x25, 0x2e, 0xe6, + 0x21, 0x0d, 0xc9, 0xfa, 0xcf, 0xe3, 0x01, 0xcf, 0x24, 0x71, 0xa5, 0xf5, 0x2e, + 0xdf, 0x35, 0x17, 0x30, 0xe3, 0xeb, 0x1e, 0x29, 0x16, 0xfb, 0x23, 0xe5, 0x20, + 0xf8, 0x1e, 0xf4, 0xb1, 0xe9, 0xbc, 0x08, 0x20, 0x00, 0x17, 0xcf, 0x03, 0x20, + 0xde, 0xbb, 0xd4, 0xf4, 0xc3, 0xe7, 0x2b, 0xe1, 0xb0, 0x38, 0x01, 0xdf, 0x9d, + 0x73, 0x16, 0x17, 0xc2, 0xe8, 0x47, 0x15, 0xfb, 0xc7, 0x07, 0xfb, 0x49, 0xd3, + 0x09, 0xbb, 0xaa, 0x38, 0x29, 0xef, 0xe6, 0xc9, 0xbf, 0x0c, 0x4b, 0xe0, 0x09, + 0x52, 0x15, 0x0a, 0x94, 0x89, 0xa6, 0xd5, 0xe4, 0xf6, 0x18, 0x04, 0xe1, 0x2a, + 0xda, 0xe6, 0xb4, 0xd1, 0x0b, 0x59, 0xf7, 0xb6, 0xc2, 0x91, 0xec, 0xaf, 0xbb, + 0x3b, 0xcb, 0x22, 0xfc, 0xf8, 0x18, 0xc4, 0xbd, 0x12, 0x81, 0xc0, 0xcd, 0xdf, + 0x09, 0xaa, 0x0d, 0x50, 0xe7, 0xe3, 0x10, 0x28, 0x25, 0x9f, 0xd7, 0xbc, 0xac, + 0x02, 0x3b, 0x00, 0xcd, 0x21, 0xee, 0xf3, 0xdc, 0x16, 0x10, 0xbb, 0x25, 0xae, + 0xe1, 0x22, 0xca, 0xfa, 0x95, 0xf1, 0xd6, 0x38, 0xd7, 0x9e, 0xd8, 0xc9, 0xe8, + 0xd9, 0x10, 0xd9, 0xdb, 0xd7, 0xeb, 0xa2, 0x59, 0x39, 0xd7, 0x08, 0xd7, 0xf1, + 0x9e, 0xef, 0x0c, 0xc6, 0xda, 0x17, 0xef, 0xd9, 0xec, 0xc0, 0x03, 0x09, 0x1e, + 0xea, 0xef, 0x63, 0xfb, 0xdd, 0x89, 0xdf, 0xaa, 0xf6, 0xec, 0x0a, 0x2e, 0x31, + 0xee, 0x2e, 0x90, 0xe8, 0x17, 0xd5, 0x52, 0xde, 0x29, 0xac, 0x0b, 0xfa, 0xf1, + 0xff, 0xb3, 0xb0, 0x01, 0xdf, 0x0f, 0x53, 0xa4, 0xea, 0xd0, 0xe0, 0xb0, 0xc7, + 0x22, 0xf4, 0x1b, 0x7f, 0xbd, 0xe5, 0xe4, 0x93, 0x16, 0xca, 0xf8, 0xb6, 0xee, + 0x01, 0x04, 0x07, 0xf7, 0x07, 0xfc, 0xe4, 0xd1, 0x00, 0xf8, 0xc2, 0xca, 0xfa, + 0x33, 0x03, 0xec, 0xd3, 0xd6, 0x03, 0x0c, 0xce, 0x0a, 0x15, 0xb8, 0xf1, 0x05, + 0xe9, 0x32, 0x95, 0xf0, 0x0c, 0xd8, 0x10, 0x00, 0xcd, 0xe0, 0xbe, 0xf9, 0x11, + 0xac, 0xba, 0xfc, 0x75, 0xe7, 0x27, 0xa8, 0x36, 0xbb, 0xf4, 0x35, 0x32, 0xfc, + 0xb4, 0xdc, 0x0b, 0x1c, 0x50, 0x0e, 0xad, 0xd4, 0xc1, 0xc7, 0xde, 0x05, 0xdc, + 0x41, 0x0e, 0xae, 0xfa, 0x09, 0xf0, 0x96, 0xe0, 0xc1, 0xd7, 0xc6, 0x00, 0x9d, + 0x05, 0xff, 0xec, 0x14, 0xce, 0xe4, 0x09, 0x17, 0x02, 0x04, 0xeb, 0x58, 0xee, + 0x0c, 0x15, 0x19, 0xd7, 0xb1, 0xcd, 0xea, 0x89, 0x8a, 0x12, 0xf5, 0x3c, 0x02, + 0x5b, 0xf8, 0xca, 0x06, 0xa6, 0xc5, 0xec, 0x11, 0xcd, 0x30, 0xe0, 0x04, 0x1e, + 0xf9, 0xc4, 0xe1, 0xae, 0xbe, 0x12, 0x1c, 0x03, 0xfc, 0xf0, 0xa2, 0x3a, 0xae, + 0x0c, 0x6e, 0x0a, 0xe1, 0xe5, 0xeb, 0xba, 0x31, 0xbe, 0x42, 0x27, 0xd5, 0x00, + 0xaa, 0xcc, 0x28, 0xcd, 0x05, 0x09, 0xd3, 0xd0, 0xf4, 0x07, 0xbe, 0x14, 0xf3, + 0x10, 0xf2, 0x18, 0x35, 0x1f, 0x42, 0xe0, 0xf1, 0xeb, 0xd2, 0x24, 0xfc, 0x01, + 0xc7, 0x47, 0x9e, 0x04, 0x17, 0x03, 0xf4, 0xab, 0xe6, 0x96, 0x78, 0xbb, 0xbd, + 0x16, 0xb3, 0x03, 0xca, 0xda, 0x07, 0x09, 0xc9, 0x13, 0xf7, 0x00, 0x14, 0xb8, + 0xc7, 0xee, 0x02, 0x1f, 0x1e, 0xc6, 0x88, 0xe2, 0x3c, 0xd9, 0xf9, 0xb5, 0xfe, + 0x9e, 0x04, 0xe4, 0x01, 0xf4, 0x46, 0x55, 0x0d, 0xe3, 0x22, 0x45, 0xf7, 0xb7, + 0xae, 0x0b, 0x49, 0xe7, 0x43, 0x24, 0x49, 0x3a, 0xd8, 0xd7, 0x49, 0x11, 0x06, + 0x15, 0x12, 0xec, 0x02, 0x4e, 0x61, 0x45, 0xf9, 0xe9, 0x1a, 0x0f, 0x0b, 0x98, + 0xf8, 0x4f, 0x22, 0x2d, 0x1b, 0xc7, 0xf4, 0x21, 0xa2, 0xe0, 0x7f, 0xda, 0xdc, + 0xa3, 0x2b, 0x33, 0xf9, 0x10, 0x1d, 0xe4, 0xc4, 0xd6, 0xb1, 0xd7, 0x05, 0xd7, + 0xa4, 0x1e, 0x42, 0xcc, 0xf2, 0xc6, 0xd4, 0xf3, 0xc2, 0x39, 0x91, 0x21, 0xf9, + 0xd4, 0x24, 0xe1, 0x16, 0xc4, 0xf3, 0xd4, 0xbc, 0xfe, 0x15, 0x11, 0x99, 0xee, + 0xd1, 0x0c, 0x17, 0xe0, 0x29, 0xe0, 0x2e, 0x5f, 0x4f, 0x27, 0xe7, 0x06, 0x36, + 0xcd, 0x41, 0xe4, 0x97, 0x18, 0x31, 0xf7, 0x23, 0x0a, 0x05, 0xfd, 0x9e, 0x17, + 0x27, 0x15, 0x03, 0x0d, 0x19, 0x1a, 0xe6, 0xf1, 0x0e, 0x2b, 0xce, 0xda, 0xc7, + 0xc2, 0xf8, 0xdc, 0xc0, 0xaa, 0x35, 0xb9, 0xba, 0xe4, 0xc2, 0x16, 0x1c, 0x38, + 0xc2, 0xc1, 0x09, 0x23, 0xf5, 0x0a, 0x0d, 0xf3, 0x0b, 0x05, 0x49, 0xdf, 0x05, + 0x0b, 0x22, 0x1d, 0x3f, 0xdd, 0x39, 0x61, 0xc8, 0xc5, 0x70, 0x18, 0xdb, 0x26, + 0x24, 0x8f, 0xbb, 0x5e, 0x47, 0x19, 0x0e, 0xbf, 0xe0, 0x1d, 0xc8, 0xdf, 0x1f, + 0xaf, 0x40, 0x3d, 0x42, 0x46, 0xfb, 0xb2, 0xfb, 0xe5, 0x90, 0x26, 0xe0, 0x19, + 0x3b, 0x13, 0x32, 0x15, 0x54, 0x15, 0xe5, 0xa6, 0x9d, 0xd3, 0xab, 0xc2, 0xf8, + 0xb4, 0x25, 0x10, 0x3a, 0xce, 0x23, 0xf4, 0xa1, 0xcf, 0xff, 0x0f, 0xf8, 0x10, + 0xd8, 0x72, 0x0e, 0xe5, 0xde, 0xd6, 0x0a, 0x32, 0xb8, 0x11, 0xec, 0x9f, 0x19, + 0x12, 0x07, 0xc1, 0x2a, 0xf6, 0x33, 0xc8, 0xfc, 0x0f, 0xf6, 0xf8, 0x19, 0x13, + 0x12, 0xfa, 0x01, 0xce, 0x26, 0xdb, 0x11, 0x1e, 0xbe, 0xe5, 0xd6, 0xdb, 0xfb, + 0xf8, 0x2b, 0x2a, 0x32, 0x34, 0xf4, 0xc5, 0x43, 0x18, 0x06, 0xcb, 0xd5, 0x13, + 0xe1, 0x1b, 0xff, 0x2d, 0x17, 0x0c, 0xee, 0xc0, 0xe0, 0x9c, 0xbe, 0x1d, 0x0c, + 0xff, 0x25, 0x52, 0xed, 0xf3, 0x3d, 0xec, 0xd3, 0x35, 0xe2, 0x0f, 0xcb, 0x52, + 0x0f, 0x1b, 0xd5, 0xee, 0x12, 0x41, 0xdf, 0xf7, 0x1d, 0xdc, 0xd9, 0xd5, 0xf8, + 0xfa, 0xfc, 0xe2, 0x26, 0xf8, 0xd1, 0x3b, 0xd1, 0xf0, 0x18, 0xe9, 0x2f, 0x37, + 0x07, 0xd8, 0xe2, 0xd9, 0x99, 0xdc, 0xf1, 0xec, 0xfc, 0xe3, 0x1b, 0xb5, 0x0c, + 0x2c, 0x34, 0xfb, 0x38, 0x26, 0xe6, 0xa7, 0xd8, 0xbd, 0xd9, 0xe8, 0xe6, 0x21, + 0x08, 0xfd, 0x18, 0x44, 0xf1, 0x0a, 0xae, 0xfd, 0xd6, 0x45, 0x0b, 0xcf, 0x12, + 0xf8, 0xdd, 0xf1, 0x28, 0xd5, 0x0c, 0xec, 0x19, 0x3d, 0xe7, 0xec, 0xf2, 0xf6, + 0xb0, 0x53, 0x1a, 0xe4, 0x20, 0x21, 0x35, 0xf0, 0xd6, 0xcb, 0x15, 0xdc, 0xd7, + 0xff, 0xf9, 0xe1, 0x9e, 0xf6, 0xbd, 0x08, 0xfe, 0xdb, 0xed, 0xd9, 0x10, 0x37, + 0xf1, 0xbf, 0xf6, 0x9a, 0xf0, 0xeb, 0x3a, 0xf8, 0x04, 0xc5, 0xe2, 0xb9, 0x05, + 0x2f, 0x29, 0x11, 0x1f, 0x15, 0xe8, 0x19, 0x0f, 0xd2, 0x18, 0xde, 0x7f, 0x03, + 0x0d, 0xf8, 0xdb, 0xe7, 0xe1, 0xe6, 0xd8, 0x08, 0xcc, 0xd9, 0x29, 0xef, 0xb4, + 0x03, 0x48, 0x29, 0x00, 0x05, 0x0c, 0xf0, 0x26, 0xfa, 0xfd, 0xcf, 0x0f, 0x19, + 0xeb, 0xb6, 0xdd, 0xd6, 0x27, 0x53, 0x13, 0xfa, 0x0a, 0xf4, 0xf8, 0x0b, 0x5f, + 0xfb, 0xcc, 0xe7, 0xb3, 0x21, 0xf9, 0x68, 0x08, 0x63, 0xb5, 0x2d, 0xd1, 0xea, + 0x22, 0xdd, 0x1b, 0x03, 0xe3, 0xcf, 0xa6, 0xe9, 0xd7, 0x1e, 0x0a, 0x1e, 0x3f, + 0xb8, 0x08, 0xca, 0xdb, 0x14, 0x06, 0x3b, 0x64, 0x27, 0x21, 0xcd, 0xb9, 0xf1, + 0x1f, 0xc4, 0x08, 0x05, 0xcf, 0xce, 0xbb, 0xf8, 0x8d, 0xb9, 0xec, 0x5b, 0x56, + 0x6f, 0x0b, 0xe0, 0xcd, 0x21, 0xb8, 0xe0, 0x10, 0xf8, 0xc7, 0x39, 0xea, 0x56, + 0xde, 0x36, 0xb3, 0xf7, 0xeb, 0xde, 0xde, 0x1d, 0xf2, 0x39, 0xd1, 0xb7, 0xf6, + 0xaa, 0x50, 0x01, 0xc8, 0x20, 0xcf, 0xd5, 0x98, 0xca, 0x08, 0xa1, 0xf0, 0x1a, + 0xc5, 0x1b, 0xdc, 0xde, 0x10, 0xce, 0x09, 0x05, 0xba, 0xa8, 0xf2, 0xdf, 0xd9, + 0xed, 0xc2, 0x1d, 0x17, 0xf3, 0xff, 0xca, 0x56, 0x5c, 0xf9, 0x14, 0x95, 0xdc, + 0x14, 0x02, 0x5f, 0x01, 0xc3, 0xf4, 0x42, 0xb1, 0x44, 0xc4, 0x9b, 0xb2, 0xfd, + 0xff, 0x01, 0x2c, 0x01, 0xbc, 0xb7, 0xa1, 0xd1, 0xee, 0x16, 0x2b, 0xe6, 0x50, + 0xef, 0xc8, 0x3b, 0xaa, 0xbb, 0x15, 0xfd, 0xde, 0xfc, 0xe0, 0xee, 0x0a, 0xed, + 0xf2, 0x44, 0x06, 0xab, 0x11, 0xee, 0xe8, 0x05, 0xdb, 0xeb, 0x27, 0xf9, 0xa9, + 0xd3, 0x08, 0xf7, 0x60, 0x3b, 0xf8, 0xe2, 0xe4, 0x07, 0xf4, 0xf7, 0x08, 0xf4, + 0x0c, 0x49, 0x1f, 0xb9, 0xef, 0xd0, 0xc4, 0x6f, 0x05, 0xc1, 0xbc, 0x0f, 0xc0, + 0xbe, 0x33, 0x3f, 0x81, 0xbf, 0xcf, 0xe3, 0x34, 0xd1, 0xfb, 0x2f, 0xe9, 0x28, + 0xe0, 0xf9, 0xba, 0x2c, 0x18, 0xe3, 0x23, 0xfc, 0xf2, 0xa8, 0x16, 0x90, 0x29, + 0xcd, 0x66, 0x0d, 0xd8, 0x21, 0xeb, 0xb5, 0xed, 0x1b, 0xad, 0xfa, 0x33, 0x1b, + 0x3b, 0x9c, 0xbd, 0x0e, 0x9f, 0x11, 0x06, 0xd0, 0xd8, 0xa2, 0x0d, 0xb3, 0x92, + 0xc8, 0x08, 0x22, 0xc4, 0x0a, 0xf9, 0x12, 0xe6, 0x25, 0xd3, 0x2b, 0xeb, 0xea, + 0xfa, 0xbe, 0x09, 0xf6, 0x30, 0x0f, 0xf3, 0x05, 0x18, 0x04, 0xee, 0xef, 0xee, + 0xbc, 0xf1, 0xc4, 0xe0, 0x0c, 0xf5, 0xfe, 0xf5, 0xee, 0xed, 0x05, 0xcd, 0x3e, + 0xd5, 0xd3, 0x15, 0xf1, 0xd7, 0x18, 0xb1, 0x0b, 0xe8, 0xff, 0xc4, 0x37, 0x10, + 0xd7, 0xba, 0xf2, 0x0d, 0xbb, 0xe8, 0x03, 0x36, 0x2e, 0x0d, 0xf0, 0xf3, 0x05, + 0xd8, 0xd1, 0xf0, 0x0f, 0xe4, 0x03, 0xc8, 0xf3, 0x06, 0xe8, 0xf3, 0x06, 0xf8, + 0x0a, 0xdf, 0xc8, 0xf9, 0xfb, 0xd3, 0xd6, 0xfa, 0xf0, 0xd4, 0x16, 0xcd, 0xf8, + 0x2d, 0xfd, 0xe0, 0xfa, 0xab, 0x14, 0xe6, 0x1e, 0xd6, 0x12, 0x32, 0xef, 0x04, + 0xf9, 0xd7, 0xec, 0xce, 0xf7, 0xc8, 0xfa, 0x01, 0x1e, 0x0b, 0x0e, 0xfc, 0xd5, + 0xe5, 0xf4, 0xd5, 0x0e, 0x06, 0xf4, 0xeb, 0xe2, 0xb8, 0xe4, 0xee, 0x0c, 0xd4, + 0xfe, 0xd0, 0xff, 0xe8, 0x10, 0x13, 0xc4, 0xad, 0xed, 0xf7, 0xea, 0xfc, 0xf2, + 0xf8, 0xfa, 0xf4, 0xd7, 0xf4, 0xea, 0xed, 0x22, 0x2c, 0xf8, 0xe9, 0xe5, 0x2e, + 0xda, 0x7f, 0x03, 0xf3, 0xef, 0xf3, 0xc2, 0xe4, 0x39, 0xf3, 0x07, 0x11, 0xc4, + 0xe0, 0xdd, 0x11, 0xe3, 0xf7, 0xe7, 0xf0, 0x1d, 0xf7, 0x11, 0xfb, 0x07, 0x1a, + 0x11, 0x05, 0x07, 0xf3, 0xd5, 0xdc, 0x2c, 0xfe, 0xe6, 0x23, 0xcb, 0x15, 0x09, + 0xc0, 0xc2, 0xdb, 0xe7, 0x1c, 0xea, 0xe0, 0x34, 0xfc, 0x11, 0x04, 0xfd, 0xf2, + 0x0e, 0xaa, 0xce, 0x10, 0x19, 0xe6, 0xff, 0xd4, 0xe1, 0xca, 0xdc, 0xcf, 0x2c, + 0xbc, 0x0d, 0xfe, 0xf6, 0xf1, 0x05, 0xfe, 0xed, 0x35, 0xd6, 0x13, 0x48, 0xdd, + 0x27, 0x0b, 0xdc, 0xfd, 0x0a, 0x23, 0x26, 0xfa, 0xfb, 0x13, 0xe9, 0xd2, 0x18, + 0xe4, 0x4f, 0xbb, 0xcc, 0x21, 0xe6, 0xf3, 0x22, 0x01, 0x04, 0x37, 0x04, 0x09, + 0x51, 0xc9, 0xb5, 0xe3, 0x0b, 0x30, 0xf2, 0x13, 0xf4, 0xe8, 0x13, 0x01, 0xc4, + 0xfe, 0xfc, 0x43, 0x52, 0xcf, 0x20, 0xde, 0xfd, 0xc4, 0xc4, 0xf6, 0xb3, 0x3a, + 0xd9, 0xd7, 0xea, 0xf0, 0xef, 0xed, 0x0b, 0x1c, 0xcf, 0x7f, 0x43, 0x30, 0x25, + 0x3e, 0xce, 0x11, 0xf7, 0xda, 0xce, 0xf5, 0x0d, 0x15, 0x10, 0x0e, 0x1f, 0xfe, + 0x45, 0xd3, 0x26, 0xfb, 0x1f, 0xfc, 0x29, 0x31, 0xf3, 0x17, 0xf9, 0xe4, 0xce, + 0x37, 0x15, 0x07, 0xf0, 0xe2, 0x2e, 0x0a, 0x4f, 0xc7, 0x51, 0xcf, 0xe9, 0xc3, + 0xe2, 0xea, 0x12, 0xea, 0x27, 0xb1, 0xe6, 0x30, 0xe6, 0xd8, 0x09, 0xd9, 0xf5, + 0x07, 0x13, 0xf7, 0xf8, 0xfc, 0xc7, 0x19, 0xf8, 0xe6, 0xd2, 0x00, 0xe0, 0x33, + 0x09, 0x05, 0x13, 0xfa, 0x00, 0xfc, 0x06, 0xad, 0xcc, 0xf8, 0x38, 0x05, 0x05, + 0x35, 0xed, 0x1a, 0x1c, 0xea, 0x15, 0xec, 0xec, 0x04, 0xee, 0xca, 0x17, 0xe9, + 0xf6, 0x3f, 0xf6, 0xde, 0xd5, 0x25, 0x1a, 0x0c, 0x1a, 0xea, 0xd7, 0xd7, 0xdd, + 0x23, 0xf8, 0xaf, 0x07, 0xfa, 0xbb, 0x29, 0x35, 0xd5, 0x02, 0xd0, 0x02, 0xff, + 0xd2, 0x14, 0xc5, 0x4d, 0x1e, 0xe7, 0xe0, 0x1d, 0xc0, 0xfd, 0xd3, 0xcd, 0x4d, + 0x23, 0xca, 0x49, 0x07, 0xff, 0x6f, 0x06, 0x39, 0xdf, 0x17, 0x1d, 0xc5, 0x04, + 0xf1, 0xee, 0xe4, 0xee, 0xfd, 0x05, 0xe9, 0x19, 0x26, 0x17, 0x13, 0xc5, 0xf9, + 0x2c, 0x06, 0x26, 0xea, 0x0c, 0xea, 0x13, 0xb3, 0xb2, 0xdb, 0x0e, 0x09, 0x19, + 0xf7, 0xff, 0x0a, 0xe9, 0x30, 0xdf, 0x20, 0xca, 0xd9, 0xf8, 0x02, 0x0d, 0xd1, + 0xec, 0xf0, 0x11, 0xf3, 0xf8, 0xd6, 0xe6, 0xf6, 0xd4, 0x08, 0x0a, 0xfa, 0xdb, + 0x00, 0x59, 0xdf, 0xef, 0x0a, 0xf8, 0x00, 0xee, 0xea, 0xfe, 0xc0, 0xed, 0x01, + 0xd9, 0x1e, 0x0e, 0x41, 0x20, 0x23, 0x18, 0xfb, 0x1f, 0xf1, 0x11, 0xf4, 0xf2, + 0x34, 0xed, 0xdf, 0xf4, 0xe0, 0xfc, 0xde, 0xff, 0x26, 0xd6, 0xc3, 0x14, 0xdf, + 0xfa, 0xcc, 0xda, 0xdd, 0x12, 0xee, 0x03, 0x02, 0xd0, 0xdb, 0x2d, 0xdb, 0xda, + 0xf3, 0xf8, 0xd4, 0x27, 0xbc, 0xdf, 0x06, 0xf6, 0xff, 0x1b, 0x00, 0xd2, 0x06, + 0x10, 0xfd, 0xfd, 0xeb, 0xff, 0xe9, 0xe5, 0xdd, 0x03, 0xdc, 0x06, 0x3f, 0x45, + 0xfe, 0x08, 0x20, 0x24, 0x2f, 0x1e, 0xf3, 0xf3, 0xc2, 0x20, 0xd0, 0xfc, 0xed, + 0xbf, 0x03, 0xfb, 0xee, 0x04, 0x18, 0xd9, 0xd2, 0x1b, 0xe2, 0xdd, 0xfe, 0xdb, + 0x21, 0x2a, 0xe6, 0xf7, 0x07, 0xd4, 0x04, 0xe3, 0x27, 0x27, 0xdc, 0x03, 0xc8, + 0xed, 0xe0, 0x1b, 0xf7, 0x34, 0xc8, 0xe5, 0xc3, 0x1d, 0xfb, 0x08, 0xeb, 0xd5, + 0xe6, 0x21, 0x11, 0x21, 0xed, 0x2a, 0xc7, 0xd8, 0xe1, 0xfe, 0x0a, 0xe5, 0xb9, + 0x10, 0xff, 0x23, 0x1b, 0xb1, 0xf4, 0xe3, 0xf2, 0x11, 0xe7, 0xd4, 0x0d, 0xfe, + 0x00, 0x21, 0xd6, 0xdd, 0x03, 0xe5, 0xf0, 0x11, 0xf7, 0xed, 0xe1, 0xfc, 0x0c, + 0x09, 0xa9, 0xdf, 0xed, 0xdc, 0xf2, 0xb8, 0xfc, 0xf2, 0x06, 0x3a, 0x32, 0x1f, + 0xfb, 0xac, 0xe0, 0xec, 0x01, 0x2f, 0xdd, 0xcd, 0x0e, 0xcc, 0x16, 0x2f, 0x20, + 0x2e, 0x03, 0xf4, 0x1f, 0xdf, 0xbf, 0xd8, 0x14, 0x0a, 0x0b, 0xe4, 0xf8, 0xec, + 0xd7, 0xe2, 0xe0, 0xe6, 0xfa, 0xf6, 0xcd, 0xf9, 0xd5, 0xcc, 0xe2, 0xfd, 0x16, + 0xf9, 0xea, 0x0c, 0xc6, 0xcc, 0x26, 0xd3, 0xec, 0xea, 0xed, 0x08, 0xe2, 0xee, + 0xe4, 0x00, 0xe2, 0xfa, 0xe1, 0x0e, 0x0d, 0xfe, 0x29, 0xc9, 0x1d, 0x1d, 0x0d, + 0xfb, 0x26, 0xfd, 0x0e, 0x22, 0xf4, 0xe8, 0xc3, 0x5d, 0xe4, 0xff, 0x7f, 0x2f, + 0x20, 0xee, 0xc8, 0xe7, 0xf7, 0xcc, 0x0b, 0xe3, 0x0f, 0xa5, 0xd0, 0xcd, 0x08, + 0xe6, 0xff, 0xc7, 0x01, 0x12, 0xe8, 0xe2, 0xd6, 0xf2, 0xfc, 0xf2, 0x06, 0xf1, + 0xa2, 0xfa, 0xc7, 0xd5, 0xdd, 0xc9, 0xcb, 0xe5, 0xe5, 0xd2, 0xfb, 0xf0, 0x00, + 0xe0, 0xfc, 0x04, 0xf4, 0xd6, 0x40, 0x1a, 0xa2, 0xee, 0xe7, 0x15, 0xd4, 0x16, + 0xdd, 0xf8, 0x00, 0xd0, 0xe2, 0x3c, 0xec, 0xe4, 0xe3, 0xde, 0xf4, 0x04, 0xc3, + 0xd7, 0x11, 0x28, 0xed, 0xd2, 0xa6, 0xe1, 0x21, 0xe7, 0xf3, 0x3a, 0x07, 0x1e, + 0x72, 0x38, 0x09, 0xea, 0xf0, 0xf4, 0x08, 0xf2, 0xd4, 0x01, 0xcf, 0x1a, 0xd1, + 0xfb, 0x3e, 0xc6, 0xf1, 0x30, 0xe4, 0xeb, 0x38, 0xb3, 0xf7, 0x18, 0xd7, 0xe6, + 0xf6, 0x19, 0xfe, 0x04, 0xc5, 0x2f, 0xf6, 0xf2, 0xe5, 0xe4, 0xca, 0x08, 0xfd, + 0x5f, 0xbf, 0x09, 0xb3, 0xfc, 0xea, 0xcf, 0xc7, 0xe0, 0xac, 0x2f, 0x1c, 0x36, + 0x20, 0xf6, 0xb2, 0xc2, 0xa2, 0x0d, 0x05, 0xdf, 0xc3, 0x1f, 0xc9, 0xf3, 0xfa, + 0xb7, 0x3b, 0x05, 0x19, 0xb1, 0xf2, 0xe6, 0xf5, 0x07, 0x1d, 0xeb, 0xc0, 0xa6, + 0xb5, 0xea, 0xd9, 0xf7, 0xf0, 0xf9, 0x05, 0xf6, 0xff, 0x2d, 0xf2, 0xc9, 0x02, + 0xd3, 0x03, 0xbb, 0xb2, 0xe2, 0xe0, 0x38, 0x40, 0xcd, 0xf7, 0xda, 0x20, 0xd4, + 0x26, 0x0d, 0x32, 0xb4, 0x13, 0xbb, 0x19, 0x6f, 0xf6, 0xe7, 0xbf, 0xe1, 0x19, + 0xaf, 0x14, 0xc5, 0x3c, 0xfd, 0xdd, 0xf7, 0xef, 0xcc, 0x08, 0xce, 0xd4, 0xf5, + 0x04, 0xc2, 0xc9, 0x02, 0xaa, 0xc3, 0xb3, 0xc6, 0x19, 0xfe, 0x0f, 0x28, 0xe4, + 0x81, 0x13, 0x17, 0xf8, 0xbd, 0x14, 0x08, 0x2d, 0xfb, 0x3d, 0xf7, 0x07, 0x0f, + 0x12, 0xe5, 0xda, 0xcb, 0x41, 0xda, 0x2b, 0xf4, 0x19, 0xcd, 0x2d, 0x38, 0x10, + 0x19, 0x2a, 0x16, 0xd1, 0xdd, 0xda, 0xd7, 0x23, 0x13, 0x0c, 0xe6, 0xda, 0x93, + 0xe3, 0xc2, 0xcd, 0xe1, 0xe4, 0xe8, 0xe8, 0x07, 0xf6, 0x19, 0x0c, 0xd1, 0x14, + 0x09, 0xd8, 0xc4, 0x20, 0x0d, 0xc6, 0x0b, 0xcf, 0x00, 0x00, 0xfc, 0xea, 0xde, + 0xaa, 0x0f, 0x0d, 0x19, 0x95, 0xe7, 0x44, 0xb3, 0x2c, 0xcc, 0x38, 0x39, 0xdc, + 0xc1, 0xe0, 0x1f, 0xd7, 0xd0, 0x07, 0xbc, 0x30, 0x3f, 0x0a, 0xde, 0xea, 0xe7, + 0xf1, 0xc2, 0xf2, 0x1c, 0xb2, 0xee, 0xee, 0xb0, 0xea, 0xdc, 0xcf, 0x95, 0x17, + 0xe8, 0x4f, 0xce, 0x49, 0xb9, 0xdd, 0x0f, 0xe9, 0x02, 0x32, 0xa9, 0xf0, 0xe8, + 0x19, 0x32, 0x10, 0xfa, 0x09, 0xbd, 0xd4, 0x01, 0x1d, 0xf8, 0x23, 0xec, 0xde, + 0xae, 0xe8, 0xd3, 0x14, 0xe4, 0x31, 0xfd, 0x56, 0xeb, 0xb9, 0x03, 0x06, 0xeb, + 0x32, 0xd8, 0xe5, 0x1f, 0x35, 0x53, 0xfe, 0xda, 0x0c, 0xb1, 0xdb, 0xc1, 0xcd, + 0x53, 0xe6, 0x16, 0xfb, 0xf3, 0xd7, 0xde, 0x01, 0xc8, 0xef, 0x23, 0x2e, 0xda, + 0xdf, 0xc0, 0xc9, 0xe4, 0xf0, 0xe1, 0xcb, 0xe7, 0x7f, 0xf5, 0xe8, 0xe2, 0x14, + 0x17, 0x2f, 0xe1, 0xda, 0xcb, 0xa2, 0x2d, 0x0b, 0xfb, 0xee, 0x10, 0x20, 0xf6, + 0x0f, 0x15, 0xfd, 0x11, 0xd4, 0x50, 0xec, 0xfb, 0xf7, 0xd8, 0xb3, 0xe6, 0xe2, + 0xbe, 0x3a, 0x32, 0xf1, 0xf2, 0x36, 0xc3, 0xaa, 0x27, 0xf9, 0x31, 0x41, 0xf6, + 0xd7, 0x0d, 0x07, 0xc8, 0xee, 0xfc, 0x13, 0x00, 0xeb, 0x1c, 0xe5, 0x08, 0x1f, + 0x17, 0xf7, 0xf1, 0xee, 0xe2, 0x1a, 0xf9, 0xcc, 0xec, 0x95, 0x26, 0xee, 0x03, + 0xf1, 0xbf, 0x0e, 0x1c, 0x46, 0xf6, 0x16, 0x1c, 0xf6, 0xd4, 0x1a, 0xfa, 0xef, + 0x0d, 0x44, 0xe4, 0x3e, 0x6d, 0x3f, 0x1c, 0x43, 0xd8, 0xfd, 0x3a, 0xcb, 0xe8, + 0x06, 0xfc, 0xf6, 0x07, 0x3f, 0xfa, 0xef, 0xc1, 0xb7, 0xfd, 0x0b, 0x3c, 0x0f, + 0xe1, 0x0b, 0xe1, 0xef, 0x9b, 0xd3, 0x95, 0x1d, 0xf3, 0xf5, 0xf1, 0xff, 0x16, + 0x02, 0xf4, 0x15, 0xf5, 0xa6, 0xd5, 0xf6, 0x03, 0x1c, 0x3a, 0xfd, 0xe0, 0x05, + 0xff, 0x0e, 0xda, 0xce, 0xc0, 0xdd, 0xcd, 0xe2, 0xdf, 0xba, 0x14, 0xc7, 0xf9, + 0xf8, 0x12, 0xfd, 0xe3, 0x31, 0xe5, 0x8e, 0xfb, 0x07, 0xf0, 0xf9, 0xf3, 0xd5, + 0xd5, 0x08, 0xa6, 0x01, 0x11, 0x33, 0x23, 0x24, 0x45, 0x4e, 0x3a, 0x0d, 0x20, + 0xd7, 0x1e, 0x39, 0x19, 0xd7, 0xfd, 0xa0, 0xc6, 0xe5, 0xe7, 0xd3, 0xba, 0x11, + 0xfc, 0x2a, 0xfe, 0x19, 0xf0, 0xcb, 0xce, 0xe1, 0xdd, 0x35, 0x0c, 0x3c, 0xf2, + 0xf9, 0x07, 0x17, 0xc1, 0xf9, 0xd5, 0x06, 0x11, 0x87, 0xf1, 0x0d, 0x0d, 0xee, + 0xf1, 0xdb, 0xa5, 0x12, 0xe6, 0xd2, 0x29, 0x37, 0xd9, 0xe4, 0xcb, 0x38, 0xc4, + 0x2a, 0x14, 0xbf, 0xc2, 0x2b, 0x0e, 0xe6, 0xda, 0xd7, 0xce, 0xf6, 0xf7, 0x39, + 0x1d, 0xfb, 0x01, 0xfe, 0xe9, 0xb2, 0xde, 0x99, 0xfb, 0x38, 0x24, 0xbc, 0xe9, + 0xd6, 0xc8, 0x1f, 0xbb, 0x55, 0xfc, 0xe2, 0xdc, 0x33, 0xde, 0x01, 0x08, 0x0e, + 0x19, 0xe9, 0x20, 0x33, 0xfb, 0x9b, 0xdd, 0x0c, 0xbb, 0xf2, 0xc6, 0x1d, 0xbc, + 0x16, 0x1a, 0xd9, 0xc6, 0x81, 0x35, 0xfd, 0xe8, 0x1e, 0x25, 0xbb, 0x27, 0xd0, + 0x16, 0xe4, 0xd9, 0x39, 0xad, 0xa0, 0xd3, 0xe1, 0x20, 0xfa, 0x01, 0xee, 0x08, + 0xdb, 0xdc, 0x6a, 0x2f, 0xc1, 0x43, 0xf0, 0x01, 0x07, 0xb1, 0xc6, 0xa7, 0x32, + 0x02, 0xcf, 0x20, 0x06, 0x48, 0x28, 0x11, 0xc4, 0xec, 0x6b, 0xd0, 0x14, 0xee, + 0x6a, 0x26, 0xd7, 0xf2, 0x46, 0xff, 0x29, 0xa5, 0xdf, 0xe1, 0xdc, 0xd6, 0x11, + 0xd8, 0x08, 0xe9, 0xf2, 0x0e, 0xdc, 0x89, 0xdf, 0xe6, 0x14, 0xec, 0x3a, 0x10, + 0x3e, 0xed, 0xe2, 0x20, 0x3e, 0x13, 0xf9, 0xba, 0xfe, 0xd7, 0xca, 0xf2, 0x44, + 0x1f, 0x04, 0x14, 0xc1, 0xfb, 0x0b, 0xf2, 0x66, 0xc8, 0xf8, 0x45, 0x0b, 0x36, + 0x1b, 0xd1, 0x28, 0x1c, 0x00, 0x0b, 0x14, 0xb5, 0xfa, 0xd3, 0xf6, 0x2a, 0xd4, + 0xcc, 0xc9, 0xaf, 0xd8, 0xca, 0x06, 0x26, 0x02, 0xd1, 0xde, 0xc5, 0x02, 0xc0, + 0xf0, 0x1d, 0x32, 0x31, 0xd4, 0x2f, 0xf9, 0xf3, 0xe2, 0x1f, 0x97, 0xb8, 0x1d, + 0xc4, 0x2d, 0xfe, 0xbe, 0xfa, 0xce, 0xd8, 0x15, 0xea, 0xbd, 0xda, 0x56, 0xd7, + 0x09, 0xca, 0x23, 0x14, 0xbf, 0x5c, 0x52, 0x1b, 0x3b, 0xe4, 0x19, 0xf1, 0xec, + 0x15, 0xfb, 0xa7, 0xb7, 0xe2, 0xdf, 0xd8, 0xe8, 0x23, 0x2a, 0x1d, 0x04, 0x1b, + 0x20, 0xf0, 0xf3, 0x83, 0x2e, 0xdb, 0xf6, 0x99, 0xfd, 0x33, 0x09, 0xf1, 0x3b, + 0xfd, 0x20, 0xd7, 0x96, 0x04, 0x01, 0x2b, 0xd1, 0x0b, 0x32, 0x4b, 0x29, 0x20, + 0xfa, 0x0e, 0xcd, 0xdd, 0x4c, 0xae, 0x00, 0xaf, 0x0b, 0xf5, 0xe5, 0x03, 0xdb, + 0x99, 0xc5, 0xe6, 0xf5, 0x81, 0xe7, 0x0b, 0x11, 0xc2, 0x1f, 0xf6, 0xfb, 0x2f, + 0x47, 0x40, 0xff, 0x1f, 0xfe, 0xdc, 0xc6, 0xc5, 0xed, 0x04, 0x1e, 0x27, 0x12, + 0xc3, 0x2f, 0x1d, 0x23, 0xfe, 0xed, 0x41, 0x3f, 0xfb, 0x09, 0xf8, 0xf1, 0xf4, + 0xff, 0xc7, 0xc5, 0x1b, 0xdb, 0x01, 0x8c, 0x0e, 0xf2, 0x36, 0xf3, 0xfc, 0xcd, + 0xd2, 0xfb, 0x0a, 0x15, 0x46, 0x25, 0x03, 0xfe, 0xeb, 0xca, 0xba, 0x11, 0x19, + 0xec, 0xba, 0x04, 0xba, 0x25, 0xef, 0x1c, 0xfb, 0x09, 0x0e, 0x22, 0x1e, 0xda, + 0x01, 0xf9, 0x36, 0xec, 0x24, 0xbd, 0xed, 0x10, 0xee, 0x19, 0xb7, 0xa8, 0xf2, + 0xe0, 0x9a, 0x12, 0xdb, 0xb9, 0xf9, 0xbd, 0xc8, 0x10, 0x24, 0x06, 0x8f, 0xeb, + 0x0c, 0x19, 0xd9, 0x0a, 0x8f, 0xd7, 0xc1, 0x0a, 0xd9, 0x43, 0x0d, 0xb6, 0x03, + 0xe5, 0x09, 0x2e, 0xfd, 0xdc, 0xd1, 0xf9, 0xa1, 0xd7, 0x10, 0xc0, 0xf8, 0x0f, + 0xe2, 0x15, 0x30, 0x15, 0x25, 0xed, 0xf7, 0x1e, 0x2a, 0xb3, 0xdb, 0x48, 0x21, + 0x01, 0xf0, 0x04, 0xc1, 0x05, 0xfd, 0x20, 0xd4, 0xe4, 0x04, 0xc3, 0x01, 0xde, + 0xe2, 0xe0, 0x03, 0xef, 0xd2, 0x22, 0x0d, 0x29, 0xfb, 0xca, 0xf1, 0xe5, 0x11, + 0x07, 0xe3, 0xe3, 0xe9, 0x3a, 0xad, 0x06, 0x13, 0xfc, 0xca, 0x39, 0xd0, 0xf2, + 0xf4, 0x0f, 0x0f, 0x1d, 0xd4, 0xf5, 0xd4, 0x1c, 0xc5, 0x2f, 0x0f, 0xdd, 0x01, + 0x0b, 0xc7, 0xfd, 0xfe, 0x20, 0x24, 0x24, 0x2d, 0xe8, 0x13, 0x1f, 0x1a, 0xfa, + 0xfc, 0x11, 0xe9, 0x25, 0x07, 0x05, 0xf9, 0xea, 0x11, 0xd4, 0xac, 0x17, 0x07, + 0x26, 0x04, 0xf9, 0xc0, 0xe1, 0xf9, 0x00, 0xc3, 0x04, 0xc1, 0xfb, 0x25, 0xe3, + 0xf6, 0x1b, 0xf0, 0x12, 0xf1, 0xf8, 0xd0, 0xf1, 0x1b, 0xe2, 0x08, 0x32, 0xf1, + 0x15, 0xf2, 0xb8, 0xe4, 0xe3, 0x12, 0xef, 0xd2, 0xd9, 0xdc, 0xf4, 0xbe, 0x1d, + 0x08, 0x19, 0x13, 0xdc, 0xd0, 0x20, 0xf5, 0xdc, 0xd9, 0x29, 0xeb, 0xee, 0xc8, + 0x1b, 0xb3, 0x0b, 0x0c, 0xda, 0xd8, 0x20, 0xfa, 0xc8, 0xeb, 0x0e, 0x1d, 0xe8, + 0xd8, 0xd0, 0x20, 0x2b, 0xf4, 0x31, 0x19, 0x22, 0xce, 0x1d, 0x23, 0xed, 0xe7, + 0x1a, 0xcb, 0xd6, 0xe0, 0xea, 0x09, 0x0b, 0xbd, 0xf3, 0x09, 0xd0, 0x07, 0xd5, + 0x16, 0xf1, 0xfa, 0xfa, 0x09, 0xce, 0xf0, 0x1b, 0xe9, 0x43, 0xf8, 0xe5, 0xfd, + 0x05, 0xdd, 0x31, 0xfa, 0x0d, 0x16, 0x08, 0xfa, 0xd0, 0x06, 0x49, 0xcd, 0xf3, + 0xd1, 0x06, 0xf4, 0xf5, 0xf2, 0x25, 0xef, 0x03, 0x32, 0x45, 0x96, 0x22, 0x24, + 0x08, 0xe8, 0x37, 0xb6, 0x06, 0x1f, 0xda, 0xf3, 0xd8, 0xc9, 0x0d, 0xd5, 0xcb, + 0xac, 0xdd, 0x01, 0x09, 0x09, 0x12, 0x19, 0xba, 0xfa, 0x09, 0xd8, 0x11, 0x04, + 0x16, 0xec, 0x25, 0xf0, 0xe2, 0x30, 0x04, 0xeb, 0x0b, 0xfc, 0xd8, 0xec, 0x05, + 0x10, 0xf4, 0x01, 0x0f, 0x08, 0x06, 0xfd, 0xf6, 0x7f, 0x10, 0xf2, 0xf8, 0xd9, + 0x0e, 0x04, 0x1b, 0x1c, 0xfa, 0x1e, 0xc6, 0xf0, 0xa6, 0x0f, 0x2d, 0xdb, 0xc3, + 0x5c, 0xb3, 0xf0, 0xcd, 0x31, 0x68, 0x04, 0xee, 0x1b, 0xe0, 0x01, 0xfc, 0x16, + 0xe6, 0xf7, 0xf8, 0x2d, 0xaa, 0xfa, 0xe2, 0x07, 0x02, 0xc3, 0xdf, 0xd1, 0xe6, + 0x23, 0xe4, 0x01, 0x00, 0x36, 0xa5, 0x03, 0xdc, 0xd2, 0xc5, 0xda, 0xe0, 0xca, + 0xf3, 0xba, 0xee, 0xf9, 0xec, 0x41, 0x55, 0x38, 0x00, 0x01, 0x9b, 0x17, 0xbd, + 0x41, 0x08, 0xde, 0xbc, 0x26, 0x31, 0xef, 0xf9, 0xda, 0x0b, 0x32, 0xcf, 0xd9, + 0x08, 0xd6, 0x0e, 0x56, 0x21, 0x2d, 0x28, 0xec, 0x01, 0x0a, 0xc1, 0x71, 0xf6, + 0x23, 0xf7, 0xe3, 0x04, 0xe2, 0xf7, 0x23, 0x81, 0xd4, 0x0b, 0xf5, 0x0e, 0x33, + 0xae, 0xed, 0x0e, 0xe5, 0xfd, 0x2d, 0x2f, 0x26, 0xb3, 0xe8, 0xd0, 0xf6, 0xd2, + 0xf9, 0xc8, 0xe5, 0xec, 0x12, 0xd3, 0xe9, 0x09, 0xf0, 0x16, 0x02, 0x9f, 0xee, + 0x05, 0xe2, 0x08, 0x03, 0xbe, 0xce, 0xc6, 0x61, 0x0b, 0x0e, 0x0e, 0x07, 0x13, + 0x2b, 0x13, 0xdf, 0xe8, 0x9d, 0x07, 0xb8, 0x0d, 0x9b, 0xec, 0xbe, 0xd4, 0x51, + 0x21, 0x15, 0xb9, 0xec, 0x08, 0xa3, 0xfc, 0x54, 0x2b, 0xed, 0xed, 0x0f, 0xec, + 0x13, 0xfe, 0x03, 0xe9, 0xdb, 0x3a, 0xaf, 0xad, 0xde, 0x42, 0xfb, 0xff, 0xe6, + 0x07, 0x48, 0xf8, 0xeb, 0xdb, 0xd1, 0x20, 0xe8, 0xaf, 0x3e, 0xad, 0xe4, 0xed, + 0xe8, 0xf1, 0xea, 0xf8, 0x06, 0xfe, 0xb4, 0x2b, 0xb9, 0xe6, 0x06, 0xf8, 0xd6, + 0xd7, 0xf7, 0xf4, 0xf0, 0x11, 0x0a, 0xf5, 0x1c, 0xe4, 0xd4, 0xde, 0x9a, 0x1e, + 0xf5, 0x30, 0xca, 0x26, 0xec, 0xd1, 0x07, 0x05, 0xdf, 0xb8, 0x0f, 0xd5, 0xc2, + 0x1d, 0x26, 0xe2, 0xc9, 0xbc, 0xc9, 0x89, 0xe3, 0xb5, 0xfb, 0x16, 0x98, 0xdb, + 0xc8, 0xd1, 0xf0, 0x06, 0x97, 0x27, 0x0d, 0x0b, 0x1d, 0xfb, 0xfd, 0x1f, 0x11, + 0x44, 0xd7, 0xce, 0x00, 0x39, 0xe4, 0xf3, 0x15, 0x13, 0xf8, 0x1c, 0xd7, 0x0b, + 0xf0, 0xf2, 0x25, 0x0b, 0xe6, 0x07, 0xf1, 0xe6, 0xf3, 0x02, 0x00, 0x25, 0xe5, + 0xfd, 0x23, 0x14, 0xd3, 0x0a, 0xe5, 0x05, 0x13, 0x43, 0xe3, 0xee, 0xe2, 0xe6, + 0xf5, 0xf9, 0xfd, 0x24, 0xd2, 0x20, 0x29, 0xde, 0x0b, 0xfa, 0x10, 0xd8, 0xe4, + 0xfa, 0xd3, 0x05, 0xf3, 0x24, 0xdc, 0x02, 0xe8, 0xe8, 0xf0, 0xf0, 0x2c, 0xdb, + 0xd9, 0x1c, 0xf2, 0xfc, 0xf0, 0x08, 0x17, 0xf4, 0xe0, 0xeb, 0x0f, 0xe9, 0xff, + 0x0a, 0xfb, 0xf7, 0xe7, 0x05, 0x0e, 0x10, 0x05, 0x2c, 0x06, 0xd9, 0x08, 0x02, + 0x0c, 0x35, 0x08, 0x17, 0xf6, 0xf8, 0x08, 0x17, 0xdf, 0xef, 0xfb, 0x0d, 0xb6, + 0xc1, 0x01, 0x35, 0xf5, 0xd2, 0xfe, 0xe2, 0x1c, 0xfb, 0xe1, 0xe7, 0x16, 0x0b, + 0x0b, 0xeb, 0x1a, 0x15, 0xd0, 0x00, 0xdd, 0x24, 0xf4, 0xf8, 0xed, 0x29, 0xf5, + 0x19, 0x09, 0x0e, 0xe8, 0xef, 0x1d, 0xf1, 0xdd, 0xe3, 0xd1, 0x6b, 0xf1, 0xf4, + 0x09, 0xf5, 0x1d, 0x57, 0xd9, 0x7f, 0x04, 0x15, 0xf9, 0x0a, 0xdb, 0xd4, 0xea, + 0xc7, 0xf6, 0x07, 0x06, 0xde, 0xfe, 0xed, 0x12, 0xf2, 0x6f, 0x14, 0xf6, 0xca, + 0x05, 0xdf, 0x1e, 0x17, 0x07, 0xe7, 0xf8, 0xd6, 0xf3, 0xed, 0x11, 0xd2, 0x22, + 0x1a, 0x1f, 0xf2, 0xf3, 0xe2, 0x0f, 0x11, 0xea, 0xfa, 0x6f, 0xeb, 0xec, 0xf5, + 0xee, 0x02, 0xd7, 0xfe, 0xc7, 0x19, 0xf1, 0x0e, 0x03, 0x05, 0xfc, 0xd7, 0xc6, + 0xf5, 0x07, 0x44, 0xf7, 0x02, 0x0e, 0xfc, 0x17, 0xe2, 0xf0, 0x1b, 0xf9, 0xf5, + 0xe6, 0xf8, 0xea, 0xf2, 0x0d, 0x19, 0x04, 0x1a, 0xed, 0x0f, 0xe8, 0xdc, 0xd9, + 0xfc, 0x0c, 0xf6, 0xf7, 0x19, 0x5d, 0xf0, 0x1d, 0x4e, 0x1f, 0x18, 0xe4, 0xd5, + 0x14, 0xf9, 0xf7, 0xf1, 0xab, 0x6b, 0xd7, 0x0c, 0xfe, 0xfa, 0xc0, 0x9d, 0xca, + 0x07, 0xd8, 0x1f, 0xf3, 0xfa, 0x09, 0xba, 0xdd, 0x09, 0x1e, 0x18, 0x0d, 0xf4, + 0x30, 0x39, 0xef, 0xf6, 0xf8, 0xd6, 0x2b, 0xd5, 0xf6, 0xb8, 0xdb, 0x0e, 0xd2, + 0xf6, 0x4a, 0xf9, 0x19, 0x06, 0xf1, 0xaa, 0xee, 0xc6, 0xdc, 0x21, 0x13, 0x5b, + 0x3d, 0x23, 0xc4, 0x30, 0x1f, 0x3d, 0x41, 0x06, 0xea, 0xe2, 0x17, 0x20, 0xd6, + 0xef, 0x81, 0x13, 0x1d, 0x1b, 0x01, 0xce, 0xf7, 0xf1, 0x43, 0x2d, 0x00, 0xe6, + 0x1d, 0xc3, 0xed, 0x07, 0xd3, 0x0b, 0x2d, 0xef, 0xed, 0x1b, 0xe7, 0x30, 0xc8, + 0xd3, 0xf2, 0x08, 0x03, 0xb7, 0xec, 0xdc, 0x1c, 0xb0, 0xcc, 0x56, 0x22, 0x48, + 0xaa, 0x07, 0xe5, 0xe2, 0x0a, 0x07, 0xf8, 0xbe, 0x3c, 0xe1, 0x25, 0xc4, 0x34, + 0xef, 0xa6, 0x1e, 0xfd, 0xba, 0xaf, 0x05, 0xda, 0x3b, 0xef, 0xba, 0x02, 0xd8, + 0x14, 0x31, 0x15, 0x00, 0x08, 0xba, 0xf6, 0xe7, 0xff, 0x32, 0x31, 0xd4, 0x1b, + 0xf0, 0x08, 0x1f, 0x9c, 0xf9, 0x1c, 0xde, 0xdf, 0x0d, 0xe0, 0xe8, 0x47, 0xd8, + 0x22, 0x04, 0x09, 0xec, 0xfc, 0x0b, 0x14, 0xc8, 0xed, 0xe8, 0xd2, 0xb2, 0xa9, + 0x15, 0xea, 0xf0, 0x13, 0xfd, 0xff, 0xf0, 0xda, 0xf9, 0xf2, 0x0f, 0x10, 0xfc, + 0x11, 0xf5, 0x16, 0x3f, 0x01, 0x01, 0x19, 0x22, 0x38, 0x02, 0xbb, 0xf6, 0x13, + 0x4a, 0x23, 0x17, 0x11, 0x40, 0xd2, 0xcb, 0x19, 0x0b, 0xfb, 0xf0, 0xef, 0x30, + 0x1d, 0x1b, 0xca, 0xde, 0x22, 0xeb, 0x02, 0x17, 0xc0, 0xb0, 0x21, 0x07, 0x2f, + 0x00, 0xe5, 0xb2, 0xed, 0x83, 0x20, 0xdb, 0x41, 0x04, 0x0a, 0xee, 0xc8, 0xe7, + 0x09, 0xf8, 0xf4, 0x10, 0x30, 0xda, 0x0a, 0x14, 0xfa, 0xbf, 0xf9, 0xce, 0x15, + 0xf1, 0xfc, 0xbd, 0x1e, 0x17, 0xf4, 0xe0, 0xe6, 0xcd, 0xfd, 0x29, 0x25, 0x02, + 0xcd, 0xc7, 0xb6, 0xe5, 0x06, 0x01, 0xd6, 0x1c, 0xfd, 0xfa, 0x18, 0xfd, 0xc8, + 0xc3, 0x17, 0xe2, 0x1f, 0xc8, 0xe7, 0x36, 0xc4, 0xef, 0xf2, 0xd4, 0xd2, 0x14, + 0x21, 0x06, 0x07, 0xfc, 0x06, 0x04, 0xf0, 0xc5, 0x11, 0xc6, 0x19, 0x09, 0x30, + 0xf9, 0x12, 0xfe, 0xf4, 0xfd, 0xf7, 0xf5, 0x13, 0x1c, 0xfe, 0xd4, 0xd8, 0x08, + 0x28, 0x23, 0xf5, 0x05, 0x13, 0xfb, 0x01, 0x6a, 0x1c, 0xe0, 0xea, 0xfb, 0x23, + 0xf9, 0x0a, 0x04, 0x3d, 0xf2, 0x19, 0x0a, 0xcf, 0x0b, 0x00, 0xd5, 0x12, 0xdd, + 0x12, 0x2c, 0xe1, 0x18, 0x29, 0x02, 0x1b, 0x08, 0x08, 0xee, 0xda, 0xd6, 0x1c, + 0xf6, 0x1d, 0xb8, 0xaa, 0xd9, 0xf3, 0x0e, 0xf6, 0xef, 0xd1, 0xf6, 0xf4, 0xb5, + 0xfd, 0xd9, 0xdd, 0xf8, 0x38, 0x0b, 0xeb, 0xe5, 0xfe, 0x00, 0xf9, 0xcb, 0xec, + 0x0c, 0xf0, 0xf2, 0x0f, 0xf9, 0xcd, 0xd1, 0x31, 0xd0, 0xcc, 0xe7, 0x2a, 0xd4, + 0xee, 0xf4, 0xaa, 0xe9, 0x06, 0xe7, 0xea, 0xee, 0xe8, 0xff, 0xf3, 0xe3, 0xf8, + 0x10, 0xc8, 0xed, 0x01, 0xd0, 0xee, 0x02, 0xe7, 0x03, 0xc1, 0xe4, 0xd3, 0xba, + 0x1c, 0x25, 0x49, 0xe4, 0xf1, 0xdf, 0xf6, 0xbd, 0x49, 0x0b, 0xbb, 0x03, 0xe9, + 0xfb, 0x4b, 0x1b, 0xf4, 0x7f, 0xe0, 0x27, 0xd2, 0x04, 0x0d, 0x08, 0xcc, 0xbf, + 0xf9, 0xed, 0xee, 0xed, 0x54, 0xc1, 0xf3, 0x04, 0xb5, 0xce, 0xe7, 0xc5, 0xf6, + 0xea, 0xcd, 0x09, 0x0f, 0xfe, 0x37, 0xdd, 0x0e, 0x0b, 0xf8, 0x09, 0xbf, 0xf8, + 0xcc, 0xe7, 0xf8, 0x43, 0xfe, 0x0d, 0xfb, 0xe7, 0xdf, 0xf5, 0x3a, 0xc6, 0x29, + 0x29, 0xfc, 0x31, 0xf3, 0xf0, 0x10, 0xd9, 0xd8, 0x05, 0xcb, 0x02, 0xee, 0x08, + 0x1d, 0x53, 0x06, 0x1c, 0xe3, 0xe4, 0xed, 0xd8, 0xcf, 0xeb, 0x3b, 0xeb, 0x3b, + 0x0b, 0xdb, 0x46, 0xc8, 0x05, 0x2a, 0xe5, 0x04, 0x0f, 0x99, 0x43, 0xba, 0x3a, + 0xfd, 0xf5, 0xd5, 0xee, 0x44, 0x30, 0xe8, 0x18, 0xf6, 0xe3, 0xf1, 0xf6, 0x25, + 0xe3, 0x0e, 0x43, 0x35, 0xfd, 0xc0, 0x0c, 0xf8, 0x59, 0xe3, 0x00, 0xf7, 0x11, + 0xcd, 0x1b, 0xd1, 0xef, 0x34, 0xd4, 0x93, 0x07, 0x2f, 0xf0, 0xe6, 0xda, 0xc7, + 0xf4, 0xc7, 0xd2, 0xeb, 0x15, 0xef, 0xf1, 0xe1, 0x5e, 0xce, 0x29, 0x12, 0x3f, + 0xde, 0xef, 0x2a, 0x19, 0x25, 0xe6, 0xf8, 0x07, 0x0a, 0x54, 0x3f, 0xf4, 0xf3, + 0xcf, 0xeb, 0xed, 0xd3, 0x1d, 0xc7, 0xcf, 0x24, 0xe6, 0xdb, 0x17, 0x0d, 0x56, + 0xd4, 0xc6, 0xeb, 0x23, 0xaf, 0xb2, 0x19, 0xea, 0x3e, 0x31, 0xe7, 0x17, 0x05, + 0xcb, 0xcf, 0x5d, 0x05, 0x05, 0x32, 0xfc, 0xeb, 0xd2, 0x0c, 0xd5, 0xf6, 0x15, + 0xda, 0xd4, 0x15, 0xd9, 0xba, 0xcd, 0x07, 0xd1, 0xf7, 0x30, 0xe0, 0x12, 0x1c, + 0xd5, 0xcf, 0xc1, 0x2a, 0xe1, 0x00, 0x9f, 0xb1, 0x10, 0xf2, 0xf6, 0x27, 0x03, + 0x7f, 0x10, 0x1f, 0x2e, 0x0b, 0xea, 0x22, 0xd4, 0xc9, 0xa9, 0xdb, 0x0b, 0x13, + 0xad, 0xa9, 0xe8, 0x30, 0x15, 0xda, 0xf3, 0xe8, 0xd0, 0x19, 0xfc, 0x03, 0xf1, + 0xe2, 0xbb, 0x08, 0xd0, 0x3b, 0x27, 0x22, 0xd9, 0x0d, 0x4e, 0xee, 0xe6, 0x16, + 0x1e, 0x14, 0xb4, 0xe9, 0xde, 0xf9, 0x27, 0x01, 0x0e, 0xf2, 0xf2, 0xf1, 0xe6, + 0x00, 0xc4, 0xd9, 0xe8, 0x33, 0xf0, 0x34, 0x10, 0xd0, 0x02, 0xf1, 0xeb, 0x28, + 0x26, 0xff, 0x49, 0xe5, 0x01, 0x37, 0x4e, 0x29, 0xf8, 0xc1, 0xe3, 0x22, 0xb9, + 0x1f, 0x02, 0xfd, 0x0e, 0xb7, 0xd6, 0xc7, 0xf9, 0xcd, 0xcd, 0x1a, 0x17, 0xe6, + 0xee, 0x05, 0xd1, 0xe5, 0xed, 0xf9, 0xe1, 0x32, 0x27, 0xe6, 0xf0, 0xd0, 0x31, + 0xe1, 0xea, 0xd4, 0x30, 0x06, 0x43, 0xec, 0xf6, 0xf3, 0x22, 0xf2, 0xf6, 0xd0, + 0xda, 0xfd, 0x0f, 0xad, 0x01, 0xda, 0x0a, 0xc3, 0x10, 0xf8, 0x9f, 0xfe, 0xe4, + 0xf4, 0xb0, 0x2f, 0x13, 0xd7, 0x8b, 0x13, 0xf6, 0xce, 0xd9, 0x05, 0x9e, 0x13, + 0xfb, 0x12, 0xfe, 0x9b, 0xf2, 0xf5, 0xbc, 0x18, 0xf5, 0x10, 0xd1, 0x18, 0xd8, + 0x0a, 0x49, 0xea, 0xd2, 0x0d, 0x02, 0xfd, 0xf7, 0xe1, 0x19, 0xee, 0xb4, 0x14, + 0xe1, 0xf5, 0xb3, 0xcc, 0xe2, 0xf2, 0x15, 0x52, 0xdd, 0xd9, 0x10, 0x22, 0x41, + 0x44, 0x01, 0x21, 0xb8, 0x1c, 0xdc, 0xd9, 0xd9, 0x0e, 0x0f, 0x30, 0xd1, 0xd2, + 0xe8, 0xc4, 0xdf, 0xed, 0xec, 0xc6, 0x36, 0xdb, 0xfb, 0x0f, 0x10, 0x2e, 0xbd, + 0xb5, 0x22, 0x23, 0xf8, 0x22, 0x0d, 0xde, 0xc7, 0xe6, 0xed, 0xfb, 0xe1, 0x4a, + 0x9a, 0x24, 0xd0, 0xf6, 0xe6, 0x30, 0xdc, 0xce, 0xca, 0xe5, 0xfb, 0xe9, 0xfc, + 0x24, 0xd1, 0x0b, 0xe2, 0xce, 0x07, 0xdb, 0xae, 0x34, 0x08, 0xd3, 0x2c, 0xb5, + 0xfc, 0xfa, 0xf4, 0x05, 0xfe, 0x15, 0x2b, 0xfb, 0xe8, 0x2f, 0x30, 0xa3, 0x04, + 0xad, 0x0c, 0xe7, 0xe3, 0x04, 0xea, 0x41, 0x3c, 0xfc, 0xe0, 0x9e, 0xb8, 0xf8, + 0x54, 0xdd, 0xed, 0xfd, 0xcb, 0x2b, 0x4b, 0xf8, 0x00, 0xc6, 0xe7, 0xff, 0x24, + 0x1f, 0xee, 0xc2, 0x53, 0xf0, 0x0a, 0xf7, 0xcd, 0x27, 0x1e, 0x06, 0xe4, 0x12, + 0xcc, 0xb4, 0x2e, 0x08, 0xfd, 0xfa, 0x1a, 0xf1, 0x03, 0xeb, 0xbe, 0x0b, 0xc1, + 0xea, 0x81, 0x29, 0xe9, 0xb9, 0xc0, 0xde, 0x23, 0xf7, 0xdd, 0xe8, 0xd2, 0xdc, + 0x1c, 0xec, 0xd1, 0x04, 0xe0, 0x1f, 0xf7, 0x0c, 0x26, 0xe5, 0x01, 0xe6, 0xe9, + 0x08, 0xce, 0x1f, 0xee, 0xbd, 0x06, 0x13, 0x08, 0xf0, 0xf7, 0xf3, 0x26, 0x1f, + 0x12, 0x14, 0xbe, 0x44, 0xfe, 0xdc, 0x55, 0x47, 0x24, 0x0d, 0xd7, 0xdb, 0xc0, + 0xd0, 0x1f, 0x28, 0x03, 0x92, 0xde, 0xe7, 0x15, 0xf4, 0x32, 0xaf, 0x3a, 0x2c, + 0x13, 0xd1, 0x18, 0x24, 0xb8, 0x5a, 0x47, 0x33, 0x01, 0xca, 0x19, 0xeb, 0x05, + 0xda, 0xb7, 0x81, 0xf4, 0xde, 0xde, 0x06, 0x3d, 0x90, 0xeb, 0x1a, 0xe7, 0xde, + 0xe2, 0xd0, 0x0f, 0x0a, 0x08, 0xeb, 0x21, 0xad, 0x06, 0x0e, 0xae, 0x00, 0x18, + 0x1e, 0x2f, 0x4b, 0xc0, 0xda, 0xf3, 0x42, 0x27, 0x41, 0x36, 0x55, 0xce, 0x1a, + 0xce, 0xc7, 0x12, 0x4f, 0xc9, 0x22, 0xae, 0x17, 0x2d, 0x09, 0xea, 0xc5, 0xb0, + 0xd4, 0xe8, 0x17, 0x2e, 0xdd, 0x34, 0x40, 0xdb, 0x06, 0xea, 0x13, 0xa4, 0x27, + 0xf1, 0x02, 0x34, 0xdb, 0x14, 0xfe, 0xfd, 0x26, 0x3c, 0x15, 0xc6, 0x12, 0xa2, + 0xb5, 0x03, 0x2a, 0xf0, 0xd8, 0xc1, 0xf6, 0xfa, 0x26, 0xaa, 0xc9, 0xdd, 0x21, + 0x39, 0x55, 0x32, 0x2c, 0xcb, 0x20, 0xcc, 0x02, 0x25, 0xa9, 0xed, 0x05, 0x50, + 0xc6, 0x48, 0x37, 0x14, 0xbf, 0xa6, 0x39, 0x1f, 0x44, 0xed, 0x2d, 0x0d, 0xde, + 0x1f, 0x37, 0x99, 0x99, 0x09, 0x15, 0xeb, 0x12, 0xe2, 0xfe, 0xdc, 0x91, 0xc7, + 0xe4, 0x05, 0xd9, 0xf0, 0xf1, 0xe7, 0xe3, 0x1d, 0x14, 0x10, 0xca, 0xcc, 0xaf, + 0xe1, 0x04, 0x43, 0xdc, 0xe2, 0xfc, 0x31, 0xd3, 0xe3, 0x21, 0x13, 0xd9, 0xd9, + 0xa0, 0x46, 0x16, 0x21, 0x24, 0x10, 0x1e, 0xe2, 0x06, 0x19, 0xeb, 0xdc, 0xde, + 0xc6, 0x2e, 0xba, 0xfc, 0x2b, 0xce, 0x16, 0xd2, 0x10, 0xe2, 0xb8, 0xde, 0x20, + 0xc3, 0xf5, 0x29, 0xb5, 0xea, 0x08, 0xf5, 0xd9, 0xb2, 0xca, 0x1c, 0x15, 0xf0, + 0x4c, 0xd5, 0xc1, 0x01, 0x08, 0xf8, 0xe5, 0xab, 0x19, 0xc5, 0xc8, 0xa9, 0xeb, + 0xfd, 0xeb, 0x11, 0x04, 0xd2, 0xa0, 0x25, 0x18, 0xbb, 0xb3, 0x26, 0xef, 0x01, + 0xd6, 0x4a, 0xfd, 0x0c, 0x33, 0x26, 0x12, 0x12, 0xdb, 0xf2, 0x03, 0xfa, 0xc4, + 0x33, 0x3f, 0x0b, 0x12, 0xe6, 0xa1, 0x57, 0x3a, 0x39, 0x06, 0xff, 0x3d, 0xfa, + 0x1f, 0xd1, 0x05, 0x1f, 0x00, 0x0e, 0xf7, 0xf5, 0x14, 0x17, 0xf1, 0xc9, 0xe4, + 0xff, 0x05, 0xec, 0xd3, 0xb1, 0xdc, 0x12, 0xe0, 0xfa, 0xe4, 0xf3, 0x2f, 0xec, + 0xfd, 0xfe, 0xde, 0xe0, 0xe7, 0xf0, 0x01, 0x17, 0xf3, 0x07, 0x12, 0xb1, 0xee, + 0xd4, 0x12, 0x05, 0xd6, 0x3f, 0xdd, 0xbd, 0xbb, 0xfb, 0xd7, 0x00, 0x24, 0x0b, + 0x36, 0xed, 0xee, 0x20, 0x4d, 0xf2, 0xf1, 0xeb, 0x26, 0xf0, 0xe9, 0xac, 0xd7, + 0xe7, 0x2d, 0x2a, 0xe7, 0xcf, 0xf3, 0xc3, 0xd0, 0x1c, 0xe4, 0xec, 0xff, 0x06, + 0xd3, 0xc4, 0x1e, 0xee, 0xfb, 0x08, 0xb9, 0xde, 0xd6, 0xfe, 0x18, 0x28, 0x00, + 0xd5, 0xc6, 0xe0, 0xd4, 0x32, 0x3d, 0xd9, 0x0f, 0xf9, 0xe9, 0xfd, 0xe7, 0xe5, + 0xf2, 0xe7, 0xf7, 0xd9, 0x2d, 0xcd, 0x0f, 0x07, 0x21, 0xdb, 0xce, 0xcf, 0xc5, + 0x05, 0xe1, 0xcd, 0x19, 0xb6, 0xf1, 0xed, 0x12, 0xf6, 0x0e, 0xff, 0xd8, 0xa4, + 0x1d, 0x42, 0xf0, 0xb1, 0xce, 0x02, 0xef, 0xf7, 0xba, 0x0f, 0x01, 0xd2, 0x02, + 0x31, 0xd7, 0xf1, 0xd8, 0x00, 0xfc, 0x45, 0x1a, 0xc2, 0xb8, 0x08, 0xec, 0x07, + 0x0e, 0xb7, 0x0f, 0xc6, 0xd6, 0x3a, 0xad, 0xeb, 0xca, 0xda, 0x0e, 0x2b, 0xc1, + 0x02, 0xfc, 0xef, 0x3f, 0x31, 0xe8, 0x04, 0x15, 0xef, 0xff, 0x25, 0x00, 0x04, + 0x01, 0xc9, 0xdd, 0xff, 0xe4, 0x0c, 0xd8, 0xbc, 0xd9, 0xe0, 0xc4, 0xe8, 0x1e, + 0xd9, 0x34, 0x0d, 0x25, 0xe5, 0x3b, 0xc9, 0x02, 0x1d, 0xf9, 0xce, 0x17, 0xf6, + 0x06, 0x04, 0xe1, 0xea, 0x0d, 0xcf, 0xd2, 0x15, 0xf4, 0xd2, 0x34, 0x09, 0xe0, + 0x7f, 0xa7, 0x22, 0x58, 0xdb, 0xef, 0xfd, 0xf0, 0x3a, 0x3b, 0xf5, 0x52, 0x30, + 0x18, 0xff, 0xfa, 0xa1, 0x06, 0xdc, 0x7b, 0x0a, 0x08, 0x1d, 0xef, 0x13, 0xfe, + 0xdf, 0x18, 0x67, 0x1c, 0xdd, 0xe9, 0xd9, 0xf1, 0xb0, 0xdd, 0x09, 0x14, 0x09, + 0xe0, 0x03, 0x12, 0xf5, 0xd6, 0x37, 0xe3, 0x06, 0xe0, 0xde, 0x4a, 0xcd, 0x0e, + 0xee, 0xf1, 0x1f, 0xfc, 0xf3, 0xf0, 0xd2, 0xf2, 0xfb, 0xfc, 0xd6, 0xe7, 0x34, + 0x0b, 0xfc, 0xf1, 0xd0, 0x09, 0xda, 0xef, 0x27, 0xac, 0xb8, 0x57, 0xdf, 0x00, + 0xb1, 0xf4, 0xca, 0xe3, 0x7e, 0x1d, 0x07, 0x09, 0x1d, 0xcd, 0x45, 0xcb, 0xfa, + 0xf1, 0xd3, 0xd7, 0xc8, 0xef, 0xdc, 0xf2, 0xe5, 0x01, 0x06, 0xf2, 0x12, 0xf5, + 0xda, 0x32, 0xbb, 0x15, 0xb5, 0x04, 0xb4, 0xca, 0xf2, 0x0b, 0x0c, 0x24, 0x62, + 0xdf, 0xe5, 0x95, 0x16, 0x04, 0x46, 0xe1, 0x00, 0xee, 0x4d, 0xcc, 0xdc, 0x4e, + 0xda, 0xcd, 0xc9, 0xe9, 0x0b, 0x51, 0x0e, 0x30, 0xfa, 0xf5, 0xe2, 0x0f, 0xb8, + 0xa7, 0xba, 0xe5, 0xee, 0xd0, 0xd7, 0xc3, 0xd0, 0xf6, 0x36, 0x00, 0x25, 0x48, + 0x1b, 0xc6, 0xe6, 0xb0, 0xba, 0xfb, 0x2e, 0xe9, 0xf2, 0xc6, 0x30, 0xc2, 0xef, + 0xf4, 0xde, 0x75, 0x0c, 0x06, 0x2f, 0x1c, 0x2f, 0x18, 0x03, 0xe6, 0xfa, 0x0b, + 0xf5, 0x13, 0xda, 0x51, 0xf7, 0xf0, 0x16, 0xe9, 0xe3, 0xee, 0xe3, 0xc0, 0xce, + 0x11, 0x13, 0x39, 0xf5, 0xf0, 0xd8, 0x02, 0x35, 0x11, 0xe1, 0x04, 0x1c, 0x24, + 0xda, 0xf5, 0xf8, 0x10, 0xd4, 0xd6, 0xf3, 0xe1, 0x09, 0xf7, 0xff, 0xdd, 0x02, + 0xe1, 0xdb, 0xf3, 0x0b, 0x15, 0x1d, 0xea, 0x2f, 0x08, 0xb0, 0x38, 0x0f, 0xfe, + 0xd3, 0x19, 0xde, 0x27, 0x02, 0x09, 0xd9, 0xe8, 0x7f, 0xfd, 0x04, 0xfd, 0xeb, + 0xc6, 0xff, 0xf7, 0xe0, 0xc9, 0x1d, 0xa1, 0x0c, 0x17, 0xd9, 0xdd, 0xa3, 0xdb, + 0xe1, 0x10, 0x28, 0xed, 0x07, 0xe5, 0x06, 0xf0, 0xf9, 0xd8, 0xb9, 0xc3, 0xfc, + 0x25, 0xf0, 0xfc, 0xfe, 0xe5, 0x03, 0x0f, 0xf3, 0xd9, 0xb5, 0xe5, 0xeb, 0xf3, + 0xdc, 0x2d, 0xd2, 0xc8, 0xcf, 0xef, 0xdd, 0xe5, 0xf8, 0x0a, 0x1f, 0xfc, 0xd0, + 0x11, 0xdc, 0xcb, 0x31, 0x01, 0xdf, 0xfb, 0xee, 0x2a, 0xe1, 0xf5, 0x37, 0xdd, + 0x0d, 0xcd, 0x10, 0xcc, 0xf8, 0x01, 0xff, 0xdd, 0xfc, 0xd6, 0x20, 0x43, 0xd2, + 0xec, 0x11, 0xf8, 0x03, 0xdc, 0x15, 0xfc, 0xf2, 0xca, 0xf9, 0x07, 0x08, 0xe0, + 0xfd, 0x23, 0x2b, 0x22, 0xe1, 0xcb, 0xe6, 0x10, 0x03, 0x46, 0x24, 0x00, 0xf9, + 0xdf, 0xfe, 0x27, 0x0b, 0x1e, 0xc0, 0x0e, 0x15, 0x06, 0xd3, 0x11, 0xd2, 0xd0, + 0x0d, 0xda, 0xda, 0x29, 0xc3, 0x0f, 0x5c, 0x13, 0x03, 0xf7, 0xd3, 0x14, 0xf7, + 0xf6, 0x12, 0x11, 0x13, 0x05, 0xda, 0xf3, 0xe6, 0xf0, 0xde, 0xc3, 0xcd, 0xd4, + 0xfc, 0xe5, 0xda, 0xe2, 0xe2, 0xe5, 0x1e, 0xfc, 0xfc, 0xf3, 0x08, 0xe4, 0xf2, + 0xec, 0x07, 0x01, 0xff, 0xec, 0xf5, 0x0a, 0x00, 0xe5, 0xe9, 0xe6, 0xf6, 0xfc, + 0xef, 0xe2, 0xde, 0xdd, 0xee, 0xfe, 0x06, 0xf0, 0xc2, 0xe4, 0x04, 0xf6, 0xe2, + 0x0f, 0xef, 0x09, 0xf0, 0x0b, 0xe4, 0xde, 0xde, 0x13, 0xe9, 0xd8, 0xd2, 0xf8, + 0xf6, 0xef, 0x12, 0x24, 0x7f, 0xf7, 0xc4, 0xf7, 0xd5, 0x1b, 0x02, 0x43, 0x07, + 0x04, 0x11, 0x05, 0xf9, 0x17, 0x1a, 0x4a, 0x01, 0x2d, 0xc1, 0xbf, 0xdb, 0xf7, + 0xf4, 0x05, 0x18, 0x27, 0xda, 0x22, 0x07, 0xec, 0xe5, 0x0c, 0x04, 0xb4, 0x01, + 0xba, 0xf4, 0xe8, 0x26, 0xf6, 0xee, 0xfa, 0x0e, 0xf9, 0xf6, 0xfc, 0xf8, 0xe0, + 0xd1, 0x0c, 0x08, 0xd8, 0xfa, 0x06, 0x17, 0xd8, 0x1b, 0xf9, 0x41, 0xec, 0x1f, + 0xd8, 0x04, 0xe9, 0x00, 0x35, 0xf8, 0x0f, 0x15, 0xc8, 0xf9, 0xd4, 0xfa, 0xdd, + 0x15, 0xdd, 0x0f, 0x33, 0x06, 0x19, 0xdc, 0xfd, 0xd3, 0xb3, 0xca, 0xbc, 0xfc, + 0x01, 0xb4, 0xed, 0xc6, 0x2f, 0xd8, 0x37, 0xe7, 0xe8, 0xf8, 0xeb, 0xe5, 0xde, + 0xd4, 0xe6, 0xde, 0xc3, 0xd8, 0xf4, 0xf0, 0x0c, 0xc0, 0x1c, 0xe8, 0xc0, 0x0d, + 0x16, 0x03, 0xf0, 0xd6, 0x19, 0x0c, 0xf6, 0x38, 0x3b, 0x1c, 0x0c, 0xfb, 0xa6, + 0xee, 0xdb, 0x10, 0xa1, 0x0b, 0x17, 0xe6, 0x19, 0x15, 0xb9, 0xfa, 0x03, 0xc5, + 0xf6, 0xe5, 0xe0, 0xdb, 0x4e, 0x05, 0x2e, 0xf9, 0xda, 0xf9, 0x1f, 0x26, 0xf6, + 0xcd, 0x28, 0x33, 0xee, 0x17, 0xb9, 0xe4, 0x29, 0x08, 0x16, 0xe5, 0x09, 0xca, + 0x18, 0xf5, 0xfe, 0x00, 0xfb, 0xe2, 0xef, 0x0f, 0x06, 0x19, 0xed, 0xf2, 0xf1, + 0xa6, 0x10, 0x57, 0xf1, 0xdc, 0xe2, 0x43, 0x2b, 0x24, 0xf0, 0xe7, 0x06, 0x11, + 0x23, 0xc8, 0x21, 0x0f, 0xf7, 0xd7, 0xf4, 0xd5, 0xca, 0xf5, 0xff, 0xf0, 0xf0, + 0xd2, 0xd9, 0x13, 0x0c, 0x15, 0x06, 0xdb, 0x09, 0xd1, 0x00, 0x37, 0x08, 0x0d, + 0xce, 0x16, 0xc4, 0xd5, 0xe4, 0xd9, 0xe9, 0x04, 0xaf, 0xc5, 0xde, 0xe4, 0x26, + 0xdd, 0x39, 0x08, 0xd6, 0xc9, 0x09, 0x1a, 0xe5, 0xc4, 0x3c, 0xfc, 0x2a, 0x1b, + 0xee, 0x0b, 0x0b, 0x9c, 0x2d, 0xcf, 0xad, 0xc5, 0x1e, 0xb5, 0xfa, 0x05, 0xe6, + 0x7f, 0xf2, 0xfa, 0x08, 0xd9, 0x0e, 0x03, 0x3c, 0xdf, 0xbb, 0x16, 0xe1, 0x42, + 0xfa, 0x11, 0x95, 0xb9, 0x3d, 0xbd, 0xe4, 0xd2, 0x01, 0xfe, 0xbc, 0xed, 0x0b, + 0xd3, 0x04, 0xc1, 0xd4, 0xf7, 0x2d, 0xe4, 0x08, 0xbe, 0xe5, 0x05, 0xea, 0xee, + 0xe5, 0x1a, 0xf0, 0x59, 0x03, 0xc8, 0xd6, 0x18, 0xe2, 0xe9, 0x07, 0x18, 0x1a, + 0x20, 0x24, 0xfc, 0x06, 0x1a, 0xfe, 0x03, 0xa1, 0xc7, 0xd5, 0xe3, 0x08, 0x06, + 0xf2, 0xcc, 0xb1, 0xef, 0xdf, 0x1e, 0xe3, 0x1e, 0xbb, 0xc5, 0xf1, 0x14, 0xe2, + 0xe2, 0x0e, 0x1a, 0x00, 0xb9, 0x09, 0xfe, 0xac, 0x13, 0x0e, 0xcc, 0xc6, 0xf5, + 0x34, 0xea, 0x2f, 0x5c, 0x19, 0xeb, 0x33, 0xbd, 0x9d, 0x12, 0x9a, 0x19, 0xa4, + 0xd7, 0xd3, 0xea, 0xd2, 0x1a, 0xde, 0x16, 0x1d, 0x18, 0xf0, 0x98, 0x40, 0xe9, + 0x00, 0xd8, 0xe0, 0x13, 0x03, 0x08, 0xe2, 0xf3, 0xcd, 0x1c, 0xe8, 0xcd, 0x38, + 0xfb, 0x34, 0x18, 0xf4, 0x12, 0x13, 0xfc, 0xc3, 0xf6, 0x0b, 0xfe, 0xd4, 0xee, + 0x10, 0xf8, 0xd6, 0x6f, 0x21, 0x05, 0xff, 0x07, 0xd6, 0xe0, 0x90, 0xf7, 0x2a, + 0x2b, 0xa2, 0xef, 0xdf, 0x0a, 0x06, 0x1b, 0x2a, 0x08, 0x4a, 0xc4, 0x11, 0xfa, + 0xf4, 0xae, 0x01, 0xb5, 0xf5, 0xf9, 0x26, 0x54, 0x0d, 0x43, 0x55, 0xc5, 0xe9, + 0xff, 0xe1, 0xc1, 0xf3, 0x22, 0x2b, 0xc4, 0x15, 0xe8, 0x57, 0xee, 0xfa, 0xeb, + 0xfc, 0xda, 0xd8, 0xc1, 0x0d, 0xf0, 0x1b, 0xfc, 0x0d, 0xd9, 0x2c, 0x3d, 0x12, + 0x1c, 0x1c, 0xd2, 0x3d, 0xfa, 0xf6, 0x1b, 0xf0, 0x0f, 0x40, 0x9b, 0xa7, 0xf9, + 0xb2, 0xe1, 0xf8, 0xf2, 0xf4, 0x14, 0xd6, 0xe7, 0x0f, 0xc9, 0x00, 0xe2, 0x08, + 0xdb, 0x7f, 0xb8, 0xe5, 0xe4, 0xab, 0x24, 0xfb, 0xee, 0xf5, 0xe3, 0x36, 0x2a, + 0xad, 0xfc, 0xf9, 0xbe, 0xe3, 0x01, 0xd3, 0xdb, 0xe1, 0x60, 0x0a, 0xbf, 0x0a, + 0xc0, 0xac, 0xe0, 0xd0, 0x41, 0xd6, 0x0b, 0xdc, 0x3e, 0x09, 0xf7, 0xc5, 0xe1, + 0xe6, 0xff, 0xe3, 0x22, 0xca, 0xdf, 0x24, 0xfa, 0x60, 0xe1, 0xb6, 0x97, 0xeb, + 0xe2, 0x2a, 0x39, 0x21, 0xc6, 0xdf, 0x3c, 0x1f, 0x3b, 0x16, 0xf9, 0x1f, 0x9a, + 0xda, 0xda, 0xbf, 0x4e, 0xd7, 0x03, 0x1f, 0xdd, 0xeb, 0x03, 0x33, 0x19, 0xed, + 0xfd, 0xe5, 0xcb, 0x14, 0xde, 0xf5, 0x17, 0x00, 0x59, 0xc3, 0xd7, 0xe7, 0xf0, + 0xb1, 0xce, 0x42, 0x35, 0xe5, 0xc0, 0xf1, 0x58, 0xf3, 0xd5, 0xe7, 0x13, 0xd6, + 0x0c, 0x24, 0x05, 0xcb, 0x00, 0xb6, 0xec, 0xff, 0x1e, 0x39, 0xf1, 0x1a, 0xb9, + 0xf8, 0x01, 0xff, 0xe2, 0x68, 0xde, 0x28, 0xcf, 0xcc, 0xe7, 0xd6, 0x0d, 0xa9, + 0x20, 0xf1, 0xe3, 0xeb, 0xec, 0xf0, 0xd2, 0x13, 0xf8, 0x08, 0x0c, 0xf2, 0xe5, + 0x1e, 0xc6, 0x06, 0x1f, 0xc0, 0xfd, 0xac, 0xfa, 0xb6, 0xf9, 0xff, 0xd1, 0xf0, + 0xe8, 0xbc, 0xed, 0x23, 0xa5, 0xd9, 0x0b, 0xfe, 0xf8, 0xac, 0x5c, 0xca, 0xd9, + 0xe0, 0xcf, 0x81, 0xf5, 0xfb, 0x26, 0x0b, 0x09, 0x10, 0x2d, 0x9b, 0x20, 0x01, + 0xfb, 0x0c, 0x09, 0x0d, 0xd0, 0x0c, 0x24, 0x11, 0x10, 0xb5, 0x07, 0xd3, 0xe4, + 0x17, 0x16, 0xd6, 0xdc, 0xfe, 0xcb, 0xb6, 0xc8, 0xf8, 0xde, 0xe8, 0x3c, 0xd9, + 0x47, 0xfd, 0xa0, 0x22, 0xd5, 0xde, 0xea, 0xc2, 0xea, 0xe7, 0x43, 0xde, 0x09, + 0xab, 0xd6, 0xcd, 0x1c, 0xf9, 0xc0, 0xcc, 0x03, 0xfe, 0x31, 0x18, 0x22, 0xe5, + 0xdc, 0xfb, 0xd8, 0xbb, 0xfa, 0x9d, 0x06, 0x32, 0x09, 0x0d, 0xaa, 0x1a, 0x01, + 0xbe, 0xd0, 0xcf, 0xea, 0x0e, 0x16, 0x21, 0x13, 0xef, 0xd4, 0xdc, 0x49, 0x0e, + 0xef, 0xd1, 0x1e, 0x13, 0x42, 0x2f, 0x28, 0xc9, 0xbe, 0xe5, 0x11, 0x3d, 0xf5, + 0xf0, 0xca, 0x16, 0x1c, 0xd8, 0x18, 0xfd, 0xd2, 0x19, 0xe3, 0xea, 0xbf, 0xdd, + 0xcb, 0x87, 0xff, 0x1e, 0xb7, 0xe6, 0x25, 0xcc, 0xe5, 0xf9, 0xe5, 0xe9, 0xac, + 0xfa, 0x50, 0xfa, 0xea, 0x04, 0x06, 0xa1, 0xc9, 0x07, 0x0b, 0xf3, 0xde, 0xa0, + 0xdd, 0xe8, 0x90, 0x96, 0x0b, 0xeb, 0x0d, 0x21, 0x07, 0x2f, 0x99, 0xeb, 0x9b, + 0x0a, 0x0d, 0xe4, 0xf8, 0x4e, 0xe2, 0xdf, 0x15, 0xe0, 0xe4, 0xd7, 0xc3, 0xf5, + 0xd9, 0x1e, 0xd3, 0x07, 0xfe, 0xd7, 0xf5, 0xcf, 0x29, 0x34, 0x20, 0x20, 0xd9, + 0xcd, 0x14, 0xfe, 0xe5, 0x2f, 0x1b, 0x08, 0x3f, 0x9d, 0xc4, 0x03, 0x04, 0x09, + 0xf5, 0xcb, 0xd2, 0xfa, 0xfa, 0xcf, 0x01, 0xc5, 0x07, 0x06, 0x03, 0xfa, 0xdd, + 0xc0, 0xda, 0xf1, 0xc6, 0xef, 0xf1, 0x14, 0xf6, 0xcd, 0x48, 0x9d, 0xb3, 0xb4, + 0xac, 0xff, 0xe6, 0xed, 0x04, 0xf3, 0xf8, 0xdd, 0xe7, 0x08, 0xe3, 0x37, 0xf5, + 0xd9, 0xfe, 0x08, 0xd8, 0x01, 0xf1, 0xc6, 0xd8, 0xd4, 0x38, 0x15, 0x1b, 0xe1, + 0x9c, 0x04, 0xe6, 0xe1, 0xfd, 0x03, 0xcd, 0x86, 0x0e, 0x0c, 0xe4, 0x81, 0x04, + 0xf4, 0xfc, 0xd7, 0x26, 0x37, 0x0a, 0xae, 0x0e, 0xe5, 0x33, 0xfa, 0xd8, 0xeb, + 0x01, 0xc0, 0x50, 0xf8, 0xf5, 0x24, 0x1e, 0x28, 0x06, 0xc3, 0x13, 0xf8, 0xae, + 0x03, 0xfb, 0xce, 0xbc, 0x2c, 0x17, 0x0a, 0xf3, 0xcf, 0xee, 0x1a, 0xb0, 0x1f, + 0xba, 0xbc, 0xee, 0xae, 0x00, 0x05, 0xbe, 0xd6, 0xf5, 0x12, 0xe8, 0xb5, 0x2c, + 0xd4, 0xf2, 0x20, 0x2a, 0xfd, 0x1b, 0x30, 0xf7, 0xaf, 0xc2, 0xde, 0xcb, 0x30, + 0x20, 0xdc, 0x0f, 0xfe, 0xeb, 0x1e, 0xca, 0xc7, 0xf3, 0x22, 0xce, 0xeb, 0xf1, + 0x14, 0xfb, 0xe5, 0xfe, 0xd4, 0xcd, 0xd5, 0xfb, 0xea, 0xc6, 0xd8, 0xde, 0xe3, + 0x33, 0x29, 0x61, 0x32, 0x1e, 0xfb, 0x2d, 0xcb, 0xc5, 0xef, 0x06, 0xe9, 0xeb, + 0x0d, 0x20, 0x38, 0xfb, 0xdc, 0xdd, 0xbd, 0xe7, 0xd3, 0xec, 0xcb, 0x5a, 0xe0, + 0x4e, 0x2f, 0x22, 0xc6, 0x06, 0xca, 0xe3, 0x09, 0x2c, 0x3d, 0x17, 0x08, 0xef, + 0xe6, 0xed, 0xd1, 0x33, 0x1f, 0x28, 0xd6, 0xb9, 0x88, 0xe9, 0x1b, 0xe5, 0xe1, + 0xd3, 0x6e, 0x0c, 0x09, 0xb9, 0x1e, 0xcc, 0xf1, 0x40, 0xce, 0x33, 0x0e, 0xff, + 0x2a, 0x18, 0x13, 0xf0, 0xe5, 0xa6, 0xd9, 0xe1, 0x2b, 0x11, 0xec, 0x1b, 0x23, + 0x0a, 0x18, 0xdf, 0x13, 0xfc, 0x41, 0xcc, 0x00, 0xc6, 0xf4, 0x25, 0xf3, 0x21, + 0x36, 0x04, 0x51, 0xfe, 0xbb, 0xf4, 0xf7, 0x05, 0x46, 0x0b, 0xea, 0x3d, 0xf6, + 0xaf, 0x03, 0x4b, 0xe8, 0x13, 0xf7, 0x14, 0x10, 0xf8, 0x08, 0xd0, 0xb7, 0x05, + 0xcd, 0x13, 0xda, 0x9f, 0xe8, 0x14, 0xc8, 0x02, 0x09, 0xc1, 0x2e, 0xa6, 0x07, + 0x13, 0xfd, 0xdd, 0xde, 0x43, 0x17, 0x45, 0xe4, 0xe5, 0xed, 0x1b, 0xfe, 0xf1, + 0xed, 0xf8, 0x15, 0x4d, 0x0d, 0x0e, 0x37, 0x1d, 0x09, 0xfc, 0xc5, 0xb8, 0xe9, + 0xf0, 0xef, 0xf7, 0x0a, 0x19, 0x22, 0x14, 0x11, 0x44, 0xd7, 0xe3, 0x03, 0xe6, + 0x26, 0x00, 0xb2, 0x0a, 0xe2, 0xec, 0xe4, 0x3e, 0x24, 0xe4, 0x30, 0xbe, 0x12, + 0xf4, 0x02, 0xfd, 0x1b, 0x05, 0xda, 0xde, 0x02, 0xe1, 0x33, 0xfb, 0x0f, 0xe0, + 0x03, 0x18, 0xed, 0xe6, 0xe1, 0x10, 0x2d, 0xc9, 0x19, 0xee, 0x13, 0x3b, 0xef, + 0xda, 0xe7, 0xb5, 0xc1, 0xdb, 0xee, 0xfa, 0x03, 0x2c, 0x57, 0xec, 0x02, 0x18, + 0xf3, 0xf2, 0xfe, 0x2d, 0xeb, 0x02, 0xf7, 0x1f, 0xeb, 0xef, 0x43, 0xe7, 0x2c, + 0x00, 0xa3, 0x2f, 0xf9, 0xd2, 0xec, 0xc6, 0xbe, 0x11, 0xc9, 0xce, 0xf2, 0xf2, + 0xe5, 0xf8, 0x24, 0x09, 0x25, 0x02, 0x30, 0x68, 0x2f, 0x1c, 0x1e, 0x10, 0xf9, + 0x10, 0xe5, 0xdf, 0xc2, 0xdf, 0xf3, 0x2d, 0xf5, 0xbf, 0xdd, 0x1d, 0x02, 0x06, + 0x03, 0xd1, 0x20, 0x2f, 0x2b, 0xeb, 0xda, 0x20, 0xe0, 0x40, 0x17, 0xe7, 0x47, + 0x0a, 0xf5, 0xe0, 0x1f, 0x00, 0x13, 0x23, 0x0c, 0x06, 0x46, 0xc7, 0xf7, 0x22, + 0x2b, 0xfa, 0xe5, 0x15, 0xf8, 0xe5, 0xe8, 0x43, 0x29, 0x07, 0x0d, 0xe5, 0xee, + 0x04, 0xfc, 0xd2, 0xae, 0x7f, 0xd0, 0x07, 0xe5, 0xfb, 0xf5, 0xe4, 0x1b, 0xfd, + 0xd6, 0xc3, 0xd2, 0xe4, 0xb9, 0xdc, 0xe1, 0xf4, 0x25, 0xf2, 0xf1, 0xcd, 0xee, + 0x16, 0x14, 0x01, 0x33, 0x33, 0x04, 0xf5, 0xd0, 0xfc, 0xf0, 0x1e, 0x10, 0xfc, + 0xda, 0x30, 0xe7, 0x06, 0xc5, 0xdc, 0xdd, 0xf2, 0x18, 0xe4, 0x6d, 0xe7, 0x19, + 0xe7, 0x04, 0xf7, 0x1f, 0xde, 0x0d, 0xd5, 0x0b, 0xc8, 0xbf, 0x00, 0x0e, 0xcb, + 0xff, 0xd4, 0x18, 0x9e, 0xcb, 0xf1, 0xf7, 0xed, 0xfc, 0x2f, 0x56, 0xcb, 0xec, + 0x4f, 0x1b, 0x2b, 0xcc, 0xee, 0xdc, 0x24, 0xdb, 0x1d, 0xbe, 0x32, 0xfc, 0x3d, + 0x61, 0xf4, 0xcc, 0x05, 0xe6, 0xf7, 0xc7, 0xfc, 0xd4, 0xf4, 0x91, 0xec, 0xeb, + 0x1f, 0xdd, 0xfa, 0x37, 0x0b, 0xba, 0xd9, 0x20, 0xca, 0x41, 0x5a, 0x31, 0x02, + 0xf4, 0x14, 0xae, 0x45, 0x0d, 0xf0, 0x1c, 0xb2, 0x03, 0xff, 0x17, 0xe6, 0x17, + 0xd8, 0xc2, 0xe9, 0xc3, 0xc0, 0x78, 0xcb, 0x0a, 0x40, 0xe9, 0x43, 0xbb, 0xe2, + 0xe0, 0x15, 0x2e, 0xd6, 0x21, 0xb0, 0xc6, 0xe0, 0xba, 0x20, 0x02, 0xe2, 0x00, + 0xcf, 0xce, 0xef, 0x1d, 0x35, 0x10, 0xf7, 0xd9, 0xd6, 0xed, 0xe6, 0x2a, 0x1e, + 0xe8, 0x1f, 0x0c, 0x19, 0xc5, 0x0e, 0xe9, 0x0f, 0xe0, 0x22, 0xb9, 0xc9, 0x03, + 0xf2, 0xe5, 0xde, 0xb8, 0xd0, 0xfb, 0xf9, 0xcf, 0x16, 0xf5, 0xf7, 0xe0, 0xe3, + 0x17, 0xf1, 0xe2, 0x50, 0x15, 0x3c, 0xec, 0xfb, 0xdb, 0xe7, 0x2d, 0xbc, 0xe6, + 0xbf, 0x19, 0xed, 0xe7, 0x61, 0xb8, 0x71, 0xd1, 0x08, 0x03, 0xdb, 0x05, 0x40, + 0x4c, 0x01, 0xf1, 0x09, 0xef, 0x3a, 0x02, 0x2a, 0x37, 0xc0, 0x55, 0xd1, 0x8c, + 0x14, 0x09, 0xfd, 0xea, 0x22, 0xee, 0x0b, 0x23, 0xec, 0xa9, 0x81, 0xff, 0xd3, + 0xf2, 0xe3, 0xcd, 0xc2, 0x09, 0x13, 0xdb, 0xbb, 0x0f, 0x16, 0x04, 0xa7, 0x15, + 0x4e, 0xe9, 0x16, 0xd2, 0xe4, 0xd2, 0xe2, 0xe2, 0x2c, 0xbc, 0x1b, 0xf6, 0xfc, + 0xd9, 0x60, 0x86, 0x1c, 0x29, 0xc4, 0x40, 0xe6, 0xf1, 0x25, 0xc9, 0x44, 0x20, + 0x2e, 0xd4, 0x05, 0xc8, 0x0b, 0x30, 0x1e, 0xda, 0xe7, 0xdc, 0xeb, 0xe3, 0xef, + 0xa9, 0xe0, 0x2f, 0xbc, 0xb7, 0xaf, 0x50, 0xd6, 0x59, 0xf5, 0xf0, 0x0c, 0x11, + 0xbb, 0xf8, 0xd1, 0x1c, 0x0b, 0xee, 0x28, 0xa3, 0x28, 0x21, 0xc1, 0xb9, 0xc0, + 0xe0, 0xed, 0xaa, 0xf0, 0xf9, 0xca, 0xc7, 0x0f, 0x07, 0xc4, 0x04, 0x36, 0xdf, + 0xeb, 0xf4, 0xf6, 0xde, 0xf9, 0x2a, 0x18, 0xed, 0xf0, 0x07, 0xed, 0x25, 0xdf, + 0x0f, 0xf5, 0x81, 0xd1, 0x13, 0x19, 0x15, 0xdc, 0xfe, 0xf7, 0xfe, 0x30, 0x1d, + 0xdb, 0x1f, 0x17, 0x3a, 0xeb, 0xf6, 0xd0, 0x37, 0x0c, 0xed, 0xd9, 0xb3, 0x26, + 0xfb, 0xd5, 0xfb, 0xb5, 0x07, 0xe9, 0xea, 0xe0, 0xe1, 0xc8, 0xe0, 0xd9, 0xe4, + 0xcf, 0xe2, 0xda, 0xe0, 0x04, 0xbe, 0xac, 0x1a, 0x02, 0xd6, 0x04, 0xe0, 0x18, + 0xd7, 0xff, 0x27, 0x0b, 0x24, 0x98, 0x2c, 0xfc, 0xd1, 0xd5, 0x48, 0xfb, 0x0b, + 0x02, 0xec, 0xd8, 0xfa, 0xe3, 0x9c, 0xf4, 0xfd, 0xcf, 0x5b, 0x11, 0xf2, 0xdc, + 0x03, 0xd7, 0xf9, 0xa7, 0x0d, 0xf7, 0xb8, 0xc3, 0x0f, 0xe7, 0x28, 0xa5, 0xee, + 0xf1, 0x10, 0x43, 0xde, 0x04, 0xe9, 0x10, 0x02, 0x00, 0xc7, 0x2a, 0x3d, 0xe4, + 0xac, 0xdb, 0x0a, 0xdb, 0xd8, 0xee, 0x21, 0x2c, 0x0e, 0x21, 0x2e, 0xdd, 0x30, + 0x1b, 0xde, 0x11, 0xe7, 0x46, 0xfc, 0x0f, 0x2e, 0xe8, 0x31, 0x59, 0x09, 0xe3, + 0xaa, 0x50, 0xd5, 0xd2, 0x1a, 0xfd, 0xfe, 0x29, 0xc4, 0xdc, 0xc7, 0xf5, 0xdb, + 0xa6, 0xdd, 0x25, 0xee, 0xf9, 0xb3, 0x12, 0xf9, 0xf4, 0x31, 0x13, 0x03, 0x20, + 0xff, 0xca, 0x01, 0xbe, 0xef, 0xca, 0xb9, 0xc9, 0xd4, 0x04, 0xb9, 0xd8, 0x25, + 0xb0, 0xf5, 0xbb, 0xa4, 0xd9, 0xc3, 0xfd, 0xa6, 0x16, 0x2f, 0xeb, 0xe2, 0x01, + 0x1f, 0x06, 0xf7, 0xe5, 0xbf, 0xcc, 0xbf, 0xf4, 0x0e, 0xf4, 0x25, 0x45, 0x1a, + 0xf8, 0x06, 0xd0, 0x18, 0xea, 0x03, 0xd3, 0x32, 0xf8, 0xe5, 0x24, 0x3e, 0x23, + 0xdb, 0xf2, 0xea, 0xd1, 0x04, 0x1b, 0x18, 0xe5, 0x06, 0x5f, 0xab, 0x34, 0xb9, + 0x42, 0xe8, 0xfc, 0x20, 0x20, 0x1e, 0x16, 0xed, 0x34, 0xdc, 0x27, 0x08, 0x0f, + 0xf3, 0xf2, 0xf6, 0xdd, 0xd9, 0x15, 0xd1, 0xd4, 0xb5, 0x00, 0xc4, 0xc9, 0xdb, + 0xc9, 0xd1, 0xfe, 0xdd, 0xa8, 0xe5, 0x2c, 0xcd, 0xce, 0x22, 0xdd, 0xf6, 0xe4, + 0x21, 0xda, 0x28, 0x0c, 0x93, 0xef, 0xf5, 0x4a, 0x31, 0x9e, 0xca, 0x2b, 0x13, + 0x02, 0xef, 0xeb, 0xca, 0x07, 0xc8, 0xe7, 0x5f, 0xfd, 0x7d, 0xef, 0x20, 0x45, + 0x20, 0xc6, 0x15, 0x8c, 0xd7, 0xf8, 0xcf, 0x13, 0xd2, 0x0d, 0x28, 0x46, 0x58, + 0xeb, 0x34, 0x59, 0x11, 0xb7, 0xc8, 0xe4, 0x47, 0x45, 0xf1, 0xf7, 0x34, 0x07, + 0xd3, 0x0f, 0x75, 0xdb, 0x34, 0xfb, 0xd2, 0xb7, 0x23, 0xe2, 0xf8, 0x40, 0xd6, + 0x11, 0x03, 0xd0, 0xe5, 0xac, 0xb5, 0xde, 0x36, 0x15, 0xf1, 0xd2, 0x36, 0xea, + 0xcd, 0x45, 0x59, 0xf6, 0x1e, 0xca, 0x0e, 0xf2, 0x2c, 0x25, 0xde, 0xd7, 0x66, + 0x33, 0x23, 0xd5, 0x9b, 0x1c, 0xd4, 0xab, 0x13, 0xea, 0x03, 0xb2, 0x59, 0x01, + 0x19, 0x08, 0x16, 0x64, 0xd3, 0x33, 0xd5, 0x95, 0xd5, 0x3c, 0xca, 0xdc, 0xe8, + 0x19, 0x08, 0xcb, 0xe1, 0x81, 0xdb, 0xe2, 0xde, 0x19, 0x12, 0xd6, 0x1f, 0xcf, + 0x14, 0xfb, 0xd8, 0x30, 0xf8, 0x0d, 0x3d, 0xdb, 0xbb, 0x14, 0xdc, 0x0e, 0xbe, + 0xf0, 0xe7, 0x12, 0x4d, 0xd2, 0x20, 0xb5, 0x4c, 0xb1, 0xd6, 0x4b, 0x95, 0xe1, + 0x0a, 0xa9, 0x06, 0x15, 0xf7, 0x8b, 0xb8, 0x06, 0xce, 0xc9, 0xe1, 0xdf, 0x8d, + 0x0b, 0xd4, 0xcc, 0xf8, 0xa2, 0xdb, 0x96, 0xfe, 0x45, 0x11, 0x28, 0xed, 0x1e, + 0x94, 0x07, 0x21, 0xe5, 0x2d, 0x2e, 0xc2, 0x0a, 0xf2, 0xf9, 0x0c, 0xe6, 0xe1, + 0x12, 0xd5, 0xd6, 0x4c, 0xe1, 0x30, 0x04, 0xda, 0xfb, 0x34, 0x11, 0x3d, 0xf7, + 0x02, 0xb2, 0x62, 0x13, 0xdf, 0xf5, 0x03, 0xea, 0x02, 0x89, 0xc5, 0x16, 0x1e, + 0x12, 0xd4, 0xe4, 0x20, 0xd9, 0xf1, 0xa7, 0x02, 0x51, 0xcd, 0xd9, 0xc9, 0x97, + 0x07, 0xe2, 0xab, 0xc5, 0x53, 0x45, 0xe5, 0xdf, 0xb2, 0xbc, 0xc9, 0xf5, 0x3f, + 0xae, 0xc4, 0x1f, 0xb8, 0x27, 0x05, 0xb6, 0xc4, 0xf8, 0x26, 0xd1, 0x01, 0x0e, + 0xc4, 0xfd, 0xa2, 0x05, 0x9e, 0xbf, 0x33, 0x21, 0xfa, 0xe9, 0x09, 0x07, 0x9c, + 0xf1, 0x20, 0xe2, 0x2e, 0xcb, 0xd8, 0x85, 0x1e, 0xea, 0x34, 0xf6, 0xcf, 0xd2, + 0x38, 0xf7, 0xd8, 0x2b, 0xea, 0xe9, 0x02, 0xc3, 0xc4, 0x93, 0x09, 0xa4, 0xf6, + 0x1c, 0xe2, 0xe7, 0xea, 0xbd, 0x2f, 0xfa, 0x16, 0xca, 0xcb, 0xe0, 0xc7, 0xf2, + 0x22, 0x43, 0xbe, 0x00, 0xb9, 0xf5, 0xf5, 0xf8, 0x05, 0x7d, 0x20, 0x19, 0xed, + 0xc6, 0x03, 0xf2, 0x32, 0x18, 0xc0, 0x1c, 0x93, 0x1c, 0x0f, 0x04, 0x27, 0x81, + 0xdc, 0xcf, 0xbb, 0x00, 0xda, 0xbb, 0xe6, 0xac, 0xe9, 0x36, 0x05, 0x12, 0xfd, + 0x1e, 0xf1, 0xb4, 0xa2, 0x33, 0x10, 0xbf, 0x1f, 0xe8, 0x18, 0xc9, 0x29, 0x07, + 0x0b, 0x2e, 0xfa, 0xa7, 0x02, 0xd8, 0xca, 0xf3, 0xf0, 0xe3, 0x1e, 0xfd, 0xd8, + 0xf0, 0xe5, 0x04, 0x9b, 0xec, 0x11, 0xe5, 0xfa, 0x0e, 0x93, 0xe6, 0xdb, 0x06, + 0xe8, 0xf1, 0xe3, 0x36, 0xd8, 0xe5, 0x0b, 0x02, 0xb4, 0xeb, 0x06, 0xdb, 0x0e, + 0xf0, 0xd9, 0xb6, 0xb9, 0xcc, 0xbe, 0x09, 0x42, 0x13, 0xfd, 0x3e, 0x08, 0xf2, + 0xf1, 0x8f, 0xb2, 0xe7, 0xd1, 0xa4, 0xd8, 0x35, 0xf5, 0xef, 0xf7, 0xc9, 0xef, + 0x95, 0xc2, 0x03, 0xf0, 0xce, 0x2b, 0x20, 0xed, 0x2d, 0xfe, 0xe5, 0x4f, 0xb2, + 0xd0, 0xd9, 0xdc, 0x06, 0xe7, 0x0c, 0x22, 0x08, 0xf0, 0x2d, 0xf4, 0xbd, 0x23, + 0x24, 0x4b, 0xec, 0xe0, 0xde, 0xeb, 0xf2, 0x24, 0xcd, 0xf8, 0x23, 0xfa, 0x13, + 0xf8, 0xeb, 0x49, 0x06, 0xed, 0xca, 0xde, 0xb3, 0x65, 0x3c, 0xe1, 0x27, 0xf7, + 0x32, 0xd0, 0x21, 0x8b, 0x20, 0xec, 0xf4, 0x2e, 0xf3, 0xf6, 0x02, 0xc4, 0x23, + 0x06, 0x2d, 0x3a, 0xdc, 0x1e, 0xcd, 0x0c, 0xeb, 0xa6, 0xf9, 0xe1, 0x12, 0x2a, + 0x37, 0x57, 0x0b, 0xdc, 0xa2, 0xc4, 0x01, 0xbc, 0x4b, 0x45, 0x3d, 0x4f, 0x0a, + 0x5b, 0x26, 0x40, 0x33, 0x3a, 0x95, 0xa6, 0xda, 0x5f, 0xd6, 0xd9, 0xe3, 0xe5, + 0x37, 0xbe, 0xe4, 0x00, 0xe5, 0xba, 0x07, 0x53, 0x1d, 0x27, 0x1d, 0x0b, 0x38, + 0xcf, 0xc4, 0xf5, 0x21, 0x4e, 0xf2, 0x52, 0xdf, 0xf2, 0xc2, 0xf1, 0x14, 0x17, + 0xba, 0xb3, 0x95, 0x00, 0xee, 0xd2, 0xd6, 0x1f, 0x18, 0x03, 0x88, 0x25, 0xdb, + 0xf5, 0x13, 0x00, 0x2e, 0x04, 0xb3, 0x1e, 0xee, 0xd1, 0x12, 0x17, 0xd8, 0x2d, + 0xbf, 0xfe, 0x37, 0xf1, 0xe5, 0x1b, 0xeb, 0xe4, 0xe4, 0x59, 0xf7, 0x7b, 0x0d, + 0xd9, 0x9a, 0x18, 0x22, 0xdb, 0xb8, 0xf1, 0xe4, 0x32, 0xd8, 0xdd, 0xc0, 0xf5, + 0xef, 0xc6, 0x44, 0xca, 0x02, 0x4a, 0xf0, 0x11, 0x0e, 0x90, 0xf8, 0xf5, 0x08, + 0xfe, 0xad, 0xd5, 0x17, 0xe6, 0xd0, 0x8b, 0x65, 0xf9, 0xde, 0xfc, 0x32, 0x0f, + 0xc1, 0xd0, 0xb6, 0xd6, 0x21, 0x12, 0x13, 0xcc, 0xeb, 0x10, 0x2a, 0x4e, 0xd6, + 0x4c, 0x18, 0xbc, 0xe3, 0x2a, 0x06, 0xbe, 0xe8, 0xbb, 0x0c, 0xfe, 0xef, 0xc0, + 0xf4, 0xc0, 0xdc, 0x36, 0x14, 0x35, 0x10, 0x7f, 0xf2, 0x13, 0x15, 0xe1, 0x33, + 0x26, 0xd7, 0xf2, 0x30, 0xfd, 0xe0, 0x61, 0xd5, 0xc0, 0xea, 0x35, 0xb9, 0x9d, + 0x3f, 0x15, 0x14, 0xe7, 0xd6, 0xc1, 0x08, 0xc2, 0xd7, 0xeb, 0xd5, 0xe1, 0x2a, + 0xfe, 0xab, 0xf8, 0xee, 0xf8, 0x06, 0x24, 0xe8, 0x27, 0x0c, 0x26, 0x08, 0x0f, + 0xaf, 0x04, 0xbe, 0xf3, 0xe2, 0xdd, 0xdd, 0x58, 0xc8, 0x33, 0xf1, 0xeb, 0x1a, + 0xbc, 0x4c, 0xd9, 0xc7, 0xf7, 0xd0, 0xfb, 0xc6, 0xcf, 0x2d, 0xf9, 0xe4, 0xe9, + 0xe2, 0x40, 0xf3, 0x3e, 0xe6, 0xe5, 0x19, 0xda, 0x1c, 0x05, 0x00, 0xf7, 0xba, + 0x08, 0xf7, 0xd4, 0xd4, 0x5b, 0xf1, 0x25, 0xca, 0x0a, 0xd5, 0x00, 0xe6, 0xe9, + 0x13, 0x00, 0xa5, 0x38, 0xf8, 0xe1, 0x1c, 0xe0, 0x02, 0x42, 0x6a, 0xce, 0x08, + 0xe2, 0x30, 0x33, 0xf9, 0xdd, 0xe2, 0xcf, 0xf0, 0x51, 0x22, 0x0e, 0x29, 0x62, + 0xb8, 0xcb, 0x14, 0xd1, 0x98, 0xff, 0xd0, 0xb7, 0xc0, 0xdc, 0x0b, 0xfb, 0x52, + 0x47, 0xf8, 0x05, 0xe3, 0xd5, 0x19, 0x14, 0xf1, 0xeb, 0x04, 0x2f, 0xc7, 0x58, + 0xc6, 0xc3, 0xb7, 0xeb, 0xa0, 0x22, 0xd2, 0xe7, 0xb0, 0xe7, 0x0f, 0xfb, 0xbb, + 0x15, 0x29, 0xc9, 0xd5, 0x00, 0xf0, 0x16, 0xeb, 0xfe, 0x37, 0xdd, 0xf1, 0xc8, + 0xee, 0xdb, 0xfc, 0xe0, 0xbe, 0xfa, 0x05, 0xf3, 0xf8, 0xe0, 0x13, 0xf6, 0xd6, + 0x19, 0x30, 0xd0, 0xe9, 0x33, 0xd3, 0xe3, 0xb9, 0xc4, 0x45, 0xf5, 0xa5, 0x55, + 0xfe, 0xca, 0x02, 0xc2, 0x10, 0xd4, 0x15, 0x1e, 0xe0, 0xe6, 0x07, 0xed, 0x73, + 0x06, 0xf5, 0x1d, 0xda, 0x81, 0xd9, 0xfb, 0xfe, 0xf9, 0x16, 0x28, 0xde, 0x10, + 0xf0, 0xce, 0xf8, 0x2e, 0xe2, 0x34, 0x2d, 0x1c, 0x0a, 0xf4, 0x29, 0x1d, 0xe6, + 0x98, 0xc6, 0xb8, 0x38, 0x14, 0x11, 0xe7, 0xf9, 0x01, 0x2a, 0xee, 0x5e, 0xf9, + 0xfd, 0xf7, 0xc8, 0xfe, 0xf0, 0xbf, 0x2f, 0x9d, 0xc0, 0x1b, 0xd7, 0x1f, 0xd1, + 0xd7, 0xa3, 0xa9, 0x14, 0xdd, 0xe7, 0xe4, 0x03, 0x28, 0x52, 0x34, 0x1f, 0xbc, + 0xdd, 0xfb, 0x26, 0xc3, 0xef, 0x22, 0x4f, 0x24, 0xb3, 0xaf, 0x04, 0x01, 0x04, + 0x08, 0x22, 0xce, 0xf0, 0x24, 0x3d, 0xc0, 0xa1, 0x06, 0x01, 0x16, 0x18, 0x5a, + 0xdb, 0x42, 0x10, 0xc9, 0xf3, 0xf5, 0xfb, 0xfc, 0x00, 0x0c, 0xff, 0x05, 0xf0, + 0x1e, 0xdd, 0xd4, 0x53, 0xca, 0x09, 0xf7, 0x1c, 0xb1, 0x18, 0xbc, 0x13, 0x1b, + 0x02, 0x14, 0x52, 0x24, 0xf7, 0x36, 0xb4, 0x15, 0xde, 0x1d, 0xfe, 0xf7, 0x40, + 0xe9, 0xd4, 0x25, 0x47, 0x13, 0x39, 0x46, 0x37, 0xb0, 0xfc, 0x34, 0xf1, 0x0d, + 0x04, 0x1e, 0x77, 0xcd, 0x34, 0xbe, 0x03, 0xf1, 0x1a, 0x1f, 0xc3, 0xdc, 0x96, + 0xf2, 0x21, 0xef, 0x9f, 0xe6, 0xf9, 0xfd, 0x26, 0xf8, 0x07, 0xc9, 0xf2, 0xe3, + 0xbe, 0xb7, 0x27, 0xb8, 0x39, 0xfc, 0x50, 0x16, 0xe6, 0xd8, 0xf2, 0xcc, 0xb0, + 0x48, 0x26, 0xcc, 0xf7, 0xd5, 0x4f, 0xe4, 0xc5, 0x03, 0x1b, 0xfa, 0xa1, 0xd6, + 0x09, 0x1e, 0x0e, 0xfd, 0xb4, 0x1a, 0xce, 0xce, 0x0a, 0x37, 0x12, 0xce, 0xd9, + 0xd2, 0xfc, 0x30, 0xaf, 0x05, 0x19, 0x1c, 0x46, 0xdc, 0xc9, 0x3c, 0x13, 0xed, + 0x05, 0xe6, 0x08, 0x7f, 0x56, 0xc7, 0xeb, 0x98, 0x05, 0x3e, 0xf8, 0xe9, 0x32, + 0xfd, 0xb8, 0x31, 0xd7, 0xe9, 0x18, 0x1f, 0x2f, 0xf3, 0xc5, 0xe7, 0x07, 0xc7, + 0x2e, 0x8a, 0x12, 0xd9, 0x2e, 0xf7, 0x14, 0x36, 0xe5, 0x10, 0x37, 0xd0, 0x0b, + 0xe0, 0xb6, 0xfc, 0xd7, 0x07, 0xad, 0xe6, 0x05, 0xf0, 0xcc, 0x1f, 0xe7, 0x4d, + 0xef, 0x17, 0xe0, 0xee, 0xef, 0xe9, 0xa6, 0x13, 0xc9, 0xaf, 0xf6, 0x21, 0xce, + 0x2e, 0x30, 0x1a, 0xba, 0xfb, 0x57, 0x01, 0x8c, 0xe0, 0x13, 0x09, 0x20, 0xe1, + 0x3b, 0xfb, 0xec, 0xf7, 0x27, 0xe8, 0x16, 0xc1, 0xe7, 0x0f, 0xb2, 0xd8, 0x16, + 0x0f, 0x3d, 0xe6, 0x49, 0xe4, 0x0c, 0x3a, 0x0e, 0xcf, 0x34, 0xf4, 0x2c, 0xf8, + 0xdd, 0x08, 0xd5, 0xf6, 0xf0, 0xdc, 0xfa, 0xe5, 0x17, 0xce, 0x4f, 0xb6, 0xdc, + 0x36, 0xde, 0x20, 0x32, 0xe4, 0xc0, 0x0d, 0x39, 0xf6, 0xf3, 0x0d, 0x14, 0xf9, + 0x0b, 0x2d, 0x5d, 0x42, 0xd1, 0x45, 0x14, 0xc7, 0x0c, 0xae, 0xeb, 0xbb, 0x32, + 0x0b, 0x04, 0xf5, 0x9c, 0xf2, 0xef, 0xc0, 0x4b, 0xf1, 0xb3, 0x2e, 0x13, 0x35, + 0xf4, 0xf3, 0x12, 0xfc, 0xcd, 0xed, 0xf4, 0xac, 0xd1, 0x04, 0xe9, 0xa9, 0x07, + 0xda, 0x50, 0xc7, 0xd4, 0x1e, 0xe8, 0xeb, 0x1e, 0x08, 0x4c, 0xe7, 0x57, 0xec, + 0xff, 0x04, 0xd6, 0x15, 0xcc, 0x56, 0x00, 0x0b, 0xeb, 0xe5, 0x50, 0x09, 0x16, + 0xf2, 0xd9, 0xdc, 0xf0, 0xee, 0x37, 0x26, 0x06, 0x0c, 0x20, 0xec, 0x1c, 0x0f, + 0x3c, 0xdc, 0xe6, 0x25, 0xdb, 0x04, 0x0d, 0x1c, 0x43, 0xf3, 0x23, 0x1b, 0x3a, + 0x11, 0x25, 0x02, 0xa6, 0x07, 0x06, 0xfb, 0xc9, 0xed, 0x59, 0x05, 0x1c, 0x03, + 0xde, 0x03, 0x45, 0x0d, 0xd0, 0x01, 0x33, 0x22, 0x0c, 0xfb, 0xc2, 0xf1, 0xd8, + 0xc3, 0xf0, 0x4b, 0xc3, 0x05, 0x20, 0x41, 0xcf, 0xde, 0xd7, 0x17, 0x12, 0x34, + 0xff, 0xfb, 0xe2, 0x10, 0xeb, 0xdb, 0xcd, 0x07, 0xdb, 0xed, 0xd9, 0x1e, 0x4a, + 0x2b, 0xf4, 0xab, 0xfd, 0x31, 0x04, 0xed, 0x02, 0x1c, 0xc5, 0x7e, 0xde, 0xb9, + 0x16, 0xb1, 0x05, 0x0a, 0xf2, 0xc6, 0x20, 0x1b, 0x14, 0xce, 0x4d, 0xe7, 0xf2, + 0x1b, 0xe0, 0xf8, 0x03, 0x15, 0x07, 0x19, 0x14, 0xfb, 0xeb, 0xb9, 0xbc, 0x25, + 0x0c, 0xd1, 0xfc, 0xe4, 0x34, 0xd0, 0x81, 0x0c, 0xe7, 0x07, 0x04, 0xd3, 0x34, + 0xe2, 0xc1, 0xdc, 0xd7, 0xd6, 0xe3, 0x34, 0x9d, 0xd9, 0xbc, 0x26, 0xb0, 0xbb, + 0x25, 0xdd, 0xe6, 0xdb, 0xf2, 0xe7, 0x00, 0x23, 0x06, 0x4c, 0xd9, 0x04, 0xc9, + 0x3b, 0x19, 0x0c, 0x06, 0x23, 0x1e, 0xf7, 0xe8, 0xf1, 0x32, 0x34, 0xe3, 0xd2, + 0xe5, 0xf5, 0x24, 0xf3, 0x31, 0x18, 0xef, 0xf4, 0x10, 0x0d, 0xc3, 0xed, 0x0d, + 0x3d, 0x0d, 0xfb, 0xc0, 0xda, 0x2a, 0xde, 0xee, 0x2d, 0x15, 0xfc, 0x03, 0xef, + 0x01, 0xe0, 0x2c, 0xee, 0xe4, 0x4b, 0x35, 0xcb, 0x2d, 0x1f, 0xb8, 0xdd, 0xc8, + 0xdc, 0x24, 0xdd, 0x16, 0x02, 0xd0, 0xe1, 0xd1, 0xbf, 0xea, 0x35, 0xe6, 0x8d, + 0x1b, 0xef, 0x5e, 0x0e, 0xd0, 0xe0, 0x16, 0x66, 0x18, 0x81, 0xce, 0x2c, 0x30, + 0xbd, 0xc9, 0x1a, 0x44, 0x0c, 0xfd, 0xdc, 0x04, 0xc4, 0xfa, 0xfd, 0x1b, 0x2f, + 0x04, 0xee, 0x0c, 0x0d, 0x04, 0xd4, 0x21, 0x2b, 0xd7, 0xb5, 0x33, 0x11, 0xc7, + 0xe2, 0xb2, 0x03, 0xf7, 0x00, 0x05, 0xd8, 0x5f, 0xb2, 0x27, 0x81, 0xdb, 0xa8, + 0xe5, 0xdf, 0x32, 0xf3, 0xb8, 0x13, 0xf7, 0xf2, 0xf3, 0x0f, 0x24, 0xb3, 0x1e, + 0x2e, 0xc0, 0xdc, 0xdf, 0xff, 0x36, 0x89, 0x3e, 0x30, 0xf5, 0xe2, 0x21, 0xf0, + 0x2b, 0x19, 0x10, 0xfa, 0x05, 0x3a, 0x06, 0xff, 0x1c, 0xb4, 0xff, 0xcd, 0xd9, + 0xe6, 0xf1, 0x37, 0x04, 0x19, 0xfe, 0xf2, 0xfa, 0xfb, 0x5a, 0x9d, 0xd3, 0x1e, + 0xa7, 0xb0, 0x27, 0xb0, 0xd9, 0x47, 0x3b, 0xfb, 0xf6, 0xcc, 0xf8, 0xd5, 0xdc, + 0xd9, 0xc2, 0xee, 0xc0, 0x0d, 0xf7, 0xd9, 0xc7, 0x1f, 0xd5, 0xee, 0xfd, 0xe4, + 0xea, 0x01, 0xef, 0x23, 0xfa, 0xee, 0xcf, 0xee, 0xab, 0xbb, 0x1a, 0x21, 0xdf, + 0x3f, 0x06, 0xd3, 0xd8, 0xf8, 0x2f, 0x99, 0xad, 0x06, 0xb8, 0xd7, 0x0b, 0x23, + 0x19, 0x1a, 0xc5, 0x28, 0xa5, 0x54, 0x4a, 0x14, 0x53, 0x9a, 0xd2, 0x12, 0xda, + 0x13, 0x3b, 0xf2, 0x2d, 0x0c, 0xca, 0x13, 0xe7, 0xd2, 0x07, 0xe8, 0xde, 0xb1, + 0x43, 0xcd, 0x37, 0xd6, 0xfe, 0xe9, 0xf7, 0xc0, 0x56, 0xfe, 0xc6, 0xdd, 0xf9, + 0x0b, 0xd8, 0x12, 0xe6, 0x02, 0x2b, 0x8c, 0x41, 0xb1, 0xd6, 0xaf, 0xf9, 0x26, + 0xd5, 0xc9, 0xff, 0xd8, 0x37, 0xcc, 0xf4, 0x03, 0x22, 0x40, 0x08, 0xcb, 0xcd, + 0xb1, 0xb6, 0x1c, 0xe4, 0xe1, 0xaf, 0xf8, 0xf8, 0xc2, 0xd5, 0xec, 0x29, 0xf1, + 0xe3, 0x27, 0xef, 0xf9, 0xc7, 0x08, 0x1f, 0xf0, 0xb3, 0x0a, 0x28, 0x4a, 0xea, + 0xb9, 0x08, 0x13, 0xff, 0x03, 0x52, 0x1c, 0xfb, 0x0a, 0xec, 0x02, 0x05, 0xcb, + 0x0c, 0xe0, 0x08, 0xf2, 0xf3, 0xd6, 0xe1, 0x2e, 0xf8, 0xc6, 0x0a, 0xf7, 0xc3, + 0x4a, 0x2f, 0xdd, 0x0a, 0xef, 0x1b, 0xfd, 0x10, 0xd7, 0xd1, 0xcb, 0x11, 0xfa, + 0x41, 0xc4, 0xdc, 0xf3, 0xfb, 0x3a, 0xee, 0xde, 0x12, 0x22, 0xef, 0x04, 0x24, + 0xb7, 0xd5, 0xe1, 0x07, 0x10, 0x1f, 0xb2, 0xc4, 0xd5, 0xc0, 0x30, 0xdf, 0xe9, + 0x28, 0x14, 0xe1, 0x02, 0x24, 0x27, 0x08, 0x25, 0x2f, 0x23, 0x05, 0x24, 0x00, + 0x26, 0xac, 0xb8, 0x02, 0xd5, 0x3d, 0xf0, 0x35, 0xd8, 0xe9, 0xeb, 0x6d, 0xe1, + 0xee, 0xf5, 0xfa, 0x4c, 0x27, 0x0d, 0x1d, 0xf2, 0xfb, 0xd6, 0x17, 0xf1, 0x1d, + 0xc9, 0x1a, 0x08, 0x30, 0x29, 0x17, 0xda, 0x18, 0x28, 0xea, 0x12, 0xf2, 0xf7, + 0x10, 0x3f, 0xe2, 0xe2, 0xe7, 0xfc, 0xcf, 0x1d, 0x1a, 0x07, 0xe3, 0x0e, 0xd8, + 0x1a, 0xde, 0x11, 0xf9, 0x0d, 0xa7, 0x1e, 0x37, 0x04, 0x4e, 0xcb, 0xe9, 0x28, + 0xee, 0xc5, 0xd4, 0xe9, 0xe6, 0x16, 0x16, 0x0e, 0xe8, 0x51, 0x07, 0xe6, 0xf5, + 0x00, 0xbd, 0xce, 0xc7, 0xb8, 0xed, 0x0b, 0xe2, 0x0e, 0xc0, 0x1a, 0xfc, 0xc4, + 0xc1, 0x0f, 0xe9, 0x0d, 0xcc, 0xd3, 0x28, 0x0c, 0x7f, 0xb2, 0x00, 0x22, 0xcb, + 0xe1, 0x26, 0xdb, 0x14, 0xec, 0x11, 0x27, 0x06, 0xb4, 0xff, 0xbf, 0x0b, 0x27, + 0xcb, 0xf5, 0xf8, 0x02, 0x23, 0x06, 0xc7, 0xcb, 0xfa, 0xef, 0x9a, 0x03, 0x13, + 0xce, 0x04, 0x09, 0x13, 0xe5, 0x24, 0x2a, 0x32, 0x10, 0xb8, 0xeb, 0xff, 0xe2, + 0x24, 0x14, 0xfb, 0xa5, 0xfe, 0x26, 0xc7, 0x9c, 0xe2, 0x6e, 0xd6, 0xe5, 0xd1, + 0x1d, 0xee, 0xd1, 0xf2, 0x02, 0xa7, 0x81, 0x7b, 0xe1, 0x13, 0x20, 0x1d, 0xc7, + 0x2f, 0xcf, 0x9a, 0x4f, 0xb3, 0x53, 0xc7, 0xcb, 0x05, 0x77, 0xc2, 0xa3, 0x67, + 0x98, 0x32, 0xc4, 0xe4, 0x19, 0xf6, 0x46, 0x39, 0x8d, 0xc1, 0x26, 0x37, 0xc2, + 0xf2, 0x53, 0xc6, 0x1f, 0x74, 0xf2, 0x0f, 0xc0, 0x5e, 0xf5, 0xcd, 0x49, 0x01, + 0x13, 0xfa, 0xd3, 0xe4, 0xce, 0xd8, 0xea, 0x1e, 0x21, 0xd2, 0xf9, 0x07, 0xaa, + 0x16, 0x2d, 0x25, 0xe7, 0x47, 0x0e, 0x0f, 0x24, 0xb3, 0xd6, 0xc4, 0x4b, 0x61, + 0xc4, 0xf4, 0xda, 0x06, 0xca, 0xc8, 0x15, 0x3d, 0x40, 0xfd, 0x1b, 0xdc, 0x9b, + 0x20, 0x07, 0xfc, 0x37, 0xc9, 0xc0, 0xa2, 0x95, 0xad, 0x41, 0x36, 0xd9, 0xac, + 0xfe, 0x13, 0xe5, 0x45, 0x2b, 0x1e, 0xec, 0x4c, 0x33, 0xdd, 0xf3, 0xd7, 0x1f, + 0xde, 0xf2, 0x2e, 0xf1, 0x12, 0xc3, 0xdf, 0xcf, 0x01, 0xda, 0xbd, 0xc5, 0x1a, + 0x29, 0x1b, 0x33, 0xec, 0xc3, 0xd7, 0xbe, 0x52, 0xe3, 0x25, 0x35, 0x16, 0x0a, + 0x3f, 0xae, 0x31, 0xd1, 0xef, 0xc5, 0xb7, 0xfa, 0x2e, 0x15, 0xbf, 0x3c, 0xb7, + 0x10, 0xba, 0xdc, 0x4a, 0x52, 0x68, 0x15, 0x50, 0x53, 0x2d, 0x95, 0x04, 0x0a, + 0x1f, 0x67, 0x2d, 0xbd, 0x28, 0xc6, 0xe9, 0x1d, 0xf1, 0xf8, 0xf2, 0xfd, 0x2c, + 0xec, 0xbf, 0x2d, 0xd4, 0xde, 0xdb, 0x5f, 0xdf, 0xff, 0xea, 0x15, 0xe6, 0xd6, + 0x15, 0x07, 0xf3, 0xed, 0xf1, 0xe4, 0xf0, 0x37, 0xd7, 0x90, 0xb8, 0xd3, 0x4a, + 0xd6, 0x14, 0x3b, 0xea, 0xf9, 0x32, 0x07, 0xe0, 0x15, 0x10, 0x2a, 0x16, 0xbb, + 0x10, 0xc8, 0x08, 0xca, 0x11, 0xfb, 0xb2, 0x17, 0xf1, 0x13, 0x18, 0xfe, 0xc9, + 0xe5, 0xa5, 0x2b, 0x05, 0x07, 0xef, 0x07, 0x13, 0xcd, 0x4e, 0xdc, 0x32, 0xef, + 0x1f, 0x24, 0x0d, 0x37, 0xfc, 0xf2, 0xbe, 0xea, 0xfa, 0x27, 0xa7, 0xd4, 0xe9, + 0xc8, 0x01, 0x0c, 0xf0, 0xc9, 0xeb, 0xcf, 0x51, 0x26, 0xd9, 0x0f, 0xfc, 0xcf, + 0xf2, 0x16, 0x0a, 0x0c, 0x1a, 0xe9, 0xef, 0x48, 0xf0, 0x56, 0xf0, 0xd8, 0xb2, + 0xfa, 0xa6, 0x2c, 0xb9, 0xb1, 0x15, 0x00, 0xd3, 0xf7, 0xf8, 0x27, 0xe3, 0xfd, + 0x1d, 0xff, 0xb6, 0x40, 0xef, 0x2a, 0xca, 0xdd, 0x02, 0x98, 0x12, 0x34, 0x1a, + 0x30, 0xcb, 0xf9, 0x3a, 0xd8, 0x30, 0xfb, 0x97, 0x2d, 0xb0, 0x1a, 0xa4, 0xc1, + 0xcc, 0x0c, 0xf0, 0x1b, 0x3e, 0xf1, 0x05, 0xff, 0xdb, 0x11, 0xac, 0xcd, 0xad, + 0x05, 0x0c, 0x0b, 0xf5, 0x12, 0x15, 0xf9, 0x32, 0xf0, 0xbc, 0xa9, 0x32, 0x0d, + 0xe9, 0xfc, 0xcc, 0xeb, 0x36, 0x7a, 0xf6, 0xc4, 0xff, 0xff, 0x24, 0xb2, 0xcc, + 0x47, 0xd5, 0x04, 0xe1, 0x7f, 0x21, 0xea, 0x16, 0xe2, 0x3e, 0x22, 0xcb, 0xf4, + 0xc9, 0x32, 0x36, 0xf4, 0xe8, 0x54, 0x34, 0x22, 0x3f, 0x26, 0xe2, 0xc4, 0xf8, + 0xcd, 0x29, 0xdc, 0x0f, 0xc8, 0xec, 0xc5, 0x29, 0x66, 0xe1, 0xf5, 0x54, 0xd0, + 0x00, 0x2a, 0xe2, 0x99, 0xc6, 0x11, 0xf8, 0x28, 0xf5, 0xdc, 0x2f, 0x06, 0x06, + 0x1c, 0x12, 0xd8, 0x3e, 0xba, 0xd9, 0x2f, 0x4c, 0xb6, 0x0d, 0x00, 0x25, 0x38, + 0x31, 0xe2, 0xdc, 0xd9, 0x3d, 0x65, 0x00, 0x40, 0x2f, 0xd2, 0x5d, 0xb4, 0xd7, + 0x45, 0x2b, 0x51, 0x39, 0x03, 0xf6, 0x2a, 0x06, 0x98, 0x07, 0xf5, 0x0f, 0xf5, + 0x69, 0x31, 0x2a, 0x06, 0x01, 0x38, 0xc3, 0xe0, 0xf9, 0x07, 0xfa, 0xd7, 0x15, + 0x10, 0x20, 0xf2, 0xf0, 0xc8, 0x02, 0xf2, 0x59, 0xd7, 0xcb, 0x10, 0xf9, 0x2a, + 0x1a, 0x09, 0xfc, 0xce, 0x2c, 0xe9, 0xc3, 0xd4, 0xe0, 0xb6, 0x02, 0xe4, 0xdb, + 0x29, 0xff, 0xc0, 0x3e, 0xc2, 0xfd, 0xf4, 0xeb, 0xfa, 0xf9, 0x11, 0x3b, 0x06, + 0xb6, 0x2c, 0x1d, 0xa9, 0x0c, 0xe0, 0x25, 0x00, 0xf0, 0xef, 0x29, 0xdd, 0xe1, + 0xdc, 0x17, 0xda, 0xf9, 0xe9, 0x3d, 0xff, 0x0a, 0xbe, 0xe4, 0x1e, 0x03, 0xd8, + 0x3e, 0x21, 0xb8, 0x01, 0x41, 0x0c, 0xb8, 0xe7, 0x42, 0x82, 0x28, 0x2a, 0xd4, + 0xe4, 0xee, 0xe1, 0xd4, 0x3e, 0xc5, 0xd5, 0xca, 0x41, 0x34, 0xdb, 0x20, 0x05, + 0x1b, 0x3b, 0x20, 0xd4, 0x1d, 0xa4, 0xe4, 0x00, 0xac, 0x67, 0xc5, 0xe4, 0x35, + 0x36, 0x04, 0x37, 0x13, 0xf0, 0xcc, 0xbb, 0xd5, 0xe2, 0x42, 0xac, 0x16, 0xfd, + 0xca, 0xfe, 0xc8, 0x42, 0x38, 0x29, 0x3a, 0xb5, 0xbc, 0xd6, 0x9a, 0x34, 0x08, + 0xd7, 0x9a, 0x36, 0x2e, 0x0e, 0x33, 0xb8, 0xfc, 0xda, 0x94, 0x06, 0xb7, 0xaa, + 0x33, 0xf2, 0xec, 0x9d, 0x10, 0xb7, 0x29, 0xc4, 0x73, 0x26, 0x4c, 0x09, 0x79, + 0x01, 0xfd, 0x34, 0xe3, 0xdd, 0xe5, 0x9f, 0xd2, 0x1d, 0x25, 0xa3, 0xfe, 0xf7, + 0xf2, 0x16, 0xf4, 0x33, 0x23, 0xf3, 0xca, 0x0d, 0x20, 0xe5, 0x37, 0xf2, 0xe6, + 0x38, 0x39, 0xf4, 0xf7, 0xf2, 0x53, 0xfe, 0xd5, 0xe9, 0x33, 0x17, 0xdb, 0x06, + 0xf4, 0xe9, 0xec, 0xca, 0x83, 0xb4, 0xf8, 0x15, 0x4f, 0x7a, 0xea, 0x0f, 0xfc, + 0xe5, 0x95, 0x36, 0x37, 0xe1, 0xf4, 0x51, 0xde, 0x0d, 0x04, 0x27, 0x3e, 0x32, + 0x10, 0xf2, 0xf1, 0xa1, 0xa8, 0x1f, 0xe4, 0x15, 0xee, 0xd7, 0x2b, 0xd0, 0xdd, + 0xd9, 0xdc, 0x08, 0xe6, 0xc2, 0xe8, 0xae, 0xe9, 0xd0, 0x04, 0xc3, 0xeb, 0x32, + 0x8f, 0x02, 0xa4, 0x2f, 0x97, 0xed, 0xd0, 0x00, 0xc1, 0xdd, 0x00, 0xf5, 0x1e, + 0x34, 0xed, 0x22, 0xfd, 0x0e, 0xe2, 0x48, 0x81, 0x15, 0x42, 0x3e, 0xe0, 0x59, + 0xe6, 0xf7, 0x5f, 0xe5, 0xcf, 0xaf, 0x3f, 0xfb, 0xfc, 0x17, 0x34, 0x1d, 0xe4, + 0x06, 0xb6, 0xe9, 0x20, 0xeb, 0xbc, 0xe5, 0xdb, 0xbd, 0xc4, 0x3f, 0xce, 0xe6, + 0x88, 0x20, 0xd3, 0xf3, 0xcf, 0x1c, 0xba, 0xe9, 0x13, 0xd3, 0xc3, 0xfd, 0xf1, + 0xdd, 0x53, 0xe6, 0x43, 0xf7, 0xaa, 0xdd, 0xde, 0xf9, 0xfb, 0xe6, 0xd9, 0xc3, + 0x16, 0xb1, 0xdd, 0xe3, 0x11, 0x36, 0xf4, 0xf9, 0xb7, 0xbd, 0xaa, 0x2f, 0xa0, + 0xd8, 0xfc, 0x1e, 0xb7, 0x47, 0x00, 0x32, 0x10, 0x16, 0xf4, 0x6e, 0x16, 0xce, + 0xde, 0x00, 0xea, 0xdf, 0x25, 0x32, 0xfa, 0x2e, 0x57, 0x2b, 0x0d, 0xb2, 0xde, + 0xf6, 0xd6, 0x4b, 0xe4, 0x22, 0xe5, 0x11, 0xd8, 0xdd, 0xcc, 0xd3, 0xc2, 0xc7, + 0x30, 0xc8, 0x22, 0xac, 0xe5, 0xd5, 0xf8, 0xf7, 0xf9, 0x24, 0xab, 0x24, 0xdc, + 0x15, 0xf2, 0xb3, 0x02, 0x19, 0xfa, 0x31, 0xc5, 0xd1, 0xf3, 0xea, 0xd6, 0xca, + 0x05, 0xe8, 0xdf, 0xe4, 0x09, 0x1a, 0xd4, 0xe4, 0x7f, 0x49, 0xb3, 0xdf, 0xaa, + 0xf2, 0x07, 0xdb, 0x16, 0x21, 0x21, 0x1e, 0xfb, 0xd9, 0xda, 0x0b, 0x15, 0xab, + 0x1d, 0xf7, 0x33, 0x37, 0xe3, 0x07, 0xd3, 0xe6, 0xb3, 0xf1, 0x19, 0xfe, 0xf0, + 0xd3, 0xba, 0xff, 0xe1, 0xfd, 0xcc, 0x26, 0xdd, 0x3c, 0x31, 0xef, 0xd8, 0xbe, + 0x36, 0xf3, 0xd5, 0xd5, 0xe8, 0xf5, 0x09, 0x28, 0x43, 0x1b, 0x10, 0xbd, 0x9a, + 0xdb, 0x2c, 0xdf, 0xc5, 0xe0, 0xc7, 0x1f, 0xda, 0x00, 0xd1, 0x0b, 0xba, 0xfd, + 0x0c, 0x2f, 0xc0, 0xf5, 0xf1, 0x09, 0xef, 0x06, 0x1c, 0xee, 0xfa, 0xf9, 0xf5, + 0xea, 0x9a, 0xec, 0x30, 0xf6, 0x0c, 0xbe, 0xe4, 0x06, 0xed, 0x62, 0xa9, 0xd2, + 0xc8, 0xf0, 0xfb, 0x4a, 0xf9, 0xee, 0x4d, 0xca, 0xd0, 0xdf, 0x04, 0xf5, 0x06, + 0x17, 0x3e, 0x69, 0x0b, 0x3d, 0x46, 0x9f, 0xef, 0x05, 0xb3, 0xe6, 0xc9, 0xaa, + 0x19, 0xd9, 0x1d, 0xc8, 0x0d, 0x0e, 0xd0, 0x56, 0x2a, 0xef, 0x3b, 0x6a, 0x45, + 0xad, 0x9b, 0x0d, 0xcb, 0x39, 0xd5, 0x2b, 0xf2, 0xe9, 0x20, 0xfc, 0x19, 0xd9, + 0xb7, 0xd6, 0xf0, 0xd4, 0x0a, 0xfc, 0x14, 0x11, 0xfe, 0xdb, 0x02, 0x0b, 0x11, + 0x01, 0xea, 0xa8, 0x15, 0xc9, 0x9f, 0xf0, 0xdf, 0xdf, 0xdb, 0x06, 0xee, 0xda, + 0xe1, 0xf9, 0xc2, 0x13, 0xff, 0x1b, 0x27, 0xe8, 0xf7, 0xe2, 0xf2, 0xc0, 0x13, + 0xb3, 0xf7, 0xd5, 0xdb, 0x41, 0xf4, 0xd6, 0xe5, 0xf9, 0xa2, 0xf3, 0x1a, 0x61, + 0xd6, 0x18, 0xf2, 0xf7, 0x05, 0xec, 0xdf, 0xe1, 0x44, 0xe6, 0x1d, 0x2e, 0xdf, + 0x1a, 0x42, 0xf3, 0xe0, 0x11, 0x02, 0xf0, 0xec, 0x55, 0xef, 0x01, 0xe9, 0xcd, + 0xfc, 0x0a, 0x28, 0x32, 0x38, 0x28, 0x4e, 0x57, 0x13, 0xd5, 0xf2, 0xd2, 0xda, + 0x00, 0xe6, 0x28, 0x03, 0xf3, 0xbd, 0x4c, 0x54, 0xd6, 0x01, 0xf9, 0x2e, 0x54, + 0xde, 0x25, 0x05, 0xe3, 0xbc, 0x0e, 0xa7, 0xa6, 0xd2, 0xf2, 0xc8, 0x0a, 0xcc, + 0xf1, 0xd8, 0x0f, 0x07, 0xf2, 0xf6, 0x4b, 0xf5, 0xb6, 0x08, 0xd4, 0xf9, 0x23, + 0xd4, 0xc6, 0x11, 0xd3, 0x78, 0x06, 0x3a, 0x03, 0xfc, 0x25, 0xee, 0x2b, 0xd0, + 0x27, 0x37, 0x04, 0x4c, 0xc7, 0xe2, 0xe9, 0xc3, 0xd3, 0xd4, 0xf0, 0xed, 0xe4, + 0x12, 0x45, 0xdb, 0x01, 0xf1, 0xf7, 0xd3, 0x43, 0x04, 0x3c, 0x1c, 0xfd, 0x40, + 0x10, 0x84, 0x4e, 0xe4, 0x1b, 0x03, 0x15, 0xae, 0xde, 0x05, 0xfb, 0x00, 0x26, + 0xd5, 0xc3, 0x20, 0x32, 0x21, 0xf1, 0xd9, 0xb2, 0x23, 0xf8, 0xf8, 0xf7, 0xe7, + 0x2b, 0xf4, 0xc8, 0xfe, 0x78, 0x22, 0x72, 0xdc, 0xf0, 0x2d, 0x1d, 0xc1, 0x22, + 0x10, 0x60, 0x45, 0x45, 0xc1, 0x60, 0xcc, 0x81, 0x16, 0xd3, 0xc6, 0xcd, 0xfe, + 0xc7, 0xcd, 0x07, 0xe8, 0xbf, 0xfb, 0xfb, 0xd5, 0x0b, 0x1f, 0xeb, 0x1c, 0x24, + 0xef, 0x19, 0xde, 0xc6, 0xbf, 0x00, 0xc9, 0x08, 0x11, 0xed, 0xf0, 0xf8, 0xf3, + 0xd3, 0x2f, 0xe9, 0xe8, 0xc0, 0xdf, 0xf4, 0x30, 0xe6, 0x1d, 0xff, 0xe6, 0xed, + 0x2d, 0xb2, 0xb9, 0xfd, 0xd0, 0x95, 0x2b, 0xd2, 0x38, 0x1f, 0xc2, 0x0f, 0x14, + 0xb8, 0x09, 0x07, 0xff, 0x02, 0xe7, 0xe2, 0xcc, 0x29, 0x12, 0xf1, 0x09, 0x01, + 0xc4, 0x01, 0xb7, 0xd6, 0xc5, 0xdf, 0xd8, 0xff, 0x12, 0x14, 0x1f, 0xb9, 0x1b, + 0x1b, 0x53, 0xc4, 0x02, 0xee, 0xd9, 0xcf, 0xeb, 0xc2, 0xd9, 0x0a, 0x35, 0x09, + 0xf2, 0x0e, 0x04, 0x65, 0xee, 0xad, 0x10, 0x05, 0x2c, 0x14, 0x19, 0xf3, 0x12, + 0xb7, 0x1e, 0x24, 0xe7, 0xc9, 0x24, 0xec, 0xf7, 0x24, 0x07, 0x2d, 0xce, 0x3c, + 0xf0, 0xef, 0x1b, 0xe6, 0x05, 0xb0, 0xf7, 0xe9, 0x13, 0xdb, 0xea, 0xdb, 0xff, + 0x06, 0xd8, 0x25, 0x2c, 0xc5, 0x03, 0xe0, 0xec, 0xef, 0x02, 0x04, 0xdd, 0xd7, + 0x02, 0xd3, 0xed, 0x0b, 0x1e, 0x01, 0xe7, 0xdf, 0xcb, 0xf9, 0xba, 0x02, 0xde, + 0x3b, 0x14, 0xee, 0x28, 0x2f, 0xf6, 0x1b, 0x0b, 0x20, 0x30, 0xfe, 0xf8, 0xed, + 0x1b, 0x04, 0x02, 0xef, 0xc3, 0xf5, 0x06, 0xe3, 0xe8, 0xe8, 0x24, 0x19, 0x1a, + 0xc7, 0x0c, 0x83, 0xe1, 0x7f, 0xe3, 0xc4, 0xf0, 0x00, 0xfc, 0xff, 0xfa, 0x0a, + 0xf9, 0xf7, 0x12, 0x09, 0x2f, 0xf1, 0xef, 0x6b, 0xd0, 0x1c, 0x3a, 0x02, 0xc1, + 0xde, 0x05, 0x23, 0xe8, 0xf2, 0xc9, 0xf2, 0xf0, 0x30, 0xf8, 0x02, 0xae, 0xac, + 0xcc, 0xc9, 0x20, 0x02, 0x14, 0xec, 0xd9, 0xb3, 0xf7, 0xcb, 0x03, 0x09, 0xd3, + 0x13, 0x93, 0xe0, 0xa5, 0xf1, 0xe2, 0xe1, 0xe1, 0x02, 0xd0, 0xeb, 0x05, 0x1e, + 0xdb, 0xc0, 0xf7, 0x3f, 0x2e, 0xbc, 0xfb, 0x33, 0xf7, 0x1f, 0x48, 0x11, 0x18, + 0x2a, 0x31, 0x3a, 0x01, 0x2f, 0xd6, 0xce, 0x05, 0xfd, 0xc2, 0x40, 0xf5, 0xef, + 0x06, 0x9d, 0x1a, 0xe2, 0xae, 0xe4, 0x0a, 0xb7, 0xd3, 0x07, 0x33, 0x01, 0x16, + 0x0d, 0xeb, 0xe7, 0xfc, 0x09, 0xda, 0xd9, 0xc5, 0x01, 0xfa, 0xce, 0xf3, 0xe2, + 0xd5, 0xe7, 0xc1, 0xdc, 0x1f, 0x1d, 0xc3, 0xfa, 0xc0, 0xe8, 0xf4, 0xe3, 0xba, + 0xe5, 0xe5, 0x06, 0x06, 0x3b, 0xff, 0x18, 0xac, 0xdc, 0x25, 0xd5, 0xe3, 0x32, + 0xc3, 0xb8, 0x13, 0x28, 0xed, 0x1f, 0xc9, 0xf2, 0xe7, 0x0a, 0xfa, 0xbc, 0x66, + 0xfa, 0xf6, 0xeb, 0xfa, 0xca, 0xe0, 0x17, 0x1d, 0xf7, 0x11, 0xfc, 0xf6, 0xd4, + 0x08, 0xde, 0xe6, 0x38, 0x0d, 0x25, 0xa9, 0xd9, 0xe0, 0x2f, 0x0b, 0xd0, 0x08, + 0xd6, 0xfa, 0x1f, 0x3e, 0xcf, 0xed, 0xfd, 0xaf, 0xb7, 0xc0, 0xf6, 0xf3, 0x0f, + 0x44, 0x8b, 0xd8, 0xf3, 0xc8, 0xf4, 0x1e, 0xf2, 0xe3, 0x97, 0xac, 0x0c, 0x15, + 0xee, 0x16, 0xed, 0xef, 0xe5, 0x15, 0xdb, 0x4c, 0xad, 0xdc, 0x20, 0xbe, 0xcb, + 0xf2, 0xb7, 0x00, 0x1f, 0xd7, 0xc2, 0x0e, 0xb1, 0x2a, 0x24, 0xdb, 0x2f, 0xd6, + 0x09, 0xe7, 0xe5, 0xf5, 0x36, 0x2d, 0xc0, 0xea, 0x38, 0x28, 0x15, 0x0a, 0xb5, + 0x26, 0x05, 0x05, 0x8b, 0xef, 0xf8, 0x1d, 0xfb, 0xdb, 0xef, 0x08, 0xec, 0x29, + 0xe5, 0x0c, 0x56, 0xbf, 0xf7, 0xfd, 0x08, 0xf6, 0x50, 0xed, 0x00, 0x0b, 0xc9, + 0xe0, 0x0f, 0xf2, 0xdc, 0xef, 0x1c, 0xb0, 0xe6, 0xc6, 0x00, 0x1e, 0xbf, 0x44, + 0xe4, 0xed, 0x07, 0x09, 0xfa, 0x01, 0xfd, 0xf6, 0x25, 0xe1, 0xdf, 0x72, 0xbb, + 0xfb, 0xb5, 0xe9, 0xb8, 0xbb, 0xb6, 0x7f, 0xdd, 0xe6, 0x0a, 0xda, 0x72, 0xd2, + 0x18, 0xc4, 0xc2, 0x03, 0x12, 0x09, 0xee, 0x16, 0x8b, 0x15, 0x11, 0x16, 0xfe, + 0xe7, 0xef, 0x26, 0x32, 0xdd, 0x08, 0xf9, 0x08, 0x2a, 0xb3, 0xd9, 0x5f, 0xe4, + 0x0f, 0xe6, 0xbc, 0x41, 0x1b, 0x02, 0xd9, 0xf0, 0x00, 0x45, 0xed, 0xe6, 0x16, + 0xc5, 0x12, 0x20, 0xf9, 0x08, 0x19, 0x2b, 0xd1, 0x02, 0xda, 0xf6, 0x1a, 0xff, + 0x08, 0x03, 0xdb, 0xed, 0xf9, 0xc9, 0x1b, 0xe3, 0x13, 0x17, 0x13, 0x3b, 0x2d, + 0x1d, 0xe5, 0xfb, 0xfd, 0xef, 0x28, 0x06, 0xc8, 0xc2, 0xd3, 0xcc, 0xaa, 0xd6, + 0xf8, 0xf8, 0x37, 0xf0, 0xf5, 0xd9, 0xf4, 0xf7, 0x10, 0xc7, 0xd4, 0xef, 0x02, + 0xe7, 0xf6, 0xda, 0xf8, 0xeb, 0x21, 0xc3, 0x37, 0x02, 0xbf, 0x03, 0xc7, 0xd9, + 0xd7, 0x0a, 0xfd, 0x30, 0x2b, 0x0d, 0x28, 0x18, 0x03, 0xd0, 0xcb, 0xbb, 0x36, + 0xe4, 0xed, 0xba, 0x2d, 0xf8, 0x14, 0x13, 0xaa, 0xbf, 0x22, 0xe8, 0xea, 0x11, + 0x12, 0xe6, 0xcc, 0x0b, 0xef, 0x9b, 0x15, 0xbd, 0xfa, 0xd5, 0xf2, 0xef, 0xd9, + 0xef, 0x1a, 0xec, 0x31, 0xc2, 0xd0, 0xd8, 0xf1, 0xcf, 0x2f, 0xdf, 0xf8, 0xdc, + 0xbc, 0xb8, 0xde, 0xe2, 0xfa, 0x3c, 0xf7, 0xc5, 0xcd, 0xfc, 0x0b, 0x14, 0x1e, + 0xff, 0x01, 0xfe, 0xfc, 0xe0, 0xdf, 0x07, 0x0a, 0xda, 0xf4, 0xea, 0x0e, 0xfd, + 0x3e, 0xf0, 0xce, 0x9d, 0xe5, 0xdf, 0x23, 0xc7, 0xf5, 0xec, 0x0e, 0xec, 0xea, + 0x19, 0x31, 0xb2, 0x2d, 0xfe, 0xd6, 0xe9, 0x0a, 0x00, 0xe5, 0x7f, 0x15, 0xc3, + 0xd7, 0xc7, 0xb9, 0x03, 0xf5, 0xd6, 0x30, 0xfe, 0xd1, 0x07, 0xb8, 0x4e, 0xc6, + 0xf3, 0xfe, 0xd6, 0xf8, 0x0f, 0x2f, 0xf2, 0xf0, 0x2b, 0x07, 0xe5, 0xe1, 0xd5, + 0xf7, 0xf0, 0x1b, 0xd7, 0x21, 0x42, 0xc0, 0x40, 0x13, 0xb3, 0xd1, 0xd9, 0x43, + 0x0e, 0x04, 0xfd, 0x32, 0xd6, 0x18, 0x09, 0x11, 0xda, 0x21, 0x94, 0xe3, 0xf5, + 0x16, 0xb2, 0xe0, 0xf9, 0x93, 0xf9, 0xcd, 0xfb, 0x0d, 0xc9, 0xef, 0xfa, 0x04, + 0x2c, 0x06, 0x07, 0xdd, 0x42, 0xcc, 0x15, 0x11, 0xca, 0x18, 0x2e, 0xf2, 0x4d, + 0x19, 0x1b, 0x44, 0x33, 0x30, 0xf8, 0x03, 0xd9, 0x2f, 0xdb, 0x37, 0xdb, 0x06, + 0x16, 0x0b, 0xcc, 0x09, 0xba, 0xd4, 0x6e, 0xee, 0xe8, 0x05, 0xcc, 0x21, 0xe8, + 0xec, 0xd8, 0xc5, 0xf6, 0xb0, 0x18, 0xb1, 0x24, 0xfa, 0x22, 0xc4, 0x02, 0x3a, + 0x2a, 0x26, 0xa3, 0xf8, 0x26, 0xb7, 0x07, 0xee, 0x03, 0x0d, 0x10, 0xe2, 0x38, + 0x02, 0xf9, 0xdf, 0x2e, 0x3c, 0xae, 0x37, 0x19, 0xd8, 0x00, 0x20, 0xd3, 0xdb, + 0xe0, 0x38, 0x04, 0x4b, 0x01, 0x3a, 0x60, 0xe7, 0xe2, 0xd7, 0xc4, 0xf5, 0xb8, + 0x35, 0x25, 0xc9, 0x57, 0xf3, 0x3b, 0x3b, 0xd4, 0x23, 0xd3, 0x0d, 0x09, 0x00, + 0xec, 0x00, 0x63, 0xec, 0x2e, 0x21, 0x1e, 0x81, 0xed, 0xd2, 0xc5, 0x12, 0xf9, + 0x2f, 0xf6, 0x04, 0xd6, 0xf5, 0x29, 0x0b, 0xcc, 0x09, 0x90, 0x32, 0xc8, 0x27, + 0xf6, 0xd7, 0xe6, 0xe2, 0xee, 0x1c, 0x2f, 0x0e, 0xfe, 0x03, 0xbf, 0xbb, 0x1d, + 0x27, 0x6c, 0x25, 0x10, 0x27, 0xee, 0x59, 0xc5, 0xd1, 0xd1, 0x2a, 0x50, 0xd0, + 0xe6, 0xd9, 0x33, 0xd1, 0xed, 0x1c, 0xe2, 0xea, 0x57, 0x14, 0xe3, 0xe8, 0x08, + 0x00, 0x52, 0xe8, 0x06, 0xdf, 0xb6, 0xee, 0xe0, 0x3d, 0x04, 0xdc, 0xf2, 0x0a, + 0x0a, 0xd8, 0xb9, 0xfd, 0x9a, 0xe3, 0x0a, 0x19, 0x0f, 0x1b, 0xf5, 0xd2, 0xc6, + 0x13, 0xff, 0xee, 0xb7, 0x25, 0x0e, 0x46, 0xfc, 0xe4, 0xe5, 0xdc, 0xf2, 0xd2, + 0x51, 0x2a, 0xf8, 0xf3, 0xc8, 0xc2, 0xe8, 0xe4, 0x53, 0x43, 0x15, 0x30, 0xd6, + 0x43, 0xf7, 0xd4, 0x24, 0xfa, 0x18, 0xe1, 0x23, 0xc3, 0xb5, 0x2e, 0x65, 0x4c, + 0x2a, 0x01, 0xf1, 0xce, 0xd0, 0x92, 0xab, 0xbf, 0xc5, 0x30, 0xe2, 0xa8, 0xe7, + 0x0d, 0x26, 0xba, 0x09, 0x0a, 0x4c, 0x03, 0xf9, 0xab, 0x1c, 0x05, 0x33, 0x0f, + 0x90, 0x32, 0x0d, 0xe1, 0x10, 0xa1, 0x47, 0xbf, 0x0b, 0xc5, 0xe0, 0x22, 0xd2, + 0xe7, 0xd3, 0xf1, 0xdc, 0x02, 0x25, 0x13, 0xc9, 0xf5, 0x89, 0xb2, 0x87, 0x06, + 0xce, 0xed, 0xa9, 0xd8, 0x45, 0x21, 0x20, 0xd2, 0xec, 0xfe, 0xcf, 0x2d, 0xa7, + 0xfb, 0x1a, 0x25, 0xb8, 0xe0, 0x08, 0xbb, 0xed, 0x0d, 0x1d, 0xf4, 0x91, 0xb7, + 0x55, 0xe8, 0xe6, 0x1a, 0xf9, 0x36, 0xb0, 0xba, 0xe0, 0x3b, 0xd2, 0x3b, 0xfd, + 0x03, 0xce, 0x51, 0x29, 0xf5, 0xd7, 0x30, 0x32, 0x19, 0xa2, 0xee, 0xf7, 0x5e, + 0x39, 0x25, 0xda, 0xd7, 0x26, 0x1e, 0xf0, 0x0b, 0xf5, 0xdb, 0xd9, 0x16, 0xbf, + 0x3d, 0xf9, 0xc4, 0xaa, 0xdc, 0x1f, 0x35, 0x06, 0x09, 0xca, 0xad, 0xf1, 0xdf, + 0xd6, 0x27, 0x13, 0xa2, 0xe3, 0x0c, 0xe1, 0x3c, 0x1f, 0xd3, 0x27, 0xcb, 0xf7, + 0x36, 0xef, 0x02, 0xdb, 0x0d, 0x07, 0x1b, 0xcb, 0xf1, 0xd6, 0x0c, 0x34, 0xe3, + 0xd4, 0x02, 0xf6, 0x21, 0xcd, 0xcb, 0xfd, 0xc5, 0x04, 0xda, 0x13, 0xa0, 0xa9, + 0x13, 0xca, 0x1c, 0x23, 0x23, 0x27, 0xe5, 0x5a, 0xd1, 0xef, 0x43, 0x04, 0xd3, + 0xe6, 0x45, 0xf3, 0x44, 0xbb, 0x00, 0xf1, 0x39, 0xcc, 0xba, 0xf8, 0x1d, 0x06, + 0x30, 0xf6, 0xd0, 0xb2, 0x0c, 0xdc, 0xdf, 0x1d, 0xd0, 0x45, 0xb2, 0xde, 0xe0, + 0x00, 0xd5, 0x7f, 0xfe, 0xe5, 0x1e, 0x58, 0x2e, 0x01, 0xf1, 0x1d, 0xd5, 0xeb, + 0xc6, 0x09, 0x0f, 0x14, 0xd5, 0x12, 0xe8, 0xb8, 0xda, 0x1b, 0xd5, 0x1f, 0xe7, + 0x39, 0xda, 0xd3, 0x18, 0xf6, 0xfb, 0x1f, 0x11, 0xfe, 0xff, 0x67, 0xdc, 0xe0, + 0x41, 0xf4, 0xe8, 0xe8, 0xf2, 0xed, 0x27, 0xdc, 0xa9, 0xf1, 0xc3, 0x9a, 0xb5, + 0xd7, 0xe3, 0xf5, 0xfb, 0x28, 0xb9, 0xf5, 0xd7, 0x12, 0x25, 0xd7, 0xe5, 0xf6, + 0x4c, 0x29, 0xfd, 0xdc, 0xc3, 0xe6, 0x3c, 0x12, 0x09, 0xe9, 0xfe, 0xf8, 0x05, + 0x4f, 0xbb, 0x25, 0x02, 0xd8, 0xb3, 0xd6, 0xbe, 0x1e, 0xd6, 0xdb, 0xf2, 0xe7, + 0x23, 0x04, 0x13, 0xe7, 0x09, 0x3a, 0xfa, 0xa8, 0x1e, 0xf9, 0x0b, 0x2e, 0xdb, + 0xc1, 0xe0, 0x06, 0xb5, 0xc3, 0x01, 0xf7, 0x34, 0xe6, 0xb9, 0x01, 0xf1, 0x02, + 0xe2, 0x13, 0xc7, 0x05, 0x08, 0x02, 0x4c, 0x54, 0x1d, 0xf6, 0x04, 0x25, 0x29, + 0xb1, 0xe6, 0xe9, 0xd9, 0x06, 0x26, 0xe9, 0xed, 0xfc, 0xdf, 0x2a, 0xb2, 0x0a, + 0xc9, 0x1c, 0x2a, 0xf9, 0x17, 0xf3, 0x08, 0xe9, 0xff, 0xe8, 0xba, 0x17, 0x08, + 0x09, 0xea, 0x1f, 0x07, 0xf3, 0x13, 0xea, 0xe4, 0xd7, 0x29, 0xf3, 0xe8, 0xce, + 0xf6, 0x16, 0xda, 0xfb, 0x07, 0xb7, 0x08, 0xd3, 0xe4, 0x36, 0xc7, 0xc4, 0x34, + 0x23, 0x36, 0x00, 0xe8, 0xf4, 0xbd, 0xfa, 0xf7, 0x98, 0xdd, 0xe9, 0xf9, 0x2b, + 0xb2, 0x37, 0xfe, 0xcd, 0x0b, 0x0f, 0xe8, 0x03, 0xb2, 0xdb, 0x15, 0xb7, 0xf7, + 0xc6, 0xeb, 0xf9, 0xc5, 0xf3, 0xe2, 0x23, 0x35, 0xb9, 0xb6, 0xcc, 0xfd, 0xb0, + 0x18, 0xb9, 0x1e, 0xf2, 0xf2, 0xeb, 0xe8, 0x33, 0xde, 0x02, 0xe1, 0x1e, 0xce, + 0x30, 0xfb, 0x7f, 0xec, 0xfd, 0xb4, 0x0b, 0x15, 0x1a, 0x59, 0xe6, 0xe1, 0xe3, + 0x25, 0x01, 0x07, 0x3c, 0x15, 0xae, 0xf5, 0xe9, 0x35, 0x19, 0xe8, 0xfe, 0x06, + 0x0f, 0x27, 0x0e, 0xdc, 0x17, 0x1c, 0x37, 0xaa, 0x3c, 0xe7, 0x37, 0x07, 0x18, + 0xc3, 0xc8, 0xf1, 0x53, 0xcc, 0xdc, 0xb3, 0xe0, 0xe2, 0x2d, 0xe9, 0xe4, 0xdd, + 0xf7, 0x13, 0x27, 0xc9, 0x52, 0x03, 0x0a, 0x9f, 0x06, 0x2e, 0x40, 0xf0, 0x03, + 0x22, 0x46, 0xf3, 0x0d, 0xb4, 0xfb, 0xf7, 0xd1, 0xbd, 0xd8, 0x11, 0xf8, 0xc5, + 0xcd, 0xfa, 0xf8, 0xc6, 0xbe, 0xb5, 0xc9, 0x27, 0xbb, 0xb6, 0xfe, 0x0b, 0x95, + 0xd1, 0xbf, 0xb2, 0xc4, 0x0b, 0xc8, 0x3d, 0x15, 0x2d, 0x04, 0x2e, 0xe9, 0xfd, + 0xd3, 0xc1, 0xfa, 0xe6, 0x17, 0x03, 0xc8, 0xc0, 0xeb, 0x14, 0xb3, 0x13, 0x19, + 0xda, 0x1e, 0x09, 0xa8, 0xd0, 0xf3, 0xc9, 0x23, 0xbf, 0x3f, 0xf2, 0xac, 0x26, + 0xfc, 0x17, 0xbd, 0xf9, 0xf8, 0x32, 0xe6, 0x4b, 0xd9, 0xc4, 0x58, 0xff, 0xe5, + 0xe0, 0xec, 0x19, 0xe7, 0xff, 0xf1, 0x0f, 0x99, 0xe8, 0x1c, 0xe9, 0x1c, 0x4d, + 0x27, 0xe7, 0xbd, 0xdb, 0x0b, 0x49, 0x3b, 0xf6, 0x11, 0x1a, 0x20, 0xe2, 0x0a, + 0xc8, 0xc1, 0xcf, 0xe7, 0x0a, 0x20, 0xc9, 0x9e, 0xe3, 0xe3, 0x55, 0xcc, 0x00, + 0x15, 0xfb, 0x4d, 0xc4, 0x1c, 0xfe, 0x93, 0xaa, 0xe3, 0x0e, 0xce, 0xdc, 0x1a, + 0x57, 0x16, 0x2c, 0x15, 0x45, 0xd0, 0x17, 0x17, 0xe8, 0xe6, 0x4b, 0xc4, 0x36, + 0xf7, 0x51, 0x0a, 0x32, 0x07, 0x28, 0xcb, 0xba, 0xe2, 0xea, 0x09, 0x08, 0xe1, + 0x1d, 0x41, 0xb9, 0x14, 0x7b, 0xc1, 0xd4, 0x06, 0xfd, 0x07, 0x3c, 0x11, 0x4a, + 0xf1, 0xe2, 0x29, 0xf9, 0xf1, 0xb7, 0xe3, 0x1e, 0xf9, 0x03, 0xce, 0x18, 0x27, + 0xf9, 0xd9, 0x05, 0x07, 0x6c, 0xfc, 0xbe, 0x17, 0xcf, 0xfd, 0xf1, 0xd3, 0xf4, + 0xf7, 0xc9, 0xdf, 0xaa, 0x3d, 0xfb, 0x25, 0x04, 0x2b, 0xe5, 0xf9, 0x1e, 0xfe, + 0xfa, 0x53, 0xeb, 0xca, 0xfb, 0xf3, 0xfd, 0xc8, 0x2d, 0xb8, 0x16, 0x11, 0x56, + 0x0c, 0xe0, 0xfb, 0xd2, 0x26, 0x14, 0x33, 0x5d, 0x13, 0xfd, 0x35, 0x29, 0xaa, + 0x39, 0xed, 0x14, 0x27, 0xd3, 0xf1, 0x17, 0x11, 0x39, 0xeb, 0x1d, 0xdc, 0x37, + 0x0c, 0xe0, 0xeb, 0x04, 0x0a, 0xb2, 0x06, 0x25, 0x32, 0xfe, 0x24, 0xe2, 0xf3, + 0xd2, 0xeb, 0xf6, 0x01, 0x3a, 0xe2, 0xed, 0x5b, 0xbf, 0x0f, 0x2b, 0xde, 0x00, + 0x7f, 0x56, 0x0b, 0xc4, 0xcb, 0x1a, 0x21, 0x1f, 0xd8, 0xc0, 0x25, 0xde, 0xce, + 0x1e, 0xe0, 0xd0, 0x45, 0xf6, 0x1c, 0x14, 0x32, 0x1e, 0x3a, 0x2d, 0xcf, 0xdc, + 0xa6, 0xab, 0xb4, 0x3b, 0xe0, 0xef, 0xaf, 0x0e, 0xce, 0x0b, 0xc9, 0x28, 0x2b, + 0xc7, 0x0a, 0x2a, 0xde, 0xc4, 0xc7, 0xba, 0x81, 0x29, 0xf2, 0x19, 0xd9, 0xdf, + 0x36, 0xee, 0xb1, 0xf7, 0xbf, 0xc7, 0x01, 0xe8, 0x2a, 0x92, 0xf3, 0x10, 0xe8, + 0x0a, 0x0a, 0xea, 0xb5, 0xe5, 0xc9, 0x38, 0x34, 0xde, 0xe6, 0x12, 0xcb, 0xeb, + 0x14, 0xc9, 0x3d, 0xc6, 0xb6, 0xc0, 0xca, 0xd9, 0x4e, 0xc3, 0xb0, 0x41, 0xca, + 0x0c, 0xaa, 0xd2, 0xc8, 0xec, 0xe0, 0xea, 0xd4, 0x1c, 0xf4, 0x3c, 0xff, 0x0a, + 0xe5, 0x2f, 0x3e, 0xce, 0xdd, 0x1a, 0x08, 0x24, 0xfc, 0x1b, 0x2f, 0xac, 0x00, + 0x10, 0xfe, 0x3b, 0xed, 0xee, 0xe4, 0x18, 0xde, 0xde, 0x25, 0x33, 0x5d, 0xf8, + 0x3f, 0xec, 0xfd, 0xdd, 0x0a, 0xeb, 0x07, 0xdd, 0xe9, 0x2a, 0x3a, 0x02, 0xe1, + 0x09, 0x00, 0xbe, 0x1f, 0xdd, 0x0f, 0x33, 0x49, 0x13, 0xf5, 0xec, 0xbd, 0x11, + 0xb5, 0xf0, 0xd5, 0x03, 0xca, 0xde, 0xd6, 0x73, 0xf9, 0x09, 0xdb, 0xf0, 0x28, + 0x4b, 0xfe, 0xf1, 0xf1, 0xfc, 0xa9, 0x07, 0xf3, 0x06, 0x25, 0xc6, 0x60, 0xca, + 0x29, 0xfe, 0x05, 0xf2, 0xd1, 0xe7, 0x00, 0x2c, 0x31, 0xf7, 0x0c, 0x30, 0xe3, + 0x0d, 0xe2, 0x07, 0xdf, 0xae, 0xd9, 0xc1, 0xf3, 0x1a, 0xf2, 0xd4, 0x0e, 0xc3, + 0x16, 0xf2, 0x44, 0x22, 0x00, 0xe5, 0x24, 0xef, 0xa2, 0x62, 0x13, 0x07, 0x44, + 0xdf, 0xb3, 0x03, 0xfa, 0x23, 0xfe, 0xf6, 0xd8, 0xaa, 0xf1, 0x12, 0x18, 0xee, + 0x1f, 0xd8, 0x5a, 0x14, 0x3a, 0x38, 0xe2, 0xf5, 0x22, 0xc9, 0xc5, 0x6c, 0x15, + 0x76, 0xea, 0xf6, 0x52, 0xe6, 0x12, 0x3a, 0x06, 0x27, 0x7b, 0x09, 0xde, 0x68, + 0xf0, 0xef, 0xe4, 0xc7, 0xc3, 0xd1, 0x2e, 0xdb, 0xeb, 0x47, 0xb8, 0xcc, 0xf3, + 0x0a, 0xeb, 0x19, 0x0e, 0x27, 0xed, 0x19, 0xde, 0x21, 0xdc, 0xf3, 0xcd, 0xe2, + 0xf9, 0x02, 0xe8, 0x27, 0xfe, 0x06, 0x03, 0xd2, 0x37, 0xa2, 0xde, 0xdc, 0xda, + 0x5c, 0xc7, 0xbd, 0xf4, 0x06, 0x05, 0xf5, 0xf0, 0x06, 0xab, 0x08, 0xda, 0x3f, + 0xf8, 0x17, 0x37, 0xfd, 0x25, 0xe2, 0x3c, 0xf6, 0x22, 0x16, 0x11, 0xce, 0xf8, + 0xdb, 0xc2, 0x1d, 0x16, 0x0e, 0xe5, 0xd9, 0x00, 0x32, 0xca, 0x3a, 0xa5, 0x0c, + 0x06, 0x02, 0xb2, 0x2d, 0xdb, 0x0d, 0xde, 0x24, 0xf5, 0x59, 0x0e, 0xaf, 0xe2, + 0xf3, 0xfa, 0xb3, 0xd8, 0x03, 0x3d, 0x1a, 0x1a, 0x16, 0xea, 0xf5, 0xe5, 0xfe, + 0xda, 0x3a, 0xf7, 0x15, 0xe1, 0xfe, 0xf4, 0x0f, 0xde, 0xbb, 0xf5, 0xef, 0xfe, + 0xdb, 0x32, 0xe0, 0xd7, 0xfa, 0x3f, 0xf9, 0xf9, 0xf7, 0xf5, 0xe0, 0x14, 0x35, + 0xc8, 0xe1, 0xcf, 0x15, 0x0e, 0x3a, 0xed, 0x13, 0x3b, 0xeb, 0xc2, 0x34, 0xec, + 0xa9, 0x9d, 0x01, 0x9f, 0x0b, 0xaa, 0x3d, 0x1a, 0x13, 0x0f, 0xea, 0x31, 0x02, + 0xde, 0x0b, 0x1c, 0x37, 0xf9, 0xf5, 0xbd, 0xf4, 0x04, 0xe5, 0x08, 0xf5, 0xcd, + 0xe7, 0xe3, 0x10, 0x0e, 0x13, 0x27, 0x07, 0x14, 0xd9, 0xad, 0xd5, 0xbf, 0xc5, + 0x2b, 0x1f, 0xf9, 0x24, 0x08, 0x34, 0x03, 0x14, 0x02, 0x91, 0x13, 0x0c, 0x55, + 0x1d, 0xeb, 0x09, 0x16, 0xe6, 0xf2, 0x23, 0xd3, 0x3b, 0xcd, 0xeb, 0xeb, 0xc8, + 0xf2, 0xc0, 0xf9, 0xb6, 0xe9, 0xfd, 0xe3, 0x1e, 0x18, 0x33, 0x1f, 0xf6, 0xe9, + 0xc0, 0xf3, 0xf7, 0xee, 0x29, 0xdc, 0x94, 0x5e, 0xf4, 0xeb, 0xf6, 0xf8, 0xd0, + 0xde, 0x00, 0x17, 0xfd, 0x0b, 0x56, 0xfe, 0x01, 0xae, 0x2c, 0xf9, 0x0d, 0xa4, + 0xcf, 0x07, 0x2a, 0x0e, 0x19, 0x20, 0x81, 0x08, 0xc5, 0xdf, 0x21, 0xde, 0xe6, + 0xe0, 0x24, 0xd9, 0x21, 0x1b, 0xc6, 0x28, 0x0e, 0x00, 0x13, 0x0b, 0xf6, 0x2b, + 0x13, 0x13, 0xad, 0x2e, 0x63, 0xfc, 0xfe, 0x09, 0x18, 0xaf, 0x3b, 0xdb, 0x0a, + 0xd9, 0xdc, 0x0f, 0x19, 0xc1, 0xe4, 0x02, 0x23, 0x74, 0x05, 0xdd, 0xf5, 0x43, + 0x08, 0xdd, 0xf4, 0xeb, 0x01, 0x09, 0xfb, 0xc3, 0x2f, 0xc1, 0xc9, 0x35, 0x18, + 0x28, 0xf3, 0xe4, 0xd1, 0x1c, 0xfe, 0xed, 0xae, 0xbf, 0xd5, 0xf5, 0x34, 0x23, + 0xcf, 0x08, 0x14, 0x3b, 0xd5, 0xa0, 0x3c, 0xec, 0xc8, 0xf1, 0x3a, 0xbd, 0xe4, + 0xfd, 0x1d, 0xed, 0x27, 0x13, 0xb1, 0x0c, 0xdd, 0xd5, 0xdf, 0x00, 0xe9, 0xec, + 0xcb, 0xf7, 0x3c, 0x44, 0x06, 0xea, 0xa6, 0xe2, 0x0a, 0x08, 0xd2, 0x01, 0xe1, + 0xf6, 0xc9, 0x1a, 0x43, 0xdb, 0x45, 0xb9, 0x2c, 0x1a, 0xe4, 0x1c, 0xe1, 0xfe, + 0xe8, 0xd2, 0x03, 0xb6, 0xbc, 0x43, 0x16, 0xfe, 0xad, 0xf0, 0xdc, 0xf7, 0xfe, + 0x0b, 0x33, 0xc9, 0xaa, 0xb9, 0x15, 0xfb, 0xda, 0x99, 0x2a, 0xea, 0x02, 0x3c, + 0x2a, 0x62, 0x03, 0x08, 0x1a, 0x20, 0xdd, 0x2c, 0xde, 0x05, 0x39, 0xb3, 0xc8, + 0xba, 0xc9, 0x03, 0x07, 0xd8, 0x00, 0x06, 0xc5, 0x3c, 0x16, 0xf4, 0xb5, 0xf0, + 0xc5, 0xe2, 0xe7, 0xfe, 0x05, 0x0c, 0x0b, 0x1f, 0xd6, 0xdb, 0xd1, 0xf7, 0xe5, + 0xfb, 0xb1, 0xcc, 0x1a, 0xcf, 0xa7, 0x34, 0xfa, 0xc1, 0x30, 0xa1, 0xe2, 0x16, + 0xdf, 0xed, 0x2a, 0x1a, 0x9f, 0x0e, 0xf7, 0x0d, 0xd9, 0xf6, 0x02, 0x0f, 0xb1, + 0xe8, 0xb1, 0x10, 0x14, 0xee, 0x04, 0xec, 0x9c, 0xb2, 0xa5, 0xd1, 0xde, 0x11, + 0x1a, 0x46, 0xfb, 0xa3, 0x4c, 0x10, 0xef, 0x16, 0xeb, 0x06, 0x14, 0x19, 0x48, + 0x1c, 0xe5, 0xf9, 0xe1, 0x14, 0x04, 0x20, 0xbf, 0xc0, 0xa2, 0x07, 0xd0, 0x01, + 0xd9, 0xf8, 0x93, 0xe3, 0xe7, 0xd9, 0x1b, 0xa3, 0xf9, 0xc0, 0xc0, 0xc7, 0xe2, + 0xd1, 0xff, 0x4c, 0xee, 0xfc, 0x31, 0xef, 0x3a, 0xef, 0xd5, 0xd7, 0xce, 0xf3, + 0xe5, 0xba, 0xe8, 0x15, 0x15, 0x7f, 0xf8, 0x07, 0x38, 0x17, 0x10, 0x3d, 0x0f, + 0x1b, 0xe3, 0xd3, 0xcc, 0xc5, 0x41, 0x3f, 0x35, 0xed, 0xd1, 0xe2, 0xc6, 0x1d, + 0xcf, 0xdf, 0xd4, 0xbf, 0xf9, 0xe7, 0x10, 0x0b, 0x07, 0xce, 0x19, 0xca, 0xfb, + 0xee, 0xfb, 0xf8, 0xc8, 0x10, 0xcf, 0xfa, 0xba, 0xd1, 0xe7, 0xd7, 0xdb, 0xce, + 0xcd, 0x03, 0xff, 0xd2, 0x33, 0xed, 0x25, 0x06, 0x30, 0xf0, 0x01, 0xe8, 0x25, + 0x10, 0x00, 0x15, 0x2c, 0xe8, 0x0e, 0xdd, 0x03, 0x0e, 0xd6, 0xc7, 0xd7, 0x16, + 0xf5, 0x34, 0x54, 0x12, 0xc1, 0xfe, 0x4c, 0xe8, 0x08, 0x19, 0x01, 0xf9, 0x9e, + 0x0a, 0xb7, 0xbc, 0x02, 0xcc, 0xed, 0x15, 0xea, 0xc7, 0x32, 0x33, 0x1c, 0xf9, + 0xbf, 0xbb, 0x20, 0x1e, 0x08, 0xe7, 0xea, 0x22, 0x02, 0xfc, 0x0a, 0xc1, 0xd0, + 0xec, 0x07, 0x0c, 0x38, 0xed, 0xfe, 0xd3, 0xe5, 0x13, 0xb9, 0xd5, 0xeb, 0xd2, + 0xf8, 0xdc, 0x1f, 0xbf, 0xf3, 0xf9, 0x18, 0x13, 0x09, 0xe6, 0xea, 0x14, 0x81, + 0xfc, 0xea, 0xcf, 0xfc, 0xdd, 0x08, 0xcd, 0x1f, 0x05, 0xb6, 0xce, 0x23, 0x23, + 0xce, 0xc6, 0x0e, 0xb6, 0xf3, 0xdf, 0xe9, 0x16, 0x18, 0xcc, 0x13, 0x19, 0x19, + 0xef, 0x19, 0x2a, 0xfb, 0xcc, 0x18, 0xb9, 0xca, 0xd9, 0xe2, 0x56, 0xc9, 0xc5, + 0x0b, 0x12, 0xcf, 0x12, 0xfc, 0x21, 0x5b, 0xb9, 0x0e, 0x13, 0x19, 0xeb, 0x01, + 0x0f, 0x47, 0x25, 0xed, 0xe1, 0x12, 0xf9, 0xfe, 0xf6, 0x27, 0xe9, 0x05, 0xb8, + 0xae, 0xec, 0x2d, 0x00, 0xf7, 0xde, 0xf2, 0xe7, 0xfe, 0x04, 0xc7, 0xda, 0x1e, + 0xef, 0x32, 0x9c, 0xe2, 0x15, 0xbe, 0xcc, 0x26, 0xe0, 0x02, 0xfd, 0x0c, 0xe9, + 0xf5, 0xf9, 0xfe, 0xf8, 0xe4, 0xf1, 0xd7, 0x02, 0xcf, 0x28, 0x20, 0x12, 0xde, + 0x39, 0xfa, 0xda, 0x06, 0xed, 0xc8, 0xeb, 0x03, 0x27, 0x1a, 0x1b, 0xf8, 0xf6, + 0xd6, 0xb2, 0xfc, 0xd8, 0xb5, 0xf3, 0xeb, 0xf6, 0x00, 0x18, 0x45, 0x13, 0xfd, + 0x62, 0xfb, 0xd0, 0xf0, 0xa6, 0x35, 0xdc, 0x75, 0xac, 0x9c, 0xe9, 0xd5, 0xea, + 0xbe, 0xbe, 0xf8, 0x1a, 0x05, 0x85, 0x0a, 0x1e, 0x01, 0xda, 0xd3, 0x81, 0xe1, + 0xcc, 0xd4, 0xdf, 0xd1, 0xfb, 0x13, 0xd6, 0xde, 0x1f, 0xa0, 0xd6, 0x1e, 0xe9, + 0x3d, 0xd4, 0x13, 0xce, 0x41, 0x2f, 0x40, 0xdd, 0x03, 0x61, 0xa5, 0x34, 0xc8, + 0x16, 0xdb, 0xc6, 0xbe, 0xaf, 0xe3, 0x52, 0x6e, 0xdb, 0xec, 0x49, 0xe0, 0xfb, + 0x24, 0xf9, 0x24, 0xe8, 0x29, 0xc6, 0xb9, 0x03, 0x26, 0x2c, 0xda, 0x01, 0xe9, + 0xa7, 0xde, 0x05, 0xbf, 0xa8, 0x1f, 0xbd, 0xb3, 0x84, 0xe2, 0x1f, 0x29, 0x12, + 0xcd, 0xe7, 0x1f, 0x05, 0x4f, 0x1a, 0x2a, 0xe2, 0x92, 0xc0, 0xfc, 0x1e, 0xf7, + 0xbd, 0xa7, 0xe0, 0xc1, 0xe2, 0xc9, 0x88, 0x19, 0xcf, 0xc5, 0xfa, 0x12, 0xad, + 0xd8, 0x0e, 0x20, 0x98, 0x9e, 0x04, 0x17, 0xc1, 0xf6, 0x02, 0x60, 0xf2, 0xdc, + 0x09, 0x42, 0x29, 0x26, 0x0a, 0x8a, 0xec, 0xe9, 0x12, 0x03, 0xb2, 0xb4, 0xf6, + 0x10, 0xf3, 0x87, 0x12, 0xfd, 0xda, 0xde, 0xf2, 0xdd, 0xa8, 0x44, 0x5d, 0xff, + 0x69, 0x40, 0xc0, 0x86, 0x0b, 0x4a, 0x5d, 0xef, 0x04, 0x14, 0xf9, 0x9b, 0x11, + 0xa1, 0xde, 0x3d, 0xe7, 0x5a, 0xf9, 0xbb, 0xce, 0xf9, 0xa2, 0xf8, 0x2c, 0x05, + 0xd4, 0xf7, 0x1d, 0xdf, 0xdf, 0xda, 0x34, 0xd8, 0xf5, 0xcb, 0x0a, 0xe0, 0xe0, + 0xc6, 0xdf, 0xe4, 0xd1, 0xd8, 0xf8, 0x28, 0xea, 0x01, 0xfc, 0x4b, 0xcb, 0x46, + 0xc1, 0xf7, 0x1f, 0xe7, 0xe9, 0x21, 0x09, 0xd5, 0x18, 0xdf, 0xe1, 0xfc, 0xdb, + 0xfd, 0x3e, 0xa1, 0xa8, 0xed, 0x2f, 0x4e, 0x4a, 0xba, 0xe1, 0x50, 0xff, 0x56, + 0xcb, 0xcd, 0x10, 0xe4, 0xe5, 0x77, 0x68, 0xfa, 0xd6, 0xb3, 0xd2, 0xba, 0xcb, + 0x55, 0x15, 0xf4, 0x26, 0x0c, 0x28, 0x3b, 0xdc, 0xe7, 0x2b, 0xe1, 0x06, 0xe9, + 0x83, 0x24, 0xf6, 0x0f, 0x11, 0x18, 0xf0, 0x04, 0xf7, 0x15, 0xd7, 0xe4, 0xdf, + 0x15, 0xf5, 0x81, 0xcd, 0x02, 0x45, 0x0a, 0xfc, 0xb1, 0xf3, 0xd4, 0x0b, 0xc4, + 0xdf, 0x09, 0xca, 0x05, 0xc7, 0xe9, 0x0f, 0xf7, 0xeb, 0xda, 0x7c, 0x12, 0xf6, + 0xc8, 0x04, 0xdf, 0xd3, 0x8d, 0x23, 0x64, 0x22, 0xff, 0x45, 0x23, 0xf1, 0xfa, + 0xf0, 0x15, 0xa7, 0xf2, 0xba, 0xe4, 0xbb, 0x2f, 0x85, 0x96, 0xef, 0x07, 0xa8, + 0x9c, 0xf2, 0x4a, 0xe0, 0xd3, 0xdb, 0xe6, 0x8d, 0xc0, 0xb8, 0xd2, 0xf0, 0x09, + 0xbf, 0x3b, 0xeb, 0x12, 0x56, 0xa5, 0x9f, 0x46, 0xef, 0xd6, 0x26, 0x1f, 0xf4, + 0xd8, 0xb5, 0x24, 0xdf, 0xa7, 0x02, 0xc6, 0x01, 0x4c, 0x3b, 0xef, 0xdf, 0x07, + 0xad, 0x19, 0x42, 0x0a, 0x02, 0xb1, 0xce, 0x56, 0xec, 0x0b, 0xd7, 0x4f, 0xb6, + 0xbd, 0x06, 0xf9, 0xb4, 0x21, 0x4e, 0xfd, 0x04, 0xd5, 0x46, 0x38, 0x91, 0x11, + 0xbe, 0x3d, 0x08, 0xc8, 0xee, 0x2f, 0xfd, 0x1a, 0xac, 0xcd, 0xfe, 0x29, 0x0f, + 0xda, 0xf8, 0x96, 0x21, 0xfd, 0xd9, 0x33, 0x19, 0xc1, 0x57, 0xf8, 0x10, 0xd3, + 0xe9, 0xdc, 0xfc, 0x0c, 0xf0, 0xcd, 0x19, 0xc6, 0xd7, 0x1c, 0x01, 0xe9, 0x4b, + 0xba, 0xf6, 0xb2, 0xe7, 0xf4, 0xbc, 0xfc, 0x14, 0xf3, 0xc9, 0x06, 0xf8, 0x26, + 0x26, 0x04, 0xe9, 0x52, 0xdc, 0x18, 0x11, 0xd4, 0x52, 0xf6, 0xf6, 0xf0, 0x51, + 0xde, 0xde, 0x1e, 0xdd, 0xf5, 0x40, 0xb0, 0x00, 0x03, 0xea, 0x17, 0xe3, 0x09, + 0xfd, 0x0b, 0xf0, 0x3e, 0xa3, 0xba, 0x12, 0x3f, 0x15, 0xf0, 0xef, 0x17, 0xb0, + 0x1f, 0xf3, 0xa9, 0x5f, 0xe0, 0x57, 0x06, 0x03, 0x12, 0xa0, 0x15, 0x1b, 0xe3, + 0xf0, 0xdb, 0x57, 0x0b, 0x44, 0x48, 0xd8, 0x05, 0xd6, 0xfb, 0x4e, 0xdf, 0x09, + 0xbf, 0xde, 0x27, 0x05, 0x21, 0xe0, 0xd5, 0xcf, 0x24, 0x08, 0xe4, 0xc1, 0xfc, + 0xf2, 0x33, 0xe1, 0xec, 0x15, 0x09, 0x03, 0xf4, 0x05, 0xf0, 0x11, 0xf8, 0x9b, + 0xea, 0xcc, 0xfb, 0xa7, 0xf9, 0x07, 0xdf, 0xe3, 0xa2, 0x00, 0x0c, 0xc1, 0x1e, + 0x18, 0xd4, 0xea, 0x02, 0x3f, 0xef, 0x17, 0x03, 0x24, 0x1d, 0x44, 0x15, 0xc3, + 0xe0, 0x03, 0x08, 0x10, 0xf8, 0x09, 0x16, 0x21, 0x14, 0x29, 0x02, 0xc8, 0x09, + 0x17, 0x33, 0xfe, 0x62, 0x25, 0xfc, 0xfb, 0xc3, 0x48, 0x5d, 0x1d, 0xeb, 0x00, + 0x1c, 0xd0, 0x18, 0xa5, 0x18, 0xd3, 0x2e, 0x1e, 0xc0, 0xee, 0x12, 0xee, 0x57, + 0xf6, 0xf2, 0x0e, 0xe1, 0x07, 0xb0, 0xea, 0xe9, 0x2a, 0x11, 0x3d, 0xf0, 0xf3, + 0xd4, 0xe8, 0x08, 0xd2, 0xf2, 0xe9, 0x00, 0x0b, 0xf4, 0xa2, 0xbe, 0xf9, 0xbf, + 0x5d, 0x3c, 0xb9, 0xe1, 0xc6, 0xf5, 0x00, 0xd5, 0x13, 0x05, 0x05, 0x10, 0xff, + 0xe4, 0x1d, 0xb4, 0xfa, 0xd6, 0xe9, 0xec, 0x0a, 0xf8, 0x01, 0xec, 0xe4, 0xec, + 0x3c, 0xd0, 0xcd, 0xf5, 0xc0, 0xcc, 0xda, 0xcf, 0xf5, 0x3f, 0xe0, 0xe4, 0xc0, + 0x08, 0x27, 0x53, 0xdf, 0x08, 0xa9, 0x24, 0x0c, 0xb7, 0x2c, 0x21, 0x7f, 0xd0, + 0xe2, 0x28, 0xe9, 0xbc, 0x1b, 0xca, 0xec, 0x1f, 0x00, 0x0e, 0x17, 0xfe, 0x1b, + 0x05, 0xf0, 0x5d, 0xf1, 0x0e, 0x24, 0x09, 0xe8, 0xf6, 0x13, 0x05, 0xc3, 0x2a, + 0x09, 0xc5, 0xe5, 0x26, 0xeb, 0xdc, 0xfa, 0x05, 0x09, 0xe8, 0xf3, 0xca, 0xf2, + 0x01, 0xed, 0xdf, 0xb6, 0x04, 0xdd, 0xe3, 0xb2, 0xf2, 0xbf, 0xfa, 0x4a, 0x28, + 0x01, 0x0e, 0xb4, 0x01, 0x13, 0xc6, 0x3a, 0x05, 0xe8, 0xf4, 0x02, 0x0d, 0x16, + 0x08, 0xea, 0xdd, 0xfe, 0x13, 0xe1, 0xfd, 0x38, 0xef, 0x00, 0xdb, 0x1a, 0x1f, + 0xe9, 0xe5, 0xcf, 0xe4, 0xf4, 0xfa, 0x32, 0xc5, 0x04, 0x1c, 0x0b, 0x50, 0xeb, + 0xff, 0x2c, 0xe6, 0xde, 0xf7, 0xfa, 0xa5, 0xb8, 0xc4, 0xc9, 0xe8, 0x06, 0x02, + 0xfb, 0xb5, 0xfb, 0xee, 0x1a, 0x13, 0xf7, 0xd2, 0xea, 0x2c, 0xec, 0xe4, 0x07, + 0xf4, 0x2c, 0xc1, 0x2b, 0x04, 0x13, 0x24, 0x06, 0xdd, 0xfe, 0x8f, 0xe1, 0x43, + 0xb9, 0xdf, 0xbd, 0x47, 0xac, 0x2e, 0xe2, 0x16, 0xe2, 0xfb, 0xc1, 0x48, 0x08, + 0xf2, 0x61, 0xd4, 0xf0, 0xe4, 0x4b, 0x0a, 0xd2, 0xe1, 0x3a, 0x24, 0x2f, 0xa9, + 0xea, 0xfc, 0xcd, 0x32, 0xf7, 0x03, 0x1a, 0x6a, 0xbb, 0x28, 0xea, 0xa3, 0xe4, + 0xb8, 0xbf, 0x1b, 0xce, 0xfe, 0xd1, 0xc3, 0x21, 0x0d, 0x9e, 0xf3, 0xdb, 0xdc, + 0x1b, 0xf6, 0xdf, 0xc2, 0xbf, 0x12, 0x30, 0x63, 0xc4, 0xe6, 0xf8, 0x05, 0xcc, + 0x16, 0xf7, 0x0a, 0xe4, 0xca, 0xea, 0xea, 0x0a, 0xe8, 0x2e, 0x1c, 0xc1, 0xfc, + 0xac, 0x20, 0x02, 0xfb, 0x42, 0x0b, 0xf7, 0xe2, 0xf9, 0xe1, 0xe5, 0xcb, 0xb4, + 0xb3, 0x02, 0x17, 0xd2, 0xd9, 0xca, 0xe9, 0xbe, 0xfa, 0x17, 0xd3, 0xda, 0x48, + 0xfa, 0xd1, 0x07, 0xbd, 0x10, 0x19, 0xa5, 0xe8, 0x0b, 0x3c, 0x3a, 0x0f, 0xf0, + 0xe4, 0xe2, 0x0e, 0x9e, 0xc5, 0xd5, 0xba, 0x77, 0xd6, 0xc4, 0x4d, 0x06, 0xd2, + 0xf1, 0x03, 0x5b, 0xce, 0x00, 0x35, 0x2a, 0x08, 0xf1, 0x87, 0xbb, 0x3a, 0xb3, + 0x08, 0x0c, 0xa5, 0xcf, 0x2a, 0xe4, 0x4c, 0x04, 0x41, 0xd7, 0xd7, 0xd2, 0x13, + 0xee, 0xe6, 0x9d, 0xdc, 0x09, 0xf1, 0xec, 0xd8, 0x34, 0xfe, 0x56, 0x07, 0xaf, + 0xd6, 0x37, 0xd9, 0xdf, 0x4c, 0xb6, 0x16, 0x1a, 0xa6, 0x07, 0xc7, 0x9d, 0xe6, + 0x07, 0xf8, 0x31, 0xee, 0x3a, 0xd1, 0x38, 0xb7, 0xac, 0xc2, 0x19, 0xeb, 0xba, + 0x05, 0x54, 0xe1, 0xbe, 0xf1, 0x3a, 0xc1, 0xfb, 0xe8, 0x5b, 0xd2, 0xa6, 0x30, + 0xd9, 0x81, 0xa0, 0x07, 0x1b, 0x00, 0x01, 0x6e, 0xcc, 0x24, 0x0f, 0xf4, 0x16, + 0x0b, 0xd4, 0xd1, 0x3c, 0xcc, 0xb5, 0xd6, 0xa9, 0x2c, 0xf3, 0xea, 0xe3, 0xfd, + 0xf9, 0x81, 0x21, 0x4d, 0x3e, 0xd5, 0xfe, 0xb7, 0x0f, 0xc1, 0x1c, 0x1d, 0x16, + 0xf7, 0x03, 0xf9, 0xfe, 0xd6, 0xf3, 0x11, 0xab, 0xd3, 0xfb, 0x58, 0xf3, 0xae, + 0xcc, 0xde, 0xfb, 0xc4, 0xb8, 0x0b, 0x05, 0xde, 0x30, 0x1f, 0xc9, 0x83, 0x0d, + 0xd7, 0xec, 0x03, 0x18, 0x15, 0xf6, 0x0e, 0x4a, 0xcc, 0x14, 0x31, 0xac, 0x25, + 0x2a, 0x1e, 0xb5, 0xd8, 0x6d, 0xd2, 0x1c, 0xec, 0xdb, 0xc8, 0xc7, 0xec, 0x1d, + 0xbe, 0xf1, 0x10, 0xeb, 0x0b, 0xc6, 0xca, 0xed, 0xe4, 0xdc, 0xbc, 0x09, 0x58, + 0xe2, 0xed, 0xc8, 0xdb, 0xd2, 0xec, 0xf6, 0x15, 0xeb, 0xda, 0xd4, 0x2e, 0xf0, + 0xc7, 0xdb, 0xff, 0x3b, 0xb3, 0x60, 0x15, 0xdb, 0xff, 0x06, 0x05, 0x1d, 0x00, + 0xae, 0xe6, 0xcb, 0x09, 0x50, 0x1e, 0xec, 0x36, 0x08, 0xcc, 0xa3, 0xf3, 0x54, + 0x06, 0x54, 0xeb, 0xc4, 0xf0, 0x43, 0xc1, 0xfd, 0xe5, 0xf0, 0xd5, 0xdb, 0xe4, + 0xe3, 0xfd, 0x44, 0x1c, 0x0f, 0xf0, 0xe0, 0x03, 0x2a, 0x65, 0xe3, 0xc8, 0xe9, + 0xfd, 0xef, 0xdb, 0x42, 0x05, 0x06, 0xe2, 0xd1, 0xa9, 0xdc, 0x10, 0x9d, 0x38, + 0x0d, 0x1f, 0xc0, 0x0d, 0xf1, 0xd7, 0x31, 0xc9, 0x21, 0x87, 0xf7, 0xed, 0xf7, + 0xa1, 0x08, 0xf3, 0xbf, 0xcf, 0x2a, 0xd6, 0xe9, 0xfd, 0x03, 0xf9, 0xdc, 0x22, + 0x00, 0xff, 0x15, 0xeb, 0x09, 0xfb, 0x2a, 0x29, 0xf7, 0x09, 0xfa, 0xb5, 0xf0, + 0x13, 0xe6, 0xf8, 0x46, 0x07, 0x29, 0x8d, 0xfd, 0xfe, 0x0a, 0x1b, 0x18, 0xf3, + 0xa4, 0xec, 0xc3, 0x26, 0xa0, 0xe4, 0xd8, 0x0a, 0xd8, 0xf0, 0x96, 0x86, 0x2d, + 0xc9, 0x02, 0x21, 0xf4, 0x2e, 0x40, 0x1f, 0x0e, 0x3e, 0xd7, 0x51, 0x3f, 0x0d, + 0xc9, 0x9c, 0xb7, 0x27, 0xd8, 0x23, 0x02, 0xc7, 0x0f, 0xd5, 0x90, 0x38, 0xc9, + 0x1e, 0x02, 0xaa, 0x3c, 0xbe, 0x88, 0x29, 0xdd, 0x39, 0xe7, 0x98, 0x09, 0xd9, + 0x84, 0x38, 0xe9, 0x4b, 0xb3, 0xbb, 0x2e, 0x29, 0xfd, 0x1a, 0x1f, 0x08, 0xe4, + 0x3d, 0x1e, 0xfb, 0xc2, 0x32, 0x13, 0x4b, 0x40, 0xdd, 0xfc, 0xe4, 0xff, 0xf7, + 0x28, 0xde, 0xbb, 0xf3, 0x09, 0xe5, 0x06, 0xc9, 0x34, 0xe5, 0x93, 0xde, 0xd8, + 0x2e, 0xb4, 0xfe, 0xc6, 0x41, 0xa6, 0xdc, 0xfc, 0x0c, 0x2d, 0x33, 0xd4, 0x62, + 0xe7, 0xc8, 0xcc, 0x4a, 0x28, 0xc7, 0x31, 0x93, 0x1b, 0x4c, 0x33, 0x2d, 0x3f, + 0xc1, 0x58, 0xe2, 0xcc, 0xef, 0xf1, 0xf9, 0xce, 0x09, 0x24, 0xb9, 0x09, 0xd9, + 0x23, 0xef, 0xfc, 0xd1, 0x15, 0x41, 0xfd, 0x21, 0xe6, 0x49, 0xbd, 0xd0, 0xd8, + 0xcc, 0x2c, 0xd1, 0xfe, 0xb8, 0xca, 0xd4, 0xec, 0xdb, 0x14, 0xd5, 0x61, 0xfa, + 0xbc, 0x27, 0xf8, 0x91, 0xa3, 0x3f, 0x23, 0x48, 0xcd, 0x1d, 0xf3, 0x2c, 0xfc, + 0xaa, 0xb0, 0xf0, 0x0b, 0xd9, 0xe5, 0x0c, 0xb8, 0x0f, 0xdb, 0x95, 0xf6, 0xef, + 0x1e, 0xda, 0xe5, 0xf4, 0x6f, 0x42, 0xf2, 0x35, 0xba, 0x11, 0xc9, 0x0b, 0xf2, + 0xb7, 0x16, 0xbd, 0xa0, 0x24, 0x36, 0xe5, 0x3d, 0xe7, 0xfb, 0xa0, 0xd6, 0x05, + 0xb7, 0xd8, 0x16, 0xf2, 0x1d, 0xac, 0x81, 0x04, 0xb5, 0xdd, 0xe9, 0x21, 0x99, + 0x3c, 0x16, 0xf6, 0x1a, 0xa6, 0xb8, 0x4c, 0xd1, 0x24, 0xd9, 0xeb, 0xe8, 0x03, + 0xc1, 0xe4, 0xe4, 0xab, 0x92, 0xf5, 0x11, 0xd6, 0x45, 0x35, 0xf4, 0x05, 0xe5, + 0xe5, 0xe2, 0xc4, 0x5a, 0xf9, 0xf3, 0xe7, 0xd6, 0xd0, 0x0a, 0xb0, 0x23, 0xdf, + 0x3d, 0xea, 0x29, 0xde, 0x0d, 0xb3, 0x12, 0x0a, 0xee, 0xb1, 0x36, 0x3a, 0xb6, + 0x07, 0x1b, 0xf4, 0xc1, 0x08, 0x2f, 0xc7, 0x03, 0xf6, 0xf1, 0xf8, 0x16, 0x36, + 0xe1, 0x1a, 0x02, 0x08, 0xfd, 0xe9, 0x9b, 0xd2, 0xb8, 0xfc, 0x32, 0xb2, 0xe2, + 0x37, 0xd9, 0xaf, 0x05, 0xfb, 0x52, 0x1c, 0x09, 0x03, 0xe1, 0x2e, 0xd7, 0x2c, + 0x22, 0xf6, 0x04, 0x03, 0x11, 0x26, 0xd9, 0x1e, 0xb1, 0xe4, 0xa7, 0x33, 0xf2, + 0x1a, 0x10, 0xf8, 0xe1, 0x29, 0x0b, 0xe2, 0x1b, 0xf8, 0x1c, 0xd3, 0xc9, 0x17, + 0xec, 0x00, 0x61, 0xbf, 0x01, 0x3c, 0x9c, 0x06, 0x54, 0x10, 0xd4, 0xe9, 0xa2, + 0x3f, 0xba, 0xd3, 0xe5, 0xaa, 0x05, 0x03, 0x50, 0x07, 0x38, 0x17, 0xf9, 0x44, + 0x03, 0xc5, 0xfd, 0xc3, 0xb4, 0xdc, 0xf5, 0x0c, 0x07, 0xf5, 0xcd, 0x31, 0x44, + 0x62, 0x08, 0xbe, 0xa5, 0x34, 0x2a, 0xe7, 0xfa, 0x07, 0xca, 0xd8, 0xad, 0xce, + 0x00, 0xee, 0xdb, 0x1f, 0xb7, 0x38, 0xde, 0xc2, 0x3c, 0xf3, 0xeb, 0xb7, 0x99, + 0xb2, 0x1b, 0x0f, 0xd8, 0x14, 0x17, 0x15, 0x46, 0x19, 0x29, 0x25, 0xae, 0x3a, + 0xce, 0x41, 0x43, 0xdb, 0xd7, 0x1a, 0x1b, 0x91, 0x17, 0xa4, 0x0b, 0xeb, 0x0d, + 0xde, 0xe8, 0xde, 0x81, 0xfd, 0xf2, 0x14, 0xc3, 0xa7, 0x0b, 0xc9, 0xe9, 0x30, + 0xbb, 0x23, 0xef, 0xf0, 0xe4, 0x12, 0xc9, 0xcf, 0xfb, 0x1b, 0xcb, 0xe9, 0xad, + 0xf5, 0x56, 0x03, 0x4d, 0xdb, 0xe6, 0x15, 0x07, 0x5f, 0x34, 0xfa, 0xcb, 0xf5, + 0x2d, 0xd9, 0xc9, 0x19, 0xfe, 0x23, 0xfa, 0xda, 0xdd, 0xd3, 0xac, 0xca, 0x31, + 0xd6, 0x08, 0x1d, 0xef, 0xfe, 0x18, 0xef, 0xfd, 0xee, 0xe9, 0x32, 0x4f, 0xee, + 0x02, 0xf1, 0xf3, 0xb3, 0x61, 0x0b, 0xe7, 0xbe, 0xe6, 0xa2, 0xc3, 0xdd, 0x09, + 0xe6, 0x01, 0xaf, 0xc0, 0x2b, 0xca, 0xf1, 0x3a, 0x2d, 0x2e, 0x31, 0x0c, 0xd1, + 0x88, 0xdf, 0xb5, 0xf1, 0x17, 0x23, 0xf2, 0x3b, 0x08, 0x60, 0xee, 0xd5, 0xfe, + 0x12, 0x18, 0xdc, 0x02, 0x02, 0xa9, 0xdd, 0xde, 0xca, 0xed, 0xd3, 0x11, 0x14, + 0x0f, 0x46, 0xfe, 0x02, 0xc3, 0x1c, 0x18, 0xcd, 0xdc, 0xdd, 0x58, 0xd7, 0xee, + 0x43, 0x1d, 0xce, 0xd9, 0x09, 0xf5, 0x09, 0xe4, 0x58, 0x13, 0xd2, 0x08, 0xe1, + 0xda, 0xee, 0x36, 0xa1, 0xf3, 0x00, 0x43, 0xa5, 0x06, 0xf9, 0x0b, 0xf3, 0xda, + 0x8e, 0xd5, 0xe8, 0xd7, 0xd2, 0x2b, 0x21, 0x00, 0xc0, 0x17, 0xd1, 0x09, 0xd3, + 0xda, 0xfc, 0xba, 0x15, 0x08, 0xee, 0xd8, 0xd6, 0xc4, 0xab, 0x43, 0x03, 0xfa, + 0x10, 0x22, 0xe4, 0xf5, 0xe6, 0x18, 0x18, 0x3a, 0xd2, 0xf4, 0x08, 0xfa, 0xd4, + 0x0d, 0xdc, 0xd9, 0x23, 0xa7, 0xe9, 0x3c, 0xff, 0x1d, 0xf2, 0xef, 0x39, 0x07, + 0x17, 0xc2, 0x30, 0x2f, 0xf3, 0xca, 0x55, 0x15, 0xff, 0xff, 0x99, 0x2d, 0xe0, + 0x44, 0x0d, 0x6e, 0xc6, 0xf1, 0x20, 0x0f, 0xc1, 0xf1, 0x0a, 0xf5, 0xec, 0x11, + 0x24, 0xf8, 0xe8, 0x02, 0xd2, 0xe6, 0x12, 0x1e, 0xff, 0xc9, 0x17, 0xcf, 0xd7, + 0x07, 0xd8, 0x0d, 0x04, 0x0d, 0x2a, 0xfe, 0x09, 0x3b, 0xcd, 0x56, 0x26, 0xcd, + 0x03, 0x2a, 0x0f, 0xdc, 0x3c, 0x01, 0xaa, 0xd8, 0x3f, 0x37, 0x01, 0xde, 0xf3, + 0xe8, 0xdd, 0xf8, 0xe3, 0x01, 0x39, 0xe9, 0xbc, 0x16, 0xfa, 0xe1, 0xd3, 0xf4, + 0xd1, 0x15, 0x22, 0x17, 0xdd, 0x0f, 0xef, 0xd4, 0xd2, 0x15, 0x81, 0xd2, 0x19, + 0xe6, 0xd6, 0x1d, 0x06, 0x08, 0xb7, 0xe2, 0xde, 0xed, 0xe0, 0x0e, 0xed, 0x09, + 0x38, 0xcb, 0xef, 0xea, 0x2f, 0xd9, 0xdf, 0xfb, 0x05, 0xe3, 0x11, 0xce, 0xe7, + 0xf4, 0x15, 0x45, 0xf5, 0xf4, 0x09, 0x16, 0xcc, 0x44, 0xce, 0x1b, 0xe5, 0x0e, + 0xfa, 0xc1, 0x2d, 0x44, 0xed, 0xe6, 0x27, 0xfe, 0x00, 0x23, 0xdb, 0x1a, 0xc1, + 0x2d, 0xad, 0xbe, 0x2b, 0x22, 0xe7, 0x07, 0xe1, 0xd8, 0xf6, 0xe7, 0x53, 0xbb, + 0xd1, 0x85, 0xe7, 0xdd, 0x32, 0xe2, 0xf3, 0xe0, 0x05, 0x09, 0xfa, 0xd7, 0xf4, + 0x15, 0x3b, 0xea, 0x16, 0x0f, 0xe8, 0xd4, 0x44, 0xf8, 0xb0, 0xe4, 0xe9, 0xe4, + 0xe1, 0xb7, 0x52, 0xb5, 0x65, 0x03, 0x11, 0xab, 0xbe, 0x3f, 0xc8, 0x21, 0xf7, + 0x09, 0x0f, 0x31, 0xf4, 0x47, 0xfc, 0xfb, 0xdb, 0x81, 0x2a, 0x37, 0xd4, 0xc4, + 0x08, 0xb7, 0xff, 0xfc, 0x27, 0x1c, 0xf0, 0x00, 0x07, 0x16, 0x07, 0xaf, 0xe4, + 0xda, 0x26, 0xcc, 0xf1, 0xd8, 0x37, 0x35, 0x18, 0x36, 0x0c, 0x0b, 0x4e, 0xfc, + 0xd7, 0x97, 0x15, 0xed, 0xdf, 0xf1, 0x00, 0xe7, 0x2b, 0xde, 0xf3, 0xb5, 0xc6, + 0x33, 0xd5, 0xf2, 0x0e, 0x1f, 0xf0, 0xcd, 0xbf, 0x40, 0xbe, 0x07, 0xd4, 0x8c, + 0xd4, 0xbe, 0x92, 0xdb, 0x3e, 0x1b, 0xfb, 0xd4, 0x1a, 0xe1, 0x0d, 0x0d, 0x1b, + 0xe6, 0x9f, 0xd9, 0xc0, 0xb9, 0x09, 0xd8, 0xa6, 0xdd, 0xfd, 0xf8, 0x0d, 0x01, + 0x3d, 0xb7, 0xe6, 0xe1, 0xca, 0xe0, 0x01, 0xe4, 0xa9, 0x0f, 0x18, 0x1d, 0xc2, + 0xf0, 0x08, 0x16, 0x11, 0x06, 0x14, 0xb4, 0x9a, 0xb5, 0xc1, 0x90, 0xc7, 0x00, + 0xfc, 0x0b, 0xd5, 0x95, 0xe6, 0x24, 0xf3, 0xfb, 0x01, 0xac, 0xc0, 0x13, 0xe2, + 0xff, 0xd0, 0xd2, 0x1a, 0x1c, 0xb5, 0x4d, 0x3b, 0xeb, 0x1f, 0xf0, 0xf8, 0xb5, + 0xcb, 0xff, 0xd9, 0x19, 0xd4, 0xf6, 0x16, 0x14, 0xdb, 0xfe, 0x26, 0xdb, 0x97, + 0x44, 0x21, 0x3a, 0xec, 0xda, 0xe3, 0x08, 0xa7, 0x4e, 0xd7, 0xf2, 0x34, 0xcb, + 0x40, 0xd0, 0x75, 0x1b, 0xf4, 0x2b, 0x26, 0xf3, 0x2c, 0xc8, 0xe5, 0xd6, 0x71, + 0x1d, 0xf3, 0xb9, 0x64, 0xc1, 0xee, 0x25, 0x27, 0xc0, 0x0c, 0x19, 0xf1, 0x11, + 0x61, 0x01, 0xea, 0x0c, 0xf7, 0xa1, 0x1a, 0x18, 0xe4, 0xc7, 0xf5, 0x23, 0xf5, + 0x3a, 0xfe, 0x87, 0xfb, 0x9f, 0x09, 0xd2, 0x24, 0x24, 0x27, 0xf5, 0xa1, 0x17, + 0x36, 0x0c, 0xe9, 0xf0, 0x28, 0xec, 0xe2, 0xe1, 0xb5, 0xcb, 0x07, 0xf7, 0xe0, + 0x15, 0x1c, 0xea, 0xde, 0x00, 0x0a, 0x20, 0xe8, 0xe8, 0x42, 0xde, 0xea, 0x01, + 0xff, 0xf1, 0x31, 0x2c, 0x2f, 0x11, 0xe7, 0xf1, 0xfd, 0xd4, 0xed, 0x03, 0xf1, + 0xdd, 0xf6, 0xcf, 0xca, 0x01, 0x40, 0xf4, 0xff, 0xe4, 0xe0, 0x0b, 0x3d, 0xe8, + 0x2c, 0xca, 0xf4, 0xe0, 0xf6, 0x55, 0xef, 0x27, 0xff, 0xd2, 0xd6, 0x5f, 0x07, + 0xe4, 0xfa, 0xf1, 0x32, 0xf4, 0x36, 0xca, 0xea, 0x26, 0x1a, 0x13, 0x26, 0x19, + 0xde, 0x10, 0x13, 0xe2, 0xc0, 0x00, 0xc2, 0xd2, 0x03, 0x02, 0x3e, 0xed, 0x02, + 0x54, 0xcd, 0x10, 0x06, 0x18, 0xd4, 0x60, 0x05, 0x2f, 0x07, 0xd7, 0xd7, 0x14, + 0x28, 0xf8, 0xf5, 0xec, 0xd3, 0x03, 0xe5, 0xf9, 0x4f, 0x04, 0x17, 0xec, 0x55, + 0x00, 0x13, 0x04, 0xea, 0x27, 0xf4, 0xb2, 0x07, 0xf2, 0xd7, 0x32, 0xfa, 0x31, + 0x48, 0x09, 0xfa, 0x40, 0xca, 0xff, 0xf9, 0x44, 0xf6, 0x26, 0x11, 0x11, 0xd5, + 0x20, 0xd1, 0xcf, 0x7f, 0x39, 0x25, 0x2c, 0x2c, 0xc4, 0x1c, 0x20, 0xd9, 0xa5, + 0x11, 0x0b, 0xcb, 0xfa, 0xed, 0xd9, 0xe5, 0x13, 0xd0, 0xcf, 0x26, 0xe4, 0xf7, + 0xd7, 0x16, 0x51, 0xc4, 0xea, 0xec, 0x0a, 0xfe, 0x1a, 0x11, 0x15, 0x18, 0x27, + 0x6a, 0xf1, 0x29, 0xed, 0xfd, 0xe2, 0xe3, 0xe6, 0x16, 0x1b, 0x17, 0x2a, 0x13, + 0x16, 0x01, 0xd9, 0xd2, 0x07, 0xe4, 0x04, 0xd6, 0x4a, 0xfd, 0x24, 0x09, 0xde, + 0x33, 0xb7, 0xfe, 0xc1, 0x02, 0xdc, 0x25, 0xf1, 0xe0, 0x5d, 0x19, 0xf6, 0xee, + 0xe6, 0xc8, 0x31, 0xe1, 0xe5, 0xed, 0x00, 0xf9, 0xf2, 0xf8, 0xc7, 0x02, 0x02, + 0xc1, 0xd9, 0xdd, 0x37, 0xc9, 0xbe, 0xe8, 0xf9, 0x2b, 0xe3, 0xdf, 0x14, 0xa8, + 0x31, 0xc8, 0xcf, 0xfd, 0xec, 0x2a, 0xf6, 0xb3, 0x96, 0xdb, 0xc9, 0xd5, 0x01, + 0xee, 0xec, 0x02, 0x3a, 0x03, 0xb3, 0x56, 0x21, 0xcf, 0xd3, 0x28, 0x2d, 0xb4, + 0xd0, 0x0b, 0xd6, 0xf1, 0xac, 0xf8, 0xdb, 0x12, 0x40, 0x19, 0x9e, 0xfa, 0x27, + 0xe5, 0x1d, 0xf5, 0xeb, 0xea, 0xbe, 0xb9, 0xc6, 0xde, 0xd7, 0xf9, 0xd9, 0xe4, + 0x35, 0xca, 0xce, 0x2a, 0x56, 0xbe, 0x0d, 0x06, 0xff, 0xcc, 0xe7, 0xba, 0x17, + 0x22, 0xea, 0xc2, 0x3d, 0x15, 0xe4, 0x2c, 0x0b, 0x0c, 0xf4, 0xf8, 0x56, 0x43, + 0x4c, 0xfd, 0xf4, 0xb6, 0xd5, 0xf9, 0xd5, 0x05, 0x1c, 0xdf, 0xfe, 0x00, 0x35, + 0xec, 0xe6, 0xa9, 0x06, 0x17, 0xdc, 0xcf, 0x06, 0xf1, 0x42, 0x25, 0xd2, 0xc6, + 0x1a, 0xfc, 0xe6, 0xf0, 0xd5, 0xdd, 0xde, 0xf2, 0xd3, 0xfe, 0x06, 0x81, 0x23, + 0x20, 0x3a, 0x1f, 0x24, 0xe7, 0x17, 0x09, 0x21, 0xff, 0xb7, 0xeb, 0xb4, 0xc7, + 0xf0, 0xb0, 0xb3, 0xfa, 0x0c, 0xc3, 0x22, 0xf4, 0x1b, 0xdd, 0xd3, 0x17, 0x3b, + 0x33, 0xa2, 0xd1, 0x18, 0x1f, 0x2a, 0xce, 0x0d, 0xbe, 0xc4, 0x0f, 0x3f, 0xff, + 0xe9, 0xdc, 0xaf, 0x01, 0xec, 0xeb, 0xf1, 0xc8, 0xc1, 0x22, 0xc8, 0x2d, 0xa7, + 0xc6, 0xbe, 0x44, 0xd5, 0xea, 0x1a, 0x1d, 0x0d, 0x1e, 0x0f, 0x21, 0x03, 0x45, + 0xd5, 0x39, 0xfa, 0x0e, 0xf4, 0xdf, 0xf9, 0x0d, 0xdf, 0x17, 0x23, 0x8a, 0x14, + 0x20, 0xcc, 0x08, 0x09, 0xe1, 0x25, 0xe3, 0xb9, 0x1e, 0xf4, 0x1e, 0xcf, 0xe2, + 0xef, 0xca, 0xf0, 0x2d, 0x1c, 0x00, 0xf9, 0xdd, 0x88, 0x1f, 0x0c, 0xdd, 0x2e, + 0x03, 0xd2, 0x05, 0x0a, 0xe4, 0x35, 0x0a, 0x2b, 0xbb, 0xb6, 0x09, 0xbc, 0xe5, + 0xfd, 0xeb, 0xd3, 0xe6, 0xdc, 0x08, 0xd8, 0x39, 0x1d, 0xf0, 0x3b, 0xe1, 0x04, + 0xfa, 0x0a, 0xf5, 0xe4, 0x13, 0xd6, 0x2e, 0x08, 0x05, 0x18, 0xa6, 0xd3, 0xd9, + 0x3f, 0x31, 0xb7, 0x08, 0x8e, 0x10, 0x21, 0xda, 0x1d, 0xe8, 0xe7, 0xf2, 0x1a, + 0x06, 0xba, 0xd7, 0x09, 0x01, 0xcd, 0xf7, 0xb1, 0xe6, 0x01, 0xfe, 0xf6, 0xe8, + 0xe0, 0xc5, 0xd5, 0xdc, 0xbc, 0xff, 0xb1, 0x1e, 0x2c, 0xd5, 0xf6, 0xed, 0x42, + 0xb0, 0x07, 0x08, 0x1c, 0xe9, 0x30, 0xf3, 0xde, 0xcf, 0x16, 0x2d, 0xf1, 0x28, + 0xe1, 0xd2, 0x20, 0x1c, 0xe8, 0xfb, 0x17, 0xe1, 0x23, 0xe5, 0xd1, 0xfc, 0xee, + 0x0e, 0x20, 0x0e, 0x15, 0x11, 0xc7, 0x1a, 0x00, 0x17, 0xc6, 0x24, 0xd6, 0x05, + 0x1f, 0x08, 0xfc, 0x08, 0xef, 0xf7, 0xf4, 0xc6, 0xd1, 0xe1, 0x29, 0xe6, 0xed, + 0x0b, 0xb6, 0x19, 0xf5, 0xea, 0x2a, 0x25, 0xfc, 0xa5, 0xd9, 0x1f, 0x3f, 0x30, + 0x00, 0x01, 0x29, 0xdb, 0x06, 0xf3, 0x24, 0xa9, 0x21, 0x1f, 0x16, 0x13, 0x03, + 0x1d, 0x2c, 0x04, 0xea, 0xf7, 0xe3, 0xee, 0x43, 0x20, 0x40, 0xfc, 0x38, 0xcd, + 0x5c, 0xfb, 0x36, 0xd6, 0xd5, 0x30, 0xbd, 0xeb, 0xe3, 0x0a, 0xd4, 0xec, 0xef, + 0xfb, 0xd2, 0xf5, 0x08, 0xe8, 0x0a, 0xfb, 0xe1, 0x32, 0x81, 0x2f, 0xc8, 0x38, + 0xf4, 0x1a, 0xd2, 0xac, 0xd2, 0x02, 0x1c, 0xd1, 0xef, 0xf9, 0xad, 0xe8, 0xee, + 0xf3, 0x13, 0xff, 0x16, 0xa1, 0xa7, 0xd4, 0xf2, 0xee, 0x21, 0x00, 0x19, 0x30, + 0x40, 0xd8, 0x0f, 0x19, 0x16, 0x4d, 0x3a, 0x1c, 0xb3, 0xea, 0x00, 0xff, 0x88, + 0xfd, 0xfe, 0xc6, 0x38, 0x02, 0xe9, 0x06, 0xfe, 0x2a, 0x3a, 0x11, 0x10, 0xf4, + 0x11, 0xef, 0xf7, 0xea, 0xf9, 0x28, 0xd1, 0x17, 0xdb, 0xbe, 0x07, 0x46, 0xe6, + 0x94, 0x02, 0xe8, 0x12, 0x06, 0x09, 0x06, 0xf5, 0xbd, 0xb4, 0xda, 0xd2, 0x32, + 0xd9, 0x2a, 0xa1, 0x3a, 0x3c, 0xe1, 0xe2, 0x26, 0x2a, 0x12, 0xc2, 0xeb, 0x01, + 0xbe, 0xf6, 0x1f, 0x5d, 0x36, 0xff, 0x04, 0x09, 0xcb, 0x19, 0x23, 0x10, 0xfc, + 0xc8, 0xce, 0x10, 0x18, 0x0c, 0x08, 0xc7, 0xe6, 0x0f, 0xe5, 0xd1, 0xf0, 0xda, + 0xd5, 0xe0, 0xc2, 0x24, 0xda, 0xe2, 0x0a, 0xf9, 0xec, 0x4d, 0x8c, 0xdf, 0xde, + 0xfe, 0x1a, 0xf0, 0xc1, 0xc3, 0xcd, 0x2b, 0xe9, 0x0e, 0xc9, 0xa6, 0x35, 0xee, + 0x2c, 0xe2, 0x4d, 0xfd, 0x1e, 0xfc, 0xf7, 0xc9, 0x4d, 0x27, 0xaf, 0xde, 0xd3, + 0xb2, 0xd9, 0xfb, 0xef, 0x27, 0xfd, 0x0f, 0x1a, 0xef, 0x96, 0xc4, 0x23, 0xf1, + 0xdc, 0x0c, 0x07, 0x0f, 0xeb, 0x34, 0xf7, 0x2a, 0x17, 0xf5, 0xdf, 0x09, 0x9f, + 0xdb, 0xf2, 0xb5, 0xe4, 0xf0, 0x1e, 0x3e, 0xe4, 0x4b, 0x15, 0x0b, 0xb3, 0x11, + 0xdb, 0xf4, 0xef, 0x50, 0x1f, 0x3f, 0x24, 0x46, 0xda, 0xdf, 0x0b, 0x30, 0x82, + 0xf8, 0xbd, 0xff, 0xdb, 0xdd, 0x15, 0xe8, 0x3f, 0xba, 0x3c, 0xc9, 0x3e, 0x19, + 0xb7, 0xcc, 0xee, 0xf3, 0xf2, 0xb9, 0x36, 0x25, 0x1e, 0x2c, 0x0c, 0xbf, 0x07, + 0xf1, 0xc7, 0x12, 0xfb, 0xda, 0x49, 0x2d, 0xb1, 0xbf, 0xe7, 0xce, 0x0e, 0xf9, + 0x2f, 0xe4, 0x09, 0x1c, 0xe3, 0xd2, 0x47, 0xc7, 0xf0, 0xe3, 0x3a, 0xab, 0xd1, + 0xf2, 0xf3, 0xf2, 0xb5, 0x21, 0xe5, 0xe0, 0xde, 0x13, 0xfc, 0xb6, 0x04, 0xf0, + 0xd5, 0x99, 0xe3, 0xfb, 0xbb, 0x04, 0xe3, 0xfa, 0xc8, 0xf2, 0x15, 0xdd, 0xc8, + 0xb1, 0x28, 0x0b, 0xad, 0x1d, 0x21, 0xe9, 0x23, 0xd4, 0xd0, 0xe8, 0xc0, 0xc8, + 0xe5, 0x12, 0x11, 0x14, 0xda, 0x09, 0xf8, 0xcc, 0x0f, 0xe2, 0x22, 0xcc, 0xfd, + 0x03, 0xb1, 0x9e, 0xde, 0xbc, 0x3a, 0x14, 0x2d, 0xe1, 0xe5, 0xc6, 0xd9, 0x9b, + 0xec, 0x05, 0xa3, 0x20, 0x30, 0xc1, 0xfc, 0x26, 0xe3, 0x3f, 0x1e, 0xff, 0xe3, + 0x0d, 0x50, 0x01, 0x9e, 0xd6, 0xff, 0xae, 0x18, 0x01, 0x2b, 0x49, 0x0b, 0x5d, + 0x0b, 0xf0, 0xed, 0x06, 0x2f, 0x4c, 0x3d, 0x0d, 0xd2, 0xd4, 0x7f, 0xfc, 0xf1, + 0x49, 0x10, 0xe1, 0xf6, 0xf4, 0x92, 0x2e, 0xdf, 0xed, 0x1a, 0x01, 0x17, 0x08, + 0xe2, 0xee, 0x49, 0x10, 0x8f, 0x0b, 0xde, 0x2c, 0xe8, 0x1b, 0x07, 0xbf, 0xce, + 0xc3, 0xee, 0xfa, 0x2b, 0xe7, 0xd4, 0x25, 0x05, 0xd0, 0x1d, 0xbd, 0xb1, 0xbd, + 0xfa, 0x0d, 0xd8, 0xff, 0xe2, 0x14, 0xfc, 0xf8, 0x16, 0xca, 0xf9, 0x33, 0xef, + 0x17, 0xd3, 0x2a, 0xed, 0xa4, 0x50, 0xda, 0x3b, 0x51, 0xe0, 0x5f, 0xf8, 0x03, + 0x35, 0xb8, 0xdc, 0xc5, 0xe4, 0x1c, 0x10, 0x9e, 0xe2, 0xe2, 0xba, 0xd7, 0xdb, + 0x42, 0xb5, 0xe3, 0xd4, 0xf1, 0x07, 0xeb, 0xfe, 0xe7, 0xfa, 0xa1, 0xfa, 0x38, + 0x1a, 0xc8, 0xe9, 0x41, 0xed, 0xe6, 0x9a, 0xac, 0xf1, 0x26, 0xff, 0x25, 0xc5, + 0xf4, 0xe8, 0xb6, 0xfe, 0x4e, 0xff, 0x24, 0xda, 0x21, 0xfb, 0xa5, 0x22, 0xf2, + 0xbc, 0xd2, 0xef, 0x02, 0xfd, 0xf1, 0xb2, 0xf0, 0x6a, 0xbd, 0x10, 0xe5, 0x53, + 0xe6, 0x3a, 0x18, 0x8b, 0xfb, 0x0e, 0x32, 0x24, 0xe9, 0x7f, 0x0e, 0xd2, 0x1f, + 0x32, 0xc6, 0xf0, 0xb3, 0xa1, 0xf7, 0x14, 0x3f, 0x13, 0xdf, 0xb5, 0xe9, 0xb8, + 0xc8, 0xe6, 0xe4, 0x09, 0xf6, 0x2d, 0x29, 0xf3, 0x67, 0x10, 0x0e, 0xdd, 0x27, + 0x1e, 0x0d, 0xc3, 0xd7, 0x0b, 0x38, 0x55, 0xc8, 0xee, 0xb1, 0xce, 0xf7, 0xd0, + 0xe2, 0xf4, 0xc2, 0xee, 0xd2, 0xe1, 0xf0, 0x39, 0x91, 0x4a, 0xfa, 0x9c, 0xfe, + 0x33, 0xcc, 0x15, 0xba, 0xe4, 0x9d, 0x00, 0x1e, 0xe6, 0xe8, 0x74, 0x25, 0x50, + 0xdd, 0xd3, 0x58, 0xf8, 0xed, 0xf2, 0xda, 0x67, 0xc5, 0xf9, 0x30, 0x21, 0xf7, + 0xfa, 0xdf, 0x75, 0x1d, 0xf3, 0xf9, 0xb1, 0xb3, 0xc8, 0x52, 0x2c, 0x95, 0xdb, + 0xfd, 0xe0, 0xb7, 0xde, 0x52, 0xf1, 0x50, 0xf3, 0xf9, 0xe1, 0xec, 0x1d, 0x12, + 0xe4, 0xbd, 0x23, 0x0b, 0xf0, 0xbb, 0x49, 0x38, 0xd0, 0xcc, 0x20, 0xff, 0x14, + 0xf9, 0xe3, 0xd8, 0xcb, 0xf8, 0xf7, 0xf9, 0xe9, 0xe4, 0xdb, 0xd0, 0xcc, 0xea, + 0x3c, 0x1c, 0xf2, 0xbc, 0x26, 0xf6, 0x06, 0xe3, 0x00, 0x0c, 0xf4, 0xff, 0xfb, + 0x15, 0xf8, 0x01, 0x2c, 0x05, 0xbb, 0xc6, 0x07, 0xc6, 0xf5, 0x3b, 0x2d, 0x1a, + 0xf2, 0x2f, 0xcd, 0xc9, 0xfa, 0xf3, 0x03, 0x35, 0xe8, 0x19, 0xde, 0xcc, 0xef, + 0x31, 0xf1, 0xee, 0x2e, 0x5e, 0xc9, 0x05, 0x7b, 0x1c, 0xb9, 0xbc, 0x09, 0x4a, + 0x30, 0x08, 0x01, 0xea, 0xd6, 0xe7, 0xb6, 0xcb, 0x0a, 0xd8, 0xe0, 0x0c, 0x11, + 0x09, 0x0c, 0x22, 0xe1, 0xe9, 0x13, 0xc4, 0x01, 0x18, 0xe3, 0xd0, 0xf3, 0x28, + 0x0b, 0xc1, 0xc2, 0xd4, 0xff, 0xf0, 0x16, 0x5f, 0x33, 0x16, 0xcb, 0xd4, 0xb7, + 0xde, 0xd2, 0x16, 0xde, 0xf2, 0xfe, 0xb4, 0xdf, 0xb2, 0x1b, 0xb6, 0x9e, 0xf7, + 0xfe, 0xbf, 0xaf, 0x21, 0xae, 0x2a, 0x23, 0xdb, 0xe7, 0xe9, 0x1b, 0xcd, 0x1d, + 0x17, 0xae, 0xdb, 0x32, 0x42, 0xb9, 0xc8, 0xf2, 0x0a, 0xfc, 0xe1, 0xb2, 0xd7, + 0xd6, 0xe5, 0xeb, 0x4b, 0xd0, 0x45, 0xcb, 0xa7, 0x12, 0xd0, 0x31, 0xe4, 0x8b, + 0x03, 0x38, 0x00, 0xbd, 0x28, 0xea, 0xf4, 0xf3, 0x2c, 0xfa, 0xad, 0x27, 0xf4, + 0xdd, 0x63, 0xdc, 0xf3, 0xd7, 0xd1, 0x7f, 0xfa, 0x34, 0x1b, 0x23, 0xbc, 0xf7, + 0xe0, 0x20, 0x26, 0x24, 0xd2, 0xa3, 0x16, 0xe7, 0xf0, 0xd2, 0xf9, 0xa7, 0xbe, + 0xd7, 0xec, 0x12, 0x07, 0x13, 0x00, 0x0f, 0xdc, 0x50, 0x10, 0xf3, 0xad, 0x38, + 0x93, 0x13, 0xf5, 0x01, 0xb5, 0xbd, 0xe4, 0xd3, 0x0a, 0xe2, 0x28, 0x3e, 0x2d, + 0x20, 0x1c, 0xea, 0xd8, 0xb6, 0x53, 0xe6, 0xca, 0x0b, 0xf1, 0x0e, 0xa9, 0x1e, + 0x07, 0x2f, 0x4f, 0xf1, 0xe0, 0xc3, 0xc6, 0xce, 0x01, 0x09, 0xd0, 0x0d, 0x18, + 0x25, 0x30, 0x17, 0x9d, 0x33, 0x60, 0xfa, 0x07, 0x40, 0xd6, 0x0a, 0x0a, 0x21, + 0xfe, 0xb5, 0x0d, 0x12, 0xe5, 0xe2, 0xce, 0xdf, 0x01, 0xdf, 0xd0, 0x0c, 0x27, + 0x22, 0x28, 0x21, 0x2c, 0xf2, 0x51, 0x2d, 0x1b, 0xc3, 0x2c, 0xb5, 0x07, 0xd1, + 0xd4, 0x30, 0xee, 0xd9, 0x24, 0xf5, 0x13, 0xe2, 0xc9, 0x14, 0x10, 0x19, 0xbc, + 0x00, 0xfd, 0xd1, 0xe4, 0xd8, 0x13, 0xb3, 0xdc, 0xef, 0xcd, 0xe1, 0x40, 0x1c, + 0xd7, 0xdf, 0x17, 0x1c, 0xf5, 0xe4, 0xf0, 0xcc, 0xe8, 0xd4, 0x11, 0xdd, 0xbb, + 0x34, 0xf3, 0x38, 0x09, 0x3f, 0x1a, 0xef, 0xf8, 0xee, 0xd2, 0x35, 0xe9, 0x22, + 0xd1, 0xd0, 0x36, 0x07, 0xfe, 0x1b, 0xfe, 0xd1, 0x06, 0xee, 0xd8, 0x9c, 0xee, + 0xe9, 0x24, 0x27, 0x09, 0xd1, 0x02, 0xcc, 0x34, 0xf7, 0x7f, 0x2f, 0x02, 0x09, + 0xc1, 0xea, 0xd3, 0x1c, 0x3c, 0xe8, 0xe6, 0x09, 0xda, 0xf9, 0xda, 0xe1, 0xf3, + 0x38, 0x20, 0xb9, 0x0d, 0x14, 0xeb, 0xef, 0xfd, 0xb3, 0xe6, 0x07, 0x1a, 0xff, + 0xf0, 0x1a, 0x2f, 0xc3, 0x12, 0x31, 0xf0, 0xed, 0x3c, 0xd1, 0x03, 0x2b, 0xb3, + 0x18, 0xc0, 0x9b, 0xed, 0x23, 0x1d, 0xd9, 0xc2, 0x07, 0xf9, 0x28, 0x15, 0x08, + 0x1a, 0xc5, 0x04, 0xc6, 0x19, 0xe5, 0x0c, 0x4c, 0x05, 0x09, 0xda, 0xff, 0x02, + 0x2f, 0xe9, 0x0a, 0xdf, 0xa0, 0x03, 0x21, 0x31, 0x11, 0xff, 0x07, 0x4d, 0xd7, + 0x07, 0x46, 0xdc, 0xcf, 0x08, 0xe9, 0xf8, 0xef, 0xa3, 0x38, 0x02, 0x28, 0x1b, + 0x27, 0x95, 0xe5, 0x1d, 0x99, 0x94, 0xc4, 0x23, 0xeb, 0x0e, 0xb9, 0xaf, 0xcd, + 0x39, 0xfe, 0xfb, 0xeb, 0x01, 0x2e, 0xea, 0xd9, 0xf6, 0xf3, 0x0a, 0x19, 0xc4, + 0x21, 0x2e, 0xe4, 0x03, 0xdf, 0xfc, 0xec, 0xe9, 0xc3, 0x02, 0x2b, 0x4b, 0x0b, + 0xca, 0x0a, 0x4a, 0xbe, 0x14, 0x0a, 0xe9, 0x37, 0xa3, 0xbb, 0xb6, 0x3a, 0xd7, + 0x27, 0xb0, 0x05, 0xfe, 0xff, 0xe4, 0x0f, 0x8f, 0xf8, 0x19, 0x9e, 0xcc, 0xe9, + 0x46, 0xf8, 0xb9, 0xf7, 0xc5, 0xab, 0xfa, 0x09, 0x60, 0x24, 0xc8, 0x15, 0xa0, + 0x25, 0x07, 0xc6, 0xd3, 0xda, 0xf1, 0x3a, 0x2b, 0xd7, 0xe4, 0x18, 0xee, 0x54, + 0x1a, 0x03, 0x16, 0x18, 0xb6, 0xfb, 0xd9, 0x3f, 0x00, 0x09, 0x28, 0xe3, 0xdf, + 0xc9, 0x2c, 0x85, 0xf3, 0xf6, 0x16, 0xdc, 0xee, 0x0d, 0xfa, 0x2f, 0xf4, 0xde, + 0x1d, 0xd9, 0xd9, 0x36, 0x23, 0xd5, 0xec, 0x0f, 0x05, 0x00, 0x30, 0x3a, 0xdc, + 0x20, 0xcd, 0xb6, 0x45, 0x99, 0xca, 0x0c, 0x4a, 0x31, 0x12, 0xd8, 0xfa, 0xfd, + 0x17, 0x82, 0xbd, 0x06, 0xe3, 0x25, 0xbc, 0x37, 0xdc, 0xdf, 0xc2, 0xcb, 0x34, + 0xe4, 0xf9, 0xb7, 0xf4, 0x0d, 0x9b, 0xe3, 0xd2, 0x81, 0xd9, 0x46, 0xce, 0xae, + 0xb0, 0x68, 0xe0, 0x06, 0xec, 0xfd, 0x0e, 0x37, 0x0a, 0x24, 0x18, 0x0d, 0x13, + 0xa7, 0xdb, 0x02, 0x86, 0xb0, 0x25, 0xed, 0xcf, 0x01, 0xf5, 0xd2, 0xd5, 0xf1, + 0xf1, 0xf6, 0xc6, 0xd9, 0xda, 0xc8, 0x11, 0x28, 0x22, 0xae, 0xf9, 0x07, 0xe1, + 0xdb, 0xfc, 0x0b, 0x88, 0xd0, 0x02, 0xca, 0xe7, 0xfc, 0xd1, 0xb1, 0x10, 0x03, + 0x48, 0x08, 0xfd, 0x44, 0x35, 0x0b, 0xd7, 0x23, 0xf6, 0x19, 0xfe, 0x01, 0xf3, + 0x2e, 0xd5, 0x30, 0x45, 0x3e, 0x48, 0xb6, 0x19, 0x09, 0xf7, 0x07, 0x14, 0x20, + 0xfd, 0xd6, 0xd9, 0x23, 0x0f, 0x11, 0x02, 0x3f, 0xc6, 0xec, 0x24, 0x07, 0xe2, + 0xd9, 0xeb, 0xfd, 0xf9, 0xd4, 0x12, 0x14, 0x1d, 0x29, 0x1e, 0x29, 0x0b, 0xad, + 0x1e, 0x2d, 0x0a, 0xd6, 0xd7, 0xfb, 0x33, 0x30, 0xd0, 0xc7, 0xf3, 0x3f, 0xf4, + 0xf0, 0xe1, 0x46, 0x16, 0x55, 0xf9, 0x3e, 0xc9, 0x19, 0x1c, 0xec, 0xf2, 0xeb, + 0x9a, 0xc4, 0xf1, 0x05, 0xce, 0xe6, 0xea, 0xf5, 0xd0, 0x08, 0x25, 0x22, 0xdf, + 0xf7, 0xcd, 0xb2, 0x02, 0xfc, 0xce, 0xc8, 0xd1, 0xa6, 0x33, 0x02, 0x07, 0x21, + 0xf2, 0xb1, 0xd8, 0xef, 0xe0, 0xc2, 0xd6, 0xf7, 0xfd, 0xce, 0xc4, 0x08, 0xce, + 0x2d, 0x0e, 0x98, 0xff, 0xcb, 0xf3, 0xda, 0x40, 0x15, 0xf3, 0x10, 0xf7, 0xe1, + 0xc4, 0xe0, 0xc8, 0x10, 0xf3, 0xfc, 0x27, 0xc2, 0x1a, 0xc3, 0x18, 0xdf, 0xce, + 0xa5, 0xd0, 0x42, 0x24, 0xd5, 0x0f, 0xe6, 0xf8, 0xf8, 0xf1, 0x15, 0xf1, 0xbb, + 0x1b, 0xc1, 0x05, 0xfb, 0x41, 0xba, 0xf0, 0xce, 0x01, 0x43, 0xe6, 0xf2, 0x2d, + 0xea, 0xba, 0xde, 0xd4, 0x09, 0x04, 0xfc, 0xff, 0xdd, 0xcd, 0x21, 0x09, 0xfd, + 0x2b, 0xfa, 0xf5, 0xf7, 0x2b, 0xfe, 0x13, 0xd6, 0x07, 0x86, 0x33, 0xe8, 0x13, + 0x0f, 0x03, 0xcf, 0xa3, 0xc1, 0x0d, 0x08, 0x2b, 0xd6, 0xe0, 0xce, 0x0a, 0xf5, + 0xf3, 0x04, 0xdf, 0xb0, 0xe9, 0xf4, 0x13, 0xfb, 0xa8, 0xd9, 0xd9, 0xfe, 0x0f, + 0xbe, 0xc9, 0x25, 0x35, 0x03, 0xcf, 0xe3, 0xe0, 0xf0, 0x56, 0x0e, 0xf1, 0x2b, + 0x1e, 0xf0, 0x07, 0xf0, 0x15, 0x9e, 0xc6, 0xf2, 0xfc, 0x1e, 0xa6, 0xb1, 0xed, + 0x2a, 0x25, 0x22, 0x32, 0x13, 0xbf, 0xc3, 0x0d, 0x18, 0xd3, 0xf6, 0x02, 0x02, + 0xe3, 0x22, 0x76, 0xfd, 0xdd, 0xdd, 0xed, 0xde, 0xe4, 0xd9, 0xa0, 0x26, 0xdb, + 0xbd, 0xf1, 0x1a, 0xae, 0xf7, 0xd3, 0xc0, 0xf1, 0xc7, 0xf3, 0xc9, 0xfe, 0x31, + 0x84, 0xb1, 0xc5, 0x46, 0xf4, 0xfc, 0x49, 0xf5, 0xcf, 0x16, 0xe8, 0xef, 0xe1, + 0x0a, 0xfd, 0xcd, 0xd1, 0xff, 0xf3, 0xf1, 0xf7, 0xf5, 0xec, 0xc5, 0x11, 0xd7, + 0xd4, 0x15, 0x13, 0xae, 0xe5, 0xe7, 0x34, 0xdb, 0x0f, 0x1b, 0x23, 0x9b, 0xc9, + 0xbf, 0xdd, 0x7f, 0xfa, 0x00, 0x04, 0xbc, 0xa6, 0xcb, 0xf2, 0x0e, 0xbc, 0xec, + 0x96, 0xeb, 0xf9, 0xe8, 0xe0, 0x1d, 0x97, 0xfa, 0xf0, 0xfc, 0xf3, 0x19, 0xd1, + 0x1c, 0x1b, 0xd9, 0xf0, 0xb2, 0x1f, 0xd0, 0x1e, 0x2b, 0xfc, 0x00, 0xe1, 0x0d, + 0x19, 0xf1, 0xf9, 0x08, 0xeb, 0xcd, 0xca, 0xed, 0xbf, 0xdb, 0x08, 0x2f, 0x0e, + 0xeb, 0x9f, 0xc9, 0xc4, 0x1c, 0x0b, 0xce, 0xbf, 0x28, 0x09, 0x0d, 0x3e, 0x29, + 0xc5, 0x18, 0x30, 0xf1, 0x4b, 0xed, 0xff, 0xe2, 0xec, 0xf0, 0x09, 0xd4, 0x6c, + 0x39, 0xcd, 0x21, 0xd3, 0x5b, 0x0f, 0x0c, 0xd1, 0xf2, 0x2d, 0xe3, 0x0d, 0xdd, + 0x07, 0xb1, 0x33, 0xe5, 0xb9, 0x1b, 0xc7, 0x04, 0x10, 0xf4, 0xc2, 0x4d, 0x16, + 0x98, 0xe1, 0x1c, 0xe4, 0x31, 0xfb, 0xe0, 0x00, 0x07, 0x43, 0x0e, 0xe2, 0xde, + 0xd4, 0xb1, 0x14, 0xec, 0x7f, 0xdc, 0xf2, 0xee, 0xc4, 0xd4, 0x53, 0x19, 0xe3, + 0xfb, 0xf1, 0xdb, 0xb4, 0x06, 0xb9, 0xc3, 0x16, 0x06, 0xfb, 0x00, 0xd0, 0xc9, + 0xee, 0x04, 0x50, 0x42, 0xaa, 0xbd, 0xbb, 0xe1, 0xde, 0x1c, 0xfc, 0xe2, 0xcf, + 0xb4, 0x0f, 0xeb, 0xff, 0x88, 0x4f, 0x0f, 0x9c, 0xd3, 0xe2, 0xd7, 0xdb, 0x18, + 0x1d, 0xfc, 0xef, 0xca, 0x31, 0xfc, 0x1b, 0x1b, 0xa6, 0xdd, 0xfd, 0xfc, 0x0b, + 0x4a, 0x0f, 0x1c, 0xda, 0x8d, 0x3b, 0x1b, 0xe7, 0x0d, 0xde, 0xd1, 0x15, 0x11, + 0xcf, 0x0b, 0x29, 0x19, 0x03, 0x31, 0xf0, 0x5a, 0xf0, 0xc4, 0xdd, 0x3e, 0x25, + 0xfd, 0xd3, 0xdc, 0xe8, 0xda, 0xb8, 0xc7, 0xff, 0xe6, 0xf2, 0xc7, 0x07, 0xd5, + 0x1f, 0xfa, 0xc4, 0x36, 0xb4, 0x2f, 0xe1, 0xd5, 0xfb, 0x15, 0x1b, 0x08, 0xee, + 0xda, 0xd2, 0xec, 0xbc, 0x0f, 0x1a, 0xc3, 0xeb, 0xec, 0xfa, 0x0f, 0xc9, 0x3c, + 0x5b, 0x00, 0x33, 0xfd, 0x01, 0x1d, 0xcc, 0xe2, 0x3b, 0x43, 0xcd, 0x56, 0x39, + 0x09, 0x0e, 0xc3, 0xd1, 0xfd, 0xbb, 0x30, 0xdb, 0x53, 0x1a, 0xb4, 0x2f, 0x11, + 0xfc, 0x13, 0x2f, 0xeb, 0xc8, 0xd3, 0x26, 0xf7, 0x24, 0x1f, 0xd0, 0xe5, 0xdc, + 0x36, 0xec, 0xd1, 0x2f, 0xc8, 0x28, 0xe4, 0xd1, 0x52, 0x24, 0x24, 0xe5, 0xf2, + 0x0b, 0xc4, 0xf5, 0xcf, 0x38, 0xdc, 0x2a, 0x26, 0xe6, 0xdc, 0xc0, 0xec, 0xd8, + 0xda, 0xf7, 0xd1, 0xf7, 0xfb, 0x06, 0xf7, 0xd7, 0x19, 0x2b, 0xf4, 0xff, 0xf8, + 0x19, 0xd2, 0xe4, 0xba, 0x1b, 0xd7, 0x1b, 0x22, 0xfc, 0x53, 0xef, 0xee, 0x21, + 0x9d, 0xe3, 0xf0, 0x14, 0xe7, 0xa4, 0x0e, 0x0a, 0xd5, 0x23, 0x1a, 0x2b, 0xe5, + 0x1a, 0x14, 0x0b, 0xf1, 0xe7, 0xe6, 0xdd, 0x09, 0x0f, 0x03, 0xeb, 0x09, 0x18, + 0x19, 0x31, 0xae, 0xf0, 0x29, 0x09, 0x0a, 0xe2, 0xe5, 0xe3, 0xcc, 0xfb, 0x02, + 0x03, 0xa9, 0xee, 0x18, 0xf0, 0xfe, 0xca, 0xed, 0xd2, 0xfb, 0xf4, 0xe2, 0xf7, + 0x05, 0x07, 0xdc, 0xf0, 0xf1, 0xe5, 0x11, 0x26, 0xc3, 0xaf, 0x0f, 0xf6, 0x0f, + 0x25, 0xc2, 0xd8, 0x10, 0x11, 0x1f, 0x19, 0x05, 0xfa, 0xfb, 0xd2, 0xe9, 0xf8, + 0xcc, 0xb5, 0xf3, 0xdb, 0xc8, 0x4a, 0xe7, 0xf7, 0x1b, 0x1a, 0x2c, 0xfa, 0xcd, + 0x00, 0x23, 0x33, 0xce, 0xb3, 0x13, 0xa8, 0x01, 0xc5, 0x0d, 0x32, 0xee, 0xe2, + 0xef, 0x25, 0xcd, 0xe8, 0xf3, 0x18, 0xe0, 0xf0, 0x2a, 0xde, 0x7f, 0x4a, 0xac, + 0x1a, 0x04, 0x17, 0x01, 0xe8, 0xdb, 0xdc, 0x2a, 0xf0, 0xe4, 0x11, 0x01, 0x2c, + 0x09, 0x16, 0x0f, 0xda, 0x40, 0xd8, 0x1d, 0x12, 0x0c, 0x10, 0x3a, 0xe6, 0xef, + 0x22, 0xd6, 0xad, 0xda, 0x53, 0x0b, 0x20, 0x26, 0x15, 0xb9, 0x1b, 0xe0, 0x37, + 0x09, 0xd2, 0xf3, 0xf9, 0xd7, 0xc4, 0x16, 0xcf, 0xdc, 0x16, 0xec, 0x1c, 0x23, + 0xc5, 0xe9, 0xe5, 0xca, 0x20, 0xb9, 0x10, 0xe7, 0x10, 0x51, 0x0f, 0xdd, 0x4f, + 0x21, 0x16, 0x28, 0xc1, 0xb8, 0xe3, 0x06, 0xe0, 0x12, 0x0a, 0xb5, 0x0c, 0x39, + 0x27, 0xe2, 0x02, 0x00, 0xbb, 0x4b, 0x0b, 0xaa, 0xc7, 0xf6, 0x47, 0x2d, 0xdf, + 0x0d, 0xfd, 0xf8, 0xba, 0xf0, 0xe9, 0x08, 0xdd, 0x00, 0xe4, 0xf2, 0xf6, 0xec, + 0x04, 0xc0, 0x36, 0x19, 0xd0, 0x03, 0xf9, 0xaf, 0xbc, 0xf0, 0xda, 0x21, 0xe7, + 0xc9, 0xba, 0x4f, 0xa7, 0xcc, 0xf8, 0x2f, 0xe5, 0x71, 0xe8, 0x0a, 0x38, 0xc5, + 0x15, 0xdb, 0x0f, 0x10, 0xff, 0x30, 0x02, 0xe3, 0x35, 0x0e, 0xf5, 0x24, 0xfa, + 0x32, 0xc9, 0x49, 0xf0, 0xf7, 0x1a, 0xf5, 0x0a, 0xd3, 0xb4, 0xe9, 0x0a, 0xcc, + 0x0e, 0xc0, 0xd7, 0xf4, 0x0e, 0x35, 0x1b, 0xcd, 0xf0, 0xc6, 0x01, 0x26, 0xba, + 0x10, 0xe3, 0x4b, 0x39, 0x2e, 0xbe, 0xfc, 0xd3, 0xfb, 0xf0, 0x10, 0x3a, 0xbf, + 0x09, 0xc3, 0xb3, 0xd0, 0xcb, 0xf6, 0x42, 0x06, 0x0a, 0xea, 0xca, 0x1c, 0x19, + 0x35, 0x2c, 0xdf, 0xed, 0x0e, 0x09, 0xfe, 0x08, 0x03, 0xde, 0xbb, 0xe3, 0xe6, + 0xc6, 0x2e, 0xff, 0xe2, 0xe7, 0x0c, 0x1f, 0xce, 0xf2, 0x05, 0xbc, 0xdc, 0xfe, + 0xed, 0x1b, 0x24, 0xa3, 0xe9, 0xd6, 0x0f, 0x20, 0x7f, 0x01, 0xed, 0x03, 0x3e, + 0xd9, 0xdd, 0x0a, 0xf8, 0x3e, 0xe6, 0xd5, 0xf6, 0xfc, 0xe4, 0xc9, 0xf3, 0xdd, + 0xba, 0x04, 0x1a, 0x04, 0x30, 0x26, 0xe1, 0xda, 0x49, 0xe1, 0xab, 0xfa, 0x22, + 0xe6, 0xc6, 0x0e, 0xe3, 0xd8, 0x1a, 0x1b, 0xd4, 0xd7, 0xfa, 0x20, 0xee, 0xf5, + 0xf9, 0x16, 0x0b, 0xdd, 0xd2, 0x12, 0xff, 0x51, 0xec, 0xf7, 0xdd, 0xb1, 0xec, + 0xe2, 0xfe, 0xfb, 0xd3, 0x38, 0xd2, 0xfc, 0xb7, 0xee, 0x0d, 0xf0, 0xe7, 0xed, + 0xce, 0x1b, 0x2e, 0x2a, 0x24, 0xe3, 0xeb, 0x30, 0x03, 0x0e, 0xd0, 0x04, 0xdd, + 0x3b, 0xdf, 0x49, 0x1d, 0xe5, 0x05, 0xeb, 0x07, 0xcb, 0x24, 0x23, 0xc2, 0xed, + 0xf4, 0xeb, 0xc6, 0xb7, 0x5c, 0xf0, 0xe7, 0x69, 0xf7, 0x05, 0x16, 0xc1, 0xdb, + 0xfa, 0x2b, 0xe1, 0x19, 0xe2, 0xa7, 0x0a, 0xb7, 0xf0, 0x40, 0xd2, 0xc1, 0xb8, + 0x2f, 0xc3, 0xeb, 0xcd, 0xf9, 0xe2, 0xfd, 0x0f, 0x0a, 0xe3, 0x18, 0x19, 0xa5, + 0x0d, 0xed, 0xf0, 0xcc, 0xe8, 0xed, 0xf3, 0x2a, 0x09, 0xb1, 0xf7, 0xd9, 0x3d, + 0xf6, 0x42, 0xff, 0x31, 0xdf, 0x09, 0xd0, 0x1b, 0xb8, 0xd6, 0xeb, 0x48, 0xfd, + 0x00, 0xb7, 0x05, 0xf7, 0x12, 0x01, 0x1a, 0x05, 0xcc, 0xf3, 0xe6, 0xeb, 0xcf, + 0x1f, 0xc5, 0x23, 0x00, 0x33, 0xbd, 0xf7, 0xd9, 0xb7, 0x18, 0xec, 0xa7, 0xee, + 0xf4, 0xb4, 0xf2, 0x01, 0xc7, 0x1e, 0x1b, 0xf2, 0xc7, 0x0a, 0x07, 0x17, 0x1c, + 0xbf, 0xc8, 0x32, 0x1a, 0x1c, 0xe7, 0x96, 0xf6, 0xfd, 0x34, 0x0e, 0xf8, 0xf2, + 0x10, 0x14, 0xdb, 0x02, 0x2c, 0xed, 0xef, 0x18, 0xe4, 0x16, 0xdd, 0xd9, 0xea, + 0xf2, 0x1c, 0x24, 0x13, 0x07, 0x17, 0xe1, 0x1d, 0xe9, 0xd2, 0xbe, 0xe6, 0xfe, + 0x30, 0x3e, 0x1a, 0x2f, 0x0a, 0x06, 0xdb, 0x01, 0xe0, 0x16, 0xb3, 0x1a, 0x1f, + 0xd4, 0x05, 0xea, 0xfd, 0xcb, 0x13, 0x08, 0xb8, 0x2a, 0xb6, 0xf8, 0xeb, 0x29, + 0x22, 0x3b, 0x2e, 0xf2, 0xe7, 0x10, 0xea, 0xd3, 0xf2, 0xf5, 0x14, 0x17, 0x03, + 0x29, 0x17, 0xe5, 0xfb, 0xf1, 0xc7, 0xd3, 0xb9, 0x10, 0x06, 0xcf, 0x96, 0xeb, + 0x13, 0x02, 0xd7, 0x42, 0xfd, 0xb8, 0xf0, 0xf3, 0xf9, 0x07, 0xc3, 0xe9, 0xf4, + 0x1a, 0xd5, 0xf0, 0xbf, 0x24, 0xd6, 0x17, 0xe4, 0xd6, 0x0e, 0x0d, 0xe8, 0x0e, + 0x0a, 0x44, 0xef, 0xad, 0x0f, 0xeb, 0x3b, 0xd2, 0x33, 0x32, 0xc8, 0xf5, 0x2c, + 0x47, 0xcb, 0x1c, 0x2a, 0xee, 0x31, 0x81, 0xd0, 0xe2, 0xdb, 0x10, 0xdb, 0x31, + 0xfd, 0xe6, 0x16, 0xc6, 0x40, 0xdb, 0x26, 0xf4, 0xfe, 0x2e, 0xe8, 0xc0, 0xf7, + 0x1a, 0xbb, 0xd5, 0x0f, 0x35, 0xfd, 0xf8, 0xee, 0xbc, 0x06, 0xd0, 0x0e, 0xd5, + 0xc6, 0xf9, 0xbe, 0xf5, 0xbe, 0xc8, 0xf0, 0x11, 0xfc, 0xe6, 0x01, 0xf9, 0xe7, + 0x1e, 0x27, 0xdb, 0xdb, 0xdd, 0x10, 0x1c, 0xee, 0x0f, 0x06, 0xdc, 0x2b, 0x1d, + 0xfc, 0x35, 0xf8, 0x43, 0x07, 0x05, 0xc2, 0x17, 0x36, 0xe8, 0x12, 0x13, 0x08, + 0xfd, 0xf0, 0xb3, 0xcf, 0x4f, 0xe5, 0xea, 0x2e, 0xfd, 0xfa, 0xe7, 0x26, 0x1f, + 0xee, 0xe7, 0x2f, 0xe0, 0x0c, 0x1c, 0x29, 0x11, 0x16, 0x25, 0xe4, 0x1e, 0x14, + 0x00, 0xfe, 0xd5, 0xf7, 0xe3, 0xe7, 0x13, 0xc0, 0xf5, 0xc0, 0x24, 0x0a, 0xed, + 0xf9, 0xe0, 0xc6, 0xe5, 0x10, 0x0e, 0xe6, 0xda, 0x16, 0x1b, 0x11, 0xf9, 0xf5, + 0xf1, 0xd2, 0xe8, 0xd3, 0x02, 0xd6, 0xde, 0x07, 0x1f, 0x07, 0xdc, 0xc8, 0x00, + 0x07, 0xe9, 0x40, 0x16, 0xef, 0xfa, 0xfa, 0xe3, 0x0d, 0xef, 0xdc, 0x2e, 0x03, + 0xf5, 0xc9, 0xc5, 0xda, 0xbb, 0xea, 0xb0, 0xd3, 0xfd, 0x0e, 0x02, 0x05, 0xf2, + 0xdf, 0x18, 0x94, 0xe5, 0xf1, 0xea, 0x0a, 0x08, 0x3e, 0xdf, 0xe5, 0xd2, 0x1a, + 0xb9, 0xea, 0xe4, 0x25, 0x33, 0x24, 0x2c, 0x05, 0x14, 0x7f, 0xef, 0xef, 0x2d, + 0xf1, 0xe5, 0x15, 0xdf, 0xf7, 0xa0, 0x2f, 0xf4, 0xfb, 0x10, 0x0d, 0xd4, 0x00, + 0x07, 0xde, 0x33, 0xed, 0x14, 0xff, 0xfa, 0xe2, 0x51, 0xea, 0xa5, 0x2c, 0x16, + 0x0c, 0x1d, 0x01, 0xcf, 0xdd, 0xf6, 0xef, 0x1f, 0x12, 0x5a, 0x19, 0xc4, 0xee, + 0x07, 0xdf, 0xc3, 0x6a, 0xed, 0xdf, 0x49, 0x30, 0x2d, 0x08, 0x02, 0x0b, 0xf1, + 0xdd, 0xfc, 0x15, 0xd0, 0xbd, 0x03, 0x1c, 0xef, 0xdd, 0xe7, 0xba, 0x47, 0x45, + 0xb9, 0xbe, 0xd6, 0x2e, 0xcc, 0xab, 0xbc, 0x06, 0xe8, 0x07, 0xdf, 0x0f, 0xd9, + 0x07, 0x06, 0x1a, 0xb2, 0xe2, 0x25, 0xfd, 0xfa, 0x0d, 0x16, 0x04, 0xfa, 0x2b, + 0xda, 0x1a, 0x0e, 0xb7, 0xc5, 0xef, 0xbd, 0xe0, 0x85, 0xdb, 0x03, 0xf3, 0xd5, + 0xf7, 0x91, 0xc6, 0xad, 0x0e, 0xc6, 0xed, 0xea, 0x0f, 0xfb, 0xd1, 0xaf, 0x03, + 0x24, 0x26, 0x3e, 0xe2, 0x55, 0xe7, 0xd2, 0xe7, 0xbb, 0x01, 0xc2, 0x42, 0x23, + 0xe0, 0x24, 0x11, 0xb8, 0x55, 0xf8, 0x9d, 0xf4, 0xe4, 0x2d, 0x04, 0x8b, 0x29, + 0xca, 0xff, 0x1c, 0xfe, 0xd3, 0x3f, 0x30, 0x07, 0x4b, 0xfe, 0x2e, 0xb9, 0xff, + 0x2a, 0x59, 0x4e, 0xed, 0xcb, 0x01, 0xcc, 0x09, 0x2e, 0x42, 0x1c, 0xaf, 0x46, + 0xc9, 0xee, 0x9f, 0xc6, 0xbb, 0xeb, 0xbd, 0x11, 0x3e, 0xef, 0xef, 0x36, 0xa7, + 0xde, 0xc4, 0xc8, 0xee, 0x8d, 0xbc, 0x3b, 0xdd, 0x49, 0xe1, 0xb5, 0xc0, 0xe2, + 0xe3, 0x29, 0xd1, 0xfe, 0x1a, 0x03, 0x95, 0xe6, 0xe6, 0xca, 0xfd, 0xe6, 0x1b, + 0xf1, 0x14, 0x12, 0xed, 0xf0, 0x00, 0xc6, 0x2f, 0x02, 0xb7, 0x26, 0xf7, 0x9d, + 0x27, 0x91, 0xf7, 0x54, 0x38, 0xba, 0xea, 0xf8, 0xfc, 0xd9, 0xab, 0x37, 0x07, + 0x8e, 0xf2, 0x31, 0x0c, 0x1e, 0xd6, 0x0a, 0x09, 0xef, 0x81, 0x1c, 0xbc, 0x08, + 0x13, 0xe6, 0xf8, 0xb2, 0xdd, 0x11, 0x51, 0xe4, 0x50, 0xcc, 0xa9, 0x35, 0xf8, + 0x3c, 0x97, 0xd4, 0xce, 0xea, 0xf6, 0xe2, 0xd4, 0x58, 0xf4, 0xb6, 0x42, 0xe5, + 0x33, 0x4a, 0xfc, 0xdd, 0x35, 0x2a, 0xa3, 0x28, 0xe9, 0x5a, 0xa5, 0xe0, 0xf2, + 0xe5, 0x06, 0x23, 0x2e, 0x59, 0xdc, 0x3a, 0xec, 0x26, 0x2f, 0x32, 0xc9, 0xec, + 0xc4, 0x08, 0x0c, 0xcd, 0xe6, 0x5d, 0x39, 0x95, 0xd7, 0xc7, 0x34, 0x29, 0xcb, + 0xf3, 0xe6, 0xfc, 0x0c, 0xf2, 0xd6, 0xd8, 0x3f, 0x2b, 0x1e, 0x15, 0xf4, 0x0c, + 0x51, 0x05, 0x2b, 0x26, 0xd3, 0x08, 0x28, 0x07, 0xf5, 0xff, 0x24, 0x42, 0x0a, + 0xb4, 0x1e, 0xab, 0x2a, 0x18, 0x53, 0x94, 0xd3, 0xf6, 0xfa, 0x59, 0x47, 0xbb, + 0xd7, 0xd5, 0xbb, 0x53, 0xfd, 0xf3, 0xd7, 0xf8, 0xe0, 0x09, 0x37, 0x03, 0xc4, + 0x41, 0x5b, 0xc4, 0xdf, 0xef, 0xbf, 0x35, 0xbf, 0x29, 0xb8, 0xec, 0xac, 0xf9, + 0x9c, 0xc6, 0x29, 0xf4, 0xb1, 0xd4, 0x14, 0x79, 0x56, 0xdf, 0xf2, 0x2e, 0xfe, + 0x6c, 0xc2, 0xdc, 0xc7, 0x2e, 0x08, 0xca, 0xbf, 0x02, 0xc3, 0x2f, 0xdf, 0x1f, + 0xf1, 0xa6, 0xfb, 0xf7, 0x25, 0x04, 0x72, 0xe5, 0x00, 0x1c, 0xe0, 0x32, 0xd1, + 0x6b, 0xe4, 0xb7, 0xbe, 0x06, 0x52, 0xc4, 0x5a, 0x4c, 0x15, 0x15, 0xd5, 0xe0, + 0x35, 0x8c, 0x30, 0xcd, 0xc5, 0xfb, 0xdb, 0xd0, 0x2e, 0xc6, 0x23, 0x32, 0x06, + 0xd5, 0xbc, 0xad, 0x13, 0xc6, 0x41, 0x29, 0xe2, 0x29, 0xe3, 0x25, 0x00, 0x24, + 0x01, 0x3a, 0xe9, 0xdf, 0xd8, 0x16, 0x37, 0xcf, 0xff, 0x03, 0xe9, 0x06, 0x20, + 0xe2, 0x3c, 0xd1, 0xcc, 0x26, 0xe8, 0xc2, 0xd6, 0x0d, 0x35, 0x08, 0xae, 0x13, + 0x47, 0x1b, 0xe6, 0x46, 0x49, 0x34, 0x36, 0x9a, 0xf9, 0x56, 0xdb, 0xc1, 0x36, + 0x3a, 0xd6, 0xcd, 0xca, 0xad, 0xb7, 0xa3, 0x2c, 0xa3, 0xe2, 0x0a, 0xe8, 0xf4, + 0x38, 0x47, 0xca, 0xf7, 0x0e, 0xb1, 0x15, 0x2a, 0xe8, 0xe5, 0x65, 0x3a, 0x01, + 0x54, 0x4a, 0x2d, 0xfc, 0x33, 0x23, 0x07, 0x81, 0xc3, 0xa2, 0xda, 0x05, 0x08, + 0x02, 0x57, 0x0d, 0xe4, 0xd4, 0xc8, 0xce, 0x2b, 0xc2, 0x38, 0x04, 0xd4, 0xdf, + 0xbb, 0x07, 0x0b, 0xce, 0xb6, 0xf5, 0x01, 0xd6, 0x4a, 0x01, 0x41, 0x4b, 0xd3, + 0xf4, 0x3d, 0x3f, 0x0d, 0x1c, 0xeb, 0xe6, 0x68, 0x07, 0x04, 0x19, 0x9b, 0xbb, + 0xfb, 0xfc, 0xd0, 0x03, 0x01, 0xbd, 0xf3, 0xa3, 0xcf, 0xc5, 0x2c, 0x15, 0xf3, + 0x6c, 0x34, 0xfa, 0xed, 0x17, 0x0f, 0x1b, 0xe7, 0xe1, 0x11, 0x34, 0xad, 0xfd, + 0x90, 0x00, 0x12, 0x50, 0x06, 0xf0, 0xa3, 0x12, 0xbf, 0xbe, 0x00, 0x20, 0x49, + 0xed, 0xe7, 0xde, 0x07, 0xd0, 0x12, 0x1b, 0xba, 0xab, 0x26, 0x34, 0xaa, 0x27, + 0xb2, 0x37, 0x02, 0xf8, 0x07, 0x07, 0xf3, 0x02, 0xf8, 0xd5, 0x27, 0xdb, 0x2b, + 0xc8, 0x2a, 0xd4, 0x36, 0x0d, 0xd6, 0xe5, 0x37, 0xec, 0x6b, 0x2a, 0x0f, 0xb4, + 0x58, 0xdc, 0xc7, 0x30, 0xea, 0xc5, 0x06, 0xcb, 0x22, 0x16, 0xd2, 0xf7, 0x14, + 0xff, 0xe5, 0x3b, 0x01, 0xee, 0x2e, 0xcf, 0x06, 0xcd, 0x7f, 0x11, 0xf8, 0xc6, + 0x04, 0x3e, 0xd8, 0x22, 0xd0, 0x02, 0xe1, 0xa0, 0xcf, 0x2f, 0xbb, 0x3f, 0x2c, + 0xe8, 0x34, 0x17, 0xbc, 0x21, 0xf6, 0xc7, 0x49, 0xf2, 0x0d, 0xb5, 0xed, 0xbb, + 0xce, 0x00, 0xbf, 0xb1, 0xfb, 0xc5, 0x53, 0x06, 0x13, 0xb2, 0xfb, 0x06, 0xd7, + 0xee, 0x5a, 0x0f, 0xeb, 0xa8, 0xe7, 0xfd, 0x0f, 0x16, 0xf1, 0xe1, 0x37, 0x9f, + 0x38, 0xed, 0xf0, 0xd3, 0x24, 0x2f, 0xaa, 0xef, 0xf8, 0x01, 0xfe, 0x47, 0xfb, + 0x27, 0x0a, 0xdf, 0xa2, 0xf7, 0xd2, 0x20, 0xac, 0x2e, 0x0e, 0xea, 0xc7, 0xfb, + 0xcf, 0x43, 0xed, 0x93, 0xc5, 0x00, 0x22, 0x2d, 0x57, 0x61, 0x02, 0xfc, 0xda, + 0x23, 0xec, 0xf1, 0x13, 0x44, 0xef, 0x2b, 0xeb, 0x12, 0x73, 0xcd, 0xe4, 0x00, + 0xe9, 0x5d, 0xe6, 0xcb, 0xc5, 0xd6, 0xec, 0xe4, 0x20, 0xec, 0xb0, 0x52, 0xb4, + 0xb7, 0xd1, 0xd1, 0xc8, 0xb7, 0x14, 0xd9, 0xba, 0xfe, 0xbc, 0x14, 0x1c, 0xe1, + 0xa5, 0xf1, 0xb1, 0xe0, 0xd8, 0xe7, 0xbe, 0xfc, 0xf2, 0xcf, 0x09, 0x27, 0xdd, + 0x02, 0xe4, 0x12, 0x4d, 0xcd, 0x21, 0x12, 0xac, 0xe8, 0x06, 0xee, 0xce, 0x46, + 0xdc, 0xde, 0x0f, 0xf4, 0xf2, 0xf1, 0xba, 0xd1, 0xe6, 0x36, 0xda, 0x3c, 0xfb, + 0xdb, 0xc9, 0x00, 0xdd, 0xfe, 0xc3, 0xe7, 0xa6, 0xc5, 0xba, 0x22, 0xee, 0xe3, + 0xa6, 0x43, 0x00, 0xdd, 0xd8, 0xe4, 0x24, 0x13, 0xfc, 0x0d, 0x09, 0xde, 0xcd, + 0xca, 0xfe, 0xff, 0x07, 0xe7, 0xd6, 0xaa, 0x06, 0xdd, 0xd9, 0x34, 0xcc, 0x1a, + 0x45, 0xd9, 0xe9, 0xec, 0xef, 0xfb, 0xdd, 0xee, 0xf6, 0x1d, 0x08, 0xfc, 0xdd, + 0xd4, 0x25, 0xaa, 0x0c, 0xee, 0x03, 0xaf, 0x02, 0x52, 0xcf, 0x01, 0xb8, 0xed, + 0xb6, 0x17, 0x4a, 0x1e, 0x25, 0x13, 0xba, 0xc9, 0xfa, 0xec, 0x0c, 0x16, 0xcf, + 0xcc, 0xe4, 0x02, 0xf8, 0xf0, 0x45, 0xea, 0x04, 0xee, 0xeb, 0x09, 0x3b, 0x35, + 0xc5, 0x06, 0xc0, 0x0b, 0xd1, 0xd2, 0xf7, 0x28, 0x10, 0x14, 0x2c, 0xe6, 0x19, + 0xd1, 0xf6, 0xec, 0x17, 0xd3, 0xda, 0x44, 0x47, 0x00, 0xdc, 0x15, 0x0e, 0xf5, + 0xdd, 0xdd, 0xed, 0x55, 0xa2, 0x06, 0xf5, 0xff, 0x07, 0x3f, 0xc8, 0xbb, 0xf7, + 0xe9, 0xe9, 0xcd, 0xba, 0x04, 0xd7, 0x00, 0x25, 0x15, 0x23, 0x77, 0x06, 0xbd, + 0x50, 0xc3, 0xd9, 0xcf, 0x30, 0xe2, 0xaf, 0xc0, 0x2b, 0xbd, 0x17, 0x05, 0xe9, + 0x51, 0xfe, 0x08, 0x26, 0x25, 0xdf, 0xe7, 0xfc, 0xb6, 0x02, 0xd8, 0x0c, 0xd3, + 0xe1, 0xf5, 0x20, 0xd7, 0x40, 0x11, 0x02, 0x14, 0xe9, 0xe2, 0xbe, 0xe6, 0x1e, + 0x14, 0xdc, 0xfa, 0x03, 0x27, 0xcb, 0xf9, 0x21, 0x08, 0x17, 0x1b, 0x04, 0x26, + 0xf4, 0xf1, 0xd6, 0xc2, 0xca, 0xfa, 0xfe, 0x2d, 0xf7, 0xdd, 0xd9, 0xe4, 0x3a, + 0x00, 0x35, 0x0f, 0xfc, 0xf4, 0x18, 0x08, 0xdf, 0x1d, 0x10, 0x48, 0xb3, 0xdf, + 0x1e, 0x0d, 0x00, 0x19, 0xb3, 0x3f, 0x7f, 0x1f, 0xc2, 0x1c, 0xc9, 0xd4, 0x36, + 0xf1, 0xd1, 0xeb, 0x03, 0xe6, 0x18, 0x18, 0xe7, 0xe2, 0xe6, 0xf8, 0xdd, 0x0a, + 0x23, 0xf0, 0xc5, 0x1c, 0xf0, 0x10, 0xcd, 0xf0, 0x9f, 0xc2, 0xd8, 0x1d, 0xe4, + 0x20, 0xfa, 0x1f, 0xf2, 0xcc, 0x0a, 0xc7, 0x00, 0xf5, 0x07, 0x19, 0x1a, 0x64, + 0xdb, 0xe7, 0xf3, 0xc1, 0x14, 0xe5, 0xd3, 0xe7, 0x17, 0xf4, 0xbb, 0x17, 0xcd, + 0x2d, 0x1d, 0x27, 0xb0, 0x16, 0xe3, 0xf7, 0xe2, 0xfa, 0x42, 0x20, 0x24, 0xe6, + 0xdb, 0xd9, 0x12, 0x0d, 0xee, 0xe6, 0xff, 0x28, 0x07, 0x44, 0xfc, 0xd5, 0xff, + 0x05, 0xe5, 0xd4, 0xfb, 0xc1, 0xd3, 0xf8, 0x2c, 0x0a, 0x22, 0x0e, 0xe5, 0x1d, + 0x09, 0x25, 0xf7, 0x20, 0x26, 0x2f, 0x24, 0xda, 0x1e, 0xff, 0xb1, 0x10, 0x47, + 0x46, 0xe1, 0x25, 0xd3, 0xf6, 0xfe, 0x2c, 0xc8, 0x45, 0x20, 0xd1, 0x13, 0xdf, + 0xf9, 0x04, 0xd2, 0x2a, 0xfb, 0xf1, 0x15, 0xf4, 0xd5, 0xdb, 0x08, 0x03, 0xff, + 0x1a, 0x1a, 0x0c, 0xf7, 0xd5, 0xf6, 0xfd, 0xe1, 0xaa, 0xfc, 0x45, 0x4a, 0x14, + 0xea, 0xfc, 0x07, 0xf2, 0x28, 0xfa, 0x24, 0x1e, 0xc3, 0xda, 0x3d, 0xf6, 0x01, + 0xfd, 0x1f, 0x04, 0xe3, 0x2a, 0xda, 0xfc, 0xfb, 0xdd, 0xe1, 0xf6, 0xda, 0xe5, + 0x14, 0xf8, 0xf1, 0x2e, 0x08, 0x1f, 0xfc, 0xf8, 0xff, 0xe5, 0xf5, 0x35, 0xf2, + 0x16, 0xf4, 0xfb, 0xe3, 0xf9, 0xfb, 0xf8, 0xf9, 0xe3, 0xdc, 0xfc, 0xf6, 0x13, + 0x11, 0x11, 0x7f, 0xfc, 0x16, 0xee, 0xe8, 0x21, 0x06, 0x4c, 0xec, 0x10, 0xf8, + 0xff, 0xfd, 0xff, 0x27, 0xb0, 0x17, 0x5d, 0xdd, 0xe5, 0xc0, 0xf1, 0xed, 0x38, + 0xd8, 0x04, 0xf7, 0x03, 0xd6, 0x09, 0xe9, 0x0d, 0x41, 0xea, 0x01, 0xea, 0xf4, + 0x21, 0x26, 0xe2, 0x1a, 0x00, 0x05, 0xf3, 0xe3, 0xc2, 0x0c, 0xef, 0x0c, 0xf6, + 0xd3, 0xce, 0x06, 0x08, 0x0b, 0xd2, 0x01, 0xf1, 0xf5, 0xfe, 0x38, 0x06, 0x2d, + 0x16, 0x0c, 0xf9, 0x05, 0xd4, 0x08, 0xc8, 0x24, 0xe1, 0x2a, 0xdd, 0x0c, 0x23, + 0x1c, 0x38, 0x04, 0xce, 0x0e, 0x11, 0x16, 0xf1, 0xf3, 0xd7, 0xdf, 0x0e, 0xb8, + 0xd9, 0xdb, 0x2d, 0x1e, 0x07, 0xdf, 0x06, 0xf8, 0xf7, 0x8a, 0xbe, 0xe2, 0xf6, + 0xfd, 0x09, 0xf2, 0x01, 0xc0, 0xee, 0xc7, 0x1b, 0xf3, 0x03, 0xfa, 0x97, 0xbc, + 0xd7, 0xe4, 0xb7, 0x0a, 0x0f, 0xd4, 0xc2, 0x45, 0x01, 0x07, 0x11, 0xd5, 0x03, + 0xde, 0xfa, 0xdd, 0xe2, 0xd6, 0xae, 0x41, 0xc1, 0x22, 0x0e, 0x2b, 0x81, 0xa2, + 0xf9, 0xfa, 0xed, 0x3a, 0xce, 0xe7, 0x21, 0x01, 0xf6, 0x17, 0xec, 0x17, 0x5e, + 0xb2, 0x0e, 0xe7, 0x33, 0xf7, 0xec, 0x05, 0x27, 0x08, 0x0d, 0x0e, 0xf6, 0xdb, + 0x82, 0x00, 0xd4, 0xe3, 0xed, 0xf5, 0xe8, 0x01, 0xba, 0xe6, 0xe2, 0xed, 0x17, + 0x3e, 0x1a, 0xc9, 0x46, 0xe6, 0xf1, 0x07, 0xe9, 0x04, 0x05, 0x20, 0xf7, 0x3a, + 0xf0, 0xad, 0xd4, 0xfe, 0x39, 0xd7, 0xf1, 0xdc, 0x60, 0xd8, 0xe4, 0xdf, 0x3e, + 0x01, 0xbc, 0xfa, 0x3f, 0xba, 0x58, 0x0b, 0x42, 0x42, 0xe6, 0x06, 0x0d, 0xf6, + 0x08, 0x0b, 0xd3, 0x25, 0xbe, 0x1d, 0x3e, 0xcc, 0xcd, 0xc2, 0xfe, 0xfd, 0xeb, + 0xf4, 0xff, 0xf7, 0xd6, 0xf1, 0xf6, 0xc5, 0x08, 0x39, 0xb5, 0x04, 0xae, 0xff, + 0x59, 0x32, 0x31, 0xc6, 0xc1, 0xd2, 0xd6, 0xa2, 0xa3, 0xf7, 0x17, 0xde, 0x1e, + 0x51, 0xca, 0x99, 0xa1, 0xd7, 0x2b, 0x1e, 0x14, 0xba, 0xf5, 0x08, 0xca, 0x1a, + 0x0e, 0x36, 0x07, 0x11, 0xa4, 0x07, 0xb8, 0xd5, 0x27, 0x3a, 0x9e, 0xfa, 0xd4, + 0x0e, 0xec, 0xf6, 0x01, 0x23, 0x02, 0xf6, 0x2f, 0xe5, 0x3a, 0xbd, 0x26, 0xf5, + 0xd9, 0x2e, 0xdc, 0xc8, 0xe6, 0xd0, 0xc4, 0x07, 0xfe, 0x14, 0xc2, 0xeb, 0x1b, + 0xbf, 0xc1, 0xc5, 0x4f, 0x27, 0xeb, 0xcb, 0xed, 0xfb, 0x35, 0x11, 0x07, 0x4d, + 0xbc, 0x38, 0x14, 0x2b, 0x1e, 0xff, 0xfe, 0xdf, 0xb2, 0xfb, 0xf9, 0x1d, 0xed, + 0xe8, 0xec, 0x0d, 0x10, 0xfe, 0xe0, 0x29, 0xe5, 0xe1, 0x1d, 0x8c, 0x20, 0x41, + 0xe8, 0xdd, 0xd5, 0xed, 0x0f, 0xd9, 0x62, 0xd9, 0x5e, 0x63, 0x8b, 0x0c, 0x08, + 0x04, 0xf1, 0x31, 0xbd, 0x2e, 0xf0, 0x95, 0x3e, 0xe6, 0xfd, 0x04, 0x21, 0xe9, + 0x0e, 0x30, 0xe1, 0x0f, 0x47, 0x43, 0xed, 0xbc, 0xd4, 0x95, 0x99, 0x81, 0x78, + 0x1f, 0x04, 0x08, 0xc6, 0x0e, 0x09, 0xe2, 0x31, 0xec, 0x1a, 0xc9, 0x2c, 0xf9, + 0x17, 0x2f, 0xd8, 0xd9, 0xa0, 0xff, 0x32, 0x00, 0x26, 0xf5, 0xce, 0x25, 0xe3, + 0xe5, 0xbd, 0x0d, 0x74, 0xaf, 0xb5, 0xfd, 0x67, 0xc7, 0xc8, 0x4c, 0xa4, 0xfa, + 0xf6, 0xd2, 0x03, 0xf0, 0xc5, 0xf2, 0x2d, 0x2a, 0xb3, 0xd4, 0x26, 0xcd, 0x21, + 0x32, 0xe0, 0xfc, 0xb7, 0x96, 0x13, 0xfb, 0x1f, 0xdf, 0xb2, 0xd4, 0x0c, 0xf6, + 0x33, 0x26, 0xf7, 0xd7, 0xf0, 0x02, 0xc2, 0x52, 0x90, 0xe5, 0x16, 0xc0, 0x0e, + 0x09, 0x5f, 0x1b, 0x38, 0x2b, 0xd9, 0xba, 0xe4, 0xdc, 0xcb, 0x26, 0xdc, 0xfb, + 0xdb, 0xef, 0x27, 0xce, 0x01, 0xaf, 0xbd, 0x05, 0xf6, 0xd9, 0xcf, 0xea, 0x14, + 0xe6, 0xf9, 0x48, 0xc2, 0x40, 0xff, 0xf8, 0xc0, 0x24, 0x51, 0xda, 0x23, 0xc6, + 0xe5, 0xe9, 0xdc, 0x07, 0xa0, 0xdf, 0xa0, 0x13, 0xca, 0x23, 0x5b, 0xcb, 0xf5, + 0x0a, 0x04, 0x45, 0xbe, 0x29, 0xf5, 0x21, 0xb8, 0x20, 0x21, 0xfc, 0x14, 0x2b, + 0xf7, 0xee, 0x1c, 0xe6, 0x06, 0x2e, 0x29, 0x07, 0xf4, 0xf3, 0xd1, 0xe0, 0x21, + 0x28, 0xea, 0xe9, 0x1d, 0xd3, 0xc0, 0xed, 0xe1, 0x99, 0x42, 0x2a, 0x23, 0x92, + 0x2e, 0xe1, 0x04, 0xef, 0xec, 0x9e, 0x1b, 0xd7, 0xb8, 0x10, 0xe6, 0xed, 0x09, + 0xdd, 0xe5, 0x16, 0xf4, 0x10, 0xf5, 0xd2, 0x2b, 0x21, 0xae, 0xf2, 0x42, 0x2a, + 0x41, 0x42, 0xfb, 0xfb, 0x0a, 0xff, 0xbe, 0xfc, 0x1f, 0x29, 0xdb, 0x4e, 0x1d, + 0x08, 0xed, 0x01, 0x17, 0xa3, 0xd3, 0xd8, 0x0d, 0xe8, 0xf8, 0x78, 0xdb, 0xff, + 0x09, 0x31, 0xe5, 0x05, 0xec, 0x09, 0xc7, 0xc6, 0xeb, 0xd1, 0x05, 0x10, 0xef, + 0x16, 0xbb, 0xe1, 0xc3, 0xbe, 0x06, 0xb4, 0xd9, 0x02, 0xa0, 0xe5, 0xfe, 0x05, + 0x0e, 0xc7, 0xcc, 0x41, 0x29, 0x25, 0xfe, 0xf1, 0x24, 0xe7, 0xa9, 0x44, 0x00, + 0x12, 0x00, 0xb7, 0x25, 0xbf, 0x1d, 0x0f, 0x10, 0x4d, 0x8d, 0xe8, 0xfb, 0x0f, + 0xb0, 0x1f, 0xfe, 0x3a, 0xef, 0x16, 0x11, 0xcc, 0x03, 0xdb, 0xfe, 0x5b, 0xff, + 0x03, 0xb0, 0xed, 0xba, 0xf7, 0xc6, 0x2e, 0x1e, 0x1a, 0xe4, 0x27, 0xe3, 0xe2, + 0x0f, 0x0c, 0xb9, 0xa3, 0x01, 0xd3, 0xfb, 0x31, 0xc9, 0xfd, 0xcc, 0xbe, 0xed, + 0x0f, 0xe9, 0xe6, 0x10, 0xd3, 0x01, 0x00, 0x19, 0xcb, 0xfd, 0xac, 0xf9, 0xdb, + 0xd0, 0x9e, 0x3a, 0xde, 0x12, 0xcf, 0x0b, 0xb2, 0x0a, 0x15, 0xf2, 0xfc, 0x39, + 0x19, 0xe5, 0xf0, 0xf9, 0xcb, 0x4b, 0xd5, 0x02, 0x29, 0xce, 0xec, 0xfc, 0x20, + 0x1f, 0x13, 0xe8, 0xea, 0x41, 0xdb, 0x45, 0x4e, 0xe2, 0xb3, 0xf2, 0xd4, 0xad, + 0x0a, 0xfe, 0xe5, 0x06, 0x1a, 0x20, 0xce, 0xc0, 0x49, 0xf9, 0xfe, 0xdc, 0xcf, + 0xca, 0x00, 0xce, 0x40, 0x43, 0x1f, 0xb9, 0x30, 0xd7, 0xce, 0xa4, 0x0b, 0x0a, + 0x23, 0x12, 0x03, 0x16, 0xce, 0xdd, 0x10, 0xb1, 0x2f, 0xdc, 0x06, 0xd8, 0x1d, + 0xe4, 0x15, 0xfd, 0xc8, 0xe4, 0x09, 0xff, 0x13, 0xd3, 0x05, 0x40, 0xe7, 0x1c, + 0x39, 0xde, 0xe5, 0x50, 0xf1, 0xea, 0xfe, 0x0f, 0xc4, 0x35, 0x7f, 0xc6, 0x26, + 0x25, 0xb1, 0x01, 0xf3, 0x20, 0xbe, 0x44, 0xa8, 0x1b, 0xef, 0x0f, 0xc1, 0x00, + 0xf0, 0x2d, 0x02, 0xfe, 0x3b, 0x27, 0x03, 0x08, 0xfa, 0x38, 0x01, 0xd3, 0xfa, + 0xea, 0x32, 0xfa, 0xe3, 0x33, 0x0a, 0x0b, 0x59, 0x13, 0xb3, 0x17, 0xf6, 0x23, + 0xe8, 0x3c, 0x1b, 0xd6, 0xfe, 0x1e, 0x00, 0x05, 0xca, 0x12, 0xdd, 0x1e, 0xe0, + 0xfd, 0xc8, 0x12, 0xde, 0xc5, 0x09, 0xb3, 0xfc, 0xc4, 0x24, 0xbe, 0xc0, 0xfd, + 0xed, 0x13, 0xec, 0x0f, 0xa3, 0xbb, 0xe6, 0xeb, 0xd0, 0xf1, 0xe8, 0x26, 0x99, + 0x01, 0xca, 0xd7, 0xe6, 0xc8, 0xc4, 0xce, 0x3b, 0xee, 0xf8, 0x1b, 0x9a, 0x26, + 0xb1, 0x1a, 0xf5, 0xe5, 0x3e, 0x28, 0xe8, 0x10, 0xf0, 0x2a, 0xe0, 0xfa, 0x3e, + 0x2a, 0xd7, 0xde, 0x1d, 0x1b, 0x26, 0x0b, 0xcc, 0x4c, 0xef, 0x0c, 0xe6, 0xc1, + 0xdf, 0x06, 0xf6, 0x87, 0xbe, 0xd3, 0xc3, 0x28, 0x2f, 0x06, 0xb9, 0x5a, 0xff, + 0xa4, 0xe3, 0x06, 0x2d, 0x0f, 0x20, 0x9e, 0xb0, 0xbe, 0x1e, 0x20, 0xdb, 0xd3, + 0xda, 0x86, 0xd4, 0xe8, 0xed, 0x17, 0xef, 0xc9, 0xda, 0xbc, 0xbe, 0x06, 0xb1, + 0x24, 0xf1, 0x21, 0x01, 0xf3, 0xf0, 0x1c, 0x06, 0x19, 0x18, 0xef, 0xfc, 0x9e, + 0x0a, 0xd0, 0xdc, 0x78, 0x00, 0xfb, 0xe4, 0x05, 0xbc, 0x4a, 0x2c, 0xff, 0x81, + 0xf2, 0x32, 0x19, 0x05, 0xa6, 0x33, 0xf6, 0xda, 0xbe, 0xfd, 0xe8, 0xdd, 0x01, + 0x0f, 0xcb, 0xdc, 0x48, 0x52, 0x09, 0x7f, 0xf6, 0xa2, 0x02, 0xf7, 0x23, 0x03, + 0x4b, 0xf0, 0x44, 0x27, 0xaa, 0x01, 0xfb, 0xf5, 0xec, 0xfa, 0xea, 0xd6, 0xb1, + 0xc4, 0xde, 0xe0, 0x15, 0xf7, 0x0b, 0x05, 0xf0, 0xd7, 0x09, 0xef, 0xd1, 0x03, + 0xf5, 0x26, 0xd6, 0x18, 0xf1, 0xec, 0xd7, 0xea, 0xed, 0xf0, 0x18, 0x2b, 0x07, + 0xf5, 0xe6, 0xf3, 0x21, 0xe8, 0x31, 0xeb, 0xcd, 0xc8, 0xe7, 0x17, 0x2b, 0xff, + 0xd1, 0xed, 0xd5, 0xc2, 0x19, 0xe8, 0xff, 0xc2, 0x24, 0xf6, 0x2f, 0xf9, 0xcb, + 0x78, 0x01, 0xdd, 0xdc, 0xec, 0x10, 0x07, 0xec, 0x0f, 0x3f, 0xfd, 0x19, 0xd3, + 0xc7, 0xf3, 0xad, 0xae, 0x3c, 0xb8, 0x0a, 0xe5, 0xf7, 0xf2, 0x03, 0x08, 0x00, + 0xc9, 0x04, 0x4d, 0x29, 0xe2, 0x27, 0x0d, 0x08, 0xd4, 0xf6, 0x10, 0xc5, 0xf8, + 0xa3, 0xcf, 0x9d, 0x46, 0x0a, 0x25, 0x0a, 0xd2, 0xec, 0xd0, 0x18, 0x13, 0xf5, + 0xb7, 0x0b, 0xfd, 0x2a, 0x00, 0x37, 0x30, 0xc0, 0xf6, 0x12, 0xf3, 0xb1, 0x2c, + 0x14, 0x09, 0x30, 0xd9, 0xd9, 0xc4, 0xf5, 0x01, 0xc1, 0x2e, 0x2e, 0x04, 0xc6, + 0xf0, 0xab, 0xda, 0xce, 0xd8, 0x1e, 0xea, 0x3c, 0x1a, 0xd5, 0xe0, 0x01, 0xc1, + 0x1f, 0xe8, 0x04, 0x12, 0xe8, 0x10, 0xc6, 0x03, 0xe1, 0xda, 0xb6, 0xe8, 0xcb, + 0x8e, 0x43, 0xfb, 0xf3, 0x36, 0xd5, 0xd0, 0x53, 0xeb, 0xfa, 0xee, 0xd3, 0x39, + 0xd5, 0xf7, 0xa6, 0xba, 0x37, 0xd6, 0x10, 0x06, 0xbe, 0xbb, 0xc8, 0xb4, 0x15, + 0x02, 0xe4, 0x1c, 0xe7, 0xd9, 0x01, 0x2a, 0x0c, 0x16, 0x1c, 0x01, 0x11, 0xca, + 0xd6, 0xf8, 0x4a, 0xc1, 0xf5, 0x04, 0x09, 0xc3, 0xf0, 0x14, 0xca, 0xda, 0xf7, + 0xf6, 0x17, 0xfd, 0xde, 0x33, 0x39, 0xd8, 0x98, 0x0a, 0xe9, 0x2f, 0xf6, 0xe0, + 0x13, 0xd0, 0xfb, 0x01, 0xff, 0xd9, 0xea, 0xe6, 0xf9, 0x05, 0x37, 0xf5, 0x4c, + 0x06, 0xf7, 0x22, 0x06, 0xd9, 0x22, 0x18, 0x46, 0xfb, 0xe5, 0xfb, 0xde, 0xfc, + 0xc2, 0xee, 0x11, 0xec, 0xce, 0x0b, 0x2a, 0x09, 0x08, 0x3b, 0xd1, 0xe7, 0x1f, + 0x09, 0xe2, 0xfd, 0x0a, 0x15, 0xc7, 0xff, 0xca, 0x17, 0xab, 0xde, 0xdb, 0xfb, + 0xf6, 0x29, 0xd7, 0x21, 0xea, 0xc2, 0x08, 0x0f, 0xed, 0x1b, 0xf1, 0x0b, 0xfa, + 0x07, 0xde, 0xfc, 0xe1, 0x2c, 0x35, 0xf1, 0xe2, 0xc9, 0xf6, 0xd7, 0x1d, 0xad, + 0xea, 0x48, 0xfe, 0xe1, 0x05, 0x14, 0xf1, 0x0e, 0x1c, 0x0e, 0xb0, 0x3b, 0xf3, + 0x2a, 0x03, 0xef, 0x22, 0x3e, 0x0c, 0xdf, 0xba, 0x32, 0xca, 0xfe, 0xdf, 0x21, + 0x3d, 0x3e, 0x04, 0x09, 0x43, 0xf0, 0x3b, 0xc6, 0x4c, 0x81, 0x28, 0xfe, 0x09, + 0x3e, 0x1e, 0xe6, 0x21, 0xb3, 0x2b, 0xac, 0x1a, 0x09, 0xe3, 0x09, 0xe5, 0xf7, + 0xd8, 0xfb, 0xe4, 0xd3, 0xde, 0x15, 0x09, 0xe5, 0xb5, 0xc8, 0xe8, 0x20, 0xb2, + 0xe4, 0xf6, 0xeb, 0x23, 0xff, 0xd4, 0xcb, 0xdc, 0xeb, 0x1b, 0x8f, 0xf8, 0xf2, + 0x29, 0x41, 0x06, 0xc8, 0xe5, 0xcc, 0xff, 0x07, 0xf9, 0x33, 0xbe, 0xce, 0xf2, + 0x09, 0x9a, 0xd7, 0x08, 0x2a, 0x40, 0x1c, 0xef, 0x0c, 0xc8, 0xf3, 0xdb, 0xe9, + 0x2a, 0xd4, 0x1b, 0xb1, 0xd2, 0x3b, 0x33, 0xea, 0xfd, 0xf5, 0x0c, 0xd5, 0xe2, + 0x1c, 0x04, 0xef, 0xde, 0x0c, 0xf5, 0xad, 0x1f, 0xb0, 0xf9, 0xfc, 0xe4, 0xcf, + 0x0e, 0xaf, 0xe4, 0xe3, 0x16, 0xbe, 0xe7, 0xf1, 0xf8, 0xc8, 0x1f, 0xd8, 0xe9, + 0xbd, 0xb4, 0xb9, 0xe3, 0xbe, 0x17, 0x17, 0x28, 0xef, 0x03, 0xd9, 0xc5, 0xf6, + 0xf0, 0xff, 0x1b, 0xf2, 0xc3, 0xcc, 0xd8, 0xe6, 0x19, 0xaa, 0x06, 0xf0, 0x16, + 0xce, 0x0f, 0xd8, 0x18, 0xe9, 0x13, 0xfa, 0xf9, 0xb2, 0xb0, 0x24, 0x05, 0xe5, + 0xcd, 0x2d, 0xee, 0xd1, 0x13, 0x0d, 0xe8, 0xd2, 0xee, 0xdf, 0xf6, 0x65, 0xf9, + 0xc5, 0xa1, 0xe8, 0xce, 0xdd, 0xec, 0xdd, 0x1b, 0x15, 0x9b, 0x03, 0xcf, 0x33, + 0xce, 0x1e, 0xe2, 0x00, 0xe6, 0x03, 0xe0, 0xe5, 0x18, 0x1d, 0x01, 0x09, 0xe4, + 0xdb, 0xeb, 0x2c, 0x2b, 0xca, 0xc1, 0xe1, 0xdb, 0x01, 0xfa, 0xde, 0xc8, 0xe5, + 0x06, 0xd7, 0xda, 0xd7, 0x1e, 0xce, 0x37, 0x03, 0x13, 0xe3, 0xe6, 0x81, 0xe8, + 0x01, 0x19, 0xdb, 0x0f, 0xe8, 0xfe, 0xe5, 0xe6, 0xd6, 0x07, 0x85, 0xf8, 0x0c, + 0x1f, 0xd7, 0x25, 0x0b, 0xdd, 0x37, 0xd3, 0x17, 0x56, 0xd3, 0x03, 0x0a, 0x03, + 0xe8, 0x13, 0xbb, 0xff, 0xdc, 0x14, 0x0e, 0xe5, 0xae, 0x41, 0x16, 0x6c, 0x09, + 0xc6, 0xf8, 0xf8, 0x0d, 0xd8, 0xba, 0xdd, 0xf7, 0xfd, 0x18, 0x44, 0x8c, 0x3d, + 0xe3, 0x31, 0xd7, 0x1a, 0xef, 0x4e, 0x42, 0xc5, 0x1e, 0xcd, 0xe0, 0xfa, 0x03, + 0x2d, 0x4b, 0x0b, 0xfe, 0x2f, 0xea, 0x03, 0xfa, 0x0d, 0xe9, 0x1c, 0xe6, 0x0b, + 0x19, 0xe2, 0xf1, 0x15, 0xe2, 0x00, 0x33, 0xba, 0x33, 0xc4, 0xd5, 0xc2, 0x1b, + 0xd2, 0xee, 0xed, 0x1e, 0x13, 0xf9, 0xf1, 0xed, 0xee, 0x05, 0x13, 0x10, 0x15, + 0x5f, 0xcd, 0xe0, 0xdb, 0xd4, 0x28, 0xf9, 0x1e, 0xcc, 0xea, 0x23, 0x17, 0xcc, + 0x1f, 0xd7, 0x2e, 0xa8, 0x46, 0xec, 0xd0, 0xda, 0x12, 0xe2, 0xf1, 0x09, 0x2f, + 0xe6, 0x2f, 0xd9, 0xc4, 0xf0, 0xd8, 0x11, 0xbc, 0x0f, 0xf5, 0x34, 0x1d, 0x96, + 0x10, 0x01, 0xc4, 0xe9, 0x38, 0xe1, 0x2c, 0xf8, 0xcc, 0x0b, 0x33, 0xc6, 0xe5, + 0xf1, 0x23, 0x2f, 0x06, 0xdf, 0xb1, 0xb8, 0x13, 0x09, 0x11, 0xce, 0xc9, 0x4b, + 0x18, 0xce, 0x35, 0xfc, 0x3a, 0x12, 0xc3, 0x0d, 0x53, 0xc8, 0x0c, 0xd2, 0x2d, + 0xfd, 0xa1, 0xc3, 0xed, 0x35, 0x14, 0x0a, 0xfe, 0xf3, 0xdc, 0xb8, 0xcc, 0x1d, + 0x01, 0x0e, 0x3a, 0xe5, 0xd1, 0x12, 0x81, 0xdf, 0x09, 0xbd, 0x0c, 0xf0, 0x19, + 0x06, 0xe2, 0x11, 0xad, 0x07, 0xf1, 0x0e, 0xc3, 0x2b, 0x15, 0x1a, 0x31, 0xf1, + 0x13, 0xec, 0x10, 0x07, 0xde, 0x25, 0x1e, 0x1a, 0xe5, 0xd2, 0x25, 0xf4, 0x04, + 0x26, 0x20, 0x19, 0xff, 0x1a, 0x35, 0x26, 0xeb, 0x00, 0x00, 0x49, 0xca, 0xee, + 0xd0, 0xf0, 0xde, 0x27, 0x12, 0x0b, 0x0b, 0xf7, 0x12, 0x13, 0x05, 0xf3, 0x03, + 0x05, 0x3d, 0x12, 0xfe, 0xff, 0xd4, 0xfa, 0xf1, 0x3f, 0xfb, 0x17, 0x2e, 0x12, + 0xfb, 0x1a, 0xe7, 0x41, 0xc9, 0x01, 0xe1, 0xb8, 0x1d, 0x29, 0x37, 0xdd, 0xe9, + 0xda, 0xa9, 0x38, 0xbf, 0xef, 0xdb, 0xe7, 0xcd, 0xe5, 0x21, 0x1d, 0xc5, 0x08, + 0x33, 0xc3, 0xed, 0x19, 0x0c, 0x09, 0xf4, 0xcb, 0xef, 0xf2, 0x2c, 0x11, 0xfc, + 0xe0, 0x36, 0xdf, 0x29, 0x3f, 0xe5, 0x3b, 0xc7, 0xb6, 0xc8, 0xf9, 0x1c, 0xd5, + 0xfe, 0xed, 0xdb, 0xdb, 0xa4, 0xe1, 0xea, 0x0b, 0xf8, 0x1a, 0x4e, 0x19, 0xc7, + 0xec, 0x4e, 0xa6, 0x8f, 0xe1, 0xf8, 0xff, 0xe0, 0xe2, 0xd6, 0xdb, 0x04, 0x2e, + 0x42, 0x15, 0x16, 0xe0, 0xc3, 0xf3, 0x08, 0xd0, 0xfe, 0x11, 0x20, 0x52, 0xe5, + 0x1e, 0xe4, 0xd0, 0xf8, 0xf2, 0x17, 0xc6, 0x35, 0xaf, 0xcf, 0x1b, 0xfa, 0xc7, + 0xc7, 0xff, 0x13, 0x00, 0x2a, 0x4a, 0xd0, 0x3a, 0xd7, 0x38, 0xd0, 0xc4, 0x65, + 0xd6, 0x17, 0x2c, 0xe2, 0xfd, 0xfd, 0xf4, 0x3b, 0xe0, 0xf2, 0xba, 0x04, 0xe5, + 0x21, 0xad, 0x4f, 0x03, 0xf5, 0x1f, 0xa6, 0xb8, 0xe6, 0xd0, 0x37, 0xf5, 0xe4, + 0xd0, 0xf5, 0xfe, 0x03, 0x11, 0x4c, 0xea, 0xf5, 0x1c, 0xc0, 0xd2, 0xd9, 0x1c, + 0x13, 0xd2, 0xf3, 0x05, 0x12, 0xfa, 0x18, 0xd7, 0xcd, 0xbf, 0xda, 0xc6, 0xb4, + 0x1d, 0xfe, 0x37, 0x12, 0x8f, 0xbc, 0x5b, 0xe7, 0xc8, 0x20, 0xfc, 0xcf, 0xfb, + 0xfe, 0x32, 0x1d, 0x5e, 0x15, 0xea, 0xbe, 0xc8, 0xd3, 0x81, 0xc4, 0x04, 0xea, + 0xdd, 0xca, 0x32, 0x1d, 0x37, 0xb8, 0x00, 0x25, 0xe3, 0x0d, 0xf5, 0x3b, 0x16, + 0x04, 0x0a, 0x06, 0x28, 0xb1, 0x07, 0x18, 0xcd, 0x4c, 0xf2, 0xf6, 0x07, 0xc4, + 0x19, 0x22, 0xe0, 0x28, 0xd2, 0x2d, 0xf4, 0x1a, 0x0c, 0xf4, 0x44, 0x04, 0x2b, + 0x42, 0x03, 0x15, 0xb2, 0x96, 0x27, 0x17, 0x0b, 0x21, 0xe8, 0xab, 0x41, 0xd9, + 0x15, 0xd4, 0xdf, 0xf9, 0x30, 0x10, 0xb7, 0xe0, 0xe0, 0x09, 0x35, 0x00, 0x19, + 0xf7, 0xb7, 0xcb, 0x05, 0x1b, 0x0e, 0xf2, 0xd0, 0xde, 0x2f, 0x0e, 0x19, 0xd1, + 0x17, 0x1d, 0xe0, 0xeb, 0xf6, 0xc0, 0x6a, 0x10, 0xf8, 0xd2, 0x02, 0x04, 0xdb, + 0xe0, 0x07, 0x37, 0xe7, 0x1d, 0x02, 0x07, 0xec, 0xcf, 0xe7, 0xf5, 0xef, 0xbc, + 0xf4, 0x3f, 0xa6, 0x12, 0xff, 0x1b, 0x08, 0xb5, 0xf5, 0xd3, 0xbe, 0xf6, 0xda, + 0xd5, 0xda, 0x01, 0xef, 0xcf, 0x1a, 0x3e, 0xe6, 0xb7, 0xdc, 0xfe, 0xdf, 0xd4, + 0xee, 0x16, 0x21, 0xcb, 0x19, 0x27, 0x27, 0xe0, 0xf1, 0x06, 0x2c, 0x20, 0xcc, + 0x9d, 0xb4, 0x09, 0xf5, 0x1e, 0xd2, 0x09, 0x13, 0xfa, 0xca, 0x56, 0xe5, 0xd6, + 0xde, 0xfe, 0x12, 0xe5, 0x3c, 0xe4, 0xed, 0xfa, 0xfb, 0x21, 0xdc, 0x1a, 0x06, + 0xf7, 0x3f, 0xa3, 0xfa, 0x62, 0xe4, 0xed, 0x29, 0x11, 0x35, 0x0f, 0x78, 0xd0, + 0xf6, 0xf2, 0x51, 0x2e, 0xbb, 0xa3, 0xc6, 0x81, 0xec, 0x13, 0x4a, 0xcf, 0xe7, + 0x2a, 0xfa, 0xe6, 0x16, 0xcb, 0xf2, 0x95, 0x04, 0xde, 0xd3, 0x37, 0xcf, 0x9b, + 0x14, 0xf1, 0xfd, 0xfc, 0x12, 0x16, 0x16, 0xed, 0x22, 0xd3, 0xd5, 0xba, 0xd7, + 0xec, 0xe1, 0xdf, 0x2b, 0xd2, 0xc2, 0x08, 0xd7, 0xdd, 0xab, 0xd7, 0xe4, 0x0a, + 0xf4, 0xc5, 0xb2, 0x19, 0xdf, 0xe9, 0x24, 0xc2, 0xc2, 0xfd, 0xcb, 0xbd, 0xe7, + 0xaf, 0x8d, 0xad, 0x19, 0x27, 0x04, 0xe0, 0xea, 0x2f, 0xf4, 0xe8, 0x40, 0x2e, + 0xde, 0x2c, 0xcd, 0xfa, 0x53, 0x23, 0xdf, 0x5f, 0xdd, 0xe1, 0xb5, 0xea, 0x01, + 0x1f, 0xac, 0xff, 0xfe, 0x27, 0xdb, 0x1d, 0xc3, 0x90, 0xf1, 0xe3, 0xaa, 0x01, + 0x04, 0xe5, 0x07, 0xb7, 0xbf, 0xc4, 0xc9, 0x11, 0xc9, 0xb5, 0xe0, 0x1e, 0xdf, + 0x14, 0x03, 0x1a, 0xcc, 0x28, 0x02, 0xee, 0x1b, 0x13, 0xed, 0xef, 0x58, 0xa8, + 0x09, 0x10, 0x15, 0xed, 0x00, 0x66, 0x06, 0xeb, 0xe9, 0xe5, 0xed, 0xfe, 0x28, + 0xd9, 0xaa, 0xe9, 0x99, 0x46, 0x17, 0xd1, 0xe6, 0x0a, 0xdf, 0xdc, 0xbe, 0x32, + 0xb5, 0xfa, 0xf6, 0xf2, 0xd0, 0xf7, 0xca, 0x03, 0xe6, 0xfc, 0x07, 0xcf, 0xef, + 0x93, 0xe5, 0x05, 0xf1, 0xe1, 0xdc, 0x10, 0x15, 0x25, 0x18, 0x17, 0xba, 0xb1, + 0xeb, 0x9d, 0xdc, 0x04, 0xbe, 0x27, 0x2d, 0xf2, 0x15, 0xdb, 0x25, 0xe6, 0xe4, + 0xe9, 0x1e, 0x27, 0xe9, 0xff, 0x26, 0x39, 0xca, 0x12, 0xa0, 0xd3, 0xcc, 0xfc, + 0x1c, 0x9d, 0xc0, 0xd0, 0xfc, 0xe0, 0xd2, 0x11, 0x23, 0xf6, 0x3b, 0xfe, 0xfc, + 0x3a, 0x25, 0x48, 0xd5, 0xdf, 0xc5, 0x29, 0x0e, 0xfd, 0x5b, 0xe1, 0x09, 0x4d, + 0x19, 0x31, 0xc9, 0xb1, 0xfd, 0x12, 0x32, 0xb5, 0x00, 0xf4, 0x43, 0x2c, 0xfb, + 0x1b, 0xeb, 0xd8, 0xe8, 0x11, 0xb6, 0x2b, 0xff, 0xef, 0x26, 0xcd, 0x5c, 0xf6, + 0xe9, 0xf0, 0xf3, 0xfd, 0xea, 0x00, 0xc3, 0xce, 0x1f, 0x44, 0xcf, 0xe0, 0xd2, + 0x12, 0xc1, 0x16, 0xdd, 0xe7, 0x9e, 0x3a, 0x10, 0x05, 0xfe, 0x0d, 0x04, 0xaf, + 0xdc, 0xc1, 0xc5, 0xd2, 0xdc, 0xa0, 0xd9, 0x00, 0x01, 0x71, 0xe2, 0x15, 0x1c, + 0xd3, 0x11, 0xcb, 0x0b, 0xd5, 0x86, 0x14, 0xa7, 0x0c, 0xe3, 0x3b, 0xb9, 0xb5, + 0xd7, 0x34, 0xdf, 0x37, 0xf3, 0xf6, 0xf2, 0xe1, 0x38, 0x35, 0x01, 0x00, 0xe9, + 0xad, 0xe8, 0x07, 0x2a, 0x96, 0x23, 0x2e, 0xff, 0xe0, 0xd9, 0x26, 0xeb, 0xe2, + 0x58, 0xcb, 0xe7, 0x01, 0xc8, 0x13, 0x1f, 0xca, 0xe5, 0xde, 0xfc, 0x0a, 0xe4, + 0x04, 0xd2, 0xef, 0x20, 0xd7, 0x03, 0x0a, 0xff, 0x27, 0x19, 0xf0, 0xc6, 0x01, + 0x19, 0xfa, 0xbb, 0xde, 0x13, 0xf0, 0xfd, 0x03, 0x9c, 0x07, 0xdd, 0xc3, 0x27, + 0xe1, 0xb6, 0xb4, 0xe7, 0xde, 0xe4, 0x81, 0x07, 0xef, 0x12, 0xe3, 0x19, 0x27, + 0x17, 0xca, 0xbb, 0x08, 0xc7, 0xd6, 0x20, 0x99, 0xf1, 0xe6, 0x1f, 0xcd, 0x03, + 0x05, 0x43, 0x17, 0xcc, 0x08, 0xec, 0xc3, 0x23, 0x28, 0x15, 0x07, 0xd7, 0x21, + 0xf2, 0xfc, 0x02, 0xf2, 0xc3, 0xe7, 0x20, 0x1c, 0xde, 0xa1, 0x0b, 0xcb, 0x1c, + 0xed, 0x8b, 0xcb, 0xd6, 0x23, 0x18, 0xe6, 0xfe, 0xde, 0x2a, 0xfd, 0xca, 0x2b, + 0x28, 0xf4, 0xf9, 0xd2, 0xc1, 0xe1, 0x14, 0xc8, 0x17, 0x01, 0xe4, 0xdf, 0x28, + 0x25, 0x0c, 0xfe, 0xf8, 0x15, 0x39, 0xfe, 0xd4, 0xeb, 0x1d, 0xf0, 0xeb, 0x16, + 0x92, 0x45, 0xf6, 0xbc, 0x35, 0x0c, 0xff, 0x29, 0x41, 0xf4, 0xe4, 0x46, 0x2a, + 0x0a, 0xfe, 0xc6, 0xe7, 0xe6, 0xa9, 0x0e, 0x0a, 0x01, 0x12, 0x4f, 0x21, 0xe6, + 0x14, 0xab, 0x09, 0xe0, 0xd5, 0xba, 0xfc, 0xf4, 0x02, 0xf4, 0x2b, 0x39, 0xef, + 0x1c, 0xb6, 0xed, 0xe6, 0x0c, 0x03, 0xda, 0xd4, 0xe9, 0xf7, 0x48, 0xf2, 0xe5, + 0x2f, 0xc5, 0xad, 0x31, 0xcc, 0xfd, 0xb3, 0xf2, 0xc4, 0x39, 0xee, 0x0a, 0xfe, + 0xe9, 0x1e, 0xec, 0x14, 0x14, 0xe3, 0xfb, 0x02, 0xfc, 0xf1, 0xf9, 0xb5, 0xd0, + 0xc4, 0x08, 0xe1, 0xf4, 0x15, 0xec, 0xc1, 0xd8, 0x0d, 0xff, 0x2f, 0xf9, 0x18, + 0xc1, 0xcc, 0x5d, 0xa1, 0xf2, 0x29, 0xf7, 0xf7, 0x30, 0xe3, 0x21, 0xe1, 0x11, + 0x1e, 0x89, 0xf2, 0xfd, 0xdc, 0x27, 0xd1, 0x17, 0xee, 0xcd, 0x7d, 0x12, 0xc2, + 0x14, 0xb5, 0xdf, 0x1f, 0xcd, 0x42, 0xcc, 0x0f, 0xd2, 0x13, 0x63, 0x13, 0x40, + 0xef, 0x16, 0x12, 0x04, 0x4e, 0xc5, 0xd4, 0x0c, 0x14, 0x1e, 0xda, 0xa1, 0x48, + 0xcc, 0xfd, 0x1a, 0xac, 0x18, 0xe6, 0xfc, 0x3b, 0x31, 0x0f, 0x7f, 0xf8, 0xf4, + 0x87, 0x14, 0xb8, 0xe1, 0x14, 0xec, 0xa9, 0x31, 0x20, 0x45, 0x06, 0xed, 0xf0, + 0xda, 0xe5, 0xe4, 0xcc, 0xdb, 0xff, 0xe7, 0xd3, 0x12, 0xf6, 0xe7, 0x06, 0x16, + 0xf2, 0xb6, 0xdf, 0x0b, 0x2b, 0x15, 0xe5, 0xca, 0x0f, 0x1d, 0xd2, 0x41, 0x07, + 0xea, 0xd8, 0x16, 0x0a, 0xaf, 0xad, 0xee, 0x02, 0x01, 0x04, 0x60, 0xe9, 0x31, + 0x5d, 0x04, 0x0e, 0xcb, 0xc3, 0xaa, 0x0b, 0xda, 0xbe, 0x16, 0x12, 0xed, 0xf5, + 0x1d, 0xd4, 0xd6, 0x29, 0x21, 0xfa, 0x99, 0x16, 0x06, 0xaa, 0x15, 0xd4, 0x1c, + 0x10, 0xec, 0xe9, 0xe7, 0x14, 0xe9, 0xf0, 0x34, 0xbe, 0xf5, 0x53, 0xf5, 0x08, + 0xe4, 0xd2, 0xe3, 0x1b, 0xec, 0xf7, 0xb4, 0xf2, 0x0b, 0x15, 0xcb, 0xaf, 0xe8, + 0xc3, 0xe1, 0x1d, 0x24, 0xe9, 0x23, 0xfc, 0xce, 0xd0, 0xd1, 0xac, 0x20, 0x0a, + 0x09, 0xda, 0xd3, 0xf3, 0x25, 0x12, 0xee, 0xd1, 0xc6, 0x11, 0xac, 0xf2, 0x1c, + 0xe6, 0xec, 0xf4, 0x1a, 0xc0, 0xb3, 0x08, 0x0a, 0x2b, 0x30, 0x63, 0xdb, 0xfa, + 0xd3, 0x19, 0xdd, 0xf6, 0x58, 0xcf, 0xe9, 0x25, 0xee, 0xe5, 0xcd, 0x11, 0x08, + 0xe3, 0xdc, 0xec, 0x43, 0xdc, 0x04, 0xfd, 0x11, 0xbd, 0x16, 0xda, 0xea, 0xf8, + 0xdc, 0xee, 0xe9, 0xe3, 0x42, 0xb7, 0x32, 0xc9, 0xc1, 0x4b, 0xff, 0x16, 0x1c, + 0x1d, 0x99, 0xbd, 0x5c, 0x30, 0xd3, 0x0f, 0xe4, 0x74, 0xc7, 0x02, 0x0f, 0xc7, + 0x2d, 0xec, 0x2a, 0xe2, 0x0d, 0x1d, 0xec, 0x0e, 0xe8, 0xdb, 0x22, 0xc9, 0xb3, + 0xd1, 0xfe, 0xe2, 0xe9, 0x20, 0xda, 0xd4, 0x19, 0x21, 0xa4, 0xf1, 0xe1, 0x39, + 0x2f, 0x05, 0x23, 0xe4, 0xf4, 0x01, 0x12, 0x00, 0xec, 0x25, 0x1e, 0xa8, 0xf6, + 0xf8, 0xff, 0x0e, 0xd5, 0xc0, 0xcb, 0xc1, 0x33, 0x22, 0xc4, 0x1f, 0x0e, 0x05, + 0xed, 0xe1, 0x01, 0xe0, 0x11, 0xeb, 0x0a, 0xe0, 0x32, 0xd0, 0x70, 0xaf, 0x1b, + 0xf1, 0x07, 0x10, 0xf6, 0x02, 0xed, 0x3e, 0xd6, 0xa9, 0x11, 0xee, 0x1e, 0xe0, + 0xd1, 0xbc, 0xe8, 0x01, 0xe2, 0x1c, 0x3e, 0xa3, 0xd6, 0x8a, 0x0d, 0xdd, 0xe1, + 0x30, 0xed, 0x04, 0x15, 0xff, 0x24, 0xff, 0x1b, 0x81, 0xcd, 0xd5, 0x19, 0xe1, + 0x14, 0x33, 0x29, 0xdb, 0xdc, 0x38, 0xce, 0xf7, 0xd6, 0xd9, 0x23, 0xbb, 0x01, + 0xd4, 0xfc, 0xda, 0x48, 0xde, 0xd8, 0x37, 0xd4, 0x2b, 0xcd, 0x36, 0xe9, 0x14, + 0xf7, 0xfc, 0xcc, 0xe4, 0x25, 0xe8, 0xf3, 0x22, 0x3b, 0x0a, 0xc5, 0xce, 0xfb, + 0xef, 0x1c, 0x06, 0x19, 0x19, 0x0d, 0xfd, 0xe0, 0xf4, 0xed, 0x01, 0xef, 0x30, + 0xfe, 0xed, 0xe5, 0xfa, 0xe8, 0x1b, 0x0d, 0x2f, 0x04, 0xcd, 0xda, 0xca, 0xd8, + 0xed, 0x1a, 0x1a, 0x0f, 0x00, 0x04, 0xef, 0x7f, 0xff, 0xd3, 0xf8, 0xf4, 0x14, + 0xf0, 0x1f, 0xec, 0xcf, 0xff, 0xe9, 0x03, 0xa9, 0x17, 0x98, 0x24, 0x46, 0xcf, + 0xed, 0x14, 0xc9, 0x00, 0xd0, 0xd5, 0x36, 0xec, 0x3d, 0xd0, 0xff, 0xdd, 0x0d, + 0x30, 0x01, 0xd8, 0xd2, 0xbe, 0xee, 0xe6, 0x0a, 0xe7, 0xfb, 0x17, 0x1a, 0xe4, + 0xe6, 0x03, 0xb3, 0x25, 0x10, 0x27, 0xe3, 0x11, 0xd1, 0xc3, 0xc8, 0xda, 0xe5, + 0xf0, 0x0c, 0xf1, 0x13, 0xb3, 0xeb, 0xd5, 0xce, 0xb0, 0x18, 0x16, 0xe5, 0xf1, + 0xfa, 0xcf, 0xd0, 0xd1, 0xe4, 0xd5, 0xeb, 0xea, 0x14, 0x09, 0x29, 0xbf, 0x30, + 0xd5, 0xd7, 0x2a, 0x1a, 0xed, 0x1e, 0xe7, 0x19, 0x31, 0x2f, 0xce, 0xbe, 0xd9, + 0xeb, 0xf9, 0xd1, 0x0e, 0xe5, 0xdf, 0xfb, 0xc7, 0x02, 0xea, 0xf6, 0x29, 0x11, + 0xdd, 0x03, 0xdf, 0x21, 0x12, 0xf6, 0xe9, 0xf3, 0xfb, 0x16, 0x2d, 0xdd, 0xf8, + 0xdf, 0xe8, 0xd3, 0xfe, 0x24, 0xd1, 0xf7, 0xbf, 0xe5, 0xff, 0x1f, 0x27, 0xe1, + 0x00, 0xff, 0xd5, 0xb0, 0x1b, 0x17, 0xdc, 0xef, 0x1f, 0xd2, 0xf4, 0x0c, 0xf0, + 0xaf, 0xda, 0xf4, 0x0e, 0x22, 0x1f, 0x05, 0xe5, 0x19, 0x19, 0x22, 0x00, 0x13, + 0xde, 0x1c, 0xe8, 0x41, 0x17, 0xee, 0x48, 0xe4, 0xf3, 0xf1, 0xad, 0x1a, 0x1a, + 0xeb, 0x41, 0x35, 0x14, 0x0f, 0xd6, 0xe6, 0xde, 0xd2, 0x39, 0xc9, 0xf7, 0x0b, + 0xe4, 0xf0, 0x00, 0xd7, 0x09, 0xf1, 0xff, 0xca, 0xfa, 0xfb, 0x19, 0x0e, 0xf1, + 0x09, 0x24, 0xce, 0xe4, 0x1c, 0x10, 0xfb, 0xf7, 0xf0, 0xf2, 0x2b, 0xd7, 0xfc, + 0xe8, 0xe4, 0x07, 0xfe, 0xdc, 0xe8, 0x19, 0xef, 0xed, 0xff, 0x0d, 0xe1, 0xf7, + 0xd6, 0xf9, 0xed, 0x1b, 0x17, 0x0d, 0xf6, 0xeb, 0xf5, 0x0d, 0x0b, 0xe1, 0x0f, + 0xf8, 0xfc, 0xf7, 0xf7, 0xef, 0xdf, 0x12, 0x1b, 0x03, 0x06, 0xf8, 0x03, 0xf0, + 0xe0, 0xf2, 0xe7, 0x3b, 0xc8, 0x05, 0xef, 0x0c, 0xf8, 0x15, 0xe0, 0x2e, 0xe1, + 0xb6, 0xfa, 0xf0, 0x20, 0x08, 0xe2, 0xe5, 0x02, 0xe3, 0x0a, 0x00, 0x18, 0xd1, + 0x14, 0xe5, 0x00, 0x17, 0x13, 0xfa, 0x1b, 0xee, 0x19, 0xfd, 0xd9, 0xf5, 0xcc, + 0x03, 0xe6, 0x0b, 0xe2, 0x16, 0x1a, 0x15, 0xea, 0x0f, 0xdd, 0xd3, 0xf0, 0xf4, + 0x00, 0xc5, 0x04, 0x0b, 0x0e, 0xde, 0xdc, 0x1e, 0xe8, 0xe9, 0x43, 0x00, 0x11, + 0x0b, 0x25, 0xe0, 0xfc, 0x1f, 0xd7, 0x7f, 0xf7, 0x06, 0x15, 0x0c, 0x24, 0x41, + 0xf1, 0x1c, 0xf1, 0xfb, 0xe5, 0xcc, 0xcf, 0xf7, 0xd7, 0xe6, 0x05, 0xee, 0xee, + 0x2e, 0x1b, 0x1b, 0x0a, 0x28, 0x20, 0x0d, 0x06, 0xf5, 0x0a, 0x13, 0xed, 0x00, + 0x23, 0xc6, 0xd9, 0xf8, 0x1d, 0xe1, 0x11, 0xcc, 0xe9, 0xe3, 0xfe, 0x18, 0x0a, + 0xdf, 0xfb, 0xdc, 0x02, 0xed, 0xe8, 0x00, 0x19, 0x23, 0xda, 0x14, 0x0c, 0xe9, + 0x3e, 0xf1, 0x1c, 0x05, 0x1c, 0xdd, 0xf3, 0x19, 0x11, 0x05, 0x02, 0x04, 0xf0, + 0x02, 0xf7, 0xf9, 0xf4, 0x03, 0x00, 0xe2, 0xf7, 0x16, 0x07, 0x37, 0xdd, 0x09, + 0xfe, 0x1e, 0x27, 0xef, 0x14, 0xfa, 0xdf, 0xf0, 0xd4, 0xe5, 0x08, 0xeb, 0x26, + 0x33, 0x36, 0xe7, 0x18, 0xfa, 0xfc, 0x10, 0x13, 0x0c, 0xf5, 0xe5, 0xfb, 0xfe, + 0x1b, 0xc4, 0xe8, 0x04, 0xd1, 0x0e, 0x33, 0xee, 0x15, 0x0b, 0x12, 0xf3, 0xe8, + 0xd1, 0x00, 0x01, 0xe6, 0xd8, 0xd7, 0x01, 0xe5, 0x13, 0xfe, 0xf7, 0x0f, 0xee, + 0x18, 0x06, 0x07, 0xe8, 0xdf, 0x12, 0x17, 0xd3, 0xff, 0xfe, 0xe7, 0x15, 0x13, + 0xd1, 0xa8, 0xd0, 0xf2, 0x0a, 0xce, 0xfe, 0xfb, 0xf9, 0xd8, 0xcd, 0xf2, 0xf1, + 0x25, 0x0e, 0x1d, 0xc9, 0xeb, 0x2b, 0xf9, 0xf5, 0xf2, 0xf7, 0x32, 0xf9, 0x2b, + 0xef, 0x2b, 0x04, 0xf7, 0x21, 0x11, 0x1e, 0xf5, 0x3c, 0xfc, 0xc9, 0xb8, 0x3b, + 0x03, 0xb9, 0xb2, 0xec, 0xe8, 0xe9, 0x04, 0x18, 0xdf, 0xde, 0xc2, 0x26, 0x0e, + 0x0e, 0xf7, 0xd8, 0x40, 0x0d, 0xf1, 0x4e, 0xf2, 0xe9, 0xef, 0xf1, 0x13, 0x1d, + 0xf9, 0xe0, 0x1a, 0x10, 0x18, 0x12, 0xdd, 0x35, 0x35, 0xf9, 0x02, 0xde, 0xd2, + 0x2a, 0xf9, 0xdf, 0x01, 0xd5, 0xf3, 0xf5, 0x05, 0x08, 0xe5, 0x9e, 0x19, 0x0a, + 0x0c, 0x44, 0xeb, 0x32, 0xf1, 0x06, 0x51, 0xd6, 0xdd, 0xea, 0xf1, 0xd5, 0xd8, + 0xed, 0xfe, 0x7f, 0xd2, 0x07, 0x03, 0xd6, 0x14, 0x13, 0xd7, 0x0c, 0xdd, 0xe0, + 0xff, 0xaf, 0x1a, 0xfc, 0xd5, 0xca, 0xd0, 0xe7, 0xf3, 0xf6, 0xeb, 0xea, 0x10, + 0xf0, 0xfe, 0x10, 0xfb, 0xe9, 0x1a, 0xf8, 0xde, 0x0b, 0xf9, 0xb3, 0xc6, 0xf4, + 0xe8, 0x10, 0x1c, 0xd5, 0xee, 0xcf, 0x09, 0x01, 0xfc, 0xe9, 0xf0, 0xcd, 0x20, + 0xe5, 0x04, 0x0c, 0x04, 0x11, 0xec, 0xc2, 0x10, 0x1f, 0x17, 0xd1, 0xd6, 0x08, + 0x22, 0xf3, 0xf0, 0x34, 0x1e, 0x13, 0xfd, 0xdd, 0x18, 0xfb, 0x1f, 0xe0, 0x06, + 0x0c, 0xf3, 0x05, 0x03, 0xf3, 0x0e, 0x17, 0xfe, 0xde, 0x02, 0xea, 0x0e, 0xf0, + 0x22, 0xdc, 0xef, 0xc5, 0xeb, 0xf9, 0x0a, 0xf1, 0x05, 0xe9, 0x18, 0x12, 0xf2, + 0xf7, 0xea, 0x12, 0x2a, 0x33, 0xe0, 0xfd, 0xf1, 0x08, 0x24, 0xf7, 0xe5, 0xde, + 0xe1, 0x11, 0x35, 0x16, 0x16, 0x13, 0xf9, 0x1b, 0xda, 0xbb, 0xfd, 0xfe, 0xdf, + 0x0f, 0x0a, 0x40, 0xf8, 0xed, 0xea, 0xbb, 0xbe, 0xec, 0x05, 0xd7, 0x0f, 0x1b, + 0x24, 0xd5, 0x2b, 0xf2, 0x1b, 0xe4, 0xdc, 0x5e, 0xeb, 0xdb, 0x48, 0x3e, 0x0d, + 0xad, 0x26, 0xdc, 0xf2, 0xc6, 0xb5, 0x22, 0xa5, 0xc5, 0x2d, 0xc9, 0xcb, 0xe9, + 0x2e, 0x1f, 0xba, 0x81, 0xc7, 0xcd, 0xbb, 0x0c, 0xe5, 0xd6, 0xdd, 0xf5, 0xe7, + 0x17, 0x05, 0x0d, 0xf6, 0xd8, 0xf1, 0xc0, 0xff, 0xfc, 0xf2, 0xe5, 0xeb, 0xda, + 0x03, 0x0a, 0xfb, 0x48, 0xf9, 0xa7, 0xf5, 0xe7, 0xe8, 0x31, 0xd6, 0xd2, 0x2c, + 0xba, 0x4c, 0x19, 0xb7, 0x4d, 0x08, 0x0e, 0x1c, 0xce, 0xd6, 0xa6, 0xbe, 0xc2, + 0x07, 0xed, 0x32, 0xd7, 0xfc, 0xc9, 0xa6, 0x40, 0x1c, 0x05, 0xdb, 0x40, 0xd7, + 0x0a, 0x2a, 0xaf, 0x04, 0xf8, 0xff, 0x22, 0x27, 0xa1, 0xd8, 0xeb, 0xe4, 0xf0, + 0x04, 0xa8, 0xb2, 0x3d, 0xe3, 0x12, 0xe0, 0xb5, 0x2c, 0x0d, 0xe9, 0x30, 0xb4, + 0x26, 0x1d, 0xcc, 0x0c, 0xf8, 0xe2, 0x04, 0xa9, 0xee, 0xc3, 0xb6, 0xe7, 0xfa, + 0x3d, 0xb4, 0xe7, 0xcb, 0x35, 0x02, 0xde, 0x34, 0x3c, 0xea, 0xe6, 0x0a, 0xcc, + 0xfa, 0x00, 0x44, 0x03, 0xf6, 0xf2, 0xfb, 0xec, 0xce, 0x1a, 0x45, 0x35, 0xc4, + 0xd4, 0x26, 0xdf, 0xfe, 0xeb, 0x20, 0xe8, 0xfb, 0xd5, 0xc4, 0x3a, 0xf4, 0xfc, + 0x09, 0xe8, 0x3d, 0xe7, 0xd4, 0x22, 0xc2, 0xde, 0x16, 0xf8, 0x38, 0xf8, 0x1d, + 0x36, 0x31, 0x35, 0xfc, 0xc6, 0xfa, 0xda, 0x0e, 0xcf, 0xe8, 0xe4, 0xb9, 0xed, + 0xfa, 0x37, 0x18, 0x05, 0xbb, 0xd8, 0xee, 0x14, 0x0b, 0xe5, 0xec, 0xcc, 0xc9, + 0xf6, 0xd6, 0x08, 0xfc, 0x09, 0x2a, 0x08, 0xfd, 0xcd, 0xa2, 0x13, 0x36, 0x32, + 0x31, 0xf5, 0x0a, 0xef, 0xfb, 0x09, 0x17, 0x03, 0xd8, 0x2a, 0x05, 0xe7, 0x2a, + 0xdd, 0xef, 0xe8, 0xab, 0x0d, 0xd4, 0xcb, 0x29, 0x0d, 0xf9, 0xbf, 0x85, 0xfb, + 0x2a, 0xf8, 0x44, 0xdb, 0xa1, 0x24, 0xe2, 0xfe, 0xe0, 0x3a, 0x09, 0xf0, 0x08, + 0xa1, 0xf9, 0x2c, 0x10, 0xdc, 0xf0, 0xec, 0xe8, 0xf8, 0x54, 0x01, 0x1e, 0xb0, + 0x44, 0xf9, 0x0a, 0x3a, 0x29, 0xea, 0xe3, 0xee, 0x5f, 0x22, 0x5b, 0xfe, 0xdd, + 0x89, 0x0c, 0xb2, 0xda, 0x96, 0x99, 0xf4, 0xec, 0x05, 0xc8, 0xf9, 0xdf, 0xf8, + 0xd0, 0x0e, 0xca, 0x9d, 0x38, 0x0b, 0x20, 0x35, 0xf5, 0xf9, 0x2b, 0xcb, 0xef, + 0x26, 0xe3, 0xea, 0x45, 0x23, 0xa2, 0xb7, 0xe1, 0x1c, 0x1d, 0xe1, 0xda, 0x33, + 0xc6, 0x09, 0x1b, 0x4c, 0xc7, 0xd1, 0xb7, 0xf3, 0xa5, 0x36, 0x5a, 0xef, 0x05, + 0xfb, 0x9f, 0xbf, 0x5f, 0x17, 0x84, 0xde, 0xf7, 0xf3, 0x4f, 0xc6, 0x31, 0x25, + 0x27, 0xe3, 0x04, 0xe3, 0x15, 0xa5, 0xeb, 0xbe, 0xe7, 0x0b, 0x3d, 0xcc, 0xe3, + 0x18, 0xb5, 0x21, 0x5f, 0x09, 0xf8, 0xd2, 0xc6, 0xc4, 0x29, 0x18, 0xc2, 0x3c, + 0x32, 0x26, 0xe6, 0x18, 0x36, 0xf5, 0x31, 0xcd, 0xe0, 0x21, 0x6b, 0xef, 0x5c, + 0xca, 0xfd, 0xca, 0x28, 0xc4, 0x01, 0xf7, 0x40, 0xe1, 0xe7, 0xee, 0xdd, 0x11, + 0xc6, 0x08, 0x8d, 0xbe, 0xb8, 0x57, 0x3b, 0xc2, 0xf9, 0xe1, 0xec, 0x3d, 0x32, + 0xa9, 0xc1, 0x2f, 0x3c, 0x10, 0xc5, 0x0b, 0x0d, 0x0c, 0x08, 0xbe, 0xda, 0xf1, + 0xff, 0xcd, 0x00, 0x44, 0x03, 0x59, 0xae, 0x0d, 0x18, 0xdf, 0xf3, 0x7f, 0xf1, + 0x02, 0x5d, 0x05, 0xf9, 0xea, 0xfa, 0x91, 0x1e, 0x0d, 0xf9, 0xf3, 0x33, 0x46, + 0xfc, 0xfc, 0x5a, 0xcc, 0x42, 0x39, 0xe7, 0xc3, 0xb9, 0xec, 0xce, 0x9a, 0x38, + 0xb5, 0xea, 0xc2, 0xc8, 0x24, 0x2c, 0xcc, 0x14, 0xac, 0xe2, 0xc8, 0x33, 0xb5, + 0xf2, 0xa0, 0xee, 0xdd, 0x2a, 0x97, 0xef, 0x22, 0xda, 0x5d, 0x2d, 0x4e, 0x07, + 0xdb, 0xc6, 0xb9, 0xe9, 0xa7, 0x00, 0xf4, 0xc4, 0xd4, 0xb6, 0xef, 0xdd, 0xe8, + 0xef, 0xee, 0x9d, 0xeb, 0xde, 0xec, 0xc9, 0xe7, 0xf7, 0xcb, 0xb8, 0xc2, 0x0f, + 0xfc, 0xec, 0xfa, 0xda, 0x89, 0x05, 0x3e, 0xc0, 0x29, 0xf7, 0x14, 0xe2, 0xf1, + 0xda, 0xd3, 0xe5, 0xdd, 0x0a, 0xf6, 0x16, 0x03, 0xeb, 0xed, 0x39, 0x34, 0xb8, + 0xe7, 0xf2, 0x1f, 0xb9, 0xed, 0xb5, 0xe4, 0x18, 0x35, 0xf8, 0x1b, 0xd6, 0x20, + 0x48, 0x2f, 0x06, 0xaa, 0xd7, 0x1d, 0xd8, 0x06, 0x09, 0xca, 0xdf, 0x1d, 0x28, + 0x07, 0x11, 0xf5, 0x0c, 0xf5, 0x8a, 0xe9, 0x19, 0xc6, 0xcd, 0xf6, 0xc1, 0xe9, + 0x0a, 0xfd, 0x38, 0xe2, 0xde, 0x08, 0xd1, 0xd2, 0xe7, 0x10, 0xfd, 0x16, 0xdf, + 0x50, 0x81, 0x1f, 0xd4, 0x03, 0xbe, 0x50, 0x12, 0xd1, 0xe4, 0xdd, 0xe3, 0x1a, + 0x1a, 0xe0, 0xd1, 0xdb, 0xe1, 0xbe, 0x05, 0xf5, 0x9c, 0x10, 0x02, 0x0c, 0x1a, + 0xd4, 0x27, 0xf3, 0xd2, 0x32, 0x88, 0x0e, 0x23, 0x14, 0x58, 0xfa, 0xf8, 0xf3, + 0xe2, 0x32, 0xe1, 0xdd, 0xe5, 0x00, 0xb8, 0x24, 0xee, 0x39, 0xab, 0xf8, 0xd4, + 0xf4, 0x57, 0xd8, 0xc5, 0xf7, 0x49, 0x2f, 0x4a, 0xe5, 0xf7, 0xea, 0xfa, 0xec, + 0x39, 0x27, 0xc6, 0xc8, 0x1f, 0xeb, 0xd5, 0x53, 0xf7, 0x60, 0xe4, 0xe3, 0x39, + 0xbc, 0xd1, 0xab, 0x1f, 0x1e, 0x0d, 0xd7, 0x1c, 0x51, 0xc6, 0xc3, 0x21, 0xc2, + 0xd0, 0x14, 0xbd, 0xc8, 0xb0, 0xc4, 0x0e, 0xeb, 0x4b, 0x0b, 0xf0, 0xe7, 0xee, + 0xe9, 0x63, 0xda, 0xe8, 0x2a, 0xf8, 0xd6, 0xde, 0x19, 0x22, 0xe0, 0xb8, 0xfd, + 0xee, 0xd4, 0xfb, 0xda, 0x47, 0xc7, 0x50, 0x14, 0xe2, 0xd7, 0x18, 0x05, 0xd4, + 0xfd, 0x9f, 0x06, 0xee, 0xf1, 0xe1, 0xce, 0x40, 0x2f, 0xff, 0x0c, 0x19, 0xf1, + 0x29, 0xbb, 0xc6, 0xd7, 0xee, 0xb4, 0xe9, 0xc1, 0xe2, 0xfd, 0x08, 0xb4, 0x32, + 0xdd, 0x16, 0xe1, 0x21, 0x97, 0xd0, 0xf6, 0x03, 0xe0, 0xbc, 0xd7, 0x96, 0x48, + 0xe0, 0xfb, 0xd8, 0xe4, 0xe2, 0x06, 0xd6, 0x11, 0xe7, 0xd5, 0x92, 0x32, 0xfc, + 0xef, 0xd4, 0xe6, 0x42, 0x19, 0xce, 0x09, 0x16, 0xcb, 0xae, 0x0a, 0xe2, 0x33, + 0x0d, 0xa2, 0x33, 0x00, 0xe0, 0x0e, 0xd0, 0x4c, 0x15, 0xe7, 0x3f, 0xdb, 0x1a, + 0x33, 0x38, 0xc8, 0xfb, 0xc1, 0xfa, 0x04, 0x17, 0x27, 0x3f, 0x12, 0xb4, 0x18, + 0xf4, 0x05, 0xe8, 0x0b, 0x1c, 0xa8, 0xe7, 0xde, 0x04, 0xb8, 0xf0, 0x00, 0xc5, + 0x10, 0xd7, 0xd3, 0xb8, 0x28, 0x37, 0xf7, 0x2f, 0xde, 0x05, 0xa7, 0xe8, 0xa9, + 0x15, 0xf2, 0x06, 0xb7, 0xf3, 0xc3, 0xc1, 0x21, 0x0e, 0x0b, 0x2a, 0xeb, 0x05, + 0xfe, 0x11, 0xd0, 0xf5, 0x00, 0xc7, 0x30, 0xe4, 0x15, 0x2c, 0x00, 0x0f, 0x95, + 0xd8, 0x1e, 0xe8, 0x26, 0x13, 0xd8, 0xcf, 0xde, 0xcc, 0x3e, 0xcd, 0x9d, 0x15, + 0x4d, 0x54, 0x3f, 0xac, 0xed, 0x3f, 0xce, 0xb0, 0x21, 0x47, 0xdd, 0x31, 0x81, + 0xf0, 0x1e, 0x07, 0xc9, 0x29, 0x04, 0xd3, 0x3f, 0xff, 0xef, 0xb1, 0x1a, 0x05, + 0xfb, 0x32, 0xf2, 0xfe, 0xe2, 0x1b, 0x08, 0xaf, 0xb6, 0xa9, 0xeb, 0xba, 0x16, + 0x41, 0xbc, 0xaf, 0xdb, 0xdf, 0x16, 0x1c, 0x32, 0x2d, 0x19, 0xd4, 0xc4, 0x4c, + 0xb9, 0xba, 0xdf, 0x30, 0xc1, 0x93, 0xce, 0x03, 0xac, 0xdb, 0xef, 0xff, 0xf1, + 0x4a, 0x49, 0xca, 0xfc, 0xeb, 0xbd, 0x09, 0x20, 0x2f, 0x06, 0x3f, 0xfd, 0x3b, + 0x1c, 0x29, 0xf4, 0x11, 0x16, 0x0b, 0xd8, 0xef, 0x32, 0x08, 0xfa, 0x4d, 0xe1, + 0x3a, 0xbc, 0x50, 0xeb, 0x38, 0x07, 0xf2, 0x13, 0xbb, 0xd2, 0xac, 0x4f, 0x5f, + 0x09, 0x26, 0xfa, 0xee, 0xea, 0x3c, 0xda, 0x0f, 0x54, 0xe7, 0x07, 0x09, 0xed, + 0xda, 0x33, 0x20, 0x2c, 0x33, 0xcd, 0xf4, 0x3f, 0xbe, 0xf3, 0xbe, 0xa8, 0xc1, + 0xbb, 0x12, 0xfe, 0x00, 0x02, 0xc0, 0x25, 0x0a, 0xda, 0xa8, 0xdc, 0x24, 0x0a, + 0xc7, 0xef, 0xd1, 0xf2, 0xed, 0xc1, 0x0d, 0xe2, 0x8d, 0x02, 0xeb, 0x07, 0xf7, + 0xde, 0xf1, 0xcd, 0x20, 0x26, 0x1e, 0xd2, 0xf9, 0xa7, 0xb7, 0xef, 0x01, 0xce, + 0xb8, 0xaf, 0xbc, 0xd8, 0xf5, 0x4d, 0xe3, 0xd0, 0xa3, 0xc6, 0x1e, 0x02, 0xd4, + 0x00, 0x10, 0xde, 0xd5, 0xed, 0xfe, 0xdb, 0xd5, 0xfa, 0x0d, 0x23, 0x54, 0xf9, + 0xfe, 0xd0, 0xdb, 0xa8, 0x1f, 0x0a, 0xa1, 0x04, 0xef, 0x4e, 0x03, 0x19, 0xf2, + 0xec, 0xbd, 0x20, 0xbb, 0xe6, 0xf7, 0x1b, 0xbe, 0xe9, 0x14, 0xf9, 0xdc, 0xf2, + 0xe5, 0xf7, 0xf1, 0xe8, 0xb8, 0xe9, 0xe3, 0xee, 0xf4, 0x28, 0x0b, 0x9f, 0xe3, + 0xff, 0x22, 0xd2, 0x98, 0x81, 0x16, 0xed, 0xf3, 0x9f, 0x15, 0xfd, 0x11, 0x1a, + 0xda, 0xea, 0xb5, 0xf2, 0x9d, 0x08, 0x37, 0xb9, 0x22, 0xbc, 0x11, 0x21, 0xee, + 0x1a, 0x2c, 0xca, 0x01, 0xdd, 0xfe, 0xd8, 0xf6, 0xa5, 0x05, 0xc7, 0x9b, 0xf7, + 0xe2, 0xa9, 0xd6, 0x11, 0xc0, 0xf7, 0x11, 0xfa, 0x1e, 0xde, 0xc9, 0x27, 0x13, + 0xf4, 0xee, 0x1c, 0xbd, 0x06, 0xf5, 0xde, 0x27, 0xbf, 0x11, 0xcf, 0xc7, 0x53, + 0x1c, 0x17, 0xe1, 0xf4, 0xfa, 0x35, 0xce, 0xe0, 0x06, 0xeb, 0x27, 0xed, 0xc1, + 0xdc, 0x18, 0xf4, 0xa7, 0xde, 0x12, 0xd9, 0x09, 0xe0, 0x28, 0xcf, 0xdc, 0x11, + 0x12, 0x03, 0x2f, 0x30, 0xcf, 0xfa, 0x11, 0xc7, 0xe5, 0x40, 0x07, 0xeb, 0x37, + 0xde, 0xc0, 0x26, 0x10, 0xca, 0x3d, 0xe3, 0xe8, 0xe9, 0xf1, 0x04, 0xe2, 0xe9, + 0x09, 0x30, 0x20, 0x15, 0x11, 0xc7, 0xed, 0xe0, 0x06, 0x1c, 0xdf, 0x1d, 0xea, + 0xd7, 0x18, 0x01, 0xd8, 0x99, 0xf3, 0x05, 0x19, 0x0e, 0x1b, 0x3e, 0xbf, 0x29, + 0x6e, 0xcc, 0x0b, 0x2a, 0xf6, 0xa3, 0xee, 0x8f, 0x18, 0xbb, 0xfe, 0xb0, 0xce, + 0x28, 0xbf, 0x1e, 0x01, 0x0e, 0xeb, 0x24, 0xef, 0xfb, 0xb4, 0x11, 0x67, 0xd6, + 0xec, 0xa1, 0x01, 0x90, 0x41, 0x4f, 0xc0, 0x0a, 0x1f, 0xab, 0xe4, 0xf2, 0xdc, + 0xec, 0x09, 0x12, 0x97, 0x04, 0x22, 0xf2, 0x2d, 0x20, 0x15, 0x9f, 0xc4, 0x15, + 0x2f, 0xf5, 0x11, 0xfe, 0x1e, 0x05, 0x4e, 0x08, 0x0c, 0x19, 0x38, 0xf1, 0xce, + 0x1c, 0x20, 0xc2, 0xb7, 0xd2, 0xdc, 0xf6, 0x13, 0xfb, 0xaa, 0xde, 0x24, 0x2b, + 0x04, 0xb0, 0xc4, 0x23, 0x9b, 0xb3, 0xe6, 0x8d, 0xc3, 0xd6, 0xd7, 0x37, 0x2a, + 0xd2, 0x37, 0xda, 0x81, 0xea, 0x25, 0x2b, 0xce, 0x08, 0x07, 0xf0, 0x3a, 0xe3, + 0x1e, 0xa9, 0xe7, 0xf1, 0xed, 0x1a, 0xa8, 0x21, 0xe2, 0xe9, 0xd4, 0xc2, 0xd5, + 0x15, 0x45, 0xdf, 0x38, 0xcf, 0x3b, 0x1f, 0xe4, 0x24, 0x43, 0xe4, 0x07, 0xcc, + 0xca, 0xfe, 0xe8, 0x10, 0x30, 0xc0, 0xc0, 0x31, 0x9c, 0xf9, 0xdf, 0xd5, 0xd2, + 0x07, 0x2f, 0xfc, 0xff, 0x0e, 0xe0, 0x06, 0x20, 0xb3, 0x19, 0xf9, 0x20, 0xae, + 0xe3, 0xfa, 0xd5, 0x0b, 0x25, 0x2d, 0xc6, 0xe9, 0x06, 0x36, 0xce, 0xf6, 0x17, + 0xf5, 0xde, 0x25, 0xee, 0x25, 0xd1, 0xe4, 0xe1, 0x33, 0xfa, 0xeb, 0x05, 0x55, + 0xce, 0x0c, 0xf8, 0xb5, 0xeb, 0x00, 0x65, 0x0b, 0x0b, 0x32, 0xab, 0x02, 0xab, + 0x0f, 0xfb, 0xd6, 0xf3, 0xba, 0xd8, 0xf7, 0x25, 0xb2, 0x46, 0x3b, 0xff, 0xc6, + 0xbd, 0x0b, 0x16, 0xce, 0xf2, 0xed, 0xb2, 0xf4, 0xf3, 0xf9, 0xe8, 0xe9, 0xb5, + 0xe1, 0x9d, 0xff, 0xf0, 0xed, 0xd2, 0x18, 0xfd, 0xeb, 0xc7, 0xf6, 0x3f, 0x0c, + 0xdc, 0xe8, 0x0d, 0x2b, 0xd0, 0x64, 0x15, 0x10, 0xcf, 0x05, 0xdc, 0xe0, 0xcf, + 0xda, 0xdd, 0x24, 0xd2, 0x40, 0x07, 0xb1, 0x41, 0x02, 0xe4, 0xca, 0x07, 0x23, + 0x2f, 0xbf, 0xf0, 0xcb, 0xc0, 0x00, 0xba, 0xee, 0xe2, 0xc7, 0x14, 0xca, 0x3f, + 0xf5, 0xba, 0xdd, 0xf2, 0xfc, 0x28, 0xa4, 0x09, 0xbc, 0xe5, 0x2c, 0x22, 0x57, + 0x25, 0x40, 0x20, 0xab, 0xdf, 0x01, 0x2d, 0x08, 0xa4, 0xde, 0x1a, 0x0f, 0xe9, + 0xc3, 0x1a, 0x41, 0xc1, 0xe4, 0xb9, 0xeb, 0x0d, 0xd7, 0xb6, 0x04, 0x08, 0x47, + 0xed, 0x0d, 0x32, 0x2a, 0x25, 0xe3, 0x10, 0xe2, 0xb9, 0xb3, 0xd2, 0x0d, 0x3a, + 0x2c, 0xe4, 0xef, 0x39, 0x9c, 0xcb, 0xbe, 0xf1, 0x23, 0x60, 0x02, 0x4a, 0xd1, + 0xbe, 0xd9, 0xa9, 0x2a, 0x1e, 0x0f, 0xb4, 0x02, 0x03, 0xdf, 0xd2, 0x23, 0xa7, + 0xcf, 0x1e, 0x32, 0x16, 0x09, 0xfe, 0x1d, 0xe6, 0x19, 0xd7, 0xb9, 0xd1, 0xc4, + 0x51, 0xbc, 0x13, 0x16, 0xf4, 0x4e, 0xf0, 0xcb, 0xff, 0xeb, 0xdd, 0x03, 0xf4, + 0x12, 0x25, 0x40, 0xde, 0x47, 0xf7, 0xe1, 0xdf, 0x45, 0xf6, 0x26, 0xa7, 0xeb, + 0xe6, 0xee, 0x0a, 0xed, 0xed, 0xfb, 0x32, 0xc4, 0x45, 0x33, 0xd2, 0x26, 0xeb, + 0x1e, 0x09, 0x2a, 0xde, 0x3f, 0xcc, 0x44, 0xe5, 0x27, 0xb6, 0x50, 0xb2, 0x03, + 0xf4, 0x16, 0xc7, 0xc2, 0xdc, 0xd3, 0x05, 0x35, 0x14, 0x4e, 0xd6, 0xd5, 0x4f, + 0x0d, 0xcd, 0x1b, 0xfe, 0x68, 0xe5, 0xce, 0x0c, 0x1b, 0xe4, 0xea, 0xc0, 0xfd, + 0xcb, 0x79, 0x0a, 0x9b, 0x40, 0xe2, 0xfd, 0xa4, 0xbc, 0xc3, 0x21, 0x51, 0x48, + 0xa2, 0x06, 0x91, 0x00, 0xe1, 0xfa, 0x37, 0x09, 0xdc, 0x3d, 0x00, 0xcd, 0x7f, + 0xf7, 0x43, 0x1c, 0xe4, 0x1c, 0xfc, 0x4a, 0x21, 0xb2, 0xdb, 0x04, 0x21, 0xcf, + 0x00, 0xa6, 0xe4, 0x29, 0x17, 0x2a, 0xde, 0x22, 0x47, 0xf1, 0x17, 0xe5, 0x03, + 0xd3, 0xc5, 0xce, 0xfc, 0xd9, 0xe8, 0xd8, 0xf1, 0xc2, 0x2f, 0x08, 0x47, 0xf3, + 0xc4, 0x04, 0xea, 0xd3, 0xb4, 0x33, 0xe2, 0xee, 0xc5, 0xe5, 0x19, 0xf2, 0xff, + 0xc1, 0xfb, 0xd7, 0x1e, 0xe7, 0xd2, 0x03, 0xd8, 0xd9, 0xea, 0xb0, 0xfa, 0x1f, + 0x43, 0xe8, 0xe1, 0x2e, 0x15, 0x24, 0xe5, 0xc4, 0x1b, 0xd9, 0x0d, 0x1b, 0xe3, + 0xeb, 0x0c, 0xcc, 0xe1, 0x46, 0xfc, 0xde, 0x0e, 0x0a, 0x0b, 0xd2, 0x10, 0xda, + 0x0f, 0xec, 0x0a, 0xf9, 0xe1, 0xdf, 0x14, 0xea, 0x22, 0x45, 0xf0, 0x22, 0x15, + 0xc6, 0x04, 0xfd, 0x0c, 0x2e, 0x01, 0xdc, 0x05, 0xba, 0xf3, 0xe3, 0x04, 0x1c, + 0xde, 0xf7, 0xd8, 0x13, 0xfa, 0xd6, 0xec, 0x1b, 0x15, 0xfa, 0xcf, 0xe6, 0xdd, + 0x22, 0x03, 0xf4, 0xd7, 0x1f, 0xf3, 0xe2, 0xfe, 0x02, 0x2e, 0xf7, 0xdb, 0xf6, + 0xf9, 0xfb, 0x17, 0xed, 0x1a, 0xf0, 0xed, 0xc6, 0xf7, 0x18, 0xad, 0x29, 0xfb, + 0x04, 0xf0, 0x35, 0x0b, 0xd0, 0x0d, 0x02, 0x17, 0x09, 0xf6, 0xfd, 0x0d, 0xac, + 0xdf, 0x18, 0xd5, 0xcf, 0xd9, 0xce, 0x3d, 0xf8, 0xeb, 0xff, 0x12, 0xb1, 0x15, + 0x01, 0xf9, 0x1a, 0x10, 0xeb, 0xf5, 0x1f, 0x05, 0x0e, 0xfd, 0xfd, 0x12, 0x09, + 0x27, 0xcd, 0x11, 0x0d, 0x35, 0xa3, 0xda, 0xc4, 0xde, 0xee, 0x03, 0xf7, 0x1b, + 0x26, 0x0d, 0x18, 0x2c, 0x06, 0xb9, 0xef, 0x2b, 0xe6, 0x0a, 0xee, 0x0c, 0xed, + 0x79, 0xe3, 0x16, 0x47, 0xf1, 0xfe, 0xde, 0xf2, 0xe5, 0x05, 0xd4, 0xde, 0xec, + 0x44, 0xc9, 0xd1, 0x2f, 0x07, 0xf6, 0x17, 0x1b, 0xd9, 0xdd, 0xed, 0x3a, 0x35, + 0x2a, 0x3e, 0x08, 0x08, 0xaa, 0xef, 0xeb, 0xa6, 0x7f, 0xf1, 0x57, 0x26, 0x29, + 0xe0, 0x0e, 0x33, 0xcf, 0x29, 0xdf, 0xd8, 0xed, 0x18, 0xf2, 0x07, 0x08, 0x28, + 0xd4, 0xde, 0xd7, 0xd4, 0x0b, 0xc2, 0xcf, 0xf3, 0x2e, 0x0b, 0xb3, 0x95, 0x1f, + 0x1f, 0x23, 0x02, 0x0c, 0x19, 0xf5, 0xe6, 0xfd, 0xb9, 0x12, 0xe6, 0x13, 0x13, + 0x35, 0x38, 0x20, 0x1a, 0xe6, 0xf4, 0x32, 0x50, 0xc3, 0x04, 0xb5, 0xdf, 0xe1, + 0xf4, 0xf5, 0xdb, 0x42, 0xfb, 0xeb, 0xf2, 0xb8, 0x20, 0xe7, 0x25, 0x06, 0xee, + 0x33, 0x12, 0xdd, 0x01, 0xef, 0x0f, 0x1f, 0xf2, 0xcc, 0xf9, 0x10, 0xe7, 0xc3, + 0x9e, 0xe1, 0x19, 0x2a, 0xf5, 0x0c, 0xde, 0xc8, 0xda, 0xf4, 0xb0, 0xec, 0x09, + 0x1a, 0x02, 0xab, 0x5e, 0xce, 0x0e, 0x2d, 0xfb, 0xee, 0x1b, 0xf2, 0x3d, 0x51, + 0xde, 0xbf, 0x24, 0xe0, 0x3a, 0xa9, 0x27, 0xaa, 0xce, 0xb3, 0xf7, 0xcd, 0xf8, + 0xa7, 0xf6, 0xf3, 0xe1, 0x1e, 0x3a, 0x36, 0xc2, 0xb4, 0xfb, 0x41, 0x51, 0x0e, + 0x17, 0x27, 0x00, 0x14, 0xf0, 0xe2, 0xc9, 0xcc, 0xf6, 0xcd, 0xf0, 0xcb, 0x2f, + 0xb6, 0x06, 0x29, 0xe6, 0xba, 0xf5, 0xed, 0xe1, 0xdb, 0x49, 0xfa, 0xfd, 0xfe, + 0x03, 0xff, 0x07, 0xf9, 0x33, 0xc7, 0xfd, 0x1c, 0x4c, 0x93, 0x0b, 0xeb, 0xbd, + 0xda, 0xf3, 0x1a, 0xfb, 0x3d, 0x13, 0x2d, 0x3a, 0x2e, 0x3b, 0xc7, 0x9b, 0x1b, + 0xe5, 0xec, 0x0c, 0x11, 0xdf, 0xee, 0xef, 0xce, 0x20, 0x18, 0x3e, 0xe9, 0xf9, + 0x22, 0x15, 0x04, 0xfe, 0x09, 0x00, 0x10, 0xfe, 0xf1, 0x2e, 0xf6, 0xbe, 0x3c, + 0xb7, 0xd6, 0xe2, 0x08, 0x24, 0x36, 0xf3, 0x05, 0x17, 0x47, 0xdd, 0xf9, 0xf0, + 0xff, 0xf3, 0x4a, 0xea, 0xee, 0xe1, 0x03, 0x26, 0x95, 0xc4, 0x3c, 0x44, 0x2c, + 0xd3, 0xeb, 0xb8, 0x67, 0x0d, 0x25, 0x3d, 0xbc, 0x19, 0x3e, 0xfa, 0xdb, 0xd8, + 0x7f, 0x25, 0xa0, 0x28, 0x13, 0x34, 0xef, 0xd3, 0x23, 0xec, 0xbf, 0xc4, 0x09, + 0xcf, 0x3f, 0xca, 0x02, 0xf4, 0xc1, 0xde, 0xb7, 0xfd, 0xb9, 0x0e, 0xfd, 0xf8, + 0x09, 0xdd, 0xfb, 0xb3, 0xe8, 0x2d, 0x29, 0x27, 0xf3, 0xf6, 0xfc, 0xec, 0x13, + 0x08, 0xfe, 0xf1, 0x17, 0x06, 0xc5, 0x11, 0xf5, 0xf2, 0x1d, 0x25, 0xe0, 0xd6, + 0x01, 0x00, 0x1b, 0xbc, 0x05, 0x2f, 0xbf, 0x16, 0x16, 0x2e, 0xc6, 0xfa, 0xb4, + 0x5a, 0x43, 0xaa, 0xdd, 0xf2, 0xf2, 0xd6, 0xa1, 0xef, 0x0d, 0xcc, 0xca, 0xe0, + 0x57, 0xec, 0x9d, 0xd2, 0x3c, 0xd4, 0xf2, 0xc6, 0xfc, 0xbe, 0xb2, 0x11, 0xbc, + 0xdc, 0xef, 0x3b, 0xe1, 0x23, 0xc6, 0x0c, 0xd9, 0x15, 0x05, 0xf1, 0x54, 0x34, + 0xf9, 0xaa, 0xf3, 0xf4, 0x98, 0xda, 0x21, 0x22, 0xdd, 0xf7, 0x17, 0x11, 0x4b, + 0xed, 0x05, 0xf0, 0xf4, 0x41, 0xd1, 0xa8, 0x0f, 0x08, 0x1b, 0x16, 0x04, 0x9c, + 0xff, 0x18, 0xf1, 0xbe, 0x3d, 0x0b, 0xcd, 0xbf, 0xa7, 0xe2, 0x2c, 0xec, 0x0d, + 0xf5, 0xc9, 0xf3, 0x00, 0x07, 0x0b, 0xd1, 0x9f, 0x42, 0x21, 0xcf, 0xed, 0xfa, + 0xf7, 0x14, 0x0a, 0xcf, 0xc6, 0x31, 0x0e, 0xd1, 0xd0, 0x4d, 0xbb, 0xe9, 0xe0, + 0x3d, 0xd4, 0xcb, 0x21, 0xfa, 0xd9, 0x2f, 0xb4, 0xd3, 0xe5, 0x14, 0x03, 0xa4, + 0xda, 0x17, 0x18, 0x3a, 0xf1, 0xfc, 0xb6, 0x2b, 0x21, 0xde, 0x1b, 0xaf, 0xf0, + 0xe3, 0xd0, 0xdb, 0xf2, 0x15, 0xce, 0x24, 0x19, 0xc4, 0xf7, 0x0d, 0x11, 0xf7, + 0xff, 0xfa, 0xc8, 0xa5, 0x19, 0xde, 0xe8, 0xd6, 0x05, 0x0a, 0x1d, 0x12, 0xfd, + 0xed, 0xc5, 0x2a, 0xc1, 0xc6, 0xbc, 0xc8, 0x04, 0x81, 0x4c, 0x2a, 0xe9, 0xac, + 0xfa, 0x25, 0x40, 0xeb, 0xf2, 0xf4, 0xce, 0x1a, 0xd1, 0xcb, 0xee, 0xe0, 0xc3, + 0x1e, 0xd5, 0xca, 0x0d, 0xf6, 0x3b, 0x3b, 0xf5, 0x1f, 0xe2, 0x2e, 0x35, 0x3a, + 0x3c, 0xb7, 0xd6, 0x0a, 0xd3, 0xe4, 0x47, 0x13, 0x38, 0x09, 0xde, 0xd3, 0x0b, + 0x05, 0xe7, 0xe7, 0x25, 0x17, 0x27, 0x19, 0x17, 0xce, 0xf3, 0x22, 0xbd, 0xec, + 0xee, 0xca, 0x5a, 0xf8, 0xeb, 0x22, 0xeb, 0xe3, 0x34, 0xf9, 0x18, 0xcc, 0xbd, + 0x0b, 0x01, 0xfa, 0x15, 0xce, 0x08, 0x39, 0xaf, 0xe9, 0x2a, 0x22, 0x3d, 0xe7, + 0xd4, 0x23, 0xdc, 0xdd, 0x12, 0xdc, 0x28, 0xbd, 0xde, 0x09, 0xdd, 0xee, 0x52, + 0xff, 0x21, 0xc0, 0xcb, 0xd7, 0x34, 0xfa, 0xee, 0xf3, 0x2e, 0x0a, 0x1e, 0x0a, + 0xd5, 0x2b, 0xcd, 0xe6, 0x16, 0x34, 0x04, 0xf2, 0x36, 0xed, 0x1b, 0xce, 0xd2, + 0x42, 0x04, 0xd9, 0xe2, 0x71, 0xd2, 0x00, 0xf0, 0xfb, 0xd7, 0x2a, 0x40, 0x11, + 0xe0, 0x1e, 0xfe, 0x01, 0x09, 0x34, 0xb8, 0x26, 0xc1, 0xfc, 0x9d, 0x00, 0xf0, + 0xeb, 0x11, 0x04, 0xd9, 0x9b, 0x21, 0xf3, 0x02, 0xd6, 0x06, 0xeb, 0x3c, 0xea, + 0xbb, 0xfc, 0xde, 0x12, 0x0a, 0x0c, 0x62, 0xde, 0xe3, 0xe2, 0xda, 0x19, 0xfc, + 0xe0, 0xe7, 0x40, 0xe1, 0xd2, 0x8d, 0xa4, 0xf4, 0xe3, 0x02, 0xe0, 0xd1, 0x39, + 0xd0, 0x1d, 0xed, 0xca, 0xe0, 0x11, 0x87, 0xe2, 0xd1, 0xd9, 0xb5, 0xea, 0xa3, + 0x35, 0xfe, 0x12, 0xef, 0x09, 0x37, 0x33, 0xeb, 0xf5, 0xf7, 0xe2, 0xcc, 0xf5, + 0x2b, 0xc1, 0xfa, 0xd2, 0xe6, 0x02, 0xf7, 0xc8, 0xe9, 0x7f, 0xc4, 0x5f, 0x2c, + 0x0e, 0xfc, 0x2f, 0xea, 0xad, 0x1c, 0xdd, 0xf8, 0xd1, 0xfa, 0x09, 0xb0, 0xae, + 0xd9, 0xc6, 0xde, 0x04, 0xfc, 0xe4, 0x0d, 0xef, 0xce, 0x1b, 0x11, 0x21, 0xfa, + 0xca, 0x4b, 0x1e, 0x10, 0xf1, 0x1d, 0x3c, 0xbf, 0xd1, 0xe5, 0xd6, 0x0d, 0x18, + 0xdc, 0x13, 0x10, 0xee, 0x4f, 0x0b, 0x07, 0xf3, 0x08, 0xde, 0x30, 0xd4, 0x3a, + 0x4c, 0x19, 0xac, 0xfb, 0xe1, 0x2b, 0x23, 0xde, 0x1d, 0x1d, 0x27, 0x12, 0xe4, + 0x0e, 0xe8, 0x61, 0xcb, 0xa1, 0x03, 0xe6, 0x97, 0x44, 0xab, 0x07, 0xb4, 0xef, + 0xda, 0xdc, 0x0a, 0xe7, 0xec, 0xd8, 0x1e, 0xb6, 0x2f, 0xdf, 0x13, 0xcd, 0x37, + 0x03, 0x0c, 0x1e, 0xde, 0x9a, 0x0e, 0x11, 0x2b, 0xf5, 0xdd, 0xe0, 0xd2, 0x1d, + 0xbd, 0x01, 0x0e, 0xfd, 0xdc, 0xf5, 0x0a, 0xca, 0x33, 0xe1, 0x0b, 0xf1, 0xf8, + 0x2e, 0xa5, 0x1d, 0xe7, 0x4c, 0x01, 0x33, 0x18, 0x2a, 0xc9, 0xe8, 0x04, 0xd8, + 0x1f, 0xde, 0x00, 0x44, 0xbd, 0xd9, 0xc7, 0x11, 0xf0, 0xd6, 0x32, 0xcf, 0x13, + 0x9a, 0xdd, 0xd9, 0xc7, 0xf4, 0xf2, 0xbb, 0xc5, 0xf0, 0x01, 0x00, 0x81, 0xe7, + 0x27, 0xf4, 0x10, 0x08, 0x6a, 0xee, 0xb7, 0x13, 0x58, 0x5f, 0xd8, 0x16, 0xff, + 0x43, 0xe9, 0x31, 0x13, 0x51, 0xfc, 0xed, 0x01, 0x35, 0xb7, 0x02, 0x00, 0xf8, + 0xf1, 0x0f, 0x2a, 0xf7, 0xe7, 0xc8, 0xa8, 0xeb, 0xa8, 0x2c, 0x21, 0xf4, 0x2d, + 0x15, 0x41, 0x14, 0x28, 0x18, 0xf4, 0x0f, 0x21, 0xfe, 0xd7, 0x27, 0x43, 0xf2, + 0xa3, 0xe5, 0x52, 0xf4, 0xfd, 0xc4, 0x59, 0x0a, 0xbf, 0xe2, 0xcd, 0x39, 0x15, + 0x08, 0x10, 0x09, 0x97, 0x97, 0x23, 0x40, 0x28, 0x4a, 0x0e, 0xed, 0x1d, 0x32, + 0xf4, 0xc6, 0xe6, 0xae, 0xf1, 0x45, 0x4b, 0xd0, 0xfe, 0x33, 0x35, 0x1c, 0xda, + 0xaf, 0x17, 0x03, 0x37, 0x2c, 0x02, 0x1c, 0xda, 0x27, 0xf2, 0x36, 0xed, 0x2a, + 0x2a, 0x14, 0xcf, 0xee, 0x0d, 0xd7, 0x06, 0xe2, 0x05, 0x52, 0xee, 0x14, 0xe1, + 0xf3, 0xad, 0xea, 0xe3, 0xe7, 0xfd, 0xf1, 0xea, 0xeb, 0xc4, 0x1a, 0xff, 0x0e, + 0xdc, 0xce, 0xf2, 0xfd, 0xaf, 0xb1, 0xb1, 0xaf, 0x2e, 0xb9, 0x14, 0x31, 0x31, + 0xbd, 0xcb, 0xda, 0xc1, 0x37, 0xfd, 0x64, 0xe2, 0xba, 0xfb, 0x27, 0xef, 0x15, + 0xd0, 0x1d, 0xee, 0x0f, 0xc3, 0xea, 0x30, 0x31, 0xfb, 0xd5, 0x12, 0x0c, 0xf2, + 0x3a, 0x89, 0x30, 0x91, 0xc2, 0xda, 0xc1, 0x0b, 0xe1, 0x31, 0x4c, 0x30, 0xde, + 0xe8, 0x0a, 0x11, 0x0d, 0xeb, 0xef, 0x00, 0x05, 0xd9, 0xbf, 0x08, 0x39, 0x36, + 0xed, 0xbe, 0xc9, 0x1e, 0xf0, 0x3b, 0x44, 0xfa, 0xa4, 0x8f, 0xc7, 0xd1, 0xd5, + 0x0c, 0xe0, 0x14, 0xcf, 0x24, 0xcb, 0x1b, 0xf7, 0xd9, 0xdf, 0x10, 0xfa, 0xa9, + 0xa7, 0x03, 0xfd, 0xd4, 0x0b, 0xca, 0xd5, 0xe4, 0xb6, 0x23, 0xca, 0xed, 0x04, + 0xf1, 0x38, 0xf9, 0x01, 0xac, 0x4c, 0x0e, 0xd7, 0xcf, 0xad, 0xe4, 0x20, 0x0a, + 0xf8, 0xfc, 0x2f, 0xcc, 0xff, 0xdd, 0xe1, 0x81, 0x04, 0xac, 0xd6, 0xe6, 0xbd, + 0x2e, 0x47, 0xf1, 0x1f, 0x3a, 0xd0, 0x0f, 0xb9, 0x17, 0xac, 0x04, 0xcb, 0x20, + 0x32, 0x88, 0x20, 0x00, 0x34, 0xe4, 0xdc, 0xc6, 0x37, 0x0c, 0x22, 0x02, 0x1e, + 0xd6, 0xe0, 0x02, 0x06, 0xa2, 0xe9, 0xec, 0xe5, 0x03, 0xee, 0xe6, 0xca, 0x01, + 0xd1, 0xb8, 0x0d, 0x26, 0x2a, 0x12, 0xbc, 0xdb, 0xf3, 0xcb, 0xc2, 0x21, 0xcf, + 0x3c, 0xfc, 0x04, 0xc9, 0xc5, 0x13, 0xcd, 0x04, 0x2a, 0xe8, 0xee, 0xaf, 0xec, + 0x1b, 0xf9, 0xc1, 0x05, 0x33, 0x1f, 0x1f, 0x24, 0xdb, 0xb4, 0xea, 0x12, 0x54, + 0xf7, 0xee, 0x24, 0xe3, 0xe0, 0x09, 0xbe, 0xd5, 0x15, 0xdc, 0x2d, 0xea, 0x36, + 0x1e, 0xda, 0xdf, 0x21, 0x07, 0xbd, 0x31, 0xeb, 0xc3, 0xe6, 0xb1, 0xd9, 0x24, + 0xdc, 0x19, 0x0c, 0xa8, 0xff, 0x0a, 0x13, 0xf0, 0xbe, 0xea, 0xde, 0xba, 0xea, + 0x19, 0x2c, 0xe0, 0xdb, 0x48, 0x10, 0xfc, 0x05, 0x1a, 0x0f, 0xb9, 0x2c, 0x0d, + 0xd3, 0xb5, 0xea, 0xd3, 0x04, 0xdd, 0xdc, 0x1e, 0xd8, 0x19, 0xa7, 0x0b, 0xde, + 0x1a, 0xdd, 0x2d, 0xdc, 0xe8, 0x10, 0xf7, 0x19, 0xfb, 0xf6, 0xdb, 0xca, 0xd4, + 0x19, 0xe1, 0x2b, 0xd3, 0xd9, 0xe6, 0xc7, 0xf3, 0xec, 0xfa, 0x15, 0x06, 0xc2, + 0xf9, 0x0a, 0xb0, 0xf0, 0x16, 0xdd, 0xf6, 0xd7, 0x0c, 0x26, 0xfc, 0x31, 0x05, + 0x36, 0xff, 0x35, 0x07, 0x07, 0x2d, 0xef, 0x02, 0xfb, 0xa0, 0xf2, 0xea, 0x0b, + 0x20, 0x32, 0x13, 0x0f, 0x27, 0xb3, 0xf3, 0xbb, 0xe7, 0x14, 0xdc, 0x0b, 0x02, + 0x1d, 0xe2, 0xf7, 0xea, 0xff, 0xf6, 0x0f, 0xde, 0xed, 0xf3, 0x21, 0x0b, 0xee, + 0x18, 0xf3, 0x33, 0xf7, 0x25, 0xf0, 0xf8, 0xd3, 0xc5, 0xe0, 0xeb, 0xc9, 0xea, + 0xe2, 0x08, 0x10, 0xcd, 0xfc, 0xf1, 0x0e, 0x02, 0x15, 0xcd, 0xf9, 0x18, 0x14, + 0x08, 0x1f, 0x01, 0xfe, 0xcb, 0xf8, 0xed, 0xef, 0x05, 0x07, 0xf7, 0xdd, 0x07, + 0x17, 0xd0, 0x16, 0x20, 0x22, 0x06, 0x0d, 0x05, 0x7f, 0xfd, 0xdc, 0xf4, 0x18, + 0x16, 0x0c, 0xd8, 0x14, 0x05, 0x01, 0x17, 0xc5, 0xcf, 0xf1, 0xd9, 0x02, 0xed, + 0x04, 0x0d, 0x22, 0x1e, 0xf6, 0xbb, 0xfd, 0xed, 0x0a, 0xf8, 0xde, 0xde, 0xd8, + 0x34, 0xf4, 0xfc, 0xf9, 0xcc, 0xcf, 0xf2, 0xea, 0x41, 0x47, 0xd9, 0xd6, 0xe9, + 0xf5, 0xe9, 0xc9, 0x07, 0x09, 0xfc, 0xf6, 0xd6, 0x0a, 0xeb, 0xed, 0xf7, 0xf2, + 0xfc, 0xed, 0xf6, 0xfd, 0xe3, 0xf2, 0x25, 0x0d, 0xd9, 0xd7, 0xf3, 0x14, 0xe5, + 0x4d, 0x0a, 0xeb, 0xf8, 0xeb, 0x19, 0xd2, 0xbb, 0xe7, 0xcb, 0xfa, 0xf4, 0xd7, + 0xf4, 0x17, 0xb7, 0x0e, 0xe8, 0xf0, 0x13, 0xda, 0xf3, 0x0c, 0x0e, 0x0b, 0xe5, + 0xea, 0xf9, 0x0c, 0x58, 0x03, 0xfb, 0x0b, 0xf6, 0xeb, 0x0d, 0xf9, 0xde, 0x29, + 0xda, 0x18, 0xfc, 0xdb, 0xdb, 0xc8, 0x0c, 0x37, 0x1f, 0xf9, 0x14, 0x13, 0xdf, + 0x12, 0x22, 0xff, 0x17, 0xe9, 0xe1, 0xf6, 0x0d, 0x0a, 0xe5, 0xef, 0xd3, 0xd6, + 0xf2, 0xd6, 0xfb, 0xf7, 0xe1, 0x07, 0xff, 0x42, 0xdc, 0x2d, 0xb0, 0x07, 0xfb, + 0xf3, 0x12, 0x05, 0x0f, 0xdf, 0x0e, 0xdc, 0xf2, 0x00, 0xc8, 0xdf, 0x02, 0x0e, + 0x08, 0x22, 0x18, 0x13, 0x2b, 0xd9, 0x00, 0x0b, 0xc2, 0x12, 0xdf, 0xfe, 0x4a, + 0x3c, 0xcc, 0x47, 0x12, 0x20, 0xde, 0x1a, 0xca, 0xed, 0xed, 0x30, 0x0c, 0x04, + 0x38, 0x0f, 0xeb, 0x19, 0xb5, 0x20, 0x22, 0x07, 0xec, 0x09, 0xd4, 0xb4, 0xf3, + 0x11, 0xf6, 0xbb, 0xd9, 0x05, 0xf4, 0x0a, 0xed, 0x33, 0xc1, 0xe8, 0x43, 0xd4, + 0x07, 0xfc, 0xdc, 0x2e, 0x0f, 0x1d, 0x2e, 0xd2, 0xe5, 0xff, 0x1a, 0xc1, 0xea, + 0x26, 0x29, 0xb8, 0x17, 0xbe, 0x08, 0xdc, 0xe9, 0xd7, 0xeb, 0xe1, 0x31, 0xdf, + 0xef, 0x01, 0xd8, 0xa1, 0x3b, 0x20, 0x06, 0x9b, 0xf5, 0xfd, 0xee, 0x2e, 0xd7, + 0xec, 0x18, 0x25, 0x32, 0x7f, 0x0b, 0x08, 0xeb, 0xa0, 0x0d, 0xfd, 0x33, 0xfb, + 0xce, 0xdf, 0x0a, 0xf9, 0x00, 0x18, 0xd8, 0xe7, 0x25, 0xd8, 0xd5, 0x09, 0xeb, + 0x17, 0x74, 0x10, 0xed, 0x00, 0x12, 0x0c, 0xdf, 0xb9, 0x4b, 0x08, 0x16, 0xe1, + 0xf3, 0xdf, 0x1e, 0x05, 0xf9, 0xd4, 0xc7, 0xcf, 0xd9, 0xe1, 0xc5, 0xbb, 0xe0, + 0xce, 0xf5, 0x1d, 0xe5, 0x11, 0x06, 0xe1, 0x07, 0xf6, 0x26, 0xcd, 0x03, 0xc7, + 0x15, 0xd9, 0x23, 0xe8, 0xd0, 0x05, 0xf9, 0xf3, 0xc9, 0xe1, 0xe0, 0x05, 0xe6, + 0x11, 0xf3, 0xde, 0xe2, 0xfa, 0xc4, 0xfb, 0x05, 0x13, 0x01, 0x1c, 0xe9, 0x08, + 0xd8, 0xdd, 0xb9, 0x19, 0xb5, 0xea, 0xa8, 0x03, 0xde, 0xf2, 0x09, 0x45, 0x39, + 0x0f, 0xf1, 0xda, 0xe2, 0x13, 0x37, 0x16, 0xe2, 0x3f, 0xf7, 0xdf, 0x32, 0xe9, + 0x07, 0x4c, 0xeb, 0x40, 0xac, 0xe5, 0xb0, 0xfe, 0xc2, 0xe0, 0xf4, 0xd7, 0xc1, + 0x23, 0xf5, 0xdf, 0xe7, 0x0f, 0xff, 0xe3, 0x34, 0xbf, 0xd1, 0xdc, 0xfe, 0x0c, + 0xd1, 0xf0, 0xea, 0xd6, 0xbd, 0xf8, 0xc3, 0xcc, 0xc5, 0xf0, 0xf3, 0xdb, 0x03, + 0x17, 0x1d, 0x0d, 0x28, 0xe8, 0x16, 0xd3, 0x16, 0xcc, 0xf5, 0x17, 0xec, 0x36, + 0xe4, 0x2e, 0x07, 0xdc, 0xe2, 0xd3, 0x0a, 0xd7, 0x0a, 0x1f, 0xc0, 0x19, 0x16, + 0xeb, 0xd4, 0xd9, 0xfe, 0xd9, 0xd9, 0xb6, 0xf9, 0xf6, 0xdd, 0xd1, 0xe4, 0x25, + 0xc0, 0xf9, 0xda, 0x10, 0xe5, 0x25, 0x15, 0xb5, 0x1d, 0x9c, 0x10, 0x05, 0xd1, + 0xd2, 0x8d, 0xee, 0xde, 0xa7, 0xb7, 0x49, 0xe9, 0x26, 0x9c, 0x03, 0xec, 0x22, + 0xf9, 0xe3, 0x30, 0x04, 0x29, 0x10, 0xcd, 0xe2, 0xce, 0xf6, 0x18, 0xfd, 0xe5, + 0x21, 0x0b, 0x19, 0xf7, 0x19, 0xe7, 0xd1, 0xf2, 0xfc, 0xf8, 0x10, 0xbf, 0xdb, + 0x0f, 0xd7, 0x4b, 0x0c, 0x30, 0x1a, 0x49, 0xf7, 0xd0, 0xc8, 0x14, 0x2b, 0x13, + 0xa6, 0xe6, 0xf0, 0xcf, 0x09, 0x22, 0x30, 0xf5, 0x41, 0xc9, 0x06, 0xf7, 0x1f, + 0xe9, 0xf0, 0x04, 0x0d, 0xde, 0xed, 0x10, 0x1b, 0xc2, 0x29, 0xc0, 0xd3, 0x2a, + 0xcf, 0xfb, 0xc8, 0x17, 0xf9, 0xa6, 0x11, 0x06, 0xf5, 0x0d, 0xd3, 0xd1, 0xf9, + 0xc0, 0xa7, 0xe3, 0xff, 0xec, 0x15, 0xe0, 0xed, 0xba, 0xcf, 0xfe, 0xf9, 0xea, + 0x01, 0x43, 0x01, 0x08, 0xfd, 0x2a, 0xc0, 0x42, 0x15, 0xc7, 0xfb, 0xfa, 0xf7, + 0xcd, 0x24, 0xff, 0xf4, 0xc3, 0xde, 0xef, 0xe5, 0x03, 0x06, 0x15, 0xeb, 0xf5, + 0x27, 0xe3, 0xd7, 0x09, 0x10, 0x07, 0xe9, 0x1f, 0xdf, 0xdb, 0x24, 0x1f, 0xeb, + 0xcb, 0xf8, 0xc3, 0xda, 0x1f, 0x19, 0x0c, 0xe2, 0x6a, 0xce, 0xfa, 0xf9, 0xb8, + 0x18, 0xf7, 0xf7, 0xe6, 0xd0, 0x1d, 0xac, 0x2a, 0xfd, 0xf7, 0x0c, 0xf2, 0x18, + 0xb3, 0xc5, 0x33, 0xd9, 0x43, 0xfb, 0xf0, 0x46, 0xc7, 0xb7, 0x0a, 0xde, 0xf8, + 0x08, 0xed, 0x15, 0xd9, 0xd3, 0x15, 0x24, 0x34, 0x0a, 0x36, 0x03, 0xb4, 0xce, + 0x87, 0xc0, 0x7f, 0xc1, 0xec, 0xf6, 0xec, 0x16, 0x14, 0x01, 0x23, 0x00, 0xe3, + 0xcd, 0x94, 0xee, 0xe3, 0xec, 0xf9, 0x08, 0xf6, 0x0e, 0xf3, 0xec, 0x0f, 0xba, + 0xb5, 0x07, 0x08, 0xfb, 0xd1, 0xc8, 0x0d, 0xb5, 0xe7, 0xfb, 0x13, 0xb6, 0xfb, + 0x10, 0xf7, 0xbb, 0xdb, 0xdb, 0xe2, 0x09, 0x29, 0x4e, 0x36, 0x2a, 0xe4, 0xe1, + 0x27, 0xde, 0xe8, 0xdb, 0x01, 0x15, 0x03, 0xf1, 0x20, 0xef, 0xc2, 0xd8, 0xca, + 0xac, 0x0c, 0x34, 0x2d, 0xc9, 0xb3, 0xf2, 0xc4, 0x21, 0xf3, 0x04, 0x81, 0xa7, + 0xea, 0x45, 0xd3, 0x3b, 0x09, 0x28, 0xf4, 0xad, 0xf1, 0xfc, 0x13, 0xed, 0xaa, + 0xba, 0x10, 0xea, 0x37, 0x22, 0x24, 0xd3, 0xe1, 0x0d, 0xfa, 0x09, 0xec, 0x29, + 0x13, 0x10, 0x03, 0x28, 0xfa, 0x28, 0xda, 0xdb, 0xde, 0x6c, 0x60, 0xc2, 0x0a, + 0xf0, 0x37, 0x5f, 0x01, 0x00, 0xf8, 0xbe, 0xbf, 0xc6, 0x41, 0x01, 0xcd, 0xfd, + 0x3e, 0x0d, 0xfe, 0x05, 0xef, 0xed, 0x23, 0x09, 0xee, 0x45, 0xf2, 0xbe, 0x34, + 0x2d, 0x03, 0x6f, 0xb7, 0xd3, 0xf2, 0xf6, 0x01, 0xbe, 0x11, 0x0f, 0xcb, 0x38, + 0x09, 0x0c, 0xd9, 0xc3, 0x1d, 0xe3, 0xfc, 0xa9, 0xb3, 0x2a, 0xe5, 0xa6, 0xb2, + 0x2a, 0xff, 0xf3, 0x26, 0x09, 0xed, 0xb8, 0x0d, 0xa8, 0x13, 0xe5, 0xba, 0x4d, + 0x2d, 0x38, 0xf7, 0xbe, 0xc3, 0x28, 0x3a, 0x27, 0xdf, 0xe3, 0xca, 0xb2, 0x0d, + 0x05, 0xbb, 0xd9, 0xda, 0xfe, 0xb6, 0xbc, 0xaa, 0xff, 0x1c, 0xf1, 0xf3, 0x00, + 0x03, 0x1b, 0x13, 0x16, 0xe4, 0x1a, 0xf5, 0xd7, 0x2b, 0xf4, 0x28, 0x35, 0xfe, + 0xdb, 0xcd, 0xc6, 0xf7, 0xde, 0xf8, 0xd3, 0xfc, 0x07, 0x17, 0x00, 0xdf, 0x03, + 0x03, 0x17, 0xe3, 0xb0, 0x22, 0x00, 0xd2, 0xc9, 0x30, 0x18, 0x04, 0xf2, 0x0e, + 0x0e, 0x06, 0xc8, 0xe9, 0xd7, 0xe4, 0x3b, 0x06, 0x02, 0xf6, 0x1f, 0x02, 0xfd, + 0x07, 0x11, 0xc0, 0x49, 0xd8, 0xd6, 0xbb, 0x22, 0xaf, 0x51, 0xeb, 0x05, 0xaf, + 0xe0, 0xeb, 0x07, 0x14, 0x36, 0x2d, 0xaf, 0xf8, 0xf7, 0x1b, 0xec, 0xf0, 0x23, + 0xf4, 0xed, 0xdb, 0xf4, 0x0b, 0x5d, 0x0d, 0xb5, 0xcd, 0x09, 0xfb, 0xf9, 0xde, + 0x03, 0xe3, 0xf7, 0x4a, 0x5f, 0xb3, 0xda, 0x13, 0xfd, 0xbb, 0xee, 0xe6, 0x19, + 0xe7, 0x56, 0x9d, 0x30, 0xd9, 0x2e, 0x2b, 0xb6, 0xf5, 0xca, 0x30, 0x8a, 0xc4, + 0xf8, 0xfd, 0xc8, 0xf5, 0x20, 0xf5, 0x35, 0x14, 0xfa, 0x08, 0x06, 0xd7, 0xc3, + 0xfb, 0xff, 0xd3, 0xd6, 0xb8, 0x31, 0x0c, 0x46, 0x29, 0xe6, 0x07, 0xe5, 0x0d, + 0x25, 0xaa, 0xf4, 0xa7, 0x3a, 0xe9, 0xd1, 0x39, 0xcc, 0x48, 0xfc, 0x92, 0x27, + 0xa8, 0x3a, 0x32, 0xe9, 0x09, 0xc4, 0x16, 0x18, 0xea, 0xea, 0xb6, 0xa8, 0x2b, + 0x1f, 0xea, 0x01, 0x0d, 0xb8, 0xe1, 0x15, 0x59, 0xb0, 0x2d, 0xc3, 0xfd, 0x66, + 0xdc, 0x05, 0x1e, 0xd1, 0xcf, 0x26, 0xdc, 0x00, 0x42, 0x29, 0x16, 0x19, 0xc7, + 0x27, 0xe9, 0x89, 0xc5, 0x12, 0x49, 0xcc, 0x21, 0xfd, 0xef, 0xac, 0x4f, 0xeb, + 0x07, 0xf5, 0x22, 0x1a, 0x8a, 0x28, 0xac, 0x26, 0xa4, 0x2b, 0x55, 0xf3, 0x15, + 0xa8, 0xf6, 0x18, 0x3d, 0x33, 0x10, 0x0c, 0xea, 0x12, 0xca, 0xc9, 0xec, 0xa4, + 0xb9, 0xfb, 0xce, 0x31, 0x35, 0xf0, 0x02, 0x19, 0x32, 0x95, 0x09, 0xbb, 0xc4, + 0x2c, 0xf8, 0x1c, 0xd9, 0x0a, 0xcf, 0x8c, 0xf2, 0x15, 0x8d, 0xcb, 0xa3, 0x08, + 0x28, 0xdd, 0x1b, 0x08, 0xd7, 0xb1, 0x48, 0x07, 0x0b, 0xe5, 0xe8, 0xf0, 0x40, + 0x0e, 0x07, 0xec, 0xde, 0xc6, 0xce, 0xb4, 0xe6, 0x15, 0x21, 0x0b, 0xa7, 0xf6, + 0xf0, 0xf1, 0x11, 0x36, 0xda, 0x94, 0x0f, 0xeb, 0x1e, 0x54, 0xd9, 0x9d, 0xc2, + 0x0f, 0x22, 0xce, 0x00, 0xe5, 0x5a, 0x18, 0xb8, 0x01, 0x4c, 0xc6, 0xf8, 0xe5, + 0x99, 0x28, 0x04, 0xf4, 0xf4, 0x16, 0x25, 0xdd, 0x0d, 0x3e, 0xb0, 0x01, 0xfe, + 0xb6, 0xfe, 0xe7, 0x04, 0xbd, 0x26, 0xb5, 0x4b, 0xb0, 0xe9, 0xf0, 0xfe, 0x03, + 0x3d, 0xe6, 0xf3, 0x1e, 0x6e, 0x13, 0x4d, 0x4c, 0xc5, 0xb5, 0x81, 0xa0, 0xec, + 0xc0, 0xcf, 0x0b, 0x01, 0x1a, 0xcc, 0x1d, 0xac, 0x2d, 0xd1, 0x15, 0x05, 0x0a, + 0xff, 0x2b, 0xf0, 0xb9, 0xf6, 0xbf, 0x45, 0x00, 0xb5, 0x43, 0x1a, 0xd5, 0xe0, + 0x0e, 0x10, 0xe5, 0xc9, 0xed, 0xde, 0x2e, 0xd0, 0xe8, 0x2f, 0x08, 0xd4, 0xdf, + 0xc7, 0xf8, 0xf6, 0xb3, 0x22, 0xf9, 0xec, 0xe6, 0x14, 0xd8, 0x14, 0xee, 0xc1, + 0x00, 0x12, 0xe4, 0x12, 0x00, 0xec, 0xe1, 0xac, 0xcb, 0x0c, 0xd2, 0xe9, 0x11, + 0x2e, 0xd7, 0x18, 0xd1, 0x2b, 0x3a, 0x32, 0xee, 0x08, 0x00, 0xb2, 0x8a, 0x15, + 0xe6, 0xab, 0xf8, 0xfd, 0x93, 0xe3, 0xf6, 0xeb, 0xd8, 0x1f, 0xd7, 0x29, 0xfe, + 0x40, 0x57, 0xec, 0xa2, 0xe2, 0x0d, 0x0e, 0xe9, 0xf7, 0x1f, 0x92, 0xdd, 0xaf, + 0xec, 0x13, 0x10, 0xc9, 0xe6, 0x24, 0xcf, 0xeb, 0x0a, 0xfa, 0x25, 0xbc, 0xe0, + 0x8a, 0x18, 0x89, 0x05, 0xbd, 0x20, 0x13, 0xf3, 0x06, 0x19, 0xc4, 0xdd, 0xd3, + 0x2d, 0xd1, 0xd3, 0x33, 0x07, 0xf5, 0x26, 0x2a, 0x16, 0x05, 0xeb, 0x48, 0x3f, + 0x34, 0xe7, 0xff, 0xfa, 0x81, 0xdb, 0xe9, 0xf3, 0xc0, 0x25, 0x0c, 0xb5, 0xe8, + 0x00, 0x47, 0xf6, 0x42, 0xf8, 0xd7, 0xd1, 0xf7, 0xf8, 0x20, 0x07, 0x17, 0xf9, + 0x1b, 0x9e, 0xf2, 0x3a, 0xdc, 0x0e, 0x29, 0xb0, 0x1a, 0x04, 0x99, 0x43, 0x0a, + 0x07, 0xff, 0x52, 0x02, 0x14, 0x04, 0xac, 0xe7, 0xcf, 0x04, 0x07, 0xf3, 0xf4, + 0x26, 0x07, 0xe4, 0x47, 0xd6, 0xd7, 0x01, 0xd1, 0x17, 0x18, 0x37, 0xfc, 0xfc, + 0xd5, 0xf3, 0x08, 0xfc, 0x37, 0x28, 0xce, 0xfd, 0x24, 0xde, 0xf0, 0xe3, 0x1f, + 0xa0, 0xf0, 0x07, 0xfb, 0xdc, 0xfd, 0xd4, 0xf1, 0x2e, 0xe5, 0x1c, 0xd8, 0x19, + 0xe1, 0xe5, 0x5f, 0xe5, 0xc9, 0xf2, 0x25, 0xc1, 0x34, 0x42, 0xc4, 0xf1, 0xf7, + 0xe6, 0xf5, 0xcb, 0xf3, 0x2d, 0x00, 0xe6, 0xda, 0xff, 0xac, 0x37, 0xfa, 0xd7, + 0xc0, 0xf0, 0x2a, 0xd6, 0xc3, 0xdf, 0xc3, 0x30, 0xed, 0xb0, 0xff, 0xe5, 0xf9, + 0x07, 0xf3, 0xd8, 0x1c, 0x41, 0x17, 0xda, 0xf8, 0x03, 0xf0, 0x0c, 0xce, 0x14, + 0x08, 0x06, 0xf4, 0x11, 0xde, 0x14, 0xfc, 0x19, 0x28, 0xd8, 0x04, 0x4b, 0x27, + 0x21, 0xb7, 0xee, 0xdf, 0x02, 0xf7, 0x16, 0xf1, 0xd5, 0x12, 0xea, 0xf3, 0x1f, + 0x0a, 0xd0, 0x39, 0x53, 0xf6, 0xef, 0xed, 0x1a, 0x1e, 0xea, 0xd0, 0x1f, 0xd7, + 0xf9, 0xfd, 0x1b, 0xf4, 0xfb, 0x08, 0xd5, 0x1c, 0x25, 0x33, 0xd9, 0xf7, 0x16, + 0x07, 0xf5, 0x01, 0x29, 0x3e, 0x1a, 0x10, 0x05, 0xde, 0x14, 0xe2, 0xe2, 0x1f, + 0x03, 0x0b, 0xe9, 0xed, 0x0d, 0xfd, 0xf1, 0x09, 0x05, 0x06, 0xd7, 0xcb, 0xb7, + 0x00, 0xdc, 0xff, 0xde, 0x04, 0xc1, 0x2e, 0x13, 0xf0, 0x09, 0x19, 0x0c, 0x2a, + 0x1b, 0xf2, 0x26, 0xbc, 0xe5, 0x31, 0xc5, 0x00, 0xb8, 0xfa, 0x2b, 0xf1, 0xfb, + 0xda, 0xfd, 0xc5, 0x22, 0x12, 0x03, 0xf9, 0x20, 0xd2, 0xf2, 0x3b, 0xad, 0x16, + 0xe4, 0xed, 0xee, 0x24, 0xfb, 0x0d, 0xe9, 0x04, 0x0f, 0xd4, 0xfa, 0xf0, 0xe9, + 0xe9, 0xf7, 0xf9, 0xfd, 0xdf, 0x7f, 0x0c, 0x0b, 0x0a, 0xdf, 0xdc, 0x01, 0xfa, + 0xef, 0xf6, 0x08, 0xd7, 0x42, 0x10, 0xf6, 0x6a, 0x12, 0xf9, 0xef, 0xf3, 0x0f, + 0x01, 0xe5, 0xe8, 0x0a, 0x08, 0xd8, 0xb0, 0x23, 0xd9, 0xdd, 0x03, 0xee, 0xf1, + 0xed, 0xe1, 0x24, 0x52, 0xf3, 0x7d, 0x20, 0xe8, 0x9e, 0xe7, 0x07, 0xed, 0x73, + 0xe9, 0x1e, 0x0a, 0x08, 0xe1, 0xf3, 0x17, 0xe1, 0x07, 0xf9, 0xdd, 0xff, 0x17, + 0x0e, 0xd6, 0xf4, 0xfd, 0xf9, 0xed, 0xbb, 0xd0, 0xf7, 0xcd, 0xea, 0xdb, 0xe9, + 0x19, 0xcf, 0xbd, 0x35, 0x13, 0x07, 0x27, 0x2b, 0x03, 0xca, 0x0c, 0xfb, 0xc7, + 0x01, 0x07, 0x02, 0x24, 0x27, 0x1e, 0x22, 0x38, 0xf2, 0x1c, 0x2b, 0xa3, 0xc8, + 0x14, 0xfe, 0xfa, 0x01, 0xec, 0xde, 0xff, 0xeb, 0xda, 0xca, 0xdd, 0x25, 0xd1, + 0xb0, 0xf7, 0x14, 0xd1, 0x94, 0xba, 0x3d, 0xb9, 0x1c, 0xcc, 0xbe, 0x2d, 0xfb, + 0x2f, 0x08, 0xff, 0xee, 0xaf, 0x97, 0xfd, 0xa5, 0x10, 0x48, 0x25, 0x37, 0xd8, + 0x2d, 0xff, 0xc9, 0xff, 0xf1, 0x4c, 0xf1, 0x8f, 0xf0, 0xcb, 0xc3, 0x81, 0xf9, + 0x1e, 0x49, 0x33, 0x13, 0x14, 0xf1, 0xa2, 0x5e, 0xf7, 0x3a, 0xf9, 0xdc, 0xe9, + 0x0e, 0x49, 0x6f, 0xed, 0xd0, 0xe4, 0x0a, 0xb5, 0xde, 0xd6, 0xd4, 0xe7, 0xc4, + 0xf4, 0xee, 0x08, 0xee, 0x05, 0xe8, 0xb7, 0x5c, 0x9e, 0x3b, 0xbe, 0xcd, 0x31, + 0xdf, 0x42, 0x1a, 0xfb, 0xed, 0xe5, 0xda, 0xf6, 0xab, 0xc9, 0xe3, 0xbc, 0x13, + 0xf3, 0xc8, 0xed, 0x28, 0x2a, 0xc4, 0xeb, 0xe3, 0xc4, 0xf4, 0x2a, 0x22, 0x0b, + 0x13, 0xd5, 0xcc, 0xf5, 0xb1, 0x33, 0x10, 0xee, 0xb5, 0xc4, 0xdd, 0x02, 0xcf, + 0x1e, 0xc4, 0xc7, 0xe7, 0x15, 0xa1, 0x37, 0xcf, 0x01, 0x94, 0xa6, 0xdc, 0x28, + 0xec, 0x02, 0x3e, 0x09, 0x0c, 0xae, 0x0a, 0x40, 0x03, 0x32, 0xd2, 0x8f, 0xcb, + 0x99, 0xc8, 0x3d, 0xe7, 0xec, 0x36, 0xb6, 0xf0, 0xf8, 0xcc, 0xae, 0x0e, 0xec, + 0x0b, 0xed, 0x32, 0xe3, 0x0a, 0xb7, 0xc8, 0xba, 0x45, 0x30, 0x03, 0xc5, 0x1c, + 0xf9, 0x42, 0xbf, 0x44, 0x50, 0x28, 0x0a, 0xd4, 0x9f, 0xb0, 0xe6, 0x17, 0x04, + 0x06, 0x06, 0x32, 0xc8, 0x14, 0x46, 0xe2, 0x25, 0xee, 0x95, 0xeb, 0xe2, 0xe0, + 0x06, 0xf1, 0x09, 0xf6, 0xdf, 0x12, 0x1d, 0xd8, 0xbd, 0x16, 0x35, 0xc3, 0x3f, + 0x10, 0x12, 0xc5, 0xe0, 0xeb, 0x11, 0xfc, 0x20, 0xb1, 0xc6, 0xb6, 0xdd, 0xfd, + 0x34, 0x11, 0x11, 0x22, 0x1b, 0xe8, 0xdc, 0x0d, 0xdc, 0x45, 0xe4, 0xbb, 0x1e, + 0xfe, 0xeb, 0xed, 0xfb, 0x3a, 0x1a, 0x25, 0xa9, 0xfb, 0x66, 0xc6, 0xec, 0xba, + 0xcb, 0xc9, 0x28, 0x08, 0xc5, 0x21, 0xb8, 0x2f, 0x06, 0xb7, 0x16, 0xd5, 0xb3, + 0xce, 0xad, 0xc5, 0xa9, 0xbe, 0x9e, 0x9b, 0x0c, 0x39, 0x20, 0xe8, 0xcf, 0xc8, + 0xd9, 0xf0, 0x26, 0xb6, 0xc9, 0xf3, 0xf2, 0xdc, 0xec, 0xca, 0x1f, 0xf2, 0x13, + 0xaa, 0x32, 0x11, 0xf7, 0xd1, 0xb6, 0x10, 0xa5, 0xf4, 0xf6, 0x3e, 0x0c, 0xed, + 0xd6, 0xe8, 0x92, 0xf9, 0xfa, 0x1d, 0x56, 0xbe, 0xf1, 0xc6, 0x12, 0xe9, 0xf1, + 0x21, 0xcd, 0x07, 0xa3, 0xe0, 0xd5, 0x07, 0xe9, 0xfd, 0xc5, 0x2d, 0xfb, 0xa3, + 0xe5, 0xdd, 0xd0, 0x15, 0xdc, 0x10, 0x0f, 0x81, 0x13, 0xcb, 0x31, 0xa5, 0x1d, + 0xee, 0xbc, 0xb7, 0xeb, 0xd1, 0xb4, 0xcd, 0xcc, 0x9d, 0xe8, 0xf3, 0xf5, 0x2a, + 0x30, 0xe7, 0xdc, 0xe2, 0xcc, 0xef, 0x10, 0x11, 0xba, 0x08, 0xd6, 0xd2, 0xd1, + 0x9d, 0x1f, 0x1f, 0xdc, 0xe1, 0xf4, 0xb0, 0x0d, 0xf1, 0x99, 0x9c, 0x24, 0xfb, + 0x0a, 0xdc, 0xee, 0xa9, 0xd5, 0xd8, 0xcd, 0xf4, 0x19, 0xef, 0x1e, 0x2d, 0x17, + 0xed, 0xe7, 0xf1, 0x36, 0x55, 0x22, 0xba, 0xa3, 0xe1, 0xc3, 0xda, 0xfc, 0xbb, + 0x07, 0xe3, 0xa1, 0xed, 0xc3, 0xfb, 0xe2, 0xe6, 0xff, 0xa0, 0xef, 0x02, 0xb2, + 0xd9, 0xee, 0x60, 0x15, 0x39, 0x15, 0xec, 0xfc, 0xfd, 0x2e, 0xf4, 0xa9, 0x10, + 0xf0, 0x18, 0x17, 0xa3, 0xce, 0xe1, 0xdf, 0xc0, 0xaa, 0x2c, 0x52, 0xb3, 0xf4, + 0xeb, 0x44, 0x8e, 0x17, 0xa8, 0xed, 0xef, 0x06, 0xd6, 0xe8, 0x3f, 0xd0, 0xf2, + 0xb4, 0xc9, 0xe2, 0xab, 0x03, 0x25, 0x39, 0x07, 0x35, 0xe0, 0xa3, 0xdf, 0xba, + 0x04, 0x59, 0xb2, 0xc4, 0x9a, 0x06, 0x14, 0xde, 0xf2, 0x4d, 0xf3, 0x43, 0x01, + 0xcc, 0xaa, 0x3a, 0x11, 0x43, 0xa9, 0xb0, 0x35, 0x26, 0xfc, 0xf6, 0x92, 0x0b, + 0x2a, 0x19, 0xde, 0x0d, 0xd2, 0xea, 0xf0, 0xfd, 0x09, 0xd2, 0x6c, 0xb6, 0xb9, + 0x09, 0x9b, 0xee, 0x15, 0xdf, 0x81, 0x37, 0x1a, 0xf8, 0x44, 0x16, 0xf3, 0x35, + 0xc9, 0xdf, 0xe9, 0x1a, 0x17, 0x1a, 0x2c, 0x27, 0xa9, 0x27, 0x10, 0x03, 0xd1, + 0x2f, 0x1c, 0x99, 0xe1, 0x03, 0x08, 0xcb, 0xbc, 0xef, 0x05, 0xf9, 0xac, 0x9a, + 0x19, 0xac, 0x36, 0x99, 0x3c, 0xf9, 0xbc, 0xec, 0xd2, 0x09, 0x45, 0xc0, 0x09, + 0x59, 0xbf, 0xf9, 0xcc, 0xde, 0xd4, 0x27, 0x3f, 0xd0, 0xe5, 0x15, 0xcb, 0xca, + 0x00, 0xd3, 0xed, 0x16, 0x2f, 0x28, 0xe8, 0x50, 0xbf, 0x94, 0xc9, 0xb9, 0xc0, + 0x92, 0x8a, 0xdb, 0x3e, 0xbe, 0xf3, 0x07, 0xf7, 0x16, 0x96, 0x09, 0x29, 0xe8, + 0xca, 0x54, 0x26, 0xf4, 0x08, 0x18, 0x2c, 0x08, 0x01, 0xef, 0xcf, 0x5b, 0x41, + 0x18, 0x22, 0x3a, 0xf8, 0xc2, 0xc7, 0x0d, 0x07, 0x17, 0x1d, 0x57, 0x9d, 0xfb, + 0xb3, 0xdf, 0x8d, 0xfb, 0x01, 0xf7, 0xf6, 0xb9, 0x31, 0xf3, 0xf6, 0x1f, 0x42, + 0x04, 0x93, 0xb8, 0xd5, 0xfe, 0x9e, 0x02, 0xc4, 0x4d, 0x47, 0x27, 0xc5, 0xfa, + 0x5a, 0x2b, 0xa8, 0x9e, 0x18, 0xf0, 0xe1, 0x20, 0x03, 0x9c, 0x1d, 0xb4, 0xa8, + 0x2a, 0xce, 0xac, 0xe2, 0xdf, 0x05, 0xc3, 0x52, 0xec, 0x46, 0xe0, 0xc7, 0x5e, + 0xd4, 0x16, 0xd7, 0x61, 0xdc, 0x0d, 0x0b, 0x2b, 0xf9, 0xa1, 0xa1, 0x2a, 0x21, + 0x03, 0x13, 0xc9, 0x05, 0x3c, 0xfa, 0xd1, 0x05, 0x35, 0x11, 0x4f, 0xf1, 0x1c, + 0xf1, 0xee, 0x10, 0xe0, 0xd9, 0xa9, 0xda, 0x0d, 0xa3, 0x08, 0x07, 0x1a, 0x3b, + 0x50, 0xd6, 0x8c, 0x51, 0x30, 0xe3, 0xf8, 0x32, 0xc9, 0xfc, 0x02, 0xbe, 0x1d, + 0x4e, 0xd0, 0x5b, 0x05, 0xf5, 0xfd, 0x0a, 0xfd, 0xec, 0xdc, 0x37, 0xe4, 0x1f, + 0xda, 0x3a, 0x32, 0xbd, 0xa6, 0xd1, 0x02, 0xe8, 0x82, 0xd9, 0xfd, 0xe7, 0x56, + 0x02, 0x1b, 0xbf, 0x7c, 0xc5, 0xba, 0xfb, 0xde, 0x1c, 0x1e, 0x03, 0x36, 0x58, + 0x21, 0x86, 0xef, 0x31, 0xf4, 0xdb, 0xef, 0xb1, 0xcc, 0xec, 0xd9, 0xde, 0xf6, + 0x21, 0x00, 0x31, 0xd7, 0xf4, 0x89, 0x0a, 0xe7, 0x23, 0xea, 0xc3, 0x26, 0xbf, + 0x06, 0xfa, 0x01, 0x96, 0xe2, 0x19, 0xba, 0x3a, 0x23, 0xb4, 0xc1, 0x19, 0xb6, + 0xb1, 0x00, 0x45, 0x5a, 0x4a, 0xe5, 0xf0, 0x93, 0xe0, 0xd8, 0xff, 0x30, 0xd6, + 0x17, 0x01, 0xe0, 0xe0, 0xd7, 0x24, 0xab, 0x89, 0xa9, 0xbc, 0xf5, 0x11, 0x07, + 0xca, 0xd2, 0xb1, 0xb0, 0xbd, 0x52, 0x21, 0xd2, 0xfb, 0xa0, 0xd2, 0xce, 0xd3, + 0x09, 0xdf, 0xc9, 0x9b, 0x10, 0xde, 0x3a, 0x23, 0xcd, 0xf4, 0xcd, 0xe6, 0x11, + 0xce, 0xd8, 0x1a, 0xa2, 0x19, 0x18, 0xb9, 0x0c, 0xc3, 0xe9, 0xf8, 0x18, 0xf3, + 0xd8, 0xe4, 0xce, 0xb4, 0x12, 0xd9, 0x3c, 0xb1, 0xc6, 0xef, 0x02, 0xe9, 0x74, + 0x15, 0xe3, 0xda, 0x35, 0xc8, 0x2e, 0xea, 0xad, 0xae, 0xe9, 0xc5, 0xd6, 0xda, + 0xee, 0xb9, 0x04, 0x39, 0xc2, 0x1a, 0x25, 0x15, 0xf1, 0x57, 0x31, 0x9e, 0x84, + 0xee, 0xb3, 0x81, 0x31, 0xf2, 0xf4, 0xdc, 0x28, 0xf6, 0xd3, 0xe9, 0xf8, 0x15, + 0xf7, 0xcb, 0x06, 0x87, 0xe6, 0xb7, 0xd5, 0x64, 0xeb, 0xfd, 0xbf, 0xb1, 0xd4, + 0xdb, 0x46, 0x1c, 0xe6, 0x38, 0xc6, 0x52, 0x2e, 0xe1, 0xdb, 0x92, 0xef, 0xe9, + 0xea, 0xe7, 0xe0, 0xcb, 0x4b, 0x3d, 0x4c, 0xa0, 0xc0, 0xa1, 0x16, 0x31, 0xe4, + 0xc6, 0xef, 0x00, 0xa6, 0xce, 0x1f, 0xf0, 0x18, 0x9b, 0xd4, 0xf7, 0xf5, 0xf6, + 0x49, 0xae, 0xd7, 0x3d, 0xa3, 0x46, 0x5c, 0x3e, 0x6f, 0x9d, 0xd0, 0x24, 0x5b, + 0xc3, 0x9d, 0xec, 0xf6, 0x08, 0x86, 0xc5, 0xee, 0xc2, 0x0a, 0xf7, 0xf6, 0xdf, + 0xfd, 0xdd, 0xfb, 0x14, 0xb5, 0x22, 0xbd, 0xf6, 0xd3, 0xe9, 0xc3, 0xe8, 0x10, + 0x04, 0x0d, 0x11, 0xf2, 0x1c, 0xde, 0x17, 0xe0, 0x23, 0x08, 0xdf, 0xf7, 0x07, + 0xe0, 0xee, 0x21, 0xda, 0x2b, 0x0b, 0xe2, 0xee, 0x08, 0xfc, 0x28, 0xd0, 0x2b, + 0xfd, 0x07, 0x28, 0x03, 0x07, 0xeb, 0xf7, 0x05, 0x0f, 0x15, 0x21, 0xf9, 0xcb, + 0x46, 0xcf, 0x17, 0xd4, 0xe5, 0xcb, 0xfa, 0x30, 0x1c, 0xf0, 0x01, 0x02, 0xd0, + 0x20, 0xd7, 0xe2, 0x31, 0xe5, 0xeb, 0x2b, 0xf2, 0xf8, 0x27, 0x21, 0x1d, 0xf5, + 0x1c, 0x0e, 0x13, 0x08, 0x30, 0xcc, 0xe6, 0xcf, 0x16, 0xbd, 0xd3, 0xef, 0xfe, + 0x03, 0xe7, 0x7f, 0xdc, 0xf3, 0xd9, 0x1d, 0xd2, 0x2f, 0xf9, 0xde, 0x17, 0x26, + 0xd2, 0xed, 0x7e, 0xff, 0xcf, 0xd7, 0xf2, 0x2b, 0x38, 0x02, 0x34, 0x14, 0x18, + 0xbc, 0x3d, 0xda, 0xe2, 0xee, 0xda, 0xf8, 0xfd, 0xbf, 0xed, 0x0d, 0xf9, 0x19, + 0xe5, 0x01, 0x3a, 0x10, 0xbd, 0xda, 0xfe, 0xf2, 0x0e, 0x0d, 0xce, 0xf9, 0xc9, + 0x1e, 0xcf, 0xd4, 0xfd, 0xee, 0x65, 0xf8, 0x01, 0x40, 0x15, 0xe7, 0x52, 0xe7, + 0xe8, 0xe3, 0xef, 0x18, 0x13, 0xd1, 0xf1, 0xd2, 0xec, 0x18, 0xe9, 0x03, 0x0d, + 0x23, 0xf8, 0xf8, 0xe1, 0x3e, 0x12, 0xbb, 0xe5, 0xf9, 0x0b, 0x38, 0x2c, 0xf1, + 0xf7, 0x09, 0x27, 0xe7, 0x22, 0x01, 0xe2, 0xc7, 0xf9, 0xe0, 0xec, 0xfb, 0xf5, + 0x02, 0x02, 0xe2, 0xd1, 0x00, 0xf7, 0x22, 0xf0, 0x05, 0x00, 0x3c, 0x2a, 0xdb, + 0x43, 0x07, 0x48, 0x05, 0x0b, 0xd8, 0x37, 0x0d, 0x1c, 0xbe, 0x3f, 0x55, 0xf5, + 0x05, 0x31, 0xc5, 0xca, 0x03, 0x02, 0xcf, 0xf0, 0x15, 0x01, 0x20, 0x26, 0x0e, + 0x00, 0xd0, 0xc1, 0xcd, 0xf2, 0x09, 0xf8, 0xfa, 0x15, 0xf4, 0x0b, 0xd3, 0xed, + 0xd7, 0xd9, 0x0f, 0xf5, 0xde, 0xfb, 0xe7, 0xeb, 0x1d, 0x27, 0x30, 0x03, 0xd2, + 0xd9, 0xf7, 0x00, 0x11, 0x20, 0xf4, 0x26, 0xa6, 0x2d, 0xc0, 0xed, 0xf5, 0xb9, + 0x06, 0x19, 0x04, 0xc1, 0xfd, 0xce, 0x23, 0xcd, 0x27, 0x13, 0xaf, 0xd2, 0xda, + 0xe9, 0xdc, 0x17, 0x1b, 0x10, 0x38, 0x24, 0xcf, 0x42, 0xcf, 0xf6, 0x0d, 0x22, + 0xf7, 0x0a, 0xfa, 0xc1, 0x1d, 0xbf, 0x20, 0xaa, 0xe1, 0x1b, 0xc9, 0xd9, 0xbf, + 0xe0, 0xc0, 0xbb, 0x37, 0x2a, 0xcf, 0xf4, 0x0a, 0x33, 0xe5, 0x0d, 0xe7, 0x13, + 0x11, 0x1a, 0xf3, 0x13, 0xe8, 0xfc, 0x4a, 0xe8, 0x07, 0xf8, 0x3c, 0xbc, 0x04, + 0x73, 0xc6, 0xb6, 0x17, 0xf8, 0x95, 0xba, 0x02, 0x63, 0x3f, 0xf3, 0x48, 0x0f, + 0xcc, 0x23, 0x53, 0xf4, 0xe0, 0xaf, 0x0d, 0x2a, 0x3b, 0xd8, 0xd9, 0x7f, 0x29, + 0xdd, 0xe2, 0x28, 0x36, 0xea, 0x1d, 0xd3, 0xfc, 0xf9, 0xf1, 0x11, 0xea, 0xba, + 0x13, 0x4b, 0xef, 0xd1, 0x85, 0xe5, 0x09, 0x29, 0x04, 0x04, 0x1f, 0x41, 0xe6, + 0xf3, 0xf1, 0xc8, 0xd0, 0xfd, 0xce, 0x1e, 0xda, 0xfd, 0x09, 0xcf, 0xea, 0xf4, + 0xea, 0x16, 0xf5, 0xf9, 0xe4, 0x18, 0x1a, 0x02, 0x26, 0xef, 0x14, 0xf8, 0xd0, + 0xec, 0xc7, 0xd5, 0xb9, 0x08, 0x28, 0x5f, 0xed, 0x13, 0x2e, 0x92, 0xc1, 0xd9, + 0xbf, 0x02, 0x01, 0xf0, 0xe7, 0xfc, 0xab, 0x2b, 0xef, 0xfb, 0x03, 0xfd, 0xbe, + 0xe8, 0xff, 0xe3, 0x1c, 0xe0, 0xe2, 0xdc, 0x09, 0xf0, 0x60, 0xe1, 0xcc, 0x1a, + 0x43, 0x0e, 0xe8, 0xc6, 0x1f, 0xf5, 0x06, 0x28, 0xc6, 0x2c, 0x46, 0x5a, 0x0d, + 0xeb, 0x24, 0xfc, 0xcc, 0x0a, 0xd6, 0x19, 0x25, 0x4a, 0xd4, 0x1c, 0xf9, 0xf3, + 0xfa, 0x02, 0xd6, 0x0c, 0xe5, 0x2d, 0xf8, 0x22, 0xf9, 0xd4, 0xdb, 0xe3, 0x06, + 0xd6, 0x2b, 0xf3, 0xc8, 0x65, 0x22, 0x09, 0xc2, 0xb5, 0xd2, 0x35, 0xa1, 0xfd, + 0x19, 0x33, 0xe0, 0x56, 0xbd, 0x29, 0xe1, 0xe3, 0xb2, 0xdb, 0x25, 0xff, 0xe6, + 0xbc, 0xc5, 0xdc, 0xc8, 0xf1, 0xf1, 0x19, 0xea, 0xc5, 0xcd, 0xa8, 0xdc, 0xe2, + 0xeb, 0x0e, 0x44, 0x2c, 0xbe, 0xe9, 0x11, 0xf7, 0xba, 0x0a, 0x45, 0xe9, 0xe6, + 0x0a, 0x1c, 0xac, 0x10, 0xec, 0x23, 0x05, 0xd9, 0xd1, 0x13, 0x3b, 0xfe, 0xe5, + 0xe3, 0x05, 0xfe, 0xeb, 0xb3, 0xff, 0xd0, 0x16, 0xf9, 0xf6, 0x2c, 0x00, 0xfe, + 0xf3, 0x07, 0xca, 0x47, 0x0a, 0xda, 0xc1, 0xcd, 0x30, 0xf4, 0xf9, 0xfc, 0x00, + 0xa0, 0x26, 0x13, 0xda, 0xcb, 0x17, 0xb2, 0xee, 0x9a, 0xc4, 0xd3, 0x09, 0x45, + 0xc4, 0xab, 0xb2, 0x11, 0xf0, 0xee, 0x04, 0xfe, 0x21, 0xf2, 0x17, 0x36, 0x15, + 0xf3, 0x22, 0x0a, 0xe1, 0x0c, 0xea, 0xc0, 0xf0, 0xd7, 0x29, 0xee, 0xef, 0x18, + 0x0a, 0x92, 0x2e, 0xff, 0x0d, 0xf8, 0x14, 0xc1, 0x20, 0x99, 0xc0, 0xd9, 0xe8, + 0x04, 0xb2, 0xd4, 0x2e, 0x04, 0xcb, 0x09, 0x02, 0x1f, 0xdf, 0xc7, 0xf2, 0x1b, + 0x2d, 0x56, 0x16, 0xf5, 0x07, 0xf1, 0x2f, 0xea, 0xf3, 0xf7, 0x13, 0xb7, 0x1d, + 0x23, 0xdc, 0x38, 0xcb, 0xe5, 0xfb, 0x2a, 0x30, 0x32, 0x35, 0xe4, 0x20, 0x10, + 0xa7, 0x21, 0x0d, 0x02, 0xf1, 0x0c, 0xd2, 0x22, 0x0e, 0x02, 0x43, 0xea, 0xed, + 0xd1, 0xec, 0x7f, 0x00, 0xcd, 0x08, 0xef, 0x30, 0x04, 0xcd, 0xdb, 0xd5, 0x20, + 0x07, 0xdb, 0x00, 0xdf, 0x2e, 0xe6, 0xfb, 0xc3, 0xf7, 0xa6, 0xf4, 0x25, 0x24, + 0x17, 0x08, 0x50, 0x32, 0xe7, 0xfc, 0x15, 0x2b, 0xf8, 0x05, 0xc5, 0xb0, 0xd6, + 0xf0, 0xfe, 0x0d, 0xcb, 0xc2, 0xda, 0xef, 0xb8, 0x29, 0x15, 0x43, 0xc5, 0x21, + 0x20, 0x07, 0x04, 0xbe, 0xc4, 0x29, 0xc0, 0xd6, 0xac, 0xd6, 0xdc, 0x03, 0xe0, + 0xcc, 0xc0, 0xf7, 0xd0, 0x19, 0xc2, 0xd4, 0xc6, 0x2d, 0xee, 0xda, 0xd6, 0xa4, + 0xeb, 0xa2, 0xf3, 0x11, 0xa3, 0xf9, 0xc4, 0x3c, 0x3c, 0x0f, 0xc8, 0xcf, 0xe0, + 0x18, 0xe0, 0x33, 0xe5, 0xc8, 0xea, 0xf0, 0x16, 0xff, 0xd7, 0x0c, 0x1d, 0x11, + 0xf6, 0x12, 0x13, 0xf4, 0xf6, 0xac, 0xf8, 0xe7, 0x01, 0xd7, 0xf3, 0xfd, 0xdb, + 0xf8, 0xf5, 0xde, 0xd9, 0xd0, 0xfb, 0xfc, 0xf1, 0x2e, 0x02, 0x2c, 0xeb, 0xc7, + 0x0c, 0x0e, 0xfc, 0xda, 0x26, 0xd5, 0xf0, 0xd4, 0x14, 0xb9, 0x0d, 0xe6, 0x2a, + 0x03, 0xfa, 0x06, 0xd8, 0x7f, 0xff, 0xc7, 0x12, 0x21, 0xdc, 0x27, 0xe5, 0xeb, + 0x3e, 0xcb, 0x16, 0xd8, 0xd7, 0x33, 0xec, 0x1a, 0xf6, 0xec, 0xf3, 0x29, 0xd9, + 0xd2, 0xea, 0x16, 0xc0, 0x26, 0xf1, 0xdf, 0x0c, 0xdd, 0x41, 0xf2, 0xc8, 0xcd, + 0x09, 0xd6, 0x0f, 0xfb, 0x36, 0x1b, 0xeb, 0x02, 0x2f, 0xb7, 0x1a, 0xdb, 0xdc, + 0x2b, 0xfe, 0xdb, 0xe8, 0xd1, 0xca, 0x16, 0xff, 0x18, 0xf4, 0xf5, 0xd1, 0xdc, + 0xf8, 0xed, 0xda, 0x34, 0x02, 0xe9, 0x15, 0x1c, 0xc3, 0x16, 0x2c, 0x0f, 0xbd, + 0x13, 0x06, 0xfa, 0xe2, 0xda, 0xa4, 0xed, 0x18, 0xe4, 0xf6, 0xfb, 0xd6, 0x18, + 0x16, 0x02, 0xf9, 0xcb, 0xca, 0xf9, 0xfe, 0xf7, 0xe9, 0xd3, 0xe7, 0x3a, 0xe8, + 0xda, 0xf6, 0xf5, 0xe9, 0xdd, 0x32, 0xe0, 0xee, 0x2b, 0x1f, 0xea, 0xff, 0x1e, + 0xdb, 0xda, 0x09, 0x15, 0x2d, 0x0f, 0x0b, 0xfe, 0xf8, 0x1d, 0x07, 0x05, 0xf6, + 0x1b, 0xef, 0xbf, 0x22, 0x11, 0xd7, 0xee, 0xed, 0x0f, 0xb6, 0xdc, 0xfb, 0x33, + 0xea, 0x02, 0xe3, 0x16, 0xc6, 0x24, 0x02, 0xfa, 0x12, 0xfd, 0xc1, 0xf7, 0x1a, + 0xf6, 0xfb, 0xd3, 0x09, 0x25, 0xd9, 0x2f, 0xe8, 0xf9, 0x0a, 0xf0, 0xf6, 0x31, + 0x3d, 0x22, 0x31, 0xef, 0xdd, 0x12, 0x09, 0x02, 0xf5, 0xfd, 0xde, 0x11, 0x23, + 0x2c, 0x0d, 0xb9, 0x06, 0xf8, 0xe9, 0x1b, 0xe5, 0x04, 0x1b, 0xe7, 0x0f, 0xe4, + 0x06, 0xf9, 0x2e, 0x19, 0xd6, 0x20, 0x1c, 0xb9, 0xf7, 0xc0, 0x08, 0xe2, 0xdb, + 0xf6, 0x00, 0xed, 0xf9, 0x34, 0xec, 0xe7, 0xc5, 0x2c, 0x0d, 0x1d, 0xb8, 0xdc, + 0x19, 0xd3, 0x30, 0x08, 0x3a, 0xf4, 0x12, 0xd3, 0x12, 0x03, 0xdc, 0xb1, 0x06, + 0x18, 0x3a, 0x1f, 0xc5, 0xea, 0x19, 0xf1, 0xea, 0xfe, 0xef, 0xd1, 0xcf, 0x22, + 0xe8, 0x24, 0x28, 0xc9, 0x40, 0x02, 0x1e, 0x0f, 0xcb, 0x0c, 0x28, 0x35, 0xca, + 0xad, 0xe5, 0x35, 0x0d, 0x1b, 0xe6, 0x0c, 0x11, 0xe0, 0x28, 0x35, 0x13, 0x09, + 0xdd, 0x05, 0x3e, 0xf9, 0x0c, 0xd9, 0xdc, 0x0a, 0xb2, 0x11, 0xc7, 0xf7, 0x28, + 0xd4, 0xdc, 0xed, 0xd3, 0x18, 0xed, 0x14, 0x39, 0x0c, 0x1f, 0xfc, 0xf0, 0x1d, + 0xf5, 0xa4, 0x3a, 0x37, 0x3e, 0x26, 0xd4, 0x28, 0xe6, 0xdf, 0x5f, 0x15, 0x11, + 0xf5, 0x20, 0x0d, 0xf1, 0x01, 0x05, 0x03, 0x19, 0x1e, 0x06, 0x48, 0xef, 0xe4, + 0x21, 0xde, 0xfe, 0xdc, 0xe4, 0xc2, 0x0d, 0xd7, 0xe1, 0x0c, 0xca, 0x13, 0x2d, + 0x0d, 0xf1, 0xed, 0xba, 0xe6, 0xae, 0xf5, 0x29, 0x00, 0xcc, 0xfa, 0x07, 0x46, + 0x15, 0xd8, 0xd0, 0xd9, 0xec, 0xe4, 0xca, 0xde, 0xf9, 0xd1, 0xef, 0xc9, 0xe2, + 0x0e, 0xd2, 0xfe, 0x04, 0x1a, 0x18, 0xf3, 0x2e, 0xfa, 0x15, 0x67, 0xfd, 0xc3, + 0xf4, 0xc7, 0xec, 0xdd, 0x19, 0x0c, 0xd9, 0xfd, 0xd6, 0xd8, 0x45, 0xe3, 0xe1, + 0xed, 0xe6, 0xf7, 0xd9, 0xda, 0xea, 0x1c, 0x41, 0x13, 0x25, 0x0e, 0x02, 0xfa, + 0xc3, 0xde, 0x68, 0x00, 0xfa, 0x01, 0x1e, 0xc5, 0xf9, 0x14, 0x11, 0xda, 0xf5, + 0xec, 0xf9, 0xc8, 0xf7, 0xf4, 0xd4, 0x18, 0xf3, 0xd8, 0xe8, 0x0e, 0x0e, 0x02, + 0xea, 0x07, 0x3d, 0xb8, 0x2f, 0xd5, 0xfd, 0xe3, 0xf4, 0x66, 0x28, 0xfa, 0x20, + 0x03, 0x1f, 0xf1, 0xd4, 0xcc, 0xd4, 0x13, 0xd5, 0x7f, 0x0a, 0xee, 0x02, 0x18, + 0x2c, 0x00, 0xea, 0x3e, 0x18, 0x09, 0xf6, 0x06, 0x46, 0xfe, 0xed, 0xb6, 0xff, + 0xec, 0xe5, 0xc6, 0x26, 0x07, 0x1f, 0xff, 0xfe, 0x04, 0x21, 0x0a, 0x01, 0xe7, + 0xc5, 0xf5, 0x2d, 0xe8, 0x1a, 0x1e, 0xe6, 0xd7, 0xfa, 0xe5, 0xee, 0x01, 0x1e, + 0xbd, 0x15, 0x08, 0x4d, 0xdd, 0x01, 0x0d, 0x17, 0xbf, 0x0b, 0xe5, 0x1a, 0xbb, + 0xc3, 0xb7, 0xd6, 0x0e, 0xf1, 0xed, 0x15, 0x39, 0x21, 0x2b, 0x27, 0x0e, 0x04, + 0xd5, 0xe0, 0xf8, 0xeb, 0xb0, 0xd5, 0xde, 0x10, 0x08, 0xcb, 0xf7, 0x15, 0xe5, + 0x1c, 0xa3, 0xdb, 0x31, 0xcb, 0xdb, 0x4e, 0x30, 0xea, 0x18, 0x41, 0xdc, 0x09, + 0xcf, 0x0e, 0xf9, 0x04, 0xc4, 0xc8, 0xe1, 0x08, 0x46, 0x05, 0xd3, 0xec, 0xb9, + 0xd8, 0x00, 0x58, 0xeb, 0x3a, 0xb3, 0xc8, 0xf1, 0x0d, 0x08, 0x1f, 0x06, 0xdb, + 0xf6, 0xf8, 0xcd, 0x24, 0xd9, 0x1a, 0x18, 0x0a, 0xe5, 0xe4, 0x2d, 0x13, 0xee, + 0x18, 0xaf, 0xba, 0xd1, 0x0c, 0xea, 0x0f, 0x17, 0xec, 0xbc, 0x7e, 0x2e, 0x08, + 0xc5, 0xe4, 0xeb, 0xd9, 0xf4, 0xc8, 0xea, 0xca, 0xc8, 0xe6, 0x33, 0x81, 0x13, + 0x06, 0xf5, 0xf0, 0xf9, 0x3c, 0xe8, 0xd3, 0xde, 0xc6, 0x00, 0x2e, 0xf2, 0xe4, + 0x27, 0xe0, 0xb9, 0xf3, 0xff, 0x2d, 0xd7, 0xf5, 0x1a, 0xcb, 0xe9, 0xf8, 0x43, + 0x03, 0x05, 0x08, 0xce, 0xfd, 0xf7, 0xd0, 0x0c, 0xfb, 0xe5, 0xd4, 0xaa, 0x19, + 0xd2, 0xd7, 0x11, 0xed, 0xce, 0xf3, 0xe6, 0xe0, 0xf7, 0xc7, 0xde, 0xb2, 0x0e, + 0xc4, 0x08, 0x38, 0xf3, 0xe7, 0xe8, 0xf8, 0xef, 0xec, 0x0a, 0x41, 0x00, 0x01, + 0xec, 0xec, 0xe3, 0x03, 0x31, 0xaa, 0x1d, 0x1c, 0xff, 0x2d, 0xb8, 0x3c, 0xb1, + 0xdf, 0xfb, 0xd1, 0x28, 0xf1, 0xe3, 0xf4, 0xe4, 0x2e, 0xcf, 0xe2, 0xba, 0x11, + 0x26, 0xbf, 0x01, 0xb1, 0xd2, 0xc2, 0x0e, 0x88, 0xed, 0x14, 0x0a, 0xdf, 0x48, + 0xba, 0x16, 0xbc, 0xe2, 0x18, 0xb9, 0xf5, 0xe2, 0xd2, 0x06, 0x14, 0xec, 0x8c, + 0xdf, 0x1b, 0x13, 0xd7, 0xcf, 0xf7, 0xd9, 0xc2, 0xd3, 0xdb, 0xff, 0xf2, 0x46, + 0xe1, 0xe3, 0xcd, 0xa2, 0xf0, 0xef, 0x24, 0xf8, 0x14, 0xe0, 0x12, 0x07, 0xbd, + 0xf8, 0x16, 0xf6, 0x0f, 0xa7, 0x0c, 0xb7, 0xab, 0xe3, 0xd8, 0x9c, 0xed, 0x08, + 0x20, 0x16, 0x1b, 0x27, 0x19, 0xb7, 0x02, 0xda, 0xd1, 0xf6, 0xb3, 0x25, 0xaa, + 0xe2, 0x13, 0x1d, 0xfe, 0xf1, 0xc0, 0xdc, 0xc6, 0xf9, 0x17, 0xd4, 0xf8, 0xe4, + 0xfb, 0xdb, 0xa6, 0xed, 0xf6, 0x03, 0x2f, 0xd5, 0xe1, 0xb3, 0xb3, 0x13, 0xec, + 0x06, 0xde, 0xee, 0x06, 0xbe, 0x1f, 0x08, 0x1a, 0x23, 0x04, 0xd1, 0xb8, 0x07, + 0xb8, 0xe3, 0x13, 0x0f, 0x18, 0x05, 0xc0, 0xd5, 0xf8, 0x35, 0xa4, 0x22, 0xe3, + 0xf2, 0x0d, 0x0f, 0xd4, 0xfc, 0xb2, 0xd6, 0xdc, 0xeb, 0xd1, 0x1e, 0x30, 0xb9, + 0xcf, 0xff, 0x0f, 0xe6, 0x0a, 0xc7, 0xea, 0x0a, 0x37, 0x8f, 0x21, 0x1e, 0xaf, + 0x29, 0x1d, 0xe6, 0xda, 0x26, 0x14, 0x1d, 0x66, 0xe9, 0xab, 0xcc, 0xed, 0xa5, + 0xd6, 0x2c, 0xff, 0xf6, 0x04, 0xcc, 0xda, 0xf3, 0x1f, 0xdc, 0x00, 0x35, 0xce, + 0xde, 0xb5, 0x15, 0xf3, 0xbb, 0x01, 0xce, 0xea, 0xcd, 0xdc, 0xff, 0x00, 0x09, + 0xc2, 0x04, 0xee, 0xcb, 0x37, 0xf0, 0xf5, 0xaa, 0xac, 0xef, 0xc8, 0xbe, 0x10, + 0xfe, 0xdd, 0x37, 0x1f, 0x23, 0xdf, 0xee, 0x98, 0xf6, 0x0b, 0x02, 0xeb, 0xff, + 0xea, 0x10, 0xcd, 0xf6, 0xc6, 0x18, 0xc7, 0xd2, 0x33, 0x35, 0xff, 0x22, 0x03, + 0x9b, 0x51, 0xc3, 0x00, 0x76, 0xc6, 0xf6, 0xbe, 0xd2, 0x27, 0xf4, 0xf8, 0x28, + 0x09, 0x22, 0x16, 0xea, 0xb1, 0x02, 0xe6, 0x7f, 0x2e, 0xe4, 0xfa, 0x0e, 0x07, + 0xf1, 0xc0, 0xe0, 0xec, 0xff, 0xef, 0xd8, 0x17, 0x9f, 0xd0, 0xdf, 0xf8, 0xef, + 0xec, 0xd1, 0x10, 0xf4, 0xfd, 0xf6, 0x13, 0xd4, 0xe3, 0x66, 0xea, 0xfe, 0x3b, + 0xfe, 0xfc, 0x19, 0x20, 0x22, 0x08, 0xc4, 0xf9, 0x0b, 0xdc, 0x02, 0xd6, 0xe9, + 0x29, 0x19, 0xdc, 0xe5, 0xf4, 0x58, 0xef, 0x24, 0xd3, 0xdf, 0xb7, 0x36, 0xf5, + 0x22, 0xc4, 0xde, 0xce, 0xd7, 0x39, 0x20, 0x06, 0x08, 0xf4, 0xc7, 0x30, 0xfa, + 0xe6, 0xe6, 0xc7, 0x08, 0xfb, 0x22, 0xb9, 0x0d, 0x1b, 0x1a, 0x17, 0xe4, 0x18, + 0xcd, 0xe0, 0x11, 0xe6, 0x1d, 0xf5, 0xcc, 0xc0, 0xea, 0xd8, 0x32, 0xf0, 0xe7, + 0x5a, 0xf5, 0xc9, 0xff, 0xee, 0xca, 0x32, 0xec, 0xf8, 0x2c, 0x0c, 0xd3, 0xd7, + 0x30, 0x0c, 0xe5, 0xd7, 0xf5, 0x18, 0xe6, 0xe7, 0x27, 0x0a, 0x10, 0xcb, 0x0c, + 0xe7, 0xef, 0x15, 0xe5, 0xea, 0xff, 0x13, 0xeb, 0xd3, 0x14, 0x14, 0x01, 0x0f, + 0x0f, 0x07, 0xe1, 0xfc, 0x93, 0xcc, 0x0c, 0x32, 0xea, 0x1c, 0x06, 0x16, 0xd7, + 0xec, 0x13, 0xe3, 0x7f, 0x27, 0xe9, 0x32, 0x0f, 0xfa, 0x51, 0x1b, 0xba, 0xfb, + 0x2d, 0x03, 0x16, 0xfd, 0x05, 0xd8, 0x10, 0x0d, 0xbc, 0x0f, 0x18, 0x01, 0xe1, + 0xea, 0xe5, 0x2a, 0xe9, 0xe2, 0xec, 0xf8, 0xf6, 0x57, 0xf2, 0xf2, 0x05, 0x06, + 0xf6, 0xde, 0x1c, 0xe6, 0x03, 0xfa, 0xec, 0xcb, 0x0e, 0x19, 0x1a, 0x23, 0x01, + 0xda, 0xfe, 0xe4, 0xbf, 0x14, 0x00, 0xf3, 0x0c, 0x42, 0x11, 0x00, 0x0a, 0x2f, + 0xf3, 0xbf, 0x09, 0xd8, 0x19, 0xf6, 0xe4, 0xe2, 0x15, 0x55, 0xdd, 0xeb, 0xcc, + 0x14, 0xd3, 0x22, 0xee, 0xd7, 0xf6, 0x05, 0xed, 0x05, 0x02, 0xea, 0x02, 0xc3, + 0xe8, 0xee, 0x07, 0x0c, 0x10, 0xda, 0xfb, 0xe9, 0x05, 0xf0, 0xd0, 0xe7, 0xd2, + 0x05, 0xfc, 0xdc, 0xf0, 0xec, 0xff, 0xe9, 0xec, 0xc0, 0xc8, 0xe1, 0xf0, 0xf9, + 0xe0, 0xfd, 0x1e, 0xd6, 0xbe, 0xf4, 0xfa, 0xdd, 0xc6, 0x1d, 0xfe, 0xff, 0x06, + 0xda, 0x0b, 0xf9, 0xdf, 0xf2, 0xfb, 0xf3, 0xfe, 0xe7, 0x09, 0x00, 0x1a, 0x23, + 0xfd, 0xe3, 0x33, 0xfd, 0xf9, 0x10, 0x01, 0x1b, 0xdf, 0xf0, 0xcb, 0x09, 0x16, + 0x13, 0xd4, 0x0b, 0xd1, 0xec, 0xeb, 0xef, 0x13, 0x12, 0xbe, 0x20, 0xd2, 0xf0, + 0xce, 0xfe, 0xf1, 0xd3, 0x0e, 0x2c, 0xd4, 0x0e, 0xf5, 0x25, 0xd3, 0xf6, 0xeb, + 0xee, 0xc9, 0x14, 0xea, 0xd7, 0xe1, 0xea, 0x09, 0x3b, 0xfc, 0xca, 0x17, 0xd3, + 0xf1, 0x20, 0xaf, 0xf1, 0x1c, 0xbf, 0xe1, 0xe5, 0x04, 0xc2, 0xf5, 0x1a, 0xe9, + 0xf0, 0xd9, 0xf5, 0x11, 0xfd, 0xe5, 0xf2, 0x16, 0x07, 0x12, 0x33, 0xb6, 0x31, + 0xc7, 0xef, 0xdb, 0x0a, 0x18, 0xc5, 0xfd, 0xea, 0xf7, 0x11, 0x07, 0xe8, 0xfb, + 0xf4, 0xfd, 0x07, 0xd5, 0x0f, 0xbe, 0x12, 0x19, 0xfd, 0xf9, 0xd7, 0xd0, 0x05, + 0x26, 0xd1, 0xf5, 0xe4, 0xe0, 0xf2, 0x1a, 0xf6, 0xdb, 0xe5, 0xd9, 0x2c, 0x14, + 0x1a, 0x2f, 0xed, 0xd2, 0x2a, 0x2e, 0x13, 0xf9, 0xe1, 0xa3, 0xf8, 0xe3, 0xe6, + 0xdf, 0xcc, 0xe5, 0x0d, 0x03, 0xd9, 0xf2, 0xf3, 0x1c, 0x2e, 0xf5, 0x1c, 0x21, + 0xd5, 0xe2, 0x21, 0xdb, 0x0b, 0x02, 0xef, 0x03, 0xff, 0xf2, 0xde, 0xdc, 0xe5, + 0xd7, 0x02, 0xe1, 0xf1, 0x04, 0xf5, 0x05, 0xd5, 0xf1, 0x09, 0xe4, 0xcf, 0xfc, + 0xf8, 0x05, 0xd0, 0xdc, 0x15, 0xea, 0x28, 0x2b, 0x1c, 0x0c, 0xe5, 0xee, 0xb8, + 0xf3, 0x11, 0xf1, 0xf7, 0xe7, 0x03, 0xc0, 0x0a, 0xd5, 0x1f, 0xcf, 0x18, 0xf1, + 0xea, 0x02, 0xd1, 0xe8, 0xd6, 0xfe, 0xfd, 0xee, 0x02, 0x31, 0x0f, 0xc3, 0xeb, + 0x08, 0xcf, 0xfd, 0xd1, 0xf0, 0x0a, 0x1c, 0x15, 0xf6, 0xae, 0xc3, 0x07, 0x49, + 0xe6, 0xe0, 0x03, 0xde, 0xbc, 0xf7, 0xd6, 0xf4, 0x81, 0x3f, 0xee, 0xd5, 0x96, + 0xe3, 0x14, 0x74, 0xf7, 0x02, 0x04, 0xf3, 0xda, 0x1b, 0x3c, 0x27, 0x10, 0xf0, + 0x4a, 0xc6, 0x98, 0x51, 0xfa, 0x0f, 0x27, 0x11, 0xb0, 0xa0, 0x07, 0xef, 0x4f, + 0xef, 0x1c, 0xdf, 0xde, 0xcf, 0xf2, 0x43, 0xd7, 0xe9, 0x92, 0x0e, 0xe5, 0xf7, + 0xe3, 0x93, 0xbb, 0xd7, 0xe8, 0xda, 0x10, 0x15, 0x09, 0xf3, 0xdb, 0x05, 0xe3, + 0xe2, 0xd3, 0x63, 0x89, 0x01, 0xc9, 0x3b, 0x24, 0xcc, 0x47, 0x06, 0x06, 0x2c, + 0x0c, 0xe4, 0xe2, 0x8f, 0x04, 0x05, 0x1e, 0xc2, 0xdd, 0xf8, 0x60, 0x0b, 0x06, + 0x23, 0x30, 0xed, 0x2d, 0x26, 0x1f, 0x0d, 0xca, 0x33, 0x35, 0x2f, 0xed, 0x4a, + 0x07, 0xef, 0x09, 0xd3, 0x9e, 0xc6, 0x35, 0xd9, 0xde, 0x00, 0x13, 0x58, 0x0b, + 0xfb, 0xe3, 0x0b, 0x08, 0x06, 0xd1, 0x33, 0xea, 0xaf, 0xe6, 0xd5, 0x67, 0xe3, + 0xb9, 0xf7, 0x1f, 0x0e, 0xf2, 0xbf, 0x58, 0x06, 0xff, 0xa3, 0xc6, 0xf4, 0x42, + 0xc8, 0xfd, 0x28, 0x1d, 0x09, 0x22, 0x21, 0xe8, 0xd7, 0xf2, 0x0c, 0x8b, 0xa0, + 0x0b, 0x00, 0xbf, 0xe4, 0xce, 0xf6, 0x65, 0xf3, 0xfc, 0x25, 0x18, 0xf4, 0x02, + 0xd4, 0x10, 0x02, 0x34, 0xd3, 0xf6, 0xbb, 0x1e, 0x02, 0x0c, 0x1f, 0x16, 0x9a, + 0x5c, 0xc0, 0xd1, 0xd0, 0x04, 0xf9, 0xfc, 0x9d, 0xa5, 0xf2, 0x08, 0x3e, 0xc8, + 0xce, 0x0e, 0x0f, 0xcb, 0xc8, 0xfa, 0x3e, 0xe2, 0xbe, 0x0f, 0x51, 0xdb, 0x3b, + 0x07, 0xf4, 0xdf, 0x25, 0x1b, 0x15, 0x1b, 0x07, 0xf0, 0x28, 0x07, 0x81, 0xef, + 0xfe, 0xe5, 0xa1, 0x29, 0xc6, 0xdc, 0x0a, 0xf2, 0x00, 0xb1, 0xd8, 0x15, 0x04, + 0x50, 0x45, 0x1b, 0xf9, 0xf4, 0xe8, 0x07, 0xc3, 0xce, 0x3c, 0xde, 0x47, 0x10, + 0x01, 0x2f, 0x23, 0xf7, 0xd4, 0xd4, 0xd8, 0xfe, 0x45, 0xea, 0x23, 0x1b, 0x10, + 0xd2, 0x24, 0xdc, 0x0c, 0x00, 0x25, 0xfb, 0xa3, 0xe4, 0xf6, 0xcf, 0x5e, 0xfd, + 0x13, 0xd1, 0xf4, 0xe7, 0xe6, 0xc1, 0xb9, 0xc4, 0xc6, 0x1c, 0x8e, 0x09, 0x3a, + 0xda, 0x03, 0xf4, 0xe5, 0x35, 0xfc, 0x08, 0xee, 0x81, 0xf1, 0x20, 0x11, 0xf2, + 0xcd, 0xb2, 0x2a, 0x28, 0x31, 0x25, 0xb4, 0xf6, 0x21, 0xd2, 0xf9, 0xa5, 0xf7, + 0xb8, 0xf2, 0x12, 0x02, 0x29, 0x3b, 0x08, 0xc4, 0xbb, 0xe3, 0xce, 0x16, 0xc9, + 0x20, 0xd7, 0x47, 0x0c, 0xa6, 0x10, 0x18, 0xfb, 0x4f, 0xc0, 0xc1, 0x17, 0xd8, + 0xb9, 0xf4, 0xd9, 0xcf, 0x07, 0x2a, 0x2e, 0x10, 0xfc, 0x22, 0x4f, 0x94, 0x2b, + 0x15, 0x1b, 0xbe, 0xb0, 0xa6, 0x37, 0xf1, 0x19, 0xdb, 0xe3, 0xe4, 0xfc, 0x26, + 0xee, 0xe0, 0x2b, 0xdd, 0xba, 0x1e, 0x06, 0x05, 0xbe, 0xe6, 0xc5, 0x1f, 0xd0, + 0xce, 0xb5, 0xd0, 0xfd, 0xbf, 0x9d, 0xcd, 0x1f, 0xe8, 0x5f, 0xd7, 0xb1, 0xf6, + 0x0d, 0xb5, 0x4c, 0x0b, 0xd2, 0xf5, 0x1f, 0x04, 0xe6, 0x12, 0xcf, 0xbb, 0xe6, + 0xf3, 0xcb, 0x3d, 0x24, 0xc1, 0xe6, 0x97, 0xa3, 0xf4, 0x3b, 0xd3, 0x13, 0x34, + 0xbc, 0x23, 0x2b, 0x19, 0xb2, 0x45, 0xc4, 0xb7, 0xe7, 0x3b, 0xf0, 0xf0, 0x02, + 0xab, 0xc8, 0x95, 0x32, 0x14, 0x0a, 0x4e, 0xba, 0x4b, 0x2a, 0x9c, 0xf4, 0xe1, + 0xfe, 0xe9, 0x2d, 0xe9, 0x3c, 0xed, 0x03, 0xf8, 0x11, 0xf5, 0xed, 0x0b, 0x1a, + 0x16, 0x06, 0x25, 0xb1, 0xb5, 0xdc, 0x3e, 0xea, 0x38, 0x40, 0xa5, 0xfe, 0xd6, + 0x48, 0x0f, 0x9e, 0xd1, 0xc4, 0x3b, 0x0b, 0xb1, 0xe6, 0x1b, 0x0a, 0xc0, 0xdd, + 0x0e, 0xaa, 0x66, 0x02, 0x11, 0xfb, 0xff, 0x0a, 0xc2, 0xb3, 0xf6, 0xfa, 0xe7, + 0x67, 0x0a, 0x08, 0x22, 0xf5, 0x41, 0x0d, 0xc3, 0xda, 0x0b, 0x14, 0x3c, 0xf2, + 0xcc, 0xf6, 0x33, 0xe7, 0x50, 0xfa, 0xa4, 0x2a, 0x16, 0x27, 0x2a, 0x9c, 0x33, + 0xd2, 0xbf, 0xcf, 0x02, 0xf6, 0xba, 0xf5, 0xcf, 0x1e, 0xf0, 0xd7, 0xb0, 0xe2, + 0x81, 0xf9, 0x02, 0xb9, 0x02, 0xe5, 0xe9, 0xf7, 0xd2, 0xf2, 0xe2, 0x06, 0xfc, + 0xe0, 0x03, 0x0a, 0x30, 0xd9, 0xef, 0x24, 0xc4, 0xf0, 0xbc, 0xf9, 0xdb, 0x0c, + 0xd5, 0x09, 0x03, 0x43, 0xbc, 0x4e, 0xf7, 0x08, 0x00, 0x15, 0xec, 0x19, 0xc9, + 0xe6, 0xc0, 0xd4, 0x03, 0x00, 0xe0, 0xd0, 0xa1, 0x16, 0xeb, 0x0f, 0x2e, 0xfe, + 0x02, 0x04, 0xcf, 0x07, 0xda, 0x32, 0x0d, 0xf8, 0xbe, 0x1a, 0x34, 0x15, 0x35, + 0xea, 0xe9, 0xff, 0xdd, 0xe5, 0x2a, 0xc9, 0xfe, 0x19, 0xf8, 0xbe, 0xd2, 0x25, + 0xea, 0xe2, 0xf5, 0x26, 0xe0, 0xb6, 0xfb, 0xe4, 0xd0, 0x22, 0x37, 0x22, 0x8f, + 0x11, 0xe6, 0xe1, 0x1a, 0x0a, 0xbf, 0xd8, 0xe3, 0xd1, 0xee, 0xd8, 0x32, 0x4a, + 0xb1, 0xce, 0xec, 0xde, 0xee, 0xcc, 0x25, 0x07, 0xf4, 0x33, 0x02, 0xf9, 0x33, + 0x23, 0xd0, 0xf6, 0xd1, 0x08, 0xdd, 0xe4, 0xd9, 0xbe, 0xe1, 0x2d, 0xc3, 0xed, + 0x03, 0xbc, 0x3b, 0xc3, 0xd0, 0x44, 0x08, 0x14, 0xcb, 0xca, 0xa6, 0xb1, 0xe9, + 0xa6, 0xf5, 0x41, 0x39, 0xf4, 0x01, 0xed, 0x4f, 0x1d, 0xed, 0xc5, 0x40, 0x2c, + 0x29, 0xd1, 0x45, 0x0a, 0xe1, 0x32, 0x50, 0xf5, 0x31, 0x10, 0x05, 0xdd, 0xfc, + 0xbc, 0x20, 0x2c, 0x0e, 0xdb, 0xf7, 0xfc, 0xf6, 0xa9, 0xcb, 0xff, 0xf1, 0xc8, + 0xd6, 0xec, 0xb1, 0xd8, 0xbb, 0x3d, 0xf9, 0xec, 0x03, 0xe1, 0x12, 0xbb, 0xeb, + 0x1d, 0x1e, 0xea, 0xed, 0xf1, 0x0e, 0x11, 0xe5, 0x05, 0xf1, 0xf7, 0x13, 0x29, + 0xcb, 0x0e, 0xc0, 0xec, 0xf7, 0x09, 0x01, 0xb4, 0x00, 0x3e, 0xc2, 0x23, 0xeb, + 0x1f, 0xbe, 0xaf, 0x0f, 0xbe, 0x09, 0xc2, 0xf5, 0xe6, 0x9e, 0x04, 0xbe, 0xd1, + 0xea, 0xd6, 0x28, 0xaa, 0x06, 0xd8, 0x03, 0xe8, 0xf6, 0xc6, 0x24, 0x10, 0xe0, + 0xe1, 0x17, 0xdd, 0xe0, 0x0c, 0x0a, 0xf9, 0xf8, 0xd3, 0x4a, 0x13, 0xd1, 0x0b, + 0x24, 0x17, 0xd3, 0x04, 0xd9, 0x10, 0x37, 0xc2, 0x67, 0xf6, 0xf4, 0xeb, 0x0c, + 0x1d, 0x24, 0x12, 0x1f, 0x09, 0x42, 0xff, 0x32, 0xe7, 0xca, 0x2a, 0x04, 0x40, + 0x30, 0xe8, 0xfb, 0xc2, 0xfc, 0xe7, 0x0b, 0xf8, 0x2c, 0xed, 0x0a, 0x13, 0x4e, + 0xc5, 0x2d, 0x30, 0xe7, 0x26, 0xcb, 0x09, 0x53, 0xfc, 0xf2, 0xd4, 0xd7, 0x0a, + 0xee, 0x05, 0x12, 0x25, 0xff, 0x0d, 0xd3, 0xd9, 0x17, 0x0f, 0xf8, 0x1f, 0x26, + 0x06, 0x02, 0x0f, 0x20, 0x09, 0x33, 0x10, 0x12, 0x09, 0xfd, 0xf6, 0xde, 0x7f, + 0x12, 0xf4, 0x0f, 0xc0, 0x05, 0xce, 0x0e, 0x05, 0xf7, 0xd9, 0x14, 0xe3, 0x07, + 0xa0, 0x2e, 0x23, 0x43, 0xfd, 0xf8, 0xdb, 0xfd, 0xec, 0xdb, 0xaf, 0xe6, 0x23, + 0x0b, 0xd6, 0x09, 0xe3, 0x14, 0x13, 0x07, 0xe5, 0xd3, 0x43, 0x13, 0x18, 0xff, + 0xec, 0x00, 0xe9, 0xf8, 0xc7, 0xeb, 0xe2, 0xfd, 0x09, 0x35, 0x22, 0x36, 0x18, + 0xf0, 0x1b, 0x0c, 0x02, 0xf3, 0xa8, 0xdb, 0xe1, 0xfd, 0x06, 0xdf, 0x12, 0xc3, + 0xf1, 0xf0, 0xbe, 0x0c, 0x2b, 0x3b, 0x38, 0x33, 0x5f, 0x7c, 0xf6, 0x08, 0xf8, + 0xee, 0xb7, 0x03, 0x26, 0x5e, 0xf6, 0xfa, 0xd8, 0x18, 0x07, 0x03, 0xfe, 0x1e, + 0xee, 0x38, 0xb0, 0x0c, 0x2c, 0xc6, 0x22, 0xe0, 0x05, 0x11, 0x01, 0xff, 0x03, + 0x0f, 0x08, 0x19, 0xfa, 0x03, 0xb2, 0xd7, 0x40, 0x2c, 0x0c, 0x0b, 0x24, 0x08, + 0xb3, 0x36, 0xd4, 0xbe, 0xeb, 0xe2, 0x1e, 0xfc, 0xf7, 0xe6, 0x08, 0xfa, 0xed, + 0xcf, 0x09, 0xb3, 0x30, 0xf4, 0xfb, 0x16, 0xf7, 0x1c, 0xfd, 0x2a, 0xd5, 0xff, + 0xf5, 0xf7, 0xee, 0x25, 0x04, 0x08, 0x05, 0xdc, 0xe3, 0xef, 0xc4, 0x1a, 0x02, + 0xd2, 0xf6, 0x4c, 0xb3, 0xf7, 0xc8, 0xf3, 0x36, 0xff, 0xe7, 0x33, 0xd2, 0xf9, + 0xf6, 0x0c, 0x88, 0x09, 0xb3, 0xe2, 0xc7, 0xe7, 0xf8, 0x27, 0xda, 0xbc, 0xf1, + 0xac, 0xf9, 0x0f, 0xc5, 0xba, 0xe3, 0xb1, 0x04, 0xfb, 0xfc, 0x40, 0x2e, 0xde, + 0xb6, 0xdc, 0xbb, 0x25, 0x2b, 0x0f, 0x1c, 0x21, 0xf3, 0x31, 0x15, 0xf2, 0x25, + 0xf1, 0xe0, 0xc5, 0x22, 0xc3, 0xed, 0xdc, 0x4d, 0xdb, 0xf3, 0xd3, 0x55, 0x38, + 0xf3, 0xd7, 0xac, 0xf3, 0x04, 0xa4, 0x3c, 0xd2, 0xee, 0xe1, 0xd7, 0xfc, 0xde, + 0xdb, 0xe8, 0xd6, 0x0a, 0xb3, 0x65, 0x0d, 0x2e, 0xca, 0xfe, 0xe9, 0xca, 0xc4, + 0x81, 0x16, 0x47, 0xb6, 0x5d, 0xcf, 0xac, 0x39, 0xff, 0x38, 0xdb, 0x49, 0xcd, + 0xe0, 0x34, 0x07, 0x4e, 0xc1, 0x0c, 0x1f, 0xb6, 0xaa, 0x1e, 0x2d, 0x0e, 0x29, + 0xed, 0x30, 0xdc, 0xba, 0xc7, 0xf4, 0x2f, 0x6e, 0xbe, 0x31, 0xf8, 0xdd, 0xb8, + 0x05, 0xfc, 0xee, 0xe8, 0xda, 0x0b, 0xb7, 0xf7, 0x02, 0x0f, 0x85, 0x9f, 0x3d, + 0xd2, 0x3d, 0xff, 0xd1, 0xc0, 0x27, 0xe5, 0x0f, 0xff, 0xfc, 0xcf, 0x10, 0x4b, + 0xf5, 0xf5, 0x08, 0x2b, 0xeb, 0xe5, 0xd9, 0xd2, 0xc4, 0xd4, 0xf0, 0xd8, 0xfc, + 0xac, 0xe6, 0xe6, 0xc7, 0x15, 0xf1, 0xfc, 0xc3, 0x09, 0x15, 0xc9, 0xe2, 0x00, + 0x44, 0x41, 0xbf, 0x49, 0x21, 0x17, 0xdb, 0x83, 0xa3, 0xc2, 0xfb, 0x26, 0x1a, + 0xf4, 0x26, 0x20, 0xd1, 0xa7, 0x1f, 0xe6, 0x06, 0x99, 0x07, 0x16, 0x4d, 0xb1, + 0x3e, 0xc7, 0x2b, 0x30, 0xdc, 0xed, 0xed, 0xf7, 0xd9, 0xe8, 0x1c, 0xdf, 0x17, + 0xaf, 0xfb, 0xdf, 0xfb, 0xe0, 0x18, 0xe3, 0x39, 0x15, 0xf9, 0x3d, 0xaf, 0x3e, + 0x10, 0xb6, 0x3b, 0xf3, 0xee, 0xcf, 0xfa, 0xe4, 0xd2, 0xf4, 0x02, 0xf4, 0x15, + 0x24, 0xf2, 0xea, 0xfb, 0x12, 0x4e, 0xe3, 0xfd, 0xff, 0x26, 0x13, 0x38, 0xe9, + 0xe0, 0x06, 0x26, 0xf2, 0xff, 0xde, 0xef, 0xe4, 0x3d, 0xe6, 0xe6, 0xd3, 0xf1, + 0x05, 0xcd, 0xc8, 0xe4, 0xc2, 0xe0, 0x00, 0xea, 0xe2, 0x11, 0xfc, 0xd7, 0xe7, + 0xcd, 0xe8, 0xb5, 0xc6, 0x06, 0xf3, 0xbc, 0xda, 0xd6, 0xce, 0x05, 0xfa, 0xf0, + 0xe1, 0xfd, 0xe6, 0x35, 0x49, 0xfc, 0x00, 0xf8, 0xed, 0x1e, 0x24, 0x81, 0x2d, + 0x11, 0xe6, 0xfe, 0xdc, 0xba, 0xb8, 0xf7, 0x26, 0x04, 0x12, 0x1e, 0x24, 0x6f, + 0x0b, 0xf9, 0xcd, 0xd4, 0x0c, 0xce, 0x15, 0xc6, 0xe8, 0xb3, 0x05, 0x0f, 0xac, + 0x2a, 0xbd, 0xf5, 0x2f, 0xdf, 0xd3, 0x00, 0xed, 0xd2, 0x12, 0xed, 0x19, 0x36, + 0x1a, 0xf3, 0xe6, 0x02, 0x21, 0x10, 0xfe, 0xdb, 0xa6, 0xdc, 0xd2, 0x10, 0x6b, + 0xd7, 0xde, 0xce, 0xfd, 0xc2, 0x12, 0xd2, 0xfd, 0xe4, 0xd0, 0xe2, 0xfb, 0x11, + 0xdc, 0xc0, 0xda, 0xd4, 0xf8, 0x0e, 0x05, 0xdd, 0xf9, 0xee, 0x2e, 0x22, 0xe6, + 0xc2, 0xd9, 0x0b, 0xf6, 0xe0, 0x21, 0xf9, 0xdf, 0x32, 0x0c, 0x14, 0xbc, 0xc3, + 0x17, 0xf2, 0xe0, 0xe9, 0xf4, 0xf7, 0x0c, 0xdd, 0x3b, 0xbc, 0xdb, 0x1b, 0xdf, + 0xfb, 0xd9, 0x06, 0xcb, 0xde, 0x1a, 0x35, 0x21, 0x16, 0xe7, 0xd7, 0x19, 0xfb, + 0x2b, 0xc1, 0xd2, 0x0f, 0x2c, 0x02, 0x22, 0x09, 0xf0, 0xcd, 0xd8, 0x1f, 0xaf, + 0xf2, 0xd1, 0x04, 0x05, 0xbc, 0xd2, 0xea, 0x30, 0xeb, 0xee, 0xe8, 0xef, 0xd7, + 0xce, 0xbe, 0xff, 0xbe, 0xa8, 0xbc, 0xdc, 0xfd, 0xea, 0x07, 0x00, 0xe2, 0xee, + 0x27, 0xe6, 0xe7, 0x01, 0xf8, 0x07, 0xf3, 0x07, 0x01, 0xf7, 0xec, 0xe8, 0xf9, + 0xee, 0xfe, 0x14, 0x01, 0xdd, 0x2d, 0x31, 0x25, 0xf1, 0xfe, 0x22, 0xf7, 0xcf, + 0x09, 0xcf, 0xfe, 0xfb, 0xdd, 0xcc, 0x3d, 0x2f, 0xed, 0xf1, 0xe5, 0xaa, 0xed, + 0xe2, 0xea, 0xca, 0x00, 0xf8, 0xf6, 0xe7, 0xf6, 0x0c, 0x0b, 0xd0, 0x18, 0x01, + 0x1f, 0xb3, 0x1f, 0xf0, 0x07, 0xad, 0xf1, 0xca, 0xc4, 0xec, 0xf5, 0x36, 0xa4, + 0x15, 0xd1, 0xf5, 0xae, 0xcb, 0x21, 0x81, 0xfd, 0xcc, 0xd0, 0x00, 0xbf, 0xe2, + 0x0c, 0x27, 0x64, 0x22, 0x49, 0x21, 0xbd, 0xfd, 0xdb, 0xd9, 0xa7, 0x04, 0x04, + 0xe3, 0x30, 0xf4, 0xfb, 0x2b, 0xc6, 0xef, 0xfe, 0x1c, 0xe4, 0xdd, 0x01, 0x43, + 0xef, 0x4b, 0x72, 0x5c, 0x33, 0x37, 0xe5, 0xe4, 0x01, 0xea, 0xb0, 0x0b, 0x43, + 0xde, 0x06, 0xe4, 0x30, 0x5c, 0xea, 0xcd, 0xe5, 0x1e, 0x13, 0xe9, 0x0a, 0x2e, + 0xcf, 0xd9, 0x35, 0x13, 0xb7, 0xf3, 0x1f, 0xeb, 0xc5, 0x1c, 0x09, 0x13, 0x02, + 0x20, 0x13, 0x9e, 0x20, 0xe2, 0xba, 0x0d, 0xf8, 0xdf, 0x45, 0xeb, 0x1c, 0xf6, + 0x03, 0xec, 0xe5, 0x5e, 0xbb, 0x2a, 0xd3, 0xc1, 0xce, 0xb5, 0xe7, 0xff, 0xfc, + 0xf6, 0x1c, 0xb6, 0x11, 0xa6, 0xe6, 0x1b, 0xfa, 0x32, 0x24, 0xee, 0xca, 0xdd, + 0xe6, 0x17, 0x9a, 0xef, 0xea, 0xd8, 0x47, 0xf0, 0x14, 0x37, 0xd5, 0xff, 0x8a, + 0xe8, 0x03, 0xf6, 0x8e, 0x14, 0xec, 0xc4, 0x3e, 0xfc, 0xd4, 0x11, 0xd9, 0x96, + 0x9f, 0x11, 0xf3, 0x14, 0xa6, 0xdd, 0x1a, 0xfd, 0xa8, 0xcf, 0xdd, 0x18, 0xf4, + 0xd0, 0x5c, 0xf3, 0x25, 0x02, 0x2b, 0x3a, 0x44, 0xe0, 0xce, 0xf1, 0x09, 0xbe, + 0xe2, 0x1f, 0xa3, 0x11, 0xf9, 0xe7, 0x45, 0xcd, 0xeb, 0xda, 0xe0, 0xd0, 0xd6, + 0x3c, 0xf9, 0x63, 0xc2, 0x46, 0x30, 0xd3, 0xf9, 0xfa, 0xec, 0x97, 0x3f, 0x36, + 0x1b, 0xe7, 0x0f, 0xed, 0x0d, 0xe3, 0x18, 0x42, 0xcb, 0x0d, 0x37, 0x13, 0x13, + 0x49, 0xd2, 0x01, 0xcf, 0xd6, 0x27, 0xfc, 0x0e, 0xec, 0xb7, 0x1a, 0xc6, 0xf3, + 0x15, 0x60, 0x08, 0xf9, 0xe8, 0x3b, 0xc3, 0x34, 0xfc, 0x02, 0xa8, 0xcf, 0x26, + 0x37, 0xed, 0xee, 0xfc, 0xce, 0x15, 0x63, 0xb6, 0x3e, 0x09, 0xfb, 0xec, 0xfd, + 0x00, 0xc1, 0xf3, 0x08, 0x9e, 0xe7, 0xcc, 0xcf, 0xed, 0xf4, 0xd5, 0xf8, 0x11, + 0xdd, 0x12, 0xe8, 0xfc, 0xeb, 0x05, 0x03, 0x12, 0xf8, 0x12, 0xf8, 0xdb, 0x0c, + 0xda, 0x1a, 0xe8, 0x23, 0xd9, 0x16, 0x21, 0xde, 0xe0, 0x33, 0x00, 0xd5, 0x0d, + 0xeb, 0xfd, 0xfd, 0xd2, 0x23, 0xf9, 0xda, 0xcd, 0xd8, 0x1e, 0xdf, 0x13, 0x51, + 0xe8, 0xf1, 0x0b, 0x1e, 0x1e, 0xf7, 0x19, 0xff, 0xd8, 0xde, 0xdb, 0x1b, 0xe5, + 0xf4, 0xce, 0x0a, 0xfc, 0x0b, 0x00, 0xdd, 0xf0, 0xde, 0xcd, 0xbb, 0xec, 0xc4, + 0xe0, 0x25, 0xe0, 0x13, 0xef, 0xef, 0xd6, 0xe4, 0xeb, 0x0d, 0x0c, 0x15, 0xeb, + 0x0b, 0xd8, 0x20, 0x12, 0x03, 0x81, 0x01, 0x07, 0x18, 0xfb, 0xb5, 0xb6, 0xaf, + 0xb7, 0xd8, 0x0f, 0x00, 0x17, 0xde, 0xd1, 0x24, 0x16, 0xfc, 0xfa, 0x0e, 0xed, + 0xea, 0xe3, 0x09, 0x06, 0xd1, 0xe3, 0x38, 0x11, 0x03, 0xe6, 0xcd, 0x0a, 0x0d, + 0xd9, 0xeb, 0xbb, 0xe4, 0xd5, 0xb5, 0x14, 0x0d, 0x09, 0xf3, 0x22, 0x04, 0x03, + 0xe3, 0x03, 0xce, 0xdf, 0x1a, 0xc7, 0xdf, 0xdd, 0x1c, 0x1e, 0x0b, 0x01, 0xf4, + 0x0d, 0xff, 0x18, 0xf3, 0x1a, 0xff, 0x53, 0xff, 0x19, 0xfb, 0x2f, 0xf4, 0xca, + 0xea, 0x40, 0x1b, 0xf3, 0x09, 0xf9, 0xbc, 0x01, 0xec, 0xe7, 0xdf, 0x01, 0xb4, + 0x2c, 0xf4, 0xd6, 0xf8, 0x05, 0xca, 0xf9, 0xe3, 0xef, 0xdc, 0xfe, 0xf4, 0xf3, + 0xee, 0xfc, 0x05, 0x2f, 0xbf, 0xd4, 0x0e, 0xed, 0x0e, 0xfb, 0xe5, 0xf0, 0xe3, + 0xe3, 0x05, 0x0b, 0xec, 0xde, 0x13, 0xd6, 0xd3, 0xe1, 0xf6, 0xd4, 0xee, 0x22, + 0x27, 0x14, 0xf3, 0x1b, 0xec, 0xd0, 0xfd, 0xc9, 0xe9, 0x03, 0xee, 0x13, 0x0c, + 0x2d, 0xeb, 0x03, 0x9d, 0x1a, 0xed, 0x39, 0xf7, 0xde, 0xaa, 0xd2, 0xfc, 0x4f, + 0xd4, 0xf6, 0xba, 0xf9, 0xe9, 0xd3, 0xea, 0x17, 0x93, 0x2d, 0xfe, 0xf9, 0x00, + 0x00, 0x08, 0xb7, 0xfb, 0x8d, 0x2c, 0x40, 0xc1, 0x42, 0x1f, 0xbb, 0xd3, 0x41, + 0xfb, 0x13, 0xe6, 0xa8, 0x53, 0x05, 0x24, 0x1b, 0x1a, 0xf7, 0x0c, 0x2d, 0xab, + 0x23, 0xeb, 0xee, 0x42, 0x26, 0xb0, 0x05, 0x1a, 0xf0, 0xa8, 0xf2, 0x38, 0xd0, + 0xff, 0xef, 0x21, 0x41, 0x1f, 0x2a, 0x2a, 0xeb, 0xfe, 0x23, 0x0a, 0x43, 0xff, + 0x29, 0xe1, 0xad, 0xcd, 0xf8, 0x14, 0xcc, 0xd3, 0xc2, 0xf5, 0xfa, 0xb1, 0x18, + 0xa3, 0xe6, 0x49, 0x15, 0x0d, 0xf9, 0xd1, 0xf1, 0x10, 0x14, 0xea, 0xc7, 0x55, + 0xf4, 0x22, 0xcf, 0x07, 0xc4, 0xee, 0x27, 0xc0, 0x22, 0x1c, 0xf9, 0xf7, 0xda, + 0x0f, 0xd6, 0x27, 0x35, 0x10, 0xe7, 0x01, 0x33, 0xb5, 0xf5, 0x31, 0xd5, 0xef, + 0xcd, 0xe3, 0x1a, 0xa8, 0x13, 0x23, 0x3f, 0xbb, 0xe0, 0xf7, 0xda, 0xe9, 0xf8, + 0xf6, 0x00, 0x15, 0x09, 0xba, 0x27, 0xf4, 0x81, 0xe1, 0x17, 0x06, 0x0a, 0x3f, + 0xde, 0xcd, 0x07, 0xd7, 0xdc, 0xc5, 0x44, 0xe3, 0xb8, 0xd9, 0xfc, 0xf1, 0xc5, + 0xc8, 0xec, 0xdb, 0x1a, 0xc6, 0xf7, 0x31, 0xde, 0xe3, 0xe6, 0xc7, 0x9a, 0x32, + 0xb3, 0xb4, 0x2a, 0xdc, 0xe1, 0xe5, 0x15, 0xd8, 0xe2, 0xfd, 0x46, 0xfd, 0xe0, + 0x0b, 0x0d, 0x24, 0x0f, 0x0d, 0xfb, 0xc2, 0xfe, 0xa2, 0xd2, 0x0d, 0xea, 0x09, + 0x3e, 0xd6, 0xf5, 0x21, 0xb0, 0x31, 0xd3, 0x23, 0x06, 0x20, 0x06, 0xdc, 0x35, + 0x23, 0x29, 0xf3, 0xa9, 0xa8, 0xe8, 0xc8, 0x00, 0xfa, 0xf5, 0x0b, 0xd8, 0x1b, + 0x01, 0xd5, 0xec, 0xe3, 0xa4, 0xc7, 0xb6, 0xdd, 0x14, 0x3c, 0xde, 0xde, 0x14, + 0xe1, 0x30, 0xd1, 0x1b, 0xd8, 0x3c, 0x13, 0xaf, 0xbc, 0xe7, 0xd4, 0x0b, 0x01, + 0x08, 0xd5, 0x2d, 0x27, 0xfc, 0xcd, 0xef, 0x04, 0xfb, 0xcf, 0xf3, 0x16, 0x40, + 0x4a, 0xac, 0x06, 0xce, 0x18, 0xfe, 0x13, 0xc2, 0xce, 0x28, 0xef, 0xc3, 0xf0, + 0x1f, 0xd6, 0x05, 0xd7, 0x04, 0xf5, 0x0c, 0xe1, 0xe9, 0xca, 0x06, 0x18, 0xc4, + 0x11, 0x08, 0x3b, 0x18, 0xf6, 0xd7, 0xdd, 0x0a, 0xa7, 0xb7, 0xfa, 0xf4, 0x41, + 0x11, 0x28, 0x33, 0x17, 0x9f, 0x2e, 0x17, 0xde, 0x06, 0x0d, 0xa9, 0x30, 0xdd, + 0x24, 0xe5, 0xe2, 0xe2, 0x1e, 0xd6, 0x20, 0x2c, 0x0a, 0xf8, 0xd9, 0xd7, 0x14, + 0xda, 0xff, 0xd6, 0x19, 0xf0, 0x13, 0x36, 0x2b, 0xfc, 0xb6, 0xc4, 0x2b, 0xbf, + 0xf4, 0xe0, 0xa2, 0x05, 0x8b, 0x3c, 0xf6, 0xeb, 0xe3, 0xdc, 0x24, 0xba, 0xe3, + 0x3a, 0x1f, 0x07, 0xf8, 0x34, 0x14, 0xd2, 0xdd, 0x47, 0x3d, 0xad, 0xc9, 0x06, + 0x14, 0x16, 0xf3, 0xe8, 0xcb, 0xe9, 0xec, 0xe1, 0xec, 0x0c, 0x14, 0xd1, 0xd2, + 0x0c, 0xfa, 0xeb, 0xd4, 0xfc, 0xdf, 0x43, 0x2a, 0xdc, 0x02, 0xe1, 0xc2, 0x0a, + 0xe2, 0xfa, 0xec, 0x3a, 0xf7, 0x0b, 0xbd, 0x1d, 0x18, 0x26, 0xe8, 0x08, 0x1f, + 0xda, 0xdd, 0x0b, 0xf3, 0x13, 0x15, 0xd2, 0x1a, 0x81, 0xe7, 0x07, 0xfe, 0xb2, + 0xb3, 0x39, 0x0a, 0xda, 0xee, 0xd6, 0xf3, 0xf6, 0xde, 0xb5, 0x22, 0xe4, 0x1b, + 0xe9, 0x2d, 0x07, 0x02, 0x20, 0x1f, 0xdd, 0xe9, 0xde, 0x21, 0xfa, 0xee, 0xda, + 0x39, 0xf8, 0xdc, 0xf9, 0x01, 0xfe, 0x13, 0x12, 0x0f, 0x22, 0xd1, 0xfa, 0xf4, + 0xfa, 0xca, 0xf8, 0x18, 0xfb, 0x28, 0x11, 0x0a, 0x15, 0xe4, 0xce, 0x0e, 0x23, + 0x08, 0x04, 0x09, 0xd6, 0x07, 0x06, 0x01, 0x27, 0xdd, 0xf6, 0xef, 0xbf, 0x44, + 0xd2, 0xf1, 0xd9, 0x0a, 0xde, 0x11, 0x42, 0x16, 0xf7, 0xf0, 0xe3, 0x0d, 0x00, + 0x08, 0xbe, 0xca, 0x2b, 0xf3, 0x50, 0xe6, 0xd4, 0x1d, 0x1a, 0xf3, 0x10, 0x2e, + 0xf8, 0xc1, 0x20, 0xc4, 0xf4, 0xa7, 0xe8, 0xbb, 0x03, 0xf1, 0x08, 0xc2, 0x35, + 0xde, 0xd5, 0xe1, 0x6b, 0x1e, 0xbf, 0x1d, 0xb3, 0xc3, 0x2e, 0x3c, 0x81, 0x22, + 0x1e, 0xb4, 0x15, 0xc1, 0xeb, 0xc7, 0xc5, 0xfb, 0xc7, 0xaa, 0xb5, 0x20, 0xf4, + 0xb1, 0x2e, 0xbe, 0xfa, 0x27, 0xe2, 0x28, 0xef, 0x5c, 0xd9, 0xf6, 0xf6, 0x41, + 0xd1, 0xd0, 0x20, 0x26, 0x41, 0x03, 0xd4, 0x11, 0xbf, 0xfe, 0x49, 0x01, 0xc8, + 0xc1, 0xd8, 0x35, 0xaf, 0xac, 0x17, 0xdf, 0xbf, 0xcd, 0x00, 0xba, 0xbc, 0xb2, + 0xec, 0xb8, 0xc1, 0x4e, 0xc9, 0xe6, 0xf1, 0xb3, 0xb3, 0xd9, 0x04, 0xf1, 0xdf, + 0x52, 0x24, 0xf2, 0x24, 0x00, 0xe6, 0xf3, 0xe4, 0xc5, 0xa1, 0xac, 0xb7, 0x31, + 0xc2, 0x3c, 0xf0, 0xfd, 0x27, 0xee, 0xc9, 0xe6, 0xc3, 0xad, 0xd8, 0xb7, 0x37, + 0x06, 0x96, 0xfb, 0x53, 0xc5, 0x1e, 0x0f, 0x13, 0xbd, 0x9f, 0xed, 0xf5, 0x49, + 0x33, 0x13, 0xca, 0x52, 0x58, 0x39, 0x16, 0x02, 0xd0, 0x2a, 0x11, 0x0f, 0xd0, + 0x21, 0xbe, 0xe5, 0xe0, 0x03, 0x03, 0xe5, 0x37, 0xed, 0xda, 0x16, 0x5a, 0xd9, + 0xfe, 0xfe, 0xd0, 0x0a, 0xec, 0x0f, 0xff, 0xf8, 0x22, 0xe9, 0xf5, 0xf7, 0xe3, + 0xfd, 0x09, 0xef, 0xc8, 0x03, 0xfa, 0x01, 0x2e, 0xf7, 0x1b, 0x1c, 0xfd, 0xec, + 0xe7, 0xcd, 0xec, 0x0e, 0x46, 0xe6, 0xf9, 0xc6, 0xb0, 0x15, 0x50, 0xdf, 0xf0, + 0xe4, 0x12, 0x01, 0xe2, 0xc8, 0x0b, 0x12, 0x0e, 0x10, 0x0b, 0x21, 0x2b, 0xee, + 0x14, 0xd3, 0x12, 0xe3, 0xc7, 0xaf, 0xf0, 0xe8, 0xa4, 0xc4, 0xeb, 0x99, 0x15, + 0x32, 0x2c, 0xd3, 0xe5, 0xb4, 0xaf, 0x28, 0xce, 0xd1, 0xec, 0xb7, 0xd9, 0x4e, + 0xe4, 0xed, 0x5e, 0xc2, 0x2e, 0xd6, 0xdc, 0xf6, 0xe1, 0x30, 0xd1, 0xf6, 0xf0, + 0xc0, 0x00, 0xd1, 0x03, 0xde, 0xeb, 0x15, 0xef, 0xde, 0xc7, 0xfc, 0xd7, 0x35, + 0xef, 0xbd, 0xce, 0xda, 0xc0, 0xf7, 0x1c, 0x0c, 0xde, 0xe7, 0xbe, 0x09, 0xeb, + 0xbe, 0x12, 0xc9, 0x05, 0xe7, 0xe5, 0x0b, 0x1a, 0x23, 0x18, 0xf4, 0x0c, 0x09, + 0xf7, 0x1f, 0xc0, 0x2f, 0xfb, 0x16, 0xbf, 0x05, 0xe8, 0xe1, 0xf9, 0xea, 0x24, + 0xe9, 0x11, 0x3b, 0xfa, 0xeb, 0xcf, 0xe6, 0xdc, 0xd6, 0x1c, 0x1f, 0x03, 0xb8, + 0x0d, 0x0e, 0x01, 0x37, 0x08, 0x0a, 0x45, 0x2b, 0xf3, 0xe4, 0xf9, 0x1a, 0x0e, + 0x0d, 0xf6, 0x1b, 0xe8, 0xc5, 0x03, 0x14, 0x30, 0xe3, 0x45, 0xbd, 0x0a, 0xf8, + 0xb5, 0xee, 0x12, 0xe2, 0x17, 0x21, 0x32, 0x24, 0x32, 0x2e, 0x35, 0xf0, 0xe5, + 0x12, 0xd2, 0xe9, 0x11, 0x1e, 0x06, 0xf9, 0x21, 0x16, 0x36, 0x12, 0x0e, 0x05, + 0xe1, 0xb1, 0x2e, 0xe9, 0xe9, 0xe1, 0x01, 0x03, 0xe1, 0xfc, 0xf6, 0x29, 0x2d, + 0x12, 0x03, 0xfb, 0x37, 0x0e, 0x06, 0x30, 0xbd, 0x03, 0x40, 0xd9, 0x00, 0xe7, + 0x09, 0xfd, 0xef, 0xe6, 0xec, 0x2a, 0xf8, 0xfa, 0xfe, 0x09, 0xfd, 0x29, 0xd1, + 0xe5, 0x4a, 0xc9, 0xfc, 0xdd, 0xfe, 0x2f, 0x0e, 0xdd, 0x21, 0xda, 0x11, 0xee, + 0xc7, 0xfd, 0xfe, 0xcf, 0x02, 0xe3, 0x0b, 0xed, 0xf0, 0x6f, 0xf3, 0xf5, 0x11, + 0xf5, 0xbd, 0xf0, 0xeb, 0x08, 0x00, 0x08, 0xe8, 0x25, 0xfb, 0x08, 0x26, 0x17, + 0x06, 0xe6, 0xd7, 0x12, 0xf6, 0xc3, 0x05, 0xf9, 0x1d, 0xc8, 0xc5, 0xdb, 0xe5, + 0xc0, 0x18, 0x27, 0x10, 0xfc, 0xd7, 0x3a, 0x1f, 0x21, 0xf7, 0x01, 0x0c, 0xcd, + 0xed, 0x2e, 0xd3, 0xef, 0xda, 0xd9, 0x0a, 0xe8, 0xf6, 0x07, 0x00, 0x11, 0x12, + 0x01, 0xf2, 0xe7, 0xf5, 0x0e, 0xeb, 0x0a, 0x0f, 0x2f, 0xd4, 0xcb, 0x00, 0xf4, + 0xeb, 0xea, 0xec, 0xf1, 0x24, 0x0d, 0xdd, 0x1b, 0x00, 0xff, 0x11, 0x08, 0x0d, + 0xcd, 0x06, 0xf3, 0xc7, 0xde, 0xf4, 0x02, 0x23, 0x0e, 0x7f, 0xf3, 0x32, 0x11, + 0x12, 0x02, 0x2d, 0xd9, 0x48, 0xce, 0xe2, 0xc9, 0x14, 0xe5, 0xd7, 0x28, 0x20, + 0x1a, 0xc1, 0x36, 0xe7, 0x30, 0x38, 0xec, 0x0d, 0x4c, 0x3a, 0x24, 0xd2, 0xb1, + 0x3d, 0x19, 0xbb, 0xd3, 0xca, 0xdb, 0x03, 0xe3, 0xd7, 0x0e, 0xe0, 0xc3, 0xb5, + 0xe3, 0x3e, 0xe0, 0x0f, 0xd2, 0xec, 0xb8, 0xae, 0x2c, 0xf4, 0xec, 0xcd, 0x14, + 0xee, 0xe2, 0x52, 0xdf, 0x64, 0xf3, 0xef, 0x1e, 0xb3, 0x9c, 0x08, 0x02, 0xf2, + 0x1c, 0xd6, 0x20, 0x17, 0x2b, 0x20, 0xdc, 0xed, 0xfc, 0xf7, 0xc4, 0x21, 0xd2, + 0x47, 0x2a, 0x0b, 0x00, 0x09, 0x3d, 0x3e, 0xf3, 0x32, 0xc6, 0x0b, 0xc0, 0xf9, + 0x1c, 0x00, 0x14, 0xfb, 0xfe, 0x46, 0x1f, 0xcd, 0xdf, 0x40, 0xe5, 0x0d, 0xdd, + 0x24, 0xd8, 0xf7, 0xf3, 0xf4, 0x1e, 0x0c, 0xd4, 0x2c, 0x07, 0x92, 0xd9, 0x1a, + 0xda, 0x42, 0xd2, 0x33, 0x0c, 0xe6, 0xed, 0xf6, 0xe1, 0xca, 0x27, 0x11, 0xe2, + 0xf4, 0x81, 0x26, 0x08, 0xf4, 0x40, 0xcb, 0xb6, 0xf1, 0xf7, 0x22, 0xd2, 0xce, + 0xda, 0xe7, 0xd3, 0xf3, 0xdd, 0x43, 0x36, 0xff, 0x20, 0x10, 0x18, 0x06, 0xbf, + 0x07, 0x1c, 0x0e, 0x07, 0x03, 0x2a, 0xf0, 0xec, 0xc8, 0xf8, 0xb7, 0xe3, 0xe2, + 0x14, 0xde, 0xaf, 0xda, 0x3f, 0x0f, 0xfb, 0x11, 0x2a, 0xbd, 0xe7, 0x12, 0x04, + 0xf5, 0x24, 0x17, 0xf3, 0x05, 0x22, 0x3c, 0x1b, 0xe2, 0xfb, 0xb4, 0x38, 0x04, + 0x0a, 0x1c, 0x09, 0xf0, 0x34, 0xf7, 0xf5, 0x10, 0x32, 0xe9, 0xbc, 0x36, 0xc7, + 0xef, 0x1b, 0xff, 0x29, 0xf6, 0xfc, 0xfa, 0xd8, 0x0c, 0xae, 0x9a, 0x1b, 0x06, + 0x03, 0xbf, 0x09, 0x3a, 0xde, 0x16, 0x1f, 0xca, 0x0b, 0xd6, 0x21, 0xcb, 0xb2, + 0xc4, 0x1e, 0x05, 0xc8, 0xc7, 0xdf, 0xfb, 0x0c, 0xc7, 0xef, 0x11, 0xe3, 0xdc, + 0xe4, 0x0b, 0xe1, 0xf6, 0xe2, 0xce, 0xad, 0xea, 0x1c, 0xf2, 0xe8, 0xe8, 0xde, + 0xf2, 0xe8, 0xd7, 0xfe, 0xfc, 0x23, 0xc6, 0x47, 0x06, 0xdd, 0xde, 0x64, 0x0e, + 0xda, 0xfe, 0xd5, 0x21, 0x19, 0x06, 0xf7, 0xe9, 0xe6, 0xf9, 0x1e, 0xbc, 0xea, + 0x11, 0xe1, 0x0b, 0xd0, 0x20, 0x12, 0x39, 0xf1, 0x08, 0xed, 0xcb, 0x38, 0x0c, + 0xe3, 0xe5, 0xbf, 0x39, 0x00, 0xdd, 0xcc, 0xa3, 0x0f, 0xf4, 0x29, 0x1f, 0xd4, + 0x3d, 0x25, 0xe3, 0x62, 0xf2, 0xc1, 0x02, 0x97, 0x2a, 0xfd, 0xe1, 0xc8, 0xea, + 0x36, 0x0f, 0xf4, 0xc1, 0xfb, 0x26, 0xd4, 0x2d, 0xe2, 0x09, 0xe0, 0xfa, 0xae, + 0xff, 0xf7, 0x31, 0x08, 0x1b, 0x5e, 0x0b, 0xe1, 0xd1, 0x2b, 0xd2, 0xfa, 0xec, + 0xbc, 0xed, 0x44, 0xd7, 0xcf, 0x7f, 0xd8, 0xca, 0xe9, 0x0f, 0x53, 0x44, 0x3c, + 0x15, 0x24, 0x07, 0xd1, 0x1e, 0x9f, 0xd1, 0xca, 0xe6, 0xec, 0xba, 0xea, 0xbc, + 0xc7, 0xef, 0x0c, 0xf9, 0xe8, 0x1f, 0xf4, 0xf7, 0x47, 0xbb, 0xa3, 0xe9, 0xd4, + 0xda, 0xde, 0xe0, 0x01, 0xd8, 0x1c, 0x0b, 0x21, 0x26, 0xe0, 0x32, 0x26, 0x4f, + 0xe4, 0x4e, 0xf8, 0x01, 0xed, 0xef, 0xfa, 0xf9, 0x27, 0x1c, 0xe2, 0xfb, 0xd4, + 0xfd, 0xf7, 0x01, 0xdd, 0x95, 0x02, 0xea, 0xf1, 0x2e, 0x37, 0x16, 0x0b, 0x4a, + 0x17, 0x4b, 0xcb, 0x21, 0x2e, 0x26, 0x16, 0x0a, 0x14, 0x1b, 0xf9, 0x13, 0xb9, + 0xee, 0x3a, 0x46, 0xfe, 0x16, 0xf1, 0xa4, 0x45, 0xf1, 0x24, 0xf4, 0x11, 0x1e, + 0x2f, 0x03, 0xe9, 0x34, 0x52, 0xfa, 0xb4, 0x10, 0xec, 0x47, 0x2a, 0xd4, 0xd9, + 0x08, 0x70, 0x36, 0xd7, 0x22, 0xd1, 0xaa, 0xf0, 0x00, 0xbd, 0xdd, 0xee, 0xb1, + 0x05, 0x1a, 0x00, 0xd0, 0xbb, 0xbc, 0xf5, 0x07, 0xe6, 0xfc, 0x2a, 0xeb, 0xe0, + 0x01, 0xa0, 0xfd, 0xda, 0xde, 0xf4, 0xff, 0xeb, 0xe1, 0x14, 0x1c, 0xf3, 0xf0, + 0x02, 0xe4, 0xe5, 0xef, 0xe6, 0x06, 0x05, 0x17, 0x0f, 0x20, 0xc9, 0x01, 0xd6, + 0x1e, 0xf0, 0xc9, 0xb3, 0x2d, 0x00, 0x03, 0xb6, 0xd5, 0x17, 0x0a, 0xa5, 0x13, + 0xfd, 0x44, 0x17, 0xbc, 0xec, 0xd8, 0xf2, 0xe4, 0x05, 0x2b, 0xe8, 0xcf, 0xea, + 0x2f, 0xf2, 0xde, 0xf4, 0x0a, 0xe6, 0x00, 0x04, 0xde, 0xf2, 0x9e, 0xd3, 0x12, + 0x09, 0xf6, 0x16, 0x11, 0x38, 0xd5, 0x30, 0xf0, 0x3d, 0x0d, 0xef, 0x45, 0xd8, + 0x1c, 0xe7, 0x07, 0xc8, 0x13, 0xed, 0x17, 0xe9, 0x16, 0x47, 0x22, 0xf6, 0x81, + 0x45, 0x07, 0xf8, 0xab, 0x2f, 0xd8, 0xb9, 0xfd, 0xfb, 0xeb, 0xcb, 0xcb, 0xf9, + 0x3a, 0x2c, 0xe6, 0x0c, 0x93, 0xec, 0x1d, 0x12, 0x06, 0xd9, 0x15, 0xf6, 0x16, + 0x91, 0xf7, 0xd0, 0xdf, 0x2b, 0x1a, 0x30, 0xef, 0xc5, 0x05, 0x28, 0xbb, 0xc5, + 0x9d, 0xfd, 0xce, 0xe4, 0x13, 0xc7, 0x0e, 0xd5, 0xcb, 0xeb, 0xd1, 0xdb, 0x3f, + 0x25, 0x02, 0x01, 0xa2, 0x47, 0xe0, 0xf6, 0x3d, 0xd3, 0x1a, 0x30, 0x1a, 0x25, + 0xdf, 0xc6, 0x0d, 0xfd, 0x2d, 0xde, 0xdb, 0xd4, 0x43, 0xc5, 0x35, 0xee, 0xf4, + 0x13, 0xd0, 0xe2, 0xb8, 0x05, 0x2f, 0xe4, 0xaa, 0x17, 0x36, 0xe3, 0x4e, 0x2e, + 0x09, 0x01, 0xef, 0x06, 0xb2, 0xeb, 0x04, 0x2e, 0x12, 0x02, 0x16, 0xf0, 0x0f, + 0xda, 0x14, 0xfa, 0xd2, 0xba, 0xe9, 0x02, 0x2e, 0x17, 0xeb, 0xcb, 0x8d, 0x06, + 0xd3, 0xa7, 0x17, 0x15, 0x1a, 0x0f, 0xcf, 0x23, 0x3d, 0xff, 0x33, 0xd4, 0x21, + 0xfe, 0xbe, 0xf8, 0xf0, 0xd0, 0xbf, 0xab, 0x11, 0xe0, 0x18, 0xb1, 0x41, 0xb5, + 0x26, 0x1e, 0xff, 0x07, 0x37, 0xec, 0xbc, 0x96, 0x19, 0x0c, 0x1b, 0xf0, 0x48, + 0x2f, 0xc6, 0xd2, 0xd8, 0xbc, 0xf9, 0x11, 0xbb, 0xff, 0xe7, 0xe7, 0x1f, 0x3d, + 0x24, 0xff, 0x16, 0x54, 0x0c, 0xdf, 0x1b, 0xd3, 0xba, 0xf6, 0x43, 0x01, 0xd8, + 0x4f, 0x23, 0x02, 0x00, 0x41, 0xab, 0xdb, 0xbe, 0x12, 0xf7, 0xfe, 0xcc, 0xdb, + 0xaf, 0x2c, 0xf3, 0x10, 0xea, 0x96, 0x18, 0x00, 0xf4, 0xf0, 0x06, 0xbc, 0x00, + 0xac, 0xe3, 0x3d, 0xa3, 0xbb, 0xba, 0xf5, 0xd5, 0x19, 0xe6, 0xa6, 0xff, 0x56, + 0xf8, 0x07, 0x26, 0xeb, 0x11, 0xed, 0xb1, 0xcb, 0xc9, 0x07, 0x27, 0x69, 0xaa, + 0xef, 0x06, 0x4b, 0xf1, 0xe6, 0xe4, 0x21, 0xa4, 0xe1, 0xda, 0xe7, 0xe2, 0xb9, + 0x30, 0x0c, 0x0a, 0x44, 0x2c, 0xdc, 0xf3, 0xe8, 0xe3, 0xe0, 0x1a, 0xcb, 0xa4, + 0xfd, 0x07, 0xdf, 0xd8, 0x11, 0xe1, 0x08, 0x2b, 0xcc, 0x15, 0x13, 0xd0, 0xc0, + 0xf3, 0x22, 0x59, 0xd2, 0x33, 0xf5, 0x1d, 0xd9, 0xfc, 0xd6, 0x30, 0x1a, 0xf5, + 0xd5, 0x19, 0x1c, 0x11, 0xd7, 0x20, 0x3f, 0xd9, 0xdb, 0x18, 0xf7, 0xae, 0xfd, + 0x15, 0x54, 0x06, 0x27, 0xc8, 0xe6, 0xa4, 0xc4, 0x3f, 0x03, 0x4f, 0xda, 0xaf, + 0xd1, 0xad, 0xf7, 0x31, 0x37, 0x1b, 0xa6, 0xe6, 0x32, 0x2e, 0x04, 0x15, 0x1a, + 0x0f, 0xb8, 0xc0, 0x37, 0xbc, 0x81, 0x09, 0xe5, 0x1b, 0x51, 0x94, 0x10, 0x19, + 0x1b, 0xf5, 0xea, 0xc5, 0xee, 0x00, 0xe5, 0xcd, 0x01, 0xfe, 0x11, 0x9b, 0xa2, + 0x05, 0xd7, 0xab, 0xe7, 0xfd, 0xb6, 0xd9, 0xec, 0xe3, 0x3d, 0xbb, 0x1f, 0x10, + 0x1e, 0xe7, 0xdd, 0xeb, 0x4d, 0x21, 0xd2, 0x35, 0x9d, 0x53, 0x41, 0x23, 0x1c, + 0xe5, 0xc6, 0xf7, 0x15, 0xd4, 0x3d, 0x1a, 0x0d, 0xec, 0xba, 0x23, 0xfc, 0x02, + 0x38, 0xa1, 0x04, 0xf5, 0x99, 0xff, 0x49, 0xbc, 0xab, 0xba, 0xad, 0xe3, 0xb7, + 0x19, 0xcf, 0xf7, 0x0e, 0x25, 0x68, 0x13, 0xbe, 0xcb, 0xd7, 0x1b, 0xd5, 0x29, + 0xfe, 0x0c, 0x42, 0x1d, 0x61, 0x0b, 0xfa, 0x08, 0xf0, 0xde, 0xff, 0xf3, 0xbd, + 0x29, 0x9d, 0xb1, 0xf6, 0x50, 0x07, 0x55, 0xf8, 0x1e, 0xe2, 0xfe, 0x19, 0xfc, + 0xc5, 0xde, 0xdc, 0x0d, 0xfb, 0x17, 0x13, 0xf6, 0xf3, 0xf4, 0xfe, 0xe8, 0x0e, + 0xc7, 0xee, 0xb8, 0xd1, 0x5a, 0xd4, 0x1a, 0xbe, 0xe9, 0x1e, 0xb2, 0x15, 0xa6, + 0xc0, 0x06, 0xd4, 0x0f, 0xcd, 0xec, 0x0d, 0xd9, 0x03, 0xd9, 0xc9, 0xd2, 0x05, + 0xdf, 0x23, 0xd2, 0xbe, 0x66, 0xec, 0xf7, 0xbf, 0x02, 0xd8, 0xdc, 0x60, 0xf3, + 0x27, 0x28, 0xe5, 0xf7, 0xfa, 0xca, 0xbe, 0x2f, 0x0d, 0xcc, 0xd8, 0x0a, 0xff, + 0x18, 0x11, 0xfa, 0x01, 0xe9, 0x2e, 0xd6, 0x03, 0x4b, 0xe4, 0x20, 0x0c, 0xe3, + 0xca, 0xb2, 0x12, 0x34, 0x13, 0x42, 0x49, 0x0e, 0xd3, 0xc5, 0xee, 0xfe, 0x16, + 0x09, 0x03, 0x39, 0x1d, 0xcf, 0xcc, 0xff, 0x0b, 0xb9, 0xf8, 0x10, 0xf4, 0x34, + 0xd7, 0xe5, 0x05, 0x06, 0xd7, 0x02, 0xd0, 0xe7, 0xe0, 0xb6, 0xc2, 0xbc, 0xca, + 0xd3, 0xcd, 0x1a, 0xdc, 0xeb, 0x28, 0x2c, 0x1a, 0x07, 0x16, 0x86, 0xd9, 0x01, + 0x02, 0xeb, 0xc1, 0xcc, 0x58, 0xd1, 0x17, 0x06, 0xe0, 0x6d, 0xdd, 0x05, 0x19, + 0x2e, 0x04, 0x0d, 0x3d, 0xe6, 0xd9, 0xfe, 0x02, 0x0f, 0xf0, 0x10, 0xfb, 0xff, + 0x13, 0xc1, 0xe7, 0xe8, 0x01, 0xc0, 0xfa, 0x01, 0xed, 0x34, 0x16, 0xf2, 0xe1, + 0xea, 0x03, 0x14, 0xe4, 0xed, 0x25, 0x12, 0x11, 0xee, 0x01, 0x18, 0x0d, 0xdd, + 0xfe, 0xb7, 0x1c, 0x04, 0x14, 0xfc, 0x00, 0xcd, 0x24, 0x08, 0x0e, 0xfc, 0x0b, + 0xdc, 0x23, 0xf9, 0xba, 0x5b, 0x31, 0x28, 0xc0, 0x1b, 0xdd, 0x31, 0x20, 0x09, + 0xea, 0xf5, 0x7e, 0xca, 0xcb, 0x0d, 0xb8, 0xf5, 0x09, 0xf8, 0xad, 0xec, 0x0f, + 0xd3, 0xfd, 0x0d, 0xe7, 0xc7, 0x82, 0xe6, 0xd9, 0x03, 0x05, 0x26, 0xe0, 0xe0, + 0xde, 0xfd, 0xde, 0x05, 0x81, 0xea, 0xd9, 0xfc, 0x0e, 0xeb, 0xcd, 0x12, 0xf4, + 0xc1, 0x0a, 0xdd, 0xdc, 0xea, 0xef, 0xdb, 0xe2, 0x07, 0xe8, 0xe4, 0xaa, 0xd4, + 0x2b, 0xb1, 0xce, 0x04, 0xfd, 0xf3, 0xe7, 0xd6, 0x4e, 0x83, 0xd1, 0x89, 0xa6, + 0x2f, 0x00, 0x06, 0xc9, 0x36, 0x1f, 0x35, 0x28, 0xee, 0xdf, 0x1a, 0x11, 0x2e, + 0xb4, 0xc7, 0x23, 0x37, 0xf9, 0x2f, 0x0d, 0xdb, 0xe8, 0x11, 0x3a, 0xc2, 0x91, + 0x48, 0x34, 0x38, 0x13, 0x07, 0xe8, 0xa5, 0xcf, 0x27, 0x52, 0x8d, 0x0a, 0x04, + 0x3a, 0x17, 0x3d, 0x5c, 0xf6, 0xff, 0xe0, 0xd9, 0x4c, 0x20, 0x05, 0xb0, 0xe9, + 0xc6, 0x2b, 0x0c, 0xd7, 0x1d, 0xec, 0xb5, 0x7a, 0xd0, 0xa0, 0xd4, 0x49, 0x34, + 0x3d, 0x1b, 0x6e, 0x5f, 0x63, 0xff, 0xe3, 0x11, 0xa6, 0xff, 0x3e, 0x99, 0xcb, + 0xff, 0x88, 0xa1, 0x3b, 0xe1, 0xca, 0xa6, 0x2c, 0x3f, 0x3d, 0xf3, 0xb4, 0xb5, + 0x32, 0x53, 0xb2, 0xf2, 0x2a, 0x39, 0x11, 0xdc, 0x32, 0xdd, 0x5c, 0x60, 0x10, + 0xfe, 0xdb, 0x01, 0x18, 0xbf, 0x94, 0x34, 0xb2, 0xaf, 0xa2, 0xf4, 0x05, 0x2e, + 0x19, 0x09, 0xc8, 0x3f, 0x01, 0xfa, 0xfa, 0xe1, 0x17, 0x0f, 0x3c, 0xc6, 0xe6, + 0xf5, 0xb7, 0xf8, 0xe7, 0xed, 0x0d, 0xf5, 0xec, 0x1c, 0x27, 0xf6, 0x19, 0xec, + 0xd3, 0xc5, 0xc6, 0x9a, 0x11, 0x03, 0x58, 0x08, 0x09, 0x54, 0xd9, 0x36, 0xb7, + 0x26, 0xe7, 0x41, 0xf9, 0xfe, 0xf9, 0x20, 0x3e, 0x33, 0xb1, 0x01, 0xd2, 0x0f, + 0xf8, 0x36, 0x27, 0xbd, 0xe8, 0x06, 0x3b, 0x24, 0xf8, 0xf1, 0xa7, 0x52, 0x2b, + 0x25, 0xe7, 0x49, 0x2b, 0x01, 0xcf, 0xd9, 0x1b, 0x1b, 0xa1, 0xf1, 0x41, 0x24, + 0xcc, 0xcf, 0xaf, 0x4d, 0xcc, 0x58, 0x04, 0xd3, 0xbf, 0xde, 0x13, 0xca, 0x41, + 0x06, 0xfb, 0x33, 0xd7, 0xd3, 0xdc, 0xe2, 0x00, 0x12, 0xbb, 0xbd, 0xd9, 0x5a, + 0xf0, 0xcf, 0xf6, 0x12, 0x28, 0x02, 0x13, 0xd3, 0x9e, 0xff, 0xf4, 0x7f, 0x0c, + 0xf1, 0xb5, 0x09, 0xd4, 0x10, 0x8c, 0xff, 0x12, 0x23, 0x4a, 0x9f, 0xae, 0xed, + 0x17, 0xec, 0xd4, 0xf2, 0xd5, 0xa6, 0x2b, 0xe8, 0xcb, 0xde, 0x4d, 0xec, 0xf9, + 0xae, 0xaf, 0x0f, 0xa6, 0xcf, 0x08, 0x96, 0xd1, 0xb9, 0xa5, 0x1b, 0x1f, 0xf2, + 0xe6, 0x36, 0xf5, 0x97, 0xfc, 0x19, 0x34, 0xe0, 0xeb, 0x02, 0x40, 0xde, 0xf5, + 0x2d, 0xb7, 0xce, 0xae, 0xb9, 0x1a, 0x05, 0x5d, 0x64, 0xdb, 0xf2, 0x67, 0x27, + 0xf6, 0x1f, 0xa5, 0xb9, 0xe4, 0xf3, 0xc6, 0x6b, 0x8d, 0x12, 0xf6, 0x48, 0xed, + 0xf4, 0xfe, 0xc7, 0x32, 0xe4, 0x96, 0x27, 0xde, 0xcc, 0x44, 0x16, 0xe7, 0xeb, + 0xef, 0xbb, 0x23, 0x4f, 0x36, 0x0b, 0xf4, 0xbb, 0xcb, 0x05, 0xdf, 0x0f, 0x24, + 0xc1, 0x3c, 0xc8, 0xb4, 0xb9, 0xcf, 0xf5, 0x36, 0xa9, 0x05, 0x51, 0x29, 0xef, + 0xc9, 0x15, 0xdc, 0x99, 0xe0, 0xbf, 0xf1, 0x21, 0x3f, 0xfb, 0xe0, 0xfe, 0x3e, + 0x31, 0xf2, 0xef, 0xcd, 0xc7, 0xa6, 0xc3, 0xfa, 0xce, 0x2d, 0xae, 0xcd, 0xe9, + 0xce, 0x15, 0x1b, 0x2b, 0x29, 0xbc, 0xf1, 0xfa, 0xe6, 0x0b, 0x3e, 0xc8, 0x27, + 0x2c, 0xe7, 0xc0, 0xe1, 0x2c, 0x5b, 0x59, 0x0f, 0xca, 0xca, 0x23, 0x9b, 0xc2, + 0x34, 0x6c, 0x12, 0x0c, 0xc1, 0xe7, 0xf4, 0x27, 0x0c, 0x02, 0xbb, 0xf8, 0x06, + 0xda, 0xe5, 0xd3, 0xe6, 0xb5, 0x4a, 0x2e, 0x18, 0xf9, 0xea, 0x20, 0x22, 0x33, + 0xdd, 0xec, 0xdc, 0xd2, 0x04, 0xd7, 0xed, 0xf0, 0xbb, 0x9e, 0xbc, 0x0d, 0xea, + 0xe5, 0xc9, 0xcd, 0xec, 0x1e, 0x99, 0xa0, 0xe0, 0xfd, 0x1b, 0xa4, 0x3a, 0xfe, + 0xd7, 0xea, 0xa6, 0x3c, 0x8f, 0x1b, 0x18, 0x42, 0xf8, 0xf8, 0x05, 0x25, 0x52, + 0x2b, 0x06, 0xe8, 0x69, 0xf5, 0xc4, 0xd8, 0x0e, 0x05, 0x03, 0xf6, 0x58, 0x40, + 0xd6, 0x46, 0x02, 0x5d, 0x81, 0xdb, 0x99, 0xf2, 0xd2, 0xd7, 0xd1, 0x0b, 0x0d, + 0xc5, 0xc6, 0x05, 0x0b, 0x52, 0xfe, 0xb9, 0x1d, 0x28, 0xbe, 0x33, 0x36, 0xff, + 0xf5, 0xab, 0x53, 0xed, 0x62, 0xfd, 0xb1, 0x54, 0x26, 0xf5, 0x32, 0xd0, 0xba, + 0x02, 0xfa, 0x96, 0x37, 0x03, 0xcf, 0x19, 0xa7, 0x16, 0x3c, 0xe3, 0x8e, 0x8f, + 0xe4, 0xf4, 0xba, 0xaf, 0x95, 0xed, 0x29, 0xbb, 0xb7, 0x3d, 0x29, 0xfa, 0xba, + 0x0a, 0xf8, 0x24, 0x02, 0x43, 0xb6, 0x38, 0xd9, 0x22, 0x0c, 0x23, 0x45, 0xf4, + 0x0b, 0x04, 0x3d, 0x13, 0xfb, 0x42, 0x59, 0xd7, 0xd4, 0x59, 0x0c, 0xe4, 0x49, + 0x34, 0xae, 0x35, 0x28, 0xb7, 0xb7, 0x43, 0xd8, 0x1a, 0x83, 0x38, 0x35, 0xf9, + 0x48, 0x3d, 0xc7, 0x54, 0x66, 0x0c, 0xc9, 0xb5, 0xae, 0xe9, 0xb9, 0xe7, 0x2c, + 0x3e, 0xdf, 0xef, 0xde, 0x93, 0xa7, 0xf7, 0xdb, 0x44, 0xad, 0xfa, 0x04, 0xfc, + 0x1d, 0x18, 0x24, 0x1f, 0xb9, 0x01, 0xb2, 0xe8, 0xe2, 0x9c, 0xd3, 0xb0, 0xe2, + 0x03, 0x35, 0xe4, 0x3d, 0xe5, 0x1e, 0x2c, 0xad, 0x2e, 0x1e, 0xba, 0xb1, 0x0d, + 0xa6, 0xe9, 0x0e, 0xe9, 0x06, 0x85, 0xfa, 0x11, 0x32, 0xeb, 0x18, 0x47, 0xdf, + 0x98, 0x29, 0x22, 0xcb, 0x05, 0xdb, 0xe4, 0x1f, 0xf5, 0x3c, 0x6c, 0xf2, 0x14, + 0x18, 0x1b, 0x5a, 0xe8, 0xd8, 0xc9, 0xf6, 0xeb, 0x1b, 0xc3, 0x07, 0xd6, 0xac, + 0xb9, 0x11, 0xc4, 0x20, 0xd4, 0x1a, 0x28, 0xc2, 0x25, 0x53, 0x37, 0x10, 0xdf, + 0x08, 0xf3, 0x1a, 0xcd, 0x01, 0x38, 0x50, 0x47, 0xe0, 0x17, 0xc8, 0xd5, 0xef, + 0x9c, 0x3c, 0xf4, 0x17, 0x8d, 0xb8, 0x04, 0xa8, 0xea, 0x29, 0xf5, 0x5c, 0xe2, + 0x20, 0xf2, 0x23, 0x7f, 0x36, 0x13, 0xb1, 0xe9, 0x32, 0x05, 0xca, 0xf4, 0x02, + 0xfe, 0x11, 0x0d, 0xf1, 0x31, 0x9c, 0xdb, 0x13, 0x4d, 0x1a, 0x01, 0xf2, 0x18, + 0xf9, 0xbe, 0xcf, 0x61, 0xf2, 0x3f, 0x3f, 0x29, 0x0d, 0x28, 0x15, 0x92, 0x0e, + 0xea, 0xe4, 0x18, 0xd5, 0x15, 0xc7, 0x8d, 0x07, 0x3e, 0xb4, 0xc5, 0xdb, 0x03, + 0x00, 0xc9, 0xbd, 0x0b, 0xaf, 0xde, 0xf7, 0x0c, 0xdd, 0x09, 0x0a, 0xb6, 0xf6, + 0x1c, 0xc8, 0x11, 0x1e, 0xf9, 0xd4, 0xbd, 0xfe, 0xe7, 0x27, 0xe4, 0xe4, 0xf0, + 0xde, 0x2a, 0xcd, 0xdd, 0x0d, 0xd7, 0x10, 0xd3, 0x0c, 0x0b, 0xe6, 0x1b, 0xce, + 0xf0, 0x0a, 0x2a, 0xe7, 0x7a, 0xeb, 0xea, 0x18, 0xe7, 0x0f, 0xcd, 0xec, 0xba, + 0x14, 0xb7, 0xe4, 0x23, 0x0b, 0x1c, 0x40, 0x85, 0xdd, 0x9a, 0xe6, 0xd8, 0xbc, + 0x0c, 0xed, 0x20, 0xff, 0xfd, 0x9f, 0x37, 0x09, 0x41, 0x39, 0xed, 0xab, 0x1e, + 0x0f, 0xfb, 0xe8, 0x33, 0xc7, 0xc8, 0x04, 0xd0, 0x00, 0x04, 0xff, 0xfd, 0x07, + 0x16, 0x11, 0xdd, 0x05, 0x0d, 0xe3, 0xca, 0xe1, 0x06, 0x09, 0xda, 0x28, 0x06, + 0xfe, 0xeb, 0x31, 0x51, 0xc6, 0xf4, 0x0e, 0xfa, 0xce, 0x07, 0xfe, 0xe0, 0x30, + 0x42, 0xea, 0x18, 0xf4, 0xe2, 0xd1, 0xf2, 0xce, 0x39, 0xa3, 0xc2, 0x0f, 0x9e, + 0x37, 0xb0, 0x81, 0xe8, 0x1e, 0x04, 0xce, 0x1e, 0xc3, 0x45, 0x11, 0x54, 0x08, + 0xcf, 0xe3, 0xf7, 0xb3, 0x44, 0x1c, 0xc3, 0xf2, 0x23, 0x11, 0xfb, 0x26, 0x0c, + 0xf4, 0x00, 0xef, 0xf3, 0x00, 0xb9, 0xf4, 0xed, 0x17, 0xd7, 0x1c, 0xd1, 0xe7, + 0xed, 0xbf, 0x3f, 0xe3, 0xca, 0x23, 0x15, 0x0d, 0x08, 0xa7, 0xf8, 0x33, 0xf3, + 0x41, 0x0a, 0xbc, 0x05, 0xd9, 0x35, 0xd8, 0xba, 0xda, 0xea, 0xfe, 0xd3, 0x0c, + 0x1a, 0xd8, 0xb9, 0x24, 0xfc, 0x0c, 0x11, 0x0d, 0x24, 0xdb, 0x13, 0x4b, 0x0d, + 0xc3, 0xd9, 0xf3, 0xc9, 0x11, 0xeb, 0x10, 0xd2, 0xdb, 0xe1, 0xc7, 0x63, 0x16, + 0x08, 0x0a, 0xd0, 0xf3, 0x06, 0xb6, 0x22, 0xf2, 0x05, 0xa3, 0xdb, 0xfc, 0xfb, + 0x08, 0xff, 0xd3, 0xf8, 0xc8, 0x0f, 0x20, 0xc2, 0xed, 0xec, 0x1c, 0xdf, 0x29, + 0xdf, 0x12, 0xdf, 0xd6, 0xec, 0x56, 0xc7, 0xf3, 0x11, 0xae, 0xf6, 0xf6, 0x1a, + 0xd5, 0xcd, 0xdd, 0x04, 0xdb, 0x0d, 0xde, 0xd5, 0xf7, 0x4c, 0xd7, 0xec, 0x0b, + 0x25, 0xf9, 0x11, 0xfa, 0x1d, 0xf7, 0x3e, 0xfb, 0xc5, 0xdd, 0x23, 0xb2, 0x26, + 0xc6, 0xe6, 0x14, 0xd0, 0x1d, 0x25, 0x14, 0x2f, 0x21, 0xc0, 0x26, 0xe6, 0xce, + 0x1a, 0xd6, 0xf8, 0x00, 0x02, 0x08, 0x0d, 0xee, 0x17, 0xff, 0xbf, 0xeb, 0x3b, + 0xf5, 0x1c, 0xe0, 0xe6, 0x2d, 0x05, 0xb6, 0xe2, 0xef, 0x3a, 0xfa, 0x29, 0x70, + 0xda, 0xc2, 0xc1, 0xd5, 0x0a, 0x43, 0x15, 0xfe, 0xeb, 0x0c, 0xc5, 0xca, 0x2d, + 0xf8, 0x05, 0xf3, 0xf2, 0xfb, 0x3d, 0xf9, 0x35, 0x03, 0xee, 0xb6, 0x23, 0xd5, + 0xbb, 0xb8, 0xfc, 0xfc, 0xbd, 0xcd, 0x10, 0xb4, 0x0c, 0xfe, 0x1b, 0xf8, 0x12, + 0x12, 0xad, 0xfc, 0xa1, 0xbd, 0x16, 0x39, 0xee, 0xd5, 0xd2, 0xf7, 0xef, 0xd9, + 0xd3, 0xfd, 0x38, 0xf5, 0xde, 0x0f, 0x4c, 0xfd, 0x38, 0x38, 0xdb, 0x1a, 0x2d, + 0xce, 0xff, 0xed, 0x20, 0xe9, 0x1f, 0x23, 0xd3, 0xf8, 0x0c, 0x02, 0xb8, 0xc2, + 0xe6, 0x30, 0x2c, 0x0d, 0xe3, 0x01, 0x0c, 0x23, 0x3a, 0xe4, 0x07, 0x17, 0x31, + 0xe5, 0x17, 0xe8, 0x04, 0xe2, 0x9d, 0xd2, 0xe7, 0x27, 0xf0, 0x11, 0xdd, 0xe5, + 0xda, 0xc4, 0xe9, 0x17, 0xf1, 0x05, 0x17, 0x16, 0x32, 0xb1, 0x2c, 0x1e, 0x18, + 0xbf, 0xf6, 0xe4, 0x22, 0x08, 0xdc, 0x01, 0x1f, 0x7f, 0x02, 0xf2, 0x07, 0xd0, + 0xd7, 0x24, 0x06, 0xff, 0xf2, 0x37, 0x97, 0xe5, 0x0c, 0x0b, 0xf3, 0xcb, 0xd3, + 0xf3, 0xdb, 0x1c, 0x08, 0xe6, 0xfd, 0xda, 0x11, 0xda, 0x18, 0xe3, 0xd8, 0xfb, + 0xfa, 0x13, 0x09, 0x13, 0xfb, 0xe4, 0x12, 0x0a, 0xe0, 0xf7, 0xd3, 0xd3, 0x23, + 0xb8, 0x10, 0xa3, 0xe6, 0xc0, 0xe6, 0xde, 0xed, 0xdf, 0x05, 0xca, 0x16, 0xd2, + 0xe1, 0xfe, 0xd2, 0x30, 0xd7, 0x1b, 0xb6, 0x1a, 0x2a, 0xf5, 0xdc, 0x41, 0xd7, + 0x8a, 0x17, 0x2b, 0xd9, 0xec, 0xba, 0x1d, 0xa5, 0x06, 0x9b, 0x2c, 0x21, 0x18, + 0x9b, 0x1d, 0x1c, 0xc0, 0xe3, 0xce, 0x27, 0x16, 0xa4, 0x4a, 0xe3, 0x97, 0x9b, + 0x0b, 0xf8, 0x16, 0x3b, 0x26, 0x0a, 0xe6, 0xf5, 0x3d, 0x73, 0x2d, 0xfe, 0x00, + 0xc7, 0x41, 0xe6, 0xf7, 0x08, 0x03, 0x07, 0x28, 0x0d, 0xb5, 0xa9, 0xb0, 0xac, + 0x3b, 0xac, 0xd0, 0x32, 0xc8, 0xf9, 0x29, 0xf2, 0x07, 0xd3, 0xc4, 0xf3, 0xf3, + 0xfc, 0x20, 0xea, 0x12, 0xae, 0x84, 0xb1, 0x38, 0xe0, 0x66, 0xb4, 0xc5, 0xc0, + 0xf7, 0xc8, 0xb1, 0x2b, 0xb5, 0xb6, 0xf2, 0x09, 0x04, 0x2d, 0xdd, 0x81, 0xc4, + 0x13, 0xda, 0xf4, 0x06, 0xd5, 0x24, 0x1a, 0x20, 0x07, 0xd6, 0xea, 0xc0, 0xc2, + 0x06, 0xbb, 0xb1, 0xee, 0xdf, 0xff, 0x23, 0xcf, 0xb4, 0xb2, 0xfe, 0xf5, 0x13, + 0x1b, 0xea, 0x23, 0xc5, 0x05, 0x18, 0xa3, 0x00, 0x13, 0xe7, 0x33, 0x03, 0xff, + 0xa7, 0xf4, 0x16, 0x37, 0x68, 0x06, 0xa3, 0xec, 0x0f, 0x1c, 0x53, 0x28, 0xbc, + 0xd2, 0x0f, 0x28, 0x01, 0xe1, 0xdf, 0x7f, 0xb6, 0x26, 0xaf, 0x09, 0xff, 0xe6, + 0xcc, 0xa6, 0xef, 0xfb, 0x23, 0xc4, 0x4d, 0x16, 0xc0, 0x27, 0xdf, 0x93, 0x15, + 0xab, 0x9d, 0xcc, 0xcb, 0x1d, 0xb4, 0xe3, 0xfc, 0xf1, 0xdd, 0x10, 0xce, 0x9e, + 0x12, 0xf5, 0xdc, 0x38, 0xf2, 0x20, 0x4d, 0xac, 0xea, 0xe0, 0x24, 0xaf, 0x31, + 0xe6, 0xb1, 0x25, 0xc7, 0x1d, 0xf8, 0x04, 0xf9, 0x2c, 0xf9, 0xbd, 0xc8, 0xc0, + 0x53, 0x4c, 0xdf, 0x60, 0x05, 0xf3, 0xf3, 0x15, 0xd4, 0x12, 0xbc, 0xdc, 0x35, + 0x00, 0x08, 0xee, 0xb4, 0x20, 0xc2, 0x43, 0xe6, 0x11, 0xf9, 0x24, 0xcc, 0xdd, + 0x1c, 0x19, 0xef, 0x9e, 0x04, 0xfe, 0xf6, 0xc1, 0xd1, 0xf3, 0xf9, 0xe3, 0xf8, + 0x19, 0x39, 0xea, 0x38, 0x07, 0x28, 0x1a, 0x20, 0xca, 0xcf, 0xe8, 0xc2, 0xb4, + 0xe3, 0x33, 0xc8, 0xdd, 0xfb, 0x0a, 0x10, 0x33, 0x0c, 0xc8, 0x51, 0xd7, 0x11, + 0xcd, 0xc7, 0x0a, 0xf7, 0x3f, 0x26, 0x03, 0xf3, 0xec, 0x10, 0x16, 0xce, 0xee, + 0xf0, 0x03, 0x1f, 0xee, 0xe7, 0x0e, 0x43, 0xe9, 0xfb, 0xfe, 0xef, 0xc0, 0xc7, + 0x04, 0x06, 0x11, 0x18, 0xc4, 0xbd, 0x09, 0x06, 0xf4, 0x11, 0xdd, 0xde, 0x32, + 0x95, 0xa5, 0x07, 0x11, 0xe1, 0x03, 0x39, 0xea, 0x27, 0xef, 0xcf, 0x00, 0xc8, + 0xf0, 0x12, 0xf1, 0xf1, 0xe1, 0x2f, 0xbd, 0x59, 0x13, 0xc2, 0x0a, 0x24, 0xa8, + 0x36, 0x08, 0x3a, 0xde, 0xbb, 0xea, 0x24, 0x46, 0xfc, 0xd5, 0x12, 0xdb, 0xdd, + 0xe6, 0x21, 0xea, 0x00, 0xac, 0x25, 0x07, 0xfc, 0x0f, 0xec, 0xbe, 0xf0, 0x22, + 0xec, 0x0a, 0x3b, 0x1c, 0x30, 0x02, 0x2f, 0x4d, 0x19, 0xf6, 0xe8, 0x25, 0x24, + 0xe7, 0xc0, 0x1c, 0xa5, 0x27, 0x96, 0x1f, 0xd7, 0xf9, 0x2d, 0x16, 0x41, 0x22, + 0xe5, 0xdd, 0xf0, 0xec, 0x27, 0x09, 0x20, 0xf6, 0x14, 0x38, 0xdf, 0xc5, 0xf7, + 0x19, 0x25, 0x14, 0xd7, 0x28, 0xbf, 0xd5, 0xcb, 0x05, 0x50, 0xff, 0xed, 0x13, + 0xfe, 0xb7, 0xc9, 0xbc, 0x25, 0xd1, 0xeb, 0xd1, 0x55, 0xba, 0xef, 0x15, 0x51, + 0x03, 0xe7, 0xea, 0xb7, 0x09, 0xe9, 0x22, 0x37, 0xe2, 0x39, 0xd2, 0xe8, 0xe7, + 0x15, 0xac, 0x2f, 0xfa, 0x01, 0xdb, 0x49, 0xe4, 0xea, 0xda, 0xc9, 0xce, 0xfb, + 0xe1, 0x10, 0xe9, 0x14, 0xc3, 0x13, 0xd4, 0x46, 0xaa, 0x65, 0xe7, 0xb5, 0xf1, + 0xef, 0xfa, 0x37, 0x10, 0x02, 0xba, 0xee, 0xd4, 0xed, 0x33, 0x81, 0xcd, 0xb6, + 0x47, 0x0c, 0x10, 0xd2, 0x54, 0xe7, 0x0e, 0xe0, 0xe4, 0xf5, 0x02, 0x00, 0x0f, + 0xd7, 0xb5, 0x14, 0xff, 0xef, 0xdf, 0xfd, 0x03, 0xe9, 0x3d, 0xe1, 0xd3, 0x7f, + 0xfc, 0xeb, 0xf8, 0x9a, 0xe3, 0xf0, 0x2a, 0xef, 0xf2, 0xfe, 0x43, 0xde, 0xec, + 0xfb, 0xd2, 0xff, 0xe4, 0x1c, 0x04, 0xe6, 0x0a, 0x16, 0xec, 0xc7, 0x9d, 0xfc, + 0x0e, 0x2c, 0xcd, 0xc3, 0xed, 0xf1, 0x15, 0xf5, 0x05, 0xef, 0x27, 0x21, 0xef, + 0xda, 0xfc, 0x1d, 0x26, 0x28, 0x15, 0xff, 0x0d, 0xdf, 0x1e, 0x06, 0xe2, 0xba, + 0x28, 0xec, 0x04, 0xee, 0x04, 0x21, 0xff, 0x01, 0x1d, 0x15, 0xd3, 0x26, 0xf5, + 0xdf, 0x37, 0x06, 0xf2, 0x1a, 0xe7, 0x45, 0xf9, 0xfa, 0x2a, 0x25, 0xd8, 0x12, + 0xd3, 0x07, 0x1c, 0xe1, 0xfb, 0x00, 0xee, 0xdd, 0x27, 0x1f, 0xd9, 0xed, 0x14, + 0xf5, 0x1a, 0xcd, 0x3c, 0xfa, 0x1b, 0x00, 0xe2, 0xf4, 0xe2, 0x10, 0xdd, 0x17, + 0xd3, 0x15, 0xcd, 0x3d, 0x5c, 0xc4, 0x04, 0x03, 0xde, 0xed, 0xef, 0xeb, 0xe4, + 0xf7, 0x15, 0xbf, 0xe8, 0xee, 0xec, 0x05, 0x0a, 0xe1, 0x24, 0x26, 0xde, 0x09, + 0xfb, 0x2a, 0xf0, 0x29, 0xde, 0x09, 0xea, 0xf5, 0xdc, 0xf0, 0xfd, 0xfd, 0xbd, + 0xfa, 0xe1, 0x30, 0xc5, 0x08, 0xc6, 0xf5, 0xca, 0xfd, 0xea, 0xd4, 0xde, 0xe7, + 0xe7, 0x0a, 0xdf, 0xf1, 0xe4, 0xe9, 0x01, 0x04, 0xf9, 0xd8, 0x3c, 0xe6, 0xe3, + 0xeb, 0xe4, 0x22, 0xec, 0xdf, 0x15, 0x24, 0x07, 0x23, 0xff, 0x18, 0xf7, 0x0a, + 0xb7, 0xe5, 0x28, 0xe6, 0x0f, 0x0b, 0x06, 0xf8, 0xdc, 0x00, 0x20, 0xf4, 0xcb, + 0x06, 0xf6, 0xfe, 0xfb, 0xd3, 0xc2, 0x0b, 0x47, 0x05, 0x0c, 0x22, 0x07, 0x06, + 0xec, 0x1f, 0xe1, 0xfc, 0x08, 0xdf, 0xb6, 0xf1, 0x0b, 0x05, 0xf6, 0x38, 0x00, + 0xeb, 0x07, 0xcd, 0x19, 0x29, 0xda, 0xed, 0xfa, 0xfe, 0x39, 0xa8, 0xc1, 0x19, + 0xd9, 0xdf, 0x23, 0xec, 0x2a, 0xfc, 0x0a, 0x00, 0xc1, 0x26, 0xb7, 0xfe, 0xbd, + 0xf6, 0x48, 0x0a, 0xd6, 0xe3, 0xd5, 0xe0, 0x1a, 0xf3, 0x0e, 0x00, 0x19, 0x22, + 0xf8, 0xcf, 0x22, 0x04, 0xbf, 0xeb, 0x08, 0xee, 0xbb, 0xfd, 0xf6, 0xd9, 0x30, + 0x26, 0xd0, 0xe7, 0x01, 0x07, 0xee, 0x1f, 0x07, 0xf8, 0xb1, 0x41, 0x00, 0x17, + 0xb9, 0xd2, 0xeb, 0xce, 0x0b, 0xea, 0xe5, 0xf0, 0xd7, 0x1d, 0x10, 0xe8, 0x23, + 0x02, 0xdb, 0x25, 0x06, 0xdf, 0xe0, 0xf9, 0xec, 0xf1, 0xe1, 0xee, 0xfd, 0xea, + 0xde, 0xfe, 0x03, 0xd1, 0xe5, 0xd9, 0xfb, 0xed, 0x01, 0xe2, 0x1a, 0x02, 0x1a, + 0x31, 0xc8, 0x1b, 0x3c, 0xf5, 0xe2, 0xfd, 0x0d, 0x31, 0xec, 0x30, 0xb9, 0x3f, + 0xc8, 0xe7, 0x0a, 0x0f, 0xee, 0xea, 0xfd, 0xfd, 0x04, 0x01, 0x05, 0x27, 0xff, + 0xee, 0x00, 0xef, 0xd1, 0xc1, 0xde, 0x11, 0xf2, 0xe0, 0x0a, 0xbe, 0xed, 0x20, + 0x09, 0x08, 0xed, 0xd4, 0xc7, 0x08, 0x05, 0xcc, 0x00, 0xcf, 0xd3, 0x0d, 0x07, + 0x24, 0xc8, 0x0e, 0xe8, 0x4e, 0x41, 0xf1, 0xdf, 0xd8, 0xc5, 0x30, 0xfc, 0x12, + 0xf4, 0xfd, 0xdd, 0x23, 0x34, 0xf1, 0x18, 0xef, 0x20, 0x01, 0x01, 0x10, 0x04, + 0x03, 0x14, 0xf8, 0x0b, 0xcf, 0xfd, 0x35, 0xff, 0xf3, 0x0c, 0x0a, 0xc0, 0xb9, + 0xf9, 0x2d, 0x0f, 0xe0, 0x24, 0xef, 0x26, 0xae, 0xde, 0xdc, 0xf4, 0x1a, 0xe3, + 0x25, 0xfb, 0xd5, 0x1b, 0x22, 0xf7, 0x17, 0x1c, 0xb8, 0x40, 0xb7, 0xf0, 0xe1, + 0x09, 0x1c, 0xc3, 0xdf, 0xd1, 0xc9, 0xd6, 0xf2, 0xf6, 0x07, 0xd6, 0x0c, 0xd7, + 0xbb, 0xe5, 0xbd, 0xd6, 0xdf, 0xf9, 0x04, 0x17, 0xe2, 0xda, 0x1a, 0x45, 0x1c, + 0xd6, 0xe7, 0x0c, 0xdd, 0x14, 0x1a, 0xcf, 0x0f, 0xd1, 0xe3, 0xef, 0xd8, 0x27, + 0x16, 0xe3, 0xd1, 0xc9, 0x0e, 0xf9, 0xfb, 0xd9, 0x81, 0x13, 0xeb, 0x01, 0xe5, + 0x26, 0xee, 0x7f, 0xcf, 0xc3, 0xe0, 0xc1, 0x20, 0xd6, 0x01, 0xdf, 0x27, 0xfb, + 0xe9, 0x10, 0xb8, 0xfa, 0xda, 0x15, 0xb8, 0xe7, 0xc9, 0xeb, 0xbf, 0x03, 0xea, + 0xed, 0x11, 0xe5, 0x0f, 0xc5, 0xee, 0xe6, 0xa5, 0x03, 0x0a, 0x0e, 0x11, 0x24, + 0xdd, 0x11, 0xdc, 0x1c, 0xe1, 0xc5, 0x19, 0xf0, 0xd7, 0xdb, 0xdc, 0xc4, 0xec, + 0x10, 0x60, 0x3d, 0x25, 0x06, 0xf2, 0xee, 0x05, 0x23, 0xf3, 0xf4, 0xfb, 0xfb, + 0xb8, 0xfb, 0x02, 0xd3, 0x16, 0xae, 0xca, 0xfe, 0xa2, 0xfd, 0x16, 0xd2, 0xbe, + 0xec, 0xe6, 0xb0, 0xb9, 0xe5, 0x03, 0x07, 0x14, 0xa9, 0x25, 0xee, 0xc6, 0x1e, + 0xf5, 0xb1, 0xc5, 0xdb, 0xfb, 0xd5, 0x49, 0xda, 0x2e, 0xf1, 0xe7, 0x08, 0xe0, + 0xe4, 0xc2, 0xbf, 0xdd, 0x0a, 0xd5, 0xf1, 0xe3, 0xc1, 0x01, 0x42, 0xdc, 0xe4, + 0xfd, 0xfa, 0xd6, 0xd7, 0xcb, 0x37, 0xc3, 0xf1, 0xd8, 0x07, 0xbc, 0x21, 0xf8, + 0xc8, 0xc7, 0xf2, 0x38, 0xe6, 0xc4, 0xc3, 0x0a, 0xff, 0xb9, 0xf4, 0xc5, 0xda, + 0xc4, 0xf9, 0x3d, 0x00, 0x0d, 0x1c, 0x06, 0xfa, 0x35, 0x2e, 0xe8, 0xec, 0x05, + 0x04, 0x15, 0x26, 0xc0, 0xde, 0x23, 0xda, 0x23, 0xd7, 0x12, 0xa9, 0xf5, 0x36, + 0xfb, 0xc1, 0xe6, 0xaa, 0xf4, 0xfb, 0x1b, 0xd3, 0x1b, 0xea, 0xd0, 0xc7, 0x03, + 0xd4, 0x30, 0x0c, 0x0d, 0xed, 0x16, 0xf5, 0xd2, 0xc2, 0xf8, 0xe7, 0xd1, 0xa7, + 0xef, 0x07, 0xe4, 0xf5, 0x25, 0x2e, 0xd1, 0x58, 0xef, 0x15, 0xfe, 0x1d, 0xe7, + 0x14, 0xfe, 0x05, 0xda, 0xfc, 0x1a, 0x09, 0x95, 0xca, 0xe8, 0x0d, 0xce, 0x06, + 0x1a, 0x13, 0x1c, 0x05, 0x0c, 0x28, 0x02, 0x39, 0xe6, 0xc0, 0xe1, 0x02, 0xbf, + 0x36, 0x30, 0xf9, 0x1c, 0xc5, 0xa8, 0xff, 0xd0, 0x2d, 0xff, 0xf1, 0x0e, 0xf1, + 0x05, 0xfb, 0xd4, 0xf4, 0x24, 0x09, 0xec, 0x18, 0xf2, 0xfa, 0xe8, 0x11, 0xbb, + 0x41, 0xce, 0xbb, 0xd5, 0xf1, 0x01, 0x34, 0x16, 0xc3, 0xec, 0xfb, 0xbd, 0x61, + 0xd6, 0x20, 0xdb, 0xd9, 0xf9, 0xb1, 0xff, 0x03, 0x4a, 0x14, 0x31, 0xe8, 0xe5, + 0x14, 0xd0, 0xe6, 0xb3, 0x8c, 0x5e, 0xc3, 0x0e, 0xc4, 0xfd, 0x98, 0xf8, 0xfe, + 0x42, 0xa4, 0x1e, 0x16, 0xee, 0x15, 0xc9, 0xee, 0xe6, 0x31, 0x1e, 0xea, 0x53, + 0x2e, 0x81, 0x1b, 0xb6, 0xe6, 0x14, 0x28, 0xe4, 0x4f, 0x1f, 0x28, 0x11, 0xd6, + 0xd5, 0x5e, 0x39, 0x07, 0x1d, 0xdc, 0xb5, 0xea, 0xfe, 0x2b, 0x35, 0x54, 0xc3, + 0xba, 0x32, 0xec, 0xe9, 0xc3, 0x29, 0x13, 0xcc, 0xc4, 0xf8, 0x37, 0xbf, 0x85, + 0xb4, 0xcd, 0x23, 0xf4, 0xa4, 0xeb, 0xdc, 0x20, 0x48, 0x0b, 0xce, 0x03, 0x0d, + 0xf7, 0xdb, 0x93, 0x0d, 0xfd, 0xaf, 0x1c, 0x32, 0x24, 0x07, 0x0e, 0xb5, 0x3e, + 0x2a, 0xdc, 0x43, 0xe9, 0xe7, 0x1a, 0x1b, 0xe4, 0x28, 0x12, 0xf3, 0x28, 0xd1, + 0xc6, 0xfa, 0x18, 0xe8, 0x21, 0xef, 0x88, 0xea, 0xe8, 0xe2, 0x9b, 0xca, 0xdb, + 0x57, 0x0d, 0x07, 0x94, 0xf2, 0x2e, 0x9e, 0xda, 0xb6, 0x2c, 0x2d, 0xf6, 0xfa, + 0xba, 0x3f, 0xd9, 0x6c, 0x23, 0x06, 0x2d, 0xff, 0xfe, 0x27, 0x11, 0x1f, 0x13, + 0x1a, 0xd2, 0x1f, 0x99, 0xd9, 0xb0, 0xe7, 0xe4, 0xb2, 0x2c, 0xb0, 0xce, 0xcf, + 0x4a, 0x41, 0xbf, 0xb8, 0xd5, 0x93, 0xed, 0x55, 0xbe, 0x05, 0xed, 0xf1, 0x2b, + 0x27, 0x49, 0xcf, 0x05, 0x07, 0xd6, 0x21, 0x1b, 0xf3, 0xcc, 0x0c, 0xa9, 0x26, + 0x32, 0xd0, 0x1d, 0xc6, 0x18, 0x0c, 0x15, 0x08, 0xba, 0x19, 0xb9, 0xe7, 0xe4, + 0x42, 0x35, 0x11, 0xe2, 0xea, 0x05, 0xe9, 0x10, 0xb0, 0xd3, 0xe8, 0x25, 0x28, + 0xbf, 0xc5, 0xe9, 0x09, 0xd5, 0xed, 0x0d, 0x98, 0x22, 0xf0, 0x50, 0x0a, 0x26, + 0x33, 0x0e, 0xff, 0xca, 0xe0, 0x17, 0xd6, 0xe9, 0xf0, 0x1e, 0x02, 0x1d, 0xd1, + 0xfd, 0xe3, 0x1c, 0xfe, 0xe2, 0x42, 0xb2, 0x2f, 0x48, 0x07, 0xec, 0xb1, 0xb7, + 0x00, 0x88, 0x23, 0xd5, 0x21, 0xa2, 0x18, 0xd8, 0x81, 0xef, 0x0b, 0xf8, 0x01, + 0x25, 0x14, 0x3d, 0xc3, 0x00, 0x03, 0x0f, 0x42, 0xa1, 0x3a, 0xc3, 0x3b, 0xb8, + 0x4e, 0xdb, 0xf4, 0xf4, 0xfe, 0xea, 0x1b, 0x23, 0xc1, 0x23, 0x1a, 0x3b, 0xcc, + 0x22, 0x1d, 0x0c, 0x8c, 0xdd, 0xf5, 0xca, 0xed, 0xf8, 0xef, 0xf3, 0x1c, 0x2a, + 0xd3, 0xc0, 0xc9, 0xdc, 0xeb, 0x11, 0xeb, 0xe7, 0xc5, 0xcb, 0x02, 0xff, 0xfe, + 0xb9, 0xe3, 0xf3, 0x22, 0x4f, 0x10, 0xfb, 0x37, 0x0e, 0x2d, 0x1f, 0xc7, 0x1e, + 0xce, 0x1d, 0xfd, 0x12, 0x86, 0x39, 0xcd, 0xc5, 0x33, 0xce, 0xc3, 0x45, 0x11, + 0x24, 0x9f, 0x1b, 0xd0, 0x24, 0xf6, 0x22, 0xb7, 0x30, 0xc7, 0xb8, 0x2a, 0xef, + 0x02, 0x3d, 0x5c, 0x15, 0x60, 0xf2, 0xc6, 0xe3, 0xd5, 0x05, 0xc2, 0x0e, 0xe2, + 0xb2, 0xc6, 0x2e, 0xf4, 0xef, 0x0f, 0x98, 0xc4, 0xce, 0x1f, 0xe6, 0xd2, 0xaa, + 0xf2, 0x46, 0xc6, 0xe5, 0x62, 0x3f, 0xcc, 0x4f, 0xe9, 0xdf, 0x16, 0xed, 0x53, + 0xb6, 0xf3, 0xde, 0xc3, 0x89, 0x32, 0xc7, 0xe5, 0x04, 0x09, 0x2c, 0x07, 0xc0, + 0xe0, 0x4a, 0x31, 0x41, 0xdc, 0xb2, 0xbe, 0xc4, 0x3f, 0xf1, 0x09, 0xb0, 0x0f, + 0x42, 0x0c, 0x15, 0x26, 0xd6, 0xad, 0x29, 0xcc, 0x98, 0xb1, 0xe9, 0xd6, 0xf7, + 0xa8, 0xe4, 0xe4, 0x0a, 0xd2, 0x1c, 0xdf, 0xbe, 0xa9, 0xeb, 0x09, 0xdf, 0x2e, + 0x13, 0x31, 0x0a, 0x37, 0xad, 0x3c, 0xcb, 0xf3, 0x37, 0xe9, 0xe8, 0x3d, 0xae, + 0x14, 0xf2, 0xef, 0xe6, 0x18, 0x00, 0xc6, 0xc3, 0xe3, 0xf3, 0xcd, 0xb0, 0xee, + 0x28, 0x19, 0x4b, 0xb1, 0xd4, 0x2b, 0x0a, 0xe5, 0x05, 0x05, 0xee, 0xfb, 0xfa, + 0x23, 0xeb, 0x01, 0xf1, 0xe5, 0x1c, 0xe5, 0xd1, 0xb9, 0xeb, 0x18, 0xe1, 0x02, + 0xe6, 0x24, 0x24, 0xd6, 0xf3, 0x0b, 0x27, 0xfa, 0xe6, 0xce, 0xfe, 0xe9, 0xf3, + 0xe3, 0x06, 0x0d, 0x0d, 0xf4, 0x3f, 0xf6, 0xdc, 0x27, 0xd2, 0xf7, 0xd8, 0x01, + 0xe9, 0x05, 0x15, 0xf6, 0x17, 0xfd, 0x1d, 0x08, 0xcd, 0xf5, 0xfb, 0x06, 0x0d, + 0x08, 0xe0, 0x37, 0x20, 0x0b, 0x16, 0xfc, 0x29, 0x09, 0xdc, 0x16, 0xdc, 0x14, + 0x1a, 0x51, 0xc2, 0x58, 0x05, 0x16, 0xf9, 0x11, 0xee, 0x14, 0xd7, 0x22, 0x19, + 0xd3, 0xfc, 0xf3, 0x00, 0x44, 0xe5, 0xff, 0xea, 0xe5, 0x13, 0xd3, 0xee, 0xe9, + 0x0e, 0xf6, 0xdc, 0x49, 0xe1, 0xf9, 0x12, 0xe3, 0xcb, 0x04, 0xe0, 0xe1, 0x15, + 0xe9, 0xeb, 0x08, 0x01, 0x02, 0xda, 0x04, 0xf5, 0x13, 0xfd, 0xec, 0x1c, 0xdb, + 0x16, 0xed, 0xf8, 0xcc, 0x0f, 0xd2, 0x3d, 0x0e, 0xd6, 0x1d, 0x1b, 0x13, 0x19, + 0x13, 0x03, 0xf3, 0x1c, 0x24, 0x25, 0x4d, 0xc2, 0xc8, 0x00, 0xbf, 0x27, 0x18, + 0x15, 0x28, 0x02, 0x1a, 0x06, 0xe9, 0xde, 0x0e, 0x2a, 0xfe, 0x03, 0x10, 0x36, + 0xe4, 0xd6, 0xec, 0x0f, 0x0e, 0xf7, 0xd1, 0xe5, 0x12, 0xf5, 0xcf, 0x46, 0x12, + 0xd2, 0xd6, 0x10, 0x01, 0x7f, 0x0b, 0xd1, 0x22, 0xd6, 0xf7, 0xe4, 0xdf, 0xe6, + 0xf4, 0xda, 0xd5, 0xf3, 0x2f, 0xe2, 0x18, 0x09, 0xd2, 0xdb, 0xe2, 0x1c, 0xf5, + 0xd7, 0x1c, 0xed, 0xe2, 0xff, 0xb5, 0x38, 0xd7, 0xf6, 0xbc, 0x2b, 0x06, 0xc5, + 0xea, 0x14, 0xf3, 0xb7, 0xfa, 0xfe, 0x20, 0x12, 0xe8, 0x27, 0xd1, 0xf4, 0xdc, + 0xf3, 0xf1, 0xfb, 0x37, 0x29, 0xfc, 0x0d, 0xc5, 0xfc, 0xcd, 0x1d, 0xff, 0xc4, + 0xd4, 0xc5, 0x25, 0xf9, 0x16, 0x0a, 0x18, 0xfc, 0x08, 0x03, 0xd9, 0xf3, 0xe1, + 0xfc, 0xea, 0x06, 0x19, 0xe5, 0x05, 0xfe, 0x01, 0xe6, 0xfc, 0x1f, 0x24, 0xd9, + 0x10, 0xfc, 0xfc, 0xe5, 0xd8, 0x30, 0x10, 0xcc, 0x04, 0xd7, 0xe5, 0xad, 0x0a, + 0xf4, 0xfc, 0x21, 0xb5, 0x16, 0x03, 0x30, 0x1f, 0x3f, 0xfa, 0xe1, 0x3b, 0xf2, + 0xc1, 0xe1, 0xe1, 0x0c, 0x15, 0xe7, 0xee, 0x19, 0xfd, 0x38, 0xef, 0xfc, 0xf4, + 0xf0, 0x0e, 0xf8, 0x2d, 0xdb, 0xc9, 0xeb, 0x18, 0x48, 0x1d, 0x14, 0xd6, 0x2e, + 0xd9, 0x27, 0xaf, 0x2a, 0xe6, 0xe1, 0xe8, 0x07, 0x2d, 0xff, 0xe7, 0xd8, 0xcf, + 0xc6, 0x09, 0x29, 0xd9, 0x0d, 0xd2, 0xe3, 0x3f, 0xbe, 0x09, 0xf5, 0x0d, 0x02, + 0xea, 0x14, 0xfc, 0xe9, 0x01, 0xb3, 0x04, 0x1d, 0xf1, 0xfc, 0xe0, 0x36, 0x39, + 0xff, 0xa9, 0xfc, 0xdb, 0x04, 0x09, 0x23, 0xf0, 0x28, 0xca, 0xd6, 0xed, 0x08, + 0xf0, 0x97, 0xf3, 0xec, 0xf4, 0x50, 0x0e, 0x56, 0xff, 0xe5, 0x20, 0xf7, 0xcb, + 0xf0, 0x13, 0xf4, 0xfa, 0x0f, 0x23, 0x7f, 0x0f, 0x04, 0xe0, 0x2e, 0xff, 0xd5, + 0xbd, 0x09, 0xe6, 0x11, 0x27, 0xfc, 0xb6, 0xfd, 0xa8, 0xd8, 0xe8, 0xf1, 0x08, + 0xc1, 0xdb, 0x1a, 0x00, 0xf1, 0x2c, 0xc1, 0xf5, 0xad, 0x10, 0x05, 0xe9, 0x07, + 0xed, 0xca, 0xdb, 0xd8, 0x13, 0xd9, 0x0c, 0x09, 0xe2, 0xe6, 0xd4, 0x25, 0x17, + 0xff, 0x17, 0xf0, 0x50, 0xfb, 0x04, 0x18, 0xdd, 0xef, 0x21, 0xd0, 0xfc, 0xe9, + 0xe3, 0xfe, 0xc1, 0xf0, 0x24, 0xfd, 0x0f, 0x05, 0x08, 0xef, 0xf7, 0x1c, 0xd4, + 0xce, 0xff, 0xb1, 0xdf, 0x16, 0x05, 0xf0, 0xd8, 0xe3, 0xf6, 0xe9, 0x1a, 0x1a, + 0xf8, 0xfd, 0xe5, 0xc1, 0x1d, 0x03, 0x0a, 0xd0, 0xf6, 0xf6, 0x16, 0x27, 0xe8, + 0x04, 0x3c, 0xd3, 0xba, 0xc8, 0x35, 0x29, 0x14, 0x17, 0x03, 0xeb, 0xca, 0x44, + 0xee, 0xe4, 0xb4, 0x0e, 0x16, 0x16, 0x0b, 0xfc, 0xd5, 0x04, 0xea, 0x19, 0xdd, + 0xe5, 0x11, 0x23, 0x18, 0x36, 0xe9, 0xb7, 0xfd, 0x2f, 0x1e, 0x8c, 0xbf, 0x4b, + 0x17, 0xba, 0xe8, 0xef, 0x0f, 0xaf, 0xc8, 0x11, 0xdf, 0x13, 0x98, 0x29, 0x20, + 0x12, 0x4c, 0xe9, 0x9c, 0x28, 0x18, 0xc9, 0x24, 0xf5, 0xf5, 0xe3, 0x9b, 0x21, + 0x19, 0xe1, 0xd0, 0xb5, 0xf7, 0x41, 0x0a, 0xef, 0x88, 0xd0, 0xe5, 0xc1, 0xf0, + 0xfc, 0xca, 0xc6, 0x06, 0xf0, 0xea, 0x21, 0xf2, 0x1e, 0xd5, 0xc3, 0xf6, 0xfb, + 0x09, 0x01, 0x9a, 0x13, 0x04, 0xb0, 0xbb, 0x0b, 0x18, 0x05, 0xa0, 0x01, 0xcc, + 0xe3, 0x45, 0x81, 0xae, 0x28, 0x98, 0xe3, 0x8a, 0x1c, 0x6b, 0xe6, 0xca, 0xf9, + 0x1d, 0xe7, 0x08, 0x1a, 0xcd, 0xda, 0x58, 0x4c, 0x0f, 0xa9, 0xf1, 0x16, 0x08, + 0xa6, 0x47, 0x05, 0xd5, 0x17, 0xfc, 0x39, 0x31, 0xe1, 0x5f, 0x12, 0x5f, 0x00, + 0xf0, 0xac, 0xe5, 0x29, 0xbc, 0xec, 0xf2, 0x11, 0x07, 0x33, 0x0e, 0x19, 0x1e, + 0xbb, 0x29, 0xfc, 0xc4, 0xb3, 0x41, 0x59, 0x15, 0xe4, 0x64, 0x57, 0xf0, 0xb7, + 0xeb, 0xef, 0x00, 0xad, 0xc7, 0x19, 0xdb, 0xed, 0x15, 0xdc, 0xfa, 0xeb, 0xde, + 0x26, 0xd2, 0x0c, 0x8b, 0xf0, 0x3b, 0x04, 0xed, 0xee, 0x1d, 0xe9, 0xe6, 0x23, + 0xe3, 0x34, 0x34, 0x07, 0x4f, 0x3e, 0x08, 0xa5, 0xa9, 0x3f, 0xe6, 0x0a, 0xeb, + 0xd6, 0xd6, 0xf0, 0xe4, 0x09, 0x97, 0xec, 0x41, 0xd5, 0x04, 0xe0, 0xf3, 0x04, + 0xfe, 0x10, 0xc9, 0x07, 0x86, 0xfc, 0x55, 0xc4, 0xe6, 0xf9, 0x1a, 0x57, 0x4e, + 0xd5, 0xd5, 0xd6, 0xe8, 0x07, 0x1a, 0xe4, 0x01, 0xb0, 0xe2, 0x83, 0xff, 0xee, + 0xb2, 0xf4, 0x2f, 0xc0, 0x17, 0x52, 0x39, 0x0b, 0x0a, 0x08, 0x24, 0xe5, 0xfc, + 0x20, 0x35, 0x81, 0x2c, 0x4d, 0x3a, 0x33, 0x2c, 0x15, 0x14, 0x93, 0xb8, 0x29, + 0xff, 0x08, 0x50, 0xd8, 0xc2, 0xb6, 0xd6, 0x3b, 0xc6, 0x13, 0xe4, 0x12, 0xfb, + 0xcf, 0x29, 0x33, 0x11, 0x10, 0xf2, 0x1f, 0x1a, 0xe6, 0xb2, 0x0c, 0x0e, 0x1f, + 0x0a, 0x1a, 0x14, 0xde, 0x03, 0xec, 0xed, 0x28, 0xe4, 0xbe, 0x0d, 0xaf, 0x1a, + 0x10, 0xe5, 0xe7, 0x03, 0xfd, 0xb7, 0xe6, 0xd5, 0xff, 0x0a, 0x15, 0x06, 0xca, + 0xe3, 0x07, 0xe9, 0xc3, 0xae, 0xe5, 0x11, 0x31, 0x1a, 0xfd, 0x38, 0x09, 0xe4, + 0x02, 0xe3, 0xec, 0xd6, 0x1f, 0xae, 0xed, 0xe3, 0x00, 0xc9, 0xfe, 0xd1, 0xf5, + 0x00, 0xf7, 0xf1, 0x04, 0x14, 0x05, 0xed, 0x3a, 0xfd, 0xf1, 0xea, 0xec, 0x31, + 0x41, 0x1f, 0x21, 0xf7, 0xbc, 0x3e, 0xea, 0x39, 0x01, 0x05, 0x09, 0x0e, 0xd9, + 0x22, 0xfb, 0xef, 0x04, 0x42, 0x22, 0x02, 0xc5, 0xc7, 0x1a, 0x1a, 0x0a, 0xed, + 0xfd, 0x14, 0xf7, 0xf2, 0x0d, 0xf4, 0xc3, 0x1f, 0x27, 0xe7, 0xd9, 0xdd, 0x04, + 0x20, 0x02, 0x7f, 0xb3, 0xc0, 0xcf, 0xe2, 0xd1, 0x0c, 0x07, 0xe0, 0x6d, 0x12, + 0x28, 0xf5, 0x1c, 0x18, 0x1f, 0xf6, 0xfe, 0xb9, 0xf2, 0xfa, 0xda, 0xa9, 0xeb, + 0xd9, 0xe3, 0x1d, 0x08, 0xd0, 0xcc, 0x1c, 0xd7, 0x30, 0xea, 0x09, 0xed, 0xe5, + 0x04, 0x1d, 0x14, 0xdb, 0x1c, 0x1d, 0xf8, 0xfd, 0xe0, 0x14, 0x05, 0xcd, 0xd4, + 0xdb, 0xbc, 0x02, 0xf2, 0xf2, 0x00, 0xd5, 0xf4, 0x07, 0x29, 0xe4, 0xfc, 0x01, + 0x35, 0xd8, 0xd3, 0xd4, 0xeb, 0x3e, 0xee, 0xd5, 0x0a, 0xd1, 0x0c, 0x0a, 0x10, + 0x2c, 0xf1, 0x0d, 0xeb, 0xdc, 0xff, 0xe9, 0xd2, 0x02, 0x14, 0xf0, 0xae, 0x22, + 0x06, 0xd6, 0xf4, 0x30, 0xc5, 0xd4, 0xcc, 0x19, 0x05, 0x18, 0xe0, 0xc6, 0x15, + 0x0e, 0xea, 0xf9, 0x11, 0x3b, 0xe8, 0x60, 0x15, 0xfe, 0xec, 0xfb, 0x24, 0xe1, + 0xf8, 0x1a, 0x14, 0x12, 0xea, 0x23, 0xce, 0xe0, 0xe3, 0x0e, 0x32, 0x51, 0x05, + 0x26, 0x06, 0x06, 0x4c, 0xde, 0xeb, 0xf0, 0xdf, 0xf1, 0x02, 0x1f, 0x3a, 0x1b, + 0x3d, 0xd7, 0xcc, 0x0c, 0xd4, 0xe3, 0xef, 0x08, 0xed, 0xaa, 0x15, 0xb3, 0x19, + 0xe6, 0xbb, 0x2b, 0x1d, 0xde, 0x2d, 0x01, 0xbd, 0xe5, 0xfa, 0x10, 0xba, 0x1a, + 0xec, 0xe9, 0xb5, 0x17, 0x1f, 0xd5, 0x19, 0xd8, 0x3a, 0x1c, 0xe0, 0xb8, 0x07, + 0xe4, 0x14, 0x38, 0xeb, 0x06, 0xfe, 0xc5, 0xee, 0xf8, 0xa6, 0x08, 0xff, 0xf2, + 0x00, 0xd4, 0xe2, 0x2c, 0xfe, 0x28, 0x2a, 0x17, 0xa0, 0x05, 0xe9, 0xf9, 0xb6, + 0x15, 0xef, 0x06, 0x27, 0xfa, 0x17, 0xda, 0xe1, 0x18, 0xd0, 0xb8, 0x58, 0xaf, + 0xf6, 0xdd, 0xf6, 0x2f, 0x05, 0x0f, 0xe1, 0x38, 0xfd, 0x06, 0xd2, 0x05, 0xb4, + 0x00, 0xd6, 0x02, 0x01, 0x27, 0x8b, 0x06, 0xdb, 0xfa, 0x10, 0x4c, 0xe8, 0x02, + 0xa1, 0x16, 0xf8, 0xe8, 0xdd, 0xf4, 0xa5, 0xcd, 0xab, 0xf8, 0xf7, 0x09, 0xc2, + 0x18, 0x2f, 0x10, 0xd6, 0xd3, 0x40, 0xea, 0x33, 0xd2, 0xec, 0x08, 0xf4, 0x01, + 0x03, 0xe3, 0x1f, 0xc5, 0xe5, 0x7f, 0xd7, 0xe1, 0x16, 0x0c, 0x0d, 0xb1, 0xf3, + 0x3e, 0xed, 0xc9, 0xd8, 0xf9, 0x72, 0x08, 0x9a, 0xea, 0xf9, 0x2f, 0x4d, 0xd7, + 0xc5, 0x0a, 0xe2, 0xe2, 0xb8, 0x54, 0xd2, 0xe0, 0x16, 0x0b, 0xeb, 0x13, 0xe0, + 0x2a, 0xbe, 0xce, 0x33, 0x8c, 0xfc, 0xdc, 0x60, 0xdf, 0xe0, 0xed, 0xe5, 0x2b, + 0xd9, 0xbd, 0xd3, 0x2a, 0x26, 0xb1, 0xab, 0x12, 0x9a, 0xc0, 0xd3, 0xb0, 0x12, + 0xd4, 0x17, 0xc6, 0xed, 0xa6, 0xe5, 0x06, 0x09, 0x2a, 0xf5, 0xa9, 0xfc, 0xe1, + 0x5b, 0xd2, 0xfa, 0xed, 0x23, 0x1f, 0xed, 0xb1, 0x11, 0xec, 0x0c, 0x01, 0x01, + 0xcb, 0x25, 0xd8, 0x13, 0x15, 0xf2, 0x1c, 0xee, 0xd4, 0xd8, 0xf6, 0xfe, 0x3d, + 0xde, 0x01, 0xca, 0xc7, 0xe7, 0x9a, 0xd4, 0x15, 0x0d, 0xf9, 0x17, 0xd7, 0xfa, + 0xe6, 0xc0, 0xcc, 0x36, 0x23, 0xeb, 0xf8, 0xe5, 0xd2, 0x1c, 0xd8, 0xdf, 0xb2, + 0xeb, 0xf4, 0xea, 0x1e, 0xfb, 0xdd, 0xfc, 0xf2, 0x1f, 0xe0, 0xfb, 0xd0, 0x26, + 0xef, 0xa5, 0xeb, 0xd2, 0xfb, 0x07, 0x19, 0xfd, 0xee, 0x16, 0x06, 0xd2, 0xee, + 0x0f, 0x21, 0xea, 0x04, 0x20, 0x4b, 0xf0, 0x17, 0x0f, 0x19, 0xfe, 0x3d, 0xdf, + 0xdd, 0xd5, 0xe7, 0x14, 0x00, 0x06, 0x02, 0x11, 0x0d, 0x0e, 0x02, 0xf6, 0xe7, + 0x4a, 0xf0, 0xff, 0xff, 0xb2, 0x28, 0x22, 0x1b, 0xd0, 0x25, 0xd7, 0x03, 0xf9, + 0xfb, 0x0c, 0x05, 0xdf, 0x14, 0x1a, 0x17, 0x34, 0xef, 0x0c, 0x22, 0xf5, 0x0d, + 0xf5, 0x0e, 0x09, 0xdd, 0xfc, 0x42, 0xf7, 0x07, 0xfb, 0xdf, 0xe0, 0xd7, 0x08, + 0xcd, 0xf6, 0xcb, 0xe1, 0xdc, 0x18, 0xf0, 0xee, 0x07, 0x1d, 0x26, 0xd6, 0x10, + 0xf3, 0xf0, 0xd8, 0xf5, 0xf1, 0xc8, 0x23, 0xf4, 0xc1, 0xd4, 0xed, 0x07, 0xcf, + 0x4c, 0x1b, 0x21, 0x34, 0xf3, 0xe3, 0xf4, 0x22, 0xeb, 0xfd, 0x01, 0xcb, 0xfc, + 0xd0, 0xeb, 0x0a, 0x07, 0x20, 0x00, 0x1a, 0xcc, 0x23, 0x31, 0xfa, 0xe6, 0xc3, + 0xf0, 0x08, 0x15, 0xdf, 0xed, 0xf3, 0xf4, 0xf6, 0x17, 0xf9, 0x16, 0xd6, 0xd2, + 0x11, 0x31, 0xdb, 0xfe, 0x1d, 0x13, 0xdf, 0x09, 0x1f, 0x00, 0x7f, 0x20, 0xe1, + 0xff, 0xdd, 0xba, 0xfd, 0xe7, 0xe4, 0xf2, 0x00, 0xda, 0xdf, 0x1e, 0xbd, 0x04, + 0xd1, 0xfd, 0xd1, 0x05, 0xf0, 0xfa, 0xd3, 0xd2, 0xec, 0xcb, 0x28, 0xf4, 0xf9, + 0xf1, 0x08, 0xbb, 0xea, 0x0d, 0x0f, 0x27, 0x10, 0xce, 0x23, 0xe1, 0xec, 0x38, + 0x1a, 0x17, 0xcc, 0x12, 0x17, 0xe2, 0xf4, 0x33, 0xdf, 0xcf, 0x37, 0x1a, 0x0b, + 0xda, 0x12, 0xcb, 0xf4, 0xe4, 0x9a, 0x06, 0xf7, 0x28, 0x00, 0x0b, 0xc4, 0x12, + 0xfd, 0xe0, 0xf9, 0xdc, 0xce, 0xda, 0x12, 0x04, 0x24, 0xfb, 0x18, 0x14, 0x20, + 0xff, 0x13, 0xf2, 0x16, 0xdb, 0xfc, 0xf2, 0x02, 0x2b, 0x00, 0xe4, 0xef, 0x22, + 0xf5, 0xe7, 0x13, 0xf6, 0xe5, 0x19, 0xdf, 0x14, 0x1e, 0xd5, 0xf3, 0xf4, 0xcc, + 0xe0, 0x01, 0xf4, 0xe6, 0xeb, 0x1f, 0x06, 0xed, 0xcf, 0xcd, 0x36, 0xf1, 0x03, + 0x24, 0x0d, 0xf4, 0x2f, 0xda, 0xf5, 0xee, 0xfc, 0xe1, 0xe0, 0xff, 0xf5, 0xd7, + 0xd6, 0xdd, 0x17, 0x17, 0xde, 0xf8, 0x02, 0xce, 0x1a, 0x7f, 0x15, 0xda, 0x03, + 0xd1, 0xf4, 0xe4, 0x35, 0xf9, 0xf1, 0xf1, 0x04, 0xf3, 0xbe, 0x10, 0xf3, 0xfd, + 0x0c, 0xd5, 0xdb, 0x15, 0x0e, 0xfa, 0xd5, 0x0b, 0x13, 0xf8, 0x00, 0xef, 0xf5, + 0xfc, 0x2a, 0x05, 0xf9, 0xfe, 0xdf, 0xd9, 0x14, 0x00, 0x4b, 0x1b, 0x01, 0xd0, + 0xf0, 0xf7, 0x07, 0xfe, 0xe5, 0x04, 0x0d, 0xec, 0xf2, 0xf1, 0xd9, 0xf7, 0x02, + 0xcb, 0xf7, 0x1a, 0xe5, 0xe3, 0xdf, 0xca, 0xf2, 0xf8, 0xf6, 0xe2, 0xe4, 0x22, + 0xfd, 0xf8, 0xe5, 0xe6, 0xed, 0xfe, 0x00, 0xf0, 0xc0, 0x00, 0xc7, 0x1d, 0xe3, + 0xd6, 0xfe, 0xf1, 0xef, 0xda, 0x12, 0xf6, 0x08, 0x00, 0xf0, 0xe3, 0xdb, 0x06, + 0xf3, 0xf7, 0x14, 0x3b, 0x0c, 0xfa, 0x00, 0xff, 0xd6, 0xe8, 0x4b, 0xd7, 0xec, + 0x33, 0x04, 0x0d, 0x40, 0xe7, 0x00, 0xfb, 0x00, 0x05, 0xee, 0x1f, 0x38, 0x21, + 0xb8, 0xf3, 0x1b, 0xfa, 0x13, 0xe2, 0xd8, 0xe1, 0x0b, 0xfc, 0xe8, 0xea, 0x00, + 0xe1, 0xf7, 0x0d, 0xe0, 0x22, 0xd3, 0xee, 0xf2, 0xce, 0xee, 0x32, 0xf5, 0xfe, + 0xcd, 0x10, 0x01, 0x15, 0xea, 0x2b, 0xef, 0x1c, 0xd9, 0xfa, 0x0e, 0x22, 0x13, + 0xf1, 0xf8, 0xfb, 0xff, 0x2a, 0xfd, 0x03, 0x2e, 0x19, 0xca, 0x05, 0xfc, 0x13, + 0x1f, 0x16, 0xea, 0x0b, 0x2c, 0xfd, 0xdf, 0x11, 0xf5, 0xc7, 0x12, 0x06, 0xd3, + 0x07, 0x2b, 0x13, 0xf2, 0x05, 0xf4, 0x0a, 0x0a, 0x18, 0x03, 0xf9, 0xeb, 0xdb, + 0x0f, 0xd2, 0xff, 0xd5, 0xda, 0xf6, 0xd5, 0xda, 0xf4, 0xc7, 0xf7, 0xb9, 0xf0, + 0x10, 0xca, 0x45, 0xf1, 0xf8, 0x1e, 0xe3, 0xbd, 0xe8, 0x0f, 0x10, 0x2b, 0xd3, + 0x0a, 0x18, 0xe1, 0x25, 0xbd, 0x23, 0xd8, 0xd1, 0x11, 0x20, 0xef, 0xee, 0x0d, + 0x11, 0xdb, 0x1e, 0xfb, 0x52, 0x15, 0xdb, 0xf5, 0x10, 0xd2, 0xf2, 0x02, 0x2b, + 0xf3, 0xf2, 0x46, 0x07, 0x00, 0xbe, 0x10, 0xf2, 0xef, 0x15, 0xe8, 0x07, 0x05, + 0x25, 0x10, 0x33, 0x32, 0xd7, 0xb5, 0xe8, 0x24, 0xf5, 0xf4, 0xf1, 0xdd, 0x08, + 0xc4, 0x0b, 0xd0, 0x20, 0xdb, 0xcf, 0xf8, 0x0c, 0x30, 0x07, 0xbd, 0x06, 0x04, + 0x15, 0x1f, 0xd8, 0x2e, 0xf6, 0xb7, 0xe4, 0xec, 0xef, 0xb1, 0x0b, 0xec, 0xf5, + 0xcc, 0xf3, 0x43, 0x2c, 0x07, 0xdc, 0x42, 0x24, 0xe7, 0xff, 0xdc, 0xed, 0x12, + 0xc2, 0xb6, 0x21, 0xda, 0xf7, 0xf2, 0xe7, 0x00, 0xd9, 0xf2, 0x1b, 0x25, 0x07, + 0x2a, 0x37, 0xd4, 0xe1, 0xf1, 0xeb, 0xc4, 0x1d, 0x0e, 0xd2, 0xd3, 0xe7, 0x26, + 0x1c, 0xe9, 0x33, 0xdb, 0xa6, 0x32, 0x02, 0x07, 0xe8, 0xf9, 0xf8, 0x0f, 0xde, + 0xe0, 0x27, 0x14, 0x20, 0x10, 0xe0, 0xf3, 0xe2, 0x06, 0xcd, 0x24, 0xc0, 0xf2, + 0x10, 0x4b, 0x7f, 0xe0, 0xad, 0xef, 0x01, 0xb3, 0xc6, 0xf7, 0x17, 0xdd, 0x52, + 0xd8, 0xdb, 0x4c, 0xfc, 0x2b, 0x0d, 0xbc, 0xf9, 0xe2, 0x00, 0x18, 0xbb, 0x04, + 0x30, 0x0e, 0x1a, 0xdb, 0x17, 0xd1, 0xd8, 0x01, 0xf1, 0xf6, 0xfa, 0x23, 0x20, + 0xfe, 0xdd, 0x0d, 0xef, 0xce, 0x09, 0xdc, 0xda, 0xe4, 0x5c, 0xc6, 0x11, 0x03, + 0xdc, 0xf6, 0x2b, 0x40, 0xf3, 0x0b, 0x1d, 0x19, 0xa7, 0x05, 0xc5, 0x09, 0xc8, + 0xed, 0x28, 0x07, 0xe8, 0x0c, 0x0a, 0x24, 0x13, 0xec, 0xb4, 0x09, 0xfd, 0xec, + 0x25, 0x1a, 0xe2, 0xe1, 0xfe, 0x26, 0xa1, 0xcd, 0x15, 0xe6, 0x1d, 0xdf, 0xeb, + 0x9e, 0xe7, 0x0f, 0x05, 0x9c, 0x33, 0x36, 0xcb, 0x39, 0xd2, 0x0e, 0x4c, 0xa6, + 0xe5, 0xbd, 0xd1, 0x07, 0xc9, 0xef, 0xaa, 0xdd, 0xec, 0x02, 0x09, 0xe5, 0xed, + 0xf7, 0xd3, 0xfb, 0xd1, 0xa8, 0xb0, 0xdb, 0xf3, 0xed, 0x0a, 0x81, 0x49, 0x00, + 0xb3, 0xc6, 0xc3, 0xd5, 0xfa, 0xfc, 0xe1, 0xbd, 0x48, 0xd9, 0xfd, 0xc3, 0x09, + 0xe4, 0x24, 0x26, 0xd9, 0xd4, 0xfc, 0x03, 0x51, 0x2f, 0x07, 0xe5, 0x9d, 0x02, + 0xc5, 0xd1, 0x07, 0xf8, 0x31, 0xea, 0xf6, 0xeb, 0x05, 0x01, 0x0c, 0x21, 0xa9, + 0xea, 0xf1, 0xb1, 0xfb, 0x60, 0xf4, 0x0b, 0x40, 0xb0, 0x4f, 0x33, 0xba, 0xcf, + 0x13, 0x03, 0xea, 0xd5, 0x3d, 0xd0, 0x3d, 0x06, 0x99, 0xf2, 0x04, 0xf1, 0xe2, + 0x94, 0xee, 0xf2, 0xa5, 0xac, 0x33, 0x19, 0xcc, 0x84, 0x30, 0xd4, 0xa8, 0x34, + 0x81, 0x26, 0x0a, 0xb8, 0xde, 0xfa, 0x32, 0x02, 0xd8, 0xfb, 0x39, 0x49, 0xd7, + 0x0e, 0x24, 0xda, 0xda, 0xed, 0x3d, 0x93, 0xbe, 0x0b, 0xdb, 0x39, 0xd9, 0xfb, + 0xe3, 0x27, 0xe3, 0xba, 0xe9, 0x36, 0xf3, 0xea, 0xde, 0xb9, 0x20, 0x21, 0x84, + 0xf9, 0x2c, 0x0a, 0xff, 0xed, 0x27, 0xef, 0x1a, 0x08, 0xe1, 0xe0, 0xfb, 0xe1, + 0x0a, 0x13, 0xe2, 0x20, 0xfa, 0xae, 0xf9, 0xe1, 0xf4, 0x96, 0x30, 0x11, 0xb3, + 0xdf, 0x49, 0x42, 0xd9, 0xbc, 0xbc, 0xcf, 0xf4, 0xe3, 0xff, 0x02, 0x57, 0x17, + 0xf6, 0xc5, 0x35, 0xe4, 0xf1, 0x03, 0xc1, 0xd4, 0x26, 0xa5, 0x05, 0xcd, 0x31, + 0xab, 0xf8, 0x14, 0x18, 0xa6, 0xe4, 0x3b, 0x94, 0xf5, 0xe7, 0xc3, 0xb1, 0x0e, + 0xc6, 0xd4, 0xd2, 0x33, 0x02, 0x60, 0xf0, 0xe2, 0xc8, 0x08, 0x20, 0x93, 0xe8, + 0xc0, 0x20, 0xfd, 0x46, 0xcc, 0x3d, 0x0b, 0xf9, 0xe6, 0xae, 0xf5, 0xff, 0xff, + 0xd6, 0xdd, 0x10, 0xd0, 0xd3, 0x01, 0xe0, 0x11, 0xf9, 0x09, 0x0e, 0xc3, 0xbe, + 0x0f, 0xea, 0xde, 0xc9, 0x02, 0x02, 0x0b, 0xeb, 0xfa, 0xed, 0xf6, 0x15, 0x04, + 0x14, 0xf7, 0x11, 0x10, 0xde, 0x2b, 0x0f, 0xe0, 0xc8, 0xed, 0xec, 0x2b, 0x24, + 0x10, 0xd1, 0xf0, 0xfd, 0xeb, 0xef, 0x06, 0xcc, 0x15, 0xf5, 0xf3, 0xf0, 0x27, + 0xe4, 0xf9, 0xc0, 0x04, 0xcd, 0x01, 0xf6, 0x10, 0x20, 0xea, 0x81, 0x15, 0xdd, + 0xef, 0xd3, 0x11, 0xe5, 0xbd, 0x0e, 0xd5, 0x2d, 0x1e, 0x1d, 0x0b, 0x0d, 0x13, + 0xf1, 0xe9, 0x05, 0x00, 0x0b, 0xe7, 0x01, 0xdf, 0xfc, 0x01, 0xe6, 0xe7, 0xee, + 0x11, 0x14, 0xc4, 0xf2, 0xde, 0xfd, 0xe1, 0x12, 0x0a, 0x12, 0xf1, 0xe5, 0xe4, + 0x17, 0xee, 0x12, 0x14, 0x0c, 0x02, 0xf9, 0xf8, 0x35, 0x07, 0x0a, 0x03, 0x04, + 0x10, 0x0d, 0x07, 0xd7, 0x03, 0x0f, 0x0d, 0x2c, 0x0a, 0xdf, 0x0e, 0xd5, 0xf7, + 0xc9, 0x14, 0xd7, 0xd5, 0x14, 0xea, 0x00, 0xee, 0x12, 0xf4, 0x2e, 0x08, 0x15, + 0xf5, 0x18, 0x18, 0xdd, 0x25, 0x12, 0xea, 0xe8, 0xf2, 0xad, 0x1c, 0x12, 0xe6, + 0x01, 0xeb, 0xf0, 0xfa, 0xee, 0x1a, 0x22, 0xed, 0x22, 0x29, 0xfe, 0x0e, 0x23, + 0xd2, 0xfd, 0x15, 0x07, 0xfc, 0xf1, 0x3c, 0xde, 0xd6, 0x09, 0xbb, 0xcf, 0xef, + 0xc1, 0x1e, 0x19, 0x09, 0x1d, 0xfd, 0xf3, 0xec, 0x14, 0xf1, 0xe8, 0xf9, 0x22, + 0xf7, 0xe5, 0x0a, 0x02, 0x13, 0xee, 0x26, 0x03, 0x0f, 0xef, 0xdb, 0xe9, 0x46, + 0xed, 0x0c, 0xf0, 0xfb, 0xd4, 0xdb, 0xfd, 0xe3, 0x13, 0x14, 0xc9, 0x07, 0xea, + 0xea, 0xda, 0xcc, 0x08, 0x2e, 0xdc, 0xde, 0xe6, 0x21, 0xc5, 0xf1, 0x0c, 0x38, + 0xde, 0xf3, 0x0e, 0x01, 0xc3, 0xe9, 0xfd, 0x0b, 0xf7, 0x39, 0xe2, 0x17, 0xdf, + 0x0e, 0x1b, 0xda, 0x08, 0xeb, 0xdf, 0x0b, 0x03, 0xd0, 0x35, 0x43, 0xa9, 0x00, + 0xb6, 0xba, 0x9e, 0xa9, 0xa4, 0xe3, 0x01, 0x1a, 0xdf, 0x12, 0x10, 0xba, 0xb0, + 0xd2, 0xf7, 0x69, 0xfa, 0xfe, 0xdc, 0xb0, 0x00, 0x01, 0x05, 0xe5, 0x3d, 0xaa, + 0xe7, 0xa4, 0xf0, 0xc5, 0xeb, 0xa0, 0xc0, 0xa6, 0xc9, 0xbf, 0x17, 0x74, 0xe7, + 0x08, 0x11, 0x1c, 0x1f, 0x2b, 0xed, 0x39, 0x01, 0x00, 0x9b, 0xfb, 0xd8, 0xfa, + 0x21, 0xc9, 0x14, 0x2e, 0x0e, 0x17, 0x9a, 0x08, 0xd3, 0xfc, 0x00, 0xcf, 0xff, + 0xc5, 0xba, 0xf6, 0x1a, 0xfd, 0x2f, 0xd8, 0x36, 0x4d, 0xcd, 0xf6, 0x11, 0x06, + 0x65, 0xe2, 0x1b, 0xc3, 0x0f, 0xc7, 0xdd, 0xde, 0xd2, 0xcf, 0xeb, 0xcc, 0xfb, + 0xb7, 0x56, 0xc6, 0x12, 0xdd, 0xec, 0xdc, 0xfb, 0x04, 0x20, 0xc0, 0xcc, 0x17, + 0xd3, 0xf4, 0xe4, 0x0d, 0x21, 0xde, 0xc5, 0xb5, 0x0d, 0x3e, 0x1d, 0x06, 0xe9, + 0x23, 0xfa, 0xc0, 0xd2, 0xf2, 0x69, 0xff, 0x05, 0xda, 0x11, 0xe5, 0xb9, 0x21, + 0xd5, 0x97, 0x25, 0xe4, 0x0e, 0xfc, 0x05, 0x1c, 0xc0, 0xef, 0xed, 0xa8, 0xf9, + 0xe5, 0xed, 0x44, 0x0d, 0x26, 0xff, 0x29, 0x1c, 0x41, 0xc3, 0xd1, 0xff, 0xe3, + 0xe7, 0x9a, 0xc9, 0x34, 0x29, 0x5e, 0xbd, 0xdc, 0xc4, 0xf2, 0xe4, 0xeb, 0xf9, + 0x7f, 0x3b, 0xf1, 0x63, 0x19, 0xdd, 0xea, 0xda, 0x34, 0xe5, 0xf0, 0xf9, 0xc2, + 0x1d, 0xcc, 0x1f, 0xd8, 0xd0, 0x40, 0xfe, 0x26, 0xd2, 0xad, 0x32, 0xb3, 0xdc, + 0xa5, 0xe1, 0x14, 0x11, 0x76, 0x5f, 0xe7, 0x13, 0xde, 0xdf, 0x2e, 0x32, 0x05, + 0xe3, 0x27, 0xf5, 0xfc, 0xee, 0x1a, 0x3d, 0xb4, 0x1f, 0xd4, 0xf2, 0xd9, 0x2e, + 0xe1, 0x00, 0x1e, 0x05, 0x2c, 0xd4, 0xc4, 0x09, 0x25, 0xea, 0xa1, 0xc8, 0x29, + 0xd5, 0x1f, 0xcb, 0x0f, 0x2e, 0xf1, 0xee, 0xe5, 0x3b, 0xed, 0xd7, 0x22, 0xfe, + 0xdb, 0x32, 0xd7, 0xd6, 0xff, 0x09, 0x02, 0x18, 0xf2, 0x01, 0x05, 0x01, 0xe2, + 0xd4, 0xdb, 0xf4, 0x10, 0xaf, 0xfc, 0xe8, 0x22, 0xe0, 0x0f, 0xe0, 0xff, 0x36, + 0x04, 0xf5, 0xd2, 0xd1, 0xa9, 0x12, 0xde, 0x0e, 0x0d, 0xe2, 0xfe, 0xdf, 0xf5, + 0xf5, 0xd3, 0x1a, 0x13, 0x0a, 0x2f, 0x03, 0xeb, 0xe2, 0xdb, 0x11, 0xfd, 0xf7, + 0xd8, 0x0f, 0x02, 0xbf, 0xc8, 0x1e, 0xe2, 0x0e, 0x05, 0xd1, 0x23, 0x02, 0x22, + 0x11, 0xff, 0x92, 0x27, 0x2b, 0xd3, 0x07, 0xb1, 0xfd, 0xd1, 0xd1, 0x32, 0xeb, + 0x2c, 0xfe, 0xd2, 0xea, 0xf7, 0xe1, 0x21, 0x0e, 0xde, 0x0a, 0x02, 0xf9, 0xc4, + 0x0c, 0xfc, 0x0a, 0x20, 0x01, 0xbf, 0xc9, 0xee, 0x09, 0xd3, 0x05, 0xff, 0xcb, + 0xf4, 0x15, 0xe8, 0x1b, 0x0a, 0xd3, 0xf0, 0xef, 0xb1, 0x33, 0xba, 0x4f, 0xd8, + 0xfa, 0x06, 0xcd, 0x13, 0x00, 0xe5, 0x31, 0xd6, 0x25, 0xec, 0xfe, 0xb0, 0xd6, + 0xf5, 0x11, 0x1a, 0xd9, 0x03, 0xe6, 0x0c, 0x4c, 0xf4, 0xe9, 0xf4, 0xd6, 0xbb, + 0xfa, 0xf8, 0xde, 0x9f, 0x1a, 0xb7, 0xef, 0xe2, 0x17, 0x0d, 0x0f, 0x2c, 0xf0, + 0x07, 0xbc, 0x36, 0xf9, 0x32, 0x04, 0xfe, 0x07, 0xe3, 0xe9, 0xc0, 0xf7, 0xde, + 0x2d, 0xe0, 0xed, 0x18, 0xd6, 0x38, 0xf6, 0xe3, 0xdd, 0xe0, 0xfc, 0xc1, 0x7f, + 0x13, 0xe0, 0x25, 0x2e, 0x13, 0xed, 0xde, 0xe5, 0xe5, 0x17, 0xe3, 0xc9, 0x3c, + 0xde, 0x0c, 0xf2, 0xa5, 0xda, 0xdd, 0x3c, 0xec, 0xdb, 0x0c, 0x27, 0xed, 0xef, + 0xd2, 0x36, 0xd1, 0xf5, 0xc2, 0xab, 0x0c, 0x0a, 0xc2, 0x28, 0xdc, 0xcf, 0x10, + 0xc6, 0xd9, 0xca, 0xe6, 0xdf, 0x16, 0x10, 0xe4, 0xfe, 0x1e, 0xe5, 0x4f, 0x02, + 0x15, 0xfe, 0x00, 0xd7, 0x0e, 0x07, 0xef, 0xd4, 0xef, 0xf1, 0xf2, 0x21, 0x2f, + 0xc6, 0xfc, 0x39, 0x16, 0x32, 0x9a, 0xcd, 0x07, 0x1e, 0x04, 0x23, 0xf5, 0xfa, + 0x12, 0x34, 0x21, 0xfa, 0x05, 0x30, 0x24, 0x33, 0xf2, 0xf9, 0xfd, 0xd5, 0xff, + 0x46, 0xd2, 0x18, 0x1a, 0xc3, 0x32, 0x15, 0xdc, 0x03, 0xd7, 0x32, 0xf2, 0xe7, + 0xd7, 0x16, 0xf0, 0xf0, 0x03, 0xe9, 0xdd, 0x25, 0xf4, 0xf8, 0xfa, 0x13, 0xe3, + 0x41, 0x1b, 0xc4, 0xe1, 0x18, 0x14, 0xe9, 0xe7, 0xe2, 0xff, 0x2d, 0xf6, 0xea, + 0xd4, 0xdc, 0x23, 0xea, 0xea, 0x29, 0x14, 0x0e, 0xec, 0x0b, 0xec, 0x00, 0xf7, + 0x08, 0xdc, 0x1a, 0xef, 0xe4, 0xf2, 0x20, 0xcb, 0xc3, 0xf6, 0x3d, 0x14, 0xe2, + 0xc5, 0xf7, 0xf7, 0xd2, 0xe6, 0x0b, 0x1a, 0xf9, 0x26, 0x20, 0x1f, 0x0f, 0xd4, + 0xf3, 0x0e, 0xd6, 0x4d, 0x01, 0x07, 0x1a, 0xf1, 0xe1, 0xe0, 0x1e, 0xea, 0xea, + 0x1d, 0xfe, 0xed, 0x1e, 0xf0, 0x00, 0x00, 0xff, 0x0d, 0xb3, 0x02, 0x4b, 0x0a, + 0xf3, 0x1c, 0x38, 0xfb, 0xee, 0x5d, 0x0c, 0xe6, 0xdf, 0x02, 0xed, 0x1f, 0xfe, + 0xea, 0x7f, 0xe5, 0xf7, 0x01, 0x02, 0x22, 0x60, 0xdd, 0xee, 0xcf, 0x11, 0xfc, + 0xee, 0xf1, 0x14, 0xc7, 0xe4, 0xf8, 0x3b, 0x09, 0xe6, 0xf7, 0xdc, 0xf9, 0x27, + 0x06, 0x10, 0x25, 0xf8, 0xe6, 0x12, 0xe5, 0xe1, 0x1b, 0xd3, 0xd3, 0xea, 0x04, + 0x12, 0x02, 0xe1, 0xe4, 0xf3, 0x4a, 0x13, 0xf1, 0xb4, 0x0c, 0xf7, 0x53, 0xd0, + 0xcd, 0xe5, 0x2c, 0x09, 0x06, 0xdf, 0xf1, 0x0d, 0x1f, 0xfc, 0xdd, 0xdf, 0x07, + 0x1f, 0x41, 0x23, 0xff, 0x1f, 0x22, 0x15, 0x06, 0x0f, 0x02, 0xd7, 0x11, 0x1f, + 0xea, 0x24, 0xef, 0xe9, 0x0a, 0x0d, 0x1c, 0xd9, 0xeb, 0xe1, 0x2b, 0x00, 0x08, + 0xd9, 0xd1, 0xfa, 0xdc, 0x06, 0x14, 0x0b, 0x03, 0x40, 0x3c, 0xdc, 0xf4, 0xc3, + 0xeb, 0xfa, 0xeb, 0x07, 0xd8, 0x18, 0x09, 0xfa, 0x6d, 0xe2, 0xff, 0x06, 0xfa, + 0x16, 0xec, 0xd4, 0xf8, 0xdc, 0xd7, 0x30, 0x08, 0xe1, 0x37, 0x08, 0xca, 0xe1, + 0xc7, 0x0a, 0xd0, 0x10, 0xed, 0x10, 0x09, 0xd4, 0xed, 0x4e, 0xea, 0x1b, 0x2b, + 0xd3, 0x14, 0xe0, 0xfd, 0x0a, 0x12, 0xeb, 0xd1, 0xe8, 0x2f, 0xc6, 0xd8, 0xfe, + 0xec, 0xf6, 0xca, 0xfa, 0xc1, 0xfd, 0xc9, 0x22, 0xdb, 0xdb, 0xe4, 0x09, 0x22, + 0xfb, 0xb7, 0xb5, 0xdd, 0xf9, 0x03, 0xda, 0x1f, 0x00, 0x24, 0xf5, 0xd6, 0x05, + 0x0e, 0x07, 0x16, 0x01, 0x3e, 0xbe, 0x44, 0x18, 0x00, 0xe0, 0xdb, 0x4e, 0x0b, + 0xe6, 0xf2, 0xd9, 0xd1, 0x1e, 0x00, 0x95, 0x0e, 0xd4, 0xf3, 0xd9, 0x10, 0xf9, + 0xf8, 0x0f, 0x51, 0xa0, 0xb9, 0x4f, 0xc9, 0xd9, 0x05, 0xf5, 0xde, 0xc4, 0x27, + 0x37, 0x26, 0x06, 0xef, 0xf0, 0x13, 0xd2, 0xc9, 0x35, 0xe0, 0x19, 0x00, 0xf8, + 0x81, 0xf0, 0xf1, 0xf5, 0xd6, 0x33, 0xf4, 0x19, 0x0e, 0xf9, 0xc5, 0x25, 0xe8, + 0x0f, 0x0e, 0xee, 0xd0, 0x92, 0xe2, 0xf5, 0x01, 0xf0, 0x01, 0x10, 0x0c, 0x0a, + 0xeb, 0xd1, 0xc0, 0x04, 0x25, 0x22, 0xc9, 0xbd, 0xf8, 0xff, 0x17, 0xe9, 0x2d, + 0x1c, 0xcd, 0xd5, 0x2d, 0xae, 0x0d, 0x05, 0xf6, 0x1b, 0x0f, 0xf7, 0xeb, 0xf9, + 0xe6, 0xe2, 0x1d, 0x0c, 0xc3, 0x0f, 0x1f, 0xb7, 0xf7, 0xcb, 0x22, 0x26, 0xfe, + 0x16, 0x30, 0xbe, 0x18, 0xbd, 0x24, 0x2c, 0xe0, 0x00, 0xdf, 0xa5, 0xe1, 0x28, + 0x1a, 0x09, 0xf0, 0xef, 0xc9, 0x13, 0x3c, 0x06, 0xd6, 0x4c, 0xe1, 0x04, 0xfc, + 0x12, 0xf0, 0xda, 0xcd, 0x15, 0x0a, 0x67, 0xf1, 0x1e, 0xe9, 0xf7, 0x0c, 0x20, + 0xf4, 0x3f, 0x11, 0xfd, 0x38, 0x07, 0x0b, 0xf0, 0xde, 0xff, 0x21, 0x15, 0x14, + 0x02, 0x15, 0xcd, 0x70, 0xba, 0x08, 0xdd, 0xf5, 0xe5, 0xd9, 0xe7, 0x4b, 0x61, + 0x0e, 0x15, 0x0a, 0xe7, 0x34, 0xe6, 0xd0, 0xc0, 0xf4, 0x28, 0x2e, 0x22, 0xfd, + 0x07, 0xf8, 0xfe, 0xed, 0x24, 0x33, 0x03, 0x05, 0xd3, 0xd8, 0xd7, 0xd8, 0x3a, + 0x1e, 0xfd, 0x58, 0x16, 0x9e, 0xc8, 0x1f, 0xb8, 0xc0, 0xfa, 0x1f, 0x33, 0x0c, + 0xf5, 0xb7, 0x17, 0x25, 0x30, 0x21, 0xb6, 0xdd, 0x0f, 0x42, 0x0f, 0xdb, 0x22, + 0xc1, 0x91, 0xd3, 0x5c, 0x16, 0xc6, 0xdf, 0x01, 0x15, 0x0e, 0x42, 0xed, 0x1c, + 0x01, 0x7a, 0xbe, 0x28, 0x32, 0x1a, 0x04, 0xda, 0xff, 0xc1, 0x1e, 0xc2, 0x0c, + 0x3a, 0xdd, 0xe7, 0x38, 0xc3, 0x9a, 0x0a, 0x02, 0xf0, 0xfd, 0xf9, 0xce, 0xbb, + 0x8e, 0x27, 0xdf, 0x23, 0x38, 0x1e, 0xf5, 0x06, 0xfc, 0xdb, 0x43, 0xfe, 0xdf, + 0x35, 0x03, 0xf4, 0x14, 0x1c, 0xc8, 0xe1, 0xf0, 0xf1, 0xe0, 0xc3, 0xdd, 0xba, + 0xc9, 0xf3, 0x0e, 0xda, 0x07, 0xfc, 0x2c, 0xf7, 0x2c, 0x1c, 0xeb, 0x4e, 0xfd, + 0xef, 0xb4, 0x0a, 0xd2, 0x07, 0xb7, 0xe3, 0xcf, 0x0a, 0x07, 0xf9, 0x18, 0xa4, + 0xeb, 0x30, 0xaf, 0xf0, 0x0b, 0xfc, 0x3e, 0xf2, 0x24, 0x0b, 0xac, 0xb8, 0xfe, + 0xdc, 0xd9, 0x05, 0xd5, 0x16, 0x33, 0xe2, 0xf3, 0x15, 0xca, 0xd5, 0xc7, 0x10, + 0x0d, 0xd4, 0x16, 0x19, 0xab, 0x3e, 0xc0, 0xa5, 0xd3, 0xac, 0xed, 0x20, 0xf1, + 0xbf, 0x05, 0xf3, 0xc7, 0x44, 0x38, 0x33, 0x4f, 0xdd, 0xd4, 0x61, 0xff, 0x39, + 0xdd, 0x0d, 0x15, 0xfc, 0x58, 0x13, 0xe7, 0xc9, 0xfb, 0x1c, 0x0a, 0xcc, 0x74, + 0x99, 0xec, 0x00, 0xec, 0x01, 0xe0, 0xfb, 0xfb, 0xe5, 0xce, 0x24, 0xb5, 0x42, + 0x46, 0x02, 0xe5, 0xf9, 0x13, 0x1b, 0xd3, 0x00, 0x0a, 0xe9, 0xbd, 0xfe, 0x00, + 0x32, 0x1c, 0xc1, 0x2a, 0x0d, 0x0c, 0x07, 0xbb, 0xe1, 0xdd, 0x17, 0xd3, 0x06, + 0x02, 0x24, 0xc8, 0xbc, 0xd5, 0x45, 0xbe, 0x81, 0x53, 0xdf, 0x13, 0x11, 0x43, + 0x01, 0x00, 0xc8, 0xcb, 0xb1, 0xea, 0x1b, 0xcd, 0x24, 0x1b, 0xd9, 0xd0, 0x25, + 0xfe, 0xeb, 0xc7, 0x07, 0xe3, 0xf9, 0x9e, 0xda, 0x26, 0x04, 0xca, 0x05, 0xfc, + 0x12, 0x10, 0xdd, 0x1d, 0x26, 0xe1, 0xd8, 0x74, 0xe5, 0x92, 0x7f, 0x06, 0x08, + 0x0c, 0xc5, 0xfd, 0xee, 0xfc, 0xe1, 0xf7, 0xba, 0x2f, 0x25, 0xf7, 0xe6, 0xd9, + 0xe9, 0xee, 0x00, 0x58, 0xea, 0x2a, 0xec, 0xab, 0xdc, 0xb5, 0x29, 0x25, 0xfa, + 0xe5, 0x06, 0x25, 0xff, 0x24, 0x0e, 0x06, 0xf8, 0x16, 0x77, 0xbb, 0xf5, 0xe6, + 0xcb, 0xf0, 0xdf, 0x07, 0xea, 0x07, 0xd1, 0x2e, 0x15, 0xdf, 0xfd, 0x16, 0xed, + 0x33, 0x14, 0xfe, 0xe4, 0xc2, 0xe4, 0x10, 0x07, 0x24, 0xd8, 0xe7, 0x2d, 0x09, + 0x1e, 0xdc, 0xf8, 0xc0, 0x42, 0x17, 0x0e, 0x3a, 0x09, 0xde, 0xc9, 0xf0, 0xf0, + 0xd3, 0x00, 0x1e, 0xb5, 0xb6, 0xdb, 0x3d, 0x06, 0x0c, 0xe7, 0x43, 0x23, 0x06, + 0x19, 0xe4, 0x0c, 0xf8, 0x2a, 0xd2, 0x28, 0xe6, 0xf1, 0x31, 0xff, 0x16, 0xf9, + 0xb1, 0x20, 0x4e, 0xe1, 0x17, 0xfc, 0xe8, 0x2b, 0xfd, 0xeb, 0xf3, 0xf1, 0xea, + 0xd2, 0x16, 0x1d, 0x0b, 0x6c, 0x1a, 0xed, 0x03, 0x23, 0x11, 0xe8, 0xe8, 0x15, + 0x09, 0x25, 0xd3, 0x0e, 0xfa, 0xe1, 0xfa, 0xf3, 0x12, 0x04, 0x10, 0xca, 0x07, + 0x03, 0xce, 0xfb, 0xd5, 0x16, 0x06, 0x08, 0xd2, 0xea, 0xc3, 0xf8, 0x0d, 0xf7, + 0xea, 0xe6, 0x04, 0xc5, 0x09, 0xd8, 0x1c, 0xbb, 0x1c, 0x0f, 0x14, 0xc9, 0xf0, + 0xef, 0xd2, 0x1b, 0x07, 0x17, 0x31, 0x56, 0xee, 0x38, 0xf6, 0x10, 0xfb, 0x9f, + 0x11, 0xec, 0xf5, 0x1b, 0xf7, 0x27, 0x0e, 0x09, 0x32, 0xf7, 0xc1, 0xf8, 0x07, + 0xf7, 0xf3, 0xa3, 0xec, 0xc5, 0x71, 0xe1, 0x04, 0xeb, 0x3e, 0xf5, 0x03, 0x1a, + 0xe1, 0xec, 0x1a, 0xb9, 0xf6, 0x24, 0x21, 0xd6, 0xd7, 0x47, 0xb9, 0xe1, 0xef, + 0xed, 0x15, 0x10, 0xe0, 0xf0, 0xb4, 0x06, 0x36, 0x8f, 0xed, 0x16, 0xc6, 0x14, + 0xc2, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x15, + 0x1a, 0x00, 0x00, 0xf7, 0xf1, 0xff, 0xff, 0xaa, 0x0e, 0x00, 0x00, 0xcc, 0x66, + 0x00, 0x00, 0x67, 0xed, 0xff, 0xff, 0x7e, 0x1d, 0x00, 0x00, 0x14, 0x05, 0x00, + 0x00, 0xd9, 0xd3, 0xff, 0xff, 0xe0, 0x30, 0x00, 0x00, 0x3b, 0x29, 0x00, 0x00, + 0x40, 0x3e, 0x00, 0x00, 0x99, 0xfa, 0xff, 0xff, 0x83, 0x1b, 0x00, 0x00, 0x78, + 0xe4, 0xff, 0xff, 0xf8, 0x23, 0x00, 0x00, 0x0e, 0x25, 0x00, 0x00, 0x33, 0x06, + 0x00, 0x00, 0xfe, 0x32, 0x00, 0x00, 0x27, 0xe5, 0xff, 0xff, 0xba, 0x0d, 0x00, + 0x00, 0xc4, 0x51, 0x00, 0x00, 0x07, 0xf0, 0xff, 0xff, 0x40, 0xf2, 0xff, 0xff, + 0x2a, 0x57, 0x00, 0x00, 0xd1, 0x01, 0x00, 0x00, 0x11, 0x0e, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x51, 0x29, 0x00, 0x00, 0x53, 0x29, 0x00, 0x00, 0xcf, 0x38, + 0x00, 0x00, 0x78, 0x5f, 0x00, 0x00, 0x90, 0x13, 0x00, 0x00, 0xee, 0x08, 0x00, + 0x00, 0xec, 0xec, 0xff, 0xff, 0x2c, 0x3d, 0x00, 0x00, 0x53, 0x34, 0x00, 0x00, + 0xd2, 0x08, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0xa9, 0xe5, 0xff, 0xff, 0x91, + 0x0c, 0x00, 0x00, 0xc7, 0x02, 0x00, 0x00, 0xdc, 0x12, 0x00, 0x00, 0x67, 0xd1, + 0xff, 0xff, 0x8b, 0xfc, 0xff, 0xff, 0x6e, 0x13, 0x00, 0x00, 0x3e, 0xe7, 0xff, + 0xff, 0x34, 0x53, 0x00, 0x00, 0x05, 0x3a, 0x00, 0x00, 0x5c, 0x1a, 0x00, 0x00, + 0xdd, 0x16, 0x00, 0x00, 0x31, 0x52, 0x00, 0x00, 0xa0, 0x0a, 0x00, 0x00, 0x4a, + 0x15, 0x00, 0x00, 0x26, 0x2f, 0x00, 0x00, 0xcb, 0x12, 0x00, 0x00, 0xd0, 0x1a, + 0x00, 0x00, 0xda, 0x19, 0x00, 0x00, 0x2e, 0x57, 0x00, 0x00, 0x3d, 0x04, 0x00, + 0x00, 0x9d, 0x28, 0x00, 0x00, 0x94, 0x09, 0x00, 0x00, 0x7f, 0xfa, 0xff, 0xff, + 0x11, 0x22, 0x00, 0x00, 0x06, 0x0a, 0x00, 0x00, 0xce, 0x4b, 0x00, 0x00, 0xff, + 0x16, 0x00, 0x00, 0xf2, 0x41, 0x00, 0x00, 0xca, 0x1c, 0x00, 0x00, 0x57, 0x28, + 0x00, 0x00, 0x6d, 0x27, 0x00, 0x00, 0x4a, 0x0a, 0x00, 0x00, 0xbf, 0x50, 0x00, + 0x00, 0x55, 0x3d, 0x00, 0x00, 0x59, 0x57, 0x00, 0x00, 0x44, 0x4c, 0x00, 0x00, + 0x32, 0x22, 0x00, 0x00, 0x88, 0x02, 0x00, 0x00, 0x73, 0xde, 0xff, 0xff, 0xbe, + 0x37, 0x00, 0x00, 0xca, 0x18, 0x00, 0x00, 0x3c, 0xfb, 0xff, 0xff, 0x0b, 0x42, + 0x00, 0x00, 0x68, 0x72, 0x00, 0x00, 0xff, 0xe9, 0xff, 0xff, 0x03, 0x0d, 0x00, + 0x00, 0x40, 0x22, 0x00, 0x00, 0x79, 0x2e, 0x00, 0x00, 0x3f, 0xe5, 0xff, 0xff, + 0x63, 0x33, 0x00, 0x00, 0x2c, 0x5f, 0x00, 0x00, 0x94, 0x2e, 0x00, 0x00, 0x71, + 0x01, 0x00, 0x00, 0x4e, 0x38, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x9e, 0x2e, + 0x00, 0x00, 0xc4, 0xdd, 0xff, 0xff, 0x1b, 0x0c, 0x00, 0x00, 0x23, 0x28, 0x00, + 0x00, 0xee, 0x1c, 0x00, 0x00, 0x8b, 0x2e, 0x00, 0x00, 0xff, 0xf7, 0xff, 0xff, + 0xab, 0x0b, 0x00, 0x00, 0x96, 0x3a, 0x00, 0x00, 0xdf, 0x2b, 0x00, 0x00, 0xc2, + 0x4e, 0x00, 0x00, 0x6f, 0x09, 0x00, 0x00, 0xc3, 0x6a, 0x00, 0x00, 0x61, 0x19, + 0x00, 0x00, 0x2c, 0xdc, 0xff, 0xff, 0xfb, 0x25, 0x00, 0x00, 0x67, 0x66, 0x00, + 0x00, 0x65, 0xf6, 0xff, 0xff, 0xf5, 0x6e, 0x00, 0x00, 0xb6, 0x17, 0x00, 0x00, + 0xc3, 0x08, 0x00, 0x00, 0x81, 0xf3, 0xff, 0xff, 0x6b, 0xe9, 0xff, 0xff, 0x36, + 0x38, 0x00, 0x00, 0xbb, 0x0e, 0x00, 0x00, 0x35, 0xcf, 0xff, 0xff, 0xdb, 0xd7, + 0xff, 0xff, 0xcd, 0xfb, 0xff, 0xff, 0x2f, 0x11, 0x00, 0x00, 0xfd, 0xfe, 0xff, + 0xff, 0x5d, 0x13, 0x00, 0x00, 0x45, 0x1c, 0x00, 0x00, 0xd6, 0x22, 0x00, 0x00, + 0xb2, 0x0a, 0x00, 0x00, 0x82, 0x17, 0x00, 0x00, 0x9a, 0x52, 0x00, 0x00, 0xe0, + 0xe2, 0xff, 0xff, 0x20, 0x02, 0x00, 0x00, 0x25, 0xfd, 0xff, 0xff, 0xb1, 0x2f, + 0x00, 0x00, 0xa0, 0x3b, 0x00, 0x00, 0xae, 0x26, 0x00, 0x00, 0xb5, 0x3e, 0x00, + 0x00, 0xb9, 0xfb, 0xff, 0xff, 0x2c, 0x40, 0x00, 0x00, 0x64, 0x39, 0x00, 0x00, + 0xeb, 0x46, 0x00, 0x00, 0x2a, 0x1c, 0x00, 0x00, 0xd9, 0x0a, 0x00, 0x00, 0xf0, + 0x40, 0x00, 0x00, 0x55, 0xda, 0xff, 0xff, 0xa7, 0x1e, 0x00, 0x00, 0xa3, 0xf6, + 0xff, 0xff, 0x68, 0x31, 0x00, 0x00, 0x23, 0x29, 0x00, 0x00, 0x0f, 0x25, 0x00, + 0x00, 0x55, 0xfd, 0xff, 0xff, 0x83, 0x1c, 0x00, 0x00, 0xc6, 0x87, 0x00, 0x00, + 0x65, 0xf8, 0xff, 0xff, 0x13, 0xfe, 0xff, 0xff, 0x56, 0x13, 0x00, 0x00, 0xfc, + 0x17, 0x00, 0x00, 0x4e, 0x10, 0x00, 0x00, 0xfd, 0x15, 0x00, 0x00, 0x93, 0xd1, + 0xff, 0xff, 0x13, 0x12, 0x00, 0x00, 0x9d, 0x14, 0x00, 0x00, 0xf3, 0xde, 0xff, + 0xff, 0x83, 0x37, 0x00, 0x00, 0x9f, 0xf9, 0xff, 0xff, 0xbb, 0xed, 0xff, 0xff, + 0x05, 0x2e, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x23, 0x5c, 0x00, 0x00, 0xb8, + 0xf8, 0xff, 0xff, 0xd8, 0x08, 0x00, 0x00, 0x05, 0x44, 0x00, 0x00, 0xc2, 0x5b, + 0x00, 0x00, 0xe8, 0x0a, 0x00, 0x00, 0xe8, 0x47, 0x00, 0x00, 0x1e, 0x1b, 0x00, + 0x00, 0xcd, 0xff, 0xff, 0xff, 0x0e, 0x1c, 0x00, 0x00, 0x4c, 0x40, 0x00, 0x00, + 0x5b, 0x28, 0x00, 0x00, 0x17, 0x3a, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x53, + 0x77, 0x00, 0x00, 0xf4, 0x42, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x5e, 0xed, + 0xff, 0xff, 0x78, 0x17, 0x00, 0x00, 0x32, 0x26, 0x00, 0x00, 0x50, 0x1a, 0x00, + 0x00, 0x91, 0xfb, 0xff, 0xff, 0xb9, 0x4f, 0x00, 0x00, 0xd8, 0x05, 0x00, 0x00, + 0x64, 0x38, 0x00, 0x00, 0x17, 0x2f, 0x00, 0x00, 0x81, 0x1e, 0x00, 0x00, 0xf4, + 0x17, 0x00, 0x00, 0x27, 0x26, 0x00, 0x00, 0xea, 0xed, 0xff, 0xff, 0x1a, 0x3b, + 0x00, 0x00, 0x87, 0x7b, 0x00, 0x00, 0xcd, 0x22, 0x00, 0x00, 0xb0, 0x53, 0x00, + 0x00, 0x7a, 0xda, 0xff, 0xff, 0x7f, 0x0c, 0x00, 0x00, 0x01, 0x43, 0x00, 0x00, + 0x2e, 0x07, 0x00, 0x00, 0x89, 0xf3, 0xff, 0xff, 0xdf, 0x2b, 0x00, 0x00, 0xb1, + 0x61, 0x00, 0x00, 0xe0, 0x1c, 0x00, 0x00, 0x95, 0x4d, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x00, 0x9e, 0x40, 0x00, 0x00, 0x44, 0x4a, 0x00, 0x00, 0xa2, 0xcb, 0xff, + 0xff, 0x9d, 0x16, 0x00, 0x00, 0xca, 0x47, 0x00, 0x00, 0x33, 0x0e, 0x00, 0x00, + 0x2e, 0x50, 0x00, 0x00, 0xf9, 0x28, 0x00, 0x00, 0x40, 0x17, 0x00, 0x00, 0x03, + 0x57, 0x00, 0x00, 0xfe, 0xe3, 0xff, 0xff, 0xa8, 0x2f, 0x00, 0x00, 0xe9, 0x00, + 0x00, 0x00, 0xa6, 0x07, 0x00, 0x00, 0x78, 0x10, 0x00, 0x00, 0xd3, 0x45, 0x00, + 0x00, 0xd3, 0xce, 0xff, 0xff, 0x0f, 0x2d, 0x00, 0x00, 0x83, 0xf4, 0xff, 0xff, + 0xba, 0x2a, 0x00, 0x00, 0xec, 0x15, 0x00, 0x00, 0x94, 0x5d, 0x00, 0x00, 0x83, + 0x0e, 0x00, 0x00, 0xe6, 0x1c, 0x00, 0x00, 0x98, 0x39, 0x00, 0x00, 0x9c, 0x3a, + 0x00, 0x00, 0x7e, 0x05, 0x00, 0x00, 0x17, 0x46, 0x00, 0x00, 0xa8, 0xf9, 0xff, + 0xff, 0x40, 0x0d, 0x00, 0x00, 0x40, 0x12, 0x00, 0x00, 0x1a, 0x07, 0x00, 0x00, + 0x32, 0x23, 0x00, 0x00, 0x3f, 0x0c, 0x00, 0x00, 0xd5, 0x08, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0xe3, 0x75, 0x00, 0x00, 0xa3, 0x1f, 0x00, 0x00, 0xa1, 0x27, + 0x00, 0x00, 0xd0, 0x23, 0x00, 0x00, 0xeb, 0xdc, 0xff, 0xff, 0x99, 0x05, 0x00, + 0x00, 0x27, 0x0e, 0x00, 0x00, 0xd7, 0xf2, 0xff, 0xff, 0xce, 0xfc, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xf1, 0x25, 0xba, 0xa3, 0xe0, + 0xeb, 0xbd, 0x28, 0xce, 0x20, 0xc9, 0xfb, 0x37, 0x28, 0x43, 0xea, 0x70, 0xa9, + 0xe0, 0x2c, 0xe1, 0x9e, 0x5f, 0xc9, 0x52, 0xd2, 0x28, 0x21, 0xcb, 0xef, 0xc2, + 0x08, 0x13, 0xc5, 0x29, 0xfa, 0x40, 0xfa, 0x0d, 0xfd, 0xdb, 0x16, 0x50, 0x43, + 0xb5, 0xf1, 0x5d, 0xdc, 0x2d, 0x42, 0x0d, 0xd9, 0x94, 0x22, 0xae, 0x1f, 0x31, + 0x13, 0xcc, 0xcf, 0xc2, 0xa6, 0x81, 0xc5, 0xaa, 0x17, 0xaf, 0xef, 0xd4, 0x0c, + 0xab, 0xb2, 0xa8, 0x12, 0x36, 0xa5, 0x3c, 0xd4, 0xbf, 0xbb, 0xca, 0x0f, 0xaf, + 0x14, 0xb6, 0xdb, 0xb0, 0xcb, 0xb1, 0x8b, 0x31, 0xd0, 0x19, 0xcd, 0xab, 0x47, + 0x16, 0xb8, 0x29, 0xa8, 0xfa, 0x82, 0x59, 0xa5, 0xad, 0xb2, 0xa6, 0xde, 0xbf, + 0xbd, 0x17, 0xcf, 0xb9, 0x1a, 0xcd, 0x17, 0xc4, 0xe2, 0xd0, 0xe2, 0x2f, 0xc8, + 0xbf, 0x3e, 0xd4, 0xbe, 0xae, 0xe6, 0x03, 0x1b, 0x2e, 0x47, 0xa0, 0xe2, 0xb4, + 0xc4, 0x28, 0xb1, 0xb7, 0xe4, 0x18, 0x00, 0xcb, 0x18, 0x3a, 0xea, 0x01, 0x22, + 0xe1, 0xb8, 0xd9, 0xfd, 0xbb, 0xd3, 0xd5, 0xc7, 0xde, 0xc1, 0xf8, 0xab, 0xab, + 0x44, 0xb7, 0x08, 0xd9, 0xd2, 0xc9, 0xfe, 0xa4, 0x1a, 0xd8, 0xc5, 0x22, 0x9a, + 0x48, 0xd6, 0x30, 0x38, 0x1e, 0x38, 0xb8, 0xeb, 0x1f, 0x10, 0xd8, 0xbe, 0x15, + 0xde, 0x24, 0x0d, 0x14, 0xa7, 0x97, 0xab, 0x26, 0xeb, 0xe7, 0x9b, 0xd4, 0xb2, + 0xf3, 0xc8, 0x5d, 0x33, 0x0f, 0xce, 0xc5, 0xce, 0xaa, 0x50, 0xbc, 0x1e, 0x11, + 0xbe, 0xde, 0xe2, 0xc6, 0xee, 0xba, 0xf4, 0xe9, 0x0e, 0x97, 0x30, 0x3f, 0x01, + 0xd8, 0x5c, 0x0f, 0xec, 0x22, 0xe0, 0x3e, 0xbb, 0xd8, 0x39, 0xc1, 0xb3, 0x02, + 0x15, 0xd0, 0x17, 0xf9, 0x32, 0xc6, 0xcf, 0xb2, 0xbc, 0x20, 0xbb, 0xd3, 0xc7, + 0x2c, 0xb9, 0xd7, 0x2f, 0x1c, 0xe4, 0x4d, 0x65, 0x2e, 0x08, 0x32, 0xd8, 0x38, + 0xe1, 0x52, 0x19, 0xc4, 0xf2, 0xb8, 0x16, 0x91, 0x5a, 0x27, 0xca, 0x20, 0x74, + 0xa5, 0x22, 0xb3, 0x2e, 0xdd, 0xe5, 0x2c, 0x14, 0x42, 0xf7, 0xe5, 0x40, 0xc0, + 0xf9, 0xb8, 0x07, 0xee, 0x0f, 0x1e, 0xed, 0xa3, 0xc8, 0x3b, 0x0d, 0xa4, 0x0f, + 0xe8, 0xb8, 0xfd, 0x16, 0x64, 0xd9, 0x46, 0xe3, 0xce, 0xe9, 0x2d, 0x48, 0x34, + 0x4f, 0x78, 0x3a, 0x56, 0xe2, 0x55, 0x0d, 0x40, 0xf9, 0x4e, 0x5f, 0x68, 0xea, + 0xb9, 0x63, 0xc9, 0x30, 0x50, 0x57, 0x30, 0xfb, 0x4d, 0xf6, 0x55, 0x2c, 0x56, + 0x35, 0x5e, 0x78, 0xd3, 0x37, 0xe9, 0x3f, 0x64, 0xb0, 0xe5, 0x49, 0xdb, 0x55, + 0x10, 0x7f, 0x9a, 0x61, 0x47, 0x4e, 0x52, 0x27, 0x44, 0x45, 0xdf, 0x2e, 0x46, + 0xe4, 0x53, 0xe4, 0x2c, 0x28, 0x2f, 0x2b, 0xd6, 0x3e, 0x37, 0xbb, 0x28, 0x43, + 0x59, 0x18, 0xe8, 0xd4, 0xe8, 0xd0, 0x5f, 0x0a, 0x47, 0x43, 0xe5, 0x4f, 0x62, + 0x22, 0xf4, 0x00, 0x32, 0xee, 0xb8, 0x27, 0xfd, 0xde, 0x3f, 0x3b, 0x43, 0x05, + 0x4b, 0x38, 0x3c, 0x31, 0x29, 0x40, 0x10, 0x3c, 0x65, 0x9d, 0x38, 0xe0, 0x23, + 0x1e, 0x38, 0xfe, 0x52, 0xed, 0x31, 0x44, 0xd8, 0x6c, 0xb0, 0x33, 0xd4, 0xd4, + 0xf7, 0xca, 0x4f, 0x10, 0xd6, 0xf2, 0x2c, 0x3d, 0xee, 0x1f, 0xe7, 0x00, 0xf0, + 0x58, 0x6d, 0x5d, 0xc1, 0x1b, 0x0d, 0x6a, 0x27, 0x55, 0x05, 0x43, 0xa8, 0xdd, + 0xe8, 0x2a, 0x46, 0x44, 0x53, 0xb4, 0x29, 0xcc, 0xdb, 0x46, 0x26, 0x27, 0x52, + 0x0e, 0x45, 0xfd, 0x17, 0xe1, 0x6b, 0xe1, 0xb5, 0x01, 0x2b, 0x99, 0xf9, 0x23, + 0xe7, 0x34, 0xcb, 0x39, 0x2d, 0xc2, 0x43, 0x5a, 0x0e, 0xeb, 0x3b, 0xe4, 0x19, + 0xd4, 0x4c, 0x30, 0x6b, 0x3e, 0xdc, 0x46, 0x39, 0x38, 0xce, 0x47, 0x2c, 0xc6, + 0xda, 0xfe, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8b, + 0x3f, 0x00, 0x00, 0x49, 0xbd, 0xff, 0xff, 0xee, 0xfe, 0xff, 0xff, 0x04, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0xd8, 0x56, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x54, 0x4f, 0x43, 0x4f, + 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x78, 0x54, 0xff, 0xff, 0xf0, 0x08, + 0x00, 0x00, 0xe4, 0x08, 0x00, 0x00, 0xd8, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x1f, 0x00, 0x00, 0x00, 0x78, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, + 0xc0, 0x07, 0x00, 0x00, 0x78, 0x07, 0x00, 0x00, 0x34, 0x07, 0x00, 0x00, 0xec, + 0x06, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x1c, 0x06, + 0x00, 0x00, 0xd4, 0x05, 0x00, 0x00, 0x90, 0x05, 0x00, 0x00, 0x48, 0x05, 0x00, + 0x00, 0x04, 0x05, 0x00, 0x00, 0xbc, 0x04, 0x00, 0x00, 0x78, 0x04, 0x00, 0x00, + 0x30, 0x04, 0x00, 0x00, 0xec, 0x03, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x60, + 0x03, 0x00, 0x00, 0x18, 0x03, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x8c, 0x02, + 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xbc, 0x01, 0x00, + 0x00, 0x74, 0x01, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x66, + 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xce, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x42, 0xf8, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x8a, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x10, 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x3c, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x07, + 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x82, 0xf9, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd0, 0xf9, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xc2, 0xf9, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5e, 0xf9, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, + 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x54, 0xfa, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x46, 0xfa, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe2, 0xf9, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x8a, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd8, + 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x27, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0xca, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x66, 0xfa, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x0e, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x5c, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0x00, 0x4e, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xea, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x92, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0xe0, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x55, 0x00, 0x00, 0x00, 0xd2, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x6e, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x16, 0xfc, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x52, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x56, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xf2, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x9a, 0xfc, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe8, 0xfc, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x4e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0xda, 0xfc, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x76, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0xfd, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6c, 0xfd, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x5e, 0xfd, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfa, 0xfc, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x46, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0xa2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf0, 0xfd, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xe2, + 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7e, 0xfd, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x00, 0x26, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x74, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, + 0x00, 0x66, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, + 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xaa, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0xf8, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x00, 0x00, 0xea, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x86, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x2e, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x7c, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x39, 0x00, 0x00, 0x00, 0x6e, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, + 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x0a, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x37, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xb2, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x0c, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x08, + 0x00, 0x0c, 0x00, 0x10, 0x00, 0x07, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x07, 0x00, + 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, + 0x00, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x57, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, + 0x00, 0x00, 0xb4, 0x2f, 0x01, 0x00, 0x1c, 0x29, 0x01, 0x00, 0x88, 0x22, 0x01, + 0x00, 0x04, 0x1c, 0x01, 0x00, 0x8c, 0x15, 0x01, 0x00, 0x04, 0x0f, 0x01, 0x00, + 0x8c, 0x02, 0x01, 0x00, 0x04, 0xf6, 0x00, 0x00, 0x8c, 0xe9, 0x00, 0x00, 0xa4, + 0xe8, 0x00, 0x00, 0x6c, 0xe7, 0x00, 0x00, 0x24, 0xe6, 0x00, 0x00, 0x2c, 0xe4, + 0x00, 0x00, 0x24, 0xe2, 0x00, 0x00, 0x2c, 0xe0, 0x00, 0x00, 0x24, 0xde, 0x00, + 0x00, 0xac, 0xda, 0x00, 0x00, 0x24, 0xd7, 0x00, 0x00, 0xac, 0xd3, 0x00, 0x00, + 0x24, 0xd0, 0x00, 0x00, 0xac, 0xc9, 0x00, 0x00, 0x24, 0xc3, 0x00, 0x00, 0xac, + 0xbc, 0x00, 0x00, 0x24, 0xb6, 0x00, 0x00, 0xac, 0xaf, 0x00, 0x00, 0x24, 0xa9, + 0x00, 0x00, 0xac, 0xa2, 0x00, 0x00, 0x0c, 0xa2, 0x00, 0x00, 0x74, 0xa1, 0x00, + 0x00, 0xf0, 0xa0, 0x00, 0x00, 0x5c, 0xa0, 0x00, 0x00, 0xd0, 0x9f, 0x00, 0x00, + 0x78, 0x9f, 0x00, 0x00, 0xa4, 0x9e, 0x00, 0x00, 0x0c, 0x9e, 0x00, 0x00, 0x68, + 0x9d, 0x00, 0x00, 0xe8, 0x96, 0x00, 0x00, 0x70, 0x90, 0x00, 0x00, 0xcc, 0x8f, + 0x00, 0x00, 0x28, 0x8f, 0x00, 0x00, 0xa8, 0x88, 0x00, 0x00, 0x30, 0x82, 0x00, + 0x00, 0x8c, 0x81, 0x00, 0x00, 0xe8, 0x80, 0x00, 0x00, 0x68, 0x7a, 0x00, 0x00, + 0xf0, 0x6d, 0x00, 0x00, 0x4c, 0x6d, 0x00, 0x00, 0xa8, 0x6c, 0x00, 0x00, 0x28, + 0x60, 0x00, 0x00, 0xb0, 0x53, 0x00, 0x00, 0x0c, 0x53, 0x00, 0x00, 0x68, 0x52, + 0x00, 0x00, 0x88, 0x51, 0x00, 0x00, 0x50, 0x50, 0x00, 0x00, 0xac, 0x4f, 0x00, + 0x00, 0x08, 0x4f, 0x00, 0x00, 0xc8, 0x4d, 0x00, 0x00, 0xd0, 0x4b, 0x00, 0x00, + 0x2c, 0x4b, 0x00, 0x00, 0x88, 0x4a, 0x00, 0x00, 0x88, 0x48, 0x00, 0x00, 0x90, + 0x46, 0x00, 0x00, 0xec, 0x45, 0x00, 0x00, 0x48, 0x45, 0x00, 0x00, 0x48, 0x43, + 0x00, 0x00, 0xd0, 0x3f, 0x00, 0x00, 0x2c, 0x3f, 0x00, 0x00, 0x88, 0x3e, 0x00, + 0x00, 0x08, 0x3b, 0x00, 0x00, 0x90, 0x37, 0x00, 0x00, 0xec, 0x36, 0x00, 0x00, + 0x48, 0x36, 0x00, 0x00, 0xc8, 0x32, 0x00, 0x00, 0x50, 0x2c, 0x00, 0x00, 0xac, + 0x2b, 0x00, 0x00, 0x08, 0x2b, 0x00, 0x00, 0x88, 0x24, 0x00, 0x00, 0x10, 0x1e, + 0x00, 0x00, 0x6c, 0x1d, 0x00, 0x00, 0xc8, 0x1c, 0x00, 0x00, 0x48, 0x16, 0x00, + 0x00, 0xd0, 0x0f, 0x00, 0x00, 0x2c, 0x0f, 0x00, 0x00, 0x88, 0x0e, 0x00, 0x00, + 0x08, 0x08, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xd8, 0xfe, 0xff, 0x00, 0x00, + 0x00, 0x09, 0x54, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xec, 0x5e, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x81, 0x80, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, 0x05, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xc2, 0xd8, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x09, 0x5c, 0x00, 0x00, + 0x00, 0x55, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x44, 0xdf, 0xfe, 0xff, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3b, 0x21, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x50, 0x72, 0x65, 0x64, 0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x52, + 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x32, 0xd9, 0xfe, + 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xcc, 0x5f, 0xff, 0xff, 0x30, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, + 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x39, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, + 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xd2, 0xd9, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x06, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x54, + 0xe0, 0xfe, 0xff, 0x10, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x09, 0xc1, 0x56, 0x38, 0x70, 0xbe, + 0x8a, 0x38, 0xc6, 0x5e, 0x5c, 0x38, 0x6b, 0x13, 0x7e, 0x38, 0x35, 0xee, 0x4e, + 0x38, 0x92, 0x3c, 0xb2, 0x38, 0x73, 0x8f, 0x83, 0x38, 0x0e, 0x10, 0x96, 0x38, + 0x30, 0xad, 0x59, 0x38, 0x3a, 0xfb, 0x97, 0x38, 0x7d, 0xae, 0x8d, 0x38, 0x37, + 0x9b, 0x8a, 0x38, 0x06, 0xbc, 0x4d, 0x38, 0x17, 0x10, 0x7e, 0x38, 0x6a, 0xf4, + 0x80, 0x38, 0x76, 0x67, 0x2f, 0x38, 0xcc, 0x91, 0x68, 0x38, 0x9a, 0x18, 0x55, + 0x38, 0x1b, 0x65, 0x30, 0x38, 0x52, 0xad, 0x97, 0x38, 0x99, 0x46, 0x80, 0x38, + 0x7e, 0x0e, 0x81, 0x38, 0x50, 0xe4, 0x69, 0x38, 0xc7, 0x6b, 0x51, 0x38, 0x9b, + 0x88, 0x39, 0x38, 0xf3, 0xa1, 0xc5, 0x38, 0x62, 0xe9, 0x42, 0x38, 0x89, 0xe8, + 0xad, 0x38, 0x8e, 0xc1, 0xc0, 0x38, 0x2c, 0xf5, 0x85, 0x38, 0x94, 0xee, 0x7c, + 0x38, 0x4c, 0xde, 0x9f, 0x38, 0xea, 0xa8, 0x98, 0x38, 0xe4, 0x06, 0x5e, 0x38, + 0x83, 0x3e, 0x92, 0x38, 0x1b, 0x6c, 0x4d, 0x38, 0x38, 0xee, 0x8d, 0x38, 0xe2, + 0xb2, 0x82, 0x38, 0x8e, 0xc1, 0x55, 0x38, 0xc9, 0x3b, 0x9d, 0x38, 0xf6, 0x00, + 0x9a, 0x38, 0x65, 0x1f, 0x9f, 0x38, 0x38, 0xc2, 0x5a, 0x38, 0x8c, 0x70, 0x7b, + 0x38, 0xa7, 0x22, 0x53, 0x38, 0xe2, 0xe7, 0x55, 0x38, 0xfc, 0xcf, 0x8c, 0x38, + 0xed, 0x8b, 0x7a, 0x38, 0x13, 0xa5, 0x86, 0x38, 0x7f, 0xf3, 0x87, 0x38, 0x76, + 0x25, 0x69, 0x38, 0x2e, 0x32, 0x80, 0x38, 0x72, 0x5e, 0x95, 0x38, 0x7a, 0x2c, + 0x85, 0x38, 0xc3, 0x7d, 0x94, 0x38, 0x50, 0x99, 0x97, 0x38, 0x0a, 0x98, 0x80, + 0x38, 0x47, 0xa5, 0x4c, 0x38, 0x61, 0x07, 0x7c, 0x38, 0x4b, 0x39, 0x82, 0x38, + 0xc3, 0x09, 0x6f, 0x38, 0x41, 0xb8, 0x78, 0x38, 0x5f, 0x0e, 0x51, 0x38, 0x23, + 0xc2, 0x86, 0x38, 0x30, 0xc3, 0x98, 0x38, 0xa8, 0x15, 0x80, 0x38, 0xea, 0xe4, + 0x8b, 0x38, 0x8b, 0x83, 0x86, 0x38, 0x03, 0xff, 0x52, 0x38, 0x19, 0xcf, 0x84, + 0x38, 0x30, 0xfe, 0xad, 0x38, 0xd5, 0x13, 0x56, 0x38, 0x41, 0x60, 0x7f, 0x38, + 0x73, 0xa4, 0x81, 0x38, 0xd9, 0x0d, 0xbc, 0x38, 0xf5, 0xae, 0xa6, 0x38, 0x59, + 0xa6, 0x7f, 0x38, 0x04, 0xb7, 0x91, 0x38, 0xb0, 0x51, 0x88, 0x38, 0xdf, 0x68, + 0x85, 0x38, 0x73, 0xfc, 0x88, 0x38, 0x3e, 0xf8, 0x79, 0x38, 0xf6, 0x38, 0x97, + 0x38, 0x69, 0x3e, 0x97, 0x38, 0x50, 0xf3, 0x7a, 0x38, 0x91, 0x57, 0x5d, 0x38, + 0x06, 0x22, 0x63, 0x38, 0xaf, 0x51, 0x7c, 0x38, 0x6e, 0x68, 0xa1, 0x38, 0x08, + 0x2a, 0xa3, 0x38, 0x5b, 0x07, 0xb2, 0x38, 0x36, 0x72, 0x95, 0x38, 0x02, 0xcf, + 0x6e, 0x38, 0x17, 0x6b, 0x84, 0x38, 0x7f, 0x72, 0x78, 0x38, 0xc7, 0x37, 0x78, + 0x38, 0xb3, 0xd1, 0x61, 0x38, 0x69, 0xc3, 0x96, 0x38, 0x8e, 0x04, 0x50, 0x38, + 0x4b, 0x1c, 0x89, 0x38, 0x7d, 0x9d, 0x7f, 0x38, 0xb0, 0x7d, 0x5f, 0x38, 0xe8, + 0x6b, 0x70, 0x38, 0xd3, 0x12, 0x65, 0x38, 0x5b, 0x57, 0x91, 0x38, 0x35, 0x42, + 0x6d, 0x38, 0x3d, 0xa2, 0x89, 0x38, 0xa9, 0xdb, 0x56, 0x38, 0x8e, 0x11, 0x5f, + 0x38, 0x0b, 0x42, 0x4b, 0x38, 0xe7, 0x81, 0xc2, 0x38, 0x9e, 0xfc, 0x61, 0x38, + 0x95, 0xd3, 0xb9, 0x38, 0x15, 0x9f, 0x93, 0x38, 0x07, 0x4e, 0x39, 0x38, 0x9e, + 0xa7, 0x70, 0x38, 0x4d, 0xd4, 0x61, 0x38, 0xc6, 0x72, 0x70, 0x38, 0x04, 0xf0, + 0xa8, 0x38, 0x59, 0x15, 0xd0, 0x38, 0x9c, 0x9a, 0xbf, 0x38, 0x39, 0x42, 0x84, + 0x38, 0xfa, 0x8a, 0x8d, 0x38, 0x36, 0x1c, 0x3a, 0x38, 0xfc, 0x64, 0x61, 0x38, + 0x61, 0xb6, 0x73, 0x38, 0x3d, 0x27, 0x75, 0x38, 0xd9, 0xc4, 0x97, 0x38, 0x36, + 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x39, 0x5f, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, + 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x46, 0xe0, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x06, 0x00, + 0x00, 0x11, 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xa2, 0xd9, 0xfe, 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x8f, + 0xcb, 0x23, 0x39, 0x92, 0x83, 0xcf, 0x38, 0x7c, 0x0d, 0xdd, 0x38, 0xbc, 0x8b, + 0x0a, 0x39, 0x18, 0x12, 0x7a, 0x39, 0x9b, 0x70, 0x06, 0x39, 0x6a, 0xc6, 0xff, + 0x38, 0x8b, 0x50, 0x1d, 0x39, 0x18, 0xe3, 0xe4, 0x38, 0xf7, 0x10, 0xdb, 0x38, + 0x6c, 0xc8, 0x1a, 0x39, 0x79, 0x8f, 0x3f, 0x39, 0xb3, 0x01, 0xe1, 0x38, 0xde, + 0x9f, 0xd4, 0x38, 0xdb, 0x07, 0x55, 0x39, 0xea, 0x41, 0x30, 0x39, 0xf5, 0xa0, + 0x3a, 0x39, 0x4b, 0x1f, 0x00, 0x39, 0x59, 0xf8, 0xe1, 0x38, 0xea, 0x98, 0xae, + 0x38, 0x56, 0x25, 0x36, 0x39, 0x43, 0x8e, 0xda, 0x38, 0xa3, 0x92, 0x53, 0x39, + 0xd0, 0x31, 0x66, 0x39, 0x14, 0x14, 0x51, 0x39, 0xa9, 0xf9, 0x2a, 0x39, 0x56, + 0x7e, 0xd5, 0x38, 0x7a, 0x79, 0x55, 0x39, 0xfc, 0xb2, 0x3a, 0x39, 0x8e, 0x31, + 0x95, 0x39, 0x4d, 0x04, 0x49, 0x39, 0x61, 0xaf, 0x20, 0x39, 0xa4, 0xb7, 0x04, + 0x39, 0x80, 0x50, 0x2a, 0x39, 0xff, 0xd1, 0x1a, 0x39, 0x4b, 0xe2, 0x3b, 0x39, + 0x02, 0xbb, 0x21, 0x39, 0x92, 0x95, 0x02, 0x39, 0xba, 0x20, 0x04, 0x39, 0x61, + 0x09, 0x6b, 0x39, 0x8b, 0x71, 0xca, 0x38, 0x98, 0x2e, 0x08, 0x39, 0xf6, 0xa6, + 0xe1, 0x38, 0x29, 0x2a, 0x43, 0x39, 0x0f, 0x60, 0x36, 0x39, 0xe2, 0x80, 0x08, + 0x39, 0xa7, 0x75, 0xf3, 0x38, 0xd4, 0x07, 0x09, 0x39, 0x68, 0x6f, 0x6c, 0x39, + 0xe4, 0x93, 0x7f, 0x39, 0xa9, 0x4c, 0x04, 0x39, 0x53, 0x42, 0x4a, 0x39, 0xe4, + 0x10, 0x1f, 0x39, 0x80, 0x86, 0xe8, 0x38, 0x73, 0xef, 0x04, 0x39, 0xf8, 0xa4, + 0x05, 0x39, 0x28, 0x51, 0x15, 0x39, 0x1e, 0x0c, 0x23, 0x39, 0x8c, 0x98, 0xa8, + 0x39, 0x05, 0x83, 0x7a, 0x39, 0xd1, 0x6b, 0x1a, 0x39, 0x17, 0x32, 0x8c, 0x39, + 0xb9, 0xa8, 0x18, 0x39, 0x00, 0x47, 0x03, 0x39, 0x0b, 0x94, 0x23, 0x39, 0xb5, + 0xd3, 0x5c, 0x39, 0x92, 0xba, 0xd8, 0x38, 0x4b, 0x61, 0x18, 0x39, 0x41, 0x3f, + 0x6f, 0x39, 0x84, 0x04, 0xac, 0x38, 0x30, 0x2b, 0x48, 0x39, 0xa4, 0x34, 0x23, + 0x39, 0x8b, 0x5e, 0xe8, 0x38, 0x2a, 0x30, 0xe6, 0x38, 0xf0, 0x4c, 0x09, 0x39, + 0x29, 0xe9, 0xac, 0x39, 0x2a, 0xdf, 0x08, 0x39, 0xed, 0x3c, 0x30, 0x39, 0x8f, + 0x37, 0xf1, 0x38, 0x94, 0xf6, 0xd6, 0x38, 0x8e, 0x51, 0xee, 0x38, 0x39, 0x4a, + 0x0f, 0x39, 0x83, 0xca, 0x44, 0x39, 0x70, 0x12, 0xf0, 0x38, 0x93, 0x9a, 0x34, + 0x39, 0x77, 0xfc, 0xdc, 0x38, 0x3b, 0xaa, 0xf1, 0x38, 0x86, 0x48, 0x16, 0x39, + 0x52, 0xb3, 0x3c, 0x39, 0xd2, 0x02, 0x37, 0x39, 0xba, 0x0a, 0xe7, 0x38, 0xe5, + 0x71, 0xfc, 0x38, 0x2d, 0x79, 0x05, 0x39, 0xb7, 0x1e, 0xb7, 0x38, 0x7f, 0x1e, + 0x97, 0x39, 0x91, 0xcc, 0xd1, 0x38, 0x2b, 0x81, 0x36, 0x39, 0xb6, 0x3f, 0x4a, + 0x39, 0x2f, 0x77, 0xe9, 0x38, 0xfc, 0x08, 0xe2, 0x38, 0xdb, 0xac, 0x41, 0x39, + 0x6e, 0x60, 0xe8, 0x38, 0x32, 0x5a, 0x0a, 0x39, 0x8c, 0x3a, 0xd8, 0x38, 0x97, + 0x15, 0xd5, 0x38, 0x4d, 0x54, 0xf7, 0x38, 0xc6, 0x45, 0x3a, 0x39, 0xcf, 0x4c, + 0x24, 0x39, 0xf7, 0x4e, 0x00, 0x39, 0x9b, 0xa0, 0x3f, 0x39, 0x7c, 0x4c, 0xeb, + 0x38, 0x34, 0x60, 0x40, 0x39, 0xd8, 0xdc, 0xe2, 0x38, 0x21, 0x86, 0xce, 0x38, + 0x5f, 0x05, 0x0d, 0x39, 0x79, 0x9f, 0x01, 0x39, 0x15, 0xa6, 0x19, 0x39, 0x70, + 0x6d, 0x1a, 0x39, 0x0e, 0xe6, 0x4b, 0x39, 0x22, 0x44, 0x35, 0x39, 0x7a, 0x72, + 0x45, 0x39, 0x75, 0x03, 0xb3, 0x38, 0xdf, 0x93, 0xe4, 0x38, 0xcf, 0x69, 0xd4, + 0x38, 0x56, 0xa3, 0x02, 0x39, 0x29, 0x15, 0xd1, 0x38, 0xf9, 0x55, 0xf6, 0x38, + 0xea, 0x4f, 0x0f, 0x39, 0x39, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x39, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc2, 0xe6, + 0xfe, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5c, 0x6d, 0xff, 0xff, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, + 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x39, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, + 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x62, 0xe7, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xfc, 0x6d, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x38, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x02, 0xe8, 0xfe, 0xff, 0x00, 0x00, 0x00, + 0x02, 0x64, 0x06, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x84, 0xee, 0xfe, 0xff, 0x10, 0x04, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, + 0x87, 0x53, 0x38, 0x9e, 0xa2, 0x7d, 0x38, 0x7f, 0xbe, 0x75, 0x38, 0xa1, 0x24, + 0x71, 0x38, 0x94, 0x4d, 0xb1, 0x38, 0x29, 0xe9, 0xae, 0x38, 0x71, 0x40, 0x73, + 0x38, 0x2d, 0x97, 0x66, 0x38, 0x02, 0xf5, 0x6a, 0x38, 0xdf, 0xd8, 0x99, 0x38, + 0x88, 0x06, 0x87, 0x38, 0xd1, 0xe2, 0x82, 0x38, 0x30, 0xc7, 0x82, 0x38, 0x47, + 0x1e, 0x87, 0x38, 0xc7, 0x7d, 0x50, 0x38, 0xac, 0x3f, 0x59, 0x38, 0xf9, 0xac, + 0x8c, 0x38, 0x30, 0xa1, 0x91, 0x38, 0x5b, 0x15, 0x7f, 0x38, 0xff, 0xfa, 0x54, + 0x38, 0x85, 0x90, 0x8c, 0x38, 0x37, 0x35, 0x7e, 0x38, 0xfa, 0xe0, 0x88, 0x38, + 0x18, 0x32, 0x87, 0x38, 0x52, 0x6e, 0x92, 0x38, 0xf0, 0xb0, 0x7e, 0x38, 0x18, + 0xd4, 0x73, 0x38, 0x67, 0x2d, 0x95, 0x38, 0x44, 0x40, 0x83, 0x38, 0x8c, 0xae, + 0x83, 0x38, 0x22, 0xa0, 0x86, 0x38, 0x1a, 0xad, 0x94, 0x38, 0xed, 0xfd, 0x8f, + 0x38, 0xa1, 0x1d, 0x65, 0x38, 0xff, 0x45, 0x67, 0x38, 0x24, 0x9b, 0x85, 0x38, + 0xfb, 0x5f, 0xb1, 0x38, 0xee, 0xe4, 0x8e, 0x38, 0x3f, 0xd4, 0x83, 0x38, 0x67, + 0x1c, 0x70, 0x38, 0xab, 0xef, 0x8a, 0x38, 0x9e, 0x4b, 0x83, 0x38, 0x4d, 0x92, + 0x5c, 0x38, 0xd9, 0x84, 0x7a, 0x38, 0x41, 0xde, 0x51, 0x38, 0x2d, 0x3c, 0x75, + 0x38, 0x6d, 0x6f, 0x96, 0x38, 0xb5, 0x6d, 0x95, 0x38, 0xdc, 0xf4, 0x31, 0x38, + 0x74, 0x9c, 0x2c, 0x38, 0xb6, 0x91, 0x8b, 0x38, 0xa3, 0xac, 0x32, 0x38, 0x8e, + 0xf8, 0x80, 0x38, 0x33, 0x35, 0x66, 0x38, 0x91, 0x5c, 0x41, 0x38, 0x70, 0x7b, + 0x88, 0x38, 0xa8, 0x31, 0x85, 0x38, 0x4a, 0xf1, 0x50, 0x38, 0x20, 0x68, 0x86, + 0x38, 0x2f, 0x82, 0x80, 0x38, 0x08, 0x63, 0x43, 0x38, 0x62, 0x65, 0x70, 0x38, + 0x5b, 0x58, 0x84, 0x38, 0x3c, 0x49, 0x97, 0x38, 0x98, 0x68, 0x60, 0x38, 0xd0, + 0xe8, 0x83, 0x38, 0x62, 0xca, 0x4b, 0x38, 0xc5, 0xaf, 0x81, 0x38, 0x0f, 0x62, + 0x73, 0x38, 0xff, 0xbd, 0x7f, 0x38, 0xc6, 0x43, 0x9f, 0x38, 0x96, 0x2d, 0x93, + 0x38, 0x40, 0x9d, 0x8f, 0x38, 0x54, 0xaa, 0xac, 0x38, 0x20, 0x51, 0xb0, 0x38, + 0x8e, 0xa3, 0x84, 0x38, 0xaa, 0x0f, 0xb8, 0x38, 0xad, 0x3d, 0x5f, 0x38, 0x45, + 0x6d, 0x83, 0x38, 0x4d, 0x6c, 0x6a, 0x38, 0xea, 0xc4, 0x87, 0x38, 0xa7, 0x52, + 0xac, 0x38, 0x12, 0xef, 0x95, 0x38, 0xeb, 0x1b, 0x8b, 0x38, 0xf0, 0xe9, 0xaf, + 0x38, 0xb3, 0xf3, 0x81, 0x38, 0xe4, 0xa8, 0x3e, 0x38, 0xde, 0x8f, 0x5d, 0x38, + 0xaa, 0xd3, 0x44, 0x38, 0x61, 0x96, 0x87, 0x38, 0x40, 0x35, 0x7a, 0x38, 0xf3, + 0x84, 0x90, 0x38, 0x05, 0x94, 0x79, 0x38, 0x90, 0x70, 0x93, 0x38, 0xa9, 0x54, + 0x6c, 0x38, 0x5d, 0x5e, 0x81, 0x38, 0xd6, 0x95, 0xa7, 0x38, 0xc0, 0xd9, 0x8d, + 0x38, 0xb8, 0xd5, 0x62, 0x38, 0x94, 0x3e, 0x6c, 0x38, 0x0c, 0xf8, 0xa4, 0x38, + 0xd5, 0x76, 0x54, 0x38, 0xe6, 0xe2, 0x93, 0x38, 0x74, 0x27, 0x3d, 0x38, 0x9e, + 0xcb, 0x93, 0x38, 0xeb, 0x8c, 0x5d, 0x38, 0x6f, 0x7d, 0x94, 0x38, 0x2e, 0x42, + 0xb9, 0x38, 0x94, 0x65, 0x55, 0x38, 0x1a, 0xe5, 0x66, 0x38, 0x17, 0x0f, 0x55, + 0x38, 0xbe, 0x91, 0x84, 0x38, 0x1b, 0xc5, 0x89, 0x38, 0x72, 0x38, 0x85, 0x38, + 0x87, 0xcc, 0x8f, 0x38, 0x96, 0x71, 0x83, 0x38, 0xbd, 0x04, 0x6f, 0x38, 0x33, + 0x99, 0x3c, 0x38, 0x73, 0x9d, 0x7d, 0x38, 0x8f, 0x0d, 0x4b, 0x38, 0xa4, 0x6f, + 0x73, 0x38, 0xca, 0xbf, 0x69, 0x38, 0x64, 0x33, 0x7e, 0x38, 0x55, 0x02, 0x81, + 0x38, 0xe5, 0xd2, 0x96, 0x38, 0x27, 0x00, 0x5d, 0x38, 0xd2, 0x15, 0x7b, 0x38, + 0xbf, 0xea, 0x81, 0x38, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x38, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x76, 0xee, 0xfe, 0xff, 0x00, 0x00, + 0x00, 0x02, 0x6c, 0x06, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xd2, 0xe7, 0xfe, 0xff, 0x14, 0x04, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x6c, 0xe2, 0x0b, 0x39, 0xc3, 0x54, 0x4b, 0x39, 0x78, + 0x29, 0x00, 0x39, 0x17, 0x23, 0xcd, 0x38, 0xa2, 0x60, 0x0c, 0x39, 0xf0, 0xcc, + 0x5e, 0x39, 0x9b, 0x41, 0x5d, 0x39, 0x8d, 0xb7, 0x25, 0x39, 0x5c, 0xc1, 0xdf, + 0x38, 0x54, 0x8d, 0x01, 0x39, 0x37, 0x5d, 0xf5, 0x38, 0xa0, 0xf1, 0x70, 0x39, + 0x3e, 0xb2, 0xfd, 0x38, 0x98, 0x3f, 0xe4, 0x38, 0x65, 0x48, 0xd0, 0x38, 0x3e, + 0x60, 0xdd, 0x38, 0xcd, 0x65, 0x7b, 0x39, 0xed, 0xa9, 0x21, 0x39, 0x7c, 0x44, + 0x8c, 0x39, 0x68, 0xf2, 0xf6, 0x38, 0xa0, 0x2a, 0x85, 0x39, 0xd6, 0x79, 0xf1, + 0x38, 0xc9, 0x1a, 0x1f, 0x39, 0x70, 0xb3, 0x08, 0x39, 0xa4, 0x37, 0xdd, 0x38, + 0x6e, 0xfb, 0x15, 0x39, 0x6c, 0xa5, 0x39, 0x39, 0x82, 0xd6, 0x00, 0x39, 0xd5, + 0x9a, 0x0b, 0x39, 0xef, 0xa1, 0x14, 0x39, 0x02, 0xd1, 0x81, 0x39, 0x00, 0x71, + 0x57, 0x39, 0x77, 0xd6, 0x30, 0x39, 0xb3, 0xe9, 0x1e, 0x39, 0x08, 0x37, 0xbf, + 0x38, 0x7f, 0x9e, 0x1a, 0x39, 0x5c, 0xb7, 0xf5, 0x38, 0x1d, 0xb5, 0x22, 0x39, + 0x92, 0x15, 0xf4, 0x38, 0xaa, 0x0e, 0x04, 0x39, 0xa1, 0x4e, 0x02, 0x39, 0x83, + 0xd2, 0x54, 0x39, 0xad, 0x3c, 0x25, 0x39, 0x70, 0x88, 0x09, 0x39, 0x65, 0x13, + 0xc3, 0x38, 0x18, 0x02, 0xf0, 0x38, 0xc2, 0xa6, 0x36, 0x39, 0xeb, 0x6f, 0x6a, + 0x39, 0xfa, 0x9a, 0xe6, 0x38, 0x03, 0xd5, 0x20, 0x39, 0xef, 0x8b, 0x13, 0x39, + 0x3e, 0xdb, 0xfb, 0x38, 0xca, 0xc2, 0x1b, 0x39, 0x9a, 0x7a, 0xe7, 0x38, 0x9b, + 0x14, 0x00, 0x39, 0x5f, 0x15, 0x27, 0x39, 0x39, 0xd9, 0x30, 0x39, 0x4c, 0xbf, + 0x86, 0x39, 0xe9, 0x2f, 0x29, 0x39, 0xcc, 0xda, 0xda, 0x38, 0xf4, 0x7f, 0x7a, + 0x39, 0x3a, 0x7d, 0x1a, 0x39, 0xe4, 0xb2, 0xf3, 0x38, 0xb8, 0x92, 0x3a, 0x39, + 0x03, 0x6d, 0x1a, 0x39, 0x35, 0x9d, 0x4e, 0x39, 0xb0, 0xf5, 0xef, 0x38, 0x15, + 0xc7, 0xce, 0x38, 0x91, 0x19, 0x50, 0x39, 0xbc, 0x6d, 0x0a, 0x39, 0x06, 0xfe, + 0x22, 0x39, 0x61, 0xea, 0x30, 0x39, 0xe8, 0x52, 0x26, 0x39, 0xfd, 0xea, 0xd6, + 0x38, 0x17, 0xba, 0x33, 0x39, 0xd8, 0x54, 0x12, 0x39, 0x0f, 0x2a, 0x18, 0x39, + 0x14, 0x44, 0x04, 0x39, 0xf2, 0x1f, 0x2a, 0x39, 0x3f, 0x04, 0x99, 0x39, 0xc7, + 0xa3, 0x09, 0x39, 0x83, 0x12, 0xe8, 0x38, 0x05, 0x9a, 0x6f, 0x39, 0x21, 0xbe, + 0x02, 0x39, 0x81, 0xf9, 0x26, 0x39, 0xf0, 0x4d, 0xec, 0x38, 0x17, 0x0e, 0x21, + 0x39, 0xc4, 0x6f, 0x63, 0x39, 0x3e, 0xa9, 0x36, 0x39, 0x3b, 0x91, 0x35, 0x39, + 0xe8, 0x6e, 0x95, 0x39, 0xe8, 0xd4, 0xfd, 0x38, 0xbf, 0xfb, 0x43, 0x39, 0xfd, + 0xd8, 0xce, 0x38, 0x0f, 0x5e, 0xea, 0x38, 0x8c, 0x83, 0xdf, 0x38, 0xc4, 0x46, + 0x5a, 0x39, 0x57, 0x2e, 0x27, 0x39, 0xad, 0x75, 0x20, 0x39, 0xdd, 0xcf, 0x24, + 0x39, 0x79, 0xcb, 0xd9, 0x38, 0x8c, 0xf2, 0xf7, 0x38, 0x00, 0xbe, 0xeb, 0x38, + 0xe8, 0x7c, 0x32, 0x39, 0xbd, 0xe0, 0xd3, 0x38, 0x73, 0xd3, 0xf3, 0x38, 0xb9, + 0x02, 0x2a, 0x39, 0x3b, 0xd8, 0x30, 0x39, 0x18, 0xb2, 0x09, 0x39, 0xc7, 0x6b, + 0x62, 0x39, 0xbf, 0x36, 0x06, 0x39, 0xe1, 0x87, 0x3c, 0x39, 0xde, 0xa6, 0x27, + 0x39, 0x44, 0x9f, 0x63, 0x39, 0xa9, 0x3e, 0x2c, 0x39, 0x1b, 0xd6, 0xfb, 0x38, + 0xd8, 0x3c, 0xdb, 0x38, 0xcd, 0xf0, 0xed, 0x38, 0xa1, 0xb9, 0x82, 0x39, 0xd9, + 0x5d, 0xd8, 0x38, 0xf4, 0x20, 0xef, 0x38, 0x68, 0x24, 0x71, 0x39, 0x7a, 0x10, + 0xe4, 0x38, 0x0b, 0x9c, 0x88, 0x39, 0x8f, 0xcb, 0x35, 0x39, 0x82, 0xaa, 0xfb, + 0x38, 0xce, 0x66, 0x02, 0x39, 0xde, 0x38, 0x17, 0x39, 0x39, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x38, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, + 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, + 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0xf2, 0xf4, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, + 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x8c, 0x7b, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x38, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, + 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x92, 0xf5, 0xfe, 0xff, 0x00, 0x00, + 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x2c, 0x7c, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x37, 0x5f, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x32, 0xf6, + 0xfe, 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x06, 0x00, 0x00, 0x53, 0x00, 0x00, + 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb4, 0xfc, 0xfe, 0xff, + 0x10, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xaa, 0x0c, 0x61, 0x38, 0xf0, 0x53, 0xb3, 0x38, 0x35, + 0xea, 0x8d, 0x38, 0xa4, 0xc2, 0x86, 0x38, 0xe8, 0x92, 0x60, 0x38, 0xc0, 0x2c, + 0x5c, 0x38, 0x67, 0xa0, 0x62, 0x38, 0xa1, 0xb3, 0xb4, 0x38, 0x5c, 0x07, 0x60, + 0x38, 0x30, 0xdc, 0x5f, 0x38, 0x2a, 0xa0, 0xd1, 0x38, 0xc9, 0x14, 0x9e, 0x38, + 0x9d, 0xac, 0x58, 0x38, 0xf3, 0x95, 0x8a, 0x38, 0x83, 0x03, 0x8d, 0x38, 0x78, + 0x46, 0x86, 0x38, 0x80, 0xea, 0x5d, 0x38, 0xe1, 0x99, 0x9a, 0x38, 0x4b, 0xe2, + 0x96, 0x38, 0xa9, 0xeb, 0x83, 0x38, 0x6b, 0x80, 0x8f, 0x38, 0x18, 0xf4, 0x80, + 0x38, 0x65, 0xfb, 0x67, 0x38, 0x1b, 0xd7, 0x8e, 0x38, 0xc4, 0x6c, 0x96, 0x38, + 0x92, 0x70, 0x98, 0x38, 0x9e, 0x46, 0x47, 0x38, 0xaa, 0xde, 0x7c, 0x38, 0x5f, + 0xc7, 0x4b, 0x38, 0xff, 0xa2, 0x83, 0x38, 0x4b, 0xa4, 0x82, 0x38, 0x61, 0xee, + 0x9b, 0x38, 0x47, 0xdb, 0x66, 0x38, 0xb4, 0x48, 0x85, 0x38, 0xe1, 0x54, 0x6e, + 0x38, 0x47, 0xba, 0xb8, 0x38, 0x65, 0x8b, 0x85, 0x38, 0xaa, 0x65, 0x41, 0x38, + 0x33, 0x6d, 0x88, 0x38, 0xfc, 0xe2, 0x72, 0x38, 0x92, 0x90, 0xae, 0x38, 0x60, + 0x60, 0x9e, 0x38, 0x9a, 0xa0, 0x77, 0x38, 0x67, 0x07, 0x78, 0x38, 0x6a, 0x34, + 0x83, 0x38, 0xba, 0xe1, 0x6b, 0x38, 0x1d, 0x9b, 0x78, 0x38, 0xd7, 0x8f, 0x8b, + 0x38, 0x0f, 0xc0, 0x8a, 0x38, 0xbb, 0xcc, 0x85, 0x38, 0x85, 0xf7, 0x50, 0x38, + 0x48, 0xc2, 0x8c, 0x38, 0x4a, 0x58, 0x56, 0x38, 0x73, 0x66, 0x5a, 0x38, 0x6d, + 0x58, 0x63, 0x38, 0x49, 0x9b, 0x6a, 0x38, 0xd9, 0x6a, 0x5b, 0x38, 0x61, 0xbc, + 0x58, 0x38, 0xe4, 0x43, 0x55, 0x38, 0x4c, 0x13, 0x9a, 0x38, 0xe5, 0xe5, 0x94, + 0x38, 0x92, 0xf8, 0x3a, 0x38, 0xa9, 0x4e, 0x66, 0x38, 0x46, 0xdf, 0x69, 0x38, + 0xc3, 0xbc, 0x92, 0x38, 0xee, 0xc7, 0x84, 0x38, 0x63, 0x4c, 0x9c, 0x38, 0xfc, + 0x62, 0x60, 0x38, 0xfb, 0x60, 0x85, 0x38, 0xeb, 0x7f, 0x7b, 0x38, 0xb0, 0xbc, + 0xa1, 0x38, 0x0d, 0x46, 0x8c, 0x38, 0xc8, 0xf9, 0x88, 0x38, 0x81, 0x37, 0x81, + 0x38, 0xf2, 0x93, 0x95, 0x38, 0x38, 0xc8, 0x98, 0x38, 0x1f, 0x9a, 0x9b, 0x38, + 0xfb, 0x1e, 0x80, 0x38, 0xce, 0x84, 0x81, 0x38, 0x1d, 0x96, 0x7d, 0x38, 0xbb, + 0x15, 0xb2, 0x38, 0x39, 0x9f, 0x84, 0x38, 0xeb, 0xbe, 0x7a, 0x38, 0xc4, 0x6f, + 0x87, 0x38, 0x37, 0x62, 0x93, 0x38, 0xc1, 0x53, 0x99, 0x38, 0xa2, 0xe3, 0x3f, + 0x38, 0x67, 0xdf, 0x43, 0x38, 0x7f, 0xd2, 0x64, 0x38, 0x7c, 0x06, 0x7f, 0x38, + 0x0c, 0xe0, 0x6c, 0x38, 0x30, 0x77, 0x90, 0x38, 0x49, 0xd7, 0x57, 0x38, 0x65, + 0x1d, 0x7a, 0x38, 0x36, 0x38, 0xb0, 0x38, 0xb9, 0x08, 0x86, 0x38, 0x9d, 0x25, + 0x47, 0x38, 0xd6, 0x87, 0x69, 0x38, 0x73, 0x64, 0xce, 0x38, 0x14, 0xae, 0x5b, + 0x38, 0x65, 0xe5, 0x99, 0x38, 0xb0, 0xec, 0x5e, 0x38, 0xf2, 0x88, 0x9f, 0x38, + 0x3c, 0x3b, 0x8a, 0x38, 0xd1, 0xf0, 0x82, 0x38, 0x3e, 0xe0, 0x7b, 0x38, 0xc9, + 0xd2, 0x6f, 0x38, 0xa4, 0x9f, 0x95, 0x38, 0x0e, 0x3b, 0x5b, 0x38, 0x15, 0x3c, + 0x6d, 0x38, 0xd3, 0xed, 0x5a, 0x38, 0xa0, 0x9e, 0x96, 0x38, 0x49, 0x50, 0xcc, + 0x38, 0x1e, 0xe4, 0x48, 0x38, 0xda, 0x56, 0x3a, 0x38, 0x41, 0x0d, 0x57, 0x38, + 0xc9, 0x68, 0xc0, 0x38, 0x86, 0x69, 0x4a, 0x38, 0x97, 0x84, 0x6f, 0x38, 0xb3, + 0x7c, 0x9d, 0x38, 0x24, 0x1c, 0x6f, 0x38, 0x62, 0xb0, 0x8e, 0x38, 0x61, 0xaf, + 0x72, 0x38, 0x03, 0x03, 0x83, 0x38, 0xf3, 0x9f, 0x5b, 0x38, 0x6f, 0xbe, 0x89, + 0x38, 0x82, 0x3b, 0x9c, 0x38, 0x9f, 0x52, 0x8a, 0x38, 0x36, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x37, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, + 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, + 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xa6, + 0xfc, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x06, 0x00, 0x00, 0x4e, 0x00, + 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0xf6, 0xfe, + 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xa1, 0x0c, 0xe5, 0x38, + 0xb5, 0x80, 0x28, 0x39, 0x9e, 0xce, 0x25, 0x39, 0xeb, 0xb3, 0x62, 0x39, 0x74, + 0x53, 0x38, 0x39, 0x9f, 0x2b, 0xb8, 0x38, 0xb9, 0x9e, 0x07, 0x39, 0xdb, 0x1c, + 0x63, 0x39, 0x9e, 0x9d, 0x0f, 0x39, 0xbd, 0x02, 0x0c, 0x39, 0xc0, 0xda, 0x50, + 0x39, 0x0c, 0x9f, 0x4e, 0x39, 0xfb, 0xe3, 0x85, 0x39, 0x9b, 0x35, 0xd1, 0x39, + 0xde, 0x77, 0x12, 0x39, 0x61, 0x64, 0x33, 0x39, 0xeb, 0xba, 0x62, 0x39, 0xa4, + 0x8c, 0x63, 0x39, 0x4c, 0xd0, 0x39, 0x39, 0xb5, 0x69, 0x9b, 0x39, 0xb9, 0x55, + 0x80, 0x39, 0x97, 0x96, 0x52, 0x39, 0xd6, 0x78, 0x74, 0x39, 0xa2, 0x2d, 0x09, + 0x39, 0x67, 0xac, 0xc4, 0x38, 0x1d, 0x5f, 0x21, 0x39, 0x02, 0x83, 0x13, 0x39, + 0xdb, 0x4b, 0x4a, 0x39, 0xcf, 0x1b, 0x20, 0x39, 0xb4, 0x50, 0x70, 0x39, 0xf7, + 0xd3, 0xe9, 0x38, 0xe2, 0x48, 0x15, 0x39, 0x93, 0x55, 0x04, 0x39, 0xfc, 0xb9, + 0x34, 0x39, 0xda, 0x08, 0x2d, 0x39, 0xb3, 0x09, 0x5f, 0x39, 0x25, 0x87, 0x07, + 0x39, 0x7c, 0x80, 0x37, 0x39, 0xfd, 0x85, 0x24, 0x39, 0x0b, 0x4b, 0x0d, 0x39, + 0xae, 0xfa, 0x17, 0x39, 0x80, 0x0e, 0x44, 0x39, 0xa4, 0x0e, 0x12, 0x39, 0xa1, + 0xb3, 0x12, 0x39, 0xd2, 0x44, 0x1c, 0x39, 0x15, 0x69, 0xd7, 0x38, 0x18, 0x08, + 0x25, 0x39, 0x73, 0x4a, 0x6f, 0x39, 0x70, 0xe3, 0x78, 0x39, 0xbe, 0x9e, 0x31, + 0x39, 0x1b, 0x13, 0x1b, 0x39, 0x3f, 0xf2, 0x41, 0x39, 0xc3, 0xb6, 0x1c, 0x39, + 0xfe, 0x9d, 0x13, 0x39, 0x61, 0x1b, 0x0d, 0x39, 0x23, 0x75, 0x06, 0x39, 0x7b, + 0xa1, 0x3c, 0x39, 0xde, 0x43, 0x7c, 0x39, 0xeb, 0x1b, 0x22, 0x39, 0x76, 0xff, + 0x30, 0x39, 0x24, 0x23, 0x53, 0x39, 0x8b, 0x71, 0x03, 0x39, 0x3b, 0x12, 0x84, + 0x39, 0x9b, 0x1d, 0x9a, 0x39, 0x1e, 0xe6, 0x02, 0x39, 0x2c, 0xbe, 0xdd, 0x38, + 0x55, 0xdd, 0x7b, 0x39, 0xc8, 0xdf, 0x05, 0x39, 0x61, 0x65, 0x25, 0x39, 0x23, + 0xbb, 0x43, 0x39, 0x18, 0x72, 0xe3, 0x38, 0x4d, 0x09, 0x6e, 0x39, 0x91, 0xf0, + 0x36, 0x39, 0x9b, 0x10, 0x1e, 0x39, 0x54, 0xa5, 0x8f, 0x39, 0x8c, 0x4f, 0xbb, + 0x39, 0xf5, 0xd3, 0x1a, 0x39, 0xe7, 0x86, 0xc7, 0x38, 0x0f, 0x4e, 0x11, 0x39, + 0xab, 0xce, 0x17, 0x39, 0xc4, 0xb5, 0x56, 0x39, 0x18, 0xfb, 0x76, 0x39, 0x06, + 0x4d, 0x46, 0x39, 0x1f, 0x49, 0x09, 0x39, 0xd0, 0x09, 0xf7, 0x38, 0xbc, 0x92, + 0x38, 0x39, 0x5c, 0x55, 0x63, 0x39, 0x49, 0xda, 0x43, 0x39, 0xf9, 0xcd, 0x0a, + 0x39, 0xfd, 0xf5, 0xc2, 0x39, 0x49, 0xd8, 0x45, 0x39, 0xf9, 0x91, 0x0d, 0x39, + 0x59, 0x18, 0x15, 0x39, 0xc5, 0x1a, 0x12, 0x39, 0xa6, 0xfe, 0x1d, 0x39, 0x1d, + 0x58, 0x35, 0x39, 0x24, 0x78, 0x42, 0x39, 0x59, 0x85, 0x63, 0x39, 0xd1, 0x0f, + 0x00, 0x39, 0xfa, 0x4c, 0x6a, 0x39, 0xf8, 0x36, 0x27, 0x39, 0x8e, 0xea, 0x21, + 0x39, 0x6e, 0xdc, 0x77, 0x39, 0x21, 0x26, 0xf4, 0x38, 0x3f, 0xff, 0x00, 0x39, + 0x2c, 0x94, 0x14, 0x39, 0x12, 0x2e, 0x36, 0x39, 0x00, 0xd5, 0xd7, 0x38, 0xbd, + 0xa6, 0x18, 0x39, 0xb5, 0xda, 0x5d, 0x39, 0xcd, 0x8e, 0x94, 0x39, 0x64, 0x41, + 0xa4, 0x39, 0xcf, 0x85, 0x10, 0x39, 0x15, 0x89, 0x8f, 0x39, 0x7a, 0x67, 0x1f, + 0x39, 0x30, 0x0c, 0x8e, 0x39, 0x2d, 0x18, 0x1b, 0x39, 0x5e, 0x4b, 0x6d, 0x39, + 0xda, 0x52, 0x25, 0x39, 0x27, 0x75, 0x70, 0x39, 0xea, 0x56, 0x39, 0x39, 0x05, + 0x83, 0xce, 0x38, 0x68, 0x65, 0xea, 0x38, 0x05, 0xd0, 0xe0, 0x38, 0xf6, 0xf8, + 0x67, 0x39, 0x3c, 0x43, 0x41, 0x39, 0xa0, 0x45, 0x4d, 0x39, 0xa9, 0x70, 0xda, + 0x38, 0x39, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x37, 0x5f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x22, 0x03, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0x89, 0xff, 0xff, 0x30, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x37, 0x5f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc2, + 0x03, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x31, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5c, 0x8a, 0xff, + 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, + 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x36, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x62, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x06, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0xe4, 0x0a, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x30, 0x0b, 0xba, 0x38, + 0x07, 0xe6, 0x99, 0x38, 0x5b, 0xb2, 0x0d, 0x39, 0x9a, 0xf2, 0xbe, 0x38, 0x1f, + 0x1d, 0x99, 0x38, 0x8b, 0x74, 0xed, 0x38, 0xaf, 0x9e, 0x6d, 0x38, 0xcb, 0xd4, + 0x9e, 0x38, 0xde, 0xf6, 0xda, 0x38, 0x9a, 0xb8, 0xa7, 0x38, 0x2e, 0x44, 0x99, + 0x38, 0x6a, 0x0c, 0xd5, 0x38, 0x30, 0x65, 0x86, 0x38, 0xcb, 0xe2, 0x38, 0x38, + 0x20, 0xca, 0x7d, 0x38, 0xa1, 0x51, 0x8b, 0x38, 0x0e, 0xc5, 0x88, 0x38, 0x3e, + 0x33, 0x95, 0x38, 0xa2, 0x88, 0xbb, 0x38, 0xcf, 0xaf, 0x7e, 0x38, 0x6a, 0x0d, + 0xae, 0x38, 0xf3, 0x33, 0x86, 0x38, 0x67, 0xd4, 0xc5, 0x38, 0x0f, 0x0f, 0xcc, + 0x38, 0xa6, 0xfb, 0xd7, 0x38, 0x6e, 0xf4, 0x8e, 0x38, 0x61, 0x41, 0xa3, 0x38, + 0xf7, 0xbe, 0xb4, 0x38, 0xb1, 0xe2, 0x9b, 0x38, 0x70, 0x32, 0xca, 0x38, 0xe1, + 0xfb, 0xac, 0x38, 0xff, 0xc4, 0x93, 0x38, 0x49, 0x65, 0xb3, 0x38, 0x95, 0xae, + 0x8b, 0x38, 0x1e, 0x8a, 0x86, 0x38, 0xcf, 0x20, 0x83, 0x38, 0x64, 0x37, 0x9c, + 0x38, 0x8a, 0xb5, 0x35, 0x38, 0xe5, 0xbe, 0xa6, 0x38, 0x35, 0x13, 0xbe, 0x38, + 0x70, 0x9c, 0xc5, 0x38, 0xa9, 0xf2, 0xa6, 0x38, 0x45, 0x16, 0x95, 0x38, 0x29, + 0xe0, 0xaa, 0x38, 0x64, 0xfa, 0xc7, 0x38, 0xa3, 0x66, 0x49, 0x38, 0xe7, 0x2d, + 0xa4, 0x38, 0xd4, 0x74, 0xa8, 0x38, 0xb8, 0xb8, 0x63, 0x38, 0x26, 0x53, 0x72, + 0x38, 0x06, 0x28, 0xc2, 0x38, 0x06, 0xe0, 0xb0, 0x38, 0xa7, 0x1d, 0xa6, 0x38, + 0x05, 0x41, 0xaa, 0x38, 0xc2, 0x93, 0x95, 0x38, 0x38, 0xc1, 0x97, 0x38, 0xb0, + 0xa8, 0xb6, 0x38, 0x7a, 0x24, 0xa5, 0x38, 0xeb, 0xed, 0x83, 0x38, 0xd6, 0x54, + 0x48, 0x38, 0x6f, 0x32, 0x94, 0x38, 0x54, 0x98, 0x8a, 0x38, 0x88, 0x4d, 0x83, + 0x38, 0xb0, 0xe4, 0x96, 0x38, 0xf9, 0xf6, 0xa9, 0x38, 0xe1, 0x67, 0xa6, 0x38, + 0x06, 0x46, 0x78, 0x38, 0xed, 0xd5, 0xea, 0x38, 0x05, 0x1f, 0x94, 0x38, 0x91, + 0xe5, 0x91, 0x38, 0xf6, 0x2e, 0x98, 0x38, 0x94, 0x63, 0x5d, 0x38, 0xf9, 0x4f, + 0xa4, 0x38, 0x4b, 0x46, 0x9e, 0x38, 0x19, 0xcf, 0x98, 0x38, 0x3e, 0x3b, 0x4b, + 0x38, 0x38, 0xc9, 0x79, 0x38, 0x24, 0xbb, 0x88, 0x38, 0xda, 0x39, 0x87, 0x38, + 0xd0, 0xe6, 0x84, 0x38, 0x05, 0x05, 0xa9, 0x38, 0x1a, 0xae, 0x9d, 0x38, 0xc1, + 0x65, 0xbe, 0x38, 0xf1, 0xc2, 0x98, 0x38, 0x20, 0x08, 0x93, 0x38, 0x15, 0xb5, + 0x9c, 0x38, 0xba, 0x98, 0x63, 0x38, 0x98, 0xf0, 0x97, 0x38, 0x04, 0xe0, 0x90, + 0x38, 0xc7, 0x9e, 0x74, 0x38, 0xfe, 0x4c, 0xb7, 0x38, 0x50, 0xeb, 0x7f, 0x38, + 0x2a, 0xe3, 0xa6, 0x38, 0x14, 0xed, 0x73, 0x38, 0x62, 0x8f, 0xcd, 0x38, 0xee, + 0x19, 0x78, 0x38, 0x3a, 0xd7, 0x6c, 0x38, 0x61, 0x01, 0xbd, 0x38, 0x56, 0xda, + 0x97, 0x38, 0xd0, 0xa5, 0xa5, 0x38, 0x1b, 0xb8, 0xc4, 0x38, 0xbb, 0x0b, 0xcc, + 0x38, 0x9d, 0xe2, 0xa7, 0x38, 0xef, 0xaf, 0xb6, 0x38, 0x9e, 0x37, 0xae, 0x38, + 0x6a, 0x46, 0x72, 0x38, 0xfb, 0x4c, 0x88, 0x38, 0x7a, 0xea, 0x96, 0x38, 0x2e, + 0xf7, 0x98, 0x38, 0x08, 0x3a, 0xa5, 0x38, 0xe1, 0xdf, 0xb4, 0x38, 0xcf, 0x6f, + 0x4d, 0x38, 0x9b, 0xe7, 0x91, 0x38, 0xd6, 0x8a, 0x94, 0x38, 0x71, 0x6f, 0x88, + 0x38, 0xa5, 0x79, 0x9d, 0x38, 0xf7, 0xe3, 0xa4, 0x38, 0x3d, 0xe7, 0x6e, 0x38, + 0xea, 0xa0, 0x8c, 0x38, 0x66, 0x7f, 0x3d, 0x38, 0x0e, 0x6e, 0x93, 0x38, 0xd3, + 0x64, 0x6d, 0x38, 0xc9, 0xb9, 0x9b, 0x38, 0xde, 0x7c, 0xdc, 0x38, 0xc9, 0xa5, + 0xcf, 0x38, 0xc7, 0xca, 0x7d, 0x38, 0x79, 0x75, 0xa0, 0x38, 0x5e, 0xab, 0x95, + 0x38, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x36, 0x5f, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, + 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xd6, 0x0a, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x6c, + 0x03, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x32, 0x04, 0xff, 0xff, 0x14, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xe4, 0xe1, 0xd9, 0x38, + 0x59, 0x7e, 0xcd, 0x38, 0x89, 0x65, 0xac, 0x38, 0x2d, 0x36, 0xbb, 0x38, 0xa1, + 0x1e, 0x8e, 0x38, 0xbb, 0x08, 0x92, 0x38, 0x77, 0xc7, 0xf3, 0x38, 0xb3, 0xfb, + 0xbc, 0x38, 0x7f, 0x6a, 0xba, 0x38, 0xff, 0xe1, 0x05, 0x39, 0x24, 0xf5, 0xb9, + 0x38, 0x71, 0xb3, 0xcb, 0x38, 0xbe, 0x56, 0xce, 0x38, 0x18, 0xb7, 0xc0, 0x38, + 0xd2, 0x9d, 0xbd, 0x38, 0x74, 0x16, 0x37, 0x39, 0x46, 0x11, 0xb2, 0x38, 0xbd, + 0x56, 0x6c, 0x39, 0xdb, 0x35, 0xb7, 0x38, 0xe8, 0x93, 0xd7, 0x38, 0x53, 0xc4, + 0xab, 0x38, 0xb6, 0xa6, 0xc4, 0x38, 0xb5, 0xd1, 0x09, 0x39, 0xdd, 0x60, 0xa5, + 0x38, 0x77, 0x4e, 0xed, 0x38, 0x35, 0x67, 0xb4, 0x38, 0x85, 0x14, 0xe0, 0x38, + 0x6b, 0x21, 0xc0, 0x38, 0xfd, 0x90, 0xbf, 0x38, 0xd6, 0x8b, 0xe1, 0x38, 0x76, + 0x9c, 0xaa, 0x38, 0x06, 0x37, 0xc2, 0x38, 0x18, 0x19, 0xac, 0x38, 0xbc, 0x40, + 0xb5, 0x38, 0x54, 0x25, 0x3a, 0x39, 0x03, 0xd8, 0x01, 0x39, 0x1a, 0xdc, 0xe0, + 0x38, 0xdb, 0x58, 0xe6, 0x38, 0x8f, 0xb3, 0x98, 0x38, 0xe6, 0xda, 0x9c, 0x38, + 0x80, 0xed, 0xb5, 0x38, 0x71, 0x6c, 0xfd, 0x38, 0x0f, 0xc1, 0xf6, 0x38, 0x20, + 0x63, 0xde, 0x38, 0x89, 0x1f, 0xab, 0x38, 0xc7, 0xcd, 0xdd, 0x38, 0x5c, 0xf0, + 0x9f, 0x38, 0x1a, 0x54, 0xe4, 0x38, 0x2d, 0x39, 0xba, 0x38, 0x20, 0x55, 0xd1, + 0x38, 0xcf, 0x66, 0x87, 0x38, 0xe1, 0xb7, 0xe6, 0x38, 0x9a, 0x6d, 0x1a, 0x39, + 0xfc, 0x97, 0x11, 0x39, 0x28, 0x62, 0xaf, 0x38, 0x0b, 0xcf, 0xc5, 0x38, 0x61, + 0xbc, 0x23, 0x39, 0x0c, 0x7b, 0xc5, 0x38, 0xfc, 0xfa, 0x94, 0x38, 0x39, 0x7c, + 0x96, 0x38, 0x2a, 0x7e, 0x8e, 0x38, 0x5e, 0x2d, 0xd6, 0x38, 0xa1, 0xd1, 0xcc, + 0x38, 0x43, 0x1a, 0x24, 0x39, 0x39, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x36, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, + 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x52, + 0x0e, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x2c, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xec, 0x94, 0xff, + 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, + 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x36, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0xf2, 0x0e, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, + 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x8c, 0x95, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x35, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, + 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x92, 0x0f, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x02, 0x64, 0x03, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x16, 0xff, 0xff, 0x10, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xd3, 0x57, 0x81, 0x38, 0x47, + 0x8c, 0xbc, 0x38, 0x50, 0xdf, 0xd4, 0x38, 0xe8, 0xc0, 0xf7, 0x38, 0xa1, 0x2a, + 0xaa, 0x38, 0x11, 0x80, 0x8b, 0x38, 0xdc, 0xc8, 0xb0, 0x38, 0xbc, 0xd0, 0xa3, + 0x38, 0x79, 0xa4, 0xd5, 0x38, 0xb0, 0x8f, 0xc2, 0x38, 0x83, 0xa4, 0xbf, 0x38, + 0xf4, 0xa6, 0xa9, 0x38, 0x77, 0x21, 0xc2, 0x38, 0x2f, 0xca, 0x6f, 0x38, 0x06, + 0x11, 0xfe, 0x38, 0xe8, 0xd1, 0x57, 0x38, 0x97, 0xa2, 0xc2, 0x38, 0x6b, 0x93, + 0x59, 0x38, 0x7a, 0x86, 0x7d, 0x38, 0x15, 0xc0, 0xe4, 0x38, 0x70, 0xa8, 0xb4, + 0x38, 0x14, 0x02, 0xa1, 0x38, 0x58, 0x71, 0xb0, 0x38, 0xfd, 0x49, 0xb5, 0x38, + 0x91, 0x89, 0x81, 0x38, 0x3a, 0x10, 0x6c, 0x38, 0x68, 0x77, 0xea, 0x38, 0x45, + 0xdc, 0xa9, 0x38, 0x91, 0x2c, 0xd9, 0x38, 0x22, 0x65, 0xa5, 0x38, 0x4c, 0x00, + 0xc3, 0x38, 0x82, 0x95, 0xa6, 0x38, 0xdf, 0xb7, 0x91, 0x38, 0x4f, 0xb4, 0xa3, + 0x38, 0xcf, 0x1e, 0x9a, 0x38, 0x15, 0xe8, 0x8d, 0x38, 0xd5, 0xfc, 0xa2, 0x38, + 0x68, 0xb5, 0x62, 0x38, 0x51, 0x04, 0x82, 0x38, 0x4a, 0x25, 0xd2, 0x38, 0x8b, + 0xd1, 0xc4, 0x38, 0x02, 0x61, 0xb0, 0x38, 0x5f, 0x34, 0x8b, 0x38, 0xf3, 0xd3, + 0xb3, 0x38, 0x6d, 0x60, 0xb8, 0x38, 0x7f, 0xeb, 0xa8, 0x38, 0x85, 0x4d, 0x8d, + 0x38, 0x56, 0x3a, 0x6c, 0x38, 0x9d, 0xee, 0x94, 0x38, 0x9c, 0x0c, 0x3d, 0x38, + 0xc0, 0x96, 0xae, 0x38, 0x52, 0xab, 0xd5, 0x38, 0xe1, 0xa7, 0x18, 0x38, 0x47, + 0xfe, 0x55, 0x38, 0x36, 0xac, 0xb0, 0x38, 0xd8, 0xdf, 0xa3, 0x38, 0xc1, 0x94, + 0x9c, 0x38, 0x24, 0xd7, 0xb0, 0x38, 0x40, 0x4a, 0xad, 0x38, 0x0f, 0x31, 0xa7, + 0x38, 0x7c, 0xb9, 0xbf, 0x38, 0xd0, 0x06, 0xc6, 0x38, 0x53, 0x4e, 0x5f, 0x38, + 0x94, 0x25, 0x5d, 0x38, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x35, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x06, 0x13, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x02, 0x6c, 0x03, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0x0c, 0xff, 0xff, 0x14, 0x02, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa7, + 0x20, 0xfc, 0x38, 0x89, 0x62, 0x69, 0x39, 0xfc, 0x00, 0x35, 0x39, 0xca, 0x7e, + 0x39, 0x39, 0x08, 0x4e, 0x66, 0x39, 0xf3, 0x61, 0xd8, 0x38, 0x94, 0xb7, 0x05, + 0x39, 0x40, 0x49, 0x97, 0x38, 0x31, 0xdd, 0x9c, 0x39, 0x72, 0x72, 0xb2, 0x39, + 0x74, 0xe6, 0xd4, 0x39, 0x53, 0x96, 0x64, 0x39, 0x38, 0xbe, 0x5f, 0x39, 0x6a, + 0x5f, 0xbe, 0x38, 0x01, 0x21, 0x21, 0x39, 0x8f, 0xf1, 0x40, 0x39, 0xa2, 0x39, + 0x0f, 0x39, 0xc1, 0x47, 0xe9, 0x38, 0x86, 0x92, 0x22, 0x39, 0x34, 0xfb, 0xec, + 0x38, 0xdf, 0x67, 0xe0, 0x38, 0x53, 0x3a, 0x11, 0x39, 0x1a, 0xf8, 0xd1, 0x39, + 0xb5, 0x00, 0x19, 0x39, 0x26, 0x8e, 0x05, 0x39, 0x43, 0x28, 0xac, 0x39, 0xdb, + 0xee, 0x8a, 0x39, 0x85, 0x31, 0xe1, 0x38, 0x0f, 0x1e, 0x11, 0x39, 0xe7, 0xea, + 0x2f, 0x39, 0x42, 0x73, 0x05, 0x39, 0xec, 0x15, 0x2f, 0x39, 0x12, 0x09, 0xd2, + 0x38, 0xd2, 0x2e, 0x09, 0x39, 0x1e, 0x05, 0x22, 0x39, 0xaa, 0x44, 0xaf, 0x38, + 0x02, 0xe1, 0x86, 0x39, 0x59, 0x42, 0x92, 0x39, 0xe4, 0x90, 0x09, 0x39, 0x3c, + 0xde, 0x04, 0x39, 0xaa, 0xf2, 0x32, 0x39, 0xc0, 0x84, 0x2a, 0x39, 0x1d, 0xd5, + 0x76, 0x39, 0x1a, 0x13, 0x24, 0x39, 0x4f, 0xbd, 0xbc, 0x38, 0xe0, 0x06, 0xa8, + 0x38, 0xd5, 0x4b, 0x8f, 0x39, 0xe1, 0xed, 0xc7, 0x38, 0xfd, 0xea, 0x80, 0x39, + 0x77, 0xf5, 0x5b, 0x39, 0x00, 0xa6, 0x37, 0x39, 0xf3, 0x36, 0x55, 0x39, 0x77, + 0x6e, 0xa1, 0x39, 0x2b, 0x10, 0x07, 0x39, 0xd0, 0xf0, 0xdb, 0x38, 0x62, 0xd5, + 0xff, 0x38, 0xcd, 0xfc, 0x53, 0x39, 0x5c, 0xc1, 0x16, 0x39, 0xd3, 0xbe, 0xe9, + 0x38, 0x77, 0xc2, 0xf2, 0x38, 0x71, 0x2a, 0x98, 0x39, 0xe4, 0x4e, 0xd0, 0x38, + 0x4b, 0x79, 0x0a, 0x39, 0x56, 0x9a, 0x8e, 0x39, 0x39, 0x00, 0x00, 0x00, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x35, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, + 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x82, 0x16, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, + 0x00, 0x57, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0x9d, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x35, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x22, 0x17, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x09, 0x84, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xbc, 0x9d, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x34, 0x5f, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xc2, 0x17, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x03, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x20, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x44, 0x1e, 0xff, 0xff, 0x10, + 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa9, 0xbb, + 0xd0, 0x38, 0x3a, 0x81, 0x84, 0x38, 0x12, 0x86, 0xf8, 0x38, 0xd8, 0xe1, 0xd0, + 0x38, 0xb4, 0x0a, 0xa1, 0x38, 0x93, 0x51, 0xb6, 0x38, 0x65, 0xd7, 0xf0, 0x38, + 0x98, 0x9a, 0xc6, 0x38, 0xbf, 0x4e, 0x88, 0x38, 0xc6, 0xa5, 0xd3, 0x38, 0x59, + 0xc6, 0x60, 0x38, 0xd2, 0xdc, 0xf0, 0x38, 0x70, 0x7e, 0x87, 0x38, 0xa3, 0xd3, + 0xcf, 0x38, 0x54, 0xfb, 0x02, 0x39, 0xdb, 0x90, 0x45, 0x39, 0x8b, 0x00, 0xcc, + 0x38, 0x3b, 0xd8, 0xc4, 0x38, 0x73, 0xed, 0xd3, 0x38, 0xcb, 0xb7, 0x8d, 0x38, + 0x3e, 0xc5, 0x2d, 0x39, 0xe9, 0xaf, 0x9f, 0x38, 0x61, 0x00, 0xa6, 0x38, 0xa9, + 0xf7, 0x12, 0x39, 0x70, 0x6d, 0x0c, 0x39, 0x18, 0x81, 0x2a, 0x38, 0x9d, 0x17, + 0x83, 0x38, 0x0b, 0x0d, 0x22, 0x39, 0x83, 0x52, 0x07, 0x39, 0x26, 0x7c, 0xc5, + 0x38, 0xb5, 0x04, 0xd0, 0x38, 0x42, 0xcc, 0x12, 0x39, 0x01, 0x47, 0x00, 0x39, + 0x5e, 0x12, 0x74, 0x38, 0x62, 0x92, 0xb3, 0x38, 0x20, 0xfd, 0x27, 0x39, 0xd0, + 0x51, 0x6e, 0x38, 0x79, 0x0f, 0x77, 0x38, 0x3e, 0x76, 0xb4, 0x38, 0x32, 0x98, + 0x88, 0x38, 0x30, 0x5d, 0xa8, 0x38, 0x11, 0x95, 0xd5, 0x38, 0xb0, 0x91, 0x9f, + 0x38, 0xad, 0x1f, 0xd7, 0x38, 0xec, 0x9d, 0x1b, 0x39, 0xcb, 0x15, 0x1d, 0x39, + 0x27, 0x48, 0x4a, 0x38, 0x09, 0xb3, 0xb5, 0x38, 0x98, 0x7f, 0x02, 0x39, 0x47, + 0x95, 0x53, 0x39, 0xf1, 0x99, 0x47, 0x39, 0x73, 0x76, 0xd8, 0x38, 0x71, 0x7a, + 0xd5, 0x38, 0x67, 0x79, 0x4e, 0x39, 0x42, 0xf0, 0x01, 0x39, 0x59, 0xbe, 0xe5, + 0x38, 0x0a, 0xec, 0x9f, 0x38, 0x87, 0x6a, 0x20, 0x39, 0x6a, 0x06, 0xdc, 0x38, + 0x40, 0x5d, 0xfa, 0x38, 0x95, 0x1d, 0x92, 0x38, 0xd3, 0xcd, 0x3e, 0x39, 0xa1, + 0x43, 0x0d, 0x39, 0x6b, 0x23, 0x97, 0x38, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x5f, 0x34, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, + 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x36, 0x1b, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x02, 0xec, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0xa4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x92, 0x14, 0xff, 0xff, 0x14, + 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xc5, 0xba, 0x8c, 0x38, 0x92, 0x4d, 0xa9, + 0x38, 0x52, 0x02, 0x82, 0x38, 0xfc, 0xa9, 0xaf, 0x38, 0xff, 0x9a, 0x46, 0x39, + 0x14, 0xa1, 0xcb, 0x38, 0x60, 0xad, 0x95, 0x38, 0xb6, 0xdd, 0x96, 0x38, 0x69, + 0x54, 0x96, 0x38, 0xca, 0x22, 0x68, 0x38, 0x68, 0x2c, 0xac, 0x38, 0xe7, 0x85, + 0x95, 0x38, 0x41, 0x03, 0xd5, 0x38, 0xd5, 0x13, 0x28, 0x39, 0xa9, 0xae, 0xde, + 0x38, 0x26, 0x06, 0xa4, 0x38, 0xa7, 0x7b, 0x9a, 0x38, 0x0e, 0x89, 0x8f, 0x38, + 0x4c, 0x4a, 0xf2, 0x38, 0x6d, 0x8f, 0x9d, 0x38, 0x03, 0xb2, 0xef, 0x38, 0x3e, + 0x97, 0xd8, 0x38, 0x80, 0xfe, 0x4b, 0x38, 0xed, 0x28, 0xad, 0x38, 0x04, 0xbb, + 0x2a, 0x39, 0x49, 0x6b, 0xbb, 0x38, 0x82, 0x54, 0xa2, 0x38, 0xbd, 0xee, 0x90, + 0x38, 0x46, 0xb5, 0xea, 0x38, 0xd2, 0x63, 0xa7, 0x38, 0x11, 0x03, 0xda, 0x38, + 0x48, 0x20, 0x22, 0x39, 0x39, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x34, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x32, 0x1d, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xcc, 0xa3, 0xff, 0xff, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, + 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x34, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, + 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0xd2, 0x1d, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, + 0x00, 0x35, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6c, 0xa4, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x33, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x72, 0x1e, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x02, 0xe4, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xf4, 0x24, 0xff, 0xff, 0x10, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3e, 0x8f, + 0xd5, 0x38, 0xe1, 0xa8, 0x15, 0x39, 0x06, 0x19, 0xf5, 0x38, 0x79, 0x80, 0xc5, + 0x38, 0x35, 0x5e, 0x4f, 0x38, 0x3f, 0x44, 0x8d, 0x38, 0x0a, 0xa0, 0xb7, 0x38, + 0xb2, 0xf2, 0xa7, 0x38, 0x34, 0xb7, 0xf3, 0x38, 0xb4, 0xd4, 0xb8, 0x38, 0x08, + 0x3d, 0x0e, 0x39, 0xea, 0xad, 0xa8, 0x38, 0x47, 0xf9, 0x00, 0x39, 0xbf, 0x4e, + 0x04, 0x39, 0xdb, 0x31, 0xa0, 0x38, 0xed, 0x1d, 0xbd, 0x38, 0x41, 0x75, 0xc6, + 0x38, 0x76, 0x6a, 0xe9, 0x38, 0xe5, 0x13, 0x0f, 0x39, 0x14, 0xa9, 0xed, 0x38, + 0xd2, 0x34, 0x26, 0x39, 0xc4, 0x70, 0xc7, 0x38, 0x27, 0xd1, 0xb3, 0x38, 0xb7, + 0x3f, 0xfd, 0x38, 0x58, 0x20, 0x1e, 0x39, 0xd6, 0xeb, 0x47, 0x39, 0x15, 0x4c, + 0x22, 0x39, 0xa1, 0xd0, 0x04, 0x39, 0xa2, 0x9e, 0x8c, 0x38, 0x2c, 0x4b, 0xbe, + 0x38, 0xd9, 0xb7, 0xe5, 0x38, 0x2a, 0xdd, 0xbf, 0x38, 0x36, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x33, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, + 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, + 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x66, + 0x20, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0xec, 0x01, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0xa4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc2, 0x19, 0xff, + 0xff, 0x14, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xe1, 0x95, 0x47, 0x39, 0x5c, + 0xa6, 0x6d, 0x39, 0x76, 0xe7, 0x2c, 0x39, 0x44, 0x2e, 0x74, 0x39, 0x27, 0x35, + 0x9d, 0x39, 0x0c, 0xe8, 0x14, 0x3a, 0x59, 0x1e, 0xd8, 0x38, 0x9b, 0xf8, 0x30, + 0x39, 0xfc, 0xec, 0x33, 0x39, 0xcd, 0x64, 0xd1, 0x39, 0x39, 0xe6, 0x05, 0x3a, + 0x72, 0xd9, 0x25, 0x39, 0x42, 0xa7, 0x87, 0x38, 0xd6, 0xfc, 0xa1, 0x39, 0xe1, + 0x80, 0x50, 0x39, 0xe2, 0x17, 0x4b, 0x38, 0x07, 0xb7, 0x2c, 0x39, 0xa1, 0x48, + 0xd2, 0x38, 0x3d, 0xfc, 0x06, 0x3a, 0xae, 0x9c, 0x16, 0x3a, 0x53, 0xec, 0x07, + 0x39, 0x9c, 0xa6, 0x10, 0x3a, 0x59, 0x92, 0x9c, 0x38, 0xd0, 0xc6, 0x1f, 0x39, + 0x61, 0x0a, 0x16, 0x39, 0xb9, 0x19, 0x35, 0x3a, 0x4d, 0x18, 0x3b, 0x39, 0x21, + 0x5f, 0x9e, 0x38, 0x70, 0x69, 0xfb, 0x38, 0x85, 0x13, 0x29, 0x39, 0xca, 0x56, + 0x1f, 0x39, 0x98, 0x9d, 0x8a, 0x39, 0x39, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x33, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, + 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, + 0x61, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x62, 0x22, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfc, 0xa8, + 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, + 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x33, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, + 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x02, 0x23, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x9c, 0xa9, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa2, 0x23, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x02, 0xe4, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0xa0, 0x01, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x24, 0x2a, 0xff, 0xff, 0x10, 0x01, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0xa9, 0x23, 0x8e, 0x39, 0xb2, 0x18, 0xc6, 0x38, 0x94, 0x74, 0x1a, 0x39, 0x67, + 0xb0, 0x1d, 0x39, 0xcd, 0x82, 0xf5, 0x38, 0xb3, 0x69, 0x1d, 0x38, 0x67, 0xcc, + 0x03, 0x39, 0x74, 0xc8, 0x29, 0x39, 0xaf, 0x8a, 0xb9, 0x38, 0x18, 0x9b, 0xa7, + 0x38, 0xb5, 0x00, 0x2d, 0x38, 0x4f, 0x24, 0xfe, 0x38, 0xce, 0xc8, 0x1c, 0x39, + 0xe2, 0x95, 0xfb, 0x38, 0xc4, 0x61, 0x72, 0x39, 0x18, 0x6d, 0x8d, 0x39, 0x57, + 0x16, 0x24, 0x39, 0x92, 0xe1, 0x3c, 0x39, 0x03, 0x6a, 0x5a, 0x38, 0x21, 0x2c, + 0x9b, 0x38, 0xa9, 0x0d, 0x05, 0x39, 0xd1, 0x14, 0x3f, 0x38, 0x2a, 0xa9, 0x11, + 0x39, 0xf1, 0xe3, 0x25, 0x39, 0xd4, 0x0c, 0x05, 0x39, 0x8c, 0x1e, 0xdc, 0x37, + 0xfa, 0xf1, 0x07, 0x39, 0x33, 0x53, 0x34, 0x39, 0x97, 0x2f, 0x6a, 0x39, 0xd0, + 0x60, 0xe8, 0x38, 0x00, 0x42, 0x4d, 0x39, 0xf1, 0xd0, 0xb5, 0x38, 0x36, 0x00, + 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x5f, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, + 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x96, 0x25, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x2c, 0x01, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf2, + 0x1e, 0xff, 0xff, 0x94, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x27, + 0xf0, 0xac, 0x38, 0x4d, 0xb4, 0x95, 0x38, 0x20, 0x35, 0xf3, 0x38, 0xed, 0x7a, + 0xc5, 0x38, 0x08, 0x25, 0x10, 0x39, 0xff, 0xdf, 0xec, 0x38, 0x1b, 0x9b, 0xf9, + 0x38, 0xce, 0x25, 0x84, 0x38, 0x67, 0xff, 0xf7, 0x38, 0xf1, 0x99, 0x5b, 0x39, + 0x59, 0xbf, 0x93, 0x38, 0x9e, 0x8e, 0xf4, 0x38, 0xf9, 0x05, 0xb2, 0x38, 0xa0, + 0x01, 0xad, 0x38, 0x04, 0x3f, 0x24, 0x39, 0xef, 0x8a, 0x32, 0x39, 0x39, 0x00, + 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x5f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0xd2, 0x26, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x84, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x6c, 0xad, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x32, 0x5f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x72, 0x27, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0xae, 0xff, 0xff, 0x30, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, + 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x5f, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, + 0x75, 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x12, 0x28, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x24, 0x01, 0x00, 0x00, 0x24, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x94, 0x2e, + 0xff, 0xff, 0x90, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x58, 0x91, 0xaa, 0x39, 0x89, 0x15, + 0x5a, 0x39, 0x0c, 0xe3, 0xcb, 0x39, 0x37, 0x66, 0x33, 0x39, 0xb6, 0xee, 0x95, + 0x39, 0x82, 0xd1, 0x97, 0x39, 0xc1, 0x33, 0x41, 0x39, 0x27, 0x74, 0x53, 0x39, + 0xfc, 0x35, 0xb0, 0x39, 0x97, 0x5a, 0x4c, 0x39, 0x7b, 0xb4, 0x9e, 0x39, 0x95, + 0xda, 0x45, 0x39, 0xfc, 0x96, 0x95, 0x39, 0x36, 0x8b, 0x2b, 0x39, 0x2f, 0x32, + 0x48, 0x39, 0x51, 0x8f, 0x86, 0x39, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x31, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x46, 0x29, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x02, 0xcc, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa2, 0x22, 0xff, 0xff, 0x54, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfa, 0x50, 0xd3, 0x38, 0x62, + 0x8a, 0x18, 0x39, 0x74, 0x24, 0x61, 0x3b, 0x22, 0x48, 0x8f, 0x38, 0xec, 0xd9, + 0xb4, 0x39, 0x0a, 0xb5, 0x82, 0x38, 0x1c, 0xef, 0x35, 0x39, 0xd6, 0x72, 0xf6, + 0x3b, 0x39, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x5f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x2a, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbc, 0xb0, 0xff, 0xff, 0x30, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x5f, 0x64, + 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xc2, + 0x2a, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x27, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5c, 0xb1, 0xff, + 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x98, 0x72, + 0x98, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x25, 0xda, 0x97, 0x40, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x31, 0x33, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, + 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x62, 0x2b, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x0c, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0xe4, 0x31, 0xff, 0xff, 0x10, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x37, 0xa6, 0x37, 0xa1, 0xb4, 0x00, + 0x38, 0x98, 0x9f, 0xe0, 0x37, 0x43, 0x01, 0x4f, 0x37, 0x0f, 0xa8, 0xe7, 0x37, + 0x6d, 0x06, 0x84, 0x37, 0x96, 0x2b, 0x92, 0x37, 0x4d, 0xf5, 0xe0, 0x37, 0x9e, + 0xa2, 0xa7, 0x37, 0xa0, 0x06, 0xcc, 0x37, 0xe4, 0x70, 0xa6, 0x37, 0x4d, 0x9c, + 0x85, 0x37, 0xbd, 0x71, 0xd4, 0x37, 0xfe, 0x3d, 0x8b, 0x37, 0xd5, 0xe9, 0x87, + 0x37, 0x0a, 0x83, 0xa1, 0x37, 0xae, 0x42, 0xae, 0x37, 0xc5, 0xda, 0x82, 0x37, + 0xad, 0xbd, 0x6b, 0x37, 0xa5, 0x09, 0xbe, 0x37, 0xb8, 0xf0, 0x5c, 0x37, 0x78, + 0xb8, 0x95, 0x37, 0x6a, 0xbe, 0xc1, 0x37, 0xc7, 0xbc, 0x96, 0x37, 0x14, 0xb4, + 0xe4, 0x37, 0xf2, 0x48, 0x92, 0x37, 0x46, 0xc4, 0x06, 0x38, 0x59, 0x42, 0xc5, + 0x37, 0x7c, 0x19, 0x66, 0x37, 0x30, 0xe4, 0x8a, 0x37, 0x5b, 0x24, 0xa4, 0x37, + 0x78, 0x26, 0xba, 0x37, 0xca, 0xbf, 0xd9, 0x37, 0xf5, 0xb8, 0x9c, 0x37, 0xee, + 0xa0, 0x96, 0x37, 0xb5, 0xa5, 0x8f, 0x37, 0x58, 0xa9, 0x9e, 0x37, 0xc0, 0x9e, + 0x79, 0x37, 0x56, 0xde, 0xac, 0x37, 0x89, 0xa8, 0x94, 0x37, 0xcc, 0xeb, 0xc6, + 0x37, 0xd2, 0x26, 0xa3, 0x37, 0x3b, 0x10, 0xc7, 0x37, 0x7c, 0x49, 0xba, 0x37, + 0xbb, 0x07, 0x5a, 0x37, 0xe4, 0x03, 0x6f, 0x37, 0xee, 0x71, 0x93, 0x37, 0x74, + 0x4a, 0x89, 0x37, 0x3d, 0x2f, 0xd1, 0x37, 0x38, 0x2e, 0xca, 0x37, 0xa3, 0x44, + 0xa3, 0x37, 0x4d, 0xbe, 0x6d, 0x37, 0x27, 0x53, 0x88, 0x37, 0x87, 0x38, 0x1c, + 0x38, 0x53, 0x4c, 0x8e, 0x37, 0x3f, 0x6a, 0xbe, 0x37, 0x6a, 0x06, 0xc9, 0x37, + 0xf6, 0xa8, 0x96, 0x37, 0x07, 0x79, 0x87, 0x37, 0xa5, 0x0f, 0xa6, 0x37, 0xc0, + 0x65, 0xa6, 0x37, 0x4d, 0xf4, 0x9a, 0x37, 0xa1, 0x4f, 0xc2, 0x37, 0x49, 0xa7, + 0x8f, 0x37, 0x46, 0x94, 0x68, 0x37, 0xd8, 0x90, 0xa0, 0x37, 0x00, 0x2c, 0x76, + 0x37, 0xe0, 0xdc, 0x92, 0x37, 0x02, 0x50, 0x92, 0x37, 0xb5, 0x1f, 0xab, 0x37, + 0x77, 0x9c, 0xae, 0x37, 0x4f, 0x20, 0x8f, 0x37, 0x30, 0xd6, 0x43, 0x37, 0xbc, + 0xb3, 0x9f, 0x37, 0x08, 0x44, 0x7e, 0x37, 0x8b, 0x1a, 0x79, 0x37, 0x2f, 0xb3, + 0xf9, 0x37, 0x19, 0x9a, 0xa3, 0x37, 0x64, 0xa1, 0x87, 0x37, 0x39, 0xb2, 0x4f, + 0x37, 0x24, 0x04, 0x19, 0x38, 0x06, 0x87, 0x81, 0x37, 0x8b, 0xfb, 0x4f, 0x37, + 0xbc, 0x34, 0x93, 0x37, 0xff, 0x66, 0xd9, 0x37, 0xfc, 0x08, 0x66, 0x37, 0x44, + 0xf8, 0x87, 0x37, 0xfd, 0xf8, 0xec, 0x37, 0x74, 0x22, 0x93, 0x37, 0x8b, 0x02, + 0x99, 0x37, 0x05, 0x49, 0xc1, 0x37, 0x7d, 0x68, 0x7d, 0x37, 0x7e, 0x66, 0x99, + 0x37, 0xff, 0xdd, 0xa3, 0x37, 0xc7, 0x00, 0x5b, 0x37, 0x1b, 0x9c, 0xe9, 0x37, + 0xbe, 0x3f, 0xc6, 0x37, 0x12, 0x48, 0xad, 0x37, 0x61, 0x61, 0xe4, 0x37, 0x61, + 0xd1, 0x81, 0x37, 0x4f, 0xd5, 0x80, 0x37, 0x5b, 0x9b, 0x7c, 0x37, 0xc3, 0x4c, + 0x7c, 0x37, 0xad, 0xdd, 0xa6, 0x37, 0x0f, 0x98, 0xcf, 0x37, 0x6f, 0xb3, 0x83, + 0x37, 0xff, 0xdd, 0x7e, 0x37, 0x8f, 0x15, 0x7e, 0x37, 0x39, 0xbb, 0xb7, 0x37, + 0xc2, 0xa7, 0xa1, 0x37, 0x33, 0xa7, 0xc9, 0x37, 0x5e, 0x0a, 0x7d, 0x37, 0xb5, + 0x3e, 0x45, 0x37, 0xbb, 0x10, 0xe8, 0x37, 0xc9, 0xc0, 0x86, 0x37, 0xb3, 0x01, + 0xc6, 0x37, 0x1a, 0xfe, 0xd6, 0x37, 0x12, 0x88, 0x8b, 0x37, 0x5b, 0x0c, 0xf5, + 0x37, 0xeb, 0x77, 0x7b, 0x37, 0xb1, 0x5b, 0xa6, 0x37, 0x80, 0xb2, 0x6e, 0x37, + 0x2c, 0x7e, 0x78, 0x37, 0xea, 0xc5, 0xa0, 0x37, 0x8c, 0xee, 0xa6, 0x37, 0xf1, + 0x74, 0x7a, 0x37, 0x47, 0xd0, 0x72, 0x37, 0x7a, 0xca, 0xb8, 0x37, 0x4f, 0x17, + 0xb1, 0x37, 0xe8, 0xee, 0xe9, 0x37, 0x0c, 0xb2, 0xf3, 0x37, 0x43, 0xcd, 0xbe, + 0x37, 0x4e, 0xe2, 0xa2, 0x37, 0xcc, 0x69, 0x77, 0x37, 0x63, 0xbf, 0xae, 0x37, + 0xcf, 0xf5, 0x49, 0x37, 0x15, 0x5a, 0xbd, 0x37, 0x87, 0xe5, 0xb5, 0x37, 0x0e, + 0x9c, 0x78, 0x37, 0x58, 0x6c, 0x92, 0x37, 0x82, 0xbe, 0xb3, 0x37, 0xbe, 0xbd, + 0x92, 0x37, 0xd5, 0xe0, 0x97, 0x37, 0xcb, 0xee, 0xa7, 0x37, 0x6e, 0xab, 0xa0, + 0x37, 0x21, 0x07, 0x9d, 0x37, 0xa1, 0x64, 0xac, 0x37, 0x56, 0xbc, 0xa9, 0x37, + 0xb5, 0x8d, 0xb8, 0x37, 0xed, 0x81, 0x87, 0x37, 0x95, 0xbf, 0xaa, 0x37, 0xc1, + 0xd9, 0x93, 0x37, 0xaa, 0x1d, 0x79, 0x37, 0x89, 0xa7, 0x66, 0x37, 0x52, 0x2f, + 0xb7, 0x37, 0x72, 0xb9, 0xa3, 0x37, 0x1d, 0xa3, 0x91, 0x37, 0xe2, 0x52, 0xef, + 0x37, 0xb0, 0x2b, 0x95, 0x37, 0xed, 0x68, 0x97, 0x37, 0x15, 0xd7, 0x76, 0x37, + 0x53, 0xba, 0x95, 0x37, 0x24, 0x50, 0x0a, 0x38, 0xbd, 0xc8, 0x9b, 0x37, 0xcd, + 0x2e, 0x92, 0x37, 0x41, 0x93, 0x8c, 0x37, 0x7d, 0xa0, 0x6e, 0x37, 0x05, 0x97, + 0x97, 0x37, 0x11, 0xc1, 0x5d, 0x37, 0x40, 0x3d, 0xf4, 0x37, 0x88, 0x74, 0x9c, + 0x37, 0x6d, 0x48, 0x6e, 0x37, 0xf1, 0x0a, 0xd1, 0x37, 0x6b, 0x91, 0x87, 0x37, + 0x1d, 0x90, 0x96, 0x37, 0x8a, 0x5c, 0x97, 0x37, 0xcd, 0x78, 0x4c, 0x38, 0xb6, + 0xc4, 0x18, 0x38, 0xe7, 0xee, 0xaa, 0x37, 0x76, 0xff, 0x9c, 0x37, 0x3e, 0xe5, + 0x75, 0x37, 0x5e, 0x91, 0x8d, 0x37, 0xe8, 0x93, 0x94, 0x37, 0x67, 0xa9, 0xa1, + 0x37, 0x38, 0x67, 0xbc, 0x37, 0x0f, 0x70, 0xae, 0x37, 0x56, 0xb9, 0xe5, 0x37, + 0xb9, 0x85, 0x8f, 0x37, 0x9e, 0xfe, 0x89, 0x37, 0xeb, 0x2d, 0x98, 0x37, 0xad, + 0x33, 0x9e, 0x37, 0x15, 0x54, 0xbd, 0x37, 0xac, 0x25, 0x78, 0x37, 0xa2, 0x99, + 0xa2, 0x37, 0x0f, 0x39, 0xb8, 0x37, 0x1d, 0x29, 0x70, 0x37, 0x49, 0x30, 0x88, + 0x37, 0x29, 0x56, 0xc4, 0x37, 0x5c, 0xc7, 0x73, 0x37, 0x5a, 0x86, 0x28, 0x37, + 0xb9, 0x1a, 0x89, 0x37, 0x19, 0x6d, 0x34, 0x37, 0x86, 0xf1, 0xb0, 0x37, 0xc2, + 0xbb, 0xb5, 0x37, 0xb9, 0xcc, 0x9e, 0x37, 0x53, 0xfc, 0xc1, 0x37, 0x15, 0x65, + 0xd7, 0x37, 0x36, 0x53, 0x84, 0x37, 0x11, 0x3c, 0x5f, 0x37, 0x21, 0xdf, 0xad, + 0x37, 0xaa, 0xa4, 0xb3, 0x37, 0xf0, 0x1d, 0xc0, 0x37, 0x89, 0x4d, 0x9d, 0x37, + 0x0b, 0x3f, 0x90, 0x37, 0xc7, 0x60, 0x0d, 0x38, 0x17, 0xd5, 0x62, 0x37, 0x79, + 0xf9, 0x64, 0x37, 0x05, 0xa7, 0x9d, 0x37, 0xa4, 0x54, 0xb6, 0x37, 0xd5, 0xd7, + 0x9a, 0x37, 0x6d, 0x6c, 0xa5, 0x37, 0xbc, 0x04, 0x84, 0x37, 0x26, 0xd0, 0xc6, + 0x37, 0x27, 0x4f, 0xd9, 0x37, 0xe4, 0x88, 0x97, 0x37, 0xa0, 0xb0, 0x90, 0x37, + 0xd0, 0x8a, 0x70, 0x37, 0x37, 0x89, 0x65, 0x37, 0xd0, 0xed, 0x84, 0x37, 0x51, + 0x5b, 0x81, 0x37, 0xa1, 0xcb, 0xcf, 0x37, 0x50, 0x99, 0x89, 0x37, 0x06, 0x12, + 0x98, 0x37, 0xb9, 0x3c, 0x46, 0x37, 0x79, 0x62, 0xc0, 0x37, 0x77, 0x44, 0xfd, + 0x37, 0xe2, 0x7a, 0xc5, 0x37, 0xcd, 0xd7, 0x74, 0x37, 0xfe, 0x0e, 0x80, 0x37, + 0xc2, 0x16, 0xbe, 0x37, 0xd8, 0x0f, 0x0f, 0x38, 0x06, 0x17, 0xd0, 0x37, 0x17, + 0xb5, 0x7e, 0x37, 0xda, 0x09, 0x0d, 0x38, 0x12, 0xbe, 0x6c, 0x37, 0xae, 0x7e, + 0xfe, 0x37, 0xc7, 0xb0, 0xe0, 0x37, 0x2b, 0xdd, 0xaf, 0x37, 0x8a, 0xa2, 0x86, + 0x37, 0x71, 0x66, 0x13, 0x38, 0x3e, 0x15, 0x8b, 0x37, 0xd1, 0x60, 0xa3, 0x37, + 0xd0, 0xe7, 0xf9, 0x37, 0xf3, 0xcf, 0xcb, 0x37, 0xc5, 0x4b, 0xa0, 0x37, 0x35, + 0xae, 0xcb, 0x37, 0x37, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, + 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, + 0x33, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xd6, 0x37, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x02, 0x6c, 0x0c, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x0c, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x32, 0x31, 0xff, 0xff, 0x14, 0x08, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0xb0, 0xe5, 0x90, 0x39, 0xc1, 0x92, 0x2e, 0x39, 0x18, 0xad, 0xa1, 0x39, 0x8b, + 0xcb, 0x3b, 0x39, 0x27, 0xd9, 0x0f, 0x39, 0xb2, 0x7b, 0x51, 0x39, 0x41, 0xb1, + 0x05, 0x39, 0x4f, 0x04, 0x77, 0x39, 0xf3, 0x6c, 0x0f, 0x39, 0x3d, 0xfc, 0x77, + 0x39, 0x70, 0x73, 0x25, 0x39, 0x99, 0xd2, 0x12, 0x39, 0x26, 0xc1, 0x33, 0x39, + 0x8f, 0x0b, 0x33, 0x39, 0xae, 0xe1, 0x81, 0x39, 0xe4, 0xf5, 0x62, 0x39, 0x63, + 0x50, 0x20, 0x39, 0x76, 0x82, 0x10, 0x39, 0xc6, 0x80, 0x65, 0x39, 0xf6, 0x7d, + 0x54, 0x39, 0x0f, 0x03, 0x79, 0x39, 0x9b, 0xef, 0x4c, 0x39, 0xa1, 0x12, 0x48, + 0x39, 0x23, 0x63, 0x51, 0x39, 0x52, 0xcf, 0x62, 0x39, 0x3c, 0xff, 0x24, 0x39, + 0x9a, 0xbd, 0x33, 0x39, 0x89, 0x8e, 0x5a, 0x39, 0x53, 0x05, 0x71, 0x39, 0xe1, + 0x35, 0x06, 0x39, 0x36, 0x71, 0x1b, 0x39, 0x3b, 0x22, 0x09, 0x39, 0x4e, 0x59, + 0x17, 0x39, 0x51, 0x6c, 0x31, 0x39, 0xd2, 0x94, 0x46, 0x39, 0x15, 0x9a, 0x4c, + 0x39, 0x68, 0x27, 0x85, 0x39, 0x57, 0x9e, 0x40, 0x39, 0xdd, 0x3e, 0x9e, 0x39, + 0x05, 0x2d, 0x87, 0x39, 0x9b, 0xb1, 0x55, 0x39, 0x79, 0x55, 0x42, 0x39, 0x5e, + 0x90, 0x21, 0x39, 0xa1, 0x2a, 0x2d, 0x39, 0xb0, 0xa2, 0x36, 0x39, 0x06, 0x7a, + 0x40, 0x39, 0x00, 0x86, 0x4d, 0x39, 0x12, 0xab, 0x82, 0x39, 0x90, 0xf3, 0x3f, + 0x39, 0xe0, 0x70, 0x2c, 0x39, 0x5b, 0x73, 0x27, 0x39, 0x54, 0x38, 0x23, 0x39, + 0xf7, 0xd0, 0xff, 0x38, 0xbb, 0x29, 0x5e, 0x39, 0x1b, 0xd5, 0x83, 0x39, 0x4d, + 0xff, 0x25, 0x39, 0x21, 0xa7, 0x28, 0x39, 0x92, 0x5f, 0x2c, 0x39, 0x55, 0x77, + 0x76, 0x39, 0xc4, 0x8a, 0x09, 0x39, 0x5f, 0xdc, 0x3d, 0x39, 0xed, 0xe2, 0x8c, + 0x39, 0xde, 0x2b, 0x44, 0x39, 0x36, 0x74, 0x9c, 0x39, 0xf6, 0xe6, 0x7d, 0x39, + 0x15, 0xad, 0x6c, 0x39, 0x94, 0x7b, 0x23, 0x39, 0x21, 0xda, 0x65, 0x39, 0xf0, + 0xe6, 0x51, 0x39, 0xb0, 0xcd, 0x54, 0x39, 0x93, 0x79, 0x19, 0x39, 0x8c, 0x13, + 0x6c, 0x39, 0x9b, 0x9e, 0x26, 0x39, 0x2e, 0xd8, 0x37, 0x39, 0x2c, 0x02, 0x4e, + 0x39, 0xe1, 0x82, 0x3b, 0x39, 0x80, 0x97, 0x14, 0x39, 0xb0, 0x36, 0x47, 0x39, + 0x4b, 0x5c, 0x84, 0x39, 0xac, 0xcb, 0x38, 0x39, 0xad, 0xc9, 0x78, 0x39, 0x77, + 0x79, 0x25, 0x39, 0x58, 0x48, 0x7a, 0x39, 0xb6, 0x02, 0x31, 0x39, 0x6a, 0xcd, + 0x0b, 0x39, 0xde, 0xf4, 0x50, 0x39, 0xd2, 0x52, 0x83, 0x39, 0x30, 0x2e, 0x34, + 0x39, 0x35, 0x7c, 0x59, 0x39, 0x2c, 0x59, 0x2f, 0x39, 0x3b, 0x14, 0x19, 0x39, + 0xc2, 0x49, 0x26, 0x39, 0xea, 0xbf, 0x4c, 0x39, 0x64, 0xb8, 0x97, 0x39, 0xf3, + 0xb8, 0x52, 0x39, 0xed, 0xde, 0x44, 0x39, 0xb5, 0xb9, 0x58, 0x39, 0x58, 0x74, + 0x62, 0x39, 0x6f, 0x38, 0x1a, 0x39, 0x82, 0x10, 0x2f, 0x39, 0xf7, 0xa6, 0x60, + 0x39, 0xd3, 0xbd, 0x6f, 0x39, 0x12, 0xb3, 0x3b, 0x39, 0xf1, 0x46, 0x42, 0x39, + 0x72, 0xd8, 0x2c, 0x39, 0xd3, 0x91, 0x4e, 0x39, 0xaa, 0x80, 0x26, 0x39, 0x1b, + 0x95, 0xff, 0x38, 0xf0, 0xa8, 0x69, 0x39, 0xcf, 0x29, 0x86, 0x39, 0xd1, 0x23, + 0x1a, 0x39, 0xb6, 0x2f, 0x3a, 0x39, 0xa5, 0x55, 0x1e, 0x39, 0x17, 0xcf, 0x45, + 0x39, 0x15, 0x57, 0xea, 0x38, 0xcf, 0xbb, 0x17, 0x39, 0x52, 0xc3, 0x44, 0x39, + 0x2d, 0x44, 0x66, 0x39, 0x13, 0x22, 0x9e, 0x39, 0xa2, 0x1f, 0x2b, 0x39, 0x6d, + 0xac, 0x57, 0x39, 0x06, 0xa5, 0x84, 0x39, 0x9f, 0x2c, 0x0f, 0x39, 0x2a, 0xab, + 0x35, 0x39, 0x8c, 0x72, 0x49, 0x39, 0x73, 0x53, 0x4c, 0x39, 0xc6, 0x1a, 0x90, + 0x39, 0xf9, 0xa3, 0x6c, 0x39, 0xa7, 0xa9, 0xac, 0x39, 0x5d, 0x07, 0x1c, 0x39, + 0x75, 0x46, 0x21, 0x39, 0x4d, 0xad, 0x4a, 0x39, 0x23, 0x7f, 0x52, 0x39, 0x94, + 0x97, 0x4b, 0x39, 0xab, 0x86, 0x17, 0x39, 0x15, 0xa4, 0x05, 0x39, 0xe3, 0xce, + 0x1b, 0x39, 0xbb, 0xe3, 0xd9, 0x38, 0x55, 0x62, 0x1e, 0x39, 0x8e, 0x3c, 0x6c, + 0x39, 0x92, 0xd5, 0x4d, 0x39, 0x33, 0x73, 0x81, 0x39, 0x98, 0xce, 0xb0, 0x39, + 0x57, 0xe4, 0x25, 0x39, 0x59, 0x1f, 0x67, 0x39, 0x09, 0x6b, 0x77, 0x39, 0xbe, + 0xcc, 0x52, 0x39, 0x30, 0x00, 0x5a, 0x39, 0x24, 0x7f, 0x5c, 0x39, 0x62, 0x99, + 0x6e, 0x39, 0xa7, 0xc8, 0x44, 0x39, 0xd3, 0x1c, 0xf9, 0x38, 0xad, 0xa2, 0x8b, + 0x39, 0x0b, 0xe0, 0x61, 0x39, 0x64, 0xf5, 0x25, 0x39, 0x56, 0x0a, 0x53, 0x39, + 0x35, 0x4a, 0x47, 0x39, 0x0f, 0x33, 0x3c, 0x39, 0xc0, 0xb1, 0x34, 0x39, 0x24, + 0x11, 0x6c, 0x39, 0x32, 0x70, 0x3c, 0x39, 0xfe, 0x33, 0x36, 0x39, 0xe7, 0xbc, + 0xeb, 0x38, 0xba, 0xd8, 0x17, 0x39, 0x27, 0x6b, 0x5f, 0x39, 0xef, 0x82, 0x2d, + 0x39, 0x34, 0x5c, 0x6a, 0x39, 0x8c, 0x54, 0x3b, 0x39, 0x44, 0x16, 0x3c, 0x39, + 0x08, 0x5b, 0x78, 0x39, 0x20, 0xb4, 0xc1, 0x39, 0x49, 0xb8, 0x08, 0x39, 0x08, + 0xe9, 0x63, 0x39, 0x4d, 0x7b, 0x49, 0x39, 0x0a, 0x6c, 0x2c, 0x39, 0x15, 0x27, + 0x86, 0x39, 0x71, 0xda, 0x74, 0x39, 0xb1, 0x10, 0x18, 0x39, 0xa4, 0x45, 0x94, + 0x39, 0x61, 0x87, 0x71, 0x39, 0x8c, 0x1c, 0x64, 0x39, 0x7a, 0x1e, 0x7b, 0x39, + 0x7e, 0xb6, 0x36, 0x39, 0x2f, 0x59, 0x14, 0x39, 0xd5, 0x70, 0x1a, 0x39, 0x12, + 0xa8, 0xc2, 0x39, 0xe5, 0x23, 0x80, 0x39, 0x73, 0xd2, 0x95, 0x39, 0xe4, 0xe4, + 0x2c, 0x39, 0xc7, 0x98, 0x50, 0x39, 0xe2, 0x0d, 0x62, 0x39, 0xef, 0xd1, 0x22, + 0x39, 0xc5, 0xb5, 0x05, 0x39, 0x7b, 0x81, 0x3b, 0x39, 0xe7, 0xc4, 0x00, 0x39, + 0x93, 0xcf, 0x24, 0x39, 0xa4, 0x08, 0x18, 0x39, 0xa9, 0xa7, 0x5f, 0x39, 0x70, + 0xad, 0x8b, 0x39, 0x8c, 0xa8, 0x7c, 0x39, 0x9e, 0x62, 0x85, 0x39, 0x26, 0x5a, + 0x54, 0x39, 0xfc, 0x19, 0x0d, 0x39, 0x66, 0x93, 0x06, 0x39, 0x5c, 0x72, 0x7e, + 0x39, 0xde, 0x33, 0xf3, 0x38, 0x1e, 0x7d, 0x42, 0x39, 0x73, 0xfb, 0x46, 0x39, + 0x9a, 0x5f, 0x96, 0x39, 0x9c, 0xf5, 0x80, 0x39, 0x92, 0x05, 0x2a, 0x39, 0x64, + 0x49, 0x2e, 0x39, 0xcf, 0xb0, 0x3c, 0x39, 0x6e, 0x23, 0x41, 0x39, 0x46, 0xda, + 0x63, 0x39, 0xde, 0x7d, 0x7f, 0x39, 0x2c, 0x55, 0x5c, 0x39, 0xc0, 0x05, 0x29, + 0x39, 0xdf, 0xf3, 0x44, 0x39, 0xba, 0x41, 0x06, 0x39, 0xe5, 0x32, 0x7a, 0x39, + 0xee, 0xf3, 0x67, 0x39, 0x0c, 0x2d, 0x49, 0x39, 0xf7, 0x67, 0x7f, 0x39, 0x86, + 0x07, 0x3b, 0x39, 0x94, 0x91, 0x50, 0x39, 0x8a, 0xc6, 0x32, 0x39, 0x20, 0x3b, + 0x17, 0x39, 0x77, 0xba, 0x46, 0x39, 0x53, 0xe6, 0x58, 0x39, 0x2a, 0x2e, 0x9f, + 0x39, 0x08, 0x04, 0x5a, 0x39, 0x02, 0xc9, 0x2c, 0x39, 0x9e, 0x69, 0x6e, 0x39, + 0x42, 0xac, 0x92, 0x39, 0xb7, 0xa2, 0x17, 0x39, 0x1b, 0x22, 0x7f, 0x39, 0x59, + 0x99, 0x24, 0x39, 0x8c, 0xee, 0x42, 0x39, 0x79, 0xb6, 0x2a, 0x39, 0x41, 0xef, + 0x78, 0x39, 0xad, 0x11, 0x25, 0x39, 0x55, 0x23, 0x07, 0x39, 0x13, 0xd7, 0x38, + 0x39, 0x6e, 0xff, 0x5f, 0x39, 0x80, 0x41, 0x7f, 0x39, 0x58, 0xd1, 0x52, 0x39, + 0x4a, 0x08, 0x74, 0x39, 0x7a, 0xa0, 0x64, 0x39, 0xc1, 0x91, 0x66, 0x39, 0xbe, + 0x37, 0x6e, 0x39, 0xb9, 0xa4, 0x32, 0x39, 0x67, 0x88, 0x00, 0x39, 0xb8, 0xeb, + 0x56, 0x39, 0xec, 0x29, 0x15, 0x39, 0xec, 0x57, 0x40, 0x39, 0x3a, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x52, 0x44, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, + 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0xec, 0xca, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, + 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x33, 0x5f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf2, 0x44, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xcb, 0xff, 0xff, 0x30, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x31, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x32, 0x5f, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, + 0x75, 0x36, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x92, + 0x45, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x0c, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x4c, 0xff, + 0xff, 0x10, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x5e, 0xab, 0x58, 0x38, 0x1b, 0x09, 0x10, 0x38, 0x76, 0x32, 0x30, + 0x38, 0xb8, 0xde, 0x27, 0x38, 0xe2, 0x95, 0x9b, 0x38, 0xac, 0xeb, 0x28, 0x38, + 0x59, 0xcd, 0x7f, 0x38, 0xfb, 0xe1, 0x81, 0x38, 0x42, 0x88, 0x30, 0x38, 0x21, + 0x9e, 0x49, 0x38, 0x15, 0x51, 0x46, 0x38, 0x57, 0xbd, 0x3e, 0x38, 0x2f, 0xbe, + 0x17, 0x38, 0xdc, 0x57, 0x53, 0x38, 0xae, 0xf1, 0xa4, 0x38, 0x12, 0xd3, 0x64, + 0x38, 0x91, 0x27, 0x7a, 0x38, 0xf3, 0x6c, 0x14, 0x38, 0x97, 0x6f, 0x4a, 0x38, + 0x8b, 0xcb, 0x48, 0x38, 0x08, 0xfb, 0x82, 0x38, 0x3f, 0x07, 0x44, 0x38, 0xdb, + 0xb2, 0x3a, 0x38, 0x27, 0xbd, 0x26, 0x38, 0xde, 0xeb, 0x56, 0x38, 0x6a, 0x0a, + 0x7d, 0x38, 0x79, 0x0c, 0x58, 0x38, 0x98, 0x0d, 0x79, 0x38, 0x22, 0x01, 0x2f, + 0x38, 0xaa, 0x72, 0x46, 0x38, 0x91, 0x50, 0x07, 0x38, 0xea, 0xe2, 0x68, 0x38, + 0x14, 0x55, 0x53, 0x38, 0x32, 0xe4, 0x4b, 0x38, 0x9b, 0x92, 0x0f, 0x38, 0xf7, + 0xef, 0x3c, 0x38, 0x62, 0x4e, 0xa8, 0x38, 0x67, 0x90, 0x3c, 0x38, 0x05, 0xdf, + 0x14, 0x38, 0x3a, 0x8e, 0x7d, 0x38, 0x32, 0x6c, 0x7f, 0x38, 0x05, 0x40, 0x4b, + 0x38, 0x85, 0x4e, 0x46, 0x38, 0xbe, 0x73, 0x26, 0x38, 0xf9, 0x5d, 0x36, 0x38, + 0x8a, 0x30, 0x3d, 0x38, 0x3c, 0x9b, 0x2c, 0x38, 0x6a, 0x3b, 0x2c, 0x38, 0xe1, + 0x38, 0x89, 0x38, 0xdf, 0x1e, 0x5c, 0x38, 0x11, 0x07, 0x4f, 0x38, 0x08, 0x26, + 0x15, 0x38, 0x92, 0x27, 0x75, 0x38, 0xcf, 0x76, 0x3a, 0x38, 0x14, 0x13, 0x55, + 0x38, 0x64, 0x30, 0x53, 0x38, 0x4d, 0x19, 0x75, 0x38, 0xea, 0x65, 0x3d, 0x38, + 0xe5, 0x0c, 0x1d, 0x38, 0xc0, 0xb7, 0x4a, 0x38, 0x9f, 0xc4, 0x1c, 0x38, 0x38, + 0xae, 0x72, 0x38, 0x00, 0xba, 0x11, 0x38, 0xc9, 0xb0, 0x54, 0x38, 0x51, 0xb9, + 0x83, 0x38, 0x30, 0xf6, 0x57, 0x38, 0x2f, 0x3b, 0x4f, 0x38, 0xe4, 0x2f, 0x58, + 0x38, 0x59, 0xec, 0x16, 0x38, 0xf4, 0x06, 0x4a, 0x38, 0x8e, 0x81, 0x41, 0x38, + 0x30, 0x10, 0x40, 0x38, 0xb3, 0xfd, 0x95, 0x38, 0xa9, 0xfa, 0x49, 0x38, 0xcd, + 0x4f, 0x45, 0x38, 0x48, 0x3e, 0x22, 0x38, 0x5b, 0xb5, 0x5e, 0x38, 0x80, 0x22, + 0x44, 0x38, 0x02, 0x38, 0x78, 0x38, 0xfc, 0x94, 0xef, 0x38, 0xc1, 0xab, 0x95, + 0x38, 0xfc, 0x35, 0x17, 0x38, 0xcd, 0xd4, 0x6d, 0x38, 0xa0, 0xed, 0xe6, 0x37, + 0x17, 0xfc, 0x26, 0x38, 0x9a, 0x2a, 0xdd, 0x37, 0x00, 0x2a, 0x6e, 0x38, 0xc3, + 0xcf, 0x97, 0x38, 0x4b, 0x50, 0x1a, 0x38, 0x34, 0xe2, 0x78, 0x38, 0x65, 0x83, + 0x76, 0x38, 0xff, 0xf5, 0x8f, 0x38, 0x00, 0x75, 0x4c, 0x38, 0xed, 0x8f, 0x8a, + 0x38, 0xa4, 0x3f, 0x6c, 0x38, 0x32, 0x37, 0x66, 0x38, 0xb9, 0xa6, 0x40, 0x38, + 0x6f, 0x8b, 0x40, 0x38, 0xea, 0x25, 0x5f, 0x38, 0x8c, 0xbb, 0x52, 0x38, 0x1e, + 0x92, 0x4d, 0x38, 0x64, 0xda, 0x51, 0x38, 0xb2, 0xc2, 0x16, 0x38, 0xa6, 0x8a, + 0x2f, 0x38, 0x8b, 0x23, 0x58, 0x38, 0x9d, 0x86, 0x4c, 0x38, 0x39, 0xd1, 0x24, + 0x38, 0x59, 0x2d, 0x2d, 0x38, 0xdd, 0x33, 0x92, 0x38, 0x39, 0xe8, 0x28, 0x38, + 0xc6, 0x34, 0x57, 0x38, 0x16, 0xd8, 0x2d, 0x38, 0x44, 0x45, 0x63, 0x38, 0x12, + 0x10, 0x9b, 0x38, 0xf7, 0x0b, 0x05, 0x38, 0xae, 0x23, 0x35, 0x38, 0xd5, 0xd1, + 0x96, 0x38, 0xfd, 0xf5, 0x81, 0x38, 0x0b, 0x99, 0x71, 0x38, 0xd5, 0xae, 0x7e, + 0x38, 0xb0, 0x03, 0x50, 0x38, 0xff, 0x6c, 0x70, 0x38, 0xbd, 0xeb, 0x23, 0x38, + 0xce, 0xd1, 0x33, 0x38, 0x27, 0xe9, 0x3f, 0x38, 0x94, 0xc7, 0x39, 0x38, 0x1c, + 0x36, 0x22, 0x38, 0xb0, 0x96, 0x37, 0x38, 0x2e, 0x1b, 0x24, 0x38, 0xa6, 0x99, + 0x53, 0x38, 0x89, 0x1b, 0x3e, 0x38, 0x4d, 0x3d, 0x65, 0x38, 0x82, 0xda, 0x30, + 0x38, 0x7f, 0xe9, 0x47, 0x38, 0xe8, 0xd4, 0xa1, 0x38, 0xc1, 0x4b, 0x2f, 0x38, + 0x68, 0x9d, 0x48, 0x38, 0x62, 0xfb, 0x09, 0x38, 0xa7, 0x96, 0xff, 0x37, 0xb3, + 0x52, 0x43, 0x38, 0x3f, 0x5f, 0x2a, 0x38, 0x08, 0x03, 0x76, 0x38, 0x11, 0x90, + 0x2d, 0x38, 0xed, 0x50, 0x4f, 0x38, 0x46, 0xf5, 0x75, 0x38, 0x73, 0xd3, 0x8e, + 0x38, 0x4a, 0x4a, 0x84, 0x38, 0xaf, 0xdc, 0x82, 0x38, 0x77, 0xda, 0x24, 0x38, + 0x5e, 0x8b, 0x45, 0x38, 0x6e, 0x38, 0x4a, 0x38, 0x12, 0x5b, 0x3c, 0x38, 0x7c, + 0x27, 0x68, 0x38, 0x77, 0x4e, 0x0f, 0x38, 0xb6, 0x1d, 0x5c, 0x38, 0xa2, 0x68, + 0x9c, 0x38, 0x32, 0x4e, 0x5c, 0x38, 0xa4, 0xeb, 0x6b, 0x38, 0xfa, 0x00, 0x69, + 0x38, 0xe1, 0xb9, 0x5a, 0x38, 0xe2, 0xa4, 0x57, 0x38, 0xb3, 0x7c, 0x4e, 0x38, + 0xef, 0x33, 0x32, 0x38, 0x6b, 0x57, 0x08, 0x38, 0x25, 0xf4, 0x2b, 0x38, 0x26, + 0x3a, 0x74, 0x38, 0xc7, 0x13, 0x74, 0x38, 0x1f, 0x16, 0x82, 0x38, 0x27, 0x5f, + 0x21, 0x38, 0xbe, 0x7b, 0x7d, 0x38, 0x7b, 0x58, 0x98, 0x38, 0xe7, 0x8b, 0x95, + 0x38, 0x4f, 0xd2, 0x3c, 0x38, 0xdb, 0x19, 0x3f, 0x38, 0x06, 0xed, 0x7d, 0x38, + 0x75, 0x64, 0x2a, 0x38, 0xcf, 0x6a, 0x56, 0x38, 0x32, 0x2a, 0x39, 0x38, 0xb3, + 0xd9, 0x4d, 0x38, 0x8f, 0xe5, 0x79, 0x38, 0x20, 0xf9, 0x4a, 0x38, 0x9b, 0x1b, + 0x4f, 0x38, 0xa1, 0xbf, 0x9e, 0x38, 0xa5, 0x73, 0x3a, 0x38, 0x33, 0xe8, 0x34, + 0x38, 0xbb, 0x0b, 0x3b, 0x38, 0x8b, 0xbd, 0x42, 0x38, 0xc6, 0x6b, 0x38, 0x38, + 0x80, 0x3c, 0x52, 0x38, 0x18, 0xd2, 0x8b, 0x38, 0x2e, 0x63, 0x40, 0x38, 0x07, + 0x07, 0x3d, 0x38, 0xb8, 0x65, 0x5a, 0x38, 0xa2, 0x62, 0x11, 0x38, 0x44, 0x30, + 0x4b, 0x38, 0x7c, 0xf0, 0x4c, 0x38, 0x5b, 0xf6, 0x3d, 0x38, 0x2f, 0x0b, 0x84, + 0x38, 0xc7, 0xb6, 0x77, 0x38, 0x7c, 0x0e, 0x82, 0x38, 0x3e, 0x69, 0x6a, 0x38, + 0x80, 0x1a, 0x62, 0x38, 0x55, 0x09, 0x7f, 0x38, 0x05, 0x5b, 0x89, 0x38, 0xbf, + 0xa8, 0x10, 0x38, 0xac, 0x94, 0x86, 0x38, 0x84, 0xe1, 0x39, 0x38, 0xcd, 0xe1, + 0x6c, 0x38, 0x44, 0xc8, 0x6d, 0x38, 0xb5, 0x9e, 0x32, 0x38, 0xb0, 0x68, 0x71, + 0x38, 0x58, 0x21, 0x1f, 0x38, 0x68, 0x40, 0x4a, 0x38, 0xb5, 0x63, 0x7e, 0x38, + 0x51, 0x7d, 0x25, 0x38, 0x76, 0x9f, 0x4e, 0x38, 0xc6, 0x16, 0x7e, 0x38, 0x82, + 0x8f, 0x41, 0x38, 0xbe, 0x2b, 0x58, 0x38, 0xe2, 0x0c, 0x5e, 0x38, 0xff, 0xba, + 0x83, 0x38, 0xf0, 0x81, 0x99, 0x38, 0x97, 0x78, 0x4f, 0x38, 0x44, 0x39, 0x51, + 0x38, 0x49, 0xee, 0x6f, 0x38, 0x32, 0xce, 0x0c, 0x38, 0x67, 0x24, 0x2f, 0x38, + 0xde, 0xb2, 0x52, 0x38, 0xad, 0x9c, 0x36, 0x38, 0x03, 0x36, 0x23, 0x38, 0x55, + 0x22, 0x60, 0x38, 0x68, 0xd0, 0x87, 0x38, 0x77, 0x81, 0x41, 0x38, 0x0b, 0xc1, + 0x4c, 0x38, 0x41, 0xfd, 0x7a, 0x38, 0x32, 0x30, 0x24, 0x38, 0x0c, 0xca, 0x24, + 0x38, 0xb9, 0xa1, 0x48, 0x38, 0x92, 0x65, 0x73, 0x38, 0x20, 0x5f, 0x55, 0x38, + 0xdb, 0xe4, 0x2a, 0x38, 0x86, 0x64, 0x13, 0x38, 0x71, 0x46, 0x5a, 0x38, 0x3e, + 0x8c, 0x96, 0x38, 0x09, 0xa2, 0x35, 0x38, 0x49, 0x97, 0x71, 0x38, 0x38, 0xd5, + 0x4b, 0x38, 0xd9, 0xfc, 0x5a, 0x38, 0x7a, 0xbd, 0x73, 0x38, 0xba, 0x91, 0x8a, + 0x38, 0xcc, 0x88, 0x54, 0x38, 0xaa, 0xbe, 0x3f, 0x38, 0x39, 0xe4, 0x2d, 0x38, + 0x47, 0x27, 0x4a, 0x38, 0x22, 0xc9, 0x98, 0x38, 0x3c, 0x45, 0x93, 0x38, 0x37, + 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x32, 0x5f, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x06, 0x52, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x06, 0x00, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x62, 0x4b, 0xff, 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xaf, + 0xee, 0x04, 0x39, 0x1a, 0x2d, 0xe1, 0x38, 0xcd, 0x5c, 0x4a, 0x39, 0x9e, 0x09, + 0x23, 0x39, 0x24, 0x90, 0x63, 0x39, 0x5e, 0x18, 0xd8, 0x38, 0x4f, 0x1f, 0x02, + 0x39, 0x8f, 0x4d, 0x25, 0x39, 0xb8, 0x22, 0xe3, 0x38, 0xbb, 0xb9, 0x51, 0x39, + 0x64, 0x85, 0x10, 0x39, 0xfc, 0xae, 0xee, 0x38, 0x6d, 0x49, 0x23, 0x39, 0x77, + 0xdd, 0x05, 0x39, 0xac, 0xbd, 0xfc, 0x38, 0xfc, 0x0d, 0x1b, 0x39, 0x8f, 0xdc, + 0x65, 0x39, 0x40, 0xf4, 0x2c, 0x39, 0x34, 0xb4, 0x0b, 0x39, 0xc5, 0x81, 0x01, + 0x39, 0xbe, 0xfd, 0x06, 0x39, 0x4c, 0xa1, 0xe8, 0x38, 0x53, 0xb2, 0x25, 0x39, + 0xcb, 0x38, 0x0b, 0x39, 0x73, 0x8a, 0xce, 0x38, 0x69, 0xdc, 0x28, 0x39, 0x95, + 0x30, 0x0e, 0x39, 0xee, 0x53, 0xdd, 0x38, 0x1a, 0x2f, 0x33, 0x39, 0xbf, 0x3e, + 0x1e, 0x39, 0x45, 0x1b, 0x1e, 0x39, 0x12, 0x7d, 0x3e, 0x39, 0x16, 0x99, 0x24, + 0x39, 0x2a, 0xbc, 0x36, 0x39, 0xa1, 0x90, 0x05, 0x39, 0xbe, 0x5a, 0x33, 0x39, + 0x74, 0x39, 0x2d, 0x39, 0x1b, 0xc8, 0xbe, 0x38, 0x73, 0xbe, 0xda, 0x38, 0xff, + 0x96, 0x5e, 0x39, 0xb8, 0xdb, 0xc5, 0x38, 0x08, 0x9c, 0x74, 0x39, 0x5c, 0x88, + 0x46, 0x39, 0x2f, 0x30, 0x12, 0x39, 0xe2, 0x1a, 0xff, 0x38, 0xf5, 0x05, 0x12, + 0x39, 0xd8, 0x56, 0xed, 0x38, 0xee, 0xd7, 0x53, 0x39, 0xf4, 0x60, 0xfa, 0x38, + 0x44, 0x47, 0xfc, 0x38, 0x65, 0x71, 0xf3, 0x38, 0x7d, 0x30, 0xdc, 0x38, 0x8c, + 0xb8, 0x2e, 0x39, 0x7a, 0x16, 0x40, 0x39, 0x1f, 0x90, 0x29, 0x39, 0xf5, 0x2a, + 0x39, 0x39, 0x15, 0x22, 0xde, 0x38, 0x49, 0x46, 0x28, 0x39, 0x24, 0x4d, 0xc1, + 0x38, 0x9a, 0x81, 0x05, 0x39, 0xb0, 0xfd, 0x31, 0x39, 0x87, 0x96, 0x35, 0x39, + 0xfd, 0x04, 0x14, 0x39, 0x56, 0x18, 0xce, 0x38, 0xe7, 0x38, 0x04, 0x39, 0x89, + 0x3d, 0x2d, 0x39, 0xad, 0x29, 0xe1, 0x38, 0x89, 0x83, 0x17, 0x39, 0xa7, 0x0c, + 0x16, 0x39, 0x41, 0x56, 0x4d, 0x39, 0x04, 0x5a, 0x0f, 0x39, 0x6d, 0x76, 0xd5, + 0x38, 0x6a, 0xbd, 0x03, 0x39, 0x8e, 0x29, 0xdd, 0x38, 0xa9, 0x07, 0x09, 0x39, + 0x75, 0x72, 0x02, 0x39, 0x9b, 0x42, 0xb7, 0x38, 0x42, 0x41, 0x03, 0x39, 0xbc, + 0xb7, 0x1e, 0x39, 0x2c, 0xaa, 0xf1, 0x38, 0xaf, 0xed, 0x1f, 0x39, 0x8c, 0xe9, + 0x3d, 0x39, 0x4f, 0xae, 0x02, 0x39, 0xb3, 0x70, 0x19, 0x39, 0x78, 0xa2, 0x37, + 0x39, 0xcf, 0xbf, 0x24, 0x39, 0x11, 0x48, 0x2a, 0x39, 0x88, 0xc4, 0x09, 0x39, + 0xb8, 0x9c, 0x61, 0x39, 0x2a, 0xbb, 0x2d, 0x39, 0x4d, 0x46, 0xb3, 0x38, 0x2c, + 0xb1, 0x2f, 0x39, 0x3b, 0xb2, 0x5c, 0x39, 0x68, 0x02, 0x0b, 0x39, 0xac, 0x5f, + 0x0e, 0x39, 0x97, 0x49, 0x52, 0x39, 0x5b, 0x3c, 0xf5, 0x38, 0x9c, 0x54, 0x14, + 0x39, 0xa5, 0x79, 0x19, 0x39, 0x05, 0x86, 0xf3, 0x38, 0x98, 0xb5, 0x4e, 0x39, + 0xeb, 0x2d, 0x65, 0x39, 0x64, 0xe8, 0x74, 0x39, 0x2c, 0xf8, 0xf9, 0x38, 0x76, + 0x51, 0x20, 0x39, 0x6d, 0xf2, 0xf9, 0x38, 0x23, 0xa2, 0x4d, 0x39, 0xb9, 0xfe, + 0x14, 0x39, 0xcc, 0x69, 0x09, 0x39, 0xa2, 0x12, 0x85, 0x39, 0x09, 0x0a, 0x39, + 0x39, 0xc0, 0xa2, 0xf4, 0x38, 0x3e, 0x22, 0x19, 0x39, 0xa1, 0x25, 0x0e, 0x39, + 0x1b, 0xf8, 0x13, 0x39, 0x19, 0x29, 0x16, 0x39, 0xa0, 0x37, 0x5e, 0x39, 0x24, + 0x0b, 0x1c, 0x39, 0x9d, 0x0b, 0xce, 0x38, 0x1b, 0x8f, 0xe9, 0x38, 0xd7, 0x0e, + 0x26, 0x39, 0x18, 0x13, 0xc2, 0x38, 0x5a, 0xb2, 0x07, 0x39, 0xe5, 0xa3, 0x74, + 0x39, 0x15, 0x8b, 0x99, 0x38, 0x37, 0xae, 0xfe, 0x38, 0x85, 0x31, 0x53, 0x39, + 0x73, 0x9b, 0x49, 0x39, 0x3a, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x31, 0x32, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, + 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x82, 0x58, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0xff, 0xff, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, + 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x31, 0x32, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x22, 0x59, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, + 0x00, 0x26, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xbc, 0xdf, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x31, 0x31, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, + 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xc2, 0x59, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x02, 0x64, 0x06, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x44, 0x60, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x69, + 0x47, 0x9f, 0x38, 0x5b, 0xf0, 0x8b, 0x38, 0xaa, 0xcd, 0x9a, 0x38, 0x40, 0x1d, + 0x5d, 0x38, 0x15, 0xe3, 0x78, 0x38, 0xdb, 0x22, 0x2f, 0x38, 0xb7, 0xfc, 0x7c, + 0x38, 0x05, 0xdd, 0x4b, 0x38, 0x70, 0xd6, 0x56, 0x38, 0xfd, 0x3d, 0x4a, 0x38, + 0x70, 0xb2, 0x4d, 0x38, 0x21, 0xe6, 0x7e, 0x38, 0x51, 0xa8, 0x8b, 0x38, 0x00, + 0x8f, 0x43, 0x38, 0x02, 0xd3, 0x73, 0x38, 0x4c, 0x13, 0x44, 0x38, 0x1e, 0x6c, + 0xa3, 0x38, 0xa9, 0x97, 0x88, 0x38, 0x5b, 0x0c, 0x3e, 0x38, 0xf6, 0x0a, 0x6a, + 0x38, 0x1a, 0x32, 0x71, 0x38, 0x05, 0xfb, 0x42, 0x38, 0x7d, 0x9d, 0x57, 0x38, + 0x1e, 0x05, 0x7c, 0x38, 0x9b, 0x6e, 0x9b, 0x38, 0xe5, 0x57, 0x55, 0x38, 0x15, + 0xcd, 0x74, 0x38, 0x79, 0xb9, 0x82, 0x38, 0x9a, 0x43, 0x30, 0x38, 0xa6, 0xd0, + 0x75, 0x38, 0xba, 0x21, 0x79, 0x38, 0x85, 0x96, 0x5f, 0x38, 0x89, 0xcb, 0x5d, + 0x38, 0xee, 0xb0, 0x90, 0x38, 0x39, 0xf4, 0x8c, 0x38, 0x98, 0xf8, 0x3a, 0x38, + 0x85, 0x5f, 0x65, 0x38, 0x93, 0x54, 0x39, 0x38, 0xf6, 0xa8, 0x77, 0x38, 0xb8, + 0xa7, 0x58, 0x38, 0x38, 0x90, 0x54, 0x38, 0x66, 0x29, 0x8a, 0x38, 0xbb, 0xbe, + 0x59, 0x38, 0x69, 0x3f, 0x85, 0x38, 0x96, 0x0d, 0xaa, 0x38, 0x2b, 0x8d, 0x98, + 0x38, 0x0b, 0x19, 0x57, 0x38, 0x14, 0x47, 0x7c, 0x38, 0xe1, 0x06, 0x91, 0x38, + 0xaa, 0x54, 0x72, 0x38, 0xaa, 0x43, 0x4b, 0x38, 0x24, 0x3a, 0x55, 0x38, 0xad, + 0xc2, 0x45, 0x38, 0x38, 0xd2, 0x6c, 0x38, 0x21, 0x95, 0x43, 0x38, 0xd6, 0x2d, + 0x5f, 0x38, 0x6b, 0x28, 0xaa, 0x38, 0x59, 0xf8, 0x56, 0x38, 0x3d, 0xa1, 0x72, + 0x38, 0xcf, 0x5e, 0x46, 0x38, 0x98, 0x72, 0x64, 0x38, 0x59, 0xb0, 0x82, 0x38, + 0x93, 0x97, 0x89, 0x38, 0x94, 0x0b, 0x71, 0x38, 0x68, 0x1e, 0x9e, 0x38, 0x4f, + 0x79, 0x6b, 0x38, 0x64, 0x7c, 0x71, 0x38, 0x5c, 0x15, 0x69, 0x38, 0x5c, 0x37, + 0x82, 0x38, 0xbb, 0x01, 0x5e, 0x38, 0x38, 0x98, 0x3c, 0x38, 0x40, 0xc6, 0x59, + 0x38, 0xa7, 0x14, 0x57, 0x38, 0xa7, 0xad, 0x8f, 0x38, 0x1a, 0xc8, 0x51, 0x38, + 0x30, 0x3a, 0x6b, 0x38, 0x18, 0xbd, 0x2f, 0x38, 0x27, 0x7e, 0x34, 0x38, 0x24, + 0xe2, 0x84, 0x38, 0x5c, 0x2c, 0x74, 0x38, 0xfd, 0xc7, 0xc2, 0x38, 0xe7, 0xfd, + 0xb9, 0x38, 0x1a, 0x1c, 0x75, 0x38, 0x07, 0x09, 0x86, 0x38, 0x1b, 0x05, 0x4b, + 0x38, 0x4f, 0xc3, 0x5a, 0x38, 0xbc, 0x2c, 0x36, 0x38, 0x17, 0x0d, 0x45, 0x38, + 0xb3, 0x8a, 0x92, 0x38, 0x30, 0x8f, 0x94, 0x38, 0x79, 0xf2, 0x53, 0x38, 0x2c, + 0x41, 0x95, 0x38, 0x57, 0x91, 0x8f, 0x38, 0x46, 0x02, 0x4b, 0x38, 0xd0, 0xaa, + 0x2d, 0x38, 0xe4, 0x49, 0x5a, 0x38, 0xf2, 0xaa, 0x37, 0x38, 0x02, 0x5e, 0x5a, + 0x38, 0x30, 0x54, 0x40, 0x38, 0x44, 0xbc, 0xb3, 0x38, 0xe7, 0x64, 0x79, 0x38, + 0xe5, 0x9f, 0x78, 0x38, 0x9c, 0x06, 0x88, 0x38, 0x2d, 0x40, 0x77, 0x38, 0x82, + 0x16, 0x2f, 0x38, 0xce, 0xd7, 0x8c, 0x38, 0x11, 0x5a, 0x54, 0x38, 0xa5, 0x49, + 0x8a, 0x38, 0xa3, 0x55, 0x6f, 0x38, 0x39, 0xb9, 0x4d, 0x38, 0xcb, 0x17, 0x85, + 0x38, 0x20, 0xec, 0x5f, 0x38, 0xe8, 0x9c, 0x7f, 0x38, 0x12, 0xe5, 0x55, 0x38, + 0xcc, 0xb5, 0x6b, 0x38, 0xc3, 0xa4, 0x6c, 0x38, 0x2e, 0x80, 0x87, 0x38, 0xb6, + 0x54, 0x47, 0x38, 0xfd, 0x78, 0x88, 0x38, 0xca, 0x4d, 0x62, 0x38, 0x88, 0x90, + 0x74, 0x38, 0xf6, 0xe1, 0x42, 0x38, 0x0b, 0x9f, 0x55, 0x38, 0xfb, 0xe5, 0x94, + 0x38, 0x2c, 0x57, 0x49, 0x38, 0x58, 0xdf, 0x76, 0x38, 0x7f, 0x56, 0x9a, 0x38, + 0x80, 0x6d, 0x6d, 0x38, 0x37, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x31, 0x31, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x36, 0x60, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x02, 0x6c, 0x06, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x92, 0x59, 0xff, 0xff, 0x14, 0x04, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xa6, 0x5d, 0x16, 0x39, 0x80, 0xca, 0x26, 0x39, 0x1d, + 0x38, 0x4e, 0x39, 0x85, 0x11, 0x0e, 0x39, 0x7a, 0xb2, 0xf1, 0x38, 0xe4, 0x71, + 0xf9, 0x38, 0xf8, 0xbb, 0x22, 0x39, 0x83, 0xfe, 0x50, 0x39, 0xa7, 0x56, 0x2a, + 0x39, 0x64, 0xa7, 0x64, 0x39, 0xc3, 0x88, 0x5f, 0x39, 0xe8, 0x19, 0x12, 0x39, + 0x73, 0xa6, 0x46, 0x39, 0x32, 0xc1, 0x7c, 0x39, 0xfc, 0x05, 0x25, 0x39, 0x2c, + 0x83, 0xdd, 0x38, 0x09, 0x83, 0x3f, 0x39, 0x1a, 0xee, 0xf2, 0x38, 0xca, 0x53, + 0xff, 0x38, 0x98, 0xc7, 0x8a, 0x38, 0x3c, 0x4e, 0x0a, 0x39, 0xbb, 0xe2, 0x2a, + 0x39, 0x73, 0x31, 0xa6, 0x38, 0xba, 0x18, 0x16, 0x39, 0x16, 0x5c, 0x26, 0x39, + 0x16, 0x0f, 0x23, 0x39, 0x9d, 0x2c, 0x7a, 0x39, 0xed, 0x6f, 0x80, 0x39, 0xfd, + 0xae, 0x61, 0x39, 0xb5, 0xd3, 0x56, 0x39, 0x52, 0xe0, 0xaa, 0x38, 0x71, 0x4c, + 0x34, 0x39, 0x86, 0x28, 0x3a, 0x39, 0xff, 0xb9, 0x3d, 0x39, 0x86, 0x87, 0xff, + 0x38, 0x5b, 0xb7, 0x33, 0x39, 0x6e, 0x8a, 0xdc, 0x38, 0xd8, 0xfa, 0x17, 0x39, + 0xfa, 0x05, 0x9b, 0x39, 0x54, 0x55, 0x03, 0x39, 0x2e, 0x3e, 0x38, 0x39, 0x55, + 0xe2, 0x58, 0x39, 0x6b, 0x3d, 0x7a, 0x39, 0xa9, 0xf1, 0x01, 0x39, 0xc4, 0x32, + 0xd8, 0x38, 0x2f, 0xa2, 0xe2, 0x38, 0x64, 0x41, 0x24, 0x39, 0x74, 0x1a, 0x21, + 0x39, 0x02, 0x5f, 0x36, 0x39, 0x27, 0x2b, 0x03, 0x39, 0xfc, 0xdf, 0xf0, 0x38, + 0x63, 0xa1, 0x31, 0x39, 0x45, 0x79, 0x16, 0x39, 0xd8, 0x1d, 0x39, 0x39, 0x72, + 0x33, 0x1b, 0x39, 0xe9, 0x8d, 0x85, 0x39, 0xcd, 0xf4, 0x07, 0x39, 0x30, 0x96, + 0x60, 0x39, 0x2d, 0x4a, 0x36, 0x39, 0x73, 0xac, 0x17, 0x39, 0x8f, 0x96, 0x04, + 0x39, 0xe0, 0xe9, 0x14, 0x39, 0x02, 0xd8, 0x74, 0x39, 0xd3, 0x31, 0x3b, 0x39, + 0xc6, 0x17, 0x61, 0x39, 0x47, 0xbf, 0x00, 0x39, 0x3b, 0x76, 0xf1, 0x38, 0x1b, + 0x81, 0xeb, 0x38, 0xd8, 0xf2, 0xf8, 0x38, 0xbd, 0xd6, 0x2a, 0x39, 0x99, 0x29, + 0x23, 0x39, 0xa7, 0x7a, 0x10, 0x39, 0x7d, 0x22, 0x30, 0x39, 0x9b, 0xd2, 0xf2, + 0x38, 0xfd, 0x0b, 0x16, 0x39, 0x88, 0xd2, 0x14, 0x39, 0x0c, 0x47, 0x46, 0x39, + 0x25, 0x27, 0x35, 0x39, 0xed, 0xda, 0x4c, 0x39, 0x61, 0xa7, 0x3d, 0x39, 0x47, + 0xde, 0xfb, 0x38, 0x92, 0x79, 0xf0, 0x38, 0x33, 0x22, 0x1d, 0x39, 0xe0, 0x77, + 0xb5, 0x38, 0xcc, 0x41, 0x13, 0x39, 0x32, 0xe3, 0x24, 0x39, 0xef, 0xfb, 0x3c, + 0x39, 0x18, 0x5d, 0x89, 0x39, 0xed, 0xb6, 0x31, 0x39, 0x80, 0xf8, 0xdc, 0x38, + 0xde, 0xc0, 0x61, 0x39, 0xab, 0x1b, 0x1d, 0x39, 0xd7, 0xde, 0x3a, 0x39, 0x2b, + 0xa0, 0x80, 0x39, 0x9b, 0xbf, 0x6f, 0x39, 0xa3, 0x07, 0x82, 0x39, 0x11, 0xa3, + 0x68, 0x39, 0x0d, 0x4d, 0x28, 0x39, 0x37, 0xf5, 0xe5, 0x38, 0xe2, 0x07, 0x1d, + 0x39, 0x22, 0xe9, 0x2b, 0x39, 0x64, 0x6d, 0xdc, 0x38, 0xe7, 0xfb, 0x96, 0x38, + 0xa9, 0x83, 0x2e, 0x39, 0xce, 0x74, 0x31, 0x39, 0xa4, 0xab, 0x71, 0x39, 0xf6, + 0xbc, 0x3b, 0x39, 0xb8, 0x99, 0x7f, 0x39, 0xa7, 0xd0, 0x18, 0x39, 0x3b, 0x6e, + 0x5f, 0x39, 0x35, 0x63, 0xd0, 0x38, 0x92, 0xbf, 0xf0, 0x38, 0x99, 0x14, 0x40, + 0x39, 0x36, 0xed, 0x0d, 0x39, 0x67, 0x31, 0x17, 0x39, 0x3e, 0x94, 0x28, 0x39, + 0x57, 0x94, 0x17, 0x39, 0x1e, 0x64, 0x11, 0x39, 0x73, 0x4a, 0x72, 0x39, 0xa7, + 0xf6, 0x39, 0x39, 0x73, 0xd8, 0x35, 0x39, 0xc5, 0x95, 0x1a, 0x39, 0x01, 0xa4, + 0x07, 0x39, 0x15, 0x2b, 0x2f, 0x39, 0xcf, 0xa3, 0x5c, 0x39, 0x98, 0xfc, 0x71, + 0x39, 0x66, 0xc2, 0x88, 0x39, 0xc0, 0xba, 0x55, 0x39, 0x3a, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x31, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, + 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0xb2, 0x66, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x84, 0x00, + 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x4c, 0xed, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x31, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x52, 0x67, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0xec, 0xed, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x30, 0x5f, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, 0x75, + 0x36, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf2, 0x67, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x64, 0x06, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x74, 0x6e, 0xff, 0xff, + 0x10, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x0f, 0xdb, 0x81, 0x38, 0x9a, 0x27, 0x6e, 0x38, 0xf4, + 0x34, 0x6d, 0x38, 0xd5, 0x59, 0x5c, 0x38, 0xfa, 0x44, 0x57, 0x38, 0x7d, 0xe6, + 0x46, 0x38, 0xc9, 0xad, 0x3f, 0x38, 0xcc, 0x17, 0x2a, 0x38, 0xc3, 0x1f, 0x69, + 0x38, 0x5a, 0x69, 0x85, 0x38, 0xa7, 0xd6, 0xad, 0x38, 0xd1, 0x8d, 0x8a, 0x38, + 0x68, 0xae, 0x66, 0x38, 0xeb, 0xdf, 0x6a, 0x38, 0x20, 0x8b, 0x56, 0x38, 0x3c, + 0x9c, 0x91, 0x38, 0x20, 0xc1, 0x8e, 0x38, 0x56, 0x75, 0x5d, 0x38, 0xb0, 0x8a, + 0x82, 0x38, 0xd1, 0xe7, 0x87, 0x38, 0xa7, 0xbf, 0x82, 0x38, 0x8b, 0xf8, 0xa1, + 0x38, 0x6e, 0x1e, 0x6c, 0x38, 0xbb, 0x19, 0x7f, 0x38, 0x32, 0xb7, 0x7a, 0x38, + 0xb2, 0x5a, 0x75, 0x38, 0x36, 0x30, 0xaa, 0x38, 0x09, 0x83, 0x67, 0x38, 0x76, + 0x02, 0x91, 0x38, 0x95, 0x5a, 0x7b, 0x38, 0xc1, 0xa1, 0x55, 0x38, 0x6a, 0x3e, + 0x3d, 0x38, 0x67, 0xf7, 0x6f, 0x38, 0x32, 0x6e, 0x40, 0x38, 0x0f, 0x3a, 0x86, + 0x38, 0xb5, 0xd7, 0x7d, 0x38, 0x6c, 0xfd, 0xa5, 0x38, 0x24, 0xfa, 0x7b, 0x38, + 0x47, 0x81, 0x70, 0x38, 0xad, 0x65, 0x65, 0x38, 0xa2, 0xce, 0x83, 0x38, 0x27, + 0xa2, 0x62, 0x38, 0x6d, 0x47, 0x6b, 0x38, 0x82, 0x04, 0x3a, 0x38, 0x52, 0x8e, + 0x69, 0x38, 0xfc, 0x53, 0x45, 0x38, 0x77, 0x70, 0x61, 0x38, 0xc8, 0xc8, 0x95, + 0x38, 0x9b, 0x83, 0x5f, 0x38, 0x95, 0xb5, 0x9d, 0x38, 0x71, 0x60, 0x6c, 0x38, + 0x49, 0x40, 0xa6, 0x38, 0x6a, 0x26, 0x80, 0x38, 0x89, 0x76, 0x4b, 0x38, 0x7a, + 0xdd, 0x87, 0x38, 0x01, 0x7e, 0x90, 0x38, 0x12, 0xd1, 0x73, 0x38, 0x62, 0x7a, + 0x8e, 0x38, 0xf4, 0xd6, 0x6a, 0x38, 0x8b, 0xd9, 0x4a, 0x38, 0x41, 0x51, 0x3c, + 0x38, 0xf6, 0x05, 0x3a, 0x38, 0xa1, 0x01, 0x81, 0x38, 0x43, 0x13, 0x72, 0x38, + 0x92, 0x81, 0x94, 0x38, 0x70, 0x8b, 0x6d, 0x38, 0x18, 0xc6, 0x71, 0x38, 0x80, + 0xd6, 0xa2, 0x38, 0x1f, 0xdb, 0xae, 0x38, 0xb3, 0x44, 0xd1, 0x38, 0xde, 0x33, + 0x3f, 0x38, 0x51, 0xf0, 0x3c, 0x38, 0xbe, 0x68, 0x6d, 0x38, 0xf0, 0xc2, 0x30, + 0x38, 0x8b, 0x96, 0x84, 0x38, 0xcf, 0x4e, 0x6d, 0x38, 0x39, 0xcb, 0x4c, 0x38, + 0x64, 0xf9, 0x32, 0x38, 0x90, 0x6f, 0x3f, 0x38, 0xa0, 0xd9, 0x65, 0x38, 0x2d, + 0x33, 0x74, 0x38, 0x8f, 0x61, 0x5b, 0x38, 0xc8, 0xcb, 0x80, 0x38, 0x9e, 0x5d, + 0x4b, 0x38, 0xb8, 0x83, 0x97, 0x38, 0x2a, 0x05, 0x96, 0x38, 0xfc, 0x2b, 0x6a, + 0x38, 0xb6, 0x3f, 0x36, 0x38, 0x50, 0x70, 0x6a, 0x38, 0x52, 0xfe, 0x64, 0x38, + 0xd2, 0x09, 0x6d, 0x38, 0x2a, 0x53, 0x9e, 0x38, 0x4c, 0x99, 0x8c, 0x38, 0xac, + 0x4d, 0x94, 0x38, 0x6f, 0x65, 0xa6, 0x38, 0xe0, 0xc6, 0x83, 0x38, 0x24, 0xb7, + 0x8a, 0x38, 0x5e, 0x02, 0x74, 0x38, 0xdb, 0xbe, 0x4d, 0x38, 0x1b, 0x8b, 0x43, + 0x38, 0xa1, 0x86, 0x2b, 0x38, 0x67, 0x24, 0x89, 0x38, 0xd5, 0x4c, 0x40, 0x38, + 0x30, 0xf2, 0x4b, 0x38, 0x8c, 0xf6, 0x63, 0x38, 0x3d, 0x68, 0x78, 0x38, 0x64, + 0x47, 0x98, 0x38, 0xde, 0xaa, 0x66, 0x38, 0x2f, 0x29, 0x6a, 0x38, 0xa3, 0x0e, + 0x50, 0x38, 0x4a, 0xd1, 0x53, 0x38, 0xa1, 0xd8, 0x62, 0x38, 0xfc, 0x95, 0x84, + 0x38, 0x64, 0x6e, 0x9d, 0x38, 0x4f, 0xa2, 0x8d, 0x38, 0x03, 0xbe, 0x80, 0x38, + 0xa1, 0x5f, 0x55, 0x38, 0x43, 0x55, 0x71, 0x38, 0xb5, 0xef, 0x5b, 0x38, 0x94, + 0x43, 0x5e, 0x38, 0x31, 0x5b, 0x77, 0x38, 0x32, 0xe8, 0x61, 0x38, 0x0c, 0x74, + 0x53, 0x38, 0x7a, 0xe4, 0x5f, 0x38, 0x62, 0xdf, 0x51, 0x38, 0x23, 0x25, 0x99, + 0x38, 0x17, 0xd0, 0x64, 0x38, 0x62, 0xd0, 0x68, 0x38, 0x37, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x30, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x77, 0x69, 0x73, 0x65, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, + 0x69, 0x61, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x66, + 0x6e, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x6c, 0x06, 0x00, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc2, 0x67, 0xff, + 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x8d, 0xb4, 0x0a, 0x39, + 0x7e, 0xcb, 0x12, 0x39, 0x18, 0x65, 0x2f, 0x39, 0x96, 0xaa, 0x18, 0x39, 0x5e, + 0xca, 0x1c, 0x39, 0x2f, 0x14, 0x37, 0x39, 0x40, 0x9c, 0x08, 0x39, 0x42, 0x07, + 0x23, 0x39, 0x7b, 0xbd, 0x1c, 0x39, 0x0f, 0xa2, 0xf1, 0x38, 0xeb, 0x75, 0x25, + 0x39, 0xb6, 0x10, 0x4c, 0x39, 0x1e, 0x2c, 0x31, 0x39, 0x98, 0xa3, 0x48, 0x39, + 0xfa, 0x46, 0x7a, 0x39, 0xaa, 0xdf, 0xd6, 0x38, 0xff, 0xec, 0x4e, 0x39, 0x8f, + 0xac, 0x3e, 0x39, 0x94, 0x6b, 0x02, 0x39, 0xfd, 0xcc, 0xf7, 0x38, 0x71, 0x65, + 0x42, 0x39, 0x9a, 0x8d, 0x17, 0x39, 0x2a, 0x92, 0xb3, 0x38, 0x2a, 0x7d, 0x27, + 0x39, 0x7d, 0x6a, 0x6f, 0x39, 0xd8, 0xce, 0xda, 0x38, 0x2a, 0x54, 0x0b, 0x39, + 0x05, 0x96, 0x05, 0x39, 0xef, 0x61, 0x2b, 0x39, 0xe2, 0x57, 0x75, 0x39, 0x3b, + 0x78, 0x2c, 0x39, 0xbe, 0x24, 0xb6, 0x38, 0x8b, 0xca, 0x46, 0x39, 0x11, 0x3f, + 0x42, 0x39, 0x03, 0x1c, 0x14, 0x39, 0x3f, 0x96, 0x8c, 0x39, 0x53, 0xac, 0x00, + 0x39, 0x20, 0x71, 0x35, 0x39, 0x29, 0x32, 0x53, 0x39, 0x8e, 0x91, 0xfc, 0x38, + 0xb9, 0xf3, 0x29, 0x39, 0x2f, 0xed, 0xde, 0x38, 0x52, 0x28, 0x5a, 0x39, 0xb4, + 0x10, 0x82, 0x39, 0xd9, 0xdb, 0x42, 0x39, 0x26, 0xb8, 0xd0, 0x38, 0xd1, 0x22, + 0x22, 0x39, 0x73, 0xda, 0x13, 0x39, 0x23, 0x11, 0x55, 0x39, 0x4d, 0xd7, 0xce, + 0x38, 0x7c, 0x2d, 0x29, 0x39, 0xa2, 0x76, 0x3a, 0x39, 0x30, 0x7f, 0x45, 0x39, + 0x36, 0x9d, 0x29, 0x39, 0x49, 0x0c, 0xd5, 0x38, 0x70, 0x44, 0x30, 0x39, 0x4f, + 0x38, 0xec, 0x38, 0x3f, 0x3d, 0xb5, 0x38, 0xbf, 0x25, 0x33, 0x39, 0x12, 0xd7, + 0xbd, 0x38, 0xc6, 0x3e, 0xd0, 0x38, 0x9e, 0xdd, 0x25, 0x39, 0x5d, 0x82, 0x93, + 0x39, 0x3c, 0x1b, 0x19, 0x39, 0xe8, 0xcc, 0xf0, 0x38, 0x73, 0x56, 0x38, 0x39, + 0xbe, 0x5c, 0xf0, 0x38, 0x7f, 0x48, 0x30, 0x39, 0x02, 0xed, 0x57, 0x39, 0x6d, + 0x10, 0x1d, 0x39, 0x94, 0xbf, 0x21, 0x39, 0x89, 0x6e, 0x5e, 0x39, 0x52, 0x37, + 0x01, 0x39, 0x36, 0x31, 0xb7, 0x38, 0x09, 0xc4, 0xec, 0x38, 0x1d, 0xcd, 0x17, + 0x39, 0xb8, 0xd1, 0xd2, 0x38, 0x14, 0x86, 0x03, 0x39, 0x0f, 0xd3, 0xc9, 0x38, + 0x0a, 0x46, 0x03, 0x39, 0xa7, 0xb6, 0x1f, 0x39, 0x91, 0x21, 0xfc, 0x38, 0x47, + 0x19, 0x61, 0x39, 0x33, 0x5a, 0x0f, 0x39, 0x3e, 0x5c, 0xb4, 0x38, 0xb6, 0x11, + 0x22, 0x39, 0xf3, 0x79, 0x61, 0x39, 0xd8, 0x00, 0x6c, 0x39, 0x67, 0xe8, 0x30, + 0x39, 0x41, 0xd7, 0x8a, 0x39, 0xff, 0x16, 0x1f, 0x39, 0x75, 0x6b, 0x28, 0x39, + 0xe4, 0x57, 0x40, 0x39, 0x82, 0xef, 0xdb, 0x38, 0x8c, 0x69, 0xa0, 0x39, 0xc2, + 0xb9, 0x40, 0x39, 0x04, 0xc8, 0x83, 0x39, 0xce, 0xdd, 0x0e, 0x39, 0x4d, 0xa8, + 0xee, 0x38, 0xea, 0xbf, 0x24, 0x39, 0xfe, 0x8e, 0x10, 0x39, 0x17, 0x94, 0xe9, + 0x38, 0x38, 0x42, 0xaa, 0x38, 0x87, 0x5e, 0x37, 0x39, 0xa7, 0xe2, 0xd0, 0x38, + 0xa6, 0x2c, 0x21, 0x39, 0xd0, 0xeb, 0x41, 0x39, 0x59, 0x17, 0x5a, 0x39, 0x15, + 0xe7, 0x8c, 0x39, 0xf4, 0xde, 0x67, 0x39, 0x58, 0x8c, 0x2d, 0x39, 0x5c, 0x8e, + 0x1b, 0x39, 0x9a, 0xe9, 0xe6, 0x38, 0xa4, 0xe6, 0x29, 0x39, 0x3c, 0x34, 0x0a, + 0x39, 0x7c, 0x46, 0xcb, 0x38, 0xe7, 0x15, 0x28, 0x39, 0xa1, 0x03, 0x35, 0x39, + 0xa3, 0x8a, 0x20, 0x39, 0x05, 0xe8, 0xf2, 0x38, 0x61, 0xcf, 0xbb, 0x38, 0xc6, + 0x8a, 0x13, 0x39, 0x4d, 0xb1, 0x41, 0x39, 0x3f, 0x33, 0x38, 0x39, 0xac, 0x8c, + 0x5d, 0x39, 0xa1, 0x08, 0xc6, 0x38, 0x12, 0x0e, 0x39, 0x39, 0x79, 0x73, 0x3a, + 0x39, 0x3a, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x30, 0x5f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, + 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe2, 0x74, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x09, 0x84, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7c, 0xfb, 0xff, 0xff, 0x30, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, 0xc0, 0x3c, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x31, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x30, 0x5f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x52, 0x65, 0x6c, + 0x75, 0x36, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x82, + 0x75, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, 0x00, 0x59, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xfc, 0xff, + 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xc1, 0xc0, + 0xc0, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x30, 0x2f, 0x52, 0x65, 0x6c, 0x75, 0x36, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x16, 0x76, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0xc0, + 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x72, 0x6f, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x8c, 0x89, 0x06, 0x39, 0x3a, 0xd9, 0x5a, 0x39, 0xb1, 0xe4, + 0xc7, 0x37, 0x81, 0xa6, 0xd6, 0x37, 0x69, 0xc0, 0xbd, 0x38, 0xcd, 0xb7, 0x99, + 0x39, 0xeb, 0x2f, 0x15, 0x39, 0x7f, 0xee, 0x0e, 0x37, 0x2c, 0x00, 0x00, 0x00, + 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, + 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x30, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, + 0x5f, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xe6, 0x76, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x44, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x4c, 0x6f, 0x67, 0x69, 0x74, 0x73, 0x2f, 0x53, 0x70, 0x61, 0x74, 0x69, 0x61, + 0x6c, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x70, + 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x3a, 0x77, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd4, 0xfd, 0xff, 0xff, 0x30, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x1b, 0x4d, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0xce, 0xb0, 0xcc, 0x3f, 0x01, 0x00, 0x00, 0x00, 0xe2, + 0xeb, 0xcb, 0xbf, 0x21, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4c, 0x6f, 0x67, 0x69, 0x74, 0x73, 0x2f, + 0x53, 0x70, 0x61, 0x74, 0x69, 0x61, 0x6c, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0xc2, 0x77, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x44, 0x7e, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0xe5, 0xd6, 0xbf, 0x3a, 0x4a, 0xd6, 0xb6, 0x3a, 0x2d, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x4c, 0x6f, 0x67, 0x69, 0x74, 0x73, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x31, 0x63, 0x5f, 0x31, 0x78, 0x31, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x52, 0x78, 0xff, 0xff, 0x00, 0x00, 0x00, 0x02, 0x70, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0xd4, 0x7e, 0xff, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xef, + 0x7a, 0xe4, 0x37, 0x28, 0xc2, 0xd9, 0x37, 0x2c, 0x00, 0x00, 0x00, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4c, 0x6f, 0x67, + 0x69, 0x74, 0x73, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x63, + 0x5f, 0x31, 0x78, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x44, 0x5f, 0x62, + 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0xd2, 0x78, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x78, 0x00, 0x00, + 0x00, 0x4b, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6c, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x73, 0x1b, 0x4d, + 0x3c, 0x01, 0x00, 0x00, 0x00, 0xce, 0xb0, 0xcc, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0xe2, 0xeb, 0xcb, 0xbf, 0x28, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4c, 0x6f, 0x67, 0x69, 0x74, 0x73, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x63, 0x5f, 0x31, 0x78, + 0x31, 0x2f, 0x42, 0x69, 0x61, 0x73, 0x41, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x66, 0x79, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x09, 0x80, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x98, 0x72, 0x98, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x25, 0xda, 0x97, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x4d, + 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x4c, 0x6f, + 0x67, 0x69, 0x74, 0x73, 0x2f, 0x41, 0x76, 0x67, 0x50, 0x6f, 0x6f, 0x6c, 0x5f, + 0x31, 0x61, 0x2f, 0x41, 0x76, 0x67, 0x50, 0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7a, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x09, 0x58, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x84, 0x80, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x30, 0x9c, 0x0e, 0x3b, 0xed, 0x44, 0x38, 0x3b, 0xef, 0x56, 0x12, 0x3b, 0xe5, + 0xb8, 0x28, 0x3b, 0x2f, 0x6a, 0x09, 0x3b, 0x71, 0xb8, 0x6c, 0x3b, 0x85, 0xba, + 0x2e, 0x3b, 0x52, 0x4d, 0x47, 0x3b, 0x02, 0x8d, 0x10, 0x3b, 0xa9, 0xd9, 0x49, + 0x3b, 0xbe, 0x2b, 0x3c, 0x3b, 0x25, 0x16, 0x38, 0x3b, 0xdc, 0x9e, 0x08, 0x3b, + 0xaf, 0xb6, 0x28, 0x3b, 0x9d, 0x44, 0x2b, 0x3b, 0x68, 0xf5, 0xe8, 0x3a, 0xd1, + 0x70, 0x1a, 0x3b, 0x56, 0x82, 0x0d, 0x3b, 0x47, 0x46, 0xea, 0x3a, 0x30, 0x72, + 0x49, 0x3b, 0xc3, 0x5d, 0x2a, 0x3b, 0x3f, 0x67, 0x2b, 0x3b, 0x9d, 0x51, 0x1b, + 0x3b, 0x92, 0x11, 0x0b, 0x3b, 0x6e, 0x69, 0xf6, 0x3a, 0x8b, 0x3d, 0x83, 0x3b, + 0xfb, 0x6e, 0x01, 0x3b, 0xd5, 0xf8, 0x66, 0x3b, 0x88, 0x00, 0x80, 0x3b, 0x9e, + 0xe9, 0x31, 0x3b, 0x6e, 0xf6, 0x27, 0x3b, 0x3d, 0x53, 0x54, 0x3b, 0x57, 0xc0, + 0x4a, 0x3b, 0x93, 0x70, 0x13, 0x3b, 0x06, 0x3b, 0x42, 0x3b, 0xca, 0x69, 0x08, + 0x3b, 0x62, 0x80, 0x3c, 0x3b, 0x94, 0x95, 0x2d, 0x3b, 0x88, 0xf2, 0x0d, 0x3b, + 0x67, 0xd3, 0x50, 0x3b, 0x47, 0x89, 0x4c, 0x3b, 0xb2, 0x55, 0x53, 0x3b, 0xf9, + 0x44, 0x11, 0x3b, 0xbd, 0xf8, 0x26, 0x3b, 0x03, 0x35, 0x0c, 0x3b, 0xfc, 0x0b, + 0x0e, 0x3b, 0x3a, 0x04, 0x3b, 0x3b, 0xeb, 0x60, 0x26, 0x3b, 0x3d, 0xd3, 0x32, + 0x3b, 0x65, 0x8f, 0x34, 0x3b, 0xe0, 0xd2, 0x1a, 0x3b, 0xa5, 0x42, 0x2a, 0x3b, + 0x6f, 0x61, 0x46, 0x3b, 0x12, 0xdf, 0x30, 0x3b, 0x07, 0x37, 0x45, 0x3b, 0x9e, + 0x57, 0x49, 0x3b, 0xed, 0xc9, 0x2a, 0x3b, 0xc1, 0xe5, 0x07, 0x3b, 0xe6, 0x5c, + 0x27, 0x3b, 0x18, 0xf4, 0x2c, 0x3b, 0x7b, 0xbc, 0x1e, 0x3b, 0x5b, 0x2a, 0x25, + 0x3b, 0x8b, 0xd3, 0x0a, 0x3b, 0xd6, 0xf9, 0x32, 0x3b, 0x3b, 0xe3, 0x4a, 0x3b, + 0xc3, 0x1c, 0x2a, 0x3b, 0x06, 0xcc, 0x39, 0x3b, 0xb5, 0xa6, 0x32, 0x3b, 0x58, + 0x1d, 0x0c, 0x3b, 0x0d, 0x63, 0x30, 0x3b, 0x98, 0x15, 0x67, 0x3b, 0x2b, 0x29, + 0x0e, 0x3b, 0xeb, 0x95, 0x29, 0x3b, 0x68, 0x2e, 0x2c, 0x3b, 0x64, 0xc2, 0x79, + 0x3b, 0x5d, 0x60, 0x5d, 0x3b, 0x77, 0xc4, 0x29, 0x3b, 0x11, 0x87, 0x41, 0x3b, + 0x7e, 0x0c, 0x35, 0x3b, 0x48, 0x2f, 0x31, 0x3b, 0x48, 0xef, 0x35, 0x3b, 0xd9, + 0xfe, 0x25, 0x3b, 0xa7, 0xd7, 0x48, 0x3b, 0xe3, 0xde, 0x48, 0x3b, 0x93, 0xa5, + 0x26, 0x3b, 0x26, 0xfc, 0x12, 0x3b, 0x98, 0xd4, 0x16, 0x3b, 0x3e, 0x8e, 0x27, + 0x3b, 0xb2, 0x5e, 0x56, 0x3b, 0xd3, 0xb3, 0x58, 0x3b, 0xc5, 0x71, 0x6c, 0x3b, + 0xb0, 0x7b, 0x46, 0x3b, 0x77, 0x95, 0x1e, 0x3b, 0x3a, 0xde, 0x2f, 0x3b, 0x08, + 0xfc, 0x24, 0x3b, 0x0a, 0xd5, 0x24, 0x3b, 0x41, 0xf5, 0x15, 0x3b, 0x87, 0x3b, + 0x48, 0x3b, 0x06, 0x23, 0x0a, 0x3b, 0x94, 0x19, 0x36, 0x3b, 0x95, 0xbe, 0x29, + 0x3b, 0x77, 0x69, 0x14, 0x3b, 0xa8, 0xa7, 0x1f, 0x3b, 0x80, 0x1e, 0x18, 0x3b, + 0x05, 0x08, 0x41, 0x3b, 0xf7, 0x8d, 0x1d, 0x3b, 0x79, 0xcb, 0x36, 0x3b, 0xde, + 0xad, 0x0e, 0x3b, 0xa8, 0x21, 0x14, 0x3b, 0xdb, 0xf9, 0x06, 0x3b, 0x43, 0x2a, + 0x81, 0x3b, 0xc1, 0x11, 0x16, 0x3b, 0x01, 0xcd, 0x76, 0x3b, 0x47, 0x0f, 0x44, + 0x3b, 0xa1, 0x1b, 0xf6, 0x3a, 0x4f, 0xcf, 0x1f, 0x3b, 0xfb, 0xf6, 0x15, 0x3b, + 0x37, 0xac, 0x1f, 0x3b, 0xc5, 0x5e, 0x60, 0x3b, 0x2d, 0x2e, 0x8a, 0x3b, 0x57, + 0x79, 0x7e, 0x3b, 0xf3, 0xa7, 0x2f, 0x3b, 0x94, 0xfc, 0x3b, 0x3b, 0x78, 0x2d, + 0xf7, 0x3a, 0x0f, 0xad, 0x15, 0x3b, 0x1c, 0xd7, 0x21, 0x3b, 0x0e, 0xcc, 0x22, + 0x3b, 0x70, 0x91, 0x49, 0x3b, 0x2b, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x39, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, + 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x76, 0x80, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x09, 0x68, 0x06, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x24, 0x06, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd2, 0x79, 0xff, 0xff, 0x14, 0x04, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x5a, 0x8a, 0xd9, 0x3b, 0x5f, 0xcd, 0x89, 0x3b, + 0xf4, 0xca, 0x92, 0x3b, 0x96, 0x01, 0xb8, 0x3b, 0x04, 0x10, 0x26, 0x3c, 0x8e, + 0x8d, 0xb2, 0x3b, 0xc2, 0xd9, 0xa9, 0x3b, 0xf9, 0xee, 0xd0, 0x3b, 0xce, 0xfe, + 0x97, 0x3b, 0x44, 0x79, 0x91, 0x3b, 0x2f, 0x92, 0xcd, 0x3b, 0x8d, 0x6a, 0xfe, + 0x3b, 0x21, 0x6b, 0x95, 0x3b, 0x29, 0x32, 0x8d, 0x3b, 0x37, 0x77, 0x0d, 0x3c, + 0x8a, 0x17, 0xea, 0x3b, 0xc5, 0xdd, 0xf7, 0x3b, 0x8f, 0x29, 0xaa, 0x3b, 0xeb, + 0x0e, 0x96, 0x3b, 0x17, 0xe3, 0x67, 0x3b, 0x96, 0xe9, 0xf1, 0x3b, 0x78, 0x22, + 0x91, 0x3b, 0x60, 0x7f, 0x0c, 0x3c, 0x14, 0xdd, 0x18, 0x3c, 0x55, 0xd7, 0x0a, + 0x3c, 0x94, 0x13, 0xe3, 0x3b, 0xe5, 0xc5, 0x8d, 0x3b, 0xab, 0xc2, 0x0d, 0x3c, + 0xb7, 0xf5, 0xf7, 0x3b, 0xd0, 0x25, 0x46, 0x3c, 0xdb, 0x7c, 0x05, 0x3c, 0xec, + 0x68, 0xd5, 0x3b, 0xe5, 0x43, 0xb0, 0x3b, 0xea, 0x32, 0xe2, 0x3b, 0xe6, 0x9e, + 0xcd, 0x3b, 0x8b, 0x88, 0xf9, 0x3b, 0x5e, 0xcc, 0xd6, 0x3b, 0xa6, 0x6e, 0xad, + 0x3b, 0x77, 0x7b, 0xaf, 0x3b, 0x3a, 0x14, 0x1c, 0x3c, 0x66, 0x6f, 0x86, 0x3b, + 0xe2, 0xdd, 0xb4, 0x3b, 0xdf, 0xd8, 0x95, 0x3b, 0xff, 0x99, 0x01, 0x3c, 0x94, + 0x37, 0xf2, 0x3b, 0x2c, 0x4b, 0xb5, 0x3b, 0x21, 0xac, 0xa1, 0x3b, 0x65, 0xfe, + 0xb5, 0x3b, 0xfb, 0x01, 0x1d, 0x3c, 0x35, 0xb8, 0x29, 0x3c, 0xd0, 0xb5, 0xaf, + 0x3b, 0x0b, 0x50, 0x06, 0x3c, 0x6f, 0x42, 0xd3, 0x3b, 0x51, 0x69, 0x9a, 0x3b, + 0x05, 0x8e, 0xb0, 0x3b, 0x19, 0x7f, 0xb1, 0x3b, 0xc9, 0x4f, 0xc6, 0x3b, 0x17, + 0x8c, 0xd8, 0x3b, 0x99, 0xea, 0x5f, 0x3c, 0x01, 0x5b, 0x26, 0x3c, 0x31, 0x17, + 0xcd, 0x3b, 0x86, 0x32, 0x3a, 0x3c, 0x16, 0xc0, 0xca, 0x3b, 0x4c, 0x5a, 0xae, + 0x3b, 0x9e, 0x40, 0xd9, 0x3b, 0x96, 0xa4, 0x12, 0x3c, 0xe5, 0xeb, 0x8f, 0x3b, + 0x37, 0x61, 0xca, 0x3b, 0x01, 0xe0, 0x1e, 0x3c, 0xff, 0x75, 0x64, 0x3b, 0xae, + 0xec, 0x04, 0x3c, 0xe9, 0xc1, 0xd8, 0x3b, 0xc8, 0x4e, 0x9a, 0x3b, 0xfc, 0xdb, + 0x98, 0x3b, 0x2e, 0x5a, 0xb6, 0x3b, 0xaa, 0xa5, 0x65, 0x3c, 0x63, 0xc8, 0xb5, + 0x3b, 0xeb, 0x10, 0xea, 0x3b, 0xe5, 0x2e, 0xa0, 0x3b, 0xbe, 0xbf, 0x8e, 0x3b, + 0x28, 0x42, 0x9e, 0x3b, 0x94, 0x4e, 0xbe, 0x3b, 0x7b, 0xae, 0x02, 0x3c, 0x3e, + 0x6c, 0x9f, 0x3b, 0x4b, 0xdd, 0xef, 0x3b, 0xa7, 0xbf, 0x92, 0x3b, 0x0b, 0x7b, + 0xa0, 0x3b, 0x52, 0x98, 0xc7, 0x3b, 0x29, 0x9e, 0xfa, 0x3b, 0xbf, 0x0f, 0xf3, + 0x3b, 0x1f, 0x6d, 0x99, 0x3b, 0xa2, 0xa3, 0xa7, 0x3b, 0xf0, 0x44, 0xb1, 0x3b, + 0xcb, 0x34, 0x73, 0x3b, 0x80, 0xb4, 0x48, 0x3c, 0xd8, 0x51, 0x8b, 0x3b, 0x8d, + 0x63, 0xf2, 0x3b, 0x4f, 0x4e, 0x06, 0x3c, 0x25, 0x09, 0x9b, 0x3b, 0xf7, 0x19, + 0x96, 0x3b, 0xc9, 0x9c, 0x00, 0x3c, 0x09, 0x50, 0x9a, 0x3b, 0xca, 0xbf, 0xb7, + 0x3b, 0xe1, 0x96, 0x8f, 0x3b, 0x56, 0x80, 0x8d, 0x3b, 0xfb, 0x3d, 0xa4, 0x3b, + 0xab, 0x64, 0xf7, 0x3b, 0x02, 0x36, 0xda, 0x3b, 0xe0, 0x68, 0xaa, 0x3b, 0x4d, + 0x81, 0xfe, 0x3b, 0xca, 0x40, 0x9c, 0x3b, 0xc5, 0x7f, 0xff, 0x3b, 0xa7, 0xa6, + 0x96, 0x3b, 0x12, 0x25, 0x89, 0x3b, 0x22, 0x4b, 0xbb, 0x3b, 0xcd, 0x27, 0xac, + 0x3b, 0x94, 0x10, 0xcc, 0x3b, 0x58, 0x19, 0xcd, 0x3b, 0xc5, 0x66, 0x07, 0x3c, + 0x7d, 0xbe, 0xf0, 0x3b, 0x05, 0x1e, 0x03, 0x3c, 0x97, 0xc0, 0x6d, 0x3b, 0x32, + 0xca, 0x97, 0x3b, 0x43, 0x0e, 0x8d, 0x3b, 0xee, 0x80, 0xad, 0x3b, 0x0d, 0xd8, + 0x8a, 0x3b, 0x17, 0x95, 0xa3, 0x3b, 0x22, 0x56, 0xbe, 0x3b, 0x35, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x39, 0x5f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, + 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xfa, + 0x86, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x58, 0x06, 0x00, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7c, 0x8d, 0xff, + 0xff, 0x10, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x25, 0x78, 0x0c, 0x3b, 0xfd, 0x6d, 0x28, 0x3b, + 0x80, 0x30, 0x23, 0x3b, 0x53, 0x22, 0x20, 0x3b, 0x08, 0x7b, 0x6b, 0x3b, 0xaa, + 0x4d, 0x68, 0x3b, 0xcb, 0x88, 0x21, 0x3b, 0x64, 0x20, 0x19, 0x3b, 0xb3, 0x06, + 0x1c, 0x3b, 0x08, 0x54, 0x4c, 0x3b, 0xad, 0x54, 0x33, 0x3b, 0x3e, 0xd5, 0x2d, + 0x3b, 0x8c, 0xb0, 0x2d, 0x3b, 0x36, 0x74, 0x33, 0x3b, 0x86, 0x73, 0x0a, 0x3b, + 0x48, 0x44, 0x10, 0x3b, 0xba, 0xd5, 0x3a, 0x3b, 0x14, 0x6a, 0x41, 0x3b, 0x2e, + 0x64, 0x29, 0x3b, 0xad, 0x6e, 0x0d, 0x3b, 0xf0, 0xaf, 0x3a, 0x3b, 0x56, 0xcf, + 0x28, 0x3b, 0xcc, 0xca, 0x35, 0x3b, 0x87, 0x8e, 0x33, 0x3b, 0x84, 0x7a, 0x42, + 0x3b, 0x7f, 0x21, 0x29, 0x3b, 0xd8, 0xea, 0x21, 0x3b, 0x4c, 0x20, 0x46, 0x3b, + 0x5a, 0x51, 0x2e, 0x3b, 0xd2, 0xe3, 0x2e, 0x3b, 0xad, 0xcc, 0x32, 0x3b, 0xe6, + 0x75, 0x45, 0x3b, 0x3e, 0x3d, 0x3f, 0x3b, 0xad, 0x25, 0x18, 0x3b, 0x7b, 0x94, + 0x19, 0x3b, 0x0c, 0x72, 0x31, 0x3b, 0x79, 0x93, 0x6b, 0x3b, 0x0c, 0xc8, 0x3d, + 0x3b, 0xe3, 0x15, 0x2f, 0x3b, 0xdc, 0x72, 0x1f, 0x3b, 0x4f, 0x86, 0x38, 0x3b, + 0x6e, 0x60, 0x2e, 0x3b, 0x27, 0x79, 0x12, 0x3b, 0x38, 0x5c, 0x26, 0x3b, 0x97, + 0x5d, 0x0b, 0x3b, 0xf6, 0xd9, 0x22, 0x3b, 0xfd, 0xcb, 0x47, 0x3b, 0xb4, 0x75, + 0x46, 0x3b, 0x34, 0x59, 0xec, 0x3a, 0xca, 0x3f, 0xe5, 0x3a, 0x85, 0x5d, 0x39, + 0x3b, 0x48, 0x4d, 0xed, 0x3a, 0x1c, 0x4a, 0x2b, 0x3b, 0x54, 0xdf, 0x18, 0x3b, + 0x78, 0x67, 0x00, 0x3b, 0xf0, 0x43, 0x35, 0x3b, 0xf3, 0xe5, 0x30, 0x3b, 0x3b, + 0xc0, 0x0a, 0x3b, 0x4a, 0x82, 0x32, 0x3b, 0xe6, 0xac, 0x2a, 0x3b, 0xc3, 0xbf, + 0x01, 0x3b, 0x53, 0xa3, 0x1f, 0x3b, 0x59, 0xc5, 0x2f, 0x3b, 0x43, 0xed, 0x48, + 0x3b, 0x75, 0x05, 0x15, 0x3b, 0x34, 0x31, 0x2f, 0x3b, 0x65, 0x54, 0x07, 0x3b, + 0x71, 0x3d, 0x2c, 0x3b, 0x1e, 0x9f, 0x21, 0x3b, 0x2b, 0xd4, 0x29, 0x3b, 0x03, + 0x86, 0x53, 0x3b, 0x8b, 0x78, 0x43, 0x3b, 0xd9, 0xbc, 0x3e, 0x3b, 0x37, 0x52, + 0x65, 0x3b, 0xbe, 0x2b, 0x6a, 0x3b, 0x39, 0x29, 0x30, 0x3b, 0xce, 0x74, 0x74, + 0x3b, 0xf5, 0x3e, 0x14, 0x3b, 0x20, 0x8d, 0x2e, 0x3b, 0xeb, 0xab, 0x1b, 0x3b, + 0x86, 0x51, 0x34, 0x3b, 0xc5, 0xdd, 0x64, 0x3b, 0x83, 0x21, 0x47, 0x3b, 0x14, + 0xc1, 0x38, 0x3b, 0xb2, 0xa2, 0x69, 0x3b, 0xaa, 0x97, 0x2c, 0x3b, 0x4f, 0x38, + 0xfd, 0x3a, 0x89, 0x21, 0x13, 0x3b, 0x8f, 0xb4, 0x02, 0x3b, 0xb8, 0x13, 0x34, + 0x3b, 0x5c, 0x27, 0x26, 0x3b, 0x92, 0xf0, 0x3f, 0x3b, 0x4b, 0xbc, 0x25, 0x3b, + 0x7f, 0xd1, 0x43, 0x3b, 0x38, 0xf0, 0x1c, 0x3b, 0x53, 0xd1, 0x2b, 0x3b, 0x00, + 0x93, 0x5e, 0x3b, 0x33, 0x65, 0x3c, 0x3b, 0xec, 0xa1, 0x16, 0x3b, 0x8e, 0xe1, + 0x1c, 0x3b, 0x70, 0x19, 0x5b, 0x3b, 0xe9, 0x16, 0x0d, 0x3b, 0x59, 0x69, 0x44, + 0x3b, 0x66, 0x38, 0xfb, 0x3a, 0x6d, 0x4a, 0x44, 0x3b, 0x94, 0x1f, 0x13, 0x3b, + 0x97, 0x36, 0x45, 0x3b, 0xe5, 0x0b, 0x76, 0x3b, 0x74, 0xb5, 0x0d, 0x3b, 0x23, + 0x54, 0x19, 0x3b, 0x05, 0x7c, 0x0d, 0x3b, 0x90, 0x11, 0x30, 0x3b, 0xc7, 0xf9, + 0x36, 0x3b, 0xf7, 0xee, 0x30, 0x3b, 0xa3, 0xfb, 0x3e, 0x3b, 0xdb, 0x92, 0x2e, + 0x3b, 0x25, 0xb9, 0x1e, 0x3b, 0x77, 0x7b, 0xfa, 0x3a, 0x8e, 0x6a, 0x28, 0x3b, + 0x01, 0xd7, 0x06, 0x3b, 0x23, 0xa8, 0x21, 0x3b, 0x5c, 0x39, 0x1b, 0x3b, 0x20, + 0xce, 0x28, 0x3b, 0x19, 0x57, 0x2b, 0x3b, 0x18, 0x50, 0x48, 0x3b, 0x1a, 0xc2, + 0x12, 0x3b, 0x7d, 0xbc, 0x26, 0x3b, 0xc6, 0x8b, 0x2c, 0x3b, 0x2b, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x38, 0x5f, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, + 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x6e, 0x8d, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x68, 0x06, 0x00, 0x00, 0x47, + 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xca, 0x86, + 0xff, 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb7, 0xc8, 0xb9, + 0x3b, 0x49, 0x06, 0x07, 0x3c, 0x13, 0x37, 0xaa, 0x3b, 0x4d, 0x39, 0x88, 0x3b, + 0x57, 0x70, 0xba, 0x3b, 0x17, 0xf4, 0x13, 0x3c, 0x91, 0xed, 0x12, 0x3c, 0xc7, + 0x17, 0xdc, 0x3b, 0x67, 0x96, 0x94, 0x3b, 0xb3, 0x0f, 0xac, 0x3b, 0xe6, 0xef, + 0xa2, 0x3b, 0x74, 0x00, 0x20, 0x3c, 0x5d, 0x78, 0xa8, 0x3b, 0x3b, 0x92, 0x97, + 0x3b, 0x13, 0x50, 0x8a, 0x3b, 0xe9, 0x01, 0x93, 0x3b, 0x9a, 0xf1, 0x26, 0x3c, + 0xaf, 0xb5, 0xd6, 0x3b, 0xf4, 0x4a, 0x3a, 0x3c, 0xf9, 0xfc, 0xa3, 0x3b, 0x9c, + 0xdc, 0x30, 0x3c, 0xe8, 0x5a, 0xa0, 0x3b, 0x93, 0x4f, 0xd3, 0x3b, 0x50, 0x8e, + 0xb5, 0x3b, 0xf3, 0xe6, 0x92, 0x3b, 0xee, 0x31, 0xc7, 0x3b, 0xb3, 0x8f, 0xf6, + 0x3b, 0xe5, 0x1c, 0xab, 0x3b, 0xa2, 0x69, 0xb9, 0x3b, 0x11, 0x67, 0xc5, 0x3b, + 0x97, 0x69, 0x2c, 0x3c, 0x0a, 0x11, 0x0f, 0x3c, 0xd6, 0xdc, 0xea, 0x3b, 0x62, + 0x0e, 0xd3, 0x3b, 0x16, 0xf5, 0x7d, 0x3b, 0x81, 0x5a, 0xcd, 0x3b, 0xc3, 0x2b, + 0xa3, 0x3b, 0x8a, 0x18, 0xd8, 0x3b, 0x53, 0x16, 0xa2, 0x3b, 0x79, 0x63, 0xaf, + 0x3b, 0x6d, 0x10, 0xad, 0x3b, 0xcb, 0x53, 0x0d, 0x3c, 0x96, 0x74, 0xdb, 0x3b, + 0x34, 0xa9, 0xb6, 0x3b, 0xe1, 0x8a, 0x81, 0x3b, 0x64, 0x61, 0x9f, 0x3b, 0x79, + 0x95, 0xf2, 0x3b, 0x52, 0xae, 0x1b, 0x3c, 0xea, 0x22, 0x99, 0x3b, 0xe8, 0x9a, + 0xd5, 0x3b, 0xd9, 0xf5, 0xc3, 0x3b, 0x97, 0x3f, 0xa7, 0x3b, 0xb4, 0xde, 0xce, + 0x3b, 0x6a, 0xb7, 0x99, 0x3b, 0x5d, 0x1b, 0xaa, 0x3b, 0x62, 0xe8, 0xdd, 0x3b, + 0x80, 0xe0, 0xea, 0x3b, 0x11, 0xf6, 0x32, 0x3c, 0xa1, 0xb3, 0xe0, 0x3b, 0x4b, + 0x55, 0x91, 0x3b, 0xf8, 0x58, 0x26, 0x3c, 0x51, 0x2e, 0xcd, 0x3b, 0xcb, 0xd4, + 0xa1, 0x3b, 0xdc, 0xca, 0xf7, 0x3b, 0xc8, 0x18, 0xcd, 0x3b, 0x65, 0x34, 0x09, + 0x3c, 0x27, 0x59, 0x9f, 0x3b, 0x34, 0x50, 0x89, 0x3b, 0xfa, 0x30, 0x0a, 0x3c, + 0xbd, 0xd9, 0xb7, 0x3b, 0x60, 0x79, 0xd8, 0x3b, 0x48, 0xf7, 0xea, 0x3b, 0x1c, + 0xe6, 0xdc, 0x3b, 0x0c, 0xb8, 0x8e, 0x3b, 0x26, 0xb3, 0xee, 0x3b, 0xae, 0x58, + 0xc2, 0x3b, 0xdb, 0x17, 0xca, 0x3b, 0x6b, 0xaa, 0xaf, 0x3b, 0x6d, 0xf2, 0xe1, + 0x3b, 0xa3, 0x39, 0x4b, 0x3c, 0x84, 0xcd, 0xb6, 0x3b, 0x4b, 0x1c, 0x9a, 0x3b, + 0x47, 0x1c, 0x1f, 0x3c, 0x83, 0xa4, 0xad, 0x3b, 0x5f, 0xc3, 0xdd, 0x3b, 0xc1, + 0xeb, 0x9c, 0x3b, 0xb6, 0xe6, 0xd5, 0x3b, 0x38, 0x08, 0x17, 0x3c, 0xc6, 0x98, + 0xf2, 0x3b, 0xe2, 0x24, 0xf1, 0x3b, 0x4c, 0x77, 0x46, 0x3c, 0x62, 0x8f, 0xa8, + 0x3b, 0x2d, 0x25, 0x02, 0x3c, 0x18, 0x5c, 0x89, 0x3b, 0x76, 0xa2, 0x9b, 0x3b, + 0x5b, 0x6d, 0x94, 0x3b, 0xfe, 0xf2, 0x10, 0x3c, 0x8b, 0x09, 0xde, 0x3b, 0x4a, + 0x1c, 0xd5, 0x3b, 0x11, 0xe4, 0xda, 0x3b, 0x1e, 0xa1, 0x90, 0x3b, 0x11, 0xa7, + 0xa4, 0x3b, 0x2c, 0x8c, 0x9c, 0x3b, 0xe4, 0x0d, 0xed, 0x3b, 0x3d, 0xb3, 0x8c, + 0x3b, 0x6a, 0xea, 0xa1, 0x3b, 0x9e, 0xcb, 0xe1, 0x3b, 0x2e, 0xdf, 0xea, 0x3b, + 0x87, 0xe0, 0xb6, 0x3b, 0x92, 0x5b, 0x16, 0x3c, 0xb6, 0x40, 0xb2, 0x3b, 0x77, + 0x64, 0xfa, 0x3b, 0x9f, 0xa9, 0xde, 0x3b, 0xc3, 0x27, 0x17, 0x3c, 0x38, 0xc3, + 0xe4, 0x3b, 0x2e, 0x3c, 0xa7, 0x3b, 0x67, 0x96, 0x91, 0x3b, 0xe8, 0x01, 0x9e, + 0x3b, 0x8a, 0x9e, 0x2d, 0x3c, 0x52, 0xae, 0x8f, 0x3b, 0xe2, 0xcb, 0x9e, 0x3b, + 0x2d, 0x22, 0x20, 0x3c, 0xf1, 0x72, 0x97, 0x3b, 0x3e, 0x6f, 0x35, 0x3c, 0x5a, + 0x72, 0xf1, 0x3b, 0x3a, 0x1f, 0xa7, 0x3b, 0x8a, 0x30, 0xad, 0x3b, 0x86, 0xd7, + 0xc8, 0x3b, 0x35, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, + 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x38, + 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, + 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xf2, 0x93, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x58, + 0x06, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x74, 0x9a, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x69, 0x72, 0x15, + 0x3b, 0x7b, 0x2b, 0x6e, 0x3b, 0x0e, 0x7b, 0x3c, 0x3b, 0x82, 0xfa, 0x32, 0x3b, + 0x8e, 0x21, 0x15, 0x3b, 0xb7, 0x35, 0x12, 0x3b, 0x84, 0x7e, 0x16, 0x3b, 0x91, + 0xfe, 0x6f, 0x3b, 0xe3, 0xc4, 0x14, 0x3b, 0x38, 0xa8, 0x14, 0x3b, 0x5c, 0x34, + 0x8b, 0x3b, 0x9b, 0xf3, 0x51, 0x3b, 0xa0, 0xe2, 0x0f, 0x3b, 0x26, 0x0f, 0x38, + 0x3b, 0xaa, 0x48, 0x3b, 0x3b, 0x97, 0x55, 0x32, 0x3b, 0xb9, 0x5d, 0x13, 0x3b, + 0x5e, 0x54, 0x4d, 0x3b, 0x8b, 0x64, 0x48, 0x3b, 0xfc, 0x34, 0x2f, 0x3b, 0x8e, + 0x96, 0x3e, 0x3b, 0x2f, 0x44, 0x2b, 0x3b, 0xf1, 0x0c, 0x1a, 0x3b, 0xaf, 0xb5, + 0x3d, 0x3b, 0x74, 0xc8, 0x47, 0x3b, 0x81, 0x75, 0x4a, 0x3b, 0xe5, 0x54, 0x04, + 0x3b, 0xdd, 0xeb, 0x27, 0x3b, 0x65, 0x52, 0x07, 0x3b, 0x7a, 0xd4, 0x2e, 0x3b, + 0x34, 0x82, 0x2d, 0x3b, 0x98, 0x18, 0x4f, 0x3b, 0x9d, 0x4d, 0x19, 0x3b, 0x8f, + 0x04, 0x31, 0x3b, 0x5d, 0x44, 0x1e, 0x3b, 0x66, 0x57, 0x75, 0x3b, 0x22, 0x5d, + 0x31, 0x3b, 0x83, 0x6d, 0x00, 0x3b, 0x07, 0x31, 0x35, 0x3b, 0xbb, 0x4a, 0x21, + 0x3b, 0x02, 0xd8, 0x67, 0x3b, 0xff, 0x57, 0x52, 0x3b, 0xa6, 0x70, 0x24, 0x3b, + 0xea, 0xb4, 0x24, 0x3b, 0x9d, 0x41, 0x2e, 0x3b, 0xe5, 0xa3, 0x1c, 0x3b, 0x01, + 0x17, 0x25, 0x3b, 0x09, 0x5b, 0x39, 0x3b, 0x14, 0x47, 0x38, 0x3b, 0xe8, 0xb3, + 0x31, 0x3b, 0x5e, 0xc4, 0x0a, 0x3b, 0x07, 0xf2, 0x3a, 0x3b, 0xa1, 0x56, 0x0e, + 0x3b, 0x08, 0x08, 0x11, 0x3b, 0xb8, 0xf8, 0x16, 0x3b, 0x1e, 0xcb, 0x1b, 0x3b, + 0xf4, 0xb4, 0x11, 0x3b, 0x18, 0xed, 0x0f, 0x3b, 0x15, 0x9f, 0x0d, 0x3b, 0xa1, + 0xa1, 0x4c, 0x3b, 0x54, 0xc1, 0x45, 0x3b, 0x22, 0x52, 0xf8, 0x3a, 0x3c, 0xf0, + 0x18, 0x3b, 0x44, 0x4e, 0x1b, 0x3b, 0xb3, 0xe2, 0x42, 0x3b, 0x88, 0x59, 0x30, + 0x3b, 0x73, 0x95, 0x4f, 0x3b, 0xbb, 0x01, 0x15, 0x3b, 0xcd, 0x24, 0x31, 0x3b, + 0xf2, 0x02, 0x27, 0x3b, 0x99, 0xce, 0x56, 0x3b, 0x09, 0x4d, 0x3a, 0x3b, 0xbe, + 0xeb, 0x35, 0x3b, 0xb7, 0x9d, 0x2b, 0x3b, 0x7d, 0xa8, 0x46, 0x3b, 0xea, 0xe9, + 0x4a, 0x3b, 0xb1, 0xa8, 0x4e, 0x3b, 0x25, 0x29, 0x2a, 0x3b, 0x61, 0x04, 0x2c, + 0x3b, 0xaf, 0x65, 0x28, 0x3b, 0xdc, 0x84, 0x6c, 0x3b, 0x77, 0x23, 0x30, 0x3b, + 0xc8, 0x82, 0x26, 0x3b, 0x70, 0xe0, 0x33, 0x3b, 0x71, 0xbe, 0x43, 0x3b, 0x3c, + 0xa3, 0x4b, 0x3b, 0x53, 0xda, 0xfe, 0x3a, 0x5a, 0x12, 0x02, 0x3b, 0xc8, 0xf3, + 0x17, 0x3b, 0x4e, 0x5a, 0x29, 0x3b, 0xc8, 0x4c, 0x1d, 0x3b, 0x4b, 0xde, 0x3f, + 0x3b, 0xf6, 0x54, 0x0f, 0x3b, 0x85, 0x17, 0x26, 0x3b, 0xa8, 0x0a, 0x6a, 0x3b, + 0x96, 0x03, 0x32, 0x3b, 0xfa, 0x3e, 0x04, 0x3b, 0x34, 0x14, 0x1b, 0x3b, 0xb4, + 0x0e, 0x89, 0x3b, 0x99, 0xe1, 0x11, 0x3b, 0xaa, 0x64, 0x4c, 0x3b, 0x2d, 0x09, + 0x14, 0x3b, 0xe1, 0xe1, 0x53, 0x3b, 0xac, 0x96, 0x37, 0x3b, 0xd6, 0xe7, 0x2d, + 0x3b, 0xe9, 0x42, 0x27, 0x3b, 0xf9, 0x41, 0x1f, 0x3b, 0x05, 0xb8, 0x46, 0x3b, + 0x37, 0x95, 0x11, 0x3b, 0xe6, 0x89, 0x1d, 0x3b, 0xee, 0x61, 0x11, 0x3b, 0xac, + 0x0a, 0x48, 0x3b, 0x50, 0xad, 0x87, 0x3b, 0x7c, 0x67, 0x05, 0x3b, 0x59, 0x7b, + 0xf7, 0x3a, 0xcd, 0xce, 0x0e, 0x3b, 0x2b, 0x8b, 0x7f, 0x3b, 0x13, 0x6a, 0x06, + 0x3b, 0x0c, 0x0e, 0x1f, 0x3b, 0x9d, 0x29, 0x51, 0x3b, 0xb0, 0xc8, 0x1e, 0x3b, + 0x42, 0x82, 0x3d, 0x3b, 0x76, 0x28, 0x21, 0x3b, 0x00, 0x00, 0x2e, 0x3b, 0x37, + 0xd8, 0x11, 0x3b, 0xeb, 0xf0, 0x36, 0x3b, 0x08, 0x7f, 0x4f, 0x3b, 0xbb, 0xb5, + 0x37, 0x3b, 0x2b, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, + 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x37, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x66, 0x9a, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x68, 0x06, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0xc2, 0x93, 0xff, 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x63, 0x1a, 0x98, 0x3b, 0xf0, 0xca, 0xdf, 0x3b, 0x6a, 0x36, 0xdc, + 0x3b, 0x7a, 0x8b, 0x16, 0x3c, 0xd6, 0xce, 0xf4, 0x3b, 0xef, 0x99, 0x74, 0x3b, + 0xcd, 0x1e, 0xb4, 0x3b, 0x29, 0xd1, 0x16, 0x3c, 0x55, 0xbd, 0xbe, 0x3b, 0xa3, + 0xf3, 0xb9, 0x3b, 0x43, 0xb1, 0x0a, 0x3c, 0x9e, 0x35, 0x09, 0x3c, 0xc9, 0xd2, + 0x31, 0x3c, 0x99, 0xed, 0x8a, 0x3c, 0x32, 0x87, 0xc2, 0x3b, 0x50, 0x41, 0xee, + 0x3b, 0x20, 0x90, 0x16, 0x3c, 0x65, 0x1b, 0x17, 0x3c, 0xa5, 0xc8, 0xf6, 0x3b, + 0x64, 0x68, 0x4e, 0x3c, 0xda, 0x71, 0x2a, 0x3c, 0x00, 0xd8, 0x0b, 0x3c, 0x3e, + 0x58, 0x22, 0x3c, 0x9b, 0x30, 0xb6, 0x3b, 0x7c, 0x9a, 0x82, 0x3b, 0x52, 0x52, + 0xd6, 0x3b, 0xfe, 0xe9, 0xc3, 0x3b, 0x5f, 0x56, 0x06, 0x3c, 0xef, 0xa4, 0xd4, + 0x3b, 0x97, 0x95, 0x1f, 0x3c, 0xc2, 0x46, 0x9b, 0x3b, 0xcc, 0x44, 0xc6, 0x3b, + 0xa7, 0xc1, 0xaf, 0x3b, 0x02, 0x07, 0xf0, 0x3b, 0xc1, 0xcf, 0xe5, 0x3b, 0x71, + 0x1c, 0x14, 0x3c, 0x7d, 0xff, 0xb3, 0x3b, 0xa4, 0xb6, 0xf3, 0x3b, 0xf4, 0x81, + 0xda, 0x3b, 0xab, 0xa7, 0xbb, 0x3b, 0xef, 0xd8, 0xc9, 0x3b, 0xa1, 0x31, 0x02, + 0x3c, 0x71, 0xfb, 0xc1, 0x3b, 0x91, 0xd6, 0xc2, 0x3b, 0x67, 0x8b, 0xcf, 0x3b, + 0xc8, 0x0b, 0x8f, 0x3b, 0xbf, 0x2e, 0xdb, 0x3b, 0x70, 0xe7, 0x1e, 0x3c, 0x08, + 0x47, 0x25, 0x3c, 0xd4, 0xe6, 0xeb, 0x3b, 0x60, 0xf5, 0xcd, 0x3b, 0xde, 0xca, + 0x00, 0x3c, 0xbb, 0x22, 0xd0, 0x3b, 0xd5, 0x0d, 0xc4, 0x3b, 0x5c, 0x68, 0xbb, + 0x3b, 0x92, 0x93, 0xb2, 0x3b, 0x77, 0x86, 0xfa, 0x3b, 0x11, 0x85, 0x27, 0x3c, + 0x14, 0x4d, 0xd7, 0x3b, 0x49, 0x13, 0xeb, 0x3b, 0x56, 0x35, 0x0c, 0x3c, 0xcc, + 0x92, 0xae, 0x3b, 0x36, 0x68, 0x2f, 0x3c, 0x52, 0xaf, 0x4c, 0x3c, 0xa0, 0xd9, + 0xad, 0x3b, 0x49, 0x40, 0x93, 0x3b, 0xfa, 0x40, 0x27, 0x3c, 0x35, 0xcd, 0xb1, + 0x3b, 0xa4, 0xaa, 0xdb, 0x3b, 0x45, 0xfa, 0x01, 0x3c, 0xc4, 0x09, 0x97, 0x3b, + 0x2d, 0x12, 0x1e, 0x3c, 0x80, 0xf7, 0xf2, 0x3b, 0x0e, 0xee, 0xd1, 0x3b, 0x93, + 0xc7, 0x3e, 0x3c, 0xa5, 0xc5, 0x78, 0x3c, 0x81, 0xa1, 0xcd, 0x3b, 0x95, 0x7f, + 0x84, 0x3b, 0xac, 0xfb, 0xc0, 0x3b, 0x7b, 0x9e, 0xc9, 0x3b, 0xb4, 0x94, 0x0e, + 0x3c, 0xbe, 0x02, 0x24, 0x3c, 0x26, 0xaf, 0x03, 0x3c, 0x1d, 0x55, 0xb6, 0x3b, + 0x84, 0x0c, 0xa4, 0x3b, 0xe1, 0x22, 0xf5, 0x3b, 0xaf, 0xf6, 0x16, 0x3c, 0xf4, + 0x0e, 0x02, 0x3c, 0x8f, 0x59, 0xb8, 0x3b, 0x5a, 0x77, 0x81, 0x3c, 0xa0, 0x61, + 0x03, 0x3c, 0xdf, 0x05, 0xbc, 0x3b, 0x56, 0x04, 0xc6, 0x3b, 0x8d, 0x0b, 0xc2, + 0x3b, 0x34, 0xd6, 0xd1, 0x3b, 0x06, 0xd9, 0xf0, 0x3b, 0xc8, 0x23, 0x01, 0x3c, + 0x8d, 0x16, 0x17, 0x3c, 0x01, 0x15, 0xaa, 0x3b, 0x1e, 0x97, 0x1b, 0x3c, 0x01, + 0x15, 0xde, 0x3b, 0x84, 0x0b, 0xd7, 0x3b, 0x61, 0x98, 0x24, 0x3c, 0x52, 0x21, + 0xa2, 0x3b, 0x00, 0x53, 0xab, 0x3b, 0xca, 0x54, 0xc5, 0x3b, 0x2f, 0xf5, 0xf1, + 0x3b, 0x72, 0x53, 0x8f, 0x3b, 0x73, 0xbd, 0xca, 0x3b, 0x3c, 0x53, 0x13, 0x3c, + 0xa8, 0x4d, 0x45, 0x3c, 0xd9, 0x26, 0x5a, 0x3c, 0xb7, 0xf1, 0xbf, 0x3b, 0x0f, + 0xa2, 0x3e, 0x3c, 0x6e, 0xb5, 0xd3, 0x3b, 0x30, 0xa8, 0x3c, 0x3c, 0x1c, 0xfc, + 0xcd, 0x3b, 0x0c, 0x94, 0x1d, 0x3c, 0x09, 0x92, 0xdb, 0x3b, 0xcc, 0xad, 0x1f, + 0x3c, 0x6e, 0x27, 0xf6, 0x3b, 0x01, 0x23, 0x89, 0x3b, 0x57, 0xa7, 0x9b, 0x3b, + 0x23, 0x4a, 0x95, 0x3b, 0x53, 0x0b, 0x1a, 0x3c, 0xa6, 0x56, 0x00, 0x3c, 0x3c, + 0x50, 0x08, 0x3c, 0xd0, 0x0e, 0x91, 0x3b, 0x35, 0x00, 0x00, 0x00, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x37, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xea, 0xa0, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x58, 0x06, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, + 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6c, 0xa7, 0xff, 0xff, 0x10, 0x04, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, + 0x00, 0x00, 0xdb, 0x16, 0x77, 0x3b, 0x81, 0x65, 0x4c, 0x3b, 0xe0, 0x30, 0xbc, + 0x3b, 0x34, 0x9a, 0x7d, 0x3b, 0xad, 0x5a, 0x4b, 0x3b, 0x64, 0xaf, 0x9d, 0x3b, + 0x60, 0xcb, 0x1d, 0x3b, 0x9d, 0xf2, 0x52, 0x3b, 0xef, 0x67, 0x91, 0x3b, 0x2c, + 0xc1, 0x5e, 0x3b, 0x8d, 0x8e, 0x4b, 0x3b, 0x3e, 0x7a, 0x8d, 0x3b, 0x64, 0x7e, + 0x32, 0x3b, 0x35, 0x8d, 0xf5, 0x3a, 0x39, 0x88, 0x28, 0x3b, 0x69, 0x08, 0x39, + 0x3b, 0xb7, 0xa5, 0x35, 0x3b, 0x0e, 0x28, 0x46, 0x3b, 0x77, 0x11, 0x79, 0x3b, + 0xbf, 0x20, 0x29, 0x3b, 0xd0, 0x29, 0x67, 0x3b, 0xff, 0x3c, 0x32, 0x3b, 0x0c, + 0x5f, 0x83, 0x3b, 0x00, 0x82, 0x87, 0x3b, 0x1c, 0x6d, 0x8f, 0x3b, 0xa2, 0xdc, + 0x3d, 0x3b, 0xd5, 0xd2, 0x58, 0x3b, 0xa0, 0x0d, 0x70, 0x3b, 0x13, 0x09, 0x4f, + 0x3b, 0x7e, 0x45, 0x86, 0x3b, 0x87, 0xbe, 0x65, 0x3b, 0xa3, 0x41, 0x44, 0x3b, + 0x85, 0x42, 0x6e, 0x3b, 0xdd, 0x83, 0x39, 0x3b, 0x70, 0xaf, 0x32, 0x3b, 0x93, + 0x27, 0x2e, 0x3b, 0x90, 0x79, 0x4f, 0x3b, 0x1b, 0x55, 0xf1, 0x3a, 0x88, 0x75, + 0x5d, 0x3b, 0x82, 0x71, 0x7c, 0x3b, 0xe2, 0x39, 0x83, 0x3b, 0x48, 0xba, 0x5d, + 0x3b, 0x93, 0x01, 0x46, 0x3b, 0xb6, 0xf1, 0x62, 0x3b, 0x46, 0xcc, 0x84, 0x3b, + 0x28, 0xbe, 0x05, 0x3b, 0xf6, 0x0c, 0x5a, 0x3b, 0x29, 0xbb, 0x5f, 0x3b, 0xaa, + 0x38, 0x17, 0x3b, 0x37, 0xeb, 0x20, 0x3b, 0x94, 0xee, 0x80, 0x3b, 0x88, 0xe9, + 0x6a, 0x3b, 0x62, 0x9f, 0x5c, 0x3b, 0x5b, 0x1e, 0x62, 0x3b, 0x3d, 0xa8, 0x46, + 0x3b, 0x9e, 0x8c, 0x49, 0x3b, 0x0a, 0x98, 0x72, 0x3b, 0x72, 0x54, 0x5b, 0x3b, + 0xfc, 0x37, 0x2f, 0x3b, 0x56, 0x08, 0x05, 0x3b, 0xfb, 0xd2, 0x44, 0x3b, 0x4f, + 0x12, 0x38, 0x3b, 0xf8, 0x62, 0x2e, 0x3b, 0xba, 0x67, 0x48, 0x3b, 0x02, 0xbc, + 0x61, 0x3b, 0xf7, 0x01, 0x5d, 0x3b, 0x80, 0xde, 0x24, 0x3b, 0x0f, 0xf2, 0x9b, + 0x3b, 0x33, 0xb9, 0x44, 0x3b, 0xe4, 0xc4, 0x41, 0x3b, 0x5e, 0x1e, 0x4a, 0x3b, + 0x20, 0x04, 0x13, 0x3b, 0x37, 0x3a, 0x5a, 0x3b, 0x5c, 0x35, 0x52, 0x3b, 0x0d, + 0xf3, 0x4a, 0x3b, 0x57, 0xf5, 0x06, 0x3b, 0x9f, 0xdf, 0x25, 0x3b, 0x8c, 0x98, + 0x35, 0x3b, 0xd5, 0x98, 0x33, 0x3b, 0x8c, 0x82, 0x30, 0x3b, 0xaa, 0x7a, 0x60, + 0x3b, 0x3a, 0x6b, 0x51, 0x3b, 0x24, 0xdf, 0x7c, 0x3b, 0xe8, 0xe2, 0x4a, 0x3b, + 0xca, 0x46, 0x43, 0x3b, 0x7f, 0x20, 0x50, 0x3b, 0x6b, 0x23, 0x17, 0x3b, 0x89, + 0xcb, 0x49, 0x3b, 0x85, 0x69, 0x40, 0x3b, 0x70, 0x71, 0x22, 0x3b, 0x41, 0x72, + 0x73, 0x3b, 0x43, 0xf2, 0x29, 0x3b, 0xb4, 0xa5, 0x5d, 0x3b, 0x6f, 0xfb, 0x21, + 0x3b, 0x37, 0x81, 0x88, 0x3b, 0x38, 0xc1, 0x24, 0x3b, 0xec, 0x46, 0x1d, 0x3b, + 0xd5, 0x05, 0x7b, 0x3b, 0xfa, 0xad, 0x49, 0x3b, 0x38, 0x00, 0x5c, 0x3b, 0x42, + 0xa2, 0x82, 0x3b, 0xca, 0x7f, 0x87, 0x3b, 0xf8, 0xf8, 0x5e, 0x3b, 0xa9, 0xa1, + 0x72, 0x3b, 0xdd, 0x61, 0x67, 0x3b, 0xc2, 0xe2, 0x20, 0x3b, 0x3d, 0x06, 0x35, + 0x3b, 0x6a, 0x6f, 0x48, 0x3b, 0x49, 0x28, 0x4b, 0x3b, 0x13, 0x71, 0x5b, 0x3b, + 0x57, 0x39, 0x70, 0x3b, 0x3f, 0x6c, 0x08, 0x3b, 0x99, 0xc7, 0x41, 0x3b, 0x64, + 0x48, 0x45, 0x3b, 0x02, 0x34, 0x35, 0x3b, 0x8f, 0x25, 0x51, 0x3b, 0xc4, 0xfe, + 0x5a, 0x3b, 0x8e, 0xa5, 0x1e, 0x3b, 0xb6, 0xc5, 0x3a, 0x3b, 0x33, 0xad, 0xfb, + 0x3a, 0x2b, 0xce, 0x43, 0x3b, 0xf4, 0xa4, 0x1d, 0x3b, 0xbf, 0xd2, 0x4e, 0x3b, + 0xeb, 0x6a, 0x92, 0x3b, 0x17, 0xe4, 0x89, 0x3b, 0xa8, 0x88, 0x28, 0x3b, 0x04, + 0x1c, 0x55, 0x3b, 0x98, 0xc7, 0x46, 0x3b, 0x2b, 0x00, 0x00, 0x00, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x36, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, + 0x61, 0x64, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x5e, 0xa7, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x09, 0x68, 0x03, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x24, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xba, 0xa0, 0xff, 0xff, 0x14, + 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x01, 0xb0, 0x90, 0x3b, 0xe7, 0x75, 0x88, 0x3b, 0xda, 0xf6, 0x64, + 0x3b, 0xf3, 0xa3, 0x78, 0x3b, 0xae, 0xc0, 0x3c, 0x3b, 0x98, 0xf3, 0x41, 0x3b, + 0x75, 0xe2, 0xa1, 0x3b, 0x49, 0xfe, 0x7a, 0x3b, 0x71, 0x95, 0x77, 0x3b, 0x26, + 0xd0, 0xb1, 0x3b, 0x93, 0xf9, 0x76, 0x3b, 0x29, 0x45, 0x87, 0x3b, 0x9a, 0x05, + 0x89, 0x3b, 0x2c, 0xf3, 0x7f, 0x3b, 0x9b, 0xd5, 0x7b, 0x3b, 0xd2, 0x29, 0xf3, + 0x3b, 0xf1, 0x7e, 0x6c, 0x3b, 0x99, 0xf1, 0x1c, 0x3c, 0x86, 0x53, 0x73, 0x3b, + 0x38, 0x28, 0x8f, 0x3b, 0xbe, 0x20, 0x64, 0x3b, 0xb5, 0x96, 0x82, 0x3b, 0x84, + 0x0a, 0xb7, 0x3b, 0xa5, 0xa4, 0x5b, 0x3b, 0x1b, 0x96, 0x9d, 0x3b, 0x12, 0x99, + 0x6f, 0x3b, 0xa0, 0xcd, 0x94, 0x3b, 0x62, 0x2c, 0x7f, 0x3b, 0x90, 0x6c, 0x7e, + 0x3b, 0xdc, 0xc6, 0x95, 0x3b, 0xcd, 0x97, 0x62, 0x3b, 0x8a, 0xf8, 0x80, 0x3b, + 0x53, 0x91, 0x64, 0x3b, 0xf9, 0xb9, 0x70, 0x3b, 0x93, 0x39, 0xf7, 0x3b, 0xe4, + 0x72, 0xac, 0x3b, 0x29, 0x52, 0x95, 0x3b, 0x01, 0xf7, 0x98, 0x3b, 0x7a, 0xce, + 0x4a, 0x3b, 0xb9, 0x52, 0x50, 0x3b, 0x6e, 0x9f, 0x71, 0x3b, 0x03, 0x4a, 0xa8, + 0x3b, 0x34, 0xdc, 0xa3, 0x3b, 0xd3, 0xad, 0x93, 0x3b, 0xe2, 0x45, 0x63, 0x3b, + 0xa6, 0x4a, 0x93, 0x3b, 0x3a, 0x6b, 0x54, 0x3b, 0xd9, 0x9f, 0x97, 0x3b, 0xef, + 0x53, 0x77, 0x3b, 0x87, 0x02, 0x8b, 0x3b, 0x8b, 0xd4, 0x33, 0x3b, 0x1b, 0x36, + 0x99, 0x3b, 0x90, 0x19, 0xcd, 0x3b, 0xda, 0x5d, 0xc1, 0x3b, 0x5d, 0xee, 0x68, + 0x3b, 0x7d, 0x5b, 0x83, 0x3b, 0x30, 0x76, 0xd9, 0x3b, 0xb6, 0x23, 0x83, 0x3b, + 0x57, 0xdd, 0x45, 0x3b, 0xfc, 0xdc, 0x47, 0x3b, 0x90, 0x3f, 0x3d, 0x3b, 0x20, + 0x3a, 0x8e, 0x3b, 0x35, 0x03, 0x88, 0x3b, 0xe1, 0xf2, 0xd9, 0x3b, 0x35, 0x00, + 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x36, 0x5f, 0x64, 0x65, 0x70, + 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, + 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, + 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0xe2, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x58, 0x03, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x64, 0xb1, + 0xff, 0xff, 0x10, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0xa4, 0xc8, 0x2b, 0x3b, 0x4e, 0x6a, 0x7a, 0x3b, 0x4b, 0x5c, 0x8d, 0x3b, + 0x1a, 0x86, 0xa4, 0x3b, 0x9d, 0x00, 0x62, 0x3b, 0x17, 0x46, 0x39, 0x3b, 0xc4, + 0xca, 0x6a, 0x3b, 0x39, 0x91, 0x59, 0x3b, 0x38, 0xdf, 0x8d, 0x3b, 0x6b, 0x33, + 0x81, 0x3b, 0x7e, 0x86, 0x7e, 0x3b, 0xbc, 0x51, 0x61, 0x3b, 0x39, 0xea, 0x80, + 0x3b, 0x43, 0x3c, 0x1f, 0x3b, 0x4e, 0xb7, 0xa8, 0x3b, 0x64, 0x51, 0x0f, 0x3b, + 0xf8, 0x3f, 0x81, 0x3b, 0xe5, 0x7b, 0x10, 0x3b, 0x4d, 0x5b, 0x28, 0x3b, 0x8e, + 0xe7, 0x97, 0x3b, 0xb4, 0xef, 0x6f, 0x3b, 0xc2, 0xd6, 0x55, 0x3b, 0x89, 0x56, + 0x6a, 0x3b, 0x44, 0xc6, 0x70, 0x3b, 0xb4, 0x0a, 0x2c, 0x3b, 0xc6, 0xc2, 0x1c, + 0x3b, 0x4b, 0xb3, 0x9b, 0x3b, 0x8c, 0x98, 0x61, 0x3b, 0x98, 0x37, 0x90, 0x3b, + 0x51, 0xaa, 0x5b, 0x3b, 0x32, 0x7e, 0x81, 0x3b, 0x90, 0x3e, 0x5d, 0x3b, 0x34, + 0x88, 0x41, 0x3b, 0x78, 0x6b, 0x59, 0x3b, 0xeb, 0xb0, 0x4c, 0x3b, 0x3c, 0x78, + 0x3c, 0x3b, 0xcb, 0x77, 0x58, 0x3b, 0x77, 0x8c, 0x16, 0x3b, 0xbb, 0xad, 0x2c, + 0x3b, 0xc3, 0x8c, 0x8b, 0x3b, 0x26, 0xb3, 0x82, 0x3b, 0xd6, 0x40, 0x6a, 0x3b, + 0x8e, 0xe1, 0x38, 0x3b, 0x7e, 0xd5, 0x6e, 0x3b, 0x10, 0xe0, 0x74, 0x3b, 0xc5, + 0x58, 0x60, 0x3b, 0xf5, 0xaa, 0x3b, 0x3b, 0xbd, 0xde, 0x1c, 0x3b, 0xe8, 0xcc, + 0x45, 0x3b, 0xbf, 0x14, 0xfb, 0x3a, 0x37, 0xe0, 0x67, 0x3b, 0xc4, 0xe3, 0x8d, + 0x3b, 0xf7, 0xbe, 0xca, 0x3a, 0xdb, 0x1a, 0x0e, 0x3b, 0xb8, 0xa4, 0x6a, 0x3b, + 0x4b, 0xa5, 0x59, 0x3b, 0x90, 0xf5, 0x4f, 0x3b, 0xbc, 0xdd, 0x6a, 0x3b, 0x9d, + 0x26, 0x66, 0x3b, 0x28, 0x0d, 0x5e, 0x3b, 0x58, 0xa2, 0x7e, 0x3b, 0x86, 0x80, + 0x83, 0x3b, 0x03, 0x4a, 0x14, 0x3b, 0xf4, 0xda, 0x12, 0x3b, 0x2b, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x35, 0x5f, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, + 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x56, 0xae, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x68, 0x03, 0x00, 0x00, 0x4d, + 0x00, 0x00, 0x00, 0x24, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb2, 0xa7, + 0xff, 0xff, 0x14, 0x02, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0xaf, 0x6d, 0xa7, 0x3b, 0x6f, 0xfb, 0x1a, 0x3c, + 0x4f, 0x65, 0xf0, 0x3b, 0x64, 0x5c, 0xf6, 0x3b, 0xd1, 0xef, 0x18, 0x3c, 0x0b, + 0xb1, 0x8f, 0x3b, 0xd0, 0x97, 0xb1, 0x3b, 0x49, 0xed, 0x48, 0x3b, 0xc5, 0x55, + 0x50, 0x3c, 0xff, 0xff, 0x6c, 0x3c, 0x09, 0x61, 0x8d, 0x3c, 0xd3, 0xcb, 0x17, + 0x3c, 0x51, 0x94, 0x14, 0x3c, 0xb9, 0xd6, 0x7c, 0x3b, 0xd5, 0xff, 0xd5, 0x3b, + 0x69, 0x20, 0x00, 0x3c, 0x8b, 0x38, 0xbe, 0x3b, 0xa6, 0xe9, 0x9a, 0x3b, 0x9a, + 0xea, 0xd7, 0x3b, 0xd0, 0x5e, 0x9d, 0x3b, 0xfa, 0x04, 0x95, 0x3b, 0x76, 0xe1, + 0xc0, 0x3b, 0xc1, 0x6e, 0x8b, 0x3c, 0xf0, 0x34, 0xcb, 0x3b, 0xca, 0x60, 0xb1, + 0x3b, 0x79, 0xa5, 0x64, 0x3c, 0x3b, 0x85, 0x38, 0x3c, 0xe2, 0x8a, 0x95, 0x3b, + 0xec, 0xbb, 0xc0, 0x3b, 0xfb, 0xa3, 0xe9, 0x3b, 0x14, 0x3d, 0xb1, 0x3b, 0x1d, + 0x89, 0xe8, 0x3b, 0x06, 0x7a, 0x8b, 0x3b, 0x2f, 0x32, 0xb6, 0x3b, 0xcc, 0x2e, + 0xd7, 0x3b, 0x32, 0xc7, 0x68, 0x3b, 0xd7, 0x22, 0x33, 0x3c, 0x1e, 0x40, 0x42, + 0x3c, 0x6e, 0xb4, 0xb6, 0x3b, 0x28, 0x77, 0xb0, 0x3b, 0x49, 0xaa, 0xed, 0x3b, + 0x4f, 0x78, 0xe2, 0x3b, 0x85, 0xe9, 0x23, 0x3c, 0x5e, 0xe9, 0xd9, 0x3b, 0x6d, + 0xab, 0x7a, 0x3b, 0x21, 0x29, 0x5f, 0x3b, 0xb7, 0x50, 0x3e, 0x3c, 0xf7, 0xc3, + 0x84, 0x3b, 0x18, 0x38, 0x2b, 0x3c, 0x01, 0x11, 0x12, 0x3c, 0x78, 0xe8, 0xf3, + 0x3b, 0x7d, 0x96, 0x0d, 0x3c, 0xb6, 0x66, 0x56, 0x3c, 0x79, 0x61, 0xb3, 0x3b, + 0xea, 0x0d, 0x92, 0x3b, 0xb3, 0xe3, 0xa9, 0x3b, 0xe0, 0xc5, 0x0c, 0x3c, 0xce, + 0x38, 0xc8, 0x3b, 0xb8, 0x38, 0x9b, 0x3b, 0x23, 0x35, 0xa1, 0x3b, 0x5e, 0x18, + 0x4a, 0x3c, 0x63, 0x54, 0x8a, 0x3b, 0x17, 0xe9, 0xb7, 0x3b, 0xfa, 0x64, 0x3d, + 0x3c, 0x35, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x35, 0x5f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, + 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0xda, 0xb1, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x58, 0x03, + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x5c, 0xb8, 0xff, 0xff, 0x10, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x9e, 0x9c, 0x8a, 0x3b, 0xa1, 0xfb, 0x2f, 0x3b, 0x08, + 0x09, 0xa5, 0x3b, 0xf9, 0xb5, 0x8a, 0x3b, 0x37, 0xe2, 0x55, 0x3b, 0x57, 0x24, + 0x72, 0x3b, 0x09, 0xef, 0x9f, 0x3b, 0xa9, 0xe2, 0x83, 0x3b, 0x95, 0x08, 0x35, + 0x3b, 0x15, 0x8c, 0x8c, 0x3b, 0xb7, 0x43, 0x15, 0x3b, 0xa3, 0xf2, 0x9f, 0x3b, + 0xed, 0xf3, 0x33, 0x3b, 0x8a, 0x02, 0x8a, 0x3b, 0xcc, 0xf5, 0xad, 0x3b, 0x31, + 0x32, 0x03, 0x3c, 0x5c, 0x78, 0x87, 0x3b, 0x97, 0xb7, 0x82, 0x3b, 0xae, 0xbb, + 0x8c, 0x3b, 0x1a, 0x38, 0x3c, 0x3b, 0xf6, 0xc9, 0xe6, 0x3b, 0xa1, 0x15, 0x54, + 0x3b, 0x80, 0x78, 0x5c, 0x3b, 0xec, 0x30, 0xc3, 0x3b, 0x58, 0x81, 0xba, 0x3b, + 0x74, 0x73, 0xe2, 0x3a, 0x5c, 0x1b, 0x2e, 0x3b, 0x52, 0x39, 0xd7, 0x3b, 0x96, + 0xb9, 0xb3, 0x3b, 0x71, 0x24, 0x83, 0x3b, 0x20, 0x23, 0x8a, 0x3b, 0x48, 0xf7, + 0xc2, 0x3b, 0x4d, 0x5e, 0xaa, 0x3b, 0x32, 0x14, 0x22, 0x3b, 0x6a, 0x7e, 0x6e, + 0x3b, 0x2e, 0x1c, 0xdf, 0x3b, 0x54, 0x42, 0x1e, 0x3b, 0x46, 0x10, 0x24, 0x3b, + 0x0a, 0xad, 0x6f, 0x3b, 0x22, 0x6a, 0x35, 0x3b, 0xc4, 0x9b, 0x5f, 0x3b, 0xfd, + 0xd4, 0x8d, 0x3b, 0x7e, 0xed, 0x53, 0x3b, 0x09, 0xdb, 0x8e, 0x3b, 0xbd, 0xad, + 0xce, 0x3b, 0xf2, 0xa0, 0xd0, 0x3b, 0xea, 0x53, 0x06, 0x3b, 0xc8, 0x51, 0x71, + 0x3b, 0x76, 0x51, 0xad, 0x3b, 0x21, 0x81, 0x0c, 0x3c, 0x3a, 0x8c, 0x04, 0x3c, + 0xa8, 0xbe, 0x8f, 0x3b, 0x4f, 0xc3, 0x8d, 0x3b, 0x9e, 0x1c, 0x09, 0x3c, 0x17, + 0x93, 0xac, 0x3b, 0x67, 0x90, 0x98, 0x3b, 0x7d, 0x65, 0x54, 0x3b, 0x7b, 0x0d, + 0xd5, 0x3b, 0x42, 0x1c, 0x92, 0x3b, 0xec, 0x41, 0xa6, 0x3b, 0x4a, 0x0f, 0x42, + 0x3b, 0x5c, 0x69, 0xfd, 0x3b, 0xd2, 0x9d, 0xbb, 0x3b, 0x0a, 0xbb, 0x48, 0x3b, + 0x2b, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, + 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x34, 0x5f, 0x70, + 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x4e, 0xb5, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0xe8, 0x01, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0xaa, 0xae, 0xff, 0xff, 0x14, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0e, + 0xe8, 0x3a, 0x3b, 0x06, 0xdb, 0x60, 0x3b, 0x15, 0xab, 0x2c, 0x3b, 0xc2, 0x4d, + 0x69, 0x3b, 0xed, 0xe2, 0x03, 0x3c, 0xf7, 0x38, 0x87, 0x3b, 0x43, 0xca, 0x46, + 0x3b, 0x75, 0x5e, 0x48, 0x3b, 0x1b, 0xa8, 0x47, 0x3b, 0x1a, 0x27, 0x1a, 0x3b, + 0xfa, 0xaa, 0x64, 0x3b, 0xd7, 0x95, 0x46, 0x3b, 0x29, 0x74, 0x8d, 0x3b, 0x56, + 0x3a, 0xdf, 0x3b, 0xfc, 0xdf, 0x93, 0x3b, 0x2a, 0xd8, 0x59, 0x3b, 0x3a, 0x2c, + 0x4d, 0x3b, 0x06, 0xa2, 0x3e, 0x3b, 0x56, 0xe5, 0xa0, 0x3b, 0x7c, 0x42, 0x51, + 0x3b, 0x36, 0x2c, 0x9f, 0x3b, 0x6f, 0xd4, 0x8f, 0x3b, 0x01, 0x77, 0x07, 0x3b, + 0x5a, 0xfa, 0x65, 0x3b, 0x61, 0xc0, 0xe2, 0x3b, 0x7d, 0xea, 0x78, 0x3b, 0x3d, + 0x98, 0x57, 0x3b, 0x13, 0x7d, 0x40, 0x3b, 0x60, 0xdc, 0x9b, 0x3b, 0x92, 0x50, + 0x5e, 0x3b, 0x09, 0xc6, 0x90, 0x3b, 0xe0, 0x52, 0xd7, 0x3b, 0x35, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x34, 0x5f, 0x64, 0x65, 0x70, 0x74, + 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, + 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x52, + 0xb7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0xd8, 0x01, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd4, 0xbd, 0xff, + 0xff, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x1f, 0xd1, 0x8d, 0x3b, 0x4a, 0xc4, 0xc6, 0x3b, 0x9e, + 0xc2, 0xa2, 0x3b, 0x50, 0x27, 0x83, 0x3b, 0x8f, 0xb4, 0x09, 0x3b, 0xa4, 0x9e, + 0x3b, 0x3b, 0x8d, 0xe0, 0x73, 0x3b, 0x54, 0x0e, 0x5f, 0x3b, 0xa8, 0xd7, 0xa1, + 0x3b, 0x7f, 0x7a, 0x75, 0x3b, 0x0e, 0xe9, 0xbc, 0x3b, 0xfa, 0x06, 0x60, 0x3b, + 0x12, 0x4b, 0xab, 0x3b, 0x95, 0xb8, 0xaf, 0x3b, 0x37, 0xc2, 0x54, 0x3b, 0xbe, + 0x2b, 0x7b, 0x3b, 0xdd, 0xc9, 0x83, 0x3b, 0xb2, 0x00, 0x9b, 0x3b, 0x6c, 0x06, + 0xbe, 0x3b, 0x47, 0xd2, 0x9d, 0x3b, 0x27, 0xbe, 0xdc, 0x3b, 0xe2, 0x70, 0x84, + 0x3b, 0xc7, 0xd1, 0x6e, 0x3b, 0x4f, 0x2c, 0xa8, 0x3b, 0xf4, 0x02, 0xd2, 0x3b, + 0x9c, 0xc2, 0x04, 0x3c, 0x0b, 0x8d, 0xd7, 0x3b, 0x16, 0x65, 0xb0, 0x3b, 0xaf, + 0xc2, 0x3a, 0x3b, 0xd6, 0xbb, 0x7c, 0x3b, 0x16, 0x8c, 0x98, 0x3b, 0xbb, 0xd1, + 0x7e, 0x3b, 0x2b, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, + 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x33, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x46, 0xb9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0xe8, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0xa2, 0xb2, 0xff, 0xff, 0x14, 0x01, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x87, 0x89, 0x04, 0x3c, 0x79, 0xd0, 0x1d, 0x3c, 0x68, 0xa3, 0xe5, 0x3b, + 0xb9, 0x26, 0x22, 0x3c, 0x98, 0xca, 0x50, 0x3c, 0x30, 0xc4, 0xc5, 0x3c, 0x27, + 0x84, 0x8f, 0x3b, 0x2d, 0x0a, 0xeb, 0x3b, 0xbe, 0xf6, 0xee, 0x3b, 0xf0, 0x0c, + 0x8b, 0x3c, 0xc4, 0xd5, 0xb1, 0x3c, 0xcb, 0x44, 0xdc, 0x3b, 0x23, 0x2a, 0x34, + 0x3b, 0xcc, 0x23, 0x57, 0x3c, 0x95, 0x75, 0x0a, 0x3c, 0xdc, 0xdd, 0x06, 0x3b, + 0x15, 0x63, 0xe5, 0x3b, 0x3b, 0xa4, 0x8b, 0x3b, 0x01, 0x47, 0xb3, 0x3c, 0x17, + 0x08, 0xc8, 0x3c, 0xde, 0x85, 0xb4, 0x3b, 0x47, 0x1d, 0xc0, 0x3c, 0x5e, 0xf2, + 0x4f, 0x3b, 0x0c, 0x34, 0xd4, 0x3b, 0xc9, 0x45, 0xc7, 0x3b, 0x2a, 0x86, 0xf0, + 0x3c, 0x46, 0x7c, 0xf8, 0x3b, 0x57, 0x56, 0x52, 0x3b, 0x04, 0xf4, 0xa6, 0x3b, + 0xec, 0x8d, 0xe0, 0x3b, 0x44, 0x9f, 0xd3, 0x3b, 0x4d, 0x19, 0x38, 0x3c, 0x35, + 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x33, 0x5f, 0x64, 0x65, + 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, + 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x4a, 0xbb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0xd8, 0x01, 0x00, 0x00, + 0x3d, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xcc, + 0xc1, 0xff, 0xff, 0x10, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x5c, 0xc7, 0x3c, 0x3c, 0x66, 0x8c, 0x83, + 0x3b, 0xd4, 0x22, 0xcd, 0x3b, 0x48, 0x6e, 0xd1, 0x3b, 0xdc, 0x08, 0xa3, 0x3b, + 0x61, 0x10, 0xd1, 0x3a, 0x79, 0x0b, 0xaf, 0x3b, 0x3a, 0x7e, 0xe1, 0x3b, 0x30, + 0x6c, 0x76, 0x3b, 0xfb, 0x99, 0x5e, 0x3b, 0xf0, 0xc4, 0xe5, 0x3a, 0x1c, 0xc4, + 0xa8, 0x3b, 0xb1, 0x3a, 0xd0, 0x3b, 0x88, 0x11, 0xa7, 0x3b, 0xec, 0xf4, 0x20, + 0x3c, 0xe3, 0xd4, 0x3b, 0x3c, 0xab, 0xed, 0xd9, 0x3b, 0x95, 0xdb, 0xfa, 0x3b, + 0x66, 0x0a, 0x11, 0x3b, 0x9b, 0x16, 0x4e, 0x3b, 0x24, 0xb6, 0xb0, 0x3b, 0xa5, + 0xc7, 0xfd, 0x3a, 0xac, 0x74, 0xc1, 0x3b, 0xbc, 0x52, 0xdc, 0x3b, 0x0a, 0xb5, + 0xb0, 0x3b, 0x49, 0x2c, 0x92, 0x3a, 0x60, 0x8d, 0xb4, 0x3b, 0x7f, 0x7e, 0xef, + 0x3b, 0x9a, 0x83, 0x1b, 0x3c, 0x4a, 0x50, 0x9a, 0x3b, 0xd4, 0x4d, 0x08, 0x3c, + 0x80, 0x79, 0x71, 0x3b, 0x2b, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x32, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3e, 0xbd, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x09, 0x28, 0x01, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x9a, 0xb6, 0xff, 0xff, 0x94, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0xf3, 0xae, 0x65, 0x3b, 0x76, 0xd3, 0x46, 0x3b, + 0x47, 0x81, 0xa1, 0x3b, 0xa1, 0x23, 0x83, 0x3b, 0x2e, 0x71, 0xbf, 0x3b, 0xbf, + 0x4c, 0x9d, 0x3b, 0x00, 0xc1, 0xa5, 0x3b, 0x36, 0x82, 0x2f, 0x3b, 0x9a, 0xaf, + 0xa4, 0x3b, 0x3a, 0xd4, 0x11, 0x3c, 0x22, 0x3a, 0x44, 0x3b, 0xb5, 0x66, 0xa2, + 0x3b, 0xef, 0x6f, 0x6c, 0x3b, 0x28, 0xc6, 0x65, 0x3b, 0xb1, 0x23, 0xda, 0x3b, + 0x85, 0x20, 0xed, 0x3b, 0x35, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, + 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, + 0x5f, 0x32, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x82, 0xbe, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x09, 0x18, 0x01, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0xc5, 0xff, 0xff, 0x90, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x09, 0x89, 0x62, 0x3c, 0x4d, 0xd2, 0x10, 0x3c, 0xc6, 0x64, 0x87, 0x3c, 0xc1, + 0x43, 0xee, 0x3b, 0x0a, 0x21, 0x47, 0x3c, 0x41, 0xa2, 0x49, 0x3c, 0x5e, 0x4c, + 0x00, 0x3c, 0x22, 0x6b, 0x0c, 0x3c, 0xb3, 0x07, 0x6a, 0x3c, 0x28, 0xb4, 0x07, + 0x3c, 0xb3, 0xc7, 0x52, 0x3c, 0x27, 0x63, 0x03, 0x3c, 0x87, 0xac, 0x46, 0x3c, + 0xe4, 0xd4, 0xe3, 0x3b, 0x53, 0xf1, 0x04, 0x3c, 0x58, 0xb6, 0x32, 0x3c, 0x2b, + 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, + 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x5f, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x00, 0xb6, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0xc8, 0x00, 0x00, + 0x00, 0x3c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x12, 0xb9, 0xff, 0xff, 0x54, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0xc6, 0x53, 0x8c, 0x3b, 0xca, 0x97, 0xca, 0x3b, 0x35, 0x82, 0x15, 0x3e, + 0xcd, 0x4b, 0x3e, 0x3b, 0x6d, 0x31, 0x70, 0x3c, 0x71, 0x98, 0x2d, 0x3b, 0x91, + 0xa1, 0xf1, 0x3b, 0x42, 0xa8, 0xa3, 0x3e, 0x35, 0x00, 0x00, 0x00, 0x4d, 0x6f, + 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, + 0x76, 0x32, 0x64, 0x5f, 0x31, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9a, 0xc0, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x09, 0x58, 0x0c, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c, + 0x0c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xc7, 0xff, 0xff, 0x0c, 0x08, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x35, 0xc1, 0x5c, 0x3a, 0xe5, + 0xef, 0xaa, 0x3a, 0xfb, 0x29, 0x95, 0x3a, 0xd6, 0x76, 0x09, 0x3a, 0x9a, 0xd5, + 0x99, 0x3a, 0x88, 0x58, 0x2f, 0x3a, 0xe3, 0x21, 0x42, 0x3a, 0xe5, 0x62, 0x95, + 0x3a, 0xfa, 0xa3, 0x5e, 0x3a, 0x66, 0x7c, 0x87, 0x3a, 0xef, 0x0d, 0x5d, 0x3a, + 0x96, 0x73, 0x31, 0x3a, 0x87, 0x13, 0x8d, 0x3a, 0x55, 0xee, 0x38, 0x3a, 0x8f, + 0x82, 0x34, 0x3a, 0x09, 0x82, 0x56, 0x3a, 0x8f, 0x70, 0x67, 0x3a, 0x8d, 0xca, + 0x2d, 0x3a, 0xf5, 0x8b, 0x1c, 0x3a, 0xcf, 0x64, 0x7c, 0x3a, 0xda, 0xb7, 0x12, + 0x3a, 0xff, 0xd8, 0x46, 0x3a, 0x72, 0xa8, 0x80, 0x3a, 0xb8, 0x32, 0x48, 0x3a, + 0x95, 0xdf, 0x97, 0x3a, 0xe1, 0x48, 0x42, 0x3a, 0xad, 0xfc, 0xb2, 0x3a, 0x0f, + 0xfe, 0x82, 0x3a, 0xec, 0xcc, 0x18, 0x3a, 0x0f, 0x77, 0x38, 0x3a, 0x48, 0x00, + 0x5a, 0x3a, 0x17, 0x3b, 0x77, 0x3a, 0x5c, 0x99, 0x90, 0x3a, 0xa5, 0x25, 0x50, + 0x3a, 0xbc, 0x0d, 0x48, 0x3a, 0x14, 0xc8, 0x3e, 0x3a, 0xe9, 0xb8, 0x52, 0x3a, + 0x6b, 0xc3, 0x25, 0x3a, 0x4a, 0x97, 0x65, 0x3a, 0xd6, 0x6f, 0x45, 0x3a, 0x95, + 0x18, 0x84, 0x3a, 0x8e, 0xaf, 0x58, 0x3a, 0xc7, 0x30, 0x84, 0x3a, 0x99, 0x69, + 0x77, 0x3a, 0x22, 0xc9, 0x10, 0x3a, 0x95, 0xb8, 0x1e, 0x3a, 0x50, 0xd3, 0x43, + 0x3a, 0xe2, 0x56, 0x36, 0x3a, 0x5e, 0xe9, 0x8a, 0x3a, 0xb1, 0x42, 0x86, 0x3a, + 0x28, 0xd7, 0x58, 0x3a, 0x5f, 0xe0, 0x1d, 0x3a, 0x70, 0x0e, 0x35, 0x3a, 0x13, + 0x7b, 0xcf, 0x3a, 0x5e, 0xfd, 0x3c, 0x3a, 0x1c, 0xe5, 0x7c, 0x3a, 0x42, 0x7e, + 0x85, 0x3a, 0x67, 0x18, 0x48, 0x3a, 0xbd, 0xec, 0x33, 0x3a, 0xc7, 0x8c, 0x5c, + 0x3a, 0x23, 0xff, 0x5c, 0x3a, 0x76, 0xcc, 0x4d, 0x3a, 0xe1, 0x08, 0x81, 0x3a, + 0x2d, 0xca, 0x3e, 0x3a, 0x76, 0x72, 0x1a, 0x3a, 0x5e, 0x40, 0x55, 0x3a, 0x38, + 0x79, 0x23, 0x3a, 0x59, 0x0d, 0x43, 0x3a, 0x43, 0x52, 0x42, 0x3a, 0x1c, 0x46, + 0x63, 0x3a, 0xce, 0xe7, 0x67, 0x3a, 0xe9, 0x16, 0x3e, 0x3a, 0x3c, 0x0c, 0x02, + 0x3a, 0xb6, 0x1a, 0x54, 0x3a, 0x2d, 0xd9, 0x28, 0x3a, 0xa0, 0x6b, 0x25, 0x3a, + 0xfd, 0xd0, 0xa5, 0x3a, 0xa9, 0x48, 0x59, 0x3a, 0x58, 0x22, 0x34, 0x3a, 0x5a, + 0xec, 0x09, 0x3a, 0x80, 0x39, 0xcb, 0x3a, 0x54, 0x07, 0x2c, 0x3a, 0x0a, 0x1d, + 0x0a, 0x3a, 0x0a, 0x82, 0x43, 0x3a, 0x65, 0x5e, 0x90, 0x3a, 0xf7, 0xc1, 0x18, + 0x3a, 0xba, 0x95, 0x34, 0x3a, 0x58, 0x5d, 0x9d, 0x3a, 0xc2, 0x69, 0x43, 0x3a, + 0x61, 0x37, 0x4b, 0x3a, 0x7d, 0x5a, 0x80, 0x3a, 0x63, 0x47, 0x28, 0x3a, 0x1f, + 0xbc, 0x4b, 0x3a, 0xd7, 0xa2, 0x59, 0x3a, 0x84, 0x6e, 0x11, 0x3a, 0xaa, 0x21, + 0x9b, 0x3a, 0x54, 0xa6, 0x83, 0x3a, 0xb7, 0x23, 0x66, 0x3a, 0xaa, 0xa8, 0x97, + 0x3a, 0x14, 0x6a, 0x2c, 0x3a, 0x4d, 0x1b, 0x2b, 0x3a, 0x2a, 0xbf, 0x27, 0x3a, + 0xf9, 0x8a, 0x27, 0x3a, 0x6a, 0x9e, 0x5d, 0x3a, 0xfa, 0xda, 0x89, 0x3a, 0x4f, + 0xea, 0x2e, 0x3a, 0x6b, 0x3f, 0x29, 0x3a, 0x51, 0xba, 0x28, 0x3a, 0xa8, 0x04, + 0x74, 0x3a, 0xcd, 0xb2, 0x56, 0x3a, 0x08, 0xe9, 0x85, 0x3a, 0xe2, 0x08, 0x28, + 0x3a, 0xa4, 0xfb, 0x02, 0x3a, 0x1c, 0x1b, 0x9a, 0x3a, 0x0b, 0xf8, 0x32, 0x3a, + 0x21, 0x7d, 0x83, 0x3a, 0xbd, 0xc4, 0x8e, 0x3a, 0xb8, 0x50, 0x39, 0x3a, 0x34, + 0xba, 0xa2, 0x3a, 0xa2, 0xfd, 0x26, 0x3a, 0xc7, 0xf1, 0x5c, 0x3a, 0x89, 0x82, + 0x1e, 0x3a, 0xc9, 0x03, 0x25, 0x3a, 0xda, 0x86, 0x55, 0x3a, 0xd2, 0xb4, 0x5d, + 0x3a, 0xa8, 0x51, 0x26, 0x3a, 0x4f, 0x3e, 0x21, 0x3a, 0xea, 0x6c, 0x75, 0x3a, + 0xf4, 0x32, 0x6b, 0x3a, 0xa6, 0x58, 0x9b, 0x3a, 0x3c, 0xd4, 0xa1, 0x3a, 0x9c, + 0x68, 0x7d, 0x3a, 0x8f, 0x54, 0x58, 0x3a, 0x41, 0x4c, 0x24, 0x3a, 0x2f, 0x16, + 0x68, 0x3a, 0x3b, 0x1d, 0x06, 0x3a, 0xa3, 0x7b, 0x7b, 0x3a, 0xd7, 0x94, 0x71, + 0x3a, 0xa1, 0x17, 0x25, 0x3a, 0xe4, 0x77, 0x42, 0x3a, 0x05, 0xb9, 0x6e, 0x3a, + 0x00, 0xe4, 0x42, 0x3a, 0x9b, 0xb6, 0x49, 0x3a, 0x25, 0x09, 0x5f, 0x3a, 0xae, + 0x63, 0x55, 0x3a, 0x78, 0x8d, 0x50, 0x3a, 0xa5, 0xf5, 0x64, 0x3a, 0x22, 0x6e, + 0x61, 0x3a, 0x34, 0x1c, 0x75, 0x3a, 0x8f, 0xf8, 0x33, 0x3a, 0x71, 0xc6, 0x62, + 0x3a, 0x34, 0x5d, 0x44, 0x3a, 0xb3, 0x6d, 0x25, 0x3a, 0x41, 0x2b, 0x19, 0x3a, + 0xd8, 0x4a, 0x73, 0x3a, 0x4b, 0x72, 0x59, 0x3a, 0xa2, 0x6c, 0x41, 0x3a, 0x0a, + 0xed, 0x9e, 0x3a, 0x05, 0x1e, 0x46, 0x3a, 0x5a, 0x17, 0x49, 0x3a, 0xd4, 0xea, + 0x23, 0x3a, 0x76, 0xdb, 0x46, 0x3a, 0x6f, 0xb2, 0xb7, 0x3a, 0x9b, 0xe6, 0x4e, + 0x3a, 0x28, 0x26, 0x42, 0x3a, 0x92, 0xb3, 0x3a, 0x3a, 0x93, 0x76, 0x1e, 0x3a, + 0x92, 0x54, 0x49, 0x3a, 0x35, 0x42, 0x13, 0x3a, 0xac, 0x30, 0xa2, 0x3a, 0xc4, + 0xca, 0x4f, 0x3a, 0x18, 0x3c, 0x1e, 0x3a, 0x44, 0xd1, 0x8a, 0x3a, 0x22, 0x0d, + 0x34, 0x3a, 0x66, 0xf7, 0x47, 0x3a, 0xe7, 0x06, 0x49, 0x3a, 0x38, 0xc8, 0x07, + 0x3b, 0x41, 0xe5, 0xca, 0x3a, 0x4b, 0x05, 0x63, 0x3a, 0x48, 0x83, 0x50, 0x3a, + 0x3b, 0x4a, 0x23, 0x3a, 0x10, 0x05, 0x3c, 0x3a, 0x70, 0x54, 0x45, 0x3a, 0xfc, + 0xb4, 0x56, 0x3a, 0x16, 0x39, 0x7a, 0x3a, 0xd3, 0xac, 0x67, 0x3a, 0x13, 0x8d, + 0x98, 0x3a, 0x99, 0x9d, 0x3e, 0x3a, 0x2a, 0x46, 0x37, 0x3a, 0xfc, 0x1c, 0x4a, + 0x3a, 0xa1, 0x1c, 0x52, 0x3a, 0xab, 0x73, 0x7b, 0x3a, 0x04, 0xc9, 0x24, 0x3a, + 0x0b, 0xf4, 0x57, 0x3a, 0xc8, 0xab, 0x74, 0x3a, 0x4d, 0x7b, 0x1f, 0x3a, 0x21, + 0xe0, 0x34, 0x3a, 0x37, 0x61, 0x82, 0x3a, 0x63, 0xe2, 0x21, 0x3a, 0x6f, 0xd2, + 0xdf, 0x39, 0x7e, 0x17, 0x36, 0x3a, 0xe5, 0xa0, 0xef, 0x39, 0xc6, 0x00, 0x6b, + 0x3a, 0x5d, 0x5d, 0x71, 0x3a, 0xe6, 0xe7, 0x52, 0x3a, 0x8f, 0xd1, 0x80, 0x3a, + 0x20, 0x09, 0x8f, 0x3a, 0x83, 0xbe, 0x2f, 0x3a, 0xe3, 0x3d, 0x14, 0x3a, 0x58, + 0xec, 0x66, 0x3a, 0xb2, 0x96, 0x6e, 0x3a, 0xc3, 0x27, 0x7f, 0x3a, 0xfa, 0xea, + 0x50, 0x3a, 0xbb, 0x93, 0x3f, 0x3a, 0x88, 0xc4, 0xbb, 0x3a, 0x81, 0xa1, 0x16, + 0x3a, 0xaa, 0x0d, 0x18, 0x3a, 0xd3, 0x61, 0x51, 0x3a, 0x6a, 0x28, 0x72, 0x3a, + 0xa7, 0xa6, 0x4d, 0x3a, 0x01, 0xb4, 0x5b, 0x3a, 0x49, 0x56, 0x2f, 0x3a, 0x39, + 0x06, 0x84, 0x3a, 0x90, 0x4e, 0x90, 0x3a, 0xce, 0x41, 0x49, 0x3a, 0x94, 0x2a, + 0x40, 0x3a, 0x2e, 0xbc, 0x1f, 0x3a, 0x1e, 0x6d, 0x18, 0x3a, 0xd8, 0x8b, 0x30, + 0x3a, 0x48, 0xcd, 0x2b, 0x3a, 0x39, 0xfd, 0x89, 0x3a, 0x9e, 0xbf, 0x36, 0x3a, + 0xf0, 0xf7, 0x49, 0x3a, 0x53, 0xa4, 0x03, 0x3a, 0xc8, 0x82, 0x7f, 0x3a, 0x77, + 0x2f, 0xa8, 0x3a, 0x9a, 0x23, 0x83, 0x3a, 0x4e, 0x97, 0x22, 0x3a, 0xe9, 0x13, + 0x2a, 0x3a, 0x39, 0x76, 0x7c, 0x3a, 0x0b, 0x01, 0xbe, 0x3a, 0x4a, 0x2f, 0x8a, + 0x3a, 0x41, 0x24, 0x29, 0x3a, 0x15, 0x51, 0xbb, 0x3a, 0x38, 0x36, 0x1d, 0x3a, + 0x1f, 0x00, 0xa9, 0x3a, 0x64, 0x35, 0x95, 0x3a, 0xbd, 0x91, 0x69, 0x3a, 0xdf, + 0xcf, 0x32, 0x3a, 0x0e, 0xc4, 0xc3, 0x3a, 0x36, 0xb8, 0x38, 0x3a, 0x95, 0xfc, + 0x58, 0x3a, 0xf0, 0xf3, 0xa5, 0x3a, 0x17, 0x58, 0x87, 0x3a, 0xa1, 0xe4, 0x54, + 0x3a, 0xaf, 0x41, 0x87, 0x3a, 0x2c, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x31, 0x33, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, + 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, + 0xcd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x68, 0x0c, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x24, 0x0c, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6a, 0xc6, 0xff, + 0xff, 0x14, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x71, 0x40, 0x3c, 0xe8, 0xda, 0xe7, + 0x3b, 0xe4, 0xb9, 0x56, 0x3c, 0x54, 0x6a, 0xf9, 0x3b, 0x67, 0x0c, 0xbf, 0x3b, + 0x24, 0x1c, 0x0b, 0x3c, 0x6a, 0x8f, 0xb1, 0x3b, 0xdc, 0x08, 0x24, 0x3c, 0xb2, + 0x7c, 0xbe, 0x3b, 0x80, 0xad, 0x24, 0x3c, 0x51, 0xbd, 0xdb, 0x3b, 0xb3, 0xff, + 0xc2, 0x3b, 0x86, 0xbc, 0xee, 0x3b, 0x59, 0xcb, 0xed, 0x3b, 0xbb, 0x7f, 0x2c, + 0x3c, 0x49, 0xb7, 0x16, 0x3c, 0xc3, 0xea, 0xd4, 0x3b, 0x45, 0xed, 0xbf, 0x3b, + 0x83, 0x67, 0x18, 0x3c, 0xa5, 0x1b, 0x0d, 0x3c, 0x08, 0x5c, 0x25, 0x3c, 0x1d, + 0x17, 0x08, 0x3c, 0x5f, 0xdc, 0x04, 0x3c, 0xd5, 0x0b, 0x0b, 0x3c, 0xac, 0x9d, + 0x16, 0x3c, 0xfb, 0x22, 0xdb, 0x3b, 0xd0, 0xb7, 0xee, 0x3b, 0xa7, 0x22, 0x11, + 0x3c, 0x89, 0x0d, 0x20, 0x3c, 0x8f, 0x3f, 0xb2, 0x3b, 0x5b, 0x72, 0xce, 0x3b, + 0x76, 0x21, 0xb6, 0x3b, 0x9b, 0x02, 0xc9, 0x3b, 0xdb, 0xa3, 0xeb, 0x3b, 0xd3, + 0xde, 0x03, 0x3c, 0x52, 0xde, 0x07, 0x3c, 0x56, 0xd8, 0x30, 0x3c, 0x4b, 0xd2, + 0xff, 0x3b, 0x7d, 0x2b, 0x52, 0x3c, 0xca, 0x87, 0x33, 0x3c, 0xf1, 0xe7, 0x0d, + 0x3c, 0xc2, 0x0c, 0x01, 0x3c, 0xbc, 0x93, 0xd6, 0x3b, 0x9d, 0xfc, 0xe5, 0x3b, + 0x11, 0x90, 0xf2, 0x3b, 0x0f, 0xa2, 0xff, 0x3b, 0xfc, 0x7a, 0x08, 0x3c, 0x34, + 0x8b, 0x2d, 0x3c, 0x7b, 0xef, 0xfe, 0x3b, 0xe9, 0x05, 0xe5, 0x3b, 0x35, 0x65, + 0xde, 0x3b, 0xcf, 0xc6, 0xd8, 0x3b, 0xc4, 0xe0, 0xa9, 0x3b, 0xb6, 0x87, 0x13, + 0x3c, 0x08, 0x17, 0x2f, 0x3c, 0x12, 0x77, 0xdc, 0x3b, 0xf8, 0xfd, 0xdf, 0x3b, + 0xed, 0xee, 0xe4, 0x3b, 0x3e, 0xab, 0x23, 0x3c, 0x4c, 0xac, 0xb6, 0x3b, 0xae, + 0x28, 0xfc, 0x3b, 0x63, 0x1d, 0x3b, 0x3c, 0x21, 0x45, 0x02, 0x3c, 0x58, 0xca, + 0x4f, 0x3c, 0x5f, 0x9b, 0x28, 0x3c, 0xf0, 0x2a, 0x1d, 0x3c, 0x20, 0x20, 0xd9, + 0x3b, 0xda, 0xa2, 0x18, 0x3c, 0x5b, 0x63, 0x0b, 0x3c, 0x97, 0x50, 0x0d, 0x3c, + 0x77, 0xd5, 0xcb, 0x3b, 0xfb, 0xc4, 0x1c, 0x3c, 0xa6, 0x4a, 0xdd, 0x3b, 0x1d, + 0x2b, 0xf4, 0x3b, 0x71, 0xcd, 0x08, 0x3c, 0xd3, 0x09, 0xf9, 0x3b, 0x36, 0x59, + 0xc5, 0x3b, 0x51, 0x4a, 0x04, 0x3c, 0x93, 0xca, 0x2f, 0x3c, 0x80, 0x6e, 0xf5, + 0x3b, 0xed, 0x35, 0x25, 0x3c, 0x52, 0xc5, 0xdb, 0x3b, 0x0a, 0x34, 0x26, 0x3c, + 0x9a, 0x17, 0xeb, 0x3b, 0xd1, 0xac, 0xb9, 0x3b, 0x9b, 0xc2, 0x0a, 0x3c, 0xff, + 0x69, 0x2e, 0x3c, 0x57, 0x4d, 0xef, 0x3b, 0x7b, 0x6c, 0x10, 0x3c, 0x6e, 0xe2, + 0xe8, 0x3b, 0xde, 0x4e, 0xcb, 0x3b, 0xf6, 0xd9, 0xdc, 0x3b, 0x71, 0xf7, 0x07, + 0x3c, 0xe5, 0x80, 0x49, 0x3c, 0xd1, 0xee, 0x0b, 0x3c, 0x09, 0xbc, 0x02, 0x3c, + 0x52, 0xeb, 0x0f, 0x3c, 0x42, 0x61, 0x16, 0x3c, 0xf3, 0xd2, 0xcc, 0x3b, 0xec, + 0x81, 0xe8, 0x3b, 0xe0, 0x2e, 0x15, 0x3c, 0x0e, 0x34, 0x1f, 0x3c, 0xd3, 0x49, + 0xf9, 0x3b, 0x1c, 0x03, 0x01, 0x3c, 0x77, 0x8f, 0xe5, 0x3b, 0xd6, 0x2c, 0x09, + 0x3c, 0xe1, 0x22, 0xdd, 0x3b, 0x04, 0xb9, 0xa9, 0x3b, 0x2f, 0x2a, 0x1b, 0x3c, + 0x87, 0x2f, 0x32, 0x3c, 0x91, 0xb7, 0xcc, 0x3b, 0x5e, 0x47, 0xf7, 0x3b, 0xbf, + 0x49, 0xd2, 0x3b, 0x85, 0x5b, 0x03, 0x3c, 0xd4, 0x9d, 0x9b, 0x3b, 0x6f, 0x85, + 0xc9, 0x3b, 0xb4, 0xa9, 0x02, 0x3c, 0x46, 0xe9, 0x18, 0x3c, 0x41, 0x05, 0x52, + 0x3c, 0x03, 0x46, 0xe3, 0x3b, 0x80, 0x38, 0x0f, 0x3c, 0x2c, 0x2b, 0x30, 0x3c, + 0x43, 0x27, 0xbe, 0x3b, 0x53, 0x47, 0xf1, 0x3b, 0x11, 0xc6, 0x05, 0x3c, 0x6a, + 0xaf, 0x07, 0x3c, 0x8f, 0x63, 0x3f, 0x3c, 0xe3, 0x24, 0x1d, 0x3c, 0x52, 0x51, + 0x65, 0x3c, 0xc7, 0x39, 0xcf, 0x3b, 0x93, 0x31, 0xd6, 0x3b, 0x15, 0x97, 0x06, + 0x3c, 0x6d, 0xc8, 0x0b, 0x3c, 0xa8, 0x32, 0x07, 0x3c, 0xdb, 0x3e, 0xc9, 0x3b, + 0xec, 0x7d, 0xb1, 0x3b, 0xc5, 0xee, 0xce, 0x3b, 0x3a, 0xb1, 0x90, 0x3b, 0x99, + 0x5a, 0xd2, 0x3b, 0x36, 0xe0, 0x1c, 0x3c, 0xd3, 0xaf, 0x08, 0x3c, 0x00, 0xed, + 0x2b, 0x3c, 0x61, 0xd2, 0x6a, 0x3c, 0x43, 0x53, 0xdc, 0x3b, 0xd1, 0x7a, 0x19, + 0x3c, 0x14, 0x4d, 0x24, 0x3c, 0xf6, 0xfb, 0x0b, 0x3c, 0x20, 0xc4, 0x10, 0x3c, + 0x6e, 0x6c, 0x12, 0x3c, 0xdb, 0x71, 0x1e, 0x3c, 0x3f, 0xad, 0x02, 0x3c, 0x24, + 0x6d, 0xa5, 0x3b, 0x0e, 0x74, 0x39, 0x3c, 0xc7, 0xfe, 0x15, 0x3c, 0xe8, 0x69, + 0xdc, 0x3b, 0xdd, 0x24, 0x0c, 0x3c, 0x47, 0x57, 0x04, 0x3c, 0xcf, 0xf3, 0xf9, + 0x3b, 0x13, 0xfc, 0xef, 0x3b, 0x62, 0xc3, 0x1c, 0x3c, 0x02, 0x45, 0xfa, 0x3b, + 0x0d, 0xfd, 0xf1, 0x3b, 0x71, 0x8b, 0x9c, 0x3b, 0xd7, 0xab, 0xc9, 0x3b, 0x28, + 0x5d, 0x14, 0x3c, 0xe5, 0x71, 0xe6, 0x3b, 0x3a, 0xa1, 0x1b, 0x3c, 0x49, 0xcc, + 0xf8, 0x3b, 0x92, 0xcd, 0xf9, 0x3b, 0x73, 0xec, 0x24, 0x3c, 0x9d, 0xa1, 0x80, + 0x3c, 0xc1, 0x94, 0xb5, 0x3b, 0xbf, 0x58, 0x17, 0x3c, 0xe1, 0xcb, 0x05, 0x3c, + 0x7d, 0xff, 0xe4, 0x3b, 0xe8, 0x2b, 0x32, 0x3c, 0x0f, 0x99, 0x22, 0x3c, 0x2b, + 0xf6, 0xc9, 0x3b, 0x7d, 0xec, 0x44, 0x3c, 0xe6, 0x63, 0x20, 0x3c, 0xf5, 0x7a, + 0x17, 0x3c, 0x3d, 0xc2, 0x26, 0x3c, 0x5f, 0xaa, 0xf2, 0x3b, 0x72, 0x06, 0xc5, + 0x3b, 0xdb, 0x1d, 0xcd, 0x3b, 0x9c, 0x43, 0x81, 0x3c, 0xac, 0x2f, 0x2a, 0x3c, + 0x80, 0xfb, 0x46, 0x3c, 0xfe, 0x9f, 0xe5, 0x3b, 0x74, 0x85, 0x0a, 0x3c, 0x38, + 0x1d, 0x16, 0x3c, 0xd1, 0x3e, 0xd8, 0x3b, 0x6a, 0x95, 0xb1, 0x3b, 0xf7, 0x07, + 0xf9, 0x3b, 0x82, 0x05, 0xab, 0x3b, 0xaf, 0xe3, 0xda, 0x3b, 0x7a, 0xeb, 0xc9, + 0x3b, 0x56, 0x85, 0x14, 0x3c, 0x58, 0x82, 0x39, 0x3c, 0xed, 0xc7, 0x27, 0x3c, + 0xfa, 0x26, 0x31, 0x3c, 0xdd, 0x03, 0x0d, 0x3c, 0x82, 0x66, 0xbb, 0x3b, 0xc3, + 0xbb, 0xb2, 0x3b, 0xf1, 0xf7, 0x28, 0x3c, 0x71, 0x80, 0xa1, 0x3b, 0x16, 0x27, + 0x01, 0x3c, 0xfa, 0x22, 0x04, 0x3c, 0xf8, 0xb6, 0x47, 0x3c, 0x33, 0x46, 0x2b, + 0x3c, 0x65, 0xcf, 0xe1, 0x3b, 0x78, 0x79, 0xe7, 0x3b, 0xd3, 0x9a, 0xfa, 0x3b, + 0x87, 0x41, 0x00, 0x3c, 0xf2, 0x4e, 0x17, 0x3c, 0x95, 0xa9, 0x29, 0x3c, 0x8f, + 0x50, 0x12, 0x3c, 0xa3, 0x7b, 0xe0, 0x3b, 0xf2, 0xc9, 0x02, 0x3c, 0x4b, 0x4f, + 0xb2, 0x3b, 0xcc, 0x25, 0x26, 0x3c, 0xfc, 0x07, 0x1a, 0x3c, 0xea, 0x97, 0x05, + 0x3c, 0x0a, 0x9b, 0x29, 0x3c, 0xfe, 0x65, 0xf8, 0x3b, 0xac, 0x80, 0x0a, 0x3c, + 0xaf, 0x6f, 0xed, 0x3b, 0x86, 0xda, 0xc8, 0x3b, 0xd3, 0xf7, 0x03, 0x3c, 0xf3, + 0x08, 0x10, 0x3c, 0x4f, 0x69, 0x53, 0x3c, 0xad, 0xc6, 0x10, 0x3c, 0xf6, 0x7a, + 0xe5, 0x3b, 0x23, 0x52, 0x1e, 0x3c, 0xc8, 0xcc, 0x42, 0x3c, 0x1b, 0x64, 0xc9, + 0x3b, 0xa6, 0x6c, 0x29, 0x3c, 0xaa, 0x9b, 0xda, 0x3b, 0x69, 0x72, 0x01, 0x3c, + 0x59, 0xba, 0xe2, 0x3b, 0xe1, 0x4e, 0x25, 0x3c, 0x79, 0x3b, 0xdb, 0x3b, 0xed, + 0x7a, 0xb3, 0x3b, 0xa5, 0x7d, 0xf5, 0x3b, 0x9f, 0xbf, 0x14, 0x3c, 0x7f, 0x81, + 0x29, 0x3c, 0x04, 0xff, 0x0b, 0x3c, 0x81, 0x0d, 0x22, 0x3c, 0x91, 0xd2, 0x17, + 0x3c, 0xca, 0x1c, 0x19, 0x3c, 0x04, 0x31, 0x1e, 0x3c, 0xc5, 0x42, 0xed, 0x3b, + 0x29, 0xb5, 0xaa, 0x3b, 0x88, 0xb8, 0x0e, 0x3c, 0xad, 0x1b, 0xc6, 0x3b, 0xc5, + 0x74, 0xff, 0x3b, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, + 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, + 0x31, 0x33, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, + 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, + 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x92, 0xd9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, + 0x58, 0x0c, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x14, 0xe0, 0xff, 0xff, 0x0c, 0x08, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0xcc, 0xe1, 0x0f, 0x3b, 0x17, 0x4c, 0xbf, 0x3a, 0x04, + 0x03, 0xea, 0x3a, 0xcc, 0xf3, 0xde, 0x3a, 0x10, 0xa3, 0x4e, 0x3b, 0x00, 0x59, + 0xe0, 0x3a, 0x5d, 0xde, 0x29, 0x3b, 0x21, 0x80, 0x2c, 0x3b, 0xf8, 0x74, 0xea, + 0x3a, 0x02, 0xe3, 0x05, 0x3b, 0xd8, 0xb1, 0x03, 0x3b, 0x77, 0x53, 0xfd, 0x3a, + 0x96, 0x88, 0xc9, 0x3a, 0x58, 0x58, 0x0c, 0x3b, 0xfb, 0x10, 0x5b, 0x3b, 0x2a, + 0xf4, 0x17, 0x3b, 0x46, 0x1e, 0x26, 0x3b, 0xb2, 0x20, 0xc5, 0x3a, 0x1a, 0x6e, + 0x06, 0x3b, 0x2a, 0x57, 0x05, 0x3b, 0x67, 0xf5, 0x2d, 0x3b, 0xd0, 0x2c, 0x02, + 0x3b, 0x8a, 0xf5, 0xf7, 0x3a, 0x38, 0x73, 0xdd, 0x3a, 0xa1, 0xb8, 0x0e, 0x3b, + 0xea, 0x08, 0x28, 0x3b, 0x48, 0x78, 0x0f, 0x3b, 0x07, 0x63, 0x25, 0x3b, 0x81, + 0x6d, 0xe8, 0x3a, 0x25, 0xc8, 0x03, 0x3b, 0x00, 0xb7, 0xb3, 0x3a, 0xaf, 0xa6, + 0x1a, 0x3b, 0x7f, 0x56, 0x0c, 0x3b, 0x89, 0x65, 0x07, 0x3b, 0xb5, 0xae, 0xbe, + 0x3a, 0xb4, 0xee, 0xfa, 0x3a, 0x1a, 0x88, 0x5f, 0x3b, 0xc9, 0x6f, 0xfa, 0x3a, + 0x32, 0xb8, 0xc5, 0x3a, 0x72, 0x60, 0x28, 0x3b, 0xd9, 0x9d, 0x29, 0x3b, 0x83, + 0xf8, 0x06, 0x3b, 0x24, 0xb0, 0x03, 0x3b, 0xb8, 0x11, 0xdd, 0x3a, 0xce, 0x34, + 0xf2, 0x3a, 0x77, 0x44, 0xfb, 0x3a, 0x2c, 0x3e, 0xe5, 0x3a, 0xe8, 0xbe, 0xe4, + 0x3a, 0x8b, 0x3f, 0x36, 0x3b, 0x80, 0x2c, 0x12, 0x3b, 0xb1, 0x7a, 0x09, 0x3b, + 0x83, 0x16, 0xc6, 0x3a, 0x47, 0xcc, 0x22, 0x3b, 0xcb, 0xa5, 0xf7, 0x3a, 0xab, + 0x7e, 0x0d, 0x3b, 0x22, 0x3e, 0x0c, 0x3b, 0xcd, 0xc2, 0x22, 0x3b, 0x5a, 0x8b, + 0xfb, 0x3a, 0x20, 0x95, 0xd0, 0x3a, 0x05, 0x9e, 0x06, 0x3b, 0x23, 0x35, 0xd0, + 0x3a, 0xb1, 0x27, 0x21, 0x3b, 0x08, 0x8b, 0xc1, 0x3a, 0x65, 0x3d, 0x0d, 0x3b, + 0x1f, 0xf2, 0x2e, 0x3b, 0x7c, 0x69, 0x0f, 0x3b, 0x4d, 0x9d, 0x09, 0x3b, 0xcd, + 0x8f, 0x0f, 0x3b, 0xe6, 0x71, 0xc8, 0x3a, 0x9e, 0x28, 0x06, 0x3b, 0x08, 0x80, + 0x00, 0x3b, 0x80, 0x15, 0xff, 0x3a, 0xf1, 0x34, 0x47, 0x3b, 0x74, 0x20, 0x06, + 0x3b, 0xfe, 0x06, 0x03, 0x3b, 0xb7, 0x7a, 0xd7, 0x3a, 0x6e, 0xe4, 0x13, 0x3b, + 0xe9, 0x3e, 0x02, 0x3b, 0x31, 0xd5, 0x24, 0x3b, 0xef, 0x18, 0x9f, 0x3b, 0x1c, + 0xc8, 0x46, 0x3b, 0xb3, 0xd3, 0xc8, 0x3a, 0x50, 0xef, 0x1d, 0x3b, 0xcc, 0x59, + 0x99, 0x3a, 0xce, 0xc6, 0xdd, 0x3a, 0x4a, 0xde, 0x92, 0x3a, 0xe4, 0x27, 0x1e, + 0x3b, 0xef, 0x9f, 0x49, 0x3b, 0xa4, 0xf2, 0xcc, 0x3a, 0x36, 0x46, 0x25, 0x3b, + 0x41, 0xb3, 0x23, 0x3b, 0xb6, 0x32, 0x3f, 0x3b, 0xb2, 0xc5, 0x07, 0x3b, 0x26, + 0x07, 0x38, 0x3b, 0x43, 0xe2, 0x1c, 0x3b, 0xa7, 0xe0, 0x18, 0x3b, 0x6e, 0xdd, + 0xff, 0x3a, 0x2f, 0xb9, 0xff, 0x3a, 0x2d, 0x2f, 0x14, 0x3b, 0x8b, 0xf0, 0x0b, + 0x3b, 0x08, 0x83, 0x08, 0x3b, 0x06, 0x5b, 0x0b, 0x3b, 0x94, 0x3a, 0xc8, 0x3a, + 0x24, 0x24, 0xe9, 0x3a, 0x9a, 0x87, 0x0f, 0x3b, 0x64, 0xd1, 0x07, 0x3b, 0xdf, + 0xe5, 0xda, 0x3a, 0x3a, 0x00, 0xe6, 0x3a, 0xe1, 0x2c, 0x42, 0x3b, 0x6c, 0x54, + 0xe0, 0x3a, 0x0b, 0xe9, 0x0e, 0x3b, 0xfd, 0xe2, 0xe6, 0x3a, 0xff, 0xeb, 0x16, + 0x3b, 0x57, 0xf1, 0x4d, 0x3b, 0xe4, 0xb3, 0xb0, 0x3a, 0x63, 0x93, 0xf0, 0x3a, + 0xaf, 0x4e, 0x48, 0x3b, 0xb4, 0x9a, 0x2c, 0x3b, 0xa1, 0x6f, 0x20, 0x3b, 0x19, + 0x20, 0x29, 0x3b, 0x73, 0x22, 0x0a, 0x3b, 0x61, 0xa8, 0x1f, 0x3b, 0x17, 0xb5, + 0xd9, 0x3a, 0xa5, 0xd2, 0xee, 0x3a, 0xa7, 0xe1, 0xfe, 0x3a, 0x10, 0xbd, 0xf6, + 0x3a, 0xdd, 0x6f, 0xd7, 0x3a, 0x21, 0xd4, 0xf3, 0x3a, 0x19, 0xf4, 0xd9, 0x3a, + 0x08, 0x84, 0x0c, 0x3b, 0x92, 0x7c, 0xfc, 0x3a, 0xb5, 0x3a, 0x18, 0x3b, 0x34, + 0xe2, 0xea, 0x3a, 0x0e, 0xc1, 0x04, 0x3b, 0xc4, 0xee, 0x56, 0x3b, 0x9c, 0xd0, + 0xe8, 0x3a, 0x87, 0x38, 0x05, 0x3b, 0xde, 0x41, 0xb7, 0x3a, 0x0b, 0xba, 0xa9, + 0x3a, 0xeb, 0xb4, 0x01, 0x3b, 0x7f, 0x46, 0xe2, 0x3a, 0x03, 0x5e, 0x23, 0x3b, + 0x56, 0x83, 0xe6, 0x3a, 0xbd, 0xab, 0x09, 0x3b, 0xe0, 0x54, 0x23, 0x3b, 0xd5, + 0xb0, 0x3d, 0x3b, 0xaa, 0xb2, 0x2f, 0x3b, 0x18, 0xcd, 0x2d, 0x3b, 0x26, 0xf2, + 0xda, 0x3a, 0x8c, 0x2e, 0x03, 0x3b, 0x79, 0x49, 0x06, 0x3b, 0xf3, 0x28, 0xfa, + 0x3a, 0x38, 0x2a, 0x1a, 0x3b, 0x36, 0x54, 0xbe, 0x3a, 0xbb, 0x2b, 0x12, 0x3b, + 0xf7, 0xba, 0x4f, 0x3b, 0xed, 0x4b, 0x12, 0x3b, 0x7b, 0xaa, 0x1c, 0x3b, 0xa6, + 0xba, 0x1a, 0x3b, 0x6f, 0x3f, 0x11, 0x3b, 0x7e, 0x33, 0x0f, 0x3b, 0xcf, 0x1e, + 0x09, 0x3b, 0xf9, 0xac, 0xec, 0x3a, 0x1a, 0x14, 0xb5, 0x3a, 0x41, 0x60, 0xe4, + 0x3a, 0x9d, 0x2e, 0x22, 0x3b, 0x22, 0x15, 0x22, 0x3b, 0x61, 0xc5, 0x2c, 0x3b, + 0x5f, 0x52, 0xd6, 0x3a, 0x2c, 0x54, 0x28, 0x3b, 0x83, 0x55, 0x4a, 0x3b, 0xce, + 0x9d, 0x46, 0x3b, 0x50, 0xc7, 0xfa, 0x3a, 0x57, 0xce, 0xfd, 0x3a, 0x66, 0x9f, + 0x28, 0x3b, 0x6b, 0x4d, 0xe2, 0x3a, 0xed, 0x62, 0x0e, 0x3b, 0x0a, 0xec, 0xf5, + 0x3a, 0x91, 0xb2, 0x08, 0x3b, 0x71, 0xf2, 0x25, 0x3b, 0x6f, 0xc9, 0x06, 0x3b, + 0x55, 0x88, 0x09, 0x3b, 0x81, 0xd6, 0x52, 0x3b, 0x97, 0xa1, 0xf7, 0x3a, 0x63, + 0x44, 0xf0, 0x3a, 0x94, 0x6b, 0xf8, 0x3a, 0xde, 0x51, 0x01, 0x3b, 0x22, 0xef, + 0xf4, 0x3a, 0x2d, 0x9c, 0x0b, 0x3b, 0x08, 0xb3, 0x39, 0x3b, 0xb9, 0x83, 0xff, + 0x3a, 0x55, 0x0d, 0xfb, 0x3a, 0x8c, 0x07, 0x11, 0x3b, 0xff, 0x16, 0xc1, 0x3a, + 0x0d, 0xee, 0x06, 0x3b, 0xb2, 0x17, 0x08, 0x3b, 0x31, 0x4b, 0xfc, 0x3a, 0xda, + 0x5e, 0x2f, 0x3b, 0x60, 0x7f, 0x24, 0x3b, 0x3d, 0xbb, 0x2c, 0x3b, 0xe3, 0xa9, + 0x1b, 0x3b, 0x99, 0x25, 0x16, 0x3b, 0x32, 0x5c, 0x29, 0x3b, 0xe2, 0x6c, 0x36, + 0x3b, 0x1e, 0x20, 0xc0, 0x3a, 0x74, 0xbd, 0x32, 0x3b, 0x83, 0xdf, 0xf6, 0x3a, + 0xf2, 0x4d, 0x1d, 0x3b, 0xfd, 0xe6, 0x1d, 0x3b, 0xc8, 0x3a, 0xed, 0x3a, 0x85, + 0x4f, 0x20, 0x3b, 0x49, 0x58, 0xd3, 0x3a, 0xc5, 0x4e, 0x06, 0x3b, 0x36, 0xee, + 0x28, 0x3b, 0x6f, 0xca, 0xdb, 0x3a, 0xe4, 0x35, 0x09, 0x3b, 0x1f, 0xbb, 0x28, + 0x3b, 0x4c, 0x89, 0x00, 0x3b, 0x0c, 0x8d, 0x0f, 0x3b, 0x8e, 0x74, 0x13, 0x3b, + 0x5b, 0xf4, 0x2e, 0x3b, 0x93, 0xe0, 0x4b, 0x3b, 0x14, 0xc6, 0x09, 0x3b, 0x07, + 0xf0, 0x0a, 0x3b, 0x3c, 0x54, 0x1f, 0x3b, 0xda, 0x01, 0xbb, 0x3a, 0x59, 0x9c, + 0xe8, 0x3a, 0xc7, 0xea, 0x0b, 0x3b, 0x15, 0x88, 0xf2, 0x3a, 0xbc, 0xc3, 0xd8, + 0x3a, 0xcc, 0xd6, 0x14, 0x3b, 0xca, 0x60, 0x34, 0x3b, 0xf9, 0x7f, 0x00, 0x3b, + 0x31, 0xf8, 0x07, 0x3b, 0x2d, 0xac, 0x26, 0x3b, 0x02, 0x10, 0xda, 0x3a, 0x58, + 0xdc, 0xda, 0x3a, 0x65, 0x3b, 0x05, 0x3b, 0x73, 0xa1, 0x21, 0x3b, 0x2b, 0xb1, + 0x0d, 0x3b, 0xf2, 0xf7, 0xe2, 0x3a, 0x82, 0xc1, 0xc3, 0x3a, 0xc7, 0xf2, 0x10, + 0x3b, 0x42, 0xf2, 0x47, 0x3b, 0x33, 0x3b, 0xf1, 0x3a, 0x76, 0x6e, 0x20, 0x3b, + 0x97, 0x5b, 0x07, 0x3b, 0xe8, 0x6b, 0x11, 0x3b, 0xd3, 0xdb, 0x21, 0x3b, 0x8b, + 0x09, 0x38, 0x3b, 0xd7, 0x22, 0x0d, 0x3b, 0x39, 0xa9, 0xfe, 0x3a, 0x1b, 0xf3, + 0xe6, 0x3a, 0x15, 0x3e, 0x06, 0x3b, 0x21, 0xeb, 0x4a, 0x3b, 0xf3, 0x97, 0x43, + 0x3b, 0x2c, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, + 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x32, + 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0xe6, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x09, 0x68, 0x06, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x24, 0x06, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0xdf, 0xff, 0xff, 0x14, 0x04, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x8d, 0xb0, 0x3b, 0xf3, 0x87, 0x95, 0x3b, + 0xa0, 0x61, 0x06, 0x3c, 0xc6, 0x88, 0xd8, 0x3b, 0xb8, 0x1d, 0x17, 0x3c, 0x2e, + 0x80, 0x8f, 0x3b, 0x95, 0xd1, 0xac, 0x3b, 0x02, 0x8b, 0xdb, 0x3b, 0x0e, 0xd5, + 0x96, 0x3b, 0x56, 0x45, 0x0b, 0x3c, 0x29, 0xf1, 0xbf, 0x3b, 0x33, 0x80, 0x9e, + 0x3b, 0x84, 0xdd, 0xd8, 0x3b, 0x22, 0xca, 0xb1, 0x3b, 0xf4, 0xd5, 0xa7, 0x3b, + 0x93, 0xee, 0xcd, 0x3b, 0x77, 0xa4, 0x18, 0x3c, 0x65, 0xb4, 0xe5, 0x3b, 0x55, + 0x8b, 0xb9, 0x3b, 0x5a, 0x00, 0xac, 0x3b, 0x00, 0x49, 0xb3, 0x3b, 0x1c, 0x7b, + 0x9a, 0x3b, 0xd6, 0x10, 0xdc, 0x3b, 0x6d, 0xe7, 0xb8, 0x3b, 0xf0, 0x27, 0x89, + 0x3b, 0xbb, 0x44, 0xe0, 0x3b, 0x85, 0xd8, 0xbc, 0x3b, 0xbc, 0xf9, 0x92, 0x3b, + 0x8e, 0xfa, 0xed, 0x3b, 0x55, 0x2b, 0xd2, 0x3b, 0x37, 0xfc, 0xd1, 0x3b, 0x1b, + 0xfe, 0xfc, 0x3b, 0x51, 0x9b, 0xda, 0x3b, 0xe7, 0xb1, 0xf2, 0x3b, 0x15, 0x64, + 0xb1, 0x3b, 0x84, 0x34, 0xee, 0x3b, 0x4e, 0x10, 0xe6, 0x3b, 0xc4, 0x61, 0x7d, + 0x3b, 0x78, 0x42, 0x91, 0x3b, 0x45, 0xd0, 0x13, 0x3c, 0xe8, 0x63, 0x83, 0x3b, + 0x9d, 0x6f, 0x22, 0x3c, 0x8d, 0xd6, 0x03, 0x3c, 0xfe, 0x27, 0xc2, 0x3b, 0xda, + 0x67, 0xa9, 0x3b, 0xe9, 0xef, 0xc1, 0x3b, 0xab, 0x9b, 0x9d, 0x3b, 0x64, 0xad, + 0x0c, 0x3c, 0x62, 0x44, 0xa6, 0x3b, 0x53, 0x87, 0xa7, 0x3b, 0x4d, 0xa9, 0xa1, + 0x3b, 0x33, 0x38, 0x92, 0x3b, 0x1a, 0x0d, 0xe8, 0x3b, 0xda, 0x1d, 0xff, 0x3b, + 0x69, 0x33, 0xe1, 0x3b, 0x0d, 0xed, 0xf5, 0x3b, 0xa2, 0x82, 0x93, 0x3b, 0x59, + 0x7d, 0xdf, 0x3b, 0x3a, 0x5d, 0x80, 0x3b, 0x20, 0x50, 0xb1, 0x3b, 0xee, 0x64, + 0xec, 0x3b, 0xeb, 0x2b, 0xf1, 0x3b, 0xa0, 0x96, 0xc4, 0x3b, 0x29, 0xdc, 0x88, + 0x3b, 0x92, 0x9b, 0xaf, 0x3b, 0xb9, 0x15, 0xe6, 0x3b, 0xad, 0x85, 0x95, 0x3b, + 0xb2, 0x3a, 0xc9, 0x3b, 0xcd, 0x48, 0xc7, 0x3b, 0x47, 0x5b, 0x08, 0x3c, 0x8d, + 0x63, 0xbe, 0x3b, 0xa4, 0xc0, 0x8d, 0x3b, 0x91, 0xf7, 0xae, 0x3b, 0x98, 0xdd, + 0x92, 0x3b, 0x2c, 0xfe, 0xb5, 0x3b, 0x03, 0x40, 0xad, 0x3b, 0x76, 0x64, 0x73, + 0x3b, 0xac, 0x52, 0xae, 0x3b, 0x06, 0xcc, 0xd2, 0x3b, 0x01, 0x7b, 0xa0, 0x3b, + 0xac, 0x67, 0xd4, 0x3b, 0x2d, 0x3a, 0xfc, 0x3b, 0x81, 0x8f, 0xad, 0x3b, 0xae, + 0xc9, 0xcb, 0x3b, 0xc7, 0xe3, 0xf3, 0x3b, 0xbf, 0xce, 0xda, 0x3b, 0xb6, 0x27, + 0xe2, 0x3b, 0x05, 0xf9, 0xb6, 0x3b, 0x12, 0xd2, 0x15, 0x3c, 0x93, 0xbc, 0xe6, + 0x3b, 0x5e, 0x19, 0x6e, 0x3b, 0x4e, 0x57, 0xe9, 0x3b, 0x5b, 0x8e, 0x12, 0x3c, + 0x32, 0x9f, 0xb8, 0x3b, 0x10, 0x17, 0xbd, 0x3b, 0xde, 0xa4, 0x0b, 0x3c, 0x14, + 0xda, 0xa2, 0x3b, 0x5f, 0x00, 0xc5, 0x3b, 0x8f, 0xd5, 0xcb, 0x3b, 0xff, 0xb6, + 0xa1, 0x3b, 0x97, 0x44, 0x09, 0x3c, 0x7e, 0x30, 0x18, 0x3c, 0x52, 0xa2, 0x22, + 0x3c, 0xcd, 0xfe, 0xa5, 0x3b, 0x30, 0xec, 0xd4, 0x3b, 0xfc, 0xfa, 0xa5, 0x3b, + 0xab, 0x8d, 0x08, 0x3c, 0x4e, 0xe2, 0xc5, 0x3b, 0x83, 0x80, 0xb6, 0x3b, 0xbf, + 0xbc, 0x30, 0x3c, 0x53, 0xc1, 0xf5, 0x3b, 0x13, 0x74, 0xa2, 0x3b, 0x7a, 0x61, + 0xcb, 0x3b, 0xf9, 0xc9, 0xbc, 0x3b, 0x84, 0x85, 0xc4, 0x3b, 0x95, 0x6e, 0xc7, + 0x3b, 0xf0, 0x90, 0x13, 0x3c, 0xcc, 0x3e, 0xcf, 0x3b, 0xb6, 0xd3, 0x88, 0x3b, + 0x08, 0x19, 0x9b, 0x3b, 0xb5, 0x8b, 0xdc, 0x3b, 0xae, 0xe0, 0x80, 0x3b, 0xdf, + 0x38, 0xb4, 0x3b, 0xd6, 0x74, 0x22, 0x3c, 0xb8, 0xec, 0x4b, 0x3b, 0xb0, 0x1f, + 0xa9, 0x3b, 0xe2, 0x3e, 0x0c, 0x3c, 0x3a, 0xe1, 0x05, 0x3c, 0x36, 0x00, 0x00, + 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, + 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x32, 0x5f, 0x64, 0x65, 0x70, + 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, + 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, + 0x65, 0x61, 0x64, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x8a, + 0xec, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x58, 0x06, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0xf3, 0xff, + 0xff, 0x0c, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xd7, 0x8a, 0x53, 0x3b, 0x38, 0xdb, 0x39, 0x3b, 0x26, 0x99, 0x4d, 0x3b, + 0x6c, 0xd5, 0x12, 0x3b, 0xcc, 0x46, 0x25, 0x3b, 0x4b, 0x9a, 0xe8, 0x3a, 0xd1, + 0xff, 0x27, 0x3b, 0xc5, 0x60, 0x07, 0x3b, 0x66, 0xaa, 0x0e, 0x3b, 0x2a, 0x4d, + 0x06, 0x3b, 0x7e, 0x98, 0x08, 0x3b, 0xd2, 0x44, 0x29, 0x3b, 0x8c, 0x7b, 0x39, + 0x3b, 0xf6, 0xdc, 0x01, 0x3b, 0x1f, 0xea, 0x21, 0x3b, 0xd0, 0x34, 0x02, 0x3b, + 0x98, 0x0b, 0x59, 0x3b, 0x6c, 0x69, 0x35, 0x3b, 0x68, 0x68, 0xfc, 0x3a, 0x47, + 0x6b, 0x1b, 0x3b, 0x45, 0x2b, 0x20, 0x3b, 0xb1, 0x7a, 0x01, 0x3b, 0x95, 0x2e, + 0x0f, 0x3b, 0x66, 0x5b, 0x27, 0x3b, 0xe6, 0x6e, 0x4e, 0x3b, 0x5e, 0xac, 0x0d, + 0x3b, 0x30, 0x90, 0x22, 0x3b, 0x54, 0x9e, 0x2d, 0x3b, 0xc8, 0x19, 0xea, 0x3a, + 0x8e, 0x3c, 0x23, 0x3b, 0x65, 0x70, 0x25, 0x3b, 0xf4, 0x79, 0x14, 0x3b, 0x29, + 0x49, 0x13, 0x3b, 0xfc, 0x2a, 0x40, 0x3b, 0x5c, 0x34, 0x3b, 0x3b, 0x2a, 0x52, + 0xf8, 0x3a, 0x6e, 0x51, 0x18, 0x3b, 0x53, 0x24, 0xf6, 0x3a, 0x33, 0x76, 0x24, + 0x3b, 0x60, 0xdf, 0x0f, 0x3b, 0xc5, 0x27, 0x0d, 0x3b, 0xfb, 0x7e, 0x37, 0x3b, + 0xa8, 0x98, 0x10, 0x3b, 0x37, 0xf8, 0x30, 0x3b, 0x0b, 0xda, 0x61, 0x3b, 0x7d, + 0x9b, 0x4a, 0x3b, 0xa1, 0xd6, 0x0e, 0x3b, 0x33, 0x87, 0x27, 0x3b, 0x23, 0x9d, + 0x40, 0x3b, 0x39, 0xec, 0x20, 0x3b, 0xef, 0xfa, 0x06, 0x3b, 0x9c, 0x98, 0x0d, + 0x3b, 0x47, 0x53, 0x03, 0x3b, 0x99, 0x43, 0x1d, 0x3b, 0x08, 0xe1, 0x01, 0x3b, + 0x70, 0x34, 0x14, 0x3b, 0xae, 0xfd, 0x61, 0x3b, 0xeb, 0xc0, 0x0e, 0x3b, 0x12, + 0x1f, 0x21, 0x3b, 0xf5, 0xba, 0x03, 0x3b, 0x19, 0xb4, 0x17, 0x3b, 0x36, 0x92, + 0x2d, 0x3b, 0x4f, 0xbd, 0x36, 0x3b, 0xb0, 0x11, 0x20, 0x3b, 0x62, 0x00, 0x52, + 0x3b, 0x8e, 0x5e, 0x1c, 0x3b, 0x9a, 0x5c, 0x20, 0x3b, 0x2f, 0xc8, 0x1a, 0x3b, + 0x86, 0xf1, 0x2c, 0x3b, 0x26, 0x6d, 0x13, 0x3b, 0x2a, 0x7a, 0xfa, 0x3a, 0xa6, + 0x9d, 0x10, 0x3b, 0xb7, 0xd3, 0x0e, 0x3b, 0xa1, 0xd2, 0x3e, 0x3b, 0xe1, 0x4e, + 0x0b, 0x3b, 0xa4, 0x34, 0x1c, 0x3b, 0x23, 0x67, 0xe9, 0x3a, 0x8c, 0xb7, 0xef, + 0x3a, 0x58, 0x7c, 0x30, 0x3b, 0x75, 0x25, 0x22, 0x3b, 0xce, 0x58, 0x81, 0x3b, + 0x37, 0x05, 0x77, 0x3b, 0xa9, 0xc4, 0x22, 0x3b, 0xfd, 0x03, 0x32, 0x3b, 0x64, + 0xd1, 0x06, 0x3b, 0xb2, 0x45, 0x11, 0x3b, 0x69, 0xf3, 0xf1, 0x3a, 0xb1, 0xda, + 0x02, 0x3b, 0x36, 0xa0, 0x42, 0x3b, 0x2c, 0x4e, 0x45, 0x3b, 0x04, 0xbf, 0x0c, + 0x3b, 0x8e, 0x3a, 0x46, 0x3b, 0x07, 0xad, 0x3e, 0x3b, 0x82, 0xcf, 0x06, 0x3b, + 0xdc, 0xa6, 0xe6, 0x3a, 0x11, 0xf5, 0x10, 0x3b, 0x09, 0xef, 0xf3, 0x3a, 0x6d, + 0x02, 0x11, 0x3b, 0xcf, 0x6f, 0xff, 0x3a, 0x0a, 0xb6, 0x6e, 0x3b, 0x01, 0x9d, + 0x25, 0x3b, 0x2e, 0x1a, 0x25, 0x3b, 0xc7, 0xa8, 0x34, 0x3b, 0x9e, 0x30, 0x24, + 0x3b, 0xe5, 0x89, 0xe8, 0x3a, 0x9e, 0x0e, 0x3b, 0x3b, 0xcf, 0x03, 0x0d, 0x3b, + 0xcf, 0xa9, 0x37, 0x3b, 0xde, 0xee, 0x1e, 0x3b, 0x00, 0x9d, 0x08, 0x3b, 0x9a, + 0xc3, 0x30, 0x3b, 0xcd, 0xb2, 0x14, 0x3b, 0x32, 0xbe, 0x29, 0x3b, 0x1e, 0x0a, + 0x0e, 0x3b, 0xb9, 0x86, 0x1c, 0x3b, 0x69, 0x25, 0x1d, 0x3b, 0x3d, 0xf6, 0x33, + 0x3b, 0x41, 0x5e, 0x04, 0x3b, 0xb0, 0x40, 0x35, 0x3b, 0xa8, 0x47, 0x16, 0x3b, + 0xfa, 0x67, 0x22, 0x3b, 0x0d, 0x6a, 0x01, 0x3b, 0x9d, 0xdb, 0x0d, 0x3b, 0x71, + 0xc1, 0x45, 0x3b, 0xe3, 0xb3, 0x05, 0x3b, 0x50, 0xf0, 0x23, 0x3b, 0xe0, 0xfa, + 0x4c, 0x3b, 0xb7, 0xaa, 0x1d, 0x3b, 0x2c, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x5f, 0x31, 0x31, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, + 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfe, 0xf2, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x64, 0x06, 0x00, 0x00, 0x0d, + 0x00, 0x00, 0x00, 0x20, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x5a, 0xec, + 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x60, 0xb4, 0xc7, 0x3b, 0xf2, 0x84, 0xdd, + 0x3b, 0x43, 0xf1, 0x08, 0x3c, 0x44, 0xaf, 0xbc, 0x3b, 0x85, 0x80, 0xa0, 0x3b, + 0xa1, 0xa5, 0xa5, 0x3b, 0xa5, 0x21, 0xd8, 0x3b, 0x03, 0xc9, 0x0a, 0x3c, 0x16, + 0x3b, 0xe2, 0x3b, 0x28, 0xd7, 0x17, 0x3c, 0xd1, 0x70, 0x14, 0x3c, 0x68, 0x0a, + 0xc2, 0x3b, 0x88, 0xea, 0x03, 0x3c, 0x4b, 0xd8, 0x27, 0x3c, 0xf2, 0x2b, 0xdb, + 0x3b, 0x1b, 0x19, 0x93, 0x3b, 0x08, 0x5a, 0xfe, 0x3b, 0x1d, 0x52, 0xa1, 0x3b, + 0xa4, 0x8d, 0xa9, 0x3b, 0x15, 0x51, 0x38, 0x3b, 0xe8, 0xaf, 0xb7, 0x3b, 0x20, + 0xf5, 0xe2, 0x3b, 0xad, 0xb9, 0x5c, 0x3b, 0xd7, 0x58, 0xc7, 0x3b, 0x4d, 0xf2, + 0xdc, 0x3b, 0x09, 0x90, 0xd8, 0x3b, 0xa0, 0x21, 0x26, 0x3c, 0xa6, 0x94, 0x2a, + 0x3c, 0x34, 0xde, 0x15, 0x3c, 0x96, 0xa8, 0x0e, 0x3c, 0xec, 0xf1, 0x62, 0x3b, + 0x86, 0x75, 0xef, 0x3b, 0xd2, 0x3d, 0xf7, 0x3b, 0x06, 0xfb, 0xfb, 0x3b, 0xff, + 0xaf, 0xa9, 0x3b, 0x84, 0xaf, 0xee, 0x3b, 0xed, 0x73, 0x92, 0x3b, 0x26, 0xd9, + 0xc9, 0x3b, 0xf0, 0xe3, 0x4d, 0x3c, 0x54, 0x6d, 0xae, 0x3b, 0x95, 0xb2, 0xf4, + 0x3b, 0x4c, 0x06, 0x10, 0x3c, 0xc9, 0x2c, 0x26, 0x3c, 0xf4, 0x94, 0xac, 0x3b, + 0xb6, 0x91, 0x8f, 0x3b, 0xb3, 0x7f, 0x96, 0x3b, 0xd8, 0x26, 0xda, 0x3b, 0x22, + 0xf7, 0xd5, 0x3b, 0x2f, 0x36, 0xf2, 0x3b, 0x4f, 0x35, 0xae, 0x3b, 0xbd, 0xf4, + 0x9f, 0x3b, 0x57, 0xea, 0xeb, 0x3b, 0x0f, 0xd9, 0xc7, 0x3b, 0xa2, 0xdb, 0xf5, + 0x3b, 0x53, 0x20, 0xce, 0x3b, 0x79, 0x60, 0x31, 0x3c, 0x20, 0x91, 0xb4, 0x3b, + 0xbc, 0x23, 0x15, 0x3c, 0x83, 0x1a, 0xf2, 0x3b, 0x09, 0x71, 0xc9, 0x3b, 0xf6, + 0x17, 0xb0, 0x3b, 0x9d, 0xc6, 0xc5, 0x3b, 0x71, 0x97, 0x22, 0x3c, 0x2c, 0x9e, + 0xf8, 0x3b, 0xc9, 0x79, 0x15, 0x3c, 0x0a, 0xfe, 0xaa, 0x3b, 0x83, 0x58, 0xa0, + 0x3b, 0xbc, 0x63, 0x9c, 0x3b, 0x43, 0x51, 0xa5, 0x3b, 0x33, 0xe5, 0xe2, 0x3b, + 0x3f, 0xb3, 0xd8, 0x3b, 0xe6, 0xe2, 0xbf, 0x3b, 0xce, 0xed, 0xe9, 0x3b, 0xdb, + 0x3f, 0xa1, 0x3b, 0xec, 0x47, 0xc7, 0x3b, 0x9d, 0xa7, 0xc5, 0x3b, 0x2e, 0xab, + 0x03, 0x3c, 0xfd, 0x97, 0xf0, 0x3b, 0x61, 0x09, 0x08, 0x3c, 0x4c, 0xe2, 0xfb, + 0x3b, 0x9b, 0x41, 0xa7, 0x3b, 0xbb, 0xb0, 0x9f, 0x3b, 0x6c, 0xb1, 0xd0, 0x3b, + 0x35, 0x03, 0x71, 0x3b, 0x63, 0x93, 0xc3, 0x3b, 0xbe, 0xfd, 0xda, 0x3b, 0x99, + 0xfe, 0xfa, 0x3b, 0xa3, 0x6f, 0x36, 0x3c, 0xf2, 0x06, 0xec, 0x3b, 0x05, 0xbd, + 0x92, 0x3b, 0x13, 0xea, 0x15, 0x3c, 0xbf, 0xa8, 0xd0, 0x3b, 0xf5, 0x2f, 0xf8, + 0x3b, 0xb9, 0xd4, 0x2a, 0x3c, 0x3d, 0x35, 0x1f, 0x3c, 0x24, 0xb2, 0x2c, 0x3c, + 0x49, 0x7c, 0x1a, 0x3c, 0x55, 0x86, 0xdf, 0x3b, 0xd6, 0xb4, 0x98, 0x3b, 0x78, + 0x8e, 0xd0, 0x3b, 0xa1, 0x51, 0xe4, 0x3b, 0xa4, 0x60, 0x92, 0x3b, 0x8e, 0x86, + 0x48, 0x3b, 0xdc, 0xc6, 0xe7, 0x3b, 0x21, 0xaf, 0xeb, 0x3b, 0xfb, 0x7b, 0x20, + 0x3c, 0xf6, 0x56, 0xf9, 0x3b, 0x14, 0xbc, 0x29, 0x3c, 0x1e, 0xf5, 0xca, 0x3b, + 0x33, 0x5f, 0x14, 0x3c, 0xe1, 0x61, 0x8a, 0x3b, 0x37, 0xdf, 0x9f, 0x3b, 0x5b, + 0x1b, 0xff, 0x3b, 0x0b, 0x7f, 0xbc, 0x3b, 0x9d, 0xcd, 0xc8, 0x3b, 0xe2, 0xe4, + 0xdf, 0x3b, 0x03, 0x51, 0xc9, 0x3b, 0xf8, 0x18, 0xc1, 0x3b, 0x70, 0xe5, 0x20, + 0x3c, 0x96, 0xfb, 0xf6, 0x3b, 0x78, 0x83, 0xf1, 0x3b, 0xe9, 0x4e, 0xcd, 0x3b, + 0xd1, 0x25, 0xb4, 0x3b, 0x38, 0xa5, 0xe8, 0x3b, 0xc7, 0x84, 0x12, 0x3c, 0xbd, + 0xb1, 0x20, 0x3c, 0x2f, 0xa2, 0x35, 0x3c, 0x03, 0xee, 0x0d, 0x3c, 0x36, 0x00, + 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, + 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, 0x64, 0x5f, 0x31, 0x31, 0x5f, 0x64, 0x65, + 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, + 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, + 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x7e, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x09, 0x64, 0x06, 0x00, 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x28, 0x06, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x00, + 0x00, 0x0c, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xf0, 0x76, 0x2c, 0x3b, 0x4c, 0x26, 0x1e, 0x3b, 0x2a, 0x85, 0x1d, 0x3b, + 0xa7, 0x53, 0x12, 0x3b, 0xce, 0xf3, 0x0e, 0x3b, 0x0f, 0x15, 0x04, 0x3b, 0xce, + 0x92, 0xfe, 0x3a, 0x9b, 0xe7, 0xe1, 0x3a, 0x17, 0xcf, 0x1a, 0x3b, 0xeb, 0x2f, + 0x31, 0x3b, 0x15, 0xe1, 0x66, 0x3b, 0x5a, 0x04, 0x38, 0x3b, 0xd1, 0x2f, 0x19, + 0x3b, 0xb2, 0xf8, 0x1b, 0x3b, 0x63, 0x78, 0x0e, 0x3b, 0x80, 0x63, 0x41, 0x3b, + 0x7e, 0x98, 0x3d, 0x3b, 0xeb, 0x0f, 0x13, 0x3b, 0x31, 0x60, 0x2d, 0x3b, 0xe1, + 0x7f, 0x34, 0x3b, 0x89, 0xa6, 0x2d, 0x3b, 0x18, 0x1e, 0x57, 0x3b, 0x35, 0xcc, + 0x1c, 0x3b, 0x16, 0x67, 0x29, 0x3b, 0xa7, 0x7d, 0x26, 0x3b, 0x3a, 0xee, 0x22, + 0x3b, 0x08, 0x08, 0x62, 0x3b, 0x04, 0xbd, 0x19, 0x3b, 0x44, 0x97, 0x40, 0x3b, + 0x27, 0xea, 0x26, 0x3b, 0x6a, 0xdd, 0x0d, 0x3b, 0xe4, 0x56, 0xfb, 0x3a, 0x4a, + 0x5a, 0x1f, 0x3b, 0x5a, 0x92, 0xff, 0x3a, 0x1c, 0x45, 0x32, 0x3b, 0x3e, 0x91, + 0x28, 0x3b, 0x93, 0x74, 0x5c, 0x3b, 0x1c, 0x54, 0x27, 0x3b, 0xd9, 0xb5, 0x1f, + 0x3b, 0x85, 0x55, 0x18, 0x3b, 0x6f, 0x0e, 0x2f, 0x3b, 0xae, 0x7f, 0x16, 0x3b, + 0x6e, 0x3d, 0x1c, 0x3b, 0xfc, 0x0d, 0xf7, 0x3a, 0x82, 0x18, 0x1b, 0x3b, 0xc5, + 0x09, 0x03, 0x3b, 0xaf, 0xb4, 0x15, 0x3b, 0xa9, 0xee, 0x46, 0x3b, 0x65, 0x6d, + 0x14, 0x3b, 0x29, 0x75, 0x51, 0x3b, 0x0b, 0xf8, 0x1c, 0x3b, 0x61, 0xcd, 0x5c, + 0x3b, 0x05, 0x33, 0x2a, 0x3b, 0xb7, 0x1c, 0x07, 0x3b, 0x26, 0x72, 0x34, 0x3b, + 0x59, 0xe7, 0x3f, 0x3b, 0xd6, 0xe8, 0x21, 0x3b, 0x8a, 0x3a, 0x3d, 0x3b, 0xbe, + 0xf2, 0x1b, 0x3b, 0x76, 0xb4, 0x06, 0x3b, 0xea, 0x1b, 0xfa, 0x3a, 0xeb, 0x0f, + 0xf7, 0x3a, 0x2a, 0x56, 0x2b, 0x3b, 0xca, 0xc0, 0x20, 0x3b, 0x15, 0x3c, 0x45, + 0x3b, 0x98, 0xbe, 0x1d, 0x3b, 0x8c, 0x8d, 0x20, 0x3b, 0xe2, 0x44, 0x58, 0x3b, + 0x05, 0x3b, 0x68, 0x3b, 0x9f, 0xf7, 0x8a, 0x3b, 0xe2, 0xf0, 0xfd, 0x3a, 0x2b, + 0xef, 0xfa, 0x3a, 0x8e, 0xa7, 0x1d, 0x3b, 0xe6, 0xc2, 0xea, 0x3a, 0xf1, 0x17, + 0x30, 0x3b, 0x55, 0x96, 0x1d, 0x3b, 0xf4, 0xfe, 0x07, 0x3b, 0x39, 0xb3, 0xed, + 0x3a, 0x2b, 0x40, 0xfe, 0x3a, 0x84, 0xa2, 0x18, 0x3b, 0xfc, 0x29, 0x22, 0x3b, + 0xc9, 0xae, 0x11, 0x3b, 0xa5, 0x0e, 0x2b, 0x3b, 0x2b, 0x0c, 0x07, 0x3b, 0xf0, + 0x3a, 0x49, 0x3b, 0xdc, 0x3e, 0x47, 0x3b, 0x35, 0x81, 0x1b, 0x3b, 0x9d, 0x0c, + 0xf2, 0x3a, 0x95, 0xae, 0x1b, 0x3b, 0xe2, 0x10, 0x18, 0x3b, 0x85, 0x68, 0x1d, + 0x3b, 0x74, 0x46, 0x52, 0x3b, 0x99, 0xbb, 0x3a, 0x3b, 0x28, 0xf7, 0x44, 0x3b, + 0xb7, 0xfe, 0x5c, 0x3b, 0x21, 0x04, 0x2f, 0x3b, 0x3b, 0x3b, 0x38, 0x3b, 0x92, + 0x09, 0x22, 0x3b, 0xbd, 0xa0, 0x08, 0x3b, 0x60, 0xda, 0x01, 0x3b, 0xcd, 0xce, + 0xe3, 0x3a, 0x59, 0x24, 0x36, 0x3b, 0x0a, 0x66, 0xff, 0x3a, 0xd4, 0x6e, 0x07, + 0x3b, 0xb9, 0x61, 0x17, 0x3b, 0x38, 0xf5, 0x24, 0x3b, 0xd1, 0x3e, 0x4a, 0x3b, + 0x77, 0x2d, 0x19, 0x3b, 0x59, 0x7f, 0x1b, 0x3b, 0xb8, 0x29, 0x0a, 0x3b, 0xfb, + 0xa8, 0x0c, 0x3b, 0xdb, 0xa3, 0x16, 0x3b, 0x33, 0x17, 0x30, 0x3b, 0x9c, 0x16, + 0x51, 0x3b, 0x91, 0x1b, 0x3c, 0x3b, 0x5c, 0xfc, 0x2a, 0x3b, 0x81, 0xb1, 0x0d, + 0x3b, 0x9e, 0x42, 0x20, 0x3b, 0x2e, 0x0d, 0x12, 0x3b, 0xe0, 0x98, 0x13, 0x3b, + 0x8e, 0x42, 0x24, 0x3b, 0x31, 0x04, 0x16, 0x3b, 0x10, 0x6b, 0x0c, 0x3b, 0xb9, + 0xad, 0x14, 0x3b, 0x57, 0x5e, 0x0b, 0x3b, 0x52, 0x65, 0x4b, 0x3b, 0x2f, 0xf2, + 0x17, 0x3b, 0x61, 0x9a, 0x1a, 0x3b, 0x2c, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, + 0x69, 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, + 0x32, 0x64, 0x5f, 0x31, 0x30, 0x5f, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x77, 0x69, + 0x73, 0x65, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, + 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x10, + 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x68, 0x06, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x6a, 0xf9, 0xff, 0xff, 0x14, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xcb, 0x37, 0xb8, 0x3b, 0x43, 0xf6, 0xc2, 0x3b, 0x44, 0xf2, 0xe8, 0x3b, 0x8f, + 0xc2, 0xca, 0x3b, 0xc4, 0x3c, 0xd0, 0x3b, 0xce, 0x26, 0xf3, 0x3b, 0x85, 0x6f, + 0xb5, 0x3b, 0xa4, 0x85, 0xd8, 0x3b, 0xa7, 0x2b, 0xd0, 0x3b, 0x9e, 0x75, 0xa0, + 0x3b, 0x9c, 0xc0, 0xdb, 0x3b, 0x19, 0x83, 0x07, 0x3c, 0x97, 0x4e, 0xeb, 0x3b, + 0xa3, 0x3c, 0x05, 0x3c, 0x22, 0x33, 0x26, 0x3c, 0x87, 0xb0, 0x8e, 0x3b, 0x61, + 0x69, 0x09, 0x3c, 0x2e, 0x3d, 0xfd, 0x3b, 0xe0, 0x36, 0xad, 0x3b, 0x20, 0x8e, + 0xa4, 0x3b, 0x5d, 0x17, 0x01, 0x3c, 0x10, 0x48, 0xc9, 0x3b, 0x1f, 0x7e, 0x6e, + 0x3b, 0x3c, 0x72, 0xde, 0x3b, 0xb7, 0xfc, 0x1e, 0x3c, 0x5b, 0x4d, 0x91, 0x3b, + 0xc7, 0x0b, 0xb9, 0x3b, 0x3f, 0x6b, 0xb1, 0x3b, 0x11, 0x9e, 0xe3, 0x3b, 0x5c, + 0xec, 0x22, 0x3c, 0xae, 0x0f, 0xe5, 0x3b, 0xcc, 0xe8, 0x71, 0x3b, 0x80, 0x02, + 0x04, 0x3c, 0xe1, 0xfd, 0x00, 0x3c, 0x34, 0xb5, 0xc4, 0x3b, 0x8c, 0xb7, 0x3a, + 0x3c, 0xde, 0xe4, 0xaa, 0x3b, 0x3e, 0xfa, 0xf0, 0x3b, 0x4f, 0x3f, 0x0c, 0x3c, + 0xa8, 0xb8, 0xa7, 0x3b, 0xb1, 0xb7, 0xe1, 0x3b, 0x81, 0x09, 0x94, 0x3b, 0xc6, + 0xde, 0x10, 0x3c, 0x2f, 0xbe, 0x2c, 0x3c, 0xfe, 0x65, 0x01, 0x3c, 0x49, 0x9a, + 0x8a, 0x3b, 0x3d, 0x56, 0xd7, 0x3b, 0x21, 0x5e, 0xc4, 0x3b, 0x61, 0x7d, 0x0d, + 0x3c, 0xf9, 0x5a, 0x89, 0x3b, 0x69, 0xb0, 0xe0, 0x3b, 0x8f, 0xa5, 0xf7, 0x3b, + 0x76, 0x26, 0x03, 0x3c, 0xcb, 0x44, 0xe1, 0x3b, 0x28, 0x7a, 0x8d, 0x3b, 0xe5, + 0x1a, 0xea, 0x3b, 0x64, 0xdd, 0x9c, 0x3b, 0x57, 0xb5, 0x70, 0x3b, 0x22, 0xee, + 0xed, 0x3b, 0xa3, 0x21, 0x7c, 0x3b, 0xaf, 0x49, 0x8a, 0x3b, 0x56, 0x4a, 0xdc, + 0x3b, 0x23, 0xe9, 0x43, 0x3c, 0x2c, 0x58, 0xcb, 0x3b, 0x12, 0xe8, 0x9f, 0x3b, + 0xd0, 0xd2, 0xf4, 0x3b, 0x96, 0x9d, 0x9f, 0x3b, 0x48, 0x20, 0xea, 0x3b, 0x63, + 0x63, 0x0f, 0x3c, 0xd0, 0x99, 0xd0, 0x3b, 0x70, 0xd2, 0xd6, 0x3b, 0x67, 0xb5, + 0x13, 0x3c, 0x79, 0x9d, 0xab, 0x3b, 0x5b, 0x4d, 0x73, 0x3b, 0x2e, 0x3a, 0x9d, + 0x3b, 0x6a, 0x9c, 0xc9, 0x3b, 0x44, 0xff, 0x8b, 0x3b, 0x13, 0xae, 0xae, 0x3b, + 0x28, 0x06, 0x86, 0x3b, 0x05, 0x59, 0xae, 0x3b, 0x95, 0x1e, 0xd4, 0x3b, 0x4a, + 0x6e, 0xa7, 0x3b, 0xc9, 0x7a, 0x15, 0x3c, 0xcb, 0x63, 0xbe, 0x3b, 0x82, 0x8a, + 0x6f, 0x3b, 0x86, 0x3f, 0xd7, 0x3b, 0xfb, 0xba, 0x15, 0x3c, 0x8f, 0xb8, 0x1c, + 0x3c, 0xa9, 0xf4, 0xea, 0x3b, 0xe2, 0x65, 0x38, 0x3c, 0x8b, 0x4a, 0xd3, 0x3b, + 0xb7, 0xae, 0xdf, 0x3b, 0xbb, 0x74, 0xff, 0x3b, 0x0c, 0x0d, 0x92, 0x3b, 0x2e, + 0x0c, 0x55, 0x3c, 0xb5, 0xf6, 0xff, 0x3b, 0xa5, 0x05, 0x2f, 0x3c, 0x95, 0xbe, + 0xbd, 0x3b, 0xc3, 0x7b, 0x9e, 0x3b, 0xe2, 0xce, 0xda, 0x3b, 0xe9, 0xfd, 0xbf, + 0x3b, 0x57, 0x1c, 0x9b, 0x3b, 0xf2, 0x1f, 0x62, 0x3b, 0x8b, 0x89, 0xf3, 0x3b, + 0x83, 0xb6, 0x8a, 0x3b, 0x4c, 0x0f, 0xd6, 0x3b, 0x98, 0xc6, 0x00, 0x3c, 0x81, + 0xd3, 0x10, 0x3c, 0xe8, 0x22, 0x3b, 0x3c, 0x0e, 0xfa, 0x19, 0x3c, 0x64, 0x7e, + 0xe6, 0x3b, 0x12, 0x99, 0xce, 0x3b, 0x20, 0x57, 0x99, 0x3b, 0x51, 0xa6, 0xe1, + 0x3b, 0x5f, 0x8d, 0xb7, 0x3b, 0xce, 0xfc, 0x86, 0x3b, 0x17, 0x3d, 0xdf, 0x3b, + 0xd1, 0x68, 0xf0, 0x3b, 0x20, 0x38, 0xd5, 0x3b, 0x13, 0x4e, 0xa1, 0x3b, 0x6d, + 0x6f, 0x79, 0x3b, 0x4f, 0xf4, 0xc3, 0x3b, 0xbd, 0x9f, 0x00, 0x3c, 0x0f, 0xa4, + 0xf4, 0x3b, 0x6a, 0x1f, 0x13, 0x3c, 0xbb, 0x81, 0x83, 0x3b, 0xaf, 0xc6, 0xf5, + 0x3b, 0x5c, 0xa1, 0xf7, 0x3b, 0x36, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x31, 0x30, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, + 0x65, 0x2f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x77, 0x69, 0x73, 0x65, 0x5f, 0x77, + 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x1a, 0x00, + 0x08, 0x00, 0x07, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0xc4, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x12, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, + 0x03, 0x86, 0x3c, 0x60, 0xfe, 0xd9, 0x3c, 0xcc, 0x1c, 0x47, 0x3b, 0xda, 0xcf, + 0x55, 0x3b, 0xa8, 0x02, 0x3d, 0x3c, 0x15, 0x1e, 0x19, 0x3d, 0xbb, 0x9a, 0x94, + 0x3c, 0x90, 0x5f, 0x8e, 0x3a, 0x21, 0x00, 0x00, 0x00, 0x4d, 0x6f, 0x62, 0x69, + 0x6c, 0x65, 0x6e, 0x65, 0x74, 0x56, 0x31, 0x2f, 0x43, 0x6f, 0x6e, 0x76, 0x32, + 0x64, 0x5f, 0x30, 0x2f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x73, 0x2f, 0x72, + 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd6, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x19, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x08, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, + 0xf2, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, +}; +const int g_person_detect_model_data_len = 300568; diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detect_model_data.h b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detect_model_data.h new file mode 100644 index 000000000..86471b304 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detect_model_data.h @@ -0,0 +1,27 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 is a standard TensorFlow Lite model file that has been converted into a +// C data array, so it can be easily compiled into a binary for devices that +// don't have a file system. It was created using the command: +// xxd -i person_detect.tflite > person_detect_model_data.cc + +#ifndef TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_PERSON_DETECT_MODEL_DATA_H_ +#define TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_PERSON_DETECT_MODEL_DATA_H_ + +extern const unsigned char g_person_detect_model_data[]; +extern const int g_person_detect_model_data_len; + +#endif // TENSORFLOW_LITE_MICRO_EXAMPLES_PERSON_DETECTION_PERSON_DETECT_MODEL_DATA_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detection.ino b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detection.ino new file mode 100644 index 000000000..caefcf71c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/examples/person_detection/person_detection.ino @@ -0,0 +1,132 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "detection_responder.h" +#include "image_provider.h" +#include "main_functions.h" +#include "model_settings.h" +#include "person_detect_model_data.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" + +// Globals, used for compatibility with Arduino-style sketches. +namespace { +tflite::ErrorReporter* error_reporter = nullptr; +const tflite::Model* model = nullptr; +tflite::MicroInterpreter* interpreter = nullptr; +TfLiteTensor* input = nullptr; + +// In order to use optimized tensorflow lite kernels, a signed int8_t quantized +// model is preferred over the legacy unsigned model format. This means that +// throughout this project, input images must be converted from unisgned to +// signed format. The easiest and quickest way to convert from unsigned to +// signed 8-bit integers is to subtract 128 from the unsigned value to get a +// signed value. + +// An area of memory to use for input, output, and intermediate arrays. +constexpr int kTensorArenaSize = 136 * 1024; +static uint8_t tensor_arena[kTensorArenaSize]; +} // namespace + +// The name of this function is important for Arduino compatibility. +void setup() { + tflite::InitializeTarget(); + + // Set up logging. Google style is to avoid globals or statics because of + // lifetime uncertainty, but since this has a trivial destructor it's okay. + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::MicroErrorReporter micro_error_reporter; + error_reporter = µ_error_reporter; + + // Map the model into a usable data structure. This doesn't involve any + // copying or parsing, it's a very lightweight operation. + model = tflite::GetModel(g_person_detect_model_data); + if (model->version() != TFLITE_SCHEMA_VERSION) { + TF_LITE_REPORT_ERROR(error_reporter, + "Model provided is schema version %d not equal " + "to supported version %d.", + model->version(), TFLITE_SCHEMA_VERSION); + return; + } + + // Pull in only the operation implementations we need. + // This relies on a complete list of all the ops needed by this graph. + // An easier approach is to just use the AllOpsResolver, but this will + // incur some penalty in code space for op implementations that are not + // needed by this graph. + // + // tflite::AllOpsResolver resolver; + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::MicroMutableOpResolver<5> micro_op_resolver; + micro_op_resolver.AddAveragePool2D(); + micro_op_resolver.AddConv2D(); + micro_op_resolver.AddDepthwiseConv2D(); + micro_op_resolver.AddReshape(); + micro_op_resolver.AddSoftmax(); + + // Build an interpreter to run the model with. + // NOLINTNEXTLINE(runtime-global-variables) + static tflite::MicroInterpreter static_interpreter( + model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter); + interpreter = &static_interpreter; + + // Allocate memory from the tensor_arena for the model's tensors. + TfLiteStatus allocate_status = interpreter->AllocateTensors(); + if (allocate_status != kTfLiteOk) { + TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed"); + return; + } + + // Get information about the memory area to use for the model's input. + input = interpreter->input(0); + + if ((input->dims->size != 4) || (input->dims->data[0] != 1) || + (input->dims->data[1] != kNumRows) || + (input->dims->data[2] != kNumCols) || + (input->dims->data[3] != kNumChannels) || (input->type != kTfLiteInt8)) { + TF_LITE_REPORT_ERROR(error_reporter, + "Bad input tensor parameters in model"); + return; + } +} + +// The name of this function is important for Arduino compatibility. +void loop() { + // Get image from provider. + if (kTfLiteOk != GetImage(error_reporter, input)) { + TF_LITE_REPORT_ERROR(error_reporter, "Image capture failed."); + } + + // Run the model on this input and make sure it succeeds. + if (kTfLiteOk != interpreter->Invoke()) { + TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed."); + } + + TfLiteTensor* output = interpreter->output(0); + + // Process the inference results. + int8_t person_score = output->data.uint8[kPersonIndex]; + int8_t no_person_score = output->data.uint8[kNotAPersonIndex]; + float person_score_f = + (person_score - output->params.zero_point) * output->params.scale; + float no_person_score_f = + (no_person_score - output->params.zero_point) * output->params.scale; + RespondToDetection(error_reporter, person_score_f, no_person_score_f); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/library.json b/lib/libesp32_ml/tf_lite_esp32/library.json new file mode 100644 index 000000000..5c49bb378 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/library.json @@ -0,0 +1,15 @@ +{ + "name": "tf_lite_esp32", + "version": "0.0.1", + "keywords": "tensor flow", + "description": "Tensor flow lite for Arduino-ESP32", + "frameworks": "arduino", + "platforms": "espressif32", + "build": { + "libArchive": true, + "flags": [ + "-I Source/include", + "-I Source/esp-nn/include" + ] + } +} \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/library.properties b/lib/libesp32_ml/tf_lite_esp32/library.properties new file mode 100644 index 000000000..028d14440 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/library.properties @@ -0,0 +1,13 @@ +name=Arduino_TensorFlowLite for ESP32 +version=0.0.1-ALPHA +author=TensorFlow Authors +maintainer=Pete Warden +sentence=Allows you to run machine learning models locally on your device. +paragraph=This library runs TensorFlow machine learning models on microcontrollers, allowing you to build AI/ML applications powered by deep learning and neural networks. With the included examples, you can recognize speech, detect people using a camera, and recognise "magic wand" gestures using an accelerometer. +category=Data Processing +url=https://www.tensorflow.org/lite/microcontrollers/overview +ldflags= +includes=TensorFlowLite.h +precompiled=full +dot_a_linkage=false +depends=Arduino diff --git a/lib/libesp32_ml/tf_lite_esp32/src/TensorFlowLite.h b/lib/libesp32_ml/tf_lite_esp32/src/TensorFlowLite.h new file mode 100644 index 000000000..f549f5233 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/TensorFlowLite.h @@ -0,0 +1,26 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_TOOLS_MAKE_TEMPLATES_TENSORFLOWLITE_H_ +#define TENSORFLOW_LITE_MICRO_TOOLS_MAKE_TEMPLATES_TENSORFLOWLITE_H_ + +// This header is deliberately empty, and is only present because including it +// in a .ino sketch forces the Arduino toolchain to build the rest of the +// library. + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "esp-nn/include/esp_nn.h" + + +#endif // TENSORFLOW_LITE_MICRO_TOOLS_MAKE_TEMPLATES_TENSORFLOWLITE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/.gitignore b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/.gitignore new file mode 100644 index 000000000..08ca72b5b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/.gitignore @@ -0,0 +1,57 @@ +.config +*.o +*.i +*.s +*.orig +*.pyc + +# gtags +GTAGS +GRTAGS +GPATH + +# emacs +.dir-locals.el + +# emacs temp file suffixes +*~ +.#* +\#*# + +# eclipse setting +.settings + +# MacOS directory files +.DS_Store + +# Example project files +examples/**/sdkconfig +examples/**/sdkconfig.old +examples/**/build + +# Test app files +test_app/build +test_app/sdkconfig +test_app/sdkconfig.old + +# Doc build artifacts +docs/_build/ +docs/doxygen-warning-log.txt +docs/sphinx-warning-log.txt +docs/sphinx-warning-log-sanitized.txt +docs/xml/ +docs/xml_in/ +docs/man/ +docs/doxygen_sqlite3.db + +TEST_LOGS + + +# gcov coverage reports +*.gcda +*.gcno +coverage.info +coverage_report/ + +# VS Code Settings +.vscode/ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/.gitlab-ci.yml b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/.gitlab-ci.yml new file mode 100644 index 000000000..6b540bda8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/.gitlab-ci.yml @@ -0,0 +1,55 @@ +stages: + - build + +variables: + BATCH_BUILD: "1" + V: "0" + MAKEFLAGS: "-j8 --no-keep-going" + IDF_PATH: "$CI_PROJECT_DIR/esp-idf" + LOG_PATH: "$CI_PROJECT_DIR" + +.set_git_config: &set_git_config + # Set git config + - git config user.email "test@espressif.com" + - git config user.name "Espressif" + +.add_ssh_key: &add_ssh_key + # Add gitlab ssh key + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $GITLAB_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host gitlab.espressif.cn\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config + +before_script: + # Add gitlab ssh key + - *add_ssh_key + # Set git config + - *set_git_config + +.build_esp32s3: &build_esp32s3 + - idf.py set-target esp32s3 build + +.build_esp32: &build_esp32 + - idf.py set-target esp32 build + +build_demo: + stage: build + image: $CI_DOCKER_REGISTRY/esp32-ci-env:esp-nn + tags: + - build + script: + # Clone IDF + - git clone --recursive --single-branch -b release/v4.4 --reference-if-able /local_references/gitlab/ https://gitlab-ci-token:${BOT_TOKEN}@gitlab.espressif.cn:6688/espressif/esp-idf.git + - cd esp-idf + - ./install.sh + - . ./export.sh + - cd .. + # Build examples now + - cd test_app + # Build esp32s3 + - *build_esp32s3 + # Build esp32 + - *build_esp32 + - cd - diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/LICENSE b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/LICENSE @@ -0,0 +1,202 @@ + + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/README.md b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/README.md new file mode 100644 index 000000000..f70f40747 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/README.md @@ -0,0 +1,55 @@ +# ESP-NN + +The library contains optimised NN (Neural Network) functions for various Espressif chipsets. + +* Supported platforms: + * TensorFlow Lite Micro (TFLite Micro). Repo can be found [here](https://github.com/espressif/tflite-micro-esp-examples) + +* Supported ESP chipsets include: + * ESP32-S3 (Assembly versions optimised to benefit from vector instructions of ESP32-S3) + * ESP32 (Generic optimisations) + * ESP32-C3 (Generic optimisations) + +## Performance + +### Kernelwise performance for s8 versions: + + * Kernelwise performance on ESP32-S3 chip + * Numbers are ticks taken for kernel to execute + * Chip config: 240MHz, SPI: QPI 80MHz, Data cache: 64KB + + | Function | ANSI C | ESP32-S3 Opt | Opt Ratio | Data info | Memory | + | ----------------| --------|---------|---------|-------------|-----------| + | elementwise_add | 320397 | 87119 | 3.68 | size = 1615 | External | + | elementwise_mul | 125958 | 44239 | 2.85 | size = 1615 | External | + | convolution | 4663012 | 428675 | 10.88 | input(10,10), filter(64x1x1x64) | External | + | convolution | 301014 | 32433 | 9.28 | input(8,8), filter(16x1x1x16) | External | + | convolution | 2115418 | 1020923 | 2.07 | input(10,10), filter(64x3x3x3) | External | + | depthwise conv | 1190062 | 203278 | 5.85 | input (18, 18), pad(0,0), stride(1,1) filter: 1x3x3x16 | External | + | depthwise conv | 837072 | 182335 | 4.59 | input (12, 12), pad(1,1), stride(1,1) filter: 8x5x5x4 | External | + | max pool | 485714 | 76747 | 6.33 | input(16,16), filter (1x3x3x16) | Internal | + | avg pool | 541462 | 160580 | 3.37 | input(16,16), filter (1x3x3x16) | Internal | + | fully connected | 15853 | 9547 | 1.66 | len: 265, ch = 3 | Internal | + | prelu (relu6) | 19472 | 2734 | 7.12 | size, 1615 | Internal | + + +## Configuration + + * To configure, please use `idf.py menuconfig` and under `ESP-NN` select `NN_OPTIMIZATIONS` + * There are two options presented: + * Optimized versions + * ANSI C + + * Default selection is for `Optimized versions`. For ESP32-S3, assembly versions are automatically selected, whereas for other chipsets (viz., ESP32, ESP32-C3), generic optimisations are selected. + * For debugging purposes, you may want to select `ANSI C` reference versions. + + +## Contributing + +If you encounter an issue with ESP-NN, or wish to submit a feature request, please use the Issues section on the Github. + +For general questions related to this library, please use the esp32.com forum. + +## Copyrights and License + +All original source code in this repository is Copyright (C) 2020-2021 Espressif Systems. This source code is licensed under the Apache License 2.0 as described in the file LICENSE. diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn.h new file mode 100644 index 000000000..bd5331194 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn.h @@ -0,0 +1,46 @@ +// Copyright 2020-2021 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 defined(CONFIG_NN_OPTIMIZED) +// select apt optimisations +#ifdef CONFIG_IDF_TARGET_ESP32S3 +#define ARCH_ESP32_S3 1 +#endif +#ifdef CONFIG_IDF_TARGET_ESP32 +#define ARCH_ESP32 1 +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* reference kernels included by default */ +#include "esp_nn_ansi_headers.h" + +#if defined(CONFIG_NN_OPTIMIZED) +#if defined(ARCH_ESP32_S3) +#include "esp_nn_esp32s3.h" +#else // for other platforms use generic optimisations +#include "esp_nn_generic_opt.h" +#endif // #if defined(ARCH_ESP32_S3) +#else +#include "esp_nn_ansi_c.h" +#endif + +#ifdef __cplusplus +} +#endif diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_ansi_c.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_ansi_c.h new file mode 100644 index 000000000..8279ebef3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_ansi_c.h @@ -0,0 +1,47 @@ +// Copyright 2020-2021 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 Header definitions to include for ANSI C versions. + * These are just typedefs to pick up ANSI versions. + */ + +#pragma once + +#include "esp_nn_defs.h" +#include "esp_nn_ansi_headers.h" + +#define esp_nn_add_elementwise_s8 esp_nn_add_elementwise_s8_ansi +#define esp_nn_mul_elementwise_s8 esp_nn_mul_elementwise_s8_ansi + +#define esp_nn_depthwise_conv_s8 esp_nn_depthwise_conv_s8_ansi + +#define esp_nn_conv_s8 esp_nn_conv_s8_ansi + +#define esp_nn_get_conv_scratch_size esp_nn_get_conv_scratch_size_ansi +#define esp_nn_set_conv_scratch_buf esp_nn_set_conv_scratch_buf_ansi + +#define esp_nn_get_depthwise_conv_scratch_size esp_nn_get_depthwise_conv_scratch_size_ansi +#define esp_nn_set_depthwise_conv_scratch_buf esp_nn_set_depthwise_conv_scratch_buf_ansi + +#define esp_nn_relu6_s8 esp_nn_relu6_s8_ansi + +#define esp_nn_avg_pool_s8 esp_nn_avg_pool_s8_ansi +#define esp_nn_max_pool_s8 esp_nn_max_pool_s8_ansi + +#define esp_nn_fully_connected_s8 esp_nn_fully_connected_s8_ansi + +#define esp_nn_get_softmax_scratch_size esp_nn_get_softmax_scratch_size_ansi +#define esp_nn_set_softmax_scratch_buf esp_nn_set_softmax_scratch_buf_ansi +#define esp_nn_softmax_s8 esp_nn_softmax_s8_ansi diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_ansi_headers.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_ansi_headers.h new file mode 100644 index 000000000..52ebb6800 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_ansi_headers.h @@ -0,0 +1,309 @@ +// Copyright 2020-2021 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 + +/** + * @file Header definitions to include for esp_nn reference functions + */ + +#include "esp_nn_defs.h" +/************************** Basic math functions ****************************/ + +/** + * @brief elementwise addition + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + * + * shift values are expected to be <= 0 + */ +void esp_nn_add_elementwise_s8_ansi(const int8_t *input1_data, + const int8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + const int32_t input1_mult, + const int32_t input2_mult, + const int32_t input1_shift, + const int32_t input2_shift, + const int32_t left_shift, + int8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size); +/** + * @brief elementwise multiplication + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + * + * output shift is expected to be <= 0 + */ +void esp_nn_mul_elementwise_s8_ansi(const int8_t *input1_data, + const int8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + int8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size); + + +/************************** Convolution functions *****************************/ + +/** + * @brief depthwise convolution per channel + * + * @note inputs type: int8_t, output: int8_t + * Version used in tflite is per channel. + * This version follows the same footsprints. + * Meaning, it has per out_channel shift and multiplier for + * requantization + * + * optimization notes: Though input_offset is int32 type, + * offset values are contained in 8 bits [-128, 127] + */ +void esp_nn_depthwise_conv_s8_ansi(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data); + +/** + * @brief 2d-convolution channelwise + * + * @note operation: result += (input + offset) * filter + * + * inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_conv_s8_ansi(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data); + +int esp_nn_get_conv_scratch_size_ansi(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const conv_params_t *conv_params); +void esp_nn_set_conv_scratch_buf_ansi(const void *buf); + +int esp_nn_get_depthwise_conv_scratch_size_ansi(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const dw_conv_params_t *conv_params); +void esp_nn_set_depthwise_conv_scratch_buf_ansi(const void *buf); + +/************************** Activation functions *****************************/ + +/** + * @brief relu6 + * + * @note inout: int8_t + */ +void esp_nn_relu6_s8_ansi(int8_t *data, uint16_t size); + +/************************** Pooling functions *****************************/ + + +/** + * @brief max_pool + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_max_pool_s8_ansi(const int8_t *input, + const uint16_t input_wd, + const uint16_t input_ht, + int8_t *output, + const uint16_t output_wd, + const uint16_t output_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t filter_wd, + const uint16_t filter_ht, + const uint16_t pad_wd, + const uint16_t pad_ht, + const int32_t activation_min, + const int32_t activation_max, + const uint16_t channels); + +/** + * @brief avg_pool + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_avg_pool_s8_ansi(const int8_t *input, + const uint16_t input_wd, + const uint16_t input_ht, + int8_t *output, + const uint16_t output_wd, + const uint16_t output_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t filter_wd, + const uint16_t filter_ht, + const uint16_t pad_wd, + const uint16_t pad_ht, + const int32_t activation_min, + const int32_t activation_max, + const uint16_t channels); + + +/************************** Fully connected functions ***********************/ + +/** + * @brief fully connected + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_fully_connected_s8_ansi(const int8_t *input_data, + const int32_t input_offset, + const uint16_t row_len, + const int8_t *filter_data, + const int32_t filter_offset, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t out_shift, + const int32_t out_mult, + const int32_t activation_min, + const int32_t activation_max); + +/** + * @brief Get scratch buffer size needed by softmax function + * + * @param width + * @param height + * @return size in bytes + * + * @note buffer must be 4 byte aligned + */ +int32_t esp_nn_get_softmax_scratch_size_ansi(const int32_t width, const int32_t height); + +/* ANSI C function to be hooked up when optimised version needed */ +int32_t esp_nn_get_softmax_scratch_size_opt(const int32_t width, const int32_t height); + +/** + * @brief Set scratch buffer to be used by softmax function + * + * @param buffer this can be NULL if one needs to unset it + * must be aligned to 4 bytes + */ +void esp_nn_set_softmax_scratch_buf_ansi(void *buffer); + +/** + * @brief reference softmax function + * + * @note inputs type: int8_t, output: int8_t + */ +void esp_nn_softmax_s8_ansi(const int8_t *input_data, + const int32_t height, + const int32_t width, + const int32_t mult, + const int32_t shift, + const int32_t diff_min, + int8_t *output_data); + + +//////////////////////////// Generic optimisations ///////////////////////////// + +/************************** Convolution functions *****************************/ + +/** + * @brief 2d-convolution channelwise optimized version + * + * @note operation: result += (input + offset) * filter + * + * inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_conv_s8_opt(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data); + +/** + * @brief depthwise convolution per channel optimized version + * + * @note inputs type: int8_t, output: int8_t + * Version used in tflite is per channel. + * This version follows the same footsprints. + * Meaning, it has per out_channel shift and multiplier for + * requantization + * + * optimization notes: Though input_offset is int32 type, + * offset values are contained in 8 bits [-128, 127] + */ +void esp_nn_depthwise_conv_s8_opt(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data); + +int esp_nn_get_conv_scratch_size_opt(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const conv_params_t *conv_params); +void esp_nn_set_conv_scratch_buf_opt(const void *buf); + +int esp_nn_get_depthwise_conv_scratch_size_opt(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const dw_conv_params_t *conv_params); +void esp_nn_set_depthwise_conv_scratch_buf_opt(const void *buf); + +/* ANSI C function to be hooked up when optimised version needed */ +void esp_nn_set_softmax_scratch_buf_opt(void *buffer); + +/** + * @brief optimised version of softmax function + * + * @note the function uses extra buffer (4 * width bytes) + * hence, scratch buffers must be set before calling this. + */ +void esp_nn_softmax_s8_opt(const int8_t *input_data, + const int32_t height, + const int32_t width, + const int32_t mult, + const int32_t shift, + const int32_t diff_min, + int8_t *output_data); diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_defs.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_defs.h new file mode 100644 index 000000000..756d8e6fb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_defs.h @@ -0,0 +1,83 @@ +// Copyright 2022 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 + +#include + +/** + * @brief structure to club data dims + * this structure can be used for input, output and filter + */ +typedef struct data_dims { + int32_t width; + int32_t height; + int32_t channels; + + int32_t extra; // can be used as batch or any other param +} data_dims_t; + +/** + * @brief 2d data structure (width, height) + * + */ +typedef struct data_2d { + int32_t width; + int32_t height; +} data_2d_t; + +/** + * @brief min/max activation + */ +typedef struct act_params { + int32_t min; + int32_t max; +} act_params_t; + +/** + * @brief per channel quant data + * + * @note number of shift and mult elements are equal to output channels + */ +typedef struct quant_data { + int32_t *shift; + int32_t *mult; +} quant_data_t; + +/** + * @brief params specific to convolution 2d + * + */ +typedef struct conv_params { + int32_t in_offset; + int32_t out_offset; + data_2d_t stride; + data_2d_t padding; + data_2d_t dilation; + act_params_t activation; +} conv_params_t; + +/** + * @brief params specific to depthwise convolution 2d + * + */ +typedef struct dw_conv_params { + int32_t in_offset; + int32_t out_offset; + int32_t ch_mult; // channel multiplier. (in_ch * ch_mult = out_ch) + data_2d_t stride; + data_2d_t padding; + data_2d_t dilation; + act_params_t activation; +} dw_conv_params_t; diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_esp32s3.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_esp32s3.h new file mode 100644 index 000000000..9f7664549 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_esp32s3.h @@ -0,0 +1,233 @@ +// Copyright 2020-2021 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 Header definitions to include for esp_nn optimized functions for + * the ESP32-S3 platform + */ + +#pragma once +#ifdef CONFIG_IDF_TARGET_ESP32S3 +#include "esp_nn_defs.h" +#include "esp_nn_ansi_headers.h" + +/************************** Basic math functions *****************************/ + + +/** + * @brief elementwise addition + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + * + * shift values are expected to be <= 0 + */ +void esp_nn_add_elementwise_s8_esp32s3(const int8_t *input1_data, + const int8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + const int32_t input1_mult, + const int32_t input2_mult, + const int32_t input1_shift, + const int32_t input2_shift, + const int32_t left_shift, + int8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size); + +/** + * @brief elementwise multiplication + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + * + * output shift is expected to be <= 0 + */ +void esp_nn_mul_elementwise_s8_esp32s3(const int8_t *input1_data, + const int8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + int8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size); + + +/************************** Convolution functions *****************************/ + +/** + * @brief depthwise convolution per channel + * + * @note inputs type: int8_t, output: int8_t + * Version used in tflite is per channel. + * This version follows the same footsprints. + * Meaning, it has per out_channel shift and multiplier for + * requantization + * + * optimization notes: Though input_offset is int32 type, + * offset values are contained in 8 bits [-128, 127] + */ +void esp_nn_depthwise_conv_s8_esp32s3(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *output_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data); + +/** + * @brief 2d - convolution channelwise + * + * @note operation: result += (input + offset) * filter + * + * inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_conv_s8_esp32s3(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *output_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data); + +int esp_nn_get_conv_scratch_size_esp32s3(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const conv_params_t *conv_params); +void esp_nn_set_conv_scratch_buf_esp32s3(const void *buf); + +int esp_nn_get_depthwise_conv_scratch_size_esp32s3(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const dw_conv_params_t *conv_params); +void esp_nn_set_depthwise_conv_scratch_buf_esp32s3(const void *buf); + +/************************** Pooling functions *****************************/ + +/** + * @brief max_pool + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_max_pool_s8_esp32s3(const int8_t *input, + const uint16_t input_wd, + const uint16_t input_ht, + int8_t *output, + const uint16_t output_wd, + const uint16_t output_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t filter_wd, + const uint16_t filter_ht, + const uint16_t pad_wd, + const uint16_t pad_ht, + const int32_t activation_min, + const int32_t activation_max, + const uint16_t channels); + +/** + * @brief avg_pool + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + */ +void esp_nn_avg_pool_s8_esp32s3(const int8_t *input, + const uint16_t input_wd, + const uint16_t input_ht, + int8_t *output, + const uint16_t output_wd, + const uint16_t output_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t filter_wd, + const uint16_t filter_ht, + const uint16_t pad_wd, + const uint16_t pad_ht, + const int32_t activation_min, + const int32_t activation_max, + const uint16_t channels); + + +/************************** Fully connected functions *****************************/ + +/** + * @brief fully connected + * + * @note inputs type: int8_t, output: int8_t + * input offsets: although int32_t, they are contained in 8 bits [-128, 127] + * + * Current version works only on aligned input. + * row_len and channels should both be multiple of 8. + */ +void esp_nn_fully_connected_s8_esp32s3(const int8_t *input_data, + const int32_t input_offset, + const uint16_t row_len, + const int8_t *filter_data, + const int32_t filter_offset, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t out_shift, + const int32_t out_mult, + const int32_t activation_min, + const int32_t activation_max); + +/** + * @brief relu6 + * + * @note inout: int8_t + */ +void esp_nn_relu6_s8_esp32s3(int8_t *data, uint16_t size); + +/********************** function defines ***************************/ + +#define esp_nn_add_elementwise_s8 esp_nn_add_elementwise_s8_esp32s3 +#define esp_nn_mul_elementwise_s8 esp_nn_mul_elementwise_s8_esp32s3 + +#define esp_nn_depthwise_conv_s8 esp_nn_depthwise_conv_s8_esp32s3 + +#define esp_nn_get_conv_scratch_size esp_nn_get_conv_scratch_size_esp32s3 +#define esp_nn_set_conv_scratch_buf esp_nn_set_conv_scratch_buf_esp32s3 + +#define esp_nn_get_depthwise_conv_scratch_size esp_nn_get_depthwise_conv_scratch_size_esp32s3 +#define esp_nn_set_depthwise_conv_scratch_buf esp_nn_set_depthwise_conv_scratch_buf_esp32s3 + +#define esp_nn_conv_s8 esp_nn_conv_s8_esp32s3 + +#define esp_nn_relu6_s8 esp_nn_relu6_s8_esp32s3 + +#define esp_nn_avg_pool_s8 esp_nn_avg_pool_s8_esp32s3 +#define esp_nn_max_pool_s8 esp_nn_max_pool_s8_esp32s3 + +#define esp_nn_fully_connected_s8 esp_nn_fully_connected_s8_esp32s3 + +#define esp_nn_get_softmax_scratch_size esp_nn_get_softmax_scratch_size_opt +#define esp_nn_set_softmax_scratch_buf esp_nn_set_softmax_scratch_buf_opt +#define esp_nn_softmax_s8 esp_nn_softmax_s8_opt + +#endif // CONFIG_IDF_TARGET_ESP32S3 \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_generic_opt.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_generic_opt.h new file mode 100644 index 000000000..136cba5de --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/include/esp_nn_generic_opt.h @@ -0,0 +1,47 @@ +// Copyright 2020-2021 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 Header definitions to include for esp_nn generic optimisations + * For functions which not having optimisations, _ansi versions are picked. + */ + +#pragma once + +#include "esp_nn_defs.h" +#include "esp_nn_ansi_headers.h" + +#define esp_nn_add_elementwise_s8 esp_nn_add_elementwise_s8_ansi +#define esp_nn_mul_elementwise_s8 esp_nn_mul_elementwise_s8_ansi + +#define esp_nn_depthwise_conv_s8 esp_nn_depthwise_conv_s8_opt + +#define esp_nn_conv_s8 esp_nn_conv_s8_opt + +#define esp_nn_get_conv_scratch_size esp_nn_get_conv_scratch_size_opt +#define esp_nn_set_conv_scratch_buf esp_nn_set_conv_scratch_buf_opt + +#define esp_nn_get_depthwise_conv_scratch_size esp_nn_get_depthwise_conv_scratch_size_opt +#define esp_nn_set_depthwise_conv_scratch_buf esp_nn_set_depthwise_conv_scratch_buf_opt + +#define esp_nn_relu6_s8 esp_nn_relu6_s8_ansi + +#define esp_nn_avg_pool_s8 esp_nn_avg_pool_s8_ansi +#define esp_nn_max_pool_s8 esp_nn_max_pool_s8_ansi + +#define esp_nn_fully_connected_s8 esp_nn_fully_connected_s8_ansi + +#define esp_nn_get_softmax_scratch_size esp_nn_get_softmax_scratch_size_opt +#define esp_nn_set_softmax_scratch_buf esp_nn_set_softmax_scratch_buf_opt +#define esp_nn_softmax_s8 esp_nn_softmax_s8_opt diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/activation_functions/esp_nn_relu_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/activation_functions/esp_nn_relu_ansi.c new file mode 100644 index 000000000..3c83bf89b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/activation_functions/esp_nn_relu_ansi.c @@ -0,0 +1,30 @@ +// Copyright 2020-2021 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 + +#include "../common/common_functions.h" + +void esp_nn_relu6_s8_ansi(int8_t *data, uint16_t size) +{ + int32_t i; + + for (i = 0; i < size; i++) { + int32_t ip = data[i]; + + ip = max(ip, 0); + data[i] = min(ip, 6); + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/basic_math/esp_nn_add_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/basic_math/esp_nn_add_ansi.c new file mode 100644 index 000000000..d7fe34e62 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/basic_math/esp_nn_add_ansi.c @@ -0,0 +1,97 @@ +// Copyright 2020-2021 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 "../common/common_functions.h" + +void esp_nn_add_elementwise_u8_ansi(const uint8_t *input1_data, + const uint8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + const int32_t input1_mult, + const int32_t input2_mult, + const int32_t input1_shift, + const int32_t input2_shift, + const int32_t left_shift, + uint8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size) +{ + for (int i = 0; i < size; i++) { + int32_t tmp1 = input1_data[i] + input1_offset; + int32_t tmp2 = input2_data[i] + input2_offset; + + tmp1 <<= left_shift; + tmp2 <<= left_shift; + + tmp1 = esp_nn_sat_round_doubling_high_mul(tmp1, input1_mult); + tmp2 = esp_nn_sat_round_doubling_high_mul(tmp2, input2_mult); + + tmp1 = esp_nn_div_by_power_of_two(tmp1, -input1_shift); + tmp2 = esp_nn_div_by_power_of_two(tmp2, -input2_shift); + + int32_t out = tmp1 + tmp2; + out = esp_nn_sat_round_doubling_high_mul(out, out_mult); + out = esp_nn_div_by_power_of_two(out, -out_shift); + out = out + out_offset; + + out = max(activation_min, min(out, activation_max)); + output[i] = (uint8_t) out; + } +} + +void esp_nn_add_elementwise_s8_ansi(const int8_t *input1_data, + const int8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + const int32_t input1_mult, + const int32_t input2_mult, + const int32_t input1_shift, + const int32_t input2_shift, + const int32_t left_shift, + int8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size) +{ + for (int i = 0; i < size; i++) { + int32_t tmp1 = input1_data[i] + input1_offset; + int32_t tmp2 = input2_data[i] + input2_offset; + + tmp1 <<= left_shift; + tmp2 <<= left_shift; + + tmp1 = esp_nn_sat_round_doubling_high_mul(tmp1, input1_mult); + tmp2 = esp_nn_sat_round_doubling_high_mul(tmp2, input2_mult); + + tmp1 = esp_nn_div_by_power_of_two(tmp1, -input1_shift); + tmp2 = esp_nn_div_by_power_of_two(tmp2, -input2_shift); + + int32_t out = tmp1 + tmp2; + out = esp_nn_sat_round_doubling_high_mul(out, out_mult); + out = esp_nn_div_by_power_of_two(out, -out_shift); + out = out + out_offset; + + out = max(activation_min, min(out, activation_max)); + output[i] = (int8_t) out; + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/basic_math/esp_nn_mul_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/basic_math/esp_nn_mul_ansi.c new file mode 100644 index 000000000..c2eae5e59 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/basic_math/esp_nn_mul_ansi.c @@ -0,0 +1,42 @@ +// Copyright 2020-2021 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 "../common/common_functions.h" + +void esp_nn_mul_elementwise_s8_ansi(const int8_t *input1_data, + const int8_t *input2_data, + const int32_t input1_offset, + const int32_t input2_offset, + int8_t *output, + const int32_t out_offset, + const int32_t out_mult, + const int32_t out_shift, + const int32_t activation_min, + const int32_t activation_max, + const int32_t size) +{ + for (int i = 0; i < size; i++) { + int32_t tmp1 = input1_data[i] + input1_offset; + int32_t tmp2 = input2_data[i] + input2_offset; + + int32_t out = tmp1 * tmp2; + out = esp_nn_multiply_by_quantized_mult(out, out_mult, out_shift); + out = out + out_offset; + + out = max(activation_min, min(out, activation_max)); + output[i] = (int8_t) out; + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/common/common_functions.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/common/common_functions.h new file mode 100644 index 000000000..0a74eca40 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/common/common_functions.h @@ -0,0 +1,255 @@ +// Copyright 2020-2021 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 + +#include +#include +#include + +/** + * c99 standard still doesn't strictly inline functions + * We need to use attribute as well to do this. + */ +#define __NN_FORCE_INLINE__ __attribute((always_inline)) static inline + +/* min/max macros */ +#ifndef max +#define max(a, b) ({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; \ +}) + +#define min(a, b) ({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; \ +}) +#endif + +__NN_FORCE_INLINE__ int32_t esp_nn_clz32(uint32_t in) +{ +#if CONFIG_IDF_TARGET_ARCH_XTENSA + __asm__ volatile("nsau %0, %0" : "+r" (in)); + return in; +#elif defined(__GNUC__) + return __builtin_clz(in); +#else + int32_t count = 32; + uint32_t x = in, y = in >> 16; + if (y != 0) { + count -= 16; + x = y; + } + y = x >> 8; + if (y != 0) { + count -= 8; + x = y; + } + y = x >> 4; + if (y != 0) { + count -= 4; + x = y; + } + y = x >> 2; + if (y != 0) { + count -= 2; + x = y; + } + y = x >> 1; + if (y != 0) { + return count - 2; + } + return count - x; +#endif +} + +/** + * Signed saturate a 32 bit value to 8 bits keeping output in 32 bit variable. + */ +__NN_FORCE_INLINE__ int32_t esp_nn_saturate8(int32_t in) +{ +#if CONFIG_IDF_TARGET_ARCH_XTENSA + __asm__ volatile("clamps %0, %0, 7" : "+a"(in)); + return in; +#else + return max(INT8_MIN, min(in, INT8_MAX)); +#endif +} + +__NN_FORCE_INLINE__ int32_t esp_nn_pick_sat_high32_of64(int64_t val64) +{ + int32_t sign = (int32_t) (val64 >> 63); + int32_t to_add = sign & ((1ul << 31) - 1); + return (int32_t) ((int64_t) (val64 + to_add) >> 31); +} + +__NN_FORCE_INLINE__ int32_t esp_nn_sat_round_doubling_high_mul(int32_t in0, int32_t in1) +{ + int32_t result; + int64_t in0_64 = (int64_t) in0; + bool overflow = (in0 == in1) && (in0 == (int32_t) INT32_MIN); + + /* Nudge value */ + int64_t nudge_val = 1 << 30; + if ((in0 < 0) ^ (in1 < 0)) { + nudge_val = 1 - nudge_val; + } + + /* Multiply and add nudge */ + int64_t mult = in0_64 * in1 + nudge_val; + + /* Round and pickup 32 bits */ + result = esp_nn_pick_sat_high32_of64(mult); + + return overflow ? INT32_MAX : result; +} + +/** + * fast version + * this will fail for values closer to INT32_MAX and INT32_MIN by `1 << (exponent - 1)`. + * We can afford to do this because we are at the very last stage of filter. + * Also it is pretty rare condition as our output is going to be 8 bit. + */ +__NN_FORCE_INLINE__ int32_t esp_nn_div_by_power_of_two_fast(int32_t val, int32_t exponent) +{ + int32_t to_add = (1 << (exponent - 1)) - (val < 0); + return (int32_t) ((val + to_add) >> exponent); +} + +__NN_FORCE_INLINE__ int32_t esp_nn_div_by_power_of_two(int32_t val, int32_t exponent) +{ + int32_t result; + + const int32_t mask = (1 << exponent) - 1; + const int32_t remainder = val & mask; + + result = val >> exponent; + int32_t threshold = (mask >> 1) + (result < 0); + + if (remainder > threshold) { + result += 1; + } + return result; +} + +__NN_FORCE_INLINE__ int32_t esp_nn_multiply_by_quantized_mult(int32_t x, int32_t mult, int32_t shift) +{ + int32_t left_shift = shift > 0 ? shift : 0; + int32_t right_shift = shift > 0 ? 0 : -shift; + int32_t result = esp_nn_sat_round_doubling_high_mul(x * (1 << left_shift), mult); + return esp_nn_div_by_power_of_two(result, right_shift); +} + +__NN_FORCE_INLINE__ int32_t esp_nn_multiply_by_quantized_mult_fast(int32_t x, int32_t mult, int32_t shift) +{ + int32_t left_shift = max(shift, 0); + int32_t right_shift = left_shift - shift; + + int64_t nudge_val = 1 << 30; + int64_t in0_64 = (int64_t) (x << left_shift); + + /* Multiply and add nudge */ + int64_t mult_64 = in0_64 * mult + nudge_val; + int32_t result = (int32_t) (mult_64 >> 31); + if (right_shift) { + result = esp_nn_div_by_power_of_two_fast(result, right_shift); + } + return result; +} + +static void esp_nn_aligned_s8_pad_with_value(const int8_t *src, int8_t *dst, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const int32_t pad_val, + const uint16_t pad_wd, + const uint16_t pad_ht) +{ + /* memset with pad_val */ + memset(dst, pad_val, ((input_wd + 2 * pad_wd) * (input_ht + 2 * pad_ht)) * channels); + dst += (pad_wd + input_wd + pad_wd) * channels; + + for (int i = 0; i < input_ht; i++) { + dst += pad_wd * channels; + for (int j = 0; j < input_wd * channels; j++) { + *dst++ = *src++; + } + dst += pad_wd * channels; + } +} + +static void esp_nn_aligned_s8_pad_end_with_value(const int8_t *src, int8_t *dst, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const int32_t pad_val, + const uint16_t pad_wd, + const uint16_t pad_ht) +{ + for (int i = 0; i < input_ht; i++) { + for (int j = 0; j < input_wd * channels; j++) { + *dst++ = *src++; + } + if (pad_wd) { + memset(dst, pad_val, pad_wd * channels); + dst += pad_wd * channels; + } + } + /* pad end `pad_ht` lines at end */ + if (pad_ht) { + memset(dst, pad_val, (input_wd + pad_wd) * pad_ht * channels); + } +} + +/** + * @brief convert 8 bit input data to 16 bit + * + * @param src int8_t source data + * @param dst int16_t dst data + * @param size length of data + * @param offset offset to be added to src data. Range: [-128, 127] + */ +__NN_FORCE_INLINE__ void esp_nn_s8_to_s16_with_offset(const int8_t *src, int16_t *dst, + const int size, const int32_t offset) +{ + int i = 0; + for (; i < size; i += 2) { + dst[i + 0] = src[i + 0] + offset; + dst[i + 1] = src[i + 1] + offset; + } + if(i < size) { + dst[i] = src[i] + offset; + } +} + +/** + * @brief convert 8 bit input data to 16 bit + * + * @param src int8_t source data + * @param dst int16_t dst data + * @param size length of data + */ +__NN_FORCE_INLINE__ void esp_nn_s8_to_s16(const int8_t *src, int16_t *dst, const int size) +{ + int i = 0; + for (; i < size; i += 2) { + dst[i + 0] = src[i + 0]; + dst[i + 1] = src[i + 1]; + } + if(i < size) { + dst[i] = src[i]; + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_ansi.c new file mode 100644 index 000000000..c7a415ba6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_ansi.c @@ -0,0 +1,179 @@ +// Copyright 2020-2021 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/esp_nn_defs.h" + +#include "../common/common_functions.h" + +int esp_nn_get_conv_scratch_size_ansi(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const conv_params_t *conv_params) +{ + return 0; +} + +void esp_nn_set_conv_scratch_buf_ansi(const void *buf) +{ + +} + +/** + * Assumption 1: i/p channels == o/p channels + * Assumption 2: Pointers are valid + * Assumption 3: dialation width = 1 + */ +void esp_nn_conv_u8_ansi(const uint8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t in_channels, + const int32_t input_offset, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint8_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t filter_offset, + const int32_t *bias, + uint8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t out_shift, + const int32_t out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + for (int out_y = 0; out_y < out_ht; out_y++) { //height loop + const int16_t base_y = (out_y * stride_ht) - pad_ht; + for (int out_x = 0; out_x < out_wd; out_x++) { //width_loop + const int16_t base_x = (out_x * stride_wd) - pad_wd; + for (int out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) {//channel_loop + int32_t result = 0; + + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + for (int in_ch_idx = 0; in_ch_idx < in_channels; in_ch_idx++) { + int32_t input_index = (idx_y * input_wd + idx_x) * in_channels + in_ch_idx; + int32_t filter_index = ((out_ch_idx * filter_ht + filter_y_idx) + * filter_wd + filter_x_idx) * in_channels + + in_ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val = filter_data[filter_index] + filter_offset; + result += input_val * filter_val; + } + } + } + if (bias) { + result += bias[out_ch_idx]; + } + result = esp_nn_multiply_by_quantized_mult(result, out_mult, out_shift); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + + int out_index = (out_y * out_wd + out_x) * out_channels + out_ch_idx; + out_data[out_index] = (uint8_t) result; + } + } + } +} + +/** + * Assumption 1: i/p channels == o/p channels + * Assumption 2: Pointers are valid + * Assumption 3: dialation width = 1 + */ +void esp_nn_conv_s8_ansi(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t in_channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const uint16_t out_channels = output_dims->channels; + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + int32_t out_ch_idx, out_y, out_x, in_ch_idx, filter_y_idx, filter_x_idx; + + for (out_y = 0; out_y < out_ht; out_y++) { + for (out_x = 0; out_x < out_wd; out_x++) { + for (out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) { + int32_t conv_out = 0; + + const int32_t base_y = stride_ht * out_y - pad_ht; + const int32_t base_x = stride_wd * out_x - pad_wd; + + const int32_t filter_y_start = max(0, -base_y); + const int32_t filter_x_start = max(0, -base_x); + + const int32_t filter_y_end = min(filter_ht, input_ht - base_y); + const int32_t filter_x_end = min(filter_wd, input_wd - base_x); + + for (filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + for (filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t in_row = base_y + filter_y_idx; + const int32_t in_col = base_x + filter_x_idx; + int32_t input_base_offset = (in_row * input_wd + in_col) * in_channels; + int32_t filter_base_offset = out_ch_idx * in_channels * filter_ht * filter_wd + + (filter_y_idx * filter_wd + filter_x_idx) * in_channels; + for (in_ch_idx = 0; in_ch_idx < in_channels; in_ch_idx++) { + conv_out += + (input_data[input_base_offset + in_ch_idx] + input_offset) * + filter_data[filter_base_offset + in_ch_idx]; + } + } + } + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult(conv_out, out_mult[out_ch_idx], out_shift[out_ch_idx]); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_esp32s3.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_esp32s3.c new file mode 100644 index 000000000..8918bd861 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_esp32s3.c @@ -0,0 +1,463 @@ +// Copyright 2020-2021 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 "../../include/esp_nn_defs.h" + +#include "../common/common_functions.h" + +static int16_t *scratch_buffer = NULL; + +extern void esp_nn_conv_s8_mult8_1x1_esp32s3(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t in_channels, + const int32_t input_offset, + const int8_t *filter_aligned, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max, + void *buffer /* scratch buffer */); + +extern void esp_nn_conv_s16_mult4_1x1_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t in_channels, + const int16_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max, + void *buffer /* scratch buffer */); + +extern void esp_nn_conv_s16_mult8_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t in_channels, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int16_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_aligned_s8_to_s16_with_offset_esp32s3(const int8_t *src, int16_t *dst, + const int size, const int32_t offset); + +extern void esp_nn_s8_to_s16_esp32s3(const int8_t *src, int16_t *dst, const int size); + +static void esp_nn_conv_s8_unrolled(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t in_ch = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const uint16_t out_ch = output_dims->channels; + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + int32_t out_ch_idx, out_y, out_x, in_ch_idx, filter_y_idx, filter_x_idx; + + for (out_y = 0; out_y < out_ht; out_y++) { + for (out_x = 0; out_x < out_wd; out_x++) { + for (out_ch_idx = 0; out_ch_idx < out_ch; out_ch_idx++) { + int32_t conv_out = 0; + + const int32_t base_y = stride_ht * out_y - pad_ht; + const int32_t base_x = stride_wd * out_x - pad_wd; + + const int32_t filter_y_start = max(0, -base_y); + const int32_t filter_x_start = max(0, -base_x); + + const int32_t filter_y_end = min(filter_ht, input_ht - base_y); + const int32_t filter_x_end = min(filter_wd, input_wd - base_x); + + for (filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + for (filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t in_row = base_y + filter_y_idx; + const int32_t in_col = base_x + filter_x_idx; + int32_t input_base_offset = (in_row * input_wd + in_col) * in_ch; + int32_t filter_base_offset = out_ch_idx * in_ch * filter_ht * filter_wd + + (filter_y_idx * filter_wd + filter_x_idx) * in_ch; + for (in_ch_idx = 0; in_ch_idx < in_ch; in_ch_idx++) { + conv_out += + (input_data[input_base_offset + in_ch_idx] + input_offset) * + filter_data[filter_base_offset + in_ch_idx]; + } + } + } + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult_fast(conv_out, out_mult[out_ch_idx], out_shift[out_ch_idx]); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} + +static void esp_nn_conv_s8_pad_valid(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t in_channels, + const int32_t input_offset, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int8_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + int32_t out_ch_idx, out_y, out_x, in_ch_idx, filter_y_idx, filter_x_idx; + + for (out_y = 0; out_y < out_ht; out_y++) { + for (out_x = 0; out_x < out_wd; out_x++) { + for (out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) { + int32_t conv_out = 0; + + const int32_t base_y = stride_ht * out_y; + const int32_t base_x = stride_wd * out_x; + + for (filter_y_idx = 0; filter_y_idx < filter_ht; filter_y_idx++) { + for (filter_x_idx = 0; filter_x_idx < filter_wd; filter_x_idx++) { + const int32_t in_row = base_y + filter_y_idx; + const int32_t in_col = base_x + filter_x_idx; + int32_t input_base_offset = (in_row * input_wd + in_col) * in_channels; + int32_t filter_base_offset = out_ch_idx * in_channels * filter_ht * filter_wd + + (filter_y_idx * filter_wd + filter_x_idx) * in_channels; + const int8_t *input_data_ptr = input_data + input_base_offset; + const int8_t *filter_data_ptr = filter_data + filter_base_offset; + for (in_ch_idx = 0; in_ch_idx < in_channels; in_ch_idx++) { + conv_out += (*input_data_ptr++ + input_offset) * *filter_data_ptr++; + } + } + } + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult_fast(conv_out, out_mult[out_ch_idx], out_shift[out_ch_idx]); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} + +static void esp_nn_conv_s8_pad_valid_3x3(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t in_channels, + const int32_t input_offset, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int8_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + int32_t out_ch_idx, out_y, out_x, in_ch_idx, filter_y_idx, filter_x_idx; + + for (out_y = 0; out_y < out_ht; out_y++) { + for (out_x = 0; out_x < out_wd; out_x++) { + const int32_t base_y = stride_ht * out_y; + const int32_t base_x = stride_wd * out_x; + for (out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) { + int32_t conv_out = 0; + for (filter_y_idx = 0; filter_y_idx < 3; filter_y_idx++) { + for (filter_x_idx = 0; filter_x_idx < 3; filter_x_idx++) { + const int32_t in_row = base_y + filter_y_idx; + const int32_t in_col = base_x + filter_x_idx; + int32_t input_base_offset = (in_row * input_wd + in_col) * in_channels; + int32_t filter_base_offset = out_ch_idx * in_channels * 3 * 3 + + (filter_y_idx * 3 + filter_x_idx) * in_channels; + const int8_t *input_data_ptr = input_data + input_base_offset; + const int8_t *filter_data_ptr = filter_data + filter_base_offset; + for (in_ch_idx = 0; in_ch_idx < in_channels; in_ch_idx++) { + conv_out += (*input_data_ptr++ + input_offset) * *filter_data_ptr++; + } + } + } + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult_fast(conv_out, out_mult[out_ch_idx], out_shift[out_ch_idx]); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} + +static void esp_nn_conv_s8_pad_valid_ch3_3x3(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const int32_t input_offset, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int8_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + int32_t out_ch_idx, out_y, out_x, filter_y_idx; + + /* use scratch_buffer to pre-compute offset factor */ + int16_t *filter_sum = (int16_t *) scratch_buffer; + const int8_t *filter_ptr = filter_data; + for (out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) { + int16_t sum_val = 0; + for (int i = 0; i < 9; i++) { + sum_val += *filter_ptr++; + sum_val += *filter_ptr++; + sum_val += *filter_ptr++; + } + *filter_sum++ = sum_val; + } + + for (out_y = 0; out_y < out_ht; out_y++) { + for (out_x = 0; out_x < out_wd; out_x++) { + const int8_t *filter_data_ptr = filter_data; + const int32_t base_y = stride_ht * out_y; + const int32_t base_x = stride_wd * out_x; + const int8_t *input_base_ptr = input_data + (base_y * input_wd + base_x) * 3; + int16_t *filter_sum = (int16_t *) scratch_buffer; + for (out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) { + int32_t conv_out = 0; + + for (filter_y_idx = 0; filter_y_idx < 3; filter_y_idx++) { + const int8_t *input_data_ptr = input_base_ptr + (filter_y_idx * input_wd) * 3; + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + conv_out += (*input_data_ptr++) * (*filter_data_ptr++); + } + + conv_out += *filter_sum++ * input_offset; + + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult_fast(conv_out, out_mult[out_ch_idx], out_shift[out_ch_idx]); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} + +int esp_nn_get_conv_scratch_size_esp32s3(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const conv_params_t *conv_params) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t in_ch = input_dims->channels; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_ch = output_dims->channels; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + + int filter_size = filter_wd * filter_ht * in_ch * out_ch; + int input_size = input_wd * input_ht * in_ch; + + int transpose_buf_size = 2 * (8 * in_ch); /* to store intermediate data */ + if (input_wd * input_ht < 8) { + transpose_buf_size = 0; // not using this for leftover + } + int align_buf_size = 32; /* extra buffer for alignment */ + if (in_ch % 8 == 0 && filter_wd == 1 && filter_ht == 1 && + pad_wd == 0 && pad_ht == 0 && stride_wd == 1 && stride_ht == 1) { + return filter_size + transpose_buf_size + align_buf_size; + } + return 2 * (filter_size + input_size) + transpose_buf_size + align_buf_size; +} + +void esp_nn_set_conv_scratch_buf_esp32s3(void *buf) +{ + scratch_buffer = (int16_t *) buf; +} + +void esp_nn_conv_s8_esp32s3(const data_dims_t *input_dims, + const int8_t *input, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const uint16_t out_channels = output_dims->channels; + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + int filter_size = filter_wd * filter_ht * channels * out_channels; + int input_size = input_wd * input_ht * channels; + int align_len = 16 - (filter_size & 15); + int16_t *filter_data16 = scratch_buffer; + int16_t *input_data16 = scratch_buffer + filter_size + align_len; + + if (scratch_buffer == NULL) { + printf("esp_nn_conv error! scratch_buffer not set!\n"); + return; + } + + if (channels % 8 == 0 && filter_wd == 1 && filter_ht == 1 && + pad_wd == 0 && pad_ht == 0 && stride_wd == 1 && stride_ht == 1) { + int8_t *filter_aligned = (int8_t *) scratch_buffer; + int scratch_offset = (int) (filter_aligned + filter_size); + void *scratch_buf = (void *) (scratch_offset + 16 - (scratch_offset & 15)); + memcpy(filter_aligned, filter_data, filter_size); // copy to aligned address + esp_nn_conv_s8_mult8_1x1_esp32s3( + input, input_wd, input_ht, channels, input_offset, filter_aligned, + bias, out_data, out_wd, out_ht, out_channels, out_offset, + out_shift, out_mult, activation_min, activation_max, scratch_buf); + } else if (channels % 4 == 0 && filter_wd == 1 && filter_ht == 1 && + (input_wd * input_ht) % 4 == 0 && /* TODO: remove this check */ + pad_wd == 0 && pad_ht == 0 && stride_wd == 1 && stride_ht == 1) { + int scratch_offset = (int) (input_data16 + input_size); + void *scratch_buf = (void *) (scratch_offset + 16 - (scratch_offset & 15)); + esp_nn_s8_to_s16_esp32s3(filter_data, filter_data16, filter_size); + esp_nn_aligned_s8_to_s16_with_offset_esp32s3(input, input_data16, input_size, input_offset); + esp_nn_conv_s16_mult4_1x1_esp32s3( + input_data16, input_wd, input_ht, channels, filter_data16, + bias, out_data, out_wd, out_ht, out_channels, out_offset, + out_shift, out_mult, activation_min, activation_max, scratch_buf); + } else if (channels % 8 == 0) { + esp_nn_s8_to_s16_esp32s3(filter_data, filter_data16, filter_size); + esp_nn_aligned_s8_to_s16_with_offset_esp32s3(input, input_data16, input_size, input_offset); + esp_nn_conv_s16_mult8_esp32s3( + input_data16, input_wd, input_ht, channels, pad_wd, pad_ht, + stride_wd, stride_ht, filter_data16, filter_wd, filter_ht, bias, + out_data, out_wd, out_ht, out_channels, out_offset, out_shift, + out_mult, activation_min, activation_max); + } else if (pad_wd == 0 && pad_ht == 0) { + if (filter_wd == 3 && filter_ht == 3 && channels == 3) { + esp_nn_conv_s8_pad_valid_ch3_3x3(input, input_wd, input_ht, input_offset, + stride_wd, stride_ht, filter_data, bias, + out_data, out_wd, out_ht, out_channels, out_offset, + out_shift, out_mult, activation_min, activation_max); + } else { + esp_nn_conv_s8_pad_valid(input, input_wd, input_ht, channels, input_offset, + stride_wd, stride_ht, filter_data, filter_wd, filter_ht, bias, + out_data, out_wd, out_ht, out_channels, out_offset, out_shift, + out_mult, activation_min, activation_max); + } + } else { + /* Basic unrolled version */ + esp_nn_conv_s8_unrolled(input_dims, input, filter_dims, filter_data, + bias, output_dims, out_data, conv_params, quant_data); + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_opt.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_opt.c new file mode 100644 index 000000000..80b1e13a5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_conv_opt.c @@ -0,0 +1,179 @@ +// Copyright 2020-2021 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/esp_nn_defs.h" + +#include "../common/common_functions.h" + +int esp_nn_get_conv_scratch_size_opt(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const conv_params_t *conv_params) +{ + return 0; +} + +void esp_nn_set_conv_scratch_buf_opt(const void *buf) +{ + +} + +__attribute__ ((noinline)) +static void esp_nn_conv_s8_1x1(const data_dims_t *input_dims, + const int8_t *input_data, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t in_channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const uint16_t out_channels = output_dims->channels; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + for (int32_t in_row = 0; in_row < out_ht * stride_ht; in_row += stride_ht) { + for (int32_t in_col = 0; in_col < out_wd * stride_wd; in_col += stride_wd) { + const int32_t *out_mult = quant_data->mult; + const int32_t *out_shift = quant_data->shift; + const int8_t *filter_ptr = filter_data; + const int8_t *input_base_ptr = input_data + (in_row * input_wd + in_col) * in_channels; + int32_t out_ch_idx = 0; + for (; out_ch_idx < out_channels; out_ch_idx++) { + int32_t conv_out = 0; + + const int8_t *input_ptr = input_base_ptr; + + int32_t in_ch_idx = 0; + for (; in_ch_idx < in_channels - 3; in_ch_idx += 4) { + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + } + for (; in_ch_idx < in_channels; in_ch_idx ++) { + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + } + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult_fast(conv_out, *out_mult++, *out_shift++); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} + +/** + * Assumption 1: i/p channels == o/p channels + * Assumption 2: Pointers are valid + * Assumption 3: dialation width = 1 + */ +void esp_nn_conv_s8_opt(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + + if (filter_wd == 1 && filter_ht == 1) { + esp_nn_conv_s8_1x1(input_dims, input_data, filter_data, bias, + output_dims, out_data, conv_params, quant_data); + return; + } + + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t in_channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const uint16_t out_channels = output_dims->channels; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + int32_t out_ch_idx, out_y, out_x, filter_y_idx, filter_x_idx; + + for (out_y = 0; out_y < out_ht; out_y++) { + for (out_x = 0; out_x < out_wd; out_x++) { + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + for (out_ch_idx = 0; out_ch_idx < out_channels; out_ch_idx++) { + int32_t conv_out = 0; + + const int32_t base_y = stride_ht * out_y - pad_ht; + const int32_t base_x = stride_wd * out_x - pad_wd; + + const int32_t filter_y_start = max(0, -base_y); + const int32_t filter_x_start = max(0, -base_x); + + const int32_t filter_y_end = min(filter_ht, input_ht - base_y); + const int32_t filter_x_end = min(filter_wd, input_wd - base_x); + + for (filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + for (filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t in_row = base_y + filter_y_idx; + const int32_t in_col = base_x + filter_x_idx; + + const int8_t *input_ptr = input_data + + (in_row * input_wd + in_col) * in_channels; + const int8_t *filter_ptr = filter_data + + out_ch_idx * in_channels * filter_ht * filter_wd + + (filter_y_idx * filter_wd + filter_x_idx) * in_channels; + int32_t in_ch_idx = 0; + for (; in_ch_idx < in_channels - 3; in_ch_idx += 4) { + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + } + for (; in_ch_idx < in_channels; in_ch_idx ++) { + conv_out += (*input_ptr++ + input_offset) * *filter_ptr++; + } + } + } + if (bias) { + conv_out += bias[out_ch_idx]; + } + conv_out = esp_nn_multiply_by_quantized_mult_fast(conv_out, *out_mult++, *out_shift++); + conv_out += out_offset; + conv_out = max(conv_out, activation_min); + conv_out = min(conv_out, activation_max); + *out_data++ = (int8_t) conv_out; + } + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_ansi.c new file mode 100644 index 000000000..7cd3cde1f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_ansi.c @@ -0,0 +1,100 @@ +// Copyright 2020-2021 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/esp_nn_defs.h" +#include "../common/common_functions.h" + +int esp_nn_get_depthwise_conv_scratch_size_ansi(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const dw_conv_params_t *conv_params) +{ + return 0; +} + +void esp_nn_set_depthwise_conv_scratch_buf_ansi(const void *buf) +{ + +} + +void esp_nn_depthwise_conv_s8_ansi(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + const uint16_t ch_mult = conv_params->ch_mult; + + int out_idx = 0; + for (int out_y = 0; out_y < out_ht; out_y++) { //height loop + const int16_t base_y = (out_y * stride_ht) - pad_ht; + for (int out_x = 0; out_x < out_wd; out_x++) { //width_loop + const int16_t base_x = (out_x * stride_wd) - pad_wd; + for (int ch_idx = 0; ch_idx < channels; ch_idx++) {//channel_loop + for (int ch_mult_idx = 0; ch_mult_idx < ch_mult; ch_mult_idx++) { + int32_t result = 0; + const int out_ch_idx = ch_mult_idx + ch_idx * ch_mult; + + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels * ch_mult) + out_ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val = filter_data[filter_index]; + result += input_val * filter_val; + } + } + if (bias) { + result += bias[out_ch_idx]; + } + result = esp_nn_multiply_by_quantized_mult(result, out_mult[out_ch_idx], out_shift[out_ch_idx]); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + + out_data[out_idx++] = result; + } + } + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_opt.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_opt.c new file mode 100644 index 000000000..d7063f72c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_opt.c @@ -0,0 +1,291 @@ +// Copyright 2020-2021 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/esp_nn_defs.h" +#include "../common/common_functions.h" + +int esp_nn_get_depthwise_conv_scratch_size_opt(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const dw_conv_params_t *conv_params) +{ + return 0; +} + +void esp_nn_set_depthwise_conv_scratch_buf_opt(const void *buf) +{ + +} + +/* common channel multiplier == 1 case */ +__attribute__ ((noinline)) +static void esp_nn_depthwise_conv_s8_ch_mult_1(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + int out_idx = 0; + for (int out_y = 0; out_y < out_ht; out_y++) { //height loop + const int16_t base_y = (out_y * stride_ht) - pad_ht; + for (int out_x = 0; out_x < out_wd; out_x++) { //width_loop + const int16_t base_x = (out_x * stride_wd) - pad_wd; + + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + int ch_idx = 0; + for (; ch_idx < channels - 3; ch_idx += 4) {//channel_loop + int32_t result0 = 0; + int32_t result1 = 0; + int32_t result2 = 0; + int32_t result3 = 0; + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels) + ch_idx; + int32_t input_val0 = input_data[input_index + 0] + input_offset; + int32_t input_val1 = input_data[input_index + 1] + input_offset; + int32_t input_val2 = input_data[input_index + 2] + input_offset; + int32_t input_val3 = input_data[input_index + 3] + input_offset; + int32_t filter_val0 = filter_data[filter_index + 0]; + int32_t filter_val1 = filter_data[filter_index + 1]; + int32_t filter_val2 = filter_data[filter_index + 2]; + int32_t filter_val3 = filter_data[filter_index + 3]; + result0 += input_val0 * filter_val0; + result1 += input_val1 * filter_val1; + result2 += input_val2 * filter_val2; + result3 += input_val3 * filter_val3; + } + } + if (bias) { + result0 += bias[ch_idx + 0]; + result1 += bias[ch_idx + 1]; + result2 += bias[ch_idx + 2]; + result3 += bias[ch_idx + 3]; + } + result0 = esp_nn_multiply_by_quantized_mult_fast(result0, *out_mult++, *out_shift++); + result1 = esp_nn_multiply_by_quantized_mult_fast(result1, *out_mult++, *out_shift++); + result2 = esp_nn_multiply_by_quantized_mult_fast(result2, *out_mult++, *out_shift++); + result3 = esp_nn_multiply_by_quantized_mult_fast(result3, *out_mult++, *out_shift++); + + result0 += out_offset; + result1 += out_offset; + result2 += out_offset; + result3 += out_offset; + + result0 = max(result0, activation_min); + result1 = max(result1, activation_min); + result2 = max(result2, activation_min); + result3 = max(result3, activation_min); + + result0 = min(result0, activation_max); + result1 = min(result1, activation_max); + result2 = min(result2, activation_max); + result3 = min(result3, activation_max); + + out_data[out_idx++] = result0; + out_data[out_idx++] = result1; + out_data[out_idx++] = result2; + out_data[out_idx++] = result3; + } + for (; ch_idx < channels; ch_idx++) {//channel_loop + int32_t result = 0; + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels) + ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val = filter_data[filter_index]; + result += input_val * filter_val; + } + } + if (bias) { + result += bias[ch_idx]; + } + result = esp_nn_multiply_by_quantized_mult_fast(result, *out_mult++, *out_shift++); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + + out_data[out_idx++] = result; + } + } + } +} + +void esp_nn_depthwise_conv_s8_opt(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t ch_mult = conv_params->ch_mult; + if (ch_mult == 1) { + esp_nn_depthwise_conv_s8_ch_mult_1(input_dims, input_data, filter_dims, filter_data, + bias, output_dims, out_data, conv_params, quant_data); + return; + } + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + + int out_idx = 0; + for (int out_y = 0; out_y < out_ht; out_y++) { //height loop + const int16_t base_y = (out_y * stride_ht) - pad_ht; + for (int out_x = 0; out_x < out_wd; out_x++) { //width_loop + const int16_t base_x = (out_x * stride_wd) - pad_wd; + + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + for (int ch_idx = 0; ch_idx < channels; ch_idx++) {//channel_loop + int ch_mult_idx = 0; + for (; ch_mult_idx < ch_mult - 3; ch_mult_idx += 4) { + int32_t result0 = 0; + int32_t result1 = 0; + int32_t result2 = 0; + int32_t result3 = 0; + const int out_ch_idx = ch_idx * ch_mult + ch_mult_idx; + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels * ch_mult) + out_ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val0 = filter_data[filter_index + 0]; + int32_t filter_val1 = filter_data[filter_index + 1]; + int32_t filter_val2 = filter_data[filter_index + 2]; + int32_t filter_val3 = filter_data[filter_index + 3]; + result0 += input_val * filter_val0; + result1 += input_val * filter_val1; + result2 += input_val * filter_val2; + result3 += input_val * filter_val3; + } + } + if (bias) { + result0 += bias[out_ch_idx + 0]; + result1 += bias[out_ch_idx + 1]; + result2 += bias[out_ch_idx + 2]; + result3 += bias[out_ch_idx + 3]; + } + result0 = esp_nn_multiply_by_quantized_mult_fast(result0, *out_mult++, *out_shift++); + result1 = esp_nn_multiply_by_quantized_mult_fast(result1, *out_mult++, *out_shift++); + result2 = esp_nn_multiply_by_quantized_mult_fast(result2, *out_mult++, *out_shift++); + result3 = esp_nn_multiply_by_quantized_mult_fast(result3, *out_mult++, *out_shift++); + + result0 += out_offset; + result1 += out_offset; + result2 += out_offset; + result3 += out_offset; + + result0 = max(result0, activation_min); + result1 = max(result1, activation_min); + result2 = max(result2, activation_min); + result3 = max(result3, activation_min); + result0 = min(result0, activation_max); + result1 = min(result1, activation_max); + result2 = min(result2, activation_max); + result3 = min(result3, activation_max); + + out_data[out_idx++] = result0; + out_data[out_idx++] = result1; + out_data[out_idx++] = result2; + out_data[out_idx++] = result3; + } + for (; ch_mult_idx < ch_mult; ch_mult_idx++) { + int32_t result = 0; + const int out_ch_idx = ch_idx * ch_mult + ch_mult_idx; + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels * ch_mult) + out_ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val = filter_data[filter_index]; + result += input_val * filter_val; + } + } + if (bias) { + result += bias[out_ch_idx]; + } + result = esp_nn_multiply_by_quantized_mult_fast(result, *out_mult++, *out_shift++); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + + out_data[out_idx++] = result; + } + } + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_s8_esp32s3.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_s8_esp32s3.c new file mode 100644 index 000000000..8840977f6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/convolution/esp_nn_depthwise_conv_s8_esp32s3.c @@ -0,0 +1,543 @@ +// Copyright 2020-2021 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 "../../include/esp_nn_defs.h" + +#include "../common/common_functions.h" + +static int16_t *scratch_buffer = NULL; + +extern void esp_nn_depthwise_conv_s16_mult8_3x3_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t ch_mult, + const int16_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_depthwise_conv_s8_mult1_3x3_padded_esp32s3(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const int32_t input_offset, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int8_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_depthwise_conv_s16_mult1_3x3_no_pad_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int16_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_depthwise_conv_s16_mult8_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t ch_mult, + const int16_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_depthwise_conv_s16_mult4_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t ch_mult, + const int16_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_depthwise_conv_s16_mult1_3x3_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int16_t *filter_data, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_depthwise_conv_s16_mult1_esp32s3(const int16_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int16_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max); + +extern void esp_nn_s8_to_s16_esp32s3(const int8_t *src, int16_t *dst, const int size); + +extern void esp_nn_aligned_s8_to_s16_with_offset_esp32s3(const int8_t *src, int16_t *dst, + const int size, const int32_t offset); + +static void esp_nn_depthwise_conv_s8_unrolled(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const int32_t input_offset, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t ch_mult, + const int8_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + int out_idx = 0; + for (int out_y = 0; out_y < out_ht; out_y++) { //height loop + const int16_t base_y = (out_y * stride_ht) - pad_ht; + for (int out_x = 0; out_x < out_wd; out_x++) { //width_loop + const int16_t base_x = (out_x * stride_wd) - pad_wd; + for (int ch_idx = 0; ch_idx < channels; ch_idx++) {//channel_loop + int ch_mult_idx = 0; + for (; ch_mult_idx < ch_mult - 3; ch_mult_idx += 4) { + int32_t result0 = 0, result1 = 0, result2 = 0, result3 = 0; + const int out_ch_idx = ch_mult_idx + ch_idx * ch_mult; + + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels * ch_mult) + out_ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val0 = filter_data[filter_index + 0]; + int32_t filter_val1 = filter_data[filter_index + 1]; + int32_t filter_val2 = filter_data[filter_index + 2]; + int32_t filter_val3 = filter_data[filter_index + 3]; + result0 += input_val * filter_val0; + result1 += input_val * filter_val1; + result2 += input_val * filter_val2; + result3 += input_val * filter_val3; + } + } + if (bias) { + result0 += bias[out_ch_idx + 0]; + result1 += bias[out_ch_idx + 1]; + result2 += bias[out_ch_idx + 2]; + result3 += bias[out_ch_idx + 3]; + } + result0 = esp_nn_multiply_by_quantized_mult(result0, + out_mult[out_ch_idx + 0], out_shift[out_ch_idx + 0]); + result1 = esp_nn_multiply_by_quantized_mult(result1, + out_mult[out_ch_idx + 1], out_shift[out_ch_idx + 1]); + result2 = esp_nn_multiply_by_quantized_mult(result2, + out_mult[out_ch_idx + 2], out_shift[out_ch_idx + 2]); + result3 = esp_nn_multiply_by_quantized_mult(result3, + out_mult[out_ch_idx + 3], out_shift[out_ch_idx + 3]); + + result0 += out_offset; + result1 += out_offset; + result2 += out_offset; + result3 += out_offset; + + result0 = max(result0, activation_min); + result1 = max(result1, activation_min); + result2 = max(result2, activation_min); + result3 = max(result3, activation_min); + + result0 = min(result0, activation_max); + result1 = min(result1, activation_max); + result2 = min(result2, activation_max); + result3 = min(result3, activation_max); + + out_data[out_idx++] = result0; + out_data[out_idx++] = result1; + out_data[out_idx++] = result2; + out_data[out_idx++] = result3; + } + + /* left-over */ + for (; ch_mult_idx < ch_mult; ch_mult_idx++) { + int32_t result = 0; + const int out_ch_idx = ch_mult_idx + ch_idx * ch_mult; + + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * (channels * ch_mult) + out_ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val = filter_data[filter_index]; + result += input_val * filter_val; + } + } + if (bias) { + result += bias[out_ch_idx]; + } + result = esp_nn_multiply_by_quantized_mult(result, out_mult[out_ch_idx], out_shift[out_ch_idx]); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + + out_data[out_idx++] = result; + } + } + } + } +} + +void esp_nn_depthwise_conv_s8_ch_mult1(const int8_t *input_data, + const uint16_t input_wd, + const uint16_t input_ht, + const uint16_t channels, + const int32_t input_offset, + const uint16_t pad_wd, + const uint16_t pad_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const int8_t *filter_data, + const uint16_t filter_wd, + const uint16_t filter_ht, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_wd, + const uint16_t out_ht, + const int32_t out_offset, + const int32_t *out_shift, + const int32_t *out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + int out_idx = 0; + for (int out_y = 0; out_y < out_ht; out_y++) { //height loop + const int16_t base_y = (out_y * stride_ht) - pad_ht; + for (int out_x = 0; out_x < out_wd; out_x++) { //width_loop + const int16_t base_x = (out_x * stride_wd) - pad_wd; + for (int ch_idx = 0; ch_idx < channels; ch_idx++) {//channel_loop + int32_t result = 0; + /* Select filter so as the point doesn't lie outside block */ + int filter_y_start = max(0, -base_y); + int filter_x_start = max(0, -base_x); + int filter_y_end = min(filter_ht, input_ht - base_y); + int filter_x_end = min(filter_wd, input_wd - base_x); + + for (int filter_y_idx = filter_y_start; filter_y_idx < filter_y_end; filter_y_idx++) { + const int32_t idx_y = base_y + filter_y_idx; + for (int filter_x_idx = filter_x_start; filter_x_idx < filter_x_end; filter_x_idx++) { + const int32_t idx_x = base_x + filter_x_idx; + int32_t input_index = (idx_y * input_wd + idx_x) * channels + ch_idx; + int32_t filter_index = (filter_y_idx * filter_wd + filter_x_idx) * channels + ch_idx; + int32_t input_val = input_data[input_index] + input_offset; + int32_t filter_val = filter_data[filter_index]; + result += input_val * filter_val; + } + } + if (bias) { + result += bias[ch_idx]; + } + result = esp_nn_multiply_by_quantized_mult(result, out_mult[ch_idx], out_shift[ch_idx]); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + + out_data[out_idx++] = result; + } + } + } +} + +int esp_nn_get_depthwise_conv_scratch_size_esp32s3(const data_dims_t *input_dims, + const data_dims_t *filter_dims, + const data_dims_t *output_dims, + const dw_conv_params_t *conv_params) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t channels = input_dims->channels; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t ch_mult = conv_params->ch_mult; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + + int filter_size = filter_wd * filter_ht * channels * ch_mult; + int pad_width = 0, pad_height = 0; + + if ((ch_mult == 1) && (channels % 8 == 0) && (filter_wd == 3) && (filter_ht == 3)) { + if (channels % 16 == 0) { + if (pad_wd || pad_ht) { + pad_width = pad_wd * 2; + pad_height = pad_ht * 2; + } else { + // check if we need to pad additionally + pad_width = (out_wd * stride_wd + filter_wd - 1) - input_wd; + pad_height = (out_ht * stride_ht + filter_ht - 1) - input_ht; + // printf("in(%d %d %d), out(%d %d), filter (%d %d) stride (%d %d), pad (%d %d)", + // input_wd, input_ht, channels, out_wd, out_ht, filter_wd, filter_ht, + // stride_wd, stride_ht, pad_wd, pad_ht); + } + if (pad_width || pad_height) { + int input_size = (input_wd + pad_width) * (input_ht + pad_height) * channels; + // printf("ask1 %d\n", filter_size + input_size + 16); + return filter_size + input_size + 16; // 16 for alignment + } else { + // printf("ask2 %d\n", filter_size + 16); + return filter_size + 16; // 16 for alignment + } + } else { + int input_size = input_wd * input_ht * channels; + // printf("ask3 %d\n", 2 * (filter_size + input_size) + 16); + return 2 * (filter_size + input_size) + 16; // 16 for alignment + } + } else if (ch_mult % 4 == 0) { + int input_size = input_wd * input_ht * channels; + // printf("ask4 %d\n", 2 * (filter_size + input_size) + 16); + return 2 * (filter_size + input_size) + 16; // 16 for alignment + } + return 32; // just few bytes +} + +void esp_nn_set_depthwise_conv_scratch_buf_esp32s3(void *buf) +{ + scratch_buffer = (int16_t *) buf; +} + +/** + * Assumption 1: i/p channels == o/p channels + * Assumption 2: Pointers are valid + * Assumption 3: dialation width = 1 + */ + + + +void esp_nn_depthwise_conv_s8_esp32s3(const data_dims_t *input_dims, + const int8_t *input_data, + const data_dims_t *filter_dims, + const int8_t *filter_data, + const int32_t *bias, + const data_dims_t *output_dims, + int8_t *out_data, + const dw_conv_params_t *conv_params, + const quant_data_t *quant_data) +{ + const uint16_t input_wd = input_dims->width; + const uint16_t input_ht = input_dims->height; + const uint16_t channels = input_dims->channels; + const int32_t input_offset = conv_params->in_offset; + const int32_t out_offset = conv_params->out_offset; + const uint16_t pad_wd = conv_params->padding.width; + const uint16_t pad_ht = conv_params->padding.height; + const uint16_t stride_wd = conv_params->stride.width; + const uint16_t stride_ht = conv_params->stride.height; + const uint16_t filter_wd = filter_dims->width; + const uint16_t filter_ht = filter_dims->height; + const uint16_t out_wd = output_dims->width; + const uint16_t out_ht = output_dims->height; + const int32_t *out_shift = quant_data->shift; + const int32_t *out_mult = quant_data->mult; + const int32_t activation_min = conv_params->activation.min; + const int32_t activation_max = conv_params->activation.max; + const uint16_t ch_mult = conv_params->ch_mult; + + int filter_size = filter_wd * filter_ht * channels * ch_mult; + int align_len = 16 - (filter_size & 15); + int input_size = input_wd * input_ht * channels; + int16_t *filter_data16 = scratch_buffer; + int16_t *input_data16 = scratch_buffer + filter_size + align_len; + if (scratch_buffer == NULL) { + printf("esp_nn_depthwise_conv error! scratch_buffer not set!\n"); + return; + } + + if ((ch_mult == 1) && (channels % 8 == 0)) { + if ((filter_wd == 3) && (filter_ht == 3)) { + if ((channels % 16 == 0) && (pad_wd == 1) && (pad_ht == 1)) { + /* process in 8 bits */ + int8_t *filter_aligned = (int8_t *) scratch_buffer; + int8_t *input_padded = (int8_t *) scratch_buffer + filter_size + align_len; + memcpy(filter_aligned, filter_data, filter_size); + esp_nn_aligned_s8_pad_with_value(input_data, input_padded, input_wd, input_ht, channels, + -input_offset, pad_wd, pad_ht); + esp_nn_depthwise_conv_s8_mult1_3x3_padded_esp32s3(input_padded, input_wd + 2 * pad_wd, + input_ht + 2 * pad_ht, channels, input_offset, + stride_wd, stride_ht, filter_aligned, bias, + out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } else if ((channels % 16 == 0) && (pad_wd == 0) && (pad_ht == 0)) { + /* process in 8 bits */ + int8_t *filter_aligned = (int8_t *) scratch_buffer; + int8_t *input_padded = (int8_t *) scratch_buffer + filter_size + align_len; + + // check if we need to pad additionally + int pad_right = (out_wd * stride_wd + filter_wd - 1) - input_wd; + int pad_bottom = (out_ht * stride_ht + filter_ht - 1) - input_ht; + if (pad_right || pad_bottom) { // pad right and bottom + esp_nn_aligned_s8_pad_end_with_value(input_data, input_padded, input_wd, input_ht, + channels, -input_offset, pad_right, pad_bottom); + } else { + input_padded = (int8_t *) input_data; + } + memcpy(filter_aligned, filter_data, filter_size); + esp_nn_depthwise_conv_s8_mult1_3x3_padded_esp32s3(input_padded, input_wd + pad_right, + input_ht + pad_bottom, channels, input_offset, + stride_wd, stride_ht, filter_aligned, bias, + out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } else { /* (channels % 8) == 0 */ + esp_nn_s8_to_s16_esp32s3(filter_data, filter_data16, filter_size); + esp_nn_aligned_s8_to_s16_with_offset_esp32s3(input_data, input_data16, input_size, input_offset); + esp_nn_depthwise_conv_s16_mult1_3x3_esp32s3(input_data16, input_wd, input_ht, channels, + pad_wd, pad_ht, stride_wd, stride_ht, filter_data16, + bias, out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } + } else { // all other ch_mult == 1, `channels % 8 == 0` + esp_nn_depthwise_conv_s8_ch_mult1(input_data, input_wd, input_ht, channels, input_offset, + pad_wd, pad_ht, stride_wd, stride_ht, + filter_data, filter_wd, filter_ht, + bias, out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } + } else if (ch_mult % 8 == 0) { + esp_nn_s8_to_s16_esp32s3(filter_data, filter_data16, filter_size); + esp_nn_aligned_s8_to_s16_with_offset_esp32s3(input_data, input_data16, input_size, input_offset); + if (filter_wd == 3 && filter_ht == 3) { + esp_nn_depthwise_conv_s16_mult8_3x3_esp32s3(input_data16, input_wd, input_ht, channels, + pad_wd, pad_ht, stride_wd, stride_ht, ch_mult, + filter_data16, bias, + out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } else { + esp_nn_depthwise_conv_s16_mult8_esp32s3(input_data16, input_wd, input_ht, channels, + pad_wd, pad_ht, stride_wd, stride_ht, ch_mult, + filter_data16, filter_wd, filter_ht, bias, + out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } + } else if (ch_mult % 4 == 0) { + esp_nn_s8_to_s16_esp32s3(filter_data, filter_data16, filter_size); + esp_nn_aligned_s8_to_s16_with_offset_esp32s3(input_data, input_data16, input_size, input_offset); + esp_nn_depthwise_conv_s16_mult4_esp32s3(input_data16, input_wd, input_ht, channels, + pad_wd, pad_ht, stride_wd, stride_ht, ch_mult, + filter_data16, filter_wd, filter_ht, bias, + out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } else { + esp_nn_depthwise_conv_s8_unrolled(input_data, input_wd, input_ht, channels, input_offset, + pad_wd, pad_ht, stride_wd, stride_ht, ch_mult, + filter_data, filter_wd, filter_ht, + bias, out_data, out_wd, out_ht, out_offset, out_shift, + out_mult, activation_min, activation_max); + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/fully_connected/esp_nn_fully_connected_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/fully_connected/esp_nn_fully_connected_ansi.c new file mode 100644 index 000000000..ddf3cce76 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/fully_connected/esp_nn_fully_connected_ansi.c @@ -0,0 +1,50 @@ +// Copyright 2020-2021 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 "../common/common_functions.h" + +void esp_nn_fully_connected_s8_ansi(const int8_t *input_data, + const int32_t input_offset, + const uint16_t row_len, + const int8_t *filter_data, + const int32_t filter_offset, + const int32_t *bias, + int8_t *out_data, + const uint16_t out_channels, + const int32_t out_offset, + const int32_t out_shift, + const int32_t out_mult, + const int32_t activation_min, + const int32_t activation_max) +{ + for (int32_t out_c = 0; out_c < out_channels; ++out_c) { + int32_t result = 0; + for (int32_t data_idx = 0; data_idx < row_len; data_idx++) { + int32_t filter_index = row_len * out_c + data_idx; + int32_t input_val = input_data[data_idx]; + int32_t filter_val = filter_data[filter_index]; + result += (filter_val + filter_offset) * (input_val + input_offset); + } + if (bias) { + result += bias[out_c]; + } + result = esp_nn_multiply_by_quantized_mult(result, out_mult, out_shift); + result += out_offset; + result = max(result, activation_min); + result = min(result, activation_max); + out_data[out_c] = (int8_t) result; + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/pooling/esp_nn_avg_pool_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/pooling/esp_nn_avg_pool_ansi.c new file mode 100644 index 000000000..14ad9c3cc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/pooling/esp_nn_avg_pool_ansi.c @@ -0,0 +1,72 @@ +// Copyright 2020-2021 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 "../common/common_functions.h" + +void esp_nn_avg_pool_s8_ansi(const int8_t *input, + const uint16_t input_wd, + const uint16_t input_ht, + int8_t *output, + const uint16_t output_wd, + const uint16_t output_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t filter_wd, + const uint16_t filter_ht, + const uint16_t pad_wd, + const uint16_t pad_ht, + const int32_t activation_min, + const int32_t activation_max, + const uint16_t channels) +{ + int32_t base_y = -pad_ht; + for (int32_t out_y = 0; out_y < output_ht; out_y++, base_y += stride_ht) { + int32_t base_x = -pad_wd; + for (int32_t out_x = 0; out_x < output_wd; out_x++, base_x += stride_wd) { + for (int32_t ch_idx = 0; ch_idx < channels; ch_idx++) { + int32_t result = 0; + int32_t filter_cnt = 0; + /* Make sure filter does not cross the input box */ + int32_t filter_y_start = max(0, -base_y); + int32_t filter_x_start = max(0, -base_x); + + int32_t filter_y_end = min(filter_ht, input_ht - base_y); + int32_t filter_x_end = min(filter_wd, input_wd - base_x); + + for (int32_t filter_y = filter_y_start; filter_y < filter_y_end; filter_y++) { + for (int32_t filter_x = filter_x_start; filter_x < filter_x_end; filter_x++) { + int32_t in_x_idx = base_x + filter_x; + int32_t in_y_idx = base_y + filter_y; + int32_t input_index = (in_y_idx * input_wd + in_x_idx) * channels + ch_idx; + result += input[input_index]; + filter_cnt++; + } + } + + /* Rounded average */ + result = result > 0 ? (result + filter_cnt / 2) / filter_cnt + : (result - filter_cnt / 2) / filter_cnt; + + /* Activation function */ + result = max(result, activation_min); + result = min(result, activation_max); + + int32_t output_index = (out_y * output_wd + out_x) * channels + ch_idx; + output[output_index] = (int8_t) result; + } + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/pooling/esp_nn_max_pool_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/pooling/esp_nn_max_pool_ansi.c new file mode 100644 index 000000000..404cfe850 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/pooling/esp_nn_max_pool_ansi.c @@ -0,0 +1,66 @@ +// Copyright 2020-2021 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 "../common/common_functions.h" + +void esp_nn_max_pool_s8_ansi(const int8_t *input, + const uint16_t input_wd, + const uint16_t input_ht, + int8_t *output, + const uint16_t output_wd, + const uint16_t output_ht, + const uint16_t stride_wd, + const uint16_t stride_ht, + const uint16_t filter_wd, + const uint16_t filter_ht, + const uint16_t pad_wd, + const uint16_t pad_ht, + const int32_t activation_min, + const int32_t activation_max, + const uint16_t channels) +{ + int32_t base_y = -pad_ht; + for (int32_t out_y = 0; out_y < output_ht; out_y++, base_y += stride_ht) { + int32_t base_x = -pad_wd; + for (int32_t out_x = 0; out_x < output_wd; out_x++, base_x += stride_wd) { + /* Make sure filter does not cross the input box */ + int32_t filter_y_start = max(0, -base_y); + int32_t filter_x_start = max(0, -base_x); + int32_t filter_y_end = min(filter_ht, input_ht - base_y); + int32_t filter_x_end = min(filter_wd, input_wd - base_x); + + for (int32_t ch_idx = 0; ch_idx < channels; ch_idx++) { + int8_t result = INT8_MIN; + + for (int32_t filter_y = filter_y_start; filter_y < filter_y_end; filter_y++) { + for (int32_t filter_x = filter_x_start; filter_x < filter_x_end; filter_x++) { + int32_t in_x_idx = base_x + filter_x; + int32_t in_y_idx = base_y + filter_y; + int32_t input_index = (in_y_idx * input_wd + in_x_idx) * channels + ch_idx; + result = max(input[input_index], result); + } + } + + /* Activation function */ + result = max(result, activation_min); + result = min(result, activation_max); + + int32_t output_index = (out_y * output_wd + out_x) * channels + ch_idx; + output[output_index] = result; + } + } + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/esp_nn_softmax_ansi.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/esp_nn_softmax_ansi.c new file mode 100644 index 000000000..d71a8616f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/esp_nn_softmax_ansi.c @@ -0,0 +1,88 @@ +// Copyright 2022 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 "softmax_common.h" + +int32_t esp_nn_get_softmax_scratch_size_ansi(const int32_t width, const int32_t height) +{ + (void) width; + (void) height; + return 0; +} + +void esp_nn_set_softmax_scratch_buf_ansi(void *buffer) +{ + (void) buffer; + return; +} + +void esp_nn_softmax_s8_ansi(const int8_t *input_data, + const int32_t height, + const int32_t width, + const int32_t mult, + const int32_t shift, + const int32_t diff_min, + int8_t *output_data) +{ + // The representation chosen for the input to the exp() function is Q5.26. + // We need to leave extra space since values that we skip might be as large as + // -32 before multiplying by input mult, and therefore as large as + // -16 afterwards. Note that exp(-8) is definitely not insignificant to + // accumulation, but exp(-16) definitely is. +#define ACCUM_BITS 12 +#define DIFF_BITS 5 + + const int32_t mask = (1 << shift); + int32_t col = 0; + const int8_t *in_ptr = input_data; + int8_t *out_ptr = output_data; + + for (int row_idx = 0; row_idx < height; row_idx++) { + int8_t max_in_row = in_ptr[0]; + for (col = 1; col < width; col++) { + max_in_row = max(max_in_row, in_ptr[col]); + } + + int32_t input_diff = 0; + int32_t sum_of_exps = 0; + + for (col = 0; col < width; col++) { + input_diff = in_ptr[col] - max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_rescaled = SAT_HIGH_MUL(input_diff * mask, mult); + const int32_t exp_raw = esp_nn_exp_on_negative_values(input_diff_rescaled); + sum_of_exps += DIV_POW2(exp_raw, ACCUM_BITS); + } + } + + const int32_t headroom_plus1 = esp_nn_clz32((uint32_t) sum_of_exps); + const int32_t shifted_scale = ONE_OVER_ONE_X((sum_of_exps << headroom_plus1) - (1 << 31)); + const int32_t bits_over_unit = ACCUM_BITS - headroom_plus1 + 31 - sizeof(int8_t) * 8; + + for (col = 0; col < width; col++) { + input_diff = in_ptr[col] - max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_rescaled = SAT_HIGH_MUL(input_diff * mask, mult); + const int32_t exp_raw = esp_nn_exp_on_negative_values(input_diff_rescaled); + const int32_t shifted_output = SAT_HIGH_MUL(shifted_scale, exp_raw); + const int32_t result = DIV_POW2(shifted_output, bits_over_unit) - 128; + out_ptr[col] = (int8_t) esp_nn_saturate8(result); + } else { + out_ptr[col] = -128; + } + } + in_ptr += width; + out_ptr += width; + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/esp_nn_softmax_opt.c b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/esp_nn_softmax_opt.c new file mode 100644 index 000000000..93337d32d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/esp_nn_softmax_opt.c @@ -0,0 +1,108 @@ +// Copyright 2022 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 "softmax_common.h" +#include + +static int32_t *scratch_buf = NULL; + +/** + * @brief Get scratch buffer size needed by softmax function + * + * @param width + * @param height + * @return size in bytes + * + * @note buffer must be 4 byte aligned + */ +int32_t esp_nn_get_softmax_scratch_size_opt(const int32_t width, const int32_t height) +{ + (void) height; + return width * 4; +} + +/** + * @brief Set scratch buffer to be used by softmax function + * + * @param buffer this can be NULL if one needs to unset it + * must be aligned to 4 bytes + */ +void esp_nn_set_softmax_scratch_buf_opt(void *buffer) +{ + scratch_buf = (int32_t *) buffer; +} + +void esp_nn_softmax_s8_opt(const int8_t *input_data, + const int32_t height, + const int32_t width, + const int32_t mult, + const int32_t shift, + const int32_t diff_min, + int8_t *output_data) +{ + if (scratch_buf == NULL) { + printf("%s error! scratch buffer not set\n", __FUNCTION__); + return; + } + // The representation chosen for the input to the exp() function is Q5.26. + // We need to leave extra space since values that we skip might be as large as + // -32 before multiplying by input mult, and therefore as large as + // -16 afterwards. Note that exp(-8) is definitely not insignificant to + // accumulation, but exp(-16) definitely is. +#define ACCUM_BITS 12 +#define DIFF_BITS 5 + + const int32_t mask = (1 << shift); + int32_t col = 0; + const int8_t *in_ptr = input_data; + int8_t *out_ptr = output_data; + + for (int row_idx = 0; row_idx < height; row_idx++) { + int8_t max_in_row = in_ptr[0]; + for (col = 1; col < width; col++) { + max_in_row = max(max_in_row, in_ptr[col]); + } + + int32_t input_diff = 0; + int32_t sum_of_exps = 0; + + for (col = 0; col < width; col++) { + input_diff = in_ptr[col] - max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_rescaled = SAT_HIGH_MUL(input_diff * mask, mult); + const int32_t exp_raw = esp_nn_exp_on_negative_values(input_diff_rescaled); + scratch_buf[col] = exp_raw; // store to avoid duplicate calculation later + sum_of_exps += DIV_POW2(exp_raw, ACCUM_BITS); + } + } + + const int32_t headroom_plus1 = esp_nn_clz32((uint32_t) sum_of_exps); + const int32_t shifted_scale = ONE_OVER_ONE_X((sum_of_exps << headroom_plus1) - (1 << 31)); + const int32_t bits_over_unit = ACCUM_BITS - headroom_plus1 + 31 - sizeof(int8_t) * 8; + + for (col = 0; col < width; col++) { + input_diff = in_ptr[col] - max_in_row; + if (input_diff >= diff_min) { + int32_t exp_raw = scratch_buf[col]; + const int32_t shifted_output = SAT_HIGH_MUL(shifted_scale, exp_raw); + const int32_t result = DIV_POW2(shifted_output, bits_over_unit) - 128; + out_ptr[col] = (int8_t) esp_nn_saturate8(result); + } else { + out_ptr[col] = -128; + } + } + in_ptr += width; + out_ptr += width; + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/softmax_common.h b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/softmax_common.h new file mode 100644 index 000000000..010036224 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/esp-nn/src/softmax/softmax_common.h @@ -0,0 +1,104 @@ +// Copyright 2022 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 "../common/common_functions.h" + +#define MASK_IF_ZERO(x) (x) == 0 ? ~0 : 0 +#define MASK_IF_NON_ZERO(x) (x) != 0 ? ~0 : 0 +#define SELECT_USING_MASK(mask, a, b) ((mask) & (a)) ^ (~(mask) & (b)) +#define SAT_HIGH_MUL(x, y) esp_nn_sat_round_doubling_high_mul((x), (y)) +#define DIV_POW2(x,y) esp_nn_div_by_power_of_two((x), (y)) + +__NN_FORCE_INLINE__ int32_t mul_power_of_2(int val, int exp) +{ + const int32_t thresh = ((1 << (31 - exp)) - 1); + int32_t result = val << exp; + result = SELECT_USING_MASK(MASK_IF_NON_ZERO(val > thresh), INT32_MAX, result); + result = SELECT_USING_MASK(MASK_IF_NON_ZERO(val < -thresh), INT32_MIN, result); + return result; +} + +/** + * @brief Calculate `1 / (1 + x)` for x in [0, 1] + * + * @param val input value to calculate `1/(1+x)` for + * @return `int32_t` result + * @note Newton-Raphson division + * + * https://en.wikipedia.org/wiki/Division_algorithm#Newton.E2.80.93Raphson_division + * Refer to that page for the logic behind the 48/17 and 32/17 constants. + * Pseudocode: https://en.wikipedia.org/wiki/Division_algorithm#Pseudocode + */ +__NN_FORCE_INLINE__ int32_t esp_nn_one_over_one_plus_x_for_x_in_0_1(int32_t val) +{ + const int64_t sum = (int64_t) val + INT32_MAX; + const int32_t half_denominator = (int32_t) ((sum + (sum >= 0 ? 1 : -1)) / 2L); + int32_t constant_48_over_17 = 1515870810; + int32_t constant_neg_32_over_17 = -1010580540; + int32_t x = constant_48_over_17 + SAT_HIGH_MUL(half_denominator, constant_neg_32_over_17); + const int32_t fixed_2_one = (1 << 29); + + x += mul_power_of_2(SAT_HIGH_MUL(x, fixed_2_one - SAT_HIGH_MUL(half_denominator, x)), 2); + x += mul_power_of_2(SAT_HIGH_MUL(x, fixed_2_one - SAT_HIGH_MUL(half_denominator, x)), 2); + x += mul_power_of_2(SAT_HIGH_MUL(x, fixed_2_one - SAT_HIGH_MUL(half_denominator, x)), 2); + + return mul_power_of_2(x, 1); +} + +#define ONE_OVER_ONE_X(x) esp_nn_one_over_one_plus_x_for_x_in_0_1((x)) + +/** + * @brief Return exp(x) for x < 0. + * + */ +__NN_FORCE_INLINE__ int32_t esp_nn_exp_on_negative_values(int32_t val) +{ + int32_t shift = 24; + + const int32_t one_quarter = (1 << shift); + int32_t mask = one_quarter - 1; + const int32_t val_mod_minus_quarter = (val & mask) - one_quarter; + const int32_t remainder = val_mod_minus_quarter - val; + + // calculate exponent for x in [-1/4, 0) in `result` + const int32_t x = (val_mod_minus_quarter << 5) + (1 << 28); + const int32_t x2 = SAT_HIGH_MUL(x, x); + const int32_t x3 = SAT_HIGH_MUL(x2, x); + const int32_t x4 = SAT_HIGH_MUL(x2, x2); + const int32_t one_over_3 = 715827883; + const int32_t one_over_8 = 1895147668; + + const int32_t x4_over_4 = DIV_POW2(x4, 2); + const int32_t x4_over_4_plus_x3_over_6_plus_x2_over_2 = DIV_POW2(SAT_HIGH_MUL(x4_over_4 + x3, one_over_3) + x2, 1); + int32_t result = one_over_8 + SAT_HIGH_MUL(one_over_8, x + x4_over_4_plus_x3_over_6_plus_x2_over_2); + +#define SELECT_IF_NON_ZERO(x) { \ + mask = MASK_IF_NON_ZERO(remainder & (1 << shift++)); \ + result = SELECT_USING_MASK(mask, SAT_HIGH_MUL(result, x), result); \ +} + + SELECT_IF_NON_ZERO(1672461947) + SELECT_IF_NON_ZERO(1302514674) + SELECT_IF_NON_ZERO(790015084) + SELECT_IF_NON_ZERO(290630308) + SELECT_IF_NON_ZERO(39332535) + SELECT_IF_NON_ZERO(720401) + SELECT_IF_NON_ZERO(242) + +#undef SELECT_IF_NON_ZERO + + mask = MASK_IF_ZERO(val); + return SELECT_USING_MASK(mask, INT32_MAX, result); +} \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/builtin_op_data.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/builtin_op_data.h new file mode 100644 index 000000000..b9d428451 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/builtin_op_data.h @@ -0,0 +1,22 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ +// Compatibility shim for new location of interface definitions. + +#ifndef TENSORFLOW_LITE_BUILTIN_OP_DATA_H_ +#define TENSORFLOW_LITE_BUILTIN_OP_DATA_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" + +#endif // TENSORFLOW_LITE_BUILTIN_OP_DATA_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/builtin_ops.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/builtin_ops.h new file mode 100644 index 000000000..337073080 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/builtin_ops.h @@ -0,0 +1,194 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_BUILTIN_OPS_H_ +#define TENSORFLOW_LITE_BUILTIN_OPS_H_ + +// DO NOT EDIT MANUALLY: This file is automatically generated by +// `schema/builtin_ops_header/generator.cc`. + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// The enum for builtin operators. +// Note: CUSTOM, DELEGATE, and PLACEHOLDER_FOR_GREATER_OP_CODES are 3 special +// ops which are not real built-in ops. +typedef enum { + kTfLiteBuiltinAdd = 0, + kTfLiteBuiltinAveragePool2d = 1, + kTfLiteBuiltinConcatenation = 2, + kTfLiteBuiltinConv2d = 3, + kTfLiteBuiltinDepthwiseConv2d = 4, + kTfLiteBuiltinDepthToSpace = 5, + kTfLiteBuiltinDequantize = 6, + kTfLiteBuiltinEmbeddingLookup = 7, + kTfLiteBuiltinFloor = 8, + kTfLiteBuiltinFullyConnected = 9, + kTfLiteBuiltinHashtableLookup = 10, + kTfLiteBuiltinL2Normalization = 11, + kTfLiteBuiltinL2Pool2d = 12, + kTfLiteBuiltinLocalResponseNormalization = 13, + kTfLiteBuiltinLogistic = 14, + kTfLiteBuiltinLshProjection = 15, + kTfLiteBuiltinLstm = 16, + kTfLiteBuiltinMaxPool2d = 17, + kTfLiteBuiltinMul = 18, + kTfLiteBuiltinRelu = 19, + kTfLiteBuiltinReluN1To1 = 20, + kTfLiteBuiltinRelu6 = 21, + kTfLiteBuiltinReshape = 22, + kTfLiteBuiltinResizeBilinear = 23, + kTfLiteBuiltinRnn = 24, + kTfLiteBuiltinSoftmax = 25, + kTfLiteBuiltinSpaceToDepth = 26, + kTfLiteBuiltinSvdf = 27, + kTfLiteBuiltinTanh = 28, + kTfLiteBuiltinConcatEmbeddings = 29, + kTfLiteBuiltinSkipGram = 30, + kTfLiteBuiltinCall = 31, + kTfLiteBuiltinCustom = 32, + kTfLiteBuiltinEmbeddingLookupSparse = 33, + kTfLiteBuiltinPad = 34, + kTfLiteBuiltinUnidirectionalSequenceRnn = 35, + kTfLiteBuiltinGather = 36, + kTfLiteBuiltinBatchToSpaceNd = 37, + kTfLiteBuiltinSpaceToBatchNd = 38, + kTfLiteBuiltinTranspose = 39, + kTfLiteBuiltinMean = 40, + kTfLiteBuiltinSub = 41, + kTfLiteBuiltinDiv = 42, + kTfLiteBuiltinSqueeze = 43, + kTfLiteBuiltinUnidirectionalSequenceLstm = 44, + kTfLiteBuiltinStridedSlice = 45, + kTfLiteBuiltinBidirectionalSequenceRnn = 46, + kTfLiteBuiltinExp = 47, + kTfLiteBuiltinTopkV2 = 48, + kTfLiteBuiltinSplit = 49, + kTfLiteBuiltinLogSoftmax = 50, + kTfLiteBuiltinDelegate = 51, + kTfLiteBuiltinBidirectionalSequenceLstm = 52, + kTfLiteBuiltinCast = 53, + kTfLiteBuiltinPrelu = 54, + kTfLiteBuiltinMaximum = 55, + kTfLiteBuiltinArgMax = 56, + kTfLiteBuiltinMinimum = 57, + kTfLiteBuiltinLess = 58, + kTfLiteBuiltinNeg = 59, + kTfLiteBuiltinPadv2 = 60, + kTfLiteBuiltinGreater = 61, + kTfLiteBuiltinGreaterEqual = 62, + kTfLiteBuiltinLessEqual = 63, + kTfLiteBuiltinSelect = 64, + kTfLiteBuiltinSlice = 65, + kTfLiteBuiltinSin = 66, + kTfLiteBuiltinTransposeConv = 67, + kTfLiteBuiltinSparseToDense = 68, + kTfLiteBuiltinTile = 69, + kTfLiteBuiltinExpandDims = 70, + kTfLiteBuiltinEqual = 71, + kTfLiteBuiltinNotEqual = 72, + kTfLiteBuiltinLog = 73, + kTfLiteBuiltinSum = 74, + kTfLiteBuiltinSqrt = 75, + kTfLiteBuiltinRsqrt = 76, + kTfLiteBuiltinShape = 77, + kTfLiteBuiltinPow = 78, + kTfLiteBuiltinArgMin = 79, + kTfLiteBuiltinFakeQuant = 80, + kTfLiteBuiltinReduceProd = 81, + kTfLiteBuiltinReduceMax = 82, + kTfLiteBuiltinPack = 83, + kTfLiteBuiltinLogicalOr = 84, + kTfLiteBuiltinOneHot = 85, + kTfLiteBuiltinLogicalAnd = 86, + kTfLiteBuiltinLogicalNot = 87, + kTfLiteBuiltinUnpack = 88, + kTfLiteBuiltinReduceMin = 89, + kTfLiteBuiltinFloorDiv = 90, + kTfLiteBuiltinReduceAny = 91, + kTfLiteBuiltinSquare = 92, + kTfLiteBuiltinZerosLike = 93, + kTfLiteBuiltinFill = 94, + kTfLiteBuiltinFloorMod = 95, + kTfLiteBuiltinRange = 96, + kTfLiteBuiltinResizeNearestNeighbor = 97, + kTfLiteBuiltinLeakyRelu = 98, + kTfLiteBuiltinSquaredDifference = 99, + kTfLiteBuiltinMirrorPad = 100, + kTfLiteBuiltinAbs = 101, + kTfLiteBuiltinSplitV = 102, + kTfLiteBuiltinUnique = 103, + kTfLiteBuiltinCeil = 104, + kTfLiteBuiltinReverseV2 = 105, + kTfLiteBuiltinAddN = 106, + kTfLiteBuiltinGatherNd = 107, + kTfLiteBuiltinCos = 108, + kTfLiteBuiltinWhere = 109, + kTfLiteBuiltinRank = 110, + kTfLiteBuiltinElu = 111, + kTfLiteBuiltinReverseSequence = 112, + kTfLiteBuiltinMatrixDiag = 113, + kTfLiteBuiltinQuantize = 114, + kTfLiteBuiltinMatrixSetDiag = 115, + kTfLiteBuiltinRound = 116, + kTfLiteBuiltinHardSwish = 117, + kTfLiteBuiltinIf = 118, + kTfLiteBuiltinWhile = 119, + kTfLiteBuiltinNonMaxSuppressionV4 = 120, + kTfLiteBuiltinNonMaxSuppressionV5 = 121, + kTfLiteBuiltinScatterNd = 122, + kTfLiteBuiltinSelectV2 = 123, + kTfLiteBuiltinDensify = 124, + kTfLiteBuiltinSegmentSum = 125, + kTfLiteBuiltinBatchMatmul = 126, + kTfLiteBuiltinPlaceholderForGreaterOpCodes = 127, + kTfLiteBuiltinCumsum = 128, + kTfLiteBuiltinCallOnce = 129, + kTfLiteBuiltinBroadcastTo = 130, + kTfLiteBuiltinRfft2d = 131, + kTfLiteBuiltinConv3d = 132, + kTfLiteBuiltinImag = 133, + kTfLiteBuiltinReal = 134, + kTfLiteBuiltinComplexAbs = 135, + kTfLiteBuiltinHashtable = 136, + kTfLiteBuiltinHashtableFind = 137, + kTfLiteBuiltinHashtableImport = 138, + kTfLiteBuiltinHashtableSize = 139, + kTfLiteBuiltinReduceAll = 140, + kTfLiteBuiltinConv3dTranspose = 141, + kTfLiteBuiltinVarHandle = 142, + kTfLiteBuiltinReadVariable = 143, + kTfLiteBuiltinAssignVariable = 144, + kTfLiteBuiltinBroadcastArgs = 145, + kTfLiteBuiltinRandomStandardNormal = 146, + kTfLiteBuiltinBucketize = 147, + kTfLiteBuiltinRandomUniform = 148, + kTfLiteBuiltinMultinomial = 149, + kTfLiteBuiltinGelu = 150, + kTfLiteBuiltinDynamicUpdateSlice = 151, + kTfLiteBuiltinRelu0To1 = 152, + kTfLiteBuiltinUnsortedSegmentProd = 153, + kTfLiteBuiltinUnsortedSegmentMax = 154, + kTfLiteBuiltinUnsortedSegmentSum = 155, + kTfLiteBuiltinAtan2 = 156, + kTfLiteBuiltinUnsortedSegmentMin = 157, + kTfLiteBuiltinSign = 158, +} TfLiteBuiltinOperator; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif // TENSORFLOW_LITE_BUILTIN_OPS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/builtin_op_data.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/builtin_op_data.h new file mode 100644 index 000000000..7f160972e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/builtin_op_data.h @@ -0,0 +1,525 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_C_BUILTIN_OP_DATA_H_ +#define TENSORFLOW_LITE_C_BUILTIN_OP_DATA_H_ + +#include + +#include "tensorflow/lite/c/common.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// TfLiteReshapeParams can't have dynamic data so we fix the maximum possible +// number of dimensions. +#define TFLITE_RESHAPE_PARAMS_MAX_DIMENSION_COUNT 8 + +// TODO(aselle): Consider using "if this then that" for testing. + +// Useful placeholder to put in otherwise empty structs to avoid size warnings. +typedef struct { + char dummy; +} EmptyStructPlaceholder; + +// IMPORTANT: All new members of structs must be added at the end to ensure +// backwards compatibility. + +// Possible padding types (for convolutions) +typedef enum { + kTfLitePaddingUnknown = 0, + kTfLitePaddingSame, + kTfLitePaddingValid, +} TfLitePadding; + +typedef enum { + kTfLiteMirrorPaddingUnknown = 0, + kTfLiteMirrorPaddingReflect, + kTfLiteMirrorPaddingSymmetric, +} TfLiteMirrorPaddingMode; + +// TODO(b/130259536): We should move this out of builtin_op_data. +typedef struct { + int width; + int height; + int width_offset; + int height_offset; +} TfLitePaddingValues; + +typedef struct { + TfLiteMirrorPaddingMode mode; +} TfLiteMirrorPaddingParams; + +// Possible fused activation functions. +typedef enum { + kTfLiteActNone = 0, + kTfLiteActRelu, + kTfLiteActReluN1To1, // min(max(-1, x), 1) + kTfLiteActRelu6, // min(max(0, x), 6) + kTfLiteActTanh, + kTfLiteActSignBit, + kTfLiteActSigmoid, +} TfLiteFusedActivation; + +typedef struct { + // Parameters for CONV_2D version 1. + TfLitePadding padding; + int stride_width; + int stride_height; + TfLiteFusedActivation activation; + + // Parameters for CONV_2D version 2. + // Note: Version 2 supports dilation values not equal to 1. + int dilation_width_factor; + int dilation_height_factor; +} TfLiteConvParams; + +typedef struct { + TfLitePadding padding; + int stride_width; + int stride_height; + int stride_depth; + int dilation_width_factor; + int dilation_height_factor; + int dilation_depth_factor; + TfLiteFusedActivation activation; +} TfLiteConv3DParams; + +typedef TfLiteConv3DParams TfLiteConv3DTransposeParams; + +typedef struct { + TfLitePadding padding; + int stride_width; + int stride_height; + int filter_width; + int filter_height; + TfLiteFusedActivation activation; + struct { + TfLitePaddingValues padding; + } computed; +} TfLitePoolParams; + +typedef struct { + // Parameters for DepthwiseConv version 1 or above. + TfLitePadding padding; + int stride_width; + int stride_height; + // `depth_multiplier` is redundant. It's used by CPU kernels in + // TensorFlow 2.0 or below, but ignored in versions above. + // + // The information can be deduced from the shape of input and the shape of + // weights. Since the TFLiteConverter toolchain doesn't support partially + // specified shapes, relying on `depth_multiplier` stops us from supporting + // graphs with dynamic shape tensors. + // + // Note: Some of the delegates (e.g. NNAPI, GPU) are still relying on this + // field. + int depth_multiplier; + TfLiteFusedActivation activation; + // Parameters for DepthwiseConv version 2 or above. + int dilation_width_factor; + int dilation_height_factor; +} TfLiteDepthwiseConvParams; + +typedef struct { + int rank; + TfLiteFusedActivation activation; + + // Parameter for SVDF version 4. + bool asymmetric_quantize_inputs; +} TfLiteSVDFParams; + +typedef struct { + TfLiteFusedActivation activation; + + // Parameter for RNN version 3. + bool asymmetric_quantize_inputs; +} TfLiteRNNParams; + +typedef struct { + bool time_major; + TfLiteFusedActivation activation; + + // Parameter for Sequence RNN version 3. + bool asymmetric_quantize_inputs; +} TfLiteSequenceRNNParams; + +typedef struct { + bool time_major; + TfLiteFusedActivation activation; + bool merge_outputs; + + // Parameter for Bidirectional RNN verison 3. + bool asymmetric_quantize_inputs; +} TfLiteBidirectionalSequenceRNNParams; + +typedef enum { + kTfLiteFullyConnectedWeightsFormatDefault = 0, + kTfLiteFullyConnectedWeightsFormatShuffled4x16Int8 = 1, +} TfLiteFullyConnectedWeightsFormat; + +typedef struct { + // Parameters for FullyConnected version 1 or above. + TfLiteFusedActivation activation; + + // Parameters for FullyConnected version 2 or above. + TfLiteFullyConnectedWeightsFormat weights_format; + + // Parameters for FullyConnected version 5 or above. + // If set to true, then the number of dimensions in the input and the output + // tensors are the same. Furthermore, all but the last dimension of the input + // and output shapes will be equal. + bool keep_num_dims; + + // Parameters for FullyConnected version 7 or above. + // If set to true and the weights are quantized, then non constant inputs + // are quantized at evaluation time with asymmetric quantization. + bool asymmetric_quantize_inputs; +} TfLiteFullyConnectedParams; + +typedef enum { + kTfLiteLshProjectionUnknown = 0, + kTfLiteLshProjectionSparse = 1, + kTfLiteLshProjectionDense = 2, +} TfLiteLSHProjectionType; + +typedef struct { + TfLiteLSHProjectionType type; +} TfLiteLSHProjectionParams; + +typedef struct { + float beta; +} TfLiteSoftmaxParams; + +typedef struct { + int axis; + TfLiteFusedActivation activation; +} TfLiteConcatenationParams; + +typedef struct { + TfLiteFusedActivation activation; + // Parameter added for the version 4. + bool pot_scale_int16; +} TfLiteAddParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLiteSpaceToBatchNDParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLiteBatchToSpaceNDParams; + +typedef struct { + bool adj_x; + bool adj_y; + // Parameters for BatchMatMul version 4 or above. + // If set to true and the weights are quantized, then non constant inputs + // are quantized at evaluation time with asymmetric quantization. + bool asymmetric_quantize_inputs; +} TfLiteBatchMatMulParams; + +typedef struct { + TfLiteFusedActivation activation; +} TfLiteMulParams; + +typedef struct { + TfLiteFusedActivation activation; + // Parameter added for the version 5. + bool pot_scale_int16; +} TfLiteSubParams; + +typedef struct { + TfLiteFusedActivation activation; +} TfLiteDivParams; + +typedef struct { + TfLiteFusedActivation activation; +} TfLiteL2NormParams; + +typedef struct { + int radius; + float bias; + float alpha; + float beta; +} TfLiteLocalResponseNormParams; + +typedef enum { + kTfLiteLSTMFullKernel = 0, + kTfLiteLSTMBasicKernel +} TfLiteLSTMKernelType; + +typedef struct { + // Parameters for LSTM version 1. + TfLiteFusedActivation activation; + float cell_clip; + float proj_clip; + + // Parameters for LSTM version 2. + // kTfLiteLSTMBasicKernel is only supported in version 2 or above. + TfLiteLSTMKernelType kernel_type; + + // Parameters for LSTM version 4. + bool asymmetric_quantize_inputs; +} TfLiteLSTMParams; + +typedef struct { + // Parameters needed for the underlying LSTM. + TfLiteFusedActivation activation; + float cell_clip; + float proj_clip; + + // If set to true then the first dimension is time, otherwise batch. + bool time_major; + + // Parameter for unidirectional sequence RNN version 3. + bool asymmetric_quantize_inputs; +} TfLiteUnidirectionalSequenceLSTMParams; + +typedef struct { + // Parameters supported by version 1: + // Parameters inherited for the LSTM kernel. + TfLiteFusedActivation activation; + float cell_clip; + float proj_clip; + + // If true, store the outputs of both directions in the first output. + bool merge_outputs; + + // Parameters supported by version 2: + // If set to true then the first dimension is time, otherwise batch. + bool time_major; + + // Parameters supported by version 4: + // If set to true, then hybrid ops use asymmetric quantization for inputs. + bool asymmetric_quantize_inputs; +} TfLiteBidirectionalSequenceLSTMParams; + +typedef struct { + bool align_corners; + // half_pixel_centers assumes pixels are of half the actual dimensions, and + // yields more accurate resizes. Corresponds to the same argument for the + // original TensorFlow op in TF2.0. + bool half_pixel_centers; +} TfLiteResizeBilinearParams; + +typedef struct { + bool align_corners; + bool half_pixel_centers; +} TfLiteResizeNearestNeighborParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLitePadParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLitePadV2Params; + +typedef struct { + // These fields are only used in old models for backward compatibility. + // In the current implementation, we use the 2nd input of the op as the shape, + // and these fields are unused. + int shape[TFLITE_RESHAPE_PARAMS_MAX_DIMENSION_COUNT]; + int num_dimensions; +} TfLiteReshapeParams; + +typedef struct { + int ngram_size; + int max_skip_size; + bool include_all_ngrams; +} TfLiteSkipGramParams; + +typedef struct { + int block_size; +} TfLiteSpaceToDepthParams; + +typedef struct { + int block_size; +} TfLiteDepthToSpaceParams; + +typedef struct { + TfLiteType in_data_type; + TfLiteType out_data_type; +} TfLiteCastParams; + +typedef enum { + kTfLiteCombinerTypeSum = 0, + kTfLiteCombinerTypeMean = 1, + kTfLiteCombinerTypeSqrtn = 2, +} TfLiteCombinerType; + +typedef struct { + TfLiteCombinerType combiner; +} TfLiteEmbeddingLookupSparseParams; + +typedef struct { + int axis; + int batch_dims; +} TfLiteGatherParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLiteTransposeParams; + +typedef struct { + bool keep_dims; +} TfLiteReducerParams; + +typedef struct { + int num_splits; +} TfLiteSplitParams; + +typedef struct { + int num_splits; +} TfLiteSplitVParams; + +typedef struct { + // TODO(ahentz): We can't have dynamic data in this struct, at least not yet. + // For now we will fix the maximum possible number of dimensions. + int squeeze_dims[8]; + int num_squeeze_dims; +} TfLiteSqueezeParams; + +typedef struct { + int begin_mask; + int end_mask; + int ellipsis_mask; + int new_axis_mask; + int shrink_axis_mask; +} TfLiteStridedSliceParams; + +typedef struct { + TfLiteType output_type; +} TfLiteArgMaxParams; + +typedef struct { + TfLiteType output_type; +} TfLiteArgMinParams; + +typedef struct { + TfLitePadding padding; + int stride_width; + int stride_height; +} TfLiteTransposeConvParams; + +typedef struct { + bool validate_indices; +} TfLiteSparseToDenseParams; + +typedef struct { + TfLiteType out_type; +} TfLiteShapeParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLiteRankParams; + +typedef struct { + // Parameters supported by version 1: + float min; + float max; + int num_bits; + + // Parameters supported by version 2: + bool narrow_range; +} TfLiteFakeQuantParams; + +typedef struct { + int values_count; + int axis; +} TfLitePackParams; + +typedef struct { + int axis; +} TfLiteOneHotParams; + +typedef struct { + int num; + int axis; +} TfLiteUnpackParams; + +typedef struct { + float alpha; +} TfLiteLeakyReluParams; + +typedef struct { + TfLiteType index_out_type; +} TfLiteUniqueParams; + +typedef struct { + int seq_dim; + int batch_dim; +} TfLiteReverseSequenceParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLiteMatrixDiagParams; + +typedef struct { + EmptyStructPlaceholder placeholder; +} TfLiteMatrixSetDiagParams; + +typedef struct { + int then_subgraph_index; + int else_subgraph_index; +} TfLiteIfParams; + +typedef struct { + int cond_subgraph_index; + int body_subgraph_index; +} TfLiteWhileParams; + +typedef struct { + bool exclusive; + bool reverse; +} TfLiteCumsumParams; + +typedef struct { + int init_subgraph_index; +} TfLiteCallOnceParams; + +typedef struct { + int table_id; + TfLiteType key_dtype; + TfLiteType value_dtype; +} TfLiteHashtableParams; + +typedef struct { + const char* container; + const char* shared_name; +} TfLiteVarHandleParams; + +typedef struct { + int seed; + int seed2; +} TfLiteRandomParams; + +typedef struct { + int num_boundaries; + // This points to the memory stored in the model (flatbuffer), + // and is not owned. + const float* boundaries; +} TfLiteBucketizeParams; + +typedef struct { + bool approximate; +} TfLiteGeluParams; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_C_BUILTIN_OP_DATA_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/c_api_types.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/c_api_types.h new file mode 100644 index 000000000..9d7668e13 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/c_api_types.h @@ -0,0 +1,147 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 file declares types used by the pure C inference API defined in c_api.h, +// some of which are also used in the C++ and C kernel and interpreter APIs. + +#ifndef TENSORFLOW_LITE_C_C_API_TYPES_H_ +#define TENSORFLOW_LITE_C_C_API_TYPES_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Define TFL_CAPI_EXPORT macro to export a function properly with a shared +// library. +#ifdef SWIG +#define TFL_CAPI_EXPORT +#elif defined(TFL_STATIC_LIBRARY_BUILD) +#define TFL_CAPI_EXPORT +#else // not definded TFL_STATIC_LIBRARY_BUILD +#if defined(_WIN32) +#ifdef TFL_COMPILE_LIBRARY +#define TFL_CAPI_EXPORT __declspec(dllexport) +#else +#define TFL_CAPI_EXPORT __declspec(dllimport) +#endif // TFL_COMPILE_LIBRARY +#else +#define TFL_CAPI_EXPORT __attribute__((visibility("default"))) +#endif // _WIN32 +#endif // SWIG + +// Note that new error status values may be added in future in order to +// indicate more fine-grained internal states, therefore, applications should +// not rely on status values being members of the enum. +typedef enum TfLiteStatus { + kTfLiteOk = 0, + + // Generally referring to an error in the runtime (i.e. interpreter) + kTfLiteError = 1, + + // Generally referring to an error from a TfLiteDelegate itself. + kTfLiteDelegateError = 2, + + // Generally referring to an error in applying a delegate due to + // incompatibility between runtime and delegate, e.g., this error is returned + // when trying to apply a TF Lite delegate onto a model graph that's already + // immutable. + kTfLiteApplicationError = 3, + + // Generally referring to serialized delegate data not being found. + // See tflite::delegates::Serialization. + kTfLiteDelegateDataNotFound = 4, + + // Generally referring to data-writing issues in delegate serialization. + // See tflite::delegates::Serialization. + kTfLiteDelegateDataWriteError = 5, + + // Generally referring to data-reading issues in delegate serialization. + // See tflite::delegates::Serialization. + kTfLiteDelegateDataReadError = 6, + + // Generally referring to issues when the TF Lite model has ops that cannot be + // resolved at runtime. This could happen when the specific op is not + // registered or built with the TF Lite framework. + kTfLiteUnresolvedOps = 7, + + // Generally referring to invocation cancelled by the user. + // See `interpreter::Cancel`. + // TODO(b/194915839): Implement `interpreter::Cancel`. + // TODO(b/250636993): Cancellation triggered by `SetCancellationFunction` + // should also return this status code. + kTfLiteCancelled = 8, +} TfLiteStatus; + +// Types supported by tensor +typedef enum { + kTfLiteNoType = 0, + kTfLiteFloat32 = 1, + kTfLiteInt32 = 2, + kTfLiteUInt8 = 3, + kTfLiteInt64 = 4, + kTfLiteString = 5, + kTfLiteBool = 6, + kTfLiteInt16 = 7, + kTfLiteComplex64 = 8, + kTfLiteInt8 = 9, + kTfLiteFloat16 = 10, + kTfLiteFloat64 = 11, + kTfLiteComplex128 = 12, + kTfLiteUInt64 = 13, + kTfLiteResource = 14, + kTfLiteVariant = 15, + kTfLiteUInt32 = 16, + kTfLiteUInt16 = 17, + kTfLiteInt4 = 18, +} TfLiteType; + +// Legacy. Will be deprecated in favor of TfLiteAffineQuantization. +// If per-layer quantization is specified this field will still be populated in +// addition to TfLiteAffineQuantization. +// Parameters for asymmetric quantization. Quantized values can be converted +// back to float using: +// real_value = scale * (quantized_value - zero_point) +typedef struct TfLiteQuantizationParams { + float scale; + int32_t zero_point; +} TfLiteQuantizationParams; + +// -------------------------------------------------------------------------- +// Opaque types used by c_api.h, c_api_opaque.h and common.h. + +// TfLiteOpaqueContext is an opaque version of TfLiteContext; +typedef struct TfLiteOpaqueContext TfLiteOpaqueContext; + +// TfLiteOpaqueNode is an opaque version of TfLiteNode; +typedef struct TfLiteOpaqueNode TfLiteOpaqueNode; + +// TfLiteOpaqueTensor is an opaque version of TfLiteTensor; +typedef struct TfLiteOpaqueTensor TfLiteOpaqueTensor; + +// TfLiteOpaqueDelegateStruct: opaque version of TfLiteDelegate; allows +// delegation of nodes to alternative backends. +// +// This is an abstract type that is intended to have the same +// role as TfLiteDelegate from common.h, but without exposing the implementation +// details of how delegates are implemented. +// WARNING: This is an experimental type and subject to change. +typedef struct TfLiteOpaqueDelegateStruct TfLiteOpaqueDelegateStruct; + +#ifdef __cplusplus +} // extern C +#endif +#endif // TENSORFLOW_LITE_C_C_API_TYPES_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/common.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/common.cpp new file mode 100644 index 000000000..4e87300af --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/common.cpp @@ -0,0 +1,321 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" + +#include "tensorflow/lite/c/c_api_types.h" +#ifdef TF_LITE_TENSORFLOW_PROFILER +#include "tensorflow/lite/tensorflow_profiler_logger.h" +#endif + +#ifndef ARDUINO +#include +#include +#endif // ARDUINO + +extern "C" { + +size_t TfLiteIntArrayGetSizeInBytes(int size) { + static TfLiteIntArray dummy; + + size_t computed_size = sizeof(dummy) + sizeof(dummy.data[0]) * size; +#if defined(_MSC_VER) + // Context for why this is needed is in http://b/189926408#comment21 + computed_size -= sizeof(dummy.data[0]); +#endif + return computed_size; +} + +int TfLiteIntArrayEqual(const TfLiteIntArray* a, const TfLiteIntArray* b) { + if (a == b) return 1; + if (a == nullptr || b == nullptr) return 0; + return TfLiteIntArrayEqualsArray(a, b->size, b->data); +} + +int TfLiteIntArrayEqualsArray(const TfLiteIntArray* a, int b_size, + const int b_data[]) { + if (a == nullptr) return (b_size == 0); + if (a->size != b_size) return 0; + int i = 0; + for (; i < a->size; i++) + if (a->data[i] != b_data[i]) return 0; + return 1; +} + +#ifndef ARDUINO + +TfLiteIntArray* TfLiteIntArrayCreate(int size) { + size_t alloc_size = TfLiteIntArrayGetSizeInBytes(size); + if (alloc_size <= 0) return nullptr; + TfLiteIntArray* ret = (TfLiteIntArray*)malloc(alloc_size); + if (!ret) return ret; + ret->size = size; + return ret; +} + +TfLiteIntArray* TfLiteIntArrayCopy(const TfLiteIntArray* src) { + if (!src) return nullptr; + TfLiteIntArray* ret = TfLiteIntArrayCreate(src->size); + if (ret) { + memcpy(ret->data, src->data, src->size * sizeof(int)); + } + return ret; +} + +void TfLiteIntArrayFree(TfLiteIntArray* a) { free(a); } + +#endif // ARDUINO + +int TfLiteFloatArrayGetSizeInBytes(int size) { + static TfLiteFloatArray dummy; + + int computed_size = sizeof(dummy) + sizeof(dummy.data[0]) * size; +#if defined(_MSC_VER) + // Context for why this is needed is in http://b/189926408#comment21 + computed_size -= sizeof(dummy.data[0]); +#endif + return computed_size; +} + +#ifndef ARDUINO + +TfLiteFloatArray* TfLiteFloatArrayCreate(int size) { + TfLiteFloatArray* ret = + (TfLiteFloatArray*)malloc(TfLiteFloatArrayGetSizeInBytes(size)); + ret->size = size; + return ret; +} + +void TfLiteFloatArrayFree(TfLiteFloatArray* a) { free(a); } + +void TfLiteTensorDataFree(TfLiteTensor* t) { + if (t->allocation_type == kTfLiteDynamic || + t->allocation_type == kTfLitePersistentRo) { + if (t->data.raw) { +#ifdef TF_LITE_TENSORFLOW_PROFILER + tflite::OnTfLiteTensorDealloc(t); +#endif + free(t->data.raw); + } + } + t->data.raw = nullptr; +} + +void TfLiteQuantizationFree(TfLiteQuantization* quantization) { + if (quantization->type == kTfLiteAffineQuantization) { + TfLiteAffineQuantization* q_params = + (TfLiteAffineQuantization*)(quantization->params); + if (q_params->scale) { + TfLiteFloatArrayFree(q_params->scale); + q_params->scale = nullptr; + } + if (q_params->zero_point) { + TfLiteIntArrayFree(q_params->zero_point); + q_params->zero_point = nullptr; + } + free(q_params); + } + quantization->params = nullptr; + quantization->type = kTfLiteNoQuantization; +} + +void TfLiteSparsityFree(TfLiteSparsity* sparsity) { + if (sparsity == nullptr) { + return; + } + + if (sparsity->traversal_order) { + TfLiteIntArrayFree(sparsity->traversal_order); + sparsity->traversal_order = nullptr; + } + + if (sparsity->block_map) { + TfLiteIntArrayFree(sparsity->block_map); + sparsity->block_map = nullptr; + } + + if (sparsity->dim_metadata) { + int i = 0; + for (; i < sparsity->dim_metadata_size; i++) { + TfLiteDimensionMetadata metadata = sparsity->dim_metadata[i]; + if (metadata.format == kTfLiteDimSparseCSR) { + TfLiteIntArrayFree(metadata.array_segments); + metadata.array_segments = nullptr; + TfLiteIntArrayFree(metadata.array_indices); + metadata.array_indices = nullptr; + } + } + free(sparsity->dim_metadata); + sparsity->dim_metadata = nullptr; + } + + free(sparsity); +} + +void TfLiteTensorFree(TfLiteTensor* t) { + TfLiteTensorDataFree(t); + if (t->dims) TfLiteIntArrayFree(t->dims); + t->dims = nullptr; + + if (t->dims_signature) { + TfLiteIntArrayFree((TfLiteIntArray*)t->dims_signature); + } + t->dims_signature = nullptr; + + TfLiteQuantizationFree(&t->quantization); + TfLiteSparsityFree(t->sparsity); + t->sparsity = nullptr; +} + +void TfLiteTensorReset(TfLiteType type, const char* name, TfLiteIntArray* dims, + TfLiteQuantizationParams quantization, char* buffer, + size_t size, TfLiteAllocationType allocation_type, + const void* allocation, bool is_variable, + TfLiteTensor* tensor) { + TfLiteTensorFree(tensor); + tensor->type = type; + tensor->name = name; + tensor->dims = dims; + tensor->params = quantization; + tensor->data.raw = buffer; + tensor->bytes = size; + tensor->allocation_type = allocation_type; + tensor->allocation = allocation; + tensor->is_variable = is_variable; + + tensor->quantization.type = kTfLiteNoQuantization; + tensor->quantization.params = nullptr; +} + +TfLiteStatus TfLiteTensorCopy(const TfLiteTensor* src, TfLiteTensor* dst) { + if (!src || !dst) return kTfLiteOk; + if (src->bytes != dst->bytes) return kTfLiteError; + if (src == dst) return kTfLiteOk; + + dst->type = src->type; + if (dst->dims) TfLiteIntArrayFree(dst->dims); + dst->dims = TfLiteIntArrayCopy(src->dims); + memcpy(dst->data.raw, src->data.raw, src->bytes); + dst->buffer_handle = src->buffer_handle; + dst->data_is_stale = src->data_is_stale; + dst->delegate = src->delegate; + + return kTfLiteOk; +} + +void TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor, + bool preserve_data) { + if (tensor->allocation_type != kTfLiteDynamic && + tensor->allocation_type != kTfLitePersistentRo) { + return; + } + // TODO(b/145340303): Tensor data should be aligned. + if (!tensor->data.data) { + tensor->data.data = (char*)malloc(num_bytes); +#ifdef TF_LITE_TENSORFLOW_PROFILER + tflite::OnTfLiteTensorAlloc(tensor, num_bytes); +#endif + } else if (num_bytes > tensor->bytes) { +#ifdef TF_LITE_TENSORFLOW_PROFILER + tflite::OnTfLiteTensorDealloc(tensor); +#endif + if (preserve_data) { + tensor->data.data = (char*)realloc(tensor->data.data, num_bytes); + } else { + // Calling free and malloc can be more efficient as it avoids needlessly + // copying the data when it is not required. + free(tensor->data.data); + tensor->data.data = (char*)malloc(num_bytes); + } +#ifdef TF_LITE_TENSORFLOW_PROFILER + tflite::OnTfLiteTensorAlloc(tensor, num_bytes); +#endif + } + tensor->bytes = num_bytes; +} + +void TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor) { + return TfLiteTensorResizeMaybeCopy(num_bytes, tensor, true); +} +#endif // ARDUINO + +const char* TfLiteTypeGetName(TfLiteType type) { + switch (type) { + case kTfLiteNoType: + return "NOTYPE"; + case kTfLiteFloat32: + return "FLOAT32"; + case kTfLiteUInt16: + return "UINT16"; + case kTfLiteInt16: + return "INT16"; + case kTfLiteInt32: + return "INT32"; + case kTfLiteUInt32: + return "UINT32"; + case kTfLiteUInt8: + return "UINT8"; + case kTfLiteInt8: + return "INT8"; + case kTfLiteInt64: + return "INT64"; + case kTfLiteUInt64: + return "UINT64"; + case kTfLiteBool: + return "BOOL"; + case kTfLiteComplex64: + return "COMPLEX64"; + case kTfLiteComplex128: + return "COMPLEX128"; + case kTfLiteString: + return "STRING"; + case kTfLiteFloat16: + return "FLOAT16"; + case kTfLiteFloat64: + return "FLOAT64"; + case kTfLiteResource: + return "RESOURCE"; + case kTfLiteVariant: + return "VARIANT"; + case kTfLiteInt4: + return "INT4"; + } + return "Unknown type"; +} + +TfLiteDelegate TfLiteDelegateCreate() { return TfLiteDelegate{}; } + +struct TfLiteOpaqueDelegateStruct* TfLiteOpaqueDelegateCreate( + const TfLiteOpaqueDelegateBuilder* opaque_delegate_builder) { + if (!opaque_delegate_builder) return nullptr; + + TfLiteDelegate* result = new TfLiteDelegate{}; + result->opaque_delegate_builder = new TfLiteOpaqueDelegateBuilder{}; + *(result->opaque_delegate_builder) = *opaque_delegate_builder; + + return reinterpret_cast(result); +} + +void TfLiteOpaqueDelegateDelete( + const struct TfLiteOpaqueDelegateStruct* opaque_delegate) { + if (!opaque_delegate) return; + + const TfLiteDelegate* tflite_delegate = + reinterpret_cast(opaque_delegate); + delete tflite_delegate->opaque_delegate_builder; + delete tflite_delegate; +} + +} // extern "C" diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/common.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/common.h new file mode 100644 index 000000000..08909ab08 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/c/common.h @@ -0,0 +1,1110 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 file defines common C types and APIs for implementing operations, +// delegates and other constructs in TensorFlow Lite. The actual operations and +// delegates can be defined using C++, but the interface between the interpreter +// and the operations are C. +// +// Summary of abstractions +// TF_LITE_ENSURE - Self-sufficient error checking +// TfLiteStatus - Status reporting +// TfLiteIntArray - stores tensor shapes (dims), +// TfLiteContext - allows an op to access the tensors +// TfLiteTensor - tensor (a multidimensional array) +// TfLiteNode - a single node or operation +// TfLiteRegistration - the implementation of a conceptual operation. +// TfLiteDelegate - allows delegation of nodes to alternative backends. +// +// Some abstractions in this file are created and managed by Interpreter. +// +// NOTE: The order of values in these structs are "semi-ABI stable". New values +// should be added only to the end of structs and never reordered. + +#ifndef TENSORFLOW_LITE_C_COMMON_H_ +#define TENSORFLOW_LITE_C_COMMON_H_ + +#include +#include +#include + +#include "tensorflow/lite/c/c_api_types.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// The list of external context types known to TF Lite. This list exists solely +// to avoid conflicts and to ensure ops can share the external contexts they +// need. Access to the external contexts is controlled by one of the +// corresponding support files. +typedef enum TfLiteExternalContextType { + kTfLiteEigenContext = 0, // include eigen_support.h to use. + kTfLiteGemmLowpContext = 1, // include gemm_support.h to use. + kTfLiteEdgeTpuContext = 2, // Placeholder for Edge TPU support. + kTfLiteCpuBackendContext = 3, // include cpu_backend_context.h to use. + kTfLiteMaxExternalContexts = 4 +} TfLiteExternalContextType; + +// Forward declare so dependent structs and methods can reference these types +// prior to the struct definitions. +struct TfLiteContext; +struct TfLiteDelegate; +struct TfLiteRegistration; +struct TfLiteOpaqueDelegateStruct; +struct TfLiteOpaqueDelegateBuilder; + +// An external context is a collection of information unrelated to the TF Lite +// framework, but useful to a subset of the ops. TF Lite knows very little +// about the actual contexts, but it keeps a list of them, and is able to +// refresh them if configurations like the number of recommended threads +// change. +typedef struct TfLiteExternalContext { + TfLiteExternalContextType type; + TfLiteStatus (*Refresh)(struct TfLiteContext* context); +} TfLiteExternalContext; + +#define kTfLiteOptionalTensor (-1) + +// Fixed size list of integers. Used for dimensions and inputs/outputs tensor +// indices +typedef struct TfLiteIntArray { + int size; + +#if defined(_MSC_VER) + // Context for why this is needed is in http://b/189926408#comment21 + int data[1]; +#elif (!defined(__clang__) && defined(__GNUC__) && __GNUC__ == 6 && \ + __GNUC_MINOR__ >= 1) || \ + defined(HEXAGON) || \ + (defined(__clang__) && __clang_major__ == 7 && __clang_minor__ == 1) + // gcc 6.1+ have a bug where flexible members aren't properly handled + // https://github.com/google/re2/commit/b94b7cd42e9f02673cd748c1ac1d16db4052514c + int data[0]; +#else + int data[]; +#endif +} TfLiteIntArray; + +// Given the size (number of elements) in a TfLiteIntArray, calculate its size +// in bytes. +size_t TfLiteIntArrayGetSizeInBytes(int size); + +#ifndef ARDUINO +// Create a array of a given `size` (uninitialized entries). +// This returns a pointer, that you must free using TfLiteIntArrayFree(). +TfLiteIntArray* TfLiteIntArrayCreate(int size); +#endif + +// Check if two intarrays are equal. Returns 1 if they are equal, 0 otherwise. +int TfLiteIntArrayEqual(const TfLiteIntArray* a, const TfLiteIntArray* b); + +// Check if an intarray equals an array. Returns 1 if equals, 0 otherwise. +int TfLiteIntArrayEqualsArray(const TfLiteIntArray* a, int b_size, + const int b_data[]); + +#ifndef ARDUINO +// Create a copy of an array passed as `src`. +// You are expected to free memory with TfLiteIntArrayFree +TfLiteIntArray* TfLiteIntArrayCopy(const TfLiteIntArray* src); + +// Free memory of array `a`. +void TfLiteIntArrayFree(TfLiteIntArray* a); +#endif // ARDUINO + +// Fixed size list of floats. Used for per-channel quantization. +typedef struct TfLiteFloatArray { + int size; +#if defined(_MSC_VER) + // Context for why this is needed is in http://b/189926408#comment21 + float data[1]; +#elif (!defined(__clang__) && defined(__GNUC__) && __GNUC__ == 6 && \ + __GNUC_MINOR__ >= 1) || \ + defined(HEXAGON) || \ + (defined(__clang__) && __clang_major__ == 7 && __clang_minor__ == 1) + // gcc 6.1+ have a bug where flexible members aren't properly handled + // https://github.com/google/re2/commit/b94b7cd42e9f02673cd748c1ac1d16db4052514c + float data[0]; +#else + float data[]; +#endif +} TfLiteFloatArray; + +// Given the size (number of elements) in a TfLiteFloatArray, calculate its size +// in bytes. +int TfLiteFloatArrayGetSizeInBytes(int size); + +#ifndef ARDUINO +// Create a array of a given `size` (uninitialized entries). +// This returns a pointer, that you must free using TfLiteFloatArrayFree(). +TfLiteFloatArray* TfLiteFloatArrayCreate(int size); + +// Free memory of array `a`. +void TfLiteFloatArrayFree(TfLiteFloatArray* a); +#endif // ARDUINO + +// Since we must not depend on any libraries, define a minimal subset of +// error macros while avoiding names that have pre-conceived meanings like +// assert and check. + +// Try to make all reporting calls through TF_LITE_KERNEL_LOG rather than +// calling the context->ReportError function directly, so that message strings +// can be stripped out if the binary size needs to be severely optimized. +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#define TF_LITE_KERNEL_LOG(context, ...) \ + do { \ + (context)->ReportError((context), __VA_ARGS__); \ + } while (false) + +#define TF_LITE_MAYBE_KERNEL_LOG(context, ...) \ + do { \ + if ((context) != nullptr) { \ + (context)->ReportError((context), __VA_ARGS__); \ + } \ + } while (false) +#else // TF_LITE_STRIP_ERROR_STRINGS +#define ARGS_UNUSED(...) (void)sizeof(#__VA_ARGS__) +#define TF_LITE_KERNEL_LOG(context, ...) ARGS_UNUSED(__VA_ARGS__) +#define TF_LITE_MAYBE_KERNEL_LOG(context, ...) ARGS_UNUSED(__VA_ARGS__) +#endif // TF_LITE_STRIP_ERROR_STRINGS + +// Check whether value is true, and if not return kTfLiteError from +// the current function (and report the error string msg). +#define TF_LITE_ENSURE_MSG(context, value, msg) \ + do { \ + if (!(value)) { \ + TF_LITE_KERNEL_LOG((context), __FILE__ " " msg); \ + return kTfLiteError; \ + } \ + } while (0) + +// Check whether the value `a` is true, and if not return kTfLiteError from +// the current function, while also reporting the location of the error. +#define TF_LITE_ENSURE(context, a) \ + do { \ + if (!(a)) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s was not true.", __FILE__, \ + __LINE__, #a); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_STATUS(a) \ + do { \ + const TfLiteStatus s = (a); \ + if (s != kTfLiteOk) { \ + return s; \ + } \ + } while (0) + +// Check whether the value `a == b` is true, and if not return kTfLiteError from +// the current function, while also reporting the location of the error. +// `a` and `b` may be evaluated more than once, so no side effects or +// extremely expensive computations should be done. +// NOTE: Use TF_LITE_ENSURE_TYPES_EQ if comparing TfLiteTypes. +#define TF_LITE_ENSURE_EQ(context, a, b) \ + do { \ + if ((a) != (b)) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s != %s (%d != %d)", __FILE__, \ + __LINE__, #a, #b, (a), (b)); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_TYPES_EQ(context, a, b) \ + do { \ + if ((a) != (b)) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s != %s (%s != %s)", __FILE__, \ + __LINE__, #a, #b, TfLiteTypeGetName(a), \ + TfLiteTypeGetName(b)); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_NEAR(context, a, b, epsilon) \ + do { \ + auto delta = ((a) > (b)) ? ((a) - (b)) : ((b) - (a)); \ + if (delta > epsilon) { \ + TF_LITE_KERNEL_LOG((context), "%s:%d %s not near %s (%f != %f)", \ + __FILE__, __LINE__, #a, #b, static_cast(a), \ + static_cast(b)); \ + return kTfLiteError; \ + } \ + } while (0) + +#define TF_LITE_ENSURE_OK(context, status) \ + do { \ + const TfLiteStatus s = (status); \ + if ((s) != kTfLiteOk) { \ + return s; \ + } \ + } while (0) + +// Single-precision complex data type compatible with the C99 definition. +typedef struct TfLiteComplex64 { + float re, im; // real and imaginary parts, respectively. +} TfLiteComplex64; + +// Double-precision complex data type compatible with the C99 definition. +typedef struct TfLiteComplex128 { + double re, im; // real and imaginary parts, respectively. +} TfLiteComplex128; + +// Half precision data type compatible with the C99 definition. +typedef struct TfLiteFloat16 { + uint16_t data; +} TfLiteFloat16; + +// Return the name of a given type, for error reporting purposes. +const char* TfLiteTypeGetName(TfLiteType type); + +// SupportedQuantizationTypes. +typedef enum TfLiteQuantizationType { + // No quantization. + kTfLiteNoQuantization = 0, + // Affine quantization (with support for per-channel quantization). + // Corresponds to TfLiteAffineQuantization. + kTfLiteAffineQuantization = 1, +} TfLiteQuantizationType; + +// Structure specifying the quantization used by the tensor, if-any. +typedef struct TfLiteQuantization { + // The type of quantization held by params. + TfLiteQuantizationType type; + // Holds an optional reference to a quantization param structure. The actual + // type depends on the value of the `type` field (see the comment there for + // the values and corresponding types). + void* params; +} TfLiteQuantization; + +// Parameters for asymmetric quantization across a dimension (i.e per output +// channel quantization). +// quantized_dimension specifies which dimension the scales and zero_points +// correspond to. +// For a particular value in quantized_dimension, quantized values can be +// converted back to float using: +// real_value = scale * (quantized_value - zero_point) +typedef struct TfLiteAffineQuantization { + TfLiteFloatArray* scale; + TfLiteIntArray* zero_point; + int32_t quantized_dimension; +} TfLiteAffineQuantization; + +/* A union of pointers that points to memory for a given tensor. */ +typedef union TfLitePtrUnion { + /* Do not access these members directly, if possible, use + * GetTensorData(tensor) instead, otherwise only access .data, as other + * members are deprecated. */ + int32_t* i32; + uint32_t* u32; + int64_t* i64; + uint64_t* u64; + float* f; + TfLiteFloat16* f16; + double* f64; + char* raw; + const char* raw_const; + uint8_t* uint8; + bool* b; + int16_t* i16; + uint16_t* ui16; + TfLiteComplex64* c64; + TfLiteComplex128* c128; + int8_t* int8; + /* Only use this member. */ + void* data; +} TfLitePtrUnion; + +// Memory allocation strategies. +// * kTfLiteMmapRo: Read-only memory-mapped data, or data externally allocated. +// * kTfLiteArenaRw: Arena allocated with no guarantees about persistence, +// and available during eval. +// * kTfLiteArenaRwPersistent: Arena allocated but persistent across eval, and +// only available during eval. +// * kTfLiteDynamic: Allocated during eval, or for string tensors. +// * kTfLitePersistentRo: Allocated and populated during prepare. This is +// useful for tensors that can be computed during prepare and treated +// as constant inputs for downstream ops (also in prepare). +// * kTfLiteCustom: Custom memory allocation provided by the user. See +// TfLiteCustomAllocation below. +typedef enum TfLiteAllocationType { + kTfLiteMemNone = 0, + kTfLiteMmapRo, + kTfLiteArenaRw, + kTfLiteArenaRwPersistent, + kTfLiteDynamic, + kTfLitePersistentRo, + kTfLiteCustom, +} TfLiteAllocationType; + +// The delegates should use zero or positive integers to represent handles. +// -1 is reserved from unallocated status. +typedef int TfLiteBufferHandle; +enum { + kTfLiteNullBufferHandle = -1, +}; + +// Storage format of each dimension in a sparse tensor. +typedef enum TfLiteDimensionType { + kTfLiteDimDense = 0, + kTfLiteDimSparseCSR, +} TfLiteDimensionType; + +// Metadata to encode each dimension in a sparse tensor. +typedef struct TfLiteDimensionMetadata { + TfLiteDimensionType format; + int dense_size; + TfLiteIntArray* array_segments; + TfLiteIntArray* array_indices; +} TfLiteDimensionMetadata; + +// Parameters used to encode a sparse tensor. For detailed explanation of each +// field please refer to lite/schema/schema.fbs. +typedef struct TfLiteSparsity { + TfLiteIntArray* traversal_order; + TfLiteIntArray* block_map; + TfLiteDimensionMetadata* dim_metadata; + int dim_metadata_size; +} TfLiteSparsity; + +// Defines a custom memory allocation not owned by the runtime. +// `data` should be aligned to kDefaultTensorAlignment defined in +// lite/util.h. (Currently 64 bytes) +// NOTE: See Interpreter.SetCustomAllocationForTensor for details on usage. +typedef struct TfLiteCustomAllocation { + void* data; + size_t bytes; +} TfLiteCustomAllocation; + +// The flags used in `Interpreter::SetCustomAllocationForTensor`. +// Note that this is a bitmask, so the values should be 1, 2, 4, 8, ...etc. +typedef enum TfLiteCustomAllocationFlags { + kTfLiteCustomAllocationFlagsNone = 0, + // Skips checking whether allocation.data points to an aligned buffer as + // expected by the TFLite runtime. + // NOTE: Setting this flag can cause crashes when calling Invoke(). + // Use with caution. + kTfLiteCustomAllocationFlagsSkipAlignCheck = 1, +} TfLiteCustomAllocationFlags; + +// A tensor in the interpreter system which is a wrapper around a buffer of +// data including a dimensionality (or NULL if not currently defined). +#ifndef ARDUINO +typedef struct TfLiteTensor { + // The data type specification for data stored in `data`. This affects + // what member of `data` union should be used. + TfLiteType type; + // A union of data pointers. The appropriate type should be used for a typed + // tensor based on `type`. + TfLitePtrUnion data; + // A pointer to a structure representing the dimensionality interpretation + // that the buffer should have. NOTE: the product of elements of `dims` + // and the element datatype size should be equal to `bytes` below. + TfLiteIntArray* dims; + // Quantization information. + TfLiteQuantizationParams params; + // How memory is mapped + // kTfLiteMmapRo: Memory mapped read only. + // i.e. weights + // kTfLiteArenaRw: Arena allocated read write memory + // (i.e. temporaries, outputs). + TfLiteAllocationType allocation_type; + // The number of bytes required to store the data of this Tensor. I.e. + // (bytes of each element) * dims[0] * ... * dims[n-1]. For example, if + // type is kTfLiteFloat32 and dims = {3, 2} then + // bytes = sizeof(float) * 3 * 2 = 4 * 3 * 2 = 24. + size_t bytes; + + // An opaque pointer to a tflite::MMapAllocation + const void* allocation; + + // Null-terminated name of this tensor. + const char* name; + + // The delegate which knows how to handle `buffer_handle`. + // WARNING: This is an experimental interface that is subject to change. + struct TfLiteDelegate* delegate; + + // An integer buffer handle that can be handled by `delegate`. + // The value is valid only when delegate is not null. + // WARNING: This is an experimental interface that is subject to change. + TfLiteBufferHandle buffer_handle; + + // If the delegate uses its own buffer (e.g. GPU memory), the delegate is + // responsible to set data_is_stale to true. + // `delegate->CopyFromBufferHandle` can be called to copy the data from + // delegate buffer. + // WARNING: This is an // experimental interface that is subject to change. + bool data_is_stale; + + // True if the tensor is a variable. + bool is_variable; + + // Quantization information. Replaces params field above. + TfLiteQuantization quantization; + + // Parameters used to encode a sparse tensor. + // This is optional. The field is NULL if a tensor is dense. + // WARNING: This is an experimental interface that is subject to change. + TfLiteSparsity* sparsity; + + // Optional. Encodes shapes with unknown dimensions with -1. This field is + // only populated when unknown dimensions exist in a read-write tensor (i.e. + // an input or output tensor). (e.g. `dims` contains [1, 1, 1, 3] and + // `dims_signature` contains [1, -1, -1, 3]). Note that this field only + // exists when TF_LITE_STATIC_MEMORY is not defined. + const TfLiteIntArray* dims_signature; +} TfLiteTensor; + +// A structure representing an instance of a node. +// This structure only exhibits the inputs, outputs, user defined data and some +// node properties (like statefulness), not other features like the type. +typedef struct TfLiteNode { + // Inputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* inputs; + + // Outputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* outputs; + + // intermediate tensors to this node expressed as indices into the simulator's + // tensors. + TfLiteIntArray* intermediates; + + // Temporary tensors uses during the computations. This usually contains no + // tensors, but ops are allowed to change that if they need scratch space of + // any sort. + TfLiteIntArray* temporaries; + + // Opaque data provided by the node implementer through `Registration.init`. + void* user_data; + + // Opaque data provided to the node if the node is a builtin. This is usually + // a structure defined in builtin_op_data.h + void* builtin_data; + + // Custom initial data. This is the opaque data provided in the flatbuffer. + // WARNING: This is an experimental interface that is subject to change. + const void* custom_initial_data; + int custom_initial_data_size; + + // The pointer to the delegate. This is non-null only when the node is + // created by calling `interpreter.ModifyGraphWithDelegate`. + // WARNING: This is an experimental interface that is subject to change. + struct TfLiteDelegate* delegate; + + // Whether this op might have side effect (e.g. stateful op). + bool might_have_side_effect; +} TfLiteNode; +#else // defined(ARDUINO)? +// NOTE: This flag is opt-in only at compile time. +// +// Specific reduced TfLiteTensor struct for TF Micro runtime. This struct +// contains only the minimum fields required to initialize and prepare a micro +// inference graph. The fields in this struct have been ordered from +// largest-to-smallest for optimal struct sizeof. +// +// This struct does not use: +// - allocation +// - buffer_handle +// - data_is_stale +// - delegate +// - dims_signature +// - name +// - sparsity +typedef struct TfLiteTensor { + // TODO(b/155784997): Consider consolidating these quantization fields: + // Quantization information. Replaces params field above. + TfLiteQuantization quantization; + + // Quantization information. + TfLiteQuantizationParams params; + + // A union of data pointers. The appropriate type should be used for a typed + // tensor based on `type`. + TfLitePtrUnion data; + + // A pointer to a structure representing the dimensionality interpretation + // that the buffer should have. NOTE: the product of elements of `dims` + // and the element datatype size should be equal to `bytes` below. + TfLiteIntArray* dims; + + // The number of bytes required to store the data of this Tensor. I.e. + // (bytes of each element) * dims[0] * ... * dims[n-1]. For example, if + // type is kTfLiteFloat32 and dims = {3, 2} then + // bytes = sizeof(float) * 3 * 2 = 4 * 3 * 2 = 24. + size_t bytes; + + // The data type specification for data stored in `data`. This affects + // what member of `data` union should be used. + TfLiteType type; + + // How memory is mapped + // kTfLiteMmapRo: Memory mapped read only. + // i.e. weights + // kTfLiteArenaRw: Arena allocated read write memory + // (i.e. temporaries, outputs). + TfLiteAllocationType allocation_type; + + // True if the tensor is a variable. + bool is_variable; +} TfLiteTensor; + +// Specific reduced TfLiteNode struct for TF Micro runtime. This struct contains +// only the minimum fields required to represent a node. +// +// This struct does not use: +// - delegate +// - intermediates +// - temporaries +typedef struct TfLiteNode { + // Inputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* inputs; + + // Outputs to this node expressed as indices into the simulator's tensors. + TfLiteIntArray* outputs; + + // intermediate tensors to this node expressed as indices into the simulator's + // tensors. + TfLiteIntArray* intermediates; + + // Opaque data provided by the node implementer through `Registration.init`. + void* user_data; + + // Opaque data provided to the node if the node is a builtin. This is usually + // a structure defined in builtin_op_data.h + void* builtin_data; + + // Custom initial data. This is the opaque data provided in the flatbuffer. + // WARNING: This is an experimental interface that is subject to change. + const void* custom_initial_data; + int custom_initial_data_size; +} TfLiteNode; +#endif // ARDUINO + +// Light-weight tensor struct for TF Micro runtime. Provides the minimal amount +// of information required for a kernel to run during TfLiteRegistration::Eval. +// TODO(b/160955687): Move this field into TF_LITE_STATIC_MEMORY when TFLM +// builds with this flag by default internally. +typedef struct TfLiteEvalTensor { + // A union of data pointers. The appropriate type should be used for a typed + // tensor based on `type`. + TfLitePtrUnion data; + + // A pointer to a structure representing the dimensionality interpretation + // that the buffer should have. + TfLiteIntArray* dims; + + // The data type specification for data stored in `data`. This affects + // what member of `data` union should be used. + TfLiteType type; +} TfLiteEvalTensor; + +#ifndef ARDUINO +// Free data memory of tensor `t`. +void TfLiteTensorDataFree(TfLiteTensor* t); + +// Free quantization data. +void TfLiteQuantizationFree(TfLiteQuantization* quantization); + +// Free sparsity parameters. +void TfLiteSparsityFree(TfLiteSparsity* sparsity); + +// Free memory of tensor `t`. +void TfLiteTensorFree(TfLiteTensor* t); + +// Set all of a tensor's fields (and free any previously allocated data). +void TfLiteTensorReset(TfLiteType type, const char* name, TfLiteIntArray* dims, + TfLiteQuantizationParams quantization, char* buffer, + size_t size, TfLiteAllocationType allocation_type, + const void* allocation, bool is_variable, + TfLiteTensor* tensor); + +// Copies the contents of 'src' in 'dst'. +// Function does nothing if either 'src' or 'dst' is passed as nullptr and +// return kTfLiteOk. +// Returns kTfLiteError if 'src' and 'dst' doesn't have matching data size. +// Note function copies contents, so it won't create new data pointer +// or change allocation type. +// All Tensor related properties will be copied from 'src' to 'dst' like +// quantization, sparsity, ... +TfLiteStatus TfLiteTensorCopy(const TfLiteTensor* src, TfLiteTensor* dst); + +// Change the size of the memory block owned by `tensor` to `num_bytes`. +// Tensors with allocation types other than kTfLiteDynamic will be ignored. +// `tensor`'s internal data buffer will be assigned a pointer +// which can safely be passed to free or realloc if `num_bytes` is zero. +// Behaviour is undefined if `tensor` is NULL. +// If `preserve_data` is true, tensor data will be unchanged in the range from +// the start of the region up to the minimum of the old and new sizes. +void TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor, + bool preserve_data); + +// Change the size of the memory block owned by `tensor` to `num_bytes`. +// Tensors with allocation types other than kTfLiteDynamic will be ignored. +// `tensor`'s internal data buffer will be assigned a pointer +// which can safely be passed to free or realloc if `num_bytes` is zero. +// Behaviour is undefined if `tensor` is NULL. +// Tensor data will be unchanged in the range from the start of the region up to +// the minimum of the old and new sizes. +void TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor); +#endif // ARDUINO + +// WARNING: This is an experimental interface that is subject to change. +// +// Currently, TfLiteDelegateParams has to be allocated in a way that it's +// trivially destructable. It will be stored as `builtin_data` field in +// `TfLiteNode` of the delegate node. +// +// See also the `CreateDelegateParams` function in `interpreter.cc` details. +typedef struct TfLiteDelegateParams { + struct TfLiteDelegate* delegate; + TfLiteIntArray* nodes_to_replace; + TfLiteIntArray* input_tensors; + TfLiteIntArray* output_tensors; +} TfLiteDelegateParams; + +typedef struct TfLiteContext { + // Number of tensors in the context. + size_t tensors_size; + + // The execution plan contains a list of the node indices in execution + // order. execution_plan->size is the current number of nodes. And, + // execution_plan->data[0] is the first node that needs to be run. + // TfLiteDelegates can traverse the current execution plan by iterating + // through each member of this array and using GetNodeAndRegistration() to + // access details about a node. i.e. + // + // TfLiteIntArray* execution_plan; + // TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &execution_plan)); + // for (int exec_index = 0; exec_index < execution_plan->size; exec_index++) { + // int node_index = execution_plan->data[exec_index]; + // TfLiteNode* node; + // TfLiteRegistration* reg; + // context->GetNodeAndRegistration(context, node_index, &node, ®); + // } + // Note: the memory pointed by '`*execution_plan` is OWNED by TfLite runtime. + // Future calls to GetExecutionPlan invalidates earlier outputs. The following + // code snippet shows the issue of such an invocation pattern. After calling + // CheckNode, subsequent access to `plan_1st` is undefined. + // + // void CheckNode(const TfLiteNode* node) { + // ... + // TfLiteIntArray* plan_2nd; + // TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &plan_2nd)); + // ... + // } + // + // TfLiteIntArray* plan_1st; + // TF_LITE_ENSURE_STATUS(context->GetExecutionPlan(context, &plan_1st)); + // for (int exec_index = 0; exec_index < plan_1st->size; exec_index++) { + // int node_index = plan_1st->data[exec_index]; + // TfLiteNode* node; + // TfLiteRegistration* reg; + // context->GetNodeAndRegistration(context, node_index, &node, ®); + // CheckNode(node); + // } + // + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*GetExecutionPlan)(struct TfLiteContext* context, + TfLiteIntArray** execution_plan); + + // An array of tensors in the interpreter context (of length `tensors_size`) + TfLiteTensor* tensors; + + // opaque full context ptr (an opaque c++ data structure) + void* impl_; + + // Request memory pointer be resized. Updates dimensions on the tensor. + // NOTE: ResizeTensor takes ownership of newSize. + TfLiteStatus (*ResizeTensor)(struct TfLiteContext*, TfLiteTensor* tensor, + TfLiteIntArray* new_size); + // Request that an error be reported with format string msg. + void (*ReportError)(struct TfLiteContext*, const char* msg, ...); + + // Add `tensors_to_add` tensors, preserving pre-existing Tensor entries. If + // non-null, the value pointed to by `first_new_tensor_index` will be set to + // the index of the first new tensor. + TfLiteStatus (*AddTensors)(struct TfLiteContext*, int tensors_to_add, + int* first_new_tensor_index); + + // Get a Tensor node by node_index. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*GetNodeAndRegistration)( + struct TfLiteContext*, int node_index, TfLiteNode** node, + struct TfLiteRegistration** registration); + + // Replace ops with one or more stub delegate operations. This function + // does not take ownership of `nodes_to_replace`. + TfLiteStatus (*ReplaceNodeSubsetsWithDelegateKernels)( + struct TfLiteContext*, struct TfLiteRegistration registration, + const TfLiteIntArray* nodes_to_replace, struct TfLiteDelegate* delegate); + + // Number of threads that are recommended to subsystems like gemmlowp and + // eigen. + int recommended_num_threads; + + // Access external contexts by type. + // WARNING: This is an experimental interface that is subject to change. + TfLiteExternalContext* (*GetExternalContext)(struct TfLiteContext*, + TfLiteExternalContextType); + // Set the value of a external context. Does not take ownership of the + // pointer. + // WARNING: This is an experimental interface that is subject to change. + void (*SetExternalContext)(struct TfLiteContext*, TfLiteExternalContextType, + TfLiteExternalContext*); + + // Flag for allowing float16 precision for FP32 calculation. + // default: false. + // WARNING: This is an experimental API and subject to change. + bool allow_fp32_relax_to_fp16; + + // Pointer to the op-level profiler, if set; nullptr otherwise. + void* profiler; + + // Allocate persistent buffer which has the same life time as the interpreter. + // Returns nullptr on failure. + // The memory is allocated from heap for TFL, and from tail in TFLM. + // This method is only available in Init or Prepare stage. + // WARNING: This is an experimental interface that is subject to change. + void* (*AllocatePersistentBuffer)(struct TfLiteContext* ctx, size_t bytes); + + // Allocate a buffer which will be deallocated right after invoke phase. + // The memory is allocated from heap in TFL, and from volatile arena in TFLM. + // This method is only available in invoke stage. + // NOTE: If possible use RequestScratchBufferInArena method to avoid memory + // allocation during inference time. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*AllocateBufferForEval)(struct TfLiteContext* ctx, size_t bytes, + void** ptr); + + // Request a scratch buffer in the arena through static memory planning. + // This method is only available in Prepare stage and the buffer is allocated + // by the interpreter between Prepare and Eval stage. In Eval stage, + // GetScratchBuffer API can be used to fetch the address. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*RequestScratchBufferInArena)(struct TfLiteContext* ctx, + size_t bytes, int* buffer_idx); + + // Get the scratch buffer pointer. + // This method is only available in Eval stage. + // WARNING: This is an experimental interface that is subject to change. + void* (*GetScratchBuffer)(struct TfLiteContext* ctx, int buffer_idx); + + // Resize the memory pointer of the `tensor`. This method behaves the same as + // `ResizeTensor`, except that it makes a copy of the shape array internally + // so the shape array could be deallocated right afterwards. + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*ResizeTensorExplicit)(struct TfLiteContext* ctx, + TfLiteTensor* tensor, int dims, + const int* shape); + + // This method provides a preview of post-delegation partitioning. Each + // TfLiteDelegateParams in the referenced array corresponds to one instance of + // the delegate kernel. + // Example usage: + // + // TfLiteIntArray* nodes_to_replace = ...; + // TfLiteDelegateParams* params_array; + // int num_partitions = 0; + // TF_LITE_ENSURE_STATUS(context->PreviewDelegatePartitioning( + // context, delegate, nodes_to_replace, ¶ms_array, &num_partitions)); + // for (int idx = 0; idx < num_partitions; idx++) { + // const auto& partition_params = params_array[idx]; + // ... + // } + // + // NOTE: The context owns the memory referenced by partition_params_array. It + // will be cleared with another call to PreviewDelegateParitioning, or after + // TfLiteDelegateParams::Prepare returns. + // + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*PreviewDelegatePartitioning)( + struct TfLiteContext* context, const TfLiteIntArray* nodes_to_replace, + TfLiteDelegateParams** partition_params_array, int* num_partitions); + + // Returns a TfLiteTensor struct for a given index. + // WARNING: This is an experimental interface that is subject to change. + // WARNING: This method may not be available on all platforms. + TfLiteTensor* (*GetTensor)(const struct TfLiteContext* context, + int tensor_idx); + + // Returns a TfLiteEvalTensor struct for a given index. + // WARNING: This is an experimental interface that is subject to change. + // WARNING: This method may not be available on all platforms. + TfLiteEvalTensor* (*GetEvalTensor)(const struct TfLiteContext* context, + int tensor_idx); + + // Retrieves named metadata buffer from the TFLite model. + // Returns kTfLiteOk if metadata is successfully obtained from the flatbuffer + // Model: that is, there exists a `metadata` entry with given `name` string. + // (see TFLite's schema.fbs). + // The corresponding `buffer` information is populated in `ptr` & `bytes`. + // The data from `ptr` is valid for the lifetime of the Interpreter. + // + // WARNING: This is an experimental interface that is subject to change. + TfLiteStatus (*GetModelMetadata)(const struct TfLiteContext* context, + const char* name, const char** ptr, + size_t* bytes); +} TfLiteContext; + +// `TfLiteRegistrationExternal` is an external version of `TfLiteRegistration` +// for C API which doesn't use internal types (such as `TfLiteContext`) but only +// uses stable API types (such as `TfLiteOpaqueContext`). The purpose of each +// field is the exactly the same as with `TfLiteRegistration`. +typedef struct TfLiteRegistrationExternal TfLiteRegistrationExternal; + +typedef struct TfLiteRegistration { + // Initializes the op from serialized data. + // Called only *once* for the lifetime of the op, so any one-time allocations + // should be made here (unless they depend on tensor sizes). + // + // If a built-in op: + // `buffer` is the op's params data (TfLiteLSTMParams*). + // `length` is zero. + // If custom op: + // `buffer` is the op's `custom_options`. + // `length` is the size of the buffer. + // + // Returns a type-punned (i.e. void*) opaque data (e.g. a primitive pointer + // or an instance of a struct). + // + // The returned pointer will be stored with the node in the `user_data` field, + // accessible within prepare and invoke functions below. + // NOTE: if the data is already in the desired format, simply implement this + // function to return `nullptr` and implement the free function to be a no-op. + void* (*init)(TfLiteContext* context, const char* buffer, size_t length); + + // The pointer `buffer` is the data previously returned by an init invocation. + void (*free)(TfLiteContext* context, void* buffer); + + // prepare is called when the inputs this node depends on have been resized. + // context->ResizeTensor() can be called to request output tensors to be + // resized. + // Can be called multiple times for the lifetime of the op. + // + // Returns kTfLiteOk on success. + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node); + + // Execute the node (should read node->inputs and output to node->outputs). + // Returns kTfLiteOk on success. + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node); + + // profiling_string is called during summarization of profiling information + // in order to group executions together. Providing a value here will cause a + // given op to appear multiple times is the profiling report. This is + // particularly useful for custom ops that can perform significantly + // different calculations depending on their `user-data`. + const char* (*profiling_string)(const TfLiteContext* context, + const TfLiteNode* node); + + // Builtin codes. If this kernel refers to a builtin this is the code + // of the builtin. This is so we can do marshaling to other frameworks like + // NN API. + // Note: It is the responsibility of the registration binder to set this + // properly. + int32_t builtin_code; + + // Custom op name. If the op is a builtin, this will be null. + // Note: It is the responsibility of the registration binder to set this + // properly. + // WARNING: This is an experimental interface that is subject to change. + const char* custom_name; + + // The version of the op. + // Note: It is the responsibility of the registration binder to set this + // properly. + int version; + + // The external version of `TfLiteRegistration`. Since we can't use internal + // types (such as `TfLiteContext`) for C API to maintain ABI stability. + // C API user will provide `TfLiteRegistrationExternal` to implement custom + // ops. We keep it inside of `TfLiteRegistration` and use it to route + // callbacks properly. + TfLiteRegistrationExternal* registration_external; +} TfLiteRegistration; + +// Old version of `TfLiteRegistration` to maintain binary backward +// compatibility. +// WARNING: This structure is deprecated / not an official part of the API. +// It should be only used for binary backward compatibility. +typedef struct TfLiteRegistration_V1 { + void* (*init)(TfLiteContext* context, const char* buffer, size_t length); + void (*free)(TfLiteContext* context, void* buffer); + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node); + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node); + const char* (*profiling_string)(const TfLiteContext* context, + const TfLiteNode* node); + int32_t builtin_code; + const char* custom_name; + int version; +} TfLiteRegistration_V1; + +// The flags used in `TfLiteDelegate`. Note that this is a bitmask, so the +// values should be 1, 2, 4, 8, ...etc. +typedef enum TfLiteDelegateFlags { + kTfLiteDelegateFlagsNone = 0, + // The flag is set if the delegate can handle dynamic sized tensors. + // For example, the output shape of a `Resize` op with non-constant shape + // can only be inferred when the op is invoked. + // In this case, the Delegate is responsible for calling + // `SetTensorToDynamic` to mark the tensor as a dynamic tensor, and calling + // `ResizeTensor` when invoking the op. + // + // If the delegate isn't capable to handle dynamic tensors, this flag need + // to be set to false. + kTfLiteDelegateFlagsAllowDynamicTensors = 1, + + // This flag can be used by delegates (that allow dynamic tensors) to ensure + // applicable tensor shapes are automatically propagated in the case of tensor + // resizing. + // This means that non-dynamic (allocation_type != kTfLiteDynamic) I/O tensors + // of a delegate kernel will have correct shapes before its Prepare() method + // is called. The runtime leverages TFLite builtin ops in the original + // execution plan to propagate shapes. + // + // A few points to note: + // 1. This requires kTfLiteDelegateFlagsAllowDynamicTensors. If that flag is + // false, this one is redundant since the delegate kernels are re-initialized + // every time tensors are resized. + // 2. Enabling this flag adds some overhead to AllocateTensors(), since extra + // work is required to prepare the original execution plan. + // 3. This flag requires that the original execution plan only have ops with + // valid registrations (and not 'dummy' custom ops like with Flex). + // WARNING: This feature is experimental and subject to change. + kTfLiteDelegateFlagsRequirePropagatedShapes = 2 +} TfLiteDelegateFlags; + +// WARNING: This is an experimental interface that is subject to change. +typedef struct TfLiteDelegate { + // Data that delegate needs to identify itself. This data is owned by the + // delegate. The delegate is owned in the user code, so the delegate is + // responsible for deallocating this when it is destroyed. + void* data_; + + // Invoked by ModifyGraphWithDelegate. This prepare is called, giving the + // delegate a view of the current graph through TfLiteContext*. It typically + // will look at the nodes and call ReplaceNodeSubsetsWithDelegateKernels() + // to ask the TensorFlow lite runtime to create macro-nodes to represent + // delegated subgraphs of the original graph. + TfLiteStatus (*Prepare)(TfLiteContext* context, + struct TfLiteDelegate* delegate); + + // Copy the data from delegate buffer handle into raw memory of the given + // 'tensor'. Note that the delegate is allowed to allocate the raw bytes as + // long as it follows the rules for kTfLiteDynamic tensors, in which case this + // cannot be null. + TfLiteStatus (*CopyFromBufferHandle)(TfLiteContext* context, + struct TfLiteDelegate* delegate, + TfLiteBufferHandle buffer_handle, + TfLiteTensor* tensor); + + // Copy the data from raw memory of the given 'tensor' to delegate buffer + // handle. This can be null if the delegate doesn't use its own buffer. + TfLiteStatus (*CopyToBufferHandle)(TfLiteContext* context, + struct TfLiteDelegate* delegate, + TfLiteBufferHandle buffer_handle, + TfLiteTensor* tensor); + + // Free the Delegate Buffer Handle. Note: This only frees the handle, but + // this doesn't release the underlying resource (e.g. textures). The + // resources are either owned by application layer or the delegate. + // This can be null if the delegate doesn't use its own buffer. + void (*FreeBufferHandle)(TfLiteContext* context, + struct TfLiteDelegate* delegate, + TfLiteBufferHandle* handle); + + // Bitmask flags. See the comments in `TfLiteDelegateFlags`. + int64_t flags; + + // The opaque delegate builder associated with this object. If set then the + // TF Lite runtime will give precedence to this field. E.g. instead of + // invoking 'Prepare' via the function pointer inside the 'TfLiteDelegate' + // object, the runtime will first check if the corresponding function + // pointer inside 'opaque_delegate_builder' is set and if so invoke that. + // + // If this field is non-null, then the 'Prepare' field (of the + // 'TfLiteDelegate') should be null. + struct TfLiteOpaqueDelegateBuilder* opaque_delegate_builder; +} TfLiteDelegate; + +// Build a 'null' delegate, with all the fields properly set to their default +// values. +TfLiteDelegate TfLiteDelegateCreate(void); + +// `TfLiteOpaqueDelegateBuilder` is used for constructing +// `TfLiteOpaqueDelegateStruct`, see `TfLiteOpaqueDelegateCreate` below. Note: +// This struct is not ABI stable. +// +// For forward source compatibility `TfLiteOpaqueDelegateBuilder` objects should +// be brace-initialized, so that all fields (including any that might be added +// in the future) get zero-initialized. The purpose of each field is exactly +// the same as with `TfLiteDelegate`. +// +// WARNING: This is an experimental interface that is subject to change. +typedef struct TfLiteOpaqueDelegateBuilder { + // Data that delegate needs to identify itself. This data is owned by the + // delegate. The delegate is owned in the user code, so the delegate is + // responsible for deallocating this when it is destroyed. + void* data; + // Invoked by ModifyGraphWithDelegate. This prepare is called, giving the + // delegate a view of the current graph through TfLiteContext*. It typically + // will look at the nodes and call ReplaceNodeSubsetsWithDelegateKernels() + // to ask the TensorFlow lite runtime to create macro-nodes to represent + // delegated subgraphs of the original graph. + TfLiteStatus (*Prepare)(TfLiteOpaqueContext* context, // NOLINT + struct TfLiteOpaqueDelegateStruct* delegate, + void* data); + // Copies the data from delegate buffer handle into raw memory of the given + // 'tensor'. Note that the delegate is allowed to allocate the raw bytes as + // long as it follows the rules for kTfLiteDynamic tensors, in which case this + // cannot be null. + TfLiteStatus (*CopyFromBufferHandle)( // NOLINT + TfLiteOpaqueContext* context, struct TfLiteOpaqueDelegateStruct* delegate, + void* data, TfLiteBufferHandle buffer_handle, TfLiteOpaqueTensor* tensor); + // Copies the data from raw memory of the given 'tensor' to delegate buffer + // handle. This can be null if the delegate doesn't use its own buffer. + TfLiteStatus (*CopyToBufferHandle)( // NOLINT + TfLiteOpaqueContext* context, struct TfLiteOpaqueDelegateStruct* delegate, + void* data, TfLiteBufferHandle buffer_handle, TfLiteOpaqueTensor* tensor); + // Frees the Delegate Buffer Handle. Note: This only frees the handle, but + // this doesn't release the underlying resource (e.g. textures). The + // resources are either owned by application layer or the delegate. + // This can be null if the delegate doesn't use its own buffer. + void (*FreeBufferHandle)(TfLiteOpaqueContext* context, // NOLINT + struct TfLiteOpaqueDelegateStruct* delegate, + void* data, TfLiteBufferHandle* handle); + // Bitmask flags. See the comments in `TfLiteDelegateFlags`. + int64_t flags; +} TfLiteOpaqueDelegateBuilder; + +// Creates an opaque delegate and returns its address. The opaque delegate will +// behave according to the provided 'opaque_delegate_builder'. The lifetime of +// the fields within the 'opaque_delegate_builder' must outlive any interaction +// between the runtime and the returned 'TfLiteOpaqueDelegateStruct'. The +// returned address should be passed to 'TfLiteOpaqueDelegateDelete' for +// deletion. If 'opaque_delegate_builder' is a null pointer, then a null +// pointer will be returned. +struct TfLiteOpaqueDelegateStruct* TfLiteOpaqueDelegateCreate( + const TfLiteOpaqueDelegateBuilder* opaque_delegate_builder); + +// Deletes the provided opaque 'delegate'. This function has no effect if the +// 'delegate' is a null pointer. +void TfLiteOpaqueDelegateDelete( + const struct TfLiteOpaqueDelegateStruct* delegate); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif // TENSORFLOW_LITE_C_COMMON_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/context_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/context_util.h new file mode 100644 index 000000000..ed42cc736 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/context_util.h @@ -0,0 +1,53 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 +/// This provides a few C++ helpers that are useful for manipulating C +/// structures in C++. +#ifndef TENSORFLOW_LITE_CONTEXT_UTIL_H_ +#define TENSORFLOW_LITE_CONTEXT_UTIL_H_ + +#include + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +/// Provides a range iterable wrapper for TfLiteIntArray* (C lists) that TfLite +/// C api uses. +// Can't use the google array_view, since we can't depend on even +// absl for embedded device reasons. +class TfLiteIntArrayView { + public: + /// Construct a view of a TfLiteIntArray*. Note, `int_array` should be + /// non-null and this view does not take ownership of it. + explicit TfLiteIntArrayView(const TfLiteIntArray* int_array) + : int_array_(int_array) {} + + TfLiteIntArrayView(const TfLiteIntArrayView&) = default; + TfLiteIntArrayView& operator=(const TfLiteIntArrayView& rhs) = default; + + typedef const int* const_iterator; + const_iterator begin() const { return int_array_->data; } + const_iterator end() const { return &int_array_->data[int_array_->size]; } + size_t size() const { return end() - begin(); } + int operator[](size_t pos) const { return int_array_->data[pos]; } + + private: + const TfLiteIntArray* int_array_; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_CONTEXT_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/error_reporter.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/error_reporter.cpp new file mode 100644 index 000000000..7070eaa57 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/error_reporter.cpp @@ -0,0 +1,38 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/core/api/error_reporter.h" +#include + +namespace tflite { + +int ErrorReporter::Report(const char* format, ...) { + va_list args; + va_start(args, format); + int code = Report(format, args); + va_end(args); + return code; +} + +// TODO(aselle): Make the name of ReportError on context the same, so +// we can use the ensure functions w/o a context and w/ a reporter. +int ErrorReporter::ReportError(void*, const char* format, ...) { + va_list args; + va_start(args, format); + int code = Report(format, args); + va_end(args); + return code; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/error_reporter.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/error_reporter.h new file mode 100644 index 000000000..05839a611 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/error_reporter.h @@ -0,0 +1,59 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_CORE_API_ERROR_REPORTER_H_ +#define TENSORFLOW_LITE_CORE_API_ERROR_REPORTER_H_ + +#include + +namespace tflite { + +/// A functor that reports error to supporting system. Invoked similar to +/// printf. +/// +/// Usage: +/// ErrorReporter foo; +/// foo.Report("test %d", 5); +/// or +/// va_list args; +/// foo.Report("test %d", args); // where args is va_list +/// +/// Subclass ErrorReporter to provide another reporting destination. +/// For example, if you have a GUI program, you might redirect to a buffer +/// that drives a GUI error log box. +class ErrorReporter { + public: + virtual ~ErrorReporter() {} + virtual int Report(const char* format, va_list args) = 0; + int Report(const char* format, ...); + int ReportError(void*, const char* format, ...); +}; + +} // namespace tflite + +// You should not make bare calls to the error reporter, instead use the +// TF_LITE_REPORT_ERROR macro, since this allows message strings to be +// stripped when the binary size has to be optimized. If you are looking to +// reduce binary size, define TF_LITE_STRIP_ERROR_STRINGS when compiling and +// every call will be stubbed out, taking no memory. +#ifndef TF_LITE_STRIP_ERROR_STRINGS +#define TF_LITE_REPORT_ERROR(reporter, ...) \ + do { \ + static_cast(reporter)->Report(__VA_ARGS__); \ + } while (false) +#else // TF_LITE_STRIP_ERROR_STRINGS +#define TF_LITE_REPORT_ERROR(reporter, ...) +#endif // TF_LITE_STRIP_ERROR_STRINGS + +#endif // TENSORFLOW_LITE_CORE_API_ERROR_REPORTER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/flatbuffer_conversions.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/flatbuffer_conversions.cpp new file mode 100644 index 000000000..535e4c8a6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/flatbuffer_conversions.cpp @@ -0,0 +1,2472 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/core/api/flatbuffer_conversions.h" + +#include +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +namespace { + +// Utility class for safely allocating POD data. This is useful for avoiding +// leaks in cases where op params are allocated but fail to propagate to the +// parsed op data (e.g., when model parameters are invalid). +class SafeBuiltinDataAllocator { + public: + class BuiltinDataDeleter { + public: + explicit BuiltinDataDeleter(BuiltinDataAllocator* allocator) + : allocator_(allocator) {} + + void operator()(void* data) { allocator_->Deallocate(data); } + + private: + BuiltinDataAllocator* allocator_; + }; + + template + using BuiltinDataPtr = std::unique_ptr; + + explicit SafeBuiltinDataAllocator(BuiltinDataAllocator* allocator) + : allocator_(allocator) {} + + template + BuiltinDataPtr Allocate() { + return BuiltinDataPtr(allocator_->AllocatePOD(), + BuiltinDataDeleter(allocator_)); + } + + private: + BuiltinDataAllocator* allocator_; +}; + +// All the Parse functions take some pointers as params and this function has +// the common DCHECKs to catch if any of those are nullptr. +void CheckParsePointerParams(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + TFLITE_DCHECK(op != nullptr); + TFLITE_DCHECK(error_reporter != nullptr); + TFLITE_DCHECK(allocator != nullptr); + TFLITE_DCHECK(builtin_data != nullptr); +} + +// Copies the contents from the flatbuffer int vector `flatbuffer` into the +// int array `buffer`. `flat_vector` and `buffer` represent the same +// configuration operation for a given operation. +TfLiteStatus FlatBufferIntVectorToArray( + int max_size_of_buffer, const flatbuffers::Vector* flat_vector, + int* buffer, ErrorReporter* error_reporter, const char* op_name) { + if (!flat_vector) { + TF_LITE_REPORT_ERROR(error_reporter, + "Input array not provided for operation '%s'.\n", + op_name); + return kTfLiteError; + } else { + size_t num_dimensions = flat_vector->size(); + if (num_dimensions > max_size_of_buffer / sizeof(int)) { + TF_LITE_REPORT_ERROR( + error_reporter, + "Found too many dimensions in the input array of operation '%s'.\n", + op_name); + return kTfLiteError; + } else { + for (size_t i = 0; i < num_dimensions; ++i) { + buffer[i] = flat_vector->Get(i); + } + } + } + return kTfLiteOk; +} + +// Converts the flatbuffer activation to what is used at runtime. +TfLiteFusedActivation ConvertActivation(ActivationFunctionType activation) { + switch (activation) { + case ActivationFunctionType_NONE: + return kTfLiteActNone; + case ActivationFunctionType_RELU: + return kTfLiteActRelu; + case ActivationFunctionType_RELU_N1_TO_1: + return kTfLiteActReluN1To1; + case ActivationFunctionType_RELU6: + return kTfLiteActRelu6; + case ActivationFunctionType_TANH: + return kTfLiteActTanh; + case ActivationFunctionType_SIGN_BIT: + return kTfLiteActSignBit; + } + return kTfLiteActNone; +} + +// Converts the flatbuffer padding enum to what is used at runtime. +TfLitePadding ConvertPadding(Padding padding) { + switch (padding) { + case Padding_SAME: + return kTfLitePaddingSame; + case Padding_VALID: + return kTfLitePaddingValid; + } + return kTfLitePaddingUnknown; +} + +// Converts the flatbuffer mirror padding enum to what is used at runtime. +TfLiteMirrorPaddingMode ConvertMirrorPadding(MirrorPadMode padding) { + switch (padding) { + case MirrorPadMode_REFLECT: + return kTfLiteMirrorPaddingReflect; + case MirrorPadMode_SYMMETRIC: + return kTfLiteMirrorPaddingSymmetric; + } + return kTfLiteMirrorPaddingUnknown; +} + +#ifndef ARDUINO +TfLiteStatus ParseOpDataTfLite(const Operator* op, BuiltinOperator op_type, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + auto parseLSHProjectionType = [](LSHProjectionType type) { + switch (type) { + case LSHProjectionType_SPARSE: + return kTfLiteLshProjectionSparse; + case LSHProjectionType_DENSE: + return kTfLiteLshProjectionDense; + default: + return kTfLiteLshProjectionUnknown; + } + }; + auto parseCombinerType = [](CombinerType type) { + switch (type) { + case CombinerType_MEAN: + return kTfLiteCombinerTypeMean; + case CombinerType_SQRTN: + return kTfLiteCombinerTypeSqrtn; + case CombinerType_SUM: + default: + return kTfLiteCombinerTypeSum; + } + }; + + SafeBuiltinDataAllocator safe_allocator(allocator); + *builtin_data = nullptr; + switch (op_type) { + case BuiltinOperator_ABS: { + return ParseAbs(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ADD: { + return ParseAdd(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ADD_N: { + return ParseAddN(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ARG_MAX: { + return ParseArgMax(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ARG_MIN: { + return ParseArgMin(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ASSIGN_VARIABLE: { + return ParseAssignVariable(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_AVERAGE_POOL_2D: { + return ParsePool(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_BATCH_MATMUL: { + return ParseBatchMatMul(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_BATCH_TO_SPACE_ND: { + return ParseBatchToSpaceNd(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_BROADCAST_ARGS: { + return ParseBroadcastArgs(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_BROADCAST_TO: { + return ParseBroadcastTo(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_CALL_ONCE: { + return ParseCallOnce(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_CEIL: { + return ParseCeil(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_CONCATENATION: { + return ParseConcatenation(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_CONV_2D: { + return ParseConv2D(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_CUMSUM: { + return ParseCumsum(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_DEPTH_TO_SPACE: { + return ParseDepthToSpace(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_DEPTHWISE_CONV_2D: { + return ParseDepthwiseConv2D(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_DEQUANTIZE: { + return ParseDequantize(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_DIV: { + return ParseDiv(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ELU: { + return ParseElu(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_EXP: { + return ParseExp(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_EXPAND_DIMS: { + return ParseExpandDims(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_FILL: { + return ParseFill(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_FLOOR: { + return ParseFloor(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_FLOOR_DIV: { + return ParseFloorDiv(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_FLOOR_MOD: { + return ParseFloorMod(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_FULLY_CONNECTED: { + return ParseFullyConnected(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_GATHER_ND: { + return ParseGatherNd(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_GREATER: { + return ParseGreater(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_GREATER_EQUAL: { + return ParseGreaterEqual(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_HARD_SWISH: { + return ParseHardSwish(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_L2_NORMALIZATION: { + return ParseL2Normalization(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_L2_POOL_2D: { + return ParsePool(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LEAKY_RELU: { + return ParseLeakyRelu(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LESS: { + return ParseLess(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LESS_EQUAL: { + return ParseLessEqual(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LOG: { + return ParseLog(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LOGICAL_AND: { + return ParseLogicalAnd(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LOGICAL_NOT: { + return ParseLogicalNot(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LOGICAL_OR: { + return ParseLogicalOr(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LOGISTIC: { + return ParseLogistic(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LOG_SOFTMAX: { + return ParseLogSoftmax(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_LSTM: { + return ParseLSTM(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_MAXIMUM: { + return ParseMaximum(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_MAX_POOL_2D: { + return ParsePool(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_MIRROR_PAD: { + return ParseMirrorPad(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_MEAN: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_MINIMUM: { + return ParseMinimum(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_MUL: { + return ParseMul(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_NEG: { + return ParseNeg(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_NOT_EQUAL: { + return ParseNotEqual(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_PACK: { + return ParsePack(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_PAD: { + return ParsePad(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_PADV2: { + return ParsePadV2(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_POW: { + return ParsePow(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_PRELU: { + return ParsePrelu(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_QUANTIZE: { + return ParseQuantize(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_READ_VARIABLE: { + return ParseReadVariable(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_REDUCE_ANY: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_REDUCE_ALL: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_REDUCE_MAX: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_REDUCE_MIN: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_REDUCE_PROD: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_RELU: { + return ParseRelu(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_RELU6: { + return ParseRelu6(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_RESHAPE: { + return ParseReshape(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_RESIZE_BILINEAR: { + return ParseResizeBilinear(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_RESIZE_NEAREST_NEIGHBOR: { + return ParseResizeNearestNeighbor(op, error_reporter, allocator, + builtin_data); + } + + case BuiltinOperator_ROUND: { + return ParseRound(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_RSQRT: { + return ParseRsqrt(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SELECT_V2: { + return ParseSelectV2(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SHAPE: { + return ParseShape(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SIN: { + return ParseSin(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SOFTMAX: { + return ParseSoftmax(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SPACE_TO_BATCH_ND: { + return ParseSpaceToBatchNd(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SPACE_TO_DEPTH: { + return ParseSpaceToDepth(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SPLIT: { + return ParseSplit(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SPLIT_V: { + return ParseSplitV(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SQRT: { + return ParseSqrt(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SQUARE: { + return ParseSquare(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SQUARED_DIFFERENCE: { + return ParseSquaredDifference(op, error_reporter, allocator, + builtin_data); + } + + case BuiltinOperator_SQUEEZE: { + return ParseSqueeze(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_STRIDED_SLICE: { + return ParseStridedSlice(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SUB: { + return ParseSub(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SUM: { + return ParseReducer(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_SVDF: { + return ParseSvdf(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_TANH: { + return ParseTanh(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_TRANSPOSE_CONV: { + return ParseTransposeConv(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_UNPACK: { + return ParseUnpack(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_VAR_HANDLE: { + return ParseVarHandle(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_ZEROS_LIKE: { + return ParseZerosLike(op, error_reporter, allocator, builtin_data); + } + + case BuiltinOperator_CAST: { + return ParseCast(op, error_reporter, allocator, builtin_data); + } + case BuiltinOperator_LSH_PROJECTION: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* lshParams = + op->builtin_options_as_LSHProjectionOptions()) { + params->type = parseLSHProjectionType(lshParams->type()); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* sequence_rnn_params = + op->builtin_options_as_SequenceRNNOptions()) { + params->activation = + ConvertActivation(sequence_rnn_params->fused_activation_function()); + params->time_major = sequence_rnn_params->time_major(); + params->asymmetric_quantize_inputs = + sequence_rnn_params->asymmetric_quantize_inputs(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN: { + auto params = + safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* bidi_sequence_rnn_params = + op->builtin_options_as_BidirectionalSequenceRNNOptions()) { + params->activation = ConvertActivation( + bidi_sequence_rnn_params->fused_activation_function()); + params->time_major = bidi_sequence_rnn_params->time_major(); + params->merge_outputs = bidi_sequence_rnn_params->merge_outputs(); + params->asymmetric_quantize_inputs = + bidi_sequence_rnn_params->asymmetric_quantize_inputs(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_RNN: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* rnn_params = op->builtin_options_as_RNNOptions()) { + params->activation = + ConvertActivation(rnn_params->fused_activation_function()); + params->asymmetric_quantize_inputs = + rnn_params->asymmetric_quantize_inputs(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_EMBEDDING_LOOKUP_SPARSE: { + auto params = + safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* embedding_params = + op->builtin_options_as_EmbeddingLookupSparseOptions()) { + params->combiner = parseCombinerType(embedding_params->combiner()); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + + case BuiltinOperator_HASHTABLE_LOOKUP: + // no-op. + return kTfLiteOk; + + case BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* schema_params = + op->builtin_options_as_LocalResponseNormalizationOptions()) { + params->radius = schema_params->radius(); + params->bias = schema_params->bias(); + params->alpha = schema_params->alpha(); + params->beta = schema_params->beta(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM: { + return ParseUnidirectionalSequenceLSTM(op, error_reporter, allocator, + builtin_data); + } + case BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM: { + auto params = + safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* bidi_lstm_params = + op->builtin_options_as_BidirectionalSequenceLSTMOptions()) { + params->activation = + ConvertActivation(bidi_lstm_params->fused_activation_function()); + params->cell_clip = bidi_lstm_params->cell_clip(); + params->proj_clip = bidi_lstm_params->proj_clip(); + params->merge_outputs = bidi_lstm_params->merge_outputs(); + params->time_major = bidi_lstm_params->time_major(); + params->asymmetric_quantize_inputs = + bidi_lstm_params->asymmetric_quantize_inputs(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_SKIP_GRAM: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* skip_gram_params = + op->builtin_options_as_SkipGramOptions()) { + params->ngram_size = skip_gram_params->ngram_size(); + params->max_skip_size = skip_gram_params->max_skip_size(); + params->include_all_ngrams = skip_gram_params->include_all_ngrams(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + + case BuiltinOperator_GATHER: { + return ParseGather(op, error_reporter, allocator, builtin_data); + } + case BuiltinOperator_SPARSE_TO_DENSE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* sparse_to_dense_params = + op->builtin_options_as_SparseToDenseOptions()) { + params->validate_indices = sparse_to_dense_params->validate_indices(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_DELEGATE: { + TF_LITE_REPORT_ERROR(error_reporter, + "DELEGATE op shouldn't exist in model."); + return kTfLiteError; + } + case BuiltinOperator_FAKE_QUANT: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* schema_params = + op->builtin_options_as_FakeQuantOptions()) { + params->min = schema_params->min(); + params->max = schema_params->max(); + params->num_bits = schema_params->num_bits(); + params->narrow_range = schema_params->narrow_range(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_ONE_HOT: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* schema_params = op->builtin_options_as_OneHotOptions()) { + params->axis = schema_params->axis(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_UNIQUE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + const auto* unique_params = op->builtin_options_as_UniqueOptions(); + if (unique_params != nullptr) { + params->index_out_type = + unique_params->idx_out_type() == tflite::TensorType_INT64 + ? TfLiteType::kTfLiteInt64 + : TfLiteType::kTfLiteInt32; + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_REVERSE_SEQUENCE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* reverse_seq_params = + op->builtin_options_as_ReverseSequenceOptions()) { + params->seq_dim = reverse_seq_params->seq_dim(); + params->batch_dim = reverse_seq_params->batch_dim(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_IF: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* if_params = op->builtin_options_as_IfOptions()) { + params->then_subgraph_index = if_params->then_subgraph_index(); + params->else_subgraph_index = if_params->else_subgraph_index(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_WHILE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* while_params = op->builtin_options_as_WhileOptions()) { + params->cond_subgraph_index = while_params->cond_subgraph_index(); + params->body_subgraph_index = while_params->body_subgraph_index(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_CONV_3D: + case BuiltinOperator_CONV_3D_TRANSPOSE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* conv3d_params = op->builtin_options_as_Conv3DOptions()) { + params->padding = ConvertPadding(conv3d_params->padding()); + params->activation = + ConvertActivation(conv3d_params->fused_activation_function()); + params->stride_depth = conv3d_params->stride_d(); + params->stride_height = conv3d_params->stride_h(); + params->stride_width = conv3d_params->stride_w(); + params->dilation_depth_factor = conv3d_params->dilation_d_factor(); + params->dilation_height_factor = conv3d_params->dilation_h_factor(); + params->dilation_width_factor = conv3d_params->dilation_w_factor(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_HASHTABLE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* hashtable_params = + op->builtin_options_as_HashtableOptions()) { + params->table_id = hashtable_params->table_id(); + TF_LITE_ENSURE_STATUS(ConvertTensorType( + hashtable_params->key_dtype(), ¶ms->key_dtype, error_reporter)); + TF_LITE_ENSURE_STATUS(ConvertTensorType(hashtable_params->value_dtype(), + ¶ms->value_dtype, + error_reporter)); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_MULTINOMIAL: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* multinomial_params = + op->builtin_options_as_RandomOptions()) { + params->seed = multinomial_params->seed(); + params->seed2 = multinomial_params->seed2(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_RANDOM_STANDARD_NORMAL: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* random_std_normal_params = + op->builtin_options_as_RandomOptions()) { + params->seed = random_std_normal_params->seed(); + params->seed2 = random_std_normal_params->seed2(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_BUCKETIZE: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* bucketize_params = + op->builtin_options_as_BucketizeOptions()) { + const flatbuffers::Vector* boundaries = + bucketize_params->boundaries(); + if (boundaries == nullptr) { + TF_LITE_REPORT_ERROR( + error_reporter, + "boundaries array not provided for operation 'bucketize'.\n"); + return kTfLiteError; + } + params->num_boundaries = boundaries->size(); + if (boundaries->data() == nullptr) { + TF_LITE_REPORT_ERROR(error_reporter, + "boundaries.data() returned nullptr for " + "operation 'bucketize'.\n"); + return kTfLiteError; + } + params->boundaries = boundaries->data(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_RANDOM_UNIFORM: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* random_uniform_params = + op->builtin_options_as_RandomOptions()) { + params->seed = random_uniform_params->seed(); + params->seed2 = random_uniform_params->seed2(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + case BuiltinOperator_GELU: { + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* gelu_params = op->builtin_options_as_GeluOptions()) { + params->approximate = gelu_params->approximate(); + } + *builtin_data = params.release(); + return kTfLiteOk; + } + // Below are the ops with no builtin_data structure. + // TODO(aselle): Implement call in BuiltinOptions, but nullptrs are + // ok for now, since there is no call implementation either. + case BuiltinOperator_CALL: + case BuiltinOperator_COMPLEX_ABS: + case BuiltinOperator_CONCAT_EMBEDDINGS: + case BuiltinOperator_COS: + case BuiltinOperator_CUSTOM: + case BuiltinOperator_DENSIFY: + case BuiltinOperator_DYNAMIC_UPDATE_SLICE: + case BuiltinOperator_EMBEDDING_LOOKUP: + case BuiltinOperator_EQUAL: + case BuiltinOperator_HASHTABLE_FIND: + case BuiltinOperator_HASHTABLE_IMPORT: + case BuiltinOperator_HASHTABLE_SIZE: + case BuiltinOperator_IMAG: + case BuiltinOperator_MATRIX_DIAG: + case BuiltinOperator_MATRIX_SET_DIAG: + case BuiltinOperator_NON_MAX_SUPPRESSION_V4: + case BuiltinOperator_NON_MAX_SUPPRESSION_V5: + case BuiltinOperator_RELU_N1_TO_1: + case BuiltinOperator_RELU_0_TO_1: + case BuiltinOperator_SCATTER_ND: + case BuiltinOperator_SELECT: + case BuiltinOperator_SLICE: + case BuiltinOperator_TILE: + case BuiltinOperator_TOPK_V2: + case BuiltinOperator_TRANSPOSE: + case BuiltinOperator_RANGE: + case BuiltinOperator_RANK: + case BuiltinOperator_REAL: + case BuiltinOperator_RFFT2D: + case BuiltinOperator_SEGMENT_SUM: + case BuiltinOperator_REVERSE_V2: + case BuiltinOperator_UNSORTED_SEGMENT_MAX: + case BuiltinOperator_UNSORTED_SEGMENT_MIN: + case BuiltinOperator_UNSORTED_SEGMENT_PROD: + case BuiltinOperator_UNSORTED_SEGMENT_SUM: + case BuiltinOperator_ATAN2: + case BuiltinOperator_SIGN: + case BuiltinOperator_WHERE: + return kTfLiteOk; + case BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES: + return kTfLiteError; + } + return kTfLiteError; +} // NOLINT[readability/fn_size] +#endif // !defined(ARDUINO) +} // namespace + +TfLiteStatus ConvertTensorType(TensorType tensor_type, TfLiteType* type, + ErrorReporter* error_reporter) { + switch (tensor_type) { + case TensorType_FLOAT16: + *type = kTfLiteFloat16; + return kTfLiteOk; + case TensorType_FLOAT32: + *type = kTfLiteFloat32; + return kTfLiteOk; + case TensorType_FLOAT64: + *type = kTfLiteFloat64; + return kTfLiteOk; + case TensorType_INT16: + *type = kTfLiteInt16; + return kTfLiteOk; + case TensorType_UINT16: + *type = kTfLiteUInt16; + return kTfLiteOk; + case TensorType_INT32: + *type = kTfLiteInt32; + return kTfLiteOk; + case TensorType_UINT32: + *type = kTfLiteUInt32; + return kTfLiteOk; + case TensorType_UINT8: + *type = kTfLiteUInt8; + return kTfLiteOk; + case TensorType_INT8: + *type = kTfLiteInt8; + return kTfLiteOk; + case TensorType_INT64: + *type = kTfLiteInt64; + return kTfLiteOk; + case TensorType_UINT64: + *type = kTfLiteUInt64; + return kTfLiteOk; + case TensorType_STRING: + *type = kTfLiteString; + return kTfLiteOk; + case TensorType_BOOL: + *type = kTfLiteBool; + return kTfLiteOk; + case TensorType_COMPLEX64: + *type = kTfLiteComplex64; + return kTfLiteOk; + case TensorType_COMPLEX128: + *type = kTfLiteComplex128; + return kTfLiteOk; + case TensorType_RESOURCE: + *type = kTfLiteResource; + return kTfLiteOk; + case TensorType_VARIANT: + *type = kTfLiteVariant; + return kTfLiteOk; + case TensorType_INT4: + *type = kTfLiteInt4; + return kTfLiteOk; + default: + *type = kTfLiteNoType; + TF_LITE_REPORT_ERROR(error_reporter, + "Unsupported data type %d in tensor\n", tensor_type); + return kTfLiteError; + } +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseAbs(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseAdd(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const AddOptions* schema_params = op->builtin_options_as_AddOptions(); + + if (schema_params != nullptr) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + params->pot_scale_int16 = schema_params->pot_scale_int16(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseAddN(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + return kTfLiteOk; +} + +TfLiteStatus ParseArgMax(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ArgMaxOptions* schema_params = op->builtin_options_as_ArgMaxOptions(); + + if (schema_params != nullptr) { + TF_LITE_ENSURE_STATUS(ConvertTensorType( + schema_params->output_type(), ¶ms->output_type, error_reporter)); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseArgMin(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ArgMinOptions* schema_params = op->builtin_options_as_ArgMinOptions(); + + if (schema_params != nullptr) { + TF_LITE_ENSURE_STATUS(ConvertTensorType( + schema_params->output_type(), ¶ms->output_type, error_reporter)); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseAssignVariable(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseBatchMatMul(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* bmm_params = op->builtin_options_as_BatchMatMulOptions()) { + params->adj_x = bmm_params->adj_x(); + params->adj_y = bmm_params->adj_y(); + params->asymmetric_quantize_inputs = + bmm_params->asymmetric_quantize_inputs(); + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseBatchToSpaceNd(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseBroadcastArgs(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseBroadcastTo(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseCallOnce(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const CallOnceOptions* schema_params = + op->builtin_options_as_CallOnceOptions(); + + if (schema_params != nullptr) { + params->init_subgraph_index = schema_params->init_subgraph_index(); + + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseCast(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* schema_params = op->builtin_options_as_CastOptions()) { + TF_LITE_ENSURE_STATUS(ConvertTensorType( + schema_params->in_data_type(), ¶ms->in_data_type, error_reporter)); + TF_LITE_ENSURE_STATUS(ConvertTensorType(schema_params->out_data_type(), + ¶ms->out_data_type, + error_reporter)); + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseCeil(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseConcatenation(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ConcatenationOptions* schema_params = + op->builtin_options_as_ConcatenationOptions(); + + if (schema_params != nullptr) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + params->axis = schema_params->axis(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseConv2D(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const Conv2DOptions* schema_params = op->builtin_options_as_Conv2DOptions(); + + if (schema_params != nullptr) { + params->padding = ConvertPadding(schema_params->padding()); + params->stride_width = schema_params->stride_w(); + params->stride_height = schema_params->stride_h(); + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + + params->dilation_width_factor = schema_params->dilation_w_factor(); + params->dilation_height_factor = schema_params->dilation_h_factor(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseCumsum(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* cumsum_params = op->builtin_options_as_CumsumOptions()) { + params->exclusive = cumsum_params->exclusive(); + params->reverse = cumsum_params->reverse(); + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseCos(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseDepthToSpace(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const auto* schema_params = op->builtin_options_as_DepthToSpaceOptions(); + if (schema_params != nullptr) { + params->block_size = schema_params->block_size(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseDepthwiseConv2D(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const DepthwiseConv2DOptions* schema_params = + op->builtin_options_as_DepthwiseConv2DOptions(); + + if (schema_params != nullptr) { + params->padding = ConvertPadding(schema_params->padding()); + params->stride_width = schema_params->stride_w(); + params->stride_height = schema_params->stride_h(); + params->depth_multiplier = schema_params->depth_multiplier(); + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + + params->dilation_width_factor = schema_params->dilation_w_factor(); + params->dilation_height_factor = schema_params->dilation_h_factor(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseDequantize(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseDiv(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* schema_params = op->builtin_options_as_DivOptions()) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseElu(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseEqual(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseExp(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseExpandDims(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseFill(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseFloor(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseFloorDiv(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseFloorMod(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseFullyConnected(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const FullyConnectedOptions* schema_params = + op->builtin_options_as_FullyConnectedOptions(); + + if (schema_params != nullptr) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + params->keep_num_dims = schema_params->keep_num_dims(); + params->asymmetric_quantize_inputs = + schema_params->asymmetric_quantize_inputs(); + + switch (schema_params->weights_format()) { + case FullyConnectedOptionsWeightsFormat_DEFAULT: + params->weights_format = kTfLiteFullyConnectedWeightsFormatDefault; + break; + case FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8: + params->weights_format = + kTfLiteFullyConnectedWeightsFormatShuffled4x16Int8; + break; + default: + TF_LITE_REPORT_ERROR(error_reporter, + "Unhandled fully-connected weights format."); + return kTfLiteError; + } + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseGather(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + params->axis = 0; + params->batch_dims = 0; + if (const auto* gather_params = op->builtin_options_as_GatherOptions()) { + params->axis = gather_params->axis(); + params->batch_dims = gather_params->batch_dims(); + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseGatherNd(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseGreater(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseGreaterEqual(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseHardSwish(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseIf(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const IfOptions* schema_params = op->builtin_options_as_IfOptions(); + + if (schema_params != nullptr) { + params->then_subgraph_index = schema_params->then_subgraph_index(); + params->else_subgraph_index = schema_params->else_subgraph_index(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseL2Normalization(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const L2NormOptions* schema_params = op->builtin_options_as_L2NormOptions(); + + if (schema_params != nullptr) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseLeakyRelu(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* leaky_relu_params = + op->builtin_options_as_LeakyReluOptions()) { + params->alpha = leaky_relu_params->alpha(); + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLess(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLessEqual(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLog(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLogicalAnd(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLogicalNot(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLogicalOr(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLogistic(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseLogSoftmax(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseLSTM(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* lstm_params = op->builtin_options_as_LSTMOptions()) { + params->activation = + ConvertActivation(lstm_params->fused_activation_function()); + params->cell_clip = lstm_params->cell_clip(); + params->proj_clip = lstm_params->proj_clip(); + switch (lstm_params->kernel_type()) { + case LSTMKernelType_FULL: + params->kernel_type = kTfLiteLSTMFullKernel; + break; + case LSTMKernelType_BASIC: + params->kernel_type = kTfLiteLSTMBasicKernel; + break; + default: + TF_LITE_REPORT_ERROR(error_reporter, "Unhandled LSTM kernel type: %d", + lstm_params->kernel_type()); + return kTfLiteError; + } + params->asymmetric_quantize_inputs = + lstm_params->asymmetric_quantize_inputs(); + } else { + TF_LITE_REPORT_ERROR(error_reporter, "No valid LSTM builtin options exist"); + return kTfLiteError; + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseMaximum(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseMinimum(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseMirrorPad(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const MirrorPadOptions* schema_params = + op->builtin_options_as_MirrorPadOptions(); + + if (schema_params != nullptr) { + params->mode = ConvertMirrorPadding(schema_params->mode()); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseMul(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const MulOptions* schema_params = op->builtin_options_as_MulOptions(); + + if (schema_params != nullptr) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseNeg(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseNotEqual(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParsePack(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const PackOptions* schema_params = op->builtin_options_as_PackOptions(); + + if (schema_params != nullptr) { + params->values_count = schema_params->values_count(); + params->axis = schema_params->axis(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParsePad(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParsePadV2(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +TfLiteStatus ParsePool(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const Pool2DOptions* schema_params = op->builtin_options_as_Pool2DOptions(); + + if (schema_params != nullptr) { + params->padding = ConvertPadding(schema_params->padding()); + params->stride_width = schema_params->stride_w(); + params->stride_height = schema_params->stride_h(); + params->filter_width = schema_params->filter_width(); + params->filter_height = schema_params->filter_height(); + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParsePow(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParsePrelu(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseQuantize(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseReadVariable(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseReducer(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ReducerOptions* schema_params = op->builtin_options_as_ReducerOptions(); + + if (schema_params != nullptr) { + params->keep_dims = schema_params->keep_dims(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseRelu(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseRelu6(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseReshape(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ReshapeOptions* schema_params = op->builtin_options_as_ReshapeOptions(); + + if (schema_params != nullptr) { + const flatbuffers::Vector* new_shape = schema_params->new_shape(); + if (new_shape != nullptr) { + TF_LITE_ENSURE_STATUS( + FlatBufferIntVectorToArray(sizeof(params->shape), new_shape, + params->shape, error_reporter, "reshape")); + params->num_dimensions = new_shape->size(); + } else { + // TODO(b/157480169) TODO(b/147203660): We should either return + // kTfLiteError or fill in some reasonable defaults in the params struct. + // We are not doing so until we better undertand the ramifications of + // changing the legacy behavior. + } + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseResizeBilinear(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ResizeBilinearOptions* schema_params = + op->builtin_options_as_ResizeBilinearOptions(); + + if (schema_params != nullptr) { + params->align_corners = schema_params->align_corners(); + params->half_pixel_centers = schema_params->half_pixel_centers(); + } else { + params->align_corners = false; + params->half_pixel_centers = false; + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseResizeNearestNeighbor(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ResizeNearestNeighborOptions* schema_params = + op->builtin_options_as_ResizeNearestNeighborOptions(); + + if (schema_params != nullptr) { + params->align_corners = schema_params->align_corners(); + params->half_pixel_centers = schema_params->half_pixel_centers(); + } else { + params->align_corners = false; + params->half_pixel_centers = false; + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseRound(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseRsqrt(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSelectV2(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseShape(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const ShapeOptions* schema_params = op->builtin_options_as_ShapeOptions(); + + if (schema_params != nullptr) { + TF_LITE_ENSURE_STATUS(ConvertTensorType(schema_params->out_type(), + ¶ms->out_type, error_reporter)); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSin(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSlice(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseSoftmax(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const SoftmaxOptions* schema_params = op->builtin_options_as_SoftmaxOptions(); + + if (schema_params != nullptr) { + params->beta = schema_params->beta(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSpaceToBatchNd(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseSpaceToDepth(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const auto* schema_params = op->builtin_options_as_SpaceToDepthOptions(); + if (schema_params != nullptr) { + params->block_size = schema_params->block_size(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseSplit(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const SplitOptions* schema_params = op->builtin_options_as_SplitOptions(); + + if (schema_params != nullptr) { + params->num_splits = schema_params->num_splits(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseSplitV(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const SplitVOptions* schema_params = op->builtin_options_as_SplitVOptions(); + + if (schema_params != nullptr) { + params->num_splits = schema_params->num_splits(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseUnidirectionalSequenceLSTM(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + SafeBuiltinDataAllocator safe_allocator(allocator); + auto params = + safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + if (const auto* seq_lstm_params = + op->builtin_options_as_UnidirectionalSequenceLSTMOptions()) { + params->activation = + ConvertActivation(seq_lstm_params->fused_activation_function()); + params->cell_clip = seq_lstm_params->cell_clip(); + params->proj_clip = seq_lstm_params->proj_clip(); + params->time_major = seq_lstm_params->time_major(); + params->asymmetric_quantize_inputs = + seq_lstm_params->asymmetric_quantize_inputs(); + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseSqueeze(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + SafeBuiltinDataAllocator safe_allocator(allocator); + + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const SqueezeOptions* schema_params = op->builtin_options_as_SqueezeOptions(); + + if (schema_params != nullptr) { + const auto* squeeze_dims = schema_params->squeeze_dims(); + if (squeeze_dims != nullptr) { + TF_LITE_ENSURE_STATUS(FlatBufferIntVectorToArray( + sizeof(params->squeeze_dims), squeeze_dims, params->squeeze_dims, + error_reporter, "squeeze")); + params->num_squeeze_dims = squeeze_dims->size(); + } else { + params->num_squeeze_dims = 0; + } + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSqrt(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSquare(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseSquaredDifference(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseStridedSlice(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const StridedSliceOptions* schema_params = + op->builtin_options_as_StridedSliceOptions(); + + if (schema_params != nullptr) { + params->begin_mask = schema_params->begin_mask(); + params->end_mask = schema_params->end_mask(); + params->ellipsis_mask = schema_params->ellipsis_mask(); + params->new_axis_mask = schema_params->new_axis_mask(); + params->shrink_axis_mask = schema_params->shrink_axis_mask(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseSub(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const SubOptions* schema_params = op->builtin_options_as_SubOptions(); + + if (schema_params != nullptr) { + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + params->pot_scale_int16 = schema_params->pot_scale_int16(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseSvdf(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const SVDFOptions* schema_params = op->builtin_options_as_SVDFOptions(); + if (schema_params != nullptr) { + params->rank = schema_params->rank(); + params->activation = + ConvertActivation(schema_params->fused_activation_function()); + params->asymmetric_quantize_inputs = + schema_params->asymmetric_quantize_inputs(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseTanh(const Operator*, ErrorReporter*, BuiltinDataAllocator*, + void**) { + return kTfLiteOk; +} +// +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseTranspose(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseTransposeConv(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + const TransposeConvOptions* transpose_conv_params = + op->builtin_options_as_TransposeConvOptions(); + if (transpose_conv_params != nullptr) { + params->padding = ConvertPadding(transpose_conv_params->padding()); + params->stride_width = transpose_conv_params->stride_w(); + params->stride_height = transpose_conv_params->stride_h(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseUnpack(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const UnpackOptions* schema_params = op->builtin_options_as_UnpackOptions(); + + if (schema_params != nullptr) { + params->num = schema_params->num(); + params->axis = schema_params->axis(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseVarHandle(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const VarHandleOptions* schema_params = + op->builtin_options_as_VarHandleOptions(); + + if (schema_params != nullptr) { + if (schema_params->container()) { + params->container = schema_params->container()->c_str(); + } + if (schema_params->shared_name()) { + params->shared_name = schema_params->shared_name()->c_str(); + } + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +TfLiteStatus ParseWhile(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { + CheckParsePointerParams(op, error_reporter, allocator, builtin_data); + + SafeBuiltinDataAllocator safe_allocator(allocator); + std::unique_ptr + params = safe_allocator.Allocate(); + TF_LITE_ENSURE(error_reporter, params != nullptr); + + const WhileOptions* schema_params = op->builtin_options_as_WhileOptions(); + + if (schema_params != nullptr) { + params->cond_subgraph_index = schema_params->cond_subgraph_index(); + params->body_subgraph_index = schema_params->body_subgraph_index(); + } else { + // TODO(b/157480169): We should either return kTfLiteError or fill in some + // reasonable defaults in the params struct. We are not doing so until we + // better undertand the ramifications of changing the legacy behavior. + } + + *builtin_data = params.release(); + return kTfLiteOk; +} + +// We have this parse function instead of directly returning kTfLiteOk from the +// switch-case in ParseOpData because this function is used as part of the +// selective registration for the OpResolver implementation in micro. +TfLiteStatus ParseZerosLike(const Operator*, ErrorReporter*, + BuiltinDataAllocator*, void**) { + return kTfLiteOk; +} + +TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data) { +// TODO(b/145762662): It would be preferable to have the build graph for TF Lite +// Micro not have the ParseOpData function at all. This would require splitting +// the current file into two separate files, one of which defines the +// ParseOpData function and the other that defines the operator specific parse +// functions (e.g. ParseAdd). +// +// Such a split was attempted but was not worth the effort at the time because +// of the following reasons: +// * We could either duplicate the functions and the SafeBuiltinDataAllocator +// class in the anonymous namespace of this file, or attempt to make a common +// library with these helper functions and class. +// * Making a common library with a separate build target was not feasible as +// it introduced circular dependencies due to the ErrorReporter and a common +// .cc and .h within the same api build target the also cause circular +// dependencies due to the BuiltinDataAllocator class. +// * If all the builtin operators were to have their own parse functions, or we +// were ok with some amount of code duplication, then this split of the .cc +// files would be a lot more feasible. +#ifdef ARDUINO + TF_LITE_REPORT_ERROR( + error_reporter, + "ParseOpData is unsupported on TfLiteMicro, please use the operator " + "specific parse functions (e.g. ParseAdd etc.).\n"); + return kTfLiteError; +#else + return ParseOpDataTfLite(op, op_type, error_reporter, allocator, + builtin_data); +#endif +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/flatbuffer_conversions.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/flatbuffer_conversions.h new file mode 100644 index 000000000..c7653f01f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/flatbuffer_conversions.h @@ -0,0 +1,412 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_CORE_API_FLATBUFFER_CONVERSIONS_H_ +#define TENSORFLOW_LITE_CORE_API_FLATBUFFER_CONVERSIONS_H_ + +// These functions transform codes and data structures that are defined in the +// flatbuffer serialization format into in-memory values that are used by the +// runtime API and interpreter. + +#include +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// Interface class for builtin data allocations. +class BuiltinDataAllocator { + public: + virtual void* Allocate(size_t size, size_t alignment_hint) = 0; + virtual void Deallocate(void* data) = 0; + + // Allocate a structure, but make sure it is a POD structure that doesn't + // require constructors to run. The reason we do this, is that Interpreter's C + // extension part will take ownership so destructors will not be run during + // deallocation. + template + T* AllocatePOD() { + // TODO(b/154346074): Change this to is_trivially_destructible when all + // platform targets support that properly. + static_assert(std::is_pod::value, "Builtin data structure must be POD."); + void* allocated_memory = this->Allocate(sizeof(T), alignof(T)); + return new (allocated_memory) T(); + } + + virtual ~BuiltinDataAllocator() {} +}; + +// Parse the appropriate data out of the op. +// +// This handles builtin data explicitly as there are flatbuffer schemas. +// If it returns kTfLiteOk, it passes the data out with `builtin_data`. The +// calling function has to pass in an allocator object, and this allocator +// will be called to reserve space for the output data. If the calling +// function's allocator reserves memory on the heap, then it's the calling +// function's responsibility to free it. +// If it returns kTfLiteError, `builtin_data` will be `nullptr`. +TfLiteStatus ParseOpData(const Operator* op, BuiltinOperator op_type, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +// Converts the tensor data type used in the flat buffer to the representation +// used by the runtime. +TfLiteStatus ConvertTensorType(TensorType tensor_type, TfLiteType* type, + ErrorReporter* error_reporter); + +TfLiteStatus ParseAbs(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseAdd(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseAddN(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseArgMax(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseArgMin(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseAssignVariable(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseBatchMatMul(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseBatchToSpaceNd(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseBroadcastArgs(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseBroadcastTo(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseCallOnce(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseCeil(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseCast(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseConcatenation(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseConv2D(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseCos(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseCumsum(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseDepthToSpace(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseDepthwiseConv2D(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseDequantize(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseDiv(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseElu(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseEqual(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseExp(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseExpandDims(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseFill(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseFloor(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseFloorDiv(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseFloorMod(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseFullyConnected(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseGather(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseGatherNd(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseGreater(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseGreaterEqual(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseHardSwish(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseIf(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseL2Normalization(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLeakyRelu(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLess(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseLessEqual(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLog(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseLogicalAnd(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLogicalNot(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLogicalOr(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLogistic(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLogSoftmax(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseLSTM(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseMaximum(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseMinimum(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseMirrorPad(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseMul(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseNeg(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseNotEqual(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParsePack(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParsePad(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParsePadV2(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParsePool(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParsePow(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParsePrelu(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseQuantize(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseReadVariable(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseReducer(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseRelu(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseRelu6(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseReshape(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseResizeBilinear(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseResizeNearestNeighbor(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseRound(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseRsqrt(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSelectV2(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseShape(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSin(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSlice(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSoftmax(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSpaceToBatchNd(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseSpaceToDepth(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseSplit(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSplitV(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSqueeze(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSqrt(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSquare(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSquaredDifference(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseStridedSlice(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseSub(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseSvdf(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseTanh(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseTranspose(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseTransposeConv(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseUnpack(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseUnidirectionalSequenceLSTM(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseVarHandle(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +TfLiteStatus ParseWhile(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, void** builtin_data); + +TfLiteStatus ParseZerosLike(const Operator* op, ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_CORE_API_FLATBUFFER_CONVERSIONS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/op_resolver.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/op_resolver.cpp new file mode 100644 index 000000000..7a48d6624 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/op_resolver.cpp @@ -0,0 +1,68 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/core/api/op_resolver.h" + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/schema/schema_utils.h" + +namespace tflite { + +TfLiteStatus GetRegistrationFromOpCode( + const OperatorCode* opcode, const OpResolver& op_resolver, + ErrorReporter* error_reporter, const TfLiteRegistration** registration) { + TfLiteStatus status = kTfLiteOk; + *registration = nullptr; + auto builtin_code = GetBuiltinCode(opcode); + int version = opcode->version(); + + if (builtin_code > BuiltinOperator_MAX) { + TF_LITE_REPORT_ERROR( + error_reporter, + "Op builtin_code out of range: %d. Are you using old TFLite binary " + "with newer model?", + builtin_code); + status = kTfLiteError; + } else if (builtin_code != BuiltinOperator_CUSTOM) { + *registration = op_resolver.FindOp(builtin_code, version); + if (*registration == nullptr) { + TF_LITE_REPORT_ERROR( + error_reporter, + "Didn't find op for builtin opcode '%s' version '%d'. " + "An older version of this builtin might be supported. " + "Are you using an old TFLite binary with a newer model?\n", + EnumNameBuiltinOperator(builtin_code), version); + status = kTfLiteError; + } + } else if (!opcode->custom_code()) { + TF_LITE_REPORT_ERROR( + error_reporter, + "Operator with CUSTOM builtin_code has no custom_code.\n"); + status = kTfLiteError; + } else { + const char* name = opcode->custom_code()->c_str(); + *registration = op_resolver.FindOp(name, version); + if (*registration == nullptr) { + // Do not report error for unresolved custom op, we do the final check + // while preparing ops. + status = kTfLiteError; + } + } + return status; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/op_resolver.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/op_resolver.h new file mode 100644 index 000000000..cec1f2dd4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/op_resolver.h @@ -0,0 +1,140 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_CORE_API_OP_RESOLVER_H_ +#define TENSORFLOW_LITE_CORE_API_OP_RESOLVER_H_ + +#include +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/schema/schema_generated.h" + +// Opaque type similar to TfLiteDelegate / TfLiteOpaqueDelegate. +// This is used for cases (e.g. when using "TF Lite with Google Play Services") +// where the TF Lite runtime might be built using a newer (or older) +// version of the TF Lite sources than the app, and hence might have a +// different definition of the TfLiteDelegate type. TF Lite APIs use +// TfLiteOpaqueDelegate rather than TfLiteDelegate when they want to +// refer to a delegate defined with that potentially different version +// of the TfLiteDelegate type. +struct TfLiteOpaqueDelegateStruct; + +namespace tflite { + +/// Abstract interface that returns TfLiteRegistrations given op codes or custom +/// op names. This is the mechanism that ops being referenced in the flatbuffer +/// model are mapped to executable function pointers (TfLiteRegistrations). +class OpResolver { + public: + /// Finds the op registration for a builtin operator by enum code. + virtual const TfLiteRegistration* FindOp(tflite::BuiltinOperator op, + int version) const = 0; + /// Finds the op registration of a custom operator by op name. + virtual const TfLiteRegistration* FindOp(const char* op, + int version) const = 0; + + // Represents a sequence of delegates. + using TfLiteDelegatePtrVector = + std::vector>; + + // Returns optional delegates for resolving and handling ops in the flatbuffer + // model. This may be used in addition to the standard TfLiteRegistration + // lookup for graph resolution. + // WARNING: This API is deprecated, GetDelegateCreators is preferred. + virtual TfLiteDelegatePtrVector GetDelegates(int num_threads) const { + return {}; + } + + // Represents a function that creates a TfLite delegate instance. + using TfLiteDelegateCreator = + std::function( + int /*num_threads*/)>; + + // Represents a sequence of delegate creator functions. + using TfLiteDelegateCreators = std::vector; + + // Returns a vector of delegate creators to create optional delegates for + // resolving and handling ops in the flatbuffer model. This may be used in + // addition to the standard TfLiteRegistration lookup for graph resolution. + // + // Note that this method is not used (will not be called) if you are using + // TF Lite in Google Play Services; the GetOpaqueDelegateCreators method + // (see below) is used for that case. + virtual TfLiteDelegateCreators GetDelegateCreators() const { return {}; } + + // TODO(b/202712825): it would be nice if we could avoid the need for separate + // "opaque" types & methods for use only with TF Lite in Google Play Services. + + // Represents an opaque delegate instance. + // WARNING: Experimental interface, subject to change. + using TfLiteOpaqueDelegatePtr = + std::unique_ptr; + + // Represents a function that creates an opaque delegate instance. + // WARNING: Experimental interface, subject to change. + using TfLiteOpaqueDelegateCreator = + std::function; + + // Represents a sequence of opaque delegate creator functions. + // WARNING: Experimental interface, subject to change. + using TfLiteOpaqueDelegateCreators = std::vector; + + // Returns a vector of opaque delegate creators to create optional opaque + // delegates for resolving and handling ops in the flatbuffer model. This may + // be used in addition to the standard TfLiteRegistration lookup for graph + // resolution. + // + // Note that this method will be called only if you are using TF Lite in + // Google Play Services; if you are using regular TF Lite, GetDelegateCreators + // (see above) is used instead. + // + // WARNING: Experimental interface, subject to change. + virtual TfLiteOpaqueDelegateCreators GetOpaqueDelegateCreators() const { + return {}; + } + + virtual ~OpResolver() {} + + private: + /// Returns true if this OpResolver may contain any "user defined" ops. + /// By "user defined" ops, we mean any op definitions other than those + /// contained in tflite::ops::builtin::BuiltinOpResolver. + /// + /// If this method returns true, it doesn't necessarily mean that the + /// OpResolver contains a user-defined op, just that the absence of + /// user-defined ops can't be guaranteed. + /// + /// Note that "user-defined" ops are not the same as "custom" ops; + /// BuiltinOpResolver may support certain "custom" ops, in addition to + /// "builtin" ops, and may not support all of the "builtin" op enum values. + virtual bool MayContainUserDefinedOps() const { return true; } + + friend class OpResolverInternal; +}; + +// Handles the logic for converting between an OperatorCode structure extracted +// from a flatbuffer and information about a registered operator +// implementation. +TfLiteStatus GetRegistrationFromOpCode(const OperatorCode* opcode, + const OpResolver& op_resolver, + ErrorReporter* error_reporter, + const TfLiteRegistration** registration); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_CORE_API_OP_RESOLVER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/tensor_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/tensor_utils.cpp new file mode 100644 index 000000000..3aac16b68 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/tensor_utils.cpp @@ -0,0 +1,50 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/core/api/tensor_utils.h" + +#include + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +TfLiteStatus ResetVariableTensor(TfLiteTensor* tensor) { + if (!tensor->is_variable) { + return kTfLiteOk; + } + // TODO(b/115961645): Implement - If a variable tensor has a buffer, reset it + // to the value of the buffer. + int value = 0; + if (tensor->type == kTfLiteInt8) { + value = tensor->params.zero_point; + } + // TODO(b/139446230): Provide a platform header to better handle these + // specific scenarios. +#if __ANDROID__ || defined(__x86_64__) || defined(__i386__) || \ + defined(__i386) || defined(__x86__) || defined(__X86__) || \ + defined(_X86_) || defined(_M_IX86) || defined(_M_X64) + memset(tensor->data.raw, value, tensor->bytes); +#else + char* raw_ptr = tensor->data.raw; + for (size_t i = 0; i < tensor->bytes; ++i) { + *raw_ptr = value; + raw_ptr++; + } +#endif + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/tensor_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/tensor_utils.h new file mode 100644 index 000000000..9f1cf94a5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/core/api/tensor_utils.h @@ -0,0 +1,28 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_CORE_API_TENSOR_UTILS_H_ +#define TENSORFLOW_LITE_CORE_API_TENSOR_UTILS_H_ + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// Resets a variable tensor to the default value. +TfLiteStatus ResetVariableTensor(TfLiteTensor* tensor); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_CORE_API_TENSOR_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/bits.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/bits.h new file mode 100644 index 000000000..04b3ba6f0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/bits.h @@ -0,0 +1,102 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_BITS_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_BITS_H_ + +#ifdef __cplusplus +#include + +extern "C" { +#endif + +static inline int CountLeadingZeros32Slow(uint64_t n) { + int zeroes = 28; + if (n >> 16) zeroes -= 16, n >>= 16; + if (n >> 8) zeroes -= 8, n >>= 8; + if (n >> 4) zeroes -= 4, n >>= 4; + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes; +} + +static inline int CountLeadingZeros32(uint32_t n) { +#if defined(_MSC_VER) + unsigned long result = 0; // NOLINT(runtime/int) + if (_BitScanReverse(&result, n)) { + return 31 - result; + } + return 32; +#elif defined(__GNUC__) + + // Handle 0 as a special case because __builtin_clz(0) is undefined. + if (n == 0) { + return 32; + } + return __builtin_clz(n); +#else + return CountLeadingZeros32Slow(n); +#endif +} + +static inline int MostSignificantBit32(uint32_t n) { + return 32 - CountLeadingZeros32(n); +} + +static inline int CountLeadingZeros64Slow(uint64_t n) { + int zeroes = 60; + if (n >> 32) zeroes -= 32, n >>= 32; + if (n >> 16) zeroes -= 16, n >>= 16; + if (n >> 8) zeroes -= 8, n >>= 8; + if (n >> 4) zeroes -= 4, n >>= 4; + return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes; +} + +static inline int CountLeadingZeros64(uint64_t n) { +#if defined(_MSC_VER) && defined(_M_X64) + // MSVC does not have __builtin_clzll. Use _BitScanReverse64. + unsigned long result = 0; // NOLINT(runtime/int) + if (_BitScanReverse64(&result, n)) { + return 63 - result; + } + return 64; +#elif defined(_MSC_VER) + // MSVC does not have __builtin_clzll. Compose two calls to _BitScanReverse + unsigned long result = 0; // NOLINT(runtime/int) + if ((n >> 32) && _BitScanReverse(&result, n >> 32)) { + return 31 - result; + } + if (_BitScanReverse(&result, n)) { + return 63 - result; + } + return 64; +#elif defined(__GNUC__) + + // Handle 0 as a special case because __builtin_clzll(0) is undefined. + if (n == 0) { + return 64; + } + return __builtin_clzll(n); +#else + return CountLeadingZeros64Slow(n); +#endif +} + +static inline int MostSignificantBit64(uint64_t n) { + return 64 - CountLeadingZeros64(n); +} + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_BITS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft.cpp new file mode 100644 index 000000000..bcdd9cc0d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft.cpp @@ -0,0 +1,52 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/fft.h" + +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.h" + +void FftCompute(struct FftState* state, const int16_t* input, + int input_scale_shift) { + const size_t input_size = state->input_size; + const size_t fft_size = state->fft_size; + + int16_t* fft_input = state->input; + // First, scale the input by the given shift. + size_t i; + for (i = 0; i < input_size; ++i) { + fft_input[i] = static_cast(static_cast(input[i]) + << input_scale_shift); + } + // Zero out whatever else remains in the top part of the input. + for (; i < fft_size; ++i) { + fft_input[i] = 0; + } + + // Apply the FFT. + kissfft_fixed16::kiss_fftr( + reinterpret_cast(state->scratch), + state->input, + reinterpret_cast(state->output)); +} + +void FftInit(struct FftState* state) { + // All the initialization is done in FftPopulateState() +} + +void FftReset(struct FftState* state) { + memset(state->input, 0, state->fft_size * sizeof(*state->input)); + memset(state->output, 0, (state->fft_size / 2 + 1) * sizeof(*state->output)); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft.h new file mode 100644 index 000000000..aaffa69de --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft.h @@ -0,0 +1,50 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct complex_int16_t { + int16_t real; + int16_t imag; +}; + +struct FftState { + int16_t* input; + struct complex_int16_t* output; + size_t fft_size; + size_t input_size; + void* scratch; + size_t scratch_size; +}; + +void FftCompute(struct FftState* state, const int16_t* input, + int input_scale_shift); + +void FftInit(struct FftState* state); + +void FftReset(struct FftState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft_util.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft_util.cpp new file mode 100644 index 000000000..ed3dc8fbd --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft_util.cpp @@ -0,0 +1,70 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/fft_util.h" + +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.h" + +int FftPopulateState(struct FftState* state, size_t input_size) { + state->input_size = input_size; + state->fft_size = 1; + while (state->fft_size < state->input_size) { + state->fft_size <<= 1; + } + + state->input = reinterpret_cast( + malloc(state->fft_size * sizeof(*state->input))); + if (state->input == nullptr) { + fprintf(stderr, "Failed to alloc fft input buffer\n"); + return 0; + } + + state->output = reinterpret_cast( + malloc((state->fft_size / 2 + 1) * sizeof(*state->output) * 2)); + if (state->output == nullptr) { + fprintf(stderr, "Failed to alloc fft output buffer\n"); + return 0; + } + + // Ask kissfft how much memory it wants. + size_t scratch_size = 0; + kissfft_fixed16::kiss_fftr_cfg kfft_cfg = kissfft_fixed16::kiss_fftr_alloc( + state->fft_size, 0, nullptr, &scratch_size); + if (kfft_cfg != nullptr) { + fprintf(stderr, "Kiss memory sizing failed.\n"); + return 0; + } + state->scratch = malloc(scratch_size); + if (state->scratch == nullptr) { + fprintf(stderr, "Failed to alloc fft scratch buffer\n"); + return 0; + } + state->scratch_size = scratch_size; + // Let kissfft configure the scratch space we just allocated + kfft_cfg = kissfft_fixed16::kiss_fftr_alloc(state->fft_size, 0, + state->scratch, &scratch_size); + if (kfft_cfg != state->scratch) { + fprintf(stderr, "Kiss memory preallocation strategy failed.\n"); + return 0; + } + return 1; +} + +void FftFreeStateContents(struct FftState* state) { + free(state->input); + free(state->output); + free(state->scratch); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft_util.h new file mode 100644 index 000000000..6a471301c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/fft_util.h @@ -0,0 +1,34 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_UTIL_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/fft.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Prepares and FFT for the given input size. +int FftPopulateState(struct FftState* state, size_t input_size); + +// Frees any allocated buffers. +void FftFreeStateContents(struct FftState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank.c new file mode 100644 index 000000000..80f8738f0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank.c @@ -0,0 +1,134 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/filterbank.h" + +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/bits.h" + +void FilterbankConvertFftComplexToEnergy(struct FilterbankState* state, + struct complex_int16_t* fft_output, + int32_t* energy) { + const int end_index = state->end_index; + int i; + energy += state->start_index; + fft_output += state->start_index; + for (i = state->start_index; i < end_index; ++i) { + const int32_t real = fft_output->real; + const int32_t imag = fft_output->imag; + fft_output++; + const uint32_t mag_squared = (real * real) + (imag * imag); + *energy++ = mag_squared; + } +} + +void FilterbankAccumulateChannels(struct FilterbankState* state, + const int32_t* energy) { + uint64_t* work = state->work; + uint64_t weight_accumulator = 0; + uint64_t unweight_accumulator = 0; + + const int16_t* channel_frequency_starts = state->channel_frequency_starts; + const int16_t* channel_weight_starts = state->channel_weight_starts; + const int16_t* channel_widths = state->channel_widths; + + int num_channels_plus_1 = state->num_channels + 1; + int i; + for (i = 0; i < num_channels_plus_1; ++i) { + const int32_t* magnitudes = energy + *channel_frequency_starts++; + const int16_t* weights = state->weights + *channel_weight_starts; + const int16_t* unweights = state->unweights + *channel_weight_starts++; + const int width = *channel_widths++; + int j; + for (j = 0; j < width; ++j) { + weight_accumulator += *weights++ * ((uint64_t)*magnitudes); + unweight_accumulator += *unweights++ * ((uint64_t)*magnitudes); + ++magnitudes; + } + *work++ = weight_accumulator; + weight_accumulator = unweight_accumulator; + unweight_accumulator = 0; + } +} + +static uint16_t Sqrt32(uint32_t num) { + if (num == 0) { + return 0; + } + uint32_t res = 0; + int max_bit_number = 32 - MostSignificantBit32(num); + max_bit_number |= 1; + uint32_t bit = 1U << (31 - max_bit_number); + int iterations = (31 - max_bit_number) / 2 + 1; + while (iterations--) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1U) + bit; + } else { + res >>= 1U; + } + bit >>= 2U; + } + // Do rounding - if we have the bits. + if (num > res && res != 0xFFFF) { + ++res; + } + return res; +} + +static uint32_t Sqrt64(uint64_t num) { + // Take a shortcut and just use 32 bit operations if the upper word is all + // clear. This will cause a slight off by one issue for numbers close to 2^32, + // but it probably isn't going to matter (and gives us a big performance win). + if ((num >> 32) == 0) { + return Sqrt32((uint32_t)num); + } + uint64_t res = 0; + int max_bit_number = 64 - MostSignificantBit64(num); + max_bit_number |= 1; + uint64_t bit = 1ULL << (63 - max_bit_number); + int iterations = (63 - max_bit_number) / 2 + 1; + while (iterations--) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1U) + bit; + } else { + res >>= 1U; + } + bit >>= 2U; + } + // Do rounding - if we have the bits. + if (num > res && res != 0xFFFFFFFFLL) { + ++res; + } + return res; +} + +uint32_t* FilterbankSqrt(struct FilterbankState* state, int scale_down_shift) { + const int num_channels = state->num_channels; + const uint64_t* work = state->work + 1; + // Reuse the work buffer since we're fine clobbering it at this point to hold + // the output. + uint32_t* output = (uint32_t*)state->work; + int i; + for (i = 0; i < num_channels; ++i) { + *output++ = Sqrt64(*work++) >> scale_down_shift; + } + return (uint32_t*)state->work; +} + +void FilterbankReset(struct FilterbankState* state) { + memset(state->work, 0, (state->num_channels + 1) * sizeof(*state->work)); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank.h new file mode 100644 index 000000000..1e6d3885f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank.h @@ -0,0 +1,63 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_H_ + +#include +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/fft.h" + +#define kFilterbankBits 12 + +#ifdef __cplusplus +extern "C" { +#endif + +struct FilterbankState { + int num_channels; + int start_index; + int end_index; + int16_t* channel_frequency_starts; + int16_t* channel_weight_starts; + int16_t* channel_widths; + int16_t* weights; + int16_t* unweights; + uint64_t* work; +}; + +// Converts the relevant complex values of an FFT output into energy (the +// square magnitude). +void FilterbankConvertFftComplexToEnergy(struct FilterbankState* state, + struct complex_int16_t* fft_output, + int32_t* energy); + +// Computes the mel-scale filterbank on the given energy array. Output is cached +// internally - to fetch it, you need to call FilterbankSqrt. +void FilterbankAccumulateChannels(struct FilterbankState* state, + const int32_t* energy); + +// Applies an integer square root to the 64 bit intermediate values of the +// filterbank, and returns a pointer to them. Memory will be invalidated the +// next time FilterbankAccumulateChannels is called. +uint32_t* FilterbankSqrt(struct FilterbankState* state, int scale_down_shift); + +void FilterbankReset(struct FilterbankState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank_util.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank_util.c new file mode 100644 index 000000000..f18ebf547 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank_util.c @@ -0,0 +1,220 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/filterbank_util.h" + +#include +#include +#include + +#define kFilterbankIndexAlignment 4 +#define kFilterbankChannelBlockSize 4 + +void FilterbankFillConfigWithDefaults(struct FilterbankConfig* config) { + config->num_channels = 32; + config->lower_band_limit = 125.0f; + config->upper_band_limit = 7500.0f; + config->output_scale_shift = 7; +} + +static float FreqToMel(float freq) { return 1127.0 * log1p(freq / 700.0); } + +static void CalculateCenterFrequencies(const int num_channels, + const float lower_frequency_limit, + const float upper_frequency_limit, + float* center_frequencies) { + assert(lower_frequency_limit >= 0.0f); + assert(upper_frequency_limit > lower_frequency_limit); + + const float mel_low = FreqToMel(lower_frequency_limit); + const float mel_hi = FreqToMel(upper_frequency_limit); + const float mel_span = mel_hi - mel_low; + const float mel_spacing = mel_span / ((float)num_channels); + int i; + for (i = 0; i < num_channels; ++i) { + center_frequencies[i] = mel_low + (mel_spacing * (i + 1)); + } +} + +static void QuantizeFilterbankWeights(const float float_weight, int16_t* weight, + int16_t* unweight) { + *weight = floor(float_weight * (1 << kFilterbankBits) + 0.5); + *unweight = floor((1.0 - float_weight) * (1 << kFilterbankBits) + 0.5); +} + +int FilterbankPopulateState(const struct FilterbankConfig* config, + struct FilterbankState* state, int sample_rate, + int spectrum_size) { + state->num_channels = config->num_channels; + const int num_channels_plus_1 = config->num_channels + 1; + + // How should we align things to index counts given the byte alignment? + const int index_alignment = + (kFilterbankIndexAlignment < sizeof(int16_t) + ? 1 + : kFilterbankIndexAlignment / sizeof(int16_t)); + + state->channel_frequency_starts = + malloc(num_channels_plus_1 * sizeof(*state->channel_frequency_starts)); + state->channel_weight_starts = + malloc(num_channels_plus_1 * sizeof(*state->channel_weight_starts)); + state->channel_widths = + malloc(num_channels_plus_1 * sizeof(*state->channel_widths)); + state->work = malloc(num_channels_plus_1 * sizeof(*state->work)); + + float* center_mel_freqs = + malloc(num_channels_plus_1 * sizeof(*center_mel_freqs)); + int16_t* actual_channel_starts = + malloc(num_channels_plus_1 * sizeof(*actual_channel_starts)); + int16_t* actual_channel_widths = + malloc(num_channels_plus_1 * sizeof(*actual_channel_widths)); + + if (state->channel_frequency_starts == NULL || + state->channel_weight_starts == NULL || state->channel_widths == NULL || + center_mel_freqs == NULL || actual_channel_starts == NULL || + actual_channel_widths == NULL) { + free(center_mel_freqs); + free(actual_channel_starts); + free(actual_channel_widths); + fprintf(stderr, "Failed to allocate channel buffers\n"); + return 0; + } + + CalculateCenterFrequencies(num_channels_plus_1, config->lower_band_limit, + config->upper_band_limit, center_mel_freqs); + + // Always exclude DC. + const float hz_per_sbin = 0.5 * sample_rate / ((float)spectrum_size - 1); + state->start_index = 1.5 + config->lower_band_limit / hz_per_sbin; + state->end_index = 0; // Initialized to zero here, but actually set below. + + // For each channel, we need to figure out what frequencies belong to it, and + // how much padding we need to add so that we can efficiently multiply the + // weights and unweights for accumulation. To simplify the multiplication + // logic, all channels will have some multiplication to do (even if there are + // no frequencies that accumulate to that channel) - they will be directed to + // a set of zero weights. + int chan_freq_index_start = state->start_index; + int weight_index_start = 0; + int needs_zeros = 0; + + int chan; + for (chan = 0; chan < num_channels_plus_1; ++chan) { + // Keep jumping frequencies until we overshoot the bound on this channel. + int freq_index = chan_freq_index_start; + while (FreqToMel((freq_index)*hz_per_sbin) <= center_mel_freqs[chan]) { + ++freq_index; + } + + const int width = freq_index - chan_freq_index_start; + actual_channel_starts[chan] = chan_freq_index_start; + actual_channel_widths[chan] = width; + + if (width == 0) { + // This channel doesn't actually get anything from the frequencies, it's + // always zero. We need then to insert some 'zero' weights into the + // output, and just redirect this channel to do a single multiplication at + // this point. For simplicity, the zeros are placed at the beginning of + // the weights arrays, so we have to go and update all the other + // weight_starts to reflect this shift (but only once). + state->channel_frequency_starts[chan] = 0; + state->channel_weight_starts[chan] = 0; + state->channel_widths[chan] = kFilterbankChannelBlockSize; + if (!needs_zeros) { + needs_zeros = 1; + int j; + for (j = 0; j < chan; ++j) { + state->channel_weight_starts[j] += kFilterbankChannelBlockSize; + } + weight_index_start += kFilterbankChannelBlockSize; + } + } else { + // How far back do we need to go to ensure that we have the proper + // alignment? + const int aligned_start = + (chan_freq_index_start / index_alignment) * index_alignment; + const int aligned_width = (chan_freq_index_start - aligned_start + width); + const int padded_width = + (((aligned_width - 1) / kFilterbankChannelBlockSize) + 1) * + kFilterbankChannelBlockSize; + + state->channel_frequency_starts[chan] = aligned_start; + state->channel_weight_starts[chan] = weight_index_start; + state->channel_widths[chan] = padded_width; + weight_index_start += padded_width; + } + chan_freq_index_start = freq_index; + } + + // Allocate the two arrays to store the weights - weight_index_start contains + // the index of what would be the next set of weights that we would need to + // add, so that's how many weights we need to allocate. + state->weights = calloc(weight_index_start, sizeof(*state->weights)); + state->unweights = calloc(weight_index_start, sizeof(*state->unweights)); + + // If the alloc failed, we also need to nuke the arrays. + if (state->weights == NULL || state->unweights == NULL) { + free(center_mel_freqs); + free(actual_channel_starts); + free(actual_channel_widths); + fprintf(stderr, "Failed to allocate weights or unweights\n"); + return 0; + } + + // Next pass, compute all the weights. Since everything has been memset to + // zero, we only need to fill in the weights that correspond to some frequency + // for a channel. + const float mel_low = FreqToMel(config->lower_band_limit); + for (chan = 0; chan < num_channels_plus_1; ++chan) { + int frequency = actual_channel_starts[chan]; + const int num_frequencies = actual_channel_widths[chan]; + const int frequency_offset = + frequency - state->channel_frequency_starts[chan]; + const int weight_start = state->channel_weight_starts[chan]; + const float denom_val = (chan == 0) ? mel_low : center_mel_freqs[chan - 1]; + + int j; + for (j = 0; j < num_frequencies; ++j, ++frequency) { + const float weight = + (center_mel_freqs[chan] - FreqToMel(frequency * hz_per_sbin)) / + (center_mel_freqs[chan] - denom_val); + + // Make the float into an integer for the weights (and unweights). + const int weight_index = weight_start + frequency_offset + j; + QuantizeFilterbankWeights(weight, state->weights + weight_index, + state->unweights + weight_index); + } + if (frequency > state->end_index) { + state->end_index = frequency; + } + } + + free(center_mel_freqs); + free(actual_channel_starts); + free(actual_channel_widths); + if (state->end_index >= spectrum_size) { + fprintf(stderr, "Filterbank end_index is above spectrum size.\n"); + return 0; + } + return 1; +} + +void FilterbankFreeStateContents(struct FilterbankState* state) { + free(state->channel_frequency_starts); + free(state->channel_weight_starts); + free(state->channel_widths); + free(state->weights); + free(state->unweights); + free(state->work); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank_util.h new file mode 100644 index 000000000..781d10247 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/filterbank_util.h @@ -0,0 +1,50 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_UTIL_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/filterbank.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct FilterbankConfig { + // number of frequency channel buckets for filterbank + int num_channels; + // maximum frequency to include + float upper_band_limit; + // minimum frequency to include + float lower_band_limit; + // unused + int output_scale_shift; +}; + +// Fills the frontendConfig with "sane" defaults. +void FilterbankFillConfigWithDefaults(struct FilterbankConfig* config); + +// Allocates any buffers. +int FilterbankPopulateState(const struct FilterbankConfig* config, + struct FilterbankState* state, int sample_rate, + int spectrum_size); + +// Frees any allocated buffers. +void FilterbankFreeStateContents(struct FilterbankState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend.c new file mode 100644 index 000000000..9de2a8796 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend.c @@ -0,0 +1,72 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/frontend.h" + +#include "tensorflow/lite/experimental/microfrontend/lib/bits.h" + +struct FrontendOutput FrontendProcessSamples(struct FrontendState* state, + const int16_t* samples, + size_t num_samples, + size_t* num_samples_read) { + struct FrontendOutput output; + output.values = NULL; + output.size = 0; + + // Try to apply the window - if it fails, return and wait for more data. + if (!WindowProcessSamples(&state->window, samples, num_samples, + num_samples_read)) { + return output; + } + + // Apply the FFT to the window's output (and scale it so that the fixed point + // FFT can have as much resolution as possible). + int input_shift = + 15 - MostSignificantBit32(state->window.max_abs_output_value); + FftCompute(&state->fft, state->window.output, input_shift); + + // We can re-ruse the fft's output buffer to hold the energy. + int32_t* energy = (int32_t*)state->fft.output; + + FilterbankConvertFftComplexToEnergy(&state->filterbank, state->fft.output, + energy); + + FilterbankAccumulateChannels(&state->filterbank, energy); + uint32_t* scaled_filterbank = FilterbankSqrt(&state->filterbank, input_shift); + + // Apply noise reduction. + NoiseReductionApply(&state->noise_reduction, scaled_filterbank); + + if (state->pcan_gain_control.enable_pcan) { + PcanGainControlApply(&state->pcan_gain_control, scaled_filterbank); + } + + // Apply the log and scale. + int correction_bits = + MostSignificantBit32(state->fft.fft_size) - 1 - (kFilterbankBits / 2); + uint16_t* logged_filterbank = + LogScaleApply(&state->log_scale, scaled_filterbank, + state->filterbank.num_channels, correction_bits); + + output.size = state->filterbank.num_channels; + output.values = logged_filterbank; + return output; +} + +void FrontendReset(struct FrontendState* state) { + WindowReset(&state->window); + FftReset(&state->fft); + FilterbankReset(&state->filterbank); + NoiseReductionReset(&state->noise_reduction); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend.h new file mode 100644 index 000000000..883df5fd3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend.h @@ -0,0 +1,64 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_H_ + +#include +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/fft.h" +#include "tensorflow/lite/experimental/microfrontend/lib/filterbank.h" +#include "tensorflow/lite/experimental/microfrontend/lib/log_scale.h" +#include "tensorflow/lite/experimental/microfrontend/lib/noise_reduction.h" +#include "tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.h" +#include "tensorflow/lite/experimental/microfrontend/lib/window.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct FrontendState { + struct WindowState window; + struct FftState fft; + struct FilterbankState filterbank; + struct NoiseReductionState noise_reduction; + struct PcanGainControlState pcan_gain_control; + struct LogScaleState log_scale; +}; + +struct FrontendOutput { + const uint16_t* values; + size_t size; +}; + +// Main entry point to processing frontend samples. Updates num_samples_read to +// contain the number of samples that have been consumed from the input array. +// Returns a struct containing the generated output. If not enough samples were +// added to generate a feature vector, the returned size will be 0 and the +// values pointer will be NULL. Note that the output pointer will be invalidated +// as soon as FrontendProcessSamples is called again, so copy the contents +// elsewhere if you need to use them later. +struct FrontendOutput FrontendProcessSamples(struct FrontendState* state, + const int16_t* samples, + size_t num_samples, + size_t* num_samples_read); + +void FrontendReset(struct FrontendState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend_util.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend_util.c new file mode 100644 index 000000000..27224f6d2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend_util.c @@ -0,0 +1,85 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/frontend_util.h" + +#include +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/bits.h" + +void FrontendFillConfigWithDefaults(struct FrontendConfig* config) { + WindowFillConfigWithDefaults(&config->window); + FilterbankFillConfigWithDefaults(&config->filterbank); + NoiseReductionFillConfigWithDefaults(&config->noise_reduction); + PcanGainControlFillConfigWithDefaults(&config->pcan_gain_control); + LogScaleFillConfigWithDefaults(&config->log_scale); +} + +int FrontendPopulateState(const struct FrontendConfig* config, + struct FrontendState* state, int sample_rate) { + memset(state, 0, sizeof(*state)); + + if (!WindowPopulateState(&config->window, &state->window, sample_rate)) { + fprintf(stderr, "Failed to populate window state\n"); + return 0; + } + + if (!FftPopulateState(&state->fft, state->window.size)) { + fprintf(stderr, "Failed to populate fft state\n"); + return 0; + } + FftInit(&state->fft); + + if (!FilterbankPopulateState(&config->filterbank, &state->filterbank, + sample_rate, state->fft.fft_size / 2 + 1)) { + fprintf(stderr, "Failed to populate filterbank state\n"); + return 0; + } + + if (!NoiseReductionPopulateState(&config->noise_reduction, + &state->noise_reduction, + state->filterbank.num_channels)) { + fprintf(stderr, "Failed to populate noise reduction state\n"); + return 0; + } + + int input_correction_bits = + MostSignificantBit32(state->fft.fft_size) - 1 - (kFilterbankBits / 2); + if (!PcanGainControlPopulateState( + &config->pcan_gain_control, &state->pcan_gain_control, + state->noise_reduction.estimate, state->filterbank.num_channels, + state->noise_reduction.smoothing_bits, input_correction_bits)) { + fprintf(stderr, "Failed to populate pcan gain control state\n"); + return 0; + } + + if (!LogScalePopulateState(&config->log_scale, &state->log_scale)) { + fprintf(stderr, "Failed to populate log scale state\n"); + return 0; + } + + FrontendReset(state); + + // All good, return a true value. + return 1; +} + +void FrontendFreeStateContents(struct FrontendState* state) { + WindowFreeStateContents(&state->window); + FftFreeStateContents(&state->fft); + FilterbankFreeStateContents(&state->filterbank); + NoiseReductionFreeStateContents(&state->noise_reduction); + PcanGainControlFreeStateContents(&state->pcan_gain_control); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend_util.h new file mode 100644 index 000000000..895ce6cd2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/frontend_util.h @@ -0,0 +1,52 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_UTIL_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/fft_util.h" +#include "tensorflow/lite/experimental/microfrontend/lib/filterbank_util.h" +#include "tensorflow/lite/experimental/microfrontend/lib/frontend.h" +#include "tensorflow/lite/experimental/microfrontend/lib/log_scale_util.h" +#include "tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.h" +#include "tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.h" +#include "tensorflow/lite/experimental/microfrontend/lib/window_util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct FrontendConfig { + struct WindowConfig window; + struct FilterbankConfig filterbank; + struct NoiseReductionConfig noise_reduction; + struct PcanGainControlConfig pcan_gain_control; + struct LogScaleConfig log_scale; +}; + +// Fills the frontendConfig with "sane" defaults. +void FrontendFillConfigWithDefaults(struct FrontendConfig* config); + +// Allocates any buffers. +int FrontendPopulateState(const struct FrontendConfig* config, + struct FrontendState* state, int sample_rate); + +// Frees any allocated buffers. +void FrontendFreeStateContents(struct FrontendState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h new file mode 100644 index 000000000..f704677d2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h @@ -0,0 +1,48 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_KISS_FFT_COMMON_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_KISS_FFT_COMMON_H_ + +// This header file should be included in all variants of kiss_fft_$type.{h,cc} +// so that their sub-included source files do not mistakenly wrap libc header +// files within their kissfft_$type namespaces. +// E.g, This header avoids kissfft_int16.h containing: +// namespace kiss_fft_int16 { +// #include "third_party/kissfft/kiss_fft.h" +// } +// where kiss_fft_.h contains: +// #include +// +// TRICK: By including the following header files here, their preprocessor +// header guards prevent them being re-defined inside of the kiss_fft_$type +// namespaces declared within the kiss_fft_$type.{h,cc} sources. +// Note that the original kiss_fft*.h files are untouched since they +// may be used in libraries that include them directly. + +#include +#include +#include +#include +#include + +#ifdef FIXED_POINT +#include +#endif + +#ifdef USE_SIMD +#include +#endif +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_KISS_FFT_COMMON_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.cpp new file mode 100644 index 000000000..546306612 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.cpp @@ -0,0 +1,10 @@ +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h" + +#define FIXED_POINT 16 +namespace kissfft_fixed16 { +#include "third_party/kissfft/kiss_fft.c" +#include "third_party/kissfft/tools/kiss_fftr.c" +} // namespace kissfft_fixed16 +#undef FIXED_POINT diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.h new file mode 100644 index 000000000..380307a46 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/kiss_fft_int16.h @@ -0,0 +1,33 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_KISS_FFT_INT16_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_KISS_FFT_INT16_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h" + +// Wrap 16-bit kiss fft in its own namespace. Enables us to link an application +// with different kiss fft resultions (16/32 bit interger, float, double) +// without getting a linker error. +#define FIXED_POINT 16 +namespace kissfft_fixed16 { +#include "third_party/kissfft/kiss_fft.h" +#include "third_party/kissfft/tools/kiss_fftr.h" +} // namespace kissfft_fixed16 +#undef FIXED_POINT +#undef kiss_fft_scalar +#undef KISS_FFT_H + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_KISS_FFT_INT16_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_lut.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_lut.c new file mode 100644 index 000000000..f59618e02 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_lut.c @@ -0,0 +1,30 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/log_lut.h" +const uint16_t kLogLut[] +#ifndef _MSC_VER + __attribute__((aligned(4))) +#endif // _MSV_VER + = {0, 224, 442, 654, 861, 1063, 1259, 1450, 1636, 1817, 1992, 2163, + 2329, 2490, 2646, 2797, 2944, 3087, 3224, 3358, 3487, 3611, 3732, 3848, + 3960, 4068, 4172, 4272, 4368, 4460, 4549, 4633, 4714, 4791, 4864, 4934, + 5001, 5063, 5123, 5178, 5231, 5280, 5326, 5368, 5408, 5444, 5477, 5507, + 5533, 5557, 5578, 5595, 5610, 5622, 5631, 5637, 5640, 5641, 5638, 5633, + 5626, 5615, 5602, 5586, 5568, 5547, 5524, 5498, 5470, 5439, 5406, 5370, + 5332, 5291, 5249, 5203, 5156, 5106, 5054, 5000, 4944, 4885, 4825, 4762, + 4697, 4630, 4561, 4490, 4416, 4341, 4264, 4184, 4103, 4020, 3935, 3848, + 3759, 3668, 3575, 3481, 3384, 3286, 3186, 3084, 2981, 2875, 2768, 2659, + 2549, 2437, 2323, 2207, 2090, 1971, 1851, 1729, 1605, 1480, 1353, 1224, + 1094, 963, 830, 695, 559, 421, 282, 142, 0, 0}; diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_lut.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_lut.h new file mode 100644 index 000000000..b2448a322 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_lut.h @@ -0,0 +1,40 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_LUT_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_LUT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Number of segments in the log lookup table. The table will be kLogSegments+1 +// in length (with some padding). +#define kLogSegments 128 +#define kLogSegmentsLog2 7 + +// Scale used by lookup table. +#define kLogScale 65536 +#define kLogScaleLog2 16 +#define kLogCoeff 45426 + +extern const uint16_t kLogLut[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_LUT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale.c new file mode 100644 index 000000000..c27a50a62 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale.c @@ -0,0 +1,83 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/log_scale.h" + +#include "tensorflow/lite/experimental/microfrontend/lib/bits.h" +#include "tensorflow/lite/experimental/microfrontend/lib/log_lut.h" + +#define kuint16max 0x0000FFFF + +// The following functions implement integer logarithms of various sizes. The +// approximation is calculated according to method described in +// www.inti.gob.ar/electronicaeinformatica/instrumentacion/utic/ +// publicaciones/SPL2007/Log10-spl07.pdf +// It first calculates log2 of the input and then converts it to natural +// logarithm. + +static uint32_t Log2FractionPart(const uint32_t x, const uint32_t log2x) { + // Part 1 + int32_t frac = x - (1LL << log2x); + if (log2x < kLogScaleLog2) { + frac <<= kLogScaleLog2 - log2x; + } else { + frac >>= log2x - kLogScaleLog2; + } + // Part 2 + const uint32_t base_seg = frac >> (kLogScaleLog2 - kLogSegmentsLog2); + const uint32_t seg_unit = + (((uint32_t)1) << kLogScaleLog2) >> kLogSegmentsLog2; + + const int32_t c0 = kLogLut[base_seg]; + const int32_t c1 = kLogLut[base_seg + 1]; + const int32_t seg_base = seg_unit * base_seg; + const int32_t rel_pos = ((c1 - c0) * (frac - seg_base)) >> kLogScaleLog2; + return frac + c0 + rel_pos; +} + +static uint32_t Log(const uint32_t x, const uint32_t scale_shift) { + const uint32_t integer = MostSignificantBit32(x) - 1; + const uint32_t fraction = Log2FractionPart(x, integer); + const uint32_t log2 = (integer << kLogScaleLog2) + fraction; + const uint32_t round = kLogScale / 2; + const uint32_t loge = (((uint64_t)kLogCoeff) * log2 + round) >> kLogScaleLog2; + // Finally scale to our output scale + const uint32_t loge_scaled = ((loge << scale_shift) + round) >> kLogScaleLog2; + return loge_scaled; +} + +uint16_t* LogScaleApply(struct LogScaleState* state, uint32_t* signal, + int signal_size, int correction_bits) { + const int scale_shift = state->scale_shift; + uint16_t* output = (uint16_t*)signal; + uint16_t* ret = output; + int i; + for (i = 0; i < signal_size; ++i) { + uint32_t value = *signal++; + if (state->enable_log) { + if (correction_bits < 0) { + value >>= -correction_bits; + } else { + value <<= correction_bits; + } + if (value > 1) { + value = Log(value, scale_shift); + } else { + value = 0; + } + } + *output++ = (value < kuint16max) ? value : kuint16max; + } + return ret; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale.h new file mode 100644 index 000000000..a383f32f5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale.h @@ -0,0 +1,39 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct LogScaleState { + int enable_log; + int scale_shift; +}; + +// Applies a fixed point logarithm to the signal and converts it to 16 bit. Note +// that the signal array will be modified. +uint16_t* LogScaleApply(struct LogScaleState* state, uint32_t* signal, + int signal_size, int correction_bits); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale_util.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale_util.c new file mode 100644 index 000000000..0e3dd1d1e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale_util.c @@ -0,0 +1,27 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/log_scale_util.h" + +void LogScaleFillConfigWithDefaults(struct LogScaleConfig* config) { + config->enable_log = 1; + config->scale_shift = 6; +} + +int LogScalePopulateState(const struct LogScaleConfig* config, + struct LogScaleState* state) { + state->enable_log = config->enable_log; + state->scale_shift = config->scale_shift; + return 1; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale_util.h new file mode 100644 index 000000000..11f7d9eeb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/log_scale_util.h @@ -0,0 +1,45 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_UTIL_H_ + +#include +#include + +#include "tensorflow/lite/experimental/microfrontend/lib/log_scale.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct LogScaleConfig { + // set to false (0) to disable this module + int enable_log; + // scale results by 2^(scale_shift) + int scale_shift; +}; + +// Populates the LogScaleConfig with "sane" default values. +void LogScaleFillConfigWithDefaults(struct LogScaleConfig* config); + +// Allocates any buffers. +int LogScalePopulateState(const struct LogScaleConfig* config, + struct LogScaleState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction.c new file mode 100644 index 000000000..16b30e66a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction.c @@ -0,0 +1,51 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/noise_reduction.h" + +#include + +void NoiseReductionApply(struct NoiseReductionState* state, uint32_t* signal) { + int i; + for (i = 0; i < state->num_channels; ++i) { + const uint32_t smoothing = + ((i & 1) == 0) ? state->even_smoothing : state->odd_smoothing; + const uint32_t one_minus_smoothing = (1 << kNoiseReductionBits) - smoothing; + + // Update the estimate of the noise. + const uint32_t signal_scaled_up = signal[i] << state->smoothing_bits; + uint32_t estimate = + (((uint64_t)signal_scaled_up * smoothing) + + ((uint64_t)state->estimate[i] * one_minus_smoothing)) >> + kNoiseReductionBits; + state->estimate[i] = estimate; + + // Make sure that we can't get a negative value for the signal - estimate. + if (estimate > signal_scaled_up) { + estimate = signal_scaled_up; + } + + const uint32_t floor = + ((uint64_t)signal[i] * state->min_signal_remaining) >> + kNoiseReductionBits; + const uint32_t subtracted = + (signal_scaled_up - estimate) >> state->smoothing_bits; + const uint32_t output = subtracted > floor ? subtracted : floor; + signal[i] = output; + } +} + +void NoiseReductionReset(struct NoiseReductionState* state) { + memset(state->estimate, 0, sizeof(*state->estimate) * state->num_channels); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction.h new file mode 100644 index 000000000..46d3f52e6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction.h @@ -0,0 +1,46 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_H_ + +#define kNoiseReductionBits 14 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct NoiseReductionState { + int smoothing_bits; + uint16_t even_smoothing; + uint16_t odd_smoothing; + uint16_t min_signal_remaining; + int num_channels; + uint32_t* estimate; +}; + +// Removes stationary noise from each channel of the signal using a low pass +// filter. +void NoiseReductionApply(struct NoiseReductionState* state, uint32_t* signal); + +void NoiseReductionReset(struct NoiseReductionState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.c new file mode 100644 index 000000000..a6c9234eb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.c @@ -0,0 +1,45 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.h" + +#include + +void NoiseReductionFillConfigWithDefaults(struct NoiseReductionConfig* config) { + config->smoothing_bits = 10; + config->even_smoothing = 0.025; + config->odd_smoothing = 0.06; + config->min_signal_remaining = 0.05; +} + +int NoiseReductionPopulateState(const struct NoiseReductionConfig* config, + struct NoiseReductionState* state, + int num_channels) { + state->smoothing_bits = config->smoothing_bits; + state->odd_smoothing = config->odd_smoothing * (1 << kNoiseReductionBits); + state->even_smoothing = config->even_smoothing * (1 << kNoiseReductionBits); + state->min_signal_remaining = + config->min_signal_remaining * (1 << kNoiseReductionBits); + state->num_channels = num_channels; + state->estimate = calloc(state->num_channels, sizeof(*state->estimate)); + if (state->estimate == NULL) { + fprintf(stderr, "Failed to alloc estimate buffer\n"); + return 0; + } + return 1; +} + +void NoiseReductionFreeStateContents(struct NoiseReductionState* state) { + free(state->estimate); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.h new file mode 100644 index 000000000..fa5553914 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/noise_reduction_util.h @@ -0,0 +1,50 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_UTIL_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/noise_reduction.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct NoiseReductionConfig { + // scale the signal up by 2^(smoothing_bits) before reduction + int smoothing_bits; + // smoothing coefficient for even-numbered channels + float even_smoothing; + // smoothing coefficient for odd-numbered channels + float odd_smoothing; + // fraction of signal to preserve (1.0 disables this module) + float min_signal_remaining; +}; + +// Populates the NoiseReductionConfig with "sane" default values. +void NoiseReductionFillConfigWithDefaults(struct NoiseReductionConfig* config); + +// Allocates any buffers. +int NoiseReductionPopulateState(const struct NoiseReductionConfig* config, + struct NoiseReductionState* state, + int num_channels); + +// Frees any allocated buffers. +void NoiseReductionFreeStateContents(struct NoiseReductionState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.c new file mode 100644 index 000000000..22d587674 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.c @@ -0,0 +1,56 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.h" + +#include "tensorflow/lite/experimental/microfrontend/lib/bits.h" + +int16_t WideDynamicFunction(const uint32_t x, const int16_t* lut) { + if (x <= 2) { + return lut[x]; + } + + const int16_t interval = MostSignificantBit32(x); + lut += 4 * interval - 6; + + const int16_t frac = + ((interval < 11) ? (x << (11 - interval)) : (x >> (interval - 11))) & + 0x3FF; + + int32_t result = ((int32_t)lut[2] * frac) >> 5; + result += (int32_t)((uint32_t)lut[1] << 5); + result *= frac; + result = (result + (1 << 14)) >> 15; + result += lut[0]; + return (int16_t)result; +} + +uint32_t PcanShrink(const uint32_t x) { + if (x < (2 << kPcanSnrBits)) { + return (x * x) >> (2 + 2 * kPcanSnrBits - kPcanOutputBits); + } else { + return (x >> (kPcanSnrBits - kPcanOutputBits)) - (1 << kPcanOutputBits); + } +} + +void PcanGainControlApply(struct PcanGainControlState* state, + uint32_t* signal) { + int i; + for (i = 0; i < state->num_channels; ++i) { + const uint32_t gain = + WideDynamicFunction(state->noise_estimate[i], state->gain_lut); + const uint32_t snr = ((uint64_t)signal[i] * gain) >> state->snr_shift; + signal[i] = PcanShrink(snr); + } +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.h new file mode 100644 index 000000000..3f6222beb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.h @@ -0,0 +1,47 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_H_ + +#include +#include + +#define kPcanSnrBits 12 +#define kPcanOutputBits 6 + +#ifdef __cplusplus +extern "C" { +#endif + +// Details at https://research.google/pubs/pub45911.pdf +struct PcanGainControlState { + int enable_pcan; + uint32_t* noise_estimate; + int num_channels; + int16_t* gain_lut; + int32_t snr_shift; +}; + +int16_t WideDynamicFunction(const uint32_t x, const int16_t* lut); + +uint32_t PcanShrink(const uint32_t x); + +void PcanGainControlApply(struct PcanGainControlState* state, uint32_t* signal); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.c new file mode 100644 index 000000000..e850d439e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.c @@ -0,0 +1,92 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.h" + +#include +#include + +#define kint16max 0x00007FFF + +void PcanGainControlFillConfigWithDefaults( + struct PcanGainControlConfig* config) { + config->enable_pcan = 0; + config->strength = 0.95; + config->offset = 80.0; + config->gain_bits = 21; +} + +int16_t PcanGainLookupFunction(const struct PcanGainControlConfig* config, + int32_t input_bits, uint32_t x) { + const float x_as_float = ((float)x) / ((uint32_t)1 << input_bits); + const float gain_as_float = + ((uint32_t)1 << config->gain_bits) * + powf(x_as_float + config->offset, -config->strength); + + if (gain_as_float > kint16max) { + return kint16max; + } + return (int16_t)(gain_as_float + 0.5f); +} + +int PcanGainControlPopulateState(const struct PcanGainControlConfig* config, + struct PcanGainControlState* state, + uint32_t* noise_estimate, + const int num_channels, + const uint16_t smoothing_bits, + const int32_t input_correction_bits) { + state->enable_pcan = config->enable_pcan; + if (!state->enable_pcan) { + return 1; + } + state->noise_estimate = noise_estimate; + state->num_channels = num_channels; + state->gain_lut = malloc(kWideDynamicFunctionLUTSize * sizeof(int16_t)); + if (state->gain_lut == NULL) { + fprintf(stderr, "Failed to allocate gain LUT\n"); + return 0; + } + state->snr_shift = config->gain_bits - input_correction_bits - kPcanSnrBits; + + const int32_t input_bits = smoothing_bits - input_correction_bits; + state->gain_lut[0] = PcanGainLookupFunction(config, input_bits, 0); + state->gain_lut[1] = PcanGainLookupFunction(config, input_bits, 1); + state->gain_lut -= 6; + int interval; + for (interval = 2; interval <= kWideDynamicFunctionBits; ++interval) { + const uint32_t x0 = (uint32_t)1 << (interval - 1); + const uint32_t x1 = x0 + (x0 >> 1); + const uint32_t x2 = + (interval == kWideDynamicFunctionBits) ? x0 + (x0 - 1) : 2 * x0; + + const int16_t y0 = PcanGainLookupFunction(config, input_bits, x0); + const int16_t y1 = PcanGainLookupFunction(config, input_bits, x1); + const int16_t y2 = PcanGainLookupFunction(config, input_bits, x2); + + const int32_t diff1 = (int32_t)y1 - y0; + const int32_t diff2 = (int32_t)y2 - y0; + const int32_t a1 = 4 * diff1 - diff2; + const int32_t a2 = diff2 - a1; + + state->gain_lut[4 * interval] = y0; + state->gain_lut[4 * interval + 1] = (int16_t)a1; + state->gain_lut[4 * interval + 2] = (int16_t)a2; + } + state->gain_lut += 6; + return 1; +} + +void PcanGainControlFreeStateContents(struct PcanGainControlState* state) { + free(state->gain_lut); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.h new file mode 100644 index 000000000..d4bfaa2ed --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control_util.h @@ -0,0 +1,57 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_UTIL_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/pcan_gain_control.h" + +#define kWideDynamicFunctionBits 32 +#define kWideDynamicFunctionLUTSize (4 * kWideDynamicFunctionBits - 3) + +#ifdef __cplusplus +extern "C" { +#endif + +struct PcanGainControlConfig { + // set to false (0) to disable this module + int enable_pcan; + // gain normalization exponent (0.0 disables, 1.0 full strength) + float strength; + // positive value added in the normalization denominator + float offset; + // number of fractional bits in the gain + int gain_bits; +}; + +void PcanGainControlFillConfigWithDefaults( + struct PcanGainControlConfig* config); + +int16_t PcanGainLookupFunction(const struct PcanGainControlConfig* config, + int32_t input_bits, uint32_t x); + +int PcanGainControlPopulateState(const struct PcanGainControlConfig* config, + struct PcanGainControlState* state, + uint32_t* noise_estimate, + const int num_channels, + const uint16_t smoothing_bits, + const int32_t input_correction_bits); + +void PcanGainControlFreeStateContents(struct PcanGainControlState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window.c new file mode 100644 index 000000000..10da6762c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window.c @@ -0,0 +1,70 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/window.h" + +#include + +int WindowProcessSamples(struct WindowState* state, const int16_t* samples, + size_t num_samples, size_t* num_samples_read) { + const int size = state->size; + + // Copy samples from the samples buffer over to our local input. + size_t max_samples_to_copy = state->size - state->input_used; + if (max_samples_to_copy > num_samples) { + max_samples_to_copy = num_samples; + } + memcpy(state->input + state->input_used, samples, + max_samples_to_copy * sizeof(*samples)); + *num_samples_read = max_samples_to_copy; + state->input_used += max_samples_to_copy; + + if (state->input_used < state->size) { + // We don't have enough samples to compute a window. + return 0; + } + + // Apply the window to the input. + const int16_t* coefficients = state->coefficients; + const int16_t* input = state->input; + int16_t* output = state->output; + int i; + int16_t max_abs_output_value = 0; + for (i = 0; i < size; ++i) { + int16_t new_value = + (((int32_t)*input++) * *coefficients++) >> kFrontendWindowBits; + *output++ = new_value; + if (new_value < 0) { + new_value = -new_value; + } + if (new_value > max_abs_output_value) { + max_abs_output_value = new_value; + } + } + // Shuffle the input down by the step size, and update how much we have used. + memmove(state->input, state->input + state->step, + sizeof(*state->input) * (state->size - state->step)); + state->input_used -= state->step; + state->max_abs_output_value = max_abs_output_value; + + // Indicate that the output buffer is valid for the next stage. + return 1; +} + +void WindowReset(struct WindowState* state) { + memset(state->input, 0, state->size * sizeof(*state->input)); + memset(state->output, 0, state->size * sizeof(*state->output)); + state->input_used = 0; + state->max_abs_output_value = 0; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window.h new file mode 100644 index 000000000..bad815141 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window.h @@ -0,0 +1,49 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_H_ + +#include +#include + +#define kFrontendWindowBits 12 + +#ifdef __cplusplus +extern "C" { +#endif + +struct WindowState { + size_t size; + int16_t* coefficients; + size_t step; + + int16_t* input; + size_t input_used; + int16_t* output; + int16_t max_abs_output_value; +}; + +// Applies a window to the samples coming in, stepping forward at the given +// rate. +int WindowProcessSamples(struct WindowState* state, const int16_t* samples, + size_t num_samples, size_t* num_samples_read); + +void WindowReset(struct WindowState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window_util.c b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window_util.c new file mode 100644 index 000000000..eee6e7b56 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window_util.c @@ -0,0 +1,73 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/experimental/microfrontend/lib/window_util.h" + +#include +#include +#include +#include + +// Some platforms don't have M_PI +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +void WindowFillConfigWithDefaults(struct WindowConfig* config) { + config->size_ms = 25; + config->step_size_ms = 10; +} + +int WindowPopulateState(const struct WindowConfig* config, + struct WindowState* state, int sample_rate) { + state->size = config->size_ms * sample_rate / 1000; + state->step = config->step_size_ms * sample_rate / 1000; + + state->coefficients = malloc(state->size * sizeof(*state->coefficients)); + if (state->coefficients == NULL) { + fprintf(stderr, "Failed to allocate window coefficients\n"); + return 0; + } + + // Populate the window values. + const float arg = M_PI * 2.0 / ((float)state->size); + int i; + for (i = 0; i < state->size; ++i) { + float float_value = 0.5 - (0.5 * cos(arg * (i + 0.5))); + // Scale it to fixed point and round it. + state->coefficients[i] = + floor(float_value * (1 << kFrontendWindowBits) + 0.5); + } + + state->input_used = 0; + state->input = malloc(state->size * sizeof(*state->input)); + if (state->input == NULL) { + fprintf(stderr, "Failed to allocate window input\n"); + return 0; + } + + state->output = malloc(state->size * sizeof(*state->output)); + if (state->output == NULL) { + fprintf(stderr, "Failed to allocate window output\n"); + return 0; + } + + return 1; +} + +void WindowFreeStateContents(struct WindowState* state) { + free(state->coefficients); + free(state->input); + free(state->output); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window_util.h new file mode 100644 index 000000000..68e4de9eb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/experimental/microfrontend/lib/window_util.h @@ -0,0 +1,45 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_UTIL_H_ +#define TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_UTIL_H_ + +#include "tensorflow/lite/experimental/microfrontend/lib/window.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct WindowConfig { + // length of window frame in milliseconds + size_t size_ms; + // length of step for next frame in milliseconds + size_t step_size_ms; +}; + +// Populates the WindowConfig with "sane" default values. +void WindowFillConfigWithDefaults(struct WindowConfig* config); + +// Allocates any buffers. +int WindowPopulateState(const struct WindowConfig* config, + struct WindowState* state, int sample_rate); + +// Frees any allocated buffers. +void WindowFreeStateContents(struct WindowState* state); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // TENSORFLOW_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/common.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/common.h new file mode 100644 index 000000000..c59a01b33 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/common.h @@ -0,0 +1,1227 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_COMMON_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_COMMON_H_ + +#include +#ifndef ALLOW_SLOW_GENERIC_DEPTHWISECONV_FALLBACK +#ifdef GEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK +#define ALLOW_SLOW_GENERIC_DEPTHWISECONV_FALLBACK +#endif +#endif + +#include +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/optimized/neon_check.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +constexpr int kReverseShift = -1; + +inline void GetActivationMinMax(FusedActivationFunctionType ac, + float* output_activation_min, + float* output_activation_max) { + switch (ac) { + case FusedActivationFunctionType::kNone: + *output_activation_min = std::numeric_limits::lowest(); + *output_activation_max = std::numeric_limits::max(); + break; + case FusedActivationFunctionType::kRelu: + *output_activation_min = 0.f; + *output_activation_max = std::numeric_limits::max(); + break; + case FusedActivationFunctionType::kRelu1: + *output_activation_min = -1.f; + *output_activation_max = 1.f; + break; + case FusedActivationFunctionType::kRelu6: + *output_activation_min = 0.f; + *output_activation_max = 6.f; + break; + } +} + +template +inline T ActivationFunctionWithMinMax(T x, T output_activation_min, + T output_activation_max) { + using std::max; + using std::min; + return min(max(x, output_activation_min), output_activation_max); +} + +// Legacy function, left for compatibility only. +template +float ActivationFunction(float x) { + float output_activation_min, output_activation_max; + GetActivationMinMax(Ac, &output_activation_min, &output_activation_max); + return ActivationFunctionWithMinMax(x, output_activation_min, + output_activation_max); +} + +inline void BiasAndClamp(float clamp_min, float clamp_max, int bias_size, + const float* bias_data, int array_size, + float* array_data) { + if (bias_size == 0) return; + // Note: see b/132215220: in May 2019 we thought it would be OK to replace + // this with the Eigen one-liner: + // return (array.colwise() + bias).cwiseMin(clamp_max).cwiseMin(clamp_max). + // This turned out to severely regress performance: +4ms (i.e. 8%) on + // MobileNet v2 / 1.0 / 224. So we keep custom NEON code for now. + TFLITE_DCHECK_EQ((array_size % bias_size), 0); +#ifdef USE_NEON + float* array_ptr = array_data; + float* array_end_ptr = array_ptr + array_size; + const auto clamp_min_vec = vdupq_n_f32(clamp_min); + const auto clamp_max_vec = vdupq_n_f32(clamp_max); + for (; array_ptr != array_end_ptr; array_ptr += bias_size) { + int i = 0; + for (; i <= bias_size - 16; i += 16) { + auto b0 = vld1q_f32(bias_data + i); + auto b1 = vld1q_f32(bias_data + i + 4); + auto b2 = vld1q_f32(bias_data + i + 8); + auto b3 = vld1q_f32(bias_data + i + 12); + auto a0 = vld1q_f32(array_ptr + i); + auto a1 = vld1q_f32(array_ptr + i + 4); + auto a2 = vld1q_f32(array_ptr + i + 8); + auto a3 = vld1q_f32(array_ptr + i + 12); + auto x0 = vaddq_f32(a0, b0); + auto x1 = vaddq_f32(a1, b1); + auto x2 = vaddq_f32(a2, b2); + auto x3 = vaddq_f32(a3, b3); + x0 = vmaxq_f32(clamp_min_vec, x0); + x1 = vmaxq_f32(clamp_min_vec, x1); + x2 = vmaxq_f32(clamp_min_vec, x2); + x3 = vmaxq_f32(clamp_min_vec, x3); + x0 = vminq_f32(clamp_max_vec, x0); + x1 = vminq_f32(clamp_max_vec, x1); + x2 = vminq_f32(clamp_max_vec, x2); + x3 = vminq_f32(clamp_max_vec, x3); + vst1q_f32(array_ptr + i, x0); + vst1q_f32(array_ptr + i + 4, x1); + vst1q_f32(array_ptr + i + 8, x2); + vst1q_f32(array_ptr + i + 12, x3); + } + for (; i <= bias_size - 4; i += 4) { + auto b = vld1q_f32(bias_data + i); + auto a = vld1q_f32(array_ptr + i); + auto x = vaddq_f32(a, b); + x = vmaxq_f32(clamp_min_vec, x); + x = vminq_f32(clamp_max_vec, x); + vst1q_f32(array_ptr + i, x); + } + for (; i < bias_size; i++) { + array_ptr[i] = ActivationFunctionWithMinMax(array_ptr[i] + bias_data[i], + clamp_min, clamp_max); + } + } +#else // not NEON + for (int array_offset = 0; array_offset < array_size; + array_offset += bias_size) { + for (int i = 0; i < bias_size; i++) { + array_data[array_offset + i] = ActivationFunctionWithMinMax( + array_data[array_offset + i] + bias_data[i], clamp_min, clamp_max); + } + } +#endif +} + +// Single-rounding MultiplyByQuantizedMultiplier +#if TFLITE_SINGLE_ROUNDING +inline int32_t MultiplyByQuantizedMultiplier(int32_t x, + int32_t quantized_multiplier, + int shift) { + TFLITE_DCHECK(quantized_multiplier >= 0); + TFLITE_DCHECK(shift >= -31 && shift <= 30); + + const int64_t total_shift = 31 - shift; + const int64_t round = static_cast(1) << (total_shift - 1); + int64_t result = x * static_cast(quantized_multiplier) + round; + result = result >> total_shift; + + TFLITE_DCHECK(result >= std::numeric_limits::min() && + result <= std::numeric_limits::max()); + return static_cast(result); +} + +inline int32_t MultiplyByQuantizedMultiplierSmallerThanOneExp( + int32_t x, int32_t quantized_multiplier, int shift) { + TFLITE_DCHECK_LE(shift, 0); + return MultiplyByQuantizedMultiplier(x, quantized_multiplier, shift); +} + +inline int32_t MultiplyByQuantizedMultiplierGreaterThanOne( + int32_t x, int32_t quantized_multiplier, int shift) { + TFLITE_DCHECK_GE(shift, 0); + return MultiplyByQuantizedMultiplier(x, quantized_multiplier, shift); +} + +inline int32_t MultiplyByQuantizedMultiplier(int64_t x, + int32_t quantized_multiplier, + int shift) { + // Inputs: + // - quantized_multiplier has fixed point at bit 31 + // - shift is -31 to +7 (negative for right shift) + // + // Assumptions: The following input ranges are assumed + // - quantize_scale>=0 (the usual range is (1<<30) to (1>>31)-1) + // - scaling is chosen so final scaled result fits in int32_t + // - input x is in the range -(1<<47) <= x < (1<<47) + TFLITE_DCHECK(quantized_multiplier >= 0); + TFLITE_DCHECK(shift >= -31 && shift < 8); + TFLITE_DCHECK(x >= -(static_cast(1) << 47) && + x < (static_cast(1) << 47)); + + const int32_t reduced_multiplier = + (quantized_multiplier < 0x7FFF0000) + ? ((quantized_multiplier + (1 << 15)) >> 16) + : 0x7FFF; + const int64_t total_shift = 15 - shift; + const int64_t round = static_cast(1) << (total_shift - 1); + int64_t result = x * static_cast(reduced_multiplier) + round; + result = result >> total_shift; + + TFLITE_DCHECK(result >= std::numeric_limits::min() && + result <= std::numeric_limits::max()); + return static_cast(result); +} + +#ifdef USE_NEON +inline int32x4x4_t MultiplyByQuantizedMultiplier4Rows( + int32x4x4_t input_val, int32_t quantized_multiplier, int shift) { + TFLITE_DCHECK(quantized_multiplier >= 0); + + const int right_shift = std::min(-1, shift); + const int left_shift = shift - right_shift; + + const int32x4_t multiplier_dup = vdupq_n_s32(quantized_multiplier); + const int32x4_t left_shift_dup = vdupq_n_s32(left_shift); + const int32x4_t right_shift_dup = vdupq_n_s32(right_shift); + + int32x4x4_t result; + result.val[0] = vrshlq_s32( + vqdmulhq_s32(vshlq_s32(input_val.val[0], left_shift_dup), multiplier_dup), + right_shift_dup); + + result.val[1] = vrshlq_s32( + vqdmulhq_s32(vshlq_s32(input_val.val[1], left_shift_dup), multiplier_dup), + right_shift_dup); + + result.val[2] = vrshlq_s32( + vqdmulhq_s32(vshlq_s32(input_val.val[2], left_shift_dup), multiplier_dup), + right_shift_dup); + + result.val[3] = vrshlq_s32( + vqdmulhq_s32(vshlq_s32(input_val.val[3], left_shift_dup), multiplier_dup), + right_shift_dup); + + return result; +} +#endif // USE_NEON +// Double-rounding MultiplyByQuantizedMultiplier +#else +inline int32_t MultiplyByQuantizedMultiplierSmallerThanOneExp( + int32_t x, int32_t quantized_multiplier, int left_shift) { + using gemmlowp::RoundingDivideByPOT; + using gemmlowp::SaturatingRoundingDoublingHighMul; + return RoundingDivideByPOT( + SaturatingRoundingDoublingHighMul(x, quantized_multiplier), -left_shift); +} + +inline int32_t MultiplyByQuantizedMultiplierGreaterThanOne( + int32_t x, int32_t quantized_multiplier, int left_shift) { + using gemmlowp::SaturatingRoundingDoublingHighMul; + return SaturatingRoundingDoublingHighMul(x * (1 << left_shift), + quantized_multiplier); +} + +inline int32_t MultiplyByQuantizedMultiplier(int32_t x, + int32_t quantized_multiplier, + int shift) { + using gemmlowp::RoundingDivideByPOT; + using gemmlowp::SaturatingRoundingDoublingHighMul; + int left_shift = shift > 0 ? shift : 0; + int right_shift = shift > 0 ? 0 : -shift; + return RoundingDivideByPOT(SaturatingRoundingDoublingHighMul( + x * (1 << left_shift), quantized_multiplier), + right_shift); +} + +inline int32_t MultiplyByQuantizedMultiplier(int64_t x, + int32_t quantized_multiplier, + int shift) { + // Inputs: + // - quantized_multiplier has fixed point at bit 31 + // - shift is -31 to +7 (negative for right shift) + // + // Assumptions: The following input ranges are assumed + // - quantize_scale>=0 (the usual range is (1<<30) to (1>>31)-1) + // - scaling is chosen so final scaled result fits in int32_t + // - input x is in the range -(1<<47) <= x < (1<<47) + assert(quantized_multiplier >= 0); + assert(shift >= -31 && shift < 8); + assert(x >= -(static_cast(1) << 47) && + x < (static_cast(1) << 47)); + + int32_t reduced_multiplier = (quantized_multiplier < 0x7FFF0000) + ? ((quantized_multiplier + (1 << 15)) >> 16) + : 0x7FFF; + int total_shift = 15 - shift; + x = (x * (int64_t)reduced_multiplier) + ((int64_t)1 << (total_shift - 1)); + int32_t result = x >> total_shift; + return result; +} + +#ifdef USE_NEON +// Round uses ARM's rounding shift right. +inline int32x4x4_t MultiplyByQuantizedMultiplier4Rows( + int32x4x4_t input_val, int32_t quantized_multiplier, int shift) { + const int left_shift = std::max(shift, 0); + const int right_shift = std::min(shift, 0); + int32x4x4_t result; + + int32x4_t multiplier_dup = vdupq_n_s32(quantized_multiplier); + int32x4_t left_shift_dup = vdupq_n_s32(left_shift); + int32x4_t right_shift_dup = vdupq_n_s32(right_shift); + + result.val[0] = + vrshlq_s32(vqrdmulhq_s32(vshlq_s32(input_val.val[0], left_shift_dup), + multiplier_dup), + right_shift_dup); + + result.val[1] = + vrshlq_s32(vqrdmulhq_s32(vshlq_s32(input_val.val[1], left_shift_dup), + multiplier_dup), + right_shift_dup); + + result.val[2] = + vrshlq_s32(vqrdmulhq_s32(vshlq_s32(input_val.val[2], left_shift_dup), + multiplier_dup), + right_shift_dup); + + result.val[3] = + vrshlq_s32(vqrdmulhq_s32(vshlq_s32(input_val.val[3], left_shift_dup), + multiplier_dup), + right_shift_dup); + + return result; +} +#endif // USE_NEON +#endif // TFLITE_SINGLE_ROUNDING + +template +int CountLeadingZeros(T integer_input) { + static_assert(std::is_unsigned::value, + "Only unsigned integer types handled."); +#if defined(__GNUC__) + return integer_input ? __builtin_clz(integer_input) + : std::numeric_limits::digits; +#else + if (integer_input == 0) { + return std::numeric_limits::digits; + } + + const T one_in_leading_positive = static_cast(1) + << (std::numeric_limits::digits - 1); + int leading_zeros = 0; + while (integer_input < one_in_leading_positive) { + integer_input <<= 1; + ++leading_zeros; + } + return leading_zeros; +#endif +} + +template +inline int CountLeadingSignBits(T integer_input) { + static_assert(std::is_signed::value, "Only signed integer types handled."); +#if defined(__GNUC__) && !defined(__clang__) + return integer_input ? __builtin_clrsb(integer_input) + : std::numeric_limits::digits; +#else + using U = typename std::make_unsigned::type; + return integer_input >= 0 + ? CountLeadingZeros(static_cast(integer_input)) - 1 + : integer_input != std::numeric_limits::min() + ? CountLeadingZeros(2 * static_cast(-integer_input) - 1) + : 0; +#endif +} + +// Use "count leading zeros" helper functions to do a fast Floor(log_2(x)). +template +inline Integer FloorLog2(Integer n) { + static_assert(std::is_integral::value, ""); + static_assert(std::is_signed::value, ""); + static_assert(sizeof(Integer) == 4 || sizeof(Integer) == 8, ""); + TFLITE_CHECK_GT(n, 0); + if (sizeof(Integer) == 4) { + return 30 - CountLeadingSignBits(n); + } else { + return 62 - CountLeadingSignBits(n); + } +} + +// The size of the LUT depends on the type of input. For uint8 and int8 inputs +// we use a 256 entries LUT to map all the values in the (u)int8 range. For +// int16 inputs the high 9 bits are used for indexing and the 7 remaining bits +// are used for interpolation. We thus use a 513-entries LUT for int16 cases, +// 512 for the 9-bit indexing and 1 extra entry to interpolate the last value. +template +constexpr int LUTSize() { + static_assert(std::is_same::value || + std::is_same::value || + std::is_same::value, + "Only LUTs with uint8, int8 or int16 inputs are supported."); + // As per c++11: constexpr methods cannot have more than one return statement. + return (std::is_same::value || std::is_same::value) + ? 256 + : 513; +} + +// Use the same LUT generation code for both uint8_t and int8_t. Int8_t indexes +// will be directly casted to uint8_t, the int8 LUT will thus be ordered as [0, +// 1, ..., 127, -128, ..., -2, -1] instead of [-128, -127, ..., -1, 0, 1, ..., +// 126, 127]. +template +inline typename std::enable_if::value || + std::is_same::value, + void>::type +LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale, + int32_t output_zero_point, float (*transform)(float), T* lut) { + uint8_t* lut_uint8 = reinterpret_cast(lut); + const float inverse_scale = 1 / output_scale; + int32_t maxval = std::numeric_limits::max(); + int32_t minval = std::numeric_limits::min(); + for (int32_t val = minval; val <= maxval; ++val) { + const float dequantized = input_scale * (val - input_zero_point); + const float transformed = transform(dequantized); + const float rescaled = std::round(transformed * inverse_scale); + const int32_t quantized = + static_cast(rescaled + output_zero_point); + lut_uint8[static_cast(static_cast(val))] = static_cast( + static_cast(std::max(std::min(maxval, quantized), minval))); + } +} + +// Keep floating-point type configurable for backward compatibility. float +// should be used for FloatT by default. +template +inline typename std::enable_if::value, void>::type +LUTPopulate(FloatT input_scale, int32_t input_zero_point, FloatT output_scale, + int32_t output_zero_point, FloatT (*transform)(FloatT), T* lut) { + static_assert(std::is_floating_point::value, + "FloatT must be a floating-point type."); + const FloatT input_min = + input_scale * (std::numeric_limits::min() - input_zero_point); + const FloatT input_max = + input_scale * (std::numeric_limits::max() - input_zero_point); + const FloatT output_min = + output_scale * (std::numeric_limits::min() - output_zero_point); + const FloatT output_max = + output_scale * (std::numeric_limits::max() - output_zero_point); + + const int nb_steps = 512; + const FloatT step = (input_max - input_min) / nb_steps; + const FloatT half_step = step / 2; + const FloatT output_scaling_inv = + static_cast(std::numeric_limits::max() - + std::numeric_limits::min() + 1) / + (output_max - output_min); + const FloatT table_min = static_cast(std::numeric_limits::min()); + const FloatT table_max = static_cast(std::numeric_limits::max()); + + for (int i = 0; i < nb_steps; i++) { + const FloatT val = transform(input_min + i * step); + const FloatT val_midpoint = transform(input_min + i * step + half_step); + const FloatT val_next = transform(input_min + (i + 1) * step); + + const FloatT sample_val = TfLiteRound(val * output_scaling_inv); + const FloatT midpoint_interp_val = + TfLiteRound((val_next * output_scaling_inv + + TfLiteRound(val * output_scaling_inv)) / + 2); + const FloatT midpoint_val = TfLiteRound(val_midpoint * output_scaling_inv); + const FloatT midpoint_err = midpoint_interp_val - midpoint_val; + const FloatT bias = TfLiteRound(midpoint_err / 2); + + lut[i] = static_cast(std::min( + std::max(sample_val - bias, table_min), table_max)); + } + + lut[nb_steps] = static_cast(std::min( + std::max(TfLiteRound(transform(input_max) * output_scaling_inv), + table_min), + table_max)); +} + +template +inline typename std::enable_if::value, void>::type +LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale, + int32_t output_zero_point, float (*transform)(float), T* lut) { + LUTPopulate(input_scale, input_zero_point, output_scale, + output_zero_point, transform, lut); +} + +// Deprecated and will be removed in future, please use LUTPopulate instead +template +inline void gen_lut(FloatT (*func)(FloatT), FloatT input_min, FloatT input_max, + FloatT output_min, FloatT output_max, LutOutT* lut) { + static_assert(std::is_same::value, + "Input and output type of the LUT must be the same."); + static_assert(std::is_same::value, + "Only int16_t type LUT are supported."); + static_assert(std::is_same::value, + "Only float type is supported for FloatT."); + using T = LutInT; + + const auto zero_point = [](float min, float max, float scale) { + // Symmetric int16 LUT, we know the zero-point will not overflow an int32_t + // and zero-point from min will be the same as from max. + return static_cast( + static_cast(std::numeric_limits::min()) - min / scale); + }; + + const float scale = static_cast(std::numeric_limits::max() - + std::numeric_limits::min()); + const float input_scale = (input_max - input_min) / scale; + const FloatT output_scale = (output_max - output_min) / scale; + const int32_t input_zero_point = + zero_point(input_min, input_max, input_scale); + const int32_t output_zero_point = + zero_point(output_min, output_max, output_scale); + + return LUTPopulate(input_scale, input_zero_point, output_scale, + output_zero_point, func, lut); +} + +// int16_t -> int16_t table lookup with interpolation +// LUT must have 513 values +inline int16_t LUTLookup(int16_t value, const int16_t* lut) { + // 512 base values, lut[513] is only used to calculate the slope + const uint16_t index = static_cast(256 + (value >> 7)); + assert(index < 512 && "LUT index out of range."); + const int16_t offset = value & 0x7f; + + // Base and slope are Q0.x + const int16_t base = lut[index]; + const int16_t slope = lut[index + 1] - lut[index]; + + // Q0.x * Q0.7 = Q0.(x + 7) + // Round and convert from Q0.(x + 7) to Q0.x + const int delta = (slope * offset + 64) >> 7; + + // Q0.15 + Q0.15 + return static_cast(base + delta); +} + +// int8_t -> int8_t table lookup without interpolation +// LUT must have 256 values +// LUTPopulate has ordered the LUT so that indexing it with an +// int8_t is just done by casting it to an uint8_t. +inline int8_t LUTLookup(int8_t value, const int8_t* lut) { + return lut[static_cast(value)]; +} + +// uint8_t -> uint8_t table lookup without interpolation +// LUT must have 256 values +inline uint8_t LUTLookup(uint8_t value, const uint8_t* lut) { + return lut[value]; +} + +// Table of sigmoid(i/24) at 0.16 format - 256 elements. + +// We use combined sigmoid and tanh look-up table, since +// tanh(x) = 2*sigmoid(2*x) -1. +// Both functions are symmetric, so the LUT table is only needed +// for the absolute value of the input. +static const uint16_t sigmoid_table_uint16[256] = { + 32768, 33451, 34133, 34813, 35493, 36169, 36843, 37513, 38180, 38841, 39498, + 40149, 40794, 41432, 42064, 42688, 43304, 43912, 44511, 45102, 45683, 46255, + 46817, 47369, 47911, 48443, 48964, 49475, 49975, 50464, 50942, 51409, 51865, + 52311, 52745, 53169, 53581, 53983, 54374, 54755, 55125, 55485, 55834, 56174, + 56503, 56823, 57133, 57433, 57724, 58007, 58280, 58544, 58800, 59048, 59288, + 59519, 59743, 59959, 60168, 60370, 60565, 60753, 60935, 61110, 61279, 61441, + 61599, 61750, 61896, 62036, 62172, 62302, 62428, 62549, 62666, 62778, 62886, + 62990, 63090, 63186, 63279, 63368, 63454, 63536, 63615, 63691, 63765, 63835, + 63903, 63968, 64030, 64090, 64148, 64204, 64257, 64308, 64357, 64405, 64450, + 64494, 64536, 64576, 64614, 64652, 64687, 64721, 64754, 64786, 64816, 64845, + 64873, 64900, 64926, 64950, 64974, 64997, 65019, 65039, 65060, 65079, 65097, + 65115, 65132, 65149, 65164, 65179, 65194, 65208, 65221, 65234, 65246, 65258, + 65269, 65280, 65291, 65301, 65310, 65319, 65328, 65337, 65345, 65352, 65360, + 65367, 65374, 65381, 65387, 65393, 65399, 65404, 65410, 65415, 65420, 65425, + 65429, 65433, 65438, 65442, 65445, 65449, 65453, 65456, 65459, 65462, 65465, + 65468, 65471, 65474, 65476, 65479, 65481, 65483, 65485, 65488, 65489, 65491, + 65493, 65495, 65497, 65498, 65500, 65501, 65503, 65504, 65505, 65507, 65508, + 65509, 65510, 65511, 65512, 65513, 65514, 65515, 65516, 65517, 65517, 65518, + 65519, 65520, 65520, 65521, 65522, 65522, 65523, 65523, 65524, 65524, 65525, + 65525, 65526, 65526, 65526, 65527, 65527, 65528, 65528, 65528, 65529, 65529, + 65529, 65529, 65530, 65530, 65530, 65530, 65531, 65531, 65531, 65531, 65531, + 65532, 65532, 65532, 65532, 65532, 65532, 65533, 65533, 65533, 65533, 65533, + 65533, 65533, 65533, 65534, 65534, 65534, 65534, 65534, 65534, 65534, 65534, + 65534, 65534, 65535}; + +// TODO(b/77858996): Add these to gemmlowp. +template +IntegerType SaturatingAddNonGemmlowp(IntegerType a, IntegerType b) { + static_assert(std::is_same::value, "unimplemented"); + return a; +} + +template <> +inline std::int32_t SaturatingAddNonGemmlowp(std::int32_t a, std::int32_t b) { + std::int64_t a64 = a; + std::int64_t b64 = b; + std::int64_t sum = a64 + b64; + return static_cast(std::min( + static_cast(std::numeric_limits::max()), + std::max( + static_cast(std::numeric_limits::min()), + sum))); +} + +template +gemmlowp::FixedPoint SaturatingAddNonGemmlowp( + gemmlowp::FixedPoint a, + gemmlowp::FixedPoint b) { + return gemmlowp::FixedPoint::FromRaw( + SaturatingAddNonGemmlowp(a.raw(), b.raw())); +} + +template +IntegerType SaturatingSub(IntegerType a, IntegerType b) { + static_assert(std::is_same::value, "unimplemented"); + return a; +} + +template <> +inline std::int16_t SaturatingSub(std::int16_t a, std::int16_t b) { + std::int32_t a32 = a; + std::int32_t b32 = b; + std::int32_t diff = a32 - b32; + return static_cast( + std::min(static_cast(32767), + std::max(static_cast(-32768), diff))); +} + +template <> +inline std::int32_t SaturatingSub(std::int32_t a, std::int32_t b) { + std::int64_t a64 = a; + std::int64_t b64 = b; + std::int64_t diff = a64 - b64; + return static_cast(std::min( + static_cast(std::numeric_limits::max()), + std::max( + static_cast(std::numeric_limits::min()), + diff))); +} + +template +gemmlowp::FixedPoint SaturatingSub( + gemmlowp::FixedPoint a, + gemmlowp::FixedPoint b) { + return gemmlowp::FixedPoint::FromRaw( + SaturatingSub(a.raw(), b.raw())); +} +// End section to be moved to gemmlowp. + +template +IntegerType SaturatingRoundingMultiplyByPOTParam(IntegerType x, int exponent) { + if (exponent == 0) { + return x; + } + using ScalarIntegerType = + typename gemmlowp::FixedPointRawTypeTraits::ScalarRawType; + const IntegerType min = + gemmlowp::Dup(std::numeric_limits::min()); + const IntegerType max = + gemmlowp::Dup(std::numeric_limits::max()); + const int ScalarIntegerTypeBits = 8 * sizeof(ScalarIntegerType); + + const std::int32_t threshold = + ((1 << (ScalarIntegerTypeBits - 1 - exponent)) - 1); + const IntegerType positive_mask = + gemmlowp::MaskIfGreaterThan(x, gemmlowp::Dup(threshold)); + const IntegerType negative_mask = + gemmlowp::MaskIfLessThan(x, gemmlowp::Dup(-threshold)); + + IntegerType result = gemmlowp::ShiftLeft(x, exponent); + result = gemmlowp::SelectUsingMask(positive_mask, max, result); + result = gemmlowp::SelectUsingMask(negative_mask, min, result); + return result; +} + +// If we want to leave IntegerBits fixed, then multiplication +// by a power of two has to be saturating/rounding, not exact anymore. +template +gemmlowp::FixedPoint +SaturatingRoundingMultiplyByPOTParam( + gemmlowp::FixedPoint a, int exponent) { + return gemmlowp::FixedPoint::FromRaw( + SaturatingRoundingMultiplyByPOTParam(a.raw(), exponent)); +} + +// Convert int32_t multiplier to int16_t with rounding. +inline void DownScaleInt32ToInt16Multiplier(int32_t multiplier_int32_t, + int16_t* multiplier_int16_t) { + TFLITE_DCHECK_GE(multiplier_int32_t, 0); + static constexpr int32_t kRoundingOffset = 1 << 15; + if (multiplier_int32_t >= + std::numeric_limits::max() - kRoundingOffset) { + *multiplier_int16_t = std::numeric_limits::max(); + return; + } + const int32_t result = (multiplier_int32_t + kRoundingOffset) >> 16; + TFLITE_DCHECK_LE(result << 16, multiplier_int32_t + kRoundingOffset); + TFLITE_DCHECK_GT(result << 16, multiplier_int32_t - kRoundingOffset); + *multiplier_int16_t = result; + TFLITE_DCHECK_EQ(*multiplier_int16_t, result); +} + +// Minimum output bits to accommodate log of maximum input range. It actually +// does not matter if one considers, say, [-64,64] or [-64,64). +// +// For example, run this through Octave: +// [0:127; ... +// ceil(log(abs( log(2.^(0:127))+1 ))/log(2)); ... +// ceil(log(abs( log(2.^(0:127))+1 ))/log(2))] +constexpr int min_log_x_output_bits(int input_bits) { + return input_bits > 90 ? 7 + : input_bits > 44 ? 6 + : input_bits > 21 ? 5 + : input_bits > 10 ? 4 + : input_bits > 4 ? 3 + : input_bits > 1 ? 2 + : 1; +} + +// Although currently the name of this function says that it cannot handle +// values less than 1, in practice it can handle as low as 1/x_max, where +// x_max is the largest representable input. In other words, the output range +// is symmetric. +template +inline gemmlowp::FixedPoint +log_x_for_x_greater_than_or_equal_to_1_impl( + gemmlowp::FixedPoint input_val) { + // assert(__builtin_clz(0u) >= std::numeric_limits::digits - 1); + // assert(__builtin_clz(0u) <= std::numeric_limits::digits); + using FixedPoint0 = gemmlowp::FixedPoint; + // The reason for accumulating the result with an extra bit of headroom is + // that z_pow_2_adj * log_2 might be saturated, and adding num_scaled * + // recip_denom will otherwise introduce an error. + static constexpr int kAccumIntegerBits = OutputIntegerBits + 1; + using FixedPointAccum = gemmlowp::FixedPoint; + + const FixedPoint0 log_2 = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 1488522236, std::log(2.0)); + const FixedPoint0 sqrt_sqrt_half = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 1805811301, std::sqrt(std::sqrt(0.5))); + const FixedPoint0 sqrt_half = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 1518500250, std::sqrt(0.5)); + const FixedPoint0 one_quarter = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(FixedPoint0, 536870912, 1.0 / 4.0); + + const FixedPoint0 alpha_n = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 117049297, 11.0 / 240.0 * std::sqrt(std::sqrt(2.0))); + const FixedPoint0 alpha_d = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 127690142, 1.0 / 20.0 * std::sqrt(std::sqrt(2.0))); + const FixedPoint0 alpha_i = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 1057819769, + 2.0 / std::sqrt(std::sqrt(2.0)) - std::sqrt(std::sqrt(2.0))); + const FixedPoint0 alpha_f = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( + FixedPoint0, 638450708, 1.0 / 4.0 * std::sqrt(std::sqrt(2.0))); + + const FixedPointAccum shifted_quarter = + gemmlowp::Rescale(one_quarter); + + // Reinterpret the input value as Q0.31, because we will figure out the + // required shift "ourselves" instead of using, say, Rescale. + FixedPoint0 z_a = FixedPoint0::FromRaw(input_val.raw()); + // z_a_pow_2 = input_integer_bits - z_a_headroom; + int z_a_headroom_plus_1 = CountLeadingZeros(static_cast(z_a.raw())); + FixedPoint0 r_a_tmp = + SaturatingRoundingMultiplyByPOTParam(z_a, (z_a_headroom_plus_1 - 1)); + const int32_t r_a_raw = + SaturatingRoundingMultiplyByPOTParam((r_a_tmp * sqrt_half).raw(), 1); + // z_pow_2_adj = max(z_pow_2_a - 0.75, z_pow_2_b - 0.25); + // z_pow_2_adj = max(InputIntegerBits - z_a_headroom_plus_1 + 0.25, + // InputIntegerBits - z_b_headroom - 0.25); + const FixedPointAccum z_a_pow_2_adj = SaturatingAddNonGemmlowp( + FixedPointAccum::FromRaw(SaturatingRoundingMultiplyByPOTParam( + static_cast(InputIntegerBits - z_a_headroom_plus_1), + 31 - kAccumIntegerBits)), + shifted_quarter); + + // z_b is treated like z_a, but premultiplying by sqrt(0.5). + FixedPoint0 z_b = z_a * sqrt_half; + int z_b_headroom = CountLeadingZeros(static_cast(z_b.raw())) - 1; + const int32_t r_b_raw = + SaturatingRoundingMultiplyByPOTParam(z_a.raw(), z_b_headroom); + const FixedPointAccum z_b_pow_2_adj = SaturatingSub( + FixedPointAccum::FromRaw(SaturatingRoundingMultiplyByPOTParam( + static_cast(InputIntegerBits - z_b_headroom), + 31 - kAccumIntegerBits)), + shifted_quarter); + + const FixedPoint0 r = FixedPoint0::FromRaw(std::min(r_a_raw, r_b_raw)); + const FixedPointAccum z_pow_2_adj = FixedPointAccum::FromRaw( + std::max(z_a_pow_2_adj.raw(), z_b_pow_2_adj.raw())); + + const FixedPoint0 p = gemmlowp::RoundingHalfSum(r, sqrt_sqrt_half); + FixedPoint0 q = r - sqrt_sqrt_half; + q = q + q; + + const FixedPoint0 common_sq = q * q; + const FixedPoint0 num = q * r + q * common_sq * alpha_n; + const FixedPoint0 denom_minus_one_0 = + p * (alpha_i + q + alpha_d * common_sq) + alpha_f * q; + const FixedPoint0 recip_denom = + one_over_one_plus_x_for_x_in_0_1(denom_minus_one_0); + + const FixedPointAccum num_scaled = gemmlowp::Rescale(num); + return gemmlowp::Rescale(z_pow_2_adj * log_2 + + num_scaled * recip_denom); +} + +template +inline gemmlowp::FixedPoint +log_x_for_x_greater_than_or_equal_to_1( + gemmlowp::FixedPoint input_val) { + static_assert( + OutputIntegerBits >= min_log_x_output_bits(InputIntegerBits), + "Output integer bits must be sufficient to accommodate logs of inputs."); + return log_x_for_x_greater_than_or_equal_to_1_impl( + input_val); +} + +inline int32_t GetReciprocal(int32_t x, int x_integer_digits, + int* num_bits_over_unit) { + int headroom_plus_one = CountLeadingZeros(static_cast(x)); + // This is the number of bits to the left of the binary point above 1.0. + // Consider x=1.25. In that case shifted_scale=0.8 and + // no later adjustment will be needed. + *num_bits_over_unit = x_integer_digits - headroom_plus_one; + const int32_t shifted_sum_minus_one = + static_cast((static_cast(x) << headroom_plus_one) - + (static_cast(1) << 31)); + + gemmlowp::FixedPoint shifted_scale = + gemmlowp::one_over_one_plus_x_for_x_in_0_1( + gemmlowp::FixedPoint::FromRaw(shifted_sum_minus_one)); + return shifted_scale.raw(); +} + +inline void GetInvSqrtQuantizedMultiplierExp(int32_t input, int reverse_shift, + int32_t* output_inv_sqrt, + int* output_shift) { + TFLITE_DCHECK_GE(input, 0); + if (input <= 1) { + // Handle the input value 1 separately to avoid overflow in that case + // in the general computation below (b/143972021). Also handle 0 as if it + // were a 1. 0 is an invalid input here (divide by zero) and 1 is a valid + // but rare/unrealistic input value. We can expect both to occur in some + // incompletely trained models, but probably not in fully trained models. + *output_inv_sqrt = std::numeric_limits::max(); + *output_shift = 0; + return; + } + TFLITE_DCHECK_GT(input, 1); + *output_shift = 11; + while (input >= (1 << 29)) { + input /= 4; + ++*output_shift; + } + const unsigned max_left_shift_bits = + CountLeadingZeros(static_cast(input)) - 1; + const unsigned max_left_shift_bit_pairs = max_left_shift_bits / 2; + const unsigned left_shift_bit_pairs = max_left_shift_bit_pairs - 1; + *output_shift -= left_shift_bit_pairs; + input <<= 2 * left_shift_bit_pairs; + TFLITE_DCHECK_GE(input, (1 << 27)); + TFLITE_DCHECK_LT(input, (1 << 29)); + using gemmlowp::FixedPoint; + using gemmlowp::Rescale; + using gemmlowp::SaturatingRoundingMultiplyByPOT; + // Using 3 integer bits gives us enough room for the internal arithmetic in + // this Newton-Raphson iteration. + using F3 = FixedPoint; + using F0 = FixedPoint; + const F3 fixedpoint_input = F3::FromRaw(input >> 1); + const F3 fixedpoint_half_input = + SaturatingRoundingMultiplyByPOT<-1>(fixedpoint_input); + const F3 fixedpoint_half_three = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F3, (1 << 28) + (1 << 27), 1.5); + // Newton-Raphson iteration + // Naive unoptimized starting guess: x = 1 + F3 x = F3::One(); + // Naive unoptimized number of iterations: 5 + for (int i = 0; i < 5; i++) { + const F3 x3 = Rescale<3>(x * x * x); + x = Rescale<3>(fixedpoint_half_three * x - fixedpoint_half_input * x3); + } + const F0 fixedpoint_half_sqrt_2 = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F0, 1518500250, std::sqrt(2.) / 2.); + x = x * fixedpoint_half_sqrt_2; + *output_inv_sqrt = x.raw(); + if (*output_shift < 0) { + *output_inv_sqrt <<= -*output_shift; + *output_shift = 0; + } + // Convert right shift (right is positive) to left shift. + *output_shift *= reverse_shift; +} + +// DO NOT USE THIS STRUCT FOR NEW FUNCTIONALITY BEYOND IMPLEMENTING +// BROADCASTING. +// +// NdArrayDesc describes the shape and memory layout of an N-dimensional +// rectangular array of numbers. +// +// NdArrayDesc is basically identical to Dims defined in types.h. +// However, as Dims is to be deprecated, this class exists as an adaptor +// to enable simple unoptimized implementations of element-wise broadcasting +// operations. +template +struct NdArrayDesc { + // The "extent" of each dimension. Indices along dimension d must be in the + // half-open interval [0, extents[d]). + int extents[N]; + + // The number of *elements* (not bytes) between consecutive indices of each + // dimension. + int strides[N]; +}; + +// DO NOT USE THIS FUNCTION FOR NEW FUNCTIONALITY BEYOND IMPLEMENTING +// BROADCASTING. +// +// Same as Offset(), except takes as NdArrayDesc instead of Dims. +inline int SubscriptToIndex(const NdArrayDesc<4>& desc, int i0, int i1, int i2, + int i3) { + TFLITE_DCHECK(i0 >= 0 && i0 < desc.extents[0]); + TFLITE_DCHECK(i1 >= 0 && i1 < desc.extents[1]); + TFLITE_DCHECK(i2 >= 0 && i2 < desc.extents[2]); + TFLITE_DCHECK(i3 >= 0 && i3 < desc.extents[3]); + return i0 * desc.strides[0] + i1 * desc.strides[1] + i2 * desc.strides[2] + + i3 * desc.strides[3]; +} + +inline int SubscriptToIndex(const NdArrayDesc<5>& desc, int indexes[5]) { + return indexes[0] * desc.strides[0] + indexes[1] * desc.strides[1] + + indexes[2] * desc.strides[2] + indexes[3] * desc.strides[3] + + indexes[4] * desc.strides[4]; +} + +inline int SubscriptToIndex(const NdArrayDesc<8>& desc, int indexes[8]) { + return indexes[0] * desc.strides[0] + indexes[1] * desc.strides[1] + + indexes[2] * desc.strides[2] + indexes[3] * desc.strides[3] + + indexes[4] * desc.strides[4] + indexes[5] * desc.strides[5] + + indexes[6] * desc.strides[6] + indexes[7] * desc.strides[7]; +} + +// Given the dimensions of the operands for an element-wise binary broadcast, +// adjusts them so that they can be directly iterated over with simple loops. +// Returns the adjusted dims as instances of NdArrayDesc in 'desc0_out' and +// 'desc1_out'. 'desc0_out' and 'desc1_out' cannot be nullptr. +// +// This function assumes that the two input shapes are compatible up to +// broadcasting and the shorter one has already been prepended with 1s to be the +// same length. E.g., if shape0 is (1, 16, 16, 64) and shape1 is (1, 64), +// shape1 must already have been prepended to be (1, 1, 1, 64). Recall that +// Dims refer to shapes in reverse order. In this case, input0_dims will be +// (64, 16, 16, 1) and input1_dims will be (64, 1, 1, 1). +// +// When two shapes are compatible up to broadcasting, for each dimension d, +// the input extents are either equal, or one of them is 1. +// +// This function performs the following for each dimension d: +// - If the extents are equal, then do nothing since the loop that walks over +// both of the input arrays is correct. +// - Otherwise, one (and only one) of the extents must be 1. Say extent0 is 1 +// and extent1 is e1. Then set extent0 to e1 and stride0 *to 0*. This allows +// array0 to be referenced *at any index* in dimension d and still access the +// same slice. +template +inline void NdArrayDescsForElementwiseBroadcast(const Dims& input0_dims, + const Dims& input1_dims, + NdArrayDesc* desc0_out, + NdArrayDesc* desc1_out) { + TFLITE_DCHECK(desc0_out != nullptr); + TFLITE_DCHECK(desc1_out != nullptr); + + // Copy dims to desc. + for (int i = 0; i < N; ++i) { + desc0_out->extents[i] = input0_dims.sizes[i]; + desc0_out->strides[i] = input0_dims.strides[i]; + desc1_out->extents[i] = input1_dims.sizes[i]; + desc1_out->strides[i] = input1_dims.strides[i]; + } + + // Walk over each dimension. If the extents are equal do nothing. + // Otherwise, set the desc with extent 1 to have extent equal to the other and + // stride 0. + for (int i = 0; i < N; ++i) { + const int extent0 = ArraySize(input0_dims, i); + const int extent1 = ArraySize(input1_dims, i); + if (extent0 != extent1) { + if (extent0 == 1) { + desc0_out->strides[i] = 0; + desc0_out->extents[i] = extent1; + } else { + TFLITE_DCHECK_EQ(extent1, 1); + desc1_out->strides[i] = 0; + desc1_out->extents[i] = extent0; + } + } + } +} + +// Copies dims to desc, calculating strides. +template +inline void CopyDimsToDesc(const RuntimeShape& input_shape, + NdArrayDesc* desc_out) { + int desc_stride = 1; + for (int i = N - 1; i >= 0; --i) { + desc_out->extents[i] = input_shape.Dims(i); + desc_out->strides[i] = desc_stride; + desc_stride *= input_shape.Dims(i); + } +} + +template +inline void NdArrayDescsForElementwiseBroadcast( + const RuntimeShape& input0_shape, const RuntimeShape& input1_shape, + NdArrayDesc* desc0_out, NdArrayDesc* desc1_out) { + TFLITE_DCHECK(desc0_out != nullptr); + TFLITE_DCHECK(desc1_out != nullptr); + + auto extended_input0_shape = RuntimeShape::ExtendedShape(N, input0_shape); + auto extended_input1_shape = RuntimeShape::ExtendedShape(N, input1_shape); + + // Copy dims to desc, calculating strides. + CopyDimsToDesc(extended_input0_shape, desc0_out); + CopyDimsToDesc(extended_input1_shape, desc1_out); + + // Walk over each dimension. If the extents are equal do nothing. + // Otherwise, set the desc with extent 1 to have extent equal to the other and + // stride 0. + for (int i = 0; i < N; ++i) { + const int extent0 = extended_input0_shape.Dims(i); + const int extent1 = extended_input1_shape.Dims(i); + if (extent0 != extent1) { + if (extent0 == 1) { + desc0_out->strides[i] = 0; + desc0_out->extents[i] = extent1; + } else { + TFLITE_DCHECK_EQ(extent1, 1); + desc1_out->strides[i] = 0; + desc1_out->extents[i] = extent0; + } + } + } +} + +template +inline void NdArrayDescsForElementwiseBroadcast( + const RuntimeShape& input0_shape, const RuntimeShape& input1_shape, + const RuntimeShape& input2_shape, NdArrayDesc* desc0_out, + NdArrayDesc* desc1_out, NdArrayDesc* desc2_out) { + TFLITE_DCHECK(desc0_out != nullptr); + TFLITE_DCHECK(desc1_out != nullptr); + TFLITE_DCHECK(desc2_out != nullptr); + + auto extended_input0_shape = RuntimeShape::ExtendedShape(N, input0_shape); + auto extended_input1_shape = RuntimeShape::ExtendedShape(N, input1_shape); + auto extended_input2_shape = RuntimeShape::ExtendedShape(N, input2_shape); + + // Copy dims to desc, calculating strides. + CopyDimsToDesc(extended_input0_shape, desc0_out); + CopyDimsToDesc(extended_input1_shape, desc1_out); + CopyDimsToDesc(extended_input2_shape, desc2_out); + + // Walk over each dimension. If the extents are equal do nothing. + // Otherwise, set the desc with extent 1 to have extent equal to the other and + // stride 0. + for (int i = 0; i < N; ++i) { + const int extent0 = extended_input0_shape.Dims(i); + const int extent1 = extended_input1_shape.Dims(i); + const int extent2 = extended_input2_shape.Dims(i); + + int extent = extent0; + if (extent1 != 1) extent = extent1; + if (extent2 != 1) extent = extent2; + + TFLITE_DCHECK(extent0 == 1 || extent0 == extent); + TFLITE_DCHECK(extent1 == 1 || extent1 == extent); + TFLITE_DCHECK(extent2 == 1 || extent2 == extent); + + if (!(extent0 == extent1 && extent1 == extent2)) { + if (extent0 == 1) { + desc0_out->strides[i] = 0; + desc0_out->extents[i] = extent; + } + if (extent1 == 1) { + desc1_out->strides[i] = 0; + desc1_out->extents[i] = extent; + } + if (extent2 == 1) { + desc2_out->strides[i] = 0; + desc2_out->extents[i] = extent; + } + } + } +} + +// Detailed implementation of NDOpsHelper, the indexes must be a zero array. +// This implementation is equivalent to N nested loops. Ex, if N=4, it can be +// re-writen as: +// for (int b = 0; b < output.extents[0]; ++b) { +// for (int y = 0; y < output.extents[1]; ++y) { +// for (int x = 0; x < output.extents[2]; ++x) { +// for (int c = 0; c < output.extents[3]; ++c) { +// calc({b,y,x,c}); +// } +// } +// } +// } +template +typename std::enable_if::type NDOpsHelperImpl( + const NdArrayDesc& output, const Calc& calc, int indexes[N]) { + for (indexes[DIM] = 0; indexes[DIM] < output.extents[DIM]; ++indexes[DIM]) { + NDOpsHelperImpl(output, calc, indexes); + } +} + +template +typename std::enable_if::type NDOpsHelperImpl( + const NdArrayDesc& output, const Calc& calc, int indexes[N]) { + for (indexes[DIM] = 0; indexes[DIM] < output.extents[DIM]; ++indexes[DIM]) { + calc(indexes); + } +} + +// Execute the calc function in the innermost iteration based on the shape of +// the output. The calc function should take a single argument of type int[N]. +template +inline void NDOpsHelper(const NdArrayDesc& output, const Calc& calc) { + int indexes[N] = {0}; + NDOpsHelperImpl(output, calc, indexes); +} +// Copied from gemmlowp::RoundDown when we dropped direct dependency on +// gemmlowp. +// +// Returns the runtime argument rounded down to the nearest multiple of +// the fixed Modulus. +template +Integer RoundDown(Integer i) { + return i - (i % Modulus); +} + +// Copied from gemmlowp::RoundUp when we dropped direct dependency on +// gemmlowp. +// +// Returns the runtime argument rounded up to the nearest multiple of +// the fixed Modulus. +template +Integer RoundUp(Integer i) { + return RoundDown(i + Modulus - 1); +} + +// Copied from gemmlowp::CeilQuotient when we dropped direct dependency on +// gemmlowp. +// +// Returns the quotient a / b rounded up ('ceil') to the nearest integer. +template +Integer CeilQuotient(Integer a, Integer b) { + return (a + b - 1) / b; +} + +// This function is a copy of gemmlowp::HowManyThreads, copied when we dropped +// the direct dependency of internal/optimized/ on gemmlowp. +// +// It computes a reasonable number of threads to use for a GEMM of shape +// (rows, cols, depth). +// +// TODO(b/131910176): get rid of this function by switching each call site +// to its own more sensible logic for its own workload. +template +inline int LegacyHowManyThreads(int max_num_threads, int rows, int cols, + int depth) { + // Early-exit in the default case where multi-threading is disabled. + if (max_num_threads == 1) { + return 1; + } + + // Ensure that each thread has KernelRows rows to process, if at all possible. + int thread_count = std::min(max_num_threads, rows / KernelRows); + + // Limit the number of threads according to the overall size of the problem. + if (thread_count > 1) { + // Empirically determined value. + static constexpr std::uint64_t min_cubic_size_per_thread = 64 * 1024; + + // We can only multiply two out of three sizes without risking overflow + const std::uint64_t cubic_size = + std::uint64_t(rows) * std::uint64_t(cols) * std::uint64_t(depth); + + thread_count = std::min( + thread_count, static_cast(cubic_size / min_cubic_size_per_thread)); + } + + if (thread_count < 1) { + thread_count = 1; + } + + assert(thread_count > 0 && thread_count <= max_num_threads); + return thread_count; +} + +template +void optimized_ops_preload_l1_stream(const T* ptr) { +#ifdef __GNUC__ + // builtin offered by GCC-compatible compilers including clang + __builtin_prefetch(ptr, /* 0 means read */ 0, /* 0 means no locality */ 0); +#else + (void)ptr; +#endif +} + +template +void optimized_ops_preload_l1_keep(const T* ptr) { +#ifdef __GNUC__ + // builtin offered by GCC-compatible compilers including clang + __builtin_prefetch(ptr, /* 0 means read */ 0, /* 3 means high locality */ 3); +#else + (void)ptr; +#endif +} + +template +void optimized_ops_prefetch_write_l1_keep(const T* ptr) { +#ifdef __GNUC__ + // builtin offered by GCC-compatible compilers including clang + __builtin_prefetch(ptr, /* 1 means write */ 1, /* 3 means high locality */ 3); +#else + (void)ptr; +#endif +} + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_COMMON_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/compatibility.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/compatibility.h new file mode 100644 index 000000000..0d7f9d635 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/compatibility.h @@ -0,0 +1,122 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ + +#include + +#include "tensorflow/lite/kernels/op_macros.h" + +#ifndef TFLITE_DCHECK +#define TFLITE_DCHECK(condition) (condition) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +#ifndef TFLITE_DCHECK_EQ +#define TFLITE_DCHECK_EQ(x, y) ((x) == (y)) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +#ifndef TFLITE_DCHECK_NE +#define TFLITE_DCHECK_NE(x, y) ((x) != (y)) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +#ifndef TFLITE_DCHECK_GE +#define TFLITE_DCHECK_GE(x, y) ((x) >= (y)) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +#ifndef TFLITE_DCHECK_GT +#define TFLITE_DCHECK_GT(x, y) ((x) > (y)) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +#ifndef TFLITE_DCHECK_LE +#define TFLITE_DCHECK_LE(x, y) ((x) <= (y)) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +#ifndef TFLITE_DCHECK_LT +#define TFLITE_DCHECK_LT(x, y) ((x) < (y)) ? (void)0 : TFLITE_ASSERT_FALSE +#endif + +// TODO(ahentz): Clean up: We should stick to the DCHECK versions. +#ifndef TFLITE_CHECK +#define TFLITE_CHECK(condition) (condition) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef TFLITE_CHECK_EQ +#define TFLITE_CHECK_EQ(x, y) ((x) == (y)) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef TFLITE_CHECK_NE +#define TFLITE_CHECK_NE(x, y) ((x) != (y)) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef TFLITE_CHECK_GE +#define TFLITE_CHECK_GE(x, y) ((x) >= (y)) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef TFLITE_CHECK_GT +#define TFLITE_CHECK_GT(x, y) ((x) > (y)) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef TFLITE_CHECK_LE +#define TFLITE_CHECK_LE(x, y) ((x) <= (y)) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef TFLITE_CHECK_LT +#define TFLITE_CHECK_LT(x, y) ((x) < (y)) ? (void)0 : TFLITE_ABORT +#endif + +#ifndef ARDUINO +// TODO(b/162019032): Consider removing these type-aliases. +using int8 = std::int8_t; +using uint8 = std::uint8_t; +using int16 = std::int16_t; +using uint16 = std::uint16_t; +using int32 = std::int32_t; +using uint32 = std::uint32_t; +#endif // !defined(ARDUINO) + +// Allow for cross-compiler usage of function signatures - currently used for +// specifying named RUY profiler regions in templated methods. +#if defined(_MSC_VER) +#define TFLITE_PRETTY_FUNCTION __FUNCSIG__ +#elif defined(__GNUC__) +#define TFLITE_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#else +#define TFLITE_PRETTY_FUNCTION __func__ +#endif + +// TFLITE_DEPRECATED() +// +// Duplicated from absl/base/macros.h to avoid pulling in that library. +// Marks a deprecated class, struct, enum, function, method and variable +// declarations. The macro argument is used as a custom diagnostic message (e.g. +// suggestion of a better alternative). +// +// Example: +// +// class TFLITE_DEPRECATED("Use Bar instead") Foo {...}; +// TFLITE_DEPRECATED("Use Baz instead") void Bar() {...} +// +// Every usage of a deprecated entity will trigger a warning when compiled with +// clang's `-Wdeprecated-declarations` option. This option is turned off by +// default, but the warnings will be reported by clang-tidy. +#if defined(__clang__) && __cplusplus >= 201103L +#define TFLITE_DEPRECATED(message) __attribute__((deprecated(message))) +#endif + +#ifndef TFLITE_DEPRECATED +#define TFLITE_DEPRECATED(message) +#endif + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_COMPATIBILITY_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/cppmath.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/cppmath.h new file mode 100644 index 000000000..5cd5b7df6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/cppmath.h @@ -0,0 +1,40 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_CPPMATH_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_CPPMATH_H_ + +#include + +namespace tflite { + +#if defined(ARDUINO) || \ + (defined(__ANDROID__) && !defined(__NDK_MAJOR__)) || defined(__ZEPHYR__) +#define TF_LITE_GLOBAL_STD_PREFIX +#else +#define TF_LITE_GLOBAL_STD_PREFIX std +#endif + +#define DECLARE_STD_GLOBAL_SWITCH1(tf_name, std_name) \ + template \ + inline T tf_name(const T x) { \ + return TF_LITE_GLOBAL_STD_PREFIX::std_name(x); \ + } + +DECLARE_STD_GLOBAL_SWITCH1(TfLiteRound, round); +DECLARE_STD_GLOBAL_SWITCH1(TfLiteExpm1, expm1); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_CPPMATH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/max.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/max.h new file mode 100644 index 000000000..c18100272 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/max.h @@ -0,0 +1,35 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_MAX_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_MAX_H_ + +#include + +namespace tflite { + +#if defined(TF_LITE_USE_GLOBAL_MAX) || defined(__ZEPHYR__) +inline float TfLiteMax(const float& x, const float& y) { + return std::max(x, y); +} +#else +template +inline T TfLiteMax(const T& x, const T& y) { + return std::fmax(x, y); +} +#endif + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_MAX_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/min.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/min.h new file mode 100644 index 000000000..62035dccd --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/min.h @@ -0,0 +1,35 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_MIN_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_MIN_H_ + +#include + +namespace tflite { + +#if defined(TF_LITE_USE_GLOBAL_MIN) || defined(__ZEPHYR__) +inline float TfLiteMin(const float& x, const float& y) { + return std::min(x, y); +} +#else +template +inline T TfLiteMin(const T& x, const T& y) { + return std::fmin(x, y); +} +#endif + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_MIN_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/optimized/neon_check.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/optimized/neon_check.h new file mode 100644 index 000000000..7df1129d5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/optimized/neon_check.h @@ -0,0 +1,20 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_CHECK_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_CHECK_H_ + +// TFLM does not need to utilize any Neon optimizations. + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_OPTIMIZED_NEON_CHECK_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor.h new file mode 100644 index 000000000..4d71c9678 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor.h @@ -0,0 +1,122 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_PORTABLE_TENSOR_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_PORTABLE_TENSOR_H_ + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +inline RuntimeShape GetTensorShape(std::vector data) { + return RuntimeShape(data.size(), data.data()); +} + +// A list of tensors in a format that can be used by kernels like split and +// concatenation. +template +class VectorOfTensors { + public: + // Build with the tensors in 'tensor_list'. + VectorOfTensors(const TfLiteContext& context, + const TfLiteIntArray& tensor_list) { + int num_tensors = tensor_list.size; + + all_data_.reserve(num_tensors); + all_shape_.reserve(num_tensors); + all_shape_ptr_.reserve(num_tensors); + + for (int i = 0; i < num_tensors; ++i) { + TfLiteTensor* t = &context.tensors[tensor_list.data[i]]; + all_data_.push_back(GetTensorData(t)); + all_shape_.push_back(GetTensorShape(t)); + } + + // Taking the pointer from inside a std::vector is only OK if the vector is + // never modified, so we populate all_shape in the previous loop and then we + // are free to grab iterators here. + for (int i = 0; i < num_tensors; ++i) { + all_shape_ptr_.push_back(&all_shape_[i]); + } + } + // Return a pointer to the data pointers of all tensors in the list. For + // example: + // float* const* f = v.data(); + // f[0][1] is the second element of the first tensor. + T* const* data() const { return all_data_.data(); } + + // Return a pointer the shape pointers of all tensors in the list. For + // example: + // const RuntimeShape* const* d = v.dims(); + // dims[1] are the dimensions of the second tensor in the list. + const RuntimeShape* const* shapes() const { return all_shape_ptr_.data(); } + + private: + std::vector all_data_; + std::vector all_shape_; + std::vector all_shape_ptr_; +}; + +// A list of quantized tensors in a format that can be used by kernels like +// split and concatenation. +class VectorOfQuantizedTensors : public VectorOfTensors { + public: + // Build with the tensors in 'tensor_list'. + VectorOfQuantizedTensors(const TfLiteContext& context, + const TfLiteIntArray& tensor_list) + : VectorOfTensors(context, tensor_list) { + for (int i = 0; i < tensor_list.size; ++i) { + TfLiteTensor* t = &context.tensors[tensor_list.data[i]]; + zero_point_.push_back(t->params.zero_point); + scale_.push_back(t->params.scale); + } + } + + const float* scale() const { return scale_.data(); } + const int32_t* zero_point() const { return zero_point_.data(); } + + private: + std::vector zero_point_; + std::vector scale_; +}; + +// Writes randomly accessed values from `input` sequentially into `output`. +template +class SequentialTensorWriter { + public: + SequentialTensorWriter(const TfLiteTensor* input, TfLiteTensor* output) { + input_data_ = GetTensorData(input); + output_ptr_ = GetTensorData(output); + } + SequentialTensorWriter(const T* input_data, T* output_data) + : input_data_(input_data), output_ptr_(output_data) {} + + void Write(int position) { *output_ptr_++ = input_data_[position]; } + void WriteN(int position, int len) { + memcpy(output_ptr_, &input_data_[position], sizeof(T) * len); + output_ptr_ += len; + } + + private: + const T* input_data_; + T* output_ptr_; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_PORTABLE_TENSOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor_utils.cpp new file mode 100644 index 000000000..4904a6a3a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor_utils.cpp @@ -0,0 +1,86 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ + +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" + +#include +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" + +#if defined(_MSC_VER) +#define __restrict__ __restrict +#endif + +namespace tflite { + +// Not all backends support CpuBackendContext usage, so forward declare to avoid +// pulling in its implementation. Use of CpuBackendContext in method +// implementations is purely optional. +class CpuBackendContext; + +namespace tensor_utils { + +// Apply Rectified Linear to elements of a vector. +void ApplyReluToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result) { + for (int v = 0; v < v_size; v++) { + result[v] = std::max(0.0f, vector[v]); + } +} + +// Apply Rectified Linear 1 (cap to [-1;1]) to elements of a vector +void ApplyRelu1ToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result) { + for (int v = 0; v < v_size; v++) { + result[v] = std::max(-1.0f, std::min(vector[v], 1.0f)); + } +} + +// Apply Rectified Linear 6 (cap to [0;6]) to elements of a vector +void ApplyRelu6ToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result) { + for (int v = 0; v < v_size; v++) { + result[v] = std::max(0.0f, std::min(vector[v], 6.0f)); + } +} + +// Apply signbit to elements of a vector +void ApplySignbitToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result) { + for (int v = 0; v < v_size; v++) { + result[v] = std::signbit(vector[v]); + } +} + +void UnpackDenseInt4IntoInt8(const int8_t* src_buffer, int num_elements, + int8_t* dst_buffer) { + for (int i = 0; i < num_elements; i += 2) { + // Shift left first so that sign is properly extended when shifted right + dst_buffer[i] = static_cast(src_buffer[i / 2] << 4) >> 4; + // Break early if the tensor has odd length and the higher nibble should be + // ignored. + if (i + 1 == num_elements) break; + dst_buffer[i + 1] = static_cast(src_buffer[i / 2]) >> 4; + } +} + +} // namespace tensor_utils +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_TENSOR_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor_utils.h new file mode 100644 index 000000000..266d0b4ff --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/portable_tensor_utils.h @@ -0,0 +1,623 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_PORTABLE_TENSOR_UTILS_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_PORTABLE_TENSOR_UTILS_H_ + +#include +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +#if defined(_MSC_VER) +#define __restrict__ __restrict +#endif + +namespace tflite { + +// Not all backends support CpuBackendContext usage, so forward declare to avoid +// pulling in its implementation. Use of CpuBackendContext in method +// implementations is purely optional. +class CpuBackendContext; + +namespace tensor_utils { + +// Multiplies a matrix with a scalar and reduce the result on each row to a +// scalar. +// Parameters: +// - matrix: matrix of size n_row * n_col +// - scalar: the scalar that is multiplied to each element in the matrix +// - n_row: the row count of the matrix +// - n_col: the column count of the matrix +// - output: the 32bit output +// Note: We do not need saturation because the int8 * int8 is safe from overflow +// in (2^31-1) / (2^14) = 131072, which is bigger than the n_row. Non-zero +// initial output value is not exceptionally large. +void MatrixScalarMultiplyAccumulate(const int8_t* matrix, int32_t scalar, + int32_t n_row, int32_t n_col, + int32_t* output); + +// Add another vector for each batch in the batch vector. +template +void VectorBatchVectorAdd(const T* vector, int v_size, int n_batch, + T* batch_vector) { + for (int b = 0; b < n_batch; b++) { + for (int i = 0; i < v_size; ++i) { + batch_vector[i] += vector[i]; + } + batch_vector += v_size; + } +} + +// Cwise product of two vectors. +template +inline void VectorVectorCwiseProduct(const T* vector1, const T* vector2, + int v_size, T* result) { + for (int v = 0; v < v_size; v++) { + *result++ = *vector1++ * *vector2++; + } +} + +// Cwise product of a vector and a batch-vector. +template +inline void VectorBatchVectorCwiseProduct(const T* vector, int v_size, + const T* batch_vector, int n_batch, + T* result) { + for (int b = 0; b < n_batch; b++) { + VectorVectorCwiseProduct(vector, batch_vector, v_size, result); + // Update the pointers. + result += v_size; + batch_vector += v_size; + } +} + +// Cwise product and accumulate of two vectors. Since it's a MAC operation, the +// assumption here is that result array is initialized to valid values. +template +inline void VectorVectorCwiseProductAccumulate(const T* __restrict__ vector1, + const T* __restrict__ vector2, + int v_size, + T* __restrict__ result) { + for (int v = 0; v < v_size; v++) { + *result++ += *vector1++ * *vector2++; + } +} + +// Cwise product and accumulate of a vector and a batch-vector. Since it's a MAC +// operation, the assumption here is that result array is initialized to valid +// values. +template +inline void VectorBatchVectorCwiseProductAccumulate(const T* vector, int v_size, + const T* batch_vector, + int n_batch, T* result) { + for (int b = 0; b < n_batch; b++) { + VectorVectorCwiseProductAccumulate(vector, batch_vector, v_size, result); + // Update the pointers. + result += v_size; + batch_vector += v_size; + } +} + +// Batch vector initialization with another vector. +template +void VectorBatchVectorAssign(const T* vector, int v_size, int n_batch, + T* batch_vector) { + for (int b = 0; b < n_batch; b++) { + std::copy_n(vector, v_size, batch_vector + b * v_size); + } +} + +// Checks if all entries of vector are zero for float. +bool IsZeroVector(const float* vector, int v_size); + +// Checks if all entries of vector are zero for int8. +bool IsZeroVector(const int8_t* vector, int v_size); + +// Quantizes a buffer of floating point values using a symmetric quantization +// (i.e. linear quantization without an offset) to 8-bit signed integers. +// It also outputs the range (min, max) of the floating point buffer, and the +// scaling factor used to quantize the values. +void SymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float* min_value, + float* max_value, float* scaling_factor); + +// Quantizes a buffer of floating point values using a symmetric quantization +// (i.e. linear quantization without an offset) to 8-bit signed integers. +// It uses the range (min, max) provided to the function to calculate the +// appropriate scaling factor to quantize the values. +void SymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float min_value, + float max_value, float* scaling_factor); + +void AsymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float* scaling_factor, + int32_t* offset); + +// Helper function to quantize floats. +// float_data_ptr input float vectors +// n_batch number of input vectors +// n_data size of a single input vector +// quantized_data_ptr (out) vector with quantized data +// scaling_factors (out) scaling factors (one per vector) +// zero_points (out) zero points (one per vector) +// do_asymmetric controls if the quantization should be asymmetric. +inline void BatchQuantizeFloats(const float* float_data_ptr, int n_batch, + int n_data, int8_t* quantized_data_ptr, + float* scaling_factors, int32_t* zero_points, + bool do_asymmetric) { + for (int b = 0; b < n_batch; ++b) { + const int offset = b * n_data; + if (do_asymmetric) { + tensor_utils::AsymmetricQuantizeFloats( + float_data_ptr + offset, n_data, quantized_data_ptr + offset, + &scaling_factors[b], &zero_points[b]); + } else { + float unused_min, unused_max; + tensor_utils::SymmetricQuantizeFloats( + float_data_ptr + offset, n_data, quantized_data_ptr + offset, + &unused_min, &unused_max, &scaling_factors[b]); + } + } +} + +// Multiplies a matrix by a "batched" vector (i.e. a matrix with a batch +// dimension composed by input vectors independent from each other). The result +// of the multiplication is accumulated to the passed result buffer. +// More specifically, for a matrix M of shape [n, i] and a batched-vector +// of shape [i, batch] it will first compute the product of shape [n, batch]. +// This product will be accumulated to the result buffer. +void MatrixBatchVectorMultiplyAccumulate(const float* matrix, int m_rows, + int m_cols, const float* vector, + int n_batch, float* result); + +// Same as the function above, but the matrix is a sparse tensor with block +// pattern 1x4. +// This function assumes that m_cols is a multiple of the block size (4 in this +// case) so that there's no incomplete block. +void SparseMatrixBatchVectorMultiplyAccumulate1x4( + const float* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const float* __restrict__ vector, int n_batch, float* __restrict__ result); + +// Same as the function above, but the matrix is stored in block compressed +// sparse row format with block pattern 1x16 which consists of two arrays: +// 1. A matrix array stores non-zero blocks of the matrix in row major. +// 2. A ledger array stores nrows groups, one group per row. Each group starts +// with an integer representing the number of non-zero blocks for the +// corresponding row and follows with column indexes of the first element +// of each non-zero block. +// This function assumes that +// 1. m_cols is a multiple of 16 so that all blocks are full blocks. +// 2. m_cols < 254 * 16 so that block index can be represented by uint8. +void SparseMatrixBatchVectorMultiplyAccumulate( + const float* __restrict__ matrix, const uint8_t* __restrict__ ledger, + int m_rows, int m_cols, const float* __restrict__ vector, int n_batch, + float* __restrict__ result); + +// Same as the function above, but for values quantized using symmetric +// quantization (e.g. by calling SymmetricQuantizeFloats). +// The passed scaling factors is a buffer of the quantization scaling factors +// that will be used to dequentize the products into the final result buffer. +// These scaling factors are the multiplication of the matrix scaling factor +// by the vector's scaling factor, one per batch (i.e. this allows quantizing +// each batch in the batch-vector matrix independently). +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, + const float* __restrict__ scaling_factors, int n_batch, + float* __restrict__ result); + +// Same as the function above except that vector values +// are quantized with asymmetric quantization per-batch and the matrix +// is quantized per row. +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, + const float* __restrict__ scaling_factors, int n_batch, + float* __restrict__ result, const float* __restrict__ per_channel_scale, + const int32_t* __restrict__ input_offset); + +// Same as the function above, but the matrix is a sparse tensor with block +// pattern 1x16. +// This function assumes that m_cols is a multiple of the block size (16 in this +// case) so that there's no incomplete block. Also, it assumes all offsets of +// input, output and filter are zero. +void SparseMatrixBatchVectorMultiplyAccumulate1x16( + const int8_t* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const int8_t* __restrict__ vector, const int32_t* __restrict__ bias_vector, + int n_batch, const int32_t input_offset, const int32_t output_multiplier, + const int32_t output_shift, const int32_t output_offset, + const int32_t output_activation_min, const int32_t output_activation_max, + int8_t* __restrict__ result); + +// Same as the function above, but the matrix is stored in block compressed +// sparse row format with block pattern 1x16 which consists of two arrays: +// 1. A matrix array stores non-zero blocks of the matrix in row major. +// 2. A ledger array stores nrows groups, one group per row. Each group starts +// with an integer representing the number of non-zero blocks for the +// corresponding row followed by column index of the first element of +// each non-zero block. +// This function assumes that +// 1. m_cols is a multiple of 16 so that all blocks are full blocks. +// 2. m_cols < 254 * 16 so that block index can be represented by uint8. +void SparseMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const uint8_t* __restrict__ ledger, + const int m_rows, const int m_cols, const int8_t* __restrict__ vectors, + const float* __restrict__ scaling_factors, int n_batch, + float* __restrict__ result); + +// Same as the above 8, 8, 8 integer matmul except for the presence of zero +// point and non-accumulative. +// TODO(b/148688698): remove this function by folding zero point calculation in +// prepare() function. +void MatrixBatchVectorMultiply(const int8_t* input, int32_t input_zeropoint, + const int8_t* input_to_gate_weights, + int32_t input_to_gate_effective_scale_a, + int32_t input_to_gate_effective_scale_b, + int32_t n_batch, int32_t n_input, int32_t n_cell, + int8_t* gate_output, int8_t gate_output_zp); + +// Same as above but has 16 bit and 8 bit input and 8 bit output. +// Used in projection when hidden is 16bit. +void MatrixBatchVectorMultiply(const int16_t* hidden, + const int8_t* hidden_to_output_weights, + int32_t proj_effective_scale_a, + int32_t proj_effective_scale_b, + const int32_t* gate_bias, int32_t n_batch, + int32_t n_hidden, int32_t n_output, + int32_t output_zp, int8_t* proj_output); + +// Apply Layer Normalization (https://arxiv.org/abs/1607.06450) to a Quantized +// vector. +// Parameters: +// - input: batch vector of size n_batch * n_input; 16 bit. +// - layer_norm_weights: the quantized layer normalization weights. +// - bias: the bias for the layer normalization. +// - layer_norm_scale_a: multiplier for scale factor. +// - layer_norm_scale_b: shift for scale factor. +// - variance_limit: the guard to make sure the inverse does not overflow. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - output: the 16 bit output +void ApplyLayerNorm(const int16_t* input, const int16_t* layer_norm_weights, + const int32_t* bias, int32_t layer_norm_scale_a, + int32_t layer_norm_scale_b, int32_t variance_limit, + int n_batch, int n_input, int16_t* output); + +// Same as above but the internal calculation is done in float. +void ApplyLayerNormFloat(const int16_t* input, + const int16_t* layer_norm_weights, + int32_t layer_norm_scale_a, int32_t layer_norm_scale_b, + const int32_t* bias, int n_batch, int n_input, + int16_t* output); + +// Apply Sigmoid to a quantized vector. +// Parameters: +// - input: batch vector of size n_batch * n_input; 16 bit. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - output: the 16 bit output +// The input is in Q3.12 format and the output is in Q0.15 format. +void ApplySigmoid(const int16_t* input, int32_t n_batch, int32_t n_input, + int16_t* output); + +// Same as above but the internal calcualtion is float. +void ApplySigmoidFloat(const int16_t* input, int32_t n_batch, int32_t n_input, + int16_t* output); + +// Apply Tanh to a quantized vector. +// Parameters: +// - integer_bits: the integer bits of the input. +// Currently supports 0, 1, 2, 3, 4, 5, 6. +// - input: batch vector of size n_batch * n_input; 16 bit. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - output: the 16 bit output +// The input is in Qm.15-m format and the output is in Q0.15 format. +void ApplyTanh(int32_t intger_bits, const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output); + +// Apply Tanh to a quantized vector. Tbe internal calculation is in float. +// - Input has 2^(integer_bits) as scale. +// - Output has Q0.15 as scale. +void ApplyTanhFloat(const int16_t* input, int32_t n_batch, int32_t n_input, + int32_t integer_bits, int16_t* output); + +// Element-wise multiplication of two quantized vectors. +// Parameters: +// - input_1: batch vector of size n_batch * n_input; 16 bit. +// - input_2: batch vector of size n_batch * n_input; 16 bit. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - shift: the shift needed to produce the output. +// - output: the 16 bit output of size n_batch * n_input. +// Output does not need to be initialized. +void CwiseMul(const int16_t* input_1, const int16_t* input_2, int n_batch, + int n_input, int shift, int16_t* output); + +// Element-wise multiplication of two quantized vectors. +// Parameters: +// - input_1: batch vector of size n_batch * n_input; 16 bit. +// - input_2: batch vector of size n_batch * n_input; 16 bit. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - shift: the shift needed to produce the output. +// - output: the 8 bit output of size n_batch * n_input. +// Output does not need to be initialized. +void CwiseMul(const int16_t* input_1, const int16_t* input_2, int n_batch, + int n_input, int shift, int8_t* output); + +// Element-wise multiplication of two quantized vectors with rescaling. +// Parameters: +// - input_1: batch vector of size n_batch * n_input; 16 bit. +// - input_2: batch vector of size n_batch * n_input; 16 bit. +// - multiplier: the multiplier part of scale. +// - shift: the shift part of scale. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - output: the 8 bit output of size n_batch * n_input. +// - output_zp: the zero point of output. +// Output does not need to be initialized. +// Multiplier ("m") and shift ("s") are connected to scale ("s") with s = m * +// 2^(s - 31). +void CwiseMul(const int16_t* input_1, const int16_t* input_2, + int32_t multiplier, int32_t shift, int32_t n_batch, + int32_t n_input, int32_t output_zp, int8_t* output); + +// Element-wise saturating addition of two quantized vectors without rescaling. +// Parameters: +// - input_1: batch vector of size n_batch * n_input; 16 bit. +// - input_2: batch vector of size n_batch * n_input; 16 bit. +// - n_batch: the number of batches. +// - n_input: the size for input and output. +// - output: the 8 bit output of size n_batch * n_input. +// Output does not need to be initialized. +void CwiseAdd(const int16_t* input_1, const int16_t* input_2, int n_batch, + int n_input, int16_t* output); + +// Element-wise in-place clipping of a vector. Overloaded for float, int16_t, +// int8_t. Parameters: +// - vector: vector of size v_size. +// - v_size: the size of the vector. +// - clipping_value: the value used for clipping. +void CwiseClipping(float* vector, const int v_size, const float clipping_value); +void CwiseClipping(int16_t* vector, const int v_size, + const int16_t clipping_value); +void CwiseClipping(int8_t* vector, const int v_size, + const int8_t clipping_value); + +// Dot product of two vectors. +float VectorVectorDotProduct(const float* vector1, const float* vector2, + int v_size); + +// Dot product of two batch vectors of size n_batch * v_size: +// vector1 = [x_1_1, x_1_2, ..., x_1_vsize, +// x_2_1, x_2_2, ..., x_2_vsize, +// ... +// x_nbatch_1,..., x_nbatch_vsize] +// vector2 = [y_1_1, y_1_2, ..., y_1_vsize, +// y_2_1, y_2_2, ..., y_2_vsize, +// ... +// y_nbatch_1,..., y_nbatch_vsize] +// Then result will be a vector of n_batch size starting from 'result': +// [x_1_1 * y_1_1 + x_1_2 * y_1_2 + ... + x_1_vsize * y_1_vsize, +// x_2_1 * y_2_1 + x_2_2 * y_2_2 + ... + x_2_vsize * y_2_vsize, +// ... +// x_nbatch_1 * y_nbatch_1 + ... + x_nbatch_vsize * y_nbatch_vsize] +template +inline void BatchVectorBatchVectorDotProduct(const T* vector1, const T* vector2, + int v_size, int n_batch, + T* result) { + for (int b = 0; b < n_batch; b++) { + result[b] = VectorVectorDotProduct(vector1, vector2, v_size); + vector1 += v_size; + vector2 += v_size; + } +} + +// Same as above but input is 16bit and output is 32bit. +void BatchVectorBatchVectorDotProduct(const int16_t* vector1, + const int16_t* vector2, int v_size, + int n_batch, int32_t* result); + +// Same as above, but inputs are 16bit integer and output is 16bit integer. +void VectorBatchVectorCwiseProductAccumulate(const int16_t* vector, int v_size, + const int16_t* batch_vector, + int n_batch, int32_t multiplier, + int shift, int16_t* result); + +// Compute "1.0f - elements of vector" (used in CIFG). +void Sub1Vector(const float* vector, int v_size, float* result); + +// Compute "1.0f - elements of vector" (used in CIFG) for int16 input. +// "vector" has range [0, 32767] because it is the output of sigmoid function. +void Sub1Vector(const int16_t* vector, int v_size, int16_t* result); + +// Reduce-sum on a float input vector: +// input_vector: float pointer to input vector. +// output_vector: float pointer to vector. +// output_size: output vector size. +// reduction_size: number of consecutive elements from input vector which are +// added to get one element of output. +void ReductionSumVector(const float* input_vector, float* output_vector, + int output_size, int reduction_size); + +// Same as above but input/output is 32 bit integer. +void ReductionSumVector(const int32_t* input_vector, int32_t* output_vector, + int output_size, int reduction_size); + +// Same as above but input is 8 bit integer. +void ReductionSumVector(const int8_t* input_vector, int32_t* output_vector, + int output_size, int reduction_size); + +// Multiply all elements of vector with a scalar. +void VectorScalarMultiply(const int8_t* vector, int v_size, float scale, + float* result); + +// Layer norm for each batch. +void MeanStddevNormalization(const float* input_vector, float* output_vector, + int v_size, int n_batch); + +// Saturate Add with rescale on both inputs. +void TwoGateSaturatingAdd(const int8_t* input, int8_t input_zp, + const int8_t* recurrent, int8_t recurrent_zp, + int32_t input_effective_scale_a, + int32_t input_effective_scale_b, + int32_t recurrent_effective_scale_a, + int32_t recurrent_effective_scale_b, int32_t n_batch, + int32_t n_cell, int16_t* output); + +// Same as the function above, but provide a scratch buffer for the +// int8 x int8 -> int32 and a CpuBackendContext for the accumulator +// computation. +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, + const float* __restrict__ scaling_factors, int n_batch, + int32_t* __restrict__ scratch, float* __restrict__ result, + CpuBackendContext* __restrict__ context); + +// Same as the function above except that can make use of cached row sums. +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float* scaling_factors, + int n_batch, float* __restrict__ result, const float* per_channel_scale, + const int32_t* input_offset, int32_t* scratch, int32_t* row_sums, + bool* compute_row_sums, CpuBackendContext* context); + +// Same as the function above, but provides separate scaling factor for the +// matrix and the vectors. The scaling factors are multiplied in the +// scaling_factor_scratch buffer. +inline void MatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float matrix_scaling_factor, + const float* vector_scaling_factors, int n_batch, + float* __restrict__ result, const float* per_channel_scale, + const int32_t* input_offset, int32_t* scratch, int32_t* row_sums, + bool* compute_row_sums, float* scaling_factor_scratch, + CpuBackendContext* context) { + for (int b = 0; b < n_batch; ++b) { + scaling_factor_scratch[b] = + vector_scaling_factors[b] * matrix_scaling_factor; + } + MatrixBatchVectorMultiplyAccumulate(matrix, m_rows, m_cols, vectors, + scaling_factor_scratch, n_batch, result, + per_channel_scale, input_offset, scratch, + row_sums, compute_row_sums, context); +} + +// Multiplies a matrix by a "batched" vector (i.e. a matrix with a batch +// dimension composed by input vectors independent from each other). The result +// of the multiplication is accumulated to the passed result buffer. +// More specifically, for a matrix M of shape [n, i] and a batched-vector +// of shape [i, batch] it will first compute the product of shape [n, batch]. +// This product will be accumulated to the result buffer, +// Parameters: +// - input: batch vector of size n_batch * n_input +// - bias: vector of size b_input +// - input_to_gate_weights: matrix of size n_input * n_output +// - multiplier: scalar +// - shift: scalar +// - n_batch: the batch size +// - n_input: the input size +// - n_output: the output size +// - output_zp: the zero point of the output. +// - scratch: batch vector of size n_batch * n_output +// - output: the 16 bit output +// Notes: +// - this is used for gate matmul: for non-cifg it is for input, forget, +// cell, output gates; for cifg, it is for forget, cell, output gates. +// - multiplier and shift combined gives the scale. +// - assumes input zero point is 0. +// - scratch is created for optimization purpose only. +// TODO(b/152066492): this can be removed if some future optimization +// work makes it unnecessary. +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int16_t* output, CpuBackendContext* context); + +// Multiplies a matrix by a "batched" vector (i.e. a matrix with a batch +// dimension composed by input vectors independent from each other). The result +// of the multiplication is accumulated to the passed result buffer. +// More specifically, for a matrix M of shape [n, i] and a batched-vector +// of shape [i, batch] it will first compute the product of shape [n, batch]. +// This product will be accumulated to the result buffer, +// Parameters: +// - input: batch vector of size n_batch * n_input +// - bias: vector of size b_input +// - input_to_gate_weights: matrix of size n_input * n_output +// - multiplier: scalar +// - shift: scalar +// - n_batch: the batch size +// - n_input: the input size +// - n_output: the output size +// - output_zp: the zero point of the output. +// - scratch: batch vector of size n_batch * n_output +// - output: the 8 bit output +// Notes: +// - this is used for projection matmul. +// - multiplier and shift combined gives the scale. +// - assumes input zero point is 0. +// - scratch is created for optimization purpose only. +// TODO(b/152066492): this can be removed if some future optimization +// work makes it unnecessary. +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int8_t* output, CpuBackendContext* context); + +// Apply Rectified Linear to elements of a vector. +void ApplyReluToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result); + +// Apply Rectified Linear 1 (cap to [-1;1]) to elements of a vector +void ApplyRelu1ToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result); + +// Apply Rectified Linear 6 (cap to [0;6]) to elements of a vector +void ApplyRelu6ToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result); + +// Apply signbit to elements of a vector +void ApplySignbitToVector(const float* __restrict__ vector, int v_size, + float* __restrict__ result); + +// Unpack or inflate `src_buffer` by taking each element and splitting it as +// two elements into `dst_buffer`. +// Parameters: +// src_buffer : Densely packed buffer containing int4 values +// num_elements : Number of elements stored in the buffer. Note that this can +// be smaller than the size of `src_buffer` by 1 if it's odd, +// in which case the last nibble in `src_buffer` is ignored. +// This should be equal to the size of `dst_buffer`. +// dst_buffer : Buffer to unpack into. Should be allocated by the caller. +// Size should be at least `num_elements`. +// Notes: +// For example, given `src_buffer = {0x12, 0x34};`, calling this function +// will return `dst_buffer = {0x02, 0x01, 0x04, 0x03}`. +void UnpackDenseInt4IntoInt8(const int8_t* src_buffer, int num_elements, + int8_t* dst_buffer); + +} // namespace tensor_utils + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_PORTABLE_TENSOR_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/quantization_util.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/quantization_util.cpp new file mode 100644 index 000000000..62045d67a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/quantization_util.cpp @@ -0,0 +1,416 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/quantization_util.h" + +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" + +namespace tflite { + +namespace { +// These constants are used to manipulate the binary representation of doubles. +// Double-precision binary64 floating point format is: +// Bit | 63 | 62-52 | 51-0 | +// | Sign | Exponent | Fraction | +// To avoid 64-bit integers as much as possible, I break this into high and +// low 32-bit chunks. High is: +// Bit | 31 | 30-20 | 19-0 | +// | Sign | Exponent | High Fraction | +// Low is: +// Bit | 31-0 | +// | Low Fraction | +// We then access the components through logical bit-wise operations to +// extract the parts needed, with the positions and masks derived from the +// layout shown above. +constexpr uint64_t kSignMask = 0x8000000000000000LL; +constexpr uint64_t kExponentMask = 0x7ff0000000000000LL; +constexpr int32_t kExponentShift = 52; +constexpr int32_t kExponentBias = 1023; +constexpr uint32_t kExponentIsBadNum = 0x7ff; +constexpr uint64_t kFractionMask = 0x000fffffffc00000LL; +constexpr uint32_t kFractionShift = 22; +constexpr uint32_t kFractionRoundingMask = 0x003fffff; +constexpr uint32_t kFractionRoundingThreshold = 0x00200000; +} // namespace + +void QuantizeMultiplier(double double_multiplier, int32_t* quantized_multiplier, + int* shift) { +#if TFLITE_SINGLE_ROUNDING + // Single-rounding MultiplyByQuantizedMultiplier only supports positive + // multipliers. + // TFLITE_DCHECK(double_multiplier >= 0); +#endif + if (double_multiplier == 0.) { + *quantized_multiplier = 0; + *shift = 0; + return; + } +#ifdef TFLITE_EMULATE_FLOAT + // If we're trying to avoid the use of floating-point instructions (for + // example on microcontrollers) then use an alternative implementation + // that only requires integer and bitwise operations. To enable this, you + // need to set the define during the build process for your platform. + int64_t q_fixed = IntegerFrExp(double_multiplier, shift); +#else // TFLITE_EMULATE_FLOAT + const double q = std::frexp(double_multiplier, shift); + auto q_fixed = static_cast(TfLiteRound(q * (1LL << 31))); +#endif // TFLITE_EMULATE_FLOAT + TFLITE_CHECK(q_fixed <= (1LL << 31)); + if (q_fixed == (1LL << 31)) { + q_fixed /= 2; + ++*shift; + } + TFLITE_CHECK_LE(q_fixed, std::numeric_limits::max()); + // A shift amount smaller than -31 would cause all bits to be shifted out + // and thus all results would be zero. We implement that instead with + // q_fixed==0, so as to avoid hitting issues with right-shift + // operations with shift amounts greater than 31. Note that this happens + // roughly when abs(double_multiplier) < 2^-31 and the present handling means + // that we're effectively flushing tiny double_multiplier's to zero. + // We could conceivably handle values in the range (roughly) [32, 63] + // as 'denormals' i.e. (shift==0, q_fixed < 2^30). In that point of view + // the present handling is just doing 'flush denormals to zero'. We could + // reconsider and actually generate nonzero denormals if a need arises. + if (*shift < -31) { + *shift = 0; + q_fixed = 0; + } +#if TFLITE_SINGLE_ROUNDING + // Single-rounding MultiplyByQuantizedMultiplier doesn't support a shift > 30, + // saturate it. + if (*shift > 30) { + *shift = 30; + q_fixed = (1LL << 31) - 1; + } +#endif + *quantized_multiplier = static_cast(q_fixed); +} + +void QuantizeMultiplierGreaterThanOne(double double_multiplier, + int32_t* quantized_multiplier, + int* left_shift) { + TFLITE_CHECK_GT(double_multiplier, 1.); + QuantizeMultiplier(double_multiplier, quantized_multiplier, left_shift); + TFLITE_CHECK_GE(*left_shift, 0); +} + +void QuantizeMultiplierSmallerThanOneExp(double double_multiplier, + int32_t* quantized_multiplier, + int* left_shift) { + TFLITE_CHECK_LT(double_multiplier, 1.); + TFLITE_CHECK_GT(double_multiplier, 0.); + int shift; + QuantizeMultiplier(double_multiplier, quantized_multiplier, &shift); + TFLITE_CHECK_LE(shift, 0); + *left_shift = shift; +} + +int64_t IntegerFrExp(double input, int* shift) { + // Make sure our assumptions about the double layout hold. + TFLITE_CHECK_EQ(8, sizeof(double)); + + // We want to access the bits of the input double value directly, which is + // tricky to do safely, so use a union to handle the casting. + union { + double double_value; + uint64_t double_as_uint; + } cast_union; + cast_union.double_value = input; + const uint64_t u = cast_union.double_as_uint; + + // If the bitfield is all zeros apart from the sign bit, this is a normalized + // zero value, so return standard values for this special case. + if ((u & ~kSignMask) == 0) { + *shift = 0; + return 0; + } + + // Deal with NaNs and Infs, which are always indicated with a fixed pattern in + // the exponent, and distinguished by whether the fractions are zero or + // non-zero. + const uint32_t exponent_part = ((u & kExponentMask) >> kExponentShift); + if (exponent_part == kExponentIsBadNum) { + *shift = std::numeric_limits::max(); + if (u & kFractionMask) { + // NaN, so just return zero (with the exponent set to INT_MAX). + return 0; + } else { + // Infinity, so return +/- INT_MAX. + if (u & kSignMask) { + return std::numeric_limits::min(); + } else { + return std::numeric_limits::max(); + } + } + } + + // The shift is fairly easy to extract from the high bits of the double value, + // just by masking it out and applying a bias. The std::frexp() implementation + // always returns values between 0.5 and 1.0 though, whereas the exponent + // assumes 1.0 to 2.0 is the standard range, so I add on one to match that + // interface. + *shift = (exponent_part - kExponentBias) + 1; + + // There's an implicit high bit in the double format definition, so make sure + // we include that at the top, and then reconstruct the rest of the fractional + // value from the remaining fragments. + int64_t fraction = 0x40000000 + ((u & kFractionMask) >> kFractionShift); + + // We're cutting off some bits at the bottom, so to exactly match the standard + // frexp implementation here we'll apply rounding by adding one to the least + // significant bit of the result if the discarded portion is over half of the + // maximum. + if ((u & kFractionRoundingMask) > kFractionRoundingThreshold) { + fraction += 1; + } + // Negate the fraction if the sign bit was set. + if (u & kSignMask) { + fraction *= -1; + } + + return fraction; +} + +double DoubleFromFractionAndShift(int64_t fraction, int shift) { + union { + double double_value; + uint64_t double_as_uint; + } result; + + // Detect NaNs and infinities. + if (shift == std::numeric_limits::max()) { + if (fraction == 0) { + return std::numeric_limits::quiet_NaN(); + } else if (fraction > 0) { + return std::numeric_limits::infinity(); + } else { + return -std::numeric_limits::infinity(); + } + } + + // Return a normalized zero for a zero fraction. + if (fraction == 0) { + result.double_as_uint = 0; + return result.double_value; + } + + bool is_negative = (fraction < 0); + int64_t encoded_fraction = is_negative ? -fraction : fraction; + int64_t encoded_shift = (shift - 1); + while (encoded_fraction < 0x40000000) { + encoded_fraction *= 2; + encoded_shift -= 1; + } + while (encoded_fraction > 0x80000000) { + encoded_fraction /= 2; + encoded_shift += 1; + } + encoded_fraction -= 0x40000000; + if (encoded_shift < -1022) { + encoded_shift = -1023; + } else if (encoded_shift > 1022) { + encoded_shift = 1023; + } + encoded_shift += kExponentBias; + uint64_t encoded_sign = is_negative ? kSignMask : 0; + result.double_as_uint = encoded_sign | (encoded_shift << kExponentShift) | + (encoded_fraction << kFractionShift); + return result.double_value; +} + +double IntegerDoubleMultiply(double a, double b) { + int a_shift; + const int64_t a_fraction = IntegerFrExp(a, &a_shift); + int b_shift; + const int64_t b_fraction = IntegerFrExp(b, &b_shift); + // Detect NaNs and infinities. + if (a_shift == std::numeric_limits::max() || + (b_shift == std::numeric_limits::max())) { + return std::numeric_limits::quiet_NaN(); + } + const int result_shift = a_shift + b_shift + 1; + const int64_t result_fraction = (a_fraction * b_fraction) >> 32; + return DoubleFromFractionAndShift(result_fraction, result_shift); +} + +int IntegerDoubleCompare(double a, double b) { + int a_shift; + const int64_t a_fraction = IntegerFrExp(a, &a_shift); + int b_shift; + const int64_t b_fraction = IntegerFrExp(b, &b_shift); + + // Detect NaNs and infinities. + if (a_shift == std::numeric_limits::max() || + (b_shift == std::numeric_limits::max())) { + return 1; + } + + if ((a_fraction == 0) && (b_fraction < 0)) { + return 1; + } else if ((a_fraction < 0) && (b_fraction == 0)) { + return -1; + } else if (a_shift < b_shift) { + return -1; + } else if (a_shift > b_shift) { + return 1; + } else if (a_fraction < b_fraction) { + return -1; + } else if (a_fraction > b_fraction) { + return 1; + } else { + return 0; + } +} + +void PreprocessSoftmaxScaling(double beta, double input_scale, + int input_integer_bits, + int32_t* quantized_multiplier, int* left_shift) { + // If the overall multiplier (input and beta) is large, then exp() of an + // input difference of 1 scaled by this will be large. In other words, we + // can cap the multiplier and know that, when it is used, the output will be + // (round to) zero wherever the input is not at the maximum value. + + // If the overall scale is less than one, and input_integer_bits=0, then the + // result is double equivalent of Q0.31 (actually with more precision). Thus + // this generates a Q(input_integer_bits).(31-input_integer_bits) + // representation. +#if TFLITE_SINGLE_ROUNDING + const double max_real_multiplier = (1LL << 30) - 1.0; +#else + const double max_real_multiplier = (1LL << 31) - 1.0; +#endif + +#ifdef TFLITE_EMULATE_FLOAT + const double input_beta = IntegerDoubleMultiply(beta, input_scale); + int shift; + int64_t fraction = IntegerFrExp(input_beta, &shift); + shift += (31 - input_integer_bits); + double input_beta_real_multiplier = + DoubleFromFractionAndShift(fraction, shift); + if (IntegerDoubleCompare(input_beta_real_multiplier, max_real_multiplier) > + 0) { + input_beta_real_multiplier = max_real_multiplier; + } +#else // TFLITE_EMULATE_FLOAT + const double input_beta_real_multiplier = + std::min(beta * input_scale * (1 << (31 - input_integer_bits)), + max_real_multiplier); +#endif // TFLITE_EMULATE_FLOAT + + QuantizeMultiplierGreaterThanOne(input_beta_real_multiplier, + quantized_multiplier, left_shift); +} + +void PreprocessLogSoftmaxScalingExp(double beta, double input_scale, + int input_integer_bits, + int32_t* quantized_multiplier, + int* left_shift, + int32_t* reverse_scaling_divisor, + int* reverse_scaling_left_shift) { + PreprocessSoftmaxScaling(beta, input_scale, input_integer_bits, + quantized_multiplier, left_shift); + + // Also calculate what amounts to the inverse scaling factor for the input. + const double real_reverse_scaling_divisor = + (1 << (31 - *left_shift)) / static_cast(*quantized_multiplier); + tflite::QuantizeMultiplierSmallerThanOneExp(real_reverse_scaling_divisor, + reverse_scaling_divisor, + reverse_scaling_left_shift); +} + +int CalculateInputRadius(int input_integer_bits, int input_left_shift, + int total_signed_bits) { +#ifdef TFLITE_EMULATE_FLOAT + int64_t result = (1 << input_integer_bits) - 1; + result <<= (total_signed_bits - input_integer_bits); + result >>= input_left_shift; + return result; +#else // TFLITE_EMULATE_FLOAT + const double max_input_rescaled = + 1.0 * ((1 << input_integer_bits) - 1) * + (1LL << (total_signed_bits - input_integer_bits)) / + (1LL << input_left_shift); + // Tighten bound using floor. Suppose that we could use the exact value. + // After scaling the difference, the result would be at the maximum. Thus we + // must ensure that our value has lower magnitude. + return static_cast(std::floor(max_input_rescaled)); +#endif // TFLITE_EMULATE_FLOAT +} + +void NudgeQuantizationRange(const float min, const float max, + const int quant_min, const int quant_max, + float* nudged_min, float* nudged_max, + float* nudged_scale) { + // This code originates from tensorflow/core/kernels/fake_quant_ops_functor.h. + const float quant_min_float = static_cast(quant_min); + const float quant_max_float = static_cast(quant_max); + *nudged_scale = (max - min) / (quant_max_float - quant_min_float); + const float zero_point_from_min = quant_min_float - min / *nudged_scale; + uint16_t nudged_zero_point; + if (zero_point_from_min < quant_min_float) { + nudged_zero_point = static_cast(quant_min); + } else if (zero_point_from_min > quant_max_float) { + nudged_zero_point = static_cast(quant_max); + } else { + nudged_zero_point = static_cast(TfLiteRound(zero_point_from_min)); + } + *nudged_min = (quant_min_float - nudged_zero_point) * (*nudged_scale); + *nudged_max = (quant_max_float - nudged_zero_point) * (*nudged_scale); +} + +void FakeQuantizeArray(const float nudged_scale, const float nudged_min, + const float nudged_max, const float* input_data, + float* output_data, const float size) { + // This code originates from tensorflow/core/kernels/fake_quant_ops_functor.h. + const float inv_nudged_scale = 1.0f / nudged_scale; + + for (int i = 0; i < size; i++) { + const float src_val = input_data[i]; + const float clamped = std::min(nudged_max, std::max(nudged_min, src_val)); + const float clamped_shifted = clamped - nudged_min; + const float dst_val = + TfLiteRound(clamped_shifted * inv_nudged_scale) * nudged_scale + + nudged_min; + output_data[i] = dst_val; + } +} + +bool CheckedLog2(const float x, int* log2_result) { + // Using TfLiteRound instead of std::round and std::log instead of + // std::log2 to work around these functions being missing in a toolchain + // used in some TensorFlow tests as of May 2018. + const float x_log2 = std::log(x) * (1.0f / std::log(2.0f)); + const float x_log2_rounded = TfLiteRound(x_log2); + const float x_log2_fracpart = x_log2 - x_log2_rounded; + + *log2_result = static_cast(x_log2_rounded); + return std::abs(x_log2_fracpart) < 1e-3f; +} + +void QuantizeMultiplierArray(const double* effective_scales, size_t size, + int32_t* effective_scale_significand, + int* effective_shift) { + for (size_t i = 0; i < size; ++i) { + QuantizeMultiplier(effective_scales[i], &effective_scale_significand[i], + &effective_shift[i]); + } +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/quantization_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/quantization_util.h new file mode 100644 index 000000000..0ee914b06 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/quantization_util.h @@ -0,0 +1,292 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_QUANTIZATION_UTIL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_QUANTIZATION_UTIL_H_ + +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +// Given the min and max values of a float array, return +// reasonable quantization parameters to use for this array. +template +QuantizationParams ChooseQuantizationParams(double rmin, double rmax, + bool narrow_range) { + const T qmin = std::numeric_limits::min() + (narrow_range ? 1 : 0); + const T qmax = std::numeric_limits::max(); + const double qmin_double = qmin; + const double qmax_double = qmax; + // 0 should always be a representable value. Let's assume that the initial + // min,max range contains 0. + TFLITE_CHECK_LE(rmin, 0.); + TFLITE_CHECK_GE(rmax, 0.); + if (rmin == rmax) { + // Special case where the min,max range is a point. Should be {0}. + TFLITE_CHECK_EQ(rmin, 0.); + TFLITE_CHECK_EQ(rmax, 0.); + QuantizationParams quantization_params; + quantization_params.zero_point = 0; + quantization_params.scale = 0.; + return quantization_params; + } + + // General case. + // + // First determine the scale. + const double scale = (rmax - rmin) / (qmax_double - qmin_double); + + // Zero-point computation. + // First the initial floating-point computation. The zero-point can be + // determined from solving an affine equation for any known pair + // (real value, corresponding quantized value). + // We know two such pairs: (rmin, qmin) and (rmax, qmax). + // The arithmetic error on the zero point computed from either pair + // will be roughly machine_epsilon * (sum of absolute values of terms) + // so we want to use the variant that adds the smaller terms. + const double zero_point_from_min = qmin_double - rmin / scale; + const double zero_point_from_max = qmax_double - rmax / scale; + const double zero_point_from_min_error = + std::abs(qmin_double) + std::abs(rmin / scale); + const double zero_point_from_max_error = + std::abs(qmax_double) + std::abs(rmax / scale); + + const double zero_point_double = + zero_point_from_min_error < zero_point_from_max_error + ? zero_point_from_min + : zero_point_from_max; + + // Now we need to nudge the zero point to be an integer + // (our zero points are integer, and this is motivated by the requirement + // to be able to represent the real value "0" exactly as a quantized value, + // which is required in multiple places, for example in Im2col with SAME + // padding). + T nudged_zero_point = 0; + if (zero_point_double < qmin_double) { + nudged_zero_point = qmin; + } else if (zero_point_double > qmax_double) { + nudged_zero_point = qmax; + } else { + nudged_zero_point = static_cast(round(zero_point_double)); + } + // The zero point should always be in the range of quantized value, + // [qmin, qmax]. + TFLITE_CHECK_GE(nudged_zero_point, qmin); + TFLITE_CHECK_LE(nudged_zero_point, qmax); + + // Finally, store the result nudged quantization params. + QuantizationParams quantization_params; + quantization_params.zero_point = nudged_zero_point; + quantization_params.scale = scale; + return quantization_params; +} + +template +QuantizationParams ChooseQuantizationParams(double rmin, double rmax) { + return ChooseQuantizationParams(rmin, rmax, false); +} + +// Converts a floating-point number to an integer. For all inputs x where +// static_cast(x) is legal according to the C++ standard, the result +// is identical to that cast (i.e. the result is x with its fractional part +// truncated whenever that is representable as IntOut). +// +// static_cast would cause undefined behavior for the following cases, which +// have well-defined behavior for this function: +// +// 1. If x is NaN, the result is zero. +// +// 2. If the truncated form of x is above the representable range of IntOut, +// the result is std::numeric_limits::max(). +// +// 3. If the truncated form of x is below the representable range of IntOut, +// the result is std::numeric_limits::min(). +// +// Note that cases #2 and #3 cover infinities as well as finite numbers. +// +// The range of FloatIn must include the range of IntOut, otherwise +// the results are undefined. +// TODO(sfeuz): Replace by absl::SafeCast once available. +template +IntOut SafeCast(FloatIn x) { + static_assert(!std::numeric_limits::is_integer, + "FloatIn is integer"); + static_assert(std::numeric_limits::is_integer, + "IntOut is not integer"); + static_assert(std::numeric_limits::radix == 2, "IntOut is base 2"); + + // Special case NaN, for which the logic below doesn't work. + if (std::isnan(x)) { + return 0; + } + + // Negative values all clip to zero for unsigned results. + if (!std::numeric_limits::is_signed && x < 0) { + return 0; + } + + // Handle infinities. + if (std::isinf(x)) { + return x < 0 ? std::numeric_limits::min() + : std::numeric_limits::max(); + } + + // Set exp such that x == f * 2^exp for some f with |f| in [0.5, 1.0), + // unless x is zero in which case exp == 0. Note that this implies that the + // magnitude of x is strictly less than 2^exp. + int exp = 0; + std::frexp(x, &exp); + + // Let N be the number of non-sign bits in the representation of IntOut. If + // the magnitude of x is strictly less than 2^N, the truncated version of x + // is representable as IntOut. The only representable integer for which this + // is not the case is kMin for signed types (i.e. -2^N), but that is covered + // by the fall-through below. + if (exp <= std::numeric_limits::digits) { + return x; + } + + // Handle numbers with magnitude >= 2^N. + return x < 0 ? std::numeric_limits::min() + : std::numeric_limits::max(); +} + +// Decompose a double multiplier into a Q0.31 int32 representation of its +// significand, and shift representation of NEGATIVE its exponent --- +// this is intended as a RIGHT-shift. +// +// Restricted to the case where the multiplier < 1 (and non-negative). +void QuantizeMultiplierSmallerThanOneExp(double double_multiplier, + int32_t* quantized_multiplier, + int* left_shift); + +// Decompose a double multiplier into a Q0.31 int32 representation of its +// significand, and shift representation of its exponent. +// +// Restricted to the case where the multiplier > 1. +void QuantizeMultiplierGreaterThanOne(double double_multiplier, + int32_t* quantized_multiplier, + int* left_shift); + +// Decompose a double multiplier into a Q0.31 int32 representation of its +// significand, and shift representation of its exponent. +// +// Handles an arbitrary positive multiplier. The 'shift' output-value is +// basically the 'floating-point exponent' of the multiplier: +// Negative for a right-shift (when the multiplier is <1), positive for a +// left-shift (when the multiplier is >1) +void QuantizeMultiplier(double double_multiplier, int32_t* quantized_multiplier, + int* shift); + +// Splits a double input value into a returned fraction, and a shift value from +// the exponent, using only bitwise and integer operations to support +// microcontrollers and other environments without floating-point support. +// +// This is designed to be a replacement for how std::frexp() is used within the +// QuantizeMultiplier() function, and so has a different signature than the +// standard version, returning a 64-bit integer rather than a double. This +// result has a maximum value of 1<<31, with the fraction expressed as a +// proportion of that maximum. +// +// std::frexp() returns NaNs and infinities unmodified, but since we're +// returning integers that can't represent those values, instead we return +// a shift of std::numeric_limits::max() for all bad numbers, with an int64 +// result of 0 for NaNs, std:numeric_limits::max() for +INFINITY, and +// std::numeric_limits::min() for -INFINITY. Denormalized inputs will +// result in return values that end up truncating some bits at the end, +// reflecting the loss of precision inherent in denormalization. +int64_t IntegerFrExp(double input, int* shift); + +// Converts an integer fraction in the format produced by IntegerFrExp (where +// 0x40000000 is 1.0) and an exponent shift (between -1022 and +1022) into an +// IEEE binary64 double format result. The implementation uses only integer and +// bitwise operators, so no floating point hardware support or emulation is +// needed. This is here so quantized operations can run non-time-critical +// preparation calculations on microcontrollers and other platforms without +// float support. +double DoubleFromFractionAndShift(int64_t fraction, int shift); + +// Performs a multiplication of two numbers in double format, using only integer +// and bitwise instructions. This is aimed at supporting housekeeping functions +// for quantized operations on microcontrollers without floating-point hardware. +double IntegerDoubleMultiply(double a, double b); + +// Returns -1 if a is less than b, 0 if a and b are equal, and +1 if a is +// greater than b. It is implemented using only integer and logical instructions +// so that it can be easily run on microcontrollers for quantized operations. +int IntegerDoubleCompare(double a, double b); + +// This first creates a multiplier in a double equivalent of +// Q(input_integer_bits).(31-input_integer_bits) representation, with extra +// precision in the double's fractional bits. It then splits the result into +// significand and exponent. +void PreprocessSoftmaxScaling(double beta, double input_scale, + int input_integer_bits, + int32_t* quantized_multiplier, int* left_shift); +// Like PreprocessSoftmaxScaling, but inverse scaling factors also calculated. +void PreprocessLogSoftmaxScalingExp(double beta, double input_scale, + int input_integer_bits, + int32_t* quantized_multiplier, + int* left_shift, + int32_t* reverse_scaling_divisor, + int* reverse_scaling_left_shift); +// Calculate the largest input that will result in a within-bounds intermediate +// result within MultiplyByQuantizedMultiplierGreaterThanOne. In other words, +// it must not overflow before we reduce the value by multiplication by the +// input multiplier. The negative radius is used as the minimum difference in +// Softmax. +int CalculateInputRadius(int input_integer_bits, int input_left_shift, + int total_signed_bits = 31); + +// Nudges a min/max quantization range to ensure zero is zero. +// Gymnastics with nudged zero point is to ensure that real zero maps to +// an integer, which is required for e.g. zero-padding in convolutional layers. +// Outputs nudged_min, nudged_max, nudged_scale. +void NudgeQuantizationRange(const float min, const float max, + const int quant_min, const int quant_max, + float* nudged_min, float* nudged_max, + float* nudged_scale); + +// Fake quantizes (quantizes and dequantizes) input_data using the scale, +// nudged_min, and nudged_max from NudgeQuantizationRange. This matches the code +// in TensorFlow's FakeQuantizeWithMinMaxVarsFunctor. +void FakeQuantizeArray(const float nudged_scale, const float nudged_min, + const float nudged_max, const float* input_data, + float* output_data, const float size); + +// If x is approximately a power of two (with any positive or negative +// exponent), stores that exponent (i.e. log2(x)) in *log2_result, otherwise +// returns false. +bool CheckedLog2(const float x, int* log2_result); + +// Decomposes an array of double multipliers into a Q0.31 int32 representation +// of its significand, and shift representation of its exponent. +// +// Handles an arbitrary multiplier. The 'shift' output-value is +// basically the 'floating-point exponent' of the multiplier: +// Negative for a right-shift (when the multiplier is <1), positive for a +// left-shift (when the multiplier is >1) +void QuantizeMultiplierArray(const double* effective_scales, size_t size, + int32_t* effective_scale_significand, + int* effective_shift); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_QUANTIZATION_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/add.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/add.h new file mode 100644 index 000000000..ae1f47a83 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/add.h @@ -0,0 +1,400 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ADD_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ADD_H_ + +#include +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { + +namespace reference_ops { + +template +inline void Add(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + T activation_min, activation_max; + GetActivationParams(params, &activation_min, &activation_max); + + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = ActivationFunctionWithMinMax( + input1_data[i] + input2_data[i], activation_min, activation_max); + } +} + +// Element-wise add that can often be used for inner loop of broadcast add as +// well as the non-broadcast add. + +// This function is used for 8-bit as well as for 16-bit, but the accumulator +// is 32-bit for both cases. The overflow does not happen due to the +// choice of the shift (20 or 15, accordingly - see add.cc for more comments). +template +inline void AddElementwise(int size, const ArithmeticParams& params, + const T* input1_data, const T* input2_data, + T* output_data) { + TFLITE_DCHECK_GT(params.input1_offset, -std::numeric_limits::max()); + TFLITE_DCHECK_GT(params.input2_offset, -std::numeric_limits::max()); + TFLITE_DCHECK_LT(params.input1_offset, std::numeric_limits::max()); + TFLITE_DCHECK_LT(params.input2_offset, std::numeric_limits::max()); + + for (int i = 0; i < size; ++i) { + const int32_t input1_val = params.input1_offset + input1_data[i]; + const int32_t input2_val = params.input2_offset + input2_data[i]; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sum = scaled_input1_val + scaled_input2_val; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sum, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[i] = static_cast(clamped_output); + } +} + +// Scalar-broadcast add that can be used for inner loop of more general +// broadcast add, so that, for example, scalar-broadcast with batch will still +// be fast. +inline void AddScalarBroadcast(int size, const ArithmeticParams& params, + uint8_t input1_data, const uint8_t* input2_data, + uint8_t* output_data) { + TFLITE_DCHECK_GT(params.input1_offset, -256); + TFLITE_DCHECK_GT(params.input2_offset, -256); + TFLITE_DCHECK_LT(params.input1_offset, 256); + TFLITE_DCHECK_LT(params.input2_offset, 256); + + const int32_t input1_val = params.input1_offset + input1_data; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + for (int i = 0; i < size; ++i) { + const int32_t input2_val = params.input2_offset + input2_data[i]; + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sum = scaled_input1_val + scaled_input2_val; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sum, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[i] = static_cast(clamped_output); + } +} + +inline void Add(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const uint8_t* input1_data, + const RuntimeShape& input2_shape, const uint8_t* input2_data, + const RuntimeShape& output_shape, uint8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + TFLITE_DCHECK_GT(params.input1_offset, -256); + TFLITE_DCHECK_GT(params.input2_offset, -256); + TFLITE_DCHECK_LT(params.input1_offset, 256); + TFLITE_DCHECK_LT(params.input2_offset, 256); + AddElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void AddGeneralParamScale(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const int16_t* input1_data, + const RuntimeShape& input2_shape, + const int16_t* input2_data, + const RuntimeShape& output_shape, + int16_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + int max_value = std::numeric_limits::max(); + + TFLITE_DCHECK_GT(params.input1_offset, -max_value); + TFLITE_DCHECK_GT(params.input2_offset, -max_value); + TFLITE_DCHECK_LT(params.input1_offset, max_value); + TFLITE_DCHECK_LT(params.input2_offset, max_value); + AddElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void Add(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const int16_t* input1_data, + const RuntimeShape& input2_shape, const int16_t* input2_data, + const RuntimeShape& output_shape, int16_t* output_data, + bool pot_scale = true) { + if (!pot_scale) { + AddGeneralParamScale(params, input1_shape, input1_data, input2_shape, + input2_data, output_shape, output_data); + return; + } + + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + + const int input1_shift = params.input1_shift; + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + const int16_t output_activation_min = params.quantized_activation_min; + const int16_t output_activation_max = params.quantized_activation_max; + + TFLITE_DCHECK(input1_shift == 0 || params.input2_shift == 0); + TFLITE_DCHECK_LE(input1_shift, 0); + TFLITE_DCHECK_LE(params.input2_shift, 0); + const int16_t* not_shift_input = + input1_shift == 0 ? input1_data : input2_data; + const int16_t* shift_input = input1_shift == 0 ? input2_data : input1_data; + const int input_right_shift = + input1_shift == 0 ? -params.input2_shift : -input1_shift; + + for (int i = 0; i < flat_size; i++) { + // F0 uses 0 integer bits, range [-1, 1]. + using F0 = gemmlowp::FixedPoint; + + F0 input_ready_scaled = F0::FromRaw(not_shift_input[i]); + F0 scaled_input = F0::FromRaw( + gemmlowp::RoundingDivideByPOT(shift_input[i], input_right_shift)); + F0 result = gemmlowp::SaturatingAdd(scaled_input, input_ready_scaled); + const int16_t raw_output = result.raw(); + const int16_t clamped_output = std::min( + output_activation_max, std::max(output_activation_min, raw_output)); + output_data[i] = clamped_output; + } +} + +template +inline typename std::enable_if::value, void>::type +BroadcastAdd4DSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + + T activation_min, activation_max; + GetActivationParams(params, &activation_min, &activation_max); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + output_data[Offset(extended_output_shape, b, y, x, c)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, b, y, x, c)] + + input2_data[SubscriptToIndex(desc2, b, y, x, c)], + activation_min, activation_max); + } + } + } + } +} + +// This function is used for 8-bit as well as for 16-bit, but the accumulator +// is 32-bit for both cases. The overflow does not happen due to the +// choice of the shift (20 or 15, accordingly - see add.cc for more comments). +template +inline typename std::enable_if::value, void>::type +BroadcastAdd4DSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + const int32_t input1_val = + params.input1_offset + + input1_data[SubscriptToIndex(desc1, b, y, x, c)]; + const int32_t input2_val = + params.input2_offset + + input2_data[SubscriptToIndex(desc2, b, y, x, c)]; + const int32_t shifted_input1_val = + input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = + input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, + params.input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, + params.input2_shift); + const int32_t raw_sum = scaled_input1_val + scaled_input2_val; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sum, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[Offset(extended_output_shape, b, y, x, c)] = + static_cast(clamped_output); + } + } + } + } +} + +inline void BroadcastAddFivefold(const ArithmeticParams& unswitched_params, + const RuntimeShape& unswitched_input1_shape, + const uint8_t* unswitched_input1_data, + const RuntimeShape& unswitched_input2_shape, + const uint8_t* unswitched_input2_data, + const RuntimeShape& output_shape, + uint8_t* output_data) { + ArithmeticParams switched_params = unswitched_params; + switched_params.input1_offset = unswitched_params.input2_offset; + switched_params.input1_multiplier = unswitched_params.input2_multiplier; + switched_params.input1_shift = unswitched_params.input2_shift; + switched_params.input2_offset = unswitched_params.input1_offset; + switched_params.input2_multiplier = unswitched_params.input1_multiplier; + switched_params.input2_shift = unswitched_params.input1_shift; + + const bool use_unswitched = + unswitched_params.broadcast_category == + tflite::BroadcastableOpCategory::kFirstInputBroadcastsFast; + + const ArithmeticParams& params = + use_unswitched ? unswitched_params : switched_params; + const uint8_t* input1_data = + use_unswitched ? unswitched_input1_data : unswitched_input2_data; + const uint8_t* input2_data = + use_unswitched ? unswitched_input2_data : unswitched_input1_data; + + // Fivefold nested loops. The second input resets its position for each + // iteration of the second loop. The first input resets its position at the + // beginning of the fourth loop. The innermost loop is an elementwise add of + // sections of the arrays. + uint8_t* output_data_ptr = output_data; + const uint8_t* input1_data_ptr = input1_data; + const uint8_t* input2_data_reset = input2_data; + // In the fivefold pattern, y0, y2 and y4 are not broadcast, and so shared + // between input shapes. y3 for input 1 is always broadcast, and so the + // dimension there is 1, whereas optionally y1 might be broadcast for input 2. + // Put another way, + // input1.shape.FlatSize = y0 * y1 * y2 * y4, + // input2.shape.FlatSize = y0 * y2 * y3 * y4. + int y0 = params.broadcast_shape[0]; + int y1 = params.broadcast_shape[1]; + int y2 = params.broadcast_shape[2]; + int y3 = params.broadcast_shape[3]; + int y4 = params.broadcast_shape[4]; + if (y4 > 1) { + // General fivefold pattern, with y4 > 1 so there is a non-broadcast inner + // dimension. + for (int i0 = 0; i0 < y0; ++i0) { + const uint8_t* input2_data_ptr; + for (int i1 = 0; i1 < y1; ++i1) { + input2_data_ptr = input2_data_reset; + for (int i2 = 0; i2 < y2; ++i2) { + for (int i3 = 0; i3 < y3; ++i3) { + AddElementwise(y4, params, input1_data_ptr, input2_data_ptr, + output_data_ptr); + input2_data_ptr += y4; + output_data_ptr += y4; + } + // We have broadcast y4 of input1 data y3 times, and now move on. + input1_data_ptr += y4; + } + } + // We have broadcast y2*y3*y4 of input2 data y1 times, and now move on. + input2_data_reset = input2_data_ptr; + } + } else { + // Special case of y4 == 1, in which the innermost loop is a single element + // and can be combined with the next (y3) as an inner broadcast. + // + // Note that this handles the case of pure scalar broadcast when + // y0 == y1 == y2 == 1. With low overhead it handles cases such as scalar + // broadcast with batch (as y2 > 1). + // + // NOTE The process is the same as the above general case except simplified + // for y4 == 1 and the loop over y3 is contained within the + // AddScalarBroadcast function. + for (int i0 = 0; i0 < y0; ++i0) { + const uint8_t* input2_data_ptr; + for (int i1 = 0; i1 < y1; ++i1) { + input2_data_ptr = input2_data_reset; + for (int i2 = 0; i2 < y2; ++i2) { + AddScalarBroadcast(y3, params, *input1_data_ptr, input2_data_ptr, + output_data_ptr); + input2_data_ptr += y3; + output_data_ptr += y3; + input1_data_ptr += 1; + } + } + input2_data_reset = input2_data_ptr; + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ADD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/add_n.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/add_n.h new file mode 100644 index 000000000..b6b5882d8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/add_n.h @@ -0,0 +1,86 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ADD_N_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ADD_N_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_ops { + +// T is expected to be either float or int. +template +inline void AddN(const RuntimeShape& input_shape, const size_t num_inputs, + const T* const* input_data, T* output_data) { + // All inputs and output should have the same shape, this is checked during + // Prepare stage. + const size_t size = input_shape.FlatSize(); + for (size_t i = 0; i < size; ++i) { + T x = 0; + for (size_t j = 0; j < num_inputs; ++j) { + x += input_data[j][i]; + } + output_data[i] = x; + } +} + +inline void AddN(const ArithmeticParams& params, + const RuntimeShape& input_shape, const size_t num_inputs, + const int8_t* const* input_data, int8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + // Input offset is negative input zero point. Activation tensors are + // asymmetric quantized so they span the full int8 range. + // All inputs should have same zero-point and scale, this is checked during + // Prepare stage. + TFLITE_DCHECK_GE(-params.input1_offset, std::numeric_limits::min()); + TFLITE_DCHECK_LE(-params.input1_offset, std::numeric_limits::max()); + + // All inputs and output should have the same shape, this is checked during + // Prepare stage. + const size_t size = input_shape.FlatSize(); + for (size_t i = 0; i < size; ++i) { + // accumulate in scaled_x before clamping to avoid overflow + const int32_t x = params.input1_offset; // x = 0 + const int32_t shifted_x = x * (1 << params.left_shift); + int32_t scaled_x = MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_x, params.input1_multiplier, params.input1_shift); + + for (size_t j = 0; j < num_inputs; ++j) { + const int32_t y = params.input1_offset + input_data[j][i]; + const int32_t shifted_y = y * (1 << params.left_shift); + int32_t scaled_y = MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_y, params.input1_multiplier, params.input1_shift); + scaled_x += scaled_y; + } + + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + scaled_x, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[i] = static_cast(clamped_output); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ADD_N_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/arg_min_max.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/arg_min_max.h new file mode 100644 index 000000000..8154fbf71 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/arg_min_max.h @@ -0,0 +1,88 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ARG_MIN_MAX_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ARG_MIN_MAX_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +std::function GetComparefunction(bool is_arg_max) { + if (is_arg_max) { + return std::greater(); + } else { + return std::less(); + } +} + +template +void ArgMinMax(const RuntimeShape& input1_shape, const T1* input1_data, + const T3* input2_data, const RuntimeShape& output_shape, + T2* output_data, const Cmp& cmp) { + TFLITE_DCHECK_GT(input1_shape.DimensionsCount(), 0); + TFLITE_DCHECK_EQ(input1_shape.DimensionsCount() - 1, + output_shape.DimensionsCount()); + int axis = input2_data[0]; + if (axis < 0) { + axis += input1_shape.DimensionsCount(); + } + const int axis_size = input1_shape.Dims(axis); + + int outer_size = 1; + for (int i = 0; i < axis; ++i) { + TFLITE_DCHECK_EQ(input1_shape.Dims(i), output_shape.Dims(i)); + outer_size *= input1_shape.Dims(i); + } + + int inner_size = 1; + const int dims_count = input1_shape.DimensionsCount(); + for (int i = axis + 1; i < dims_count; ++i) { + TFLITE_DCHECK_EQ(input1_shape.Dims(i), output_shape.Dims(i - 1)); + inner_size *= input1_shape.Dims(i); + } + for (int outer = 0; outer < outer_size; ++outer) { + for (int inner = 0; inner < inner_size; ++inner) { + auto min_max_value = input1_data[outer * axis_size * inner_size + inner]; + T2 min_max_index = 0; + for (int i = 1; i < axis_size; ++i) { + const auto& curr_value = + input1_data[(outer * axis_size + i) * inner_size + inner]; + if (cmp(curr_value, min_max_value)) { + min_max_value = curr_value; + min_max_index = static_cast(i); + } + } + output_data[outer * inner_size + inner] = min_max_index; + } + } +} + +template +void ArgMinMax(const RuntimeShape& input1_shape, const T1* input1_data, + const T3* input2_data, const RuntimeShape& output_shape, + T2* output_data, const bool is_arg_max) { + ArgMinMax(input1_shape, input1_data, input2_data, output_shape, output_data, + GetComparefunction(is_arg_max)); +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ARG_MIN_MAX_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/batch_matmul.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/batch_matmul.h new file mode 100644 index 000000000..767ad6ab0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/batch_matmul.h @@ -0,0 +1,275 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BATCH_MATMUL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BATCH_MATMUL_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { +namespace batch_matmul { + +// Determine which dimension is the broadcast dimension. +inline int broadcast_dim(int lhs_dim, int rhs_dim) { + if (lhs_dim == rhs_dim) return lhs_dim; + if (lhs_dim == 1) return rhs_dim; + TFLITE_DCHECK_EQ(rhs_dim, 1); + return lhs_dim; +} + +// Compute the "extent" for iterating on this dimension. +// If we are broadcasting, then don't advance (i.e return 0). +inline int extent(const RuntimeShape& shape, int x) { + if (shape.Dims(x) == 1) { + return 0; + } + int prod = 1; + for (int i = x + 1; i < shape.DimensionsCount(); ++i) { + prod *= shape.Dims(i); + } + return prod; +} + +} // namespace batch_matmul + +template +inline void BatchMatMul(const RuntimeShape& lhs_shape, const Ta* lhs_data, + const RuntimeShape& rhs_shape, const Tb* rhs_data, + const RuntimeShape& output_shape, Tout* output_data) { + const RuntimeShape extended_lhs_shape = + RuntimeShape::ExtendedShape(5, lhs_shape); + const RuntimeShape extended_rhs_shape = + RuntimeShape::ExtendedShape(5, rhs_shape); + + const int batch_dim0 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(0), extended_rhs_shape.Dims(0)); + const int batch_dim1 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(1), extended_rhs_shape.Dims(1)); + const int batch_dim2 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(2), extended_rhs_shape.Dims(2)); + + const int lhs_ext0 = batch_matmul::extent(extended_lhs_shape, 0); + const int lhs_ext1 = batch_matmul::extent(extended_lhs_shape, 1); + const int lhs_ext2 = batch_matmul::extent(extended_lhs_shape, 2); + const int rhs_ext0 = batch_matmul::extent(extended_rhs_shape, 0); + const int rhs_ext1 = batch_matmul::extent(extended_rhs_shape, 1); + const int rhs_ext2 = batch_matmul::extent(extended_rhs_shape, 2); + + // Set params for each matrix multiply. + const int lhs_rows = extended_lhs_shape.Dims(3); + const int rhs_cols = extended_rhs_shape.Dims(4); + const int accum_depth = extended_lhs_shape.Dims(4); + + for (int b0 = 0; b0 < batch_dim0; ++b0) { + const Ta* lhs_ptr0 = lhs_data + (b0 * lhs_ext0); + const Tb* rhs_ptr0 = rhs_data + (b0 * rhs_ext0); + for (int b1 = 0; b1 < batch_dim1; ++b1) { + const Ta* lhs_ptr1 = lhs_ptr0 + b1 * lhs_ext1; + const Tb* rhs_ptr1 = rhs_ptr0 + b1 * rhs_ext1; + for (int b2 = 0; b2 < batch_dim2; ++b2) { + const Ta* lhs_ptr2 = lhs_ptr1 + b2 * lhs_ext2; + const Tb* rhs_ptr2 = rhs_ptr1 + b2 * rhs_ext2; + Tout* out_ptr = output_data + ((b0 * batch_dim1 * batch_dim2) + + b1 * batch_dim2 + b2) * + lhs_rows * rhs_cols; + for (int j = 0; j < rhs_cols; ++j) { + for (int i = 0; i < lhs_rows; ++i) { + Tout total = 0; + for (int k = 0; k < accum_depth; ++k) { + total += static_cast(lhs_ptr2[accum_depth * i + k]) * + static_cast(rhs_ptr2[j * accum_depth + k]); + } + int idx = lhs_rows * j + i; + out_ptr[idx] = total; + } + } + } + } + } +} + +inline void BatchMatMul(const RuntimeShape& lhs_shape, const int8_t* lhs_data, + const RuntimeShape& rhs_shape, const int8_t* rhs_data, + const float* scaling_factors, + const int32_t* input_offset, int32_t* row_sums, + const RuntimeShape& output_shape, float* output_data, + bool* compute_row_sums) { + const RuntimeShape extended_lhs_shape = + RuntimeShape::ExtendedShape(5, lhs_shape); + const RuntimeShape extended_rhs_shape = + RuntimeShape::ExtendedShape(5, rhs_shape); + + const int batch_dim0 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(0), extended_rhs_shape.Dims(0)); + const int batch_dim1 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(1), extended_rhs_shape.Dims(1)); + const int batch_dim2 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(2), extended_rhs_shape.Dims(2)); + + const int lhs_ext0 = batch_matmul::extent(extended_lhs_shape, 0); + const int lhs_ext1 = batch_matmul::extent(extended_lhs_shape, 1); + const int lhs_ext2 = batch_matmul::extent(extended_lhs_shape, 2); + const int rhs_ext0 = batch_matmul::extent(extended_rhs_shape, 0); + const int rhs_ext1 = batch_matmul::extent(extended_rhs_shape, 1); + const int rhs_ext2 = batch_matmul::extent(extended_rhs_shape, 2); + + // Set params for each matrix multiply. + const int lhs_rows = extended_lhs_shape.Dims(3); + const int rhs_cols = extended_rhs_shape.Dims(4); + const int accum_depth = extended_lhs_shape.Dims(4); + + const int ioff_ext0 = rhs_ext0 == 0 ? 0 : rhs_cols; + const int ioff_ext1 = rhs_ext1 == 0 ? 0 : rhs_cols; + const int ioff_ext2 = rhs_ext2 == 0 ? 0 : rhs_cols; + const int woff_ext0 = lhs_ext0 == 0 ? 0 : lhs_rows; + const int woff_ext1 = lhs_ext1 == 0 ? 0 : lhs_rows; + const int woff_ext2 = lhs_ext2 == 0 ? 0 : lhs_rows; + + if (!compute_row_sums || *compute_row_sums) { + int num_weights_matrices = 1; + for (int i = 1; i < extended_lhs_shape.DimensionsCount() - 2; ++i) { + num_weights_matrices *= extended_lhs_shape.Dims(i); + } + tensor_utils::ReductionSumVector( + lhs_data, row_sums, num_weights_matrices * lhs_rows, accum_depth); + if (compute_row_sums) { + *compute_row_sums = false; + } + } + + for (int b0 = 0; b0 < batch_dim0; ++b0) { + const int8_t* lhs_ptr0 = lhs_data + (b0 * lhs_ext0); + const int8_t* rhs_ptr0 = rhs_data + (b0 * rhs_ext0); + const int32_t* ioff_ptr0 = input_offset + (b0 * ioff_ext0); + const float* scale_ptr0 = scaling_factors + (b0 * ioff_ext0); + const int32_t* woff_ptr0 = row_sums + (b0 * woff_ext0); + for (int b1 = 0; b1 < batch_dim1; ++b1) { + const int8_t* lhs_ptr1 = lhs_ptr0 + b1 * lhs_ext1; + const int8_t* rhs_ptr1 = rhs_ptr0 + b1 * rhs_ext1; + const int32_t* ioff_ptr1 = ioff_ptr0 + (b1 * ioff_ext1); + const float* scale_ptr1 = scale_ptr0 + (b1 * ioff_ext1); + const int32_t* woff_ptr1 = woff_ptr0 + (b1 * woff_ext1); + for (int b2 = 0; b2 < batch_dim2; ++b2) { + const int8_t* lhs_ptr2 = lhs_ptr1 + b2 * lhs_ext2; + const int8_t* rhs_ptr2 = rhs_ptr1 + b2 * rhs_ext2; + const int32_t* ioff_ptr2 = ioff_ptr1 + (b2 * ioff_ext2); + const float* scale_ptr2 = scale_ptr1 + (b2 * ioff_ext2); + const int32_t* woff_ptr2 = woff_ptr1 + (b2 * woff_ext2); + float* out_ptr = output_data + ((b0 * batch_dim1 * batch_dim2) + + b1 * batch_dim2 + b2) * + lhs_rows * rhs_cols; + for (int j = 0; j < rhs_cols; ++j) { + const float batch_scaling_factor = scale_ptr2[j]; + const float batch_offset = static_cast(ioff_ptr2[j]); + for (int i = 0; i < lhs_rows; ++i) { + int32_t total = 0; + for (int k = 0; k < accum_depth; ++k) { + total += + lhs_ptr2[accum_depth * i + k] * rhs_ptr2[j * accum_depth + k]; + } + int32_t row_sum = woff_ptr2[i]; + total -= row_sum * batch_offset; + int idx = lhs_rows * j + i; + out_ptr[idx] += batch_scaling_factor * total; + } + } + } + } + } +} + +template +inline void BatchMatMul(const FullyConnectedParams& params, + const RuntimeShape& lhs_shape, const T* lhs_data, + const RuntimeShape& rhs_shape, const T* rhs_data, + const RuntimeShape& output_shape, T* output_data) { + const RuntimeShape extended_lhs_shape = + RuntimeShape::ExtendedShape(5, lhs_shape); + const RuntimeShape extended_rhs_shape = + RuntimeShape::ExtendedShape(5, rhs_shape); + + const int batch_dim0 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(0), extended_rhs_shape.Dims(0)); + const int batch_dim1 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(1), extended_rhs_shape.Dims(1)); + const int batch_dim2 = batch_matmul::broadcast_dim( + extended_lhs_shape.Dims(2), extended_rhs_shape.Dims(2)); + + const int lhs_ext0 = batch_matmul::extent(extended_lhs_shape, 0); + const int lhs_ext1 = batch_matmul::extent(extended_lhs_shape, 1); + const int lhs_ext2 = batch_matmul::extent(extended_lhs_shape, 2); + const int rhs_ext0 = batch_matmul::extent(extended_rhs_shape, 0); + const int rhs_ext1 = batch_matmul::extent(extended_rhs_shape, 1); + const int rhs_ext2 = batch_matmul::extent(extended_rhs_shape, 2); + + // Set params for each matrix multiply. + const int lhs_rows = extended_lhs_shape.Dims(3); + const int rhs_cols = extended_rhs_shape.Dims(4); + const int accum_depth = extended_lhs_shape.Dims(4); + + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + + for (int b0 = 0; b0 < batch_dim0; ++b0) { + const T* lhs_ptr0 = lhs_data + (b0 * lhs_ext0); + const T* rhs_ptr0 = rhs_data + (b0 * rhs_ext0); + for (int b1 = 0; b1 < batch_dim1; ++b1) { + const T* lhs_ptr1 = lhs_ptr0 + b1 * lhs_ext1; + const T* rhs_ptr1 = rhs_ptr0 + b1 * rhs_ext1; + for (int b2 = 0; b2 < batch_dim2; ++b2) { + const T* lhs_ptr2 = lhs_ptr1 + b2 * lhs_ext2; + const T* rhs_ptr2 = rhs_ptr1 + b2 * rhs_ext2; + T* out_ptr = output_data + + ((b0 * batch_dim1 * batch_dim2) + b1 * batch_dim2 + b2) * + lhs_rows * rhs_cols; + + for (int j = 0; j < rhs_cols; ++j) { + for (int i = 0; i < lhs_rows; ++i) { + AccumT total = 0; + for (int k = 0; k < accum_depth; ++k) { + AccumT lhs_val = lhs_ptr2[accum_depth * i + k]; + AccumT rhs_val = rhs_ptr2[accum_depth * j + k]; + total += (lhs_val + filter_offset) * (rhs_val + input_offset); + } + int32_t total_scaled = MultiplyByQuantizedMultiplier( + total, output_multiplier, output_shift); + total_scaled += output_offset; + total_scaled = std::max(total_scaled, output_activation_min); + total_scaled = std::min(total_scaled, output_activation_max); + const int idx = lhs_rows * j + i; + out_ptr[idx] = static_cast(total_scaled); + } + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BATCH_MATMUL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/batch_to_space_nd.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/batch_to_space_nd.h new file mode 100644 index 000000000..54c526077 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/batch_to_space_nd.h @@ -0,0 +1,101 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BATCH_TO_SPACE_ND_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BATCH_TO_SPACE_ND_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +// TODO(b/135760455): Move this method anonymous namespace in a cc file. +inline RuntimeShape ExtendShapeBatchToSpace(const RuntimeShape& shape) { + if (shape.DimensionsCount() == 4) { + return shape; + } + RuntimeShape new_shape(4, 1); + new_shape.SetDim(0, shape.Dims(0)); + new_shape.SetDim(1, shape.Dims(1)); + new_shape.SetDim(3, shape.Dims(2)); + return new_shape; +} + +template +inline void BatchToSpaceND(const RuntimeShape& unextended_input1_shape, + const T* input1_data, + const RuntimeShape& unextended_input2_shape, + const int32_t* block_shape_data, + const RuntimeShape& unextended_input3_shape, + const int32_t* crops_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + ruy::profiler::ScopeLabel label("BatchToSpaceND"); + TFLITE_DCHECK_GE(unextended_input1_shape.DimensionsCount(), 3); + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(unextended_input1_shape.DimensionsCount(), + unextended_output_shape.DimensionsCount()); + + const RuntimeShape input1_shape = + ExtendShapeBatchToSpace(unextended_input1_shape); + const RuntimeShape output_shape = + ExtendShapeBatchToSpace(unextended_output_shape); + + const int output_width = output_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_batch_size = output_shape.Dims(0); + + const int depth = input1_shape.Dims(3); + const int input_width = input1_shape.Dims(2); + const int input_height = input1_shape.Dims(1); + const int input_batch_size = input1_shape.Dims(0); + + const int block_shape_height = block_shape_data[0]; + const int block_shape_width = + unextended_input1_shape.DimensionsCount() == 4 ? block_shape_data[1] : 1; + const int crops_top = crops_data[0]; + const int crops_left = + unextended_input1_shape.DimensionsCount() == 4 ? crops_data[2] : 0; + for (int in_batch = 0; in_batch < input_batch_size; ++in_batch) { + const int out_batch = in_batch % output_batch_size; + const int spatial_offset = in_batch / output_batch_size; + for (int in_h = 0; in_h < input_height; ++in_h) { + const int out_h = in_h * block_shape_height + + spatial_offset / block_shape_width - crops_top; + if (out_h < 0 || out_h >= output_height) { + continue; + } + for (int in_w = 0; in_w < input_width; ++in_w) { + const int out_w = in_w * block_shape_width + + spatial_offset % block_shape_width - crops_left; + + if (out_w < 0 || out_w >= output_width) { + continue; + } + T* out = output_data + Offset(output_shape, out_batch, out_h, out_w, 0); + const T* in = + input1_data + Offset(input1_shape, in_batch, in_h, in_w, 0); + memcpy(out, in, depth * sizeof(T)); + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BATCH_TO_SPACE_ND_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/binary_function.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/binary_function.h new file mode 100644 index 000000000..0b124af87 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/binary_function.h @@ -0,0 +1,91 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BINARY_FUNCTION_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BINARY_FUNCTION_H_ + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +// Also appears to duplicate MinimumMaximum. +// +// R: Result type. T1: Input 1 type. T2: Input 2 type. +template +inline void BroadcastBinaryFunction4DSlow( + const RuntimeShape& unextended_input1_shape, const T1* input1_data, + const RuntimeShape& unextended_input2_shape, const T2* input2_data, + const RuntimeShape& unextended_output_shape, R* output_data, + R (*func)(T1, T2)) { + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + + const int* dims_data = + reinterpret_cast(output_shape.DimsDataUpTo5D()); + for (int b = 0; b < output_shape.Dims(0); ++b) { + int out_idx_b = b * dims_data[1]; + int in_idx1_b = desc1.strides[0] * b; + int in_idx2_b = desc2.strides[0] * b; + for (int y = 0; y < output_shape.Dims(1); ++y) { + int out_idx_y = (out_idx_b + y) * dims_data[2]; + int in_idx1_y = in_idx1_b + desc1.strides[1] * y; + int in_idx2_y = in_idx2_b + desc2.strides[1] * y; + for (int x = 0; x < output_shape.Dims(2); ++x) { + int out_idx_x = (out_idx_y + x) * dims_data[3]; + int in1_idx = in_idx1_y + desc1.strides[2] * x; + int in2_idx = in_idx2_y + desc2.strides[2] * x; + for (int c = 0; c < output_shape.Dims(3); ++c) { + auto out_idx = out_idx_x + c; + auto in1_val = input1_data[in1_idx]; + auto in2_val = input2_data[in2_idx]; + output_data[out_idx] = func(in1_val, in2_val); + in1_idx += desc1.strides[3]; + in2_idx += desc2.strides[3]; + } + } + } + } +} + +// R: Result type. T1: Input 1 type. T2: Input 2 type. +template +inline void BinaryFunction(const RuntimeShape& input1_shape, + const T1* input1_data, + const RuntimeShape& input2_shape, + const T2* input2_data, + const RuntimeShape& output_shape, R* output_data, + R (*func)(T1, T2)) { + const int flat_size = + MatchingFlatSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = func(input1_data[i], input2_data[i]); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BINARY_FUNCTION_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/broadcast_args.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/broadcast_args.h new file mode 100644 index 000000000..d93c316d1 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/broadcast_args.h @@ -0,0 +1,56 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BROADCAST_ARGS_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BROADCAST_ARGS_H_ + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +void BroadcastArgs(const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + // Gets data at the backward index i of the shape tensor. Returns 1 if the + // index is out of range. + auto get_shape_data = [](const RuntimeShape& shape, const T* data, + int backward_idx) -> T { + int forward_idx = shape.FlatSize() - 1 - backward_idx; + if (forward_idx < 0) return 1; + return data[forward_idx]; + }; + + int output_num_elements = output_shape.FlatSize(); + for (int i = 0; i < output_num_elements; ++i) { + int backward_i = output_num_elements - 1 - i; + int shape1_i = get_shape_data(input1_shape, input1_data, i); + int shape2_i = get_shape_data(input2_shape, input2_data, i); + if (shape1_i == 1) { + output_data[backward_i] = shape2_i; + } else if (shape2_i == 1) { + output_data[backward_i] = shape1_i; + } else { + TFLITE_CHECK_EQ(shape1_i, shape2_i); + output_data[backward_i] = shape1_i; + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BROADCAST_ARGS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/broadcast_to.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/broadcast_to.h new file mode 100644 index 000000000..f106b2b52 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/broadcast_to.h @@ -0,0 +1,97 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BROADCAST_TO_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BROADCAST_TO_H_ + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/kernel_util.h" + +namespace tflite { +namespace reference_ops { +template +void BroadcastImpl(const NdArrayDesc& input_desc, const char* input_data, + const NdArrayDesc& output_desc, char* output_data, + int indexes[N], int dim, const int last_broadcasting_dim, + const int type_size) { + // Copy data from input to output. + if (dim == last_broadcasting_dim) { + int copy_size = output_desc.strides[dim] * type_size; + const char* data_src = + input_data + SubscriptToIndex(input_desc, indexes) * type_size; + char* data_dst = + output_data + SubscriptToIndex(output_desc, indexes) * type_size; + for (int i = 0; i < output_desc.extents[dim]; ++i, data_dst += copy_size) { + memcpy(data_dst, data_src, copy_size); + } + return; + } + + // Recursive call to find the next broadcasting. + for (indexes[dim] = 0; indexes[dim] < input_desc.extents[dim]; + ++indexes[dim]) { + BroadcastImpl(input_desc, input_data, output_desc, output_data, indexes, + dim + 1, last_broadcasting_dim, type_size); + } + + // Duplicate data in output tensor. + indexes[dim] = 0; + if (input_desc.extents[dim] != output_desc.extents[dim]) { + int copy_size = output_desc.strides[dim] * type_size; + char* data_src = + output_data + SubscriptToIndex(output_desc, indexes) * type_size; + char* data_dst = data_src + copy_size; + for (int i = 1; i < output_desc.extents[dim]; ++i, data_dst += copy_size) { + memcpy(data_dst, data_src, copy_size); + } + } +} + +template +inline void BroadcastTo(const RuntimeShape& unextended_input_shape, + const char* input_data, + const RuntimeShape& unextended_output_shape, + char* output_data, TfLiteType data_type) { + NdArrayDesc input_desc; + NdArrayDesc output_desc; + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_input_shape), + &input_desc); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_output_shape), + &output_desc); + + // Get the last dimension has broadcasting. At this dimension, the data is + // copied from input tensor to output tensor. + int last_broadcast_dim = -1; + for (int i = N - 1; i >= 0; --i) { + if (input_desc.extents[i] != output_desc.extents[i]) { + last_broadcast_dim = i; + break; + } + } + + // If non-broadcasting, just copy data from input to output tensor. + if (last_broadcast_dim == -1) { + memcpy(output_data, input_data, + unextended_input_shape.FlatSize() * TfLiteTypeGetSize(data_type)); + return; + } + + // Broadcasting using memcpy. + int indexes[N] = {0}; + BroadcastImpl(input_desc, input_data, output_desc, output_data, indexes, 0, + last_broadcast_dim, TfLiteTypeGetSize(data_type)); +} +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_BROADCAST_TO_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/ceil.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/ceil.h new file mode 100644 index 000000000..66d1dc359 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/ceil.h @@ -0,0 +1,37 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CEIL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CEIL_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void Ceil(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; ++i) { + output_data[i] = std::ceil(input_data[i]); + } +} + +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CEIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/comparisons.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/comparisons.h new file mode 100644 index 000000000..6344bdc72 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/comparisons.h @@ -0,0 +1,280 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_COMPARISONS_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_COMPARISONS_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +inline bool EqualFn(T lhs, T rhs) { + return lhs == rhs; +} + +template +inline bool NotEqualFn(T lhs, T rhs) { + return lhs != rhs; +} + +template +inline bool GreaterFn(T lhs, T rhs) { + return lhs > rhs; +} +template +inline bool GreaterEqualFn(T lhs, T rhs) { + return lhs >= rhs; +} +template +inline bool LessFn(T lhs, T rhs) { + return lhs < rhs; +} +template +inline bool LessEqualFn(T lhs, T rhs) { + return lhs <= rhs; +} + +template +using ComparisonFn = bool (*)(T, T); + +template F> +inline void ComparisonImpl( + const ComparisonParams& op_params, const RuntimeShape& input1_shape, + const T* input1_data, const RuntimeShape& input2_shape, + const T* input2_data, const RuntimeShape& output_shape, bool* output_data) { + const int64_t flatsize = + MatchingFlatSize(input1_shape, input2_shape, output_shape); + for (int64_t i = 0; i < flatsize; ++i) { + output_data[i] = F(input1_data[i], input2_data[i]); + } +} + +template F> +inline void Comparison(const ComparisonParams& op_params, + const RuntimeShape& input1_shape, + const float* input1_data, + const RuntimeShape& input2_shape, + const float* input2_data, + const RuntimeShape& output_shape, bool* output_data) { + ComparisonImpl(op_params, input1_shape, input1_data, input2_shape, + input2_data, output_shape, output_data); +} + +template F> +inline void ComparisonWithScaling( + const ComparisonParams& op_params, const RuntimeShape& input1_shape, + const T* input1_data, const RuntimeShape& input2_shape, + const T* input2_data, const RuntimeShape& output_shape, bool* output_data) { + int left_shift = op_params.left_shift; + int32_t input1_offset = op_params.input1_offset; + int32_t input1_multiplier = op_params.input1_multiplier; + int input1_shift = op_params.input1_shift; + int32_t input2_offset = op_params.input2_offset; + int32_t input2_multiplier = op_params.input2_multiplier; + int input2_shift = op_params.input2_shift; + + const int64_t flatsize = + MatchingFlatSize(input1_shape, input2_shape, output_shape); + for (int64_t i = 0; i < flatsize; ++i) { + const int32_t input1_val = input1_offset + input1_data[i]; + const int32_t input2_val = input2_offset + input2_data[i]; + const int32_t shifted_input1_val = input1_val * (1 << left_shift); + const int32_t shifted_input2_val = input2_val * (1 << left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, input1_multiplier, input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, input2_multiplier, input2_shift); + output_data[i] = F(scaled_input1_val, scaled_input2_val); + } +} + +struct BroadcastComparison4DSlowCommon { + const RuntimeShape output_shape; + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; +}; + +inline BroadcastComparison4DSlowCommon BroadcastComparison4DSlowPreprocess( + const RuntimeShape& unextended_input1_shape, + const RuntimeShape& unextended_input2_shape, + const RuntimeShape& unextended_output_shape) { + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + return {RuntimeShape::ExtendedShape(4, unextended_output_shape), desc1, + desc2}; +} + +template F> +inline void BroadcastComparison4DSlowImpl( + const ComparisonParams& op_params, + const RuntimeShape& unextended_input1_shape, const T* input1_data, + const RuntimeShape& unextended_input2_shape, const T* input2_data, + const RuntimeShape& unextended_output_shape, bool* output_data) { + const BroadcastComparison4DSlowCommon dims = + BroadcastComparison4DSlowPreprocess(unextended_input1_shape, + unextended_input2_shape, + unextended_output_shape); + + for (int b = 0; b < dims.output_shape.Dims(0); ++b) { + for (int y = 0; y < dims.output_shape.Dims(1); ++y) { + for (int x = 0; x < dims.output_shape.Dims(2); ++x) { + for (int c = 0; c < dims.output_shape.Dims(3); ++c) { + output_data[Offset(dims.output_shape, b, y, x, c)] = + F(input1_data[SubscriptToIndex(dims.desc1, b, y, x, c)], + input2_data[SubscriptToIndex(dims.desc2, b, y, x, c)]); + } + } + } + } +} + +template F> +inline void BroadcastComparison4DSlow(const ComparisonParams& op_params, + const RuntimeShape& input1_shape, + const float* input1_data, + const RuntimeShape& input2_shape, + const float* input2_data, + const RuntimeShape& output_shape, + bool* output_data) { + BroadcastComparison4DSlowImpl(op_params, input1_shape, input1_data, + input2_shape, input2_data, + output_shape, output_data); +} + +template F> +inline void BroadcastComparison4DSlowWithScaling( + const ComparisonParams& op_params, + const RuntimeShape& unextended_input1_shape, const T* input1_data, + const RuntimeShape& unextended_input2_shape, const T* input2_data, + const RuntimeShape& unextended_output_shape, bool* output_data) { + const BroadcastComparison4DSlowCommon dims = + BroadcastComparison4DSlowPreprocess(unextended_input1_shape, + unextended_input2_shape, + unextended_output_shape); + + int left_shift = op_params.left_shift; + int32_t input1_offset = op_params.input1_offset; + int32_t input1_multiplier = op_params.input1_multiplier; + int input1_shift = op_params.input1_shift; + int32_t input2_offset = op_params.input2_offset; + int32_t input2_multiplier = op_params.input2_multiplier; + int input2_shift = op_params.input2_shift; + + for (int b = 0; b < dims.output_shape.Dims(0); ++b) { + for (int y = 0; y < dims.output_shape.Dims(1); ++y) { + for (int x = 0; x < dims.output_shape.Dims(2); ++x) { + for (int c = 0; c < dims.output_shape.Dims(3); ++c) { + const int32_t input1_val = + input1_offset + + input1_data[SubscriptToIndex(dims.desc1, b, y, x, c)]; + const int32_t input2_val = + input2_offset + + input2_data[SubscriptToIndex(dims.desc2, b, y, x, c)]; + const int32_t shifted_input1_val = input1_val * (1 << left_shift); + const int32_t shifted_input2_val = input2_val * (1 << left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, input1_multiplier, input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, input2_multiplier, input2_shift); + output_data[Offset(dims.output_shape, b, y, x, c)] = + F(scaled_input1_val, scaled_input2_val); + } + } + } + } +} + +#define TFLITE_COMPARISON_OP(name) \ + inline void name(const ComparisonParams& op_params, \ + const RuntimeShape& input1_shape, const float* input1_data, \ + const RuntimeShape& input2_shape, const float* input2_data, \ + const RuntimeShape& output_shape, bool* output_data) { \ + Comparison(op_params, input1_shape, input1_data, input2_shape, \ + input2_data, output_shape, output_data); \ + } \ + template \ + inline void name##NoScaling( \ + const ComparisonParams& op_params, const RuntimeShape& input1_shape, \ + const T* input1_data, const RuntimeShape& input2_shape, \ + const T* input2_data, const RuntimeShape& output_shape, \ + bool* output_data) { \ + ComparisonImpl(op_params, input1_shape, input1_data, \ + input2_shape, input2_data, output_shape, \ + output_data); \ + } \ + template \ + inline void name##WithScaling( \ + const ComparisonParams& op_params, const RuntimeShape& input1_shape, \ + const T* input1_data, const RuntimeShape& input2_shape, \ + const T* input2_data, const RuntimeShape& output_shape, \ + bool* output_data) { \ + ComparisonWithScaling(op_params, input1_shape, input1_data, \ + input2_shape, input2_data, \ + output_shape, output_data); \ + } \ + template \ + inline void Broadcast4DSlow##name##NoScaling( \ + const ComparisonParams& op_params, const RuntimeShape& input1_shape, \ + const T* input1_data, const RuntimeShape& input2_shape, \ + const T* input2_data, const RuntimeShape& output_shape, \ + bool* output_data) { \ + BroadcastComparison4DSlowImpl( \ + op_params, input1_shape, input1_data, input2_shape, input2_data, \ + output_shape, output_data); \ + } \ + inline void Broadcast4DSlow##name( \ + const ComparisonParams& op_params, const RuntimeShape& input1_shape, \ + const float* input1_data, const RuntimeShape& input2_shape, \ + const float* input2_data, const RuntimeShape& output_shape, \ + bool* output_data) { \ + BroadcastComparison4DSlow(op_params, input1_shape, input1_data, \ + input2_shape, input2_data, \ + output_shape, output_data); \ + } \ + template \ + inline void Broadcast4DSlow##name##WithScaling( \ + const ComparisonParams& op_params, const RuntimeShape& input1_shape, \ + const T* input1_data, const RuntimeShape& input2_shape, \ + const T* input2_data, const RuntimeShape& output_shape, \ + bool* output_data) { \ + BroadcastComparison4DSlowWithScaling( \ + op_params, input1_shape, input1_data, input2_shape, input2_data, \ + output_shape, output_data); \ + } +TFLITE_COMPARISON_OP(Equal); +TFLITE_COMPARISON_OP(NotEqual); +TFLITE_COMPARISON_OP(Greater); +TFLITE_COMPARISON_OP(GreaterEqual); +TFLITE_COMPARISON_OP(Less); +TFLITE_COMPARISON_OP(LessEqual); +#undef TFLITE_COMPARISON_OP + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_COMPARISONS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/concatenation.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/concatenation.h new file mode 100644 index 000000000..9d2ecbecc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/concatenation.h @@ -0,0 +1,141 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONCATENATION_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONCATENATION_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +inline void Concatenation(const ConcatenationParams& params, + const RuntimeShape* const* input_shapes, + const Scalar* const* input_data, + const RuntimeShape& output_shape, + Scalar* output_data) { + int axis = params.axis; + int inputs_count = params.inputs_count; + const int concat_dimensions = output_shape.DimensionsCount(); + TFLITE_DCHECK_LT(axis, concat_dimensions); + + int64_t concat_size = 0; + for (int i = 0; i < inputs_count; i++) { + TFLITE_DCHECK_EQ(input_shapes[i]->DimensionsCount(), concat_dimensions); + for (int j = 0; j < concat_dimensions; j++) { + if (j != axis) { + MatchingDim(*input_shapes[i], j, output_shape, j); + } + } + concat_size += input_shapes[i]->Dims(axis); + } + TFLITE_DCHECK_EQ(concat_size, output_shape.Dims(axis)); + int64_t outer_size = 1; + for (int i = 0; i < axis; ++i) { + outer_size *= output_shape.Dims(i); + } + // For all input arrays, + // FlatSize() = outer_size * Dims(axis) * base_inner_size; + int64_t base_inner_size = 1; + for (int i = axis + 1; i < concat_dimensions; ++i) { + base_inner_size *= output_shape.Dims(i); + } + + Scalar* output_ptr = output_data; + for (int k = 0; k < outer_size; k++) { + for (int i = 0; i < inputs_count; ++i) { + const int copy_size = input_shapes[i]->Dims(axis) * base_inner_size; + const Scalar* input_ptr = input_data[i] + k * copy_size; + memcpy(output_ptr, input_ptr, copy_size * sizeof(Scalar)); + output_ptr += copy_size; + } + } +} + +// TODO(b/174275780): The quantized implementation of concatentation isn't fully +// quantized as it takes scale as a floating point value. This should be fixed +// when optimizng this routine further. +inline void ConcatenationWithScaling(const ConcatenationParams& params, + const RuntimeShape* const* input_shapes, + const uint8_t* const* input_data, + const RuntimeShape& output_shape, + uint8_t* output_data) { + int axis = params.axis; + const int32_t* input_zeropoint = params.input_zeropoint; + const float* input_scale = params.input_scale; + int inputs_count = params.inputs_count; + const int32_t output_zeropoint = params.output_zeropoint; + const float output_scale = params.output_scale; + + const int concat_dimensions = output_shape.DimensionsCount(); + TFLITE_DCHECK_LT(axis, concat_dimensions); + + int64_t concat_size = 0; + for (int i = 0; i < inputs_count; i++) { + TFLITE_DCHECK_EQ(input_shapes[i]->DimensionsCount(), concat_dimensions); + for (int j = 0; j < concat_dimensions; j++) { + if (j != axis) { + MatchingDim(*input_shapes[i], j, output_shape, j); + } + } + concat_size += input_shapes[i]->Dims(axis); + } + TFLITE_DCHECK_EQ(concat_size, output_shape.Dims(axis)); + int64_t outer_size = 1; + for (int i = 0; i < axis; ++i) { + outer_size *= output_shape.Dims(i); + } + // For all input arrays, + // FlatSize() = outer_size * Dims(axis) * base_inner_size; + int64_t base_inner_size = 1; + for (int i = axis + 1; i < concat_dimensions; ++i) { + base_inner_size *= output_shape.Dims(i); + } + + const float inverse_output_scale = 1.f / output_scale; + uint8_t* output_ptr = output_data; + for (int k = 0; k < outer_size; k++) { + for (int i = 0; i < inputs_count; ++i) { + const int copy_size = input_shapes[i]->Dims(axis) * base_inner_size; + const uint8_t* input_ptr = input_data[i] + k * copy_size; + if (input_zeropoint[i] == output_zeropoint && + input_scale[i] == output_scale) { + memcpy(output_ptr, input_ptr, copy_size); + } else { + const float scale = input_scale[i] * inverse_output_scale; + const float bias = -input_zeropoint[i] * scale; + for (int j = 0; j < copy_size; ++j) { + const int32_t value = static_cast(tflite::TfLiteRound( + input_ptr[j] * scale + bias)) + + output_zeropoint; + output_ptr[j] = static_cast( + std::max(std::min(255, value), 0)); + } + } + output_ptr += copy_size; + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONCATENATION_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/conv.h new file mode 100644 index 000000000..3a53e06e7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/conv.h @@ -0,0 +1,287 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONV_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void Conv(const ConvParams& params, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& filter_shape, + const float* filter_data, const RuntimeShape& bias_shape, + const float* bias_data, const RuntimeShape& output_shape, + float* output_data, const RuntimeShape& im2col_shape, + float* im2col_data) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int filter_input_depth = filter_shape.Dims(3); + const int groups = input_depth / filter_input_depth; + TFLITE_DCHECK_EQ(input_depth % filter_input_depth, 0); + const int filters_per_group = output_depth / groups; + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + const int in_y_origin = (out_y * stride_height) - pad_height; + for (int out_x = 0; out_x < output_width; ++out_x) { + const int in_x_origin = (out_x * stride_width) - pad_width; + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + auto group = out_channel / filters_per_group; + float total = 0.f; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + const int in_y = in_y_origin + dilation_height_factor * filter_y; + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + + if (!is_point_inside_image) { + continue; + } + for (int in_channel = 0; in_channel < filter_input_depth; + ++in_channel) { + float input_value = + input_data[Offset(input_shape, batch, in_y, in_x, + in_channel + group * filter_input_depth)]; + float filter_value = filter_data[Offset( + filter_shape, out_channel, filter_y, filter_x, in_channel)]; + total += (input_value * filter_value); + } + } + } + float bias_value = 0.0f; + if (bias_data) { + bias_value = bias_data[out_channel]; + } + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + ActivationFunctionWithMinMax(total + bias_value, + output_activation_min, + output_activation_max); + } + } + } + } +} + +inline void Conv(const ConvParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& filter_shape, + const uint8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + uint8_t* output_data, const RuntimeShape& im2col_shape, + uint8_t* im2col_data, void* cpu_backend_context) { + (void)cpu_backend_context; // only used in optimized code. + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int filter_input_depth = filter_shape.Dims(3); + const int groups = input_depth / filter_input_depth; + TFLITE_DCHECK_EQ(input_depth % filter_input_depth, 0); + const int filters_per_group = output_depth / groups; + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + const int in_y_origin = (out_y * stride_height) - pad_height; + for (int out_x = 0; out_x < output_width; ++out_x) { + const int in_x_origin = (out_x * stride_width) - pad_width; + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + auto group = out_channel / filters_per_group; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + const int in_y = in_y_origin + dilation_height_factor * filter_y; + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + + if (!is_point_inside_image) { + continue; + } + + for (int in_channel = 0; in_channel < filter_input_depth; + ++in_channel) { + int32_t input_val = + input_data[Offset(input_shape, batch, in_y, in_x, + in_channel + group * filter_input_depth)]; + int32_t filter_val = filter_data[Offset( + filter_shape, out_channel, filter_y, filter_x, in_channel)]; + acc += + (filter_val + filter_offset) * (input_val + input_offset); + } + } + } + if (bias_data) { + acc += bias_data[out_channel]; + } + acc = MultiplyByQuantizedMultiplier(acc, output_multiplier, + output_shift); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + static_cast(acc); + } + } + } + } +} + +inline void HybridConvPerChannel( + const ConvParams& params, float* scaling_factors_ptr, + const RuntimeShape& input_shape, const int8_t* input_data, + const RuntimeShape& filter_shape, const int8_t* filter_data, + const RuntimeShape& bias_shape, const float* bias_data, + const RuntimeShape& output_shape, float* output_data, + const RuntimeShape& im2col_shape, int8_t* im2col_data, + const float* per_channel_scale, int32_t* input_offset) { + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int filter_input_depth = filter_shape.Dims(3); + const int groups = input_depth / filter_input_depth; + TFLITE_DCHECK_EQ(input_depth % filter_input_depth, 0); + const int filters_per_group = output_depth / groups; + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + auto group = out_channel / filters_per_group; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + for (int in_channel = 0; in_channel < filter_input_depth; + ++in_channel) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // If the location is outside the bounds of the input image, + // use zero as a default value. + if ((in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height)) { + int32_t input_val = input_data[Offset( + input_shape, batch, in_y, in_x, + in_channel + group * filter_input_depth)]; + int32_t filter_val = + filter_data[Offset(filter_shape, out_channel, filter_y, + filter_x, in_channel)]; + acc += filter_val * (input_val - input_offset[batch]); + } + } + } + } + float acc_float = + acc * per_channel_scale[out_channel] * scaling_factors_ptr[batch]; + if (bias_data) { + acc_float += bias_data[out_channel]; + } + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + ActivationFunctionWithMinMax(acc_float, output_activation_min, + output_activation_max); + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/cumsum.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/cumsum.h new file mode 100644 index 000000000..7cbc87c08 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/cumsum.h @@ -0,0 +1,175 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CUMSUM_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CUMSUM_H_ + +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" + +namespace tflite { +namespace reference_ops { + +template +inline void CumSum(const T* input_data, const RuntimeShape& shape, int32_t axis, + bool exclusive, bool reverse, T* output_data) { + const int32_t rank = shape.DimensionsCount(); + TFLITE_DCHECK_GE(rank, 1); + TFLITE_DCHECK_GE(axis, 0); + TFLITE_DCHECK_LT(axis, rank); + + size_t inner = 1; + size_t outer = 1; + size_t depth = 1; + for (int32_t i = 0; i < rank; i++) { + if (i < axis) + inner *= shape.Dims(i); + else if (i > axis) + outer *= shape.Dims(i); + else + depth = shape.Dims(i); + } + + for (size_t outer_index = 0; outer_index < outer; outer_index++) { + size_t outer_index_adj; + if (reverse) + outer_index_adj = (outer - 1) - outer_index; + else + outer_index_adj = outer_index; + for (size_t inner_index = 0; inner_index < inner; inner_index++) { + T accumulator = 0; + size_t inner_index_adj; + if (reverse) + inner_index_adj = (inner - 1) - inner_index; + else + inner_index_adj = inner_index; + for (size_t depth_index = 0; depth_index < depth; depth_index++) { + size_t depth_index_adj; + if (reverse) + depth_index_adj = (depth - 1) - depth_index; + else + depth_index_adj = depth_index; + + size_t index = outer_index_adj; + index += inner_index_adj * depth * outer; + index += depth_index_adj * outer; + + if (exclusive) { + output_data[index] = accumulator; + accumulator += input_data[index]; + } else { + accumulator += input_data[index]; + output_data[index] = accumulator; + } + } + } + } +} + +// +// Quantized INT8 CUMSUM +// +inline void CumSum(const ArithmeticParams& params, const int8_t* input_data, + const RuntimeShape& shape, int32_t axis, bool exclusive, + bool reverse, int8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + // Input offset is negative input zero point. Activation tensors are + // asymmetric quantized so they span the full int8 range. + // All inputs should have same zero-point and scale, this is checked during + // Prepare stage. + TFLITE_DCHECK_GE(-params.input1_offset, std::numeric_limits::min()); + TFLITE_DCHECK_LE(-params.input1_offset, std::numeric_limits::max()); + + const int32_t rank = shape.DimensionsCount(); + TFLITE_DCHECK_GE(rank, 1); + TFLITE_DCHECK_GE(axis, 0); + TFLITE_DCHECK_LT(axis, rank); + + size_t inner = 1; + size_t outer = 1; + size_t depth = 1; + for (int32_t i = 0; i < rank; i++) { + if (i < axis) + inner *= shape.Dims(i); + else if (i > axis) + outer *= shape.Dims(i); + else + depth = shape.Dims(i); + } + + for (size_t outer_index = 0; outer_index < outer; outer_index++) { + size_t outer_index_adj; + if (reverse) + outer_index_adj = (outer - 1) - outer_index; + else + outer_index_adj = outer_index; + for (size_t inner_index = 0; inner_index < inner; inner_index++) { + int32_t accumulator = params.input1_offset; // accumulator = 0 + accumulator *= (1 << params.left_shift); + accumulator = MultiplyByQuantizedMultiplierSmallerThanOneExp( + accumulator, params.input1_multiplier, params.input1_shift); + + size_t inner_index_adj; + if (reverse) + inner_index_adj = (inner - 1) - inner_index; + else + inner_index_adj = inner_index; + + for (size_t depth_index = 0; depth_index < depth; depth_index++) { + size_t depth_index_adj; + if (reverse) + depth_index_adj = (depth - 1) - depth_index; + else + depth_index_adj = depth_index; + + size_t index = outer_index_adj; + index += inner_index_adj * depth * outer; + index += depth_index_adj * outer; + + const int32_t y = params.input1_offset + input_data[index]; + const int32_t shifted_y = y * (1 << params.left_shift); + const int32_t scaled_y = MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_y, params.input1_multiplier, params.input1_shift); + + int32_t scaled_output; + if (exclusive) { + scaled_output = accumulator; + accumulator += scaled_y; + } else { + accumulator += scaled_y; + scaled_output = accumulator; + } + + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + scaled_output, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[index] = static_cast(clamped_output); + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CUMSUM_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depth_to_space.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depth_to_space.h new file mode 100644 index 000000000..23cff2853 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depth_to_space.h @@ -0,0 +1,79 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTH_TO_SPACE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTH_TO_SPACE_H_ + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +inline void DepthToSpace(const tflite::DepthToSpaceParams& op_params, + const RuntimeShape& unextended_input_shape, + const T* input_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + const int input_depth = input_shape.Dims(3); + const int input_width = input_shape.Dims(2); + const int input_height = input_shape.Dims(1); + const int input_batch = input_shape.Dims(0); + + const int output_depth = output_shape.Dims(3); + const int output_width = output_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_batch = output_shape.Dims(0); + + const int32_t block_size = op_params.block_size; + + TFLITE_DCHECK_EQ(input_width * block_size, output_width); + TFLITE_DCHECK_EQ(input_height * block_size, output_height); + TFLITE_DCHECK_EQ(input_depth, output_depth * block_size * block_size); + TFLITE_DCHECK_EQ(input_batch, output_batch); + + for (int out_b = 0; out_b < output_batch; ++out_b) { + for (int out_h = 0; out_h < output_height; ++out_h) { + for (int out_w = 0; out_w < output_width; ++out_w) { + for (int out_d = 0; out_d < output_depth; ++out_d) { + const int in_d = + out_d + ((out_h % block_size) * block_size + out_w % block_size) * + output_depth; + + const int in_w = out_w / block_size; + const int in_h = out_h / block_size; + const int in_b = out_b; + + const int input_index = Offset(input_shape, in_b, in_h, in_w, in_d); + const int output_index = + Offset(output_shape, out_b, out_h, out_w, out_d); + + output_data[output_index] = input_data[input_index]; + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTH_TO_SPACE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h new file mode 100644 index 000000000..0cecb16b4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h @@ -0,0 +1,100 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +inline void DepthwiseConv( + const DepthwiseParams& params, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& filter_shape, + const float* filter_data, const RuntimeShape& bias_shape, + const float* bias_data, const RuntimeShape& output_shape, + float* output_data) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int depth_multiplier = params.depth_multiplier; + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + + for (int b = 0; b < batches; ++b) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int ic = 0; ic < input_depth; ++ic) { + for (int m = 0; m < depth_multiplier; m++) { + const int oc = m + ic * depth_multiplier; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + float total = 0.f; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // If the location is outside the bounds of the input image, + // use zero as a default value. + if ((in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height)) { + float input_value = + input_data[Offset(input_shape, b, in_y, in_x, ic)]; + float filter_value = filter_data[Offset( + filter_shape, 0, filter_y, filter_x, oc)]; + total += (input_value * filter_value); + } + } + } + float bias_value = 0.0f; + if (bias_data) { + bias_value = bias_data[oc]; + } + output_data[Offset(output_shape, b, out_y, out_x, oc)] = + ActivationFunctionWithMinMax(total + bias_value, + output_activation_min, + output_activation_max); + } + } + } + } + } +} + +} // end namespace reference_ops +} // end namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_FLOAT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h new file mode 100644 index 000000000..bb51a39f0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h @@ -0,0 +1,319 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ + +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +// Used in tests and template parameters to control which version of depthwise +// convolution is called. Primarily for reference code, and specializations +// forced in tests. +enum class DepthwiseConvImplementation { + // Run all tests against kUseStandardEntry even if also testing another + // kernel, since we need to be sure that the main DepthwiseConv() function in + // optimized_ops.h dispatches to a correctly-executing kernel. + kNone = 0, // The "default" option: use the normal + // DepthwiseConv kernel (entry) function. + kUseGenericKernel, // Forced use of generic kernel. + kUseNeon3x3, // 3x3 kernel that uses NEON when available. + kUseNeon3x3DotProduct, // 3x3 kernel that uses dot-product enabled NEON + // when available. + kUseCModel3x3DotProduct, // 3x3 kernel, reference C model that is intended + // to match overall design NEON code. + kUseUnwound3x3DotProduct, // 3x3 kernel, reference C model with unwound loops + // and some arrays. + kUseIntrinsics3x3DotProduct, // 3x3 kernel using NEON intrinsics. +}; + +// Category of depthwise convolution output rounding. +enum class DepthwiseConvOutputRounding { + kNone = 0, // Invalid: specific method must be specified. + kAwayFromZero, // Original method: exact halves rounded away from zero. + kUpward, // Halves towards +infinity: adds 0.5 before truncate. + // This is where a future kNearestEven would be placed. +}; + +// Category of depthwise convolution depth multiplication. +enum class DepthwiseConvDepthMultiplication { + kNoMultiplication = 0, // Depth multiplier = 1. + kUnitInputDepth, // Input depth = 1, output depth = depth multiplier. +}; + +namespace reference_ops { +namespace depthwise_conv { + +template +inline int32_t DepthwiseConvRound(int32_t x, int32_t quantized_multiplier, + int shift) { + TFLITE_DCHECK_NE(output_rounding, DepthwiseConvOutputRounding::kNone); + return MultiplyByQuantizedMultiplier(x, quantized_multiplier, shift); +} + +// Single-rounding MultiplyByQuantizedMultiplier +#if TFLITE_SINGLE_ROUNDING +template <> +inline int32_t DepthwiseConvRound( + int32_t x, int32_t quantized_multiplier, int shift) { + using gemmlowp::RoundingDivideByPOT; + using gemmlowp::SaturatingRoundingDoublingHighMul; + int left_shift = shift > 0 ? shift : 0; + int right_shift = shift > 0 ? 0 : -shift; + return RoundingDivideByPOT(SaturatingRoundingDoublingHighMul( + x * (1 << left_shift), quantized_multiplier), + right_shift); +} + +template <> +inline int32_t DepthwiseConvRound( + int32_t x, int32_t quantized_multiplier, int shift) { + return MultiplyByQuantizedMultiplier(x, quantized_multiplier, shift); +} +// Double-rounding MultiplyByQuantizedMultiplier +#else +template <> +inline int32_t DepthwiseConvRound( + int32_t x, int32_t quantized_multiplier, int shift) { + return MultiplyByQuantizedMultiplier(x, quantized_multiplier, shift); +} + +template <> +inline int32_t DepthwiseConvRound( + int32_t x, int32_t quantized_multiplier, int shift) { + using gemmlowp::SaturatingRoundingDoublingHighMul; + const int left_shift = shift > 0 ? shift : 0; + const int right_shift = shift > 0 ? 0 : -shift; + const int rounding_offset = right_shift > 0 ? 1 << (right_shift - 1) : 0; + return (SaturatingRoundingDoublingHighMul(x * (1 << left_shift), + quantized_multiplier) + + rounding_offset) >> + right_shift; +} +#endif // TFLITE_SINGLE_ROUNDING + +template +struct DepthwiseConvBasicKernel { + static inline void Run( + const DepthwiseParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& filter_shape, + const uint8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + uint8_t* output_data) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int depth_multiplier = params.depth_multiplier; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + + for (int b = 0; b < batches; ++b) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int ic = 0; ic < input_depth; ++ic) { + for (int m = 0; m < depth_multiplier; m++) { + const int oc = m + ic * depth_multiplier; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = + in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // If the location is outside the bounds of the input image, + // use zero as a default value. + if ((in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height)) { + int32_t input_val = + input_data[Offset(input_shape, b, in_y, in_x, ic)]; + int32_t filter_val = filter_data[Offset( + filter_shape, 0, filter_y, filter_x, oc)]; + acc += (filter_val + filter_offset) * + (input_val + input_offset); + } + } + } + if (bias_data) { + acc += bias_data[oc]; + } + acc = DepthwiseConvRound(acc, output_multiplier, + output_shift); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[Offset(output_shape, b, out_y, out_x, oc)] = + static_cast(acc); + } + } + } + } + } + } + + // TODO(b/148596273): Reconcile reference versions, perhaps with common + // MultiplyByQuantizedMultiplier or DepthwiseConvRound function. + static inline void RunPerChannel( + const DepthwiseParams& params, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int8_t* output_data) { + // Get parameters. + // TODO(b/141565753): Re-introduce ScopedProfilingLabel on Micro. + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int depth_multiplier = params.depth_multiplier; + const int32_t input_offset = params.input_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + const int32_t* output_multiplier = params.output_multiplier_per_channel; + const int32_t* output_shift = params.output_shift_per_channel; + + // Check dimensions of the tensors. + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + for (int m = 0; m < depth_multiplier; ++m) { + const int output_channel = m + in_channel * depth_multiplier; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = + in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + if (is_point_inside_image) { + int32_t input_val = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + int32_t filter_val = filter_data[Offset( + filter_shape, 0, filter_y, filter_x, output_channel)]; + // Accumulate with 32 bits accumulator. + // In the nudging process during model quantization, we + // force real value of 0.0 be represented by a quantized + // value. This guarantees that the input_offset is a int8_t, + // even though it is represented using int32_t. int32_t += + // int8_t + // * (int8_t - int8_t) so the highest value we can get from + // each accumulation is [-127, 127] * ([-128, 127] - + // [-128, 127]), which is [-32512, 32512]. log2(32512) + // = 14.98, which means we can accumulate at least 2^16 + // multiplications without overflow. The accumulator is + // applied to a filter so the accumulation logic will hold + // as long as the filter size (filter_y * filter_x * + // in_channel) does not exceed 2^16, which is the case in + // all the models we have seen so far. + acc += filter_val * (input_val + input_offset); + } + } + } + if (bias_data) { + acc += bias_data[output_channel]; + } + acc = DepthwiseConvRound( + acc, output_multiplier[output_channel], + output_shift[output_channel]); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, + output_channel)] = static_cast(acc); + } + } + } + } + } + } +}; + +} // namespace depthwise_conv + +inline void DepthwiseConv( + const DepthwiseParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& filter_shape, + const uint8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + uint8_t* output_data) { + return depthwise_conv::DepthwiseConvBasicKernel< + DepthwiseConvOutputRounding::kAwayFromZero>::Run(params, input_shape, + input_data, filter_shape, + filter_data, bias_shape, + bias_data, output_shape, + output_data); +} + +} // namespace reference_ops +} // end namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEPTHWISECONV_UINT8_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/dequantize.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/dequantize.h new file mode 100644 index 000000000..b90951f96 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/dequantize.h @@ -0,0 +1,78 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEQUANTIZE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEQUANTIZE_H_ + +#include + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +// Dequantizes into a float without rounding. +template +inline void Dequantize(const tflite::DequantizationParams& op_params, + const RuntimeShape& input_shape, + const InputT* input_data, + const RuntimeShape& output_shape, OutputT* output_data) { + int32_t zero_point = op_params.zero_point; + const double scale = op_params.scale; + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + const int32_t val = input_data[i]; + const OutputT result = static_cast(scale * (val - zero_point)); + output_data[i] = result; + } +} + +// Dequantizes per-channel quantized tensor to float. +template +inline void PerChannelDequantize( + const tflite::PerChannelDequantizationParams& op_params, + const RuntimeShape& input_shape, const T* input_data, + const RuntimeShape& output_shape, float* output_data) { + // Ensure flat size is same. + MatchingFlatSize(input_shape, output_shape); + + const int32_t* zero_point = op_params.zero_point; + const float* scale = op_params.scale; + const int32_t quantized_dimension = op_params.quantized_dimension; + const int32_t num_dims = input_shape.DimensionsCount(); + const int32_t* dims_data = input_shape.DimsData(); + std::vector current_dim(num_dims, 0); + + do { + size_t offset = + ReducedOutputOffset(num_dims, reinterpret_cast(dims_data), + current_dim.data(), 0, nullptr); + const int channel = current_dim[quantized_dimension]; + const int32_t val = input_data[offset]; + const float result = + static_cast(scale[channel] * (val - zero_point[channel])); + output_data[offset] = result; + } while (NextIndex(num_dims, reinterpret_cast(dims_data), + current_dim.data())); +} + +} // namespace reference_ops + +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DEQUANTIZE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/div.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/div.h new file mode 100644 index 000000000..df8da1b1a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/div.h @@ -0,0 +1,247 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DIV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DIV_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { + +namespace reference_ops { + +template +inline void DivCheckArithmeticParams(const ArithmeticParams& params) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + // Input offset is negative input zero point. Activation tensors are + // asymmetric quantized so they span the full int8 range. + constexpr int32_t max_value = + static_cast(std::numeric_limits::max()); + TFLITE_DCHECK_GE(params.input1_offset, -max_value); + TFLITE_DCHECK_LE(params.input1_offset, max_value); + TFLITE_DCHECK_GE(params.input2_offset, -max_value); + TFLITE_DCHECK_LE(params.input2_offset, max_value); + TFLITE_DCHECK_GE(params.output_offset, -max_value); + TFLITE_DCHECK_LE(params.output_offset, max_value); +} + +// Element-wise div that can often be used for inner loop of broadcast Div as +// well as the non-broadcast Div. +template +inline void DivElementwise(int size, const ArithmeticParams& params, + const T* input1_data, const T* input2_data, + T* output_data) { + DivCheckArithmeticParams(params); + + for (int i = 0; i < size; ++i) { + int32_t input1_val = params.input1_offset + input1_data[i]; + int32_t input2_val = params.input2_offset + input2_data[i]; + TFLITE_DCHECK_NE(input2_val, 0); + if (input2_val < 0) { + // Invert signs to avoid a negative input2_val as input2_inv needs to be + // positive to be used as multiplier of MultiplyByQuantizedMultiplier. + input1_val = -input1_val; + input2_val = -input2_val; + } + int recip_shift; + const int32_t input2_inv = GetReciprocal(input2_val, 31, &recip_shift); + const int headroom = CountLeadingSignBits(input1_val); + const int32_t unscaled_quotient = + MultiplyByQuantizedMultiplierGreaterThanOne(input1_val, input2_inv, + headroom); + const int total_shift = params.output_shift - recip_shift - headroom; + const int32_t unclamped_result = + params.output_offset + + MultiplyByQuantizedMultiplierSmallerThanOneExp( + unscaled_quotient, params.output_multiplier, total_shift); + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, unclamped_result)); + output_data[i] = static_cast(clamped_output); + } +} + +inline void Div(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const uint8_t* input1_data, + const RuntimeShape& input2_shape, const uint8_t* input2_data, + const RuntimeShape& output_shape, uint8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + DivElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void Div(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const int8_t* input1_data, + const RuntimeShape& input2_shape, const int8_t* input2_data, + const RuntimeShape& output_shape, int8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + DivElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +template +inline void BroadcastDivSlowQuantized( + const ArithmeticParams& params, const RuntimeShape& unextended_input1_shape, + const T* input1_data, const RuntimeShape& unextended_input2_shape, + const T* input2_data, const RuntimeShape& unextended_output_shape, + T* output_data) { + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), N); + + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_output_shape), + &output_desc); + + DivCheckArithmeticParams(params); + + auto div_func = [&](int indexes[N]) { + int32_t input1_val = + params.input1_offset + input1_data[SubscriptToIndex(desc1, indexes)]; + int32_t input2_val = + params.input2_offset + input2_data[SubscriptToIndex(desc2, indexes)]; + TFLITE_DCHECK_NE(input2_val, 0); + if (input2_val < 0) { + // Invert signs to avoid a negative input2_val as input2_inv needs to be + // positive to be used as multiplier of MultiplyByQuantizedMultiplier. + input1_val = -input1_val; + input2_val = -input2_val; + } + int recip_shift; + const int32_t input2_inv = GetReciprocal(input2_val, 31, &recip_shift); + const int headroom = CountLeadingSignBits(input1_val); + const int32_t unscaled_quotient = + MultiplyByQuantizedMultiplierGreaterThanOne(input1_val, input2_inv, + headroom); + const int total_shift = params.output_shift - recip_shift - headroom; + const int32_t unclamped_result = + params.output_offset + + MultiplyByQuantizedMultiplierSmallerThanOneExp( + unscaled_quotient, params.output_multiplier, total_shift); + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, unclamped_result)); + output_data[SubscriptToIndex(output_desc, indexes)] = + static_cast(clamped_output); + }; + NDOpsHelper(output_desc, div_func); +} + +template +inline void BroadcastDivSlow(const ArithmeticParams& params, + const RuntimeShape& unextended_input1_shape, + const uint8_t* input1_data, + const RuntimeShape& unextended_input2_shape, + const uint8_t* input2_data, + const RuntimeShape& unextended_output_shape, + uint8_t* output_data) { + BroadcastDivSlowQuantized( + params, unextended_input1_shape, input1_data, unextended_input2_shape, + input2_data, unextended_output_shape, output_data); +} + +template +inline void BroadcastDivSlow(const ArithmeticParams& params, + const RuntimeShape& unextended_input1_shape, + const int8_t* input1_data, + const RuntimeShape& unextended_input2_shape, + const int8_t* input2_data, + const RuntimeShape& unextended_output_shape, + int8_t* output_data) { + BroadcastDivSlowQuantized( + params, unextended_input1_shape, input1_data, unextended_input2_shape, + input2_data, unextended_output_shape, output_data); +} + +// TODO(jiawen): We can implement BroadcastDiv on buffers of arbitrary +// dimensionality if the runtime code does a single loop over one dimension +// that handles broadcasting as the base case. The code generator would then +// generate max(D1, D2) nested for loops. +template +void BroadcastDivSlow(const ArithmeticParams& params, + const RuntimeShape& unextended_input1_shape, + const T* input1_data, + const RuntimeShape& unextended_input2_shape, + const T* input2_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + T output_activation_min; + T output_activation_max; + GetActivationParams(params, &output_activation_min, &output_activation_max); + + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), N); + + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_output_shape), + &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest + // stride, typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + + auto div_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, indexes)] / + input2_data[SubscriptToIndex(desc2, indexes)], + output_activation_min, output_activation_max); + }; + NDOpsHelper(output_desc, div_func); +} + +template +inline void Div(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + T output_activation_min; + T output_activation_max; + GetActivationParams(params, &output_activation_min, &output_activation_max); + + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = ActivationFunctionWithMinMax( + input1_data[i] / input2_data[i], output_activation_min, + output_activation_max); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_DIV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/elu.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/elu.h new file mode 100644 index 000000000..3dc935898 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/elu.h @@ -0,0 +1,37 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ELU_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ELU_H_ + +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void Elu(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const float val = input_data[i]; + output_data[i] = val < 0.0f ? TfLiteExpm1(val) : val; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ELU_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/exp.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/exp.h new file mode 100644 index 000000000..9b33bf15b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/exp.h @@ -0,0 +1,38 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_EXP_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_EXP_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +inline void Exp(const T* input_data, const size_t num_elements, + T* output_data) { + ruy::profiler::ScopeLabel label("Exp"); + for (size_t idx = 0; idx < num_elements; ++idx) { + output_data[idx] = std::exp(input_data[idx]); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_EXP_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/fill.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/fill.h new file mode 100644 index 000000000..16630e617 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/fill.h @@ -0,0 +1,38 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FILL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FILL_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +void Fill(const RuntimeShape& value_shape, const T* value_data, + const RuntimeShape& output_shape, T* output_data) { + TFLITE_DCHECK_EQ(value_shape.DimensionsCount(), 0); + const int flat_size = output_shape.FlatSize(); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = *value_data; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FILL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor.h new file mode 100644 index 000000000..0693fd429 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor.h @@ -0,0 +1,39 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void Floor(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + int offset = i; + output_data[offset] = std::floor(input_data[offset]); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor_div.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor_div.h new file mode 100644 index 000000000..e75d473cf --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor_div.h @@ -0,0 +1,35 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_DIV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_DIV_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +T FloorDiv(T input1, T input2) { + return std::floor(std::divides()(static_cast(input1), + static_cast(input2))); +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_DIV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor_mod.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor_mod.h new file mode 100644 index 000000000..20ce18b73 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/floor_mod.h @@ -0,0 +1,44 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_MOD_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_MOD_H_ + +#include +#include + +namespace tflite { + +namespace reference_ops { + +template +T FloorMod(T input1, T input2) { + struct FloatMod { + float operator()(const float lhs, const float rhs) const { + return std::fmod(lhs, rhs); + } + }; + using ModFunc = typename std::conditional::value, + std::modulus, FloatMod>::type; + ModFunc mod_func; + T trunc_mod = mod_func(input1, input2); + return (trunc_mod != 0) && ((input2 < 0) != (trunc_mod < 0)) + ? (trunc_mod + input2) + : trunc_mod; +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_MOD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/fully_connected.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/fully_connected.h new file mode 100644 index 000000000..cd67828d3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/fully_connected.h @@ -0,0 +1,323 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FULLY_CONNECTED_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FULLY_CONNECTED_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +inline void FullyConnected( + const FullyConnectedParams& params, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& weights_shape, + const float* weights_data, const RuntimeShape& bias_shape, + const float* bias_data, const RuntimeShape& output_shape, + float* output_data) { + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + // TODO(b/62193649): This really should be: + // const int batches = ArraySize(output_dims, 1); + // but the current --variable_batch hack consists in overwriting the 3rd + // dimension with the runtime batch size, as we don't keep track for each + // array of which dimension is the batch dimension in it. + const int output_dims_count = output_shape.DimensionsCount(); + const int weights_dims_count = weights_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dims_count - 1); + const int output_depth = MatchingDim(weights_shape, weights_dims_count - 2, + output_shape, output_dims_count - 1); + const int accum_depth = weights_shape.Dims(weights_dims_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + float total = 0.f; + for (int d = 0; d < accum_depth; ++d) { + total += input_data[b * accum_depth + d] * + weights_data[out_c * accum_depth + d]; + } + float bias_value = 0.0f; + if (bias_data) { + bias_value = bias_data[out_c]; + } + output_data[out_c + output_depth * b] = ActivationFunctionWithMinMax( + total + bias_value, output_activation_min, output_activation_max); + } + } +} + +inline void FullyConnected( + const FullyConnectedParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& filter_shape, + const uint8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + uint8_t* output_data) { + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_GE(filter_shape.DimensionsCount(), 2); + TFLITE_DCHECK_GE(output_shape.DimensionsCount(), 1); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + // TODO(b/62193649): This really should be: + // const int batches = ArraySize(output_dims, 1); + // but the current --variable_batch hack consists in overwriting the 3rd + // dimension with the runtime batch size, as we don't keep track for each + // array of which dimension is the batch dimension in it. + const int output_dim_count = output_shape.DimensionsCount(); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dim_count - 1); + const int output_depth = MatchingDim(filter_shape, filter_dim_count - 2, + output_shape, output_dim_count - 1); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + int32_t acc = 0; + for (int d = 0; d < accum_depth; ++d) { + int32_t input_val = input_data[b * accum_depth + d]; + int32_t filter_val = filter_data[out_c * accum_depth + d]; + acc += (filter_val + filter_offset) * (input_val + input_offset); + } + if (bias_data) { + acc += bias_data[out_c]; + } + acc = MultiplyByQuantizedMultiplier(acc, output_multiplier, output_shift); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[out_c + output_depth * b] = static_cast(acc); + } + } +} + +inline void FullyConnected( + const FullyConnectedParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& filter_shape, + const uint8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int16_t* output_data) { + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + TFLITE_DCHECK_EQ(output_offset, 0); + // TODO(b/62193649): This really should be: + // const int batches = ArraySize(output_dims, 1); + // but the current --variable_batch hack consists in overwriting the 3rd + // dimension with the runtime batch size, as we don't keep track for each + // array of which dimension is the batch dimension in it. + const int output_dim_count = output_shape.DimensionsCount(); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dim_count - 1); + const int output_depth = MatchingDim(filter_shape, filter_dim_count - 2, + output_shape, output_dim_count - 1); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + // Internal accumulation. + // Initialize accumulator with the bias-value. + int32_t accum = bias_data[out_c]; + // Accumulation loop. + for (int d = 0; d < accum_depth; ++d) { + int16_t input_val = input_data[b * accum_depth + d] + input_offset; + int16_t filter_val = + filter_data[out_c * accum_depth + d] + filter_offset; + accum += filter_val * input_val; + } + // Down-scale the final int32_t accumulator to the scale used by our + // (16-bit, typically 3 integer bits) fixed-point format. The quantized + // multiplier and shift here have been pre-computed offline + // (e.g. by toco). + accum = + MultiplyByQuantizedMultiplier(accum, output_multiplier, output_shift); + // Saturate, cast to int16_t, and store to output array. + accum = std::max(accum, output_activation_min - output_offset); + accum = std::min(accum, output_activation_max - output_offset); + accum += output_offset; + output_data[out_c + output_depth * b] = accum; + } + } +} + +inline void ShuffledFullyConnected( + const FullyConnectedParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& weights_shape, + const uint8_t* shuffled_weights_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int16_t* output_data, uint8_t* shuffled_input_workspace_data) { + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + + TFLITE_DCHECK_GE(input_shape.DimensionsCount(), 1); + TFLITE_DCHECK_GE(weights_shape.DimensionsCount(), 2); + TFLITE_DCHECK_GE(output_shape.DimensionsCount(), 1); + // TODO(b/62193649): This really should be: + // const int batches = ArraySize(output_dims, 1); + // but the current --variable_batch hack consists in overwriting the 3rd + // dimension with the runtime batch size, as we don't keep track for each + // array of which dimension is the batch dimension in it. + const int output_dim_count = output_shape.DimensionsCount(); + const int weights_dim_count = weights_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dim_count - 1); + const int output_depth = MatchingDim(weights_shape, weights_dim_count - 2, + output_shape, output_dim_count - 1); + const int accum_depth = weights_shape.Dims(weights_dim_count - 1); + TFLITE_DCHECK((accum_depth % 16) == 0); + TFLITE_DCHECK((output_depth % 4) == 0); + + // Shuffling and xoring of input activations into the workspace buffer + uint8_t* shuffled_input_workspace_ptr = shuffled_input_workspace_data; + if (batches == 1) { + for (int i = 0; i < accum_depth; i++) { + shuffled_input_workspace_data[i] = input_data[i] ^ 0x80; + } + } else if (batches == 4) { + for (int c = 0; c < accum_depth; c += 16) { + for (int b = 0; b < 4; b++) { + const uint8_t* src_data_ptr = input_data + b * accum_depth + c; + for (int j = 0; j < 16; j++) { + uint8_t src_val = *src_data_ptr++; + // Flip the sign bit, so that the kernel will only need to + // reinterpret these uint8_t values as int8_t, getting for free the + // subtraction of the zero_point value 128. + uint8_t dst_val = src_val ^ 0x80; + *shuffled_input_workspace_ptr++ = dst_val; + } + } + } + } else { + TFLITE_DCHECK(false); + return; + } + + // Actual computation + if (batches == 1) { + int16_t* output_ptr = output_data; + // Shuffled weights have had their sign bit (0x80) pre-flipped (xor'd) + // so that just reinterpreting them as int8_t values is equivalent to + // subtracting 128 from them, thus implementing for free the subtraction of + // the zero_point value 128. + const int8_t* shuffled_weights_ptr = + reinterpret_cast(shuffled_weights_data); + // Likewise, we preshuffled and pre-xored the input data above. + const int8_t* shuffled_input_data = + reinterpret_cast(shuffled_input_workspace_data); + for (int c = 0; c < output_depth; c += 4) { + // Internal accumulation. + // Initialize accumulator with the bias-value. + int32_t accum[4] = {0}; + // Accumulation loop. + for (int d = 0; d < accum_depth; d += 16) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 16; j++) { + int8_t input_val = shuffled_input_data[d + j]; + int8_t weights_val = *shuffled_weights_ptr++; + accum[i] += weights_val * input_val; + } + } + } + for (int i = 0; i < 4; i++) { + // Add bias value + int32_t acc = accum[i] + bias_data[c + i]; + // Down-scale the final int32_t accumulator to the scale used by our + // (16-bit, typically 3 integer bits) fixed-point format. The quantized + // multiplier and shift here have been pre-computed offline + // (e.g. by toco). + acc = + MultiplyByQuantizedMultiplier(acc, output_multiplier, output_shift); + // Saturate, cast to int16_t, and store to output array. + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_ptr[c + i] = acc; + } + } + } else if (batches == 4) { + int16_t* output_ptr = output_data; + // Shuffled weights have had their sign bit (0x80) pre-flipped (xor'd) + // so that just reinterpreting them as int8_t values is equivalent to + // subtracting 128 from them, thus implementing for free the subtraction of + // the zero_point value 128. + const int8_t* shuffled_weights_ptr = + reinterpret_cast(shuffled_weights_data); + // Likewise, we preshuffled and pre-xored the input data above. + const int8_t* shuffled_input_data = + reinterpret_cast(shuffled_input_workspace_data); + for (int c = 0; c < output_depth; c += 4) { + const int8_t* shuffled_input_ptr = shuffled_input_data; + // Accumulation loop. + // Internal accumulation. + // Initialize accumulator with the bias-value. + int32_t accum[4][4]; + for (int i = 0; i < 4; i++) { + for (int b = 0; b < 4; b++) { + accum[i][b] = 0; + } + } + for (int d = 0; d < accum_depth; d += 16) { + for (int i = 0; i < 4; i++) { + for (int b = 0; b < 4; b++) { + for (int j = 0; j < 16; j++) { + int8_t input_val = shuffled_input_ptr[16 * b + j]; + int8_t weights_val = shuffled_weights_ptr[16 * i + j]; + accum[i][b] += weights_val * input_val; + } + } + } + shuffled_input_ptr += 64; + shuffled_weights_ptr += 64; + } + for (int i = 0; i < 4; i++) { + for (int b = 0; b < 4; b++) { + // Add bias value + int32_t acc = accum[i][b] + bias_data[c + i]; + // Down-scale the final int32_t accumulator to the scale used by our + // (16-bit, typically 3 integer bits) fixed-point format. The + // quantized multiplier and shift here have been pre-computed offline + // (e.g. by toco). + acc = MultiplyByQuantizedMultiplier(acc, output_multiplier, + output_shift); + // Saturate, cast to int16_t, and store to output array. + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_ptr[b * output_depth + c + i] = acc; + } + } + } + } else { + TFLITE_DCHECK(false); + return; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FULLY_CONNECTED_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/hard_swish.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/hard_swish.h new file mode 100644 index 000000000..40504f9bb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/hard_swish.h @@ -0,0 +1,168 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_HARD_SWISH_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_HARD_SWISH_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +inline int16_t SaturatingLeftShift(int16_t value, int amount) { + int64_t result = static_cast(value) * (1 << amount); + result = std::min(result, std::numeric_limits::max()); + result = std::max(result, std::numeric_limits::min()); + return result; +} + +// Similar to ARM instruction SQDMULH. +// Similar to gemmlowp::SaturatingRoundingDoublingHighMul except +// rounding to zero instead of to nearest (SQRDMULH). +inline std::int16_t SaturatingDoublingHighMul(std::int16_t a, std::int16_t b) { + bool overflow = a == b && a == std::numeric_limits::min(); + std::int32_t a_32(a); + std::int32_t b_32(b); + std::int32_t ab_32 = a_32 * b_32; + std::int16_t ab_x2_high16 = static_cast((ab_32) / (1 << 15)); + return overflow ? std::numeric_limits::max() : ab_x2_high16; +} + +template +inline void HardSwish(const RuntimeShape& input_shape, const T* input_data, + const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("ReferenceHardSwish/Float"); + auto matching_size = MatchingFlatSize(input_shape, output_shape); + const T* in_end = input_data + matching_size; + for (; input_data < in_end; input_data++, output_data++) { + const float in = *input_data; + *output_data = + in * std::min(static_cast(6), std::max(static_cast(0), in + 3)) / + 6; + } +} + +template +inline void HardSwish(const HardSwishParams& params, + const RuntimeShape& input_shape, const T* input_data, + const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("ReferenceHardSwish/Quantized"); + + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + const int16_t input_value = input_data[i] - params.input_zero_point; + // Left-shift as much as we can without overflow/saturation to put + // significant bits in the high bits of our 16-bit fixedpoint values, so + // that fixed-point approximate computations below are as accurate as + // possible. + const int16_t input_value_on_hires_input_scale = input_value * (1 << 7); + // Compute the input value on essentially the output scale, just not + // right-shifted yet. This is the value that we'll use in the (x >= +3) + // case, and that in the general case we'll multiply against the "relu-ish" + // fixed-point multiplier in [0, 1]. + const int16_t input_value_on_preshift_output_scale = + gemmlowp::SaturatingRoundingDoublingHighMul( + input_value_on_hires_input_scale, + params.output_multiplier_fixedpoint_int16); + // Now compute the "relu-ish multiplier". In the (-3 <= x <= +3) case, that + // is just an affine rescaling of x from [-3, 3] to [0, 1]. In the general + // case, it is just that plus saturation at the boundaries of [-3, 3]. + // First, we rescale from [-3, 3] to [-1, 1], saturating. + // That is done by rescaling the input value with a fixed-point multiplier + // (reluish_multiplier_fixedpoint) and bit-shift such that we represent + // that input value on the scale where the real value 3.0f is represented + // by the quantized value 32768. (+32768 is actually not representable as + // int16_t, so this saturates at +32767, and that is seen empirically to be + // a negligible contribution to numerical error/bias). + // + // This code is careful to correctly implement any magnitude of multiplier, + // involving either a right shift or a left shift, with correct saturation + // behavior in the left-shift case. This forces this code to be more + // complicated, but is necessary for real applications: a partially + // trained quantized MobileNet v3-small model that motivated this code + // exhibits some large [min, max] range boundaries, of the order of + // magnitude of 10 or 100 depending on layers. + // + // The next few lines are basically just an ordinary + // MultiplyByQuantizedMultiplier, except that we are more careful here + // about the fine details of saturation when left-shifting, because here + // overflow in left-shift is a common case, not an anomaly as + // MultiplyByQuantizedMultiplier assumes. + int16_t reluish_value = input_value_on_hires_input_scale; + // Shift left, saturating, as much as we can while ensuring that this + // saturation will not contribute to the result. That is, left shift amount + // reduced by 1. + if (params.reluish_multiplier_exponent > 0) { + reluish_value = SaturatingLeftShift( + reluish_value, params.reluish_multiplier_exponent - 1); + } + // Apply the fixed-point multiplier, dividing the value by a divisor + // ranging in [1, 2]. + reluish_value = gemmlowp::SaturatingRoundingDoublingHighMul( + reluish_value, params.reluish_multiplier_fixedpoint_int16); + // Apply the last bit of left-shift. Thus, in the left-shifting case, if + // any saturation affects the result, it is happening here --- any + // saturation having occurred above is overwritten here, not affecting the + // result. + if (params.reluish_multiplier_exponent > 0) { + reluish_value = SaturatingLeftShift(reluish_value, 1); + } + // Shift right, in the right-shifting case. + if (params.reluish_multiplier_exponent < 0) { + reluish_value = gemmlowp::RoundingDivideByPOT( + reluish_value, -params.reluish_multiplier_exponent); + } + // At this point we have rescaled the value into a 16bit fixedpoint + // reluish_value in [-1, 1]. + // We now convert that to a 16bit fixedpoint value in [0, 1]. + reluish_value = (reluish_value + (1 << 15)) >> 1; + // Use of SaturatingDoublingHighMul here is important to cancel the biases + // from the above SaturatingRoundingDoublingHighMul. + // + // On a partially trained MobileNet-v3-small, + // + // | bias on | ImageNet + // | quantized | Top-1 + // Operation used here | values | accuracy (50k) + // --------------------------------------+------------+----------- + // SaturatingDoublingHighMul | -0.0024 | 58.920 + // SaturatingRoundingDoublingHighMul | -0.0067 | 58.064 + // + // In activations_test, this is covered by this testcase: + // QuantizedActivationsOpTest.HardSwishBias + // + const int16_t preshift_output_value = SaturatingDoublingHighMul( + reluish_value, input_value_on_preshift_output_scale); + // We were so far operating on the pre-shift output scale. Now we finally + // apply that output shift, arriving at the final output scale. + int16_t output_value = gemmlowp::RoundingDivideByPOT( + preshift_output_value, -params.output_multiplier_exponent); + output_value += params.output_zero_point; + output_value = + std::min(output_value, std::numeric_limits::max()); + output_value = + std::max(output_value, std::numeric_limits::min()); + output_data[i] = output_value; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_HARD_SWISH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/add.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/add.h new file mode 100644 index 000000000..8d9b318cc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/add.h @@ -0,0 +1,145 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_ADD_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_ADD_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_integer_ops { + +inline void CheckArithmeticParams(const ArithmeticParams& params) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + // Input offset is negative input zero point. Activation tensors are + // asymmetric quantized so they span the full int8 range. + TFLITE_DCHECK_GE(-params.input1_offset, std::numeric_limits::min()); + TFLITE_DCHECK_GE(-params.input2_offset, std::numeric_limits::min()); + TFLITE_DCHECK_LE(-params.input1_offset, std::numeric_limits::max()); + TFLITE_DCHECK_LE(-params.input2_offset, std::numeric_limits::max()); +} + +inline void ElementWise( + int size, const ArithmeticParams& params, const int8_t* input1_data, + const int8_t* input2_data, int8_t* output_data, + void (*check_arithmetic_params)(const ArithmeticParams&), + int8_t (*binary_func)(int8_t, int8_t, const ArithmeticParams&)) { + CheckArithmeticParams(params); + for (int i = 0; i < size; ++i) { + output_data[i] = binary_func(input1_data[i], input2_data[i], params); + } +} + +inline void BroadcastBinaryFunction4DSlow( + const ArithmeticParams& params, const RuntimeShape& input1_shape, + const int8_t* input1_data, const RuntimeShape& input2_shape, + const int8_t* input2_data, const RuntimeShape& output_shape, + int8_t* output_data, + void (*check_arithmetic_params)(const ArithmeticParams&), + int8_t (*binary_func)(int8_t, int8_t, const ArithmeticParams&)) { + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + output_data[Offset(extended_output_shape, b, y, x, c)] = binary_func( + input1_data[SubscriptToIndex(desc1, b, y, x, c)], + input2_data[SubscriptToIndex(desc2, b, y, x, c)], params); + } + } + } + } +} + +inline int8_t AddFunc(int8_t x, int8_t y, const ArithmeticParams& params) { + const int32_t input1_val = params.input1_offset + x; + const int32_t input2_val = params.input2_offset + y; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sum = scaled_input1_val + scaled_input2_val; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sum, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + return static_cast(clamped_output); +} + +// Element-wise add that can often be used for inner loop of broadcast add as +// well as the non-broadcast add. +inline void AddElementwise(int size, const ArithmeticParams& params, + const int8_t* input1_data, const int8_t* input2_data, + int8_t* output_data) { + ElementWise(size, params, input1_data, input2_data, output_data, + CheckArithmeticParams, AddFunc); +} + +inline void Add(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const int8_t* input1_data, + const RuntimeShape& input2_shape, const int8_t* input2_data, + const RuntimeShape& output_shape, int8_t* output_data) { + CheckArithmeticParams(params); + + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + AddElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void BroadcastAdd4DSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const int8_t* input1_data, + const RuntimeShape& input2_shape, + const int8_t* input2_data, + const RuntimeShape& output_shape, + int8_t* output_data) { + BroadcastBinaryFunction4DSlow(params, input1_shape, input1_data, input2_shape, + input2_data, output_shape, output_data, + CheckArithmeticParams, AddFunc); +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_ADD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/conv.h new file mode 100644 index 000000000..5ddf04aea --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/conv.h @@ -0,0 +1,254 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_CONV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_CONV_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" + +namespace tflite { +namespace reference_integer_ops { + +// Fixed-point per-channel-quantization convolution reference kernel. +inline void ConvPerChannel( + const ConvParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int8_t* output_data) { + // Get parameters. + const int32_t input_offset = params.input_offset; // r = s(q - Z) + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int32_t output_offset = params.output_offset; + + // Set min and max value of the output. + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + + // Consistency check. + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + + // Check dimensions of the tensors. + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int filter_input_depth = filter_shape.Dims(3); + const int groups = input_depth / filter_input_depth; + TFLITE_DCHECK_EQ(input_depth % filter_input_depth, 0); + const int filters_per_group = output_depth / groups; + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + const int in_y_origin = (out_y * stride_height) - pad_height; + for (int out_x = 0; out_x < output_width; ++out_x) { + const int in_x_origin = (out_x * stride_width) - pad_width; + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + auto group = out_channel / filters_per_group; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + const int in_y = in_y_origin + dilation_height_factor * filter_y; + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + + if (!is_point_inside_image) { + continue; + } + + for (int in_channel = 0; in_channel < filter_input_depth; + ++in_channel) { + int32_t input_val = + input_data[Offset(input_shape, batch, in_y, in_x, + in_channel + group * filter_input_depth)]; + int32_t filter_val = filter_data[Offset( + filter_shape, out_channel, filter_y, filter_x, in_channel)]; + // Accumulate with 32 bits accumulator. + // In the nudging process during model quantization, we force + // real value of 0.0 be represented by a quantized value. This + // guarantees that the input_offset is a int8_t, even though + // it is represented using int32_t. int32_t += int8_t * + // (int8_t - int8_t) so the highest value we can get from each + // accumulation is [-127, 127] * ([-128, 127] - + // [-128, 127]), which is [-32512, 32512]. log2(32512) + // = 14.98, which means we can accumulate at least 2^16 + // multiplications without overflow. The accumulator is + // applied to a filter so the accumulation logic will hold as + // long as the filter size (filter_y * filter_x * in_channel) + // does not exceed 2^16, which is the case in all the models + // we have seen so far. + // TODO(b/174275578): Add a check to make sure the + // accumulator depth is smaller than 2^16. + acc += filter_val * (input_val + input_offset); + } + } + } + + if (bias_data) { + acc += bias_data[out_channel]; + } + acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier[out_channel], output_shift[out_channel]); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + static_cast(acc); + } + } + } + } +} + +inline void ConvPerChannelWithPackedInt4Weights( + const ConvParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_input, int8_t* unpacked_filter_data, + const RuntimeShape& bias_shape, const int32_t* bias_data, + const RuntimeShape& output_shape, int8_t* output_data) { + TFLITE_DCHECK(unpacked_filter_data != nullptr); + tflite::tensor_utils::UnpackDenseInt4IntoInt8( + filter_input, filter_shape.FlatSize(), unpacked_filter_data); + ConvPerChannel(params, output_multiplier, output_shift, input_shape, + input_data, filter_shape, unpacked_filter_data, bias_shape, + bias_data, output_shape, output_data); +} + +// Fixed-point per-channel-quantization convolution reference kernel. +// 16-bit data and 8-bit filter +template +inline void ConvPerChannel( + const ConvParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const AccumScalar* bias_data, const RuntimeShape& output_shape, + int16_t* output_data) { + // Get parameters. + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + + // Set min and max value of the output. + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + + // Consistency check. + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + + // Check dimensions of the tensors. + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int filter_input_depth = filter_shape.Dims(3); + const int groups = input_depth / filter_input_depth; + TFLITE_DCHECK_EQ(input_depth % filter_input_depth, 0); + const int filters_per_group = output_depth / groups; + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + const int in_y_origin = (out_y * stride_height) - pad_height; + for (int out_x = 0; out_x < output_width; ++out_x) { + const int in_x_origin = (out_x * stride_width) - pad_width; + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + auto group = out_channel / filters_per_group; + AccumScalar acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + const int in_y = in_y_origin + dilation_height_factor * filter_y; + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + + if (!is_point_inside_image) { + continue; + } + + for (int in_channel = 0; in_channel < filter_input_depth; + ++in_channel) { + int32_t input_val = + input_data[Offset(input_shape, batch, in_y, in_x, + in_channel + group * filter_input_depth)]; + int32_t filter_val = filter_data[Offset( + filter_shape, out_channel, filter_y, filter_x, in_channel)]; + // Accumulate with 64 bits accumulator. + // int64_t += int8_t * int16_t so the highest value we can + // get from each accumulation is [-127, 127] * ([-32768, + // 32767] - + // [-32768, 32767]), which is [-8322945, 8322945]. + // log2(8322945) = 22.99. + acc += filter_val * input_val; + } + } + } + if (bias_data) { + acc += bias_data[out_channel]; + } + int32_t scaled_acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier[out_channel], output_shift[out_channel]); + scaled_acc = std::max(scaled_acc, output_activation_min); + scaled_acc = std::min(scaled_acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + static_cast(scaled_acc); + } + } + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/depthwise_conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/depthwise_conv.h new file mode 100644 index 000000000..7676fce0f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/depthwise_conv.h @@ -0,0 +1,291 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_DEPTHWISE_CONV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_DEPTHWISE_CONV_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { +inline void DepthwiseConvPerChannel( + const DepthwiseParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int8_t* output_data) { + // Get parameters. + // TODO(b/141565753): Re-introduce ScopedProfilingLabel on Micro. + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int depth_multiplier = params.depth_multiplier; + const int32_t input_offset = params.input_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + + // Check dimensions of the tensors. + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + for (int m = 0; m < depth_multiplier; ++m) { + const int output_channel = m + in_channel * depth_multiplier; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + if (is_point_inside_image) { + int32_t input_val = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + int32_t filter_val = filter_data[Offset( + filter_shape, 0, filter_y, filter_x, output_channel)]; + // Accumulate with 32 bits accumulator. + // In the nudging process during model quantization, we force + // real value of 0.0 be represented by a quantized value. This + // guarantees that the input_offset is a int8_t, even though + // it is represented using int32_t. int32_t += int8_t * + // (int8_t - int8_t) so the highest value we can get from each + // accumulation is [-127, 127] * ([-128, 127] - + // [-128, 127]), which is [-32512, 32512]. log2(32512) + // = 14.98, which means we can accumulate at least 2^16 + // multiplications without overflow. The accumulator is + // applied to a filter so the accumulation logic will hold as + // long as the filter size (filter_y * filter_x * in_channel) + // does not exceed 2^16, which is the case in all the models + // we have seen so far. + // TODO(b/174275578): Add a check to make sure the + // accumulator depth is smaller than 2^16. + acc += filter_val * (input_val + input_offset); + } + } + } + if (bias_data) { + acc += bias_data[output_channel]; + } + acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier[output_channel], + output_shift[output_channel]); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, + output_channel)] = static_cast(acc); + } + } + } + } + } +} + +inline void DepthwiseConvPerChannel( + const DepthwiseParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const std::int64_t* bias_data, const RuntimeShape& output_shape, + int16_t* output_data) { + // Get parameters. + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int depth_multiplier = params.depth_multiplier; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + + // Check dimensions of the tensors. + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + for (int m = 0; m < depth_multiplier; ++m) { + const int output_channel = m + in_channel * depth_multiplier; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + std::int64_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + if (is_point_inside_image) { + int32_t input_val = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + int32_t filter_val = filter_data[Offset( + filter_shape, 0, filter_y, filter_x, output_channel)]; + // Accumulate with 64 bits accumulator. + // We assume maximum of 2^16 accumulations as with the 8-bit + // case so actually the value in the accumulator should not + // exceed 40 bits + acc += static_cast(filter_val) * + static_cast(input_val); + } + } + } + if (bias_data) { + acc += bias_data[output_channel]; + } + int32_t scaled_acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier[output_channel], + output_shift[output_channel]); + scaled_acc = std::max(scaled_acc, output_activation_min); + scaled_acc = std::min(scaled_acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, + output_channel)] = + static_cast(scaled_acc); + } + } + } + } + } +} + +inline void DepthwiseConvHybridPerChannel( + const DepthwiseParams& params, float* scaling_factors_ptr, + const RuntimeShape& input_shape, const int8_t* input_data, + const RuntimeShape& filter_shape, const int8_t* filter_data, + const RuntimeShape& bias_shape, const float* bias_data, + const RuntimeShape& output_shape, float* output_data, + const float* per_channel_scale, int32_t* input_offset) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + const int depth_multiplier = params.depth_multiplier; + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + // Check dimensions of the tensors. + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int bias_depth = bias_shape.FlatSize(); + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + TFLITE_DCHECK_EQ(bias_depth, output_depth); + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + for (int m = 0; m < depth_multiplier; ++m) { + const int output_channel = m + in_channel * depth_multiplier; + const int in_x_origin = (out_x * stride_width) - pad_width; + const int in_y_origin = (out_y * stride_height) - pad_height; + int32_t acc = 0; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + const int in_x = in_x_origin + dilation_width_factor * filter_x; + const int in_y = + in_y_origin + dilation_height_factor * filter_y; + // Zero padding by omitting the areas outside the image. + const bool is_point_inside_image = + (in_x >= 0) && (in_x < input_width) && (in_y >= 0) && + (in_y < input_height); + if (is_point_inside_image) { + int32_t input_val = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + int32_t filter_val = filter_data[Offset( + filter_shape, 0, filter_y, filter_x, output_channel)]; + acc += filter_val * (input_val - input_offset[batch]); + } + } + } + float acc_float = static_cast(acc); + acc_float *= + per_channel_scale[output_channel] * scaling_factors_ptr[batch]; + if (bias_data && output_channel < bias_depth) { + acc_float += bias_data[output_channel]; + } + output_data[Offset(output_shape, batch, out_y, out_x, + output_channel)] = + ActivationFunctionWithMinMax(acc_float, output_activation_min, + output_activation_max); + } + } + } + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_DEPTHWISE_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/fully_connected.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/fully_connected.h new file mode 100644 index 000000000..634f0bffa --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/fully_connected.h @@ -0,0 +1,201 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_FULLY_CONNECTED_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_FULLY_CONNECTED_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +// For per-channel functions, since it is defined in quantization spec that +// weights are symmetric +// (https://www.tensorflow.org/lite/performance/quantization_spec#symmetric_vs_asymmetric), +// zero_point (params.weights_offset) is always 0. +// However, for per-tensor functions, params.weights_offset is still applied for +// backward compatibility. + +inline void FullyConnectedPerChannel( + const FullyConnectedParams& params, const int32_t* output_multiplier, + const int* output_shift, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int8_t* output_data) { + const int32_t input_offset = params.input_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_GE(filter_shape.DimensionsCount(), 2); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 2); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int batches = output_shape.Dims(0); + const int output_depth = output_shape.Dims(1); + TFLITE_DCHECK_LE(output_depth, filter_shape.Dims(filter_dim_count - 2)); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + int32_t acc = 0; + for (int d = 0; d < accum_depth; ++d) { + int32_t input_val = input_data[b * accum_depth + d]; + int32_t filter_val = filter_data[out_c * accum_depth + d]; + acc += filter_val * (input_val + input_offset); + } + if (bias_data) { + acc += bias_data[out_c]; + } + acc = MultiplyByQuantizedMultiplier(acc, output_multiplier[out_c], + output_shift[out_c]); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[out_c + output_depth * b] = static_cast(acc); + } + } +} + +template +inline void FullyConnectedPerChannel( + const FullyConnectedParams& params, const int32_t* output_multiplier, + const int* output_shift, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const AccumScalar* bias_data, const RuntimeShape& output_shape, + int16_t* output_data) { + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_GE(filter_shape.DimensionsCount(), 2); + TFLITE_DCHECK_GE(output_shape.DimensionsCount(), 1); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int output_dim_count = output_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dim_count - 1); + const int output_depth = output_shape.Dims(output_dim_count - 1); + TFLITE_DCHECK_LE(output_depth, filter_shape.Dims(filter_dim_count - 2)); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + AccumScalar acc = 0; + for (int d = 0; d < accum_depth; ++d) { + int32_t input_val = input_data[b * accum_depth + d]; + int32_t filter_val = filter_data[out_c * accum_depth + d]; + acc += filter_val * input_val; + } + if (bias_data) { + acc += bias_data[out_c]; + } + int32_t acc_scaled = MultiplyByQuantizedMultiplier( + acc, output_multiplier[out_c], output_shift[out_c]); + acc_scaled = std::max(acc_scaled, output_activation_min); + acc_scaled = std::min(acc_scaled, output_activation_max); + output_data[out_c + output_depth * b] = static_cast(acc_scaled); + } + } +} + +inline void FullyConnected( + const FullyConnectedParams& params, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int8_t* output_data) { + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_GE(filter_shape.DimensionsCount(), 2); + TFLITE_DCHECK_GE(output_shape.DimensionsCount(), 1); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int output_dim_count = output_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dim_count - 1); + const int output_depth = output_shape.Dims(output_dim_count - 1); + TFLITE_DCHECK_LE(output_depth, filter_shape.Dims(filter_dim_count - 2)); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + int32_t acc = 0; + for (int d = 0; d < accum_depth; ++d) { + int32_t input_val = input_data[b * accum_depth + d]; + int32_t filter_val = filter_data[out_c * accum_depth + d]; + acc += (filter_val + filter_offset) * (input_val + input_offset); + } + if (bias_data) { + acc += bias_data[out_c]; + } + acc = MultiplyByQuantizedMultiplier(acc, output_multiplier, output_shift); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[out_c + output_depth * b] = static_cast(acc); + } + } +} + +template +inline void FullyConnected( + const FullyConnectedParams& params, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const AccumScalar* bias_data, const RuntimeShape& output_shape, + int16_t* output_data) { + const int32_t filter_offset = params.weights_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_GE(filter_shape.DimensionsCount(), 2); + TFLITE_DCHECK_GE(output_shape.DimensionsCount(), 1); + + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int output_dim_count = output_shape.DimensionsCount(); + const int batches = FlatSizeSkipDim(output_shape, output_dim_count - 1); + const int output_depth = output_shape.Dims(output_dim_count - 1); + TFLITE_DCHECK_LE(output_depth, filter_shape.Dims(filter_dim_count - 2)); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) { + for (int out_c = 0; out_c < output_depth; ++out_c) { + AccumScalar acc = 0; + for (int d = 0; d < accum_depth; ++d) { + int32_t input_val = input_data[b * accum_depth + d]; + int32_t filter_val = filter_data[out_c * accum_depth + d]; + acc += (filter_val + filter_offset) * input_val; + } + if (bias_data) { + acc += bias_data[out_c]; + } + int32_t acc_scaled = + MultiplyByQuantizedMultiplier(acc, output_multiplier, output_shift); + acc_scaled = std::max(acc_scaled, output_activation_min); + acc_scaled = std::min(acc_scaled, output_activation_max); + output_data[out_c + output_depth * b] = static_cast(acc_scaled); + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_FULLY_CONNECTED_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h new file mode 100644 index 000000000..164a83670 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h @@ -0,0 +1,67 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_L2NORMALIZATION_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_L2NORMALIZATION_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +inline void L2Normalization(int32_t input_zero_point, int32_t outer_size, + int32_t depth, const int8_t* input_data, + int8_t* output_data) { + static constexpr int8_t kMinInt8 = std::numeric_limits::min(); + static constexpr int8_t kMaxInt8 = std::numeric_limits::max(); + // The output scale must be in sync with Prepare(). + // Output is in 1/128 scale so the actual output range is nudged from [-1, 1] + // to [-1, 127/128]. + static constexpr int32_t kOutputScale = 7; + for (int outer_index = 0; outer_index < outer_size; ++outer_index) { + // int32_t = (int8_t - int8_t) ^ 2. + // ([-128, 127] - [-128, 127]) ^ 2 = [0, (2^8 - 1)^2] so the accumulator is + // safe from overflowing in at least 2^16 steps. + int32_t acc = 0; + for (int inner_index = 0; inner_index < depth; ++inner_index) { + int32_t input = + input_data[depth * outer_index + inner_index] - input_zero_point; + acc += input * input; + } + int32_t inv_l2norm_multiplier; + int inv_l2norm_shift; + GetInvSqrtQuantizedMultiplierExp(acc, kReverseShift, &inv_l2norm_multiplier, + &inv_l2norm_shift); + + for (int inner_index = 0; inner_index < depth; ++inner_index) { + int32_t input = + input_data[depth * outer_index + inner_index] - input_zero_point; + + // Rescale and downcast. Rescale is folded into the division. + int32_t output_in_q24 = MultiplyByQuantizedMultiplier( + input, inv_l2norm_multiplier, inv_l2norm_shift + kOutputScale); + output_in_q24 = + std::min(static_cast(kMaxInt8), + std::max(static_cast(kMinInt8), output_in_q24)); + output_data[depth * outer_index + inner_index] = + static_cast(output_in_q24); + } + } +} +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_L2NORMALIZATION_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h new file mode 100644 index 000000000..16eff133d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h @@ -0,0 +1,121 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_LOGISTIC_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_LOGISTIC_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +inline void Logistic(int32_t input_zero_point, int32_t input_range_radius, + int32_t input_multiplier, int32_t input_left_shift, + int32_t input_size, const int8_t* input_data, + int8_t* output_data) { + // Integer bits must be in sync with Prepare() function. + static constexpr int32_t kInputIntegerBits = 4; + static constexpr int32_t kOutputIntegerBits = 8; + static constexpr int8_t kMinInt8 = std::numeric_limits::min(); + static constexpr int8_t kMaxInt8 = std::numeric_limits::max(); + static constexpr int32_t kOutputZeroPoint = -128; + + for (int i = 0; i < input_size; ++i) { + const int32_t input = + static_cast(input_data[i]) - input_zero_point; + if (input <= -input_range_radius) { + output_data[i] = kMinInt8; + } else if (input >= input_range_radius) { + output_data[i] = kMaxInt8; + } else { + const int32_t input_in_q4 = MultiplyByQuantizedMultiplier( + input, input_multiplier, input_left_shift); + using FixedPoint4 = gemmlowp::FixedPoint; + const int32_t output_in_q0 = + gemmlowp::logistic(FixedPoint4::FromRaw(input_in_q4)).raw(); + + // Rescale and downcast. + using gemmlowp::RoundingDivideByPOT; + int32_t output_in_q23 = + RoundingDivideByPOT(output_in_q0, 31 - kOutputIntegerBits); + output_in_q23 = std::min(std::max(output_in_q23 + kOutputZeroPoint, + static_cast(kMinInt8)), + static_cast(kMaxInt8)); + output_data[i] = static_cast(output_in_q23); + } + } +} + +inline void Logistic(int32_t input_multiplier, int32_t input_left_shift, + int32_t input_size, const int16_t* ptr_input_data, + int16_t* ptr_output_data) { + // We use the LUT for sigmoid and take into account, that + // tanh(x) = 2*sigmoid(2*x) - 1 + + // We scale by 3/4 to expand range [-8,8]->[-10.7,10.7]. + // In case of general parameter scale, multiplier 3 is taken into account + // in TanhPrepare function and it is included in + // input_multiplier already. + + TFLITE_DCHECK_GE(input_left_shift, 0); + if (input_multiplier == 0) { // power of two case + input_multiplier = 3 << input_left_shift; + input_left_shift = 0; + } + + int32_t round = (input_left_shift > 0) ? 1 << (input_left_shift - 1) : 0; + + for (int i = 0; i < input_size; ++i, ptr_input_data++, ptr_output_data++) { + int32_t input_data = + ((*ptr_input_data) * input_multiplier + round) >> input_left_shift; + + // We do interpolation on unsigned values. + uint32_t abs_input_data = abs(input_data); + + // We divide by 2 power of 9, because + // we need to divide by 2 in power of 7 for + // the input conversion + 1/4 from the scale above. + + // Define uh as uint32_t type not to make this function overflow. + uint32_t uh = abs_input_data >> 9; + uint32_t result; + + if (uh >= 255) { + // Saturate to maximum. + result = 0x7FFF << 10; + } else { + uint32_t ua = sigmoid_table_uint16[uh]; + uint32_t ub = sigmoid_table_uint16[uh + 1]; + uint32_t ut = abs_input_data & 0x1ff; + // Interpolation is done using the fractional bit. + result = (ua << 9) + ut * (ub - ua); + } + + result = (input_data >= 0) ? (result + (1 << 9)) + : ((1 << (16 + 9)) - result + (1 << 9) - 1); + + // Back to 16-bit. + result >>= 10; + + *ptr_output_data = result; + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_LOGISTIC_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/mean.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/mean.h new file mode 100644 index 000000000..09d37b726 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/mean.h @@ -0,0 +1,79 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_MEAN_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_MEAN_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +template +inline void Mean(const tflite::MeanParams& op_params, int32_t multiplier, + int32_t shift, const RuntimeShape& unextended_input_shape, + const integer_type* input_data, int32_t input_zero_point, + const RuntimeShape& unextended_output_shape, + integer_type* output_data, int32_t output_zero_point) { + // Current implementation only supports dimension equals 4 and simultaneous + // reduction over width and height. + TFLITE_CHECK_EQ(unextended_input_shape.DimensionsCount(), 4); + TFLITE_CHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + const int output_batch = output_shape.Dims(0); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int output_depth = output_shape.Dims(3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int num_elements_in_axis = input_width * input_height; + + TFLITE_CHECK_EQ(op_params.axis_count, 2); + TFLITE_CHECK((op_params.axis[0] == 1 && op_params.axis[1] == 2) || + (op_params.axis[0] == 2 && op_params.axis[1] == 1)); + TFLITE_CHECK_EQ(output_height, 1); + TFLITE_CHECK_EQ(output_width, 1); + + static constexpr int32_t kMinInt = std::numeric_limits::min(); + static constexpr int32_t kMaxInt = std::numeric_limits::max(); + + for (int out_b = 0; out_b < output_batch; ++out_b) { + for (int out_d = 0; out_d < output_depth; ++out_d) { + int32_t acc = 0; + for (int in_h = 0; in_h < input_height; ++in_h) { + for (int in_w = 0; in_w < input_width; ++in_w) { + acc += input_data[Offset(input_shape, out_b, in_h, in_w, out_d)] - + input_zero_point; + } + } + acc = MultiplyByQuantizedMultiplier(acc, multiplier, shift); + acc = acc > 0 ? (acc + num_elements_in_axis / 2) / num_elements_in_axis + : (acc - num_elements_in_axis / 2) / num_elements_in_axis; + acc += output_zero_point; + acc = std::min(std::max(acc, kMinInt), kMaxInt); + output_data[Offset(output_shape, out_b, 0, 0, out_d)] = + static_cast(acc); + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_MEAN_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/mul.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/mul.h new file mode 100644 index 000000000..778772888 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/mul.h @@ -0,0 +1,133 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_MUL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_MUL_H_ + +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +template +inline void MulElementwise(int size, const ArithmeticParams& params, + const T* input1_data, const T* input2_data, + T* output_data) { + for (int i = 0; i < size; ++i) { + const int32_t input1_val = params.input1_offset + input1_data[i]; + const int32_t input2_val = params.input2_offset + input2_data[i]; + const int32_t unclamped_result = + params.output_offset + + MultiplyByQuantizedMultiplier(input1_val * input2_val, + params.output_multiplier, + params.output_shift); + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, unclamped_result)); + output_data[i] = static_cast(clamped_output); + } +} + +template +inline void Mul(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + ruy::profiler::ScopeLabel label("Mul/8bit"); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + MulElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +// Mul with 16 bit inputs and int8_t outputs. +inline void Mul(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const int16_t* input1_data, + const RuntimeShape& input2_shape, const int16_t* input2_data, + const RuntimeShape& output_shape, int8_t* output_data) { + ruy::profiler::ScopeLabel label("Mul/Int16Int8"); + int32_t output_offset = params.output_offset; + int32_t output_activation_min = params.quantized_activation_min; + int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + // F0 uses 0 integer bits, range [-1, 1]. + using F0 = gemmlowp::FixedPoint; + + F0 unclamped_result = + F0::FromRaw(input1_data[i]) * F0::FromRaw(input2_data[i]); + int16_t rescaled_result = + gemmlowp::RoundingDivideByPOT(unclamped_result.raw(), 8); + int16_t clamped_result = std::min( + output_activation_max - output_offset, rescaled_result); + clamped_result = std::max(output_activation_min - output_offset, + clamped_result); + output_data[i] = output_offset + clamped_result; + } +} + +template +inline void BroadcastMul4DSlow( + const ArithmeticParams& params, const RuntimeShape& input1_shape, + const T* input1_data, const RuntimeShape& input2_shape, + const T* input2_data, const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("BroadcastMul4DSlow"); + + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + // The input shapes are extended as part of NdArrayDesc initialization. + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + const int32_t input1_val = + params.input1_offset + + input1_data[SubscriptToIndex(desc1, b, y, x, c)]; + const int32_t input2_val = + params.input2_offset + + input2_data[SubscriptToIndex(desc2, b, y, x, c)]; + const int32_t unclamped_result = + params.output_offset + + MultiplyByQuantizedMultiplier(input1_val * input2_val, + params.output_multiplier, + params.output_shift); + const int32_t clamped_output = std::min( + params.quantized_activation_max, + std::max(params.quantized_activation_min, unclamped_result)); + output_data[Offset(extended_output_shape, b, y, x, c)] = + static_cast(clamped_output); + } + } + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_MUL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h new file mode 100644 index 000000000..4dc31d9ed --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h @@ -0,0 +1,264 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +inline bool AveragePool(const PoolParams& params, + const RuntimeShape& input_shape, + const int8_t* input_data, + const RuntimeShape& output_shape, int8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + int32_t acc = 0; + int filter_count = 0; + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + acc += + input_data[Offset(input_shape, batch, in_y, in_x, channel)]; + filter_count++; + } + } + if (filter_count == 0) return false; + // Round to the closest integer value. + acc = acc > 0 ? (acc + filter_count / 2) / filter_count + : (acc - filter_count / 2) / filter_count; + acc = std::max(acc, params.quantized_activation_min); + acc = std::min(acc, params.quantized_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + static_cast(acc); + } + } + } + } + return true; +} + +inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& output_shape, + int8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + TFLITE_DCHECK_GE(params.quantized_activation_min, + std::numeric_limits::min()); + TFLITE_DCHECK_LE(params.quantized_activation_max, + std::numeric_limits::max()); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + int8_t max = std::numeric_limits::lowest(); + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + max = std::max( + max, + input_data[Offset(input_shape, batch, in_y, in_x, channel)]); + } + } + max = std::max(max, params.quantized_activation_min); + max = std::min(max, params.quantized_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + static_cast(max); + } + } + } + } +} + +inline bool AveragePool(const PoolParams& params, + const RuntimeShape& input_shape, + const int16_t* input_data, + const RuntimeShape& output_shape, + int16_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + int32_t acc = 0; + int filter_count = 0; + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + acc += + input_data[Offset(input_shape, batch, in_y, in_x, channel)]; + filter_count++; + } + } + if (filter_count == 0) return false; + // Round to the closest integer value. + acc = acc > 0 ? (acc + filter_count / 2) / filter_count + : (acc - filter_count / 2) / filter_count; + acc = std::max(acc, params.quantized_activation_min); + acc = std::min(acc, params.quantized_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + static_cast(acc); + } + } + } + } + return true; +} + +inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& output_shape, + int16_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + TFLITE_DCHECK_GE(params.quantized_activation_min, + std::numeric_limits::min()); + TFLITE_DCHECK_LE(params.quantized_activation_max, + std::numeric_limits::max()); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + int16_t max = std::numeric_limits::lowest(); + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + max = std::max( + max, + input_data[Offset(input_shape, batch, in_y, in_x, channel)]); + } + } + max = std::max(max, params.quantized_activation_min); + max = std::min(max, params.quantized_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + static_cast(max); + } + } + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/tanh.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/tanh.h new file mode 100644 index 000000000..93b0bb87e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/tanh.h @@ -0,0 +1,117 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_TANH_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_TANH_H_ + +#include +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +inline void Tanh(int32_t input_zero_point, int32_t input_range_radius, + int32_t input_multiplier, int32_t input_shift, + const RuntimeShape& input_shape, const int8_t* input_data, + const RuntimeShape& output_shape, int8_t* output_data) { + // Integer bits must be in sync with Prepare() function. + static constexpr int32_t kInputIntegerBits = 4; + static constexpr int32_t kOutputScale = 7; + static constexpr int32_t kMinInt8 = std::numeric_limits::min(); + static constexpr int32_t kMaxInt8 = std::numeric_limits::max(); + using F4 = gemmlowp::FixedPoint; + + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; ++i) { + const int32_t input = + static_cast(input_data[i]) - input_zero_point; + if (input <= -input_range_radius) { + output_data[i] = kMinInt8; + } else if (input >= input_range_radius) { + output_data[i] = kMaxInt8; + } else { + const int32_t input_in_q4 = + MultiplyByQuantizedMultiplier(input, input_multiplier, input_shift); + const int32_t output_in_q0 = + gemmlowp::tanh(F4::FromRaw(input_in_q4)).raw(); + + // Rescale and downcast. + using gemmlowp::RoundingDivideByPOT; + int32_t output_in_q24 = + RoundingDivideByPOT(output_in_q0, 31 - kOutputScale); + output_in_q24 = std::min(std::max(output_in_q24, kMinInt8), kMaxInt8); + output_data[i] = static_cast(output_in_q24); + } + } +} + +inline void Tanh(int32_t input_multiplier, int32_t input_left_shift, + const RuntimeShape& input_shape, const int16_t* ptr_input_data, + const RuntimeShape& output_shape, int16_t* ptr_output_data) { + // We use the LUT for sigmoid and take into account, that + // tanh(x) = 2*sigmoid(2*x) - 1 + + // We scale by 3/4 to expand range [-8,8]->[-10.7,10.7]. + // In case of general parameter scale, multiplier 3 is taken into account + // in TanhPrepare function and it is included in + // input_multiplier already. + + if (input_multiplier == 0) { // power of two case + input_multiplier = 3 << input_left_shift; + input_left_shift = 0; + } + + int32_t round = (input_left_shift > 0) ? 1 << (input_left_shift - 1) : 0; + + int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; ++i, ptr_input_data++, ptr_output_data++) { + int32_t input_data = + ((*ptr_input_data) * input_multiplier + round) >> input_left_shift; + + uint32_t abs_input_data = abs(input_data); + uint32_t uh = abs_input_data >> 8; + int32_t result; + + if (uh >= 255) { + // Saturate to maximum. + result = 0xFFFF << 8; + } else { + uint32_t ua = sigmoid_table_uint16[uh]; + uint32_t ub = sigmoid_table_uint16[uh + 1]; + + uint8_t ut = abs_input_data & 0xFF; + + result = (ua << 8) + ut * (ub - ua); + } + + result = (input_data >= 0) + ? (result - (1 << (14 + 9)) + (1 << (9 - 2))) + : (-result + (1 << (14 + 9)) + (1 << (9 - 2)) - 1); + + // Convert back to 16-bit. + result >>= (9 - 1); + + *ptr_output_data = result; + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_TANH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/transpose_conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/transpose_conv.h new file mode 100644 index 000000000..92919a71d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/integer_ops/transpose_conv.h @@ -0,0 +1,224 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_TRANSPOSE_CONV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_TRANSPOSE_CONV_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_integer_ops { + +// Fixed-point per-channel-quantization transpose convolution reference kernel. +inline void TransposeConv( + const ConvParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + int8_t* output_data, const RuntimeShape& im2col_shape, int8_t* im2col_data, + int32_t* scratch_buffer) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int32_t input_offset = params.input_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_activation_min = std::numeric_limits::min(); + const int32_t output_activation_max = std::numeric_limits::max(); + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + + const int num_elements = output_shape.FlatSize(); + // We need to initialize scratch_buffer to all 0s, as we apply the same + // 'scatter' based trick as in float version. + memset(scratch_buffer, 0, num_elements * sizeof(int32_t)); + + // Loop through input elements one at a time. + for (int batch = 0; batch < batches; ++batch) { + for (int in_y = 0; in_y < input_height; ++in_y) { + for (int in_x = 0; in_x < input_width; ++in_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + // Loop through the output elements it will influence. + const int out_x_origin = (in_x * stride_width) - pad_width; + const int out_y_origin = (in_y * stride_height) - pad_height; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + for (int out_channel = 0; out_channel < output_depth; + ++out_channel) { + // Compute output element location. + const int out_x = out_x_origin + filter_x; + const int out_y = out_y_origin + filter_y; + // We cannot accumulate out of bounds. + if ((out_x >= 0) && (out_x < output_width) && (out_y >= 0) && + (out_y < output_height)) { + const int8_t input_value = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + const int8_t filter_value = + filter_data[Offset(filter_shape, out_channel, filter_y, + filter_x, in_channel)]; + scratch_buffer[Offset(output_shape, batch, out_y, out_x, + out_channel)] += + (input_value + input_offset) * filter_value; + } + } + } + } + } + } + } + } + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + int32_t acc = scratch_buffer[Offset(output_shape, batch, out_y, out_x, + out_channel)]; + if (bias_data) { + acc += bias_data[out_channel]; + } + acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier[out_channel], output_shift[out_channel]); + acc += output_offset; + acc = std::max(acc, output_activation_min); + acc = std::min(acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + static_cast(acc); + } + } + } + } +} + +// int16_t input (zero_point=0), int8_t filter, int32 or int64 accumulator +template +inline void TransposeConv( + const ConvParams& params, const int32_t* output_multiplier, + const int32_t* output_shift, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& filter_shape, + const int8_t* filter_data, const RuntimeShape& bias_shape, + const Scalar* bias_data, const RuntimeShape& output_shape, + int16_t* output_data, const RuntimeShape& im2col_shape, int8_t* im2col_data, + Scalar* scratch_buffer) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int32_t output_activation_min = std::numeric_limits::min(); + const int32_t output_activation_max = std::numeric_limits::max(); + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + + const int num_elements = output_shape.FlatSize(); + // We need to initialize scratch_buffer to all 0s, as we apply the same + // 'scatter' based trick as in float version. + memset(scratch_buffer, 0, num_elements * sizeof(Scalar)); + + // Loop through input elements one at a time. + for (int batch = 0; batch < batches; ++batch) { + for (int in_y = 0; in_y < input_height; ++in_y) { + for (int in_x = 0; in_x < input_width; ++in_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + // Loop through the output elements it will influence. + const int out_x_origin = (in_x * stride_width) - pad_width; + const int out_y_origin = (in_y * stride_height) - pad_height; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + for (int out_channel = 0; out_channel < output_depth; + ++out_channel) { + // Compute output element location. + const int out_x = out_x_origin + filter_x; + const int out_y = out_y_origin + filter_y; + // We cannot accumulate out of bounds. + if ((out_x >= 0) && (out_x < output_width) && (out_y >= 0) && + (out_y < output_height)) { + const int32_t input_value = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + const int32_t filter_value = + filter_data[Offset(filter_shape, out_channel, filter_y, + filter_x, in_channel)]; + scratch_buffer[Offset(output_shape, batch, out_y, out_x, + out_channel)] += + input_value * filter_value; + } + } + } + } + } + } + } + } + + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + Scalar acc = scratch_buffer[Offset(output_shape, batch, out_y, out_x, + out_channel)]; + if (bias_data) { + acc += bias_data[out_channel]; + } + int32_t scaled_acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier[out_channel], output_shift[out_channel]); + scaled_acc = std::max(scaled_acc, output_activation_min); + scaled_acc = std::min(scaled_acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + static_cast(scaled_acc); + } + } + } + } +} + +} // namespace reference_integer_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_TRANSPOSE_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/l2normalization.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/l2normalization.h new file mode 100644 index 000000000..7587d2b5c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/l2normalization.h @@ -0,0 +1,90 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_L2NORMALIZATION_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_L2NORMALIZATION_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void L2Normalization(const tflite::L2NormalizationParams& op_params, + const RuntimeShape& input_shape, + const float* input_data, + const RuntimeShape& output_shape, + float* output_data, float epsilon = 1e-6) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + for (int i = 0; i < outer_size; ++i) { + float squared_l2_norm = 0; + for (int c = 0; c < depth; ++c) { + const float val = input_data[depth * i + c]; + squared_l2_norm += val * val; + } + float l2_norm = std::sqrt(squared_l2_norm); + l2_norm = std::max(l2_norm, epsilon); + for (int c = 0; c < depth; ++c) { + output_data[depth * i + c] = input_data[depth * i + c] / l2_norm; + } + } +} + +inline void L2Normalization(const tflite::L2NormalizationParams& op_params, + const RuntimeShape& input_shape, + const uint8_t* input_data, + const RuntimeShape& output_shape, + uint8_t* output_data) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int32_t input_zero_point = op_params.input_zero_point; + + for (int i = 0; i < outer_size; ++i) { + int32_t square_l2_norm = 0; + for (int c = 0; c < depth; c++) { + int32_t diff = input_data[depth * i + c] - input_zero_point; + square_l2_norm += diff * diff; + } + int32_t inv_l2norm_multiplier; + int inv_l2norm_shift; + GetInvSqrtQuantizedMultiplierExp(square_l2_norm, kReverseShift, + &inv_l2norm_multiplier, &inv_l2norm_shift); + for (int c = 0; c < depth; c++) { + int32_t diff = input_data[depth * i + c] - input_zero_point; + int32_t rescaled_diff = MultiplyByQuantizedMultiplierSmallerThanOneExp( + 128 * diff, inv_l2norm_multiplier, inv_l2norm_shift); + int32_t unclamped_output_val = 128 + rescaled_diff; + int32_t output_val = + std::min(static_cast(255), + std::max(static_cast(0), unclamped_output_val)); + output_data[depth * i + c] = static_cast(output_val); + } + } +} + +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_L2NORMALIZATION_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/leaky_relu.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/leaky_relu.h new file mode 100644 index 000000000..06f691abd --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/leaky_relu.h @@ -0,0 +1,69 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LEAKY_RELU_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LEAKY_RELU_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_ops { + +inline void LeakyRelu(const tflite::LeakyReluParams& params, + const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const float val = input_data[i]; + // Note that alpha might be > 1 or < 0, so we don't use std::max here. + output_data[i] = val > 0 ? val : val * params.alpha; + } +} + +template +inline void QuantizeLeakyRelu(const LeakyReluParams& params, + const RuntimeShape& input_shape, + const T* input_data, + const RuntimeShape& output_shape, + T* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + static const int32_t quantized_min = std::numeric_limits::min(); + static const int32_t quantized_max = std::numeric_limits::max(); + for (int i = 0; i < flat_size; ++i) { + const int32_t input_value = input_data[i] - params.input_offset; + int32_t unclamped_output; + if (input_value >= 0) { + unclamped_output = params.output_offset + + MultiplyByQuantizedMultiplier( + input_value, params.output_multiplier_identity, + params.output_shift_identity); + } else { + unclamped_output = params.output_offset + + MultiplyByQuantizedMultiplier( + input_value, params.output_multiplier_alpha, + params.output_shift_alpha); + } + const T clamped_output = + std::min(quantized_max, std::max(quantized_min, unclamped_output)); + output_data[i] = static_cast(clamped_output); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LEAKY_RELU_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/log_softmax.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/log_softmax.h new file mode 100644 index 000000000..67e6e667f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/log_softmax.h @@ -0,0 +1,256 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LOG_SOFTMAX_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LOG_SOFTMAX_H_ + +#include +#include +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { +namespace reference_ops { + +inline void LogSoftmax(const SoftmaxParams& params, + const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + + for (int i = 0; i < outer_size; ++i) { + // Find max element value which we'll use to ensure numerical stability + // taking advantage of the following equality: + // log(exp(x[i])/sum(exp(x[i]))) == log(exp(x[i]+C)/sum(exp(x[i]+C))) + float max = std::numeric_limits::lowest(); + for (int c = 0; c < depth; ++c) { + max = std::max(max, input_data[i * depth + c]); + } + + // Compute sum. + float sum = 0.f; + for (int c = 0; c < depth; ++c) { + sum += std::exp(input_data[i * depth + c] - max); + } + + // Compute result. + const float log_sum = std::log(sum); + for (int c = 0; c < depth; ++c) { + output_data[i * depth + c] = input_data[i * depth + c] - max - log_sum; + } + } +} + +inline void LogSoftmax(const SoftmaxParams& params, + const RuntimeShape& input_shape, + const uint8_t* input_data, + const RuntimeShape& output_shape, uint8_t* output_data) { + const int32_t input_multiplier = params.input_multiplier; + const int32_t input_left_shift = params.input_left_shift; + const int32_t reverse_scaling_divisor = params.reverse_scaling_divisor; + const int32_t reverse_scaling_right_shift = + params.reverse_scaling_right_shift; + const int diff_min = params.diff_min; + // The representation chosen for the input to the exp() function is Q5.26. + // We need to leave extra space since values that we skip might be as large + // as -32 before multiplying by input_beta_multiplier, and therefore as + // large as -16 afterwards. Note that exp(-8) is definitely not + // insignificant to accumulation, but exp(-16) definitely is. + static constexpr int kScaledDiffIntegerBits = 5; + static constexpr int kAccumulationIntegerBits = 12; + static constexpr int kOutputIntegerBits = 4; + using FixedPointScaledDiff = + gemmlowp::FixedPoint; + using FixedPointAccum = + gemmlowp::FixedPoint; + + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + + for (int i = 0; i < outer_size; ++i) { + uint8_t max_in_row = 0; + for (int c = 0; c < depth; ++c) { + max_in_row = std::max(max_in_row, input_data[i * depth + c]); + } + + FixedPointAccum sum_of_exps = FixedPointAccum::Zero(); + for (int c = 0; c < depth; ++c) { + int32_t input_diff = + static_cast(input_data[i * depth + c]) - max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_rescaled = + MultiplyByQuantizedMultiplierGreaterThanOne( + input_diff, input_multiplier, input_left_shift); + const FixedPointScaledDiff scaled_diff_f8 = + FixedPointScaledDiff::FromRaw(input_diff_rescaled); + sum_of_exps = sum_of_exps + gemmlowp::Rescale( + exp_on_negative_values(scaled_diff_f8)); + } + } + + const int32_t fixed_log_sum_of_exps = + log_x_for_x_greater_than_or_equal_to_1( + sum_of_exps) + .raw(); + + // rescaled_diff_min is smallest representable in + // Q(kScaledDiffIntegerBits).(31-kScaledDiffIntegerBits) plus the + // log-sub-exps that will be subtracted in the loop. + // + // The thresholds diff_min, etc are negative. + const int rescaled_diff_min = + fixed_log_sum_of_exps + std::numeric_limits::lowest(); + const int adjusted_diff_min = + std::max(static_cast( + diff_min - 1), // Note use of > below instead of >= above. + MultiplyByQuantizedMultiplierSmallerThanOneExp( + rescaled_diff_min, reverse_scaling_divisor, + -reverse_scaling_right_shift)); + + for (int c = 0; c < depth; ++c) { + int32_t input_diff = + static_cast(input_data[i * depth + c]) - max_in_row; + if (input_diff > adjusted_diff_min) { + const int32_t input_diff_rescaled = + MultiplyByQuantizedMultiplierGreaterThanOne( + input_diff, input_multiplier, input_left_shift); + int32_t unsat_output = + gemmlowp::RoundingDivideByPOT( + (input_diff_rescaled - fixed_log_sum_of_exps), + 31 - kScaledDiffIntegerBits - kOutputIntegerBits) + + 255; + + output_data[i * depth + c] = static_cast( + std::max(std::min(unsat_output, static_cast(255)), + static_cast(0))); + } else { + // Set output to smallest value. + output_data[i * depth + c] = 0; + } + } + } +} + +template +inline void LogSoftmaxQuantized(const SoftmaxParams& params, + const size_t outer_size, const size_t depth, + const RuntimeShape& input_shape, + const T* input_data, + const RuntimeShape& output_shape, + T* output_data) { + const int32_t input_multiplier = params.input_multiplier; + const int32_t input_left_shift = params.input_left_shift; + const int32_t reverse_scaling_divisor = params.reverse_scaling_divisor; + const int32_t reverse_scaling_right_shift = + params.reverse_scaling_right_shift; + const int diff_min = params.diff_min; + + static constexpr T kMinT8 = std::numeric_limits::min(); + static constexpr T kMaxT8 = std::numeric_limits::max(); + static constexpr int32_t kMinInt32 = std::numeric_limits::min(); + + // All IntegerBits must agree with Prepare function. + // Input is chosen as Q5.26 so exp(-1 * 2^5 * 2^-1) = exp(-16) is negligible. + static constexpr int kInputIntegerBits = 5; + static constexpr int kAccumulationIntegerBits = 12; + static constexpr int kOutputIntegerBits = 4; + using F5 = gemmlowp::FixedPoint; + using F12 = gemmlowp::FixedPoint; + + for (size_t outer_index = 0; outer_index < outer_size; ++outer_index) { + T max_in_row = kMinT8; + for (size_t inner_index = 0; inner_index < depth; ++inner_index) { + max_in_row = + std::max(max_in_row, input_data[outer_index * depth + inner_index]); + } + + // Accumulator "sum_of_exps_in_q12" is safe from overflowing in 2^12 steps. + F12 sum_of_exps_in_q12 = F12::FromRaw(0); + for (size_t inner_index = 0; inner_index < depth; ++inner_index) { + int32_t input_diff = + static_cast(input_data[outer_index * depth + inner_index]) - + max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_in_q5 = MultiplyByQuantizedMultiplier( + input_diff, input_multiplier, input_left_shift); + sum_of_exps_in_q12 = + sum_of_exps_in_q12 + + gemmlowp::Rescale( + exp_on_negative_values(F5::FromRaw(input_diff_in_q5))); + } + } + + const int32_t log_sum_of_exps_in_q5 = + log_x_for_x_greater_than_or_equal_to_1( + sum_of_exps_in_q12) + .raw(); + + // Potentially reduced the valid range. shifted_log_sum_of_exps_in_q5 is + // smallest representable in Q5.26 plus the log_sum_of_exps. + const int32_t shifted_log_sum_of_exps_in_q5 = + log_sum_of_exps_in_q5 + kMinInt32; + const int32_t adjusted_diff_min = + std::max(static_cast(diff_min - 1), + MultiplyByQuantizedMultiplier(shifted_log_sum_of_exps_in_q5, + reverse_scaling_divisor, + -reverse_scaling_right_shift)); + + for (size_t inner_index = 0; inner_index < depth; ++inner_index) { + int32_t input_diff = + static_cast(input_data[outer_index * depth + inner_index]) - + max_in_row; + // Note use of > below instead of >= above. + if (input_diff > adjusted_diff_min) { + const int32_t input_diff_in_q5 = MultiplyByQuantizedMultiplier( + input_diff, input_multiplier, input_left_shift); + + // Rescale and downcast. + int32_t output_in_q27 = + gemmlowp::RoundingDivideByPOT( + (input_diff_in_q5 - log_sum_of_exps_in_q5), + 31 - kInputIntegerBits - kOutputIntegerBits) + + kMaxT8; + + output_in_q27 = + std::max(std::min(output_in_q27, static_cast(kMaxT8)), + static_cast(kMinT8)); + output_data[outer_index * depth + inner_index] = + static_cast(output_in_q27); + } else { + output_data[outer_index * depth + inner_index] = kMinT8; + } + } + } +} + +inline void LogSoftmax(const SoftmaxParams& params, const size_t outer_size, + const size_t depth, const RuntimeShape& input_shape, + const int8_t* input_data, + const RuntimeShape& output_shape, int8_t* output_data) { + LogSoftmaxQuantized(params, outer_size, depth, input_shape, input_data, + output_shape, output_data); +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LOG_SOFTMAX_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/logistic.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/logistic.h new file mode 100644 index 000000000..96b541517 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/logistic.h @@ -0,0 +1,132 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LOGISTIC_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LOGISTIC_H_ + +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/op_macros.h" + +namespace tflite { +namespace reference_ops { + +inline void Logistic(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const float cutoff_upper = 16.619047164916992188f; + const float cutoff_lower = -9.f; + + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + // Rational for using approximation in reference kernel. + // 0. This approximation gives enough precision for float. + // 1. This works around an issue on an embedded chipset where exp() does not + // return correctly as expected - exp(x) should return inf when overflown + // not 1.701417 IEEE 754 defines representation for inf. + // 2. This will speed up calculation and is matching the behavior in the + // optimized kernels. (check the definition of scalar_logistic_op) + + for (int i = 0; i < flat_size; i++) { + float val = input_data[i]; + float result; + if (val > cutoff_upper) { + result = 1.0f; + } else if (val < cutoff_lower) { + result = std::exp(val); + } else { + result = 1.f / (1.f + std::exp(-val)); + } + output_data[i] = result; + } +} + +// Convenience version that allows, for example, generated-code calls to be +// uniform between data types. +inline void Logistic(const LogisticParams&, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& output_shape, + float* output_data) { + // Drop params: not needed. + Logistic(input_shape, input_data, output_shape, output_data); +} + +inline void Logistic(const LogisticParams& params, + const RuntimeShape& input_shape, const int16_t* input_data, + const RuntimeShape& output_shape, int16_t* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + // F0 uses 0 integer bits, range [-1, 1]. + // This is the return type of math functions such as tanh, logistic, + // whose range is in [-1, 1]. + using F0 = gemmlowp::FixedPoint; + // F3 uses 3 integer bits, range [-8, 8], the input range expected here. + using F3 = gemmlowp::FixedPoint; + + const F3 input = F3::FromRaw(input_data[i]); + F0 output = gemmlowp::logistic(input); + output_data[i] = output.raw(); + } +} + +// Quantized int8_t logistic activation. Cheats by dequantizing and +// requantizing around the floating point logistic method. This implementation +// is slow on platforms without a floating point unit. + +// TODO(b/141211002): Delete this int8_t implementation once we can reuse the +// approach used in TFLite for int8_t Logistic. +inline void Logistic(const RuntimeShape& input_shape, const int8_t* input_data, + float input_scale, int input_zero_point, + const RuntimeShape& output_shape, int8_t* output_data, + float output_scale, int output_zero_point) { + const float cutoff_upper = 16.619047164916992188f; + const float cutoff_lower = -9.f; + + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + // Rational for using approximation in reference kernel. + // 0. This approximation gives enough precision for float. + // 1. This works around an issue on an embedded chipset where exp() does not + // return correctly as expected - exp(x) should return inf when overflown + // not 1.701417 IEEE 754 defines representation for inf. + // 2. This will speed up calculation and is matching the behavior in the + // optimized kernels. (check the definition of scalar_logistic_op) + + for (int i = 0; i < flat_size; i++) { + // Dequantize. + float val = + static_cast((input_data[i] - input_zero_point) * input_scale); + float result; + if (val > cutoff_upper) { + result = 1.0f; + } else if (val < cutoff_lower) { + result = std::exp(val); + } else { + result = 1.f / (1.f + std::exp(-val)); + } + // Requantize + int8_t output = + static_cast(result / output_scale + output_zero_point); + output_data[i] = output; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LOGISTIC_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/lstm_cell.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/lstm_cell.h new file mode 100644 index 000000000..17b113eb9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/lstm_cell.h @@ -0,0 +1,422 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LSTM_CELL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LSTM_CELL_H_ + +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/reference/concatenation.h" +#include "tensorflow/lite/kernels/internal/reference/fully_connected.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +inline void LstmCell( + const LstmCellParams& params, const RuntimeShape& unextended_input_shape, + const float* input_data, const RuntimeShape& unextended_prev_activ_shape, + const float* prev_activ_data, const RuntimeShape& weights_shape, + const float* weights_data, const RuntimeShape& unextended_bias_shape, + const float* bias_data, const RuntimeShape& unextended_prev_state_shape, + const float* prev_state_data, + const RuntimeShape& unextended_output_state_shape, float* output_state_data, + const RuntimeShape& unextended_output_activ_shape, float* output_activ_data, + const RuntimeShape& unextended_concat_temp_shape, float* concat_temp_data, + const RuntimeShape& unextended_activ_temp_shape, float* activ_temp_data) { + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_prev_activ_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_bias_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_prev_state_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_state_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_activ_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_concat_temp_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_activ_temp_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape prev_activ_shape = + RuntimeShape::ExtendedShape(4, unextended_prev_activ_shape); + const RuntimeShape bias_shape = + RuntimeShape::ExtendedShape(4, unextended_bias_shape); + const RuntimeShape prev_state_shape = + RuntimeShape::ExtendedShape(4, unextended_prev_state_shape); + const RuntimeShape output_state_shape = + RuntimeShape::ExtendedShape(4, unextended_output_state_shape); + const RuntimeShape output_activ_shape = + RuntimeShape::ExtendedShape(4, unextended_output_activ_shape); + const RuntimeShape concat_temp_shape = + RuntimeShape::ExtendedShape(4, unextended_concat_temp_shape); + const RuntimeShape activ_temp_shape = + RuntimeShape::ExtendedShape(4, unextended_activ_temp_shape); + TFLITE_DCHECK_GE(weights_shape.DimensionsCount(), 2); + + const int weights_dim_count = weights_shape.DimensionsCount(); + const int batches = + MatchingDim(input_shape, 0, prev_activ_shape, 0, prev_state_shape, 0, + output_state_shape, 0, output_activ_shape, 0); + const int height = + MatchingDim(input_shape, 1, prev_activ_shape, 1, prev_state_shape, 1, + output_state_shape, 1, output_activ_shape, 1); + const int width = + MatchingDim(input_shape, 2, prev_activ_shape, 2, prev_state_shape, 2, + output_state_shape, 2, output_activ_shape, 2); + const int input_depth = input_shape.Dims(3); + const int prev_activ_depth = prev_activ_shape.Dims(3); + const int total_input_depth = prev_activ_depth + input_depth; + TFLITE_DCHECK_EQ(weights_shape.Dims(weights_dim_count - 1), + total_input_depth); + TFLITE_DCHECK_EQ(FlatSizeSkipDim(bias_shape, 3), 1); + const int intern_activ_depth = + MatchingDim(weights_shape, weights_dim_count - 2, bias_shape, 3); + TFLITE_DCHECK_EQ(weights_shape.FlatSize(), + intern_activ_depth * total_input_depth); + TFLITE_DCHECK_EQ(intern_activ_depth % 4, 0); + const int output_depth = + MatchingDim(prev_state_shape, 3, prev_activ_shape, 3, output_state_shape, + 3, output_activ_shape, 3); + TFLITE_DCHECK_EQ(output_depth, intern_activ_depth / 4); + + // Concatenate prev_activ and input data together + float const* concat_input_arrays_data[2] = {input_data, prev_activ_data}; + const RuntimeShape* concat_input_arrays_shapes[2] = {&input_shape, + &prev_activ_shape}; + tflite::ConcatenationParams concat_params; + concat_params.axis = 3; + concat_params.inputs_count = 2; + Concatenation(concat_params, concat_input_arrays_shapes, + concat_input_arrays_data, concat_temp_shape, concat_temp_data); + + // Fully connected + tflite::FullyConnectedParams fc_params; + fc_params.float_activation_min = std::numeric_limits::lowest(); + fc_params.float_activation_max = std::numeric_limits::max(); + FullyConnected(fc_params, concat_temp_shape, concat_temp_data, weights_shape, + weights_data, bias_shape, bias_data, activ_temp_shape, + activ_temp_data); + + // Memory state update (the LSTM "guts") + for (int b = 0; b < batches; ++b) { + for (int w = 0; w < width; ++w) { + for (int h = 0; h < height; ++h) { + for (int c = 0; c < output_depth; ++c) { + const float input_gate = + 1.f / + (1.f + std::exp(-activ_temp_data[Offset(activ_temp_shape, b, h, w, + 0 * output_depth + c)])); + const float new_input = std::tanh(activ_temp_data[Offset( + activ_temp_shape, b, h, w, 1 * output_depth + c)]); + const float forget_gate = + 1.f / + (1.f + std::exp(-activ_temp_data[Offset(activ_temp_shape, b, h, w, + 2 * output_depth + c)])); + const float output_gate = + 1.f / + (1.f + std::exp(-activ_temp_data[Offset(activ_temp_shape, b, h, w, + 3 * output_depth + c)])); + const float new_state = + input_gate * new_input + + forget_gate * + prev_state_data[Offset(prev_state_shape, b, h, w, c)]; + output_state_data[Offset(output_state_shape, b, h, w, c)] = new_state; + output_activ_data[Offset(output_activ_shape, b, h, w, c)] = + output_gate * std::tanh(new_state); + } + } + } + } +} + +// Quantized LSTM cell implementation. +// The quantization of the input, output arrays is as follows: +// - The input activations are quantized as uint8 on the interval +// [-1, 127/128]. +// The rationale for that is that is the natural interval for output +// activations (see next point) and these need to be concatenated together. +// We could accommodate different ranges by re-scaling, but we empirically +// found that setting the input activations range to be [-1, 127/128] in the +// first place, removing the need for re-scaling, greatly improves accuracy. +// - The output activations are quantized as uint8 on the interval +// [-1, 127/128]. +// The rationale for that is that the definition of a LSTM cell makes them +// intrinsically constrained in [-1, 1]; tweaking that to [-1, 127/128] +// makes for simpler, more accurate fixed-point arithmetic. +// - The output-at-previous-timestep state array is obviously quantized as +// the output activations. +// - The internal LSTM memory (not the output-at-previous-timestep, the other +// internal state array) is int16-quantized and may use any power-of-two, +// symmetric range i.e. [-2^N, 2^N * 32767/32768] for any N, which we call +// StateIntegerBits below, see the below discussion of that template +// parameter ("The StateIntegerBits template parameter"). +// - The output of the internal fully-connected node is int16-quantized +// on the interval [-8, 8 * 32767/32768], the rationale for which is +// explained just below ("Why [-8, 8] for fully-connected output?"). +// +// +// === The StateIntegerBits template parameter === +// +// The StateIntegerBits template parameter controls the fixed-point format used +// to represent the internal memory of the LSTM cell (not the +// output-at-previous-timestep, the other internal state array). It's currently +// a template parameter so that the model can control that. The most typical +// value for StateIntegerBits is 4. Other plausible values are anywhere between +// 3 and 5. We might eventually standardize on a single supported value, e.g. 4, +// and drop that template parameter. The reason why it can't be a runtime +// parameter is that this controls the fixed-point format used, i.e. we need to +// generate actually different code based on it. In particular, we generate code +// for a fixed-point tanh() implementation for that format, which internally +// uses a fixed-point exp() implementation, which internally uses a +// barrel-shifter with a number of steps that depends on StateIntegerBits. +// Another consequence of that is that a higher value of StateIntegerBits +// results in a more expensive implementation (more barrel shifter steps +// needed). +// +// +// === Why [-8, 8] for fully-connected output? === +// +// This array is only fed to Logistic and Tanh functions, for which +// the quantized implementation will want to use fixed-point arithmetic, +// requiring a power-of-two representation interval. Thus, we should right +// away quantize this array to a power-of-two interval; otherwise, +// implementation will need to rescale that, losing any benefit that a tighter +// representation interval might otherwise yield, while introducing some +// numerical error and computational overhead. +// +// Now, Logistic and Tanh +// are nearly constant (nearly equal to their horizontal asymptotes) +// outside of a small bounded interval around 0: +// +// Logistic(4) = 1 - 1.8e-2 Tanh(4) = 1 - 6.7e-4 +// Logistic(8) = 1 - 3.4e-4 Tanh(8) = 1 - 2.3e-7 +// Logistic(16) = 1 - 1.1e-7 Tanh(16) = 1 - 2.5e-14 +// +// From this, we see that clamping to [-4, 4] would be too inaccurate +// (the error of 1.8e-2 on Logistic would be felt even in 8bit precision) +// while clamping to [-16, 16] would make no difference even in float32. +// However, for a fixed-point implementation in 16-bit integers, using 5 +// integer bits to represent the [-16, 16] range would leave only 11 +// fractional bits, giving an increment of 2^-11 = 4.9e-4 between consecutive +// representable values. Notice that is higher than the +// worst-case clamping error with clamping to [-8, 8]: 3.4e-4 for Logistic. +// Using [-8, 8] thus seems like the better compromise overall, enjoying +// an increment of 2.4e-4 between representable values and a worst-case +// clamping error of 3.4e-4, both better than the increment of 4.9e-4 with +// [-16, 16]. +// +// Moreover, all other things being equal, it is nice to choose the narrower +// representation range, as that makes the implementation of fixed-point +// math functions a little cheaper (each integer bit requires an additional +// barrel-shifter atep in the implementation of exp(-x)). That is further +// reason to prefer [-8, 8] over [-16, 16]. The choice of [-16, 16] would make +// sense for 32-bit float or 32-bit fixed-point quantization, but we are +// aiming for 16-bit fixed-point quantization of these internal nodes here. +// +template +inline void LstmCell(const LstmCellParams& params, + const RuntimeShape& unextended_input_shape, + const uint8_t* input_data_uint8, + const RuntimeShape& unextended_prev_activ_shape, + const uint8_t* prev_activ_data_uint8, + const RuntimeShape& weights_shape, + const uint8_t* weights_data_uint8, + const RuntimeShape& unextended_bias_shape, + const int32_t* bias_data_int32, + const RuntimeShape& unextended_prev_state_shape, + const int16_t* prev_state_data_int16, + const RuntimeShape& unextended_output_state_shape, + int16_t* output_state_data_int16, + const RuntimeShape& unextended_output_activ_shape, + uint8_t* output_activ_data_uint8, + const RuntimeShape& unextended_concat_temp_shape, + uint8_t* concat_temp_data_uint8, + const RuntimeShape& unextended_activ_temp_shape, + int16_t* activ_temp_data_int16, void* gemmlowp_context) { + (void)gemmlowp_context; // only used in optimized code. + int32_t weights_zero_point = params.weights_zero_point; + int32_t accum_multiplier = params.accum_multiplier; + int accum_shift = params.accum_shift; + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_prev_activ_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_bias_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_prev_state_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_state_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_activ_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_concat_temp_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_activ_temp_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape prev_activ_shape = + RuntimeShape::ExtendedShape(4, unextended_prev_activ_shape); + const RuntimeShape bias_shape = + RuntimeShape::ExtendedShape(4, unextended_bias_shape); + const RuntimeShape prev_state_shape = + RuntimeShape::ExtendedShape(4, unextended_prev_state_shape); + const RuntimeShape output_state_shape = + RuntimeShape::ExtendedShape(4, unextended_output_state_shape); + const RuntimeShape output_activ_shape = + RuntimeShape::ExtendedShape(4, unextended_output_activ_shape); + const RuntimeShape concat_temp_shape = + RuntimeShape::ExtendedShape(4, unextended_concat_temp_shape); + const RuntimeShape activ_temp_shape = + RuntimeShape::ExtendedShape(4, unextended_activ_temp_shape); + TFLITE_DCHECK_GE(weights_shape.DimensionsCount(), 2); + + // Gather dimensions information, and perform consistency checks. + const int weights_dim_count = weights_shape.DimensionsCount(); + const int outer_size = MatchingFlatSizeSkipDim( + input_shape, 3, prev_activ_shape, prev_state_shape, output_state_shape, + output_activ_shape); + const int input_depth = input_shape.Dims(3); + const int prev_activ_depth = prev_activ_shape.Dims(3); + const int total_input_depth = prev_activ_depth + input_depth; + TFLITE_DCHECK_EQ(weights_shape.Dims(weights_dim_count - 1), + total_input_depth); + const int intern_activ_depth = + MatchingDim(weights_shape, weights_dim_count - 2, bias_shape, 3); + TFLITE_DCHECK_EQ(weights_shape.FlatSize(), + intern_activ_depth * total_input_depth); + TFLITE_DCHECK_EQ(FlatSizeSkipDim(bias_shape, 3), 1); + TFLITE_DCHECK_EQ(intern_activ_depth % 4, 0); + const int output_depth = + MatchingDim(prev_state_shape, 3, prev_activ_shape, 3, output_state_shape, + 3, output_activ_shape, 3); + TFLITE_DCHECK_EQ(output_depth, intern_activ_depth / 4); + const int fc_batches = FlatSizeSkipDim(activ_temp_shape, 3); + const int fc_output_depth = + MatchingDim(weights_shape, weights_dim_count - 2, activ_temp_shape, 3); + const int fc_accum_depth = total_input_depth; + TFLITE_DCHECK_EQ(fc_output_depth, 4 * output_depth); + + // Depth-concatenate prev_activ and input data together. + uint8_t const* concat_input_arrays_data[2] = {input_data_uint8, + prev_activ_data_uint8}; + const RuntimeShape* concat_input_arrays_shapes[2] = {&input_shape, + &prev_activ_shape}; + tflite::ConcatenationParams concat_params; + concat_params.axis = 3; + concat_params.inputs_count = 2; + Concatenation(concat_params, concat_input_arrays_shapes, + concat_input_arrays_data, concat_temp_shape, + concat_temp_data_uint8); + + // Implementation of the fully connected node inside the LSTM cell. + // The operands are 8-bit integers, the accumulators are internally 32bit + // integers, and the output is 16-bit fixed-point with 3 integer bits so + // the output range is [-2^3, 2^3] == [-8, 8]. The rationale for that + // is explained in the function comment above. + for (int b = 0; b < fc_batches; ++b) { + for (int out_c = 0; out_c < fc_output_depth; ++out_c) { + // Internal accumulation. + // Initialize accumulator with the bias-value. + int32_t accum = bias_data_int32[out_c]; + // Accumulation loop. + for (int d = 0; d < fc_accum_depth; ++d) { + int16_t input_val = + concat_temp_data_uint8[b * fc_accum_depth + d] - 128; + int16_t weights_val = + weights_data_uint8[out_c * fc_accum_depth + d] - weights_zero_point; + accum += input_val * weights_val; + } + // Down-scale the final int32 accumulator to the scale used by our + // (16-bit, using 3 integer bits) fixed-point format. The quantized + // multiplier and shift here have been pre-computed offline + // (e.g. by toco). + accum = + MultiplyByQuantizedMultiplier(accum, accum_multiplier, accum_shift); + // Saturate, cast to int16, and store to the temporary activations array. + accum = std::max(-32768, std::min(32767, accum)); + activ_temp_data_int16[out_c + fc_output_depth * b] = accum; + } + } + + // Rest of the LSTM cell: tanh and logistic math functions, and some adds + // and muls, all done in 16-bit fixed-point. + for (int b = 0; b < outer_size; ++b) { + for (int c = 0; c < output_depth; ++c) { + // Define the fixed-point data types that we will use here. All use + // int16 as the underlying integer type i.e. all are 16-bit fixed-point. + // They only differ by the number of integral vs. fractional bits, + // determining the range of values that they can represent. + // + // F0 uses 0 integer bits, range [-1, 1]. + // This is the return type of math functions such as tanh, logistic, + // whose range is in [-1, 1]. + using F0 = gemmlowp::FixedPoint; + // F3 uses 3 integer bits, range [-8, 8]. + // This is the range of the previous fully-connected node's output, + // which is our input here. + using F3 = gemmlowp::FixedPoint; + // FS uses StateIntegerBits integer bits, range [-2^StateIntegerBits, + // 2^StateIntegerBits]. It's used to represent the internal state, whose + // number of integer bits is currently dictated by the model. See comment + // on the StateIntegerBits template parameter above. + using FS = gemmlowp::FixedPoint; + // Implementation of input gate, using fixed-point logistic function. + F3 input_gate_input = F3::FromRaw( + activ_temp_data_int16[b * fc_output_depth + 0 * output_depth + c]); + F0 input_gate_output = gemmlowp::logistic(input_gate_input); + // Implementation of input modulation gate, using fixed-point tanh + // function. + F3 input_modulation_gate_input = F3::FromRaw( + activ_temp_data_int16[b * fc_output_depth + 1 * output_depth + c]); + F0 input_modulation_gate_output = + gemmlowp::tanh(input_modulation_gate_input); + // Implementation of forget gate, using fixed-point logistic function. + F3 forget_gate_input = F3::FromRaw( + activ_temp_data_int16[b * fc_output_depth + 2 * output_depth + c]); + F0 forget_gate_output = gemmlowp::logistic(forget_gate_input); + // Implementation of output gate, using fixed-point logistic function. + F3 output_gate_input = F3::FromRaw( + activ_temp_data_int16[b * fc_output_depth + 3 * output_depth + c]); + F0 output_gate_output = gemmlowp::logistic(output_gate_input); + // Implementation of internal multiplication nodes, still in fixed-point. + F0 input_times_input_modulation = + input_gate_output * input_modulation_gate_output; + FS prev_state = FS::FromRaw(prev_state_data_int16[b * output_depth + c]); + FS prev_state_times_forget_state = forget_gate_output * prev_state; + // Implementation of internal addition node, saturating. + FS new_state = gemmlowp::SaturatingAdd( + gemmlowp::Rescale(input_times_input_modulation), + prev_state_times_forget_state); + // Implementation of last internal Tanh node, still in fixed-point. + // Since a Tanh fixed-point implementation is specialized for a given + // number or integer bits, and each specialization can have a substantial + // code size, and we already used above a Tanh on an input with 3 integer + // bits, and per the table in the above function comment there is no + // significant accuracy to be lost by clamping to [-8, +8] for a + // 3-integer-bits representation, let us just do that. This helps people + // porting this to targets where code footprint must be minimized. + F3 new_state_f3 = gemmlowp::Rescale<3>(new_state); + F0 output_activ_int16 = output_gate_output * gemmlowp::tanh(new_state_f3); + // Store the new internal state back to memory, as 16-bit integers. + // Note: here we store the original value with StateIntegerBits, not + // the rescaled 3-integer-bits value fed to tanh. + output_state_data_int16[b * output_depth + c] = new_state.raw(); + // Down-scale the output activations to 8-bit integers, saturating, + // and store back to memory. + int16_t rescaled_output_activ = + gemmlowp::RoundingDivideByPOT(output_activ_int16.raw(), 8); + int16_t clamped_output_activ = std::max( + -128, std::min(127, rescaled_output_activ)); + output_activ_data_uint8[b * output_depth + c] = + 128 + clamped_output_activ; + } + } +} + +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_LSTM_CELL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/maximum_minimum.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/maximum_minimum.h new file mode 100644 index 000000000..cd11b4191 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/maximum_minimum.h @@ -0,0 +1,64 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MAXIMUM_MINIMUM_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MAXIMUM_MINIMUM_H_ + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +void MaximumMinimumBroadcastSlow(const RuntimeShape& unextended_input1_shape, + const T* input1_data, + const RuntimeShape& unextended_input2_shape, + const T* input2_data, + const RuntimeShape& unextended_output_shape, + T* output_data, Op op) { + // Uses element-wise calculation if broadcast is not required. + if (unextended_input1_shape == unextended_input2_shape) { + const int flat_size = + MatchingElementsSize(unextended_input1_shape, unextended_input2_shape, + unextended_output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = op(input1_data[i], input2_data[i]); + } + } else { + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), N); + + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast( + unextended_input1_shape, unextended_input2_shape, &desc1, &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_output_shape), + &output_desc); + + auto maxmin_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + op(input1_data[SubscriptToIndex(desc1, indexes)], + input2_data[SubscriptToIndex(desc2, indexes)]); + }; + NDOpsHelper(output_desc, maxmin_func); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MAXIMUM_MINIMUM_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/mul.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/mul.h new file mode 100644 index 000000000..531977327 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/mul.h @@ -0,0 +1,214 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MUL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MUL_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" + +namespace tflite { + +namespace reference_ops { + +// Element-wise mul that can often be used for inner loop of broadcast Mul as +// well as the non-broadcast Mul. +inline void MulElementwise(int size, const ArithmeticParams& params, + const uint8_t* input1_data, + const uint8_t* input2_data, uint8_t* output_data) { + for (int i = 0; i < size; ++i) { + const int32_t input1_val = params.input1_offset + input1_data[i]; + const int32_t input2_val = params.input2_offset + input2_data[i]; + const int32_t unclamped_result = + params.output_offset + + MultiplyByQuantizedMultiplier(input1_val * input2_val, + params.output_multiplier, + params.output_shift); + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, unclamped_result)); + output_data[i] = static_cast(clamped_output); + } +} + +template +inline void Mul(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + T output_activation_min; + T output_activation_max; + GetActivationParams(params, &output_activation_min, &output_activation_max); + + const int flat_size = + MatchingExtendedShapeFlatSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = ActivationFunctionWithMinMax( + input1_data[i] * input2_data[i], output_activation_min, + output_activation_max); + } +} + +inline void Mul(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const std::complex* input1_data, + const RuntimeShape& input2_shape, + const std::complex* input2_data, + const RuntimeShape& output_shape, + std::complex* output_data) { + const int flat_size = + MatchingExtendedShapeFlatSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = input1_data[i] * input2_data[i]; + } +} + +inline void Mul(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const uint8_t* input1_data, + const RuntimeShape& input2_shape, const uint8_t* input2_data, + const RuntimeShape& output_shape, uint8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + const int flat_size = + MatchingExtendedShapeFlatSize(input1_shape, input2_shape, output_shape); + + MulElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void BroadcastMul4DSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const uint8_t* input1_data, + const RuntimeShape& input2_shape, + const uint8_t* input2_data, + const RuntimeShape& output_shape, + uint8_t* output_data) { + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + const int32_t input1_val = + params.input1_offset + + input1_data[SubscriptToIndex(desc1, b, y, x, c)]; + const int32_t input2_val = + params.input2_offset + + input2_data[SubscriptToIndex(desc2, b, y, x, c)]; + const int32_t unclamped_result = + params.output_offset + + MultiplyByQuantizedMultiplier(input1_val * input2_val, + params.output_multiplier, + params.output_shift); + const int32_t clamped_output = std::min( + params.quantized_activation_max, + std::max(params.quantized_activation_min, unclamped_result)); + output_data[Offset(extended_output_shape, b, y, x, c)] = + static_cast(clamped_output); + } + } + } + } +} + +template +void BroadcastMul4DSlow(const ArithmeticParams& params, + const RuntimeShape& unextended_input1_shape, + const T* input1_data, + const RuntimeShape& unextended_input2_shape, + const T* input2_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + T output_activation_min; + T output_activation_max; + GetActivationParams(params, &output_activation_min, &output_activation_max); + + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + for (int b = 0; b < output_shape.Dims(0); ++b) { + for (int y = 0; y < output_shape.Dims(1); ++y) { + for (int x = 0; x < output_shape.Dims(2); ++x) { + for (int c = 0; c < output_shape.Dims(3); ++c) { + output_data[Offset(output_shape, b, y, x, c)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, b, y, x, c)] * + input2_data[SubscriptToIndex(desc2, b, y, x, c)], + output_activation_min, output_activation_max); + } + } + } + } +} + +inline void BroadcastMul4DSlow(const ArithmeticParams& params, + const RuntimeShape& unextended_input1_shape, + const std::complex* input1_data, + const RuntimeShape& unextended_input2_shape, + const std::complex* input2_data, + const RuntimeShape& unextended_output_shape, + std::complex* output_data) { + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + + for (int b = 0; b < output_shape.Dims(0); ++b) { + for (int y = 0; y < output_shape.Dims(1); ++y) { + for (int x = 0; x < output_shape.Dims(2); ++x) { + for (int c = 0; c < output_shape.Dims(3); ++c) { + output_data[Offset(output_shape, b, y, x, c)] = + input1_data[SubscriptToIndex(desc1, b, y, x, c)] * + input2_data[SubscriptToIndex(desc2, b, y, x, c)]; + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MUL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/neg.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/neg.h new file mode 100644 index 000000000..e127883f9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/neg.h @@ -0,0 +1,37 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_NEG_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_NEG_H_ + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +inline void Negate(const RuntimeShape& input_shape, const T* input_data, + const RuntimeShape& output_shape, T* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; ++i) { + output_data[i] = -input_data[i]; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_NEG_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/pad.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/pad.h new file mode 100644 index 000000000..275894458 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/pad.h @@ -0,0 +1,169 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PAD_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PAD_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +// TFLite Pad supports activation tensors with up to 5 dimensions. +constexpr int PadKernelMaxDimensionCount() { return 5; } + +// There are two versions of pad: Pad and PadV2. In PadV2 there is a second +// scalar input that provides the padding value. Therefore pad_value_ptr can be +// equivalent to a simple input1_data. For Pad, it should point to a zero +// value. +// +// Note that two typenames are required, so that T=P=int32_t is considered a +// specialization distinct from P=int32_t. +template +inline void PadImpl(const tflite::PadParams& op_params, + const RuntimeShape& input_shape, const T* input_data, + const P* pad_value_ptr, const RuntimeShape& output_shape, + T* output_data) { + const RuntimeShape ext_input_shape = + RuntimeShape::ExtendedShape(PadKernelMaxDimensionCount(), input_shape); + const RuntimeShape ext_output_shape = + RuntimeShape::ExtendedShape(PadKernelMaxDimensionCount(), output_shape); + TFLITE_DCHECK_LE(op_params.left_padding_count, PadKernelMaxDimensionCount()); + TFLITE_DCHECK_LE(op_params.right_padding_count, PadKernelMaxDimensionCount()); + + // Runtime calls are currently fixed at 5 dimensions. Copy inputs so we can + // pad them to 5 dims (yes, we are "padding the padding"). + int left_padding_copy[PadKernelMaxDimensionCount()]; + for (int i = 0; i < PadKernelMaxDimensionCount(); i++) { + left_padding_copy[i] = 0; + } + for (int i = 0; i < op_params.left_padding_count; ++i) { + left_padding_copy[i + PadKernelMaxDimensionCount() - + op_params.left_padding_count] = op_params.left_padding[i]; + } + int right_padding_copy[PadKernelMaxDimensionCount()]; + for (int i = 0; i < PadKernelMaxDimensionCount(); i++) { + right_padding_copy[i] = 0; + } + for (int i = 0; i < op_params.right_padding_count; ++i) { + right_padding_copy[i + PadKernelMaxDimensionCount() - + op_params.right_padding_count] = + op_params.right_padding[i]; + } + + const int output_batch = ext_output_shape.Dims(0); + const int output_plane = ext_output_shape.Dims(1); + const int output_height = ext_output_shape.Dims(2); + const int output_width = ext_output_shape.Dims(3); + const int output_depth = ext_output_shape.Dims(4); + + const int left_b_padding = left_padding_copy[0]; + const int left_p_padding = left_padding_copy[1]; + const int left_h_padding = left_padding_copy[2]; + const int left_w_padding = left_padding_copy[3]; + const int left_d_padding = left_padding_copy[4]; + + const int right_b_padding = right_padding_copy[0]; + const int right_p_padding = right_padding_copy[1]; + const int right_h_padding = right_padding_copy[2]; + const int right_w_padding = right_padding_copy[3]; + const int right_d_padding = right_padding_copy[4]; + + const T pad_value = *pad_value_ptr; + + const T* in_ptr = input_data; + T* out_ptr = output_data; + for (int out_b = 0; out_b < output_batch; ++out_b) { + for (int out_p = 0; out_p < output_plane; ++out_p) { + for (int out_h = 0; out_h < output_height; ++out_h) { + for (int out_w = 0; out_w < output_width; ++out_w) { + for (int out_d = 0; out_d < output_depth; ++out_d) { + if (out_b < left_b_padding || + out_b >= output_batch - right_b_padding || + out_p < left_p_padding || + out_p >= output_plane - right_p_padding || + out_h < left_h_padding || + out_h >= output_height - right_h_padding || + out_w < left_w_padding || + out_w >= output_width - right_w_padding || + out_d < left_d_padding || + out_d >= output_depth - right_d_padding) { + *out_ptr++ = pad_value; + } else { + *out_ptr++ = *in_ptr++; + } + } + } + } + } + } +} + +template +inline void Pad(const tflite::PadParams& op_params, + const RuntimeShape& input_shape, const T* input_data, + const P* pad_value_ptr, const RuntimeShape& output_shape, + T* output_data) { + PadImpl(op_params, input_shape, input_data, pad_value_ptr, output_shape, + output_data); +} + +// The second (pad-value) input can be int32_t when, say, the first is uint8_t. +template +inline void Pad(const tflite::PadParams& op_params, + const RuntimeShape& input_shape, const T* input_data, + const int32_t* pad_value_ptr, const RuntimeShape& output_shape, + T* output_data) { + const T converted_pad_value = static_cast(*pad_value_ptr); + PadImpl(op_params, input_shape, input_data, &converted_pad_value, + output_shape, output_data); +} + +// This version avoids conflicting template matching. +template <> +inline void Pad(const tflite::PadParams& op_params, + const RuntimeShape& input_shape, const int32_t* input_data, + const int32_t* pad_value_ptr, const RuntimeShape& output_shape, + int32_t* output_data) { + PadImpl(op_params, input_shape, input_data, pad_value_ptr, output_shape, + output_data); +} + +template +inline void PadImageStyle(const tflite::PadParams& op_params, + const RuntimeShape& input_shape, const T* input_data, + const P* pad_value_ptr, + const RuntimeShape& output_shape, T* output_data) { + Pad(op_params, input_shape, input_data, pad_value_ptr, output_shape, + output_data); +} + +template +inline void PadImageStyle(const tflite::PadParams& op_params, + const RuntimeShape& input_shape, + const float* input_data, const P* pad_value_ptr, + const RuntimeShape& output_shape, + float* output_data) { + Pad(op_params, input_shape, input_data, pad_value_ptr, output_shape, + output_data); +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PAD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/pooling.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/pooling.h new file mode 100644 index 000000000..fe17484cf --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/pooling.h @@ -0,0 +1,303 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_POOLING_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_POOLING_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +inline bool AveragePool(const PoolParams& params, + const RuntimeShape& input_shape, + const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + float total = 0.f; + float filter_count = 0; + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + total += + input_data[Offset(input_shape, batch, in_y, in_x, channel)]; + filter_count++; + } + } + if (filter_count == 0) return false; + const float average = total / filter_count; + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + ActivationFunctionWithMinMax(average, params.float_activation_min, + params.float_activation_max); + } + } + } + } + return true; +} + +inline bool AveragePool(const PoolParams& params, + const RuntimeShape& input_shape, + const uint8_t* input_data, + const RuntimeShape& output_shape, + uint8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + int32_t acc = 0; + int filter_count = 0; + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + acc += + input_data[Offset(input_shape, batch, in_y, in_x, channel)]; + filter_count++; + } + } + if (filter_count == 0) return false; + acc = (acc + filter_count / 2) / filter_count; + acc = std::max(acc, params.quantized_activation_min); + acc = std::min(acc, params.quantized_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + static_cast(acc); + } + } + } + } + return true; +} + +inline void L2Pool(const PoolParams& params, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& output_shape, + float* output_data) { + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + float sum_squares = 0.f; + int filter_count = 0; + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + const float val = + input_data[Offset(input_shape, batch, in_y, in_x, channel)]; + sum_squares += val * val; + filter_count++; + } + } + const float l2pool_result = std::sqrt(sum_squares / filter_count); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + ActivationFunctionWithMinMax(l2pool_result, + params.float_activation_min, + params.float_activation_max); + } + } + } + } +} + +inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& output_shape, + float* output_data) { + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + float max = std::numeric_limits::lowest(); + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + max = std::max( + max, + input_data[Offset(input_shape, batch, in_y, in_x, channel)]); + } + } + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + ActivationFunctionWithMinMax(max, params.float_activation_min, + params.float_activation_max); + } + } + } + } +} + +inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& output_shape, + uint8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + TFLITE_DCHECK_GE(params.quantized_activation_min, 0); + TFLITE_DCHECK_LE(params.quantized_activation_max, 255); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int channel = 0; channel < depth; ++channel) { + const int in_x_origin = + (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = + (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = + std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = + std::min(params.filter_height, input_height - in_y_origin); + uint8_t max = 0; + for (int filter_y = filter_y_start; filter_y < filter_y_end; + ++filter_y) { + for (int filter_x = filter_x_start; filter_x < filter_x_end; + ++filter_x) { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + max = std::max( + max, + input_data[Offset(input_shape, batch, in_y, in_x, channel)]); + } + } + max = std::max(max, params.quantized_activation_min); + max = std::min(max, params.quantized_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, channel)] = + static_cast(max); + } + } + } + } +} +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_POOLING_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.cpp new file mode 100644 index 000000000..3796f5db4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.cpp @@ -0,0 +1,809 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/reference/portable_tensor_utils_impl.h" + +#if defined(_MSC_VER) +#define __restrict__ __restrict +#endif + +namespace tflite { +namespace tensor_utils { + +namespace { +const int32_t kInt16Max = std::numeric_limits::max(); +const int32_t kInt16Min = std::numeric_limits::min(); +} // namespace + +void PortableSymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float* min_value, + float* max_value, float* scaling_factor) { + auto minmax = std::minmax_element(values, values + size); + *min_value = *minmax.first; + *max_value = *minmax.second; + + PortableSymmetricQuantizeFloats(values, size, quantized_values, *min_value, + *max_value, scaling_factor); +} + +void PortableSymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float min_value, + float max_value, float* scaling_factor) { + const int32_t kScale = 127; + const float range = std::max(std::abs(min_value), std::abs(max_value)); + if (range == 0) { + memset(quantized_values, 0, size * sizeof(int8_t)); + *scaling_factor = 1; + return; + } + *scaling_factor = range / kScale; + const float scaling_factor_inv = kScale / range; + for (int i = 0; i < size; ++i) { + const int32_t quantized_value = + static_cast(TfLiteRound(values[i] * scaling_factor_inv)); + // Clamp: just in case some odd numeric offset. + quantized_values[i] = static_cast( + std::min(kScale, std::max(-kScale, quantized_value))); + } +} + +void PortableAsymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, + float* scaling_factor, int32_t* offset) { + const int32_t kMinScale = -128; + const int32_t kMaxScale = 127; + const double qmin_double = kMinScale; + const double qmax_double = kMaxScale; + const auto minmax = std::minmax_element(values, values + size); + const double rmin = static_cast(std::min(0.0f, *minmax.first)); + const double rmax = static_cast(std::max(0.0f, *minmax.second)); + if (rmin == rmax) { + memset(quantized_values, 0, size * sizeof(int8_t)); + *scaling_factor = 1; + *offset = 0; + return; + } else { + double scale = (rmax - rmin) / (qmax_double - qmin_double); + const double zero_point_from_min = qmin_double - rmin / scale; + const double zero_point_from_max = qmax_double - rmax / scale; + const double zero_point_from_min_error = + std::abs(qmin_double) + std::abs(rmin / scale); + const double zero_point_from_max_error = + std::abs(qmax_double) + std::abs(rmax / scale); + const double zero_point_double = + zero_point_from_min_error < zero_point_from_max_error + ? zero_point_from_min + : zero_point_from_max; + int8_t nudged_zero_point = 0; + if (zero_point_double <= qmin_double) { + nudged_zero_point = kMinScale; + } else if (zero_point_double >= qmax_double) { + nudged_zero_point = kMaxScale; + } else { + nudged_zero_point = static_cast(round(zero_point_double)); + } + *scaling_factor = scale; + *offset = nudged_zero_point; + } + const float scaling_factor_inv = 1.0f / *scaling_factor; + for (int i = 0; i < size; ++i) { + const int32_t quantized_value = static_cast( + TfLiteRound(*offset + values[i] * scaling_factor_inv)); + quantized_values[i] = + std::min(kMaxScale, std::max(kMinScale, quantized_value)); + } +} + +void PortableMatrixBatchVectorMultiplyAccumulate(const float* matrix, + int m_rows, int m_cols, + const float* vector, + int n_batch, float* result) { + float* result_in_batch = result; + for (int b = 0; b < n_batch; b++) { + const float* matrix_ptr = matrix; + for (int r = 0; r < m_rows; r++) { + float dot_prod = 0.0f; + const float* vector_in_batch = vector + b * m_cols; + for (int c = 0; c < m_cols; c++) { + dot_prod += *matrix_ptr++ * *vector_in_batch++; + } + *result_in_batch += dot_prod; + ++result_in_batch; + } + } +} + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float* scaling_factors, + int n_batch, float* __restrict__ result) { + for (int batch = 0; batch < n_batch; ++batch, vectors += m_cols) { + const float batch_scaling_factor = scaling_factors[batch]; + // Get the address of the first row. + const int8_t* row_ptr = matrix; + for (int row = 0; row < m_rows; ++row) { + // Initialize the dot product sum for the row to 0. + int32_t dotprod = 0; +#if defined(__GNUC__) + // Prefetch the row to cache. + __builtin_prefetch(row_ptr, 0 /* prefetch for read */, + 3 /* temporal locality */); +#endif + for (int col = 0; col < m_cols; ++col, ++row_ptr) { + dotprod += (*row_ptr) * (vectors[col]); + } // for col + *result += dotprod * batch_scaling_factor; + ++result; + } // for row + } // for batch +} + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float* scaling_factors, + int n_batch, float* __restrict__ result, const float* per_channel_scale, + const int32_t* input_offset, int32_t* scratch, int32_t* row_sums, + bool* compute_row_sums, CpuBackendContext* context) { + if (input_offset == nullptr) { + PortableMatrixBatchVectorMultiplyAccumulate( + matrix, m_rows, m_cols, vectors, scaling_factors, n_batch, result); + return; + } + if (!compute_row_sums || *compute_row_sums) { + PortableReductionSumVector(matrix, row_sums, m_rows, m_cols); + if (compute_row_sums) { + *compute_row_sums = false; + } + } + + for (int batch = 0; batch < n_batch; ++batch, vectors += m_cols) { + const float batch_scaling_factor = scaling_factors[batch]; + const int32_t batch_offset = input_offset[batch]; + const int8_t* row_ptr = matrix; + for (int row = 0; row < m_rows; ++row) { + int32_t dotprod = 0; + float scale = batch_scaling_factor; + if (per_channel_scale) { + scale *= per_channel_scale[row]; + } +#if defined(__GNUC__) + // Prefetch the row to cache. + __builtin_prefetch(row_ptr, 0 /* prefetch for read */, + 3 /* temporal locality */); +#endif + for (int col = 0; col < m_cols; ++col, ++row_ptr) { + dotprod += (*row_ptr) * vectors[col]; + } // for col + dotprod -= row_sums[row] * batch_offset; + *result += dotprod * scale; + ++result; + } // for row + } // for batch +} + +void PortableSparseMatrixBatchVectorMultiplyAccumulate1x4( + const float* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const float* __restrict__ vector, int n_batch, float* __restrict__ result) { + const int kBlockSize = 4; + TFLITE_DCHECK_EQ(m_cols % kBlockSize, 0); + for (int batch = 0; batch < n_batch; batch++) { + const float* matrix_ptr = matrix; + for (int row = 0; row < m_rows; row++) { + float dot_prod = 0.0f; + const float* vector_in_batch = vector + batch * m_cols; + for (int i = segments[row]; i < segments[row + 1]; i++) { + const int block_start_index = indices[i] * kBlockSize; + const float* vector_block_in_batch_ptr = + vector_in_batch + block_start_index; + for (int c = 0; c < kBlockSize; c++) { + dot_prod += *matrix_ptr++ * *vector_block_in_batch_ptr++; + } + } + result[batch * m_rows + row] += dot_prod; + } + } +} + +void PortableSparseMatrixBatchVectorMultiplyAccumulate1x16( + const int8_t* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const int8_t* __restrict__ vector, const int32_t* __restrict__ bias_vector, + int n_batch, const int32_t input_offset, const int32_t output_multiplier, + const int32_t output_shift, const int32_t output_offset, + const int32_t output_activation_min, const int32_t output_activation_max, + int8_t* __restrict__ result) { + const int kBlockSize = 16; + TFLITE_DCHECK_EQ(m_cols % kBlockSize, 0); + for (int batch = 0; batch < n_batch; ++batch) { + const int8_t* matrix_ptr = matrix; + for (int row = 0; row < m_rows; ++row) { + int32_t dot_prod = 0; + const int8_t* vector_in_batch = vector + batch * m_cols; + for (int i = segments[row]; i < segments[row + 1]; ++i) { + const int block_start_index = indices[i] * kBlockSize; + const int8_t* vector_block_in_batch_ptr = + vector_in_batch + block_start_index; + for (int c = 0; c < kBlockSize; c++) { + dot_prod += *matrix_ptr * *vector_block_in_batch_ptr++; + dot_prod += *matrix_ptr++ * input_offset; + } + } + const int32_t bias_value = bias_vector != nullptr ? bias_vector[row] : 0; + dot_prod = MultiplyByQuantizedMultiplier(dot_prod + bias_value, + output_multiplier, output_shift); + dot_prod += output_offset; + result[batch * m_rows + row] = + static_cast(ActivationFunctionWithMinMax( + dot_prod, output_activation_min, output_activation_max)); + } + } +} + +void PortableSparseMatrixBatchVectorMultiplyAccumulate( + const float* __restrict__ matrix, const uint8_t* __restrict__ ledger, + int m_rows, int m_cols, const float* __restrict__ vector, int n_batch, + float* __restrict__ result) { + const int kBlockSize = 16; + TFLITE_DCHECK_EQ( // NOLINT + m_cols % kBlockSize, 0); + for (int batch = 0; batch < n_batch; batch++) { + const float* matrix_ptr = matrix; + const uint8_t* ledger_ptr = ledger; + for (int row = 0; row < m_rows; row++) { + float dot_prod = 0.0f; + int num_nonzero_blocks = *ledger_ptr++; + if (num_nonzero_blocks > 0) { + const float* vector_in_batch = vector + batch * m_cols; + for (int i = 0; i < num_nonzero_blocks; i++) { + const int block_start_index = *ledger_ptr++ * kBlockSize; + const float* vector_block_in_batch_ptr = + vector_in_batch + block_start_index; + for (int c = 0; c < kBlockSize; c++) { + dot_prod += *matrix_ptr++ * *vector_block_in_batch_ptr++; + } + } + } + result[batch * m_rows + row] += dot_prod; + } + } +} + +void PortableSparseMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const uint8_t* ledger, const int m_rows, + const int m_cols, const int8_t* __restrict__ vectors, + const float* scaling_factors, int n_batch, float* __restrict__ result) { + static const int kBlockSize = 16; + TFLITE_DCHECK_EQ( // NOLINT + m_cols % kBlockSize, 0); + for (int batch = 0; batch < n_batch; ++batch, vectors += m_cols) { + const float batch_scaling_factor = scaling_factors[batch]; + const uint8_t* ledger_ptr = ledger; + // Get the address of the first row. + const int8_t* row_ptr = matrix; + for (int row = 0; row < m_rows; ++row) { + // Initialize the dot product sum for the row to 0. + int32_t dotprod = 0; +#if defined(__GNUC__) + // Prefetch the row to cache. + __builtin_prefetch(row_ptr, 0 /* prefetch for read */, + 3 /* temporal locality */); +#endif + int num_nonzero_blocks = *ledger_ptr++; + for (int i = 0; i < num_nonzero_blocks; i++) { + const int block_start_index = *ledger_ptr++ * kBlockSize; + const int8_t* vector_block_ptr = vectors + block_start_index; + for (int c = 0; c < kBlockSize; c++) { + dotprod += (*row_ptr++) * (*vector_block_ptr++); + } // for block + } // for num_nonzero_blocks + result[batch * m_rows + row] += dotprod * batch_scaling_factor; + } // for row + } // for batch +} + +template +void PortableMatrixBatchVectorMultiplyAccumulateImpl( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + T* output) { + const int16_t output_max = std::numeric_limits::max(); + const int16_t output_min = std::numeric_limits::min(); + for (int batch = 0; batch < n_batch; ++batch) { + for (int row = 0; row < n_output; ++row) { + int32_t acc = bias[row]; + for (int col = 0; col < n_input; ++col) { + int8_t input_val = input[batch * n_input + col]; + int8_t weights_val = input_to_gate_weights[row * n_input + col]; + acc += input_val * weights_val; + } + acc = MultiplyByQuantizedMultiplier(acc, multiplier, shift); + acc += output_zp; + acc += output[batch * n_output + row]; + if (acc > output_max) { + acc = output_max; + } + if (acc < output_min) { + acc = output_min; + } + output[batch * n_output + row] = static_cast(acc); + } + } +} + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int16_t* output, CpuBackendContext* context) { + PortableMatrixBatchVectorMultiplyAccumulateImpl( + input, bias, input_to_gate_weights, multiplier, shift, n_batch, n_input, + n_output, output_zp, output); +} + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int8_t* output, CpuBackendContext* context) { + PortableMatrixBatchVectorMultiplyAccumulateImpl( + input, bias, input_to_gate_weights, multiplier, shift, n_batch, n_input, + n_output, output_zp, output); +} + +void PortableMatrixBatchVectorMultiply(const int8_t* input, + int32_t input_zeropoint, + const int8_t* input_to_gate_weights, + int32_t input_to_gate_effective_scale_a, + int32_t input_to_gate_effective_scale_b, + int32_t n_batch, int32_t n_input, + int32_t n_cell, int8_t* gate_output, + int8_t gate_output_zp) { + const int32_t int8_max = std::numeric_limits::max(); + const int32_t int8_min = std::numeric_limits::min(); + for (int batch = 0; batch < n_batch; ++batch) { + for (int row = 0; row < n_cell; ++row) { + int32_t acc = 0; + for (int col = 0; col < n_input; ++col) { + int32_t input_val = input[batch * n_input + col]; + int8_t weights_val = input_to_gate_weights[row * n_input + col]; + acc += (input_val - input_zeropoint) * weights_val; + } + acc = MultiplyByQuantizedMultiplier(acc, input_to_gate_effective_scale_a, + input_to_gate_effective_scale_b); + acc += gate_output_zp; + if (acc > int8_max) { + acc = int8_max; + } + if (acc < int8_min) { + acc = int8_min; + } + gate_output[batch * n_cell + row] = static_cast(acc); + } + } +} + +void PortableMatrixBatchVectorMultiply( + const int16_t* hidden, const int8_t* hidden_to_output_weights, + int32_t proj_effective_scale_a, int32_t proj_effective_scale_b, + const int32_t* gate_bias, int32_t n_batch, int32_t n_hidden, + int32_t n_output, int32_t output_zp, int8_t* proj_output) { + const int16_t int8_max = std::numeric_limits::max(); + const int16_t int8_min = std::numeric_limits::min(); + for (int batch = 0; batch < n_batch; ++batch) { + for (int row = 0; row < n_output; ++row) { + int64_t acc = gate_bias[row]; + for (int col = 0; col < n_hidden; ++col) { + int16_t input_val = hidden[batch * n_hidden + col]; + int8_t weights_val = hidden_to_output_weights[row * n_hidden + col]; + int64_t curr = acc; + acc += input_val * weights_val; + if (input_val * weights_val > 0 && acc < curr) { + acc = std::numeric_limits::max(); + } + if (input_val * weights_val < 0 && acc > curr) { + acc = std::numeric_limits::min(); + } + } + acc = MultiplyByQuantizedMultiplier(acc, proj_effective_scale_a, + proj_effective_scale_b); + acc += output_zp; + if (acc > int8_max) { + acc = int8_max; + } + if (acc < int8_min) { + acc = int8_min; + } + proj_output[batch * n_output + row] = acc; + } + } +} + +void PortableApplyLayerNorm(const int16_t* input, + const int16_t* layer_norm_weights, + const int32_t* bias, int32_t layer_norm_scale_a, + int32_t layer_norm_scale_b, int32_t variance_limit, + int n_batch, int n_input, int16_t* output) { + // The square of std::pow(2, 10), which is the extra factor that makes sure + // normalized values has enough resolution. + static const int kTwoToPower20 = 1 << 20; + for (int i = 0; i < n_batch; ++i) { + int64_t sum = 0; + int64_t sum_sq = 0; + for (int j = 0; j < n_input; ++j) { + const int32_t index = i * n_input + j; + int32_t val = static_cast(input[index]); + sum += val; + sum_sq += val * val; + } + int32_t mean = + static_cast(static_cast(sum) * 1024 / n_input); + // TODO(b/173994730): Avoids overflow but only works for POT n_input. + int32_t temp = kTwoToPower20 / n_input; + int64_t variance = + sum_sq * temp - static_cast(mean) * static_cast(mean); + int32_t variance2 = static_cast(variance / kTwoToPower20); + if (variance2 < 1) { + variance2 = variance_limit; + } + int32_t stddev_inverse_a; + int stddev_inverse_b; + GetInvSqrtQuantizedMultiplierExp(variance2, /*reverse_shift*/ -1, + &stddev_inverse_a, &stddev_inverse_b); + + for (int j = 0; j < n_input; ++j) { + const int32_t index = i * n_input + j; + int32_t val = static_cast(input[index]); + int32_t shifted = 1024 * val - mean; + int32_t rescaled = MultiplyByQuantizedMultiplier( + shifted, stddev_inverse_a, stddev_inverse_b); + // TODO(jianlijianli): Saturate this. + int64_t val3 = rescaled * layer_norm_weights[j] + bias[j]; + int32_t val4 = + static_cast((val3 > 0 ? val3 + 512 : val3 - 512) / 1024); + int32_t val5 = MultiplyByQuantizedMultiplier(val4, layer_norm_scale_a, + layer_norm_scale_b + 12); + val5 = std::min(std::max(kInt16Min, val5), kInt16Max); + output[index] = static_cast(val5); + } + } +} + +void PortableApplyLayerNormFloat(const int16_t* input, + const int16_t* layer_norm_weights, + int32_t layer_norm_scale_a, + int32_t layer_norm_scale_b, + const int32_t* bias, int n_batch, int n_input, + int16_t* output) { + const int32_t int16_max = std::numeric_limits::max(); + const int32_t int16_min = std::numeric_limits::min(); + const float layer_norm_scale = + layer_norm_scale_a * + std::pow(2.0, static_cast(layer_norm_scale_b - 31)); + const float bias_scale = + static_cast(std::pow(2.0, -10)) * layer_norm_scale; + + for (int batch = 0; batch < n_batch; ++batch) { + float sum = 0.0f; + float sum_sq = 0.0f; + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + const float value = static_cast(input[index]); + sum += value; + sum_sq += value * value; + } + const float mean = sum / n_input; + float stddev_inv = 0.0f; + const float variance = sum_sq / n_input - mean * mean; + if (variance == 0) { + stddev_inv = 1.0f / std::sqrt(1e-8f); + } else { + stddev_inv = 1.0f / std::sqrt(variance); + } + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + const float normalized_value = + (static_cast(input[index]) - mean) * stddev_inv; + const float weighted_normalized_value = + normalized_value * layer_norm_weights[i] * layer_norm_scale + + bias[i] * bias_scale; + const int32_t quant_output = static_cast(round( + weighted_normalized_value * static_cast(std::pow(2, 12)))); + output[index] = std::min(int16_max, std::max(int16_min, quant_output)); + } + } +} + +void PortableMatrixScalarMultiplyAccumulate(const int8_t* matrix, + int32_t scalar, int32_t n_row, + int32_t n_col, int32_t* output) { + for (int i = 0; i < n_row; ++i) { + int32_t row_sum = 0; + for (int j = 0; j < n_col; ++j) { + row_sum += *matrix++; + } + output[i] += row_sum * scalar; + } +} + +void PortableApplySigmoid(const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output) { + for (int batch = 0; batch < n_batch; ++batch) { + for (int c = 0; c < n_input; c++) { + using F3 = gemmlowp::FixedPoint; + using F0 = gemmlowp::FixedPoint; + const int index = batch * n_input + c; + F3 sigmoid_input = F3::FromRaw(input[index]); + F0 sigmoid_output = gemmlowp::logistic(sigmoid_input); + output[index] = sigmoid_output.raw(); + } + } +} + +void PortableApplySigmoidFloat(const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output) { + const int32_t int16_max = std::numeric_limits::max(); + const int32_t int16_min = std::numeric_limits::min(); + for (int batch = 0; batch < n_batch; ++batch) { + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + const float float_input = + input[index] * static_cast(std::pow(2, -12)); + const float float_output = 1.0f / (1.0f + std::exp(-float_input)); + const int32_t quant_output = static_cast( + float_output * static_cast(std::pow(2, 15))); + const int32_t quant_output_clamped = + std::min(int16_max, std::max(int16_min, quant_output)); + output[index] = static_cast(quant_output_clamped); + } + } +} + +template +void PortableApplyTanhImpl(const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output) { + using FX = gemmlowp::FixedPoint; + using F0 = gemmlowp::FixedPoint; + for (int batch = 0; batch < n_batch; ++batch) { + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + FX tanh_input = FX::FromRaw(input[index]); + F0 tanh_output = gemmlowp::tanh(tanh_input); + output[index] = tanh_output.raw(); + } + } +} + +void PortableApplyTanh(int32_t integer_bits, const int16_t* input, + int32_t n_batch, int32_t n_input, int16_t* output) { + assert(integer_bits <= 6); +#define DISPATCH_TANH(i) \ + case i: \ + PortableApplyTanhImpl(input, n_batch, n_input, output); \ + break; + switch (integer_bits) { + DISPATCH_TANH(0); + DISPATCH_TANH(1); + DISPATCH_TANH(2); + DISPATCH_TANH(3); + DISPATCH_TANH(4); + DISPATCH_TANH(5); + DISPATCH_TANH(6); + default: + return; + } +#undef DISPATCH_TANH +} + +void PortableApplyTanhFloat(const int16_t* input, int32_t n_batch, + int32_t n_input, int32_t integer_bits, + int16_t* output) { + const int32_t int16_max = std::numeric_limits::max(); + const int32_t int16_min = std::numeric_limits::min(); + const double two = 2.0; + for (int batch = 0; batch < n_batch; ++batch) { + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + const float float_input = + input[index] * std::pow(two, static_cast(integer_bits)); + const float float_output = std::tanh(float_input); + const int32_t quant_output = static_cast( + float_output * static_cast(std::pow(2, 15))); + const int32_t quant_output_clamped = + std::min(int16_max, std::max(int16_min, quant_output)); + output[index] = static_cast(quant_output_clamped); + } + } +} + +void PortableCwiseMul(const int16_t* input_1, const int16_t* input_2, + int n_batch, int n_input, int shift, int16_t* output) { + for (int batch = 0; batch < n_batch; ++batch) { + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + const int16_t a = input_1[index]; + const int16_t b = input_2[index]; + const int32_t value = static_cast(a) * static_cast(b); + output[index] = + static_cast(gemmlowp::RoundingDivideByPOT(value, shift)); + } + } +} + +void PortableCwiseMul(const int16_t* input_1, const int16_t* input_2, + int32_t multiplier, int32_t shift, int32_t n_batch, + int32_t n_input, int32_t output_zp, int8_t* output) { + for (int batch = 0; batch < n_batch; ++batch) { + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + const int16_t a = input_1[index]; + const int16_t b = input_2[index]; + int32_t value = static_cast(a) * static_cast(b); + value = MultiplyByQuantizedMultiplier(value, multiplier, shift); + value -= output_zp; + value = std::min(std::max(static_cast(-128), value), + static_cast(127)); + + output[index] = static_cast(value); + } + } +} + +void PortableCwiseAdd(const int16_t* input_1, const int16_t* input_2, + int n_batch, int n_input, int16_t* output) { + for (int batch = 0; batch < n_batch; ++batch) { + for (int i = 0; i < n_input; ++i) { + const int index = batch * n_input + i; + int32_t sum = input_1[index] + input_2[index]; + const int32_t sum_clamped = std::min(kInt16Max, std::max(kInt16Min, sum)); + output[index] = static_cast(sum_clamped); + } + } +} + +float PortableVectorVectorDotProduct(const float* vector1, const float* vector2, + int v_size) { + float result = 0.0; + for (int v = 0; v < v_size; v++) { + result += *vector1++ * *vector2++; + } + return result; +} + +namespace { +inline int32_t VectorVectorDotProduct(const int16_t* vector1, + const int16_t* vector2, int v_size) { + int32_t result = 0; + for (int v = 0; v < v_size; v++) { + result += *vector1++ * *vector2++; + } + return result; +} +} // namespace + +void PortableBatchVectorBatchVectorDotProduct(const int16_t* vector1, + const int16_t* vector2, + int v_size, int n_batch, + int32_t* result) { + for (int b = 0; b < n_batch; b++) { + result[b] = VectorVectorDotProduct(vector1, vector2, v_size); + vector1 += v_size; + vector2 += v_size; + } +} + +void PortableVectorBatchVectorCwiseProductAccumulate( + const int16_t* vector, int v_size, const int16_t* batch_vector, int n_batch, + int32_t multiplier, int shift, int16_t* result) { + for (int b = 0; b < n_batch; b++) { + for (int v = 0; v < v_size; v++) { + int32_t prod = vector[v] * *batch_vector++; + prod = MultiplyByQuantizedMultiplier(prod, multiplier, shift); + int32_t output = prod + *result; + output = std::max(std::min(static_cast(32767), output), + static_cast(-32768)); + *result++ = output; + } + } +} + +void PortableSub1Vector(const float* vector, int v_size, float* result) { + for (int v = 0; v < v_size; v++) { + *result++ = 1.0f - *vector++; + } +} + +void PortableSub1Vector(const int16_t* vector, int v_size, int16_t* result) { + static const int16_t kOne = 32767; + for (int v = 0; v < v_size; v++) { + *result++ = kOne - *vector++; + } +} + +void PortableVectorScalarMultiply(const int8_t* vector, const int v_size, + const float scale, float* result) { + for (int v = 0; v < v_size; ++v) { + *result++ = scale * *vector++; + } +} + +void PortableMeanStddevNormalization(const float* __restrict__ input_vector, + float* __restrict__ output_vector, + int v_size, int n_batch) { + for (int batch = 0; batch < n_batch; ++batch) { + float sum = 0.0f; + for (int i = 0; i < v_size; ++i) { + sum += input_vector[i]; + } + const float mean = sum / v_size; + float sum_diff_sq = 0.0f; + for (int i = 0; i < v_size; ++i) { + const float diff = input_vector[i] - mean; + sum_diff_sq += diff * diff; + } + const float variance = sum_diff_sq / v_size; + constexpr float kNormalizationConstant = 1e-8f; + const float stddev_inv = + 1.0f / std::sqrt(variance + kNormalizationConstant); + for (int i = 0; i < v_size; ++i) { + output_vector[i] = (input_vector[i] - mean) * stddev_inv; + } + input_vector += v_size; + output_vector += v_size; + } +} + +void PortableTwoGateSaturatingAdd(const int8_t* input, int8_t input_zp, + const int8_t* recurrent, int8_t recurrent_zp, + int32_t input_effective_scale_a, + int32_t input_effective_scale_b, + int32_t recurrent_effective_scale_a, + int32_t recurrent_effective_scale_b, + int32_t n_batch, int32_t n_cell, + int16_t* output) { + const int32_t int16_max = std::numeric_limits::max(); + const int32_t int16_min = std::numeric_limits::min(); + for (int i = 0; i < n_batch * n_cell; ++i) { + int32_t x = static_cast(input[i]) - static_cast(input_zp); + int32_t h = + static_cast(recurrent[i]) - static_cast(recurrent_zp); + int32_t x_scaled = MultiplyByQuantizedMultiplier(x, input_effective_scale_a, + input_effective_scale_b); + int32_t h_scaled = MultiplyByQuantizedMultiplier( + h, recurrent_effective_scale_a, recurrent_effective_scale_b); + int32_t y = h_scaled + x_scaled; + if (y > int16_max) { + y = int16_max; + } + if (y < int16_min) { + y = int16_min; + } + output[i] = static_cast(y); + } +} + +} // namespace tensor_utils +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.h new file mode 100644 index 000000000..0416db093 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils.h @@ -0,0 +1,333 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ + +#include "tensorflow/lite/kernels/internal/reference/portable_tensor_utils_impl.h" + +#if defined(_MSC_VER) +#define __restrict__ __restrict +#endif + +namespace tflite { +namespace tensor_utils { + +// Check if all entries of a vector are zero for float. +bool IsZeroVector(const float* vector, int v_size) { + return PortableIsZeroVector(vector, v_size); +} + +// Check if all entries of a vector are zero for int8_t. +bool IsZeroVector(const int8_t* vector, int v_size) { + return PortableIsZeroVector(vector, v_size); +} + +void SymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float* min, float* max, + float* scaling_factor) { + PortableSymmetricQuantizeFloats(values, size, quantized_values, min, max, + scaling_factor); +} + +void SymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float min_value, + float max_value, float* scaling_factor) { + PortableSymmetricQuantizeFloats(values, size, quantized_values, min_value, + max_value, scaling_factor); +} + +void AsymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float* scaling_factor, + int32_t* offset) { + PortableAsymmetricQuantizeFloats(values, size, quantized_values, + scaling_factor, offset); +} + +void MatrixBatchVectorMultiplyAccumulate(const float* matrix, int m_rows, + int m_cols, const float* vector, + int n_batch, float* result) { + PortableMatrixBatchVectorMultiplyAccumulate(matrix, m_rows, m_cols, vector, + n_batch, result); +} + +void MatrixBatchVectorMultiplyAccumulate(const int8_t* __restrict__ matrix, + const int m_rows, const int m_cols, + const int8_t* __restrict__ vector, + const float* scaling_factors, + int n_batch, + float* __restrict__ result) { + PortableMatrixBatchVectorMultiplyAccumulate(matrix, m_rows, m_cols, vector, + scaling_factors, n_batch, result); +} + +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float* scaling_factors, + int n_batch, float* __restrict__ result, const float* per_channel_scale, + const int32_t* input_offset, int32_t* scratch, int32_t* row_sums, + bool* compute_row_sums, CpuBackendContext* context) { + PortableMatrixBatchVectorMultiplyAccumulate( + matrix, m_rows, m_cols, vectors, scaling_factors, n_batch, result, + per_channel_scale, input_offset, scratch, row_sums, compute_row_sums, + context); +} + +void MatrixBatchVectorMultiplyAccumulate(const int8_t* __restrict__ matrix, + const int m_rows, const int m_cols, + const int8_t* __restrict__ vector, + const float* scaling_factors, + int n_batch, int32_t* scratch, + float* __restrict__ result, + CpuBackendContext* context) { + PortableMatrixBatchVectorMultiplyAccumulate(matrix, m_rows, m_cols, vector, + scaling_factors, n_batch, result); +} + +void SparseMatrixBatchVectorMultiplyAccumulate1x4( + const float* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const float* __restrict__ vector, int n_batch, float* __restrict__ result) { + PortableSparseMatrixBatchVectorMultiplyAccumulate1x4( + matrix, segments, indices, m_rows, m_cols, vector, n_batch, result); +} + +void SparseMatrixBatchVectorMultiplyAccumulate( + const float* __restrict__ matrix, const uint8_t* __restrict__ ledger, + int m_rows, int m_cols, const float* __restrict__ vector, int n_batch, + float* __restrict__ result) { + PortableSparseMatrixBatchVectorMultiplyAccumulate( + matrix, ledger, m_rows, m_cols, vector, n_batch, result); +} + +void SparseMatrixBatchVectorMultiplyAccumulate1x16( + const int8_t* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const int8_t* __restrict__ vector, const int32_t* __restrict__ bias_vector, + int n_batch, const int32_t input_offset, const int32_t output_multiplier, + const int32_t output_shift, const int32_t output_offset, + const int32_t output_activation_min, const int32_t output_activation_max, + + int8_t* __restrict__ result) { + PortableSparseMatrixBatchVectorMultiplyAccumulate1x16( + matrix, segments, indices, m_rows, m_cols, vector, bias_vector, n_batch, + input_offset, output_multiplier, output_shift, output_offset, + output_activation_min, output_activation_max, result); +} + +void SparseMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const uint8_t* ledger, const int m_rows, + const int m_cols, const int8_t* __restrict__ vectors, + const float* scaling_factors, int n_batch, float* __restrict__ result) { + PortableSparseMatrixBatchVectorMultiplyAccumulate( + matrix, ledger, m_rows, m_cols, vectors, scaling_factors, n_batch, + result); +} + +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int16_t* output, CpuBackendContext* context) { + PortableMatrixBatchVectorMultiplyAccumulate( + input, bias, input_to_gate_weights, multiplier, shift, n_batch, n_input, + n_output, output_zp, scratch, output, context); +} + +void MatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int8_t* output, CpuBackendContext* context) { + PortableMatrixBatchVectorMultiplyAccumulate( + input, bias, input_to_gate_weights, multiplier, shift, n_batch, n_input, + n_output, output_zp, scratch, output, context); +} + +void MatrixScalarMultiplyAccumulate(const int8_t* matrix, int32_t scalar, + int32_t n_row, int32_t n_col, + int32_t* output) { + PortableMatrixScalarMultiplyAccumulate(matrix, scalar, n_row, n_col, output); +} + +void MatrixBatchVectorMultiply(const int8_t* input, int32_t input_zeropoint, + const int8_t* input_to_gate_weights, + int32_t input_to_gate_effective_scale_a, + int32_t input_to_gate_effective_scale_b, + int32_t n_batch, int32_t n_input, int32_t n_cell, + int8_t* gate_output, int8_t gate_output_zp) { + PortableMatrixBatchVectorMultiply( + input, input_zeropoint, input_to_gate_weights, + input_to_gate_effective_scale_a, input_to_gate_effective_scale_b, n_batch, + n_input, n_cell, gate_output, gate_output_zp); +} + +void MatrixBatchVectorMultiply(const int16_t* hidden, + const int8_t* hidden_to_output_weights, + int32_t proj_effective_scale_a, + int32_t proj_effective_scale_b, + const int32_t* gate_bias, int32_t n_batch, + int32_t n_hidden, int32_t n_output, + int32_t output_zp, int8_t* proj_output) { + PortableMatrixBatchVectorMultiply(hidden, hidden_to_output_weights, + proj_effective_scale_a, + proj_effective_scale_b, gate_bias, n_batch, + n_hidden, n_output, output_zp, proj_output); +} + +void ApplyLayerNorm(const int16_t* input, const int16_t* layer_norm_weights, + const int32_t* bias, int32_t layer_norm_scale_a, + int32_t layer_norm_scale_b, int32_t variance_limit, + int n_batch, int n_input, int16_t* output) { + PortableApplyLayerNorm(input, layer_norm_weights, bias, layer_norm_scale_a, + layer_norm_scale_b, variance_limit, n_batch, n_input, + output); +} + +void ApplyLayerNormFloat(const int16_t* input, + const int16_t* layer_norm_weights, + int32_t layer_norm_scale_a, int32_t layer_norm_scale_b, + const int32_t* bias, int n_batch, int n_input, + int16_t* output) { + PortableApplyLayerNormFloat(input, layer_norm_weights, layer_norm_scale_a, + layer_norm_scale_b, bias, n_batch, n_input, + output); +} + +void ApplySigmoid(const int16_t* input, int32_t n_batch, int32_t n_input, + int16_t* output) { + PortableApplySigmoid(input, n_batch, n_input, output); +} + +void ApplySigmoidFloat(const int16_t* input, int32_t n_batch, int32_t n_input, + int16_t* output) { + PortableApplySigmoidFloat(input, n_batch, n_input, output); +} + +void ApplyTanh(int32_t integer_bits, const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output) { + PortableApplyTanh(integer_bits, input, n_batch, n_input, output); +} + +void ApplyTanhFloat(const int16_t* input, int32_t n_batch, int32_t n_input, + int32_t integer_bits, int16_t* output) { + PortableApplyTanhFloat(input, n_batch, n_input, integer_bits, output); +} + +void CwiseMul(const int16_t* input_1, const int16_t* input_2, int n_batch, + int n_input, int shift, int16_t* output) { + PortableCwiseMul(input_1, input_2, n_batch, n_input, shift, output); +} + +void CwiseMul(const int16_t* input_1, const int16_t* input_2, + int32_t multiplier, int32_t shift, int32_t n_batch, + int32_t n_input, int32_t output_zp, int8_t* output) { + PortableCwiseMul(input_1, input_2, multiplier, shift, n_batch, n_input, + output_zp, output); +} + +void CwiseAdd(const int16_t* input_1, const int16_t* input_2, int n_batch, + int n_input, int16_t* output) { + PortableCwiseAdd(input_1, input_2, n_batch, n_input, output); +} + +void CwiseClipping(float* vector, const int v_size, + const float clipping_value) { + PortableCwiseClipping(vector, v_size, clipping_value); +} + +void CwiseClipping(int16_t* vector, const int v_size, + const int16_t clipping_value) { + PortableCwiseClipping(vector, v_size, clipping_value); +} + +void CwiseClipping(int8_t* vector, const int v_size, + const int8_t clipping_value) { + PortableCwiseClipping(vector, v_size, clipping_value); +} + +void VectorBatchVectorCwiseProductAccumulate(const int16_t* vector, int v_size, + const int16_t* batch_vector, + int n_batch, int32_t multiplier, + int shift, int16_t* result) { + PortableVectorBatchVectorCwiseProductAccumulate( + vector, v_size, batch_vector, n_batch, multiplier, shift, result); +} + +float VectorVectorDotProduct(const float* vector1, const float* vector2, + int v_size) { + return PortableVectorVectorDotProduct(vector1, vector2, v_size); +} + +void BatchVectorBatchVectorDotProduct(const int16_t* vector1, + const int16_t* vector2, int v_size, + int n_batch, int32_t* result) { + PortableBatchVectorBatchVectorDotProduct(vector1, vector2, v_size, n_batch, + result); +} + +void Sub1Vector(const float* vector, int v_size, float* result) { + PortableSub1Vector(vector, v_size, result); +} + +void Sub1Vector(const int16_t* vector, int v_size, int16_t* result) { + PortableSub1Vector(vector, v_size, result); +} + +// Multiply all elements of vector with a scalar. +void VectorScalarMultiply(const int8_t* vector, int v_size, float scale, + float* result) { + PortableVectorScalarMultiply(vector, v_size, scale, result); +} + +void ReductionSumVector(const float* input_vector, float* output_vector, + int output_size, int reduction_size) { + PortableReductionSumVector(input_vector, output_vector, output_size, + reduction_size); +} + +void ReductionSumVector(const int32_t* input_vector, int32_t* output_vector, + int output_size, int reduction_size) { + PortableReductionSumVector(input_vector, output_vector, output_size, + reduction_size); +} + +void ReductionSumVector(const int8_t* input_vector, int32_t* output_vector, + int output_size, int reduction_size) { + PortableReductionSumVector(input_vector, output_vector, output_size, + reduction_size); +} + +void MeanStddevNormalization(const float* input_vector, float* output_vector, + int v_size, int n_batch) { + PortableMeanStddevNormalization(input_vector, output_vector, v_size, n_batch); +} + +void TwoGateSaturatingAdd(const int8_t* input, int8_t input_zp, + const int8_t* recurrent, int8_t recurrent_zp, + int32_t input_effective_scale_a, + int32_t input_effective_scale_b, + int32_t recurrent_effective_scale_a, + int32_t recurrent_effective_scale_b, int32_t n_batch, + int32_t n_cell, int16_t* output) { + PortableTwoGateSaturatingAdd( + input, input_zp, recurrent, recurrent_zp, input_effective_scale_a, + input_effective_scale_b, recurrent_effective_scale_a, + recurrent_effective_scale_b, n_batch, n_cell, output); +} + +} // namespace tensor_utils +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils_impl.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils_impl.h new file mode 100644 index 000000000..6c404d5ec --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/portable_tensor_utils_impl.h @@ -0,0 +1,244 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_IMPL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_IMPL_H_ + +#include +#include + +#if defined(_MSC_VER) +#define __restrict__ __restrict +#endif + +namespace tflite { + +// Not all backends support CpuBackendContext usage, so forward declare to avoid +// pulling in its implementation. +class CpuBackendContext; + +namespace tensor_utils { + +template +bool PortableIsZeroVector(const T* vector, int v_size) { + for (int i = 0; i < v_size; ++i) { + if (vector[i] != 0) { + return false; + } + } + return true; +} + +void PortableSymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float* min_value, + float* max_value, float* scaling_factor); + +void PortableSymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, float min_value, + float max_value, float* scaling_factor); + +void PortableAsymmetricQuantizeFloats(const float* values, const int size, + int8_t* quantized_values, + float* scaling_factor, int32_t* offset); + +// Multiply a matrix by a batch vector, and store results in a batch-size +// vector. +void PortableMatrixBatchVectorMultiplyAccumulate(const float* matrix, + int m_rows, int m_cols, + const float* vector, + int n_batch, float* result); + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float* scaling_factors, + int n_batch, float* __restrict__ result); + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vectors, const float* scaling_factors, + int n_batch, float* __restrict__ result, const float* per_channel_scale, + const int32_t* input_offset, int32_t* scratch, int32_t* row_sums, + bool* compute_row_sums, CpuBackendContext* context); + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const int m_rows, const int m_cols, + const int8_t* __restrict__ vector, const float* scaling_factors, + int n_batch, int32_t* scratch, float* __restrict__ result, + CpuBackendContext* context); + +void PortableSparseMatrixBatchVectorMultiplyAccumulate1x4( + const float* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const float* __restrict__ vector, int n_batch, float* __restrict__ result); + +void PortableSparseMatrixBatchVectorMultiplyAccumulate( + const float* __restrict__ matrix, const uint8_t* __restrict__ ledger, + int m_rows, int m_cols, const float* __restrict__ vector, int n_batch, + float* __restrict__ result); + +void PortableSparseMatrixBatchVectorMultiplyAccumulate1x16( + const int8_t* __restrict__ matrix, const int32_t* __restrict__ segments, + const int32_t* __restrict__ indices, int m_rows, int m_cols, + const int8_t* __restrict__ vector, const int32_t* __restrict__ bias_vector, + int n_batch, const int32_t input_offset, const int32_t output_multiplier, + const int32_t output_shift, const int32_t output_offset, + const int32_t output_activation_min, const int32_t output_activation_max, + int8_t* __restrict__ result); + +void PortableSparseMatrixBatchVectorMultiplyAccumulate( + const int8_t* __restrict__ matrix, const uint8_t* ledger, const int m_rows, + const int m_cols, const int8_t* __restrict__ vectors, + const float* scaling_factors, int n_batch, float* __restrict__ result); + +// Dot product of two vectors. +float PortableVectorVectorDotProduct(const float* vector1, const float* vector2, + int v_size); + +void PortableBatchVectorBatchVectorDotProduct(const int16_t* vector1, + const int16_t* vector2, + int v_size, int n_batch, + int32_t* result); + +void PortableVectorBatchVectorCwiseProductAccumulate( + const int16_t* vector, int v_size, const int16_t* batch_vector, int n_batch, + int32_t multiplier, int shift, int16_t* result); + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int16_t* output, CpuBackendContext* context); + +void PortableMatrixBatchVectorMultiplyAccumulate( + const int8_t* input, const int32_t* bias, + const int8_t* input_to_gate_weights, int32_t multiplier, int32_t shift, + int32_t n_batch, int32_t n_input, int32_t n_output, int32_t output_zp, + int32_t* scratch, int8_t* output, CpuBackendContext* context); + +void PortableMatrixBatchVectorMultiply(const int8_t* input, + int32_t input_zeropoint, + const int8_t* input_to_gate_weights, + int32_t input_to_gate_effective_scale_a, + int32_t input_to_gate_effective_scale_b, + int32_t n_batch, int32_t n_input, + int32_t n_cell, int8_t* gate_output, + int8_t gate_output_zp); + +void PortableMatrixBatchVectorMultiply( + const int16_t* hidden, const int8_t* hidden_to_output_weights, + int32_t proj_effective_scale_a, int32_t proj_effective_scale_b, + const int32_t* gate_bias, int32_t n_batch, int32_t n_hidden, + int32_t n_output, int32_t output_zp, int8_t* proj_output); + +void PortableMatrixScalarMultiplyAccumulate(const int8_t* matrix, + int32_t scalar, int32_t n_row, + int32_t n_col, int32_t* output); + +void PortableApplyLayerNorm(const int16_t* input, + const int16_t* layer_norm_weights, + const int32_t* bias, int32_t layer_norm_scale_a, + int32_t layer_norm_scale_b, int32_t variance_limit, + int n_batch, int n_input, int16_t* output); + +void PortableApplyLayerNormFloat(const int16_t* input, + const int16_t* layer_norm_weights, + int32_t layer_norm_scale_a, + int32_t layer_norm_scale_b, + const int32_t* bias, int n_batch, int n_input, + int16_t* output); + +void PortableApplySigmoid(const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output); + +void PortableApplySigmoidFloat(const int16_t* input, int32_t n_batch, + int32_t n_input, int16_t* output); + +void PortableApplyTanh(int32_t integer_bits, const int16_t* input, + int32_t n_batch, int32_t n_input, int16_t* output); + +void PortableApplyTanhFloat(const int16_t* input, int32_t n_batch, + int32_t n_input, int32_t integer_bits, + int16_t* output); + +void PortableCwiseMul(const int16_t* input_1, const int16_t* input_2, + int n_batch, int n_input, int shift, int16_t* output); + +void PortableCwiseMul(const int16_t* input_1, const int16_t* input_2, + int32_t multiplier, int32_t shift, int32_t n_batch, + int32_t n_input, int32_t output_zp, int8_t* output); + +void PortableCwiseAdd(const int16_t* input_1, const int16_t* input_2, + int n_batch, int n_input, int16_t* output); + +template +void PortableCwiseClipping(T* vector, const int v_size, + const T& clipping_value) { + for (int i = 0; i < v_size; i++) { + vector[i] = std::max(std::min(clipping_value, vector[i]), + static_cast(-clipping_value)); + } +} + +// Batch vector initialization with another vector. +void PortableVectorBatchVectorAssign(const float* vector, int v_size, + int n_batch, float* batch_vector); + +// Compute "1.0f - elements of vector" (used in CIFG). +void PortableSub1Vector(const float* vector, int v_size, float* result); + +void PortableSub1Vector(const int16_t* vector, int v_size, int16_t* result); + +// Multiply all elements of vector with a scalar. +void PortableVectorScalarMultiply(const int8_t* vector, int v_size, float scale, + float* result); + +// Reduce-sum on a vector: +// input_vector: pointer to input vector. +// output_vector: pointer to vector. +// output_size: output vector size. +// reduction_size: number of consecutive elements from input vector which are +// added to get one element of output. +template +void PortableReductionSumVector(const INPUT* input_vector, + OUTPUT* output_vector, int output_size, + int reduction_size) { + for (int o = 0; o < output_size; o++) { + OUTPUT result = 0; + for (int r = 0; r < reduction_size; r++) { + result += input_vector[r]; + } + output_vector[o] = result; + input_vector += reduction_size; + } +} + +// Layer norm for each batch. +void PortableMeanStddevNormalization(const float* __restrict__ input_vector, + float* __restrict__ output_vector, + int v_size, int n_batch); + +// Saturate Add. +void PortableTwoGateSaturatingAdd(const int8_t* input, int8_t input_zp, + const int8_t* recurrent, int8_t recurrent_zp, + int32_t input_effective_scale_a, + int32_t input_effective_scale_b, + int32_t recurrent_effective_scale_a, + int32_t recurrent_effective_scale_b, + int32_t n_batch, int32_t n_cell, + int16_t* output); + +} // namespace tensor_utils +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PORTABLE_TENSOR_UTILS_IMPL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/prelu.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/prelu.h new file mode 100644 index 000000000..aa9901d60 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/prelu.h @@ -0,0 +1,111 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PRELU_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PRELU_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +// Broadcast prelu to output_shape for quantized uint8_t/int8_t data. +template +inline void BroadcastPrelu4DSlow( + const PreluParams& params, const RuntimeShape& input_shape, + const T* input_data, const RuntimeShape& alpha_shape, const T* alpha_data, + const RuntimeShape& output_shape, T* output_data) { + TFLITE_DCHECK_LE(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(alpha_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), 4); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(input_shape, alpha_shape, &desc1, &desc2); + + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + int output_index = Offset(extended_output_shape, b, y, x, c); + int input_index = SubscriptToIndex(desc1, b, y, x, c); + const int32_t input_value = + params.input_offset + input_data[input_index]; + int32_t output_value; + if (input_value >= 0) { + output_value = MultiplyByQuantizedMultiplier( + input_value, params.output_multiplier_1, params.output_shift_1); + } else { + auto alpha_index = SubscriptToIndex(desc2, b, y, x, c); + const int32_t alpha_value = + params.alpha_offset + alpha_data[alpha_index]; + + output_value = MultiplyByQuantizedMultiplier( + input_value * alpha_value, params.output_multiplier_2, + params.output_shift_2); + } + output_value += params.output_offset; + + const int32_t quantized_min = std::numeric_limits::min(); + const int32_t quantized_max = std::numeric_limits::max(); + const int32_t clamped_output = + std::min(quantized_max, std::max(quantized_min, output_value)); + output_data[output_index] = static_cast(clamped_output); + } + } + } + } +} + +template +inline void Prelu(const PreluParams& params, const RuntimeShape& input_shape, + const T* input_data, const RuntimeShape& alpha_shape, + const T* alpha_data, const RuntimeShape& output_shape, + T* output_data) { + const int32_t quantized_min = std::numeric_limits::min(); + const int32_t quantized_max = std::numeric_limits::max(); + + const int flat_size = + MatchingElementsSize(input_shape, alpha_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const int32_t input_value = params.input_offset + input_data[i]; + int32_t output_value; + if (input_value >= 0) { + output_value = MultiplyByQuantizedMultiplier( + input_value, params.output_multiplier_1, params.output_shift_1); + } else { + const int32_t alpha_value = params.alpha_offset + alpha_data[i]; + + output_value = MultiplyByQuantizedMultiplier(input_value * alpha_value, + params.output_multiplier_2, + params.output_shift_2); + } + output_value += params.output_offset; + + const int32_t clamped_output = + std::min(quantized_max, std::max(quantized_min, output_value)); + output_data[i] = static_cast(clamped_output); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PRELU_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h new file mode 100644 index 000000000..bda27693f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h @@ -0,0 +1,140 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PROCESS_BROADCAST_SHAPES_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PROCESS_BROADCAST_SHAPES_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +// Consolidates dimensions in broadcast inputs, checks for five-fold pattern. +// +// For example, if sequence of dimensions of one input is +// ..., 1, 3, 1, 7, 9, 5,... and the other is ..., 2, 3, 1, 7, 1, 1, ... +// we can consolidate these as +// ..., 1, 3*7, 9*5, ... and 2, 3*7, 1. +// +// The category is updated in the less-frequent case of shapes that are +// not suited to a fivefold-loop broadcast. +// +// Falls back to generic pattern when it does not know how to process properly. +// +// Returns true iff there is some sort of broadcast, which includes five-fold +// patterns and falling back to generic broadcast. +inline bool ProcessBroadcastShapes(const RuntimeShape& shape0, + const RuntimeShape& shape1, + tflite::ArithmeticParams* params) { + const int dims_count = + std::max(shape0.DimensionsCount(), shape1.DimensionsCount()); + + params->broadcast_category = BroadcastableOpCategory::kGenericBroadcast; + RuntimeShape scalar_shape(dims_count, 1); + + auto extended_shape0 = RuntimeShape::ExtendedShape(dims_count, shape0); + auto extended_shape1 = RuntimeShape::ExtendedShape(dims_count, shape1); + + // Check for "exact" match, implicitly accepting any scalar shapes. + if (extended_shape0 == extended_shape1) { + params->broadcast_category = BroadcastableOpCategory::kNonBroadcast; + return false; + } + + for (int i = dims_count - 1; i >= 0; --i) { + if (extended_shape0.Dims(i) == extended_shape1.Dims(i)) { + continue; + } else if (extended_shape0.Dims(i) == 1) { + params->broadcast_category = + BroadcastableOpCategory::kFirstInputBroadcastsFast; + break; + } else if (extended_shape1.Dims(i) == 1) { + params->broadcast_category = + BroadcastableOpCategory::kSecondInputBroadcastsFast; + break; + } else { + // This case is erroneous: there is a dimension that does not match and + // is not a broadcast from one shape to the other. + params->broadcast_category = BroadcastableOpCategory::kGenericBroadcast; + return true; + } + } + + if (params->broadcast_category != + BroadcastableOpCategory::kFirstInputBroadcastsFast && + params->broadcast_category != + BroadcastableOpCategory::kSecondInputBroadcastsFast) { + // This is unreachable because at least one else clause in the above loop + // must be reached. + TFLITE_DCHECK(false); + params->broadcast_category = BroadcastableOpCategory::kNonBroadcast; + return false; + } + + // From this point it is assumed contractually that corresponding dimensions + // in shape0 and shape1 are either (a) equal or (b) one or other equals 1. + const bool swap_inputs = params->broadcast_category == + BroadcastableOpCategory::kSecondInputBroadcastsFast; + const RuntimeShape* shape_a = + swap_inputs ? &extended_shape1 : &extended_shape0; + const RuntimeShape* shape_b = + swap_inputs ? &extended_shape0 : &extended_shape1; + + int i = dims_count - 1; + params->broadcast_shape[0] = 1; + params->broadcast_shape[1] = 1; + params->broadcast_shape[2] = 1; + params->broadcast_shape[3] = 1; + params->broadcast_shape[4] = 1; + // y_0 is greedy: include dims if both or neither equal 1: in other words, + // test for equality rather than (shape_a->Dims(i) != 1). + while (i >= 0 && shape_a->Dims(i) == shape_b->Dims(i)) { + params->broadcast_shape[4] *= shape_b->Dims(i); + --i; + } + // Here either input_a or input_b has dim of 1 (if i >= 0). If it is input_b + // that has the unit dimension, the next two loops are not entered. + while (i >= 0 && shape_a->Dims(i) == 1) { + params->broadcast_shape[3] *= shape_b->Dims(i); + --i; + } + while (i >= 0 && shape_a->Dims(i) == shape_b->Dims(i)) { + params->broadcast_shape[2] *= shape_a->Dims(i); + --i; + } + // Here either input_a or input_b has dim of 1 (if i >= 0). + while (i >= 0 && shape_b->Dims(i) == 1) { + params->broadcast_shape[1] *= shape_a->Dims(i); + --i; + } + while (i >= 0 && shape_a->Dims(i) == shape_b->Dims(i)) { + params->broadcast_shape[0] *= shape_b->Dims(i); + --i; + } + + // Rarer case is when the broadcast dimensions cannot be handled by a fivefold + // loop. + if (i >= 0) { + params->broadcast_category = BroadcastableOpCategory::kGenericBroadcast; + } + return true; +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_PROCESS_BROADCAST_SHAPES_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/quantize.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/quantize.h new file mode 100644 index 000000000..f304b641a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/quantize.h @@ -0,0 +1,89 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_QUANTIZE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_QUANTIZE_H_ + +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +inline void AffineQuantize(const tflite::QuantizationParams& op_params, + const RuntimeShape& input_shape, + const InputT* input_data, + const RuntimeShape& output_shape, + OutputT* output_data) { + const int32_t zero_point = op_params.zero_point; + const double scale = op_params.scale; + const int flat_size = MatchingFlatSize(input_shape, output_shape); + static constexpr int32_t min_val = std::numeric_limits::min(); + static constexpr int32_t max_val = std::numeric_limits::max(); + + for (int i = 0; i < flat_size; i++) { + const InputT val = input_data[i]; + int32_t unclamped = + static_cast(TfLiteRound(val / static_cast(scale))) + + zero_point; + int32_t clamped = std::min(std::max(unclamped, min_val), max_val); + output_data[i] = clamped; + } +} + +// Quantizes per-channel. +template +inline void PerChannelQuantize( + const tflite::PerChannelQuantizationParams& op_params, + const RuntimeShape& input_shape, const InputT* input_data, + const RuntimeShape& output_shape, OutputT* output_data) { + // Ensure flat size is same. + MatchingFlatSize(input_shape, output_shape); + + const int32_t* zero_point = op_params.zero_point; + const float* scale = op_params.scale; + const int32_t quantized_dimension = op_params.quantized_dimension; + const int32_t num_dims = input_shape.DimensionsCount(); + const int32_t* dims_data = input_shape.DimsData(); + std::vector current_dim(num_dims, 0); + static constexpr int32_t min_val = std::numeric_limits::min(); + static constexpr int32_t max_val = std::numeric_limits::max(); + + do { + size_t offset = + ReducedOutputOffset(num_dims, reinterpret_cast(dims_data), + current_dim.data(), 0, nullptr); + const InputT val = input_data[offset]; + const int channel = current_dim[quantized_dimension]; + int32_t unclamped = static_cast(TfLiteRound( + val / static_cast(scale[channel]))) + + zero_point[channel]; + int32_t clamped = std::min(std::max(unclamped, min_val), max_val); + output_data[offset] = static_cast(clamped); + } while (NextIndex(num_dims, reinterpret_cast(dims_data), + current_dim.data())); +} + +} // namespace reference_ops + +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_QUANTIZE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/reduce.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/reduce.h new file mode 100644 index 000000000..e83bb7b3c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/reduce.h @@ -0,0 +1,526 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_REDUCE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_REDUCE_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/max.h" +#include "tensorflow/lite/kernels/internal/min.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/types.h" + +// Check if the reduction at index is the first one along the dimensions given +// in axis. +inline bool IsFirstReduction(const int* index, const int num_axis, + const int* axis) { + if (num_axis == 0) { + return true; + } + + TFLITE_DCHECK(index != nullptr); + TFLITE_DCHECK(axis != nullptr); + for (int axis_idx = 0; axis_idx < num_axis; ++axis_idx) { + if (index[axis[axis_idx]] != 0) { + return false; + } + } + + return true; +} + +namespace tflite { + +namespace reference_ops { + +// A generic reduce method that can be used for reduce_sum, reduce_mean, etc. +// This method iterates through input data and reduce elements along the +// dimensions given in axis. +template +inline bool Reduce(const In* input_data, const int* input_dims, + const int* output_dims, const int input_num_dims, + const int output_num_dims, const int* axis, + const int num_axis, int* input_iter, + Out reducer(Out current, const In in), Out* output_data) { + // Reset input iterator. + for (int idx = 0; idx < input_num_dims; ++idx) { + input_iter[idx] = 0; + } + // Iterate through input_data. + do { + size_t input_offset = + ReducedOutputOffset(input_num_dims, input_dims, input_iter, 0, nullptr); + size_t output_offset = ReducedOutputOffset(input_num_dims, input_dims, + input_iter, num_axis, axis); + output_data[output_offset] = + reducer(output_data[output_offset], input_data[input_offset]); + } while (NextIndex(input_num_dims, input_dims, input_iter)); + return true; +} + +// Similar to above Reduce function but takes two reducer functions. +// The 'reducer_first' is called with the first value of the reduction, +// 'reducer_next' is then called for all the others. +template +inline bool Reduce(const In* input_data, const int* input_dims, + const int* output_dims, const int input_num_dims, + const int output_num_dims, const int* axis, + const int num_axis, int* input_iter, + const std::function& reducer_first, + const std::function& reducer_next, + Out* output_data) { + // Reset input iterator. + for (int idx = 0; idx < input_num_dims; ++idx) { + input_iter[idx] = 0; + } + // Iterate through input_data. + do { + size_t input_offset = + ReducedOutputOffset(input_num_dims, input_dims, input_iter, 0, nullptr); + size_t output_offset = ReducedOutputOffset(input_num_dims, input_dims, + input_iter, num_axis, axis); + if (IsFirstReduction(input_iter, num_axis, axis)) { + output_data[output_offset] = reducer_first(input_data[input_offset]); + } else { + output_data[output_offset] = + reducer_next(output_data[output_offset], input_data[input_offset]); + } + } while (NextIndex(input_num_dims, input_dims, input_iter)); + return true; +} + +// This method parses the input 'axis' to remove duplicates and handle negative +// values, and returns a valid 'out_axis' +inline bool ResolveAxis(const int num_dims, const int* axis, + const int64_t num_axis, int* out_axis, + int* out_num_axis) { + *out_num_axis = 0; // Just in case. + // Short-circuit axis resolution for scalars; the axis will go unused. + if (num_dims == 0) { + return true; + } + // o(n^2) is fine since out_num_axis should be really small, mostly <= 4 + for (int64_t idx = 0; idx < num_axis; ++idx) { + // Handle negative index. A positive index 'p_idx' can be represented as a + // negative index 'n_idx' as: n_idx = p_idx-num_dims + // eg: For num_dims=3, [0, 1, 2] is the same as [-3, -2, -1] */ + int current = axis[idx] < 0 ? (axis[idx] + num_dims) : axis[idx]; + TFLITE_DCHECK(current >= 0 && current < num_dims); + if (current < 0 || current >= num_dims) { + return false; + } + bool is_dup = false; + for (int j = 0; j < *out_num_axis; ++j) { + if (out_axis[j] == current) { + is_dup = true; + break; + } + } + if (!is_dup) { + out_axis[*out_num_axis] = current; + *out_num_axis += 1; + } + } + return true; +} + +// This method expects that output_data has been initialized. +template +inline bool ReduceSumImpl(const In* input_data, const int* input_dims, + const int* output_dims, const int input_num_dims, + const int output_num_dims, const int* axis, + const int num_axis, int* input_iter, + Out* output_data) { + auto reducer = [](const Out current, const In in) -> Out { + const Out actual_in = static_cast(in); + return current + actual_in; + }; + return Reduce(input_data, input_dims, output_dims, input_num_dims, + output_num_dims, axis, num_axis, input_iter, reducer, + output_data); +} + +template +inline bool InitTensorDataForReduce(const int* dims, const int num_dims, + const T init_value, T* data) { + size_t num_elements = 1; + for (int idx = 0; idx < num_dims; ++idx) { + size_t current = static_cast(dims[idx]); + // Overflow prevention. + if (current > 0 && + num_elements > std::numeric_limits::max() / current) { + return false; + } + num_elements *= current; + } + for (size_t idx = 0; idx < num_elements; ++idx) { + data[idx] = init_value; + } + return true; +} + +// Computes the generic value (i.e., sum/max/min/prod) of elements across +// dimensions given in axis. It needs to pass in init_value and reducer. +template +inline bool ReduceGeneric(const T* input_data, const int* input_dims, + const int input_num_dims, T* output_data, + const int* output_dims, const int output_num_dims, + const int* axis, const int64_t num_axis_dimensions, + bool keep_dims, int* temp_index, int* resolved_axis, + T init_value, + T reducer(const T current, const T in)) { + // Reset output data. + if (!InitTensorDataForReduce(output_dims, output_num_dims, init_value, + output_data)) { + return false; + } + + // Return early when input shape has zero dim. This is done after initializing + // data for output tensor because there are cases that the input tensor is + // empty but output tensor is not. In that case, output tensor should be + // filled with init_value. + for (int i = 0; i < input_num_dims; ++i) { + if (input_dims[i] == 0) return true; + } + + // Resolve axis. + int num_resolved_axis = 0; + if (!ResolveAxis(input_num_dims, axis, num_axis_dimensions, resolved_axis, + &num_resolved_axis)) { + return false; + } + + return Reduce(input_data, input_dims, output_dims, input_num_dims, + output_num_dims, resolved_axis, num_resolved_axis, + temp_index, reducer, output_data); +} + +// Computes the mean of elements across dimensions given in axis. +// It does so in two stages, first calculates the sum of elements along the axis +// then divides it by the number of element in axis. +template +inline bool Mean(const T* input_data, const int* input_dims, + const int input_num_dims, T* output_data, + const int* output_dims, const int output_num_dims, + const int* axis, const int num_axis_dimensions, bool keep_dims, + int* temp_index, int* resolved_axis, U* temp_sum) { + ruy::profiler::ScopeLabel label("Mean"); + // Reset output data. + size_t num_outputs = 1; + for (int idx = 0; idx < output_num_dims; ++idx) { + size_t current = static_cast(output_dims[idx]); + // Overflow prevention. + if (num_outputs > std::numeric_limits::max() / current) { + return false; + } + num_outputs *= current; + } + for (size_t idx = 0; idx < num_outputs; ++idx) { + output_data[idx] = T(); + temp_sum[idx] = U(); + } + + // Resolve axis. + int num_resolved_axis = 0; + if (!ResolveAxis(input_num_dims, axis, num_axis_dimensions, resolved_axis, + &num_resolved_axis)) { + return false; + } + + if (!ReduceSumImpl(input_data, input_dims, output_dims, input_num_dims, + output_num_dims, resolved_axis, num_resolved_axis, + temp_index, temp_sum)) { + return false; + } + + // Calculate mean by dividing output_data by num of aggregated element. + size_t num_elements_in_axis = 1; + for (int idx = 0; idx < num_resolved_axis; ++idx) { + size_t current = static_cast(input_dims[resolved_axis[idx]]); + // Overflow prevention. + if (current > (std::numeric_limits::max() / num_elements_in_axis)) { + return false; + } + num_elements_in_axis *= current; + } + + if (num_elements_in_axis > 0) { + for (size_t idx = 0; idx < num_outputs; ++idx) { + output_data[idx] = + static_cast(temp_sum[idx] / static_cast(num_elements_in_axis)); + } + } + return true; +} + +template +inline void Mean(const tflite::MeanParams& op_params, + const RuntimeShape& unextended_input_shape, + const T* input_data, + const RuntimeShape& unextended_output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("Mean4D"); + + // Current implementation only supports dimension equals 4 and simultaneous + // reduction over width and height. + TFLITE_CHECK_EQ(unextended_input_shape.DimensionsCount(), 4); + TFLITE_CHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + const int output_batch = output_shape.Dims(0); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int output_depth = output_shape.Dims(3); + + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + + TFLITE_CHECK_EQ(op_params.axis_count, 2); + TFLITE_CHECK((op_params.axis[0] == 1 && op_params.axis[1] == 2) || + (op_params.axis[0] == 2 && op_params.axis[1] == 1)); + TFLITE_CHECK_EQ(output_height, 1); + TFLITE_CHECK_EQ(output_width, 1); + + for (int out_b = 0; out_b < output_batch; ++out_b) { + for (int out_d = 0; out_d < output_depth; ++out_d) { + float value = 0; + for (int in_h = 0; in_h < input_height; ++in_h) { + for (int in_w = 0; in_w < input_width; ++in_w) { + value += input_data[Offset(input_shape, out_b, in_h, in_w, out_d)]; + } + } + output_data[Offset(output_shape, out_b, 0, 0, out_d)] = + value / (input_width * input_height); + } + } +} + +inline void Mean(const tflite::MeanParams& op_params, + const RuntimeShape& unextended_input_shape, + const uint8_t* input_data, int32_t input_zero_point, + float input_scale, const RuntimeShape& unextended_output_shape, + uint8_t* output_data, int32_t output_zero_point, + float output_scale) { + ruy::profiler::ScopeLabel label("Mean4D/Uint8"); + + // Current implementation only supports dimension equals 4 and simultaneous + // reduction over width and height. + TFLITE_CHECK_EQ(unextended_input_shape.DimensionsCount(), 4); + TFLITE_CHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + const int output_batch = output_shape.Dims(0); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int output_depth = output_shape.Dims(3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const float num_elements_in_axis = input_width * input_height; + + TFLITE_CHECK_EQ(op_params.axis_count, 2); + TFLITE_CHECK((op_params.axis[0] == 1 && op_params.axis[1] == 2) || + (op_params.axis[0] == 2 && op_params.axis[1] == 1)); + TFLITE_CHECK_EQ(output_height, 1); + TFLITE_CHECK_EQ(output_width, 1); + + constexpr int32_t kMinValue = std::numeric_limits::min(); + constexpr int32_t kMaxValue = std::numeric_limits::max(); + + float temp = input_zero_point * input_scale / output_scale; + temp = temp > 0 ? temp + 0.5f : temp - 0.5f; + int32_t bias = output_zero_point - static_cast(temp); + double real_scale = + static_cast(input_scale / (num_elements_in_axis * output_scale)); + + int32_t multiplier; + int shift; + QuantizeMultiplier(real_scale, &multiplier, &shift); + for (int out_b = 0; out_b < output_batch; ++out_b) { + for (int out_d = 0; out_d < output_depth; ++out_d) { + int32_t acc = 0; + for (int in_h = 0; in_h < input_height; ++in_h) { + for (int in_w = 0; in_w < input_width; ++in_w) { + acc += input_data[Offset(input_shape, out_b, in_h, in_w, out_d)]; + } + } + acc = MultiplyByQuantizedMultiplier(acc, multiplier, shift); + acc += bias; + acc = std::min(std::max(acc, kMinValue), kMaxValue); + output_data[Offset(output_shape, out_b, 0, 0, out_d)] = + static_cast(acc); + } + } +} + +// Computes the mean of elements across dimensions given in axis. +// It does so in two stages, first calculates the sum of elements along the axis +// then divides it by the number of element in axis for quantized values. +template +inline bool QuantizedMeanOrSum(const T* input_data, int32_t input_zero_point, + float input_scale, const int* input_dims, + const int input_num_dims, T* output_data, + int32_t output_zero_point, float output_scale, + const int* output_dims, + const int output_num_dims, const int* axis, + const int num_axis_dimensions, bool keep_dims, + int* temp_index, int* resolved_axis, U* temp_sum, + bool compute_sum) { + const bool uint8_case = std::is_same::value; + const bool int16_case = std::is_same::value; + if (uint8_case) { + ruy::profiler::ScopeLabel label(compute_sum ? "Sum/Uint8" : "Mean/Uint8"); + } else if (int16_case) { + ruy::profiler::ScopeLabel label(compute_sum ? "Sum/Int16" : "Mean/Int16"); + } else { + ruy::profiler::ScopeLabel label(compute_sum ? "Sum/Int8" : "Mean/Int8"); + } + // Reset output data. + size_t num_outputs = 1; + for (int idx = 0; idx < output_num_dims; ++idx) { + size_t current = static_cast(output_dims[idx]); + // Overflow prevention. + if (num_outputs > std::numeric_limits::max() / current) { + return false; + } + num_outputs *= current; + } + for (size_t idx = 0; idx < num_outputs; ++idx) { + output_data[idx] = T(); + temp_sum[idx] = U(); + } + + // Return early when input shape has zero dim. This is done after initializing + // data for output tensor because there are cases that the input tensor is + // empty but output tensor is not. In that case, output tensor should be + // filled with init_value. + for (int i = 0; i < input_num_dims; ++i) { + if (input_dims[i] == 0) return true; + } + + // Resolve axis. + int num_resolved_axis = 0; + if (!ResolveAxis(input_num_dims, axis, num_axis_dimensions, resolved_axis, + &num_resolved_axis)) { + return false; + } + + if (!ReduceSumImpl(input_data, input_dims, output_dims, input_num_dims, + output_num_dims, resolved_axis, num_resolved_axis, + temp_index, temp_sum)) { + return false; + } + + // Calculate mean by dividing output_data by num of aggregated element. + size_t num_elements_in_axis = 1; + for (int idx = 0; idx < num_resolved_axis; ++idx) { + size_t current = static_cast(input_dims[resolved_axis[idx]]); + // Overflow prevention. + if (current > (std::numeric_limits::max() / num_elements_in_axis)) { + return false; + } + num_elements_in_axis *= current; + } + + if (num_elements_in_axis > 0) { + const float scale = input_scale / output_scale; + if (compute_sum) { + // TODO(b/116341117): Eliminate float and do this completely in 8bit. + const float bias = -input_zero_point * scale * num_elements_in_axis; + for (size_t idx = 0; idx < num_outputs; ++idx) { + const U value = + static_cast(TfLiteRound(temp_sum[idx] * scale + bias)) + + output_zero_point; + output_data[idx] = static_cast(value); + } + } else { + const float bias = -input_zero_point * scale; + for (size_t idx = 0; idx < num_outputs; ++idx) { + float float_mean = static_cast(temp_sum[idx]) / + static_cast(num_elements_in_axis); + float result = TfLiteMin( + TfLiteRound(float_mean * scale + bias) + output_zero_point, + static_cast(std::numeric_limits::max())); + result = TfLiteMax(result, + static_cast(std::numeric_limits::min())); + output_data[idx] = static_cast(result); + } + } + } + return true; +} + +template +inline bool QuantizedReduceProd(const T* input_data, int32_t input_zero_point, + const RuntimeShape& input_shape, T* output_data, + int32_t output_zero_point, + const RuntimeShape& output_shape, + const int* axis, + const int64_t num_axis_dimensions, + bool keep_dims, int* temp_index, + int* resolved_axis, int32_t* temp_prod, + int32_t scaling_multiplier, int scaling_shift) { + const int32_t kMinValue = std::numeric_limits::min(); + const int32_t kMaxValue = std::numeric_limits::max(); + + // Resolve axis. + int num_resolved_axis = 0; + if (!ResolveAxis(input_shape.DimensionsCount(), axis, num_axis_dimensions, + resolved_axis, &num_resolved_axis)) { + return false; + } + + // Calculate the reduced product by rescaling each multiplication step to + // avoid an overflow. + auto reducer_first = [&](T in) -> int32_t { return in - input_zero_point; }; + + auto reducer_next = [&](int32_t current, T in) -> int32_t { + const int64_t result = + static_cast(current) * (in - input_zero_point); + return MultiplyByQuantizedMultiplier(result, scaling_multiplier, + scaling_shift); + }; + + if (!Reduce( + input_data, input_shape.DimsData(), output_shape.DimsData(), + input_shape.DimensionsCount(), output_shape.DimensionsCount(), + resolved_axis, num_resolved_axis, temp_index, reducer_first, + reducer_next, temp_prod)) { + return false; + } + + for (int i = 0; i < output_shape.FlatSize(); i++) { + int32_t result = + MultiplyByQuantizedMultiplier(static_cast(temp_prod[i]), + scaling_multiplier, scaling_shift) + + output_zero_point; + result = std::min(std::max(result, kMinValue), kMaxValue); + output_data[i] = static_cast(result); + } + + return true; +} + +} // namespace reference_ops + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_REDUCE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/requantize.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/requantize.h new file mode 100644 index 000000000..83879fbb5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/requantize.h @@ -0,0 +1,70 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_REQUANTIZE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_REQUANTIZE_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +inline void Requantize(const input_type* input_data, int32_t size, + int32_t effective_scale_multiplier, + int32_t effective_scale_shift, int32_t input_zeropoint, + int32_t output_zeropoint, output_type* output_data) { + ruy::profiler::ScopeLabel label("Requantize"); + const bool same_scale = + (effective_scale_multiplier == 1 << 30 && effective_scale_shift == 1); + if (same_scale) { + const bool mixed_type_int8_uint8 = + std::is_same::value && + std::is_same::value; + const bool mixed_type_uint8_int8 = + std::is_same::value && + std::is_same::value; + const int32_t zero_point_diff = input_zeropoint - output_zeropoint; + // Fast path to do requantization for the case when just a shift of 128 is + // needed. + if ((mixed_type_int8_uint8 && zero_point_diff == -128) || + (mixed_type_uint8_int8 && zero_point_diff == 128)) { + for (int i = 0; i < size; ++i) { + output_data[i] = input_data[i] ^ 0x80; + } + return; + } + } + static constexpr int32_t kMinOutput = std::numeric_limits::min(); + static constexpr int32_t kMaxOutput = std::numeric_limits::max(); + for (int i = 0; i < size; ++i) { + const int32_t input = input_data[i] - input_zeropoint; + const int32_t output = + MultiplyByQuantizedMultiplier(input, effective_scale_multiplier, + effective_scale_shift) + + output_zeropoint; + const int32_t clamped_output = + std::max(std::min(output, kMaxOutput), kMinOutput); + output_data[i] = static_cast(clamped_output); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_REQUANTIZE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/resize_bilinear.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/resize_bilinear.h new file mode 100644 index 000000000..b5edadb98 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/resize_bilinear.h @@ -0,0 +1,228 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_RESIZE_BILINEAR_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_RESIZE_BILINEAR_H_ + +#include +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +inline void ComputeInterpolationValues(const float value, const float scale, + const bool half_pixel_centers, + int32_t input_size, float* scaled_value, + int32_t* lower_bound, + int32_t* upper_bound) { + if (half_pixel_centers) { + *scaled_value = (value + 0.5f) * scale - 0.5f; + } else { + *scaled_value = value * scale; + } + float scaled_value_floor = std::floor(*scaled_value); + *lower_bound = std::max(static_cast(scaled_value_floor), + static_cast(0)); + *upper_bound = + std::min(static_cast(std::ceil(*scaled_value)), input_size - 1); +} + +template +inline void ResizeBilinear(const tflite::ResizeBilinearParams& op_params, + const RuntimeShape& unextended_input_shape, + const T* input_data, + const RuntimeShape& unextended_output_size_shape, + const int32_t* output_size_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + // If half_pixel_centers is True, align_corners must be False. + TFLITE_DCHECK(!op_params.half_pixel_centers || !op_params.align_corners); + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_size_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_size_shape = + RuntimeShape::ExtendedShape(4, unextended_output_size_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + int32_t batches = MatchingDim(input_shape, 0, output_shape, 0); + int32_t input_height = input_shape.Dims(1); + int32_t input_width = input_shape.Dims(2); + int32_t depth = MatchingDim(input_shape, 3, output_shape, 3); + + TFLITE_DCHECK_EQ(output_size_shape.Dims(0), 1); + TFLITE_DCHECK_EQ(output_size_shape.Dims(1), 1); + TFLITE_DCHECK_EQ(output_size_shape.Dims(2), 1); + TFLITE_DCHECK_EQ(output_size_shape.Dims(3), 2); + int32_t output_height = + output_size_data[Offset(output_size_shape, 0, 0, 0, 0)]; + int32_t output_width = + output_size_data[Offset(output_size_shape, 0, 0, 0, 1)]; + + float height_scale = static_cast(input_height) / output_height; + float width_scale = static_cast(input_width) / output_width; + if (op_params.align_corners && output_height > 1) { + height_scale = static_cast(input_height - 1) / (output_height - 1); + } + if (op_params.align_corners && output_width > 1) { + width_scale = static_cast(input_width - 1) / (output_width - 1); + } + const float rounding_offset = std::numeric_limits::is_integer ? .5f : .0f; + + for (int b = 0; b < batches; ++b) { + for (int y = 0; y < output_height; ++y) { + float input_y; + int32_t y0, y1; + ComputeInterpolationValues(y, height_scale, op_params.half_pixel_centers, + input_height, &input_y, &y0, &y1); + for (int x = 0; x < output_width; ++x) { + float input_x; + int32_t x0, x1; + ComputeInterpolationValues(x, width_scale, op_params.half_pixel_centers, + input_width, &input_x, &x0, &x1); + for (int c = 0; c < depth; ++c) { + T interpolation = + static_cast(input_data[Offset(input_shape, b, y0, x0, c)] * + (1 - (input_y - y0)) * (1 - (input_x - x0)) + + input_data[Offset(input_shape, b, y1, x0, c)] * + (input_y - y0) * (1 - (input_x - x0)) + + input_data[Offset(input_shape, b, y0, x1, c)] * + (1 - (input_y - y0)) * (input_x - x0) + + input_data[Offset(input_shape, b, y1, x1, c)] * + (input_y - y0) * (input_x - x0) + + rounding_offset); + output_data[Offset(output_shape, b, y, x, c)] = interpolation; + } + } + } + } +} + +inline void ComputeInterpolationValuesInteger( + const int32_t value, const int32_t scale_10, const bool half_pixel_centers, + int32_t input_size, int32_t* scaled_value, int32_t* lower_bound, + int32_t* upper_bound) { + if (half_pixel_centers) { + *scaled_value = value * scale_10 + scale_10 / 2 - (1 << 9); + } else { + *scaled_value = value * scale_10; + } + constexpr int32_t zero = 0; + *lower_bound = std::max(*scaled_value / (1 << 10), zero); + *upper_bound = + std::min((*scaled_value + (1 << 10) - 1) / (1 << 10), input_size - 1); +} + +// Same as above but doesn't use any floating-point for the resize +template +inline void ResizeBilinearInteger( + const tflite::ResizeBilinearParams& op_params, + const RuntimeShape& unextended_input_shape, const T* input_data, + const RuntimeShape& unextended_output_size_shape, + const int32_t* output_size_data, + const RuntimeShape& unextended_output_shape, T* output_data) { + // If half_pixel_centers is True, align_corners must be False. + TFLITE_DCHECK(!op_params.half_pixel_centers || !op_params.align_corners); + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_size_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_size_shape = + RuntimeShape::ExtendedShape(4, unextended_output_size_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + const int32_t batches = MatchingDim(input_shape, 0, output_shape, 0); + const int32_t input_height = input_shape.Dims(1); + const int32_t input_width = input_shape.Dims(2); + const int32_t depth = MatchingDim(input_shape, 3, output_shape, 3); + + TFLITE_DCHECK_EQ(output_size_shape.Dims(0), 1); + TFLITE_DCHECK_EQ(output_size_shape.Dims(1), 1); + TFLITE_DCHECK_EQ(output_size_shape.Dims(2), 1); + TFLITE_DCHECK_EQ(output_size_shape.Dims(3), 2); + const int32_t output_height = + output_size_data[Offset(output_size_shape, 0, 0, 0, 0)]; + const int32_t output_width = + output_size_data[Offset(output_size_shape, 0, 0, 0, 1)]; + + int32_t height_scale_10 = + ((1 << 10) * input_height + output_height / 2) / output_height; + int32_t width_scale_10 = + ((1 << 10) * input_width + output_width / 2) / output_width; + if (op_params.align_corners && output_height > 1) { + height_scale_10 = + ((1 << 10) * (input_height - 1) + (output_height - 1) / 2) / + (output_height - 1); + } + if (op_params.align_corners && output_width > 1) { + width_scale_10 = ((1 << 10) * (input_width - 1) + (output_width - 1) / 2) / + (output_width - 1); + } + + for (int b = 0; b < batches; ++b) { + for (int y = 0; y < output_height; ++y) { + int32_t input_y, y0, y1; + ComputeInterpolationValuesInteger(y, height_scale_10, + op_params.half_pixel_centers, + input_height, &input_y, &y0, &y1); + for (int x = 0; x < output_width; ++x) { + int32_t input_x, x0, x1; + ComputeInterpolationValuesInteger(x, width_scale_10, + op_params.half_pixel_centers, + input_width, &input_x, &x0, &x1); + for (int c = 0; c < depth; ++c) { + const int64_t output_20_ll = + static_cast( + input_data[Offset(input_shape, b, y0, x0, c)]) * + ((1 << 10) - (input_y - (1 << 10) * y0)) * + ((1 << 10) - (input_x - (1 << 10) * x0)); + const int64_t output_20_lu = + static_cast( + input_data[Offset(input_shape, b, y1, x0, c)]) * + (input_y - (1 << 10) * y0) * + ((1 << 10) - (input_x - (1 << 10) * x0)); + const int64_t output_20_rl = + static_cast( + input_data[Offset(input_shape, b, y0, x1, c)]) * + ((1 << 10) - (input_y - (1 << 10) * y0)) * + (input_x - (1 << 10) * x0); + const int64_t output_20_ru = + static_cast( + input_data[Offset(input_shape, b, y1, x1, c)]) * + (input_y - (1 << 10) * y0) * (input_x - (1 << 10) * x0); + const int64_t output_20 = + output_20_ll + output_20_lu + output_20_rl + output_20_ru; + const int64_t round = (output_20 > 0) ? (1 << 19) : -(1 << 19); + const T interpolation = + static_cast((output_20 + round) / (1 << 20)); + output_data[Offset(output_shape, b, y, x, c)] = interpolation; + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_RESIZE_BILINEAR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/resize_nearest_neighbor.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/resize_nearest_neighbor.h new file mode 100644 index 000000000..bf0b757e9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/resize_nearest_neighbor.h @@ -0,0 +1,102 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_RESIZE_NEAREST_NEIGHBOR_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_RESIZE_NEAREST_NEIGHBOR_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline int32_t GetNearestNeighbor(const int input_value, + const int32_t input_size, + const int32_t output_size, + const bool align_corners, + const bool half_pixel_centers) { + const float scale = + (align_corners && output_size > 1) + ? (input_size - 1) / static_cast(output_size - 1) + : input_size / static_cast(output_size); + const float offset = half_pixel_centers ? 0.5f : 0.0f; + int32_t output_value = std::min( + align_corners + ? static_cast(TfLiteRound((input_value + offset) * scale)) + : static_cast(std::floor((input_value + offset) * scale)), + input_size - 1); + if (half_pixel_centers) { + output_value = std::max(static_cast(0), output_value); + } + return output_value; +} + +template +inline void ResizeNearestNeighbor( + const tflite::ResizeNearestNeighborParams& op_params, + const RuntimeShape& unextended_input_shape, const T* input_data, + const RuntimeShape& output_size_shape, const int32_t* output_size_data, + const RuntimeShape& unextended_output_shape, T* output_data) { + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + int32_t batches = MatchingDim(input_shape, 0, output_shape, 0); + int32_t input_height = input_shape.Dims(1); + int32_t input_width = input_shape.Dims(2); + int32_t depth = MatchingDim(input_shape, 3, output_shape, 3); + + // The Tensorflow version of this op allows resize on the width and height + // axis only. + TFLITE_DCHECK_EQ(output_size_shape.FlatSize(), 2); + int32_t output_height = output_size_data[0]; + int32_t output_width = output_size_data[1]; + + const int col_offset = input_shape.Dims(3); + const int row_offset = input_shape.Dims(2) * col_offset; + const int batch_offset = input_shape.Dims(1) * row_offset; + + const T* input_ptr = input_data; + T* output_ptr = output_data; + for (int b = 0; b < batches; ++b) { + for (int y = 0; y < output_height; ++y) { + int32_t in_y = GetNearestNeighbor(y, input_height, output_height, + op_params.align_corners, + op_params.half_pixel_centers); + const T* y_input_ptr = input_ptr + in_y * row_offset; + for (int x = 0; x < output_width; ++x) { + int32_t in_x = GetNearestNeighbor(x, input_width, output_width, + op_params.align_corners, + op_params.half_pixel_centers); + const T* x_input_ptr = y_input_ptr + in_x * col_offset; + memcpy(output_ptr, x_input_ptr, depth * sizeof(T)); + output_ptr += depth; + } + } + input_ptr += batch_offset; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_RESIZE_NEAREST_NEIGHBOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/round.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/round.h new file mode 100644 index 000000000..9bd8f3f2b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/round.h @@ -0,0 +1,51 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ROUND_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ROUND_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline float RoundToNearest(float value) { + auto floor_val = std::floor(value); + auto diff = value - floor_val; + if ((diff < 0.5f) || + ((diff == 0.5f) && (static_cast(floor_val) % 2 == 0))) { + return floor_val; + } else { + return floor_val = floor_val + 1.0f; + } +} + +inline void Round(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + // Note that this implementation matches that of tensorFlow tf.round + // and corresponds to the bankers rounding method. + // cfenv (for fesetround) is not yet supported universally on Android, so + // using a work around. + output_data[i] = RoundToNearest(input_data[i]); + } +} + +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ROUND_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/select.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/select.h new file mode 100644 index 000000000..3c0d312c6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/select.h @@ -0,0 +1,151 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SELECT_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SELECT_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +void Select(const RuntimeShape& input_condition_shape, + const D* input_condition_data, const RuntimeShape& input_x_shape, + const T* input_x_data, const RuntimeShape& input_y_shape, + const T* input_y_data, const RuntimeShape& output_shape, + T* output_data) { + ruy::profiler::ScopeLabel label("Select"); + int64_t flatsize; + // Allow select operator executions on mixed scalar tensors and one element + // tensors. + if (input_condition_shape.FlatSize() == 1 && input_x_shape.FlatSize() == 1 && + input_y_shape.FlatSize() == 1 && output_shape.FlatSize() == 1) { + flatsize = 1; + } else { + flatsize = MatchingFlatSize(input_condition_shape, input_x_shape, + input_y_shape, output_shape); + } + for (int64_t i = 0; i < flatsize; ++i) { + output_data[i] = + input_condition_data[i] ? input_x_data[i] : input_y_data[i]; + } +} + +template +void RankOneSelect(const RuntimeShape& input_condition_shape, + const D* input_condition_data, + const RuntimeShape& input_x_shape, const T* input_x_data, + const RuntimeShape& input_y_shape, const T* input_y_data, + const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("Select/RankOneSelect"); + const int64_t outer_size = input_condition_shape.FlatSize(); + int64_t inner_size; + if (input_condition_shape.DimensionsCount() == 0) { + inner_size = MatchingFlatSize(input_x_shape, input_y_shape, output_shape); + } else { + TFLITE_DCHECK_EQ( + MatchingDim(input_x_shape, 0, input_y_shape, 0, output_shape, 0), + outer_size); + inner_size = + MatchingFlatSizeSkipDim(input_x_shape, 0, input_y_shape, output_shape); + } + + int64_t offset = 0; + for (int64_t i = 0; i < outer_size; i++) { + const T* input_data = input_condition_data[i] ? input_x_data : input_y_data; + memcpy(output_data + offset, input_data + offset, inner_size * sizeof(T)); + offset += inner_size; + } +} + +template +void BroadcastSelect5DSlow(const RuntimeShape& input_condition_shape, + const D* input_condition_data, + const RuntimeShape& input_x_shape, + const T* input_x_data, + const RuntimeShape& input_y_shape, + const T* input_y_data, + const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("Select/BroadcastSelectSlow"); + TFLITE_DCHECK_LE(input_condition_shape.DimensionsCount(), 5); + TFLITE_DCHECK_LE(input_x_shape.DimensionsCount(), 5); + TFLITE_DCHECK_LE(input_y_shape.DimensionsCount(), 5); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), 5); + + NdArrayDesc<5> desc_condition; + NdArrayDesc<5> desc_x; + NdArrayDesc<5> desc_y; + NdArrayDesc<5> desc_output; + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(5, output_shape); + CopyDimsToDesc(extended_output_shape, &desc_output); + NdArrayDescsForElementwiseBroadcast(input_condition_shape, input_x_shape, + input_y_shape, &desc_condition, &desc_x, + &desc_y); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest + // stride, typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for + // the best cache behavior. + for (int n = 0; n < desc_output.extents[0]; ++n) { + int out_idx_n = desc_output.extents[1] * n; + int cond_idx_n = desc_condition.strides[0] * n; + int in_idx1_n = desc_x.strides[0] * n; + int in_idx2_n = desc_y.strides[0] * n; + for (int b = 0; b < desc_output.extents[1]; ++b) { + int out_idx_b = (out_idx_n + b) * desc_output.extents[2]; + int cond_idx_b = cond_idx_n + desc_condition.strides[1] * b; + int in_idx1_b = in_idx1_n + desc_x.strides[1] * b; + int in_idx2_b = in_idx2_n + desc_y.strides[1] * b; + for (int y = 0; y < desc_output.extents[2]; ++y) { + int out_idx_y = (out_idx_b + y) * desc_output.extents[3]; + int cond_idx_y = cond_idx_b + desc_condition.strides[2] * y; + int in_idx1_y = in_idx1_b + desc_x.strides[2] * y; + int in_idx2_y = in_idx2_b + desc_y.strides[2] * y; + for (int x = 0; x < desc_output.extents[3]; ++x) { + int out_idx = (out_idx_y + x) * desc_output.extents[4]; + int cond_idx = cond_idx_y + desc_condition.strides[3] * x; + int in_idx1 = in_idx1_y + desc_x.strides[3] * x; + int in_idx2 = in_idx2_y + desc_y.strides[3] * x; + for (int c = 0; c < desc_output.extents[4]; ++c) { + output_data[out_idx] = input_condition_data[cond_idx] + ? input_x_data[in_idx1] + : input_y_data[in_idx2]; + out_idx++; + cond_idx += desc_condition.strides[4]; + in_idx1 += desc_x.strides[4]; + in_idx2 += desc_y.strides[4]; + } + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SELECT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/slice.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/slice.h new file mode 100644 index 000000000..cb73ea0d0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/slice.h @@ -0,0 +1,80 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SLICE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SLICE_H_ + +#include "tensorflow/lite/kernels/internal/portable_tensor.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +inline void Slice(const tflite::SliceParams& op_params, + const RuntimeShape& input_shape, + const RuntimeShape& output_shape, + SequentialTensorWriter* writer) { + const RuntimeShape ext_shape = RuntimeShape::ExtendedShape(5, input_shape); + TFLITE_DCHECK_LE(op_params.begin_count, 5); + TFLITE_DCHECK_LE(op_params.size_count, 5); + const int begin_count = op_params.begin_count; + const int size_count = op_params.size_count; + // We front-pad the begin and size vectors. + int start[5]; + int stop[5]; + for (int i = 0; i < 5; ++i) { + int padded_i = 5 - i; + start[i] = + begin_count < padded_i ? 0 : op_params.begin[begin_count - padded_i]; + stop[i] = + (size_count < padded_i || op_params.size[size_count - padded_i] == -1) + ? ext_shape.Dims(i) + : start[i] + op_params.size[size_count - padded_i]; + } + + for (int i0 = start[0]; i0 < stop[0]; ++i0) { + for (int i1 = start[1]; i1 < stop[1]; ++i1) { + for (int i2 = start[2]; i2 < stop[2]; ++i2) { + for (int i3 = start[3]; i3 < stop[3]; ++i3) { + for (int i4 = start[4]; i4 < stop[4]; ++i4) { + writer->Write(Offset(ext_shape, i0, i1, i2, i3, i4)); + } + } + } + } + } +} + +template +inline void Slice(const tflite::SliceParams& op_params, + const RuntimeShape& input_shape, const T* input_data, + const RuntimeShape& output_shape, T* output_data) { + SequentialTensorWriter writer(input_data, output_data); + return Slice(op_params, input_shape, output_shape, &writer); +} + +template +inline void Slice(const tflite::SliceParams& op_params, + const RuntimeShape& input_shape, const TfLiteTensor* input, + const RuntimeShape& output_shape, TfLiteTensor* output) { + SequentialTensorWriter writer(input, output); + return Slice(op_params, input_shape, output_shape, &writer); +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SLICE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/softmax.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/softmax.h new file mode 100644 index 000000000..f43c72024 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/softmax.h @@ -0,0 +1,233 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SOFTMAX_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SOFTMAX_H_ + +#include +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/op_macros.h" + +namespace tflite { +namespace reference_ops { + +inline void Softmax(const SoftmaxParams& params, + const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + + for (int i = 0; i < outer_size; ++i) { + // Find max element value which we'll use to ensure numerical stability + // taking advantage of the following equality: + // exp(x[i])/sum(exp(x[i])) == exp(x[i]+C)/sum(exp(x[i]+C)) + float max = std::numeric_limits::lowest(); + for (int c = 0; c < depth; ++c) { + max = std::max(max, input_data[i * depth + c]); + } + + // Compute sum. + float sum = 0.f; + for (int c = 0; c < depth; ++c) { + const float exp_c = std::exp((input_data[i * depth + c] - max) * + static_cast(params.beta)); + output_data[i * depth + c] = exp_c; + sum += exp_c; + } + + // Compute result. + for (int c = 0; c < depth; ++c) { + output_data[i * depth + c] = output_data[i * depth + c] / sum; + } + } +} + +// Quantized softmax with int8_t/uint8_t input and int8_t/uint8_t/int16_t +// output. +template +inline void Softmax(const SoftmaxParams& params, + const RuntimeShape& input_shape, const InputT* input_data, + const RuntimeShape& output_shape, OutputT* output_data) { + const int32_t input_beta_multiplier = params.input_multiplier; + const int32_t input_beta_left_shift = params.input_left_shift; + const int diff_min = params.diff_min; + // The representation chosen for the input to the exp() function is Q5.26. + // We need to leave extra space since values that we skip might be as large as + // -32 before multiplying by input_beta_multiplier, and therefore as large as + // -16 afterwards. Note that exp(-8) is definitely not insignificant to + // accumulation, but exp(-16) definitely is. + static const int kScaledDiffIntegerBits = 5; + static const int kAccumulationIntegerBits = 12; + using FixedPointScaledDiff = + gemmlowp::FixedPoint; + using FixedPointAccum = + gemmlowp::FixedPoint; + using FixedPoint0 = gemmlowp::FixedPoint; + + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + + for (int i = 0; i < outer_size; ++i) { + InputT max_in_row = std::numeric_limits::min(); + for (int c = 0; c < depth; ++c) { + max_in_row = std::max(max_in_row, input_data[i * depth + c]); + } + + FixedPointAccum sum_of_exps = FixedPointAccum::Zero(); + for (int c = 0; c < depth; ++c) { + int32_t input_diff = + static_cast(input_data[i * depth + c]) - max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_rescaled = + MultiplyByQuantizedMultiplierGreaterThanOne( + input_diff, input_beta_multiplier, input_beta_left_shift); + const FixedPointScaledDiff scaled_diff_f8 = + FixedPointScaledDiff::FromRaw(input_diff_rescaled); + sum_of_exps = sum_of_exps + gemmlowp::Rescale( + exp_on_negative_values(scaled_diff_f8)); + } + } + + int num_bits_over_unit; + FixedPoint0 shifted_scale = FixedPoint0::FromRaw(GetReciprocal( + sum_of_exps.raw(), kAccumulationIntegerBits, &num_bits_over_unit)); + + for (int c = 0; c < depth; ++c) { + int32_t input_diff = + static_cast(input_data[i * depth + c]) - max_in_row; + if (input_diff >= diff_min) { + const int32_t input_diff_rescaled = + MultiplyByQuantizedMultiplierGreaterThanOne( + input_diff, input_beta_multiplier, input_beta_left_shift); + const FixedPointScaledDiff scaled_diff_f8 = + FixedPointScaledDiff::FromRaw(input_diff_rescaled); + + FixedPoint0 exp_in_0 = exp_on_negative_values(scaled_diff_f8); + int32_t unsat_output = gemmlowp::RoundingDivideByPOT( + (shifted_scale * exp_in_0).raw(), + num_bits_over_unit + 31 - (sizeof(OutputT) * 8)); + + const int32_t shifted_output = + unsat_output + + static_cast(std::numeric_limits::min()); + + output_data[i * depth + c] = static_cast(std::max( + std::min(shifted_output, + static_cast(std::numeric_limits::max())), + static_cast(std::numeric_limits::min()))); + } else { + output_data[i * depth + c] = std::numeric_limits::min(); + } + } + } +} + +// Computes exp(input - max_input) +inline int16_t SoftMaxCalculateExp(const SoftmaxParams& params, + const int16_t* input_data, const int depth, + int16_t max_in_row, int i, int c) { + int32_t input_diff = input_data[i * depth + c] - max_in_row; + // scale the input_diff such that [-65535, 0] correspond to [-10.0, 0.0] + // exp lut generated with range [-10, 0], as exp(-10) is negligible. + int32_t scaled_diff = MultiplyByQuantizedMultiplier( + input_diff, params.input_multiplier, params.input_left_shift); + // recenter to [-32768, 32767] + int32_t sym_scaled_diff = scaled_diff + 32767; + int16_t sat_sym_scaled_diff = + std::min(std::max(sym_scaled_diff, static_cast(-32768)), + static_cast(32767)); + // apply the exp() LUT activation function + return LUTLookup(sat_sym_scaled_diff, params.exp_lut); +} +// Quantized softmax with int16_t input and int16_t output. +inline void SoftmaxInt16(const SoftmaxParams& params, + const RuntimeShape& input_shape, + const int16_t* input_data, + const RuntimeShape& output_shape, + int16_t* output_data) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + + for (int i = 0; i < outer_size; ++i) { + // Find the largest element + int16_t max_in_row = std::numeric_limits::min(); + for (int c = 0; c < depth; ++c) { + max_in_row = std::max(max_in_row, input_data[i * depth + c]); + } + + // This loops computes the exp values and their sum. We will need the exp + // values later on in the function so we cache them in the output_data + // buffer. This is an optimization done to avoid calculating the exp values + // twice making use of the output_data buffer as scratch memory. + int32_t sum_of_exps = 0; // Q16.15 fixed point format. + int16_t* exp_results_Q015 = output_data + i * depth; + for (int c = 0; c < depth; ++c) { + exp_results_Q015[c] = + SoftMaxCalculateExp(params, input_data, depth, max_in_row, i, c); + sum_of_exps += exp_results_Q015[c]; + } + + // Compute the reciprocal 1/sum_of_exps + uint8_t headroom_plus_one = + CountLeadingZeros(static_cast(sum_of_exps)); + int32_t shifted_sum = + ((static_cast(sum_of_exps) << (headroom_plus_one - 1)) + + (1 << 13)) >> + 14; + // since the LUT computes 1/(1 + x) we need to first compute x = (sum - 1). + // also, the LUT expects a symmetrical input, so we must also recenter x + // from [0, 65535] to [-32768, 32767]. + int32_t sym_shifted_sum = shifted_sum + (-((1 << 15) + (1 << 16))); + int16_t sat_sym_shifted_sum = static_cast( + std::min(std::max(sym_shifted_sum, static_cast(-32768)), + static_cast(32767))); + // apply 1/(1 + x) LUT activation function + int16_t reciprocal_scale_Q015 = + LUTLookup(sat_sym_shifted_sum, params.one_over_one_plus_x_lut); + + // Rescale the exp_result with reciprocal + // range of output is [0, 32767] correspond to [0.0, 1.0] + for (int c = 0; c < depth; ++c) { + uint8_t right_shift = 31 - headroom_plus_one; + int64_t round = 1 << (right_shift - 1); + int32_t result = (static_cast(exp_results_Q015[c]) * + static_cast(reciprocal_scale_Q015) + + round) >> + right_shift; + output_data[i * depth + c] = static_cast( + std::min(std::max(result, static_cast(0)), + static_cast(32767))); + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SOFTMAX_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/space_to_batch_nd.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/space_to_batch_nd.h new file mode 100644 index 000000000..dcef04a8f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/space_to_batch_nd.h @@ -0,0 +1,109 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SPACE_TO_BATCH_ND_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SPACE_TO_BATCH_ND_H_ + +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +// TODO(b/135760455): Move this method anonymous namespace in a cc file. +inline RuntimeShape ExtendShapeSpaceToBatch(const RuntimeShape& shape) { + if (shape.DimensionsCount() == 4) { + return shape; + } + RuntimeShape new_shape(4, 1); + new_shape.SetDim(0, shape.Dims(0)); + new_shape.SetDim(1, shape.Dims(1)); + new_shape.SetDim(3, shape.Dims(2)); + return new_shape; +} + +template +inline void SpaceToBatchND(const SpaceToBatchParams& params, + const RuntimeShape& unextended_input1_shape, + const T* input1_data, + const RuntimeShape& unextended_input2_shape, + const int32_t* block_shape_data, + const RuntimeShape& unextended_input3_shape, + const int32_t* paddings_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + ruy::profiler::ScopeLabel label("SpaceToBatchND"); + TFLITE_DCHECK_GE(unextended_input1_shape.DimensionsCount(), 3); + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(unextended_input1_shape.DimensionsCount(), + unextended_output_shape.DimensionsCount()); + + // Extends the input/output shape from 3D to 4D if needed, NHC -> NH1C. + const RuntimeShape input1_shape = + ExtendShapeSpaceToBatch(unextended_input1_shape); + const RuntimeShape output_shape = + ExtendShapeSpaceToBatch(unextended_output_shape); + + const int depth = input1_shape.Dims(3); + const int input_width = input1_shape.Dims(2); + const int input_height = input1_shape.Dims(1); + const int input_batch_size = input1_shape.Dims(0); + + const int output_width = output_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_batch_size = output_shape.Dims(0); + + const int block_shape_height = block_shape_data[0]; + const int block_shape_width = + unextended_input1_shape.DimensionsCount() == 4 ? block_shape_data[1] : 1; + const int padding_top = paddings_data[0]; + const int padding_left = + unextended_input1_shape.DimensionsCount() == 4 ? paddings_data[2] : 0; + + // For uint8 quantized, the correct padding "zero value" is the output offset. + const int32_t pad_value = params.output_offset; + for (int out_b = 0; out_b < output_batch_size; ++out_b) { + int input_batch = out_b % input_batch_size; + int shift_w = (out_b / input_batch_size) % block_shape_width; + int shift_h = (out_b / input_batch_size) / block_shape_width; + for (int out_h = 0; out_h < output_height; ++out_h) { + for (int out_w = 0; out_w < output_width; ++out_w) { + T* out = output_data + Offset(output_shape, out_b, out_h, out_w, 0); + if (out_h * block_shape_height + shift_h < padding_top || + out_h * block_shape_height + shift_h >= + padding_top + input_height || + out_w * block_shape_width + shift_w < padding_left || + out_w * block_shape_width + shift_w >= padding_left + input_width) { + // This may not execute correctly when pad_value != 0 and T != uint8. + memset(out, pad_value, depth * sizeof(T)); + } else { + const T* in = + input1_data + + Offset(input1_shape, input_batch, + (out_h * block_shape_height + shift_h) - padding_top, + (out_w * block_shape_width + shift_w) - padding_left, 0); + memcpy(out, in, depth * sizeof(T)); + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SPACE_TO_BATCH_ND_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/space_to_depth.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/space_to_depth.h new file mode 100644 index 000000000..7ad465494 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/space_to_depth.h @@ -0,0 +1,80 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SPACE_TO_DEPTH_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SPACE_TO_DEPTH_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace reference_ops { + +template +inline void SpaceToDepth(const tflite::SpaceToDepthParams& op_params, + const RuntimeShape& unextended_input_shape, + const T* input_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(4, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + const int input_depth = input_shape.Dims(3); + const int input_width = input_shape.Dims(2); + const int input_height = input_shape.Dims(1); + const int input_batch = input_shape.Dims(0); + + const int output_depth = output_shape.Dims(3); + const int output_width = output_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_batch = output_shape.Dims(0); + + const int32_t block_size = op_params.block_size; + + TFLITE_DCHECK_EQ(input_width, output_width * block_size); + TFLITE_DCHECK_EQ(input_height, output_height * block_size); + TFLITE_DCHECK_EQ(input_depth * block_size * block_size, output_depth); + TFLITE_DCHECK_EQ(input_batch, output_batch); + + for (int in_b = 0; in_b < input_batch; ++in_b) { + for (int in_h = 0; in_h < input_height; ++in_h) { + for (int in_w = 0; in_w < input_width; ++in_w) { + for (int in_d = 0; in_d < input_depth; ++in_d) { + const int out_d = + in_d + ((in_h % block_size) * block_size + in_w % block_size) * + input_depth; + const int out_w = in_w / block_size; + const int out_h = in_h / block_size; + const int out_b = in_b; + + const int input_index = Offset(input_shape, in_b, in_h, in_w, in_d); + const int output_index = + Offset(output_shape, out_b, out_h, out_w, out_d); + + output_data[output_index] = input_data[input_index]; + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SPACE_TO_DEPTH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/strided_slice.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/strided_slice.h new file mode 100644 index 000000000..2b71c79b2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/strided_slice.h @@ -0,0 +1,121 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_STRIDED_SLICE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_STRIDED_SLICE_H_ + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/portable_tensor.h" +#include "tensorflow/lite/kernels/internal/strided_slice_logic.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +inline void StridedSlice(const tflite::StridedSliceParams& op_params, + const RuntimeShape& unextended_input_shape, + const RuntimeShape& unextended_output_shape, + SequentialTensorWriter* writer) { + using strided_slice::LoopCondition; + using strided_slice::StartForAxis; + using strided_slice::StopForAxis; + + ruy::profiler::ScopeLabel label("StridedSlice"); + + // Note that the output_shape is not used herein. + tflite::StridedSliceParams params_copy = op_params; + + TFLITE_DCHECK_LE(unextended_input_shape.DimensionsCount(), 5); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 5); + const RuntimeShape input_shape = + RuntimeShape::ExtendedShape(5, unextended_input_shape); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(5, unextended_output_shape); + + // Reverse and pad to 5 dimensions because that is what the runtime code + // requires (ie. all shapes must be 5D and are given backwards). + strided_slice::StridedSlicePadIndices(¶ms_copy, 5); + + const int start_0 = StartForAxis(params_copy, input_shape, 0); + const int stop_0 = StopForAxis(params_copy, input_shape, 0, start_0); + const int start_1 = StartForAxis(params_copy, input_shape, 1); + const int stop_1 = StopForAxis(params_copy, input_shape, 1, start_1); + const int start_2 = StartForAxis(params_copy, input_shape, 2); + const int stop_2 = StopForAxis(params_copy, input_shape, 2, start_2); + const int start_3 = StartForAxis(params_copy, input_shape, 3); + const int stop_3 = StopForAxis(params_copy, input_shape, 3, start_3); + const int start_4 = StartForAxis(params_copy, input_shape, 4); + const int stop_4 = StopForAxis(params_copy, input_shape, 4, start_4); + + for (int offset_0 = start_0 * input_shape.Dims(1), + end_0 = stop_0 * input_shape.Dims(1), + step_0 = params_copy.strides[0] * input_shape.Dims(1); + !LoopCondition(offset_0, end_0, params_copy.strides[0]); + offset_0 += step_0) { + for (int offset_1 = (offset_0 + start_1) * input_shape.Dims(2), + end_1 = (offset_0 + stop_1) * input_shape.Dims(2), + step_1 = params_copy.strides[1] * input_shape.Dims(2); + !LoopCondition(offset_1, end_1, params_copy.strides[1]); + offset_1 += step_1) { + for (int offset_2 = (offset_1 + start_2) * input_shape.Dims(3), + end_2 = (offset_1 + stop_2) * input_shape.Dims(3), + step_2 = params_copy.strides[2] * input_shape.Dims(3); + !LoopCondition(offset_2, end_2, params_copy.strides[2]); + offset_2 += step_2) { + for (int offset_3 = (offset_2 + start_3) * input_shape.Dims(4), + end_3 = (offset_2 + stop_3) * input_shape.Dims(4), + step_3 = params_copy.strides[3] * input_shape.Dims(4); + !LoopCondition(offset_3, end_3, params_copy.strides[3]); + offset_3 += step_3) { + for (int offset_4 = offset_3 + start_4, end_4 = offset_3 + stop_4; + !LoopCondition(offset_4, end_4, params_copy.strides[4]); + offset_4 += params_copy.strides[4]) { + writer->Write(offset_4); + } + } + } + } + } +} + +template +inline void StridedSlice(const tflite::StridedSliceParams& op_params, + const RuntimeShape& unextended_input_shape, + const T* input_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + SequentialTensorWriter writer(input_data, output_data); + StridedSlice(op_params, unextended_input_shape, unextended_output_shape, + &writer); +} + +template +inline void StridedSlice(const tflite::StridedSliceParams& op_params, + const RuntimeShape& unextended_input_shape, + const TfLiteTensor* input, + const RuntimeShape& unextended_output_shape, + TfLiteTensor* output) { + SequentialTensorWriter writer(input, output); + StridedSlice(op_params, unextended_input_shape, unextended_output_shape, + &writer); +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_STRIDED_SLICE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/sub.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/sub.h new file mode 100644 index 000000000..6af4cbd91 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/sub.h @@ -0,0 +1,479 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SUB_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SUB_H_ + +#include + +#include +#include + +#include "third_party/ruy/ruy/profiler/instrumentation.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void SubNonBroadcast(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const float* input1_data, + const RuntimeShape& input2_shape, + const float* input2_data, + const RuntimeShape& output_shape, + float* output_data) { + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = ActivationFunctionWithMinMax( + input1_data[i] - input2_data[i], params.float_activation_min, + params.float_activation_max); + } +} + +inline void SubNonBroadcast(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const int32_t* input1_data, + const RuntimeShape& input2_shape, + const int32_t* input2_data, + const RuntimeShape& output_shape, + int32_t* output_data) { + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + output_data[i] = ActivationFunctionWithMinMax( + input1_data[i] - input2_data[i], params.quantized_activation_min, + params.quantized_activation_max); + } +} + +// TODO(b/151345304): We can implement BroadcastSub on buffers of arbitrary +// dimensionality if the runtime code does a single loop over one dimension +// that handles broadcasting as the base case. The code generator would then +// generate max(D1, D2) nested for loops. +template +inline void BroadcastSubSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const float* input1_data, + const RuntimeShape& input2_shape, + const float* input2_data, + const RuntimeShape& output_shape, + float* output_data) { + ruy::profiler::ScopeLabel label("BroadcastSubSlow/float"); + TFLITE_DCHECK_LE(input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), N); + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, output_shape), &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + auto sub_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, indexes)] - + input2_data[SubscriptToIndex(desc2, indexes)], + params.float_activation_min, params.float_activation_max); + }; + NDOpsHelper(output_desc, sub_func); +} + +template +inline void BroadcastSubSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const int32_t* input1_data, + const RuntimeShape& input2_shape, + const int32_t* input2_data, + const RuntimeShape& output_shape, + int32_t* output_data) { + ruy::profiler::ScopeLabel label("BroadcastSubSlow/int32_t"); + TFLITE_DCHECK_LE(input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), N); + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, output_shape), &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + auto sub_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, indexes)] - + input2_data[SubscriptToIndex(desc2, indexes)], + params.quantized_activation_min, params.quantized_activation_max); + }; + NDOpsHelper(output_desc, sub_func); +} + +template +void BroadcastSubSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const int64_t* input1_data, + const RuntimeShape& input2_shape, + const int64_t* input2_data, + const RuntimeShape& output_shape, int64_t* output_data) { + ruy::profiler::ScopeLabel label("BroadcastSubSlow/int64_t"); + TFLITE_DCHECK_LE(input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), N); + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, output_shape), &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + auto sub_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, indexes)] - + input2_data[SubscriptToIndex(desc2, indexes)], + params.int64_activation_min, params.int64_activation_max); + }; + NDOpsHelper(output_desc, sub_func); +} + +template +void BroadcastSubSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const T* input1_data, + const RuntimeShape& input2_shape, const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("BroadcastSubSlow/templated"); + TFLITE_DCHECK_LE(input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), N); + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, output_shape), &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + auto sub_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + ActivationFunctionWithMinMax( + input1_data[SubscriptToIndex(desc1, indexes)] - + input2_data[SubscriptToIndex(desc2, indexes)], + params.quantized_activation_min, params.quantized_activation_max); + }; + NDOpsHelper(output_desc, sub_func); +} + +template +inline void BroadcastSub16POTSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const int16_t* input1_data, + const RuntimeShape& input2_shape, + const int16_t* input2_data, + const RuntimeShape& output_shape, + int16_t* output_data) { + ruy::profiler::ScopeLabel label("BroadcastSub16POTSlow/int16_t"); + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, output_shape), &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + auto sub_func = [&](int indexes[N]) { + const int32_t input1_val = input1_data[SubscriptToIndex(desc1, indexes)]; + const int32_t input2_val = input2_data[SubscriptToIndex(desc2, indexes)]; + const int32_t scaled_input1_val = + gemmlowp::RoundingDivideByPOT(input1_val, -params.input1_shift); + const int32_t scaled_input2_val = + gemmlowp::RoundingDivideByPOT(input2_val, -params.input2_shift); + const int32_t raw_output = scaled_input1_val - scaled_input2_val; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[SubscriptToIndex(output_desc, indexes)] = + static_cast(clamped_output); + }; + NDOpsHelper(output_desc, sub_func); +} + +template +void BroadcastQuantSubSlow(const ArithmeticParams& params, + const RuntimeShape& input1_shape, + const T* input1_data, + const RuntimeShape& input2_shape, + const T* input2_data, + const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("BroadcastQuantSubSlow/T"); + TFLITE_DCHECK_LE(input1_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(input2_shape.DimensionsCount(), N); + TFLITE_DCHECK_LE(output_shape.DimensionsCount(), N); + NdArrayDesc desc1; + NdArrayDesc desc2; + NdArrayDesc output_desc; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, output_shape), &output_desc); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + auto sub_func = [&](int indexes[N]) { + const int32_t input1_val = + params.input1_offset + input1_data[SubscriptToIndex(desc1, indexes)]; + const int32_t input2_val = + params.input2_offset + input2_data[SubscriptToIndex(desc2, indexes)]; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sub = scaled_input1_val - scaled_input2_val; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sub, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[SubscriptToIndex(output_desc, indexes)] = + static_cast(clamped_output); + }; + NDOpsHelper(output_desc, sub_func); +} + +// Element-wise add that can often be used for inner loop of broadcast add as +// well as the non-broadcast add. +template +inline void SubElementwise(int size, const ArithmeticParams& params, + const T* input1_data, const T* input2_data, + T* output_data) { + for (int i = 0; i < size; ++i) { + const int32_t input1_val = params.input1_offset + input1_data[i]; + const int32_t input2_val = params.input2_offset + input2_data[i]; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sub = scaled_input1_val - scaled_input2_val; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sub, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + output_data[i] = static_cast(clamped_output); + } +} + +inline void Sub(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const uint8_t* input1_data, + const RuntimeShape& input2_shape, const uint8_t* input2_data, + const RuntimeShape& output_shape, uint8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + TFLITE_DCHECK_GT(params.input1_offset, -256); + TFLITE_DCHECK_GT(params.input2_offset, -256); + TFLITE_DCHECK_LT(params.input1_offset, 256); + TFLITE_DCHECK_LT(params.input2_offset, 256); + SubElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void Sub(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const int8_t* input1_data, + const RuntimeShape& input2_shape, const int8_t* input2_data, + const RuntimeShape& output_shape, int8_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + TFLITE_DCHECK_GE(params.input1_offset, -128); + TFLITE_DCHECK_GE(params.input2_offset, -128); + // offset = -quantization_params.zero_point in PrepareGeneralSubOp(). + // So it's maximum can be 128 not 127. + TFLITE_DCHECK_LE(params.input1_offset, 128); + TFLITE_DCHECK_LE(params.input2_offset, 128); + SubElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +inline void Sub(const ArithmeticParams& params, + const RuntimeShape& input1_shape, const int16_t* input1_data, + const RuntimeShape& input2_shape, const int16_t* input2_data, + const RuntimeShape& output_shape, int16_t* output_data) { + TFLITE_DCHECK_LE(params.quantized_activation_min, + params.quantized_activation_max); + + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + + TFLITE_DCHECK_EQ(params.input1_offset, 0); + TFLITE_DCHECK_EQ(params.input2_offset, 0); + SubElementwise(flat_size, params, input1_data, input2_data, output_data); +} + +template +void Sub(const ArithmeticParams& params, const RuntimeShape& input1_shape, + const T* input1_data, const RuntimeShape& input2_shape, + const T* input2_data, const RuntimeShape& output_shape, + T* output_data) { + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(input1_shape, input2_shape, &desc1, + &desc2); + const RuntimeShape extended_output_shape = + RuntimeShape::ExtendedShape(4, output_shape); + + // In Tensorflow, the dimensions are canonically named (batch_number, row, + // col, channel), with extents (batches, height, width, depth), with the + // trailing dimension changing most rapidly (channels has the smallest stride, + // typically 1 element). + // + // In generated C code, we store arrays with the dimensions reversed. The + // first dimension has smallest stride. + // + // We name our variables by their Tensorflow convention, but generate C code + // nesting loops such that the innermost loop has the smallest stride for the + // best cache behavior. + for (int b = 0; b < extended_output_shape.Dims(0); ++b) { + for (int y = 0; y < extended_output_shape.Dims(1); ++y) { + for (int x = 0; x < extended_output_shape.Dims(2); ++x) { + for (int c = 0; c < extended_output_shape.Dims(3); ++c) { + output_data[Offset(extended_output_shape, b, y, x, c)] = + input1_data[SubscriptToIndex(desc1, b, y, x, c)] - + input2_data[SubscriptToIndex(desc2, b, y, x, c)]; + } + } + } + } +} + +inline void SetActivationMinMax(const ArithmeticParams& params, + int32_t* activation_min, + int32_t* activation_max) { + *activation_min = params.quantized_activation_min; + *activation_max = params.quantized_activation_max; +} + +inline void SetActivationMinMax(const ArithmeticParams& params, + float* activation_min, float* activation_max) { + *activation_min = params.float_activation_min; + *activation_max = params.float_activation_max; +} + +inline void SetActivationMinMax(const ArithmeticParams& params, + int64_t* activation_min, + int64_t* activation_max) { + *activation_min = params.int64_activation_min; + *activation_max = params.int64_activation_max; +} + +template +inline void SubWithActivation( + const ArithmeticParams& params, const RuntimeShape& input1_shape, + const T* input1_data, const RuntimeShape& input2_shape, + const T* input2_data, const RuntimeShape& output_shape, T* output_data) { + ruy::profiler::ScopeLabel label("SubWithActivation"); + const int flat_size = + MatchingElementsSize(input1_shape, input2_shape, output_shape); + T activation_min, activation_max; + SetActivationMinMax(params, &activation_min, &activation_max); + + for (int i = 0; i < flat_size; ++i) { + output_data[i] = ActivationFunctionWithMinMax( + input1_data[i] - input2_data[i], activation_min, activation_max); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SUB_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/tanh.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/tanh.h new file mode 100644 index 000000000..9d9969176 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/tanh.h @@ -0,0 +1,129 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TANH_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TANH_H_ + +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/op_macros.h" + +namespace tflite { +namespace reference_ops { + +inline void Tanh(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + float val = input_data[i]; + float result = std::tanh(val); + output_data[i] = result; + } +} + +// Convenience version that allows, for example, generated-code calls to be +// uniform between data types. +inline void Tanh(const TanhParams&, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& output_shape, + float* output_data) { + // Drop params: not needed. + Tanh(input_shape, input_data, output_shape, output_data); +} + +inline void Tanh(const TanhParams& params, const RuntimeShape& input_shape, + const int16_t* input_data, const RuntimeShape& output_shape, + int16_t* output_data) { + const int input_left_shift = params.input_left_shift; + // Support for shifts is limited until we have a parameterized version of + // SaturatingRoundingMultiplyByPOT(). + TFLITE_DCHECK_GE(input_left_shift, 0); + TFLITE_DCHECK_LE(input_left_shift, 1); + + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + // F0 uses 0 integer bits, range [-1, 1]. + // This is the return type of math functions such as tanh, logistic, + // whose range is in [-1, 1]. + using F0 = gemmlowp::FixedPoint; + // F3 uses 3 integer bits, range [-8, 8], the input range expected here. + using F3 = gemmlowp::FixedPoint; + + if (input_left_shift == 0) { + for (int i = 0; i < flat_size; i++) { + F3 input = F3::FromRaw(input_data[i]); + F0 output = gemmlowp::tanh(input); + output_data[i] = output.raw(); + } + } else { + for (int i = 0; i < flat_size; i++) { + F3 input = F3::FromRaw( + gemmlowp::SaturatingRoundingMultiplyByPOT<1>(input_data[i])); + F0 output = gemmlowp::tanh(input); + output_data[i] = output.raw(); + } + } +} + +inline void Tanh(const TanhParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& output_shape, + uint8_t* output_data) { + const int32_t input_zero_point = params.input_zero_point; + const int32_t input_range_radius = params.input_range_radius; + const int32_t input_multiplier = params.input_multiplier; + const int input_left_shift = params.input_left_shift; + const int32_t output_zero_point = 128; + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; i++) { + const uint8_t input_val_u8 = input_data[i]; + const int32_t input_val_centered = + static_cast(input_val_u8) - input_zero_point; + uint8_t output_val; + if (input_val_centered <= -input_range_radius) { + output_val = 0; + } else if (input_val_centered >= input_range_radius) { + output_val = 255; + } else { + const int32_t input_val_rescaled = + MultiplyByQuantizedMultiplierGreaterThanOne( + input_val_centered, input_multiplier, input_left_shift); + using FixedPoint4 = gemmlowp::FixedPoint; + using FixedPoint0 = gemmlowp::FixedPoint; + const FixedPoint4 input_val_f4 = FixedPoint4::FromRaw(input_val_rescaled); + const FixedPoint0 output_val_f0 = gemmlowp::tanh(input_val_f4); + // Convert from Q0.31 to Q24.7. + using gemmlowp::RoundingDivideByPOT; + int32_t output_val_s32 = RoundingDivideByPOT(output_val_f0.raw(), 24); + output_val_s32 += output_zero_point; + if (output_val_s32 == 256) { + output_val_s32 = 255; + } + // Reinterpret as Q0.7, encoded in uint8_t. + TFLITE_DCHECK_GE(output_val_s32, 0); + TFLITE_DCHECK_LE(output_val_s32, 255); + output_val = static_cast(output_val_s32); + } + output_data[i] = output_val; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TANH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/transpose.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/transpose.h new file mode 100644 index 000000000..96aa4ccaa --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/transpose.h @@ -0,0 +1,111 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TRANSPOSE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TRANSPOSE_H_ + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +template +void TransposeImpl(const TransposeParams& params, + const RuntimeShape& unextended_input_shape, + const T* input_data, + const RuntimeShape& unextended_output_shape, + T* output_data) { + const int unextended_input_size = unextended_input_shape.DimensionsCount(); + const int unextended_output_size = unextended_output_shape.DimensionsCount(); + TFLITE_DCHECK_LE(unextended_input_size, N); + TFLITE_DCHECK_LE(unextended_output_size, N); + TFLITE_DCHECK_EQ(unextended_output_size, params.perm_count); + const int input_ext_size = N - unextended_input_size; + const int output_ext_size = N - unextended_output_size; + NdArrayDesc input_desc; + NdArrayDesc output_desc; + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_input_shape), + &input_desc); + CopyDimsToDesc(RuntimeShape::ExtendedShape(N, unextended_output_shape), + &output_desc); + + // The perm data is extended to match the output, each index incremented by + // the amount of front padding of the input shape. + int extended_perm[N]; + for (int i = 0; i < N; ++i) { + extended_perm[i] = i < output_ext_size + ? i + : params.perm[i - output_ext_size] + input_ext_size; + } + + // Permutes the input shape so we don't need to permute the indexes inside + // the loop. Check to make sure output_dims is matching input_dims. + NdArrayDesc perm_input_desc; + for (int k = 0; k < N; ++k) { + TFLITE_DCHECK_EQ(input_desc.extents[extended_perm[k]], + output_desc.extents[k]); + perm_input_desc.extents[k] = input_desc.extents[extended_perm[k]]; + perm_input_desc.strides[k] = input_desc.strides[extended_perm[k]]; + } + + // Naive transpose loop (iterate on output index and compute input index). + auto tranpose_func = [&](int indexes[N]) { + output_data[SubscriptToIndex(output_desc, indexes)] = + input_data[SubscriptToIndex(perm_input_desc, indexes)]; + }; + NDOpsHelper(output_desc, tranpose_func); +} + +template +void Transpose(const TransposeParams& params, + const RuntimeShape& unextended_input_shape, const T* input_data, + const RuntimeShape& unextended_output_shape, T* output_data) { + // Transpose kernel only does rearranging values not numeric evaluations on + // each cell. It's safe to implement per size of scalar type and this trick + // keeps the total code size in a reasonable range. + switch (sizeof(T)) { + case 1: + TransposeImpl(params, unextended_input_shape, + reinterpret_cast(input_data), + unextended_output_shape, + reinterpret_cast(output_data)); + break; + case 2: + TransposeImpl(params, unextended_input_shape, + reinterpret_cast(input_data), + unextended_output_shape, + reinterpret_cast(output_data)); + break; + + case 4: + TransposeImpl(params, unextended_input_shape, + reinterpret_cast(input_data), + unextended_output_shape, + reinterpret_cast(output_data)); + break; + case 8: + TransposeImpl(params, unextended_input_shape, + reinterpret_cast(input_data), + unextended_output_shape, + reinterpret_cast(output_data)); + break; + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TRANSPOSE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/transpose_conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/transpose_conv.h new file mode 100644 index 000000000..ac91f379a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/reference/transpose_conv.h @@ -0,0 +1,219 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TRANSPOSE_CONV_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TRANSPOSE_CONV_H_ + +#include + +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void TransposeConv( + const ConvParams& params, const RuntimeShape& input_shape, + const float* input_data, const RuntimeShape& filter_shape, + const float* filter_data, const RuntimeShape& bias_shape, + const float* bias_data, const RuntimeShape& output_shape, + float* output_data, const RuntimeShape& im2col_shape, float* im2col_data) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + + // Although transpose convolution simplifies to convolution with transposed + // weights for strides of 1, non-unitary striding complicates matters. To + // keep this reference implementation as clear as possible, we use a + // "scatter" access pattern, where we loop through all the input elements, + // computing their influence on the output, rather than looping through the + // output elements in the typical "gather" access pattern of a conv. We + // therefore must initialize the output array to zero. + const int num_elements = output_shape.FlatSize(); + for (int i = 0; i < num_elements; i++) { + output_data[i] = 0.0f; + } + + // Loop through input elements one at a time. + for (int batch = 0; batch < batches; ++batch) { + for (int in_y = 0; in_y < input_height; ++in_y) { + for (int in_x = 0; in_x < input_width; ++in_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + // Loop through the output elements it will influence + const int out_x_origin = (in_x * stride_width) - pad_width; + const int out_y_origin = (in_y * stride_height) - pad_height; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + for (int out_channel = 0; out_channel < output_depth; + ++out_channel) { + // Compute output element location + const int out_x = out_x_origin + filter_x; + const int out_y = out_y_origin + filter_y; + // We cannot accumulate out of bounds + if ((out_x >= 0) && (out_x < output_width) && (out_y >= 0) && + (out_y < output_height)) { + float input_value = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + float filter_value = + filter_data[Offset(filter_shape, out_channel, filter_y, + filter_x, in_channel)]; + output_data[Offset(output_shape, batch, out_y, out_x, + out_channel)] += + input_value * filter_value; + } + } + } + } + } + } + } + } + if (bias_data) { + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + output_data[Offset(output_shape, batch, out_y, out_x, + out_channel)] += bias_data[out_channel]; + } + } + } + } + } +} + +inline void TransposeConv( + const ConvParams& params, const RuntimeShape& input_shape, + const uint8_t* input_data, const RuntimeShape& filter_shape, + const uint8_t* filter_data, const RuntimeShape& bias_shape, + const int32_t* bias_data, const RuntimeShape& output_shape, + uint8_t* output_data, const RuntimeShape& im2col_shape, + uint8_t* im2col_data, int32_t* scratch_buffer) { + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + (void)im2col_data; // only used in optimized code. + (void)im2col_shape; // only used in optimized code. + + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + TFLITE_DCHECK_LE(output_activation_min, output_activation_max); + if (bias_data) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + + const int num_elements = output_shape.FlatSize(); + // We need to initialize scratch_buffer to all 0s, as we apply the same + // 'scatter' based trick as in float version. + memset(scratch_buffer, 0, num_elements * sizeof(int32_t)); + + // Loop through input elements one at a time. + for (int batch = 0; batch < batches; ++batch) { + for (int in_y = 0; in_y < input_height; ++in_y) { + for (int in_x = 0; in_x < input_width; ++in_x) { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) { + // Loop through the output elements it will influence. + const int out_x_origin = (in_x * stride_width) - pad_width; + const int out_y_origin = (in_y * stride_height) - pad_height; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) { + for (int out_channel = 0; out_channel < output_depth; + ++out_channel) { + // Compute output element location. + const int out_x = out_x_origin + filter_x; + const int out_y = out_y_origin + filter_y; + // We cannot accumulate out of bounds. + if ((out_x >= 0) && (out_x < output_width) && (out_y >= 0) && + (out_y < output_height)) { + uint8_t input_value = input_data[Offset( + input_shape, batch, in_y, in_x, in_channel)]; + uint8_t filter_value = + filter_data[Offset(filter_shape, out_channel, filter_y, + filter_x, in_channel)]; + scratch_buffer[Offset(output_shape, batch, out_y, out_x, + out_channel)] += + (input_value + input_offset) * + (filter_value + filter_offset); + } + } + } + } + } + } + } + } + for (int batch = 0; batch < batches; ++batch) { + for (int out_y = 0; out_y < output_height; ++out_y) { + for (int out_x = 0; out_x < output_width; ++out_x) { + for (int out_channel = 0; out_channel < output_depth; ++out_channel) { + int32_t acc = scratch_buffer[Offset(output_shape, batch, out_y, out_x, + out_channel)]; + if (bias_data) { + acc += bias_data[out_channel]; + } + int32_t scaled_acc = MultiplyByQuantizedMultiplier( + acc, output_multiplier, output_shift); + scaled_acc += output_offset; + scaled_acc = std::max(scaled_acc, output_activation_min); + scaled_acc = std::min(scaled_acc, output_activation_max); + output_data[Offset(output_shape, batch, out_y, out_x, out_channel)] = + static_cast(scaled_acc); + } + } + } + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_TRANSPOSE_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/runtime_shape.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/runtime_shape.h new file mode 100644 index 000000000..c2678b57d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/runtime_shape.h @@ -0,0 +1,158 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_RUNTIME_SHAPE_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_RUNTIME_SHAPE_H_ + +namespace tflite { + +template +struct Dims { + int sizes[N]; + int strides[N]; +}; + +class RuntimeShape { + public: + RuntimeShape& operator=(RuntimeShape const&) = delete; + + // RuntimeShape in TFLM supports up to 5 dimensions. + // The name kMaxSmallSize comes from the same file of the upstream + // tensorflow lite repo and need to be kept the same for max reuse. + static constexpr int kMaxSmallSize = 5; + + RuntimeShape() : size_(0) {} + + explicit RuntimeShape(int dimensions_count) : size_(dimensions_count) {} + + RuntimeShape(int shape_size, int32_t value) : size_(shape_size) { + for (int i = 0; i < shape_size; ++i) { + SetDim(i, value); + } + } + + RuntimeShape(int dimensions_count, const int32_t* dims_data) + : size_(dimensions_count) { + ReplaceWith(dimensions_count, dims_data); + } + + bool operator==(const RuntimeShape& comp) const { + return this->size_ == comp.size_ && + std::memcmp(DimsData(), comp.DimsData(), size_ * sizeof(int32_t)) == + 0; + } + + ~RuntimeShape() {} + + int32_t DimensionsCount() const { return size_; } + int32_t Dims(int i) const { + TFLITE_DCHECK_GE(i, 0); + TFLITE_DCHECK_LT(i, size_); + return dims_[i]; + } + void SetDim(int i, int32_t val) { + TFLITE_DCHECK_GE(i, 0); + TFLITE_DCHECK_LT(i, size_); + dims_[i] = val; + } + + static RuntimeShape ExtendedShape(int new_shape_size, + const RuntimeShape& shape) { + return RuntimeShape(new_shape_size, shape, 1); + } + int32_t* DimsData() { return dims_; } + const int32_t* DimsData() const { return dims_; } + const int32_t* DimsDataUpTo5D() const { return dims_; } + + void ReplaceWith(int dimensions_count, const int32_t* dims_data) { + size_ = dimensions_count; + int32_t* dst_dims = DimsData(); + std::memcpy(dst_dims, dims_data, dimensions_count * sizeof(int32_t)); + } + + // Returns the total count of elements, that is the size when flattened into a + // vector. + int FlatSize() const { + int buffer_size = 1; + const int* dims_data = reinterpret_cast(DimsData()); + for (int i = 0; i < size_; i++) { + buffer_size *= dims_data[i]; + } + return buffer_size; + } + + private: + // For use only by ExtendedShape(), written to guarantee (return-value) copy + // elision in C++17. + // This creates a shape padded to the desired size with the specified value. + RuntimeShape(int new_shape_size, const RuntimeShape& shape, int pad_value) + : size_(new_shape_size) { + // If the following check fails, it is likely because a 4D-only kernel is + // being used with an array of larger dimension count. + TFLITE_CHECK_GE(new_shape_size, shape.DimensionsCount()); + const int size_increase = new_shape_size - shape.DimensionsCount(); + for (int i = 0; i < size_increase; ++i) { + SetDim(i, pad_value); + } + std::memcpy(DimsData() + size_increase, shape.DimsData(), + sizeof(int32_t) * shape.DimensionsCount()); + } + + int32_t size_; + union { + int32_t dims_[kMaxSmallSize]; + }; +}; + +// Since tensors with '0' in their shape are valid in TF, these offset functions +// allow that as long as the corresponding index is also 0. It is upto the +// calling ops to ensure that they perform verification checks on tensor shapes +// if they don't support a particular behavior. + +inline int Offset(const RuntimeShape& shape, int i0, int i1, int i2, int i3) { + TFLITE_DCHECK_EQ(shape.DimensionsCount(), 4); + const int* dims_data = reinterpret_cast(shape.DimsData()); + TFLITE_DCHECK((dims_data[0] == 0 && i0 == 0) || + (i0 >= 0 && i0 < dims_data[0])); + TFLITE_DCHECK((dims_data[1] == 0 && i1 == 0) || + (i1 >= 0 && i1 < dims_data[1])); + TFLITE_DCHECK((dims_data[2] == 0 && i2 == 0) || + (i2 >= 0 && i2 < dims_data[2])); + TFLITE_DCHECK((dims_data[3] == 0 && i3 == 0) || + (i3 >= 0 && i3 < dims_data[3])); + return ((i0 * dims_data[1] + i1) * dims_data[2] + i2) * dims_data[3] + i3; +} + +inline int Offset(const RuntimeShape& shape, int i0, int i1, int i2, int i3, + int i4) { + TFLITE_DCHECK_EQ(shape.DimensionsCount(), 5); + const int* dims_data = reinterpret_cast(shape.DimsData()); + TFLITE_DCHECK((dims_data[0] == 0 && i0 == 0) || + (i0 >= 0 && i0 < dims_data[0])); + TFLITE_DCHECK((dims_data[1] == 0 && i1 == 0) || + (i1 >= 0 && i1 < dims_data[1])); + TFLITE_DCHECK((dims_data[2] == 0 && i2 == 0) || + (i2 >= 0 && i2 < dims_data[2])); + TFLITE_DCHECK((dims_data[3] == 0 && i3 == 0) || + (i3 >= 0 && i3 < dims_data[3])); + TFLITE_DCHECK((dims_data[4] == 0 && i4 == 0) || + (i4 >= 0 && i4 < dims_data[4])); + return (((i0 * dims_data[1] + i1) * dims_data[2] + i2) * dims_data[3] + i3) * + dims_data[4] + + i4; +} + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_RUNTIME_SHAPE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/strided_slice_logic.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/strided_slice_logic.h new file mode 100644 index 000000000..bfe84050d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/strided_slice_logic.h @@ -0,0 +1,211 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_STRIDED_SLICE_LOGIC_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_STRIDED_SLICE_LOGIC_H_ + +#include +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { +namespace strided_slice { + +// Use until std::clamp() is available from C++17. +inline int Clamp(const int v, const int lo, const int hi) { + TFLITE_DCHECK(!(hi < lo)); + if (hi < v) return hi; + if (v < lo) return lo; + return v; +} + +inline void StridedSlicePadIndices(tflite::StridedSliceParams* p, + int dim_count) { + // Add indices and mask bits to fully include extra dimensions + TFLITE_CHECK_LE(dim_count, 5); + TFLITE_CHECK_GE(dim_count, p->start_indices_count); + TFLITE_CHECK_EQ(p->start_indices_count, p->stop_indices_count); + TFLITE_CHECK_EQ(p->stop_indices_count, p->strides_count); + + const int pad_count = dim_count - p->start_indices_count; + + // Pad indices at start, so move arrays by pad_count. + for (int i = p->start_indices_count - 1; i >= 0; --i) { + p->strides[i + pad_count] = p->strides[i]; + p->start_indices[i + pad_count] = p->start_indices[i]; + p->stop_indices[i + pad_count] = p->stop_indices[i]; + } + for (int i = 0; i < pad_count; ++i) { + p->start_indices[i] = 0; + p->stop_indices[i] = 1; + p->strides[i] = 1; + } + + // Pad masks with 0s or 1s as required. + p->shrink_axis_mask <<= pad_count; + p->ellipsis_mask <<= pad_count; + p->new_axis_mask <<= pad_count; + p->begin_mask <<= pad_count; + p->end_mask <<= pad_count; + p->begin_mask |= (1 << pad_count) - 1; + p->end_mask |= (1 << pad_count) - 1; + + p->start_indices_count = dim_count; + p->stop_indices_count = dim_count; + p->strides_count = dim_count; +} + +// Return the index for the first element along that axis. This index will be a +// positive integer between [0, axis_size] (or [-1, axis_size -1] if stride < 0) +// that can be used to index directly into the data. +inline int StartForAxis(const tflite::StridedSliceParams& params, + const RuntimeShape& input_shape, int axis) { + const auto begin_mask = params.begin_mask; + const auto* start_indices = params.start_indices; + const auto* strides = params.strides; + const int axis_size = input_shape.Dims(axis); + if (axis_size == 0) { + return 0; + } + // Begin with the specified index. + int start = start_indices[axis]; + + // begin_mask override + if (begin_mask & 1 << axis) { + if (strides[axis] > 0) { + // Forward iteration - use the first element. These values will get + // clamped below (Note: We could have set them to 0 and axis_size-1, but + // use lowest() and max() to maintain symmetry with StopForAxis()) + start = std::numeric_limits::lowest(); + } else { + // Backward iteration - use the last element. + start = std::numeric_limits::max(); + } + } + + // Handle negative indices + if (start < 0) { + start += axis_size; + } + + // Clamping + if (strides[axis] > 0) { + // Forward iteration + start = Clamp(start, 0, axis_size); + } else { + // Backward iteration + start = Clamp(start, -1, axis_size - 1); + } + + return start; +} + +// Return the "real" index for the end of iteration along that axis. This is an +// "end" in the traditional C sense, in that it points to one past the last +// element. ie. So if you were iterating through all elements of a 1D array of +// size 4, this function would return 4 as the stop, because it is one past the +// "real" indices of 0, 1, 2 & 3. +inline int StopForAxis(const tflite::StridedSliceParams& params, + const RuntimeShape& input_shape, int axis, + int start_for_axis) { + const auto end_mask = params.end_mask; + const auto shrink_axis_mask = params.shrink_axis_mask; + const auto* stop_indices = params.stop_indices; + const auto* strides = params.strides; + const int axis_size = input_shape.Dims(axis); + if (axis_size == 0) { + return 0; + } + + // Begin with the specified index + const bool shrink_axis = shrink_axis_mask & (1 << axis); + int stop = stop_indices[axis]; + + // When shrinking an axis, the end position does not matter (and can be + // incorrect when negative indexing is used, see Issue #19260). Always use + // start_for_axis + 1 to generate a length 1 slice, since start_for_axis has + // already been adjusted for negative indices. + if (shrink_axis) { + return start_for_axis + 1; + } + + // end_mask override + if (end_mask & (1 << axis)) { + if (strides[axis] > 0) { + // Forward iteration - use the last element. These values will get + // clamped below + stop = std::numeric_limits::max(); + } else { + // Backward iteration - use the first element. + stop = std::numeric_limits::lowest(); + } + } + + // Handle negative indices + if (stop < 0) { + stop += axis_size; + } + + // Clamping + // Because the end index points one past the last element, we need slightly + // different clamping ranges depending on the direction. + if (strides[axis] > 0) { + // Forward iteration + stop = Clamp(stop, 0, axis_size); + } else { + // Backward iteration + stop = Clamp(stop, -1, axis_size - 1); + } + + return stop; +} + +inline bool LoopCondition(int index, int stop, int stride) { + // True when we have reached the end of an axis and should loop. + return stride > 0 ? index >= stop : index <= stop; +} + +inline tflite::StridedSliceParams BuildStridedSliceParams( + int begin_mask, int end_mask, int shrink_axis_mask, + const std::vector& start_indices, const std::vector& stop_indices, + const std::vector& strides) { + tflite::StridedSliceParams op_params; + const int dims_count = start_indices.size(); + + op_params.start_indices_count = dims_count; + op_params.stop_indices_count = dims_count; + op_params.strides_count = dims_count; + for (int i = 0; i < dims_count; ++i) { + op_params.start_indices[i] = start_indices[i]; + op_params.stop_indices[i] = stop_indices[i]; + op_params.strides[i] = strides[i]; + } + + op_params.begin_mask = begin_mask; + op_params.ellipsis_mask = 0; + op_params.end_mask = end_mask; + op_params.new_axis_mask = 0; + op_params.shrink_axis_mask = shrink_axis_mask; + + return op_params; +} + +} // namespace strided_slice + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_STRIDED_SLICE_LOGIC_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/tensor_ctypes.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/tensor_ctypes.h new file mode 100644 index 000000000..f1d3e17fc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/tensor_ctypes.h @@ -0,0 +1,47 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_TENSOR_CTYPES_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_TENSOR_CTYPES_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +template +inline T* GetTensorData(TfLiteTensor* tensor) { + return tensor != nullptr ? reinterpret_cast(tensor->data.raw) : nullptr; +} + +template +inline const T* GetTensorData(const TfLiteTensor* tensor) { + return tensor != nullptr ? reinterpret_cast(tensor->data.raw) + : nullptr; +} + +inline RuntimeShape GetTensorShape(const TfLiteTensor* tensor) { + if (tensor == nullptr) { + return RuntimeShape(); + } + + TfLiteIntArray* dims = tensor->dims; + const int dims_size = dims->size; + const int32_t* dims_data = reinterpret_cast(dims->data); + return RuntimeShape(dims_size, dims_data); +} + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_TENSOR_CTYPES_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/tensor_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/tensor_utils.cpp new file mode 100644 index 000000000..7e5d98101 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/tensor_utils.cpp @@ -0,0 +1,25 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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. +============================================================================== +*/ + +// internal/reference/portable_tensor_utils.h has the implementation of the +// functions declared in internal/portable_tensor_utils.h. This somewhat +// confusing setup is derived from how the code is organized in TfLite where it +// is used to select between NEON, SSE and portable implementaitons. See +// https://github.com/tensorflow/tensorflow/blob/d76c23975c4a3a0d7987cfe3f45c76566df06180/tensorflow/lite/kernels/internal/tensor_utils.cc +// for how the code is written in TfLite. + +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" +#include "tensorflow/lite/kernels/internal/reference/portable_tensor_utils.h" diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/types.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/types.h new file mode 100644 index 000000000..c44ba48e4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/internal/types.h @@ -0,0 +1,1065 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_INTERNAL_TYPES_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_TYPES_H_ + +#include +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/runtime_shape.h" + +namespace tflite { + +enum class FusedActivationFunctionType : uint8_t { + kNone, + kRelu6, + kRelu1, + kRelu +}; +enum class PaddingType : uint8_t { kNone, kSame, kValid }; + +struct PaddingValues { + int16_t width; + int16_t height; + // offset is used for calculating "remaining" padding, for example, `width` + // is 1 and `width_offset` is 1, so padding_left is 1 while padding_right is + // 1 + 1 = 2. + int16_t width_offset; + // Same as width_offset except it's over the height dimension. + int16_t height_offset; +}; + +struct Padding3DValues { + int16_t width; + int16_t height; + int16_t depth; + // offset is used for calculating "remaining" padding, for example, `width` + // is 1 and `width_offset` is 1, so padding_left is 1 while padding_right is + // 1 + 1 = 2. + int16_t width_offset; + // Same as width_offset except it's over the height dimension. + int16_t height_offset; + // Same as width_offset except it's over the depth dimension. + int16_t depth_offset; +}; + +// This enumeration allows for non-default formats for the weights array +// of a fully-connected operator, allowing the use of special optimized +// runtime paths. +enum class FullyConnectedWeightsFormat : uint8_t { + // Default format (flat 2D layout, the inner contiguous dimension + // is input_depth, the outer non-contiguous dimension is output_depth) + kDefault, + // Summary: optimized layout for fast CPU runtime implementation, + // aimed specifically at ARM CPUs at the moment, and specialized for + // 8-bit quantized layers. + // + // The use case we're concerned with here is: 8-bit quantization, + // large weights matrix that doesn't fit in cache (e.g. 4096x2048 in + // a key application that drove this), very small batch size (e.g. 1 -- 4). + // + // Even with 8-bit quantization of weights, the performance of memory + // accesses to the weights can become the dominant issue when + // the batch size is small, so each weight value is used in only a few + // arithmetic ops, i.e. the fully-connected node has a low arithmetic + // intensity. The specific issues that arise are of three kinds: + // (1) One may, ideally, max out DRAM bandwidth, i.e. be truly memory + // bound. That's the "good" issue to run into. + // (2) One may run into sub-optimal pre-fetching: the data hasn't been + // prefetched into the cache by the time we need it. + // (3) One may run into cache aliasing: multiple values that are + // pre-fetched, alias each other in the L1 cache (which typically + // has only 4-way set associativity in ARM CPUs) and thus evict + // each other before we get to using them. + // + // The point of this shuffling is to avoid issues (2) and (3) so that + // we get as fast as possible given only the hard constraint (1). + // This is achieved by turning the difficulty into a solution: the + // difficulty, that each value loaded from memory is used only in + // one kernel iteration, making this operation memory-intensive, hints at + // the solution, of shuffling the weights so that they are stored in the + // exact order as the kernel needs to load them, so that the memory + // accesses made by the kernel are trivial. This solves (2) because the + // trivial memory access pattern allows the CPU's automatic prefetching + // to perform very well (no need even for preload instructions), and this + // solves (3) because the values being loaded concurrently are now + // contiguous in the address space, thus don't alias each other in the cache. + // + // On ARM, we typically want our kernel to process a 4x16 block of weights + // at a time, because: + // - 16 is the number of bytes in a NEON register. + // - 4 is how many rows we need to handle concurrently in the kernel in + // order to have sufficient mutual independence of instructions to + // maximize arithmetic throughput. + // + // Finally, the 'Int8' part in the name refers to the fact that this + // weights format has each weights value encoded as a signed int8_t value, + // even if the data type of the weights buffer is uint8_t. This is intended + // to save runtime kernels the effort to have to XOR the top bit of these + // bytes before using them in signed arithmetic, see this file for more + // explanations on the 'signed int8_t trick' in matrix multiplication kernels: + // + // tensorflow/lite/toco/graph_transformations/ensure_uint8_weights_safe_for_fast_int8_kernels.cc + // + kShuffled4x16Int8, +}; + +// Quantization parameters, determining the mapping of quantized values +// to real values (i.e. determining how quantized values are mathematically +// interpreted). +// +// The correspondence is as follows: +// +// real_value = scale * (quantized_value - zero_point); +// +// In other words, zero_point designates which quantized value corresponds to +// the real 0 value, and scale designates the difference between the real values +// corresponding to consecutive quantized values differing by 1. +struct QuantizationParams { + int32_t zero_point = 0; + double scale = 0.0; +}; + +inline bool operator==(const QuantizationParams& qp1, + const QuantizationParams& qp2) { + return qp1.zero_point == qp2.zero_point && qp1.scale == qp2.scale; +} + +// Quantization parameters for each channel, determining the mapping of +// quantized values to real values. See QuantizationParams for a single set of +// parameters per tensor. This has one parameters set per each channel. +// +// The correspondence is as follows: +// +// real_value = scale[channel] * (quantized_value - zero_point[channel]); +// +struct PerChannelQuantizationParams { + // The following members typically point to the corresponding members of a + // TfLiteAffineQuantization struct. + const float* scale; + const int32_t* zero_point; + int32_t quantized_dimension; +}; + +// Gets next index to iterate through a multidimensional array. +inline bool NextIndex(const int num_dims, const int* dims, int* current) { + if (num_dims == 0) { + return false; + } + TFLITE_DCHECK(dims != nullptr); + TFLITE_DCHECK(current != nullptr); + int carry = 1; + for (int idx = num_dims - 1; idx >= 0; --idx) { + int current_val = current[idx] + carry; + TFLITE_DCHECK_GE(dims[idx], current_val); + if (dims[idx] == current_val) { + current[idx] = 0; + } else { + current[idx] = current_val; + carry = 0; + break; + } + } + return (carry == 0); +} + +// Gets offset of index if reducing on axis. When reducing, the flattened offset +// will not change, if the input index changes on the given axis. For example, +// if you have a 3D tensor and you are reducing to 2D by eliminating axis 0, +// then index (0, 1, 2) and index (1, 1, 2) will map to the same flattened +// offset. +// TODO(kanlig): uses Dims to represent dimensions. +inline size_t ReducedOutputOffset(const int num_dims, const int* dims, + const int* index, const int num_axis, + const int* axis) { + if (num_dims == 0) { + return 0; + } + TFLITE_DCHECK(dims != nullptr); + TFLITE_DCHECK(index != nullptr); + size_t offset = 0; + for (int idx = 0; idx < num_dims; ++idx) { + // if we need to skip this axis + bool is_axis = false; + if (axis != nullptr) { + for (int axis_idx = 0; axis_idx < num_axis; ++axis_idx) { + if (idx == axis[axis_idx]) { + is_axis = true; + break; + } + } + } + if (!is_axis) { + offset = offset * static_cast(dims[idx]) + + static_cast(index[idx]); + } + } + return offset; +} + +// Since tensors with '0' in their shape are valid in TF, these offset functions +// allow that as long as the corresponding index is also 0. It is upto the +// calling ops to ensure that they perform verification checks on tensor shapes +// if they don't support a particular behavior. + +inline int Offset(const Dims<4>& dims, int i0, int i1, int i2, int i3) { + TFLITE_DCHECK((i0 == 0 && dims.sizes[0] == 0) || + (i0 >= 0 && i0 < dims.sizes[0])); + TFLITE_DCHECK((i1 == 0 && dims.sizes[1] == 0) || + (i1 >= 0 && i1 < dims.sizes[1])); + TFLITE_DCHECK((i2 == 0 && dims.sizes[2] == 0) || + (i2 >= 0 && i2 < dims.sizes[2])); + TFLITE_DCHECK((i3 == 0 && dims.sizes[3] == 0) || + (i3 >= 0 && i3 < dims.sizes[3])); + return i0 * dims.strides[0] + i1 * dims.strides[1] + i2 * dims.strides[2] + + i3 * dims.strides[3]; +} + +inline int Offset(const Dims<4>& dims, int* index) { + return Offset(dims, index[0], index[1], index[2], index[3]); +} + +// Get array size, DCHECKing that the dim index is in range. +// +// Note that this will be phased out with Dims<4>, since RuntimeShape::Dims() +// already performs this check. +template +int ArraySize(const Dims& array, int index) { + TFLITE_DCHECK(index >= 0 && index < N); + return array.sizes[index]; +} + +// Get common array size, DCHECKing that they all agree. +template +int MatchingArraySize(const ArrayType1& array1, int index1, + const ArrayType2& array2, int index2) { + TFLITE_DCHECK_EQ(ArraySize(array1, index1), ArraySize(array2, index2)); + return ArraySize(array1, index1); +} + +template +int MatchingArraySize(const ArrayType1& array1, int index1, + const ArrayType2& array2, int index2, Args... args) { + TFLITE_DCHECK_EQ(ArraySize(array1, index1), ArraySize(array2, index2)); + return MatchingArraySize(array1, index1, args...); +} + +// Get common shape dim, DCHECKing that they all agree. +inline int MatchingDim(const RuntimeShape& shape1, int index1, + const RuntimeShape& shape2, int index2) { + TFLITE_DCHECK_EQ(shape1.Dims(index1), shape2.Dims(index2)); + return std::min(shape1.Dims(index1), shape2.Dims(index2)); +} + +template +int MatchingDim(const RuntimeShape& shape1, int index1, + const RuntimeShape& shape2, int index2, Args... args) { + TFLITE_DCHECK_EQ(shape1.Dims(index1), shape2.Dims(index2)); + return MatchingDim(shape1, index1, args...); +} + +// Will be phased out with Dims<4>, replaced by RuntimeShape::FlatSize(). +template +inline int FlatSize(const Dims& dims) { + int flat_size = 1; + for (int i = 0; i < N; ++i) { + flat_size *= dims.sizes[i]; + } + return flat_size; +} + +TFLITE_DEPRECATED("Prefer FlatSize.") +inline int RequiredBufferSizeForDims(const Dims<4>& dims) { + return FlatSize(dims); +} + +inline int MatchingElementsSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0) { + const int size_1 = shape.FlatSize(); + const int size_2 = check_shape_0.FlatSize(); + TFLITE_CHECK_EQ(size_1, size_2); + return size_1; +} + +inline int MatchingElementsSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1) { + const int size_1 = shape.FlatSize(); + const int size_2 = check_shape_0.FlatSize(); + const int size_3 = check_shape_1.FlatSize(); + TFLITE_CHECK_EQ(size_1, size_2); + TFLITE_CHECK_EQ(size_2, size_3); + return size_1; +} + +// Flat size calculation, checking that dimensions match with one or more other +// arrays. +inline int MatchingFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0) { + TFLITE_DCHECK_EQ(shape.DimensionsCount(), check_shape_0.DimensionsCount()); + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + return shape.FlatSize(); +} + +inline int MatchingFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1) { + TFLITE_DCHECK_EQ(shape.DimensionsCount(), check_shape_0.DimensionsCount()); + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + return MatchingFlatSize(shape, check_shape_1); +} + +inline int MatchingFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1, + const RuntimeShape& check_shape_2) { + TFLITE_DCHECK_EQ(shape.DimensionsCount(), check_shape_0.DimensionsCount()); + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + return MatchingFlatSize(shape, check_shape_1, check_shape_2); +} + +inline int MatchingFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1, + const RuntimeShape& check_shape_2, + const RuntimeShape& check_shape_3) { + TFLITE_DCHECK_EQ(shape.DimensionsCount(), check_shape_0.DimensionsCount()); + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + return MatchingFlatSize(shape, check_shape_1, check_shape_2, check_shape_3); +} + +// Flat size calculation, checking that dimensions match with one or more other +// arrays. +template +inline int MatchingFlatSize(const Dims& dims, const Dims& check_dims_0) { + for (int i = 0; i < N; ++i) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + return FlatSize(dims); +} + +template +inline int MatchingFlatSize(const Dims& dims, const Dims& check_dims_0, + const Dims& check_dims_1) { + for (int i = 0; i < N; ++i) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + return MatchingFlatSize(dims, check_dims_1); +} + +template +inline int MatchingFlatSize(const Dims& dims, const Dims& check_dims_0, + const Dims& check_dims_1, + const Dims& check_dims_2) { + for (int i = 0; i < N; ++i) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + return MatchingFlatSize(dims, check_dims_1, check_dims_2); +} + +template +inline int MatchingFlatSize(const Dims& dims, const Dims& check_dims_0, + const Dims& check_dims_1, + const Dims& check_dims_2, + const Dims& check_dims_3) { + for (int i = 0; i < N; ++i) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + return MatchingFlatSize(dims, check_dims_1, check_dims_2, check_dims_3); +} + +// Flat size calculation, checking if their extended shapes match. +inline int MatchingExtendedShapeFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0) { + const int shape_dims = shape.DimensionsCount(); + const int check_shape_0_dims = check_shape_0.DimensionsCount(); + const int min_dims = std::min(shape_dims, check_shape_0_dims); + + for (int i = 0; i < min_dims; ++i) { + TFLITE_DCHECK_EQ(shape.Dims(shape_dims - 1 - i), + check_shape_0.Dims(check_shape_0_dims - 1 - i)); + } + for (int i = min_dims; i < shape_dims; ++i) { + TFLITE_DCHECK_EQ(shape.Dims(shape_dims - 1 - i), 1); + } + for (int i = min_dims; i < check_shape_0_dims; ++i) { + TFLITE_DCHECK_EQ(check_shape_0.Dims(check_shape_0_dims - 1 - i), 1); + } + return shape.FlatSize(); +} + +inline int MatchingExtendedShapeFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1) { + const int flat_size = MatchingExtendedShapeFlatSize(shape, check_shape_0); + TFLITE_DCHECK_EQ(MatchingExtendedShapeFlatSize(shape, check_shape_1), + flat_size); + return flat_size; +} + +inline int MatchingExtendedShapeFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1, + const RuntimeShape& check_shape_2) { + const int flat_size = MatchingExtendedShapeFlatSize(shape, check_shape_0); + TFLITE_DCHECK_EQ( + MatchingExtendedShapeFlatSize(shape, check_shape_1, check_shape_2), + flat_size); + return flat_size; +} + +inline int MatchingExtendedShapeFlatSize(const RuntimeShape& shape, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1, + const RuntimeShape& check_shape_2, + const RuntimeShape& check_shape_3) { + const int flat_size = MatchingExtendedShapeFlatSize(shape, check_shape_0); + TFLITE_DCHECK_EQ(MatchingExtendedShapeFlatSize(shape, check_shape_1, + check_shape_2, check_shape_3), + flat_size); + return flat_size; +} + +// Data is required to be contiguous, and so many operators can use either the +// full array flat size or the flat size with one dimension skipped (commonly +// the depth). +template +inline int FlatSizeSkipDim(const Dims& dims, int skip_dim) { + TFLITE_DCHECK(skip_dim >= 0 && skip_dim < N); + int flat_size = 1; + for (int i = 0; i < N; ++i) { + flat_size *= (i == skip_dim) ? 1 : dims.sizes[i]; + } + return flat_size; +} + +// A combination of MatchingFlatSize() and FlatSizeSkipDim(). +template +inline int MatchingFlatSizeSkipDim(const Dims& dims, int skip_dim, + const Dims& check_dims_0) { + for (int i = 0; i < N; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + } + return FlatSizeSkipDim(dims, skip_dim); +} + +template +inline int MatchingFlatSizeSkipDim(const Dims& dims, int skip_dim, + const Dims& check_dims_0, + const Dims& check_dims_1) { + for (int i = 0; i < N; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + } + return MatchingFlatSizeSkipDim(dims, skip_dim, check_dims_1); +} + +template +inline int MatchingFlatSizeSkipDim(const Dims& dims, int skip_dim, + const Dims& check_dims_0, + const Dims& check_dims_1, + const Dims& check_dims_2) { + for (int i = 0; i < N; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + } + return MatchingFlatSizeSkipDim(dims, skip_dim, check_dims_1, check_dims_2); +} + +template +inline int MatchingFlatSizeSkipDim(const Dims& dims, int skip_dim, + const Dims& check_dims_0, + const Dims& check_dims_1, + const Dims& check_dims_2, + const Dims& check_dims_3) { + for (int i = 0; i < N; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(ArraySize(dims, i), ArraySize(check_dims_0, i)); + } + } + return MatchingFlatSizeSkipDim(dims, skip_dim, check_dims_1, check_dims_2, + check_dims_3); +} + +// Data is required to be contiguous, and so many operators can use either the +// full array flat size or the flat size with one dimension skipped (commonly +// the depth). +inline int FlatSizeSkipDim(const RuntimeShape& shape, int skip_dim) { + const int dims_count = shape.DimensionsCount(); + TFLITE_DCHECK(skip_dim >= 0 && skip_dim < dims_count); + const auto* dims_data = shape.DimsData(); + int flat_size = 1; + for (int i = 0; i < dims_count; ++i) { + flat_size *= (i == skip_dim) ? 1 : dims_data[i]; + } + return flat_size; +} + +// A combination of MatchingFlatSize() and FlatSizeSkipDim(). +inline int MatchingFlatSizeSkipDim(const RuntimeShape& shape, int skip_dim, + const RuntimeShape& check_shape_0) { + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + } + return FlatSizeSkipDim(shape, skip_dim); +} + +inline int MatchingFlatSizeSkipDim(const RuntimeShape& shape, int skip_dim, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1) { + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + } + return MatchingFlatSizeSkipDim(shape, skip_dim, check_shape_1); +} + +inline int MatchingFlatSizeSkipDim(const RuntimeShape& shape, int skip_dim, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1, + const RuntimeShape& check_shape_2) { + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + } + return MatchingFlatSizeSkipDim(shape, skip_dim, check_shape_1, check_shape_2); +} + +inline int MatchingFlatSizeSkipDim(const RuntimeShape& shape, int skip_dim, + const RuntimeShape& check_shape_0, + const RuntimeShape& check_shape_1, + const RuntimeShape& check_shape_2, + const RuntimeShape& check_shape_3) { + const int dims_count = shape.DimensionsCount(); + for (int i = 0; i < dims_count; ++i) { + if (i != skip_dim) { + TFLITE_DCHECK_EQ(shape.Dims(i), check_shape_0.Dims(i)); + } + } + return MatchingFlatSizeSkipDim(shape, skip_dim, check_shape_1, check_shape_2, + check_shape_3); +} + +template +bool IsPackedWithoutStrides(const Dims& dims) { + int expected_stride = 1; + for (int d = 0; d < N; d++) { + if (dims.strides[d] != expected_stride) return false; + expected_stride *= dims.sizes[d]; + } + return true; +} + +template +void ComputeStrides(Dims* dims) { + dims->strides[0] = 1; + for (int d = 1; d < N; d++) { + dims->strides[d] = dims->strides[d - 1] * dims->sizes[d - 1]; + } +} + +enum class BroadcastableOpCategory : uint8_t { + kNone, + kNonBroadcast, // Matching input shapes. + kFirstInputBroadcastsFast, // Fivefold nested loops. + kSecondInputBroadcastsFast, // Fivefold nested loops. + kGenericBroadcast, // Fall-back. +}; + +struct MinMax { + float min; + float max; +}; +static_assert(sizeof(MinMax) == 8, ""); + +struct ActivationParams { + FusedActivationFunctionType activation_type; + // uint8_t, etc, activation params. + int32_t quantized_activation_min; + int32_t quantized_activation_max; +}; + +struct ReluParams : public ActivationParams { + int32_t input_offset; + int32_t output_offset; + int32_t output_multiplier; + int output_shift; +}; + +// Styles of resizing op usages. For example, kImageStyle can be used with a Pad +// op for pattern-specific optimization. +enum class ResizingCategory : uint8_t { + kNone, + kImageStyle, // 4D, operating on inner dimensions, say {0, a, b, 0}. + kGenericResize, +}; + +// For Add, Sub, Mul ops. +struct ArithmeticParams { + // Shape dependent / common to data / op types. + BroadcastableOpCategory broadcast_category; + // uint8_t inference params. + int32_t input1_offset; + int32_t input2_offset; + int32_t output_offset; + int32_t output_multiplier; + int output_shift; + // Add / Sub, not Mul, uint8_t inference params. + int left_shift; + int32_t input1_multiplier; + int input1_shift; + int32_t input2_multiplier; + int input2_shift; + + // TODO(b/158622529): Union the following activation params. + // uint8_t, etc, activation params. + int32_t quantized_activation_min; + int32_t quantized_activation_max; + // float activation params. + float float_activation_min; + float float_activation_max; + // int64_t activation params. + int64_t int64_activation_min; + int64_t int64_activation_max; + + // Processed output dimensions. + // Let input "a" be the one that broadcasts in the faster-changing dimension. + // Then, after coalescing, for shapes {a0, a1, a2, a3, a4} and + // {b0, b1, b2, b3, b4}, + // broadcast_shape[4] = b0 = a0. + // broadcast_shape[3] = b1; a1 = 1. + // broadcast_shape[2] = b2 = a2. + // broadcast_shape[1] = a3; b3 = 1. + // broadcast_shape[0] = b4 = a4. + int broadcast_shape[5]; +}; + +struct ConcatenationParams { + int8_t axis; + const int32_t* input_zeropoint; + const float* input_scale; + uint16_t inputs_count; + int32_t output_zeropoint; + float output_scale; +}; + +struct ComparisonParams { + // uint8_t inference params. + int left_shift; + int32_t input1_offset; + int32_t input1_multiplier; + int input1_shift; + int32_t input2_offset; + int32_t input2_multiplier; + int input2_shift; + // Shape dependent / common to inference types. + bool is_broadcast; +}; + +struct ConvParams { + PaddingType padding_type; + PaddingValues padding_values; + // TODO(starka): This was just "stride", so check that width+height is OK. + int16_t stride_width; + int16_t stride_height; + int16_t dilation_width_factor; + int16_t dilation_height_factor; + // uint8_t inference params. + // TODO(b/65838351): Use smaller types if appropriate. + int32_t input_offset; + int32_t weights_offset; + int32_t output_offset; + int32_t output_multiplier; + int output_shift; + // uint8_t, etc, activation params. + int32_t quantized_activation_min; + int32_t quantized_activation_max; + // float activation params. + float float_activation_min; + float float_activation_max; +}; + +struct Conv3DParams { + Padding3DValues padding_values; + int stride_width; + int stride_height; + int stride_depth; + int dilation_width; + int dilation_height; + int dilation_depth; + // float activation params. + float float_activation_min; + float float_activation_max; +}; + +typedef Conv3DParams Conv3DTransposeParams; + +struct DepthToSpaceParams { + int32_t block_size; +}; + +struct DepthwiseParams { + PaddingType padding_type; + PaddingValues padding_values; + int16_t stride_width; + int16_t stride_height; + int16_t dilation_width_factor; + int16_t dilation_height_factor; + int16_t depth_multiplier; + // uint8_t inference params. + // TODO(b/65838351): Use smaller types if appropriate. + int32_t input_offset; + int32_t weights_offset; + int32_t output_offset; + int32_t output_multiplier; + int output_shift; + // uint8_t, etc, activation params. + int32_t quantized_activation_min; + int32_t quantized_activation_max; + // float activation params. + float float_activation_min; + float float_activation_max; + const int32_t* output_multiplier_per_channel; + const int32_t* output_shift_per_channel; +}; + +struct DequantizationParams { + double scale; + int32_t zero_point; +}; + +struct PerChannelDequantizationParams { + const float* scale; + const int32_t* zero_point; + int32_t quantized_dimension; +}; + +struct FakeQuantParams { + MinMax minmax; + int32_t num_bits; +}; + +struct FullyConnectedParams { + // uint8_t inference params. + // TODO(b/65838351): Use smaller types if appropriate. + int32_t input_offset; + int32_t weights_offset; + int32_t output_offset; + int32_t output_multiplier; + int output_shift; + // uint8_t, etc, activation params. + int32_t quantized_activation_min; + int32_t quantized_activation_max; + // float activation params. + float float_activation_min; + float float_activation_max; + // Mark the operands as cacheable if they are unchanging, e.g. weights. + bool lhs_cacheable; + bool rhs_cacheable; + FullyConnectedWeightsFormat weights_format; +}; + +struct GatherParams { + int16_t axis; + int16_t batch_dims; +}; + +struct L2NormalizationParams { + // uint8_t inference params. + int32_t input_zero_point; +}; + +struct LocalResponseNormalizationParams { + int32_t range; + double bias; + double alpha; + double beta; +}; + +struct HardSwishParams { + // zero_point of the input activations. + int16_t input_zero_point; + // zero_point of the output activations. + int16_t output_zero_point; + // 16bit fixed-point component of the multiplier to apply to go from the + // "high-res input scale", which is the input scale multiplied by 2^7, to the + // "relu-ish scale", which 3.0/32768. + // See the implementation of HardSwishPrepare. + int16_t reluish_multiplier_fixedpoint_int16; + // exponent/bit-shift component of the aforementioned multiplier. + int reluish_multiplier_exponent; + // 16bit fixed-point component of the multiplier to apply to go from the + // "high-res input scale", which is the input scale multiplied by 2^7, to the + // output scale. + // See the implementation of HardSwishPrepare. + int16_t output_multiplier_fixedpoint_int16; + // exponent/bit-shift component of the aforementioned multiplier. + int output_multiplier_exponent; +}; + +struct LogisticParams { + // uint8_t inference params. + int32_t input_zero_point; + int32_t input_range_radius; + int32_t input_multiplier; + int input_left_shift; +}; + +struct LstmCellParams { + int32_t weights_zero_point; + int32_t accum_multiplier; + int accum_shift; + int state_integer_bits; +}; + +struct MeanParams { + int8_t axis_count; + int16_t axis[4]; +}; + +struct PackParams { + int8_t axis; + const int32_t* input_zeropoint; + const float* input_scale; + uint16_t inputs_count; + int32_t output_zeropoint; + float output_scale; +}; + +struct PadParams { + int8_t left_padding_count; + int32_t left_padding[5]; + int8_t right_padding_count; + int32_t right_padding[5]; + ResizingCategory resizing_category; +}; + +struct PreluParams { + int32_t input_offset; + int32_t alpha_offset; + int32_t output_offset; + int32_t output_multiplier_1; + int output_shift_1; + int32_t output_multiplier_2; + int output_shift_2; +}; + +struct PoolParams { + FusedActivationFunctionType activation; + PaddingType padding_type; + PaddingValues padding_values; + int stride_height; + int stride_width; + int filter_height; + int filter_width; + // uint8_t, etc, activation params. + int32_t quantized_activation_min; + int32_t quantized_activation_max; + // float activation params. + float float_activation_min; + float float_activation_max; +}; + +struct ReshapeParams { + int8_t shape_count; + int32_t shape[4]; +}; + +struct ResizeBilinearParams { + bool align_corners; + // half_pixel_centers assumes pixels are of half the actual dimensions, and + // yields more accurate resizes. Corresponds to the same argument for the + // original TensorFlow op in TF2.0. + bool half_pixel_centers; +}; + +struct ResizeNearestNeighborParams { + bool align_corners; + bool half_pixel_centers; +}; + +struct SliceParams { + int8_t begin_count; + int32_t begin[5]; + int8_t size_count; + int32_t size[5]; +}; + +struct SoftmaxParams { + // beta is not really used (not a Tensorflow parameter) and not implemented + // for LogSoftmax. + double beta; + // uint8_t inference params. Used even when beta defaults to 1.0. + int32_t input_multiplier; + int32_t input_left_shift; + // Reverse scaling is only used by LogSoftmax. + int32_t reverse_scaling_divisor; + int32_t reverse_scaling_right_shift; + int diff_min; + int32_t zero_point; + float scale; + float* table; + // int16 LUT for exp(x), where x uniform distributed between [-10.0 , 0.0] + int16_t* exp_lut; + // int16 LUT for 1 / (1 + x), where x uniform distributed between [0.0 , 1.0] + int16_t* one_over_one_plus_x_lut; + uint8_t* uint8_table1; + uint8_t* uint8_table2; +}; + +struct SpaceToBatchParams { + // "Zero" padding for uint8_t means padding with the output offset. + int32_t output_offset; +}; + +struct SpaceToDepthParams { + int32_t block_size; +}; + +struct SplitParams { + // Graphs that split into, say, 2000 nodes are encountered. The indices in + // OperatorEdges are of type uint16_t. + uint16_t num_split; + int16_t axis; +}; + +struct SqueezeParams { + int8_t squeeze_dims_count; + int32_t squeeze_dims[4]; +}; + +struct StridedSliceParams { + int8_t start_indices_count; + int32_t start_indices[5]; + int8_t stop_indices_count; + int32_t stop_indices[5]; + int8_t strides_count; + int32_t strides[5]; + + uint16_t begin_mask; + uint16_t ellipsis_mask; + uint16_t end_mask; + uint16_t new_axis_mask; + uint16_t shrink_axis_mask; +}; + +struct TanhParams { + int32_t input_zero_point; + int32_t input_range_radius; + int32_t input_multiplier; + int input_left_shift; +}; + +struct TransposeParams { + int8_t perm_count; + int32_t perm[5]; +}; + +struct UnpackParams { + uint16_t num_split; + int16_t axis; +}; + +struct LeakyReluParams { + float alpha; + int32_t input_offset; + int32_t output_offset; + int32_t output_multiplier_alpha; + int32_t output_shift_alpha; + int32_t output_multiplier_identity; + int32_t output_shift_identity; +}; + +template +inline void SetActivationParams(float min, float max, P* params) { + params->float_activation_min = min; + params->float_activation_max = max; +} + +template +inline void SetActivationParams(int32_t min, int32_t max, P* params) { + params->quantized_activation_min = min; + params->quantized_activation_max = max; +} + +template +inline void SetActivationParams(int64_t min, int64_t max, P* params) { + params->int64_activation_min = min; + params->int64_activation_max = max; +} + +template +inline void GetActivationParams(const P& params, int32_t* min, int32_t* max) { + *min = params.quantized_activation_min; + *max = params.quantized_activation_max; +} + +template +inline void GetActivationParams(const P& params, float* min, float* max) { + *min = params.float_activation_min; + *max = params.float_activation_max; +} + +template +inline void GetActivationParams(const P& params, int64_t* min, int64_t* max) { + *min = params.int64_activation_min; + *max = params.int64_activation_max; +} + +// Type trait to check of given type has size smaller than 4 bytes. +template +struct is_small_integer + : public std::integral_constant::value || + std::is_same::value || + std::is_same::value || + std::is_same::value> {}; + +// Type trait to check of given type is int32 or int64. +template +struct is_int32_or_int64 + : public std::integral_constant::value || + std::is_same::value> { +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_TYPES_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/kernel_util.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/kernel_util.cpp new file mode 100644 index 000000000..e8b2dfd61 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/kernel_util.cpp @@ -0,0 +1,594 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/kernel_util.h" + +#include +#include + +#include +#include +#include +#include +#ifndef ARDUINO +#include +#endif // ARDUINO + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/context_util.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" + +#if defined(__APPLE__) +#include "TargetConditionals.h" +#endif + +namespace tflite { + +namespace { + +// Assumes tensor_index is a valid index (in bounds) +inline TfLiteTensor* GetTensorAtIndex(const TfLiteContext* context, + int tensor_index) { + if (context->tensors != nullptr) { + return &context->tensors[tensor_index]; + } else { + return context->GetTensor(context, tensor_index); + } +} + +// Validate in a single place to reduce binary size +inline TfLiteStatus ValidateTensorIndexingSafe(const TfLiteContext* context, + int index, int max_size, + const int* tensor_indices, + int* tensor_index) { + if (index < 0 || index >= max_size) { + TF_LITE_KERNEL_LOG(const_cast(context), + "Invalid tensor index %d (not in [0, %d))\n", index, + max_size); + return kTfLiteError; + } + if (tensor_indices[index] == kTfLiteOptionalTensor) { + TF_LITE_KERNEL_LOG(const_cast(context), + "Tensor at index %d was optional but was expected\n", + index); + return kTfLiteError; + } + + *tensor_index = tensor_indices[index]; + return kTfLiteOk; +} + +// Same as above but returns -1 for invalid inputs instead of status + logging +// error. +inline int ValidateTensorIndexing(const TfLiteContext* context, int index, + int max_size, const int* tensor_indices) { + if (index >= 0 && index < max_size) { + const int tensor_index = tensor_indices[index]; + if (tensor_index != kTfLiteOptionalTensor) { + return tensor_index; + } + } + return -1; +} + +inline TfLiteTensor* GetMutableInput(const TfLiteContext* context, + const TfLiteNode* node, int index) { + const int tensor_index = ValidateTensorIndexing( + context, index, node->inputs->size, node->inputs->data); + if (tensor_index < 0) { + return nullptr; + } + return GetTensorAtIndex(context, tensor_index); +} + +inline TfLiteStatus GetMutableInputSafe(const TfLiteContext* context, + const TfLiteNode* node, int index, + const TfLiteTensor** tensor) { + int tensor_index; + TF_LITE_ENSURE_OK( + context, ValidateTensorIndexingSafe(context, index, node->inputs->size, + node->inputs->data, &tensor_index)); + *tensor = GetTensorAtIndex(context, tensor_index); + return kTfLiteOk; +} + +} // anonymous namespace. + +const TfLiteTensor* GetInput(const TfLiteContext* context, + const TfLiteNode* node, int index) { + return GetMutableInput(context, node, index); +} + +TfLiteStatus GetInputSafe(const TfLiteContext* context, const TfLiteNode* node, + int index, const TfLiteTensor** tensor) { + return GetMutableInputSafe(context, node, index, tensor); +} + +TfLiteTensor* GetVariableInput(TfLiteContext* context, const TfLiteNode* node, + int index) { + TfLiteTensor* tensor = GetMutableInput(context, node, index); + if (tensor == nullptr) return nullptr; + return tensor->is_variable ? tensor : nullptr; +} + +TfLiteTensor* GetOutput(TfLiteContext* context, const TfLiteNode* node, + int index) { + const int tensor_index = ValidateTensorIndexing( + context, index, node->outputs->size, node->outputs->data); + if (tensor_index < 0) { + return nullptr; + } + return GetTensorAtIndex(context, tensor_index); +} + +TfLiteStatus GetOutputSafe(const TfLiteContext* context, const TfLiteNode* node, + int index, TfLiteTensor** tensor) { + int tensor_index; + TF_LITE_ENSURE_OK( + context, ValidateTensorIndexingSafe(context, index, node->outputs->size, + node->outputs->data, &tensor_index)); + *tensor = GetTensorAtIndex(context, tensor_index); + return kTfLiteOk; +} + +const TfLiteTensor* GetOptionalInputTensor(const TfLiteContext* context, + const TfLiteNode* node, int index) { + return GetInput(context, node, index); +} + +#ifndef ARDUINO +TfLiteTensor* GetTemporary(TfLiteContext* context, const TfLiteNode* node, + int index) { + const int tensor_index = ValidateTensorIndexing( + context, index, node->temporaries->size, node->temporaries->data); + if (tensor_index < 0) { + return nullptr; + } + return GetTensorAtIndex(context, tensor_index); +} + +TfLiteStatus GetTemporarySafe(const TfLiteContext* context, + const TfLiteNode* node, int index, + TfLiteTensor** tensor) { + int tensor_index; + TF_LITE_ENSURE_OK(context, ValidateTensorIndexingSafe( + context, index, node->temporaries->size, + node->temporaries->data, &tensor_index)); + *tensor = GetTensorAtIndex(context, tensor_index); + return kTfLiteOk; +} + +const TfLiteTensor* GetIntermediates(TfLiteContext* context, + const TfLiteNode* node, int index) { + const int tensor_index = ValidateTensorIndexing( + context, index, node->intermediates->size, node->intermediates->data); + if (tensor_index < 0) { + return nullptr; + } + return GetTensorAtIndex(context, tensor_index); +} + +TfLiteStatus GetIntermediatesSafe(const TfLiteContext* context, + const TfLiteNode* node, int index, + TfLiteTensor** tensor) { + int tensor_index; + TF_LITE_ENSURE_OK(context, ValidateTensorIndexingSafe( + context, index, node->intermediates->size, + node->intermediates->data, &tensor_index)); + *tensor = GetTensorAtIndex(context, tensor_index); + return kTfLiteOk; +} +#endif // ARDUINO + +// Per-axis +TfLiteStatus PopulateConvolutionQuantizationParams( + TfLiteContext* context, const TfLiteTensor* input, + const TfLiteTensor* filter, const TfLiteTensor* bias, TfLiteTensor* output, + const TfLiteFusedActivation& activation, int32_t* multiplier, int* shift, + int32_t* output_activation_min, int32_t* output_activation_max, + int32_t* per_channel_multiplier, int32_t* per_channel_shift) { + const auto* affine_quantization = + reinterpret_cast(filter->quantization.params); + return PopulateConvolutionQuantizationParams( + context, input, filter, bias, output, activation, multiplier, shift, + output_activation_min, output_activation_max, per_channel_multiplier, + per_channel_shift, affine_quantization->scale->size); +} + +// Per-axis & per-tensor +TfLiteStatus PopulateConvolutionQuantizationParams( + TfLiteContext* context, const TfLiteTensor* input, + const TfLiteTensor* filter, const TfLiteTensor* bias, TfLiteTensor* output, + const TfLiteFusedActivation& activation, int32_t* multiplier, int* shift, + int32_t* output_activation_min, int32_t* output_activation_max, + int32_t* per_channel_multiplier, int32_t* per_channel_shift, + int num_channels) { + TF_LITE_ENSURE_EQ(context, input->quantization.type, + kTfLiteAffineQuantization); + TF_LITE_ENSURE_EQ(context, filter->quantization.type, + kTfLiteAffineQuantization); + // TODO(jianlijianli): Enable bias type check and bias scale == input scale + // * filter scale for each channel in affine quantization once bias + // quantization is properly populated. + // TF_LITE_ENSURE_EQ(context, bias->quantization.type, + // kTfLiteAffineQuantization); + + // Check data type. + const auto* affine_quantization = + reinterpret_cast(filter->quantization.params); + TF_LITE_ENSURE(context, affine_quantization); + TF_LITE_ENSURE(context, affine_quantization->scale); + const bool is_per_channel = affine_quantization->scale->size > 1; + if (is_per_channel) { + // Currently only Int8/Int16 is supported for per channel quantization. + TF_LITE_ENSURE(context, + input->type == kTfLiteInt8 || input->type == kTfLiteInt16); + TF_LITE_ENSURE(context, + filter->type == kTfLiteInt8 || filter->type == kTfLiteInt4); + TF_LITE_ENSURE_EQ(context, affine_quantization->scale->size, num_channels); + TF_LITE_ENSURE_EQ( + context, num_channels, + filter->dims->data[affine_quantization->quantized_dimension]); + } + + // Populate multiplier and shift using affine quantization. + const float input_scale = input->params.scale; + const float output_scale = output->params.scale; + const float* filter_scales = affine_quantization->scale->data; + for (int i = 0; i < num_channels; ++i) { + // If per-tensor quantization parameter is specified, broadcast it along the + // quantization dimension (channels_out). + const float scale = is_per_channel ? filter_scales[i] : filter_scales[0]; + const double filter_scale = static_cast(scale); + const double effective_output_scale = static_cast(input_scale) * + filter_scale / + static_cast(output_scale); + int32_t significand; + int channel_shift; + QuantizeMultiplier(effective_output_scale, &significand, &channel_shift); + per_channel_multiplier[i] = significand; + per_channel_shift[i] = channel_shift; + } + + // Populate scalar quantization parameters. + // This check on legacy quantization parameters is kept only for backward + // compatibility. + if (input->type == kTfLiteUInt8) { + // Check bias scale == input scale * filter scale. + double real_multiplier = 0.0; + TF_LITE_ENSURE_STATUS(GetQuantizedConvolutionMultipler( + context, input, filter, bias, output, &real_multiplier)); + int exponent; + + // Populate quantization parameters with multiplier and shift. + QuantizeMultiplier(real_multiplier, multiplier, &exponent); + *shift = -exponent; + } + if (input->type == kTfLiteInt8 || input->type == kTfLiteUInt8 || + input->type == kTfLiteInt16) { + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, activation, output, output_activation_min, + output_activation_max)); + } + return kTfLiteOk; +} + +TfLiteStatus GetQuantizedConvolutionMultipler(TfLiteContext* context, + const TfLiteTensor* input, + const TfLiteTensor* filter, + const TfLiteTensor* bias, + TfLiteTensor* output, + double* multiplier) { + const double input_product_scale = static_cast(input->params.scale) * + static_cast(filter->params.scale); + // The following conditions must be guaranteed by the training pipeline. + if (bias) { + const double bias_scale = static_cast(bias->params.scale); + // Here we're making sure the input_product_scale & bias_scale are about the + // same. Since we have: + // (output - output_zp) * output_scale = + // input_product_scale * input_product + bias * bias_scale ---- (0) + // + // (0) equals: + // (input_product + bias) * input_product_scale ----- (1) + // + + // bias * (bias_scale - input_product_scale) ------ (2) + // + // For the real kernel computation, we're doing (1), so we really need to + // make sure (2) has minimum impact on the output, so: + // bias * (bias_scale - input_product_scale) / output_scale should be + // a small number for an integer. + // Since normally bias should be within a small range. + // We should expect (bias_scale - input_product_scale) / output_scale to + // be a small number like 0.02. + const double scale_diff = std::abs(input_product_scale - bias_scale); + const double output_scale = static_cast(output->params.scale); + + TF_LITE_ENSURE(context, scale_diff / output_scale <= 0.02); + } + return GetQuantizedConvolutionMultipler(context, input, filter, output, + multiplier); +} + +TfLiteStatus GetQuantizedConvolutionMultipler(TfLiteContext* context, + const TfLiteTensor* input, + const TfLiteTensor* filter, + TfLiteTensor* output, + double* multiplier) { + const double input_product_scale = + static_cast(input->params.scale * filter->params.scale); + TF_LITE_ENSURE(context, input_product_scale >= 0); + *multiplier = input_product_scale / static_cast(output->params.scale); + + return kTfLiteOk; +} + +namespace { + +inline TfLiteStatus Quantize(TfLiteContext* context, float scale, + int32_t zero_point, float f, int32_t& q) { + const float tmp = TfLiteRound(f / scale); + const bool no_integer_overflow_from_quantization = + (tmp >= static_cast(std::numeric_limits::min()) && + tmp <= static_cast(std::numeric_limits::max())); + TF_LITE_ENSURE(context, no_integer_overflow_from_quantization); + q = zero_point + static_cast(tmp); + return kTfLiteOk; +} + +TfLiteStatus CalculateActivationRangeQuantizedImpl( + TfLiteContext* context, TfLiteFusedActivation activation, int32_t qmin, + int32_t qmax, TfLiteTensor* output, int32_t* act_min, int32_t* act_max) { + const auto scale = output->params.scale; + const auto zero_point = output->params.zero_point; + + int32_t tmp_q; + if (activation == kTfLiteActRelu) { + TF_LITE_ENSURE_OK(context, + Quantize(context, scale, zero_point, 0.0, tmp_q)); + *act_min = std::max(qmin, tmp_q); + *act_max = qmax; + } else if (activation == kTfLiteActRelu6) { + TF_LITE_ENSURE_OK(context, + Quantize(context, scale, zero_point, 0.0, tmp_q)); + *act_min = std::max(qmin, tmp_q); + TF_LITE_ENSURE_OK(context, + Quantize(context, scale, zero_point, 6.0, tmp_q)); + *act_max = std::min(qmax, tmp_q); + } else if (activation == kTfLiteActReluN1To1) { + TF_LITE_ENSURE_OK(context, + Quantize(context, scale, zero_point, -1.0, tmp_q)); + *act_min = std::max(qmin, tmp_q); + TF_LITE_ENSURE_OK(context, + Quantize(context, scale, zero_point, 1.0, tmp_q)); + *act_max = std::min(qmax, tmp_q); + } else { + *act_min = qmin; + *act_max = qmax; + } + return kTfLiteOk; +} +} // namespace + +TfLiteStatus CalculateActivationRangeQuantized(TfLiteContext* context, + TfLiteFusedActivation activation, + TfLiteTensor* output, + int32_t* act_min, + int32_t* act_max) { + int32_t qmin = 0; + int32_t qmax = 0; + if (output->type == kTfLiteUInt8) { + qmin = std::numeric_limits::min(); + qmax = std::numeric_limits::max(); + } else if (output->type == kTfLiteInt8) { + qmin = std::numeric_limits::min(); + qmax = std::numeric_limits::max(); + } else if (output->type == kTfLiteInt16) { + qmin = std::numeric_limits::min(); + qmax = std::numeric_limits::max(); + } else { + TF_LITE_ENSURE(context, false); + } + + return CalculateActivationRangeQuantizedImpl(context, activation, qmin, qmax, + output, act_min, act_max); +} + +bool HaveSameShapes(const TfLiteTensor* input1, const TfLiteTensor* input2) { + return TfLiteIntArrayEqual(input1->dims, input2->dims); +} + +#ifndef ARDUINO +TfLiteStatus GetOutputShapeFromInput(TfLiteContext* context, + const TfLiteTensor* input, + TfLiteIntArray** output_shape) { + if (NumDimensions(input) != 1) { + TF_LITE_KERNEL_LOG(const_cast(context), + "Invalid %dD input tensor (must be a 1D tensor).", + NumDimensions(input)); + return kTfLiteError; + } + const int output_dims = SizeOfDimension(input, 0); + std::unique_ptr shape( + TfLiteIntArrayCreate(output_dims), TfLiteIntArrayFree); + for (int i = 0; i < output_dims; i++) { + shape->data[i] = input->data.i32[i]; + } + *output_shape = shape.release(); + return kTfLiteOk; +} + +// TODO(b/172067338): Having this function be part of TF_LITE_STATIC_MEMORY +// build results in a 6KB size increase, even though the function is unsused for +// that build. What appears to be happening is that while the linker drops the +// unsused function, the string library that gets pulled in is not dropped, +// resulting in the increased binary size. +const std::string GetShapeDebugString(const TfLiteIntArray* shape) { + std::string str; + for (int d = 0; d < shape->size; ++d) { + if (str.empty()) + str = "[" + std::to_string(shape->data[d]); + else + // Don't add space after "," to make the output consistent with + // tensorflow::shape_inference::InferenceContext::DebugString() + str += "," + std::to_string(shape->data[d]); + } + if (str.empty()) { + str = "[]"; + } else { + str += "]"; + } + return str; +} + +TfLiteStatus CalculateShapeForBroadcast(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteIntArray** output_shape) { + const int dims1 = NumDimensions(input1); + const int dims2 = NumDimensions(input2); + const int out_dims = std::max(dims1, dims2); + + std::unique_ptr shape( + TfLiteIntArrayCreate(out_dims), TfLiteIntArrayFree); + for (int i = 0; i < out_dims; ++i) { + const int d1 = i >= dims1 ? 1 : SizeOfDimension(input1, dims1 - i - 1); + const int d2 = i >= dims2 ? 1 : SizeOfDimension(input2, dims2 - i - 1); + if (!(d1 == d2 || d1 == 1 || d2 == 1)) { + TF_LITE_KERNEL_LOG(context, + "Given shapes, %s and %s, are not broadcastable.", + GetShapeDebugString(input1->dims).c_str(), + GetShapeDebugString(input2->dims).c_str()); + return kTfLiteError; + } + + if (d1 == 0 || d2 == 0) { + shape->data[out_dims - i - 1] = 0; + } else { + shape->data[out_dims - i - 1] = std::max(d1, d2); + } + } + *output_shape = shape.release(); + return kTfLiteOk; +} + +TfLiteStatus CalculateShapeForBroadcast(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + const TfLiteTensor* input3, + TfLiteIntArray** output_shape) { + const int dims1 = NumDimensions(input1); + const int dims2 = NumDimensions(input2); + const int dims3 = NumDimensions(input3); + const int out_dims = std::max(std::max(dims1, dims2), dims3); + std::unique_ptr shape( + TfLiteIntArrayCreate(out_dims), TfLiteIntArrayFree); + for (int i = 0; i < out_dims; ++i) { + const int d1 = i >= dims1 ? 1 : SizeOfDimension(input1, dims1 - i - 1); + const int d2 = i >= dims2 ? 1 : SizeOfDimension(input2, dims2 - i - 1); + const int d3 = i >= dims3 ? 1 : SizeOfDimension(input3, dims3 - i - 1); + const int min_value = std::min(std::min(d1, d2), d3); + int max_value = std::max(std::max(d1, d2), d3); + // If one dimention is 0, others must be 0 or 1. + if (min_value == 0) max_value = 0; + if (!(d1 == 1 || d1 == max_value) || !(d2 == 1 || d2 == max_value) || + !(d3 == 1 || d3 == max_value)) { + TF_LITE_KERNEL_LOG(context, + "Given shapes, %s, %s and %s, are not broadcastable.", + GetShapeDebugString(input1->dims).c_str(), + GetShapeDebugString(input2->dims).c_str(), + GetShapeDebugString(input3->dims).c_str()); + return kTfLiteError; + } + shape->data[out_dims - i - 1] = max_value; + } + *output_shape = shape.release(); + return kTfLiteOk; +} +#endif // ARDUINO + +// Size of string is not constant, return 0 in such case. +int TfLiteTypeGetSize(TfLiteType type) { + switch (type) { + case kTfLiteUInt8: + static_assert(sizeof(uint8_t) == 1, ""); + return 1; + case kTfLiteInt8: + static_assert(sizeof(int8_t) == 1, ""); + return 1; + case kTfLiteBool: + return sizeof(bool); + case kTfLiteUInt16: + static_assert(sizeof(uint16_t) == 2, ""); + return 2; + case kTfLiteInt16: + static_assert(sizeof(int16_t) == 2, ""); + return 2; + case kTfLiteFloat16: + static_assert(sizeof(int16_t) == 2, ""); + return 2; + case kTfLiteFloat32: + static_assert(sizeof(float) == 4, ""); + return 4; + case kTfLiteInt32: + static_assert(sizeof(int32_t) == 4, ""); + return 4; + case kTfLiteUInt32: + static_assert(sizeof(uint32_t) == 4, ""); + return 4; + case kTfLiteInt64: + static_assert(sizeof(int64_t) == 8, ""); + return 8; + case kTfLiteUInt64: + static_assert(sizeof(uint64_t) == 8, ""); + return 8; + case kTfLiteFloat64: + static_assert(sizeof(double) == 8, ""); + return 8; + case kTfLiteComplex64: + static_assert(sizeof(std::complex) == 8, ""); + return 8; + case kTfLiteComplex128: + static_assert(sizeof(std::complex) == 16, ""); + return 16; + default: + return 0; + } +} + +bool IsMobilePlatform() { +#if defined(ANDROID) || defined(__ANDROID__) + return true; +#elif defined(__APPLE__) +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE + return true; +#endif +#endif + return false; +} + +bool HasUnspecifiedDimension(const TfLiteTensor* tensor) { +#ifndef ARDUINO + if (tensor->dims_signature) { + for (int i : TfLiteIntArrayView(tensor->dims_signature)) { + if (i == -1) return true; + } + } +#endif // ARDUINO + return false; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/kernel_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/kernel_util.h new file mode 100644 index 000000000..781e27778 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/kernel_util.h @@ -0,0 +1,330 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_KERNEL_UTIL_H_ +#define TENSORFLOW_LITE_KERNELS_KERNEL_UTIL_H_ + +#include + +#include +#ifndef ARDUINO +#include +#endif // ARDUINO + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// A fair number of functions in this header have historically been inline. +// It is ok to change functions to not be inline if the latency with +// benchmark_model for MobileNet + MobileBERT is unaffected. If such a change is +// made, move the newly non-inlined function declarations to the top of this +// header file. + +// Note: You must check if result is not null: +// +// TfLiteTensor* my_tensor = GetInput(context, node, kMyTensorIdx); +// TF_LITE_ENSURE(context, my_tensor != nullptr); +// +// This is because the index might point to the optional tensor constant +// (kTfLiteOptionalTensor) in which case there is no tensor to return. +const TfLiteTensor* GetInput(const TfLiteContext* context, + const TfLiteNode* node, int index); + +// Same as `GetInput` but returns boolean and uses output argument for tensor. +// +// TfLiteTensor* my_tensor; +// TF_LITE_ENSURE_OK(context, +// GetInputSafe(context, node, kMyTensorIdx, &my_tensor)); +// // can use my_tensor directly from here onwards, it is not nullptr +// +// Should be used in cases where the binary size is too large. +TfLiteStatus GetInputSafe(const TfLiteContext* context, const TfLiteNode* node, + int index, const TfLiteTensor** tensor); + +// Note: You must check if result is not null: +// +// TfLiteTensor* my_tensor = GetVariableInput(context, node, kMyTensorIdx); +// TF_LITE_ENSURE(context, my_tensor != nullptr); +// +// This is because the index might point to the optional tensor constant +// (kTfLiteOptionalTensor) in which case there is no tensor to return. +TfLiteTensor* GetVariableInput(TfLiteContext* context, const TfLiteNode* node, + int index); + +// Note: You must check if result is not null: +// +// TfLiteTensor* my_tensor = GetOutput(context, node, kMyTensorIdx); +// TF_LITE_ENSURE(context, my_tensor != nullptr); +// +// This is because the index might point to the optional tensor constant +// (kTfLiteOptionalTensor) in which case there is no tensor to return. +TfLiteTensor* GetOutput(TfLiteContext* context, const TfLiteNode* node, + int index); + +// Same as `GetOutput` but returns boolean and uses output argument for tensor. +// +// TfLiteTensor* my_tensor; +// TF_LITE_ENSURE_OK(context, +// GetOutputSafe(context, node, kMyTensorIdx, &my_tensor)); +// // can use my_tensor directly from here onwards, it is not nullptr +// +// Should be used in cases where the binary size is too large. +TfLiteStatus GetOutputSafe(const TfLiteContext* context, const TfLiteNode* node, + int index, TfLiteTensor** tensor); + +// Note: You must check if result is not null: +// +// TfLiteTensor* my_tensor = GetOptionalInputTensor(context, node, kIdx); +// TF_LITE_ENSURE(context, my_tensor != nullptr); +// +// This is because the index might point to the optional tensor constant +// (kTfLiteOptionalTensor) in which case there is no tensor to return. +// +// Deprecated. GetInput has the same functionality. +const TfLiteTensor* GetOptionalInputTensor(const TfLiteContext* context, + const TfLiteNode* node, int index); + +#ifndef ARDUINO +// Note: You must check if result is not null: +// +// TfLiteTensor* my_tensor = GetTemporary(context, node, kMyTensorIdx); +// TF_LITE_ENSURE(context, my_tensor != nullptr); +// +// This is because the index might point to the optional tensor constant +// (kTfLiteOptionalTensor) in which case there is no tensor to return. +TfLiteTensor* GetTemporary(TfLiteContext* context, const TfLiteNode* node, + int index); + +// Same as `GetTemporary` but returns boolean and uses output argument for +// tensor. +// +// TfLiteTensor* my_tensor; +// TF_LITE_ENSURE_OK(context, +// GetTemporarySafe(context, node, kMyTensorIdx, +// &my_tensor)); +// // can use my_tensor directly from here onwards, it is not nullptr +// +// Should be used in cases where the binary size is too large. +TfLiteStatus GetTemporarySafe(const TfLiteContext* context, + const TfLiteNode* node, int index, + TfLiteTensor** tensor); + +// Note: You must check if result is not null: +// +// TfLiteTensor* my_tensor = GetIntermediates(context, node, kMyTensorIdx); +// TF_LITE_ENSURE(context, my_tensor != nullptr); +// +// This is because the index might point to the optional tensor constant +// (kTfLiteOptionalTensor) in which case there is no tensor to return. +const TfLiteTensor* GetIntermediates(TfLiteContext* context, + const TfLiteNode* node, int index); + +// Same as `GetIntermediates` but returns boolean and uses output argument for +// tensor. +// +// TfLiteTensor* my_tensor; +// TF_LITE_ENSURE_OK(context, +// GetIntermediatesSafe(context, node, kMyTensorIdx, +// &my_tensor)); +// // can use my_tensor directly from here onwards, it is not nullptr +// +// Should be used in cases where the binary size is too large. +TfLiteStatus GetIntermediatesSafe(const TfLiteContext* context, + const TfLiteNode* node, int index, + TfLiteTensor** tensor); +#endif // ARDUINO + +inline int NumDimensions(const TfLiteTensor* t) { return t->dims->size; } +inline int SizeOfDimension(const TfLiteTensor* t, int dim) { + return t->dims->data[dim]; +} + +inline int NumInputs(const TfLiteNode* node) { + return node->inputs == nullptr ? 0 : node->inputs->size; +} +inline int NumOutputs(const TfLiteNode* node) { + return node->outputs == nullptr ? 0 : node->outputs->size; +} + +#ifndef ARDUINO +inline int NumIntermediates(const TfLiteNode* node) { + return node->intermediates->size; +} +#endif // ARDUINO + +inline int64_t NumElements(const TfLiteIntArray* dims) { + int64_t count = 1; + for (int i = 0; i < dims->size; ++i) { + count *= dims->data[i]; + } + return count; +} + +inline int64_t NumElements(const TfLiteTensor* t) { + return NumElements(t->dims); +} + +inline int64_t NumElements(const int* dims, int num_dims) { + int64_t count = 1; + for (int i = 0; i < num_dims; ++i) { + count *= dims[i]; + } + return count; +} + +// Determines whether tensor is constant. +// TODO(b/138199592): Introduce new query which checks for constant OR +// persistent-read-only, which would be useful for most tensor kernels that +// are potentially dynamic based on the input tensor value availability at the +// time of prepare. +inline bool IsConstantTensor(const TfLiteTensor* tensor) { + return tensor->allocation_type == kTfLiteMmapRo; +} + +inline bool IsConstantOrPersistentTensor(const TfLiteTensor* tensor) { + return IsConstantTensor(tensor) || + (tensor->allocation_type == kTfLitePersistentRo); +} + +// Determines whether tensor is dynamic. Note that a tensor can be non-const and +// not dynamic. This function specifically checks for a dynamic tensor. +inline bool IsDynamicTensor(const TfLiteTensor* tensor) { + return tensor->allocation_type == kTfLiteDynamic; +} + +// Sets tensor to dynamic. +inline void SetTensorToDynamic(TfLiteTensor* tensor) { + if (tensor->allocation_type != kTfLiteDynamic) { + tensor->allocation_type = kTfLiteDynamic; + tensor->data.raw = nullptr; + } +} + +// Sets tensor to persistent and read-only. +inline void SetTensorToPersistentRo(TfLiteTensor* tensor) { + if (tensor->allocation_type != kTfLitePersistentRo) { + tensor->allocation_type = kTfLitePersistentRo; + tensor->data.raw = nullptr; + } +} + +// Determines whether it is a hybrid op - one that has float inputs and +// quantized weights. +inline bool IsHybridOp(const TfLiteTensor* input, const TfLiteTensor* weight) { + return ((weight->type == kTfLiteUInt8 || weight->type == kTfLiteInt8) && + input->type == kTfLiteFloat32); +} + +// Check dimensionality match and populate OpData for Conv and DepthwiseConv. +TfLiteStatus PopulateConvolutionQuantizationParams( + TfLiteContext* context, const TfLiteTensor* input, + const TfLiteTensor* filter, const TfLiteTensor* bias, TfLiteTensor* output, + const TfLiteFusedActivation& activation, int32_t* multiplier, int* shift, + int32_t* output_activation_min, int32_t* output_activation_max, + int32_t* per_channel_multiplier, int32_t* per_channel_shift); + +TfLiteStatus PopulateConvolutionQuantizationParams( + TfLiteContext* context, const TfLiteTensor* input, + const TfLiteTensor* filter, const TfLiteTensor* bias, TfLiteTensor* output, + const TfLiteFusedActivation& activation, int32_t* multiplier, int* shift, + int32_t* output_activation_min, int32_t* output_activation_max, + int32_t* per_channel_multiplier, int32_t* per_channel_shift, + int num_channels); + +// Calculates the multiplication factor for a quantized convolution (or +// quantized depthwise convolution) involving the given tensors. Returns an +// error if the scales of the tensors are not compatible. +TfLiteStatus GetQuantizedConvolutionMultipler(TfLiteContext* context, + const TfLiteTensor* input, + const TfLiteTensor* filter, + const TfLiteTensor* bias, + TfLiteTensor* output, + double* multiplier); + +TfLiteStatus GetQuantizedConvolutionMultipler(TfLiteContext* context, + const TfLiteTensor* input, + const TfLiteTensor* filter, + TfLiteTensor* output, + double* multiplier); + +// Calculates the useful quantized range of an activation layer given its +// activation tensor. +TfLiteStatus CalculateActivationRangeQuantized(TfLiteContext* context, + TfLiteFusedActivation activation, + TfLiteTensor* output, + int32_t* act_min, + int32_t* act_max); + +// Calculates the useful range of an activation layer given its activation +// tensor.a +template +void CalculateActivationRange(TfLiteFusedActivation activation, + T* activation_min, T* activation_max) { + if (activation == kTfLiteActRelu) { + *activation_min = 0; + *activation_max = std::numeric_limits::max(); + } else if (activation == kTfLiteActRelu6) { + *activation_min = 0; + *activation_max = 6; + } else if (activation == kTfLiteActReluN1To1) { + *activation_min = -1; + *activation_max = 1; + } else { + *activation_min = std::numeric_limits::lowest(); + *activation_max = std::numeric_limits::max(); + } +} + +// Return true if the given tensors have the same shape. +bool HaveSameShapes(const TfLiteTensor* input1, const TfLiteTensor* input2); + +#if !defined(ARDUINO) +// Gets the output shape from the input tensor. +TfLiteStatus GetOutputShapeFromInput(TfLiteContext* context, + const TfLiteTensor* input, + TfLiteIntArray** output_shape); + +const std::string GetShapeDebugString(const TfLiteIntArray* shape); + +#endif // !defined(ARDUINO) + +// Calculates the output_shape that is necessary for element-wise operations +// with broadcasting involving the two input tensors. +TfLiteStatus CalculateShapeForBroadcast(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteIntArray** output_shape); + +// Calculates the output_shape that is necessary for element-wise operations +// with broadcasting involving the three input tensors. +TfLiteStatus CalculateShapeForBroadcast(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + const TfLiteTensor* input3, + TfLiteIntArray** output_shape); + +// Return the size of given type in bytes. Return 0 in case of string. +int TfLiteTypeGetSize(TfLiteType type); + +// Whether the current platform is mobile (Android or iOS). +bool IsMobilePlatform(); + +// Returns whether there is unspecified dimension in the tensor's dim signature. +bool HasUnspecifiedDimension(const TfLiteTensor* tensor); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_KERNEL_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/op_macros.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/op_macros.h new file mode 100644 index 000000000..ba297de5c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/op_macros.h @@ -0,0 +1,38 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_OP_MACROS_H_ +#define TENSORFLOW_LITE_KERNELS_OP_MACROS_H_ + +#include "tensorflow/lite/micro/debug_log.h" + +#if !defined(TF_LITE_MCU_DEBUG_LOG) +#include +#define TFLITE_ABORT abort() +#else +inline void AbortImpl() { + DebugLog("HALTED\n"); + while (1) { + } +} +#define TFLITE_ABORT AbortImpl(); +#endif + +#if defined(ARDUINO) +#define TFLITE_ASSERT_FALSE (static_cast(0)) +#else +#define TFLITE_ASSERT_FALSE TFLITE_ABORT +#endif + +#endif // TENSORFLOW_LITE_KERNELS_OP_MACROS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/padding.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/padding.h new file mode 100644 index 000000000..d9cca3ea1 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/kernels/padding.h @@ -0,0 +1,115 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_KERNELS_PADDING_H_ +#define TENSORFLOW_LITE_KERNELS_PADDING_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +inline int ComputePadding(int stride, int dilation_rate, int in_size, + int filter_size, int out_size) { + int effective_filter_size = (filter_size - 1) * dilation_rate + 1; + int padding = ((out_size - 1) * stride + effective_filter_size - in_size) / 2; + return padding > 0 ? padding : 0; +} + +// It's not guaranteed that padding is symmetric. It's important to keep +// offset for algorithms need all paddings. +inline int ComputePaddingWithOffset(int stride, int dilation_rate, int in_size, + int filter_size, int out_size, + int* offset) { + int effective_filter_size = (filter_size - 1) * dilation_rate + 1; + int total_padding = + ((out_size - 1) * stride + effective_filter_size - in_size); + total_padding = total_padding > 0 ? total_padding : 0; + *offset = total_padding % 2; + return total_padding / 2; +} + +// Matching GetWindowedOutputSize in TensorFlow. +inline int ComputeOutSize(TfLitePadding padding, int image_size, + int filter_size, int stride, int dilation_rate = 1) { + int effective_filter_size = (filter_size - 1) * dilation_rate + 1; + + // TODO(b/186448822): This uses 0 since the function has no other way to + // report error case + if (stride == 0) return 0; + + switch (padding) { + case kTfLitePaddingSame: + return (image_size + stride - 1) / stride; + case kTfLitePaddingValid: + return (image_size + stride - effective_filter_size) / stride; + default: + return 0; + } +} + +inline TfLitePaddingValues ComputePaddingHeightWidth( + int stride_height, int stride_width, int dilation_rate_height, + int dilation_rate_width, int in_height, int in_width, int filter_height, + int filter_width, TfLitePadding padding, int* out_height, int* out_width) { + *out_width = ComputeOutSize(padding, in_width, filter_width, stride_width, + dilation_rate_width); + *out_height = ComputeOutSize(padding, in_height, filter_height, stride_height, + dilation_rate_height); + + TfLitePaddingValues padding_values; + int offset = 0; + padding_values.height = + ComputePaddingWithOffset(stride_height, dilation_rate_height, in_height, + filter_height, *out_height, &offset); + padding_values.height_offset = offset; + padding_values.width = + ComputePaddingWithOffset(stride_width, dilation_rate_width, in_width, + filter_width, *out_width, &offset); + padding_values.width_offset = offset; + return padding_values; +} + +inline Padding3DValues ComputePadding3DValues( + int stride_height, int stride_width, int stride_depth, + int dilation_rate_height, int dilation_rate_width, int dilation_rate_depth, + int in_height, int in_width, int in_depth, int filter_height, + int filter_width, int filter_depth, TfLitePadding padding, int* out_height, + int* out_width, int* out_depth) { + *out_width = ComputeOutSize(padding, in_width, filter_width, stride_width, + dilation_rate_width); + *out_height = ComputeOutSize(padding, in_height, filter_height, stride_height, + dilation_rate_height); + *out_depth = ComputeOutSize(padding, in_depth, filter_depth, stride_depth, + dilation_rate_depth); + + Padding3DValues padding_values; + int offset = 0; + padding_values.depth = + ComputePaddingWithOffset(stride_depth, dilation_rate_depth, in_depth, + filter_depth, *out_depth, &offset); + padding_values.depth_offset = offset; + padding_values.height = + ComputePaddingWithOffset(stride_height, dilation_rate_height, in_height, + filter_height, *out_height, &offset); + padding_values.height_offset = offset; + padding_values.width = + ComputePaddingWithOffset(stride_width, dilation_rate_width, in_width, + filter_width, *out_width, &offset); + padding_values.width_offset = offset; + return padding_values; +} +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_PADDING_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/all_ops_resolver.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/all_ops_resolver.cpp new file mode 100644 index 000000000..150f45259 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/all_ops_resolver.cpp @@ -0,0 +1,123 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/all_ops_resolver.h" + +#include "tensorflow/lite/micro/kernels/micro_ops.h" + +namespace tflite { + +AllOpsResolver::AllOpsResolver() { + // Please keep this list of Builtin Operators in alphabetical order. + AddAbs(); + AddAdd(); + AddAddN(); + AddArgMax(); + AddArgMin(); + AddAssignVariable(); + AddAveragePool2D(); + AddBatchToSpaceNd(); + AddBroadcastArgs(); + AddBroadcastTo(); + AddCallOnce(); + AddCast(); + AddCeil(); + AddCircularBuffer(); + AddConcatenation(); + AddConv2D(); + AddCos(); + AddCumSum(); + AddDepthToSpace(); + AddDepthwiseConv2D(); + AddDequantize(); + AddDetectionPostprocess(); + AddDiv(); + AddElu(); + AddEqual(); + AddEthosU(); + AddExp(); + AddExpandDims(); + AddFill(); + AddFloor(); + AddFloorDiv(); + AddFloorMod(); + AddFullyConnected(); + AddGather(); + AddGatherNd(); + AddGreater(); + AddGreaterEqual(); + AddHardSwish(); + AddIf(); + AddL2Normalization(); + AddL2Pool2D(); + AddLeakyRelu(); + AddLess(); + AddLessEqual(); + AddLog(); + AddLogicalAnd(); + AddLogicalNot(); + AddLogicalOr(); + AddLogistic(); + AddLogSoftmax(); + AddMaxPool2D(); + AddMaximum(); + AddMean(); + AddMinimum(); + AddMirrorPad(); + AddMul(); + AddNeg(); + AddNotEqual(); + AddPack(); + AddPad(); + AddPadV2(); + AddPrelu(); + AddQuantize(); + AddReadVariable(); + AddReduceMax(); + AddRelu(); + AddRelu6(); + AddReshape(); + AddResizeBilinear(); + AddResizeNearestNeighbor(); + AddRound(); + AddRsqrt(); + AddSelectV2(); + AddShape(); + AddSin(); + AddSlice(); + AddSoftmax(); + AddSpaceToBatchNd(); + AddSpaceToDepth(); + AddSplit(); + AddSplitV(); + AddSqrt(); + AddSquare(); + AddSquaredDifference(); + AddSqueeze(); + AddStridedSlice(); + AddSub(); + AddSum(); + AddSvdf(); + AddTanh(); + AddTranspose(); + AddTransposeConv(); + AddUnidirectionalSequenceLSTM(); + AddUnpack(); + AddVarHandle(); + AddWhile(); + AddZerosLike(); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/all_ops_resolver.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/all_ops_resolver.h new file mode 100644 index 000000000..391b4f08e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/all_ops_resolver.h @@ -0,0 +1,38 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_ALL_OPS_RESOLVER_H_ +#define TENSORFLOW_LITE_MICRO_ALL_OPS_RESOLVER_H_ + +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/micro_mutable_op_resolver.h" + +namespace tflite { + +// The magic number in the template parameter is the maximum number of ops that +// can be added to AllOpsResolver. It can be increased if needed. And most +// applications that care about the memory footprint will want to directly use +// MicroMutableOpResolver and have an application specific template parameter. +// The examples directory has sample code for this. +class AllOpsResolver : public MicroMutableOpResolver<128> { + public: + AllOpsResolver(); + + private: + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_ALL_OPS_RESOLVER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/ibuffer_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/ibuffer_allocator.h new file mode 100644 index 000000000..b92d6b2d9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/ibuffer_allocator.h @@ -0,0 +1,100 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_IBUFFER_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_IBUFFER_ALLOCATOR_H_ + +#include +#include + +#include "tensorflow/lite/c/c_api_types.h" + +namespace tflite { +// Interface classes that the TFLM framework relies on to get buffers it needs. +// There are two types of buffers that the TFLM framework requires: persistent +// and non-persistent. Persistent buffers, once allocated, are never freed by +// the TFLM framework. Non-persist buffers can be allocated and deallocated by +// the TFLM framework. This file defines two interfaces classes that TFLM +// framework will rely on to manage these buffers. + +// Interface class for managing persistent buffers. +class IPersistentBufferAllocator { + public: + IPersistentBufferAllocator() {} + virtual ~IPersistentBufferAllocator() {} + + // Allocates persistent memory. The persistent buffer is never freed. + virtual uint8_t* AllocatePersistentBuffer(size_t size, size_t alignment) = 0; + + // Returns the size of all persistent allocations in bytes. + virtual size_t GetPersistentUsedBytes() const = 0; +}; + +// Interface class for managing non-persistent buffers. +// The default non-persistent buffers are temp buffers that are not resizable. +// Support of at least one resizable buffer is required. +class INonPersistentBufferAllocator { + public: + INonPersistentBufferAllocator() {} + virtual ~INonPersistentBufferAllocator() {} + + // Allocates a temporary buffer. This buffer is not resizable. + virtual uint8_t* AllocateTemp(size_t size, size_t alignment) = 0; + + // Signals that a temporary buffer is no longer needed. + virtual void DeallocateTemp(uint8_t* buf) = 0; + + // Returns true if all temporary buffers are already deallocated. + virtual bool IsAllTempDeallocated() = 0; + + // Signals that all temporary allocations can be reclaimed. TFLM calls this + // API when it knows that all temporary buffers that it requested has been + // deallocated. The goal of API is to facilitate implementations of + // INonPersistentBufferAllocator can reuse buffer with some reasonable + // complexity. + virtual TfLiteStatus ResetTempAllocations() = 0; + + // Returns a buffer that is resizable viable ResizeBuffer(). + virtual uint8_t* AllocateResizableBuffer(size_t size, size_t alignment) = 0; + + // Resizes a buffer that is previously returned by the + // AllocateResizableBuffer. + virtual TfLiteStatus ResizeBuffer(uint8_t* resizable_buf, size_t size, + size_t alignment) = 0; + + // Frees up the memory occupied by the resizable buffer. + virtual TfLiteStatus DeallocateResizableBuffer(uint8_t* resizable_buf) = 0; + + // Returns a pointer pointing to the start of the overlay memory, which is + // used for activation tensors and scratch buffers by kernels at Invoke stage. + virtual uint8_t* GetOverlayMemoryAddress() const = 0; + + // Reserves the size of the overlay memory. This overlay is reserved for the + // kernels at Invoke stage. This is referred to as the overlay because before + // Invoket state, the same memory can be used for temp buffers. The layout of + // the memory is planned by the memory planner separately at Invoke stage. + virtual TfLiteStatus ReserveNonPersistentOverlayMemory(size_t size, + size_t alignment) = 0; + + // Returns the size of non-persistent buffer in use. + virtual size_t GetNonPersistentUsedBytes() const = 0; + + // Returns the number of bytes available with a given alignment. This number + // takes in account any temporary allocations. + virtual size_t GetAvailableMemory(size_t alignment) const = 0; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_IBUFFER_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.cpp new file mode 100644 index 000000000..a8f00eadc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.cpp @@ -0,0 +1,170 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.h" + +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +NonPersistentArenaBufferAllocator::NonPersistentArenaBufferAllocator( + uint8_t* buffer, size_t buffer_size) + : buffer_head_(buffer), + buffer_tail_(buffer + buffer_size), + head_temp_(buffer), + next_temp_(buffer) {} + +NonPersistentArenaBufferAllocator::~NonPersistentArenaBufferAllocator() {} + +// Allocates a temporary buffer. This buffer is not resizable. +uint8_t* NonPersistentArenaBufferAllocator::AllocateTemp(size_t size, + size_t alignment) { + uint8_t* const aligned_result = AlignPointerUp(next_temp_, alignment); + const size_t available_memory = buffer_tail_ - aligned_result; + if (available_memory < size) { + MicroPrintf( + "Failed to allocate temp memory. Requested: %u, " + "available %u, missing: %u", + size, available_memory, size - available_memory); + return nullptr; + } + next_temp_ = aligned_result + size; + temp_buffer_ptr_check_sum_ ^= reinterpret_cast(aligned_result); + temp_buffer_count_++; + return aligned_result; +} + +// Signals that a temporary buffer is no longer needed. +void NonPersistentArenaBufferAllocator::DeallocateTemp(uint8_t* temp_buf) { + temp_buffer_ptr_check_sum_ ^= reinterpret_cast(temp_buf); + temp_buffer_count_--; +} + +// Returns true if all temporary buffers are already deallocated. +bool NonPersistentArenaBufferAllocator::IsAllTempDeallocated() { + if (temp_buffer_count_ != 0 || temp_buffer_ptr_check_sum_ != 0) { + MicroPrintf( + "Number of allocated temp buffers: %d. Checksum passing status: %d", + temp_buffer_count_, !temp_buffer_ptr_check_sum_); + return false; + } + return true; +} + +// Signals that all temporary allocations can be reclaimed. TFLM calls this +// API when it knows that all temporary buffers that it requested has been +// deallocated. The goal of API is to facilitate implementations of +// INonPersistentBufferAllocator can reuse buffer with some reasonable +// complexity. +TfLiteStatus NonPersistentArenaBufferAllocator::ResetTempAllocations() { + if (!IsAllTempDeallocated()) { + MicroPrintf( + "All temp buffers must be freed before calling ResetTempAllocations()"); + return kTfLiteError; + } + next_temp_ = head_temp_; + return kTfLiteOk; +} + +// Returns a buffer that is resizable viable ResizeBuffer(). +uint8_t* NonPersistentArenaBufferAllocator::AllocateResizableBuffer( + size_t size, size_t alignment) { + // Only supports one resizable buffer, which starts at the buffer head. + uint8_t* expected_resizable_buf = AlignPointerUp(buffer_head_, alignment); + + if (resizable_buffer_allocated_) { + MicroPrintf( + "Cannot allocate a new resizable buffer when one is already allocated"); + return nullptr; + } + + if (ResizeBuffer(expected_resizable_buf, size, alignment) == kTfLiteOk) { + resizable_buffer_allocated_ = true; + return expected_resizable_buf; + } + return nullptr; +} + +// Resizes a buffer that is previously returned by the AllocateResizableBuffer. +// Note that ResizeBuffer(old_resizable_buf, 0, 1) effectively deallocates +// a previous allocated resizable buffer. +TfLiteStatus NonPersistentArenaBufferAllocator::ResizeBuffer( + uint8_t* resizable_buf, size_t size, size_t alignment) { + // Only supports one resizable buffer, which starts at the buffer head. + uint8_t* expect_resizable_buf = AlignPointerUp(buffer_head_, alignment); + if (resizable_buf != expect_resizable_buf) { + MicroPrintf("Internal error: buffer is not resizable"); + return kTfLiteError; + } + if (head_temp_ != next_temp_) { + MicroPrintf("ResetTempAllocations() is not called before ResizeBuffer()."); + return kTfLiteError; + } + + const size_t available_memory = buffer_tail_ - expect_resizable_buf; + if (available_memory < size) { + MicroPrintf( + "Failed to resize buffer. Requested: %u, available %u, missing: %u", + size, available_memory, size - available_memory); + return kTfLiteError; + } + head_temp_ = expect_resizable_buf + size; + next_temp_ = head_temp_; + + return kTfLiteOk; +} + +// Frees up the memory occupied by the resizable buffer. +TfLiteStatus NonPersistentArenaBufferAllocator::DeallocateResizableBuffer( + uint8_t* resizable_buf) { + TfLiteStatus status = ResizeBuffer(resizable_buf, 0, 1); + if (status == kTfLiteOk) { + resizable_buffer_allocated_ = false; + } + return status; +} + +// Returns a pointer pointing to the start of the overlay memory, which is +// used for activation tensors and scratch buffers by kernels at Invoke stage. +uint8_t* NonPersistentArenaBufferAllocator::GetOverlayMemoryAddress() const { + return buffer_head_; +} + +// Reserves the size of the overlay memory. This overlay is reserved for the +// kernels at Invoke stage. This is referred to as the overlay because before +// Invoket state, the same memory can be used for temp buffers. The layout of +// the memory is planned by the memory planner separately at Invoke stage. +TfLiteStatus +NonPersistentArenaBufferAllocator::ReserveNonPersistentOverlayMemory( + size_t size, size_t alignment) { + uint8_t* expect_resizable_buf = AlignPointerUp(buffer_head_, alignment); + return ResizeBuffer(expect_resizable_buf, size, alignment); +} + +// Returns the size of non-persistent buffer in use. +size_t NonPersistentArenaBufferAllocator::GetNonPersistentUsedBytes() const { + return (next_temp_ - buffer_head_); +} + +// Returns the number of bytes available with a given alignment. This number +// takes in account any temporary allocations. +size_t NonPersistentArenaBufferAllocator::GetAvailableMemory( + size_t alignment) const { + uint8_t* const aligned_temp = AlignPointerUp(next_temp_, alignment); + uint8_t* const aligned_tail = AlignPointerDown(buffer_tail_, alignment); + return aligned_tail - aligned_temp; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.h new file mode 100644 index 000000000..ebd376466 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.h @@ -0,0 +1,104 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_NON_PERSISTENT_ARENA_BUFFER_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_NON_PERSISTENT_ARENA_BUFFER_ALLOCATOR_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/arena_allocator/ibuffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" + +namespace tflite { + +// Implement INonPersistentBufferAllocator on an arena that is dedicated for +// non-persistent buffers. +class NonPersistentArenaBufferAllocator : public INonPersistentBufferAllocator { + public: + NonPersistentArenaBufferAllocator(uint8_t* buffer, size_t buffer_size); + virtual ~NonPersistentArenaBufferAllocator(); + + // Allocates a temporary buffer. This buffer is not resizable. + uint8_t* AllocateTemp(size_t size, size_t alignment) override; + + // Signals that a temporary buffer is no longer needed. + void DeallocateTemp(uint8_t* buf) override; + + // Returns true if all temporary buffers are already deallocated. + bool IsAllTempDeallocated() override; + + // Signals that all temporary allocations can be reclaimed. TFLM calls this + // API when it knows that all temporary buffers that it requested has been + // deallocated. + TfLiteStatus ResetTempAllocations() override; + + // Returns a buffer that is resizable viable ResizeBuffer(). + uint8_t* AllocateResizableBuffer(size_t size, size_t alignment) override; + + // Resizes a buffer that is previously returned by the + // AllocateResizableBuffer. + TfLiteStatus ResizeBuffer(uint8_t* resizable_buf, size_t size, + size_t alignment) override; + + // Frees up the memory occupied by the resizable buffer. + TfLiteStatus DeallocateResizableBuffer(uint8_t* resizable_buf) override; + + // Returns a pointer pointing to the start of the overlay memory, which is + // used for activation tensors and scratch buffers by kernels at Invoke stage. + uint8_t* GetOverlayMemoryAddress() const override; + + // Reserves the size of the overlay memory. This overlay is reserved for the + // kernels at Invoke stage. This is referred to as the overlay because before + // Invoket state, the same memory can be used for temp buffers. The layout of + // the memory is planned by the memory planner separately at Invoke stage. + TfLiteStatus ReserveNonPersistentOverlayMemory(size_t size, + size_t alignment) override; + + // Returns the size of non-persistent buffer in use. + size_t GetNonPersistentUsedBytes() const override; + + // Returns the number of bytes available with a given alignment. This number + // takes in account any temporary allocations. + size_t GetAvailableMemory(size_t alignment) const override; + + TF_LITE_REMOVE_VIRTUAL_DELETE + + private: + // The memory arena that this allocator manages. + uint8_t* const buffer_head_; + uint8_t* const buffer_tail_; + + // The whole region is split into two parts: + // buffer_head_ to head_temp_ - 1 belongs to the only resizable buffer. + // head_temp_ to buffer_tail_ can be used for (non-resizable) temp buffers. + uint8_t* head_temp_; + + // next_temp_ points to the next available temp buffer allocation address and + // its range is between head_temp_ and buffer_tail_ + uint8_t* next_temp_; + + // XOR Check sum for outstanding temp buffers. + // If all temp buffers are deallocated OR no temp buffers are allocated, + // temp_buffer_ptr_check_sum_ == nullptr. + intptr_t temp_buffer_ptr_check_sum_ = 0; + // Count of outstanding temp buffers. + int temp_buffer_count_ = 0; + bool resizable_buffer_allocated_ = false; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_NON_PERSISTENT_ARENA_BUFFER_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.cpp new file mode 100644 index 000000000..a770bc9df --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.cpp @@ -0,0 +1,52 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.h" + +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +PersistentArenaBufferAllocator::PersistentArenaBufferAllocator( + uint8_t* buffer, size_t buffer_size) + : buffer_head_(buffer), + buffer_tail_(buffer + buffer_size), + tail_temp_(buffer_tail_) {} + +PersistentArenaBufferAllocator::~PersistentArenaBufferAllocator() {} + +uint8_t* PersistentArenaBufferAllocator::AllocatePersistentBuffer( + size_t size, size_t alignment) { + uint8_t* const aligned_result = + AlignPointerDown(tail_temp_ - size, alignment); + if (aligned_result < buffer_head_) { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + const size_t missing_memory = buffer_head_ - aligned_result; + MicroPrintf( + "Failed to allocate tail memory. Requested: %u, " + "available %u, missing: %u", + size, size - missing_memory, missing_memory); +#endif + return nullptr; + } + tail_temp_ = aligned_result; + return aligned_result; +} + +size_t PersistentArenaBufferAllocator::GetPersistentUsedBytes() const { + return buffer_tail_ - tail_temp_; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.h new file mode 100644 index 000000000..2c8e3dca5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.h @@ -0,0 +1,58 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_PERSISTENT_ARENA_BUFFER_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_PERSISTENT_ARENA_BUFFER_ALLOCATOR_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/arena_allocator/ibuffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" + +namespace tflite { + +// PersistentArenaBufferAllocator is an implementatation of +// IPersistentBufferAllocator interface on an arena that is dedicated for +// persistent buffers. +class PersistentArenaBufferAllocator : public IPersistentBufferAllocator { + public: + PersistentArenaBufferAllocator(uint8_t* buffer, size_t buffer_size); + virtual ~PersistentArenaBufferAllocator(); + + // Allocates persistent memory. The persistent buffer is never freed. + // Returns nullptr if errors occured. + uint8_t* AllocatePersistentBuffer(size_t size, size_t alignment) override; + + // Returns the size of all persistent allocations in bytes. + size_t GetPersistentUsedBytes() const override; + + TF_LITE_REMOVE_VIRTUAL_DELETE + private: + // The memory arena that this allocator manages. + uint8_t* const buffer_head_; + uint8_t* const buffer_tail_; + + // The whole region is split into two parts: + // tail_temp_ to buffer_tail_ contains allocated buffers; + // buffer_head_ to tail_temp_ - 1 belongs to still available spaces. + // So in essence, the allocated region grows from the bottom and emulates + // SingleArenaBufferAllocator's persistent part. + uint8_t* tail_temp_; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_PERSISTENT_ARENA_BUFFER_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.cpp new file mode 100644 index 000000000..e21e36469 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.cpp @@ -0,0 +1,85 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.h" + +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" + +namespace tflite { + +RecordingSingleArenaBufferAllocator::RecordingSingleArenaBufferAllocator( + uint8_t* buffer_head, size_t buffer_size) + : SingleArenaBufferAllocator(buffer_head, buffer_size), + requested_head_bytes_(0), + requested_tail_bytes_(0), + used_bytes_(0), + alloc_count_(0) {} + +RecordingSingleArenaBufferAllocator::~RecordingSingleArenaBufferAllocator() {} + +RecordingSingleArenaBufferAllocator* +RecordingSingleArenaBufferAllocator::Create(uint8_t* buffer_head, + size_t buffer_size) { + TFLITE_DCHECK(buffer_head != nullptr); + RecordingSingleArenaBufferAllocator tmp = + RecordingSingleArenaBufferAllocator(buffer_head, buffer_size); + + uint8_t* allocator_buffer = tmp.AllocatePersistentBuffer( + sizeof(RecordingSingleArenaBufferAllocator), + alignof(RecordingSingleArenaBufferAllocator)); + // Use the default copy constructor to populate internal states. + return new (allocator_buffer) RecordingSingleArenaBufferAllocator(tmp); +} + +size_t RecordingSingleArenaBufferAllocator::GetRequestedBytes() const { + return requested_head_bytes_ + requested_tail_bytes_; +} + +size_t RecordingSingleArenaBufferAllocator::GetUsedBytes() const { + return used_bytes_; +} + +size_t RecordingSingleArenaBufferAllocator::GetAllocatedCount() const { + return alloc_count_; +} + +TfLiteStatus RecordingSingleArenaBufferAllocator::ResizeBuffer( + uint8_t* resizable_buf, size_t size, size_t alignment) { + const uint8_t* previous_head = head(); + TfLiteStatus status = + SingleArenaBufferAllocator::ResizeBuffer(resizable_buf, size, alignment); + if (status == kTfLiteOk) { + used_bytes_ += head() - previous_head; + requested_head_bytes_ = size; + } + return status; +} + +uint8_t* RecordingSingleArenaBufferAllocator::AllocatePersistentBuffer( + size_t size, size_t alignment) { + const uint8_t* previous_tail = tail(); + uint8_t* result = + SingleArenaBufferAllocator::AllocatePersistentBuffer(size, alignment); + if (result != nullptr) { + used_bytes_ += previous_tail - tail(); + requested_tail_bytes_ += size; + alloc_count_++; + } + return result; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.h new file mode 100644 index 000000000..321215439 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.h @@ -0,0 +1,78 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_RECORDING_SINGLE_ARENA_BUFFER_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_RECORDING_SINGLE_ARENA_BUFFER_ALLOCATOR_H_ + +#include "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" + +namespace tflite { + +// Utility class used to log allocations of a SingleArenaBufferAllocator. Should +// only be used in debug/evaluation settings or unit tests to evaluate +// allocation usage. +class RecordingSingleArenaBufferAllocator : public SingleArenaBufferAllocator { + public: + // TODO(b/246776144): Will be removed with http://b/246776144 + RecordingSingleArenaBufferAllocator(ErrorReporter* error_reporter, + uint8_t* buffer_head, size_t buffer_size) + : RecordingSingleArenaBufferAllocator(buffer_head, buffer_size) { + (void)error_reporter; + } + + RecordingSingleArenaBufferAllocator(uint8_t* buffer_head, size_t buffer_size); + // TODO(b/157615197): Cleanup constructors/destructor and use factory + // functions. + ~RecordingSingleArenaBufferAllocator() override; + + static RecordingSingleArenaBufferAllocator* Create(uint8_t* buffer_head, + size_t buffer_size); + + // TODO(b/246776144): Will be removed with http://b/246776144 + static RecordingSingleArenaBufferAllocator* Create( + ErrorReporter* error_reporter, uint8_t* buffer_head, size_t buffer_size) { + (void)error_reporter; + return RecordingSingleArenaBufferAllocator::Create(buffer_head, + buffer_size); + } + + // Returns the number of bytes requested from the head or tail. + size_t GetRequestedBytes() const; + + // Returns the number of bytes actually allocated from the head or tail. This + // value will be >= to the number of requested bytes due to padding and + // alignment. + size_t GetUsedBytes() const; + + // Returns the number of alloc calls from the head or tail. + size_t GetAllocatedCount() const; + + TfLiteStatus ResizeBuffer(uint8_t* resizable_buf, size_t size, + size_t alignment) override; + uint8_t* AllocatePersistentBuffer(size_t size, size_t alignment) override; + + private: + size_t requested_head_bytes_; + size_t requested_tail_bytes_; + size_t used_bytes_; + size_t alloc_count_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_RECORDING_SINGLE_ARENA_BUFFER_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.cpp new file mode 100644 index 000000000..8655cfdce --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.cpp @@ -0,0 +1,199 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" + +#include +#include +#include + +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +SingleArenaBufferAllocator::SingleArenaBufferAllocator(uint8_t* buffer_head, + uint8_t* buffer_tail) + : buffer_head_(buffer_head), + buffer_tail_(buffer_tail), + head_(buffer_head), + tail_(buffer_tail), + temp_(buffer_head_) {} + +SingleArenaBufferAllocator::SingleArenaBufferAllocator(uint8_t* buffer, + size_t buffer_size) + : SingleArenaBufferAllocator(buffer, buffer + buffer_size) {} + +/* static */ +SingleArenaBufferAllocator* SingleArenaBufferAllocator::Create( + uint8_t* buffer_head, size_t buffer_size) { + TFLITE_DCHECK(buffer_head != nullptr); + SingleArenaBufferAllocator tmp = + SingleArenaBufferAllocator(buffer_head, buffer_size); + + // Allocate enough bytes from the buffer to create a + // SingleArenaBufferAllocator. The new instance will use the current adjusted + // tail buffer from the tmp allocator instance. + uint8_t* allocator_buffer = tmp.AllocatePersistentBuffer( + sizeof(SingleArenaBufferAllocator), alignof(SingleArenaBufferAllocator)); + // Use the default copy constructor to populate internal states. + return new (allocator_buffer) SingleArenaBufferAllocator(tmp); +} + +SingleArenaBufferAllocator::~SingleArenaBufferAllocator() {} + +uint8_t* SingleArenaBufferAllocator::AllocateResizableBuffer(size_t size, + size_t alignment) { + // Only supports one resizable buffer, which starts at the buffer head. + uint8_t* expect_resizable_buf = AlignPointerUp(buffer_head_, alignment); + if (ResizeBuffer(expect_resizable_buf, size, alignment) == kTfLiteOk) { + return expect_resizable_buf; + } + return nullptr; +} + +TfLiteStatus SingleArenaBufferAllocator::DeallocateResizableBuffer( + uint8_t* resizable_buf) { + return ResizeBuffer(resizable_buf, 0, 1); +} + +TfLiteStatus SingleArenaBufferAllocator::ReserveNonPersistentOverlayMemory( + size_t size, size_t alignment) { + uint8_t* expect_resizable_buf = AlignPointerUp(buffer_head_, alignment); + return ResizeBuffer(expect_resizable_buf, size, alignment); +} + +TfLiteStatus SingleArenaBufferAllocator::ResizeBuffer(uint8_t* resizable_buf, + size_t size, + size_t alignment) { + // Only supports one resizable buffer, which starts at the buffer head. + uint8_t* expect_resizable_buf = AlignPointerUp(buffer_head_, alignment); + if (head_ != temp_ || resizable_buf != expect_resizable_buf) { + MicroPrintf( + "Internal error: either buffer is not resizable or " + "ResetTempAllocations() is not called before ResizeBuffer()."); + return kTfLiteError; + } + + uint8_t* const aligned_result = AlignPointerUp(buffer_head_, alignment); + const size_t available_memory = tail_ - aligned_result; + if (available_memory < size) { + MicroPrintf( + "Failed to resize buffer. Requested: %u, available %u, missing: %u", + size, available_memory, size - available_memory); + return kTfLiteError; + } + head_ = aligned_result + size; + temp_ = head_; + + return kTfLiteOk; +} + +uint8_t* SingleArenaBufferAllocator::AllocatePersistentBuffer( + size_t size, size_t alignment) { + uint8_t* const aligned_result = AlignPointerDown(tail_ - size, alignment); + if (aligned_result < head_) { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + const size_t missing_memory = head_ - aligned_result; + MicroPrintf( + "Failed to allocate tail memory. Requested: %u, " + "available %u, missing: %u", + size, size - missing_memory, missing_memory); +#endif + return nullptr; + } + tail_ = aligned_result; + return aligned_result; +} + +uint8_t* SingleArenaBufferAllocator::AllocateTemp(size_t size, + size_t alignment) { + uint8_t* const aligned_result = AlignPointerUp(temp_, alignment); + const size_t available_memory = tail_ - aligned_result; + if (available_memory < size) { + MicroPrintf( + "Failed to allocate temp memory. Requested: %u, " + "available %u, missing: %u", + size, available_memory, size - available_memory); + return nullptr; + } + temp_ = aligned_result + size; + temp_buffer_ptr_check_sum_ ^= (reinterpret_cast(aligned_result)); + temp_buffer_count_++; + return aligned_result; +} + +void SingleArenaBufferAllocator::DeallocateTemp(uint8_t* temp_buf) { + temp_buffer_ptr_check_sum_ ^= (reinterpret_cast(temp_buf)); + temp_buffer_count_--; +} + +bool SingleArenaBufferAllocator::IsAllTempDeallocated() { + if (temp_buffer_count_ != 0 || temp_buffer_ptr_check_sum_ != 0) { + MicroPrintf( + "Number of allocated temp buffers: %d. Checksum passing status: %d", + temp_buffer_count_, !temp_buffer_ptr_check_sum_); + return false; + } + return true; +} + +TfLiteStatus SingleArenaBufferAllocator::ResetTempAllocations() { + // TODO(b/209453859): enable error check based on IsAllTempDeallocated after + // all AllocateTemp have been paird with DeallocateTemp + if (!IsAllTempDeallocated()) { + MicroPrintf( + "All temp buffers must be freed before calling ResetTempAllocations()"); + return kTfLiteError; + } + temp_ = head_; + return kTfLiteOk; +} + +uint8_t* SingleArenaBufferAllocator::GetOverlayMemoryAddress() const { + return buffer_head_; +} + +size_t SingleArenaBufferAllocator::GetNonPersistentUsedBytes() const { + return std::max(head_ - buffer_head_, temp_ - buffer_head_); +} + +size_t SingleArenaBufferAllocator::GetPersistentUsedBytes() const { + return buffer_tail_ - tail_; +} + +size_t SingleArenaBufferAllocator::GetAvailableMemory(size_t alignment) const { + uint8_t* const aligned_temp = AlignPointerUp(temp_, alignment); + uint8_t* const aligned_tail = AlignPointerDown(tail_, alignment); + return aligned_tail - aligned_temp; +} + +size_t SingleArenaBufferAllocator::GetUsedBytes() const { + return GetPersistentUsedBytes() + GetNonPersistentUsedBytes(); +} + +size_t SingleArenaBufferAllocator::GetBufferSize() const { + return buffer_tail_ - buffer_head_; +} + +uint8_t* SingleArenaBufferAllocator::head() const { return head_; } + +uint8_t* SingleArenaBufferAllocator::tail() const { return tail_; } + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h new file mode 100644 index 000000000..68aa35a1a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h @@ -0,0 +1,165 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_SINGLE_ARENA_BUFFER_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_SINGLE_ARENA_BUFFER_ALLOCATOR_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/micro/arena_allocator/ibuffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" + +namespace tflite { + +// TODO(petewarden): This allocator never frees up or reuses any memory, even +// though we have enough information about lifetimes of the tensors to do so. +// This makes it pretty wasteful, so we should use a more intelligent method. +class SingleArenaBufferAllocator : public INonPersistentBufferAllocator, + public IPersistentBufferAllocator { + public: + // TODO(b/246776144): Will be removed with http://b/246776144 + SingleArenaBufferAllocator(ErrorReporter* error_reporter, + uint8_t* buffer_head, uint8_t* buffer_tail) + : SingleArenaBufferAllocator(buffer_head, buffer_tail) { + (void)error_reporter; + } + SingleArenaBufferAllocator(ErrorReporter* error_reporter, uint8_t* buffer, + size_t buffer_size) + : SingleArenaBufferAllocator(buffer, buffer_size) { + (void)error_reporter; + } + + // TODO(b/157615197): Cleanup constructors/destructor and use factory + // functions. + SingleArenaBufferAllocator(uint8_t* buffer_head, uint8_t* buffer_tail); + SingleArenaBufferAllocator(uint8_t* buffer, size_t buffer_size); + virtual ~SingleArenaBufferAllocator(); + + // TODO(b/246776144): Will be removed with http://b/246776144 + static SingleArenaBufferAllocator* Create(ErrorReporter* error_reporter, + uint8_t* buffer_head, + size_t buffer_size) { + (void)error_reporter; + return SingleArenaBufferAllocator::Create(buffer_head, buffer_size); + } + + // Creates a new SingleArenaBufferAllocator from a given buffer head and size. + static SingleArenaBufferAllocator* Create(uint8_t* buffer_head, + size_t buffer_size); + + // Resizes a buffer that is previously returned by the + // AllocateResizableBuffer. In current implementation, it Adjusts the head + // (lowest address and moving upwards) memory allocation to a given size. + // Calls to this method will also invalidate all temporary allocation values + // (it sets the location of temp space at the end of the head section). This + // call will fail if a chain of allocations through AllocateTemp() have not + // been cleaned up with a call to ResetTempAllocations(). + virtual TfLiteStatus ResizeBuffer(uint8_t* resizable_buf, size_t size, + size_t alignment) override; + + // Returns a buffer that is resizable viable ResizeBuffer(). Only one + // resizable buffer is currently supported. + virtual uint8_t* AllocateResizableBuffer(size_t size, + size_t alignment) override; + + // Frees up the memory occupied by the resizable buffer + virtual TfLiteStatus DeallocateResizableBuffer( + uint8_t* resizable_buf) override; + + // Reserves the non-persistent memory that is planned by the memory planner. + virtual TfLiteStatus ReserveNonPersistentOverlayMemory( + size_t size, size_t alignment) override; + + // Allocates persistent memory starting at the tail of the arena (highest + // address and moving downwards). + virtual uint8_t* AllocatePersistentBuffer(size_t size, + size_t alignment) override; + + // Allocates a temporary buffer from the head of the arena (lowest address and + // moving upwards) but does not update the actual head allocation size or + // position. The returned buffer is guaranteed until either + // ResetTempAllocations() is called or another call to AllocateFromHead(). + // Repeat calls to this function will create a chain of temp allocations. All + // calls to AllocateTemp() must end with a call to ResetTempAllocations(). If + // AllocateFromHead() is called before a call to ResetTempAllocations(), it + // will fail with an error message. + virtual uint8_t* AllocateTemp(size_t size, size_t alignment) override; + + // Signals that a temporary buffer is no longer needed. This is currently for + // book-keeping purpose and the memory region are not immediately available + // for re-use. The deallocated memory region are only reclaimed after + // ResetTempAllocations is called as it is right now. + virtual void DeallocateTemp(uint8_t* buf) override; + + // Returns true if all temporary buffers are already deallocated. + virtual bool IsAllTempDeallocated() override; + + // Resets a chain of temporary allocations back to the current head of the + // arena (lowest address). + virtual TfLiteStatus ResetTempAllocations() override; + + // Returns a pointer to the buffer currently assigned to the head section. + // This buffer is set by calling SetHeadSize(). + uint8_t* GetOverlayMemoryAddress() const override; + + // Returns the size of the head section in bytes. + size_t GetNonPersistentUsedBytes() const override; + + // Returns the size of all allocations in the tail section in bytes. + size_t GetPersistentUsedBytes() const override; + + // Returns the number of bytes available with a given alignment. This number + // takes in account any temporary allocations. + size_t GetAvailableMemory(size_t alignment) const override; + + // Returns the number of used bytes in the allocator. This number takes in + // account any temporary allocations. + size_t GetUsedBytes() const; + + TF_LITE_REMOVE_VIRTUAL_DELETE + + protected: + // Returns a pointer to the current end of the head buffer. + uint8_t* head() const; + + // Returns a pointer to the current end of the tail buffer. + uint8_t* tail() const; + + private: + size_t GetBufferSize() const; + uint8_t* buffer_head_; + uint8_t* buffer_tail_; + uint8_t* head_; + uint8_t* tail_; + uint8_t* temp_; + + // The combination of the checksum of outstanding temporary buffer pointers + // AND the count of outstanding temporary buffer provide a low cost mechanism + // to audit temporary buffers' allocation and deallocation. + // + // XOR Check sum for outstanding temp buffers. + // If all temp buffers are deallocated OR no temp buffers are allocated, + // temp_buffer_ptr_check_sum_ == nullptr. + intptr_t temp_buffer_ptr_check_sum_ = 0; + // Count of outstanding temp buffers. + int temp_buffer_count_ = 0; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_ARENA_ALLOCATOR_SINGLE_ARENA_BUFFER_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/compatibility.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/compatibility.h new file mode 100644 index 000000000..983de7d14 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/compatibility.h @@ -0,0 +1,32 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_COMPATIBILITY_H_ +#define TENSORFLOW_LITE_MICRO_COMPATIBILITY_H_ + +// C++ will automatically create class-specific delete operators for virtual +// objects, which by default call the global delete function. For embedded +// applications we want to avoid this, and won't be calling new/delete on these +// objects, so we need to override the default implementation with one that does +// nothing to avoid linking in ::delete(). +// This macro needs to be included in all subclasses of a virtual base class in +// the private section. +#ifdef ARDUINO +#define TF_LITE_REMOVE_VIRTUAL_DELETE \ + void operator delete(void* p) {} +#else +#define TF_LITE_REMOVE_VIRTUAL_DELETE +#endif + +#endif // TENSORFLOW_LITE_MICRO_COMPATIBILITY_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/debug_log.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/debug_log.cpp new file mode 100644 index 000000000..630143ce6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/debug_log.cpp @@ -0,0 +1,30 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 file is empty to ensure that a specialized implementation of +// debug_log.h is used (instead of the default implementation from +// tensorflow/lite/micro/debug_log.cc). +// +// The actual target-specific implementation of debug_log.h is in +// system_setup.cc since that allows us to consolidate all the target-specific +// specializations into one source file. + +#include +#include "tensorflow/lite/micro/debug_log.h" + +extern void TFL_Log(char* s); + +void DebugLog(const char* s) { + TFL_Log((char*)s); +}; \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/debug_log.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/debug_log.h new file mode 100644 index 000000000..c2840d0f4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/debug_log.h @@ -0,0 +1,31 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_ +#define TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// This function should be implemented by each target platform, and provide a +// way for strings to be output to some text stream. For more information, see +// tensorflow/lite/micro/debug_log.cc. +void DebugLog(const char* s); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // TENSORFLOW_LITE_MICRO_DEBUG_LOG_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/fake_micro_context.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/fake_micro_context.cpp new file mode 100644 index 000000000..81f74ae36 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/fake_micro_context.cpp @@ -0,0 +1,106 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/fake_micro_context.h" + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_arena_constants.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { +// Dummy static variables to allow creation of dummy MicroAllocator. +// All tests are guarateed to run serially. +static constexpr int KDummyTensorArenaSize = 256; +static uint8_t dummy_tensor_arena[KDummyTensorArenaSize]; +} // namespace + +FakeMicroContext::FakeMicroContext(TfLiteTensor* tensors, + SingleArenaBufferAllocator* allocator, + MicroGraph* micro_graph) + : MicroContext( + MicroAllocator::Create(dummy_tensor_arena, KDummyTensorArenaSize), + nullptr, micro_graph), + tensors_(tensors), + allocator_(allocator) {} + +TfLiteTensor* FakeMicroContext::AllocateTempTfLiteTensor(int tensor_index) { + allocated_tensor_count_++; + return &tensors_[tensor_index]; +} + +void FakeMicroContext::DeallocateTempTfLiteTensor(TfLiteTensor* tensor) { + allocated_tensor_count_--; +} + +bool FakeMicroContext::IsAllTempTfLiteTensorDeallocated() { + return !allocated_tensor_count_; +} + +TfLiteEvalTensor* FakeMicroContext::GetEvalTensor(int tensor_index) { + TfLiteEvalTensor* eval_tensor = + reinterpret_cast(allocator_->AllocateTemp( + sizeof(TfLiteEvalTensor), alignof(TfLiteEvalTensor))); + TFLITE_DCHECK(eval_tensor != nullptr); + + // In unit tests, the TfLiteTensor pointer contains the source of truth for + // buffers and values: + eval_tensor->data = tensors_[tensor_index].data; + eval_tensor->dims = tensors_[tensor_index].dims; + eval_tensor->type = tensors_[tensor_index].type; + return eval_tensor; +} + +void* FakeMicroContext::AllocatePersistentBuffer(size_t bytes) { + // FakeMicroContext use SingleArenaBufferAllocator, which does not + // automatically apply the buffer alignment like MicroAllocator. The buffer + // alignment is potentially wasteful but allows the fake_micro_context to work + // correctly with optimized kernels. + return allocator_->AllocatePersistentBuffer(bytes, + MicroArenaBufferAlignment()); +} + +TfLiteStatus FakeMicroContext::RequestScratchBufferInArena(size_t bytes, + int* buffer_index) { + TFLITE_DCHECK(buffer_index != nullptr); + + if (scratch_buffer_count_ == kNumScratchBuffers_) { + MicroPrintf("Exceeded the maximum number of scratch tensors allowed (%d).", + kNumScratchBuffers_); + return kTfLiteError; + } + + // For tests, we allocate scratch buffers from the tail and keep them around + // for the lifetime of model. This means that the arena size in the tests will + // be more than what we would have if the scratch buffers could share memory. + scratch_buffers_[scratch_buffer_count_] = + allocator_->AllocatePersistentBuffer(bytes, MicroArenaBufferAlignment()); + TFLITE_DCHECK(scratch_buffers_[scratch_buffer_count_] != nullptr); + + *buffer_index = scratch_buffer_count_++; + return kTfLiteOk; +} + +void* FakeMicroContext::GetScratchBuffer(int buffer_index) { + TFLITE_DCHECK(scratch_buffer_count_ <= kNumScratchBuffers_); + if (buffer_index >= scratch_buffer_count_) { + return nullptr; + } + return scratch_buffers_[buffer_index]; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/fake_micro_context.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/fake_micro_context.h new file mode 100644 index 000000000..31b39d384 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/fake_micro_context.h @@ -0,0 +1,56 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_FAKE_MICRO_CONTEXT_H_ +#define TENSORFLOW_LITE_MICRO_FAKE_MICRO_CONTEXT_H_ + +#include "tensorflow/lite/micro/micro_context.h" +#include "tensorflow/lite/micro/micro_graph.h" + +namespace tflite { +// A fake of MicroContext for kernel util tests. +class FakeMicroContext : public MicroContext { + public: + FakeMicroContext(TfLiteTensor* tensors, SingleArenaBufferAllocator* allocator, + MicroGraph* micro_graph); + + void* AllocatePersistentBuffer(size_t bytes) override; + TfLiteStatus RequestScratchBufferInArena(size_t bytes, + int* buffer_index) override; + void* GetScratchBuffer(int buffer_index) override; + + TfLiteTensor* AllocateTempTfLiteTensor(int tensor_index) override; + void DeallocateTempTfLiteTensor(TfLiteTensor* tensor) override; + bool IsAllTempTfLiteTensorDeallocated(); + + TfLiteEvalTensor* GetEvalTensor(int tensor_index) override; + + private: + static constexpr int kNumScratchBuffers_ = 12; + + int scratch_buffer_count_ = 0; + uint8_t* scratch_buffers_[kNumScratchBuffers_]; + + TfLiteTensor* tensors_; + int allocated_tensor_count_ = 0; + + SingleArenaBufferAllocator* allocator_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_FAKE_MICRO_CONTEXT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/flatbuffer_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/flatbuffer_utils.cpp new file mode 100644 index 000000000..9996172ba --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/flatbuffer_utils.cpp @@ -0,0 +1,84 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/flatbuffer_utils.h" + +namespace tflite { + +FlexbufferWrapper::FlexbufferWrapper(const uint8_t* buffer, size_t size) + : flexbuffers::Vector(flexbuffers::GetRoot(buffer, size).AsVector()) {} + +int64_t FlexbufferWrapper::ElementAsInt64(size_t i) const { + const uint8_t* elem = data_ + i * byte_width_; + return ::flexbuffers::ReadInt64(elem, byte_width_); +} + +uint64_t FlexbufferWrapper::ElementAsUInt64(size_t i) const { + const uint8_t* elem = data_ + i * byte_width_; + return ::flexbuffers::ReadUInt64(elem, byte_width_); +} + +int32_t FlexbufferWrapper::ElementAsInt32(size_t i) const { + return static_cast(ElementAsInt64(i)); +} + +bool FlexbufferWrapper::ElementAsBool(size_t i) const { + return static_cast(ElementAsUInt64(i)); +} + +double FlexbufferWrapper::ElementAsDouble(size_t i) const { + const uint8_t* elem = data_ + i * byte_width_; + return ::flexbuffers::ReadDouble(elem, byte_width_); +} + +float FlexbufferWrapper::ElementAsFloat(size_t i) const { + return static_cast(FlexbufferWrapper::ElementAsDouble(i)); +} + +// TODO(b/192589496): Ops must always be there. Remove this function when fixed +uint32_t NumSubgraphOperators(const SubGraph* subgraph) { + if (subgraph->operators() != nullptr) { + return subgraph->operators()->size(); + } else { + return 0; + } +} +// TODO(b/192589496): Ops must always be there. Remove this function when fixed +uint32_t NumSubgraphOperators(const Model* model, int subgraph_idx) { + const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx); + return NumSubgraphOperators(subgraph); +} + +TfLiteIntArray* FlatBufferVectorToTfLiteTypeArray( + const flatbuffers::Vector* flatbuffer_array) { + // On little-endian machines, TfLiteIntArray happens to have the same memory + // layout as flatbuffers:Vector, so we can reinterpret_cast the + // flatbuffer vector and avoid a copy and malloc. + // TODO(b/188459715): audit this usage of const_cast. + return const_cast( + reinterpret_cast(flatbuffer_array)); +} + +TfLiteFloatArray* FlatBufferVectorToTfLiteTypeArray( + const flatbuffers::Vector* flatbuffer_array) { + // On little-endian machines, TfLiteFloatArray happens to have the same memory + // layout as flatbuffers:Vector, so we can reinterpret_cast the + // flatbuffer vector and avoid a copy and malloc. + // TODO(b/188459715): audit this usage of const_cast. + return const_cast( + reinterpret_cast(flatbuffer_array)); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/flatbuffer_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/flatbuffer_utils.h new file mode 100644 index 000000000..e3f421017 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/flatbuffer_utils.h @@ -0,0 +1,65 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 THIRD_PARTY_TFLITE_MICRO_TENSORFLOW_LITE_MICRO_FLATBUFFER_UTILS_H_ +#define THIRD_PARTY_TFLITE_MICRO_TENSORFLOW_LITE_MICRO_FLATBUFFER_UTILS_H_ + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "third_party/flatbuffers/include/flatbuffers/flexbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { +// Kernels use flexbuffers::Map to pack their init parameters in a tflite file, +// with the parameter names as map keys and the parameter values as the +// corresponding map values. +// Accessing the map values using the flexbuffers:Map class is inline heavy, +// which can cause the code size to bloat beyond what's reasonable for a micro +// application. Use this class instead, when possible. +// FlexbufferWrapper takes advantage of the following properties of +// flexbuffers::Map: +// 1. It can be viewed as a flexbuffers::Vector of the values. +// 2. The values in the vector are ordered alphabetically by their keys. +// 3. All integer and Boolean values are stored as 64-bit numbers. +// 4. All floating point values are stored as double precision numbers. +// The properties are mentioned in the flexbuffers docs, but we rely on +// a unit test to catch design changes. +class FlexbufferWrapper : public flexbuffers::Vector { + public: + // Construct with a serialized flexbuffer 'buffer' of 'size' bytes + explicit FlexbufferWrapper(const uint8_t* buffer, size_t size); + int64_t ElementAsInt64(size_t i) const; + uint64_t ElementAsUInt64(size_t i) const; + int32_t ElementAsInt32(size_t i) const; + bool ElementAsBool(size_t i) const; + double ElementAsDouble(size_t i) const; + float ElementAsFloat(size_t i) const; +}; + +// Return the number of operators in a subgraph tflite +uint32_t NumSubgraphOperators(const SubGraph* subgraph); +uint32_t NumSubgraphOperators(const Model* model, int subgraph_idx); + +// Converts a flatbuffer array to a TfLiteArray. +// TODO(b/188459715): These function convert a const input to a non-const via a +// const_cast. It is unclear exactly why this is required. +TfLiteIntArray* FlatBufferVectorToTfLiteTypeArray( + const flatbuffers::Vector* flatbuffer_array); +TfLiteFloatArray* FlatBufferVectorToTfLiteTypeArray( + const flatbuffers::Vector* flatbuffer_array); + +} // namespace tflite + +#endif // THIRD_PARTY_TFLITE_MICRO_TENSORFLOW_LITE_MICRO_FLATBUFFER_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activation_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activation_utils.h new file mode 100644 index 000000000..95ecc26dd --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activation_utils.h @@ -0,0 +1,57 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_ACTIVATION_UTILS_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_ACTIVATION_UTILS_H_ + +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/max.h" +#include "tensorflow/lite/kernels/internal/min.h" + +namespace tflite { +namespace ops { +namespace micro { + +// Returns the floating point value for a fused activation: +inline float ActivationValFloat(TfLiteFusedActivation act, float a) { + switch (act) { + case kTfLiteActNone: + return a; + case kTfLiteActRelu: + return TfLiteMax(0.0f, a); + case kTfLiteActReluN1To1: + return TfLiteMax(-1.0f, TfLiteMin(a, 1.0f)); + case kTfLiteActRelu6: + return TfLiteMax(0.0f, TfLiteMin(a, 6.0f)); + case kTfLiteActTanh: + return std::tanh(a); + case kTfLiteActSignBit: + return std::signbit(a); + case kTfLiteActSigmoid: + return 1.0f / (1.0f + std::exp(-a)); + } + return 0.0f; // To indicate an unsupported activation (i.e. when a new fused + // activation is added to the enum and not handled here). +} + +} // namespace micro +} // namespace ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_ACTIVATION_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations.cc new file mode 100644 index 000000000..716dd6fc7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations.cc @@ -0,0 +1,120 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/activations.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +void* ReluInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(ReluOpData)); +} + +TfLiteStatus ReluEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const ReluOpData& data = *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kActivationsInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kActivationsOutputTensor); + + switch (input->type) { + case kTfLiteFloat32: { + ReluFloat(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + + return kTfLiteOk; + } + case kTfLiteInt8: { + tflite::ReluQuantized(data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + default: { + MicroPrintf("Only float32 is supported currently, got %s", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + } +} + +void* Relu6Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(Relu6OpData)); +} + +TfLiteStatus Relu6Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const Relu6OpData& data = *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kActivationsInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kActivationsOutputTensor); + + switch (input->type) { + case kTfLiteFloat32: { + Relu6Float(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + + return kTfLiteOk; + } + case kTfLiteInt8: { + Relu6Quantized(data.zero_int8, data.six_int8, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + default: { + MicroPrintf("Only float32 is supported currently, got %s", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + } +} + +} // namespace + +TfLiteRegistration Register_RELU() { + return tflite::micro::RegisterOp(ReluInit, ReluPrepare, ReluEval); +} + +TfLiteRegistration Register_RELU6() { + return tflite::micro::RegisterOp(Relu6Init, Relu6Prepare, Relu6Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations.h new file mode 100644 index 000000000..e953f0e0d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations.h @@ -0,0 +1,63 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_ACTIVATIONS_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_ACTIVATIONS_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +extern const int kActivationsInputTensor; +extern const int kActivationsOutputTensor; + +struct ReluOpData { + ReluParams params; +}; + +struct Relu6OpData { + int8_t six_int8; + int8_t zero_int8; +}; + +void ReluQuantized(const ReluOpData& data, const RuntimeShape& input_shape, + const RuntimeShape& output_shape, const int8_t* input_data, + int8_t* output_data); + +template +void CalculateReluOpData(const TfLiteTensor* input, TfLiteTensor* output, + ReluOpData* data); + +void ReluFloat(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data); + +void Relu6Float(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data); + +void Relu6Quantized(int8_t lower, int8_t upper, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& output_shape, + int8_t* output_data); + +TfLiteStatus ReluPrepare(TfLiteContext* context, TfLiteNode* node); + +TfLiteStatus Relu6Prepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_ACTIVATIONS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations_common.cc new file mode 100644 index 000000000..4403edc87 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/activations_common.cc @@ -0,0 +1,158 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/activations.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +const int kActivationsInputTensor = 0; +const int kActivationsOutputTensor = 0; + +void ReluQuantized(const ReluOpData& data, const RuntimeShape& input_shape, + const RuntimeShape& output_shape, const int8_t* input_data, + int8_t* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const int32_t val = static_cast(input_data[i]); + int32_t clamped = + data.params.output_offset + + MultiplyByQuantizedMultiplier(val - data.params.input_offset, + data.params.output_multiplier, + data.params.output_shift); + clamped = std::max(data.params.quantized_activation_min, clamped); + clamped = std::min(data.params.quantized_activation_max, clamped); + output_data[i] = static_cast(clamped); + } +} + +template +void CalculateReluOpData(const TfLiteTensor* input, TfLiteTensor* output, + ReluOpData* data) { + float act_min = 0.0; + float act_max = std::numeric_limits::infinity(); + double real_multiplier = static_cast(input->params.scale) / + static_cast(output->params.scale); + + const RuntimeShape input_shape = GetTensorShape(input); + const RuntimeShape output_shape = GetTensorShape(output); + + QuantizeMultiplier(real_multiplier, &data->params.output_multiplier, + &data->params.output_shift); + + data->params.quantized_activation_min = std::max( + static_cast(std::numeric_limits::min()), + output->params.zero_point + + static_cast(roundf(act_min / output->params.scale))); + data->params.quantized_activation_max = + act_max == std::numeric_limits::infinity() + ? static_cast(std::numeric_limits::max()) + : std::min(static_cast(std::numeric_limits::max()), + output->params.zero_point + + static_cast( + roundf(act_max / output->params.scale))); + data->params.input_offset = input->params.zero_point; + data->params.output_offset = output->params.zero_point; +} + +void ReluFloat(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const float val = input_data[i]; + const float lower = 0.0f; + const float clamped = val < lower ? lower : val; + output_data[i] = clamped; + } +} + +void Relu6Float(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const float val = input_data[i]; + const float upper = 6.0f; + const float lower = 0.0f; + const float clamped = val > upper ? upper : val < lower ? lower : val; + output_data[i] = clamped; + } +} + +void Relu6Quantized(int8_t lower, int8_t upper, const RuntimeShape& input_shape, + const int8_t* input_data, const RuntimeShape& output_shape, + int8_t* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + for (int i = 0; i < flat_size; ++i) { + const int8_t val = input_data[i]; + const int8_t clamped = val > upper ? upper : val < lower ? lower : val; + output_data[i] = clamped; + } +} + +TfLiteStatus ReluPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + ReluOpData* data = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kActivationsInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kActivationsOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + if (input->type == kTfLiteInt8) { + CalculateReluOpData(input, output, data); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Relu6Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + Relu6OpData* data = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kActivationsInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + + if (input->type == kTfLiteInt8) { + data->six_int8 = FloatToQuantizedType(6.0f, input->params.scale, + input->params.zero_point); + data->zero_int8 = input->params.zero_point; + } + + micro_context->DeallocateTempTfLiteTensor(input); + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add.cc new file mode 100644 index 000000000..81b3b9c9b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add.cc @@ -0,0 +1,165 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/add.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/add.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/add.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +void EvalAdd(TfLiteContext* context, TfLiteNode* node, TfLiteAddParams* params, + const OpDataAdd* data, const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params; + SetActivationParams(data->output_activation_min_f32, + data->output_activation_max_f32, &op_params); + if (data->requires_broadcast) { + reference_ops::BroadcastAdd4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Add(op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} + +TfLiteStatus EvalAddQuantized(TfLiteContext* context, TfLiteNode* node, + TfLiteAddParams* params, const OpDataAdd* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params; + op_params.left_shift = data->left_shift; + op_params.input1_offset = data->input1_offset; + op_params.input1_multiplier = data->input1_multiplier; + op_params.input1_shift = data->input1_shift; + op_params.input2_offset = data->input2_offset; + op_params.input2_multiplier = data->input2_multiplier; + op_params.input2_shift = data->input2_shift; + op_params.output_offset = data->output_offset; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = data->output_shift; + SetActivationParams(data->output_activation_min, data->output_activation_max, + &op_params); + bool need_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + switch (output->type) { + case kTfLiteInt8: { + if (need_broadcast) { + reference_integer_ops::BroadcastAdd4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_integer_ops::Add( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + break; + } + case kTfLiteInt16: { + if (need_broadcast) { + reference_ops::BroadcastAdd4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Add(op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + false); + } + break; + } + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(output->type), output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +void* AddInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataAdd)); +} + +TfLiteStatus AddEval(TfLiteContext* context, TfLiteNode* node) { + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataAdd* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kAddInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kAddInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kAddOutputTensor); + + if (output->type == kTfLiteFloat32) { + EvalAdd(context, node, params, data, input1, input2, output); + } else if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + TF_LITE_ENSURE_OK(context, EvalAddQuantized(context, node, params, data, + input1, input2, output)); + } else { + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(output->type), + output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +TfLiteRegistration Register_ADD() { + return tflite::micro::RegisterOp(AddInit, AddPrepare, AddEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add.h new file mode 100644 index 000000000..e2e5d23ba --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add.h @@ -0,0 +1,77 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_ADD_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_ADD_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +extern const int kAddInputTensor1; +extern const int kAddInputTensor2; +extern const int kAddOutputTensor; + +struct OpDataAdd { + bool requires_broadcast; + + // These fields are used in both the general 8-bit -> 8bit quantized path, + // and the special 16-bit -> 16bit quantized path + int input1_shift; + int input2_shift; + int32_t output_activation_min; + int32_t output_activation_max; + + // These fields are used only in the general 8-bit -> 8bit quantized path + int32_t input1_multiplier; + int32_t input2_multiplier; + int32_t output_multiplier; + int output_shift; + int left_shift; + int32_t input1_offset; + int32_t input2_offset; + int32_t output_offset; + + // Used only for float evals: + float output_activation_min_f32; + float output_activation_max_f32; +}; + +TfLiteStatus CalculateOpDataAdd(TfLiteContext* context, TfLiteAddParams* params, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteTensor* output, OpDataAdd* data); + +TfLiteStatus AddPrepare(TfLiteContext* context, TfLiteNode* node); + +// Generic must define registration function. +TfLiteRegistration Register_ADD(); + +#if defined(CMSIS_NN) +TfLiteRegistration Register_ADD_INT8(); + +TfLiteRegistration Register_ADD_INT16(); +#else +// Fallback registration +inline TfLiteRegistration Register_ADD_INT8() { return Register_ADD(); } + +inline TfLiteRegistration Register_ADD_INT16() { return Register_ADD(); } +#endif +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_ADD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add_common.cc new file mode 100644 index 000000000..b285b800c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add_common.cc @@ -0,0 +1,106 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/add.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/add.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/add.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" + +namespace tflite { + +const int kAddInputTensor1 = 0; +const int kAddInputTensor2 = 1; +const int kAddOutputTensor = 0; + +TfLiteStatus CalculateOpDataAdd(TfLiteContext* context, TfLiteAddParams* params, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteTensor* output, OpDataAdd* data) { + data->requires_broadcast = !HaveSameShapes(input1, input2); + + if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + // 8bit -> 8bit general quantized path, with general rescalings + data->input1_offset = -input1->params.zero_point; + data->input2_offset = -input2->params.zero_point; + data->output_offset = output->params.zero_point; + data->left_shift = (output->type == kTfLiteInt16) ? 15 : 20; + const double twice_max_input_scale = + 2 * static_cast( + std::max(input1->params.scale, input2->params.scale)); + const double real_input1_multiplier = + static_cast(input1->params.scale) / twice_max_input_scale; + const double real_input2_multiplier = + static_cast(input2->params.scale) / twice_max_input_scale; + const double real_output_multiplier = + twice_max_input_scale / + ((1 << data->left_shift) * static_cast(output->params.scale)); + + QuantizeMultiplierSmallerThanOneExp( + real_input1_multiplier, &data->input1_multiplier, &data->input1_shift); + + QuantizeMultiplierSmallerThanOneExp( + real_input2_multiplier, &data->input2_multiplier, &data->input2_shift); + + QuantizeMultiplierSmallerThanOneExp( + real_output_multiplier, &data->output_multiplier, &data->output_shift); + + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, params->activation, output, &data->output_activation_min, + &data->output_activation_max)); + } else if (output->type == kTfLiteFloat32) { + CalculateActivationRange(params->activation, + &data->output_activation_min_f32, + &data->output_activation_max_f32); + } + + return kTfLiteOk; +} + +TfLiteStatus AddPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kAddInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kAddInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kAddOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + OpDataAdd* data = static_cast(node->user_data); + auto* params = reinterpret_cast(node->builtin_data); + + TF_LITE_ENSURE_STATUS( + CalculateOpDataAdd(context, params, input1, input2, output, data)); + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add_n.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add_n.cc new file mode 100644 index 000000000..1139e1a95 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/add_n.cc @@ -0,0 +1,215 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/add_n.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor0 = 0; +constexpr int kOutputTensor = 0; + +constexpr int kAddNIntegerShift = 20; + +// only used with INT8 tensors +struct OpData { + int32_t output_activation_min; + int32_t output_activation_max; + int32_t input_offset; + int32_t output_offset; + int32_t input_multiplier; + int32_t output_multiplier; + int input_shift; + int output_shift; + int left_shift; + int scratch_index; +}; + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + int num_inputs = NumInputs(node); + TF_LITE_ENSURE(context, num_inputs >= 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input_tensor_first = + micro_context->AllocateTempInputTensor(node, kInputTensor0); + TF_LITE_ENSURE(context, input_tensor_first != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + // Check that all tensors have the same shape and type. + TF_LITE_ENSURE_TYPES_EQ(context, output->type, input_tensor_first->type); + for (int i = kInputTensor0 + 1; i < num_inputs; ++i) { + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, i); + TF_LITE_ENSURE(context, input != nullptr); + TF_LITE_ENSURE(context, HaveSameShapes(input_tensor_first, input)); + TF_LITE_ENSURE_TYPES_EQ(context, input_tensor_first->type, input->type); + + // Check that all INT8 input tensors have the same zero-point and scale. + if (input_tensor_first->type == kTfLiteInt8) { + TF_LITE_ENSURE(context, input_tensor_first->params.zero_point == + input->params.zero_point); + TF_LITE_ENSURE(context, + input_tensor_first->params.scale == input->params.scale); + } + + micro_context->DeallocateTempTfLiteTensor(input); + } + + if (output->type == kTfLiteFloat32) { + // Allocate scratch buffer space for pointer to each tensor's data + // and store the scratch buffer index in the node's user_data + int scratch_index; + size_t scratch_size = sizeof(float*) * num_inputs; + TF_LITE_ENSURE_OK(context, context->RequestScratchBufferInArena( + context, scratch_size, &scratch_index)); + node->user_data = + reinterpret_castuser_data)>(scratch_index); + } else if (output->type == kTfLiteInt8) { + node->user_data = + context->AllocatePersistentBuffer(context, sizeof(OpData)); + OpData* data = static_cast(node->user_data); + + // Allocate scratch buffer space for pointer to each tensor's data + // and store the scratch buffer index in OpData + size_t scratch_size = sizeof(int8_t*) * num_inputs; + TF_LITE_ENSURE_OK( + context, context->RequestScratchBufferInArena(context, scratch_size, + &data->scratch_index)); + + // 8bit -> 8bit general quantized path, with general rescalings + data->input_offset = -input_tensor_first->params.zero_point; + data->output_offset = output->params.zero_point; + data->left_shift = kAddNIntegerShift; + const double twice_max_input_scale = + 2 * static_cast(input_tensor_first->params.scale); + const double real_input_multiplier = + static_cast(input_tensor_first->params.scale) / + twice_max_input_scale; + const double real_output_multiplier = + twice_max_input_scale / + ((1 << data->left_shift) * static_cast(output->params.scale)); + + QuantizeMultiplierSmallerThanOneExp( + real_input_multiplier, &data->input_multiplier, &data->input_shift); + + QuantizeMultiplierSmallerThanOneExp( + real_output_multiplier, &data->output_multiplier, &data->output_shift); + + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, kTfLiteActNone, output, &data->output_activation_min, + &data->output_activation_max)); + } else { + MicroPrintf("ADD_N only supports FLOAT32 and INT8, got %s.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + + micro_context->DeallocateTempTfLiteTensor(input_tensor_first); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +template +inline const T** CopyInputsToScratchBuffer(TfLiteContext* context, + TfLiteNode* node, + const int scratch_index) { + int num_inputs = NumInputs(node); + void* scratch_buffer = context->GetScratchBuffer(context, scratch_index); + const T** all_inputs = static_cast(scratch_buffer); + for (int i = 0; i < num_inputs; i++) { + const TfLiteEvalTensor* next_input = + tflite::micro::GetEvalInput(context, node, kInputTensor0 + i); + all_inputs[i] = tflite::micro::GetTensorData(next_input); + } + + return all_inputs; +} + +template +void EvalAddN(TfLiteContext* context, TfLiteNode* node, + TfLiteEvalTensor* output) { + int num_inputs = NumInputs(node); + + int scratch_index = + static_cast(reinterpret_cast(node->user_data)); + const T** all_inputs = + CopyInputsToScratchBuffer(context, node, scratch_index); + + reference_ops::AddN(tflite::micro::GetTensorShape(output), num_inputs, + all_inputs, tflite::micro::GetTensorData(output)); +} + +template +void EvalAddNQuantized(TfLiteContext* context, TfLiteNode* node, + TfLiteEvalTensor* output) { + int num_inputs = NumInputs(node); + + OpData* data = static_cast(node->user_data); + const T** all_inputs = + CopyInputsToScratchBuffer(context, node, data->scratch_index); + + ArithmeticParams params; + params.left_shift = data->left_shift; + params.input1_offset = data->input_offset; + params.input1_multiplier = data->input_multiplier; + params.input1_shift = data->input_shift; + params.output_offset = data->output_offset; + params.output_multiplier = data->output_multiplier; + params.output_shift = data->output_shift; + SetActivationParams(data->output_activation_min, data->output_activation_max, + ¶ms); + + reference_ops::AddN(params, tflite::micro::GetTensorShape(output), num_inputs, + all_inputs, tflite::micro::GetTensorData(output)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + if (output->type == kTfLiteFloat32) { + EvalAddN(context, node, output); + } else if (output->type == kTfLiteInt8) { + EvalAddNQuantized(context, node, output); + } else { + MicroPrintf("ADD_N only supports FLOAT32 and INT8, got %s.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_ADD_N() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/arg_min_max.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/arg_min_max.cc new file mode 100644 index 000000000..d0e433c5d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/arg_min_max.cc @@ -0,0 +1,116 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/arg_min_max.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/micro_utils.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace arg_min_max { + +constexpr int kInputTensor = 0; +constexpr int kAxis = 1; +constexpr int kOutputTensor = 0; + +template +inline void ArgMinMaxHelper(const RuntimeShape& input1_shape, + const T1* input1_data, const T3* input2_data, + const RuntimeShape& output_shape, T2* output_data, + bool is_arg_max) { + if (is_arg_max) { + reference_ops::ArgMinMax(input1_shape, input1_data, input2_data, + output_shape, output_data, micro::Greater()); + } else { + reference_ops::ArgMinMax(input1_shape, input1_data, input2_data, + output_shape, output_data, micro::Less()); + } +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node, bool is_arg_max) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* axis = + tflite::micro::GetEvalInput(context, node, kAxis); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + +#define TF_LITE_ARG_MIN_MAX(data_type, axis_type, output_type) \ + ArgMinMaxHelper(tflite::micro::GetTensorShape(input), \ + tflite::micro::GetTensorData(input), \ + tflite::micro::GetTensorData(axis), \ + tflite::micro::GetTensorShape(output), \ + tflite::micro::GetTensorData(output), \ + is_arg_max) + if (axis->type == kTfLiteInt32) { + if (output->type == kTfLiteInt32) { + switch (input->type) { + case kTfLiteFloat32: + TF_LITE_ARG_MIN_MAX(float, int32_t, int32_t); + break; + case kTfLiteInt8: + TF_LITE_ARG_MIN_MAX(int8_t, int32_t, int32_t); + break; + default: + MicroPrintf( + "Only float32, uint8_t and int8_t are " + "supported currently, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + } else { + MicroPrintf("Only int32_t are supported currently, got %s.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else { + MicroPrintf("Only int32_t are supported currently, got %s.", + TfLiteTypeGetName(axis->type)); + return kTfLiteError; + } + +#undef TF_LITE_ARG_MIN_MAX + + return kTfLiteOk; +} + +TfLiteStatus ArgMinEval(TfLiteContext* context, TfLiteNode* node) { + return Eval(context, node, false); +} + +TfLiteStatus ArgMaxEval(TfLiteContext* context, TfLiteNode* node) { + return Eval(context, node, true); +} + +} // namespace arg_min_max + +TfLiteRegistration Register_ARG_MAX() { + return tflite::micro::RegisterOp(nullptr, nullptr, arg_min_max::ArgMaxEval); +} + +TfLiteRegistration Register_ARG_MIN() { + return tflite::micro::RegisterOp(nullptr, nullptr, arg_min_max::ArgMinEval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/assign_variable.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/assign_variable.cc new file mode 100644 index 000000000..f3aa12fa4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/assign_variable.cc @@ -0,0 +1,101 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_resource_variable.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +namespace { + +constexpr int kInputVariableId = 0; +constexpr int kInputValue = 1; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 0); + + // This must be a TfLiteEvalTensor despite this being in Prepare, because + // CreateTensor allocates a temp tensor from the flatbuffer, which does not + // contain the correct ID generated within the VAR_HANDLE op. EvalTensors are + // all allocated during StartModelAllocation which happens before + // init/prepare, and VAR_HANDLE Prepare() references its own op_data in the + // TfLiteEvalTensor, so reading the ID here is valid. + const TfLiteEvalTensor* input_resource_id_tensor = + tflite::micro::GetEvalInput(context, node, kInputVariableId); + TFLITE_DCHECK(input_resource_id_tensor != nullptr); + TF_LITE_ENSURE(context, (input_resource_id_tensor->type == kTfLiteResource || + input_resource_id_tensor->type == kTfLiteInt32)); + TF_LITE_ENSURE_EQ(context, NumElements(input_resource_id_tensor->dims), 1); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + TfLiteTensor* input_value = + micro_context->AllocateTempInputTensor(node, kInputValue); + TFLITE_DCHECK(input_value != nullptr); + + MicroGraph& graph_info = micro_context->graph(); + + MicroResourceVariables* resources = graph_info.GetResourceVariables(); + TF_LITE_ENSURE_OK(context, + resources->Allocate(input_resource_id_tensor->data.i32[0], + context, input_value)); + + micro_context->DeallocateTempTfLiteTensor(input_value); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input_id = + tflite::micro::GetEvalInput(context, node, kInputVariableId); + TFLITE_DCHECK(input_id != nullptr); + + const TfLiteEvalTensor* input_value = + tflite::micro::GetEvalInput(context, node, kInputValue); + TFLITE_DCHECK(input_value != nullptr); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + MicroGraph& graph_info = micro_context->graph(); + + MicroResourceVariables* resources = graph_info.GetResourceVariables(); + if (resources == nullptr) { + MicroPrintf( + "ASSIGN_VARIABLE requires resource variables. Please create " + "ResourceVariables and pass it to the interpreter."); + return kTfLiteError; + } + TF_LITE_ENSURE_OK(context, + resources->Assign(input_id->data.i32[0], input_value)); + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_ASSIGN_VARIABLE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/batch_to_space_nd.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/batch_to_space_nd.cc new file mode 100644 index 000000000..83fb35688 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/batch_to_space_nd.cc @@ -0,0 +1,112 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/batch_to_space_nd.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +namespace { + +constexpr int kInputTensor = 0; +constexpr int kBlockShapeTensor = 1; +constexpr int kCropsTensor = 2; +constexpr int kOutputTensor = 0; + +// Currently, only 3D NHC and 4D NHWC input/output op_context are supported. +// In case of 3D input, it will be extended to 3D NHWC by adding W=1. +// The 4D array need to have exactly 2 spatial dimensions. +// TODO(b/149952582): Support arbitrary dimension in SpaceToBatchND. +const int kInputOutputMinDimensionNum = 3; +const int kInputOutputMaxDimensionNum = 4; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, input != nullptr && output != nullptr); + + TF_LITE_ENSURE(context, NumDimensions(input) >= kInputOutputMinDimensionNum); + TF_LITE_ENSURE(context, NumDimensions(output) >= kInputOutputMinDimensionNum); + TF_LITE_ENSURE(context, NumDimensions(input) <= kInputOutputMaxDimensionNum); + TF_LITE_ENSURE(context, NumDimensions(output) <= kInputOutputMaxDimensionNum); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* block_shape = + tflite::micro::GetEvalInput(context, node, kBlockShapeTensor); + const TfLiteEvalTensor* crops = + tflite::micro::GetEvalInput(context, node, kCropsTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + reference_ops::BatchToSpaceND( + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(block_shape), + tflite::micro::GetTensorData(block_shape), + tflite::micro::GetTensorShape(crops), + tflite::micro::GetTensorData(crops), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::BatchToSpaceND( + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(block_shape), + tflite::micro::GetTensorData(block_shape), + tflite::micro::GetTensorShape(crops), + tflite::micro::GetTensorData(crops), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_BATCH_TO_SPACE_ND() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/broadcast_args.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/broadcast_args.cc new file mode 100644 index 000000000..be2672ec9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/broadcast_args.cc @@ -0,0 +1,91 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/broadcast_args.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_context.h" + +namespace tflite { +namespace { +constexpr int kShape1Tensor = 0; +constexpr int kShape2Tensor = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus BroadcastArgsPrepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE(context, NumInputs(node) == 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* shape1 = + micro_context->AllocateTempInputTensor(node, kShape1Tensor); + TfLiteTensor* shape2 = + micro_context->AllocateTempInputTensor(node, kShape2Tensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + + TF_LITE_ENSURE(context, + shape1->type == kTfLiteInt32 || shape1->type == kTfLiteInt64); + TF_LITE_ENSURE_EQ(context, shape1->type, shape2->type); + TF_LITE_ENSURE_EQ(context, shape1->type, output->type); + + // Ensures the shapes are 1D tensor. + TF_LITE_ENSURE_EQ(context, NumDimensions(shape1), 1); + TF_LITE_ENSURE_EQ(context, NumDimensions(shape2), 1); + + // Ensure the shape of the output tensor is compatible + TF_LITE_ENSURE_EQ(context, NumDimensions(output), 1); + + micro_context->DeallocateTempTfLiteTensor(shape1); + micro_context->DeallocateTempTfLiteTensor(shape2); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus BroadcastArgsEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* shape1 = + micro::GetEvalInput(context, node, kShape1Tensor); + const TfLiteEvalTensor* shape2 = + micro::GetEvalInput(context, node, kShape2Tensor); + TfLiteEvalTensor* output = micro::GetEvalOutput(context, node, kOutputTensor); + + if (output->type == kTfLiteInt32) { + reference_ops::BroadcastArgs( + micro::GetTensorShape(shape1), micro::GetTensorData(shape1), + micro::GetTensorShape(shape2), micro::GetTensorData(shape2), + micro::GetTensorShape(output), micro::GetTensorData(output)); + } else { + reference_ops::BroadcastArgs( + micro::GetTensorShape(shape1), micro::GetTensorData(shape1), + micro::GetTensorShape(shape2), micro::GetTensorData(shape2), + micro::GetTensorShape(output), micro::GetTensorData(output)); + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_BROADCAST_ARGS() { + return tflite::micro::RegisterOp(nullptr, BroadcastArgsPrepare, + BroadcastArgsEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/broadcast_to.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/broadcast_to.cc new file mode 100644 index 000000000..63a14db25 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/broadcast_to.cc @@ -0,0 +1,123 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/broadcast_to.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_context.h" + +namespace tflite { + +namespace { +constexpr int kInputTensor = 0; +constexpr int kShapeTensor = 1; +constexpr int kOutputTensor = 0; +// Support a maximum of 5 dimensions in TFLM. +constexpr int kMaxDims = 5; + +TfLiteStatus ValidateOutputTensor(TfLiteContext* context, TfLiteTensor* input, + TfLiteTensor* shape, TfLiteTensor* output) { + // Ensures the shape is 1D tensor. + TF_LITE_ENSURE_EQ(context, NumDimensions(shape), 1); + + // Ensure output dims is not less than input dims. + int input_num_dims = NumDimensions(input); + int output_num_dims = NumDimensions(output); + int shape_num_dims = SizeOfDimension(shape, 0); + TF_LITE_ENSURE_MSG(context, output_num_dims == shape_num_dims, + "Output must match with the expected shape dimension."); + TF_LITE_ENSURE_MSG(context, input_num_dims <= output_num_dims, + "Output shape must be broadcastable from input shape."); + TF_LITE_ENSURE_MSG(context, output_num_dims <= kMaxDims, + "BroadcastTo only supports 1-5D tensor."); + + // Check if output shape is broadcastable from input shape. + auto get_shape_data = [shape](int i) -> int32_t { + if (shape->type == kTfLiteInt32) { + return GetTensorData(shape)[i]; + } else { + return GetTensorData(shape)[i]; + } + }; + + int extending_dims = output_num_dims - input_num_dims; + for (int idx = 0; idx < input_num_dims; ++idx) { + TF_LITE_ENSURE_MSG( + context, + (SizeOfDimension(input, idx) == 1 || + SizeOfDimension(input, idx) == get_shape_data(extending_dims + idx)), + "Output shape must be broadcastable from input shape."); + } + + // Validating the shape of the output tensor. + tflite::RuntimeShape output_shape = tflite::GetTensorShape(output); + for (int idx = 0; idx < output_num_dims; ++idx) { + TF_LITE_ENSURE(context, output_shape.Dims(idx) == get_shape_data(idx)); + } + return kTfLiteOk; +} + +TfLiteStatus BroadcastToPrepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE(context, NumInputs(node) == 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TfLiteTensor* shape = + micro_context->AllocateTempInputTensor(node, kShapeTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + + TF_LITE_ENSURE_MSG(context, (NumDimensions(input) <= kMaxDims), + "BroadcastTo only supports 1-5D tensor."); + + TF_LITE_ENSURE(context, + shape->type == kTfLiteInt32 || shape->type == kTfLiteInt64); + TF_LITE_ENSURE_EQ(context, input->type, output->type); + + // Does not support String type due to its variable size. This limitation is + // the same as TFLite. + TF_LITE_ENSURE(context, input->type != kTfLiteString); + + TF_LITE_ENSURE_STATUS(ValidateOutputTensor(context, input, shape, output)); + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(shape); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus BroadcastToEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = micro::GetEvalOutput(context, node, kOutputTensor); + + // BroadcastTo op support upto 5 dims, different from 8 dims in TFLite. + reference_ops::BroadcastTo( + micro::GetTensorShape(input), input->data.raw, + micro::GetTensorShape(output), output->data.raw, input->type); + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_BROADCAST_TO() { + return tflite::micro::RegisterOp(nullptr, BroadcastToPrepare, + BroadcastToEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/call_once.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/call_once.cc new file mode 100644 index 000000000..200242b2c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/call_once.cc @@ -0,0 +1,88 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_context.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +namespace { + +struct OpData { + int init_subgraph_index; + bool has_run; +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + OpData* op_data = reinterpret_cast(node->user_data); + const auto* params = + reinterpret_cast(node->builtin_data); + op_data->init_subgraph_index = params->init_subgraph_index; + op_data->has_run = false; + + TF_LITE_ENSURE(context, NumInputs(node) == 0); + TF_LITE_ENSURE(context, NumOutputs(node) == 0); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + MicroGraph& graph_info = micro_context->graph(); + + TF_LITE_ENSURE(context, + op_data->init_subgraph_index < graph_info.NumSubgraphs()); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + OpData* op_data = reinterpret_cast(node->user_data); + + // Call once only runs one time then is a no-op for every subsequent call. + if (op_data->has_run) { + return kTfLiteOk; + } + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + MicroGraph& graph_info = micro_context->graph(); + + TF_LITE_ENSURE_OK(context, + graph_info.InvokeSubgraph(op_data->init_subgraph_index)); + + op_data->has_run = true; + + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_CALL_ONCE() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/cast.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/cast.cc new file mode 100644 index 000000000..0a0204d2e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/cast.cc @@ -0,0 +1,114 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +template +void copyCast(const FromT* in, ToT* out, int num_elements) { + std::transform(in, in + num_elements, out, + [](FromT a) { return static_cast(a); }); +} + +template +TfLiteStatus copyToTensor(TfLiteContext* context, const FromT* in, + TfLiteEvalTensor* out, int num_elements) { + switch (out->type) { + case kTfLiteInt8: + copyCast(in, out->data.int8, num_elements); + break; + case kTfLiteInt16: + copyCast(in, out->data.i16, num_elements); + break; + case kTfLiteInt32: + copyCast(in, out->data.i32, num_elements); + break; + case kTfLiteFloat32: + copyCast(in, tflite::micro::GetTensorData(out), num_elements); + break; + default: + // Unsupported type. + MicroPrintf("Output type %s (%d) not supported.", + TfLiteTypeGetName(out->type), out->type); + } + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + int num_elements = MatchingFlatSize(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output)); + + switch (input->type) { + case kTfLiteInt8: + return copyToTensor(context, input->data.int8, output, num_elements); + case kTfLiteInt16: + return copyToTensor(context, tflite::micro::GetTensorData(input), + output, num_elements); + case kTfLiteInt32: + return copyToTensor(context, tflite::micro::GetTensorData(input), + output, num_elements); + case kTfLiteUInt32: + return copyToTensor(context, + tflite::micro::GetTensorData(input), output, + num_elements); + case kTfLiteFloat32: + return copyToTensor(context, tflite::micro::GetTensorData(input), + output, num_elements); + default: + // Unsupported type. + MicroPrintf("Input type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + } + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_CAST() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ceil.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ceil.cc new file mode 100644 index 000000000..a390a7355 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ceil.cc @@ -0,0 +1,75 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/ceil.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace ceil { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteFloat32); + TF_LITE_ENSURE_TYPES_EQ(context, output->type, input->type); + TF_LITE_ENSURE_EQ(context, output->bytes, input->bytes); + TF_LITE_ENSURE_EQ(context, output->dims->size, input->dims->size); + for (int i = 0; i < output->dims->size; ++i) { + TF_LITE_ENSURE_EQ(context, output->dims->data[i], input->dims->data[i]); + } + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + reference_ops::Ceil(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + + return kTfLiteOk; +} +} // namespace ceil + +TfLiteRegistration Register_CEIL() { + return tflite::micro::RegisterOp(nullptr, ceil::Prepare, ceil::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer.cc new file mode 100644 index 000000000..9779c32d9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer.cc @@ -0,0 +1,117 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/circular_buffer.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +/* + * The circular buffer custom operator is used to implement strided streaming + * convolutions on TFLite Micro. Each time this operator is invoked, it checks + * whether or not to run, based on a predetermined stride in time. If the op + * runs, it inserts the input into the end of the output buffer and shifts the + * output values towards the start of the buffer. It discards the oldest value + * in the output buffer. + * + * Input: [, , , ] + * + * After shifting: + * Output: [, , , ] + * + * We make some assumptions in this custom operator: + * - Input shape must be [1, 1, 1, depth] + * - Output shape must be [1, num_slots, 1, depth] + * - Input and output types must match. + * - Input and output quantization params must be identical. + */ +namespace tflite { + +void* CircularBufferInit(TfLiteContext* context, const char* buffer, + size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + OpDataCircularBuffer* op_data = static_cast( + context->AllocatePersistentBuffer(context, sizeof(OpDataCircularBuffer))); + + if (buffer != nullptr && length > 0) { + const uint8_t* buffer_t = reinterpret_cast(buffer); + tflite::FlexbufferWrapper wrapper(buffer_t, length); + op_data->cycles_max = wrapper.ElementAsInt32(kCircularBufferCyclesMaxIndex); + } else { + op_data->cycles_max = 0; + } + + return op_data; +} + +// Shifts buffer over by the output depth, and write new input to end of buffer. +// num_slots is the number of samples stored in the output buffer. +// depth is the size of each sample. +void EvalInt8(const int8_t* input, int num_slots, int depth, int8_t* output) { + memmove(output, &output[depth], (num_slots - 1) * depth); + memcpy(&output[(num_slots - 1) * depth], input, depth); +} + +TfLiteStatus CircularBufferEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kCircularBufferInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kCircularBufferOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataCircularBuffer* data = + reinterpret_cast(node->user_data); + + int num_slots = output->dims->data[1]; + int depth = output->dims->data[2] * output->dims->data[3]; + + if (input->type == kTfLiteInt8) { + EvalInt8(tflite::micro::GetTensorData(input), num_slots, depth, + tflite::micro::GetTensorData(output)); + } else { + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + + if (--data->cycles_until_run != 0) { + // Signal the interpreter to end current run if the delay before op invoke + // has not been reached. + // TODO(b/149795762): Add kTfLiteAbort to TfLiteStatus enum. + return static_cast(kTfLiteAbort); + } + + data->cycles_until_run = data->cycles_max; + + return kTfLiteOk; +} + +TfLiteRegistration* Register_CIRCULAR_BUFFER() { + static TfLiteRegistration r = tflite::micro::RegisterOp( + CircularBufferInit, CircularBufferPrepare, CircularBufferEval); + return &r; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer.h new file mode 100644 index 000000000..51adf746d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer.h @@ -0,0 +1,48 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_CIRCULAR_BUFFER_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_CIRCULAR_BUFFER_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// The CircularBuffer op has one input and one output tensor. +extern const int kCircularBufferInputTensor; +extern const int kCircularBufferOutputTensor; + +// Indices into the init flexbuffer's vector. +// The parameter's name is in the comment that follows. +// Elements in the vectors are ordered alphabetically by parameter name. +extern const int kCircularBufferCyclesMaxIndex; // 'cycles_max' + +// TODO(b/149795762): Add this to TfLiteStatus enum. +extern const TfLiteStatus kTfLiteAbort; + +// These fields control the stride period of a strided streaming model. This op +// returns kTfLiteAbort until cycles_until_run-- is zero. At this time, +// cycles_until_run is reset to cycles_max. +struct OpDataCircularBuffer { + int cycles_until_run; + int cycles_max; +}; + +TfLiteStatus CircularBufferPrepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_CIRCULAR_BUFFER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer_common.cc new file mode 100644 index 000000000..81db6e65f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer_common.cc @@ -0,0 +1,97 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/kernels/circular_buffer.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { + +// The CircularBuffer op has one input and one output tensor. +const int kCircularBufferInputTensor = 0; +const int kCircularBufferOutputTensor = 0; + +// Indices into the init flexbuffer's vector. +// The parameter's name is in the comment that follows. +// Elements in the vectors are ordered alphabetically by parameter name. +const int kCircularBufferCyclesMaxIndex = 0; // 'cycles_max' + +// TODO(b/149795762): Add this to TfLiteStatus enum. +const TfLiteStatus kTfLiteAbort = static_cast(-9); + +TfLiteStatus CircularBufferPrepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kCircularBufferInputTensor); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor( + node, kCircularBufferOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataCircularBuffer* op_data = + static_cast(node->user_data); + + TF_LITE_ENSURE(context, input != nullptr); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_EQ(context, input->dims->data[0], output->dims->data[0]); + TF_LITE_ENSURE_EQ(context, 1, input->dims->data[1]); + TF_LITE_ENSURE_EQ(context, input->dims->data[2], output->dims->data[2]); + TF_LITE_ENSURE_EQ(context, output->dims->data[3], input->dims->data[3]); + + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + // The circular buffer custom operator currently only supports int8. + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteInt8); + + if (op_data->cycles_max <= 0) { + // The last circular buffer layer simply accumulates outputs, and does not + // run periodically. + // TODO(b/150001379): Move this special case logic to the tflite flatbuffer. + static int cb_prepare_count = 0; + cb_prepare_count++; + // These checks specifically work for the only two streaming models + // supported on TFLM. They use the shape of the output tensor along with the + // layer number to determine if the circular buffer period should be 1 or 2. + + // These models are outlined int the following documents: + // https://docs.google.com/document/d/1lc_G2ZFhjiKFo02UHjBaljye1xsL0EkfybkaVELEE3Q/edit?usp=sharing + // https://docs.google.com/document/d/1pGc42PuWyrk-Jy1-9qeqtggvsmHr1ifz8Lmqfpr2rKA/edit?usp=sharing + if (output->dims->data[1] == 5 || output->dims->data[1] == 13 || + output->dims->data[1] == 25 || + (cb_prepare_count == 5 && output->dims->data[2] == 2 && + output->dims->data[3] == 96)) { + op_data->cycles_max = 1; + cb_prepare_count = 0; + } else { + op_data->cycles_max = 2; + } + } + op_data->cycles_until_run = op_data->cycles_max; + node->user_data = op_data; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer_flexbuffers_generated_data.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer_flexbuffers_generated_data.h new file mode 100644 index 000000000..2fbf4fe96 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/circular_buffer_flexbuffers_generated_data.h @@ -0,0 +1,22 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_FLEXBUFFERS_GENERATED_DATA_H +#define TENSORFLOW_LITE_MICRO_KERNELS_FLEXBUFFERS_GENERATED_DATA_H + +extern const int g_gen_data_size_circular_buffer_config; +extern const unsigned char g_gen_data_circular_buffer_config[]; + +#endif diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/comparisons.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/comparisons.cc new file mode 100644 index 000000000..597856cd2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/comparisons.cc @@ -0,0 +1,618 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/comparisons.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace comparisons { +namespace { + +struct OpData { + ComparisonParams params; +}; + +constexpr int kInputTensor1 = 0; +constexpr int kInputTensor2 = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus EqualEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + RuntimeShape input1_shape = tflite::micro::GetTensorShape(input1); + RuntimeShape input2_shape = tflite::micro::GetTensorShape(input2); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + bool* output_data = tflite::micro::GetTensorData(output); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + switch (input1->type) { + case kTfLiteBool: + requires_broadcast + ? reference_ops::Broadcast4DSlowEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::EqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteFloat32: + requires_broadcast + ? reference_ops::Broadcast4DSlowEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::EqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt32: + requires_broadcast + ? reference_ops::Broadcast4DSlowEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::EqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt64: + requires_broadcast + ? reference_ops::Broadcast4DSlowEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::EqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt8: + requires_broadcast + ? reference_ops::Broadcast4DSlowEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::EqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +// TODO(renjieliu): Refactor the logic to avoid duplications. +TfLiteStatus NotEqualEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + RuntimeShape input1_shape = tflite::micro::GetTensorShape(input1); + RuntimeShape input2_shape = tflite::micro::GetTensorShape(input2); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + bool* output_data = tflite::micro::GetTensorData(output); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + switch (input1->type) { + case kTfLiteBool: + requires_broadcast + ? reference_ops::Broadcast4DSlowNotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::NotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteFloat32: + requires_broadcast + ? reference_ops::Broadcast4DSlowNotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::NotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt32: + requires_broadcast + ? reference_ops::Broadcast4DSlowNotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::NotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt64: + requires_broadcast + ? reference_ops::Broadcast4DSlowNotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::NotEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt8: + requires_broadcast + ? reference_ops::Broadcast4DSlowNotEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::NotEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus GreaterEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + RuntimeShape input1_shape = tflite::micro::GetTensorShape(input1); + RuntimeShape input2_shape = tflite::micro::GetTensorShape(input2); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + bool* output_data = tflite::micro::GetTensorData(output); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + switch (input1->type) { + case kTfLiteFloat32: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt32: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt64: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt8: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus GreaterEqualEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + RuntimeShape input1_shape = tflite::micro::GetTensorShape(input1); + RuntimeShape input2_shape = tflite::micro::GetTensorShape(input2); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + bool* output_data = tflite::micro::GetTensorData(output); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + switch (input1->type) { + case kTfLiteFloat32: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt32: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt64: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt8: + requires_broadcast + ? reference_ops::Broadcast4DSlowGreaterEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::GreaterEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus LessEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + RuntimeShape input1_shape = tflite::micro::GetTensorShape(input1); + RuntimeShape input2_shape = tflite::micro::GetTensorShape(input2); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + bool* output_data = tflite::micro::GetTensorData(output); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + switch (input1->type) { + case kTfLiteFloat32: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt32: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt64: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt8: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus LessEqualEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + RuntimeShape input1_shape = tflite::micro::GetTensorShape(input1); + RuntimeShape input2_shape = tflite::micro::GetTensorShape(input2); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + bool* output_data = tflite::micro::GetTensorData(output); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + switch (input1->type) { + case kTfLiteFloat32: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt32: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt64: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessEqualNoScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + case kTfLiteInt8: + requires_broadcast + ? reference_ops::Broadcast4DSlowLessEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data) + : reference_ops::LessEqualWithScaling( + data->params, input1_shape, + tflite::micro::GetTensorData(input1), input2_shape, + tflite::micro::GetTensorData(input2), output_shape, + output_data); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + OpData* data = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + + if (input1->type == kTfLiteInt8) { + auto input1_offset = -input1->params.zero_point; + auto input2_offset = -input2->params.zero_point; + const int kLeftShift = 8; + + int32_t input1_multiplier; + int input1_shift; + QuantizeMultiplierSmallerThanOneExp( + static_cast(input1->params.scale), &input1_multiplier, + &input1_shift); + int32_t input2_multiplier; + int input2_shift; + QuantizeMultiplierSmallerThanOneExp( + static_cast(input2->params.scale), &input2_multiplier, + &input2_shift); + + data->params.left_shift = kLeftShift; + data->params.input1_offset = input1_offset; + data->params.input1_multiplier = input1_multiplier; + data->params.input1_shift = input1_shift; + data->params.input2_offset = input2_offset; + data->params.input2_multiplier = input2_multiplier; + data->params.input2_shift = input2_shift; + } + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + + return kTfLiteOk; +} + +} // namespace comparisons + +TfLiteRegistration Register_EQUAL() { + return tflite::micro::RegisterOp(comparisons::Init, comparisons::Prepare, + comparisons::EqualEval); +} + +TfLiteRegistration Register_NOT_EQUAL() { + return tflite::micro::RegisterOp(comparisons::Init, comparisons::Prepare, + comparisons::NotEqualEval); +} + +TfLiteRegistration Register_GREATER() { + return tflite::micro::RegisterOp(comparisons::Init, comparisons::Prepare, + comparisons::GreaterEval); +} + +TfLiteRegistration Register_GREATER_EQUAL() { + return tflite::micro::RegisterOp(comparisons::Init, comparisons::Prepare, + comparisons::GreaterEqualEval); +} + +TfLiteRegistration Register_LESS() { + return tflite::micro::RegisterOp(comparisons::Init, comparisons::Prepare, + comparisons::LessEval); +} + +TfLiteRegistration Register_LESS_EQUAL() { + return tflite::micro::RegisterOp(comparisons::Init, comparisons::Prepare, + comparisons::LessEqualEval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/concatenation.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/concatenation.cc new file mode 100644 index 000000000..a3f1cc346 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/concatenation.cc @@ -0,0 +1,263 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/concatenation.h" + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/portable_tensor.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace concatenation { + +constexpr int kMaxInputNum = 10; // Maximum number of input tensors +constexpr int kOutputTensor = 0; + +struct OpData { + ConcatenationParams params; +}; + +// Handles negative axis index, coerces to positive index value. +inline int CalculatePositiveAxis(int axis, const TfLiteTensor* output_tensor) { + if (axis >= 0) { + return axis; + } else { + return NumDimensions(output_tensor) + axis; + } +} + +// The following functions are helpers to get tensor data in the format that the +// reference op implementation expects. They provide the same functionality as +// class VectorOfTensors and class VectorOfQuantizedTensors in TFLite. + +// Gets shapes from a list of tensors. +inline void GetAllInputTensorShapes(const TfLiteContext* context, + const TfLiteNode* node, + RuntimeShape all_shapes[kMaxInputNum]) { + TFLITE_DCHECK(context != nullptr); + TFLITE_DCHECK(node != nullptr); + for (int i = 0; i < node->inputs->size; ++i) { + const TfLiteEvalTensor* t = tflite::micro::GetEvalInput(context, node, i); + RuntimeShape shape = tflite::micro::GetTensorShape(t); + all_shapes[i].ReplaceWith(shape.DimensionsCount(), shape.DimsData()); + } +} + +// Get shape pointers from a list of shapes. +inline void GetShapesPointers(const RuntimeShape* shapes, size_t num, + const RuntimeShape* pointers[]) { + for (size_t i = 0; i < num; ++i) { + pointers[i] = &shapes[i]; + } +} + +// Gets data pointers from a list of tensors. +template +inline void GetAllInputTensorData(const TfLiteContext* context, + const TfLiteNode* node, + T* all_data[kMaxInputNum]) { + TFLITE_DCHECK(context != nullptr); + TFLITE_DCHECK(node != nullptr); + for (int i = 0; i < node->inputs->size; ++i) { + const TfLiteEvalTensor* t = tflite::micro::GetEvalInput(context, node, i); + all_data[i] = tflite::micro::GetTensorData(t); + } +} + +template +void EvalUnquantized(TfLiteContext* context, TfLiteNode* node) { + // Collect the shapes and data pointer of input tensors + RuntimeShape inputs_shape[kMaxInputNum]; + const RuntimeShape* inputs_shape_ptr[kMaxInputNum]; + const data_type* inputs_data[kMaxInputNum]; + GetAllInputTensorShapes(context, node, inputs_shape); + GetShapesPointers(inputs_shape, node->inputs->size, inputs_shape_ptr); + GetAllInputTensorData(context, node, inputs_data); + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + reference_ops::Concatenation(data->params, inputs_shape_ptr, inputs_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + // This function only checks the types. Additional shape validations are + // performed in the reference implementation called during Eval(). + const TfLiteConcatenationParams* params = + reinterpret_cast(node->builtin_data); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input_tensor = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input_tensor != nullptr); + TfLiteType input_type = input_tensor->type; + TfLiteTensor* output_tensor = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output_tensor != nullptr); + TfLiteType output_type = output_tensor->type; + + micro_context->DeallocateTempTfLiteTensor(input_tensor); + micro_context->DeallocateTempTfLiteTensor(output_tensor); + + // Check activation and input type + TF_LITE_ENSURE_EQ(context, params->activation, kTfLiteActNone); + TF_LITE_ENSURE(context, + input_type == kTfLiteFloat32 || input_type == kTfLiteInt8 || + input_type == kTfLiteInt16 || input_type == kTfLiteInt32 || + input_type == kTfLiteInt64 || input_type == kTfLiteBool); + + // Output type must match input type + TF_LITE_ENSURE_EQ(context, output_type, input_type); + + // This implementation does not support large number of input tensors + const int num_inputs = NumInputs(node); + TF_LITE_ENSURE(context, num_inputs <= kMaxInputNum); + + // Shapes with dimensions >4 are not yet supported with static allocation. + for (int i = 0; i < num_inputs; ++i) { + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, i); + TF_LITE_ENSURE(context, input != nullptr); + int num_dimensions = NumDimensions(input); + + if (num_dimensions > RuntimeShape::kMaxSmallSize) { + MicroPrintf( + "Op Concatenation does not currently support num dimensions > %d " + "Tensor has %d dimensions.", + RuntimeShape::kMaxSmallSize, num_dimensions); + return kTfLiteError; + } + micro_context->DeallocateTempTfLiteTensor(input); + } + + // Calculate OpData. + TFLITE_DCHECK(node->user_data != nullptr); + OpData* data = static_cast(node->user_data); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + switch (output_type) { // Already know in/outtypes are same. + case kTfLiteBool: + case kTfLiteFloat32: + case kTfLiteInt16: + case kTfLiteInt32: + case kTfLiteInt64: { + data->params.axis = CalculatePositiveAxis(params->axis, output); + data->params.inputs_count = node->inputs->size; + break; + } + case kTfLiteInt8: { + data->params.axis = CalculatePositiveAxis(params->axis, output); + data->params.inputs_count = node->inputs->size; + + float* input_scales = + reinterpret_cast(context->AllocatePersistentBuffer( + context, node->inputs->size * sizeof(float))); + + int32_t* input_zero_points = + reinterpret_cast(context->AllocatePersistentBuffer( + context, node->inputs->size * sizeof(int32_t))); + + // Allocate persistent scale and zeropoint buffers. + // Store input scale and zero point values in OpParams: + for (int i = 0; i < node->inputs->size; ++i) { + TfLiteTensor* t = micro_context->AllocateTempInputTensor(node, i); + TF_LITE_ENSURE(context, t != nullptr); + input_scales[i] = t->params.scale; + input_zero_points[i] = t->params.zero_point; + micro_context->DeallocateTempTfLiteTensor(t); + } + + data->params.input_scale = input_scales; + data->params.input_zeropoint = input_zero_points; + data->params.output_zeropoint = output->params.zero_point; + data->params.output_scale = output->params.scale; + break; + } + default: + MicroPrintf("Op Concatenation does not currently support Type '%s'.", + TfLiteTypeGetName(output_type)); + return kTfLiteError; + } + + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* output_tensor = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + TF_LITE_ENSURE(context, output_tensor != nullptr); + TfLiteType output_type = output_tensor->type; + + switch (output_type) { // Already know in/outtypes are same. + case kTfLiteFloat32: + EvalUnquantized(context, node); + break; + case kTfLiteInt32: + EvalUnquantized(context, node); + break; + case kTfLiteInt8: + EvalUnquantized(context, node); + break; + case kTfLiteInt64: + EvalUnquantized(context, node); + break; + case kTfLiteInt16: + EvalUnquantized(context, node); + break; + case kTfLiteBool: + EvalUnquantized(context, node); + break; + + default: + MicroPrintf("Op Concatenation does not currently support Type '%s'.", + TfLiteTypeGetName(output_type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace concatenation + +TfLiteRegistration Register_CONCATENATION() { + return tflite::micro::RegisterOp(concatenation::Init, concatenation::Prepare, + concatenation::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv.cc new file mode 100644 index 000000000..36c57655a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv.cc @@ -0,0 +1,166 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/conv.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/reference/conv.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/conv.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataConv)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kConvInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kConvWeightsTensor); + const TfLiteEvalTensor* bias = + (NumInputs(node) == 3) + ? tflite::micro::GetEvalInput(context, node, kConvBiasTensor) + : nullptr; + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kConvOutputTensor); + + TFLITE_DCHECK(node->builtin_data != nullptr); + const auto& params = + *(reinterpret_cast(node->builtin_data)); + TFLITE_DCHECK(node->user_data != nullptr); + const auto& data = *(static_cast(node->user_data)); + + TF_LITE_ENSURE_EQ(context, input->type, output->type); + TF_LITE_ENSURE_MSG( + context, + input->type == filter->type || + (input->type == kTfLiteInt16 && filter->type == kTfLiteInt8) || + (input->type == kTfLiteInt8 && filter->type == kTfLiteInt4), + "Hybrid models are not supported on TFLite Micro."); + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: { + tflite::reference_ops::Conv( + ConvParamsFloat(params, data), tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr); + break; + } + case kTfLiteInt16: { + switch (bias->type) { + case kTfLiteInt32: { + reference_integer_ops::ConvPerChannel( + ConvParamsQuantized(params, data), + data.per_channel_output_multiplier, data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + case kTfLiteInt64: { + reference_integer_ops::ConvPerChannel( + ConvParamsQuantized(params, data), + data.per_channel_output_multiplier, data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + default: + MicroPrintf("Bias type %s (%d) not supported.", + TfLiteTypeGetName(bias->type), bias->type); + return kTfLiteError; + } + break; + } + case kTfLiteInt8: { + switch (filter->type) { + case kTfLiteInt4: { + int8_t* unpacked_filter_data = nullptr; + OpDataConv* op_data = static_cast(node->user_data); + unpacked_filter_data = static_cast( + context->GetScratchBuffer(context, op_data->filter_buffer_index)); + reference_integer_ops::ConvPerChannelWithPackedInt4Weights( + ConvParamsQuantized(params, data), + data.per_channel_output_multiplier, data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + unpacked_filter_data, tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + case kTfLiteInt8: { + reference_integer_ops::ConvPerChannel( + ConvParamsQuantized(params, data), + data.per_channel_output_multiplier, data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + default: + MicroPrintf("Weight type %s (%d) not supported.", + TfLiteTypeGetName(filter->type), filter->type); + return kTfLiteError; + } + break; + } + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_CONV_2D() { + return tflite::micro::RegisterOp(Init, ConvPrepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv.h new file mode 100644 index 000000000..06e9db43a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv.h @@ -0,0 +1,116 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_CONV_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_CONV_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +struct OpDataConv { + TfLitePaddingValues padding; + + // Cached tensor zero point values for quantized operations. + int32_t input_zero_point; + int32_t filter_zero_point; + int32_t output_zero_point; + + // The scaling factor from input to output (aka the 'real multiplier') can + // be represented as a fixed point multiplier plus a left shift. + int32_t output_multiplier; + int output_shift; + + // Per channel output multiplier and shift. + int32_t* per_channel_output_multiplier; + int32_t* per_channel_output_shift; + + // The range of the fused activation layer. For example for kNone and + // uint8_t these would be 0 and 255. + int32_t output_activation_min; + int32_t output_activation_max; + + // A buffer used to store unpacked filter values. This is used if the source + // tensor is of n-bit precision that cannot be easily processed by kernels. + int filter_buffer_index; +}; + +extern const int kConvInputTensor; +extern const int kConvWeightsTensor; +extern const int kConvBiasTensor; +extern const int kConvOutputTensor; +extern const int kConvQuantizedDimension; + +// Returns a ConvParams struct with all the parameters needed for a +// float computation. +ConvParams ConvParamsFloat(const TfLiteConvParams& params, + const OpDataConv& data); + +// Returns a ConvParams struct with all the parameters needed for a +// quantized computation. +ConvParams ConvParamsQuantized(const TfLiteConvParams& params, + const OpDataConv& data); + +TfLiteStatus CalculateOpDataConv(TfLiteContext* context, TfLiteNode* node, + const TfLiteConvParams& params, int width, + int height, int filter_width, + int filter_height, int out_width, + int out_height, const TfLiteType data_type, + OpDataConv* data); + +TfLiteStatus ConvPrepare(TfLiteContext* context, TfLiteNode* node); + +// This is the most generic TfLiteRegistration. The actual supported types may +// still be target dependent. The only requirement is that every implementation +// (reference or optimized) must define this function. +TfLiteRegistration Register_CONV_2D(); + +#if defined(XTENSA) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int8 activations and int8 weights and always calls the reference +// implementation. +TfLiteRegistration Register_CONV_2D_INT8REF(); +#else +inline TfLiteRegistration Register_CONV_2D_INT8REF() { + return Register_CONV_2D(); +} +#endif + +#if defined(CMSIS_NN) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int8 activations and int8 weights and uses the latency optimized +// implementations. +TfLiteRegistration Register_CONV_2D_INT8(); + +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int16 activations and int8 weights and uses the latency optimized +// implementations. +TfLiteRegistration Register_CONV_2D_INT16(); + +#else +inline TfLiteRegistration Register_CONV_2D_INT8() { return Register_CONV_2D(); } + +inline TfLiteRegistration Register_CONV_2D_INT16() { + return Register_CONV_2D(); +} +#endif + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv_common.cc new file mode 100644 index 000000000..c548c932c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv_common.cc @@ -0,0 +1,202 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/conv.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { + +const int kConvInputTensor = 0; +const int kConvWeightsTensor = 1; +const int kConvBiasTensor = 2; +const int kConvOutputTensor = 0; + +// Conv is quantized along dimension 0: +// https://www.tensorflow.org/lite/performance/quantization_spec +const int kConvQuantizedDimension = 0; + +// Returns a ConvParams struct with all the parameters needed for a +// float computation. +ConvParams ConvParamsFloat(const TfLiteConvParams& params, + const OpDataConv& data) { + ConvParams op_params; + CalculateActivationRange(params.activation, &op_params.float_activation_min, + &op_params.float_activation_max); + op_params.padding_type = tflite::micro::RuntimePaddingType(params.padding); + op_params.padding_values.width = data.padding.width; + op_params.padding_values.height = data.padding.height; + op_params.stride_width = params.stride_width; + op_params.stride_height = params.stride_height; + op_params.dilation_width_factor = params.dilation_width_factor; + op_params.dilation_height_factor = params.dilation_height_factor; + return op_params; +} + +// Returns a ConvParams struct with all the parameters needed for a +// quantized computation. +ConvParams ConvParamsQuantized(const TfLiteConvParams& params, + const OpDataConv& data) { + ConvParams op_params; + op_params.input_offset = -data.input_zero_point; + op_params.weights_offset = -data.filter_zero_point; + op_params.output_offset = data.output_zero_point; + op_params.output_multiplier = data.output_multiplier; + op_params.output_shift = -data.output_shift; + op_params.padding_type = tflite::micro::RuntimePaddingType(params.padding); + op_params.padding_values.height = data.padding.height; + op_params.padding_values.width = data.padding.width; + op_params.stride_height = params.stride_height; + op_params.stride_width = params.stride_width; + op_params.dilation_height_factor = params.dilation_height_factor; + op_params.dilation_width_factor = params.dilation_width_factor; + op_params.quantized_activation_min = data.output_activation_min; + op_params.quantized_activation_max = data.output_activation_max; + return op_params; +} + +TfLiteStatus CalculateOpDataConv(TfLiteContext* context, TfLiteNode* node, + const TfLiteConvParams& params, int width, + int height, int filter_width, + int filter_height, int out_width, + int out_height, const TfLiteType data_type, + OpDataConv* data) { + bool has_bias = node->inputs->size == 3; + // Check number of inputs/outputs + TF_LITE_ENSURE(context, has_bias || node->inputs->size == 2); + TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); + + // Matching GetWindowedOutputSize in TensorFlow. + auto padding = params.padding; + data->padding = ComputePaddingHeightWidth( + params.stride_height, params.stride_width, params.dilation_height_factor, + params.dilation_width_factor, height, width, filter_height, filter_width, + padding, &out_height, &out_width); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kConvInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kConvWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kConvBiasTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kConvOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + // Note that quantized inference requires that all tensors have their + // parameters set. This is usually done during quantized training. + if (data_type != kTfLiteFloat32) { + int output_channels = filter->dims->data[kConvQuantizedDimension]; + + TF_LITE_ENSURE_STATUS(tflite::PopulateConvolutionQuantizationParams( + context, input, filter, bias, output, params.activation, + &data->output_multiplier, &data->output_shift, + &data->output_activation_min, &data->output_activation_max, + data->per_channel_output_multiplier, data->per_channel_output_shift, + output_channels)); + } + + data->input_zero_point = input->params.zero_point; + data->filter_zero_point = filter->params.zero_point; + data->output_zero_point = output->params.zero_point; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(bias); + + return kTfLiteOk; +} + +TfLiteStatus ConvPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + OpDataConv* data = static_cast(node->user_data); + const auto& params = + *(static_cast(node->builtin_data)); + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kConvOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kConvInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kConvWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + + const int input_width = input->dims->data[2]; + const int input_height = input->dims->data[1]; + const int filter_width = filter->dims->data[2]; + const int filter_height = filter->dims->data[1]; + const int output_width = output->dims->data[2]; + const int output_height = output->dims->data[1]; + + // Dynamically allocate per-channel quantization parameters. + const int num_channels = filter->dims->data[kConvQuantizedDimension]; + data->per_channel_output_multiplier = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + data->per_channel_output_shift = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + + // All per-channel quantized tensors need valid zero point and scale arrays. + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, filter->quantization.type, + kTfLiteAffineQuantization); + + const auto* affine_quantization = + static_cast(filter->quantization.params); + TFLITE_DCHECK(affine_quantization != nullptr); + TFLITE_DCHECK(affine_quantization->scale != nullptr); + TFLITE_DCHECK(affine_quantization->zero_point != nullptr); + + TF_LITE_ENSURE(context, + affine_quantization->scale->size == 1 || + affine_quantization->scale->size == + filter->dims->data[kConvQuantizedDimension]); + } + + TF_LITE_ENSURE_STATUS(CalculateOpDataConv( + context, node, params, input_width, input_height, filter_width, + filter_height, output_width, output_height, input->type, data)); + + if (filter->type == kTfLiteInt4) { + int filter_size = + RuntimeShape(filter->dims->size, + reinterpret_cast(filter->dims->data)) + .FlatSize(); + context->RequestScratchBufferInArena(context, filter_size, + &data->filter_buffer_index); + } + + micro_context->DeallocateTempTfLiteTensor(filter); + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv_test.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv_test.h new file mode 100644 index 000000000..47ba8ac40 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/conv_test.h @@ -0,0 +1,113 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_CONV_TEST_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_CONV_TEST_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/kernels/kernel_runner.h" +#include "tensorflow/lite/micro/kernels/micro_ops.h" +#include "tensorflow/lite/micro/test_helpers.h" +#include "tensorflow/lite/micro/testing/micro_test.h" + +namespace tflite { +namespace testing { + +TfLiteStatus InvokeConv(TfLiteTensor* tensors, int tensors_size, + int output_length, TfLiteConvParams* conv_params, + TfLiteRegistration registration, float* output_data); + +TfLiteStatus InvokeConv(TfLiteTensor* tensors, int tensors_size, + int output_length, TfLiteConvParams* conv_params, + TfLiteRegistration registration, int8_t* output_data); + +TfLiteStatus InvokeConv(TfLiteTensor* tensors, int tensors_size, + int output_length, TfLiteConvParams* conv_params, + TfLiteRegistration registration, uint8_t* output_data); + +TfLiteStatus ValidateConvGoldens(TfLiteTensor* tensors, int tensors_size, + const float* expected_output_data, + int output_length, + TfLiteConvParams* conv_params, + TfLiteRegistration registration, + float* output_data, float tolerance = 1e-5); + +TfLiteStatus ValidateConvGoldens(TfLiteTensor* tensors, int tensors_size, + const int8_t* expected_output_data, + int output_length, + TfLiteConvParams* conv_params, + TfLiteRegistration registration, + int8_t* output_data, float tolerance = 1e-5); + +TfLiteStatus ValidateConvGoldens(TfLiteTensor* tensors, int tensors_size, + const uint8_t* expected_output_data, + int output_length, + TfLiteConvParams* conv_params, + TfLiteRegistration registration, + uint8_t* output_data, float tolerance = 1e-5); + +TfLiteStatus TestConvFloat(int* input_dims_data, const float* input_data, + int* filter_dims_data, const float* filter_data, + int* bias_dims_data, const float* bias_data, + int* output_dims_data, + const float* expected_output_data, + TfLiteConvParams* conv_params, + TfLiteRegistration registration, float* output_data); + +TfLiteStatus TestConvQuantizedPerLayer( + int* input_dims_data, const float* input_data, uint8_t* input_quantized, + float input_scale, int* filter_dims_data, const float* filter_data, + uint8_t* filter_quantized, float filter_scale, int* bias_dims_data, + const float* bias_data, int32_t* bias_quantized, int* output_dims_data, + const float* expected_output_data, uint8_t* expected_output_quantized, + float output_scale, TfLiteConvParams* conv_params, + TfLiteRegistration registration, uint8_t* output_data); + +TfLiteStatus TestConvQuantizedPerChannel( + int* input_dims_data, const float* input_data, int8_t* input_quantized, + float input_scale, int input_zero_point, int* filter_dims_data, + const float* filter_data, int8_t* filter_data_quantized, + int* bias_dims_data, const float* bias_data, int32_t* bias_data_quantized, + float* bias_scales, int* bias_zero_points, int* output_dims_data, + const float* expected_output_data, int8_t* expected_output_data_quantized, + float output_scale, int output_zero_point, TfLiteConvParams* conv_params, + TfLiteRegistration registration, int8_t* output_data); + +TfLiteStatus TestConvQuantizedPerChannel( + int* input_dims_data, const float* input_data, int16_t* input_quantized, + float input_scale, int input_zero_point, int* filter_dims_data, + const float* filter_data, int8_t* filter_data_quantized, + int* bias_dims_data, const float* bias_data, + std::int64_t* bias_data_quantized, float* bias_scales, + int* bias_zero_points, int* output_dims_data, + const float* expected_output_data, int16_t* expected_output_data_quantized, + float output_scale, int output_zero_point, TfLiteConvParams* conv_params, + TfLiteRegistration registration, int16_t* output_data); + +TfLiteStatus TestConvQuantizedPerChannel( + int* input_dims_data, const float* input_data, int16_t* input_quantized, + float input_scale, int input_zero_point, int* filter_dims_data, + const float* filter_data, int8_t* filter_data_quantized, + int* bias_dims_data, const float* bias_data, int32_t* bias_data_quantized, + float* bias_scales, int* bias_zero_points, int* output_dims_data, + const float* expected_output_data, int16_t* expected_output_data_quantized, + float output_scale, int output_zero_point, TfLiteConvParams* conv_params, + TfLiteRegistration registration, int16_t* output_data); + +} // namespace testing +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_CONV_TEST_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/cumsum.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/cumsum.cc new file mode 100644 index 000000000..4f8a96591 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/cumsum.cc @@ -0,0 +1,175 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/cumsum.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kAxisTensor = 1; +constexpr int kOutputTensor = 0; + +constexpr int kCumSumIntegerShift = 20; + +// only used with INT8 tensors +struct OpData { + int32_t output_activation_min; + int32_t output_activation_max; + int32_t input_offset; + int32_t output_offset; + int32_t input_multiplier; + int32_t output_multiplier; + int input_shift; + int output_shift; + int left_shift; +}; + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TfLiteTensor* axis = + micro_context->AllocateTempInputTensor(node, kAxisTensor); + + TF_LITE_ENSURE(context, + input->type == kTfLiteFloat32 || input->type == kTfLiteInt8); + TF_LITE_ENSURE_EQ(context, axis->type, kTfLiteInt32); + + TF_LITE_ENSURE_EQ(context, NumElements(axis), 1); + + TF_LITE_ENSURE(context, NumDimensions(input) >= 1); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + + TF_LITE_ENSURE_EQ(context, input->type, output->type); + TF_LITE_ENSURE(context, HaveSameShapes(input, output)); + + if (output->type == kTfLiteInt8) { + node->user_data = + context->AllocatePersistentBuffer(context, sizeof(OpData)); + OpData* data = static_cast(node->user_data); + + // 8bit -> 8bit general quantized path, with general rescalings + data->input_offset = -input->params.zero_point; + data->output_offset = output->params.zero_point; + data->left_shift = kCumSumIntegerShift; + const double twice_max_input_scale = + 2 * static_cast(input->params.scale); + const double real_input_multiplier = + static_cast(input->params.scale) / twice_max_input_scale; + const double real_output_multiplier = + twice_max_input_scale / + ((1 << data->left_shift) * static_cast(output->params.scale)); + + QuantizeMultiplierSmallerThanOneExp( + real_input_multiplier, &data->input_multiplier, &data->input_shift); + + QuantizeMultiplierSmallerThanOneExp( + real_output_multiplier, &data->output_multiplier, &data->output_shift); + + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, kTfLiteActNone, output, &data->output_activation_min, + &data->output_activation_max)); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(axis); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* axis_tensor = + tflite::micro::GetEvalInput(context, node, kAxisTensor); + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + auto* cs_params = static_cast(node->builtin_data); + auto input_shape = tflite::micro::GetTensorShape(input); + + int32_t axis = *tflite::micro::GetTensorData(axis_tensor); + if (axis < 0) axis += input_shape.DimensionsCount(); + + if (axis < 0 || axis >= input_shape.DimensionsCount()) { + MicroPrintf("CUMSUM Invalid axis: %d", axis); + return kTfLiteError; + } + + switch (input->type) { + case kTfLiteFloat32: { + reference_ops::CumSum(tflite::micro::GetTensorData(input), + input_shape, axis, cs_params->exclusive, + cs_params->reverse, + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + + case kTfLiteInt8: { + auto* data = static_cast(node->user_data); + ArithmeticParams params; + params.left_shift = data->left_shift; + params.input1_offset = data->input_offset; + params.input1_multiplier = data->input_multiplier; + params.input1_shift = data->input_shift; + params.output_offset = data->output_offset; + params.output_multiplier = data->output_multiplier; + params.output_shift = data->output_shift; + SetActivationParams(data->output_activation_min, + data->output_activation_max, ¶ms); + reference_ops::CumSum(params, tflite::micro::GetTensorData(input), + input_shape, axis, cs_params->exclusive, + cs_params->reverse, + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + + default: { + MicroPrintf("CUMSUM only supports FLOAT32 and INT8, got %s.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } + + return kTfLiteError; +} + +} // namespace + +TfLiteRegistration Register_CUMSUM() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depth_to_space.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depth_to_space.cc new file mode 100644 index 000000000..7f229fbf4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depth_to_space.cc @@ -0,0 +1,142 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/depth_to_space.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +// input/output tensor shape rank associations +constexpr int kBatchRank = 0; +constexpr int kHeightRank = 1; +constexpr int kWidthRank = 2; +constexpr int kDepthRank = 3; + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + auto* params = + reinterpret_cast(node->builtin_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); + + auto data_type = output->type; + TF_LITE_ENSURE(context, + data_type == kTfLiteFloat32 || data_type == kTfLiteInt8); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + const int block_size = params->block_size; + TF_LITE_ENSURE(context, block_size > 0); + const int input_height = input->dims->data[kHeightRank]; + const int input_width = input->dims->data[kWidthRank]; + const int input_channels = input->dims->data[kDepthRank]; + int output_height = input_height * block_size; + int output_width = input_width * block_size; + int output_channels = input_channels / block_size / block_size; + + TF_LITE_ENSURE_EQ(context, input_height, output_height / block_size); + TF_LITE_ENSURE_EQ(context, input_width, output_width / block_size); + TF_LITE_ENSURE_EQ(context, input_channels, + output_channels * block_size * block_size); + + // We must update the output tensor dimensions. + // The dims storage is expected to be the same area in memory + // for both TfLiteTensor and TfLiteEvalTensor. This is important + // because TfLiteTensor in the MicroInterpreter is a temporary + // allocation. For the KernelRunner interpreter, TfLiteEvalTensor + // is a temporary allocation. We must therefore relocate the dims + // from the FlatBuffer to the persistant storage arena. + TfLiteEvalTensor* output_eval = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + TF_LITE_ENSURE_OK(context, tflite::micro::CreateWritableTensorDimsWithCopy( + context, output, output_eval)); + output->dims->data[kBatchRank] = input->dims->data[kBatchRank]; + output->dims->data[kHeightRank] = output_height; + output->dims->data[kWidthRank] = output_width; + output->dims->data[kDepthRank] = output_channels; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = + reinterpret_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + tflite::DepthToSpaceParams op_params; + op_params.block_size = static_cast(params->block_size); + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + reference_ops::DepthToSpace(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::DepthToSpace(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("DEPTH_TO_SPACE only supports FLOAT32 and INT8, got %s.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_DEPTH_TO_SPACE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv.cc new file mode 100644 index 000000000..146da07fa --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv.cc @@ -0,0 +1,99 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/depthwise_conv.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/depthwise_conv.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataConv)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + auto& params = + *(reinterpret_cast(node->builtin_data)); + const OpDataConv& data = *(static_cast(node->user_data)); + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kDepthwiseConvOutputTensor); + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kDepthwiseConvInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kDepthwiseConvWeightsTensor); + const TfLiteEvalTensor* bias = + (NumInputs(node) == 3) + ? tflite::micro::GetEvalInput(context, node, kDepthwiseConvBiasTensor) + : nullptr; + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: { + tflite::reference_ops::DepthwiseConv( + DepthwiseConvParamsFloat(params, data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + case kTfLiteInt8: { + reference_integer_ops::DepthwiseConvPerChannel( + DepthwiseConvParamsQuantized(params, data), + data.per_channel_output_multiplier, data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_DEPTHWISE_CONV_2D() { + return tflite::micro::RegisterOp(Init, DepthwiseConvPrepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv.h new file mode 100644 index 000000000..562438d7c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv.h @@ -0,0 +1,80 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_DEPTHWISE_CONV_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_DEPTHWISE_CONV_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/micro/kernels/conv.h" + +namespace tflite { + +extern const int kDepthwiseConvInputTensor; +extern const int kDepthwiseConvWeightsTensor; +extern const int kDepthwiseConvBiasTensor; +extern const int kDepthwiseConvOutputTensor; +extern const int kDepthwiseConvQuantizedDimension; + +// Returns a DepthwiseParams struct with all the parameters needed for a +// float computation. +DepthwiseParams DepthwiseConvParamsFloat( + const TfLiteDepthwiseConvParams& params, const OpDataConv& data); + +// Returns a DepthwiseParams struct with all the parameters needed for a +// quantized computation. +DepthwiseParams DepthwiseConvParamsQuantized( + const TfLiteDepthwiseConvParams& params, const OpDataConv& data); + +TfLiteStatus CalculateOpDataDepthwiseConv( + TfLiteContext* context, TfLiteNode* node, + const TfLiteDepthwiseConvParams& params, int width, int height, + int filter_width, int filter_height, int out_width, int out_height, + const TfLiteType data_type, OpDataConv* data); + +TfLiteStatus DepthwiseConvPrepare(TfLiteContext* context, TfLiteNode* node); + +// This is the most generic TfLiteRegistration. The actual supported types may +// still be target dependent. The only requirement is that every implementation +// (reference or optimized) must define this function. +TfLiteRegistration Register_DEPTHWISE_CONV_2D(); + +#if defined(CMSIS_NN) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int8 activations and int8 weights and uses the latency optimized +// implementations. +TfLiteRegistration Register_DEPTHWISE_CONV_2D_INT8(); + +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int16 activations and int8 weights and uses the latency optimized +// implementations. +TfLiteRegistration Register_DEPTHWISE_CONV_2D_INT16(); + +#else +inline TfLiteRegistration Register_DEPTHWISE_CONV_2D_INT8() { + return Register_DEPTHWISE_CONV_2D(); +} + +inline TfLiteRegistration Register_DEPTHWISE_CONV_2D_INT16() { + return Register_DEPTHWISE_CONV_2D(); +} +#endif + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_DEPTHWISE_CONV_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv_common.cc new file mode 100644 index 000000000..3bf07274e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/depthwise_conv_common.cc @@ -0,0 +1,202 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/depthwise_conv.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/depthwise_conv.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { + +const int kDepthwiseConvInputTensor = 0; +const int kDepthwiseConvWeightsTensor = 1; +const int kDepthwiseConvBiasTensor = 2; +const int kDepthwiseConvOutputTensor = 0; + +// DepthwiseConv is quantized along dimension 3: +// https://www.tensorflow.org/lite/performance/quantization_spec +const int kDepthwiseConvQuantizedDimension = 3; + +// Returns a DepthwiseParams struct with all the parameters needed for a +// float computation. +DepthwiseParams DepthwiseConvParamsFloat( + const TfLiteDepthwiseConvParams& params, const OpDataConv& data) { + DepthwiseParams op_params; + CalculateActivationRange(params.activation, &op_params.float_activation_min, + &op_params.float_activation_max); + op_params.padding_type = tflite::micro::RuntimePaddingType(params.padding); + op_params.padding_values.width = data.padding.width; + op_params.padding_values.height = data.padding.height; + op_params.stride_width = params.stride_width; + op_params.stride_height = params.stride_height; + op_params.dilation_width_factor = params.dilation_width_factor; + op_params.dilation_height_factor = params.dilation_height_factor; + op_params.depth_multiplier = params.depth_multiplier; + return op_params; +} + +// Returns a DepthwiseParams struct with all the parameters needed for a +// quantized computation. +DepthwiseParams DepthwiseConvParamsQuantized( + const TfLiteDepthwiseConvParams& params, const OpDataConv& data) { + DepthwiseParams op_params; + op_params.input_offset = -data.input_zero_point; + op_params.weights_offset = -data.filter_zero_point; + op_params.output_offset = data.output_zero_point; + op_params.output_multiplier = data.output_multiplier; + op_params.output_shift = -data.output_shift; + op_params.padding_type = tflite::micro::RuntimePaddingType(params.padding); + op_params.padding_values.height = data.padding.height; + op_params.padding_values.width = data.padding.width; + op_params.stride_height = params.stride_height; + op_params.stride_width = params.stride_width; + op_params.dilation_height_factor = params.dilation_height_factor; + op_params.dilation_width_factor = params.dilation_width_factor; + op_params.depth_multiplier = params.depth_multiplier; + op_params.quantized_activation_min = data.output_activation_min; + op_params.quantized_activation_max = data.output_activation_max; + return op_params; +} + +TfLiteStatus CalculateOpDataDepthwiseConv( + TfLiteContext* context, TfLiteNode* node, + const TfLiteDepthwiseConvParams& params, int width, int height, + int filter_width, int filter_height, int out_width, int out_height, + const TfLiteType data_type, OpDataConv* data) { + bool has_bias = node->inputs->size == 3; + // Check number of inputs/outputs + TF_LITE_ENSURE(context, has_bias || node->inputs->size == 2); + TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); + + // Matching GetWindowedOutputSize in TensorFlow. + auto padding = params.padding; + data->padding = ComputePaddingHeightWidth( + params.stride_height, params.stride_width, params.dilation_height_factor, + params.dilation_width_factor, height, width, filter_height, filter_width, + padding, &out_height, &out_width); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kConvInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kConvWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kConvBiasTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kConvOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + // Note that quantized inference requires that all tensors have their + // parameters set. This is usually done during quantized training. + if (data_type != kTfLiteFloat32) { + int output_channels = filter->dims->data[kDepthwiseConvQuantizedDimension]; + + TF_LITE_ENSURE_STATUS(tflite::PopulateConvolutionQuantizationParams( + context, input, filter, bias, output, params.activation, + &data->output_multiplier, &data->output_shift, + &data->output_activation_min, &data->output_activation_max, + data->per_channel_output_multiplier, data->per_channel_output_shift, + output_channels)); + } + + data->input_zero_point = input->params.zero_point; + data->filter_zero_point = filter->params.zero_point; + data->output_zero_point = output->params.zero_point; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + micro_context->DeallocateTempTfLiteTensor(bias); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus DepthwiseConvPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + OpDataConv* data = static_cast(node->user_data); + const auto& params = + *(static_cast(node->builtin_data)); + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kDepthwiseConvOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kDepthwiseConvInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kDepthwiseConvWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + + const int input_width = input->dims->data[2]; + const int input_height = input->dims->data[1]; + const int filter_width = filter->dims->data[2]; + const int filter_height = filter->dims->data[1]; + const int output_width = output->dims->data[2]; + const int output_height = output->dims->data[1]; + + // Dynamically allocate per-channel quantization parameters. + const int num_channels = filter->dims->data[kDepthwiseConvQuantizedDimension]; + data->per_channel_output_multiplier = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + data->per_channel_output_shift = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + + // All per-channel quantized tensors need valid zero point and scale arrays. + if (input->type == kTfLiteInt8) { + TF_LITE_ENSURE_EQ(context, filter->quantization.type, + kTfLiteAffineQuantization); + + const auto* affine_quantization = + static_cast(filter->quantization.params); + TFLITE_DCHECK(affine_quantization != nullptr); + TFLITE_DCHECK(affine_quantization->scale != nullptr); + TFLITE_DCHECK(affine_quantization->zero_point != nullptr); + + TF_LITE_ENSURE( + context, affine_quantization->scale->size == 1 || + affine_quantization->scale->size == + filter->dims->data[kDepthwiseConvQuantizedDimension]); + + TF_LITE_ENSURE_EQ(context, affine_quantization->scale->size, + affine_quantization->zero_point->size); + } + + TF_LITE_ENSURE_STATUS(CalculateOpDataDepthwiseConv( + context, node, params, input_width, input_height, filter_width, + filter_height, output_width, output_height, input->type, data)); + + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize.cc new file mode 100644 index 000000000..f51db508d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize.cc @@ -0,0 +1,88 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/dequantize.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/quantize.h" +#include "tensorflow/lite/kernels/internal/reference/requantize.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/dequantize.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +void* DequantizeInit(TfLiteContext* context, const char* buffer, + size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(DequantizeOpData)); +} + +TfLiteStatus DequantizeEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + DequantizeOpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + + if (output->type == kTfLiteFloat32) { + switch (input->type) { + case kTfLiteInt8: + reference_ops::Dequantize(data->quantization_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::Dequantize(data->quantization_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteUInt8: + reference_ops::Dequantize(data->quantization_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else { + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +TfLiteRegistration Register_DEQUANTIZE() { + return tflite::micro::RegisterOp(DequantizeInit, DequantizePrepare, + DequantizeEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize.h new file mode 100644 index 000000000..fe6ec1697 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize.h @@ -0,0 +1,38 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_DEQUANTIZE_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_DEQUANTIZE_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +struct DequantizeOpData { + tflite::DequantizationParams quantization_params; + // The scaling factor from input to output (aka the 'real multiplier') can + // be represented as a fixed point multiplier plus a left shift. + int32_t output_multiplier; + int output_shift; + int32_t output_zero_point; +}; + +TfLiteStatus DequantizePrepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_DEQUANTIZE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize_common.cc new file mode 100644 index 000000000..438f9cda8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/dequantize_common.cc @@ -0,0 +1,67 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/dequantize.h" +#include "tensorflow/lite/kernels/internal/reference/quantize.h" +#include "tensorflow/lite/kernels/internal/reference/requantize.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/dequantize.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { + +TfLiteStatus DequantizePrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + DequantizeOpData* data = static_cast(node->user_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + // TODO(b/140515557): Add cached dequant to improve hybrid model performance. + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE(context, input->type == kTfLiteInt8 || + input->type == kTfLiteInt16 || + input->type == kTfLiteUInt8); + TF_LITE_ENSURE(context, output->type == kTfLiteFloat32); + + if (output->type == kTfLiteInt32) { + const double effective_output_scale = + static_cast(input->params.scale) / + static_cast(output->params.scale); + QuantizeMultiplier(effective_output_scale, &data->output_multiplier, + &data->output_shift); + } + + data->quantization_params.zero_point = input->params.zero_point; + data->quantization_params.scale = static_cast(input->params.scale); + data->output_zero_point = output->params.zero_point; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/detection_postprocess.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/detection_postprocess.cc new file mode 100644 index 000000000..7aadbbf85 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/detection_postprocess.cc @@ -0,0 +1,807 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "third_party/flatbuffers/include/flatbuffers/flexbuffers.h" +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +/** + * This version of detection_postprocess is specific to TFLite Micro. It + * contains the following differences between the TFLite version: + * + * 1.) Temporaries (temporary tensors) - Micro use instead scratch buffer API. + * 2.) Output dimensions - the TFLite version does not support undefined out + * dimensions. So model must have static out dimensions. + */ + +// Input tensors +constexpr int kInputTensorBoxEncodings = 0; +constexpr int kInputTensorClassPredictions = 1; +constexpr int kInputTensorAnchors = 2; + +// Output tensors +constexpr int kOutputTensorDetectionBoxes = 0; +constexpr int kOutputTensorDetectionClasses = 1; +constexpr int kOutputTensorDetectionScores = 2; +constexpr int kOutputTensorNumDetections = 3; + +constexpr int kNumCoordBox = 4; +constexpr int kBatchSize = 1; + +constexpr int kNumDetectionsPerClass = 100; + +// Object Detection model produces axis-aligned boxes in two formats: +// BoxCorner represents the lower left corner (xmin, ymin) and +// the upper right corner (xmax, ymax). +// CenterSize represents the center (xcenter, ycenter), height and width. +// BoxCornerEncoding and CenterSizeEncoding are related as follows: +// ycenter = y / y_scale * anchor.h + anchor.y; +// xcenter = x / x_scale * anchor.w + anchor.x; +// half_h = 0.5*exp(h/ h_scale)) * anchor.h; +// half_w = 0.5*exp(w / w_scale)) * anchor.w; +// ymin = ycenter - half_h +// ymax = ycenter + half_h +// xmin = xcenter - half_w +// xmax = xcenter + half_w +struct BoxCornerEncoding { + float ymin; + float xmin; + float ymax; + float xmax; +}; + +struct CenterSizeEncoding { + float y; + float x; + float h; + float w; +}; +// We make sure that the memory allocations are contiguous with static_assert. +static_assert(sizeof(BoxCornerEncoding) == sizeof(float) * kNumCoordBox, + "Size of BoxCornerEncoding is 4 float values"); +static_assert(sizeof(CenterSizeEncoding) == sizeof(float) * kNumCoordBox, + "Size of CenterSizeEncoding is 4 float values"); + +struct OpData { + int max_detections; + int max_classes_per_detection; // Fast Non-Max-Suppression + int detections_per_class; // Regular Non-Max-Suppression + float non_max_suppression_score_threshold; + float intersection_over_union_threshold; + int num_classes; + bool use_regular_non_max_suppression; + CenterSizeEncoding scale_values; + + // Scratch buffers indexes + int active_candidate_idx; + int decoded_boxes_idx; + int scores_idx; + int score_buffer_idx; + int keep_scores_idx; + int scores_after_regular_non_max_suppression_idx; + int sorted_values_idx; + int keep_indices_idx; + int sorted_indices_idx; + int buffer_idx; + int selected_idx; + + // Cached tensor scale and zero point values for quantized operations + TfLiteQuantizationParams input_box_encodings; + TfLiteQuantizationParams input_class_predictions; + TfLiteQuantizationParams input_anchors; +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + OpData* op_data = nullptr; + + const uint8_t* buffer_t = reinterpret_cast(buffer); + const flexbuffers::Map& m = flexbuffers::GetRoot(buffer_t, length).AsMap(); + op_data = reinterpret_cast( + context->AllocatePersistentBuffer(context, sizeof(OpData))); + + op_data->max_detections = m["max_detections"].AsInt32(); + op_data->max_classes_per_detection = m["max_classes_per_detection"].AsInt32(); + if (m["detections_per_class"].IsNull()) + op_data->detections_per_class = kNumDetectionsPerClass; + else + op_data->detections_per_class = m["detections_per_class"].AsInt32(); + if (m["use_regular_nms"].IsNull()) + op_data->use_regular_non_max_suppression = false; + else + op_data->use_regular_non_max_suppression = m["use_regular_nms"].AsBool(); + + op_data->non_max_suppression_score_threshold = + m["nms_score_threshold"].AsFloat(); + op_data->intersection_over_union_threshold = m["nms_iou_threshold"].AsFloat(); + op_data->num_classes = m["num_classes"].AsInt32(); + op_data->scale_values.y = m["y_scale"].AsFloat(); + op_data->scale_values.x = m["x_scale"].AsFloat(); + op_data->scale_values.h = m["h_scale"].AsFloat(); + op_data->scale_values.w = m["w_scale"].AsFloat(); + + return op_data; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + auto* op_data = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + + // Inputs: box_encodings, scores, anchors + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + TfLiteTensor* input_box_encodings = + micro_context->AllocateTempInputTensor(node, kInputTensorBoxEncodings); + TfLiteTensor* input_class_predictions = + micro_context->AllocateTempInputTensor(node, + kInputTensorClassPredictions); + TfLiteTensor* input_anchors = + micro_context->AllocateTempInputTensor(node, kInputTensorAnchors); + TF_LITE_ENSURE_EQ(context, NumDimensions(input_box_encodings), 3); + TF_LITE_ENSURE_EQ(context, NumDimensions(input_class_predictions), 3); + TF_LITE_ENSURE_EQ(context, NumDimensions(input_anchors), 2); + + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 4); + const int num_boxes = input_box_encodings->dims->data[1]; + const int num_classes = op_data->num_classes; + + op_data->input_box_encodings.scale = input_box_encodings->params.scale; + op_data->input_box_encodings.zero_point = + input_box_encodings->params.zero_point; + op_data->input_class_predictions.scale = + input_class_predictions->params.scale; + op_data->input_class_predictions.zero_point = + input_class_predictions->params.zero_point; + op_data->input_anchors.scale = input_anchors->params.scale; + op_data->input_anchors.zero_point = input_anchors->params.zero_point; + + // Scratch tensors + context->RequestScratchBufferInArena(context, num_boxes, + &op_data->active_candidate_idx); + context->RequestScratchBufferInArena(context, + num_boxes * kNumCoordBox * sizeof(float), + &op_data->decoded_boxes_idx); + context->RequestScratchBufferInArena( + context, + input_class_predictions->dims->data[1] * + input_class_predictions->dims->data[2] * sizeof(float), + &op_data->scores_idx); + + // Additional buffers + context->RequestScratchBufferInArena(context, num_boxes * sizeof(float), + &op_data->score_buffer_idx); + context->RequestScratchBufferInArena(context, num_boxes * sizeof(float), + &op_data->keep_scores_idx); + context->RequestScratchBufferInArena( + context, op_data->max_detections * num_boxes * sizeof(float), + &op_data->scores_after_regular_non_max_suppression_idx); + context->RequestScratchBufferInArena( + context, op_data->max_detections * num_boxes * sizeof(float), + &op_data->sorted_values_idx); + context->RequestScratchBufferInArena(context, num_boxes * sizeof(int), + &op_data->keep_indices_idx); + context->RequestScratchBufferInArena( + context, op_data->max_detections * num_boxes * sizeof(int), + &op_data->sorted_indices_idx); + int buffer_size = std::max(num_classes, op_data->max_detections); + context->RequestScratchBufferInArena( + context, buffer_size * num_boxes * sizeof(int), &op_data->buffer_idx); + buffer_size = std::min(num_boxes, op_data->max_detections); + context->RequestScratchBufferInArena( + context, buffer_size * num_boxes * sizeof(int), &op_data->selected_idx); + + // Outputs: detection_boxes, detection_scores, detection_classes, + // num_detections + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 4); + + micro_context->DeallocateTempTfLiteTensor(input_box_encodings); + micro_context->DeallocateTempTfLiteTensor(input_class_predictions); + micro_context->DeallocateTempTfLiteTensor(input_anchors); + + return kTfLiteOk; +} + +class Dequantizer { + public: + Dequantizer(int zero_point, float scale) + : zero_point_(zero_point), scale_(scale) {} + float operator()(uint8_t x) { + return (static_cast(x) - zero_point_) * scale_; + } + + private: + int zero_point_; + float scale_; +}; + +template +T ReInterpretTensor(const TfLiteEvalTensor* tensor) { + const float* tensor_base = tflite::micro::GetTensorData(tensor); + return reinterpret_cast(tensor_base); +} + +template +T ReInterpretTensor(TfLiteEvalTensor* tensor) { + float* tensor_base = tflite::micro::GetTensorData(tensor); + return reinterpret_cast(tensor_base); +} + +TfLiteStatus DecodeCenterSizeBoxes(TfLiteContext* context, TfLiteNode* node, + OpData* op_data) { + // Parse input tensor boxencodings + const TfLiteEvalTensor* input_box_encodings = + tflite::micro::GetEvalInput(context, node, kInputTensorBoxEncodings); + TF_LITE_ENSURE_EQ(context, input_box_encodings->dims->data[0], kBatchSize); + const int num_boxes = input_box_encodings->dims->data[1]; + TF_LITE_ENSURE(context, input_box_encodings->dims->data[2] >= kNumCoordBox); + const TfLiteEvalTensor* input_anchors = + tflite::micro::GetEvalInput(context, node, kInputTensorAnchors); + + // Decode the boxes to get (ymin, xmin, ymax, xmax) based on the anchors + CenterSizeEncoding box_centersize; + CenterSizeEncoding scale_values = op_data->scale_values; + CenterSizeEncoding anchor; + for (int idx = 0; idx < num_boxes; ++idx) { + switch (input_box_encodings->type) { + // Float + case kTfLiteFloat32: { + // Please see DequantizeBoxEncodings function for the support detail. + const int box_encoding_idx = idx * input_box_encodings->dims->data[2]; + const float* boxes = &(tflite::micro::GetTensorData( + input_box_encodings)[box_encoding_idx]); + box_centersize = *reinterpret_cast(boxes); + anchor = + ReInterpretTensor(input_anchors)[idx]; + break; + } + default: + // Unsupported type. + return kTfLiteError; + } + + float ycenter = static_cast(static_cast(box_centersize.y) / + static_cast(scale_values.y) * + static_cast(anchor.h) + + static_cast(anchor.y)); + + float xcenter = static_cast(static_cast(box_centersize.x) / + static_cast(scale_values.x) * + static_cast(anchor.w) + + static_cast(anchor.x)); + + float half_h = + static_cast(0.5 * + (std::exp(static_cast(box_centersize.h) / + static_cast(scale_values.h))) * + static_cast(anchor.h)); + float half_w = + static_cast(0.5 * + (std::exp(static_cast(box_centersize.w) / + static_cast(scale_values.w))) * + static_cast(anchor.w)); + + float* decoded_boxes = reinterpret_cast( + context->GetScratchBuffer(context, op_data->decoded_boxes_idx)); + auto& box = reinterpret_cast(decoded_boxes)[idx]; + box.ymin = ycenter - half_h; + box.xmin = xcenter - half_w; + box.ymax = ycenter + half_h; + box.xmax = xcenter + half_w; + } + return kTfLiteOk; +} + +void DecreasingPartialArgSort(const float* values, int num_values, + int num_to_sort, int* indices) { + std::iota(indices, indices + num_values, 0); + std::partial_sort(indices, indices + num_to_sort, indices + num_values, + [&values](const int i, const int j) { + return std::tie(values[i], j) > std::tie(values[j], i); + }); +} + +template +void InsertionSort(int* start, int* end, Compare compare) { + for (int* i = start; i != end; ++i) { + std::rotate(std::upper_bound(start, i, *i, compare), i, i + 1); + } +} + +template +void TopDownMerge(int* values, int* scratch, const int half_num_values, + int num_values, Compare compare) { + int left = 0; + int right = half_num_values; + + for (int i = 0; i < num_values; i++) { + if (left >= half_num_values || + (right < num_values && compare(values[right], values[left]))) { + scratch[i] = values[right++]; + } else { + scratch[i] = values[left++]; + } + } + memcpy(values, scratch, num_values * sizeof(int)); +} + +template +void MergeSort(int* values, int* scratch, const int num_values, + Compare compare) { + constexpr int threshold = 20; + + if (num_values < threshold) { + InsertionSort(values, values + num_values, compare); + return; + } + + const int half_num_values = num_values / 2; + + MergeSort(values, scratch, half_num_values, compare); + MergeSort(values + half_num_values, scratch, num_values - half_num_values, + compare); + TopDownMerge(values, scratch, half_num_values, num_values, compare); +} + +void DecreasingArgSort(const float* values, int num_values, int* indices, + int* scratch) { + std::iota(indices, indices + num_values, 0); + + MergeSort(indices, scratch, num_values, [&values](const int i, const int j) { + return values[i] > values[j]; + }); +} + +int SelectDetectionsAboveScoreThreshold(const float* values, int size, + const float threshold, + float* keep_values, int* keep_indices) { + int counter = 0; + for (int i = 0; i < size; i++) { + if (values[i] >= threshold) { + keep_values[counter] = values[i]; + keep_indices[counter] = i; + counter++; + } + } + return counter; +} + +bool ValidateBoxes(const float* decoded_boxes, const int num_boxes) { + for (int i = 0; i < num_boxes; ++i) { + // ymax>=ymin, xmax>=xmin + auto& box = reinterpret_cast(decoded_boxes)[i]; + if (box.ymin >= box.ymax || box.xmin >= box.xmax) { + return false; + } + } + return true; +} + +float ComputeIntersectionOverUnion(const float* decoded_boxes, const int i, + const int j) { + auto& box_i = reinterpret_cast(decoded_boxes)[i]; + auto& box_j = reinterpret_cast(decoded_boxes)[j]; + const float area_i = (box_i.ymax - box_i.ymin) * (box_i.xmax - box_i.xmin); + const float area_j = (box_j.ymax - box_j.ymin) * (box_j.xmax - box_j.xmin); + if (area_i <= 0 || area_j <= 0) return 0.0; + const float intersection_ymin = std::max(box_i.ymin, box_j.ymin); + const float intersection_xmin = std::max(box_i.xmin, box_j.xmin); + const float intersection_ymax = std::min(box_i.ymax, box_j.ymax); + const float intersection_xmax = std::min(box_i.xmax, box_j.xmax); + const float intersection_area = + std::max(intersection_ymax - intersection_ymin, 0.0) * + std::max(intersection_xmax - intersection_xmin, 0.0); + return intersection_area / (area_i + area_j - intersection_area); +} + +// NonMaxSuppressionSingleClass() prunes out the box locations with high overlap +// before selecting the highest scoring boxes (max_detections in number) +// It assumes all boxes are good in beginning and sorts based on the scores. +// If lower-scoring box has too much overlap with a higher-scoring box, +// we get rid of the lower-scoring box. +// Complexity is O(N^2) pairwise comparison between boxes +TfLiteStatus NonMaxSuppressionSingleClassHelper( + TfLiteContext* context, TfLiteNode* node, OpData* op_data, + const float* scores, int* selected, int* selected_size, + int max_detections) { + const TfLiteEvalTensor* input_box_encodings = + tflite::micro::GetEvalInput(context, node, kInputTensorBoxEncodings); + const int num_boxes = input_box_encodings->dims->data[1]; + const float non_max_suppression_score_threshold = + op_data->non_max_suppression_score_threshold; + const float intersection_over_union_threshold = + op_data->intersection_over_union_threshold; + // Maximum detections should be positive. + TF_LITE_ENSURE(context, (max_detections >= 0)); + // intersection_over_union_threshold should be positive + // and should be less than 1. + TF_LITE_ENSURE(context, (intersection_over_union_threshold > 0.0f) && + (intersection_over_union_threshold <= 1.0f)); + // Validate boxes + float* decoded_boxes = reinterpret_cast( + context->GetScratchBuffer(context, op_data->decoded_boxes_idx)); + + TF_LITE_ENSURE(context, ValidateBoxes(decoded_boxes, num_boxes)); + + // threshold scores + int* keep_indices = reinterpret_cast( + context->GetScratchBuffer(context, op_data->keep_indices_idx)); + float* keep_scores = reinterpret_cast( + context->GetScratchBuffer(context, op_data->keep_scores_idx)); + int num_scores_kept = SelectDetectionsAboveScoreThreshold( + scores, num_boxes, non_max_suppression_score_threshold, keep_scores, + keep_indices); + int* sorted_indices = reinterpret_cast( + context->GetScratchBuffer(context, op_data->sorted_indices_idx)); + + // Reusing keep_indices for scratch buffer and write back its values + // after the sorting is done. + DecreasingArgSort(keep_scores, num_scores_kept, sorted_indices, keep_indices); + int counter = 0; + for (int i = 0; i < num_boxes; i++) { + if (scores[i] >= non_max_suppression_score_threshold) { + keep_indices[counter] = i; + counter++; + } + } + + const int num_boxes_kept = num_scores_kept; + const int output_size = std::min(num_boxes_kept, max_detections); + *selected_size = 0; + + int num_active_candidate = num_boxes_kept; + uint8_t* active_box_candidate = reinterpret_cast( + context->GetScratchBuffer(context, op_data->active_candidate_idx)); + + for (int row = 0; row < num_boxes_kept; row++) { + active_box_candidate[row] = 1; + } + for (int i = 0; i < num_boxes_kept; ++i) { + if (num_active_candidate == 0 || *selected_size >= output_size) break; + if (active_box_candidate[i] == 1) { + selected[(*selected_size)++] = keep_indices[sorted_indices[i]]; + active_box_candidate[i] = 0; + num_active_candidate--; + } else { + continue; + } + for (int j = i + 1; j < num_boxes_kept; ++j) { + if (active_box_candidate[j] == 1) { + float intersection_over_union = ComputeIntersectionOverUnion( + decoded_boxes, keep_indices[sorted_indices[i]], + keep_indices[sorted_indices[j]]); + + if (intersection_over_union > intersection_over_union_threshold) { + active_box_candidate[j] = 0; + num_active_candidate--; + } + } + } + } + + return kTfLiteOk; +} + +// This function implements a regular version of Non Maximal Suppression (NMS) +// for multiple classes where +// 1) we do NMS separately for each class across all anchors and +// 2) keep only the highest anchor scores across all classes +// 3) The worst runtime of the regular NMS is O(K*N^2) +// where N is the number of anchors and K the number of +// classes. +TfLiteStatus NonMaxSuppressionMultiClassRegularHelper(TfLiteContext* context, + TfLiteNode* node, + OpData* op_data, + const float* scores) { + const TfLiteEvalTensor* input_box_encodings = + tflite::micro::GetEvalInput(context, node, kInputTensorBoxEncodings); + const TfLiteEvalTensor* input_class_predictions = + tflite::micro::GetEvalInput(context, node, kInputTensorClassPredictions); + TfLiteEvalTensor* detection_boxes = + tflite::micro::GetEvalOutput(context, node, kOutputTensorDetectionBoxes); + TfLiteEvalTensor* detection_classes = tflite::micro::GetEvalOutput( + context, node, kOutputTensorDetectionClasses); + TfLiteEvalTensor* detection_scores = + tflite::micro::GetEvalOutput(context, node, kOutputTensorDetectionScores); + TfLiteEvalTensor* num_detections = + tflite::micro::GetEvalOutput(context, node, kOutputTensorNumDetections); + + const int num_boxes = input_box_encodings->dims->data[1]; + const int num_classes = op_data->num_classes; + const int num_detections_per_class = op_data->detections_per_class; + const int max_detections = op_data->max_detections; + const int num_classes_with_background = + input_class_predictions->dims->data[2]; + // The row index offset is 1 if background class is included and 0 otherwise. + int label_offset = num_classes_with_background - num_classes; + TF_LITE_ENSURE(context, num_detections_per_class > 0); + + // For each class, perform non-max suppression. + float* class_scores = reinterpret_cast( + context->GetScratchBuffer(context, op_data->score_buffer_idx)); + int* box_indices_after_regular_non_max_suppression = reinterpret_cast( + context->GetScratchBuffer(context, op_data->buffer_idx)); + float* scores_after_regular_non_max_suppression = + reinterpret_cast(context->GetScratchBuffer( + context, op_data->scores_after_regular_non_max_suppression_idx)); + + int size_of_sorted_indices = 0; + int* sorted_indices = reinterpret_cast( + context->GetScratchBuffer(context, op_data->sorted_indices_idx)); + float* sorted_values = reinterpret_cast( + context->GetScratchBuffer(context, op_data->sorted_values_idx)); + + for (int col = 0; col < num_classes; col++) { + for (int row = 0; row < num_boxes; row++) { + // Get scores of boxes corresponding to all anchors for single class + class_scores[row] = + *(scores + row * num_classes_with_background + col + label_offset); + } + // Perform non-maximal suppression on single class + int selected_size = 0; + int* selected = reinterpret_cast( + context->GetScratchBuffer(context, op_data->selected_idx)); + TF_LITE_ENSURE_STATUS(NonMaxSuppressionSingleClassHelper( + context, node, op_data, class_scores, selected, &selected_size, + num_detections_per_class)); + // Add selected indices from non-max suppression of boxes in this class + int output_index = size_of_sorted_indices; + for (int i = 0; i < selected_size; i++) { + int selected_index = selected[i]; + + box_indices_after_regular_non_max_suppression[output_index] = + (selected_index * num_classes_with_background + col + label_offset); + scores_after_regular_non_max_suppression[output_index] = + class_scores[selected_index]; + output_index++; + } + // Sort the max scores among the selected indices + // Get the indices for top scores + int num_indices_to_sort = std::min(output_index, max_detections); + DecreasingPartialArgSort(scores_after_regular_non_max_suppression, + output_index, num_indices_to_sort, sorted_indices); + + // Copy values to temporary vectors + for (int row = 0; row < num_indices_to_sort; row++) { + int temp = sorted_indices[row]; + sorted_indices[row] = box_indices_after_regular_non_max_suppression[temp]; + sorted_values[row] = scores_after_regular_non_max_suppression[temp]; + } + // Copy scores and indices from temporary vectors + for (int row = 0; row < num_indices_to_sort; row++) { + box_indices_after_regular_non_max_suppression[row] = sorted_indices[row]; + scores_after_regular_non_max_suppression[row] = sorted_values[row]; + } + size_of_sorted_indices = num_indices_to_sort; + } + + // Allocate output tensors + for (int output_box_index = 0; output_box_index < max_detections; + output_box_index++) { + if (output_box_index < size_of_sorted_indices) { + const int anchor_index = floor( + box_indices_after_regular_non_max_suppression[output_box_index] / + num_classes_with_background); + const int class_index = + box_indices_after_regular_non_max_suppression[output_box_index] - + anchor_index * num_classes_with_background - label_offset; + const float selected_score = + scores_after_regular_non_max_suppression[output_box_index]; + // detection_boxes + float* decoded_boxes = reinterpret_cast( + context->GetScratchBuffer(context, op_data->decoded_boxes_idx)); + ReInterpretTensor(detection_boxes)[output_box_index] = + reinterpret_cast(decoded_boxes)[anchor_index]; + // detection_classes + tflite::micro::GetTensorData(detection_classes)[output_box_index] = + class_index; + // detection_scores + tflite::micro::GetTensorData(detection_scores)[output_box_index] = + selected_score; + } else { + ReInterpretTensor( + detection_boxes)[output_box_index] = {0.0f, 0.0f, 0.0f, 0.0f}; + // detection_classes + tflite::micro::GetTensorData(detection_classes)[output_box_index] = + 0.0f; + // detection_scores + tflite::micro::GetTensorData(detection_scores)[output_box_index] = + 0.0f; + } + } + tflite::micro::GetTensorData(num_detections)[0] = + size_of_sorted_indices; + + return kTfLiteOk; +} + +// This function implements a fast version of Non Maximal Suppression for +// multiple classes where +// 1) we keep the top-k scores for each anchor and +// 2) during NMS, each anchor only uses the highest class score for sorting. +// 3) Compared to standard NMS, the worst runtime of this version is O(N^2) +// instead of O(KN^2) where N is the number of anchors and K the number of +// classes. +TfLiteStatus NonMaxSuppressionMultiClassFastHelper(TfLiteContext* context, + TfLiteNode* node, + OpData* op_data, + const float* scores) { + const TfLiteEvalTensor* input_box_encodings = + tflite::micro::GetEvalInput(context, node, kInputTensorBoxEncodings); + const TfLiteEvalTensor* input_class_predictions = + tflite::micro::GetEvalInput(context, node, kInputTensorClassPredictions); + TfLiteEvalTensor* detection_boxes = + tflite::micro::GetEvalOutput(context, node, kOutputTensorDetectionBoxes); + + TfLiteEvalTensor* detection_classes = tflite::micro::GetEvalOutput( + context, node, kOutputTensorDetectionClasses); + TfLiteEvalTensor* detection_scores = + tflite::micro::GetEvalOutput(context, node, kOutputTensorDetectionScores); + TfLiteEvalTensor* num_detections = + tflite::micro::GetEvalOutput(context, node, kOutputTensorNumDetections); + + const int num_boxes = input_box_encodings->dims->data[1]; + const int num_classes = op_data->num_classes; + const int max_categories_per_anchor = op_data->max_classes_per_detection; + const int num_classes_with_background = + input_class_predictions->dims->data[2]; + + // The row index offset is 1 if background class is included and 0 otherwise. + int label_offset = num_classes_with_background - num_classes; + TF_LITE_ENSURE(context, (max_categories_per_anchor > 0)); + const int num_categories_per_anchor = + std::min(max_categories_per_anchor, num_classes); + float* max_scores = reinterpret_cast( + context->GetScratchBuffer(context, op_data->score_buffer_idx)); + int* sorted_class_indices = reinterpret_cast( + context->GetScratchBuffer(context, op_data->buffer_idx)); + + for (int row = 0; row < num_boxes; row++) { + const float* box_scores = + scores + row * num_classes_with_background + label_offset; + int* class_indices = sorted_class_indices + row * num_classes; + DecreasingPartialArgSort(box_scores, num_classes, num_categories_per_anchor, + class_indices); + max_scores[row] = box_scores[class_indices[0]]; + } + + // Perform non-maximal suppression on max scores + int selected_size = 0; + int* selected = reinterpret_cast( + context->GetScratchBuffer(context, op_data->selected_idx)); + TF_LITE_ENSURE_STATUS(NonMaxSuppressionSingleClassHelper( + context, node, op_data, max_scores, selected, &selected_size, + op_data->max_detections)); + + // Allocate output tensors + int output_box_index = 0; + + for (int i = 0; i < selected_size; i++) { + int selected_index = selected[i]; + + const float* box_scores = + scores + selected_index * num_classes_with_background + label_offset; + const int* class_indices = + sorted_class_indices + selected_index * num_classes; + + for (int col = 0; col < num_categories_per_anchor; ++col) { + int box_offset = num_categories_per_anchor * output_box_index + col; + + // detection_boxes + float* decoded_boxes = reinterpret_cast( + context->GetScratchBuffer(context, op_data->decoded_boxes_idx)); + ReInterpretTensor(detection_boxes)[box_offset] = + reinterpret_cast(decoded_boxes)[selected_index]; + + // detection_classes + tflite::micro::GetTensorData(detection_classes)[box_offset] = + class_indices[col]; + + // detection_scores + tflite::micro::GetTensorData(detection_scores)[box_offset] = + box_scores[class_indices[col]]; + + output_box_index++; + } + } + + tflite::micro::GetTensorData(num_detections)[0] = output_box_index; + return kTfLiteOk; +} + +TfLiteStatus NonMaxSuppressionMultiClass(TfLiteContext* context, + TfLiteNode* node, OpData* op_data) { + // Get the input tensors + const TfLiteEvalTensor* input_box_encodings = + tflite::micro::GetEvalInput(context, node, kInputTensorBoxEncodings); + const TfLiteEvalTensor* input_class_predictions = + tflite::micro::GetEvalInput(context, node, kInputTensorClassPredictions); + const int num_boxes = input_box_encodings->dims->data[1]; + const int num_classes = op_data->num_classes; + + TF_LITE_ENSURE_EQ(context, input_class_predictions->dims->data[0], + kBatchSize); + TF_LITE_ENSURE_EQ(context, input_class_predictions->dims->data[1], num_boxes); + const int num_classes_with_background = + input_class_predictions->dims->data[2]; + + TF_LITE_ENSURE(context, (num_classes_with_background - num_classes <= 1)); + TF_LITE_ENSURE(context, (num_classes_with_background >= num_classes)); + + const float* scores; + switch (input_class_predictions->type) { + case kTfLiteFloat32: + scores = tflite::micro::GetTensorData(input_class_predictions); + break; + default: + // Unsupported type. + return kTfLiteError; + } + + if (op_data->use_regular_non_max_suppression) { + TF_LITE_ENSURE_STATUS(NonMaxSuppressionMultiClassRegularHelper( + context, node, op_data, scores)); + } else { + TF_LITE_ENSURE_STATUS( + NonMaxSuppressionMultiClassFastHelper(context, node, op_data, scores)); + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE(context, (kBatchSize == 1)); + auto* op_data = static_cast(node->user_data); + + // These two functions correspond to two blocks in the Object Detection model. + // In future, we would like to break the custom op in two blocks, which is + // currently not feasible because we would like to input quantized inputs + // and do all calculations in float. Mixed quantized/float calculations are + // currently not supported in TFLite. + + // This fills in temporary decoded_boxes + // by transforming input_box_encodings and input_anchors from + // CenterSizeEncodings to BoxCornerEncoding + TF_LITE_ENSURE_STATUS(DecodeCenterSizeBoxes(context, node, op_data)); + + // This fills in the output tensors + // by choosing effective set of decoded boxes + // based on Non Maximal Suppression, i.e. selecting + // highest scoring non-overlapping boxes. + TF_LITE_ENSURE_STATUS(NonMaxSuppressionMultiClass(context, node, op_data)); + + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration* Register_DETECTION_POSTPROCESS() { + static TfLiteRegistration r = tflite::micro::RegisterOp(Init, Prepare, Eval); + return &r; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/detection_postprocess_flexbuffers_generated_data.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/detection_postprocess_flexbuffers_generated_data.h new file mode 100644 index 000000000..f5b9eae01 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/detection_postprocess_flexbuffers_generated_data.h @@ -0,0 +1,25 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_FLEXBUFFERS_GENERATED_DATA_H +#define TENSORFLOW_LITE_MICRO_KERNELS_FLEXBUFFERS_GENERATED_DATA_H + +extern const int g_gen_data_size_none_regular_nms; +extern const unsigned char g_gen_data_none_regular_nms[]; + +extern const int g_gen_data_size_regular_nms; +extern const unsigned char g_gen_data_regular_nms[]; + +#endif diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/div.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/div.cc new file mode 100644 index 000000000..5c9861269 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/div.cc @@ -0,0 +1,208 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/div.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor1 = 0; +constexpr int kInputTensor2 = 1; +constexpr int kOutputTensor = 0; + +struct OpDataDiv { + // Parameters used in the quantized paths where the output is 8bit + int32_t input1_zero_point; + int32_t input2_zero_point; + int32_t output_zero_point; + int32_t output_activation_min; + int32_t output_activation_max; + + // Parameters used in all quantized paths + int32_t output_multiplier; + int output_shift; +}; + +TfLiteStatus CalculateOpDataDiv(TfLiteContext* context, TfLiteTensor* input1, + TfLiteTensor* input2, TfLiteTensor* output, + TfLiteDivParams* params, OpDataDiv* data) { + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, input2->type); + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, output->type); + + if (output->type == kTfLiteInt8) { + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, params->activation, output, &data->output_activation_min, + &data->output_activation_max)); + const double real_multiplier = static_cast( + input1->params.scale / (input2->params.scale * output->params.scale)); + QuantizeMultiplier(real_multiplier, &data->output_multiplier, + &data->output_shift); + data->input1_zero_point = input1->params.zero_point; + data->input2_zero_point = input2->params.zero_point; + data->output_zero_point = output->params.zero_point; + } + + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataDiv)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + OpDataDiv* data = static_cast(node->user_data); + auto* params = reinterpret_cast(node->builtin_data); + + TF_LITE_ENSURE_STATUS( + CalculateOpDataDiv(context, input1, input2, output, params, data)); + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +void EvalDiv(TfLiteContext* context, TfLiteNode* node, TfLiteDivParams* params, + const OpDataDiv* data, const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params = {}; + +#define TF_LITE_DIV(type, opname, data_type) \ + data_type output_activation_min, output_activation_max; \ + CalculateActivationRange(params->activation, &output_activation_min, \ + &output_activation_max); \ + SetActivationParams(output_activation_min, output_activation_max, \ + &op_params); \ + type::opname(op_params, tflite::micro::GetTensorShape(input1), \ + tflite::micro::GetTensorData(input1), \ + tflite::micro::GetTensorShape(input2), \ + tflite::micro::GetTensorData(input2), \ + tflite::micro::GetTensorShape(output), \ + tflite::micro::GetTensorData(output)) + + bool requires_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + if (requires_broadcast) { + TF_LITE_DIV(reference_ops, BroadcastDivSlow, float); + } else { + TF_LITE_DIV(reference_ops, Div, float); + } +#undef TF_LITE_DIV +} + +TfLiteStatus EvalQuantized(TfLiteContext* context, TfLiteNode* node, + TfLiteDivParams* params, const OpDataDiv* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params = {}; + +#define TF_LITE_DIV(type, opname, dtype) \ + type::opname(op_params, tflite::micro::GetTensorShape(input1), \ + tflite::micro::GetTensorData(input1), \ + tflite::micro::GetTensorShape(input2), \ + tflite::micro::GetTensorData(input2), \ + tflite::micro::GetTensorShape(output), \ + tflite::micro::GetTensorData(output)) + + if (input1->type == kTfLiteInt8 && input2->type == kTfLiteInt8 && + output->type == kTfLiteInt8) { + SetActivationParams(data->output_activation_min, + data->output_activation_max, &op_params); + op_params.input1_offset = -data->input1_zero_point; + op_params.input2_offset = -data->input2_zero_point; + op_params.output_offset = data->output_zero_point; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = data->output_shift; + + bool requires_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + if (requires_broadcast) { + TF_LITE_DIV(reference_ops, BroadcastDivSlow, int8_t); + } else { + TF_LITE_DIV(reference_ops, Div, int8_t); + } +#undef TF_LITE_DIV + } else { + MicroPrintf("Unsupported combination of input and output types in DIV."); + return kTfLiteError; + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = static_cast(node->builtin_data); + TFLITE_DCHECK(node->user_data != nullptr); + auto* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + if (output->type == kTfLiteFloat32) { + EvalDiv(context, node, params, data, input1, input2, output); + } else if (output->type == kTfLiteInt8) { + TF_LITE_ENSURE_OK(context, EvalQuantized(context, node, params, data, + input1, input2, output)); + } else { + MicroPrintf( + "DIV only supports FLOAT32, quantized INT8 " + "now, got type %s (%d).", + TfLiteTypeGetName(output->type), output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_DIV() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/elementwise.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/elementwise.cc new file mode 100644 index 000000000..81b27039f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/elementwise.cc @@ -0,0 +1,430 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace elementwise { +namespace { + +constexpr int kAbsNameId = 0; +constexpr int kRsrqtNameId = 1; + +const int kElementwiseInputTensor = 0; +const int kElementwiseOutputTensor = 0; + +struct OpDataAbsRsqrt { + int32_t multiplier; + int shift; + int input_offset; + int output_offset; + bool needs_rescale; + TfLiteQuantizationType input_quantization_type; + TfLiteType input_type; +}; + +bool IsNumericSupportedType(const TfLiteType type) { + return type == kTfLiteFloat32; +} + +bool IsLogicalSupportedType(const TfLiteType type) { + return type == kTfLiteBool; +} + +bool IsAbsSupportedType(const TfLiteType type) { + return type == kTfLiteFloat32 || type == kTfLiteInt8 || type == kTfLiteInt16; +} + +bool IsRsqrtSupportedType(const TfLiteType type) { + return type == kTfLiteFloat32 || type == kTfLiteInt8; +} + +inline void SetAbsOutputMultiplier(const float input_scale, + const float output_scale, + int32_t* multiplier, int* shift) { + QuantizeMultiplier(static_cast(input_scale / output_scale), + multiplier, shift); +} + +inline void SetRsqrtOutputMultiplier(const float input_scale, + const float output_scale, + int32_t* multiplier, int* shift) { + const double scale = + 1. / static_cast((std::sqrt(input_scale) * output_scale)); + QuantizeMultiplier(scale, multiplier, shift); +} + +typedef bool (*IsSupportedType)(TfLiteType); +template +TfLiteStatus GenericPrepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kElementwiseInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kElementwiseOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + if (!IsSupportedType(input->type)) { + MicroPrintf("Input data type %s (%d) is not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +typedef bool (*IsSupportedType)(TfLiteType); +template +TfLiteStatus PrepareAbsRsqrt(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + if (!IsSupportedType(input->type)) { + MicroPrintf("Input data type %s (%d) is not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + + auto* op_data = static_cast(node->user_data); + op_data->input_type = input->type; + + // For int16 type input, we support both quantized and non-quantized + // evaluation. + if (op_nameid == kAbsNameId) { + op_data->input_quantization_type = input->quantization.type; + } + + if (input->type == kTfLiteInt8 || + (input->type == kTfLiteInt16 && + input->quantization.type != kTfLiteNoQuantization)) { + TF_LITE_ENSURE_EQ(context, input->quantization.type, + kTfLiteAffineQuantization); + TF_LITE_ENSURE_EQ(context, output->quantization.type, + kTfLiteAffineQuantization); + const auto* input_params = + reinterpret_cast(input->quantization.params); + const auto* output_params = reinterpret_cast( + output->quantization.params); + TF_LITE_ENSURE(context, input_params != nullptr); + TF_LITE_ENSURE(context, input_params->scale != nullptr); + TF_LITE_ENSURE(context, input_params->scale->size > 0); + TF_LITE_ENSURE(context, input_params->zero_point->size > 0); + TF_LITE_ENSURE(context, output_params != nullptr); + TF_LITE_ENSURE(context, output_params->scale != nullptr); + TF_LITE_ENSURE(context, output_params->scale->size > 0); + TF_LITE_ENSURE(context, output_params->zero_point->size > 0); + op_data->input_offset = input_params->zero_point->data[0]; + op_data->output_offset = output_params->zero_point->data[0]; + if (input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, op_data->input_offset, 0); + TF_LITE_ENSURE_EQ(context, op_data->output_offset, 0); + } + const float input_scale = input_params->scale->data[0]; + const float output_scale = output_params->scale->data[0]; + op_data->needs_rescale = input_scale != output_scale; + if (op_nameid == kAbsNameId && op_data->needs_rescale) { + SetAbsOutputMultiplier(input_scale, output_scale, &op_data->multiplier, + &op_data->shift); + } else if (op_nameid == kRsrqtNameId) { + SetRsqrtOutputMultiplier(input_scale, output_scale, &op_data->multiplier, + &op_data->shift); + } + } + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +template +inline TfLiteStatus EvalImplQuantized( + TfLiteContext* context, TfLiteNode* node, + T func(TfLiteContext*, TfLiteNode*, T), + TfLiteStatus validate_input_func(TfLiteContext*, TfLiteNode*, T), + TfLiteType expected_type) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, expected_type); + const size_t num_elements = ElementCount(*input->dims); + const T* in_data = tflite::micro::GetTensorData(input); + T* out_data = tflite::micro::GetTensorData(output); + for (size_t i = 0; i < num_elements; ++i) { + if (validate_input_func) { + TF_LITE_ENSURE_OK(context, + validate_input_func(context, node, in_data[i])); + } + out_data[i] = func(context, node, in_data[i]); + } + return kTfLiteOk; +} + +template +inline T AbsHelper(T i) { + return std::abs(i); +} + +template +inline TfLiteStatus EvalImpl(TfLiteContext* context, TfLiteNode* node, + T func(T), TfLiteStatus validate_input_func(T), + TfLiteType expected_type) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, expected_type); + const size_t num_elements = ElementCount(*input->dims); + const T* in_data = tflite::micro::GetTensorData(input); + T* out_data = tflite::micro::GetTensorData(output); + for (size_t i = 0; i < num_elements; ++i) { + if (validate_input_func) { + TF_LITE_ENSURE_OK(context, validate_input_func(in_data[i])); + } + out_data[i] = func(in_data[i]); + } + return kTfLiteOk; +} + +inline TfLiteStatus EvalNumeric(TfLiteContext* context, TfLiteNode* node, + float float_func(float)) { + return EvalImpl(context, node, float_func, + /*validate_input_func=*/nullptr, kTfLiteFloat32); +} + +inline TfLiteStatus EvalLogical(TfLiteContext* context, TfLiteNode* node, + + bool bool_func(bool)) { + return EvalImpl(context, node, bool_func, + /*validate_input_func=*/nullptr, kTfLiteBool); +} + +void* ElementWiseAbsRsqrtInit(TfLiteContext* context, const char* buffer, + size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataAbsRsqrt)); +} + +template +inline T AbsEvalQuantized(TfLiteContext* context, TfLiteNode* node, T i) { + const auto* op_data = static_cast(node->user_data); + const int kMin = std::numeric_limits::min(); + const int kMax = std::numeric_limits::max(); + + const int32_t value = std::abs(i - op_data->input_offset); + if (!op_data->needs_rescale) { + return static_cast( + std::min(std::max(static_cast(value + op_data->output_offset), + static_cast(kMin)), + static_cast(kMax))); + } + + const int32_t output = tflite::MultiplyByQuantizedMultiplier( + value, op_data->multiplier, op_data->shift) + + op_data->output_offset; + return static_cast(std::min( + std::max(static_cast(output), static_cast(kMin)), + static_cast(kMax))); +} + +template +inline T RsqrtEvalQuantized(TfLiteContext* context, TfLiteNode* node, T i) { + const auto* op_data = static_cast(node->user_data); + const int kMin = std::numeric_limits::min(); + const int kMax = std::numeric_limits::max(); + + const int32_t value = (i - op_data->input_offset); + const int32_t kShift = 20; // Shift to keep value integer. + if (value == 0) { + // Assume that any value close to 0 represents the max output value. + return static_cast(kMax); + } + int32_t inv_sqrt_multiplier; + int inv_sqrt_shift; + GetInvSqrtQuantizedMultiplierExp(value, kReverseShift, &inv_sqrt_multiplier, + &inv_sqrt_shift); + const int32_t data = tflite::MultiplyByQuantizedMultiplier( + static_cast(1), inv_sqrt_multiplier, inv_sqrt_shift + kShift); + const int32_t output = + tflite::MultiplyByQuantizedMultiplier(data, op_data->multiplier, + op_data->shift - kShift) + + op_data->output_offset; + return static_cast(std::min( + std::max(static_cast(output), static_cast(kMin)), + static_cast(kMax))); +} + +template +TfLiteStatus validate_input_func(TfLiteContext* context, TfLiteNode* node, + T i) { + const auto* op_data = static_cast(node->user_data); + + TF_LITE_ENSURE_MSG(context, i >= op_data->input_offset, + "Rsqrt is only defined for positive values"); + return static_cast(kTfLiteOk); +} + +TfLiteStatus AbsEval(TfLiteContext* context, TfLiteNode* node) { + OpDataAbsRsqrt* op_data = reinterpret_cast(node->user_data); + TfLiteType type = op_data->input_type; + TfLiteQuantizationType input_quantization_type = + op_data->input_quantization_type; + TfLiteStatus eval_result; + + switch (type) { + case kTfLiteFloat32: + eval_result = EvalNumeric(context, node, std::abs); + break; + case kTfLiteInt8: + eval_result = + EvalImplQuantized(context, node, AbsEvalQuantized, + /*validate_input_func=*/nullptr, type); + break; + case kTfLiteInt16: + eval_result = + input_quantization_type == kTfLiteNoQuantization + ? EvalImpl(context, node, AbsHelper, + /*validate_input_func=*/nullptr, type) + : EvalImplQuantized(context, node, AbsEvalQuantized, + /*validate_input_func=*/nullptr, + type); + break; + default: + MicroPrintf("Current data type %s is not supported.", + TfLiteTypeGetName(type)); + return kTfLiteError; + break; + } + return eval_result; +} + +TfLiteStatus SinEval(TfLiteContext* context, TfLiteNode* node) { + return EvalNumeric(context, node, std::sin); +} + +TfLiteStatus CosEval(TfLiteContext* context, TfLiteNode* node) { + return EvalNumeric(context, node, std::cos); +} + +TfLiteStatus LogEval(TfLiteContext* context, TfLiteNode* node) { + return EvalNumeric(context, node, std::log); +} + +TfLiteStatus SqrtEval(TfLiteContext* context, TfLiteNode* node) { + return EvalNumeric(context, node, std::sqrt); +} + +TfLiteStatus RsqrtEval(TfLiteContext* context, TfLiteNode* node) { + const auto* op_data = static_cast(node->user_data); + TfLiteType type = op_data->input_type; + switch (type) { + case kTfLiteFloat32: + return EvalImpl( + context, node, [](float f) { return 1.f / std::sqrt(f); }, + /*validate_input_func=*/nullptr, type); + case kTfLiteInt8: + return EvalImplQuantized(context, node, + elementwise::RsqrtEvalQuantized, + elementwise::validate_input_func, type); + + default: + MicroPrintf("Current data type %s is not supported.", + TfLiteTypeGetName(type)); + return kTfLiteError; + } +} + +TfLiteStatus SquareEval(TfLiteContext* context, TfLiteNode* node) { + return EvalNumeric(context, node, [](float f) { return f * f; }); +} + +TfLiteStatus LogicalNotEval(TfLiteContext* context, TfLiteNode* node) { + return EvalLogical(context, node, [](bool v) { return !v; }); +} + +} // namespace +} // namespace elementwise + +TfLiteRegistration Register_ABS() { + return tflite::micro::RegisterOp( + elementwise::ElementWiseAbsRsqrtInit, + elementwise::PrepareAbsRsqrt, + elementwise::AbsEval); +} + +TfLiteRegistration Register_SIN() { + return tflite::micro::RegisterOp( + nullptr, elementwise::GenericPrepare, + elementwise::SinEval); +} + +TfLiteRegistration Register_COS() { + return tflite::micro::RegisterOp( + nullptr, elementwise::GenericPrepare, + elementwise::CosEval); +} + +TfLiteRegistration Register_LOG() { + return tflite::micro::RegisterOp( + nullptr, elementwise::GenericPrepare, + elementwise::LogEval); +} + +TfLiteRegistration Register_SQRT() { + return tflite::micro::RegisterOp( + nullptr, elementwise::GenericPrepare, + elementwise::SqrtEval); +} + +TfLiteRegistration Register_RSQRT() { + return tflite::micro::RegisterOp( + elementwise::ElementWiseAbsRsqrtInit, + elementwise::PrepareAbsRsqrt, + elementwise::RsqrtEval); +} + +TfLiteRegistration Register_SQUARE() { + return tflite::micro::RegisterOp( + nullptr, elementwise::GenericPrepare, + elementwise::SquareEval); +} + +TfLiteRegistration Register_LOGICAL_NOT() { + return tflite::micro::RegisterOp( + nullptr, elementwise::GenericPrepare, + elementwise::LogicalNotEval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/elu.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/elu.cc new file mode 100644 index 000000000..c4786d6fc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/elu.cc @@ -0,0 +1,151 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/elu.h" + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +// Input/output tensor index. +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +// OLD-TODO(b/142762739): We should figure out a multi-threading plan for most +// of the activation ops below. + +struct OpData { + int8_t table[256]; +}; + +using TransformFunc = float (*)(float); + +template +void PopulateLookupTable(const TfLiteTensor* input, const TfLiteTensor* output, + const TransformFunc transform, OpData* data) { + if (sizeof(T) != 1) { + MicroPrintf("Lookup table valid only for 8bit"); + TFLITE_ABORT; + } + + const float inverse_scale = 1 / output->params.scale; + int32_t maxval = std::numeric_limits::max(); + int32_t minval = std::numeric_limits::min(); + for (int32_t val = minval; val <= maxval; ++val) { + const float dequantized = + input->params.scale * (val - input->params.zero_point); + const float transformed = transform(dequantized); + const float rescaled = TfLiteRound(transformed * inverse_scale); + const int32_t quantized = + static_cast(rescaled + output->params.zero_point); + data->table[static_cast(static_cast(val))] = + static_cast(std::max(std::min(maxval, quantized), minval)); + } +} + +// OLD-TODO(b/143696793): move this to optimized_ops. +void EvalUsingLookupTable(const OpData* data, const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + const int size = MatchingFlatSize(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output)); + int8_t* output_data = tflite::micro::GetTensorData(output); + const int8_t* input_data = tflite::micro::GetTensorData(input); + + for (int i = 0; i < size; ++i) { + output_data[i] = data->table[static_cast(input_data[i])]; + } +} + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + // Use LUT to handle quantized elu path. + if (input->type == kTfLiteInt8) { + OpData* data = static_cast(node->user_data); + TransformFunc transform = [](float value) { + return value < 0.0f ? std::exp(value) - 1.0f : value; + }; + PopulateLookupTable(input, output, transform, data); + } + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +void* EluInit(TfLiteContext* context, const char* buffer, size_t length) { + // This is a builtin op, so we don't use the contents in 'buffer', if any. + // Instead, we allocate a new object to carry information from Prepare() to + // Eval(). + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus EluPrepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +TfLiteStatus EluEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + switch (input->type) { + case kTfLiteFloat32: { + reference_ops::Elu(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + case kTfLiteInt8: { + const OpData* data = static_cast(node->user_data); + EvalUsingLookupTable(data, input, output); + return kTfLiteOk; + } + default: + MicroPrintf("ELU only supports float32 and int8 currently, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } +} + +} // namespace + +TfLiteRegistration Register_ELU() { + return tflite::micro::RegisterOp(EluInit, EluPrepare, EluEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/README.md b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/README.md new file mode 100644 index 000000000..b0c215fbd --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/README.md @@ -0,0 +1,11 @@ +# Info + +These are the Espressif chipset specific replacement kernels. +The kernels call optimized routines or reference routines depending upon optimization option selected. + +By default optimizations are selected if available. +To change this behaviour, please make the appropriate `ESP-NN` menu selection after running: + +``` +idf.py menuconfig +``` diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/add.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/add.cc new file mode 100644 index 000000000..f9ee538b9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/add.cc @@ -0,0 +1,203 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/add.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/add.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/add.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +#include + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + +long long add_total_time = 0; + +namespace tflite { + +void EvalAdd(TfLiteContext* context, TfLiteNode* node, TfLiteAddParams* params, + const OpDataAdd* data, const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params; + SetActivationParams(data->output_activation_min_f32, + data->output_activation_max_f32, &op_params); + if (data->requires_broadcast) { + reference_ops::BroadcastAdd4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Add(op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} + +TfLiteStatus EvalAddQuantized(TfLiteContext* context, TfLiteNode* node, + TfLiteAddParams* params, const OpDataAdd* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params; + op_params.left_shift = data->left_shift; + op_params.input1_offset = data->input1_offset; + op_params.input1_multiplier = data->input1_multiplier; + op_params.input1_shift = data->input1_shift; + op_params.input2_offset = data->input2_offset; + op_params.input2_multiplier = data->input2_multiplier; + op_params.input2_shift = data->input2_shift; + op_params.output_offset = data->output_offset; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = data->output_shift; + SetActivationParams(data->output_activation_min, data->output_activation_max, + &op_params); + bool need_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + switch (output->type) { + case kTfLiteInt8: { + if (need_broadcast) { + reference_integer_ops::BroadcastAdd4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { +#if ESP_NN + const int8_t *input1_data = tflite::micro::GetTensorData(input1); + const int8_t *input2_data = tflite::micro::GetTensorData(input2); + int8_t *out_data = tflite::micro::GetTensorData(output); + + esp_nn_add_elementwise_s8(input1_data, + input2_data, + data->input1_offset, + data->input2_offset, + data->input1_multiplier, + data->input2_multiplier, + data->input1_shift, + data->input2_shift, + data->left_shift, + out_data, + data->output_offset, + data->output_multiplier, + data->output_shift, + data->output_activation_min, + data->output_activation_max, + MatchingElementsSize(tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorShape(output)) + ); +#else + reference_integer_ops::Add( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +#endif + } + break; + } + case kTfLiteInt16: { + if (need_broadcast) { + reference_ops::BroadcastAdd4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Add(op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + false); + } + break; + } + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(output->type), output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +void* AddInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataAdd)); +} + +TfLiteStatus AddEval(TfLiteContext* context, TfLiteNode* node) { + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataAdd* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kAddInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kAddInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kAddOutputTensor); + + long long start_time = esp_timer_get_time(); + + if (output->type == kTfLiteFloat32) { + EvalAdd(context, node, params, data, input1, input2, output); + } else if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + TF_LITE_ENSURE_OK(context, EvalAddQuantized(context, node, params, data, + input1, input2, output)); + } else { + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(output->type), + output->type); + return kTfLiteError; + } + add_total_time += esp_timer_get_time() - start_time; + + return kTfLiteOk; +} + +TfLiteRegistration Register_ADD() { + return tflite::micro::RegisterOp(AddInit, AddPrepare, AddEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/conv.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/conv.cc new file mode 100644 index 000000000..3782413f0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/conv.cc @@ -0,0 +1,345 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/conv.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/conv.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/conv.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +#include + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + + +long long conv_total_time = 0; + +namespace tflite { +namespace { + +struct NodeData { + OpDataConv op_data; +#if ESP_NN + int buffer_idx; +#endif +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(NodeData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + NodeData* data = static_cast(node->user_data); + const auto& params = + *(static_cast(node->builtin_data)); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kConvInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kConvWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kConvOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + const int input_width = input->dims->data[2]; + const int input_height = input->dims->data[1]; + const int filter_width = filter->dims->data[2]; + const int filter_height = filter->dims->data[1]; + const int output_width = output->dims->data[2]; + const int output_height = output->dims->data[1]; + + // Dynamically allocate per-channel quantization parameters. + const int num_channels = filter->dims->data[kConvQuantizedDimension]; + data->op_data.per_channel_output_multiplier = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + data->op_data.per_channel_output_shift = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + + // All per-channel quantized tensors need valid zero point and scale arrays. + if (input->type == kTfLiteInt8) { + TF_LITE_ENSURE_EQ(context, filter->quantization.type, + kTfLiteAffineQuantization); + + const auto* affine_quantization = + static_cast(filter->quantization.params); + TFLITE_DCHECK(affine_quantization != nullptr); + TFLITE_DCHECK(affine_quantization->scale != nullptr); + TFLITE_DCHECK(affine_quantization->zero_point != nullptr); + + TF_LITE_ENSURE(context, + affine_quantization->scale->size == 1 || + affine_quantization->scale->size == + filter->dims->data[kConvQuantizedDimension]); + TF_LITE_ENSURE_EQ(context, affine_quantization->scale->size, + affine_quantization->zero_point->size); + } + + TF_LITE_ENSURE_STATUS(CalculateOpDataConv( + context, node, params, input_width, input_height, filter_width, + filter_height, output_width, output_height, input->type, &data->op_data)); + +#if ESP_NN + if (input->type == kTfLiteInt8) { + data_dims_t input_dims = { + .width = input_width, .height = input_height, + .channels = input->dims->data[3], 1 + }; + data_dims_t output_dims = { + .width = output_width, .height = output_height, + .channels = output->dims->data[3], 1 + }; + data_dims_t filter_dims = {.width = filter_width, .height = filter_height, 0, 0}; + conv_params_t conv_params = { + .in_offset = 0, .out_offset = 0, + .stride = {params.stride_width, params.stride_height}, + .padding = {data->op_data.padding.width, data->op_data.padding.height}, + .dilation = {0, 0}, .activation = {-128, 127} + }; + + int scratch_buf_size = esp_nn_get_conv_scratch_size( + &input_dims, &filter_dims, &output_dims, &conv_params); + if (scratch_buf_size > 0) { + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, scratch_buf_size, &data->buffer_idx)); + } else { + data->buffer_idx = -1; + } + } +#endif + + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + + return kTfLiteOk; +} + +#if ESP_NN +// Fixed-point per-channel-quantization convolution Int8 function wrapper. +inline void EvalQuantizedPerChannel( + TfLiteContext* context, TfLiteNode* node, const TfLiteConvParams& params, + const NodeData& data, const TfLiteEvalTensor* input, + const TfLiteEvalTensor* filter, const TfLiteEvalTensor* bias, + TfLiteEvalTensor* output) { + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + + if (dilation_width_factor == 1 && dilation_height_factor == 1) { + // Get parameters. + RuntimeShape filter_shape = tflite::micro::GetTensorShape(filter); + RuntimeShape input_shape = tflite::micro::GetTensorShape(input); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + RuntimeShape bias_shape = tflite::micro::GetTensorShape(bias); + + const int8_t *input_data = tflite::micro::GetTensorData(input); + int8_t *output_data = tflite::micro::GetTensorData(output); + + const int32_t input_offset = -data.op_data.input_zero_point; + const int32_t output_offset = data.op_data.output_zero_point; + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = data.op_data.padding.width; + const int pad_height = data.op_data.padding.height; + + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + // Set min and max value of the output. + const int32_t activation_min = data.op_data.output_activation_min; + const int32_t activation_max = data.op_data.output_activation_max; + + // Consistency check. + TFLITE_DCHECK_LE(activation_min, activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batch_size = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = MatchingDim(input_shape, 3, filter_shape, 3); + const int output_depth = MatchingDim(filter_shape, 0, output_shape, 3); + + if (tflite::micro::GetTensorData(bias)) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + + void *scratch_buf = NULL; + if (data.buffer_idx > -1) { + scratch_buf = context->GetScratchBuffer(context, data.buffer_idx); + } + esp_nn_set_conv_scratch_buf(scratch_buf); + + const int input_size = input_width * input_height * input_depth; + const int output_size = output_width * output_height * output_depth; + + data_dims_t input_dims = { + .width = input_width, .height = input_height, + .channels = input_depth, 1 + }; + data_dims_t output_dims = { + .width = output_width, .height = output_height, + .channels = output_depth, 1 + }; + data_dims_t filter_dims = {.width = filter_width, .height = filter_height, 0, 0}; + conv_params_t conv_params = { + .in_offset = input_offset, .out_offset = output_offset, + .stride = {stride_width, stride_height}, + .padding = {pad_width, pad_height}, + .dilation = {0, 0}, + .activation = {activation_min, activation_max} + }; + quant_data_t quant_data = { + .shift = data.op_data.per_channel_output_shift, + .mult = data.op_data.per_channel_output_multiplier + }; + + for (int i_batch = 0; i_batch < batch_size; i_batch++) { + esp_nn_conv_s8(&input_dims, input_data + i_batch * input_size, + &filter_dims, tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorData(bias), + &output_dims, output_data + i_batch * output_size, + &conv_params, &quant_data); + } + } else { + reference_integer_ops::ConvPerChannel( + ConvParamsQuantized(params, data.op_data), + data.op_data.per_channel_output_multiplier, + data.op_data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} +#endif + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kConvInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kConvWeightsTensor); + const TfLiteEvalTensor* bias = + (NumInputs(node) == 3) + ? tflite::micro::GetEvalInput(context, node, kConvBiasTensor) + : nullptr; + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kConvOutputTensor); + + TFLITE_DCHECK(node->builtin_data != nullptr); + const auto& params = + *(reinterpret_cast(node->builtin_data)); + TFLITE_DCHECK(node->user_data != nullptr); + const auto& data = *(static_cast(node->user_data)); + + TF_LITE_ENSURE_EQ(context, input->type, output->type); + TF_LITE_ENSURE_MSG(context, input->type == filter->type, + "Hybrid models are not supported on TFLite Micro."); + + long long start_time = esp_timer_get_time(); + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: { + tflite::reference_ops::Conv( + ConvParamsFloat(params, data.op_data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr); + break; + } + case kTfLiteInt8: { +#if ESP_NN + EvalQuantizedPerChannel(context, node, params, data, input, filter, + bias, output); +#else + reference_integer_ops::ConvPerChannel( + ConvParamsQuantized(params, data.op_data), + data.op_data.per_channel_output_multiplier, + data.op_data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +#endif + break; + } + case kTfLiteUInt8: { + //EvalQuantized + reference_ops::Conv(ConvParamsQuantized(params, data.op_data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr, + nullptr); + break; + } + default: + TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + long long time_this_instance = esp_timer_get_time() - start_time; + conv_total_time += time_this_instance; + //printf("time this instance: %llu\n", time_this_instance / 1000); + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_CONV_2D() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/depthwise_conv.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/depthwise_conv.cc new file mode 100644 index 000000000..75bfeb638 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/depthwise_conv.cc @@ -0,0 +1,347 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/depthwise_conv.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h" +#include "tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/depthwise_conv.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +#include + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + +long long dc_total_time = 0; + +namespace tflite { +namespace { + +struct NodeData { + OpDataConv op_data; +#if ESP_NN + int buffer_idx; +#endif +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(NodeData)); +} + +#if ESP_NN +inline void EvalQuantizedPerChannel(TfLiteContext* context, TfLiteNode* node, + const TfLiteDepthwiseConvParams& params, + const NodeData& data, + const TfLiteEvalTensor* input, + const TfLiteEvalTensor* filter, + const TfLiteEvalTensor* bias, + TfLiteEvalTensor* output) { + const int dilation_width_factor = params.dilation_width_factor; + const int dilation_height_factor = params.dilation_height_factor; + + if (dilation_width_factor == 1 && dilation_height_factor == 1) { + // Get parameters. + RuntimeShape input_shape = tflite::micro::GetTensorShape(input); + RuntimeShape filter_shape = tflite::micro::GetTensorShape(filter); + RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + RuntimeShape bias_shape = tflite::micro::GetTensorShape(bias); + + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + + const int8_t *input_data = tflite::micro::GetTensorData(input); + int8_t *output_data = tflite::micro::GetTensorData(output); + + const int depth_multiplier = params.depth_multiplier; + const int32_t input_offset = -data.op_data.input_zero_point; + const int32_t output_offset = data.op_data.output_zero_point; + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = data.op_data.padding.width; + const int pad_height = data.op_data.padding.height; + + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int input_depth = input_shape.Dims(3); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + // Set min and max value of the output. + const int32_t activation_min = data.op_data.output_activation_min; + const int32_t activation_max = data.op_data.output_activation_max; + + // Consistency check. + TFLITE_DCHECK_LE(activation_min, activation_max); + const int batch_size = MatchingDim(input_shape, 0, output_shape, 0); + const int output_depth = MatchingDim(filter_shape, 3, output_shape, 3); + + TFLITE_DCHECK_EQ(output_depth, input_depth * depth_multiplier); + if (tflite::micro::GetTensorData(bias)) { + TFLITE_DCHECK_EQ(bias_shape.FlatSize(), output_depth); + } + + const int input_size = input_width * input_height * input_depth; + const int output_size = output_width * output_height * output_depth; + void *scratch_buf = NULL; + if (data.buffer_idx > -1) { + scratch_buf = context->GetScratchBuffer(context, data.buffer_idx); + } + + esp_nn_set_depthwise_conv_scratch_buf(scratch_buf); + + data_dims_t input_dims = { + .width = input_width, .height = input_height, + .channels = input_depth, 1 + }; + data_dims_t output_dims = { + .width = output_width, .height = output_height, + .channels = output_depth, 1 + }; + data_dims_t filter_dims = {.width = filter_width, .height = filter_height, 0, 0}; + dw_conv_params_t conv_params = { + .in_offset = input_offset, .out_offset = output_offset, + .ch_mult = depth_multiplier, + .stride = {stride_width, stride_height}, + .padding = {pad_width, pad_height}, .dilation = {0, 0}, + .activation = {activation_min, activation_max} + }; + quant_data_t quant_data = { + .shift = data.op_data.per_channel_output_shift, + .mult = data.op_data.per_channel_output_multiplier + }; + + for (int i_batch = 0; i_batch < batch_size; i_batch++) { + esp_nn_depthwise_conv_s8(&input_dims, input_data + i_batch * input_size, + &filter_dims, tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorData(bias), + &output_dims, output_data + i_batch * output_size, + &conv_params, &quant_data); + } + } else { + reference_integer_ops::DepthwiseConvPerChannel( + DepthwiseConvParamsQuantized(params, data.op_data), + data.op_data.per_channel_output_multiplier, + data.op_data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} +#endif + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + NodeData* data = static_cast(node->user_data); + const TfLiteDepthwiseConvParams& params = + *(static_cast(node->builtin_data)); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kConvInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kConvWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kConvBiasTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kConvOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + const int input_width = input->dims->data[2]; + const int input_height = input->dims->data[1]; + const int filter_width = filter->dims->data[2]; + const int filter_height = filter->dims->data[1]; + const int output_width = output->dims->data[2]; + const int output_height = output->dims->data[1]; + + // Dynamically allocate per-channel quantization parameters. + const int num_channels = filter->dims->data[kDepthwiseConvQuantizedDimension]; + data->op_data.per_channel_output_multiplier = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + data->op_data.per_channel_output_shift = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + + // All per-channel quantized tensors need valid zero point and scale arrays. + if (input->type == kTfLiteInt8) { + TF_LITE_ENSURE_EQ(context, filter->quantization.type, + kTfLiteAffineQuantization); + + const auto* affine_quantization = + static_cast(filter->quantization.params); + TFLITE_DCHECK(affine_quantization != nullptr); + TFLITE_DCHECK(affine_quantization->scale != nullptr); + TFLITE_DCHECK(affine_quantization->zero_point != nullptr); + + TF_LITE_ENSURE( + context, affine_quantization->scale->size == 1 || + affine_quantization->scale->size == + filter->dims->data[kDepthwiseConvQuantizedDimension]); + + TF_LITE_ENSURE_EQ(context, affine_quantization->scale->size, + affine_quantization->zero_point->size); + } + + TF_LITE_ENSURE_STATUS(CalculateOpDataDepthwiseConv( + context, node, params, input_width, input_height, filter_width, + filter_height, output_width, output_height, input->type, &data->op_data)); + +#if ESP_NN + if (input->type == kTfLiteInt8) { + data_dims_t input_dims = { + .width = input_width, .height = input_height, + .channels = input->dims->data[3], 1 + }; + data_dims_t output_dims = { + .width = output_width, .height = output_height, + .channels = output->dims->data[3], 1 + }; + data_dims_t filter_dims = {.width = filter_width, .height = filter_height, 0, 0}; + dw_conv_params_t conv_params = { + .in_offset = 0, .out_offset = 0, + .ch_mult = params.depth_multiplier, + .stride = {params.stride_width, params.stride_height}, + .padding = {data->op_data.padding.width, data->op_data.padding.height}, + .dilation = {0, 0}, .activation = {-128, 127} + }; + + int scratch_buf_size = esp_nn_get_depthwise_conv_scratch_size( + &input_dims, &filter_dims, &output_dims, &conv_params); + if (scratch_buf_size > 0) { + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, scratch_buf_size, &data->buffer_idx)); + } else { + data->buffer_idx = -1; + } + } +#endif + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + micro_context->DeallocateTempTfLiteTensor(bias); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + auto& params = + *(reinterpret_cast(node->builtin_data)); + const NodeData& data = *(static_cast(node->user_data)); + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kDepthwiseConvOutputTensor); + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kDepthwiseConvInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kDepthwiseConvWeightsTensor); + const TfLiteEvalTensor* bias = + (NumInputs(node) == 3) + ? tflite::micro::GetEvalInput(context, node, kDepthwiseConvBiasTensor) + : nullptr; + + long long start_time = esp_timer_get_time(); + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + tflite::reference_ops::DepthwiseConv( + DepthwiseConvParamsFloat(params, data.op_data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: +#if ESP_NN + EvalQuantizedPerChannel(context, node, params, data, input, filter, bias, + output); +#else + reference_integer_ops::DepthwiseConvPerChannel( + DepthwiseConvParamsQuantized(params, data.op_data), + data.op_data.per_channel_output_multiplier, + data.op_data.per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +#endif + break; + case kTfLiteUInt8: + //EvalQuantized(context, node, params, &data, input, filter, bias, output); + reference_ops::DepthwiseConv( + DepthwiseConvParamsQuantized(params, data.op_data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + long long time_this_instance = esp_timer_get_time() - start_time; + dc_total_time += time_this_instance; + // printf("time this instance: %llu\n", time_this_instance / 1000); + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_DEPTHWISE_CONV_2D() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/fully_connected.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/fully_connected.cc new file mode 100644 index 000000000..bc102e7c7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/fully_connected.cc @@ -0,0 +1,193 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/fully_connected.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/fully_connected.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/fully_connected.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + +#include + +long long fc_total_time = 0; + +namespace tflite { +namespace { + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, + sizeof(OpDataFullyConnected)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + auto* data = static_cast(node->user_data); + const auto params = + static_cast(node->builtin_data); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kFullyConnectedInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = micro_context->AllocateTempInputTensor( + node, kFullyConnectedWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kFullyConnectedBiasTensor); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor( + node, kFullyConnectedOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + TF_LITE_ENSURE_MSG(context, input->type == filter->type, + "Hybrid models are not supported on TFLite Micro."); + + TF_LITE_ENSURE_OK(context, CalculateOpDataFullyConnected( + context, params->activation, input->type, + input, filter, bias, output, data)); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + if (bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(bias); + } + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + const auto* params = + static_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kFullyConnectedInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kFullyConnectedWeightsTensor); + const TfLiteEvalTensor* bias = + tflite::micro::GetEvalInput(context, node, kFullyConnectedBiasTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kFullyConnectedOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + const auto& data = + *(static_cast(node->user_data)); + + long long start_time = esp_timer_get_time(); + // Checks in Prepare ensure input, output and filter types are all the same. + switch (input->type) { + case kTfLiteFloat32: { + tflite::reference_ops::FullyConnected( + FullyConnectedParamsFloat(params->activation), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + + case kTfLiteInt8: { + const int32_t* bias_data = + nullptr != bias ? tflite::micro::GetTensorData(bias) + : nullptr; +#if ESP_NN + const RuntimeShape& filter_shape = tflite::micro::GetTensorShape(filter); + const RuntimeShape& output_shape = tflite::micro::GetTensorShape(output); + const int filter_dim_count = filter_shape.DimensionsCount(); + const int batches = output_shape.Dims(0); + const int output_depth = output_shape.Dims(1); + TFLITE_DCHECK_LE(output_depth, filter_shape.Dims(filter_dim_count - 2)); + const int accum_depth = filter_shape.Dims(filter_dim_count - 1); + + const int8_t *input_data = tflite::micro::GetTensorData(input); + int8_t *output_data = tflite::micro::GetTensorData(output); + const int8_t *filter_data = tflite::micro::GetTensorData(filter); + + for (int b = 0; b < batches; ++b) { + esp_nn_fully_connected_s8(input_data, -data.input_zero_point, + accum_depth, + filter_data, -data.filter_zero_point, + bias_data, output_data, output_depth, + data.output_zero_point, + data.output_shift, data.output_multiplier, + data.output_activation_min, + data.output_activation_max); + input_data += accum_depth; + output_data += output_depth; + } +#else + tflite::reference_integer_ops::FullyConnected( + FullyConnectedParamsQuantized(data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), bias_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +#endif + break; + } + + case kTfLiteUInt8: { + tflite::reference_ops::FullyConnected( + FullyConnectedParamsQuantized(data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + default: { + TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + } + fc_total_time += esp_timer_get_time() - start_time; + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_FULLY_CONNECTED() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/mul.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/mul.cc new file mode 100644 index 000000000..65618ed59 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/mul.cc @@ -0,0 +1,125 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/mul.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/mul.h" +#include "tensorflow/lite/kernels/internal/reference/mul.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + +#include + +long long mul_total_time = 0; + +namespace tflite { +#if ESP_NN +void MulEvalQuantized(TfLiteContext* context, TfLiteNode* node, + const OpDataMul* data, const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params = {}; + op_params.quantized_activation_min = data->output_activation_min; + op_params.quantized_activation_max = data->output_activation_max; + op_params.float_activation_max = data->output_activation_max_f32; + op_params.input1_offset = -data->input1_zero_point; + op_params.input2_offset = -data->input2_zero_point; + op_params.output_offset = data->output_zero_point; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = data->output_shift; + + bool need_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + if (need_broadcast) { + reference_integer_ops::BroadcastMul4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + const int8_t *input1_data = tflite::micro::GetTensorData(input1); + const int8_t *input2_data = tflite::micro::GetTensorData(input2); + int8_t *out_data = tflite::micro::GetTensorData(output); + + esp_nn_mul_elementwise_s8(input1_data, input2_data, op_params.input1_offset, + op_params.input2_offset, out_data, op_params.output_offset, + op_params.output_multiplier, op_params.output_shift, + op_params.quantized_activation_min, op_params.quantized_activation_max, + MatchingElementsSize(tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorShape(output))); + } +} +#endif + +TfLiteStatus MulEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataMul* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kMulInput1Tensor); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kMulInput2Tensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kMulOutputTensor); + + long long start_time = esp_timer_get_time(); + switch (input1->type) { + case kTfLiteInt8: +#if ESP_NN + MulEvalQuantized(context, node, data, input1, input2, output); +#else + EvalMulQuantizedReference(context, node, data, input1, input2, output); +#endif + break; + case kTfLiteInt32: + EvalMulQuantizedReference(context, node, data, input1, input2, output); + break; + case kTfLiteFloat32: + EvalMulFloatReference(context, node, params, data, input1, input2, + output); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + mul_total_time += esp_timer_get_time() - start_time; + return kTfLiteOk; +} + +TfLiteRegistration Register_MUL() { + return tflite::micro::RegisterOp(MulInit, MulPrepare, MulEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/pooling.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/pooling.cc new file mode 100644 index 000000000..f7214665d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/pooling.cc @@ -0,0 +1,233 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/pooling.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/pooling.h" +#include "tensorflow/lite/micro/micro_log.h" + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + +#include + +long long pooling_total_time = 0; + +namespace tflite { + +namespace { +#if ESP_NN +void AverageEvalQuantized(TfLiteContext* context, const TfLiteNode* node, + const TfLitePoolParams* params, const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + + const int stride_height = params->stride_height; + const int stride_width = params->stride_width; + const int filter_height = params->filter_height; + const int filter_width = params->filter_width; + const int activation_min = data->activation_min; + const int activation_max = data->activation_max; + const int pad_height = data->padding.height; + const int pad_width = data->padding.width; + + const RuntimeShape& input_shape = tflite::micro::GetTensorShape(input); + const RuntimeShape& output_shape = tflite::micro::GetTensorShape(output); + TFLITE_DCHECK_LE(activation_min, activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + const int8_t *input_data = tflite::micro::GetTensorData(input); + int8_t *output_data = tflite::micro::GetTensorData(output); + + const int input_size = input_width * input_height * depth; + const int output_size = output_width * output_height * depth; + + if (depth % 4 == 0) { // S3 version only supports channels multiple of 4 + for (int batch = 0; batch < batches; ++batch) { + esp_nn_avg_pool_s8(input_data, input_width, input_height, + output_data, output_width, output_height, + stride_width, stride_height, + filter_width, filter_height, + pad_width, pad_height, + activation_min, activation_max, depth); + input_data += input_size; + output_data += output_size; + } + } else { + for (int batch = 0; batch < batches; ++batch) { + esp_nn_avg_pool_s8_ansi(input_data, input_width, input_height, + output_data, output_width, output_height, + stride_width, stride_height, + filter_width, filter_height, + pad_width, pad_height, + activation_min, activation_max, depth); + input_data += input_size; + output_data += output_size; + } + } +} + +void MaxEvalQuantized(TfLiteContext* context, TfLiteNode* node, + TfLitePoolParams* params, const OpDataPooling* data, + const TfLiteEvalTensor* input, TfLiteEvalTensor* output) { + + const int stride_height = params->stride_height; + const int stride_width = params->stride_width; + const int filter_height = params->filter_height; + const int filter_width = params->filter_width; + const int activation_min = data->activation_min; + const int activation_max = data->activation_max; + const int pad_height = data->padding.height; + const int pad_width = data->padding.width; + + const RuntimeShape& input_shape = tflite::micro::GetTensorShape(input); + const RuntimeShape& output_shape = tflite::micro::GetTensorShape(output); + TFLITE_DCHECK_LE(activation_min, activation_max); + TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); + TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); + const int batches = MatchingDim(input_shape, 0, output_shape, 0); + const int depth = MatchingDim(input_shape, 3, output_shape, 3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + + const int8_t *input_data = tflite::micro::GetTensorData(input); + int8_t *output_data = tflite::micro::GetTensorData(output); + + const int input_size = input_width * input_height * depth; + const int output_size = output_width * output_height * depth; + if (depth % 4 == 0) { // S3 version only supports channels multiple of 4 + for (int batch = 0; batch < batches; ++batch) { + esp_nn_max_pool_s8(input_data, input_width, input_height, + output_data, output_width, output_height, + stride_width, stride_height, + filter_width, filter_height, + pad_width, pad_height, + activation_min, activation_max, depth); + input_data += input_size; + output_data += output_size; + } + } else { + for (int batch = 0; batch < batches; ++batch) { + esp_nn_max_pool_s8_ansi(input_data, input_width, input_height, + output_data, output_width, output_height, + stride_width, stride_height, + filter_width, filter_height, + pad_width, pad_height, + activation_min, activation_max, depth); + input_data += input_size; + output_data += output_size; + } + } +} +#endif + +TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataPooling* data = + static_cast(node->user_data); + + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kPoolingInputTensor); + TfLiteEvalTensor* output = + micro::GetEvalOutput(context, node, kPoolingOutputTensor); + + long long start_time = esp_timer_get_time(); + // Inputs and outputs share the same type, guaranteed by the converter. + switch (input->type) { + case kTfLiteFloat32: + AveragePoolingEvalFloat(context, node, params, data, input, output); + break; + case kTfLiteInt8: +#if ESP_NN + AverageEvalQuantized(context, node, params, data, input, output); +#else + AveragePoolingEvalQuantized(context, node, params, data, input, output); +#endif + break; + default: + TF_LITE_KERNEL_LOG(context, "Input type %s is not currently supported", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + pooling_total_time += esp_timer_get_time() - start_time; + return kTfLiteOk; +} + +TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataPooling* data = + static_cast(node->user_data); + + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kPoolingInputTensor); + TfLiteEvalTensor* output = + micro::GetEvalOutput(context, node, kPoolingOutputTensor); + + long long start_time = esp_timer_get_time(); + switch (input->type) { + case kTfLiteFloat32: + MaxPoolingEvalFloat(context, node, params, data, input, output); + break; + case kTfLiteInt8: +#if ESP_NN + MaxEvalQuantized(context, node, params, data, input, output); +#else + MaxPoolingEvalQuantized(context, node, params, data, input, output); +#endif + break; + default: + TF_LITE_KERNEL_LOG(context, "Type %s not currently supported.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + pooling_total_time += esp_timer_get_time() - start_time; + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataPooling)); +} + +} // namespace + +TfLiteRegistration Register_AVERAGE_POOL_2D() { + return tflite::micro::RegisterOp(Init, PoolingPrepare, AverageEval); +} + +TfLiteRegistration Register_MAX_POOL_2D() { + return tflite::micro::RegisterOp(Init, PoolingPrepare, MaxEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/softmax.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/softmax.cc new file mode 100644 index 000000000..5748435b6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/esp_nn/softmax.cc @@ -0,0 +1,209 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/softmax.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/softmax.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +#include + +#if ESP_NN +// #include +#include "esp-nn/include/esp_nn.h" +#endif + +long long softmax_total_time = 0; + +namespace tflite { +namespace { +// Softmax parameter data that persists in user_data +const int kInt16LUTArraySize = 513; + +struct NodeData { + SoftmaxParams op_data; +#if ESP_NN + int buffer_idx; +#endif +}; + +static void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(NodeData)); +} + +void SoftmaxQuantized(TfLiteContext* context, const TfLiteEvalTensor* input, + TfLiteEvalTensor* output, const NodeData* data) { + if (input->type == kTfLiteInt8) { + if (output->type == kTfLiteInt16) { + tflite::reference_ops::Softmax( + data->op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { +#if ESP_NN + const int32_t input_beta_multiplier = data->op_data.input_multiplier; + const int32_t input_beta_left_shift = data->op_data.input_left_shift; + const int diff_min = data->op_data.diff_min; + const RuntimeShape input_shape = tflite::micro::GetTensorShape(input); + const RuntimeShape output_shape = tflite::micro::GetTensorShape(output); + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + const int8_t *in_ptr = tflite::micro::GetTensorData(input); + int8_t *out_ptr = tflite::micro::GetTensorData(output); + void *scratch_buf = NULL; + if (data->buffer_idx > -1) { + scratch_buf = context->GetScratchBuffer(context, data->buffer_idx); + } + esp_nn_set_softmax_scratch_buf(scratch_buf); + esp_nn_softmax_s8(in_ptr, outer_size, depth, input_beta_multiplier, + input_beta_left_shift, diff_min, out_ptr); +#else + tflite::reference_ops::Softmax( + data->op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +#endif + } + } else { + tflite::reference_ops::SoftmaxInt16( + data->op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} + +static TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + + TFLITE_DCHECK(node->user_data != nullptr); + NodeData data = *static_cast(node->user_data); + + long long start_time = esp_timer_get_time(); + switch (input->type) { + case kTfLiteFloat32: { + tflite::reference_ops::Softmax( + data.op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + break; + case kTfLiteInt8: + case kTfLiteInt16: { + SoftmaxQuantized(context, input, output, &data); + } + break; + default: + TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + softmax_total_time += esp_timer_get_time() - start_time; + return kTfLiteOk; +} + +static TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input != nullptr); + TF_LITE_ENSURE(context, NumDimensions(input) >= 1); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE(context, node->user_data != nullptr); + NodeData* data = static_cast(node->user_data); + // Only allocate LUTs for KTfLiteInt16 data type + if (input->type == kTfLiteInt16) { + void* raw_exp_lut = context->AllocatePersistentBuffer( + context, sizeof(int16_t) * kInt16LUTArraySize); + TF_LITE_ENSURE(context, raw_exp_lut != nullptr); + data->op_data.exp_lut = reinterpret_cast(raw_exp_lut); + void* one_over_one_plus_x_lut = context->AllocatePersistentBuffer( + context, sizeof(int16_t) * kInt16LUTArraySize); + TF_LITE_ENSURE(context, one_over_one_plus_x_lut != nullptr); + data->op_data.one_over_one_plus_x_lut = + reinterpret_cast(one_over_one_plus_x_lut); + } + + if (output->type == kTfLiteInt16) { + TF_LITE_ENSURE(context, + input->type == kTfLiteInt8 || input->type == kTfLiteInt16); + } else { + TF_LITE_ENSURE_EQ(context, input->type, output->type); + } + + // Populate LUT if required + if (input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0); + // exp LUT only used on negative values + // we consider exp(-10.0) is insignificant to accumulation + gen_lut( + [](float value) { return std::exp(value); }, -10.0f, 0.0f, -1.0f, 1.0f, + data->op_data.exp_lut); + gen_lut( + [](float value) { return 1.0f / (1.0f + value); }, 0.0f, 1.0f, -1.0f, + 1.0f, data->op_data.one_over_one_plus_x_lut); + data->op_data.zero_point = output->params.zero_point; + data->op_data.scale = output->params.scale; + } + + auto* params = static_cast(node->builtin_data); + auto ret_val = + CalculateSoftmaxParams(context, input, output, params, &data->op_data); + +#if ESP_NN + if (output->type == kTfLiteInt8 && input->type == kTfLiteInt8) { + const int32_t input_width = input->dims->data[1]; + const int32_t input_height = input->dims->data[2]; + int scratch_buf_size = esp_nn_get_softmax_scratch_size(input_width, + input_height); + if (scratch_buf_size > 0) { + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, scratch_buf_size, &data->buffer_idx)); + } + } +#endif + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return ret_val; +} + +} // namespace + +TfLiteRegistration Register_SOFTMAX() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ethosu.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ethosu.cc new file mode 100644 index 000000000..c305121e8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ethosu.cc @@ -0,0 +1,27 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 is a stub file for non-Ethos platforms +// +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +TfLiteRegistration* Register_ETHOSU() { return nullptr; } + +const char* GetString_ETHOSU() { return ""; } + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ethosu.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ethosu.h new file mode 100644 index 000000000..cfbb0d3f7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/ethosu.h @@ -0,0 +1,28 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_ETHOSU_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_ETHOSU_H_ + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +TfLiteRegistration* Register_ETHOSU(); + +const char* GetString_ETHOSU(); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_ETHOSU_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/exp.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/exp.cc new file mode 100644 index 000000000..a835ee0af --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/exp.cc @@ -0,0 +1,79 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/exp.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteFloat32); + TF_LITE_ENSURE_TYPES_EQ(context, output->type, input->type); + TF_LITE_ENSURE_EQ(context, output->bytes, input->bytes); + TF_LITE_ENSURE_EQ(context, output->dims->size, input->dims->size); + for (int i = 0; i < output->dims->size; ++i) { + TF_LITE_ENSURE_EQ(context, output->dims->data[i], input->dims->data[i]); + } + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + int flat_size = MatchingFlatSize(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output)); + + if (input->type == kTfLiteFloat32) { + reference_ops::Exp(tflite::micro::GetTensorData(input), + static_cast(flat_size), + tflite::micro::GetTensorData(output)); + } else { + MicroPrintf("Type %s (%d) currently not supported by Exp.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_EXP() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/expand_dims.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/expand_dims.cc new file mode 100644 index 000000000..ad45dd882 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/expand_dims.cc @@ -0,0 +1,149 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kAxisTensor = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus GetAxisValueFromTensor(TfLiteContext* context, + const TfLiteTensor* axis, + int32_t* axis_value) { + const int axis_dims = (tflite::GetTensorShape(axis)).DimensionsCount(); + if (axis_dims > 1) { + MicroPrintf("Axis has only one element for Expand_Dims.", axis_dims); + return kTfLiteError; + } + + if (kTfLiteInt32 == (axis->type)) { + const int32_t* axis_ptr = tflite::GetTensorData(axis); + *axis_value = axis_ptr[0]; + return kTfLiteOk; + } else { + MicroPrintf("Axis type %s (%d) not supported by Expand_Dims.", + TfLiteTypeGetName(axis->type), axis->type); + return kTfLiteError; + } +} + +// Verifies that the output tensor's dimension shape is equivalent to inserting +// a dimension of length 1 at the dimension index axis of input's shape as +// defined in https://www.tensorflow.org/api_docs/python/tf/expand_dims. +TfLiteStatus VerifyTensorDim(TfLiteContext* context, const TfLiteTensor* input, + const TfLiteTensor* axis_tensor, + const TfLiteTensor* output) { + int32_t axis_value = 0; + TF_LITE_ENSURE_OK(context, + GetAxisValueFromTensor(context, axis_tensor, &axis_value)); + + tflite::RuntimeShape input_shape = tflite::GetTensorShape(input); + if (axis_value < 0) { + axis_value = input_shape.DimensionsCount() + 1 + axis_value; + } + TF_LITE_ENSURE(context, axis_value <= input_shape.DimensionsCount()); + + // TFLM only supports fixed dimension tensor and assumes that the output shape + // is fully specified in the model. As such, TFLM directly use the pointer to + // the dimension array in the model buffer. + tflite::RuntimeShape output_shape = tflite::GetTensorShape(output); + + TF_LITE_ENSURE(context, output_shape.DimensionsCount() == + input_shape.DimensionsCount() + 1); + for (int i = 0; i < output_shape.DimensionsCount(); ++i) { + if (i < axis_value) { + TF_LITE_ENSURE(context, output_shape.Dims(i) == input_shape.Dims(i)); + } else if (i == axis_value) { + TF_LITE_ENSURE(context, output_shape.Dims(i) == 1); + } else { + TF_LITE_ENSURE(context, output_shape.Dims(i) == input_shape.Dims(i - 1)); + } + } + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* axis = + micro_context->AllocateTempInputTensor(node, kAxisTensor); + TF_LITE_ENSURE(context, axis != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + output->type = input->type; + if (IsDynamicTensor(axis)) { + MicroPrintf("DynamicTensor is not yet supported by Expand_Dims."); + return kTfLiteError; + } + TF_LITE_ENSURE_OK(context, VerifyTensorDim(context, input, axis, output)); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(axis); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +template +void memCopyN(T* out, const T* in, const int num_elements) { + for (int i = 0; i < num_elements; ++i) { + out[i] = in[i]; + } +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + const int flat_size = ElementCount(*input->dims); + + switch (input->type) { + case kTfLiteFloat32: { + memCopyN(tflite::micro::GetTensorData(output), + tflite::micro::GetTensorData(input), flat_size); + } break; + case kTfLiteInt8: { + memCopyN(tflite::micro::GetTensorData(output), + tflite::micro::GetTensorData(input), flat_size); + } break; + default: + MicroPrintf( + "Expand_Dims only currently supports int8 and float32, got %d.", + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_EXPAND_DIMS() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fill.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fill.cc new file mode 100644 index 000000000..6a3f4998e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fill.cc @@ -0,0 +1,140 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/fill.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +namespace { + +template +TfLiteStatus EnsureEqImpl(TfLiteContext* context, const TfLiteIntArray* array, + const TfLiteTensor* tensor) { + for (int i = 0; i < array->size; ++i) { + TF_LITE_ENSURE_EQ(context, array->data[i], GetTensorData(tensor)[i]); + } + return kTfLiteOk; +} + +// Ensure the equality of an int array and a tensor, which must be +// one-dimensional and of an integer type. +TfLiteStatus EnsureEq(TfLiteContext* context, const TfLiteIntArray* array, + const TfLiteTensor* tensor) { + TF_LITE_ENSURE_EQ(context, NumDimensions(tensor), 1); + const auto tensor_len = tensor->dims->data[0]; + TF_LITE_ENSURE_EQ(context, array->size, tensor_len); + + switch (tensor->type) { + case kTfLiteInt8: + return EnsureEqImpl(context, array, tensor); + case kTfLiteInt16: + return EnsureEqImpl(context, array, tensor); + case kTfLiteInt32: + return EnsureEqImpl(context, array, tensor); + case kTfLiteInt64: + return EnsureEqImpl(context, array, tensor); + default: + MicroPrintf("cannot compare int array to tensor of type %d.", + tensor->type); + return kTfLiteError; + } +} + +constexpr int kDimsTensor = 0; +constexpr int kValueTensor = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + // Ensure inputs and outputs exist. + TfLiteTensor* dims = + micro_context->AllocateTempInputTensor(node, kDimsTensor); + TF_LITE_ENSURE(context, dims != nullptr); + TfLiteTensor* value = + micro_context->AllocateTempInputTensor(node, kValueTensor); + TF_LITE_ENSURE(context, value != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + // The value tensor must be a scalar. + TF_LITE_ENSURE_EQ(context, NumDimensions(value), 0); + + // The value type and output type must match. + TF_LITE_ENSURE_EQ(context, value->type, output->type); + + // The dimension of the output tensor is known in model already. + TFLITE_DCHECK(output->dims != nullptr); + + if (dims->data.data != nullptr) { + // When the dims tensor is specified in model already (i.e. is not an + // activation tensor), the dims tensor must match the output tensor shape. + // As a byproduct, ensures the dims tensor is of an integer type. + TF_LITE_ENSURE_OK(context, EnsureEq(context, output->dims, dims)); + } + + micro_context->DeallocateTempTfLiteTensor(dims); + micro_context->DeallocateTempTfLiteTensor(value); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +template +void FillImpl(const TfLiteEvalTensor* value, TfLiteEvalTensor* output) { + reference_ops::Fill( + micro::GetTensorShape(value), micro::GetTensorData(value), + micro::GetTensorShape(output), micro::GetTensorData(output)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* value = + micro::GetEvalInput(context, node, kValueTensor); + TfLiteEvalTensor* output = micro::GetEvalOutput(context, node, kOutputTensor); + + switch (value->type) { + case kTfLiteFloat32: + FillImpl(value, output); + break; + case kTfLiteInt32: + FillImpl(value, output); + break; + case kTfLiteInt8: + FillImpl(value, output); + break; + default: + MicroPrintf("Fill only currently supports float32 for input 1, got %d.", + TfLiteTypeGetName(value->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_FILL() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor.cc new file mode 100644 index 000000000..6b2a4cc25 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor.cc @@ -0,0 +1,50 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/floor.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace floor { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteFloat32); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + reference_ops::Floor(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; +} +} // namespace floor + +TfLiteRegistration Register_FLOOR() { + return tflite::micro::RegisterOp(nullptr, nullptr, floor::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor_div.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor_div.cc new file mode 100644 index 000000000..f143d28af --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor_div.cc @@ -0,0 +1,130 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/floor_div.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/reference/binary_function.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +// Input/output tensor index. +constexpr int kInputTensor1 = 0; +constexpr int kInputTensor2 = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, input2->type); + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, output->type); + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + return nullptr; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +template +TfLiteStatus EvalFloorDiv(TfLiteContext* context, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + const T* denominator_data = tflite::micro::GetTensorData(input2); + + // Validate the denominator. + for (int i = 0; i < tflite::ElementCount(*input2->dims); ++i) { + if (std::equal_to()(denominator_data[i], 0)) { + MicroPrintf("Division by 0"); + return kTfLiteError; + } + } + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + + if (requires_broadcast) { + reference_ops::BroadcastBinaryFunction4DSlow( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), denominator_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), reference_ops::FloorDiv); + } else { + reference_ops::BinaryFunction( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), denominator_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), reference_ops::FloorDiv); + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + switch (input1->type) { + case kTfLiteFloat32: { + return EvalFloorDiv(context, input1, input2, output); + } + default: { + MicroPrintf("Type '%s' is not supported by FLOOR_DIV.", + TfLiteTypeGetName(input1->type)); + return kTfLiteError; + } + } +} + +} // namespace + +TfLiteRegistration Register_FLOOR_DIV() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor_mod.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor_mod.cc new file mode 100644 index 000000000..939a4dd78 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/floor_mod.cc @@ -0,0 +1,128 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/floor_mod.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/reference/binary_function.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +// OLD-TODO(b/117523611): We should factor out a binary_op and put binary ops +// there. +namespace tflite { +namespace { + +// Input/output tensor index. +constexpr int kInputTensor1 = 0; +constexpr int kInputTensor2 = 1; +constexpr int kOutputTensor = 0; + +// OLD-TODO(b/117912880): Support quantization. + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, input2->type); + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, output->type); + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + return nullptr; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +template +TfLiteStatus EvalFloorMod(TfLiteContext* context, bool requires_broadcast, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + const T* denominator_data = tflite::micro::GetTensorData(input2); + + if (requires_broadcast) { + reference_ops::BroadcastBinaryFunction4DSlow( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), denominator_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), reference_ops::FloorMod); + } else { + reference_ops::BinaryFunction( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), denominator_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), reference_ops::FloorMod); + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + bool requires_broadcast = !tflite::micro::HaveSameShapes(input1, input2); + + switch (input1->type) { + case kTfLiteFloat32: { + return EvalFloorMod(context, requires_broadcast, input1, input2, + output); + } + default: { + MicroPrintf("Type '%s' is not supported by FLOOR_MOD.", + TfLiteTypeGetName(input1->type)); + return kTfLiteError; + } + } +} + +} // namespace + +TfLiteRegistration Register_FLOOR_MOD() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected.cc new file mode 100644 index 000000000..6b73f4857 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected.cc @@ -0,0 +1,159 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/fully_connected.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/fully_connected.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/fully_connected.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, + sizeof(OpDataFullyConnected)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + auto* data = static_cast(node->user_data); + const auto params = + static_cast(node->builtin_data); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kFullyConnectedInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = micro_context->AllocateTempInputTensor( + node, kFullyConnectedWeightsTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kFullyConnectedBiasTensor); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor( + node, kFullyConnectedOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + TF_LITE_ENSURE_OK(context, CalculateOpDataFullyConnected( + context, params->activation, input->type, + input, filter, bias, output, data)); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + if (bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(bias); + } + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + const auto* params = + static_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kFullyConnectedInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kFullyConnectedWeightsTensor); + const TfLiteEvalTensor* bias = + tflite::micro::GetEvalInput(context, node, kFullyConnectedBiasTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kFullyConnectedOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + const auto& data = + *(static_cast(node->user_data)); + + // Checks in Prepare ensure input, output and filter types are all the same. + switch (input->type) { + case kTfLiteFloat32: { + const float* bias_data = + nullptr != bias ? tflite::micro::GetTensorData(bias) : nullptr; + + tflite::reference_ops::FullyConnected( + FullyConnectedParamsFloat(params->activation), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), bias_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + + case kTfLiteInt8: { + const int32_t* bias_data = + nullptr != bias ? tflite::micro::GetTensorData(bias) + : nullptr; + + tflite::reference_integer_ops::FullyConnected( + FullyConnectedParamsQuantized(data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), bias_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + + case kTfLiteInt16: { + const int64_t* bias_data = + nullptr != bias ? tflite::micro::GetTensorData(bias) + : nullptr; + + tflite::reference_integer_ops::FullyConnected( + FullyConnectedParamsQuantized(data), + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), bias_data, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + } + + default: { + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_FULLY_CONNECTED() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected.h new file mode 100644 index 000000000..93026cd59 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected.h @@ -0,0 +1,104 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_FULLY_CONNECTED_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_FULLY_CONNECTED_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +struct OpDataFullyConnected { + // The scaling factor from input to output (aka the 'real multiplier') can + // be represented as a fixed point multiplier plus a left shift. + int32_t output_multiplier; + int output_shift; + // The range of the fused activation layer. For example for kNone and + // uint8_t these would be 0 and 255. + int32_t output_activation_min; + int32_t output_activation_max; + // The index of the temporary tensor where the quantized inputs are cached. + int input_quantized_index; + // Cached zero point values of tensors. + int32_t input_zero_point; + int32_t filter_zero_point; + int32_t output_zero_point; +}; + +extern const int kFullyConnectedInputTensor; +extern const int kFullyConnectedWeightsTensor; +extern const int kFullyConnectedBiasTensor; +extern const int kFullyConnectedOutputTensor; + +// Returns a FullyConnectedParams struct with all the parameters needed for a +// float computation. +FullyConnectedParams FullyConnectedParamsFloat( + TfLiteFusedActivation activation); + +// Returns a FullyConnectedParams struct with all the parameters needed for a +// quantized computation. +FullyConnectedParams FullyConnectedParamsQuantized( + const OpDataFullyConnected& op_data); + +TfLiteStatus CalculateOpDataFullyConnected( + TfLiteContext* context, TfLiteFusedActivation activation, + TfLiteType data_type, const TfLiteTensor* input, const TfLiteTensor* filter, + const TfLiteTensor* bias, TfLiteTensor* output, OpDataFullyConnected* data); + +// This is the most generic TfLiteRegistration. The actual supported types may +// still be target dependent. The only requirement is that every implementation +// (reference or optimized) must define this function. +TfLiteRegistration Register_FULLY_CONNECTED(); + +#if defined(CMSIS_NN) || defined(HEXAGON) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int8. +TfLiteRegistration Register_FULLY_CONNECTED_INT8(); + +#else +// Note that while this block gets used for both reference and optimized kernels +// that do not have any specialized implementations, the only goal here is to +// define fallback implementation that allow reference kernels to still be used +// from applications that call a more specific kernel variant. + +inline TfLiteRegistration Register_FULLY_CONNECTED_INT8() { + return Register_FULLY_CONNECTED(); +} + +#endif + +#if defined(CMSIS_NN) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int16. +TfLiteRegistration Register_FULLY_CONNECTED_INT16(); + +#else +// Note that while this block gets used for both reference and optimized kernels +// that do not have any specialized implementations, the only goal here is to +// define fallback implementation that allow reference kernels to still be used +// from applications that call a more specific kernel variant. + +inline TfLiteRegistration Register_FULLY_CONNECTED_INT16() { + return Register_FULLY_CONNECTED(); +} + +#endif + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_FULLY_CONNECTED_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected_common.cc new file mode 100644 index 000000000..e7d0056c3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/fully_connected_common.cc @@ -0,0 +1,83 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/fully_connected.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/fully_connected.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/fully_connected.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { + +const int kFullyConnectedInputTensor = 0; +const int kFullyConnectedWeightsTensor = 1; +const int kFullyConnectedBiasTensor = 2; +const int kFullyConnectedOutputTensor = 0; + +FullyConnectedParams FullyConnectedParamsQuantized( + const OpDataFullyConnected& op_data) { + FullyConnectedParams op_params; + op_params.input_offset = -op_data.input_zero_point; + op_params.weights_offset = -op_data.filter_zero_point; + op_params.output_offset = op_data.output_zero_point; + op_params.output_multiplier = op_data.output_multiplier; + op_params.output_shift = op_data.output_shift; + op_params.quantized_activation_min = op_data.output_activation_min; + op_params.quantized_activation_max = op_data.output_activation_max; + return op_params; +} + +FullyConnectedParams FullyConnectedParamsFloat( + TfLiteFusedActivation activation) { + FullyConnectedParams op_params; + CalculateActivationRange(activation, &op_params.float_activation_min, + &op_params.float_activation_max); + return op_params; +} + +TfLiteStatus CalculateOpDataFullyConnected( + TfLiteContext* context, TfLiteFusedActivation activation, + TfLiteType data_type, const TfLiteTensor* input, const TfLiteTensor* filter, + const TfLiteTensor* bias, TfLiteTensor* output, + OpDataFullyConnected* data) { + if (data_type != kTfLiteFloat32) { + double real_multiplier = 0.0; + TF_LITE_ENSURE_STATUS(GetQuantizedConvolutionMultipler( + context, input, filter, bias, output, &real_multiplier)); + QuantizeMultiplier(real_multiplier, &data->output_multiplier, + &data->output_shift); + + data->input_zero_point = input->params.zero_point; + // Filter weights will always be symmetric quantized since we only support + // int8 quantization. See + // https://github.com/tensorflow/tensorflow/issues/44912 for additional + // context. + TFLITE_DCHECK(filter->params.zero_point == 0); + data->filter_zero_point = filter->params.zero_point; + data->output_zero_point = output->params.zero_point; + + return CalculateActivationRangeQuantized(context, activation, output, + &data->output_activation_min, + &data->output_activation_max); + } + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/gather.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/gather.cc new file mode 100644 index 000000000..4ec534731 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/gather.cc @@ -0,0 +1,224 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kInputPositions = 1; +constexpr int kOutputTensor = 0; + +template +TfLiteStatus Gather(const TfLiteGatherParams* params, + const TfLiteEvalTensor* input, + const TfLiteEvalTensor* coords, TfLiteEvalTensor* output) { + const InputT* input_data = tflite::micro::GetTensorData(input); + const CoordsT* coords_data = tflite::micro::GetTensorData(coords); + InputT* output_data = tflite::micro::GetTensorData(output); + const TfLiteIntArray* input_dims = input->dims; + const int input_dims_size = input_dims->size; + int axis = params->axis; + if (axis < 0) { + axis += input_dims_size; + } + TFLITE_DCHECK_GE(axis, 0); + TFLITE_DCHECK_LT(axis, input_dims_size); + + int batch_dims = params->batch_dims; + // batch_dims should be in range: [-rank(coords), rank(coords)]. + // Negative batch_dims is added with rank of coords. + const TfLiteIntArray* coords_dims = coords->dims; + const int coords_dims_size = coords_dims->size; + if (batch_dims < 0) { + batch_dims += coords_dims_size; + } + TFLITE_DCHECK_GE(batch_dims, 0); + TFLITE_DCHECK_LT(batch_dims, input_dims_size); + TFLITE_DCHECK_LE(batch_dims, coords_dims_size); + TFLITE_DCHECK_GE(axis, batch_dims); + for (int i = 0; i < batch_dims; ++i) { + TFLITE_DCHECK_EQ(input_dims->data[i], coords_dims->data[i]); + } + + const int axis_size = input_dims->data[axis]; + + int batch_size = 1; + for (int i = 0; i < batch_dims; ++i) { + batch_size *= input_dims->data[i]; + } + int outer_size = 1; + for (int i = batch_dims; i < axis; ++i) { + outer_size *= input_dims->data[i]; + } + int inner_size = 1; + for (int i = axis + 1; i < input_dims_size; ++i) { + inner_size *= input_dims->data[i]; + } + int coord_size = 1; + for (int i = batch_dims; i < coords_dims_size; ++i) { + coord_size *= coords_dims->data[i]; + } + + for (int batch = 0; batch < batch_size; ++batch) { + for (int outer = 0; outer < outer_size; ++outer) { + for (int coord = 0; coord < coord_size; ++coord) { + TFLITE_DCHECK_GE(coords_data[coord], 0); + TFLITE_DCHECK_LT(coords_data[coord], axis_size); + std::memcpy(output_data + + (((batch * outer_size) + outer) * coord_size + coord) * + inner_size, + input_data + (((batch * outer_size) + outer) * axis_size + + coords_data[batch * coord_size + coord]) * + inner_size, + sizeof(InputT) * inner_size); + } + } + } + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + const auto* params = + reinterpret_cast(node->builtin_data); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* coords = + micro_context->AllocateTempInputTensor(node, kInputPositions); + TF_LITE_ENSURE(context, coords != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + switch (coords->type) { + case kTfLiteInt32: + break; + default: + MicroPrintf("Positions of type '%s' are not supported by gather.", + TfLiteTypeGetName(coords->type)); + return kTfLiteError; + break; + } + + // Assign to output the input type. + output->type = input->type; + + // Check conditions for different types. + switch (input->type) { + case kTfLiteFloat32: + case kTfLiteInt8: + break; + default: + MicroPrintf("Type '%s' is not supported by gather.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + break; + } + + int axis = params->axis; + if (axis < 0) { + axis += NumDimensions(input); + } + TF_LITE_ENSURE(context, 0 <= axis && axis < NumDimensions(input)); + + int batch_dims = params->batch_dims; + // batch_dims should be in range: [-rank(coords), rank(coords)]. + // Negative batch_dims is added with rank of coords. + if (batch_dims < 0) { + batch_dims += NumDimensions(coords); + } + TF_LITE_ENSURE(context, batch_dims <= axis); + TF_LITE_ENSURE(context, 0 <= batch_dims && batch_dims < NumDimensions(input)); + TF_LITE_ENSURE(context, batch_dims <= NumDimensions(coords)); + for (int i = 0; i < batch_dims; ++i) { + TF_LITE_ENSURE_EQ(context, input->dims->data[i], coords->dims->data[i]); + } + + // GATHER updates the output tensor dimensions, but TfLiteTensor in the + // MicroInterpreter is a temporary allocation. We must therefore relocate the + // dims from the FlatBuffer to the persistant storage arena. + TfLiteEvalTensor* output_eval = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + TF_LITE_ENSURE_OK(context, tflite::micro::CreateWritableTensorDimsWithCopy( + context, output, output_eval)); + + TfLiteIntArray* output_shape = output->dims; + output_shape->size = + NumDimensions(input) + NumDimensions(coords) - 1 - batch_dims; + int output_index = 0; + for (int i = 0; i < axis; ++i) { + output_shape->data[output_index++] = input->dims->data[i]; + } + for (int i = batch_dims; i < coords->dims->size; ++i) { + output_shape->data[output_index++] = coords->dims->data[i]; + } + for (int i = axis + 1; i < input->dims->size; ++i) { + output_shape->data[output_index++] = input->dims->data[i]; + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(coords); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const auto* params = + reinterpret_cast(node->builtin_data); + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* coords = + tflite::micro::GetEvalInput(context, node, kInputPositions); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + if (coords->type == kTfLiteInt32) { + switch (input->type) { + case kTfLiteFloat32: + return Gather(params, input, coords, output); + break; + case kTfLiteInt8: + return Gather(params, input, coords, output); + break; + default: + MicroPrintf("Type '%s' is not supported by gather.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + break; + } + } + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_GATHER() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/gather_nd.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/gather_nd.cc new file mode 100644 index 000000000..1f46dd1ef --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/gather_nd.cc @@ -0,0 +1,205 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +constexpr int kParams = 0; +constexpr int kIndices = 1; +constexpr int kOutputTensor = 0; +constexpr int MAX_INDICES_ND = 5; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* params = micro_context->AllocateTempInputTensor(node, kParams); + TF_LITE_ENSURE(context, params != nullptr); + TfLiteTensor* indices = + micro_context->AllocateTempInputTensor(node, kIndices); + TF_LITE_ENSURE(context, indices != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + switch (params->type) { + case kTfLiteFloat32: + case kTfLiteInt8: + break; + default: + MicroPrintf("Params of type '%s' are not supported by gather_nd.", + TfLiteTypeGetName(params->type)); + return kTfLiteError; + break; + } + switch (indices->type) { + case kTfLiteInt32: + break; + default: + MicroPrintf("Indices of type '%s' are not supported by gather_nd.", + TfLiteTypeGetName(indices->type)); + return kTfLiteError; + } + + const int params_rank = NumDimensions(params); + const int indices_rank = NumDimensions(indices); + const int indices_nd = SizeOfDimension(indices, indices_rank - 1); + if (params_rank < 1) { + MicroPrintf("Params must be at least a vector."); + return kTfLiteError; + } + if (indices_rank < 1) { + MicroPrintf("Indices must be at least a vector."); + return kTfLiteError; + } + if (indices_nd > params_rank) { + MicroPrintf("Index innermost dimension length must be <= params rank."); + return kTfLiteError; + } + if (indices_nd > MAX_INDICES_ND) { + MicroPrintf("Index innermost dimension length must not exceed %d.", + MAX_INDICES_ND); + return kTfLiteError; + } + + // Assign to output the input type. + output->type = params->type; + + // TFLM gather_nd does not create the output tensor, but it needs to ensure + // that the output shape is correct. The result shape is + // indices.shape[:-1] + params.shape[indices.shape[-1]:] + TfLiteIntArray* output_shape = output->dims; + int output_index = 0; + for (int i = 0; i < indices_rank - 1; ++i) { + output_shape->data[output_index++] = indices->dims->data[i]; + } + for (int i = indices_nd; i < params_rank; ++i) { + output_shape->data[output_index++] = params->dims->data[i]; + } + output_shape->size = output_index; + + micro_context->DeallocateTempTfLiteTensor(params); + micro_context->DeallocateTempTfLiteTensor(indices); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +template +TfLiteStatus GatherNd(const TfLiteEvalTensor* params, + const TfLiteEvalTensor* indices, + TfLiteEvalTensor* output) { + const int indices_dims = indices->dims->size; + const int indices_nd = indices->dims->data[indices_dims - 1]; + const int params_dims = params->dims->size; + const IndicesT* index_data = tflite::micro::GetTensorData(indices); + const ParamsT* param_data = tflite::micro::GetTensorData(params); + ParamsT* output_data = tflite::micro::GetTensorData(output); + + int n_slices = 1; + for (int i = 0; i < indices_dims - 1; ++i) { + n_slices *= indices->dims->data[i]; + } + + // If indices[-1] == params.rank, fetch single elements. + // If indices[-1] < params.rank, fetch slices. + int slice_size = 1; + for (int i = indices_nd; i < params_dims; ++i) { + slice_size *= params->dims->data[i]; + } + + int params_flat_size = ElementCount(*params->dims); + int remain_flat_size = params_flat_size; + + // Number of elements per dimension + int dims_to_count[MAX_INDICES_ND]; + for (int i = 0; i < indices_nd; ++i) { + dims_to_count[i] = remain_flat_size / params->dims->data[i]; + remain_flat_size = dims_to_count[i]; + } + + for (int i = 0; i < n_slices; ++i) { + int from_pos = 0; + for (int j = 0; j < indices_nd; ++j) { + int offset = i * indices_nd + j; + IndicesT index = index_data[offset]; + from_pos += index * dims_to_count[j]; + } + if (from_pos < 0 || from_pos + slice_size > params_flat_size) { + return kTfLiteError; + } + std::memcpy(output_data + i * slice_size, param_data + from_pos, + sizeof(ParamsT) * slice_size); + } + return kTfLiteOk; +} + +template +TfLiteStatus EvalGatherNd(TfLiteContext* context, + const TfLiteEvalTensor* params, + const TfLiteEvalTensor* indices, + TfLiteEvalTensor* output) { + TfLiteStatus status = kTfLiteError; + switch (params->type) { + case kTfLiteFloat32: + status = GatherNd(params, indices, output); + break; + case kTfLiteInt8: + status = GatherNd(params, indices, output); + break; + default: + MicroPrintf("Params type '%s' are not supported by gather_nd.", + TfLiteTypeGetName(params->type)); + return kTfLiteError; + } + if (status != kTfLiteOk) { + MicroPrintf("gather_nd index out of bounds"); + } + return status; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* params = + tflite::micro::GetEvalInput(context, node, kParams); + const TfLiteEvalTensor* indices = + tflite::micro::GetEvalInput(context, node, kIndices); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + switch (indices->type) { + case kTfLiteInt32: + return EvalGatherNd(context, params, indices, output); + break; + default: + MicroPrintf("Indices of type '%s' are not supported by gather_nd.", + TfLiteTypeGetName(indices->type)); + return kTfLiteError; + } +} +} // namespace + +TfLiteRegistration Register_GATHER_ND() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish.cc new file mode 100644 index 000000000..a0b3f7c62 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish.cc @@ -0,0 +1,75 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/hard_swish.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/hard_swish.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { +void* HardSwishInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(HardSwishParams)); +} + +TfLiteStatus HardSwishEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kHardSwishInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kHardSwishOutputTensor); + HardSwishParams* params = static_cast(node->user_data); + + switch (input->type) { + case kTfLiteFloat32: { + tflite::reference_ops::HardSwish( + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } break; + case kTfLiteInt8: { + tflite::reference_ops::HardSwish( + *params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } break; + default: { + MicroPrintf("Unsupported type %s", TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_HARD_SWISH() { + return tflite::micro::RegisterOp(HardSwishInit, tflite::HardSwishPrepare, + HardSwishEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish.h new file mode 100644 index 000000000..3ffe60dce --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish.h @@ -0,0 +1,30 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_HARD_SWISH_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_HARD_SWISH_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +extern const int kHardSwishInputTensor; +extern const int kHardSwishOutputTensor; + +TfLiteStatus HardSwishPrepare(TfLiteContext* context, TfLiteNode* node); +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_HARD_SWISH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish_common.cc new file mode 100644 index 000000000..8f8465226 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/hard_swish_common.cc @@ -0,0 +1,86 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/hard_swish.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/hard_swish.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +const int kHardSwishInputTensor = 0; +const int kHardSwishOutputTensor = 0; + +TfLiteStatus HardSwishPrepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TFLITE_DCHECK(node->user_data != nullptr); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kHardSwishInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kHardSwishOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + if (input->type == kTfLiteInt8) { + HardSwishParams* params = static_cast(node->user_data); + + params->input_zero_point = input->params.zero_point; + params->output_zero_point = output->params.zero_point; + + const float input_scale = input->params.scale; + const float hires_input_scale = (1.0f / 128.0f) * input_scale; + const float reluish_scale = 3.0f / 32768.0f; + const float output_scale = output->params.scale; + + const double output_multiplier = + static_cast(hires_input_scale / output_scale); + int32_t output_multiplier_fixedpoint_int32; + QuantizeMultiplier(output_multiplier, &output_multiplier_fixedpoint_int32, + ¶ms->output_multiplier_exponent); + DownScaleInt32ToInt16Multiplier( + output_multiplier_fixedpoint_int32, + ¶ms->output_multiplier_fixedpoint_int16); + + TF_LITE_ENSURE(context, params->output_multiplier_exponent <= 0); + + const double reluish_multiplier = + static_cast(hires_input_scale / reluish_scale); + int32_t reluish_multiplier_fixedpoint_int32; + QuantizeMultiplier(reluish_multiplier, &reluish_multiplier_fixedpoint_int32, + ¶ms->reluish_multiplier_exponent); + DownScaleInt32ToInt16Multiplier( + reluish_multiplier_fixedpoint_int32, + ¶ms->reluish_multiplier_fixedpoint_int16); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/if.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/if.cc new file mode 100644 index 000000000..39eca8b48 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/if.cc @@ -0,0 +1,121 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_context.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +namespace { + +struct OpData { + int then_subgraph_index; + int else_subgraph_index; +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + OpData* op_data = reinterpret_cast(node->user_data); + const auto* params = + reinterpret_cast(node->builtin_data); + op_data->then_subgraph_index = params->then_subgraph_index; + op_data->else_subgraph_index = params->else_subgraph_index; + + TF_LITE_ENSURE(context, node->inputs->size > 0); + + // The first input is the condition. + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + TfLiteTensor* cond = micro_context->AllocateTempInputTensor(node, 0); + + TF_LITE_ENSURE(context, cond != nullptr); + TF_LITE_ENSURE_EQ(context, cond->type, kTfLiteBool); + TF_LITE_ENSURE_EQ(context, NumElements(cond), 1); + + micro_context->DeallocateTempTfLiteTensor(cond); + + // The first input of the node is the condition. The rest of inputs are + // passed to the branch subgraphs. Therefore, the number of subgraph inputs + // will be the number of node inputs - 1. + size_t num_inputs = node->inputs->size - 1; + size_t num_outputs = node->outputs->size; + + MicroGraph& graph_info = micro_context->graph(); + + TF_LITE_ENSURE(context, + op_data->then_subgraph_index < graph_info.NumSubgraphs()); + TF_LITE_ENSURE(context, + op_data->else_subgraph_index < graph_info.NumSubgraphs()); + + TF_LITE_ENSURE_EQ(context, num_inputs, + graph_info.NumSubgraphInputs(op_data->then_subgraph_index)); + TF_LITE_ENSURE_EQ( + context, num_outputs, + graph_info.NumSubgraphOutputs(op_data->then_subgraph_index)); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const OpData* op_data = reinterpret_cast(node->user_data); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + TfLiteTensor* cond = micro_context->AllocateTempInputTensor(node, 0); + + TF_LITE_ENSURE(context, cond != nullptr); + bool cond_value = cond->data.b[0]; + micro_context->DeallocateTempTfLiteTensor(cond); + + MicroGraph* graph_info = µ_context->graph(); + // Currently we copy the input / output between the subgraphs. + int active_branch_subgraph_index = + cond_value ? op_data->then_subgraph_index : op_data->else_subgraph_index; + + TF_LITE_ENSURE_OK(context, + tflite::micro::CopyOpInputsToSubgraphInputs( + context, node, graph_info, active_branch_subgraph_index, + /*first_tensor_idx=*/1)); + + TF_LITE_ENSURE_OK(context, + graph_info->InvokeSubgraph(active_branch_subgraph_index)); + + TF_LITE_ENSURE_OK( + context, tflite::micro::CopySubgraphOutputsToOpOutputs( + context, node, graph_info, active_branch_subgraph_index)); + + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_IF() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_runner.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_runner.cc new file mode 100644 index 000000000..b31aa0ebb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_runner.cc @@ -0,0 +1,122 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/kernel_runner.h" + +#include "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/micro_arena_constants.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/test_helpers.h" + +namespace tflite { +namespace micro { + +// TODO(b/161841696): Consider moving away from global arena buffers: +constexpr int KernelRunner::kKernelRunnerBufferSize_; +uint8_t KernelRunner::kKernelRunnerBuffer_[]; + +void ClearBufferApi(TfLiteContext* context_) { + context_->GetScratchBuffer = nullptr; + context_->GetExternalContext = nullptr; + context_->AllocatePersistentBuffer = nullptr; + context_->RequestScratchBufferInArena = nullptr; +} + +KernelRunner::KernelRunner(const TfLiteRegistration& registration, + TfLiteTensor* tensors, int tensors_size, + TfLiteIntArray* inputs, TfLiteIntArray* outputs, + void* builtin_data, TfLiteIntArray* intermediates) + : registration_(registration), + allocator_(SingleArenaBufferAllocator::Create(kKernelRunnerBuffer_, + kKernelRunnerBufferSize_)), + mock_micro_graph_(allocator_), + fake_micro_context_(tensors, allocator_, &mock_micro_graph_) { + // Prepare TfLiteContext: + context_.impl_ = static_cast(&fake_micro_context_); + context_.ReportError = MicroContextReportOpError; + context_.recommended_num_threads = 1; + context_.GetTensor = MicroContextGetTensor; + context_.GetEvalTensor = MicroContextGetEvalTensor; + tflite::micro::ClearBufferApi(&context_); + context_.AllocatePersistentBuffer = MicroContextAllocatePersistentBuffer; + + context_.recommended_num_threads = 0; + + // Prepare TfLiteNode: + node_.inputs = inputs; + node_.outputs = outputs; + node_.builtin_data = builtin_data; + node_.intermediates = intermediates; +} + +bool KernelRunner::ValidateTempBufferDeallocated() { + return fake_micro_context_.IsAllTempTfLiteTensorDeallocated(); +} + +TfLiteStatus KernelRunner::InitAndPrepare(const char* init_data, + size_t length) { + if (registration_.init) { + tflite::micro::ClearBufferApi(&context_); + context_.AllocatePersistentBuffer = MicroContextAllocatePersistentBuffer; + node_.user_data = registration_.init(&context_, init_data, length); + } + + TF_LITE_ENSURE(&context_, ValidateTempBufferDeallocated()); + + if (registration_.prepare) { + tflite ::micro::ClearBufferApi(&context_); + context_.AllocatePersistentBuffer = MicroContextAllocatePersistentBuffer; + context_.RequestScratchBufferInArena = + MicroContextRequestScratchBufferInArena; + context_.GetExternalContext = MicroContextGetExternalContext; + TF_LITE_ENSURE_STATUS(registration_.prepare(&context_, &node_)); + } + + TF_LITE_ENSURE(&context_, ValidateTempBufferDeallocated()); + + return kTfLiteOk; +} + +TfLiteStatus KernelRunner::Invoke() { + tflite::micro::ClearBufferApi(&context_); + context_.GetScratchBuffer = MicroContextGetScratchBuffer; + + if (registration_.invoke == nullptr) { + MicroPrintf("TfLiteRegistration missing invoke function pointer!"); + return kTfLiteError; + } + + TF_LITE_ENSURE_STATUS(registration_.invoke(&context_, &node_)); + + TF_LITE_ENSURE(&context_, ValidateTempBufferDeallocated()); + + return kTfLiteOk; +} + +TfLiteStatus KernelRunner::Free() { + tflite::micro::ClearBufferApi(&context_); + context_.GetScratchBuffer = MicroContextGetScratchBuffer; + + if (registration_.free == nullptr) { + MicroPrintf("TfLiteRegistration missing free function pointer!"); + return kTfLiteError; + } + + registration_.free(&context_, node_.user_data); + return kTfLiteOk; +} +} // namespace micro +} // namespace tflite \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_runner.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_runner.h new file mode 100644 index 000000000..c7d53c3a5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_runner.h @@ -0,0 +1,81 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_KERNEL_RUNNER_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_KERNEL_RUNNER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/fake_micro_context.h" +#include "tensorflow/lite/micro/mock_micro_graph.h" + +namespace tflite { +namespace micro { + +// Helper class to perform a simulated kernel (i.e. TfLiteRegistration) +// lifecycle (init, prepare, invoke). All internal allocations are handled by +// this class. Simply pass in the registration, list of required tensors, inputs +// array, outputs array, and any pre-builtin data. Calling Invoke() will +// automatically walk the kernel and outputs will be ready on the TfLiteTensor +// output provided during construction. +class KernelRunner { + public: + KernelRunner(const TfLiteRegistration& registration, TfLiteTensor* tensors, + int tensors_size, TfLiteIntArray* inputs, + TfLiteIntArray* outputs, void* builtin_data, + TfLiteIntArray* intermediates = nullptr); + + // Calls init and prepare on the kernel (i.e. TfLiteRegistration) struct. Any + // exceptions will be DebugLog'd and returned as a status code. + TfLiteStatus InitAndPrepare(const char* init_data = nullptr, + size_t length = 0); + + // Calls init, prepare, and invoke on a given TfLiteRegistration pointer. + // After successful invoke, results will be available in the output tensor as + // passed into the constructor of this class. + TfLiteStatus Invoke(); + + // Calls Free on a given TfLiteRegistration pointer(if it's implemented). + // After successful Free, kTfLiteOk status will be returned. If Free is not + // implemented for a given kernel kTfLiteError will be returned. + TfLiteStatus Free(); + + // Returns a pointer to the internal MockMicroGraph which KernelRunner uses + // to stub out MicroGraph methods and track invocations on each subgraph. + MockMicroGraph* GetMockGraph() { return &mock_micro_graph_; } + + // Returns true if all temp buffer in tests are deallocated. + // TODO(b/209453859): move this function to private after deallocation checks + // are enabled for all kernel tests. + bool ValidateTempBufferDeallocated(); + + private: + static constexpr int kKernelRunnerBufferSize_ = 10000; + static uint8_t kKernelRunnerBuffer_[kKernelRunnerBufferSize_]; + + TfLiteContext context_ = {}; + TfLiteNode node_ = {}; + const TfLiteRegistration& registration_; + + SingleArenaBufferAllocator* allocator_; + MockMicroGraph mock_micro_graph_; + FakeMicroContext fake_micro_context_; +}; + +} // namespace micro +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_KERNEL_RUNNER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_util.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_util.cc new file mode 100644 index 000000000..0499260f5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_util.cc @@ -0,0 +1,260 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/kernel_util.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace micro { + +namespace { + +int ValidateTensorIndexing(const TfLiteContext* context, int index, + int max_size, const int* tensor_indices) { + if (index >= 0 && index < max_size) { + const int tensor_index = tensor_indices[index]; + if (tensor_index != kTfLiteOptionalTensor) { + return tensor_index; + } + } + return -1; +} + +} // namespace + +TfLiteRegistration RegisterOp( + void* (*init)(TfLiteContext* context, const char* buffer, size_t length), + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node), + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node), + void (*free)(TfLiteContext* context, void* buffer)) { + return {/*init=*/init, + /*free=*/free, + /*prepare=*/prepare, + /*invoke=*/invoke, + /*profiling_string=*/nullptr, + /*builtin_code=*/0, + /*custom_name=*/nullptr, + /*version=*/0, + /*registration_external=*/nullptr}; +} + +// Returns a mutable tensor for a given input index. is_variable must be checked +// during prepare when the full TfLiteTensor is available. +TfLiteEvalTensor* GetMutableEvalInput(const TfLiteContext* context, + const TfLiteNode* node, int index) { + TFLITE_DCHECK(context != nullptr); + TFLITE_DCHECK(node != nullptr); + const int tensor_index = ValidateTensorIndexing( + context, index, node->inputs->size, node->inputs->data); + + if (tensor_index < 0) { + return nullptr; + } + + return context->GetEvalTensor(context, node->inputs->data[index]); +} + +// Returns the TfLiteEvalTensor struct for a given input index in a node. +const TfLiteEvalTensor* GetEvalInput(const TfLiteContext* context, + const TfLiteNode* node, int index) { + return GetMutableEvalInput(context, node, index); +} + +// Returns the TfLiteEvalTensor struct for a given output index in a node. +TfLiteEvalTensor* GetEvalOutput(const TfLiteContext* context, + const TfLiteNode* node, int index) { + TFLITE_DCHECK(context != nullptr); + TFLITE_DCHECK(node != nullptr); + return context->GetEvalTensor(context, node->outputs->data[index]); +} + +bool HaveSameShapes(const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2) { + TFLITE_DCHECK(input1 != nullptr); + TFLITE_DCHECK(input2 != nullptr); + return TfLiteIntArrayEqual(input1->dims, input2->dims); +} + +const RuntimeShape GetTensorShape(const TfLiteEvalTensor* tensor) { + if (tensor == nullptr || tensor->dims == nullptr) { + return RuntimeShape(); + } + TfLiteIntArray* dims = tensor->dims; + const int dims_size = dims->size; + const int32_t* dims_data = reinterpret_cast(dims->data); + return RuntimeShape(dims_size, dims_data); +} + +PaddingType RuntimePaddingType(TfLitePadding padding) { + switch (padding) { + case TfLitePadding::kTfLitePaddingSame: + return PaddingType::kSame; + case TfLitePadding::kTfLitePaddingValid: + return PaddingType::kValid; + case TfLitePadding::kTfLitePaddingUnknown: + default: + return PaddingType::kNone; + } +} + +// Relocate tensor dims from FlatBuffer to the persistent storage arena. +// The old dims data is copied to the new storage area. +// The tensor and eval_tensor must be the same tensor. +// Only use during Prepare phase. +TfLiteStatus CreateWritableTensorDimsWithCopy(TfLiteContext* context, + TfLiteTensor* tensor, + TfLiteEvalTensor* eval_tensor) { + TF_LITE_ENSURE(context, tensor != nullptr); + TF_LITE_ENSURE(context, eval_tensor != nullptr); + TF_LITE_ENSURE(context, context->AllocatePersistentBuffer != nullptr); + int ranks = tensor->dims->size; + size_t alloc_size = TfLiteIntArrayGetSizeInBytes(ranks); + TfLiteIntArray* new_dims = static_cast( + context->AllocatePersistentBuffer(context, alloc_size)); + TfLiteIntArray* old_dims = tensor->dims; + new_dims->size = ranks; + tensor->dims = new_dims; + eval_tensor->dims = new_dims; + for (int i = 0; i < ranks; i++) { + new_dims->data[i] = old_dims->data[i]; + } + + return kTfLiteOk; +} + +// Verify that both tensors have the same type and size, then return the size +// of both tensors in bytes if they are the same, or -1 if they are different. +size_t ValidateAndGetTensorSizes(const TfLiteEvalTensor* tensor1, + const TfLiteEvalTensor* tensor2) { + TFLITE_DCHECK(tensor1->type == tensor2->type); + size_t tensor1_size = 0; + size_t tensor2_size = 0; + TfLiteEvalTensorByteLength(tensor1, &tensor1_size); + TfLiteEvalTensorByteLength(tensor2, &tensor2_size); + return (tensor1_size == tensor2_size) ? tensor1_size : -1; +} + +TfLiteStatus CopyOpInputsToOpOutputs(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE(context, node->inputs->size == node->outputs->size); + for (int i = 0; i < node->inputs->size; i++) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, i); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, i); + int bytes = ValidateAndGetTensorSizes(input, output); + TF_LITE_ENSURE(context, bytes >= 0); + memcpy(output->data.raw, input->data.raw, bytes); + } + return kTfLiteOk; +} + +// Args: +// 1. int8_t tensor_data - int8_t buffer of unknown size who's data you'd +// like +// to print +// 2. int n_btyes - a small int representing number of bytes you want to +// print +// to debug output. It should always be <= tensor_data's size. +// 3. prefix - optional message you'd like to print before printing bytes +// +// Purpose: +// Function takes in paramaters above and prints n_bytes bytes from the +// tensor_data buffer. This can be use to debug the output of a model and it's +// op. + +void PrintNBytes(const int8_t* tensor_data, int n_bytes, const char* prefix) { + if (prefix != nullptr) { + MicroPrintf("%s", prefix); + } + + for (int i = 0; i < n_bytes; ++i) { + MicroPrintf(" %x", tensor_data[i]); + } + MicroPrintf("\n"); +} + +// same as the PrintNBytes above but the buffer needs to be extracted out of the +// TfLiteEvalTensor* +void PrintNBytes(const TfLiteEvalTensor* tensor, int n_bytes, + const char* prefix) { + const int8_t* tensor_data = tflite::micro::GetTensorData(tensor); + PrintNBytes(tensor_data, n_bytes, prefix); +} + +// same as the PrintNBytes above but the buffer needs to be extracted out of the +// TfLiteEvalTensor* +void PrintNBytes(const TfLiteTensor* tensor, int n_bytes, const char* prefix) { + const int8_t* tensor_data = tflite::GetTensorData(tensor); + PrintNBytes(tensor_data, n_bytes, prefix); +} + +TfLiteStatus CopyOpInputsToSubgraphInputs(TfLiteContext* context, + TfLiteNode* node, + MicroGraph* graph_info, + int subgraph_idx, + int first_tensor_idx) { + TF_LITE_ENSURE(context, + static_cast(node->inputs->size - first_tensor_idx) == + graph_info->NumSubgraphInputs(subgraph_idx)); + for (int i = 0; i < node->inputs->size - first_tensor_idx; i++) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, i + first_tensor_idx); + TfLiteEvalTensor* subgraph_input = + graph_info->GetSubgraphInput(subgraph_idx, i); + int bytes = ValidateAndGetTensorSizes(input, subgraph_input); + TF_LITE_ENSURE(context, bytes >= 0); + memcpy(subgraph_input->data.raw, input->data.raw, bytes); + } + return kTfLiteOk; +} + +TfLiteStatus CopyOpOutputsToSubgraphInputs(TfLiteContext* context, + TfLiteNode* node, + MicroGraph* graph_info, + int subgraph_idx) { + TF_LITE_ENSURE(context, static_cast(node->outputs->size) == + graph_info->NumSubgraphInputs(subgraph_idx)); + for (int i = 0; i < node->outputs->size; i++) { + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, i); + TfLiteEvalTensor* subgraph_input = + graph_info->GetSubgraphInput(subgraph_idx, i); + int bytes = ValidateAndGetTensorSizes(output, subgraph_input); + TF_LITE_ENSURE(context, bytes >= 0); + memcpy(subgraph_input->data.raw, output->data.raw, bytes); + } + return kTfLiteOk; +} + +TfLiteStatus CopySubgraphOutputsToOpOutputs(TfLiteContext* context, + TfLiteNode* node, + MicroGraph* graph_info, + int subgraph_idx) { + TF_LITE_ENSURE(context, static_cast(node->outputs->size) == + graph_info->NumSubgraphOutputs(subgraph_idx)); + for (int i = 0; i < node->outputs->size; i++) { + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, i); + TfLiteEvalTensor* subgraph_output = + graph_info->GetSubgraphOutput(subgraph_idx, i); + int bytes = ValidateAndGetTensorSizes(output, subgraph_output); + TF_LITE_ENSURE(context, bytes >= 0); + memcpy(output->data.raw, subgraph_output->data.raw, bytes); + } + return kTfLiteOk; +} + +} // namespace micro +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_util.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_util.h new file mode 100644 index 000000000..aa369605e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/kernel_util.h @@ -0,0 +1,137 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_KERNEL_UTIL_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_KERNEL_UTIL_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/micro/micro_context.h" + +namespace tflite { +namespace micro { + +TfLiteRegistration RegisterOp( + void* (*init)(TfLiteContext* context, const char* buffer, size_t length), + TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node), + TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node), + void (*free)(TfLiteContext* context, void* buffer) = nullptr); + +// Prints out n bytes in a int8_t buffer as hex +void PrintNBytes(const int8_t* tensor_data, int n_bytes, + const char* prefix = nullptr); + +// Prints out the the n bytes in a TfLiteEvalTensor as hex +void PrintNBytes(const TfLiteEvalTensor* tensor, int n_bytes, + const char* prefix = nullptr); + +// Prints out the the n bytes in a TfLiteTensor as hex +void PrintNBytes(const TfLiteTensor* tensor, int n_bytes, + const char* prefix = nullptr); + +// Returns a mutable tensor for a given input index. is_variable must be checked +// during prepare when the full TfLiteTensor is available. +TfLiteEvalTensor* GetMutableEvalInput(const TfLiteContext* context, + const TfLiteNode* node, int index); + +// Returns the TfLiteEvalTensor struct for a given input index in a node. +const TfLiteEvalTensor* GetEvalInput(const TfLiteContext* context, + const TfLiteNode* node, int index); + +// Returns the TfLiteEvalTensor struct for a given output index in a node. +TfLiteEvalTensor* GetEvalOutput(const TfLiteContext* context, + const TfLiteNode* node, int index); + +// Returns data for a TfLiteEvalTensor struct that are expected to exist. +template +T* GetTensorData(TfLiteEvalTensor* tensor) { + TFLITE_DCHECK(tensor != nullptr); + return reinterpret_cast(tensor->data.raw); +} + +// Returns const data for a TfLiteEvalTensor struct that are expected to exist. +template +const T* GetTensorData(const TfLiteEvalTensor* tensor) { + TFLITE_DCHECK(tensor != nullptr); + return reinterpret_cast(tensor->data.raw); +} + +// Returns data for a TfLiteEvalTensor struct that could be null. +template +T* GetOptionalTensorData(TfLiteEvalTensor* tensor) { + return tensor == nullptr ? nullptr : reinterpret_cast(tensor->data.raw); +} + +// Returns const data for a TfLiteEvalTensor struct that could be null. +template +const T* GetOptionalTensorData(const TfLiteEvalTensor* tensor) { + return tensor == nullptr ? nullptr + : reinterpret_cast(tensor->data.raw); +} + +// Returns the shape of a TfLiteEvalTensor struct. +const RuntimeShape GetTensorShape(const TfLiteEvalTensor* tensor); + +// Return true if the given tensors have the same shape. +bool HaveSameShapes(const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2); + +PaddingType RuntimePaddingType(TfLitePadding padding); + +// Relocate tensor dims from FlatBuffer to the persistent storage arena. +// The old dims data is copied to the new storage area. +// The tensor and eval_tensor must be the same tensor. +// Only use during Prepare phase. +TfLiteStatus CreateWritableTensorDimsWithCopy(TfLiteContext* context, + TfLiteTensor* tensor, + TfLiteEvalTensor* eval_tensor); + +// Copy all op input tensors to op output tensors. Requires all op input tensor +// shapes and types to be identical to op output tensor shapes and types. +TfLiteStatus CopyOpInputsToOpOutputs(TfLiteContext* context, TfLiteNode* node); + +// Copy all op input tensors to subgraph input tensors. Requires all op input +// tensor shapes and types to be identical to subgraph input tensor shapes and +// types. +TfLiteStatus CopyOpInputsToSubgraphInputs(TfLiteContext* context, + TfLiteNode* node, + MicroGraph* graph_info, + int subgraph_idx, + int first_tensor_idx); + +// Copy all op output tensors to subgraph input tensors. Requires all op output +// tensor shapes and types to be identical to subgraph input tensor shapes and +// types. +TfLiteStatus CopyOpOutputsToSubgraphInputs(TfLiteContext* context, + TfLiteNode* node, + MicroGraph* graph_info, + int subgraph_idx); + +// Copy all subgraph output tensors to op outputs. Requires all subgraph output +// tensor shapes and types to be identical to op output tensor shapes and types. +TfLiteStatus CopySubgraphOutputsToOpOutputs(TfLiteContext* context, + TfLiteNode* node, + MicroGraph* graph_info, + int subgraph_idx); + +} // namespace micro +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_KERNEL_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/l2_pool_2d.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/l2_pool_2d.cc new file mode 100644 index 000000000..d4225e466 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/l2_pool_2d.cc @@ -0,0 +1,142 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/reference/pooling.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +// Input/output tensor index. +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +// required rank for input/output tensor shape +constexpr int kTensorShapeRank = 4; + +// input/output tensor shape rank associations +enum { kBatchRank = 0, kHeightRank, kWidthRank, kChannelRank }; + +TfLiteStatus L2Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + auto* params = static_cast(node->builtin_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TF_LITE_ENSURE_EQ(context, NumDimensions(input), kTensorShapeRank); + TF_LITE_ENSURE_EQ(context, NumDimensions(output), kTensorShapeRank); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + int batches = SizeOfDimension(input, kBatchRank); + int height = SizeOfDimension(input, kHeightRank); + int width = SizeOfDimension(input, kWidthRank); + int channels_out = SizeOfDimension(input, kChannelRank); + + // Matching GetWindowedOutputSize in TensorFlow. + auto padding = params->padding; + int out_width, out_height; + + params->computed.padding = ComputePaddingHeightWidth( + params->stride_height, params->stride_width, 1, 1, height, width, + params->filter_height, params->filter_width, padding, &out_height, + &out_width); + + // We currently don't have a quantized implementation of L2Pool + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteFloat32); + + // We must update the output tensor dimensions. + // The dims storage is expected to be the same area in memory + // for both TfLiteTensor and TfLiteEvalTensor. This is important + // because TfLiteTensor in the MicroInterpreter is a temporary + // allocation. For the KernelRunner interpreter, TfLiteEvalTensor + // is a temporary allocation. We must therefore relocate the dims + // from the FlatBuffer to the persistant storage arena. + TfLiteEvalTensor* output_eval = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + TF_LITE_ENSURE_OK(context, tflite::micro::CreateWritableTensorDimsWithCopy( + context, output, output_eval)); + output->dims->data[kBatchRank] = batches; + output->dims->data[kHeightRank] = out_height; + output->dims->data[kWidthRank] = out_width; + output->dims->data[kChannelRank] = channels_out; + + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(input); + + return kTfLiteOk; +} + +void L2EvalFloat(const TfLitePoolParams& params, const TfLiteEvalTensor& input, + tflite::PoolParams* op_params, TfLiteEvalTensor* output) { + float activation_min, activation_max; + CalculateActivationRange(params.activation, &activation_min, &activation_max); + + op_params->float_activation_min = activation_min; + op_params->float_activation_max = activation_max; + reference_ops::L2Pool(*op_params, tflite::micro::GetTensorShape(&input), + tflite::micro::GetTensorData(&input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +TfLiteStatus L2Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = static_cast(node->builtin_data); + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + + tflite::PoolParams op_params; + op_params.stride_height = params->stride_height; + op_params.stride_width = params->stride_width; + op_params.filter_height = params->filter_height; + op_params.filter_width = params->filter_width; + op_params.padding_values.height = params->computed.padding.height; + op_params.padding_values.width = params->computed.padding.width; + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + L2EvalFloat(*params, *input, &op_params, output); + break; + default: + MicroPrintf("L2_POOL_2D only supports float32 currently, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_L2_POOL_2D() { + return tflite::micro::RegisterOp(nullptr, L2Prepare, L2Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/l2norm.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/l2norm.cc new file mode 100644 index 000000000..5adea8e29 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/l2norm.cc @@ -0,0 +1,148 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/portable_tensor.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h" +#include "tensorflow/lite/kernels/internal/reference/l2normalization.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace l2norm { + +namespace { + +// This file has two implementation of L2Norm. +enum KernelType { + kReference, + kGenericOptimized, +}; + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +} // namespace + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + auto* params = reinterpret_cast(node->builtin_data); + L2NormalizationParams* data = + static_cast(node->user_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE(context, NumDimensions(input) <= 4); + + TF_LITE_ENSURE(context, + output->type == kTfLiteFloat32 || output->type == kTfLiteInt8); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + if (output->type == kTfLiteInt8) { + data->input_zero_point = input->params.zero_point; + } else if (output->type == kTfLiteFloat32) { + data->input_zero_point = 0; + } + + // Our implementations don't currently support activations. + TF_LITE_ENSURE_EQ(context, params->activation, kTfLiteActNone); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, + sizeof(L2NormalizationParams)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const L2NormalizationParams& data = + *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + // TODO(b/143912164): instead of hardcode the epsilon here, we should read it + // from tensorflow, i.e., adding a params. + // We don't compute epsilon for quantized kernel: + // + // epsilon_float = (epsilon_quant - zp) * scale + // so + // espsilon_quant = epsilon_float / scale + zp + // We know epsilon_float is just a very small number to avoid division by + // zero error, and scale is > 1, so the integer value of epsilon for quant + // is just dominated by the zero point. + // Also, GetInvSqrtQuantizedMultiplierExp handles the scenario where the sum + // of input value squared is zero case well. + // So we don't even need to do handle the epsilon for quantized kernel case. + const float epsilon = 1e-6f; + if (output->type == kTfLiteFloat32) { + reference_ops::L2Normalization(data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + epsilon); + } else if (output->type == kTfLiteInt8) { + const auto input_shape = tflite::micro::GetTensorShape(input); + const auto output_shape = tflite::micro::GetTensorShape(output); + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + reference_integer_ops::L2Normalization( + data.input_zero_point, outer_size, depth, + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + } else { + MicroPrintf("Output type is %s, requires float.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace l2norm + +TfLiteRegistration Register_L2NORM_REF() { + return tflite::micro::RegisterOp(l2norm::Init, l2norm::Prepare, l2norm::Eval); +} + +TfLiteRegistration Register_L2_NORMALIZATION() { return Register_L2NORM_REF(); } + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu.cc new file mode 100644 index 000000000..7b51ebcb3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu.cc @@ -0,0 +1,95 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/leaky_relu.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/leaky_relu.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +template +void QuantizeLeakyRelu(const LeakyReluOpData& data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + LeakyReluParams op_params = {}; + + op_params.input_offset = data.input_zero_point; + op_params.output_offset = data.output_zero_point; + op_params.output_multiplier_alpha = data.output_multiplier_alpha; + op_params.output_shift_alpha = data.output_shift_alpha; + op_params.output_multiplier_identity = data.output_multiplier_identity; + op_params.output_shift_identity = data.output_shift_identity; + reference_ops::QuantizeLeakyRelu(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +void* LeakyReluInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(LeakyReluOpData)); +} + +TfLiteStatus LeakyReluEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + const LeakyReluOpData& data = *static_cast(node->user_data); + + switch (input->type) { + case kTfLiteFloat32: { + LeakyReluParams op_params = {}; + const auto* params = + static_cast(node->builtin_data); + + op_params.alpha = params->alpha; + reference_ops::LeakyRelu(op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + case kTfLiteInt8: { + QuantizeLeakyRelu(data, input, output); + return kTfLiteOk; + } break; + case kTfLiteInt16: { + QuantizeLeakyRelu(data, input, output); + return kTfLiteOk; + } break; + default: + MicroPrintf("Only float32, int8 are supported by LEAKY_RELU, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + + return kTfLiteError; +} + +TfLiteRegistration Register_LEAKY_RELU() { + return tflite::micro::RegisterOp(LeakyReluInit, LeakyReluPrepare, + LeakyReluEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu.h new file mode 100644 index 000000000..dfcd6e93d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu.h @@ -0,0 +1,43 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_LEAKY_RELU_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_LEAKY_RELU_H_ + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// Input/output tensor index. +extern const int kInputTensor; +extern const int kOutputTensor; + +struct LeakyReluOpData { + // quantization parameters + int32_t output_multiplier_alpha; + int32_t output_shift_alpha; + int32_t output_multiplier_identity; + int32_t output_shift_identity; + int32_t input_zero_point; + int32_t output_zero_point; +}; + +TfLiteStatus CalculateOpDataLeakyRelu(TfLiteContext* context, TfLiteNode* node); + +TfLiteStatus LeakyReluPrepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_LEAKY_RELU_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu_common.cc new file mode 100644 index 000000000..7d3cb176f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/leaky_relu_common.cc @@ -0,0 +1,79 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/leaky_relu.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/leaky_relu.h" + +namespace tflite { + +// Input/output tensor index. +const int kInputTensor = 0; +const int kOutputTensor = 0; + +TfLiteStatus CalculateOpDataLeakyRelu(TfLiteContext* context, + TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + LeakyReluOpData* data = static_cast(node->user_data); + const auto* params = + static_cast(node->builtin_data); + + data->input_zero_point = input->params.zero_point; + data->output_zero_point = output->params.zero_point; + + int output_shift_alpha; + double alpha_multiplier = static_cast(input->params.scale) * + static_cast(params->alpha) / + static_cast(output->params.scale); + QuantizeMultiplier(alpha_multiplier, &data->output_multiplier_alpha, + &output_shift_alpha); + data->output_shift_alpha = static_cast(output_shift_alpha); + + int output_shift_identity; + double identity_multiplier = static_cast(input->params.scale) / + static_cast(output->params.scale); + QuantizeMultiplier(identity_multiplier, &data->output_multiplier_identity, + &output_shift_identity); + data->output_shift_identity = static_cast(output_shift_identity); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus LeakyReluPrepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpDataLeakyRelu(context, node); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/log_softmax.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/log_softmax.cc new file mode 100644 index 000000000..0b1838c30 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/log_softmax.cc @@ -0,0 +1,148 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/log_softmax.h" + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +// used only with quantized data +struct LogSoftmaxOpData { + int32_t input_multiplier; + int32_t input_left_shift; + int32_t reverse_scaling_divisor; + int32_t reverse_scaling_right_shift; + int diff_min; + size_t outer_size; // number of tensor elements skipping computation axis + size_t depth; // number of tensor elements on computation axis +}; + +// input/output tensor index +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + TF_LITE_ENSURE(context, HaveSameShapes(input, output)); + + if (input->type == kTfLiteInt8) { + node->user_data = + context->AllocatePersistentBuffer(context, sizeof(LogSoftmaxOpData)); + auto data = static_cast(node->user_data); + + // quantization datum + constexpr int32_t kOutputZeroPoint = 127; + constexpr float kOutputScale = 16.0 / 256; + constexpr double kBeta = 1.0; + constexpr int kScaledDiffIntegerBits = 5; + + TF_LITE_ENSURE(context, output->params.scale == kOutputScale); + TF_LITE_ENSURE(context, output->params.zero_point == kOutputZeroPoint); + + int input_left_shift; + int reverse_scaling_right_shift; + tflite::PreprocessLogSoftmaxScalingExp( + kBeta, static_cast(input->params.scale), kScaledDiffIntegerBits, + &data->input_multiplier, &input_left_shift, + &data->reverse_scaling_divisor, &reverse_scaling_right_shift); + data->input_left_shift = static_cast(input_left_shift); + data->reverse_scaling_right_shift = + static_cast(-reverse_scaling_right_shift); + // diff_min has a negative value, and is used to limit the maximum magnitude + // of the diffs, which are <= 0. + data->diff_min = + -tflite::CalculateInputRadius(kScaledDiffIntegerBits, input_left_shift); + + RuntimeShape input_shape = GetTensorShape(input); + const int trailing_dim = input_shape.DimensionsCount() - 1; + data->outer_size = + static_cast(FlatSizeSkipDim(input_shape, trailing_dim)); + data->depth = static_cast(input_shape.Dims(trailing_dim)); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus LogSoftmaxPrepare(TfLiteContext* context, TfLiteNode* node) { + return CalculateOpData(context, node); +} + +TfLiteStatus LogSoftmaxEval(TfLiteContext* context, TfLiteNode* node) { + const LogSoftmaxOpData* data = + static_cast(node->user_data); + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + switch (input->type) { + case kTfLiteFloat32: { + SoftmaxParams op_params = {}; + reference_ops::LogSoftmax(op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + case kTfLiteInt8: { + SoftmaxParams op_params = {}; + op_params.input_multiplier = data->input_multiplier; + op_params.input_left_shift = data->input_left_shift; + op_params.reverse_scaling_divisor = data->reverse_scaling_divisor; + op_params.reverse_scaling_right_shift = data->reverse_scaling_right_shift; + op_params.diff_min = data->diff_min; + reference_ops::LogSoftmax(op_params, data->outer_size, data->depth, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + default: + MicroPrintf("LOG_SOFTMAX only supports float32, int8, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } +} + +} // namespace + +TfLiteRegistration Register_LOG_SOFTMAX() { + return tflite::micro::RegisterOp(nullptr, LogSoftmaxPrepare, LogSoftmaxEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical.cc new file mode 100644 index 000000000..c85e0c5be --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical.cc @@ -0,0 +1,44 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/logical.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/reference/binary_function.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { +namespace { + +TfLiteStatus LogicalOrEval(TfLiteContext* context, TfLiteNode* node) { + return LogicalImpl(context, node, LogicalOr); +} + +TfLiteStatus LogicalAndEval(TfLiteContext* context, TfLiteNode* node) { + return LogicalImpl(context, node, LogicalAnd); +} + +} // namespace + +TfLiteRegistration Register_LOGICAL_OR() { + return tflite::micro::RegisterOp(nullptr, nullptr, LogicalOrEval); +} + +TfLiteRegistration Register_LOGICAL_AND() { + return tflite::micro::RegisterOp(nullptr, nullptr, LogicalAndEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical.h new file mode 100644 index 000000000..e70e45762 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical.h @@ -0,0 +1,35 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_LOGICAL_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_LOGICAL_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { +// Input/output tensor index. +extern const int kLogicalInputTensor1; +extern const int kLogicalInputTensor2; +extern const int kLogicalOutputTensor; + +TfLiteStatus LogicalImpl(TfLiteContext* context, TfLiteNode* node, + bool (*func)(bool, bool)); + +bool LogicalOr(bool x, bool y); +bool LogicalAnd(bool x, bool y); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_LOGICAL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical_common.cc new file mode 100644 index 000000000..2612d3a4b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logical_common.cc @@ -0,0 +1,63 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/reference/binary_function.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/logical.h" + +namespace tflite { + +// Input/output tensor index. +const int kLogicalInputTensor1 = 0; +const int kLogicalInputTensor2 = 1; +const int kLogicalOutputTensor = 0; + +TfLiteStatus LogicalImpl(TfLiteContext* context, TfLiteNode* node, + bool (*func)(bool, bool)) { + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kLogicalInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kLogicalInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kLogicalOutputTensor); + + if (tflite::micro::HaveSameShapes(input1, input2)) { + reference_ops::BinaryFunction( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), func); + } else { + reference_ops::BroadcastBinaryFunction4DSlow( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), func); + } + + return kTfLiteOk; +} + +bool LogicalOr(bool x, bool y) { return x || y; } + +bool LogicalAnd(bool x, bool y) { return x && y; } + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic.cc new file mode 100644 index 000000000..108206ad3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic.cc @@ -0,0 +1,111 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/logistic.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/logistic.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +void* LogisticInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataLogistic)); +} + +TfLiteStatus LogisticEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kLogisticInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kLogisticOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataLogistic* data = static_cast(node->user_data); + + if (input->type == kTfLiteFloat32) { + switch (output->type) { + case kTfLiteFloat32: { + reference_ops::Logistic(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else if (input->type == kTfLiteInt16) { + switch (output->type) { + case kTfLiteInt16: { + reference_integer_ops::Logistic( + data->input_multiplier, data->input_left_shift, + NumElements(input->dims), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else if (input->type == kTfLiteInt8) { + switch (output->type) { + case kTfLiteInt8: { + reference_integer_ops::Logistic( + data->input_zero_point, data->input_range_radius, + data->input_multiplier, data->input_left_shift, + NumElements(input->dims), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else { + // TODO(b/141211002): Also support other data types once we have supported + // temporary tensors in TFLM. + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_LOGISTIC() { + return tflite::micro::RegisterOp(LogisticInit, LogisticPrepare, LogisticEval); +} +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic.h new file mode 100644 index 000000000..1de0cdab6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic.h @@ -0,0 +1,42 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_LOGISTIC_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_LOGISTIC_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { +extern const int kLogisticInputTensor; +extern const int kLogisticOutputTensor; + +struct OpDataLogistic { + int32_t input_zero_point; + int32_t input_range_radius; + int32_t input_multiplier; + int input_left_shift; +}; + +TfLiteStatus CalculateArithmeticOpDataLogistic(TfLiteContext* context, + TfLiteNode* node, + OpDataLogistic* data); + +TfLiteStatus LogisticPrepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite +#endif // TENSORFLOW_LITE_MICRO_KERNELS_LOGISTIC_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic_common.cc new file mode 100644 index 000000000..a79fd6bbf --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/logistic_common.cc @@ -0,0 +1,119 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h" +#include "tensorflow/lite/kernels/internal/reference/logistic.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/logistic.h" + +namespace tflite { +const int kLogisticInputTensor = 0; +const int kLogisticOutputTensor = 0; + +TfLiteStatus CalculateArithmeticOpDataLogistic(TfLiteContext* context, + TfLiteNode* node, + OpDataLogistic* data) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kLogisticInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kLogisticOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + if (input->type == kTfLiteInt8) { + TF_LITE_ENSURE_EQ(context, output->params.zero_point, + std::numeric_limits::min()); + + static constexpr int kInputIntegerBits = 4; + const double input_real_multiplier = + static_cast(input->params.scale) * + static_cast(1 << (31 - kInputIntegerBits)); + + data->input_zero_point = input->params.zero_point; + + const double q = std::frexp(input_real_multiplier, &data->input_left_shift); + data->input_multiplier = static_cast(TfLiteRound(q * (1ll << 31))); + + data->input_range_radius = + CalculateInputRadius(kInputIntegerBits, data->input_left_shift, 31); + } + + if (input->type == kTfLiteInt16) { + static constexpr int kInputIntegerBits = 3; + static constexpr int kOutputFractionalBits = 15; + + // See comments in TanhPrepare about requiring zero_point==0 + // and a power-of-two ("POT") scale. + + TF_LITE_ENSURE_EQ(context, input->params.zero_point, 0); + TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0); + + int input_scale_log2_rounded; + bool param_scale_pot = + CheckedLog2(input->params.scale, &input_scale_log2_rounded); + + data->input_left_shift = + (15 - kInputIntegerBits) + input_scale_log2_rounded; + param_scale_pot &= (data->input_left_shift == 0); + + if (param_scale_pot) { + data->input_multiplier = 0; + } else { + // Calculate multiplier to change input scale to 1/(3*4096) + // as required by the table lookup. + // In this scaling +/-2^17 represents +/-10.7 + double multiplier = + static_cast(input->params.scale) * 4096.0 * 3.0; + + data->input_left_shift = 0; + + while (multiplier <= 32767.0 / 2.0 && data->input_left_shift <= 30) { + data->input_left_shift++; + multiplier = multiplier * 2.0; + } + + data->input_multiplier = static_cast(multiplier); + } + + int output_scale_log2_rounded; + TF_LITE_ENSURE( + context, CheckedLog2(output->params.scale, &output_scale_log2_rounded)); + TF_LITE_ENSURE_EQ(context, output_scale_log2_rounded, + -kOutputFractionalBits); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus LogisticPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + OpDataLogistic* data = static_cast(node->user_data); + + return CalculateArithmeticOpDataLogistic(context, node, data); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_eval.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_eval.cc new file mode 100644 index 000000000..04952c1d0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_eval.cc @@ -0,0 +1,1459 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/lstm_eval.h" + +#include +#include +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/tanh.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/micro_tensor_utils.h" + +namespace tflite { +namespace { +// Calculates a single LSTM gate. +// +// Implements the following formula: (* is matrix multiply) +// gate = activate(W_input * input + W_aux * aux_input + +// W_peephole * cell + W_recurrent * prev_output + bias) +// with layer norm: +// gate = activate(W_norm * normalize(...) + bias) // not adding bias inside +// +// Activation is sigmoid except for the "cell" gate (configurable, usually tanh) +// +// Parameters: +// Input vectors (to LSTM): | Size: | Optional? +// input | n_input | +// aux_input | n_aux_input | y (bidir LSTM) +// Input vectors (persistent states): +// output_state | n_output | +// cell_state | n_cell | +// 'Constant' inputs: +// input_to_gate_weights | n_cell * n_input | +// aux_input_to_gate_weights | n_cell * n_aux_input | y (bidir LSTM) +// recurrent_to_gate_weights | n_cell * n_output | +// cell_to_gate_weights | n_cell | y (peephole) +// gate_bias | n_cell | +// layer_norm_coefficients | n_cell | y (layer norm) +// Output vector: +// gate | n_cell | +// Scalar parameters: +// n_batch - batch size / number of vectors +// n_input, n_aux_input, n_output, n_cell - size of vectors. +// activation - activation to use. +// is_input_all_zeros, is_aux_input_all_zeros - if input vectors are all zero. +// use_layer_norm - if doing layer norm LSTM. +inline void CalculateLstmGateFloat( + const float* input, const float* input_to_gate_weights, + const float* aux_input, const float* aux_input_to_gate_weights, + const float* output_state, const float* recurrent_to_gate_weights, + const float* cell_state, const float* cell_to_gate_weights, + const float* layer_norm_coefficients, const float* gate_bias, + const int n_batch, const int n_input, const int n_aux_input, + const int n_output, const int n_cell, + const TfLiteFusedActivation activation, float* gate, + const bool is_input_all_zeros, const bool is_aux_input_all_zeros) { + const bool use_peephole = (cell_to_gate_weights != nullptr); + const bool use_layer_norm = (layer_norm_coefficients != nullptr); + + // Initialize scratch buffers with bias for regular lstm or initialize with + // zero for layer norm lstm. + if (use_layer_norm) { + memset(gate, 0, n_cell * n_batch * sizeof(float)); + } else { + tflite::tensor_utils::VectorBatchVectorAssign(gate_bias, n_cell, n_batch, + gate); + } + // For each batch and cell: compute input_weight * input. + // Skip if input is all zeros. + if (!is_input_all_zeros) { + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + input_to_gate_weights, n_cell, n_input, input, n_batch, gate); + } + // For each batch and cell: compute aux_input_weight * aux_input. + // Skip if auxiliary input is not available or all zeros. + if (!is_aux_input_all_zeros) { + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + aux_input_to_gate_weights, n_cell, n_aux_input, aux_input, n_batch, + gate); + } + // For each batch and cell: compute recurrent_weight * output_state. + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + recurrent_to_gate_weights, n_cell, n_output, output_state, n_batch, gate); + // For each batch and cell: compute cell_weight .* cell_state (peephole LSTM) + if (use_peephole) { + tflite::tensor_utils::VectorBatchVectorCwiseProductAccumulate( + cell_to_gate_weights, n_cell, cell_state, n_batch, gate); + } + // Do layer normalization (if layer norm LSTM) + if (use_layer_norm) { + tflite::tensor_utils::MeanStddevNormalization(gate, gate, n_cell, n_batch); + tflite::tensor_utils::VectorBatchVectorCwiseProduct( + layer_norm_coefficients, n_cell, gate, n_batch, gate); + tflite::tensor_utils::VectorBatchVectorAdd(gate_bias, n_cell, n_batch, + gate); + } + // Apply activation + tflite::PortableApplyActivationToVector(gate, n_batch * n_cell, activation, + gate); +} + +// Updates the LSTM cell state, used by both float and hybrid LSTM versions. +// +// Implements the following formula: +// cell_state_new = clip(forget_gate * cell_state + input_gate * cell_gate) +// +// With CIFG LSTM, input gate is replaced by (1-forget_gate). +// +// Parameters: +// - n_batch, n_cell: sizes of vectors +// - cell_state: input/output vector, size n_batch*n_cell +// - input_gate: input vector, size n_batch*n_cell. +// - forget_gate: input/scratch vector, size n_batch*n_cell, modified with CIFG +// - cell_gate: input vector, size n_batch*n_cell. +// - use_cifg: use 1-forget_gate instead of input_gate. +// - clip: if > 0, clip the resulting cell state to [-clip, +clip]. +void UpdateLstmCellFloat(int n_batch, int n_cell, float* cell_state, + const float* input_gate, float* forget_gate, + const float* cell_gate, bool use_cifg, float clip) { + tflite::tensor_utils::VectorVectorCwiseProduct(forget_gate, cell_state, + n_batch * n_cell, cell_state); + + if (use_cifg) { + // With CIFG, input_gate = 1-forget_gate. Use the forget_gate array as + // scratch, as input_gate array is not allocated in this case. (Be careful + // not to write to the scratch before reading the forget gate data.) + float* scratch = forget_gate; + tflite::tensor_utils::Sub1Vector(forget_gate, n_batch * n_cell, scratch); + tflite::tensor_utils::VectorVectorCwiseProductAccumulate( + cell_gate, scratch, n_batch * n_cell, cell_state); + } else { + tflite::tensor_utils::VectorVectorCwiseProductAccumulate( + cell_gate, input_gate, n_batch * n_cell, cell_state); + } + if (clip > 0.0f) { + tflite::tensor_utils::CwiseClipping(cell_state, n_batch * n_cell, clip); + } +} + +// Calculates the output state tensor of an LSTM step. +// +// Implements the following formula: +// output_no_projection = output_gate .* activate(cell_state) +// (elementwise vector product) +// If no projection is used: +// output = output_state = output_no_projection +// With projection: +// output = output_state = clip(W*output_no_projection + bias) +// +// Output might not have a different 'stride' than n_batch, so we need to copy. +// +// Parameters: +// - n_batch: batches: the number of distinct vectors in each array. +// - n_cell, n_output: sizes of vectors. +// - cell_state, output_gate: input vectors, size n_batch*n_cell. +// - projection_weights, projection_weights_scale, projection_bias: +// constant inputs, describing projection matrix and bias. +// - proj_clip: if > 0, clip the output of the projection. +// - output_state: output vector, size n_batch*n_output. Must be contigous. +// - scratch: scratch area, size n_batch*n_cell. +void CalculateLstmOutputFloat(int n_batch, int n_cell, int n_output, + const float* cell_state, const float* output_gate, + TfLiteFusedActivation activation, + const float* projection_weights, + const float* projection_bias, + const float proj_clip, float* output_state, + float* scratch) { + tflite::PortableApplyActivationToVector(cell_state, n_batch * n_cell, + activation, scratch); + tflite::tensor_utils::VectorVectorCwiseProduct(output_gate, scratch, + n_batch * n_cell, scratch); + + const bool use_projection = (projection_weights != nullptr); + const bool use_projection_bias = (projection_bias != nullptr); + + if (use_projection) { + if (use_projection_bias) { + tflite::tensor_utils::VectorBatchVectorAssign(projection_bias, n_output, + n_batch, output_state); + } else { + memset(output_state, 0, n_batch * n_output * sizeof(float)); + } + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + projection_weights, n_output, n_cell, scratch, n_batch, output_state); + if (proj_clip > 0.0f) { + tflite::tensor_utils::CwiseClipping(output_state, n_batch * n_output, + proj_clip); + } + } else { + std::memcpy(output_state, scratch, n_batch * n_output * sizeof(float)); + } +} + +// Calculates a single LSTM gate, int8x8_16 version. +// Implements the same functionality as CalculateLstmGateFloat. +void CalculateLstmGateInteger8x8_16( + // Input and weights + const int8_t* input, const int8_t* input_to_gate_weights, + const int32_t* input_to_gate_bias, const int32_t input_to_gate_scale_a, + const int32_t input_to_gate_scale_b, + // Output state and weights + const int8_t* output_state, const int8_t* recurrent_to_gate_weights, + const int32_t* recurrent_to_gate_bias, + const int32_t recurrent_to_gate_scale_a, + const int32_t recurrent_to_gate_scale_b, + // Cell state and weights + const int16_t* cell_state, const int16_t* cell_to_gate_weights, + const int32_t cell_to_gate_scale_a, const int32_t cell_to_gate_scale_b, + // Layer normalization parameters (layer norm LSTM) + const int16_t* layer_norm_coefficients, const int32_t* layer_norm_bias, + const int32_t layer_norm_input_scale_a, + const int32_t layer_norm_input_scale_b, + const int32_t layer_norm_variance_guard, + // Array sizes + const int n_batch, const int n_input, const int n_output, const int n_cell, + const TfLiteFusedActivation activation, + // Output + int16_t* gate, + // Parameters for performance optimizations + // Scratch arrays + int32_t* scratch5) { + const bool use_peephole = (cell_to_gate_weights != nullptr); + const bool use_layer_norm = (layer_norm_coefficients != nullptr); + + // Initialize scratch buffers with zeros. Note that unlike float and hybrid + // versions, bias is only used in layer normalization. + memset(gate, 0, n_batch * n_cell * sizeof(int16_t)); + // For each batch and cell: compute input_weight * input. + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + input, input_to_gate_bias, input_to_gate_weights, input_to_gate_scale_a, + input_to_gate_scale_b, n_batch, n_input, n_cell, 0, scratch5, gate, + nullptr); + // Note: no aux_input. + + // For each batch and cell: compute recurrent_weight * output_state. + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + output_state, recurrent_to_gate_bias, recurrent_to_gate_weights, + recurrent_to_gate_scale_a, recurrent_to_gate_scale_b, n_batch, n_output, + n_cell, 0, scratch5, gate, nullptr); + // For each batch and cell: compute cell_weight * cell_state (peephole LSTM) + if (use_peephole) { + tflite::tensor_utils::VectorBatchVectorCwiseProductAccumulate( + cell_to_gate_weights, n_output, cell_state, n_batch, + cell_to_gate_scale_a, cell_to_gate_scale_b, gate); + } + // Do layer normalization (if layer norm LSTM) + if (use_layer_norm) { + tflite::tensor_utils::ApplyLayerNorm( + gate, layer_norm_coefficients, layer_norm_bias, + layer_norm_input_scale_a, layer_norm_input_scale_b, + layer_norm_variance_guard, n_batch, n_cell, gate); + } + // Apply activation + switch (activation) { + case kTfLiteActSigmoid: + + reference_integer_ops::Logistic( + 0 /*data->input_multiplier*/, 0 /*data->input_left_shift */, + n_batch * n_cell /*NumElements(input->dims)*/, + gate /* tflite::micro::GetTensorData(input) */, + gate /*tflite::micro::GetTensorData(output) */); + + break; + case kTfLiteActTanh: { + int32_t dims_data = n_batch * n_cell; + RuntimeShape tanh_inp_shape = RuntimeShape(1, &dims_data); + reference_integer_ops::Tanh(0, 0, tanh_inp_shape, gate, tanh_inp_shape, + gate); + } break; + default: + // Only Sigmoid or Tanh is used. + TFLITE_ASSERT_FALSE; + } +} + +// Updates the LSTM cell state, used by both integer LSTM versions. +// Also see UpdateLstmCellFloat. +// +// Parameters: +// - n_batch, n_cell: sizes of vectors +// - cell_state: input/output vector, size n_batch*n_cell +// - cell_state_scale: scaling factor of cell state. +// - input_gate: input vector, size n_batch*n_cell. +// - forget_gate: input/scratch vector, size n_batch*n_cell, always modified. +// - cell_gate: input vector, size n_batch*n_cell. +// - use_cifg: use 1-forget_gate instead of input_gate. +// - clip: if > 0, clip the resulting cell state to [-clip, +clip]. +void UpdateLstmCellInteger(int n_batch, int n_cell, int16_t* cell_state, + int32_t cell_state_scale, const int16_t* input_gate, + int16_t* forget_gate, const int16_t* cell_gate, + bool use_cifg, int16_t clip) { + // Use the forget_gate array as scratch, as input_gate array is not allocated + // in CIFG case. (Be careful not to write to the scratch before reading the + // forget gate data.) + int16_t* scratch = forget_gate; + + tflite::tensor_utils::CwiseMul(forget_gate, cell_state, n_batch, n_cell, 15, + cell_state); + if (use_cifg) { + tflite::tensor_utils::Sub1Vector(forget_gate, n_batch * n_cell, scratch); + tflite::tensor_utils::CwiseMul(scratch, cell_gate, n_batch, n_cell, + 30 + cell_state_scale, scratch); + } else { + tflite::tensor_utils::CwiseMul(input_gate, cell_gate, n_batch, n_cell, + 30 + cell_state_scale, scratch); + } + tflite::tensor_utils::CwiseAdd(cell_state, scratch, n_batch, n_cell, + cell_state); + + if (clip > 0) { + tflite::tensor_utils::CwiseClipping(cell_state, n_batch * n_cell, clip); + } +} + +// Calculates the output state tensor of an LSTM step. See Float and hybrid +// versions as well. +// +// Parameters: +// - n_batch: batches: the number of distinct vectors in each array. +// - n_cell, n_output: sizes of vectors. +// - cell_state, output_gate: input vectors, size n_batch*n_cell. +// - cell_state_scale: scaling of cell_state. +// - hidden_scale_[a|b]: effective scale of cell_state.*output_gate +// - hidden_zp: zero_point for cell_state.*output_gate +// - projection_weights, proj_scale_[a|b], projection_bias: +// constant inputs, describing projection matrix and bias. +// - output_state_zp: zero point of output_state. (Input, calibrated value.) +// - quantized_proj_clip: if > 0, clip the output of the projection. +// - output_state: output vector, size n_batch*n_output. Must be contigous. +// - scratch0: scratch area of size n_batch*n_cell +// - scratch1: scratch area of size n_batch*n_cell +// - scratch2: scratch area used by MatrixBatchVectorMultiplyAccumulate +void CalculateLstmOutputInteger8x8_16( + int n_batch, int n_cell, int n_output, int16_t* cell_state, + int32_t cell_state_scale, const int16_t* output_gate, + int32_t hidden_scale_a, int32_t hidden_scale_b, int32_t hidden_zp, + const int8_t* projection_weights, int32_t proj_scale_a, + int32_t proj_scale_b, const int32_t* projection_bias, + int32_t output_state_zp, int8_t quantized_proj_clip, int8_t* output_state, + int16_t* scratch0, int8_t* scratch1, int32_t* scratch2) { + // Note: unlike float/hybrid, the activation is always Tanh. + + { + int32_t tanh_input_left_shift = (15 + cell_state_scale) - 3; + int32_t dims_data = n_batch * n_cell; + if (tanh_input_left_shift < 0) /* handling negative shift value */ + { + int32_t i; + tanh_input_left_shift = -tanh_input_left_shift; + for (i = 0; i < dims_data; i++) { + cell_state[i] = cell_state[i] >> tanh_input_left_shift; + } + tanh_input_left_shift = 0; + } + RuntimeShape tanh_inp_shape = RuntimeShape(1, &dims_data); + reference_integer_ops::Tanh(0, tanh_input_left_shift, tanh_inp_shape, + cell_state, tanh_inp_shape, scratch0); + } + tflite::tensor_utils::CwiseMul(output_gate, scratch0, hidden_scale_a, + hidden_scale_b, n_batch, n_cell, hidden_zp, + scratch1); + + const bool use_projection = (projection_weights != nullptr); + + if (use_projection) { + // Note: no bias like in float/hybrid + memset(output_state, 0, n_batch * n_output * sizeof(int8_t)); + tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + scratch1, projection_bias, projection_weights, proj_scale_a, + proj_scale_b, n_batch, n_cell, n_output, output_state_zp, scratch2, + output_state, nullptr); + if (quantized_proj_clip > 0) { + tflite::tensor_utils::CwiseClipping(output_state, n_batch * n_output, + quantized_proj_clip); + } + } else { + std::memcpy(output_state, scratch1, n_batch * n_output * sizeof(int8_t)); + } +} + +// Performs an LSTM batch inference step for input specified by input_ptr. +// The LSTM cell is specified by the pointers to its weights (*_weights_ptr) and +// biases (*_bias_ptr), and buffers (*_scratch), along with additional +// parameters: +// - params: various LSTM params including activation, clipping, etc., +// - n_batch: size of batch, +// - n_cell: number of cells (or units), +// - n_input: the input size, +// - n_aux_input: the auxiliary input size. +// - n_output: the output size. +// - output_batch_leading_dim: the leading dimension of the output buffer. +// +// Input of size 'n_batch * n_input': +// input_ptr +// Input of size 'n_batch * n_aux_input': +// aux_input_ptr - optional (can be nullptr) +// +// LSTM weights: +// Input weights of size 'n_cell * n_input': +// input_to_input_weights - optional +// input_to_forget_weights +// input_to_cell_weights +// input_to_output_weights +// Auxiliary input weights of size 'n_cell * n_aux_input': +// aux_input_to_input_weights - optional +// aux_input_to_forget_weights - optional +// aux_input_to_cell_weights - optional +// aux_input_to_output_weights - optional +// Recurrent weights of size 'n_cell * n_output': +// recurrent_to_input_weights - optional +// recurrent_to_forget_weights +// recurrent_to_cell_weights +// recurrent_to_input_weights +// Peephole weights of size 'n_cell', representing diagonal matrices. +// cell_to_input_weights - optional +// cell_to_cell_weights - optional +// cell_to_output_weights - optional +// Projection weights of size 'n_output * n_cell' +// projection_weights_ptr - optional +// Gate biases of size 'n_cell': +// input_gate_bias_ptr - optional +// forget_gate_bias_ptr +// cell_gate_bias_ptr +// output_gate_bias_ptr +// +// Layer norm coefficients of size 'n_cell', representing diagonal matrices. +// input_layer_norm_coefficients_ptr - optional +// forget_layer_norm_coefficients_ptr - optional +// cell_layer_norm_coefficients_ptr - optional +// output_layer_norm_coefficients_ptr - optional +// +// The pointers to the cell and output state and the output are updated. +// +// The pointers input_ptr, aux_input_ptr, and output_ptr point to data aligned +// in batch_major order, and each step processes batch_size many inputs from +// input_ptr, and updates batch_size many cell and output states. +// +// The output_batch_dim is output.shape[-1], i.e. the outermost dimension of the +// output tensor, and in most cases will be equal to n_output. It is usually not +// when we want to store the LSTM output into a slice of the output tensor, e.g. +// for bidirectional LSTMs with merge_outputs. In this case, the batched +// operations cannot be used since they assume that the batched outputs are +// contiguous, and we manually loop over the batched outputs. +inline void LstmStepFloat( + const float* input_ptr, const float* input_to_input_weights_ptr, + const float* input_to_forget_weights_ptr, + const float* input_to_cell_weights_ptr, + const float* input_to_output_weights_ptr, const float* aux_input_ptr, + const float* aux_input_to_input_weights_ptr, + const float* aux_input_to_forget_weights_ptr, + const float* aux_input_to_cell_weights_ptr, + const float* aux_input_to_output_weights_ptr, + const float* recurrent_to_input_weights_ptr, + const float* recurrent_to_forget_weights_ptr, + const float* recurrent_to_cell_weights_ptr, + const float* recurrent_to_output_weights_ptr, + const float* cell_to_input_weights_ptr, + const float* cell_to_forget_weights_ptr, + const float* cell_to_output_weights_ptr, + const float* input_layer_norm_coefficients_ptr, + const float* forget_layer_norm_coefficients_ptr, + const float* cell_layer_norm_coefficients_ptr, + const float* output_layer_norm_coefficients_ptr, + const float* input_gate_bias_ptr, const float* forget_gate_bias_ptr, + const float* cell_gate_bias_ptr, const float* output_gate_bias_ptr, + const float* projection_weights_ptr, const float* projection_bias_ptr, + const TfLiteLSTMParams* params, int n_batch, int n_cell, int n_input, + int n_aux_input, int n_output, int output_batch_leading_dim, + float* output_state_ptr, float* cell_state_ptr, float* scratch0, + float* scratch1, float* scratch2, float* scratch3, float* output_ptr) { + // Since we have already checked that weights are all there or none, we can + // check the existence of only one to the get the condition. + const bool use_cifg = (input_to_input_weights_ptr == nullptr); + + // Make named scratch buffers. + float* input_gate_scratch = scratch0; + float* forget_gate_scratch = scratch1; + float* cell_gate_scratch = scratch2; + float* output_gate_scratch = scratch3; + + // Check if inputs are all zeros so we can skip some computations. + const bool is_input_all_zeros = + tflite::tensor_utils::IsZeroVector(input_ptr, n_batch * n_input); + const bool is_aux_input_all_zeros = + (aux_input_ptr == nullptr || tflite::tensor_utils::IsZeroVector( + aux_input_ptr, n_batch * n_aux_input)); + if (!use_cifg) { + // Calculate the input gate. (If not CIFG.) + CalculateLstmGateFloat( + input_ptr, input_to_input_weights_ptr, aux_input_ptr, + aux_input_to_input_weights_ptr, output_state_ptr, + recurrent_to_input_weights_ptr, cell_state_ptr, + cell_to_input_weights_ptr, input_layer_norm_coefficients_ptr, + input_gate_bias_ptr, n_batch, n_input, n_aux_input, n_output, n_cell, + /*activation=*/kTfLiteActSigmoid, input_gate_scratch, + is_input_all_zeros, is_aux_input_all_zeros); + } + // Calculate the forget gate. + CalculateLstmGateFloat( + input_ptr, input_to_forget_weights_ptr, aux_input_ptr, + aux_input_to_forget_weights_ptr, output_state_ptr, + recurrent_to_forget_weights_ptr, cell_state_ptr, + cell_to_forget_weights_ptr, forget_layer_norm_coefficients_ptr, + forget_gate_bias_ptr, n_batch, n_input, n_aux_input, n_output, n_cell, + /*activation=*/kTfLiteActSigmoid, forget_gate_scratch, is_input_all_zeros, + is_aux_input_all_zeros); + // Calculate the cell update gate. + CalculateLstmGateFloat(input_ptr, input_to_cell_weights_ptr, aux_input_ptr, + aux_input_to_cell_weights_ptr, output_state_ptr, + recurrent_to_cell_weights_ptr, /*cell_state=*/nullptr, + /*cell_to_gate_weights=*/nullptr, + cell_layer_norm_coefficients_ptr, cell_gate_bias_ptr, + n_batch, n_input, n_aux_input, n_output, n_cell, + params->activation, cell_gate_scratch, + is_input_all_zeros, is_aux_input_all_zeros); + // Update the cell state. + UpdateLstmCellFloat(n_batch, n_cell, cell_state_ptr, input_gate_scratch, + forget_gate_scratch, cell_gate_scratch, use_cifg, + params->cell_clip); + // Calculate output gate. + CalculateLstmGateFloat( + input_ptr, input_to_output_weights_ptr, aux_input_ptr, + aux_input_to_output_weights_ptr, output_state_ptr, + recurrent_to_output_weights_ptr, cell_state_ptr, + cell_to_output_weights_ptr, output_layer_norm_coefficients_ptr, + output_gate_bias_ptr, n_batch, n_input, n_aux_input, n_output, n_cell, + /*activation=*/kTfLiteActSigmoid, output_gate_scratch, is_input_all_zeros, + is_aux_input_all_zeros); + // Update the output state. + CalculateLstmOutputFloat(n_batch, n_cell, n_output, cell_state_ptr, + output_gate_scratch, params->activation, + projection_weights_ptr, projection_bias_ptr, + params->proj_clip, output_state_ptr, scratch2); + // Copy output state to the output. Note that the output's rows may not be + // contiguous (output_batch_leading_dim != n_output). + for (int b = 0; b < n_batch; b++) { + std::memcpy(output_ptr + b * output_batch_leading_dim, + output_state_ptr + b * n_output, n_output * sizeof(float)); + } +} + +// Fully quantized lstm kernel for 16 bit gate matmul output. +// +// Input tensor of size n_batch * n_input: +// input_ptr +// +// LSTM weights: +// Quantized input weights of size 'n_cell * n_input': +// input_to_input_weight_ptr - optional +// input_to_forget_weight_ptr - optional +// input_to_cell_weight_ptr - optional +// input_to_output_weight_ptr - optional +// +// Quantized recurrent weights of size 'n_cell * n_output': +// recurrent_to_input_weight_ptr - optional +// recurrent_to_forget_weights_ptr +// recurrent_to_cell_weights_ptr +// recurrent_to_input_weights_ptr +// +// Quantized peephole weights of size 'n_cell', representing diagonal matrices. +// cell_to_input_weights - optional +// cell_to_cell_weights - optional +// cell_to_output_weights - optional +// +// Quantized projection weights of size 'n_output * n_cell' +// projection_weight_ptr - optional +// +// Weight scales (scalars) for each of the weights above. +// effective_input_to_input_scale_a - optional +// effective_input_to_input_scale_b - optional +// effective_input_to_forget_scale_a +// effective_input_to_forget_scale_b +// effective_input_to_cell_scale_a +// effective_input_to_cell_scale_b +// effective_input_to_output_scale_a +// effective_input_to_output_scale_b +// effective_recurrent_to_input_scale_a - optional +// effective_recurrent_to_input_scale_b - optional +// effective_recurrent_to_forget_scale_a +// effective_recurrent_to_forget_scale_b +// effective_recurrent_to_cell_scale_a +// effective_recurrent_to_cell_scale_b +// effective_recurrent_to_output_scale_a +// effective_recurrent_to_output_scale_b +// effective_proj_scale_a - optional +// effective_proj_scale_b - optional +// +// Gate biases of size 'n_cell': +// input_gate_bias_ptr - optional +// forget_gate_bias_ptr +// cell_gate_bias_ptr +// output_gate_bias_ptr +// +// Layer norm coefficients of size 'n_cell', representing diagonal matrices. +// layer_norm_input_weight_ptr - optional +// layer_norm_forget_weight_ptr - optional +// layer_norm_cell_weight_ptr - optional +// layer_norm_output_weight_ptr - optional +// +// Layer norm scales of size 'n_cell'. +// layer_norm_input_scale_a - optional +// layer_norm_input_scale_b - optional +// layer_norm_forget_scale_a - optional +// layer_norm_forget_scale_b - optional +// layer_norm_cell_scale_a - optional +// layer_norm_cell_scale_b - optional +// layer_norm_output_scale_a - optional +// layer_norm_output_scale_b - optional +// +// Scalar values: +// quantized_cell_clip: quantized clip value for cell. +// quantized_proj_clip: quantized clip value for projection. +// cell_state_scale: the power of two scale for cell state. +// +// Zero points: +// output_state_zp: zero point of output state +// hidden_zp: zero point for hidden state. +// +// Temporary pre-allocated storage for the calculation. Each is of size n_cell * +// n_batch. +// scratch0 +// scratch1 +// scratch2 +// scratch3 +// scratch4 +// scratch5: this scratch buffer is created purely for optimizing the +// MatrixBatchVectorMultiplyAccumulate. +// +// Outputs: +// output_state_ptr - size 'n_batch * n_output' +// cell_state_ptr - size 'n_batch * n_cell' +// output_ptr - size 'n_batch * n_output' +// TODO(b/159947023): scratch0 is not used if (!cifg). Don't allocate then. +inline void LstmStepInteger8x8_16( + const int8_t* input_ptr, const int8_t* input_to_input_weight_ptr, + int32_t effective_input_to_input_scale_a, + int32_t effective_input_to_input_scale_b, + const int8_t* input_to_forget_weight_ptr, + int32_t effective_input_to_forget_scale_a, + int32_t effective_input_to_forget_scale_b, + const int8_t* input_to_cell_weight_ptr, + int32_t effective_input_to_cell_scale_a, + int32_t effective_input_to_cell_scale_b, + const int8_t* input_to_output_weight_ptr, + int32_t effective_input_to_output_scale_a, + int32_t effective_input_to_output_scale_b, + const int8_t* recurrent_to_input_weight_ptr, + int32_t effective_recurrent_to_input_scale_a, + int32_t effective_recurrent_to_input_scale_b, + const int8_t* recurrent_to_forget_weight_ptr, + int32_t effective_recurrent_to_forget_scale_a, + int32_t effective_recurrent_to_forget_scale_b, + const int8_t* recurrent_to_cell_weight_ptr, + int32_t effective_recurrent_to_cell_scale_a, + int32_t effective_recurrent_to_cell_scale_b, + const int8_t* recurrent_to_output_weight_ptr, + int32_t effective_recurrent_to_output_scale_a, + int32_t effective_recurrent_to_output_scale_b, + const int16_t* cell_to_input_weight_ptr, + int32_t effective_cell_to_input_scale_a, + int32_t effective_cell_to_input_scale_b, + const int16_t* cell_to_forget_weight_ptr, + int32_t effective_cell_to_forget_scale_a, + int32_t effective_cell_to_forget_scale_b, + const int16_t* cell_to_output_weight_ptr, + int32_t effective_cell_to_output_scale_a, + int32_t effective_cell_to_output_scale_b, + const int8_t* projection_weight_ptr, int32_t effective_proj_scale_a, + int32_t effective_proj_scale_b, int32_t hidden_zp, + int32_t effective_hidden_scale_a, int32_t effective_hidden_scale_b, + const int16_t* layer_norm_input_weight_ptr, + int32_t layer_norm_input_scale_a, int32_t layer_norm_input_scale_b, + const int16_t* layer_norm_forget_weight_ptr, + int32_t layer_norm_forget_scale_a, int32_t layer_norm_forget_scale_b, + const int16_t* layer_norm_cell_weight_ptr, int32_t layer_norm_cell_scale_a, + int32_t layer_norm_cell_scale_b, + const int16_t* layer_norm_output_weight_ptr, + int32_t layer_norm_output_scale_a, int32_t layer_norm_output_scale_b, + const int32_t* input_gate_bias_ptr, const int32_t* forget_gate_bias_ptr, + const int32_t* cell_gate_bias_ptr, const int32_t* output_gate_bias_ptr, + int16_t quantized_cell_clip, int8_t quantized_proj_clip, + int32_t cell_state_scale, int32_t input_variance_guard, + int32_t forget_variance_guard, int32_t cell_variance_guard, + int32_t output_variance_guard, + const int32_t* input_to_forget_effective_bias, + const int32_t* recurrent_to_forget_effective_bias, + const int32_t* input_to_cell_effective_bias, + const int32_t* recurrent_to_cell_effective_bias, + const int32_t* input_to_output_effective_bias, + const int32_t* recurrent_to_output_effective_bias, + const int32_t* input_to_input_effective_bias, + const int32_t* recurrent_to_input_effective_bias, + const int32_t* projection_effective_bias, int n_batch, int n_cell, + int n_input, int n_output, int8_t* output_state_ptr, + int32_t output_state_zp, int16_t* cell_state_ptr, int8_t* output_ptr, + int16_t* scratch0, int16_t* scratch1, int16_t* scratch2, int16_t* scratch3, + int8_t* scratch4, int32_t* scratch5) { + // Make named scratch buffers for the different gates. + int16_t* input_gate_scratch = scratch0; + int16_t* forget_gate_scratch = scratch1; + int16_t* cell_gate_scratch = scratch2; + int16_t* output_gate_scratch = scratch3; + + // Since we have already checked that weights are all there or none, we + // can check the existence of only one to the get the condition. + const bool use_cifg = (input_to_input_weight_ptr == nullptr); + + // Check for nullptrs. + TFLITE_DCHECK(input_to_forget_effective_bias); + TFLITE_DCHECK(recurrent_to_forget_effective_bias); + TFLITE_DCHECK(input_to_cell_effective_bias); + TFLITE_DCHECK(recurrent_to_cell_effective_bias); + TFLITE_DCHECK(input_to_output_effective_bias); + TFLITE_DCHECK(recurrent_to_output_effective_bias); + if (!use_cifg) { + TFLITE_DCHECK(input_to_input_effective_bias); + TFLITE_DCHECK(recurrent_to_input_effective_bias); + } + const bool use_projection = (projection_weight_ptr != nullptr); + if (use_projection) { + TFLITE_DCHECK(projection_effective_bias); + } + if (!use_cifg) { + // Calculate the input gate. (If not CIFG.) + CalculateLstmGateInteger8x8_16( + input_ptr, input_to_input_weight_ptr, input_to_input_effective_bias, + effective_input_to_input_scale_a, effective_input_to_input_scale_b, + output_state_ptr, recurrent_to_input_weight_ptr, + recurrent_to_input_effective_bias, effective_recurrent_to_input_scale_a, + effective_recurrent_to_input_scale_b, cell_state_ptr, + cell_to_input_weight_ptr, effective_cell_to_input_scale_a, + effective_cell_to_input_scale_b, layer_norm_input_weight_ptr, + input_gate_bias_ptr, layer_norm_input_scale_a, layer_norm_input_scale_b, + input_variance_guard, n_batch, n_input, n_output, n_cell, + kTfLiteActSigmoid, input_gate_scratch, scratch5); + } + // Calculate the forget gate. + CalculateLstmGateInteger8x8_16( + input_ptr, input_to_forget_weight_ptr, input_to_forget_effective_bias, + effective_input_to_forget_scale_a, effective_input_to_forget_scale_b, + output_state_ptr, recurrent_to_forget_weight_ptr, + recurrent_to_forget_effective_bias, effective_recurrent_to_forget_scale_a, + effective_recurrent_to_forget_scale_b, cell_state_ptr, + cell_to_forget_weight_ptr, effective_cell_to_forget_scale_a, + effective_cell_to_forget_scale_b, layer_norm_forget_weight_ptr, + forget_gate_bias_ptr, layer_norm_forget_scale_a, + layer_norm_forget_scale_b, forget_variance_guard, n_batch, n_input, + n_output, n_cell, kTfLiteActSigmoid, forget_gate_scratch, scratch5); + // Calculate the cell update gate. + CalculateLstmGateInteger8x8_16( + input_ptr, input_to_cell_weight_ptr, input_to_cell_effective_bias, + effective_input_to_cell_scale_a, effective_input_to_cell_scale_b, + output_state_ptr, recurrent_to_cell_weight_ptr, + recurrent_to_cell_effective_bias, effective_recurrent_to_cell_scale_a, + effective_recurrent_to_cell_scale_b, cell_state_ptr, + /*cell_to_gate_weights=*/nullptr, /*cell_to_gate_scale_a=*/0, + /*cell_to_gate_scale_b=*/0, layer_norm_cell_weight_ptr, + cell_gate_bias_ptr, layer_norm_cell_scale_a, layer_norm_cell_scale_b, + cell_variance_guard, n_batch, n_input, n_output, n_cell, kTfLiteActTanh, + cell_gate_scratch, scratch5); + // Update the cell state. + UpdateLstmCellInteger(n_batch, n_cell, cell_state_ptr, cell_state_scale, + input_gate_scratch, forget_gate_scratch, + cell_gate_scratch, use_cifg, quantized_cell_clip); + // Calculate the output gate. + CalculateLstmGateInteger8x8_16( + input_ptr, input_to_output_weight_ptr, input_to_output_effective_bias, + effective_input_to_output_scale_a, effective_input_to_output_scale_b, + output_state_ptr, recurrent_to_output_weight_ptr, + recurrent_to_output_effective_bias, effective_recurrent_to_output_scale_a, + effective_recurrent_to_output_scale_b, cell_state_ptr, + cell_to_output_weight_ptr, effective_cell_to_output_scale_a, + effective_cell_to_output_scale_b, layer_norm_output_weight_ptr, + output_gate_bias_ptr, layer_norm_output_scale_a, + layer_norm_output_scale_b, output_variance_guard, n_batch, n_input, + n_output, n_cell, kTfLiteActSigmoid, output_gate_scratch, scratch5); + // Update the output state. + CalculateLstmOutputInteger8x8_16( + n_batch, n_cell, n_output, cell_state_ptr, cell_state_scale, + output_gate_scratch, effective_hidden_scale_a, effective_hidden_scale_b, + hidden_zp, projection_weight_ptr, effective_proj_scale_a, + effective_proj_scale_b, projection_effective_bias, output_state_zp, + quantized_proj_clip, output_state_ptr, scratch0, scratch4, scratch5); + // Copy output state to the output. Note that unlike float or hybrid, output + // is always contiguous. + std::memcpy(output_ptr, output_state_ptr, + n_batch * n_output * sizeof(int8_t)); +} + +} // namespace + +TfLiteStatus EvalFloatLstm( + const TfLiteEvalTensor* input, + const TfLiteEvalTensor* input_to_input_weights, + const TfLiteEvalTensor* input_to_forget_weights, + const TfLiteEvalTensor* input_to_cell_weights, + const TfLiteEvalTensor* input_to_output_weights, + const TfLiteEvalTensor* recurrent_to_input_weights, + const TfLiteEvalTensor* recurrent_to_forget_weights, + const TfLiteEvalTensor* recurrent_to_cell_weights, + const TfLiteEvalTensor* recurrent_to_output_weights, + const TfLiteEvalTensor* cell_to_input_weights, + const TfLiteEvalTensor* cell_to_forget_weights, + const TfLiteEvalTensor* cell_to_output_weights, + const TfLiteEvalTensor* input_layer_norm_coefficients, + const TfLiteEvalTensor* forget_layer_norm_coefficients, + const TfLiteEvalTensor* cell_layer_norm_coefficients, + const TfLiteEvalTensor* output_layer_norm_coefficients, + const TfLiteEvalTensor* aux_input, + const TfLiteEvalTensor* aux_input_to_input_weights, + const TfLiteEvalTensor* aux_input_to_forget_weights, + const TfLiteEvalTensor* aux_input_to_cell_weights, + const TfLiteEvalTensor* aux_input_to_output_weights, + const TfLiteEvalTensor* input_gate_bias, + const TfLiteEvalTensor* forget_gate_bias, + const TfLiteEvalTensor* cell_gate_bias, + const TfLiteEvalTensor* output_gate_bias, + const TfLiteEvalTensor* projection_weights, + const TfLiteEvalTensor* projection_bias, const TfLiteLSTMParams* params, + bool forward_sequence, bool time_major, int output_offset, + float* scratch_buffer, TfLiteEvalTensor* output_state, + TfLiteEvalTensor* cell_state, TfLiteEvalTensor* output) { + TFLITE_DCHECK(input->dims->size >= 2 && input->dims->size <= 3); + int max_time, n_batch; + if (input->dims->size == 3) { + max_time = (time_major) ? input->dims->data[0] : input->dims->data[1]; + n_batch = (time_major) ? input->dims->data[1] : input->dims->data[0]; + } else { + max_time = 1; + n_batch = input->dims->data[0]; + } + const int n_input = input->dims->data[input->dims->size - 1]; + const int aux_input_size = + (aux_input) ? aux_input->dims->data[aux_input->dims->size - 1] : 0; + + // n_cell and n_output will be the same size when there is no projection. + const int n_cell = input_to_output_weights->dims->data[0]; + const int n_output = recurrent_to_output_weights->dims->data[1]; + + // Since we have already checked that weights are all there or none, we can + // check the existence of only one to the get the condition. + const bool use_cifg = (input_to_input_weights == nullptr); + + // Index the scratch buffers pointers to the global scratch buffer. + float* input_gate_scratch = nullptr; + float* cell_gate_scratch = nullptr; + float* forget_gate_scratch = nullptr; + float* output_gate_scratch = nullptr; + if (use_cifg) { + cell_gate_scratch = scratch_buffer; + forget_gate_scratch = scratch_buffer + n_cell * n_batch; + output_gate_scratch = scratch_buffer + 2 * n_cell * n_batch; + } else { + input_gate_scratch = scratch_buffer; + cell_gate_scratch = scratch_buffer + n_cell * n_batch; + forget_gate_scratch = scratch_buffer + 2 * n_cell * n_batch; + output_gate_scratch = scratch_buffer + 3 * n_cell * n_batch; + } + + const int output_batch_leading_dim = + output->dims->data[output->dims->size - 1]; + if (time_major) { + // Loop through the sequence. + const int input_step = n_batch * n_input; + const int output_step = n_batch * output_batch_leading_dim; + for (int t = 0; t < max_time; t++) { + // If this is the forward_sequence, step forward, otherwise step + // backwards. + const int t_rel = forward_sequence ? t : max_time - t - 1; + const float* input_ptr = + tflite::micro::GetTensorData(input) + t_rel * input_step; + const float* aux_input_ptr = nullptr; + if (aux_input) { + aux_input_ptr = + tflite::micro::GetTensorData(aux_input) + t_rel * input_step; + } + float* output_ptr = tflite::micro::GetTensorData(output) + + t_rel * output_step + output_offset; + + LstmStepFloat( + input_ptr, + input_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_input_weights), + input_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_forget_weights), + input_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_cell_weights), + input_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_output_weights), + aux_input_ptr, + aux_input_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(aux_input_to_input_weights), + aux_input_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + aux_input_to_forget_weights), + aux_input_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(aux_input_to_cell_weights), + aux_input_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + aux_input_to_output_weights), + recurrent_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(recurrent_to_input_weights), + recurrent_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_forget_weights), + recurrent_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(recurrent_to_cell_weights), + recurrent_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_output_weights), + cell_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_input_weights), + cell_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_forget_weights), + cell_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_output_weights), + input_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + input_layer_norm_coefficients), + forget_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + forget_layer_norm_coefficients), + cell_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + cell_layer_norm_coefficients), + output_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + output_layer_norm_coefficients), + input_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_gate_bias), + forget_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(forget_gate_bias), + cell_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_gate_bias), + output_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(output_gate_bias), + projection_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(projection_weights), + projection_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(projection_bias), + params, n_batch, n_cell, n_input, aux_input_size, n_output, + output_batch_leading_dim, + tflite::micro::GetTensorData(output_state), + tflite::micro::GetTensorData(cell_state), input_gate_scratch, + forget_gate_scratch, cell_gate_scratch, output_gate_scratch, + output_ptr); + } + } else { + for (int b = 0; b < n_batch; b++) { + const int input_step = n_input; + const int output_step = output_batch_leading_dim; + for (int t = 0; t < max_time; t++) { + // If this is the forward_sequence, step forward, otherwise step + // backwards. + const int t_rel = forward_sequence ? t : max_time - t - 1; + const int time_offset = b * max_time + t_rel; + const float* input_ptr = tflite::micro::GetTensorData(input) + + time_offset * input_step; + const float* aux_input_ptr = nullptr; + if (aux_input) { + aux_input_ptr = tflite::micro::GetTensorData(aux_input) + + time_offset * input_step; + } + float* output_ptr = tflite::micro::GetTensorData(output) + + time_offset * output_step + output_offset; + + // Offset the {output,cell}_state pointers to the right batch. + float* output_state_ptr = + tflite::micro::GetTensorData(output_state) + + b * output_batch_leading_dim; + float* cell_state_ptr = + tflite::micro::GetTensorData(cell_state) + b * n_cell; + // Offset the scratch pointers to the right batch. + float* input_gate_scratch_ptr = + input_gate_scratch ? input_gate_scratch + b * n_cell : nullptr; + float* forget_gate_scratch_ptr = forget_gate_scratch + b * n_cell; + float* cell_gate_scratch_ptr = cell_gate_scratch + b * n_cell; + float* output_gate_scratch_ptr = output_gate_scratch + b * n_cell; + + LstmStepFloat( + input_ptr, + input_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_input_weights), + input_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_forget_weights), + input_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_cell_weights), + input_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_output_weights), + aux_input_ptr, + aux_input_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + aux_input_to_input_weights), + aux_input_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + aux_input_to_forget_weights), + aux_input_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + aux_input_to_cell_weights), + aux_input_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + aux_input_to_output_weights), + recurrent_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_input_weights), + recurrent_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_forget_weights), + recurrent_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_cell_weights), + recurrent_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_output_weights), + cell_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_input_weights), + cell_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_forget_weights), + cell_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_output_weights), + input_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + input_layer_norm_coefficients), + forget_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + forget_layer_norm_coefficients), + cell_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + cell_layer_norm_coefficients), + output_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + output_layer_norm_coefficients), + input_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_gate_bias), + forget_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(forget_gate_bias), + cell_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_gate_bias), + output_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(output_gate_bias), + projection_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(projection_weights), + projection_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(projection_bias), + params, + /*n_batch=*/1, n_cell, n_input, aux_input_size, n_output, + output_batch_leading_dim, output_state_ptr, cell_state_ptr, + input_gate_scratch_ptr, forget_gate_scratch_ptr, + cell_gate_scratch_ptr, output_gate_scratch_ptr, output_ptr); + } + } + } + return kTfLiteOk; +} + +TfLiteStatus EvalInteger8x8_16Lstm( + const TfLiteEvalTensor* input, + const TfLiteEvalTensor* input_to_input_weights, + const TfLiteEvalTensor* input_to_forget_weights, + const TfLiteEvalTensor* input_to_cell_weights, + const TfLiteEvalTensor* input_to_output_weights, + const TfLiteEvalTensor* recurrent_to_input_weights, + const TfLiteEvalTensor* recurrent_to_forget_weights, + const TfLiteEvalTensor* recurrent_to_cell_weights, + const TfLiteEvalTensor* recurrent_to_output_weights, + const TfLiteEvalTensor* cell_to_input_weights, + const TfLiteEvalTensor* cell_to_forget_weights, + const TfLiteEvalTensor* cell_to_output_weights, + const TfLiteEvalTensor* input_layer_norm_coefficients, + const TfLiteEvalTensor* forget_layer_norm_coefficients, + const TfLiteEvalTensor* cell_layer_norm_coefficients, + const TfLiteEvalTensor* output_layer_norm_coefficients, + const TfLiteEvalTensor* input_gate_bias, + const TfLiteEvalTensor* forget_gate_bias, + const TfLiteEvalTensor* cell_gate_bias, + const TfLiteEvalTensor* output_gate_bias, + const TfLiteEvalTensor* projection_weights, + const TfLiteEvalTensor* projection_bias, const TfLiteLSTMParams* params, + bool forward_sequence, bool time_major, + const IntegerLstmParameter* integer_lstm_param, int32_t output_state_zp, + TfLiteEvalTensor* output_state, TfLiteEvalTensor* cell_state, + TfLiteEvalTensor* output, int16_t* scratch0, int16_t* scratch1, + int16_t* scratch2, int16_t* scratch3, int8_t* scratch4, int32_t* scratch5) { + TFLITE_DCHECK(input->dims->size >= 2 && input->dims->size <= 3); + const int n_input = input->dims->data[input->dims->size - 1]; + int max_time, n_batch; + if (input->dims->size == 2) { + max_time = 1; + n_batch = input->dims->data[0]; + } else { + max_time = (time_major) ? input->dims->data[0] : input->dims->data[1]; + n_batch = (time_major) ? input->dims->data[1] : input->dims->data[0]; + } + + // n_cell and n_output will be the same size when there is no projection. + const int n_cell = input_to_output_weights->dims->data[0]; + const int n_output = recurrent_to_output_weights->dims->data[1]; + + // Get params for time/batch/sequence. + const int output_batch_leading_dim = + output->dims->data[output->dims->size - 1]; + + if (time_major) { + const int input_step = n_batch * n_input; + const int output_step = n_batch * output_batch_leading_dim; + for (int t = 0; t < max_time; t++) { + const int t_rel = t; + int8_t* output_ptr = + tflite::micro::GetTensorData(output) + t_rel * output_step; + const int8_t* input_ptr = + tflite::micro::GetTensorData(input) + t_rel * input_step; + LstmStepInteger8x8_16( + input_ptr, + input_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_input_weights), + integer_lstm_param->effective_input_to_input_scale_a, + integer_lstm_param->effective_input_to_input_scale_b, + input_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_forget_weights), + integer_lstm_param->effective_input_to_forget_scale_a, + integer_lstm_param->effective_input_to_forget_scale_b, + input_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_cell_weights), + integer_lstm_param->effective_input_to_cell_scale_a, + integer_lstm_param->effective_input_to_cell_scale_b, + input_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_output_weights), + integer_lstm_param->effective_input_to_output_scale_a, + integer_lstm_param->effective_input_to_output_scale_b, + recurrent_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_input_weights), + integer_lstm_param->effective_recurrent_to_input_scale_a, + integer_lstm_param->effective_recurrent_to_input_scale_b, + recurrent_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_forget_weights), + integer_lstm_param->effective_recurrent_to_forget_scale_a, + integer_lstm_param->effective_recurrent_to_forget_scale_b, + recurrent_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(recurrent_to_cell_weights), + integer_lstm_param->effective_recurrent_to_cell_scale_a, + integer_lstm_param->effective_recurrent_to_cell_scale_b, + recurrent_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_output_weights), + integer_lstm_param->effective_recurrent_to_output_scale_a, + integer_lstm_param->effective_recurrent_to_output_scale_b, + cell_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_input_weights), + integer_lstm_param->effective_cell_to_input_scale_a, + integer_lstm_param->effective_cell_to_input_scale_b, + cell_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_forget_weights), + integer_lstm_param->effective_cell_to_forget_scale_a, + integer_lstm_param->effective_cell_to_forget_scale_b, + cell_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_output_weights), + integer_lstm_param->effective_cell_to_output_scale_a, + integer_lstm_param->effective_cell_to_output_scale_b, + projection_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(projection_weights), + integer_lstm_param->effective_proj_scale_a, + integer_lstm_param->effective_proj_scale_b, + integer_lstm_param->hidden_zp, + integer_lstm_param->effective_hidden_scale_a, + integer_lstm_param->effective_hidden_scale_b, + input_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + input_layer_norm_coefficients), + integer_lstm_param->layer_norm_input_scale_a, + integer_lstm_param->layer_norm_input_scale_b, + forget_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + forget_layer_norm_coefficients), + integer_lstm_param->layer_norm_forget_scale_a, + integer_lstm_param->layer_norm_forget_scale_b, + cell_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + cell_layer_norm_coefficients), + integer_lstm_param->layer_norm_cell_scale_a, + integer_lstm_param->layer_norm_cell_scale_b, + output_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + output_layer_norm_coefficients), + integer_lstm_param->layer_norm_output_scale_a, + integer_lstm_param->layer_norm_output_scale_b, + input_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_gate_bias), + forget_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(forget_gate_bias), + cell_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_gate_bias), + output_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(output_gate_bias), + integer_lstm_param->quantized_cell_clip, + integer_lstm_param->quantized_proj_clip, + integer_lstm_param->cell_scale, + integer_lstm_param->input_variance_guard, + integer_lstm_param->forget_variance_guard, + integer_lstm_param->cell_variance_guard, + integer_lstm_param->output_variance_guard, + integer_lstm_param->input_to_forget_effective_bias, + integer_lstm_param->recurrent_to_forget_effective_bias, + integer_lstm_param->input_to_cell_effective_bias, + integer_lstm_param->recurrent_to_cell_effective_bias, + integer_lstm_param->input_to_output_effective_bias, + integer_lstm_param->recurrent_to_output_effective_bias, + integer_lstm_param->input_to_input_effective_bias, + integer_lstm_param->recurrent_to_input_effective_bias, + integer_lstm_param->projection_effective_bias, n_batch, n_cell, + n_input, n_output, tflite::micro::GetTensorData(output_state), + output_state_zp, tflite::micro::GetTensorData(cell_state), + output_ptr, scratch0, scratch1, scratch2, scratch3, scratch4, + scratch5); + } + } else { + for (int b = 0; b < n_batch; b++) { + const int input_step = n_input; + const int output_step = output_batch_leading_dim; + for (int t = 0; t < max_time; t++) { + // If this is the forward_sequence, step forward, otherwise step + // backwards. + const int t_rel = forward_sequence ? t : max_time - t - 1; + const int time_offset = b * max_time + t_rel; + const int8_t* input_ptr = tflite::micro::GetTensorData(input) + + time_offset * input_step; + int8_t* output_ptr = tflite::micro::GetTensorData(output) + + time_offset * output_step; + + // Offset the {output,cell}_state pointers to the right batch. + int8_t* output_state_ptr = + tflite::micro::GetTensorData(output_state) + + b * output_batch_leading_dim; + int16_t* cell_state_ptr = + tflite::micro::GetTensorData(cell_state) + b * n_cell; + + LstmStepInteger8x8_16( + input_ptr, + input_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_input_weights), + integer_lstm_param->effective_input_to_input_scale_a, + integer_lstm_param->effective_input_to_input_scale_b, + input_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_forget_weights), + integer_lstm_param->effective_input_to_forget_scale_a, + integer_lstm_param->effective_input_to_forget_scale_b, + input_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_cell_weights), + integer_lstm_param->effective_input_to_cell_scale_a, + integer_lstm_param->effective_input_to_cell_scale_b, + input_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_to_output_weights), + integer_lstm_param->effective_input_to_output_scale_a, + integer_lstm_param->effective_input_to_output_scale_b, + recurrent_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_input_weights), + integer_lstm_param->effective_recurrent_to_input_scale_a, + integer_lstm_param->effective_recurrent_to_input_scale_b, + recurrent_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_forget_weights), + integer_lstm_param->effective_recurrent_to_forget_scale_a, + integer_lstm_param->effective_recurrent_to_forget_scale_b, + recurrent_to_cell_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_cell_weights), + integer_lstm_param->effective_recurrent_to_cell_scale_a, + integer_lstm_param->effective_recurrent_to_cell_scale_b, + recurrent_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData( + recurrent_to_output_weights), + integer_lstm_param->effective_recurrent_to_output_scale_a, + integer_lstm_param->effective_recurrent_to_output_scale_b, + cell_to_input_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_input_weights), + integer_lstm_param->effective_cell_to_input_scale_a, + integer_lstm_param->effective_cell_to_input_scale_b, + cell_to_forget_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_forget_weights), + integer_lstm_param->effective_cell_to_forget_scale_a, + integer_lstm_param->effective_cell_to_forget_scale_b, + cell_to_output_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_to_output_weights), + integer_lstm_param->effective_cell_to_output_scale_a, + integer_lstm_param->effective_cell_to_output_scale_b, + projection_weights == nullptr + ? nullptr + : tflite::micro::GetTensorData(projection_weights), + integer_lstm_param->effective_proj_scale_a, + integer_lstm_param->effective_proj_scale_b, + integer_lstm_param->hidden_zp, + integer_lstm_param->effective_hidden_scale_a, + integer_lstm_param->effective_hidden_scale_b, + input_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + input_layer_norm_coefficients), + integer_lstm_param->layer_norm_input_scale_a, + integer_lstm_param->layer_norm_input_scale_b, + forget_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + forget_layer_norm_coefficients), + integer_lstm_param->layer_norm_forget_scale_a, + integer_lstm_param->layer_norm_forget_scale_b, + cell_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + cell_layer_norm_coefficients), + integer_lstm_param->layer_norm_cell_scale_a, + integer_lstm_param->layer_norm_cell_scale_b, + output_layer_norm_coefficients == nullptr + ? nullptr + : tflite::micro::GetTensorData( + output_layer_norm_coefficients), + integer_lstm_param->layer_norm_output_scale_a, + integer_lstm_param->layer_norm_output_scale_b, + input_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(input_gate_bias), + forget_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(forget_gate_bias), + cell_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(cell_gate_bias), + output_gate_bias == nullptr + ? nullptr + : tflite::micro::GetTensorData(output_gate_bias), + integer_lstm_param->quantized_cell_clip, + integer_lstm_param->quantized_proj_clip, + integer_lstm_param->cell_scale, + integer_lstm_param->input_variance_guard, + integer_lstm_param->forget_variance_guard, + integer_lstm_param->cell_variance_guard, + integer_lstm_param->output_variance_guard, + integer_lstm_param->input_to_forget_effective_bias, + integer_lstm_param->recurrent_to_forget_effective_bias, + integer_lstm_param->input_to_cell_effective_bias, + integer_lstm_param->recurrent_to_cell_effective_bias, + integer_lstm_param->input_to_output_effective_bias, + integer_lstm_param->recurrent_to_output_effective_bias, + integer_lstm_param->input_to_input_effective_bias, + integer_lstm_param->recurrent_to_input_effective_bias, + integer_lstm_param->projection_effective_bias, /*n_batch=*/1, + n_cell, n_input, n_output, output_state_ptr, output_state_zp, + cell_state_ptr, output_ptr, scratch0, scratch1, scratch2, scratch3, + scratch4, scratch5); + } + } + } + + return kTfLiteOk; +} + +} // namespace tflite \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_eval.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_eval.h new file mode 100644 index 000000000..262735dd0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_eval.h @@ -0,0 +1,154 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_LSTM_EVAL_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_LSTM_EVAL_H_ + +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// Pamameters for integer LSTM. +// Consider split this into two Integer Parameters if more fields are added. +struct IntegerLstmParameter { + int32_t effective_input_to_input_scale_a; + int32_t effective_input_to_input_scale_b; + int32_t effective_recurrent_to_input_scale_a; + int32_t effective_recurrent_to_input_scale_b; + int32_t effective_cell_to_input_scale_a; + int32_t effective_cell_to_input_scale_b; + int32_t effective_input_to_forget_scale_a; + int32_t effective_input_to_forget_scale_b; + int32_t effective_recurrent_to_forget_scale_a; + int32_t effective_recurrent_to_forget_scale_b; + int32_t effective_cell_to_forget_scale_a; + int32_t effective_cell_to_forget_scale_b; + int32_t effective_input_to_cell_scale_a; + int32_t effective_input_to_cell_scale_b; + int32_t effective_recurrent_to_cell_scale_a; + int32_t effective_recurrent_to_cell_scale_b; + int32_t effective_input_to_output_scale_a; + int32_t effective_input_to_output_scale_b; + int32_t effective_recurrent_to_output_scale_a; + int32_t effective_recurrent_to_output_scale_b; + int32_t effective_cell_to_output_scale_a; + int32_t effective_cell_to_output_scale_b; + int32_t effective_proj_scale_a; + int32_t effective_proj_scale_b; + int32_t effective_hidden_scale_a; + int32_t effective_hidden_scale_b; + int32_t layer_norm_input_scale_a; + int32_t layer_norm_input_scale_b; + int32_t layer_norm_forget_scale_a; + int32_t layer_norm_forget_scale_b; + int32_t layer_norm_cell_scale_a; + int32_t layer_norm_cell_scale_b; + int32_t layer_norm_output_scale_a; + int32_t layer_norm_output_scale_b; + // Quantized clip value for cell and projection. Zero value means no clipping. + int16_t quantized_cell_clip; + int8_t quantized_proj_clip; + int32_t hidden_zp; + int32_t cell_scale; + + int32_t input_variance_guard; + int32_t forget_variance_guard; + int32_t cell_variance_guard; + int32_t output_variance_guard; + + // Pre-calculate bias + zero_point * weight. + int32_t* input_to_forget_effective_bias; + int32_t* recurrent_to_forget_effective_bias; + int32_t* input_to_cell_effective_bias; + int32_t* recurrent_to_cell_effective_bias; + int32_t* input_to_output_effective_bias; + int32_t* recurrent_to_output_effective_bias; + int32_t* input_to_input_effective_bias; + int32_t* recurrent_to_input_effective_bias; + int32_t* projection_effective_bias; + + // Scale and zero point for intermediate tensors. + // Used only in the 8x8_8 case. + int32_t intermediate_scale_a[8]; + int32_t intermediate_scale_b[8]; + int32_t intermediate_zp[12]; +}; + +TfLiteStatus EvalFloatLstm( + const TfLiteEvalTensor* input, + const TfLiteEvalTensor* input_to_input_weights, + const TfLiteEvalTensor* input_to_forget_weights, + const TfLiteEvalTensor* input_to_cell_weights, + const TfLiteEvalTensor* input_to_output_weights, + const TfLiteEvalTensor* recurrent_to_input_weights, + const TfLiteEvalTensor* recurrent_to_forget_weights, + const TfLiteEvalTensor* recurrent_to_cell_weights, + const TfLiteEvalTensor* recurrent_to_output_weights, + const TfLiteEvalTensor* cell_to_input_weights, + const TfLiteEvalTensor* cell_to_forget_weights, + const TfLiteEvalTensor* cell_to_output_weights, + const TfLiteEvalTensor* input_layer_norm_coefficients, + const TfLiteEvalTensor* forget_layer_norm_coefficients, + const TfLiteEvalTensor* cell_layer_norm_coefficients, + const TfLiteEvalTensor* output_layer_norm_coefficients, + const TfLiteEvalTensor* aux_input, + const TfLiteEvalTensor* aux_input_to_input_weights, + const TfLiteEvalTensor* aux_input_to_forget_weights, + const TfLiteEvalTensor* aux_input_to_cell_weights, + const TfLiteEvalTensor* aux_input_to_output_weights, + const TfLiteEvalTensor* input_gate_bias, + const TfLiteEvalTensor* forget_gate_bias, + const TfLiteEvalTensor* cell_gate_bias, + const TfLiteEvalTensor* output_gate_bias, + const TfLiteEvalTensor* projection_weights, + const TfLiteEvalTensor* projection_bias, const TfLiteLSTMParams* params, + bool forward_sequence, bool time_major, int output_offset, + float* scratch_buffer, TfLiteEvalTensor* output_state, + TfLiteEvalTensor* cell_state, TfLiteEvalTensor* output); + +TfLiteStatus EvalInteger8x8_16Lstm( + const TfLiteEvalTensor* input, + const TfLiteEvalTensor* input_to_input_weights, + const TfLiteEvalTensor* input_to_forget_weights, + const TfLiteEvalTensor* input_to_cell_weights, + const TfLiteEvalTensor* input_to_output_weights, + const TfLiteEvalTensor* recurrent_to_input_weights, + const TfLiteEvalTensor* recurrent_to_forget_weights, + const TfLiteEvalTensor* recurrent_to_cell_weights, + const TfLiteEvalTensor* recurrent_to_output_weights, + const TfLiteEvalTensor* cell_to_input_weights, + const TfLiteEvalTensor* cell_to_forget_weights, + const TfLiteEvalTensor* cell_to_output_weights, + const TfLiteEvalTensor* input_layer_norm_coefficients, + const TfLiteEvalTensor* forget_layer_norm_coefficients, + const TfLiteEvalTensor* cell_layer_norm_coefficients, + const TfLiteEvalTensor* output_layer_norm_coefficients, + const TfLiteEvalTensor* input_gate_bias, + const TfLiteEvalTensor* forget_gate_bias, + const TfLiteEvalTensor* cell_gate_bias, + const TfLiteEvalTensor* output_gate_bias, + const TfLiteEvalTensor* projection_weights, + const TfLiteEvalTensor* projection_bias, const TfLiteLSTMParams* params, + bool forward_sequence, bool time_major, + const IntegerLstmParameter* integer_lstm_param, int32_t output_state_zp, + TfLiteEvalTensor* output_state, TfLiteEvalTensor* cell_state, + TfLiteEvalTensor* output, int16_t* scratch0, int16_t* scratch1, + int16_t* scratch2, int16_t* scratch3, int8_t* scratch4, int32_t* scratch5); + +} // namespace tflite +#endif // TENSORFLOW_LITE_MICRO_KERNELS_LSTM_EVAL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_shared.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_shared.h new file mode 100644 index 000000000..ee34b8489 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/lstm_shared.h @@ -0,0 +1,67 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_LSTM_SHARED_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_LSTM_SHARED_H_ + +namespace tflite { + +// Input Tensors of size {n_batch, n_input} +constexpr int kLstmInputTensor = 0; + +// Input weight tensors of size: {n_cell, n_input} +constexpr int kLstmInputToInputWeightsTensor = 1; // Optional +constexpr int kLstmInputToForgetWeightsTensor = 2; +constexpr int kLstmInputToCellWeightsTensor = 3; +constexpr int kLstmInputToOutputWeightsTensor = 4; + +// Recurrent weight tensors of size {n_cell, n_output} +constexpr int kLstmRecurrentToInputWeightsTensor = 5; // Optional +constexpr int kLstmRecurrentToForgetWeightsTensor = 6; +constexpr int kLstmRecurrentToCellWeightsTensor = 7; +constexpr int kLstmRecurrentToOutputWeightsTensor = 8; + +// Peephole weights tensors of size {n_cell}, representing a diagonal matrix. +constexpr int kLstmCellToInputWeightsTensor = 9; // Optional +constexpr int kLstmCellToForgetWeightsTensor = 10; // Optional +constexpr int kLstmCellToOutputWeightsTensor = 11; // Optional + +// Gates bias tensors of size {n_cell} +constexpr int kLstmInputGateBiasTensor = 12; // Optional +constexpr int kLstmForgetGateBiasTensor = 13; +constexpr int kLstmCellGateBiasTensor = 14; +constexpr int kLstmOutputGateBiasTensor = 15; + +// Projection weight tensor of size {n_output, n_cell} +constexpr int kLstmProjectionWeightsTensor = 16; // Optional +// Projection bias tensor of size {n_output} +constexpr int kLstmProjectionBiasTensor = 17; // Optional + +// These state tensors are defined as variable tensors, and will be modified by +// this op. +constexpr int kLstmOutputStateTensor = 18; +constexpr int kLstmCellStateTensor = 19; + +// Layer norm coefficient tensors of size {n_cell}, representing a diagonal +// matrix. +constexpr int kLstmInputLayerNormCoefficientsTensor = 20; // Optional +constexpr int kLstmForgetLayerNormCoefficientsTensor = 21; // Optional +constexpr int kLstmCellLayerNormCoefficientsTensor = 22; // Optional +constexpr int kLstmOutputLayerNormCoefficientsTensor = 23; // Optional + +// Output tensors. +constexpr int kLstmOutputTensor = 0; + +} // namespace tflite +#endif // TENSORFLOW_LITE_MICRO_KERNELS_LSTM_SHARED_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/maximum_minimum.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/maximum_minimum.cc new file mode 100644 index 000000000..1aebdefdc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/maximum_minimum.cc @@ -0,0 +1,132 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/maximum_minimum.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace maximum_minimum { +namespace { + +// This file has a reference implementation of TFMaximum/TFMinimum. +enum KernelType { + kReference, +}; + +constexpr int kInputTensor1 = 0; +constexpr int kInputTensor2 = 1; +constexpr int kOutputTensor = 0; + +struct OpContext { + OpContext(TfLiteContext* context, TfLiteNode* node) { + input1 = tflite::micro::GetEvalInput(context, node, kInputTensor1); + input2 = tflite::micro::GetEvalInput(context, node, kInputTensor2); + output = tflite::micro::GetEvalOutput(context, node, kOutputTensor); + } + const TfLiteEvalTensor* input1; + const TfLiteEvalTensor* input2; + TfLiteEvalTensor* output; +}; + +struct MaximumOp { + template + static data_type op(data_type el1, data_type el2) { + return el1 > el2 ? el1 : el2; + } +}; + +struct MinimumOp { + template + static data_type op(data_type el1, data_type el2) { + return el1 < el2 ? el1 : el2; + } +}; + +} // namespace + +template +void TFLiteOperation(TfLiteContext* context, TfLiteNode* node, + const OpContext& op_context) { + reference_ops::MaximumMinimumBroadcastSlow( + tflite::micro::GetTensorShape(op_context.input1), + tflite::micro::GetTensorData(op_context.input1), + tflite::micro::GetTensorShape(op_context.input2), + tflite::micro::GetTensorData(op_context.input2), + tflite::micro::GetTensorShape(op_context.output), + tflite::micro::GetTensorData(op_context.output), + op_type::template op); +} + +template +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + OpContext op_context(context, node); + + if (kernel_type == kReference) { + switch (op_context.output->type) { + case kTfLiteFloat32: + TFLiteOperation(context, node, op_context); + break; + case kTfLiteInt8: + TFLiteOperation(context, node, op_context); + break; + case kTfLiteInt32: + TFLiteOperation(context, node, op_context); + break; + case kTfLiteInt64: + TFLiteOperation(context, node, op_context); + break; + default: + MicroPrintf("Type %s (%d) is not supported by Maximum/Minimum.", + TfLiteTypeGetName(op_context.output->type), + op_context.output->type); + return kTfLiteError; + } + } else { + MicroPrintf("Kernel type not supported by Maximum/Minimum."); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace maximum_minimum + +TfLiteRegistration Register_MAXIMUM() { + return tflite::micro::RegisterOp( + nullptr, nullptr, + maximum_minimum::Eval); +} + +TfLiteRegistration Register_MINIMUM() { + return tflite::micro::RegisterOp( + nullptr, nullptr, + maximum_minimum::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_ops.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_ops.h new file mode 100644 index 000000000..68583f75e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_ops.h @@ -0,0 +1,135 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_MICRO_OPS_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_MICRO_OPS_H_ + +#include "tensorflow/lite/c/common.h" + +// Forward declaration of all micro op kernel registration methods. These +// registrations are included with the standard `BuiltinOpResolver`. +// +// This header is particularly useful in cases where only a subset of ops are +// needed. In such cases, the client can selectively add only the registrations +// their model requires, using a custom `(Micro)MutableOpResolver`. Selective +// registration in turn allows the linker to strip unused kernels. + +namespace tflite { + +// TFLM is incrementally moving towards a flat tflite namespace +// (https://abseil.io/tips/130). Any new ops (or cleanup of existing ops should +// have their Register function declarations in the tflite namespace. + +TfLiteRegistration Register_ADD(); +TfLiteRegistration Register_ADD_N(); +TfLiteRegistration Register_ASSIGN_VARIABLE(); +TfLiteRegistration Register_AVERAGE_POOL_2D(); +TfLiteRegistration Register_BATCH_TO_SPACE_ND(); +TfLiteRegistration Register_BROADCAST_ARGS(); +TfLiteRegistration Register_BROADCAST_TO(); +TfLiteRegistration Register_CALL_ONCE(); +TfLiteRegistration Register_CAST(); +// TODO(b/160234179): Change custom OPs to also return by value. +TfLiteRegistration* Register_CIRCULAR_BUFFER(); +TfLiteRegistration Register_CUMSUM(); +TfLiteRegistration Register_DEPTH_TO_SPACE(); +TfLiteRegistration Register_DEPTHWISE_CONV_2D(); +TfLiteRegistration Register_DEQUANTIZE(); +TfLiteRegistration Register_DIV(); +TfLiteRegistration Register_ELU(); +TfLiteRegistration Register_EXP(); +TfLiteRegistration Register_EXPAND_DIMS(); +TfLiteRegistration Register_FILL(); +TfLiteRegistration Register_FLOOR_DIV(); +TfLiteRegistration Register_FLOOR_MOD(); +TfLiteRegistration Register_GATHER(); +TfLiteRegistration Register_GATHER_ND(); +TfLiteRegistration Register_HARD_SWISH(); +TfLiteRegistration Register_IF(); +TfLiteRegistration Register_L2_POOL_2D(); +TfLiteRegistration Register_LEAKY_RELU(); +TfLiteRegistration Register_LOG_SOFTMAX(); +TfLiteRegistration Register_LOGICAL_AND(); +TfLiteRegistration Register_LOGICAL_OR(); +TfLiteRegistration Register_LOGISTIC(); +TfLiteRegistration Register_MAX_POOL_2D(); +TfLiteRegistration Register_MIRROR_PAD(); +TfLiteRegistration Register_PRELU(); +TfLiteRegistration Register_MUL(); +TfLiteRegistration Register_QUANTIZE(); +TfLiteRegistration Register_READ_VARIABLE(); +TfLiteRegistration Register_RELU(); +TfLiteRegistration Register_RELU6(); +TfLiteRegistration Register_RESIZE_BILINEAR(); +TfLiteRegistration Register_SELECT_V2(); +TfLiteRegistration Register_SHAPE(); +TfLiteRegistration Register_SLICE(); +TfLiteRegistration Register_SPACE_TO_BATCH_ND(); +TfLiteRegistration Register_SPACE_TO_DEPTH(); +TfLiteRegistration Register_SQUARED_DIFFERENCE(); +TfLiteRegistration Register_SQUEEZE(); +TfLiteRegistration Register_SUB(); +TfLiteRegistration Register_SUM(); +TfLiteRegistration Register_SVDF(); +TfLiteRegistration Register_TRANSPOSE(); +TfLiteRegistration Register_TRANSPOSE_CONV(); +// TODO(b/230666079): resolve conflict with xtensa implementation +TfLiteRegistration Register_UNIDIRECTIONAL_SEQUENCE_LSTM(); +TfLiteRegistration Register_VAR_HANDLE(); +TfLiteRegistration Register_WHILE(); +TfLiteRegistration Register_ZEROS_LIKE(); + +namespace ops { +namespace micro { + +TfLiteRegistration Register_ABS(); +TfLiteRegistration Register_ARG_MAX(); +TfLiteRegistration Register_ARG_MIN(); +TfLiteRegistration Register_CEIL(); +TfLiteRegistration Register_CONCATENATION(); +TfLiteRegistration Register_COS(); +TfLiteRegistration Register_EQUAL(); +TfLiteRegistration Register_FLOOR(); +TfLiteRegistration Register_GREATER(); +TfLiteRegistration Register_GREATER_EQUAL(); +TfLiteRegistration Register_LESS(); +TfLiteRegistration Register_LESS_EQUAL(); +TfLiteRegistration Register_LOG(); +TfLiteRegistration Register_LOGICAL_NOT(); +TfLiteRegistration Register_MAXIMUM(); +TfLiteRegistration Register_MINIMUM(); +TfLiteRegistration Register_NEG(); +TfLiteRegistration Register_NOT_EQUAL(); +TfLiteRegistration Register_PACK(); +TfLiteRegistration Register_PAD(); +TfLiteRegistration Register_PADV2(); +TfLiteRegistration Register_RESHAPE(); +TfLiteRegistration Register_RESIZE_NEAREST_NEIGHBOR(); +TfLiteRegistration Register_ROUND(); +TfLiteRegistration Register_RSQRT(); +TfLiteRegistration Register_SIN(); +TfLiteRegistration Register_SPLIT(); +TfLiteRegistration Register_SPLIT_V(); +TfLiteRegistration Register_SQRT(); +TfLiteRegistration Register_SQUARE(); +TfLiteRegistration Register_STRIDED_SLICE(); +TfLiteRegistration Register_UNPACK(); +TfLiteRegistration Register_L2_NORMALIZATION(); +TfLiteRegistration Register_TANH(); + +} // namespace micro +} // namespace ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_MICRO_OPS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_tensor_utils.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_tensor_utils.cc new file mode 100644 index 000000000..628be9b4b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_tensor_utils.cc @@ -0,0 +1,67 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/micro_tensor_utils.h" + +#include +#include +#include +#include +#include +#include + +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/cppmath.h" +#include "tensorflow/lite/kernels/op_macros.h" + +namespace tflite { + +// Apply sigmoid to elements of a vector. +void PortableApplySigmoidToVector(const float* vector, int v_size, + float* result) { + for (int v = 0; v < v_size; v++) { + result[v] = 1.0f / (1.0f + std::exp(-vector[v])); + } +} + +void PortableApplyTanhToVector(const float* vector, int v_size, float* result) { + for (int v = 0; v < v_size; v++) { + result[v] = std::tanh(vector[v]); + } +} + +void PortableApplyActivationToVector(const float* vector, int v_size, + TfLiteFusedActivation activation, + float* result) { + switch (activation) { + case kTfLiteActNone: + return; + case kTfLiteActRelu: + return tflite::tensor_utils::ApplyReluToVector(vector, v_size, result); + case kTfLiteActReluN1To1: + return tflite::tensor_utils::ApplyRelu1ToVector(vector, v_size, result); + case kTfLiteActRelu6: + return tflite::tensor_utils::ApplyRelu6ToVector(vector, v_size, result); + case kTfLiteActTanh: + return PortableApplyTanhToVector(vector, v_size, result); + case kTfLiteActSignBit: + return tflite::tensor_utils::ApplySignbitToVector(vector, v_size, result); + case kTfLiteActSigmoid: + return PortableApplySigmoidToVector(vector, v_size, result); + } +} + +} // namespace tflite \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_tensor_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_tensor_utils.h new file mode 100644 index 000000000..0b87f0aea --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_tensor_utils.h @@ -0,0 +1,56 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 file and the associated .cc file is branched from +// tensorflow/lite/kernels/internal/reference/portable_tensor_utils* +// TFLM needs to create its own because the original files are coupled with +// the tensor_utils module, which we cannot reuse due to its use of the +// Eigen library. + +#ifndef TENSORFLOW_LITE_MICRO_KERNELS_MICRO_TENSOR_UTILS_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_MICRO_TENSOR_UTILS_H_ + +#include +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" + +#if defined(_MSC_VER) +#define __restrict__ __restrict +#endif + +namespace tflite { + +// Not all backends support CpuBackendContext usage, so forward declare to avoid +// pulling in its implementation. +// TODO(b/230666277): consider removing this since micro does not utilize it +class CpuBackendContext; + +// Apply sigmoid to elements of a vector. +void PortableApplySigmoidToVector(const float* vector, int v_size, + float* result); +// Apply tanh to elements of a vector +void PortableApplyTanhToVector(const float* vector, int v_size, float* result); +// Apply appropriate activation function to elements of a vector. +void PortableApplyActivationToVector(const float* vector, int v_size, + TfLiteFusedActivation activation, + float* result); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_MICRO_TENSOR_UTILS_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_utils.h new file mode 100644 index 000000000..e406ac12f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/micro_utils.h @@ -0,0 +1,40 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_MICRO_UTILS_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_MICRO_UTILS_H_ +namespace tflite { +namespace ops { +namespace micro { + +// Same as gtl::Greater but defined here to reduce dependencies and +// binary size for micro environment. +struct Greater { + template + bool operator()(const T& x, const T& y) const { + return x > y; + } +}; + +struct Less { + template + bool operator()(const T& x, const T& y) const { + return x < y; + } +}; + +} // namespace micro +} // namespace ops +} // namespace tflite +#endif // TENSORFLOW_LITE_MICRO_KERNELS_MICRO_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mirror_pad.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mirror_pad.cc new file mode 100644 index 000000000..90d3bd9e0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mirror_pad.cc @@ -0,0 +1,215 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { +namespace { + +struct OpDataMirrorPad { + int input_dims; + int output_size; + int offset; + int output_dims_num_elements_buffer_index; + int input_dims_num_elements_buffer_index; +}; + +// Helper method that fills the left and right pads. +template +inline void GetPadding(const T* data, int offset, int64_t* left_pad, + int64_t* right_pad) { + *left_pad = static_cast(*(data + offset * 2)); + *right_pad = static_cast(*(data + offset * 2 + 1)); +} + +// Given dimension index and the left/right padding. +// Returns the corresponding dimension in the input array. +inline int GetInputDimension(int padded_dimension, int left_pad, int right_pad, + int input_dim_size, int offset) { + if (padded_dimension < left_pad) { + const int original_ind = left_pad + offset - 1; + return original_ind - (std::min(padded_dimension, original_ind - offset)); + } + padded_dimension -= left_pad; + if (padded_dimension >= input_dim_size) { + padded_dimension -= input_dim_size; + const int original_ind = input_dim_size - (1 + offset); + return original_ind - std::min(padded_dimension, original_ind); + } + return padded_dimension; +} + +// Given and index in output array, returns the index of the value +// in input array. +int GetFlatIndex(int index, int num_dims, + const TfLiteEvalTensor* padding_matrix, + const TfLiteIntArray* input_dims, + int* output_dims_num_elements, int* input_dims_num_elements, + const int offset) { + int flat_index = 0; + int64_t left_pad = 0, right_pad = 0, dimension_index, index_in_input; + + for (int i = 0; i < num_dims; ++i) { + switch (padding_matrix->type) { + case kTfLiteInt32: + GetPadding(padding_matrix->data.i32, i, &left_pad, &right_pad); + break; + case kTfLiteInt64: + GetPadding(padding_matrix->data.i64, i, &left_pad, &right_pad); + break; + default: + break; + } + dimension_index = index / output_dims_num_elements[i]; + + index_in_input = GetInputDimension(dimension_index, left_pad, right_pad, + input_dims->data[i], offset); + + flat_index += index_in_input * (input_dims_num_elements)[i]; + index %= output_dims_num_elements[i]; + } + + return flat_index; +} + +template +void MirrorPad(const TfLiteEvalTensor* padding_matrix, + const TfLiteIntArray* input_dims, int* output_dims_num_elements, + int* input_dims_num_elements, const T* input_data, + T* output_data, const int offset, const int num_dims, + const int output_size) { + for (int i = 0; i < output_size; ++i) { + output_data[i] = input_data[GetFlatIndex( + i, num_dims, padding_matrix, input_dims, output_dims_num_elements, + input_dims_num_elements, offset)]; + } +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TfLiteStatus status = kTfLiteOk; + const OpDataMirrorPad* data = + static_cast(node->user_data); + + const TfLiteEvalTensor* input_tensor = + tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* padding_matrix = + tflite::micro::GetEvalInput(context, node, 1); + + TfLiteEvalTensor* output_tensor = + tflite::micro::GetEvalOutput(context, node, 0); + const int input_dims = data->input_dims; + const int output_size = data->output_size; + + int* input_dims_num_elements = (int*)context->GetScratchBuffer( + context, data->input_dims_num_elements_buffer_index); + int* output_dims_num_elements = (int*)context->GetScratchBuffer( + context, data->output_dims_num_elements_buffer_index); + + for (int i = 0; i < input_dims; i++) { + output_dims_num_elements[i] = 1; + input_dims_num_elements[i] = 1; + } + + for (int i = input_dims - 2; i >= 0; i--) { + output_dims_num_elements[i] = + output_dims_num_elements[i + 1] * output_tensor->dims->data[i + 1]; + + input_dims_num_elements[i] = + input_dims_num_elements[i + 1] * input_tensor->dims->data[i + 1]; + } + + switch (output_tensor->type) { + case kTfLiteFloat32: { + MirrorPad(padding_matrix, input_tensor->dims, output_dims_num_elements, + input_dims_num_elements, + tflite::micro::GetTensorData(input_tensor), + tflite::micro::GetTensorData(output_tensor), + data->offset, input_dims, output_size); + break; + } + case kTfLiteInt8: { + MirrorPad(padding_matrix, input_tensor->dims, output_dims_num_elements, + input_dims_num_elements, + tflite::micro::GetTensorData(input_tensor), + tflite::micro::GetTensorData(output_tensor), + data->offset, input_dims, output_size); + break; + } + default: + status = kTfLiteError; + break; + } + +#undef TF_LITE_MIRROR_PAD + + return status; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataMirrorPad)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataMirrorPad* data = static_cast(node->user_data); + + TfLiteTensor* input_tensor = micro_context->AllocateTempInputTensor(node, 0); + TfLiteTensor* padding_matrix = + micro_context->AllocateTempInputTensor(node, 1); + TfLiteTensor* output_tensor = + micro_context->AllocateTempOutputTensor(node, 0); + + TF_LITE_ENSURE_EQ(context, NumDimensions(padding_matrix), 2); + TF_LITE_ENSURE_EQ(context, SizeOfDimension(padding_matrix, 0), + NumDimensions(input_tensor)); + auto* params = + reinterpret_cast(node->builtin_data); + if (params == nullptr) { + return kTfLiteError; + } + + data->offset = + params->mode != TfLiteMirrorPaddingMode::kTfLiteMirrorPaddingReflect ? 0 + : 1; + data->input_dims = NumDimensions(input_tensor); + data->output_size = NumElements(output_tensor); + + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, data->input_dims * sizeof(int), + &data->output_dims_num_elements_buffer_index)); + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, data->input_dims * sizeof(int), + &data->input_dims_num_elements_buffer_index)); + + micro_context->DeallocateTempTfLiteTensor(input_tensor); + micro_context->DeallocateTempTfLiteTensor(padding_matrix); + micro_context->DeallocateTempTfLiteTensor(output_tensor); + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_MIRROR_PAD() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul.cc new file mode 100644 index 000000000..abbfb3ebf --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul.cc @@ -0,0 +1,67 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/mul.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/mul.h" +#include "tensorflow/lite/kernels/internal/reference/mul.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +TfLiteStatus MulEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataMul* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kMulInput1Tensor); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kMulInput2Tensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kMulOutputTensor); + + switch (input1->type) { + case kTfLiteInt8: + case kTfLiteInt32: + EvalMulQuantizedReference(context, node, data, input1, input2, output); + break; + case kTfLiteFloat32: + EvalMulFloatReference(context, node, params, data, input1, input2, + output); + break; + default: + MicroPrintf("Type %s (%d) not supported.", + TfLiteTypeGetName(input1->type), input1->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +TfLiteRegistration Register_MUL() { + return tflite::micro::RegisterOp(MulInit, MulPrepare, MulEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul.h new file mode 100644 index 000000000..0c6379e11 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul.h @@ -0,0 +1,74 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_MUL_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_MUL_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +extern const int kMulInput1Tensor; +extern const int kMulInput2Tensor; +extern const int kMulOutputTensor; + +struct OpDataMul { + int32_t input1_zero_point; + int32_t input2_zero_point; + + int32_t output_activation_min; + int32_t output_activation_max; + int32_t output_zero_point; + int32_t output_multiplier; + int output_shift; + + float output_activation_min_f32; + float output_activation_max_f32; +}; + +void* MulInit(TfLiteContext* context, const char* buffer, size_t length); + +TfLiteStatus CalculateOpDataMul(TfLiteContext* context, TfLiteNode* node, + TfLiteMulParams* params, OpDataMul* data); + +TfLiteStatus MulPrepare(TfLiteContext* context, TfLiteNode* node); + +void EvalMulQuantizedReference(TfLiteContext* context, TfLiteNode* node, + const OpDataMul* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output); + +void EvalMulFloatReference(TfLiteContext* context, TfLiteNode* node, + TfLiteMulParams* params, const OpDataMul* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output); + +// Generic must define registration function. +TfLiteRegistration Register_MUL(); + +#if defined(CMSIS_NN) +TfLiteRegistration Register_MUL_INT8(); +#else +// Fallback registration +inline TfLiteRegistration Register_MUL_INT8() { return Register_MUL(); } +#endif +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_MUL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul_common.cc new file mode 100644 index 000000000..6d19ac7aa --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/mul_common.cc @@ -0,0 +1,184 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/mul.h" +#include "tensorflow/lite/kernels/internal/reference/mul.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/mul.h" +#include "tensorflow/lite/micro/memory_helpers.h" + +namespace tflite { + +const int kMulInput1Tensor = 0; +const int kMulInput2Tensor = 1; +const int kMulOutputTensor = 0; + +void* MulInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataMul)); +} + +TfLiteStatus CalculateOpDataMul(TfLiteContext* context, TfLiteNode* node, + TfLiteMulParams* params, OpDataMul* data) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kMulInput1Tensor); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kMulInput2Tensor); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kMulOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, input2->type); + + if (output->type == kTfLiteInt8) { + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, params->activation, output, &data->output_activation_min, + &data->output_activation_max)); + + double real_multiplier = static_cast(input1->params.scale) * + static_cast(input2->params.scale) / + static_cast(output->params.scale); + QuantizeMultiplier(real_multiplier, &data->output_multiplier, + &data->output_shift); + + data->input1_zero_point = input1->params.zero_point; + data->input2_zero_point = input2->params.zero_point; + data->output_zero_point = output->params.zero_point; + } else if (output->type == kTfLiteInt32) { + CalculateActivationRange(params->activation, &data->output_activation_min, + &data->output_activation_max); + } else { + CalculateActivationRange(params->activation, + &data->output_activation_min_f32, + &data->output_activation_max_f32); + } + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus MulPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataMul* data = static_cast(node->user_data); + + return CalculateOpDataMul(context, node, params, data); +} + +void EvalMulQuantizedReference(TfLiteContext* context, TfLiteNode* node, + const OpDataMul* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params = {}; + op_params.quantized_activation_min = data->output_activation_min; + op_params.quantized_activation_max = data->output_activation_max; + op_params.float_activation_max = data->output_activation_max_f32; + op_params.input1_offset = -data->input1_zero_point; + op_params.input2_offset = -data->input2_zero_point; + op_params.output_offset = data->output_zero_point; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = data->output_shift; + + bool need_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + if (input1->type == kTfLiteInt8) { + if (need_broadcast) { + reference_integer_ops::BroadcastMul4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_integer_ops::Mul(op_params, + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + } else if (input1->type == kTfLiteInt32) { + if (need_broadcast) { + reference_ops::BroadcastMul4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Mul(op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + } +} + +void EvalMulFloatReference(TfLiteContext* context, TfLiteNode* node, + TfLiteMulParams* params, const OpDataMul* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params = {}; + op_params.float_activation_min = data->output_activation_min_f32; + op_params.float_activation_max = data->output_activation_max_f32; + + bool need_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + if (need_broadcast) { + reference_ops::BroadcastMul4DSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Mul(op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/neg.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/neg.cc new file mode 100644 index 000000000..36c7eac66 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/neg.cc @@ -0,0 +1,60 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/neg.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace neg { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + switch (input->type) { + // TODO(wangtz): handle for kTfLiteInt8 + case kTfLiteFloat32: + reference_ops::Negate(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace neg + +TfLiteRegistration Register_NEG() { + return tflite::micro::RegisterOp(nullptr, nullptr, neg::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pack.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pack.cc new file mode 100644 index 000000000..5e322b87b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pack.cc @@ -0,0 +1,117 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace pack { +namespace { + +constexpr int kOutputTensor = 0; + +template +TfLiteStatus PackImpl(TfLiteContext* context, TfLiteNode* node, + TfLiteEvalTensor* output, int values_count, int axis) { + const TfLiteEvalTensor* input0 = + tflite::micro::GetEvalInput(context, node, 0); + + const int dimensions = output->dims->size; + const TfLiteIntArray* input_dims = input0->dims; + const TfLiteIntArray* output_dims = output->dims; + + if (axis < 0) { + axis += dimensions; + } + + int outer_size = 1; + for (int i = 0; i < axis; ++i) { + outer_size *= output_dims->data[i]; + } + int copy_size = 1; + for (int i = axis + 1; i < dimensions; ++i) { + copy_size *= output_dims->data[i]; + } + int input_size = 1; + for (int i = 0; i < input_dims->size; ++i) { + input_size *= input_dims->data[i]; + } + TFLITE_DCHECK_EQ(input_size, copy_size * outer_size); + + T* output_data = tflite::micro::GetTensorData(output); + + for (int i = 0; i < values_count; ++i) { + const TfLiteEvalTensor* t = tflite::micro::GetEvalInput(context, node, i); + const T* input_data = tflite::micro::GetTensorData(t); + for (int k = 0; k < outer_size; ++k) { + const T* input_ptr = input_data + copy_size * k; + int loc = k * values_count * copy_size + i * copy_size; + T* output_ptr = output_data + loc; + for (int j = 0; j < copy_size; ++j) output_ptr[j] = input_ptr[j]; + } + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLitePackParams* data = + reinterpret_cast(node->builtin_data); + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + switch (output->type) { + case kTfLiteFloat32: { + return PackImpl(context, node, output, data->values_count, + data->axis); + } + case kTfLiteInt8: { + return PackImpl(context, node, output, data->values_count, + data->axis); + } + case kTfLiteInt32: { + return PackImpl(context, node, output, data->values_count, + data->axis); + } + case kTfLiteInt64: { + return PackImpl(context, node, output, data->values_count, + data->axis); + } + default: { + MicroPrintf("Type '%s' is not supported by pack.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } + + return kTfLiteOk; +} + +} // namespace +} // namespace pack + +TfLiteRegistration Register_PACK() { + return tflite::micro::RegisterOp(nullptr, nullptr, pack::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pad.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pad.cc new file mode 100644 index 000000000..a0f2aeee2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pad.cc @@ -0,0 +1,237 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/pad.h" + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/portable_tensor.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace pad { +namespace { + +struct OpData { + PadParams params; + int32_t output_zero_point; +}; + +} // namespace + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TFLITE_DCHECK(node->user_data != nullptr); + OpData* data = static_cast(node->user_data); + + TF_LITE_ENSURE(context, NumInputs(node) == 2 || NumInputs(node) == 3); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, /*index=*/0); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* paddings = + micro_context->AllocateTempInputTensor(node, /*index=*/1); + TF_LITE_ENSURE(context, paddings != nullptr); + TfLiteTensor* constant_values = + NumInputs(node) == 3 + ? micro_context->AllocateTempInputTensor(node, /*index=*/2) + : nullptr; + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, /*index=*/0); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_EQ(context, input->type, output->type); + + // Current implementations rely on the inputs being <= 4D. + TF_LITE_ENSURE(context, NumDimensions(input) <= + reference_ops::PadKernelMaxDimensionCount()); + + if (constant_values != nullptr) { + TF_LITE_ENSURE_EQ(context, input->type, constant_values->type); + // Ensure that constant_values is a scalar. + TF_LITE_ENSURE_EQ(context, NumElements(constant_values), 1); + } + + // There must be a pair of paddings for each output dimension. + TF_LITE_ENSURE_EQ(context, GetTensorShape(paddings).FlatSize(), + output->dims->size * 2); + + // On Micro, outputs must be properly sized by the converter. + // NOTE: This data is only available because the paddings buffer is stored in + // the flatbuffer: + TF_LITE_ENSURE(context, IsConstantTensor(paddings)); + const int32_t* paddings_data = GetTensorData(paddings); + for (int i = 0; i < output->dims->size; i++) { + int output_dim = output->dims->data[i]; + int expected_dim = + input->dims->data[i] + paddings_data[i * 2] + paddings_data[i * 2 + 1]; + TF_LITE_ENSURE_EQ(context, output_dim, expected_dim); + } + + // Calculate OpData: + data->params.resizing_category = ResizingCategory::kGenericResize; + const int paddings_total = GetTensorShape(paddings).FlatSize(); + if (paddings_total == 8 && (paddings_data[0] == 0 && paddings_data[1] == 0) && + (paddings_data[6] == 0 && paddings_data[7] == 0)) { + data->params.resizing_category = ResizingCategory::kImageStyle; + } + + const int num_input_dimensions = NumDimensions(input); + data->params.left_padding_count = num_input_dimensions; + data->params.right_padding_count = num_input_dimensions; + + for (int idx = num_input_dimensions - 1; idx >= 0; --idx) { + data->params.left_padding[idx] = paddings_data[idx * 2]; + data->params.right_padding[idx] = paddings_data[idx * 2 + 1]; + } + + if (input->type == kTfLiteInt8) { + if (constant_values == nullptr) { + // Quantized Pad requires that 0 is represented in the quantized + // range. + TF_LITE_ENSURE(context, output->params.zero_point >= + std::numeric_limits::min()); + TF_LITE_ENSURE(context, output->params.zero_point <= + std::numeric_limits::max()); + } else { + // Quantized Pad requires that 'constant_values' is represented in the + // same quantized range as the input and output tensors. + TF_LITE_ENSURE_EQ(context, output->params.zero_point, + constant_values->params.zero_point); + TF_LITE_ENSURE_EQ(context, static_cast(output->params.scale), + static_cast(constant_values->params.scale)); + } + data->output_zero_point = output->params.zero_point; + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(paddings); + if (constant_values != nullptr) { + micro_context->DeallocateTempTfLiteTensor(constant_values); + } + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const OpData* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, /*index=*/0); + const TfLiteEvalTensor* constant_values = + NumInputs(node) == 3 + ? tflite::micro::GetEvalInput(context, node, /*index=*/2) + : nullptr; + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, /*index=*/0); + + switch (input->type) { + case kTfLiteFloat32: { + float pad_value = + constant_values == nullptr + ? 0.f + : *tflite::micro::GetTensorData(constant_values); + if (data->params.resizing_category == ResizingCategory::kImageStyle) { + reference_ops::PadImageStyle( + data->params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), &pad_value, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Pad(data->params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + &pad_value, tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + } break; + case kTfLiteInt8: { + int8_t pad_value; + if (constant_values == nullptr) { + pad_value = static_cast(data->output_zero_point); + } else { + pad_value = *tflite::micro::GetTensorData(constant_values); + } + if (data->params.resizing_category == ResizingCategory::kImageStyle) { + reference_ops::PadImageStyle( + data->params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), &pad_value, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + reference_ops::Pad(data->params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + &pad_value, tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + } break; + case kTfLiteInt16: { + int16_t pad_value = + constant_values == nullptr + ? 0 + : *tflite::micro::GetTensorData(constant_values); + reference_ops::Pad(data->params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + &pad_value, tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } break; + case kTfLiteInt32: { + int32_t pad_value = + constant_values == nullptr + ? 0 + : *tflite::micro::GetTensorData(constant_values); + reference_ops::Pad(data->params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + &pad_value, tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } break; + default: + + MicroPrintf("Type %s not currently supported by Pad.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace pad + +TfLiteRegistration Register_PAD() { + return tflite::micro::RegisterOp(pad::Init, pad::Prepare, pad::Eval); +} + +// Also register Pad as PadV2. +TfLiteRegistration Register_PADV2() { + return tflite::micro::RegisterOp(pad::Init, pad::Prepare, pad::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling.cc new file mode 100644 index 000000000..d9b147ad8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling.cc @@ -0,0 +1,99 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/pooling.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/pooling.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +namespace { + +TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataPooling* data = + static_cast(node->user_data); + + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kPoolingInputTensor); + TfLiteEvalTensor* output = + micro::GetEvalOutput(context, node, kPoolingOutputTensor); + + // Inputs and outputs share the same type, guaranteed by the converter. + switch (input->type) { + case kTfLiteFloat32: + AveragePoolingEvalFloat(context, node, params, data, input, output); + break; + case kTfLiteInt8: + AveragePoolingEvalQuantized(context, node, params, data, input, output); + break; + default: + MicroPrintf("Input type %s is not currently supported", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataPooling* data = + static_cast(node->user_data); + + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kPoolingInputTensor); + TfLiteEvalTensor* output = + micro::GetEvalOutput(context, node, kPoolingOutputTensor); + + switch (input->type) { + case kTfLiteFloat32: + MaxPoolingEvalFloat(context, node, params, data, input, output); + break; + case kTfLiteInt8: + MaxPoolingEvalQuantized(context, node, params, data, input, output); + break; + default: + MicroPrintf("Type %s not currently supported.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataPooling)); +} + +} // namespace + +TfLiteRegistration Register_AVERAGE_POOL_2D() { + return tflite::micro::RegisterOp(Init, PoolingPrepare, AverageEval); +} + +TfLiteRegistration Register_MAX_POOL_2D() { + return tflite::micro::RegisterOp(Init, PoolingPrepare, MaxEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling.h new file mode 100644 index 000000000..493250ee1 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling.h @@ -0,0 +1,85 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_POOLING_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_POOLING_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/kernels/micro_ops.h" + +namespace tflite { + +extern const int kPoolingInputTensor; +extern const int kPoolingOutputTensor; + +struct OpDataPooling { + TfLitePaddingValues padding; + int32_t activation_min; + int32_t activation_max; + float activation_min_f32; + float activation_max_f32; +}; + +TfLiteStatus CalculateOpDataPooling(const TfLiteContext* context, + const TfLitePoolParams* params, + const TfLiteTensor* input, + const TfLiteTensor* output, + OpDataPooling* data); + +TfLiteStatus PoolingPrepare(TfLiteContext* context, TfLiteNode* node); + +void AveragePoolingEvalFloat(const TfLiteContext* context, + const TfLiteNode* node, + const TfLitePoolParams* params, + const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output); + +void AveragePoolingEvalQuantized(TfLiteContext* context, const TfLiteNode* node, + const TfLitePoolParams* params, + const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output); + +void MaxPoolingEvalFloat(TfLiteContext* context, TfLiteNode* node, + TfLitePoolParams* params, const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output); + +void MaxPoolingEvalQuantized(TfLiteContext* context, TfLiteNode* node, + TfLitePoolParams* params, + const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output); + +#if defined(CMSIS_NN) +TfLiteRegistration Register_AVERAGE_POOL_2D_INT8(); + +TfLiteRegistration Register_MAX_POOL_2D_INT8(); +#else +inline TfLiteRegistration Register_AVERAGE_POOL_2D_INT8() { + return tflite::Register_AVERAGE_POOL_2D(); +} + +inline TfLiteRegistration Register_MAX_POOL_2D_INT8() { + return tflite::Register_MAX_POOL_2D(); +} +#endif +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_POOLING_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling_common.cc new file mode 100644 index 000000000..ddc18f0bb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/pooling_common.cc @@ -0,0 +1,170 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h" +#include "tensorflow/lite/kernels/internal/reference/pooling.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/pooling.h" + +namespace tflite { + +const int kPoolingInputTensor = 0; +const int kPoolingOutputTensor = 0; + +TfLiteStatus CalculateOpDataPooling(const TfLiteContext* context, + const TfLitePoolParams* params, + const TfLiteTensor* input, + const TfLiteTensor* output, + OpDataPooling* data) { + // input: batch, height, width, channel + int height = SizeOfDimension(input, 1); + int width = SizeOfDimension(input, 2); + + int out_height, out_width; + + data->padding = ComputePaddingHeightWidth( + params->stride_height, params->stride_width, + /*dilation_rate_height=*/1, + /*dilation_rate_width=*/1, height, width, params->filter_height, + params->filter_width, params->padding, &out_height, &out_width); + + return kTfLiteOk; +} + +TfLiteStatus PoolingPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + auto* params = reinterpret_cast(node->builtin_data); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataPooling* data = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kPoolingInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kPoolingOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_STATUS( + CalculateOpDataPooling(context, params, input, output, data)); + + if (input->type == kTfLiteFloat32) { + CalculateActivationRange(params->activation, &data->activation_min_f32, + &data->activation_max_f32); + } else if (input->type == kTfLiteInt8) { + CalculateActivationRangeQuantized(context, params->activation, output, + &data->activation_min, + &data->activation_max); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +void AveragePoolingEvalFloat(const TfLiteContext* context, + const TfLiteNode* node, + const TfLitePoolParams* params, + const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + PoolParams op_params; + op_params.stride_height = params->stride_height; + op_params.stride_width = params->stride_width; + op_params.filter_height = params->filter_height; + op_params.filter_width = params->filter_width; + op_params.padding_values.height = data->padding.height; + op_params.padding_values.width = data->padding.width; + op_params.float_activation_min = data->activation_min_f32; + op_params.float_activation_max = data->activation_max_f32; + reference_ops::AveragePool(op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +void AveragePoolingEvalQuantized(TfLiteContext* context, const TfLiteNode* node, + const TfLitePoolParams* params, + const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + TFLITE_DCHECK(input->type == kTfLiteInt8); + + PoolParams op_params; + op_params.stride_height = params->stride_height; + op_params.stride_width = params->stride_width; + op_params.filter_height = params->filter_height; + op_params.filter_width = params->filter_width; + op_params.padding_values.height = data->padding.height; + op_params.padding_values.width = data->padding.width; + op_params.quantized_activation_min = data->activation_min; + op_params.quantized_activation_max = data->activation_max; + + reference_integer_ops::AveragePool( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +void MaxPoolingEvalFloat(TfLiteContext* context, TfLiteNode* node, + TfLitePoolParams* params, const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + tflite::PoolParams op_params; + op_params.stride_height = params->stride_height; + op_params.stride_width = params->stride_width; + op_params.filter_height = params->filter_height; + op_params.filter_width = params->filter_width; + op_params.padding_values.height = data->padding.height; + op_params.padding_values.width = data->padding.width; + op_params.float_activation_min = data->activation_min_f32; + op_params.float_activation_max = data->activation_max_f32; + reference_ops::MaxPool(op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +void MaxPoolingEvalQuantized(TfLiteContext* context, TfLiteNode* node, + TfLitePoolParams* params, + const OpDataPooling* data, + const TfLiteEvalTensor* input, + TfLiteEvalTensor* output) { + tflite::PoolParams op_params; + op_params.stride_height = params->stride_height; + op_params.stride_width = params->stride_width; + op_params.filter_height = params->filter_height; + op_params.filter_width = params->filter_width; + op_params.padding_values.height = data->padding.height; + op_params.padding_values.width = data->padding.width; + op_params.quantized_activation_min = data->activation_min; + op_params.quantized_activation_max = data->activation_max; + + reference_integer_ops::MaxPool(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu.cc new file mode 100644 index 000000000..f4294723f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu.cc @@ -0,0 +1,75 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/prelu.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/prelu.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +void* PreluInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(PreluParams)); +} + +TfLiteStatus PreluEval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const PreluParams& params = + *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* alpha = tflite::micro::GetEvalInput(context, node, 1); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + + switch (input->type) { + case kTfLiteFloat32: { + BroadcastPrelu4DSlowFloat(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(alpha), + tflite::micro::GetTensorData(alpha), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + case kTfLiteInt8: { + reference_ops::BroadcastPrelu4DSlow( + params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(alpha), + tflite::micro::GetTensorData(alpha), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + default: + MicroPrintf("Only float32 and uint8_t are supported currently, got %d.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } +} + +TfLiteRegistration Register_PRELU() { + return tflite::micro::RegisterOp(PreluInit, PreluPrepare, PreluEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu.h new file mode 100644 index 000000000..571d1e88a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu.h @@ -0,0 +1,39 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_PRELU_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_PRELU_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +TfLiteStatus CalculatePreluParams(const TfLiteTensor* input, + const TfLiteTensor* alpha, + TfLiteTensor* output, PreluParams* params); + +void BroadcastPrelu4DSlowFloat(const RuntimeShape& unextended_input1_shape, + const float* input1_data, + const RuntimeShape& unextended_input2_shape, + const float* input2_data, + const RuntimeShape& unextended_output_shape, + float* output_data); + +TfLiteStatus PreluPrepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_PRELU_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu_common.cc new file mode 100644 index 000000000..1a89cadf9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/prelu_common.cc @@ -0,0 +1,105 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/prelu.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/prelu.h" + +namespace tflite { + +TfLiteStatus CalculatePreluParams(const TfLiteTensor* input, + const TfLiteTensor* alpha, + TfLiteTensor* output, PreluParams* params) { + if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + double real_multiplier_1 = static_cast(input->params.scale) / + static_cast(output->params.scale); + double real_multiplier_2 = static_cast(input->params.scale) * + static_cast(alpha->params.scale) / + static_cast(output->params.scale); + QuantizeMultiplier(real_multiplier_1, ¶ms->output_multiplier_1, + ¶ms->output_shift_1); + QuantizeMultiplier(real_multiplier_2, ¶ms->output_multiplier_2, + ¶ms->output_shift_2); + + params->input_offset = -input->params.zero_point; + params->alpha_offset = -alpha->params.zero_point; + params->output_offset = output->params.zero_point; + } + + return kTfLiteOk; +} + +void BroadcastPrelu4DSlowFloat(const RuntimeShape& unextended_input1_shape, + const float* input1_data, + const RuntimeShape& unextended_input2_shape, + const float* input2_data, + const RuntimeShape& unextended_output_shape, + float* output_data) { + TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), 4); + TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4); + const RuntimeShape output_shape = + RuntimeShape::ExtendedShape(4, unextended_output_shape); + + NdArrayDesc<4> desc1; + NdArrayDesc<4> desc2; + NdArrayDescsForElementwiseBroadcast(unextended_input1_shape, + unextended_input2_shape, &desc1, &desc2); + + for (int b = 0; b < output_shape.Dims(0); ++b) { + for (int y = 0; y < output_shape.Dims(1); ++y) { + for (int x = 0; x < output_shape.Dims(2); ++x) { + for (int c = 0; c < output_shape.Dims(3); ++c) { + auto out_idx = Offset(output_shape, b, y, x, c); + auto in1_idx = SubscriptToIndex(desc1, b, y, x, c); + auto in2_idx = SubscriptToIndex(desc2, b, y, x, c); + auto in1_val = input1_data[in1_idx]; + auto in2_val = input2_data[in2_idx]; + output_data[out_idx] = in1_val >= 0.0f ? in1_val : in1_val * in2_val; + } + } + } + } +} + +TfLiteStatus PreluPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + PreluParams* params = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* alpha = micro_context->AllocateTempInputTensor(node, 1); + TF_LITE_ENSURE(context, alpha != nullptr); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_OK(context, + CalculatePreluParams(input, alpha, output, params)); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(alpha); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize.cc new file mode 100644 index 000000000..b5eb9c3c9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize.cc @@ -0,0 +1,41 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/quantize.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, + sizeof(OpDataQuantizeReference)); +} + +} // namespace + +TfLiteRegistration Register_QUANTIZE() { + return tflite::micro::RegisterOp(Init, PrepareQuantizeReference, + EvalQuantizeReference); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize.h new file mode 100644 index 000000000..ba93809a2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize.h @@ -0,0 +1,37 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_QUANTIZE_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_QUANTIZE_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +struct OpDataQuantizeReference { + tflite::QuantizationParams quantization_params; + // The scaling factor from input to output (aka the 'real multiplier') can + // be represented as a fixed point multiplier plus a left shift. + int32_t requantize_output_multiplier; + int requantize_output_shift; + + int32_t input_zero_point; +}; + +TfLiteStatus EvalQuantizeReference(TfLiteContext* context, TfLiteNode* node); +TfLiteStatus PrepareQuantizeReference(TfLiteContext* context, TfLiteNode* node); +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_QUANTIZE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize_common.cc new file mode 100644 index 000000000..cb04eafce --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/quantize_common.cc @@ -0,0 +1,239 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/quantize.h" +#include "tensorflow/lite/kernels/internal/reference/requantize.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/quantize.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +TfLiteStatus PrepareQuantizeReference(TfLiteContext* context, + TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + auto* data = static_cast(node->user_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TF_LITE_ENSURE(context, output != nullptr); + + // TODO(b/128934713): Add support for fixed-point per-channel quantization. + // Currently this only support affine per-layer quantization. + TF_LITE_ENSURE_EQ(context, output->quantization.type, + kTfLiteAffineQuantization); + const auto* affine_quantization = + reinterpret_cast(output->quantization.params); + TF_LITE_ENSURE(context, affine_quantization); + TF_LITE_ENSURE(context, affine_quantization->scale); + TF_LITE_ENSURE(context, affine_quantization->scale->size == 1); + + TF_LITE_ENSURE( + context, input->type == kTfLiteFloat32 || input->type == kTfLiteInt32 || + input->type == kTfLiteInt16 || input->type == kTfLiteInt8 || + input->type == kTfLiteUInt8); + TF_LITE_ENSURE(context, output->type == kTfLiteInt8 || + output->type == kTfLiteInt16 || + output->type == kTfLiteInt32 || + output->type == kTfLiteUInt8); + + if ((input->type == kTfLiteInt16 && output->type == kTfLiteInt8) || + (input->type == kTfLiteInt8 && output->type == kTfLiteInt8) || + (input->type == kTfLiteInt8 && output->type == kTfLiteUInt8) || + (input->type == kTfLiteUInt8 && output->type == kTfLiteInt8) || + (input->type == kTfLiteInt8 && output->type == kTfLiteInt16) || + (input->type == kTfLiteInt8 && output->type == kTfLiteInt32) || + (input->type == kTfLiteInt16 && output->type == kTfLiteInt16) || + (input->type == kTfLiteInt16 && output->type == kTfLiteInt32) || + (input->type == kTfLiteInt32 && output->type == kTfLiteInt8) || + (input->type == kTfLiteInt32 && output->type == kTfLiteInt16)) { + double effective_scale = static_cast(input->params.scale) / + static_cast(output->params.scale); + + QuantizeMultiplier(effective_scale, &data->requantize_output_multiplier, + &data->requantize_output_shift); + } + + data->quantization_params.zero_point = output->params.zero_point; + data->quantization_params.scale = static_cast(output->params.scale); + + data->input_zero_point = input->params.zero_point; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus EvalQuantizeReference(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + auto* data = static_cast(node->user_data); + + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + + if (input->type == kTfLiteFloat32) { + switch (output->type) { + case kTfLiteInt8: + reference_ops::AffineQuantize( + data->quantization_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::AffineQuantize( + data->quantization_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else if (input->type == kTfLiteInt32) { + size_t size = ElementCount(*input->dims); + switch (output->type) { + case kTfLiteInt8: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else if (input->type == kTfLiteInt16) { + size_t size = ElementCount(*input->dims); + switch (output->type) { + case kTfLiteInt8: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + case kTfLiteInt32: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else if (input->type == kTfLiteInt8) { + // Int8 to Int8 requantization, required if the input and output tensors + // have different scales and/or zero points. + size_t size = ElementCount(*input->dims); + switch (output->type) { + case kTfLiteInt8: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + case kTfLiteUInt8: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt32: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else if (input->type == kTfLiteUInt8) { + size_t size = ElementCount(*input->dims); + switch (output->type) { + case kTfLiteInt8: + reference_ops::Requantize( + tflite::micro::GetTensorData(input), size, + data->requantize_output_multiplier, data->requantize_output_shift, + data->input_zero_point, data->quantization_params.zero_point, + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + } else { + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/read_variable.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/read_variable.cc new file mode 100644 index 000000000..600a1bdd5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/read_variable.cc @@ -0,0 +1,87 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_resource_variable.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +namespace { + +constexpr int kInputVariableId = 0; +constexpr int kOutputValue = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(NumInputs(node) == 1); + TFLITE_DCHECK(NumOutputs(node) == 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input_resource_id_tensor = + micro_context->AllocateTempInputTensor(node, kInputVariableId); + + TFLITE_DCHECK(input_resource_id_tensor != nullptr); + TFLITE_DCHECK(input_resource_id_tensor->type == kTfLiteResource); + TFLITE_DCHECK(NumElements(input_resource_id_tensor) == 1); + + micro_context->DeallocateTempTfLiteTensor(input_resource_id_tensor); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input_resource_id_tensor = + tflite::micro::GetEvalInput(context, node, kInputVariableId); + TFLITE_DCHECK(input_resource_id_tensor != nullptr); + + TfLiteEvalTensor* output_value = + tflite::micro::GetEvalOutput(context, node, kOutputValue); + TFLITE_DCHECK(output_value != nullptr); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + MicroGraph& graph_info = micro_context->graph(); + + MicroResourceVariables* resources = graph_info.GetResourceVariables(); + if (resources == nullptr) { + MicroPrintf( + "READ_VARIABLE requires resource variables. Please create " + "ResourceVariables and pass it to the interpreter."); + return kTfLiteError; + } + TF_LITE_ENSURE_OK( + context, + resources->Read(input_resource_id_tensor->data.i32[0], output_value)); + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_READ_VARIABLE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce.cc new file mode 100644 index 000000000..b4734f932 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce.cc @@ -0,0 +1,72 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/reduce.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/mean.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/reduce.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +void* InitReduce(TfLiteContext* context, const char* buffer, size_t length) { + return context->AllocatePersistentBuffer(context, sizeof(OpDataReduce)); +} + +TfLiteStatus PrepareMax(TfLiteContext* context, TfLiteNode* node) { + return PrepareMaxHelper(context, node, + static_cast(node->user_data)); +} + +TfLiteStatus PrepareMeanOrSum(TfLiteContext* context, TfLiteNode* node) { + return PrepareMeanOrSumHelper(context, node, + static_cast(node->user_data)); +} + +TfLiteStatus EvalMean(TfLiteContext* context, TfLiteNode* node) { + return EvalMeanHelper(context, node, + static_cast(node->user_data)); +} + +TfLiteStatus EvalMax(TfLiteContext* context, TfLiteNode* node) { + OpDataReduce* op_data = static_cast(node->user_data); + return EvalMaxHelper(context, node, op_data); +} + +TfLiteStatus EvalSum(TfLiteContext* context, TfLiteNode* node) { + return EvalSumHelper(context, node, + static_cast(node->user_data)); +} + +TfLiteRegistration Register_MEAN() { + return tflite::micro::RegisterOp(InitReduce, PrepareMeanOrSum, EvalMean); +} + +TfLiteRegistration Register_REDUCE_MAX() { + return tflite::micro::RegisterOp(InitReduce, PrepareMax, EvalMax); +} + +TfLiteRegistration Register_SUM() { + return tflite::micro::RegisterOp(InitReduce, PrepareMeanOrSum, EvalSum); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce.h new file mode 100644 index 000000000..8d5240696 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce.h @@ -0,0 +1,64 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_REDUCE_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_REDUCE_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +extern const int kMaxNumberOfAxis; +extern const int kMaxNumberOfReducedAxis; + +struct OpDataReduce { + int32_t multiplier; + int shift; + int temp_buffer_idx; + int resolved_axis_idx; + int input_zp; + float input_scale; + int output_zp; + float output_scale; + int num_output_elements; +}; + +TfLiteStatus PrepareMaxHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data); + +TfLiteStatus PrepareMeanOrSumHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data); + +TfLiteStatus EvalMaxHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data); +TfLiteStatus EvalMeanHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data); +TfLiteStatus EvalSumHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data); + +void ReduceResolveAxis(const int* axis_data, int axis_count, + MeanParams* op_params); + +TfLiteRegistration Register_MEAN(); +TfLiteRegistration Register_REDUCE_MAX(); +TfLiteRegistration Register_SUM(); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_REDUCE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce_common.cc new file mode 100644 index 000000000..e84c0dc86 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reduce_common.cc @@ -0,0 +1,374 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/mean.h" +#include "tensorflow/lite/kernels/internal/reference/reduce.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/reduce.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +const int kMaxNumberOfAxis = 5; +const int kMaxNumberOfReducedAxis = 2; + +TfLiteStatus PrepareSimple(TfLiteContext* context, TfLiteNode* node, + int32_t* multiplier, int* shift) { + MicroContext* micro_context = GetMicroContext(context); + + // Inputs Tensor (dtype depends on quantization): + // [0] = Input + // [1] = Axis + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + + // Outputs Tensor (dtype depends on quantization): + // [0] = Output + + // Validate number of inputs and outputs + TF_LITE_ENSURE_EQ(context, node->inputs->size, 2); + TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); + + // Validate axis type + TfLiteTensor* axis = micro_context->AllocateTempInputTensor(node, 1); + TF_LITE_ENSURE(context, axis != nullptr); + TF_LITE_ENSURE_TYPES_EQ(context, axis->type, kTfLiteInt32); + + if (input->type == kTfLiteInt8) { + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + const double real_multiplier = static_cast(input->params.scale) / + static_cast(output->params.scale); + QuantizeMultiplier(real_multiplier, multiplier, shift); + micro_context->DeallocateTempTfLiteTensor(output); + } + micro_context->DeallocateTempTfLiteTensor(axis); + micro_context->DeallocateTempTfLiteTensor(input); + return kTfLiteOk; +} + +TfLiteStatus PrepareMaxHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data) { + TF_LITE_ENSURE_OK(context, PrepareSimple(context, node, &op_data->multiplier, + &op_data->shift)); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TfLiteTensor* axis = micro_context->AllocateTempInputTensor(node, 1); + + op_data->input_scale = input->params.scale; + op_data->output_scale = output->params.scale; + op_data->num_output_elements = NumElements(output); + + context->RequestScratchBufferInArena(context, sizeof(int) * input->dims->size, + &op_data->temp_buffer_idx); + context->RequestScratchBufferInArena( + context, sizeof(int) * static_cast(ElementCount(*axis->dims)), + &op_data->resolved_axis_idx); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(axis); + return kTfLiteOk; +} + +TfLiteStatus PrepareMeanOrSumHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data) { + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { + const double real_multiplier = static_cast(input->params.scale) / + static_cast(output->params.scale); + QuantizeMultiplier(real_multiplier, &op_data->multiplier, &op_data->shift); + } + + int output_size = NumElements(output); + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { + context->RequestScratchBufferInArena(context, output_size * sizeof(int32_t), + &op_data->temp_buffer_idx); + op_data->input_zp = input->params.zero_point; + op_data->input_scale = input->params.scale; + op_data->output_zp = output->params.zero_point; + op_data->output_scale = output->params.scale; + } + + TF_LITE_ENSURE_OK( + context, + PrepareSimple(context, node, &(op_data->multiplier), &(op_data->shift))); + // TODO(b/144955155): Support uint8_t(b/144955155) and int8_t(b/144955018) + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +void ResolveAxis(const int* axis_data, int axis_count, + tflite::MeanParams* op_params) { + int i = 0; + for (; i < axis_count; ++i) { + op_params->axis[i] = static_cast(axis_data[i]); + } + for (; i < 4; ++i) { + op_params->axis[i] = 1; + } + op_params->axis_count = axis_count; +} + +TfLiteStatus EvalMeanHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* axis = tflite::micro::GetEvalInput(context, node, 1); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TfLiteReducerParams* params = + reinterpret_cast(node->builtin_data); + + int num_axis = static_cast(ElementCount(*axis->dims)); + int temp_index[kMaxNumberOfAxis]; + int resolved_axis[kMaxNumberOfReducedAxis]; + + tflite::MeanParams op_params; + ResolveAxis(tflite::micro::GetTensorData(axis), num_axis, &op_params); + + // Special case mean implementation exists for 4D mean across axes 1 and 2. + bool special_case_4d_axes_1_and_2 = + input->dims->size == 4 && op_params.axis_count == 2 && + ((op_params.axis[0] == 1 && op_params.axis[1] == 2) || + (op_params.axis[0] == 2 && op_params.axis[1] == 1)); + + switch (input->type) { + case kTfLiteFloat32: { + // Defer to specialized implementation for 4D Mean across axes 1 & 2. + if (params->keep_dims && special_case_4d_axes_1_and_2) { + reference_ops::Mean(op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + TF_LITE_ENSURE( + context, + reference_ops::Mean( + tflite::micro::GetTensorData(input), input->dims->data, + input->dims->size, tflite::micro::GetTensorData(output), + output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_index, resolved_axis, + tflite::micro::GetTensorData(output))); + } + } break; + case kTfLiteInt8: { + // Defer to specialized implementation for 4D Mean across axes 1 & 2. + if (params->keep_dims && special_case_4d_axes_1_and_2) { + reference_integer_ops::Mean( + op_params, op_data->multiplier, op_data->shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), op_data->input_zp, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), op_data->output_zp); + } else if (op_data->input_zp == op_data->output_zp && + op_data->input_scale == op_data->output_scale) { + int32_t* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + TF_LITE_ENSURE( + context, + reference_ops::Mean( + tflite::micro::GetTensorData(input), input->dims->data, + input->dims->size, tflite::micro::GetTensorData(output), + output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_index, resolved_axis, temp_buffer)); + } else { + int32_t* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + TF_LITE_ENSURE( + context, + reference_ops::QuantizedMeanOrSum( + tflite::micro::GetTensorData(input), op_data->input_zp, + op_data->input_scale, input->dims->data, input->dims->size, + tflite::micro::GetTensorData(output), + op_data->output_zp, op_data->output_scale, output->dims->data, + output->dims->size, tflite::micro::GetTensorData(axis), + num_axis, params->keep_dims, temp_index, resolved_axis, + temp_buffer, false)); + } + } break; + case kTfLiteInt16: { + // Defer to specialized implementation for 4D Mean across axes 1 & 2. + if (params->keep_dims && special_case_4d_axes_1_and_2) { + reference_integer_ops::Mean( + op_params, op_data->multiplier, op_data->shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), op_data->input_zp, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), op_data->output_zp); + } else if (op_data->input_zp == op_data->output_zp && + op_data->input_scale == op_data->output_scale) { + int32_t* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + TF_LITE_ENSURE( + context, + reference_ops::Mean(tflite::micro::GetTensorData(input), + input->dims->data, input->dims->size, + tflite::micro::GetTensorData(output), + output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), + num_axis, params->keep_dims, temp_index, + resolved_axis, temp_buffer)); + } else { + int32_t* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + TF_LITE_ENSURE( + context, + reference_ops::QuantizedMeanOrSum( + tflite::micro::GetTensorData(input), op_data->input_zp, + op_data->input_scale, input->dims->data, input->dims->size, + tflite::micro::GetTensorData(output), + op_data->output_zp, op_data->output_scale, output->dims->data, + output->dims->size, tflite::micro::GetTensorData(axis), + num_axis, params->keep_dims, temp_index, resolved_axis, + temp_buffer, false)); + } + } break; + default: + TF_LITE_ENSURE_MSG(context, false, + "Currently, only float32, int8 or int16 input type " + "is supported."); + } + return kTfLiteOk; +} + +TfLiteStatus EvalMaxHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* axis = tflite::micro::GetEvalInput(context, node, 1); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + TfLiteReducerParams* params = + static_cast(node->builtin_data); + + // Interpret an axis tensor with null dimensions as a scalar + int num_axis = static_cast(ElementCount(*axis->dims)); + int* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + int* resolved_axis = static_cast( + context->GetScratchBuffer(context, op_data->resolved_axis_idx)); + switch (input->type) { + case kTfLiteFloat32: + TF_LITE_ENSURE( + context, + reference_ops::ReduceGeneric( + tflite::micro::GetTensorData(input), input->dims->data, + input->dims->size, tflite::micro::GetTensorData(output), + output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_buffer, resolved_axis, + std::numeric_limits::lowest(), + [](const float current, const float in) -> float { + return (in > current) ? in : current; + })); + break; + case kTfLiteInt8: + TF_LITE_ENSURE_EQ(context, static_cast(op_data->input_scale), + static_cast(op_data->output_scale)); + TF_LITE_ENSURE_EQ(context, op_data->input_zp, op_data->output_zp); + TF_LITE_ENSURE( + context, + reference_ops::ReduceGeneric( + tflite::micro::GetTensorData(input), input->dims->data, + input->dims->size, tflite::micro::GetTensorData(output), + output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_buffer, resolved_axis, + std::numeric_limits::lowest(), + [](const int8_t current, const int8_t in) -> int8_t { + return (in > current) ? in : current; + })); + break; + default: + MicroPrintf("Only float32 and int8 types are supported."); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus EvalSumHelper(TfLiteContext* context, TfLiteNode* node, + OpDataReduce* op_data) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* axis = tflite::micro::GetEvalInput(context, node, 1); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + TfLiteReducerParams* params = + static_cast(node->builtin_data); + + // Interpret an axis tensor with null dimensions as a scalar. + int num_axis = static_cast(ElementCount(*axis->dims)); + int temp_index[kMaxNumberOfAxis]; + int resolved_axis[kMaxNumberOfReducedAxis]; + + switch (input->type) { + case kTfLiteFloat32: { + TF_LITE_ENSURE( + context, + reference_ops::ReduceGeneric( + tflite::micro::GetTensorData(input), input->dims->data, + input->dims->size, tflite::micro::GetTensorData(output), + output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_index, resolved_axis, /*init_value=*/0.f, + [](const float current, const float in) -> float { + return in + current; + })); + } break; + case kTfLiteInt8: { + int32_t* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + TF_LITE_ENSURE( + context, + reference_ops::QuantizedMeanOrSum( + tflite::micro::GetTensorData(input), op_data->input_zp, + op_data->input_scale, input->dims->data, input->dims->size, + tflite::micro::GetTensorData(output), op_data->output_zp, + op_data->output_scale, output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_index, resolved_axis, temp_buffer, + /*compute_sum=*/true)); + } break; + case kTfLiteInt16: { + int32_t* temp_buffer = static_cast( + context->GetScratchBuffer(context, op_data->temp_buffer_idx)); + TF_LITE_ENSURE( + context, + reference_ops::QuantizedMeanOrSum( + tflite::micro::GetTensorData(input), op_data->input_zp, + op_data->input_scale, input->dims->data, input->dims->size, + tflite::micro::GetTensorData(output), op_data->output_zp, + op_data->output_scale, output->dims->data, output->dims->size, + tflite::micro::GetTensorData(axis), num_axis, + params->keep_dims, temp_index, resolved_axis, temp_buffer, + /*compute_sum=*/true)); + } break; + default: + MicroPrintf("Only float32, int8, and int16 types are supported."); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reshape.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reshape.cc new file mode 100644 index 000000000..832ba2612 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/reshape.cc @@ -0,0 +1,118 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace reshape { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus ReshapeOutput(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + // Tensorflow's Reshape allows one of the shape components to have the + // special -1 value, meaning it will be calculated automatically based on the + // input. Here we calculate what that dimension should be so that the number + // of output elements in the same as the number of input elements. + int num_input_elements = NumElements(input); + TfLiteIntArray* output_shape = output->dims; + + if (NumInputs(node) == 1 && // Legacy scalar supported with params. + output_shape->size == 1 && output_shape->data[0] == 0) { + // Legacy tflite models use a shape parameter of [0] to indicate scalars, + // so adjust accordingly. TODO(b/111614235): Allow zero-sized buffers during + // toco conversion. + output_shape->size = 0; + } + + int num_output_elements = 1; + int stretch_dim = -1; + for (int i = 0; i < output_shape->size; ++i) { + int value = output_shape->data[i]; + if (value == -1) { + TF_LITE_ENSURE_EQ(context, stretch_dim, -1); + stretch_dim = i; + } else { + num_output_elements *= value; + } + } + if (stretch_dim != -1) { + output_shape->data[stretch_dim] = num_input_elements / num_output_elements; + num_output_elements *= output_shape->data[stretch_dim]; + } + + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + TF_LITE_ENSURE_EQ(context, num_input_elements, num_output_elements); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE(context, NumInputs(node) == 1 || NumInputs(node) == 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TF_LITE_ENSURE_EQ(context, ReshapeOutput(context, node), kTfLiteOk); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + // TODO(b/162522304): storing input bytes in OpData increases some models + // significantly, possibly due to alignment issues. + size_t input_bytes; + TF_LITE_ENSURE_STATUS(TfLiteTypeSizeOf(input->type, &input_bytes)); + input_bytes *= ElementCount(*input->dims); + + // Do nothing for in-place reshape. + if (input->data.raw != output->data.raw) { + // Otherwise perform reshape with copy. + memcpy(output->data.raw, input->data.raw, input_bytes); + } + return kTfLiteOk; +} + +} // namespace reshape + +TfLiteRegistration Register_RESHAPE() { + return tflite::micro::RegisterOp(nullptr, reshape::Prepare, reshape::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/resize_bilinear.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/resize_bilinear.cc new file mode 100644 index 000000000..56432e1b5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/resize_bilinear.cc @@ -0,0 +1,116 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/resize_bilinear.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kSizeTensor = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TfLiteTensor* size = + micro_context->AllocateTempInputTensor(node, kSizeTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + + TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); + TF_LITE_ENSURE_EQ(context, NumDimensions(size), 1); + + TF_LITE_ENSURE_EQ(context, size->type, kTfLiteInt32); + output->type = input->type; + + TF_LITE_ENSURE_MSG(context, IsConstantTensor(size), + "Non constant size tensor not supported"); + + // Ensure params are valid. + auto* params = + reinterpret_cast(node->builtin_data); + if (params->half_pixel_centers && params->align_corners) { + MicroPrintf("If half_pixel_centers is True, align_corners must be False."); + return kTfLiteError; + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(size); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = + reinterpret_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* size = + tflite::micro::GetEvalInput(context, node, kSizeTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + if (output->type == kTfLiteFloat32) { + tflite::ResizeBilinearParams op_params; + op_params.align_corners = params->align_corners; + op_params.half_pixel_centers = params->half_pixel_centers; + reference_ops::ResizeBilinear(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(size), + tflite::micro::GetTensorData(size), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else if (output->type == kTfLiteInt8) { + tflite::ResizeBilinearParams op_params; + op_params.align_corners = params->align_corners; + op_params.half_pixel_centers = params->half_pixel_centers; + reference_ops::ResizeBilinearInteger( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(size), + tflite::micro::GetTensorData(size), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + MicroPrintf("Output type is %d, requires float or int8.", output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_RESIZE_BILINEAR() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/resize_nearest_neighbor.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/resize_nearest_neighbor.cc new file mode 100644 index 000000000..756cf03fa --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/resize_nearest_neighbor.cc @@ -0,0 +1,126 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/resize_nearest_neighbor.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace resize_nearest_neighbor { + +constexpr int kInputTensor = 0; +constexpr int kSizeTensor = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TfLiteTensor* size = + micro_context->AllocateTempInputTensor(node, kSizeTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + + // Our current implementations rely on the input being 4D, + // and the size being 1D tensor with exactly 2 elements. + TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); + TF_LITE_ENSURE_EQ(context, NumDimensions(size), 1); + TF_LITE_ENSURE_EQ(context, size->type, kTfLiteInt32); + TF_LITE_ENSURE_EQ(context, size->dims->data[0], 2); + + output->type = input->type; + + if (!IsConstantTensor(size)) { + MicroPrintf("Dynamic tensors are unsupported in tfmicro."); + return kTfLiteError; + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(size); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = + reinterpret_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* size = + tflite::micro::GetEvalInput(context, node, kSizeTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + tflite::ResizeNearestNeighborParams op_params; + op_params.align_corners = params->align_corners; + op_params.half_pixel_centers = false; + + if (output->type == kTfLiteFloat32) { + reference_ops::ResizeNearestNeighbor( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(size), + tflite::micro::GetTensorData(size), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else if (output->type == kTfLiteInt8) { + reference_ops::ResizeNearestNeighbor( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(size), + tflite::micro::GetTensorData(size), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else if (output->type == kTfLiteInt16) { + reference_ops::ResizeNearestNeighbor( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(size), + tflite::micro::GetTensorData(size), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + MicroPrintf("Output tensor type %s (%d) not supported.", + TfLiteTypeGetName(output->type), output->type); + + return kTfLiteError; + } + + return kTfLiteOk; +} +} // namespace resize_nearest_neighbor + +TfLiteRegistration Register_RESIZE_NEAREST_NEIGHBOR() { + return tflite::micro::RegisterOp(nullptr, resize_nearest_neighbor::Prepare, + resize_nearest_neighbor::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/round.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/round.cc new file mode 100644 index 000000000..0bda8783a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/round.cc @@ -0,0 +1,76 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/round.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace round { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteFloat32); + TF_LITE_ENSURE_TYPES_EQ(context, output->type, input->type); + TF_LITE_ENSURE_EQ(context, output->bytes, input->bytes); + TF_LITE_ENSURE_EQ(context, output->dims->size, input->dims->size); + for (int i = 0; i < output->dims->size; ++i) { + TF_LITE_ENSURE_EQ(context, output->dims->data[i], input->dims->data[i]); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + reference_ops::Round(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + + return kTfLiteOk; +} +} // namespace round + +TfLiteRegistration Register_ROUND() { + return tflite::micro::RegisterOp(nullptr, round::Prepare, round::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/select.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/select.cc new file mode 100644 index 000000000..1b05bd2fb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/select.cc @@ -0,0 +1,197 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/select.h" + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +constexpr int kInputTensorCondition = 0; +constexpr int kInputTensorX = 1; +constexpr int kInputTensorY = 2; +constexpr int kOutputTensor = 0; + +struct OpData { + bool requires_broadcast; + // True if input condition is scalar or input condition has rank one and + // matches the first dimension of other inputs. + bool has_low_rank_input_condition; +}; + +void* SelectInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + auto* data = static_cast( + context->AllocatePersistentBuffer(context, sizeof(OpData))); + data->requires_broadcast = false; + data->has_low_rank_input_condition = false; + return data; +} + +TfLiteStatus CheckBroadcastShape(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + const TfLiteTensor* input3, + const TfLiteIntArray* output_shape) { + const int dims1 = NumDimensions(input1); + const int dims2 = NumDimensions(input2); + const int dims3 = NumDimensions(input3); + const int out_dims = std::max(std::max(dims1, dims2), dims3); + TF_LITE_ENSURE_EQ(context, out_dims, output_shape->size); + + for (int i = 0; i < out_dims; ++i) { + const int d1 = i >= dims1 ? 1 : SizeOfDimension(input1, dims1 - i - 1); + const int d2 = i >= dims2 ? 1 : SizeOfDimension(input2, dims2 - i - 1); + const int d3 = i >= dims3 ? 1 : SizeOfDimension(input3, dims3 - i - 1); + const int min_value = std::min(std::min(d1, d2), d3); + int max_value = std::max(std::max(d1, d2), d3); + // If one dimention is 0, others must be 0 or 1. + if (min_value == 0) max_value = 0; + if (!(d1 == 1 || d1 == max_value) || !(d2 == 1 || d2 == max_value) || + !(d3 == 1 || d3 == max_value)) { + MicroPrintf("Given shapes are not broadcastable."); + return kTfLiteError; + } + TF_LITE_ENSURE_EQ(context, output_shape->data[out_dims - i - 1], max_value); + } + return kTfLiteOk; +} + +TfLiteStatus SelectPrepare(TfLiteContext* context, TfLiteNode* node) { + OpData* data = reinterpret_cast(node->user_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input_condition = + micro_context->AllocateTempInputTensor(node, kInputTensorCondition); + + TfLiteTensor* input_x = + micro_context->AllocateTempInputTensor(node, kInputTensorX); + + TfLiteTensor* input_y = + micro_context->AllocateTempInputTensor(node, kInputTensorY); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + + // Input must be bool. + TF_LITE_ENSURE_TYPES_EQ(context, input_condition->type, kTfLiteBool); + TF_LITE_ENSURE_TYPES_EQ(context, input_x->type, input_y->type); + output->type = input_x->type; + + // Respect the original output shape when there are mixed shapes to represent + // a scalar data. + if (GetTensorShape(input_condition).FlatSize() == 1 && + GetTensorShape(input_x).FlatSize() == 1 && + GetTensorShape(input_y).FlatSize() == 1 && + GetTensorShape(output).FlatSize() == 1) { + return kTfLiteOk; + } + + bool same_shape = HaveSameShapes(input_condition, input_x) && + HaveSameShapes(input_x, input_y); + if (!same_shape) { + TF_LITE_ENSURE_OK( + context, CheckBroadcastShape(context, input_condition, input_x, input_y, + output->dims)); + data->requires_broadcast = true; + } + + micro_context->DeallocateTempTfLiteTensor(input_condition); + micro_context->DeallocateTempTfLiteTensor(input_x); + micro_context->DeallocateTempTfLiteTensor(input_y); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus SelectEval(TfLiteContext* context, TfLiteNode* node) { + OpData* data = static_cast(node->user_data); + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input_condition = + micro_context->AllocateTempInputTensor(node, kInputTensorCondition); + + TfLiteTensor* input_x = + micro_context->AllocateTempInputTensor(node, kInputTensorX); + + TfLiteTensor* input_y = + micro_context->AllocateTempInputTensor(node, kInputTensorY); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + +#define TF_LITE_SELECT(type, op) \ + reference_ops::op(GetTensorShape(input_condition), \ + GetTensorData(input_condition), \ + GetTensorShape(input_x), GetTensorData(input_x), \ + GetTensorShape(input_y), GetTensorData(input_y), \ + GetTensorShape(output), GetTensorData(output)); + +#define TF_LITE_SWITCH(type, op) \ + switch (type) { \ + case kTfLiteFloat32: \ + TF_LITE_SELECT(float, op); \ + break; \ + case kTfLiteInt8: \ + TF_LITE_SELECT(int8_t, op); \ + break; \ + case kTfLiteInt16: \ + TF_LITE_SELECT(int16_t, op); \ + break; \ + default: \ + MicroPrintf("Does not support type other than %s, but got %s", \ + "int8|int16|float32", TfLiteTypeGetName(type)); \ + return kTfLiteError; \ + } + + if (data->has_low_rank_input_condition) { + MicroPrintf("Not yet implemented."); + return kTfLiteError; + } else if (data->requires_broadcast) { + TF_LITE_SWITCH(input_x->type, BroadcastSelect5DSlow); + } else { + TF_LITE_SWITCH(input_x->type, Select); + } + +#undef TF_LITE_SELECT +#undef TF_LITE_SWITCH + micro_context->DeallocateTempTfLiteTensor(input_condition); + micro_context->DeallocateTempTfLiteTensor(input_x); + micro_context->DeallocateTempTfLiteTensor(input_y); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +// SelectV2 op selects values of 'x' if the corresponding value of 'condition' +// is true or the value of 'y' if false. There are valid condition input sizes: +// +// 1. Either the same shape (in which case the select is elementwise), or +// 2. Broadcastable shapes between 'condition', 'x' and 'y'. +TfLiteRegistration Register_SELECT_V2() { + return tflite::micro::RegisterOp(tflite::SelectInit, tflite::SelectPrepare, + tflite::SelectEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/shape.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/shape.cc new file mode 100644 index 000000000..e85bb81f7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/shape.cc @@ -0,0 +1,67 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +namespace { +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +void ExtractShape(const TfLiteEvalTensor* input, int32_t* output_data) { + for (int i = 0; i < input->dims->size; ++i) { + output_data[i] = input->dims->data[i]; + } +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + if (output->type != kTfLiteInt32) { + MicroPrintf("Output type %s (%d) not supported.", + TfLiteTypeGetName(output->type), output->type); + return kTfLiteError; + } else { + ExtractShape(input, tflite::micro::GetTensorData(output)); + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_SHAPE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/slice.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/slice.cc new file mode 100644 index 000000000..cc3cd5b42 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/slice.cc @@ -0,0 +1,157 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/slice.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +namespace { + +constexpr int kInputTensor = 0; +constexpr int kBeginTensor = 1; +constexpr int kSizeTensor = 2; +constexpr int kOutputTensor = 0; + +const int kMaxDim = 5; + +template +void GetBeginAndSizeVectors(int dimensions, const TfLiteEvalTensor* begin, + const TfLiteEvalTensor* size, int32_t* begins, + int32_t* sizes) { + int offset = kMaxDim - dimensions; + for (int idx = 0; idx < dimensions; ++idx) { + begins[offset + idx] = tflite::micro::GetTensorData(begin)[idx]; + sizes[offset + idx] = tflite::micro::GetTensorData(size)[idx]; + } +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TFLITE_DCHECK(input != nullptr); + TfLiteTensor* begin = + micro_context->AllocateTempInputTensor(node, kBeginTensor); + TFLITE_DCHECK(begin != nullptr); + TfLiteTensor* size = + micro_context->AllocateTempInputTensor(node, kSizeTensor); + TFLITE_DCHECK(size != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TFLITE_DCHECK(output != nullptr); + + // Ensure validity of input tensor and its dimension. + TFLITE_DCHECK(input->type == output->type); + TFLITE_DCHECK(begin->type == size->type); + TFLITE_DCHECK(begin->type == kTfLiteInt32 || begin->type == kTfLiteInt64); + TFLITE_DCHECK(size->type == kTfLiteInt32 || size->type == kTfLiteInt64); + TFLITE_DCHECK(NumDimensions(begin) == 1); + TFLITE_DCHECK(NumDimensions(size) == 1); + TFLITE_DCHECK(NumElements(begin) == NumElements(size)); + TFLITE_DCHECK(NumDimensions(input) <= kMaxDim); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(begin); + micro_context->DeallocateTempTfLiteTensor(size); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* begin = + tflite::micro::GetEvalInput(context, node, kBeginTensor); + const TfLiteEvalTensor* size = + tflite::micro::GetEvalInput(context, node, kSizeTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + tflite::SliceParams op_params; + op_params.begin_count = kMaxDim; + op_params.size_count = kMaxDim; + for (int i = 0; i < kMaxDim; ++i) { + op_params.begin[i] = 0; + op_params.size[i] = 1; + } + + if (begin->type == kTfLiteInt32) { + GetBeginAndSizeVectors(input->dims->size, begin, size, + op_params.begin, op_params.size); + } else if (begin->type == kTfLiteInt64) { + GetBeginAndSizeVectors(input->dims->size, begin, size, + op_params.begin, op_params.size); + } else { + MicroPrintf("Begin tensor type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + + switch (input->type) { + case kTfLiteFloat32: + reference_ops::Slice(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt32: + reference_ops::Slice( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::Slice( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::Slice( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Input tensor type %s (%d) not supported.", + TfLiteTypeGetName(input->type), input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_SLICE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax.cc new file mode 100644 index 000000000..67a1b4065 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax.cc @@ -0,0 +1,90 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/softmax.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/softmax.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +void SoftmaxQuantized(const TfLiteEvalTensor* input, TfLiteEvalTensor* output, + const SoftmaxParams& op_data) { + if (input->type == kTfLiteInt8) { + if (output->type == kTfLiteInt16) { + tflite::reference_ops::Softmax( + op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + tflite::reference_ops::Softmax( + op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + } else { + tflite::reference_ops::SoftmaxInt16( + op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} + +TfLiteStatus SoftmaxEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + + TFLITE_DCHECK(node->user_data != nullptr); + SoftmaxParams op_data = *static_cast(node->user_data); + + switch (input->type) { + case kTfLiteFloat32: { + tflite::reference_ops::Softmax( + op_data, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } + case kTfLiteInt8: + case kTfLiteInt16: { + SoftmaxQuantized(input, output, op_data); + return kTfLiteOk; + } + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } +} +} // namespace + +TfLiteRegistration Register_SOFTMAX() { + return tflite::micro::RegisterOp(SoftmaxInit, SoftmaxPrepare, SoftmaxEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax.h new file mode 100644 index 000000000..7096d2020 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax.h @@ -0,0 +1,69 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_SOFTMAX_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_SOFTMAX_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +void* SoftmaxInit(TfLiteContext* context, const char* buffer, size_t length); + +// Common helper function to SoftmaxPrepare. +TfLiteStatus CalculateSoftmaxParams(TfLiteContext* context, + const TfLiteTensor* input, + TfLiteTensor* output, + const TfLiteSoftmaxParams* params, + SoftmaxParams* op_data); + +TfLiteStatus SoftmaxPrepare(TfLiteContext* context, TfLiteNode* node); + +// This is the most generic TfLiteRegistration. The actual supported types may +// still be target dependent. The only requirement is that every implementation +// (reference or optimized) must define this function. +TfLiteRegistration Register_SOFTMAX(); + +#if defined(XTENSA) || defined(CMSIS_NN) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int8 input and int16 output. +TfLiteRegistration Register_SOFTMAX_INT8_INT16(); +#else +inline TfLiteRegistration Register_SOFTMAX_INT8_INT16() { + return Register_SOFTMAX(); +} +#endif + +#if defined(CMSIS_NN) +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int8 input/output and uses the latency optimized implementations. +TfLiteRegistration Register_SOFTMAX_INT8(); + +// Returns a TfLiteRegistration struct for kernel variant that only supports +// int16 input/output and uses the latency optimized implementations. +TfLiteRegistration Register_SOFTMAX_INT16(); + +#else +inline TfLiteRegistration Register_SOFTMAX_INT8() { return Register_SOFTMAX(); } + +inline TfLiteRegistration Register_SOFTMAX_INT16() { + return Register_SOFTMAX(); +} +#endif + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_SOFTMAX_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax_common.cc new file mode 100644 index 000000000..62b8b290b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/softmax_common.cc @@ -0,0 +1,168 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/softmax.h" +#include "tensorflow/lite/micro/micro_context.h" + +namespace tflite { + +namespace { +// Softmax parameter data that persists in user_data +const int kInt16LUTArraySize = LUTSize(); + +TfLiteStatus InitializeLutForInt16(TfLiteContext* context, + const TfLiteTensor* input, + TfLiteTensor* output, + SoftmaxParams* op_data) { + // Only allocate LUTs for KTfLiteInt16 data type + if (input->type == kTfLiteInt16) { + void* raw_exp_lut = context->AllocatePersistentBuffer( + context, sizeof(int16_t) * kInt16LUTArraySize); + TF_LITE_ENSURE(context, raw_exp_lut != nullptr); + op_data->exp_lut = reinterpret_cast(raw_exp_lut); + void* one_over_one_plus_x_lut = context->AllocatePersistentBuffer( + context, sizeof(int16_t) * kInt16LUTArraySize); + TF_LITE_ENSURE(context, one_over_one_plus_x_lut != nullptr); + op_data->one_over_one_plus_x_lut = + reinterpret_cast(one_over_one_plus_x_lut); + } + + if (output->type == kTfLiteInt16) { + TF_LITE_ENSURE(context, + input->type == kTfLiteInt8 || input->type == kTfLiteInt16); + } else { + TF_LITE_ENSURE_EQ(context, input->type, output->type); + } + + // Populate LUT if required + if (input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0); + // exp LUT only used on negative values + // we consider exp(-10.0) is insignificant to accumulation + const int32_t range = std::numeric_limits::max() - + std::numeric_limits::min(); + LUTPopulate( + 10.0f / range, std::numeric_limits::max(), 2.0f / range, 0, + [](float value) { return std::exp(value); }, op_data->exp_lut); + + LUTPopulate( + 1.0f / range, std::numeric_limits::min(), 2.0f / range, 0, + [](float value) { return 1.0f / (1.0f + value); }, + op_data->one_over_one_plus_x_lut); + + op_data->zero_point = output->params.zero_point; + op_data->scale = output->params.scale; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteStatus CalculateSoftmaxParams(TfLiteContext* context, + const TfLiteTensor* input, + TfLiteTensor* output, + const TfLiteSoftmaxParams* params, + SoftmaxParams* op_data) { + if (InitializeLutForInt16(context, input, output, op_data) != kTfLiteOk) { + return kTfLiteError; + } + + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { + if (input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, input->params.zero_point, 0); + TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0); + TF_LITE_ENSURE_NEAR(context, output->params.scale, 1.f / 32768, + (0.001f * 1.f / 32768)); + } else { // input->type == kTfLiteInt8 + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteInt8); + if (output->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, output->params.zero_point, -32768); + TF_LITE_ENSURE_NEAR(context, output->params.scale, 1.f / 65536, + (0.001f * 1.f / 65536)); + } else { // output->type == kTfLiteint8 + TF_LITE_ENSURE_TYPES_EQ(context, output->type, kTfLiteInt8); + TF_LITE_ENSURE_EQ(context, output->params.zero_point, -128); + TF_LITE_ENSURE(context, output->params.scale == 1.f / 256); + } + } + + static const int kScaledDiffIntegerBits = 5; + + // Calculate input_multiplier and input_left_shift + if (input->type == kTfLiteInt16) { + int input_left_shift; + double input_scale_beta_rescale = + static_cast(input->params.scale) * + static_cast(params->beta) / + (10.0 / 65535.0); // scale the input_diff such that [-65535, 0] + // correspond to [-10.0, 0.0] + QuantizeMultiplier(input_scale_beta_rescale, &op_data->input_multiplier, + &input_left_shift); + op_data->input_left_shift = input_left_shift; + } else { + int input_left_shift; + tflite::PreprocessSoftmaxScaling( + static_cast(params->beta), + static_cast(input->params.scale), kScaledDiffIntegerBits, + &op_data->input_multiplier, &input_left_shift); + op_data->input_left_shift = input_left_shift; + op_data->diff_min = + -1.0 * tflite::CalculateInputRadius(kScaledDiffIntegerBits, + op_data->input_left_shift); + } + } else { + TF_LITE_ENSURE_TYPES_EQ(context, input->type, kTfLiteFloat32); + TF_LITE_ENSURE_TYPES_EQ(context, output->type, kTfLiteFloat32); + op_data->beta = static_cast(params->beta); + } + return kTfLiteOk; +} + +void* SoftmaxInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(SoftmaxParams)); +} + +TfLiteStatus SoftmaxPrepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, input != nullptr); + TF_LITE_ENSURE(context, NumDimensions(input) >= 1); + TfLiteTensor* output = micro_context->AllocateTempOutputTensor(node, 0); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE(context, node->user_data != nullptr); + SoftmaxParams* op_data = static_cast(node->user_data); + + auto* params = static_cast(node->builtin_data); + auto ret_val = + CalculateSoftmaxParams(context, input, output, params, op_data); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return ret_val; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/space_to_batch_nd.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/space_to_batch_nd.cc new file mode 100644 index 000000000..11b32c3f6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/space_to_batch_nd.cc @@ -0,0 +1,121 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/space_to_batch_nd.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +namespace { + +constexpr int kInputTensor = 0; +constexpr int kBlockShapeTensor = 1; +constexpr int kCropsTensor = 2; +constexpr int kOutputTensor = 0; + +// Currently, only 3D NHC and 4D NHWC input/output op_context are supported. +// In case of 3D input, it will be extended to 3D NHWC by adding W=1. +// The 4D array need to have exactly 2 spatial dimensions. +// TODO(b/149952582): Support arbitrary dimension in SpaceToBatchND. +const int kInputOutputMinDimensionNum = 3; +const int kInputOutputMaxDimensionNum = 4; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(SpaceToBatchParams)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, input != nullptr && output != nullptr); + + TF_LITE_ENSURE(context, NumDimensions(input) >= kInputOutputMinDimensionNum); + TF_LITE_ENSURE(context, NumDimensions(output) >= kInputOutputMinDimensionNum); + TF_LITE_ENSURE(context, NumDimensions(input) <= kInputOutputMaxDimensionNum); + TF_LITE_ENSURE(context, NumDimensions(output) <= kInputOutputMaxDimensionNum); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const SpaceToBatchParams& params = + *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* block_shape = + tflite::micro::GetEvalInput(context, node, kBlockShapeTensor); + const TfLiteEvalTensor* crops = + tflite::micro::GetEvalInput(context, node, kCropsTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + reference_ops::SpaceToBatchND( + params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(block_shape), + tflite::micro::GetTensorData(block_shape), + tflite::micro::GetTensorShape(crops), + tflite::micro::GetTensorData(crops), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::SpaceToBatchND( + params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(block_shape), + tflite::micro::GetTensorData(block_shape), + tflite::micro::GetTensorShape(crops), + tflite::micro::GetTensorData(crops), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_SPACE_TO_BATCH_ND() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/space_to_depth.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/space_to_depth.cc new file mode 100644 index 000000000..3640e2cdb --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/space_to_depth.cc @@ -0,0 +1,127 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/space_to_depth.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +namespace { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; +constexpr int kBatchRank = 0; +constexpr int kHeightRank = 1; +constexpr int kWidthRank = 2; +constexpr int kDepthRank = 3; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + auto* params = + reinterpret_cast(node->builtin_data); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); + + auto data_type = output->type; + TF_LITE_ENSURE(context, + data_type == kTfLiteFloat32 || data_type == kTfLiteInt8); + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + const int block_size = params->block_size; + const int input_height = input->dims->data[kHeightRank]; + const int input_width = input->dims->data[kWidthRank]; + int output_height = input_height / block_size; + int output_width = input_width / block_size; + + TF_LITE_ENSURE_EQ(context, input_height, output_height * block_size); + TF_LITE_ENSURE_EQ(context, input_width, output_width * block_size); + + // Relocate dims to the persistent storage arena before changing them, + // otherwise we'd be modifying temporary copies made by the interpreters each + // time they process the layer. + TfLiteEvalTensor* output_eval = + micro::GetEvalOutput(context, node, kOutputTensor); + TF_LITE_ENSURE_OK(context, micro::CreateWritableTensorDimsWithCopy( + context, output, output_eval)); + + output->dims->data[kBatchRank] = input->dims->data[kBatchRank]; + output->dims->data[kHeightRank] = output_height; + output->dims->data[kWidthRank] = output_width; + output->dims->data[kDepthRank] = + input->dims->data[kDepthRank] * block_size * block_size; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = + reinterpret_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = micro::GetEvalOutput(context, node, kOutputTensor); + + SpaceToDepthParams op_params; + op_params.block_size = params->block_size; + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + reference_ops::SpaceToDepth(op_params, micro::GetTensorShape(input), + micro::GetTensorData(input), + micro::GetTensorShape(output), + micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::SpaceToDepth(op_params, micro::GetTensorShape(input), + micro::GetTensorData(input), + micro::GetTensorShape(output), + micro::GetTensorData(output)); + break; + default: + MicroPrintf("SPACE_TO_DEPTH only supports FLOAT32 and INT8, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_SPACE_TO_DEPTH() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/split.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/split.cc new file mode 100644 index 000000000..4ff748562 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/split.cc @@ -0,0 +1,128 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace split { + +template +TfLiteStatus SplitImpl(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input, int axis_value) { + const int output_count = NumOutputs(node); + const TfLiteIntArray* input_dims = input->dims; + const TfLiteEvalTensor* output0 = + tflite::micro::GetEvalOutput(context, node, 0); + const TfLiteIntArray* output_dims = output0->dims; + + const int split_dimensions = input_dims->size; + int axis = axis_value < 0 ? axis_value + split_dimensions : axis_value; + + TFLITE_DCHECK_LT(axis, split_dimensions); + TFLITE_DCHECK_EQ(output_dims->size, split_dimensions); + + int64_t split_size = output_dims->data[axis] * output_count; + + TFLITE_DCHECK_EQ(split_size, input_dims->data[axis]); + int64_t outer_size = 1; + for (int i = 0; i < axis; ++i) { + outer_size *= input_dims->data[i]; + } + + int64_t base_inner_size = 1; + for (int i = axis + 1; i < split_dimensions; ++i) { + base_inner_size *= input_dims->data[i]; + } + + const T* input_ptr = tflite::micro::GetTensorData(input); + for (int k = 0; k < outer_size; ++k) { + for (int i = 0; i < output_count; ++i) { + TfLiteEvalTensor* t = tflite::micro::GetEvalOutput(context, node, i); + T* output_data = tflite::micro::GetTensorData(t); + const int copy_size = output_dims->data[axis] * base_inner_size; + T* output_ptr = output_data + k * copy_size; + for (int j = 0; j < copy_size; ++j) output_ptr[j] = input_ptr[j]; + input_ptr += copy_size; + } + } + + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* axis = micro_context->AllocateTempInputTensor(node, 0); + TF_LITE_ENSURE(context, axis != nullptr); + + // Dynamic output tensors are needed if axis tensor is not constant. + // But Micro doesn't support dynamic memory allocation, so we only support + // constant axis tensor for now. + TF_LITE_ENSURE_MSG(context, IsConstantTensor(axis), + "Non constant axis tensor not supported"); + + micro_context->DeallocateTempTfLiteTensor(axis); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* axis = tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 1); + + int axis_value = tflite::micro::GetTensorData(axis)[0]; + if (axis_value < 0) { + axis_value += input->dims->size; + } + + TF_LITE_ENSURE(context, axis_value >= 0); + TF_LITE_ENSURE(context, axis_value < input->dims->size); + + switch (input->type) { + case kTfLiteFloat32: { + return SplitImpl(context, node, input, axis_value); + } + case kTfLiteInt8: { + return SplitImpl(context, node, input, axis_value); + } + case kTfLiteInt16: { + return SplitImpl(context, node, input, axis_value); + } + case kTfLiteInt32: { + return SplitImpl(context, node, input, axis_value); + } + default: + MicroPrintf("Type %s currently not supported.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace split + +TfLiteRegistration Register_SPLIT() { + return tflite::micro::RegisterOp(nullptr, split::Prepare, split::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/split_v.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/split_v.cc new file mode 100644 index 000000000..d0002d57c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/split_v.cc @@ -0,0 +1,130 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace split_v { + +template +TfLiteStatus SplitImpl(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input, int axis_value) { + const TfLiteIntArray* input_dims = input->dims; + const TfLiteEvalTensor* output0 = + tflite::micro::GetEvalOutput(context, node, 0); + + const int split_dimensions = input_dims->size; + + TFLITE_DCHECK_LT(axis_value, split_dimensions); + TFLITE_DCHECK_EQ(output0->dims->size, split_dimensions); + + int64_t split_size = 0; + const int output_count = NumOutputs(node); + for (int i = 0; i < output_count; i++) { + split_size += + tflite::micro::GetEvalOutput(context, node, i)->dims->data[axis_value]; + } + TFLITE_DCHECK_EQ(split_size, input_dims->data[axis_value]); + int64_t outer_size = 1; + for (int i = 0; i < axis_value; ++i) { + outer_size *= input_dims->data[i]; + } + + int64_t base_inner_size = 1; + for (int i = axis_value + 1; i < split_dimensions; ++i) { + base_inner_size *= input_dims->data[i]; + } + + const T* input_ptr = tflite::micro::GetTensorData(input); + for (int k = 0; k < outer_size; ++k) { + for (int i = 0; i < output_count; ++i) { + TfLiteEvalTensor* output_tensor = + tflite::micro::GetEvalOutput(context, node, i); + T* output_data = tflite::micro::GetTensorData(output_tensor); + const int copy_size = + output_tensor->dims->data[axis_value] * base_inner_size; + T* output_ptr = output_data + k * copy_size; + for (int j = 0; j < copy_size; ++j) output_ptr[j] = input_ptr[j]; + input_ptr += copy_size; + } + } + + return kTfLiteOk; +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); + + MicroContext* micro_context = GetMicroContext(context); + // Dynamic output tensors are needed if axis tensor is not constant. + // But Micro doesn't support dynamic memory allocation, so we only support + // constant axis tensor for now. + TfLiteTensor* axis = micro_context->AllocateTempInputTensor(node, 2); + TF_LITE_ENSURE_MSG(context, IsConstantTensor(axis), + "Non constant axis tensor not supported"); + micro_context->DeallocateTempTfLiteTensor(axis); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + const TfLiteEvalTensor* axis = tflite::micro::GetEvalInput(context, node, 2); + + int axis_value = tflite::micro::GetTensorData(axis)[0]; + if (axis_value < 0) { + axis_value += input->dims->size; + } + + TF_LITE_ENSURE(context, axis_value >= 0); + TF_LITE_ENSURE(context, axis_value < input->dims->size); + + switch (input->type) { + case kTfLiteFloat32: { + return SplitImpl(context, node, input, axis_value); + } + case kTfLiteInt8: { + return SplitImpl(context, node, input, axis_value); + } + case kTfLiteInt16: { + return SplitImpl(context, node, input, axis_value); + } + case kTfLiteInt32: { + return SplitImpl(context, node, input, axis_value); + } + default: + MicroPrintf("Type %s currently not supported.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace split_v + +TfLiteRegistration Register_SPLIT_V() { + return tflite::micro::RegisterOp(nullptr, split_v::Prepare, split_v::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/squared_difference.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/squared_difference.cc new file mode 100644 index 000000000..8786a8715 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/squared_difference.cc @@ -0,0 +1,247 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/binary_function.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/add.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_context.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { +constexpr int kInputTensor1 = 0; +constexpr int kInputTensor2 = 1; +constexpr int kOutputTensor = 0; + +struct OpData { + bool requires_broadcast; + ArithmeticParams arithmetic_params; +}; + +template +T SquaredDifference(T input1, T input2) { + const T difference = input1 - input2; + return difference * difference; +} + +void* SquaredDifferenceInit(TfLiteContext* context, const char* buffer, + size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus SquaredDifferencePrepare(TfLiteContext* context, + TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + OpData* data = reinterpret_cast(node->user_data); + data->requires_broadcast = false; + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_TYPES_EQ(context, input1->type, input2->type); + output->type = input2->type; + + // Ensure the quantization parameters are equivalent. + if (input1->type == kTfLiteInt8) { + const auto& input1_quantization_params = input1->params; + const auto& input2_quantization_params = input2->params; + const auto& output_quantization_params = output->params; + const int32_t integer_type_min = std::numeric_limits::min(); + const int32_t integer_type_max = std::numeric_limits::max(); + TF_LITE_ENSURE(context, + input1_quantization_params.zero_point >= integer_type_min); + TF_LITE_ENSURE(context, + input1_quantization_params.zero_point <= integer_type_max); + TF_LITE_ENSURE(context, + input2_quantization_params.zero_point >= integer_type_min); + TF_LITE_ENSURE(context, + input2_quantization_params.zero_point <= integer_type_max); + TF_LITE_ENSURE(context, + output_quantization_params.zero_point >= integer_type_min); + TF_LITE_ENSURE(context, + output_quantization_params.zero_point <= integer_type_max); + data->arithmetic_params.input1_offset = + -input1_quantization_params.zero_point; + data->arithmetic_params.input2_offset = + -input2_quantization_params.zero_point; + data->arithmetic_params.output_offset = + output_quantization_params.zero_point; + + // shift to make integer for scales. + // 7 is selected so that maximum shifted result 255^2 * (1 << (7 * 2 )) + // does not overflow signed 32-bit integer + data->arithmetic_params.left_shift = 7; + const double twice_max_input_scale = + 2.0 * static_cast(std::max(input1_quantization_params.scale, + input2_quantization_params.scale)); + const double real_input1_multiplier = + static_cast(input1_quantization_params.scale) / + twice_max_input_scale; + double real_input2_multiplier = + static_cast(input2_quantization_params.scale) / + twice_max_input_scale; + const double real_output_multiplier = + (twice_max_input_scale * twice_max_input_scale) / + static_cast((1 << data->arithmetic_params.left_shift * 2) * + output_quantization_params.scale); + QuantizeMultiplierSmallerThanOneExp( + real_input1_multiplier, &data->arithmetic_params.input1_multiplier, + &data->arithmetic_params.input1_shift); + QuantizeMultiplierSmallerThanOneExp( + real_input2_multiplier, &data->arithmetic_params.input2_multiplier, + &data->arithmetic_params.input2_shift); + QuantizeMultiplierSmallerThanOneExp( + real_output_multiplier, &data->arithmetic_params.output_multiplier, + &data->arithmetic_params.output_shift); + data->arithmetic_params.quantized_activation_min = + std::numeric_limits::min(); + data->arithmetic_params.quantized_activation_max = + std::numeric_limits::max(); + } + + data->requires_broadcast = !HaveSameShapes(input1, input2); + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +inline int8_t SquaredDifference(int8_t x, int8_t y, + const ArithmeticParams& params) { + const int32_t input1_val = params.input1_offset + x; + const int32_t input2_val = params.input2_offset + y; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_diff = scaled_input1_val - scaled_input2_val; + + // Max of this is 255^2 * (1 << 14), so won't overflow 32 bits. + const int32_t squared_raw_diff = raw_diff * raw_diff; + const int32_t raw_output = + MultiplyByQuantizedMultiplierSmallerThanOneExp( + squared_raw_diff, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = + std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + return static_cast(clamped_output); +} + +template +void EvalQuantizedSquaredDifference(TfLiteContext* context, TfLiteNode* node, + const OpData* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + const auto* op_data = static_cast(node->user_data); + if (data->requires_broadcast) { + reference_integer_ops::BroadcastBinaryFunction4DSlow( + op_data->arithmetic_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + reference_integer_ops::CheckArithmeticParams, SquaredDifference); + } else { + const int flat_size = tflite::micro::GetTensorShape(input1).FlatSize(); + reference_integer_ops::ElementWise( + flat_size, op_data->arithmetic_params, + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorData(output), + reference_integer_ops::CheckArithmeticParams, SquaredDifference); + } +} + +template +void EvalSquaredDifference(TfLiteContext* context, TfLiteNode* node, + const OpData* data, const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + if (data->requires_broadcast) { + reference_ops::BroadcastBinaryFunction4DSlow( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), SquaredDifference); + } else { + reference_ops::BinaryFunction( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), SquaredDifference); + } +} + +TfLiteStatus SquaredDifferenceEval(TfLiteContext* context, TfLiteNode* node) { + OpData* data = reinterpret_cast(node->user_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + if (output->type == kTfLiteFloat32) { + EvalSquaredDifference(context, node, data, input1, input2, output); + } else if (output->type == kTfLiteInt32) { + EvalSquaredDifference(context, node, data, input1, input2, output); + } else if (output->type == kTfLiteInt8) { + EvalQuantizedSquaredDifference(context, node, data, input1, input2, + output); + } else { + MicroPrintf( + "SquaredDifference only supports FLOAT32, INT32 and INT8 now, got %d.", + output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_SQUARED_DIFFERENCE() { + return tflite::micro::RegisterOp( + SquaredDifferenceInit, SquaredDifferencePrepare, SquaredDifferenceEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/squeeze.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/squeeze.cc new file mode 100644 index 000000000..017538498 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/squeeze.cc @@ -0,0 +1,118 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +struct SqueezeContext { + SqueezeContext(TfLiteContext* context, TfLiteNode* node) { + params = reinterpret_cast(node->builtin_data); + micro_context = GetMicroContext(context); + input = micro_context->AllocateTempInputTensor(node, 0); + output = micro_context->AllocateTempOutputTensor(node, 0); + } + ~SqueezeContext() { + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + } + MicroContext* micro_context; + TfLiteSqueezeParams* params; + TfLiteTensor* input; + TfLiteTensor* output; +}; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + SqueezeContext op_context(context, node); + const int input_num_dims = NumDimensions(op_context.input); + const int num_squeeze_dims = op_context.params->num_squeeze_dims; + + // Determines number of dimensions of output tensor after squeeze. + const TfLiteIntArray* input_dims = op_context.input->dims; + const TfLiteIntArray* output_dims = op_context.output->dims; + const int* squeeze_dims = op_context.params->squeeze_dims; + + constexpr int max_squeeze_dims = 8; + TF_LITE_ENSURE(context, input_num_dims <= max_squeeze_dims); + bool should_squeeze[max_squeeze_dims] = {}; + + if (num_squeeze_dims == 0) { + for (int idx = 0; idx < input_num_dims; ++idx) { + if (input_dims->data[idx] == 1) { + should_squeeze[idx] = true; + } + } + } else { + for (int idx = 0; idx < num_squeeze_dims; ++idx) { + int current = squeeze_dims[idx] < 0 ? squeeze_dims[idx] + input_num_dims + : squeeze_dims[idx]; + TF_LITE_ENSURE(context, current >= 0 && current < input_num_dims && + input_dims->data[current] == 1); + should_squeeze[current] = true; + } + } + + // Ensure output dimensions are big enough. + for (int in_idx = 0, out_idx = 0; in_idx < input_num_dims; ++in_idx) { + if (!should_squeeze[in_idx]) { + TFLITE_CHECK_GE(output_dims->data[out_idx++], input_dims->data[in_idx]); + } + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + + if (input->type == kTfLiteString) { + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + size_t input_byte_size; + size_t output_byte_size; + TF_LITE_ENSURE_OK(context, + TfLiteEvalTensorByteLength(input, &input_byte_size)); + TF_LITE_ENSURE_OK(context, + TfLiteEvalTensorByteLength(output, &output_byte_size)); + + TF_LITE_ENSURE_EQ(context, input_byte_size, output_byte_size); + memcpy(output->data.raw, input->data.raw, input_byte_size); + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_SQUEEZE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/strided_slice.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/strided_slice.cc new file mode 100644 index 000000000..9985cf913 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/strided_slice.cc @@ -0,0 +1,210 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/strided_slice.h" + +#include +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace strided_slice { + +constexpr int kInputTensor = 0; +constexpr int kBeginTensor = 1; +constexpr int kEndTensor = 2; +constexpr int kStridesTensor = 3; +constexpr int kOutputTensor = 0; + +struct StridedSliceContext { + StridedSliceContext(TfLiteContext* context, TfLiteNode* node) { + params = reinterpret_cast(node->builtin_data); + micro_context = GetMicroContext(context); + input = micro_context->AllocateTempInputTensor(node, kInputTensor); + begin = micro_context->AllocateTempInputTensor(node, kBeginTensor); + end = micro_context->AllocateTempInputTensor(node, kEndTensor); + strides = micro_context->AllocateTempInputTensor(node, kStridesTensor); + output = micro_context->AllocateTempOutputTensor(node, kOutputTensor); + dims = NumDimensions(input); + } + ~StridedSliceContext() { + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(begin); + micro_context->DeallocateTempTfLiteTensor(end); + micro_context->DeallocateTempTfLiteTensor(strides); + micro_context->DeallocateTempTfLiteTensor(output); + } + const TfLiteStridedSliceParams* params; + MicroContext* micro_context; + TfLiteTensor* input; + TfLiteTensor* begin; + TfLiteTensor* end; + TfLiteTensor* strides; + TfLiteTensor* output; + int dims; +}; + +// This Op only supports 1-4D cases and since we use the reference 4D +// implementation, the 1-3D tensors are mapped to 4D. +const int kMaxDim = 4; + +tflite::StridedSliceParams BuildStridedSliceParams( + StridedSliceContext* op_context) { + tflite::StridedSliceParams op_params; + op_params.start_indices_count = op_context->dims; + op_params.stop_indices_count = op_context->dims; + op_params.strides_count = op_context->dims; + + for (int i = 0; i < op_context->dims; ++i) { + op_params.start_indices[i] = GetTensorData(op_context->begin)[i]; + op_params.stop_indices[i] = GetTensorData(op_context->end)[i]; + op_params.strides[i] = GetTensorData(op_context->strides)[i]; + } + + op_params.begin_mask = op_context->params->begin_mask; + op_params.ellipsis_mask = 0; + op_params.end_mask = op_context->params->end_mask; + op_params.new_axis_mask = 0; + op_params.shrink_axis_mask = op_context->params->shrink_axis_mask; + return op_params; +} + +// Processes the indexing tensors (begin, end and strides) to resize the +// output tensor. This function is callable from both Prepare() and Eval() as +// long as the caller ensures the indexing tensors are present. +TfLiteStatus CheckOutputSize(TfLiteContext* context, + StridedSliceContext* op_context) { + using ::tflite::strided_slice::StartForAxis; + using ::tflite::strided_slice::StopForAxis; + TfLiteIntArray* output_shape = op_context->output->dims; + int shape_size = 0; + auto op_params = BuildStridedSliceParams(op_context); + auto input_shape = GetTensorShape(op_context->input); + for (int idx = 0; idx < op_context->dims; ++idx) { + int32_t stride = GetTensorData(op_context->strides)[idx]; + TF_LITE_ENSURE_MSG(context, stride != 0, "stride value has to be non-zero"); + int32_t begin = StartForAxis(op_params, input_shape, idx); + int32_t end = StopForAxis(op_params, input_shape, idx, begin); + + // When shrinking an axis, the end position does not matter (and can be + // incorrect when negative indexing is used, see Issue #19260). Always use + // begin + 1 to generate a length 1 slice, since begin has + // already been adjusted for negative indices by StartForAxis. + const bool shrink_axis = op_context->params->shrink_axis_mask & (1 << idx); + if (shrink_axis) { + end = begin + 1; + } + + // This is valid for both positive and negative strides + int32_t dim_shape = std::ceil((end - begin) / static_cast(stride)); + dim_shape = dim_shape < 0 ? 0 : dim_shape; + if (!shrink_axis) { + TF_LITE_ENSURE_EQ(context, output_shape->data[shape_size], dim_shape); + shape_size++; + } + } + TF_LITE_ENSURE_EQ(context, output_shape->size, shape_size); + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(StridedSliceParams)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + StridedSliceParams* op_params = + static_cast(node->user_data); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 4); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + StridedSliceContext op_context(context, node); + TF_LITE_ENSURE_MSG(context, op_context.dims <= kMaxDim, + "input dim should not exceed 4"); + auto params = BuildStridedSliceParams(&op_context); + memcpy(op_params, ¶ms, sizeof(StridedSliceParams)); + return CheckOutputSize(context, &op_context); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + const StridedSliceParams& op_params = + *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + switch (output->type) { + case kTfLiteFloat32: + reference_ops::StridedSlice(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::StridedSlice(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + reference_ops::StridedSlice( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt32: + reference_ops::StridedSlice( + op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteBool: + reference_ops::StridedSlice(op_params, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} +} // namespace strided_slice + +TfLiteRegistration Register_STRIDED_SLICE() { + return tflite::micro::RegisterOp(strided_slice::Init, strided_slice::Prepare, + strided_slice::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub.cc new file mode 100644 index 000000000..a54c488fd --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub.cc @@ -0,0 +1,168 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/sub.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/add.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/reference/sub.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +void* SubInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataSub)); +} + +void EvalSub(TfLiteContext* context, TfLiteNode* node, TfLiteSubParams* params, + const OpDataSub* data, const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, TfLiteEvalTensor* output) { + float output_activation_min, output_activation_max; + CalculateActivationRange(params->activation, &output_activation_min, + &output_activation_max); + tflite::ArithmeticParams op_params; + SetActivationParams(output_activation_min, output_activation_max, &op_params); + if (data->requires_broadcast) { + tflite::reference_ops::BroadcastSubSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + tflite::reference_ops::SubWithActivation( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } +} + +TfLiteStatus EvalSubQuantized(TfLiteContext* context, TfLiteNode* node, + TfLiteSubParams* params, const OpDataSub* data, + const TfLiteEvalTensor* input1, + const TfLiteEvalTensor* input2, + TfLiteEvalTensor* output) { + tflite::ArithmeticParams op_params; + op_params.left_shift = data->left_shift; + op_params.input1_offset = data->input1_offset; + op_params.input1_multiplier = data->input1_multiplier; + op_params.input1_shift = data->input1_shift; + op_params.input2_offset = data->input2_offset; + op_params.input2_multiplier = data->input2_multiplier; + op_params.input2_shift = data->input2_shift; + op_params.output_offset = data->output_offset; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = data->output_shift; + SetActivationParams(data->output_activation_min, data->output_activation_max, + &op_params); + bool need_broadcast = reference_ops::ProcessBroadcastShapes( + tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorShape(input2), &op_params); + + switch (output->type) { + case kTfLiteInt8: { + if (need_broadcast) { + tflite::reference_ops::BroadcastQuantSubSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + tflite::reference_ops::Sub( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + break; + } + case kTfLiteInt16: { + if (need_broadcast) { + tflite::reference_ops::BroadcastQuantSubSlow( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } else { + tflite::reference_ops::Sub( + op_params, tflite::micro::GetTensorShape(input1), + tflite::micro::GetTensorData(input1), + tflite::micro::GetTensorShape(input2), + tflite::micro::GetTensorData(input2), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + } + break; + } + default: + MicroPrintf("Quantized type %s not currently supported.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus SubEval(TfLiteContext* context, TfLiteNode* node) { + auto* params = reinterpret_cast(node->builtin_data); + + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, kSubInputTensor1); + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, kSubInputTensor2); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kSubOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataSub& data = *(static_cast(node->user_data)); + + if (output->type == kTfLiteFloat32) { + EvalSub(context, node, params, &data, input1, input2, output); + } else if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + TF_LITE_ENSURE_OK(context, EvalSubQuantized(context, node, params, &data, + input1, input2, output)); + } else { + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(output->type), + output->type); + return kTfLiteError; + } + + return kTfLiteOk; +} + +TfLiteRegistration Register_SUB() { + return tflite::micro::RegisterOp(SubInit, SubPrepare, SubEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub.h new file mode 100644 index 000000000..299002210 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub.h @@ -0,0 +1,60 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_SUB_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_SUB_H_ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +extern const int kSubInputTensor1; +extern const int kSubInputTensor2; +extern const int kSubOutputTensor; + +struct OpDataSub { + bool requires_broadcast; + + // These fields are used in both the general 8-bit -> 8bit quantized path, + // and the special 16-bit -> 16bit quantized path + int input1_shift; + int input2_shift; + int32_t output_activation_min; + int32_t output_activation_max; + + // These fields are used only in the general 8-bit -> 8bit quantized path + int32_t input1_multiplier; + int32_t input2_multiplier; + int32_t output_multiplier; + int output_shift; + int left_shift; + int32_t input1_offset; + int32_t input2_offset; + int32_t output_offset; +}; + +TfLiteStatus CalculateOpDataSub(TfLiteContext* context, TfLiteSubParams* params, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteTensor* output, OpDataSub* data); + +TfLiteStatus SubPrepare(TfLiteContext* context, TfLiteNode* node); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_SUB_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub_common.cc new file mode 100644 index 000000000..7ad3aa6aa --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/sub_common.cc @@ -0,0 +1,109 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/add.h" +#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h" +#include "tensorflow/lite/kernels/internal/reference/sub.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/sub.h" + +namespace tflite { + +const int kSubInputTensor1 = 0; +const int kSubInputTensor2 = 1; +const int kSubOutputTensor = 0; + +TfLiteStatus CalculateOpDataSub(TfLiteContext* context, TfLiteSubParams* params, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteTensor* output, OpDataSub* data) { + data->requires_broadcast = !HaveSameShapes(input1, input2); + + if (output->type == kTfLiteInt8 || output->type == kTfLiteInt16) { + // 8bit -> 8bit general quantized path, with general rescalings + data->input1_offset = -input1->params.zero_point; + data->input2_offset = -input2->params.zero_point; + data->output_offset = output->params.zero_point; + + // The shift is set to 15 in case of 16-bit and 20 in case of 8-bit, + // accordingly. In case of 16-bit we have 65535 << 15 which is less than 1 + // << 31, therefore the addition will still fit in a 32 bit accumulator. + data->left_shift = output->type == kTfLiteInt16 ? 15 : 20; + const float twice_max_input_scale = + 2 * std::max(input1->params.scale, input2->params.scale); + const double real_input1_multiplier = + static_cast(input1->params.scale) / + static_cast(twice_max_input_scale); + const double real_input2_multiplier = + static_cast(input2->params.scale) / + static_cast(twice_max_input_scale); + const double real_output_multiplier = + static_cast(twice_max_input_scale) / + ((1 << data->left_shift) * static_cast(output->params.scale)); + + QuantizeMultiplierSmallerThanOneExp( + real_input1_multiplier, &data->input1_multiplier, &data->input1_shift); + + QuantizeMultiplierSmallerThanOneExp( + real_input2_multiplier, &data->input2_multiplier, &data->input2_shift); + + QuantizeMultiplierSmallerThanOneExp( + real_output_multiplier, &data->output_multiplier, &data->output_shift); + + TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized( + context, params->activation, output, &data->output_activation_min, + &data->output_activation_max)); + } + + return kTfLiteOk; +} + +TfLiteStatus SubPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + OpDataSub* data = static_cast(node->user_data); + auto* params = reinterpret_cast(node->builtin_data); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input1 = + micro_context->AllocateTempInputTensor(node, kSubInputTensor1); + TF_LITE_ENSURE(context, input1 != nullptr); + TfLiteTensor* input2 = + micro_context->AllocateTempInputTensor(node, kSubInputTensor2); + TF_LITE_ENSURE(context, input2 != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kSubOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_STATUS( + CalculateOpDataSub(context, params, input1, input2, output, data)); + + micro_context->DeallocateTempTfLiteTensor(input1); + micro_context->DeallocateTempTfLiteTensor(input2); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf.cc new file mode 100644 index 000000000..f6aa4e8b9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf.cc @@ -0,0 +1,106 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/kernels/svdf.h" + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/activation_utils.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace { + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpDataSvdf)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = reinterpret_cast(node->builtin_data); + TFLITE_DCHECK(node->user_data != nullptr); + const OpDataSvdf& data = *(static_cast(node->user_data)); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kSvdfInputTensor); + const TfLiteEvalTensor* weights_feature = + tflite::micro::GetEvalInput(context, node, kSvdfWeightsFeatureTensor); + const TfLiteEvalTensor* weights_time = + tflite::micro::GetEvalInput(context, node, kSvdfWeightsTimeTensor); + const TfLiteEvalTensor* bias = + (NumInputs(node) == 5) + ? tflite::micro::GetEvalInput(context, node, kSvdfBiasTensor) + : nullptr; + TfLiteEvalTensor* activation_state = tflite::micro::GetMutableEvalInput( + context, node, kSvdfInputActivationStateTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kSvdfOutputTensor); + + switch (weights_feature->type) { + case kTfLiteFloat32: { + EvalFloatSvdfReference( + context, node, input, weights_feature, weights_time, bias, params, + data.scratch_tensor_index, activation_state, output); + return kTfLiteOk; + break; + } + + case kTfLiteInt8: { + switch (weights_time->type) { + case kTfLiteInt16: { + EvalInt16SvdfReference(context, node, input, weights_feature, + weights_time, bias, params, activation_state, + output, data); + return kTfLiteOk; + break; + } + case kTfLiteInt8: { + EvalInt8SvdfReference(context, node, input, weights_feature, + weights_time, bias, params, activation_state, + output, data); + return kTfLiteOk; + break; + } + default: + MicroPrintf("Type %s not currently supported.", + TfLiteTypeGetName(weights_time->type)); + return kTfLiteError; + } + } + + default: + MicroPrintf("Type %s not currently supported.", + TfLiteTypeGetName(weights_feature->type)); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_SVDF() { + return tflite::micro::RegisterOp(Init, PrepareSvdf, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf.h new file mode 100644 index 000000000..0915c9fdc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf.h @@ -0,0 +1,99 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_SVDF_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_SVDF_H_ + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +struct OpDataSvdf { + int32_t effective_scale_1_a; + int32_t effective_scale_2_a; + // b versions of each scale are kept at int since the numbers are just the + // shift value - typically between [-32, 32]. + int effective_scale_1_b; + int effective_scale_2_b; + int scratch_tensor_index; + int scratch_output_tensor_index; + + // Cached tensor zero point values for quantized operations. + int input_zero_point; + int output_zero_point; + int activation_state_zero_point; +}; + +// Input tensors. +extern const int kSvdfInputTensor; +extern const int kSvdfWeightsFeatureTensor; +extern const int kSvdfWeightsTimeTensor; +extern const int kSvdfBiasTensor; +// This is a variable tensor, and will be modified by this op. +extern const int kSvdfInputActivationStateTensor; + +// Output tensor. +extern const int kSvdfOutputTensor; + +void EvalInt8SvdfReference(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input_tensor, + const TfLiteEvalTensor* weights_feature_tensor, + const TfLiteEvalTensor* weights_time_tensor, + const TfLiteEvalTensor* bias_tensor, + const TfLiteSVDFParams* params, + TfLiteEvalTensor* activation_state_tensor, + TfLiteEvalTensor* output_tensor, + const OpDataSvdf& data); + +// TODO(#523): remove 16-bit code when no longer needed. +void EvalInt16SvdfReference(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input_tensor, + const TfLiteEvalTensor* weights_feature_tensor, + const TfLiteEvalTensor* weights_time_tensor, + const TfLiteEvalTensor* bias_tensor, + const TfLiteSVDFParams* params, + TfLiteEvalTensor* activation_state_tensor, + TfLiteEvalTensor* output_tensor, + const OpDataSvdf& data); + +void EvalFloatSvdfReference( + TfLiteContext* context, TfLiteNode* node, const TfLiteEvalTensor* input, + const TfLiteEvalTensor* weights_feature, + const TfLiteEvalTensor* weights_time, const TfLiteEvalTensor* bias, + const TfLiteSVDFParams* params, int scratch_tensor_index, + TfLiteEvalTensor* activation_state, TfLiteEvalTensor* output); + +TfLiteStatus PrepareSvdf(TfLiteContext* context, TfLiteNode* node); + +// This is the most generic TfLiteRegistration. The actual supported types may +// still be target dependent. The only requirement is that every implementation +// (reference or optimized) must define this function. +TfLiteRegistration Register_SVDF(); + +#if defined(HEXAGON) || defined(CMSIS_NN) +TfLiteRegistration Register_SVDF_INT8(); + +#else +// Note that while this block gets used for both reference and optimized kernels +// that do not have any specialized implementations, the only goal here is to +// define fallback implementation that allow reference kernels to still be used +// from applications that call a more specific kernel variant. + +inline TfLiteRegistration Register_SVDF_INT8() { return Register_SVDF(); } + +#endif +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_SVDF_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf_common.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf_common.cc new file mode 100644 index 000000000..ed74358bc --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/svdf_common.cc @@ -0,0 +1,516 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/activation_utils.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/svdf.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +/** + * This version of SVDF is specific to TFLite Micro. It contains the following + * differences between the TFLite version: + * + * 1.) Scratch tensor allocation - scratch tensors must be known ahead of time + * for the Micro interpreter. + * 2.) Output dimensions - the TFLite version determines output size and runtime + * and resizes the output tensor. Micro runtime does not support tensor + * resizing. + */ + +const int kSvdfInputTensor = 0; +const int kSvdfWeightsFeatureTensor = 1; +const int kSvdfWeightsTimeTensor = 2; +const int kSvdfBiasTensor = 3; +const int kSvdfInputActivationStateTensor = + 4; // This is a variable tensor, and will be modified by this op. +const int kSvdfOutputTensor = 0; + +template +void EvalIntegerSvdfReference(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input_tensor, + const TfLiteEvalTensor* weights_feature_tensor, + const TfLiteEvalTensor* weights_time_tensor, + const TfLiteEvalTensor* bias_tensor, + const TfLiteSVDFParams* params, + TfLiteEvalTensor* activation_state_tensor, + TfLiteEvalTensor* output_tensor, + const OpDataSvdf& data) { + const int n_rank = params->rank; + const int n_batch = input_tensor->dims->data[0]; + const int n_input = input_tensor->dims->data[1]; + const int n_filter = weights_feature_tensor->dims->data[0]; + const int n_unit = n_filter / n_rank; + const int n_memory = weights_time_tensor->dims->data[1]; + + TFLITE_DCHECK(context != nullptr); + TFLITE_DCHECK(context->GetScratchBuffer != nullptr); + + int32_t* scratch_tensor = static_cast( + context->GetScratchBuffer(context, data.scratch_tensor_index)); + int32_t* scratch_output_tensor = static_cast( + context->GetScratchBuffer(context, data.scratch_output_tensor_index)); + + // Shift states. + T* const state_ptr = tflite::micro::GetTensorData(activation_state_tensor); + + // Left shift the activation_state. + { + T* new_state_start = state_ptr; + const T* old_state_start = state_ptr + 1; + const T* old_state_end = state_ptr + n_batch * n_filter * n_memory; + while (old_state_start != old_state_end) { + *new_state_start++ = *old_state_start++; + } + } + + // Note: no need to clear the latest activation, matmul is not accumulative. + + // Feature matmul. + { + T* state = tflite::micro::GetTensorData(activation_state_tensor); + const int8_t* input = tflite::micro::GetTensorData(input_tensor); + const int8_t* weight_feature = + tflite::micro::GetTensorData(weights_feature_tensor); + const int32_t output_max = std::numeric_limits::max(); + const int32_t output_min = std::numeric_limits::min(); + T* result_in_batch = state + (n_memory - 1); + for (int b = 0; b < n_batch; b++) { + const int8_t* matrix_ptr = weight_feature; + for (int r = 0; r < n_filter; r++) { + int32_t dot_prod = 0; + const int8_t* vector_in_batch = input + b * n_input; + for (int c = 0; c < n_input; c++) { + dot_prod += + *matrix_ptr++ * (*vector_in_batch++ - data.input_zero_point); + } + dot_prod = MultiplyByQuantizedMultiplier( + dot_prod, data.effective_scale_1_a, data.effective_scale_1_b); + dot_prod = std::min(std::max(output_min, dot_prod), output_max); + // The int16 version of the op assumes a zero_point of 0. This + // code accounts for the potentially non-zero zero_point for the int8 + // version of the op. + *result_in_batch = data.activation_state_zero_point + dot_prod; + result_in_batch += n_memory; + } + } + } + + // Time. + { + for (int b = 0; b < n_batch; ++b) { + int32_t* scratch_ptr_batch = scratch_tensor + b * n_filter; + + // Perform batched vector dot product: + const T* vector1_ptr = + tflite::micro::GetTensorData(weights_time_tensor); + const T* vector2_ptr = + tflite::micro::GetTensorData(activation_state_tensor) + + b * n_memory * n_filter; + + for (int i = 0; i < n_filter; i++) { + *scratch_ptr_batch = 0; + for (int j = 0; j < n_memory; j++) { + *scratch_ptr_batch += + *vector1_ptr++ * + (*vector2_ptr++ - data.activation_state_zero_point); + } + scratch_ptr_batch++; + } + } + } + + // Reduce, add bias, rescale, activation. + { + // Add bias. + if (bias_tensor) { + // Vector batch assign: + const int32_t* bias_data = + tflite::micro::GetTensorData(bias_tensor); + for (int i = 0; i < n_batch; ++i) { + int32_t* output_ptr = scratch_output_tensor + i * n_unit; + const int32_t* bias_ptr = bias_data; + for (int j = 0; j < n_unit; ++j) { + *output_ptr++ = *bias_ptr++; + } + } + } else { + int32_t* output_ptr = scratch_output_tensor; + for (int i = 0; i < n_batch * n_unit; ++i) { + *output_ptr++ = 0; + } + } + + // Reduce. + for (int b = 0; b < n_batch; ++b) { + int32_t* output_temp_ptr = scratch_output_tensor + b * n_unit; + int32_t* scratch_ptr_batch = scratch_tensor + b * n_filter; + + // Reduction sum vector + for (int i = 0; i < n_unit; ++i) { + for (int j = 0; j < n_rank; ++j) { + output_temp_ptr[i] += *scratch_ptr_batch++; + } + } + } + + // Rescale. + const int32_t output_max = std::numeric_limits::max(); + const int32_t output_min = std::numeric_limits::min(); + for (int i = 0; i < n_batch * n_unit; ++i) { + int32_t x1 = scratch_output_tensor[i]; + int32_t x2 = MultiplyByQuantizedMultiplier(x1, data.effective_scale_2_a, + data.effective_scale_2_b); + int32_t x3 = x2 + data.output_zero_point; + int32_t x4 = std::min(std::max(output_min, x3), output_max); + tflite::micro::GetTensorData(output_tensor)[i] = + static_cast(x4); + } + } +} + +/** + * Generate two versions of the integer code. One with int16_t type for the + * time weights and the activation state, and another one with int8_t for the + * same. + */ + +void EvalInt16SvdfReference(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input_tensor, + const TfLiteEvalTensor* weights_feature_tensor, + const TfLiteEvalTensor* weights_time_tensor, + const TfLiteEvalTensor* bias_tensor, + const TfLiteSVDFParams* params, + TfLiteEvalTensor* activation_state_tensor, + TfLiteEvalTensor* output_tensor, + const OpDataSvdf& data) { + EvalIntegerSvdfReference( + context, node, input_tensor, weights_feature_tensor, weights_time_tensor, + bias_tensor, params, activation_state_tensor, output_tensor, data); +} + +void EvalInt8SvdfReference(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input_tensor, + const TfLiteEvalTensor* weights_feature_tensor, + const TfLiteEvalTensor* weights_time_tensor, + const TfLiteEvalTensor* bias_tensor, + const TfLiteSVDFParams* params, + TfLiteEvalTensor* activation_state_tensor, + TfLiteEvalTensor* output_tensor, + const OpDataSvdf& data) { + EvalIntegerSvdfReference( + context, node, input_tensor, weights_feature_tensor, weights_time_tensor, + bias_tensor, params, activation_state_tensor, output_tensor, data); +} + +static inline void ApplyTimeWeightsBiasAndActivation( + int batch_size, int memory_size, int num_filters, int num_units, int rank, + const float* const weights_time_ptr, const float* const bias_ptr, + TfLiteFusedActivation activation, float* const state_ptr, + float* const scratch_ptr, float* const output_ptr) { + // Compute matmul(activation_state, weights_time). + for (int b = 0; b < batch_size; ++b) { + // Perform batched vector dot product: + float* scratch_ptr_batch = scratch_ptr + b * num_filters; + const float* vector1_ptr = weights_time_ptr; + const float* vector2_ptr = state_ptr + b * memory_size * num_filters; + for (int i = 0; i < num_filters; ++i) { + *scratch_ptr_batch = 0.f; + for (int j = 0; j < memory_size; ++j) { + *scratch_ptr_batch += *vector1_ptr++ * *vector2_ptr++; + } + scratch_ptr_batch++; + } + } + + // Initialize output with bias if provided. + if (bias_ptr) { + // VectorBatchVectorAssign + for (int i = 0; i < batch_size; ++i) { + float* output_data = output_ptr + i * num_units; + const float* bias_data = bias_ptr; + for (int j = 0; j < num_units; ++j) { + *output_data++ = *bias_data++; + } + } + } else { + float* output_data = output_ptr; + for (int i = 0; i < batch_size * num_units; ++i) { + *output_data++ = 0.0f; + } + } + + // Reduction sum. + for (int b = 0; b < batch_size; ++b) { + float* output_ptr_batch = output_ptr + b * num_units; + float* scratch_ptr_batch = scratch_ptr + b * num_filters; + + // Reduction sum vector + for (int i = 0; i < num_units; ++i) { + for (int j = 0; j < rank; j++) { + output_ptr_batch[i] += *scratch_ptr_batch++; + } + } + } + + // Apply activation. + for (int b = 0; b < batch_size; ++b) { + float* output_ptr_batch = output_ptr + b * num_units; + for (int i = 0; i < num_units; ++i) { + *output_ptr_batch = + tflite::ops::micro::ActivationValFloat(activation, *output_ptr_batch); + ++output_ptr_batch; + } + } +} + +void EvalFloatSvdfReference( + TfLiteContext* context, TfLiteNode* node, const TfLiteEvalTensor* input, + const TfLiteEvalTensor* weights_feature, + const TfLiteEvalTensor* weights_time, const TfLiteEvalTensor* bias, + const TfLiteSVDFParams* params, int scratch_tensor_index, + TfLiteEvalTensor* activation_state, TfLiteEvalTensor* output) { + const int rank = params->rank; + const int batch_size = input->dims->data[0]; + const int input_size = input->dims->data[1]; + const int num_filters = weights_feature->dims->data[0]; + const int num_units = num_filters / rank; + const int memory_size = weights_time->dims->data[1]; + + const float* weights_feature_ptr = + tflite::micro::GetTensorData(weights_feature); + const float* weights_time_ptr = + tflite::micro::GetTensorData(weights_time); + const float* bias_ptr = tflite::micro::GetTensorData(bias); + const float* input_ptr = tflite::micro::GetTensorData(input); + + float* state_ptr = tflite::micro::GetTensorData(activation_state); + + TFLITE_DCHECK(context != nullptr); + TFLITE_DCHECK(context->GetScratchBuffer != nullptr); + + float* scratch_ptr = static_cast( + context->GetScratchBuffer(context, scratch_tensor_index)); + + float* output_ptr = tflite::micro::GetTensorData(output); + + // Left shift the activation_state. + { + float* new_state_start = state_ptr; + const float* old_state_start = state_ptr + 1; + const float* old_state_end = + state_ptr + batch_size * num_filters * memory_size; + while (old_state_start != old_state_end) { + *new_state_start++ = *old_state_start++; + } + } + + // Note: no need to clear the latest activation, matmul is not accumulative. + + // Compute conv1d(inputs, weights_feature). + // The activation_state's rightmost column is used to save current cycle + // activation. This is achieved by starting at state_ptr[memory_size - 1] and + // having the stride equal to memory_size. + + // Perform batched matrix vector multiply operation: + { + const float* matrix = weights_feature_ptr; + const float* vector = input_ptr; + float* result = &state_ptr[memory_size - 1]; + float* result_in_batch = result; + for (int i = 0; i < batch_size; ++i) { + const float* matrix_ptr = matrix; + for (int j = 0; j < num_filters; ++j) { + float dot_prod = 0.0f; + const float* vector_in_batch = vector + i * input_size; + for (int k = 0; k < input_size; ++k) { + dot_prod += *matrix_ptr++ * *vector_in_batch++; + } + *result_in_batch = dot_prod; + result_in_batch += memory_size; + } + } + } + + ApplyTimeWeightsBiasAndActivation( + batch_size, memory_size, num_filters, num_units, rank, weights_time_ptr, + bias_ptr, params->activation, state_ptr, scratch_ptr, output_ptr); +} + +TfLiteStatus PrepareSvdf(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->builtin_data != nullptr); + + const auto* params = static_cast(node->builtin_data); + + MicroContext* micro_context = GetMicroContext(context); + + // Validate Tensor Inputs (dtype depends on quantization): + // [0] = Input, {2, batch_size, input_size} + // [1] = Weights Feature, {2, num_filters, input_size} + // [2] = Weights Time, {2, num_filters, memory_size} + // [3] = Bias (optional), {1, num_units} + // [4] = Activation State (variable), + // {2, batch_size, memory_size * num_filters} + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kSvdfInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* weights_feature = + micro_context->AllocateTempInputTensor(node, kSvdfWeightsFeatureTensor); + TF_LITE_ENSURE(context, weights_feature != nullptr); + TfLiteTensor* weights_time = + micro_context->AllocateTempInputTensor(node, kSvdfWeightsTimeTensor); + TF_LITE_ENSURE(context, weights_time != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kSvdfBiasTensor); + TfLiteTensor* activation_state = micro_context->AllocateTempInputTensor( + node, kSvdfInputActivationStateTensor); + TF_LITE_ENSURE(context, activation_state != nullptr); + + // Define input constants based on input tensor definition above: + const int rank = params->rank; + const int input_size = input->dims->data[1]; + const int batch_size = input->dims->data[0]; + const int num_filters = weights_feature->dims->data[0]; + TF_LITE_ENSURE_EQ(context, num_filters % rank, 0); + const int num_units = num_filters / rank; + const int memory_size = weights_time->dims->data[1]; + + // Validate Input Tensor: + TF_LITE_ENSURE(context, + input->type == kTfLiteFloat32 || input->type == kTfLiteInt8); + TF_LITE_ENSURE_EQ(context, NumDimensions(input), 2); + + // Validate Tensor Output: + // [0] = float/int8_t, {2, batch_size, num_units} + TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kSvdfOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_EQ(context, NumDimensions(output), 2); + TF_LITE_ENSURE_EQ(context, output->dims->data[0], batch_size); + TF_LITE_ENSURE_EQ(context, output->dims->data[1], num_units); + + // Validate Weights Feature Input Tensor: + TF_LITE_ENSURE_EQ(context, NumDimensions(weights_feature), 2); + TF_LITE_ENSURE_EQ(context, weights_feature->dims->data[1], input_size); + + // Validate Weights Time Input Tensor: + TF_LITE_ENSURE_EQ(context, NumDimensions(weights_time), 2); + TF_LITE_ENSURE_EQ(context, weights_time->dims->data[0], num_filters); + TF_LITE_ENSURE_EQ(context, weights_time->dims->data[1], memory_size); + + // Validate Optional Bias Input Tensor: + if (bias != nullptr) { + TF_LITE_ENSURE_EQ(context, bias->dims->data[0], num_units); + } + + // Validate Activation State Input Tensor: + TF_LITE_ENSURE_EQ(context, NumDimensions(activation_state), 2); + TF_LITE_ENSURE_EQ(context, activation_state->dims->data[0], batch_size); + TF_LITE_ENSURE_EQ(context, activation_state->dims->data[1], + memory_size * num_filters); + // Since is_variable is not part of TFLiteEvalTensor, check is_variable here. + TF_LITE_ENSURE_EQ(context, activation_state->is_variable, true); + + TF_LITE_ENSURE_EQ(context, node->inputs->size, 5); + + TFLITE_DCHECK(node->user_data != nullptr); + OpDataSvdf* data = static_cast(node->user_data); + + if (input->type == kTfLiteInt8) { + TF_LITE_ENSURE_EQ(context, weights_feature->type, kTfLiteInt8); + TF_LITE_ENSURE(context, (weights_time->type == kTfLiteInt16) || + (weights_time->type == kTfLiteInt8)); + TF_LITE_ENSURE(context, (activation_state->type == kTfLiteInt16) || + (activation_state->type == kTfLiteInt8)); + if (bias != nullptr) { + TF_LITE_ENSURE_EQ(context, bias->type, kTfLiteInt32); + } + + TF_LITE_ENSURE_TYPES_EQ(context, output->type, kTfLiteInt8); + + const double effective_scale_1 = + static_cast(input->params.scale) * + static_cast(weights_feature->params.scale) / + static_cast(activation_state->params.scale); + const double effective_scale_2 = + static_cast(activation_state->params.scale) * + static_cast(weights_time->params.scale) / + static_cast(output->params.scale); + + // TODO(b/162018098): Use TF_LITE_ENSURE_NEAR when it is ready. + TF_LITE_ENSURE( + context, + std::abs(static_cast(bias->params.scale) - + (static_cast(activation_state->params.scale) * + static_cast(weights_time->params.scale))) < 1e-5); + + QuantizeMultiplier(effective_scale_1, &(data->effective_scale_1_a), + &(data->effective_scale_1_b)); + QuantizeMultiplier(effective_scale_2, &(data->effective_scale_2_a), + &(data->effective_scale_2_b)); + + data->input_zero_point = input->params.zero_point; + data->output_zero_point = output->params.zero_point; + data->activation_state_zero_point = activation_state->params.zero_point; + + TFLITE_DCHECK(context->RequestScratchBufferInArena != nullptr); + + const TfLiteStatus scratch_status = context->RequestScratchBufferInArena( + context, batch_size * num_filters * sizeof(int32_t), + &(data->scratch_tensor_index)); + TF_LITE_ENSURE_OK(context, scratch_status); + + const TfLiteStatus scratch_output_status = + context->RequestScratchBufferInArena( + context, batch_size * num_units * sizeof(int32_t), + &(data->scratch_output_tensor_index)); + TF_LITE_ENSURE_OK(context, scratch_output_status); + } else { + TF_LITE_ENSURE_EQ(context, weights_feature->type, kTfLiteFloat32); + TF_LITE_ENSURE_EQ(context, weights_time->type, kTfLiteFloat32); + TF_LITE_ENSURE_EQ(context, activation_state->type, kTfLiteFloat32); + if (bias != nullptr) { + TF_LITE_ENSURE_EQ(context, bias->type, kTfLiteFloat32); + } + TF_LITE_ENSURE_TYPES_EQ(context, output->type, kTfLiteFloat32); + + TFLITE_DCHECK(context->RequestScratchBufferInArena != nullptr); + const TfLiteStatus scratch_status = context->RequestScratchBufferInArena( + context, batch_size * num_filters * sizeof(float), + &(data->scratch_tensor_index)); + TF_LITE_ENSURE_OK(context, scratch_status); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(weights_feature); + micro_context->DeallocateTempTfLiteTensor(weights_time); + micro_context->DeallocateTempTfLiteTensor(activation_state); + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(bias); + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/tanh.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/tanh.cc new file mode 100644 index 000000000..e10399307 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/tanh.cc @@ -0,0 +1,204 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/integer_ops/tanh.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/tanh.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace activations { +namespace { +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +struct OpData { + int32_t input_zero_point; + int32_t input_range_radius; + int32_t input_multiplier; + int input_left_shift; +}; + +void* TanhInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus CalculateArithmeticOpData(TfLiteContext* context, TfLiteNode* node, + OpData* data) { + MicroContext* micro_context = GetMicroContext(context); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + + TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type); + + if (input->type == kTfLiteInt8) { + static constexpr int kInputIntegerBits = 4; + const double input_real_multiplier = + static_cast(input->params.scale) * + static_cast(1 << (31 - kInputIntegerBits)); + + const double q = std::frexp(input_real_multiplier, &data->input_left_shift); + data->input_multiplier = static_cast(TfLiteRound(q * (1ll << 31))); + + data->input_range_radius = + CalculateInputRadius(kInputIntegerBits, data->input_left_shift, 31); + } + + if (input->type == kTfLiteInt16) { + static constexpr int kInputIntegerBits = 3; + static constexpr int kOutputFractionalBits = 15; + + // These operators are implemented in fixed-point arithmetic, + // which intrinsically wants symmetric ranges (zero_point==0) + // and power-of-two scales (power-of-two is abbreviated below as POT). + // While more general support would be possible by means of rescaling, + // that would add some overhead and some loss of accuracy and wouldn't + // be used at the moment as current quantized LSTM applications are + // happy with symmetric, power-of-two-scales quantization. So we just + // implement that narrow case only for now. + + TF_LITE_ENSURE_EQ(context, input->params.zero_point, 0); + TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0); + + int input_scale_log2_rounded; + bool param_scale_pot = + CheckedLog2(input->params.scale, &input_scale_log2_rounded); + + data->input_left_shift = + (15 - kInputIntegerBits) + input_scale_log2_rounded; + param_scale_pot &= + (data->input_left_shift == 0 || data->input_left_shift == 1); + + if (param_scale_pot) { + data->input_multiplier = 0; + } else { + // Calculate multiplier to change input scale to 1/(3*4096) + // as required by the table lookup. + // The number 3.0 in the multiplier comes from here, + // because the interval is [-10.7, 10.7] instead of [-8, 8]. + // So, in this scaling +/-2^17 represents +/-10.7. + + double multiplier = + static_cast(input->params.scale) * 4096.0 * 3.0; + data->input_left_shift = 0; + + while (multiplier <= 32767.0 / 2.0 && data->input_left_shift <= 30) { + data->input_left_shift++; + multiplier = multiplier * 2.0; + } + + data->input_multiplier = static_cast(multiplier); + } + + int output_scale_log2_rounded; + TF_LITE_ENSURE( + context, CheckedLog2(output->params.scale, &output_scale_log2_rounded)); + TF_LITE_ENSURE_EQ(context, output_scale_log2_rounded, + -kOutputFractionalBits); + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +TfLiteStatus TanhPrepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + + OpData* data = static_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + data->input_zero_point = input->params.zero_point; + TF_LITE_ENSURE_OK(context, CalculateArithmeticOpData(context, node, data)); + + micro_context->DeallocateTempTfLiteTensor(input); + return kTfLiteOk; +} + +} // namespace + +TfLiteStatus TanhEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpData& data = *(static_cast(node->user_data)); + + switch (input->type) { + case kTfLiteFloat32: { + reference_ops::Tanh(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + case kTfLiteInt16: { + reference_integer_ops::Tanh( + data.input_multiplier, data.input_left_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + case kTfLiteInt8: { + reference_integer_ops::Tanh( + data.input_zero_point, data.input_range_radius, data.input_multiplier, + data.input_left_shift, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + return kTfLiteOk; + } break; + default: + MicroPrintf("Input %s, output %s not supported.", + TfLiteTypeGetName(input->type), + TfLiteTypeGetName(output->type), context); + return kTfLiteError; + } +} + +} // namespace activations + +TfLiteRegistration Register_TANH() { + return tflite::micro::RegisterOp( + activations::TanhInit, activations::TanhPrepare, activations::TanhEval); +} +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/transpose.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/transpose.cc new file mode 100644 index 000000000..daa75f173 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/transpose.cc @@ -0,0 +1,122 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/transpose.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/internal/types.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kPermTensor = 1; +constexpr int kOutputTensor = 0; + +struct TransposeContext { + TransposeContext(TfLiteContext* context, TfLiteNode* node) { + micro_context = GetMicroContext(context); + input = micro_context->AllocateTempInputTensor(node, kInputTensor); + perm = micro_context->AllocateTempInputTensor(node, kPermTensor); + output = micro_context->AllocateTempOutputTensor(node, kOutputTensor); + } + ~TransposeContext() { + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(perm); + micro_context->DeallocateTempTfLiteTensor(output); + } + MicroContext* micro_context; + TfLiteTensor* input; + TfLiteTensor* perm; + TfLiteTensor* output; +}; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + TransposeContext op_context(context, node); + + // Ensure validity of input tensor. + TF_LITE_ENSURE_MSG(context, NumDimensions(op_context.input) <= 5, + "Transpose op only supports 1D-5D input arrays."); + TF_LITE_ENSURE_TYPES_EQ(context, op_context.input->type, + op_context.output->type); + + int dims = NumDimensions(op_context.input); + const int32_t* perm_data = GetTensorData(op_context.perm); + + // Ensure validity of the permutations tensor as a 1D tensor. + TF_LITE_ENSURE_EQ(context, NumDimensions(op_context.perm), 1); + TF_LITE_ENSURE_EQ(context, op_context.perm->dims->data[0], dims); + for (int idx = 0; idx < dims; ++idx) { + TF_LITE_ENSURE_MSG(context, (perm_data[idx] >= 0 && perm_data[idx] < dims), + "Transpose op permutations array is out of bounds."); + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* perm_tensor = + tflite::micro::GetEvalInput(context, node, kPermTensor); + const int32_t* perm_data = perm_tensor->data.i32; + const int size = perm_tensor->dims->data[0]; + TransposeParams params; + params.perm_count = size; + for (int i = 0; i < size; ++i) { + params.perm[i] = perm_data[i]; + } + + // Transpose kernel only does rearranging values not numeric evaluations + // on each cell. It's safe to implement per size of scalar type and this + // trick keeps the total code size in a reasonable range. + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + switch (input->type) { + case kTfLiteFloat32: + reference_ops::Transpose(params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + reference_ops::Transpose(params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf( + "Type %s is currently not supported by Transpose. " + "Only float32 and int8 is supported", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_TRANSPOSE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/transpose_conv.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/transpose_conv.cc new file mode 100644 index 000000000..4b1df78ba --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/transpose_conv.cc @@ -0,0 +1,344 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/kernels/internal/reference/transpose_conv.h" + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/reference/integer_ops/transpose_conv.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +// For the TfLite transpose_conv implementation, input tensor 0 corresponds to +// the OutputShapeTensor. However, since TFLM does not support dynamic tensors, +// the TFLM implementation ignores input tensor 0 and the only inputs we care +// about are kFilterTensor, kInputTensor and kBiasTensor. +constexpr int kFilterTensor = 1; +constexpr int kInputTensor = 2; +constexpr int kBiasTensor = 3; +constexpr int kOutputTensor = 0; + +// Conv is quantized along dimension 0: +// https://www.tensorflow.org/lite/performance/quantization_spec +constexpr int kConvQuantizedDimension = 0; + +struct OpData { + ConvParams params; + + // A scratch buffer is required for quantized implementations. + int scratch_buffer_index; + + // TODO(b/192090531): Remove this once all 8x16 transpose conv models use + // 64-bit biases. + int bias_converted_buffer_index; + + // Multiplier and shift arrays are required for the int8 implementation. + int32_t* per_channel_output_multiplier; + int32_t* per_channel_output_shift; +}; + +inline PaddingType RuntimePaddingType(TfLitePadding padding) { + switch (padding) { + case TfLitePadding::kTfLitePaddingSame: + return PaddingType::kSame; + case TfLitePadding::kTfLitePaddingValid: + return PaddingType::kValid; + case TfLitePadding::kTfLitePaddingUnknown: + default: + return PaddingType::kNone; + } +} + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node, + const TfLiteTransposeConvParams* params, int width, + int height, int filter_width, int filter_height, + const TfLiteType data_type, OpData* data) { + bool has_bias = node->inputs->size == 4; + // Check number of inputs/outputs + TF_LITE_ENSURE(context, has_bias || node->inputs->size == 3); + TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); + + // Matching GetWindowedOutputSize in TensorFlow. + auto padding = params->padding; + int unused_output_width; + int unused_output_height; + TfLitePaddingValues padding_values = ComputePaddingHeightWidth( + params->stride_height, params->stride_width, 1, + 1, // Dilation height and width are always 1 for transpose_conv. + height, width, filter_height, filter_width, padding, + &unused_output_height, &unused_output_width); + + data->params.padding_type = RuntimePaddingType(padding); + data->params.padding_values.width = padding_values.width; + data->params.padding_values.height = padding_values.height; + + // Note that quantized inference requires that all tensors have their + // parameters set. This is usually done during quantized training. + if (data_type != kTfLiteFloat32) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kFilterTensor); + TF_LITE_ENSURE(context, filter != nullptr); + TfLiteTensor* bias = + micro_context->AllocateTempInputTensor(node, kBiasTensor); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + int output_channels = filter->dims->data[kConvQuantizedDimension]; + + TF_LITE_ENSURE_STATUS(tflite::PopulateConvolutionQuantizationParams( + context, input, filter, bias, output, kTfLiteActNone, + &data->params.output_multiplier, &data->params.output_shift, + &data->params.quantized_activation_min, + &data->params.quantized_activation_max, + data->per_channel_output_multiplier, data->per_channel_output_shift, + output_channels)); + + // TODO(b/192090531): Remove this once all 8x16 transpose conv models use + // 64-bit biases. + if (input->type == kTfLiteInt16) { + TFLITE_DCHECK(filter->type == kTfLiteInt8); + TFLITE_DCHECK(output->type == kTfLiteInt16); + if (bias->type == kTfLiteInt16) { + TFLITE_DCHECK( + context->RequestScratchBufferInArena( + context, GetTensorShape(bias).FlatSize() * sizeof(std::int64_t), + &(data->bias_converted_buffer_index)) == kTfLiteOk); + } + } + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + micro_context->DeallocateTempTfLiteTensor(output); + if (bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(bias); + } + } + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + TFLITE_DCHECK(node->user_data != nullptr); + TFLITE_DCHECK(node->builtin_data != nullptr); + + OpData* data = static_cast(node->user_data); + const auto params = + static_cast(node->builtin_data); + + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* filter = + micro_context->AllocateTempInputTensor(node, kFilterTensor); + TF_LITE_ENSURE(context, filter != nullptr); + + // Get height and width of the output. + const int width = SizeOfDimension(output, 2); + const int height = SizeOfDimension(output, 1); + const int filter_width = SizeOfDimension(filter, 2); + const int filter_height = SizeOfDimension(filter, 1); + + // Dynamically allocate per-channel quantization parameters. + const int num_channels = filter->dims->data[kConvQuantizedDimension]; + data->per_channel_output_multiplier = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + data->per_channel_output_shift = + static_cast(context->AllocatePersistentBuffer( + context, num_channels * sizeof(int32_t))); + + // Quantized kernels use an int32 scratch buffer. + if (input->type == kTfLiteInt8) { + TFLITE_DCHECK(context->RequestScratchBufferInArena != nullptr); + TFLITE_DCHECK(context->RequestScratchBufferInArena( + context, + GetTensorShape(output).FlatSize() * sizeof(int32_t), + &(data->scratch_buffer_index)) == kTfLiteOk); + } + + // Quantized 16x8 kernels use an int64 scratch buffer. + if (input->type == kTfLiteInt16) { + TFLITE_DCHECK(context->RequestScratchBufferInArena != nullptr); + TFLITE_DCHECK(context->RequestScratchBufferInArena( + context, + GetTensorShape(output).FlatSize() * sizeof(std::int64_t), + &(data->scratch_buffer_index)) == kTfLiteOk); + } + + // All per-channel quantized tensors need valid zero point and scale arrays. + if (input->type == kTfLiteInt8 || input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, filter->quantization.type, + kTfLiteAffineQuantization); + + const auto* affine_quantization = + static_cast(filter->quantization.params); + TF_LITE_ENSURE(context, affine_quantization); + TF_LITE_ENSURE(context, affine_quantization->scale); + TF_LITE_ENSURE(context, affine_quantization->zero_point); + + TF_LITE_ENSURE(context, + affine_quantization->scale->size == 1 || + affine_quantization->scale->size == + filter->dims->data[kConvQuantizedDimension]); + TF_LITE_ENSURE_EQ(context, affine_quantization->scale->size, + affine_quantization->zero_point->size); + } + + TF_LITE_ENSURE_STATUS(CalculateOpData(context, node, params, width, height, + filter_width, filter_height, + input->type, data)); + + // Offsets (zero points) + data->params.input_offset = -input->params.zero_point; + data->params.weights_offset = -filter->params.zero_point; + data->params.output_offset = output->params.zero_point; + + // Stride + data->params.stride_width = params->stride_width; + data->params.stride_height = params->stride_height; + + micro_context->DeallocateTempTfLiteTensor(output); + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(filter); + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* filter = + tflite::micro::GetEvalInput(context, node, kFilterTensor); + const TfLiteEvalTensor* bias = + (NumInputs(node) == 4) + ? tflite::micro::GetEvalInput(context, node, kBiasTensor) + : nullptr; + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + + TFLITE_DCHECK(node->user_data != nullptr); + const OpData& data = *(static_cast(node->user_data)); + + TF_LITE_ENSURE_EQ(context, input->type, output->type); + TF_LITE_ENSURE_MSG( + context, + input->type == filter->type || + (input->type == kTfLiteInt16 && filter->type == kTfLiteInt8), + "Hybrid models are not supported on TFLite Micro."); + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: { + reference_ops::TransposeConv( + data.params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr); + break; + } + case kTfLiteInt8: { + int32_t* scratch_buffer = static_cast( + context->GetScratchBuffer(context, data.scratch_buffer_index)); + reference_integer_ops::TransposeConv( + data.params, data.per_channel_output_multiplier, + data.per_channel_output_shift, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr, scratch_buffer); + break; + } + case kTfLiteInt16: { + std::int64_t* scratch_buffer = static_cast( + context->GetScratchBuffer(context, data.scratch_buffer_index)); + // TODO(b/192090531): Remove this once all 8x16 transpose conv models use + // 64-bit biases. + if (bias != nullptr && bias->type == kTfLiteInt16) { + std::int64_t* bias_converted_buffer = + static_cast(context->GetScratchBuffer( + context, data.bias_converted_buffer_index)); + for (int i = 0; i < tflite::micro::GetTensorShape(bias).FlatSize(); + i++) { + bias_converted_buffer[i] = bias->data.i16[i]; + } + reference_integer_ops::TransposeConv( + data.params, data.per_channel_output_multiplier, + data.per_channel_output_shift, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), bias_converted_buffer, + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr, scratch_buffer); + } else { + reference_integer_ops::TransposeConv( + data.params, data.per_channel_output_multiplier, + data.per_channel_output_shift, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetOptionalTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output), + tflite::micro::GetTensorShape(nullptr), nullptr, scratch_buffer); + } + break; + } + default: + MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type), + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace + +TfLiteRegistration Register_TRANSPOSE_CONV() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unidirectional_sequence_lstm.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unidirectional_sequence_lstm.cc new file mode 100644 index 000000000..f8b231349 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unidirectional_sequence_lstm.cc @@ -0,0 +1,1387 @@ +/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/lstm_eval.h" +#include "tensorflow/lite/micro/kernels/lstm_shared.h" +#include "tensorflow/lite/micro/kernels/micro_tensor_utils.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +namespace { + +constexpr int scratch_index_size = 12; + +struct UnidirectionalSequenceLstmOpData { + // If the lstm is layer norm. + bool use_layer_norm; + // The scratch index. + int scratch_index[scratch_index_size]; + + int32_t row_sums_size; + int32_t* row_sums; + bool compute_row_sums = false; + + int32_t input_zero_point; + int32_t output_state_zero_point; + + IntegerLstmParameter integer_lstm_param; +}; + +TfLiteStatus PopulateQuantizedLstmParams8x8_16( + TfLiteContext* context, TfLiteNode* node, + IntegerLstmParameter* integer_lstm_param) { + MicroContext* micro_context = GetMicroContext(context); + + // Calculate quantized clip for projection and cell. + const auto* params = + static_cast(node->builtin_data); + const float cell_clip = params->cell_clip; + const float proj_clip = params->proj_clip; + + TfLiteTensor* cell_state = + micro_context->AllocateTempInputTensor(node, kLstmCellStateTensor); + TF_LITE_ENSURE(context, cell_state != nullptr); + TF_LITE_ENSURE(context, cell_state->is_variable); + TfLiteTensor* output_tensor = + micro_context->AllocateTempOutputTensor(node, kLstmOutputTensor); + + TF_LITE_ENSURE(context, + cell_state->quantization.type != kTfLiteNoQuantization); + auto* cell_state_params = + static_cast(cell_state->quantization.params); + TF_LITE_ENSURE(context, + output_tensor->quantization.type != kTfLiteNoQuantization); + auto* proj_params = static_cast( + output_tensor->quantization.params); + if (cell_clip > 0.0f) { + integer_lstm_param->quantized_cell_clip = static_cast(std::min( + std::max(cell_clip / cell_state_params->scale->data[0], -32768.0f), + 32767.0f)); + } else { + integer_lstm_param->quantized_cell_clip = 0; + } + if (proj_clip > 0.0f) { + integer_lstm_param->quantized_proj_clip = static_cast(std::min( + std::max(proj_clip / proj_params->scale->data[0], -128.0f), 127.0f)); + } else { + integer_lstm_param->quantized_proj_clip = 0; + } + + // Calculate effective scales. + UnidirectionalSequenceLstmOpData* op_data = + static_cast(node->user_data); + const bool use_layer_norm = op_data->use_layer_norm; + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kLstmInputTensor); + + TfLiteTensor* input_to_input_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToInputWeightsTensor); + TfLiteTensor* input_to_forget_weights = + micro_context->AllocateTempInputTensor(node, + kLstmInputToForgetWeightsTensor); + TfLiteTensor* input_to_cell_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToCellWeightsTensor); + TfLiteTensor* input_to_output_weights = + micro_context->AllocateTempInputTensor(node, + kLstmInputToOutputWeightsTensor); + + TfLiteTensor* recurrent_to_input_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToInputWeightsTensor); + TfLiteTensor* recurrent_to_forget_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToForgetWeightsTensor); + TfLiteTensor* recurrent_to_cell_weights = + micro_context->AllocateTempInputTensor(node, + kLstmRecurrentToCellWeightsTensor); + TfLiteTensor* recurrent_to_output_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToOutputWeightsTensor); + + TfLiteTensor* cell_to_input_weights = micro_context->AllocateTempInputTensor( + node, kLstmCellToInputWeightsTensor); + TfLiteTensor* cell_to_forget_weights = micro_context->AllocateTempInputTensor( + node, kLstmCellToForgetWeightsTensor); + TfLiteTensor* cell_to_output_weights = micro_context->AllocateTempInputTensor( + node, kLstmCellToOutputWeightsTensor); + + TfLiteTensor* input_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmInputLayerNormCoefficientsTensor); + TfLiteTensor* forget_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmForgetLayerNormCoefficientsTensor); + TfLiteTensor* cell_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmCellLayerNormCoefficientsTensor); + TfLiteTensor* output_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmOutputLayerNormCoefficientsTensor); + + TfLiteTensor* projection_weights = micro_context->AllocateTempInputTensor( + node, kLstmProjectionWeightsTensor); + + TfLiteTensor* output_state = + micro_context->AllocateTempInputTensor(node, kLstmOutputStateTensor); + TF_LITE_ENSURE(context, output_state != nullptr); + TF_LITE_ENSURE(context, output_state->is_variable); + + // Since we have already checked that weights are all there or none, we can + // check the existence of only one to get the condition. + const bool use_cifg = (input_to_input_weights == nullptr); + const bool use_peephole = (cell_to_output_weights != nullptr); + const bool use_projection = (projection_weights != nullptr); + + // Get intermediate scales and zero points. + float intermediate_scale[5]; + int32_t intermediate_zp[5]; + for (int i = 0; i < 4; ++i) { + if (use_layer_norm) { + TfLiteTensor* intermediate = + micro_context->AllocateTempIntermediateTensor(node, i); + TF_LITE_ENSURE(context, + intermediate->quantization.type != kTfLiteNoQuantization); + auto* params_intermediate = static_cast( + intermediate->quantization.params); + intermediate_scale[i] = params_intermediate->scale->data[0]; + intermediate_zp[i] = params_intermediate->zero_point->data[0]; + if (intermediate != nullptr) { + micro_context->DeallocateTempTfLiteTensor(intermediate); + } + } else { + // Q3.12 for activation functions. + intermediate_scale[i] = std::pow(2.0f, -12.0f); + intermediate_zp[i] = 0; + } + } + // In the absence of projection, hidden becomes otuput and this intermediate + // is ignored. + TfLiteTensor* hidden = micro_context->AllocateTempIntermediateTensor(node, 4); + TF_LITE_ENSURE(context, hidden->quantization.type != kTfLiteNoQuantization); + auto* hidden_params = + static_cast(hidden->quantization.params); + intermediate_scale[4] = hidden_params->scale->data[0]; + intermediate_zp[4] = hidden_params->zero_point->data[0]; + if (hidden != nullptr) { + micro_context->DeallocateTempTfLiteTensor(hidden); + } + + // Scales. + const float default_scale = 1.0; + float input_scale = default_scale; + float input_to_input_weight_scale = default_scale; + float recurrent_to_input_weight_scale = default_scale; + float cell_to_input_weight_scale = default_scale; + float input_to_forget_weight_scale = default_scale; + float recurrent_to_forget_weight_scale = default_scale; + float cell_to_forget_weight_scale = default_scale; + float input_to_cell_weight_scale = default_scale; + float recurrent_to_cell_weight_scale = default_scale; + float input_to_output_weight_scale = default_scale; + float recurrent_to_output_weight_scale = default_scale; + float cell_to_output_weight_scale = default_scale; + float projection_weight_scale = default_scale; + float layer_norm_input_scale = default_scale; + float layer_norm_forget_scale = default_scale; + float layer_norm_cell_scale = default_scale; + float layer_norm_output_scale = default_scale; + float output_state_scale = default_scale; + int cell_scale = 1; + + // Effective scales. + float effective_input_to_input_scale = default_scale; + float effective_recurrent_to_input_scale = default_scale; + float effective_cell_to_input_scale = default_scale; + float effective_input_to_forget_scale = default_scale; + float effective_recurrent_to_forget_scale = default_scale; + float effective_cell_to_forget_scale = default_scale; + float effective_input_to_cell_scale = default_scale; + float effective_recurrent_to_cell_scale = default_scale; + float effective_input_to_output_scale = default_scale; + float effective_recurrent_to_output_scale = default_scale; + float effective_cell_to_output_scale = default_scale; + float effective_proj_scale = default_scale; + float effective_hidden_scale = default_scale; + + // Populate scales. + if (!use_cifg) { + input_to_input_weight_scale = input_to_input_weights->params.scale; + recurrent_to_input_weight_scale = recurrent_to_input_weights->params.scale; + } + + if (use_peephole) { + if (!use_cifg) { + cell_to_input_weight_scale = cell_to_input_weights->params.scale; + } + cell_to_forget_weight_scale = cell_to_forget_weights->params.scale; + cell_to_output_weight_scale = cell_to_output_weights->params.scale; + } + + if (use_layer_norm) { + if (!use_cifg) { + layer_norm_input_scale = input_layer_norm_coefficients->params.scale; + } + layer_norm_forget_scale = forget_layer_norm_coefficients->params.scale; + layer_norm_cell_scale = cell_layer_norm_coefficients->params.scale; + layer_norm_output_scale = output_layer_norm_coefficients->params.scale; + } + + if (use_projection) { + projection_weight_scale = projection_weights->params.scale; + } + output_state_scale = output_state->params.scale; + + input_to_forget_weight_scale = input_to_forget_weights->params.scale; + input_to_cell_weight_scale = input_to_cell_weights->params.scale; + input_to_output_weight_scale = input_to_output_weights->params.scale; + recurrent_to_forget_weight_scale = recurrent_to_forget_weights->params.scale; + recurrent_to_cell_weight_scale = recurrent_to_cell_weights->params.scale; + recurrent_to_output_weight_scale = recurrent_to_output_weights->params.scale; + + // Check cell state (already used above) + TF_LITE_ENSURE(context, CheckedLog2(cell_state->params.scale, &cell_scale)); + // TF_LITE_ENSURE(context, cell_scale <= -9); + integer_lstm_param->cell_scale = cell_scale; + input_scale = input->params.scale; + + // Calculate effective scales. + if (!use_cifg) { + effective_input_to_input_scale = + input_to_input_weight_scale * input_scale / intermediate_scale[0]; + effective_recurrent_to_input_scale = recurrent_to_input_weight_scale * + output_state_scale / + intermediate_scale[0]; + } + effective_input_to_forget_scale = + input_to_forget_weight_scale * input_scale / intermediate_scale[1]; + effective_recurrent_to_forget_scale = recurrent_to_forget_weight_scale * + output_state_scale / + intermediate_scale[1]; + + effective_input_to_cell_scale = + input_to_cell_weight_scale * input_scale / intermediate_scale[2]; + effective_recurrent_to_cell_scale = recurrent_to_cell_weight_scale * + output_state_scale / + intermediate_scale[2]; + + effective_input_to_output_scale = + input_to_output_weight_scale * input_scale / intermediate_scale[3]; + effective_recurrent_to_output_scale = recurrent_to_output_weight_scale * + output_state_scale / + intermediate_scale[3]; + + effective_hidden_scale = + std::pow(2.0f, -15.0f) / intermediate_scale[4] * std::pow(2.0f, -15.0f); + + effective_proj_scale = + projection_weight_scale * intermediate_scale[4] / output_state_scale; + + if (use_peephole) { + if (!use_cifg) { + effective_cell_to_input_scale = + std::pow(2.0f, static_cast(cell_scale)) * + cell_to_input_weight_scale / intermediate_scale[0]; + } + effective_cell_to_forget_scale = + std::pow(2.0f, static_cast(cell_scale)) * + cell_to_forget_weight_scale / intermediate_scale[1]; + effective_cell_to_output_scale = + std::pow(2.0f, static_cast(cell_scale)) * + cell_to_output_weight_scale / intermediate_scale[3]; + } + + // Decompose scales. + int shift_output; + QuantizeMultiplier(static_cast(effective_input_to_input_scale), + &integer_lstm_param->effective_input_to_input_scale_a, + &shift_output); + integer_lstm_param->effective_input_to_input_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_recurrent_to_input_scale), + &integer_lstm_param->effective_recurrent_to_input_scale_a, + &shift_output); + integer_lstm_param->effective_recurrent_to_input_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_cell_to_input_scale), + &integer_lstm_param->effective_cell_to_input_scale_a, + &shift_output); + integer_lstm_param->effective_cell_to_input_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_input_to_forget_scale), + &integer_lstm_param->effective_input_to_forget_scale_a, + &shift_output); + integer_lstm_param->effective_input_to_forget_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_recurrent_to_forget_scale), + &integer_lstm_param->effective_recurrent_to_forget_scale_a, + &shift_output); + integer_lstm_param->effective_recurrent_to_forget_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_cell_to_forget_scale), + &integer_lstm_param->effective_cell_to_forget_scale_a, + &shift_output); + integer_lstm_param->effective_cell_to_forget_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_input_to_cell_scale), + &integer_lstm_param->effective_input_to_cell_scale_a, + &shift_output); + integer_lstm_param->effective_input_to_cell_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_recurrent_to_cell_scale), + &integer_lstm_param->effective_recurrent_to_cell_scale_a, + &shift_output); + integer_lstm_param->effective_recurrent_to_cell_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_input_to_output_scale), + &integer_lstm_param->effective_input_to_output_scale_a, + &shift_output); + integer_lstm_param->effective_input_to_output_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_recurrent_to_output_scale), + &integer_lstm_param->effective_recurrent_to_output_scale_a, + &shift_output); + integer_lstm_param->effective_recurrent_to_output_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_cell_to_output_scale), + &integer_lstm_param->effective_cell_to_output_scale_a, + &shift_output); + integer_lstm_param->effective_cell_to_output_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_proj_scale), + &integer_lstm_param->effective_proj_scale_a, + &shift_output); + integer_lstm_param->effective_proj_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(effective_hidden_scale), + &integer_lstm_param->effective_hidden_scale_a, + &shift_output); + integer_lstm_param->effective_hidden_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(layer_norm_input_scale), + &integer_lstm_param->layer_norm_input_scale_a, + &shift_output); + integer_lstm_param->layer_norm_input_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(layer_norm_forget_scale), + &integer_lstm_param->layer_norm_forget_scale_a, + &shift_output); + integer_lstm_param->layer_norm_forget_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(layer_norm_cell_scale), + &integer_lstm_param->layer_norm_cell_scale_a, + &shift_output); + integer_lstm_param->layer_norm_cell_scale_b = + static_cast(shift_output); + QuantizeMultiplier(static_cast(layer_norm_output_scale), + &integer_lstm_param->layer_norm_output_scale_a, + &shift_output); + integer_lstm_param->layer_norm_output_scale_b = + static_cast(shift_output); + + integer_lstm_param->hidden_zp = intermediate_zp[4]; + + // 10000 is used to make sure the kernel logic does not overflow. + if (!use_cifg) { + integer_lstm_param->input_variance_guard = + std::max(1, static_cast(10000 * layer_norm_input_scale)); + } + integer_lstm_param->forget_variance_guard = + std::max(1, static_cast(10000 * layer_norm_forget_scale)); + integer_lstm_param->cell_variance_guard = + std::max(1, static_cast(10000 * layer_norm_cell_scale)); + integer_lstm_param->output_variance_guard = + std::max(1, static_cast(10000 * layer_norm_output_scale)); + + if (cell_state != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_state); + } + if (output_tensor != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_tensor); + } + if (input != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input); + } + if (input_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_input_weights); + } + if (input_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_forget_weights); + } + if (input_to_cell_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_cell_weights); + } + if (input_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_output_weights); + } + if (recurrent_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_input_weights); + } + if (recurrent_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_forget_weights); + } + if (recurrent_to_cell_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_cell_weights); + } + if (recurrent_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_output_weights); + } + if (cell_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_to_input_weights); + } + if (cell_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_to_forget_weights); + } + if (cell_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_to_output_weights); + } + if (input_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_layer_norm_coefficients); + } + if (forget_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(forget_layer_norm_coefficients); + } + if (cell_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_layer_norm_coefficients); + } + if (output_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_layer_norm_coefficients); + } + if (projection_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(projection_weights); + } + if (output_state != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_state); + } + + return kTfLiteOk; +} + +// Temporary buffers used for hybrid mode +enum HybridTempBuffer { + kPrimaryScratchBuffer = 0, + kInputQuantized = 1, + kOutputStateQuantized = 2, + kCellStateQuantized = 3, + kInputScalingFactors = 4, + kOutputStateScalingFactors = 5, + kProductScalingFactors = 6, + kRecoveredCellWeights = 7, + kAccumScratch = 8, + kInputZeroPoints = 9, + kOutputStateZeroPoints = 10, + kScales = 11, + kNumHybridTempBuffers = 12, +}; + +void* UnidirectionalSequenceLstmInit(TfLiteContext* context, const char* buffer, + size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer( + context, sizeof(UnidirectionalSequenceLstmOpData)); +} + +// Check that input tensor dimensions matches with each other. +TfLiteStatus CheckInputTensorDimensions(TfLiteContext* context, + TfLiteNode* node, int n_input, + int n_output, int n_cell, + bool use_layer_norm, bool is_integer) { + MicroContext* micro_context = GetMicroContext(context); + + const auto* params = reinterpret_cast(node->builtin_data); + + // Making sure clipping parameters have valid values. + // == 0 means no clipping + // > 0 means clipping + TF_LITE_ENSURE(context, params->cell_clip >= 0); + TF_LITE_ENSURE(context, params->proj_clip >= 0); + + TfLiteTensor* input_to_input_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToInputWeightsTensor); + if (input_to_input_weights != nullptr) { + TF_LITE_ENSURE_EQ(context, input_to_input_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_input_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, input_to_input_weights->dims->data[1], n_input); + } + + TfLiteTensor* input_to_forget_weights = + micro_context->AllocateTempInputTensor(node, + kLstmInputToForgetWeightsTensor); + TF_LITE_ENSURE_EQ(context, input_to_forget_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_forget_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, input_to_forget_weights->dims->data[1], n_input); + + TfLiteTensor* input_to_cell_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToCellWeightsTensor); + TF_LITE_ENSURE_EQ(context, input_to_cell_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_cell_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, input_to_cell_weights->dims->data[1], n_input); + + TfLiteTensor* recurrent_to_input_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToInputWeightsTensor); + if (recurrent_to_input_weights != nullptr) { + TF_LITE_ENSURE_EQ(context, recurrent_to_input_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_input_weights->dims->data[0], + n_cell); + TF_LITE_ENSURE_EQ(context, recurrent_to_input_weights->dims->data[1], + n_output); + } + + TfLiteTensor* recurrent_to_forget_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToForgetWeightsTensor); + TF_LITE_ENSURE_EQ(context, recurrent_to_forget_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_forget_weights->dims->data[0], + n_cell); + TF_LITE_ENSURE_EQ(context, recurrent_to_forget_weights->dims->data[1], + n_output); + + TfLiteTensor* recurrent_to_cell_weights = + micro_context->AllocateTempInputTensor(node, + kLstmRecurrentToCellWeightsTensor); + TF_LITE_ENSURE_EQ(context, recurrent_to_cell_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_cell_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_EQ(context, recurrent_to_cell_weights->dims->data[1], + n_output); + + // We make sure the input-gate's parameters are either both present (regular + // LSTM) or not at all (CIFG-LSTM). + const bool cifg_weights_all_or_none = + ((input_to_input_weights != nullptr) && + (recurrent_to_input_weights != nullptr)) || + ((input_to_input_weights == nullptr) && + (recurrent_to_input_weights == nullptr)); + TF_LITE_ENSURE(context, cifg_weights_all_or_none == true); + + TfLiteTensor* cell_to_input_weights = micro_context->AllocateTempInputTensor( + node, kLstmCellToInputWeightsTensor); + if (cell_to_input_weights != nullptr) { + TF_LITE_ENSURE_EQ(context, cell_to_input_weights->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_to_input_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_TYPES_EQ( + context, cell_to_input_weights->type, + is_integer ? kTfLiteInt16 : input_to_forget_weights->type); + } + + TfLiteTensor* cell_to_forget_weights = micro_context->AllocateTempInputTensor( + node, kLstmCellToForgetWeightsTensor); + if (cell_to_forget_weights != nullptr) { + TF_LITE_ENSURE_EQ(context, cell_to_forget_weights->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_to_forget_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_TYPES_EQ( + context, cell_to_forget_weights->type, + is_integer ? kTfLiteInt16 : input_to_forget_weights->type); + } + + TfLiteTensor* cell_to_output_weights = micro_context->AllocateTempInputTensor( + node, kLstmCellToOutputWeightsTensor); + if (cell_to_output_weights != nullptr) { + TF_LITE_ENSURE_EQ(context, cell_to_output_weights->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_to_output_weights->dims->data[0], n_cell); + TF_LITE_ENSURE_TYPES_EQ( + context, cell_to_output_weights->type, + is_integer ? kTfLiteInt16 : input_to_forget_weights->type); + } + + // Making sure the peephole weights are there all or none. + const bool use_cifg = (input_to_input_weights == nullptr); + const bool peephole_weights_all_or_none = + ((cell_to_input_weights != nullptr || use_cifg) && + (cell_to_forget_weights != nullptr) && + (cell_to_output_weights != nullptr)) || + ((cell_to_input_weights == nullptr) && + (cell_to_forget_weights == nullptr) && + (cell_to_output_weights == nullptr)); + TF_LITE_ENSURE(context, peephole_weights_all_or_none == true); + + // Make sure the input gate bias is present only when not a CIFG-LSTM. + TfLiteTensor* input_gate_bias = + micro_context->AllocateTempInputTensor(node, kLstmInputGateBiasTensor); + if (use_cifg) { + TF_LITE_ENSURE_EQ(context, input_gate_bias, nullptr); + } else { + TF_LITE_ENSURE_EQ(context, input_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, input_gate_bias->dims->data[0], n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, input_gate_bias->type, kTfLiteInt32); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, input_gate_bias->type, kTfLiteFloat32); + } + } + + TfLiteTensor* forget_gate_bias = + micro_context->AllocateTempInputTensor(node, kLstmForgetGateBiasTensor); + TF_LITE_ENSURE_EQ(context, forget_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, forget_gate_bias->dims->data[0], n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, forget_gate_bias->type, kTfLiteInt32); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, forget_gate_bias->type, kTfLiteFloat32); + } + + TfLiteTensor* cell_gate_bias = + micro_context->AllocateTempInputTensor(node, kLstmCellGateBiasTensor); + TF_LITE_ENSURE_EQ(context, cell_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_gate_bias->dims->data[0], n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, cell_gate_bias->type, kTfLiteInt32); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, cell_gate_bias->type, kTfLiteFloat32); + } + + TfLiteTensor* output_gate_bias = + micro_context->AllocateTempInputTensor(node, kLstmOutputGateBiasTensor); + TF_LITE_ENSURE_EQ(context, output_gate_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, output_gate_bias->dims->data[0], n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, output_gate_bias->type, kTfLiteInt32); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, output_gate_bias->type, kTfLiteFloat32); + } + + TfLiteTensor* projection_weights = micro_context->AllocateTempInputTensor( + node, kLstmProjectionWeightsTensor); + if (projection_weights != nullptr) { + TF_LITE_ENSURE_EQ(context, projection_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, projection_weights->dims->data[0], n_output); + TF_LITE_ENSURE_EQ(context, projection_weights->dims->data[1], n_cell); + } + + TfLiteTensor* projection_bias = + micro_context->AllocateTempInputTensor(node, kLstmProjectionBiasTensor); + if (projection_bias != nullptr) { + TF_LITE_ENSURE_EQ(context, projection_bias->dims->size, 1); + TF_LITE_ENSURE_EQ(context, projection_bias->dims->data[0], n_output); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, projection_bias->type, kTfLiteInt32); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, projection_bias->type, kTfLiteFloat32); + } + } + + // Making sure the projection tensors are consistent: + // 1) If projection weight is not present, then projection bias should not be + // present. + // 2) If projection weight is present, then projection bias is optional. + const bool projecton_tensors_consistent = + ((projection_weights != nullptr) || (projection_bias == nullptr)); + TF_LITE_ENSURE(context, projecton_tensors_consistent == true); + + if (use_layer_norm) { + TfLiteTensor* input_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmInputLayerNormCoefficientsTensor); + if (use_cifg) { + TF_LITE_ENSURE_EQ(context, input_layer_norm_coefficients, nullptr); + } else { + TF_LITE_ENSURE(context, input_layer_norm_coefficients != nullptr); + TF_LITE_ENSURE_EQ(context, input_layer_norm_coefficients->dims->size, 1); + TF_LITE_ENSURE_EQ(context, input_layer_norm_coefficients->dims->data[0], + n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, input_layer_norm_coefficients->type, + kTfLiteInt16); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, input_layer_norm_coefficients->type, + kTfLiteFloat32); + } + } + + TfLiteTensor* forget_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmForgetLayerNormCoefficientsTensor); + TF_LITE_ENSURE_EQ(context, forget_layer_norm_coefficients->dims->size, 1); + TF_LITE_ENSURE_EQ(context, forget_layer_norm_coefficients->dims->data[0], + n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, forget_layer_norm_coefficients->type, + kTfLiteInt16); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, forget_layer_norm_coefficients->type, + kTfLiteFloat32); + } + + TfLiteTensor* cell_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmCellLayerNormCoefficientsTensor); + TF_LITE_ENSURE_EQ(context, cell_layer_norm_coefficients->dims->size, 1); + TF_LITE_ENSURE_EQ(context, cell_layer_norm_coefficients->dims->data[0], + n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, cell_layer_norm_coefficients->type, + kTfLiteInt16); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, cell_layer_norm_coefficients->type, + kTfLiteFloat32); + } + + TfLiteTensor* output_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmOutputLayerNormCoefficientsTensor); + TF_LITE_ENSURE_EQ(context, output_layer_norm_coefficients->dims->size, 1); + TF_LITE_ENSURE_EQ(context, output_layer_norm_coefficients->dims->data[0], + n_cell); + if (is_integer) { + TF_LITE_ENSURE_TYPES_EQ(context, output_layer_norm_coefficients->type, + kTfLiteInt16); + } else { + TF_LITE_ENSURE_TYPES_EQ(context, output_layer_norm_coefficients->type, + kTfLiteFloat32); + } + if (input_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_layer_norm_coefficients); + } + if (forget_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(forget_layer_norm_coefficients); + } + if (cell_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_layer_norm_coefficients); + } + if (output_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_layer_norm_coefficients); + } + } + + if (input_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_input_weights); + } + if (input_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_forget_weights); + } + if (input_to_cell_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_cell_weights); + } + if (recurrent_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_input_weights); + } + if (recurrent_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_forget_weights); + } + micro_context->DeallocateTempTfLiteTensor(recurrent_to_cell_weights); + if (cell_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_to_input_weights); + } + if (cell_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_to_forget_weights); + } + if (cell_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_to_output_weights); + } + if (input_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_gate_bias); + } + if (forget_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(forget_gate_bias); + } + if (cell_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_gate_bias); + } + if (output_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_gate_bias); + } + if (projection_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(projection_weights); + } + if (projection_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(projection_bias); + } + + return kTfLiteOk; +} + +TfLiteStatus PrecomputeZeroPointTimesWeightWithBias( + TfLiteContext* context, int32_t zero_point, + const TfLiteTensor* weight_tensor, const TfLiteTensor* bias_tensor, + int32_t** output) { + if (weight_tensor == nullptr) { + return kTfLiteOk; + } + + const RuntimeShape& weight_shape = GetTensorShape(weight_tensor); + TF_LITE_ENSURE_EQ(context, weight_shape.DimensionsCount(), 2); + const int row = weight_shape.Dims(0); + const int col = weight_shape.Dims(1); + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + *output = static_cast( + context->AllocatePersistentBuffer(context, row * sizeof(int32_t))); + + if (bias_tensor == nullptr) { + memset(*output, 0, row * sizeof(int32_t)); + } else { + const int32_t* bias = GetTensorData(bias_tensor); + memcpy(*output, bias, row * sizeof(int32_t)); + } + if (zero_point != 0) { + const int8_t* weight = GetTensorData(weight_tensor); + tflite::tensor_utils::MatrixScalarMultiplyAccumulate(weight, zero_point, + row, col, *output); + } + return kTfLiteOk; +} + +TfLiteStatus PopulatePrecomputedZPTimesWeightsWithBias( + TfLiteContext* context, UnidirectionalSequenceLstmOpData* op_data, + TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kLstmInputTensor); + TfLiteTensor* output_state = + micro_context->AllocateTempInputTensor(node, kLstmOutputStateTensor); + TF_LITE_ENSURE(context, output_state != nullptr); + TF_LITE_ENSURE(context, output_state->is_variable); + + const int32_t input_zero_point = -input->params.zero_point; + const int32_t output_state_zero_point = -output_state->params.zero_point; + + TfLiteTensor* input_to_input_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToInputWeightsTensor); + TfLiteTensor* input_to_forget_weights = + micro_context->AllocateTempInputTensor(node, + kLstmInputToForgetWeightsTensor); + TfLiteTensor* input_to_cell_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToCellWeightsTensor); + TfLiteTensor* input_to_output_weights = + micro_context->AllocateTempInputTensor(node, + kLstmInputToOutputWeightsTensor); + + TfLiteTensor* recurrent_to_input_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToInputWeightsTensor); + TfLiteTensor* recurrent_to_forget_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToForgetWeightsTensor); + TfLiteTensor* recurrent_to_cell_weights = + micro_context->AllocateTempInputTensor(node, + kLstmRecurrentToCellWeightsTensor); + TfLiteTensor* recurrent_to_output_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToOutputWeightsTensor); + + TfLiteTensor* projection_weights = micro_context->AllocateTempInputTensor( + node, kLstmProjectionWeightsTensor); + TfLiteTensor* projection_bias = + micro_context->AllocateTempInputTensor(node, kLstmProjectionBiasTensor); + + IntegerLstmParameter* integer_lstm_params = &op_data->integer_lstm_param; + + TfLiteTensor* intermediate = + micro_context->AllocateTempIntermediateTensor(node, 4); + TF_LITE_ENSURE(context, + intermediate->quantization.type != kTfLiteNoQuantization); + const auto* params = + static_cast(intermediate->quantization.params); + const int32_t hidden_zp = params->zero_point->data[0]; + + // Get bias and perform zero point calculation. + // When there is layer normalization, the gate bias does not apply to matmul + // directly: + // y = ln(w * x + w * r + w * c) + b. + const bool is_layer_norm = op_data->use_layer_norm; + + // Forget gate. + TfLiteTensor* forget_gate_bias = is_layer_norm + ? nullptr + : micro_context->AllocateTempInputTensor( + node, kLstmForgetGateBiasTensor); + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, input_zero_point, input_to_forget_weights, forget_gate_bias, + &(integer_lstm_params->input_to_forget_effective_bias))); + + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, output_state_zero_point, recurrent_to_forget_weights, + nullptr, &(integer_lstm_params->recurrent_to_forget_effective_bias))); + + // Modulation gate. + TfLiteTensor* cell_gate_bias = is_layer_norm + ? nullptr + : micro_context->AllocateTempInputTensor( + node, kLstmCellGateBiasTensor); + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, input_zero_point, input_to_cell_weights, cell_gate_bias, + &(integer_lstm_params->input_to_cell_effective_bias))); + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, output_state_zero_point, recurrent_to_cell_weights, nullptr, + &(integer_lstm_params->recurrent_to_cell_effective_bias))); + + // Output gate. + TfLiteTensor* output_gate_bias = is_layer_norm + ? nullptr + : micro_context->AllocateTempInputTensor( + node, kLstmOutputGateBiasTensor); + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, input_zero_point, input_to_output_weights, output_gate_bias, + &(integer_lstm_params->input_to_output_effective_bias))); + + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, output_state_zero_point, recurrent_to_output_weights, + nullptr, &(integer_lstm_params->recurrent_to_output_effective_bias))); + + // Input gate. The calculation is only meaningful for non-cifg case. + TfLiteTensor* input_gate_bias = is_layer_norm + ? nullptr + : micro_context->AllocateTempInputTensor( + node, kLstmInputGateBiasTensor); + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, input_zero_point, input_to_input_weights, input_gate_bias, + &(integer_lstm_params->input_to_input_effective_bias))); + TF_LITE_ENSURE_OK( + context, + PrecomputeZeroPointTimesWeightWithBias( + context, output_state_zero_point, recurrent_to_input_weights, nullptr, + &(integer_lstm_params->recurrent_to_input_effective_bias))); + + // Projection bias. The calculation is only meaningful for with projection. + TF_LITE_ENSURE_OK(context, + PrecomputeZeroPointTimesWeightWithBias( + context, hidden_zp, projection_weights, projection_bias, + &(integer_lstm_params->projection_effective_bias))); + + if (input != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input); + } + if (output_state != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_state); + } + if (input_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_input_weights); + } + if (input_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_forget_weights); + } + if (input_to_cell_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_cell_weights); + } + if (input_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_output_weights); + } + if (recurrent_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_input_weights); + } + if (recurrent_to_forget_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_forget_weights); + } + if (recurrent_to_cell_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_cell_weights); + } + if (recurrent_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_output_weights); + } + if (projection_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(projection_weights); + } + if (projection_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(projection_bias); + } + if (forget_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(forget_gate_bias); + } + if (cell_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_gate_bias); + } + if (output_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_gate_bias); + } + if (input_gate_bias != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_gate_bias); + } + + if (intermediate != nullptr) { + micro_context->DeallocateTempTfLiteTensor(intermediate); + } + + return kTfLiteOk; +} + +// Resize the output and state tensors based on the sizes of the input tensors. +// Allocate a temporary scratch tensor. Also check that the sizes of the input +// tensors match each other. +TfLiteStatus UnidirectionalSequenceLstmPrepare(TfLiteContext* context, + TfLiteNode* node) { + UnidirectionalSequenceLstmOpData* op_data = + reinterpret_cast(node->user_data); + + MicroContext* micro_context = GetMicroContext(context); + + // Check we have all the inputs and outputs we need. + bool use_layer_norm = false; + if (node->inputs->size == 24) { + TfLiteTensor* forget_layer_norm_coefficients = + micro_context->AllocateTempInputTensor( + node, kLstmForgetLayerNormCoefficientsTensor); + if (forget_layer_norm_coefficients == nullptr) { + use_layer_norm = false; + } else { + use_layer_norm = true; + } + if (forget_layer_norm_coefficients != nullptr) { + micro_context->DeallocateTempTfLiteTensor(forget_layer_norm_coefficients); + } + } else if (node->inputs->size == 20) { + // This is deprecated and is only kept here for backward compatibility. + use_layer_norm = false; + } else { + MicroPrintf("The LSTM Full kernel expects 20 or 24 inputs. Got %d inputs", + node->inputs->size); + return kTfLiteError; + } + TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); + op_data->use_layer_norm = use_layer_norm; + + // Inferring batch size, number of outputs and sequence length and + // number of cells from the input tensors. + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kLstmInputTensor); + op_data->input_zero_point = input->params.zero_point; + const bool is_integer = input->type == kTfLiteInt8; + TF_LITE_ENSURE(context, input->dims->size > 1); + const auto* params = + reinterpret_cast( + node->builtin_data); + const bool time_major = params->time_major; + const int n_batch = time_major ? input->dims->data[1] : input->dims->data[0]; + const int n_input = input->dims->data[2]; + + TfLiteTensor* input_to_output_weights = + micro_context->AllocateTempInputTensor(node, + kLstmInputToOutputWeightsTensor); + const int n_cell = input_to_output_weights->dims->data[0]; + TF_LITE_ENSURE_EQ(context, input_to_output_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, input_to_output_weights->dims->data[1], n_input); + + TfLiteTensor* recurrent_to_output_weights = + micro_context->AllocateTempInputTensor( + node, kLstmRecurrentToOutputWeightsTensor); + TF_LITE_ENSURE_EQ(context, recurrent_to_output_weights->dims->size, 2); + TF_LITE_ENSURE_EQ(context, recurrent_to_output_weights->dims->data[0], + n_cell); + const int n_output = recurrent_to_output_weights->dims->data[1]; + + // Check that input tensor dimensions matches with each other. + TF_LITE_ENSURE_OK( + context, CheckInputTensorDimensions(context, node, n_input, n_output, + n_cell, use_layer_norm, is_integer)); + + // Get the pointer to output, output_state and cell_state buffer tensors. + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kLstmOutputTensor); + + TfLiteTensor* output_state = + micro_context->AllocateTempInputTensor(node, kLstmOutputStateTensor); + TF_LITE_ENSURE(context, output_state != nullptr); + TF_LITE_ENSURE(context, output_state->is_variable); + op_data->output_state_zero_point = output_state->params.zero_point; + TfLiteTensor* cell_state = + micro_context->AllocateTempInputTensor(node, kLstmCellStateTensor); + TF_LITE_ENSURE(context, cell_state != nullptr); + TF_LITE_ENSURE(context, cell_state->is_variable); + + // Check the shape of input state tensors. + // These tensor may be 1D or 2D. It's fine as long as the total size is + // correct. + TF_LITE_ENSURE_EQ(context, NumElements(output_state), n_batch * n_output); + TF_LITE_ENSURE_EQ(context, NumElements(cell_state), n_batch * n_cell); + + // Check the shape of output tensor against that of input tensor + TF_LITE_ENSURE_EQ(context, output->dims->size, 3); + TF_LITE_ENSURE_EQ(context, input->dims->data[0], output->dims->data[0]); + TF_LITE_ENSURE_EQ(context, input->dims->data[1], output->dims->data[1]); + TF_LITE_ENSURE_EQ(context, output->dims->data[2], n_output); + + if (is_integer) { + const int num_intermediate_tensors = node->intermediates->size; + TF_LITE_ENSURE(context, num_intermediate_tensors == 5); + } + + TfLiteTensor* input_to_input_weights = micro_context->AllocateTempInputTensor( + node, kLstmInputToInputWeightsTensor); + + const bool use_cifg = (input_to_input_weights == nullptr); + + // Create a primary scratch buffer for hybrid and float + // If is_integer, primary scratch buffer has a different size + if (!is_integer) { + int scratch_buffer_size[2]; + scratch_buffer_size[0] = n_batch; + + if (use_cifg) { + // Reserving space for Cell, Forget, Output gates + scratch_buffer_size[1] = n_cell * 3; + } else { + // Reserving space for Input, Cell, Forget, Output gates + scratch_buffer_size[1] = n_cell * 4; + } + + TF_LITE_ENSURE_OK(context, + context->RequestScratchBufferInArena( + context, + scratch_buffer_size[0] * scratch_buffer_size[1] * + TfLiteTypeGetSize(input->type), + &(op_data->scratch_index[kPrimaryScratchBuffer]))); + } + + if (is_integer) { + // Integer UnidirectionalSequenceLSTM prepare function for 8x8->16. + // This code path needs 5 intermediate tensors per Op. + // Populate quantization parameters. + PopulateQuantizedLstmParams8x8_16(context, node, + &op_data->integer_lstm_param); + // Allocate scratch buffer. Need 4 16-bit buffer with size n_batch * n_cell + // and 1 8-bit buffer with size n_batch * n_cell. For integer + // UnidirectionalSequenceLSTM, we do not need the extra 32-bit buffer. + for (int i = 0; i < 5; ++i) { + TfLiteType buffer_type = kTfLiteInt16; + + if (i == 4) { + buffer_type = kTfLiteInt8; + } + + TF_LITE_ENSURE_OK( + context, + context->RequestScratchBufferInArena( + context, n_batch * n_cell * TfLiteTypeGetSize(buffer_type), + &(op_data->scratch_index[i]))); + } + + // Populate precomputed zp * weight. + TF_LITE_ENSURE_OK(context, PopulatePrecomputedZPTimesWeightsWithBias( + context, op_data, node)); + } + + if (input != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input); + } + if (input_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_output_weights); + } + if (recurrent_to_output_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(recurrent_to_output_weights); + } + if (output != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output); + } + if (output_state != nullptr) { + micro_context->DeallocateTempTfLiteTensor(output_state); + } + if (cell_state != nullptr) { + micro_context->DeallocateTempTfLiteTensor(cell_state); + } + + if (input_to_input_weights != nullptr) { + micro_context->DeallocateTempTfLiteTensor(input_to_input_weights); + } + return kTfLiteOk; +} + +TfLiteStatus UnidirectionalSequenceLstmEval(TfLiteContext* context, + TfLiteNode* node) { + TFLITE_DCHECK(context->GetScratchBuffer != nullptr); + + const auto* params = + reinterpret_cast( + node->builtin_data); + const UnidirectionalSequenceLstmOpData* op_data = + reinterpret_cast(node->user_data); + const bool use_layer_norm = op_data->use_layer_norm; + const bool time_major = params->time_major; + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kLstmInputTensor); + + const TfLiteEvalTensor* input_to_input_weights = tflite::micro::GetEvalInput( + context, node, kLstmInputToInputWeightsTensor); + + const TfLiteEvalTensor* input_to_forget_weights = tflite::micro::GetEvalInput( + context, node, kLstmInputToForgetWeightsTensor); + + const TfLiteEvalTensor* input_to_cell_weights = + tflite::micro::GetEvalInput(context, node, kLstmInputToCellWeightsTensor); + + const TfLiteEvalTensor* input_to_output_weights = tflite::micro::GetEvalInput( + context, node, kLstmInputToOutputWeightsTensor); + + const TfLiteEvalTensor* recurrent_to_input_weights = + tflite::micro::GetEvalInput(context, node, + kLstmRecurrentToInputWeightsTensor); + + const TfLiteEvalTensor* recurrent_to_forget_weights = + tflite::micro::GetEvalInput(context, node, + kLstmRecurrentToForgetWeightsTensor); + + const TfLiteEvalTensor* recurrent_to_cell_weights = + tflite::micro::GetEvalInput(context, node, + kLstmRecurrentToCellWeightsTensor); + + const TfLiteEvalTensor* recurrent_to_output_weights = + tflite::micro::GetEvalInput(context, node, + kLstmRecurrentToOutputWeightsTensor); + + const TfLiteEvalTensor* cell_to_input_weights = + tflite::micro::GetEvalInput(context, node, kLstmCellToInputWeightsTensor); + + const TfLiteEvalTensor* cell_to_forget_weights = tflite::micro::GetEvalInput( + context, node, kLstmCellToForgetWeightsTensor); + + const TfLiteEvalTensor* cell_to_output_weights = tflite::micro::GetEvalInput( + context, node, kLstmCellToOutputWeightsTensor); + + const TfLiteEvalTensor* input_gate_bias = + tflite::micro::GetEvalInput(context, node, kLstmInputGateBiasTensor); + + const TfLiteEvalTensor* forget_gate_bias = + tflite::micro::GetEvalInput(context, node, kLstmForgetGateBiasTensor); + + const TfLiteEvalTensor* cell_gate_bias = + tflite::micro::GetEvalInput(context, node, kLstmCellGateBiasTensor); + + const TfLiteEvalTensor* output_gate_bias = + tflite::micro::GetEvalInput(context, node, kLstmOutputGateBiasTensor); + + const TfLiteEvalTensor* projection_weights = + tflite::micro::GetEvalInput(context, node, kLstmProjectionWeightsTensor); + + const TfLiteEvalTensor* projection_bias = + tflite::micro::GetEvalInput(context, node, kLstmProjectionBiasTensor); + + TfLiteEvalTensor* output_state = + tflite::micro::GetMutableEvalInput(context, node, kLstmOutputStateTensor); + + TfLiteEvalTensor* cell_state = + tflite::micro::GetMutableEvalInput(context, node, kLstmCellStateTensor); + + TFLITE_DCHECK(cell_state != nullptr); + + const TfLiteEvalTensor* input_layer_norm_coefficients = + use_layer_norm ? tflite::micro::GetEvalInput( + context, node, kLstmInputLayerNormCoefficientsTensor) + : nullptr; + const TfLiteEvalTensor* forget_layer_norm_coefficients = + use_layer_norm + ? tflite::micro::GetEvalInput(context, node, + kLstmForgetLayerNormCoefficientsTensor) + : nullptr; + const TfLiteEvalTensor* cell_layer_norm_coefficients = + use_layer_norm ? tflite::micro::GetEvalInput( + context, node, kLstmCellLayerNormCoefficientsTensor) + : nullptr; + const TfLiteEvalTensor* output_layer_norm_coefficients = + use_layer_norm + ? tflite::micro::GetEvalInput(context, node, + kLstmOutputLayerNormCoefficientsTensor) + : nullptr; + + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kLstmOutputTensor); + + // Copy out the LSTM specific params so they can be passed in the function. + TfLiteLSTMParams lstm_params; + lstm_params.activation = params->activation; + lstm_params.cell_clip = params->cell_clip; + lstm_params.proj_clip = params->proj_clip; + lstm_params.asymmetric_quantize_inputs = params->asymmetric_quantize_inputs; + + switch (input_to_output_weights->type) { + case kTfLiteFloat32: { + // Index the scratch buffers pointers to the global scratch buffer. + return EvalFloatLstm( + input, input_to_input_weights, input_to_forget_weights, + input_to_cell_weights, input_to_output_weights, + recurrent_to_input_weights, recurrent_to_forget_weights, + recurrent_to_cell_weights, recurrent_to_output_weights, + cell_to_input_weights, cell_to_forget_weights, cell_to_output_weights, + input_layer_norm_coefficients, forget_layer_norm_coefficients, + cell_layer_norm_coefficients, output_layer_norm_coefficients, + /*aux_input=*/nullptr, + /*aux_input_to_input_weights=*/nullptr, + /*aux_input_to_forget_weights=*/nullptr, + /*aux_input_to_cell_weights=*/nullptr, + /*aux_input_to_output_weights=*/nullptr, input_gate_bias, + forget_gate_bias, cell_gate_bias, output_gate_bias, + projection_weights, projection_bias, &lstm_params, + /*forward_sequence=*/true, time_major, + /*output_offset=*/0, + reinterpret_cast(context->GetScratchBuffer( + context, op_data->scratch_index[kPrimaryScratchBuffer])), + output_state, cell_state, output); + } break; + case kTfLiteUInt8: + case kTfLiteInt8: { + return EvalInteger8x8_16Lstm( + input, input_to_input_weights, input_to_forget_weights, + input_to_cell_weights, input_to_output_weights, + recurrent_to_input_weights, recurrent_to_forget_weights, + recurrent_to_cell_weights, recurrent_to_output_weights, + cell_to_input_weights, cell_to_forget_weights, cell_to_output_weights, + input_layer_norm_coefficients, forget_layer_norm_coefficients, + cell_layer_norm_coefficients, output_layer_norm_coefficients, + input_gate_bias, forget_gate_bias, cell_gate_bias, output_gate_bias, + projection_weights, projection_bias, &lstm_params, + /*forward_sequence=*/true, time_major, &op_data->integer_lstm_param, + op_data->output_state_zero_point, output_state, cell_state, output, + reinterpret_cast( + context->GetScratchBuffer(context, op_data->scratch_index[0])), + reinterpret_cast( + context->GetScratchBuffer(context, op_data->scratch_index[1])), + reinterpret_cast( + context->GetScratchBuffer(context, op_data->scratch_index[2])), + reinterpret_cast( + context->GetScratchBuffer(context, op_data->scratch_index[3])), + reinterpret_cast( + context->GetScratchBuffer(context, op_data->scratch_index[4])), + nullptr); + } break; + default: + MicroPrintf("Type %s is not currently supported.", + TfLiteTypeGetName(input_to_output_weights->type)); + return kTfLiteError; + } +} + +} // namespace + +TfLiteRegistration Register_UNIDIRECTIONAL_SEQUENCE_LSTM() { + return tflite::micro::RegisterOp(UnidirectionalSequenceLstmInit, + UnidirectionalSequenceLstmPrepare, + UnidirectionalSequenceLstmEval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unidirectional_sequence_lstm_test_config.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unidirectional_sequence_lstm_test_config.h new file mode 100644 index 000000000..24c838faf --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unidirectional_sequence_lstm_test_config.h @@ -0,0 +1,244 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_KERNELS_UNIDIRECTIONAL_SEQUENCE_LSTM_TEST_CONFIG_H_ +#define TENSORFLOW_LITE_MICRO_KERNELS_UNIDIRECTIONAL_SEQUENCE_LSTM_TEST_CONFIG_H_ + +#include "tensorflow/lite/c/common.h" + +namespace tflite { +namespace testing { + +// TODO(b/230666079) enable below tests for xtensa when the xtensa +// kernel is reconciled with reference kernel +#if !defined(XTENSA) + +struct LstmIntegerTestConfig { + const int n_batch; + const int n_input; + const int n_cell; + const int n_output; + const int sequence_length; + const bool time_major; + const bool use_cifg; + const bool use_peephole; + const bool use_projection_weights; + const bool use_projection_bias; + const bool use_layer_norm; + const bool use_8x8_8_implementation; + float intermediate_scale[5][2]; + int intermediate_zp[5][2]; + TfLiteAffineQuantization* intermediate_qparam; + + const float* input; + int8_t* input_quant; + + const float* input_to_input_weights; + int8_t* lstm_i2i_quant; + const float* input_to_forget_weights; + int8_t* lstm_i2f_quant; + const float* input_to_cell_weights; + int8_t* lstm_i2c_quant; + const float* input_to_output_weights; + int8_t* lstm_i2o_quant; + + const float* recurrent_to_input_weights; + int8_t* lstm_r2i_quant; + const float* recurrent_to_forget_weights; + int8_t* lstm_r2f_quant; + const float* recurrent_to_cell_weights; + int8_t* lstm_r2c_quant; + const float* recurrent_to_output_weights; + int8_t* lstm_r2o_quant; + + const float* cell_to_input_weights; + int16_t* lstm_c2i_quant; + const float* cell_to_forget_weights; + int16_t* lstm_c2f_quant; + const float* cell_to_output_weights; + int16_t* lstm_c2o_quant; + + const float* input_gate_bias; + int32_t* lstm_igate_bias_quant; + const float* forget_gate_bias; + int32_t* lstm_fgate_bias_quant; + const float* cell_gate_bias; + int32_t* lstm_cgate_bias_quant; + const float* output_gate_bias; + int32_t* lstm_ogate_bias_quant; + + const float* projection_weights; + int8_t* lstm_proj_w_quant; + const float* projection_bias; + int32_t* projection_bias_quant; + + int16_t* output_state; + int16_t* cell_state; + + const float* input_layer_norm_coefficients; + int16_t* lstm_input_layer_norm_coeff_quant; + const float* forget_layer_norm_coefficients; + int16_t* lstm_forget_layer_norm_coeff_quant; + const float* cell_layer_norm_coefficients; + int16_t* lstm_cell_layer_norm_coeff_quant; + const float* output_layer_norm_coefficients; + int16_t* lstm_output_layer_norm_coeff_quant; + + int8_t* output; + const int8_t* expected_output; + + bool asymmetric_quantize_inputs; + const float ranges[25][2]; +}; + +struct LstmFloatTestConfig { + const int n_batch; + const int n_input; + const int n_cell; + const int n_output; + const int sequence_length; + const bool time_major; + const bool use_cifg; + const bool use_peephole; + const bool use_projection_weights; + const bool use_projection_bias; + const bool use_layer_norm; + const float cell_clip; + const float proj_clip; + + const float* input_original; + float* input; + + const float* input_to_input_weights; + const float* input_to_forget_weights; + const float* input_to_cell_weights; + const float* input_to_output_weights; + + const float* recurrent_to_input_weights; + const float* recurrent_to_forget_weights; + const float* recurrent_to_cell_weights; + const float* recurrent_to_output_weights; + + const float* cell_to_input_weights; + const float* cell_to_forget_weights; + const float* cell_to_output_weights; + + const float* input_gate_bias; + const float* forget_gate_bias; + const float* cell_gate_bias; + const float* output_gate_bias; + + const float* projection_weights; + const float* projection_bias; + + float* output_state; + float* cell_state; + + const float* input_layer_norm_coefficients; + const float* forget_layer_norm_coefficients; + const float* cell_layer_norm_coefficients; + const float* output_layer_norm_coefficients; + + float* output; + const float* expected_output_original; + float* expected_output; +}; + +struct LstmWeightQuantizationBuffers { + int8_t* lstm_i2i_quant; + float* lstm_i2i_scale; + int* lstm_i2i_zp; + TfLiteAffineQuantization* lstm_i2i_qparam; + + int8_t* lstm_i2f_quant; + float* lstm_i2f_scale; + int* lstm_i2f_zp; + TfLiteAffineQuantization* lstm_i2f_qparam; + + int8_t* lstm_i2c_quant; + float* lstm_i2c_scale; + int* lstm_i2c_zp; + TfLiteAffineQuantization* lstm_i2c_qparam; + + int8_t* lstm_i2o_quant; + float* lstm_i2o_scale; + int* lstm_i2o_zp; + TfLiteAffineQuantization* lstm_i2o_qparam; + + int8_t* lstm_r2i_quant; + float* lstm_r2i_scale; + int* lstm_r2i_zp; + TfLiteAffineQuantization* lstm_r2i_qparam; + + int8_t* lstm_r2f_quant; + float* lstm_r2f_scale; + int* lstm_r2f_zp; + TfLiteAffineQuantization* lstm_r2f_qparam; + + int8_t* lstm_r2c_quant; + float* lstm_r2c_scale; + int* lstm_r2c_zp; + TfLiteAffineQuantization* lstm_r2c_qparam; + + int8_t* lstm_r2o_quant; + float* lstm_r2o_scale; + int* lstm_r2o_zp; + TfLiteAffineQuantization* lstm_r2o_qparam; + + int8_t* lstm_c2i_quant; + float* lstm_c2i_scale; + int* lstm_c2i_zp; + TfLiteAffineQuantization* lstm_c2i_qparam; + + int8_t* lstm_c2f_quant; + float* lstm_c2f_scale; + int* lstm_c2f_zp; + TfLiteAffineQuantization* lstm_c2f_qparam; + + int8_t* lstm_c2o_quant; + float* lstm_c2o_scale; + int* lstm_c2o_zp; + TfLiteAffineQuantization* lstm_c2o_qparam; + + int8_t* lstm_proj_w_quant; + float* lstm_proj_w_scale; + int* lstm_proj_w_zp; + TfLiteAffineQuantization* lstm_proj_w_qparam; +}; + +extern LstmIntegerTestConfig lstm_integer_no_peephole_config; + +extern LstmIntegerTestConfig lstm_integer_peephole_config; + +extern LstmFloatTestConfig lstm_no_cifg_no_peephole_no_proj_config; + +extern LstmFloatTestConfig lstm_cifg_peephole_no_proj_config; + +extern LstmFloatTestConfig lstm_no_cifg_peephole_proj_config; + +extern LstmFloatTestConfig lstm_no_cifg_peephole_proj_bias_config; + +extern LstmWeightQuantizationBuffers lstm_no_cifg_no_peephole_no_proj_buffers; + +extern LstmWeightQuantizationBuffers lstm_cifg_peephole_no_proj_buffers; + +extern LstmWeightQuantizationBuffers lstm_no_cifg_peephole_proj_buffers; + +extern LstmFloatTestConfig cifg_peephole_no_proj_config_layer_norm; + +#endif // !defined(XTENSA) +} // namespace testing +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_KERNELS_UNIDIRECTIONAL_SEQUENCE_LSTM_TEST_CONFIG_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unpack.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unpack.cc new file mode 100644 index 000000000..b58df2e73 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/unpack.cc @@ -0,0 +1,112 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace unpack { +namespace { + +constexpr int kInputTensor = 0; + +template +TfLiteStatus UnpackImpl(TfLiteContext* context, TfLiteNode* node, + const TfLiteEvalTensor* input, int output_count, + int axis) { + const TfLiteEvalTensor* output0 = + tflite::micro::GetEvalOutput(context, node, 0); + const TfLiteIntArray* input_dims = input->dims; + const TfLiteIntArray* output_dims = output0->dims; + const int dimensions = input_dims->size; + + if (axis < 0) { + axis += input->dims->size; + } + + TFLITE_DCHECK_LT(axis, dimensions); + + int outer_size = 1; + for (int i = 0; i < axis; ++i) { + outer_size *= input_dims->data[i]; + } + int copy_size = 1; + for (int i = axis + 1; i < dimensions; ++i) { + copy_size *= input_dims->data[i]; + } + int output_size = 1; + for (int i = 0; i < output_dims->size; ++i) { + output_size *= output_dims->data[i]; + } + TFLITE_DCHECK_EQ(output_size, copy_size * outer_size); + + const T* input_data = tflite::micro::GetTensorData(input); + + for (int i = 0; i < output_count; ++i) { + TfLiteEvalTensor* t = tflite::micro::GetEvalOutput(context, node, i); + T* output_data = tflite::micro::GetTensorData(t); + for (int k = 0; k < outer_size; ++k) { + T* output_ptr = output_data + copy_size * k; + int loc = k * output_count * copy_size + i * copy_size; + const T* input_ptr = input_data + loc; + for (int j = 0; j < copy_size; ++j) output_ptr[j] = input_ptr[j]; + } + } + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + TfLiteUnpackParams* data = + reinterpret_cast(node->builtin_data); + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + + switch (input->type) { + case kTfLiteFloat32: { + return UnpackImpl(context, node, input, data->num, data->axis); + } + case kTfLiteInt32: { + return UnpackImpl(context, node, input, data->num, data->axis); + } + case kTfLiteInt8: { + return UnpackImpl(context, node, input, data->num, data->axis); + } + default: { + MicroPrintf("Type '%s' is not supported by unpack.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + } + + return kTfLiteOk; +} +} // namespace +} // namespace unpack + +TfLiteRegistration Register_UNPACK() { + return tflite::micro::RegisterOp(nullptr, nullptr, unpack::Eval); +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/var_handle.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/var_handle.cc new file mode 100644 index 000000000..cbd2485ca --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/var_handle.cc @@ -0,0 +1,93 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_resource_variable.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +namespace { + +struct OpData { + int32_t resource_id; +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + OpData* op_data = reinterpret_cast(node->user_data); + const auto* params = + reinterpret_cast(node->builtin_data); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + MicroGraph& graph_info = micro_context->graph(); + + MicroResourceVariables* resources = graph_info.GetResourceVariables(); + if (resources == nullptr) { + MicroPrintf( + "VAR_HANDLE requires resource variables. Please create " + "ResourceVariables and pass it to the interpreter."); + return kTfLiteError; + } + op_data->resource_id = + resources->CreateIdIfNoneFound(params->container, params->shared_name); + if (op_data->resource_id < 0) { + return kTfLiteError; + } + + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TFLITE_DCHECK(output != nullptr); + + // Assign saved resource_id so this output tensor will always return the + // correct resource id. + output->data.i32 = &op_data->resource_id; + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + OpData* op_data = reinterpret_cast(node->user_data); + + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TFLITE_DCHECK(output != nullptr); + + // Assign saved resource_id so this output tensor will always return the + // correct resource id. + output->data.i32 = &op_data->resource_id; + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_VAR_HANDLE() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/while.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/while.cc new file mode 100644 index 000000000..811c9eaec --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/while.cc @@ -0,0 +1,133 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_context.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +namespace { + +struct OpData { + int cond_subgraph_index; + int body_subgraph_index; +}; + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(OpData)); +} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + OpData* op_data = reinterpret_cast(node->user_data); + const auto* params = + reinterpret_cast(node->builtin_data); + + op_data->cond_subgraph_index = params->cond_subgraph_index; + op_data->body_subgraph_index = params->body_subgraph_index; + + // The first input is the condition. + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + + size_t num_inputs = node->inputs->size; + size_t num_outputs = node->outputs->size; + + MicroGraph& graph_info = micro_context->graph(); + + TF_LITE_ENSURE(context, + op_data->cond_subgraph_index < graph_info.NumSubgraphs()); + TF_LITE_ENSURE(context, + op_data->body_subgraph_index < graph_info.NumSubgraphs()); + + TF_LITE_ENSURE_EQ(context, num_inputs, + graph_info.NumSubgraphInputs(op_data->cond_subgraph_index)); + TF_LITE_ENSURE_EQ(context, num_inputs, + graph_info.NumSubgraphInputs(op_data->body_subgraph_index)); + TF_LITE_ENSURE_EQ(context, num_inputs, num_outputs); + TF_LITE_ENSURE_EQ( + context, num_outputs, + graph_info.NumSubgraphOutputs(op_data->body_subgraph_index)); + + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const OpData* op_data = reinterpret_cast(node->user_data); + + tflite::MicroContext* micro_context = tflite::GetMicroContext(context); + MicroGraph* graph_info = µ_context->graph(); + + TF_LITE_ENSURE_OK(context, + tflite::micro::CopyOpInputsToSubgraphInputs( + context, node, graph_info, op_data->cond_subgraph_index, + /*first_tensor_idx=*/0)); + + TF_LITE_ENSURE_OK(context, + graph_info->InvokeSubgraph(op_data->cond_subgraph_index)); + + TfLiteEvalTensor* cond_subgraph_output = graph_info->GetSubgraphOutput( + op_data->cond_subgraph_index, /*tensor_idx=*/0); + bool cond_value = cond_subgraph_output->data.b[0]; + + TF_LITE_ENSURE_OK(context, + tflite::micro::CopyOpInputsToSubgraphInputs( + context, node, graph_info, op_data->body_subgraph_index, + /*first_tensor_idx=*/0)); + TF_LITE_ENSURE_OK(context, + tflite::micro::CopyOpInputsToOpOutputs(context, node)); + + while (cond_value == true) { + // Copy output of this iteration back to the body input. + TF_LITE_ENSURE_OK( + context, tflite::micro::CopyOpOutputsToSubgraphInputs( + context, node, graph_info, op_data->body_subgraph_index)); + TF_LITE_ENSURE_OK(context, + graph_info->InvokeSubgraph(op_data->body_subgraph_index)); + + TF_LITE_ENSURE_OK( + context, tflite::micro::CopySubgraphOutputsToOpOutputs( + context, node, graph_info, op_data->body_subgraph_index)); + TF_LITE_ENSURE_OK( + context, tflite::micro::CopyOpOutputsToSubgraphInputs( + context, node, graph_info, op_data->cond_subgraph_index)); + TF_LITE_ENSURE_OK(context, + graph_info->InvokeSubgraph(op_data->cond_subgraph_index)); + + cond_subgraph_output = graph_info->GetSubgraphOutput( + op_data->cond_subgraph_index, /*tensor_idx=*/0); + cond_value = cond_subgraph_output->data.b[0]; + } + + return kTfLiteOk; +} + +} // namespace. + +TfLiteRegistration Register_WHILE() { + return tflite::micro::RegisterOp(Init, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/zeros_like.cc b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/zeros_like.cc new file mode 100644 index 000000000..bb0c3147c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/kernels/zeros_like.cc @@ -0,0 +1,88 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + output->type = input->type; + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +template +void resetZeros(T* out, const int num_elements) { + for (int i = 0; i < num_elements; ++i) { + out[i] = static_cast(0); + } +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + int flat_size = MatchingFlatSize(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output)); + switch (input->type) { + case kTfLiteInt64: + resetZeros(tflite::micro::GetTensorData(output), flat_size); + break; + case kTfLiteInt32: + resetZeros(tflite::micro::GetTensorData(output), flat_size); + break; + case kTfLiteInt8: + resetZeros(tflite::micro::GetTensorData(output), flat_size); + break; + case kTfLiteFloat32: + resetZeros(tflite::micro::GetTensorData(output), flat_size); + break; + default: + MicroPrintf( + "ZerosLike only currently supports int64, int32, " + "and float32, got %d.", + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} +} // namespace + +TfLiteRegistration Register_ZEROS_LIKE() { + return tflite::micro::RegisterOp(nullptr, Prepare, Eval); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_helpers.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_helpers.cpp new file mode 100644 index 000000000..c653babc2 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_helpers.cpp @@ -0,0 +1,173 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/memory_helpers.h" + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/flatbuffer_conversions.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +uint8_t* AlignPointerUp(uint8_t* data, size_t alignment) { + std::uintptr_t data_as_uintptr_t = reinterpret_cast(data); + uint8_t* aligned_result = reinterpret_cast( + ((data_as_uintptr_t + (alignment - 1)) / alignment) * alignment); + return aligned_result; +} + +uint8_t* AlignPointerDown(uint8_t* data, size_t alignment) { + std::uintptr_t data_as_uintptr_t = reinterpret_cast(data); + uint8_t* aligned_result = + reinterpret_cast((data_as_uintptr_t / alignment) * alignment); + return aligned_result; +} + +size_t AlignSizeUp(size_t size, size_t alignment) { + size_t aligned_size = (((size + (alignment - 1)) / alignment) * alignment); + return aligned_size; +} + +TfLiteStatus TfLiteTypeSizeOf(TfLiteType type, size_t* size) { + switch (type) { + case kTfLiteFloat16: + *size = sizeof(int16_t); + break; + case kTfLiteFloat32: + *size = sizeof(float); + break; + case kTfLiteFloat64: + *size = sizeof(double); + break; + case kTfLiteInt16: + *size = sizeof(int16_t); + break; + case kTfLiteInt32: + *size = sizeof(int32_t); + break; + case kTfLiteUInt32: + *size = sizeof(uint32_t); + break; + case kTfLiteUInt8: + *size = sizeof(uint8_t); + break; + case kTfLiteInt8: + *size = sizeof(int8_t); + break; + case kTfLiteInt64: + *size = sizeof(int64_t); + break; + case kTfLiteUInt64: + *size = sizeof(uint64_t); + break; + case kTfLiteBool: + *size = sizeof(bool); + break; + case kTfLiteResource: + *size = sizeof(int32_t); + break; + case kTfLiteComplex64: + *size = sizeof(float) * 2; + break; + case kTfLiteComplex128: + *size = sizeof(double) * 2; + break; + case kTfLiteInt4: + *size = sizeof(int8_t); + break; + default: + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus BytesRequiredForTensor(const tflite::Tensor& flatbuffer_tensor, + size_t* bytes, size_t* type_size) { + int element_count = 1; + // If flatbuffer_tensor.shape == nullptr, then flatbuffer_tensor is a scalar + // so has 1 element. + if (flatbuffer_tensor.shape() != nullptr) { + for (size_t n = 0; n < flatbuffer_tensor.shape()->Length(); ++n) { + element_count *= flatbuffer_tensor.shape()->Get(n); + } + } + + TfLiteType tf_lite_type; + TF_LITE_ENSURE_STATUS(ConvertTensorType(flatbuffer_tensor.type(), + &tf_lite_type, + tflite::GetMicroErrorReporter())); + TF_LITE_ENSURE_STATUS(TfLiteTypeSizeOf(tf_lite_type, type_size)); + *bytes = element_count * (*type_size); + return kTfLiteOk; +} + +TfLiteStatus TfLiteEvalTensorByteLength(const TfLiteEvalTensor* eval_tensor, + size_t* out_bytes) { + TFLITE_DCHECK(out_bytes != nullptr); + + int element_count = 1; + // If eval_tensor->dims == nullptr, then tensor is a scalar so has 1 element. + if (eval_tensor->dims != nullptr) { + for (int n = 0; n < eval_tensor->dims->size; ++n) { + element_count *= eval_tensor->dims->data[n]; + } + } + size_t type_size; + TF_LITE_ENSURE_STATUS(TfLiteTypeSizeOf(eval_tensor->type, &type_size)); + *out_bytes = element_count * type_size; + return kTfLiteOk; +} + +TfLiteStatus AllocateOutputDimensionsFromInput(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteTensor* output) { + const TfLiteTensor* input = nullptr; + + TF_LITE_ENSURE(context, input1->dims != nullptr); + TF_LITE_ENSURE(context, input2->dims != nullptr); + TF_LITE_ENSURE(context, output->dims->size == 0); + + input = input1->dims->size > input2->dims->size ? input1 : input2; + TF_LITE_ENSURE(context, output->type == input->type); + + size_t size = 0; + TfLiteTypeSizeOf(input->type, &size); + const int dimensions_count = tflite::GetTensorShape(input).DimensionsCount(); + for (int i = 0; i < dimensions_count; i++) { + size *= input->dims->data[i]; + } + + output->bytes = size; + + output->dims = + reinterpret_cast(context->AllocatePersistentBuffer( + context, TfLiteIntArrayGetSizeInBytes(size))); + + output->dims->size = input->dims->size; + for (int i = 0; i < dimensions_count; i++) { + output->dims->data[i] = input->dims->data[i]; + } + + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_helpers.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_helpers.h new file mode 100644 index 000000000..ccdbed2ff --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_helpers.h @@ -0,0 +1,57 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MEMORY_HELPERS_H_ +#define TENSORFLOW_LITE_MICRO_MEMORY_HELPERS_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// Returns the next pointer address aligned to the given alignment. +uint8_t* AlignPointerUp(uint8_t* data, size_t alignment); + +// Returns the previous pointer address aligned to the given alignment. +uint8_t* AlignPointerDown(uint8_t* data, size_t alignment); + +// Returns an increased size that's a multiple of alignment. +size_t AlignSizeUp(size_t size, size_t alignment); + +// Returns size in bytes for a given TfLiteType. +TfLiteStatus TfLiteTypeSizeOf(TfLiteType type, size_t* size); + +// How many bytes are needed to hold a tensor's contents. +TfLiteStatus BytesRequiredForTensor(const tflite::Tensor& flatbuffer_tensor, + size_t* bytes, size_t* type_size); + +// How many bytes are used in a TfLiteEvalTensor instance. The byte length is +// returned in out_bytes. +TfLiteStatus TfLiteEvalTensorByteLength(const TfLiteEvalTensor* eval_tensor, + size_t* out_bytes); + +// Deduce output dimensions from input and allocate given size. +// Useful for operators with two inputs where the largest input should equal the +// output dimension. +TfLiteStatus AllocateOutputDimensionsFromInput(TfLiteContext* context, + const TfLiteTensor* input1, + const TfLiteTensor* input2, + TfLiteTensor* output); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MEMORY_HELPERS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cpp new file mode 100644 index 000000000..471a5b229 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/greedy_memory_planner.cpp @@ -0,0 +1,448 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h" + +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_string.h" + +namespace tflite { + +namespace { + +// Returns a character representing a numbered buffer +// for GreedyMemoryPlanner::PrintMemoryPlan() +char GetOrdinalCharacter(int i) { + if (i < 10) { + return '0' + i; + } else if (i < 36) { + return 'a' + (i - 10); + } else if (i < 62) { + return 'A' + (i - 36); + } + return '*'; +} + +} // namespace + +// Simple stable in-place sort function. Not time-efficient for large arrays. +// Would normally be in an anonymous namespace to keep it private, but we want +// to be able to test it externally. +void ReverseSortInPlace(int* values, int* ids, int size) { + bool any_swapped; + do { + any_swapped = false; + for (int i = 1; i < size; ++i) { + if (values[i - 1] < values[i]) { + const int value_temp = values[i - 1]; + values[i - 1] = values[i]; + values[i] = value_temp; + const int id_temp = ids[i - 1]; + ids[i - 1] = ids[i]; + ids[i] = id_temp; + any_swapped = true; + } + } + } while (any_swapped); +} + +GreedyMemoryPlanner::GreedyMemoryPlanner() {} + +TfLiteStatus GreedyMemoryPlanner::Init(unsigned char* scratch_buffer, + int scratch_buffer_size) { + // Reset internal states + buffer_count_ = 0; + need_to_calculate_offsets_ = true; + + // Allocate the arrays we need within the scratch buffer arena. + max_buffer_count_ = scratch_buffer_size / per_buffer_size(); + + unsigned char* next_free = scratch_buffer; + requirements_ = reinterpret_cast(next_free); + next_free += sizeof(BufferRequirements) * max_buffer_count_; + + buffer_sizes_sorted_ = reinterpret_cast(next_free); + next_free += sizeof(int) * max_buffer_count_; + + buffer_ids_sorted_ = reinterpret_cast(next_free); + next_free += sizeof(int) * max_buffer_count_; + + buffers_sorted_by_offset_ = reinterpret_cast(next_free); + next_free += sizeof(ListEntry) * max_buffer_count_; + + buffer_offsets_ = reinterpret_cast(next_free); + return kTfLiteOk; +} + +GreedyMemoryPlanner::~GreedyMemoryPlanner() { + // We don't own the scratch buffer, so don't deallocate anything. +} + +TfLiteStatus GreedyMemoryPlanner::AddBuffer(int size, int first_time_used, + int last_time_used) { + if (buffer_count_ >= max_buffer_count_) { + MicroPrintf("Too many buffers (max is %d)", max_buffer_count_); + return kTfLiteError; + } + BufferRequirements* current = &requirements_[buffer_count_]; + current->size = size; + current->first_time_used = first_time_used; + current->last_time_used = last_time_used; + current->offline_offset = kOnlinePlannedBuffer; + ++buffer_count_; + need_to_calculate_offsets_ = true; + return kTfLiteOk; +} + +TfLiteStatus GreedyMemoryPlanner::AddBuffer(int size, int first_time_used, + int last_time_used, + int offline_offset) { + BufferRequirements* current = &requirements_[buffer_count_]; + if (AddBuffer(size, first_time_used, last_time_used) != kTfLiteOk) { + return kTfLiteError; + } + current->offline_offset = offline_offset; + return kTfLiteOk; +} + +bool GreedyMemoryPlanner::DoesEntryOverlapInTime( + const GreedyMemoryPlanner::ListEntry* entry, const int first_time_used, + const int last_time_used) const { + const BufferRequirements* entry_requirements = + &requirements_[entry->requirements_index]; + if (entry_requirements->first_time_used > last_time_used) { + return false; + } + if (first_time_used > entry_requirements->last_time_used) { + return false; + } + return true; +} + +GreedyMemoryPlanner::ListEntry* +GreedyMemoryPlanner::NextSimultaneouslyActiveBuffer( + const GreedyMemoryPlanner::ListEntry* start, const int first_time_used, + const int last_time_used) { + ListEntry* result = nullptr; + ListEntry* candidate_next_entry; + if (start == nullptr) { + candidate_next_entry = &buffers_sorted_by_offset_[first_entry_index_]; + } else { + if (start->next_entry_index == -1) { + return nullptr; + } + candidate_next_entry = &buffers_sorted_by_offset_[start->next_entry_index]; + } + do { + if (DoesEntryOverlapInTime(candidate_next_entry, first_time_used, + last_time_used)) { + result = candidate_next_entry; + break; + } + if (candidate_next_entry->next_entry_index == -1) { + break; + } + candidate_next_entry = + &buffers_sorted_by_offset_[candidate_next_entry->next_entry_index]; + } while (true); + return result; +} + +void GreedyMemoryPlanner::CalculateOffsetsIfNeeded() { + if (!need_to_calculate_offsets_ || (buffer_count_ == 0)) { + return; + } + need_to_calculate_offsets_ = false; + + // Start off by ordering the buffers in descending order of size. + // This helps find a more compact layout. Intuitively, you can think + // about putting the large buffers in place first, and then the + // smaller buffers can fit in the gaps, rather than fragmenting the + // gaps with small buffers at the beginning. Add offline planned offsets + // first in the list, since they have a predetermined offset. + int idx_from_tail = buffer_count_; + int idx_from_head = 0; + for (int i = 0; i < buffer_count_; ++i) { + if (requirements_[i].offline_offset == kOnlinePlannedBuffer) { + idx_from_tail--; + buffer_sizes_sorted_[idx_from_tail] = requirements_[i].size; + buffer_ids_sorted_[idx_from_tail] = i; + buffer_offsets_[i] = -1; + } else { + buffer_sizes_sorted_[idx_from_head] = requirements_[i].size; + buffer_ids_sorted_[idx_from_head] = i; + buffer_offsets_[i] = requirements_[i].offline_offset; + idx_from_head++; + } + } + + // This sorting algorithm is naive, and may end up taking a very long time + // with hundreds of buffers. Do not sort the offline planned offsets. + ReverseSortInPlace(&buffer_sizes_sorted_[idx_from_head], + &buffer_ids_sorted_[idx_from_head], + buffer_count_ - idx_from_head); + + // Initialize the first entry to the first buffer in + // buffer_ids_sorted_. + // - If there are no offline planned offsets, the largest buffer will be + // first, and the buffers will be handled in size order. + // - If offline offsets are present, these will be handled first in order + // for the greedy algorithm to utilized gaps in the offline plan. + first_entry_index_ = 0; + next_free_entry_ = 1; + ListEntry* first_entry = &buffers_sorted_by_offset_[first_entry_index_]; + first_entry->next_entry_index = -1; // to mark the entry as end of list + int buffer_id = buffer_ids_sorted_[0]; + first_entry->requirements_index = buffer_id; + if (requirements_[buffer_id].offline_offset == kOnlinePlannedBuffer) { + buffer_offsets_[buffer_id] = 0; + } + first_entry->offset = buffer_offsets_[buffer_id]; + + // Work through the rest of the buffers to find a good gap to place each one. + for (int i = 1; i < buffer_count_; ++i) { + // The id is the order the buffer was originally added by the client. + buffer_id = buffer_ids_sorted_[i]; + // Look at what size and time range the buffer needs to be active. + BufferRequirements* wanted_requirements = &requirements_[buffer_id]; + const int wanted_size = wanted_requirements->size; + const int wanted_first_time_used = wanted_requirements->first_time_used; + const int wanted_last_time_used = wanted_requirements->last_time_used; + + // Find the first buffer that's active in our time range. All placed + // buffers are stored in the order of their starting position in the arena + // so that it's easy to find the next buffer in memory, and so the gap. + // The candidate_entry variable holds the buffer that we're considering + // placing the current buffer after. + + int candidate_offset = 0; + // Loop through the offset-ordered list of buffers, looking for gaps. + if (wanted_requirements->offline_offset == kOnlinePlannedBuffer) { + ListEntry* prior_entry = nullptr; + while (true) { + // Find out what the next active buffer is. + ListEntry* next_entry = NextSimultaneouslyActiveBuffer( + prior_entry, wanted_first_time_used, wanted_last_time_used); + + if (prior_entry) { + BufferRequirements* candidate_requirements = + &requirements_[prior_entry->requirements_index]; + const int prior_entry_offset = + prior_entry->offset + candidate_requirements->size; + if (prior_entry_offset > candidate_offset) { + candidate_offset = prior_entry_offset; + } + } + if (next_entry == nullptr) { + // We're at the end of the list, so we can always append the buffer + // here. + break; + } + // Find out how much space there is between us and the next buffer. + const int gap = next_entry->offset - candidate_offset; + if (gap >= wanted_size) { + // This entry has a big enough gap between it and the next, so + // use it! + break; + } + // The gap wasn't big enough, so move on to another candidate. + prior_entry = next_entry; + } + } else { + // Offline planned offset are to be considered constant + candidate_offset = wanted_requirements->offline_offset; + } + // At this point, we've either found a gap (possibly at the end of the + // list) and want to place the buffer there, or there are no other active + // buffers in this time range and so we can put it at offset zero. + // Record the buffer's offset in our plan. + buffer_offsets_[buffer_id] = candidate_offset; + // Add the newly-placed buffer to our offset-ordered list, so that + // subsequent passes can fit in their buffers around it. + ListEntry* new_entry = &buffers_sorted_by_offset_[next_free_entry_]; + new_entry->offset = candidate_offset; + new_entry->requirements_index = buffer_id; + const int new_entry_index = next_free_entry_; + ++next_free_entry_; + + if (first_entry->offset > candidate_offset) { + // The new entry offset is smaller than the first entry offset => + // replace the first entry + first_entry = new_entry; + first_entry->next_entry_index = first_entry_index_; + first_entry_index_ = new_entry_index; + } else { + ListEntry* current_entry = first_entry; + // Make sure that we insert the buffer at the correct place in the + // buffer-offset-ordered list + while (true) { + const int next_entry_index = current_entry->next_entry_index; + if (next_entry_index == -1) { + // We're at the end of the list, so just add the new entry here. + current_entry->next_entry_index = new_entry_index; + new_entry->next_entry_index = -1; + break; + } + // not at the end of the list -> take a look at next entry + ListEntry* next_entry = &buffers_sorted_by_offset_[next_entry_index]; + if (next_entry->offset > candidate_offset) { + // We're at the right spot to do an insertion and retain the sorting + // order, so place the new entry here. + new_entry->next_entry_index = current_entry->next_entry_index; + current_entry->next_entry_index = new_entry_index; + break; + } + current_entry = next_entry; + } + } + } +} + +size_t GreedyMemoryPlanner::GetMaximumMemorySize() { + CalculateOffsetsIfNeeded(); + if (buffer_count_ == 0) { + return 0; + } + ListEntry* entry = &buffers_sorted_by_offset_[first_entry_index_]; + size_t max_size = 0; + while (entry) { + BufferRequirements* requirements = + &requirements_[entry->requirements_index]; + const size_t current_size = entry->offset + requirements->size; + if (current_size > max_size) { + max_size = current_size; + } + if (entry->next_entry_index == -1) { + break; + } + entry = &buffers_sorted_by_offset_[entry->next_entry_index]; + } + return max_size; +} + +void GreedyMemoryPlanner::PrintMemoryPlan() { + CalculateOffsetsIfNeeded(); + + for (int i = 0; i < buffer_count_; ++i) { + MicroPrintf("%c (id=%d): size=%d, offset=%d, first_used=%d last_used=%d", + GetOrdinalCharacter(i), i, requirements_[i].size, + buffer_offsets_[i], requirements_[i].first_time_used, + requirements_[i].last_time_used); + } + + constexpr int kLineWidth = 80; + int max_size = kLineWidth; + int max_time = 0; + for (int i = 0; i < buffer_count_; ++i) { + BufferRequirements* requirements = &requirements_[i]; + const int offset = buffer_offsets_[i]; + const int last_time_used = requirements->last_time_used; + const int size = offset + requirements->size; + if (size > max_size) { + max_size = size; + } + if (last_time_used > max_time) { + max_time = last_time_used; + } + } + + char line[kLineWidth + 1]; + for (int t = 0; t <= max_time; ++t) { + for (int c = 0; c < kLineWidth; ++c) { + line[c] = '.'; + } + int memory_use = 0; + for (int i = 0; i < buffer_count_; ++i) { + BufferRequirements* requirements = &requirements_[i]; + if ((t < requirements->first_time_used) || + (t > requirements->last_time_used)) { + continue; + } + const int offset = buffer_offsets_[i]; + if (offset == -1) { + continue; + } + const int size = requirements->size; + memory_use += size; + const int line_start = (offset * kLineWidth) / max_size; + const int line_end = ((offset + size) * kLineWidth) / max_size; + for (int n = line_start; n < line_end; ++n) { + if (line[n] == '.') { + line[n] = GetOrdinalCharacter(i); + } else { + line[n] = '!'; + } + } + } + line[kLineWidth] = 0; + + MicroPrintf("%s%d: %s (%dk)", t < 10 ? " " : "", t, (const char*)line, + (memory_use + 1023) / 1024); + } +} + +int GreedyMemoryPlanner::GetBufferCount() { return buffer_count_; } + +TfLiteStatus GreedyMemoryPlanner::GetOffsetForBuffer(int buffer_index, + int* offset) { + CalculateOffsetsIfNeeded(); + if ((buffer_index < 0) || (buffer_index >= buffer_count_)) { + MicroPrintf("buffer index %d is outside range 0 to %d", buffer_index, + buffer_count_); + return kTfLiteError; + } + *offset = buffer_offsets_[buffer_index]; + return kTfLiteOk; +} + +bool GreedyMemoryPlanner::DoAnyBuffersOverlap() { + CalculateOffsetsIfNeeded(); + bool were_overlaps_found = false; + for (int i = 0; i < buffer_count_; ++i) { + BufferRequirements* a_requirements = &requirements_[i]; + const int a_start_offset = buffer_offsets_[i]; + const int a_first_time_used = a_requirements->first_time_used; + const int a_last_time_used = a_requirements->last_time_used; + const int a_end_offset = a_start_offset + a_requirements->size; + for (int j = 0; j < buffer_count_; ++j) { + if (i == j) { + continue; + } + BufferRequirements* b_requirements = &requirements_[j]; + const int b_start_offset = buffer_offsets_[j]; + const int b_first_time_used = b_requirements->first_time_used; + const int b_last_time_used = b_requirements->last_time_used; + const int b_end_offset = b_start_offset + b_requirements->size; + if ((a_first_time_used > b_last_time_used) || + (b_first_time_used > a_last_time_used)) { + // Buffers don't overlap in time. + continue; + } + if ((a_start_offset >= b_end_offset) || + (b_start_offset >= a_end_offset)) { + // No overlap in memory. + continue; + } + were_overlaps_found = true; + MicroPrintf("Overlap: %d (%d=>%d, %d->%d) vs %d (%d=>%d, %d->%d)", i, + a_first_time_used, a_last_time_used, a_start_offset, + a_end_offset, j, b_first_time_used, b_last_time_used, + b_start_offset, b_end_offset); + } + } + return were_overlaps_found; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/greedy_memory_planner.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/greedy_memory_planner.h new file mode 100644 index 000000000..ae3705d33 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/greedy_memory_planner.h @@ -0,0 +1,165 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_GREEDY_MEMORY_PLANNER_H_ +#define TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_GREEDY_MEMORY_PLANNER_H_ + +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/memory_planner/micro_memory_planner.h" + +namespace tflite { + +constexpr int kOnlinePlannedBuffer = -1; + +// A memory planner that uses a greedy algorithm to arrange buffers in memory +// to minimize the overall arena size needed. +// +// The algorithm works like this: +// - The client enters the buffer information through AddBuffer(). +// - When a function like GetOffsetForBuffer() is called, the +// CalculateOffsetsIfNeeded() method is invoked. +// - If an up to date plan is not already present, one will be calculated. +// - The buffers are sorted in descending order of size. +// - The largest buffer is placed at offset zero. +// - The rest of the buffers are looped through in descending size order. +// - The other buffers that need to be in memory at the same time are found. +// - The first gap between simultaneously active buffers that the current +// buffer fits into will be used. +// - If no large-enough gap is found, the current buffer is placed after the +// last buffer that's simultaneously active. +// - This continues until all buffers are placed, and the offsets stored. +// +// This is not guaranteed to produce the best placement, since that's an +// NP-Complete problem, but in practice it should produce one that's decent. +class GreedyMemoryPlanner : public MicroMemoryPlanner { + public: + GreedyMemoryPlanner(); + ~GreedyMemoryPlanner() override; + + // You need to pass in an area of memory to be used for planning. The client + // should ensure the validity of the memory when it needs to use this object. + // This memory isn't owned by this object, so management should be handled by + // the client. This is so it can be stack or globally allocated if necessary + // on devices without dynamic memory allocation. How many buffers can be + // planned for will depend on the size of this scratch memory, so you should + // enlarge it if you see an error when calling AddBuffer(). The memory can be + // reused once you're done with the planner, as long as you copy the + // calculated offsets to another location. Each buffer requires about 36 bytes + // of scratch. + TfLiteStatus Init(unsigned char* scratch_buffer, + int scratch_buffer_size) override; + + // Record details of a buffer we want to place. + TfLiteStatus AddBuffer(int size, int first_time_used, + int last_time_used) override; + + // Record details of an offline planned buffer offset we want to place. + // offline_offset is the buffer offset from the start of the arena. + TfLiteStatus AddBuffer(int size, int first_time_used, int last_time_used, + int offline_offset) override; + + // Returns the high-water mark of used memory. This is the minimum size of a + // memory arena you'd need to allocate to hold these buffers. + size_t GetMaximumMemorySize() override; + + // How many buffers have been recorded. + int GetBufferCount() override; + + // Where a given buffer should be placed in the memory arena. + // This information is stored in the memory arena itself, so once the arena + // is used for inference, it will be overwritten. + TfLiteStatus GetOffsetForBuffer(int buffer_index, int* offset) override; + + // Prints an ascii-art diagram of the buffer layout plan. + void PrintMemoryPlan() override; + + // Debug method to check whether any buffer allocations are overlapping. This + // is an O(N^2) complexity operation, so only use for testing. + bool DoAnyBuffersOverlap(); + + // Used to store a list of buffers ordered by their offset. + struct ListEntry { + int offset; + int requirements_index; + int next_entry_index; + }; + + // Number of bytes required in order to plan a buffer. + static size_t per_buffer_size() { + const int per_buffer_size = + sizeof(BufferRequirements) + // requirements_ + sizeof(int) + // buffer_sizes_sorted_ + sizeof(int) + // buffer_ids_sorted_ + sizeof(ListEntry) + // buffers_sorted_by_offset_ + sizeof(int); // buffer_offsets_; + return per_buffer_size; + } + + private: + // Whether a buffer is active in a given time range. + bool DoesEntryOverlapInTime(const ListEntry* entry, const int first_time_used, + const int last_time_used) const; + + // Walks the list to return the next buffer that is active in a given time + // range, or a null pointer if there are none. + ListEntry* NextSimultaneouslyActiveBuffer(const ListEntry* start, + const int first_time_used, + const int last_time_used); + + // If there isn't an up to date plan, calculate a new one. + void CalculateOffsetsIfNeeded(); + + // How many buffers we can plan for, based on the arena size we're given in + // the constructor. + int max_buffer_count_; + + // The number of buffers added so far. + int buffer_count_; + + // Records the client-provided information about each buffer. + struct BufferRequirements { + int size; + int offline_offset; + int first_time_used; + int last_time_used; + }; + + // Working arrays used during the layout algorithm. + BufferRequirements* requirements_; + // buffer_sizes_sorted_ and buffer_ids_sorted_ are sorted according to: + // { + // offline planned buffers, + // online planned buffers sorted by size + // } + int* buffer_sizes_sorted_; + int* buffer_ids_sorted_; + ListEntry* buffers_sorted_by_offset_; + int next_free_entry_; // Index of the next free entry of + // buffers_sorted_by_offset_ + int first_entry_index_; // Index of the first entry (smallest offset) of + // buffers_sorted_by_offset_ + + // Stores the outcome of the plan, the location of each buffer in the arena. + int* buffer_offsets_; + + // Whether buffers have been added since the last plan was calculated. + bool need_to_calculate_offsets_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_GREEDY_MEMORY_PLANNER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/linear_memory_planner.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/linear_memory_planner.cpp new file mode 100644 index 000000000..5c6afb545 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/linear_memory_planner.cpp @@ -0,0 +1,53 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/memory_planner/linear_memory_planner.h" + +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +LinearMemoryPlanner::LinearMemoryPlanner() + : current_buffer_count_(0), next_free_offset_(0) {} +LinearMemoryPlanner::~LinearMemoryPlanner() {} + +TfLiteStatus LinearMemoryPlanner::AddBuffer(int size, int first_time_used, + int last_time_used) { + if (current_buffer_count_ >= kMaxBufferCount) { + MicroPrintf("Too many buffers (max is %d)", kMaxBufferCount); + return kTfLiteError; + } + buffer_offsets_[current_buffer_count_] = next_free_offset_; + next_free_offset_ += size; + ++current_buffer_count_; + return kTfLiteOk; +} + +size_t LinearMemoryPlanner::GetMaximumMemorySize() { return next_free_offset_; } + +int LinearMemoryPlanner::GetBufferCount() { return current_buffer_count_; } + +TfLiteStatus LinearMemoryPlanner::GetOffsetForBuffer(int buffer_index, + int* offset) { + if ((buffer_index < 0) || (buffer_index >= current_buffer_count_)) { + MicroPrintf("buffer index %d is outside range 0 to %d", buffer_index, + current_buffer_count_); + return kTfLiteError; + } + *offset = buffer_offsets_[buffer_index]; + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/linear_memory_planner.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/linear_memory_planner.h new file mode 100644 index 000000000..d4938ddc7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/linear_memory_planner.h @@ -0,0 +1,49 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_LINEAR_MEMORY_PLANNER_H_ +#define TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_LINEAR_MEMORY_PLANNER_H_ + +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/memory_planner/micro_memory_planner.h" + +namespace tflite { + +// The simplest possible memory planner that just lays out all buffers at +// increasing offsets without trying to reuse memory. +class LinearMemoryPlanner : public MicroMemoryPlanner { + public: + LinearMemoryPlanner(); + ~LinearMemoryPlanner() override; + + TfLiteStatus AddBuffer(int size, int first_time_used, + int last_time_used) override; + + size_t GetMaximumMemorySize() override; + int GetBufferCount() override; + TfLiteStatus GetOffsetForBuffer(int buffer_index, int* offset) override; + + private: + static constexpr int kMaxBufferCount = 1024; + size_t buffer_offsets_[kMaxBufferCount]; + int current_buffer_count_; + size_t next_free_offset_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_LINEAR_MEMORY_PLANNER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/memory_plan_struct.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/memory_plan_struct.h new file mode 100644 index 000000000..c8c431cce --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/memory_plan_struct.h @@ -0,0 +1,73 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_MEMORY_PLAN_STRUCT_H_ +#define TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_MEMORY_PLAN_STRUCT_H_ + +#include +#include + +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +// This is an experimental feature and subjected to change. +// More description is available at +// tensorflow/lite/micro/docs/offline_memory_plan.md. + +// Describes a buffer's layout inside an arena. This struct should be kept as +// small as possible for memory footprint sensitive applications and should use +// only primitive fields, making it easy to adjust offline. +struct BufferDescriptor { + // Starting offset inside an arena for this buffer. + // Offset is the minimum information needed for the buffer. The user knows + // the model and the size of each buffer in order to lay out a valid buffer + // plan. + int32_t offset; +}; + +// A structure describing the lay out of buffers inside an arena. +struct BufferPlan { + // Number of buffers described in this plan. + int32_t buffer_count; + + // Each element describes one buffer. + // Buffer index is implicit by the order of AddBuffer() call. + // Specifically, indices of activation tensors are 0 … N-1 where N is the + // number of activation tensors. + // The rest are based on the order of OP requests. + // + // This is a flexible array member and should ideally be + // arena_entries[]; However, in order to support a variety + // of compilers (and without needing to add ifdef's), we + // are implementing the flexible array member with an array of + // length 1 as the last member of the struct. When the size of a BufferPlan + // is needed, use the provided SizeOfBufferPlan(buffer_count) that + // accounts for this implemenatation caveat. + BufferDescriptor buffer_plan_entries[1]; +}; + +// Returns size of a BufferPlan given a buffer count. This size is compile time +// known if buffer_count is a compile time constant. +constexpr size_t SizeOfBufferPlan(int32_t buffer_count) { + // Minus 1 because a BufferPlan struct have a BufferDescriptor already. + // Max to provide a lower bound for the corner case of buffer_count = 0. + return sizeof(BufferPlan) + + sizeof(BufferDescriptor) * Max(buffer_count - 1, 0); +} + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_MEMORY_PLAN_STRUCT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/micro_memory_planner.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/micro_memory_planner.h new file mode 100644 index 000000000..0bfe693a3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/micro_memory_planner.h @@ -0,0 +1,91 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_MEMORY_PLANNER_MEMORY_PLANNER_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_MEMORY_PLANNER_MEMORY_PLANNER_H_ + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// Interface class for planning the layout of memory buffers during the +// execution of a graph. +// It's designed to be used by a client that iterates in any order through the +// buffers it wants to lay out, and then calls the getter functions for +// information about the calculated layout. For example: +// +// SomeMemoryPlanner planner; +// planner.AddBuffer(100, 0, 1); // Buffer 0 +// planner.AddBuffer(50, 2, 3); // Buffer 1 +// planner.AddBuffer(50, 2, 3); // Buffer 2 +// +// int offset0; +// TF_EXPECT_OK(planner.GetOffsetForBuffer(0, &offset0)); +// int offset1; +// TF_EXPECT_OK(planner.GetOffsetForBuffer(1, &offset1)); +// int offset2; +// TF_EXPECT_OK(planner.GetOffsetForBuffer(2, &offset2)); +// const int arena_size_needed = planner.GetMaximumMemorySize(); +// +// The goal is for applications to be able to experiment with different layout +// strategies without changing their client code, by swapping out classes that +// implement this interface.= +class MicroMemoryPlanner { + public: + MicroMemoryPlanner() {} + virtual ~MicroMemoryPlanner() {} + + // Pass information about a buffer's size and lifetime to the layout + // algorithm. The order this is called implicitly assigns an index to the + // result, so the buffer information that's passed into the N-th call of + // this method will be used as the buffer_index argument to + // GetOffsetForBuffer(). + virtual TfLiteStatus AddBuffer(int size, int first_time_used, + int last_time_used) = 0; + + // Record details of an offline planned buffer offset we want to place. + // offline_offset is the buffer offset from the start of the arena. + // This is to support offline memory planning from the flatbuffer metadata. + // By default, it returns an error. + virtual TfLiteStatus AddBuffer(int size, int first_time_used, + int last_time_used, int offline_offset) { + return kTfLiteError; + } + + // The largest contiguous block of memory that's needed to hold the layout. + virtual size_t GetMaximumMemorySize() = 0; + // How many buffers have been added to the planner. + virtual int GetBufferCount() = 0; + // Calculated layout offset for the N-th buffer added to the planner. + virtual TfLiteStatus GetOffsetForBuffer(int buffer_index, int* offset) = 0; + + // Provides the scratch buffer in case that the memory planner needs it. + // The lifetime of scratch buffers lifetime lasts until the static memory plan + // is committed. + // The default implementation is for the memory planner that does not need + // scratch buffer and simply returns ok. + virtual TfLiteStatus Init(unsigned char* scratch_buffer, + int scratch_buffer_size) { + return kTfLiteOk; + } + + virtual void PrintMemoryPlan() { + // Default does nothing. + } +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_MEMORY_PLANNER_MEMORY_PLANNER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.cpp new file mode 100644 index 000000000..9bcb80c12 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.cpp @@ -0,0 +1,66 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.h" + +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +NonPersistentMemoryPlannerShim::NonPersistentMemoryPlannerShim( + const BufferPlan* buffer_plan) + : buffer_plan_(buffer_plan), buffer_request_count_(0) {} + +NonPersistentMemoryPlannerShim::~NonPersistentMemoryPlannerShim() {} + +TfLiteStatus NonPersistentMemoryPlannerShim::AddBuffer(int size, + int first_time_used, + int last_time_used) { + buffer_request_count_++; + if (buffer_request_count_ > buffer_plan_->buffer_count) { + MicroPrintf( + "Attempting to add buffer %d, but only %d buffers in given buffer " + "plan.", + buffer_request_count_, buffer_plan_->buffer_count); + return kTfLiteError; + } + return kTfLiteOk; +} + +size_t NonPersistentMemoryPlannerShim::GetMaximumMemorySize() { + // Simply return 0 to let the framework accept this memory plan + // because the client ensure validity of the memory plan. + return 0; +} + +// How many buffers are in the given memory plan. +int NonPersistentMemoryPlannerShim::GetBufferCount() { + return buffer_plan_->buffer_count; +} + +TfLiteStatus NonPersistentMemoryPlannerShim::GetOffsetForBuffer( + int buffer_request_index, int* offset) { + if (buffer_request_index >= buffer_plan_->buffer_count) { + MicroPrintf( + "Attempting to get offset for buffer %d, but only %d buffers in given " + "buffer plan.", + buffer_request_index, buffer_plan_->buffer_count); + return kTfLiteError; + } + *offset = buffer_plan_->buffer_plan_entries[buffer_request_index].offset; + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.h new file mode 100644 index 000000000..8f9bb26a3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/memory_planner/non_persistent_buffer_planner_shim.h @@ -0,0 +1,129 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_NON_PERSISTENT_MEMORY_PLANNER_SHIM_H__ +#define TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_NON_PERSISTENT_MEMORY_PLANNER_SHIM_H__ + +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/memory_planner/memory_plan_struct.h" +#include "tensorflow/lite/micro/memory_planner/micro_memory_planner.h" + +namespace tflite { + +/* This is an experimental feature and subjected to change. + * +The NonPersistentMemoryPlannerShim enables TFLM to work with an external tooling +that can plan the offset of each non persistent buffer for the Model within the +TFLM arena. + +If the NonPersistentMemoryPlannerShim is used, then the final binary does not +have any of the symbols associated with the GreedyMemoryPlanner which results in +a reduced memory footprint. + +Additionally, the offline planning of the non-persistent buffers can be used to +have a more efficient utilization compared to the GreedyMemoryPlanner. + +For example, consider the following hypothetical model: + +A1(400) A2(401) +──┬─────────┐ ┌─────────── + │ │ │ + │ │ │ + │ ▼ ▼ + │ ┌────────┐ + │ │ OP1 │ + │ └───┬────┘ A4(201) + │ A3(10) │ │ + │ │ │ + │ │ │ + │ ┌───┴────┐ │ + │ │ OP2 │◄────────┤ + │ └───┬────┘ │ + │ A5(11) │ A6(202) │ + │ │ │ │ + │ ▼ │ │ + │ ┌────────┐ │ │ + │ │ OP3 │◄─┘ │ + │ └───┬────┘ │ + │ │ A8(200) │ + │ A7(12) │ │ │ + │ │ │ │ + │ ┌───┴────┐◄──┘ │ + └──────►│ OP4 │ │ + └───┬────┘◄────────┘ + │ + A9(13) │ + ▼ + +The GreedyMemoryPlanner will give the following memory layout that requires 1012 +bytes of scratch arena size: + +┌─────────────────────────────────────────┬──────────────────────────┬────────┬───────┐ +│ A2(401) │ A1(400) │ A4(201)│ +A3(10)│ +└─────────────────────────────────────────┴──────────────────────────┴────────┴───────┘ + +┌───────────┬──────┬──────┐ +│ A6(202) │A5(11)│A7(12)│ +└───────────┴──────┴──────┘ + +┌──────────┬───────┐ +│ A8(200) │A9(13) │ +└──────────┴───────┘ + +But a more efficient offline memory plan that requires only 826 bytes of scratch +arena size can be + +┌──────────────────────────────────────┬─────────────────────────────┬───────┬──────┐ +│ A1(400) │ A2(401) │ +A3(10)│A5(11)│ +└──────────────────────────────────────┴─────────────────────────────┴───────┴──────┘ + + ┌────────────────┬────────────┬────────┬───────┐ + │A4(201) │ A8(200) │A9(13) +│A7(12) │ └────────────────┴────────────┴────────┴───────┘ + + ┌─────────────┐ + │ A6(202) │ + └─────────────┘ + +*/ +class NonPersistentMemoryPlannerShim : public MicroMemoryPlanner { + public: + // Does not take ownership of buffer_plan, which must refer to a valid + // BufferPlan that outlives this object. + explicit NonPersistentMemoryPlannerShim(const BufferPlan* buffer_plan); + ~NonPersistentMemoryPlannerShim() override; + + TfLiteStatus GetOffsetForBuffer(int buffer_request_index, + int* offset) override; + + TfLiteStatus AddBuffer(int size, int first_time_used, + int last_time_used) override; + size_t GetMaximumMemorySize() override; + int GetBufferCount() override; + + private: + const BufferPlan* buffer_plan_; // not owned, can't be null + + // The number of buffers requested so far. Used for error checking. + int buffer_request_count_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MEMORY_PLANNER_NON_PERSISTENT_MEMORY_PLANNER_SHIM_H__ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocation_info.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocation_info.cpp new file mode 100644 index 000000000..8686453b3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocation_info.cpp @@ -0,0 +1,353 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_allocation_info.h" + +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +namespace { +constexpr char kOfflineMemAllocMetadata[] = "OfflineMemoryAllocation"; +constexpr int kUninitializedLifetime = -1; +} // namespace + +// Mark the given Allocation info as first created at the specified allocation +// scope count. Only the first creation must be recorded since the allocation +// scope count monotonically increases throughout the lifetime marking process. +void AllocationInfoBuilder::UpdateFirstCreated(AllocationInfo* current, + int allocation_scope_count) { + TFLITE_DCHECK(current->first_created <= allocation_scope_count); + if (current->first_created == kUninitializedLifetime) { + current->first_created = allocation_scope_count; + } +} + +// Mark the given AllocationInfo as last used at the specified allocation scope +// count. Update the last used marker every time, since the allocation scope +// count monotonically increases through the lifetime marking process. +void AllocationInfoBuilder::UpdateLastUsed(AllocationInfo* current, + int allocation_scope_count) { + TFLITE_DCHECK(current->last_used <= allocation_scope_count); + current->last_used = allocation_scope_count; +} + +TfLiteStatus AllocationInfoBuilder::MarkSubgraphLifetimesIfNecessary( + const Operator* op, internal::ScratchBufferRequest* scratch_buffer_requests, + ScratchBufferHandle* scratch_buffer_handles, + SubgraphAllocations* allocations) { + int first_subgraph_index = -1; + int second_subgraph_index = -1; + const OperatorCode* opcode = + model_->operator_codes()->Get(op->opcode_index()); + switch (opcode->builtin_code()) { + case BuiltinOperator_IF: { + first_subgraph_index = + op->builtin_options_as_IfOptions()->then_subgraph_index(); + second_subgraph_index = + op->builtin_options_as_IfOptions()->else_subgraph_index(); + break; + } + case BuiltinOperator_CALL_ONCE: { + first_subgraph_index = + op->builtin_options_as_CallOnceOptions()->init_subgraph_index(); + break; + } + case BuiltinOperator_WHILE: { + first_subgraph_index = + op->builtin_options_as_WhileOptions()->cond_subgraph_index(); + second_subgraph_index = + op->builtin_options_as_WhileOptions()->body_subgraph_index(); + break; + } + default: { + break; + } + } + if (first_subgraph_index != -1) { + // Enter a new allocation scope for each subgraph. + allocation_scope_count_++; + TF_LITE_ENSURE_STATUS( + MarkAllocationLifetimes(first_subgraph_index, scratch_buffer_requests, + scratch_buffer_handles, allocations)); + } + if (second_subgraph_index != -1) { + // Enter a new allocation scope for each subgraph. + allocation_scope_count_++; + TF_LITE_ENSURE_STATUS( + MarkAllocationLifetimes(second_subgraph_index, scratch_buffer_requests, + scratch_buffer_handles, allocations)); + } + return kTfLiteOk; +} + +TfLiteStatus AllocationInfoBuilder::CreateAllocationInfo( + int scratch_buffer_request_count) { + size_t subgraph_offsets_length = model_->subgraphs()->size() * sizeof(size_t); + info_.subgraph_offsets = + reinterpret_cast(non_persistent_allocator_->AllocateTemp( + subgraph_offsets_length, alignof(size_t))); + if (info_.subgraph_offsets == nullptr) { + MicroPrintf( + "Failed to allocate memory for memory planning, %d bytes required", + subgraph_offsets_length); + return kTfLiteError; + } + size_t tensor_count = 0; + for (size_t subgraph_idx = 0; subgraph_idx < model_->subgraphs()->size(); + subgraph_idx++) { + // Add all tensors in each subgraph to the AllocationInfo array. Even weight + // tensors are added but marked with needs_allocating = false. Including all + // tensors in the graph here simplifies logic. + info_.subgraph_offsets[subgraph_idx] = tensor_count; + tensor_count += model_->subgraphs()->Get(subgraph_idx)->tensors()->size(); + } + info_.tensor_count = tensor_count; + + // Scratch buffer allocations follow tensor allocations, so the scratch offset + // is equal to the number of tensor allocations. + info_.scratch_offset = tensor_count; + info_.allocation_info_count = tensor_count + scratch_buffer_request_count; + info_.scratch_buffer_count = scratch_buffer_request_count; + size_t bytes = sizeof(AllocationInfo) * info_.allocation_info_count; + + // Allocate an array of AllocationInfo structs from the temp section. This + // struct will be used by AllocationInfoBuilder to find buffer usage. + info_.allocation_info = reinterpret_cast( + non_persistent_allocator_->AllocateTemp(bytes, alignof(AllocationInfo))); + if (info_.allocation_info == nullptr) { + MicroPrintf( + "Failed to allocate memory for memory planning, %d bytes required", + bytes); + return kTfLiteError; + } + return kTfLiteOk; +} + +TfLiteStatus AllocationInfoBuilder::FreeAllocationInfo() { + non_persistent_allocator_->DeallocateTemp( + reinterpret_cast(info_.allocation_info)); + non_persistent_allocator_->DeallocateTemp( + reinterpret_cast(info_.subgraph_offsets)); + return kTfLiteOk; +} + +TfLiteStatus AllocationInfoBuilder::ValidateSubgraph( + const SubGraph* subgraph, TfLiteEvalTensor* eval_tensors) { + uint32_t operators_size = NumSubgraphOperators(subgraph); + + for (uint32_t i = 0; i < operators_size; i++) { + const auto op = subgraph->operators()->Get(i); + for (size_t n = 0; + op->intermediates() != nullptr && n < op->intermediates()->size(); + n++) { + const int tensor_index = op->intermediates()->Get(n); + size_t tensor_size = -1; + TF_LITE_ENSURE_STATUS(TfLiteEvalTensorByteLength( + &eval_tensors[tensor_index], &tensor_size)); + if (tensor_size != 0) { + MicroPrintf( + "Does not support intermediate tensor with non-zero size: %d", + tensor_size); + return kTfLiteError; + } + } + } + return kTfLiteOk; +} + +TfLiteStatus AllocationInfoBuilder::InitializeAllocationInfo( + const int32_t* offline_offsets, SubgraphAllocations* allocations) { + AllocationInfo* allocation_info = info_.allocation_info; + // Initialize allocation info for every tensor in every subgraph. + for (size_t subgraph_idx = 0; subgraph_idx < model_->subgraphs()->size(); + subgraph_idx++) { + const SubGraph* subgraph = model_->subgraphs()->Get(subgraph_idx); + TfLiteEvalTensor* eval_tensors = allocations[subgraph_idx].tensors; + AllocationInfo* subgraph_allocation_info = + &allocation_info[info_.subgraph_offsets[subgraph_idx]]; + + // Ensure constraints are met. + TF_LITE_ENSURE_STATUS(ValidateSubgraph(subgraph, eval_tensors)); + + for (size_t i = 0; i < subgraph->tensors()->size(); ++i) { + AllocationInfo* current = &subgraph_allocation_info[i]; + current->output_ptr = &(eval_tensors[i].data.data); + + TF_LITE_ENSURE_STATUS( + TfLiteEvalTensorByteLength(&eval_tensors[i], ¤t->bytes)); + + current->first_created = kUninitializedLifetime; + current->last_used = kUninitializedLifetime; + current->needs_allocating = + (eval_tensors[i].data.data == nullptr) && + (!subgraph->tensors()->Get(i)->is_variable()) && + (current->bytes != 0); + if (offline_offsets) { + current->offline_offset = offline_offsets[i]; + } else { + current->offline_offset = kOnlinePlannedBuffer; + } + } + } + // Initialize allocation info for every scratch buffer. + AllocationInfo* scratch_allocation_info = + &allocation_info[info_.scratch_offset]; + for (size_t i = 0; i < info_.scratch_buffer_count; i++) { + AllocationInfo* current = &scratch_allocation_info[i]; + current->first_created = kUninitializedLifetime; + current->last_used = kUninitializedLifetime; + current->needs_allocating = true; + current->offline_offset = kOnlinePlannedBuffer; + } + return kTfLiteOk; +} + +TfLiteStatus AllocationInfoBuilder::MarkAllocationLifetimes( + int subgraph_idx, internal::ScratchBufferRequest* scratch_buffer_requests, + ScratchBufferHandle* scratch_buffer_handles, + SubgraphAllocations* allocations) { + const SubGraph* subgraph = model_->subgraphs()->Get(subgraph_idx); + + AllocationInfo* allocation_info = info_.allocation_info; + // Each subgraph's tensor allocations are in a contiguous block starting at + // subgraph_offsets_[subgraph index] with one entry per tensor. + AllocationInfo* subgraph_allocation_info = + &allocation_info[info_.subgraph_offsets[subgraph_idx]]; + + uint32_t operators_size = NumSubgraphOperators(subgraph); + // Mark all inputs as created at the start of the subgraph invocation. + for (size_t i = 0; + subgraph->inputs() != nullptr && i < subgraph->inputs()->size(); ++i) { + const int tensor_index = subgraph->inputs()->Get(i); + AllocationInfo* current = &subgraph_allocation_info[tensor_index]; + UpdateFirstCreated(current, allocation_scope_count_); + } + + for (uint32_t i = 0; i < operators_size; i++) { + // Each operator has a new allocation scope. + allocation_scope_count_++; + const auto* op = subgraph->operators()->Get(i); + // Figure out when the first creation and use of each tensor is. + for (size_t n = 0; op->outputs() != nullptr && n < op->outputs()->size(); + ++n) { + const int tensor_index = op->outputs()->Get(n); + AllocationInfo* current = &subgraph_allocation_info[tensor_index]; + UpdateFirstCreated(current, allocation_scope_count_); + } + + // Keep track of scope count before any subgraphs, so that scratch buffers' + // lifetime within a control flow op properly overlaps with all subgraphs. + int start_allocation_scope_count = allocation_scope_count_; + + // Control flow operators can invoke subgraphs. Plan these subgraphs + // before continuing on to the rest of the graph. + MarkSubgraphLifetimesIfNecessary(op, scratch_buffer_requests, + scratch_buffer_handles, allocations); + + // Figure out when the last use of each tensor is. + for (size_t n = 0; op->inputs() != nullptr && n < op->inputs()->size(); + ++n) { + const int tensor_index = op->inputs()->Get(n); + // Optional bias tensors can have an index of -1 when they are omitted. + if (tensor_index >= 0) { + AllocationInfo* current = &subgraph_allocation_info[tensor_index]; + // No need to update creation since it is either marked by the subgraph + // or producer op, or it is not part of the memory plan (weight, bias + // tensor). + UpdateLastUsed(current, allocation_scope_count_); + } + } + for (size_t n = 0; op->outputs() != nullptr && n < op->outputs()->size(); + ++n) { + const int tensor_index = op->outputs()->Get(n); + AllocationInfo* current = &subgraph_allocation_info[tensor_index]; + UpdateLastUsed(current, allocation_scope_count_); + } + + // Mark thse lifetime of scratch buffers belonging to the current node. This + // operation is O(N * M) where N is the total number of visited nodes and M + // is the total number of scratch buffers. + // TODO(b/217794030): Optimize this memory planning code. + AllocationInfo* scratch_allocation_info = + &allocation_info[info_.scratch_offset]; + for (size_t scratch_idx = 0; scratch_idx < info_.scratch_buffer_count; + scratch_idx++) { + internal::ScratchBufferRequest request = + scratch_buffer_requests[scratch_idx]; + AllocationInfo* current = &scratch_allocation_info[scratch_idx]; + if (request.node_idx == static_cast(i) && + request.subgraph_idx == static_cast(subgraph_idx)) { + ScratchBufferHandle* current_handle = + &(scratch_buffer_handles[scratch_idx]); + current->output_ptr = reinterpret_cast(¤t_handle->data); + current->bytes = request.bytes; + UpdateFirstCreated(current, start_allocation_scope_count); + UpdateLastUsed(current, allocation_scope_count_); + } + } + } + + // Mark all outputs as persistent to the end of the subgraph invocation. + for (size_t i = 0; + subgraph->outputs() != nullptr && i < subgraph->outputs()->size(); ++i) { + const int tensor_index = subgraph->outputs()->Get(i); + AllocationInfo* current = &subgraph_allocation_info[tensor_index]; + UpdateLastUsed(current, allocation_scope_count_); + } + return kTfLiteOk; +} + +// Get offline tensors allocation plan. See +// micro/docs/memory_management.md for more info. +TfLiteStatus AllocationInfoBuilder::GetOfflinePlannedOffsets( + const int32_t** offline_planner_offsets) { + if (model_->metadata()) { + for (size_t i = 0; i < model_->metadata()->size(); ++i) { + auto metadata = model_->metadata()->Get(i); + const size_t metadata_name_size = (size_t)metadata->name()->size(); + + if ((strncmp(metadata->name()->c_str(), kOfflineMemAllocMetadata, + std::min(metadata_name_size, + strlen(kOfflineMemAllocMetadata))) == 0) && + metadata_name_size == strlen(kOfflineMemAllocMetadata)) { + const flatbuffers::Vector>* buffers = + model_->buffers(); + auto* buffer = (*buffers)[metadata->buffer()]; + auto* array = buffer->data(); + const uint32_t* metadata_buffer = + reinterpret_cast(array->data()); + const size_t nbr_tensors = static_cast(metadata_buffer[2]); + *offline_planner_offsets = + reinterpret_cast(&metadata_buffer[3]); + + if (info_.tensor_count != nbr_tensors) { + MicroPrintf( + "Nbr of offline buffer offsets (%d) in metadata " + "not equal nbr tensors (%d)\n", + nbr_tensors, info_.tensor_count); + return kTfLiteError; + } + } + } + } + return kTfLiteOk; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocation_info.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocation_info.h new file mode 100644 index 000000000..946d9f5f6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocation_info.h @@ -0,0 +1,139 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_ALLOCATION_INFO_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_ALLOCATION_INFO_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/flatbuffer_conversions.h" +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// Used to hold information used during allocation calculations. +struct AllocationInfo { + size_t bytes; + void** output_ptr; + int first_created; + int last_used; + int32_t offline_offset; + bool needs_allocating; +}; + +// Used to hold the allocation info list and related metadata for the entire +// graph (including subgraphs). Since all subgraphs are planned together, the +// allocation info list contains allocations for all subgraphs. Track the offset +// into this list for each subgraph then reserve space to track all allocations. +// +// The AllocationInfo list is a contiguous list of allocations across all +// subgraphs and scratch buffers. Each element here is marked as +// st. The following is a possible +// AllocationInfo list: +// [s0t0, s0t1, s1t0, s2t1, s1t2, s3t0, s3t1, scratch0, scratch1, scratch2] +// +// For this example, the subgraph offsets would be [0, 2, 5] and the scratch +// offset would be 7. +struct GraphAllocationInfo { + AllocationInfo* allocation_info; + size_t allocation_info_count; + size_t* subgraph_offsets; + size_t scratch_offset; + size_t tensor_count; + size_t scratch_buffer_count; +}; + +// A helper class to construct AllocationInfo array. This array contains the +// lifetime of tensors / scratch_buffer and will be used to calculate the memory +// plan. Methods need to be called in order from `Create`, Init`, `Add*`, to +// `Finish`. +class AllocationInfoBuilder { + public: + AllocationInfoBuilder(const Model* model, + INonPersistentBufferAllocator* non_persistent_allocator) + : model_(model), non_persistent_allocator_(non_persistent_allocator) {} + + // Check if model contains offline planned buffer offsets. + // - If there's no metadata available, offline_planner_offsets is not set + // - If there's metadata available, offline_planner_offsets will point to the + // first offset in the metadata buffer list. + TfLiteStatus GetOfflinePlannedOffsets( + const int32_t** offline_planner_offsets); + + // Allocate memory for the allocation info array as well as offsets into that + // array for each subgraph. + TfLiteStatus CreateAllocationInfo(int scratch_buffer_request_count); + + // Release memory used for the allocation info array. + TfLiteStatus FreeAllocationInfo(); + + // Initialize AllocationInfo for all tensors and scratch buffers in the graph. + TfLiteStatus InitializeAllocationInfo(const int32_t* offline_offsets, + SubgraphAllocations* allocations); + + // Mark the scope of each tensor and scratch buffer across the graph. Enter + // all possible subgraphs invoked by each control flow operator. This method + // marks the maximum lifetime of each buffer so that tensors are correctly + // planned for all valid invocation flows. + TfLiteStatus MarkAllocationLifetimes( + int subgraph_idx, internal::ScratchBufferRequest* scratch_buffer_request, + ScratchBufferHandle* scratch_buffer_handles, + SubgraphAllocations* allocations); + + // Identify control flow operators and recursively mark all subgraphs which + // that operator can invoke. The lifetime of all tensors within a subgraph + // can only be extended. The order of subgraph invocation does not matter + // since subgraphs within the same control flow operator are executed + // within their own allocation scope (planned buffers in a subgraph cannot + // persist beyond the end of that subgraph's invocation). + TfLiteStatus MarkSubgraphLifetimesIfNecessary( + const Operator* op, + internal::ScratchBufferRequest* scratch_buffer_requests, + ScratchBufferHandle* scratch_buffer_handles, + SubgraphAllocations* allocations); + + // Returns the number of allocations. + int AllocationCount() const { return info_.allocation_info_count; } + + // Returns a pointer to the built AllocationInfo array. + AllocationInfo* Finish() const { return info_.allocation_info; } + + private: + // Mark the given Allocation info as first created at the specified allocation + // scope count. Only the first creation must be recorded since the allocation + // scope count monotonically increases throughout the lifetime marking + // process. + void UpdateFirstCreated(AllocationInfo* current, int allocation_scope_count); + + // Mark the given AllocationInfo as last used at the specified allocation + // scope + // count. Update the last used marker every time, since the allocation scope + // count monotonically increases through the lifetime marking process. + void UpdateLastUsed(AllocationInfo* current, int allocation_scope_count); + + // Validate if a subgraph satisfies assumptions. + TfLiteStatus ValidateSubgraph(const SubGraph* subgraph, + TfLiteEvalTensor* eval_tensors); + + const tflite::Model* model_ = nullptr; + INonPersistentBufferAllocator* non_persistent_allocator_ = nullptr; + GraphAllocationInfo info_; + int allocation_scope_count_ = 0; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_ALLOCATION_INFO_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocator.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocator.cpp new file mode 100644 index 000000000..06cef9d79 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocator.cpp @@ -0,0 +1,940 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_allocator.h" + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/flatbuffer_conversions.h" +#include "tensorflow/lite/core/api/op_resolver.h" +#include "tensorflow/lite/core/api/tensor_utils.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/arena_allocator/non_persistent_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/arena_allocator/persistent_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h" +#include "tensorflow/lite/micro/memory_planner/micro_memory_planner.h" +#include "tensorflow/lite/micro/micro_allocation_info.h" +#include "tensorflow/lite/micro/micro_arena_constants.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include "tensorflow/lite/schema/schema_utils.h" + +namespace tflite { + +namespace { + +// Maximum number of scratch buffer requests per operator. Operator kernels that +// request more than this value will receive an exception. +constexpr size_t kMaxScratchBuffersPerOp = 12; + +// Sentinel value used as a placeholder to mark a ScratchBufferRequest request +// needs a node id assignment. +constexpr int kUnassignedScratchBufferRequestIndex = -1; + +const TfLiteIntArray kZeroLengthIntArray = {}; + +class MicroBuiltinDataAllocator : public BuiltinDataAllocator { + public: + explicit MicroBuiltinDataAllocator( + IPersistentBufferAllocator* persistent_allocator) + : persistent_allocator_(persistent_allocator) {} + + void* Allocate(size_t size, size_t alignment_hint) override { + return persistent_allocator_->AllocatePersistentBuffer(size, + alignment_hint); + } + void Deallocate(void* data) override { + // Do not deallocate, builtin data needs to be available for the life time + // of the model. + } + + TF_LITE_REMOVE_VIRTUAL_DELETE + + private: + IPersistentBufferAllocator* persistent_allocator_; +}; + +TfLiteStatus CreatePlan(MicroMemoryPlanner* planner, + const AllocationInfo* allocation_info, + size_t allocation_info_size) { + // Add the tensors to our allocation plan. + for (size_t i = 0; i < allocation_info_size; ++i) { + const AllocationInfo* current = &allocation_info[i]; + if (current->needs_allocating) { + size_t aligned_bytes_required = + AlignSizeUp(current->bytes, MicroArenaBufferAlignment()); + if (current->offline_offset == kOnlinePlannedBuffer) { + TF_LITE_ENSURE_STATUS(planner->AddBuffer(aligned_bytes_required, + current->first_created, + current->last_used)); + } else { + TF_LITE_ENSURE_STATUS( + planner->AddBuffer(aligned_bytes_required, current->first_created, + current->last_used, current->offline_offset)); + } + } + } + return kTfLiteOk; +} + +TfLiteStatus CommitPlan(MicroMemoryPlanner* planner, uint8_t* starting_point, + const AllocationInfo* allocation_info, + size_t allocation_info_size) { + // Figure out the actual memory addresses for each buffer, based on the plan. + int planner_index = 0; + for (size_t i = 0; i < allocation_info_size; ++i) { + const AllocationInfo* current = &allocation_info[i]; + if (current->needs_allocating) { + int offset = -1; + TF_LITE_ENSURE_STATUS( + planner->GetOffsetForBuffer(planner_index, &offset)); + *current->output_ptr = reinterpret_cast(starting_point + offset); + ++planner_index; + } + } + return kTfLiteOk; +} + +IPersistentBufferAllocator* CreatePersistentArenaAllocator(uint8_t* buffer_head, + size_t buffer_size) { + // Align the actually used area by the tail because persistent buffer grows + // from the bottom to top. + uint8_t* aligned_buffer_tail = + AlignPointerDown(buffer_head + buffer_size, MicroArenaBufferAlignment()); + size_t aligned_buffer_size = aligned_buffer_tail - buffer_head; + PersistentArenaBufferAllocator tmp = + PersistentArenaBufferAllocator(buffer_head, aligned_buffer_size); + + // Allocate enough bytes from the buffer to create a + // SingleArenaBufferAllocator. The new instance will use the current adjusted + // tail buffer from the tmp allocator instance. + uint8_t* allocator_buffer = + tmp.AllocatePersistentBuffer(sizeof(PersistentArenaBufferAllocator), + alignof(PersistentArenaBufferAllocator)); + // Use the default copy constructor to populate internal states. + return new (allocator_buffer) PersistentArenaBufferAllocator(tmp); +} + +// NonPersistentBufferAllocator instance is created in the persistent buffer +// because it has to be persistent to keep track of the non-persistent buffer +// information. +INonPersistentBufferAllocator* CreateNonPersistentArenaAllocator( + uint8_t* buffer_head, size_t buffer_size, + IPersistentBufferAllocator* persistent_buffer_allocator) { + uint8_t* allocator_buffer = + persistent_buffer_allocator->AllocatePersistentBuffer( + sizeof(NonPersistentArenaBufferAllocator), + alignof(NonPersistentArenaBufferAllocator)); + // Align the actually used area by the head because persistent buffer grows + // from the head to bottom. + uint8_t* aligned_buffer_head = + AlignPointerUp(buffer_head, MicroArenaBufferAlignment()); + size_t aligned_buffer_size = buffer_head + buffer_size - aligned_buffer_head; + + INonPersistentBufferAllocator* non_persistent_buffer_allocator = + new (allocator_buffer) NonPersistentArenaBufferAllocator( + aligned_buffer_head, aligned_buffer_size); + return non_persistent_buffer_allocator; +} + +} // namespace + +namespace internal { + +// Returns a pointer to any buffer associated with the flatbuffer tensor. Can +// return nullptr if no buffer is found. +void* GetFlatbufferTensorBuffer( + const tflite::Tensor& flatbuffer_tensor, + const flatbuffers::Vector>* buffers) { + // We need to figure out where the actual contents of this tensor are stored + // in memory. We'll check to see if there's a serialized buffer (pretty much + // the same as a constant op in TensorFlow) associated with this tensor first, + // and if there is update the runtime structure to point to its location in + // memory. + // First see if there's any buffer information in the serialized tensor. + // TODO(b/170379532): Add better unit tests to validate flatbuffer values. + void* out_buffer = nullptr; + if (auto* buffer = (*buffers)[flatbuffer_tensor.buffer()]) { + // If we've found a buffer, does it have any data? + if (auto* array = buffer->data()) { + // If it has any data, is the data size larger than zero? + if (array->size()) { + // We've found a buffer with valid data, so update the runtime tensor + // data structure to point to it. + out_buffer = const_cast(static_cast(array->data())); + } + } + // TODO(petewarden): It's not clear in what circumstances we could have a + // buffer in the serialized tensor, but it doesn't have any data in it. Is + // that a validly-generated file, and if so what does it mean, or is it an + // error condition? It would be good to tighten up the specification to make + // it less ambiguous. + } + return out_buffer; +} + +TfLiteStatus InitializeTfLiteTensorFromFlatbuffer( + IPersistentBufferAllocator* persistent_buffer_allocator, + INonPersistentBufferAllocator* non_persistent_buffer_allocator, + bool allocate_temp, const tflite::Tensor& flatbuffer_tensor, + const flatbuffers::Vector>* buffers, + TfLiteTensor* result) { + TFLITE_DCHECK(result != nullptr); + + *result = {}; + // Make sure the serialized type is one we know how to deal with, and convert + // it from a flatbuffer enum into a constant used by the kernel C API. + TF_LITE_ENSURE_STATUS(ConvertTensorType(flatbuffer_tensor.type(), + &result->type, + tflite::GetMicroErrorReporter())); + // Make sure we remember if the serialized tensor is designated as a variable. + result->is_variable = flatbuffer_tensor.is_variable(); + + result->data.data = GetFlatbufferTensorBuffer(flatbuffer_tensor, buffers); + + // TODO(petewarden): Some of these paths aren't getting enough testing + // coverage, so we should figure out some tests that exercise them. + if (result->data.data == nullptr) { + // The tensor contents haven't been set from a serialized buffer, so + // make a note that they will be allocated from memory. The actual + // allocation won't happen until later. + result->allocation_type = kTfLiteArenaRw; + } else { + // We set the data from a serialized buffer, so record tha. + result->allocation_type = kTfLiteMmapRo; + } + + // Figure out what the size in bytes of the buffer is and store it. + size_t type_size; + TF_LITE_ENSURE_STATUS( + BytesRequiredForTensor(flatbuffer_tensor, &result->bytes, &type_size)); + + if (flatbuffer_tensor.shape() == nullptr) { + // flatbuffer_tensor.shape() can return a nullptr in the case of a scalar + // tensor. + // TODO(b/188459715): figure out why const_cast is required here. + result->dims = const_cast(&kZeroLengthIntArray); + } else { + // TFLM doesn't allow reshaping the tensor which requires dynamic memory + // allocation so it is safe to drop the const qualifier. In the future, if + // we really want to update the tensor shape, we can always pass in a new + // TfLiteIntArray - especially we have to do so if the dimension is + result->dims = FlatBufferVectorToTfLiteTypeArray(flatbuffer_tensor.shape()); + } + + // Copy the quantization information from the serialized data. + const auto* src_quantization = flatbuffer_tensor.quantization(); + if (src_quantization && src_quantization->scale() && + (src_quantization->scale()->size() > 0) && + src_quantization->zero_point() && + (src_quantization->zero_point()->size() > 0)) { + // Always populate the TfLiteTensor.params field, even if there are + // per-channel quantization parameters. + result->params.scale = src_quantization->scale()->Get(0); + // Note that the zero_point field in the FlatBuffers schema is a 64-bit + // integer, but the zero_point field in the TfLiteQuantizationParams struct + // is a 32-bit integer. + result->params.zero_point = + static_cast(src_quantization->zero_point()->Get(0)); + + // Populate per-channel quantization params. + int channels = src_quantization->scale()->size(); + TfLiteAffineQuantization* quantization = + allocate_temp + ? reinterpret_cast( + non_persistent_buffer_allocator->AllocateTemp( + sizeof(TfLiteAffineQuantization), + alignof(TfLiteAffineQuantization))) + : reinterpret_cast( + persistent_buffer_allocator->AllocatePersistentBuffer( + sizeof(TfLiteAffineQuantization), + alignof(TfLiteAffineQuantization))); + if (quantization == nullptr) { + MicroPrintf("Unable to allocate TfLiteAffineQuantization.\n"); + return kTfLiteError; + } + + // TODO(b/153688719): Reduce tail allocation by using a global zero-point + // buffer. This value can not be reused from the flatbuffer since the + // zero_point is stored as a int64_t. + quantization->zero_point = + allocate_temp + ? reinterpret_cast( + non_persistent_buffer_allocator->AllocateTemp( + TfLiteIntArrayGetSizeInBytes(channels), + alignof(TfLiteIntArray))) + : reinterpret_cast( + persistent_buffer_allocator->AllocatePersistentBuffer( + TfLiteIntArrayGetSizeInBytes(channels), + alignof(TfLiteIntArray))); + if (quantization->zero_point == nullptr) { + MicroPrintf("Unable to allocate quantization->zero_point.\n"); + return kTfLiteError; + } + + quantization->scale = + FlatBufferVectorToTfLiteTypeArray(src_quantization->scale()); + + quantization->zero_point->size = channels; + int* zero_point_data = quantization->zero_point->data; + for (int i = 0; i < channels; i++) { + // As a space-saving optimization, zero point arrays for weights can be + // reduced to a single value, since all zero points for weights are 0. + zero_point_data[i] = src_quantization->zero_point()->size() == + src_quantization->scale()->size() + ? src_quantization->zero_point()->Get(i) + : src_quantization->zero_point()->Get(0); + } + // TODO(rocky): Need to add a micro_allocator test case that fails when + // this is not copied: + quantization->quantized_dimension = src_quantization->quantized_dimension(); + + result->quantization = {kTfLiteAffineQuantization, quantization}; + } + return kTfLiteOk; +} + +TfLiteStatus InitializeTfLiteEvalTensorFromFlatbuffer( + const tflite::Tensor& flatbuffer_tensor, + const flatbuffers::Vector>* buffers, + TfLiteEvalTensor* result) { + *result = {}; + // Make sure the serialized type is one we know how to deal with, and convert + // it from a flatbuffer enum into a constant used by the kernel C API. + TF_LITE_ENSURE_STATUS(ConvertTensorType(flatbuffer_tensor.type(), + &result->type, + tflite::GetMicroErrorReporter())); + + result->data.data = GetFlatbufferTensorBuffer(flatbuffer_tensor, buffers); + + if (flatbuffer_tensor.shape() == nullptr) { + // flatbuffer_tensor.shape() can return a nullptr in the case of a scalar + // tensor. + result->dims = const_cast(&kZeroLengthIntArray); + } else { + result->dims = FlatBufferVectorToTfLiteTypeArray(flatbuffer_tensor.shape()); + } + return kTfLiteOk; +} + +} // namespace internal + +size_t MicroAllocator::GetDefaultTailUsage(bool is_memory_planner_given) { + // TODO(b/208703041): a template version of AlignSizeUp to make expression + // shorter. + size_t total_size = + AlignSizeUp(sizeof(SingleArenaBufferAllocator), + alignof(SingleArenaBufferAllocator)) + + AlignSizeUp(sizeof(MicroAllocator), alignof(MicroAllocator)) + + AlignSizeUp(sizeof(MicroBuiltinDataAllocator), + alignof(MicroBuiltinDataAllocator)) + + AlignSizeUp(sizeof(SubgraphAllocations), alignof(SubgraphAllocations)); + if (!is_memory_planner_given) { + total_size += + AlignSizeUp(sizeof(GreedyMemoryPlanner), alignof(GreedyMemoryPlanner)); + } + return total_size; +} + +MicroAllocator::MicroAllocator(SingleArenaBufferAllocator* memory_allocator, + MicroMemoryPlanner* memory_planner) + : non_persistent_buffer_allocator_(memory_allocator), + persistent_buffer_allocator_(memory_allocator), + memory_planner_(memory_planner), + model_is_allocating_(false) {} + +MicroAllocator::MicroAllocator( + IPersistentBufferAllocator* persistent_buffer_allocator, + INonPersistentBufferAllocator* non_persistent_buffer_allocator, + MicroMemoryPlanner* memory_planner) + : non_persistent_buffer_allocator_(non_persistent_buffer_allocator), + persistent_buffer_allocator_(persistent_buffer_allocator), + memory_planner_(memory_planner), + model_is_allocating_(false) {} + +MicroAllocator::~MicroAllocator() {} + +MicroAllocator* MicroAllocator::Create(uint8_t* tensor_arena, size_t arena_size, + MicroMemoryPlanner* memory_planner) { + uint8_t* aligned_arena = + AlignPointerUp(tensor_arena, MicroArenaBufferAlignment()); + size_t aligned_arena_size = tensor_arena + arena_size - aligned_arena; + SingleArenaBufferAllocator* memory_allocator = + SingleArenaBufferAllocator::Create(aligned_arena, aligned_arena_size); + + return Create(memory_allocator, memory_planner); +} + +MicroAllocator* MicroAllocator::Create(uint8_t* tensor_arena, + size_t arena_size) { + uint8_t* aligned_arena = + AlignPointerUp(tensor_arena, MicroArenaBufferAlignment()); + size_t aligned_arena_size = tensor_arena + arena_size - aligned_arena; + SingleArenaBufferAllocator* memory_allocator = + SingleArenaBufferAllocator::Create(aligned_arena, aligned_arena_size); + + // By default create GreedyMemoryPlanner. + // If a different MemoryPlanner is needed, use the other api. + uint8_t* memory_planner_buffer = memory_allocator->AllocatePersistentBuffer( + sizeof(GreedyMemoryPlanner), alignof(GreedyMemoryPlanner)); + GreedyMemoryPlanner* memory_planner = + new (memory_planner_buffer) GreedyMemoryPlanner(); + + return Create(memory_allocator, memory_planner); +} + +MicroAllocator* MicroAllocator::Create( + SingleArenaBufferAllocator* memory_allocator, + MicroMemoryPlanner* memory_planner) { + TFLITE_DCHECK(memory_allocator != nullptr); + TFLITE_DCHECK(memory_planner != nullptr); + + uint8_t* allocator_buffer = memory_allocator->AllocatePersistentBuffer( + sizeof(MicroAllocator), alignof(MicroAllocator)); + MicroAllocator* allocator = new (allocator_buffer) + MicroAllocator(memory_allocator, memory_allocator, memory_planner); + return allocator; +} + +MicroAllocator* MicroAllocator::Create(uint8_t* persistent_tensor_arena, + size_t persistent_arena_size, + uint8_t* non_persistent_tensor_arena, + size_t non_persistent_arena_size) { + TFLITE_DCHECK(persistent_tensor_arena != nullptr); + TFLITE_DCHECK(non_persistent_tensor_arena != nullptr); + TFLITE_DCHECK(persistent_tensor_arena != non_persistent_tensor_arena); + + IPersistentBufferAllocator* persistent_buffer_allocator = + CreatePersistentArenaAllocator(persistent_tensor_arena, + persistent_arena_size); + INonPersistentBufferAllocator* non_persistent_buffer_allocator = + CreateNonPersistentArenaAllocator(non_persistent_tensor_arena, + non_persistent_arena_size, + persistent_buffer_allocator); + + uint8_t* memory_planner_buffer = + persistent_buffer_allocator->AllocatePersistentBuffer( + sizeof(GreedyMemoryPlanner), alignof(GreedyMemoryPlanner)); + GreedyMemoryPlanner* memory_planner = + new (memory_planner_buffer) GreedyMemoryPlanner(); + + uint8_t* micro_allocator_buffer = + persistent_buffer_allocator->AllocatePersistentBuffer( + sizeof(MicroAllocator), alignof(MicroAllocator)); + MicroAllocator* allocator = new (micro_allocator_buffer) + MicroAllocator(persistent_buffer_allocator, + non_persistent_buffer_allocator, memory_planner); + return allocator; +} + +SubgraphAllocations* MicroAllocator::StartModelAllocation(const Model* model) { + TFLITE_DCHECK(model != nullptr); + + if (model_is_allocating_) { + MicroPrintf( + "MicroAllocator: Model allocation started before " + "finishing previously allocated model"); + return nullptr; + } + + model_is_allocating_ = true; + + uint8_t* data_allocator_buffer = + persistent_buffer_allocator_->AllocatePersistentBuffer( + sizeof(MicroBuiltinDataAllocator), + alignof(MicroBuiltinDataAllocator)); + builtin_data_allocator_ = new (data_allocator_buffer) + MicroBuiltinDataAllocator(persistent_buffer_allocator_); + + if (InitScratchBufferData() != kTfLiteOk) { + return nullptr; + } + + // Allocate struct to store eval tensors, nodes and registrations. + SubgraphAllocations* output = reinterpret_cast( + persistent_buffer_allocator_->AllocatePersistentBuffer( + sizeof(SubgraphAllocations) * model->subgraphs()->size(), + alignof(SubgraphAllocations))); + if (output == nullptr) { + MicroPrintf("Failed to allocate memory for model metadata."); + return nullptr; + } + + if (AllocateTfLiteEvalTensors(model, output) != kTfLiteOk || + AllocateNodeAndRegistrations(model, output) != kTfLiteOk) { + return nullptr; + } + return output; +} + +TfLiteStatus MicroAllocator::FinishModelAllocation( + const Model* model, SubgraphAllocations* subgraph_allocations, + ScratchBufferHandle** scratch_buffer_handles) { + if (!model_is_allocating_) { + MicroPrintf( + "MicroAllocator: Model allocation finished before " + "starting allocating model"); + return kTfLiteError; + } + + // Allocate scratch buffer metadata. + TF_LITE_ENSURE_STATUS(AllocateScratchBufferHandles( + scratch_buffer_handles, scratch_buffer_request_count_)); + + // Allocate buffers for variable tensors. + for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size(); + subgraph_idx++) { + const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx); + TFLITE_DCHECK(subgraph != nullptr); + TF_LITE_ENSURE_STATUS(AllocateVariables( + subgraph, subgraph_allocations[subgraph_idx].tensors)); + } + + // Plan all subgraphs and scratch buffers together. + TF_LITE_ENSURE_STATUS(CommitStaticMemoryPlan(model, subgraph_allocations, + *scratch_buffer_handles)); + model_is_allocating_ = false; + return kTfLiteOk; +} + +void* MicroAllocator::AllocatePersistentBuffer(size_t bytes) { + return persistent_buffer_allocator_->AllocatePersistentBuffer( + bytes, MicroArenaBufferAlignment()); +} + +TfLiteStatus MicroAllocator::RequestScratchBufferInArena(size_t bytes, + int subgraph_idx, + int* buffer_idx) { + // All scratch buffer requests are stored in the head section of the arena + // when a model is in the prepare phase. First align a scratch buffer request + // pointer to the start of the head: + internal::ScratchBufferRequest* requests = GetScratchBufferRequests(); + + // Count the number of requested scratch buffers for the current node: + size_t current_node_request_count = 0; + for (size_t i = 0; i < scratch_buffer_request_count_; ++i) { + if (requests[i].node_idx == kUnassignedScratchBufferRequestIndex) { + ++current_node_request_count; + } + } + + // First, ensure that the per-kernel request has not exceeded the limit: + if (current_node_request_count >= kMaxScratchBuffersPerOp) { + MicroPrintf("Scratch buffer request exeeds limit per operator (%d)", + kMaxScratchBuffersPerOp); + return kTfLiteError; + } + + // Initialize and assign values for the request at the current index: + internal::ScratchBufferRequest* current_request = + &requests[scratch_buffer_request_count_]; + *current_request = {}; + // Assign -1 as a sentinel value that will be updated when the node finishes + // allocating: + current_request->bytes = bytes; + current_request->node_idx = kUnassignedScratchBufferRequestIndex; + current_request->subgraph_idx = subgraph_idx; + + // Assign the current request index to the out-param: + *buffer_idx = scratch_buffer_request_count_; + + // Bump the request count to prepare for the next request: + ++scratch_buffer_request_count_; + return kTfLiteOk; +} + +TfLiteStatus MicroAllocator::FinishPrepareNodeAllocations(int node_id) { + // When a node has finished preparing, all temp allocations performed by the + // kernel should be cleaned up: + TF_LITE_ENSURE_STATUS(ResetTempAllocations()); + + // Find and update any new scratch buffer requests for the current node: + internal::ScratchBufferRequest* requests = GetScratchBufferRequests(); + + for (size_t i = 0; i < scratch_buffer_request_count_; ++i) { + // A request with a node_idx of -1 is a sentinel value used to indicate this + // was a new request for the current node. The allocator finally knows the + // node index at this point. Assign the value and update the list of new + // requests so the head section can be adjusted to allow for the next kernel + // to allocate at most kMaxScratchBuffersPerOp requests: + if (requests[i].node_idx == kUnassignedScratchBufferRequestIndex) { + requests[i].node_idx = node_id; + } + } + + // Ensure that the head is re-adjusted to allow for another at-most + // kMaxScratchBuffersPerOp scratch buffer requests in the next operator: + TF_LITE_ENSURE_STATUS(non_persistent_buffer_allocator_->ResizeBuffer( + scratch_buffer_head_, + sizeof(internal::ScratchBufferRequest) * + (scratch_buffer_request_count_ + kMaxScratchBuffersPerOp), + alignof(internal::ScratchBufferRequest))); + + return kTfLiteOk; +} + +size_t MicroAllocator::used_bytes() const { + return non_persistent_buffer_allocator_->GetNonPersistentUsedBytes() + + persistent_buffer_allocator_->GetPersistentUsedBytes(); +} + +TfLiteStatus MicroAllocator::AllocateNodeAndRegistrations( + const Model* model, SubgraphAllocations* subgraph_allocations) { + TFLITE_DCHECK(subgraph_allocations != nullptr); + + for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size(); + subgraph_idx++) { + const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx); + TFLITE_DCHECK(subgraph != nullptr); + + uint32_t operators_size = NumSubgraphOperators(subgraph); + + // Initialize NodeAndRegistrations for the subgraph. + NodeAndRegistration* output = reinterpret_cast( + persistent_buffer_allocator_->AllocatePersistentBuffer( + sizeof(NodeAndRegistration) * operators_size, + alignof(NodeAndRegistration))); + if (output == nullptr) { + MicroPrintf("Failed to allocate memory for node_and_registrations."); + return kTfLiteError; + } + subgraph_allocations[subgraph_idx].node_and_registrations = output; + } + return kTfLiteOk; +} + +TfLiteTensor* MicroAllocator::AllocatePersistentTfLiteTensor( + const Model* model, const SubgraphAllocations* subgraph_allocations, + int tensor_index, int subgraph_index) { + const SubGraph* subgraph = model->subgraphs()->Get(subgraph_index); + TFLITE_DCHECK(subgraph != nullptr); + + // This value is allocated from persistent arena space. It is guaranteed to be + // around for the lifetime of the application. + TfLiteTensor* tensor = AllocatePersistentTfLiteTensorInternal(); + + // Populate any fields from the flatbuffer, since this TfLiteTensor struct is + // allocated in the persistent section of the arena, ensure that additional + // allocations also take place in that section of the arena. + if (PopulateTfLiteTensorFromFlatbuffer( + model, tensor, tensor_index, subgraph_index, + /*allocate_temp=*/false) != kTfLiteOk) { + MicroPrintf( + "Failed to populate a persistent TfLiteTensor struct " + "from flatbuffer data!"); + return nullptr; + } + + if (subgraph_allocations != nullptr) { + // Tensor buffers that are allocated at runtime (e.g. non-weight buffers) + // and not located in the flatbuffer are stored on the pre-allocated list of + // TfLiteEvalTensors structs. These structs are the source of truth, simply + // point the corresponding buffer to the new TfLiteTensor data value. + tensor->data.data = + subgraph_allocations[subgraph_index].tensors[tensor_index].data.data; + // TfLiteEvalTensor structs must also be the source of truth for the + // TfLiteTensor dims. + tensor->dims = + subgraph_allocations[subgraph_index].tensors[tensor_index].dims; + } + return tensor; +} + +void MicroAllocator::DeallocateTempTfLiteTensor(TfLiteTensor* tensor) { + TFLITE_DCHECK(tensor != nullptr); + + if (tensor->quantization.type == kTfLiteAffineQuantization) { + TFLITE_DCHECK(tensor->quantization.params != nullptr); + TfLiteAffineQuantization* quantization = + reinterpret_cast( + tensor->quantization.params); + + non_persistent_buffer_allocator_->DeallocateTemp( + reinterpret_cast(quantization->zero_point)); + non_persistent_buffer_allocator_->DeallocateTemp( + reinterpret_cast(quantization)); + } + + // Clear the data in case someone still access tensor arena by mistake + tensor->quantization.type = kTfLiteNoQuantization; + tensor->quantization.params = nullptr; + tensor->data.data = nullptr; + tensor->dims = nullptr; + non_persistent_buffer_allocator_->DeallocateTemp( + reinterpret_cast(tensor)); +} + +TfLiteTensor* MicroAllocator::AllocateTempTfLiteTensor( + const Model* model, const SubgraphAllocations* subgraph_allocations, + int tensor_index, int subgraph_index) { + const SubGraph* subgraph = model->subgraphs()->Get(subgraph_index); + TFLITE_DCHECK(subgraph != nullptr); + + // This value is allocated from temporary arena space. It is guaranteed to be + // around for at least the scope of the calling function. Since this struct + // allocation takes place in temp space, no need to own or cleanup. + TfLiteTensor* tensor = reinterpret_cast( + non_persistent_buffer_allocator_->AllocateTemp(sizeof(TfLiteTensor), + alignof(TfLiteTensor))); + + // Populate any fields from the flatbuffer, since this TfLiteTensor struct is + // allocated in the temp section of the arena, ensure that additional + // allocations also take place in that section of the arena. + if (PopulateTfLiteTensorFromFlatbuffer(model, tensor, tensor_index, + subgraph_index, + /*allocate_temp=*/true) != kTfLiteOk) { + MicroPrintf( + "Failed to populate a temp TfLiteTensor struct from flatbuffer data!"); + return nullptr; + } + + if (subgraph_allocations != nullptr) { + // Tensor buffers that are allocated at runtime (e.g. non-weight buffers) + // and not located in the flatbuffer are stored on the pre-allocated list of + // TfLiteEvalTensors structs. These structs are the source of truth, simply + // point the corresponding buffer to the new TfLiteTensor data value. + tensor->data.data = + subgraph_allocations[subgraph_index].tensors[tensor_index].data.data; + // TfLiteEvalTensor structs must also be the source of truth for the + // TfLiteTensor dims. + tensor->dims = + subgraph_allocations[subgraph_index].tensors[tensor_index].dims; + } + return tensor; +} + +TfLiteStatus MicroAllocator::ResetTempAllocations() { + return non_persistent_buffer_allocator_->ResetTempAllocations(); +} + +bool MicroAllocator::IsAllTempDeallocated() { + return non_persistent_buffer_allocator_->IsAllTempDeallocated(); +} + +TfLiteStatus MicroAllocator::AllocateTfLiteEvalTensors( + const Model* model, SubgraphAllocations* subgraph_allocations) { + TFLITE_DCHECK(subgraph_allocations != nullptr); + + for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size(); + subgraph_idx++) { + const SubGraph* subgraph = model->subgraphs()->Get(subgraph_idx); + TFLITE_DCHECK(subgraph != nullptr); + + size_t alloc_count = subgraph->tensors()->size(); + TfLiteEvalTensor* tensors = reinterpret_cast( + persistent_buffer_allocator_->AllocatePersistentBuffer( + sizeof(TfLiteEvalTensor) * alloc_count, alignof(TfLiteEvalTensor))); + if (tensors == nullptr) { + MicroPrintf( + "Failed to allocate memory for context->eval_tensors, " + "%d bytes required", + sizeof(TfLiteEvalTensor) * alloc_count); + return kTfLiteError; + } + + for (size_t i = 0; i < alloc_count; ++i) { + TfLiteStatus status = internal::InitializeTfLiteEvalTensorFromFlatbuffer( + *subgraph->tensors()->Get(i), model->buffers(), &tensors[i]); + if (status != kTfLiteOk) { + MicroPrintf("Failed to initialize tensor %d", i); + return kTfLiteError; + } + } + subgraph_allocations[subgraph_idx].tensors = tensors; + } + return kTfLiteOk; +} + +TfLiteStatus MicroAllocator::AllocateVariables(const SubGraph* subgraph, + TfLiteEvalTensor* eval_tensors) { + for (size_t i = 0; i < subgraph->tensors()->size(); ++i) { + auto* tensor = subgraph->tensors()->Get(i); + if (tensor->is_variable()) { + size_t buffer_size; + TF_LITE_ENSURE_STATUS( + TfLiteEvalTensorByteLength(&eval_tensors[i], &buffer_size)); + + eval_tensors[i].data.data = + persistent_buffer_allocator_->AllocatePersistentBuffer( + buffer_size, MicroArenaBufferAlignment()); + + if (eval_tensors[i].data.data == nullptr) { + MicroPrintf("Failed to allocate variable tensor of size %d", + buffer_size); + return kTfLiteError; + } + } + } + return kTfLiteOk; +} + +TfLiteTensor* MicroAllocator::AllocatePersistentTfLiteTensorInternal() { + return reinterpret_cast( + persistent_buffer_allocator_->AllocatePersistentBuffer( + sizeof(TfLiteTensor), alignof(TfLiteTensor))); +} + +TfLiteStatus MicroAllocator::PopulateTfLiteTensorFromFlatbuffer( + const Model* model, TfLiteTensor* tensor, int tensor_index, + int subgraph_idx, bool allocate_temp) { + // TODO(b/162311891): This method serves as a stub to ensure quantized + // allocations in the tail can be recorded. Once the interpreter has APIs for + // accessing buffers on TfLiteEvalTensor this method can be dropped. + return internal::InitializeTfLiteTensorFromFlatbuffer( + persistent_buffer_allocator_, non_persistent_buffer_allocator_, + allocate_temp, + *model->subgraphs()->Get(subgraph_idx)->tensors()->Get(tensor_index), + model->buffers(), tensor); +} + +TfLiteStatus MicroAllocator::CommitStaticMemoryPlan( + const Model* model, SubgraphAllocations* allocations, + ScratchBufferHandle* scratch_buffer_handles) { + size_t head_usage = 0; + // Create static memory plan + // 1. Calculate AllocationInfo to know the lifetime of each tensor/buffer. + // 2. Add them into the planner (such as the GreedyMemoryPlanner). + // 3. Static memory planning using the planner. + // 4. Set tensor/buffer pointers based on the offsets from the previous step. + // + // Note that AllocationInfo is only needed for creating the plan. It will be + // allocated from the temp section and cleaned up at the bottom of this + // function. + + // Use the AllocationInfoBuilder class to help determine where buffers are + // used in the subgraph. + AllocationInfoBuilder builder(model, non_persistent_buffer_allocator_); + TF_LITE_ENSURE_STATUS( + builder.CreateAllocationInfo(scratch_buffer_request_count_)); + + const int32_t* offline_planner_offsets = nullptr; + TF_LITE_ENSURE_STATUS( + builder.GetOfflinePlannedOffsets(&offline_planner_offsets)); + TF_LITE_ENSURE_STATUS( + builder.InitializeAllocationInfo(offline_planner_offsets, allocations)); + + internal::ScratchBufferRequest* scratch_buffer_requests = + GetScratchBufferRequests(); + TF_LITE_ENSURE_STATUS(builder.MarkAllocationLifetimes( + 0, scratch_buffer_requests, scratch_buffer_handles, allocations)); + int allocation_info_count = builder.AllocationCount(); + AllocationInfo* allocation_info = builder.Finish(); + + // Remaining arena size that memory planner can use for calculating offsets. + size_t remaining_arena_size = + non_persistent_buffer_allocator_->GetAvailableMemory( + MicroArenaBufferAlignment()); + uint8_t* planner_arena = non_persistent_buffer_allocator_->AllocateTemp( + remaining_arena_size, MicroArenaBufferAlignment()); + TF_LITE_ENSURE(tflite::GetMicroErrorReporter(), planner_arena != nullptr); + memory_planner_->Init(planner_arena, remaining_arena_size); + TF_LITE_ENSURE_STATUS( + CreatePlan(memory_planner_, allocation_info, allocation_info_count)); + + // Commit the plan. + TF_LITE_ENSURE_STATUS( + CommitPlan(memory_planner_, + non_persistent_buffer_allocator_->GetOverlayMemoryAddress(), + allocation_info, allocation_info_count)); + + // Reset all temp allocations used above: + builder.FreeAllocationInfo(); + non_persistent_buffer_allocator_->DeallocateTemp(planner_arena); + TF_LITE_ENSURE_STATUS( + non_persistent_buffer_allocator_->ResetTempAllocations()); + TF_LITE_ENSURE_STATUS( + non_persistent_buffer_allocator_->DeallocateResizableBuffer( + scratch_buffer_head_)); + +#ifdef TF_LITE_SHOW_MEMORY_USE + memory_planner_->PrintMemoryPlan(); +#endif + head_usage = memory_planner_->GetMaximumMemorySize(); + + // The head is used to store memory plans for one model at a time during the + // model preparation stage, and is re-purposed to store scratch buffer handles + // during model invocation. The head must be as large as the greater of the + // largest model memory plan's size and the total space required for all + // scratch buffer handles. + if (max_head_buffer_usage_ < head_usage) { + max_head_buffer_usage_ = head_usage; + } + + // The head is used for storing scratch buffer allocations before finalizing a + // memory plan in this function. Ensure that the head is set to the largest + // memory plan sent through the allocator: + TF_LITE_ENSURE_STATUS( + non_persistent_buffer_allocator_->ReserveNonPersistentOverlayMemory( + max_head_buffer_usage_, MicroArenaBufferAlignment())); + return kTfLiteOk; +} + +TfLiteStatus MicroAllocator::AllocateScratchBufferHandles( + ScratchBufferHandle** scratch_buffer_handles, size_t handle_count) { + TFLITE_DCHECK(scratch_buffer_handles != nullptr); + + if (scratch_buffer_request_count_ == 0) { + // No scratch buffer requests were requested during model allocation. + return kTfLiteOk; + } + + // Allocate a consecutive block of memory store the scratch buffer handles. + // This alignment ensures quick lookup during inference time for the model: + *scratch_buffer_handles = reinterpret_cast( + persistent_buffer_allocator_->AllocatePersistentBuffer( + sizeof(ScratchBufferHandle) * handle_count, + alignof(ScratchBufferHandle))); + + return kTfLiteOk; +} + +TfLiteStatus MicroAllocator::InitScratchBufferData() { + // A model is preparing to allocate resources, ensure that scratch buffer + // request counter is cleared: + scratch_buffer_request_count_ = 0; + + // All requests will be stored in the head section. Each kernel is allowed at + // most kMaxScratchBuffersPerOp requests. Adjust the head to reserve at most + // that many requests to begin: + scratch_buffer_head_ = + non_persistent_buffer_allocator_->AllocateResizableBuffer( + sizeof(internal::ScratchBufferRequest) * kMaxScratchBuffersPerOp, + alignof(internal::ScratchBufferRequest)); + if (scratch_buffer_head_ == nullptr) { + return kTfLiteError; + } + + return kTfLiteOk; +} + +internal::ScratchBufferRequest* MicroAllocator::GetScratchBufferRequests() { + return reinterpret_cast(AlignPointerUp( + scratch_buffer_head_, alignof(internal::ScratchBufferRequest))); +} + +BuiltinDataAllocator* MicroAllocator::GetBuiltinDataAllocator() { + return builtin_data_allocator_; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocator.h new file mode 100644 index 000000000..1f2f5162e --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_allocator.h @@ -0,0 +1,357 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_ALLOCATOR_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/flatbuffer_conversions.h" +#include "tensorflow/lite/micro/arena_allocator/single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/memory_planner/micro_memory_planner.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// TODO(b/199402574): rename to tflite_internal or just remove internal +// namespace. +namespace internal { + +// Sets up all of the data structure members for a TfLiteTensor based on the +// contents of a serialized tensor in the flatbuffer. +// TODO(b/162311891): Drop this method when the interpreter has an API for +// returning buffers on TfLiteEvalTensor. +TfLiteStatus InitializeTfLiteTensorFromFlatbuffer( + IPersistentBufferAllocator* persistent_buffer_allocator, + INonPersistentBufferAllocator* non_persistent_buffer_allocator, + bool allocate_temp, const tflite::Tensor& flatbuffer_tensor, + const flatbuffers::Vector>* buffers, + TfLiteTensor* result); + +// Holds placeholder information for a scratch buffer request from a kernel. +// This struct is only used during the model prepare stage. Each request from a +// kernel is stored in the head section. During the prepare stage, the head +// section will at least hold kMaxScratchBuffersPerOp number of requests plus +// any requests from previous kernel requests. +// +// When the memory plan is finalized, these structs are no longer used in favor +// of a sequential, array of ScratchBufferHandle allocations in the tail +// section. These allocations are indexed by the request API defined in the +// TfLiteContext struct. +struct ScratchBufferRequest { + // Number of bytes required by the buffer. The actual allocated size might be + // greater than `bytes` due to buffer alignment. + size_t bytes; + // Node where the buffer is allocated for. This provides useful information to + // determine the lifetime of the buffer. In AllocationInfo, this buffer will + // have `before` = node_idx and `after` = node_idx. + int node_idx; + int subgraph_idx; +}; + +} // namespace internal + +struct NodeAndRegistration { + TfLiteNode node; + const TfLiteRegistration* registration; +}; + +// Holds a pointer to a buffer for a scratch buffer requested by a kernel during +// the model prepare stage. This struct is allocated in-place and allows for +// quick pointer-indexed lookup for speed during model inference. +struct ScratchBufferHandle { + // Pointer to location of the scratch buffer: + uint8_t* data; +}; + +// Stores all per-subgraph allocations. This includes the node and registration +// array, and tensor list for each subgraph. +struct SubgraphAllocations { + NodeAndRegistration* node_and_registrations; + TfLiteEvalTensor* tensors; +}; + +// Allocator responsible for allocating memory for all intermediate tensors +// necessary to invoke a model. +// +// The lifetime of the model, tensor arena and error reporter must be at +// least as long as that of the allocator object, since the allocator needs +// them to be accessible during its entire lifetime. +// +// The MicroAllocator simply plans out additional allocations that are required +// to standup a model for inference in TF Micro. This class currently relies on +// an additional allocator - SingleArenaBufferAllocator - for all allocations +// from an arena. These allocations are divided into head (non-persistent) and +// tail (persistent) regions: +// +// Memory layout to help understand how it works +// This information could change in the future version. +// ************** .memory_allocator->GetBuffer() +// Tensors/Scratch buffers (head) +// ************** .head_watermark +// unused memory +// ************** .memory_allocator->GetBuffer() + ->GetMaxBufferSize() +// - ->GetDataSize() +// persistent area (tail) +// ************** .memory_allocator->GetBuffer() + ->GetMaxBufferSize() +class MicroAllocator { + public: + // TODO(b/246776144): Will be removed with http://b/246776144 + static MicroAllocator* Create(uint8_t* tensor_arena, size_t arena_size, + ErrorReporter* error_reporter) { + (void)error_reporter; + return MicroAllocator::Create(tensor_arena, arena_size); + } + + // Creates a MicroAllocator instance from a given tensor arena. This arena + // will be managed by the created instance. The GreedyMemoryPlanner will + // by default be used and created on the arena. + // Note: Please use alignas(16) to make sure tensor_arena is 16 + // bytes aligned, otherwise some head room will be wasted. + // TODO(b/157615197): Cleanup constructor + factory usage. + static MicroAllocator* Create(uint8_t* tensor_arena, size_t arena_size); + + // TODO(b/246776144): Will be removed with http://b/246776144 + static MicroAllocator* Create(uint8_t* tensor_arena, size_t arena_size, + MicroMemoryPlanner* memory_planner, + ErrorReporter* error_reporter) { + (void)error_reporter; + return MicroAllocator::Create(tensor_arena, arena_size, memory_planner); + } + + // Creates a MicroAllocator instance from a given tensor arena and a given + // MemoryPlanner. This arena will be managed by the created instance. Note: + // Please use alignas(16) to make sure tensor_arena is 16 bytes + // aligned, otherwise some head room will be wasted. + static MicroAllocator* Create(uint8_t* tensor_arena, size_t arena_size, + MicroMemoryPlanner* memory_planner); + + // TODO(b/246776144): Will be removed with http://b/246776144 + static MicroAllocator* Create(SingleArenaBufferAllocator* memory_allocator, + MicroMemoryPlanner* memory_planner, + ErrorReporter* error_reporter) { + (void)error_reporter; + return MicroAllocator::Create(memory_allocator, memory_planner); + } + + // Creates a MicroAllocator instance using the provided + // SingleArenaBufferAllocator instance and the MemoryPlanner. This allocator + // instance will use the SingleArenaBufferAllocator instance to manage + // allocations internally. + static MicroAllocator* Create(SingleArenaBufferAllocator* memory_allocator, + MicroMemoryPlanner* memory_planner); + + // TODO(b/246776144): Will be removed with http://b/246776144 + static MicroAllocator* Create(uint8_t* persistent_tensor_arena, + size_t persistent_arena_size, + uint8_t* non_persistent_tensor_arena, + size_t non_persistent_arena_size, + ErrorReporter* error_reporter) { + (void)error_reporter; + return MicroAllocator::Create( + persistent_tensor_arena, persistent_arena_size, + non_persistent_tensor_arena, non_persistent_arena_size); + } + + // Creates a MicroAllocator instance using the provided + // SingleArenaBufferAllocator instance and the MemoryPlanner. This allocator + // instance will use the SingleArenaBufferAllocator instance to manage + // allocations internally. + static MicroAllocator* Create(uint8_t* persistent_tensor_arena, + size_t persistent_arena_size, + uint8_t* non_persistent_tensor_arena, + size_t non_persistent_arena_size); + + // Returns the fixed amount of memory overhead of MicroAllocator. + static size_t GetDefaultTailUsage(bool is_memory_planner_given); + + // Allocates internal resources required for model inference for each subgraph + // from the arena. + // + // This method will run through the flatbuffer data supplied in the model to + // properly allocate tensor, node, and op registration data. This method is + // expected to be followed with a call to FinishModelAllocation() Returns a + // pointer to an array of SubgraphAllocations (also stored in the tail of the + // arena) where each index corresponds to a different subgraph in the model. + // Return value is nullptr if the allocations failed. + SubgraphAllocations* StartModelAllocation(const Model* model); + + // Finish allocating internal resources required for model inference. + // + // -Plan the memory for activation tensors and scratch buffers. + // -Update eval tensors for each subgraph based on planned offsets. + // -Allocate scratch buffer handles array and update based on planned offsets. + // + // This method should be called after assigning model resources + // in StartModelAllocation(). The subgraph_allocations pointer should be the + // value passed into this class during StartModelAllocation(). Scratch buffer + // handles are stored in the out-param `scratch_buffer_handles` array which is + // allocated in this method. This value will be used in `GetScratchBuffer` + // call to retrieve scratch buffers. + TfLiteStatus FinishModelAllocation( + const Model* model, SubgraphAllocations* subgraph_allocations, + ScratchBufferHandle** scratch_buffer_handles); + + // Allocates a TfLiteTensor struct and populates the returned value with + // properties from the model flatbuffer. This struct is allocated from + // persistent arena memory is only guaranteed for the lifetime of the + // application. The eval_tensors pointer should be the value passed into this + // class during StartModelAllocation() and contains the source-of-truth for + // buffers. + virtual TfLiteTensor* AllocatePersistentTfLiteTensor( + const Model* model, const SubgraphAllocations* subgraph_allocations, + int tensor_index, int subgraph_index); + + // Allocates a TfLiteTensor struct and populates the returned value with + // properties from the model flatbuffer. This struct is allocated from + // temporary arena memory is only guaranteed until a call is made to + // ResetTempAllocations(). Subgraph_allocaitons contains the array of + // TfLiteEvalTensors. If the newly allocated temp at the specified subgraph + // and tensor index is already present int the TfLiteEvalTensor array, its + // data buffer will be re-used. + virtual TfLiteTensor* AllocateTempTfLiteTensor( + const Model* model, const SubgraphAllocations* subgraph_allocations, + int tensor_index, int subgraph_index); + + virtual void DeallocateTempTfLiteTensor(TfLiteTensor*); + + // Resets all temporary allocations. This method should be called after a + // chain of temp allocations (e.g. chain of TfLiteTensor objects via + // AllocateTfLiteTensor()). + virtual TfLiteStatus ResetTempAllocations(); + + // Returns true if all temporary buffers including temp TfLiteTensor are + // already deallocated. + virtual bool IsAllTempDeallocated(); + + // Allocates persistent buffer which has the same life time as the allocator. + // The memory is immediately available and is allocated from the tail of the + // arena. + virtual void* AllocatePersistentBuffer(size_t bytes); + + // Register a scratch buffer of size `bytes` for Node with `node_id`. + // This method only requests a buffer with a given size to be used after a + // model has finished allocation via FinishModelAllocation(). All requested + // buffers will be accessible by the out-param in that method. + TfLiteStatus RequestScratchBufferInArena(size_t bytes, int subgraph_idx, + int* buffer_idx); + + // Finish allocating a specific NodeAndRegistration prepare block (kernel + // entry for a model) with a given node ID. This call ensures that any scratch + // buffer requests and temporary allocations are handled and ready for the + // next node prepare block. + TfLiteStatus FinishPrepareNodeAllocations(int node_id); + + // Returns the arena usage in bytes, only available after + // `FinishModelAllocation`. Otherwise, it will return 0. + size_t used_bytes() const; + + BuiltinDataAllocator* GetBuiltinDataAllocator(); + + protected: + MicroAllocator(SingleArenaBufferAllocator* memory_allocator, + MicroMemoryPlanner* memory_planner); + MicroAllocator(IPersistentBufferAllocator* persistent_buffer_allocator, + INonPersistentBufferAllocator* non_persistent_buffer_allocator, + MicroMemoryPlanner* memory_planner); + virtual ~MicroAllocator(); + + // Allocates an array in the arena to hold pointers to the node and + // registration pointers required to represent the inference graph of the + // model. + virtual TfLiteStatus AllocateNodeAndRegistrations( + const Model* model, SubgraphAllocations* subgraph_allocations); + + // Allocates the list of persistent TfLiteEvalTensors that are used for the + // "eval" phase of model inference. These structs will be the source of truth + // for all tensor buffers. + virtual TfLiteStatus AllocateTfLiteEvalTensors( + const Model* model, SubgraphAllocations* subgraph_allocations); + // Allocates persistent tensor buffers for variable tensors in the subgraph. + virtual TfLiteStatus AllocateVariables(const SubGraph* subgraph, + TfLiteEvalTensor* eval_tensors); + + // Allocate and return a persistent TfLiteTensor. + // TODO(b/162311891): Drop this method when the interpreter has an API for + // accessing TfLiteEvalTensor structs. + virtual TfLiteTensor* AllocatePersistentTfLiteTensorInternal(); + + // Populates a TfLiteTensor struct with data from the model flatbuffer. Any + // quantization data is allocated from either the tail (persistent) or temp + // sections of the arena based on the allocation flag. + virtual TfLiteStatus PopulateTfLiteTensorFromFlatbuffer(const Model* model, + TfLiteTensor* tensor, + int tensor_index, + int subgraph_idx, + bool allocate_temp); + + private: + // Commits a memory plan for all non-persistent buffer allocations in the + // 'head' section of the memory arena. The eval_tensors pointer is the list of + // pre-allocated TfLiteEvalTensor structs that will point to the buffers that + // will be allocated into the head section in this function call. The + // scratch_buffer_handles pointer is the array of pre-allocated + // ScratchBufferHandle structs that will point to allocated buffers also in + // the head section. + virtual TfLiteStatus CommitStaticMemoryPlan( + const Model* model, SubgraphAllocations* allocations, + ScratchBufferHandle* scratch_buffer_handles); + + // Allocates an array of ScratchBufferHandle structs in the tail section for a + // given number of handles. + virtual TfLiteStatus AllocateScratchBufferHandles( + ScratchBufferHandle** scratch_buffer_handles, size_t handle_count); + + // Clears all internal scratch buffer request counts and resets the head to + // prepare for kernels to request scratch buffer data when a model is + // preparing. + TfLiteStatus InitScratchBufferData(); + + // Returns the pointer for the array of ScratchBufferRequest allocations in + // the head section. + internal::ScratchBufferRequest* GetScratchBufferRequests(); + + // A simple memory allocator that always allocate from the arena tail or head. + INonPersistentBufferAllocator* non_persistent_buffer_allocator_; + IPersistentBufferAllocator* persistent_buffer_allocator_; + + // Allocator used to allocate persistent builtin data. + BuiltinDataAllocator* builtin_data_allocator_; + + // Activation buffer memory planner. + MicroMemoryPlanner* memory_planner_; + + bool model_is_allocating_; + + // Holds the number of ScratchBufferRequest instances stored in the head + // section when a model is allocating. + size_t scratch_buffer_request_count_ = 0; + + // Holds ScratchBufferRequest when a model is allocating + uint8_t* scratch_buffer_head_ = nullptr; + + // Holds the byte length of the memory plan with the largest head usage. Used + // to ensure that multi-tenant allocations can share the head for buffers. + size_t max_head_buffer_usage_ = 0; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite +#endif // TENSORFLOW_LITE_MICRO_MICRO_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_arena_constants.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_arena_constants.h new file mode 100644 index 000000000..828281760 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_arena_constants.h @@ -0,0 +1,28 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_ARENA_CONSTANTS_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_ARENA_CONSTANTS_H_ + +namespace tflite { + +// The default buffer alignment requirement. +// We align tensor buffers to 16-byte boundaries, since this is a common +// requirement for SIMD extensions. +constexpr int MicroArenaBufferAlignment() { return 16; } + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_ARENA_CONSTANTS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_context.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_context.cpp new file mode 100644 index 000000000..9e3d71de9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_context.cpp @@ -0,0 +1,130 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_context.h" + +#include +#include +#include + +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +MicroContext::MicroContext(MicroAllocator* allocator, const Model* model, + MicroGraph* graph) + : allocator_(*allocator), graph_(*graph), model_(model) {} + +MicroContext::~MicroContext() {} + +void* MicroContext::AllocatePersistentBuffer(size_t bytes) { + return allocator_.AllocatePersistentBuffer(bytes); +} + +TfLiteStatus MicroContext::RequestScratchBufferInArena(size_t bytes, + int* buffer_idx) { + return allocator_.RequestScratchBufferInArena( + bytes, graph_.GetCurrentSubgraphIndex(), buffer_idx); +} + +void* MicroContext::GetScratchBuffer(int buffer_idx) { + ScratchBufferHandle* handle = scratch_buffer_handles_ + buffer_idx; + return handle->data; +} + +TfLiteTensor* MicroContext::AllocateTempTfLiteTensor(int tensor_idx) { + return allocator_.AllocateTempTfLiteTensor(model_, graph_.GetAllocations(), + tensor_idx, + graph_.GetCurrentSubgraphIndex()); +} + +int MicroContext::GetTensorIndex(int index, int max_size, + const int* tensor_indices) { + if (index >= 0 && index < max_size) { + const int tensor_index = tensor_indices[index]; + if (tensor_index != kTfLiteOptionalTensor) { + return tensor_index; + } + } + return -1; +} + +TfLiteTensor* MicroContext::AllocateTempInputTensor(const TfLiteNode* node, + int index) { + const int tensor_index = + GetTensorIndex(index, node->inputs->size, node->inputs->data); + if (tensor_index < 0) { + return nullptr; + } + return AllocateTempTfLiteTensor(tensor_index); +} + +TfLiteTensor* MicroContext::AllocateTempOutputTensor(const TfLiteNode* node, + int index) { + const int tensor_index = + GetTensorIndex(index, node->outputs->size, node->outputs->data); + if (tensor_index < 0) { + return nullptr; + } + return AllocateTempTfLiteTensor(tensor_index); +} + +TfLiteTensor* MicroContext::AllocateTempIntermediateTensor( + const TfLiteNode* node, int index) { + const int tensor_index = GetTensorIndex(index, node->intermediates->size, + node->intermediates->data); + if (tensor_index < 0) { + return nullptr; + } + return AllocateTempTfLiteTensor(tensor_index); +} + +void MicroContext::DeallocateTempTfLiteTensor(TfLiteTensor* tensor) { + return allocator_.DeallocateTempTfLiteTensor(tensor); +} + +TfLiteEvalTensor* MicroContext::GetEvalTensor(int tensor_idx) { + return &graph_.GetAllocations()[graph_.GetCurrentSubgraphIndex()] + .tensors[tensor_idx]; +} + +void MicroContext::SetScratchBufferHandles( + ScratchBufferHandle* scratch_buffer_handles) { + scratch_buffer_handles_ = scratch_buffer_handles; +} + +TfLiteStatus MicroContext::set_external_context( + void* external_context_payload) { + if (external_context_payload == nullptr || + external_context_payload_ != nullptr) { + MicroPrintf( + "Attempting to set external context to %x but it was %x already", + external_context_payload, external_context_payload_); + return kTfLiteError; + } + + external_context_payload_ = external_context_payload; + return kTfLiteOk; +} + +void MicroContextReportOpError(struct TfLiteContext* context, + const char* format, ...) { + va_list args; + va_start(args, format); + GetMicroErrorReporter()->Report(format, args); + va_end(args); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_context.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_context.h new file mode 100644 index 000000000..e7be65444 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_context.h @@ -0,0 +1,161 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_CONTEXT_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_CONTEXT_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_graph.h" + +namespace tflite { +// MicroContext is eventually going to become the API between TFLM and the +// kernels, replacing all the functions in TfLiteContext. The end state is code +// kernels to have code like: +// +// MicroContext* micro_context = GetMicroContext(context); +// micro_context-> +class MicroContext { + public: + // Does not take any ownership, and all pointers must refer to valid objects + // that outlive the one constructed. + explicit MicroContext(MicroAllocator* allocator, const Model* model, + MicroGraph* graph); + virtual ~MicroContext(); + + // Allocate persistent buffer which has the same life time as the interpreter. + // Returns nullptr on failure. + // The memory is allocated from the tail. + // This method is only available in Init or Prepare stage. + // Virtual so that it can be faked for kernel tests. + virtual void* AllocatePersistentBuffer(size_t bytes); + + // Request a scratch buffer in the arena through static memory planning. + // This method is only available in Prepare stage and the buffer is allocated + // by the interpreter between Prepare and Eval stage. In Eval stage, + // GetScratchBuffer API can be used to fetch the address. + // Virtual so that it can be faked for kernel tests. + virtual TfLiteStatus RequestScratchBufferInArena(size_t bytes, + int* buffer_idx); + + // Get the scratch buffer pointer. + // This method is only available in Eval stage. + // Virtual so that it can be faked for kernel tests. + virtual void* GetScratchBuffer(int buffer_idx); + + // Returns a temporary TfLiteTensor struct for a given index. + // Virtual so that it can be faked for kernel tests. + virtual TfLiteTensor* AllocateTempTfLiteTensor(int tensor_idx); + + // Returns a temporary TfLiteTensor struct for the specified input tensor of a + // given mode. This is the recommended API over the deprecated + // GetInput/GetInputSafe to get a temp input tensor. The returned tensor shall + // be freed via calling DeallocateTempTfLiteTensor. + virtual TfLiteTensor* AllocateTempInputTensor(const TfLiteNode* node, + int index); + + // Returns a temporary TfLiteTensor struct for the specified output tensor of + // a given mode. This is the recommended API over the deprecated + // GetOutput/GetOutputSafe to get a temp output tensor. The returned tensor + // shall be freed via calling DeallocateTempTfLiteTensor. + virtual TfLiteTensor* AllocateTempOutputTensor(const TfLiteNode* node, + int index); + + // Returns a temporary TfLiteTensor struct for the specified intermediate + // tensor of a given mode. This is the recommended API over the deprecated + // GetIntermediates/GetIntermediatesSafe to get a temp intermediate tensor. + // The returned tensor shall be freed via calling DeallocateTempTfLiteTensor. + virtual TfLiteTensor* AllocateTempIntermediateTensor(const TfLiteNode* node, + int index); + + // Deallocates a temp TfLiteTensor. + // Virtual so that it can be faked for kernel tests. + virtual void DeallocateTempTfLiteTensor(TfLiteTensor* tensor); + + // Returns a TfLiteEvalTensor struct for a given index. + // Virtual so that it can be faked for kernel tests. + virtual TfLiteEvalTensor* GetEvalTensor(int tensor_idx); + + // Does not take ownership of the pointer and the pointer must refer to valid + // an object that outlive this class instance. + // This can only be called once to set one external context. + TfLiteStatus set_external_context(void* external_context_payload); + + void* external_context() { return external_context_payload_; } + + MicroGraph& graph() { return graph_; } + + // Sets the pointer to a list of ScratchBufferHandle instances. + // Not API between TFLM and kernels. Primarily used by the framework for + // housekeeping in MicroContext. + void SetScratchBufferHandles(ScratchBufferHandle* scratch_buffer_handles); + + private: + // Return the tensor index as tensor_indices[index]. tensor_indices is of + // max_size. Return -1 if index is not in the valid range of tensor_indices. + int GetTensorIndex(int index, int max_size, const int* tensor_indices); + + MicroAllocator& allocator_; + MicroGraph& graph_; + const Model* model_; + + ScratchBufferHandle* scratch_buffer_handles_ = nullptr; + void* external_context_payload_ = nullptr; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +inline MicroContext* GetMicroContext(const struct TfLiteContext* context) { + return reinterpret_cast(context->impl_); +} + +// Deprecated API. Prefer to using the MicroContext API directly from the +// kernels. +// TODO(b/213010668): migrate all existing kernels to use MicroContext, delete +// these functions, and remove corresponding members from the TfLiteContext +// struct for TFLM. +inline void* MicroContextAllocatePersistentBuffer(TfLiteContext* ctx, + size_t bytes) { + return GetMicroContext(ctx)->AllocatePersistentBuffer(bytes); +} +inline TfLiteStatus MicroContextRequestScratchBufferInArena(TfLiteContext* ctx, + size_t bytes, + int* buffer_idx) { + return GetMicroContext(ctx)->RequestScratchBufferInArena(bytes, buffer_idx); +} +inline void* MicroContextGetScratchBuffer(TfLiteContext* ctx, int buffer_idx) { + return GetMicroContext(ctx)->GetScratchBuffer(buffer_idx); +} +inline TfLiteTensor* MicroContextGetTensor(const struct TfLiteContext* context, + int tensor_idx) { + return GetMicroContext(context)->AllocateTempTfLiteTensor(tensor_idx); +} +inline TfLiteEvalTensor* MicroContextGetEvalTensor( + const struct TfLiteContext* context, int tensor_idx) { + return GetMicroContext(context)->GetEvalTensor(tensor_idx); +} +inline TfLiteExternalContext* MicroContextGetExternalContext( + TfLiteContext* context, TfLiteExternalContextType unused) { + return reinterpret_cast( + GetMicroContext(context)->external_context()); +} + +// Requests that an error be reported with format string msg. +void MicroContextReportOpError(struct TfLiteContext* context, + const char* format, ...); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_CONTEXT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_error_reporter.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_error_reporter.cpp new file mode 100644 index 000000000..5eea81406 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_error_reporter.cpp @@ -0,0 +1,41 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_error_reporter.h" + +#include +#include +#include + +namespace { +uint8_t micro_error_reporter_buffer[sizeof(tflite::MicroErrorReporter)]; +tflite::MicroErrorReporter* error_reporter_ = nullptr; + +} // namespace + +namespace tflite { +ErrorReporter* GetMicroErrorReporter() { + if (error_reporter_ == nullptr) { + error_reporter_ = new (micro_error_reporter_buffer) MicroErrorReporter(); + } + return error_reporter_; +} + +int MicroErrorReporter::Report(const char* format, va_list args) { + Log(format, args); + return 0; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_error_reporter.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_error_reporter.h new file mode 100644 index 000000000..a79f728b9 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_error_reporter.h @@ -0,0 +1,39 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_ERROR_REPORTER_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_ERROR_REPORTER_H_ + +#include + +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/micro/compatibility.h" +// TODO(b/246776144): Move this include statement to the cc file. +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { +// Get a pointer to a singleton global error reporter. +ErrorReporter* GetMicroErrorReporter(); +class MicroErrorReporter : public ErrorReporter { + public: + ~MicroErrorReporter() override {} + int Report(const char* format, va_list args) override; + + private: + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_ERROR_REPORTER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_graph.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_graph.cpp new file mode 100644 index 000000000..a52b28c28 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_graph.cpp @@ -0,0 +1,248 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_graph.h" + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_profiler.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { +namespace { + +const char* OpNameFromRegistration(const TfLiteRegistration* registration) { + if (registration->builtin_code == BuiltinOperator_CUSTOM) { + return registration->custom_name; + } else { + return EnumNameBuiltinOperator(BuiltinOperator(registration->builtin_code)); + } +} + +} // namespace + +MicroGraph::MicroGraph(TfLiteContext* context, const Model* model, + MicroAllocator* allocator, + MicroResourceVariables* resource_variables) + : context_(context), + model_(model), + allocator_(allocator), + current_subgraph_index_(0), + resource_variables_(resource_variables) { + if (model != nullptr) { + subgraphs_ = model->subgraphs(); + } +} + +MicroGraph::~MicroGraph() {} + +TfLiteStatus MicroGraph::InitSubgraphs() { + int previous_subgraph_idx = current_subgraph_index_; + + for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); + subgraph_idx++) { + current_subgraph_index_ = subgraph_idx; + uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); + for (size_t i = 0; i < operators_size; ++i) { + TfLiteNode* node = + &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); + const TfLiteRegistration* registration = + subgraph_allocations_[subgraph_idx] + .node_and_registrations[i] + .registration; + size_t init_data_size; + const char* init_data; + if (registration->builtin_code == BuiltinOperator_CUSTOM) { + init_data = reinterpret_cast(node->custom_initial_data); + init_data_size = node->custom_initial_data_size; + } else { + init_data = reinterpret_cast(node->builtin_data); + init_data_size = 0; + } + if (registration->init) { + node->user_data = + registration->init(context_, init_data, init_data_size); + } + } + } + current_subgraph_index_ = previous_subgraph_idx; + + return kTfLiteOk; +} + +TfLiteStatus MicroGraph::PrepareSubgraphs() { + int previous_subgraph_idx = current_subgraph_index_; + + for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); + subgraph_idx++) { + current_subgraph_index_ = subgraph_idx; + uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); + for (size_t i = 0; i < operators_size; ++i) { + TfLiteNode* node = + &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); + const TfLiteRegistration* registration = + subgraph_allocations_[subgraph_idx] + .node_and_registrations[i] + .registration; + if (registration->prepare != nullptr) { + TfLiteStatus prepare_status = registration->prepare(context_, node); + if (prepare_status != kTfLiteOk) { + MicroPrintf("Node %s (number %df) failed to prepare with status %d", + OpNameFromRegistration(registration), i, prepare_status); + return kTfLiteError; + } + } + allocator_->FinishPrepareNodeAllocations(/*node_id=*/i); + } + } + current_subgraph_index_ = previous_subgraph_idx; + + return kTfLiteOk; +} + +TfLiteStatus MicroGraph::FreeSubgraphs() { + int previous_subgraph_idx = current_subgraph_index_; + + for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); + subgraph_idx++) { + current_subgraph_index_ = subgraph_idx; + uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); + for (size_t i = 0; i < operators_size; ++i) { + TfLiteNode* node = + &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); + const TfLiteRegistration* registration = + subgraph_allocations_[subgraph_idx] + .node_and_registrations[i] + .registration; + // registration is allocated outside the interpreter, so double check to + // make sure it's not nullptr; + if (registration != nullptr && registration->free != nullptr) { + registration->free(context_, node->user_data); + } + } + } + current_subgraph_index_ = previous_subgraph_idx; + + return kTfLiteOk; +} + +TfLiteStatus MicroGraph::InvokeSubgraph(int subgraph_idx) { + int previous_subgraph_idx = current_subgraph_index_; + current_subgraph_index_ = subgraph_idx; + + if (static_cast(subgraph_idx) >= subgraphs_->size()) { + MicroPrintf("Accessing subgraph %d but only %d subgraphs found", + subgraph_idx, subgraphs_->size()); + return kTfLiteError; + } + uint32_t operators_size = NumSubgraphOperators(model_, subgraph_idx); + for (size_t i = 0; i < operators_size; ++i) { + TfLiteNode* node = + &(subgraph_allocations_[subgraph_idx].node_and_registrations[i].node); + const TfLiteRegistration* registration = subgraph_allocations_[subgraph_idx] + .node_and_registrations[i] + .registration; + +// This ifdef is needed (even though ScopedMicroProfiler itself is a no-op with +// -DTF_LITE_STRIP_ERROR_STRINGS) because the function OpNameFromRegistration is +// only defined for builds with the error strings. +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) + ScopedMicroProfiler scoped_profiler( + OpNameFromRegistration(registration), + reinterpret_cast(context_->profiler)); +#endif + + TFLITE_DCHECK(registration->invoke); + TfLiteStatus invoke_status = registration->invoke(context_, node); + + // All TfLiteTensor structs used in the kernel are allocated from temp + // memory in the allocator. This creates a chain of allocations in the + // temp section. The call below resets the chain of allocations to + // prepare for the next call. + allocator_->ResetTempAllocations(); + + if (invoke_status == kTfLiteError) { + MicroPrintf("Node %s (number %d) failed to invoke with status %d", + OpNameFromRegistration(registration), i, invoke_status); + return kTfLiteError; + } else if (invoke_status != kTfLiteOk) { + return invoke_status; + } + } + current_subgraph_index_ = previous_subgraph_idx; + return kTfLiteOk; +} + +TfLiteStatus MicroGraph::ResetVariableTensors() { + for (size_t subgraph_idx = 0; subgraph_idx < subgraphs_->size(); + subgraph_idx++) { + const SubGraph* subgraph = (*subgraphs_)[subgraph_idx]; + for (size_t i = 0; i < subgraph->tensors()->size(); ++i) { + auto* tensor = subgraph->tensors()->Get(i); + if (tensor->is_variable()) { + size_t buffer_size; + TF_LITE_ENSURE_STATUS(TfLiteEvalTensorByteLength( + &subgraph_allocations_[subgraph_idx].tensors[i], &buffer_size)); + + int value = 0; + if (tensor->type() == tflite::TensorType_INT8) { + value = tensor->quantization()->zero_point()->Get(0); + } + memset(subgraph_allocations_[subgraph_idx].tensors[i].data.raw, value, + buffer_size); + } + } + } + if (resource_variables_ != nullptr) { + resource_variables_->ResetAll(); + } + + return kTfLiteOk; +} + +int MicroGraph::NumSubgraphs() { return model_->subgraphs()->size(); } + +void MicroGraph::SetSubgraphAllocations( + SubgraphAllocations* subgraph_allocations) { + subgraph_allocations_ = subgraph_allocations; +} + +size_t MicroGraph::NumSubgraphInputs(int subgraph_idx) { + return model_->subgraphs()->Get(subgraph_idx)->inputs()->size(); +} + +TfLiteEvalTensor* MicroGraph::GetSubgraphInput(int subgraph_idx, + int input_idx) { + int tensor_idx = + model_->subgraphs()->Get(subgraph_idx)->inputs()->Get(input_idx); + return &subgraph_allocations_[subgraph_idx].tensors[tensor_idx]; +} + +size_t MicroGraph::NumSubgraphOutputs(int subgraph_idx) { + return model_->subgraphs()->Get(subgraph_idx)->outputs()->size(); +} + +TfLiteEvalTensor* MicroGraph::GetSubgraphOutput(int subgraph_idx, + int output_idx) { + int tensor_idx = + model_->subgraphs()->Get(subgraph_idx)->outputs()->Get(output_idx); + return &subgraph_allocations_[subgraph_idx].tensors[tensor_idx]; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_graph.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_graph.h new file mode 100644 index 000000000..942082aca --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_graph.h @@ -0,0 +1,104 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_GRAPH_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_GRAPH_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_resource_variable.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// Abstracts the details of interacting with the tflite::Model. +// +// Provides methods to access, initialize, prepare, invoke and free any +// subgraph in the tflite::Graph. +class MicroGraph { + public: + // The lifetime of the context, model, allocator and resource_variables must + // be at least as long as that of the graph object, since the this class may + // need to access them at any time. If resource_variables is a nullptr, + // GetResourceVariables will return a nullptr. + MicroGraph(TfLiteContext* context, const Model* model, + MicroAllocator* allocator, + MicroResourceVariables* resource_variables); + virtual ~MicroGraph(); + + // Sets up builtin data and calls TfLiteRegistration->Init for every operator + // in every subgraph in the model. + virtual TfLiteStatus InitSubgraphs(); + + // Calls TfLiteRegistration->Prepare for every operator in every subgraph in + // the model. + virtual TfLiteStatus PrepareSubgraphs(); + + // Calls TfLiteRegistration->Free for every operator in every subgraph in the + // model. + virtual TfLiteStatus FreeSubgraphs(); + + // Calls TfLiteRegistration->Invoke for every operator in a single subgraph in + // the model. + virtual TfLiteStatus InvokeSubgraph(int subgraph_idx); + + // Zeros out all variable tensors in all subgraphs in the model. + virtual TfLiteStatus ResetVariableTensors(); + + // Number of tensor inputs to a specified subgraph in the model. + virtual size_t NumSubgraphInputs(int subgraph_idx); + + // Get the specified input tensor of a specified subgraph in the model. + virtual TfLiteEvalTensor* GetSubgraphInput(int subgraph_idx, int input_idx); + + // Number of tensor outputs from a specified subgraph in the model. + virtual size_t NumSubgraphOutputs(int subgraph_idx); + + // Get the specified output tensor of a specified subgraph in the model. + virtual TfLiteEvalTensor* GetSubgraphOutput(int subgraph_idx, int output_idx); + + // Number of subgraphs in the model. + virtual int NumSubgraphs(); + + // Hook to pass in subgraph allocations tracked within the interpreter, + // allowing MicroGraph to init / prepare / invoke subgraphs in the model. + void SetSubgraphAllocations(SubgraphAllocations* subgraph_allocations); + + // Get the current subgraph index. Within an on operator, this is guaranteed + // to be the subgraph of that operator. + int GetCurrentSubgraphIndex() { return current_subgraph_index_; } + + // Gets the list of alloctions for each subgraph. This is the source of truth + // for all per-subgraph allocation data. + SubgraphAllocations* GetAllocations() { return subgraph_allocations_; } + + // Get the resource variables for this TFLM graph. + MicroResourceVariables* GetResourceVariables() { return resource_variables_; } + + private: + TfLiteContext* context_; + const Model* model_; + MicroAllocator* allocator_; + SubgraphAllocations* subgraph_allocations_ = nullptr; + int current_subgraph_index_; + MicroResourceVariables* resource_variables_; + const flatbuffers::Vector>* subgraphs_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_GRAPH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_interpreter.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_interpreter.cpp new file mode 100644 index 000000000..f850bd2bf --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_interpreter.cpp @@ -0,0 +1,319 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_interpreter.h" + +#include +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/tensor_utils.h" +#include "tensorflow/lite/micro/flatbuffer_utils.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_op_resolver.h" +#include "tensorflow/lite/micro/micro_profiler_interface.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include "tensorflow/lite/schema/schema_utils.h" + +namespace tflite { + +MicroInterpreter::MicroInterpreter(const Model* model, + const MicroOpResolver& op_resolver, + uint8_t* tensor_arena, + size_t tensor_arena_size, + MicroResourceVariables* resource_variables, + MicroProfilerInterface* profiler) + : model_(model), + op_resolver_(op_resolver), + allocator_(*MicroAllocator::Create(tensor_arena, tensor_arena_size)), + + graph_(&context_, model, &allocator_, resource_variables), + tensors_allocated_(false), + initialization_status_(kTfLiteError), + input_tensors_(nullptr), + output_tensors_(nullptr), + micro_context_(&allocator_, model_, &graph_) { + Init(profiler); +} + +MicroInterpreter::MicroInterpreter(const Model* model, + const MicroOpResolver& op_resolver, + MicroAllocator* allocator, + MicroResourceVariables* resource_variables, + MicroProfilerInterface* profiler) + : model_(model), + op_resolver_(op_resolver), + allocator_(*allocator), + graph_(&context_, model, allocator, resource_variables), + tensors_allocated_(false), + initialization_status_(kTfLiteError), + input_tensors_(nullptr), + output_tensors_(nullptr), + micro_context_(&allocator_, model_, &graph_) { + Init(profiler); +} + +MicroInterpreter::~MicroInterpreter() { + if (graph_.GetAllocations() != nullptr) { + graph_.FreeSubgraphs(); + } +} + +void MicroInterpreter::Init(MicroProfilerInterface* profiler) { + context_.impl_ = static_cast(µ_context_); + context_.ReportError = MicroContextReportOpError; + context_.GetTensor = MicroContextGetTensor; + context_.GetEvalTensor = MicroContextGetEvalTensor; + context_.profiler = profiler; + + initialization_status_ = kTfLiteOk; +} + +TfLiteStatus MicroInterpreter::PrepareNodeAndRegistrationDataFromFlatbuffer() { + for (int subgraph_idx = 0; subgraph_idx < graph_.NumSubgraphs(); + subgraph_idx++) { + const SubGraph* subgraph = model_->subgraphs()->Get(subgraph_idx); + TFLITE_DCHECK(subgraph != nullptr); + + auto* opcodes = model_->operator_codes(); + BuiltinDataAllocator* builtin_data_allocator = + allocator_.GetBuiltinDataAllocator(); + uint32_t operators_size = NumSubgraphOperators(subgraph); + for (size_t i = 0; i < operators_size; ++i) { + const auto* op = subgraph->operators()->Get(i); + const size_t index = op->opcode_index(); + if (index >= opcodes->size()) { + MicroPrintf("Missing registration for opcode_index %d\n", index); + return kTfLiteError; + } + const auto* opcode = opcodes->Get(index); + TfLiteStatus status = GetRegistrationFromOpCode( + opcode, op_resolver_, tflite::GetMicroErrorReporter(), + &(graph_.GetAllocations()[subgraph_idx] + .node_and_registrations[i] + .registration)); + if (status != kTfLiteOk) { + MicroPrintf("Failed to get registration from op code %s\n ", + EnumNameBuiltinOperator(GetBuiltinCode(opcode))); + return status; + } + const auto* registration = graph_.GetAllocations()[subgraph_idx] + .node_and_registrations[i] + .registration; + if (registration == nullptr) { + MicroPrintf("Skipping op for opcode_index %d\n", index); + return kTfLiteError; + } + BuiltinOperator op_type = + static_cast(registration->builtin_code); + + const char* custom_data = nullptr; + size_t custom_data_size = 0; + unsigned char* builtin_data = nullptr; + + if (op_type == BuiltinOperator_CUSTOM) { + // Custom Ops may or may not have a non-null custom_options field. + if (op->custom_options() != nullptr) { + custom_data = + reinterpret_cast(op->custom_options()->data()); + custom_data_size = op->custom_options()->size(); + } + } else { + if (op->custom_options() != nullptr) { + MicroPrintf( + "Unsupported behavior: found builtin operator %s with custom " + "options.\n", + EnumNameBuiltinOperator(op_type)); + return kTfLiteError; + } + + MicroOpResolver::BuiltinParseFunction parser = + op_resolver_.GetOpDataParser(op_type); + if (parser == nullptr) { + MicroPrintf("Did not find a parser for %s", + EnumNameBuiltinOperator(op_type)); + + return kTfLiteError; + } + TF_LITE_ENSURE_STATUS(parser(op, tflite::GetMicroErrorReporter(), + builtin_data_allocator, + (void**)(&builtin_data))); + } + + TfLiteIntArray* inputs_array = + FlatBufferVectorToTfLiteTypeArray(op->inputs()); + TfLiteIntArray* outputs_array = + FlatBufferVectorToTfLiteTypeArray(op->outputs()); + + TfLiteNode* node = &( + graph_.GetAllocations()[subgraph_idx].node_and_registrations[i].node); + *node = {}; + node->inputs = inputs_array; + node->outputs = outputs_array; + node->builtin_data = reinterpret_cast(builtin_data); + node->custom_initial_data = custom_data; + node->custom_initial_data_size = custom_data_size; + + if (op->intermediates() && (op->intermediates()->size() > 0)) { + node->intermediates = + FlatBufferVectorToTfLiteTypeArray(op->intermediates()); + } + } + } + return kTfLiteOk; +} + +TfLiteStatus MicroInterpreter::AllocateTensors() { + SubgraphAllocations* allocations = allocator_.StartModelAllocation(model_); + + graph_.SetSubgraphAllocations(allocations); + + TF_LITE_ENSURE_STATUS(PrepareNodeAndRegistrationDataFromFlatbuffer()); + + // Only allow AllocatePersistentBuffer in Init stage. + context_.AllocatePersistentBuffer = MicroContextAllocatePersistentBuffer; + context_.RequestScratchBufferInArena = nullptr; + context_.GetScratchBuffer = nullptr; + context_.GetExternalContext = nullptr; + TF_LITE_ENSURE_STATUS(graph_.InitSubgraphs()); + + // Both AllocatePersistentBuffer and RequestScratchBufferInArena is + // available in Prepare stage. + context_.RequestScratchBufferInArena = + MicroContextRequestScratchBufferInArena; + // external_context become available in Prepare stage. + context_.GetExternalContext = MicroContextGetExternalContext; + + TF_LITE_ENSURE_STATUS(graph_.PrepareSubgraphs()); + + // Prepare is done, we're ready for Invoke. Memory allocation is no longer + // allowed. Kernels can only fetch scratch buffers via GetScratchBuffer. + context_.AllocatePersistentBuffer = nullptr; + context_.RequestScratchBufferInArena = nullptr; + context_.GetScratchBuffer = MicroContextGetScratchBuffer; + + TF_LITE_ENSURE_OK(&context_, allocator_.FinishModelAllocation( + model_, graph_.GetAllocations(), + &scratch_buffer_handles_)); + + micro_context_.SetScratchBufferHandles(scratch_buffer_handles_); + + // TODO(b/162311891): Drop these allocations when the interpreter supports + // handling buffers from TfLiteEvalTensor. + input_tensors_ = + reinterpret_cast(allocator_.AllocatePersistentBuffer( + sizeof(TfLiteTensor*) * inputs_size())); + if (input_tensors_ == nullptr) { + MicroPrintf( + "Failed to allocate memory for context->input_tensors_, " + "%d bytes required", + sizeof(TfLiteTensor*) * inputs_size()); + return kTfLiteError; + } + + for (size_t i = 0; i < inputs_size(); ++i) { + input_tensors_[i] = allocator_.AllocatePersistentTfLiteTensor( + model_, graph_.GetAllocations(), inputs().Get(i), 0); + if (input_tensors_[i] == nullptr) { + MicroPrintf("Failed to initialize input tensor %d", i); + return kTfLiteError; + } + } + + // TODO(b/162311891): Drop these allocations when the interpreter supports + // handling buffers from TfLiteEvalTensor. + output_tensors_ = + reinterpret_cast(allocator_.AllocatePersistentBuffer( + sizeof(TfLiteTensor*) * outputs_size())); + if (output_tensors_ == nullptr) { + MicroPrintf( + "Failed to allocate memory for context->output_tensors_, " + "%d bytes required", + sizeof(TfLiteTensor*) * outputs_size()); + return kTfLiteError; + } + + for (size_t i = 0; i < outputs_size(); ++i) { + output_tensors_[i] = allocator_.AllocatePersistentTfLiteTensor( + model_, graph_.GetAllocations(), outputs().Get(i), 0); + if (output_tensors_[i] == nullptr) { + MicroPrintf("Failed to initialize output tensor %d", i); + return kTfLiteError; + } + } + + TF_LITE_ENSURE_STATUS(ResetVariableTensors()); + + tensors_allocated_ = true; + return kTfLiteOk; +} + +TfLiteStatus MicroInterpreter::Invoke() { + if (initialization_status_ != kTfLiteOk) { + MicroPrintf("Invoke() called after initialization failed\n"); + return kTfLiteError; + } + + // Ensure tensors are allocated before the interpreter is invoked to avoid + // difficult to debug segfaults. + if (!tensors_allocated_) { + TF_LITE_ENSURE_OK(&context_, AllocateTensors()); + } + return graph_.InvokeSubgraph(0); +} + +TfLiteTensor* MicroInterpreter::input(size_t index) { + const size_t length = inputs_size(); + if (index >= length) { + MicroPrintf("Input index %d out of range (length is %d)", index, length); + return nullptr; + } + return input_tensors_[index]; +} + +TfLiteTensor* MicroInterpreter::output(size_t index) { + const size_t length = outputs_size(); + if (index >= length) { + MicroPrintf("Output index %d out of range (length is %d)", index, length); + return nullptr; + } + return output_tensors_[index]; +} +// Repurposing free subgraphs to reset state for some ops for now +// will reset api is made. See b/220940833#comment25 for more context. +TfLiteStatus MicroInterpreter::Reset() { + TfLiteStatus status = graph_.FreeSubgraphs(); + if (status != kTfLiteOk) { + return status; + } + return graph_.ResetVariableTensors(); +} + +// TODO: remove this API completely in favor of MicroInterpreter::Reset +TfLiteStatus MicroInterpreter::ResetVariableTensors() { + return graph_.ResetVariableTensors(); +} + +TfLiteStatus MicroInterpreter::SetMicroExternalContext( + void* external_context_payload) { + return micro_context_.set_external_context(external_context_payload); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_interpreter.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_interpreter.h new file mode 100644 index 000000000..ee48a76d7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_interpreter.h @@ -0,0 +1,196 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_INTERPRETER_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_INTERPRETER_H_ + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_context.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/micro/micro_op_resolver.h" +#include "tensorflow/lite/micro/micro_profiler_interface.h" +#include "tensorflow/lite/portable_type_to_tflitetype.h" +#include "tensorflow/lite/schema/schema_generated.h" + +/// Copied from tensorflow/lite/version.h to avoid a dependency chain into +// tensorflow/core. +#define TFLITE_SCHEMA_VERSION (3) + +namespace tflite { + +class MicroInterpreter { + public: + // TODO(b/246776144): Will be removed with http://b/246776144 + MicroInterpreter(const Model* model, const MicroOpResolver& op_resolver, + uint8_t* tensor_arena, size_t tensor_arena_size, + ErrorReporter* error_reporter, + MicroResourceVariables* resource_variables = nullptr, + MicroProfilerInterface* profiler = nullptr) + : MicroInterpreter(model, op_resolver, tensor_arena, tensor_arena_size, + resource_variables, profiler) { + (void)error_reporter; + } + + // The lifetime of the model, op resolver, tensor arena, error reporter, + // resource variables, and profiler must be at least as long as that of the + // interpreter object, since the interpreter may need to access them at any + // time. This means that you should usually create them with the same scope as + // each other, for example having them all allocated on the stack as local + // variables through a top-level function. The interpreter doesn't do any + // deallocation of any of the pointed-to objects, ownership remains with the + // caller. + MicroInterpreter(const Model* model, const MicroOpResolver& op_resolver, + uint8_t* tensor_arena, size_t tensor_arena_size, + MicroResourceVariables* resource_variables = nullptr, + MicroProfilerInterface* profiler = nullptr); + + // TODO(b/246776144): Will be removed with http://b/246776144 + MicroInterpreter(const Model* model, const MicroOpResolver& op_resolver, + MicroAllocator* allocator, ErrorReporter* error_reporter, + MicroResourceVariables* resource_variables = nullptr, + MicroProfilerInterface* profiler = nullptr) + : MicroInterpreter(model, op_resolver, allocator, resource_variables, + profiler) { + (void)error_reporter; + } + + // Create an interpreter instance using an existing MicroAllocator instance. + // This constructor should be used when creating an allocator that needs to + // have allocation handled in more than one interpreter or for recording + // allocations inside the interpreter. The lifetime of the allocator must be + // as long as that of the interpreter object. + MicroInterpreter(const Model* model, const MicroOpResolver& op_resolver, + MicroAllocator* allocator, + MicroResourceVariables* resource_variables = nullptr, + MicroProfilerInterface* profiler = nullptr); + + ~MicroInterpreter(); + + // Runs through the model and allocates all necessary input, output and + // intermediate tensors. + TfLiteStatus AllocateTensors(); + + // In order to support partial graph runs for strided models, this can return + // values other than kTfLiteOk and kTfLiteError. + // TODO(b/149795762): Add this to the TfLiteStatus enum. + TfLiteStatus Invoke(); + + // This is the recommended API for an application to pass an external payload + // pointer as an external context to kernels. The life time of the payload + // pointer should be at least as long as this interpreter. TFLM supports only + // one external context. + TfLiteStatus SetMicroExternalContext(void* external_context_payload); + + TfLiteTensor* input(size_t index); + size_t inputs_size() const { + return model_->subgraphs()->Get(0)->inputs()->size(); + } + const flatbuffers::Vector& inputs() const { + return *model_->subgraphs()->Get(0)->inputs(); + } + TfLiteTensor* input_tensor(size_t index) { return input(index); } + template + T* typed_input_tensor(int tensor_index) { + if (TfLiteTensor* tensor_ptr = input_tensor(tensor_index)) { + if (tensor_ptr->type == typeToTfLiteType()) { + return GetTensorData(tensor_ptr); + } + } + return nullptr; + } + + TfLiteTensor* output(size_t index); + size_t outputs_size() const { + return model_->subgraphs()->Get(0)->outputs()->size(); + } + const flatbuffers::Vector& outputs() const { + return *model_->subgraphs()->Get(0)->outputs(); + } + TfLiteTensor* output_tensor(size_t index) { return output(index); } + template + T* typed_output_tensor(int tensor_index) { + if (TfLiteTensor* tensor_ptr = output_tensor(tensor_index)) { + if (tensor_ptr->type == typeToTfLiteType()) { + return GetTensorData(tensor_ptr); + } + } + return nullptr; + } + + // Reset the state to be what you would expect when the interpreter is first + // created. i.e. after Init and Prepare is called for the very first time. + TfLiteStatus Reset(); + + // TODO(b/244457206): remove this in favor of Reset() + // Reset all variable tensors to the default value. + TfLiteStatus ResetVariableTensors(); + + TfLiteStatus initialization_status() const { return initialization_status_; } + + // Populates node and registration pointers representing the inference graph + // of the model from values inside the flatbuffer (loaded from the TfLiteModel + // instance). Persistent data (e.g. operator data) is allocated from the + // arena. + TfLiteStatus PrepareNodeAndRegistrationDataFromFlatbuffer(); + + // For debugging only. + // Returns the actual used arena in bytes. This method gives the optimal arena + // size. It's only available after `AllocateTensors` has been called. + // Note that normally `tensor_arena` requires 16 bytes alignment to fully + // utilize the space. If it's not the case, the optimial arena size would be + // arena_used_bytes() + 16. + size_t arena_used_bytes() const { return allocator_.used_bytes(); } + + protected: + const MicroAllocator& allocator() const { return allocator_; } + const TfLiteContext& context() const { return context_; } + + private: + // TODO(b/158263161): Consider switching to Create() function to enable better + // error reporting during initialization. + void Init(MicroProfilerInterface* profiler); + + // Gets the current subgraph index used from within context methods. + int get_subgraph_index() { return graph_.GetCurrentSubgraphIndex(); } + + const Model* model_; + const MicroOpResolver& op_resolver_; + TfLiteContext context_ = {}; + MicroAllocator& allocator_; + MicroGraph graph_; + bool tensors_allocated_; + + TfLiteStatus initialization_status_; + + ScratchBufferHandle* scratch_buffer_handles_ = nullptr; + + // TODO(b/162311891): Clean these pointers up when this class supports buffers + // from TfLiteEvalTensor. + TfLiteTensor** input_tensors_; + TfLiteTensor** output_tensors_; + + MicroContext micro_context_; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_INTERPRETER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_log.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_log.cpp new file mode 100644 index 000000000..9c8ccaa3c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_log.cpp @@ -0,0 +1,47 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_log.h" + +#include +#include +#include + +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) +#include "tensorflow/lite/micro/debug_log.h" +#include "tensorflow/lite/micro/micro_string.h" +#endif + +void Log(const char* format, va_list args) { +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) + // Only pulling in the implementation of this function for builds where we + // expect to make use of it to be extra cautious about not increasing the code + // size. + static constexpr int kMaxLogLen = 256; + char log_buffer[kMaxLogLen]; + MicroVsnprintf(log_buffer, kMaxLogLen, format, args); + DebugLog(log_buffer); + DebugLog("\r\n"); +#endif +} + +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) +void MicroPrintf(const char* format, ...) { + va_list args; + va_start(args, format); + Log(format, args); + va_end(args); +} +#endif diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_log.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_log.h new file mode 100644 index 000000000..d9cfbe8c0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_log.h @@ -0,0 +1,44 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_LOG_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_LOG_H_ + +#include + +// This is a free function used to perform the actual logging. +// This function will be used by MicroPrintf and MicroErrorReporter::Report() +void Log(const char* format, va_list args); + +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) +// This function can be used independent of the MicroErrorReporter to get +// printf-like functionalitys and are common to all target platforms. +void MicroPrintf(const char* format, ...); +#else +// We use a #define to ensure that the strings are completely stripped, to +// prevent an unnecessary increase in the binary size. +#define MicroPrintf(...) tflite::Unused(__VA_ARGS__) +#endif + +namespace tflite { + +// From +// https://stackoverflow.com/questions/23235910/variadic-unused-function-macro +template +void Unused(Args&&... args) { + (void)(sizeof...(args)); +} +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_LOG_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_mutable_op_resolver.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_mutable_op_resolver.h new file mode 100644 index 000000000..9093a97e0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_mutable_op_resolver.h @@ -0,0 +1,652 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_MUTABLE_OP_RESOLVER_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_MUTABLE_OP_RESOLVER_H_ + +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/flatbuffer_conversions.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/kernels/add.h" +#include "tensorflow/lite/micro/kernels/conv.h" +#include "tensorflow/lite/micro/kernels/depthwise_conv.h" +#include "tensorflow/lite/micro/kernels/ethosu.h" +#include "tensorflow/lite/micro/kernels/fully_connected.h" +#include "tensorflow/lite/micro/kernels/micro_ops.h" +#include "tensorflow/lite/micro/kernels/pooling.h" +#include "tensorflow/lite/micro/kernels/reduce.h" +#include "tensorflow/lite/micro/kernels/softmax.h" +#include "tensorflow/lite/micro/micro_error_reporter.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_op_resolver.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { +TfLiteRegistration* Register_DETECTION_POSTPROCESS(); + +template +class MicroMutableOpResolver : public MicroOpResolver { + public: + TF_LITE_REMOVE_VIRTUAL_DELETE + + // TODO(b/246776144): Will be removed with http://b/246776144 + explicit MicroMutableOpResolver(ErrorReporter* error_reporter = nullptr) { + (void)error_reporter; + } + + // explicit MicroMutableOpResolver() {} + + const TfLiteRegistration* FindOp(tflite::BuiltinOperator op) const override { + if (op == BuiltinOperator_CUSTOM) return nullptr; + + for (unsigned int i = 0; i < registrations_len_; ++i) { + const TfLiteRegistration& registration = registrations_[i]; + if (registration.builtin_code == op) { + return ®istration; + } + } + return nullptr; + } + + const TfLiteRegistration* FindOp(const char* op) const override { + for (unsigned int i = 0; i < registrations_len_; ++i) { + const TfLiteRegistration& registration = registrations_[i]; + if ((registration.builtin_code == BuiltinOperator_CUSTOM) && + (strcmp(registration.custom_name, op) == 0)) { + return ®istration; + } + } + return nullptr; + } + + MicroOpResolver::BuiltinParseFunction GetOpDataParser( + BuiltinOperator op) const override { + TFLITE_DCHECK(num_buitin_ops_ <= tOpCount); + for (unsigned int i = 0; i < num_buitin_ops_; ++i) { + if (builtin_codes_[i] == op) return builtin_parsers_[i]; + } + return nullptr; + } + + // Registers a Custom Operator with the MicroOpResolver. + // + // Only the first call for a given name will be successful. i.e. if this + // function is called again for a previously added Custom Operator, the + // MicroOpResolver will be unchanged and this function will return + // kTfLiteError. + TfLiteStatus AddCustom(const char* name, TfLiteRegistration* registration) { + if (registrations_len_ >= tOpCount) { + MicroPrintf( + "Couldn't register custom op '%s', resolver size is too" + "small (%d)", + name, tOpCount); + return kTfLiteError; + } + + if (FindOp(name) != nullptr) { + MicroPrintf("Calling AddCustom for the same op more than once "); + MicroPrintf("is not supported (Op: %s).", name); + return kTfLiteError; + } + + TfLiteRegistration* new_registration = ®istrations_[registrations_len_]; + registrations_len_ += 1; + + *new_registration = *registration; + new_registration->builtin_code = BuiltinOperator_CUSTOM; + new_registration->custom_name = name; + return kTfLiteOk; + } + + // The Add* functions below add the various Builtin operators to the + // MicroMutableOpResolver object. + + TfLiteStatus AddAbs() { + return AddBuiltin(BuiltinOperator_ABS, tflite::ops::micro::Register_ABS(), + ParseAbs); + } + + TfLiteStatus AddAdd(const TfLiteRegistration& registration = Register_ADD()) { + return AddBuiltin(BuiltinOperator_ADD, registration, ParseAdd); + } + + TfLiteStatus AddAddN() { + return AddBuiltin(BuiltinOperator_ADD_N, tflite::Register_ADD_N(), + ParseAddN); + } + + TfLiteStatus AddArgMax() { + return AddBuiltin(BuiltinOperator_ARG_MAX, + tflite::ops::micro::Register_ARG_MAX(), ParseArgMax); + } + + TfLiteStatus AddArgMin() { + return AddBuiltin(BuiltinOperator_ARG_MIN, + tflite::ops::micro::Register_ARG_MIN(), ParseArgMin); + } + + TfLiteStatus AddAssignVariable() { + return AddBuiltin(BuiltinOperator_ASSIGN_VARIABLE, + tflite::Register_ASSIGN_VARIABLE(), ParseAssignVariable); + } + + TfLiteStatus AddAveragePool2D( + const TfLiteRegistration& registration = Register_AVERAGE_POOL_2D()) { + return AddBuiltin(BuiltinOperator_AVERAGE_POOL_2D, registration, ParsePool); + } + + TfLiteStatus AddBatchToSpaceNd() { + return AddBuiltin(BuiltinOperator_BATCH_TO_SPACE_ND, + Register_BATCH_TO_SPACE_ND(), ParseBatchToSpaceNd); + } + + TfLiteStatus AddBroadcastArgs() { + return AddBuiltin(BuiltinOperator_BROADCAST_ARGS, Register_BROADCAST_ARGS(), + ParseBroadcastArgs); + } + + TfLiteStatus AddBroadcastTo() { + return AddBuiltin(BuiltinOperator_BROADCAST_TO, Register_BROADCAST_TO(), + ParseBroadcastTo); + } + + TfLiteStatus AddCallOnce() { + return AddBuiltin(BuiltinOperator_CALL_ONCE, Register_CALL_ONCE(), + ParseCallOnce); + } + + TfLiteStatus AddCast() { + return AddBuiltin(BuiltinOperator_CAST, Register_CAST(), ParseCast); + } + + TfLiteStatus AddCeil() { + return AddBuiltin(BuiltinOperator_CEIL, tflite::ops::micro::Register_CEIL(), + ParseCeil); + } + + TfLiteStatus AddCircularBuffer() { + return AddCustom("CIRCULAR_BUFFER", tflite::Register_CIRCULAR_BUFFER()); + } + + TfLiteStatus AddConcatenation() { + return AddBuiltin(BuiltinOperator_CONCATENATION, + tflite::ops::micro::Register_CONCATENATION(), + ParseConcatenation); + } + + TfLiteStatus AddConv2D( + const TfLiteRegistration& registration = Register_CONV_2D()) { + return AddBuiltin(BuiltinOperator_CONV_2D, registration, ParseConv2D); + } + + TfLiteStatus AddCos() { + return AddBuiltin(BuiltinOperator_COS, tflite::ops::micro::Register_COS(), + ParseCos); + } + + TfLiteStatus AddCumSum() { + return AddBuiltin(BuiltinOperator_CUMSUM, tflite::Register_CUMSUM(), + ParseCumsum); + } + + TfLiteStatus AddDepthToSpace() { + return AddBuiltin(BuiltinOperator_DEPTH_TO_SPACE, + tflite::Register_DEPTH_TO_SPACE(), ParseDepthToSpace); + } + + TfLiteStatus AddDepthwiseConv2D( + const TfLiteRegistration& registration = Register_DEPTHWISE_CONV_2D()) { + return AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, registration, + ParseDepthwiseConv2D); + } + + TfLiteStatus AddDequantize() { + return AddBuiltin(BuiltinOperator_DEQUANTIZE, tflite::Register_DEQUANTIZE(), + ParseDequantize); + } + + TfLiteStatus AddDetectionPostprocess() { + return AddCustom("TFLite_Detection_PostProcess", + tflite::Register_DETECTION_POSTPROCESS()); + } + + TfLiteStatus AddDiv() { + return AddBuiltin(BuiltinOperator_DIV, tflite::Register_DIV(), ParseDiv); + } + + TfLiteStatus AddElu() { + return AddBuiltin(BuiltinOperator_ELU, tflite::Register_ELU(), ParseElu); + } + + TfLiteStatus AddEqual() { + return AddBuiltin(BuiltinOperator_EQUAL, + tflite::ops::micro::Register_EQUAL(), ParseEqual); + } + + TfLiteStatus AddEthosU() { + TfLiteRegistration* registration = tflite::Register_ETHOSU(); + if (registration) { + return AddCustom(tflite::GetString_ETHOSU(), registration); + } + return kTfLiteOk; + } + + TfLiteStatus AddExp() { + return AddBuiltin(BuiltinOperator_EXP, Register_EXP(), ParseExp); + } + + TfLiteStatus AddExpandDims() { + return AddBuiltin(BuiltinOperator_EXPAND_DIMS, Register_EXPAND_DIMS(), + ParseExpandDims); + } + + TfLiteStatus AddFill() { + return AddBuiltin(BuiltinOperator_FILL, tflite::Register_FILL(), ParseFill); + } + + TfLiteStatus AddFloor() { + return AddBuiltin(BuiltinOperator_FLOOR, + tflite::ops::micro::Register_FLOOR(), ParseFloor); + } + + TfLiteStatus AddFloorDiv() { + return AddBuiltin(BuiltinOperator_FLOOR_DIV, tflite::Register_FLOOR_DIV(), + ParseFloorDiv); + } + + TfLiteStatus AddFloorMod() { + return AddBuiltin(BuiltinOperator_FLOOR_MOD, tflite::Register_FLOOR_MOD(), + ParseFloorMod); + } + + TfLiteStatus AddFullyConnected( + const TfLiteRegistration& registration = Register_FULLY_CONNECTED()) { + return AddBuiltin(BuiltinOperator_FULLY_CONNECTED, registration, + ParseFullyConnected); + } + + TfLiteStatus AddGather() { + return AddBuiltin(BuiltinOperator_GATHER, tflite::Register_GATHER(), + ParseGather); + } + + TfLiteStatus AddGatherNd() { + return AddBuiltin(BuiltinOperator_GATHER_ND, tflite::Register_GATHER_ND(), + ParseGatherNd); + } + + TfLiteStatus AddGreater() { + return AddBuiltin(BuiltinOperator_GREATER, + tflite::ops::micro::Register_GREATER(), ParseGreater); + } + + TfLiteStatus AddGreaterEqual() { + return AddBuiltin(BuiltinOperator_GREATER_EQUAL, + tflite::ops::micro::Register_GREATER_EQUAL(), + ParseGreaterEqual); + } + + TfLiteStatus AddHardSwish() { + return AddBuiltin(BuiltinOperator_HARD_SWISH, tflite::Register_HARD_SWISH(), + ParseHardSwish); + } + + TfLiteStatus AddIf() { + return AddBuiltin(BuiltinOperator_IF, tflite::Register_IF(), ParseIf); + } + + TfLiteStatus AddL2Normalization() { + return AddBuiltin(BuiltinOperator_L2_NORMALIZATION, + tflite::ops::micro::Register_L2_NORMALIZATION(), + ParseL2Normalization); + } + + TfLiteStatus AddL2Pool2D() { + return AddBuiltin(BuiltinOperator_L2_POOL_2D, tflite::Register_L2_POOL_2D(), + ParsePool); + } + + TfLiteStatus AddLeakyRelu() { + return AddBuiltin(BuiltinOperator_LEAKY_RELU, tflite::Register_LEAKY_RELU(), + ParseLeakyRelu); + } + + TfLiteStatus AddLess() { + return AddBuiltin(BuiltinOperator_LESS, tflite::ops::micro::Register_LESS(), + ParseLess); + } + + TfLiteStatus AddLessEqual() { + return AddBuiltin(BuiltinOperator_LESS_EQUAL, + tflite::ops::micro::Register_LESS_EQUAL(), + ParseLessEqual); + } + + TfLiteStatus AddLog() { + return AddBuiltin(BuiltinOperator_LOG, tflite::ops::micro::Register_LOG(), + ParseLog); + } + + TfLiteStatus AddLogicalAnd() { + return AddBuiltin(BuiltinOperator_LOGICAL_AND, + tflite::Register_LOGICAL_AND(), ParseLogicalAnd); + } + + TfLiteStatus AddLogicalNot() { + return AddBuiltin(BuiltinOperator_LOGICAL_NOT, + tflite::ops::micro::Register_LOGICAL_NOT(), + ParseLogicalNot); + } + + TfLiteStatus AddLogicalOr() { + return AddBuiltin(BuiltinOperator_LOGICAL_OR, tflite::Register_LOGICAL_OR(), + ParseLogicalOr); + } + + TfLiteStatus AddLogistic() { + return AddBuiltin(BuiltinOperator_LOGISTIC, tflite::Register_LOGISTIC(), + ParseLogistic); + } + + TfLiteStatus AddLogSoftmax() { + return AddBuiltin(BuiltinOperator_LOG_SOFTMAX, + tflite::Register_LOG_SOFTMAX(), ParseLogSoftmax); + } + + TfLiteStatus AddMaximum() { + return AddBuiltin(BuiltinOperator_MAXIMUM, + tflite::ops::micro::Register_MAXIMUM(), ParseMaximum); + } + + TfLiteStatus AddMaxPool2D( + const TfLiteRegistration& registration = Register_MAX_POOL_2D()) { + return AddBuiltin(BuiltinOperator_MAX_POOL_2D, registration, ParsePool); + } + + TfLiteStatus AddMirrorPad() { + return AddBuiltin(BuiltinOperator_MIRROR_PAD, tflite::Register_MIRROR_PAD(), + ParseMirrorPad); + } + + TfLiteStatus AddMean() { + return AddBuiltin(BuiltinOperator_MEAN, Register_MEAN(), ParseReducer); + } + + TfLiteStatus AddMinimum() { + return AddBuiltin(BuiltinOperator_MINIMUM, + tflite::ops::micro::Register_MINIMUM(), ParseMinimum); + } + + TfLiteStatus AddMul(const TfLiteRegistration& registration = Register_MUL()) { + return AddBuiltin(BuiltinOperator_MUL, registration, ParseMul); + } + + TfLiteStatus AddNeg() { + return AddBuiltin(BuiltinOperator_NEG, tflite::ops::micro::Register_NEG(), + ParseNeg); + } + + TfLiteStatus AddNotEqual() { + return AddBuiltin(BuiltinOperator_NOT_EQUAL, + tflite::ops::micro::Register_NOT_EQUAL(), ParseNotEqual); + } + + TfLiteStatus AddPack() { + return AddBuiltin(BuiltinOperator_PACK, tflite::ops::micro::Register_PACK(), + ParsePack); + } + + TfLiteStatus AddPad() { + return AddBuiltin(BuiltinOperator_PAD, tflite::ops::micro::Register_PAD(), + ParsePad); + } + + TfLiteStatus AddPadV2() { + return AddBuiltin(BuiltinOperator_PADV2, + tflite::ops::micro::Register_PADV2(), ParsePadV2); + } + + TfLiteStatus AddPrelu() { + return AddBuiltin(BuiltinOperator_PRELU, tflite::Register_PRELU(), + ParsePrelu); + } + + TfLiteStatus AddQuantize() { + return AddBuiltin(BuiltinOperator_QUANTIZE, Register_QUANTIZE(), + ParseQuantize); + } + + TfLiteStatus AddReadVariable() { + return AddBuiltin(BuiltinOperator_READ_VARIABLE, + tflite::Register_READ_VARIABLE(), ParseReadVariable); + } + + TfLiteStatus AddReduceMax() { + return AddBuiltin(BuiltinOperator_REDUCE_MAX, Register_REDUCE_MAX(), + ParseReducer); + } + + TfLiteStatus AddRelu() { + return AddBuiltin(BuiltinOperator_RELU, tflite::Register_RELU(), ParseRelu); + } + + TfLiteStatus AddRelu6() { + return AddBuiltin(BuiltinOperator_RELU6, tflite::Register_RELU6(), + ParseRelu6); + } + + TfLiteStatus AddReshape() { + return AddBuiltin(BuiltinOperator_RESHAPE, + tflite::ops::micro::Register_RESHAPE(), ParseReshape); + } + + TfLiteStatus AddResizeBilinear() { + return AddBuiltin(BuiltinOperator_RESIZE_BILINEAR, + Register_RESIZE_BILINEAR(), ParseResizeBilinear); + } + + TfLiteStatus AddResizeNearestNeighbor() { + return AddBuiltin(BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, + tflite::ops::micro::Register_RESIZE_NEAREST_NEIGHBOR(), + ParseResizeNearestNeighbor); + } + + TfLiteStatus AddRound() { + return AddBuiltin(BuiltinOperator_ROUND, + tflite::ops::micro::Register_ROUND(), ParseRound); + } + + TfLiteStatus AddRsqrt() { + return AddBuiltin(BuiltinOperator_RSQRT, + tflite::ops::micro::Register_RSQRT(), ParseRsqrt); + } + + TfLiteStatus AddSelectV2() { + return AddBuiltin(BuiltinOperator_SELECT_V2, Register_SELECT_V2(), + ParseSelectV2); + } + + TfLiteStatus AddShape() { + return AddBuiltin(BuiltinOperator_SHAPE, Register_SHAPE(), ParseShape); + } + + TfLiteStatus AddSin() { + return AddBuiltin(BuiltinOperator_SIN, tflite::ops::micro::Register_SIN(), + ParseSin); + } + + TfLiteStatus AddSlice() { + return AddBuiltin(BuiltinOperator_SLICE, Register_SLICE(), ParseSlice); + } + + TfLiteStatus AddSoftmax( + const TfLiteRegistration& registration = Register_SOFTMAX()) { + return AddBuiltin(BuiltinOperator_SOFTMAX, registration, ParseSoftmax); + } + + TfLiteStatus AddSpaceToBatchNd() { + return AddBuiltin(BuiltinOperator_SPACE_TO_BATCH_ND, + Register_SPACE_TO_BATCH_ND(), ParseSpaceToBatchNd); + } + + TfLiteStatus AddSpaceToDepth() { + return AddBuiltin(BuiltinOperator_SPACE_TO_DEPTH, Register_SPACE_TO_DEPTH(), + ParseSpaceToDepth); + } + + TfLiteStatus AddSplit() { + return AddBuiltin(BuiltinOperator_SPLIT, + tflite::ops::micro::Register_SPLIT(), ParseSplit); + } + + TfLiteStatus AddSplitV() { + return AddBuiltin(BuiltinOperator_SPLIT_V, + tflite::ops::micro::Register_SPLIT_V(), ParseSplitV); + } + + TfLiteStatus AddSqueeze() { + return AddBuiltin(BuiltinOperator_SQUEEZE, Register_SQUEEZE(), + ParseSqueeze); + } + + TfLiteStatus AddSqrt() { + return AddBuiltin(BuiltinOperator_SQRT, tflite::ops::micro::Register_SQRT(), + ParseSqrt); + } + + TfLiteStatus AddSquare() { + return AddBuiltin(BuiltinOperator_SQUARE, + tflite::ops::micro::Register_SQUARE(), ParseSquare); + } + + TfLiteStatus AddSquaredDifference() { + return AddBuiltin(BuiltinOperator_SQUARED_DIFFERENCE, + tflite::Register_SQUARED_DIFFERENCE(), + ParseSquaredDifference); + } + + TfLiteStatus AddStridedSlice() { + return AddBuiltin(BuiltinOperator_STRIDED_SLICE, + tflite::ops::micro::Register_STRIDED_SLICE(), + ParseStridedSlice); + } + + TfLiteStatus AddSub() { + return AddBuiltin(BuiltinOperator_SUB, tflite::Register_SUB(), ParseSub); + } + + TfLiteStatus AddSum() { + return AddBuiltin(BuiltinOperator_SUM, Register_SUM(), ParseReducer); + } + + TfLiteStatus AddSvdf( + const TfLiteRegistration& registration = Register_SVDF()) { + return AddBuiltin(BuiltinOperator_SVDF, registration, ParseSvdf); + } + + TfLiteStatus AddTanh() { + return AddBuiltin(BuiltinOperator_TANH, tflite::ops::micro::Register_TANH(), + ParseTanh); + } + + TfLiteStatus AddTransposeConv() { + return AddBuiltin(BuiltinOperator_TRANSPOSE_CONV, + tflite::Register_TRANSPOSE_CONV(), ParseTransposeConv); + } + + TfLiteStatus AddTranspose() { + return AddBuiltin(BuiltinOperator_TRANSPOSE, Register_TRANSPOSE(), + ParseTranspose); + } + + TfLiteStatus AddUnpack() { + return AddBuiltin(BuiltinOperator_UNPACK, + tflite::ops::micro::Register_UNPACK(), ParseUnpack); + } + + TfLiteStatus AddUnidirectionalSequenceLSTM() { + return AddBuiltin(BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + Register_UNIDIRECTIONAL_SEQUENCE_LSTM(), + ParseUnidirectionalSequenceLSTM); + } + + TfLiteStatus AddVarHandle() { + return AddBuiltin(BuiltinOperator_VAR_HANDLE, Register_VAR_HANDLE(), + ParseVarHandle); + } + + TfLiteStatus AddWhile() { + return AddBuiltin(BuiltinOperator_WHILE, Register_WHILE(), ParseWhile); + } + + TfLiteStatus AddZerosLike() { + return AddBuiltin(BuiltinOperator_ZEROS_LIKE, Register_ZEROS_LIKE(), + ParseZerosLike); + } + + unsigned int GetRegistrationLength() { return registrations_len_; } + + private: + TfLiteStatus AddBuiltin(tflite::BuiltinOperator op, + const TfLiteRegistration& registration, + MicroOpResolver::BuiltinParseFunction parser) { + if (op == BuiltinOperator_CUSTOM) { + MicroPrintf("Invalid parameter BuiltinOperator_CUSTOM to the "); + MicroPrintf("AddBuiltin function."); + return kTfLiteError; + } + + if (FindOp(op) != nullptr) { + MicroPrintf("Calling AddBuiltin with the same op more than "); + MicroPrintf("once is not supported (Op: #%d).", op); + return kTfLiteError; + } + + if (registrations_len_ >= tOpCount) { + MicroPrintf("Couldn't register builtin op #%d, resolver size ", op); + MicroPrintf("is too small (%d).", tOpCount); + return kTfLiteError; + } + + registrations_[registrations_len_] = registration; + // Strictly speaking, the builtin_code is not necessary for TFLM but filling + // it in regardless. + registrations_[registrations_len_].builtin_code = op; + registrations_len_++; + + builtin_codes_[num_buitin_ops_] = op; + builtin_parsers_[num_buitin_ops_] = parser; + num_buitin_ops_++; + + return kTfLiteOk; + } + + TfLiteRegistration registrations_[tOpCount]; + unsigned int registrations_len_ = 0; + + // Arrays (and counter) to store the builtin codes and their corresponding + // parse functions as these are registered with the Op Resolver. + BuiltinOperator builtin_codes_[tOpCount]; + MicroOpResolver::BuiltinParseFunction builtin_parsers_[tOpCount]; + unsigned int num_buitin_ops_ = 0; +}; + +}; // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_MUTABLE_OP_RESOLVER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_op_resolver.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_op_resolver.h new file mode 100644 index 000000000..757b6b894 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_op_resolver.h @@ -0,0 +1,73 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_OP_RESOLVER_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_OP_RESOLVER_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/core/api/flatbuffer_conversions.h" +#include "tensorflow/lite/core/api/op_resolver.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// This is an interface for the OpResolver for TFLiteMicro. The differences from +// the TFLite OpResolver base class are to: +// * explicitly remove support for Op versions +// * allow for finer grained registration of the Builtin Ops to reduce code +// size for TFLiteMicro. +// +// We need an interface class instead of directly using MicroMutableOpResolver +// because MicroMutableOpResolver is a class template with the number of +// registered Ops as the template parameter. +class MicroOpResolver : public OpResolver { + public: + typedef TfLiteStatus (*BuiltinParseFunction)(const Operator* op, + ErrorReporter* error_reporter, + BuiltinDataAllocator* allocator, + void** builtin_data); + + // Returns the Op registration struct corresponding to the enum code from the + // flatbuffer schema. Returns nullptr if the op is not found or if op == + // BuiltinOperator_CUSTOM. + virtual const TfLiteRegistration* FindOp(BuiltinOperator op) const = 0; + + // Returns the Op registration struct corresponding to the custom operator by + // name. + virtual const TfLiteRegistration* FindOp(const char* op) const = 0; + + // This implementation exists for compatibility with the OpResolver base class + // and disregards the version parameter. + const TfLiteRegistration* FindOp(BuiltinOperator op, + int version) const final { + return FindOp(op); + } + + // This implementation exists for compatibility with the OpResolver base class + // and disregards the version parameter. + const TfLiteRegistration* FindOp(const char* op, int version) const final { + return FindOp(op); + } + + // Returns the operator specific parsing function for the OpData for a + // BuiltinOperator (if registered), else nullptr. + virtual BuiltinParseFunction GetOpDataParser(BuiltinOperator op) const = 0; + + ~MicroOpResolver() override {} +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_OP_RESOLVER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler.cpp new file mode 100644 index 000000000..e9eb5e549 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler.cpp @@ -0,0 +1,115 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_profiler.h" + +#include +#include +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_time.h" + +namespace tflite { + +uint32_t MicroProfiler::BeginEvent(const char* tag) { + if (num_events_ == kMaxEvents) { + num_events_ = 0; + } + + tags_[num_events_] = tag; + start_ticks_[num_events_] = GetCurrentTimeTicks(); + end_ticks_[num_events_] = start_ticks_[num_events_] - 1; + return num_events_++; +} + +void MicroProfiler::EndEvent(uint32_t event_handle) { + TFLITE_DCHECK(event_handle < kMaxEvents); + end_ticks_[event_handle] = GetCurrentTimeTicks(); +} + +uint32_t MicroProfiler::GetTotalTicks() const { + int32_t ticks = 0; + for (int i = 0; i < num_events_; ++i) { + ticks += end_ticks_[i] - start_ticks_[i]; + } + return ticks; +} + +void MicroProfiler::Log() const { +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) + for (int i = 0; i < num_events_; ++i) { + uint32_t ticks = end_ticks_[i] - start_ticks_[i]; + MicroPrintf("%s took %" PRIu32 " ticks (%d ms).", tags_[i], ticks, + TicksToMs(ticks)); + } +#endif +} + +void MicroProfiler::LogCsv() const { +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) + MicroPrintf("\"Event\",\"Tag\",\"Ticks\""); + for (int i = 0; i < num_events_; ++i) { + uint32_t ticks = end_ticks_[i] - start_ticks_[i]; + MicroPrintf("%d,%s,%" PRIu32, i, tags_[i], ticks); + } +#endif +} + +void MicroProfiler::LogTicksPerTagCsv() { +#if !defined(TF_LITE_STRIP_ERROR_STRINGS) + MicroPrintf( + "\"Unique Tag\",\"Total ticks across all events with that tag.\""); + int total_ticks = 0; + for (int i = 0; i < num_events_; ++i) { + uint32_t ticks = end_ticks_[i] - start_ticks_[i]; + TFLITE_DCHECK(tags_[i] != nullptr); + int position = FindExistingOrNextPosition(tags_[i]); + TFLITE_DCHECK(position >= 0); + total_ticks_per_tag[position].tag = tags_[i]; + total_ticks_per_tag[position].ticks = + total_ticks_per_tag[position].ticks + ticks; + total_ticks += ticks; + } + + for (int i = 0; i < num_events_; ++i) { + TicksPerTag each_tag_entry = total_ticks_per_tag[i]; + if (each_tag_entry.tag == nullptr) { + break; + } + MicroPrintf("%s, %d", each_tag_entry.tag, each_tag_entry.ticks); + } + MicroPrintf("total number of ticks, %d", total_ticks); +#endif +} + +// This method finds a particular array element in the total_ticks_per_tag array +// with the matching tag_name passed in the method. If it can find a +// matching array element that has the same tag_name, then it will return the +// position of the matching element. But if it unable to find a matching element +// with the given tag_name, it will return the next available empty position +// from the array. +int MicroProfiler::FindExistingOrNextPosition(const char* tag_name) { + int pos = 0; + for (; pos < num_events_; pos++) { + TicksPerTag each_tag_entry = total_ticks_per_tag[pos]; + if (each_tag_entry.tag == nullptr || + strcmp(each_tag_entry.tag, tag_name) == 0) { + return pos; + } + } + return pos < num_events_ ? pos : -1; +} +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler.h new file mode 100644 index 000000000..0648588c4 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler.h @@ -0,0 +1,138 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_PROFILER_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_PROFILER_H_ + +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/micro_profiler_interface.h" + +namespace tflite { + +// MicroProfiler creates a common way to gain fine-grained insight into runtime +// performance. Bottleck operators can be identified along with slow code +// sections. This can be used in conjunction with running the relevant micro +// benchmark to evaluate end-to-end performance. +class MicroProfiler : public MicroProfilerInterface { + public: + MicroProfiler() = default; + virtual ~MicroProfiler() = default; + + // Marks the start of a new event and returns an event handle that can be used + // to mark the end of the event via EndEvent. The lifetime of the tag + // parameter must exceed that of the MicroProfiler. + virtual uint32_t BeginEvent(const char* tag) override; + + // Marks the end of an event associated with event_handle. It is the + // responsibility of the caller to ensure than EndEvent is called once and + // only once per event_handle. + // + // If EndEvent is called more than once for the same event_handle, the last + // call will be used as the end of event marker.If EndEvent is called 0 times + // for a particular event_handle, the duration of that event will be 0 ticks. + virtual void EndEvent(uint32_t event_handle) override; + + // Clears all the events that have been currently profiled. + void ClearEvents() { num_events_ = 0; } + + // Returns the sum of the ticks taken across all the events. This number + // is only meaningful if all of the events are disjoint (the end time of + // event[i] <= start time of event[i+1]). + uint32_t GetTotalTicks() const; + + // Prints the profiling information of each of the events in human readable + // form. + void Log() const; + + // Prints the profiling information of each of the events in CSV (Comma + // Separated Value) form. + void LogCsv() const; + + // Prints total ticks for each unique tag in CSV format. + // Output will have one row for each unique tag along with the + // total ticks summed across all events with that particular tag. + void LogTicksPerTagCsv(); + + private: + // Maximum number of events that this class can keep track of. If we call + // AddEvent more than kMaxEvents number of times, then the oldest event's + // profiling information will be overwritten. + static constexpr int kMaxEvents = 1024; + + const char* tags_[kMaxEvents]; + uint32_t start_ticks_[kMaxEvents]; + uint32_t end_ticks_[kMaxEvents]; + int num_events_ = 0; + + struct TicksPerTag { + const char* tag; + uint32_t ticks; + }; + // In practice, the number of tags will be much lower than the number of + // events. But it is theoretically possible that each event to be unique and + // hence we allow total_ticks_per_tag to have kMaxEvents entries. + TicksPerTag total_ticks_per_tag[kMaxEvents] = {}; + + int FindExistingOrNextPosition(const char* tag_name); + + TF_LITE_REMOVE_VIRTUAL_DELETE; +}; + +#if defined(TF_LITE_STRIP_ERROR_STRINGS) +// For release builds, the ScopedMicroProfiler is a noop. +// +// This is done because the ScipedProfiler is used as part of the +// MicroInterpreter and we want to ensure zero overhead for the release builds. +class ScopedMicroProfiler { + public: + explicit ScopedMicroProfiler(const char* tag, MicroProfiler* profiler) {} +}; + +#else + +// This class can be used to add events to a MicroProfiler object that span the +// lifetime of the ScopedMicroProfiler object. +// Usage example: +// +// MicroProfiler profiler(); +// ... +// { +// ScopedMicroProfiler scoped_profiler("custom_tag", profiler); +// work_to_profile(); +// } +class ScopedMicroProfiler { + public: + explicit ScopedMicroProfiler(const char* tag, MicroProfiler* profiler) + : profiler_(profiler) { + if (profiler_ != nullptr) { + event_handle_ = profiler_->BeginEvent(tag); + } + } + + ~ScopedMicroProfiler() { + if (profiler_ != nullptr) { + profiler_->EndEvent(event_handle_); + } + } + + private: + uint32_t event_handle_ = 0; + MicroProfiler* profiler_ = nullptr; +}; +#endif // !defined(TF_LITE_STRIP_ERROR_STRINGS) + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_PROFILER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler_interface.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler_interface.h new file mode 100644 index 000000000..f839a74ae --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_profiler_interface.h @@ -0,0 +1,38 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_PROFILER_INTERFACE_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_PROFILER_INTERFACE_H_ + +#include + +namespace tflite { + +// Interface class that the TFLM framework relies on for profiling. +class MicroProfilerInterface { + public: + virtual ~MicroProfilerInterface() {} + + // Marks the start of a new event and returns an event handle that can be used + // to mark the end of the event via EndEvent. + virtual uint32_t BeginEvent(const char* tag) = 0; + + // Marks the end of an event associated with event_handle. + virtual void EndEvent(uint32_t event_handle) = 0; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_PROFILER_INTERFACE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_resource_variable.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_resource_variable.cpp new file mode 100644 index 000000000..e6cea845b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_resource_variable.cpp @@ -0,0 +1,148 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_resource_variable.h" + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +namespace {} // namespace + +MicroResourceVariables* MicroResourceVariables::Create( + MicroAllocator* allocator, int max_num_variables) { + TFLITE_DCHECK(allocator != nullptr); + + uint8_t* allocator_buffer = static_cast( + allocator->AllocatePersistentBuffer(sizeof(MicroResourceVariables))); + MicroResourceVariable* variable_array = + static_cast(allocator->AllocatePersistentBuffer( + sizeof(MicroResourceVariable) * max_num_variables)); + MicroResourceVariables* variables = new (allocator_buffer) + MicroResourceVariables(variable_array, max_num_variables); + return variables; +} + +int MicroResourceVariables::CreateIdIfNoneFound(const char* container, + const char* shared_name) { + int resource_id = FindId(container, shared_name); + if (resource_id >= 0) { + return resource_id; + } + + // no existing variable found for the given container and shared name pair. + if (num_resource_variables_ >= max_variable_count_) { + MicroPrintf( + "Failed to allocate resource variable. Maximum resource variable count " + "(%d) " + "reached.", + max_variable_count_); + return -1; + } + + resource_id = num_resource_variables_++; + resource_variables_[resource_id].container = container; + resource_variables_[resource_id].shared_name = shared_name; + resource_variables_[resource_id].resource_buffer = nullptr; + resource_variables_[resource_id].bytes = 0; + return resource_id; +} + +TfLiteStatus MicroResourceVariables::Read(int id, + const TfLiteEvalTensor* tensor) { + if (id < 0 || id >= num_resource_variables_) { + MicroPrintf("Attempting to read non-existent resource variable %d", id); + return kTfLiteError; + } + MicroResourceVariable variable = resource_variables_[id]; + TFLITE_DCHECK(EvalTensorBytes(tensor) == variable.bytes); + TFLITE_DCHECK(variable.resource_buffer != nullptr); + memcpy(tensor->data.raw, variable.resource_buffer, variable.bytes); + return kTfLiteOk; +} + +TfLiteStatus MicroResourceVariables::Allocate(int id, TfLiteContext* context, + const TfLiteTensor* tensor) { + if (id < 0 || id >= num_resource_variables_) { + MicroPrintf("Attempting to read non-existent resource variable %d", id); + return kTfLiteError; + } + + MicroResourceVariable& variable = resource_variables_[id]; + + if (variable.resource_buffer == nullptr) { + variable.bytes = tensor->bytes; + variable.resource_buffer = + context->AllocatePersistentBuffer(context, tensor->bytes); + if (variable.resource_buffer == nullptr) { + MicroPrintf("Failed to allocate resource buffer."); + return kTfLiteError; + } + // Zero out resource buffers by deafult. Buffers can be initialized to + // nonzero values using ASSIGN_VARIABLE. + memset(variable.resource_buffer, 0, variable.bytes); + } + + return kTfLiteOk; +} + +TfLiteStatus MicroResourceVariables::Assign(int id, + const TfLiteEvalTensor* tensor) { + if (id < 0 || id >= num_resource_variables_) { + MicroPrintf("Attempting to read non-existent resource variable %d", id); + return kTfLiteError; + } + MicroResourceVariable variable = resource_variables_[id]; + + if (variable.resource_buffer == nullptr) { + MicroPrintf( + "Attempting to assign from a TfLiteEvalTensor before the resource " + "buffer has been allocated. Make sure to call AssignResourceVariable " + "with a TfLiteTensor first."); + return kTfLiteError; + } + TFLITE_DCHECK(EvalTensorBytes(tensor) == variable.bytes); + memcpy(variable.resource_buffer, tensor->data.raw, variable.bytes); + return kTfLiteOk; +} + +TfLiteStatus MicroResourceVariables::ResetAll() { + for (int i = 0; i < num_resource_variables_; i++) { + MicroResourceVariable variable = resource_variables_[i]; + memset(variable.resource_buffer, 0, variable.bytes); + } + return kTfLiteOk; +} + +int MicroResourceVariables::FindId(const char* container, + const char* shared_name) { + for (int i = 0; i < num_resource_variables_; i++) { + // Some TFLite flatbuffers contain null container names to save space. + if ((container == nullptr || + !strcmp(container, resource_variables_[i].container)) && + !strcmp(shared_name, resource_variables_[i].shared_name)) { + return i; + } + } + return -1; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_resource_variable.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_resource_variable.h new file mode 100644 index 000000000..e8df991c3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_resource_variable.h @@ -0,0 +1,87 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TFLITE_MICRO_TENSORFLOW_LITE_MICRO_MICRO_RESOURCE_H_ +#define TFLITE_MICRO_TENSORFLOW_LITE_MICRO_MICRO_RESOURCE_H_ + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_allocator.h" + +namespace tflite { + +class MicroResourceVariables { + public: + // Create + static MicroResourceVariables* Create(MicroAllocator* allocator, + int num_variables); + + // Creates a resource variable if none is available for the given container + // and shared name pair. Returns the resource ID corresponding to the + // container and shared name pair. If allocation fails, the returned resource + // ID will be negative. The the container and shared_name must outlive this + // class. + int CreateIdIfNoneFound(const char* container, const char* shared_name); + + // Read the resource buffer associated with the given ID into the given + // tensor. + TfLiteStatus Read(int id, const TfLiteEvalTensor* tensor); + + // Allocates the resource buffer if none has been allocated, based on the + // length of the input tensor. Copies input tensor contents to the resource + // buffer. + TfLiteStatus Allocate(int id, TfLiteContext* context, + const TfLiteTensor* tensor); + + // Copies input tensor contents to the resource buffer. + // AllocateResourceVariable with a TFLite tensor must have been called first + // in order to allocate the resource buffer. + TfLiteStatus Assign(int id, const TfLiteEvalTensor* tensor); + + // Zeros out all resource buffers. + TfLiteStatus ResetAll(); + + private: + int FindId(const char* container, const char* shared_name); + + // Micro resource contains the mapping between resource container/name strings + // and resouce IDs. Each resource ID corresponds to a resource buffer pointer. + // The resouce ID is created during the VAR_HANDLE operator preparation stage. + // The resource buffer pointer is created during ASSIGN_VARIABLE preparation + // stage based on the size of the TFLiteTensor being assigned. + struct MicroResourceVariable { + const char* container; + const char* shared_name; + void* resource_buffer; + + // This is only for verifying read size. + size_t bytes; + }; + + MicroResourceVariables(MicroResourceVariable* variables, + int max_variable_count) + : resource_variables_(variables), + max_variable_count_(max_variable_count), + num_resource_variables_(0) {} + + MicroResourceVariable* resource_variables_; + int max_variable_count_; + int num_resource_variables_; +}; + +} // namespace tflite + +#endif // TFLITE_MICRO_TENSORFLOW_LITE_MICRO_MICRO_RESOURCE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_string.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_string.cpp new file mode 100644 index 000000000..bb41a9e39 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_string.cpp @@ -0,0 +1,317 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ + +// Implements debug logging for numbers by converting them into strings and then +// calling the main DebugLog(char*) function. These are separated into a +// different file so that platforms can just implement the string output version +// of DebugLog() and then get the numerical variations without requiring any +// more code. + +#include "tensorflow/lite/micro/micro_string.h" + +#include +#include +#include + +namespace { + +// Int formats can need up to 10 bytes for the value plus a single byte for the +// sign. +constexpr int kMaxIntCharsNeeded = 10 + 1; +// Hex formats can need up to 8 bytes for the value plus two bytes for the "0x". +constexpr int kMaxHexCharsNeeded = 8 + 2; + +// Float formats can need up to 7 bytes for the fraction plus 3 bytes for "x2^" +// plus 3 bytes for the exponent and a single sign bit. +constexpr float kMaxFloatCharsNeeded = 7 + 3 + 3 + 1; + +// All input buffers to the number conversion functions must be this long. +const int kFastToBufferSize = 48; + +// Reverses a zero-terminated string in-place. +char* ReverseStringInPlace(char* start, char* end) { + char* p1 = start; + char* p2 = end - 1; + while (p1 < p2) { + char tmp = *p1; + *p1++ = *p2; + *p2-- = tmp; + } + return start; +} + +// Appends a string to a string, in-place. You need to pass in the maximum +// string length as the second argument. +char* StrCatStr(char* main, int main_max_length, const char* to_append) { + char* current = main; + while (*current != 0) { + ++current; + } + char* current_end = main + (main_max_length - 1); + while ((*to_append != 0) && (current < current_end)) { + *current = *to_append; + ++current; + ++to_append; + } + *current = 0; + return current; +} + +// Populates the provided buffer with an ASCII representation of the number. +char* FastUInt32ToBufferLeft(uint32_t i, char* buffer, int base) { + char* start = buffer; + do { + int32_t digit = i % base; + char character; + if (digit < 10) { + character = '0' + digit; + } else { + character = 'a' + (digit - 10); + } + *buffer++ = character; + i /= base; + } while (i > 0); + *buffer = 0; + ReverseStringInPlace(start, buffer); + return buffer; +} + +// Populates the provided buffer with an ASCII representation of the number. +char* FastInt32ToBufferLeft(int32_t i, char* buffer) { + uint32_t u = i; + if (i < 0) { + *buffer++ = '-'; + u = -u; + } + return FastUInt32ToBufferLeft(u, buffer, 10); +} + +// Converts a number to a string and appends it to another. +char* StrCatInt32(char* main, int main_max_length, int32_t number) { + char number_string[kFastToBufferSize]; + FastInt32ToBufferLeft(number, number_string); + return StrCatStr(main, main_max_length, number_string); +} + +// Converts a number to a string and appends it to another. +char* StrCatUInt32(char* main, int main_max_length, uint32_t number, int base) { + char number_string[kFastToBufferSize]; + FastUInt32ToBufferLeft(number, number_string, base); + return StrCatStr(main, main_max_length, number_string); +} + +// Populates the provided buffer with ASCII representation of the float number. +// Avoids the use of any floating point instructions (since these aren't +// supported on many microcontrollers) and as a consequence prints values with +// power-of-two exponents. +char* FastFloatToBufferLeft(float f, char* buffer) { + char* current = buffer; + char* current_end = buffer + (kFastToBufferSize - 1); + // Access the bit fields of the floating point value to avoid requiring any + // float instructions. These constants are derived from IEEE 754. + const uint32_t sign_mask = 0x80000000; + const uint32_t exponent_mask = 0x7f800000; + const int32_t exponent_shift = 23; + const int32_t exponent_bias = 127; + const uint32_t fraction_mask = 0x007fffff; + uint32_t u; + memcpy(&u, &f, sizeof(int32_t)); + const int32_t exponent = + ((u & exponent_mask) >> exponent_shift) - exponent_bias; + const uint32_t fraction = (u & fraction_mask); + // Expect ~0x2B1B9D3 for fraction. + if (u & sign_mask) { + *current = '-'; + current += 1; + } + *current = 0; + // These are special cases for infinities and not-a-numbers. + if (exponent == 128) { + if (fraction == 0) { + current = StrCatStr(current, (current_end - current), "Inf"); + return current; + } else { + current = StrCatStr(current, (current_end - current), "NaN"); + return current; + } + } + // 0x007fffff (8388607) represents 0.99... for the fraction, so to print the + // correct decimal digits we need to scale our value before passing it to the + // conversion function. This scale should be 10000000/8388608 = 1.1920928955. + // We can approximate this using multiply-adds and right-shifts using the + // values in this array. The 1. portion of the number string is printed out + // in a fixed way before the fraction, below. + const int32_t scale_shifts_size = 13; + const int8_t scale_shifts[13] = {3, 4, 8, 11, 13, 14, 17, + 18, 19, 20, 21, 22, 23}; + uint32_t scaled_fraction = fraction; + for (int i = 0; i < scale_shifts_size; ++i) { + scaled_fraction += (fraction >> scale_shifts[i]); + } + *current = '1'; + current += 1; + *current = '.'; + current += 1; + *current = 0; + + // Prepend leading zeros to fill in all 7 bytes of the fraction. Truncate + // zeros off the end of the fraction. Every fractional value takes 7 bytes. + // For example, 2500 would be written into the buffer as 0002500 since it + // represents .00025. + constexpr int kMaxFractionalDigits = 7; + + // Abort early if there is not enough space in the buffer. + if (current_end - current <= kMaxFractionalDigits) { + return current; + } + + // Pre-fill buffer with zeros to ensure zero-truncation works properly. + for (int i = 1; i < kMaxFractionalDigits; i++) { + *(current + i) = '0'; + } + + // Track how large the fraction is to add leading zeros. + char* previous = current; + current = StrCatUInt32(current, (current_end - current), scaled_fraction, 10); + int fraction_digits = current - previous; + int leading_zeros = kMaxFractionalDigits - fraction_digits; + + // Overwrite the null terminator from StrCatUInt32 to ensure zero-trunctaion + // works properly. + *current = '0'; + + // Shift fraction values and prepend zeros if necessary. + if (leading_zeros != 0) { + for (int i = 0; i < fraction_digits; i++) { + current--; + *(current + leading_zeros) = *current; + *current = '0'; + } + current += kMaxFractionalDigits; + } + + // Truncate trailing zeros for cleaner logs. Ensure we leave at least one + // fractional character for the case when scaled_fraction is 0. + while (*(current - 1) == '0' && (current - 1) > previous) { + current--; + } + *current = 0; + current = StrCatStr(current, (current_end - current), "*2^"); + current = StrCatInt32(current, (current_end - current), exponent); + return current; +} + +int FormatInt32(char* output, int32_t i) { + return static_cast(FastInt32ToBufferLeft(i, output) - output); +} + +int FormatUInt32(char* output, uint32_t i) { + return static_cast(FastUInt32ToBufferLeft(i, output, 10) - output); +} + +int FormatHex(char* output, uint32_t i) { + return static_cast(FastUInt32ToBufferLeft(i, output, 16) - output); +} + +int FormatFloat(char* output, float i) { + return static_cast(FastFloatToBufferLeft(i, output) - output); +} + +} // namespace + +extern "C" int MicroVsnprintf(char* output, int len, const char* format, + va_list args) { + int output_index = 0; + const char* current = format; + // One extra character must be left for the null terminator. + const int usable_length = len - 1; + while (*current != '\0' && output_index < usable_length) { + if (*current == '%') { + current++; + switch (*current) { + case 'd': + // Cut off log message if format could exceed log buffer length. + if (usable_length - output_index < kMaxIntCharsNeeded) { + output[output_index++] = '\0'; + return output_index; + } + output_index += + FormatInt32(&output[output_index], va_arg(args, int32_t)); + current++; + break; + case 'u': + if (usable_length - output_index < kMaxIntCharsNeeded) { + output[output_index++] = '\0'; + return output_index; + } + output_index += + FormatUInt32(&output[output_index], va_arg(args, uint32_t)); + current++; + break; + case 'x': + if (usable_length - output_index < kMaxHexCharsNeeded) { + output[output_index++] = '\0'; + return output_index; + } + output[output_index++] = '0'; + output[output_index++] = 'x'; + output_index += + FormatHex(&output[output_index], va_arg(args, uint32_t)); + current++; + break; + case 'f': + if (usable_length - output_index < kMaxFloatCharsNeeded) { + output[output_index++] = '\0'; + return output_index; + } + output_index += + FormatFloat(&output[output_index], va_arg(args, double)); + current++; + break; + case '%': + output[output_index++] = *current++; + break; + case 'c': + if (usable_length - output_index < 1) { + output[output_index++] = '\0'; + return output_index; + } + output[output_index++] = va_arg(args, int32_t); + current++; + break; + case 's': + char* string = va_arg(args, char*); + int string_idx = 0; + while (string_idx + output_index < usable_length && + string[string_idx] != '\0') { + output[output_index++] = string[string_idx++]; + } + current++; + } + } else { + output[output_index++] = *current++; + } + } + output[output_index++] = '\0'; + return output_index; +} + +extern "C" int MicroSnprintf(char* output, int len, const char* format, ...) { + va_list args; + va_start(args, format); + int bytes_written = MicroVsnprintf(output, len, format, args); + va_end(args); + return bytes_written; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_string.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_string.h new file mode 100644 index 000000000..59303e82b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_string.h @@ -0,0 +1,33 @@ +/* Copyright 2018 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_STRING_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_STRING_H_ + +#include + +// Implements simple string formatting for numeric types. Returns the number of +// bytes written to output. +extern "C" { +// Functionally equivalent to vsnprintf, trimmed down for TFLite Micro. +// MicroSnprintf() is implemented using MicroVsnprintf(). +int MicroVsnprintf(char* output, int len, const char* format, va_list args); +// Functionally equavalent to snprintf, trimmed down for TFLite Micro. +// For example, MicroSnprintf(buffer, 10, "int %d", 10) will put the string +// "int 10" in the buffer. +// Floating point values are logged in exponent notation (1.XXX*2^N). +int MicroSnprintf(char* output, int len, const char* format, ...); +} + +#endif // TENSORFLOW_LITE_MICRO_MICRO_STRING_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_time.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_time.cpp new file mode 100644 index 000000000..d50cb3fc3 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_time.cpp @@ -0,0 +1,63 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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. +==============================================================================*/ + +// Reference implementation of timer functions. Platforms are not required to +// implement these timer methods, but they are required to enable profiling. + +// On platforms that have a POSIX stack or C library, it can be written using +// methods from or clock() from . + +// To add an equivalent function for your own platform, create your own +// implementation file, and place it in a subfolder with named after the OS +// you're targeting. For example, see the Cortex M bare metal version in +// tensorflow/lite/micro/bluepill/micro_time.cc or the mbed one on +// tensorflow/lite/micro/mbed/micro_time.cc. + +#include "tensorflow/lite/micro/micro_time.h" + +// #include "peripherals/utility.h" + +#if defined(TF_LITE_USE_CTIME) +#include +#endif + +namespace tflite { + +#if !defined(TF_LITE_USE_CTIME) + +// Reference implementation of the ticks_per_second() function that's required +// for a platform to support Tensorflow Lite for Microcontrollers profiling. +// This returns 0 by default because timing is an optional feature that builds +// without errors on platforms that do not need it. +uint32_t ticks_per_second() { return 1000000; } + +// Reference implementation of the GetCurrentTimeTicks() function that's +// required for a platform to support Tensorflow Lite for Microcontrollers +// profiling. This returns 0 by default because timing is an optional feature +// that builds without errors on platforms that do not need it. +// uint32_t GetCurrentTimeTicks() { return peripherals::MicrosecondsCounter(); } + +uint32_t GetCurrentTimeTicks() { return 0; } + +#else // defined(TF_LITE_USE_CTIME) + +// For platforms that support ctime, we implment the micro_time interface in +// this central location. +uint32_t ticks_per_second() { return CLOCKS_PER_SEC; } + +uint32_t GetCurrentTimeTicks() { return clock(); } +#endif + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_time.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_time.h new file mode 100644 index 000000000..7a8ab455c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_time.h @@ -0,0 +1,36 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_TIME_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_TIME_H_ + +#include + +namespace tflite { + +// These functions should be implemented by each target platform, and provide an +// accurate tick count along with how many ticks there are per second. +uint32_t ticks_per_second(); + +// Return time in ticks. The meaning of a tick varies per platform. +uint32_t GetCurrentTimeTicks(); + +inline uint32_t TicksToMs(int32_t ticks) { + return static_cast(1000.0f * static_cast(ticks) / + static_cast(ticks_per_second())); +} + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_TIME_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_utils.cpp new file mode 100644 index 000000000..b84407db6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_utils.cpp @@ -0,0 +1,91 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/micro_utils.h" + +#include +#include +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/op_macros.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +int ElementCount(const TfLiteIntArray& dims) { + int result = 1; + for (int i = 0; i < dims.size; ++i) { + result *= dims.data[i]; + } + return result; +} + +size_t EvalTensorBytes(const TfLiteEvalTensor* tensor) { + size_t bytes_per_element; + TFLITE_DCHECK(kTfLiteOk == + TfLiteTypeSizeOf(tensor->type, &bytes_per_element)); + return ElementCount(*tensor->dims) * bytes_per_element; +} + +void SignedSymmetricPerChannelQuantize(const float* values, + TfLiteIntArray* dims, + int quantized_dimension, + int8_t* quantized_values, + float* scaling_factors) { + int input_size = ElementCount(*dims); + int channel_count = dims->data[quantized_dimension]; + int per_channel_size = input_size / channel_count; + + int stride; + int channel_stride; + if (quantized_dimension == 0) { + stride = 1; + channel_stride = per_channel_size; + } else if (quantized_dimension == 3) { + stride = channel_count; + channel_stride = 1; + } else { + MicroPrintf("quantized dimension must be 0 or 3"); + TFLITE_ABORT; + } + + // Calculate scales for each channel. + for (int channel = 0; channel < channel_count; channel++) { + float min = 0; + float max = 0; + + for (int i = 0; i < per_channel_size; i++) { + int idx = channel * channel_stride + i * stride; + min = fminf(min, values[idx]); + max = fmaxf(max, values[idx]); + } + scaling_factors[channel] = + fmaxf(fabs(min), fabs(max)) / std::numeric_limits::max(); + for (int i = 0; i < per_channel_size; i++) { + int idx = channel * channel_stride + i * stride; + const int32_t quantized_value = + static_cast(roundf(values[idx] / scaling_factors[channel])); + // Clamp: just in case some odd numeric offset. + quantized_values[idx] = + fminf(std::numeric_limits::max(), + fmaxf(std::numeric_limits::min() + 1, quantized_value)); + } + } +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_utils.h new file mode 100644 index 000000000..84d5c4373 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/micro_utils.h @@ -0,0 +1,143 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MICRO_UTILS_H_ +#define TENSORFLOW_LITE_MICRO_MICRO_UTILS_H_ + +#include +#include +#include +#include + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// Returns number of elements in the shape array. + +int ElementCount(const TfLiteIntArray& dims); + +size_t EvalTensorBytes(const TfLiteEvalTensor* tensor); + +// C++11 does not support constexpr max; hence, use ternary conditional to +// create our own constexpr Max function. +constexpr int Max(int a, int b) { return a >= b ? a : b; } + +// Converts a float value into a quantized value. Note that large values (close +// to max int and min int) may see significant error due to a lack of floating +// point granularity for large values. +template +T FloatToQuantizedType(const float value, const float scale, int zero_point) { + int32_t result = round(value / scale) + zero_point; + result = + std::max(static_cast(std::numeric_limits::min()), result); + result = + std::min(static_cast(std::numeric_limits::max()), result); + return result; +} + +template +T FloatToSymmetricQuantizedType(const float value, const float scale) { + // 64-bit values are required since 8x16 conv accumulates to int64, meaning + // an int64 bias is required. + std::int64_t result = round(value / scale); + result = std::max( + static_cast(std::numeric_limits::min() + 1), result); + result = std::min(static_cast(std::numeric_limits::max()), + result); + return result; +} + +// Helper methods to quantize arrays of floats to the desired format. +// +// There are several key flavors of quantization in TfLite: +// asymmetric symmetric per channel +// int8_t | X | X | X | +// uint8_t | X | X | | +// int16_t | X | | | +// int32_t | | X | X | +// +// The per-op quantization spec can be found here: +// https://www.tensorflow.org/lite/performance/quantization_spec +template +void Quantize(const float* input, T* output, int num_elements, float scale, + int zero_point) { + for (int i = 0; i < num_elements; i++) { + output[i] = FloatToQuantizedType(input[i], scale, zero_point); + } +} + +template +void SymmetricQuantize(const float* input, T* output, int num_elements, + float scale) { + for (int i = 0; i < num_elements; i++) { + output[i] = FloatToSymmetricQuantizedType(input[i], scale); + } +} + +template +void SymmetricPerChannelQuantize(const float* input, T* output, + int num_elements, int num_channels, + float* scales) { + int elements_per_channel = num_elements / num_channels; + for (int i = 0; i < num_channels; i++) { + for (int j = 0; j < elements_per_channel; j++) { + output[i * elements_per_channel + j] = FloatToSymmetricQuantizedType( + input[i * elements_per_channel + j], scales[i]); + } + } +} + +void SignedSymmetricPerChannelQuantize(const float* values, + TfLiteIntArray* dims, + int quantized_dimension, + int8_t* quantized_values, + float* scaling_factor); + +// Quantizes inputs based on the values provided, choosing the smallest range +// which includes all input values. +template +void SymmetricQuantizeCalculateScales(const float* values, TfLiteIntArray* dims, + T* output, float* scale) { + int input_size = ElementCount(*dims); + + float min = 0; + float max = 0; + for (int i = 0; i < input_size; i++) { + min = fminf(min, values[i]); + max = fmaxf(max, values[i]); + } + *scale = fmaxf(std::abs(min), std::abs(max)) / std::numeric_limits::max(); + for (int i = 0; i < input_size; i++) { + const int32_t quantized_value = + static_cast(roundf(values[i] / *scale)); + // Clamp: just in case some odd numeric offset. + quantized_value = fminf(std::numeric_limits::max(), quantized_value); + quantized_value = fmaxf(std::numeric_limits::min() + 1, quantized_value); + output[i] = quantized_value; + } +} + +template +void Dequantize(const T* values, const int size, const float scale, + int zero_point, float* dequantized_values) { + for (int i = 0; i < size; ++i) { + dequantized_values[i] = (values[i] - zero_point) * scale; + } +} + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MICRO_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/mock_micro_graph.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/mock_micro_graph.cpp new file mode 100644 index 000000000..438a40653 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/mock_micro_graph.cpp @@ -0,0 +1,66 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/mock_micro_graph.h" + +#include "tensorflow/lite/micro/test_helpers.h" + +namespace tflite { + +MockMicroGraph::MockMicroGraph(SingleArenaBufferAllocator* allocator) + : MicroGraph(nullptr, nullptr, nullptr, nullptr), + allocator_(allocator), + init_count_(0), + prepare_count_(0), + free_count_(0) { + memset(invoke_counts_, 0, sizeof(invoke_counts_)); + mock_tensor_ = + reinterpret_cast(allocator_->AllocatePersistentBuffer( + sizeof(TfLiteEvalTensor), alignof(TfLiteEvalTensor))); + int* dims_array = reinterpret_cast( + allocator_->AllocatePersistentBuffer(3 * sizeof(int), alignof(int))); + float* data_array = reinterpret_cast( + allocator_->AllocatePersistentBuffer(2 * sizeof(float), alignof(float))); + int dims[] = {2, 1, 2}; + memcpy(dims_array, dims, 3 * sizeof(int)); + mock_tensor_->dims = testing::IntArrayFromInts(dims_array); + mock_tensor_->data.f = data_array; + mock_tensor_->type = kTfLiteFloat32; +} + +TfLiteStatus MockMicroGraph::InvokeSubgraph(int subgraph_idx) { + invoke_counts_[subgraph_idx]++; + return kTfLiteOk; +} + +TfLiteStatus MockMicroGraph::ResetVariableTensors() { return kTfLiteOk; } + +size_t MockMicroGraph::NumSubgraphInputs(int subgraph_idx) { return 1; } + +TfLiteEvalTensor* MockMicroGraph::GetSubgraphInput(int subgraph_idx, + int tensor_idx) { + return mock_tensor_; +} + +size_t MockMicroGraph::NumSubgraphOutputs(int subgraph_idx) { return 1; } + +TfLiteEvalTensor* MockMicroGraph::GetSubgraphOutput(int subgraph_idx, + int tensor_idx) { + return mock_tensor_; +} + +int MockMicroGraph::NumSubgraphs() { return kMaxSubgraphs; } + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/mock_micro_graph.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/mock_micro_graph.h new file mode 100644 index 000000000..3ae7d7cf0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/mock_micro_graph.h @@ -0,0 +1,60 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_MOCK_MICRO_GRAPH_H_ +#define TENSORFLOW_LITE_MICRO_MOCK_MICRO_GRAPH_H_ + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_graph.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// MockMicroGraph stubs out all MicroGraph methods used during invoke. A count +// of the number of calls to invoke for each subgraph is maintained for +// validation of control flow operators. +class MockMicroGraph : public MicroGraph { + public: + explicit MockMicroGraph(SingleArenaBufferAllocator* allocator); + TfLiteStatus InvokeSubgraph(int subgraph_idx) override; + TfLiteStatus ResetVariableTensors() override; + size_t NumSubgraphInputs(int subgraph_idx) override; + TfLiteEvalTensor* GetSubgraphInput(int subgraph_idx, int tensor_idx) override; + size_t NumSubgraphOutputs(int subgraph_idx) override; + TfLiteEvalTensor* GetSubgraphOutput(int subgraph_idx, + int tensor_idx) override; + int NumSubgraphs() override; + int get_init_count() const { return init_count_; } + int get_prepare_count() const { return prepare_count_; } + int get_free_count() const { return free_count_; } + int get_invoke_count(int subgraph_idx) const { + return invoke_counts_[subgraph_idx]; + } + + private: + static constexpr int kMaxSubgraphs = 10; + SingleArenaBufferAllocator* allocator_; + TfLiteEvalTensor* mock_tensor_; + int init_count_; + int prepare_count_; + int free_count_; + int invoke_counts_[kMaxSubgraphs]; + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_MOCK_MICRO_GRAPH_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_allocator.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_allocator.cpp new file mode 100644 index 000000000..289ed1815 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_allocator.cpp @@ -0,0 +1,256 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/recording_micro_allocator.h" + +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/memory_planner/greedy_memory_planner.h" +#include "tensorflow/lite/micro/micro_allocator.h" +#include "tensorflow/lite/micro/micro_log.h" + +namespace tflite { + +size_t RecordingMicroAllocator::GetDefaultTailUsage() { + // RecordingMicroAllocator inherits from MicroAllocator and its tail usage is + // similar with MicroAllocator with SingleArenaBufferAllocator and + // MicroAllocator being replaced. + // TODO(b/208703041): a template version of AlignSizeUp to make expression + // shorter. + return MicroAllocator::GetDefaultTailUsage( + /*is_memory_planner_given=*/false) + + AlignSizeUp(sizeof(RecordingSingleArenaBufferAllocator), + alignof(RecordingSingleArenaBufferAllocator)) - + AlignSizeUp(sizeof(SingleArenaBufferAllocator), + alignof(SingleArenaBufferAllocator)) + + AlignSizeUp(sizeof(RecordingMicroAllocator), + alignof(RecordingMicroAllocator)) - + AlignSizeUp(sizeof(MicroAllocator), alignof(MicroAllocator)); +} + +RecordingMicroAllocator::RecordingMicroAllocator( + RecordingSingleArenaBufferAllocator* recording_memory_allocator, + MicroMemoryPlanner* memory_planner) + : MicroAllocator(recording_memory_allocator, memory_planner), + recording_memory_allocator_(recording_memory_allocator) {} + +RecordingMicroAllocator* RecordingMicroAllocator::Create(uint8_t* tensor_arena, + size_t arena_size) { + RecordingSingleArenaBufferAllocator* simple_memory_allocator = + RecordingSingleArenaBufferAllocator::Create(tensor_arena, arena_size); + TFLITE_DCHECK(simple_memory_allocator != nullptr); + + uint8_t* memory_planner_buffer = + simple_memory_allocator->AllocatePersistentBuffer( + sizeof(GreedyMemoryPlanner), alignof(GreedyMemoryPlanner)); + GreedyMemoryPlanner* memory_planner = + new (memory_planner_buffer) GreedyMemoryPlanner(); + + uint8_t* allocator_buffer = simple_memory_allocator->AllocatePersistentBuffer( + sizeof(RecordingMicroAllocator), alignof(RecordingMicroAllocator)); + RecordingMicroAllocator* allocator = new (allocator_buffer) + RecordingMicroAllocator(simple_memory_allocator, memory_planner); + return allocator; +} + +RecordedAllocation RecordingMicroAllocator::GetRecordedAllocation( + RecordedAllocationType allocation_type) const { + switch (allocation_type) { + case RecordedAllocationType::kTfLiteEvalTensorData: + return recorded_tflite_eval_tensor_data_; + case RecordedAllocationType::kPersistentTfLiteTensorData: + return recorded_persistent_tflite_tensor_data_; + case RecordedAllocationType::kPersistentTfLiteTensorQuantizationData: + return recorded_persistent_tflite_tensor_quantization_data_; + case RecordedAllocationType::kPersistentBufferData: + return recorded_persistent_buffer_data_; + case RecordedAllocationType::kTfLiteTensorVariableBufferData: + return recorded_tflite_tensor_variable_buffer_data_; + case RecordedAllocationType::kNodeAndRegistrationArray: + return recorded_node_and_registration_array_data_; + case RecordedAllocationType::kOpData: + return recorded_op_data_; + } + MicroPrintf("Invalid allocation type supplied: %d", allocation_type); + return RecordedAllocation(); +} + +const RecordingSingleArenaBufferAllocator* +RecordingMicroAllocator::GetSimpleMemoryAllocator() const { + return recording_memory_allocator_; +} + +void RecordingMicroAllocator::PrintAllocations() const { + MicroPrintf("[RecordingMicroAllocator] Arena allocation total %d bytes", + recording_memory_allocator_->GetUsedBytes()); + MicroPrintf("[RecordingMicroAllocator] Arena allocation head %d bytes", + recording_memory_allocator_->GetNonPersistentUsedBytes()); + MicroPrintf("[RecordingMicroAllocator] Arena allocation tail %d bytes", + recording_memory_allocator_->GetPersistentUsedBytes()); + PrintRecordedAllocation(RecordedAllocationType::kTfLiteEvalTensorData, + "TfLiteEvalTensor data", "allocations"); + PrintRecordedAllocation(RecordedAllocationType::kPersistentTfLiteTensorData, + "Persistent TfLiteTensor data", "tensors"); + PrintRecordedAllocation( + RecordedAllocationType::kPersistentTfLiteTensorQuantizationData, + "Persistent TfLiteTensor quantization data", "allocations"); + PrintRecordedAllocation(RecordedAllocationType::kPersistentBufferData, + "Persistent buffer data", "allocations"); + PrintRecordedAllocation( + RecordedAllocationType::kTfLiteTensorVariableBufferData, + "TfLiteTensor variable buffer data", "allocations"); + PrintRecordedAllocation(RecordedAllocationType::kNodeAndRegistrationArray, + "NodeAndRegistration struct", + "NodeAndRegistration structs"); + PrintRecordedAllocation(RecordedAllocationType::kOpData, + "Operator runtime data", "OpData structs"); +} + +void* RecordingMicroAllocator::AllocatePersistentBuffer(size_t bytes) { + RecordedAllocation allocations = SnapshotAllocationUsage(); + void* buffer = MicroAllocator::AllocatePersistentBuffer(bytes); + RecordAllocationUsage(allocations, recorded_persistent_buffer_data_); + + return buffer; +} + +void RecordingMicroAllocator::PrintRecordedAllocation( + RecordedAllocationType allocation_type, const char* allocation_name, + const char* allocation_description) const { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + RecordedAllocation allocation = GetRecordedAllocation(allocation_type); + if (allocation.used_bytes > 0 || allocation.requested_bytes > 0) { + MicroPrintf( + "[RecordingMicroAllocator] '%s' used %d bytes with alignment overhead " + "(requested %d bytes for %d %s)", + allocation_name, allocation.used_bytes, allocation.requested_bytes, + allocation.count, allocation_description); + } +#endif +} + +TfLiteStatus RecordingMicroAllocator::AllocateNodeAndRegistrations( + const Model* model, SubgraphAllocations* subgraph_allocations) { + RecordedAllocation allocations = SnapshotAllocationUsage(); + + TfLiteStatus status = + MicroAllocator::AllocateNodeAndRegistrations(model, subgraph_allocations); + + RecordAllocationUsage(allocations, + recorded_node_and_registration_array_data_); + + for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size(); + subgraph_idx++) { + // The allocation count in SingleArenaBufferAllocator will only be 1. To + // provide better logging, decrement by 1 and add in the actual number of + // operators used in the graph: The allocation for this recording will + // always be 1. This is because the parent class mallocs one large + // allocation for the number of nodes in the graph (e.g. + // sizeof(NodeAndRegistration) * num_nodes). To prevent extra overhead and + // potential for fragmentation, manually adjust the accounting by + // decrementing by 1 and adding the actual number of nodes used in the + // graph: + if (model->subgraphs()->Get(subgraph_idx)->operators()) { + recorded_node_and_registration_array_data_.count += + model->subgraphs()->Get(subgraph_idx)->operators()->size() - 1; + } else { + recorded_node_and_registration_array_data_.count -= 1; + } + } + return status; +} + +TfLiteStatus RecordingMicroAllocator::AllocateTfLiteEvalTensors( + const Model* model, SubgraphAllocations* subgraph_allocations) { + RecordedAllocation allocations = SnapshotAllocationUsage(); + + TfLiteStatus status = + MicroAllocator::AllocateTfLiteEvalTensors(model, subgraph_allocations); + + RecordAllocationUsage(allocations, recorded_tflite_eval_tensor_data_); + + for (size_t subgraph_idx = 0; subgraph_idx < model->subgraphs()->size(); + subgraph_idx++) { + // The allocation for this recording will always be 1. This is because the + // parent class mallocs one large allocation for the number of tensors in + // the graph (e.g. sizeof(TfLiteEvalTensor) * num_tensors). To prevent extra + // overhead and potential for fragmentation, manually adjust the accounting + // by decrementing by 1 and adding the actual number of tensors used in the + // graph: + recorded_tflite_eval_tensor_data_.count += + model->subgraphs()->Get(subgraph_idx)->tensors()->size() - 1; + } + return status; +} + +TfLiteStatus RecordingMicroAllocator::AllocateVariables( + const SubGraph* subgraph, TfLiteEvalTensor* eval_tensors) { + RecordedAllocation allocations = SnapshotAllocationUsage(); + + TfLiteStatus status = + MicroAllocator::AllocateVariables(subgraph, eval_tensors); + + RecordAllocationUsage(allocations, + recorded_tflite_tensor_variable_buffer_data_); + return status; +} + +TfLiteTensor* +RecordingMicroAllocator::AllocatePersistentTfLiteTensorInternal() { + RecordedAllocation allocations = SnapshotAllocationUsage(); + + TfLiteTensor* result = + MicroAllocator::AllocatePersistentTfLiteTensorInternal(); + + RecordAllocationUsage(allocations, recorded_persistent_tflite_tensor_data_); + return result; +} + +TfLiteStatus RecordingMicroAllocator::PopulateTfLiteTensorFromFlatbuffer( + const Model* model, TfLiteTensor* tensor, int tensor_index, + int subgraph_index, bool allocate_temp) { + RecordedAllocation allocations = SnapshotAllocationUsage(); + + TfLiteStatus status = MicroAllocator::PopulateTfLiteTensorFromFlatbuffer( + model, tensor, tensor_index, subgraph_index, allocate_temp); + + RecordAllocationUsage(allocations, + recorded_persistent_tflite_tensor_quantization_data_); + return status; +} + +RecordedAllocation RecordingMicroAllocator::SnapshotAllocationUsage() const { + return {/*requested_bytes=*/recording_memory_allocator_->GetRequestedBytes(), + /*used_bytes=*/recording_memory_allocator_->GetUsedBytes(), + /*count=*/recording_memory_allocator_->GetAllocatedCount()}; +} + +void RecordingMicroAllocator::RecordAllocationUsage( + const RecordedAllocation& snapshotted_allocation, + RecordedAllocation& recorded_allocation) { + recorded_allocation.requested_bytes += + recording_memory_allocator_->GetRequestedBytes() - + snapshotted_allocation.requested_bytes; + recorded_allocation.used_bytes += + recording_memory_allocator_->GetUsedBytes() - + snapshotted_allocation.used_bytes; + recorded_allocation.count += + recording_memory_allocator_->GetAllocatedCount() - + snapshotted_allocation.count; +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_allocator.h new file mode 100644 index 000000000..1b1e0ead1 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_allocator.h @@ -0,0 +1,132 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_RECORDING_MICRO_ALLOCATOR_H_ +#define TENSORFLOW_LITE_MICRO_RECORDING_MICRO_ALLOCATOR_H_ + +#include "tensorflow/lite/micro/arena_allocator/recording_single_arena_buffer_allocator.h" +#include "tensorflow/lite/micro/compatibility.h" +#include "tensorflow/lite/micro/micro_allocator.h" + +namespace tflite { + +// List of buckets currently recorded by this class. Each type keeps a list of +// allocated information during model initialization. +// TODO(b/169834511): Add tracking for scratch buffer allocations. +enum class RecordedAllocationType { + kTfLiteEvalTensorData, + kPersistentTfLiteTensorData, + kPersistentTfLiteTensorQuantizationData, + kPersistentBufferData, + kTfLiteTensorVariableBufferData, + kNodeAndRegistrationArray, + kOpData, +}; + +// Container for holding information about allocation recordings by a given +// type. Each recording contains the number of bytes requested, the actual bytes +// allocated (can defer from requested by alignment), and the number of items +// allocated. +struct RecordedAllocation { + size_t requested_bytes; + size_t used_bytes; + size_t count; +}; + +// Utility subclass of MicroAllocator that records all allocations +// inside the arena. A summary of allocations can be logged through the +// ErrorReporter by invoking LogAllocations(). This special allocator requires +// an instance of RecordingSingleArenaBufferAllocator to capture allocations in +// the head and tail. Arena allocation recording can be retrieved by type +// through the GetRecordedAllocation() function. This class should only be used +// for auditing memory usage or integration testing. +class RecordingMicroAllocator : public MicroAllocator { + public: + // TODO(b/246776144): Will be removed with http://b/246776144 + static RecordingMicroAllocator* Create(uint8_t* tensor_arena, + size_t arena_size, + ErrorReporter* error_reporter) { + (void)error_reporter; + return RecordingMicroAllocator::Create(tensor_arena, arena_size); + } + + static RecordingMicroAllocator* Create(uint8_t* tensor_arena, + size_t arena_size); + + // Returns the fixed amount of memory overhead of RecordingMicroAllocator. + static size_t GetDefaultTailUsage(); + + // Returns the recorded allocations information for a given allocation type. + RecordedAllocation GetRecordedAllocation( + RecordedAllocationType allocation_type) const; + + const RecordingSingleArenaBufferAllocator* GetSimpleMemoryAllocator() const; + + // Logs out through the ErrorReporter all allocation recordings by type + // defined in RecordedAllocationType. + void PrintAllocations() const; + + void* AllocatePersistentBuffer(size_t bytes) override; + + protected: + TfLiteStatus AllocateNodeAndRegistrations( + const Model* model, SubgraphAllocations* subgraph_allocations) override; + TfLiteStatus AllocateTfLiteEvalTensors( + const Model* model, SubgraphAllocations* subgraph_allocations) override; + TfLiteStatus AllocateVariables(const SubGraph* subgraph, + TfLiteEvalTensor* eval_tensors) override; + // TODO(b/162311891): Once all kernels have been updated to the new API drop + // this method. It is only used to record TfLiteTensor persistent allocations. + TfLiteTensor* AllocatePersistentTfLiteTensorInternal() override; + + // TODO(b/162311891): Once all kernels have been updated to the new API drop + // this function since all allocations for quantized data will take place in + // the temp section. + TfLiteStatus PopulateTfLiteTensorFromFlatbuffer(const Model* model, + TfLiteTensor* tensor, + int tensor_index, + int subgraph_index, + bool allocate_temp) override; + + private: + RecordingMicroAllocator(RecordingSingleArenaBufferAllocator* memory_allocator, + MicroMemoryPlanner* memory_planner); + + void PrintRecordedAllocation(RecordedAllocationType allocation_type, + const char* allocation_name, + const char* allocation_description) const; + + RecordedAllocation SnapshotAllocationUsage() const; + void RecordAllocationUsage(const RecordedAllocation& snapshotted_allocation, + RecordedAllocation& recorded_allocation); + + const RecordingSingleArenaBufferAllocator* recording_memory_allocator_; + + RecordedAllocation recorded_tflite_eval_tensor_data_ = {}; + RecordedAllocation recorded_persistent_tflite_tensor_data_ = {}; + RecordedAllocation recorded_persistent_tflite_tensor_quantization_data_ = {}; + RecordedAllocation recorded_persistent_buffer_data_ = {}; + RecordedAllocation recorded_tflite_tensor_variable_buffer_data_ = {}; + RecordedAllocation recorded_node_and_registration_array_data_ = {}; + + // TODO(b/187993291): Re-enable OpData allocating tracking. + RecordedAllocation recorded_op_data_ = {}; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_RECORDING_MICRO_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_interpreter.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_interpreter.h new file mode 100644 index 000000000..70b7260be --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/recording_micro_interpreter.h @@ -0,0 +1,94 @@ +/* Copyright 2022 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_RECORDING_MICRO_INTERPRETER_H_ +#define TENSORFLOW_LITE_MICRO_RECORDING_MICRO_INTERPRETER_H_ + +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/micro/micro_profiler_interface.h" +#include "tensorflow/lite/micro/recording_micro_allocator.h" + +namespace tflite { + +// Utility subclass that enables internal recordings of the MicroInterpreter. +// This class should be used to audit and analyze memory arena usage for a given +// model and interpreter. +// +// After construction and the first Invoke() or AllocateTensors() call - the +// memory usage is recorded and available through the GetMicroAllocator() +// function. See RecordingMicroAlloctor for more details on what is currently +// recorded from arena allocations. +// +// It is recommended for users to increase the tensor arena size by at least 1kb +// to ensure enough additional memory is available for internal recordings. +class RecordingMicroInterpreter : public MicroInterpreter { + public: + RecordingMicroInterpreter(const Model* model, + const MicroOpResolver& op_resolver, + uint8_t* tensor_arena, size_t tensor_arena_size, + MicroResourceVariables* resource_variable = nullptr, + MicroProfilerInterface* profiler = nullptr) + : MicroInterpreter( + model, op_resolver, + RecordingMicroAllocator::Create(tensor_arena, tensor_arena_size), + resource_variable, profiler), + recording_micro_allocator_( + static_cast(allocator())) {} + + RecordingMicroInterpreter(const Model* model, + const MicroOpResolver& op_resolver, + RecordingMicroAllocator* allocator, + MicroResourceVariables* resource_variable = nullptr, + MicroProfilerInterface* profiler = nullptr) + : MicroInterpreter(model, op_resolver, allocator, resource_variable, + profiler), + recording_micro_allocator_(*allocator) {} + + // TODO(b/246776144): Will be removed with http://b/246776144 + RecordingMicroInterpreter(const Model* model, + const MicroOpResolver& op_resolver, + uint8_t* tensor_arena, size_t tensor_arena_size, + ErrorReporter* error_reporter, + MicroResourceVariables* resource_variable = nullptr, + MicroProfilerInterface* profiler = nullptr) + : MicroInterpreter(model, op_resolver, + RecordingMicroAllocator::Create( + tensor_arena, tensor_arena_size, error_reporter), + error_reporter, resource_variable, profiler), + recording_micro_allocator_( + static_cast(allocator())) {} + + // TODO(b/246776144): Will be removed with http://b/246776144 + RecordingMicroInterpreter(const Model* model, + const MicroOpResolver& op_resolver, + RecordingMicroAllocator* allocator, + ErrorReporter* error_reporter, + MicroResourceVariables* resource_variable = nullptr, + MicroProfilerInterface* profiler = nullptr) + : MicroInterpreter(model, op_resolver, allocator, error_reporter, + resource_variable, profiler), + recording_micro_allocator_(*allocator) {} + + const RecordingMicroAllocator& GetMicroAllocator() const { + return recording_micro_allocator_; + } + + private: + const RecordingMicroAllocator& recording_micro_allocator_; +}; + +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_RECORDING_MICRO_INTERPRETER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/system_setup.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/system_setup.cpp new file mode 100644 index 000000000..dfa4e6336 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/system_setup.cpp @@ -0,0 +1,138 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/system_setup.h" + +#include + +#include "tensorflow/lite/micro/debug_log.h" + +#if defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) +#define ARDUINO_EXCLUDE_CODE +#endif // defined(ARDUINO) && !defined(ARDUINO_ARDUINO_NANO33BLE) + +#ifndef ARDUINO_EXCLUDE_CODE + +#include "Arduino.h" + +// The Arduino DUE uses a different object for the default serial port shown in +// the monitor than most other models, so make sure we pick the right one. See +// https://github.com/arduino/Arduino/issues/3088#issuecomment-406655244 +#if defined(__SAM3X8E__) +#define DEBUG_SERIAL_OBJECT (SerialUSB) +#else +#define DEBUG_SERIAL_OBJECT (Serial) +#endif + +extern "C" void DebugLog(const char* s) { DEBUG_SERIAL_OBJECT.print(s); } + +namespace tflite { + +constexpr ulong kSerialMaxInitWait = 4000; // milliseconds + +void InitializeTarget() { + DEBUG_SERIAL_OBJECT.begin(9600); + ulong start_time = millis(); + while (!DEBUG_SERIAL_OBJECT) { + // allow for Arduino IDE Serial Monitor synchronization + if (millis() - start_time > kSerialMaxInitWait) { + break; + } + } +} + +} // namespace tflite + +namespace test_over_serial { + +// Change baud rate on default serial port +void SerialChangeBaudRate(const int baud) { + DEBUG_SERIAL_OBJECT.begin(baud); + ulong start_time = millis(); + while (!DEBUG_SERIAL_OBJECT) { + // allow for Arduino IDE Serial Monitor synchronization + if (millis() - start_time > tflite::kSerialMaxInitWait) { + break; + } + } +} + +class _RingBuffer : public RingBufferN { + public: + bool need_reset = false; +}; + +static _RingBuffer _ring_buffer; + +// SerialReadLine +// Read a set of ASCII characters from the default +// serial port. Data is read up to the first newline ('\\n') character. +// This function uses an internal buffer which is automatically reset. +// The buffer will not contain the newline character. +// The buffer will be zero ('\\0') terminated. +// The value is in milliseconds. Any negative value means that +// the wait for data will be forever. +// Returns std::pair. +// The first pair element is the number of characters in buffer not including +// the newline character or zero terminator. +// Returns {0, NULL} if the timeout occurs. +std::pair SerialReadLine(int timeout) { + if (_ring_buffer.need_reset) { + _ring_buffer.need_reset = false; + _ring_buffer.clear(); + } + + ulong start_time = millis(); + + while (true) { + int value = DEBUG_SERIAL_OBJECT.read(); + if (value >= 0) { + if (value == '\n') { + // read a newline character + _ring_buffer.store_char('\0'); + _ring_buffer.need_reset = true; + break; + } else { + // read other character + _ring_buffer.store_char(value); + if (_ring_buffer.availableForStore() == 1) { + // buffer is full + _ring_buffer.store_char('\0'); + _ring_buffer.need_reset = true; + break; + } + } + } + if (timeout < 0) { + // wait forever + continue; + } else if (millis() - start_time >= static_cast(timeout)) { + // timeout + return std::make_pair(0UL, reinterpret_cast(NULL)); + } + } + + return std::make_pair(static_cast(_ring_buffer.available() - 1), + reinterpret_cast(_ring_buffer._aucBuffer)); +} + +// SerialWrite +// Write the ASCII characters in to the default serial port. +// The must be zero terminated. +void SerialWrite(const char* buffer) { DEBUG_SERIAL_OBJECT.print(buffer); } + +} // namespace test_over_serial + +#endif // ARDUINO_EXCLUDE_CODE diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/system_setup.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/system_setup.h new file mode 100644 index 000000000..ce49ddbe5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/system_setup.h @@ -0,0 +1,59 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_SYSTEM_SETUP_H_ +#define TENSORFLOW_LITE_MICRO_SYSTEM_SETUP_H_ + +#include +#include + +namespace tflite { + +// This should called during initialization of TFLM binaries and tests. It can +// be specialized if there is a need for custom target-specific intialization. +// For more information, see tensorflow/lite/micro/system_setup.cc. +void InitializeTarget(); + +} // namespace tflite + +namespace test_over_serial { + +// computed for Arduino Nano 33 BLE Sense +constexpr size_t kSerialMaxInputLength = (64); + +// Change baud rate on default serial port +void SerialChangeBaudRate(const int baud); + +// SerialReadLine +// Read a set of ASCII characters from the default +// serial port. Data is read up to the first newline ('\\n') character. +// This function uses an internal buffer which is automatically reset. +// The buffer will not contain the newline character. +// The buffer will be zero ('\\0') terminated. +// The value is in milliseconds. Any negative value means that +// the wait for data will be forever. +// Returns std::pair. +// The first pair element is the number of characters in buffer not including +// the newline character or zero terminator. +// Returns {0, NULL} if the timeout occurs. +std::pair SerialReadLine(int timeout); + +// SerialWrite +// Write the ASCII characters in to the default serial port. +// The must be zero terminated. +void SerialWrite(const char* buffer); + +} // namespace test_over_serial + +#endif // TENSORFLOW_LITE_MICRO_SYSTEM_SETUP_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helper_custom_ops.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helper_custom_ops.cpp new file mode 100644 index 000000000..b87cb5ae8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helper_custom_ops.cpp @@ -0,0 +1,112 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/test_helper_custom_ops.h" + +#include +#include +#include +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_utils.h" +#include "tensorflow/lite/schema/schema_generated.h" + +// TODO(b/170464050): Use TFLM test only version of schema_utils. + +namespace tflite { +namespace testing { + +const TfLiteRegistration* PackerOp::getRegistration() { + return GetMutableRegistration(); +} + +TfLiteRegistration* PackerOp::GetMutableRegistration() { + static TfLiteRegistration r; + r.init = Init; + r.prepare = Prepare; + r.invoke = Invoke; + r.free = Free; + return &r; +} + +void* PackerOp::Init(TfLiteContext* context, const char* buffer, + size_t length) { + freed_ = false; + // Do nothing. + return nullptr; +} + +void PackerOp::Free(TfLiteContext* context, void* buffer) { freed_ = true; } + +TfLiteStatus PackerOp::Prepare(TfLiteContext* context, TfLiteNode* node) { + return kTfLiteOk; +} + +TfLiteStatus PackerOp::Invoke(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, 0); + TF_LITE_ENSURE(context, input1 != nullptr); + const int32_t* input1_data = input1->data.i32; + TF_LITE_ENSURE_EQ(context, input1->dims->size, 1); + const int32_t input1_len = input1->dims->data[0]; + + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, 1); + TF_LITE_ENSURE(context, input2 != nullptr); + const int32_t* input2_data = input2->data.i32; + TF_LITE_ENSURE_EQ(context, input2->dims->size, 1); + const int32_t input2_len = input2->dims->data[0]; + + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE(context, output != nullptr); + int32_t* output_data = output->data.i32; + int32_t output_len = output->dims->data[0]; + + // Fill output with input: first with the first tensor, then with the second + // tensor up to the size of the output tensor. + int cnt = 0; + int i; + for (i = 0; i < input1_len && cnt < output_len; i++, cnt++) { + output_data[cnt] = input1_data[i]; + } + if (cnt >= output_len) { + return kTfLiteOk; + } + + for (i = 0; i < input2_len && cnt < output_len; i++, cnt++) { + output_data[cnt] = input2_data[i]; + } + if (cnt >= output_len) { + return kTfLiteOk; + } + + for (; cnt < output_len; cnt++) { + output_data[cnt] = 0; + } + return kTfLiteOk; +} + +bool PackerOp::freed_ = false; + +} // namespace testing +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helper_custom_ops.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helper_custom_ops.h new file mode 100644 index 000000000..9c950fc93 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helper_custom_ops.h @@ -0,0 +1,50 @@ +/* Copyright 2021 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_TEST_HELPER_CUSTOM_OPS_H_ +#define TENSORFLOW_LITE_MICRO_TEST_HELPER_CUSTOM_OPS_H_ + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "tensorflow/lite/micro/micro_utils.h" +#include "tensorflow/lite/portable_type_to_tflitetype.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { +namespace testing { + +class PackerOp { + public: + static const TfLiteRegistration* getRegistration(); + static TfLiteRegistration* GetMutableRegistration(); + static void* Init(TfLiteContext* context, const char* buffer, size_t length); + static void Free(TfLiteContext* context, void* buffer); + static TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node); + static TfLiteStatus Invoke(TfLiteContext* context, TfLiteNode* node); + + private: + static bool freed_; +}; + +} // namespace testing +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_TEST_HELPER_CUSTOM_OPS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helpers.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helpers.cpp new file mode 100644 index 000000000..003b64aab --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helpers.cpp @@ -0,0 +1,1913 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/micro/test_helpers.h" + +#include +#include +#include +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/memory_helpers.h" +#include "tensorflow/lite/micro/micro_arena_constants.h" +#include "tensorflow/lite/micro/micro_utils.h" +#include "tensorflow/lite/micro/test_helper_custom_ops.h" +#include "tensorflow/lite/schema/schema_generated.h" + +// TODO(b/170464050): Use TFLM test only version of schema_utils. + +namespace tflite { +namespace testing { +namespace { + +class StackAllocator : public flatbuffers::Allocator { + public: + StackAllocator(size_t alignment) : data_size_(0) { + data_ = AlignPointerUp(data_backing_, alignment); + } + + uint8_t* allocate(size_t size) override { + TFLITE_DCHECK((data_size_ + size) <= kStackAllocatorSize); + uint8_t* result = data_; + data_ += size; + data_size_ += size; + return result; + } + + void deallocate(uint8_t* p, size_t) override {} + + static StackAllocator& instance(size_t alignment = 1) { + // Avoid using true dynamic memory allocation to be portable to bare metal. + static char inst_memory[sizeof(StackAllocator)]; + static StackAllocator* inst = new (inst_memory) StackAllocator(alignment); + return *inst; + } + + static constexpr size_t kStackAllocatorSize = 8192; + + private: + uint8_t data_backing_[kStackAllocatorSize]; + uint8_t* data_; + int data_size_; + + TF_LITE_REMOVE_VIRTUAL_DELETE +}; + +flatbuffers::FlatBufferBuilder* BuilderInstance() { + static char inst_memory[sizeof(flatbuffers::FlatBufferBuilder)]; + static flatbuffers::FlatBufferBuilder* inst = + new (inst_memory) flatbuffers::FlatBufferBuilder( + StackAllocator::kStackAllocatorSize, + &StackAllocator::instance(MicroArenaBufferAlignment())); + return inst; +} + +// A wrapper around FlatBuffer API to help build model easily. +class ModelBuilder { + public: + typedef int32_t Tensor; + typedef int Operator; + typedef int Node; + + // `builder` needs to be available until BuildModel is called. + explicit ModelBuilder(flatbuffers::FlatBufferBuilder* builder) + : builder_(builder) {} + + // Registers an operator that will be used in the model. + Operator RegisterOp(BuiltinOperator op, const char* custom_code); + + // Adds a tensor to the model. + Tensor AddTensor(TensorType type, std::initializer_list shape) { + return AddTensorImpl(type, /* is_variable */ false, shape); + } + + // Adds a variable tensor to the model. + Tensor AddVariableTensor(TensorType type, + std::initializer_list shape) { + return AddTensorImpl(type, /* is_variable */ true, shape); + } + + // Adds a node to the model with given input and output Tensors. + Node AddNode(Operator op, std::initializer_list inputs, + std::initializer_list outputs, + std::initializer_list intermediates = + std::initializer_list{}); + + void AddMetadata(const char* description_string, + const int32_t* metadata_buffer_data, size_t num_elements); + + // Constructs the flatbuffer model using `builder_` and return a pointer to + // it. The returned model has the same lifetime as `builder_`. + // Note the default value of 0 for num_subgraph_inputs means all tensor inputs + // are in subgraph input list. + const Model* BuildModel(std::initializer_list inputs, + std::initializer_list outputs, + size_t num_subgraph_inputs = 0); + + private: + // Adds a tensor to the model. + Tensor AddTensorImpl(TensorType type, bool is_variable, + std::initializer_list shape); + + flatbuffers::FlatBufferBuilder* builder_; + + static constexpr int kMaxOperatorCodes = 10; + flatbuffers::Offset operator_codes_[kMaxOperatorCodes]; + int next_operator_code_id_ = 0; + + static constexpr int kMaxOperators = 50; + flatbuffers::Offset operators_[kMaxOperators]; + int next_operator_id_ = 0; + + static constexpr int kMaxTensors = 50; + flatbuffers::Offset tensors_[kMaxTensors]; + + static constexpr int kMaxMetadataBuffers = 10; + + static constexpr int kMaxMetadatas = 10; + flatbuffers::Offset metadata_[kMaxMetadatas]; + + flatbuffers::Offset metadata_buffers_[kMaxMetadataBuffers]; + + int nbr_of_metadata_buffers_ = 0; + + int next_tensor_id_ = 0; +}; + +ModelBuilder::Operator ModelBuilder::RegisterOp(BuiltinOperator op, + const char* custom_code) { + TFLITE_DCHECK(next_operator_code_id_ <= kMaxOperatorCodes); + operator_codes_[next_operator_code_id_] = tflite::CreateOperatorCodeDirect( + *builder_, /*deprecated_builtin_code=*/0, custom_code, /*version=*/0, op); + next_operator_code_id_++; + return next_operator_code_id_ - 1; +} + +ModelBuilder::Node ModelBuilder::AddNode( + ModelBuilder::Operator op, + std::initializer_list inputs, + std::initializer_list outputs, + std::initializer_list intermediates) { + TFLITE_DCHECK(next_operator_id_ <= kMaxOperators); + operators_[next_operator_id_] = tflite::CreateOperator( + *builder_, op, builder_->CreateVector(inputs.begin(), inputs.size()), + builder_->CreateVector(outputs.begin(), outputs.size()), + BuiltinOptions_NONE, + /*builtin_options=*/0, + /*custom_options=*/0, tflite::CustomOptionsFormat_FLEXBUFFERS, + /*mutating_variable_inputs =*/0, + builder_->CreateVector(intermediates.begin(), intermediates.size())); + next_operator_id_++; + return next_operator_id_ - 1; +} + +void ModelBuilder::AddMetadata(const char* description_string, + const int32_t* metadata_buffer_data, + size_t num_elements) { + metadata_[ModelBuilder::nbr_of_metadata_buffers_] = + CreateMetadata(*builder_, builder_->CreateString(description_string), + 1 + ModelBuilder::nbr_of_metadata_buffers_); + + metadata_buffers_[nbr_of_metadata_buffers_] = tflite::CreateBuffer( + *builder_, builder_->CreateVector((uint8_t*)metadata_buffer_data, + sizeof(uint32_t) * num_elements)); + + ModelBuilder::nbr_of_metadata_buffers_++; +} + +const Model* ModelBuilder::BuildModel( + std::initializer_list inputs, + std::initializer_list outputs, + size_t num_subgraph_inputs) { + // Model schema requires an empty buffer at idx 0. + size_t buffer_size = 1 + ModelBuilder::nbr_of_metadata_buffers_; + flatbuffers::Offset buffers[kMaxMetadataBuffers]; + buffers[0] = tflite::CreateBuffer(*builder_); + + // Place the metadata buffers first in the buffer since the indices for them + // have already been set in AddMetadata() + for (int i = 1; i < ModelBuilder::nbr_of_metadata_buffers_ + 1; ++i) { + buffers[i] = metadata_buffers_[i - 1]; + } + + // Default to single subgraph model. + constexpr size_t subgraphs_size = 1; + + // Find out number of subgraph inputs. + if (num_subgraph_inputs == 0) { + // This is the default case. + num_subgraph_inputs = inputs.size(); + } else { + // A non-zero value of num_subgraph_inputs means that some of + // the operator input tensors are not subgraph inputs. + TFLITE_DCHECK(num_subgraph_inputs <= inputs.size()); + } + + const flatbuffers::Offset subgraphs[subgraphs_size] = { + tflite::CreateSubGraph( + *builder_, builder_->CreateVector(tensors_, next_tensor_id_), + builder_->CreateVector(inputs.begin(), num_subgraph_inputs), + builder_->CreateVector(outputs.begin(), outputs.size()), + builder_->CreateVector(operators_, next_operator_id_), + builder_->CreateString("test_subgraph"))}; + + flatbuffers::Offset model_offset; + if (ModelBuilder::nbr_of_metadata_buffers_ > 0) { + model_offset = tflite::CreateModel( + *builder_, 0, + builder_->CreateVector(operator_codes_, next_operator_code_id_), + builder_->CreateVector(subgraphs, subgraphs_size), + builder_->CreateString("teset_model"), + builder_->CreateVector(buffers, buffer_size), 0, + builder_->CreateVector(metadata_, + ModelBuilder::nbr_of_metadata_buffers_)); + } else { + model_offset = tflite::CreateModel( + *builder_, 0, + builder_->CreateVector(operator_codes_, next_operator_code_id_), + builder_->CreateVector(subgraphs, subgraphs_size), + builder_->CreateString("teset_model"), + builder_->CreateVector(buffers, buffer_size)); + } + + tflite::FinishModelBuffer(*builder_, model_offset); + void* model_pointer = builder_->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +ModelBuilder::Tensor ModelBuilder::AddTensorImpl( + TensorType type, bool is_variable, std::initializer_list shape) { + TFLITE_DCHECK(next_tensor_id_ <= kMaxTensors); + tensors_[next_tensor_id_] = tflite::CreateTensor( + *builder_, builder_->CreateVector(shape.begin(), shape.size()), type, + /* buffer */ 0, /* name */ 0, /* quantization */ 0, + /* is_variable */ is_variable, + /* sparsity */ 0); + next_tensor_id_++; + return next_tensor_id_ - 1; +} + +const Model* BuildSimpleStatefulModel() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* fb_builder = BuilderInstance(); + + ModelBuilder model_builder(fb_builder); + + const int op_id = + model_builder.RegisterOp(BuiltinOperator_CUSTOM, "simple_stateful_op"); + const int input_tensor = model_builder.AddTensor(TensorType_INT8, {3}); + const int median_tensor = model_builder.AddTensor(TensorType_INT8, {3}); + const int invoke_count_tensor = + model_builder.AddTensor(TensorType_INT32, {1}); + const int intermediate_tensor = + model_builder.AddTensor(TensorType_FLOAT32, {0}); + + model_builder.AddNode(op_id, {input_tensor}, + {median_tensor, invoke_count_tensor}, + {intermediate_tensor}); + return model_builder.BuildModel({input_tensor}, + {median_tensor, invoke_count_tensor}); +} + +const Model* BuildSimpleModelWithBranch() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* fb_builder = BuilderInstance(); + + ModelBuilder model_builder(fb_builder); + /* Model structure + | t0 + +------| + | v + | +---------+ + | | n0 | + | | | + | +---------+ + v + + | + +---------+ | t1 + | n1 | | + | | | + +---------+ | + | | + t2 | v + | +---------+ + +-->| n2 | + | | + +-------|-+ + |t3 + v + */ + const int op_id = + model_builder.RegisterOp(BuiltinOperator_CUSTOM, "mock_custom"); + const int t0 = model_builder.AddTensor(TensorType_FLOAT32, {2, 2, 3}); + const int t1 = model_builder.AddTensor(TensorType_FLOAT32, {2, 2, 3}); + const int t2 = model_builder.AddTensor(TensorType_FLOAT32, {2, 2, 3}); + const int t3 = model_builder.AddTensor(TensorType_FLOAT32, {2, 2, 3}); + model_builder.AddNode(op_id, {t0}, {t1}); // n0 + model_builder.AddNode(op_id, {t0}, {t2}); // n1 + model_builder.AddNode(op_id, {t1, t2}, {t3}); // n2 + return model_builder.BuildModel({t0}, {t3}); +} + +const Model* BuildModelWithOfflinePlanning(int number_of_tensors, + const int32_t* metadata_buffer, + NodeConnection* node_conn, + int num_conns, + int num_subgraph_inputs) { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* fb_builder = BuilderInstance(); + + ModelBuilder model_builder(fb_builder); + + const int op_id = + model_builder.RegisterOp(BuiltinOperator_CUSTOM, "mock_custom"); + + for (int i = 0; i < number_of_tensors; ++i) { + model_builder.AddTensor(TensorType_FLOAT32, {2, 2, 3}); + } + + for (int i = 0; i < num_conns; ++i) { + model_builder.AddNode(op_id, node_conn[i].input, node_conn[i].output); + } + + model_builder.AddMetadata( + "OfflineMemoryAllocation", metadata_buffer, + number_of_tensors + tflite::testing::kOfflinePlannerHeaderSize); + + return model_builder.BuildModel( + node_conn[0].input, node_conn[num_conns - 1].output, num_subgraph_inputs); +} + +const Model* BuildModelWithUnusedInputs() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = {CreateBuffer(*builder)}; + constexpr size_t tensor_shape_size = 2; + const int32_t tensor_shape[tensor_shape_size] = {1, 64}; + constexpr size_t tensors_size = 4; + const Offset tensors[tensors_size] = { + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_input_tensor"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_unused_input_tensor"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_output_tensor"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_unused_tensor"), 0, false), + }; + constexpr size_t inputs_size = 2; + const int32_t inputs[inputs_size] = {0, 1}; + constexpr size_t outputs_size = 1; + const int32_t outputs[outputs_size] = {2}; + constexpr size_t operator_inputs_size = 1; + const int32_t operator_inputs[operator_inputs_size] = {0}; + constexpr size_t operator_outputs_size = 1; + const int32_t operator_outputs[operator_outputs_size] = {2}; + constexpr size_t operators_size = 1; + const Offset operators[operators_size] = { + CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE), + }; + constexpr size_t subgraphs_size = 1; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(tensors, tensors_size), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(outputs, outputs_size), + builder->CreateVector(operators, operators_size), + builder->CreateString("test_subgraph"))}; + constexpr size_t operator_codes_size = 1; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "mock_custom", + /*version=*/0, BuiltinOperator_CUSTOM)}; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +const Model* BuildModelWithUnusedOperatorOutputs() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = {CreateBuffer(*builder)}; + constexpr size_t tensor_shape_size = 2; + const int32_t tensor_shape[tensor_shape_size] = {1, 64}; + constexpr size_t tensors_size = 2; + const Offset tensors[tensors_size] = { + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_input_tensor"), 0, false), + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_unused_output_tensor"), 0, false)}; + constexpr size_t inputs_size = 0; + const int32_t inputs[inputs_size] = {}; + constexpr size_t outputs_size = 1; + const int32_t outputs[outputs_size] = {0}; + constexpr size_t operator_inputs_size = 0; + const int32_t operator_inputs[operator_inputs_size] = {}; + constexpr size_t operator_outputs_size = 2; + const int32_t operator_outputs[operator_outputs_size] = {0, 1}; + constexpr size_t operators_size = 1; + const Offset operators[operators_size] = { + CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE), + }; + constexpr size_t subgraphs_size = 1; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(tensors, tensors_size), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(outputs, outputs_size), + builder->CreateVector(operators, operators_size), + builder->CreateString("test_subgraph"))}; + constexpr size_t operator_codes_size = 1; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "mock_custom", + /*version=*/0, BuiltinOperator_CUSTOM)}; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +const Model* BuildModelWith256x256Tensor() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* fb_builder = BuilderInstance(); + + ModelBuilder model_builder(fb_builder); + + const int op_id = + model_builder.RegisterOp(BuiltinOperator_CUSTOM, "mock_custom"); + const int input1_tensor = + model_builder.AddTensor(TensorType_INT8, {256, 256}); + const int input2_tensor = + model_builder.AddTensor(TensorType_INT8, {256, 256}); + const int output_tensor = + model_builder.AddTensor(TensorType_INT8, {256, 256}); + + model_builder.AddNode(op_id, {input1_tensor, input2_tensor}, {output_tensor}); + return model_builder.BuildModel({input1_tensor, input2_tensor}, + {output_tensor}); +} + +const Model* BuildSimpleMockModel() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffer_data_size = 1; + const uint8_t buffer_data[buffer_data_size] = {21}; + constexpr size_t buffers_size = 2; + const Offset buffers[buffers_size] = { + CreateBuffer(*builder), + CreateBuffer(*builder, + builder->CreateVector(buffer_data, buffer_data_size))}; + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {1}; + constexpr size_t tensors_size = 4; + const Offset tensors[tensors_size] = { + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_input_tensor"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 1, + builder->CreateString("test_weight_tensor"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_output_tensor"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_output2_tensor"), 0, false), + }; + constexpr size_t inputs_size = 1; + const int32_t inputs[inputs_size] = {0}; + constexpr size_t outputs_size = 2; + const int32_t outputs[outputs_size] = {2, 3}; + constexpr size_t operator_inputs_size = 2; + const int32_t operator_inputs[operator_inputs_size] = {0, 1}; + constexpr size_t operator_outputs_size = 1; + const int32_t operator_outputs[operator_outputs_size] = {2}; + const int32_t operator2_outputs[operator_outputs_size] = {3}; + constexpr size_t operators_size = 2; + const Offset operators[operators_size] = { + CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE), + CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator2_outputs, operator_outputs_size), + BuiltinOptions_NONE), + }; + constexpr size_t subgraphs_size = 1; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(tensors, tensors_size), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(outputs, outputs_size), + builder->CreateVector(operators, operators_size), + builder->CreateString("test_subgraph"))}; + constexpr size_t operator_codes_size = 1; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "mock_custom", + /*version=*/0, BuiltinOperator_CUSTOM)}; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +const Model* BuildComplexMockModel() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffer_data_size = 1; + const uint8_t buffer_data_1[buffer_data_size] = {21}; + const uint8_t buffer_data_2[buffer_data_size] = {21}; + const uint8_t buffer_data_3[buffer_data_size] = {21}; + constexpr size_t buffers_size = 7; + const Offset buffers[buffers_size] = { + // Op 1 buffers: + CreateBuffer(*builder), + CreateBuffer(*builder), + CreateBuffer(*builder, + builder->CreateVector(buffer_data_1, buffer_data_size)), + // Op 2 buffers: + CreateBuffer(*builder), + CreateBuffer(*builder, + builder->CreateVector(buffer_data_2, buffer_data_size)), + // Op 3 buffers: + CreateBuffer(*builder), + CreateBuffer(*builder, + builder->CreateVector(buffer_data_3, buffer_data_size)), + }; + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {1}; + + constexpr size_t tensors_size = 10; + const Offset tensors[tensors_size] = { + // Op 1 inputs: + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_input_tensor_1"), 0, + false /* is_variable */), + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 1, builder->CreateString("test_variable_tensor_1"), + 0, true /* is_variable */), + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 2, builder->CreateString("test_weight_tensor_1"), 0, + false /* is_variable */), + // Op 1 output / Op 2 input: + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_output_tensor_1"), 0, + false /* is_variable */), + // Op 2 inputs: + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 1, builder->CreateString("test_variable_tensor_2"), + 0, true /* is_variable */), + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 2, builder->CreateString("test_weight_tensor_2"), 0, + false /* is_variable */), + // Op 2 output / Op 3 input: + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_output_tensor_2"), 0, + false /* is_variable */), + // Op 3 inputs: + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 1, builder->CreateString("test_variable_tensor_3"), + 0, true /* is_variable */), + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 2, builder->CreateString("test_weight_tensor_3"), 0, + false /* is_variable */), + // Op 3 output: + CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_output_tensor_3"), 0, + false /* is_variable */), + }; + + constexpr size_t operators_size = 3; + Offset operators[operators_size]; + { + // Set Op 1 attributes: + constexpr size_t operator_inputs_size = 3; + const int32_t operator_inputs[operator_inputs_size] = {0, 1, 2}; + constexpr size_t operator_outputs_size = 1; + const int32_t operator_outputs[operator_outputs_size] = {3}; + + operators[0] = {CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE)}; + } + + { + // Set Op 2 attributes + constexpr size_t operator_inputs_size = 3; + const int32_t operator_inputs[operator_inputs_size] = {3, 4, 5}; + constexpr size_t operator_outputs_size = 1; + const int32_t operator_outputs[operator_outputs_size] = {6}; + + operators[1] = {CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE)}; + } + + { + // Set Op 3 attributes + constexpr size_t operator_inputs_size = 3; + const int32_t operator_inputs[operator_inputs_size] = {6, 7, 8}; + constexpr size_t operator_outputs_size = 1; + const int32_t operator_outputs[operator_outputs_size] = {9}; + + operators[2] = {CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE)}; + } + + constexpr size_t inputs_size = 1; + const int32_t inputs[inputs_size] = {0}; + constexpr size_t outputs_size = 1; + const int32_t outputs[outputs_size] = {9}; + + constexpr size_t subgraphs_size = 1; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(tensors, tensors_size), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(outputs, outputs_size), + builder->CreateVector(operators, operators_size), + builder->CreateString("test_subgraph"))}; + + constexpr size_t operator_codes_size = 1; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "mock_custom", + /*version=*/0, BuiltinOperator_CUSTOM)}; + + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +const Model* BuildSimpleMultipleInputsModel() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = { + CreateBuffer(*builder), + }; + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {1}; + constexpr size_t tensors_size = 4; + const Offset tensors[tensors_size] = { + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_input_tensor1"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT8, 0, + builder->CreateString("test_input_tensor2"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_input_tensor3"), 0, false), + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_output_tensor"), 0, false), + }; + constexpr size_t inputs_size = 3; + const int32_t inputs[inputs_size] = {0, 1, 2}; + constexpr size_t outputs_size = 1; + const int32_t outputs[outputs_size] = {3}; + constexpr size_t operator_inputs_size = 3; + const int32_t operator_inputs[operator_inputs_size] = {0, 1, 2}; + constexpr size_t operator_outputs_size = 1; + const int32_t operator_outputs[operator_outputs_size] = {3}; + constexpr size_t operators_size = 1; + const Offset operators[operators_size] = { + CreateOperator( + *builder, 0, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, operator_outputs_size), + BuiltinOptions_NONE), + }; + constexpr size_t subgraphs_size = 1; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(tensors, tensors_size), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(outputs, outputs_size), + builder->CreateVector(operators, operators_size), + builder->CreateString("test_subgraph"))}; + constexpr size_t operator_codes_size = 1; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_CUSTOM)}; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +const Model* BuildSimpleModelWithSubgraphsAndIf() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = { + CreateBuffer(*builder), + }; + const int32_t condition_tensor_shape[] = {1}; + const int32_t data_tensor_shape[] = {1, 2}; + constexpr size_t tensors_size = 4; + const Offset subgraph1_tensors[tensors_size] = { + CreateTensor(*builder, builder->CreateVector(condition_tensor_shape, 1), + TensorType_BOOL, 0, + builder->CreateString("condition tensor"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor2"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("output_tensor"), 0, false), + }; + const Offset subgraph2_tensors[tensors_size] = { + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor2"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("output_tensor"), 0, false), + }; + const Offset subgraph3_tensors[tensors_size] = { + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor2"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 2), + TensorType_FLOAT32, 0, + builder->CreateString("output_tensor"), 0, false), + }; + + constexpr size_t if_inputs_size = 3; + const int32_t if_inputs[if_inputs_size] = {0, 1, 2}; + constexpr size_t outputs_size = 1; + const int32_t if_outputs[outputs_size] = {3}; + constexpr size_t operator_inputs_size = 2; + const int32_t operator_inputs[operator_inputs_size] = {0, 1}; + const int32_t operator_outputs[outputs_size] = {2}; + constexpr size_t operators_size = 1; + const Offset subgraph1_operators[operators_size] = { + CreateOperator( + *builder, 0, builder->CreateVector(if_inputs, if_inputs_size), + builder->CreateVector(if_outputs, outputs_size), + BuiltinOptions_IfOptions, CreateIfOptions(*builder, 1, 2).Union()), + }; + const Offset subgraph2_operators[operators_size] = { + CreateOperator( + *builder, 1, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, outputs_size), + BuiltinOptions_NONE), + }; + const Offset subgraph3_operators[operators_size] = { + CreateOperator( + *builder, 2, + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, outputs_size), + BuiltinOptions_NONE), + }; + constexpr size_t subgraphs_size = 3; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(subgraph1_tensors, 4), + builder->CreateVector(if_inputs, if_inputs_size), + builder->CreateVector(if_outputs, outputs_size), + builder->CreateVector(subgraph1_operators, operators_size), + builder->CreateString("if_subgraph")), + CreateSubGraph( + *builder, builder->CreateVector(subgraph2_tensors, 3), + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, outputs_size), + builder->CreateVector(subgraph2_operators, operators_size), + builder->CreateString("then_subgraph")), + CreateSubGraph( + *builder, builder->CreateVector(subgraph3_tensors, 3), + builder->CreateVector(operator_inputs, operator_inputs_size), + builder->CreateVector(operator_outputs, outputs_size), + builder->CreateVector(subgraph3_operators, operators_size), + builder->CreateString("else_subgraph")), + }; + constexpr size_t operator_codes_size = 3; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_IF), + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_ADD), + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_MUL), + }; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +const Model* BuildSimpleModelWithSubgraphsAndWhile() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = { + CreateBuffer(*builder), + }; + const int32_t data_tensor_shape[] = {1, 1}; + constexpr size_t while_tensors_size = 4; + constexpr size_t op_tensors_size = 3; + const Offset subgraph0_tensors[while_tensors_size] = { + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor0"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("output_tensor0"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("output_tensor1"), 0, false), + }; + const Offset subgraph1_tensors[op_tensors_size] = { + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor2"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_BOOL, 0, + builder->CreateString("condition_tensor"), 0, false), + }; + const Offset subgraph2_tensors[op_tensors_size] = { + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor0"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(data_tensor_shape, 1), + TensorType_FLOAT32, 0, + builder->CreateString("output_tensor0"), 0, false), + }; + + constexpr size_t inputs_size = 2; + const int32_t inputs[inputs_size] = {0, 1}; + constexpr size_t while_outputs_size = 2; + const int32_t while_outputs[while_outputs_size] = {2, 3}; + constexpr size_t cond_outputs_size = 1; + const int32_t cond_outputs[cond_outputs_size] = {2}; + constexpr size_t add_outputs_size = 1; + const int32_t add_outputs[add_outputs_size] = {2}; + constexpr size_t add_subgraph_outputs_size = 2; + const int32_t add_subgraph_outputs[add_subgraph_outputs_size] = {2, 1}; + constexpr size_t operators_size = 1; + const Offset subgraph0_operators[operators_size] = { + CreateOperator(*builder, 0, builder->CreateVector(inputs, inputs_size), + builder->CreateVector(while_outputs, while_outputs_size), + BuiltinOptions_WhileOptions, + CreateWhileOptions(*builder, 1, 2).Union()), + }; + const Offset subgraph1_operators[operators_size] = { + CreateOperator(*builder, 1, builder->CreateVector(inputs, inputs_size), + builder->CreateVector(cond_outputs, cond_outputs_size), + BuiltinOptions_NONE), + }; + const Offset subgraph2_operators[operators_size] = { + CreateOperator(*builder, 2, builder->CreateVector(inputs, inputs_size), + builder->CreateVector(add_outputs, add_outputs_size), + BuiltinOptions_NONE), + }; + constexpr size_t subgraphs_size = 3; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph(*builder, builder->CreateVector(subgraph0_tensors, 4), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(while_outputs, while_outputs_size), + builder->CreateVector(subgraph0_operators, operators_size), + builder->CreateString("while_subgraph")), + CreateSubGraph(*builder, builder->CreateVector(subgraph1_tensors, 3), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(cond_outputs, cond_outputs_size), + builder->CreateVector(subgraph1_operators, operators_size), + builder->CreateString("cond_subgraph")), + CreateSubGraph(*builder, builder->CreateVector(subgraph2_tensors, 3), + builder->CreateVector(inputs, inputs_size), + builder->CreateVector(add_subgraph_outputs, + add_subgraph_outputs_size), + builder->CreateVector(subgraph2_operators, operators_size), + builder->CreateString("body_subgraph")), + }; + constexpr size_t operator_codes_size = 3; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_WHILE), + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_LESS), + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "multiple_inputs_op", + /*version=*/0, BuiltinOperator_ADD), + }; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +// Build a model with If and two subgraphs: two data tensors A1 of size 2, A2 of +// size 4 are first concatenated, then cut to a new tensor A3 of size 3; the new +// tensor A3 of size 3 is then concatenated with A2 tensor of size 4 to produce +// a final output tensor A4. This model is specially crafted to capture the +// corner case outlined in go/avoid-memory-corruption-in-if-operator. +// +// Subgraph0 +// A0(1) A2_0(4) A1_0(2) +// | | | ---+ +// v v v | +// +--------------+ | +// | IF | | +// +------+-------+ | +// | A3_0(3) | +// v | +// +--------------+ | +// | CUSTOM |<---+ +// +------+-------+ +// | +// v +// A4_0(8) +// +// Subgraph1/2 +// A1_1(2) A2_1(4) +// | | +// v v +// +---------------+ +// | CUSTOM | +// +-------+-------+ +// | +// v A3_1(3) +// +// And it leads to memory plan as below +// +// Subgraph0 Layout +// +// +// <------------A4_0 -------------> <----- A2_0-------> <----A3_0 ---> +// +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +// | | | | | | | | | 3 | 4 | 5 | 6 | | | | +// +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +// +// +----+----+----+ +// | 1 | 2 | A0 | +// +----+----+----+ +// <---A1_0--> +// +// Subgraph 1 Layout +// +// +----+----+----+----+----+----+----+----+----+ +// | | | | | | | | | | +// +----+----+----+----+----+----+----+----+----+ +// +// +// <------A2_1 -------><----A3_1 ---><--A1_1---> +// +// +// A1_1 of subgraph 1 will overlap with A2_0 of subgraph 0. +// In a buggy implementation of IF, two overwrite may happen: +// 1. copying input from A1_0 to A1_1 overwrites A2_0 before A2_0 is copied to +// A2_1; thus subgraph 1 produce incorrect output. +// 2. copying output from A3_1 to A4_0 overwrites A1_0, which should remain +// intact so that it can be used by the OP after the IF operator in subgraph 0 +// + +const Model* BuildModelWithIfAndSubgraphInputTensorOverlap() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr TensorType kTensorType = TensorType_INT32; + constexpr int kBlockSize = + tflite::MicroArenaBufferAlignment() / sizeof(int32_t); + constexpr size_t kBuffersCount = 1; + const Offset buffers[kBuffersCount] = { + CreateBuffer(*builder), + }; + const int32_t kConditionTensorShape[] = {1}; + const int32_t kIfInput1TensorShape[] = {2 * kBlockSize}; + const int32_t kIfInput2TensorShape[] = {4 * kBlockSize}; + const int32_t kIfOutputTensorShape[] = {3 * kBlockSize}; + const int32_t kFinalOutputTensorShape[] = {8 * kBlockSize}; + constexpr size_t kSubgraph0TensorsCount = 5; + const Offset kSubgraph0Tensors[kSubgraph0TensorsCount] = { + CreateTensor(*builder, builder->CreateVector(kConditionTensorShape, 1), + TensorType_BOOL, 0, + builder->CreateString("condition tensor"), 0, false), + CreateTensor(*builder, builder->CreateVector(kIfInput1TensorShape, 1), + kTensorType, 0, builder->CreateString("if_input_tensor1"), 0, + false), + CreateTensor(*builder, builder->CreateVector(kIfInput2TensorShape, 1), + kTensorType, 0, builder->CreateString("if_input_tensor2"), 0, + false), + CreateTensor(*builder, builder->CreateVector(kIfOutputTensorShape, 1), + kTensorType, 0, builder->CreateString("if_output_tensor"), 0, + false), + CreateTensor(*builder, builder->CreateVector(kFinalOutputTensorShape, 1), + kTensorType, 0, builder->CreateString("final_output_tensor"), + 0, false), + }; + + // Subgraph 1 is the chosen path if condition tensor in IF is true. + constexpr size_t kSubgraph1TensorsCount = 3; + const Offset kSubgraph1Tensors[kSubgraph1TensorsCount] = { + CreateTensor(*builder, builder->CreateVector(kIfInput1TensorShape, 1), + kTensorType, 0, + builder->CreateString("subgraph1_input_tensor1"), 0, false), + CreateTensor(*builder, builder->CreateVector(kIfInput2TensorShape, 1), + kTensorType, 0, + builder->CreateString("subgraph1_input_tensor2"), 0, false), + CreateTensor(*builder, builder->CreateVector(kIfOutputTensorShape, 1), + kTensorType, 0, + builder->CreateString("subgraph1_output_tensor"), 0, false), + }; + + // Subgraph 2 is the chosen path if condition tensor in IF is false + constexpr size_t kSubgraph2TensorsCount = 3; + const Offset kSubgraph2Tensors[kSubgraph2TensorsCount] = { + CreateTensor(*builder, builder->CreateVector(kIfInput1TensorShape, 1), + kTensorType, 0, builder->CreateString("if_input_tensor1"), 0, + false), + CreateTensor(*builder, builder->CreateVector(kIfInput2TensorShape, 1), + kTensorType, 0, builder->CreateString("if_input_tensor2"), 0, + false), + CreateTensor(*builder, builder->CreateVector(kIfOutputTensorShape, 1), + kTensorType, 0, builder->CreateString("if_output_tensor"), 0, + false), + }; + + constexpr int kIfOpCodeIndex = 0; + constexpr int kCustomOpCodeIndex = 1; + + constexpr size_t kIfInputsCount = 3; + const int32_t kIfInputs[kIfInputsCount] = {0, 1, 2}; + constexpr size_t kOutputsCount = 1; + const int32_t kIfOutputs[kOutputsCount] = {3}; + constexpr size_t kOpAfterIfInputsCount = 2; + const int32_t kOpAfterIfInputs[kOpAfterIfInputsCount] = {3, 2}; + const int32_t kOpAfterIfOutputs[kOutputsCount] = {4}; + constexpr size_t kOperatorsCount = 2; + const Offset kSubgraph0Operators[kOperatorsCount] = { + CreateOperator(*builder, kIfOpCodeIndex, + builder->CreateVector(kIfInputs, kIfInputsCount), + builder->CreateVector(kIfOutputs, kOutputsCount), + BuiltinOptions_IfOptions, + CreateIfOptions(*builder, 1, 2).Union()), + CreateOperator( + *builder, kCustomOpCodeIndex, + builder->CreateVector(kOpAfterIfInputs, kOpAfterIfInputsCount), + builder->CreateVector(kOpAfterIfOutputs, kOutputsCount)), + }; + + constexpr size_t kSubgraph1InputsCount = 2; + const int32_t kSubgraph1Inputs[kSubgraph1InputsCount] = {0, 1}; + constexpr size_t kSubgraph1OutputsCount = 1; + const int32_t kSubgraph1Outputs[kSubgraph1OutputsCount] = {2}; + constexpr size_t kSubgraph1OperatorsCount = 1; + const Offset kSubgraph1Operators[kSubgraph1OperatorsCount] = { + CreateOperator( + *builder, kCustomOpCodeIndex, + builder->CreateVector(kSubgraph1Inputs, kSubgraph1InputsCount), + builder->CreateVector(kSubgraph1Outputs, kSubgraph1OutputsCount), + BuiltinOptions_NONE), + }; + + constexpr size_t kSubgraph2InputsCount = 2; + const int32_t kSubgraph2Inputs[kSubgraph2InputsCount] = {0, 1}; + constexpr size_t kSubgraph2OutputsCount = 1; + const int32_t kSubgraph2Outputs[kSubgraph2OutputsCount] = {2}; + constexpr size_t kSubgraph2OperatorsCount = 1; + const Offset kSubgraph2Operators[kSubgraph2OperatorsCount] = { + CreateOperator( + *builder, kCustomOpCodeIndex, + builder->CreateVector(kSubgraph2Inputs, kSubgraph2InputsCount), + builder->CreateVector(kSubgraph2Outputs, kSubgraph2OutputsCount), + BuiltinOptions_NONE), + }; + + constexpr size_t kSubgraphsCount = 3; + const Offset kSubgraphs[kSubgraphsCount] = { + CreateSubGraph( + *builder, + builder->CreateVector(kSubgraph0Tensors, kSubgraph0TensorsCount), + builder->CreateVector(kIfInputs, kIfInputsCount), + builder->CreateVector(kOpAfterIfOutputs, kOutputsCount), + builder->CreateVector(kSubgraph0Operators, kOperatorsCount), + builder->CreateString("if_subgraph")), + CreateSubGraph( + *builder, + builder->CreateVector(kSubgraph1Tensors, kSubgraph1TensorsCount), + builder->CreateVector(kSubgraph1Inputs, kSubgraph1InputsCount), + builder->CreateVector(kSubgraph1Outputs, kSubgraph1OutputsCount), + builder->CreateVector(kSubgraph1Operators, kSubgraph1OperatorsCount), + builder->CreateString("then_subgraph")), + CreateSubGraph( + *builder, + builder->CreateVector(kSubgraph2Tensors, kSubgraph2TensorsCount), + builder->CreateVector(kSubgraph2Inputs, kSubgraph2InputsCount), + builder->CreateVector(kSubgraph2Outputs, kSubgraph2OutputsCount), + builder->CreateVector(kSubgraph2Operators, kSubgraph2OperatorsCount), + builder->CreateString("else_subgraph")), + }; + + constexpr size_t kOperatorCodesCount = 2; + const Offset kOperatorCodes[kOperatorCodesCount] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, "if", + /*version=*/0, BuiltinOperator_IF), + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "custom_packer_op", + /*version=*/0, BuiltinOperator_CUSTOM), + }; + const Offset kModelOffset = CreateModel( + *builder, 0, builder->CreateVector(kOperatorCodes, kOperatorCodesCount), + builder->CreateVector(kSubgraphs, kSubgraphsCount), + builder->CreateString("test_model"), + builder->CreateVector(buffers, kBuffersCount)); + FinishModelBuffer(*builder, kModelOffset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +// Mock model with one main subgraph containing a single CALL_ONCE op (with null +// inputs and outputs) which invokes a second subgraph which has null inputs and +// outputs. +const Model* BuildSimpleMockModelWithNullInputsOutputs() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = { + CreateBuffer(*builder), + }; + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {0}; + constexpr size_t tensors_size = 1; + const Offset tensors[tensors_size] = { + CreateTensor(*builder, + builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, + builder->CreateString("test_input_tensor1"), 0, false), + }; + constexpr size_t subgraph0_inputs_size = 1; + const int32_t subgraph0_inputs[subgraph0_inputs_size] = {0}; + constexpr size_t subgraph0_outputs_size = 1; + const int32_t subgraph0_outputs[subgraph0_outputs_size] = {0}; + constexpr size_t operators_size = 1; + const Offset subgraph0_operators[operators_size] = { + CreateOperator(*builder, 0, {}, {}, BuiltinOptions_CallOnceOptions, + CreateCallOnceOptions(*builder, 1).Union()), + }; + const Offset subgraph1_operators[operators_size] = { + CreateOperator(*builder, 1, {}, {}, BuiltinOptions_NONE)}; + constexpr size_t subgraphs_size = 2; + const Offset subgraphs[subgraphs_size] = { + CreateSubGraph( + *builder, builder->CreateVector(tensors, tensors_size), + builder->CreateVector(subgraph0_inputs, subgraph0_inputs_size), + builder->CreateVector(subgraph0_outputs, subgraph0_outputs_size), + builder->CreateVector(subgraph0_operators, operators_size), + builder->CreateString("main_subgraph")), + CreateSubGraph(*builder, builder->CreateVector(tensors, tensors_size), {}, + {}, + builder->CreateVector(subgraph1_operators, operators_size), + builder->CreateString("secondary subgraph")), + }; + constexpr size_t operator_codes_size = 2; + const Offset operator_codes[operator_codes_size] = { + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, + "call_once_op", + /*version=*/0, BuiltinOperator_CALL_ONCE), + CreateOperatorCodeDirect(*builder, /*deprecated_builtin_code=*/0, "no_op", + /*version=*/0, BuiltinOperator_CUSTOM)}; + const Offset model_offset = CreateModel( + *builder, 0, builder->CreateVector(operator_codes, operator_codes_size), + builder->CreateVector(subgraphs, subgraphs_size), + builder->CreateString("test_model"), + builder->CreateVector(buffers, buffers_size)); + FinishModelBuffer(*builder, model_offset); + void* model_pointer = builder->GetBufferPointer(); + const Model* model = flatbuffers::GetRoot(model_pointer); + return model; +} + +} // namespace + +const TfLiteRegistration* SimpleStatefulOp::getRegistration() { + return GetMutableRegistration(); +} + +TfLiteRegistration* SimpleStatefulOp::GetMutableRegistration() { + static TfLiteRegistration r; + r.init = Init; + r.prepare = Prepare; + r.invoke = Invoke; + return &r; +} + +void* SimpleStatefulOp::Init(TfLiteContext* context, const char* buffer, + size_t length) { + TFLITE_DCHECK(context->AllocateBufferForEval == nullptr); + TFLITE_DCHECK(context->GetScratchBuffer == nullptr); + TFLITE_DCHECK(context->RequestScratchBufferInArena == nullptr); + + void* raw = context->AllocatePersistentBuffer(context, sizeof(OpData)); + OpData* data = reinterpret_cast(raw); + *data = {}; + return raw; +} + +TfLiteStatus SimpleStatefulOp::Prepare(TfLiteContext* context, + TfLiteNode* node) { + OpData* data = reinterpret_cast(node->user_data); + + // Make sure that the input is in uint8_t with at least 1 data entry. + MicroContext* micro_context = GetMicroContext(context); + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + + if (input->type != kTfLiteInt8) return kTfLiteError; + if (NumElements(input->dims) == 0) return kTfLiteError; + + // Allocate a temporary buffer with the same size of input for sorting. + TF_LITE_ENSURE_STATUS(context->RequestScratchBufferInArena( + context, sizeof(uint8_t) * NumElements(input->dims), + &data->sorting_buffer)); + // We can interleave scratch / persistent buffer allocation. + data->invoke_count = reinterpret_cast( + context->AllocatePersistentBuffer(context, sizeof(int))); + *data->invoke_count = 0; + + micro_context->DeallocateTempTfLiteTensor(input); + return kTfLiteOk; +} + +TfLiteStatus SimpleStatefulOp::Invoke(TfLiteContext* context, + TfLiteNode* node) { + OpData* data = reinterpret_cast(node->user_data); + *data->invoke_count += 1; + + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + const uint8_t* input_data = input->data.uint8; + int size = NumElements(input->dims); + + uint8_t* sorting_buffer = reinterpret_cast( + context->GetScratchBuffer(context, data->sorting_buffer)); + // Copy inputs data to the sorting buffer. We don't want to mutate the input + // tensor as it might be used by a another node. + for (int i = 0; i < size; i++) { + sorting_buffer[i] = input_data[i]; + } + + // In place insertion sort on `sorting_buffer`. + for (int i = 1; i < size; i++) { + for (int j = i; j > 0 && sorting_buffer[j] < sorting_buffer[j - 1]; j--) { + std::swap(sorting_buffer[j], sorting_buffer[j - 1]); + } + } + + TfLiteEvalTensor* median = + tflite::micro::GetEvalOutput(context, node, kMedianTensor); + TF_LITE_ENSURE(context, median != nullptr); + uint8_t* median_data = median->data.uint8; + TfLiteEvalTensor* invoke_count = + tflite::micro::GetEvalOutput(context, node, kInvokeCount); + TF_LITE_ENSURE(context, invoke_count != nullptr); + int32_t* invoke_count_data = invoke_count->data.i32; + + median_data[0] = sorting_buffer[size / 2]; + invoke_count_data[0] = *data->invoke_count; + return kTfLiteOk; +} + +const TfLiteRegistration* MockCustom::getRegistration() { + return GetMutableRegistration(); +} + +TfLiteRegistration* MockCustom::GetMutableRegistration() { + static TfLiteRegistration r; + r.init = Init; + r.prepare = Prepare; + r.invoke = Invoke; + r.free = Free; + return &r; +} + +void* MockCustom::Init(TfLiteContext* context, const char* buffer, + size_t length) { + // We don't support delegate in TFL micro. This is a weak check to test if + // context struct being zero-initialized. + TFLITE_DCHECK(context->ReplaceNodeSubsetsWithDelegateKernels == nullptr); + freed_ = false; + // Do nothing. + return nullptr; +} + +void MockCustom::Free(TfLiteContext* context, void* buffer) { freed_ = true; } + +TfLiteStatus MockCustom::Prepare(TfLiteContext* context, TfLiteNode* node) { + return kTfLiteOk; +} + +TfLiteStatus MockCustom::Invoke(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TF_LITE_ENSURE(context, input != nullptr); + const int32_t* input_data = input->data.i32; + const TfLiteEvalTensor* weight = + tflite::micro::GetEvalInput(context, node, 1); + TF_LITE_ENSURE(context, weight != nullptr); + const uint8_t* weight_data = weight->data.uint8; + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE(context, output != nullptr); + int32_t* output_data = output->data.i32; + output_data[0] = + 0; // Catch output tensor sharing memory with an input tensor + output_data[0] = input_data[0] + weight_data[0]; + return kTfLiteOk; +} + +bool MockCustom::freed_ = false; + +const TfLiteRegistration* MultipleInputs::getRegistration() { + return GetMutableRegistration(); +} + +TfLiteRegistration* MultipleInputs::GetMutableRegistration() { + static TfLiteRegistration r; + r.init = Init; + r.prepare = Prepare; + r.invoke = Invoke; + r.free = Free; + return &r; +} + +void* MultipleInputs::Init(TfLiteContext* context, const char* buffer, + size_t length) { + // We don't support delegate in TFL micro. This is a weak check to test if + // context struct being zero-initialized. + TFLITE_DCHECK(context->ReplaceNodeSubsetsWithDelegateKernels == nullptr); + freed_ = false; + // Do nothing. + return nullptr; +} + +void MultipleInputs::Free(TfLiteContext* context, void* buffer) { + freed_ = true; +} + +TfLiteStatus MultipleInputs::Prepare(TfLiteContext* context, TfLiteNode* node) { + return kTfLiteOk; +} + +TfLiteStatus MultipleInputs::Invoke(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = tflite::micro::GetEvalInput(context, node, 0); + TF_LITE_ENSURE(context, input != nullptr); + const int32_t* input_data = input->data.i32; + const TfLiteEvalTensor* input1 = + tflite::micro::GetEvalInput(context, node, 1); + TF_LITE_ENSURE(context, input1 != nullptr); + const int32_t* input_data1 = input1->data.i32; + const TfLiteEvalTensor* input2 = + tflite::micro::GetEvalInput(context, node, 2); + TF_LITE_ENSURE(context, input2 != nullptr); + const int32_t* input_data2 = input2->data.i32; + + TfLiteEvalTensor* output = tflite::micro::GetEvalOutput(context, node, 0); + TF_LITE_ENSURE(context, output != nullptr); + int32_t* output_data = output->data.i32; + output_data[0] = + 0; // Catch output tensor sharing memory with an input tensor + output_data[0] = input_data[0] + input_data1[0] + input_data2[0]; + return kTfLiteOk; +} + +bool MultipleInputs::freed_ = false; + +const TfLiteRegistration* NoOp::getRegistration() { + return GetMutableRegistration(); +} + +TfLiteRegistration* NoOp::GetMutableRegistration() { + static TfLiteRegistration r; + r.init = Init; + r.prepare = Prepare; + r.invoke = Invoke; + r.free = Free; + return &r; +} + +void* NoOp::Init(TfLiteContext* context, const char* buffer, size_t length) { + // We don't support delegate in TFL micro. This is a weak check to test if + // context struct being zero-initialized. + TFLITE_DCHECK(context->ReplaceNodeSubsetsWithDelegateKernels == nullptr); + freed_ = false; + // Do nothing. + return nullptr; +} + +void NoOp::Free(TfLiteContext* context, void* buffer) { freed_ = true; } + +TfLiteStatus NoOp::Prepare(TfLiteContext* context, TfLiteNode* node) { + return kTfLiteOk; +} + +TfLiteStatus NoOp::Invoke(TfLiteContext* context, TfLiteNode* node) { + return kTfLiteOk; +} + +bool NoOp::freed_ = false; + +AllOpsResolver GetOpResolver() { + AllOpsResolver op_resolver; + op_resolver.AddCustom("mock_custom", MockCustom::GetMutableRegistration()); + op_resolver.AddCustom("simple_stateful_op", + SimpleStatefulOp::GetMutableRegistration()); + op_resolver.AddCustom("multiple_inputs_op", + MultipleInputs::GetMutableRegistration()); + op_resolver.AddCustom("no_op", NoOp::GetMutableRegistration()); + op_resolver.AddCustom("custom_packer_op", PackerOp::GetMutableRegistration()); + return op_resolver; +} + +const Model* GetModelWithUnusedInputs() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildModelWithUnusedInputs()); + } + return model; +} + +const Model* GetModelWithUnusedOperatorOutputs() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildModelWithUnusedOperatorOutputs()); + } + return model; +} + +const Model* GetModelWith256x256Tensor() { + static const Model* model = BuildModelWith256x256Tensor(); + return model; +} + +const Model* GetSimpleMockModel() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleMockModel()); + } + return model; +} + +const Model* GetSimpleMultipleInputsModel() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleMultipleInputsModel()); + } + return model; +} + +const Model* GetSimpleModelWithSubgraphsAndIf() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleModelWithSubgraphsAndIf()); + } + return model; +} + +const Model* GetSimpleModelWithSubgraphsAndWhile() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleModelWithSubgraphsAndWhile()); + } + return model; +} + +const Model* GetModelWithIfAndSubgraphInputTensorOverlap() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildModelWithIfAndSubgraphInputTensorOverlap()); + } + return model; +} + +const Model* GetSimpleModelWithNullInputsAndOutputs() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleMockModelWithNullInputsOutputs()); + } + return model; +} + +const Model* GetComplexMockModel() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildComplexMockModel()); + } + return model; +} + +const Model* GetSimpleModelWithBranch() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleModelWithBranch()); + } + return model; +} + +const Model* GetModelWithOfflinePlanning(int num_tensors, + const int32_t* metadata_buffer, + NodeConnection* node_conn, + int num_conns, + int num_subgraph_inputs) { + const Model* model = BuildModelWithOfflinePlanning( + num_tensors, metadata_buffer, node_conn, num_conns, num_subgraph_inputs); + return model; +} + +const Model* GetSimpleStatefulModel() { + static Model* model = nullptr; + if (!model) { + model = const_cast(BuildSimpleStatefulModel()); + } + return model; +} + +const Tensor* Create1dFlatbufferTensor(int size, bool is_variable) { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {size}; + const Offset tensor_offset = CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_tensor"), 0, + is_variable); + builder->Finish(tensor_offset); + void* tensor_pointer = builder->GetBufferPointer(); + const Tensor* tensor = flatbuffers::GetRoot(tensor_pointer); + return tensor; +} + +const Tensor* CreateQuantizedFlatbufferTensor(int size) { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + constexpr size_t quant_params_size = 1; + const float min_array[quant_params_size] = {0.1f}; + const float max_array[quant_params_size] = {0.2f}; + const float scale_array[quant_params_size] = {0.3f}; + const int64_t zero_point_array[quant_params_size] = {100ll}; + + const Offset quant_params = + CreateQuantizationParameters( + *builder, + /*min=*/builder->CreateVector(min_array, quant_params_size), + /*max=*/builder->CreateVector(max_array, quant_params_size), + /*scale=*/ + builder->CreateVector(scale_array, quant_params_size), + /*zero_point=*/ + builder->CreateVector(zero_point_array, quant_params_size)); + + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {size}; + const Offset tensor_offset = CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_tensor"), quant_params, + false); + builder->Finish(tensor_offset); + void* tensor_pointer = builder->GetBufferPointer(); + const Tensor* tensor = flatbuffers::GetRoot(tensor_pointer); + return tensor; +} + +const Tensor* CreateMissingQuantizationFlatbufferTensor(int size) { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + const Offset quant_params = + CreateQuantizationParameters(*builder, 0, 0, 0, 0, + QuantizationDetails_NONE, 0, 0); + constexpr size_t tensor_shape_size = 1; + const int32_t tensor_shape[tensor_shape_size] = {size}; + const Offset tensor_offset = CreateTensor( + *builder, builder->CreateVector(tensor_shape, tensor_shape_size), + TensorType_INT32, 0, builder->CreateString("test_tensor"), quant_params, + false); + builder->Finish(tensor_offset); + void* tensor_pointer = builder->GetBufferPointer(); + const Tensor* tensor = flatbuffers::GetRoot(tensor_pointer); + return tensor; +} + +const flatbuffers::Vector>* +CreateFlatbufferBuffers() { + using flatbuffers::Offset; + flatbuffers::FlatBufferBuilder* builder = BuilderInstance(); + constexpr size_t buffers_size = 1; + const Offset buffers[buffers_size] = { + CreateBuffer(*builder), + }; + const flatbuffers::Offset>> + buffers_offset = builder->CreateVector(buffers, buffers_size); + builder->Finish(buffers_offset); + void* buffers_pointer = builder->GetBufferPointer(); + const flatbuffers::Vector>* result = + flatbuffers::GetRoot>>( + buffers_pointer); + return result; +} + +int TestStrcmp(const char* a, const char* b) { + if ((a == nullptr) || (b == nullptr)) { + return -1; + } + while ((*a != 0) && (*a == *b)) { + a++; + b++; + } + return *reinterpret_cast(a) - + *reinterpret_cast(b); +} + +// Wrapper to forward kernel errors to the interpreter's error reporter. +void ReportOpError(struct TfLiteContext* context, const char* format, ...) { +#ifndef TF_LITE_STRIP_ERROR_STRINGS + ErrorReporter* error_reporter = static_cast(context->impl_); + va_list args; + va_start(args, format); + TF_LITE_REPORT_ERROR(error_reporter, format, args); + va_end(args); +#endif +} + +// Create a TfLiteIntArray from an array of ints. The first element in the +// supplied array must be the size of the array expressed as an int. +TfLiteIntArray* IntArrayFromInts(int* int_array) { + return reinterpret_cast(int_array); +} + +// Create a TfLiteFloatArray from an array of floats. The first element in the +// supplied array must be the size of the array expressed as a float. +TfLiteFloatArray* FloatArrayFromFloats(const float* floats) { + static_assert(sizeof(float) == sizeof(int), + "assumes sizeof(float) == sizeof(int) to perform casting"); + int size = static_cast(floats[0]); + *reinterpret_cast(const_cast(floats)) = size; + return reinterpret_cast(const_cast(floats)); +} + +TfLiteTensor CreateQuantizedBiasTensor(const float* data, int16_t* quantized, + TfLiteIntArray* dims, float input_scale, + float weights_scale, bool is_variable) { + float bias_scale = input_scale * weights_scale; + tflite::SymmetricQuantize(data, quantized, ElementCount(*dims), bias_scale); + + // Quantized int16_t tensors always have a zero point of 0, since the range of + // int16_t values is large, and because zero point costs extra cycles during + // processing. + TfLiteTensor result = + CreateQuantizedTensor(quantized, dims, bias_scale, 0, is_variable); + return result; +} + +TfLiteTensor CreateQuantizedBiasTensor(const float* data, int32_t* quantized, + TfLiteIntArray* dims, float input_scale, + float weights_scale, bool is_variable) { + float bias_scale = input_scale * weights_scale; + tflite::SymmetricQuantize(data, quantized, ElementCount(*dims), bias_scale); + + // Quantized int32_t tensors always have a zero point of 0, since the range of + // int32_t values is large, and because zero point costs extra cycles during + // processing. + TfLiteTensor result = + CreateQuantizedTensor(quantized, dims, bias_scale, 0, is_variable); + return result; +} + +TfLiteTensor CreateQuantizedBiasTensor(const float* data, + std::int64_t* quantized, + TfLiteIntArray* dims, float input_scale, + float weights_scale, bool is_variable) { + float bias_scale = input_scale * weights_scale; + tflite::SymmetricQuantize(data, quantized, ElementCount(*dims), bias_scale); + + // Quantized int32_t tensors always have a zero point of 0, since the range of + // int32_t values is large, and because zero point costs extra cycles during + // processing. + TfLiteTensor result = + CreateQuantizedTensor(quantized, dims, bias_scale, 0, is_variable); + return result; +} + +// Quantizes int32_t bias tensor with per-channel weights determined by input +// scale multiplied by weight scale for each channel. +template +TfLiteTensor CreatePerChannelQuantizedBiasTensor( + const float* input, T* quantized, TfLiteIntArray* dims, float input_scale, + float* weight_scales, float* scales, int* zero_points, + TfLiteAffineQuantization* affine_quant, int quantized_dimension, + bool is_variable) { + int input_size = ElementCount(*dims); + int num_channels = dims->data[quantized_dimension]; + // First element is reserved for array length + zero_points[0] = num_channels; + scales[0] = static_cast(num_channels); + float* scales_array = &scales[1]; + for (int i = 0; i < num_channels; i++) { + scales_array[i] = input_scale * weight_scales[i]; + zero_points[i + 1] = 0; + } + + SymmetricPerChannelQuantize(input, quantized, input_size, num_channels, + scales_array); + + affine_quant->scale = FloatArrayFromFloats(scales); + affine_quant->zero_point = IntArrayFromInts(zero_points); + affine_quant->quantized_dimension = quantized_dimension; + + TfLiteTensor result = CreateTensor(quantized, dims, is_variable); + result.quantization = {kTfLiteAffineQuantization, affine_quant}; + return result; +} + +TfLiteTensor CreatePerChannelQuantizedBiasTensor( + const float* input, int32_t* quantized, TfLiteIntArray* dims, + float input_scale, float* weight_scales, float* scales, int* zero_points, + TfLiteAffineQuantization* affine_quant, int quantized_dimension, + bool is_variable) { + return CreatePerChannelQuantizedBiasTensor( + input, quantized, dims, input_scale, weight_scales, scales, zero_points, + affine_quant, quantized_dimension, is_variable); +} + +TfLiteTensor CreatePerChannelQuantizedBiasTensor( + const float* input, std::int64_t* quantized, TfLiteIntArray* dims, + float input_scale, float* weight_scales, float* scales, int* zero_points, + TfLiteAffineQuantization* affine_quant, int quantized_dimension, + bool is_variable) { + return CreatePerChannelQuantizedBiasTensor( + input, quantized, dims, input_scale, weight_scales, scales, zero_points, + affine_quant, quantized_dimension, is_variable); +} + +TfLiteTensor CreateSymmetricPerChannelQuantizedTensor( + const float* input, int8_t* quantized, TfLiteIntArray* dims, float* scales, + int* zero_points, TfLiteAffineQuantization* affine_quant, + int quantized_dimension, bool is_variable) { + int channel_count = dims->data[quantized_dimension]; + scales[0] = static_cast(channel_count); + zero_points[0] = channel_count; + + SignedSymmetricPerChannelQuantize(input, dims, quantized_dimension, quantized, + &scales[1]); + + for (int i = 0; i < channel_count; i++) { + zero_points[i + 1] = 0; + } + + affine_quant->scale = FloatArrayFromFloats(scales); + affine_quant->zero_point = IntArrayFromInts(zero_points); + affine_quant->quantized_dimension = quantized_dimension; + + TfLiteTensor result = CreateTensor(quantized, dims, is_variable); + result.quantization = {kTfLiteAffineQuantization, affine_quant}; + return result; +} + +size_t GetModelTensorCount(const Model* model) { + auto* subgraphs = model->subgraphs(); + if (subgraphs) { + return (*subgraphs)[0]->tensors()->size(); + } + return 0; +} + +} // namespace testing +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helpers.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helpers.h new file mode 100644 index 000000000..459d3f265 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/micro/test_helpers.h @@ -0,0 +1,298 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_MICRO_TEST_HELPERS_H_ +#define TENSORFLOW_LITE_MICRO_TEST_HELPERS_H_ + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/compatibility.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "tensorflow/lite/micro/micro_utils.h" +#include "tensorflow/lite/portable_type_to_tflitetype.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { +namespace testing { + +constexpr int kOfflinePlannerHeaderSize = 3; + +struct NodeConnection_ { + std::initializer_list input; + std::initializer_list output; +}; +typedef struct NodeConnection_ NodeConnection; + +// A simple operator that returns the median of the input with the number of +// times the kernel was invoked. The implementation below is deliberately +// complicated, just to demonstrate how kernel memory planning works. +class SimpleStatefulOp { + static constexpr int kBufferNotAllocated = 0; + // Inputs: + static constexpr int kInputTensor = 0; + // Outputs: + static constexpr int kMedianTensor = 0; + static constexpr int kInvokeCount = 1; + struct OpData { + int* invoke_count = nullptr; + int sorting_buffer = kBufferNotAllocated; + }; + + public: + static const TfLiteRegistration* getRegistration(); + static TfLiteRegistration* GetMutableRegistration(); + static void* Init(TfLiteContext* context, const char* buffer, size_t length); + static TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node); + static TfLiteStatus Invoke(TfLiteContext* context, TfLiteNode* node); +}; + +class MockCustom { + public: + static const TfLiteRegistration* getRegistration(); + static TfLiteRegistration* GetMutableRegistration(); + static void* Init(TfLiteContext* context, const char* buffer, size_t length); + static void Free(TfLiteContext* context, void* buffer); + static TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node); + static TfLiteStatus Invoke(TfLiteContext* context, TfLiteNode* node); + + static bool freed_; +}; + +// A simple operator with the purpose of testing multiple inputs. It returns +// the sum of the inputs. +class MultipleInputs { + public: + static const TfLiteRegistration* getRegistration(); + static TfLiteRegistration* GetMutableRegistration(); + static void* Init(TfLiteContext* context, const char* buffer, size_t length); + static void Free(TfLiteContext* context, void* buffer); + static TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node); + static TfLiteStatus Invoke(TfLiteContext* context, TfLiteNode* node); + + static bool freed_; +}; + +// A simple no-op operator. +class NoOp { + public: + static const TfLiteRegistration* getRegistration(); + static TfLiteRegistration* GetMutableRegistration(); + static void* Init(TfLiteContext* context, const char* buffer, size_t length); + static void Free(TfLiteContext* context, void* buffer); + static TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node); + static TfLiteStatus Invoke(TfLiteContext* context, TfLiteNode* node); + + static bool freed_; +}; + +// Returns an Op Resolver that can be used in the testing code. +AllOpsResolver GetOpResolver(); + +// Returns a simple example flatbuffer TensorFlow Lite model. Contains 1 input, +// 1 layer of weights, 1 output Tensor, and 1 operator. +const Model* GetSimpleMockModel(); + +// Returns a flatbuffer TensorFlow Lite model with more inputs, variable +// tensors, and operators. +const Model* GetComplexMockModel(); + +// Returns a simple example flatbuffer TensorFlow Lite model. Contains 1 input, +// 1 layer of weights, 1 output Tensor, and 1 operator. +// The size of all three tensors is 256 x 256, which is larger than what other +// models provide from this test helper. +const Model* GetModelWith256x256Tensor(); + +// Returns a simple flatbuffer model with two branches. +const Model* GetSimpleModelWithBranch(); + +// Returns a simple example flatbuffer TensorFlow Lite model. Contains 3 inputs, +// 1 output Tensor, and 1 operator. +const Model* GetSimpleMultipleInputsModel(); + +// Returns a simple flatbuffer model with offline planned tensors +// @param[in] num_tensors Number of tensors in the model. +// @param[in] metadata_buffer Metadata for offline planner. +// @param[in] node_con List of connections, i.e. operators +// in the model. +// @param[in] num_conns Number of connections. +// @param[in] num_subgraph_inputs How many of the input tensors are in +// the subgraph inputs. The default value +// of 0 means all of the input tensors +// are in the subgraph input list. There +// must be at least 1 input tensor in the +// subgraph input list. +const Model* GetModelWithOfflinePlanning(int num_tensors, + const int32_t* metadata_buffer, + NodeConnection* node_conn, + int num_conns, + int num_subgraph_inputs = 0); + +// Returns a flatbuffer with a single operator, two inputs (one unused) and one +// output. +const Model* GetModelWithUnusedInputs(); + +// Returns a flatbuffer with a single operator, zero inputs and two outputs +// (one unused). +const Model* GetModelWithUnusedOperatorOutputs(); + +// Returns a flatbuffer model with `simple_stateful_op` +const Model* GetSimpleStatefulModel(); + +// Returns a flatbuffer model with "if" and two subgraphs. +const Model* GetSimpleModelWithSubgraphsAndIf(); + +// Returns a flatbuffer model with "while" and three subgraphs. +const Model* GetSimpleModelWithSubgraphsAndWhile(); + +// Returns a flatbuffer model with "if" and two subgraphs and the input tensor 1 +// of "if" subgraph overlaps with the input tensor 2 of subgraph 1. +const Model* GetModelWithIfAndSubgraphInputTensorOverlap(); + +// Returns a flatbuffer model with null subgraph/operator inputs and outputs. +const Model* GetSimpleModelWithNullInputsAndOutputs(); + +// Builds a one-dimensional flatbuffer tensor of the given size. +const Tensor* Create1dFlatbufferTensor(int size, bool is_variable = false); + +// Builds a one-dimensional flatbuffer tensor of the given size with +// quantization metadata. +const Tensor* CreateQuantizedFlatbufferTensor(int size); + +// Creates a one-dimensional tensor with no quantization metadata. +const Tensor* CreateMissingQuantizationFlatbufferTensor(int size); + +// Creates a vector of flatbuffer buffers. +const flatbuffers::Vector>* +CreateFlatbufferBuffers(); + +// Performs a simple string comparison without requiring standard C library. +int TestStrcmp(const char* a, const char* b); + +// Wrapper to forward kernel errors to the interpreter's error reporter. +void ReportOpError(struct TfLiteContext* context, const char* format, ...); + +void PopulateContext(TfLiteTensor* tensors, int tensors_size, + TfLiteContext* context); + +// Create a TfLiteIntArray from an array of ints. The first element in the +// supplied array must be the size of the array expressed as an int. +TfLiteIntArray* IntArrayFromInts(int* int_array); + +// Create a TfLiteFloatArray from an array of floats. The first element in the +// supplied array must be the size of the array expressed as a float. +TfLiteFloatArray* FloatArrayFromFloats(const float* floats); + +template +TfLiteTensor CreateTensor(const T* data, TfLiteIntArray* dims, + const bool is_variable = false) { + TfLiteTensor result; + result.dims = dims; + result.params = {}; + result.quantization = {kTfLiteNoQuantization, nullptr}; + result.is_variable = is_variable; + result.allocation_type = kTfLiteMemNone; + result.type = typeToTfLiteType(); + // Const cast is used to allow passing in const and non-const arrays within a + // single CreateTensor method. A Const array should be used for immutable + // input tensors and non-const array should be used for mutable and output + // tensors. + result.data.data = const_cast(data); + result.quantization = {kTfLiteAffineQuantization, nullptr}; + result.bytes = ElementCount(*dims) * sizeof(T); + return result; +} + +template +TfLiteTensor CreateQuantizedTensor(const T* data, TfLiteIntArray* dims, + const float scale, const int zero_point = 0, + const bool is_variable = false) { + TfLiteTensor result = CreateTensor(data, dims, is_variable); + result.params = {scale, zero_point}; + result.quantization = {kTfLiteAffineQuantization, nullptr}; + return result; +} + +template +TfLiteTensor CreateQuantizedTensor(const float* input, T* quantized, + TfLiteIntArray* dims, float scale, + int zero_point, bool is_variable = false) { + int input_size = ElementCount(*dims); + tflite::Quantize(input, quantized, input_size, scale, zero_point); + return CreateQuantizedTensor(quantized, dims, scale, zero_point, is_variable); +} + +TfLiteTensor CreateQuantizedBiasTensor(const float* data, int16_t* quantized, + TfLiteIntArray* dims, float input_scale, + float weights_scale, + bool is_variable = false); + +TfLiteTensor CreateQuantizedBiasTensor(const float* data, int32_t* quantized, + TfLiteIntArray* dims, float input_scale, + float weights_scale, + bool is_variable = false); + +TfLiteTensor CreateQuantizedBiasTensor(const float* data, + std::int64_t* quantized, + TfLiteIntArray* dims, float input_scale, + float weights_scale, + bool is_variable = false); + +// Quantizes int32_t bias tensor with per-channel weights determined by input +// scale multiplied by weight scale for each channel. +TfLiteTensor CreatePerChannelQuantizedBiasTensor( + const float* input, int32_t* quantized, TfLiteIntArray* dims, + float input_scale, float* weight_scales, float* scales, int* zero_points, + TfLiteAffineQuantization* affine_quant, int quantized_dimension, + bool is_variable = false); + +// Quantizes int64_t bias tensor with per-channel weights determined by input +// scale multiplied by weight scale for each channel. +TfLiteTensor CreatePerChannelQuantizedBiasTensor( + const float* input, std::int64_t* quantized, TfLiteIntArray* dims, + float input_scale, float* weight_scales, float* scales, int* zero_points, + TfLiteAffineQuantization* affine_quant, int quantized_dimension, + bool is_variable = false); + +TfLiteTensor CreateSymmetricPerChannelQuantizedTensor( + const float* input, int8_t* quantized, TfLiteIntArray* dims, float* scales, + int* zero_points, TfLiteAffineQuantization* affine_quant, + int quantized_dimension, bool is_variable = false); + +// Returns the number of tensors in the default subgraph for a tflite::Model. +size_t GetModelTensorCount(const Model* model); + +// Derives the quantization scaling factor from a min and max range. +template +inline float ScaleFromMinMax(const float min, const float max) { + return (max - min) / + static_cast((std::numeric_limits::max() * 1.0) - + std::numeric_limits::min()); +} + +// Derives the quantization zero point from a min and max range. +template +inline int ZeroPointFromMinMax(const float min, const float max) { + return static_cast(std::numeric_limits::min()) + + static_cast(-min / ScaleFromMinMax(min, max) + 0.5f); +} + +} // namespace testing +} // namespace tflite + +#endif // TENSORFLOW_LITE_MICRO_TEST_HELPERS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/portable_type_to_tflitetype.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/portable_type_to_tflitetype.h new file mode 100644 index 000000000..52d7fdefe --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/portable_type_to_tflitetype.h @@ -0,0 +1,75 @@ +/* Copyright 2019 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_PORTABLE_TYPE_TO_TFLITETYPE_H_ +#define TENSORFLOW_LITE_PORTABLE_TYPE_TO_TFLITETYPE_H_ + +// Most of the definitions have been moved to this subheader so that Micro +// can include it without relying on and , which isn't +// available on all platforms. + +// Arduino build defines abs as a macro here. That is invalid C++, and breaks +// libc++'s header, undefine it. +#ifdef abs +#undef abs +#endif + +#include + +#include "tensorflow/lite/c/common.h" + +namespace tflite { + +// Map statically from a C++ type to a TfLiteType. Used in interpreter for +// safe casts. +// Example: +// typeToTfLiteType() -> kTfLiteBool +template +constexpr TfLiteType typeToTfLiteType() { + return kTfLiteNoType; +} +// Map from TfLiteType to the corresponding C++ type. +// Example: +// TfLiteTypeToType::Type -> bool +template +struct TfLiteTypeToType {}; // Specializations below + +// Template specialization for both typeToTfLiteType and TfLiteTypeToType. +#define MATCH_TYPE_AND_TFLITE_TYPE(CPP_TYPE, TFLITE_TYPE_ENUM) \ + template <> \ + constexpr TfLiteType typeToTfLiteType() { \ + return TFLITE_TYPE_ENUM; \ + } \ + template <> \ + struct TfLiteTypeToType { \ + using Type = CPP_TYPE; \ + } + +// No string mapping is included here, since the TF Lite packed representation +// doesn't correspond to a C++ type well. +MATCH_TYPE_AND_TFLITE_TYPE(int32_t, kTfLiteInt32); +MATCH_TYPE_AND_TFLITE_TYPE(uint32_t, kTfLiteUInt32); +MATCH_TYPE_AND_TFLITE_TYPE(int16_t, kTfLiteInt16); +MATCH_TYPE_AND_TFLITE_TYPE(uint16_t, kTfLiteUInt16); +MATCH_TYPE_AND_TFLITE_TYPE(int64_t, kTfLiteInt64); +MATCH_TYPE_AND_TFLITE_TYPE(float, kTfLiteFloat32); +MATCH_TYPE_AND_TFLITE_TYPE(unsigned char, kTfLiteUInt8); +MATCH_TYPE_AND_TFLITE_TYPE(int8_t, kTfLiteInt8); +MATCH_TYPE_AND_TFLITE_TYPE(bool, kTfLiteBool); +MATCH_TYPE_AND_TFLITE_TYPE(TfLiteFloat16, kTfLiteFloat16); +MATCH_TYPE_AND_TFLITE_TYPE(double, kTfLiteFloat64); +MATCH_TYPE_AND_TFLITE_TYPE(uint64_t, kTfLiteUInt64); + +} // namespace tflite +#endif // TENSORFLOW_LITE_PORTABLE_TYPE_TO_TFLITETYPE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_generated.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_generated.h new file mode 100644 index 000000000..43aaba396 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_generated.h @@ -0,0 +1,20139 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_SCHEMA_TFLITE_H_ +#define FLATBUFFERS_GENERATED_SCHEMA_TFLITE_H_ + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" + +// Ensure the included flatbuffers.h is the same version as when this file was +// generated, otherwise it may not be compatible. +static_assert(FLATBUFFERS_VERSION_MAJOR == 2 && + FLATBUFFERS_VERSION_MINOR == 0 && + FLATBUFFERS_VERSION_REVISION == 6, + "Non-compatible flatbuffers version included"); + +namespace tflite { + +struct CustomQuantization; +struct CustomQuantizationBuilder; +struct CustomQuantizationT; + +struct QuantizationParameters; +struct QuantizationParametersBuilder; +struct QuantizationParametersT; + +struct Int32Vector; +struct Int32VectorBuilder; +struct Int32VectorT; + +struct Uint16Vector; +struct Uint16VectorBuilder; +struct Uint16VectorT; + +struct Uint8Vector; +struct Uint8VectorBuilder; +struct Uint8VectorT; + +struct DimensionMetadata; +struct DimensionMetadataBuilder; +struct DimensionMetadataT; + +struct SparsityParameters; +struct SparsityParametersBuilder; +struct SparsityParametersT; + +struct VariantSubType; +struct VariantSubTypeBuilder; +struct VariantSubTypeT; + +struct Tensor; +struct TensorBuilder; +struct TensorT; + +struct Conv2DOptions; +struct Conv2DOptionsBuilder; +struct Conv2DOptionsT; + +struct Conv3DOptions; +struct Conv3DOptionsBuilder; +struct Conv3DOptionsT; + +struct Pool2DOptions; +struct Pool2DOptionsBuilder; +struct Pool2DOptionsT; + +struct DepthwiseConv2DOptions; +struct DepthwiseConv2DOptionsBuilder; +struct DepthwiseConv2DOptionsT; + +struct ConcatEmbeddingsOptions; +struct ConcatEmbeddingsOptionsBuilder; +struct ConcatEmbeddingsOptionsT; + +struct LSHProjectionOptions; +struct LSHProjectionOptionsBuilder; +struct LSHProjectionOptionsT; + +struct SVDFOptions; +struct SVDFOptionsBuilder; +struct SVDFOptionsT; + +struct RNNOptions; +struct RNNOptionsBuilder; +struct RNNOptionsT; + +struct SequenceRNNOptions; +struct SequenceRNNOptionsBuilder; +struct SequenceRNNOptionsT; + +struct BidirectionalSequenceRNNOptions; +struct BidirectionalSequenceRNNOptionsBuilder; +struct BidirectionalSequenceRNNOptionsT; + +struct FullyConnectedOptions; +struct FullyConnectedOptionsBuilder; +struct FullyConnectedOptionsT; + +struct SoftmaxOptions; +struct SoftmaxOptionsBuilder; +struct SoftmaxOptionsT; + +struct ConcatenationOptions; +struct ConcatenationOptionsBuilder; +struct ConcatenationOptionsT; + +struct AddOptions; +struct AddOptionsBuilder; +struct AddOptionsT; + +struct MulOptions; +struct MulOptionsBuilder; +struct MulOptionsT; + +struct L2NormOptions; +struct L2NormOptionsBuilder; +struct L2NormOptionsT; + +struct LocalResponseNormalizationOptions; +struct LocalResponseNormalizationOptionsBuilder; +struct LocalResponseNormalizationOptionsT; + +struct LSTMOptions; +struct LSTMOptionsBuilder; +struct LSTMOptionsT; + +struct UnidirectionalSequenceLSTMOptions; +struct UnidirectionalSequenceLSTMOptionsBuilder; +struct UnidirectionalSequenceLSTMOptionsT; + +struct BidirectionalSequenceLSTMOptions; +struct BidirectionalSequenceLSTMOptionsBuilder; +struct BidirectionalSequenceLSTMOptionsT; + +struct ResizeBilinearOptions; +struct ResizeBilinearOptionsBuilder; +struct ResizeBilinearOptionsT; + +struct ResizeNearestNeighborOptions; +struct ResizeNearestNeighborOptionsBuilder; +struct ResizeNearestNeighborOptionsT; + +struct CallOptions; +struct CallOptionsBuilder; +struct CallOptionsT; + +struct PadOptions; +struct PadOptionsBuilder; +struct PadOptionsT; + +struct PadV2Options; +struct PadV2OptionsBuilder; +struct PadV2OptionsT; + +struct ReshapeOptions; +struct ReshapeOptionsBuilder; +struct ReshapeOptionsT; + +struct SpaceToBatchNDOptions; +struct SpaceToBatchNDOptionsBuilder; +struct SpaceToBatchNDOptionsT; + +struct BatchToSpaceNDOptions; +struct BatchToSpaceNDOptionsBuilder; +struct BatchToSpaceNDOptionsT; + +struct SkipGramOptions; +struct SkipGramOptionsBuilder; +struct SkipGramOptionsT; + +struct SpaceToDepthOptions; +struct SpaceToDepthOptionsBuilder; +struct SpaceToDepthOptionsT; + +struct DepthToSpaceOptions; +struct DepthToSpaceOptionsBuilder; +struct DepthToSpaceOptionsT; + +struct SubOptions; +struct SubOptionsBuilder; +struct SubOptionsT; + +struct DivOptions; +struct DivOptionsBuilder; +struct DivOptionsT; + +struct TopKV2Options; +struct TopKV2OptionsBuilder; +struct TopKV2OptionsT; + +struct EmbeddingLookupSparseOptions; +struct EmbeddingLookupSparseOptionsBuilder; +struct EmbeddingLookupSparseOptionsT; + +struct GatherOptions; +struct GatherOptionsBuilder; +struct GatherOptionsT; + +struct TransposeOptions; +struct TransposeOptionsBuilder; +struct TransposeOptionsT; + +struct ExpOptions; +struct ExpOptionsBuilder; +struct ExpOptionsT; + +struct CosOptions; +struct CosOptionsBuilder; +struct CosOptionsT; + +struct ReducerOptions; +struct ReducerOptionsBuilder; +struct ReducerOptionsT; + +struct SqueezeOptions; +struct SqueezeOptionsBuilder; +struct SqueezeOptionsT; + +struct SplitOptions; +struct SplitOptionsBuilder; +struct SplitOptionsT; + +struct SplitVOptions; +struct SplitVOptionsBuilder; +struct SplitVOptionsT; + +struct StridedSliceOptions; +struct StridedSliceOptionsBuilder; +struct StridedSliceOptionsT; + +struct LogSoftmaxOptions; +struct LogSoftmaxOptionsBuilder; +struct LogSoftmaxOptionsT; + +struct CastOptions; +struct CastOptionsBuilder; +struct CastOptionsT; + +struct DequantizeOptions; +struct DequantizeOptionsBuilder; +struct DequantizeOptionsT; + +struct MaximumMinimumOptions; +struct MaximumMinimumOptionsBuilder; +struct MaximumMinimumOptionsT; + +struct TileOptions; +struct TileOptionsBuilder; +struct TileOptionsT; + +struct ArgMaxOptions; +struct ArgMaxOptionsBuilder; +struct ArgMaxOptionsT; + +struct ArgMinOptions; +struct ArgMinOptionsBuilder; +struct ArgMinOptionsT; + +struct GreaterOptions; +struct GreaterOptionsBuilder; +struct GreaterOptionsT; + +struct GreaterEqualOptions; +struct GreaterEqualOptionsBuilder; +struct GreaterEqualOptionsT; + +struct LessOptions; +struct LessOptionsBuilder; +struct LessOptionsT; + +struct LessEqualOptions; +struct LessEqualOptionsBuilder; +struct LessEqualOptionsT; + +struct NegOptions; +struct NegOptionsBuilder; +struct NegOptionsT; + +struct SelectOptions; +struct SelectOptionsBuilder; +struct SelectOptionsT; + +struct SliceOptions; +struct SliceOptionsBuilder; +struct SliceOptionsT; + +struct TransposeConvOptions; +struct TransposeConvOptionsBuilder; +struct TransposeConvOptionsT; + +struct ExpandDimsOptions; +struct ExpandDimsOptionsBuilder; +struct ExpandDimsOptionsT; + +struct SparseToDenseOptions; +struct SparseToDenseOptionsBuilder; +struct SparseToDenseOptionsT; + +struct EqualOptions; +struct EqualOptionsBuilder; +struct EqualOptionsT; + +struct NotEqualOptions; +struct NotEqualOptionsBuilder; +struct NotEqualOptionsT; + +struct ShapeOptions; +struct ShapeOptionsBuilder; +struct ShapeOptionsT; + +struct RankOptions; +struct RankOptionsBuilder; +struct RankOptionsT; + +struct PowOptions; +struct PowOptionsBuilder; +struct PowOptionsT; + +struct FakeQuantOptions; +struct FakeQuantOptionsBuilder; +struct FakeQuantOptionsT; + +struct PackOptions; +struct PackOptionsBuilder; +struct PackOptionsT; + +struct LogicalOrOptions; +struct LogicalOrOptionsBuilder; +struct LogicalOrOptionsT; + +struct OneHotOptions; +struct OneHotOptionsBuilder; +struct OneHotOptionsT; + +struct AbsOptions; +struct AbsOptionsBuilder; +struct AbsOptionsT; + +struct HardSwishOptions; +struct HardSwishOptionsBuilder; +struct HardSwishOptionsT; + +struct LogicalAndOptions; +struct LogicalAndOptionsBuilder; +struct LogicalAndOptionsT; + +struct LogicalNotOptions; +struct LogicalNotOptionsBuilder; +struct LogicalNotOptionsT; + +struct UnpackOptions; +struct UnpackOptionsBuilder; +struct UnpackOptionsT; + +struct FloorDivOptions; +struct FloorDivOptionsBuilder; +struct FloorDivOptionsT; + +struct SquareOptions; +struct SquareOptionsBuilder; +struct SquareOptionsT; + +struct ZerosLikeOptions; +struct ZerosLikeOptionsBuilder; +struct ZerosLikeOptionsT; + +struct FillOptions; +struct FillOptionsBuilder; +struct FillOptionsT; + +struct FloorModOptions; +struct FloorModOptionsBuilder; +struct FloorModOptionsT; + +struct RangeOptions; +struct RangeOptionsBuilder; +struct RangeOptionsT; + +struct LeakyReluOptions; +struct LeakyReluOptionsBuilder; +struct LeakyReluOptionsT; + +struct SquaredDifferenceOptions; +struct SquaredDifferenceOptionsBuilder; +struct SquaredDifferenceOptionsT; + +struct MirrorPadOptions; +struct MirrorPadOptionsBuilder; +struct MirrorPadOptionsT; + +struct UniqueOptions; +struct UniqueOptionsBuilder; +struct UniqueOptionsT; + +struct ReverseV2Options; +struct ReverseV2OptionsBuilder; +struct ReverseV2OptionsT; + +struct AddNOptions; +struct AddNOptionsBuilder; +struct AddNOptionsT; + +struct GatherNdOptions; +struct GatherNdOptionsBuilder; +struct GatherNdOptionsT; + +struct WhereOptions; +struct WhereOptionsBuilder; +struct WhereOptionsT; + +struct ReverseSequenceOptions; +struct ReverseSequenceOptionsBuilder; +struct ReverseSequenceOptionsT; + +struct MatrixDiagOptions; +struct MatrixDiagOptionsBuilder; +struct MatrixDiagOptionsT; + +struct QuantizeOptions; +struct QuantizeOptionsBuilder; +struct QuantizeOptionsT; + +struct MatrixSetDiagOptions; +struct MatrixSetDiagOptionsBuilder; +struct MatrixSetDiagOptionsT; + +struct IfOptions; +struct IfOptionsBuilder; +struct IfOptionsT; + +struct CallOnceOptions; +struct CallOnceOptionsBuilder; +struct CallOnceOptionsT; + +struct WhileOptions; +struct WhileOptionsBuilder; +struct WhileOptionsT; + +struct NonMaxSuppressionV4Options; +struct NonMaxSuppressionV4OptionsBuilder; +struct NonMaxSuppressionV4OptionsT; + +struct NonMaxSuppressionV5Options; +struct NonMaxSuppressionV5OptionsBuilder; +struct NonMaxSuppressionV5OptionsT; + +struct ScatterNdOptions; +struct ScatterNdOptionsBuilder; +struct ScatterNdOptionsT; + +struct SelectV2Options; +struct SelectV2OptionsBuilder; +struct SelectV2OptionsT; + +struct DensifyOptions; +struct DensifyOptionsBuilder; +struct DensifyOptionsT; + +struct SegmentSumOptions; +struct SegmentSumOptionsBuilder; +struct SegmentSumOptionsT; + +struct BatchMatMulOptions; +struct BatchMatMulOptionsBuilder; +struct BatchMatMulOptionsT; + +struct CumsumOptions; +struct CumsumOptionsBuilder; +struct CumsumOptionsT; + +struct BroadcastToOptions; +struct BroadcastToOptionsBuilder; +struct BroadcastToOptionsT; + +struct Rfft2dOptions; +struct Rfft2dOptionsBuilder; +struct Rfft2dOptionsT; + +struct HashtableOptions; +struct HashtableOptionsBuilder; +struct HashtableOptionsT; + +struct HashtableFindOptions; +struct HashtableFindOptionsBuilder; +struct HashtableFindOptionsT; + +struct HashtableImportOptions; +struct HashtableImportOptionsBuilder; +struct HashtableImportOptionsT; + +struct HashtableSizeOptions; +struct HashtableSizeOptionsBuilder; +struct HashtableSizeOptionsT; + +struct VarHandleOptions; +struct VarHandleOptionsBuilder; +struct VarHandleOptionsT; + +struct ReadVariableOptions; +struct ReadVariableOptionsBuilder; +struct ReadVariableOptionsT; + +struct AssignVariableOptions; +struct AssignVariableOptionsBuilder; +struct AssignVariableOptionsT; + +struct RandomOptions; +struct RandomOptionsBuilder; +struct RandomOptionsT; + +struct BucketizeOptions; +struct BucketizeOptionsBuilder; +struct BucketizeOptionsT; + +struct GeluOptions; +struct GeluOptionsBuilder; +struct GeluOptionsT; + +struct DynamicUpdateSliceOptions; +struct DynamicUpdateSliceOptionsBuilder; +struct DynamicUpdateSliceOptionsT; + +struct UnsortedSegmentProdOptions; +struct UnsortedSegmentProdOptionsBuilder; +struct UnsortedSegmentProdOptionsT; + +struct UnsortedSegmentMaxOptions; +struct UnsortedSegmentMaxOptionsBuilder; +struct UnsortedSegmentMaxOptionsT; + +struct UnsortedSegmentSumOptions; +struct UnsortedSegmentSumOptionsBuilder; +struct UnsortedSegmentSumOptionsT; + +struct ATan2Options; +struct ATan2OptionsBuilder; +struct ATan2OptionsT; + +struct UnsortedSegmentMinOptions; +struct UnsortedSegmentMinOptionsBuilder; +struct UnsortedSegmentMinOptionsT; + +struct SignOptions; +struct SignOptionsBuilder; +struct SignOptionsT; + +struct OperatorCode; +struct OperatorCodeBuilder; +struct OperatorCodeT; + +struct Operator; +struct OperatorBuilder; +struct OperatorT; + +struct SubGraph; +struct SubGraphBuilder; +struct SubGraphT; + +struct Buffer; +struct BufferBuilder; +struct BufferT; + +struct Metadata; +struct MetadataBuilder; +struct MetadataT; + +struct TensorMap; +struct TensorMapBuilder; +struct TensorMapT; + +struct SignatureDef; +struct SignatureDefBuilder; +struct SignatureDefT; + +struct Model; +struct ModelBuilder; +struct ModelT; + +enum TensorType : int8_t { + TensorType_FLOAT32 = 0, + TensorType_FLOAT16 = 1, + TensorType_INT32 = 2, + TensorType_UINT8 = 3, + TensorType_INT64 = 4, + TensorType_STRING = 5, + TensorType_BOOL = 6, + TensorType_INT16 = 7, + TensorType_COMPLEX64 = 8, + TensorType_INT8 = 9, + TensorType_FLOAT64 = 10, + TensorType_COMPLEX128 = 11, + TensorType_UINT64 = 12, + TensorType_RESOURCE = 13, + TensorType_VARIANT = 14, + TensorType_UINT32 = 15, + TensorType_UINT16 = 16, + TensorType_INT4 = 17, + TensorType_MIN = TensorType_FLOAT32, + TensorType_MAX = TensorType_INT4 +}; + +inline const TensorType (&EnumValuesTensorType())[18] { + static const TensorType values[] = { + TensorType_FLOAT32, + TensorType_FLOAT16, + TensorType_INT32, + TensorType_UINT8, + TensorType_INT64, + TensorType_STRING, + TensorType_BOOL, + TensorType_INT16, + TensorType_COMPLEX64, + TensorType_INT8, + TensorType_FLOAT64, + TensorType_COMPLEX128, + TensorType_UINT64, + TensorType_RESOURCE, + TensorType_VARIANT, + TensorType_UINT32, + TensorType_UINT16, + TensorType_INT4 + }; + return values; +} + +inline const char * const *EnumNamesTensorType() { + static const char * const names[19] = { + "FLOAT32", + "FLOAT16", + "INT32", + "UINT8", + "INT64", + "STRING", + "BOOL", + "INT16", + "COMPLEX64", + "INT8", + "FLOAT64", + "COMPLEX128", + "UINT64", + "RESOURCE", + "VARIANT", + "UINT32", + "UINT16", + "INT4", + nullptr + }; + return names; +} + +inline const char *EnumNameTensorType(TensorType e) { + if (flatbuffers::IsOutRange(e, TensorType_FLOAT32, TensorType_INT4)) return ""; + const size_t index = static_cast(e); + return EnumNamesTensorType()[index]; +} + +enum QuantizationDetails : uint8_t { + QuantizationDetails_NONE = 0, + QuantizationDetails_CustomQuantization = 1, + QuantizationDetails_MIN = QuantizationDetails_NONE, + QuantizationDetails_MAX = QuantizationDetails_CustomQuantization +}; + +inline const QuantizationDetails (&EnumValuesQuantizationDetails())[2] { + static const QuantizationDetails values[] = { + QuantizationDetails_NONE, + QuantizationDetails_CustomQuantization + }; + return values; +} + +inline const char * const *EnumNamesQuantizationDetails() { + static const char * const names[3] = { + "NONE", + "CustomQuantization", + nullptr + }; + return names; +} + +inline const char *EnumNameQuantizationDetails(QuantizationDetails e) { + if (flatbuffers::IsOutRange(e, QuantizationDetails_NONE, QuantizationDetails_CustomQuantization)) return ""; + const size_t index = static_cast(e); + return EnumNamesQuantizationDetails()[index]; +} + +template struct QuantizationDetailsTraits { + static const QuantizationDetails enum_value = QuantizationDetails_NONE; +}; + +template<> struct QuantizationDetailsTraits { + static const QuantizationDetails enum_value = QuantizationDetails_CustomQuantization; +}; + +template struct QuantizationDetailsUnionTraits { + static const QuantizationDetails enum_value = QuantizationDetails_NONE; +}; + +template<> struct QuantizationDetailsUnionTraits { + static const QuantizationDetails enum_value = QuantizationDetails_CustomQuantization; +}; + +struct QuantizationDetailsUnion { + QuantizationDetails type; + void *value; + + QuantizationDetailsUnion() : type(QuantizationDetails_NONE), value(nullptr) {} + QuantizationDetailsUnion(QuantizationDetailsUnion&& u) FLATBUFFERS_NOEXCEPT : + type(QuantizationDetails_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } + QuantizationDetailsUnion(const QuantizationDetailsUnion &); + QuantizationDetailsUnion &operator=(const QuantizationDetailsUnion &u) + { QuantizationDetailsUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; } + QuantizationDetailsUnion &operator=(QuantizationDetailsUnion &&u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } + ~QuantizationDetailsUnion() { Reset(); } + + void Reset(); + + template + void Set(T&& val) { + typedef typename std::remove_reference::type RT; + Reset(); + type = QuantizationDetailsUnionTraits::enum_value; + if (type != QuantizationDetails_NONE) { + value = new RT(std::forward(val)); + } + } + + static void *UnPack(const void *obj, QuantizationDetails type, const flatbuffers::resolver_function_t *resolver); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; + + tflite::CustomQuantizationT *AsCustomQuantization() { + return type == QuantizationDetails_CustomQuantization ? + reinterpret_cast(value) : nullptr; + } + const tflite::CustomQuantizationT *AsCustomQuantization() const { + return type == QuantizationDetails_CustomQuantization ? + reinterpret_cast(value) : nullptr; + } +}; + +bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj, QuantizationDetails type); +bool VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); + +enum DimensionType : int8_t { + DimensionType_DENSE = 0, + DimensionType_SPARSE_CSR = 1, + DimensionType_MIN = DimensionType_DENSE, + DimensionType_MAX = DimensionType_SPARSE_CSR +}; + +inline const DimensionType (&EnumValuesDimensionType())[2] { + static const DimensionType values[] = { + DimensionType_DENSE, + DimensionType_SPARSE_CSR + }; + return values; +} + +inline const char * const *EnumNamesDimensionType() { + static const char * const names[3] = { + "DENSE", + "SPARSE_CSR", + nullptr + }; + return names; +} + +inline const char *EnumNameDimensionType(DimensionType e) { + if (flatbuffers::IsOutRange(e, DimensionType_DENSE, DimensionType_SPARSE_CSR)) return ""; + const size_t index = static_cast(e); + return EnumNamesDimensionType()[index]; +} + +enum SparseIndexVector : uint8_t { + SparseIndexVector_NONE = 0, + SparseIndexVector_Int32Vector = 1, + SparseIndexVector_Uint16Vector = 2, + SparseIndexVector_Uint8Vector = 3, + SparseIndexVector_MIN = SparseIndexVector_NONE, + SparseIndexVector_MAX = SparseIndexVector_Uint8Vector +}; + +inline const SparseIndexVector (&EnumValuesSparseIndexVector())[4] { + static const SparseIndexVector values[] = { + SparseIndexVector_NONE, + SparseIndexVector_Int32Vector, + SparseIndexVector_Uint16Vector, + SparseIndexVector_Uint8Vector + }; + return values; +} + +inline const char * const *EnumNamesSparseIndexVector() { + static const char * const names[5] = { + "NONE", + "Int32Vector", + "Uint16Vector", + "Uint8Vector", + nullptr + }; + return names; +} + +inline const char *EnumNameSparseIndexVector(SparseIndexVector e) { + if (flatbuffers::IsOutRange(e, SparseIndexVector_NONE, SparseIndexVector_Uint8Vector)) return ""; + const size_t index = static_cast(e); + return EnumNamesSparseIndexVector()[index]; +} + +template struct SparseIndexVectorTraits { + static const SparseIndexVector enum_value = SparseIndexVector_NONE; +}; + +template<> struct SparseIndexVectorTraits { + static const SparseIndexVector enum_value = SparseIndexVector_Int32Vector; +}; + +template<> struct SparseIndexVectorTraits { + static const SparseIndexVector enum_value = SparseIndexVector_Uint16Vector; +}; + +template<> struct SparseIndexVectorTraits { + static const SparseIndexVector enum_value = SparseIndexVector_Uint8Vector; +}; + +template struct SparseIndexVectorUnionTraits { + static const SparseIndexVector enum_value = SparseIndexVector_NONE; +}; + +template<> struct SparseIndexVectorUnionTraits { + static const SparseIndexVector enum_value = SparseIndexVector_Int32Vector; +}; + +template<> struct SparseIndexVectorUnionTraits { + static const SparseIndexVector enum_value = SparseIndexVector_Uint16Vector; +}; + +template<> struct SparseIndexVectorUnionTraits { + static const SparseIndexVector enum_value = SparseIndexVector_Uint8Vector; +}; + +struct SparseIndexVectorUnion { + SparseIndexVector type; + void *value; + + SparseIndexVectorUnion() : type(SparseIndexVector_NONE), value(nullptr) {} + SparseIndexVectorUnion(SparseIndexVectorUnion&& u) FLATBUFFERS_NOEXCEPT : + type(SparseIndexVector_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } + SparseIndexVectorUnion(const SparseIndexVectorUnion &); + SparseIndexVectorUnion &operator=(const SparseIndexVectorUnion &u) + { SparseIndexVectorUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; } + SparseIndexVectorUnion &operator=(SparseIndexVectorUnion &&u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } + ~SparseIndexVectorUnion() { Reset(); } + + void Reset(); + + template + void Set(T&& val) { + typedef typename std::remove_reference::type RT; + Reset(); + type = SparseIndexVectorUnionTraits::enum_value; + if (type != SparseIndexVector_NONE) { + value = new RT(std::forward(val)); + } + } + + static void *UnPack(const void *obj, SparseIndexVector type, const flatbuffers::resolver_function_t *resolver); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; + + tflite::Int32VectorT *AsInt32Vector() { + return type == SparseIndexVector_Int32Vector ? + reinterpret_cast(value) : nullptr; + } + const tflite::Int32VectorT *AsInt32Vector() const { + return type == SparseIndexVector_Int32Vector ? + reinterpret_cast(value) : nullptr; + } + tflite::Uint16VectorT *AsUint16Vector() { + return type == SparseIndexVector_Uint16Vector ? + reinterpret_cast(value) : nullptr; + } + const tflite::Uint16VectorT *AsUint16Vector() const { + return type == SparseIndexVector_Uint16Vector ? + reinterpret_cast(value) : nullptr; + } + tflite::Uint8VectorT *AsUint8Vector() { + return type == SparseIndexVector_Uint8Vector ? + reinterpret_cast(value) : nullptr; + } + const tflite::Uint8VectorT *AsUint8Vector() const { + return type == SparseIndexVector_Uint8Vector ? + reinterpret_cast(value) : nullptr; + } +}; + +bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj, SparseIndexVector type); +bool VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); + +enum BuiltinOperator : int32_t { + BuiltinOperator_ADD = 0, + BuiltinOperator_AVERAGE_POOL_2D = 1, + BuiltinOperator_CONCATENATION = 2, + BuiltinOperator_CONV_2D = 3, + BuiltinOperator_DEPTHWISE_CONV_2D = 4, + BuiltinOperator_DEPTH_TO_SPACE = 5, + BuiltinOperator_DEQUANTIZE = 6, + BuiltinOperator_EMBEDDING_LOOKUP = 7, + BuiltinOperator_FLOOR = 8, + BuiltinOperator_FULLY_CONNECTED = 9, + BuiltinOperator_HASHTABLE_LOOKUP = 10, + BuiltinOperator_L2_NORMALIZATION = 11, + BuiltinOperator_L2_POOL_2D = 12, + BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13, + BuiltinOperator_LOGISTIC = 14, + BuiltinOperator_LSH_PROJECTION = 15, + BuiltinOperator_LSTM = 16, + BuiltinOperator_MAX_POOL_2D = 17, + BuiltinOperator_MUL = 18, + BuiltinOperator_RELU = 19, + BuiltinOperator_RELU_N1_TO_1 = 20, + BuiltinOperator_RELU6 = 21, + BuiltinOperator_RESHAPE = 22, + BuiltinOperator_RESIZE_BILINEAR = 23, + BuiltinOperator_RNN = 24, + BuiltinOperator_SOFTMAX = 25, + BuiltinOperator_SPACE_TO_DEPTH = 26, + BuiltinOperator_SVDF = 27, + BuiltinOperator_TANH = 28, + BuiltinOperator_CONCAT_EMBEDDINGS = 29, + BuiltinOperator_SKIP_GRAM = 30, + BuiltinOperator_CALL = 31, + BuiltinOperator_CUSTOM = 32, + BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33, + BuiltinOperator_PAD = 34, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35, + BuiltinOperator_GATHER = 36, + BuiltinOperator_BATCH_TO_SPACE_ND = 37, + BuiltinOperator_SPACE_TO_BATCH_ND = 38, + BuiltinOperator_TRANSPOSE = 39, + BuiltinOperator_MEAN = 40, + BuiltinOperator_SUB = 41, + BuiltinOperator_DIV = 42, + BuiltinOperator_SQUEEZE = 43, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + BuiltinOperator_STRIDED_SLICE = 45, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46, + BuiltinOperator_EXP = 47, + BuiltinOperator_TOPK_V2 = 48, + BuiltinOperator_SPLIT = 49, + BuiltinOperator_LOG_SOFTMAX = 50, + BuiltinOperator_DELEGATE = 51, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52, + BuiltinOperator_CAST = 53, + BuiltinOperator_PRELU = 54, + BuiltinOperator_MAXIMUM = 55, + BuiltinOperator_ARG_MAX = 56, + BuiltinOperator_MINIMUM = 57, + BuiltinOperator_LESS = 58, + BuiltinOperator_NEG = 59, + BuiltinOperator_PADV2 = 60, + BuiltinOperator_GREATER = 61, + BuiltinOperator_GREATER_EQUAL = 62, + BuiltinOperator_LESS_EQUAL = 63, + BuiltinOperator_SELECT = 64, + BuiltinOperator_SLICE = 65, + BuiltinOperator_SIN = 66, + BuiltinOperator_TRANSPOSE_CONV = 67, + BuiltinOperator_SPARSE_TO_DENSE = 68, + BuiltinOperator_TILE = 69, + BuiltinOperator_EXPAND_DIMS = 70, + BuiltinOperator_EQUAL = 71, + BuiltinOperator_NOT_EQUAL = 72, + BuiltinOperator_LOG = 73, + BuiltinOperator_SUM = 74, + BuiltinOperator_SQRT = 75, + BuiltinOperator_RSQRT = 76, + BuiltinOperator_SHAPE = 77, + BuiltinOperator_POW = 78, + BuiltinOperator_ARG_MIN = 79, + BuiltinOperator_FAKE_QUANT = 80, + BuiltinOperator_REDUCE_PROD = 81, + BuiltinOperator_REDUCE_MAX = 82, + BuiltinOperator_PACK = 83, + BuiltinOperator_LOGICAL_OR = 84, + BuiltinOperator_ONE_HOT = 85, + BuiltinOperator_LOGICAL_AND = 86, + BuiltinOperator_LOGICAL_NOT = 87, + BuiltinOperator_UNPACK = 88, + BuiltinOperator_REDUCE_MIN = 89, + BuiltinOperator_FLOOR_DIV = 90, + BuiltinOperator_REDUCE_ANY = 91, + BuiltinOperator_SQUARE = 92, + BuiltinOperator_ZEROS_LIKE = 93, + BuiltinOperator_FILL = 94, + BuiltinOperator_FLOOR_MOD = 95, + BuiltinOperator_RANGE = 96, + BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97, + BuiltinOperator_LEAKY_RELU = 98, + BuiltinOperator_SQUARED_DIFFERENCE = 99, + BuiltinOperator_MIRROR_PAD = 100, + BuiltinOperator_ABS = 101, + BuiltinOperator_SPLIT_V = 102, + BuiltinOperator_UNIQUE = 103, + BuiltinOperator_CEIL = 104, + BuiltinOperator_REVERSE_V2 = 105, + BuiltinOperator_ADD_N = 106, + BuiltinOperator_GATHER_ND = 107, + BuiltinOperator_COS = 108, + BuiltinOperator_WHERE = 109, + BuiltinOperator_RANK = 110, + BuiltinOperator_ELU = 111, + BuiltinOperator_REVERSE_SEQUENCE = 112, + BuiltinOperator_MATRIX_DIAG = 113, + BuiltinOperator_QUANTIZE = 114, + BuiltinOperator_MATRIX_SET_DIAG = 115, + BuiltinOperator_ROUND = 116, + BuiltinOperator_HARD_SWISH = 117, + BuiltinOperator_IF = 118, + BuiltinOperator_WHILE = 119, + BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120, + BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121, + BuiltinOperator_SCATTER_ND = 122, + BuiltinOperator_SELECT_V2 = 123, + BuiltinOperator_DENSIFY = 124, + BuiltinOperator_SEGMENT_SUM = 125, + BuiltinOperator_BATCH_MATMUL = 126, + BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES = 127, + BuiltinOperator_CUMSUM = 128, + BuiltinOperator_CALL_ONCE = 129, + BuiltinOperator_BROADCAST_TO = 130, + BuiltinOperator_RFFT2D = 131, + BuiltinOperator_CONV_3D = 132, + BuiltinOperator_IMAG = 133, + BuiltinOperator_REAL = 134, + BuiltinOperator_COMPLEX_ABS = 135, + BuiltinOperator_HASHTABLE = 136, + BuiltinOperator_HASHTABLE_FIND = 137, + BuiltinOperator_HASHTABLE_IMPORT = 138, + BuiltinOperator_HASHTABLE_SIZE = 139, + BuiltinOperator_REDUCE_ALL = 140, + BuiltinOperator_CONV_3D_TRANSPOSE = 141, + BuiltinOperator_VAR_HANDLE = 142, + BuiltinOperator_READ_VARIABLE = 143, + BuiltinOperator_ASSIGN_VARIABLE = 144, + BuiltinOperator_BROADCAST_ARGS = 145, + BuiltinOperator_RANDOM_STANDARD_NORMAL = 146, + BuiltinOperator_BUCKETIZE = 147, + BuiltinOperator_RANDOM_UNIFORM = 148, + BuiltinOperator_MULTINOMIAL = 149, + BuiltinOperator_GELU = 150, + BuiltinOperator_DYNAMIC_UPDATE_SLICE = 151, + BuiltinOperator_RELU_0_TO_1 = 152, + BuiltinOperator_UNSORTED_SEGMENT_PROD = 153, + BuiltinOperator_UNSORTED_SEGMENT_MAX = 154, + BuiltinOperator_UNSORTED_SEGMENT_SUM = 155, + BuiltinOperator_ATAN2 = 156, + BuiltinOperator_UNSORTED_SEGMENT_MIN = 157, + BuiltinOperator_SIGN = 158, + BuiltinOperator_MIN = BuiltinOperator_ADD, + BuiltinOperator_MAX = BuiltinOperator_SIGN +}; + +inline const BuiltinOperator (&EnumValuesBuiltinOperator())[159] { + static const BuiltinOperator values[] = { + BuiltinOperator_ADD, + BuiltinOperator_AVERAGE_POOL_2D, + BuiltinOperator_CONCATENATION, + BuiltinOperator_CONV_2D, + BuiltinOperator_DEPTHWISE_CONV_2D, + BuiltinOperator_DEPTH_TO_SPACE, + BuiltinOperator_DEQUANTIZE, + BuiltinOperator_EMBEDDING_LOOKUP, + BuiltinOperator_FLOOR, + BuiltinOperator_FULLY_CONNECTED, + BuiltinOperator_HASHTABLE_LOOKUP, + BuiltinOperator_L2_NORMALIZATION, + BuiltinOperator_L2_POOL_2D, + BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, + BuiltinOperator_LOGISTIC, + BuiltinOperator_LSH_PROJECTION, + BuiltinOperator_LSTM, + BuiltinOperator_MAX_POOL_2D, + BuiltinOperator_MUL, + BuiltinOperator_RELU, + BuiltinOperator_RELU_N1_TO_1, + BuiltinOperator_RELU6, + BuiltinOperator_RESHAPE, + BuiltinOperator_RESIZE_BILINEAR, + BuiltinOperator_RNN, + BuiltinOperator_SOFTMAX, + BuiltinOperator_SPACE_TO_DEPTH, + BuiltinOperator_SVDF, + BuiltinOperator_TANH, + BuiltinOperator_CONCAT_EMBEDDINGS, + BuiltinOperator_SKIP_GRAM, + BuiltinOperator_CALL, + BuiltinOperator_CUSTOM, + BuiltinOperator_EMBEDDING_LOOKUP_SPARSE, + BuiltinOperator_PAD, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN, + BuiltinOperator_GATHER, + BuiltinOperator_BATCH_TO_SPACE_ND, + BuiltinOperator_SPACE_TO_BATCH_ND, + BuiltinOperator_TRANSPOSE, + BuiltinOperator_MEAN, + BuiltinOperator_SUB, + BuiltinOperator_DIV, + BuiltinOperator_SQUEEZE, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_STRIDED_SLICE, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN, + BuiltinOperator_EXP, + BuiltinOperator_TOPK_V2, + BuiltinOperator_SPLIT, + BuiltinOperator_LOG_SOFTMAX, + BuiltinOperator_DELEGATE, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_CAST, + BuiltinOperator_PRELU, + BuiltinOperator_MAXIMUM, + BuiltinOperator_ARG_MAX, + BuiltinOperator_MINIMUM, + BuiltinOperator_LESS, + BuiltinOperator_NEG, + BuiltinOperator_PADV2, + BuiltinOperator_GREATER, + BuiltinOperator_GREATER_EQUAL, + BuiltinOperator_LESS_EQUAL, + BuiltinOperator_SELECT, + BuiltinOperator_SLICE, + BuiltinOperator_SIN, + BuiltinOperator_TRANSPOSE_CONV, + BuiltinOperator_SPARSE_TO_DENSE, + BuiltinOperator_TILE, + BuiltinOperator_EXPAND_DIMS, + BuiltinOperator_EQUAL, + BuiltinOperator_NOT_EQUAL, + BuiltinOperator_LOG, + BuiltinOperator_SUM, + BuiltinOperator_SQRT, + BuiltinOperator_RSQRT, + BuiltinOperator_SHAPE, + BuiltinOperator_POW, + BuiltinOperator_ARG_MIN, + BuiltinOperator_FAKE_QUANT, + BuiltinOperator_REDUCE_PROD, + BuiltinOperator_REDUCE_MAX, + BuiltinOperator_PACK, + BuiltinOperator_LOGICAL_OR, + BuiltinOperator_ONE_HOT, + BuiltinOperator_LOGICAL_AND, + BuiltinOperator_LOGICAL_NOT, + BuiltinOperator_UNPACK, + BuiltinOperator_REDUCE_MIN, + BuiltinOperator_FLOOR_DIV, + BuiltinOperator_REDUCE_ANY, + BuiltinOperator_SQUARE, + BuiltinOperator_ZEROS_LIKE, + BuiltinOperator_FILL, + BuiltinOperator_FLOOR_MOD, + BuiltinOperator_RANGE, + BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, + BuiltinOperator_LEAKY_RELU, + BuiltinOperator_SQUARED_DIFFERENCE, + BuiltinOperator_MIRROR_PAD, + BuiltinOperator_ABS, + BuiltinOperator_SPLIT_V, + BuiltinOperator_UNIQUE, + BuiltinOperator_CEIL, + BuiltinOperator_REVERSE_V2, + BuiltinOperator_ADD_N, + BuiltinOperator_GATHER_ND, + BuiltinOperator_COS, + BuiltinOperator_WHERE, + BuiltinOperator_RANK, + BuiltinOperator_ELU, + BuiltinOperator_REVERSE_SEQUENCE, + BuiltinOperator_MATRIX_DIAG, + BuiltinOperator_QUANTIZE, + BuiltinOperator_MATRIX_SET_DIAG, + BuiltinOperator_ROUND, + BuiltinOperator_HARD_SWISH, + BuiltinOperator_IF, + BuiltinOperator_WHILE, + BuiltinOperator_NON_MAX_SUPPRESSION_V4, + BuiltinOperator_NON_MAX_SUPPRESSION_V5, + BuiltinOperator_SCATTER_ND, + BuiltinOperator_SELECT_V2, + BuiltinOperator_DENSIFY, + BuiltinOperator_SEGMENT_SUM, + BuiltinOperator_BATCH_MATMUL, + BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES, + BuiltinOperator_CUMSUM, + BuiltinOperator_CALL_ONCE, + BuiltinOperator_BROADCAST_TO, + BuiltinOperator_RFFT2D, + BuiltinOperator_CONV_3D, + BuiltinOperator_IMAG, + BuiltinOperator_REAL, + BuiltinOperator_COMPLEX_ABS, + BuiltinOperator_HASHTABLE, + BuiltinOperator_HASHTABLE_FIND, + BuiltinOperator_HASHTABLE_IMPORT, + BuiltinOperator_HASHTABLE_SIZE, + BuiltinOperator_REDUCE_ALL, + BuiltinOperator_CONV_3D_TRANSPOSE, + BuiltinOperator_VAR_HANDLE, + BuiltinOperator_READ_VARIABLE, + BuiltinOperator_ASSIGN_VARIABLE, + BuiltinOperator_BROADCAST_ARGS, + BuiltinOperator_RANDOM_STANDARD_NORMAL, + BuiltinOperator_BUCKETIZE, + BuiltinOperator_RANDOM_UNIFORM, + BuiltinOperator_MULTINOMIAL, + BuiltinOperator_GELU, + BuiltinOperator_DYNAMIC_UPDATE_SLICE, + BuiltinOperator_RELU_0_TO_1, + BuiltinOperator_UNSORTED_SEGMENT_PROD, + BuiltinOperator_UNSORTED_SEGMENT_MAX, + BuiltinOperator_UNSORTED_SEGMENT_SUM, + BuiltinOperator_ATAN2, + BuiltinOperator_UNSORTED_SEGMENT_MIN, + BuiltinOperator_SIGN + }; + return values; +} + +inline const char * const *EnumNamesBuiltinOperator() { + static const char * const names[160] = { + "ADD", + "AVERAGE_POOL_2D", + "CONCATENATION", + "CONV_2D", + "DEPTHWISE_CONV_2D", + "DEPTH_TO_SPACE", + "DEQUANTIZE", + "EMBEDDING_LOOKUP", + "FLOOR", + "FULLY_CONNECTED", + "HASHTABLE_LOOKUP", + "L2_NORMALIZATION", + "L2_POOL_2D", + "LOCAL_RESPONSE_NORMALIZATION", + "LOGISTIC", + "LSH_PROJECTION", + "LSTM", + "MAX_POOL_2D", + "MUL", + "RELU", + "RELU_N1_TO_1", + "RELU6", + "RESHAPE", + "RESIZE_BILINEAR", + "RNN", + "SOFTMAX", + "SPACE_TO_DEPTH", + "SVDF", + "TANH", + "CONCAT_EMBEDDINGS", + "SKIP_GRAM", + "CALL", + "CUSTOM", + "EMBEDDING_LOOKUP_SPARSE", + "PAD", + "UNIDIRECTIONAL_SEQUENCE_RNN", + "GATHER", + "BATCH_TO_SPACE_ND", + "SPACE_TO_BATCH_ND", + "TRANSPOSE", + "MEAN", + "SUB", + "DIV", + "SQUEEZE", + "UNIDIRECTIONAL_SEQUENCE_LSTM", + "STRIDED_SLICE", + "BIDIRECTIONAL_SEQUENCE_RNN", + "EXP", + "TOPK_V2", + "SPLIT", + "LOG_SOFTMAX", + "DELEGATE", + "BIDIRECTIONAL_SEQUENCE_LSTM", + "CAST", + "PRELU", + "MAXIMUM", + "ARG_MAX", + "MINIMUM", + "LESS", + "NEG", + "PADV2", + "GREATER", + "GREATER_EQUAL", + "LESS_EQUAL", + "SELECT", + "SLICE", + "SIN", + "TRANSPOSE_CONV", + "SPARSE_TO_DENSE", + "TILE", + "EXPAND_DIMS", + "EQUAL", + "NOT_EQUAL", + "LOG", + "SUM", + "SQRT", + "RSQRT", + "SHAPE", + "POW", + "ARG_MIN", + "FAKE_QUANT", + "REDUCE_PROD", + "REDUCE_MAX", + "PACK", + "LOGICAL_OR", + "ONE_HOT", + "LOGICAL_AND", + "LOGICAL_NOT", + "UNPACK", + "REDUCE_MIN", + "FLOOR_DIV", + "REDUCE_ANY", + "SQUARE", + "ZEROS_LIKE", + "FILL", + "FLOOR_MOD", + "RANGE", + "RESIZE_NEAREST_NEIGHBOR", + "LEAKY_RELU", + "SQUARED_DIFFERENCE", + "MIRROR_PAD", + "ABS", + "SPLIT_V", + "UNIQUE", + "CEIL", + "REVERSE_V2", + "ADD_N", + "GATHER_ND", + "COS", + "WHERE", + "RANK", + "ELU", + "REVERSE_SEQUENCE", + "MATRIX_DIAG", + "QUANTIZE", + "MATRIX_SET_DIAG", + "ROUND", + "HARD_SWISH", + "IF", + "WHILE", + "NON_MAX_SUPPRESSION_V4", + "NON_MAX_SUPPRESSION_V5", + "SCATTER_ND", + "SELECT_V2", + "DENSIFY", + "SEGMENT_SUM", + "BATCH_MATMUL", + "PLACEHOLDER_FOR_GREATER_OP_CODES", + "CUMSUM", + "CALL_ONCE", + "BROADCAST_TO", + "RFFT2D", + "CONV_3D", + "IMAG", + "REAL", + "COMPLEX_ABS", + "HASHTABLE", + "HASHTABLE_FIND", + "HASHTABLE_IMPORT", + "HASHTABLE_SIZE", + "REDUCE_ALL", + "CONV_3D_TRANSPOSE", + "VAR_HANDLE", + "READ_VARIABLE", + "ASSIGN_VARIABLE", + "BROADCAST_ARGS", + "RANDOM_STANDARD_NORMAL", + "BUCKETIZE", + "RANDOM_UNIFORM", + "MULTINOMIAL", + "GELU", + "DYNAMIC_UPDATE_SLICE", + "RELU_0_TO_1", + "UNSORTED_SEGMENT_PROD", + "UNSORTED_SEGMENT_MAX", + "UNSORTED_SEGMENT_SUM", + "ATAN2", + "UNSORTED_SEGMENT_MIN", + "SIGN", + nullptr + }; + return names; +} + +inline const char *EnumNameBuiltinOperator(BuiltinOperator e) { + if (flatbuffers::IsOutRange(e, BuiltinOperator_ADD, BuiltinOperator_SIGN)) return ""; + const size_t index = static_cast(e); + return EnumNamesBuiltinOperator()[index]; +} + +enum BuiltinOptions : uint8_t { + BuiltinOptions_NONE = 0, + BuiltinOptions_Conv2DOptions = 1, + BuiltinOptions_DepthwiseConv2DOptions = 2, + BuiltinOptions_ConcatEmbeddingsOptions = 3, + BuiltinOptions_LSHProjectionOptions = 4, + BuiltinOptions_Pool2DOptions = 5, + BuiltinOptions_SVDFOptions = 6, + BuiltinOptions_RNNOptions = 7, + BuiltinOptions_FullyConnectedOptions = 8, + BuiltinOptions_SoftmaxOptions = 9, + BuiltinOptions_ConcatenationOptions = 10, + BuiltinOptions_AddOptions = 11, + BuiltinOptions_L2NormOptions = 12, + BuiltinOptions_LocalResponseNormalizationOptions = 13, + BuiltinOptions_LSTMOptions = 14, + BuiltinOptions_ResizeBilinearOptions = 15, + BuiltinOptions_CallOptions = 16, + BuiltinOptions_ReshapeOptions = 17, + BuiltinOptions_SkipGramOptions = 18, + BuiltinOptions_SpaceToDepthOptions = 19, + BuiltinOptions_EmbeddingLookupSparseOptions = 20, + BuiltinOptions_MulOptions = 21, + BuiltinOptions_PadOptions = 22, + BuiltinOptions_GatherOptions = 23, + BuiltinOptions_BatchToSpaceNDOptions = 24, + BuiltinOptions_SpaceToBatchNDOptions = 25, + BuiltinOptions_TransposeOptions = 26, + BuiltinOptions_ReducerOptions = 27, + BuiltinOptions_SubOptions = 28, + BuiltinOptions_DivOptions = 29, + BuiltinOptions_SqueezeOptions = 30, + BuiltinOptions_SequenceRNNOptions = 31, + BuiltinOptions_StridedSliceOptions = 32, + BuiltinOptions_ExpOptions = 33, + BuiltinOptions_TopKV2Options = 34, + BuiltinOptions_SplitOptions = 35, + BuiltinOptions_LogSoftmaxOptions = 36, + BuiltinOptions_CastOptions = 37, + BuiltinOptions_DequantizeOptions = 38, + BuiltinOptions_MaximumMinimumOptions = 39, + BuiltinOptions_ArgMaxOptions = 40, + BuiltinOptions_LessOptions = 41, + BuiltinOptions_NegOptions = 42, + BuiltinOptions_PadV2Options = 43, + BuiltinOptions_GreaterOptions = 44, + BuiltinOptions_GreaterEqualOptions = 45, + BuiltinOptions_LessEqualOptions = 46, + BuiltinOptions_SelectOptions = 47, + BuiltinOptions_SliceOptions = 48, + BuiltinOptions_TransposeConvOptions = 49, + BuiltinOptions_SparseToDenseOptions = 50, + BuiltinOptions_TileOptions = 51, + BuiltinOptions_ExpandDimsOptions = 52, + BuiltinOptions_EqualOptions = 53, + BuiltinOptions_NotEqualOptions = 54, + BuiltinOptions_ShapeOptions = 55, + BuiltinOptions_PowOptions = 56, + BuiltinOptions_ArgMinOptions = 57, + BuiltinOptions_FakeQuantOptions = 58, + BuiltinOptions_PackOptions = 59, + BuiltinOptions_LogicalOrOptions = 60, + BuiltinOptions_OneHotOptions = 61, + BuiltinOptions_LogicalAndOptions = 62, + BuiltinOptions_LogicalNotOptions = 63, + BuiltinOptions_UnpackOptions = 64, + BuiltinOptions_FloorDivOptions = 65, + BuiltinOptions_SquareOptions = 66, + BuiltinOptions_ZerosLikeOptions = 67, + BuiltinOptions_FillOptions = 68, + BuiltinOptions_BidirectionalSequenceLSTMOptions = 69, + BuiltinOptions_BidirectionalSequenceRNNOptions = 70, + BuiltinOptions_UnidirectionalSequenceLSTMOptions = 71, + BuiltinOptions_FloorModOptions = 72, + BuiltinOptions_RangeOptions = 73, + BuiltinOptions_ResizeNearestNeighborOptions = 74, + BuiltinOptions_LeakyReluOptions = 75, + BuiltinOptions_SquaredDifferenceOptions = 76, + BuiltinOptions_MirrorPadOptions = 77, + BuiltinOptions_AbsOptions = 78, + BuiltinOptions_SplitVOptions = 79, + BuiltinOptions_UniqueOptions = 80, + BuiltinOptions_ReverseV2Options = 81, + BuiltinOptions_AddNOptions = 82, + BuiltinOptions_GatherNdOptions = 83, + BuiltinOptions_CosOptions = 84, + BuiltinOptions_WhereOptions = 85, + BuiltinOptions_RankOptions = 86, + BuiltinOptions_ReverseSequenceOptions = 87, + BuiltinOptions_MatrixDiagOptions = 88, + BuiltinOptions_QuantizeOptions = 89, + BuiltinOptions_MatrixSetDiagOptions = 90, + BuiltinOptions_HardSwishOptions = 91, + BuiltinOptions_IfOptions = 92, + BuiltinOptions_WhileOptions = 93, + BuiltinOptions_DepthToSpaceOptions = 94, + BuiltinOptions_NonMaxSuppressionV4Options = 95, + BuiltinOptions_NonMaxSuppressionV5Options = 96, + BuiltinOptions_ScatterNdOptions = 97, + BuiltinOptions_SelectV2Options = 98, + BuiltinOptions_DensifyOptions = 99, + BuiltinOptions_SegmentSumOptions = 100, + BuiltinOptions_BatchMatMulOptions = 101, + BuiltinOptions_CumsumOptions = 102, + BuiltinOptions_CallOnceOptions = 103, + BuiltinOptions_BroadcastToOptions = 104, + BuiltinOptions_Rfft2dOptions = 105, + BuiltinOptions_Conv3DOptions = 106, + BuiltinOptions_HashtableOptions = 107, + BuiltinOptions_HashtableFindOptions = 108, + BuiltinOptions_HashtableImportOptions = 109, + BuiltinOptions_HashtableSizeOptions = 110, + BuiltinOptions_VarHandleOptions = 111, + BuiltinOptions_ReadVariableOptions = 112, + BuiltinOptions_AssignVariableOptions = 113, + BuiltinOptions_RandomOptions = 114, + BuiltinOptions_BucketizeOptions = 115, + BuiltinOptions_GeluOptions = 116, + BuiltinOptions_DynamicUpdateSliceOptions = 117, + BuiltinOptions_UnsortedSegmentProdOptions = 118, + BuiltinOptions_UnsortedSegmentMaxOptions = 119, + BuiltinOptions_UnsortedSegmentMinOptions = 120, + BuiltinOptions_UnsortedSegmentSumOptions = 121, + BuiltinOptions_ATan2Options = 122, + BuiltinOptions_SignOptions = 123, + BuiltinOptions_MIN = BuiltinOptions_NONE, + BuiltinOptions_MAX = BuiltinOptions_SignOptions +}; + +inline const BuiltinOptions (&EnumValuesBuiltinOptions())[124] { + static const BuiltinOptions values[] = { + BuiltinOptions_NONE, + BuiltinOptions_Conv2DOptions, + BuiltinOptions_DepthwiseConv2DOptions, + BuiltinOptions_ConcatEmbeddingsOptions, + BuiltinOptions_LSHProjectionOptions, + BuiltinOptions_Pool2DOptions, + BuiltinOptions_SVDFOptions, + BuiltinOptions_RNNOptions, + BuiltinOptions_FullyConnectedOptions, + BuiltinOptions_SoftmaxOptions, + BuiltinOptions_ConcatenationOptions, + BuiltinOptions_AddOptions, + BuiltinOptions_L2NormOptions, + BuiltinOptions_LocalResponseNormalizationOptions, + BuiltinOptions_LSTMOptions, + BuiltinOptions_ResizeBilinearOptions, + BuiltinOptions_CallOptions, + BuiltinOptions_ReshapeOptions, + BuiltinOptions_SkipGramOptions, + BuiltinOptions_SpaceToDepthOptions, + BuiltinOptions_EmbeddingLookupSparseOptions, + BuiltinOptions_MulOptions, + BuiltinOptions_PadOptions, + BuiltinOptions_GatherOptions, + BuiltinOptions_BatchToSpaceNDOptions, + BuiltinOptions_SpaceToBatchNDOptions, + BuiltinOptions_TransposeOptions, + BuiltinOptions_ReducerOptions, + BuiltinOptions_SubOptions, + BuiltinOptions_DivOptions, + BuiltinOptions_SqueezeOptions, + BuiltinOptions_SequenceRNNOptions, + BuiltinOptions_StridedSliceOptions, + BuiltinOptions_ExpOptions, + BuiltinOptions_TopKV2Options, + BuiltinOptions_SplitOptions, + BuiltinOptions_LogSoftmaxOptions, + BuiltinOptions_CastOptions, + BuiltinOptions_DequantizeOptions, + BuiltinOptions_MaximumMinimumOptions, + BuiltinOptions_ArgMaxOptions, + BuiltinOptions_LessOptions, + BuiltinOptions_NegOptions, + BuiltinOptions_PadV2Options, + BuiltinOptions_GreaterOptions, + BuiltinOptions_GreaterEqualOptions, + BuiltinOptions_LessEqualOptions, + BuiltinOptions_SelectOptions, + BuiltinOptions_SliceOptions, + BuiltinOptions_TransposeConvOptions, + BuiltinOptions_SparseToDenseOptions, + BuiltinOptions_TileOptions, + BuiltinOptions_ExpandDimsOptions, + BuiltinOptions_EqualOptions, + BuiltinOptions_NotEqualOptions, + BuiltinOptions_ShapeOptions, + BuiltinOptions_PowOptions, + BuiltinOptions_ArgMinOptions, + BuiltinOptions_FakeQuantOptions, + BuiltinOptions_PackOptions, + BuiltinOptions_LogicalOrOptions, + BuiltinOptions_OneHotOptions, + BuiltinOptions_LogicalAndOptions, + BuiltinOptions_LogicalNotOptions, + BuiltinOptions_UnpackOptions, + BuiltinOptions_FloorDivOptions, + BuiltinOptions_SquareOptions, + BuiltinOptions_ZerosLikeOptions, + BuiltinOptions_FillOptions, + BuiltinOptions_BidirectionalSequenceLSTMOptions, + BuiltinOptions_BidirectionalSequenceRNNOptions, + BuiltinOptions_UnidirectionalSequenceLSTMOptions, + BuiltinOptions_FloorModOptions, + BuiltinOptions_RangeOptions, + BuiltinOptions_ResizeNearestNeighborOptions, + BuiltinOptions_LeakyReluOptions, + BuiltinOptions_SquaredDifferenceOptions, + BuiltinOptions_MirrorPadOptions, + BuiltinOptions_AbsOptions, + BuiltinOptions_SplitVOptions, + BuiltinOptions_UniqueOptions, + BuiltinOptions_ReverseV2Options, + BuiltinOptions_AddNOptions, + BuiltinOptions_GatherNdOptions, + BuiltinOptions_CosOptions, + BuiltinOptions_WhereOptions, + BuiltinOptions_RankOptions, + BuiltinOptions_ReverseSequenceOptions, + BuiltinOptions_MatrixDiagOptions, + BuiltinOptions_QuantizeOptions, + BuiltinOptions_MatrixSetDiagOptions, + BuiltinOptions_HardSwishOptions, + BuiltinOptions_IfOptions, + BuiltinOptions_WhileOptions, + BuiltinOptions_DepthToSpaceOptions, + BuiltinOptions_NonMaxSuppressionV4Options, + BuiltinOptions_NonMaxSuppressionV5Options, + BuiltinOptions_ScatterNdOptions, + BuiltinOptions_SelectV2Options, + BuiltinOptions_DensifyOptions, + BuiltinOptions_SegmentSumOptions, + BuiltinOptions_BatchMatMulOptions, + BuiltinOptions_CumsumOptions, + BuiltinOptions_CallOnceOptions, + BuiltinOptions_BroadcastToOptions, + BuiltinOptions_Rfft2dOptions, + BuiltinOptions_Conv3DOptions, + BuiltinOptions_HashtableOptions, + BuiltinOptions_HashtableFindOptions, + BuiltinOptions_HashtableImportOptions, + BuiltinOptions_HashtableSizeOptions, + BuiltinOptions_VarHandleOptions, + BuiltinOptions_ReadVariableOptions, + BuiltinOptions_AssignVariableOptions, + BuiltinOptions_RandomOptions, + BuiltinOptions_BucketizeOptions, + BuiltinOptions_GeluOptions, + BuiltinOptions_DynamicUpdateSliceOptions, + BuiltinOptions_UnsortedSegmentProdOptions, + BuiltinOptions_UnsortedSegmentMaxOptions, + BuiltinOptions_UnsortedSegmentMinOptions, + BuiltinOptions_UnsortedSegmentSumOptions, + BuiltinOptions_ATan2Options, + BuiltinOptions_SignOptions + }; + return values; +} + +inline const char * const *EnumNamesBuiltinOptions() { + static const char * const names[125] = { + "NONE", + "Conv2DOptions", + "DepthwiseConv2DOptions", + "ConcatEmbeddingsOptions", + "LSHProjectionOptions", + "Pool2DOptions", + "SVDFOptions", + "RNNOptions", + "FullyConnectedOptions", + "SoftmaxOptions", + "ConcatenationOptions", + "AddOptions", + "L2NormOptions", + "LocalResponseNormalizationOptions", + "LSTMOptions", + "ResizeBilinearOptions", + "CallOptions", + "ReshapeOptions", + "SkipGramOptions", + "SpaceToDepthOptions", + "EmbeddingLookupSparseOptions", + "MulOptions", + "PadOptions", + "GatherOptions", + "BatchToSpaceNDOptions", + "SpaceToBatchNDOptions", + "TransposeOptions", + "ReducerOptions", + "SubOptions", + "DivOptions", + "SqueezeOptions", + "SequenceRNNOptions", + "StridedSliceOptions", + "ExpOptions", + "TopKV2Options", + "SplitOptions", + "LogSoftmaxOptions", + "CastOptions", + "DequantizeOptions", + "MaximumMinimumOptions", + "ArgMaxOptions", + "LessOptions", + "NegOptions", + "PadV2Options", + "GreaterOptions", + "GreaterEqualOptions", + "LessEqualOptions", + "SelectOptions", + "SliceOptions", + "TransposeConvOptions", + "SparseToDenseOptions", + "TileOptions", + "ExpandDimsOptions", + "EqualOptions", + "NotEqualOptions", + "ShapeOptions", + "PowOptions", + "ArgMinOptions", + "FakeQuantOptions", + "PackOptions", + "LogicalOrOptions", + "OneHotOptions", + "LogicalAndOptions", + "LogicalNotOptions", + "UnpackOptions", + "FloorDivOptions", + "SquareOptions", + "ZerosLikeOptions", + "FillOptions", + "BidirectionalSequenceLSTMOptions", + "BidirectionalSequenceRNNOptions", + "UnidirectionalSequenceLSTMOptions", + "FloorModOptions", + "RangeOptions", + "ResizeNearestNeighborOptions", + "LeakyReluOptions", + "SquaredDifferenceOptions", + "MirrorPadOptions", + "AbsOptions", + "SplitVOptions", + "UniqueOptions", + "ReverseV2Options", + "AddNOptions", + "GatherNdOptions", + "CosOptions", + "WhereOptions", + "RankOptions", + "ReverseSequenceOptions", + "MatrixDiagOptions", + "QuantizeOptions", + "MatrixSetDiagOptions", + "HardSwishOptions", + "IfOptions", + "WhileOptions", + "DepthToSpaceOptions", + "NonMaxSuppressionV4Options", + "NonMaxSuppressionV5Options", + "ScatterNdOptions", + "SelectV2Options", + "DensifyOptions", + "SegmentSumOptions", + "BatchMatMulOptions", + "CumsumOptions", + "CallOnceOptions", + "BroadcastToOptions", + "Rfft2dOptions", + "Conv3DOptions", + "HashtableOptions", + "HashtableFindOptions", + "HashtableImportOptions", + "HashtableSizeOptions", + "VarHandleOptions", + "ReadVariableOptions", + "AssignVariableOptions", + "RandomOptions", + "BucketizeOptions", + "GeluOptions", + "DynamicUpdateSliceOptions", + "UnsortedSegmentProdOptions", + "UnsortedSegmentMaxOptions", + "UnsortedSegmentMinOptions", + "UnsortedSegmentSumOptions", + "ATan2Options", + "SignOptions", + nullptr + }; + return names; +} + +inline const char *EnumNameBuiltinOptions(BuiltinOptions e) { + if (flatbuffers::IsOutRange(e, BuiltinOptions_NONE, BuiltinOptions_SignOptions)) return ""; + const size_t index = static_cast(e); + return EnumNamesBuiltinOptions()[index]; +} + +template struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NONE; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Conv2DOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DepthwiseConv2DOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ConcatEmbeddingsOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LSHProjectionOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Pool2DOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SVDFOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RNNOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FullyConnectedOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SoftmaxOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ConcatenationOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AddOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_L2NormOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LocalResponseNormalizationOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LSTMOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ResizeBilinearOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CallOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReshapeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SkipGramOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToDepthOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_EmbeddingLookupSparseOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MulOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PadOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GatherOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BatchToSpaceNDOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToBatchNDOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TransposeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReducerOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SubOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DivOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SqueezeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ExpOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TopKV2Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SplitOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogSoftmaxOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CastOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DequantizeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MaximumMinimumOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ArgMaxOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LessOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NegOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PadV2Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GreaterOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GreaterEqualOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LessEqualOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SelectOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SliceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TransposeConvOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SparseToDenseOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TileOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ExpandDimsOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_EqualOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NotEqualOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ShapeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PowOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ArgMinOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FakeQuantOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PackOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogicalOrOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_OneHotOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogicalAndOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogicalNotOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnpackOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FloorDivOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SquareOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ZerosLikeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FillOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceLSTMOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceRNNOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnidirectionalSequenceLSTMOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FloorModOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RangeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ResizeNearestNeighborOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LeakyReluOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UniqueOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReverseV2Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AddNOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GatherNdOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CosOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_WhereOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RankOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReverseSequenceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MatrixDiagOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_QuantizeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MatrixSetDiagOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HardSwishOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_IfOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_WhileOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DepthToSpaceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV4Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV5Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ScatterNdOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SelectV2Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DensifyOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SegmentSumOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BatchMatMulOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CumsumOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CallOnceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BroadcastToOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Rfft2dOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Conv3DOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableFindOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableImportOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableSizeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_VarHandleOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReadVariableOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AssignVariableOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RandomOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BucketizeOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GeluOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DynamicUpdateSliceOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentProdOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentMaxOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentMinOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentSumOptions; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ATan2Options; +}; + +template<> struct BuiltinOptionsTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SignOptions; +}; + +template struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NONE; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Conv2DOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DepthwiseConv2DOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ConcatEmbeddingsOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LSHProjectionOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Pool2DOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SVDFOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RNNOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FullyConnectedOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SoftmaxOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ConcatenationOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AddOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_L2NormOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LocalResponseNormalizationOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LSTMOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ResizeBilinearOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CallOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReshapeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SkipGramOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToDepthOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_EmbeddingLookupSparseOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MulOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PadOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GatherOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BatchToSpaceNDOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToBatchNDOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TransposeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReducerOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SubOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DivOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SqueezeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ExpOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TopKV2Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SplitOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogSoftmaxOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CastOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DequantizeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MaximumMinimumOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ArgMaxOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LessOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NegOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PadV2Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GreaterOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GreaterEqualOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LessEqualOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SelectOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SliceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TransposeConvOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SparseToDenseOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_TileOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ExpandDimsOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_EqualOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NotEqualOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ShapeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PowOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ArgMinOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FakeQuantOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_PackOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogicalOrOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_OneHotOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogicalAndOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LogicalNotOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnpackOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FloorDivOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SquareOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ZerosLikeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FillOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceLSTMOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceRNNOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnidirectionalSequenceLSTMOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_FloorModOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RangeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ResizeNearestNeighborOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_LeakyReluOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UniqueOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReverseV2Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AddNOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GatherNdOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CosOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_WhereOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RankOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReverseSequenceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MatrixDiagOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_QuantizeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_MatrixSetDiagOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HardSwishOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_IfOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_WhileOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DepthToSpaceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV4Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV5Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ScatterNdOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SelectV2Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DensifyOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SegmentSumOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BatchMatMulOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CumsumOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_CallOnceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BroadcastToOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Rfft2dOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_Conv3DOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableFindOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableImportOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_HashtableSizeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_VarHandleOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ReadVariableOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_AssignVariableOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_RandomOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_BucketizeOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_GeluOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_DynamicUpdateSliceOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentProdOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentMaxOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentMinOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_UnsortedSegmentSumOptions; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_ATan2Options; +}; + +template<> struct BuiltinOptionsUnionTraits { + static const BuiltinOptions enum_value = BuiltinOptions_SignOptions; +}; + +struct BuiltinOptionsUnion { + BuiltinOptions type; + void *value; + + BuiltinOptionsUnion() : type(BuiltinOptions_NONE), value(nullptr) {} + BuiltinOptionsUnion(BuiltinOptionsUnion&& u) FLATBUFFERS_NOEXCEPT : + type(BuiltinOptions_NONE), value(nullptr) + { std::swap(type, u.type); std::swap(value, u.value); } + BuiltinOptionsUnion(const BuiltinOptionsUnion &); + BuiltinOptionsUnion &operator=(const BuiltinOptionsUnion &u) + { BuiltinOptionsUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; } + BuiltinOptionsUnion &operator=(BuiltinOptionsUnion &&u) FLATBUFFERS_NOEXCEPT + { std::swap(type, u.type); std::swap(value, u.value); return *this; } + ~BuiltinOptionsUnion() { Reset(); } + + void Reset(); + + template + void Set(T&& val) { + typedef typename std::remove_reference::type RT; + Reset(); + type = BuiltinOptionsUnionTraits::enum_value; + if (type != BuiltinOptions_NONE) { + value = new RT(std::forward(val)); + } + } + + static void *UnPack(const void *obj, BuiltinOptions type, const flatbuffers::resolver_function_t *resolver); + flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const; + + tflite::Conv2DOptionsT *AsConv2DOptions() { + return type == BuiltinOptions_Conv2DOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::Conv2DOptionsT *AsConv2DOptions() const { + return type == BuiltinOptions_Conv2DOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::DepthwiseConv2DOptionsT *AsDepthwiseConv2DOptions() { + return type == BuiltinOptions_DepthwiseConv2DOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::DepthwiseConv2DOptionsT *AsDepthwiseConv2DOptions() const { + return type == BuiltinOptions_DepthwiseConv2DOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ConcatEmbeddingsOptionsT *AsConcatEmbeddingsOptions() { + return type == BuiltinOptions_ConcatEmbeddingsOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ConcatEmbeddingsOptionsT *AsConcatEmbeddingsOptions() const { + return type == BuiltinOptions_ConcatEmbeddingsOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LSHProjectionOptionsT *AsLSHProjectionOptions() { + return type == BuiltinOptions_LSHProjectionOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LSHProjectionOptionsT *AsLSHProjectionOptions() const { + return type == BuiltinOptions_LSHProjectionOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::Pool2DOptionsT *AsPool2DOptions() { + return type == BuiltinOptions_Pool2DOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::Pool2DOptionsT *AsPool2DOptions() const { + return type == BuiltinOptions_Pool2DOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SVDFOptionsT *AsSVDFOptions() { + return type == BuiltinOptions_SVDFOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SVDFOptionsT *AsSVDFOptions() const { + return type == BuiltinOptions_SVDFOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::RNNOptionsT *AsRNNOptions() { + return type == BuiltinOptions_RNNOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::RNNOptionsT *AsRNNOptions() const { + return type == BuiltinOptions_RNNOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::FullyConnectedOptionsT *AsFullyConnectedOptions() { + return type == BuiltinOptions_FullyConnectedOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::FullyConnectedOptionsT *AsFullyConnectedOptions() const { + return type == BuiltinOptions_FullyConnectedOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SoftmaxOptionsT *AsSoftmaxOptions() { + return type == BuiltinOptions_SoftmaxOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SoftmaxOptionsT *AsSoftmaxOptions() const { + return type == BuiltinOptions_SoftmaxOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ConcatenationOptionsT *AsConcatenationOptions() { + return type == BuiltinOptions_ConcatenationOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ConcatenationOptionsT *AsConcatenationOptions() const { + return type == BuiltinOptions_ConcatenationOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::AddOptionsT *AsAddOptions() { + return type == BuiltinOptions_AddOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::AddOptionsT *AsAddOptions() const { + return type == BuiltinOptions_AddOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::L2NormOptionsT *AsL2NormOptions() { + return type == BuiltinOptions_L2NormOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::L2NormOptionsT *AsL2NormOptions() const { + return type == BuiltinOptions_L2NormOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LocalResponseNormalizationOptionsT *AsLocalResponseNormalizationOptions() { + return type == BuiltinOptions_LocalResponseNormalizationOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LocalResponseNormalizationOptionsT *AsLocalResponseNormalizationOptions() const { + return type == BuiltinOptions_LocalResponseNormalizationOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LSTMOptionsT *AsLSTMOptions() { + return type == BuiltinOptions_LSTMOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LSTMOptionsT *AsLSTMOptions() const { + return type == BuiltinOptions_LSTMOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ResizeBilinearOptionsT *AsResizeBilinearOptions() { + return type == BuiltinOptions_ResizeBilinearOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ResizeBilinearOptionsT *AsResizeBilinearOptions() const { + return type == BuiltinOptions_ResizeBilinearOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::CallOptionsT *AsCallOptions() { + return type == BuiltinOptions_CallOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::CallOptionsT *AsCallOptions() const { + return type == BuiltinOptions_CallOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ReshapeOptionsT *AsReshapeOptions() { + return type == BuiltinOptions_ReshapeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ReshapeOptionsT *AsReshapeOptions() const { + return type == BuiltinOptions_ReshapeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SkipGramOptionsT *AsSkipGramOptions() { + return type == BuiltinOptions_SkipGramOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SkipGramOptionsT *AsSkipGramOptions() const { + return type == BuiltinOptions_SkipGramOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SpaceToDepthOptionsT *AsSpaceToDepthOptions() { + return type == BuiltinOptions_SpaceToDepthOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SpaceToDepthOptionsT *AsSpaceToDepthOptions() const { + return type == BuiltinOptions_SpaceToDepthOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::EmbeddingLookupSparseOptionsT *AsEmbeddingLookupSparseOptions() { + return type == BuiltinOptions_EmbeddingLookupSparseOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::EmbeddingLookupSparseOptionsT *AsEmbeddingLookupSparseOptions() const { + return type == BuiltinOptions_EmbeddingLookupSparseOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::MulOptionsT *AsMulOptions() { + return type == BuiltinOptions_MulOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::MulOptionsT *AsMulOptions() const { + return type == BuiltinOptions_MulOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::PadOptionsT *AsPadOptions() { + return type == BuiltinOptions_PadOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::PadOptionsT *AsPadOptions() const { + return type == BuiltinOptions_PadOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::GatherOptionsT *AsGatherOptions() { + return type == BuiltinOptions_GatherOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::GatherOptionsT *AsGatherOptions() const { + return type == BuiltinOptions_GatherOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::BatchToSpaceNDOptionsT *AsBatchToSpaceNDOptions() { + return type == BuiltinOptions_BatchToSpaceNDOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::BatchToSpaceNDOptionsT *AsBatchToSpaceNDOptions() const { + return type == BuiltinOptions_BatchToSpaceNDOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SpaceToBatchNDOptionsT *AsSpaceToBatchNDOptions() { + return type == BuiltinOptions_SpaceToBatchNDOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SpaceToBatchNDOptionsT *AsSpaceToBatchNDOptions() const { + return type == BuiltinOptions_SpaceToBatchNDOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::TransposeOptionsT *AsTransposeOptions() { + return type == BuiltinOptions_TransposeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::TransposeOptionsT *AsTransposeOptions() const { + return type == BuiltinOptions_TransposeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ReducerOptionsT *AsReducerOptions() { + return type == BuiltinOptions_ReducerOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ReducerOptionsT *AsReducerOptions() const { + return type == BuiltinOptions_ReducerOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SubOptionsT *AsSubOptions() { + return type == BuiltinOptions_SubOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SubOptionsT *AsSubOptions() const { + return type == BuiltinOptions_SubOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::DivOptionsT *AsDivOptions() { + return type == BuiltinOptions_DivOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::DivOptionsT *AsDivOptions() const { + return type == BuiltinOptions_DivOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SqueezeOptionsT *AsSqueezeOptions() { + return type == BuiltinOptions_SqueezeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SqueezeOptionsT *AsSqueezeOptions() const { + return type == BuiltinOptions_SqueezeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SequenceRNNOptionsT *AsSequenceRNNOptions() { + return type == BuiltinOptions_SequenceRNNOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SequenceRNNOptionsT *AsSequenceRNNOptions() const { + return type == BuiltinOptions_SequenceRNNOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::StridedSliceOptionsT *AsStridedSliceOptions() { + return type == BuiltinOptions_StridedSliceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::StridedSliceOptionsT *AsStridedSliceOptions() const { + return type == BuiltinOptions_StridedSliceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ExpOptionsT *AsExpOptions() { + return type == BuiltinOptions_ExpOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ExpOptionsT *AsExpOptions() const { + return type == BuiltinOptions_ExpOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::TopKV2OptionsT *AsTopKV2Options() { + return type == BuiltinOptions_TopKV2Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::TopKV2OptionsT *AsTopKV2Options() const { + return type == BuiltinOptions_TopKV2Options ? + reinterpret_cast(value) : nullptr; + } + tflite::SplitOptionsT *AsSplitOptions() { + return type == BuiltinOptions_SplitOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SplitOptionsT *AsSplitOptions() const { + return type == BuiltinOptions_SplitOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LogSoftmaxOptionsT *AsLogSoftmaxOptions() { + return type == BuiltinOptions_LogSoftmaxOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LogSoftmaxOptionsT *AsLogSoftmaxOptions() const { + return type == BuiltinOptions_LogSoftmaxOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::CastOptionsT *AsCastOptions() { + return type == BuiltinOptions_CastOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::CastOptionsT *AsCastOptions() const { + return type == BuiltinOptions_CastOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::DequantizeOptionsT *AsDequantizeOptions() { + return type == BuiltinOptions_DequantizeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::DequantizeOptionsT *AsDequantizeOptions() const { + return type == BuiltinOptions_DequantizeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::MaximumMinimumOptionsT *AsMaximumMinimumOptions() { + return type == BuiltinOptions_MaximumMinimumOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::MaximumMinimumOptionsT *AsMaximumMinimumOptions() const { + return type == BuiltinOptions_MaximumMinimumOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ArgMaxOptionsT *AsArgMaxOptions() { + return type == BuiltinOptions_ArgMaxOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ArgMaxOptionsT *AsArgMaxOptions() const { + return type == BuiltinOptions_ArgMaxOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LessOptionsT *AsLessOptions() { + return type == BuiltinOptions_LessOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LessOptionsT *AsLessOptions() const { + return type == BuiltinOptions_LessOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::NegOptionsT *AsNegOptions() { + return type == BuiltinOptions_NegOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::NegOptionsT *AsNegOptions() const { + return type == BuiltinOptions_NegOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::PadV2OptionsT *AsPadV2Options() { + return type == BuiltinOptions_PadV2Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::PadV2OptionsT *AsPadV2Options() const { + return type == BuiltinOptions_PadV2Options ? + reinterpret_cast(value) : nullptr; + } + tflite::GreaterOptionsT *AsGreaterOptions() { + return type == BuiltinOptions_GreaterOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::GreaterOptionsT *AsGreaterOptions() const { + return type == BuiltinOptions_GreaterOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::GreaterEqualOptionsT *AsGreaterEqualOptions() { + return type == BuiltinOptions_GreaterEqualOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::GreaterEqualOptionsT *AsGreaterEqualOptions() const { + return type == BuiltinOptions_GreaterEqualOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LessEqualOptionsT *AsLessEqualOptions() { + return type == BuiltinOptions_LessEqualOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LessEqualOptionsT *AsLessEqualOptions() const { + return type == BuiltinOptions_LessEqualOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SelectOptionsT *AsSelectOptions() { + return type == BuiltinOptions_SelectOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SelectOptionsT *AsSelectOptions() const { + return type == BuiltinOptions_SelectOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SliceOptionsT *AsSliceOptions() { + return type == BuiltinOptions_SliceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SliceOptionsT *AsSliceOptions() const { + return type == BuiltinOptions_SliceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::TransposeConvOptionsT *AsTransposeConvOptions() { + return type == BuiltinOptions_TransposeConvOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::TransposeConvOptionsT *AsTransposeConvOptions() const { + return type == BuiltinOptions_TransposeConvOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SparseToDenseOptionsT *AsSparseToDenseOptions() { + return type == BuiltinOptions_SparseToDenseOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SparseToDenseOptionsT *AsSparseToDenseOptions() const { + return type == BuiltinOptions_SparseToDenseOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::TileOptionsT *AsTileOptions() { + return type == BuiltinOptions_TileOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::TileOptionsT *AsTileOptions() const { + return type == BuiltinOptions_TileOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ExpandDimsOptionsT *AsExpandDimsOptions() { + return type == BuiltinOptions_ExpandDimsOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ExpandDimsOptionsT *AsExpandDimsOptions() const { + return type == BuiltinOptions_ExpandDimsOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::EqualOptionsT *AsEqualOptions() { + return type == BuiltinOptions_EqualOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::EqualOptionsT *AsEqualOptions() const { + return type == BuiltinOptions_EqualOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::NotEqualOptionsT *AsNotEqualOptions() { + return type == BuiltinOptions_NotEqualOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::NotEqualOptionsT *AsNotEqualOptions() const { + return type == BuiltinOptions_NotEqualOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ShapeOptionsT *AsShapeOptions() { + return type == BuiltinOptions_ShapeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ShapeOptionsT *AsShapeOptions() const { + return type == BuiltinOptions_ShapeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::PowOptionsT *AsPowOptions() { + return type == BuiltinOptions_PowOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::PowOptionsT *AsPowOptions() const { + return type == BuiltinOptions_PowOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ArgMinOptionsT *AsArgMinOptions() { + return type == BuiltinOptions_ArgMinOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ArgMinOptionsT *AsArgMinOptions() const { + return type == BuiltinOptions_ArgMinOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::FakeQuantOptionsT *AsFakeQuantOptions() { + return type == BuiltinOptions_FakeQuantOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::FakeQuantOptionsT *AsFakeQuantOptions() const { + return type == BuiltinOptions_FakeQuantOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::PackOptionsT *AsPackOptions() { + return type == BuiltinOptions_PackOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::PackOptionsT *AsPackOptions() const { + return type == BuiltinOptions_PackOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LogicalOrOptionsT *AsLogicalOrOptions() { + return type == BuiltinOptions_LogicalOrOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LogicalOrOptionsT *AsLogicalOrOptions() const { + return type == BuiltinOptions_LogicalOrOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::OneHotOptionsT *AsOneHotOptions() { + return type == BuiltinOptions_OneHotOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::OneHotOptionsT *AsOneHotOptions() const { + return type == BuiltinOptions_OneHotOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LogicalAndOptionsT *AsLogicalAndOptions() { + return type == BuiltinOptions_LogicalAndOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LogicalAndOptionsT *AsLogicalAndOptions() const { + return type == BuiltinOptions_LogicalAndOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LogicalNotOptionsT *AsLogicalNotOptions() { + return type == BuiltinOptions_LogicalNotOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LogicalNotOptionsT *AsLogicalNotOptions() const { + return type == BuiltinOptions_LogicalNotOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UnpackOptionsT *AsUnpackOptions() { + return type == BuiltinOptions_UnpackOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UnpackOptionsT *AsUnpackOptions() const { + return type == BuiltinOptions_UnpackOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::FloorDivOptionsT *AsFloorDivOptions() { + return type == BuiltinOptions_FloorDivOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::FloorDivOptionsT *AsFloorDivOptions() const { + return type == BuiltinOptions_FloorDivOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SquareOptionsT *AsSquareOptions() { + return type == BuiltinOptions_SquareOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SquareOptionsT *AsSquareOptions() const { + return type == BuiltinOptions_SquareOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ZerosLikeOptionsT *AsZerosLikeOptions() { + return type == BuiltinOptions_ZerosLikeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ZerosLikeOptionsT *AsZerosLikeOptions() const { + return type == BuiltinOptions_ZerosLikeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::FillOptionsT *AsFillOptions() { + return type == BuiltinOptions_FillOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::FillOptionsT *AsFillOptions() const { + return type == BuiltinOptions_FillOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::BidirectionalSequenceLSTMOptionsT *AsBidirectionalSequenceLSTMOptions() { + return type == BuiltinOptions_BidirectionalSequenceLSTMOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::BidirectionalSequenceLSTMOptionsT *AsBidirectionalSequenceLSTMOptions() const { + return type == BuiltinOptions_BidirectionalSequenceLSTMOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::BidirectionalSequenceRNNOptionsT *AsBidirectionalSequenceRNNOptions() { + return type == BuiltinOptions_BidirectionalSequenceRNNOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::BidirectionalSequenceRNNOptionsT *AsBidirectionalSequenceRNNOptions() const { + return type == BuiltinOptions_BidirectionalSequenceRNNOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UnidirectionalSequenceLSTMOptionsT *AsUnidirectionalSequenceLSTMOptions() { + return type == BuiltinOptions_UnidirectionalSequenceLSTMOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UnidirectionalSequenceLSTMOptionsT *AsUnidirectionalSequenceLSTMOptions() const { + return type == BuiltinOptions_UnidirectionalSequenceLSTMOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::FloorModOptionsT *AsFloorModOptions() { + return type == BuiltinOptions_FloorModOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::FloorModOptionsT *AsFloorModOptions() const { + return type == BuiltinOptions_FloorModOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::RangeOptionsT *AsRangeOptions() { + return type == BuiltinOptions_RangeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::RangeOptionsT *AsRangeOptions() const { + return type == BuiltinOptions_RangeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ResizeNearestNeighborOptionsT *AsResizeNearestNeighborOptions() { + return type == BuiltinOptions_ResizeNearestNeighborOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ResizeNearestNeighborOptionsT *AsResizeNearestNeighborOptions() const { + return type == BuiltinOptions_ResizeNearestNeighborOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::LeakyReluOptionsT *AsLeakyReluOptions() { + return type == BuiltinOptions_LeakyReluOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::LeakyReluOptionsT *AsLeakyReluOptions() const { + return type == BuiltinOptions_LeakyReluOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SquaredDifferenceOptionsT *AsSquaredDifferenceOptions() { + return type == BuiltinOptions_SquaredDifferenceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SquaredDifferenceOptionsT *AsSquaredDifferenceOptions() const { + return type == BuiltinOptions_SquaredDifferenceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::MirrorPadOptionsT *AsMirrorPadOptions() { + return type == BuiltinOptions_MirrorPadOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::MirrorPadOptionsT *AsMirrorPadOptions() const { + return type == BuiltinOptions_MirrorPadOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::AbsOptionsT *AsAbsOptions() { + return type == BuiltinOptions_AbsOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::AbsOptionsT *AsAbsOptions() const { + return type == BuiltinOptions_AbsOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SplitVOptionsT *AsSplitVOptions() { + return type == BuiltinOptions_SplitVOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SplitVOptionsT *AsSplitVOptions() const { + return type == BuiltinOptions_SplitVOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UniqueOptionsT *AsUniqueOptions() { + return type == BuiltinOptions_UniqueOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UniqueOptionsT *AsUniqueOptions() const { + return type == BuiltinOptions_UniqueOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ReverseV2OptionsT *AsReverseV2Options() { + return type == BuiltinOptions_ReverseV2Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::ReverseV2OptionsT *AsReverseV2Options() const { + return type == BuiltinOptions_ReverseV2Options ? + reinterpret_cast(value) : nullptr; + } + tflite::AddNOptionsT *AsAddNOptions() { + return type == BuiltinOptions_AddNOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::AddNOptionsT *AsAddNOptions() const { + return type == BuiltinOptions_AddNOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::GatherNdOptionsT *AsGatherNdOptions() { + return type == BuiltinOptions_GatherNdOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::GatherNdOptionsT *AsGatherNdOptions() const { + return type == BuiltinOptions_GatherNdOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::CosOptionsT *AsCosOptions() { + return type == BuiltinOptions_CosOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::CosOptionsT *AsCosOptions() const { + return type == BuiltinOptions_CosOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::WhereOptionsT *AsWhereOptions() { + return type == BuiltinOptions_WhereOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::WhereOptionsT *AsWhereOptions() const { + return type == BuiltinOptions_WhereOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::RankOptionsT *AsRankOptions() { + return type == BuiltinOptions_RankOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::RankOptionsT *AsRankOptions() const { + return type == BuiltinOptions_RankOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ReverseSequenceOptionsT *AsReverseSequenceOptions() { + return type == BuiltinOptions_ReverseSequenceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ReverseSequenceOptionsT *AsReverseSequenceOptions() const { + return type == BuiltinOptions_ReverseSequenceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::MatrixDiagOptionsT *AsMatrixDiagOptions() { + return type == BuiltinOptions_MatrixDiagOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::MatrixDiagOptionsT *AsMatrixDiagOptions() const { + return type == BuiltinOptions_MatrixDiagOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::QuantizeOptionsT *AsQuantizeOptions() { + return type == BuiltinOptions_QuantizeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::QuantizeOptionsT *AsQuantizeOptions() const { + return type == BuiltinOptions_QuantizeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::MatrixSetDiagOptionsT *AsMatrixSetDiagOptions() { + return type == BuiltinOptions_MatrixSetDiagOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::MatrixSetDiagOptionsT *AsMatrixSetDiagOptions() const { + return type == BuiltinOptions_MatrixSetDiagOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::HardSwishOptionsT *AsHardSwishOptions() { + return type == BuiltinOptions_HardSwishOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::HardSwishOptionsT *AsHardSwishOptions() const { + return type == BuiltinOptions_HardSwishOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::IfOptionsT *AsIfOptions() { + return type == BuiltinOptions_IfOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::IfOptionsT *AsIfOptions() const { + return type == BuiltinOptions_IfOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::WhileOptionsT *AsWhileOptions() { + return type == BuiltinOptions_WhileOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::WhileOptionsT *AsWhileOptions() const { + return type == BuiltinOptions_WhileOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::DepthToSpaceOptionsT *AsDepthToSpaceOptions() { + return type == BuiltinOptions_DepthToSpaceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::DepthToSpaceOptionsT *AsDepthToSpaceOptions() const { + return type == BuiltinOptions_DepthToSpaceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::NonMaxSuppressionV4OptionsT *AsNonMaxSuppressionV4Options() { + return type == BuiltinOptions_NonMaxSuppressionV4Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::NonMaxSuppressionV4OptionsT *AsNonMaxSuppressionV4Options() const { + return type == BuiltinOptions_NonMaxSuppressionV4Options ? + reinterpret_cast(value) : nullptr; + } + tflite::NonMaxSuppressionV5OptionsT *AsNonMaxSuppressionV5Options() { + return type == BuiltinOptions_NonMaxSuppressionV5Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::NonMaxSuppressionV5OptionsT *AsNonMaxSuppressionV5Options() const { + return type == BuiltinOptions_NonMaxSuppressionV5Options ? + reinterpret_cast(value) : nullptr; + } + tflite::ScatterNdOptionsT *AsScatterNdOptions() { + return type == BuiltinOptions_ScatterNdOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ScatterNdOptionsT *AsScatterNdOptions() const { + return type == BuiltinOptions_ScatterNdOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SelectV2OptionsT *AsSelectV2Options() { + return type == BuiltinOptions_SelectV2Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::SelectV2OptionsT *AsSelectV2Options() const { + return type == BuiltinOptions_SelectV2Options ? + reinterpret_cast(value) : nullptr; + } + tflite::DensifyOptionsT *AsDensifyOptions() { + return type == BuiltinOptions_DensifyOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::DensifyOptionsT *AsDensifyOptions() const { + return type == BuiltinOptions_DensifyOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::SegmentSumOptionsT *AsSegmentSumOptions() { + return type == BuiltinOptions_SegmentSumOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SegmentSumOptionsT *AsSegmentSumOptions() const { + return type == BuiltinOptions_SegmentSumOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::BatchMatMulOptionsT *AsBatchMatMulOptions() { + return type == BuiltinOptions_BatchMatMulOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::BatchMatMulOptionsT *AsBatchMatMulOptions() const { + return type == BuiltinOptions_BatchMatMulOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::CumsumOptionsT *AsCumsumOptions() { + return type == BuiltinOptions_CumsumOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::CumsumOptionsT *AsCumsumOptions() const { + return type == BuiltinOptions_CumsumOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::CallOnceOptionsT *AsCallOnceOptions() { + return type == BuiltinOptions_CallOnceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::CallOnceOptionsT *AsCallOnceOptions() const { + return type == BuiltinOptions_CallOnceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::BroadcastToOptionsT *AsBroadcastToOptions() { + return type == BuiltinOptions_BroadcastToOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::BroadcastToOptionsT *AsBroadcastToOptions() const { + return type == BuiltinOptions_BroadcastToOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::Rfft2dOptionsT *AsRfft2dOptions() { + return type == BuiltinOptions_Rfft2dOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::Rfft2dOptionsT *AsRfft2dOptions() const { + return type == BuiltinOptions_Rfft2dOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::Conv3DOptionsT *AsConv3DOptions() { + return type == BuiltinOptions_Conv3DOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::Conv3DOptionsT *AsConv3DOptions() const { + return type == BuiltinOptions_Conv3DOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::HashtableOptionsT *AsHashtableOptions() { + return type == BuiltinOptions_HashtableOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::HashtableOptionsT *AsHashtableOptions() const { + return type == BuiltinOptions_HashtableOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::HashtableFindOptionsT *AsHashtableFindOptions() { + return type == BuiltinOptions_HashtableFindOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::HashtableFindOptionsT *AsHashtableFindOptions() const { + return type == BuiltinOptions_HashtableFindOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::HashtableImportOptionsT *AsHashtableImportOptions() { + return type == BuiltinOptions_HashtableImportOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::HashtableImportOptionsT *AsHashtableImportOptions() const { + return type == BuiltinOptions_HashtableImportOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::HashtableSizeOptionsT *AsHashtableSizeOptions() { + return type == BuiltinOptions_HashtableSizeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::HashtableSizeOptionsT *AsHashtableSizeOptions() const { + return type == BuiltinOptions_HashtableSizeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::VarHandleOptionsT *AsVarHandleOptions() { + return type == BuiltinOptions_VarHandleOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::VarHandleOptionsT *AsVarHandleOptions() const { + return type == BuiltinOptions_VarHandleOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ReadVariableOptionsT *AsReadVariableOptions() { + return type == BuiltinOptions_ReadVariableOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::ReadVariableOptionsT *AsReadVariableOptions() const { + return type == BuiltinOptions_ReadVariableOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::AssignVariableOptionsT *AsAssignVariableOptions() { + return type == BuiltinOptions_AssignVariableOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::AssignVariableOptionsT *AsAssignVariableOptions() const { + return type == BuiltinOptions_AssignVariableOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::RandomOptionsT *AsRandomOptions() { + return type == BuiltinOptions_RandomOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::RandomOptionsT *AsRandomOptions() const { + return type == BuiltinOptions_RandomOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::BucketizeOptionsT *AsBucketizeOptions() { + return type == BuiltinOptions_BucketizeOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::BucketizeOptionsT *AsBucketizeOptions() const { + return type == BuiltinOptions_BucketizeOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::GeluOptionsT *AsGeluOptions() { + return type == BuiltinOptions_GeluOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::GeluOptionsT *AsGeluOptions() const { + return type == BuiltinOptions_GeluOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::DynamicUpdateSliceOptionsT *AsDynamicUpdateSliceOptions() { + return type == BuiltinOptions_DynamicUpdateSliceOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::DynamicUpdateSliceOptionsT *AsDynamicUpdateSliceOptions() const { + return type == BuiltinOptions_DynamicUpdateSliceOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UnsortedSegmentProdOptionsT *AsUnsortedSegmentProdOptions() { + return type == BuiltinOptions_UnsortedSegmentProdOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UnsortedSegmentProdOptionsT *AsUnsortedSegmentProdOptions() const { + return type == BuiltinOptions_UnsortedSegmentProdOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UnsortedSegmentMaxOptionsT *AsUnsortedSegmentMaxOptions() { + return type == BuiltinOptions_UnsortedSegmentMaxOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UnsortedSegmentMaxOptionsT *AsUnsortedSegmentMaxOptions() const { + return type == BuiltinOptions_UnsortedSegmentMaxOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UnsortedSegmentMinOptionsT *AsUnsortedSegmentMinOptions() { + return type == BuiltinOptions_UnsortedSegmentMinOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UnsortedSegmentMinOptionsT *AsUnsortedSegmentMinOptions() const { + return type == BuiltinOptions_UnsortedSegmentMinOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::UnsortedSegmentSumOptionsT *AsUnsortedSegmentSumOptions() { + return type == BuiltinOptions_UnsortedSegmentSumOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::UnsortedSegmentSumOptionsT *AsUnsortedSegmentSumOptions() const { + return type == BuiltinOptions_UnsortedSegmentSumOptions ? + reinterpret_cast(value) : nullptr; + } + tflite::ATan2OptionsT *AsATan2Options() { + return type == BuiltinOptions_ATan2Options ? + reinterpret_cast(value) : nullptr; + } + const tflite::ATan2OptionsT *AsATan2Options() const { + return type == BuiltinOptions_ATan2Options ? + reinterpret_cast(value) : nullptr; + } + tflite::SignOptionsT *AsSignOptions() { + return type == BuiltinOptions_SignOptions ? + reinterpret_cast(value) : nullptr; + } + const tflite::SignOptionsT *AsSignOptions() const { + return type == BuiltinOptions_SignOptions ? + reinterpret_cast(value) : nullptr; + } +}; + +bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type); +bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types); + +enum Padding : int8_t { + Padding_SAME = 0, + Padding_VALID = 1, + Padding_MIN = Padding_SAME, + Padding_MAX = Padding_VALID +}; + +inline const Padding (&EnumValuesPadding())[2] { + static const Padding values[] = { + Padding_SAME, + Padding_VALID + }; + return values; +} + +inline const char * const *EnumNamesPadding() { + static const char * const names[3] = { + "SAME", + "VALID", + nullptr + }; + return names; +} + +inline const char *EnumNamePadding(Padding e) { + if (flatbuffers::IsOutRange(e, Padding_SAME, Padding_VALID)) return ""; + const size_t index = static_cast(e); + return EnumNamesPadding()[index]; +} + +enum ActivationFunctionType : int8_t { + ActivationFunctionType_NONE = 0, + ActivationFunctionType_RELU = 1, + ActivationFunctionType_RELU_N1_TO_1 = 2, + ActivationFunctionType_RELU6 = 3, + ActivationFunctionType_TANH = 4, + ActivationFunctionType_SIGN_BIT = 5, + ActivationFunctionType_MIN = ActivationFunctionType_NONE, + ActivationFunctionType_MAX = ActivationFunctionType_SIGN_BIT +}; + +inline const ActivationFunctionType (&EnumValuesActivationFunctionType())[6] { + static const ActivationFunctionType values[] = { + ActivationFunctionType_NONE, + ActivationFunctionType_RELU, + ActivationFunctionType_RELU_N1_TO_1, + ActivationFunctionType_RELU6, + ActivationFunctionType_TANH, + ActivationFunctionType_SIGN_BIT + }; + return values; +} + +inline const char * const *EnumNamesActivationFunctionType() { + static const char * const names[7] = { + "NONE", + "RELU", + "RELU_N1_TO_1", + "RELU6", + "TANH", + "SIGN_BIT", + nullptr + }; + return names; +} + +inline const char *EnumNameActivationFunctionType(ActivationFunctionType e) { + if (flatbuffers::IsOutRange(e, ActivationFunctionType_NONE, ActivationFunctionType_SIGN_BIT)) return ""; + const size_t index = static_cast(e); + return EnumNamesActivationFunctionType()[index]; +} + +enum LSHProjectionType : int8_t { + LSHProjectionType_UNKNOWN = 0, + LSHProjectionType_SPARSE = 1, + LSHProjectionType_DENSE = 2, + LSHProjectionType_MIN = LSHProjectionType_UNKNOWN, + LSHProjectionType_MAX = LSHProjectionType_DENSE +}; + +inline const LSHProjectionType (&EnumValuesLSHProjectionType())[3] { + static const LSHProjectionType values[] = { + LSHProjectionType_UNKNOWN, + LSHProjectionType_SPARSE, + LSHProjectionType_DENSE + }; + return values; +} + +inline const char * const *EnumNamesLSHProjectionType() { + static const char * const names[4] = { + "UNKNOWN", + "SPARSE", + "DENSE", + nullptr + }; + return names; +} + +inline const char *EnumNameLSHProjectionType(LSHProjectionType e) { + if (flatbuffers::IsOutRange(e, LSHProjectionType_UNKNOWN, LSHProjectionType_DENSE)) return ""; + const size_t index = static_cast(e); + return EnumNamesLSHProjectionType()[index]; +} + +enum FullyConnectedOptionsWeightsFormat : int8_t { + FullyConnectedOptionsWeightsFormat_DEFAULT = 0, + FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 = 1, + FullyConnectedOptionsWeightsFormat_MIN = FullyConnectedOptionsWeightsFormat_DEFAULT, + FullyConnectedOptionsWeightsFormat_MAX = FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 +}; + +inline const FullyConnectedOptionsWeightsFormat (&EnumValuesFullyConnectedOptionsWeightsFormat())[2] { + static const FullyConnectedOptionsWeightsFormat values[] = { + FullyConnectedOptionsWeightsFormat_DEFAULT, + FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 + }; + return values; +} + +inline const char * const *EnumNamesFullyConnectedOptionsWeightsFormat() { + static const char * const names[3] = { + "DEFAULT", + "SHUFFLED4x16INT8", + nullptr + }; + return names; +} + +inline const char *EnumNameFullyConnectedOptionsWeightsFormat(FullyConnectedOptionsWeightsFormat e) { + if (flatbuffers::IsOutRange(e, FullyConnectedOptionsWeightsFormat_DEFAULT, FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8)) return ""; + const size_t index = static_cast(e); + return EnumNamesFullyConnectedOptionsWeightsFormat()[index]; +} + +enum LSTMKernelType : int8_t { + LSTMKernelType_FULL = 0, + LSTMKernelType_BASIC = 1, + LSTMKernelType_MIN = LSTMKernelType_FULL, + LSTMKernelType_MAX = LSTMKernelType_BASIC +}; + +inline const LSTMKernelType (&EnumValuesLSTMKernelType())[2] { + static const LSTMKernelType values[] = { + LSTMKernelType_FULL, + LSTMKernelType_BASIC + }; + return values; +} + +inline const char * const *EnumNamesLSTMKernelType() { + static const char * const names[3] = { + "FULL", + "BASIC", + nullptr + }; + return names; +} + +inline const char *EnumNameLSTMKernelType(LSTMKernelType e) { + if (flatbuffers::IsOutRange(e, LSTMKernelType_FULL, LSTMKernelType_BASIC)) return ""; + const size_t index = static_cast(e); + return EnumNamesLSTMKernelType()[index]; +} + +enum CombinerType : int8_t { + CombinerType_SUM = 0, + CombinerType_MEAN = 1, + CombinerType_SQRTN = 2, + CombinerType_MIN = CombinerType_SUM, + CombinerType_MAX = CombinerType_SQRTN +}; + +inline const CombinerType (&EnumValuesCombinerType())[3] { + static const CombinerType values[] = { + CombinerType_SUM, + CombinerType_MEAN, + CombinerType_SQRTN + }; + return values; +} + +inline const char * const *EnumNamesCombinerType() { + static const char * const names[4] = { + "SUM", + "MEAN", + "SQRTN", + nullptr + }; + return names; +} + +inline const char *EnumNameCombinerType(CombinerType e) { + if (flatbuffers::IsOutRange(e, CombinerType_SUM, CombinerType_SQRTN)) return ""; + const size_t index = static_cast(e); + return EnumNamesCombinerType()[index]; +} + +enum MirrorPadMode : int8_t { + MirrorPadMode_REFLECT = 0, + MirrorPadMode_SYMMETRIC = 1, + MirrorPadMode_MIN = MirrorPadMode_REFLECT, + MirrorPadMode_MAX = MirrorPadMode_SYMMETRIC +}; + +inline const MirrorPadMode (&EnumValuesMirrorPadMode())[2] { + static const MirrorPadMode values[] = { + MirrorPadMode_REFLECT, + MirrorPadMode_SYMMETRIC + }; + return values; +} + +inline const char * const *EnumNamesMirrorPadMode() { + static const char * const names[3] = { + "REFLECT", + "SYMMETRIC", + nullptr + }; + return names; +} + +inline const char *EnumNameMirrorPadMode(MirrorPadMode e) { + if (flatbuffers::IsOutRange(e, MirrorPadMode_REFLECT, MirrorPadMode_SYMMETRIC)) return ""; + const size_t index = static_cast(e); + return EnumNamesMirrorPadMode()[index]; +} + +enum CustomOptionsFormat : int8_t { + CustomOptionsFormat_FLEXBUFFERS = 0, + CustomOptionsFormat_MIN = CustomOptionsFormat_FLEXBUFFERS, + CustomOptionsFormat_MAX = CustomOptionsFormat_FLEXBUFFERS +}; + +inline const CustomOptionsFormat (&EnumValuesCustomOptionsFormat())[1] { + static const CustomOptionsFormat values[] = { + CustomOptionsFormat_FLEXBUFFERS + }; + return values; +} + +inline const char * const *EnumNamesCustomOptionsFormat() { + static const char * const names[2] = { + "FLEXBUFFERS", + nullptr + }; + return names; +} + +inline const char *EnumNameCustomOptionsFormat(CustomOptionsFormat e) { + if (flatbuffers::IsOutRange(e, CustomOptionsFormat_FLEXBUFFERS, CustomOptionsFormat_FLEXBUFFERS)) return ""; + const size_t index = static_cast(e); + return EnumNamesCustomOptionsFormat()[index]; +} + +struct CustomQuantizationT : public flatbuffers::NativeTable { + typedef CustomQuantization TableType; + std::vector custom{}; +}; + +struct CustomQuantization FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CustomQuantizationT NativeTableType; + typedef CustomQuantizationBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_CUSTOM = 4 + }; + const flatbuffers::Vector *custom() const { + return GetPointer *>(VT_CUSTOM); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_CUSTOM) && + verifier.VerifyVector(custom()) && + verifier.EndTable(); + } + CustomQuantizationT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CustomQuantizationT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const CustomQuantizationT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CustomQuantizationBuilder { + typedef CustomQuantization Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_custom(flatbuffers::Offset> custom) { + fbb_.AddOffset(CustomQuantization::VT_CUSTOM, custom); + } + explicit CustomQuantizationBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCustomQuantization( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> custom = 0) { + CustomQuantizationBuilder builder_(_fbb); + builder_.add_custom(custom); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateCustomQuantizationDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *custom = nullptr) { + if (custom) { _fbb.ForceVectorAlignment(custom->size(), sizeof(uint8_t), 16); } + auto custom__ = custom ? _fbb.CreateVector(*custom) : 0; + return tflite::CreateCustomQuantization( + _fbb, + custom__); +} + +flatbuffers::Offset CreateCustomQuantization(flatbuffers::FlatBufferBuilder &_fbb, const CustomQuantizationT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct QuantizationParametersT : public flatbuffers::NativeTable { + typedef QuantizationParameters TableType; + std::vector min{}; + std::vector max{}; + std::vector scale{}; + std::vector zero_point{}; + tflite::QuantizationDetailsUnion details{}; + int32_t quantized_dimension = 0; +}; + +struct QuantizationParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef QuantizationParametersT NativeTableType; + typedef QuantizationParametersBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_MIN = 4, + VT_MAX = 6, + VT_SCALE = 8, + VT_ZERO_POINT = 10, + VT_DETAILS_TYPE = 12, + VT_DETAILS = 14, + VT_QUANTIZED_DIMENSION = 16 + }; + const flatbuffers::Vector *min() const { + return GetPointer *>(VT_MIN); + } + const flatbuffers::Vector *max() const { + return GetPointer *>(VT_MAX); + } + const flatbuffers::Vector *scale() const { + return GetPointer *>(VT_SCALE); + } + const flatbuffers::Vector *zero_point() const { + return GetPointer *>(VT_ZERO_POINT); + } + tflite::QuantizationDetails details_type() const { + return static_cast(GetField(VT_DETAILS_TYPE, 0)); + } + const void *details() const { + return GetPointer(VT_DETAILS); + } + template const T *details_as() const; + const tflite::CustomQuantization *details_as_CustomQuantization() const { + return details_type() == tflite::QuantizationDetails_CustomQuantization ? static_cast(details()) : nullptr; + } + int32_t quantized_dimension() const { + return GetField(VT_QUANTIZED_DIMENSION, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_MIN) && + verifier.VerifyVector(min()) && + VerifyOffset(verifier, VT_MAX) && + verifier.VerifyVector(max()) && + VerifyOffset(verifier, VT_SCALE) && + verifier.VerifyVector(scale()) && + VerifyOffset(verifier, VT_ZERO_POINT) && + verifier.VerifyVector(zero_point()) && + VerifyField(verifier, VT_DETAILS_TYPE, 1) && + VerifyOffset(verifier, VT_DETAILS) && + VerifyQuantizationDetails(verifier, details(), details_type()) && + VerifyField(verifier, VT_QUANTIZED_DIMENSION, 4) && + verifier.EndTable(); + } + QuantizationParametersT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(QuantizationParametersT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const QuantizationParametersT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +template<> inline const tflite::CustomQuantization *QuantizationParameters::details_as() const { + return details_as_CustomQuantization(); +} + +struct QuantizationParametersBuilder { + typedef QuantizationParameters Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_min(flatbuffers::Offset> min) { + fbb_.AddOffset(QuantizationParameters::VT_MIN, min); + } + void add_max(flatbuffers::Offset> max) { + fbb_.AddOffset(QuantizationParameters::VT_MAX, max); + } + void add_scale(flatbuffers::Offset> scale) { + fbb_.AddOffset(QuantizationParameters::VT_SCALE, scale); + } + void add_zero_point(flatbuffers::Offset> zero_point) { + fbb_.AddOffset(QuantizationParameters::VT_ZERO_POINT, zero_point); + } + void add_details_type(tflite::QuantizationDetails details_type) { + fbb_.AddElement(QuantizationParameters::VT_DETAILS_TYPE, static_cast(details_type), 0); + } + void add_details(flatbuffers::Offset details) { + fbb_.AddOffset(QuantizationParameters::VT_DETAILS, details); + } + void add_quantized_dimension(int32_t quantized_dimension) { + fbb_.AddElement(QuantizationParameters::VT_QUANTIZED_DIMENSION, quantized_dimension, 0); + } + explicit QuantizationParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateQuantizationParameters( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> min = 0, + flatbuffers::Offset> max = 0, + flatbuffers::Offset> scale = 0, + flatbuffers::Offset> zero_point = 0, + tflite::QuantizationDetails details_type = tflite::QuantizationDetails_NONE, + flatbuffers::Offset details = 0, + int32_t quantized_dimension = 0) { + QuantizationParametersBuilder builder_(_fbb); + builder_.add_quantized_dimension(quantized_dimension); + builder_.add_details(details); + builder_.add_zero_point(zero_point); + builder_.add_scale(scale); + builder_.add_max(max); + builder_.add_min(min); + builder_.add_details_type(details_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateQuantizationParametersDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *min = nullptr, + const std::vector *max = nullptr, + const std::vector *scale = nullptr, + const std::vector *zero_point = nullptr, + tflite::QuantizationDetails details_type = tflite::QuantizationDetails_NONE, + flatbuffers::Offset details = 0, + int32_t quantized_dimension = 0) { + auto min__ = min ? _fbb.CreateVector(*min) : 0; + auto max__ = max ? _fbb.CreateVector(*max) : 0; + auto scale__ = scale ? _fbb.CreateVector(*scale) : 0; + auto zero_point__ = zero_point ? _fbb.CreateVector(*zero_point) : 0; + return tflite::CreateQuantizationParameters( + _fbb, + min__, + max__, + scale__, + zero_point__, + details_type, + details, + quantized_dimension); +} + +flatbuffers::Offset CreateQuantizationParameters(flatbuffers::FlatBufferBuilder &_fbb, const QuantizationParametersT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Int32VectorT : public flatbuffers::NativeTable { + typedef Int32Vector TableType; + std::vector values{}; +}; + +struct Int32Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Int32VectorT NativeTableType; + typedef Int32VectorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && + verifier.EndTable(); + } + Int32VectorT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Int32VectorT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Int32VectorT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Int32VectorBuilder { + typedef Int32Vector Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) { + fbb_.AddOffset(Int32Vector::VT_VALUES, values); + } + explicit Int32VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateInt32Vector( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) { + Int32VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateInt32VectorDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) { + auto values__ = values ? _fbb.CreateVector(*values) : 0; + return tflite::CreateInt32Vector( + _fbb, + values__); +} + +flatbuffers::Offset CreateInt32Vector(flatbuffers::FlatBufferBuilder &_fbb, const Int32VectorT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Uint16VectorT : public flatbuffers::NativeTable { + typedef Uint16Vector TableType; + std::vector values{}; +}; + +struct Uint16Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Uint16VectorT NativeTableType; + typedef Uint16VectorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && + verifier.EndTable(); + } + Uint16VectorT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Uint16VectorT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Uint16VectorT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Uint16VectorBuilder { + typedef Uint16Vector Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) { + fbb_.AddOffset(Uint16Vector::VT_VALUES, values); + } + explicit Uint16VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUint16Vector( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) { + Uint16VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateUint16VectorDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) { + if (values) { _fbb.ForceVectorAlignment(values->size(), sizeof(uint16_t), 4); } + auto values__ = values ? _fbb.CreateVector(*values) : 0; + return tflite::CreateUint16Vector( + _fbb, + values__); +} + +flatbuffers::Offset CreateUint16Vector(flatbuffers::FlatBufferBuilder &_fbb, const Uint16VectorT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Uint8VectorT : public flatbuffers::NativeTable { + typedef Uint8Vector TableType; + std::vector values{}; +}; + +struct Uint8Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Uint8VectorT NativeTableType; + typedef Uint8VectorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && + verifier.EndTable(); + } + Uint8VectorT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Uint8VectorT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Uint8VectorT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Uint8VectorBuilder { + typedef Uint8Vector Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) { + fbb_.AddOffset(Uint8Vector::VT_VALUES, values); + } + explicit Uint8VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUint8Vector( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) { + Uint8VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateUint8VectorDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) { + if (values) { _fbb.ForceVectorAlignment(values->size(), sizeof(uint8_t), 4); } + auto values__ = values ? _fbb.CreateVector(*values) : 0; + return tflite::CreateUint8Vector( + _fbb, + values__); +} + +flatbuffers::Offset CreateUint8Vector(flatbuffers::FlatBufferBuilder &_fbb, const Uint8VectorT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DimensionMetadataT : public flatbuffers::NativeTable { + typedef DimensionMetadata TableType; + tflite::DimensionType format = tflite::DimensionType_DENSE; + int32_t dense_size = 0; + tflite::SparseIndexVectorUnion array_segments{}; + tflite::SparseIndexVectorUnion array_indices{}; +}; + +struct DimensionMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DimensionMetadataT NativeTableType; + typedef DimensionMetadataBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FORMAT = 4, + VT_DENSE_SIZE = 6, + VT_ARRAY_SEGMENTS_TYPE = 8, + VT_ARRAY_SEGMENTS = 10, + VT_ARRAY_INDICES_TYPE = 12, + VT_ARRAY_INDICES = 14 + }; + tflite::DimensionType format() const { + return static_cast(GetField(VT_FORMAT, 0)); + } + int32_t dense_size() const { + return GetField(VT_DENSE_SIZE, 0); + } + tflite::SparseIndexVector array_segments_type() const { + return static_cast(GetField(VT_ARRAY_SEGMENTS_TYPE, 0)); + } + const void *array_segments() const { + return GetPointer(VT_ARRAY_SEGMENTS); + } + template const T *array_segments_as() const; + const tflite::Int32Vector *array_segments_as_Int32Vector() const { + return array_segments_type() == tflite::SparseIndexVector_Int32Vector ? static_cast(array_segments()) : nullptr; + } + const tflite::Uint16Vector *array_segments_as_Uint16Vector() const { + return array_segments_type() == tflite::SparseIndexVector_Uint16Vector ? static_cast(array_segments()) : nullptr; + } + const tflite::Uint8Vector *array_segments_as_Uint8Vector() const { + return array_segments_type() == tflite::SparseIndexVector_Uint8Vector ? static_cast(array_segments()) : nullptr; + } + tflite::SparseIndexVector array_indices_type() const { + return static_cast(GetField(VT_ARRAY_INDICES_TYPE, 0)); + } + const void *array_indices() const { + return GetPointer(VT_ARRAY_INDICES); + } + template const T *array_indices_as() const; + const tflite::Int32Vector *array_indices_as_Int32Vector() const { + return array_indices_type() == tflite::SparseIndexVector_Int32Vector ? static_cast(array_indices()) : nullptr; + } + const tflite::Uint16Vector *array_indices_as_Uint16Vector() const { + return array_indices_type() == tflite::SparseIndexVector_Uint16Vector ? static_cast(array_indices()) : nullptr; + } + const tflite::Uint8Vector *array_indices_as_Uint8Vector() const { + return array_indices_type() == tflite::SparseIndexVector_Uint8Vector ? static_cast(array_indices()) : nullptr; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FORMAT, 1) && + VerifyField(verifier, VT_DENSE_SIZE, 4) && + VerifyField(verifier, VT_ARRAY_SEGMENTS_TYPE, 1) && + VerifyOffset(verifier, VT_ARRAY_SEGMENTS) && + VerifySparseIndexVector(verifier, array_segments(), array_segments_type()) && + VerifyField(verifier, VT_ARRAY_INDICES_TYPE, 1) && + VerifyOffset(verifier, VT_ARRAY_INDICES) && + VerifySparseIndexVector(verifier, array_indices(), array_indices_type()) && + verifier.EndTable(); + } + DimensionMetadataT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DimensionMetadataT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DimensionMetadataT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +template<> inline const tflite::Int32Vector *DimensionMetadata::array_segments_as() const { + return array_segments_as_Int32Vector(); +} + +template<> inline const tflite::Uint16Vector *DimensionMetadata::array_segments_as() const { + return array_segments_as_Uint16Vector(); +} + +template<> inline const tflite::Uint8Vector *DimensionMetadata::array_segments_as() const { + return array_segments_as_Uint8Vector(); +} + +template<> inline const tflite::Int32Vector *DimensionMetadata::array_indices_as() const { + return array_indices_as_Int32Vector(); +} + +template<> inline const tflite::Uint16Vector *DimensionMetadata::array_indices_as() const { + return array_indices_as_Uint16Vector(); +} + +template<> inline const tflite::Uint8Vector *DimensionMetadata::array_indices_as() const { + return array_indices_as_Uint8Vector(); +} + +struct DimensionMetadataBuilder { + typedef DimensionMetadata Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_format(tflite::DimensionType format) { + fbb_.AddElement(DimensionMetadata::VT_FORMAT, static_cast(format), 0); + } + void add_dense_size(int32_t dense_size) { + fbb_.AddElement(DimensionMetadata::VT_DENSE_SIZE, dense_size, 0); + } + void add_array_segments_type(tflite::SparseIndexVector array_segments_type) { + fbb_.AddElement(DimensionMetadata::VT_ARRAY_SEGMENTS_TYPE, static_cast(array_segments_type), 0); + } + void add_array_segments(flatbuffers::Offset array_segments) { + fbb_.AddOffset(DimensionMetadata::VT_ARRAY_SEGMENTS, array_segments); + } + void add_array_indices_type(tflite::SparseIndexVector array_indices_type) { + fbb_.AddElement(DimensionMetadata::VT_ARRAY_INDICES_TYPE, static_cast(array_indices_type), 0); + } + void add_array_indices(flatbuffers::Offset array_indices) { + fbb_.AddOffset(DimensionMetadata::VT_ARRAY_INDICES, array_indices); + } + explicit DimensionMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDimensionMetadata( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::DimensionType format = tflite::DimensionType_DENSE, + int32_t dense_size = 0, + tflite::SparseIndexVector array_segments_type = tflite::SparseIndexVector_NONE, + flatbuffers::Offset array_segments = 0, + tflite::SparseIndexVector array_indices_type = tflite::SparseIndexVector_NONE, + flatbuffers::Offset array_indices = 0) { + DimensionMetadataBuilder builder_(_fbb); + builder_.add_array_indices(array_indices); + builder_.add_array_segments(array_segments); + builder_.add_dense_size(dense_size); + builder_.add_array_indices_type(array_indices_type); + builder_.add_array_segments_type(array_segments_type); + builder_.add_format(format); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDimensionMetadata(flatbuffers::FlatBufferBuilder &_fbb, const DimensionMetadataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SparsityParametersT : public flatbuffers::NativeTable { + typedef SparsityParameters TableType; + std::vector traversal_order{}; + std::vector block_map{}; + std::vector> dim_metadata{}; + SparsityParametersT() = default; + SparsityParametersT(const SparsityParametersT &o); + SparsityParametersT(SparsityParametersT&&) FLATBUFFERS_NOEXCEPT = default; + SparsityParametersT &operator=(SparsityParametersT o) FLATBUFFERS_NOEXCEPT; +}; + +struct SparsityParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SparsityParametersT NativeTableType; + typedef SparsityParametersBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TRAVERSAL_ORDER = 4, + VT_BLOCK_MAP = 6, + VT_DIM_METADATA = 8 + }; + const flatbuffers::Vector *traversal_order() const { + return GetPointer *>(VT_TRAVERSAL_ORDER); + } + const flatbuffers::Vector *block_map() const { + return GetPointer *>(VT_BLOCK_MAP); + } + const flatbuffers::Vector> *dim_metadata() const { + return GetPointer> *>(VT_DIM_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_TRAVERSAL_ORDER) && + verifier.VerifyVector(traversal_order()) && + VerifyOffset(verifier, VT_BLOCK_MAP) && + verifier.VerifyVector(block_map()) && + VerifyOffset(verifier, VT_DIM_METADATA) && + verifier.VerifyVector(dim_metadata()) && + verifier.VerifyVectorOfTables(dim_metadata()) && + verifier.EndTable(); + } + SparsityParametersT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SparsityParametersT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SparsityParametersT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SparsityParametersBuilder { + typedef SparsityParameters Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_traversal_order(flatbuffers::Offset> traversal_order) { + fbb_.AddOffset(SparsityParameters::VT_TRAVERSAL_ORDER, traversal_order); + } + void add_block_map(flatbuffers::Offset> block_map) { + fbb_.AddOffset(SparsityParameters::VT_BLOCK_MAP, block_map); + } + void add_dim_metadata(flatbuffers::Offset>> dim_metadata) { + fbb_.AddOffset(SparsityParameters::VT_DIM_METADATA, dim_metadata); + } + explicit SparsityParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSparsityParameters( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> traversal_order = 0, + flatbuffers::Offset> block_map = 0, + flatbuffers::Offset>> dim_metadata = 0) { + SparsityParametersBuilder builder_(_fbb); + builder_.add_dim_metadata(dim_metadata); + builder_.add_block_map(block_map); + builder_.add_traversal_order(traversal_order); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSparsityParametersDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *traversal_order = nullptr, + const std::vector *block_map = nullptr, + const std::vector> *dim_metadata = nullptr) { + auto traversal_order__ = traversal_order ? _fbb.CreateVector(*traversal_order) : 0; + auto block_map__ = block_map ? _fbb.CreateVector(*block_map) : 0; + auto dim_metadata__ = dim_metadata ? _fbb.CreateVector>(*dim_metadata) : 0; + return tflite::CreateSparsityParameters( + _fbb, + traversal_order__, + block_map__, + dim_metadata__); +} + +flatbuffers::Offset CreateSparsityParameters(flatbuffers::FlatBufferBuilder &_fbb, const SparsityParametersT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct VariantSubTypeT : public flatbuffers::NativeTable { + typedef VariantSubType TableType; + std::vector shape{}; + tflite::TensorType type = tflite::TensorType_FLOAT32; + bool has_rank = false; +}; + +struct VariantSubType FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef VariantSubTypeT NativeTableType; + typedef VariantSubTypeBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SHAPE = 4, + VT_TYPE = 6, + VT_HAS_RANK = 8 + }; + const flatbuffers::Vector *shape() const { + return GetPointer *>(VT_SHAPE); + } + tflite::TensorType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + bool has_rank() const { + return GetField(VT_HAS_RANK, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_SHAPE) && + verifier.VerifyVector(shape()) && + VerifyField(verifier, VT_TYPE, 1) && + VerifyField(verifier, VT_HAS_RANK, 1) && + verifier.EndTable(); + } + VariantSubTypeT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(VariantSubTypeT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const VariantSubTypeT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct VariantSubTypeBuilder { + typedef VariantSubType Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_shape(flatbuffers::Offset> shape) { + fbb_.AddOffset(VariantSubType::VT_SHAPE, shape); + } + void add_type(tflite::TensorType type) { + fbb_.AddElement(VariantSubType::VT_TYPE, static_cast(type), 0); + } + void add_has_rank(bool has_rank) { + fbb_.AddElement(VariantSubType::VT_HAS_RANK, static_cast(has_rank), 0); + } + explicit VariantSubTypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateVariantSubType( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> shape = 0, + tflite::TensorType type = tflite::TensorType_FLOAT32, + bool has_rank = false) { + VariantSubTypeBuilder builder_(_fbb); + builder_.add_shape(shape); + builder_.add_has_rank(has_rank); + builder_.add_type(type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateVariantSubTypeDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *shape = nullptr, + tflite::TensorType type = tflite::TensorType_FLOAT32, + bool has_rank = false) { + auto shape__ = shape ? _fbb.CreateVector(*shape) : 0; + return tflite::CreateVariantSubType( + _fbb, + shape__, + type, + has_rank); +} + +flatbuffers::Offset CreateVariantSubType(flatbuffers::FlatBufferBuilder &_fbb, const VariantSubTypeT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TensorT : public flatbuffers::NativeTable { + typedef Tensor TableType; + std::vector shape{}; + tflite::TensorType type = tflite::TensorType_FLOAT32; + uint32_t buffer = 0; + std::string name{}; + std::unique_ptr quantization{}; + bool is_variable = false; + std::unique_ptr sparsity{}; + std::vector shape_signature{}; + bool has_rank = false; + std::vector> variant_tensors{}; + TensorT() = default; + TensorT(const TensorT &o); + TensorT(TensorT&&) FLATBUFFERS_NOEXCEPT = default; + TensorT &operator=(TensorT o) FLATBUFFERS_NOEXCEPT; +}; + +struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TensorT NativeTableType; + typedef TensorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SHAPE = 4, + VT_TYPE = 6, + VT_BUFFER = 8, + VT_NAME = 10, + VT_QUANTIZATION = 12, + VT_IS_VARIABLE = 14, + VT_SPARSITY = 16, + VT_SHAPE_SIGNATURE = 18, + VT_HAS_RANK = 20, + VT_VARIANT_TENSORS = 22 + }; + const flatbuffers::Vector *shape() const { + return GetPointer *>(VT_SHAPE); + } + tflite::TensorType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + uint32_t buffer() const { + return GetField(VT_BUFFER, 0); + } + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + const tflite::QuantizationParameters *quantization() const { + return GetPointer(VT_QUANTIZATION); + } + bool is_variable() const { + return GetField(VT_IS_VARIABLE, 0) != 0; + } + const tflite::SparsityParameters *sparsity() const { + return GetPointer(VT_SPARSITY); + } + const flatbuffers::Vector *shape_signature() const { + return GetPointer *>(VT_SHAPE_SIGNATURE); + } + bool has_rank() const { + return GetField(VT_HAS_RANK, 0) != 0; + } + const flatbuffers::Vector> *variant_tensors() const { + return GetPointer> *>(VT_VARIANT_TENSORS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_SHAPE) && + verifier.VerifyVector(shape()) && + VerifyField(verifier, VT_TYPE, 1) && + VerifyField(verifier, VT_BUFFER, 4) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_QUANTIZATION) && + verifier.VerifyTable(quantization()) && + VerifyField(verifier, VT_IS_VARIABLE, 1) && + VerifyOffset(verifier, VT_SPARSITY) && + verifier.VerifyTable(sparsity()) && + VerifyOffset(verifier, VT_SHAPE_SIGNATURE) && + verifier.VerifyVector(shape_signature()) && + VerifyField(verifier, VT_HAS_RANK, 1) && + VerifyOffset(verifier, VT_VARIANT_TENSORS) && + verifier.VerifyVector(variant_tensors()) && + verifier.VerifyVectorOfTables(variant_tensors()) && + verifier.EndTable(); + } + TensorT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TensorT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TensorT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TensorBuilder { + typedef Tensor Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_shape(flatbuffers::Offset> shape) { + fbb_.AddOffset(Tensor::VT_SHAPE, shape); + } + void add_type(tflite::TensorType type) { + fbb_.AddElement(Tensor::VT_TYPE, static_cast(type), 0); + } + void add_buffer(uint32_t buffer) { + fbb_.AddElement(Tensor::VT_BUFFER, buffer, 0); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Tensor::VT_NAME, name); + } + void add_quantization(flatbuffers::Offset quantization) { + fbb_.AddOffset(Tensor::VT_QUANTIZATION, quantization); + } + void add_is_variable(bool is_variable) { + fbb_.AddElement(Tensor::VT_IS_VARIABLE, static_cast(is_variable), 0); + } + void add_sparsity(flatbuffers::Offset sparsity) { + fbb_.AddOffset(Tensor::VT_SPARSITY, sparsity); + } + void add_shape_signature(flatbuffers::Offset> shape_signature) { + fbb_.AddOffset(Tensor::VT_SHAPE_SIGNATURE, shape_signature); + } + void add_has_rank(bool has_rank) { + fbb_.AddElement(Tensor::VT_HAS_RANK, static_cast(has_rank), 0); + } + void add_variant_tensors(flatbuffers::Offset>> variant_tensors) { + fbb_.AddOffset(Tensor::VT_VARIANT_TENSORS, variant_tensors); + } + explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTensor( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> shape = 0, + tflite::TensorType type = tflite::TensorType_FLOAT32, + uint32_t buffer = 0, + flatbuffers::Offset name = 0, + flatbuffers::Offset quantization = 0, + bool is_variable = false, + flatbuffers::Offset sparsity = 0, + flatbuffers::Offset> shape_signature = 0, + bool has_rank = false, + flatbuffers::Offset>> variant_tensors = 0) { + TensorBuilder builder_(_fbb); + builder_.add_variant_tensors(variant_tensors); + builder_.add_shape_signature(shape_signature); + builder_.add_sparsity(sparsity); + builder_.add_quantization(quantization); + builder_.add_name(name); + builder_.add_buffer(buffer); + builder_.add_shape(shape); + builder_.add_has_rank(has_rank); + builder_.add_is_variable(is_variable); + builder_.add_type(type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateTensorDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *shape = nullptr, + tflite::TensorType type = tflite::TensorType_FLOAT32, + uint32_t buffer = 0, + const char *name = nullptr, + flatbuffers::Offset quantization = 0, + bool is_variable = false, + flatbuffers::Offset sparsity = 0, + const std::vector *shape_signature = nullptr, + bool has_rank = false, + const std::vector> *variant_tensors = nullptr) { + auto shape__ = shape ? _fbb.CreateVector(*shape) : 0; + auto name__ = name ? _fbb.CreateString(name) : 0; + auto shape_signature__ = shape_signature ? _fbb.CreateVector(*shape_signature) : 0; + auto variant_tensors__ = variant_tensors ? _fbb.CreateVector>(*variant_tensors) : 0; + return tflite::CreateTensor( + _fbb, + shape__, + type, + buffer, + name__, + quantization, + is_variable, + sparsity, + shape_signature__, + has_rank, + variant_tensors__); +} + +flatbuffers::Offset CreateTensor(flatbuffers::FlatBufferBuilder &_fbb, const TensorT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Conv2DOptionsT : public flatbuffers::NativeTable { + typedef Conv2DOptions TableType; + tflite::Padding padding = tflite::Padding_SAME; + int32_t stride_w = 0; + int32_t stride_h = 0; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + int32_t dilation_w_factor = 1; + int32_t dilation_h_factor = 1; +}; + +struct Conv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Conv2DOptionsT NativeTableType; + typedef Conv2DOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_FUSED_ACTIVATION_FUNCTION = 10, + VT_DILATION_W_FACTOR = 12, + VT_DILATION_H_FACTOR = 14 + }; + tflite::Padding padding() const { + return static_cast(GetField(VT_PADDING, 0)); + } + int32_t stride_w() const { + return GetField(VT_STRIDE_W, 0); + } + int32_t stride_h() const { + return GetField(VT_STRIDE_H, 0); + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_w_factor() const { + return GetField(VT_DILATION_W_FACTOR, 1); + } + int32_t dilation_h_factor() const { + return GetField(VT_DILATION_H_FACTOR, 1); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PADDING, 1) && + VerifyField(verifier, VT_STRIDE_W, 4) && + VerifyField(verifier, VT_STRIDE_H, 4) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_DILATION_W_FACTOR, 4) && + VerifyField(verifier, VT_DILATION_H_FACTOR, 4) && + verifier.EndTable(); + } + Conv2DOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Conv2DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Conv2DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Conv2DOptionsBuilder { + typedef Conv2DOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(tflite::Padding padding) { + fbb_.AddElement(Conv2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) { + fbb_.AddElement(Conv2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) { + fbb_.AddElement(Conv2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(Conv2DOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_dilation_w_factor(int32_t dilation_w_factor) { + fbb_.AddElement(Conv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) { + fbb_.AddElement(Conv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit Conv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConv2DOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::Padding padding = tflite::Padding_SAME, + int32_t stride_w = 0, + int32_t stride_h = 0, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + int32_t dilation_w_factor = 1, + int32_t dilation_h_factor = 1) { + Conv2DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +flatbuffers::Offset CreateConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, const Conv2DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Conv3DOptionsT : public flatbuffers::NativeTable { + typedef Conv3DOptions TableType; + tflite::Padding padding = tflite::Padding_SAME; + int32_t stride_d = 0; + int32_t stride_w = 0; + int32_t stride_h = 0; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + int32_t dilation_d_factor = 1; + int32_t dilation_w_factor = 1; + int32_t dilation_h_factor = 1; +}; + +struct Conv3DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Conv3DOptionsT NativeTableType; + typedef Conv3DOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PADDING = 4, + VT_STRIDE_D = 6, + VT_STRIDE_W = 8, + VT_STRIDE_H = 10, + VT_FUSED_ACTIVATION_FUNCTION = 12, + VT_DILATION_D_FACTOR = 14, + VT_DILATION_W_FACTOR = 16, + VT_DILATION_H_FACTOR = 18 + }; + tflite::Padding padding() const { + return static_cast(GetField(VT_PADDING, 0)); + } + int32_t stride_d() const { + return GetField(VT_STRIDE_D, 0); + } + int32_t stride_w() const { + return GetField(VT_STRIDE_W, 0); + } + int32_t stride_h() const { + return GetField(VT_STRIDE_H, 0); + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_d_factor() const { + return GetField(VT_DILATION_D_FACTOR, 1); + } + int32_t dilation_w_factor() const { + return GetField(VT_DILATION_W_FACTOR, 1); + } + int32_t dilation_h_factor() const { + return GetField(VT_DILATION_H_FACTOR, 1); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PADDING, 1) && + VerifyField(verifier, VT_STRIDE_D, 4) && + VerifyField(verifier, VT_STRIDE_W, 4) && + VerifyField(verifier, VT_STRIDE_H, 4) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_DILATION_D_FACTOR, 4) && + VerifyField(verifier, VT_DILATION_W_FACTOR, 4) && + VerifyField(verifier, VT_DILATION_H_FACTOR, 4) && + verifier.EndTable(); + } + Conv3DOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Conv3DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Conv3DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Conv3DOptionsBuilder { + typedef Conv3DOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(tflite::Padding padding) { + fbb_.AddElement(Conv3DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_d(int32_t stride_d) { + fbb_.AddElement(Conv3DOptions::VT_STRIDE_D, stride_d, 0); + } + void add_stride_w(int32_t stride_w) { + fbb_.AddElement(Conv3DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) { + fbb_.AddElement(Conv3DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(Conv3DOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_dilation_d_factor(int32_t dilation_d_factor) { + fbb_.AddElement(Conv3DOptions::VT_DILATION_D_FACTOR, dilation_d_factor, 1); + } + void add_dilation_w_factor(int32_t dilation_w_factor) { + fbb_.AddElement(Conv3DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) { + fbb_.AddElement(Conv3DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit Conv3DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConv3DOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::Padding padding = tflite::Padding_SAME, + int32_t stride_d = 0, + int32_t stride_w = 0, + int32_t stride_h = 0, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + int32_t dilation_d_factor = 1, + int32_t dilation_w_factor = 1, + int32_t dilation_h_factor = 1) { + Conv3DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_dilation_d_factor(dilation_d_factor); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_stride_d(stride_d); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +flatbuffers::Offset CreateConv3DOptions(flatbuffers::FlatBufferBuilder &_fbb, const Conv3DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Pool2DOptionsT : public flatbuffers::NativeTable { + typedef Pool2DOptions TableType; + tflite::Padding padding = tflite::Padding_SAME; + int32_t stride_w = 0; + int32_t stride_h = 0; + int32_t filter_width = 0; + int32_t filter_height = 0; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; +}; + +struct Pool2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Pool2DOptionsT NativeTableType; + typedef Pool2DOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_FILTER_WIDTH = 10, + VT_FILTER_HEIGHT = 12, + VT_FUSED_ACTIVATION_FUNCTION = 14 + }; + tflite::Padding padding() const { + return static_cast(GetField(VT_PADDING, 0)); + } + int32_t stride_w() const { + return GetField(VT_STRIDE_W, 0); + } + int32_t stride_h() const { + return GetField(VT_STRIDE_H, 0); + } + int32_t filter_width() const { + return GetField(VT_FILTER_WIDTH, 0); + } + int32_t filter_height() const { + return GetField(VT_FILTER_HEIGHT, 0); + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PADDING, 1) && + VerifyField(verifier, VT_STRIDE_W, 4) && + VerifyField(verifier, VT_STRIDE_H, 4) && + VerifyField(verifier, VT_FILTER_WIDTH, 4) && + VerifyField(verifier, VT_FILTER_HEIGHT, 4) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + verifier.EndTable(); + } + Pool2DOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Pool2DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Pool2DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Pool2DOptionsBuilder { + typedef Pool2DOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(tflite::Padding padding) { + fbb_.AddElement(Pool2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) { + fbb_.AddElement(Pool2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) { + fbb_.AddElement(Pool2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_filter_width(int32_t filter_width) { + fbb_.AddElement(Pool2DOptions::VT_FILTER_WIDTH, filter_width, 0); + } + void add_filter_height(int32_t filter_height) { + fbb_.AddElement(Pool2DOptions::VT_FILTER_HEIGHT, filter_height, 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(Pool2DOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + explicit Pool2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePool2DOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::Padding padding = tflite::Padding_SAME, + int32_t stride_w = 0, + int32_t stride_h = 0, + int32_t filter_width = 0, + int32_t filter_height = 0, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE) { + Pool2DOptionsBuilder builder_(_fbb); + builder_.add_filter_height(filter_height); + builder_.add_filter_width(filter_width); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +flatbuffers::Offset CreatePool2DOptions(flatbuffers::FlatBufferBuilder &_fbb, const Pool2DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DepthwiseConv2DOptionsT : public flatbuffers::NativeTable { + typedef DepthwiseConv2DOptions TableType; + tflite::Padding padding = tflite::Padding_SAME; + int32_t stride_w = 0; + int32_t stride_h = 0; + int32_t depth_multiplier = 0; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + int32_t dilation_w_factor = 1; + int32_t dilation_h_factor = 1; +}; + +struct DepthwiseConv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DepthwiseConv2DOptionsT NativeTableType; + typedef DepthwiseConv2DOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_DEPTH_MULTIPLIER = 10, + VT_FUSED_ACTIVATION_FUNCTION = 12, + VT_DILATION_W_FACTOR = 14, + VT_DILATION_H_FACTOR = 16 + }; + tflite::Padding padding() const { + return static_cast(GetField(VT_PADDING, 0)); + } + int32_t stride_w() const { + return GetField(VT_STRIDE_W, 0); + } + int32_t stride_h() const { + return GetField(VT_STRIDE_H, 0); + } + int32_t depth_multiplier() const { + return GetField(VT_DEPTH_MULTIPLIER, 0); + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_w_factor() const { + return GetField(VT_DILATION_W_FACTOR, 1); + } + int32_t dilation_h_factor() const { + return GetField(VT_DILATION_H_FACTOR, 1); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PADDING, 1) && + VerifyField(verifier, VT_STRIDE_W, 4) && + VerifyField(verifier, VT_STRIDE_H, 4) && + VerifyField(verifier, VT_DEPTH_MULTIPLIER, 4) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_DILATION_W_FACTOR, 4) && + VerifyField(verifier, VT_DILATION_H_FACTOR, 4) && + verifier.EndTable(); + } + DepthwiseConv2DOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DepthwiseConv2DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DepthwiseConv2DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct DepthwiseConv2DOptionsBuilder { + typedef DepthwiseConv2DOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(tflite::Padding padding) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_depth_multiplier(int32_t depth_multiplier) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DEPTH_MULTIPLIER, depth_multiplier, 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_dilation_w_factor(int32_t dilation_w_factor) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit DepthwiseConv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDepthwiseConv2DOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::Padding padding = tflite::Padding_SAME, + int32_t stride_w = 0, + int32_t stride_h = 0, + int32_t depth_multiplier = 0, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + int32_t dilation_w_factor = 1, + int32_t dilation_h_factor = 1) { + DepthwiseConv2DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_depth_multiplier(depth_multiplier); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDepthwiseConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, const DepthwiseConv2DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ConcatEmbeddingsOptionsT : public flatbuffers::NativeTable { + typedef ConcatEmbeddingsOptions TableType; + int32_t num_channels = 0; + std::vector num_columns_per_channel{}; + std::vector embedding_dim_per_channel{}; +}; + +struct ConcatEmbeddingsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ConcatEmbeddingsOptionsT NativeTableType; + typedef ConcatEmbeddingsOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NUM_CHANNELS = 4, + VT_NUM_COLUMNS_PER_CHANNEL = 6, + VT_EMBEDDING_DIM_PER_CHANNEL = 8 + }; + int32_t num_channels() const { + return GetField(VT_NUM_CHANNELS, 0); + } + const flatbuffers::Vector *num_columns_per_channel() const { + return GetPointer *>(VT_NUM_COLUMNS_PER_CHANNEL); + } + const flatbuffers::Vector *embedding_dim_per_channel() const { + return GetPointer *>(VT_EMBEDDING_DIM_PER_CHANNEL); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NUM_CHANNELS, 4) && + VerifyOffset(verifier, VT_NUM_COLUMNS_PER_CHANNEL) && + verifier.VerifyVector(num_columns_per_channel()) && + VerifyOffset(verifier, VT_EMBEDDING_DIM_PER_CHANNEL) && + verifier.VerifyVector(embedding_dim_per_channel()) && + verifier.EndTable(); + } + ConcatEmbeddingsOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ConcatEmbeddingsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ConcatEmbeddingsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ConcatEmbeddingsOptionsBuilder { + typedef ConcatEmbeddingsOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_channels(int32_t num_channels) { + fbb_.AddElement(ConcatEmbeddingsOptions::VT_NUM_CHANNELS, num_channels, 0); + } + void add_num_columns_per_channel(flatbuffers::Offset> num_columns_per_channel) { + fbb_.AddOffset(ConcatEmbeddingsOptions::VT_NUM_COLUMNS_PER_CHANNEL, num_columns_per_channel); + } + void add_embedding_dim_per_channel(flatbuffers::Offset> embedding_dim_per_channel) { + fbb_.AddOffset(ConcatEmbeddingsOptions::VT_EMBEDDING_DIM_PER_CHANNEL, embedding_dim_per_channel); + } + explicit ConcatEmbeddingsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConcatEmbeddingsOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_channels = 0, + flatbuffers::Offset> num_columns_per_channel = 0, + flatbuffers::Offset> embedding_dim_per_channel = 0) { + ConcatEmbeddingsOptionsBuilder builder_(_fbb); + builder_.add_embedding_dim_per_channel(embedding_dim_per_channel); + builder_.add_num_columns_per_channel(num_columns_per_channel); + builder_.add_num_channels(num_channels); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateConcatEmbeddingsOptionsDirect( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_channels = 0, + const std::vector *num_columns_per_channel = nullptr, + const std::vector *embedding_dim_per_channel = nullptr) { + auto num_columns_per_channel__ = num_columns_per_channel ? _fbb.CreateVector(*num_columns_per_channel) : 0; + auto embedding_dim_per_channel__ = embedding_dim_per_channel ? _fbb.CreateVector(*embedding_dim_per_channel) : 0; + return tflite::CreateConcatEmbeddingsOptions( + _fbb, + num_channels, + num_columns_per_channel__, + embedding_dim_per_channel__); +} + +flatbuffers::Offset CreateConcatEmbeddingsOptions(flatbuffers::FlatBufferBuilder &_fbb, const ConcatEmbeddingsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LSHProjectionOptionsT : public flatbuffers::NativeTable { + typedef LSHProjectionOptions TableType; + tflite::LSHProjectionType type = tflite::LSHProjectionType_UNKNOWN; +}; + +struct LSHProjectionOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LSHProjectionOptionsT NativeTableType; + typedef LSHProjectionOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TYPE = 4 + }; + tflite::LSHProjectionType type() const { + return static_cast(GetField(VT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_TYPE, 1) && + verifier.EndTable(); + } + LSHProjectionOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LSHProjectionOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LSHProjectionOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LSHProjectionOptionsBuilder { + typedef LSHProjectionOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_type(tflite::LSHProjectionType type) { + fbb_.AddElement(LSHProjectionOptions::VT_TYPE, static_cast(type), 0); + } + explicit LSHProjectionOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLSHProjectionOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::LSHProjectionType type = tflite::LSHProjectionType_UNKNOWN) { + LSHProjectionOptionsBuilder builder_(_fbb); + builder_.add_type(type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLSHProjectionOptions(flatbuffers::FlatBufferBuilder &_fbb, const LSHProjectionOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SVDFOptionsT : public flatbuffers::NativeTable { + typedef SVDFOptions TableType; + int32_t rank = 0; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + bool asymmetric_quantize_inputs = false; +}; + +struct SVDFOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SVDFOptionsT NativeTableType; + typedef SVDFOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_RANK = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + int32_t rank() const { + return GetField(VT_RANK, 0); + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_RANK, 4) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + SVDFOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SVDFOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SVDFOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SVDFOptionsBuilder { + typedef SVDFOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_rank(int32_t rank) { + fbb_.AddElement(SVDFOptions::VT_RANK, rank, 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(SVDFOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(SVDFOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit SVDFOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSVDFOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t rank = 0, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) { + SVDFOptionsBuilder builder_(_fbb); + builder_.add_rank(rank); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSVDFOptions(flatbuffers::FlatBufferBuilder &_fbb, const SVDFOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct RNNOptionsT : public flatbuffers::NativeTable { + typedef RNNOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + bool asymmetric_quantize_inputs = false; +}; + +struct RNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RNNOptionsT NativeTableType; + typedef RNNOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 6 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + RNNOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(RNNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const RNNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct RNNOptionsBuilder { + typedef RNNOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(RNNOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(RNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit RNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) { + RNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, const RNNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SequenceRNNOptionsT : public flatbuffers::NativeTable { + typedef SequenceRNNOptions TableType; + bool time_major = false; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + bool asymmetric_quantize_inputs = false; +}; + +struct SequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SequenceRNNOptionsT NativeTableType; + typedef SequenceRNNOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TIME_MAJOR = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + bool time_major() const { + return GetField(VT_TIME_MAJOR, 0) != 0; + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_TIME_MAJOR, 1) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + SequenceRNNOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SequenceRNNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SequenceRNNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SequenceRNNOptionsBuilder { + typedef SequenceRNNOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_time_major(bool time_major) { + fbb_.AddElement(SequenceRNNOptions::VT_TIME_MAJOR, static_cast(time_major), 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(SequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(SequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit SequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSequenceRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool time_major = false, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) { + SequenceRNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_time_major(time_major); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSequenceRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, const SequenceRNNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BidirectionalSequenceRNNOptionsT : public flatbuffers::NativeTable { + typedef BidirectionalSequenceRNNOptions TableType; + bool time_major = false; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + bool merge_outputs = false; + bool asymmetric_quantize_inputs = false; +}; + +struct BidirectionalSequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BidirectionalSequenceRNNOptionsT NativeTableType; + typedef BidirectionalSequenceRNNOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TIME_MAJOR = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_MERGE_OUTPUTS = 8, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 10 + }; + bool time_major() const { + return GetField(VT_TIME_MAJOR, 0) != 0; + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool merge_outputs() const { + return GetField(VT_MERGE_OUTPUTS, 0) != 0; + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_TIME_MAJOR, 1) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_MERGE_OUTPUTS, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + BidirectionalSequenceRNNOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BidirectionalSequenceRNNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceRNNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BidirectionalSequenceRNNOptionsBuilder { + typedef BidirectionalSequenceRNNOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_time_major(bool time_major) { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_TIME_MAJOR, static_cast(time_major), 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_merge_outputs(bool merge_outputs) { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_MERGE_OUTPUTS, static_cast(merge_outputs), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit BidirectionalSequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBidirectionalSequenceRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool time_major = false, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + bool merge_outputs = false, + bool asymmetric_quantize_inputs = false) { + BidirectionalSequenceRNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_merge_outputs(merge_outputs); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_time_major(time_major); + return builder_.Finish(); +} + +flatbuffers::Offset CreateBidirectionalSequenceRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceRNNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct FullyConnectedOptionsT : public flatbuffers::NativeTable { + typedef FullyConnectedOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + tflite::FullyConnectedOptionsWeightsFormat weights_format = tflite::FullyConnectedOptionsWeightsFormat_DEFAULT; + bool keep_num_dims = false; + bool asymmetric_quantize_inputs = false; +}; + +struct FullyConnectedOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FullyConnectedOptionsT NativeTableType; + typedef FullyConnectedOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_WEIGHTS_FORMAT = 6, + VT_KEEP_NUM_DIMS = 8, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 10 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + tflite::FullyConnectedOptionsWeightsFormat weights_format() const { + return static_cast(GetField(VT_WEIGHTS_FORMAT, 0)); + } + bool keep_num_dims() const { + return GetField(VT_KEEP_NUM_DIMS, 0) != 0; + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_WEIGHTS_FORMAT, 1) && + VerifyField(verifier, VT_KEEP_NUM_DIMS, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + FullyConnectedOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FullyConnectedOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const FullyConnectedOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FullyConnectedOptionsBuilder { + typedef FullyConnectedOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(FullyConnectedOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_weights_format(tflite::FullyConnectedOptionsWeightsFormat weights_format) { + fbb_.AddElement(FullyConnectedOptions::VT_WEIGHTS_FORMAT, static_cast(weights_format), 0); + } + void add_keep_num_dims(bool keep_num_dims) { + fbb_.AddElement(FullyConnectedOptions::VT_KEEP_NUM_DIMS, static_cast(keep_num_dims), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(FullyConnectedOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit FullyConnectedOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFullyConnectedOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + tflite::FullyConnectedOptionsWeightsFormat weights_format = tflite::FullyConnectedOptionsWeightsFormat_DEFAULT, + bool keep_num_dims = false, + bool asymmetric_quantize_inputs = false) { + FullyConnectedOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_keep_num_dims(keep_num_dims); + builder_.add_weights_format(weights_format); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateFullyConnectedOptions(flatbuffers::FlatBufferBuilder &_fbb, const FullyConnectedOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SoftmaxOptionsT : public flatbuffers::NativeTable { + typedef SoftmaxOptions TableType; + float beta = 0.0f; +}; + +struct SoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SoftmaxOptionsT NativeTableType; + typedef SoftmaxOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BETA = 4 + }; + float beta() const { + return GetField(VT_BETA, 0.0f); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_BETA, 4) && + verifier.EndTable(); + } + SoftmaxOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SoftmaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SoftmaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SoftmaxOptionsBuilder { + typedef SoftmaxOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_beta(float beta) { + fbb_.AddElement(SoftmaxOptions::VT_BETA, beta, 0.0f); + } + explicit SoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSoftmaxOptions( + flatbuffers::FlatBufferBuilder &_fbb, + float beta = 0.0f) { + SoftmaxOptionsBuilder builder_(_fbb); + builder_.add_beta(beta); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const SoftmaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ConcatenationOptionsT : public flatbuffers::NativeTable { + typedef ConcatenationOptions TableType; + int32_t axis = 0; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; +}; + +struct ConcatenationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ConcatenationOptionsT NativeTableType; + typedef ConcatenationOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_AXIS = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6 + }; + int32_t axis() const { + return GetField(VT_AXIS, 0); + } + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_AXIS, 4) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + verifier.EndTable(); + } + ConcatenationOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ConcatenationOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ConcatenationOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ConcatenationOptionsBuilder { + typedef ConcatenationOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { + fbb_.AddElement(ConcatenationOptions::VT_AXIS, axis, 0); + } + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(ConcatenationOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + explicit ConcatenationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConcatenationOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE) { + ConcatenationOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateConcatenationOptions(flatbuffers::FlatBufferBuilder &_fbb, const ConcatenationOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AddOptionsT : public flatbuffers::NativeTable { + typedef AddOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + bool pot_scale_int16 = true; +}; + +struct AddOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AddOptionsT NativeTableType; + typedef AddOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_POT_SCALE_INT16 = 6 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool pot_scale_int16() const { + return GetField(VT_POT_SCALE_INT16, 1) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_POT_SCALE_INT16, 1) && + verifier.EndTable(); + } + AddOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AddOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AddOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AddOptionsBuilder { + typedef AddOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(AddOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_pot_scale_int16(bool pot_scale_int16) { + fbb_.AddElement(AddOptions::VT_POT_SCALE_INT16, static_cast(pot_scale_int16), 1); + } + explicit AddOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAddOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + bool pot_scale_int16 = true) { + AddOptionsBuilder builder_(_fbb); + builder_.add_pot_scale_int16(pot_scale_int16); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateAddOptions(flatbuffers::FlatBufferBuilder &_fbb, const AddOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MulOptionsT : public flatbuffers::NativeTable { + typedef MulOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; +}; + +struct MulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MulOptionsT NativeTableType; + typedef MulOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + verifier.EndTable(); + } + MulOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MulOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MulOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MulOptionsBuilder { + typedef MulOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(MulOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + explicit MulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMulOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE) { + MulOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateMulOptions(flatbuffers::FlatBufferBuilder &_fbb, const MulOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct L2NormOptionsT : public flatbuffers::NativeTable { + typedef L2NormOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; +}; + +struct L2NormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef L2NormOptionsT NativeTableType; + typedef L2NormOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + verifier.EndTable(); + } + L2NormOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(L2NormOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const L2NormOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct L2NormOptionsBuilder { + typedef L2NormOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(L2NormOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + explicit L2NormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateL2NormOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE) { + L2NormOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateL2NormOptions(flatbuffers::FlatBufferBuilder &_fbb, const L2NormOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LocalResponseNormalizationOptionsT : public flatbuffers::NativeTable { + typedef LocalResponseNormalizationOptions TableType; + int32_t radius = 0; + float bias = 0.0f; + float alpha = 0.0f; + float beta = 0.0f; +}; + +struct LocalResponseNormalizationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LocalResponseNormalizationOptionsT NativeTableType; + typedef LocalResponseNormalizationOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_RADIUS = 4, + VT_BIAS = 6, + VT_ALPHA = 8, + VT_BETA = 10 + }; + int32_t radius() const { + return GetField(VT_RADIUS, 0); + } + float bias() const { + return GetField(VT_BIAS, 0.0f); + } + float alpha() const { + return GetField(VT_ALPHA, 0.0f); + } + float beta() const { + return GetField(VT_BETA, 0.0f); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_RADIUS, 4) && + VerifyField(verifier, VT_BIAS, 4) && + VerifyField(verifier, VT_ALPHA, 4) && + VerifyField(verifier, VT_BETA, 4) && + verifier.EndTable(); + } + LocalResponseNormalizationOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LocalResponseNormalizationOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LocalResponseNormalizationOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LocalResponseNormalizationOptionsBuilder { + typedef LocalResponseNormalizationOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_radius(int32_t radius) { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_RADIUS, radius, 0); + } + void add_bias(float bias) { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_BIAS, bias, 0.0f); + } + void add_alpha(float alpha) { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_ALPHA, alpha, 0.0f); + } + void add_beta(float beta) { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_BETA, beta, 0.0f); + } + explicit LocalResponseNormalizationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLocalResponseNormalizationOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t radius = 0, + float bias = 0.0f, + float alpha = 0.0f, + float beta = 0.0f) { + LocalResponseNormalizationOptionsBuilder builder_(_fbb); + builder_.add_beta(beta); + builder_.add_alpha(alpha); + builder_.add_bias(bias); + builder_.add_radius(radius); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLocalResponseNormalizationOptions(flatbuffers::FlatBufferBuilder &_fbb, const LocalResponseNormalizationOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LSTMOptionsT : public flatbuffers::NativeTable { + typedef LSTMOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + float cell_clip = 0.0f; + float proj_clip = 0.0f; + tflite::LSTMKernelType kernel_type = tflite::LSTMKernelType_FULL; + bool asymmetric_quantize_inputs = false; +}; + +struct LSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LSTMOptionsT NativeTableType; + typedef LSTMOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_KERNEL_TYPE = 10, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 12 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { + return GetField(VT_CELL_CLIP, 0.0f); + } + float proj_clip() const { + return GetField(VT_PROJ_CLIP, 0.0f); + } + tflite::LSTMKernelType kernel_type() const { + return static_cast(GetField(VT_KERNEL_TYPE, 0)); + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_CELL_CLIP, 4) && + VerifyField(verifier, VT_PROJ_CLIP, 4) && + VerifyField(verifier, VT_KERNEL_TYPE, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + LSTMOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LSTMOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LSTMOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LSTMOptionsBuilder { + typedef LSTMOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(LSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) { + fbb_.AddElement(LSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) { + fbb_.AddElement(LSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_kernel_type(tflite::LSTMKernelType kernel_type) { + fbb_.AddElement(LSTMOptions::VT_KERNEL_TYPE, static_cast(kernel_type), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(LSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit LSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + float cell_clip = 0.0f, + float proj_clip = 0.0f, + tflite::LSTMKernelType kernel_type = tflite::LSTMKernelType_FULL, + bool asymmetric_quantize_inputs = false) { + LSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_kernel_type(kernel_type); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, const LSTMOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UnidirectionalSequenceLSTMOptionsT : public flatbuffers::NativeTable { + typedef UnidirectionalSequenceLSTMOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + float cell_clip = 0.0f; + float proj_clip = 0.0f; + bool time_major = false; + bool asymmetric_quantize_inputs = false; +}; + +struct UnidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UnidirectionalSequenceLSTMOptionsT NativeTableType; + typedef UnidirectionalSequenceLSTMOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_TIME_MAJOR = 10, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 12 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { + return GetField(VT_CELL_CLIP, 0.0f); + } + float proj_clip() const { + return GetField(VT_PROJ_CLIP, 0.0f); + } + bool time_major() const { + return GetField(VT_TIME_MAJOR, 0) != 0; + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_CELL_CLIP, 4) && + VerifyField(verifier, VT_PROJ_CLIP, 4) && + VerifyField(verifier, VT_TIME_MAJOR, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + UnidirectionalSequenceLSTMOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UnidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnidirectionalSequenceLSTMOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UnidirectionalSequenceLSTMOptionsBuilder { + typedef UnidirectionalSequenceLSTMOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_time_major(bool time_major) { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_TIME_MAJOR, static_cast(time_major), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit UnidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnidirectionalSequenceLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + float cell_clip = 0.0f, + float proj_clip = 0.0f, + bool time_major = false, + bool asymmetric_quantize_inputs = false) { + UnidirectionalSequenceLSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_time_major(time_major); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUnidirectionalSequenceLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BidirectionalSequenceLSTMOptionsT : public flatbuffers::NativeTable { + typedef BidirectionalSequenceLSTMOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + float cell_clip = 0.0f; + float proj_clip = 0.0f; + bool merge_outputs = false; + bool time_major = true; + bool asymmetric_quantize_inputs = false; +}; + +struct BidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BidirectionalSequenceLSTMOptionsT NativeTableType; + typedef BidirectionalSequenceLSTMOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_MERGE_OUTPUTS = 10, + VT_TIME_MAJOR = 12, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 14 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { + return GetField(VT_CELL_CLIP, 0.0f); + } + float proj_clip() const { + return GetField(VT_PROJ_CLIP, 0.0f); + } + bool merge_outputs() const { + return GetField(VT_MERGE_OUTPUTS, 0) != 0; + } + bool time_major() const { + return GetField(VT_TIME_MAJOR, 1) != 0; + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_CELL_CLIP, 4) && + VerifyField(verifier, VT_PROJ_CLIP, 4) && + VerifyField(verifier, VT_MERGE_OUTPUTS, 1) && + VerifyField(verifier, VT_TIME_MAJOR, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + BidirectionalSequenceLSTMOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceLSTMOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BidirectionalSequenceLSTMOptionsBuilder { + typedef BidirectionalSequenceLSTMOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_merge_outputs(bool merge_outputs) { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_MERGE_OUTPUTS, static_cast(merge_outputs), 0); + } + void add_time_major(bool time_major) { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_TIME_MAJOR, static_cast(time_major), 1); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit BidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBidirectionalSequenceLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + float cell_clip = 0.0f, + float proj_clip = 0.0f, + bool merge_outputs = false, + bool time_major = true, + bool asymmetric_quantize_inputs = false) { + BidirectionalSequenceLSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_time_major(time_major); + builder_.add_merge_outputs(merge_outputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateBidirectionalSequenceLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ResizeBilinearOptionsT : public flatbuffers::NativeTable { + typedef ResizeBilinearOptions TableType; + bool align_corners = false; + bool half_pixel_centers = false; +}; + +struct ResizeBilinearOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ResizeBilinearOptionsT NativeTableType; + typedef ResizeBilinearOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ALIGN_CORNERS = 8, + VT_HALF_PIXEL_CENTERS = 10 + }; + bool align_corners() const { + return GetField(VT_ALIGN_CORNERS, 0) != 0; + } + bool half_pixel_centers() const { + return GetField(VT_HALF_PIXEL_CENTERS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ALIGN_CORNERS, 1) && + VerifyField(verifier, VT_HALF_PIXEL_CENTERS, 1) && + verifier.EndTable(); + } + ResizeBilinearOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ResizeBilinearOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ResizeBilinearOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ResizeBilinearOptionsBuilder { + typedef ResizeBilinearOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_align_corners(bool align_corners) { + fbb_.AddElement(ResizeBilinearOptions::VT_ALIGN_CORNERS, static_cast(align_corners), 0); + } + void add_half_pixel_centers(bool half_pixel_centers) { + fbb_.AddElement(ResizeBilinearOptions::VT_HALF_PIXEL_CENTERS, static_cast(half_pixel_centers), 0); + } + explicit ResizeBilinearOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateResizeBilinearOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool align_corners = false, + bool half_pixel_centers = false) { + ResizeBilinearOptionsBuilder builder_(_fbb); + builder_.add_half_pixel_centers(half_pixel_centers); + builder_.add_align_corners(align_corners); + return builder_.Finish(); +} + +flatbuffers::Offset CreateResizeBilinearOptions(flatbuffers::FlatBufferBuilder &_fbb, const ResizeBilinearOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ResizeNearestNeighborOptionsT : public flatbuffers::NativeTable { + typedef ResizeNearestNeighborOptions TableType; + bool align_corners = false; + bool half_pixel_centers = false; +}; + +struct ResizeNearestNeighborOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ResizeNearestNeighborOptionsT NativeTableType; + typedef ResizeNearestNeighborOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ALIGN_CORNERS = 4, + VT_HALF_PIXEL_CENTERS = 6 + }; + bool align_corners() const { + return GetField(VT_ALIGN_CORNERS, 0) != 0; + } + bool half_pixel_centers() const { + return GetField(VT_HALF_PIXEL_CENTERS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ALIGN_CORNERS, 1) && + VerifyField(verifier, VT_HALF_PIXEL_CENTERS, 1) && + verifier.EndTable(); + } + ResizeNearestNeighborOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ResizeNearestNeighborOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ResizeNearestNeighborOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ResizeNearestNeighborOptionsBuilder { + typedef ResizeNearestNeighborOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_align_corners(bool align_corners) { + fbb_.AddElement(ResizeNearestNeighborOptions::VT_ALIGN_CORNERS, static_cast(align_corners), 0); + } + void add_half_pixel_centers(bool half_pixel_centers) { + fbb_.AddElement(ResizeNearestNeighborOptions::VT_HALF_PIXEL_CENTERS, static_cast(half_pixel_centers), 0); + } + explicit ResizeNearestNeighborOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateResizeNearestNeighborOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool align_corners = false, + bool half_pixel_centers = false) { + ResizeNearestNeighborOptionsBuilder builder_(_fbb); + builder_.add_half_pixel_centers(half_pixel_centers); + builder_.add_align_corners(align_corners); + return builder_.Finish(); +} + +flatbuffers::Offset CreateResizeNearestNeighborOptions(flatbuffers::FlatBufferBuilder &_fbb, const ResizeNearestNeighborOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct CallOptionsT : public flatbuffers::NativeTable { + typedef CallOptions TableType; + uint32_t subgraph = 0; +}; + +struct CallOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CallOptionsT NativeTableType; + typedef CallOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SUBGRAPH = 4 + }; + uint32_t subgraph() const { + return GetField(VT_SUBGRAPH, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SUBGRAPH, 4) && + verifier.EndTable(); + } + CallOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CallOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const CallOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CallOptionsBuilder { + typedef CallOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_subgraph(uint32_t subgraph) { + fbb_.AddElement(CallOptions::VT_SUBGRAPH, subgraph, 0); + } + explicit CallOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCallOptions( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t subgraph = 0) { + CallOptionsBuilder builder_(_fbb); + builder_.add_subgraph(subgraph); + return builder_.Finish(); +} + +flatbuffers::Offset CreateCallOptions(flatbuffers::FlatBufferBuilder &_fbb, const CallOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct PadOptionsT : public flatbuffers::NativeTable { + typedef PadOptions TableType; +}; + +struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef PadOptionsT NativeTableType; + typedef PadOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + PadOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(PadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const PadOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct PadOptionsBuilder { + typedef PadOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePadOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + PadOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreatePadOptions(flatbuffers::FlatBufferBuilder &_fbb, const PadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct PadV2OptionsT : public flatbuffers::NativeTable { + typedef PadV2Options TableType; +}; + +struct PadV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef PadV2OptionsT NativeTableType; + typedef PadV2OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + PadV2OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(PadV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const PadV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct PadV2OptionsBuilder { + typedef PadV2Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PadV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePadV2Options( + flatbuffers::FlatBufferBuilder &_fbb) { + PadV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreatePadV2Options(flatbuffers::FlatBufferBuilder &_fbb, const PadV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ReshapeOptionsT : public flatbuffers::NativeTable { + typedef ReshapeOptions TableType; + std::vector new_shape{}; +}; + +struct ReshapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ReshapeOptionsT NativeTableType; + typedef ReshapeOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NEW_SHAPE = 4 + }; + const flatbuffers::Vector *new_shape() const { + return GetPointer *>(VT_NEW_SHAPE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NEW_SHAPE) && + verifier.VerifyVector(new_shape()) && + verifier.EndTable(); + } + ReshapeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ReshapeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReshapeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ReshapeOptionsBuilder { + typedef ReshapeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_new_shape(flatbuffers::Offset> new_shape) { + fbb_.AddOffset(ReshapeOptions::VT_NEW_SHAPE, new_shape); + } + explicit ReshapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateReshapeOptions( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> new_shape = 0) { + ReshapeOptionsBuilder builder_(_fbb); + builder_.add_new_shape(new_shape); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateReshapeOptionsDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *new_shape = nullptr) { + auto new_shape__ = new_shape ? _fbb.CreateVector(*new_shape) : 0; + return tflite::CreateReshapeOptions( + _fbb, + new_shape__); +} + +flatbuffers::Offset CreateReshapeOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReshapeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SpaceToBatchNDOptionsT : public flatbuffers::NativeTable { + typedef SpaceToBatchNDOptions TableType; +}; + +struct SpaceToBatchNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SpaceToBatchNDOptionsT NativeTableType; + typedef SpaceToBatchNDOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SpaceToBatchNDOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SpaceToBatchNDOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToBatchNDOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SpaceToBatchNDOptionsBuilder { + typedef SpaceToBatchNDOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SpaceToBatchNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSpaceToBatchNDOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SpaceToBatchNDOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSpaceToBatchNDOptions(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToBatchNDOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BatchToSpaceNDOptionsT : public flatbuffers::NativeTable { + typedef BatchToSpaceNDOptions TableType; +}; + +struct BatchToSpaceNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BatchToSpaceNDOptionsT NativeTableType; + typedef BatchToSpaceNDOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + BatchToSpaceNDOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BatchToSpaceNDOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BatchToSpaceNDOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BatchToSpaceNDOptionsBuilder { + typedef BatchToSpaceNDOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit BatchToSpaceNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBatchToSpaceNDOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + BatchToSpaceNDOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateBatchToSpaceNDOptions(flatbuffers::FlatBufferBuilder &_fbb, const BatchToSpaceNDOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SkipGramOptionsT : public flatbuffers::NativeTable { + typedef SkipGramOptions TableType; + int32_t ngram_size = 0; + int32_t max_skip_size = 0; + bool include_all_ngrams = false; +}; + +struct SkipGramOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SkipGramOptionsT NativeTableType; + typedef SkipGramOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NGRAM_SIZE = 4, + VT_MAX_SKIP_SIZE = 6, + VT_INCLUDE_ALL_NGRAMS = 8 + }; + int32_t ngram_size() const { + return GetField(VT_NGRAM_SIZE, 0); + } + int32_t max_skip_size() const { + return GetField(VT_MAX_SKIP_SIZE, 0); + } + bool include_all_ngrams() const { + return GetField(VT_INCLUDE_ALL_NGRAMS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NGRAM_SIZE, 4) && + VerifyField(verifier, VT_MAX_SKIP_SIZE, 4) && + VerifyField(verifier, VT_INCLUDE_ALL_NGRAMS, 1) && + verifier.EndTable(); + } + SkipGramOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SkipGramOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SkipGramOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SkipGramOptionsBuilder { + typedef SkipGramOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_ngram_size(int32_t ngram_size) { + fbb_.AddElement(SkipGramOptions::VT_NGRAM_SIZE, ngram_size, 0); + } + void add_max_skip_size(int32_t max_skip_size) { + fbb_.AddElement(SkipGramOptions::VT_MAX_SKIP_SIZE, max_skip_size, 0); + } + void add_include_all_ngrams(bool include_all_ngrams) { + fbb_.AddElement(SkipGramOptions::VT_INCLUDE_ALL_NGRAMS, static_cast(include_all_ngrams), 0); + } + explicit SkipGramOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSkipGramOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t ngram_size = 0, + int32_t max_skip_size = 0, + bool include_all_ngrams = false) { + SkipGramOptionsBuilder builder_(_fbb); + builder_.add_max_skip_size(max_skip_size); + builder_.add_ngram_size(ngram_size); + builder_.add_include_all_ngrams(include_all_ngrams); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSkipGramOptions(flatbuffers::FlatBufferBuilder &_fbb, const SkipGramOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SpaceToDepthOptionsT : public flatbuffers::NativeTable { + typedef SpaceToDepthOptions TableType; + int32_t block_size = 0; +}; + +struct SpaceToDepthOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SpaceToDepthOptionsT NativeTableType; + typedef SpaceToDepthOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BLOCK_SIZE = 4 + }; + int32_t block_size() const { + return GetField(VT_BLOCK_SIZE, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_BLOCK_SIZE, 4) && + verifier.EndTable(); + } + SpaceToDepthOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SpaceToDepthOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToDepthOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SpaceToDepthOptionsBuilder { + typedef SpaceToDepthOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_block_size(int32_t block_size) { + fbb_.AddElement(SpaceToDepthOptions::VT_BLOCK_SIZE, block_size, 0); + } + explicit SpaceToDepthOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSpaceToDepthOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t block_size = 0) { + SpaceToDepthOptionsBuilder builder_(_fbb); + builder_.add_block_size(block_size); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSpaceToDepthOptions(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToDepthOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DepthToSpaceOptionsT : public flatbuffers::NativeTable { + typedef DepthToSpaceOptions TableType; + int32_t block_size = 0; +}; + +struct DepthToSpaceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DepthToSpaceOptionsT NativeTableType; + typedef DepthToSpaceOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BLOCK_SIZE = 4 + }; + int32_t block_size() const { + return GetField(VT_BLOCK_SIZE, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_BLOCK_SIZE, 4) && + verifier.EndTable(); + } + DepthToSpaceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DepthToSpaceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DepthToSpaceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct DepthToSpaceOptionsBuilder { + typedef DepthToSpaceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_block_size(int32_t block_size) { + fbb_.AddElement(DepthToSpaceOptions::VT_BLOCK_SIZE, block_size, 0); + } + explicit DepthToSpaceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDepthToSpaceOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t block_size = 0) { + DepthToSpaceOptionsBuilder builder_(_fbb); + builder_.add_block_size(block_size); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDepthToSpaceOptions(flatbuffers::FlatBufferBuilder &_fbb, const DepthToSpaceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SubOptionsT : public flatbuffers::NativeTable { + typedef SubOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; + bool pot_scale_int16 = true; +}; + +struct SubOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SubOptionsT NativeTableType; + typedef SubOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_POT_SCALE_INT16 = 6 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool pot_scale_int16() const { + return GetField(VT_POT_SCALE_INT16, 1) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + VerifyField(verifier, VT_POT_SCALE_INT16, 1) && + verifier.EndTable(); + } + SubOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SubOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SubOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SubOptionsBuilder { + typedef SubOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(SubOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + void add_pot_scale_int16(bool pot_scale_int16) { + fbb_.AddElement(SubOptions::VT_POT_SCALE_INT16, static_cast(pot_scale_int16), 1); + } + explicit SubOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSubOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE, + bool pot_scale_int16 = true) { + SubOptionsBuilder builder_(_fbb); + builder_.add_pot_scale_int16(pot_scale_int16); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSubOptions(flatbuffers::FlatBufferBuilder &_fbb, const SubOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DivOptionsT : public flatbuffers::NativeTable { + typedef DivOptions TableType; + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE; +}; + +struct DivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DivOptionsT NativeTableType; + typedef DivOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + tflite::ActivationFunctionType fused_activation_function() const { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION, 1) && + verifier.EndTable(); + } + DivOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DivOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DivOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct DivOptionsBuilder { + typedef DivOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(tflite::ActivationFunctionType fused_activation_function) { + fbb_.AddElement(DivOptions::VT_FUSED_ACTIVATION_FUNCTION, static_cast(fused_activation_function), 0); + } + explicit DivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDivOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::ActivationFunctionType fused_activation_function = tflite::ActivationFunctionType_NONE) { + DivOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDivOptions(flatbuffers::FlatBufferBuilder &_fbb, const DivOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TopKV2OptionsT : public flatbuffers::NativeTable { + typedef TopKV2Options TableType; +}; + +struct TopKV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TopKV2OptionsT NativeTableType; + typedef TopKV2OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + TopKV2OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TopKV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TopKV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TopKV2OptionsBuilder { + typedef TopKV2Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TopKV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTopKV2Options( + flatbuffers::FlatBufferBuilder &_fbb) { + TopKV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateTopKV2Options(flatbuffers::FlatBufferBuilder &_fbb, const TopKV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct EmbeddingLookupSparseOptionsT : public flatbuffers::NativeTable { + typedef EmbeddingLookupSparseOptions TableType; + tflite::CombinerType combiner = tflite::CombinerType_SUM; +}; + +struct EmbeddingLookupSparseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef EmbeddingLookupSparseOptionsT NativeTableType; + typedef EmbeddingLookupSparseOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_COMBINER = 4 + }; + tflite::CombinerType combiner() const { + return static_cast(GetField(VT_COMBINER, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_COMBINER, 1) && + verifier.EndTable(); + } + EmbeddingLookupSparseOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(EmbeddingLookupSparseOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const EmbeddingLookupSparseOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct EmbeddingLookupSparseOptionsBuilder { + typedef EmbeddingLookupSparseOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_combiner(tflite::CombinerType combiner) { + fbb_.AddElement(EmbeddingLookupSparseOptions::VT_COMBINER, static_cast(combiner), 0); + } + explicit EmbeddingLookupSparseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateEmbeddingLookupSparseOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::CombinerType combiner = tflite::CombinerType_SUM) { + EmbeddingLookupSparseOptionsBuilder builder_(_fbb); + builder_.add_combiner(combiner); + return builder_.Finish(); +} + +flatbuffers::Offset CreateEmbeddingLookupSparseOptions(flatbuffers::FlatBufferBuilder &_fbb, const EmbeddingLookupSparseOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct GatherOptionsT : public flatbuffers::NativeTable { + typedef GatherOptions TableType; + int32_t axis = 0; + int32_t batch_dims = 0; +}; + +struct GatherOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef GatherOptionsT NativeTableType; + typedef GatherOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_AXIS = 4, + VT_BATCH_DIMS = 6 + }; + int32_t axis() const { + return GetField(VT_AXIS, 0); + } + int32_t batch_dims() const { + return GetField(VT_BATCH_DIMS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_AXIS, 4) && + VerifyField(verifier, VT_BATCH_DIMS, 4) && + verifier.EndTable(); + } + GatherOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(GatherOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const GatherOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct GatherOptionsBuilder { + typedef GatherOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { + fbb_.AddElement(GatherOptions::VT_AXIS, axis, 0); + } + void add_batch_dims(int32_t batch_dims) { + fbb_.AddElement(GatherOptions::VT_BATCH_DIMS, batch_dims, 0); + } + explicit GatherOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGatherOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0, + int32_t batch_dims = 0) { + GatherOptionsBuilder builder_(_fbb); + builder_.add_batch_dims(batch_dims); + builder_.add_axis(axis); + return builder_.Finish(); +} + +flatbuffers::Offset CreateGatherOptions(flatbuffers::FlatBufferBuilder &_fbb, const GatherOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TransposeOptionsT : public flatbuffers::NativeTable { + typedef TransposeOptions TableType; +}; + +struct TransposeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TransposeOptionsT NativeTableType; + typedef TransposeOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + TransposeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TransposeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TransposeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TransposeOptionsBuilder { + typedef TransposeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TransposeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTransposeOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + TransposeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateTransposeOptions(flatbuffers::FlatBufferBuilder &_fbb, const TransposeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ExpOptionsT : public flatbuffers::NativeTable { + typedef ExpOptions TableType; +}; + +struct ExpOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ExpOptionsT NativeTableType; + typedef ExpOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ExpOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ExpOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ExpOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ExpOptionsBuilder { + typedef ExpOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ExpOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateExpOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + ExpOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateExpOptions(flatbuffers::FlatBufferBuilder &_fbb, const ExpOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct CosOptionsT : public flatbuffers::NativeTable { + typedef CosOptions TableType; +}; + +struct CosOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CosOptionsT NativeTableType; + typedef CosOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + CosOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CosOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const CosOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CosOptionsBuilder { + typedef CosOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit CosOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCosOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + CosOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateCosOptions(flatbuffers::FlatBufferBuilder &_fbb, const CosOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ReducerOptionsT : public flatbuffers::NativeTable { + typedef ReducerOptions TableType; + bool keep_dims = false; +}; + +struct ReducerOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ReducerOptionsT NativeTableType; + typedef ReducerOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_KEEP_DIMS = 4 + }; + bool keep_dims() const { + return GetField(VT_KEEP_DIMS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_KEEP_DIMS, 1) && + verifier.EndTable(); + } + ReducerOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ReducerOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReducerOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ReducerOptionsBuilder { + typedef ReducerOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_keep_dims(bool keep_dims) { + fbb_.AddElement(ReducerOptions::VT_KEEP_DIMS, static_cast(keep_dims), 0); + } + explicit ReducerOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateReducerOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool keep_dims = false) { + ReducerOptionsBuilder builder_(_fbb); + builder_.add_keep_dims(keep_dims); + return builder_.Finish(); +} + +flatbuffers::Offset CreateReducerOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReducerOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SqueezeOptionsT : public flatbuffers::NativeTable { + typedef SqueezeOptions TableType; + std::vector squeeze_dims{}; +}; + +struct SqueezeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SqueezeOptionsT NativeTableType; + typedef SqueezeOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SQUEEZE_DIMS = 4 + }; + const flatbuffers::Vector *squeeze_dims() const { + return GetPointer *>(VT_SQUEEZE_DIMS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_SQUEEZE_DIMS) && + verifier.VerifyVector(squeeze_dims()) && + verifier.EndTable(); + } + SqueezeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SqueezeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SqueezeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SqueezeOptionsBuilder { + typedef SqueezeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_squeeze_dims(flatbuffers::Offset> squeeze_dims) { + fbb_.AddOffset(SqueezeOptions::VT_SQUEEZE_DIMS, squeeze_dims); + } + explicit SqueezeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSqueezeOptions( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> squeeze_dims = 0) { + SqueezeOptionsBuilder builder_(_fbb); + builder_.add_squeeze_dims(squeeze_dims); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSqueezeOptionsDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *squeeze_dims = nullptr) { + auto squeeze_dims__ = squeeze_dims ? _fbb.CreateVector(*squeeze_dims) : 0; + return tflite::CreateSqueezeOptions( + _fbb, + squeeze_dims__); +} + +flatbuffers::Offset CreateSqueezeOptions(flatbuffers::FlatBufferBuilder &_fbb, const SqueezeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SplitOptionsT : public flatbuffers::NativeTable { + typedef SplitOptions TableType; + int32_t num_splits = 0; +}; + +struct SplitOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SplitOptionsT NativeTableType; + typedef SplitOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { + return GetField(VT_NUM_SPLITS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NUM_SPLITS, 4) && + verifier.EndTable(); + } + SplitOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SplitOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SplitOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SplitOptionsBuilder { + typedef SplitOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) { + fbb_.AddElement(SplitOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) { + SplitOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SplitVOptionsT : public flatbuffers::NativeTable { + typedef SplitVOptions TableType; + int32_t num_splits = 0; +}; + +struct SplitVOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SplitVOptionsT NativeTableType; + typedef SplitVOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { + return GetField(VT_NUM_SPLITS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NUM_SPLITS, 4) && + verifier.EndTable(); + } + SplitVOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SplitVOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SplitVOptionsBuilder { + typedef SplitVOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) { + fbb_.AddElement(SplitVOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitVOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitVOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) { + SplitVOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct StridedSliceOptionsT : public flatbuffers::NativeTable { + typedef StridedSliceOptions TableType; + int32_t begin_mask = 0; + int32_t end_mask = 0; + int32_t ellipsis_mask = 0; + int32_t new_axis_mask = 0; + int32_t shrink_axis_mask = 0; +}; + +struct StridedSliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef StridedSliceOptionsT NativeTableType; + typedef StridedSliceOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BEGIN_MASK = 4, + VT_END_MASK = 6, + VT_ELLIPSIS_MASK = 8, + VT_NEW_AXIS_MASK = 10, + VT_SHRINK_AXIS_MASK = 12 + }; + int32_t begin_mask() const { + return GetField(VT_BEGIN_MASK, 0); + } + int32_t end_mask() const { + return GetField(VT_END_MASK, 0); + } + int32_t ellipsis_mask() const { + return GetField(VT_ELLIPSIS_MASK, 0); + } + int32_t new_axis_mask() const { + return GetField(VT_NEW_AXIS_MASK, 0); + } + int32_t shrink_axis_mask() const { + return GetField(VT_SHRINK_AXIS_MASK, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_BEGIN_MASK, 4) && + VerifyField(verifier, VT_END_MASK, 4) && + VerifyField(verifier, VT_ELLIPSIS_MASK, 4) && + VerifyField(verifier, VT_NEW_AXIS_MASK, 4) && + VerifyField(verifier, VT_SHRINK_AXIS_MASK, 4) && + verifier.EndTable(); + } + StridedSliceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(StridedSliceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct StridedSliceOptionsBuilder { + typedef StridedSliceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_begin_mask(int32_t begin_mask) { + fbb_.AddElement(StridedSliceOptions::VT_BEGIN_MASK, begin_mask, 0); + } + void add_end_mask(int32_t end_mask) { + fbb_.AddElement(StridedSliceOptions::VT_END_MASK, end_mask, 0); + } + void add_ellipsis_mask(int32_t ellipsis_mask) { + fbb_.AddElement(StridedSliceOptions::VT_ELLIPSIS_MASK, ellipsis_mask, 0); + } + void add_new_axis_mask(int32_t new_axis_mask) { + fbb_.AddElement(StridedSliceOptions::VT_NEW_AXIS_MASK, new_axis_mask, 0); + } + void add_shrink_axis_mask(int32_t shrink_axis_mask) { + fbb_.AddElement(StridedSliceOptions::VT_SHRINK_AXIS_MASK, shrink_axis_mask, 0); + } + explicit StridedSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateStridedSliceOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t begin_mask = 0, + int32_t end_mask = 0, + int32_t ellipsis_mask = 0, + int32_t new_axis_mask = 0, + int32_t shrink_axis_mask = 0) { + StridedSliceOptionsBuilder builder_(_fbb); + builder_.add_shrink_axis_mask(shrink_axis_mask); + builder_.add_new_axis_mask(new_axis_mask); + builder_.add_ellipsis_mask(ellipsis_mask); + builder_.add_end_mask(end_mask); + builder_.add_begin_mask(begin_mask); + return builder_.Finish(); +} + +flatbuffers::Offset CreateStridedSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LogSoftmaxOptionsT : public flatbuffers::NativeTable { + typedef LogSoftmaxOptions TableType; +}; + +struct LogSoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LogSoftmaxOptionsT NativeTableType; + typedef LogSoftmaxOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + LogSoftmaxOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LogSoftmaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogSoftmaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LogSoftmaxOptionsBuilder { + typedef LogSoftmaxOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogSoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLogSoftmaxOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + LogSoftmaxOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLogSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogSoftmaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct CastOptionsT : public flatbuffers::NativeTable { + typedef CastOptions TableType; + tflite::TensorType in_data_type = tflite::TensorType_FLOAT32; + tflite::TensorType out_data_type = tflite::TensorType_FLOAT32; +}; + +struct CastOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CastOptionsT NativeTableType; + typedef CastOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_IN_DATA_TYPE = 4, + VT_OUT_DATA_TYPE = 6 + }; + tflite::TensorType in_data_type() const { + return static_cast(GetField(VT_IN_DATA_TYPE, 0)); + } + tflite::TensorType out_data_type() const { + return static_cast(GetField(VT_OUT_DATA_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_IN_DATA_TYPE, 1) && + VerifyField(verifier, VT_OUT_DATA_TYPE, 1) && + verifier.EndTable(); + } + CastOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CastOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const CastOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CastOptionsBuilder { + typedef CastOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_in_data_type(tflite::TensorType in_data_type) { + fbb_.AddElement(CastOptions::VT_IN_DATA_TYPE, static_cast(in_data_type), 0); + } + void add_out_data_type(tflite::TensorType out_data_type) { + fbb_.AddElement(CastOptions::VT_OUT_DATA_TYPE, static_cast(out_data_type), 0); + } + explicit CastOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCastOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::TensorType in_data_type = tflite::TensorType_FLOAT32, + tflite::TensorType out_data_type = tflite::TensorType_FLOAT32) { + CastOptionsBuilder builder_(_fbb); + builder_.add_out_data_type(out_data_type); + builder_.add_in_data_type(in_data_type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateCastOptions(flatbuffers::FlatBufferBuilder &_fbb, const CastOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DequantizeOptionsT : public flatbuffers::NativeTable { + typedef DequantizeOptions TableType; +}; + +struct DequantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DequantizeOptionsT NativeTableType; + typedef DequantizeOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + DequantizeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DequantizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DequantizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct DequantizeOptionsBuilder { + typedef DequantizeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DequantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDequantizeOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + DequantizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDequantizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const DequantizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MaximumMinimumOptionsT : public flatbuffers::NativeTable { + typedef MaximumMinimumOptions TableType; +}; + +struct MaximumMinimumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MaximumMinimumOptionsT NativeTableType; + typedef MaximumMinimumOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + MaximumMinimumOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MaximumMinimumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MaximumMinimumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MaximumMinimumOptionsBuilder { + typedef MaximumMinimumOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MaximumMinimumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMaximumMinimumOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + MaximumMinimumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateMaximumMinimumOptions(flatbuffers::FlatBufferBuilder &_fbb, const MaximumMinimumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TileOptionsT : public flatbuffers::NativeTable { + typedef TileOptions TableType; +}; + +struct TileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TileOptionsT NativeTableType; + typedef TileOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + TileOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TileOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TileOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TileOptionsBuilder { + typedef TileOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTileOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + TileOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateTileOptions(flatbuffers::FlatBufferBuilder &_fbb, const TileOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ArgMaxOptionsT : public flatbuffers::NativeTable { + typedef ArgMaxOptions TableType; + tflite::TensorType output_type = tflite::TensorType_FLOAT32; +}; + +struct ArgMaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ArgMaxOptionsT NativeTableType; + typedef ArgMaxOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_OUTPUT_TYPE = 4 + }; + tflite::TensorType output_type() const { + return static_cast(GetField(VT_OUTPUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_OUTPUT_TYPE, 1) && + verifier.EndTable(); + } + ArgMaxOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ArgMaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ArgMaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ArgMaxOptionsBuilder { + typedef ArgMaxOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_output_type(tflite::TensorType output_type) { + fbb_.AddElement(ArgMaxOptions::VT_OUTPUT_TYPE, static_cast(output_type), 0); + } + explicit ArgMaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateArgMaxOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::TensorType output_type = tflite::TensorType_FLOAT32) { + ArgMaxOptionsBuilder builder_(_fbb); + builder_.add_output_type(output_type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateArgMaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const ArgMaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ArgMinOptionsT : public flatbuffers::NativeTable { + typedef ArgMinOptions TableType; + tflite::TensorType output_type = tflite::TensorType_FLOAT32; +}; + +struct ArgMinOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ArgMinOptionsT NativeTableType; + typedef ArgMinOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_OUTPUT_TYPE = 4 + }; + tflite::TensorType output_type() const { + return static_cast(GetField(VT_OUTPUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_OUTPUT_TYPE, 1) && + verifier.EndTable(); + } + ArgMinOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ArgMinOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ArgMinOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ArgMinOptionsBuilder { + typedef ArgMinOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_output_type(tflite::TensorType output_type) { + fbb_.AddElement(ArgMinOptions::VT_OUTPUT_TYPE, static_cast(output_type), 0); + } + explicit ArgMinOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateArgMinOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::TensorType output_type = tflite::TensorType_FLOAT32) { + ArgMinOptionsBuilder builder_(_fbb); + builder_.add_output_type(output_type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateArgMinOptions(flatbuffers::FlatBufferBuilder &_fbb, const ArgMinOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct GreaterOptionsT : public flatbuffers::NativeTable { + typedef GreaterOptions TableType; +}; + +struct GreaterOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef GreaterOptionsT NativeTableType; + typedef GreaterOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + GreaterOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(GreaterOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const GreaterOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct GreaterOptionsBuilder { + typedef GreaterOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GreaterOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGreaterOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + GreaterOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateGreaterOptions(flatbuffers::FlatBufferBuilder &_fbb, const GreaterOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct GreaterEqualOptionsT : public flatbuffers::NativeTable { + typedef GreaterEqualOptions TableType; +}; + +struct GreaterEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef GreaterEqualOptionsT NativeTableType; + typedef GreaterEqualOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + GreaterEqualOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(GreaterEqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const GreaterEqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct GreaterEqualOptionsBuilder { + typedef GreaterEqualOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GreaterEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGreaterEqualOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + GreaterEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateGreaterEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const GreaterEqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LessOptionsT : public flatbuffers::NativeTable { + typedef LessOptions TableType; +}; + +struct LessOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LessOptionsT NativeTableType; + typedef LessOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + LessOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LessOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LessOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LessOptionsBuilder { + typedef LessOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LessOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLessOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + LessOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLessOptions(flatbuffers::FlatBufferBuilder &_fbb, const LessOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LessEqualOptionsT : public flatbuffers::NativeTable { + typedef LessEqualOptions TableType; +}; + +struct LessEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LessEqualOptionsT NativeTableType; + typedef LessEqualOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + LessEqualOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LessEqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LessEqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LessEqualOptionsBuilder { + typedef LessEqualOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LessEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLessEqualOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + LessEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLessEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const LessEqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct NegOptionsT : public flatbuffers::NativeTable { + typedef NegOptions TableType; +}; + +struct NegOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef NegOptionsT NativeTableType; + typedef NegOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + NegOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(NegOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const NegOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct NegOptionsBuilder { + typedef NegOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NegOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateNegOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + NegOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateNegOptions(flatbuffers::FlatBufferBuilder &_fbb, const NegOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SelectOptionsT : public flatbuffers::NativeTable { + typedef SelectOptions TableType; +}; + +struct SelectOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SelectOptionsT NativeTableType; + typedef SelectOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SelectOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SelectOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SelectOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SelectOptionsBuilder { + typedef SelectOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SelectOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSelectOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SelectOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSelectOptions(flatbuffers::FlatBufferBuilder &_fbb, const SelectOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SliceOptionsT : public flatbuffers::NativeTable { + typedef SliceOptions TableType; +}; + +struct SliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SliceOptionsT NativeTableType; + typedef SliceOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SliceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SliceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SliceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SliceOptionsBuilder { + typedef SliceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSliceOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SliceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, const SliceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TransposeConvOptionsT : public flatbuffers::NativeTable { + typedef TransposeConvOptions TableType; + tflite::Padding padding = tflite::Padding_SAME; + int32_t stride_w = 0; + int32_t stride_h = 0; +}; + +struct TransposeConvOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TransposeConvOptionsT NativeTableType; + typedef TransposeConvOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8 + }; + tflite::Padding padding() const { + return static_cast(GetField(VT_PADDING, 0)); + } + int32_t stride_w() const { + return GetField(VT_STRIDE_W, 0); + } + int32_t stride_h() const { + return GetField(VT_STRIDE_H, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_PADDING, 1) && + VerifyField(verifier, VT_STRIDE_W, 4) && + VerifyField(verifier, VT_STRIDE_H, 4) && + verifier.EndTable(); + } + TransposeConvOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TransposeConvOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TransposeConvOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TransposeConvOptionsBuilder { + typedef TransposeConvOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(tflite::Padding padding) { + fbb_.AddElement(TransposeConvOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) { + fbb_.AddElement(TransposeConvOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) { + fbb_.AddElement(TransposeConvOptions::VT_STRIDE_H, stride_h, 0); + } + explicit TransposeConvOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTransposeConvOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::Padding padding = tflite::Padding_SAME, + int32_t stride_w = 0, + int32_t stride_h = 0) { + TransposeConvOptionsBuilder builder_(_fbb); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_padding(padding); + return builder_.Finish(); +} + +flatbuffers::Offset CreateTransposeConvOptions(flatbuffers::FlatBufferBuilder &_fbb, const TransposeConvOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ExpandDimsOptionsT : public flatbuffers::NativeTable { + typedef ExpandDimsOptions TableType; +}; + +struct ExpandDimsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ExpandDimsOptionsT NativeTableType; + typedef ExpandDimsOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ExpandDimsOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ExpandDimsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ExpandDimsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ExpandDimsOptionsBuilder { + typedef ExpandDimsOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ExpandDimsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateExpandDimsOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + ExpandDimsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateExpandDimsOptions(flatbuffers::FlatBufferBuilder &_fbb, const ExpandDimsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SparseToDenseOptionsT : public flatbuffers::NativeTable { + typedef SparseToDenseOptions TableType; + bool validate_indices = false; +}; + +struct SparseToDenseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SparseToDenseOptionsT NativeTableType; + typedef SparseToDenseOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VALIDATE_INDICES = 4 + }; + bool validate_indices() const { + return GetField(VT_VALIDATE_INDICES, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_VALIDATE_INDICES, 1) && + verifier.EndTable(); + } + SparseToDenseOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SparseToDenseOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SparseToDenseOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SparseToDenseOptionsBuilder { + typedef SparseToDenseOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_validate_indices(bool validate_indices) { + fbb_.AddElement(SparseToDenseOptions::VT_VALIDATE_INDICES, static_cast(validate_indices), 0); + } + explicit SparseToDenseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSparseToDenseOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool validate_indices = false) { + SparseToDenseOptionsBuilder builder_(_fbb); + builder_.add_validate_indices(validate_indices); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSparseToDenseOptions(flatbuffers::FlatBufferBuilder &_fbb, const SparseToDenseOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct EqualOptionsT : public flatbuffers::NativeTable { + typedef EqualOptions TableType; +}; + +struct EqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef EqualOptionsT NativeTableType; + typedef EqualOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + EqualOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(EqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const EqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct EqualOptionsBuilder { + typedef EqualOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit EqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateEqualOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + EqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const EqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct NotEqualOptionsT : public flatbuffers::NativeTable { + typedef NotEqualOptions TableType; +}; + +struct NotEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef NotEqualOptionsT NativeTableType; + typedef NotEqualOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + NotEqualOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(NotEqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const NotEqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct NotEqualOptionsBuilder { + typedef NotEqualOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NotEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateNotEqualOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + NotEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateNotEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const NotEqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ShapeOptionsT : public flatbuffers::NativeTable { + typedef ShapeOptions TableType; + tflite::TensorType out_type = tflite::TensorType_FLOAT32; +}; + +struct ShapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ShapeOptionsT NativeTableType; + typedef ShapeOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_OUT_TYPE = 4 + }; + tflite::TensorType out_type() const { + return static_cast(GetField(VT_OUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_OUT_TYPE, 1) && + verifier.EndTable(); + } + ShapeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ShapeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ShapeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ShapeOptionsBuilder { + typedef ShapeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_out_type(tflite::TensorType out_type) { + fbb_.AddElement(ShapeOptions::VT_OUT_TYPE, static_cast(out_type), 0); + } + explicit ShapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateShapeOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::TensorType out_type = tflite::TensorType_FLOAT32) { + ShapeOptionsBuilder builder_(_fbb); + builder_.add_out_type(out_type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateShapeOptions(flatbuffers::FlatBufferBuilder &_fbb, const ShapeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct RankOptionsT : public flatbuffers::NativeTable { + typedef RankOptions TableType; +}; + +struct RankOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RankOptionsT NativeTableType; + typedef RankOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + RankOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(RankOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const RankOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct RankOptionsBuilder { + typedef RankOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit RankOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRankOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + RankOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateRankOptions(flatbuffers::FlatBufferBuilder &_fbb, const RankOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct PowOptionsT : public flatbuffers::NativeTable { + typedef PowOptions TableType; +}; + +struct PowOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef PowOptionsT NativeTableType; + typedef PowOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + PowOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(PowOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const PowOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct PowOptionsBuilder { + typedef PowOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PowOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePowOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + PowOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreatePowOptions(flatbuffers::FlatBufferBuilder &_fbb, const PowOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct FakeQuantOptionsT : public flatbuffers::NativeTable { + typedef FakeQuantOptions TableType; + float min = 0.0f; + float max = 0.0f; + int32_t num_bits = 0; + bool narrow_range = false; +}; + +struct FakeQuantOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FakeQuantOptionsT NativeTableType; + typedef FakeQuantOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_MIN = 4, + VT_MAX = 6, + VT_NUM_BITS = 8, + VT_NARROW_RANGE = 10 + }; + float min() const { + return GetField(VT_MIN, 0.0f); + } + float max() const { + return GetField(VT_MAX, 0.0f); + } + int32_t num_bits() const { + return GetField(VT_NUM_BITS, 0); + } + bool narrow_range() const { + return GetField(VT_NARROW_RANGE, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_MIN, 4) && + VerifyField(verifier, VT_MAX, 4) && + VerifyField(verifier, VT_NUM_BITS, 4) && + VerifyField(verifier, VT_NARROW_RANGE, 1) && + verifier.EndTable(); + } + FakeQuantOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FakeQuantOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const FakeQuantOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FakeQuantOptionsBuilder { + typedef FakeQuantOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_min(float min) { + fbb_.AddElement(FakeQuantOptions::VT_MIN, min, 0.0f); + } + void add_max(float max) { + fbb_.AddElement(FakeQuantOptions::VT_MAX, max, 0.0f); + } + void add_num_bits(int32_t num_bits) { + fbb_.AddElement(FakeQuantOptions::VT_NUM_BITS, num_bits, 0); + } + void add_narrow_range(bool narrow_range) { + fbb_.AddElement(FakeQuantOptions::VT_NARROW_RANGE, static_cast(narrow_range), 0); + } + explicit FakeQuantOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFakeQuantOptions( + flatbuffers::FlatBufferBuilder &_fbb, + float min = 0.0f, + float max = 0.0f, + int32_t num_bits = 0, + bool narrow_range = false) { + FakeQuantOptionsBuilder builder_(_fbb); + builder_.add_num_bits(num_bits); + builder_.add_max(max); + builder_.add_min(min); + builder_.add_narrow_range(narrow_range); + return builder_.Finish(); +} + +flatbuffers::Offset CreateFakeQuantOptions(flatbuffers::FlatBufferBuilder &_fbb, const FakeQuantOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct PackOptionsT : public flatbuffers::NativeTable { + typedef PackOptions TableType; + int32_t values_count = 0; + int32_t axis = 0; +}; + +struct PackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef PackOptionsT NativeTableType; + typedef PackOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VALUES_COUNT = 4, + VT_AXIS = 6 + }; + int32_t values_count() const { + return GetField(VT_VALUES_COUNT, 0); + } + int32_t axis() const { + return GetField(VT_AXIS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_VALUES_COUNT, 4) && + VerifyField(verifier, VT_AXIS, 4) && + verifier.EndTable(); + } + PackOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(PackOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const PackOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct PackOptionsBuilder { + typedef PackOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values_count(int32_t values_count) { + fbb_.AddElement(PackOptions::VT_VALUES_COUNT, values_count, 0); + } + void add_axis(int32_t axis) { + fbb_.AddElement(PackOptions::VT_AXIS, axis, 0); + } + explicit PackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePackOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t values_count = 0, + int32_t axis = 0) { + PackOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_values_count(values_count); + return builder_.Finish(); +} + +flatbuffers::Offset CreatePackOptions(flatbuffers::FlatBufferBuilder &_fbb, const PackOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LogicalOrOptionsT : public flatbuffers::NativeTable { + typedef LogicalOrOptions TableType; +}; + +struct LogicalOrOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LogicalOrOptionsT NativeTableType; + typedef LogicalOrOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + LogicalOrOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LogicalOrOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogicalOrOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LogicalOrOptionsBuilder { + typedef LogicalOrOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalOrOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLogicalOrOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + LogicalOrOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLogicalOrOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogicalOrOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct OneHotOptionsT : public flatbuffers::NativeTable { + typedef OneHotOptions TableType; + int32_t axis = 0; +}; + +struct OneHotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef OneHotOptionsT NativeTableType; + typedef OneHotOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_AXIS = 4 + }; + int32_t axis() const { + return GetField(VT_AXIS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_AXIS, 4) && + verifier.EndTable(); + } + OneHotOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(OneHotOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const OneHotOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct OneHotOptionsBuilder { + typedef OneHotOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { + fbb_.AddElement(OneHotOptions::VT_AXIS, axis, 0); + } + explicit OneHotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateOneHotOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0) { + OneHotOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + return builder_.Finish(); +} + +flatbuffers::Offset CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb, const OneHotOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AbsOptionsT : public flatbuffers::NativeTable { + typedef AbsOptions TableType; +}; + +struct AbsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AbsOptionsT NativeTableType; + typedef AbsOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + AbsOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AbsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AbsOptionsBuilder { + typedef AbsOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AbsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAbsOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + AbsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct HardSwishOptionsT : public flatbuffers::NativeTable { + typedef HardSwishOptions TableType; +}; + +struct HardSwishOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef HardSwishOptionsT NativeTableType; + typedef HardSwishOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + HardSwishOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(HardSwishOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const HardSwishOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct HardSwishOptionsBuilder { + typedef HardSwishOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit HardSwishOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateHardSwishOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + HardSwishOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateHardSwishOptions(flatbuffers::FlatBufferBuilder &_fbb, const HardSwishOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LogicalAndOptionsT : public flatbuffers::NativeTable { + typedef LogicalAndOptions TableType; +}; + +struct LogicalAndOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LogicalAndOptionsT NativeTableType; + typedef LogicalAndOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + LogicalAndOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LogicalAndOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogicalAndOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LogicalAndOptionsBuilder { + typedef LogicalAndOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalAndOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLogicalAndOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + LogicalAndOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLogicalAndOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogicalAndOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LogicalNotOptionsT : public flatbuffers::NativeTable { + typedef LogicalNotOptions TableType; +}; + +struct LogicalNotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LogicalNotOptionsT NativeTableType; + typedef LogicalNotOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + LogicalNotOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LogicalNotOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogicalNotOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LogicalNotOptionsBuilder { + typedef LogicalNotOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalNotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLogicalNotOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + LogicalNotOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLogicalNotOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogicalNotOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UnpackOptionsT : public flatbuffers::NativeTable { + typedef UnpackOptions TableType; + int32_t num = 0; + int32_t axis = 0; +}; + +struct UnpackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UnpackOptionsT NativeTableType; + typedef UnpackOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NUM = 4, + VT_AXIS = 6 + }; + int32_t num() const { + return GetField(VT_NUM, 0); + } + int32_t axis() const { + return GetField(VT_AXIS, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_NUM, 4) && + VerifyField(verifier, VT_AXIS, 4) && + verifier.EndTable(); + } + UnpackOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UnpackOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnpackOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UnpackOptionsBuilder { + typedef UnpackOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num(int32_t num) { + fbb_.AddElement(UnpackOptions::VT_NUM, num, 0); + } + void add_axis(int32_t axis) { + fbb_.AddElement(UnpackOptions::VT_AXIS, axis, 0); + } + explicit UnpackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnpackOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t num = 0, + int32_t axis = 0) { + UnpackOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_num(num); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUnpackOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnpackOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct FloorDivOptionsT : public flatbuffers::NativeTable { + typedef FloorDivOptions TableType; +}; + +struct FloorDivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FloorDivOptionsT NativeTableType; + typedef FloorDivOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + FloorDivOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FloorDivOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const FloorDivOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FloorDivOptionsBuilder { + typedef FloorDivOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FloorDivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFloorDivOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + FloorDivOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateFloorDivOptions(flatbuffers::FlatBufferBuilder &_fbb, const FloorDivOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SquareOptionsT : public flatbuffers::NativeTable { + typedef SquareOptions TableType; +}; + +struct SquareOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SquareOptionsT NativeTableType; + typedef SquareOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SquareOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SquareOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SquareOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SquareOptionsBuilder { + typedef SquareOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SquareOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSquareOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SquareOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSquareOptions(flatbuffers::FlatBufferBuilder &_fbb, const SquareOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ZerosLikeOptionsT : public flatbuffers::NativeTable { + typedef ZerosLikeOptions TableType; +}; + +struct ZerosLikeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ZerosLikeOptionsT NativeTableType; + typedef ZerosLikeOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ZerosLikeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ZerosLikeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ZerosLikeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ZerosLikeOptionsBuilder { + typedef ZerosLikeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ZerosLikeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateZerosLikeOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + ZerosLikeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateZerosLikeOptions(flatbuffers::FlatBufferBuilder &_fbb, const ZerosLikeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct FillOptionsT : public flatbuffers::NativeTable { + typedef FillOptions TableType; +}; + +struct FillOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FillOptionsT NativeTableType; + typedef FillOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + FillOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FillOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const FillOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FillOptionsBuilder { + typedef FillOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FillOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFillOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + FillOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateFillOptions(flatbuffers::FlatBufferBuilder &_fbb, const FillOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct FloorModOptionsT : public flatbuffers::NativeTable { + typedef FloorModOptions TableType; +}; + +struct FloorModOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FloorModOptionsT NativeTableType; + typedef FloorModOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + FloorModOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(FloorModOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const FloorModOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct FloorModOptionsBuilder { + typedef FloorModOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FloorModOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFloorModOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + FloorModOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateFloorModOptions(flatbuffers::FlatBufferBuilder &_fbb, const FloorModOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct RangeOptionsT : public flatbuffers::NativeTable { + typedef RangeOptions TableType; +}; + +struct RangeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RangeOptionsT NativeTableType; + typedef RangeOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + RangeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(RangeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const RangeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct RangeOptionsBuilder { + typedef RangeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit RangeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRangeOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + RangeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateRangeOptions(flatbuffers::FlatBufferBuilder &_fbb, const RangeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct LeakyReluOptionsT : public flatbuffers::NativeTable { + typedef LeakyReluOptions TableType; + float alpha = 0.0f; +}; + +struct LeakyReluOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef LeakyReluOptionsT NativeTableType; + typedef LeakyReluOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ALPHA = 4 + }; + float alpha() const { + return GetField(VT_ALPHA, 0.0f); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ALPHA, 4) && + verifier.EndTable(); + } + LeakyReluOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(LeakyReluOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const LeakyReluOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct LeakyReluOptionsBuilder { + typedef LeakyReluOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_alpha(float alpha) { + fbb_.AddElement(LeakyReluOptions::VT_ALPHA, alpha, 0.0f); + } + explicit LeakyReluOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLeakyReluOptions( + flatbuffers::FlatBufferBuilder &_fbb, + float alpha = 0.0f) { + LeakyReluOptionsBuilder builder_(_fbb); + builder_.add_alpha(alpha); + return builder_.Finish(); +} + +flatbuffers::Offset CreateLeakyReluOptions(flatbuffers::FlatBufferBuilder &_fbb, const LeakyReluOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SquaredDifferenceOptionsT : public flatbuffers::NativeTable { + typedef SquaredDifferenceOptions TableType; +}; + +struct SquaredDifferenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SquaredDifferenceOptionsT NativeTableType; + typedef SquaredDifferenceOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SquaredDifferenceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SquaredDifferenceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SquaredDifferenceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SquaredDifferenceOptionsBuilder { + typedef SquaredDifferenceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SquaredDifferenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSquaredDifferenceOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SquaredDifferenceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb, const SquaredDifferenceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MirrorPadOptionsT : public flatbuffers::NativeTable { + typedef MirrorPadOptions TableType; + tflite::MirrorPadMode mode = tflite::MirrorPadMode_REFLECT; +}; + +struct MirrorPadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MirrorPadOptionsT NativeTableType; + typedef MirrorPadOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_MODE = 4 + }; + tflite::MirrorPadMode mode() const { + return static_cast(GetField(VT_MODE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_MODE, 1) && + verifier.EndTable(); + } + MirrorPadOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MirrorPadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MirrorPadOptionsBuilder { + typedef MirrorPadOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_mode(tflite::MirrorPadMode mode) { + fbb_.AddElement(MirrorPadOptions::VT_MODE, static_cast(mode), 0); + } + explicit MirrorPadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMirrorPadOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::MirrorPadMode mode = tflite::MirrorPadMode_REFLECT) { + MirrorPadOptionsBuilder builder_(_fbb); + builder_.add_mode(mode); + return builder_.Finish(); +} + +flatbuffers::Offset CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UniqueOptionsT : public flatbuffers::NativeTable { + typedef UniqueOptions TableType; + tflite::TensorType idx_out_type = tflite::TensorType_INT32; +}; + +struct UniqueOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UniqueOptionsT NativeTableType; + typedef UniqueOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_IDX_OUT_TYPE = 4 + }; + tflite::TensorType idx_out_type() const { + return static_cast(GetField(VT_IDX_OUT_TYPE, 2)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_IDX_OUT_TYPE, 1) && + verifier.EndTable(); + } + UniqueOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UniqueOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UniqueOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UniqueOptionsBuilder { + typedef UniqueOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_idx_out_type(tflite::TensorType idx_out_type) { + fbb_.AddElement(UniqueOptions::VT_IDX_OUT_TYPE, static_cast(idx_out_type), 2); + } + explicit UniqueOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUniqueOptions( + flatbuffers::FlatBufferBuilder &_fbb, + tflite::TensorType idx_out_type = tflite::TensorType_INT32) { + UniqueOptionsBuilder builder_(_fbb); + builder_.add_idx_out_type(idx_out_type); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUniqueOptions(flatbuffers::FlatBufferBuilder &_fbb, const UniqueOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ReverseV2OptionsT : public flatbuffers::NativeTable { + typedef ReverseV2Options TableType; +}; + +struct ReverseV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ReverseV2OptionsT NativeTableType; + typedef ReverseV2OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ReverseV2OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ReverseV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReverseV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ReverseV2OptionsBuilder { + typedef ReverseV2Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ReverseV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateReverseV2Options( + flatbuffers::FlatBufferBuilder &_fbb) { + ReverseV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateReverseV2Options(flatbuffers::FlatBufferBuilder &_fbb, const ReverseV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AddNOptionsT : public flatbuffers::NativeTable { + typedef AddNOptions TableType; +}; + +struct AddNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AddNOptionsT NativeTableType; + typedef AddNOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + AddNOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AddNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AddNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AddNOptionsBuilder { + typedef AddNOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AddNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAddNOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + AddNOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateAddNOptions(flatbuffers::FlatBufferBuilder &_fbb, const AddNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct GatherNdOptionsT : public flatbuffers::NativeTable { + typedef GatherNdOptions TableType; +}; + +struct GatherNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef GatherNdOptionsT NativeTableType; + typedef GatherNdOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + GatherNdOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(GatherNdOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const GatherNdOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct GatherNdOptionsBuilder { + typedef GatherNdOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GatherNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGatherNdOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + GatherNdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateGatherNdOptions(flatbuffers::FlatBufferBuilder &_fbb, const GatherNdOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct WhereOptionsT : public flatbuffers::NativeTable { + typedef WhereOptions TableType; +}; + +struct WhereOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef WhereOptionsT NativeTableType; + typedef WhereOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + WhereOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(WhereOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const WhereOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct WhereOptionsBuilder { + typedef WhereOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit WhereOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWhereOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + WhereOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateWhereOptions(flatbuffers::FlatBufferBuilder &_fbb, const WhereOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ReverseSequenceOptionsT : public flatbuffers::NativeTable { + typedef ReverseSequenceOptions TableType; + int32_t seq_dim = 0; + int32_t batch_dim = 0; +}; + +struct ReverseSequenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ReverseSequenceOptionsT NativeTableType; + typedef ReverseSequenceOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SEQ_DIM = 4, + VT_BATCH_DIM = 6 + }; + int32_t seq_dim() const { + return GetField(VT_SEQ_DIM, 0); + } + int32_t batch_dim() const { + return GetField(VT_BATCH_DIM, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SEQ_DIM, 4) && + VerifyField(verifier, VT_BATCH_DIM, 4) && + verifier.EndTable(); + } + ReverseSequenceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ReverseSequenceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReverseSequenceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ReverseSequenceOptionsBuilder { + typedef ReverseSequenceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_seq_dim(int32_t seq_dim) { + fbb_.AddElement(ReverseSequenceOptions::VT_SEQ_DIM, seq_dim, 0); + } + void add_batch_dim(int32_t batch_dim) { + fbb_.AddElement(ReverseSequenceOptions::VT_BATCH_DIM, batch_dim, 0); + } + explicit ReverseSequenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateReverseSequenceOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t seq_dim = 0, + int32_t batch_dim = 0) { + ReverseSequenceOptionsBuilder builder_(_fbb); + builder_.add_batch_dim(batch_dim); + builder_.add_seq_dim(seq_dim); + return builder_.Finish(); +} + +flatbuffers::Offset CreateReverseSequenceOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReverseSequenceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MatrixDiagOptionsT : public flatbuffers::NativeTable { + typedef MatrixDiagOptions TableType; +}; + +struct MatrixDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MatrixDiagOptionsT NativeTableType; + typedef MatrixDiagOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + MatrixDiagOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MatrixDiagOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MatrixDiagOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MatrixDiagOptionsBuilder { + typedef MatrixDiagOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MatrixDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMatrixDiagOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + MatrixDiagOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateMatrixDiagOptions(flatbuffers::FlatBufferBuilder &_fbb, const MatrixDiagOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct QuantizeOptionsT : public flatbuffers::NativeTable { + typedef QuantizeOptions TableType; +}; + +struct QuantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef QuantizeOptionsT NativeTableType; + typedef QuantizeOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + QuantizeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(QuantizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const QuantizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct QuantizeOptionsBuilder { + typedef QuantizeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit QuantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateQuantizeOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + QuantizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateQuantizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const QuantizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MatrixSetDiagOptionsT : public flatbuffers::NativeTable { + typedef MatrixSetDiagOptions TableType; +}; + +struct MatrixSetDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MatrixSetDiagOptionsT NativeTableType; + typedef MatrixSetDiagOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + MatrixSetDiagOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MatrixSetDiagOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MatrixSetDiagOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MatrixSetDiagOptionsBuilder { + typedef MatrixSetDiagOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MatrixSetDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMatrixSetDiagOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + MatrixSetDiagOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateMatrixSetDiagOptions(flatbuffers::FlatBufferBuilder &_fbb, const MatrixSetDiagOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct IfOptionsT : public flatbuffers::NativeTable { + typedef IfOptions TableType; + int32_t then_subgraph_index = 0; + int32_t else_subgraph_index = 0; +}; + +struct IfOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef IfOptionsT NativeTableType; + typedef IfOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_THEN_SUBGRAPH_INDEX = 4, + VT_ELSE_SUBGRAPH_INDEX = 6 + }; + int32_t then_subgraph_index() const { + return GetField(VT_THEN_SUBGRAPH_INDEX, 0); + } + int32_t else_subgraph_index() const { + return GetField(VT_ELSE_SUBGRAPH_INDEX, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_THEN_SUBGRAPH_INDEX, 4) && + VerifyField(verifier, VT_ELSE_SUBGRAPH_INDEX, 4) && + verifier.EndTable(); + } + IfOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(IfOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const IfOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct IfOptionsBuilder { + typedef IfOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_then_subgraph_index(int32_t then_subgraph_index) { + fbb_.AddElement(IfOptions::VT_THEN_SUBGRAPH_INDEX, then_subgraph_index, 0); + } + void add_else_subgraph_index(int32_t else_subgraph_index) { + fbb_.AddElement(IfOptions::VT_ELSE_SUBGRAPH_INDEX, else_subgraph_index, 0); + } + explicit IfOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateIfOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t then_subgraph_index = 0, + int32_t else_subgraph_index = 0) { + IfOptionsBuilder builder_(_fbb); + builder_.add_else_subgraph_index(else_subgraph_index); + builder_.add_then_subgraph_index(then_subgraph_index); + return builder_.Finish(); +} + +flatbuffers::Offset CreateIfOptions(flatbuffers::FlatBufferBuilder &_fbb, const IfOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct CallOnceOptionsT : public flatbuffers::NativeTable { + typedef CallOnceOptions TableType; + int32_t init_subgraph_index = 0; +}; + +struct CallOnceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CallOnceOptionsT NativeTableType; + typedef CallOnceOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_INIT_SUBGRAPH_INDEX = 4 + }; + int32_t init_subgraph_index() const { + return GetField(VT_INIT_SUBGRAPH_INDEX, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_INIT_SUBGRAPH_INDEX, 4) && + verifier.EndTable(); + } + CallOnceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CallOnceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const CallOnceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CallOnceOptionsBuilder { + typedef CallOnceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_init_subgraph_index(int32_t init_subgraph_index) { + fbb_.AddElement(CallOnceOptions::VT_INIT_SUBGRAPH_INDEX, init_subgraph_index, 0); + } + explicit CallOnceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCallOnceOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t init_subgraph_index = 0) { + CallOnceOptionsBuilder builder_(_fbb); + builder_.add_init_subgraph_index(init_subgraph_index); + return builder_.Finish(); +} + +flatbuffers::Offset CreateCallOnceOptions(flatbuffers::FlatBufferBuilder &_fbb, const CallOnceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct WhileOptionsT : public flatbuffers::NativeTable { + typedef WhileOptions TableType; + int32_t cond_subgraph_index = 0; + int32_t body_subgraph_index = 0; +}; + +struct WhileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef WhileOptionsT NativeTableType; + typedef WhileOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_COND_SUBGRAPH_INDEX = 4, + VT_BODY_SUBGRAPH_INDEX = 6 + }; + int32_t cond_subgraph_index() const { + return GetField(VT_COND_SUBGRAPH_INDEX, 0); + } + int32_t body_subgraph_index() const { + return GetField(VT_BODY_SUBGRAPH_INDEX, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_COND_SUBGRAPH_INDEX, 4) && + VerifyField(verifier, VT_BODY_SUBGRAPH_INDEX, 4) && + verifier.EndTable(); + } + WhileOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(WhileOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const WhileOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct WhileOptionsBuilder { + typedef WhileOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_cond_subgraph_index(int32_t cond_subgraph_index) { + fbb_.AddElement(WhileOptions::VT_COND_SUBGRAPH_INDEX, cond_subgraph_index, 0); + } + void add_body_subgraph_index(int32_t body_subgraph_index) { + fbb_.AddElement(WhileOptions::VT_BODY_SUBGRAPH_INDEX, body_subgraph_index, 0); + } + explicit WhileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWhileOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t cond_subgraph_index = 0, + int32_t body_subgraph_index = 0) { + WhileOptionsBuilder builder_(_fbb); + builder_.add_body_subgraph_index(body_subgraph_index); + builder_.add_cond_subgraph_index(cond_subgraph_index); + return builder_.Finish(); +} + +flatbuffers::Offset CreateWhileOptions(flatbuffers::FlatBufferBuilder &_fbb, const WhileOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct NonMaxSuppressionV4OptionsT : public flatbuffers::NativeTable { + typedef NonMaxSuppressionV4Options TableType; +}; + +struct NonMaxSuppressionV4Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef NonMaxSuppressionV4OptionsT NativeTableType; + typedef NonMaxSuppressionV4OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + NonMaxSuppressionV4OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(NonMaxSuppressionV4OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV4OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct NonMaxSuppressionV4OptionsBuilder { + typedef NonMaxSuppressionV4Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NonMaxSuppressionV4OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateNonMaxSuppressionV4Options( + flatbuffers::FlatBufferBuilder &_fbb) { + NonMaxSuppressionV4OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateNonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV4OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct NonMaxSuppressionV5OptionsT : public flatbuffers::NativeTable { + typedef NonMaxSuppressionV5Options TableType; +}; + +struct NonMaxSuppressionV5Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef NonMaxSuppressionV5OptionsT NativeTableType; + typedef NonMaxSuppressionV5OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + NonMaxSuppressionV5OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(NonMaxSuppressionV5OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV5OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct NonMaxSuppressionV5OptionsBuilder { + typedef NonMaxSuppressionV5Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NonMaxSuppressionV5OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateNonMaxSuppressionV5Options( + flatbuffers::FlatBufferBuilder &_fbb) { + NonMaxSuppressionV5OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateNonMaxSuppressionV5Options(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV5OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ScatterNdOptionsT : public flatbuffers::NativeTable { + typedef ScatterNdOptions TableType; +}; + +struct ScatterNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ScatterNdOptionsT NativeTableType; + typedef ScatterNdOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ScatterNdOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ScatterNdOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ScatterNdOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ScatterNdOptionsBuilder { + typedef ScatterNdOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ScatterNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateScatterNdOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + ScatterNdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateScatterNdOptions(flatbuffers::FlatBufferBuilder &_fbb, const ScatterNdOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SelectV2OptionsT : public flatbuffers::NativeTable { + typedef SelectV2Options TableType; +}; + +struct SelectV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SelectV2OptionsT NativeTableType; + typedef SelectV2OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SelectV2OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SelectV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SelectV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SelectV2OptionsBuilder { + typedef SelectV2Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SelectV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSelectV2Options( + flatbuffers::FlatBufferBuilder &_fbb) { + SelectV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSelectV2Options(flatbuffers::FlatBufferBuilder &_fbb, const SelectV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DensifyOptionsT : public flatbuffers::NativeTable { + typedef DensifyOptions TableType; +}; + +struct DensifyOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DensifyOptionsT NativeTableType; + typedef DensifyOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + DensifyOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DensifyOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DensifyOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct DensifyOptionsBuilder { + typedef DensifyOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DensifyOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDensifyOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + DensifyOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDensifyOptions(flatbuffers::FlatBufferBuilder &_fbb, const DensifyOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SegmentSumOptionsT : public flatbuffers::NativeTable { + typedef SegmentSumOptions TableType; +}; + +struct SegmentSumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SegmentSumOptionsT NativeTableType; + typedef SegmentSumOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SegmentSumOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SegmentSumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SegmentSumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SegmentSumOptionsBuilder { + typedef SegmentSumOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SegmentSumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSegmentSumOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SegmentSumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb, const SegmentSumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BatchMatMulOptionsT : public flatbuffers::NativeTable { + typedef BatchMatMulOptions TableType; + bool adj_x = false; + bool adj_y = false; + bool asymmetric_quantize_inputs = false; +}; + +struct BatchMatMulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BatchMatMulOptionsT NativeTableType; + typedef BatchMatMulOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_ADJ_X = 4, + VT_ADJ_Y = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + bool adj_x() const { + return GetField(VT_ADJ_X, 0) != 0; + } + bool adj_y() const { + return GetField(VT_ADJ_Y, 0) != 0; + } + bool asymmetric_quantize_inputs() const { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_ADJ_X, 1) && + VerifyField(verifier, VT_ADJ_Y, 1) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS, 1) && + verifier.EndTable(); + } + BatchMatMulOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BatchMatMulOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BatchMatMulOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BatchMatMulOptionsBuilder { + typedef BatchMatMulOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_adj_x(bool adj_x) { + fbb_.AddElement(BatchMatMulOptions::VT_ADJ_X, static_cast(adj_x), 0); + } + void add_adj_y(bool adj_y) { + fbb_.AddElement(BatchMatMulOptions::VT_ADJ_Y, static_cast(adj_y), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) { + fbb_.AddElement(BatchMatMulOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, static_cast(asymmetric_quantize_inputs), 0); + } + explicit BatchMatMulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBatchMatMulOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool adj_x = false, + bool adj_y = false, + bool asymmetric_quantize_inputs = false) { + BatchMatMulOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_adj_y(adj_y); + builder_.add_adj_x(adj_x); + return builder_.Finish(); +} + +flatbuffers::Offset CreateBatchMatMulOptions(flatbuffers::FlatBufferBuilder &_fbb, const BatchMatMulOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct CumsumOptionsT : public flatbuffers::NativeTable { + typedef CumsumOptions TableType; + bool exclusive = false; + bool reverse = false; +}; + +struct CumsumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef CumsumOptionsT NativeTableType; + typedef CumsumOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_EXCLUSIVE = 4, + VT_REVERSE = 6 + }; + bool exclusive() const { + return GetField(VT_EXCLUSIVE, 0) != 0; + } + bool reverse() const { + return GetField(VT_REVERSE, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_EXCLUSIVE, 1) && + VerifyField(verifier, VT_REVERSE, 1) && + verifier.EndTable(); + } + CumsumOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(CumsumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const CumsumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct CumsumOptionsBuilder { + typedef CumsumOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_exclusive(bool exclusive) { + fbb_.AddElement(CumsumOptions::VT_EXCLUSIVE, static_cast(exclusive), 0); + } + void add_reverse(bool reverse) { + fbb_.AddElement(CumsumOptions::VT_REVERSE, static_cast(reverse), 0); + } + explicit CumsumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCumsumOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool exclusive = false, + bool reverse = false) { + CumsumOptionsBuilder builder_(_fbb); + builder_.add_reverse(reverse); + builder_.add_exclusive(exclusive); + return builder_.Finish(); +} + +flatbuffers::Offset CreateCumsumOptions(flatbuffers::FlatBufferBuilder &_fbb, const CumsumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BroadcastToOptionsT : public flatbuffers::NativeTable { + typedef BroadcastToOptions TableType; +}; + +struct BroadcastToOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BroadcastToOptionsT NativeTableType; + typedef BroadcastToOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + BroadcastToOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BroadcastToOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BroadcastToOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BroadcastToOptionsBuilder { + typedef BroadcastToOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit BroadcastToOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBroadcastToOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + BroadcastToOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateBroadcastToOptions(flatbuffers::FlatBufferBuilder &_fbb, const BroadcastToOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct Rfft2dOptionsT : public flatbuffers::NativeTable { + typedef Rfft2dOptions TableType; +}; + +struct Rfft2dOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef Rfft2dOptionsT NativeTableType; + typedef Rfft2dOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + Rfft2dOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(Rfft2dOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const Rfft2dOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct Rfft2dOptionsBuilder { + typedef Rfft2dOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit Rfft2dOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRfft2dOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + Rfft2dOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateRfft2dOptions(flatbuffers::FlatBufferBuilder &_fbb, const Rfft2dOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct HashtableOptionsT : public flatbuffers::NativeTable { + typedef HashtableOptions TableType; + int32_t table_id = 0; + tflite::TensorType key_dtype = tflite::TensorType_FLOAT32; + tflite::TensorType value_dtype = tflite::TensorType_FLOAT32; +}; + +struct HashtableOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef HashtableOptionsT NativeTableType; + typedef HashtableOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TABLE_ID = 4, + VT_KEY_DTYPE = 6, + VT_VALUE_DTYPE = 8 + }; + int32_t table_id() const { + return GetField(VT_TABLE_ID, 0); + } + tflite::TensorType key_dtype() const { + return static_cast(GetField(VT_KEY_DTYPE, 0)); + } + tflite::TensorType value_dtype() const { + return static_cast(GetField(VT_VALUE_DTYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_TABLE_ID, 4) && + VerifyField(verifier, VT_KEY_DTYPE, 1) && + VerifyField(verifier, VT_VALUE_DTYPE, 1) && + verifier.EndTable(); + } + HashtableOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(HashtableOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct HashtableOptionsBuilder { + typedef HashtableOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_table_id(int32_t table_id) { + fbb_.AddElement(HashtableOptions::VT_TABLE_ID, table_id, 0); + } + void add_key_dtype(tflite::TensorType key_dtype) { + fbb_.AddElement(HashtableOptions::VT_KEY_DTYPE, static_cast(key_dtype), 0); + } + void add_value_dtype(tflite::TensorType value_dtype) { + fbb_.AddElement(HashtableOptions::VT_VALUE_DTYPE, static_cast(value_dtype), 0); + } + explicit HashtableOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateHashtableOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int32_t table_id = 0, + tflite::TensorType key_dtype = tflite::TensorType_FLOAT32, + tflite::TensorType value_dtype = tflite::TensorType_FLOAT32) { + HashtableOptionsBuilder builder_(_fbb); + builder_.add_table_id(table_id); + builder_.add_value_dtype(value_dtype); + builder_.add_key_dtype(key_dtype); + return builder_.Finish(); +} + +flatbuffers::Offset CreateHashtableOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct HashtableFindOptionsT : public flatbuffers::NativeTable { + typedef HashtableFindOptions TableType; +}; + +struct HashtableFindOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef HashtableFindOptionsT NativeTableType; + typedef HashtableFindOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + HashtableFindOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(HashtableFindOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableFindOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct HashtableFindOptionsBuilder { + typedef HashtableFindOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit HashtableFindOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateHashtableFindOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + HashtableFindOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateHashtableFindOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableFindOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct HashtableImportOptionsT : public flatbuffers::NativeTable { + typedef HashtableImportOptions TableType; +}; + +struct HashtableImportOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef HashtableImportOptionsT NativeTableType; + typedef HashtableImportOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + HashtableImportOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(HashtableImportOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableImportOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct HashtableImportOptionsBuilder { + typedef HashtableImportOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit HashtableImportOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateHashtableImportOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + HashtableImportOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateHashtableImportOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableImportOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct HashtableSizeOptionsT : public flatbuffers::NativeTable { + typedef HashtableSizeOptions TableType; +}; + +struct HashtableSizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef HashtableSizeOptionsT NativeTableType; + typedef HashtableSizeOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + HashtableSizeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(HashtableSizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableSizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct HashtableSizeOptionsBuilder { + typedef HashtableSizeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit HashtableSizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateHashtableSizeOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + HashtableSizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateHashtableSizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableSizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct VarHandleOptionsT : public flatbuffers::NativeTable { + typedef VarHandleOptions TableType; + std::string container{}; + std::string shared_name{}; +}; + +struct VarHandleOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef VarHandleOptionsT NativeTableType; + typedef VarHandleOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_CONTAINER = 4, + VT_SHARED_NAME = 6 + }; + const flatbuffers::String *container() const { + return GetPointer(VT_CONTAINER); + } + const flatbuffers::String *shared_name() const { + return GetPointer(VT_SHARED_NAME); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_CONTAINER) && + verifier.VerifyString(container()) && + VerifyOffset(verifier, VT_SHARED_NAME) && + verifier.VerifyString(shared_name()) && + verifier.EndTable(); + } + VarHandleOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(VarHandleOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const VarHandleOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct VarHandleOptionsBuilder { + typedef VarHandleOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_container(flatbuffers::Offset container) { + fbb_.AddOffset(VarHandleOptions::VT_CONTAINER, container); + } + void add_shared_name(flatbuffers::Offset shared_name) { + fbb_.AddOffset(VarHandleOptions::VT_SHARED_NAME, shared_name); + } + explicit VarHandleOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateVarHandleOptions( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset container = 0, + flatbuffers::Offset shared_name = 0) { + VarHandleOptionsBuilder builder_(_fbb); + builder_.add_shared_name(shared_name); + builder_.add_container(container); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateVarHandleOptionsDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *container = nullptr, + const char *shared_name = nullptr) { + auto container__ = container ? _fbb.CreateString(container) : 0; + auto shared_name__ = shared_name ? _fbb.CreateString(shared_name) : 0; + return tflite::CreateVarHandleOptions( + _fbb, + container__, + shared_name__); +} + +flatbuffers::Offset CreateVarHandleOptions(flatbuffers::FlatBufferBuilder &_fbb, const VarHandleOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ReadVariableOptionsT : public flatbuffers::NativeTable { + typedef ReadVariableOptions TableType; +}; + +struct ReadVariableOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ReadVariableOptionsT NativeTableType; + typedef ReadVariableOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ReadVariableOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ReadVariableOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReadVariableOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ReadVariableOptionsBuilder { + typedef ReadVariableOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ReadVariableOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateReadVariableOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + ReadVariableOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateReadVariableOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReadVariableOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct AssignVariableOptionsT : public flatbuffers::NativeTable { + typedef AssignVariableOptions TableType; +}; + +struct AssignVariableOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef AssignVariableOptionsT NativeTableType; + typedef AssignVariableOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + AssignVariableOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(AssignVariableOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const AssignVariableOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct AssignVariableOptionsBuilder { + typedef AssignVariableOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AssignVariableOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAssignVariableOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + AssignVariableOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateAssignVariableOptions(flatbuffers::FlatBufferBuilder &_fbb, const AssignVariableOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct RandomOptionsT : public flatbuffers::NativeTable { + typedef RandomOptions TableType; + int64_t seed = 0; + int64_t seed2 = 0; +}; + +struct RandomOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RandomOptionsT NativeTableType; + typedef RandomOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_SEED = 4, + VT_SEED2 = 6 + }; + int64_t seed() const { + return GetField(VT_SEED, 0); + } + int64_t seed2() const { + return GetField(VT_SEED2, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_SEED, 8) && + VerifyField(verifier, VT_SEED2, 8) && + verifier.EndTable(); + } + RandomOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(RandomOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const RandomOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct RandomOptionsBuilder { + typedef RandomOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_seed(int64_t seed) { + fbb_.AddElement(RandomOptions::VT_SEED, seed, 0); + } + void add_seed2(int64_t seed2) { + fbb_.AddElement(RandomOptions::VT_SEED2, seed2, 0); + } + explicit RandomOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRandomOptions( + flatbuffers::FlatBufferBuilder &_fbb, + int64_t seed = 0, + int64_t seed2 = 0) { + RandomOptionsBuilder builder_(_fbb); + builder_.add_seed2(seed2); + builder_.add_seed(seed); + return builder_.Finish(); +} + +flatbuffers::Offset CreateRandomOptions(flatbuffers::FlatBufferBuilder &_fbb, const RandomOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BucketizeOptionsT : public flatbuffers::NativeTable { + typedef BucketizeOptions TableType; + std::vector boundaries{}; +}; + +struct BucketizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BucketizeOptionsT NativeTableType; + typedef BucketizeOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BOUNDARIES = 4 + }; + const flatbuffers::Vector *boundaries() const { + return GetPointer *>(VT_BOUNDARIES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_BOUNDARIES) && + verifier.VerifyVector(boundaries()) && + verifier.EndTable(); + } + BucketizeOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BucketizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BucketizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BucketizeOptionsBuilder { + typedef BucketizeOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_boundaries(flatbuffers::Offset> boundaries) { + fbb_.AddOffset(BucketizeOptions::VT_BOUNDARIES, boundaries); + } + explicit BucketizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBucketizeOptions( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> boundaries = 0) { + BucketizeOptionsBuilder builder_(_fbb); + builder_.add_boundaries(boundaries); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateBucketizeOptionsDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *boundaries = nullptr) { + auto boundaries__ = boundaries ? _fbb.CreateVector(*boundaries) : 0; + return tflite::CreateBucketizeOptions( + _fbb, + boundaries__); +} + +flatbuffers::Offset CreateBucketizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const BucketizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct GeluOptionsT : public flatbuffers::NativeTable { + typedef GeluOptions TableType; + bool approximate = false; +}; + +struct GeluOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef GeluOptionsT NativeTableType; + typedef GeluOptionsBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_APPROXIMATE = 4 + }; + bool approximate() const { + return GetField(VT_APPROXIMATE, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_APPROXIMATE, 1) && + verifier.EndTable(); + } + GeluOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(GeluOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const GeluOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct GeluOptionsBuilder { + typedef GeluOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_approximate(bool approximate) { + fbb_.AddElement(GeluOptions::VT_APPROXIMATE, static_cast(approximate), 0); + } + explicit GeluOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGeluOptions( + flatbuffers::FlatBufferBuilder &_fbb, + bool approximate = false) { + GeluOptionsBuilder builder_(_fbb); + builder_.add_approximate(approximate); + return builder_.Finish(); +} + +flatbuffers::Offset CreateGeluOptions(flatbuffers::FlatBufferBuilder &_fbb, const GeluOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct DynamicUpdateSliceOptionsT : public flatbuffers::NativeTable { + typedef DynamicUpdateSliceOptions TableType; +}; + +struct DynamicUpdateSliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef DynamicUpdateSliceOptionsT NativeTableType; + typedef DynamicUpdateSliceOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + DynamicUpdateSliceOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(DynamicUpdateSliceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const DynamicUpdateSliceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct DynamicUpdateSliceOptionsBuilder { + typedef DynamicUpdateSliceOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DynamicUpdateSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDynamicUpdateSliceOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + DynamicUpdateSliceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateDynamicUpdateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, const DynamicUpdateSliceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UnsortedSegmentProdOptionsT : public flatbuffers::NativeTable { + typedef UnsortedSegmentProdOptions TableType; +}; + +struct UnsortedSegmentProdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UnsortedSegmentProdOptionsT NativeTableType; + typedef UnsortedSegmentProdOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + UnsortedSegmentProdOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UnsortedSegmentProdOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentProdOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UnsortedSegmentProdOptionsBuilder { + typedef UnsortedSegmentProdOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit UnsortedSegmentProdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnsortedSegmentProdOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + UnsortedSegmentProdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUnsortedSegmentProdOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentProdOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UnsortedSegmentMaxOptionsT : public flatbuffers::NativeTable { + typedef UnsortedSegmentMaxOptions TableType; +}; + +struct UnsortedSegmentMaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UnsortedSegmentMaxOptionsT NativeTableType; + typedef UnsortedSegmentMaxOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + UnsortedSegmentMaxOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UnsortedSegmentMaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UnsortedSegmentMaxOptionsBuilder { + typedef UnsortedSegmentMaxOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit UnsortedSegmentMaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnsortedSegmentMaxOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + UnsortedSegmentMaxOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUnsortedSegmentMaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UnsortedSegmentSumOptionsT : public flatbuffers::NativeTable { + typedef UnsortedSegmentSumOptions TableType; +}; + +struct UnsortedSegmentSumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UnsortedSegmentSumOptionsT NativeTableType; + typedef UnsortedSegmentSumOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + UnsortedSegmentSumOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UnsortedSegmentSumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentSumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UnsortedSegmentSumOptionsBuilder { + typedef UnsortedSegmentSumOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit UnsortedSegmentSumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnsortedSegmentSumOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + UnsortedSegmentSumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUnsortedSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentSumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ATan2OptionsT : public flatbuffers::NativeTable { + typedef ATan2Options TableType; +}; + +struct ATan2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ATan2OptionsT NativeTableType; + typedef ATan2OptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + ATan2OptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ATan2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ATan2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ATan2OptionsBuilder { + typedef ATan2Options Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ATan2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateATan2Options( + flatbuffers::FlatBufferBuilder &_fbb) { + ATan2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateATan2Options(flatbuffers::FlatBufferBuilder &_fbb, const ATan2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct UnsortedSegmentMinOptionsT : public flatbuffers::NativeTable { + typedef UnsortedSegmentMinOptions TableType; +}; + +struct UnsortedSegmentMinOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef UnsortedSegmentMinOptionsT NativeTableType; + typedef UnsortedSegmentMinOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + UnsortedSegmentMinOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(UnsortedSegmentMinOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMinOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct UnsortedSegmentMinOptionsBuilder { + typedef UnsortedSegmentMinOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit UnsortedSegmentMinOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnsortedSegmentMinOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + UnsortedSegmentMinOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateUnsortedSegmentMinOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMinOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SignOptionsT : public flatbuffers::NativeTable { + typedef SignOptions TableType; +}; + +struct SignOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SignOptionsT NativeTableType; + typedef SignOptionsBuilder Builder; + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + verifier.EndTable(); + } + SignOptionsT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SignOptionsT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SignOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SignOptionsBuilder { + typedef SignOptions Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SignOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSignOptions( + flatbuffers::FlatBufferBuilder &_fbb) { + SignOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +flatbuffers::Offset CreateSignOptions(flatbuffers::FlatBufferBuilder &_fbb, const SignOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct OperatorCodeT : public flatbuffers::NativeTable { + typedef OperatorCode TableType; + int8_t deprecated_builtin_code = 0; + std::string custom_code{}; + int32_t version = 1; + tflite::BuiltinOperator builtin_code = tflite::BuiltinOperator_ADD; +}; + +struct OperatorCode FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef OperatorCodeT NativeTableType; + typedef OperatorCodeBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DEPRECATED_BUILTIN_CODE = 4, + VT_CUSTOM_CODE = 6, + VT_VERSION = 8, + VT_BUILTIN_CODE = 10 + }; + int8_t deprecated_builtin_code() const { + return GetField(VT_DEPRECATED_BUILTIN_CODE, 0); + } + const flatbuffers::String *custom_code() const { + return GetPointer(VT_CUSTOM_CODE); + } + int32_t version() const { + return GetField(VT_VERSION, 1); + } + tflite::BuiltinOperator builtin_code() const { + return static_cast(GetField(VT_BUILTIN_CODE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_DEPRECATED_BUILTIN_CODE, 1) && + VerifyOffset(verifier, VT_CUSTOM_CODE) && + verifier.VerifyString(custom_code()) && + VerifyField(verifier, VT_VERSION, 4) && + VerifyField(verifier, VT_BUILTIN_CODE, 4) && + verifier.EndTable(); + } + OperatorCodeT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(OperatorCodeT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const OperatorCodeT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct OperatorCodeBuilder { + typedef OperatorCode Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_deprecated_builtin_code(int8_t deprecated_builtin_code) { + fbb_.AddElement(OperatorCode::VT_DEPRECATED_BUILTIN_CODE, deprecated_builtin_code, 0); + } + void add_custom_code(flatbuffers::Offset custom_code) { + fbb_.AddOffset(OperatorCode::VT_CUSTOM_CODE, custom_code); + } + void add_version(int32_t version) { + fbb_.AddElement(OperatorCode::VT_VERSION, version, 1); + } + void add_builtin_code(tflite::BuiltinOperator builtin_code) { + fbb_.AddElement(OperatorCode::VT_BUILTIN_CODE, static_cast(builtin_code), 0); + } + explicit OperatorCodeBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateOperatorCode( + flatbuffers::FlatBufferBuilder &_fbb, + int8_t deprecated_builtin_code = 0, + flatbuffers::Offset custom_code = 0, + int32_t version = 1, + tflite::BuiltinOperator builtin_code = tflite::BuiltinOperator_ADD) { + OperatorCodeBuilder builder_(_fbb); + builder_.add_builtin_code(builtin_code); + builder_.add_version(version); + builder_.add_custom_code(custom_code); + builder_.add_deprecated_builtin_code(deprecated_builtin_code); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateOperatorCodeDirect( + flatbuffers::FlatBufferBuilder &_fbb, + int8_t deprecated_builtin_code = 0, + const char *custom_code = nullptr, + int32_t version = 1, + tflite::BuiltinOperator builtin_code = tflite::BuiltinOperator_ADD) { + auto custom_code__ = custom_code ? _fbb.CreateString(custom_code) : 0; + return tflite::CreateOperatorCode( + _fbb, + deprecated_builtin_code, + custom_code__, + version, + builtin_code); +} + +flatbuffers::Offset CreateOperatorCode(flatbuffers::FlatBufferBuilder &_fbb, const OperatorCodeT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct OperatorT : public flatbuffers::NativeTable { + typedef Operator TableType; + uint32_t opcode_index = 0; + std::vector inputs{}; + std::vector outputs{}; + tflite::BuiltinOptionsUnion builtin_options{}; + std::vector custom_options{}; + tflite::CustomOptionsFormat custom_options_format = tflite::CustomOptionsFormat_FLEXBUFFERS; + std::vector mutating_variable_inputs{}; + std::vector intermediates{}; +}; + +struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef OperatorT NativeTableType; + typedef OperatorBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_OPCODE_INDEX = 4, + VT_INPUTS = 6, + VT_OUTPUTS = 8, + VT_BUILTIN_OPTIONS_TYPE = 10, + VT_BUILTIN_OPTIONS = 12, + VT_CUSTOM_OPTIONS = 14, + VT_CUSTOM_OPTIONS_FORMAT = 16, + VT_MUTATING_VARIABLE_INPUTS = 18, + VT_INTERMEDIATES = 20 + }; + uint32_t opcode_index() const { + return GetField(VT_OPCODE_INDEX, 0); + } + const flatbuffers::Vector *inputs() const { + return GetPointer *>(VT_INPUTS); + } + const flatbuffers::Vector *outputs() const { + return GetPointer *>(VT_OUTPUTS); + } + tflite::BuiltinOptions builtin_options_type() const { + return static_cast(GetField(VT_BUILTIN_OPTIONS_TYPE, 0)); + } + const void *builtin_options() const { + return GetPointer(VT_BUILTIN_OPTIONS); + } + template const T *builtin_options_as() const; + const tflite::Conv2DOptions *builtin_options_as_Conv2DOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_Conv2DOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::DepthwiseConv2DOptions *builtin_options_as_DepthwiseConv2DOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_DepthwiseConv2DOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ConcatEmbeddingsOptions *builtin_options_as_ConcatEmbeddingsOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ConcatEmbeddingsOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LSHProjectionOptions *builtin_options_as_LSHProjectionOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LSHProjectionOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::Pool2DOptions *builtin_options_as_Pool2DOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_Pool2DOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SVDFOptions *builtin_options_as_SVDFOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SVDFOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::RNNOptions *builtin_options_as_RNNOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_RNNOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::FullyConnectedOptions *builtin_options_as_FullyConnectedOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_FullyConnectedOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SoftmaxOptions *builtin_options_as_SoftmaxOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SoftmaxOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ConcatenationOptions *builtin_options_as_ConcatenationOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ConcatenationOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::AddOptions *builtin_options_as_AddOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_AddOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::L2NormOptions *builtin_options_as_L2NormOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_L2NormOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LocalResponseNormalizationOptions *builtin_options_as_LocalResponseNormalizationOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LocalResponseNormalizationOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LSTMOptions *builtin_options_as_LSTMOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LSTMOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ResizeBilinearOptions *builtin_options_as_ResizeBilinearOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ResizeBilinearOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::CallOptions *builtin_options_as_CallOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_CallOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ReshapeOptions *builtin_options_as_ReshapeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ReshapeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SkipGramOptions *builtin_options_as_SkipGramOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SkipGramOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SpaceToDepthOptions *builtin_options_as_SpaceToDepthOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SpaceToDepthOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::EmbeddingLookupSparseOptions *builtin_options_as_EmbeddingLookupSparseOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_EmbeddingLookupSparseOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::MulOptions *builtin_options_as_MulOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_MulOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::PadOptions *builtin_options_as_PadOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_PadOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::GatherOptions *builtin_options_as_GatherOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_GatherOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::BatchToSpaceNDOptions *builtin_options_as_BatchToSpaceNDOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_BatchToSpaceNDOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SpaceToBatchNDOptions *builtin_options_as_SpaceToBatchNDOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SpaceToBatchNDOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::TransposeOptions *builtin_options_as_TransposeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_TransposeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ReducerOptions *builtin_options_as_ReducerOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ReducerOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SubOptions *builtin_options_as_SubOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SubOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::DivOptions *builtin_options_as_DivOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_DivOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SqueezeOptions *builtin_options_as_SqueezeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SqueezeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SequenceRNNOptions *builtin_options_as_SequenceRNNOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SequenceRNNOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::StridedSliceOptions *builtin_options_as_StridedSliceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_StridedSliceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ExpOptions *builtin_options_as_ExpOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ExpOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::TopKV2Options *builtin_options_as_TopKV2Options() const { + return builtin_options_type() == tflite::BuiltinOptions_TopKV2Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::SplitOptions *builtin_options_as_SplitOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SplitOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LogSoftmaxOptions *builtin_options_as_LogSoftmaxOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LogSoftmaxOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::CastOptions *builtin_options_as_CastOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_CastOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::DequantizeOptions *builtin_options_as_DequantizeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_DequantizeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::MaximumMinimumOptions *builtin_options_as_MaximumMinimumOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_MaximumMinimumOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ArgMaxOptions *builtin_options_as_ArgMaxOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ArgMaxOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LessOptions *builtin_options_as_LessOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LessOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::NegOptions *builtin_options_as_NegOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_NegOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::PadV2Options *builtin_options_as_PadV2Options() const { + return builtin_options_type() == tflite::BuiltinOptions_PadV2Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::GreaterOptions *builtin_options_as_GreaterOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_GreaterOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::GreaterEqualOptions *builtin_options_as_GreaterEqualOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_GreaterEqualOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LessEqualOptions *builtin_options_as_LessEqualOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LessEqualOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SelectOptions *builtin_options_as_SelectOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SelectOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SliceOptions *builtin_options_as_SliceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SliceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::TransposeConvOptions *builtin_options_as_TransposeConvOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_TransposeConvOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SparseToDenseOptions *builtin_options_as_SparseToDenseOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SparseToDenseOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::TileOptions *builtin_options_as_TileOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_TileOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ExpandDimsOptions *builtin_options_as_ExpandDimsOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ExpandDimsOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::EqualOptions *builtin_options_as_EqualOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_EqualOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::NotEqualOptions *builtin_options_as_NotEqualOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_NotEqualOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ShapeOptions *builtin_options_as_ShapeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ShapeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::PowOptions *builtin_options_as_PowOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_PowOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ArgMinOptions *builtin_options_as_ArgMinOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ArgMinOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::FakeQuantOptions *builtin_options_as_FakeQuantOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_FakeQuantOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::PackOptions *builtin_options_as_PackOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_PackOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LogicalOrOptions *builtin_options_as_LogicalOrOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LogicalOrOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::OneHotOptions *builtin_options_as_OneHotOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_OneHotOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LogicalAndOptions *builtin_options_as_LogicalAndOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LogicalAndOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LogicalNotOptions *builtin_options_as_LogicalNotOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LogicalNotOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UnpackOptions *builtin_options_as_UnpackOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UnpackOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::FloorDivOptions *builtin_options_as_FloorDivOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_FloorDivOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SquareOptions *builtin_options_as_SquareOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SquareOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ZerosLikeOptions *builtin_options_as_ZerosLikeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ZerosLikeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::FillOptions *builtin_options_as_FillOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_FillOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::BidirectionalSequenceLSTMOptions *builtin_options_as_BidirectionalSequenceLSTMOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_BidirectionalSequenceLSTMOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::BidirectionalSequenceRNNOptions *builtin_options_as_BidirectionalSequenceRNNOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_BidirectionalSequenceRNNOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UnidirectionalSequenceLSTMOptions *builtin_options_as_UnidirectionalSequenceLSTMOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UnidirectionalSequenceLSTMOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::FloorModOptions *builtin_options_as_FloorModOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_FloorModOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::RangeOptions *builtin_options_as_RangeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_RangeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ResizeNearestNeighborOptions *builtin_options_as_ResizeNearestNeighborOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ResizeNearestNeighborOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::LeakyReluOptions *builtin_options_as_LeakyReluOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_LeakyReluOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SquaredDifferenceOptions *builtin_options_as_SquaredDifferenceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SquaredDifferenceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::MirrorPadOptions *builtin_options_as_MirrorPadOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_MirrorPadOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::AbsOptions *builtin_options_as_AbsOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_AbsOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SplitVOptions *builtin_options_as_SplitVOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SplitVOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UniqueOptions *builtin_options_as_UniqueOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UniqueOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ReverseV2Options *builtin_options_as_ReverseV2Options() const { + return builtin_options_type() == tflite::BuiltinOptions_ReverseV2Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::AddNOptions *builtin_options_as_AddNOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_AddNOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::GatherNdOptions *builtin_options_as_GatherNdOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_GatherNdOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::CosOptions *builtin_options_as_CosOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_CosOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::WhereOptions *builtin_options_as_WhereOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_WhereOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::RankOptions *builtin_options_as_RankOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_RankOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ReverseSequenceOptions *builtin_options_as_ReverseSequenceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ReverseSequenceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::MatrixDiagOptions *builtin_options_as_MatrixDiagOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_MatrixDiagOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::QuantizeOptions *builtin_options_as_QuantizeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_QuantizeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::MatrixSetDiagOptions *builtin_options_as_MatrixSetDiagOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_MatrixSetDiagOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::HardSwishOptions *builtin_options_as_HardSwishOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_HardSwishOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::IfOptions *builtin_options_as_IfOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_IfOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::WhileOptions *builtin_options_as_WhileOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_WhileOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::DepthToSpaceOptions *builtin_options_as_DepthToSpaceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_DepthToSpaceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::NonMaxSuppressionV4Options *builtin_options_as_NonMaxSuppressionV4Options() const { + return builtin_options_type() == tflite::BuiltinOptions_NonMaxSuppressionV4Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::NonMaxSuppressionV5Options *builtin_options_as_NonMaxSuppressionV5Options() const { + return builtin_options_type() == tflite::BuiltinOptions_NonMaxSuppressionV5Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::ScatterNdOptions *builtin_options_as_ScatterNdOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ScatterNdOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SelectV2Options *builtin_options_as_SelectV2Options() const { + return builtin_options_type() == tflite::BuiltinOptions_SelectV2Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::DensifyOptions *builtin_options_as_DensifyOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_DensifyOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::SegmentSumOptions *builtin_options_as_SegmentSumOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SegmentSumOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::BatchMatMulOptions *builtin_options_as_BatchMatMulOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_BatchMatMulOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::CumsumOptions *builtin_options_as_CumsumOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_CumsumOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::CallOnceOptions *builtin_options_as_CallOnceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_CallOnceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::BroadcastToOptions *builtin_options_as_BroadcastToOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_BroadcastToOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::Rfft2dOptions *builtin_options_as_Rfft2dOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_Rfft2dOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::Conv3DOptions *builtin_options_as_Conv3DOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_Conv3DOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::HashtableOptions *builtin_options_as_HashtableOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_HashtableOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::HashtableFindOptions *builtin_options_as_HashtableFindOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_HashtableFindOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::HashtableImportOptions *builtin_options_as_HashtableImportOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_HashtableImportOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::HashtableSizeOptions *builtin_options_as_HashtableSizeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_HashtableSizeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::VarHandleOptions *builtin_options_as_VarHandleOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_VarHandleOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ReadVariableOptions *builtin_options_as_ReadVariableOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_ReadVariableOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::AssignVariableOptions *builtin_options_as_AssignVariableOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_AssignVariableOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::RandomOptions *builtin_options_as_RandomOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_RandomOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::BucketizeOptions *builtin_options_as_BucketizeOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_BucketizeOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::GeluOptions *builtin_options_as_GeluOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_GeluOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::DynamicUpdateSliceOptions *builtin_options_as_DynamicUpdateSliceOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_DynamicUpdateSliceOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UnsortedSegmentProdOptions *builtin_options_as_UnsortedSegmentProdOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UnsortedSegmentProdOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UnsortedSegmentMaxOptions *builtin_options_as_UnsortedSegmentMaxOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UnsortedSegmentMaxOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UnsortedSegmentMinOptions *builtin_options_as_UnsortedSegmentMinOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UnsortedSegmentMinOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::UnsortedSegmentSumOptions *builtin_options_as_UnsortedSegmentSumOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_UnsortedSegmentSumOptions ? static_cast(builtin_options()) : nullptr; + } + const tflite::ATan2Options *builtin_options_as_ATan2Options() const { + return builtin_options_type() == tflite::BuiltinOptions_ATan2Options ? static_cast(builtin_options()) : nullptr; + } + const tflite::SignOptions *builtin_options_as_SignOptions() const { + return builtin_options_type() == tflite::BuiltinOptions_SignOptions ? static_cast(builtin_options()) : nullptr; + } + const flatbuffers::Vector *custom_options() const { + return GetPointer *>(VT_CUSTOM_OPTIONS); + } + tflite::CustomOptionsFormat custom_options_format() const { + return static_cast(GetField(VT_CUSTOM_OPTIONS_FORMAT, 0)); + } + const flatbuffers::Vector *mutating_variable_inputs() const { + return GetPointer *>(VT_MUTATING_VARIABLE_INPUTS); + } + const flatbuffers::Vector *intermediates() const { + return GetPointer *>(VT_INTERMEDIATES); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_OPCODE_INDEX, 4) && + VerifyOffset(verifier, VT_INPUTS) && + verifier.VerifyVector(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && + verifier.VerifyVector(outputs()) && + VerifyField(verifier, VT_BUILTIN_OPTIONS_TYPE, 1) && + VerifyOffset(verifier, VT_BUILTIN_OPTIONS) && + VerifyBuiltinOptions(verifier, builtin_options(), builtin_options_type()) && + VerifyOffset(verifier, VT_CUSTOM_OPTIONS) && + verifier.VerifyVector(custom_options()) && + VerifyField(verifier, VT_CUSTOM_OPTIONS_FORMAT, 1) && + VerifyOffset(verifier, VT_MUTATING_VARIABLE_INPUTS) && + verifier.VerifyVector(mutating_variable_inputs()) && + VerifyOffset(verifier, VT_INTERMEDIATES) && + verifier.VerifyVector(intermediates()) && + verifier.EndTable(); + } + OperatorT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(OperatorT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const OperatorT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +template<> inline const tflite::Conv2DOptions *Operator::builtin_options_as() const { + return builtin_options_as_Conv2DOptions(); +} + +template<> inline const tflite::DepthwiseConv2DOptions *Operator::builtin_options_as() const { + return builtin_options_as_DepthwiseConv2DOptions(); +} + +template<> inline const tflite::ConcatEmbeddingsOptions *Operator::builtin_options_as() const { + return builtin_options_as_ConcatEmbeddingsOptions(); +} + +template<> inline const tflite::LSHProjectionOptions *Operator::builtin_options_as() const { + return builtin_options_as_LSHProjectionOptions(); +} + +template<> inline const tflite::Pool2DOptions *Operator::builtin_options_as() const { + return builtin_options_as_Pool2DOptions(); +} + +template<> inline const tflite::SVDFOptions *Operator::builtin_options_as() const { + return builtin_options_as_SVDFOptions(); +} + +template<> inline const tflite::RNNOptions *Operator::builtin_options_as() const { + return builtin_options_as_RNNOptions(); +} + +template<> inline const tflite::FullyConnectedOptions *Operator::builtin_options_as() const { + return builtin_options_as_FullyConnectedOptions(); +} + +template<> inline const tflite::SoftmaxOptions *Operator::builtin_options_as() const { + return builtin_options_as_SoftmaxOptions(); +} + +template<> inline const tflite::ConcatenationOptions *Operator::builtin_options_as() const { + return builtin_options_as_ConcatenationOptions(); +} + +template<> inline const tflite::AddOptions *Operator::builtin_options_as() const { + return builtin_options_as_AddOptions(); +} + +template<> inline const tflite::L2NormOptions *Operator::builtin_options_as() const { + return builtin_options_as_L2NormOptions(); +} + +template<> inline const tflite::LocalResponseNormalizationOptions *Operator::builtin_options_as() const { + return builtin_options_as_LocalResponseNormalizationOptions(); +} + +template<> inline const tflite::LSTMOptions *Operator::builtin_options_as() const { + return builtin_options_as_LSTMOptions(); +} + +template<> inline const tflite::ResizeBilinearOptions *Operator::builtin_options_as() const { + return builtin_options_as_ResizeBilinearOptions(); +} + +template<> inline const tflite::CallOptions *Operator::builtin_options_as() const { + return builtin_options_as_CallOptions(); +} + +template<> inline const tflite::ReshapeOptions *Operator::builtin_options_as() const { + return builtin_options_as_ReshapeOptions(); +} + +template<> inline const tflite::SkipGramOptions *Operator::builtin_options_as() const { + return builtin_options_as_SkipGramOptions(); +} + +template<> inline const tflite::SpaceToDepthOptions *Operator::builtin_options_as() const { + return builtin_options_as_SpaceToDepthOptions(); +} + +template<> inline const tflite::EmbeddingLookupSparseOptions *Operator::builtin_options_as() const { + return builtin_options_as_EmbeddingLookupSparseOptions(); +} + +template<> inline const tflite::MulOptions *Operator::builtin_options_as() const { + return builtin_options_as_MulOptions(); +} + +template<> inline const tflite::PadOptions *Operator::builtin_options_as() const { + return builtin_options_as_PadOptions(); +} + +template<> inline const tflite::GatherOptions *Operator::builtin_options_as() const { + return builtin_options_as_GatherOptions(); +} + +template<> inline const tflite::BatchToSpaceNDOptions *Operator::builtin_options_as() const { + return builtin_options_as_BatchToSpaceNDOptions(); +} + +template<> inline const tflite::SpaceToBatchNDOptions *Operator::builtin_options_as() const { + return builtin_options_as_SpaceToBatchNDOptions(); +} + +template<> inline const tflite::TransposeOptions *Operator::builtin_options_as() const { + return builtin_options_as_TransposeOptions(); +} + +template<> inline const tflite::ReducerOptions *Operator::builtin_options_as() const { + return builtin_options_as_ReducerOptions(); +} + +template<> inline const tflite::SubOptions *Operator::builtin_options_as() const { + return builtin_options_as_SubOptions(); +} + +template<> inline const tflite::DivOptions *Operator::builtin_options_as() const { + return builtin_options_as_DivOptions(); +} + +template<> inline const tflite::SqueezeOptions *Operator::builtin_options_as() const { + return builtin_options_as_SqueezeOptions(); +} + +template<> inline const tflite::SequenceRNNOptions *Operator::builtin_options_as() const { + return builtin_options_as_SequenceRNNOptions(); +} + +template<> inline const tflite::StridedSliceOptions *Operator::builtin_options_as() const { + return builtin_options_as_StridedSliceOptions(); +} + +template<> inline const tflite::ExpOptions *Operator::builtin_options_as() const { + return builtin_options_as_ExpOptions(); +} + +template<> inline const tflite::TopKV2Options *Operator::builtin_options_as() const { + return builtin_options_as_TopKV2Options(); +} + +template<> inline const tflite::SplitOptions *Operator::builtin_options_as() const { + return builtin_options_as_SplitOptions(); +} + +template<> inline const tflite::LogSoftmaxOptions *Operator::builtin_options_as() const { + return builtin_options_as_LogSoftmaxOptions(); +} + +template<> inline const tflite::CastOptions *Operator::builtin_options_as() const { + return builtin_options_as_CastOptions(); +} + +template<> inline const tflite::DequantizeOptions *Operator::builtin_options_as() const { + return builtin_options_as_DequantizeOptions(); +} + +template<> inline const tflite::MaximumMinimumOptions *Operator::builtin_options_as() const { + return builtin_options_as_MaximumMinimumOptions(); +} + +template<> inline const tflite::ArgMaxOptions *Operator::builtin_options_as() const { + return builtin_options_as_ArgMaxOptions(); +} + +template<> inline const tflite::LessOptions *Operator::builtin_options_as() const { + return builtin_options_as_LessOptions(); +} + +template<> inline const tflite::NegOptions *Operator::builtin_options_as() const { + return builtin_options_as_NegOptions(); +} + +template<> inline const tflite::PadV2Options *Operator::builtin_options_as() const { + return builtin_options_as_PadV2Options(); +} + +template<> inline const tflite::GreaterOptions *Operator::builtin_options_as() const { + return builtin_options_as_GreaterOptions(); +} + +template<> inline const tflite::GreaterEqualOptions *Operator::builtin_options_as() const { + return builtin_options_as_GreaterEqualOptions(); +} + +template<> inline const tflite::LessEqualOptions *Operator::builtin_options_as() const { + return builtin_options_as_LessEqualOptions(); +} + +template<> inline const tflite::SelectOptions *Operator::builtin_options_as() const { + return builtin_options_as_SelectOptions(); +} + +template<> inline const tflite::SliceOptions *Operator::builtin_options_as() const { + return builtin_options_as_SliceOptions(); +} + +template<> inline const tflite::TransposeConvOptions *Operator::builtin_options_as() const { + return builtin_options_as_TransposeConvOptions(); +} + +template<> inline const tflite::SparseToDenseOptions *Operator::builtin_options_as() const { + return builtin_options_as_SparseToDenseOptions(); +} + +template<> inline const tflite::TileOptions *Operator::builtin_options_as() const { + return builtin_options_as_TileOptions(); +} + +template<> inline const tflite::ExpandDimsOptions *Operator::builtin_options_as() const { + return builtin_options_as_ExpandDimsOptions(); +} + +template<> inline const tflite::EqualOptions *Operator::builtin_options_as() const { + return builtin_options_as_EqualOptions(); +} + +template<> inline const tflite::NotEqualOptions *Operator::builtin_options_as() const { + return builtin_options_as_NotEqualOptions(); +} + +template<> inline const tflite::ShapeOptions *Operator::builtin_options_as() const { + return builtin_options_as_ShapeOptions(); +} + +template<> inline const tflite::PowOptions *Operator::builtin_options_as() const { + return builtin_options_as_PowOptions(); +} + +template<> inline const tflite::ArgMinOptions *Operator::builtin_options_as() const { + return builtin_options_as_ArgMinOptions(); +} + +template<> inline const tflite::FakeQuantOptions *Operator::builtin_options_as() const { + return builtin_options_as_FakeQuantOptions(); +} + +template<> inline const tflite::PackOptions *Operator::builtin_options_as() const { + return builtin_options_as_PackOptions(); +} + +template<> inline const tflite::LogicalOrOptions *Operator::builtin_options_as() const { + return builtin_options_as_LogicalOrOptions(); +} + +template<> inline const tflite::OneHotOptions *Operator::builtin_options_as() const { + return builtin_options_as_OneHotOptions(); +} + +template<> inline const tflite::LogicalAndOptions *Operator::builtin_options_as() const { + return builtin_options_as_LogicalAndOptions(); +} + +template<> inline const tflite::LogicalNotOptions *Operator::builtin_options_as() const { + return builtin_options_as_LogicalNotOptions(); +} + +template<> inline const tflite::UnpackOptions *Operator::builtin_options_as() const { + return builtin_options_as_UnpackOptions(); +} + +template<> inline const tflite::FloorDivOptions *Operator::builtin_options_as() const { + return builtin_options_as_FloorDivOptions(); +} + +template<> inline const tflite::SquareOptions *Operator::builtin_options_as() const { + return builtin_options_as_SquareOptions(); +} + +template<> inline const tflite::ZerosLikeOptions *Operator::builtin_options_as() const { + return builtin_options_as_ZerosLikeOptions(); +} + +template<> inline const tflite::FillOptions *Operator::builtin_options_as() const { + return builtin_options_as_FillOptions(); +} + +template<> inline const tflite::BidirectionalSequenceLSTMOptions *Operator::builtin_options_as() const { + return builtin_options_as_BidirectionalSequenceLSTMOptions(); +} + +template<> inline const tflite::BidirectionalSequenceRNNOptions *Operator::builtin_options_as() const { + return builtin_options_as_BidirectionalSequenceRNNOptions(); +} + +template<> inline const tflite::UnidirectionalSequenceLSTMOptions *Operator::builtin_options_as() const { + return builtin_options_as_UnidirectionalSequenceLSTMOptions(); +} + +template<> inline const tflite::FloorModOptions *Operator::builtin_options_as() const { + return builtin_options_as_FloorModOptions(); +} + +template<> inline const tflite::RangeOptions *Operator::builtin_options_as() const { + return builtin_options_as_RangeOptions(); +} + +template<> inline const tflite::ResizeNearestNeighborOptions *Operator::builtin_options_as() const { + return builtin_options_as_ResizeNearestNeighborOptions(); +} + +template<> inline const tflite::LeakyReluOptions *Operator::builtin_options_as() const { + return builtin_options_as_LeakyReluOptions(); +} + +template<> inline const tflite::SquaredDifferenceOptions *Operator::builtin_options_as() const { + return builtin_options_as_SquaredDifferenceOptions(); +} + +template<> inline const tflite::MirrorPadOptions *Operator::builtin_options_as() const { + return builtin_options_as_MirrorPadOptions(); +} + +template<> inline const tflite::AbsOptions *Operator::builtin_options_as() const { + return builtin_options_as_AbsOptions(); +} + +template<> inline const tflite::SplitVOptions *Operator::builtin_options_as() const { + return builtin_options_as_SplitVOptions(); +} + +template<> inline const tflite::UniqueOptions *Operator::builtin_options_as() const { + return builtin_options_as_UniqueOptions(); +} + +template<> inline const tflite::ReverseV2Options *Operator::builtin_options_as() const { + return builtin_options_as_ReverseV2Options(); +} + +template<> inline const tflite::AddNOptions *Operator::builtin_options_as() const { + return builtin_options_as_AddNOptions(); +} + +template<> inline const tflite::GatherNdOptions *Operator::builtin_options_as() const { + return builtin_options_as_GatherNdOptions(); +} + +template<> inline const tflite::CosOptions *Operator::builtin_options_as() const { + return builtin_options_as_CosOptions(); +} + +template<> inline const tflite::WhereOptions *Operator::builtin_options_as() const { + return builtin_options_as_WhereOptions(); +} + +template<> inline const tflite::RankOptions *Operator::builtin_options_as() const { + return builtin_options_as_RankOptions(); +} + +template<> inline const tflite::ReverseSequenceOptions *Operator::builtin_options_as() const { + return builtin_options_as_ReverseSequenceOptions(); +} + +template<> inline const tflite::MatrixDiagOptions *Operator::builtin_options_as() const { + return builtin_options_as_MatrixDiagOptions(); +} + +template<> inline const tflite::QuantizeOptions *Operator::builtin_options_as() const { + return builtin_options_as_QuantizeOptions(); +} + +template<> inline const tflite::MatrixSetDiagOptions *Operator::builtin_options_as() const { + return builtin_options_as_MatrixSetDiagOptions(); +} + +template<> inline const tflite::HardSwishOptions *Operator::builtin_options_as() const { + return builtin_options_as_HardSwishOptions(); +} + +template<> inline const tflite::IfOptions *Operator::builtin_options_as() const { + return builtin_options_as_IfOptions(); +} + +template<> inline const tflite::WhileOptions *Operator::builtin_options_as() const { + return builtin_options_as_WhileOptions(); +} + +template<> inline const tflite::DepthToSpaceOptions *Operator::builtin_options_as() const { + return builtin_options_as_DepthToSpaceOptions(); +} + +template<> inline const tflite::NonMaxSuppressionV4Options *Operator::builtin_options_as() const { + return builtin_options_as_NonMaxSuppressionV4Options(); +} + +template<> inline const tflite::NonMaxSuppressionV5Options *Operator::builtin_options_as() const { + return builtin_options_as_NonMaxSuppressionV5Options(); +} + +template<> inline const tflite::ScatterNdOptions *Operator::builtin_options_as() const { + return builtin_options_as_ScatterNdOptions(); +} + +template<> inline const tflite::SelectV2Options *Operator::builtin_options_as() const { + return builtin_options_as_SelectV2Options(); +} + +template<> inline const tflite::DensifyOptions *Operator::builtin_options_as() const { + return builtin_options_as_DensifyOptions(); +} + +template<> inline const tflite::SegmentSumOptions *Operator::builtin_options_as() const { + return builtin_options_as_SegmentSumOptions(); +} + +template<> inline const tflite::BatchMatMulOptions *Operator::builtin_options_as() const { + return builtin_options_as_BatchMatMulOptions(); +} + +template<> inline const tflite::CumsumOptions *Operator::builtin_options_as() const { + return builtin_options_as_CumsumOptions(); +} + +template<> inline const tflite::CallOnceOptions *Operator::builtin_options_as() const { + return builtin_options_as_CallOnceOptions(); +} + +template<> inline const tflite::BroadcastToOptions *Operator::builtin_options_as() const { + return builtin_options_as_BroadcastToOptions(); +} + +template<> inline const tflite::Rfft2dOptions *Operator::builtin_options_as() const { + return builtin_options_as_Rfft2dOptions(); +} + +template<> inline const tflite::Conv3DOptions *Operator::builtin_options_as() const { + return builtin_options_as_Conv3DOptions(); +} + +template<> inline const tflite::HashtableOptions *Operator::builtin_options_as() const { + return builtin_options_as_HashtableOptions(); +} + +template<> inline const tflite::HashtableFindOptions *Operator::builtin_options_as() const { + return builtin_options_as_HashtableFindOptions(); +} + +template<> inline const tflite::HashtableImportOptions *Operator::builtin_options_as() const { + return builtin_options_as_HashtableImportOptions(); +} + +template<> inline const tflite::HashtableSizeOptions *Operator::builtin_options_as() const { + return builtin_options_as_HashtableSizeOptions(); +} + +template<> inline const tflite::VarHandleOptions *Operator::builtin_options_as() const { + return builtin_options_as_VarHandleOptions(); +} + +template<> inline const tflite::ReadVariableOptions *Operator::builtin_options_as() const { + return builtin_options_as_ReadVariableOptions(); +} + +template<> inline const tflite::AssignVariableOptions *Operator::builtin_options_as() const { + return builtin_options_as_AssignVariableOptions(); +} + +template<> inline const tflite::RandomOptions *Operator::builtin_options_as() const { + return builtin_options_as_RandomOptions(); +} + +template<> inline const tflite::BucketizeOptions *Operator::builtin_options_as() const { + return builtin_options_as_BucketizeOptions(); +} + +template<> inline const tflite::GeluOptions *Operator::builtin_options_as() const { + return builtin_options_as_GeluOptions(); +} + +template<> inline const tflite::DynamicUpdateSliceOptions *Operator::builtin_options_as() const { + return builtin_options_as_DynamicUpdateSliceOptions(); +} + +template<> inline const tflite::UnsortedSegmentProdOptions *Operator::builtin_options_as() const { + return builtin_options_as_UnsortedSegmentProdOptions(); +} + +template<> inline const tflite::UnsortedSegmentMaxOptions *Operator::builtin_options_as() const { + return builtin_options_as_UnsortedSegmentMaxOptions(); +} + +template<> inline const tflite::UnsortedSegmentMinOptions *Operator::builtin_options_as() const { + return builtin_options_as_UnsortedSegmentMinOptions(); +} + +template<> inline const tflite::UnsortedSegmentSumOptions *Operator::builtin_options_as() const { + return builtin_options_as_UnsortedSegmentSumOptions(); +} + +template<> inline const tflite::ATan2Options *Operator::builtin_options_as() const { + return builtin_options_as_ATan2Options(); +} + +template<> inline const tflite::SignOptions *Operator::builtin_options_as() const { + return builtin_options_as_SignOptions(); +} + +struct OperatorBuilder { + typedef Operator Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_opcode_index(uint32_t opcode_index) { + fbb_.AddElement(Operator::VT_OPCODE_INDEX, opcode_index, 0); + } + void add_inputs(flatbuffers::Offset> inputs) { + fbb_.AddOffset(Operator::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset> outputs) { + fbb_.AddOffset(Operator::VT_OUTPUTS, outputs); + } + void add_builtin_options_type(tflite::BuiltinOptions builtin_options_type) { + fbb_.AddElement(Operator::VT_BUILTIN_OPTIONS_TYPE, static_cast(builtin_options_type), 0); + } + void add_builtin_options(flatbuffers::Offset builtin_options) { + fbb_.AddOffset(Operator::VT_BUILTIN_OPTIONS, builtin_options); + } + void add_custom_options(flatbuffers::Offset> custom_options) { + fbb_.AddOffset(Operator::VT_CUSTOM_OPTIONS, custom_options); + } + void add_custom_options_format(tflite::CustomOptionsFormat custom_options_format) { + fbb_.AddElement(Operator::VT_CUSTOM_OPTIONS_FORMAT, static_cast(custom_options_format), 0); + } + void add_mutating_variable_inputs(flatbuffers::Offset> mutating_variable_inputs) { + fbb_.AddOffset(Operator::VT_MUTATING_VARIABLE_INPUTS, mutating_variable_inputs); + } + void add_intermediates(flatbuffers::Offset> intermediates) { + fbb_.AddOffset(Operator::VT_INTERMEDIATES, intermediates); + } + explicit OperatorBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateOperator( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t opcode_index = 0, + flatbuffers::Offset> inputs = 0, + flatbuffers::Offset> outputs = 0, + tflite::BuiltinOptions builtin_options_type = tflite::BuiltinOptions_NONE, + flatbuffers::Offset builtin_options = 0, + flatbuffers::Offset> custom_options = 0, + tflite::CustomOptionsFormat custom_options_format = tflite::CustomOptionsFormat_FLEXBUFFERS, + flatbuffers::Offset> mutating_variable_inputs = 0, + flatbuffers::Offset> intermediates = 0) { + OperatorBuilder builder_(_fbb); + builder_.add_intermediates(intermediates); + builder_.add_mutating_variable_inputs(mutating_variable_inputs); + builder_.add_custom_options(custom_options); + builder_.add_builtin_options(builtin_options); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + builder_.add_opcode_index(opcode_index); + builder_.add_custom_options_format(custom_options_format); + builder_.add_builtin_options_type(builtin_options_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateOperatorDirect( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t opcode_index = 0, + const std::vector *inputs = nullptr, + const std::vector *outputs = nullptr, + tflite::BuiltinOptions builtin_options_type = tflite::BuiltinOptions_NONE, + flatbuffers::Offset builtin_options = 0, + const std::vector *custom_options = nullptr, + tflite::CustomOptionsFormat custom_options_format = tflite::CustomOptionsFormat_FLEXBUFFERS, + const std::vector *mutating_variable_inputs = nullptr, + const std::vector *intermediates = nullptr) { + auto inputs__ = inputs ? _fbb.CreateVector(*inputs) : 0; + auto outputs__ = outputs ? _fbb.CreateVector(*outputs) : 0; + auto custom_options__ = custom_options ? _fbb.CreateVector(*custom_options) : 0; + auto mutating_variable_inputs__ = mutating_variable_inputs ? _fbb.CreateVector(*mutating_variable_inputs) : 0; + auto intermediates__ = intermediates ? _fbb.CreateVector(*intermediates) : 0; + return tflite::CreateOperator( + _fbb, + opcode_index, + inputs__, + outputs__, + builtin_options_type, + builtin_options, + custom_options__, + custom_options_format, + mutating_variable_inputs__, + intermediates__); +} + +flatbuffers::Offset CreateOperator(flatbuffers::FlatBufferBuilder &_fbb, const OperatorT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SubGraphT : public flatbuffers::NativeTable { + typedef SubGraph TableType; + std::vector> tensors{}; + std::vector inputs{}; + std::vector outputs{}; + std::vector> operators{}; + std::string name{}; + SubGraphT() = default; + SubGraphT(const SubGraphT &o); + SubGraphT(SubGraphT&&) FLATBUFFERS_NOEXCEPT = default; + SubGraphT &operator=(SubGraphT o) FLATBUFFERS_NOEXCEPT; +}; + +struct SubGraph FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SubGraphT NativeTableType; + typedef SubGraphBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_TENSORS = 4, + VT_INPUTS = 6, + VT_OUTPUTS = 8, + VT_OPERATORS = 10, + VT_NAME = 12 + }; + const flatbuffers::Vector> *tensors() const { + return GetPointer> *>(VT_TENSORS); + } + const flatbuffers::Vector *inputs() const { + return GetPointer *>(VT_INPUTS); + } + const flatbuffers::Vector *outputs() const { + return GetPointer *>(VT_OUTPUTS); + } + const flatbuffers::Vector> *operators() const { + return GetPointer> *>(VT_OPERATORS); + } + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_TENSORS) && + verifier.VerifyVector(tensors()) && + verifier.VerifyVectorOfTables(tensors()) && + VerifyOffset(verifier, VT_INPUTS) && + verifier.VerifyVector(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && + verifier.VerifyVector(outputs()) && + VerifyOffset(verifier, VT_OPERATORS) && + verifier.VerifyVector(operators()) && + verifier.VerifyVectorOfTables(operators()) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + verifier.EndTable(); + } + SubGraphT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SubGraphT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SubGraphT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SubGraphBuilder { + typedef SubGraph Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_tensors(flatbuffers::Offset>> tensors) { + fbb_.AddOffset(SubGraph::VT_TENSORS, tensors); + } + void add_inputs(flatbuffers::Offset> inputs) { + fbb_.AddOffset(SubGraph::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset> outputs) { + fbb_.AddOffset(SubGraph::VT_OUTPUTS, outputs); + } + void add_operators(flatbuffers::Offset>> operators) { + fbb_.AddOffset(SubGraph::VT_OPERATORS, operators); + } + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(SubGraph::VT_NAME, name); + } + explicit SubGraphBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSubGraph( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> tensors = 0, + flatbuffers::Offset> inputs = 0, + flatbuffers::Offset> outputs = 0, + flatbuffers::Offset>> operators = 0, + flatbuffers::Offset name = 0) { + SubGraphBuilder builder_(_fbb); + builder_.add_name(name); + builder_.add_operators(operators); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + builder_.add_tensors(tensors); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSubGraphDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *tensors = nullptr, + const std::vector *inputs = nullptr, + const std::vector *outputs = nullptr, + const std::vector> *operators = nullptr, + const char *name = nullptr) { + auto tensors__ = tensors ? _fbb.CreateVector>(*tensors) : 0; + auto inputs__ = inputs ? _fbb.CreateVector(*inputs) : 0; + auto outputs__ = outputs ? _fbb.CreateVector(*outputs) : 0; + auto operators__ = operators ? _fbb.CreateVector>(*operators) : 0; + auto name__ = name ? _fbb.CreateString(name) : 0; + return tflite::CreateSubGraph( + _fbb, + tensors__, + inputs__, + outputs__, + operators__, + name__); +} + +flatbuffers::Offset CreateSubGraph(flatbuffers::FlatBufferBuilder &_fbb, const SubGraphT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct BufferT : public flatbuffers::NativeTable { + typedef Buffer TableType; + std::vector data{}; +}; + +struct Buffer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef BufferT NativeTableType; + typedef BufferBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_DATA = 4 + }; + const flatbuffers::Vector *data() const { + return GetPointer *>(VT_DATA); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_DATA) && + verifier.VerifyVector(data()) && + verifier.EndTable(); + } + BufferT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(BufferT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const BufferT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct BufferBuilder { + typedef Buffer Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_data(flatbuffers::Offset> data) { + fbb_.AddOffset(Buffer::VT_DATA, data); + } + explicit BufferBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBuffer( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> data = 0) { + BufferBuilder builder_(_fbb); + builder_.add_data(data); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateBufferDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *data = nullptr) { + if (data) { _fbb.ForceVectorAlignment(data->size(), sizeof(uint8_t), 16); } + auto data__ = data ? _fbb.CreateVector(*data) : 0; + return tflite::CreateBuffer( + _fbb, + data__); +} + +flatbuffers::Offset CreateBuffer(flatbuffers::FlatBufferBuilder &_fbb, const BufferT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct MetadataT : public flatbuffers::NativeTable { + typedef Metadata TableType; + std::string name{}; + uint32_t buffer = 0; +}; + +struct Metadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef MetadataT NativeTableType; + typedef MetadataBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_BUFFER = 6 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + uint32_t buffer() const { + return GetField(VT_BUFFER, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_BUFFER, 4) && + verifier.EndTable(); + } + MetadataT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(MetadataT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct MetadataBuilder { + typedef Metadata Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(Metadata::VT_NAME, name); + } + void add_buffer(uint32_t buffer) { + fbb_.AddElement(Metadata::VT_BUFFER, buffer, 0); + } + explicit MetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateMetadata( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + uint32_t buffer = 0) { + MetadataBuilder builder_(_fbb); + builder_.add_buffer(buffer); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateMetadataDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + uint32_t buffer = 0) { + auto name__ = name ? _fbb.CreateString(name) : 0; + return tflite::CreateMetadata( + _fbb, + name__, + buffer); +} + +flatbuffers::Offset CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct TensorMapT : public flatbuffers::NativeTable { + typedef TensorMap TableType; + std::string name{}; + uint32_t tensor_index = 0; +}; + +struct TensorMap FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TensorMapT NativeTableType; + typedef TensorMapBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_TENSOR_INDEX = 6 + }; + const flatbuffers::String *name() const { + return GetPointer(VT_NAME); + } + uint32_t tensor_index() const { + return GetField(VT_TENSOR_INDEX, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField(verifier, VT_TENSOR_INDEX, 4) && + verifier.EndTable(); + } + TensorMapT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(TensorMapT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const TensorMapT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct TensorMapBuilder { + typedef TensorMap Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) { + fbb_.AddOffset(TensorMap::VT_NAME, name); + } + void add_tensor_index(uint32_t tensor_index) { + fbb_.AddElement(TensorMap::VT_TENSOR_INDEX, tensor_index, 0); + } + explicit TensorMapBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTensorMap( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, + uint32_t tensor_index = 0) { + TensorMapBuilder builder_(_fbb); + builder_.add_tensor_index(tensor_index); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateTensorMapDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + uint32_t tensor_index = 0) { + auto name__ = name ? _fbb.CreateString(name) : 0; + return tflite::CreateTensorMap( + _fbb, + name__, + tensor_index); +} + +flatbuffers::Offset CreateTensorMap(flatbuffers::FlatBufferBuilder &_fbb, const TensorMapT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct SignatureDefT : public flatbuffers::NativeTable { + typedef SignatureDef TableType; + std::vector> inputs{}; + std::vector> outputs{}; + std::string signature_key{}; + uint32_t subgraph_index = 0; + SignatureDefT() = default; + SignatureDefT(const SignatureDefT &o); + SignatureDefT(SignatureDefT&&) FLATBUFFERS_NOEXCEPT = default; + SignatureDefT &operator=(SignatureDefT o) FLATBUFFERS_NOEXCEPT; +}; + +struct SignatureDef FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SignatureDefT NativeTableType; + typedef SignatureDefBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_INPUTS = 4, + VT_OUTPUTS = 6, + VT_SIGNATURE_KEY = 8, + VT_SUBGRAPH_INDEX = 12 + }; + const flatbuffers::Vector> *inputs() const { + return GetPointer> *>(VT_INPUTS); + } + const flatbuffers::Vector> *outputs() const { + return GetPointer> *>(VT_OUTPUTS); + } + const flatbuffers::String *signature_key() const { + return GetPointer(VT_SIGNATURE_KEY); + } + uint32_t subgraph_index() const { + return GetField(VT_SUBGRAPH_INDEX, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffset(verifier, VT_INPUTS) && + verifier.VerifyVector(inputs()) && + verifier.VerifyVectorOfTables(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && + verifier.VerifyVector(outputs()) && + verifier.VerifyVectorOfTables(outputs()) && + VerifyOffset(verifier, VT_SIGNATURE_KEY) && + verifier.VerifyString(signature_key()) && + VerifyField(verifier, VT_SUBGRAPH_INDEX, 4) && + verifier.EndTable(); + } + SignatureDefT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(SignatureDefT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const SignatureDefT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct SignatureDefBuilder { + typedef SignatureDef Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_inputs(flatbuffers::Offset>> inputs) { + fbb_.AddOffset(SignatureDef::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset>> outputs) { + fbb_.AddOffset(SignatureDef::VT_OUTPUTS, outputs); + } + void add_signature_key(flatbuffers::Offset signature_key) { + fbb_.AddOffset(SignatureDef::VT_SIGNATURE_KEY, signature_key); + } + void add_subgraph_index(uint32_t subgraph_index) { + fbb_.AddElement(SignatureDef::VT_SUBGRAPH_INDEX, subgraph_index, 0); + } + explicit SignatureDefBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSignatureDef( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> inputs = 0, + flatbuffers::Offset>> outputs = 0, + flatbuffers::Offset signature_key = 0, + uint32_t subgraph_index = 0) { + SignatureDefBuilder builder_(_fbb); + builder_.add_subgraph_index(subgraph_index); + builder_.add_signature_key(signature_key); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSignatureDefDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *inputs = nullptr, + const std::vector> *outputs = nullptr, + const char *signature_key = nullptr, + uint32_t subgraph_index = 0) { + auto inputs__ = inputs ? _fbb.CreateVector>(*inputs) : 0; + auto outputs__ = outputs ? _fbb.CreateVector>(*outputs) : 0; + auto signature_key__ = signature_key ? _fbb.CreateString(signature_key) : 0; + return tflite::CreateSignatureDef( + _fbb, + inputs__, + outputs__, + signature_key__, + subgraph_index); +} + +flatbuffers::Offset CreateSignatureDef(flatbuffers::FlatBufferBuilder &_fbb, const SignatureDefT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +struct ModelT : public flatbuffers::NativeTable { + typedef Model TableType; + uint32_t version = 0; + std::vector> operator_codes{}; + std::vector> subgraphs{}; + std::string description{}; + std::vector> buffers{}; + std::vector metadata_buffer{}; + std::vector> metadata{}; + std::vector> signature_defs{}; + ModelT() = default; + ModelT(const ModelT &o); + ModelT(ModelT&&) FLATBUFFERS_NOEXCEPT = default; + ModelT &operator=(ModelT o) FLATBUFFERS_NOEXCEPT; +}; + +struct Model FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ModelT NativeTableType; + typedef ModelBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_VERSION = 4, + VT_OPERATOR_CODES = 6, + VT_SUBGRAPHS = 8, + VT_DESCRIPTION = 10, + VT_BUFFERS = 12, + VT_METADATA_BUFFER = 14, + VT_METADATA = 16, + VT_SIGNATURE_DEFS = 18 + }; + uint32_t version() const { + return GetField(VT_VERSION, 0); + } + const flatbuffers::Vector> *operator_codes() const { + return GetPointer> *>(VT_OPERATOR_CODES); + } + const flatbuffers::Vector> *subgraphs() const { + return GetPointer> *>(VT_SUBGRAPHS); + } + const flatbuffers::String *description() const { + return GetPointer(VT_DESCRIPTION); + } + const flatbuffers::Vector> *buffers() const { + return GetPointer> *>(VT_BUFFERS); + } + const flatbuffers::Vector *metadata_buffer() const { + return GetPointer *>(VT_METADATA_BUFFER); + } + const flatbuffers::Vector> *metadata() const { + return GetPointer> *>(VT_METADATA); + } + const flatbuffers::Vector> *signature_defs() const { + return GetPointer> *>(VT_SIGNATURE_DEFS); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_VERSION, 4) && + VerifyOffset(verifier, VT_OPERATOR_CODES) && + verifier.VerifyVector(operator_codes()) && + verifier.VerifyVectorOfTables(operator_codes()) && + VerifyOffset(verifier, VT_SUBGRAPHS) && + verifier.VerifyVector(subgraphs()) && + verifier.VerifyVectorOfTables(subgraphs()) && + VerifyOffset(verifier, VT_DESCRIPTION) && + verifier.VerifyString(description()) && + VerifyOffset(verifier, VT_BUFFERS) && + verifier.VerifyVector(buffers()) && + verifier.VerifyVectorOfTables(buffers()) && + VerifyOffset(verifier, VT_METADATA_BUFFER) && + verifier.VerifyVector(metadata_buffer()) && + VerifyOffset(verifier, VT_METADATA) && + verifier.VerifyVector(metadata()) && + verifier.VerifyVectorOfTables(metadata()) && + VerifyOffset(verifier, VT_SIGNATURE_DEFS) && + verifier.VerifyVector(signature_defs()) && + verifier.VerifyVectorOfTables(signature_defs()) && + verifier.EndTable(); + } + ModelT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; + void UnPackTo(ModelT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const; + static flatbuffers::Offset Pack(flatbuffers::FlatBufferBuilder &_fbb, const ModelT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); +}; + +struct ModelBuilder { + typedef Model Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_version(uint32_t version) { + fbb_.AddElement(Model::VT_VERSION, version, 0); + } + void add_operator_codes(flatbuffers::Offset>> operator_codes) { + fbb_.AddOffset(Model::VT_OPERATOR_CODES, operator_codes); + } + void add_subgraphs(flatbuffers::Offset>> subgraphs) { + fbb_.AddOffset(Model::VT_SUBGRAPHS, subgraphs); + } + void add_description(flatbuffers::Offset description) { + fbb_.AddOffset(Model::VT_DESCRIPTION, description); + } + void add_buffers(flatbuffers::Offset>> buffers) { + fbb_.AddOffset(Model::VT_BUFFERS, buffers); + } + void add_metadata_buffer(flatbuffers::Offset> metadata_buffer) { + fbb_.AddOffset(Model::VT_METADATA_BUFFER, metadata_buffer); + } + void add_metadata(flatbuffers::Offset>> metadata) { + fbb_.AddOffset(Model::VT_METADATA, metadata); + } + void add_signature_defs(flatbuffers::Offset>> signature_defs) { + fbb_.AddOffset(Model::VT_SIGNATURE_DEFS, signature_defs); + } + explicit ModelBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateModel( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t version = 0, + flatbuffers::Offset>> operator_codes = 0, + flatbuffers::Offset>> subgraphs = 0, + flatbuffers::Offset description = 0, + flatbuffers::Offset>> buffers = 0, + flatbuffers::Offset> metadata_buffer = 0, + flatbuffers::Offset>> metadata = 0, + flatbuffers::Offset>> signature_defs = 0) { + ModelBuilder builder_(_fbb); + builder_.add_signature_defs(signature_defs); + builder_.add_metadata(metadata); + builder_.add_metadata_buffer(metadata_buffer); + builder_.add_buffers(buffers); + builder_.add_description(description); + builder_.add_subgraphs(subgraphs); + builder_.add_operator_codes(operator_codes); + builder_.add_version(version); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateModelDirect( + flatbuffers::FlatBufferBuilder &_fbb, + uint32_t version = 0, + const std::vector> *operator_codes = nullptr, + const std::vector> *subgraphs = nullptr, + const char *description = nullptr, + const std::vector> *buffers = nullptr, + const std::vector *metadata_buffer = nullptr, + const std::vector> *metadata = nullptr, + const std::vector> *signature_defs = nullptr) { + auto operator_codes__ = operator_codes ? _fbb.CreateVector>(*operator_codes) : 0; + auto subgraphs__ = subgraphs ? _fbb.CreateVector>(*subgraphs) : 0; + auto description__ = description ? _fbb.CreateString(description) : 0; + auto buffers__ = buffers ? _fbb.CreateVector>(*buffers) : 0; + auto metadata_buffer__ = metadata_buffer ? _fbb.CreateVector(*metadata_buffer) : 0; + auto metadata__ = metadata ? _fbb.CreateVector>(*metadata) : 0; + auto signature_defs__ = signature_defs ? _fbb.CreateVector>(*signature_defs) : 0; + return tflite::CreateModel( + _fbb, + version, + operator_codes__, + subgraphs__, + description__, + buffers__, + metadata_buffer__, + metadata__, + signature_defs__); +} + +flatbuffers::Offset CreateModel(flatbuffers::FlatBufferBuilder &_fbb, const ModelT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); + +inline CustomQuantizationT *CustomQuantization::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CustomQuantizationT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void CustomQuantization::UnPackTo(CustomQuantizationT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = custom(); if (_e) { _o->custom.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->custom.begin()); } } +} + +inline flatbuffers::Offset CustomQuantization::Pack(flatbuffers::FlatBufferBuilder &_fbb, const CustomQuantizationT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateCustomQuantization(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateCustomQuantization(flatbuffers::FlatBufferBuilder &_fbb, const CustomQuantizationT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const CustomQuantizationT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + _fbb.ForceVectorAlignment(_o->custom.size(), sizeof(uint8_t), 16); + auto _custom = _o->custom.size() ? _fbb.CreateVector(_o->custom) : 0; + return tflite::CreateCustomQuantization( + _fbb, + _custom); +} + +inline QuantizationParametersT *QuantizationParameters::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new QuantizationParametersT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void QuantizationParameters::UnPackTo(QuantizationParametersT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = min(); if (_e) { _o->min.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->min[_i] = _e->Get(_i); } } } + { auto _e = max(); if (_e) { _o->max.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->max[_i] = _e->Get(_i); } } } + { auto _e = scale(); if (_e) { _o->scale.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->scale[_i] = _e->Get(_i); } } } + { auto _e = zero_point(); if (_e) { _o->zero_point.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->zero_point[_i] = _e->Get(_i); } } } + { auto _e = details_type(); _o->details.type = _e; } + { auto _e = details(); if (_e) _o->details.value = tflite::QuantizationDetailsUnion::UnPack(_e, details_type(), _resolver); } + { auto _e = quantized_dimension(); _o->quantized_dimension = _e; } +} + +inline flatbuffers::Offset QuantizationParameters::Pack(flatbuffers::FlatBufferBuilder &_fbb, const QuantizationParametersT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateQuantizationParameters(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateQuantizationParameters(flatbuffers::FlatBufferBuilder &_fbb, const QuantizationParametersT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const QuantizationParametersT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _min = _o->min.size() ? _fbb.CreateVector(_o->min) : 0; + auto _max = _o->max.size() ? _fbb.CreateVector(_o->max) : 0; + auto _scale = _o->scale.size() ? _fbb.CreateVector(_o->scale) : 0; + auto _zero_point = _o->zero_point.size() ? _fbb.CreateVector(_o->zero_point) : 0; + auto _details_type = _o->details.type; + auto _details = _o->details.Pack(_fbb); + auto _quantized_dimension = _o->quantized_dimension; + return tflite::CreateQuantizationParameters( + _fbb, + _min, + _max, + _scale, + _zero_point, + _details_type, + _details, + _quantized_dimension); +} + +inline Int32VectorT *Int32Vector::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Int32VectorT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Int32Vector::UnPackTo(Int32VectorT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = values(); if (_e) { _o->values.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->values[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset Int32Vector::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Int32VectorT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateInt32Vector(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateInt32Vector(flatbuffers::FlatBufferBuilder &_fbb, const Int32VectorT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Int32VectorT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _values = _o->values.size() ? _fbb.CreateVector(_o->values) : 0; + return tflite::CreateInt32Vector( + _fbb, + _values); +} + +inline Uint16VectorT *Uint16Vector::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Uint16VectorT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Uint16Vector::UnPackTo(Uint16VectorT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = values(); if (_e) { _o->values.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->values[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset Uint16Vector::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Uint16VectorT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUint16Vector(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUint16Vector(flatbuffers::FlatBufferBuilder &_fbb, const Uint16VectorT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Uint16VectorT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + _fbb.ForceVectorAlignment(_o->values.size(), sizeof(uint16_t), 4); + auto _values = _o->values.size() ? _fbb.CreateVector(_o->values) : 0; + return tflite::CreateUint16Vector( + _fbb, + _values); +} + +inline Uint8VectorT *Uint8Vector::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Uint8VectorT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Uint8Vector::UnPackTo(Uint8VectorT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = values(); if (_e) { _o->values.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->values.begin()); } } +} + +inline flatbuffers::Offset Uint8Vector::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Uint8VectorT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUint8Vector(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUint8Vector(flatbuffers::FlatBufferBuilder &_fbb, const Uint8VectorT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Uint8VectorT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + _fbb.ForceVectorAlignment(_o->values.size(), sizeof(uint8_t), 4); + auto _values = _o->values.size() ? _fbb.CreateVector(_o->values) : 0; + return tflite::CreateUint8Vector( + _fbb, + _values); +} + +inline DimensionMetadataT *DimensionMetadata::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DimensionMetadataT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DimensionMetadata::UnPackTo(DimensionMetadataT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = format(); _o->format = _e; } + { auto _e = dense_size(); _o->dense_size = _e; } + { auto _e = array_segments_type(); _o->array_segments.type = _e; } + { auto _e = array_segments(); if (_e) _o->array_segments.value = tflite::SparseIndexVectorUnion::UnPack(_e, array_segments_type(), _resolver); } + { auto _e = array_indices_type(); _o->array_indices.type = _e; } + { auto _e = array_indices(); if (_e) _o->array_indices.value = tflite::SparseIndexVectorUnion::UnPack(_e, array_indices_type(), _resolver); } +} + +inline flatbuffers::Offset DimensionMetadata::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DimensionMetadataT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDimensionMetadata(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDimensionMetadata(flatbuffers::FlatBufferBuilder &_fbb, const DimensionMetadataT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DimensionMetadataT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _format = _o->format; + auto _dense_size = _o->dense_size; + auto _array_segments_type = _o->array_segments.type; + auto _array_segments = _o->array_segments.Pack(_fbb); + auto _array_indices_type = _o->array_indices.type; + auto _array_indices = _o->array_indices.Pack(_fbb); + return tflite::CreateDimensionMetadata( + _fbb, + _format, + _dense_size, + _array_segments_type, + _array_segments, + _array_indices_type, + _array_indices); +} + +inline SparsityParametersT::SparsityParametersT(const SparsityParametersT &o) + : traversal_order(o.traversal_order), + block_map(o.block_map) { + dim_metadata.reserve(o.dim_metadata.size()); + for (const auto &dim_metadata_ : o.dim_metadata) { dim_metadata.emplace_back((dim_metadata_) ? new tflite::DimensionMetadataT(*dim_metadata_) : nullptr); } +} + +inline SparsityParametersT &SparsityParametersT::operator=(SparsityParametersT o) FLATBUFFERS_NOEXCEPT { + std::swap(traversal_order, o.traversal_order); + std::swap(block_map, o.block_map); + std::swap(dim_metadata, o.dim_metadata); + return *this; +} + +inline SparsityParametersT *SparsityParameters::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SparsityParametersT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SparsityParameters::UnPackTo(SparsityParametersT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = traversal_order(); if (_e) { _o->traversal_order.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->traversal_order[_i] = _e->Get(_i); } } } + { auto _e = block_map(); if (_e) { _o->block_map.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->block_map[_i] = _e->Get(_i); } } } + { auto _e = dim_metadata(); if (_e) { _o->dim_metadata.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->dim_metadata[_i]) { _e->Get(_i)->UnPackTo(_o->dim_metadata[_i].get(), _resolver); } else { _o->dim_metadata[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } +} + +inline flatbuffers::Offset SparsityParameters::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SparsityParametersT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSparsityParameters(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSparsityParameters(flatbuffers::FlatBufferBuilder &_fbb, const SparsityParametersT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SparsityParametersT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _traversal_order = _o->traversal_order.size() ? _fbb.CreateVector(_o->traversal_order) : 0; + auto _block_map = _o->block_map.size() ? _fbb.CreateVector(_o->block_map) : 0; + auto _dim_metadata = _o->dim_metadata.size() ? _fbb.CreateVector> (_o->dim_metadata.size(), [](size_t i, _VectorArgs *__va) { return CreateDimensionMetadata(*__va->__fbb, __va->__o->dim_metadata[i].get(), __va->__rehasher); }, &_va ) : 0; + return tflite::CreateSparsityParameters( + _fbb, + _traversal_order, + _block_map, + _dim_metadata); +} + +inline VariantSubTypeT *VariantSubType::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new VariantSubTypeT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void VariantSubType::UnPackTo(VariantSubTypeT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = shape(); if (_e) { _o->shape.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->shape[_i] = _e->Get(_i); } } } + { auto _e = type(); _o->type = _e; } + { auto _e = has_rank(); _o->has_rank = _e; } +} + +inline flatbuffers::Offset VariantSubType::Pack(flatbuffers::FlatBufferBuilder &_fbb, const VariantSubTypeT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateVariantSubType(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateVariantSubType(flatbuffers::FlatBufferBuilder &_fbb, const VariantSubTypeT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const VariantSubTypeT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _shape = _o->shape.size() ? _fbb.CreateVector(_o->shape) : 0; + auto _type = _o->type; + auto _has_rank = _o->has_rank; + return tflite::CreateVariantSubType( + _fbb, + _shape, + _type, + _has_rank); +} + +inline TensorT::TensorT(const TensorT &o) + : shape(o.shape), + type(o.type), + buffer(o.buffer), + name(o.name), + quantization((o.quantization) ? new tflite::QuantizationParametersT(*o.quantization) : nullptr), + is_variable(o.is_variable), + sparsity((o.sparsity) ? new tflite::SparsityParametersT(*o.sparsity) : nullptr), + shape_signature(o.shape_signature), + has_rank(o.has_rank) { + variant_tensors.reserve(o.variant_tensors.size()); + for (const auto &variant_tensors_ : o.variant_tensors) { variant_tensors.emplace_back((variant_tensors_) ? new tflite::VariantSubTypeT(*variant_tensors_) : nullptr); } +} + +inline TensorT &TensorT::operator=(TensorT o) FLATBUFFERS_NOEXCEPT { + std::swap(shape, o.shape); + std::swap(type, o.type); + std::swap(buffer, o.buffer); + std::swap(name, o.name); + std::swap(quantization, o.quantization); + std::swap(is_variable, o.is_variable); + std::swap(sparsity, o.sparsity); + std::swap(shape_signature, o.shape_signature); + std::swap(has_rank, o.has_rank); + std::swap(variant_tensors, o.variant_tensors); + return *this; +} + +inline TensorT *Tensor::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new TensorT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Tensor::UnPackTo(TensorT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = shape(); if (_e) { _o->shape.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->shape[_i] = _e->Get(_i); } } } + { auto _e = type(); _o->type = _e; } + { auto _e = buffer(); _o->buffer = _e; } + { auto _e = name(); if (_e) _o->name = _e->str(); } + { auto _e = quantization(); if (_e) { if(_o->quantization) { _e->UnPackTo(_o->quantization.get(), _resolver); } else { _o->quantization = std::unique_ptr(_e->UnPack(_resolver)); } } } + { auto _e = is_variable(); _o->is_variable = _e; } + { auto _e = sparsity(); if (_e) { if(_o->sparsity) { _e->UnPackTo(_o->sparsity.get(), _resolver); } else { _o->sparsity = std::unique_ptr(_e->UnPack(_resolver)); } } } + { auto _e = shape_signature(); if (_e) { _o->shape_signature.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->shape_signature[_i] = _e->Get(_i); } } } + { auto _e = has_rank(); _o->has_rank = _e; } + { auto _e = variant_tensors(); if (_e) { _o->variant_tensors.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->variant_tensors[_i]) { _e->Get(_i)->UnPackTo(_o->variant_tensors[_i].get(), _resolver); } else { _o->variant_tensors[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } +} + +inline flatbuffers::Offset Tensor::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TensorT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTensor(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateTensor(flatbuffers::FlatBufferBuilder &_fbb, const TensorT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TensorT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _shape = _o->shape.size() ? _fbb.CreateVector(_o->shape) : 0; + auto _type = _o->type; + auto _buffer = _o->buffer; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + auto _quantization = _o->quantization ? CreateQuantizationParameters(_fbb, _o->quantization.get(), _rehasher) : 0; + auto _is_variable = _o->is_variable; + auto _sparsity = _o->sparsity ? CreateSparsityParameters(_fbb, _o->sparsity.get(), _rehasher) : 0; + auto _shape_signature = _o->shape_signature.size() ? _fbb.CreateVector(_o->shape_signature) : 0; + auto _has_rank = _o->has_rank; + auto _variant_tensors = _o->variant_tensors.size() ? _fbb.CreateVector> (_o->variant_tensors.size(), [](size_t i, _VectorArgs *__va) { return CreateVariantSubType(*__va->__fbb, __va->__o->variant_tensors[i].get(), __va->__rehasher); }, &_va ) : 0; + return tflite::CreateTensor( + _fbb, + _shape, + _type, + _buffer, + _name, + _quantization, + _is_variable, + _sparsity, + _shape_signature, + _has_rank, + _variant_tensors); +} + +inline Conv2DOptionsT *Conv2DOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Conv2DOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Conv2DOptions::UnPackTo(Conv2DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = padding(); _o->padding = _e; } + { auto _e = stride_w(); _o->stride_w = _e; } + { auto _e = stride_h(); _o->stride_h = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = dilation_w_factor(); _o->dilation_w_factor = _e; } + { auto _e = dilation_h_factor(); _o->dilation_h_factor = _e; } +} + +inline flatbuffers::Offset Conv2DOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Conv2DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateConv2DOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, const Conv2DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Conv2DOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _padding = _o->padding; + auto _stride_w = _o->stride_w; + auto _stride_h = _o->stride_h; + auto _fused_activation_function = _o->fused_activation_function; + auto _dilation_w_factor = _o->dilation_w_factor; + auto _dilation_h_factor = _o->dilation_h_factor; + return tflite::CreateConv2DOptions( + _fbb, + _padding, + _stride_w, + _stride_h, + _fused_activation_function, + _dilation_w_factor, + _dilation_h_factor); +} + +inline Conv3DOptionsT *Conv3DOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Conv3DOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Conv3DOptions::UnPackTo(Conv3DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = padding(); _o->padding = _e; } + { auto _e = stride_d(); _o->stride_d = _e; } + { auto _e = stride_w(); _o->stride_w = _e; } + { auto _e = stride_h(); _o->stride_h = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = dilation_d_factor(); _o->dilation_d_factor = _e; } + { auto _e = dilation_w_factor(); _o->dilation_w_factor = _e; } + { auto _e = dilation_h_factor(); _o->dilation_h_factor = _e; } +} + +inline flatbuffers::Offset Conv3DOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Conv3DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateConv3DOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateConv3DOptions(flatbuffers::FlatBufferBuilder &_fbb, const Conv3DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Conv3DOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _padding = _o->padding; + auto _stride_d = _o->stride_d; + auto _stride_w = _o->stride_w; + auto _stride_h = _o->stride_h; + auto _fused_activation_function = _o->fused_activation_function; + auto _dilation_d_factor = _o->dilation_d_factor; + auto _dilation_w_factor = _o->dilation_w_factor; + auto _dilation_h_factor = _o->dilation_h_factor; + return tflite::CreateConv3DOptions( + _fbb, + _padding, + _stride_d, + _stride_w, + _stride_h, + _fused_activation_function, + _dilation_d_factor, + _dilation_w_factor, + _dilation_h_factor); +} + +inline Pool2DOptionsT *Pool2DOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Pool2DOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Pool2DOptions::UnPackTo(Pool2DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = padding(); _o->padding = _e; } + { auto _e = stride_w(); _o->stride_w = _e; } + { auto _e = stride_h(); _o->stride_h = _e; } + { auto _e = filter_width(); _o->filter_width = _e; } + { auto _e = filter_height(); _o->filter_height = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } +} + +inline flatbuffers::Offset Pool2DOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Pool2DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreatePool2DOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreatePool2DOptions(flatbuffers::FlatBufferBuilder &_fbb, const Pool2DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Pool2DOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _padding = _o->padding; + auto _stride_w = _o->stride_w; + auto _stride_h = _o->stride_h; + auto _filter_width = _o->filter_width; + auto _filter_height = _o->filter_height; + auto _fused_activation_function = _o->fused_activation_function; + return tflite::CreatePool2DOptions( + _fbb, + _padding, + _stride_w, + _stride_h, + _filter_width, + _filter_height, + _fused_activation_function); +} + +inline DepthwiseConv2DOptionsT *DepthwiseConv2DOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DepthwiseConv2DOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DepthwiseConv2DOptions::UnPackTo(DepthwiseConv2DOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = padding(); _o->padding = _e; } + { auto _e = stride_w(); _o->stride_w = _e; } + { auto _e = stride_h(); _o->stride_h = _e; } + { auto _e = depth_multiplier(); _o->depth_multiplier = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = dilation_w_factor(); _o->dilation_w_factor = _e; } + { auto _e = dilation_h_factor(); _o->dilation_h_factor = _e; } +} + +inline flatbuffers::Offset DepthwiseConv2DOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DepthwiseConv2DOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDepthwiseConv2DOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDepthwiseConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, const DepthwiseConv2DOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DepthwiseConv2DOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _padding = _o->padding; + auto _stride_w = _o->stride_w; + auto _stride_h = _o->stride_h; + auto _depth_multiplier = _o->depth_multiplier; + auto _fused_activation_function = _o->fused_activation_function; + auto _dilation_w_factor = _o->dilation_w_factor; + auto _dilation_h_factor = _o->dilation_h_factor; + return tflite::CreateDepthwiseConv2DOptions( + _fbb, + _padding, + _stride_w, + _stride_h, + _depth_multiplier, + _fused_activation_function, + _dilation_w_factor, + _dilation_h_factor); +} + +inline ConcatEmbeddingsOptionsT *ConcatEmbeddingsOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ConcatEmbeddingsOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ConcatEmbeddingsOptions::UnPackTo(ConcatEmbeddingsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = num_channels(); _o->num_channels = _e; } + { auto _e = num_columns_per_channel(); if (_e) { _o->num_columns_per_channel.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->num_columns_per_channel[_i] = _e->Get(_i); } } } + { auto _e = embedding_dim_per_channel(); if (_e) { _o->embedding_dim_per_channel.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->embedding_dim_per_channel[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset ConcatEmbeddingsOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ConcatEmbeddingsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateConcatEmbeddingsOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateConcatEmbeddingsOptions(flatbuffers::FlatBufferBuilder &_fbb, const ConcatEmbeddingsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ConcatEmbeddingsOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _num_channels = _o->num_channels; + auto _num_columns_per_channel = _o->num_columns_per_channel.size() ? _fbb.CreateVector(_o->num_columns_per_channel) : 0; + auto _embedding_dim_per_channel = _o->embedding_dim_per_channel.size() ? _fbb.CreateVector(_o->embedding_dim_per_channel) : 0; + return tflite::CreateConcatEmbeddingsOptions( + _fbb, + _num_channels, + _num_columns_per_channel, + _embedding_dim_per_channel); +} + +inline LSHProjectionOptionsT *LSHProjectionOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LSHProjectionOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LSHProjectionOptions::UnPackTo(LSHProjectionOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = type(); _o->type = _e; } +} + +inline flatbuffers::Offset LSHProjectionOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LSHProjectionOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLSHProjectionOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLSHProjectionOptions(flatbuffers::FlatBufferBuilder &_fbb, const LSHProjectionOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LSHProjectionOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _type = _o->type; + return tflite::CreateLSHProjectionOptions( + _fbb, + _type); +} + +inline SVDFOptionsT *SVDFOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SVDFOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SVDFOptions::UnPackTo(SVDFOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = rank(); _o->rank = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset SVDFOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SVDFOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSVDFOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSVDFOptions(flatbuffers::FlatBufferBuilder &_fbb, const SVDFOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SVDFOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _rank = _o->rank; + auto _fused_activation_function = _o->fused_activation_function; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateSVDFOptions( + _fbb, + _rank, + _fused_activation_function, + _asymmetric_quantize_inputs); +} + +inline RNNOptionsT *RNNOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new RNNOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void RNNOptions::UnPackTo(RNNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset RNNOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const RNNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateRNNOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, const RNNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const RNNOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateRNNOptions( + _fbb, + _fused_activation_function, + _asymmetric_quantize_inputs); +} + +inline SequenceRNNOptionsT *SequenceRNNOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SequenceRNNOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SequenceRNNOptions::UnPackTo(SequenceRNNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = time_major(); _o->time_major = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset SequenceRNNOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SequenceRNNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSequenceRNNOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSequenceRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, const SequenceRNNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SequenceRNNOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _time_major = _o->time_major; + auto _fused_activation_function = _o->fused_activation_function; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateSequenceRNNOptions( + _fbb, + _time_major, + _fused_activation_function, + _asymmetric_quantize_inputs); +} + +inline BidirectionalSequenceRNNOptionsT *BidirectionalSequenceRNNOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BidirectionalSequenceRNNOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void BidirectionalSequenceRNNOptions::UnPackTo(BidirectionalSequenceRNNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = time_major(); _o->time_major = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = merge_outputs(); _o->merge_outputs = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset BidirectionalSequenceRNNOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceRNNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBidirectionalSequenceRNNOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBidirectionalSequenceRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceRNNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BidirectionalSequenceRNNOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _time_major = _o->time_major; + auto _fused_activation_function = _o->fused_activation_function; + auto _merge_outputs = _o->merge_outputs; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateBidirectionalSequenceRNNOptions( + _fbb, + _time_major, + _fused_activation_function, + _merge_outputs, + _asymmetric_quantize_inputs); +} + +inline FullyConnectedOptionsT *FullyConnectedOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new FullyConnectedOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void FullyConnectedOptions::UnPackTo(FullyConnectedOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = weights_format(); _o->weights_format = _e; } + { auto _e = keep_num_dims(); _o->keep_num_dims = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset FullyConnectedOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FullyConnectedOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateFullyConnectedOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateFullyConnectedOptions(flatbuffers::FlatBufferBuilder &_fbb, const FullyConnectedOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FullyConnectedOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _weights_format = _o->weights_format; + auto _keep_num_dims = _o->keep_num_dims; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateFullyConnectedOptions( + _fbb, + _fused_activation_function, + _weights_format, + _keep_num_dims, + _asymmetric_quantize_inputs); +} + +inline SoftmaxOptionsT *SoftmaxOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SoftmaxOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SoftmaxOptions::UnPackTo(SoftmaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = beta(); _o->beta = _e; } +} + +inline flatbuffers::Offset SoftmaxOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SoftmaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSoftmaxOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const SoftmaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SoftmaxOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _beta = _o->beta; + return tflite::CreateSoftmaxOptions( + _fbb, + _beta); +} + +inline ConcatenationOptionsT *ConcatenationOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ConcatenationOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ConcatenationOptions::UnPackTo(ConcatenationOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = axis(); _o->axis = _e; } + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } +} + +inline flatbuffers::Offset ConcatenationOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ConcatenationOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateConcatenationOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateConcatenationOptions(flatbuffers::FlatBufferBuilder &_fbb, const ConcatenationOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ConcatenationOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _axis = _o->axis; + auto _fused_activation_function = _o->fused_activation_function; + return tflite::CreateConcatenationOptions( + _fbb, + _axis, + _fused_activation_function); +} + +inline AddOptionsT *AddOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new AddOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AddOptions::UnPackTo(AddOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = pot_scale_int16(); _o->pot_scale_int16 = _e; } +} + +inline flatbuffers::Offset AddOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AddOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAddOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAddOptions(flatbuffers::FlatBufferBuilder &_fbb, const AddOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AddOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _pot_scale_int16 = _o->pot_scale_int16; + return tflite::CreateAddOptions( + _fbb, + _fused_activation_function, + _pot_scale_int16); +} + +inline MulOptionsT *MulOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new MulOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void MulOptions::UnPackTo(MulOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } +} + +inline flatbuffers::Offset MulOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MulOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMulOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMulOptions(flatbuffers::FlatBufferBuilder &_fbb, const MulOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MulOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + return tflite::CreateMulOptions( + _fbb, + _fused_activation_function); +} + +inline L2NormOptionsT *L2NormOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new L2NormOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void L2NormOptions::UnPackTo(L2NormOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } +} + +inline flatbuffers::Offset L2NormOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const L2NormOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateL2NormOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateL2NormOptions(flatbuffers::FlatBufferBuilder &_fbb, const L2NormOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const L2NormOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + return tflite::CreateL2NormOptions( + _fbb, + _fused_activation_function); +} + +inline LocalResponseNormalizationOptionsT *LocalResponseNormalizationOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LocalResponseNormalizationOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LocalResponseNormalizationOptions::UnPackTo(LocalResponseNormalizationOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = radius(); _o->radius = _e; } + { auto _e = bias(); _o->bias = _e; } + { auto _e = alpha(); _o->alpha = _e; } + { auto _e = beta(); _o->beta = _e; } +} + +inline flatbuffers::Offset LocalResponseNormalizationOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LocalResponseNormalizationOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLocalResponseNormalizationOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLocalResponseNormalizationOptions(flatbuffers::FlatBufferBuilder &_fbb, const LocalResponseNormalizationOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LocalResponseNormalizationOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _radius = _o->radius; + auto _bias = _o->bias; + auto _alpha = _o->alpha; + auto _beta = _o->beta; + return tflite::CreateLocalResponseNormalizationOptions( + _fbb, + _radius, + _bias, + _alpha, + _beta); +} + +inline LSTMOptionsT *LSTMOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LSTMOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LSTMOptions::UnPackTo(LSTMOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = cell_clip(); _o->cell_clip = _e; } + { auto _e = proj_clip(); _o->proj_clip = _e; } + { auto _e = kernel_type(); _o->kernel_type = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset LSTMOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LSTMOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLSTMOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, const LSTMOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LSTMOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _cell_clip = _o->cell_clip; + auto _proj_clip = _o->proj_clip; + auto _kernel_type = _o->kernel_type; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateLSTMOptions( + _fbb, + _fused_activation_function, + _cell_clip, + _proj_clip, + _kernel_type, + _asymmetric_quantize_inputs); +} + +inline UnidirectionalSequenceLSTMOptionsT *UnidirectionalSequenceLSTMOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UnidirectionalSequenceLSTMOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UnidirectionalSequenceLSTMOptions::UnPackTo(UnidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = cell_clip(); _o->cell_clip = _e; } + { auto _e = proj_clip(); _o->proj_clip = _e; } + { auto _e = time_major(); _o->time_major = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset UnidirectionalSequenceLSTMOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnidirectionalSequenceLSTMOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUnidirectionalSequenceLSTMOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUnidirectionalSequenceLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UnidirectionalSequenceLSTMOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _cell_clip = _o->cell_clip; + auto _proj_clip = _o->proj_clip; + auto _time_major = _o->time_major; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateUnidirectionalSequenceLSTMOptions( + _fbb, + _fused_activation_function, + _cell_clip, + _proj_clip, + _time_major, + _asymmetric_quantize_inputs); +} + +inline BidirectionalSequenceLSTMOptionsT *BidirectionalSequenceLSTMOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BidirectionalSequenceLSTMOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void BidirectionalSequenceLSTMOptions::UnPackTo(BidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = cell_clip(); _o->cell_clip = _e; } + { auto _e = proj_clip(); _o->proj_clip = _e; } + { auto _e = merge_outputs(); _o->merge_outputs = _e; } + { auto _e = time_major(); _o->time_major = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset BidirectionalSequenceLSTMOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceLSTMOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBidirectionalSequenceLSTMOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBidirectionalSequenceLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, const BidirectionalSequenceLSTMOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BidirectionalSequenceLSTMOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _cell_clip = _o->cell_clip; + auto _proj_clip = _o->proj_clip; + auto _merge_outputs = _o->merge_outputs; + auto _time_major = _o->time_major; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateBidirectionalSequenceLSTMOptions( + _fbb, + _fused_activation_function, + _cell_clip, + _proj_clip, + _merge_outputs, + _time_major, + _asymmetric_quantize_inputs); +} + +inline ResizeBilinearOptionsT *ResizeBilinearOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ResizeBilinearOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ResizeBilinearOptions::UnPackTo(ResizeBilinearOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = align_corners(); _o->align_corners = _e; } + { auto _e = half_pixel_centers(); _o->half_pixel_centers = _e; } +} + +inline flatbuffers::Offset ResizeBilinearOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ResizeBilinearOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateResizeBilinearOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateResizeBilinearOptions(flatbuffers::FlatBufferBuilder &_fbb, const ResizeBilinearOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ResizeBilinearOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _align_corners = _o->align_corners; + auto _half_pixel_centers = _o->half_pixel_centers; + return tflite::CreateResizeBilinearOptions( + _fbb, + _align_corners, + _half_pixel_centers); +} + +inline ResizeNearestNeighborOptionsT *ResizeNearestNeighborOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ResizeNearestNeighborOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ResizeNearestNeighborOptions::UnPackTo(ResizeNearestNeighborOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = align_corners(); _o->align_corners = _e; } + { auto _e = half_pixel_centers(); _o->half_pixel_centers = _e; } +} + +inline flatbuffers::Offset ResizeNearestNeighborOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ResizeNearestNeighborOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateResizeNearestNeighborOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateResizeNearestNeighborOptions(flatbuffers::FlatBufferBuilder &_fbb, const ResizeNearestNeighborOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ResizeNearestNeighborOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _align_corners = _o->align_corners; + auto _half_pixel_centers = _o->half_pixel_centers; + return tflite::CreateResizeNearestNeighborOptions( + _fbb, + _align_corners, + _half_pixel_centers); +} + +inline CallOptionsT *CallOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CallOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void CallOptions::UnPackTo(CallOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = subgraph(); _o->subgraph = _e; } +} + +inline flatbuffers::Offset CallOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const CallOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateCallOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateCallOptions(flatbuffers::FlatBufferBuilder &_fbb, const CallOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const CallOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _subgraph = _o->subgraph; + return tflite::CreateCallOptions( + _fbb, + _subgraph); +} + +inline PadOptionsT *PadOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new PadOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void PadOptions::UnPackTo(PadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset PadOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const PadOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreatePadOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreatePadOptions(flatbuffers::FlatBufferBuilder &_fbb, const PadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const PadOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreatePadOptions( + _fbb); +} + +inline PadV2OptionsT *PadV2Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new PadV2OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void PadV2Options::UnPackTo(PadV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset PadV2Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const PadV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreatePadV2Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreatePadV2Options(flatbuffers::FlatBufferBuilder &_fbb, const PadV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const PadV2OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreatePadV2Options( + _fbb); +} + +inline ReshapeOptionsT *ReshapeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ReshapeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ReshapeOptions::UnPackTo(ReshapeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = new_shape(); if (_e) { _o->new_shape.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->new_shape[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset ReshapeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReshapeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateReshapeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateReshapeOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReshapeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ReshapeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _new_shape = _o->new_shape.size() ? _fbb.CreateVector(_o->new_shape) : 0; + return tflite::CreateReshapeOptions( + _fbb, + _new_shape); +} + +inline SpaceToBatchNDOptionsT *SpaceToBatchNDOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SpaceToBatchNDOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SpaceToBatchNDOptions::UnPackTo(SpaceToBatchNDOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SpaceToBatchNDOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToBatchNDOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSpaceToBatchNDOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSpaceToBatchNDOptions(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToBatchNDOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SpaceToBatchNDOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSpaceToBatchNDOptions( + _fbb); +} + +inline BatchToSpaceNDOptionsT *BatchToSpaceNDOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BatchToSpaceNDOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void BatchToSpaceNDOptions::UnPackTo(BatchToSpaceNDOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset BatchToSpaceNDOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BatchToSpaceNDOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBatchToSpaceNDOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBatchToSpaceNDOptions(flatbuffers::FlatBufferBuilder &_fbb, const BatchToSpaceNDOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BatchToSpaceNDOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateBatchToSpaceNDOptions( + _fbb); +} + +inline SkipGramOptionsT *SkipGramOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SkipGramOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SkipGramOptions::UnPackTo(SkipGramOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = ngram_size(); _o->ngram_size = _e; } + { auto _e = max_skip_size(); _o->max_skip_size = _e; } + { auto _e = include_all_ngrams(); _o->include_all_ngrams = _e; } +} + +inline flatbuffers::Offset SkipGramOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SkipGramOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSkipGramOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSkipGramOptions(flatbuffers::FlatBufferBuilder &_fbb, const SkipGramOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SkipGramOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _ngram_size = _o->ngram_size; + auto _max_skip_size = _o->max_skip_size; + auto _include_all_ngrams = _o->include_all_ngrams; + return tflite::CreateSkipGramOptions( + _fbb, + _ngram_size, + _max_skip_size, + _include_all_ngrams); +} + +inline SpaceToDepthOptionsT *SpaceToDepthOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SpaceToDepthOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SpaceToDepthOptions::UnPackTo(SpaceToDepthOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = block_size(); _o->block_size = _e; } +} + +inline flatbuffers::Offset SpaceToDepthOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToDepthOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSpaceToDepthOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSpaceToDepthOptions(flatbuffers::FlatBufferBuilder &_fbb, const SpaceToDepthOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SpaceToDepthOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _block_size = _o->block_size; + return tflite::CreateSpaceToDepthOptions( + _fbb, + _block_size); +} + +inline DepthToSpaceOptionsT *DepthToSpaceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DepthToSpaceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DepthToSpaceOptions::UnPackTo(DepthToSpaceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = block_size(); _o->block_size = _e; } +} + +inline flatbuffers::Offset DepthToSpaceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DepthToSpaceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDepthToSpaceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDepthToSpaceOptions(flatbuffers::FlatBufferBuilder &_fbb, const DepthToSpaceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DepthToSpaceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _block_size = _o->block_size; + return tflite::CreateDepthToSpaceOptions( + _fbb, + _block_size); +} + +inline SubOptionsT *SubOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SubOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SubOptions::UnPackTo(SubOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } + { auto _e = pot_scale_int16(); _o->pot_scale_int16 = _e; } +} + +inline flatbuffers::Offset SubOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SubOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSubOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSubOptions(flatbuffers::FlatBufferBuilder &_fbb, const SubOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SubOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + auto _pot_scale_int16 = _o->pot_scale_int16; + return tflite::CreateSubOptions( + _fbb, + _fused_activation_function, + _pot_scale_int16); +} + +inline DivOptionsT *DivOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DivOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DivOptions::UnPackTo(DivOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = fused_activation_function(); _o->fused_activation_function = _e; } +} + +inline flatbuffers::Offset DivOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DivOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDivOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDivOptions(flatbuffers::FlatBufferBuilder &_fbb, const DivOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DivOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _fused_activation_function = _o->fused_activation_function; + return tflite::CreateDivOptions( + _fbb, + _fused_activation_function); +} + +inline TopKV2OptionsT *TopKV2Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new TopKV2OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void TopKV2Options::UnPackTo(TopKV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset TopKV2Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TopKV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTopKV2Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateTopKV2Options(flatbuffers::FlatBufferBuilder &_fbb, const TopKV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TopKV2OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateTopKV2Options( + _fbb); +} + +inline EmbeddingLookupSparseOptionsT *EmbeddingLookupSparseOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new EmbeddingLookupSparseOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void EmbeddingLookupSparseOptions::UnPackTo(EmbeddingLookupSparseOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = combiner(); _o->combiner = _e; } +} + +inline flatbuffers::Offset EmbeddingLookupSparseOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const EmbeddingLookupSparseOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateEmbeddingLookupSparseOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateEmbeddingLookupSparseOptions(flatbuffers::FlatBufferBuilder &_fbb, const EmbeddingLookupSparseOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const EmbeddingLookupSparseOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _combiner = _o->combiner; + return tflite::CreateEmbeddingLookupSparseOptions( + _fbb, + _combiner); +} + +inline GatherOptionsT *GatherOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new GatherOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void GatherOptions::UnPackTo(GatherOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = axis(); _o->axis = _e; } + { auto _e = batch_dims(); _o->batch_dims = _e; } +} + +inline flatbuffers::Offset GatherOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const GatherOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateGatherOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateGatherOptions(flatbuffers::FlatBufferBuilder &_fbb, const GatherOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const GatherOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _axis = _o->axis; + auto _batch_dims = _o->batch_dims; + return tflite::CreateGatherOptions( + _fbb, + _axis, + _batch_dims); +} + +inline TransposeOptionsT *TransposeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new TransposeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void TransposeOptions::UnPackTo(TransposeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset TransposeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TransposeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTransposeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateTransposeOptions(flatbuffers::FlatBufferBuilder &_fbb, const TransposeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TransposeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateTransposeOptions( + _fbb); +} + +inline ExpOptionsT *ExpOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ExpOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ExpOptions::UnPackTo(ExpOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ExpOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ExpOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateExpOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateExpOptions(flatbuffers::FlatBufferBuilder &_fbb, const ExpOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ExpOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateExpOptions( + _fbb); +} + +inline CosOptionsT *CosOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CosOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void CosOptions::UnPackTo(CosOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset CosOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const CosOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateCosOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateCosOptions(flatbuffers::FlatBufferBuilder &_fbb, const CosOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const CosOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateCosOptions( + _fbb); +} + +inline ReducerOptionsT *ReducerOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ReducerOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ReducerOptions::UnPackTo(ReducerOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = keep_dims(); _o->keep_dims = _e; } +} + +inline flatbuffers::Offset ReducerOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReducerOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateReducerOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateReducerOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReducerOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ReducerOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _keep_dims = _o->keep_dims; + return tflite::CreateReducerOptions( + _fbb, + _keep_dims); +} + +inline SqueezeOptionsT *SqueezeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SqueezeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SqueezeOptions::UnPackTo(SqueezeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = squeeze_dims(); if (_e) { _o->squeeze_dims.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->squeeze_dims[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset SqueezeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SqueezeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSqueezeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSqueezeOptions(flatbuffers::FlatBufferBuilder &_fbb, const SqueezeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SqueezeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _squeeze_dims = _o->squeeze_dims.size() ? _fbb.CreateVector(_o->squeeze_dims) : 0; + return tflite::CreateSqueezeOptions( + _fbb, + _squeeze_dims); +} + +inline SplitOptionsT *SplitOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SplitOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SplitOptions::UnPackTo(SplitOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = num_splits(); _o->num_splits = _e; } +} + +inline flatbuffers::Offset SplitOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SplitOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSplitOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SplitOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _num_splits = _o->num_splits; + return tflite::CreateSplitOptions( + _fbb, + _num_splits); +} + +inline SplitVOptionsT *SplitVOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SplitVOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SplitVOptions::UnPackTo(SplitVOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = num_splits(); _o->num_splits = _e; } +} + +inline flatbuffers::Offset SplitVOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSplitVOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb, const SplitVOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SplitVOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _num_splits = _o->num_splits; + return tflite::CreateSplitVOptions( + _fbb, + _num_splits); +} + +inline StridedSliceOptionsT *StridedSliceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new StridedSliceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void StridedSliceOptions::UnPackTo(StridedSliceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = begin_mask(); _o->begin_mask = _e; } + { auto _e = end_mask(); _o->end_mask = _e; } + { auto _e = ellipsis_mask(); _o->ellipsis_mask = _e; } + { auto _e = new_axis_mask(); _o->new_axis_mask = _e; } + { auto _e = shrink_axis_mask(); _o->shrink_axis_mask = _e; } +} + +inline flatbuffers::Offset StridedSliceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateStridedSliceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateStridedSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, const StridedSliceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const StridedSliceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _begin_mask = _o->begin_mask; + auto _end_mask = _o->end_mask; + auto _ellipsis_mask = _o->ellipsis_mask; + auto _new_axis_mask = _o->new_axis_mask; + auto _shrink_axis_mask = _o->shrink_axis_mask; + return tflite::CreateStridedSliceOptions( + _fbb, + _begin_mask, + _end_mask, + _ellipsis_mask, + _new_axis_mask, + _shrink_axis_mask); +} + +inline LogSoftmaxOptionsT *LogSoftmaxOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LogSoftmaxOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LogSoftmaxOptions::UnPackTo(LogSoftmaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset LogSoftmaxOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogSoftmaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLogSoftmaxOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLogSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogSoftmaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LogSoftmaxOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateLogSoftmaxOptions( + _fbb); +} + +inline CastOptionsT *CastOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CastOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void CastOptions::UnPackTo(CastOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = in_data_type(); _o->in_data_type = _e; } + { auto _e = out_data_type(); _o->out_data_type = _e; } +} + +inline flatbuffers::Offset CastOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const CastOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateCastOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateCastOptions(flatbuffers::FlatBufferBuilder &_fbb, const CastOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const CastOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _in_data_type = _o->in_data_type; + auto _out_data_type = _o->out_data_type; + return tflite::CreateCastOptions( + _fbb, + _in_data_type, + _out_data_type); +} + +inline DequantizeOptionsT *DequantizeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DequantizeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DequantizeOptions::UnPackTo(DequantizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset DequantizeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DequantizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDequantizeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDequantizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const DequantizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DequantizeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateDequantizeOptions( + _fbb); +} + +inline MaximumMinimumOptionsT *MaximumMinimumOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new MaximumMinimumOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void MaximumMinimumOptions::UnPackTo(MaximumMinimumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset MaximumMinimumOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MaximumMinimumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMaximumMinimumOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMaximumMinimumOptions(flatbuffers::FlatBufferBuilder &_fbb, const MaximumMinimumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MaximumMinimumOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateMaximumMinimumOptions( + _fbb); +} + +inline TileOptionsT *TileOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new TileOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void TileOptions::UnPackTo(TileOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset TileOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TileOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTileOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateTileOptions(flatbuffers::FlatBufferBuilder &_fbb, const TileOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TileOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateTileOptions( + _fbb); +} + +inline ArgMaxOptionsT *ArgMaxOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ArgMaxOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ArgMaxOptions::UnPackTo(ArgMaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = output_type(); _o->output_type = _e; } +} + +inline flatbuffers::Offset ArgMaxOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ArgMaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateArgMaxOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateArgMaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const ArgMaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ArgMaxOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _output_type = _o->output_type; + return tflite::CreateArgMaxOptions( + _fbb, + _output_type); +} + +inline ArgMinOptionsT *ArgMinOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ArgMinOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ArgMinOptions::UnPackTo(ArgMinOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = output_type(); _o->output_type = _e; } +} + +inline flatbuffers::Offset ArgMinOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ArgMinOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateArgMinOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateArgMinOptions(flatbuffers::FlatBufferBuilder &_fbb, const ArgMinOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ArgMinOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _output_type = _o->output_type; + return tflite::CreateArgMinOptions( + _fbb, + _output_type); +} + +inline GreaterOptionsT *GreaterOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new GreaterOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void GreaterOptions::UnPackTo(GreaterOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset GreaterOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const GreaterOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateGreaterOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateGreaterOptions(flatbuffers::FlatBufferBuilder &_fbb, const GreaterOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const GreaterOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateGreaterOptions( + _fbb); +} + +inline GreaterEqualOptionsT *GreaterEqualOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new GreaterEqualOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void GreaterEqualOptions::UnPackTo(GreaterEqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset GreaterEqualOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const GreaterEqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateGreaterEqualOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateGreaterEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const GreaterEqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const GreaterEqualOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateGreaterEqualOptions( + _fbb); +} + +inline LessOptionsT *LessOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LessOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LessOptions::UnPackTo(LessOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset LessOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LessOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLessOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLessOptions(flatbuffers::FlatBufferBuilder &_fbb, const LessOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LessOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateLessOptions( + _fbb); +} + +inline LessEqualOptionsT *LessEqualOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LessEqualOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LessEqualOptions::UnPackTo(LessEqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset LessEqualOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LessEqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLessEqualOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLessEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const LessEqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LessEqualOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateLessEqualOptions( + _fbb); +} + +inline NegOptionsT *NegOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new NegOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void NegOptions::UnPackTo(NegOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset NegOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const NegOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateNegOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateNegOptions(flatbuffers::FlatBufferBuilder &_fbb, const NegOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const NegOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateNegOptions( + _fbb); +} + +inline SelectOptionsT *SelectOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SelectOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SelectOptions::UnPackTo(SelectOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SelectOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SelectOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSelectOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSelectOptions(flatbuffers::FlatBufferBuilder &_fbb, const SelectOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SelectOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSelectOptions( + _fbb); +} + +inline SliceOptionsT *SliceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SliceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SliceOptions::UnPackTo(SliceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SliceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SliceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSliceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, const SliceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SliceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSliceOptions( + _fbb); +} + +inline TransposeConvOptionsT *TransposeConvOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new TransposeConvOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void TransposeConvOptions::UnPackTo(TransposeConvOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = padding(); _o->padding = _e; } + { auto _e = stride_w(); _o->stride_w = _e; } + { auto _e = stride_h(); _o->stride_h = _e; } +} + +inline flatbuffers::Offset TransposeConvOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TransposeConvOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTransposeConvOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateTransposeConvOptions(flatbuffers::FlatBufferBuilder &_fbb, const TransposeConvOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TransposeConvOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _padding = _o->padding; + auto _stride_w = _o->stride_w; + auto _stride_h = _o->stride_h; + return tflite::CreateTransposeConvOptions( + _fbb, + _padding, + _stride_w, + _stride_h); +} + +inline ExpandDimsOptionsT *ExpandDimsOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ExpandDimsOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ExpandDimsOptions::UnPackTo(ExpandDimsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ExpandDimsOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ExpandDimsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateExpandDimsOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateExpandDimsOptions(flatbuffers::FlatBufferBuilder &_fbb, const ExpandDimsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ExpandDimsOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateExpandDimsOptions( + _fbb); +} + +inline SparseToDenseOptionsT *SparseToDenseOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SparseToDenseOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SparseToDenseOptions::UnPackTo(SparseToDenseOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = validate_indices(); _o->validate_indices = _e; } +} + +inline flatbuffers::Offset SparseToDenseOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SparseToDenseOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSparseToDenseOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSparseToDenseOptions(flatbuffers::FlatBufferBuilder &_fbb, const SparseToDenseOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SparseToDenseOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _validate_indices = _o->validate_indices; + return tflite::CreateSparseToDenseOptions( + _fbb, + _validate_indices); +} + +inline EqualOptionsT *EqualOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new EqualOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void EqualOptions::UnPackTo(EqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset EqualOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const EqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateEqualOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const EqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const EqualOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateEqualOptions( + _fbb); +} + +inline NotEqualOptionsT *NotEqualOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new NotEqualOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void NotEqualOptions::UnPackTo(NotEqualOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset NotEqualOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const NotEqualOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateNotEqualOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateNotEqualOptions(flatbuffers::FlatBufferBuilder &_fbb, const NotEqualOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const NotEqualOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateNotEqualOptions( + _fbb); +} + +inline ShapeOptionsT *ShapeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ShapeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ShapeOptions::UnPackTo(ShapeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = out_type(); _o->out_type = _e; } +} + +inline flatbuffers::Offset ShapeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ShapeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateShapeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateShapeOptions(flatbuffers::FlatBufferBuilder &_fbb, const ShapeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ShapeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _out_type = _o->out_type; + return tflite::CreateShapeOptions( + _fbb, + _out_type); +} + +inline RankOptionsT *RankOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new RankOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void RankOptions::UnPackTo(RankOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset RankOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const RankOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateRankOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateRankOptions(flatbuffers::FlatBufferBuilder &_fbb, const RankOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const RankOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateRankOptions( + _fbb); +} + +inline PowOptionsT *PowOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new PowOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void PowOptions::UnPackTo(PowOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset PowOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const PowOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreatePowOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreatePowOptions(flatbuffers::FlatBufferBuilder &_fbb, const PowOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const PowOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreatePowOptions( + _fbb); +} + +inline FakeQuantOptionsT *FakeQuantOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new FakeQuantOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void FakeQuantOptions::UnPackTo(FakeQuantOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = min(); _o->min = _e; } + { auto _e = max(); _o->max = _e; } + { auto _e = num_bits(); _o->num_bits = _e; } + { auto _e = narrow_range(); _o->narrow_range = _e; } +} + +inline flatbuffers::Offset FakeQuantOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FakeQuantOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateFakeQuantOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateFakeQuantOptions(flatbuffers::FlatBufferBuilder &_fbb, const FakeQuantOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FakeQuantOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _min = _o->min; + auto _max = _o->max; + auto _num_bits = _o->num_bits; + auto _narrow_range = _o->narrow_range; + return tflite::CreateFakeQuantOptions( + _fbb, + _min, + _max, + _num_bits, + _narrow_range); +} + +inline PackOptionsT *PackOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new PackOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void PackOptions::UnPackTo(PackOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = values_count(); _o->values_count = _e; } + { auto _e = axis(); _o->axis = _e; } +} + +inline flatbuffers::Offset PackOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const PackOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreatePackOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreatePackOptions(flatbuffers::FlatBufferBuilder &_fbb, const PackOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const PackOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _values_count = _o->values_count; + auto _axis = _o->axis; + return tflite::CreatePackOptions( + _fbb, + _values_count, + _axis); +} + +inline LogicalOrOptionsT *LogicalOrOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LogicalOrOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LogicalOrOptions::UnPackTo(LogicalOrOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset LogicalOrOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogicalOrOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLogicalOrOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLogicalOrOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogicalOrOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LogicalOrOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateLogicalOrOptions( + _fbb); +} + +inline OneHotOptionsT *OneHotOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new OneHotOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void OneHotOptions::UnPackTo(OneHotOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = axis(); _o->axis = _e; } +} + +inline flatbuffers::Offset OneHotOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const OneHotOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateOneHotOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb, const OneHotOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const OneHotOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _axis = _o->axis; + return tflite::CreateOneHotOptions( + _fbb, + _axis); +} + +inline AbsOptionsT *AbsOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new AbsOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AbsOptions::UnPackTo(AbsOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset AbsOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAbsOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb, const AbsOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AbsOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateAbsOptions( + _fbb); +} + +inline HardSwishOptionsT *HardSwishOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new HardSwishOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void HardSwishOptions::UnPackTo(HardSwishOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset HardSwishOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const HardSwishOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateHardSwishOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateHardSwishOptions(flatbuffers::FlatBufferBuilder &_fbb, const HardSwishOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const HardSwishOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateHardSwishOptions( + _fbb); +} + +inline LogicalAndOptionsT *LogicalAndOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LogicalAndOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LogicalAndOptions::UnPackTo(LogicalAndOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset LogicalAndOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogicalAndOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLogicalAndOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLogicalAndOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogicalAndOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LogicalAndOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateLogicalAndOptions( + _fbb); +} + +inline LogicalNotOptionsT *LogicalNotOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LogicalNotOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LogicalNotOptions::UnPackTo(LogicalNotOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset LogicalNotOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LogicalNotOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLogicalNotOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLogicalNotOptions(flatbuffers::FlatBufferBuilder &_fbb, const LogicalNotOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LogicalNotOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateLogicalNotOptions( + _fbb); +} + +inline UnpackOptionsT *UnpackOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UnpackOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UnpackOptions::UnPackTo(UnpackOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = num(); _o->num = _e; } + { auto _e = axis(); _o->axis = _e; } +} + +inline flatbuffers::Offset UnpackOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnpackOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUnpackOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUnpackOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnpackOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UnpackOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _num = _o->num; + auto _axis = _o->axis; + return tflite::CreateUnpackOptions( + _fbb, + _num, + _axis); +} + +inline FloorDivOptionsT *FloorDivOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new FloorDivOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void FloorDivOptions::UnPackTo(FloorDivOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset FloorDivOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FloorDivOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateFloorDivOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateFloorDivOptions(flatbuffers::FlatBufferBuilder &_fbb, const FloorDivOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FloorDivOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateFloorDivOptions( + _fbb); +} + +inline SquareOptionsT *SquareOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SquareOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SquareOptions::UnPackTo(SquareOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SquareOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SquareOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSquareOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSquareOptions(flatbuffers::FlatBufferBuilder &_fbb, const SquareOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SquareOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSquareOptions( + _fbb); +} + +inline ZerosLikeOptionsT *ZerosLikeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ZerosLikeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ZerosLikeOptions::UnPackTo(ZerosLikeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ZerosLikeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ZerosLikeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateZerosLikeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateZerosLikeOptions(flatbuffers::FlatBufferBuilder &_fbb, const ZerosLikeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ZerosLikeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateZerosLikeOptions( + _fbb); +} + +inline FillOptionsT *FillOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new FillOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void FillOptions::UnPackTo(FillOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset FillOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FillOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateFillOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateFillOptions(flatbuffers::FlatBufferBuilder &_fbb, const FillOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FillOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateFillOptions( + _fbb); +} + +inline FloorModOptionsT *FloorModOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new FloorModOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void FloorModOptions::UnPackTo(FloorModOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset FloorModOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FloorModOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateFloorModOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateFloorModOptions(flatbuffers::FlatBufferBuilder &_fbb, const FloorModOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FloorModOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateFloorModOptions( + _fbb); +} + +inline RangeOptionsT *RangeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new RangeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void RangeOptions::UnPackTo(RangeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset RangeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const RangeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateRangeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateRangeOptions(flatbuffers::FlatBufferBuilder &_fbb, const RangeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const RangeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateRangeOptions( + _fbb); +} + +inline LeakyReluOptionsT *LeakyReluOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new LeakyReluOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void LeakyReluOptions::UnPackTo(LeakyReluOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = alpha(); _o->alpha = _e; } +} + +inline flatbuffers::Offset LeakyReluOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LeakyReluOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateLeakyReluOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateLeakyReluOptions(flatbuffers::FlatBufferBuilder &_fbb, const LeakyReluOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const LeakyReluOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _alpha = _o->alpha; + return tflite::CreateLeakyReluOptions( + _fbb, + _alpha); +} + +inline SquaredDifferenceOptionsT *SquaredDifferenceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SquaredDifferenceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SquaredDifferenceOptions::UnPackTo(SquaredDifferenceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SquaredDifferenceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SquaredDifferenceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSquaredDifferenceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb, const SquaredDifferenceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SquaredDifferenceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSquaredDifferenceOptions( + _fbb); +} + +inline MirrorPadOptionsT *MirrorPadOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new MirrorPadOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void MirrorPadOptions::UnPackTo(MirrorPadOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = mode(); _o->mode = _e; } +} + +inline flatbuffers::Offset MirrorPadOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMirrorPadOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb, const MirrorPadOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MirrorPadOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _mode = _o->mode; + return tflite::CreateMirrorPadOptions( + _fbb, + _mode); +} + +inline UniqueOptionsT *UniqueOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UniqueOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UniqueOptions::UnPackTo(UniqueOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = idx_out_type(); _o->idx_out_type = _e; } +} + +inline flatbuffers::Offset UniqueOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UniqueOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUniqueOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUniqueOptions(flatbuffers::FlatBufferBuilder &_fbb, const UniqueOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UniqueOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _idx_out_type = _o->idx_out_type; + return tflite::CreateUniqueOptions( + _fbb, + _idx_out_type); +} + +inline ReverseV2OptionsT *ReverseV2Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ReverseV2OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ReverseV2Options::UnPackTo(ReverseV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ReverseV2Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReverseV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateReverseV2Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateReverseV2Options(flatbuffers::FlatBufferBuilder &_fbb, const ReverseV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ReverseV2OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateReverseV2Options( + _fbb); +} + +inline AddNOptionsT *AddNOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new AddNOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AddNOptions::UnPackTo(AddNOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset AddNOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AddNOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAddNOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAddNOptions(flatbuffers::FlatBufferBuilder &_fbb, const AddNOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AddNOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateAddNOptions( + _fbb); +} + +inline GatherNdOptionsT *GatherNdOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new GatherNdOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void GatherNdOptions::UnPackTo(GatherNdOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset GatherNdOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const GatherNdOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateGatherNdOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateGatherNdOptions(flatbuffers::FlatBufferBuilder &_fbb, const GatherNdOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const GatherNdOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateGatherNdOptions( + _fbb); +} + +inline WhereOptionsT *WhereOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new WhereOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void WhereOptions::UnPackTo(WhereOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset WhereOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const WhereOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateWhereOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateWhereOptions(flatbuffers::FlatBufferBuilder &_fbb, const WhereOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const WhereOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateWhereOptions( + _fbb); +} + +inline ReverseSequenceOptionsT *ReverseSequenceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ReverseSequenceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ReverseSequenceOptions::UnPackTo(ReverseSequenceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = seq_dim(); _o->seq_dim = _e; } + { auto _e = batch_dim(); _o->batch_dim = _e; } +} + +inline flatbuffers::Offset ReverseSequenceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReverseSequenceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateReverseSequenceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateReverseSequenceOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReverseSequenceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ReverseSequenceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _seq_dim = _o->seq_dim; + auto _batch_dim = _o->batch_dim; + return tflite::CreateReverseSequenceOptions( + _fbb, + _seq_dim, + _batch_dim); +} + +inline MatrixDiagOptionsT *MatrixDiagOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new MatrixDiagOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void MatrixDiagOptions::UnPackTo(MatrixDiagOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset MatrixDiagOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MatrixDiagOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMatrixDiagOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMatrixDiagOptions(flatbuffers::FlatBufferBuilder &_fbb, const MatrixDiagOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MatrixDiagOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateMatrixDiagOptions( + _fbb); +} + +inline QuantizeOptionsT *QuantizeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new QuantizeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void QuantizeOptions::UnPackTo(QuantizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset QuantizeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const QuantizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateQuantizeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateQuantizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const QuantizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const QuantizeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateQuantizeOptions( + _fbb); +} + +inline MatrixSetDiagOptionsT *MatrixSetDiagOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new MatrixSetDiagOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void MatrixSetDiagOptions::UnPackTo(MatrixSetDiagOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset MatrixSetDiagOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MatrixSetDiagOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMatrixSetDiagOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMatrixSetDiagOptions(flatbuffers::FlatBufferBuilder &_fbb, const MatrixSetDiagOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MatrixSetDiagOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateMatrixSetDiagOptions( + _fbb); +} + +inline IfOptionsT *IfOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new IfOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void IfOptions::UnPackTo(IfOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = then_subgraph_index(); _o->then_subgraph_index = _e; } + { auto _e = else_subgraph_index(); _o->else_subgraph_index = _e; } +} + +inline flatbuffers::Offset IfOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const IfOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateIfOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateIfOptions(flatbuffers::FlatBufferBuilder &_fbb, const IfOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const IfOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _then_subgraph_index = _o->then_subgraph_index; + auto _else_subgraph_index = _o->else_subgraph_index; + return tflite::CreateIfOptions( + _fbb, + _then_subgraph_index, + _else_subgraph_index); +} + +inline CallOnceOptionsT *CallOnceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CallOnceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void CallOnceOptions::UnPackTo(CallOnceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = init_subgraph_index(); _o->init_subgraph_index = _e; } +} + +inline flatbuffers::Offset CallOnceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const CallOnceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateCallOnceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateCallOnceOptions(flatbuffers::FlatBufferBuilder &_fbb, const CallOnceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const CallOnceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _init_subgraph_index = _o->init_subgraph_index; + return tflite::CreateCallOnceOptions( + _fbb, + _init_subgraph_index); +} + +inline WhileOptionsT *WhileOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new WhileOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void WhileOptions::UnPackTo(WhileOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = cond_subgraph_index(); _o->cond_subgraph_index = _e; } + { auto _e = body_subgraph_index(); _o->body_subgraph_index = _e; } +} + +inline flatbuffers::Offset WhileOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const WhileOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateWhileOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateWhileOptions(flatbuffers::FlatBufferBuilder &_fbb, const WhileOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const WhileOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _cond_subgraph_index = _o->cond_subgraph_index; + auto _body_subgraph_index = _o->body_subgraph_index; + return tflite::CreateWhileOptions( + _fbb, + _cond_subgraph_index, + _body_subgraph_index); +} + +inline NonMaxSuppressionV4OptionsT *NonMaxSuppressionV4Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new NonMaxSuppressionV4OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void NonMaxSuppressionV4Options::UnPackTo(NonMaxSuppressionV4OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset NonMaxSuppressionV4Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV4OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateNonMaxSuppressionV4Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateNonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV4OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const NonMaxSuppressionV4OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateNonMaxSuppressionV4Options( + _fbb); +} + +inline NonMaxSuppressionV5OptionsT *NonMaxSuppressionV5Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new NonMaxSuppressionV5OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void NonMaxSuppressionV5Options::UnPackTo(NonMaxSuppressionV5OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset NonMaxSuppressionV5Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV5OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateNonMaxSuppressionV5Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateNonMaxSuppressionV5Options(flatbuffers::FlatBufferBuilder &_fbb, const NonMaxSuppressionV5OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const NonMaxSuppressionV5OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateNonMaxSuppressionV5Options( + _fbb); +} + +inline ScatterNdOptionsT *ScatterNdOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ScatterNdOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ScatterNdOptions::UnPackTo(ScatterNdOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ScatterNdOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ScatterNdOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateScatterNdOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateScatterNdOptions(flatbuffers::FlatBufferBuilder &_fbb, const ScatterNdOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ScatterNdOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateScatterNdOptions( + _fbb); +} + +inline SelectV2OptionsT *SelectV2Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SelectV2OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SelectV2Options::UnPackTo(SelectV2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SelectV2Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SelectV2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSelectV2Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSelectV2Options(flatbuffers::FlatBufferBuilder &_fbb, const SelectV2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SelectV2OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSelectV2Options( + _fbb); +} + +inline DensifyOptionsT *DensifyOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DensifyOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DensifyOptions::UnPackTo(DensifyOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset DensifyOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DensifyOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDensifyOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDensifyOptions(flatbuffers::FlatBufferBuilder &_fbb, const DensifyOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DensifyOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateDensifyOptions( + _fbb); +} + +inline SegmentSumOptionsT *SegmentSumOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SegmentSumOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SegmentSumOptions::UnPackTo(SegmentSumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SegmentSumOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SegmentSumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSegmentSumOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb, const SegmentSumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SegmentSumOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSegmentSumOptions( + _fbb); +} + +inline BatchMatMulOptionsT *BatchMatMulOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BatchMatMulOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void BatchMatMulOptions::UnPackTo(BatchMatMulOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = adj_x(); _o->adj_x = _e; } + { auto _e = adj_y(); _o->adj_y = _e; } + { auto _e = asymmetric_quantize_inputs(); _o->asymmetric_quantize_inputs = _e; } +} + +inline flatbuffers::Offset BatchMatMulOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BatchMatMulOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBatchMatMulOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBatchMatMulOptions(flatbuffers::FlatBufferBuilder &_fbb, const BatchMatMulOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BatchMatMulOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _adj_x = _o->adj_x; + auto _adj_y = _o->adj_y; + auto _asymmetric_quantize_inputs = _o->asymmetric_quantize_inputs; + return tflite::CreateBatchMatMulOptions( + _fbb, + _adj_x, + _adj_y, + _asymmetric_quantize_inputs); +} + +inline CumsumOptionsT *CumsumOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new CumsumOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void CumsumOptions::UnPackTo(CumsumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = exclusive(); _o->exclusive = _e; } + { auto _e = reverse(); _o->reverse = _e; } +} + +inline flatbuffers::Offset CumsumOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const CumsumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateCumsumOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateCumsumOptions(flatbuffers::FlatBufferBuilder &_fbb, const CumsumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const CumsumOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _exclusive = _o->exclusive; + auto _reverse = _o->reverse; + return tflite::CreateCumsumOptions( + _fbb, + _exclusive, + _reverse); +} + +inline BroadcastToOptionsT *BroadcastToOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BroadcastToOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void BroadcastToOptions::UnPackTo(BroadcastToOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset BroadcastToOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BroadcastToOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBroadcastToOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBroadcastToOptions(flatbuffers::FlatBufferBuilder &_fbb, const BroadcastToOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BroadcastToOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateBroadcastToOptions( + _fbb); +} + +inline Rfft2dOptionsT *Rfft2dOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new Rfft2dOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Rfft2dOptions::UnPackTo(Rfft2dOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset Rfft2dOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Rfft2dOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateRfft2dOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateRfft2dOptions(flatbuffers::FlatBufferBuilder &_fbb, const Rfft2dOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const Rfft2dOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateRfft2dOptions( + _fbb); +} + +inline HashtableOptionsT *HashtableOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new HashtableOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void HashtableOptions::UnPackTo(HashtableOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = table_id(); _o->table_id = _e; } + { auto _e = key_dtype(); _o->key_dtype = _e; } + { auto _e = value_dtype(); _o->value_dtype = _e; } +} + +inline flatbuffers::Offset HashtableOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateHashtableOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateHashtableOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const HashtableOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _table_id = _o->table_id; + auto _key_dtype = _o->key_dtype; + auto _value_dtype = _o->value_dtype; + return tflite::CreateHashtableOptions( + _fbb, + _table_id, + _key_dtype, + _value_dtype); +} + +inline HashtableFindOptionsT *HashtableFindOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new HashtableFindOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void HashtableFindOptions::UnPackTo(HashtableFindOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset HashtableFindOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableFindOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateHashtableFindOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateHashtableFindOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableFindOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const HashtableFindOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateHashtableFindOptions( + _fbb); +} + +inline HashtableImportOptionsT *HashtableImportOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new HashtableImportOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void HashtableImportOptions::UnPackTo(HashtableImportOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset HashtableImportOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableImportOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateHashtableImportOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateHashtableImportOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableImportOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const HashtableImportOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateHashtableImportOptions( + _fbb); +} + +inline HashtableSizeOptionsT *HashtableSizeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new HashtableSizeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void HashtableSizeOptions::UnPackTo(HashtableSizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset HashtableSizeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const HashtableSizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateHashtableSizeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateHashtableSizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const HashtableSizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const HashtableSizeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateHashtableSizeOptions( + _fbb); +} + +inline VarHandleOptionsT *VarHandleOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new VarHandleOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void VarHandleOptions::UnPackTo(VarHandleOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = container(); if (_e) _o->container = _e->str(); } + { auto _e = shared_name(); if (_e) _o->shared_name = _e->str(); } +} + +inline flatbuffers::Offset VarHandleOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const VarHandleOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateVarHandleOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateVarHandleOptions(flatbuffers::FlatBufferBuilder &_fbb, const VarHandleOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const VarHandleOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _container = _o->container.empty() ? 0 : _fbb.CreateString(_o->container); + auto _shared_name = _o->shared_name.empty() ? 0 : _fbb.CreateString(_o->shared_name); + return tflite::CreateVarHandleOptions( + _fbb, + _container, + _shared_name); +} + +inline ReadVariableOptionsT *ReadVariableOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ReadVariableOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ReadVariableOptions::UnPackTo(ReadVariableOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ReadVariableOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReadVariableOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateReadVariableOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateReadVariableOptions(flatbuffers::FlatBufferBuilder &_fbb, const ReadVariableOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ReadVariableOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateReadVariableOptions( + _fbb); +} + +inline AssignVariableOptionsT *AssignVariableOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new AssignVariableOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void AssignVariableOptions::UnPackTo(AssignVariableOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset AssignVariableOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AssignVariableOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateAssignVariableOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateAssignVariableOptions(flatbuffers::FlatBufferBuilder &_fbb, const AssignVariableOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AssignVariableOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateAssignVariableOptions( + _fbb); +} + +inline RandomOptionsT *RandomOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new RandomOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void RandomOptions::UnPackTo(RandomOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = seed(); _o->seed = _e; } + { auto _e = seed2(); _o->seed2 = _e; } +} + +inline flatbuffers::Offset RandomOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const RandomOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateRandomOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateRandomOptions(flatbuffers::FlatBufferBuilder &_fbb, const RandomOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const RandomOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _seed = _o->seed; + auto _seed2 = _o->seed2; + return tflite::CreateRandomOptions( + _fbb, + _seed, + _seed2); +} + +inline BucketizeOptionsT *BucketizeOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BucketizeOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void BucketizeOptions::UnPackTo(BucketizeOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = boundaries(); if (_e) { _o->boundaries.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->boundaries[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset BucketizeOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BucketizeOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBucketizeOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBucketizeOptions(flatbuffers::FlatBufferBuilder &_fbb, const BucketizeOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BucketizeOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _boundaries = _o->boundaries.size() ? _fbb.CreateVector(_o->boundaries) : 0; + return tflite::CreateBucketizeOptions( + _fbb, + _boundaries); +} + +inline GeluOptionsT *GeluOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new GeluOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void GeluOptions::UnPackTo(GeluOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = approximate(); _o->approximate = _e; } +} + +inline flatbuffers::Offset GeluOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const GeluOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateGeluOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateGeluOptions(flatbuffers::FlatBufferBuilder &_fbb, const GeluOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const GeluOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _approximate = _o->approximate; + return tflite::CreateGeluOptions( + _fbb, + _approximate); +} + +inline DynamicUpdateSliceOptionsT *DynamicUpdateSliceOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new DynamicUpdateSliceOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void DynamicUpdateSliceOptions::UnPackTo(DynamicUpdateSliceOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset DynamicUpdateSliceOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const DynamicUpdateSliceOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateDynamicUpdateSliceOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateDynamicUpdateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, const DynamicUpdateSliceOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const DynamicUpdateSliceOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateDynamicUpdateSliceOptions( + _fbb); +} + +inline UnsortedSegmentProdOptionsT *UnsortedSegmentProdOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UnsortedSegmentProdOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UnsortedSegmentProdOptions::UnPackTo(UnsortedSegmentProdOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset UnsortedSegmentProdOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentProdOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUnsortedSegmentProdOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUnsortedSegmentProdOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentProdOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UnsortedSegmentProdOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateUnsortedSegmentProdOptions( + _fbb); +} + +inline UnsortedSegmentMaxOptionsT *UnsortedSegmentMaxOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UnsortedSegmentMaxOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UnsortedSegmentMaxOptions::UnPackTo(UnsortedSegmentMaxOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset UnsortedSegmentMaxOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMaxOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUnsortedSegmentMaxOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUnsortedSegmentMaxOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMaxOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UnsortedSegmentMaxOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateUnsortedSegmentMaxOptions( + _fbb); +} + +inline UnsortedSegmentSumOptionsT *UnsortedSegmentSumOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UnsortedSegmentSumOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UnsortedSegmentSumOptions::UnPackTo(UnsortedSegmentSumOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset UnsortedSegmentSumOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentSumOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUnsortedSegmentSumOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUnsortedSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentSumOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UnsortedSegmentSumOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateUnsortedSegmentSumOptions( + _fbb); +} + +inline ATan2OptionsT *ATan2Options::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ATan2OptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void ATan2Options::UnPackTo(ATan2OptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset ATan2Options::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ATan2OptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateATan2Options(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateATan2Options(flatbuffers::FlatBufferBuilder &_fbb, const ATan2OptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ATan2OptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateATan2Options( + _fbb); +} + +inline UnsortedSegmentMinOptionsT *UnsortedSegmentMinOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new UnsortedSegmentMinOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void UnsortedSegmentMinOptions::UnPackTo(UnsortedSegmentMinOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset UnsortedSegmentMinOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMinOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateUnsortedSegmentMinOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateUnsortedSegmentMinOptions(flatbuffers::FlatBufferBuilder &_fbb, const UnsortedSegmentMinOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const UnsortedSegmentMinOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateUnsortedSegmentMinOptions( + _fbb); +} + +inline SignOptionsT *SignOptions::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SignOptionsT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SignOptions::UnPackTo(SignOptionsT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; +} + +inline flatbuffers::Offset SignOptions::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SignOptionsT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSignOptions(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSignOptions(flatbuffers::FlatBufferBuilder &_fbb, const SignOptionsT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SignOptionsT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + return tflite::CreateSignOptions( + _fbb); +} + +inline OperatorCodeT *OperatorCode::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new OperatorCodeT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void OperatorCode::UnPackTo(OperatorCodeT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = deprecated_builtin_code(); _o->deprecated_builtin_code = _e; } + { auto _e = custom_code(); if (_e) _o->custom_code = _e->str(); } + { auto _e = version(); _o->version = _e; } + { auto _e = builtin_code(); _o->builtin_code = _e; } +} + +inline flatbuffers::Offset OperatorCode::Pack(flatbuffers::FlatBufferBuilder &_fbb, const OperatorCodeT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateOperatorCode(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateOperatorCode(flatbuffers::FlatBufferBuilder &_fbb, const OperatorCodeT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const OperatorCodeT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _deprecated_builtin_code = _o->deprecated_builtin_code; + auto _custom_code = _o->custom_code.empty() ? 0 : _fbb.CreateString(_o->custom_code); + auto _version = _o->version; + auto _builtin_code = _o->builtin_code; + return tflite::CreateOperatorCode( + _fbb, + _deprecated_builtin_code, + _custom_code, + _version, + _builtin_code); +} + +inline OperatorT *Operator::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new OperatorT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Operator::UnPackTo(OperatorT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = opcode_index(); _o->opcode_index = _e; } + { auto _e = inputs(); if (_e) { _o->inputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inputs[_i] = _e->Get(_i); } } } + { auto _e = outputs(); if (_e) { _o->outputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->outputs[_i] = _e->Get(_i); } } } + { auto _e = builtin_options_type(); _o->builtin_options.type = _e; } + { auto _e = builtin_options(); if (_e) _o->builtin_options.value = tflite::BuiltinOptionsUnion::UnPack(_e, builtin_options_type(), _resolver); } + { auto _e = custom_options(); if (_e) { _o->custom_options.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->custom_options.begin()); } } + { auto _e = custom_options_format(); _o->custom_options_format = _e; } + { auto _e = mutating_variable_inputs(); if (_e) { _o->mutating_variable_inputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->mutating_variable_inputs[_i] = _e->Get(_i) != 0; } } } + { auto _e = intermediates(); if (_e) { _o->intermediates.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->intermediates[_i] = _e->Get(_i); } } } +} + +inline flatbuffers::Offset Operator::Pack(flatbuffers::FlatBufferBuilder &_fbb, const OperatorT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateOperator(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateOperator(flatbuffers::FlatBufferBuilder &_fbb, const OperatorT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const OperatorT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _opcode_index = _o->opcode_index; + auto _inputs = _o->inputs.size() ? _fbb.CreateVector(_o->inputs) : 0; + auto _outputs = _o->outputs.size() ? _fbb.CreateVector(_o->outputs) : 0; + auto _builtin_options_type = _o->builtin_options.type; + auto _builtin_options = _o->builtin_options.Pack(_fbb); + auto _custom_options = _o->custom_options.size() ? _fbb.CreateVector(_o->custom_options) : 0; + auto _custom_options_format = _o->custom_options_format; + auto _mutating_variable_inputs = _o->mutating_variable_inputs.size() ? _fbb.CreateVector(_o->mutating_variable_inputs) : 0; + auto _intermediates = _o->intermediates.size() ? _fbb.CreateVector(_o->intermediates) : 0; + return tflite::CreateOperator( + _fbb, + _opcode_index, + _inputs, + _outputs, + _builtin_options_type, + _builtin_options, + _custom_options, + _custom_options_format, + _mutating_variable_inputs, + _intermediates); +} + +inline SubGraphT::SubGraphT(const SubGraphT &o) + : inputs(o.inputs), + outputs(o.outputs), + name(o.name) { + tensors.reserve(o.tensors.size()); + for (const auto &tensors_ : o.tensors) { tensors.emplace_back((tensors_) ? new tflite::TensorT(*tensors_) : nullptr); } + operators.reserve(o.operators.size()); + for (const auto &operators_ : o.operators) { operators.emplace_back((operators_) ? new tflite::OperatorT(*operators_) : nullptr); } +} + +inline SubGraphT &SubGraphT::operator=(SubGraphT o) FLATBUFFERS_NOEXCEPT { + std::swap(tensors, o.tensors); + std::swap(inputs, o.inputs); + std::swap(outputs, o.outputs); + std::swap(operators, o.operators); + std::swap(name, o.name); + return *this; +} + +inline SubGraphT *SubGraph::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SubGraphT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SubGraph::UnPackTo(SubGraphT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = tensors(); if (_e) { _o->tensors.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->tensors[_i]) { _e->Get(_i)->UnPackTo(_o->tensors[_i].get(), _resolver); } else { _o->tensors[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = inputs(); if (_e) { _o->inputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inputs[_i] = _e->Get(_i); } } } + { auto _e = outputs(); if (_e) { _o->outputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->outputs[_i] = _e->Get(_i); } } } + { auto _e = operators(); if (_e) { _o->operators.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->operators[_i]) { _e->Get(_i)->UnPackTo(_o->operators[_i].get(), _resolver); } else { _o->operators[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = name(); if (_e) _o->name = _e->str(); } +} + +inline flatbuffers::Offset SubGraph::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SubGraphT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSubGraph(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSubGraph(flatbuffers::FlatBufferBuilder &_fbb, const SubGraphT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SubGraphT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _tensors = _o->tensors.size() ? _fbb.CreateVector> (_o->tensors.size(), [](size_t i, _VectorArgs *__va) { return CreateTensor(*__va->__fbb, __va->__o->tensors[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _inputs = _o->inputs.size() ? _fbb.CreateVector(_o->inputs) : 0; + auto _outputs = _o->outputs.size() ? _fbb.CreateVector(_o->outputs) : 0; + auto _operators = _o->operators.size() ? _fbb.CreateVector> (_o->operators.size(), [](size_t i, _VectorArgs *__va) { return CreateOperator(*__va->__fbb, __va->__o->operators[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + return tflite::CreateSubGraph( + _fbb, + _tensors, + _inputs, + _outputs, + _operators, + _name); +} + +inline BufferT *Buffer::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new BufferT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Buffer::UnPackTo(BufferT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = data(); if (_e) { _o->data.resize(_e->size()); std::copy(_e->begin(), _e->end(), _o->data.begin()); } } +} + +inline flatbuffers::Offset Buffer::Pack(flatbuffers::FlatBufferBuilder &_fbb, const BufferT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateBuffer(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateBuffer(flatbuffers::FlatBufferBuilder &_fbb, const BufferT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const BufferT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + _fbb.ForceVectorAlignment(_o->data.size(), sizeof(uint8_t), 16); + auto _data = _o->data.size() ? _fbb.CreateVector(_o->data) : 0; + return tflite::CreateBuffer( + _fbb, + _data); +} + +inline MetadataT *Metadata::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new MetadataT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Metadata::UnPackTo(MetadataT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = name(); if (_e) _o->name = _e->str(); } + { auto _e = buffer(); _o->buffer = _e; } +} + +inline flatbuffers::Offset Metadata::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateMetadata(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb, const MetadataT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MetadataT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + auto _buffer = _o->buffer; + return tflite::CreateMetadata( + _fbb, + _name, + _buffer); +} + +inline TensorMapT *TensorMap::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new TensorMapT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void TensorMap::UnPackTo(TensorMapT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = name(); if (_e) _o->name = _e->str(); } + { auto _e = tensor_index(); _o->tensor_index = _e; } +} + +inline flatbuffers::Offset TensorMap::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TensorMapT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateTensorMap(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateTensorMap(flatbuffers::FlatBufferBuilder &_fbb, const TensorMapT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TensorMapT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name); + auto _tensor_index = _o->tensor_index; + return tflite::CreateTensorMap( + _fbb, + _name, + _tensor_index); +} + +inline SignatureDefT::SignatureDefT(const SignatureDefT &o) + : signature_key(o.signature_key), + subgraph_index(o.subgraph_index) { + inputs.reserve(o.inputs.size()); + for (const auto &inputs_ : o.inputs) { inputs.emplace_back((inputs_) ? new tflite::TensorMapT(*inputs_) : nullptr); } + outputs.reserve(o.outputs.size()); + for (const auto &outputs_ : o.outputs) { outputs.emplace_back((outputs_) ? new tflite::TensorMapT(*outputs_) : nullptr); } +} + +inline SignatureDefT &SignatureDefT::operator=(SignatureDefT o) FLATBUFFERS_NOEXCEPT { + std::swap(inputs, o.inputs); + std::swap(outputs, o.outputs); + std::swap(signature_key, o.signature_key); + std::swap(subgraph_index, o.subgraph_index); + return *this; +} + +inline SignatureDefT *SignatureDef::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new SignatureDefT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void SignatureDef::UnPackTo(SignatureDefT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = inputs(); if (_e) { _o->inputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->inputs[_i]) { _e->Get(_i)->UnPackTo(_o->inputs[_i].get(), _resolver); } else { _o->inputs[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = outputs(); if (_e) { _o->outputs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->outputs[_i]) { _e->Get(_i)->UnPackTo(_o->outputs[_i].get(), _resolver); } else { _o->outputs[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = signature_key(); if (_e) _o->signature_key = _e->str(); } + { auto _e = subgraph_index(); _o->subgraph_index = _e; } +} + +inline flatbuffers::Offset SignatureDef::Pack(flatbuffers::FlatBufferBuilder &_fbb, const SignatureDefT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateSignatureDef(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateSignatureDef(flatbuffers::FlatBufferBuilder &_fbb, const SignatureDefT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const SignatureDefT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _inputs = _o->inputs.size() ? _fbb.CreateVector> (_o->inputs.size(), [](size_t i, _VectorArgs *__va) { return CreateTensorMap(*__va->__fbb, __va->__o->inputs[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _outputs = _o->outputs.size() ? _fbb.CreateVector> (_o->outputs.size(), [](size_t i, _VectorArgs *__va) { return CreateTensorMap(*__va->__fbb, __va->__o->outputs[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _signature_key = _o->signature_key.empty() ? 0 : _fbb.CreateString(_o->signature_key); + auto _subgraph_index = _o->subgraph_index; + return tflite::CreateSignatureDef( + _fbb, + _inputs, + _outputs, + _signature_key, + _subgraph_index); +} + +inline ModelT::ModelT(const ModelT &o) + : version(o.version), + description(o.description), + metadata_buffer(o.metadata_buffer) { + operator_codes.reserve(o.operator_codes.size()); + for (const auto &operator_codes_ : o.operator_codes) { operator_codes.emplace_back((operator_codes_) ? new tflite::OperatorCodeT(*operator_codes_) : nullptr); } + subgraphs.reserve(o.subgraphs.size()); + for (const auto &subgraphs_ : o.subgraphs) { subgraphs.emplace_back((subgraphs_) ? new tflite::SubGraphT(*subgraphs_) : nullptr); } + buffers.reserve(o.buffers.size()); + for (const auto &buffers_ : o.buffers) { buffers.emplace_back((buffers_) ? new tflite::BufferT(*buffers_) : nullptr); } + metadata.reserve(o.metadata.size()); + for (const auto &metadata_ : o.metadata) { metadata.emplace_back((metadata_) ? new tflite::MetadataT(*metadata_) : nullptr); } + signature_defs.reserve(o.signature_defs.size()); + for (const auto &signature_defs_ : o.signature_defs) { signature_defs.emplace_back((signature_defs_) ? new tflite::SignatureDefT(*signature_defs_) : nullptr); } +} + +inline ModelT &ModelT::operator=(ModelT o) FLATBUFFERS_NOEXCEPT { + std::swap(version, o.version); + std::swap(operator_codes, o.operator_codes); + std::swap(subgraphs, o.subgraphs); + std::swap(description, o.description); + std::swap(buffers, o.buffers); + std::swap(metadata_buffer, o.metadata_buffer); + std::swap(metadata, o.metadata); + std::swap(signature_defs, o.signature_defs); + return *this; +} + +inline ModelT *Model::UnPack(const flatbuffers::resolver_function_t *_resolver) const { + auto _o = std::unique_ptr(new ModelT()); + UnPackTo(_o.get(), _resolver); + return _o.release(); +} + +inline void Model::UnPackTo(ModelT *_o, const flatbuffers::resolver_function_t *_resolver) const { + (void)_o; + (void)_resolver; + { auto _e = version(); _o->version = _e; } + { auto _e = operator_codes(); if (_e) { _o->operator_codes.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->operator_codes[_i]) { _e->Get(_i)->UnPackTo(_o->operator_codes[_i].get(), _resolver); } else { _o->operator_codes[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = subgraphs(); if (_e) { _o->subgraphs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->subgraphs[_i]) { _e->Get(_i)->UnPackTo(_o->subgraphs[_i].get(), _resolver); } else { _o->subgraphs[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = description(); if (_e) _o->description = _e->str(); } + { auto _e = buffers(); if (_e) { _o->buffers.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->buffers[_i]) { _e->Get(_i)->UnPackTo(_o->buffers[_i].get(), _resolver); } else { _o->buffers[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = metadata_buffer(); if (_e) { _o->metadata_buffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->metadata_buffer[_i] = _e->Get(_i); } } } + { auto _e = metadata(); if (_e) { _o->metadata.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->metadata[_i]) { _e->Get(_i)->UnPackTo(_o->metadata[_i].get(), _resolver); } else { _o->metadata[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } + { auto _e = signature_defs(); if (_e) { _o->signature_defs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { if(_o->signature_defs[_i]) { _e->Get(_i)->UnPackTo(_o->signature_defs[_i].get(), _resolver); } else { _o->signature_defs[_i] = std::unique_ptr(_e->Get(_i)->UnPack(_resolver)); }; } } } +} + +inline flatbuffers::Offset Model::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ModelT* _o, const flatbuffers::rehasher_function_t *_rehasher) { + return CreateModel(_fbb, _o, _rehasher); +} + +inline flatbuffers::Offset CreateModel(flatbuffers::FlatBufferBuilder &_fbb, const ModelT *_o, const flatbuffers::rehasher_function_t *_rehasher) { + (void)_rehasher; + (void)_o; + struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ModelT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va; + auto _version = _o->version; + auto _operator_codes = _o->operator_codes.size() ? _fbb.CreateVector> (_o->operator_codes.size(), [](size_t i, _VectorArgs *__va) { return CreateOperatorCode(*__va->__fbb, __va->__o->operator_codes[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _subgraphs = _o->subgraphs.size() ? _fbb.CreateVector> (_o->subgraphs.size(), [](size_t i, _VectorArgs *__va) { return CreateSubGraph(*__va->__fbb, __va->__o->subgraphs[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _description = _o->description.empty() ? 0 : _fbb.CreateString(_o->description); + auto _buffers = _o->buffers.size() ? _fbb.CreateVector> (_o->buffers.size(), [](size_t i, _VectorArgs *__va) { return CreateBuffer(*__va->__fbb, __va->__o->buffers[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _metadata_buffer = _o->metadata_buffer.size() ? _fbb.CreateVector(_o->metadata_buffer) : 0; + auto _metadata = _o->metadata.size() ? _fbb.CreateVector> (_o->metadata.size(), [](size_t i, _VectorArgs *__va) { return CreateMetadata(*__va->__fbb, __va->__o->metadata[i].get(), __va->__rehasher); }, &_va ) : 0; + auto _signature_defs = _o->signature_defs.size() ? _fbb.CreateVector> (_o->signature_defs.size(), [](size_t i, _VectorArgs *__va) { return CreateSignatureDef(*__va->__fbb, __va->__o->signature_defs[i].get(), __va->__rehasher); }, &_va ) : 0; + return tflite::CreateModel( + _fbb, + _version, + _operator_codes, + _subgraphs, + _description, + _buffers, + _metadata_buffer, + _metadata, + _signature_defs); +} + +inline bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj, QuantizationDetails type) { + switch (type) { + case QuantizationDetails_NONE: { + return true; + } + case QuantizationDetails_CustomQuantization: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: return true; + } +} + +inline bool VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types) { + if (!values || !types) return !values && !types; + if (values->size() != types->size()) return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyQuantizationDetails( + verifier, values->Get(i), types->GetEnum(i))) { + return false; + } + } + return true; +} + +inline void *QuantizationDetailsUnion::UnPack(const void *obj, QuantizationDetails type, const flatbuffers::resolver_function_t *resolver) { + (void)resolver; + switch (type) { + case QuantizationDetails_CustomQuantization: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + default: return nullptr; + } +} + +inline flatbuffers::Offset QuantizationDetailsUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { + (void)_rehasher; + switch (type) { + case QuantizationDetails_CustomQuantization: { + auto ptr = reinterpret_cast(value); + return CreateCustomQuantization(_fbb, ptr, _rehasher).Union(); + } + default: return 0; + } +} + +inline QuantizationDetailsUnion::QuantizationDetailsUnion(const QuantizationDetailsUnion &u) : type(u.type), value(nullptr) { + switch (type) { + case QuantizationDetails_CustomQuantization: { + value = new tflite::CustomQuantizationT(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + +inline void QuantizationDetailsUnion::Reset() { + switch (type) { + case QuantizationDetails_CustomQuantization: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + default: break; + } + value = nullptr; + type = QuantizationDetails_NONE; +} + +inline bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj, SparseIndexVector type) { + switch (type) { + case SparseIndexVector_NONE: { + return true; + } + case SparseIndexVector_Int32Vector: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case SparseIndexVector_Uint16Vector: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case SparseIndexVector_Uint8Vector: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: return true; + } +} + +inline bool VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types) { + if (!values || !types) return !values && !types; + if (values->size() != types->size()) return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifySparseIndexVector( + verifier, values->Get(i), types->GetEnum(i))) { + return false; + } + } + return true; +} + +inline void *SparseIndexVectorUnion::UnPack(const void *obj, SparseIndexVector type, const flatbuffers::resolver_function_t *resolver) { + (void)resolver; + switch (type) { + case SparseIndexVector_Int32Vector: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case SparseIndexVector_Uint16Vector: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case SparseIndexVector_Uint8Vector: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + default: return nullptr; + } +} + +inline flatbuffers::Offset SparseIndexVectorUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { + (void)_rehasher; + switch (type) { + case SparseIndexVector_Int32Vector: { + auto ptr = reinterpret_cast(value); + return CreateInt32Vector(_fbb, ptr, _rehasher).Union(); + } + case SparseIndexVector_Uint16Vector: { + auto ptr = reinterpret_cast(value); + return CreateUint16Vector(_fbb, ptr, _rehasher).Union(); + } + case SparseIndexVector_Uint8Vector: { + auto ptr = reinterpret_cast(value); + return CreateUint8Vector(_fbb, ptr, _rehasher).Union(); + } + default: return 0; + } +} + +inline SparseIndexVectorUnion::SparseIndexVectorUnion(const SparseIndexVectorUnion &u) : type(u.type), value(nullptr) { + switch (type) { + case SparseIndexVector_Int32Vector: { + value = new tflite::Int32VectorT(*reinterpret_cast(u.value)); + break; + } + case SparseIndexVector_Uint16Vector: { + value = new tflite::Uint16VectorT(*reinterpret_cast(u.value)); + break; + } + case SparseIndexVector_Uint8Vector: { + value = new tflite::Uint8VectorT(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + +inline void SparseIndexVectorUnion::Reset() { + switch (type) { + case SparseIndexVector_Int32Vector: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case SparseIndexVector_Uint16Vector: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case SparseIndexVector_Uint8Vector: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + default: break; + } + value = nullptr; + type = SparseIndexVector_NONE; +} + +inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type) { + switch (type) { + case BuiltinOptions_NONE: { + return true; + } + case BuiltinOptions_Conv2DOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DepthwiseConv2DOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ConcatEmbeddingsOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LSHProjectionOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_Pool2DOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SVDFOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RNNOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FullyConnectedOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SoftmaxOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ConcatenationOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AddOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_L2NormOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LocalResponseNormalizationOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LSTMOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ResizeBilinearOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CallOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReshapeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SkipGramOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SpaceToDepthOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_EmbeddingLookupSparseOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MulOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PadOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GatherOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BatchToSpaceNDOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SpaceToBatchNDOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TransposeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReducerOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SubOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DivOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SqueezeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SequenceRNNOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ExpOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TopKV2Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SplitOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogSoftmaxOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CastOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DequantizeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MaximumMinimumOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ArgMaxOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LessOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NegOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PadV2Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GreaterOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GreaterEqualOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LessEqualOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SelectOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SliceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TransposeConvOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SparseToDenseOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TileOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ExpandDimsOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_EqualOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NotEqualOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ShapeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PowOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ArgMinOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FakeQuantOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PackOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalOrOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_OneHotOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalAndOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalNotOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnpackOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FloorDivOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SquareOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ZerosLikeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FillOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FloorModOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RangeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ResizeNearestNeighborOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LeakyReluOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SquaredDifferenceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UniqueOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReverseV2Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AddNOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GatherNdOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CosOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_WhereOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RankOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReverseSequenceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MatrixDiagOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_QuantizeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MatrixSetDiagOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HardSwishOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_IfOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_WhileOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DepthToSpaceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NonMaxSuppressionV4Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NonMaxSuppressionV5Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ScatterNdOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SelectV2Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DensifyOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SegmentSumOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BatchMatMulOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CumsumOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CallOnceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BroadcastToOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_Rfft2dOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_Conv3DOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HashtableOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HashtableFindOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HashtableImportOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HashtableSizeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_VarHandleOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReadVariableOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AssignVariableOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RandomOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BucketizeOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GeluOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DynamicUpdateSliceOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnsortedSegmentProdOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnsortedSegmentMaxOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnsortedSegmentMinOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnsortedSegmentSumOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ATan2Options: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SignOptions: { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: return true; + } +} + +inline bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector> *values, const flatbuffers::Vector *types) { + if (!values || !types) return !values && !types; + if (values->size() != types->size()) return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { + if (!VerifyBuiltinOptions( + verifier, values->Get(i), types->GetEnum(i))) { + return false; + } + } + return true; +} + +inline void *BuiltinOptionsUnion::UnPack(const void *obj, BuiltinOptions type, const flatbuffers::resolver_function_t *resolver) { + (void)resolver; + switch (type) { + case BuiltinOptions_Conv2DOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_DepthwiseConv2DOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ConcatEmbeddingsOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LSHProjectionOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_Pool2DOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SVDFOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_RNNOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_FullyConnectedOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SoftmaxOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ConcatenationOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_AddOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_L2NormOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LocalResponseNormalizationOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LSTMOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ResizeBilinearOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_CallOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ReshapeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SkipGramOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SpaceToDepthOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_EmbeddingLookupSparseOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_MulOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_PadOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_GatherOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_BatchToSpaceNDOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SpaceToBatchNDOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_TransposeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ReducerOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SubOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_DivOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SqueezeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SequenceRNNOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ExpOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_TopKV2Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SplitOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LogSoftmaxOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_CastOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_DequantizeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_MaximumMinimumOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ArgMaxOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LessOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_NegOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_PadV2Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_GreaterOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_GreaterEqualOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LessEqualOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SelectOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SliceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_TransposeConvOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SparseToDenseOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_TileOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ExpandDimsOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_EqualOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_NotEqualOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ShapeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_PowOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ArgMinOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_FakeQuantOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_PackOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LogicalOrOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_OneHotOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LogicalAndOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LogicalNotOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UnpackOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_FloorDivOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SquareOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ZerosLikeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_FillOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_FloorModOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_RangeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ResizeNearestNeighborOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_LeakyReluOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SquaredDifferenceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UniqueOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ReverseV2Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_AddNOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_GatherNdOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_CosOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_WhereOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_RankOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ReverseSequenceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_MatrixDiagOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_QuantizeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_MatrixSetDiagOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_HardSwishOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_IfOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_WhileOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_DepthToSpaceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_NonMaxSuppressionV4Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_NonMaxSuppressionV5Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ScatterNdOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SelectV2Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_DensifyOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SegmentSumOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_BatchMatMulOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_CumsumOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_CallOnceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_BroadcastToOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_Rfft2dOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_Conv3DOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_HashtableOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_HashtableFindOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_HashtableImportOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_HashtableSizeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_VarHandleOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ReadVariableOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_AssignVariableOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_RandomOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_BucketizeOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_GeluOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_DynamicUpdateSliceOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UnsortedSegmentProdOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UnsortedSegmentMaxOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UnsortedSegmentMinOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_UnsortedSegmentSumOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_ATan2Options: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + case BuiltinOptions_SignOptions: { + auto ptr = reinterpret_cast(obj); + return ptr->UnPack(resolver); + } + default: return nullptr; + } +} + +inline flatbuffers::Offset BuiltinOptionsUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const { + (void)_rehasher; + switch (type) { + case BuiltinOptions_Conv2DOptions: { + auto ptr = reinterpret_cast(value); + return CreateConv2DOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_DepthwiseConv2DOptions: { + auto ptr = reinterpret_cast(value); + return CreateDepthwiseConv2DOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ConcatEmbeddingsOptions: { + auto ptr = reinterpret_cast(value); + return CreateConcatEmbeddingsOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LSHProjectionOptions: { + auto ptr = reinterpret_cast(value); + return CreateLSHProjectionOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_Pool2DOptions: { + auto ptr = reinterpret_cast(value); + return CreatePool2DOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SVDFOptions: { + auto ptr = reinterpret_cast(value); + return CreateSVDFOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_RNNOptions: { + auto ptr = reinterpret_cast(value); + return CreateRNNOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_FullyConnectedOptions: { + auto ptr = reinterpret_cast(value); + return CreateFullyConnectedOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SoftmaxOptions: { + auto ptr = reinterpret_cast(value); + return CreateSoftmaxOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ConcatenationOptions: { + auto ptr = reinterpret_cast(value); + return CreateConcatenationOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_AddOptions: { + auto ptr = reinterpret_cast(value); + return CreateAddOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_L2NormOptions: { + auto ptr = reinterpret_cast(value); + return CreateL2NormOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LocalResponseNormalizationOptions: { + auto ptr = reinterpret_cast(value); + return CreateLocalResponseNormalizationOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LSTMOptions: { + auto ptr = reinterpret_cast(value); + return CreateLSTMOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ResizeBilinearOptions: { + auto ptr = reinterpret_cast(value); + return CreateResizeBilinearOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_CallOptions: { + auto ptr = reinterpret_cast(value); + return CreateCallOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ReshapeOptions: { + auto ptr = reinterpret_cast(value); + return CreateReshapeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SkipGramOptions: { + auto ptr = reinterpret_cast(value); + return CreateSkipGramOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SpaceToDepthOptions: { + auto ptr = reinterpret_cast(value); + return CreateSpaceToDepthOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_EmbeddingLookupSparseOptions: { + auto ptr = reinterpret_cast(value); + return CreateEmbeddingLookupSparseOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_MulOptions: { + auto ptr = reinterpret_cast(value); + return CreateMulOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_PadOptions: { + auto ptr = reinterpret_cast(value); + return CreatePadOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_GatherOptions: { + auto ptr = reinterpret_cast(value); + return CreateGatherOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_BatchToSpaceNDOptions: { + auto ptr = reinterpret_cast(value); + return CreateBatchToSpaceNDOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SpaceToBatchNDOptions: { + auto ptr = reinterpret_cast(value); + return CreateSpaceToBatchNDOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_TransposeOptions: { + auto ptr = reinterpret_cast(value); + return CreateTransposeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ReducerOptions: { + auto ptr = reinterpret_cast(value); + return CreateReducerOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SubOptions: { + auto ptr = reinterpret_cast(value); + return CreateSubOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_DivOptions: { + auto ptr = reinterpret_cast(value); + return CreateDivOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SqueezeOptions: { + auto ptr = reinterpret_cast(value); + return CreateSqueezeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SequenceRNNOptions: { + auto ptr = reinterpret_cast(value); + return CreateSequenceRNNOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(value); + return CreateStridedSliceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ExpOptions: { + auto ptr = reinterpret_cast(value); + return CreateExpOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_TopKV2Options: { + auto ptr = reinterpret_cast(value); + return CreateTopKV2Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SplitOptions: { + auto ptr = reinterpret_cast(value); + return CreateSplitOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LogSoftmaxOptions: { + auto ptr = reinterpret_cast(value); + return CreateLogSoftmaxOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_CastOptions: { + auto ptr = reinterpret_cast(value); + return CreateCastOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_DequantizeOptions: { + auto ptr = reinterpret_cast(value); + return CreateDequantizeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_MaximumMinimumOptions: { + auto ptr = reinterpret_cast(value); + return CreateMaximumMinimumOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ArgMaxOptions: { + auto ptr = reinterpret_cast(value); + return CreateArgMaxOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LessOptions: { + auto ptr = reinterpret_cast(value); + return CreateLessOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_NegOptions: { + auto ptr = reinterpret_cast(value); + return CreateNegOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_PadV2Options: { + auto ptr = reinterpret_cast(value); + return CreatePadV2Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_GreaterOptions: { + auto ptr = reinterpret_cast(value); + return CreateGreaterOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_GreaterEqualOptions: { + auto ptr = reinterpret_cast(value); + return CreateGreaterEqualOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LessEqualOptions: { + auto ptr = reinterpret_cast(value); + return CreateLessEqualOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SelectOptions: { + auto ptr = reinterpret_cast(value); + return CreateSelectOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SliceOptions: { + auto ptr = reinterpret_cast(value); + return CreateSliceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_TransposeConvOptions: { + auto ptr = reinterpret_cast(value); + return CreateTransposeConvOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SparseToDenseOptions: { + auto ptr = reinterpret_cast(value); + return CreateSparseToDenseOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_TileOptions: { + auto ptr = reinterpret_cast(value); + return CreateTileOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ExpandDimsOptions: { + auto ptr = reinterpret_cast(value); + return CreateExpandDimsOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_EqualOptions: { + auto ptr = reinterpret_cast(value); + return CreateEqualOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_NotEqualOptions: { + auto ptr = reinterpret_cast(value); + return CreateNotEqualOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ShapeOptions: { + auto ptr = reinterpret_cast(value); + return CreateShapeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_PowOptions: { + auto ptr = reinterpret_cast(value); + return CreatePowOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ArgMinOptions: { + auto ptr = reinterpret_cast(value); + return CreateArgMinOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_FakeQuantOptions: { + auto ptr = reinterpret_cast(value); + return CreateFakeQuantOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_PackOptions: { + auto ptr = reinterpret_cast(value); + return CreatePackOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LogicalOrOptions: { + auto ptr = reinterpret_cast(value); + return CreateLogicalOrOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_OneHotOptions: { + auto ptr = reinterpret_cast(value); + return CreateOneHotOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LogicalAndOptions: { + auto ptr = reinterpret_cast(value); + return CreateLogicalAndOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LogicalNotOptions: { + auto ptr = reinterpret_cast(value); + return CreateLogicalNotOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UnpackOptions: { + auto ptr = reinterpret_cast(value); + return CreateUnpackOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_FloorDivOptions: { + auto ptr = reinterpret_cast(value); + return CreateFloorDivOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SquareOptions: { + auto ptr = reinterpret_cast(value); + return CreateSquareOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ZerosLikeOptions: { + auto ptr = reinterpret_cast(value); + return CreateZerosLikeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_FillOptions: { + auto ptr = reinterpret_cast(value); + return CreateFillOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(value); + return CreateBidirectionalSequenceLSTMOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: { + auto ptr = reinterpret_cast(value); + return CreateBidirectionalSequenceRNNOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(value); + return CreateUnidirectionalSequenceLSTMOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_FloorModOptions: { + auto ptr = reinterpret_cast(value); + return CreateFloorModOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_RangeOptions: { + auto ptr = reinterpret_cast(value); + return CreateRangeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ResizeNearestNeighborOptions: { + auto ptr = reinterpret_cast(value); + return CreateResizeNearestNeighborOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_LeakyReluOptions: { + auto ptr = reinterpret_cast(value); + return CreateLeakyReluOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SquaredDifferenceOptions: { + auto ptr = reinterpret_cast(value); + return CreateSquaredDifferenceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(value); + return CreateMirrorPadOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(value); + return CreateAbsOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(value); + return CreateSplitVOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UniqueOptions: { + auto ptr = reinterpret_cast(value); + return CreateUniqueOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ReverseV2Options: { + auto ptr = reinterpret_cast(value); + return CreateReverseV2Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_AddNOptions: { + auto ptr = reinterpret_cast(value); + return CreateAddNOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_GatherNdOptions: { + auto ptr = reinterpret_cast(value); + return CreateGatherNdOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_CosOptions: { + auto ptr = reinterpret_cast(value); + return CreateCosOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_WhereOptions: { + auto ptr = reinterpret_cast(value); + return CreateWhereOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_RankOptions: { + auto ptr = reinterpret_cast(value); + return CreateRankOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ReverseSequenceOptions: { + auto ptr = reinterpret_cast(value); + return CreateReverseSequenceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_MatrixDiagOptions: { + auto ptr = reinterpret_cast(value); + return CreateMatrixDiagOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_QuantizeOptions: { + auto ptr = reinterpret_cast(value); + return CreateQuantizeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_MatrixSetDiagOptions: { + auto ptr = reinterpret_cast(value); + return CreateMatrixSetDiagOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_HardSwishOptions: { + auto ptr = reinterpret_cast(value); + return CreateHardSwishOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_IfOptions: { + auto ptr = reinterpret_cast(value); + return CreateIfOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_WhileOptions: { + auto ptr = reinterpret_cast(value); + return CreateWhileOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_DepthToSpaceOptions: { + auto ptr = reinterpret_cast(value); + return CreateDepthToSpaceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_NonMaxSuppressionV4Options: { + auto ptr = reinterpret_cast(value); + return CreateNonMaxSuppressionV4Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_NonMaxSuppressionV5Options: { + auto ptr = reinterpret_cast(value); + return CreateNonMaxSuppressionV5Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ScatterNdOptions: { + auto ptr = reinterpret_cast(value); + return CreateScatterNdOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SelectV2Options: { + auto ptr = reinterpret_cast(value); + return CreateSelectV2Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_DensifyOptions: { + auto ptr = reinterpret_cast(value); + return CreateDensifyOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SegmentSumOptions: { + auto ptr = reinterpret_cast(value); + return CreateSegmentSumOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_BatchMatMulOptions: { + auto ptr = reinterpret_cast(value); + return CreateBatchMatMulOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_CumsumOptions: { + auto ptr = reinterpret_cast(value); + return CreateCumsumOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_CallOnceOptions: { + auto ptr = reinterpret_cast(value); + return CreateCallOnceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_BroadcastToOptions: { + auto ptr = reinterpret_cast(value); + return CreateBroadcastToOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_Rfft2dOptions: { + auto ptr = reinterpret_cast(value); + return CreateRfft2dOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_Conv3DOptions: { + auto ptr = reinterpret_cast(value); + return CreateConv3DOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_HashtableOptions: { + auto ptr = reinterpret_cast(value); + return CreateHashtableOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_HashtableFindOptions: { + auto ptr = reinterpret_cast(value); + return CreateHashtableFindOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_HashtableImportOptions: { + auto ptr = reinterpret_cast(value); + return CreateHashtableImportOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_HashtableSizeOptions: { + auto ptr = reinterpret_cast(value); + return CreateHashtableSizeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_VarHandleOptions: { + auto ptr = reinterpret_cast(value); + return CreateVarHandleOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ReadVariableOptions: { + auto ptr = reinterpret_cast(value); + return CreateReadVariableOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_AssignVariableOptions: { + auto ptr = reinterpret_cast(value); + return CreateAssignVariableOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_RandomOptions: { + auto ptr = reinterpret_cast(value); + return CreateRandomOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_BucketizeOptions: { + auto ptr = reinterpret_cast(value); + return CreateBucketizeOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_GeluOptions: { + auto ptr = reinterpret_cast(value); + return CreateGeluOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_DynamicUpdateSliceOptions: { + auto ptr = reinterpret_cast(value); + return CreateDynamicUpdateSliceOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UnsortedSegmentProdOptions: { + auto ptr = reinterpret_cast(value); + return CreateUnsortedSegmentProdOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UnsortedSegmentMaxOptions: { + auto ptr = reinterpret_cast(value); + return CreateUnsortedSegmentMaxOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UnsortedSegmentMinOptions: { + auto ptr = reinterpret_cast(value); + return CreateUnsortedSegmentMinOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_UnsortedSegmentSumOptions: { + auto ptr = reinterpret_cast(value); + return CreateUnsortedSegmentSumOptions(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_ATan2Options: { + auto ptr = reinterpret_cast(value); + return CreateATan2Options(_fbb, ptr, _rehasher).Union(); + } + case BuiltinOptions_SignOptions: { + auto ptr = reinterpret_cast(value); + return CreateSignOptions(_fbb, ptr, _rehasher).Union(); + } + default: return 0; + } +} + +inline BuiltinOptionsUnion::BuiltinOptionsUnion(const BuiltinOptionsUnion &u) : type(u.type), value(nullptr) { + switch (type) { + case BuiltinOptions_Conv2DOptions: { + value = new tflite::Conv2DOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_DepthwiseConv2DOptions: { + value = new tflite::DepthwiseConv2DOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ConcatEmbeddingsOptions: { + value = new tflite::ConcatEmbeddingsOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LSHProjectionOptions: { + value = new tflite::LSHProjectionOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_Pool2DOptions: { + value = new tflite::Pool2DOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SVDFOptions: { + value = new tflite::SVDFOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_RNNOptions: { + value = new tflite::RNNOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_FullyConnectedOptions: { + value = new tflite::FullyConnectedOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SoftmaxOptions: { + value = new tflite::SoftmaxOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ConcatenationOptions: { + value = new tflite::ConcatenationOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_AddOptions: { + value = new tflite::AddOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_L2NormOptions: { + value = new tflite::L2NormOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LocalResponseNormalizationOptions: { + value = new tflite::LocalResponseNormalizationOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LSTMOptions: { + value = new tflite::LSTMOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ResizeBilinearOptions: { + value = new tflite::ResizeBilinearOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_CallOptions: { + value = new tflite::CallOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ReshapeOptions: { + value = new tflite::ReshapeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SkipGramOptions: { + value = new tflite::SkipGramOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SpaceToDepthOptions: { + value = new tflite::SpaceToDepthOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_EmbeddingLookupSparseOptions: { + value = new tflite::EmbeddingLookupSparseOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_MulOptions: { + value = new tflite::MulOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_PadOptions: { + value = new tflite::PadOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_GatherOptions: { + value = new tflite::GatherOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_BatchToSpaceNDOptions: { + value = new tflite::BatchToSpaceNDOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SpaceToBatchNDOptions: { + value = new tflite::SpaceToBatchNDOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_TransposeOptions: { + value = new tflite::TransposeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ReducerOptions: { + value = new tflite::ReducerOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SubOptions: { + value = new tflite::SubOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_DivOptions: { + value = new tflite::DivOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SqueezeOptions: { + value = new tflite::SqueezeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SequenceRNNOptions: { + value = new tflite::SequenceRNNOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_StridedSliceOptions: { + value = new tflite::StridedSliceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ExpOptions: { + value = new tflite::ExpOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_TopKV2Options: { + value = new tflite::TopKV2OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SplitOptions: { + value = new tflite::SplitOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LogSoftmaxOptions: { + value = new tflite::LogSoftmaxOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_CastOptions: { + value = new tflite::CastOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_DequantizeOptions: { + value = new tflite::DequantizeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_MaximumMinimumOptions: { + value = new tflite::MaximumMinimumOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ArgMaxOptions: { + value = new tflite::ArgMaxOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LessOptions: { + value = new tflite::LessOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_NegOptions: { + value = new tflite::NegOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_PadV2Options: { + value = new tflite::PadV2OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_GreaterOptions: { + value = new tflite::GreaterOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_GreaterEqualOptions: { + value = new tflite::GreaterEqualOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LessEqualOptions: { + value = new tflite::LessEqualOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SelectOptions: { + value = new tflite::SelectOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SliceOptions: { + value = new tflite::SliceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_TransposeConvOptions: { + value = new tflite::TransposeConvOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SparseToDenseOptions: { + value = new tflite::SparseToDenseOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_TileOptions: { + value = new tflite::TileOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ExpandDimsOptions: { + value = new tflite::ExpandDimsOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_EqualOptions: { + value = new tflite::EqualOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_NotEqualOptions: { + value = new tflite::NotEqualOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ShapeOptions: { + value = new tflite::ShapeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_PowOptions: { + value = new tflite::PowOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ArgMinOptions: { + value = new tflite::ArgMinOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_FakeQuantOptions: { + value = new tflite::FakeQuantOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_PackOptions: { + value = new tflite::PackOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LogicalOrOptions: { + value = new tflite::LogicalOrOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_OneHotOptions: { + value = new tflite::OneHotOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LogicalAndOptions: { + value = new tflite::LogicalAndOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LogicalNotOptions: { + value = new tflite::LogicalNotOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UnpackOptions: { + value = new tflite::UnpackOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_FloorDivOptions: { + value = new tflite::FloorDivOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SquareOptions: { + value = new tflite::SquareOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ZerosLikeOptions: { + value = new tflite::ZerosLikeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_FillOptions: { + value = new tflite::FillOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: { + value = new tflite::BidirectionalSequenceLSTMOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: { + value = new tflite::BidirectionalSequenceRNNOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: { + value = new tflite::UnidirectionalSequenceLSTMOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_FloorModOptions: { + value = new tflite::FloorModOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_RangeOptions: { + value = new tflite::RangeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ResizeNearestNeighborOptions: { + value = new tflite::ResizeNearestNeighborOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_LeakyReluOptions: { + value = new tflite::LeakyReluOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SquaredDifferenceOptions: { + value = new tflite::SquaredDifferenceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_MirrorPadOptions: { + value = new tflite::MirrorPadOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_AbsOptions: { + value = new tflite::AbsOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SplitVOptions: { + value = new tflite::SplitVOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UniqueOptions: { + value = new tflite::UniqueOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ReverseV2Options: { + value = new tflite::ReverseV2OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_AddNOptions: { + value = new tflite::AddNOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_GatherNdOptions: { + value = new tflite::GatherNdOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_CosOptions: { + value = new tflite::CosOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_WhereOptions: { + value = new tflite::WhereOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_RankOptions: { + value = new tflite::RankOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ReverseSequenceOptions: { + value = new tflite::ReverseSequenceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_MatrixDiagOptions: { + value = new tflite::MatrixDiagOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_QuantizeOptions: { + value = new tflite::QuantizeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_MatrixSetDiagOptions: { + value = new tflite::MatrixSetDiagOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_HardSwishOptions: { + value = new tflite::HardSwishOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_IfOptions: { + value = new tflite::IfOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_WhileOptions: { + value = new tflite::WhileOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_DepthToSpaceOptions: { + value = new tflite::DepthToSpaceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_NonMaxSuppressionV4Options: { + value = new tflite::NonMaxSuppressionV4OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_NonMaxSuppressionV5Options: { + value = new tflite::NonMaxSuppressionV5OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ScatterNdOptions: { + value = new tflite::ScatterNdOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SelectV2Options: { + value = new tflite::SelectV2OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_DensifyOptions: { + value = new tflite::DensifyOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SegmentSumOptions: { + value = new tflite::SegmentSumOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_BatchMatMulOptions: { + value = new tflite::BatchMatMulOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_CumsumOptions: { + value = new tflite::CumsumOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_CallOnceOptions: { + value = new tflite::CallOnceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_BroadcastToOptions: { + value = new tflite::BroadcastToOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_Rfft2dOptions: { + value = new tflite::Rfft2dOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_Conv3DOptions: { + value = new tflite::Conv3DOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_HashtableOptions: { + value = new tflite::HashtableOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_HashtableFindOptions: { + value = new tflite::HashtableFindOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_HashtableImportOptions: { + value = new tflite::HashtableImportOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_HashtableSizeOptions: { + value = new tflite::HashtableSizeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_VarHandleOptions: { + value = new tflite::VarHandleOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ReadVariableOptions: { + value = new tflite::ReadVariableOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_AssignVariableOptions: { + value = new tflite::AssignVariableOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_RandomOptions: { + value = new tflite::RandomOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_BucketizeOptions: { + value = new tflite::BucketizeOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_GeluOptions: { + value = new tflite::GeluOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_DynamicUpdateSliceOptions: { + value = new tflite::DynamicUpdateSliceOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UnsortedSegmentProdOptions: { + value = new tflite::UnsortedSegmentProdOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UnsortedSegmentMaxOptions: { + value = new tflite::UnsortedSegmentMaxOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UnsortedSegmentMinOptions: { + value = new tflite::UnsortedSegmentMinOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_UnsortedSegmentSumOptions: { + value = new tflite::UnsortedSegmentSumOptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_ATan2Options: { + value = new tflite::ATan2OptionsT(*reinterpret_cast(u.value)); + break; + } + case BuiltinOptions_SignOptions: { + value = new tflite::SignOptionsT(*reinterpret_cast(u.value)); + break; + } + default: + break; + } +} + +inline void BuiltinOptionsUnion::Reset() { + switch (type) { + case BuiltinOptions_Conv2DOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_DepthwiseConv2DOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ConcatEmbeddingsOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LSHProjectionOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_Pool2DOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SVDFOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_RNNOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_FullyConnectedOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SoftmaxOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ConcatenationOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_AddOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_L2NormOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LocalResponseNormalizationOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LSTMOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ResizeBilinearOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_CallOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ReshapeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SkipGramOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SpaceToDepthOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_EmbeddingLookupSparseOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_MulOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_PadOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_GatherOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_BatchToSpaceNDOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SpaceToBatchNDOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_TransposeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ReducerOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SubOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_DivOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SqueezeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SequenceRNNOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_StridedSliceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ExpOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_TopKV2Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SplitOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LogSoftmaxOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_CastOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_DequantizeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_MaximumMinimumOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ArgMaxOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LessOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_NegOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_PadV2Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_GreaterOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_GreaterEqualOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LessEqualOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SelectOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SliceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_TransposeConvOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SparseToDenseOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_TileOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ExpandDimsOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_EqualOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_NotEqualOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ShapeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_PowOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ArgMinOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_FakeQuantOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_PackOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LogicalOrOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_OneHotOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LogicalAndOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LogicalNotOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UnpackOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_FloorDivOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SquareOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ZerosLikeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_FillOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_FloorModOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_RangeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ResizeNearestNeighborOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_LeakyReluOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SquaredDifferenceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_MirrorPadOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_AbsOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SplitVOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UniqueOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ReverseV2Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_AddNOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_GatherNdOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_CosOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_WhereOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_RankOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ReverseSequenceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_MatrixDiagOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_QuantizeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_MatrixSetDiagOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_HardSwishOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_IfOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_WhileOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_DepthToSpaceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_NonMaxSuppressionV4Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_NonMaxSuppressionV5Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ScatterNdOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SelectV2Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_DensifyOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SegmentSumOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_BatchMatMulOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_CumsumOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_CallOnceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_BroadcastToOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_Rfft2dOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_Conv3DOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_HashtableOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_HashtableFindOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_HashtableImportOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_HashtableSizeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_VarHandleOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ReadVariableOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_AssignVariableOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_RandomOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_BucketizeOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_GeluOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_DynamicUpdateSliceOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UnsortedSegmentProdOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UnsortedSegmentMaxOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UnsortedSegmentMinOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_UnsortedSegmentSumOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_ATan2Options: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + case BuiltinOptions_SignOptions: { + auto ptr = reinterpret_cast(value); + delete ptr; + break; + } + default: break; + } + value = nullptr; + type = BuiltinOptions_NONE; +} + +inline const tflite::Model *GetModel(const void *buf) { + return flatbuffers::GetRoot(buf); +} + +inline const tflite::Model *GetSizePrefixedModel(const void *buf) { + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *ModelIdentifier() { + return "TFL3"; +} + +inline bool ModelBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, ModelIdentifier()); +} + +inline bool SizePrefixedModelBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, ModelIdentifier(), true); +} + +inline bool VerifyModelBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer(ModelIdentifier()); +} + +inline bool VerifySizePrefixedModelBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer(ModelIdentifier()); +} + +inline const char *ModelExtension() { + return "tflite"; +} + +inline void FinishModelBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.Finish(root, ModelIdentifier()); +} + +inline void FinishSizePrefixedModelBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) { + fbb.FinishSizePrefixed(root, ModelIdentifier()); +} + +inline std::unique_ptr UnPackModel( + const void *buf, + const flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetModel(buf)->UnPack(res)); +} + +inline std::unique_ptr UnPackSizePrefixedModel( + const void *buf, + const flatbuffers::resolver_function_t *res = nullptr) { + return std::unique_ptr(GetSizePrefixedModel(buf)->UnPack(res)); +} + +} // namespace tflite + +#endif // FLATBUFFERS_GENERATED_SCHEMA_TFLITE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_utils.cpp b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_utils.cpp new file mode 100644 index 000000000..fc19290b8 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_utils.cpp @@ -0,0 +1,62 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 "tensorflow/lite/schema/schema_utils.h" + +#include + +#include "tensorflow/lite/kernels/internal/compatibility.h" + +namespace tflite { + +// The following GetBuiltinCode methods are the utility methods for reading +// builtin operatore code, ensuring compatibility issues between v3 and v3a +// schema. Always the maximum value of the two fields always will be the correct +// value as follows: +// +// - Supporting schema version v3 models +// +// The `builtin_code` field is not available in the v3 models. Flatbuffer +// library will feed zero value, which is the default value in the v3a schema. +// The actual builtin operatore code value will exist in the +// `deprecated_builtin_code` field. At the same time, it implies that +// `deprecated_builtin_code` >= `builtin_code` and the maximum value of the two +// fields will be same with `deprecated_builtin_code'. +// +// - Supporting builtin operator codes beyonds 127 +// +// New builtin operators, whose operator code is larger than 127, can not be +// assigned to the `deprecated_builtin_code` field. In such cases, the +// value of the `builtin_code` field should be used for the builtin operator +// code. In the case, the maximum value of the two fields will be the value of +// the `builtin_code` as the right value. + +BuiltinOperator GetBuiltinCode(const OperatorCode* op_code) { + // Caller should guarantee that the given argument value is not a nullptr. + TFLITE_DCHECK(op_code != nullptr); + + return std::max( + op_code->builtin_code(), + static_cast(op_code->deprecated_builtin_code())); +} + +BuiltinOperator GetBuiltinCode(const OperatorCodeT* op_code) { + // Caller should guarantee that the given argument value is not a nullptr. + TFLITE_DCHECK(op_code != nullptr); + + return std::max(op_code->builtin_code, static_cast( + op_code->deprecated_builtin_code)); +} + +} // namespace tflite diff --git a/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_utils.h b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_utils.h new file mode 100644 index 000000000..4d9142655 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/tensorflow/lite/schema/schema_utils.h @@ -0,0 +1,33 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +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 TENSORFLOW_LITE_SCHEMA_SCHEMA_UTILS_H_ +#define TENSORFLOW_LITE_SCHEMA_SCHEMA_UTILS_H_ + +#include "third_party/flatbuffers/include/flatbuffers/flatbuffers.h" +#include "tensorflow/lite/schema/schema_generated.h" + +namespace tflite { + +// The following methods are introduced to resolve op builtin code shortage +// problem. The new builtin operator will be assigned to the extended builtin +// code field in the flatbuffer schema. Those methods helps to hide builtin code +// details. +BuiltinOperator GetBuiltinCode(const OperatorCode *op_code); + +BuiltinOperator GetBuiltinCode(const OperatorCodeT *op_code); + +} // namespace tflite + +#endif // TENSORFLOW_LITE_SCHEMA_SCHEMA_UTILS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/LICENSE.txt b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/LICENSE.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/LICENSE.txt @@ -0,0 +1,202 @@ + + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/allocator.h new file mode 100644 index 000000000..50a46734a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/allocator.h @@ -0,0 +1,68 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_ALLOCATOR_H_ +#define FLATBUFFERS_ALLOCATOR_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" + +namespace flatbuffers { + +// Allocator interface. This is flatbuffers-specific and meant only for +// `vector_downward` usage. +class Allocator { + public: + virtual ~Allocator() {} + + // Allocate `size` bytes of memory. + virtual uint8_t *allocate(size_t size) = 0; + + // Deallocate `size` bytes of memory at `p` allocated by this allocator. + virtual void deallocate(uint8_t *p, size_t size) = 0; + + // Reallocate `new_size` bytes of memory, replacing the old region of size + // `old_size` at `p`. In contrast to a normal realloc, this grows downwards, + // and is intended specifcally for `vector_downward` use. + // `in_use_back` and `in_use_front` indicate how much of `old_size` is + // actually in use at each end, and needs to be copied. + virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size, + size_t new_size, size_t in_use_back, + size_t in_use_front) { + FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows + uint8_t *new_p = allocate(new_size); + memcpy_downward(old_p, old_size, new_p, new_size, in_use_back, + in_use_front); + deallocate(old_p, old_size); + return new_p; + } + + protected: + // Called by `reallocate_downward` to copy memory from `old_p` of `old_size` + // to `new_p` of `new_size`. Only memory of size `in_use_front` and + // `in_use_back` will be copied from the front and back of the old memory + // allocation. + void memcpy_downward(uint8_t *old_p, size_t old_size, uint8_t *new_p, + size_t new_size, size_t in_use_back, + size_t in_use_front) { + memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back, + in_use_back); + memcpy(new_p, old_p, in_use_front); + } +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_ALLOCATOR_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/array.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/array.h new file mode 100644 index 000000000..17e377565 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/array.h @@ -0,0 +1,243 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_ARRAY_H_ +#define FLATBUFFERS_ARRAY_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/stl_emulation.h" +#include "third_party/flatbuffers/include/flatbuffers/vector.h" + +namespace flatbuffers { + +// This is used as a helper type for accessing arrays. +template class Array { + // Array can carry only POD data types (scalars or structs). + typedef typename flatbuffers::bool_constant::value> + scalar_tag; + typedef + typename flatbuffers::conditional::type + IndirectHelperType; + + public: + typedef uint16_t size_type; + typedef typename IndirectHelper::return_type return_type; + typedef VectorIterator const_iterator; + typedef VectorReverseIterator const_reverse_iterator; + + // If T is a LE-scalar or a struct (!scalar_tag::value). + static FLATBUFFERS_CONSTEXPR bool is_span_observable = + (scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) || + !scalar_tag::value; + + FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; } + + return_type Get(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return IndirectHelper::Read(Data(), i); + } + + return_type operator[](uoffset_t i) const { return Get(i); } + + // If this is a Vector of enums, T will be its storage type, not the enum + // type. This function makes it convenient to retrieve value with enum + // type E. + template E GetEnum(uoffset_t i) const { + return static_cast(Get(i)); + } + + const_iterator begin() const { return const_iterator(Data(), 0); } + const_iterator end() const { return const_iterator(Data(), size()); } + + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + const_reverse_iterator crbegin() const { return rbegin(); } + const_reverse_iterator crend() const { return rend(); } + + // Get a mutable pointer to elements inside this array. + // This method used to mutate arrays of structs followed by a @p Mutate + // operation. For primitive types use @p Mutate directly. + // @warning Assignments and reads to/from the dereferenced pointer are not + // automatically converted to the correct endianness. + typename flatbuffers::conditional::type + GetMutablePointer(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return const_cast(&data()[i]); + } + + // Change elements if you have a non-const pointer to this object. + void Mutate(uoffset_t i, const T &val) { MutateImpl(scalar_tag(), i, val); } + + // The raw data in little endian format. Use with care. + const uint8_t *Data() const { return data_; } + + uint8_t *Data() { return data_; } + + // Similarly, but typed, much like std::vector::data + const T *data() const { return reinterpret_cast(Data()); } + T *data() { return reinterpret_cast(Data()); } + + // Copy data from a span with endian conversion. + // If this Array and the span overlap, the behavior is undefined. + void CopyFromSpan(flatbuffers::span src) { + const auto p1 = reinterpret_cast(src.data()); + const auto p2 = Data(); + FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) && + !(p2 >= p1 && p2 < (p1 + length))); + (void)p1; + (void)p2; + CopyFromSpanImpl(flatbuffers::bool_constant(), src); + } + + protected: + void MutateImpl(flatbuffers::true_type, uoffset_t i, const T &val) { + FLATBUFFERS_ASSERT(i < size()); + WriteScalar(data() + i, val); + } + + void MutateImpl(flatbuffers::false_type, uoffset_t i, const T &val) { + *(GetMutablePointer(i)) = val; + } + + void CopyFromSpanImpl(flatbuffers::true_type, + flatbuffers::span src) { + // Use std::memcpy() instead of std::copy() to avoid performance degradation + // due to aliasing if T is char or unsigned char. + // The size is known at compile time, so memcpy would be inlined. + std::memcpy(data(), src.data(), length * sizeof(T)); + } + + // Copy data from flatbuffers::span with endian conversion. + void CopyFromSpanImpl(flatbuffers::false_type, + flatbuffers::span src) { + for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); } + } + + // This class is only used to access pre-existing data. Don't ever + // try to construct these manually. + // 'constexpr' allows us to use 'size()' at compile time. + // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on + // a constructor. +#if defined(__cpp_constexpr) + constexpr Array(); +#else + Array(); +#endif + + uint8_t data_[length * sizeof(T)]; + + private: + // This class is a pointer. Copying will therefore create an invalid object. + // Private and unimplemented copy constructor. + Array(const Array &); + Array &operator=(const Array &); +}; + +// Specialization for Array[struct] with access using Offset pointer. +// This specialization used by idl_gen_text.cpp. +template class Array, length> { + static_assert(flatbuffers::is_same::value, "unexpected type T"); + + public: + typedef const void *return_type; + + const uint8_t *Data() const { return data_; } + + // Make idl_gen_text.cpp::PrintContainer happy. + return_type operator[](uoffset_t) const { + FLATBUFFERS_ASSERT(false); + return nullptr; + } + + private: + // This class is only used to access pre-existing data. + Array(); + Array(const Array &); + Array &operator=(const Array &); + + uint8_t data_[1]; +}; + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Array &arr) + FLATBUFFERS_NOEXCEPT { + static_assert( + Array::is_span_observable, + "wrong type U, only plain struct, LE-scalar, or byte types are allowed"); + return span(arr.data(), N); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( + const Array &arr) FLATBUFFERS_NOEXCEPT { + static_assert( + Array::is_span_observable, + "wrong type U, only plain struct, LE-scalar, or byte types are allowed"); + return span(arr.data(), N); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span +make_bytes_span(Array &arr) FLATBUFFERS_NOEXCEPT { + static_assert(Array::is_span_observable, + "internal error, Array might hold only scalars or structs"); + return span(arr.Data(), sizeof(U) * N); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span +make_bytes_span(const Array &arr) FLATBUFFERS_NOEXCEPT { + static_assert(Array::is_span_observable, + "internal error, Array might hold only scalars or structs"); + return span(arr.Data(), sizeof(U) * N); +} + +// Cast a raw T[length] to a raw flatbuffers::Array +// without endian conversion. Use with care. +// TODO: move these Cast-methods to `internal` namespace. +template +Array &CastToArray(T (&arr)[length]) { + return *reinterpret_cast *>(arr); +} + +template +const Array &CastToArray(const T (&arr)[length]) { + return *reinterpret_cast *>(arr); +} + +template +Array &CastToArrayOfEnum(T (&arr)[length]) { + static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); + return *reinterpret_cast *>(arr); +} + +template +const Array &CastToArrayOfEnum(const T (&arr)[length]) { + static_assert(sizeof(E) == sizeof(T), "invalid enum type E"); + return *reinterpret_cast *>(arr); +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_ARRAY_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/base.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/base.h new file mode 100644 index 000000000..525a8e5ce --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/base.h @@ -0,0 +1,496 @@ +#ifndef FLATBUFFERS_BASE_H_ +#define FLATBUFFERS_BASE_H_ + +// For TFLM, we always want FLATBUFFERS_LOCALE_INDEPENDENT to be defined as 0. +// We could achieve this by adding -DFLATBUFFERS_LOCALE_INDEPENDENT=0 to the +// TFLM Makefile. However, for (at least) the Arduino, adding additional build +// flags during the compilation can be a bit awkward. As such, we have instead +// made a decision to change the default to be FLATBUFFERS_LOCALE_INDEPENDENT=0 +// for TFLM to make it easier for external IDE integration. +#ifndef FLATBUFFERS_LOCALE_INDEPENDENT +#define FLATBUFFERS_LOCALE_INDEPENDENT 0 +#endif + +// clang-format off + +// If activate should be declared and included first. +#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \ + defined(_MSC_VER) && defined(_DEBUG) + // The _CRTDBG_MAP_ALLOC inside will replace + // calloc/free (etc) to its debug version using #define directives. + #define _CRTDBG_MAP_ALLOC + #include + #include + // Replace operator new by trace-enabled version. + #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) + #define new DEBUG_NEW +#endif + +#if !defined(FLATBUFFERS_ASSERT) +#include +#define FLATBUFFERS_ASSERT assert +#elif defined(FLATBUFFERS_ASSERT_INCLUDE) +// Include file with forward declaration +#include FLATBUFFERS_ASSERT_INCLUDE +#endif + +#ifndef ARDUINO +#include +#endif + +#include +#include +#include + +#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H) + #include +#else + #include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__unix__) && !defined(FLATBUFFERS_LOCALE_INDEPENDENT) + #include +#endif + +#ifdef __ANDROID__ + #include +#endif + +#if defined(__ICCARM__) +#include +#endif + +// Note the __clang__ check is needed, because clang presents itself +// as an older GNUC compiler (4.2). +// Clang 3.3 and later implement all of the ISO C++ 2011 standard. +// Clang 3.4 and later implement all of the ISO C++ 2014 standard. +// http://clang.llvm.org/cxx_status.html + +// Note the MSVC value '__cplusplus' may be incorrect: +// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L, +// indicating (erroneously!) that the compiler conformed to the C++98 Standard. +// This value should be correct starting from MSVC2017-15.7-Preview-3. +// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set. +// Workaround (for details see MSDN): +// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility. +// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch. + +#if defined(__GNUC__) && !defined(__clang__) + #define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#else + #define FLATBUFFERS_GCC 0 +#endif + +#if defined(__clang__) + #define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#else + #define FLATBUFFERS_CLANG 0 +#endif + +/// @cond FLATBUFFERS_INTERNAL +#if __cplusplus <= 199711L && \ + (!defined(_MSC_VER) || _MSC_VER < 1600) && \ + (!defined(__GNUC__) || \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400)) + #error A C++11 compatible compiler with support for the auto typing is \ + required for FlatBuffers. + #error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ +#endif + +#if !defined(__clang__) && \ + defined(__GNUC__) && \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600) + // Backwards compatibility for g++ 4.4, and 4.5 which don't have the nullptr + // and constexpr keywords. Note the __clang__ check is needed, because clang + // presents itself as an older GNUC compiler. + #ifndef nullptr_t + const class nullptr_t { + public: + template inline operator T*() const { return 0; } + private: + void operator&() const; + } nullptr = {}; + #endif + #ifndef constexpr + #define constexpr const + #endif +#endif + +// The wire format uses a little endian encoding (since that's efficient for +// the common platforms). +#if defined(__s390x__) + #define FLATBUFFERS_LITTLEENDIAN 0 +#endif // __s390x__ +#if !defined(FLATBUFFERS_LITTLEENDIAN) + #if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) + #if (defined(__BIG_ENDIAN__) || \ + (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + #define FLATBUFFERS_LITTLEENDIAN 0 + #else + #define FLATBUFFERS_LITTLEENDIAN 1 + #endif // __BIG_ENDIAN__ + #elif defined(_MSC_VER) + #if defined(_M_PPC) + #define FLATBUFFERS_LITTLEENDIAN 0 + #else + #define FLATBUFFERS_LITTLEENDIAN 1 + #endif + #else + #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN. + #endif +#endif // !defined(FLATBUFFERS_LITTLEENDIAN) + +#define FLATBUFFERS_VERSION_MAJOR 2 +#define FLATBUFFERS_VERSION_MINOR 0 +#define FLATBUFFERS_VERSION_REVISION 6 +#define FLATBUFFERS_STRING_EXPAND(X) #X +#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) +namespace flatbuffers { + // Returns version as string "MAJOR.MINOR.REVISION". + const char* FLATBUFFERS_VERSION(); +} + +#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \ + defined(__clang__) + #define FLATBUFFERS_FINAL_CLASS final + #define FLATBUFFERS_OVERRIDE override + #define FLATBUFFERS_EXPLICIT_CPP11 explicit + #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t +#else + #define FLATBUFFERS_FINAL_CLASS + #define FLATBUFFERS_OVERRIDE + #define FLATBUFFERS_EXPLICIT_CPP11 + #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE +#endif + +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ + (defined(__cpp_constexpr) && __cpp_constexpr >= 200704) + #define FLATBUFFERS_CONSTEXPR constexpr + #define FLATBUFFERS_CONSTEXPR_CPP11 constexpr + #define FLATBUFFERS_CONSTEXPR_DEFINED +#else + #define FLATBUFFERS_CONSTEXPR const + #define FLATBUFFERS_CONSTEXPR_CPP11 +#endif + +#if (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (defined(__cpp_constexpr) && __cpp_constexpr >= 201304) + #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11 +#else + #define FLATBUFFERS_CONSTEXPR_CPP14 +#endif + +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \ + (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \ + defined(__clang__) + #define FLATBUFFERS_NOEXCEPT noexcept +#else + #define FLATBUFFERS_NOEXCEPT +#endif + +// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to +// private, so be sure to put it at the end or reset access mode explicitly. +#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \ + defined(__clang__) + #define FLATBUFFERS_DELETE_FUNC(func) func = delete +#else + #define FLATBUFFERS_DELETE_FUNC(func) private: func +#endif + +#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \ + (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \ + defined(__clang__) + #define FLATBUFFERS_DEFAULT_DECLARATION +#endif + +// Check if we can use template aliases +// Not possible if Microsoft Compiler before 2012 +// Possible is the language feature __cpp_alias_templates is defined well +// Or possible if the C++ std is C+11 or newer +#if (defined(_MSC_VER) && _MSC_VER > 1700 /* MSVC2012 */) \ + || (defined(__cpp_alias_templates) && __cpp_alias_templates >= 200704) \ + || (defined(__cplusplus) && __cplusplus >= 201103L) + #define FLATBUFFERS_TEMPLATES_ALIASES +#endif + +#ifndef FLATBUFFERS_HAS_STRING_VIEW + // Only provide flatbuffers::string_view if __has_include can be used + // to detect a header that provides an implementation + #if defined(__has_include) + // Check for std::string_view (in c++17) + #if __has_include() && (__cplusplus >= 201606 || (defined(_HAS_CXX17) && _HAS_CXX17)) + #include + namespace flatbuffers { + typedef std::string_view string_view; + } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + // Check for std::experimental::string_view (in c++14, compiler-dependent) + #elif __has_include() && (__cplusplus >= 201411) + #include + namespace flatbuffers { + typedef std::experimental::string_view string_view; + } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + // Check for absl::string_view + #elif __has_include("absl/strings/string_view.h") + #include "absl/strings/string_view.h" + namespace flatbuffers { + typedef absl::string_view string_view; + } + #define FLATBUFFERS_HAS_STRING_VIEW 1 + #endif + #endif // __has_include +#endif // !FLATBUFFERS_HAS_STRING_VIEW + +#ifndef FLATBUFFERS_GENERAL_HEAP_ALLOC_OK + // Allow heap allocations to be used + #define FLATBUFFERS_GENERAL_HEAP_ALLOC_OK 1 +#endif // !FLATBUFFERS_GENERAL_HEAP_ALLOC_OK + +#ifndef FLATBUFFERS_HAS_NEW_STRTOD + // Modern (C++11) strtod and strtof functions are available for use. + // 1) nan/inf strings as argument of strtod; + // 2) hex-float as argument of strtod/strtof. + #if (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \ + (defined(__clang__)) + #define FLATBUFFERS_HAS_NEW_STRTOD 1 + #endif +#endif // !FLATBUFFERS_HAS_NEW_STRTOD + +#ifndef FLATBUFFERS_LOCALE_INDEPENDENT + // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, + // strtoull_l}. + #if (defined(_MSC_VER) && _MSC_VER >= 1800) || \ + (defined(__ANDROID_API__) && __ANDROID_API__>= 21) || \ + (defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \ + (!defined(__Fuchsia__) && !defined(__ANDROID_API__)) + #define FLATBUFFERS_LOCALE_INDEPENDENT 1 + #else + #define FLATBUFFERS_LOCALE_INDEPENDENT 0 + #endif +#endif // !FLATBUFFERS_LOCALE_INDEPENDENT + +// Suppress Undefined Behavior Sanitizer (recoverable only). Usage: +// - __supress_ubsan__("undefined") +// - __supress_ubsan__("signed-integer-overflow") +#if defined(__clang__) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >=7)) + #define __supress_ubsan__(type) __attribute__((no_sanitize(type))) +#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409) + #define __supress_ubsan__(type) __attribute__((no_sanitize_undefined)) +#else + #define __supress_ubsan__(type) +#endif + +// This is constexpr function used for checking compile-time constants. +// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`. +template FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) { + return !!t; +} + +// Enable C++ attribute [[]] if std:c++17 or higher. +#if ((__cplusplus >= 201703L) \ + || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))) + // All attributes unknown to an implementation are ignored without causing an error. + #define FLATBUFFERS_ATTRIBUTE(attr) attr + + #define FLATBUFFERS_FALLTHROUGH() [[fallthrough]] +#else + #define FLATBUFFERS_ATTRIBUTE(attr) + + #if FLATBUFFERS_CLANG >= 30800 + #define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]] + #elif FLATBUFFERS_GCC >= 70300 + #define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]] + #else + #define FLATBUFFERS_FALLTHROUGH() + #endif +#endif + +/// @endcond + +/// @file +namespace flatbuffers { + +/// @cond FLATBUFFERS_INTERNAL +// Our default offset / size type, 32bit on purpose on 64bit systems. +// Also, using a consistent offset type maintains compatibility of serialized +// offset values between 32bit and 64bit systems. +typedef uint32_t uoffset_t; + +// Signed offsets for references that can go in both directions. +typedef int32_t soffset_t; + +// Offset/index used in v-tables, can be changed to uint8_t in +// format forks to save a bit of space if desired. +typedef uint16_t voffset_t; + +typedef uintmax_t largest_scalar_t; + +// In 32bits, this evaluates to 2GB - 1 +#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(::flatbuffers::soffset_t) * 8 - 1)) - 1) + +// The minimum size buffer that can be a valid flatbuffer. +// Includes the offset to the root table (uoffset_t), the offset to the vtable +// of the root table (soffset_t), the size of the vtable (uint16_t), and the +// size of the referring table (uint16_t). +#define FLATBUFFERS_MIN_BUFFER_SIZE sizeof(uoffset_t) + sizeof(soffset_t) + \ + sizeof(uint16_t) + sizeof(uint16_t) + +// We support aligning the contents of buffers up to this size. +#ifndef FLATBUFFERS_MAX_ALIGNMENT + #define FLATBUFFERS_MAX_ALIGNMENT 32 +#endif + +/// @brief The length of a FlatBuffer file header. +static const size_t kFileIdentifierLength = 4; + +inline bool VerifyAlignmentRequirements(size_t align, size_t min_align = 1) { + return (min_align <= align) && (align <= (FLATBUFFERS_MAX_ALIGNMENT)) && + (align & (align - 1)) == 0; // must be power of 2 +} + +#if defined(_MSC_VER) + #pragma warning(disable: 4351) // C4351: new behavior: elements of array ... will be default initialized + #pragma warning(push) + #pragma warning(disable: 4127) // C4127: conditional expression is constant +#endif + +template T EndianSwap(T t) { + #if defined(_MSC_VER) + #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort + #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong + #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64 + #elif defined(__ICCARM__) + #define FLATBUFFERS_BYTESWAP16 __REV16 + #define FLATBUFFERS_BYTESWAP32 __REV + #define FLATBUFFERS_BYTESWAP64(x) \ + ((__REV(static_cast(x >> 32U))) | (static_cast(__REV(static_cast(x)))) << 32U) + #else + #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__) + // __builtin_bswap16 was missing prior to GCC 4.8. + #define FLATBUFFERS_BYTESWAP16(x) \ + static_cast(__builtin_bswap32(static_cast(x) << 16)) + #else + #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16 + #endif + #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32 + #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64 + #endif + if (sizeof(T) == 1) { // Compile-time if-then's. + return t; + } else if (sizeof(T) == 2) { + union { T t; uint16_t i; } u = { t }; + u.i = FLATBUFFERS_BYTESWAP16(u.i); + return u.t; + } else if (sizeof(T) == 4) { + union { T t; uint32_t i; } u = { t }; + u.i = FLATBUFFERS_BYTESWAP32(u.i); + return u.t; + } else if (sizeof(T) == 8) { + union { T t; uint64_t i; } u = { t }; + u.i = FLATBUFFERS_BYTESWAP64(u.i); + return u.t; + } else { + FLATBUFFERS_ASSERT(0); + return t; + } +} + +#if defined(_MSC_VER) + #pragma warning(pop) +#endif + + +template T EndianScalar(T t) { + #if FLATBUFFERS_LITTLEENDIAN + return t; + #else + return EndianSwap(t); + #endif +} + +template +// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. +__supress_ubsan__("alignment") +T ReadScalar(const void *p) { + return EndianScalar(*reinterpret_cast(p)); +} + +// See https://github.com/google/flatbuffers/issues/5950 + +#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstringop-overflow" +#endif + +template +// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details. +__supress_ubsan__("alignment") +void WriteScalar(void *p, T t) { + *reinterpret_cast(p) = EndianScalar(t); +} + +template struct Offset; +template __supress_ubsan__("alignment") void WriteScalar(void *p, Offset t) { + *reinterpret_cast(p) = EndianScalar(t.o); +} + +#if (FLATBUFFERS_GCC >= 100000) && (FLATBUFFERS_GCC < 110000) + #pragma GCC diagnostic pop +#endif + +// Computes how many bytes you'd have to pad to be able to write an +// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in +// memory). +__supress_ubsan__("unsigned-integer-overflow") +inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { + return ((~buf_size) + 1) & (scalar_size - 1); +} + +// Generic 'operator==' with conditional specialisations. +// T e - new value of a scalar field. +// T def - default of scalar (is known at compile-time). +template inline bool IsTheSameAs(T e, T def) { return e == def; } + +#if defined(FLATBUFFERS_NAN_DEFAULTS) && \ + defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) +// Like `operator==(e, def)` with weak NaN if T=(float|double). +template inline bool IsFloatTheSameAs(T e, T def) { + return (e == def) || ((def != def) && (e != e)); +} +template<> inline bool IsTheSameAs(float e, float def) { + return IsFloatTheSameAs(e, def); +} +template<> inline bool IsTheSameAs(double e, double def) { + return IsFloatTheSameAs(e, def); +} +#endif + +// Check 'v' is out of closed range [low; high]. +// Workaround for GCC warning [-Werror=type-limits]: +// comparison is always true due to limited range of data type. +template +inline bool IsOutRange(const T &v, const T &low, const T &high) { + return (v < low) || (high < v); +} + +// Check 'v' is in closed range [low; high]. +template +inline bool IsInRange(const T &v, const T &low, const T &high) { + return !IsOutRange(v, low, high); +} + +} // namespace flatbuffers +#endif // FLATBUFFERS_BASE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/buffer.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/buffer.h new file mode 100644 index 000000000..c0b79a858 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/buffer.h @@ -0,0 +1,142 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_BUFFER_H_ +#define FLATBUFFERS_BUFFER_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" + +namespace flatbuffers { + +// Wrapper for uoffset_t to allow safe template specialization. +// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset). +template struct Offset { + uoffset_t o; + Offset() : o(0) {} + Offset(uoffset_t _o) : o(_o) {} + Offset Union() const { return Offset(o); } + bool IsNull() const { return !o; } +}; + +inline void EndianCheck() { + int endiantest = 1; + // If this fails, see FLATBUFFERS_LITTLEENDIAN above. + FLATBUFFERS_ASSERT(*reinterpret_cast(&endiantest) == + FLATBUFFERS_LITTLEENDIAN); + (void)endiantest; +} + +template FLATBUFFERS_CONSTEXPR size_t AlignOf() { + // clang-format off + #ifdef _MSC_VER + return __alignof(T); + #else + #ifndef alignof + return __alignof__(T); + #else + return alignof(T); + #endif + #endif + // clang-format on +} + +// Lexicographically compare two strings (possibly containing nulls), and +// return true if the first is less than the second. +static inline bool StringLessThan(const char *a_data, uoffset_t a_size, + const char *b_data, uoffset_t b_size) { + const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size)); + return cmp == 0 ? a_size < b_size : cmp < 0; +} + +// When we read serialized data from memory, in the case of most scalars, +// we want to just read T, but in the case of Offset, we want to actually +// perform the indirection and return a pointer. +// The template specialization below does just that. +// It is wrapped in a struct since function templates can't overload on the +// return type like this. +// The typedef is for the convenience of callers of this function +// (avoiding the need for a trailing return decltype) +template struct IndirectHelper { + typedef T return_type; + typedef T mutable_return_type; + static const size_t element_stride = sizeof(T); + static return_type Read(const uint8_t *p, uoffset_t i) { + return EndianScalar((reinterpret_cast(p))[i]); + } +}; +template struct IndirectHelper> { + typedef const T *return_type; + typedef T *mutable_return_type; + static const size_t element_stride = sizeof(uoffset_t); + static return_type Read(const uint8_t *p, uoffset_t i) { + p += i * sizeof(uoffset_t); + return reinterpret_cast(p + ReadScalar(p)); + } +}; +template struct IndirectHelper { + typedef const T *return_type; + typedef T *mutable_return_type; + static const size_t element_stride = sizeof(T); + static return_type Read(const uint8_t *p, uoffset_t i) { + return reinterpret_cast(p + i * sizeof(T)); + } +}; + +/// @brief Get a pointer to the the file_identifier section of the buffer. +/// @return Returns a const char pointer to the start of the file_identifier +/// characters in the buffer. The returned char * has length +/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'. +/// This function is UNDEFINED for FlatBuffers whose schema does not include +/// a file_identifier (likely points at padding or the start of a the root +/// vtable). +inline const char *GetBufferIdentifier(const void *buf, + bool size_prefixed = false) { + return reinterpret_cast(buf) + + ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t)); +} + +// Helper to see if the identifier in a buffer has the expected value. +inline bool BufferHasIdentifier(const void *buf, const char *identifier, + bool size_prefixed = false) { + return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier, + flatbuffers::kFileIdentifierLength) == 0; +} + +/// @cond FLATBUFFERS_INTERNAL +// Helpers to get a typed pointer to the root object contained in the buffer. +template T *GetMutableRoot(void *buf) { + EndianCheck(); + return reinterpret_cast( + reinterpret_cast(buf) + + EndianScalar(*reinterpret_cast(buf))); +} + +template T *GetMutableSizePrefixedRoot(void *buf) { + return GetMutableRoot(reinterpret_cast(buf) + + sizeof(uoffset_t)); +} + +template const T *GetRoot(const void *buf) { + return GetMutableRoot(const_cast(buf)); +} + +template const T *GetSizePrefixedRoot(const void *buf) { + return GetRoot(reinterpret_cast(buf) + sizeof(uoffset_t)); +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_BUFFER_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/buffer_ref.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/buffer_ref.h new file mode 100644 index 000000000..c9fd4635a --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/buffer_ref.h @@ -0,0 +1,53 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_BUFFER_REF_H_ +#define FLATBUFFERS_BUFFER_REF_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/verifier.h" + +namespace flatbuffers { + +// Convenient way to bundle a buffer and its length, to pass it around +// typed by its root. +// A BufferRef does not own its buffer. +struct BufferRefBase {}; // for std::is_base_of + +template struct BufferRef : BufferRefBase { + BufferRef() : buf(nullptr), len(0), must_free(false) {} + BufferRef(uint8_t *_buf, uoffset_t _len) + : buf(_buf), len(_len), must_free(false) {} + + ~BufferRef() { + if (must_free) free(buf); + } + + const T *GetRoot() const { return flatbuffers::GetRoot(buf); } + + bool Verify() { + Verifier verifier(buf, len); + return verifier.VerifyBuffer(nullptr); + } + + uint8_t *buf; + uoffset_t len; + bool must_free; +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_BUFFER_REF_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/default_allocator.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/default_allocator.h new file mode 100644 index 000000000..3c5aa83e5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/default_allocator.h @@ -0,0 +1,58 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_DEFAULT_ALLOCATOR_H_ +#define FLATBUFFERS_DEFAULT_ALLOCATOR_H_ + +#include "third_party/flatbuffers/include/flatbuffers/allocator.h" +#include "third_party/flatbuffers/include/flatbuffers/base.h" + +namespace flatbuffers { + +// DefaultAllocator uses new/delete to allocate memory regions +class DefaultAllocator : public Allocator { + public: + uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE { + return new uint8_t[size]; + } + + void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE { delete[] p; } + + static void dealloc(void *p, size_t) { delete[] static_cast(p); } +}; + +// These functions allow for a null allocator to mean use the default allocator, +// as used by DetachedBuffer and vector_downward below. +// This is to avoid having a statically or dynamically allocated default +// allocator, or having to move it between the classes that may own it. +inline uint8_t *Allocate(Allocator *allocator, size_t size) { + return allocator->allocate(size); +} + +inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) { + allocator->deallocate(p, size); +} + +inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p, + size_t old_size, size_t new_size, + size_t in_use_back, size_t in_use_front) { + return allocator->reallocate_downward(old_p, old_size, new_size, in_use_back, + in_use_front); +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_DEFAULT_ALLOCATOR_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/detached_buffer.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/detached_buffer.h new file mode 100644 index 000000000..3b266656c --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/detached_buffer.h @@ -0,0 +1,114 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_DETACHED_BUFFER_H_ +#define FLATBUFFERS_DETACHED_BUFFER_H_ + +#include "third_party/flatbuffers/include/flatbuffers/allocator.h" +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/default_allocator.h" + +namespace flatbuffers { + +// DetachedBuffer is a finished flatbuffer memory region, detached from its +// builder. The original memory region and allocator are also stored so that +// the DetachedBuffer can manage the memory lifetime. +class DetachedBuffer { + public: + DetachedBuffer() + : allocator_(nullptr), + own_allocator_(false), + buf_(nullptr), + reserved_(0), + cur_(nullptr), + size_(0) {} + + DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf, + size_t reserved, uint8_t *cur, size_t sz) + : allocator_(allocator), + own_allocator_(own_allocator), + buf_(buf), + reserved_(reserved), + cur_(cur), + size_(sz) {} + + DetachedBuffer(DetachedBuffer &&other) + : allocator_(other.allocator_), + own_allocator_(other.own_allocator_), + buf_(other.buf_), + reserved_(other.reserved_), + cur_(other.cur_), + size_(other.size_) { + other.reset(); + } + + DetachedBuffer &operator=(DetachedBuffer &&other) { + if (this == &other) return *this; + + destroy(); + + allocator_ = other.allocator_; + own_allocator_ = other.own_allocator_; + buf_ = other.buf_; + reserved_ = other.reserved_; + cur_ = other.cur_; + size_ = other.size_; + + other.reset(); + + return *this; + } + + ~DetachedBuffer() { destroy(); } + + const uint8_t *data() const { return cur_; } + + uint8_t *data() { return cur_; } + + size_t size() const { return size_; } + + // These may change access mode, leave these at end of public section + FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other)); + FLATBUFFERS_DELETE_FUNC( + DetachedBuffer &operator=(const DetachedBuffer &other)); + + protected: + Allocator *allocator_; + bool own_allocator_; + uint8_t *buf_; + size_t reserved_; + uint8_t *cur_; + size_t size_; + + inline void destroy() { + if (buf_) Deallocate(allocator_, buf_, reserved_); + if (own_allocator_ && allocator_) { delete allocator_; } + reset(); + } + + inline void reset() { + allocator_ = nullptr; + own_allocator_ = false; + buf_ = nullptr; + reserved_ = 0; + cur_ = nullptr; + size_ = 0; + } +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_DETACHED_BUFFER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flatbuffer_builder.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flatbuffer_builder.h new file mode 100644 index 000000000..7233dcc54 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flatbuffer_builder.h @@ -0,0 +1,1214 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_FLATBUFFER_BUILDER_H_ +#define FLATBUFFERS_FLATBUFFER_BUILDER_H_ + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/allocator.h" +#include "third_party/flatbuffers/include/flatbuffers/array.h" +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/buffer_ref.h" +#include "third_party/flatbuffers/include/flatbuffers/default_allocator.h" +#include "third_party/flatbuffers/include/flatbuffers/detached_buffer.h" +#include "third_party/flatbuffers/include/flatbuffers/stl_emulation.h" +#include "third_party/flatbuffers/include/flatbuffers/string.h" +#include "third_party/flatbuffers/include/flatbuffers/struct.h" +#include "third_party/flatbuffers/include/flatbuffers/table.h" +#include "third_party/flatbuffers/include/flatbuffers/vector.h" +#include "third_party/flatbuffers/include/flatbuffers/vector_downward.h" +#include "third_party/flatbuffers/include/flatbuffers/verifier.h" + +namespace flatbuffers { + +// Converts a Field ID to a virtual table offset. +inline voffset_t FieldIndexToOffset(voffset_t field_id) { + // Should correspond to what EndTable() below builds up. + const int fixed_fields = 2; // Vtable size and Object Size. + return static_cast((field_id + fixed_fields) * sizeof(voffset_t)); +} + +template> +const T *data(const std::vector &v) { + // Eventually the returned pointer gets passed down to memcpy, so + // we need it to be non-null to avoid undefined behavior. + static uint8_t t; + return v.empty() ? reinterpret_cast(&t) : &v.front(); +} +template> +T *data(std::vector &v) { + // Eventually the returned pointer gets passed down to memcpy, so + // we need it to be non-null to avoid undefined behavior. + static uint8_t t; + return v.empty() ? reinterpret_cast(&t) : &v.front(); +} + +/// @addtogroup flatbuffers_cpp_api +/// @{ +/// @class FlatBufferBuilder +/// @brief Helper class to hold data needed in creation of a FlatBuffer. +/// To serialize data, you typically call one of the `Create*()` functions in +/// the generated code, which in turn call a sequence of `StartTable`/ +/// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/ +/// `CreateVector` functions. Do this is depth-first order to build up a tree to +/// the root. `Finish()` wraps up the buffer ready for transport. +class FlatBufferBuilder { + public: + /// @brief Default constructor for FlatBufferBuilder. + /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults + /// to `1024`. + /// @param[in] allocator An `Allocator` to use. If null will use + /// `DefaultAllocator`. + /// @param[in] own_allocator Whether the builder/vector should own the + /// allocator. Defaults to / `false`. + /// @param[in] buffer_minalign Force the buffer to be aligned to the given + /// minimum alignment upon reallocation. Only needed if you intend to store + /// types with custom alignment AND you wish to read the buffer in-place + /// directly after creation. + explicit FlatBufferBuilder( + size_t initial_size = 1024, Allocator *allocator = nullptr, + bool own_allocator = false, + size_t buffer_minalign = AlignOf()) + : buf_(initial_size, allocator, own_allocator, buffer_minalign), + num_field_loc(0), + max_voffset_(0), + nested(false), + finished(false), + minalign_(1), + force_defaults_(false), + dedup_vtables_(true), + string_pool(nullptr) { + EndianCheck(); + } + + /// @brief Move constructor for FlatBufferBuilder. + FlatBufferBuilder(FlatBufferBuilder &&other) + : buf_(1024, nullptr, false, AlignOf()), + num_field_loc(0), + max_voffset_(0), + nested(false), + finished(false), + minalign_(1), + force_defaults_(false), + dedup_vtables_(true), + string_pool(nullptr) { + EndianCheck(); + // Default construct and swap idiom. + // Lack of delegating constructors in vs2010 makes it more verbose than + // needed. + Swap(other); + } + + /// @brief Move assignment operator for FlatBufferBuilder. + FlatBufferBuilder &operator=(FlatBufferBuilder &&other) { + // Move construct a temporary and swap idiom + FlatBufferBuilder temp(std::move(other)); + Swap(temp); + return *this; + } + + void Swap(FlatBufferBuilder &other) { + using std::swap; + buf_.swap(other.buf_); + swap(num_field_loc, other.num_field_loc); + swap(max_voffset_, other.max_voffset_); + swap(nested, other.nested); + swap(finished, other.finished); + swap(minalign_, other.minalign_); + swap(force_defaults_, other.force_defaults_); + swap(dedup_vtables_, other.dedup_vtables_); + swap(string_pool, other.string_pool); + } + + ~FlatBufferBuilder() { + if (string_pool) delete string_pool; + } + + void Reset() { + Clear(); // clear builder state + buf_.reset(); // deallocate buffer + } + + /// @brief Reset all the state in this FlatBufferBuilder so it can be reused + /// to construct another buffer. + void Clear() { + ClearOffsets(); + buf_.clear(); + nested = false; + finished = false; + minalign_ = 1; + if (string_pool) string_pool->clear(); + } + + /// @brief The current size of the serialized buffer, counting from the end. + /// @return Returns an `uoffset_t` with the current size of the buffer. + uoffset_t GetSize() const { return buf_.size(); } + + /// @brief Get the serialized buffer (after you call `Finish()`). + /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the + /// buffer. + uint8_t *GetBufferPointer() const { + Finished(); + return buf_.data(); + } + + /// @brief Get the serialized buffer (after you call `Finish()`) as a span. + /// @return Returns a constructed flatbuffers::span that is a view over the + /// FlatBuffer data inside the buffer. + flatbuffers::span GetBufferSpan() const { + Finished(); + return flatbuffers::span(buf_.data(), buf_.size()); + } + + /// @brief Get a pointer to an unfinished buffer. + /// @return Returns a `uint8_t` pointer to the unfinished buffer. + uint8_t *GetCurrentBufferPointer() const { return buf_.data(); } + + /// @brief Get the released pointer to the serialized buffer. + /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards! + /// @return A `FlatBuffer` that owns the buffer and its allocator and + /// behaves similar to a `unique_ptr` with a deleter. + FLATBUFFERS_ATTRIBUTE([[deprecated("use Release() instead")]]) + DetachedBuffer ReleaseBufferPointer() { + Finished(); + return buf_.release(); + } + + /// @brief Get the released DetachedBuffer. + /// @return A `DetachedBuffer` that owns the buffer and its allocator. + DetachedBuffer Release() { + Finished(); + return buf_.release(); + } + + /// @brief Get the released pointer to the serialized buffer. + /// @param size The size of the memory block containing + /// the serialized `FlatBuffer`. + /// @param offset The offset from the released pointer where the finished + /// `FlatBuffer` starts. + /// @return A raw pointer to the start of the memory block containing + /// the serialized `FlatBuffer`. + /// @remark If the allocator is owned, it gets deleted when the destructor is + /// called.. + uint8_t *ReleaseRaw(size_t &size, size_t &offset) { + Finished(); + return buf_.release_raw(size, offset); + } + + /// @brief get the minimum alignment this buffer needs to be accessed + /// properly. This is only known once all elements have been written (after + /// you call Finish()). You can use this information if you need to embed + /// a FlatBuffer in some other buffer, such that you can later read it + /// without first having to copy it into its own buffer. + size_t GetBufferMinAlignment() const { + Finished(); + return minalign_; + } + + /// @cond FLATBUFFERS_INTERNAL + void Finished() const { + // If you get this assert, you're attempting to get access a buffer + // which hasn't been finished yet. Be sure to call + // FlatBufferBuilder::Finish with your root table. + // If you really need to access an unfinished buffer, call + // GetCurrentBufferPointer instead. + FLATBUFFERS_ASSERT(finished); + } + /// @endcond + + /// @brief In order to save space, fields that are set to their default value + /// don't get serialized into the buffer. + /// @param[in] fd When set to `true`, always serializes default values that + /// are set. Optional fields which are not set explicitly, will still not be + /// serialized. + void ForceDefaults(bool fd) { force_defaults_ = fd; } + + /// @brief By default vtables are deduped in order to save space. + /// @param[in] dedup When set to `true`, dedup vtables. + void DedupVtables(bool dedup) { dedup_vtables_ = dedup; } + + /// @cond FLATBUFFERS_INTERNAL + void Pad(size_t num_bytes) { buf_.fill(num_bytes); } + + void TrackMinAlign(size_t elem_size) { + if (elem_size > minalign_) minalign_ = elem_size; + } + + void Align(size_t elem_size) { + TrackMinAlign(elem_size); + buf_.fill(PaddingBytes(buf_.size(), elem_size)); + } + + void PushFlatBuffer(const uint8_t *bytes, size_t size) { + PushBytes(bytes, size); + finished = true; + } + + void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); } + + void PopBytes(size_t amount) { buf_.pop(amount); } + + template void AssertScalarT() { + // The code assumes power of 2 sizes and endian-swap-ability. + static_assert(flatbuffers::is_scalar::value, "T must be a scalar type"); + } + + // Write a single aligned scalar to the buffer + template uoffset_t PushElement(T element) { + AssertScalarT(); + Align(sizeof(T)); + buf_.push_small(EndianScalar(element)); + return GetSize(); + } + + template uoffset_t PushElement(Offset off) { + // Special case for offsets: see ReferTo below. + return PushElement(ReferTo(off.o)); + } + + // When writing fields, we track where they are, so we can create correct + // vtables later. + void TrackField(voffset_t field, uoffset_t off) { + FieldLoc fl = { off, field }; + buf_.scratch_push_small(fl); + num_field_loc++; + if (field > max_voffset_) { max_voffset_ = field; } + } + + // Like PushElement, but additionally tracks the field this represents. + template void AddElement(voffset_t field, T e, T def) { + // We don't serialize values equal to the default. + if (IsTheSameAs(e, def) && !force_defaults_) return; + TrackField(field, PushElement(e)); + } + + template void AddElement(voffset_t field, T e) { + TrackField(field, PushElement(e)); + } + + template void AddOffset(voffset_t field, Offset off) { + if (off.IsNull()) return; // Don't store. + AddElement(field, ReferTo(off.o), static_cast(0)); + } + + template void AddStruct(voffset_t field, const T *structptr) { + if (!structptr) return; // Default, don't store. + Align(AlignOf()); + buf_.push_small(*structptr); + TrackField(field, GetSize()); + } + + void AddStructOffset(voffset_t field, uoffset_t off) { + TrackField(field, off); + } + + // Offsets initially are relative to the end of the buffer (downwards). + // This function converts them to be relative to the current location + // in the buffer (when stored here), pointing upwards. + uoffset_t ReferTo(uoffset_t off) { + // Align to ensure GetSize() below is correct. + Align(sizeof(uoffset_t)); + // Offset must refer to something already in buffer. + const uoffset_t size = GetSize(); + FLATBUFFERS_ASSERT(off && off <= size); + return size - off + static_cast(sizeof(uoffset_t)); + } + + void NotNested() { + // If you hit this, you're trying to construct a Table/Vector/String + // during the construction of its parent table (between the MyTableBuilder + // and table.Finish(). + // Move the creation of these sub-objects to above the MyTableBuilder to + // not get this assert. + // Ignoring this assert may appear to work in simple cases, but the reason + // it is here is that storing objects in-line may cause vtable offsets + // to not fit anymore. It also leads to vtable duplication. + FLATBUFFERS_ASSERT(!nested); + // If you hit this, fields were added outside the scope of a table. + FLATBUFFERS_ASSERT(!num_field_loc); + } + + // From generated code (or from the parser), we call StartTable/EndTable + // with a sequence of AddElement calls in between. + uoffset_t StartTable() { + NotNested(); + nested = true; + return GetSize(); + } + + // This finishes one serialized object by generating the vtable if it's a + // table, comparing it against existing vtables, and writing the + // resulting vtable offset. + uoffset_t EndTable(uoffset_t start) { + // If you get this assert, a corresponding StartTable wasn't called. + FLATBUFFERS_ASSERT(nested); + // Write the vtable offset, which is the start of any Table. + // We fill it's value later. + auto vtableoffsetloc = PushElement(0); + // Write a vtable, which consists entirely of voffset_t elements. + // It starts with the number of offsets, followed by a type id, followed + // by the offsets themselves. In reverse: + // Include space for the last offset and ensure empty tables have a + // minimum size. + max_voffset_ = + (std::max)(static_cast(max_voffset_ + sizeof(voffset_t)), + FieldIndexToOffset(0)); + buf_.fill_big(max_voffset_); + auto table_object_size = vtableoffsetloc - start; + // Vtable use 16bit offsets. + FLATBUFFERS_ASSERT(table_object_size < 0x10000); + WriteScalar(buf_.data() + sizeof(voffset_t), + static_cast(table_object_size)); + WriteScalar(buf_.data(), max_voffset_); + // Write the offsets into the table + for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc); + it < buf_.scratch_end(); it += sizeof(FieldLoc)) { + auto field_location = reinterpret_cast(it); + auto pos = static_cast(vtableoffsetloc - field_location->off); + // If this asserts, it means you've set a field twice. + FLATBUFFERS_ASSERT( + !ReadScalar(buf_.data() + field_location->id)); + WriteScalar(buf_.data() + field_location->id, pos); + } + ClearOffsets(); + auto vt1 = reinterpret_cast(buf_.data()); + auto vt1_size = ReadScalar(vt1); + auto vt_use = GetSize(); + // See if we already have generated a vtable with this exact same + // layout before. If so, make it point to the old one, remove this one. + if (dedup_vtables_) { + for (auto it = buf_.scratch_data(); it < buf_.scratch_end(); + it += sizeof(uoffset_t)) { + auto vt_offset_ptr = reinterpret_cast(it); + auto vt2 = reinterpret_cast(buf_.data_at(*vt_offset_ptr)); + auto vt2_size = ReadScalar(vt2); + if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue; + vt_use = *vt_offset_ptr; + buf_.pop(GetSize() - vtableoffsetloc); + break; + } + } + // If this is a new vtable, remember it. + if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); } + // Fill the vtable offset we created above. + // The offset points from the beginning of the object to where the + // vtable is stored. + // Offsets default direction is downward in memory for future format + // flexibility (storing all vtables at the start of the file). + WriteScalar(buf_.data_at(vtableoffsetloc), + static_cast(vt_use) - + static_cast(vtableoffsetloc)); + + nested = false; + return vtableoffsetloc; + } + + FLATBUFFERS_ATTRIBUTE([[deprecated("call the version above instead")]]) + uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) { + return EndTable(start); + } + + // This checks a required field has been set in a given table that has + // just been constructed. + template void Required(Offset table, voffset_t field); + + uoffset_t StartStruct(size_t alignment) { + Align(alignment); + return GetSize(); + } + + uoffset_t EndStruct() { return GetSize(); } + + void ClearOffsets() { + buf_.scratch_pop(num_field_loc * sizeof(FieldLoc)); + num_field_loc = 0; + max_voffset_ = 0; + } + + // Aligns such that when "len" bytes are written, an object can be written + // after it with "alignment" without padding. + void PreAlign(size_t len, size_t alignment) { + if (len == 0) return; + TrackMinAlign(alignment); + buf_.fill(PaddingBytes(GetSize() + len, alignment)); + } + template void PreAlign(size_t len) { + AssertScalarT(); + PreAlign(len, sizeof(T)); + } + /// @endcond + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const char pointer to the data to be stored as a string. + /// @param[in] len The number of bytes that should be stored from `str`. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(const char *str, size_t len) { + NotNested(); + PreAlign(len + 1); // Always 0-terminated. + buf_.fill(1); + PushBytes(reinterpret_cast(str), len); + PushElement(static_cast(len)); + return Offset(GetSize()); + } + + /// @brief Store a string in the buffer, which is null-terminated. + /// @param[in] str A const char pointer to a C-string to add to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(const char *str) { + return CreateString(str, strlen(str)); + } + + /// @brief Store a string in the buffer, which is null-terminated. + /// @param[in] str A char pointer to a C-string to add to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(char *str) { + return CreateString(str, strlen(str)); + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const reference to a std::string to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(const std::string &str) { + return CreateString(str.c_str(), str.length()); + } + + // clang-format off + #ifdef FLATBUFFERS_HAS_STRING_VIEW + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const string_view to copy in to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateString(flatbuffers::string_view str) { + return CreateString(str.data(), str.size()); + } + #endif // FLATBUFFERS_HAS_STRING_VIEW + // clang-format on + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const pointer to a `String` struct to add to the buffer. + /// @return Returns the offset in the buffer where the string starts + Offset CreateString(const String *str) { + return str ? CreateString(str->c_str(), str->size()) : 0; + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// @param[in] str A const reference to a std::string like type with support + /// of T::c_str() and T::length() to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + template Offset CreateString(const T &str) { + return CreateString(str.c_str(), str.length()); + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const char pointer to the data to be stored as a string. + /// @param[in] len The number of bytes that should be stored from `str`. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateSharedString(const char *str, size_t len) { + FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK); + if (!string_pool) + string_pool = new StringOffsetMap(StringOffsetCompare(buf_)); + auto size_before_string = buf_.size(); + // Must first serialize the string, since the set is all offsets into + // buffer. + auto off = CreateString(str, len); + auto it = string_pool->find(off); + // If it exists we reuse existing serialized data! + if (it != string_pool->end()) { + // We can remove the string we serialized. + buf_.pop(buf_.size() - size_before_string); + return *it; + } + // Record this string for future use. + string_pool->insert(off); + return off; + } + +#ifdef FLATBUFFERS_HAS_STRING_VIEW + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const std::string_view to store in the buffer. + /// @return Returns the offset in the buffer where the string starts + Offset CreateSharedString(const flatbuffers::string_view str) { + return CreateSharedString(str.data(), str.size()); + } +#else + /// @brief Store a string in the buffer, which null-terminated. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const char pointer to a C-string to add to the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateSharedString(const char *str) { + return CreateSharedString(str, strlen(str)); + } + + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const reference to a std::string to store in the buffer. + /// @return Returns the offset in the buffer where the string starts. + Offset CreateSharedString(const std::string &str) { + return CreateSharedString(str.c_str(), str.length()); + } +#endif + + /// @brief Store a string in the buffer, which can contain any binary data. + /// If a string with this exact contents has already been serialized before, + /// instead simply returns the offset of the existing string. This uses a map + /// stored on the heap, but only stores the numerical offsets. + /// @param[in] str A const pointer to a `String` struct to add to the buffer. + /// @return Returns the offset in the buffer where the string starts + Offset CreateSharedString(const String *str) { + return CreateSharedString(str->c_str(), str->size()); + } + + /// @cond FLATBUFFERS_INTERNAL + uoffset_t EndVector(size_t len) { + FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector. + nested = false; + return PushElement(static_cast(len)); + } + + void StartVector(size_t len, size_t elemsize) { + NotNested(); + nested = true; + PreAlign(len * elemsize); + PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t. + } + + // Call this right before StartVector/CreateVector if you want to force the + // alignment to be something different than what the element size would + // normally dictate. + // This is useful when storing a nested_flatbuffer in a vector of bytes, + // or when storing SIMD floats, etc. + void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) { + if (len == 0) return; + FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); + PreAlign(len * elemsize, alignment); + } + + // Similar to ForceVectorAlignment but for String fields. + void ForceStringAlignment(size_t len, size_t alignment) { + if (len == 0) return; + FLATBUFFERS_ASSERT(VerifyAlignmentRequirements(alignment)); + PreAlign((len + 1) * sizeof(char), alignment); + } + + /// @endcond + + /// @brief Serialize an array into a FlatBuffer `vector`. + /// @tparam T The data type of the array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template Offset> CreateVector(const T *v, size_t len) { + // If this assert hits, you're specifying a template argument that is + // causing the wrong overload to be selected, remove it. + AssertScalarT(); + StartVector(len, sizeof(T)); + if (len == 0) { return Offset>(EndVector(len)); } + // clang-format off + #if FLATBUFFERS_LITTLEENDIAN + PushBytes(reinterpret_cast(v), len * sizeof(T)); + #else + if (sizeof(T) == 1) { + PushBytes(reinterpret_cast(v), len); + } else { + for (auto i = len; i > 0; ) { + PushElement(v[--i]); + } + } + #endif + // clang-format on + return Offset>(EndVector(len)); + } + + /// @brief Serialize an array like object into a FlatBuffer `vector`. + /// @tparam T The data type of the array elements. + /// @tparam C The type of the array. + /// @param[in] array A reference to an array like object of type `T` to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template Offset> CreateVector(const C &array) { + return CreateVector(array.data(), array.size()); + } + + /// @brief Serialize an initializer list into a FlatBuffer `vector`. + /// @tparam T The data type of the initializer list elements. + /// @param[in] v The value of the initializer list. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVector(std::initializer_list v) { + return CreateVector(v.begin(), v.size()); + } + + template + Offset>> CreateVector(const Offset *v, size_t len) { + StartVector(len, sizeof(Offset)); + for (auto i = len; i > 0;) { PushElement(v[--i]); } + return Offset>>(EndVector(len)); + } + + /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. + /// @tparam T The data type of the `std::vector` elements. + /// @param v A const reference to the `std::vector` to serialize into the + /// buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVector(const std::vector &v) { + return CreateVector(data(v), v.size()); + } + + // vector may be implemented using a bit-set, so we can't access it as + // an array. Instead, read elements manually. + // Background: https://isocpp.org/blog/2012/11/on-vectorbool + Offset> CreateVector(const std::vector &v) { + StartVector(v.size(), sizeof(uint8_t)); + for (auto i = v.size(); i > 0;) { + PushElement(static_cast(v[--i])); + } + return Offset>(EndVector(v.size())); + } + + /// @brief Serialize values returned by a function into a FlatBuffer `vector`. + /// This is a convenience function that takes care of iteration for you. + /// @tparam T The data type of the `std::vector` elements. + /// @param f A function that takes the current iteration 0..vector_size-1 and + /// returns any type that you can construct a FlatBuffers vector out of. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVector(size_t vector_size, + const std::function &f) { + FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK); + std::vector elems(vector_size); + for (size_t i = 0; i < vector_size; i++) elems[i] = f(i); + return CreateVector(elems); + } + + /// @brief Serialize values returned by a function into a FlatBuffer `vector`. + /// This is a convenience function that takes care of iteration for you. This + /// uses a vector stored on the heap to store the intermediate results of the + /// iteration. + /// @tparam T The data type of the `std::vector` elements. + /// @param f A function that takes the current iteration 0..vector_size-1, + /// and the state parameter returning any type that you can construct a + /// FlatBuffers vector out of. + /// @param state State passed to f. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVector(size_t vector_size, F f, S *state) { + FLATBUFFERS_ASSERT(FLATBUFFERS_GENERAL_HEAP_ALLOC_OK); + std::vector elems(vector_size); + for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state); + return CreateVector(elems); + } + + /// @brief Serialize a `std::vector` into a FlatBuffer `vector`. + /// whereas StringType is any type that is accepted by the CreateString() + /// overloads. + /// This is a convenience function for a common case. + /// @param v A const reference to the `std::vector` to serialize into the + /// buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset>> CreateVectorOfStrings( + const std::vector &v) { + return CreateVectorOfStrings(v.cbegin(), v.cend()); + } + + /// @brief Serialize a collection of Strings into a FlatBuffer `vector`. + /// This is a convenience function for a common case. + /// @param begin The begining iterator of the collection + /// @param end The ending iterator of the collection + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset>> CreateVectorOfStrings(It begin, It end) { + auto size = std::distance(begin, end); + auto scratch_buffer_usage = size * sizeof(Offset); + // If there is not enough space to store the offsets, there definitely won't + // be enough space to store all the strings. So ensuring space for the + // scratch region is OK, for it it fails, it would have failed later. + buf_.ensure_space(scratch_buffer_usage); + for (auto it = begin; it != end; ++it) { + buf_.scratch_push_small(CreateString(*it)); + } + StartVector(size, sizeof(Offset)); + for (auto i = 1; i <= size; i++) { + // Note we re-evaluate the buf location each iteration to account for any + // underlying buffer resizing that may occur. + PushElement(*reinterpret_cast *>( + buf_.scratch_end() - i * sizeof(Offset))); + } + buf_.scratch_pop(scratch_buffer_usage); + return Offset>>(EndVector(size)); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfStructs(const T *v, size_t len) { + StartVector(len * sizeof(T) / AlignOf(), AlignOf()); + if (len > 0) { + PushBytes(reinterpret_cast(v), sizeof(T) * len); + } + return Offset>(EndVector(len)); + } + + /// @brief Serialize an array of native structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @tparam S The data type of the native struct array elements. + /// @param[in] v A pointer to the array of type `S` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @param[in] pack_func Pointer to a function to convert the native struct + /// to the FlatBuffer struct. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfNativeStructs( + const S *v, size_t len, T (*const pack_func)(const S &)) { + FLATBUFFERS_ASSERT(pack_func); + auto structs = StartVectorOfStructs(len); + for (size_t i = 0; i < len; i++) { structs[i] = pack_func(v[i]); } + return EndVectorOfStructs(len); + } + + /// @brief Serialize an array of native structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @tparam S The data type of the native struct array elements. + /// @param[in] v A pointer to the array of type `S` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfNativeStructs(const S *v, + size_t len) { + extern T Pack(const S &); + return CreateVectorOfNativeStructs(v, len, Pack); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] filler A function that takes the current iteration + /// 0..vector_size-1 and a pointer to the struct that must be filled. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + /// This is mostly useful when flatbuffers are generated with mutation + /// accessors. + template + Offset> CreateVectorOfStructs( + size_t vector_size, const std::function &filler) { + T *structs = StartVectorOfStructs(vector_size); + for (size_t i = 0; i < vector_size; i++) { + filler(i, structs); + structs++; + } + return EndVectorOfStructs(vector_size); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the struct array elements. + /// @param[in] f A function that takes the current iteration 0..vector_size-1, + /// a pointer to the struct that must be filled and the state argument. + /// @param[in] state Arbitrary state to pass to f. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + /// This is mostly useful when flatbuffers are generated with mutation + /// accessors. + template + Offset> CreateVectorOfStructs(size_t vector_size, F f, + S *state) { + T *structs = StartVectorOfStructs(vector_size); + for (size_t i = 0; i < vector_size; i++) { + f(i, structs, state); + structs++; + } + return EndVectorOfStructs(vector_size); + } + + /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfStructs( + const std::vector &v) { + return CreateVectorOfStructs(data(v), v.size()); + } + + /// @brief Serialize a `std::vector` of native structs into a FlatBuffer + /// `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam S The data type of the `std::vector` native struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @param[in] pack_func Pointer to a function to convert the native struct + /// to the FlatBuffer struct. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfNativeStructs( + const std::vector &v, T (*const pack_func)(const S &)) { + return CreateVectorOfNativeStructs(data(v), v.size(), pack_func); + } + + /// @brief Serialize a `std::vector` of native structs into a FlatBuffer + /// `vector`. + /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam S The data type of the `std::vector` native struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfNativeStructs( + const std::vector &v) { + return CreateVectorOfNativeStructs(data(v), v.size()); + } + + /// @cond FLATBUFFERS_INTERNAL + template struct StructKeyComparator { + bool operator()(const T &a, const T &b) const { + return a.KeyCompareLessThan(&b); + } + }; + /// @endcond + + /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector` + /// in sorted order. + /// @tparam T The data type of the `std::vector` struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfSortedStructs( + std::vector *v) { + return CreateVectorOfSortedStructs(data(*v), v->size()); + } + + /// @brief Serialize a `std::vector` of native structs into a FlatBuffer + /// `vector` in sorted order. + /// @tparam T The data type of the `std::vector` struct elements. + /// @tparam S The data type of the `std::vector` native struct elements. + /// @param[in] v A const reference to the `std::vector` of structs to + /// serialize into the buffer as a `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset> CreateVectorOfSortedNativeStructs( + std::vector *v) { + return CreateVectorOfSortedNativeStructs(data(*v), v->size()); + } + + /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted + /// order. + /// @tparam T The data type of the struct array elements. + /// @param[in] v A pointer to the array of type `T` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfSortedStructs(T *v, size_t len) { + std::stable_sort(v, v + len, StructKeyComparator()); + return CreateVectorOfStructs(v, len); + } + + /// @brief Serialize an array of native structs into a FlatBuffer `vector` in + /// sorted order. + /// @tparam T The data type of the struct array elements. + /// @tparam S The data type of the native struct array elements. + /// @param[in] v A pointer to the array of type `S` to serialize into the + /// buffer as a `vector`. + /// @param[in] len The number of elements to serialize. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset> CreateVectorOfSortedNativeStructs(S *v, + size_t len) { + extern T Pack(const S &); + auto structs = StartVectorOfStructs(len); + for (size_t i = 0; i < len; i++) { structs[i] = Pack(v[i]); } + std::stable_sort(structs, structs + len, StructKeyComparator()); + return EndVectorOfStructs(len); + } + + /// @cond FLATBUFFERS_INTERNAL + template struct TableKeyComparator { + TableKeyComparator(vector_downward &buf) : buf_(buf) {} + TableKeyComparator(const TableKeyComparator &other) : buf_(other.buf_) {} + bool operator()(const Offset &a, const Offset &b) const { + auto table_a = reinterpret_cast(buf_.data_at(a.o)); + auto table_b = reinterpret_cast(buf_.data_at(b.o)); + return table_a->KeyCompareLessThan(table_b); + } + vector_downward &buf_; + + private: + FLATBUFFERS_DELETE_FUNC( + TableKeyComparator &operator=(const TableKeyComparator &other)); + }; + /// @endcond + + /// @brief Serialize an array of `table` offsets as a `vector` in the buffer + /// in sorted order. + /// @tparam T The data type that the offset refers to. + /// @param[in] v An array of type `Offset` that contains the `table` + /// offsets to store in the buffer in sorted order. + /// @param[in] len The number of elements to store in the `vector`. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template + Offset>> CreateVectorOfSortedTables(Offset *v, + size_t len) { + std::stable_sort(v, v + len, TableKeyComparator(buf_)); + return CreateVector(v, len); + } + + /// @brief Serialize an array of `table` offsets as a `vector` in the buffer + /// in sorted order. + /// @tparam T The data type that the offset refers to. + /// @param[in] v An array of type `Offset` that contains the `table` + /// offsets to store in the buffer in sorted order. + /// @return Returns a typed `Offset` into the serialized data indicating + /// where the vector is stored. + template> + Offset>> CreateVectorOfSortedTables( + std::vector, Alloc> *v) { + return CreateVectorOfSortedTables(data(*v), v->size()); + } + + /// @brief Specialized version of `CreateVector` for non-copying use cases. + /// Write the data any time later to the returned buffer pointer `buf`. + /// @param[in] len The number of elements to store in the `vector`. + /// @param[in] elemsize The size of each element in the `vector`. + /// @param[out] buf A pointer to a `uint8_t` pointer that can be + /// written to at a later time to serialize the data into a `vector` + /// in the buffer. + uoffset_t CreateUninitializedVector(size_t len, size_t elemsize, + uint8_t **buf) { + NotNested(); + StartVector(len, elemsize); + buf_.make_space(len * elemsize); + auto vec_start = GetSize(); + auto vec_end = EndVector(len); + *buf = buf_.data_at(vec_start); + return vec_end; + } + + /// @brief Specialized version of `CreateVector` for non-copying use cases. + /// Write the data any time later to the returned buffer pointer `buf`. + /// @tparam T The data type of the data that will be stored in the buffer + /// as a `vector`. + /// @param[in] len The number of elements to store in the `vector`. + /// @param[out] buf A pointer to a pointer of type `T` that can be + /// written to at a later time to serialize the data into a `vector` + /// in the buffer. + template + Offset> CreateUninitializedVector(size_t len, T **buf) { + AssertScalarT(); + return CreateUninitializedVector(len, sizeof(T), + reinterpret_cast(buf)); + } + + template + Offset> CreateUninitializedVectorOfStructs(size_t len, + T **buf) { + return CreateUninitializedVector(len, sizeof(T), + reinterpret_cast(buf)); + } + + // @brief Create a vector of scalar type T given as input a vector of scalar + // type U, useful with e.g. pre "enum class" enums, or any existing scalar + // data of the wrong type. + template + Offset> CreateVectorScalarCast(const U *v, size_t len) { + AssertScalarT(); + AssertScalarT(); + StartVector(len, sizeof(T)); + for (auto i = len; i > 0;) { PushElement(static_cast(v[--i])); } + return Offset>(EndVector(len)); + } + + /// @brief Write a struct by itself, typically to be part of a union. + template Offset CreateStruct(const T &structobj) { + NotNested(); + Align(AlignOf()); + buf_.push_small(structobj); + return Offset(GetSize()); + } + + /// @brief Finish serializing a buffer by writing the root offset. + /// @param[in] file_identifier If a `file_identifier` is given, the buffer + /// will be prefixed with a standard FlatBuffers file header. + template + void Finish(Offset root, const char *file_identifier = nullptr) { + Finish(root.o, file_identifier, false); + } + + /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the + /// buffer following the size field). These buffers are NOT compatible + /// with standard buffers created by Finish, i.e. you can't call GetRoot + /// on them, you have to use GetSizePrefixedRoot instead. + /// All >32 bit quantities in this buffer will be aligned when the whole + /// size pre-fixed buffer is aligned. + /// These kinds of buffers are useful for creating a stream of FlatBuffers. + template + void FinishSizePrefixed(Offset root, + const char *file_identifier = nullptr) { + Finish(root.o, file_identifier, true); + } + + void SwapBufAllocator(FlatBufferBuilder &other) { + buf_.swap_allocator(other.buf_); + } + + /// @brief The length of a FlatBuffer file header. + static const size_t kFileIdentifierLength = + ::flatbuffers::kFileIdentifierLength; + + protected: + // You shouldn't really be copying instances of this class. + FlatBufferBuilder(const FlatBufferBuilder &); + FlatBufferBuilder &operator=(const FlatBufferBuilder &); + + void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) { + NotNested(); + buf_.clear_scratch(); + // This will cause the whole buffer to be aligned. + PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) + + (file_identifier ? kFileIdentifierLength : 0), + minalign_); + if (file_identifier) { + FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength); + PushBytes(reinterpret_cast(file_identifier), + kFileIdentifierLength); + } + PushElement(ReferTo(root)); // Location of root. + if (size_prefix) { PushElement(GetSize()); } + finished = true; + } + + struct FieldLoc { + uoffset_t off; + voffset_t id; + }; + + vector_downward buf_; + + // Accumulating offsets of table members while it is being built. + // We store these in the scratch pad of buf_, after the vtable offsets. + uoffset_t num_field_loc; + // Track how much of the vtable is in use, so we can output the most compact + // possible vtable. + voffset_t max_voffset_; + + // Ensure objects are not nested. + bool nested; + + // Ensure the buffer is finished before it is being accessed. + bool finished; + + size_t minalign_; + + bool force_defaults_; // Serialize values equal to their defaults anyway. + + bool dedup_vtables_; + + struct StringOffsetCompare { + StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {} + bool operator()(const Offset &a, const Offset &b) const { + auto stra = reinterpret_cast(buf_->data_at(a.o)); + auto strb = reinterpret_cast(buf_->data_at(b.o)); + return StringLessThan(stra->data(), stra->size(), strb->data(), + strb->size()); + } + const vector_downward *buf_; + }; + + // For use with CreateSharedString. Instantiated on first use only. + typedef std::set, StringOffsetCompare> StringOffsetMap; + StringOffsetMap *string_pool; + + private: + // Allocates space for a vector of structures. + // Must be completed with EndVectorOfStructs(). + template T *StartVectorOfStructs(size_t vector_size) { + StartVector(vector_size * sizeof(T) / AlignOf(), AlignOf()); + return reinterpret_cast(buf_.make_space(vector_size * sizeof(T))); + } + + // End the vector of structures in the flatbuffers. + // Vector should have previously be started with StartVectorOfStructs(). + template + Offset> EndVectorOfStructs(size_t vector_size) { + return Offset>(EndVector(vector_size)); + } +}; +/// @} + +/// Helpers to get a typed pointer to objects that are currently being built. +/// @warning Creating new objects will lead to reallocations and invalidates +/// the pointer! +template +T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset offset) { + return reinterpret_cast(fbb.GetCurrentBufferPointer() + fbb.GetSize() - + offset.o); +} + +template +const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset offset) { + return GetMutableTemporaryPointer(fbb, offset); +} + +template +void FlatBufferBuilder::Required(Offset table, voffset_t field) { + auto table_ptr = reinterpret_cast(buf_.data_at(table.o)); + bool ok = table_ptr->GetOptionalFieldOffset(field) != 0; + // If this fails, the caller will show what field needs to be set. + FLATBUFFERS_ASSERT(ok); + (void)ok; +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flatbuffers.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flatbuffers.h new file mode 100644 index 000000000..6e7dc1b00 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flatbuffers.h @@ -0,0 +1,270 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_H_ +#define FLATBUFFERS_H_ + +// TODO: These includes are for mitigating the pains of users editing their +// source because they relied on flatbuffers.h to include everything for them. +#include "third_party/flatbuffers/include/flatbuffers/array.h" +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/buffer.h" +#include "third_party/flatbuffers/include/flatbuffers/buffer_ref.h" +#include "third_party/flatbuffers/include/flatbuffers/detached_buffer.h" +#include "third_party/flatbuffers/include/flatbuffers/flatbuffer_builder.h" +#include "third_party/flatbuffers/include/flatbuffers/stl_emulation.h" +#include "third_party/flatbuffers/include/flatbuffers/string.h" +#include "third_party/flatbuffers/include/flatbuffers/struct.h" +#include "third_party/flatbuffers/include/flatbuffers/table.h" +#include "third_party/flatbuffers/include/flatbuffers/vector.h" +#include "third_party/flatbuffers/include/flatbuffers/vector_downward.h" +#include "third_party/flatbuffers/include/flatbuffers/verifier.h" + +namespace flatbuffers { + +/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e. +/// it is the opposite transformation of GetRoot(). +/// This may be useful if you want to pass on a root and have the recipient +/// delete the buffer afterwards. +inline const uint8_t *GetBufferStartFromRootPointer(const void *root) { + auto table = reinterpret_cast(root); + auto vtable = table->GetVTable(); + // Either the vtable is before the root or after the root. + auto start = (std::min)(vtable, reinterpret_cast(root)); + // Align to at least sizeof(uoffset_t). + start = reinterpret_cast(reinterpret_cast(start) & + ~(sizeof(uoffset_t) - 1)); + // Additionally, there may be a file_identifier in the buffer, and the root + // offset. The buffer may have been aligned to any size between + // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align"). + // Sadly, the exact alignment is only known when constructing the buffer, + // since it depends on the presence of values with said alignment properties. + // So instead, we simply look at the next uoffset_t values (root, + // file_identifier, and alignment padding) to see which points to the root. + // None of the other values can "impersonate" the root since they will either + // be 0 or four ASCII characters. + static_assert(flatbuffers::kFileIdentifierLength == sizeof(uoffset_t), + "file_identifier is assumed to be the same size as uoffset_t"); + for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1; + possible_roots; possible_roots--) { + start -= sizeof(uoffset_t); + if (ReadScalar(start) + start == + reinterpret_cast(root)) + return start; + } + // We didn't find the root, either the "root" passed isn't really a root, + // or the buffer is corrupt. + // Assert, because calling this function with bad data may cause reads + // outside of buffer boundaries. + FLATBUFFERS_ASSERT(false); + return nullptr; +} + +/// @brief This return the prefixed size of a FlatBuffer. +inline uoffset_t GetPrefixedSize(const uint8_t *buf) { + return ReadScalar(buf); +} + +// Base class for native objects (FlatBuffer data de-serialized into native +// C++ data structures). +// Contains no functionality, purely documentative. +struct NativeTable {}; + +/// @brief Function types to be used with resolving hashes into objects and +/// back again. The resolver gets a pointer to a field inside an object API +/// object that is of the type specified in the schema using the attribute +/// `cpp_type` (it is thus important whatever you write to this address +/// matches that type). The value of this field is initially null, so you +/// may choose to implement a delayed binding lookup using this function +/// if you wish. The resolver does the opposite lookup, for when the object +/// is being serialized again. +typedef uint64_t hash_value_t; +typedef std::function + resolver_function_t; +typedef std::function rehasher_function_t; + +// Helper function to test if a field is present, using any of the field +// enums in the generated code. +// `table` must be a generated table type. Since this is a template parameter, +// this is not typechecked to be a subclass of Table, so beware! +// Note: this function will return false for fields equal to the default +// value, since they're not stored in the buffer (unless force_defaults was +// used). +template +bool IsFieldPresent(const T *table, typename T::FlatBuffersVTableOffset field) { + // Cast, since Table is a private baseclass of any table types. + return reinterpret_cast(table)->CheckField( + static_cast(field)); +} + +// Utility function for reverse lookups on the EnumNames*() functions +// (in the generated C++ code) +// names must be NULL terminated. +inline int LookupEnum(const char **names, const char *name) { + for (const char **p = names; *p; p++) + if (!strcmp(*p, name)) return static_cast(p - names); + return -1; +} + +// These macros allow us to layout a struct with a guarantee that they'll end +// up looking the same on different compilers and platforms. +// It does this by disallowing the compiler to do any padding, and then +// does padding itself by inserting extra padding fields that make every +// element aligned to its own size. +// Additionally, it manually sets the alignment of the struct as a whole, +// which is typically its largest element, or a custom size set in the schema +// by the force_align attribute. +// These are used in the generated code only. + +// clang-format off +#if defined(_MSC_VER) + #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ + __pragma(pack(1)) \ + struct __declspec(align(alignment)) + #define FLATBUFFERS_STRUCT_END(name, size) \ + __pragma(pack()) \ + static_assert(sizeof(name) == size, "compiler breaks packing rules") +#elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__) + #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \ + _Pragma("pack(1)") \ + struct __attribute__((aligned(alignment))) + #define FLATBUFFERS_STRUCT_END(name, size) \ + _Pragma("pack()") \ + static_assert(sizeof(name) == size, "compiler breaks packing rules") +#else + #error Unknown compiler, please define structure alignment macros +#endif +// clang-format on + +// Minimal reflection via code generation. +// Besides full-fat reflection (see reflection.h) and parsing/printing by +// loading schemas (see idl.h), we can also have code generation for minimal +// reflection data which allows pretty-printing and other uses without needing +// a schema or a parser. +// Generate code with --reflect-types (types only) or --reflect-names (names +// also) to enable. +// See minireflect.h for utilities using this functionality. + +// These types are organized slightly differently as the ones in idl.h. +enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM }; + +// Scalars have the same order as in idl.h +// clang-format off +#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \ + ET(ET_UTYPE) \ + ET(ET_BOOL) \ + ET(ET_CHAR) \ + ET(ET_UCHAR) \ + ET(ET_SHORT) \ + ET(ET_USHORT) \ + ET(ET_INT) \ + ET(ET_UINT) \ + ET(ET_LONG) \ + ET(ET_ULONG) \ + ET(ET_FLOAT) \ + ET(ET_DOUBLE) \ + ET(ET_STRING) \ + ET(ET_SEQUENCE) // See SequenceType. + +enum ElementaryType { + #define FLATBUFFERS_ET(E) E, + FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) + #undef FLATBUFFERS_ET +}; + +inline const char * const *ElementaryTypeNames() { + static const char * const names[] = { + #define FLATBUFFERS_ET(E) #E, + FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET) + #undef FLATBUFFERS_ET + }; + return names; +} +// clang-format on + +// Basic type info cost just 16bits per field! +// We're explicitly defining the signedness since the signedness of integer +// bitfields is otherwise implementation-defined and causes warnings on older +// GCC compilers. +struct TypeCode { + // ElementaryType + unsigned short base_type : 4; + // Either vector (in table) or array (in struct) + unsigned short is_repeating : 1; + // Index into type_refs below, or -1 for none. + signed short sequence_ref : 11; +}; + +static_assert(sizeof(TypeCode) == 2, "TypeCode"); + +struct TypeTable; + +// Signature of the static method present in each type. +typedef const TypeTable *(*TypeFunction)(); + +struct TypeTable { + SequenceType st; + size_t num_elems; // of type_codes, values, names (but not type_refs). + const TypeCode *type_codes; // num_elems count + const TypeFunction *type_refs; // less than num_elems entries (see TypeCode). + const int16_t *array_sizes; // less than num_elems entries (see TypeCode). + const int64_t *values; // Only set for non-consecutive enum/union or structs. + const char *const *names; // Only set if compiled with --reflect-names. +}; + +// String which identifies the current version of FlatBuffers. +inline const char *flatbuffers_version_string() { + return "FlatBuffers " FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); +} + +// clang-format off +#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\ + inline E operator | (E lhs, E rhs){\ + return E(T(lhs) | T(rhs));\ + }\ + inline E operator & (E lhs, E rhs){\ + return E(T(lhs) & T(rhs));\ + }\ + inline E operator ^ (E lhs, E rhs){\ + return E(T(lhs) ^ T(rhs));\ + }\ + inline E operator ~ (E lhs){\ + return E(~T(lhs));\ + }\ + inline E operator |= (E &lhs, E rhs){\ + lhs = lhs | rhs;\ + return lhs;\ + }\ + inline E operator &= (E &lhs, E rhs){\ + lhs = lhs & rhs;\ + return lhs;\ + }\ + inline E operator ^= (E &lhs, E rhs){\ + lhs = lhs ^ rhs;\ + return lhs;\ + }\ + inline bool operator !(E rhs) \ + {\ + return !bool(T(rhs)); \ + } +/// @endcond +} // namespace flatbuffers + +// clang-format on + +#endif // FLATBUFFERS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flexbuffers.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flexbuffers.h new file mode 100644 index 000000000..2061c6c09 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/flexbuffers.h @@ -0,0 +1,1903 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_FLEXBUFFERS_H_ +#define FLATBUFFERS_FLEXBUFFERS_H_ + +#include +// Used to select STL variant. +#include "third_party/flatbuffers/include/flatbuffers/base.h" +// We use the basic binary writing functions from the regular FlatBuffers. +#include "third_party/flatbuffers/include/flatbuffers/util.h" + +#ifdef _MSC_VER +# include +#endif + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4127) // C4127: conditional expression is constant +#endif + +namespace flexbuffers { + +class Reference; +class Map; + +// These are used in the lower 2 bits of a type field to determine the size of +// the elements (and or size field) of the item pointed to (e.g. vector). +enum BitWidth { + BIT_WIDTH_8 = 0, + BIT_WIDTH_16 = 1, + BIT_WIDTH_32 = 2, + BIT_WIDTH_64 = 3, +}; + +// These are used as the upper 6 bits of a type field to indicate the actual +// type. +enum Type { + FBT_NULL = 0, + FBT_INT = 1, + FBT_UINT = 2, + FBT_FLOAT = 3, + // Types above stored inline, types below (except FBT_BOOL) store an offset. + FBT_KEY = 4, + FBT_STRING = 5, + FBT_INDIRECT_INT = 6, + FBT_INDIRECT_UINT = 7, + FBT_INDIRECT_FLOAT = 8, + FBT_MAP = 9, + FBT_VECTOR = 10, // Untyped. + FBT_VECTOR_INT = 11, // Typed any size (stores no type table). + FBT_VECTOR_UINT = 12, + FBT_VECTOR_FLOAT = 13, + FBT_VECTOR_KEY = 14, + // DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead. + // Read test.cpp/FlexBuffersDeprecatedTest() for details on why. + FBT_VECTOR_STRING_DEPRECATED = 15, + FBT_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field). + FBT_VECTOR_UINT2 = 17, + FBT_VECTOR_FLOAT2 = 18, + FBT_VECTOR_INT3 = 19, // Typed triple (no type table, no size field). + FBT_VECTOR_UINT3 = 20, + FBT_VECTOR_FLOAT3 = 21, + FBT_VECTOR_INT4 = 22, // Typed quad (no type table, no size field). + FBT_VECTOR_UINT4 = 23, + FBT_VECTOR_FLOAT4 = 24, + FBT_BLOB = 25, + FBT_BOOL = 26, + FBT_VECTOR_BOOL = + 36, // To Allow the same type of conversion of type to vector type + + FBT_MAX_TYPE = 37 +}; + +inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; } + +inline bool IsTypedVectorElementType(Type t) { + return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL; +} + +inline bool IsTypedVector(Type t) { + return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING_DEPRECATED) || + t == FBT_VECTOR_BOOL; +} + +inline bool IsFixedTypedVector(Type t) { + return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4; +} + +inline Type ToTypedVector(Type t, size_t fixed_len = 0) { + FLATBUFFERS_ASSERT(IsTypedVectorElementType(t)); + switch (fixed_len) { + case 0: return static_cast(t - FBT_INT + FBT_VECTOR_INT); + case 2: return static_cast(t - FBT_INT + FBT_VECTOR_INT2); + case 3: return static_cast(t - FBT_INT + FBT_VECTOR_INT3); + case 4: return static_cast(t - FBT_INT + FBT_VECTOR_INT4); + default: FLATBUFFERS_ASSERT(0); return FBT_NULL; + } +} + +inline Type ToTypedVectorElementType(Type t) { + FLATBUFFERS_ASSERT(IsTypedVector(t)); + return static_cast(t - FBT_VECTOR_INT + FBT_INT); +} + +inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) { + FLATBUFFERS_ASSERT(IsFixedTypedVector(t)); + auto fixed_type = t - FBT_VECTOR_INT2; + *len = static_cast(fixed_type / 3 + + 2); // 3 types each, starting from length 2. + return static_cast(fixed_type % 3 + FBT_INT); +} + +// TODO: implement proper support for 8/16bit floats, or decide not to +// support them. +typedef int16_t half; +typedef int8_t quarter; + +// TODO: can we do this without conditionals using intrinsics or inline asm +// on some platforms? Given branch prediction the method below should be +// decently quick, but it is the most frequently executed function. +// We could do an (unaligned) 64-bit read if we ifdef out the platforms for +// which that doesn't work (or where we'd read into un-owned memory). +template +R ReadSizedScalar(const uint8_t *data, uint8_t byte_width) { + return byte_width < 4 + ? (byte_width < 2 + ? static_cast(flatbuffers::ReadScalar(data)) + : static_cast(flatbuffers::ReadScalar(data))) + : (byte_width < 8 + ? static_cast(flatbuffers::ReadScalar(data)) + : static_cast(flatbuffers::ReadScalar(data))); +} + +inline int64_t ReadInt64(const uint8_t *data, uint8_t byte_width) { + return ReadSizedScalar( + data, byte_width); +} + +inline uint64_t ReadUInt64(const uint8_t *data, uint8_t byte_width) { + // This is the "hottest" function (all offset lookups use this), so worth + // optimizing if possible. + // TODO: GCC apparently replaces memcpy by a rep movsb, but only if count is a + // constant, which here it isn't. Test if memcpy is still faster than + // the conditionals in ReadSizedScalar. Can also use inline asm. + + // clang-format off + #if defined(_MSC_VER) && defined(_M_X64) && !defined(_M_ARM64EC) + // This is 64-bit Windows only, __movsb does not work on 32-bit Windows. + uint64_t u = 0; + __movsb(reinterpret_cast(&u), + reinterpret_cast(data), byte_width); + return flatbuffers::EndianScalar(u); + #else + return ReadSizedScalar( + data, byte_width); + #endif + // clang-format on +} + +inline double ReadDouble(const uint8_t *data, uint8_t byte_width) { + return ReadSizedScalar(data, + byte_width); +} + +inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) { + return offset - ReadUInt64(offset, byte_width); +} + +template const uint8_t *Indirect(const uint8_t *offset) { + return offset - flatbuffers::ReadScalar(offset); +} + +inline BitWidth WidthU(uint64_t u) { +#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) \ + { \ + if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \ + } + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 8); + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 16); + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 32); +#undef FLATBUFFERS_GET_FIELD_BIT_WIDTH + return BIT_WIDTH_64; +} + +inline BitWidth WidthI(int64_t i) { + auto u = static_cast(i) << 1; + return WidthU(i >= 0 ? u : ~u); +} + +inline BitWidth WidthF(double f) { + return static_cast(static_cast(f)) == f ? BIT_WIDTH_32 + : BIT_WIDTH_64; +} + +// Base class of all types below. +// Points into the data buffer and allows access to one type. +class Object { + public: + Object(const uint8_t *data, uint8_t byte_width) + : data_(data), byte_width_(byte_width) {} + + protected: + const uint8_t *data_; + uint8_t byte_width_; +}; + +// Object that has a size, obtained either from size prefix, or elsewhere. +class Sized : public Object { + public: + // Size prefix. + Sized(const uint8_t *data, uint8_t byte_width) + : Object(data, byte_width), size_(read_size()) {} + // Manual size. + Sized(const uint8_t *data, uint8_t byte_width, size_t sz) + : Object(data, byte_width), size_(sz) {} + size_t size() const { return size_; } + // Access size stored in `byte_width_` bytes before data_ pointer. + size_t read_size() const { + return static_cast(ReadUInt64(data_ - byte_width_, byte_width_)); + } + + protected: + size_t size_; +}; + +class String : public Sized { + public: + // Size prefix. + String(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {} + // Manual size. + String(const uint8_t *data, uint8_t byte_width, size_t sz) + : Sized(data, byte_width, sz) {} + + size_t length() const { return size(); } + const char *c_str() const { return reinterpret_cast(data_); } + std::string str() const { return std::string(c_str(), size()); } + + static String EmptyString() { + static const char *empty_string = ""; + return String(reinterpret_cast(empty_string), 1, 0); + } + bool IsTheEmptyString() const { return data_ == EmptyString().data_; } +}; + +class Blob : public Sized { + public: + Blob(const uint8_t *data_buf, uint8_t byte_width) + : Sized(data_buf, byte_width) {} + + static Blob EmptyBlob() { + static const uint8_t empty_blob[] = { 0 /*len*/ }; + return Blob(empty_blob + 1, 1); + } + bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; } + const uint8_t *data() const { return data_; } +}; + +class Vector : public Sized { + public: + Vector(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {} + + Reference operator[](size_t i) const; + + static Vector EmptyVector() { + static const uint8_t empty_vector[] = { 0 /*len*/ }; + return Vector(empty_vector + 1, 1); + } + bool IsTheEmptyVector() const { return data_ == EmptyVector().data_; } +}; + +class TypedVector : public Sized { + public: + TypedVector(const uint8_t *data, uint8_t byte_width, Type element_type) + : Sized(data, byte_width), type_(element_type) {} + + Reference operator[](size_t i) const; + + static TypedVector EmptyTypedVector() { + static const uint8_t empty_typed_vector[] = { 0 /*len*/ }; + return TypedVector(empty_typed_vector + 1, 1, FBT_INT); + } + bool IsTheEmptyVector() const { + return data_ == TypedVector::EmptyTypedVector().data_; + } + + Type ElementType() { return type_; } + + friend Reference; + + private: + Type type_; + + friend Map; +}; + +class FixedTypedVector : public Object { + public: + FixedTypedVector(const uint8_t *data, uint8_t byte_width, Type element_type, + uint8_t len) + : Object(data, byte_width), type_(element_type), len_(len) {} + + Reference operator[](size_t i) const; + + static FixedTypedVector EmptyFixedTypedVector() { + static const uint8_t fixed_empty_vector[] = { 0 /* unused */ }; + return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0); + } + bool IsTheEmptyFixedTypedVector() const { + return data_ == FixedTypedVector::EmptyFixedTypedVector().data_; + } + + Type ElementType() const { return type_; } + uint8_t size() const { return len_; } + + private: + Type type_; + uint8_t len_; +}; + +class Map : public Vector { + public: + Map(const uint8_t *data, uint8_t byte_width) : Vector(data, byte_width) {} + + Reference operator[](const char *key) const; + Reference operator[](const std::string &key) const; + + Vector Values() const { return Vector(data_, byte_width_); } + + TypedVector Keys() const { + const size_t num_prefixed_fields = 3; + auto keys_offset = data_ - byte_width_ * num_prefixed_fields; + return TypedVector(Indirect(keys_offset, byte_width_), + static_cast( + ReadUInt64(keys_offset + byte_width_, byte_width_)), + FBT_KEY); + } + + static Map EmptyMap() { + static const uint8_t empty_map[] = { + 0 /*keys_len*/, 0 /*keys_offset*/, 1 /*keys_width*/, 0 /*len*/ + }; + return Map(empty_map + 4, 1); + } + + bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; } +}; + +template +void AppendToString(std::string &s, T &&v, bool keys_quoted) { + s += "[ "; + for (size_t i = 0; i < v.size(); i++) { + if (i) s += ", "; + v[i].ToString(true, keys_quoted, s); + } + s += " ]"; +} + +class Reference { + public: + Reference() + : data_(nullptr), parent_width_(0), byte_width_(0), type_(FBT_NULL) {} + + Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width, + Type type) + : data_(data), + parent_width_(parent_width), + byte_width_(byte_width), + type_(type) {} + + Reference(const uint8_t *data, uint8_t parent_width, uint8_t packed_type) + : data_(data), parent_width_(parent_width) { + byte_width_ = 1U << static_cast(packed_type & 3); + type_ = static_cast(packed_type >> 2); + } + + Type GetType() const { return type_; } + + bool IsNull() const { return type_ == FBT_NULL; } + bool IsBool() const { return type_ == FBT_BOOL; } + bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; } + bool IsUInt() const { + return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT; + } + bool IsIntOrUint() const { return IsInt() || IsUInt(); } + bool IsFloat() const { + return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT; + } + bool IsNumeric() const { return IsIntOrUint() || IsFloat(); } + bool IsString() const { return type_ == FBT_STRING; } + bool IsKey() const { return type_ == FBT_KEY; } + bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; } + bool IsUntypedVector() const { return type_ == FBT_VECTOR; } + bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); } + bool IsFixedTypedVector() const { + return flexbuffers::IsFixedTypedVector(type_); + } + bool IsAnyVector() const { + return (IsTypedVector() || IsFixedTypedVector() || IsVector()); + } + bool IsMap() const { return type_ == FBT_MAP; } + bool IsBlob() const { return type_ == FBT_BLOB; } + bool AsBool() const { + return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_) + : AsUInt64()) != 0; + } + + // Reads any type as a int64_t. Never fails, does most sensible conversion. + // Truncates floats, strings are attempted to be parsed for a number, + // vectors/maps return their size. Returns 0 if all else fails. + int64_t AsInt64() const { + if (type_ == FBT_INT) { + // A fast path for the common case. + return ReadInt64(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_); + case FBT_UINT: return ReadUInt64(data_, parent_width_); + case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_); + case FBT_FLOAT: + return static_cast(ReadDouble(data_, parent_width_)); + case FBT_INDIRECT_FLOAT: + return static_cast(ReadDouble(Indirect(), byte_width_)); + case FBT_NULL: return 0; + case FBT_STRING: return flatbuffers::StringToInt(AsString().c_str()); + case FBT_VECTOR: return static_cast(AsVector().size()); + case FBT_BOOL: return ReadInt64(data_, parent_width_); + default: + // Convert other things to int. + return 0; + } + } + + // TODO: could specialize these to not use AsInt64() if that saves + // extension ops in generated code, and use a faster op than ReadInt64. + int32_t AsInt32() const { return static_cast(AsInt64()); } + int16_t AsInt16() const { return static_cast(AsInt64()); } + int8_t AsInt8() const { return static_cast(AsInt64()); } + + uint64_t AsUInt64() const { + if (type_ == FBT_UINT) { + // A fast path for the common case. + return ReadUInt64(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_); + case FBT_INT: return ReadInt64(data_, parent_width_); + case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_); + case FBT_FLOAT: + return static_cast(ReadDouble(data_, parent_width_)); + case FBT_INDIRECT_FLOAT: + return static_cast(ReadDouble(Indirect(), byte_width_)); + case FBT_NULL: return 0; + case FBT_STRING: return flatbuffers::StringToUInt(AsString().c_str()); + case FBT_VECTOR: return static_cast(AsVector().size()); + case FBT_BOOL: return ReadUInt64(data_, parent_width_); + default: + // Convert other things to uint. + return 0; + } + } + + uint32_t AsUInt32() const { return static_cast(AsUInt64()); } + uint16_t AsUInt16() const { return static_cast(AsUInt64()); } + uint8_t AsUInt8() const { return static_cast(AsUInt64()); } + + double AsDouble() const { + if (type_ == FBT_FLOAT) { + // A fast path for the common case. + return ReadDouble(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_); + case FBT_INT: + return static_cast(ReadInt64(data_, parent_width_)); + case FBT_UINT: + return static_cast(ReadUInt64(data_, parent_width_)); + case FBT_INDIRECT_INT: + return static_cast(ReadInt64(Indirect(), byte_width_)); + case FBT_INDIRECT_UINT: + return static_cast(ReadUInt64(Indirect(), byte_width_)); + case FBT_NULL: return 0.0; + case FBT_STRING: { +#if 1 +#if !defined( _MSC_VER) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnull-dereference" +#endif + // See b/173239141 for additional context. Patched via + // micro/tools/make/flexbuffers_download.sh + // Introduce a segfault for an unsupported code path for TFLM. + return *(static_cast(nullptr)); +#if !defined( _MSC_VER) +#pragma GCC diagnostic pop +#endif +#else + // This is the original code + double d; + flatbuffers::StringToNumber(AsString().c_str(), &d); + return d; +#endif + } + case FBT_VECTOR: return static_cast(AsVector().size()); + case FBT_BOOL: + return static_cast(ReadUInt64(data_, parent_width_)); + default: + // Convert strings and other things to float. + return 0; + } + } + + float AsFloat() const { return static_cast(AsDouble()); } + + const char *AsKey() const { + if (type_ == FBT_KEY || type_ == FBT_STRING) { + return reinterpret_cast(Indirect()); + } else { + return ""; + } + } + + // This function returns the empty string if you try to read something that + // is not a string or key. + String AsString() const { + if (type_ == FBT_STRING) { + return String(Indirect(), byte_width_); + } else if (type_ == FBT_KEY) { + auto key = Indirect(); + return String(key, byte_width_, + strlen(reinterpret_cast(key))); + } else { + return String::EmptyString(); + } + } + + // Unlike AsString(), this will convert any type to a std::string. + std::string ToString() const { + std::string s; + ToString(false, false, s); + return s; + } + + // Convert any type to a JSON-like string. strings_quoted determines if + // string values at the top level receive "" quotes (inside other values + // they always do). keys_quoted determines if keys are quoted, at any level. + // TODO(wvo): add further options to have indentation/newlines. + void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const { + if (type_ == FBT_STRING) { + String _str(Indirect(), byte_width_); + if (strings_quoted) { + flatbuffers::EscapeString(_str.c_str(), _str.length(), &s, true, false); + } else { + s.append(_str.c_str(), _str.length()); + } + } else if (IsKey()) { + auto str = AsKey(); + if (keys_quoted) { + flatbuffers::EscapeString(str, strlen(str), &s, true, false); + } else { + s += str; + } + } else if (IsInt()) { + s += flatbuffers::NumToString(AsInt64()); + } else if (IsUInt()) { + s += flatbuffers::NumToString(AsUInt64()); + } else if (IsFloat()) { + s += flatbuffers::NumToString(AsDouble()); + } else if (IsNull()) { + s += "null"; + } else if (IsBool()) { + s += AsBool() ? "true" : "false"; + } else if (IsMap()) { + s += "{ "; + auto m = AsMap(); + auto keys = m.Keys(); + auto vals = m.Values(); + for (size_t i = 0; i < keys.size(); i++) { + bool kq = keys_quoted; + if (!kq) { + // FlexBuffers keys may contain arbitrary characters, only allow + // unquoted if it looks like an "identifier": + const char *p = keys[i].AsKey(); + if (!flatbuffers::is_alpha(*p) && *p != '_') { + kq = true; + } else { + while (*++p) { + if (!flatbuffers::is_alnum(*p) && *p != '_') { + kq = true; + break; + } + } + } + } + keys[i].ToString(true, kq, s); + s += ": "; + vals[i].ToString(true, keys_quoted, s); + if (i < keys.size() - 1) s += ", "; + } + s += " }"; + } else if (IsVector()) { + AppendToString(s, AsVector(), keys_quoted); + } else if (IsTypedVector()) { + AppendToString(s, AsTypedVector(), keys_quoted); + } else if (IsFixedTypedVector()) { + AppendToString(s, AsFixedTypedVector(), keys_quoted); + } else if (IsBlob()) { + auto blob = AsBlob(); + flatbuffers::EscapeString(reinterpret_cast(blob.data()), + blob.size(), &s, true, false); + } else { + s += "(?)"; + } + } + + // This function returns the empty blob if you try to read a not-blob. + // Strings can be viewed as blobs too. + Blob AsBlob() const { + if (type_ == FBT_BLOB || type_ == FBT_STRING) { + return Blob(Indirect(), byte_width_); + } else { + return Blob::EmptyBlob(); + } + } + + // This function returns the empty vector if you try to read a not-vector. + // Maps can be viewed as vectors too. + Vector AsVector() const { + if (type_ == FBT_VECTOR || type_ == FBT_MAP) { + return Vector(Indirect(), byte_width_); + } else { + return Vector::EmptyVector(); + } + } + + TypedVector AsTypedVector() const { + if (IsTypedVector()) { + auto tv = + TypedVector(Indirect(), byte_width_, ToTypedVectorElementType(type_)); + if (tv.type_ == FBT_STRING) { + // These can't be accessed as strings, since we don't know the bit-width + // of the size field, see the declaration of + // FBT_VECTOR_STRING_DEPRECATED above for details. + // We change the type here to be keys, which are a subtype of strings, + // and will ignore the size field. This will truncate strings with + // embedded nulls. + tv.type_ = FBT_KEY; + } + return tv; + } else { + return TypedVector::EmptyTypedVector(); + } + } + + FixedTypedVector AsFixedTypedVector() const { + if (IsFixedTypedVector()) { + uint8_t len = 0; + auto vtype = ToFixedTypedVectorElementType(type_, &len); + return FixedTypedVector(Indirect(), byte_width_, vtype, len); + } else { + return FixedTypedVector::EmptyFixedTypedVector(); + } + } + + Map AsMap() const { + if (type_ == FBT_MAP) { + return Map(Indirect(), byte_width_); + } else { + return Map::EmptyMap(); + } + } + + template T As() const; + + // Experimental: Mutation functions. + // These allow scalars in an already created buffer to be updated in-place. + // Since by default scalars are stored in the smallest possible space, + // the new value may not fit, in which case these functions return false. + // To avoid this, you can construct the values you intend to mutate using + // Builder::ForceMinimumBitWidth. + bool MutateInt(int64_t i) { + if (type_ == FBT_INT) { + return Mutate(data_, i, parent_width_, WidthI(i)); + } else if (type_ == FBT_INDIRECT_INT) { + return Mutate(Indirect(), i, byte_width_, WidthI(i)); + } else if (type_ == FBT_UINT) { + auto u = static_cast(i); + return Mutate(data_, u, parent_width_, WidthU(u)); + } else if (type_ == FBT_INDIRECT_UINT) { + auto u = static_cast(i); + return Mutate(Indirect(), u, byte_width_, WidthU(u)); + } else { + return false; + } + } + + bool MutateBool(bool b) { + return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8); + } + + bool MutateUInt(uint64_t u) { + if (type_ == FBT_UINT) { + return Mutate(data_, u, parent_width_, WidthU(u)); + } else if (type_ == FBT_INDIRECT_UINT) { + return Mutate(Indirect(), u, byte_width_, WidthU(u)); + } else if (type_ == FBT_INT) { + auto i = static_cast(u); + return Mutate(data_, i, parent_width_, WidthI(i)); + } else if (type_ == FBT_INDIRECT_INT) { + auto i = static_cast(u); + return Mutate(Indirect(), i, byte_width_, WidthI(i)); + } else { + return false; + } + } + + bool MutateFloat(float f) { + if (type_ == FBT_FLOAT) { + return MutateF(data_, f, parent_width_, BIT_WIDTH_32); + } else if (type_ == FBT_INDIRECT_FLOAT) { + return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32); + } else { + return false; + } + } + + bool MutateFloat(double d) { + if (type_ == FBT_FLOAT) { + return MutateF(data_, d, parent_width_, WidthF(d)); + } else if (type_ == FBT_INDIRECT_FLOAT) { + return MutateF(Indirect(), d, byte_width_, WidthF(d)); + } else { + return false; + } + } + + bool MutateString(const char *str, size_t len) { + auto s = AsString(); + if (s.IsTheEmptyString()) return false; + // This is very strict, could allow shorter strings, but that creates + // garbage. + if (s.length() != len) return false; + memcpy(const_cast(s.c_str()), str, len); + return true; + } + bool MutateString(const char *str) { return MutateString(str, strlen(str)); } + bool MutateString(const std::string &str) { + return MutateString(str.data(), str.length()); + } + + private: + const uint8_t *Indirect() const { + return flexbuffers::Indirect(data_, parent_width_); + } + + template + bool Mutate(const uint8_t *dest, T t, size_t byte_width, + BitWidth value_width) { + auto fits = static_cast(static_cast(1U) << value_width) <= + byte_width; + if (fits) { + t = flatbuffers::EndianScalar(t); + memcpy(const_cast(dest), &t, byte_width); + } + return fits; + } + + template + bool MutateF(const uint8_t *dest, T t, size_t byte_width, + BitWidth value_width) { + if (byte_width == sizeof(double)) + return Mutate(dest, static_cast(t), byte_width, value_width); + if (byte_width == sizeof(float)) + return Mutate(dest, static_cast(t), byte_width, value_width); + FLATBUFFERS_ASSERT(false); + return false; + } + + friend class Verifier; + + const uint8_t *data_; + uint8_t parent_width_; + uint8_t byte_width_; + Type type_; +}; + +// Template specialization for As(). +template<> inline bool Reference::As() const { return AsBool(); } + +template<> inline int8_t Reference::As() const { return AsInt8(); } +template<> inline int16_t Reference::As() const { return AsInt16(); } +template<> inline int32_t Reference::As() const { return AsInt32(); } +template<> inline int64_t Reference::As() const { return AsInt64(); } + +template<> inline uint8_t Reference::As() const { return AsUInt8(); } +template<> inline uint16_t Reference::As() const { + return AsUInt16(); +} +template<> inline uint32_t Reference::As() const { + return AsUInt32(); +} +template<> inline uint64_t Reference::As() const { + return AsUInt64(); +} + +template<> inline double Reference::As() const { return AsDouble(); } +template<> inline float Reference::As() const { return AsFloat(); } + +template<> inline String Reference::As() const { return AsString(); } +template<> inline std::string Reference::As() const { + return AsString().str(); +} + +template<> inline Blob Reference::As() const { return AsBlob(); } +template<> inline Vector Reference::As() const { return AsVector(); } +template<> inline TypedVector Reference::As() const { + return AsTypedVector(); +} +template<> inline FixedTypedVector Reference::As() const { + return AsFixedTypedVector(); +} +template<> inline Map Reference::As() const { return AsMap(); } + +inline uint8_t PackedType(BitWidth bit_width, Type type) { + return static_cast(bit_width | (type << 2)); +} + +inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); } + +// Vector accessors. +// Note: if you try to access outside of bounds, you get a Null value back +// instead. Normally this would be an assert, but since this is "dynamically +// typed" data, you may not want that (someone sends you a 2d vector and you +// wanted 3d). +// The Null converts seamlessly into a default value for any other type. +// TODO(wvo): Could introduce an #ifdef that makes this into an assert? +inline Reference Vector::operator[](size_t i) const { + auto len = size(); + if (i >= len) return Reference(nullptr, 1, NullPackedType()); + auto packed_type = (data_ + len * byte_width_)[i]; + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, packed_type); +} + +inline Reference TypedVector::operator[](size_t i) const { + auto len = size(); + if (i >= len) return Reference(nullptr, 1, NullPackedType()); + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, 1, type_); +} + +inline Reference FixedTypedVector::operator[](size_t i) const { + if (i >= len_) return Reference(nullptr, 1, NullPackedType()); + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, 1, type_); +} + +template int KeyCompare(const void *key, const void *elem) { + auto str_elem = reinterpret_cast( + Indirect(reinterpret_cast(elem))); + auto skey = reinterpret_cast(key); + return strcmp(skey, str_elem); +} + +inline Reference Map::operator[](const char *key) const { + auto keys = Keys(); + // We can't pass keys.byte_width_ to the comparison function, so we have + // to pick the right one ahead of time. + int (*comp)(const void *, const void *) = nullptr; + switch (keys.byte_width_) { + case 1: comp = KeyCompare; break; + case 2: comp = KeyCompare; break; + case 4: comp = KeyCompare; break; + case 8: comp = KeyCompare; break; + default: FLATBUFFERS_ASSERT(false); return Reference(); + } + auto res = std::bsearch(key, keys.data_, keys.size(), keys.byte_width_, comp); + if (!res) return Reference(nullptr, 1, NullPackedType()); + auto i = (reinterpret_cast(res) - keys.data_) / keys.byte_width_; + return (*static_cast(this))[i]; +} + +inline Reference Map::operator[](const std::string &key) const { + return (*this)[key.c_str()]; +} + +inline Reference GetRoot(const uint8_t *buffer, size_t size) { + // See Finish() below for the serialization counterpart of this. + // The root starts at the end of the buffer, so we parse backwards from there. + auto end = buffer + size; + auto byte_width = *--end; + auto packed_type = *--end; + end -= byte_width; // The root data item. + return Reference(end, byte_width, packed_type); +} + +inline Reference GetRoot(const std::vector &buffer) { + return GetRoot(buffer.data(), buffer.size()); +} + +// Flags that configure how the Builder behaves. +// The "Share" flags determine if the Builder automatically tries to pool +// this type. Pooling can reduce the size of serialized data if there are +// multiple maps of the same kind, at the expense of slightly slower +// serialization (the cost of lookups) and more memory use (std::set). +// By default this is on for keys, but off for strings. +// Turn keys off if you have e.g. only one map. +// Turn strings on if you expect many non-unique string values. +// Additionally, sharing key vectors can save space if you have maps with +// identical field populations. +enum BuilderFlag { + BUILDER_FLAG_NONE = 0, + BUILDER_FLAG_SHARE_KEYS = 1, + BUILDER_FLAG_SHARE_STRINGS = 2, + BUILDER_FLAG_SHARE_KEYS_AND_STRINGS = 3, + BUILDER_FLAG_SHARE_KEY_VECTORS = 4, + BUILDER_FLAG_SHARE_ALL = 7, +}; + +class Builder FLATBUFFERS_FINAL_CLASS { + public: + Builder(size_t initial_size = 256, + BuilderFlag flags = BUILDER_FLAG_SHARE_KEYS) + : buf_(initial_size), + finished_(false), + has_duplicate_keys_(false), + flags_(flags), + force_min_bit_width_(BIT_WIDTH_8), + key_pool(KeyOffsetCompare(buf_)), + string_pool(StringOffsetCompare(buf_)) { + buf_.clear(); + } + +#ifdef FLATBUFFERS_DEFAULT_DECLARATION + Builder(Builder &&) = default; + Builder &operator=(Builder &&) = default; +#endif + + /// @brief Get the serialized buffer (after you call `Finish()`). + /// @return Returns a vector owned by this class. + const std::vector &GetBuffer() const { + Finished(); + return buf_; + } + + // Size of the buffer. Does not include unfinished values. + size_t GetSize() const { return buf_.size(); } + + // Reset all state so we can re-use the buffer. + void Clear() { + buf_.clear(); + stack_.clear(); + finished_ = false; + // flags_ remains as-is; + force_min_bit_width_ = BIT_WIDTH_8; + key_pool.clear(); + string_pool.clear(); + } + + // All value constructing functions below have two versions: one that + // takes a key (for placement inside a map) and one that doesn't (for inside + // vectors and elsewhere). + + void Null() { stack_.push_back(Value()); } + void Null(const char *key) { + Key(key); + Null(); + } + + void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); } + void Int(const char *key, int64_t i) { + Key(key); + Int(i); + } + + void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); } + void UInt(const char *key, uint64_t u) { + Key(key); + UInt(u); + } + + void Float(float f) { stack_.push_back(Value(f)); } + void Float(const char *key, float f) { + Key(key); + Float(f); + } + + void Double(double f) { stack_.push_back(Value(f)); } + void Double(const char *key, double d) { + Key(key); + Double(d); + } + + void Bool(bool b) { stack_.push_back(Value(b)); } + void Bool(const char *key, bool b) { + Key(key); + Bool(b); + } + + void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); } + void IndirectInt(const char *key, int64_t i) { + Key(key); + IndirectInt(i); + } + + void IndirectUInt(uint64_t u) { + PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u)); + } + void IndirectUInt(const char *key, uint64_t u) { + Key(key); + IndirectUInt(u); + } + + void IndirectFloat(float f) { + PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32); + } + void IndirectFloat(const char *key, float f) { + Key(key); + IndirectFloat(f); + } + + void IndirectDouble(double f) { + PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f)); + } + void IndirectDouble(const char *key, double d) { + Key(key); + IndirectDouble(d); + } + + size_t Key(const char *str, size_t len) { + auto sloc = buf_.size(); + WriteBytes(str, len + 1); + if (flags_ & BUILDER_FLAG_SHARE_KEYS) { + auto it = key_pool.find(sloc); + if (it != key_pool.end()) { + // Already in the buffer. Remove key we just serialized, and use + // existing offset instead. + buf_.resize(sloc); + sloc = *it; + } else { + key_pool.insert(sloc); + } + } + stack_.push_back(Value(static_cast(sloc), FBT_KEY, BIT_WIDTH_8)); + return sloc; + } + + size_t Key(const char *str) { return Key(str, strlen(str)); } + size_t Key(const std::string &str) { return Key(str.c_str(), str.size()); } + + size_t String(const char *str, size_t len) { + auto reset_to = buf_.size(); + auto sloc = CreateBlob(str, len, 1, FBT_STRING); + if (flags_ & BUILDER_FLAG_SHARE_STRINGS) { + StringOffset so(sloc, len); + auto it = string_pool.find(so); + if (it != string_pool.end()) { + // Already in the buffer. Remove string we just serialized, and use + // existing offset instead. + buf_.resize(reset_to); + sloc = it->first; + stack_.back().u_ = sloc; + } else { + string_pool.insert(so); + } + } + return sloc; + } + size_t String(const char *str) { return String(str, strlen(str)); } + size_t String(const std::string &str) { + return String(str.c_str(), str.size()); + } + void String(const flexbuffers::String &str) { + String(str.c_str(), str.length()); + } + + void String(const char *key, const char *str) { + Key(key); + String(str); + } + void String(const char *key, const std::string &str) { + Key(key); + String(str); + } + void String(const char *key, const flexbuffers::String &str) { + Key(key); + String(str); + } + + size_t Blob(const void *data, size_t len) { + return CreateBlob(data, len, 0, FBT_BLOB); + } + size_t Blob(const std::vector &v) { + return CreateBlob(v.data(), v.size(), 0, FBT_BLOB); + } + + void Blob(const char *key, const void *data, size_t len) { + Key(key); + Blob(data, len); + } + void Blob(const char *key, const std::vector &v) { + Key(key); + Blob(v); + } + + // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String), + // e.g. Vector etc. Also in overloaded versions. + // Also some FlatBuffers types? + + size_t StartVector() { return stack_.size(); } + size_t StartVector(const char *key) { + Key(key); + return stack_.size(); + } + size_t StartMap() { return stack_.size(); } + size_t StartMap(const char *key) { + Key(key); + return stack_.size(); + } + + // TODO(wvo): allow this to specify an alignment greater than the natural + // alignment. + size_t EndVector(size_t start, bool typed, bool fixed) { + auto vec = CreateVector(start, stack_.size() - start, 1, typed, fixed); + // Remove temp elements and return vector. + stack_.resize(start); + stack_.push_back(vec); + return static_cast(vec.u_); + } + + size_t EndMap(size_t start) { + // We should have interleaved keys and values on the stack. + // Make sure it is an even number: + auto len = stack_.size() - start; + FLATBUFFERS_ASSERT(!(len & 1)); + len /= 2; + // Make sure keys are all strings: + for (auto key = start; key < stack_.size(); key += 2) { + FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY); + } + // Now sort values, so later we can do a binary search lookup. + // We want to sort 2 array elements at a time. + struct TwoValue { + Value key; + Value val; + }; + // TODO(wvo): strict aliasing? + // TODO(wvo): allow the caller to indicate the data is already sorted + // for maximum efficiency? With an assert to check sortedness to make sure + // we're not breaking binary search. + // Or, we can track if the map is sorted as keys are added which would be + // be quite cheap (cheaper than checking it here), so we can skip this + // step automatically when appliccable, and encourage people to write in + // sorted fashion. + // std::sort is typically already a lot faster on sorted data though. + auto dict = reinterpret_cast(stack_.data() + start); + std::sort( + dict, dict + len, [&](const TwoValue &a, const TwoValue &b) -> bool { + auto as = reinterpret_cast(buf_.data() + a.key.u_); + auto bs = reinterpret_cast(buf_.data() + b.key.u_); + auto comp = strcmp(as, bs); + // We want to disallow duplicate keys, since this results in a + // map where values cannot be found. + // But we can't assert here (since we don't want to fail on + // random JSON input) or have an error mechanism. + // Instead, we set has_duplicate_keys_ in the builder to + // signal this. + // TODO: Have to check for pointer equality, as some sort + // implementation apparently call this function with the same + // element?? Why? + if (!comp && &a != &b) has_duplicate_keys_ = true; + return comp < 0; + }); + // First create a vector out of all keys. + // TODO(wvo): if kBuilderFlagShareKeyVectors is true, see if we can share + // the first vector. + auto keys = CreateVector(start, len, 2, true, false); + auto vec = CreateVector(start + 1, len, 2, false, false, &keys); + // Remove temp elements and return map. + stack_.resize(start); + stack_.push_back(vec); + return static_cast(vec.u_); + } + + // Call this after EndMap to see if the map had any duplicate keys. + // Any map with such keys won't be able to retrieve all values. + bool HasDuplicateKeys() const { return has_duplicate_keys_; } + + template size_t Vector(F f) { + auto start = StartVector(); + f(); + return EndVector(start, false, false); + } + template size_t Vector(F f, T &state) { + auto start = StartVector(); + f(state); + return EndVector(start, false, false); + } + template size_t Vector(const char *key, F f) { + auto start = StartVector(key); + f(); + return EndVector(start, false, false); + } + template + size_t Vector(const char *key, F f, T &state) { + auto start = StartVector(key); + f(state); + return EndVector(start, false, false); + } + + template void Vector(const T *elems, size_t len) { + if (flatbuffers::is_scalar::value) { + // This path should be a lot quicker and use less space. + ScalarVector(elems, len, false); + } else { + auto start = StartVector(); + for (size_t i = 0; i < len; i++) Add(elems[i]); + EndVector(start, false, false); + } + } + template + void Vector(const char *key, const T *elems, size_t len) { + Key(key); + Vector(elems, len); + } + template void Vector(const std::vector &vec) { + Vector(vec.data(), vec.size()); + } + + template size_t TypedVector(F f) { + auto start = StartVector(); + f(); + return EndVector(start, true, false); + } + template size_t TypedVector(F f, T &state) { + auto start = StartVector(); + f(state); + return EndVector(start, true, false); + } + template size_t TypedVector(const char *key, F f) { + auto start = StartVector(key); + f(); + return EndVector(start, true, false); + } + template + size_t TypedVector(const char *key, F f, T &state) { + auto start = StartVector(key); + f(state); + return EndVector(start, true, false); + } + + template size_t FixedTypedVector(const T *elems, size_t len) { + // We only support a few fixed vector lengths. Anything bigger use a + // regular typed vector. + FLATBUFFERS_ASSERT(len >= 2 && len <= 4); + // And only scalar values. + static_assert(flatbuffers::is_scalar::value, "Unrelated types"); + return ScalarVector(elems, len, true); + } + + template + size_t FixedTypedVector(const char *key, const T *elems, size_t len) { + Key(key); + return FixedTypedVector(elems, len); + } + + template size_t Map(F f) { + auto start = StartMap(); + f(); + return EndMap(start); + } + template size_t Map(F f, T &state) { + auto start = StartMap(); + f(state); + return EndMap(start); + } + template size_t Map(const char *key, F f) { + auto start = StartMap(key); + f(); + return EndMap(start); + } + template size_t Map(const char *key, F f, T &state) { + auto start = StartMap(key); + f(state); + return EndMap(start); + } + template void Map(const std::map &map) { + auto start = StartMap(); + for (auto it = map.begin(); it != map.end(); ++it) + Add(it->first.c_str(), it->second); + EndMap(start); + } + + // If you wish to share a value explicitly (a value not shared automatically + // through one of the BUILDER_FLAG_SHARE_* flags) you can do so with these + // functions. Or if you wish to turn those flags off for performance reasons + // and still do some explicit sharing. For example: + // builder.IndirectDouble(M_PI); + // auto id = builder.LastValue(); // Remember where we stored it. + // .. more code goes here .. + // builder.ReuseValue(id); // Refers to same double by offset. + // LastValue works regardless of whether the value has a key or not. + // Works on any data type. + struct Value; + Value LastValue() { return stack_.back(); } + void ReuseValue(Value v) { stack_.push_back(v); } + void ReuseValue(const char *key, Value v) { + Key(key); + ReuseValue(v); + } + + // Overloaded Add that tries to call the correct function above. + void Add(int8_t i) { Int(i); } + void Add(int16_t i) { Int(i); } + void Add(int32_t i) { Int(i); } + void Add(int64_t i) { Int(i); } + void Add(uint8_t u) { UInt(u); } + void Add(uint16_t u) { UInt(u); } + void Add(uint32_t u) { UInt(u); } + void Add(uint64_t u) { UInt(u); } + void Add(float f) { Float(f); } + void Add(double d) { Double(d); } + void Add(bool b) { Bool(b); } + void Add(const char *str) { String(str); } + void Add(const std::string &str) { String(str); } + void Add(const flexbuffers::String &str) { String(str); } + + template void Add(const std::vector &vec) { Vector(vec); } + + template void Add(const char *key, const T &t) { + Key(key); + Add(t); + } + + template void Add(const std::map &map) { + Map(map); + } + + template void operator+=(const T &t) { Add(t); } + + // This function is useful in combination with the Mutate* functions above. + // It forces elements of vectors and maps to have a minimum size, such that + // they can later be updated without failing. + // Call with no arguments to reset. + void ForceMinimumBitWidth(BitWidth bw = BIT_WIDTH_8) { + force_min_bit_width_ = bw; + } + + void Finish() { + // If you hit this assert, you likely have objects that were never included + // in a parent. You need to have exactly one root to finish a buffer. + // Check your Start/End calls are matched, and all objects are inside + // some other object. + FLATBUFFERS_ASSERT(stack_.size() == 1); + + // Write root value. + auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0)); + WriteAny(stack_[0], byte_width); + // Write root type. + Write(stack_[0].StoredPackedType(), 1); + // Write root size. Normally determined by parent, but root has no parent :) + Write(byte_width, 1); + + finished_ = true; + } + + private: + void Finished() const { + // If you get this assert, you're attempting to get access a buffer + // which hasn't been finished yet. Be sure to call + // Builder::Finish with your root object. + FLATBUFFERS_ASSERT(finished_); + } + + // Align to prepare for writing a scalar with a certain size. + uint8_t Align(BitWidth alignment) { + auto byte_width = 1U << alignment; + buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width), + 0); + return static_cast(byte_width); + } + + void WriteBytes(const void *val, size_t size) { + buf_.insert(buf_.end(), reinterpret_cast(val), + reinterpret_cast(val) + size); + } + + template void Write(T val, size_t byte_width) { + FLATBUFFERS_ASSERT(sizeof(T) >= byte_width); + val = flatbuffers::EndianScalar(val); + WriteBytes(&val, byte_width); + } + + void WriteDouble(double f, uint8_t byte_width) { + switch (byte_width) { + case 8: Write(f, byte_width); break; + case 4: Write(static_cast(f), byte_width); break; + // case 2: Write(static_cast(f), byte_width); break; + // case 1: Write(static_cast(f), byte_width); break; + default: FLATBUFFERS_ASSERT(0); + } + } + + void WriteOffset(uint64_t o, uint8_t byte_width) { + auto reloff = buf_.size() - o; + FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8)); + Write(reloff, byte_width); + } + + template void PushIndirect(T val, Type type, BitWidth bit_width) { + auto byte_width = Align(bit_width); + auto iloc = buf_.size(); + Write(val, byte_width); + stack_.push_back(Value(static_cast(iloc), type, bit_width)); + } + + static BitWidth WidthB(size_t byte_width) { + switch (byte_width) { + case 1: return BIT_WIDTH_8; + case 2: return BIT_WIDTH_16; + case 4: return BIT_WIDTH_32; + case 8: return BIT_WIDTH_64; + default: FLATBUFFERS_ASSERT(false); return BIT_WIDTH_64; + } + } + + template static Type GetScalarType() { + static_assert(flatbuffers::is_scalar::value, "Unrelated types"); + return flatbuffers::is_floating_point::value + ? FBT_FLOAT + : flatbuffers::is_same::value + ? FBT_BOOL + : (flatbuffers::is_unsigned::value ? FBT_UINT + : FBT_INT); + } + + public: + // This was really intended to be private, except for LastValue/ReuseValue. + struct Value { + union { + int64_t i_; + uint64_t u_; + double f_; + }; + + Type type_; + + // For scalars: of itself, for vector: of its elements, for string: length. + BitWidth min_bit_width_; + + Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {} + + Value(bool b) + : u_(static_cast(b)), + type_(FBT_BOOL), + min_bit_width_(BIT_WIDTH_8) {} + + Value(int64_t i, Type t, BitWidth bw) + : i_(i), type_(t), min_bit_width_(bw) {} + Value(uint64_t u, Type t, BitWidth bw) + : u_(u), type_(t), min_bit_width_(bw) {} + + Value(float f) + : f_(static_cast(f)), + type_(FBT_FLOAT), + min_bit_width_(BIT_WIDTH_32) {} + Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {} + + uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const { + return PackedType(StoredWidth(parent_bit_width_), type_); + } + + BitWidth ElemWidth(size_t buf_size, size_t elem_index) const { + if (IsInline(type_)) { + return min_bit_width_; + } else { + // We have an absolute offset, but want to store a relative offset + // elem_index elements beyond the current buffer end. Since whether + // the relative offset fits in a certain byte_width depends on + // the size of the elements before it (and their alignment), we have + // to test for each size in turn. + for (size_t byte_width = 1; + byte_width <= sizeof(flatbuffers::largest_scalar_t); + byte_width *= 2) { + // Where are we going to write this offset? + auto offset_loc = buf_size + + flatbuffers::PaddingBytes(buf_size, byte_width) + + elem_index * byte_width; + // Compute relative offset. + auto offset = offset_loc - u_; + // Does it fit? + auto bit_width = WidthU(offset); + if (static_cast(static_cast(1U) << bit_width) == + byte_width) + return bit_width; + } + FLATBUFFERS_ASSERT(false); // Must match one of the sizes above. + return BIT_WIDTH_64; + } + } + + BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const { + if (IsInline(type_)) { + return (std::max)(min_bit_width_, parent_bit_width_); + } else { + return min_bit_width_; + } + } + }; + + private: + void WriteAny(const Value &val, uint8_t byte_width) { + switch (val.type_) { + case FBT_NULL: + case FBT_INT: Write(val.i_, byte_width); break; + case FBT_BOOL: + case FBT_UINT: Write(val.u_, byte_width); break; + case FBT_FLOAT: WriteDouble(val.f_, byte_width); break; + default: WriteOffset(val.u_, byte_width); break; + } + } + + size_t CreateBlob(const void *data, size_t len, size_t trailing, Type type) { + auto bit_width = WidthU(len); + auto byte_width = Align(bit_width); + Write(len, byte_width); + auto sloc = buf_.size(); + WriteBytes(data, len + trailing); + stack_.push_back(Value(static_cast(sloc), type, bit_width)); + return sloc; + } + + template + size_t ScalarVector(const T *elems, size_t len, bool fixed) { + auto vector_type = GetScalarType(); + auto byte_width = sizeof(T); + auto bit_width = WidthB(byte_width); + // If you get this assert, you're trying to write a vector with a size + // field that is bigger than the scalars you're trying to write (e.g. a + // byte vector > 255 elements). For such types, write a "blob" instead. + // TODO: instead of asserting, could write vector with larger elements + // instead, though that would be wasteful. + FLATBUFFERS_ASSERT(WidthU(len) <= bit_width); + Align(bit_width); + if (!fixed) Write(len, byte_width); + auto vloc = buf_.size(); + for (size_t i = 0; i < len; i++) Write(elems[i], byte_width); + stack_.push_back(Value(static_cast(vloc), + ToTypedVector(vector_type, fixed ? len : 0), + bit_width)); + return vloc; + } + + Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed, + bool fixed, const Value *keys = nullptr) { + FLATBUFFERS_ASSERT( + !fixed || + typed); // typed=false, fixed=true combination is not supported. + // Figure out smallest bit width we can store this vector with. + auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len)); + auto prefix_elems = 1; + if (keys) { + // If this vector is part of a map, we will pre-fix an offset to the keys + // to this vector. + bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0)); + prefix_elems += 2; + } + Type vector_type = FBT_KEY; + // Check bit widths and types for all elements. + for (size_t i = start; i < stack_.size(); i += step) { + auto elem_width = + stack_[i].ElemWidth(buf_.size(), i - start + prefix_elems); + bit_width = (std::max)(bit_width, elem_width); + if (typed) { + if (i == start) { + vector_type = stack_[i].type_; + } else { + // If you get this assert, you are writing a typed vector with + // elements that are not all the same type. + FLATBUFFERS_ASSERT(vector_type == stack_[i].type_); + } + } + } + // If you get this assert, your typed types are not one of: + // Int / UInt / Float / Key. + FLATBUFFERS_ASSERT(!typed || IsTypedVectorElementType(vector_type)); + auto byte_width = Align(bit_width); + // Write vector. First the keys width/offset if available, and size. + if (keys) { + WriteOffset(keys->u_, byte_width); + Write(1ULL << keys->min_bit_width_, byte_width); + } + if (!fixed) Write(vec_len, byte_width); + // Then the actual data. + auto vloc = buf_.size(); + for (size_t i = start; i < stack_.size(); i += step) { + WriteAny(stack_[i], byte_width); + } + // Then the types. + if (!typed) { + for (size_t i = start; i < stack_.size(); i += step) { + buf_.push_back(stack_[i].StoredPackedType(bit_width)); + } + } + return Value(static_cast(vloc), + keys ? FBT_MAP + : (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0) + : FBT_VECTOR), + bit_width); + } + + // You shouldn't really be copying instances of this class. + Builder(const Builder &); + Builder &operator=(const Builder &); + + std::vector buf_; + std::vector stack_; + + bool finished_; + bool has_duplicate_keys_; + + BuilderFlag flags_; + + BitWidth force_min_bit_width_; + + struct KeyOffsetCompare { + explicit KeyOffsetCompare(const std::vector &buf) : buf_(&buf) {} + bool operator()(size_t a, size_t b) const { + auto stra = reinterpret_cast(buf_->data() + a); + auto strb = reinterpret_cast(buf_->data() + b); + return strcmp(stra, strb) < 0; + } + const std::vector *buf_; + }; + + typedef std::pair StringOffset; + struct StringOffsetCompare { + explicit StringOffsetCompare(const std::vector &buf) + : buf_(&buf) {} + bool operator()(const StringOffset &a, const StringOffset &b) const { + auto stra = buf_->data() + a.first; + auto strb = buf_->data() + b.first; + auto cr = memcmp(stra, strb, (std::min)(a.second, b.second) + 1); + return cr < 0 || (cr == 0 && a.second < b.second); + } + const std::vector *buf_; + }; + + typedef std::set KeyOffsetMap; + typedef std::set StringOffsetMap; + + KeyOffsetMap key_pool; + StringOffsetMap string_pool; + + friend class Verifier; +}; + +// Helper class to verify the integrity of a FlexBuffer +class Verifier FLATBUFFERS_FINAL_CLASS { + public: + Verifier(const uint8_t *buf, size_t buf_len, + // Supplying this vector likely results in faster verification + // of larger buffers with many shared keys/strings, but + // comes at the cost of using additional memory the same size of + // the buffer being verified, so it is by default off. + std::vector *reuse_tracker = nullptr, + bool _check_alignment = true, size_t max_depth = 64) + : buf_(buf), + size_(buf_len), + depth_(0), + max_depth_(max_depth), + num_vectors_(0), + max_vectors_(buf_len), + check_alignment_(_check_alignment), + reuse_tracker_(reuse_tracker) { + FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE); + if (reuse_tracker_) { + reuse_tracker_->clear(); + reuse_tracker_->resize(size_, PackedType(BIT_WIDTH_8, FBT_NULL)); + } + } + + private: + // Central location where any verification failures register. + bool Check(bool ok) const { + // clang-format off + #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE + FLATBUFFERS_ASSERT(ok); + #endif + // clang-format on + return ok; + } + + // Verify any range within the buffer. + bool VerifyFrom(size_t elem, size_t elem_len) const { + return Check(elem_len < size_ && elem <= size_ - elem_len); + } + bool VerifyBefore(size_t elem, size_t elem_len) const { + return Check(elem_len <= elem); + } + + bool VerifyFromPointer(const uint8_t *p, size_t len) { + auto o = static_cast(p - buf_); + return VerifyFrom(o, len); + } + bool VerifyBeforePointer(const uint8_t *p, size_t len) { + auto o = static_cast(p - buf_); + return VerifyBefore(o, len); + } + + bool VerifyByteWidth(size_t width) { + return Check(width == 1 || width == 2 || width == 4 || width == 8); + } + + bool VerifyType(int type) { return Check(type >= 0 && type < FBT_MAX_TYPE); } + + bool VerifyOffset(uint64_t off, const uint8_t *p) { + return Check(off <= static_cast(size_)) && + off <= static_cast(p - buf_); + } + + bool VerifyAlignment(const uint8_t *p, size_t size) const { + auto o = static_cast(p - buf_); + return Check((o & (size - 1)) == 0 || !check_alignment_); + } + +// Macro, since we want to escape from parent function & use lazy args. +#define FLEX_CHECK_VERIFIED(P, PACKED_TYPE) \ + if (reuse_tracker_) { \ + auto packed_type = PACKED_TYPE; \ + auto existing = (*reuse_tracker_)[P - buf_]; \ + if (existing == packed_type) return true; \ + /* Fail verification if already set with different type! */ \ + if (!Check(existing == 0)) return false; \ + (*reuse_tracker_)[P - buf_] = packed_type; \ + } + + bool VerifyVector(Reference r, const uint8_t *p, Type elem_type) { + // Any kind of nesting goes thru this function, so guard against that + // here, both with simple nesting checks, and the reuse tracker if on. + depth_++; + num_vectors_++; + if (!Check(depth_ <= max_depth_ && num_vectors_ <= max_vectors_)) + return false; + auto size_byte_width = r.byte_width_; + if (!VerifyBeforePointer(p, size_byte_width)) return false; + FLEX_CHECK_VERIFIED(p - size_byte_width, + PackedType(Builder::WidthB(size_byte_width), r.type_)); + auto sized = Sized(p, size_byte_width); + auto num_elems = sized.size(); + auto elem_byte_width = r.type_ == FBT_STRING || r.type_ == FBT_BLOB + ? uint8_t(1) + : r.byte_width_; + auto max_elems = SIZE_MAX / elem_byte_width; + if (!Check(num_elems < max_elems)) + return false; // Protect against byte_size overflowing. + auto byte_size = num_elems * elem_byte_width; + if (!VerifyFromPointer(p, byte_size)) return false; + if (elem_type == FBT_NULL) { + // Verify type bytes after the vector. + if (!VerifyFromPointer(p + byte_size, num_elems)) return false; + auto v = Vector(p, size_byte_width); + for (size_t i = 0; i < num_elems; i++) + if (!VerifyRef(v[i])) return false; + } else if (elem_type == FBT_KEY) { + auto v = TypedVector(p, elem_byte_width, FBT_KEY); + for (size_t i = 0; i < num_elems; i++) + if (!VerifyRef(v[i])) return false; + } else { + FLATBUFFERS_ASSERT(IsInline(elem_type)); + } + depth_--; + return true; + } + + bool VerifyKeys(const uint8_t *p, uint8_t byte_width) { + // The vector part of the map has already been verified. + const size_t num_prefixed_fields = 3; + if (!VerifyBeforePointer(p, byte_width * num_prefixed_fields)) return false; + p -= byte_width * num_prefixed_fields; + auto off = ReadUInt64(p, byte_width); + if (!VerifyOffset(off, p)) return false; + auto key_byte_with = + static_cast(ReadUInt64(p + byte_width, byte_width)); + if (!VerifyByteWidth(key_byte_with)) return false; + return VerifyVector(Reference(p, byte_width, key_byte_with, FBT_VECTOR_KEY), + p - off, FBT_KEY); + } + + bool VerifyKey(const uint8_t *p) { + FLEX_CHECK_VERIFIED(p, PackedType(BIT_WIDTH_8, FBT_KEY)); + while (p < buf_ + size_) + if (*p++) return true; + return false; + } + +#undef FLEX_CHECK_VERIFIED + + bool VerifyTerminator(const String &s) { + return VerifyFromPointer(reinterpret_cast(s.c_str()), + s.size() + 1); + } + + bool VerifyRef(Reference r) { + // r.parent_width_ and r.data_ already verified. + if (!VerifyByteWidth(r.byte_width_) || !VerifyType(r.type_)) { + return false; + } + if (IsInline(r.type_)) { + // Inline scalars, don't require further verification. + return true; + } + // All remaining types are an offset. + auto off = ReadUInt64(r.data_, r.parent_width_); + if (!VerifyOffset(off, r.data_)) return false; + auto p = r.Indirect(); + if (!VerifyAlignment(p, r.byte_width_)) return false; + switch (r.type_) { + case FBT_INDIRECT_INT: + case FBT_INDIRECT_UINT: + case FBT_INDIRECT_FLOAT: return VerifyFromPointer(p, r.byte_width_); + case FBT_KEY: return VerifyKey(p); + case FBT_MAP: + return VerifyVector(r, p, FBT_NULL) && VerifyKeys(p, r.byte_width_); + case FBT_VECTOR: return VerifyVector(r, p, FBT_NULL); + case FBT_VECTOR_INT: return VerifyVector(r, p, FBT_INT); + case FBT_VECTOR_BOOL: + case FBT_VECTOR_UINT: return VerifyVector(r, p, FBT_UINT); + case FBT_VECTOR_FLOAT: return VerifyVector(r, p, FBT_FLOAT); + case FBT_VECTOR_KEY: return VerifyVector(r, p, FBT_KEY); + case FBT_VECTOR_STRING_DEPRECATED: + // Use of FBT_KEY here intentional, see elsewhere. + return VerifyVector(r, p, FBT_KEY); + case FBT_BLOB: return VerifyVector(r, p, FBT_UINT); + case FBT_STRING: + return VerifyVector(r, p, FBT_UINT) && + VerifyTerminator(String(p, r.byte_width_)); + case FBT_VECTOR_INT2: + case FBT_VECTOR_UINT2: + case FBT_VECTOR_FLOAT2: + case FBT_VECTOR_INT3: + case FBT_VECTOR_UINT3: + case FBT_VECTOR_FLOAT3: + case FBT_VECTOR_INT4: + case FBT_VECTOR_UINT4: + case FBT_VECTOR_FLOAT4: { + uint8_t len = 0; + auto vtype = ToFixedTypedVectorElementType(r.type_, &len); + if (!VerifyType(vtype)) return false; + return VerifyFromPointer(p, r.byte_width_ * len); + } + default: return false; + } + } + + public: + bool VerifyBuffer() { + if (!Check(size_ >= 3)) return false; + auto end = buf_ + size_; + auto byte_width = *--end; + auto packed_type = *--end; + return VerifyByteWidth(byte_width) && Check(end - buf_ >= byte_width) && + VerifyRef(Reference(end - byte_width, byte_width, packed_type)); + } + + private: + const uint8_t *buf_; + size_t size_; + size_t depth_; + const size_t max_depth_; + size_t num_vectors_; + const size_t max_vectors_; + bool check_alignment_; + std::vector *reuse_tracker_; +}; + +// Utility function that contructs the Verifier for you, see above for +// parameters. +inline bool VerifyBuffer(const uint8_t *buf, size_t buf_len, + std::vector *reuse_tracker = nullptr) { + Verifier verifier(buf, buf_len, reuse_tracker); + return verifier.VerifyBuffer(); +} + +} // namespace flexbuffers + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // FLATBUFFERS_FLEXBUFFERS_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/stl_emulation.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/stl_emulation.h new file mode 100644 index 000000000..0b91f0d78 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/stl_emulation.h @@ -0,0 +1,509 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_STL_EMULATION_H_ +#define FLATBUFFERS_STL_EMULATION_H_ + +// clang-format off +#include "third_party/flatbuffers/include/flatbuffers/base.h" + +#include +#include +#include +#include +#include + +#ifndef FLATBUFFERS_USE_STD_OPTIONAL + // Detect C++17 compatible compiler. + // __cplusplus >= 201703L - a compiler has support of 'static inline' variables. + #if (defined(__cplusplus) && __cplusplus >= 201703L) \ + || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) + #define FLATBUFFERS_USE_STD_OPTIONAL 1 + #else + #define FLATBUFFERS_USE_STD_OPTIONAL 0 + #endif // (defined(__cplusplus) && __cplusplus >= 201703L) ... +#endif // FLATBUFFERS_USE_STD_OPTIONAL + +#if FLATBUFFERS_USE_STD_OPTIONAL + #include +#endif + +// The __cpp_lib_span is the predefined feature macro. +#if defined(FLATBUFFERS_USE_STD_SPAN) + #include +#elif defined(__cpp_lib_span) && defined(__has_include) + #if __has_include() + #include + #define FLATBUFFERS_USE_STD_SPAN + #endif +#else + // Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined. + #if !defined(FLATBUFFERS_TEMPLATES_ALIASES) + #define FLATBUFFERS_SPAN_MINIMAL + #else + // Enable implicit construction of a span from a std::array. + #include + #endif +#endif // defined(FLATBUFFERS_USE_STD_SPAN) + +// This header provides backwards compatibility for older versions of the STL. +namespace flatbuffers { + +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) + template + using numeric_limits = std::numeric_limits; +#else + template class numeric_limits : + public std::numeric_limits {}; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) + +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) + template using is_scalar = std::is_scalar; + template using is_same = std::is_same; + template using is_floating_point = std::is_floating_point; + template using is_unsigned = std::is_unsigned; + template using is_enum = std::is_enum; + template using make_unsigned = std::make_unsigned; + template + using conditional = std::conditional; + template + using integral_constant = std::integral_constant; + template + using bool_constant = integral_constant; + using true_type = std::true_type; + using false_type = std::false_type; +#else + // MSVC 2010 doesn't support C++11 aliases. + template struct is_scalar : public std::is_scalar {}; + template struct is_same : public std::is_same {}; + template struct is_floating_point : + public std::is_floating_point {}; + template struct is_unsigned : public std::is_unsigned {}; + template struct is_enum : public std::is_enum {}; + template struct make_unsigned : public std::make_unsigned {}; + template + struct conditional : public std::conditional {}; + template + struct integral_constant : public std::integral_constant {}; + template + struct bool_constant : public integral_constant {}; + typedef bool_constant true_type; + typedef bool_constant false_type; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) + +#if defined(FLATBUFFERS_TEMPLATES_ALIASES) + template using unique_ptr = std::unique_ptr; +#else + // MSVC 2010 doesn't support C++11 aliases. + // We're manually "aliasing" the class here as we want to bring unique_ptr + // into the flatbuffers namespace. We have unique_ptr in the flatbuffers + // namespace we have a completely independent implementation (see below) + // for C++98 STL implementations. + template class unique_ptr : public std::unique_ptr { + public: + unique_ptr() {} + explicit unique_ptr(T* p) : std::unique_ptr(p) {} + unique_ptr(std::unique_ptr&& u) { *this = std::move(u); } + unique_ptr(unique_ptr&& u) { *this = std::move(u); } + unique_ptr& operator=(std::unique_ptr&& u) { + std::unique_ptr::reset(u.release()); + return *this; + } + unique_ptr& operator=(unique_ptr&& u) { + std::unique_ptr::reset(u.release()); + return *this; + } + unique_ptr& operator=(T* p) { + return std::unique_ptr::operator=(p); + } + }; +#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) + +#if FLATBUFFERS_USE_STD_OPTIONAL +template +using Optional = std::optional; +using nullopt_t = std::nullopt_t; +inline constexpr nullopt_t nullopt = std::nullopt; + +#else +// Limited implementation of Optional type for a scalar T. +// This implementation limited by trivial types compatible with +// std::is_arithmetic or std::is_enum type traits. + +// A tag to indicate an empty flatbuffers::optional. +struct nullopt_t { + explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {} +}; + +#if defined(FLATBUFFERS_CONSTEXPR_DEFINED) + namespace internal { + template struct nullopt_holder { + static constexpr nullopt_t instance_ = nullopt_t(0); + }; + template + constexpr nullopt_t nullopt_holder::instance_; + } + static constexpr const nullopt_t &nullopt = internal::nullopt_holder::instance_; + +#else + namespace internal { + template struct nullopt_holder { + static const nullopt_t instance_; + }; + template + const nullopt_t nullopt_holder::instance_ = nullopt_t(0); + } + static const nullopt_t &nullopt = internal::nullopt_holder::instance_; + +#endif + +template +class Optional FLATBUFFERS_FINAL_CLASS { + // Non-scalar 'T' would extremely complicated Optional. + // Use is_scalar checking because flatbuffers flatbuffers::is_arithmetic + // isn't implemented. + static_assert(flatbuffers::is_scalar::value, "unexpected type T"); + + public: + ~Optional() {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT + : value_(), has_value_(false) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT + : value_(), has_value_(false) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT + : value_(val), has_value_(true) {} + + FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT + : value_(other.value_), has_value_(other.has_value_) {} + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT { + value_ = other.value_; + has_value_ = other.has_value_; + return *this; + } + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT { + value_ = T(); + has_value_ = false; + return *this; + } + + FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT { + value_ = val; + has_value_ = true; + return *this; + } + + void reset() FLATBUFFERS_NOEXCEPT { + *this = nullopt; + } + + void swap(Optional &other) FLATBUFFERS_NOEXCEPT { + std::swap(value_, other.value_); + std::swap(has_value_, other.has_value_); + } + + FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT { + return has_value_; + } + + FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT { + return has_value_; + } + + FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT { + return value_; + } + + const T& value() const { + FLATBUFFERS_ASSERT(has_value()); + return value_; + } + + T value_or(T default_value) const FLATBUFFERS_NOEXCEPT { + return has_value() ? value_ : default_value; + } + + private: + T value_; + bool has_value_; +}; + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& opt, nullopt_t) FLATBUFFERS_NOEXCEPT { + return !opt; +} +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional& opt) FLATBUFFERS_NOEXCEPT { + return !opt; +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast(lhs) && (*lhs == rhs); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast(rhs) && (lhs == *rhs); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional& lhs, const Optional& rhs) FLATBUFFERS_NOEXCEPT { + return static_cast(lhs) != static_cast(rhs) + ? false + : !static_cast(lhs) ? false : (*lhs == *rhs); +} +#endif // FLATBUFFERS_USE_STD_OPTIONAL + + +// Very limited and naive partial implementation of C++20 std::span. +#if defined(FLATBUFFERS_USE_STD_SPAN) + inline constexpr std::size_t dynamic_extent = std::dynamic_extent; + template + using span = std::span; + +#else // !defined(FLATBUFFERS_USE_STD_SPAN) +FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast(-1); + +// Exclude this code if MSVC2010 or non-STL Android is active. +// The non-STL Android doesn't have `std::is_convertible` required for SFINAE. +#if !defined(FLATBUFFERS_SPAN_MINIMAL) +namespace internal { + // This is SFINAE helper class for checking of a common condition: + // > This overload only participates in overload resolution + // > Check whether a pointer to an array of From can be converted + // > to a pointer to an array of To. + // This helper is used for checking of 'From -> const From'. + template + struct is_span_convertable { + using type = + typename std::conditional::value + && (Extent == dynamic_extent || N == Extent), + int, void>::type; + }; + + template + struct SpanIterator { + // TODO: upgrade to std::random_access_iterator_tag. + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = typename std::remove_cv::type; + using reference = T&; + using pointer = T*; + + // Convince MSVC compiler that this iterator is trusted (it is verified). + #ifdef _MSC_VER + using _Unchecked_type = pointer; + #endif // _MSC_VER + + SpanIterator(pointer ptr) : ptr_(ptr) {} + reference operator*() const { return *ptr_; } + pointer operator->() { return ptr_; } + SpanIterator& operator++() { ptr_++; return *this; } + SpanIterator operator++(int) { auto tmp = *this; ++(*this); return tmp; } + + friend bool operator== (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ == rhs.ptr_; } + friend bool operator!= (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ != rhs.ptr_; } + + private: + pointer ptr_; + }; +} // namespace internal +#endif // !defined(FLATBUFFERS_SPAN_MINIMAL) + +// T - element type; must be a complete type that is not an abstract +// class type. +// Extent - the number of elements in the sequence, or dynamic. +template +class span FLATBUFFERS_FINAL_CLASS { + public: + typedef T element_type; + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + typedef std::size_t size_type; + + static FLATBUFFERS_CONSTEXPR size_type extent = Extent; + + // Returns the number of elements in the span. + FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT { + return count_; + } + + // Returns the size of the sequence in bytes. + FLATBUFFERS_CONSTEXPR_CPP11 + size_type size_bytes() const FLATBUFFERS_NOEXCEPT { + return size() * sizeof(element_type); + } + + // Checks if the span is empty. + FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT { + return size() == 0; + } + + // Returns a pointer to the beginning of the sequence. + FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT { + return data_; + } + + #if !defined(FLATBUFFERS_SPAN_MINIMAL) + using Iterator = internal::SpanIterator; + + Iterator begin() const { return Iterator(data()); } + Iterator end() const { return Iterator(data() + size()); } + #endif + + // Returns a reference to the idx-th element of the sequence. + // The behavior is undefined if the idx is greater than or equal to size(). + FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const { + return data()[idx]; + } + + FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT + : data_(other.data_), count_(other.count_) {} + + FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other) + FLATBUFFERS_NOEXCEPT { + data_ = other.data_; + count_ = other.count_; + } + + // Limited implementation of + // `template constexpr std::span(It first, size_type count);`. + // + // Constructs a span that is a view over the range [first, first + count); + // the resulting span has: data() == first and size() == count. + // The behavior is undefined if [first, first + count) is not a valid range, + // or if (extent != flatbuffers::dynamic_extent && count != extent). + FLATBUFFERS_CONSTEXPR_CPP11 + explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT + : data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)), + count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) { + // Make span empty if the count argument is incompatible with span. + } + + // Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11 + // compliant, it doesn't support default template arguments for functions. + #if defined(FLATBUFFERS_SPAN_MINIMAL) + FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr), + count_(0) { + static_assert(extent == 0 || extent == dynamic_extent, "invalid span"); + } + + #else + // Constructs an empty span whose data() == nullptr and size() == 0. + // This overload only participates in overload resolution if + // extent == 0 || extent == flatbuffers::dynamic_extent. + // A dummy template argument N is need dependency for SFINAE. + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr), + count_(0) { + static_assert(extent == 0 || extent == dynamic_extent, "invalid span"); + } + + // Constructs a span that is a view over the array arr; the resulting span + // has size() == N and data() == std::data(arr). These overloads only + // participate in overload resolution if + // extent == std::dynamic_extent || N == extent is true and + // std::remove_pointer_t(*)[] + // is convertible to element_type (*)[]. + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT + : data_(arr), count_(N) {} + + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(std::array &arr) FLATBUFFERS_NOEXCEPT + : data_(arr.data()), count_(N) {} + + //template + //FLATBUFFERS_CONSTEXPR_CPP11 span(std::array &arr) FLATBUFFERS_NOEXCEPT + // : data_(arr.data()), count_(N) {} + + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array &arr) FLATBUFFERS_NOEXCEPT + : data_(arr.data()), count_(N) {} + + // Converting constructor from another span s; + // the resulting span has size() == s.size() and data() == s.data(). + // This overload only participates in overload resolution + // if extent == std::dynamic_extent || N == extent is true and U (*)[] + // is convertible to element_type (*)[]. + template::type = 0> + FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span &s) FLATBUFFERS_NOEXCEPT + : span(s.data(), s.size()) { + } + + #endif // !defined(FLATBUFFERS_SPAN_MINIMAL) + + private: + // This is a naive implementation with 'count_' member even if (Extent != dynamic_extent). + pointer const data_; + size_type count_; +}; +#endif // defined(FLATBUFFERS_USE_STD_SPAN) + +#if !defined(FLATBUFFERS_SPAN_MINIMAL) +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(const ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(std::array &arr) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(const std::array &arr) FLATBUFFERS_NOEXCEPT { + return span(arr); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT { + return span(first, count); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 +flatbuffers::span make_span(const ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT { + return span(first, count); +} +#endif // !defined(FLATBUFFERS_SPAN_MINIMAL) + +} // namespace flatbuffers + +#endif // FLATBUFFERS_STL_EMULATION_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/string.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/string.h new file mode 100644 index 000000000..e08d96057 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/string.h @@ -0,0 +1,64 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_STRING_H_ +#define FLATBUFFERS_STRING_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/vector.h" + +namespace flatbuffers { + +struct String : public Vector { + const char *c_str() const { return reinterpret_cast(Data()); } + std::string str() const { return std::string(c_str(), size()); } + + // clang-format off + #ifdef FLATBUFFERS_HAS_STRING_VIEW + flatbuffers::string_view string_view() const { + return flatbuffers::string_view(c_str(), size()); + } + #endif // FLATBUFFERS_HAS_STRING_VIEW + // clang-format on + + bool operator<(const String &o) const { + return StringLessThan(this->data(), this->size(), o.data(), o.size()); + } +}; + +// Convenience function to get std::string from a String returning an empty +// string on null pointer. +static inline std::string GetString(const String *str) { + return str ? str->str() : ""; +} + +// Convenience function to get char* from a String returning an empty string on +// null pointer. +static inline const char *GetCstring(const String *str) { + return str ? str->c_str() : ""; +} + +#ifdef FLATBUFFERS_HAS_STRING_VIEW +// Convenience function to get string_view from a String returning an empty +// string_view on null pointer. +static inline flatbuffers::string_view GetStringView(const String *str) { + return str ? str->string_view() : flatbuffers::string_view(); +} +#endif // FLATBUFFERS_HAS_STRING_VIEW + +} // namespace flatbuffers + +#endif // FLATBUFFERS_STRING_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/struct.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/struct.h new file mode 100644 index 000000000..dd3510d7d --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/struct.h @@ -0,0 +1,53 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_STRUCT_H_ +#define FLATBUFFERS_STRUCT_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" + +namespace flatbuffers { + +// "structs" are flat structures that do not have an offset table, thus +// always have all members present and do not support forwards/backwards +// compatible extensions. + +class Struct FLATBUFFERS_FINAL_CLASS { + public: + template T GetField(uoffset_t o) const { + return ReadScalar(&data_[o]); + } + + template T GetStruct(uoffset_t o) const { + return reinterpret_cast(&data_[o]); + } + + const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; } + uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; } + + private: + // private constructor & copy constructor: you obtain instances of this + // class by pointing to existing data only + Struct(); + Struct(const Struct &); + Struct &operator=(const Struct &); + + uint8_t data_[1]; +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_STRUCT_H_ \ No newline at end of file diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/table.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/table.h new file mode 100644 index 000000000..bfafb3ad7 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/table.h @@ -0,0 +1,168 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_TABLE_H_ +#define FLATBUFFERS_TABLE_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/verifier.h" + +namespace flatbuffers { + +// "tables" use an offset table (possibly shared) that allows fields to be +// omitted and added at will, but uses an extra indirection to read. +class Table { + public: + const uint8_t *GetVTable() const { + return data_ - ReadScalar(data_); + } + + // This gets the field offset for any of the functions below it, or 0 + // if the field was not present. + voffset_t GetOptionalFieldOffset(voffset_t field) const { + // The vtable offset is always at the start. + auto vtable = GetVTable(); + // The first element is the size of the vtable (fields + type id + itself). + auto vtsize = ReadScalar(vtable); + // If the field we're accessing is outside the vtable, we're reading older + // data, so it's the same as if the offset was 0 (not present). + return field < vtsize ? ReadScalar(vtable + field) : 0; + } + + template T GetField(voffset_t field, T defaultval) const { + auto field_offset = GetOptionalFieldOffset(field); + return field_offset ? ReadScalar(data_ + field_offset) : defaultval; + } + + template P GetPointer(voffset_t field) { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? reinterpret_cast

(p + ReadScalar(p)) + : nullptr; + } + template P GetPointer(voffset_t field) const { + return const_cast(this)->GetPointer

(field); + } + + template P GetStruct(voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = const_cast(data_ + field_offset); + return field_offset ? reinterpret_cast

(p) : nullptr; + } + + template + flatbuffers::Optional GetOptional(voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? Optional(static_cast(ReadScalar(p))) + : Optional(); + } + + template bool SetField(voffset_t field, T val, T def) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return IsTheSameAs(val, def); + WriteScalar(data_ + field_offset, val); + return true; + } + template bool SetField(voffset_t field, T val) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return false; + WriteScalar(data_ + field_offset, val); + return true; + } + + bool SetPointer(voffset_t field, const uint8_t *val) { + auto field_offset = GetOptionalFieldOffset(field); + if (!field_offset) return false; + WriteScalar(data_ + field_offset, + static_cast(val - (data_ + field_offset))); + return true; + } + + uint8_t *GetAddressOf(voffset_t field) { + auto field_offset = GetOptionalFieldOffset(field); + return field_offset ? data_ + field_offset : nullptr; + } + const uint8_t *GetAddressOf(voffset_t field) const { + return const_cast

(this)->GetAddressOf(field); + } + + bool CheckField(voffset_t field) const { + return GetOptionalFieldOffset(field) != 0; + } + + // Verify the vtable of this table. + // Call this once per table, followed by VerifyField once per field. + bool VerifyTableStart(Verifier &verifier) const { + return verifier.VerifyTableStart(data_); + } + + // Verify a particular field. + template + bool VerifyField(const Verifier &verifier, voffset_t field, + size_t align) const { + // Calling GetOptionalFieldOffset should be safe now thanks to + // VerifyTable(). + auto field_offset = GetOptionalFieldOffset(field); + // Check the actual field. + return !field_offset || verifier.VerifyField(data_, field_offset, align); + } + + // VerifyField for required fields. + template + bool VerifyFieldRequired(const Verifier &verifier, voffset_t field, + size_t align) const { + auto field_offset = GetOptionalFieldOffset(field); + return verifier.Check(field_offset != 0) && + verifier.VerifyField(data_, field_offset, align); + } + + // Versions for offsets. + bool VerifyOffset(const Verifier &verifier, voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + return !field_offset || verifier.VerifyOffset(data_, field_offset); + } + + bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + return verifier.Check(field_offset != 0) && + verifier.VerifyOffset(data_, field_offset); + } + + private: + // private constructor & copy constructor: you obtain instances of this + // class by pointing to existing data only + Table(); + Table(const Table &other); + Table &operator=(const Table &); + + uint8_t data_[1]; +}; + +// This specialization allows avoiding warnings like: +// MSVC C4800: type: forcing value to bool 'true' or 'false'. +template<> +inline flatbuffers::Optional Table::GetOptional( + voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? Optional(ReadScalar(p) != 0) + : Optional(); +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_TABLE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/util.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/util.h new file mode 100644 index 000000000..150739618 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/util.h @@ -0,0 +1,725 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_UTIL_H_ +#define FLATBUFFERS_UTIL_H_ + +#include +#include + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/stl_emulation.h" + +// For TFLM we always want to use FLATBUFFERS_PREFER_PRINTF=1. See +// http://b/211811553 for more context. +#ifndef FLATBUFFERS_PREFER_PRINTF +#define FLATBUFFERS_PREFER_PRINTF 1 +#endif + +#ifndef FLATBUFFERS_PREFER_PRINTF +# include +# include +#else // FLATBUFFERS_PREFER_PRINTF +# include +# include +#endif // FLATBUFFERS_PREFER_PRINTF + +#include + +namespace flatbuffers { + +// @locale-independent functions for ASCII characters set. + +// Fast checking that character lies in closed range: [a <= x <= b] +// using one compare (conditional branch) operator. +inline bool check_ascii_range(char x, char a, char b) { + FLATBUFFERS_ASSERT(a <= b); + // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`. + // The x, a, b will be promoted to int and subtracted without overflow. + return static_cast(x - a) <= static_cast(b - a); +} + +// Case-insensitive isalpha +inline bool is_alpha(char c) { + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF); +} + +// Check for uppercase alpha +inline bool is_alpha_upper(char c) { return check_ascii_range(c, 'A', 'Z'); } + +// Check (case-insensitive) that `c` is equal to alpha. +inline bool is_alpha_char(char c, char alpha) { + FLATBUFFERS_ASSERT(is_alpha(alpha)); + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return ((c & 0xDF) == (alpha & 0xDF)); +} + +// https://en.cppreference.com/w/cpp/string/byte/isxdigit +// isdigit and isxdigit are the only standard narrow character classification +// functions that are not affected by the currently installed C locale. although +// some implementations (e.g. Microsoft in 1252 codepage) may classify +// additional single-byte characters as digits. +inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); } + +inline bool is_xdigit(char c) { + // Replace by look-up table. + return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF); +} + +// Case-insensitive isalnum +inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); } + +inline char CharToUpper(char c) { + return static_cast(::toupper(static_cast(c))); +} + +inline char CharToLower(char c) { + return static_cast(::tolower(static_cast(c))); +} + +// @end-locale-independent functions for ASCII character set + +#ifdef FLATBUFFERS_PREFER_PRINTF +template size_t IntToDigitCount(T t) { + size_t digit_count = 0; + // Count the sign for negative numbers + if (t < 0) digit_count++; + // Count a single 0 left of the dot for fractional numbers + if (-1 < t && t < 1) digit_count++; + // Count digits until fractional part + T eps = std::numeric_limits::epsilon(); + while (t <= (-1 + eps) || (1 - eps) <= t) { + t /= 10; + digit_count++; + } + return digit_count; +} + +template size_t NumToStringWidth(T t, int precision = 0) { + size_t string_width = IntToDigitCount(t); + // Count the dot for floating point numbers + if (precision) string_width += (precision + 1); + return string_width; +} + +template +std::string NumToStringImplWrapper(T t, const char *fmt, int precision = 0) { + size_t string_width = NumToStringWidth(t, precision); + std::string s(string_width, 0x00); + // Allow snprintf to use std::string trailing null to detect buffer overflow + snprintf(const_cast(s.data()), (s.size() + 1), fmt, string_width, t); + return s; +} +#endif // FLATBUFFERS_PREFER_PRINTF + +// Convert an integer or floating point value to a string. +// In contrast to std::stringstream, "char" values are +// converted to a string of digits, and we don't use scientific notation. +template std::string NumToString(T t) { + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + std::stringstream ss; + ss << t; + return ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + auto v = static_cast(t); + return NumToStringImplWrapper(v, "%.*lld"); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on +} +// Avoid char types used as character data. +template<> inline std::string NumToString(signed char t) { + return NumToString(static_cast(t)); +} +template<> inline std::string NumToString(unsigned char t) { + return NumToString(static_cast(t)); +} +template<> inline std::string NumToString(char t) { + return NumToString(static_cast(t)); +} + +// Special versions for floats/doubles. +template std::string FloatToString(T t, int precision) { + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + // to_string() prints different numbers of digits for floats depending on + // platform and isn't available on Android, so we use stringstream + std::stringstream ss; + // Use std::fixed to suppress scientific notation. + ss << std::fixed; + // Default precision is 6, we want that to be higher for doubles. + ss << std::setprecision(precision); + ss << t; + auto s = ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + auto v = static_cast(t); + auto s = NumToStringImplWrapper(v, "%0.*f", precision); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on + // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. + auto p = s.find_last_not_of('0'); + if (p != std::string::npos) { + // Strip trailing zeroes. If it is a whole number, keep one zero. + s.resize(p + (s[p] == '.' ? 2 : 1)); + } + return s; +} + +template<> inline std::string NumToString(double t) { + return FloatToString(t, 12); +} +template<> inline std::string NumToString(float t) { + return FloatToString(t, 6); +} + +// Convert an integer value to a hexadecimal string. +// The returned string length is always xdigits long, prefixed by 0 digits. +// For example, IntToStringHex(0x23, 8) returns the string "00000023". +inline std::string IntToStringHex(int i, int xdigits) { + FLATBUFFERS_ASSERT(i >= 0); + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + std::stringstream ss; + ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase + << i; + return ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + return NumToStringImplWrapper(i, "%.*X", xdigits); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on +} + +// clang-format off +// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}. +#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0) + class ClassicLocale { + #ifdef _MSC_VER + typedef _locale_t locale_type; + #else + typedef locale_t locale_type; // POSIX.1-2008 locale_t type + #endif + ClassicLocale(); + ~ClassicLocale(); + locale_type locale_; + static ClassicLocale instance_; + public: + static locale_type Get() { return instance_.locale_; } + }; + + #ifdef _MSC_VER + #define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get()) + #define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get()) + #define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get()) + #define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get()) + #else + #define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get()) + #define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get()) + #define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get()) + #define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get()) + #endif +#else + #define __strtod_impl(s, pe) strtod(s, pe) + #define __strtof_impl(s, pe) static_cast(strtod(s, pe)) + #ifdef _MSC_VER + #define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b) + #define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b) + #else + #define __strtoull_impl(s, pe, b) strtoull(s, pe, b) + #define __strtoll_impl(s, pe, b) strtoll(s, pe, b) + #endif +#endif + +inline void strtoval_impl(int64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoll_impl(str, endptr, base); +} + +inline void strtoval_impl(uint64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoull_impl(str, endptr, base); +} + +inline void strtoval_impl(double *val, const char *str, char **endptr) { + *val = __strtod_impl(str, endptr); +} + +// UBSAN: double to float is safe if numeric_limits::is_iec559 is true. +__supress_ubsan__("float-cast-overflow") +inline void strtoval_impl(float *val, const char *str, char **endptr) { + *val = __strtof_impl(str, endptr); +} +#undef __strtoull_impl +#undef __strtoll_impl +#undef __strtod_impl +#undef __strtof_impl +// clang-format on + +// Adaptor for strtoull()/strtoll(). +// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9), +// while strtoll with base=0 interprets first leading zero as octal prefix. +// In future, it is possible to add prefixed 0b0101. +// 1) Checks errno code for overflow condition (out of range). +// 2) If base <= 0, function try to detect base of number by prefix. +// +// Return value (like strtoull and strtoll, but reject partial result): +// - If successful, an integer value corresponding to the str is returned. +// - If full string conversion can't be performed, 0 is returned. +// - If the converted value falls out of range of corresponding return type, a +// range error occurs. In this case value MAX(T)/MIN(T) is returned. +template +inline bool StringToIntegerImpl(T *val, const char *const str, + const int base = 0, + const bool check_errno = true) { + // T is int64_t or uint64_T + FLATBUFFERS_ASSERT(str); + if (base <= 0) { + auto s = str; + while (*s && !is_digit(*s)) s++; + if (s[0] == '0' && is_alpha_char(s[1], 'X')) + return StringToIntegerImpl(val, str, 16, check_errno); + // if a prefix not match, try base=10 + return StringToIntegerImpl(val, str, 10, check_errno); + } else { + if (check_errno) errno = 0; // clear thread-local errno + auto endptr = str; + strtoval_impl(val, str, const_cast(&endptr), base); + if ((*endptr != '\0') || (endptr == str)) { + *val = 0; // erase partial result + return false; // invalid string + } + // errno is out-of-range, return MAX/MIN + if (check_errno && errno) return false; + return true; + } +} + +template +inline bool StringToFloatImpl(T *val, const char *const str) { + // Type T must be either float or double. + FLATBUFFERS_ASSERT(str && val); + auto end = str; + strtoval_impl(val, str, const_cast(&end)); + auto done = (end != str) && (*end == '\0'); + if (!done) *val = 0; // erase partial result + return done; +} + +// Convert a string to an instance of T. +// Return value (matched with StringToInteger64Impl and strtod): +// - If successful, a numeric value corresponding to the str is returned. +// - If full string conversion can't be performed, 0 is returned. +// - If the converted value falls out of range of corresponding return type, a +// range error occurs. In this case value MAX(T)/MIN(T) is returned. +template inline bool StringToNumber(const char *s, T *val) { + // Assert on `unsigned long` and `signed long` on LP64. + // If it is necessary, it could be solved with flatbuffers::enable_if. + static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); + FLATBUFFERS_ASSERT(s && val); + int64_t i64; + // The errno check isn't needed, will return MAX/MIN on overflow. + if (StringToIntegerImpl(&i64, s, 0, false)) { + const int64_t max = (flatbuffers::numeric_limits::max)(); + const int64_t min = flatbuffers::numeric_limits::lowest(); + if (i64 > max) { + *val = static_cast(max); + return false; + } + if (i64 < min) { + // For unsigned types return max to distinguish from + // "no conversion can be performed" when 0 is returned. + *val = static_cast(flatbuffers::is_unsigned::value ? max : min); + return false; + } + *val = static_cast(i64); + return true; + } + *val = 0; + return false; +} + +template<> inline bool StringToNumber(const char *str, int64_t *val) { + return StringToIntegerImpl(val, str); +} + +template<> +inline bool StringToNumber(const char *str, uint64_t *val) { + if (!StringToIntegerImpl(val, str)) return false; + // The strtoull accepts negative numbers: + // If the minus sign was part of the input sequence, the numeric value + // calculated from the sequence of digits is negated as if by unary minus + // in the result type, which applies unsigned integer wraparound rules. + // Fix this behaviour (except -0). + if (*val) { + auto s = str; + while (*s && !is_digit(*s)) s++; + s = (s > str) ? (s - 1) : s; // step back to one symbol + if (*s == '-') { + // For unsigned types return the max to distinguish from + // "no conversion can be performed". + *val = (flatbuffers::numeric_limits::max)(); + return false; + } + } + return true; +} + +template<> inline bool StringToNumber(const char *s, float *val) { + return StringToFloatImpl(val, s); +} + +template<> inline bool StringToNumber(const char *s, double *val) { + return StringToFloatImpl(val, s); +} + +inline int64_t StringToInt(const char *s, int base = 10) { + int64_t val; + return StringToIntegerImpl(&val, s, base) ? val : 0; +} + +inline uint64_t StringToUInt(const char *s, int base = 10) { + uint64_t val; + return StringToIntegerImpl(&val, s, base) ? val : 0; +} + +typedef bool (*LoadFileFunction)(const char *filename, bool binary, + std::string *dest); +typedef bool (*FileExistsFunction)(const char *filename); + +LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function); + +FileExistsFunction SetFileExistsFunction( + FileExistsFunction file_exists_function); + +// Check if file "name" exists. +bool FileExists(const char *name); + +// Check if "name" exists and it is also a directory. +bool DirExists(const char *name); + +// Load file "name" into "buf" returning true if successful +// false otherwise. If "binary" is false data is read +// using ifstream's text mode, otherwise data is read with +// no transcoding. +bool LoadFile(const char *name, bool binary, std::string *buf); + +// Save data "buf" of length "len" bytes into a file +// "name" returning true if successful, false otherwise. +// If "binary" is false data is written using ifstream's +// text mode, otherwise data is written with no +// transcoding. +bool SaveFile(const char *name, const char *buf, size_t len, bool binary); + +// Save data "buf" into file "name" returning true if +// successful, false otherwise. If "binary" is false +// data is written using ifstream's text mode, otherwise +// data is written with no transcoding. +inline bool SaveFile(const char *name, const std::string &buf, bool binary) { + return SaveFile(name, buf.c_str(), buf.size(), binary); +} + +// Functionality for minimalistic portable path handling. + +// The functions below behave correctly regardless of whether posix ('/') or +// Windows ('/' or '\\') separators are used. + +// Any new separators inserted are always posix. +FLATBUFFERS_CONSTEXPR char kPathSeparator = '/'; + +// Returns the path with the extension, if any, removed. +std::string StripExtension(const std::string &filepath); + +// Returns the extension, if any. +std::string GetExtension(const std::string &filepath); + +// Return the last component of the path, after the last separator. +std::string StripPath(const std::string &filepath); + +// Strip the last component of the path + separator. +std::string StripFileName(const std::string &filepath); + +std::string StripPrefix(const std::string &filepath, + const std::string &prefix_to_remove); + +// Concatenates a path with a filename, regardless of whether the path +// ends in a separator or not. +std::string ConCatPathFileName(const std::string &path, + const std::string &filename); + +// Replaces any '\\' separators with '/' +std::string PosixPath(const char *path); +std::string PosixPath(const std::string &path); + +// This function ensure a directory exists, by recursively +// creating dirs for any parts of the path that don't exist yet. +void EnsureDirExists(const std::string &filepath); + +// Obtains the absolute path from any other path. +// Returns the input path if the absolute path couldn't be resolved. +std::string AbsolutePath(const std::string &filepath); + +// Returns files relative to the --project_root path, prefixed with `//`. +std::string RelativeToRootPath(const std::string &project, + const std::string &filepath); + +// To and from UTF-8 unicode conversion functions + +// Convert a unicode code point into a UTF-8 representation by appending it +// to a string. Returns the number of bytes generated. +inline int ToUTF8(uint32_t ucc, std::string *out) { + FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set. + // 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8 + for (int i = 0; i < 6; i++) { + // Max bits this encoding can represent. + uint32_t max_bits = 6 + i * 5 + static_cast(!i); + if (ucc < (1u << max_bits)) { // does it fit? + // Remaining bits not encoded in the first byte, store 6 bits each + uint32_t remain_bits = i * 6; + // Store first byte: + (*out) += static_cast((0xFE << (max_bits - remain_bits)) | + (ucc >> remain_bits)); + // Store remaining bytes: + for (int j = i - 1; j >= 0; j--) { + (*out) += static_cast(((ucc >> (j * 6)) & 0x3F) | 0x80); + } + return i + 1; // Return the number of bytes added. + } + } + FLATBUFFERS_ASSERT(0); // Impossible to arrive here. + return -1; +} + +// Converts whatever prefix of the incoming string corresponds to a valid +// UTF-8 sequence into a unicode code. The incoming pointer will have been +// advanced past all bytes parsed. +// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in +// this case). +inline int FromUTF8(const char **in) { + int len = 0; + // Count leading 1 bits. + for (int mask = 0x80; mask >= 0x04; mask >>= 1) { + if (**in & mask) { + len++; + } else { + break; + } + } + if ((static_cast(**in) << len) & 0x80) + return -1; // Bit after leading 1's must be 0. + if (!len) return *(*in)++; + // UTF-8 encoded values with a length are between 2 and 4 bytes. + if (len < 2 || len > 4) { return -1; } + // Grab initial bits of the code. + int ucc = *(*in)++ & ((1 << (7 - len)) - 1); + for (int i = 0; i < len - 1; i++) { + if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0. + ucc <<= 6; + ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code. + } + // UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for + // UTF-16 surrogate pairs). + if (ucc >= 0xD800 && ucc <= 0xDFFF) { return -1; } + // UTF-8 must represent code points in their shortest possible encoding. + switch (len) { + case 2: + // Two bytes of UTF-8 can represent code points from U+0080 to U+07FF. + if (ucc < 0x0080 || ucc > 0x07FF) { return -1; } + break; + case 3: + // Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF. + if (ucc < 0x0800 || ucc > 0xFFFF) { return -1; } + break; + case 4: + // Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF. + if (ucc < 0x10000 || ucc > 0x10FFFF) { return -1; } + break; + } + return ucc; +} + +#ifndef FLATBUFFERS_PREFER_PRINTF +// Wraps a string to a maximum length, inserting new lines where necessary. Any +// existing whitespace will be collapsed down to a single space. A prefix or +// suffix can be provided, which will be inserted before or after a wrapped +// line, respectively. +inline std::string WordWrap(const std::string in, size_t max_length, + const std::string wrapped_line_prefix, + const std::string wrapped_line_suffix) { + std::istringstream in_stream(in); + std::string wrapped, line, word; + + in_stream >> word; + line = word; + + while (in_stream >> word) { + if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) < + max_length) { + line += " " + word; + } else { + wrapped += line + wrapped_line_suffix + "\n"; + line = wrapped_line_prefix + word; + } + } + wrapped += line; + + return wrapped; +} +#endif // !FLATBUFFERS_PREFER_PRINTF + +inline bool EscapeString(const char *s, size_t length, std::string *_text, + bool allow_non_utf8, bool natural_utf8) { + std::string &text = *_text; + text += "\""; + for (uoffset_t i = 0; i < length; i++) { + char c = s[i]; + switch (c) { + case '\n': text += "\\n"; break; + case '\t': text += "\\t"; break; + case '\r': text += "\\r"; break; + case '\b': text += "\\b"; break; + case '\f': text += "\\f"; break; + case '\"': text += "\\\""; break; + case '\\': text += "\\\\"; break; + default: + if (c >= ' ' && c <= '~') { + text += c; + } else { + // Not printable ASCII data. Let's see if it's valid UTF-8 first: + const char *utf8 = s + i; + int ucc = FromUTF8(&utf8); + if (ucc < 0) { + if (allow_non_utf8) { + text += "\\x"; + text += IntToStringHex(static_cast(c), 2); + } else { + // There are two cases here: + // + // 1) We reached here by parsing an IDL file. In that case, + // we previously checked for non-UTF-8, so we shouldn't reach + // here. + // + // 2) We reached here by someone calling GenerateText() + // on a previously-serialized flatbuffer. The data might have + // non-UTF-8 Strings, or might be corrupt. + // + // In both cases, we have to give up and inform the caller + // they have no JSON. + return false; + } + } else { + if (natural_utf8) { + // utf8 points to past all utf-8 bytes parsed + text.append(s + i, static_cast(utf8 - s - i)); + } else if (ucc <= 0xFFFF) { + // Parses as Unicode within JSON's \uXXXX range, so use that. + text += "\\u"; + text += IntToStringHex(ucc, 4); + } else if (ucc <= 0x10FFFF) { + // Encode Unicode SMP values to a surrogate pair using two \u + // escapes. + uint32_t base = ucc - 0x10000; + auto high_surrogate = (base >> 10) + 0xD800; + auto low_surrogate = (base & 0x03FF) + 0xDC00; + text += "\\u"; + text += IntToStringHex(high_surrogate, 4); + text += "\\u"; + text += IntToStringHex(low_surrogate, 4); + } + // Skip past characters recognized. + i = static_cast(utf8 - s - 1); + } + } + break; + } + } + text += "\""; + return true; +} + +inline std::string BufferToHexText(const void *buffer, size_t buffer_size, + size_t max_length, + const std::string &wrapped_line_prefix, + const std::string &wrapped_line_suffix) { + std::string text = wrapped_line_prefix; + size_t start_offset = 0; + const char *s = reinterpret_cast(buffer); + for (size_t i = 0; s && i < buffer_size; i++) { + // Last iteration or do we have more? + bool have_more = i + 1 < buffer_size; + text += "0x"; + text += IntToStringHex(static_cast(s[i]), 2); + if (have_more) { text += ','; } + // If we have more to process and we reached max_length + if (have_more && + text.size() + wrapped_line_suffix.size() >= start_offset + max_length) { + text += wrapped_line_suffix; + text += '\n'; + start_offset = text.size(); + text += wrapped_line_prefix; + } + } + text += wrapped_line_suffix; + return text; +} + +// Remove paired quotes in a string: "text"|'text' -> text. +std::string RemoveStringQuotes(const std::string &s); + +// Change th global C-locale to locale with name . +// Returns an actual locale name in <_value>, useful if locale_name is "" or +// null. +bool SetGlobalTestLocale(const char *locale_name, + std::string *_value = nullptr); + +// Read (or test) a value of environment variable. +bool ReadEnvironmentVariable(const char *var_name, + std::string *_value = nullptr); + +// MSVC specific: Send all assert reports to STDOUT to prevent CI hangs. +void SetupDefaultCRTReportMode(); + +enum class Case { + kUnknown = 0, + // TheQuickBrownFox + kUpperCamel = 1, + // theQuickBrownFox + kLowerCamel = 2, + // the_quick_brown_fox + kSnake = 3, + // THE_QUICK_BROWN_FOX + kScreamingSnake = 4, + // THEQUICKBROWNFOX + kAllUpper = 5, + // thequickbrownfox + kAllLower = 6, + // the-quick-brown-fox + kDasher = 7, + // THEQuiCKBr_ownFox (or whatever you want, we won't change it) + kKeep = 8, + // the_quick_brown_fox123 (as opposed to the_quick_brown_fox_123) + kSnake2 = 9, +}; + +// Convert the `input` string of case `input_case` to the specified `output_case`. +std::string ConvertCase(const std::string &input, Case output_case, + Case input_case = Case::kSnake); + +} // namespace flatbuffers + +#endif // FLATBUFFERS_UTIL_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/vector.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/vector.h new file mode 100644 index 000000000..f0cd2f037 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/vector.h @@ -0,0 +1,389 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_VECTOR_H_ +#define FLATBUFFERS_VECTOR_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/buffer.h" +#include "third_party/flatbuffers/include/flatbuffers/stl_emulation.h" + +namespace flatbuffers { + +struct String; + +// An STL compatible iterator implementation for Vector below, effectively +// calling Get() for every element. +template struct VectorIterator { + typedef std::random_access_iterator_tag iterator_category; + typedef IT value_type; + typedef ptrdiff_t difference_type; + typedef IT *pointer; + typedef IT &reference; + + VectorIterator(const uint8_t *data, uoffset_t i) + : data_(data + IndirectHelper::element_stride * i) {} + VectorIterator(const VectorIterator &other) : data_(other.data_) {} + VectorIterator() : data_(nullptr) {} + + VectorIterator &operator=(const VectorIterator &other) { + data_ = other.data_; + return *this; + } + + VectorIterator &operator=(VectorIterator &&other) { + data_ = other.data_; + return *this; + } + + bool operator==(const VectorIterator &other) const { + return data_ == other.data_; + } + + bool operator<(const VectorIterator &other) const { + return data_ < other.data_; + } + + bool operator!=(const VectorIterator &other) const { + return data_ != other.data_; + } + + difference_type operator-(const VectorIterator &other) const { + return (data_ - other.data_) / IndirectHelper::element_stride; + } + + // Note: return type is incompatible with the standard + // `reference operator*()`. + IT operator*() const { return IndirectHelper::Read(data_, 0); } + + // Note: return type is incompatible with the standard + // `pointer operator->()`. + IT operator->() const { return IndirectHelper::Read(data_, 0); } + + VectorIterator &operator++() { + data_ += IndirectHelper::element_stride; + return *this; + } + + VectorIterator operator++(int) { + VectorIterator temp(data_, 0); + data_ += IndirectHelper::element_stride; + return temp; + } + + VectorIterator operator+(const uoffset_t &offset) const { + return VectorIterator(data_ + offset * IndirectHelper::element_stride, + 0); + } + + VectorIterator &operator+=(const uoffset_t &offset) { + data_ += offset * IndirectHelper::element_stride; + return *this; + } + + VectorIterator &operator--() { + data_ -= IndirectHelper::element_stride; + return *this; + } + + VectorIterator operator--(int) { + VectorIterator temp(data_, 0); + data_ -= IndirectHelper::element_stride; + return temp; + } + + VectorIterator operator-(const uoffset_t &offset) const { + return VectorIterator(data_ - offset * IndirectHelper::element_stride, + 0); + } + + VectorIterator &operator-=(const uoffset_t &offset) { + data_ -= offset * IndirectHelper::element_stride; + return *this; + } + + private: + const uint8_t *data_; +}; + +template +struct VectorReverseIterator : public std::reverse_iterator { + explicit VectorReverseIterator(Iterator iter) + : std::reverse_iterator(iter) {} + + // Note: return type is incompatible with the standard + // `reference operator*()`. + typename Iterator::value_type operator*() const { + auto tmp = std::reverse_iterator::current; + return *--tmp; + } + + // Note: return type is incompatible with the standard + // `pointer operator->()`. + typename Iterator::value_type operator->() const { + auto tmp = std::reverse_iterator::current; + return *--tmp; + } +}; + +// This is used as a helper type for accessing vectors. +// Vector::data() assumes the vector elements start after the length field. +template class Vector { + public: + typedef VectorIterator::mutable_return_type> + iterator; + typedef VectorIterator::return_type> + const_iterator; + typedef VectorReverseIterator reverse_iterator; + typedef VectorReverseIterator const_reverse_iterator; + + typedef typename flatbuffers::bool_constant::value> + scalar_tag; + + static FLATBUFFERS_CONSTEXPR bool is_span_observable = + scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1); + + uoffset_t size() const { return EndianScalar(length_); } + + // Deprecated: use size(). Here for backwards compatibility. + FLATBUFFERS_ATTRIBUTE([[deprecated("use size() instead")]]) + uoffset_t Length() const { return size(); } + + typedef typename IndirectHelper::return_type return_type; + typedef typename IndirectHelper::mutable_return_type mutable_return_type; + typedef return_type value_type; + + return_type Get(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return IndirectHelper::Read(Data(), i); + } + + return_type operator[](uoffset_t i) const { return Get(i); } + + // If this is a Vector of enums, T will be its storage type, not the enum + // type. This function makes it convenient to retrieve value with enum + // type E. + template E GetEnum(uoffset_t i) const { + return static_cast(Get(i)); + } + + // If this a vector of unions, this does the cast for you. There's no check + // to make sure this is the right type! + template const U *GetAs(uoffset_t i) const { + return reinterpret_cast(Get(i)); + } + + // If this a vector of unions, this does the cast for you. There's no check + // to make sure this is actually a string! + const String *GetAsString(uoffset_t i) const { + return reinterpret_cast(Get(i)); + } + + const void *GetStructFromOffset(size_t o) const { + return reinterpret_cast(Data() + o); + } + + iterator begin() { return iterator(Data(), 0); } + const_iterator begin() const { return const_iterator(Data(), 0); } + + iterator end() { return iterator(Data(), size()); } + const_iterator end() const { return const_iterator(Data(), size()); } + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const { return begin(); } + + const_iterator cend() const { return end(); } + + const_reverse_iterator crbegin() const { return rbegin(); } + + const_reverse_iterator crend() const { return rend(); } + + // Change elements if you have a non-const pointer to this object. + // Scalars only. See reflection.h, and the documentation. + void Mutate(uoffset_t i, const T &val) { + FLATBUFFERS_ASSERT(i < size()); + WriteScalar(data() + i, val); + } + + // Change an element of a vector of tables (or strings). + // "val" points to the new table/string, as you can obtain from + // e.g. reflection::AddFlatBuffer(). + void MutateOffset(uoffset_t i, const uint8_t *val) { + FLATBUFFERS_ASSERT(i < size()); + static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types"); + WriteScalar(data() + i, + static_cast(val - (Data() + i * sizeof(uoffset_t)))); + } + + // Get a mutable pointer to tables/strings inside this vector. + mutable_return_type GetMutableObject(uoffset_t i) const { + FLATBUFFERS_ASSERT(i < size()); + return const_cast(IndirectHelper::Read(Data(), i)); + } + + // The raw data in little endian format. Use with care. + const uint8_t *Data() const { + return reinterpret_cast(&length_ + 1); + } + + uint8_t *Data() { return reinterpret_cast(&length_ + 1); } + + // Similarly, but typed, much like std::vector::data + const T *data() const { return reinterpret_cast(Data()); } + T *data() { return reinterpret_cast(Data()); } + + template return_type LookupByKey(K key) const { + void *search_result = std::bsearch( + &key, Data(), size(), IndirectHelper::element_stride, KeyCompare); + + if (!search_result) { + return nullptr; // Key not found. + } + + const uint8_t *element = reinterpret_cast(search_result); + + return IndirectHelper::Read(element, 0); + } + + template mutable_return_type MutableLookupByKey(K key) { + return const_cast(LookupByKey(key)); + } + + protected: + // This class is only used to access pre-existing data. Don't ever + // try to construct these manually. + Vector(); + + uoffset_t length_; + + private: + // This class is a pointer. Copying will therefore create an invalid object. + // Private and unimplemented copy constructor. + Vector(const Vector &); + Vector &operator=(const Vector &); + + template static int KeyCompare(const void *ap, const void *bp) { + const K *key = reinterpret_cast(ap); + const uint8_t *data = reinterpret_cast(bp); + auto table = IndirectHelper::Read(data, 0); + + // std::bsearch compares with the operands transposed, so we negate the + // result here. + return -table->KeyCompareWithValue(*key); + } +}; + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Vector &vec) + FLATBUFFERS_NOEXCEPT { + static_assert(Vector::is_span_observable, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.data(), vec.size()); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( + const Vector &vec) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::is_span_observable, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.data(), vec.size()); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_bytes_span( + Vector &vec) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::scalar_tag::value, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.Data(), vec.size() * sizeof(U)); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_bytes_span( + const Vector &vec) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::scalar_tag::value, + "wrong type U, only LE-scalar, or byte types are allowed"); + return span(vec.Data(), vec.size() * sizeof(U)); +} + +// Convenient helper functions to get a span of any vector, regardless +// of whether it is null or not (the field is not set). +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span(Vector *ptr) + FLATBUFFERS_NOEXCEPT { + static_assert(Vector::is_span_observable, + "wrong type U, only LE-scalar, or byte types are allowed"); + return ptr ? make_span(*ptr) : span(); +} + +template +FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span make_span( + const Vector *ptr) FLATBUFFERS_NOEXCEPT { + static_assert(Vector::is_span_observable, + "wrong type U, only LE-scalar, or byte types are allowed"); + return ptr ? make_span(*ptr) : span(); +} + +// Represent a vector much like the template above, but in this case we +// don't know what the element types are (used with reflection.h). +class VectorOfAny { + public: + uoffset_t size() const { return EndianScalar(length_); } + + const uint8_t *Data() const { + return reinterpret_cast(&length_ + 1); + } + uint8_t *Data() { return reinterpret_cast(&length_ + 1); } + + protected: + VectorOfAny(); + + uoffset_t length_; + + private: + VectorOfAny(const VectorOfAny &); + VectorOfAny &operator=(const VectorOfAny &); +}; + +template +Vector> *VectorCast(Vector> *ptr) { + static_assert(std::is_base_of::value, "Unrelated types"); + return reinterpret_cast> *>(ptr); +} + +template +const Vector> *VectorCast(const Vector> *ptr) { + static_assert(std::is_base_of::value, "Unrelated types"); + return reinterpret_cast> *>(ptr); +} + +// Convenient helper function to get the length of any vector, regardless +// of whether it is null or not (the field is not set). +template static inline size_t VectorLength(const Vector *v) { + return v ? v->size() : 0; +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_VERIFIER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/vector_downward.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/vector_downward.h new file mode 100644 index 000000000..dbe8e56a5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/vector_downward.h @@ -0,0 +1,271 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_VECTOR_DOWNWARD_H_ +#define FLATBUFFERS_VECTOR_DOWNWARD_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/default_allocator.h" +#include "third_party/flatbuffers/include/flatbuffers/detached_buffer.h" + +namespace flatbuffers { + +// This is a minimal replication of std::vector functionality, +// except growing from higher to lower addresses. i.e push_back() inserts data +// in the lowest address in the vector. +// Since this vector leaves the lower part unused, we support a "scratch-pad" +// that can be stored there for temporary data, to share the allocated space. +// Essentially, this supports 2 std::vectors in a single buffer. +class vector_downward { + public: + explicit vector_downward(size_t initial_size, Allocator *allocator, + bool own_allocator, size_t buffer_minalign) + : allocator_(allocator), + own_allocator_(own_allocator), + initial_size_(initial_size), + buffer_minalign_(buffer_minalign), + reserved_(0), + size_(0), + buf_(nullptr), + cur_(nullptr), + scratch_(nullptr) {} + + vector_downward(vector_downward &&other) + // clang-format on + : allocator_(other.allocator_), + own_allocator_(other.own_allocator_), + initial_size_(other.initial_size_), + buffer_minalign_(other.buffer_minalign_), + reserved_(other.reserved_), + size_(other.size_), + buf_(other.buf_), + cur_(other.cur_), + scratch_(other.scratch_) { + // No change in other.allocator_ + // No change in other.initial_size_ + // No change in other.buffer_minalign_ + other.own_allocator_ = false; + other.reserved_ = 0; + other.buf_ = nullptr; + other.cur_ = nullptr; + other.scratch_ = nullptr; + } + + vector_downward &operator=(vector_downward &&other) { + // Move construct a temporary and swap idiom + vector_downward temp(std::move(other)); + swap(temp); + return *this; + } + + ~vector_downward() { + clear_buffer(); + clear_allocator(); + } + + void reset() { + clear_buffer(); + clear(); + } + + void clear() { + if (buf_) { + cur_ = buf_ + reserved_; + } else { + reserved_ = 0; + cur_ = nullptr; + } + size_ = 0; + clear_scratch(); + } + + void clear_scratch() { scratch_ = buf_; } + + void clear_allocator() { + if (own_allocator_ && allocator_) { delete allocator_; } + allocator_ = nullptr; + own_allocator_ = false; + } + + void clear_buffer() { + if (buf_) Deallocate(allocator_, buf_, reserved_); + buf_ = nullptr; + } + + // Relinquish the pointer to the caller. + uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) { + auto *buf = buf_; + allocated_bytes = reserved_; + offset = static_cast(cur_ - buf_); + + // release_raw only relinquishes the buffer ownership. + // Does not deallocate or reset the allocator. Destructor will do that. + buf_ = nullptr; + clear(); + return buf; + } + + // Relinquish the pointer to the caller. + DetachedBuffer release() { + // allocator ownership (if any) is transferred to DetachedBuffer. + DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_, + size()); + if (own_allocator_) { + allocator_ = nullptr; + own_allocator_ = false; + } + buf_ = nullptr; + clear(); + return fb; + } + + size_t ensure_space(size_t len) { + FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_); + if (len > static_cast(cur_ - scratch_)) { reallocate(len); } + // Beyond this, signed offsets may not have enough range: + // (FlatBuffers > 2GB not supported). + FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE); + return len; + } + + inline uint8_t *make_space(size_t len) { + if (len) { + ensure_space(len); + cur_ -= len; + size_ += static_cast(len); + } + return cur_; + } + + // Returns nullptr if using the DefaultAllocator. + Allocator *get_custom_allocator() { return allocator_; } + + inline uoffset_t size() const { return size_; } + + uoffset_t scratch_size() const { + return static_cast(scratch_ - buf_); + } + + size_t capacity() const { return reserved_; } + + uint8_t *data() const { + FLATBUFFERS_ASSERT(cur_); + return cur_; + } + + uint8_t *scratch_data() const { + FLATBUFFERS_ASSERT(buf_); + return buf_; + } + + uint8_t *scratch_end() const { + FLATBUFFERS_ASSERT(scratch_); + return scratch_; + } + + uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; } + + void push(const uint8_t *bytes, size_t num) { + if (num > 0) { memcpy(make_space(num), bytes, num); } + } + + // Specialized version of push() that avoids memcpy call for small data. + template void push_small(const T &little_endian_t) { + make_space(sizeof(T)); + *reinterpret_cast(cur_) = little_endian_t; + } + + template void scratch_push_small(const T &t) { + ensure_space(sizeof(T)); + *reinterpret_cast(scratch_) = t; + scratch_ += sizeof(T); + } + + // fill() is most frequently called with small byte counts (<= 4), + // which is why we're using loops rather than calling memset. + void fill(size_t zero_pad_bytes) { + make_space(zero_pad_bytes); + for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0; + } + + // Version for when we know the size is larger. + // Precondition: zero_pad_bytes > 0 + void fill_big(size_t zero_pad_bytes) { + memset(make_space(zero_pad_bytes), 0, zero_pad_bytes); + } + + void pop(size_t bytes_to_remove) { + cur_ += bytes_to_remove; + size_ -= static_cast(bytes_to_remove); + } + + void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; } + + void swap(vector_downward &other) { + using std::swap; + swap(allocator_, other.allocator_); + swap(own_allocator_, other.own_allocator_); + swap(initial_size_, other.initial_size_); + swap(buffer_minalign_, other.buffer_minalign_); + swap(reserved_, other.reserved_); + swap(size_, other.size_); + swap(buf_, other.buf_); + swap(cur_, other.cur_); + swap(scratch_, other.scratch_); + } + + void swap_allocator(vector_downward &other) { + using std::swap; + swap(allocator_, other.allocator_); + swap(own_allocator_, other.own_allocator_); + } + + private: + // You shouldn't really be copying instances of this class. + FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &)); + FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &)); + + Allocator *allocator_; + bool own_allocator_; + size_t initial_size_; + size_t buffer_minalign_; + size_t reserved_; + uoffset_t size_; + uint8_t *buf_; + uint8_t *cur_; // Points at location between empty (below) and used (above). + uint8_t *scratch_; // Points to the end of the scratchpad in use. + + void reallocate(size_t len) { + auto old_reserved = reserved_; + auto old_size = size(); + auto old_scratch_size = scratch_size(); + reserved_ += + (std::max)(len, old_reserved ? old_reserved / 2 : initial_size_); + reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1); + if (buf_) { + buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_, + old_size, old_scratch_size); + } else { + buf_ = Allocate(allocator_, reserved_); + } + cur_ = buf_ + reserved_ - old_size; + scratch_ = buf_ + old_scratch_size; + } +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_VECTOR_DOWNWARD_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/verifier.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/verifier.h new file mode 100644 index 000000000..16a335f79 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/flatbuffers/include/flatbuffers/verifier.h @@ -0,0 +1,304 @@ +/* + * Copyright 2021 Google Inc. All rights reserved. + * + * 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 FLATBUFFERS_VERIFIER_H_ +#define FLATBUFFERS_VERIFIER_H_ + +#include "third_party/flatbuffers/include/flatbuffers/base.h" +#include "third_party/flatbuffers/include/flatbuffers/vector.h" + +namespace flatbuffers { + +// Helper class to verify the integrity of a FlatBuffer +class Verifier FLATBUFFERS_FINAL_CLASS { + public: + Verifier(const uint8_t *const buf, const size_t buf_len, + const uoffset_t _max_depth = 64, + const uoffset_t _max_tables = 1000000, + const bool _check_alignment = true) + : buf_(buf), + size_(buf_len), + max_depth_(_max_depth), + max_tables_(_max_tables), + check_alignment_(_check_alignment), + upper_bound_(0), + depth_(0), + num_tables_(0), + flex_reuse_tracker_(nullptr) { + FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE); + } + + // Central location where any verification failures register. + bool Check(const bool ok) const { + // clang-format off + #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE + FLATBUFFERS_ASSERT(ok); + #endif + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + if (!ok) + upper_bound_ = 0; + #endif + // clang-format on + return ok; + } + + // Verify any range within the buffer. + bool Verify(const size_t elem, const size_t elem_len) const { + // clang-format off + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + auto upper_bound = elem + elem_len; + if (upper_bound_ < upper_bound) + upper_bound_ = upper_bound; + #endif + // clang-format on + return Check(elem_len < size_ && elem <= size_ - elem_len); + } + + bool VerifyAlignment(const size_t elem, const size_t align) const { + return Check((elem & (align - 1)) == 0 || !check_alignment_); + } + + // Verify a range indicated by sizeof(T). + template bool Verify(const size_t elem) const { + return VerifyAlignment(elem, sizeof(T)) && Verify(elem, sizeof(T)); + } + + bool VerifyFromPointer(const uint8_t *const p, const size_t len) { + return Verify(static_cast(p - buf_), len); + } + + // Verify relative to a known-good base pointer. + bool VerifyFieldStruct(const uint8_t *const base, const voffset_t elem_off, + const size_t elem_len, const size_t align) const { + const auto f = static_cast(base - buf_) + elem_off; + return VerifyAlignment(f, align) && Verify(f, elem_len); + } + + template + bool VerifyField(const uint8_t *const base, const voffset_t elem_off, + const size_t align) const { + const auto f = static_cast(base - buf_) + elem_off; + return VerifyAlignment(f, align) && Verify(f, sizeof(T)); + } + + // Verify a pointer (may be NULL) of a table type. + template bool VerifyTable(const T *const table) { + return !table || table->Verify(*this); + } + + // Verify a pointer (may be NULL) of any vector type. + template bool VerifyVector(const Vector *const vec) const { + return !vec || VerifyVectorOrString(reinterpret_cast(vec), + sizeof(T)); + } + + // Verify a pointer (may be NULL) of a vector to struct. + template + bool VerifyVector(const Vector *const vec) const { + return VerifyVector(reinterpret_cast *>(vec)); + } + + // Verify a pointer (may be NULL) to string. + bool VerifyString(const String *const str) const { + size_t end; + return !str || (VerifyVectorOrString(reinterpret_cast(str), + 1, &end) && + Verify(end, 1) && // Must have terminator + Check(buf_[end] == '\0')); // Terminating byte must be 0. + } + + // Common code between vectors and strings. + bool VerifyVectorOrString(const uint8_t *const vec, const size_t elem_size, + size_t *const end = nullptr) const { + const auto veco = static_cast(vec - buf_); + // Check we can read the size field. + if (!Verify(veco)) return false; + // Check the whole array. If this is a string, the byte past the array + // must be 0. + const auto size = ReadScalar(vec); + const auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size; + if (!Check(size < max_elems)) + return false; // Protect against byte_size overflowing. + const auto byte_size = sizeof(size) + elem_size * size; + if (end) *end = veco + byte_size; + return Verify(veco, byte_size); + } + + // Special case for string contents, after the above has been called. + bool VerifyVectorOfStrings(const Vector> *const vec) const { + if (vec) { + for (uoffset_t i = 0; i < vec->size(); i++) { + if (!VerifyString(vec->Get(i))) return false; + } + } + return true; + } + + // Special case for table contents, after the above has been called. + template + bool VerifyVectorOfTables(const Vector> *const vec) { + if (vec) { + for (uoffset_t i = 0; i < vec->size(); i++) { + if (!vec->Get(i)->Verify(*this)) return false; + } + } + return true; + } + + __supress_ubsan__("unsigned-integer-overflow") bool VerifyTableStart( + const uint8_t *const table) { + // Check the vtable offset. + const auto tableo = static_cast(table - buf_); + if (!Verify(tableo)) return false; + // This offset may be signed, but doing the subtraction unsigned always + // gives the result we want. + const auto vtableo = + tableo - static_cast(ReadScalar(table)); + // Check the vtable size field, then check vtable fits in its entirety. + if (!(VerifyComplexity() && Verify(vtableo) && + VerifyAlignment(ReadScalar(buf_ + vtableo), + sizeof(voffset_t)))) + return false; + const auto vsize = ReadScalar(buf_ + vtableo); + return Check((vsize & 1) == 0) && Verify(vtableo, vsize); + } + + template + bool VerifyBufferFromStart(const char *const identifier, const size_t start) { + // Buffers have to be of some size to be valid. The reason it is a runtime + // check instead of static_assert, is that nested flatbuffers go through + // this call and their size is determined at runtime. + if (!Check(size_ >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false; + + // If an identifier is provided, check that we have a buffer + if (identifier && !Check((size_ >= 2 * sizeof(flatbuffers::uoffset_t) && + BufferHasIdentifier(buf_ + start, identifier)))) { + return false; + } + + // Call T::Verify, which must be in the generated code for this type. + const auto o = VerifyOffset(start); + return Check(o != 0) && + reinterpret_cast(buf_ + start + o)->Verify(*this) + // clang-format off + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + && GetComputedSize() + #endif + ; + // clang-format on + } + + template + bool VerifyNestedFlatBuffer(const Vector *const buf, + const char *const identifier) { + // An empty buffer is OK as it indicates not present. + if (!buf) return true; + + // If there is a nested buffer, it must be greater than the min size. + if(!Check(buf->size() >= FLATBUFFERS_MIN_BUFFER_SIZE)) return false; + + Verifier nested_verifier(buf->data(), buf->size()); + return nested_verifier.VerifyBuffer(identifier); + } + + // Verify this whole buffer, starting with root type T. + template bool VerifyBuffer() { return VerifyBuffer(nullptr); } + + template bool VerifyBuffer(const char *const identifier) { + return VerifyBufferFromStart(identifier, 0); + } + + template + bool VerifySizePrefixedBuffer(const char *const identifier) { + return Verify(0U) && + Check(ReadScalar(buf_) == size_ - sizeof(uoffset_t)) && + VerifyBufferFromStart(identifier, sizeof(uoffset_t)); + } + + uoffset_t VerifyOffset(const size_t start) const { + if (!Verify(start)) return 0; + const auto o = ReadScalar(buf_ + start); + // May not point to itself. + if (!Check(o != 0)) return 0; + // Can't wrap around / buffers are max 2GB. + if (!Check(static_cast(o) >= 0)) return 0; + // Must be inside the buffer to create a pointer from it (pointer outside + // buffer is UB). + if (!Verify(start + o, 1)) return 0; + return o; + } + + uoffset_t VerifyOffset(const uint8_t *const base, + const voffset_t start) const { + return VerifyOffset(static_cast(base - buf_) + start); + } + + // Called at the start of a table to increase counters measuring data + // structure depth and amount, and possibly bails out with false if + // limits set by the constructor have been hit. Needs to be balanced + // with EndTable(). + bool VerifyComplexity() { + depth_++; + num_tables_++; + return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_); + } + + // Called at the end of a table to pop the depth count. + bool EndTable() { + depth_--; + return true; + } + + // Returns the message size in bytes + size_t GetComputedSize() const { + // clang-format off + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + uintptr_t size = upper_bound_; + // Align the size to uoffset_t + size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1); + return (size > size_) ? 0 : size; + #else + // Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work. + (void)upper_bound_; + FLATBUFFERS_ASSERT(false); + return 0; + #endif + // clang-format on + } + + std::vector *GetFlexReuseTracker() { return flex_reuse_tracker_; } + + void SetFlexReuseTracker(std::vector *const rt) { + flex_reuse_tracker_ = rt; + } + + private: + const uint8_t *buf_; + const size_t size_; + const uoffset_t max_depth_; + const uoffset_t max_tables_; + const bool check_alignment_; + + mutable size_t upper_bound_; + + uoffset_t depth_; + uoffset_t num_tables_; + std::vector *flex_reuse_tracker_; +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_VERIFIER_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/LICENSE b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/LICENSE @@ -0,0 +1,202 @@ + + 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 [yyyy] [name of copyright owner] + + 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. diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint.h new file mode 100644 index 000000000..51b5aff41 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint.h @@ -0,0 +1,900 @@ +// Copyright 2015 The Gemmlowp Authors. All Rights Reserved. +// +// 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. + +// fixedpoint.h: fixed-point arithmetic, with basic operations and +// a few math functions such as tanh. + +#ifndef GEMMLOWP_INTERNAL_FIXEDPOINT_H_ +#define GEMMLOWP_INTERNAL_FIXEDPOINT_H_ + +#include +#include +#include +#include +#include + +#include "../internal/detect_platform.h" + +namespace gemmlowp { + +// Part 1: Low-level integer-arithmetic primitives. +// The implementations here are generic implementations valid for +// scalar types (e.g. std::int32_t). Architecture-specific SIMD types +// (e.g. NEON int32x4_t) may be supported by providing +// specializations for them in separate files. +// +// The purpose of these primitives is two-fold: +// - They will be used to implement higher-level fixed-point +// abstractions, namely the FixedPoint class and its arithmetic +// operators. +// - They will be directly used to implement some more involved +// fixed-point computations, e.g. the fixed-point implementation +// of math functions such as tanh. + +// Some compile-time traits around raw types to handle SIMD aspects: +// number of lanes, underlying scalar type. +template +struct FixedPointRawTypeTraits {}; + +template <> +struct FixedPointRawTypeTraits { + typedef std::int32_t ScalarRawType; + static constexpr int kLanes = 1; +}; + +template <> +struct FixedPointRawTypeTraits { + typedef std::int16_t ScalarRawType; + static constexpr int kLanes = 1; +}; + +// Returns a SIMD value duplicating a scalar value across all lanes. +template +tRawType Dup(typename FixedPointRawTypeTraits::ScalarRawType x) { + return x; +} + +// Plain bit-wise AND +template +tIntegerType BitAnd(tIntegerType a, tIntegerType b) { + return a & b; +} + +// Plain bit-wise OR +template +tIntegerType BitOr(tIntegerType a, tIntegerType b) { + return a | b; +} + +// Plain bit-wise XOR +template +tIntegerType BitXor(tIntegerType a, tIntegerType b) { + return a ^ b; +} + +// Plain bit-wise NOT +template +tIntegerType BitNot(tIntegerType a) { + return ~a; +} + +// Integer addition. Not saturating. Overflow is undefined behavior. +template +tIntegerType Add(tIntegerType a, tIntegerType b) { + return a + b; +} + +// Integer subtraction. Not saturating. Overflow is undefined behavior. +template +tIntegerType Mul(tIntegerType a, tIntegerType b) { + return a * b; +} + +template +tIntegerType Sub(tIntegerType a, tIntegerType b) { + return a - b; +} + +// Integer unary negative. Not saturating. Overflow is undefined behavior. +template +tIntegerType Neg(tIntegerType a) { + return -a; +} + +// Integer arithmetic left-shift, equivalent to multiplying with a power of two. +// Negative values are OK. In case of overflow, no Undefined +// Behavior, but the results are implementation-defined (in practice, +// they currently are saturated, but we make no commitment to that). The idea +// is that the caller will want to implement the overflowing cases with +// saturation with compare-and-mask, so we don't care about the results +// in the overflow case, we just want to avoid undefined behavior. +// +// tIntegerType may be int32 or any narrower signed type. +template +tIntegerType ShiftLeft(tIntegerType a, int offset) { + const std::int64_t wide_a = static_cast(a); + const std::int64_t wide_shifted = wide_a * (1 << offset); + const auto min = std::numeric_limits::min(); + const auto max = std::numeric_limits::max(); + return wide_shifted < min + ? min + : wide_shifted > max ? max + : static_cast(wide_shifted); +} + +// Integer arithmetic right-shift. Not rounding. +// Relying on implementation-defined, but in-practice-consistent, +// C++ compiler behavior. +template +tIntegerType ShiftRight(tIntegerType a, int offset) { + return a >> offset; +} + +// Each bit of the result is set to the corresponding bit of either then_val or +// else_val depending on whether the corresponding bit of if_mask is set. +// Equivalent to the VBSL instruction in ARM NEON. +template +tIntegerType SelectUsingMask(tIntegerType if_mask, tIntegerType then_val, + tIntegerType else_val) { + return BitXor(BitAnd(if_mask, then_val), BitAnd(BitNot(if_mask), else_val)); +} + +// For each input scalar, the corresponding bits of the result are set if the +// input scalar is non-zero. +template +tIntegerType MaskIfNonZero(tIntegerType a) { + static constexpr tIntegerType zero = 0; + return a ? BitNot(zero) : zero; +} + +// For each input scalar, the corresponding bits of the result are set if the +// input scalar is zero. +template +tIntegerType MaskIfZero(tIntegerType a) { + return MaskIfNonZero(!a); +} + +// For each pair of input scalars, the corresponding bits of the result are +// set if the input scalars are equal. +template +tIntegerType MaskIfEqual(tIntegerType a, tIntegerType b) { + return MaskIfNonZero(a == b); +} + +// For each pair of input scalars, the corresponding bits of the result are +// set if the input scalars are not equal. +template +tIntegerType MaskIfNotEqual(tIntegerType a, tIntegerType b) { + return MaskIfNonZero(a != b); +} + +// For each pair of input scalars, the corresponding bits of the result are +// set if the input scalars a, b satisfy a > b. +template +tIntegerType MaskIfGreaterThan(tIntegerType a, tIntegerType b) { + return MaskIfNonZero(a > b); +} + +// For each pair of input scalars, the corresponding bits of the result are +// set if the input scalars a, b satisfy a >= b. +template +tIntegerType MaskIfGreaterThanOrEqual(tIntegerType a, tIntegerType b) { + return MaskIfNonZero(a >= b); +} + +// For each pair of input scalars, the corresponding bits of the result are +// set if the input scalars a, b satisfy a < b. +template +tIntegerType MaskIfLessThan(tIntegerType a, tIntegerType b) { + return MaskIfNonZero(a < b); +} + +// For each pair of input scalars, the corresponding bits of the result are +// set if the input scalars a, b satisfy a <= b. +template +tIntegerType MaskIfLessThanOrEqual(tIntegerType a, tIntegerType b) { + return MaskIfNonZero(a <= b); +} + +// Returns true if all of the input scalars are nonzero. +// This function may currently assume that each of the input scalars has either +// all or none of its bits set. Otherwise, its behavior is currently undefined. +template +bool All(tIntegerType a) { + return a; +} + +// Returns true if any of the input scalars are nonzero. +// This function may currently assume that each of the input scalars has either +// all or none of its bits set. Otherwise, its behavior is currently undefined. +template +bool Any(tIntegerType a) { + return a; +} + +// Returns (a+b)/2, rounded to the nearest integer. +// Equivalent to VRHADD in the ARM NEON instruction set. +template +IntegerType RoundingHalfSum(IntegerType a, IntegerType b) { + static_assert(std::is_same::value, "unimplemented"); + (void)b; + return a; +} + +template <> +inline std::int32_t RoundingHalfSum(std::int32_t a, std::int32_t b) { + std::int64_t a64 = a; + std::int64_t b64 = b; + std::int64_t sum = a64 + b64; + std::int64_t sign = sum >= 0 ? 1 : -1; + return static_cast((sum + sign) / 2); +} + +template <> +inline std::int16_t RoundingHalfSum(std::int16_t a, std::int16_t b) { + std::int32_t a32 = a; + std::int32_t b32 = b; + std::int32_t sum = a32 + b32; + std::int32_t sign = sum >= 0 ? 1 : -1; + return static_cast((sum + sign) / 2); +} + +template +IntegerType SaturatingAdd(IntegerType a, IntegerType b) { + static_assert(std::is_same::value, "unimplemented"); + (void)b; + return a; +} + +// So far this is only needed for int16. +template <> +inline std::int16_t SaturatingAdd(std::int16_t a, std::int16_t b) { + std::int32_t a32 = a; + std::int32_t b32 = b; + std::int32_t sum = a32 + b32; + return static_cast( + std::min(static_cast(32767), + std::max(static_cast(-32768), sum))); +} + +// Returns a+b, saturating if the integers are 16bit or narrower, +// otherwise just a plain addition. +template +struct AddSaturatingIf16BitImpl { + static IntegerType Run(IntegerType a, IntegerType b) { return Add(a, b); } +}; +template +struct AddSaturatingIf16BitImpl { + static IntegerType Run(IntegerType a, IntegerType b) { + return SaturatingAdd(a, b); + } +}; +template +IntegerType AddSaturatingIf16Bit(IntegerType a, IntegerType b) { + using ScalarType = + typename FixedPointRawTypeTraits::ScalarRawType; + return AddSaturatingIf16BitImpl::Run(a, + b); +} + +// Returns the integer that represents the product of two fixed-point +// numbers, interpreting all integers as fixed-point values in the +// interval [-1, 1), rounding to the nearest value, and saturating +// -1 * -1 to the maximum value (since 1 is not in the half-open +// interval [-1, 1)). +// +// [The explanation below specializes to std::int32_t for example purpose.] +// +// The mapping between IntegerType and the interval [-1, 1) is unique and +// implied by IntegerType, which is assumed to be signed. For example, +// for IntegerType==std::int32_t, the mapping is +// real_value = integer_value / 2^31. +// So in this case, and leaving aside rounding and saturating, this +// function computes ((a / 2^31) * (b / 2^31)) * 2^31, which simplifies to +// (a * b) / 2^31. +// +// The 'doubling' part in the name of this function comes from the fact that +// this operation is very close to a "multiply-high" operation, keeping only +// the top half bits, except that that would be effectively computing +// (a * b) / 2^32, +// so here we are computing 2x that, since +// 1/2^31 = 2 * 1/2^32. +// The idea is to use all of the available 32 bits in the destination int32 +// value. +// +// [End of the explanation specializing to int32.] +// +// This is equivalent to the VQRDMULH instruction in ARM NEON. +template +IntegerType SaturatingRoundingDoublingHighMul(IntegerType a, IntegerType b) { + static_assert(std::is_same::value, "unimplemented"); + (void)b; + return a; +} + +// This function implements the same computation as the ARMv7 NEON VQRDMULH +// instruction. +template <> +inline std::int32_t SaturatingRoundingDoublingHighMul(std::int32_t a, + std::int32_t b) { + bool overflow = a == b && a == std::numeric_limits::min(); + std::int64_t a_64(a); + std::int64_t b_64(b); + std::int64_t ab_64 = a_64 * b_64; + std::int32_t nudge = ab_64 >= 0 ? (1 << 30) : (1 - (1 << 30)); + std::int32_t ab_x2_high32 = + static_cast((ab_64 + nudge) / (1ll << 31)); + return overflow ? std::numeric_limits::max() : ab_x2_high32; +} + +template <> +inline std::int16_t SaturatingRoundingDoublingHighMul(std::int16_t a, + std::int16_t b) { + bool overflow = a == b && a == std::numeric_limits::min(); + std::int32_t a_32(a); + std::int32_t b_32(b); + std::int32_t ab_32 = a_32 * b_32; + std::int16_t nudge = ab_32 >= 0 ? (1 << 14) : (1 - (1 << 14)); + std::int16_t ab_x2_high16 = + static_cast((ab_32 + nudge) / (1 << 15)); + return overflow ? std::numeric_limits::max() : ab_x2_high16; +} + +// Correctly-rounded-to-nearest division by a power-of-two. +// Also known as a rounding arithmetic right shift. +template +inline IntegerType RoundingDivideByPOT(IntegerType x, int exponent) { + assert(exponent >= 0); + assert(exponent <= 31); + const IntegerType mask = Dup((1ll << exponent) - 1); + const IntegerType zero = Dup(0); + const IntegerType one = Dup(1); + const IntegerType remainder = BitAnd(x, mask); + const IntegerType threshold = + Add(ShiftRight(mask, 1), BitAnd(MaskIfLessThan(x, zero), one)); + return Add(ShiftRight(x, exponent), + BitAnd(MaskIfGreaterThan(remainder, threshold), one)); +} + +// Returns the product of a run-time integer value by a compile-time power +// of two, with either a positive exponent (equivalent to an arithmetic +// left shift, saturating) or a negative exponent (equivalent to an arithmetic +// right shift, rounding to nearest). +template 0 ? 1 : Exponent < 0 ? -1 : 0)> +struct ImplSaturatingRoundingMultiplyByPOT {}; + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static IntegerType eval(IntegerType x) { return x; } +}; + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static IntegerType eval(IntegerType x) { + using ScalarIntegerType = + typename FixedPointRawTypeTraits::ScalarRawType; + const IntegerType min = + Dup(std::numeric_limits::min()); + const IntegerType max = + Dup(std::numeric_limits::max()); + const int ScalarIntegerTypeBits = 8 * sizeof(ScalarIntegerType); + + const std::int32_t threshold = + ((1 << (ScalarIntegerTypeBits - 1 - Exponent)) - 1); + const IntegerType positive_mask = + MaskIfGreaterThan(x, Dup(threshold)); + const IntegerType negative_mask = + MaskIfLessThan(x, Dup(-threshold)); + + IntegerType result = ShiftLeft(x, Exponent); + result = SelectUsingMask(positive_mask, max, result); + result = SelectUsingMask(negative_mask, min, result); + return result; + } +}; + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static IntegerType eval(IntegerType x) { + return RoundingDivideByPOT(x, -Exponent); + } +}; + +template +IntegerType SaturatingRoundingMultiplyByPOT(IntegerType x) { + return ImplSaturatingRoundingMultiplyByPOT::eval(x); +} + +// Part 2: the FixedPoint class. + +// A FixedPoint object represents a fixed-point value stored in the underlying +// integer type tRawType, if tRawType is a plain scalar integer type. +// Alternatively, tRawType may be a SIMD type (e.g. NEON int32x4_t) in which +// case a FixedPoint object represents a corresponding SIMD vector of fixed +// point values. +// +// tIntegerBits describes the range of the fixed-point format: if +// tIntegerBits == m then the range of representable values is the half-open +// interval [-2^m; 2^m) where the open boundary on the right side means that +// 2^m is not representable (how close the maximum representable value is to +// it, depends on bit-depth of tRawType). +// +// In "Q format notation", +// https://en.wikipedia.org/wiki/Q_(number_format) +// we are describing the format +// Qm.n +// where +// m = tIntegerBits +// and +// n = NumberOfBits(tRawType) - (m + 1) +// Note that the (m + 1) in the above line is because we adopt the convention +// that we count the integer bits exclusively of the sign bit; so (m + 1) is +// the total number of integer bits inclusive of the sign bit. +// +// Accordingly, the number of integral representable values in our range +// [-2^m ; 2^m) +// is equal to 2^(m+1). +template +class FixedPoint { + public: + typedef tRawType RawType; + + typedef FixedPointRawTypeTraits RawTypeTraits; + typedef typename RawTypeTraits::ScalarRawType ScalarRawType; + + static constexpr int kTotalBits = 8 * sizeof(ScalarRawType); + static constexpr int kIntegerBits = tIntegerBits; + static constexpr int kFractionalBits = kTotalBits - 1 - kIntegerBits; + static_assert(kIntegerBits >= 0 && kIntegerBits < kTotalBits, + "bad IntegerBits"); + + typedef FixedPoint ScalarFixedPointType; + + static const ScalarRawType ScalarRawMin() { + return std::numeric_limits::min(); + } + + static const ScalarRawType ScalarRawMax() { + return std::numeric_limits::max(); + } + + static const ScalarRawType RawMin() { + return VectorFromScalar(ScalarRawMin()); + } + + static const ScalarRawType RawMax() { + return VectorFromScalar(ScalarRawMax()); + } + + static FixedPoint FromRaw(RawType x) { + FixedPoint retval; + retval.raw() = x; + return retval; + } + + static FixedPoint FromScalarRaw(ScalarRawType x) { + FixedPoint retval; + retval.raw() = Dup(x); + return retval; + } + + static FixedPoint FromScalarFixedPoint(ScalarFixedPointType x) { + return FromScalarRaw(x.raw()); + } + + template + static FixedPoint ConstantPOT() { + static constexpr int kOffset = kFractionalBits + Exponent; + static_assert( + kOffset < 31, + "Constant not exactly representable in this fixed-point format"); + return FromScalarRaw(ScalarRawType(1) << kOffset); + } + + static FixedPoint Zero() { return FromScalarRaw(0); } + + static FixedPoint One() { + return FromScalarRaw( + kIntegerBits == 0 + ? ScalarRawMax() + : (ScalarRawType(1) << (kIntegerBits == 0 ? 0 : kFractionalBits))); + } + + static FixedPoint FromDouble(double x) { + const double min_bound = static_cast(ScalarRawMin()); + const double max_bound = static_cast(ScalarRawMax()); + return FromScalarRaw(static_cast(std::min( + std::max(round(x * static_cast(1ll << kFractionalBits)), + min_bound), + max_bound))); + } + + RawType raw() const { return i_; } + RawType& raw() { return i_; } + + private: + RawType i_; +}; + +// Part 3: implementation of arithmetic operators for the +// FixedPoint class, and a few related functions. + +// A FixedPoint multiplication is just a +// SaturatingRoundingDoublingHighMul operation on the underlying +// raw integer values. The IntegerBits simply add up, as is obvious +// from the fact that the range is [-2^IntegerBits, 2^IntegerBits). +template +FixedPoint operator*( + FixedPoint a, + FixedPoint b) { + FixedPoint c; + c.raw() = SaturatingRoundingDoublingHighMul(a.raw(), b.raw()); + return c; +} + +// Tweaking IntegerBits gives exact multiplication by a power of two. +template +FixedPoint ExactMulByPot( + FixedPoint a) { + FixedPoint c; + c.raw() = a.raw(); + return c; +} + +// If we want to leave IntegerBits fixed, then multiplication +// by a power of two has to be saturating/rounding, not exact anymore. +template +FixedPoint SaturatingRoundingMultiplyByPOT( + FixedPoint a) { + return FixedPoint::FromRaw( + SaturatingRoundingMultiplyByPOT(a.raw())); +} + +// Generic arithmetic operators. + +#define MAKE_FIXEDPOINT_UNARY_FUNC(FuncName, ImplFuncName) \ + template \ + FixedPoint FuncName( \ + FixedPoint a) { \ + return FixedPoint::FromRaw(ImplFuncName(a.raw())); \ + } + +#define MAKE_FIXEDPOINT_BINARY_FUNC(FuncName, ImplFuncName) \ + template \ + FixedPoint FuncName( \ + FixedPoint a, \ + FixedPoint b) { \ + return FixedPoint::FromRaw( \ + ImplFuncName(a.raw(), b.raw())); \ + } + +MAKE_FIXEDPOINT_UNARY_FUNC(operator-, Neg) +MAKE_FIXEDPOINT_UNARY_FUNC(operator~, BitNot) +MAKE_FIXEDPOINT_BINARY_FUNC(operator+, Add) +MAKE_FIXEDPOINT_BINARY_FUNC(operator-, Sub) +MAKE_FIXEDPOINT_BINARY_FUNC(operator&, BitAnd) +MAKE_FIXEDPOINT_BINARY_FUNC(operator^, BitXor) +MAKE_FIXEDPOINT_BINARY_FUNC(operator|, BitOr) +MAKE_FIXEDPOINT_BINARY_FUNC(RoundingHalfSum, RoundingHalfSum) + +#undef MAKE_FIXEDPOINT_UNARY_FUNC +#undef MAKE_FIXEDPOINT_BINARY_FUNC + +#define MAKE_FIXEDPOINT_UNARY_FUNC_RETURNING_RAW(FuncName) \ + template \ + tRawType FuncName(FixedPoint a) { \ + return FuncName(a.raw()); \ + } + +#define MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(FuncName) \ + template \ + tRawType FuncName(FixedPoint a, \ + FixedPoint b) { \ + return FuncName(a.raw(), b.raw()); \ + } + +MAKE_FIXEDPOINT_UNARY_FUNC_RETURNING_RAW(MaskIfZero) +MAKE_FIXEDPOINT_UNARY_FUNC_RETURNING_RAW(MaskIfNonZero) +MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(MaskIfEqual) +MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(MaskIfNotEqual) +MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(MaskIfGreaterThan) +MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(MaskIfGreaterThanOrEqual) +MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(MaskIfLessThan) +MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW(MaskIfLessThanOrEqual) + +#undef MAKE_FIXEDPOINT_UNARY_FUNC_RETURNING_RAW +#undef MAKE_FIXEDPOINT_BINARY_FUNC_RETURNING_RAW + +template +FixedPoint SelectUsingMask( + tRawType if_mask, FixedPoint then_val, + FixedPoint else_val) { + return FixedPoint::FromRaw( + SelectUsingMask(if_mask, then_val.raw(), else_val.raw())); +} + +template +bool operator==(FixedPoint a, + FixedPoint b) { + return All(MaskIfEqual(a.raw(), b.raw())); +} + +template +bool operator!=(FixedPoint a, + FixedPoint b) { + return !(a == b); +} + +template +FixedPoint SaturatingAdd( + FixedPoint a, + FixedPoint b) { + return FixedPoint::FromRaw( + SaturatingAdd(a.raw(), b.raw())); +} + +template +FixedPoint AddSaturatingIf16Bit( + FixedPoint a, + FixedPoint b) { + return FixedPoint::FromRaw( + AddSaturatingIf16Bit(a.raw(), b.raw())); +} + +// Conversion to floating-point. +template +double ToDouble(FixedPoint x) { + static_assert(FixedPointRawTypeTraits::kLanes == 1, + "not applicable to SIMD types"); + typedef FixedPoint F; + return x.raw() / static_cast(1ll << F::kFractionalBits); +} + +// Rescale changes the number of IntegerBits and updates the underlying +// raw integer value accordingly. +template +FixedPoint Rescale( + FixedPoint x) { + static constexpr int kExponent = tIntegerBitsSrc - tIntegerBitsDst; + FixedPoint result; + result.raw() = SaturatingRoundingMultiplyByPOT(x.raw()); + return result; +} + +// CheckedFixedPointConstant allows to specify fixed-point constants +// initialized as real numbers, in a way that does not compile floating-point +// arithmetic in production code, yet still checks agreement with the +// floating-point expressions when asserts are enabled. +// +// The raw integer value provided is always a int32, encoding a 32-bit +// fixed-point value, regardless of the actual Scalar type. This allows +// writing generic code that applies just as well to the 32-bit and 16-bit +// cases. In the 16-bit case, the raw integer value is internally +// rounding-shifted by 16 bits to the right. +template +inline typename FixedPointType::ScalarRawType RescaleConstantInitializer( + std::int32_t int32_value) { + typedef typename FixedPointType::ScalarRawType ScalarRawType; + static constexpr int ScalarTypeBits = 8 * sizeof(ScalarRawType); + return static_cast( + RoundingDivideByPOT(int32_value, 32 - ScalarTypeBits)); +} +#ifdef GEMMLOWP_ENABLE_FIXEDPOINT_CONSTANTS_CHECKS +template +FixedPointType CheckedFixedPointConstant(std::int32_t raw_value, + double double_value) { + const FixedPointType result = FixedPointType::FromScalarRaw(raw_value); + assert(result == FixedPointType::FromDouble(double_value)); + return result; +} +#define GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(FixedPointType, \ + ScalarRawInt32Value, DoubleValue) \ + (gemmlowp::CheckedFixedPointConstant( \ + gemmlowp::RescaleConstantInitializer( \ + ScalarRawInt32Value), \ + DoubleValue)) + +#else +#define GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(FixedPointType, \ + ScalarRawInt32Value, DoubleValue) \ + (FixedPointType::FromScalarRaw( \ + gemmlowp::RescaleConstantInitializer( \ + ScalarRawInt32Value))) +#endif + +// Implementation of exponential function. + +// Returns exp(x) for x in [-1/4, 0). +template +FixedPoint exp_on_interval_between_negative_one_quarter_and_0_excl( + FixedPoint a) { + typedef FixedPoint F; + const F constant_term = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F, 1895147668, std::exp(-1.0 / 8.0)); + const F constant_1_over_3 = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F, 715827883, 1.0 / 3.0); + // We're evaluating a Taylor expansion around -1/8, so we do the change of + // variable: x = a + 1/8. + // In fixed-point with 0 integer bits, 1/8 is represented by 1 << 28. + F x = a + F::template ConstantPOT<-3>(); + F x2 = x * x; + F x3 = x2 * x; + F x4 = x2 * x2; + F x4_over_4 = SaturatingRoundingMultiplyByPOT<-2>(x4); + F x4_over_24_plus_x3_over_6_plus_x2_over_2 = + SaturatingRoundingMultiplyByPOT<-1>( + ((x4_over_4 + x3) * constant_1_over_3) + x2); + return AddSaturatingIf16Bit( + constant_term, + constant_term * (x + x4_over_24_plus_x3_over_6_plus_x2_over_2)); +} + +// Returns exp(x) for x < 0. +template +FixedPoint exp_on_negative_values( + FixedPoint a) { + typedef FixedPoint InputF; + typedef FixedPoint ResultF; + static constexpr int kFractionalBits = InputF::kFractionalBits; + static constexpr int kIntegerBits = InputF::kIntegerBits; + const InputF kOneQuarter = InputF::template ConstantPOT<-2>(); + InputF mask = kOneQuarter - InputF::FromScalarRaw(1); + InputF a_mod_quarter_minus_one_quarter = (a & mask) - kOneQuarter; + ResultF result = exp_on_interval_between_negative_one_quarter_and_0_excl( + Rescale<0>(a_mod_quarter_minus_one_quarter)); + tRawType remainder = (a_mod_quarter_minus_one_quarter - a).raw(); + +#define GEMMLOWP_EXP_BARREL_SHIFTER(Exponent, FixedPointMultiplier) \ + if (kIntegerBits > Exponent) { \ + const ResultF kMultiplier = GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT( \ + ResultF, FixedPointMultiplier, std::exp(-std::pow(2.0, Exponent))); \ + static constexpr int kShiftAmount = \ + kIntegerBits > Exponent ? kFractionalBits + Exponent : 0; \ + result = SelectUsingMask( \ + MaskIfNonZero(BitAnd(remainder, Dup(1 << kShiftAmount))), \ + result * kMultiplier, result); \ + } + + GEMMLOWP_EXP_BARREL_SHIFTER(-2, 1672461947); + GEMMLOWP_EXP_BARREL_SHIFTER(-1, 1302514674); + GEMMLOWP_EXP_BARREL_SHIFTER(+0, 790015084); + GEMMLOWP_EXP_BARREL_SHIFTER(+1, 290630308); + GEMMLOWP_EXP_BARREL_SHIFTER(+2, 39332535); + GEMMLOWP_EXP_BARREL_SHIFTER(+3, 720401); + GEMMLOWP_EXP_BARREL_SHIFTER(+4, 242); + +#undef GEMMLOWP_EXP_BARREL_SHIFTER + + static constexpr int clampB = kIntegerBits > 5 ? 36 - kIntegerBits : 0; + if (kIntegerBits > 5) { + const InputF clamp = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(InputF, -(1 << clampB), -32.0); + result = SelectUsingMask(MaskIfLessThan(a, clamp), ResultF::Zero(), result); + } + + result = SelectUsingMask(MaskIfZero(a), ResultF::One(), result); + return result; +} + +// Implementation of tanh: (1 - exp(-2x)) / (1 + exp(-2x)). + +// Returns (1 - x) / (1 + x) for x in (0, 1). +template +FixedPoint one_minus_x_over_one_plus_x_for_x_in_0_1( + FixedPoint a) { + typedef FixedPoint F0; + typedef FixedPoint F2; + F0 half_denominator = RoundingHalfSum(a, F0::One()); + // Newton-Raphson division + // https://en.wikipedia.org/wiki/Division_algorithm#Newton.E2.80.93Raphson_division + // Refer to that page for the logic behind the 48/17 and 32/17 constants. + const F2 constant_48_over_17 = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F2, 1515870810, 48.0 / 17.0); + const F2 constant_neg_32_over_17 = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F2, -1010580540, -32.0 / 17.0); + F2 x = constant_48_over_17 + half_denominator * constant_neg_32_over_17; + for (int i = 0; i < 3; i++) { + F2 half_denominator_times_x = half_denominator * x; + F2 one_minus_half_denominator_times_x = + F2::One() - half_denominator_times_x; + x = x + Rescale<2>(x * one_minus_half_denominator_times_x); + } + return Rescale<0>(x - F2::One()); +} + +// Returns -tanh(x) for x < 0. +template +FixedPoint neg_tanh_on_negative_values( + FixedPoint a) { + return one_minus_x_over_one_plus_x_for_x_in_0_1( + exp_on_negative_values(ExactMulByPot<1>(a))); +} + +// Returns tanh(x) for any x. +template +FixedPoint tanh(FixedPoint a) { + typedef FixedPoint InputF; + typedef FixedPoint ResultF; + tRawType mask_if_negative = MaskIfLessThan(a, InputF::Zero()); + tRawType mask_if_zero = MaskIfZero(a); + InputF n = SelectUsingMask(mask_if_negative, a, -a); + ResultF t = neg_tanh_on_negative_values(n); + return SelectUsingMask(mask_if_zero, ResultF::Zero(), + SelectUsingMask(mask_if_negative, -t, t)); +} + +// Implementation of logistic function. + +// Returns 1 / (1 + x) for x in (0, 1). +template +FixedPoint one_over_one_plus_x_for_x_in_0_1( + FixedPoint a) { + typedef FixedPoint F0; + typedef FixedPoint F2; + F0 half_denominator = RoundingHalfSum(a, F0::One()); + // Newton-Raphson division + // https://en.wikipedia.org/wiki/Division_algorithm#Newton.E2.80.93Raphson_division + // Refer to that page for the logic behind the 48/17 and 32/17 constants. + const F2 constant_48_over_17 = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F2, 1515870810, 48.0 / 17.0); + const F2 constant_neg_32_over_17 = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(F2, -1010580540, -32.0 / 17.0); + F2 x = constant_48_over_17 + half_denominator * constant_neg_32_over_17; + for (int i = 0; i < 3; i++) { + F2 half_denominator_times_x = half_denominator * x; + F2 one_minus_half_denominator_times_x = + F2::One() - half_denominator_times_x; + x = x + Rescale<2>(x * one_minus_half_denominator_times_x); + } + return Rescale<0>(ExactMulByPot<-1>(x)); +} + +// Returns logistic(x) = 1 / (1 + exp(-x)) for x > 0. +template +FixedPoint logistic_on_positive_values( + FixedPoint a) { + return one_over_one_plus_x_for_x_in_0_1(exp_on_negative_values(-a)); +} + +// Returns logistic(x) = 1 / (1 + exp(-x)) for any x. +template +FixedPoint logistic(FixedPoint a) { + typedef FixedPoint InputF; + typedef FixedPoint ResultF; + tRawType mask_if_positive = MaskIfGreaterThan(a, InputF::Zero()); + tRawType mask_if_zero = MaskIfZero(a); + InputF abs_input = SelectUsingMask(mask_if_positive, a, -a); + ResultF result_if_positive = logistic_on_positive_values(abs_input); + ResultF result_if_negative = ResultF::One() - result_if_positive; + const ResultF one_half = + GEMMLOWP_CHECKED_FIXEDPOINT_CONSTANT(ResultF, 1 << 30, 0.5); + return SelectUsingMask(mask_if_zero, one_half, + SelectUsingMask(mask_if_positive, result_if_positive, + result_if_negative)); +} + +} // end namespace gemmlowp + +#ifdef GEMMLOWP_NEON +#include "./fixedpoint_neon.h" +#elif defined(GEMMLOWP_AVX2) +#include "./fixedpoint_avx.h" +#elif defined(GEMMLOWP_SSE4) +#include "./fixedpoint_sse.h" +#elif defined(GEMMLOWP_MSA) +#include "./fixedpoint_msa.h" +#endif + +#endif // GEMMLOWP_INTERNAL_FIXEDPOINT_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint_neon.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint_neon.h new file mode 100644 index 000000000..646c5907b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint_neon.h @@ -0,0 +1,331 @@ +// Copyright 2015 The Gemmlowp Authors. All Rights Reserved. +// +// 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. + +// fixedpoint_neon.h: optimized NEON specializations of the templates +// in fixedpoint.h. + +#ifndef GEMMLOWP_INTERNAL_FIXEDPOINT_NEON_H_ +#define GEMMLOWP_INTERNAL_FIXEDPOINT_NEON_H_ + +#include + +namespace gemmlowp { + +template <> +struct FixedPointRawTypeTraits { + typedef std::int32_t ScalarRawType; + static constexpr int kLanes = 4; +}; + +template <> +struct FixedPointRawTypeTraits { + typedef std::int16_t ScalarRawType; + static constexpr int kLanes = 8; +}; + +template <> +inline int32x4_t BitAnd(int32x4_t a, int32x4_t b) { + return vandq_s32(a, b); +} + +template <> +inline int16x8_t BitAnd(int16x8_t a, int16x8_t b) { + return vandq_s16(a, b); +} + +template <> +inline int32x4_t BitOr(int32x4_t a, int32x4_t b) { + return vorrq_s32(a, b); +} + +template <> +inline int16x8_t BitOr(int16x8_t a, int16x8_t b) { + return vorrq_s16(a, b); +} + +template <> +inline int32x4_t BitXor(int32x4_t a, int32x4_t b) { + return veorq_s32(a, b); +} + +template <> +inline int16x8_t BitXor(int16x8_t a, int16x8_t b) { + return veorq_s16(a, b); +} + +template <> +inline int32x4_t BitNot(int32x4_t a) { + return veorq_s32(a, vdupq_n_s32(-1)); +} + +template <> +inline int16x8_t BitNot(int16x8_t a) { + return veorq_s16(a, vdupq_n_s16(-1)); +} + +template <> +inline int32x4_t Add(int32x4_t a, int32x4_t b) { + return vaddq_s32(a, b); +} + +template <> +inline int16x8_t Add(int16x8_t a, int16x8_t b) { + return vaddq_s16(a, b); +} + +template <> +inline int32x4_t Sub(int32x4_t a, int32x4_t b) { + return vsubq_s32(a, b); +} + +template <> +inline int16x8_t Sub(int16x8_t a, int16x8_t b) { + return vsubq_s16(a, b); +} + +template <> +inline int32x4_t Neg(int32x4_t a) { + return vnegq_s32(a); +} + +template <> +inline int16x8_t Neg(int16x8_t a) { + return vnegq_s16(a); +} + +template <> +inline int32x4_t ShiftLeft(int32x4_t a, int offset) { + return vshlq_s32(a, vdupq_n_s32(offset)); +} + +template <> +inline int16x8_t ShiftLeft(int16x8_t a, int offset) { + return vshlq_s16(a, vdupq_n_s16(offset)); +} + +template <> +inline int32x4_t ShiftRight(int32x4_t a, int offset) { + return vshlq_s32(a, vdupq_n_s32(-offset)); +} + +template <> +inline int16x8_t ShiftRight(int16x8_t a, int offset) { + return vshlq_s16(a, vdupq_n_s16(-offset)); +} + +template <> +inline int32x4_t SelectUsingMask(int32x4_t if_mask, int32x4_t then_val, + int32x4_t else_val) { + return vbslq_s32(vreinterpretq_u32_s32(if_mask), then_val, else_val); +} + +template <> +inline int16x8_t SelectUsingMask(int16x8_t if_mask, int16x8_t then_val, + int16x8_t else_val) { + return vbslq_s16(vreinterpretq_u16_s16(if_mask), then_val, else_val); +} + +template <> +inline int32x4_t MaskIfEqual(int32x4_t a, int32x4_t b) { + return vreinterpretq_s32_u32(vceqq_s32(a, b)); +} + +template <> +inline int16x8_t MaskIfEqual(int16x8_t a, int16x8_t b) { + return vreinterpretq_s16_u16(vceqq_s16(a, b)); +} + +template <> +inline int32x4_t MaskIfNotEqual(int32x4_t a, int32x4_t b) { + return BitNot(MaskIfEqual(a, b)); +} + +template <> +inline int16x8_t MaskIfNotEqual(int16x8_t a, int16x8_t b) { + return BitNot(MaskIfEqual(a, b)); +} + +template <> +inline int32x4_t MaskIfZero(int32x4_t a) { + return MaskIfEqual(a, vdupq_n_s32(0)); +} + +template <> +inline int16x8_t MaskIfZero(int16x8_t a) { + return MaskIfEqual(a, vdupq_n_s16(0)); +} + +template <> +inline int32x4_t MaskIfNonZero(int32x4_t a) { + return vreinterpretq_s32_u32(vtstq_s32(a, a)); +} + +template <> +inline int16x8_t MaskIfNonZero(int16x8_t a) { + return vreinterpretq_s16_u16(vtstq_s16(a, a)); +} + +template <> +inline int32x4_t MaskIfGreaterThan(int32x4_t a, int32x4_t b) { + return vreinterpretq_s32_u32(vcgtq_s32(a, b)); +} + +template <> +inline int16x8_t MaskIfGreaterThan(int16x8_t a, int16x8_t b) { + return vreinterpretq_s16_u16(vcgtq_s16(a, b)); +} + +template <> +inline int32x4_t MaskIfGreaterThanOrEqual(int32x4_t a, int32x4_t b) { + return vreinterpretq_s32_u32(vcgeq_s32(a, b)); +} + +template <> +inline int16x8_t MaskIfGreaterThanOrEqual(int16x8_t a, int16x8_t b) { + return vreinterpretq_s16_u16(vcgeq_s16(a, b)); +} + +template <> +inline int32x4_t MaskIfLessThan(int32x4_t a, int32x4_t b) { + return vreinterpretq_s32_u32(vcltq_s32(a, b)); +} + +template <> +inline int16x8_t MaskIfLessThan(int16x8_t a, int16x8_t b) { + return vreinterpretq_s16_u16(vcltq_s16(a, b)); +} + +template <> +inline int32x4_t MaskIfLessThanOrEqual(int32x4_t a, int32x4_t b) { + return vreinterpretq_s32_u32(vcleq_s32(a, b)); +} + +template <> +inline int16x8_t MaskIfLessThanOrEqual(int16x8_t a, int16x8_t b) { + return vreinterpretq_s16_u16(vcleq_s16(a, b)); +} + +template <> +inline bool All(int32x4_t a) { + a = vandq_s32(a, vextq_s32(a, a, 1)); + a = vandq_s32(a, vextq_s32(a, a, 2)); + return vgetq_lane_s32(a, 0); +} + +template <> +inline bool All(int16x8_t a) { + a = vandq_s16(a, vextq_s16(a, a, 1)); + a = vandq_s16(a, vextq_s16(a, a, 2)); + a = vandq_s16(a, vextq_s16(a, a, 4)); + return vgetq_lane_s16(a, 0); +} + +template <> +inline bool Any(int32x4_t a) { + a = vorrq_s32(a, vextq_s32(a, a, 1)); + a = vorrq_s32(a, vextq_s32(a, a, 2)); + return vgetq_lane_s32(a, 0); +} + +template <> +inline bool Any(int16x8_t a) { + a = vorrq_s16(a, vextq_s16(a, a, 1)); + a = vorrq_s16(a, vextq_s16(a, a, 2)); + a = vorrq_s16(a, vextq_s16(a, a, 4)); + return vgetq_lane_s16(a, 0); +} + +template <> +inline int32x4_t RoundingHalfSum(int32x4_t a, int32x4_t b) { + return vrhaddq_s32(a, b); +} + +template <> +inline int16x8_t RoundingHalfSum(int16x8_t a, int16x8_t b) { + return vrhaddq_s16(a, b); +} + +template <> +inline int32x4_t SaturatingRoundingDoublingHighMul(int32x4_t a, int32x4_t b) { + return vqrdmulhq_s32(a, b); +} + +template <> +inline int16x8_t SaturatingRoundingDoublingHighMul(int16x8_t a, int16x8_t b) { + return vqrdmulhq_s16(a, b); +} + +template <> +inline int32x4_t RoundingDivideByPOT(int32x4_t x, int exponent) { + const int32x4_t shift_vec = vdupq_n_s32(-exponent); + const int32x4_t fixup = vshrq_n_s32(vandq_s32(x, shift_vec), 31); + const int32x4_t fixed_up_x = vqaddq_s32(x, fixup); + return vrshlq_s32(fixed_up_x, shift_vec); +} + +template <> +inline int16x8_t RoundingDivideByPOT(int16x8_t x, int exponent) { + const int16x8_t shift_vec = vdupq_n_s16(-exponent); + const int16x8_t fixup = vshrq_n_s16(vandq_s16(x, shift_vec), 15); + const int16x8_t fixed_up_x = vqaddq_s16(x, fixup); + return vrshlq_s16(fixed_up_x, shift_vec); +} + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static int32x4_t eval(int32x4_t x) { return vqshlq_n_s32(x, Exponent); } +}; + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static int32x4_t eval(int32x4_t x) { + const int32x4_t fixup = vshrq_n_s32(x, 31); + const int32x4_t fixed_up_x = vqaddq_s32(x, fixup); + return vrshrq_n_s32(fixed_up_x, -Exponent); + } +}; + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static int16x8_t eval(int16x8_t x) { return vqshlq_n_s16(x, Exponent); } +}; + +template +struct ImplSaturatingRoundingMultiplyByPOT { + static int16x8_t eval(int16x8_t x) { + const int16x8_t fixup = vshrq_n_s16(x, 15); + const int16x8_t fixed_up_x = vqaddq_s16(x, fixup); + return vrshrq_n_s16(fixed_up_x, -Exponent); + } +}; + +template <> +inline int32x4_t Dup(std::int32_t x) { + return vdupq_n_s32(x); +} + +template <> +inline int16x8_t Dup(std::int16_t x) { + return vdupq_n_s16(x); +} + +// So far this is only needed for int16. +template <> +inline int16x8_t SaturatingAdd(int16x8_t a, int16x8_t b) { + return vqaddq_s16(a, b); +} + +} // end namespace gemmlowp + +#endif // GEMMLOWP_INTERNAL_FIXEDPOINT_NEON_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint_sse.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint_sse.h new file mode 100644 index 000000000..45e0e5597 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/fixedpoint/fixedpoint_sse.h @@ -0,0 +1,384 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// 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. + +// fixedpoint_SSE.h: optimized SSE specializations of the templates +// in fixedpoint.h. + +#ifndef GEMMLOWP_INTERNAL_FIXEDPOINT_SSE_H_ +#define GEMMLOWP_INTERNAL_FIXEDPOINT_SSE_H_ + +#include +#include "third_party/gemmlowp/fixedpoint/fixedpoint.h" + +namespace gemmlowp { + +// SSE intrinsics are not finely typed: there is a single __m128i vector +// type that does not distinguish between "int32x4" and "int16x8" use +// cases, unlike the NEON equivalents. Because we had initially focused +// on int32x4, we did not pay attention and specialized these fixedpoint +// templates directly for __m128i hardcoding the int32x4 semantics, +// not leaving room for int16x8 semantics. Amending that by adding a separate +// data type, int16x8_m128i, that wraps __m128i while being a separate +// type. +struct int16x8_m128i { + int16x8_m128i() {} + explicit int16x8_m128i(__m128i w) : v(w) {} + ~int16x8_m128i() {} + + __m128i v; +}; + +template <> +struct FixedPointRawTypeTraits<__m128i> { + typedef std::int32_t ScalarRawType; + static constexpr int kLanes = 4; +}; + +template <> +struct FixedPointRawTypeTraits { + typedef std::int16_t ScalarRawType; + static constexpr int kLanes = 8; +}; + +template <> +inline __m128i BitAnd(__m128i a, __m128i b) { + return _mm_and_si128(a, b); +} + +template <> +inline int16x8_m128i BitAnd(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_and_si128(a.v, b.v)); +} + +template <> +inline __m128i BitOr(__m128i a, __m128i b) { + return _mm_or_si128(a, b); +} + +template <> +inline int16x8_m128i BitOr(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_or_si128(a.v, b.v)); +} + +template <> +inline __m128i BitXor(__m128i a, __m128i b) { + return _mm_xor_si128(a, b); +} + +template <> +inline int16x8_m128i BitXor(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_xor_si128(a.v, b.v)); +} + +template <> +inline __m128i BitNot(__m128i a) { + return _mm_andnot_si128(a, _mm_set1_epi32(-1)); +} + +template <> +inline int16x8_m128i BitNot(int16x8_m128i a) { + return int16x8_m128i(_mm_andnot_si128(a.v, _mm_set1_epi16(-1))); +} + +template <> +inline __m128i Add(__m128i a, __m128i b) { + return _mm_add_epi32(a, b); +} + +template <> +inline int16x8_m128i Add(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_add_epi16(a.v, b.v)); +} + +template <> +inline __m128i Mul(__m128i a, __m128i b) { + return _mm_mullo_epi32(a, b); +} + +template <> +inline int16x8_m128i Mul(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_mullo_epi16(a.v, b.v)); +} + +template <> +inline __m128i Sub(__m128i a, __m128i b) { + return _mm_sub_epi32(a, b); +} + +template <> +inline int16x8_m128i Sub(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_sub_epi16(a.v, b.v)); +} + +template <> +inline __m128i Neg(__m128i a) { + return _mm_sign_epi32(a, _mm_set1_epi32(-1)); +} + +template <> +inline int16x8_m128i Neg(int16x8_m128i a) { + return int16x8_m128i(_mm_sign_epi16(a.v, _mm_set1_epi16(-1))); +} + +template <> +inline __m128i ShiftLeft(__m128i a, int offset) { + return _mm_slli_epi32(a, offset); +} + +template <> +inline int16x8_m128i ShiftLeft(int16x8_m128i a, int offset) { + return int16x8_m128i(_mm_slli_epi16(a.v, offset)); +} + +template <> +inline __m128i ShiftRight(__m128i a, int offset) { + return _mm_srai_epi32(a, offset); +} + +template <> +inline int16x8_m128i ShiftRight(int16x8_m128i a, int offset) { + return int16x8_m128i(_mm_srai_epi16(a.v, offset)); +} + +template <> +inline __m128i SelectUsingMask(__m128i if_mask, __m128i then_val, + __m128i else_val) { + // borrowed from Intel's arm_neon_sse.h header. + return _mm_or_si128(_mm_and_si128(if_mask, then_val), + _mm_andnot_si128(if_mask, else_val)); +} + +template <> +inline int16x8_m128i SelectUsingMask(int16x8_m128i if_mask, + int16x8_m128i then_val, + int16x8_m128i else_val) { + // borrowed from Intel's arm_neon_sse.h header. + return int16x8_m128i(SelectUsingMask(if_mask.v, then_val.v, else_val.v)); +} + +template <> +inline __m128i MaskIfEqual(__m128i a, __m128i b) { + return _mm_cmpeq_epi32(a, b); +} + +template <> +inline int16x8_m128i MaskIfEqual(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_cmpeq_epi16(a.v, b.v)); +} + +template <> +inline __m128i MaskIfNotEqual(__m128i a, __m128i b) { + return BitNot(MaskIfEqual(a, b)); +} + +template <> +inline int16x8_m128i MaskIfNotEqual(int16x8_m128i a, int16x8_m128i b) { + return BitNot(MaskIfEqual(a, b)); +} + +template <> +inline __m128i MaskIfZero(__m128i a) { + return MaskIfEqual(a, _mm_set1_epi32(0)); +} + +template <> +inline int16x8_m128i MaskIfZero(int16x8_m128i a) { + return MaskIfEqual(a, int16x8_m128i(_mm_set1_epi16(0))); +} + +template <> +inline __m128i MaskIfNonZero(__m128i a) { + return MaskIfNotEqual(a, _mm_set1_epi32(0)); +} + +template <> +inline int16x8_m128i MaskIfNonZero(int16x8_m128i a) { + return MaskIfNotEqual(a, int16x8_m128i(_mm_set1_epi16(0))); +} + +template <> +inline __m128i MaskIfGreaterThan(__m128i a, __m128i b) { + return _mm_cmpgt_epi32(a, b); +} + +template <> +inline int16x8_m128i MaskIfGreaterThan(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_cmpgt_epi16(a.v, b.v)); +} + +template <> +inline __m128i MaskIfLessThan(__m128i a, __m128i b) { + return _mm_cmplt_epi32(a, b); +} + +template <> +inline int16x8_m128i MaskIfLessThan(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_cmplt_epi16(a.v, b.v)); +} + +template <> +inline __m128i MaskIfGreaterThanOrEqual(__m128i a, __m128i b) { + return BitNot(MaskIfLessThan(a, b)); +} + +template <> +inline int16x8_m128i MaskIfGreaterThanOrEqual(int16x8_m128i a, + int16x8_m128i b) { + return BitNot(MaskIfLessThan(a, b)); +} + +template <> +inline __m128i MaskIfLessThanOrEqual(__m128i a, __m128i b) { + return BitNot(MaskIfGreaterThan(a, b)); +} + +template <> +inline int16x8_m128i MaskIfLessThanOrEqual(int16x8_m128i a, int16x8_m128i b) { + return BitNot(MaskIfGreaterThan(a, b)); +} + +/* Assumptions: + - All and Any are used on masks. + - masks are all_ones for true lanes, all_zeroes otherwise. +Hence, All means all 128bits set, and Any means any bit set. +*/ + +template <> +inline bool All(__m128i a) { + return _mm_testc_si128(a, a); +} + +template <> +inline bool All(int16x8_m128i a) { + return _mm_testc_si128(a.v, a.v); +} + +template <> +inline bool Any(__m128i a) { + return !_mm_testz_si128(a, a); +} + +template <> +inline bool Any(int16x8_m128i a) { + return !_mm_testz_si128(a.v, a.v); +} + +template <> +inline __m128i RoundingHalfSum(__m128i a, __m128i b) { + /* __m128i round_bit_mask, a_over_2, b_over_2, round_bit, sum; */ + /* We divide the inputs before the add to avoid the overflow and costly test + */ + /* of checking if an overflow occured on signed add */ + /* round_bit_mask = _mm_set1_epi32(1); */ + /* a_over_2 = _mm_srai_epi32(a, 1); */ + /* b_over_2 = _mm_srai_epi32(b, 1); */ + /* sum = Add(a_over_2, b_over_2); */ + /* round_bit = _mm_sign_epi32(BitAnd(BitOr(a,b), round_bit_mask), sum); */ + /* return Add(sum, round_bit); */ + + /* Other possibility detecting overflow and xor the sign if an overflow + * happened*/ + __m128i one, sign_bit_mask, sum, rounded_half_sum, overflow, result; + one = _mm_set1_epi32(1); + sign_bit_mask = _mm_set1_epi32(0x80000000); + sum = Add(a, b); + rounded_half_sum = _mm_srai_epi32(Add(sum, one), 1); + overflow = + BitAnd(BitAnd(BitXor(a, rounded_half_sum), BitXor(b, rounded_half_sum)), + sign_bit_mask); + result = BitXor(rounded_half_sum, overflow); + return result; +} + +template <> +inline int16x8_m128i RoundingHalfSum(int16x8_m128i a, int16x8_m128i b) { + // Idea: go to unsigned to use _mm_avg_epu16, + // borrowed from Intel's arm_neon_sse.h header. + __m128i constant_neg_32768 = _mm_set1_epi16(-32768); + __m128i a_unsigned = _mm_sub_epi16(a.v, constant_neg_32768); + __m128i b_unsigned = _mm_sub_epi16(b.v, constant_neg_32768); + __m128i avg_unsigned = _mm_avg_epu16(a_unsigned, b_unsigned); + __m128i avg = _mm_add_epi16(avg_unsigned, constant_neg_32768); + return int16x8_m128i(avg); +} + +template <> +inline __m128i SaturatingRoundingDoublingHighMul(__m128i a, __m128i b) { + __m128i min, saturation_mask, a0_a2, a1_a3, b0_b2, b1_b3; + __m128i a0b0_a2b2, a1b1_a3b3, a0b0_a2b2_rounded, a1b1_a3b3_rounded; + __m128i a0b0_a2b2_rounded_2x, a1b1_a3b3_rounded_2x, result; + __m128i nudge; + + // saturation only happen if a == b == INT_MIN + min = _mm_set1_epi32(std::numeric_limits::min()); + saturation_mask = BitAnd(MaskIfEqual(a, b), MaskIfEqual(a, min)); + + // a = a0 | a1 | a2 | a3 + // b = b0 | b1 | b2 | b3 + a0_a2 = a; + a1_a3 = _mm_srli_si128(a, 4); + b0_b2 = b; + b1_b3 = _mm_srli_si128(b, 4); + + a0b0_a2b2 = _mm_mul_epi32(a0_a2, b0_b2); + a1b1_a3b3 = _mm_mul_epi32(a1_a3, b1_b3); + + // do the rounding and take into account that it will be doubled + nudge = _mm_set1_epi64x(1 << 30); + a0b0_a2b2_rounded = _mm_add_epi64(a0b0_a2b2, nudge); + a1b1_a3b3_rounded = _mm_add_epi64(a1b1_a3b3, nudge); + + // do the doubling + a0b0_a2b2_rounded_2x = _mm_slli_epi64(a0b0_a2b2_rounded, 1); + a1b1_a3b3_rounded_2x = _mm_slli_epi64(a1b1_a3b3_rounded, 1); + + // get the high part of the products + result = _mm_blend_epi16(_mm_srli_si128(a0b0_a2b2_rounded_2x, 4), + a1b1_a3b3_rounded_2x, 0xcc); + + // saturate those which overflowed + return SelectUsingMask(saturation_mask, min, result); +} + +template <> +inline int16x8_m128i SaturatingRoundingDoublingHighMul(int16x8_m128i a, + int16x8_m128i b) { + // Idea: use _mm_mulhrs_epi16 then saturate with a bit-operation, + // borrowed from Intel's arm_neon_sse.h header. + __m128i result_unsaturated = _mm_mulhrs_epi16(a.v, b.v); + __m128i saturation_mask = + _mm_cmpeq_epi16(result_unsaturated, _mm_set1_epi16(0x8000)); + __m128i result = _mm_xor_si128(result_unsaturated, saturation_mask); + return int16x8_m128i(result); +} + +template <> +inline __m128i Dup<__m128i>(std::int32_t x) { + return _mm_set1_epi32(x); +} + +template <> +inline int16x8_m128i Dup(std::int16_t x) { + return int16x8_m128i(_mm_set1_epi16(x)); +} + +// So far this is only needed for int16. +template <> +inline int16x8_m128i SaturatingAdd(int16x8_m128i a, int16x8_m128i b) { + return int16x8_m128i(_mm_adds_epi16(a.v, b.v)); +} + +} // end namespace gemmlowp + +#endif // GEMMLOWP_INTERNAL_FIXEDPOINT_SSE_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/internal/detect_platform.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/internal/detect_platform.h new file mode 100644 index 000000000..6f06d19f6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/gemmlowp/internal/detect_platform.h @@ -0,0 +1,166 @@ +// Copyright 2018 The Gemmlowp Authors. All Rights Reserved. +// +// 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. + +// detect_platform.h: Sets up macros that control architecture-specific +// features of gemmlowp's implementation. + +#ifndef GEMMLOWP_INTERNAL_DETECT_PLATFORM_H_ +#define GEMMLOWP_INTERNAL_DETECT_PLATFORM_H_ + +// Our inline assembly path assume GCC/Clang syntax. +// Native Client doesn't seem to support inline assembly(?). +#if defined(__GNUC__) && !defined(__native_client__) +#define GEMMLOWP_ALLOW_INLINE_ASM +#endif + +// Define macro statement that avoids inlining for GCC. +// For non-GCC, define as empty macro. +#if defined(__GNUC__) +#define GEMMLOWP_NOINLINE __attribute__((noinline)) +#else +#define GEMMLOWP_NOINLINE +#endif + +// Detect ARM, 32-bit or 64-bit +#ifdef __arm__ +#define GEMMLOWP_ARM_32 +#endif + +#ifdef __aarch64__ +#define GEMMLOWP_ARM_64 +#endif + +#if defined(GEMMLOWP_ARM_32) || defined(GEMMLOWP_ARM_64) +#define GEMMLOWP_ARM +#endif + +// Detect MIPS, 32-bit or 64-bit +#if defined(__mips) && !defined(__LP64__) +#define GEMMLOWP_MIPS_32 +#endif + +#if defined(__mips) && defined(__LP64__) +#define GEMMLOWP_MIPS_64 +#endif + +#if defined(GEMMLOWP_MIPS_32) || defined(GEMMLOWP_MIPS_64) +#define GEMMLOWP_MIPS +#endif + +// Detect x86, 32-bit or 64-bit +#if defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__i386) +#define GEMMLOWP_X86_32 +#endif + +#if defined(__x86_64__) || defined(_M_X64) || defined(__amd64) +#define GEMMLOWP_X86_64 +#endif + +#if defined(GEMMLOWP_X86_32) || defined(GEMMLOWP_X86_64) +#define GEMMLOWP_X86 +#endif + +// Some of our optimized paths use inline assembly and for +// now we don't bother enabling some other optimized paths using intrinddics +// where we can't use inline assembly paths. +#ifdef GEMMLOWP_ALLOW_INLINE_ASM + +// Detect NEON. It's important to check for both tokens. +#if (defined __ARM_NEON) || (defined __ARM_NEON__) +#define GEMMLOWP_NEON +#endif + +// Convenience NEON tokens for 32-bit or 64-bit +#if defined(GEMMLOWP_NEON) && defined(GEMMLOWP_ARM_32) +#define GEMMLOWP_NEON_32 +#endif + +#if defined(GEMMLOWP_NEON) && defined(GEMMLOWP_ARM_64) +#define GEMMLOWP_NEON_64 +#endif + +// Detect MIPS MSA. +// Limit MSA optimizations to little-endian CPUs for now. +// TODO: Perhaps, eventually support MSA optimizations on big-endian CPUs? +#if defined(GEMMLOWP_MIPS) && (__mips_isa_rev >= 5) && defined(__mips_msa) && \ + defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define GEMMLOWP_MSA +#endif + +// Convenience MIPS MSA tokens for 32-bit or 64-bit. +#if defined(GEMMLOWP_MSA) && defined(GEMMLOWP_MIPS_32) +#define GEMMLOWP_MSA_32 +#endif + +#if defined(GEMMLOWP_MSA) && defined(GEMMLOWP_MIPS_64) +#define GEMMLOWP_MSA_64 +#endif + +// compiler define for AVX2 -D GEMMLOWP_ENABLE_AVX2 +// Detect AVX2 +#if defined(__AVX2__) && defined(GEMMLOWP_ENABLE_AVX2) +#define GEMMLOWP_AVX2 +// Detect SSE4. +// MSVC does not have __SSE4_1__ macro, but will enable SSE4 +// when AVX is turned on. +#elif defined(__SSE4_1__) || (defined(_MSC_VER) && defined(__AVX__)) +#define GEMMLOWP_SSE4 +// Detect SSE3. +#elif defined(__SSE3__) +#define GEMMLOWP_SSE3 +#endif + +// Convenience SSE4 tokens for 32-bit or 64-bit +#if defined(GEMMLOWP_SSE4) && defined(GEMMLOWP_X86_32) && \ + !defined(GEMMLOWP_DISABLE_SSE4) +#define GEMMLOWP_SSE4_32 +#endif + +#if defined(GEMMLOWP_SSE3) && defined(GEMMLOWP_X86_32) +#define GEMMLOWP_SSE3_32 +#endif + +#if defined(GEMMLOWP_SSE4) && defined(GEMMLOWP_X86_64) && \ + !defined(GEMMLOWP_DISABLE_SSE4) +#define GEMMLOWP_SSE4_64 +#endif + +#if defined(GEMMLOWP_SSE3) && defined(GEMMLOWP_X86_64) +#define GEMMLOWP_SSE3_64 +#endif + +#if defined(GEMMLOWP_AVX2) && defined(GEMMLOWP_X86_64) +#define GEMMLOWP_AVX2_64 +#endif + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#include +#define GEMMLOWP_MARK_MEMORY_AS_INITIALIZED __msan_unpoison +#elif __has_feature(address_sanitizer) +#include +#define GEMMLOWP_MARK_MEMORY_AS_INITIALIZED __asan_unpoison_memory_region +#endif +#endif + +#endif // GEMMLOWP_ALLOW_INLINE_ASM + +// Detect Android. Don't conflate with ARM - we care about tuning +// for non-ARM Android devices too. This can be used in conjunction +// with x86 to tune differently for mobile x86 CPUs (Atom) vs. desktop x86 CPUs. +#if defined(__ANDROID__) || defined(ANDROID) +#define GEMMLOWP_ANDROID +#endif + +#endif // GEMMLOWP_INTERNAL_DETECT_PLATFORM_H_ diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/COPYING b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/COPYING new file mode 100644 index 000000000..2fc6685a6 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/COPYING @@ -0,0 +1,11 @@ +Copyright (c) 2003-2010 Mark Borgerding + +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 author nor the names of any 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. diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/_kiss_fft_guts.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/_kiss_fft_guts.h new file mode 100644 index 000000000..2f8b37af5 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/_kiss_fft_guts.h @@ -0,0 +1,168 @@ +#ifndef _KISS_FFT_GUTS_H +#define _KISS_FFT_GUTS_H + +/* +Copyright (c) 2003-2010, Mark Borgerding + +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 author nor the names of any 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. +*/ + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "third_party/kissfft/kiss_fft.h" +#include + +#define MAXFACTORS 32 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +struct kiss_fft_state{ + int nfft; + int inverse; + int factors[2*MAXFACTORS]; + kiss_fft_cpx twiddles[1]; +}; + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#if (FIXED_POINT==32) +# define FRACBITS 31 +# define SAMPPROD int64_t +#define SAMP_MAX 2147483647 +#else +# define FRACBITS 15 +# define SAMPPROD int32_t +#define SAMP_MAX 32767 +#endif + +#define SAMP_MIN -SAMP_MAX + +#if defined(CHECK_OVERFLOW) +# define CHECK_OVERFLOW_OP(a,op,b) \ + if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ + fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } +#endif + + +# define smul(a,b) ( (SAMPPROD)(a)*(b) ) +# define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) + +# define S_MUL(a,b) sround( smul(a,b) ) + +# define C_MUL(m,a,b) \ + do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ + (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) + +# define DIVSCALAR(x,k) \ + (x) = sround( smul( x, SAMP_MAX/k ) ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = sround( smul( (c).r , s ) ) ;\ + (c).i = sround( smul( (c).i , s ) ) ; }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) + + +#ifdef FIXED_POINT +# define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*(kiss_fft_scalar).5) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + + +/* a debugging function */ +#define pcpx(c)\ + fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) + + +#ifdef KISS_FFT_USE_ALLOCA +// define this to allow use of alloca instead of malloc for temporary buffers +// Temporary buffers are used in two case: +// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5 +// 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform. +#include +#define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes) +#define KISS_FFT_TMP_FREE(ptr) +#else +#define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes) +#define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr) +#endif +#endif // _KISS_FFT_GUTS_H diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/kiss_fft.c b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/kiss_fft.c new file mode 100644 index 000000000..02da5e870 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/kiss_fft.c @@ -0,0 +1,408 @@ +/* +Copyright (c) 2003-2010, Mark Borgerding + +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 author nor the names of any 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. +*/ + + +#include "third_party/kissfft/_kiss_fft_guts.h" +/* The guts header contains all the multiplication and addition macros that are defined for + fixed or floating point complex numbers. It also delares the kf_ internal functions. + */ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx * Fout2; + kiss_fft_cpx * tw1 = st->twiddles; + kiss_fft_cpx t; + Fout2 = Fout + m; + do{ + C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); + + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + }while (--m); +} + +static void kf_bfly4( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + const size_t m + ) +{ + kiss_fft_cpx *tw1,*tw2,*tw3; + kiss_fft_cpx scratch[6]; + size_t k=m; + const size_t m2=2*m; + const size_t m3=3*m; + + + tw3 = tw2 = tw1 = st->twiddles; + + do { + C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4); + + C_MUL(scratch[0],Fout[m] , *tw1 ); + C_MUL(scratch[1],Fout[m2] , *tw2 ); + C_MUL(scratch[2],Fout[m3] , *tw3 ); + + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + if(st->inverse) { + Fout[m].r = scratch[5].r - scratch[4].i; + Fout[m].i = scratch[5].i + scratch[4].r; + Fout[m3].r = scratch[5].r + scratch[4].i; + Fout[m3].i = scratch[5].i - scratch[4].r; + }else{ + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + } + ++Fout; + }while(--k); +} + +static void kf_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + size_t m + ) +{ + size_t k=m; + const size_t m2 = 2*m; + kiss_fft_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_fft_cpx epi3; + epi3 = st->twiddles[fstride*m]; + + tw1=tw2=st->twiddles; + + do{ + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int u; + kiss_fft_cpx scratch[13]; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx *tw; + kiss_fft_cpx ya,yb; + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + + Fout0=Fout; + Fout1=Fout0+m; + Fout2=Fout0+2*m; + Fout3=Fout0+3*m; + Fout4=Fout0+4*m; + + tw=st->twiddles; + for ( u=0; ur += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } +} + +/* perform the butterfly for one stage of a mixed radix FFT */ +static void kf_bfly_generic( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_cfg st, + int m, + int p + ) +{ + int u,k,q1,q; + kiss_fft_cpx * twiddles = st->twiddles; + kiss_fft_cpx t; + int Norig = st->nfft; + + kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p); + + for ( u=0; u=Norig) twidx-=Norig; + C_MUL(t,scratch[q] , twiddles[twidx] ); + C_ADDTO( Fout[ k ] ,t); + } + k += m; + } + } + KISS_FFT_TMP_FREE(scratch); +} + +static +void kf_work( + kiss_fft_cpx * Fout, + const kiss_fft_cpx * f, + const size_t fstride, + int in_stride, + int * factors, + const kiss_fft_cfg st + ) +{ + kiss_fft_cpx * Fout_beg=Fout; + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + const kiss_fft_cpx * Fout_end = Fout + p*m; + +#ifdef _OPENMP + // use openmp extensions at the + // top-level (not recursive) + if (fstride==1 && p<=5) + { + int k; + + // execute the p different work units in different threads +# pragma omp parallel for + for (k=0;k floor_sqrt) + p = n; /* no more factors, skip to end */ + } + n /= p; + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); +} + +/* + * + * User-callable function to allocate all necessary storage space for the fft. + * + * The return value is a contiguous block of memory, allocated with malloc. As such, + * It can be freed with free(), rather than a kiss_fft-specific function. + * */ +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) +{ + kiss_fft_cfg st=NULL; + size_t memneeded = sizeof(struct kiss_fft_state) + + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ + + if ( lenmem==NULL ) { + st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); + }else{ + if (mem != NULL && *lenmem >= memneeded) + st = (kiss_fft_cfg)mem; + *lenmem = memneeded; + } + if (st) { + int i; + st->nfft=nfft; + st->inverse = inverse_fft; + + for (i=0;iinverse) + phase *= -1; + kf_cexp(st->twiddles+i, phase ); + } + + kf_factor(nfft,st->factors); + } + return st; +} + + +void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) +{ + if (fin == fout) { + //NOTE: this is not really an in-place FFT algorithm. + //It just performs an out-of-place FFT into a temp buffer + kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft); + kf_work(tmpbuf,fin,1,in_stride, st->factors,st); + /* memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); */ + KISS_FFT_TMP_FREE(tmpbuf); + }else{ + kf_work( fout, fin, 1,in_stride, st->factors,st ); + } +} + +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + kiss_fft_stride(cfg,fin,fout,1); +} + + +void kiss_fft_cleanup(void) +{ + // nothing needed any more +} + +int kiss_fft_next_fast_size(int n) +{ + while(1) { + int m=n; + while ( (m%2) == 0 ) m/=2; + while ( (m%3) == 0 ) m/=3; + while ( (m%5) == 0 ) m/=5; + if (m<=1) + break; /* n is completely factorable by twos, threes, and fives */ + n++; + } + return n; +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/kiss_fft.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/kiss_fft.h new file mode 100644 index 000000000..c2c5d8ff0 --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/kiss_fft.h @@ -0,0 +1,125 @@ +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include +//#include +/* Patched by create_tflm_arduino.py for Arduino compatibility */ + +#ifdef __cplusplus +extern "C++" { +#endif + +/* + ATTENTION! + If you would like a : + -- a utility that will handle the caching of fft objects + -- real-only (no imaginary time component ) FFT + -- a multi-dimensional FFT + -- a command-line utility to perform ffts + -- a command-line utility to perform fast-convolution filtering + + Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c + in the tools/ directory. +*/ + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16) +#define KISS_FFT_FREE _mm_free +#else +#define KISS_FFT_MALLOC(X) (void*)(0x0) /* Patched. */ +#define KISS_FFT_FREE(X) /* Patched. */ +#endif + + +#ifdef FIXED_POINT +#include /* Patched. */ +# if (FIXED_POINT == 32) +# define kiss_fft_scalar int32_t +# else +# define kiss_fft_scalar int16_t +# endif +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct kiss_fft_state* kiss_fft_cfg; + +/* + * kiss_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); + +/* + * kiss_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +/* + A more generic version of the above function. It reads its input from every Nth sample. + * */ +void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); + +/* If kiss_fft_alloc allocated a buffer, it is one contiguous + buffer and can be simply free()d when no longer needed*/ +#define kiss_fft_free free + +/* + Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up + your compiler output to call this before you exit. +*/ +void kiss_fft_cleanup(void); + + +/* + * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) + */ +int kiss_fft_next_fast_size(int n); + +/* for real ffts, we need an even size */ +#define kiss_fftr_next_fast_size_real(n) \ + (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/tools/kiss_fftr.c b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/tools/kiss_fftr.c new file mode 100644 index 000000000..dd3a1b79b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/tools/kiss_fftr.c @@ -0,0 +1,159 @@ +/* +Copyright (c) 2003-2004, Mark Borgerding + +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 author nor the names of any 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. +*/ + +#include "third_party/kissfft/tools/kiss_fftr.h" +#include "third_party/kissfft/_kiss_fft_guts.h" + +struct kiss_fftr_state{ + kiss_fft_cfg substate; + kiss_fft_cpx * tmpbuf; + kiss_fft_cpx * super_twiddles; +#ifdef USE_SIMD + void * pad; +#endif +}; + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) +{ + int i; + kiss_fftr_cfg st = NULL; + size_t subsize, memneeded; + + if (nfft & 1) { + /* fprintf(stderr,"Real FFT optimization must be even.\n"); */ + return NULL; + } + nfft >>= 1; + + kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); + memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2); + + if (lenmem == NULL) { + st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); + } else { + if (*lenmem >= memneeded) + st = (kiss_fftr_cfg) mem; + *lenmem = memneeded; + } + if (!st) + return NULL; + + st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ + st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); + st->super_twiddles = st->tmpbuf + nfft; + kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); + + for (i = 0; i < nfft/2; ++i) { + double phase = + -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5); + if (inverse_fft) + phase *= -1; + kf_cexp (st->super_twiddles+i,phase); + } + return st; +} + +void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) +{ + /* input buffer timedata is stored row-wise */ + int k,ncfft; + kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; + + if ( st->substate->inverse) { + /* fprintf(stderr,"kiss fft usage error: improper alloc\n"); */ + return; /* exit(1); */ + } + + ncfft = st->substate->nfft; + + /*perform the parallel fft of two real signals packed in real,imag*/ + kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); + /* The real part of the DC element of the frequency spectrum in st->tmpbuf + * contains the sum of the even-numbered elements of the input time sequence + * The imag part is the sum of the odd-numbered elements + * + * The sum of tdc.r and tdc.i is the sum of the input time sequence. + * yielding DC of input time sequence + * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... + * yielding Nyquist bin of input time sequence + */ + + tdc.r = st->tmpbuf[0].r; + tdc.i = st->tmpbuf[0].i; + C_FIXDIV(tdc,2); + CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); + CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); + freqdata[0].r = tdc.r + tdc.i; + freqdata[ncfft].r = tdc.r - tdc.i; +#ifdef USE_SIMD + freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); +#else + freqdata[ncfft].i = freqdata[0].i = 0; +#endif + + for ( k=1;k <= ncfft/2 ; ++k ) { + fpk = st->tmpbuf[k]; + fpnk.r = st->tmpbuf[ncfft-k].r; + fpnk.i = - st->tmpbuf[ncfft-k].i; + C_FIXDIV(fpk,2); + C_FIXDIV(fpnk,2); + + C_ADD( f1k, fpk , fpnk ); + C_SUB( f2k, fpk , fpnk ); + C_MUL( tw , f2k , st->super_twiddles[k-1]); + + freqdata[k].r = HALF_OF(f1k.r + tw.r); + freqdata[k].i = HALF_OF(f1k.i + tw.i); + freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); + freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); + } +} + +void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) +{ + /* input buffer timedata is stored row-wise */ + int k, ncfft; + + if (st->substate->inverse == 0) { + /* fprintf (stderr, "kiss fft usage error: improper alloc\n"); */ + return; /* exit (1); */ + } + + ncfft = st->substate->nfft; + + st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; + st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; + C_FIXDIV(st->tmpbuf[0],2); + + for (k = 1; k <= ncfft / 2; ++k) { + kiss_fft_cpx fk, fnkc, fek, fok, tmp; + fk = freqdata[k]; + fnkc.r = freqdata[ncfft - k].r; + fnkc.i = -freqdata[ncfft - k].i; + C_FIXDIV( fk , 2 ); + C_FIXDIV( fnkc , 2 ); + + C_ADD (fek, fk, fnkc); + C_SUB (tmp, fk, fnkc); + C_MUL (fok, tmp, st->super_twiddles[k-1]); + C_ADD (st->tmpbuf[k], fek, fok); + C_SUB (st->tmpbuf[ncfft - k], fek, fok); +#ifdef USE_SIMD + st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); +#else + st->tmpbuf[ncfft - k].i *= -1; +#endif + } + kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); +} diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/tools/kiss_fftr.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/tools/kiss_fftr.h new file mode 100644 index 000000000..8faf0628b --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/kissfft/tools/kiss_fftr.h @@ -0,0 +1,46 @@ +#ifndef KISS_FTR_H +#define KISS_FTR_H + +#include "third_party/kissfft/kiss_fft.h" +#ifdef __cplusplus +extern "C++" { +#endif + + +/* + + Real optimized version can save about 45% cpu time vs. complex fft of a real seq. + + + + */ + +typedef struct kiss_fftr_state *kiss_fftr_cfg; + + +kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); +/* + nfft must be even + + If you don't care to allocate space, use mem = lenmem = NULL +*/ + + +void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); +/* + input timedata has nfft scalar points + output freqdata has nfft/2+1 complex points +*/ + +void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); +/* + input freqdata has nfft/2+1 complex points + output timedata has nfft scalar points +*/ + +#define kiss_fftr_free free + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/libesp32_ml/tf_lite_esp32/src/third_party/ruy/ruy/profiler/instrumentation.h b/lib/libesp32_ml/tf_lite_esp32/src/third_party/ruy/ruy/profiler/instrumentation.h new file mode 100644 index 000000000..c4df1e68f --- /dev/null +++ b/lib/libesp32_ml/tf_lite_esp32/src/third_party/ruy/ruy/profiler/instrumentation.h @@ -0,0 +1,203 @@ +/* Copyright 2020 Google LLC. All Rights Reserved. + +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 RUY_RUY_PROFILER_INSTRUMENTATION_H_ +#define RUY_RUY_PROFILER_INSTRUMENTATION_H_ + +#ifdef RUY_PROFILER +#include +#include +#include +#endif + +namespace ruy { +namespace profiler { + +#ifdef RUY_PROFILER + +// A label is how a code scope is annotated to appear in profiles. +// The stacks that are sampled by the profiler are stacks of such labels. +// A label consists of a literal string, plus optional integer arguments. +class Label { + public: + Label() {} + template + explicit Label(Args... args) { + Set(args...); + } + void Set(const char* format) { + format_ = format; + args_count_ = 0; + } + template + void Set(const char* format, Args... args) { + format_ = format; + args_count_ = sizeof...(args); + SetArgs(0, args...); + } + + void operator=(const Label& other); + + bool operator==(const Label& other) const; + + std::string Formatted() const; + const char* format() const { return format_; } + + private: + void SetArgs(int position, int arg0) { args_[position] = arg0; } + + template + void SetArgs(int position, int arg0, Args... args) { + SetArgs(position, arg0); + SetArgs(position + 1, args...); + } + + static constexpr int kMaxArgs = 4; + const char* format_ = nullptr; + int args_count_ = 0; + int args_[kMaxArgs]; +}; + +namespace detail { + +// Forward-declaration, see class ThreadStack below. +class ThreadStack; + +bool& GlobalIsProfilerRunning(); + +// Returns the global vector of pointers to all stacks, there being one stack +// per thread executing instrumented code. +std::vector* GlobalAllThreadStacks(); + +// Returns the mutex to be locked around any access to GlobalAllThreadStacks(). +std::mutex* GlobalsMutex(); + +// Returns the thread-local stack, specific to the current thread. +ThreadStack* ThreadLocalThreadStack(); + +// This 'stack' is what may be more appropriately called a 'pseudostack': +// It contains Label entries that are 'manually' entered by instrumentation +// code. It's unrelated to real call stacks. +struct Stack { + std::uint32_t id = 0; + static constexpr int kMaxSize = 64; + int size = 0; + Label labels[kMaxSize]; +}; + +// Returns the buffer byte size required by CopyToSample. +int GetBufferSize(const Stack& stack); + +// Copies this Stack into a byte buffer, called a 'sample'. +void CopyToBuffer(const Stack& stack, char* dst); + +// Populates this Stack from an existing sample buffer, typically +// produced by CopyToSample. +void ReadFromBuffer(const char* src, Stack* stack); + +// ThreadStack is meant to be used as a thread-local singleton, assigning to +// each thread a Stack object holding its pseudo-stack of profile labels, +// plus a mutex allowing to synchronize accesses to this pseudo-stack between +// this thread and a possible profiler thread sampling it. +class ThreadStack { + public: + ThreadStack(); + ~ThreadStack(); + + const Stack& stack() const { return stack_; } + + // Returns the mutex to lock around any access to this stack. Each stack is + // accessed by potentially two threads: the thread that it belongs to + // (which calls Push and Pop) and the profiler thread during profiling + // (which calls CopyToSample). + std::mutex& Mutex() const { return mutex_; } + + // Pushes a new label on the top of this Stack. + template + void Push(Args... args) { + // This mutex locking is needed to guard against race conditions as both + // the current thread and the profiler thread may be concurrently accessing + // this stack. In addition to that, this mutex locking also serves the other + // purpose of acting as a barrier (of compiler code reordering, of runtime + // CPU instruction reordering, and of memory access reordering), which + // gives a measure of correctness to this profiler. The downside is some + // latency. As this lock will be uncontended most of the times, the cost + // should be roughly that of an sequentially-consistent atomic access, + // comparable to an access to the level of CPU data cache that is shared + // among all cores, typically 60 cycles on current ARM CPUs, plus side + // effects from barrier instructions. + std::lock_guard lock(mutex_); + // Avoid overrunning the stack, even in 'release' builds. This profiling + // instrumentation code should not ship in release builds anyway, the + // overhead of this check is negligible, and overrunning a stack array would + // be bad. + if (stack_.size >= Stack::kMaxSize) { + abort(); + } + stack_.labels[stack_.size++].Set(args...); + } + + // Pops the top-most label from this Stack. + void Pop() { + // See the comment in Push about this lock. While it would be tempting to + // try to remove this lock and just atomically decrement size_ with a + // store-release, that would not necessarily be a substitute for all of the + // purposes that this lock serves, or if it was done carefully to serve all + // of the same purposes, then that wouldn't be faster than this (mostly + // uncontended) lock. + std::lock_guard lock(mutex_); + stack_.size--; + } + + private: + mutable std::mutex mutex_; + Stack stack_; +}; + +} // namespace detail + +// RAII user-facing way to construct Labels associated with their life scope +// and get them pushed to / popped from the current thread stack. +class ScopeLabel { + public: + template + ScopeLabel(Args... args) : thread_stack_(detail::ThreadLocalThreadStack()) { + thread_stack_->Push(args...); + } + + ~ScopeLabel() { thread_stack_->Pop(); } + + private: + detail::ThreadStack* thread_stack_; +}; + +#else // no RUY_PROFILER + +class ScopeLabel { + public: + template + explicit ScopeLabel(Args...) {} + + // This destructor is needed to consistently silence clang's -Wunused-variable + // which seems to trigger semi-randomly. + ~ScopeLabel() {} +}; + +#endif + +} // namespace profiler +} // namespace ruy + +#endif // RUY_RUY_PROFILER_INSTRUMENTATION_H_ diff --git a/pio-tools/download_fs.py b/pio-tools/custom_target.py similarity index 90% rename from pio-tools/download_fs.py rename to pio-tools/custom_target.py index 0235af850..9bf136a1e 100644 --- a/pio-tools/download_fs.py +++ b/pio-tools/custom_target.py @@ -14,6 +14,7 @@ import sys from os.path import isfile, join from enum import Enum import os +import tasmotapiolib import subprocess import shutil @@ -256,9 +257,14 @@ def get_fs_type_start_and_length(): def download_fs(fs_info: FSInfo): esptoolpy = join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py") + upload_port = join(env.get("UPLOAD_PORT", "none")) + if "none" in upload_port: + env.AutodetectUploadPort() + upload_port = join(env.get("UPLOAD_PORT", "none")) fs_file = join(env["PROJECT_DIR"], f"downloaded_fs_{hex(fs_info.start)}_{hex(fs_info.length)}.bin") esptoolpy_flags = [ "--chip", mcu, + "--port", upload_port, "--baud", env.subst("$UPLOAD_SPEED"), "--before", "default_reset", "--after", "hard_reset", @@ -318,6 +324,27 @@ def command_download_fs(*args, **kwargs): if unpack_ok is True: display_fs(unpacked_dir) +def upload_factory(*args, **kwargs): + esptoolpy = join(platform.get_package_dir("tool-esptoolpy") or "", "esptool.py") + upload_speed = join(str(board.get("upload.speed", "115200"))) + upload_port = join(env.get("UPLOAD_PORT", "none")) + target_firm = join(env.subst("$PROJECT_DIR"),tasmotapiolib.get_final_bin_path(env).with_suffix(".bin" if mcu == "esp8266" else (".factory.bin"))) + if "none" in upload_port: + env.AutodetectUploadPort() + upload_port = join(env.get("UPLOAD_PORT", "none")) + if "tasmota" in target_firm: + esptoolpy_flags = [ + "--chip", mcu, + "--port", upload_port, + "--baud", upload_speed, + "write_flash", + "0x0", + target_firm + ] + esptoolpy_cmd = [env["PYTHONEXE"], esptoolpy] + esptoolpy_flags + print("Flash firmware at address 0x0") + subprocess.call(esptoolpy_cmd, shell=False) + env.AddCustomTarget( name="downloadfs", dependencies=None, @@ -327,3 +354,13 @@ env.AddCustomTarget( title="Download Filesystem", description="Downloads and displays files stored in the target ESP32/ESP8266" ) + +env.AddCustomTarget( + name="factory_flash", + dependencies=None, + actions=[ + upload_factory + ], + title="Flash factory", + description="Flash factory firmware" +) diff --git a/pio-tools/name-firmware.py b/pio-tools/name-firmware.py index d6a310337..09edb2866 100644 --- a/pio-tools/name-firmware.py +++ b/pio-tools/name-firmware.py @@ -29,4 +29,4 @@ def bin_map_copy(source, target, env): if env["PIOPLATFORM"] == "espressif32": shutil.copy(factory, one_bin_file) -env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", bin_map_copy) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", bin_map_copy) \ No newline at end of file diff --git a/pio-tools/set_partition_table.py b/pio-tools/set_partition_table.py new file mode 100644 index 000000000..77f937d3a --- /dev/null +++ b/pio-tools/set_partition_table.py @@ -0,0 +1,57 @@ +# +# The scipt sets the missing "LDSCRIPT_PATH" when using the command `pio run -t nobuild` +# Adopted from https://github.com/platformio/platform-espressif32/issues/861#issuecomment-1241871437 +# Possible now to upload the firmware or the filesystem with (when builded already!): +# +# `pio run -t nobuild -t upload` and `pio run -t nobuild -t uploadfs` +# + +Import("env") + +import os +import tasmotapiolib +from os.path import isfile, join +import shutil +from SCons.Script import COMMAND_LINE_TARGETS + +board_config = env.BoardConfig() + +if "nobuild" in COMMAND_LINE_TARGETS: + prog_name = join(env.subst("$BUILD_DIR"),"firmware.bin") + if not os.path.isfile(prog_name): + #print ("No firmware in path:",join(env.subst("$BUILD_DIR"))) + env.CleanProject() + cur_env = (env["PIOENV"]) + firm_name = cur_env + ".bin" + source_firm = tasmotapiolib.get_final_bin_path(env) + if not os.path.exists(join(env.subst("$BUILD_DIR"))): + os.makedirs(join(env.subst("$BUILD_DIR"))) + if os.path.isfile(source_firm): + shutil.copy(source_firm, join(env.subst("$BUILD_DIR"))) + target_ren = join(env.subst("$BUILD_DIR"), firm_name) + os.rename(target_ren, prog_name) + + if env["PIOPLATFORM"] != "espressif32": + framework_dir = env.PioPlatform().get_package_dir("framework-arduinoespressif8266") + assert os.path.isdir(framework_dir) + env.Replace( + LDSCRIPT_PATH=os.path.join( + framework_dir, + "tools", + "sdk", + "ld", + board_config.get("build.arduino.ldscript"), + ) + ) +# print("Set LDSCRIPT_PATH to: ", os.path.join(framework_dir,"tools","sdk","ld",board_config.get("build.arduino.ldscript"))) + +# +# For ESP32 sets the missing "PARTITIONS_TABLE_CSV" when using the command `pio run -t nobuild` +# + else: + env.Replace( + PARTITIONS_TABLE_CSV=os.path.join( + board_config.get("build.partitions"), + ) + ) +# print("Set PARTITIONS_TABLE_CSV to: ", os.path.join(board_config.get("build.partitions"))) diff --git a/platformio.ini b/platformio.ini index 611ffbb11..595e9736c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,6 +38,7 @@ monitor_speed = 115200 ; *** Upload Serial reset method for Wemos and NodeMCU upload_resetmethod = nodemcu extra_scripts = ${esp_defaults.extra_scripts} +lib_archive = no lib_ldf_mode = chain lib_compat_mode = strict shared_libdeps_dir = lib @@ -65,14 +66,16 @@ lib_extra_dirs = [scripts_defaults] extra_scripts = pre:pio-tools/pre_source_dir.py - pio-tools/strip-floats.py - pio-tools/name-firmware.py - pio-tools/gzip-firmware.py - pio-tools/override_copy.py - pio-tools/download_fs.py + pre:pio-tools/set_partition_table.py + pre:pio-tools/override_copy.py + post:pio-tools/strip-floats.py [esp_defaults] -extra_scripts = ${scripts_defaults.extra_scripts} +extra_scripts = post:pio-tools/name-firmware.py + post:pio-tools/gzip-firmware.py + post:pio-tools/custom_target.py +; post:pio-tools/obj-dump.py + ${scripts_defaults.extra_scripts} ; *** remove undesired all warnings build_unflags = -Wall ; -mtarget-align @@ -92,6 +95,7 @@ build_flags = -DCORE_DEBUG_LEVEL=0 ; ********************************************************************* [esp82xx_defaults] +extra_scripts = ${esp_defaults.extra_scripts} build_flags = ${esp_defaults.build_flags} -DNDEBUG -DFP_IN_IROM @@ -111,7 +115,7 @@ build_flags = ${esp_defaults.build_flags} [core] ; *** Esp8266 Tasmota modified Arduino core based on core 2.7.4. Added Backport for PWM selection -platform = https://github.com/tasmota/platform-espressif8266/releases/download/2022.12.0/platform-espressif8266.zip +platform = https://github.com/tasmota/platform-espressif8266/releases/download/2023.03.00/platform-espressif8266.zip platform_packages = build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 96a9d8571..30ed067a2 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -47,22 +47,17 @@ default_envs = [env] -; Activate Development core by removing ";" the next lines -;platform = https://github.com/platformio/platform-espressif8266.git -;platform_packages = framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git -; mcspr/toolchain-xtensa @ ~5.100300.211127 -; platformio/tool-esptoolpy @ ~1.30300 ;build_unflags = ${common.build_unflags} ; -Wswitch-unreachable ;build_flags = ${common.build_flags} -; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED +; -DF_CRYSTAL=26000000 ; -Wno-switch-unreachable ; *** Optional Debug messages ; -DDEBUG_TASMOTA_CORE ; -DDEBUG_TASMOTA_DRIVER ; -DDEBUG_TASMOTA_SENSOR ; Build variant 1MB = 1MB firmware no filesystem (default) -board = ${common.board} +;board = ${common.board} ; Build variant 2MB = 1MB firmware, 1MB filesystem (most Shelly devices) ;board = esp8266_2M1M ; Build variant 4MB = 1MB firmware, 1MB OTA, 2MB filesystem (WEMOS D1 Mini, NodeMCU, Sonoff POW) @@ -72,8 +67,6 @@ board = ${common.board} ; *** Define serial port used for erasing/flashing/terminal ;upload_port = COM4 ;monitor_port = COM4 -extra_scripts = ${esp_defaults.extra_scripts} -; pio-tools/obj-dump.py lib_ignore = Servo(esp8266) ESP8266AVRISP @@ -97,9 +90,9 @@ lib_extra_dirs = ${library.lib_extra_dirs} [env:tasmota32_base] ; *** Uncomment next lines ";" to enable development Tasmota Arduino version ESP32 ;platform = https://github.com/tasmota/platform-espressif32.git -;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1088/framework-arduinoespressif32-release_v4.4-a0113c7bfe.zip -; framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1092/framework-arduinoespressif32-solo1-release_v4.4-a0113c7bfe.zip -; framework-arduino-ITEAD @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1091/framework-arduinoespressif32-ITEAD-release_v4.4-a0113c7bfe.zip +;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1271/framework-arduinoespressif32-lwip_timeout-ed6742e7f0.zip +; framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1273/framework-arduinoespressif32-solo1-release_v4.4-804d12ce82.zip +; framework-arduino-ITEAD @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1272/framework-arduinoespressif32-ITEAD-release_v4.4-804d12ce82.zip ;build_unflags = ${esp32_defaults.build_unflags} ;build_flags = ${esp32_defaults.build_flags} ;board = esp32 @@ -116,8 +109,6 @@ lib_extra_dirs = ${library.lib_extra_dirs} ;upload_speed = 115200 monitor_speed = 115200 upload_resetmethod = ${common.upload_resetmethod} -extra_scripts = ${esp32_defaults.extra_scripts} -; pio-tools/obj-dump.py lib_ignore = HTTPUpdateServer ESP RainMaker diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index 08bd7e0a3..8de701529 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -37,12 +37,12 @@ build_flags = ${esp_defaults.build_flags} -Wl,--wrap=_Z11analogWritehi ; `analogWrite(unsigned char, int)` use the Tasmota version of analogWrite for deeper integration and phase control -Wl,--wrap=ledcReadFreq ; `uint32_t ledcReadFreq(uint8_t chan)` extra_scripts = pre:pio-tools/add_c_flags.py - pio-tools/gen-berry-structures.py + pre:pio-tools/gen-berry-structures.py post:pio-tools/post_esp32.py ${esp_defaults.extra_scripts} [core32] -platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.01.01/platform-espressif32.zip -platform_packages = +platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip +platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/pre2.0.8/framework-arduinoespressif32.zip build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} diff --git a/platformio_tasmota_cenv_sample.ini b/platformio_tasmota_cenv_sample.ini index 40d9afadf..30ac45f39 100644 --- a/platformio_tasmota_cenv_sample.ini +++ b/platformio_tasmota_cenv_sample.ini @@ -1,23 +1,27 @@ [env:tasmota-rangeextender] build_flags = ${env.build_flags} - -D FIRMWARE_RANGE_EXTENDER - -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH - -D USE_WIFI_RANGE_EXTENDER - -D USE_WIFI_RANGE_EXTENDER_NAPT + -DFIRMWARE_RANGE_EXTENDER + -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH + -DUSE_WIFI_RANGE_EXTENDER + -DUSE_WIFI_RANGE_EXTENDER_NAPT + -DOTA_URL='""' [env:tasmota32-rangeextender] extends = env:tasmota32_base build_flags = ${env:tasmota32_base.build_flags} - -D FIRMWARE_TASMOTA32 - -D USE_WIFI_RANGE_EXTENDER - -D USE_WIFI_RANGE_EXTENDER_NAPT + -DFIRMWARE_TASMOTA32 + -DUSE_WIFI_RANGE_EXTENDER + -DUSE_WIFI_RANGE_EXTENDER_NAPT + -DOTA_URL='""' [env:tasmota32s3-file] extends = env:tasmota32_base board = esp32s3-qio_qspi board_build.f_cpu = 240000000L board_build.f_flash = 80000000L -build_flags = ${env:tasmota32_base.build_flags} -D FIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s3.bin"' ; !!! Real flash size needed, avoid autoresize since it is formating FS !!! board_upload.flash_size = 8MB board_upload.maximum_size = 8388608 @@ -31,25 +35,33 @@ custom_files_upload = ${env:tasmota32_base.custom_files_upload} https://github.com/tasmota/autoconf/raw/main/esp32s3/DevKitC-1.autoconf [env:tasmota32s3-qio_opi-all] -extends = env:tasmota32_base -board = esp32s3-qio_opi -board_build.f_cpu = 240000000L -board_build.f_flash = 80000000L -build_flags = ${env:tasmota32_base.build_flags} -DUSE_WEBCAM -DUSE_BERRY_ULP -DFIRMWARE_LVGL -DUSE_LVGL_OPENHASP +extends = env:tasmota32_base +board = esp32s3-qio_opi +board_build.f_cpu = 240000000L +board_build.f_flash = 80000000L +build_flags = ${env:tasmota32_base.build_flags} + -DUSE_WEBCAM + -DUSE_BERRY_ULP + -DFIRMWARE_LVGL + -DUSE_LVGL_OPENHASP + -DOTA_URL='""' [env:tasmota32c3-bluetooth] extends = env:tasmota32c3 build_flags = ${env:tasmota32c3.build_flags} - -D USE_BLE_ESP32 - -D USE_MI_ESP32 -; -D USE_EQ3_ESP32 + -DUSE_BLE_ESP32 + -DUSE_MI_ESP32 +; -DUSE_EQ3_ESP32 + -DOTA_URL='""' lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display, lib/lib_audio [env:tasmota32s3-bluetooth] extends = env:tasmota32_base -board = esp32s3 -build_flags = ${env:tasmota32_base.build_flags} -D FIRMWARE_BLUETOOTH +board = esp32s3-qio_qspi +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_BLUETOOTH + -DOTA_URL='""' lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_ssl, lib/lib_i2c lib_ignore = TTGO TWatch Library Micro-RTSP @@ -61,6 +73,7 @@ build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_BLUETOOTH -DUSE_MI_EXT_GUI -DUSE_MI_HOMEKIT=1 ; 1 to enable; 0 to disable + -DOTA_URL='""' lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_div, lib/lib_ssl lib_ignore = ESP8266Audio ESP8266SAM @@ -74,6 +87,7 @@ build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_BLUETOOTH -DUSE_MI_EXT_GUI -DUSE_MI_HOMEKIT=1 ; 1 to enable; 0 to disable + -DOTA_URL='""' lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_div, lib/lib_ssl lib_ignore = ESP8266Audio ESP8266SAM @@ -87,6 +101,7 @@ build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_BLUETOOTH -DUSE_MI_EXT_GUI -DUSE_MI_HOMEKIT=1 ; 1 to enable; 0 to disable + -DOTA_URL='""' lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_div, lib/lib_ssl lib_ignore = ESP8266Audio ESP8266SAM @@ -103,12 +118,14 @@ check_tool = cppcheck check_skip_packages = yes build_flags = ${env.build_flags} ; -Wstack-usage=300 + -DOTA_URL='""' [env:tasmota32-debug] extends = env:tasmota32_base build_type = debug build_unflags = ${env:tasmota32_base.build_unflags} build_flags = ${env:tasmota32_base.build_flags} + -DOTA_URL='""' check_tool = cppcheck ;clangtidy check_skip_packages = yes @@ -120,58 +137,63 @@ monitor_filters = esp32_exception_decoder ; *** Install howto for Windows https://community.platformio.org/t/esp32-pio-unified-debugger/4541/20 [env:tasmota32-ocd] -build_type = debug -extends = env:tasmota32_base -board = esp32 -debug_tool = esp-prog -upload_protocol = esp-prog -debug_init_break = tbreak setup -build_unflags = ${env:tasmota32_base.build_unflags} -build_flags = ${env:tasmota32_base.build_flags} -monitor_filters = esp32_exception_decoder +build_type = debug +extends = env:tasmota32_base +board = esp32 +debug_tool = esp-prog +upload_protocol = esp-prog +debug_init_break = tbreak setup +build_unflags = ${env:tasmota32_base.build_unflags} +build_flags = ${env:tasmota32_base.build_flags} + -DOTA_URL='""' +monitor_filters = esp32_exception_decoder [env:tasmota32solo1-ocd] -build_type = debug -extends = env:tasmota32solo1 -board = esp32_solo1 -debug_tool = esp-prog -upload_protocol = esp-prog -debug_init_break = tbreak setup -build_unflags = ${env:tasmota32_base.build_unflags} -build_flags = ${env:tasmota32_base.build_flags} -monitor_filters = esp32_exception_decoder +build_type = debug +extends = env:tasmota32solo1 +board = esp32_solo1 +debug_tool = esp-prog +upload_protocol = esp-prog +debug_init_break = tbreak setup +build_unflags = ${env:tasmota32_base.build_unflags} +build_flags = ${env:tasmota32_base.build_flags} + -DOTA_URL='""' +monitor_filters = esp32_exception_decoder [env:tasmota32s2-ocd] -build_type = debug -extends = env:tasmota32_base -board = esp32s2 -debug_tool = esp-prog -upload_protocol = esp-prog -debug_init_break = tbreak setup -build_unflags = ${env:tasmota32_base.build_unflags} -build_flags = ${env:tasmota32_base.build_flags} -monitor_filters = esp32_exception_decoder +build_type = debug +extends = env:tasmota32_base +board = esp32s2 +debug_tool = esp-prog +upload_protocol = esp-prog +debug_init_break = tbreak setup +build_unflags = ${env:tasmota32_base.build_unflags} +build_flags = ${env:tasmota32_base.build_flags} + -DOTA_URL='""' +monitor_filters = esp32_exception_decoder ; *** JTAG Debug versions (only C3/S3), uses inbuilt CDC/jtag. No extra jtag hardware required! [env:tasmota32s3cdc-ocd] -build_type = debug -extends = env:tasmota32s3 -board = esp32s3cdc-qio_opi -debug_tool = esp-builtin -upload_protocol = esp-builtin -debug_init_break = tbreak setup -build_unflags = ${env:tasmota32_base.build_unflags} -build_flags = ${env:tasmota32_base.build_flags} -monitor_filters = esp32_exception_decoder +build_type = debug +extends = env:tasmota32s3 +board = esp32s3cdc-qio_opi +debug_tool = esp-builtin +upload_protocol = esp-builtin +debug_init_break = tbreak setup +build_unflags = ${env:tasmota32_base.build_unflags} +build_flags = ${env:tasmota32_base.build_flags} + -DOTA_URL='""' +monitor_filters = esp32_exception_decoder [env:tasmota32c3cdc-ocd] -build_type = debug -extends = env:tasmota32c3 -board = esp32c3cdc -debug_tool = esp-builtin -upload_protocol = esp-builtin -debug_init_break = tbreak setup -build_unflags = ${env:tasmota32c3.build_unflags} -build_flags = ${env:tasmota32c3.build_flags} -monitor_filters = esp32_exception_decoder +build_type = debug +extends = env:tasmota32c3 +board = esp32c3cdc +debug_tool = esp-builtin +upload_protocol = esp-builtin +debug_init_break = tbreak setup +build_unflags = ${env:tasmota32c3.build_unflags} +build_flags = ${env:tasmota32c3.build_flags} + -DOTA_URL='""' +monitor_filters = esp32_exception_decoder diff --git a/platformio_tasmota_env.ini b/platformio_tasmota_env.ini index a7cf65cea..944c4e7ff 100644 --- a/platformio_tasmota_env.ini +++ b/platformio_tasmota_env.ini @@ -5,10 +5,10 @@ framework = ${common.framework} board = ${common.board} board_build.filesystem = ${common.board_build.filesystem} build_unflags = ${common.build_unflags} -build_flags = ${common.build_flags} +build_flags = ${esp82xx_defaults.build_flags} monitor_speed = ${common.monitor_speed} upload_resetmethod = ${common.upload_resetmethod} -extra_scripts = ${common.extra_scripts} +extra_scripts = ${esp_defaults.extra_scripts} lib_ldf_mode = ${common.lib_ldf_mode} lib_compat_mode = ${common.lib_compat_mode} lib_extra_dirs = ${common.lib_extra_dirs} @@ -29,121 +29,130 @@ lib_ignore = Hash ; Disable next if you want to use ArduinoOTA in Tasmota (default disabled) ArduinoOTA - +; Add files to Filesystem for all env (global). Remove no files entry and add add a line with the file to include +custom_files_upload = no_files [env:tasmota] +build_flags = ${env.build_flags} -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota.bin.gz"' [env:tasmota-4M] board = esp8266_4M2M +build_flags = ${env.build_flags} + -DCODE_IMAGE_STR='"tasmota-4M"' + -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-4M.bin.gz"' [env:tasmota-minimal] -build_flags = ${env.build_flags} -DFIRMWARE_MINIMAL +build_flags = ${env.build_flags} -DFIRMWARE_MINIMAL -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-minimal.bin.gz"' lib_extra_dirs = [env:tasmota-lite] -build_flags = ${env.build_flags} -DFIRMWARE_LITE +build_flags = ${env.build_flags} -DFIRMWARE_LITE -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-lite.bin.gz"' lib_extra_dirs = [env:tasmota-knx] -build_flags = ${env.build_flags} -DFIRMWARE_KNX_NO_EMULATION +build_flags = ${env.build_flags} -DFIRMWARE_KNX_NO_EMULATION -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-knx.bin.gz"' lib_extra_dirs = lib/lib_basic, lib/lib_div [env:tasmota-sensors] -build_flags = ${env.build_flags} -DFIRMWARE_SENSORS +build_flags = ${env.build_flags} -DFIRMWARE_SENSORS -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-sensors.bin.gz"' lib_extra_dirs = lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div [env:tasmota-display] -build_flags = ${env.build_flags} -DFIRMWARE_DISPLAYS +build_flags = ${env.build_flags} -DFIRMWARE_DISPLAYS -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-display.bin.gz"' lib_extra_dirs = lib/lib_basic, lib/lib_display [env:tasmota-ir] -build_flags = ${env.build_flags} -DFIRMWARE_IR +build_flags = ${env.build_flags} -DFIRMWARE_IR -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-ir.bin.gz"' lib_extra_dirs = lib/lib_basic [env:tasmota-zbbridge] -build_flags = ${env.build_flags} -DFIRMWARE_ZBBRIDGE +build_flags = ${env.build_flags} -DFIRMWARE_ZBBRIDGE -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-zbbridge.bin.gz"' board = esp8266_zbbridge lib_extra_dirs = lib/lib_basic, lib/lib_ssl, lib/lib_div [env:tasmota-zigbee] -build_flags = ${env.build_flags} -DUSE_ZIGBEE -DUSE_CCLOADER -DUSE_UFILESYS +build_flags = ${env.build_flags} + -DUSE_ZIGBEE + -DUSE_CCLOADER + -DCODE_IMAGE_STR='"zigbee"' + -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-zigbee.bin.gz"' board = esp8266_4M2M board_build.f_cpu = 160000000L [env:tasmota-AD] -build_flags = ${env.build_flags} -DMY_LANGUAGE=ca_AD +build_flags = ${env.build_flags} -DMY_LANGUAGE=ca_AD -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmot-AD.bin.gz"' [env:tasmota-AF] -build_flags = ${env.build_flags} -DMY_LANGUAGE=af_AF +build_flags = ${env.build_flags} -DMY_LANGUAGE=af_AF -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-AF.bin.gz"' [env:tasmota-BG] -build_flags = ${env.build_flags} -DMY_LANGUAGE=bg_BG +build_flags = ${env.build_flags} -DMY_LANGUAGE=bg_BG -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-BG.bin.gz"' [env:tasmota-BR] -build_flags = ${env.build_flags} -DMY_LANGUAGE=pt_BR +build_flags = ${env.build_flags} -DMY_LANGUAGE=pt_BR -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-BR.bin.gz"' [env:tasmota-CN] -build_flags = ${env.build_flags} -DMY_LANGUAGE=zh_CN +build_flags = ${env.build_flags} -DMY_LANGUAGE=zh_CN -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-CN.bin.gz"' [env:tasmota-CZ] -build_flags = ${env.build_flags} -DMY_LANGUAGE=cs_CZ +build_flags = ${env.build_flags} -DMY_LANGUAGE=cs_CZ -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-CZ.bin.gz"' [env:tasmota-DE] -build_flags = ${env.build_flags} -DMY_LANGUAGE=de_DE +build_flags = ${env.build_flags} -DMY_LANGUAGE=de_DE -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-DE.bin.gz"' [env:tasmota-ES] -build_flags = ${env.build_flags} -DMY_LANGUAGE=es_ES +build_flags = ${env.build_flags} -DMY_LANGUAGE=es_ES -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-ES.bin.gz"' [env:tasmota-FR] -build_flags = ${env.build_flags} -DMY_LANGUAGE=fr_FR +build_flags = ${env.build_flags} -DMY_LANGUAGE=fr_FR -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-FR.bin.gz"' [env:tasmota-FY] -build_flags = ${env.build_flags} -DMY_LANGUAGE=fy_NL +build_flags = ${env.build_flags} -DMY_LANGUAGE=fy_NL -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-FY.bin.gz"' [env:tasmota-GR] -build_flags = ${env.build_flags} -DMY_LANGUAGE=el_GR +build_flags = ${env.build_flags} -DMY_LANGUAGE=el_GR -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-GR.bin.gz"' [env:tasmota-HE] -build_flags = ${env.build_flags} -DMY_LANGUAGE=he_HE +build_flags = ${env.build_flags} -DMY_LANGUAGE=he_HE -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-HE.bin.gz"' [env:tasmota-HU] -build_flags = ${env.build_flags} -DMY_LANGUAGE=hu_HU +build_flags = ${env.build_flags} -DMY_LANGUAGE=hu_HU -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-HU.bin.gz"' [env:tasmota-IT] -build_flags = ${env.build_flags} -DMY_LANGUAGE=it_IT +build_flags = ${env.build_flags} -DMY_LANGUAGE=it_IT -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-IT.bin.gz"' [env:tasmota-KO] -build_flags = ${env.build_flags} -DMY_LANGUAGE=ko_KO +build_flags = ${env.build_flags} -DMY_LANGUAGE=ko_KO -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-KO.bin.gz"' [env:tasmota-NL] -build_flags = ${env.build_flags} -DMY_LANGUAGE=nl_NL +build_flags = ${env.build_flags} -DMY_LANGUAGE=nl_NL -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-NL.bin.gz"' [env:tasmota-PL] -build_flags = ${env.build_flags} -DMY_LANGUAGE=pl_PL +build_flags = ${env.build_flags} -DMY_LANGUAGE=pl_PL -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-PL.bin.gz"' [env:tasmota-PT] -build_flags = ${env.build_flags} -DMY_LANGUAGE=pt_PT +build_flags = ${env.build_flags} -DMY_LANGUAGE=pt_PT -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-PT.bin.gz"' [env:tasmota-RO] -build_flags = ${env.build_flags} -DMY_LANGUAGE=ro_RO +build_flags = ${env.build_flags} -DMY_LANGUAGE=ro_RO -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-RO.bin.gz"' [env:tasmota-RU] -build_flags = ${env.build_flags} -DMY_LANGUAGE=ru_RU +build_flags = ${env.build_flags} -DMY_LANGUAGE=ru_RU -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-RU.bin.gz"' [env:tasmota-SE] -build_flags = ${env.build_flags} -DMY_LANGUAGE=sv_SE +build_flags = ${env.build_flags} -DMY_LANGUAGE=sv_SE -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-SE.bin.gz"' [env:tasmota-SK] -build_flags = ${env.build_flags} -DMY_LANGUAGE=sk_SK +build_flags = ${env.build_flags} -DMY_LANGUAGE=sk_SK -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-SK.bin.gz"' [env:tasmota-TR] -build_flags = ${env.build_flags} -DMY_LANGUAGE=tr_TR +build_flags = ${env.build_flags} -DMY_LANGUAGE=tr_TR -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-TR.bin.gz"' [env:tasmota-TW] -build_flags = ${env.build_flags} -DMY_LANGUAGE=zh_TW +build_flags = ${env.build_flags} -DMY_LANGUAGE=zh_TW -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-TW.bin.gz"' [env:tasmota-UK] -build_flags = ${env.build_flags} -DMY_LANGUAGE=uk_UA +build_flags = ${env.build_flags} -DMY_LANGUAGE=uk_UA -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-UK.bin.gz"' [env:tasmota-VN] -build_flags = ${env.build_flags} -DMY_LANGUAGE=vi_VN +build_flags = ${env.build_flags} -DMY_LANGUAGE=vi_VN -DOTA_URL='"http://ota.tasmota.com/tasmota/release/tasmota-VN.bin.gz"' diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini index f16b4cc12..75ca2cb78 100644 --- a/platformio_tasmota_env32.ini +++ b/platformio_tasmota_env32.ini @@ -1,48 +1,50 @@ [env:tasmota32_base] -framework = ${common.framework} -platform = ${core32.platform} -platform_packages = ${core32.platform_packages} -board_build.filesystem = ${common.board_build.filesystem} -custom_unpack_dir = ${common.custom_unpack_dir} -board = esp32 -monitor_speed = 115200 -upload_resetmethod = ${common.upload_resetmethod} -extra_scripts = ${esp32_defaults.extra_scripts} -build_unflags = ${core32.build_unflags} -build_flags = ${core32.build_flags} -lib_ldf_mode = ${common.lib_ldf_mode} -lib_compat_mode = ${common.lib_compat_mode} -lib_extra_dirs = ${common.lib_extra_dirs} - lib/libesp32 - lib/libesp32_lvgl - lib/libesp32_div - lib/libesp32_eink - lib/libesp32_audio -lib_ignore = - HTTPUpdateServer - ESP RainMaker - WiFiProv - USB - SPIFFS - ESP32 Azure IoT Arduino - ESP32 Async UDP - ESP32 BLE Arduino -; SimpleBLE - NetBIOS - ESP32 - Preferences - BluetoothSerial +framework = ${common.framework} +platform = ${core32.platform} +platform_packages = ${core32.platform_packages} +board_build.filesystem = ${common.board_build.filesystem} +custom_unpack_dir = ${common.custom_unpack_dir} +board = esp32 +monitor_speed = 115200 +upload_resetmethod = ${common.upload_resetmethod} +extra_scripts = ${esp32_defaults.extra_scripts} +build_unflags = ${core32.build_unflags} +build_flags = ${core32.build_flags} +lib_ldf_mode = ${common.lib_ldf_mode} +lib_compat_mode = ${common.lib_compat_mode} +lib_extra_dirs = ${common.lib_extra_dirs} + lib/libesp32 + lib/libesp32_lvgl + lib/libesp32_div + lib/libesp32_eink + lib/libesp32_audio +lib_ignore = + HTTPUpdateServer + ESP RainMaker + WiFiProv + USB + SPIFFS + ESP32 Azure IoT Arduino + ESP32 Async UDP + ESP32 BLE Arduino +; SimpleBLE + NetBIOS + ESP32 + Preferences + BluetoothSerial ; Disable next if you want to use ArduinoOTA in Tasmota32 (default disabled) - ArduinoOTA + ArduinoOTA ; Add files to Filesystem for all env (global). Remove no files entry and add add a line with the file to include ; Example for adding the Partition Manager ; custom_files_upload = ; tasmota/berry/modules/Partition_Manager.tapp -custom_files_upload = no_files +custom_files_upload = no_files [env:tasmota32-safeboot] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-safeboot.bin"' lib_extra_dirs = lib/lib_ssl, lib/libesp32 lib_ignore = Micro-RTSP @@ -51,59 +53,87 @@ lib_ignore = [env:tasmota32] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32.bin"' [env:tasmota32-webcam] extends = env:tasmota32_base board = esp32-fix board_build.f_cpu = 240000000L -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_WEBCAM -DCAMERA_MODEL_AI_THINKER +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_WEBCAM + -DCAMERA_MODEL_AI_THINKER + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-webcam.bin"' lib_extra_dirs = lib/lib_ssl, lib/libesp32 [env:tasmota32-odroidgo] extends = env:tasmota32-lvgl -board_build.f_cpu = 240000000L -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 -DARDUINO_ODROID_ESP32 board = esp32-fix +board_build.f_cpu = 240000000L +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DARDUINO_ODROID_ESP32 + -DCODE_IMAGE_STR='"odroid"' + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-lvgl.bin"' [env:tasmota32-core2] extends = env:tasmota32-lvgl board_build.flash_mode = qio board_build.f_cpu = 240000000L board_build.f_flash = 80000000L -build_flags = ${env:tasmota32-lvgl.build_flags} -DUSE_I2S_SAY_TIME -DUSE_I2S_WEBRADIO -DUSE_SENDMAIL +build_flags = ${env:tasmota32-lvgl.build_flags} + -DUSE_I2S_SAY_TIME + -DUSE_I2S_WEBRADIO + -DUSE_SENDMAIL + -DCODE_IMAGE_STR='"core2"' + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-lvgl.bin"' lib_extra_dirs = lib/libesp32, lib/libesp32_lvgl, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display, lib/lib_audio [env:tasmota32-bluetooth] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_BLUETOOTH +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_BLUETOOTH + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-bluetooth.bin"' lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_ssl [env:tasmota32-display] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_DISPLAYS +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_DISPLAYS + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-display.bin"' lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_display, lib/lib_ssl [env:tasmota32-lvgl] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_LVGL +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_LVGL + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-lvgl.bin"' board_build.f_cpu = 240000000L lib_extra_dirs = lib/libesp32, lib/libesp32_lvgl, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display [env:tasmota32-ir] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DUSE_IR_REMOTE_FULL -DFIRMWARE_IR +build_flags = ${env:tasmota32_base.build_flags} + -DUSE_IR_REMOTE_FULL + -DFIRMWARE_IR + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-ir.bin"' lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_ssl [env:tasmota32solo1] extends = env:tasmota32_base board = esp32_solo1 -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DCODE_IMAGE_STR='"solo1"' + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32solo1.bin"' [env:tasmota32solo1-safeboot] extends = env:tasmota32_base board = esp32_solo1 -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32solo1-safeboot.bin"' lib_extra_dirs = lib/lib_ssl, lib/libesp32 lib_ignore = Micro-RTSP @@ -114,6 +144,7 @@ lib_ignore = extends = env:tasmota32_base board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv build_flags = ${env:tasmota32_base.build_flags} + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-zbbrdgpro.bin"' -DFIRMWARE_ZBBRDGPRO -DFRAMEWORK_ARDUINO_ITEAD custom_files_upload = ${env:tasmota32_base.custom_files_upload} @@ -129,6 +160,7 @@ extends = env:tasmota32_base build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_NSPANEL -DFRAMEWORK_ARDUINO_ITEAD + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-nspanel.bin"' [env:tasmota32c3-safeboot] extends = env:tasmota32_base @@ -136,7 +168,9 @@ board = esp32c3 build_unflags = ${env:tasmota32_base.build_unflags} -flto -mtarget-align -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3-safeboot.bin"' -fno-lto lib_extra_dirs = lib/lib_ssl, lib/libesp32 lib_ignore = @@ -150,7 +184,9 @@ board = esp32c3 build_unflags = ${env:tasmota32_base.build_unflags} -flto -mtarget-align -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3.bin"' -fno-lto lib_ignore = TTGO TWatch Library @@ -161,15 +197,24 @@ lib_ignore = [env:tasmota32c3cdc-safeboot] extends = env:tasmota32c3-safeboot board = esp32c3cdc +build_flags = ${env:tasmota32_base.build_flags} + -fno-lto + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3cdc-safeboot.bin"' [env:tasmota32c3cdc] extends = env:tasmota32c3 board = esp32c3cdc +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3cdc.bin"' [env:tasmota32s2-safeboot] extends = env:tasmota32_base board = esp32s2 -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s2-safeboot.bin"' lib_extra_dirs = lib/lib_ssl, lib/libesp32 lib_ignore = Micro-RTSP @@ -179,7 +224,9 @@ lib_ignore = [env:tasmota32s2] extends = env:tasmota32_base board = esp32s2 -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s2.bin"' lib_ignore = TTGO TWatch Library NimBLE-Arduino @@ -189,15 +236,23 @@ lib_ignore = [env:tasmota32s2cdc-safeboot] extends = env:tasmota32s2-safeboot board = esp32s2cdc +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s2cdc-safeboot.bin"' [env:tasmota32s2cdc] extends = env:tasmota32s2 board = esp32s2cdc +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s2cdc.bin"' [env:tasmota32s3-safeboot] extends = env:tasmota32_base board = esp32s3-qio_qspi -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s3-safeboot.bin"' lib_extra_dirs = lib/lib_ssl, lib/libesp32 lib_ignore = Micro-RTSP @@ -207,7 +262,9 @@ lib_ignore = [env:tasmota32s3] extends = env:tasmota32_base board = esp32s3-qio_qspi -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s3.bin"' lib_ignore = TTGO TWatch Library Micro-RTSP @@ -216,111 +273,117 @@ lib_ignore = [env:tasmota32s3cdc-safeboot] extends = env:tasmota32s3-safeboot board = esp32s3cdc-qio_qspi +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_SAFEBOOT + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32c3cdc-safeboot.bin"' [env:tasmota32s3cdc] extends = env:tasmota32s3 board = esp32s3cdc-qio_qspi +build_flags = ${env:tasmota32_base.build_flags} + -DFIRMWARE_TASMOTA32 + -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32s3cdc.bin"' [env:tasmota32-AD] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ca_AD -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ca_AD -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-AD.bin"' [env:tasmota32-AF] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=af_AF -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=af_AF -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-AF.bin"' [env:tasmota32-BG] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=bg_BG -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=bg_BG -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-BG.bin"' [env:tasmota32-BR] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=pt_BR -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=pt_BR -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-BR.bin"' [env:tasmota32-CN] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=zh_CN -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=zh_CN -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-CN.bin"' [env:tasmota32-CZ] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=cs_CZ -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=cs_CZ -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-CZ.bin"' [env:tasmota32-DE] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=de_DE -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=de_DE -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-DE.bin"' [env:tasmota32-ES] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=es_ES -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=es_ES -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-ES.bin"' [env:tasmota32-FR] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=fr_FR -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=fr_FR -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-FR.bin"' [env:tasmota32-FY] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=fy_NL -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=fy_NL -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-FY.bin"' [env:tasmota32-GR] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=el_GR -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=el_GR -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-GR.bin"' [env:tasmota32-HE] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=he_HE -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=he_HE -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-HE.bin"' [env:tasmota32-HU] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=hu_HU -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=hu_HU -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-HU.bin"' [env:tasmota32-IT] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=it_IT -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=it_IT -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-IT.bin"' [env:tasmota32-KO] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ko_KO -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ko_KO -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-KO.bin"' [env:tasmota32-NL] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=nl_NL -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=nl_NL -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-NL.bin"' [env:tasmota32-PL] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=pl_PL -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=pl_PL -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-PL.bin"' [env:tasmota32-PT] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=pt_PT -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=pt_PT -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-PT.bin"' [env:tasmota32-RO] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ro_RO -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ro_RO -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-RO.bin"' [env:tasmota32-RU] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ru_RU -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=ru_RU -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-RU.bin"' [env:tasmota32-SE] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=sv_SE -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=sv_SE -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-SE.bin"' [env:tasmota32-SK] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=sk_SK -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=sk_SK -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-SK.bin"' [env:tasmota32-TR] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=tr_TR -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=tr_TR -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-TR.bin"' [env:tasmota32-TW] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=zh_TW -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=zh_TW -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-TW.bin"' [env:tasmota32-UK] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=uk_UA -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=uk_UA -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-UK.bin"' [env:tasmota32-VN] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=vi_VN -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DMY_LANGUAGE=vi_VN -DFIRMWARE_TASMOTA32 -DOTA_URL='"http://ota.tasmota.com/tasmota32/release/tasmota32-VN.bin"' diff --git a/tasmota/berry/drivers/M5Stack_DigiClock.be b/tasmota/berry/drivers/M5Stack_DigiClock.be new file mode 100644 index 000000000..9f72bdbbe --- /dev/null +++ b/tasmota/berry/drivers/M5Stack_DigiClock.be @@ -0,0 +1,38 @@ +# Simple driver for M5Stack DigiClock I2C 7 segments LED +# +# https://docs.m5stack.com/en/unit/digi_clock + +class M5Stack_DigiClock + static var I2C_ADDR = 0x30 # default I2C address is 0x30 + var led + var addr + + def init(addr) + if !addr addr = self.I2C_ADDR end + + self.addr = addr + self.led = tasmota.wire_scan(addr) + + if self.led == nil raise "configuration_error", "Could not find DigiClock I2C device" end + end + + def set_brightness(b) + if b < 0 b = 0 end + if b > 8 b = 8 end + self.led.write(self.addr, 0x30, b, 1) + end + + def set_text(t) + self.led.write_bytes(0x30, 0x20, bytes().fromstring(str(t))) + end +end + +return M5Stack_DigiClock + +#- + +var led = M5Stack_DigiClock() +led.set_brightness(1) +led.set_text("1234") + +-# diff --git a/tasmota/berry/haspmota_src/haspmota_core/haspmota.be b/tasmota/berry/haspmota_src/haspmota_core/haspmota.be index 390b3fdd7..ec43e6131 100644 --- a/tasmota/berry/haspmota_src/haspmota_core/haspmota.be +++ b/tasmota/berry/haspmota_src/haspmota_core/haspmota.be @@ -978,6 +978,24 @@ class lvh_switch : lvh_obj def get_val() return self.get_toggle() end + def set_bg_color10(t) + self._lv_obj.set_style_bg_color(self.parse_color(t), lv.PART_INDICATOR | lv.STATE_CHECKED) + end + def set_bg_color20(t) + self._lv_obj.set_style_bg_color(self.parse_color(t), lv.PART_KNOB | lv.STATE_DEFAULT) + end + def set_radius20(t) + self._lv_obj.set_style_radius(int(t), lv.PART_KNOB | lv.STATE_DEFAULT) + end + def get_bg_color10() + return self._lv_obj.get_style_bg_color(lv.PART_INDICATOR) + end + def get_bg_color20() + return self._lv_obj.get_style_bg_color(lv.PART_KNOB) + end + def get_radius20() + return self._lv_obj.get_style_radius(lv.PART_KNOB) + end end #==================================================================== diff --git a/tasmota/displaydesc/ST7735S_Pro4PM_display.ini b/tasmota/displaydesc/ST7735S_Pro4PM_display.ini index 09579367c..3d15543b5 100644 --- a/tasmota/displaydesc/ST7735S_Pro4PM_display.ini +++ b/tasmota/displaydesc/ST7735S_Pro4PM_display.ini @@ -26,10 +26,7 @@ E1,10,03,1D,07,06,2E,2C,29,2D,2E,2E,37,3F,00,00,02,10 :O,29 :A,2A,2B,2C,16 :R,36 -:0,68,00,00,00 -:1,CC,1A,01,01 -:2,A8,01,1A,02 -:3,08,1A,01,03 +:0,60,00,00,00 :i,20,21 :B,60,1 # diff --git a/tasmota/include/Powerwall.h b/tasmota/include/Powerwall.h new file mode 100755 index 000000000..324bfa262 --- /dev/null +++ b/tasmota/include/Powerwall.h @@ -0,0 +1,188 @@ + +// inspred by https://github.com/MoritzLerch/tesla-pv-display +#ifndef Powerwall_h +#define Powerwall_h + +// include libraries +#ifdef ESP8266 +#include "WiFiClientSecureLightBearSSL.h" +#else +#include +#endif //ESP8266 + + +class Powerwall { + private: + const char* powerwall_ip; + String tesla_email; + String tesla_password; + String authCookie; + + public: + Powerwall(); + String getAuthCookie(); + String GetRequest(String url, String authCookie); + String GetRequest(String url); + String AuthCookie(); +}; + + +Powerwall::Powerwall() { + powerwall_ip = POWERWALL_IP_CONFIG; + tesla_email = TESLA_EMAIL; + tesla_password = TESLA_PASSWORD; + authCookie = ""; +} + +String Powerwall::AuthCookie() { + return authCookie; +} + +/** + * This function returns a string with the authToken based on the basic login endpoint of + * the powerwall in combination with the credentials from the secrets.h + * @returns authToken to be used in an authCookie + */ +String Powerwall::getAuthCookie() { + AddLog(LOG_LEVEL_DEBUG, PSTR("PWL: requesting new auth Cookie from %s"), powerwall_ip); + String apiLoginURL = "/api/login/Basic"; + +#ifdef ESP32 + WiFiClientSecure *httpsClient = new WiFiClientSecure; +#else + // BearSSL::WiFiClientSecure_light *httpsClient = new BearSSL::WiFiClientSecure_light(1024,1024); + WiFiClientSecure *httpsClient = new WiFiClientSecure; +#endif + httpsClient->setInsecure(); + httpsClient->setTimeout(10000); + + int retry = 0; + +#define PW_RETRIES 5 + while ((!httpsClient->connect(powerwall_ip, 443)) && (retry < PW_RETRIES)) { + delay(100); + Serial.print("."); + retry++; + } + + if (retry >= PW_RETRIES) { + delete httpsClient; + return ("CONN-FAIL"); + } + + AddLog(LOG_LEVEL_DEBUG, PSTR("PWL: connected")); + + String dataString = "{\"username\":\"customer\",\"email\":\"" + tesla_email + "\",\"password\":\"" + tesla_password + "\",\"force_sm_off\":false}"; + + String payload = String("POST ") + apiLoginURL + " HTTP/1.1\r\n" + + "Host: " + powerwall_ip + "\r\n" + + "Connection: close" + "\r\n" + + "Content-Type: application/json" + "\r\n" + + "Content-Length: " + dataString.length() + "\r\n" + + "\r\n" + dataString + "\r\n\r\n"; + + httpsClient->println(payload); + + while (httpsClient->connected()) { + String response = httpsClient->readStringUntil('\n'); + if (response == "\r") { + break; + } + } + + String jsonInput = httpsClient->readStringUntil('\n'); + + char str_value[128]; + str_value[0] = 0; + float fv; + JsonParser parser((char*)jsonInput.c_str()); + JsonParserObject obj = parser.getRootObject(); + uint32_t res = JsonParsePath(&obj, "token", '#', &fv, str_value, sizeof(str_value)); + + AddLog(LOG_LEVEL_DEBUG, PSTR("PWL: token: %s"), str_value); + + authCookie = str_value; + + delete httpsClient; + + return authCookie; +} + +/** + * This function does a GET-request on the local powerwall web server. + * This is mainly used here to do API requests. + * HTTP/1.0 is used because some responses are so big that this would encounter + * chunked transfer encoding in HTTP/1.1 (https://en.wikipedia.org/wiki/Chunked_transfer_encoding) + * + * @param url relative URL on the Powerwall + * @param authCookie optional, but recommended + * @returns content of request + */ +String Powerwall::GetRequest(String url, String authCookie) { +#ifdef ESP32 + WiFiClientSecure *httpsClient = new WiFiClientSecure; +#else + //BearSSL::WiFiClientSecure_light *httpsClient = new BearSSL::WiFiClientSecure_light(1024,1024); + WiFiClientSecure *httpsClient = new WiFiClientSecure; +#endif + httpsClient->setInsecure(); + httpsClient->setTimeout(10000); + + if (authCookie == "") { + getAuthCookie(); + } + + AddLog(LOG_LEVEL_DEBUG, PSTR("PWL: doing GET-request to %s%s"), powerwall_ip, url.c_str()); + + int retry = 0; + + while ((!httpsClient->connect(powerwall_ip, 443)) && (retry < 15)) { + delay(100); + Serial.print("."); + retry++; + } + + if (retry >= 15) { + delete httpsClient; + return ("CONN-FAIL"); + } + + // HTTP/1.0 is used because of Chunked transfer encoding + httpsClient->print(String("GET ") + url + " HTTP/1.0" + "\r\n" + + "Host: " + powerwall_ip + "\r\n" + + "Cookie: " + "AuthCookie" + "=" + authCookie + "\r\n" + + "Connection: close\r\n\r\n"); + + while (httpsClient->connected()) { + String response = httpsClient->readStringUntil('\n'); + char *cp = (char*)response.c_str(); + if (!strncmp_P(cp, PSTR("HTTP"), 4)) { + char *sp = strchr(cp, ' '); + if (sp) { + sp++; + uint16_t result = strtol(sp, 0, 10); + AddLog(LOG_LEVEL_DEBUG, PSTR("PWL: result %d"), result); + // in case of error 401, get new cookie + if (result == 401) { + authCookie = ""; + } + } + } + if (response == "\r") { + break; + } + } + + String result = httpsClient->readStringUntil('\n'); + delete httpsClient; + return result; +} + +/** + * this is getting called if there was no provided authCookie in powerwallGetRequest(String url, String authCookie) + */ +String Powerwall::GetRequest(String url) { + return (GetRequest(url, getAuthCookie())); +} + +#endif diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h index c3df48348..54e51a04f 100644 --- a/tasmota/include/i18n.h +++ b/tasmota/include/i18n.h @@ -30,6 +30,7 @@ #define D_JSON_ACK "Ack" #define D_JSON_ACTIVE "Active" #define D_JSON_ADDRESS "Address" +#define D_JSON_AHUM "aHumidity" #define D_JSON_AIRQUALITY "AirQuality" #define D_JSON_ANALOG_INPUT "Analog" #define D_JSON_AP "AP" // Access Point @@ -738,6 +739,7 @@ #define D_CMND_SHUTTER_SETTILT "Tilt" #define D_CMND_SHUTTER_TILTINCDEC "TiltChange" #define D_CMND_SHUTTER_MOTORSTOP "MotorStop" +#define D_CMND_SHUTTER_SETUP "Setup" // Commands xdrv_32_hotplug.ino #define D_CMND_HOTPLUG "HotPlug" @@ -894,6 +896,10 @@ const char HTTP_SNS_F_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{ const char HTTP_SNS_F_VOLTAGE[] PROGMEM = "{s}%s " D_VOLTAGE "{m}%*_f " D_UNIT_VOLT "{e}"; const char HTTP_SNS_F_CURRENT_MA[] PROGMEM = "{s}%s " D_CURRENT "{m}%*_f " D_UNIT_MILLIAMPERE "{e}"; const char HTTP_SNS_F_DISTANCE_CM[] PROGMEM = "{s}%s " D_DISTANCE "{m}%1_f " D_UNIT_CENTIMETER "{e}"; +const char HTTP_SNS_F_NOX[] PROGMEM = "{s}%s " D_NOX "{m}%*_f " "{e}"; +const char HTTP_SNS_F_VOC[] PROGMEM = "{s}%s " D_VOC "{m}%*_f " "{e}"; +const char HTTP_SNS_F_ABS_HUM[] PROGMEM = "{s}%s " D_ABSOLUTE_HUMIDITY "{m}%*_f " D_UNIT_GRAM_PER_CUBIC_METER "{e}"; + const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s " D_UNIT_PERCENT "{e}"; const char HTTP_SNS_DEW[] PROGMEM = "{s}%s " D_DEWPOINT "{m}%s " D_UNIT_DEGREE "%c{e}"; const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s " "%s{e}"; @@ -908,10 +914,6 @@ const char HTTP_SNS_MOISTURE[] PROGMEM = "{s}%s " D_MOISTURE "{ const char HTTP_SNS_RANGE_CHR[] PROGMEM = "{s}%s " D_RANGE "{m}%s" "{e}"; const char HTTP_SNS_RANGE[] PROGMEM = "{s}%s " D_RANGE "{m}%d" "{e}"; const char HTTP_SNS_HALL_EFFECT[] PROGMEM = "{s}%s " D_HALL_EFFECT "{m}%d" "{e}"; -const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"; -const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"; -const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE_ACTIVE "{m}%s " D_UNIT_WATT "{e}"; -const char HTTP_SNS_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; const char HTTP_SNS_PH[] PROGMEM = "{s}%s " D_PH "{m}%s " "{e}"; const char HTTP_SNS_MQ[] PROGMEM = "{s}" D_MQ"-%s" "{m}%s " D_UNIT_PARTS_PER_MILLION "{e}"; const char HTTP_SNS_ORP[] PROGMEM = "{s}%s " D_ORP "{m}%s " D_UNIT_MILLIVOLT "{e}"; @@ -927,6 +929,33 @@ const char HTTP_SNS_MILLILITERS[] PROGMEM = "{s}%s " D_VOLUME "{ const char HTTP_SNS_GAS[] PROGMEM = "{s}%s " D_GAS "{m}%d " D_UNIT_PERCENT "LEL{e}"; const char HTTP_SNS_SOC[] PROGMEM = "{s}%s " D_SOC "{m}%d " D_UNIT_PERCENT "{e}"; const char HTTP_SNS_SOH[] PROGMEM = "{s}%s " D_SOH "{m}%d " D_UNIT_PERCENT "{e}"; + +const char HTTP_SNS_STANDARD_CONCENTRATION[] PROGMEM = "{s}%s " D_STANDARD_CONCENTRATION " %s " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; +const char HTTP_SNS_ENVIRONMENTAL_CONCENTRATION[] PROGMEM = "{s}%s " D_ENVIRONMENTAL_CONCENTRATION " %s " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; +const char HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION[] PROGMEM = "{s}%s " D_ENVIRONMENTAL_CONCENTRATION " %s " D_UNIT_MICROMETER "{m}%1_f " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; +const char HTTP_SNS_PARTICALS_BEYOND[] PROGMEM = "{s}%s " D_PARTICALS_BEYOND " %s " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; +const char HTTP_SNS_AVG_RAD_DOSE[] PROGMEM = "{s}%s " D_AVG_RAD_DOSE " %s " D_UNIT_MINUTE "{m}%d.%02d " D_UNIT_US_H "{e}"; + +const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}"; +const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}"; +const char HTTP_SNS_CURRENT_N[] PROGMEM = "{s}" D_CURRENT_NEUTRAL "{m}%s " D_UNIT_AMPERE "{e}"; +const char HTTP_SNS_POWER[] PROGMEM = "{s}" D_POWERUSAGE_ACTIVE "{m}%s " D_UNIT_WATT "{e}"; +const char HTTP_SNS_IMPORT_POWER[] PROGMEM = "{s}" D_IMPORT_POWER "{m}%s " D_UNIT_WATT "{e}"; +const char HTTP_SNS_EXPORT_POWER[] PROGMEM = "{s}" D_EXPORT_POWER "{m}%s " D_UNIT_WATT "{e}"; +const char HTTP_SNS_MAX_POWER[] PROGMEM = "{s}" D_MAX_POWER "{m}%s " D_UNIT_WATT "{e}"; +const char HTTP_SNS_POWERUSAGE_APPARENT[] PROGMEM = "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}"; +const char HTTP_SNS_POWERUSAGE_REACTIVE[] PROGMEM = "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}"; +const char HTTP_SNS_POWER_FACTOR[] PROGMEM = "{s}" D_POWER_FACTOR "{m}%s {e}"; +const char HTTP_SNS_ENERGY_TODAY[] PROGMEM = "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_ENERGY_YESTERDAY[] PROGMEM = "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_ENERGY_TOTAL[] PROGMEM = "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_EXPORT_ACTIVE[] PROGMEM = "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_TOTAL_ACTIVE[] PROGMEM = "{s}" D_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_RSTTBL_TOTAL_ACTIVE[] PROGMEM = "{s}" D_RESETTABLE_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; +const char HTTP_SNS_IMPORT_REACTIVE[] PROGMEM = "{s}" D_IMPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}"; +const char HTTP_SNS_EXPORT_REACTIVE[] PROGMEM = "{s}" D_EXPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}"; +const char HTTP_SNS_TOTAL_REACTIVE[] PROGMEM = "{s}" D_TOTAL_REACTIVE "{m}%s " D_UNIT_KWARH "{e}"; +const char HTTP_SNS_PHASE_ANGLE[] PROGMEM = "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}"; #endif // USE_WEBSERVER #endif // _I18N_H_ diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h index 40a8a3050..615a5bd7d 100644 --- a/tasmota/include/tasmota.h +++ b/tasmota/include/tasmota.h @@ -27,12 +27,6 @@ #define XFUNC_PTR_IN_ROM // Enable for keeping tables in ROM (PROGMEM) which seem to have access issues on some flash types #define MQTT_DATA_STRING // Use heap instead of fixed memory for TasmotaGlobal.mqtt_data -/*********************************************************************************************\ - * Default image -\*********************************************************************************************/ - -#define CODE_IMAGE_STR "tasmota" - /*********************************************************************************************\ * Power Type \*********************************************************************************************/ @@ -58,8 +52,8 @@ const uint8_t MAX_INTERLOCKS = 14; // Max number of interlock groups (u const uint8_t MAX_SWITCHES = 28; // Max number of switches selectable on GPIO const uint8_t MAX_KEYS = 28; // Max number of keys or buttons selectable on GPIO #endif // ESP32 -const uint8_t MAX_RELAYS_SET = 28; // Max number of relays -const uint8_t MAX_KEYS_SET = 28; // Max number of keys +const uint8_t MAX_RELAYS_SET = 32; // Max number of relays +const uint8_t MAX_KEYS_SET = 32; // Max number of keys // Changes to the following MAX_ defines will impact settings layout const uint8_t MAX_INTERLOCKS_SET = 14; // Max number of interlock groups (MAX_RELAYS_SET / 2) @@ -206,11 +200,6 @@ const uint16_t MAX_INPUT_BUFFER_SIZE = 2048; // Max number of characters in Ardu const uint16_t FLOATSZ = 16; // Max number of characters in float result from dtostrfd (max 32) const uint16_t CMDSZ = 24; // Max number of characters in command const uint16_t TOPSZ = 151; // Max number of characters in topic string -#ifdef ESP8266 -const uint16_t GUISZ = 300; // Max number of characters in WebEnergyFormat string -#else -const uint16_t GUISZ = 600; // Max number of characters in WebEnergyFormat string -#endif #ifdef ESP8266 #ifdef PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED @@ -319,7 +308,7 @@ enum WeekInMonthOptions {Last, First, Second, Third, Fourth}; enum DayOfTheWeekOptions {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat}; enum MonthNamesOptions {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; enum HemisphereOptions {North, South}; -enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT, DT_LOCAL_MILLIS }; +enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_BOOTCOUNT, DT_LOCAL_MILLIS }; enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; @@ -393,9 +382,9 @@ enum LightSubtypes { LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LS enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7, LT_NU8, LT_SERIAL1, LT_SERIAL2, LT_RGB, LT_RGBW, LT_RGBWC, LT_NU14, LT_NU15 }; // Do not insert new fields -enum XsnsFunctions { FUNC_SETTINGS_OVERRIDE, FUNC_I2C_INIT, FUNC_PRE_INIT, FUNC_INIT, +enum XsnsFunctions { FUNC_SETTINGS_OVERRIDE, FUNC_SETUP_RING1, FUNC_SETUP_RING2, FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_SLEEP_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND, - FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_INTERRUPT_STOP, FUNC_INTERRUPT_START, + FUNC_RESET_SETTINGS, FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART, FUNC_INTERRUPT_STOP, FUNC_INTERRUPT_START, FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_WEB_COL_SENSOR, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, FUNC_LED_LINK, diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h index c8beda51b..94acfddd9 100644 --- a/tasmota/include/tasmota_configurations.h +++ b/tasmota/include/tasmota_configurations.h @@ -27,8 +27,9 @@ #ifdef FIRMWARE_SENSORS -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "sensors" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "sensors" +#endif #undef USE_DISCOVERY // Disable mDNS (+8k code or +23.5k code with core 2_5_x, +0.3k mem) @@ -103,6 +104,7 @@ #define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) //#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) //#define USE_MCP230xx // [I2cDriver22] Enable MCP23008/MCP23017 - Must define I2C Address in #define USE_MCP230xx_ADDR below - range 0x20 - 0x27 (+4k7 code) +//#define USE_MCP23XXX_DRV // [I2cDriver77] Enable MCP23xxx support as virtual switch/button/relay (+3k(I2C)/+5k(SPI) code) //#define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) //#define USE_MPR121 // [I2cDriver23] Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) #define USE_CCS811 // [I2cDriver24] Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) @@ -121,7 +123,11 @@ //#define USE_MLX90614 // [I2cDriver32] Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) //#define USE_CHIRP // [I2cDriver33] Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) //#define USE_PAJ7620 // [I2cDriver34] Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) -//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+1k9 code) +//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+2k1 code) +// #define USE_PCF8574_MODE2 // Enable Mode2 virtual relays/buttons/switches (+2k3 code) +// #define USE_PCF8574_SENSOR // Enable Mode1 inputs and outputs in SENSOR message (+0k2 code) +// #define USE_PCF8574_DISPLAYINPUT // Enable Mode1 inputs display in Web page (+0k2 code) +// #define USE_PCF8574_MQTTINPUT // Enable Mode1 MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} (+0k5 code) #define USE_HIH6 // [I2cDriver36] Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) #define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code) @@ -156,6 +162,8 @@ //#define USE_DS3502 // [I2CDriver67] Enable DS3502 digital potentiometer (I2C address 0x28 - 0x2B) (+0k4 code) //#define USE_HYT // [I2CDriver68] Enable HYTxxx temperature and humidity sensor (I2C address 0x28) (+0k5 code) //#define USE_LUXV30B // [I2CDriver70] Enable RFRobot SEN0390 LuxV30b ambient light sensor (I2C address 0x4A) (+0k5 code) +//#define USE_PMSA003I // [I2cDriver78] Enable PMSA003I Air Quality Sensor (I2C address 0x12) (+1k8 code) +//#define USE_GDK101 // [I2cDriver79] Enable GDK101 sensor (I2C addresses 0x18 - 0x1B) (+1k2 code) //#define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC (I2C address 0x68) (+1k2 code) @@ -243,6 +251,7 @@ #define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code) //#define USE_A4988_STEPPER // Add support for A4988/DRV8825 stepper-motor-driver-circuit (+10k5 code) //#define USE_THERMOSTAT // Add support for Thermostat +#define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code) #undef DEBUG_THEO // Disable debug code #undef USE_DEBUG_DRIVER // Disable debug code #endif // FIRMWARE_SENSORS @@ -254,8 +263,9 @@ #ifdef FIRMWARE_KNX_NO_EMULATION -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "knx" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "knx" +#endif #ifndef USE_KNX #define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) @@ -280,8 +290,9 @@ #ifdef FIRMWARE_DISPLAYS -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "display" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "display" +#endif #undef USE_EMULATION // Disable Belkin WeMo and Hue Bridge emulation for Alexa (-16k code, -2k mem) #undef USE_EMULATION_HUE // Disable Hue Bridge emulation for Alexa (+14k code, +2k mem common) @@ -366,8 +377,9 @@ #ifdef FIRMWARE_IR -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "ir" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "ir" +#endif #undef USE_EMULATION #undef USE_EMULATION_HUE // Disable Hue emulation - only for lights and relays @@ -475,6 +487,7 @@ #undef USE_OPENTHERM // Disable support for OpenTherm (+15k code) #undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code) #undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface +#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor #undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor #undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI @@ -501,8 +514,9 @@ #ifdef FIRMWARE_ZBBRIDGE // ******************************************************************* -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "zbbridge" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "zbbridge" +#endif #undef MODULE #define MODULE SONOFF_ZB_BRIDGE // [Module] Select default module from tasmota_template.h @@ -607,6 +621,7 @@ #undef USE_OPENTHERM // Disable support for OpenTherm (+15k code) #undef USE_MIEL_HVAC // Disable support for Mitsubishi Electric HVAC serial interface (+5k code) #undef USE_PROJECTOR_CTRL // Disable support for LCD/DLP Projector serial control interface +#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor #undef USE_ENERGY_SENSOR // Disable energy sensors #undef USE_ADE7880 // Disable ADE7880 Energy monitor as used on Shelly 3EM (I2C address 0x38) (+3k8) @@ -664,8 +679,9 @@ #ifdef FIRMWARE_LITE -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "lite" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "lite" +#endif #undef APP_SLEEP #define APP_SLEEP 1 // Default to sleep = 1 for FIRMWARE_LITE @@ -762,6 +778,7 @@ #undef USE_TFMINIPLUS // Disable support for TFmini Plus (TFmini, TFmini-S) LiDAR modules via UART interface (+0k8) #undef USE_HRG15 // Disable support for Hydreon RG-15 Solid State Rain sensor (+1k5 code) #undef USE_VINDRIKTNING // Disable support for IKEA VINDRIKTNING particle concentration sensor (+1k code) +#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor #undef USE_ENERGY_SENSOR // Disable energy sensors #undef USE_PZEM004T // Disable PZEM004T energy sensor @@ -818,8 +835,9 @@ #ifndef FIRMWARE_MINICUSTOM #ifdef FIRMWARE_MINIMAL -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "minimal" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "minimal" +#endif #define FIRMWARE_MINIMAL_ONLY @@ -918,6 +936,7 @@ #undef USE_TFMINIPLUS // Disable support for TFmini Plus (TFmini, TFmini-S) LiDAR modules via UART interface (+0k8) #undef USE_HRG15 // Disable support for Hydreon RG-15 Solid State Rain sensor (+1k5 code) #undef USE_VINDRIKTNING // Disable support for IKEA VINDRIKTNING particle concentration sensor (+0k6 code) +#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor #undef USE_ENERGY_SENSOR // Disable energy sensors @@ -953,8 +972,9 @@ #ifdef FIRMWARE_MINICUSTOM #define FIRMWARE_MINIMAL -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "mini-custom" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "mini-custom" +#endif #undef FIRMWARE_LITE // Disable tasmota-lite with no sensors #undef FIRMWARE_SENSORS // Disable tasmota-sensors with useful sensors enabled @@ -1093,4 +1113,12 @@ #define USE_TLS // flag indicates we need to include TLS code #endif // USE_MQTT_TLS +/*********************************************************************************************\ + * Default image +\*********************************************************************************************/ + +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "tasmota" +#endif + #endif // _TASMOTA_CONFIGURATIONS_H_ diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 69de06a24..abdd66f7c 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -31,8 +31,9 @@ #ifdef FIRMWARE_SAFEBOOT -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "safeboot" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "safeboot" +#endif #undef FIRMWARE_LITE // Disable tasmota-lite with no sensors #undef FIRMWARE_SENSORS // Disable tasmota-sensors with useful sensors enabled @@ -137,6 +138,7 @@ #undef USE_TFMINIPLUS // Disable support for TFmini Plus (TFmini, TFmini-S) LiDAR modules via UART interface (+0k8) #undef USE_HRG15 // Disable support for Hydreon RG-15 Solid State Rain sensor (+1k5 code) #undef USE_VINDRIKTNING // Disable support for IKEA VINDRIKTNING particle concentration sensor (+0k6 code) +#undef USE_LOX_O2 // Disable support for LuminOx LOX O2 Sensor #undef USE_ENERGY_SENSOR // Disable energy sensors @@ -194,8 +196,9 @@ #ifdef FIRMWARE_WEBCAM -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "webcam" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "webcam" +#endif #define USE_WEBCAM #define ENABLE_RTSPSERVER @@ -238,8 +241,9 @@ #ifdef FIRMWARE_BLUETOOTH -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "bluetooth" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "bluetooth" +#endif #undef MODULE #define MODULE WEMOS // [Module] Select default module from tasmota_template.h @@ -275,8 +279,9 @@ #ifdef FIRMWARE_LVGL -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "lvgl-haspmota" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "lvgl-haspmota" +#endif #undef MODULE #define MODULE WEMOS // [Module] Select default module from tasmota_template.h @@ -346,12 +351,9 @@ #define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code) - #define USE_ENERGY_SENSOR // Add energy to support Shelly Pro 4PM display (+38k code) -#define USE_ADE7953 #define USE_SHELLY_PRO - #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) #undef USE_MLX90614 @@ -377,6 +379,7 @@ //#define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) //#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) //#define USE_MCP230xx // [I2cDriver22] Enable MCP23008/MCP23017 - Must define I2C Address in #define USE_MCP230xx_ADDR below - range 0x20 - 0x27 (+4k7 code) +#define USE_MCP23XXX_DRV // [I2cDriver77] Enable MCP23xxx support as virtual switch/button/relay (+3k(I2C)/+5k(SPI) code) //#define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) //#define USE_MPR121 // [I2cDriver23] Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) //#define USE_CCS811 // [I2cDriver24] Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) @@ -387,14 +390,18 @@ //#define USE_SCD30 // [I2cDriver29] Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) //#define USE_SCD40 // [I2cDriver62] Enable Sensiron SCd40 CO2 sensor (I2C address 0x62) (+3k3 code) //#define USE_SPS30 // [I2cDriver30] Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code) -//#define USE_ADE7953 // [I2cDriver7] Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) +#define USE_ADE7953 // [I2cDriver7] Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) //#define USE_VL53L0X // [I2cDriver31] Enable VL53L0x time of flight sensor (I2C address 0x29) (+4k code) //#define USE_VL53L1X // [I2cDriver54] Enable VL53L1X time of flight sensor (I2C address 0x29) using Pololu VL53L1X library (+2k9 code) //#define USE_TOF10120 // [I2cDriver57] Enable TOF10120 time of flight sensor (I2C address 0x52) (+0k6 code) //#define USE_MLX90614 // [I2cDriver32] Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) //#define USE_CHIRP // [I2cDriver33] Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) //#define USE_PAJ7620 // [I2cDriver34] Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) -//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+1k9 code) +//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+2k1 code) +// #define USE_PCF8574_MODE2 // Enable Mode2 virtual relays/buttons/switches (+2k3 code) +// #define USE_PCF8574_SENSOR // Enable Mode1 inputs and outputs in SENSOR message (+0k2 code) +// #define USE_PCF8574_DISPLAYINPUT // Enable Mode1 inputs display in Web page (+0k2 code) +// #define USE_PCF8574_MQTTINPUT // Enable Mode1 MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} (+0k5 code) //#define USE_HIH6 // [I2cDriver36] Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) //#define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) //#define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code) @@ -428,6 +435,8 @@ //#define USE_DS3502 // [I2CDriver67] Enable DS3502 digital potentiometer (I2C address 0x28 - 0x2B) (+0k4 code) //#define USE_HYT // [I2CDriver68] Enable HYTxxx temperature and humidity sensor (I2C address 0x28) (+0k5 code) //#define USE_LUXV30B // [I2CDriver70] Enable RFRobot SEN0390 LuxV30b ambient light sensor (I2C address 0x4A) (+0k5 code) +//#define USE_PMSA003I // [I2cDriver78] Enable PMSA003I Air Quality Sensor (I2C address 0x12) (+1k8 code) +//#define USE_GDK101 // [I2cDriver79] Enable GDK101 sensor (I2C addresses 0x18 - 0x1B) (+1k2 code) //#define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC (I2C address 0x68) (+1k2 code) @@ -472,8 +481,9 @@ #ifdef FIRMWARE_ZBBRDGPRO -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "zbbrdgpro" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "zbbrdgpro" +#endif #undef MODULE #define MODULE WEMOS // [Module] Select default module from tasmota_template.h @@ -522,8 +532,9 @@ #ifdef FIRMWARE_NSPANEL -#undef CODE_IMAGE_STR -#define CODE_IMAGE_STR "nspanel" +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "nspanel" +#endif #undef MODULE #define MODULE WEMOS // [Module] Select default module from tasmota_template.h @@ -541,6 +552,10 @@ #ifdef FIRMWARE_TASMOTA32 +#ifndef CODE_IMAGE_STR + #define CODE_IMAGE_STR "tasmota32" +#endif + #define USE_INFLUXDB // Enable influxdb support (+5k code) #define USE_ENHANCED_GUI_WIFI_SCAN @@ -595,6 +610,7 @@ #define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) //#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) //#define USE_MCP230xx // [I2cDriver22] Enable MCP23008/MCP23017 - Must define I2C Address in #define USE_MCP230xx_ADDR below - range 0x20 - 0x27 (+4k7 code) +#define USE_MCP23XXX_DRV // [I2cDriver77] Enable MCP23xxx support as virtual switch/button/relay (+3k(I2C)/+5k(SPI) code) //#define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) //#define USE_MPR121 // [I2cDriver23] Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) //#define USE_CCS811 // [I2cDriver24] Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) @@ -606,6 +622,7 @@ #define USE_SCD30 // [I2cDriver29] Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) #define USE_SCD40 // [I2cDriver62] Enable Sensiron SCd40 CO2 sensor (I2C address 0x62) (+3k5 code) //#define USE_SPS30 // [I2cDriver30] Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code) +#define USE_ADE7880 // [I2cDriver65] Enable ADE7880 Energy monitor as used on Shelly 3EM (I2C address 0x38) (+3k8) #define USE_ADE7953 // [I2cDriver7] Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) #define USE_VL53L0X // [I2cDriver31] Enable VL53L0x time of flight sensor (I2C address 0x29) (+4k code) //#define USE_VL53L1X // [I2cDriver54] Enable VL53L1X time of flight sensor (I2C address 0x29) using Pololu VL53L1X library (+2k9 code) @@ -613,7 +630,11 @@ //#define USE_MLX90614 // [I2cDriver32] Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) //#define USE_CHIRP // [I2cDriver33] Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) //#define USE_PAJ7620 // [I2cDriver34] Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) -//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+1k9 code) +//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+2k1 code) +// #define USE_PCF8574_MODE2 // Enable Mode2 virtual relays/buttons/switches (+2k3 code) +// #define USE_PCF8574_SENSOR // Enable Mode1 inputs and outputs in SENSOR message (+0k2 code) +// #define USE_PCF8574_DISPLAYINPUT // Enable Mode1 inputs display in Web page (+0k2 code) +// #define USE_PCF8574_MQTTINPUT // Enable Mode1 MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} (+0k5 code) #define USE_HIH6 // [I2cDriver36] Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) #define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code) @@ -644,6 +665,8 @@ //#define USE_DS3502 // [I2CDriver67] Enable DS3502 digital potentiometer (I2C address 0x28 - 0x2B) (+0k4 code) //#define USE_HYT // [I2CDriver68] Enable HYTxxx temperature and humidity sensor (I2C address 0x28) (+0k5 code) //#define USE_LUXV30B // [I2CDriver70] Enable RFRobot SEN0390 LuxV30b ambient light sensor (I2C address 0x4A) (+0k5 code) +//#define USE_PMSA003I // [I2cDriver78] Enable PMSA003I Air Quality Sensor (I2C address 0x12) (+1k8 code) +//#define USE_GDK101 // [I2cDriver79] Enable GDK101 sensor (I2C addresses 0x18 - 0x1B) (+1k2 code) //#define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC (I2C address 0x68) (+1k2 code) @@ -654,6 +677,7 @@ //#define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k code) //#define USE_MCP2515 // Add support for can bus using MCP2515 (+7k code) //#define USE_CANSNIFFER // Add support for can bus sniffer using MCP2515 (+5k code) +#define USE_MCP23XXX_DRV // [I2cDriver77] Enable MCP23xxx support as virtual switch/button/relay (+3k(I2C)/+5k(SPI) code) #define USE_SHELLY_PRO // Add support for Shelly Pro #define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) @@ -742,6 +766,7 @@ #define USE_BP1658CJ // Add support for BP1658CJ 5 channel led controller as used in Orein OS0100411267 Bulb #define USE_ETHERNET // Add support for ethernet (+20k code) #define USE_DISPLAY_TM1621_SONOFF // Add support for TM1621 display driver used by Sonoff POWR3xxD and THR3xxD +#define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code) #ifndef USE_KNX #define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h index 5dc854d01..53570e3c9 100644 --- a/tasmota/include/tasmota_template.h +++ b/tasmota/include/tasmota_template.h @@ -206,6 +206,9 @@ enum UserSelectablePins { GPIO_ME007_TRIG, GPIO_ME007_RX, // ME007 Serial/Trigger interface GPIO_TUYAMCUBR_TX, GPIO_TUYAMCUBR_RX, // TuyaMCU Bridge GPIO_BIOPDU_PZEM0XX_TX, GPIO_BIOPDU_PZEM016_RX, GPIO_BIOPDU_BIT, // Biomine BioPDU 625x12 + GPIO_MCP23XXX_INT, GPIO_MCP23SXX_CS, // MCP23xxx Int and SPI Chip select + GPIO_PCF8574_INT, // PCF8574 interrupt + GPIO_LOX_O2_RX, // LOX-O2 RX GPIO_SENSOR_END }; // Error as warning to rethink GPIO usage with max 2045 @@ -459,6 +462,9 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ME007_TRIG "|" D_SENSOR_ME007_RX "|" D_SENSOR_TUYAMCUBR_TX "|" D_SENSOR_TUYAMCUBR_RX "|" D_SENSOR_BIOPDU_PZEM0XX_TX "|" D_SENSOR_BIOPDU_PZEM016_RX "|" D_SENSOR_BIOPDU_BIT "|" + D_SENSOR_MCP23XXX_INT "|" D_SENSOR_MCP23SXX_CS "|" + D_SENSOR_PCF8574_INT "|" + D_SENSOR_LOX_O2_RX "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -466,6 +472,7 @@ const char kSensorNamesFixed[] PROGMEM = // Max number of GPIOs #define MAX_MAX31865S 6 +#define MAX_MCP23XXX 6 #define MAX_FLOWRATEMETER 2 #define MAX_A4988_MSS 3 #define MAX_WEBCAM_DATA 8 @@ -553,6 +560,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_I2C AGPIO(GPIO_I2C_SCL) + MAX_I2C, // I2C SCL AGPIO(GPIO_I2C_SDA) + MAX_I2C, // I2C SDA +#ifdef USE_PCF8574 + AGPIO(GPIO_PCF8574_INT), // PCF8574 Interrupt +#endif // USE_PCF8574 #endif #if defined(USE_I2S_AUDIO) || defined (USE_I2S) @@ -587,6 +597,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { #if defined(USE_MCP2515) || defined(USE_CANSNIFFER) AGPIO(GPIO_MCP2515_CS), #endif // USE_MCP2515 +#ifdef USE_MCP23XXX_DRV + AGPIO(GPIO_MCP23SXX_CS) + MAX_MCP23XXX, +#endif // USE_MCP23XXX_DRV #endif // USE_SPI #if defined(USE_SDCARD) && defined(ESP32) @@ -676,6 +689,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_SSPI_MAX31865_CS1) + MAX_MAX31865S, #endif +#ifdef USE_MCP23XXX_DRV + AGPIO(GPIO_MCP23XXX_INT) + MAX_MCP23XXX, +#endif + AGPIO(GPIO_TXD), // Serial interface AGPIO(GPIO_RXD), // Serial interface @@ -1011,6 +1028,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_LD2410_TX), // HLK-LD2410 Serial interface AGPIO(GPIO_LD2410_RX), // HLK-LD2410 Serial interface #endif +#ifdef USE_LOX_O2 // xsns_105_lox_o2.ino + AGPIO(GPIO_LOX_O2_RX), // LuminOx Oxygen Sensor LOX-O2 Serial interface +#endif /*-------------------------------------------------------------------------------------------*\ * Other sensors diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h index 757a9f2bd..7f947a51d 100644 --- a/tasmota/include/tasmota_types.h +++ b/tasmota/include/tasmota_types.h @@ -266,8 +266,7 @@ typedef union { uint32_t spare23 : 1; // bit 23 uint32_t spare24 : 1; // bit 24 uint32_t spare25 : 1; // bit 25 - uint32_t spare26 : 1; // bit 26 - uint32_t spare27 : 1; // bit 27 + uint32_t tariff_forced : 2; // bit 26..27 (v12.4.0.2) - Energy forced tariff : 0=tariff change on time, 1|2=tariff forced uint32_t sunrise_dawn_angle : 2; // bits 28/29 (v12.1.1.4) - uint32_t temperature_set_res : 2; // bits 30/31 (v9.3.1.4) - (Tuya) }; @@ -453,7 +452,10 @@ typedef union { uint32_t raw_send : 1; // Enable sending also real time raw data over MQTT uint32_t raw_limit : 1; // Limit raw data to minimal relevant fields (the ones moving quickly) uint32_t mode_standard : 1; // Set Linky Standard Mode (9600 bps stream) else legacy (1200 bps) - uint32_t spare4_1 : 4; // Keep some spares for future uses + uint32_t show_stats : 1; // Display frames stats informations on WEB interface + uint32_t spare1_1 : 1; // Keep some spares for future uses + uint32_t spare1_2 : 1; // Keep some spares for future uses + uint32_t spare1_3 : 1; // Keep some spares for future uses uint32_t spare8_1 : 8; // Keep some spares for future uses uint32_t spare8_2 : 8; // Keep some spares for future uses }; diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h index f69d0b6f2..5721cc2b8 100644 --- a/tasmota/include/tasmota_version.h +++ b/tasmota/include/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0C040000; // 12.4.0.0 +const uint32_t VERSION = 0x0C050000; // 12.5.0.0 #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index 91898f7a7..067ecf05d 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Luggehalte" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-press" #define D_NOISE "Geraas" #define D_NONE "Geen" +#define D_NOX "NOx" #define D_O2 "Suurstof" #define D_OFF "Uit" #define D_OFFLINE "Vanlyn" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV Level" #define D_UV_POWER "UV krag" #define D_VERSION "Weergawe" +#define D_VOC "VOC" #define D_VOLTAGE "Spanning" #define D_VOLUME "Volume" #define D_WEIGHT "Gewig" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "te laag" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pomptyd oorskry" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "Gemiddelde Stralingsdosis" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_AF_AF_H_ diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index db2b69eac..ca0eabab2 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Качество на въздуха" #define D_AP "Точка за достъп" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "неколкократно натискане" #define D_NOISE "Шум" #define D_NONE "Няма" +#define D_NOX "NOx" #define D_O2 "Кислород" #define D_OFF "Изкл." #define D_OFFLINE "Извън мрежа" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Ниво на UV" #define D_UV_POWER "Сила на UV" #define D_VERSION "Издание" +#define D_VOC "VOC" #define D_VOLTAGE "Напрежение" #define D_VOLUME "Обем" #define D_WEIGHT "Тегло" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "А" @@ -935,6 +942,7 @@ #define D_UNIT_GALLONS "гал" #define D_UNIT_GALLONS_PER_MIN "гал/мин" #define D_UNIT_KILOGRAM "кг" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "инч" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "твърде ниско" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "превишено време за помпане" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "средна доза радиация" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_BG_BG_H_ diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h index 754f4dee3..20b427448 100644 --- a/tasmota/language/ca_AD.h +++ b/tasmota/language/ca_AD.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Qualitat Aire" #define D_AP "PA" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-pressió" #define D_NOISE "Soroll" #define D_NONE "Cap" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Apagat" #define D_OFFLINE "Desconnectat" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Nivell UV" #define D_UV_POWER "Potència UV" #define D_VERSION "Versió" +#define D_VOC "VOC" #define D_VOLTAGE "Tensió" #define D_VOLUME "Volum" #define D_WEIGHT "Pes" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "massa baix" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "temps de bomba excedit" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "dosi mitjana de radiació" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_CA_AD_H_ diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 8fe0507c7..0752be295 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Kvalita vzduchu" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "několikeré-stisknutí" #define D_NOISE "Hluk" #define D_NONE "Žádný" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Vyp." #define D_OFFLINE "Offline" // Don't translate, LWT message! Nepředkládat, LWT zpráva! @@ -201,6 +203,7 @@ #define D_UV_LEVEL "úroveň UV" #define D_UV_POWER "UV Power" #define D_VERSION "Verze" +#define D_VOC "VOC" #define D_VOLTAGE "Napětí" #define D_VOLUME "Volume" #define D_WEIGHT "Hmotnost" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -935,6 +942,7 @@ #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" #define D_UNIT_KILOGRAM "kg" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "průměrná dávka záření" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_CS_CZ_H_ diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 83b685742..7ced98891 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Luftqualität" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "Mehrfachdruck" #define D_NOISE "Lautstärke" #define D_NONE "keine" +#define D_NOX "NOx" #define D_O2 "Sauerstoff" #define D_OFF "aus" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV-Level" #define D_UV_POWER "UV Intensität" #define D_VERSION "Version" +#define D_VOC "VOC" #define D_VOLTAGE "Spannung" #define D_VOLUME "Volume" #define D_WEIGHT "Gewicht" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Puls" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "zu niedrig" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "Pumpzeit überschritten" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "durchschnittliche Strahlendosis" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_DE_DE_H_ diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 3c5ed60c6..7228d86bb 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Διαχειριστής" #define D_AIR_QUALITY "Ποιότητα αέρα" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "ανίχνευση για πολλαπλά πατήματα" #define D_NOISE "Θόρυβος" #define D_NONE "Κανένα" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Off" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Επίπεδο UV" #define D_UV_POWER "Ένταση UV" #define D_VERSION "Έκδοση" +#define D_VOC "VOC" #define D_VOLTAGE "Τάση" #define D_VOLUME "Volume" #define D_WEIGHT "Βάρος" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "μέση δόση ακτινοβολίας" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_EL_GR_H_ diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 8071fe613..899a5691c 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Air quality" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-press" #define D_NOISE "Noise" #define D_NONE "None" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Off" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV Level" #define D_UV_POWER "UV Power" #define D_VERSION "Version" +#define D_VOC "VOC" #define D_VOLTAGE "Voltage" #define D_VOLUME "Volume" #define D_WEIGHT "Weight" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "Average Radiation Dose" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_EN_GB_H_ diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 9f6f5b351..4a8585a01 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Calidad del Aire" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-press" #define D_NOISE "Ruido" #define D_NONE "Ninguno" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Apagado" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Nivel UV" #define D_UV_POWER "UV Power" #define D_VERSION "Versión" +#define D_VOC "VOC" #define D_VOLTAGE "Tensión" #define D_VOLUME "Volumen" #define D_WEIGHT "Peso" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "Cruce por cero" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "muy bajo" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "tiempo de bomba excedido" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "dosis media de radiación" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_ES_ES_H_ diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 1657e5fdb..3991ac470 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -25,10 +25,10 @@ * Due to memory constraints only UTF-8 is supported. * To save code space keep text as short as possible. * Time and Date provided by SDK can not be localized (yet). - * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. + * Use online command StateText to translate OFF, ON, TOGGLE and HOLD. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.5.0.9 + * Updated until v12.4.0 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -51,15 +51,16 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Qualité de l'Air" #define D_AP "AP" // Access Point #define D_AS "comme" #define D_AUTO "AUTO" #define D_BATT "Batt" // Short for Battery -#define D_BLINK "Blink" +#define D_BLINK "Blink" // Not better in french #define D_BLINKOFF "BlinkOff" -#define D_BOOT_COUNT "Nombre de boot" +#define D_BOOT_COUNT "Nb. de boot" #define D_BRIGHTLIGHT "Luminosité" #define D_BSSID "BSSId" #define D_BUTTON "Bouton" @@ -75,22 +76,22 @@ #define D_CORS_DOMAIN "Domaine CORS" #define D_COUNT "Compte" #define D_COUNTER "Compteur" -#define D_CT_POWER "CT Power" +#define D_CT_POWER "Puissance CT" #define D_CURRENT "Courant" // As in Voltage and Current -#define D_CURRENT_NEUTRAL "Current Neutral" +#define D_CURRENT_NEUTRAL "Courant neutre" #define D_DATA "Donnée" #define D_DARKLIGHT "Sombre" #define D_DEBUG "Debug" #define D_DEWPOINT "Point de rosée" #define D_DISABLED "Désactivé" -#define D_MOVING_DISTANCE "Moving Distance" -#define D_STATIC_DISTANCE "Static Distance" -#define D_DETECT_DISTANCE "Detect Distance" +#define D_MOVING_DISTANCE "Distance mobile" +#define D_STATIC_DISTANCE "Distance fixe" +#define D_DETECT_DISTANCE "Distance détectée" #define D_DISTANCE "Distance" #define D_DNS_SERVER "Serveur DNS" #define D_DO "Oxygène dissout" #define D_DONE "Terminé" -#define D_DST_TIME "DST" +#define D_DST_TIME "DST" // Daylight Saving Time #define D_EC "EC" #define D_ECO2 "eCO₂" #define D_EMULATION "Émulation" @@ -105,7 +106,7 @@ #define D_FILE "Fichier" #define D_FLOW_RATE "Débit" #define D_FRAGMENTATION "frag." // Lower case abbreviated version of fragmentation used in "memory fragmentation" -#define D_FRAME_RATE "Frame rate" +#define D_FRAME_RATE "Fréq. image" #define D_FREE_MEMORY "Mémoire libre" #define D_PSR_MAX_MEMORY "Mémoire PS-RAM" #define D_PSR_FREE_MEMORY "Mémoire PS-RAM libre" @@ -114,18 +115,18 @@ #define D_GATEWAY "Passerelle" #define D_GROUP "Groupe" #define D_HOST "Hôte" -#define D_HALL_EFFECT "Hall Effect" +#define D_HALL_EFFECT "Effet Hall" #define D_HOSTNAME "Nom d'Hôte" #define D_HUMIDITY "Humidité" #define D_ILLUMINANCE "Éclairement" -#define D_IMMEDIATE "immédiat" // Button immediate +#define D_IMMEDIATE "immédiat" // Button immediate #define D_INDEX "Index" #define D_INFO "Info" #define D_INFRARED "Infra-rouge" #define D_INITIALIZED "Initialisé" #define D_IP_ADDRESS "Adresse IP" #define D_LIGHT "Lumière" -#define D_LWT "LWT" +#define D_LWT "LWT" // MQTT Last Will and Testament #define D_LQI "LQI" // ZigBee Link Quality Index #define D_MODULE "Module" #define D_MOISTURE "Humidité" @@ -133,16 +134,17 @@ #define D_MULTI_PRESS "multi-pression" #define D_NOISE "Bruit" #define D_NONE "Aucun" +#define D_NOX "NOx" #define D_O2 "Oxygène" #define D_OFF "Arrêt" #define D_OFFLINE "Déconnecté" #define D_OK "Ok" #define D_ON "Marche" #define D_ONLINE "Connecté" -#define D_ORP "ORP" +#define D_ORP "Redox" // Oxidation Reduction Potential #define D_PASSWORD "Mot de passe" #define D_PH "pH" -#define D_MQ "MQ" +#define D_MQ "MQ" // MQ series Gas sensor #define D_PARTITION "Partition" // As in flash and firmware partition #define D_PORT "Port" #define D_POWER_FACTOR "Fact de puiss" @@ -162,12 +164,12 @@ #define D_RESTARTING "Redémarre" #define D_RESTART_REASON "Raison du redémarrage" #define D_RESTORE "restaurer" -#define D_RETAINED "persistant" // MQTT +#define D_RETAINED "persistant" // MQTT #define D_RULE "Règle" #define D_SAVE "Enregistrer" #define D_SENSOR "Capteur" #define D_SSID "SSID" -#define D_START "Lancer" // "Lancer la mise à jour" +#define D_START "Lancer" // "Lancer la mise à jour" #define D_STD_TIME "STD" #define D_STOP "Stop" #define D_SUBNET_MASK "Masque sous-réseau" @@ -179,17 +181,17 @@ #define D_TEMPERATURE "Température" #define D_TO "à" #define D_TOGGLE "Inverser" -#define D_TOPIC "Topic" // Keep MQTT keyword +#define D_TOPIC "Topic" // Keep MQTT keyword #define D_TOTAL_USAGE "Eau totale" #define D_TRANSMIT "Transmettre" #define D_TRUE "Vrai" -#define D_TVOC "TVOC" +#define D_TVOC "TVOC" // not used ??? #define D_UPGRADE "la mise à jour" // "Lancer la mise à jour" -#define D_UPLOAD "Upload" // Not better in french +#define D_UPLOAD "Upload" // Not better in french #define D_UPTIME "Durée d'activité" -#define D_USED "used" +#define D_USED "utilisé" #define D_USER "Utilisateur" -#define D_UTC_TIME "UTC" +#define D_UTC_TIME "UTC" // Coordinated Universal Time #define D_UV_INDEX "Indice UV" #define D_UV_INDEX_1 "Faible" #define D_UV_INDEX_2 "Modéré" @@ -201,32 +203,33 @@ #define D_UV_LEVEL "Niveau UV" #define D_UV_POWER "Puissance UV" #define D_VERSION "Version" +#define D_VOC "VOC" #define D_VOLTAGE "Tension" #define D_VOLUME "Volume" #define D_WEIGHT "Poids" #define D_WARMLIGHT "Chaud" #define D_WEB_SERVER "Serveur web" -#define D_SOC "State of Charge" -#define D_SOH "State of Health" +#define D_SOC "État de la Charge" +#define D_SOH "État de Santé" // tasmota.ino -#define D_WARNING_MINIMAL_VERSION "ATTENTION Cette version ne supporte pas les réglages persistants" +#define D_WARNING_MINIMAL_VERSION "ATTENTION Cette version ne gère pas les réglages persistants" #define D_LEVEL_10 "niveau 1-0" #define D_LEVEL_01 "niveau 0-1" #define D_SERIAL_LOGGING_DISABLED "Journalisation série désactivée" #define D_SYSLOG_LOGGING_REENABLED "Jounalisation SysLog réactivée" #define D_SET_BAUDRATE_TO "Définir le débit à" -#define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT +#define D_RECEIVED_TOPIC "Topic reçu" // Terme MQTT #define D_DATA_SIZE "Taille données" #define D_ANALOG_INPUT "Analogique" // support.ino -#define D_OSWATCH "osWatch" +#define D_OSWATCH "osWatch" // Indicateurs #define D_BLOCKED_LOOP "Boucle bloquée" #define D_WPS_FAILED_WITH_STATUS "WPSconfig ÉCHOUÉ avec status" #define D_ACTIVE_FOR_3_MINUTES "actif pour 3 minutes" -#define D_FAILED_TO_START "Échec de démarrage" +#define D_FAILED_TO_START "Échec du démarrage" #define D_PATCH_ISSUE_2186 "Correctif 2186" #define D_CONNECTING_TO_AP "Connexion à l'AP" #define D_IN_MODE "en mode" @@ -263,13 +266,13 @@ #define D_RESTART_IN "Redémarrage dans" #define D_SECONDS "secondes" #define D_DEVICE_WILL_RESTART "Le module va redémarrer dans quelques secondes" -#define D_BUTTON_TOGGLE "on/off" +#define D_BUTTON_TOGGLE "on/off" // Not better in french #define D_CONFIGURATION "Configuration" #define D_INFORMATION "Informations" #define D_FIRMWARE_UPGRADE "Mise à jour du Firmware" #define D_MANAGEMENT "Consoles" #define D_CONSOLE "Console" -#define D_CONFIRM_RESTART "Confirmer redémarrage" +#define D_CONFIRM_RESTART "Confirmer le redémarrage" #define D_CONFIGURE_MODULE "Configuration du Module" #define D_CONFIGURE_WIFI "Configuration WiFi" @@ -285,8 +288,8 @@ #define D_MODULE_PARAMETERS "Paramètres module" #define D_MODULE_TYPE "Type de module" -#define D_PULLUP_ENABLE "Inter. sans pull-up" -#define D_ADC "ADC" +#define D_PULLUP_ENABLE "Bouton/Inter. sans pull-up" +#define D_ADC "ADC" // Analog Input pin #define D_GPIO "GPIO" #define D_SERIAL_IN "Entrée série" #define D_SERIAL_OUT "Sortie série" @@ -302,19 +305,19 @@ #define D_WEP "WEP" #define D_WPA_PSK "WPA PSK" #define D_WPA2_PSK "WPA2 PSK" -#define D_AP1_SSID "WiFi Network" -#define D_AP1_SSID_HELP "Type or Select your WiFi Network" -#define D_AP2_SSID "WiFi Network 2" -#define D_AP2_SSID_HELP "Type your Alternative WiFi Network" +#define D_AP1_SSID "Réseau WiFi" +#define D_AP1_SSID_HELP "Saisissez ou Choisissez votre réseau WiFi" +#define D_AP2_SSID "Réseau WiFi 2" +#define D_AP2_SSID_HELP "Entrez un réseau WiFi de secours" #define D_AP_PASSWORD "Mot de passe" -#define D_AP_PASSWORD_HELP "Enter your WiFi Password" -#define D_SELECT_YOUR_WIFI_NETWORK "Select your WiFi Network" -#define D_SHOW_MORE_WIFI_NETWORKS "Scan for all WiFi Networks" -#define D_SHOW_MORE_OPTIONS "More Options" -#define D_CHECK_CREDENTIALS "Please, check your credentials" -#define D_SUCCESSFUL_WIFI_CONNECTION "Successful WiFi Connection" -#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Now you can close this window" -#define D_REDIRECTING_TO_NEW_IP "Redirecting to new device's IP address" +#define D_AP_PASSWORD_HELP "Entrez votre mot de passe WiFi" +#define D_SELECT_YOUR_WIFI_NETWORK "Choisissez votre réseau WiFi" +#define D_SHOW_MORE_WIFI_NETWORKS "Scanner les réseaux WiFi" +#define D_SHOW_MORE_OPTIONS "Plus d'Options" +#define D_CHECK_CREDENTIALS "Veuillez vérifier vos identifiants" +#define D_SUCCESSFUL_WIFI_CONNECTION "Connexion WiFi réussie" +#define D_NOW_YOU_CAN_CLOSE_THIS_WINDOW "Vous pouvez fermer cette fenêtre" +#define D_REDIRECTING_TO_NEW_IP "Redirection vers l'adresse IP d'un autre appareil" #define D_MQTT_PARAMETERS "Paramètres MQTT" #define D_CLIENT "Client" @@ -367,10 +370,10 @@ #define D_MQTT_TOPIC "Topic MQTT" #define D_MQTT_GROUP_TOPIC "Groupe topic MQTT" #define D_MQTT_FULL_TOPIC "Topic complet MQTT" -#define D_MQTT_NO_RETAIN "MQTT No Retain" +#define D_MQTT_NO_RETAIN "MQTT No Retain" // Keep MQTT keyword #define D_MDNS_DISCOVERY "Découverte mDNS" #define D_MDNS_ADVERTISE "Annonce mDNS" -#define D_ESP_CHIP_ID "ESP Chip Id" +#define D_ESP_CHIP_ID "ESP Chip Id" // Not better in french #define D_FLASH_CHIP_ID "Flash Chip Id" #define D_FLASH_CHIP_SIZE "Taille flash" #define D_FREE_PROGRAM_SPACE "Espace programme libre" @@ -379,7 +382,7 @@ #define D_OTA_URL "URL OTA" #define D_START_UPGRADE "Lancer la mise à jour" #define D_UPGRADE_BY_FILE_UPLOAD "Mise à jour par téléchargement fichier" -#define D_UPLOAD_FACTORY "Switching to safeboot partition" +#define D_UPLOAD_FACTORY "Lancement de la partition Safeboot" #define D_UPLOAD_STARTED "Téléchargement lancé" #define D_UPGRADE_STARTED "Mise à jour lancée" #define D_UPLOAD_DONE "Téléchargement terminé" @@ -498,12 +501,12 @@ #define D_ZIGBEE_GENERATE_KEY "création d'une clé réseau ZigBee aléatoire" #define D_ZIGBEE_UNKNOWN_DEVICE "Module inconnu" #define D_ZIGBEE_UNKNOWN_ATTRIBUTE "Attribut inconnu" -#define D_ZIGBEE_UNKNOWN_ENDPOINT "Unknown endpoint" +#define D_ZIGBEE_UNKNOWN_ENDPOINT "Endpoint inconnu" #define D_ZIGBEE_INVALID_PARAM "Paramètre invalide" #define D_ZIGBEE_MISSING_PARAM "Paramètres manquants" #define D_ZIGBEE_UNKNWON_ATTRIBUTE "Nom d'attribut inconnu (ignoré): %s" #define D_ZIGBEE_TOO_MANY_CLUSTERS "Pas plus d'un Id de Cluster par commande" -#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflicting destination endpoints" +#define D_ZIGBEE_CONFLICTING_ENDPOINTS "Conflit de Endpoint destinataires" #define D_ZIGBEE_WRONG_DELIMITER "Mauvais délimiteur dans le contenu du message" #define D_ZIGBEE_UNRECOGNIZED_COMMAND "Commande ZigBee inconnue: %s" #define D_ZIGBEE_TOO_MANY_COMMANDS "Une seule commande autorisée (%d)" @@ -638,20 +641,20 @@ #define D_SENSOR_SI7021 "SI7021" #define D_SENSOR_MS01 "MS01" #define D_SENSOR_DS18X20 "DS18x20" -#define D_SENSOR_I2C_SCL "I2C SCL" -#define D_SENSOR_I2C_SDA "I2C SDA" -#define D_SENSOR_I2S_MCLK "I2S MCLK" -#define D_SENSOR_I2S_BCLK "I2S BCLK" -#define D_SENSOR_I2S_WS_IN "I2S BCLK IN" +#define D_SENSOR_I2C_SCL "I2C SCl" +#define D_SENSOR_I2C_SDA "I2C SDa" +#define D_SENSOR_I2S_MCLK "I2S MClk" +#define D_SENSOR_I2S_BCLK "I2S BClk" +#define D_SENSOR_I2S_WS_IN "I2S BClk In" #define D_SENSOR_I2S_WS "I2S WS" -#define D_SENSOR_I2S_BCLK_IN "I2S WS IN" -#define D_SENSOR_I2S_DIN "I2S DIN" -#define D_SENSOR_I2S_DOUT "I2S DOUT" +#define D_SENSOR_I2S_BCLK_IN "I2S WS In" +#define D_SENSOR_I2S_DIN "I2S DIn" +#define D_SENSOR_I2S_DOUT "I2S DOut" #define D_SENSOR_WS2812 "WS2812" #define D_SENSOR_DFR562 "MP3 Player" #define D_SENSOR_DFR562_BUSY "MP3 Busy" -#define D_SENSOR_IRSEND "IR TX" -#define D_SENSOR_SWITCH "Inter" // Suffix "1" +#define D_SENSOR_IRSEND "IR Tx" +#define D_SENSOR_SWITCH "Inter" // Suffix "1" #define D_SENSOR_BUTTON "Bouton" // Suffix "1" #define D_SENSOR_RELAY "Relais" // Suffix "1i" #define D_SENSOR_LED "LED" // Suffix "1i" @@ -660,181 +663,181 @@ #define D_SENSOR_COUNTER "Compteur" // Suffix "1" #define D_SENSOR_INTERRUPT "Interrupt" #define D_SENSOR_INPUT "Input" -#define D_SENSOR_IRRECV "IR RX" -#define D_SENSOR_MHZ_RX "MHZ RX" -#define D_SENSOR_MHZ_TX "MHZ TX" -#define D_SENSOR_PZEM004_RX "PZEM004 RX" -#define D_SENSOR_PZEM016_RX "PZEM016 RX" -#define D_SENSOR_PZEM017_RX "PZEM017 RX" -#define D_SENSOR_PZEM0XX_TX "PZEM0XX TX" -#define D_SENSOR_SAIR_RX "SAir RX" -#define D_SENSOR_SAIR_TX "SAir TX" +#define D_SENSOR_IRRECV "IR Rx" +#define D_SENSOR_MHZ_RX "MHZ Rx" +#define D_SENSOR_MHZ_TX "MHZ Tx" +#define D_SENSOR_PZEM004_RX "PZEM004 Rx" +#define D_SENSOR_PZEM016_RX "PZEM016 Rx" +#define D_SENSOR_PZEM017_RX "PZEM017 Rx" +#define D_SENSOR_PZEM0XX_TX "PZEM0XX Tx" +#define D_SENSOR_SAIR_RX "SAir Rx" +#define D_SENSOR_SAIR_TX "SAir Tx" #define D_SENSOR_SPI_CS "SPI CS" #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_SPI_MISO "SPI MISO" #define D_SENSOR_SPI_MOSI "SPI MOSI" -#define D_SENSOR_SPI_CLK "SPI CLK" -#define D_SENSOR_SDIO_CMD "SDIO CMD" -#define D_SENSOR_SDIO_CLK "SDIO CLK" +#define D_SENSOR_SPI_CLK "SPI Clk" +#define D_SENSOR_SDIO_CMD "SDIO Cmd" +#define D_SENSOR_SDIO_CLK "SDIO Clk" #define D_SENSOR_SDIO_D0 "SDIO D0" #define D_SENSOR_SDIO_D1 "SDIO D1" #define D_SENSOR_SDIO_D2 "SDIO D2" #define D_SENSOR_SDIO_D3 "SDIO D3" -#define D_SENSOR_BACKLIGHT "RétroÉcl" -#define D_SENSOR_PMS5003_TX "PMS5003 TX" -#define D_SENSOR_PMS5003_RX "PMS5003 RX" -#define D_SENSOR_SDS0X1_RX "SDS0X1 RX" -#define D_SENSOR_SDS0X1_TX "SDS0X1 TX" -#define D_SENSOR_HPMA_RX "HPMA RX" -#define D_SENSOR_HPMA_TX "HPMA TX" -#define D_SENSOR_SBR_RX "SerBr RX" -#define D_SENSOR_SBR_TX "SerBr TX" +#define D_SENSOR_BACKLIGHT "RétroÉcl" +#define D_SENSOR_PMS5003_TX "PMS5003 Tx" +#define D_SENSOR_PMS5003_RX "PMS5003 Rx" +#define D_SENSOR_SDS0X1_RX "SDS0X1 Rx" +#define D_SENSOR_SDS0X1_TX "SDS0X1 Tx" +#define D_SENSOR_HPMA_RX "HPMA Rx" +#define D_SENSOR_HPMA_TX "HPMA Tx" +#define D_SENSOR_SBR_RX "SerBr Rx" +#define D_SENSOR_SBR_TX "SerBr Tx" #define D_SENSOR_MBR_TX "ModBr Tx" #define D_SENSOR_MBR_RX "ModBr Rx" #define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena" -#define D_SENSOR_SR04_TRIG "SR04 Tri/TX" -#define D_SENSOR_SR04_ECHO "SR04 Ech/RX" -#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx" -#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx" -#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena" -#define D_SENSOR_SDM72_TX "SDM72 TX" -#define D_SENSOR_SDM72_RX "SDM72 RX" -#define D_SENSOR_SDM120_TX "SDMx20 TX" -#define D_SENSOR_SDM120_RX "SDMx20 RX" -#define D_SENSOR_SDM230_TX "SDM230 TX" -#define D_SENSOR_SDM230_RX "SDM230 RX" -#define D_SENSOR_SDM630_TX "SDM630 TX" -#define D_SENSOR_SDM630_RX "SDM630 RX" -#define D_SENSOR_WE517_TX "WE517 TX" -#define D_SENSOR_WE517_RX "WE517 RX" +#define D_SENSOR_SR04_TRIG "SR04 Tri/Tx" +#define D_SENSOR_SR04_ECHO "SR04 Ech/Rx" +#define D_SENSOR_NRG_MBS_TX "NrgMbus Tx" +#define D_SENSOR_NRG_MBS_RX "NrgMbus Rx" +#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbus Tx Ena" +#define D_SENSOR_SDM72_TX "SDM72 Tx" +#define D_SENSOR_SDM72_RX "SDM72 Rx" +#define D_SENSOR_SDM120_TX "SDMx20 Tx" +#define D_SENSOR_SDM120_RX "SDMx20 Rx" +#define D_SENSOR_SDM230_TX "SDM230 Tx" +#define D_SENSOR_SDM230_RX "SDM230 Rx" +#define D_SENSOR_SDM630_TX "SDM630 Tx" +#define D_SENSOR_SDM630_RX "SDM630 Rx" +#define D_SENSOR_WE517_TX "WE517 Tx" +#define D_SENSOR_WE517_RX "WE517 Rx" #define D_SENSOR_LD2410_TX "LD2410 Tx" #define D_SENSOR_LD2410_RX "LD2410 Rx" #define D_GPIO_TM1621_CS "TM1621 CS" -#define D_GPIO_TM1621_WR "TM1621 WR" -#define D_GPIO_TM1621_RD "TM1621 RD" -#define D_GPIO_TM1621_DAT "TM1621 DAT" -#define D_SENSOR_TM1637_CLK "TM1637 CLK" +#define D_GPIO_TM1621_WR "TM1621 Wr" +#define D_GPIO_TM1621_RD "TM1621 Rd" +#define D_GPIO_TM1621_DAT "TM1621 Dat" +#define D_SENSOR_TM1637_CLK "TM1637 Clk" #define D_SENSOR_TM1637_DIO "TM1637 DIO" -#define D_SENSOR_TM1638_CLK "TM1638 CLK" +#define D_SENSOR_TM1638_CLK "TM1638 Clk" #define D_SENSOR_TM1638_DIO "TM1638 DIO" -#define D_SENSOR_TM1638_STB "TM1638 STB" -#define D_SENSOR_MAX7219_DIN "MAX7219 DIN" +#define D_SENSOR_TM1638_STB "TM1638 Stb" +#define D_SENSOR_MAX7219_DIN "MAX7219 Din" #define D_SENSOR_MAX7219_CS "MAX7219 CS" -#define D_SENSOR_MAX7219_CLK "MAX7219 CLK" -#define D_SENSOR_HX711_SCK "HX711 SCK" -#define D_SENSOR_HX711_DAT "HX711 DAT" +#define D_SENSOR_MAX7219_CLK "MAX7219 Clk" +#define D_SENSOR_HX711_SCK "HX711 SCk" +#define D_SENSOR_HX711_DAT "HX711 Dat" #define D_SENSOR_FTC532 "FTC532" -#define D_SENSOR_BS814_CLK "BS814 CLK" -#define D_SENSOR_BS814_DAT "BS814 DAT" +#define D_SENSOR_BS814_CLK "BS814 Clk" +#define D_SENSOR_BS814_DAT "BS814 Dat" #define D_SENSOR_TX2X_TX "TX2x" -#define D_SENSOR_RFSEND "RF TX" -#define D_SENSOR_RFRECV "RF RX" -#define D_SENSOR_TUYA_TX "Tuya TX" -#define D_SENSOR_TUYA_RX "Tuya RX" -#define D_SENSOR_MGC3130_XFER "MGC3130 XFR" -#define D_SENSOR_MGC3130_RESET "MGC3130 RST" +#define D_SENSOR_RFSEND "RF Tx" +#define D_SENSOR_RFRECV "RF Rx" +#define D_SENSOR_TUYA_TX "Tuya Tx" +#define D_SENSOR_TUYA_RX "Tuya Rx" +#define D_SENSOR_MGC3130_XFER "MGC3130 Xfr" +#define D_SENSOR_MGC3130_RESET "MGC3130 Rst" #define D_SENSOR_SSPI_MISO "SSPI MISO" #define D_SENSOR_SSPI_MOSI "SSPI MOSI" -#define D_SENSOR_SSPI_SCLK "SSPI SCLK" +#define D_SENSOR_SSPI_SCLK "SSPI SClk" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" -#define D_SENSOR_RF_SENSOR "RF Sensor" -#define D_SENSOR_AZ_RX "AZ RX" -#define D_SENSOR_AZ_TX "AZ TX" +#define D_SENSOR_RF_SENSOR "Capteur RF" +#define D_SENSOR_AZ_RX "AZ Rx" +#define D_SENSOR_AZ_TX "AZ Tx" #define D_SENSOR_MAX31855_CS "MX31855 CS" -#define D_SENSOR_MAX31855_CLK "MX31855 CLK" +#define D_SENSOR_MAX31855_CLK "MX31855 Clk" #define D_SENSOR_MAX31855_DO "MX31855 DO" #define D_SENSOR_MAX31865_CS "MX31865 CS" -#define D_SENSOR_NRG_SEL "HLWBL SEL" // Suffix "i" +#define D_SENSOR_NRG_SEL "HLWBL Sel" // Suffix "i" #define D_SENSOR_NRG_CF1 "HLWBL CF1" #define D_SENSOR_HLW_CF "HLW8012 CF" #define D_SENSOR_HJL_CF "BL0937 CF" -#define D_SENSOR_MCP39F5_TX "MCP39F5 TX" -#define D_SENSOR_MCP39F5_RX "MCP39F5 RX" -#define D_SENSOR_MCP39F5_RST "MCP39F5 RST" -#define D_SENSOR_CSE7761_TX "CSE7761 TX" -#define D_SENSOR_CSE7761_RX "CSE7761 RX" -#define D_SENSOR_CSE7766_TX "CSE7766 TX" +#define D_SENSOR_MCP39F5_TX "MCP39F5 Tx" +#define D_SENSOR_MCP39F5_RX "MCP39F5 Rx" +#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_CSE7761_TX "CSE7761 Tx" +#define D_SENSOR_CSE7761_RX "CSE7761 Rx" +#define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" #define D_SENSOR_BL0939_RX "BL0939 Rx" #define D_SENSOR_BL0942_RX "BL0942 Rx" -#define D_SENSOR_HM330X_SET "HM330X SET" -#define D_SENSOR_PN532_TX "PN532 TX" -#define D_SENSOR_PN532_RX "PN532 RX" -#define D_SENSOR_SM16716_CLK "SM16716 CLK" -#define D_SENSOR_SM16716_DAT "SM16716 DAT" -#define D_SENSOR_SM16716_POWER "SM16716 PWR" -#define D_SENSOR_P9813_CLK "P9813 CLK" -#define D_SENSOR_P9813_DAT "P9813 DAT" +#define D_SENSOR_HM330X_SET "HM330X Set" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" +#define D_SENSOR_SM16716_CLK "SM16716 Clk" +#define D_SENSOR_SM16716_DAT "SM16716 Dat" +#define D_SENSOR_SM16716_POWER "SM16716 Pwr" +#define D_SENSOR_P9813_CLK "P9813 Clk" +#define D_SENSOR_P9813_DAT "P9813 Dat" #define D_SENSOR_MY92X1_DI "MY92x1 DI" -#define D_SENSOR_MY92X1_DCKI "MY92x1 DCKI" +#define D_SENSOR_MY92X1_DCKI "MY92x1 DCkI" #define D_SENSOR_ARIRFRCV "ALux IrRcv" #define D_SENSOR_ARIRFSEL "ALux IrSel" -#define D_SENSOR_TXD "Série TX" -#define D_SENSOR_RXD "Série RX" +#define D_SENSOR_TXD "Série Tx" +#define D_SENSOR_RXD "Série Rx" #define D_SENSOR_ROTARY "Rotary" // Suffix "1A" -#define D_SENSOR_HRE_CLOCK "HRE CLK" -#define D_SENSOR_HRE_DATA "HRE DAT" -#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ" -#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ" -#define D_SENSOR_ADE7953_RST "ADE7953 RST" +#define D_SENSOR_HRE_CLOCK "HRE Clk" +#define D_SENSOR_HRE_DATA "HRE Dat" +#define D_SENSOR_ADE7880_IRQ "ADE7880 IRq" +#define D_SENSOR_ADE7953_IRQ "ADE7953 IRq" +#define D_SENSOR_ADE7953_RST "ADE7953 Rst" #define D_SENSOR_ADE7953_CS "ADE7953 CS" #define D_SENSOR_BUZZER "Buzzer" #define D_SENSOR_DISP_RESET "Display Rst" -#define D_SENSOR_ZIGBEE_TXD "ZigBee TX" -#define D_SENSOR_ZIGBEE_RXD "ZigBee RX" -#define D_SENSOR_ZIGBEE_RST "ZigBee RST" -#define D_SENSOR_SOLAXX1_TX "SolaxX1 TX" -#define D_SENSOR_SOLAXX1_RX "SolaxX1 RX" +#define D_SENSOR_ZIGBEE_TXD "ZigBee Tx" +#define D_SENSOR_ZIGBEE_RXD "ZigBee Rx" +#define D_SENSOR_ZIGBEE_RST "ZigBee Rst" +#define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" +#define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_SOLAXX1_RTS "SolaxX1 RTS" -#define D_SENSOR_IBEACON_TX "iBeacon TX" -#define D_SENSOR_IBEACON_RX "iBeacon RX" -#define D_SENSOR_RDM6300_RX "RDM6300 RX" +#define D_SENSOR_IBEACON_TX "iBeacon Tx" +#define D_SENSOR_IBEACON_RX "iBeacon Rx" +#define D_SENSOR_RDM6300_RX "RDM6300 Rx" #define D_SENSOR_CC1101_CS "CC1101 CS" -#define D_SENSOR_A4988_DIR "A4988 DIR" -#define D_SENSOR_A4988_STP "A4988 STP" -#define D_SENSOR_A4988_ENA "A4988 ENA" +#define D_SENSOR_A4988_DIR "A4988 Dir" +#define D_SENSOR_A4988_STP "A4988 Stp" +#define D_SENSOR_A4988_ENA "A4988 Ena" #define D_SENSOR_A4988_MS1 "A4988 MS1" #define D_SENSOR_OUTPUT_HI "Sortie Hi" #define D_SENSOR_OUTPUT_LO "Sortie Lo" -#define D_SENSOR_AS608_TX "AS608 TX" -#define D_SENSOR_AS608_RX "AS608 RX" -#define D_SENSOR_DDS2382_TX "DDS238-2 TX" -#define D_SENSOR_DDS2382_RX "DDS238-2 RX" -#define D_SENSOR_DDSU666_TX "DDSU666 TX" -#define D_SENSOR_DDSU666_RX "DDSU666 RX" -#define D_SENSOR_SM2135_CLK "SM2135 CLK" -#define D_SENSOR_SM2135_DAT "SM2135 DAT" -#define D_SENSOR_SM2335_CLK "SM2335 CLK" -#define D_SENSOR_SM2335_DAT "SM2335 DAT" +#define D_SENSOR_AS608_TX "AS608 Tx" +#define D_SENSOR_AS608_RX "AS608 Rx" +#define D_SENSOR_DDS2382_TX "DDS238-2 Tx" +#define D_SENSOR_DDS2382_RX "DDS238-2 Rx" +#define D_SENSOR_DDSU666_TX "DDSU666 Tx" +#define D_SENSOR_DDSU666_RX "DDSU666 Rx" +#define D_SENSOR_SM2135_CLK "SM2135 Clk" +#define D_SENSOR_SM2135_DAT "SM2135 Dat" +#define D_SENSOR_SM2335_CLK "SM2335 Clk" +#define D_SENSOR_SM2335_DAT "SM2335 Dat" #define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk" #define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat" -#define D_SENSOR_BP5758D_CLK "BP5758D Clk" -#define D_SENSOR_BP5758D_DAT "BP5758D Dat" +#define D_SENSOR_BP5758D_CLK "BP5758D Clk" +#define D_SENSOR_BP5758D_DAT "BP5758D Dat" #define D_SENSOR_DEEPSLEEP "Hibernation" #define D_SENSOR_EXS_ENABLE "EXS Enable" -#define D_SENSOR_CLIENT_TX "Esclave TX" -#define D_SENSOR_CLIENT_RX "Esclave RX" -#define D_SENSOR_CLIENT_RESET "Esclave RST" -#define D_SENSOR_GPS_RX "GPS RX" -#define D_SENSOR_GPS_TX "GPS TX" -#define D_SENSOR_HM10_RX "HM10 RX" -#define D_SENSOR_HM10_TX "HM10 TX" -#define D_SENSOR_LE01MR_RX "LE-01MR RX" -#define D_SENSOR_LE01MR_TX "LE-01MR TX" -#define D_SENSOR_BL0940_RX "BL0940 RX" +#define D_SENSOR_CLIENT_TX "Esclave Tx" +#define D_SENSOR_CLIENT_RX "Esclave Rx" +#define D_SENSOR_CLIENT_RESET "Esclave RST" +#define D_SENSOR_GPS_RX "GPS Rx" +#define D_SENSOR_GPS_TX "GPS Tx" +#define D_SENSOR_HM10_RX "HM10 Rx" +#define D_SENSOR_HM10_TX "HM10 Tx" +#define D_SENSOR_LE01MR_RX "LE-01MR Rx" +#define D_SENSOR_LE01MR_TX "LE-01MR Tx" +#define D_SENSOR_BL0940_RX "BL0940 Rx" #define D_SENSOR_CC1101_GDO0 "CC1101 GDO0" #define D_SENSOR_CC1101_GDO2 "CC1101 GDO2" -#define D_SENSOR_HRXL_RX "HRXL RX" -#define D_SENSOR_DYP_RX "DYP RX" -#define D_SENSOR_ELECTRIQ_MOODL "MOODL TX" +#define D_SENSOR_HRXL_RX "HRXL Rx" +#define D_SENSOR_DYP_RX "DYP Rx" +#define D_SENSOR_ELECTRIQ_MOODL "MOODL Tx" #define D_SENSOR_AS3935 "AS3935" #define D_SENSOR_WINDMETER_SPEED "Anémomètre" -#define D_SENSOR_TELEINFO_RX "TInfo RX" +#define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo En" #define D_SENSOR_LMT01_PULSE "LMT01 Impulsion" #define D_SENSOR_ADC_INPUT "ADC Entrée" -#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_TEMP "ADC Temp." #define D_SENSOR_ADC_LIGHT "ADC Lumière" #define D_SENSOR_ADC_BUTTON "ADC Bouton" #define D_SENSOR_ADC_RANGE "ADC Distance" @@ -842,31 +845,31 @@ #define D_SENSOR_ADC_JOYSTICK "ADC Manette" #define D_SENSOR_ADC_PH "ADC pH" #define D_SENSOR_ADC_MQ "ADC MQ" -#define D_GPIO_WEBCAM_PWDN "CAM_PWDN" -#define D_GPIO_WEBCAM_RESET "CAM_RESET" -#define D_GPIO_WEBCAM_XCLK "CAM_XCLK" +#define D_GPIO_WEBCAM_PWDN "CAM_PwDn" +#define D_GPIO_WEBCAM_RESET "CAM_Reset" +#define D_GPIO_WEBCAM_XCLK "CAM_XClk" #define D_GPIO_WEBCAM_SIOD "CAM_SIOD" #define D_GPIO_WEBCAM_SIOC "CAM_SIOC" -#define D_GPIO_WEBCAM_DATA "CAM_DATA" -#define D_GPIO_WEBCAM_VSYNC "CAM_VSYNC" -#define D_GPIO_WEBCAM_HREF "CAM_HREF" -#define D_GPIO_WEBCAM_PCLK "CAM_PCLK" -#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK" +#define D_GPIO_WEBCAM_DATA "CAM_Data" +#define D_GPIO_WEBCAM_VSYNC "CAM_VSync" +#define D_GPIO_WEBCAM_HREF "CAM_HRef" +#define D_GPIO_WEBCAM_PCLK "CAM_PClk" +#define D_GPIO_WEBCAM_PSCLK "CAM_PSClk" #define D_GPIO_WEBCAM_HSD "CAM_HSD" #define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS" -#define D_SENSOR_ETH_PHY_POWER "ETH POWER" +#define D_SENSOR_ETH_PHY_POWER "ETH Pwr" #define D_SENSOR_ETH_PHY_MDC "ETH MDC" #define D_SENSOR_ETH_PHY_MDIO "ETH MDIO" -#define D_SENSOR_TCP_TXD "TCP TX" -#define D_SENSOR_TCP_RXD "TCP RX" -#define D_SENSOR_IEM3000_TX "iEM3000 TX" -#define D_SENSOR_IEM3000_RX "iEM3000 RX" -#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC TX" -#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC RX" -#define D_SENSOR_PROJECTOR_CTRL_TX "DLP TX" -#define D_SENSOR_PROJECTOR_CTRL_RX "DLP RX" -#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot 0" -#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Reset" +#define D_SENSOR_TCP_TXD "TCP Tx" +#define D_SENSOR_TCP_RXD "TCP Rx" +#define D_SENSOR_IEM3000_TX "iEM3000 Tx" +#define D_SENSOR_IEM3000_RX "iEM3000 Rx" +#define D_SENSOR_MIEL_HVAC_TX "MiEl HVAC Tx" +#define D_SENSOR_MIEL_HVAC_RX "MiEl HVAC Rx" +#define D_SENSOR_PROJECTOR_CTRL_TX "DLP Tx" +#define D_SENSOR_PROJECTOR_CTRL_RX "DLP Rx" +#define D_SENSOR_SHELLY_DIMMER_BOOT0 "SHD Boot0" +#define D_SENSOR_SHELLY_DIMMER_RST_INV "SHD Rst" #define D_SENSOR_RC522_RST "RC522 Rst" #define D_SENSOR_RC522_CS "RC522 CS" #define D_SENSOR_NRF24_CS "NRF24 CS" @@ -887,34 +890,37 @@ #define D_SENSOR_SDCARD_CS "CarteSD CS" #define D_SENSOR_WIEGAND_D0 "Wiegand D0" #define D_SENSOR_WIEGAND_D1 "Wiegand D1" -#define D_SENSOR_NEOPOOL_TX "NeoPool TX" -#define D_SENSOR_NEOPOOL_RX "NeoPool RX" -#define D_SENSOR_VL53LXX_XSHUT "VL53LXX XSHUT" -#define D_SENSOR_TFMINIPLUS_TX "TFmini+ TX" -#define D_SENSOR_TFMINIPLUS_RX "TFmini+ RX" +#define D_SENSOR_NEOPOOL_TX "NeoPool Tx" +#define D_SENSOR_NEOPOOL_RX "NeoPool Rx" +#define D_SENSOR_VL53LXX_XSHUT "VL53LXX XShut" +#define D_SENSOR_TFMINIPLUS_TX "TFmini+ Tx" +#define D_SENSOR_TFMINIPLUS_RX "TFmini+ Rx" #define D_SENSOR_ZEROCROSS "ZC Pulse" -#define D_SENSOR_HALLEFFECT "HallEffect" +#define D_SENSOR_HALLEFFECT "Effet Hall" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" -#define D_SENSOR_VINDRIKTNING_RX "VINDRIKTNING" -#define D_SENSOR_BL6523_TX "BL6523 Tx" -#define D_SENSOR_BL6523_RX "BL6523 Rx" +#define D_SENSOR_VINDRIKTNING_RX "Vindriktning" +#define D_SENSOR_BL6523_TX "BL6523 Tx" +#define D_SENSOR_BL6523_RX "BL6523 Rx" #define D_SENSOR_HEARTBEAT "Heartbeat" #define D_SENSOR_RESET "Reset" -#define D_GPIO_SHIFT595_SRCLK "74x595 SRCLK" -#define D_GPIO_SHIFT595_RCLK "74x595 RCLK" +#define D_GPIO_SHIFT595_SRCLK "74x595 SRClk" +#define D_GPIO_SHIFT595_RCLK "74x595 RClk" #define D_GPIO_SHIFT595_OE "74x595 OE" -#define D_GPIO_SHIFT595_SER "74x595 SER" -#define D_GPIO_DINGTIAN_CLK "Dingtian CLK" +#define D_GPIO_SHIFT595_SER "74x595 Ser" +#define D_GPIO_DINGTIAN_CLK "Dingtian Clk" #define D_GPIO_DINGTIAN_SDI "Dingtian SDI" #define D_GPIO_DINGTIAN_Q7 "Dingtian Q7" #define D_GPIO_DINGTIAN_PL "Dingtian PL" -#define D_GPIO_DINGTIAN_RCK "Dingtian RCK" -#define D_SENSOR_CM11_TX "CM110x TX" -#define D_SENSOR_CM11_RX "CM110x RX" -#define D_SENSOR_FLOWRATEMETER "Flowrate" +#define D_GPIO_DINGTIAN_RCK "Dingtian RCk" +#define D_SENSOR_CM11_TX "CM110x Tx" +#define D_SENSOR_CM11_RX "CM110x Rx" +#define D_SENSOR_FLOWRATEMETER "Débit" #define D_SENSOR_ME007_TRIG "ME007 Tri" #define D_SENSOR_ME007_RX "ME007 Rx" #define D_SENSOR_TUYAMCUBR_TX "TuyaMCUBr Tx" @@ -922,6 +928,8 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" + // Units #define D_UNIT_AMPERE "A" @@ -933,7 +941,8 @@ #define D_UNIT_HERTZ "Hz" #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" -#define D_UNIT_GALLONS_PER_MIN "gal/mn" +#define D_UNIT_GALLONS_PER_MIN "gal/min" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -943,7 +952,7 @@ #define D_UNIT_KILOOHM "kΩ" #define D_UNIT_KILOWATTHOUR "kWh" #define D_UNIT_LITERS "L" -#define D_UNIT_LITERS_PER_MIN "L/m" +#define D_UNIT_LITERS_PER_MIN "L/min" #define D_UNIT_LUX "lx" #define D_UNIT_MICROGRAM_PER_CUBIC_METER "µg/m³" #define D_UNIT_MICROMETER "µm" @@ -975,9 +984,9 @@ #define D_UNIT_CUBICMETER_PER_HOUR "m³/h" #define D_UNIT_CUBIC_METER "m³" -#define D_NEW_ADDRESS "Positionner l'adresse à" -#define D_OUT_OF_RANGE "Hors limites" -#define D_SENSOR_DETECTED "détecté" +#define D_NEW_ADDRESS "Positionner l'adresse à" +#define D_OUT_OF_RANGE "Hors limites" +#define D_SENSOR_DETECTED "détecté" //SDM220, SDM120, SDM72, LE01MR, SDM230 #define D_EXPORT_POWER "Puissance fournie" @@ -1007,9 +1016,9 @@ #define D_SOLAX_MODE_1 "En test" #define D_SOLAX_MODE_2 "En marche" #define D_SOLAX_MODE_3 "Défault" -#define D_SOLAX_MODE_4 "Permanent Failure" // to be translated -#define D_SOLAX_MODE_5 "Software Update" // to be translated -#define D_SOLAX_MODE_6 "Selftest" // to be translated +#define D_SOLAX_MODE_4 "Défaut permanent" +#define D_SOLAX_MODE_5 "MàJ logicielle" +#define D_SOLAX_MODE_6 "Autotest" #define D_SOLAX_ERROR_0 "Aucun code d'erreur" #define D_SOLAX_ERROR_1 "Défaut Perte de réseau" #define D_SOLAX_ERROR_2 "Défaut Tension réseau" @@ -1116,9 +1125,9 @@ #define D_FP_UNKNOWNERROR "Erreur" // Any other error // xsns_96_flowratemeter.ino -#define D_FLOWRATEMETER_NAME "Flowrate" -#define D_FLOWRATEMETER_AMOUNT_TODAY "Amount Today" -#define D_FLOWRATEMETER_DURATION_TODAY "Duration Today" +#define D_FLOWRATEMETER_NAME "Débit" +#define D_FLOWRATEMETER_AMOUNT_TODAY "Quantité aujourd'hui" +#define D_FLOWRATEMETER_DURATION_TODAY "Durée aujourd'hui" // xsns_83_neopool.ino #define D_NEOPOOL_MACH_NONE "NeoPool" // Machine names @@ -1154,7 +1163,7 @@ #define D_NEOPOOL_RELAY_LIGHT "Lumière" #define D_NEOPOOL_RELAY_PH_ACID "Pompe acide" #define D_NEOPOOL_RELAY_PH_BASE "Pompe base" -#define D_NEOPOOL_RELAY_RX "Pompe RedOx" +#define D_NEOPOOL_RELAY_RX "Pompe Redox" #define D_NEOPOOL_RELAY_CL "Pompe Chlore" #define D_NEOPOOL_RELAY_CD "Conductivité" #define D_NEOPOOL_RELAY_HEATING "Chauffage" @@ -1163,7 +1172,7 @@ #define D_NEOPOOL_RELAY_AUX "Aux" #define D_NEOPOOL_TIME "Durée" #define D_NEOPOOL_FILT_MODE "Filtration mode" -#define D_NEOPOOL_CELL_RUNTIME "Cell runtime" +#define D_NEOPOOL_CELL_RUNTIME "Utilisation cellule" #define D_NEOPOOL_POLARIZATION "Pol" // Sensor status #define D_NEOPOOL_PR_OFF "PrOff" #define D_NEOPOOL_SETPOINT_OK "OK" @@ -1171,9 +1180,9 @@ #define D_NEOPOOL_SHOCK "Choc chlore" #define D_NEOPOOL_STATUS_ON "ON" #define D_NEOPOOL_STATUS_OFF "OFF" -#define D_NEOPOOL_STATUS_WAIT "WAIT" -#define D_NEOPOOL_STATUS_TANK "TANK" -#define D_NEOPOOL_STATUS_FLOW "Flow" +#define D_NEOPOOL_STATUS_WAIT "Attente" +#define D_NEOPOOL_STATUS_TANK "Réservoir" +#define D_NEOPOOL_STATUS_FLOW "Flux" #define D_NEOPOOL_LOW "Bas" #define D_NEOPOOL_FLOW1 "FL1" #define D_NEOPOOL_FLOW2 "FL2" @@ -1181,4 +1190,8 @@ #define D_NEOPOOL_PH_LOW "Trop bas" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "durée pompage expirée" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "dose moyenne de rayonnement" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_FR_FR_H_ diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index a3d15372c..eab5616e8 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Luchtkwaliteit" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "meardere" #define D_NOISE "Lûd" #define D_NONE "Gjin" +#define D_NOX "NOx" #define D_O2 "Soerstof" #define D_OFF "Ut" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV peil" #define D_UV_POWER "UV yntinsiteit" #define D_VERSION "Ferzje" +#define D_VOC "VOC" #define D_VOLTAGE "Foltaazje" #define D_VOLUME "Folume" #define D_WEIGHT "Gewicht" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "gemiddelde stralingsdosis" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_FY_NL_H_ diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 670c7d0df..971d6c3e5 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "מנהל" #define D_AIR_QUALITY "איכות אוויר" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "לחיצה מרובה" #define D_NOISE "רעש" #define D_NONE "כלום" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "כבוי" #define D_OFFLINE "מנותק" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV רמת" #define D_UV_POWER "UV Power" #define D_VERSION "גרסה" +#define D_VOC "VOC" #define D_VOLTAGE "מתח" #define D_VOLUME "Volume" #define D_WEIGHT "משקל" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "מינון קרינה ממוצע" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_HE_HE_H_ diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index f2c6d03fe..71944db5a 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Levegőminőség" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "többes lenyomás" #define D_NOISE "Zaj" #define D_NONE "nincs" +#define D_NOX "NOx" #define D_O2 "Oxygén" #define D_OFF "Ki" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV szint" #define D_UV_POWER "UV teljesítmény" #define D_VERSION "Verzió" +#define D_VOC "VOC" #define D_VOLTAGE "Feszültség" #define D_VOLUME "Volume" #define D_WEIGHT "Tömeg" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -925,6 +931,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -937,6 +944,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "növ." #define D_UNIT_KELVIN "K" @@ -1184,4 +1192,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "átlagos sugárdózis" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_HU_HU_H_ diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index cd084b993..f04fb0d5c 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -28,7 +28,7 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v9.4.0.1 - Last update 04.02.2023 + * Updated until v9.4.0.1 - Last update 15.04.2023 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Umidità ass" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Qualità dell'aria" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-pressione" #define D_NOISE "Rumore" #define D_NONE "Nessuno" +#define D_NOX "NOx" #define D_O2 "Ossigeno" #define D_OFF "OFF" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Livello UV" #define D_UV_POWER "Intensità UV" #define D_VERSION "Versione" +#define D_VOC "VOC" #define D_VOLTAGE "Tensione" #define D_VOLUME "Volume" #define D_WEIGHT "Peso" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "Impulsi ZC" #define D_SENSOR_HALLEFFECT "Effetto hall" #define D_SENSOR_EPD_DATA "EPD - Dati" +#define D_SENSOR_PCF8574_INT "PCF8574 - Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx - Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx - CS" #define D_SENSOR_MCP2515_CS "MCP2515 - CS" #define D_SENSOR_HRG15_RX "HRG15 - RX" #define D_SENSOR_HRG15_TX "HRG15 - TX" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX - TX" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 - RX" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 - RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "o" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "troppo basso" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "tempo pompa superato" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "Dose media radiazioni" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_IT_IT_H_ diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 9047b95c5..13213e643 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "공기질" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-press" #define D_NOISE "소음" #define D_NONE "없음" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "꺼짐" #define D_OFFLINE "오프라인" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV 레벨" #define D_UV_POWER "UV 파워" #define D_VERSION "버전" +#define D_VOC "VOC" #define D_VOLTAGE "전압" #define D_VOLUME "Volume" #define D_WEIGHT "무게" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "시" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "average radiation dose" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_KO_KO_H_ diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 69bead33e..e4fd27026 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Lucht kwaliteit" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "meervoudig" #define D_NOISE "Lawaai" #define D_NONE "Geen" +#define D_NOX "NOx" #define D_O2 "Zuurstof" #define D_OFF "Uit" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV niveau" #define D_UV_POWER "UV intensiteit" #define D_VERSION "Versie" +#define D_VOC "VOC" #define D_VOLTAGE "Spanning" #define D_VOLUME "Volume" #define D_WEIGHT "Gewicht" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "te laag" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pomptijd bereikt" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "gemiddelde stralingsdosis" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_NL_NL_H_ diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index c8f2cd71c..71d11945c 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Jakość powietrza" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "Wielokrotne naciśnięcie" #define D_NOISE "Szum" #define D_NONE "Brak" +#define D_NOX "NOx" #define D_O2 "Tlen" #define D_OFF "Wyłączony" #define D_OFFLINE "Nieaktywny" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Poziom UV" #define D_UV_POWER "Moc UV" #define D_VERSION "Wersja" +#define D_VOC "VOC" #define D_VOLTAGE "Napięcie" #define D_VOLUME "Pojemność" #define D_WEIGHT "Waga" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "Efekt Halla" #define D_SENSOR_EPD_DATA "EPD Dane" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "Godz" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "czas pompowania przekroczony" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "Średnia Dawka Promieniowania" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_PL_PL_D_H_ diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index 7152da31d..6d43be611 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Qualidade do ar" #define D_AP "Ponto de acesso" // Ponto de Acesso @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-pressão" #define D_NOISE "Ruído" #define D_NONE "Nenhum" +#define D_NOX "NOx" #define D_O2 "Oxigênio" #define D_OFF "Desligado" #define D_OFFLINE "Desconectado" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Nível UV" #define D_UV_POWER "Potência UV" #define D_VERSION "Versão" +#define D_VOC "VOC" #define D_VOLTAGE "Voltagem" #define D_VOLUME "Volume" #define D_WEIGHT "Peso" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "Efeito Hall" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "H" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "Muito baixo" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "tempo da bomba excedido" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "dose média de radiação" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_PT_BR_H_ diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index df69b7c1c..a91db261a 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Qualidade do Ar" #define D_AP "AP" // Ponto de Acesso @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-pressão" #define D_NOISE "Ruído" #define D_NONE "Nenhum" +#define D_NOX "NOx" #define D_O2 "Oxigénio" #define D_OFF "Off" #define D_OFFLINE "Desconetado" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Nível UV" #define D_UV_POWER "Poder UV" #define D_VERSION "Versão" +#define D_VOC "VOC" #define D_VOLTAGE "Voltagem" #define D_VOLUME "Volume" #define D_WEIGHT "Peso" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "Efeito Hall" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "Muito baixo" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "tempo da bomba excedido" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "dose média de radiação" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_PT_PT_H_ diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index b7427a821..f9b5b79b7 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Calitatea aerului" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "selectare multiplă" #define D_NOISE "Zgomot" #define D_NONE "Lipsă" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Închis" #define D_OFFLINE "Offline" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Nivel UV" #define D_UV_POWER "Putere UV" #define D_VERSION "Versiune" +#define D_VOC "VOC" #define D_VOLTAGE "Voltaj" #define D_VOLUME "Volume" #define D_WEIGHT "Greutate" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "doza medie de radiație" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_RO_RO_H_ diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 02e0851dc..d1192b842 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Качество воздуха" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "многократное нажатие" #define D_NOISE "Шум" #define D_NONE "Нет" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Выкл" #define D_OFFLINE "Офф-лайн" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "УФ уровень" #define D_UV_POWER "UV Power" #define D_VERSION "Версия" +#define D_VOC "VOC" #define D_VOLTAGE "Напряжение" #define D_VOLUME "Volume" #define D_WEIGHT "Weight" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "А" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "Ч" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "средняя доза облучения" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_RU_RU_H_ diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 79212a44a..30ebb0149 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Kvalita vzduchu" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-stlačenie" #define D_NOISE "Hluk" #define D_NONE "Žiadny" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Vyp." #define D_OFFLINE "Neaktívny" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "úroveň UV" #define D_UV_POWER "UV Power" #define D_VERSION "Verzia" +#define D_VOC "VOC" #define D_VOLTAGE "Napätie" #define D_VOLUME "Volume" #define D_WEIGHT "Hmotnosť" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -935,6 +942,7 @@ #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" #define D_UNIT_KILOGRAM "kg" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "priemerná dávka žiarenia" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_SK_SK_H_ diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 2bc09f434..1881739c6 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Luftkvalitet" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "fler tryck" #define D_NOISE "Oväsen" #define D_NONE "Ingen" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Av" #define D_OFFLINE "Off-line" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV nivå" #define D_UV_POWER "UV kraft" #define D_VERSION "Version" +#define D_VOC "VOC" #define D_VOLTAGE "Volttal" #define D_VOLUME "Volume" #define D_WEIGHT "Vikt" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "Tim" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "ink" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "genomsnittlig stråldos" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_SV_SE_H_ diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 2b4b962f5..7fecfa418 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "Hava Kalitesi" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "multi-press" #define D_NOISE "Noise" #define D_NONE "None" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Off" #define D_OFFLINE "Çevirimdışı" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "UV Seviyesi" #define D_UV_POWER "UV Power" #define D_VERSION "Versiyon" +#define D_VOC "VOC" #define D_VOLTAGE "Voltaj" #define D_VOLUME "Volume" #define D_WEIGHT "Weight" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "ortalama radyasyon dozu" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_TR_TR_H_ diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index a45664b64..70acfb5b0 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "," // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Адміністратор" #define D_AIR_QUALITY "Якість повітря" #define D_AP "Точка доступу" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "Багаторазове натискання" #define D_NOISE "Шум" #define D_NONE "Нічого" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Вимкнено" #define D_OFFLINE "Неактивний" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Рівень УФ" #define D_UV_POWER "Потужність УФ" #define D_VERSION "Версія" +#define D_VOC "VOC" #define D_VOLTAGE "Напруга" #define D_VOLUME "Volume" #define D_WEIGHT "Вага" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "А" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "г" #define D_UNIT_GALLONS "гал" #define D_UNIT_GALLONS_PER_MIN "гал/хв" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "інк" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "середня доза радіації" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_UK_UA_H_ diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 2c85c22e1..9a0c740c4 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Quản trị" #define D_AIR_QUALITY "Chất lượng không khí" #define D_AP "Mạng wifi" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "bấm nhiều lần" #define D_NOISE "Nhiễu" #define D_NONE "Không" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "Tắt" #define D_OFFLINE "Ngoại tuyến" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "Mức độ UV" #define D_UV_POWER "Công suất UV" #define D_VERSION "Phiên bản" +#define D_VOC "VOC" #define D_VOLTAGE "Điện áp" #define D_VOLUME "Volume" #define D_WEIGHT "Cân nặng" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "h" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "liều bức xạ trung bình" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_VI_VN_H_ diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 7baa2711d..f32ab17bd 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "空气质量" #define D_AP "AP" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "多次按键" #define D_NOISE "嘈杂" #define D_NONE "无" +#define D_NOX "NOx" #define D_O2 "氧" #define D_OFF "关" #define D_OFFLINE "离线" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "紫外线水平" #define D_UV_POWER "紫外线功率 " #define D_VERSION "版本" +#define D_VOC "VOC" #define D_VOLTAGE "电压" #define D_VOLUME "Volume" #define D_WEIGHT "重量" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "A" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "小时" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "平均辐射剂量" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_ZH_CN_H_ diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 77de2a6f0..d34686626 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -51,6 +51,7 @@ #define D_DECIMAL_SEPARATOR "." // Common +#define D_ABSOLUTE_HUMIDITY "Abs Humidity" #define D_ADMIN "Admin" #define D_AIR_QUALITY "空氣品質" #define D_AP "存取點" // Access Point @@ -133,6 +134,7 @@ #define D_MULTI_PRESS "多重點擊" #define D_NOISE "雜訊" #define D_NONE "無" +#define D_NOX "NOx" #define D_O2 "Oxygen" #define D_OFF "關閉" #define D_OFFLINE "離線" @@ -201,6 +203,7 @@ #define D_UV_LEVEL "紫外線等級" #define D_UV_POWER "紫外線能量" #define D_VERSION "版本" +#define D_VOC "VOC" #define D_VOLTAGE "電壓" #define D_VOLUME "Volume" #define D_WEIGHT "重量" @@ -895,6 +898,9 @@ #define D_SENSOR_ZEROCROSS "ZC Pulse" #define D_SENSOR_HALLEFFECT "HallEffect" #define D_SENSOR_EPD_DATA "EPD Data" +#define D_SENSOR_PCF8574_INT "PCF8574 Int" +#define D_SENSOR_MCP23XXX_INT "MCP23xxx Int" +#define D_SENSOR_MCP23SXX_CS "MCP23Sxx CS" #define D_SENSOR_MCP2515_CS "MCP2515 CS" #define D_SENSOR_HRG15_RX "HRG15 Rx" #define D_SENSOR_HRG15_TX "HRG15 Tx" @@ -922,6 +928,7 @@ #define D_SENSOR_BIOPDU_PZEM0XX_TX "BioPDU PZEM0XX Tx" #define D_SENSOR_BIOPDU_PZEM016_RX "BioPDU PZEM016 Rx" #define D_SENSOR_BIOPDU_BIT "BioPDU Bit" +#define D_SENSOR_LOX_O2_RX "LoxO2 RX" // Units #define D_UNIT_AMPERE "安培" @@ -934,6 +941,7 @@ #define D_UNIT_HOUR "時" #define D_UNIT_GALLONS "gal" #define D_UNIT_GALLONS_PER_MIN "g/m" +#define D_UNIT_GRAM_PER_CUBIC_METER "g/m³" #define D_UNIT_INCH_MERCURY "inHg" #define D_UNIT_INCREMENTS "inc" #define D_UNIT_KELVIN "K" @@ -1181,4 +1189,8 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xsns_106_gdk101.ino +#define D_AVG_RAD_DOSE "平均輻射劑量" +#define D_UNIT_US_H "uSv/h" + #endif // _LANGUAGE_ZH_TW_H_ diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 1105b2fb8..a246126ab 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -93,24 +93,6 @@ #define WEB_LOG_LEVEL LOG_LEVEL_INFO // [WebLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE) #define MQTT_LOG_LEVEL LOG_LEVEL_NONE // [MqttLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE) -// -- Ota ----------------------------------------- -#ifdef ESP8266 -#define OTA_URL "http://ota.tasmota.com/tasmota/release/tasmota.bin.gz" // [OtaUrl] -#endif // ESP8266 -#ifdef ESP32 -#ifdef CONFIG_IDF_TARGET_ESP32C3 -#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32c3.bin" // [OtaUrl] -#elif defined(CONFIG_IDF_TARGET_ESP32S2) -#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32s2.bin" // [OtaUrl] -#elif defined(CONFIG_IDF_TARGET_ESP32S3) -#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32s3.bin" // [OtaUrl] -#elif defined(CORE32SOLO1) -#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32solo1.bin" // [OtaUrl] -#else -#define OTA_URL "https://ota.tasmota.com/tasmota32/release/tasmota32.bin" // [OtaUrl] -#endif // CONFIG_IDF_TARGET_ESP32C3 -#endif // ESP32 - // -- MQTT ---------------------------------------- #define MQTT_USE true // [SetOption3] Select default MQTT use (false = Off, true = On) @@ -631,6 +613,7 @@ // #define USE_MCP230xx_ADDR 0x20 // Enable MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x26 - set according to your wired setup) // #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+2k2 code) // #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) +// #define USE_MCP23XXX_DRV // [I2cDriver77] Enable MCP23xxx support as virtual switch/button/relay (+3k(I2C)/+5k(SPI) code) // #define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) // #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup) // #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz @@ -661,10 +644,11 @@ // #define USE_MLX90614 // [I2cDriver32] Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) // #define USE_CHIRP // [I2cDriver33] Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) // #define USE_PAJ7620 // [I2cDriver34] Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) -// #define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+1k9 code) -// #define USE_PCF8574_SENSOR // enable PCF8574 inputs and outputs in SENSOR message -// #define USE_PCF8574_DISPLAYINPUT // enable PCF8574 inputs display in Web page -// #define USE_PCF8574_MQTTINPUT // enable MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} +// #define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+2k1 code) +// #define USE_PCF8574_MODE2 // Enable Mode2 virtual relays/buttons/switches (+2k3 code) +// #define USE_PCF8574_SENSOR // Enable Mode1 inputs and outputs in SENSOR message (+0k2 code) +// #define USE_PCF8574_DISPLAYINPUT // Enable Mode1 inputs display in Web page (+0k2 code) +// #define USE_PCF8574_MQTTINPUT // Enable Mode1 MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} (+0k5 code) // #define PCF8574_ADDR1 0x20 // First address to search for PCF8574 // #define PCF8574_ADDR1_COUNT 7 // Number of addresses to search for PCF8574 - Default to 0x20 to 0x26 // #define PCF8574_ADDR2 0x39 // First address to search for PCF8574A @@ -716,6 +700,13 @@ // #define INA3221_ADDRESS1 // allow to change the 1st address to search for INA3221 to 0x41..0x43 // #define INA3221_MAX_COUNT // change the number of devices to search for (default 4). // // Both settings together allow to limit searching for INA3221 to only a subset of addresses +// #define USE_PMSA003I // [I2cDriver78] Enable PMSA003I Air Quality Sensor (I2C address 0x12) (+1k8 code) +// #define USE_GDK101 // [I2cDriver79] Enable GDK101 sensor (I2C addresses 0x18 - 0x1B) (+1k2 code) +// #define GDK101_SHOW_FW_VERSION +// #define GDK101_SHOW_STATUS +// #define GDK101_SHOW_VIBRATION_STATUS +// #define GDK101_SHOW_MEAS_TIME + // #define USE_RTC_CHIPS // Enable RTC chip support and NTP server - Select only one // #define USE_DS3231 // [I2cDriver26] Enable DS3231 RTC (I2C address 0x68) (+1k2 code) @@ -837,10 +828,10 @@ // #define VINDRIKTNING_SHOW_PM1 // Display undocumented/supposed PM1.0 values // #define VINDRIKTNING_SHOW_PM10 // Display undocumented/supposed PM10 values //#define USE_LD2410 // Add support for HLK-LD2410 24GHz smart wave motion sensor (+2k8 code) +// #define USE_LOX_O2 // Add support for LuminOx LOX O2 Sensor (+0k8 code) // -- Power monitoring sensors -------------------- #define USE_ENERGY_SENSOR // Add support for Energy Monitors (+14k code) -#define USE_ENERGY_COLUMN_GUI // Add support for column display in GUI (+0k5 code) #define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code) #define USE_ENERGY_POWER_LIMIT // Add additional support for Energy Power Limit detection (+1k2 code) #define USE_ENERGY_DUMMY // Add support for dummy Energy monitor allowing user values (+0k7 code) @@ -995,6 +986,11 @@ //#define USE_HX711 // Add support for HX711 load cell (+1k5 code) // #define USE_HX711_GUI // Add optional web GUI to HX711 as scale (+1k8 code) +//#define USE_DINGTIAN_RELAY // Add support for the Dingian board using 74'595 et 74'165 shift registers +// #define DINGTIAN_INPUTS_INVERTED // Invert input states (Hi => OFF, Low => ON) +// #define DINGTIAN_USE_AS_BUTTON // Inputs as Tasmota's virtual Buttons +// #define DINGTIAN_USE_AS_SWITCH // Inputs as Tasmota's virtual Switches + // Select none or only one of the below defines //#define USE_TX20_WIND_SENSOR // Add support for La Crosse TX20 anemometer (+2k6/0k8 code) //#define USE_TX23_WIND_SENSOR // Add support for La Crosse TX23 anemometer (+2k7/1k code) @@ -1216,6 +1212,14 @@ //#define FIRMWARE_IR // Create tasmota-ir with IR full protocols activated, and many sensors disabled //#define FIRMWARE_MINIMAL // Create tasmota-minimal as intermediate firmware for OTA-MAGIC +/*********************************************************************************************\ + * Safe guard when needed defines are not done in Platformio * +\*********************************************************************************************/ + +#ifndef OTA_URL + #define OTA_URL "" +#endif + /*********************************************************************************************\ * User configurable items override * \*********************************************************************************************/ @@ -1278,6 +1282,34 @@ #define USE_TLS // flag indicates we need to include TLS code #endif +/*********************************************************************************************\ + * Post-process compile options for Matter +\*********************************************************************************************/ + +#ifdef ESP32 +#ifdef USE_MATTER_DEVICE + #undef USE_DISCOVERY + #define USE_DISCOVERY + +// Enable all the crypto required by Matter + #undef USE_BERRY_CRYPTO_EC_P256 + #define USE_BERRY_CRYPTO_EC_P256 + #undef USE_BERRY_CRYPTO_HMAC_SHA256 + #define USE_BERRY_CRYPTO_HMAC_SHA256 + #undef USE_BERRY_CRYPTO_HKDF_SHA256 + #define USE_BERRY_CRYPTO_HKDF_SHA256 + #undef USE_BERRY_CRYPTO_AES_CCM + #define USE_BERRY_CRYPTO_AES_CCM + #undef USE_BERRY_CRYPTO_AES_CTR + #define USE_BERRY_CRYPTO_AES_CTR + #undef USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 + #define USE_BERRY_CRYPTO_PBKDF2_HMAC_SHA256 + #undef USE_BERRY_CRYPTO_SPAKE2P_MATTER + #define USE_BERRY_CRYPTO_SPAKE2P_MATTER + +#endif // USE_MATTER_DEVICE +#endif + /*********************************************************************************************\ * Post-process stack size adjustment \*********************************************************************************************/ diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index b0772932b..85c0f0d72 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -615,7 +615,7 @@ void setup(void) { snprintf_P(TasmotaGlobal.mqtt_topic, sizeof(TasmotaGlobal.mqtt_topic), ResolveToken(TasmotaGlobal.mqtt_topic).c_str()); RtcInit(); - GpioInit(); // FUNC_I2C_INIT -> FUNC_MODULE_INIT -> FUNC_LED_LINK + GpioInit(); // FUNC_SETUP_RING1 -> FUNC_SETUP_RING2 -> FUNC_MODULE_INIT -> FUNC_LED_LINK ButtonInit(); // FUNC_ADD_BUTTON SwitchInit(); // FUNC_ADD_SWITCH #ifdef ROTARY_V1 diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 7c8c90f5e..00ed4c2e0 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -757,6 +757,22 @@ bool NewerVersion(char* version_str) { return (version > VERSION); } +int32_t UpdateDevicesPresent(int32_t change) { + int32_t difference = 0; + int32_t devices_present = TasmotaGlobal.devices_present; // Between 0 and 32 + devices_present += change; + if (devices_present < 0) { // Support down to 0 + difference = devices_present; + devices_present = 0; + } + else if (devices_present >= POWER_SIZE) { // Support up to uint32_t as bitmask + difference = devices_present - POWER_SIZE; + devices_present = POWER_SIZE; + } + TasmotaGlobal.devices_present = devices_present; + return difference; +} + char* GetPowerDevice(char* dest, uint32_t idx, size_t size, uint32_t option) { strncpy_P(dest, S_RSLT_POWER, size); // POWER @@ -773,35 +789,38 @@ char* GetPowerDevice(char* dest, uint32_t idx, size_t size) return GetPowerDevice(dest, idx, size, 0); } -float ConvertTempToFahrenheit(float c) { - float result = c; +float ConvertTempToFahrenheit(float tc) { + if (isnan(tc)) { return NAN; } - if (!isnan(c) && Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit - result = c * 1.8f + 32; // Fahrenheit + float result = tc; + if (Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit + result = tc * 1.8f + 32; // Fahrenheit } result = result + (0.1f * Settings->temp_comp); return result; } -float ConvertTempToCelsius(float c) { - float result = c; - if (!isnan(c) && Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit - result = (c - 32) / 1.8f; // Celsius +float ConvertTempToCelsius(float tf) { + if (isnan(tf)) { return NAN; } + + float result = tf; + if (Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit + result = (tf - 32) / 1.8f; // Celsius } return result; } -void UpdateGlobalTemperature(float c) { +void UpdateGlobalTemperature(float t) { if (!Settings->global_sensor_index[0] && !TasmotaGlobal.user_globals[0]) { TasmotaGlobal.global_update = TasmotaGlobal.uptime; - TasmotaGlobal.temperature_celsius = c; + TasmotaGlobal.temperature_celsius = t; } } -float ConvertTemp(float c) { - UpdateGlobalTemperature(c); +float ConvertTemp(float t) { + UpdateGlobalTemperature(t); - return ConvertTempToFahrenheit(c); + return ConvertTempToFahrenheit(t); } char TempUnit(void) { @@ -826,18 +845,38 @@ float CalcTempHumToDew(float t, float h) { if (isnan(h) || isnan(t)) { return NAN; } if (Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit - t = (t - 32) / 1.8f; // Celsius + t = (t - 32) / 1.8f; // Celsius } float gamma = TaylorLog(h / 100) + 17.62f * t / (243.5f + t); float result = (243.5f * gamma / (17.62f - gamma)); if (Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit - result = result * 1.8f + 32; // Fahrenheit + result = result * 1.8f + 32; // Fahrenheit } return result; } +float CalcTempHumToAbsHum(float t, float h) { + if (isnan(t) || isnan(h)) { return NAN; } + // 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 + + if (Settings->flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit + t = (t - 32) / 1.8f; // Celsius + } + + float temp = FastPrecisePow(2.718281828f, (17.67f * t) / (t + 243.5f)); + + const float mw = 18.01534f; // Molar mass of water g/mol + const float r = 8.31447215f; // Universal gas constant J/mol/K +// return (6.112 * temp * h * 2.1674) / (273.15 + t); // Simplified version + return (6.112f * temp * h * mw) / ((273.15f + t) * r); // Long version +} + float ConvertHgToHpa(float p) { // Convert mmHg (or inHg) to hPa float result = p; @@ -1979,7 +2018,7 @@ void SetSerialBegin(void) { SetSerialSwap(); #endif // ESP8266 #ifdef ESP32 -#ifdef ARDUINO_USB_CDC_ON_BOOT +#if ARDUINO_USB_MODE // Serial.end(); // Serial.begin(); // Above sequence ends in "Exception":5,"Reason":"Load access fault" @@ -1989,7 +2028,7 @@ void SetSerialBegin(void) { Serial.end(); delay(10); // Allow time to cleanup queues - if not used hangs ESP32 Serial.begin(TasmotaGlobal.baudrate, ConvertSerialConfig(Settings->serial_config)); -#endif // Not ARDUINO_USB_CDC_ON_BOOT +#endif // Not ARDUINO_USB_MODE #endif // ESP32 } diff --git a/tasmota/tasmota_support/support_button_v4.ino b/tasmota/tasmota_support/support_button_v4.ino index a92963270..86967e84a 100644 --- a/tasmota/tasmota_support/support_button_v4.ino +++ b/tasmota/tasmota_support/support_button_v4.ino @@ -233,6 +233,9 @@ void ButtonProbe(void) { void ButtonInit(void) { bool ac_detect = (Settings->button_debounce % 10 == 9); Button.used = 0; +/* + uint32_t last_used = 0; +*/ for (uint32_t i = 0; i < MAX_KEYS_SET; i++) { Button.last_state[i] = NOT_PRESSED; #ifdef ESP8266 @@ -261,14 +264,13 @@ void ButtonInit(void) { } #endif // USE_ADC else { + // Insert, Skip and Append virtual buttons XdrvMailbox.index = i; if (XdrvCall(FUNC_ADD_BUTTON)) { - /* - At entry: - XdrvMailbox.index = button index - At exit: - XdrvMailbox.index bit 0 = current state - */ + // At entry: + // XdrvMailbox.index = button index + // At exit: + // XdrvMailbox.index bit 0 = current state bitSet(Button.used, i); // This pin is used bool state = (XdrvMailbox.index &1); ButtonSetVirtualPinState(i, state); // Virtual hardware pin state @@ -280,8 +282,38 @@ void ButtonInit(void) { } } Button.debounced_state[i] = Button.last_state[i]; +/* + if (bitRead(Button.used, i)) { + last_used = i +1; + } +*/ } +/* + // Append virtual buttons + for (uint32_t i = last_used; i < MAX_KEYS_SET; i++) { + Button.last_state[i] = NOT_PRESSED; + + XdrvMailbox.index = i; + if (XdrvCall(FUNC_ADD_BUTTON)) { + // At entry: + // XdrvMailbox.index = button index + // At exit: + // XdrvMailbox.index bit 0 = current state + bitSet(Button.used, i); // This pin is used + bool state = (XdrvMailbox.index &1); + ButtonSetVirtualPinState(i, state); // Virtual hardware pin state + if (!state) { ButtonInvertFlag(i); } // Set inverted flag + // last_state[i] must be 1 to indicate no button pressed + Button.last_state[i] = (bitRead(Button.virtual_pin, i) != bitRead(Button.inverted_mask, i)); + + AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Add vButton%d, State %d"), i +1, Button.last_state[i]); + } + + Button.debounced_state[i] = Button.last_state[i]; + } +*/ + // AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: vPinUsed %08X, State %08X, Invert %08X"), Button.used, Button.virtual_pin, Button.inverted_mask); if (Button.used) { // Any bit set diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index 9bdf91b37..4637cd09c 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -587,6 +587,31 @@ void CmndJson(void) { // {"template":"{\"NAME\":\"Dummy\",\"GPIO\":[320,0,321],\"FLAG\":0,\"BASE\":18}","power":2,"HSBColor":"51,97,100","Channel":[100,85,3]} // Output: // template {"NAME":"Dummy","GPIO":[320,0,321],"FLAG":0,"BASE":18};power 2;HSBColor 51,97,100;Channel1 100;Channel2 85;Channel3 3 +/* + String backlog; + for (auto command_key : root) { + const char *command = command_key.getStr(); + JsonParserToken parameters = command_key.getValue(); + if (parameters.isArray()) { + JsonParserArray parameter_arr = parameters.getArray(); + uint32_t index = 1; + for (auto value : parameter_arr) { + backlog = command; + backlog += index++; + backlog += " "; + backlog += value.getStr(); // Channel1 100;Channel2 85;Channel3 3 + ExecuteCommand((char*)backlog.c_str(), SRC_FILE); + } + } else if (parameters.isObject()) { // Should have been escaped +// AddLog(LOG_LEVEL_DEBUG, PSTR("JSN: Object")); + } else { + backlog = command; + backlog += " "; + backlog += parameters.getStr(); // HSBColor 51,97,100 + ExecuteCommand((char*)backlog.c_str(), SRC_FILE); + } + } +*/ String backlog; // We might need a larger string than XdrvMailbox.data_len accomodating decoded arrays for (auto command_key : root) { const char *command = command_key.getStr(); @@ -604,16 +629,23 @@ void CmndJson(void) { } else if (parameters.isObject()) { // Should have been escaped // AddLog(LOG_LEVEL_DEBUG, PSTR("JSN: Object")); } else { - if (backlog.length()) { backlog += ";"; } - backlog += command; - backlog += " "; - backlog += parameters.getStr(); // HSBColor 51,97,100 + String cmnd_param = command; + cmnd_param += " "; + cmnd_param += parameters.getStr(); + if (cmnd_param.indexOf(";") == -1) { // Rule1 ON Clock#Timer=1 DO Backlog Color #FF000000D0; Wakeup 100 ENDON + if (backlog.length()) { backlog += ";"; } + backlog += cmnd_param; // HSBColor 51,97,100 + } else { + ExecuteCommand((char*)cmnd_param.c_str(), SRC_FILE); + } } } - XdrvMailbox.data = (char*)backlog.c_str(); // Backlog commands - XdrvMailbox.data_len = 1; // Any data - XdrvMailbox.index = 0; // Backlog0 - no delay - CmndBacklog(); + if (backlog.length()) { + XdrvMailbox.data = (char*)backlog.c_str(); // Backlog commands + XdrvMailbox.data_len = 1; // Any data + XdrvMailbox.index = 0; // Backlog0 - no delay + CmndBacklog(); + } } else { ResponseCmndChar(PSTR(D_JSON_EMPTY)); } @@ -794,6 +826,10 @@ void CmndStatus(void) XsnsDriverState(); ResponseAppend_P(PSTR(",\"Sensors\":")); XsnsSensorState(0); +#ifdef USE_I2C + ResponseAppend_P(PSTR(",\"" D_CMND_I2CDRIVER "\":")); + I2cDriverState(); +#endif ResponseJsonEndEnd(); CmndStatusResponse(4); } @@ -913,24 +949,8 @@ void CmndStatus(void) } #ifdef USE_SHUTTER - if (Settings->flag3.shutter_mode) { - if ((0 == payload) || (13 == payload)) { - Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS13_SHUTTER "\":{")); - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { - if (0 == Settings->shutter_startrelay[i]) { break; } - if (i > 0) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(PSTR("\"" D_STATUS13_SHUTTER "%d\":{\"Relay1\":%d,\"Relay2\":%d,\"Open\":%d,\"Close\":%d," - "\"50perc\":%d,\"Delay\":%d,\"Opt\":\"%s\"," - "\"Calib\":[%d,%d,%d,%d,%d]," - "\"Mode\":\"%d\"}"), - i, Settings->shutter_startrelay[i], Settings->shutter_startrelay[i] +1, Settings->shutter_opentime[i], Settings->shutter_closetime[i], - Settings->shutter_set50percent[i], Settings->shutter_motordelay[i], GetBinary8(Settings->shutter_options[i], 4).c_str(), - Settings->shuttercoeff[0][i], Settings->shuttercoeff[1][i], Settings->shuttercoeff[2][i], Settings->shuttercoeff[3][i], Settings->shuttercoeff[4][i], - Settings->shutter_mode); - } - ResponseJsonEndEnd(); - CmndStatusResponse(13); - } + if ((0 == payload) || (13 == payload)) { + if (ShutterStatus()) { CmndStatusResponse(13); } } #endif @@ -1050,13 +1070,17 @@ void CmndSleep(void) } -void CmndUpgrade(void) -{ +void CmndUpgrade(void) { // Check if the payload is numerically 1, and had no trailing chars. // e.g. "1foo" or "1.2.3" could fool us. // Check if the version we have been asked to upgrade to is higher than our current version. // We also need at least 3 chars to make a valid version number string. + // Upload 1 - OTA upload binary + // Upload 2 - (ESP32 only) OTA upload safeboot binary if partition is present if (((1 == XdrvMailbox.data_len) && (1 == XdrvMailbox.payload)) || ((XdrvMailbox.data_len >= 3) && NewerVersion(XdrvMailbox.data))) { +#ifdef ESP32 + TasmotaGlobal.ota_factory = false; // Reset in case of failed safeboot upgrade +#endif // ESP32 and WEBCLIENT_HTTPS TasmotaGlobal.ota_state_flag = 3; char stemp1[TOPSZ]; Response_P(PSTR("{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}"), XdrvMailbox.command, TasmotaGlobal.version, GetOtaUrl(stemp1, sizeof(stemp1))); @@ -2135,14 +2159,29 @@ void CmndSwitchText(void) { } } -void CmndSwitchMode(void) -{ +void CmndSwitchMode(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SWITCHES_SET)) { + // SwitchMode1 - Show SwitchMode1 + // SwitchMode1 2 - Set SwitchMode tot 2 if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_SWITCH_OPTION)) { Settings->switchmode[XdrvMailbox.index -1] = XdrvMailbox.payload; } ResponseCmndIdxNumber(Settings->switchmode[XdrvMailbox.index-1]); } + else if (0 == XdrvMailbox.index) { + // SwitchMode0 - Show all SwitchMode like {"SwitchMode":[2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]} + // SwitchMode0 2 - Set all SwitchMode to 2 + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < MAX_SWITCH_OPTION)) { + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { + Settings->switchmode[i] = XdrvMailbox.payload; + } + } + Response_P(PSTR("{\"%s\":["), XdrvMailbox.command); + for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { + ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Settings->switchmode[i]); + } + ResponseAppend_P(PSTR("]}")); + } } void CmndInterlock(void) diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino index 72ba87771..7bdb9fb34 100644 --- a/tasmota/tasmota_support/support_features.ino +++ b/tasmota/tasmota_support/support_features.ino @@ -876,11 +876,19 @@ void ResponseAppendFeatures(void) #if defined(USE_ENERGY_SENSOR) && defined(USE_BIOPDU) feature9 |= 0x00010000; // xnrg_24_biopdu.ino #endif -// feature9 |= 0x00020000; -// feature9 |= 0x00040000; -// feature9 |= 0x00080000; +#if (defined(USE_I2C) || defined(USE_SPI)) && defined(USE_MCP23XXX_DRV) + feature9 |= 0x00020000; // xdrv_67_mcp23xxx.ino +#endif +#if defined(USE_I2C) && defined(USE_PMSA003I) + feature9 |= 0x00040000; // xsns_104_pmsa003i.ino +#endif +#ifdef USE_LOX_O2 + feature9 |= 0x00080000; // xsns_105_lox_o2.ino +#endif +#if defined(USE_I2C) && defined(USE_GDK101) + feature9 |= 0x00100000; // xsns_106_gdk101.ino +#endif -// feature9 |= 0x00100000; // feature9 |= 0x00200000; // feature9 |= 0x00400000; // feature9 |= 0x00800000; diff --git a/tasmota/tasmota_support/support_rtc.ino b/tasmota/tasmota_support/support_rtc.ino index 1c10811fc..84f775a98 100644 --- a/tasmota/tasmota_support/support_rtc.ino +++ b/tasmota/tasmota_support/support_rtc.ino @@ -186,9 +186,6 @@ String GetDateAndTime(uint8_t time_type) { } time = Rtc.restart_time; break; - case DT_ENERGY: - time = Settings->energy_kWhtotal_time; - break; case DT_BOOTCOUNT: time = Settings->bootcount_reset_time; break; diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 416ee8c0e..845f18766 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -556,6 +556,18 @@ void SetLedLink(uint32_t state) { #endif // USE_PWM_DIMMER } +void DebugLed(uint32_t mode) { + static bool toggle = false; + + if (PinUsed(GPIO_LEDLNK)) { + if (2 == mode) { + toggle != toggle; + mode = toggle; + } + digitalWrite(Pin(GPIO_LEDLNK), (TasmotaGlobal.ledlnk_inverted) ? !mode : mode); + } +} + void SetPulseTimer(uint32_t index, uint32_t time) { TasmotaGlobal.pulse_timer[index] = (time > 111) ? millis() + (1000 * (time - 100)) : (time > 0) ? millis() + (100 * time) : 0L; @@ -1501,6 +1513,9 @@ void Every250mSeconds(void) SettingsUpdateText(SET_MQTT_TOPIC, storage_mqtttopic); Settings->mqtt_port = mqtt_port; } + + XdrvCall(FUNC_RESET_SETTINGS); + TasmotaGlobal.restart_flag = 3; // Finish backlog then Restart 1 } else if (213 == TasmotaGlobal.restart_flag) { // Reset 3 @@ -2193,38 +2208,7 @@ void GpioInit(void) #endif #endif // USE_I2C - XdrvCall(FUNC_I2C_INIT); // Init RTC - TasmotaGlobal.devices_present = 0; - TasmotaGlobal.light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0 - - XsnsCall(FUNC_MODULE_INIT); - - if (XdrvCall(FUNC_MODULE_INIT)) { - // Serviced - } -#ifdef ESP8266 - else if (YTF_IR_BRIDGE == TasmotaGlobal.module_type) { - ClaimSerial(); // Stop serial loopback mode -// TasmotaGlobal.devices_present = 1; - } - else if (SONOFF_DUAL == TasmotaGlobal.module_type) { - TasmotaGlobal.devices_present = 2; - SetSerial(19200, TS_SERIAL_8N1); - } - else if (CH4 == TasmotaGlobal.module_type) { - TasmotaGlobal.devices_present = 4; - SetSerial(19200, TS_SERIAL_8N1); - } -#ifdef USE_SONOFF_SC - else if (SONOFF_SC == TasmotaGlobal.module_type) { - SetSerial(19200, TS_SERIAL_8N1); - } -#endif // USE_SONOFF_SC -#endif // ESP8266 - - GpioInitPwm(); - uint32_t bi_device = 0; for (uint32_t i = 0; i < MAX_RELAYS; i++) { if (PinUsed(GPIO_REL1, i)) { @@ -2241,6 +2225,30 @@ void GpioInit(void) } } + XdrvCall(FUNC_SETUP_RING1); // Setup RTC hardware + XsnsXdrvCall(FUNC_SETUP_RING2); // Setup hardware supporting virtual switches/buttons/relays + + TasmotaGlobal.light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0 + + if (XdrvCall(FUNC_MODULE_INIT)) { // Init and claim single module (like tuya, armtronix, ifan, light) + // Serviced + } +#ifdef ESP8266 + else if (YTF_IR_BRIDGE == TasmotaGlobal.module_type) { + ClaimSerial(); // Stop serial loopback mode + } + else if (SONOFF_DUAL == TasmotaGlobal.module_type) { + UpdateDevicesPresent(2); + SetSerial(19200, TS_SERIAL_8N1); + } + else if (CH4 == TasmotaGlobal.module_type) { + UpdateDevicesPresent(4); + SetSerial(19200, TS_SERIAL_8N1); + } +#endif // ESP8266 + + GpioInitPwm(); + for (uint32_t i = 0; i < MAX_LEDS; i++) { if (PinUsed(GPIO_LED1, i)) { #ifdef USE_ARILUX_RF diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index fe5b8fb0e..084d55bb5 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -461,35 +461,35 @@ void WifiSetState(uint8_t state) /*****************************************************************************************************\ * IP detection revised for full IPv4 / IPv6 support - * + * * In general, each interface (Wifi/Eth) can have 1x IPv4 and * 2x IPv6 (Global routable address and Link-Local starting witn fe80:...) - * + * * We always use an IPv4 address if one is assigned, and revert to * IPv6 only on networks that are v6 only. * Ethernet calls can be safely used even if the USE_ETHERNET is not enabled - * + * * New APIs: * - general form is: * `bool XXXGetIPYYY(IPAddress*)` returns `true` if the address exists and copies the address * if the pointer is non-null. * `bool XXXHasIPYYY()` same as above but only returns `true` or `false` * `String XXXGetIPYYYStr()` returns the IP as a `String` or empty `String` if none - * + * * `XXX` can be `Wifi` or `Eth` * `YYY` can be `` for any address, `v6` for IPv6 global address or `v6LinkLocal` for Link-local - * + * * - Legacy `Wifi.localIP()` and `ETH.localIP()` always return IPv4 and nothing on IPv6 only networks * * - v4/v6: * `WifiGetIP`, `WifiGetIPStr`, `WifiHasIP`: get preferred v4/v6 address for Wifi * `EthernetGetIP`, `EthernetGetIPStr`, `EthernetHasIP`: get preferred v4/v6 for Ethernet - * + * * - Main IP to be used dual stack v4/v6 * `hasIP`, `IPGetListeningAddress`, `IPGetListeningAddressStr`: any IP to listen to for Web Server * IPv4 is always preferred, and Eth is preferred over Wifi. * `IPForUrl`: converts v4/v6 to use in URL, enclosing v6 in [] - * + * * - v6 only: * `WifiGetIPv6`, `WifiGetIPv6Str`, `WifiHasIPv6` * `WifiGetIPv6LinkLocal`, `WifiGetIPv6LinkLocalStr` @@ -499,7 +499,7 @@ void WifiSetState(uint8_t state) * - v4 only: * `WifiGetIPv4`, `WifiGetIPv4Str`, `WifiHasIPv4` * `EthernetGetIPv4`, `EthernetGetIPv4Str`, `EthernetHasIPv4` - * + * * - DNS reporting actual values used (not the Settings): * `DNSGetIP(n)`, `DNSGetIPStr(n)` with n=`0`/`1` (same dns for Wifi and Eth) \*****************************************************************************************************/ @@ -648,7 +648,7 @@ String DNSGetIPStr(uint32_t idx) return DNSGetIP(&ip, idx) ? ip.toString() : String(F("0.0.0.0")); } -// +// #include "lwip/dns.h" void WifiDumpAddressesIPv6(void) { @@ -1254,13 +1254,14 @@ uint64_t WifiGetNtp(void) { IPAddress time_server_ip; - char fallback_ntp_server[16]; - snprintf_P(fallback_ntp_server, sizeof(fallback_ntp_server), PSTR("%d.pool.ntp.org"), random(0,3)); + char fallback_ntp_server[2][32]; + ext_snprintf_P(fallback_ntp_server[0], sizeof(fallback_ntp_server[0]), PSTR("%_I"), Settings->ipv4_address[1]); // #17984 + ext_snprintf_P(fallback_ntp_server[1], sizeof(fallback_ntp_server[1]), PSTR("%d.pool.ntp.org"), random(0,3)); char* ntp_server; - for (uint32_t i = 0; i <= MAX_NTP_SERVERS; i++) { - if (ntp_server_id > MAX_NTP_SERVERS) { ntp_server_id = 0; } - ntp_server = (ntp_server_id < MAX_NTP_SERVERS) ? SettingsText(SET_NTPSERVER1 + ntp_server_id) : fallback_ntp_server; + for (uint32_t i = 0; i < MAX_NTP_SERVERS +2; i++) { + if (ntp_server_id >= MAX_NTP_SERVERS +2) { ntp_server_id = 0; } + ntp_server = (ntp_server_id < MAX_NTP_SERVERS) ? SettingsText(SET_NTPSERVER1 + ntp_server_id) : fallback_ntp_server[ntp_server_id - MAX_NTP_SERVERS]; if (strlen(ntp_server)) { break; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_1_webserver_mail.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_1_webserver_mail.ino index 42bb029a4..8cb24b774 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_1_webserver_mail.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_1_webserver_mail.ino @@ -22,10 +22,12 @@ * #define EMAIL_SERVER "smtp.gmail.com" * #define EMAIL_PORT 465 * + * Note : starting with this update, it is not required anymore to include emails in < > as they will + * be automatically added if needed * if email body consist of a single * and scripter is present * and a section >m is found, the lines in this section (until #) are sent as email body - * - * Some mail servers do not accept the IP address in the HELO (or EHLO) message but only a fully qualified + * + * Some mail servers do not accept the IP address in the HELO (or EHLO) message but only a fully qualified * domain name (FQDN). To overcome this, use the following define to override this behavior and enter the desired FQDN * #define EMAIL_USER_DOMAIN "googlemail.com" * @@ -111,7 +113,7 @@ String SendEmail::readClient() { return r; } -bool SendEmail::send(const String& from, const String& to, const String& subject, const char *msg) { +bool SendEmail::send(const String& _from, const String& _to, const String& subject, const char *msg) { if (!host.length()) { return false; } client->setTimeout(timeout); @@ -129,6 +131,10 @@ bool SendEmail::send(const String& from, const String& to, const String& subject return false; } + String from, to; + from = ('<' == *_from.c_str()) ? _from : ("<" + _from + ">"); + to = ('<' == *_to.c_str()) ? _to : ("<" + _to +">"); + String buffer = readClient(); #ifdef DEBUG_EMAIL_PORT MailReadAddLogBuffer(&buffer); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino index 91b140e48..7c8300cb7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino @@ -1232,7 +1232,7 @@ void HandleRoot(void) #ifdef USE_SHUTTER if (Settings->flag3.shutter_mode) { // SetOption80 - Enable shutter support for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { - WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, Settings->shutter_position[i], i+1); + WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, ShutterRealToPercentPosition(-9999, i), i+1); } } #endif // USE_SHUTTER @@ -1482,9 +1482,9 @@ int32_t IsShutterWebButton(uint32_t idx) { /* 0: Not a shutter, 1..4: shutter up idx, -1..-4: shutter down idx */ int32_t ShutterWebButton = 0; if (Settings->flag3.shutter_mode) { // SetOption80 - Enable shutter support - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { - if (Settings->shutter_startrelay[i] && ((Settings->shutter_startrelay[i] == idx) || (Settings->shutter_startrelay[i] == (idx-1)))) { - ShutterWebButton = (Settings->shutter_startrelay[i] == idx) ? (i+1): (-1-i); + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present ; i++) { + if (ShutterGetStartRelay(i) && ((ShutterGetStartRelay(i) == idx) || (ShutterGetStartRelay(i) == (idx-1)))) { + ShutterWebButton = (ShutterGetStartRelay(i) == idx) ? (i+1): (-1-i); break; } } @@ -2349,7 +2349,7 @@ void HandleInformation(void) } if (Settings->flag4.network_wifi) { int32_t rssi = WiFi.RSSI(); - WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm) 11%c"), Settings->sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings->sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi, pgm_read_byte(&kWifiPhyMode[WiFi.getPhyMode() & 0x3]) ); + WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s %d (%d%%, %d dBm) 11%c"), Settings->sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings->sta_active)).c_str(), WiFi.channel(), WifiGetRssiAsQuality(rssi), rssi, pgm_read_byte(&kWifiPhyMode[WiFi.getPhyMode() & 0x3]) ); WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? PSTR(".local") : ""); #ifdef USE_IPV6 String ipv6_addr = WifiGetIPv6Str(); @@ -3239,8 +3239,7 @@ int WebSend(char *buffer) return status; } -int WebQuery(char *buffer) -{ +int WebQuery(char *buffer) { // http://192.168.1.1/path GET -> Sends HTTP GET http://192.168.1.1/path // http://192.168.1.1/path POST {"some":"message"} -> Sends HTTP POST to http://192.168.1.1/path with body {"some":"message"} // http://192.168.1.1/path PUT [Autorization: Bearer abcdxyz] potato -> Sends HTTP PUT to http://192.168.1.1/path with authorization header and body "potato" @@ -3343,8 +3342,7 @@ int WebQuery(char *buffer) } #ifdef USE_WEBGETCONFIG -int WebGetConfig(char *buffer) -{ +int WebGetConfig(char *buffer) { // http://user:password@server:port/path/%id%.dmp : %id% will be expanded to MAC address int status = WEBCMND_WRONG_PARAMETERS; @@ -3357,7 +3355,7 @@ int WebGetConfig(char *buffer) #if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS) HTTPClientLight http; - if (http.begin(UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON| + if (http.begin(UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON| #else // HTTP only WiFiClient http_client; HTTPClient http; @@ -3602,8 +3600,7 @@ void CmndWebQuery(void) } #ifdef USE_WEBGETCONFIG -void CmndWebGetConfig(void) -{ +void CmndWebGetConfig(void) { // WebGetConfig http://myserver:8000/tasmota/conf/%id%.dmp where %id% is expanded to device mac address // WebGetConfig http://myserver:8000/tasmota/conf/Config_demo_9.5.0.8.dmp if (XdrvMailbox.data_len > 0) { @@ -3631,10 +3628,9 @@ void CmndWebColor(void) #endif // FIRMWARE_MINIMAL } } - Response_P(PSTR("{\"" D_CMND_WEBCOLOR "\":[")); + Response_P(PSTR("{\"%s\":["), XdrvMailbox.command); for (uint32_t i = 0; i < COL_LAST; i++) { - if (i) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(PSTR("\"#%06x\""), WebColor(i)); + ResponseAppend_P(PSTR("%s\"#%06x\""), (i>0)?",":"", WebColor(i)); } ResponseAppend_P(PSTR("]}")); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 45613230e..ebbad0f72 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -101,6 +101,8 @@ typedef struct { int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily int32_t period[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily + char* value; + uint8_t fifth_second; uint8_t command_code; uint8_t data_valid[ENERGY_MAX_PHASES]; @@ -143,14 +145,32 @@ Ticker ticker_energy; /********************************************************************************************/ -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +const uint16_t GUISZ = 300; // Max number of characters in WebEnergyFmt string + +bool EnergyFmtMalloc(void) { + if (Energy->value == nullptr) { + Energy->value = (char*)malloc(GUISZ); + if (!Energy->value) { return false; } + } + return true; +} + +void EnergyFmtFree(void) { +// free(Energy->value); // Let's keep it for future use reducing heap fragmentation +// Energy->value = nullptr; +} + +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx or [xx,xx] or [xx,xx,xx] // single = 1 - Energy->voltage_common or Energy->frequency_common - xx // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] // single = 5 - single &0x03 = 1 - xx // single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff // single = 7 - single &0x03 = 3 - [xx,xx,xx] + + if (!EnergyFmtMalloc()) { return EmptyStr; } + uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy->phase_count : 1; // 1,2,3 if (single > 2) { single = 0; } // 0,1,2 float input_sum = 0.0f; @@ -166,19 +186,22 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin index = Energy->phase_count; } } - result[0] = '\0'; + Energy->value[0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, TOPSZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%s%*_f%s"), Energy->value, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); } - return result; + return Energy->value; } #ifdef USE_WEBSERVER -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx / xx / xx or multi column // single = 1 - Energy->voltage_common or Energy->frequency_common - xx or single column using colspan (if needed) // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column + + if (!EnergyFmtMalloc()) { return EmptyStr; } + float input_sum = 0.0f; if (single > 1) { // Sum and/or Single column if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information @@ -192,39 +215,34 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0; } } -#ifdef USE_ENERGY_COLUMN_GUI - ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column + ext_snprintf_P(Energy->value, GUISZ, PSTR("")); // Skip first column if ((Energy->phase_count > 1) && single) { // Need to set colspan so need new columns // "), - result, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), + Energy->value, (Energy->phase_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[0]); } else { // "), - result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), + Energy->value, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[i]); } } - ext_snprintf_P(result, GUISZ, PSTR("%s - -const char HTTP_ENERGY_SNS3[] PROGMEM = - "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; -#endif // USE_WEBSERVER - void EnergyShow(bool json) { bool voltage_common = (Settings->flag6.no_voltage_common) ? false : Energy->voltage_common; bool frequency_common = (Settings->flag6.no_voltage_common) ? false : Energy->frequency_common; @@ -1189,6 +1199,9 @@ void EnergyShow(bool json) { if (isnan(apparent_power[i])) { apparent_power[i] = Energy->voltage[i] * Energy->current[i]; } + else if (0 == Energy->current[i]) { + apparent_power[i] = 0; + } if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible Energy->active_power[i] = apparent_power[i]; } @@ -1216,6 +1229,9 @@ void EnergyShow(bool json) { reactive_power[i] = (float)(SqrtInt((uint32_t)(power_diff))); } } + else if (0 == Energy->current[i]) { + reactive_power[i] = 0; + } } } @@ -1232,7 +1248,7 @@ void EnergyShow(bool json) { bool energy_tariff = false; float energy_usage[2]; float energy_return[2]; - if (Settings->tariff[0][0] != Settings->tariff[1][0]) { + if (Settings->mbflag2.tariff_forced || (Settings->tariff[0][0] != Settings->tariff[1][0])) { energy_usage[0] = (float)RtcSettings.energy_usage.usage1_kWhtotal / 1000; // Tariff1 energy_usage[1] = (float)RtcSettings.energy_usage.usage2_kWhtotal / 1000; // Tariff2 energy_return[0] = (float)RtcSettings.energy_usage.return1_kWhtotal / 1000; // Tariff1 @@ -1240,34 +1256,31 @@ void EnergyShow(bool json) { energy_tariff = true; } - char value_chr[GUISZ]; // Used by EnergyFormatIndex - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - if (json) { bool show_energy_period = (0 == TasmotaGlobal.tele_period); ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), - GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + GetDT(Settings->energy_kWhtotal_time).c_str(), + EnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_usage, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_usage, Settings->flag2.energy_resolution, 6)); } - ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), - EnergyFormat(value_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), - EnergyFormat(value2_chr, Energy->daily, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_ph, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily, Settings->flag2.energy_resolution, 2)); /* #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) if (!isnan(Energy->import_active[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->import_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->import_active, Settings->flag2.energy_resolution)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return, Settings->flag2.energy_resolution, 6)); } } #endif // SDM630_IMPORT || SDM72_IMPEXP @@ -1275,47 +1288,52 @@ void EnergyShow(bool json) { if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 0 : 1; - ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value2_chr, &Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value3_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_EXPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); + if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return, Settings->flag2.energy_resolution, 6)); } } if (show_energy_period) { float energy_period[Energy->phase_count]; for (uint32_t i = 0; i < Energy->phase_count; i++) { - energy_period[i] = (float)(RtcSettings.energy_kWhtoday_ph[i] - Energy->period[i]) / 100; + energy_period[i] = (float)(RtcSettings.energy_kWhtoday_ph[i] - Energy->period[i]) / 100; // Wh Energy->period[i] = RtcSettings.energy_kWhtoday_ph[i]; } ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), - EnergyFormat(value_chr, energy_period, Settings->flag2.wattage_resolution)); + EnergyFmt(energy_period, Settings->flag2.wattage_resolution)); } ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), - EnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + EnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), - EnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - EnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - EnergyFormat(value3_chr, power_factor, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s"), + EnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_REACTIVE_POWERUSAGE "\":%s"), + EnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_POWERFACTOR "\":%s"), + EnergyFmt(power_factor, 2)); } if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + EnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + EnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), - EnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + EnergyFmt(Energy->current, Settings->flag2.current_resolution)); } XnrgCall(FUNC_JSON_APPEND); ResponseJsonEnd(); @@ -1363,7 +1381,6 @@ void EnergyShow(bool json) { #endif // USE_KNX #ifdef USE_WEBSERVER } else { -#ifdef USE_ENERGY_COLUMN_GUI // Need a new table supporting more columns using empty columns (with   in data rows) as easy column spacing // {s}
1.23  // 1.23  // 1.23  - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f %*_f 1.23  // 1.23 1.23  // 1.23 1.23 1.23  // 1.23 1.23 1.23 1.23  for (uint32_t i = 0; i < Energy->phase_count; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f %*_f "), result); -#else // not USE_ENERGY_COLUMN_GUI - uint32_t index = (single) ? 1 : Energy->phase_count; // 1,2,3 - result[0] = '\0'; - for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f"), result, (i)?" / ":"", resolution, &input[i]); - } -#endif // USE_ENERGY_COLUMN_GUI - return result; + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), Energy->value); + return Energy->value; } #endif // USE_WEBSERVER /********************************************************************************************/ bool EnergyTariff1Active() { // Off-Peak hours + if (Settings->mbflag2.tariff_forced) { + return 1 == Settings->mbflag2.tariff_forced; + } uint8_t dst = 0; if (IsDst() && (Settings->tariff[0][1] != Settings->tariff[1][1])) { dst = 1; @@ -492,8 +510,7 @@ void EnergyMarginCheck(void) { for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { power_diff_f[phase] = power_diff[phase]; } - char value_chr[TOPSZ]; - ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); + ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFmt(power_diff_f, 0)); } uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); @@ -600,6 +617,7 @@ void EnergyMarginCheck(void) { } } #endif // USE_ENERGY_POWER_LIMIT + EnergyFmtFree(); } void EnergyMqttShow(void) { @@ -665,10 +683,6 @@ void EnergyEverySecond(void) { \*********************************************************************************************/ void ResponseCmndEnergyTotalYesterdayToday(void) { - char value_chr[TOPSZ]; // Used by EnergyFormatIndex - char value2_chr[TOPSZ]; - char value3_chr[TOPSZ]; - float energy_yesterday_ph[3]; for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_ph[i] = (float)Settings->energy_kWhyesterday_ph[i] / 100000; @@ -678,16 +692,19 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { } } - Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s"), XdrvMailbox.command, - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, Energy->daily, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->total, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_ph, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily, Settings->flag2.energy_resolution)); if (Energy->local_energy_active_export) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution)); } ResponseJsonEndEnd(); + EnergyFmtFree(); } void CmndEnergyTotal(void) { @@ -697,7 +714,7 @@ void CmndEnergyTotal(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Total - RtcSettings.energy_kWhtotal_ph[phase] = values[0]; + RtcSettings.energy_kWhtotal_ph[phase] = (int32_t)values[0]; Settings->energy_kWhtotal_ph[phase] = RtcSettings.energy_kWhtotal_ph[phase]; if (params > 1) { Settings->energy_kWhtotal_time = values[1]; @@ -716,7 +733,7 @@ void CmndEnergyYesterday(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Yesterday - Settings->energy_kWhyesterday_ph[phase] = values[0] * 100; + Settings->energy_kWhyesterday_ph[phase] = (int32_t)values[0] * 100; if (params > 1) { Settings->energy_kWhtotal_time = values[1]; } @@ -732,7 +749,7 @@ void CmndEnergyToday(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Today - Energy->kWhtoday_offset[phase] = values[0] * 100; + Energy->kWhtoday_offset[phase] = (int32_t)values[0] * 100; Energy->kWhtoday[phase] = 0; Energy->kWhtoday_delta[phase] = 0; Energy->start_energy[phase] = 0; @@ -760,7 +777,7 @@ void CmndEnergyExportActive(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Export Active - RtcSettings.energy_kWhexport_ph[phase] = values[0]; + RtcSettings.energy_kWhexport_ph[phase] = (int32_t)values[0]; Settings->energy_kWhexport_ph[phase] = RtcSettings.energy_kWhexport_ph[phase]; if (params > 1) { Settings->energy_kWhtotal_time = values[1]; @@ -789,9 +806,9 @@ void CmndEnergyUsage(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.usage totals - RtcSettings.energy_usage.usage1_kWhtotal = values[0]; + RtcSettings.energy_usage.usage1_kWhtotal = (int32_t)values[0]; if (params > 1) { - RtcSettings.energy_usage.usage2_kWhtotal = values[1]; + RtcSettings.energy_usage.usage2_kWhtotal = (int32_t)values[1]; } Settings->energy_usage.usage1_kWhtotal = RtcSettings.energy_usage.usage1_kWhtotal; Settings->energy_usage.usage2_kWhtotal = RtcSettings.energy_usage.usage2_kWhtotal; @@ -804,9 +821,9 @@ void CmndEnergyExport(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.return totals - RtcSettings.energy_usage.return1_kWhtotal = values[0] * 100; + RtcSettings.energy_usage.return1_kWhtotal = (int32_t)values[0] * 100; if (params > 1) { - RtcSettings.energy_usage.return2_kWhtotal = values[1] * 100; + RtcSettings.energy_usage.return2_kWhtotal = (int32_t)values[1] * 100; } Settings->energy_usage.return1_kWhtotal = RtcSettings.energy_usage.return1_kWhtotal; Settings->energy_usage.return2_kWhtotal = RtcSettings.energy_usage.return2_kWhtotal; @@ -825,37 +842,44 @@ void CmndTariff(void) { uint32_t tariff = XdrvMailbox.index -1; uint32_t time_type = 0; char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); // 23:15, 22:30 - while ((str != nullptr) && (time_type < 2)) { - char *q; - uint32_t value = strtol(str, &q, 10); // 23 or 22 - Settings->tariff[tariff][time_type] = value; - if (value < 24) { // Below 24 is hours - Settings->tariff[tariff][time_type] *= 60; // Multiply hours by 60 minutes - char *minute = strtok_r(nullptr, ":", &q); - if (minute) { - value = strtol(minute, nullptr, 10); // 15 or 30 - if (value > 59) { - value = 59; + if (POWER_OFF == XdrvMailbox.payload) + Settings->mbflag2.tariff_forced = 0; + else if (POWER_ON == XdrvMailbox.payload) + Settings->mbflag2.tariff_forced = tariff + 1; + else { + char *str = strtok_r(XdrvMailbox.data, ", ", &p); // 23:15, 22:30 + while ((str != nullptr) && (time_type < 2)) { + char *q; + uint32_t value = strtol(str, &q, 10); // 23 or 22 + Settings->tariff[tariff][time_type] = value; + if (value < 24) { // Below 24 is hours + Settings->tariff[tariff][time_type] *= 60; // Multiply hours by 60 minutes + char *minute = strtok_r(nullptr, ":", &q); + if (minute) { + value = strtol(minute, nullptr, 10); // 15 or 30 + if (value > 59) { + value = 59; + } + Settings->tariff[tariff][time_type] += value; } - Settings->tariff[tariff][time_type] += value; } + if (Settings->tariff[tariff][time_type] > 1439) { + Settings->tariff[tariff][time_type] = 1439; // Max is 23:59 + } + str = strtok_r(nullptr, ", ", &p); + time_type++; } - if (Settings->tariff[tariff][time_type] > 1439) { - Settings->tariff[tariff][time_type] = 1439; // Max is 23:59 - } - str = strtok_r(nullptr, ", ", &p); - time_type++; } } else if (XdrvMailbox.index == 9) { Settings->flag3.energy_weekend = XdrvMailbox.payload & 1; // CMND_TARIFF } - Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\"}}"), + Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\",\"Forced\":\"%d\"}}"), XdrvMailbox.command, GetMinuteTime(Settings->tariff[0][0]).c_str(),GetMinuteTime(Settings->tariff[0][1]).c_str(), GetMinuteTime(Settings->tariff[1][0]).c_str(),GetMinuteTime(Settings->tariff[1][1]).c_str(), - GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF + GetStateText(Settings->flag3.energy_weekend), // Tariff9 + Settings->mbflag2.tariff_forced); // Tariff ON|OFF } uint32_t EnergyGetCalibration(uint32_t cal_type, uint32_t chan = 0) { @@ -1100,6 +1124,7 @@ void EnergyDrvInit(void) { Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false if (!Energy) { return; } + Energy->value = nullptr; // Energy->voltage_common = false; // Energy->frequency_common = false; // Energy->use_overtemp = false; @@ -1154,21 +1179,6 @@ void EnergySnsInit(void) } } -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SNS1[] PROGMEM = - "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" - "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" - "{s}" D_POWER_FACTOR "{m}%s{e}"; - -const char HTTP_ENERGY_SNS2[] PROGMEM = - "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; // {s} =
, {m} = , {e} =
Head1{e} // {s}Head1Head2{e} @@ -1372,45 +1389,44 @@ void EnergyShow(bool json) { WSContentSend_P(PSTR("


{t}{s}")); // First column is empty ({t} = , {s} = "), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, value_chr, 10)); + WSContentSend_P(PSTR(""), (no_label)?"":(label_o)?"O":"L", (no_label)?"":itoa(i +1, number, 10)); } WSContentSend_P(PSTR(") -#endif // USE_ENERGY_COLUMN_GUI if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (!Energy->type_dc) { if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + WebEnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFmt(Energy->current, Settings->flag2.current_resolution)); } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, power_factor, 2)); + WSContentSend_PD(HTTP_SNS_POWERUSAGE_APPARENT, WebEnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWERUSAGE_REACTIVE, WebEnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWER_FACTOR, WebEnergyFmt(power_factor, 2)); } } - WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, energy_yesterday_ph, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_ENERGY_TODAY, WebEnergyFmt(Energy->daily, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_ENERGY_YESTERDAY, WebEnergyFmt(energy_yesterday_ph, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_ENERGY_TOTAL, WebEnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + WSContentSend_PD(HTTP_SNS_EXPORT_ACTIVE, WebEnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); } -#ifdef USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_COL_SENSOR); WSContentSend_P(PSTR("
) bool label_o = voltage_common; bool no_label = (1 == Energy->phase_count); + char number[4]; for (uint32_t i = 0; i < Energy->phase_count; i++) { - WSContentSend_P(PSTR("%s%s%s%s{e}")); // Last column is units ({e} =

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR -#endif // USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_SENSOR); #endif // USE_WEBSERVER } + EnergyFmtFree(); } /*********************************************************************************************\ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino index 603a6fa2e..2261c53f2 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_esp32_energy.ino @@ -159,6 +159,8 @@ typedef struct { int32_t kWhtoday[ENERGY_MAX_PHASES]; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy->daily // Local only + char* value; + float daily_kWh[ENERGY_MAX_PHASES]; // 123.123 kWh float energy_today_offset_kWh[ENERGY_MAX_PHASES]; // 123.12312 kWh = Energy->daily float period_kWh[ENERGY_MAX_PHASES]; // 123.12312 kWh = Energy->daily @@ -273,7 +275,7 @@ bool EnergyRtcSettingsValid(void) { const uint32_t XDRV_03_VERSION = 0x0102; // Latest driver version (See settings deltas below) -void EnergySettingsLoad(void) { +void EnergySettingsLoad(bool erase) { // *** Start init default values in case file is not found *** memset(&Energy->Settings, 0x00, sizeof(tEnergySettings)); Energy->Settings.version = XDRV_03_VERSION; @@ -320,7 +322,10 @@ void EnergySettingsLoad(void) { char filename[20]; // Use for drivers: snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_03); - if (TfsLoadFile(filename, (uint8_t*)&Energy->Settings, sizeof(tEnergySettings))) { + if (erase) { + TfsDeleteFile(filename); // Use defaults + } + else if (TfsLoadFile(filename, (uint8_t*)&Energy->Settings, sizeof(tEnergySettings))) { if (Energy->Settings.version != XDRV_03_VERSION) { // Fix version dependent changes // *** Start fix possible setting deltas *** @@ -336,7 +341,8 @@ void EnergySettingsLoad(void) { EnergySettingsSave(); } AddLog(LOG_LEVEL_INFO, PSTR("CFG: Energy loaded from file")); - } else { + } + else { // File system not ready: No flash space reserved for file system AddLog(LOG_LEVEL_INFO, PSTR("CFG: Energy use defaults as file system not ready or file not found")); } @@ -366,14 +372,32 @@ void EnergySettingsSave(void) { /********************************************************************************************/ -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +const uint16_t GUISZ = 600; // Max number of characters in WebEnergyFmt string + +bool EnergyFmtMalloc(void) { + if (Energy->value == nullptr) { + Energy->value = (char*)malloc(GUISZ); + if (!Energy->value) { return false; } + } + return true; +} + +void EnergyFmtFree(void) { +// free(Energy->value); // Let's keep it for future use reducing heap fragmentation +// Energy->value = nullptr; +} + +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* EnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx or [xx,xx] or [xx,xx,xx] // single = 1 - Energy->voltage_common or Energy->frequency_common - xx // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or if SO129 1 - [xx,xx,xx] // single = 5 - single &0x03 = 1 - xx // single = 6 - single &0x03 = 2 - [xx,xx] - used by tarriff // single = 7 - single &0x03 = 3 - [xx,xx,xx] + + if (!EnergyFmtMalloc()) { return EmptyStr; } + uint32_t index = (single > 3) ? single &0x03 : (0 == single) ? Energy->phase_count : 1; // 1,2,3 if (single > 2) { single = 0; } // 0,1,2 float input_sum = 0.0f; @@ -389,19 +413,22 @@ char* EnergyFormat(char* result, float* input, uint32_t resolution, uint32_t sin index = Energy->phase_count; } } - result[0] = '\0'; + Energy->value[0] = '\0'; for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f%s"), result, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s%s%*_f%s"), Energy->value, (0==i)?(1==index)?"":"[":",", resolution, &input[i], (index-1==i)?(1==index)?"":"]":""); } - return result; + return Energy->value; } #ifdef USE_WEBSERVER -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0); -char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single) { +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single = 0); +char* WebEnergyFmt(float* input, uint32_t resolution, uint32_t single) { // single = 0 - Energy->phase_count - xx / xx / xx or multi column // single = 1 - Energy->voltage_common or Energy->frequency_common - xx or single column using colspan (if needed) // single = 2 - Sum of Energy->phase_count if SO129 0 - xx or single column using colspan (if needed) or if SO129 1 - xx / xx / xx or multi column + + if (!EnergyFmtMalloc()) { return EmptyStr; } + float input_sum = 0.0f; if (single > 1) { // Sum and/or Single column if (!Settings->flag5.energy_phase) { // SetOption129 - (Energy) Show phase information @@ -415,39 +442,34 @@ char* WebEnergyFormat(char* result, float* input, uint32_t resolution, uint32_t single = 0; } } -#ifdef USE_ENERGY_COLUMN_GUI - ext_snprintf_P(result, GUISZ, PSTR("")); // Skip first column + ext_snprintf_P(Energy->value, GUISZ, PSTR("")); // Skip first column if ((Energy->gui_count > 1) && single) { // Need to set colspan so need new columns // "), - result, (Energy->gui_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[Energy->gui_indirect[0]]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), + Energy->value, (Energy->gui_count *2) -1, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("center"), resolution, &input[Energy->gui_indirect[0]]); } else { // "), - result, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[Energy->gui_indirect[Energy->gui_offset +i]]); + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), + Energy->value, (Settings->flag5.gui_table_align)?PSTR("right"):PSTR("left"), resolution, &input[Energy->gui_indirect[Energy->gui_offset +i]]); } } - ext_snprintf_P(result, GUISZ, PSTR("%s - -const char HTTP_ENERGY_SNS3[] PROGMEM = - "{s}" D_EXPORT_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; -#endif // USE_WEBSERVER - void EnergyShow(bool json) { bool voltage_common = (Settings->flag6.no_voltage_common) ? false : Energy->voltage_common; bool frequency_common = (Settings->flag6.no_voltage_common) ? false : Energy->frequency_common; @@ -1419,6 +1433,9 @@ void EnergyShow(bool json) { if (isnan(apparent_power[i])) { apparent_power[i] = Energy->voltage[i] * Energy->current[i]; } + else if (0 == Energy->current[i]) { + apparent_power[i] = 0; + } if (apparent_power[i] < Energy->active_power[i]) { // Should be impossible Energy->active_power[i] = apparent_power[i]; } @@ -1446,6 +1463,9 @@ void EnergyShow(bool json) { reactive_power[i] = (float)(SqrtInt((uint32_t)(power_diff))); } } + else if (0 == Energy->current[i]) { + reactive_power[i] = 0; + } } } @@ -1462,7 +1482,7 @@ void EnergyShow(bool json) { bool energy_tariff = false; float energy_usage_kWh[2]; float energy_return_kWh[2]; - if (Energy->Settings.tariff[0][0] != Energy->Settings.tariff[1][0]) { + if (Settings->mbflag2.tariff_forced || (Energy->Settings.tariff[0][0] != Energy->Settings.tariff[1][0])) { energy_usage_kWh[0] = RtcEnergySettings.energy_usage.usage_total_kWh[0]; // Tariff1 energy_usage_kWh[1] = RtcEnergySettings.energy_usage.usage_total_kWh[1]; // Tariff2 energy_return_kWh[0] = RtcEnergySettings.energy_usage.return_total_kWh[0]; // Tariff1 @@ -1470,34 +1490,31 @@ void EnergyShow(bool json) { energy_tariff = true; } - char value_chr[GUISZ]; // Used by EnergyFormatIndex - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - if (json) { bool show_energy_period = (0 == TasmotaGlobal.tele_period); ResponseAppend_P(PSTR(",\"" D_RSLT_ENERGY "\":{\"" D_JSON_TOTAL_START_TIME "\":\"%s\",\"" D_JSON_TOTAL "\":%s"), - GetDateAndTime(DT_ENERGY).c_str(), - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + GetDT(Energy->Settings.energy_kWhtotal_time).c_str(), + EnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_usage_kWh, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_usage_kWh, Settings->flag2.energy_resolution, 6)); } - ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), - EnergyFormat(value_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), - EnergyFormat(value2_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_kWh, Settings->flag2.energy_resolution, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); /* #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP) if (!isnan(Energy->import_active[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->import_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->import_active, Settings->flag2.energy_resolution)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return_kWh, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return_kWh, Settings->flag2.energy_resolution, 6)); } } #endif // SDM630_IMPORT || SDM72_IMPEXP @@ -1505,47 +1522,51 @@ void EnergyShow(bool json) { if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 0 : 1; - ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s,\"" D_JSON_TODAY_SUM_EXPORT "\":%s,\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value2_chr, &Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1), - EnergyFormat(value3_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_IMPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_import_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY_SUM_EXPORT "\":%s"), + EnergyFmt(&Energy->daily_sum_export_balanced, Settings->flag2.energy_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); if (energy_tariff) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT D_CMND_TARIFF "\":%s"), - EnergyFormat(value_chr, energy_return_kWh, Settings->flag2.energy_resolution, 6)); + EnergyFmt(energy_return_kWh, Settings->flag2.energy_resolution, 6)); } } if (show_energy_period) { float energy_period[Energy->phase_count]; for (uint32_t i = 0; i < Energy->phase_count; i++) { - energy_period[i] = RtcEnergySettings.energy_today_kWh[i] - Energy->period_kWh[i]; + energy_period[i] = (RtcEnergySettings.energy_today_kWh[i] - Energy->period_kWh[i]) * 1000; // Wh Energy->period_kWh[i] = RtcEnergySettings.energy_today_kWh[i]; } ResponseAppend_P(PSTR(",\"" D_JSON_PERIOD "\":%s"), - EnergyFormat(value_chr, energy_period, Settings->flag2.wattage_resolution)); + EnergyFmt(energy_period, Settings->flag2.wattage_resolution)); } ResponseAppend_P(PSTR(",\"" D_JSON_POWERUSAGE "\":%s"), - EnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + EnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s,\"" D_JSON_REACTIVE_POWERUSAGE "\":%s,\"" D_JSON_POWERFACTOR "\":%s"), - EnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - EnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - EnergyFormat(value3_chr, power_factor, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_APPARENT_POWERUSAGE "\":%s"), + EnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_REACTIVE_POWERUSAGE "\":%s"), + EnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_POWERFACTOR "\":%s"), + EnergyFmt(power_factor, 2)); } if (!isnan(Energy->frequency[0])) { ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%s"), - EnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + EnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->voltage_available) { ResponseAppend_P(PSTR(",\"" D_JSON_VOLTAGE "\":%s"), - EnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + EnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (Energy->current_available) { ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT "\":%s"), - EnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + EnergyFmt(Energy->current, Settings->flag2.current_resolution)); } XnrgCall(FUNC_JSON_APPEND); ResponseJsonEnd(); @@ -1593,7 +1614,6 @@ void EnergyShow(bool json) { #endif // USE_KNX #ifdef USE_WEBSERVER } else { -#ifdef USE_ENERGY_COLUMN_GUI uint8_t relays[ENERGY_MAX_PHASES]; uint32_t relay_show = 0; power_t power = TasmotaGlobal.power; @@ -1647,49 +1667,48 @@ void EnergyShow(bool json) { // {s}")); // First column is empty ({t} =
1.23  // 1.23  // 1.23  - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f %*_f 1.23  // 1.23 1.23  // 1.23 1.23 1.23  // 1.23 1.23 1.23 1.23  for (uint32_t i = 0; i < Energy->gui_count; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%*_f %*_f "), result); -#else // not USE_ENERGY_COLUMN_GUI - uint32_t index = (single) ? 1 : Energy->phase_count; // 1,2,3 - result[0] = '\0'; - for (uint32_t i = 0; i < index; i++) { - ext_snprintf_P(result, GUISZ, PSTR("%s%s%*_f"), result, (i)?" / ":"", resolution, &input[i]); - } -#endif // USE_ENERGY_COLUMN_GUI - return result; + ext_snprintf_P(Energy->value, GUISZ, PSTR("%s"), Energy->value); + return Energy->value; } #endif // USE_WEBSERVER /********************************************************************************************/ bool EnergyTariff1Active() { // Off-Peak hours + if (Settings->mbflag2.tariff_forced) { + return 1 == Settings->mbflag2.tariff_forced; + } uint8_t dst = 0; if (IsDst() && (Energy->Settings.tariff[0][1] != Energy->Settings.tariff[1][1])) { dst = 1; @@ -710,8 +732,7 @@ void EnergyMarginCheck(void) { for (uint32_t phase = 0; phase < Energy->phase_count; phase++) { power_diff_f[phase] = power_diff[phase]; } - char value_chr[GUISZ]; - ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFormat(value_chr, power_diff_f, 0)); + ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%s"), EnergyFmt(power_diff_f, 0)); } uint16_t energy_power_u = (uint16_t)(Energy->active_power[0]); @@ -816,6 +837,7 @@ void EnergyMarginCheck(void) { SetAllPower(POWER_ALL_OFF, SRC_MAXENERGY); } } + EnergyFmtFree(); } void EnergyMqttShow(void) { @@ -878,10 +900,6 @@ void EnergyEverySecond(void) { \*********************************************************************************************/ void ResponseCmndEnergyTotalYesterdayToday(void) { - char value_chr[GUISZ]; // Used by EnergyFormatIndex - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - float energy_yesterday_kWh[3]; for (uint32_t i = 0; i < Energy->phase_count; i++) { energy_yesterday_kWh[i] = Energy->Settings.energy_yesterday_kWh[i]; @@ -891,16 +909,19 @@ void ResponseCmndEnergyTotalYesterdayToday(void) { } } - Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s,\"" D_JSON_YESTERDAY "\":%s,\"" D_JSON_TODAY "\":%s"), + Response_P(PSTR("{\"%s\":{\"" D_JSON_TOTAL "\":%s"), XdrvMailbox.command, - EnergyFormat(value_chr, Energy->total, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, Energy->daily_kWh, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->total, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_YESTERDAY "\":%s"), + EnergyFmt(energy_yesterday_kWh, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_TODAY "\":%s"), + EnergyFmt(Energy->daily_kWh, Settings->flag2.energy_resolution)); if (Energy->local_energy_active_export) { ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_ACTIVE "\":%s"), - EnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution)); + EnergyFmt(Energy->export_active, Settings->flag2.energy_resolution)); } ResponseJsonEndEnd(); + EnergyFmtFree(); } void CmndEnergyDisplay(void) { @@ -930,7 +951,7 @@ void CmndEnergyTotal(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Total - RtcEnergySettings.energy_total_kWh[phase] = (float)values[0] / 1000; + RtcEnergySettings.energy_total_kWh[phase] = (float)(int32_t)values[0] / 1000; Energy->Settings.energy_total_kWh[phase] = RtcEnergySettings.energy_total_kWh[phase]; if (params > 1) { Energy->Settings.energy_kWhtotal_time = values[1]; @@ -949,7 +970,7 @@ void CmndEnergyYesterday(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Yesterday - Energy->Settings.energy_yesterday_kWh[phase] = (float)values[0] / 1000; + Energy->Settings.energy_yesterday_kWh[phase] = (float)(int32_t)values[0] / 1000; if (params > 1) { Energy->Settings.energy_kWhtotal_time = values[1]; } @@ -965,7 +986,7 @@ void CmndEnergyToday(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Today - Energy->energy_today_offset_kWh[phase] = (float)values[0] / 1000; + Energy->energy_today_offset_kWh[phase] = (float)(int32_t)values[0] / 1000; Energy->kWhtoday[phase] = 0; Energy->kWhtoday_delta[phase] = 0; Energy->start_energy[phase] = 0; @@ -993,7 +1014,7 @@ void CmndEnergyExportActive(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Energy->phase_count) && (params > 0)) { uint32_t phase = XdrvMailbox.index -1; // Reset Energy Export Active - RtcEnergySettings.energy_export_kWh[phase] = (float)values[0] / 1000; + RtcEnergySettings.energy_export_kWh[phase] = (float)(int32_t)values[0] / 1000; Energy->Settings.energy_export_kWh[phase] = RtcEnergySettings.energy_export_kWh[phase]; if (params > 1) { Energy->Settings.energy_kWhtotal_time = values[1]; @@ -1017,9 +1038,9 @@ void CmndEnergyUsage(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.usage totals - RtcEnergySettings.energy_usage.usage_total_kWh[0] = (float)values[0] / 1000; + RtcEnergySettings.energy_usage.usage_total_kWh[0] = (float)(int32_t)values[0] / 1000; if (params > 1) { - RtcEnergySettings.energy_usage.usage_total_kWh[1] = (float)values[1] / 1000; + RtcEnergySettings.energy_usage.usage_total_kWh[1] = (float)(int32_t)values[1] / 1000; } Energy->Settings.energy_usage.usage_total_kWh[0] = RtcEnergySettings.energy_usage.usage_total_kWh[0]; Energy->Settings.energy_usage.usage_total_kWh[1] = RtcEnergySettings.energy_usage.usage_total_kWh[1]; @@ -1032,9 +1053,9 @@ void CmndEnergyExport(void) { uint32_t params = ParseParameters(2, values); if (params > 0) { // Reset energy_usage.return totals - RtcEnergySettings.energy_usage.return_total_kWh[0] = (float)values[0] / 1000; + RtcEnergySettings.energy_usage.return_total_kWh[0] = (float)(int32_t)values[0] / 1000; if (params > 1) { - RtcEnergySettings.energy_usage.return_total_kWh[1] = (float)values[1] / 1000; + RtcEnergySettings.energy_usage.return_total_kWh[1] = (float)(int32_t)values[1] / 1000; } Energy->Settings.energy_usage.return_total_kWh[0] = RtcEnergySettings.energy_usage.return_total_kWh[0]; Energy->Settings.energy_usage.return_total_kWh[1] = RtcEnergySettings.energy_usage.return_total_kWh[1]; @@ -1053,37 +1074,44 @@ void CmndTariff(void) { uint32_t tariff = XdrvMailbox.index -1; uint32_t time_type = 0; char *p; - char *str = strtok_r(XdrvMailbox.data, ", ", &p); // 23:15, 22:30 - while ((str != nullptr) && (time_type < 2)) { - char *q; - uint32_t value = strtol(str, &q, 10); // 23 or 22 - Energy->Settings.tariff[tariff][time_type] = value; - if (value < 24) { // Below 24 is hours - Energy->Settings.tariff[tariff][time_type] *= 60; // Multiply hours by 60 minutes - char *minute = strtok_r(nullptr, ":", &q); - if (minute) { - value = strtol(minute, nullptr, 10); // 15 or 30 - if (value > 59) { - value = 59; + if (POWER_OFF == XdrvMailbox.payload) + Settings->mbflag2.tariff_forced = 0; + else if (POWER_ON == XdrvMailbox.payload) + Settings->mbflag2.tariff_forced = tariff + 1; + else { + char *str = strtok_r(XdrvMailbox.data, ", ", &p); // 23:15, 22:30 + while ((str != nullptr) && (time_type < 2)) { + char *q; + uint32_t value = strtol(str, &q, 10); // 23 or 22 + Energy->Settings.tariff[tariff][time_type] = value; + if (value < 24) { // Below 24 is hours + Energy->Settings.tariff[tariff][time_type] *= 60; // Multiply hours by 60 minutes + char *minute = strtok_r(nullptr, ":", &q); + if (minute) { + value = strtol(minute, nullptr, 10); // 15 or 30 + if (value > 59) { + value = 59; + } + Energy->Settings.tariff[tariff][time_type] += value; } - Energy->Settings.tariff[tariff][time_type] += value; } + if (Energy->Settings.tariff[tariff][time_type] > 1439) { + Energy->Settings.tariff[tariff][time_type] = 1439; // Max is 23:59 + } + str = strtok_r(nullptr, ", ", &p); + time_type++; } - if (Energy->Settings.tariff[tariff][time_type] > 1439) { - Energy->Settings.tariff[tariff][time_type] = 1439; // Max is 23:59 - } - str = strtok_r(nullptr, ", ", &p); - time_type++; } } else if (XdrvMailbox.index == 9) { Settings->flag3.energy_weekend = XdrvMailbox.payload & 1; // CMND_TARIFF } - Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\"}}"), + Response_P(PSTR("{\"%s\":{\"Off-Peak\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Standard\":{\"STD\":\"%s\",\"DST\":\"%s\"},\"Weekend\":\"%s\",\"Forced\":\"%d\"}}"), XdrvMailbox.command, GetMinuteTime(Energy->Settings.tariff[0][0]).c_str(),GetMinuteTime(Energy->Settings.tariff[0][1]).c_str(), GetMinuteTime(Energy->Settings.tariff[1][0]).c_str(),GetMinuteTime(Energy->Settings.tariff[1][1]).c_str(), - GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF + GetStateText(Settings->flag3.energy_weekend), // Tariff9 + Settings->mbflag2.tariff_forced); // Tariff ON|OFF } uint32_t EnergyGetCalibration(uint32_t cal_type, uint32_t chan = 0) { @@ -1328,9 +1356,10 @@ void EnergyDrvInit(void) { Energy = (tEnergy*)calloc(sizeof(tEnergy), 1); // Need calloc to reset registers to 0/false if (!Energy) { return; } - EnergySettingsLoad(); + EnergySettingsLoad(0); EnergyRtcSettingsLoad(); + Energy->value = nullptr; // Energy->voltage_common = false; // Energy->frequency_common = false; // Energy->use_overtemp = false; @@ -1384,21 +1413,6 @@ void EnergySnsInit(void) { } } -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SNS1[] PROGMEM = - "{s}" D_POWERUSAGE_APPARENT "{m}%s " D_UNIT_VA "{e}" - "{s}" D_POWERUSAGE_REACTIVE "{m}%s " D_UNIT_VAR "{e}" - "{s}" D_POWER_FACTOR "{m}%s{e}"; - -const char HTTP_ENERGY_SNS2[] PROGMEM = - "{s}" D_ENERGY_TODAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_YESTERDAY "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_ENERGY_TOTAL "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; // {s} =
, {m} = , {e} =
Head1Head2Head3Head4{e} WSContentSend_P(PSTR("{t}{s}
, {s} = "), (no_label) ? "" : (label_o) ? "O" : "L", - (no_label) ? "" : itoa(relays[Energy->gui_offset +i], value_chr, 10)); + (no_label) ? "" : itoa(relays[Energy->gui_offset +i], number, 10)); } WSContentSend_P(PSTR(") -#endif // USE_ENERGY_COLUMN_GUI if (Energy->voltage_available) { - WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFormat(value_chr, Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); + WSContentSend_PD(HTTP_SNS_VOLTAGE, WebEnergyFmt(Energy->voltage, Settings->flag2.voltage_resolution, voltage_common)); } if (!Energy->type_dc) { if (!isnan(Energy->frequency[0])) { WSContentSend_PD(PSTR("{s}" D_FREQUENCY "{m}%s " D_UNIT_HERTZ "{e}"), - WebEnergyFormat(value_chr, Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); + WebEnergyFmt(Energy->frequency, Settings->flag2.frequency_resolution, frequency_common)); } } if (Energy->current_available) { - WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFormat(value_chr, Energy->current, Settings->flag2.current_resolution)); + WSContentSend_PD(HTTP_SNS_CURRENT, WebEnergyFmt(Energy->current, Settings->flag2.current_resolution)); } - WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFormat(value_chr, Energy->active_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWER, WebEnergyFmt(Energy->active_power, Settings->flag2.wattage_resolution)); if (!Energy->type_dc) { if (Energy->current_available && Energy->voltage_available) { - WSContentSend_PD(HTTP_ENERGY_SNS1, WebEnergyFormat(value_chr, apparent_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, reactive_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, power_factor, 2)); + WSContentSend_PD(HTTP_SNS_POWERUSAGE_APPARENT, WebEnergyFmt(apparent_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWERUSAGE_REACTIVE, WebEnergyFmt(reactive_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_POWER_FACTOR, WebEnergyFmt(power_factor, 2)); } } - WSContentSend_PD(HTTP_ENERGY_SNS2, WebEnergyFormat(value_chr, Energy->daily_kWh, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, energy_yesterday_kWh, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, Energy->total, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_ENERGY_TODAY, WebEnergyFmt(Energy->daily_kWh, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_ENERGY_YESTERDAY, WebEnergyFmt(energy_yesterday_kWh, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_ENERGY_TOTAL, WebEnergyFmt(Energy->total, Settings->flag2.energy_resolution, 2)); if (!isnan(Energy->export_active[0])) { uint32_t single = (!isnan(Energy->export_active[1]) && !isnan(Energy->export_active[2])) ? 2 : 1; - WSContentSend_PD(HTTP_ENERGY_SNS3, WebEnergyFormat(value_chr, Energy->export_active, Settings->flag2.energy_resolution, single)); + WSContentSend_PD(HTTP_SNS_EXPORT_ACTIVE, WebEnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); } -#ifdef USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_COL_SENSOR); WSContentSend_P(PSTR("
) bool no_label = (1 == Energy->phase_count); + char number[4]; for (uint32_t i = 0; i < Energy->gui_count; i++) { WSContentSend_P(PSTR("%s%s{e}")); // Last column is units ({e} =

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR -#endif // USE_ENERGY_COLUMN_GUI XnrgCall(FUNC_WEB_SENSOR); #endif // USE_WEBSERVER } } + EnergyFmtFree(); } #ifdef USE_WEBSERVER @@ -1730,6 +1749,9 @@ bool Xdrv03(uint32_t function) case FUNC_SERIAL: result = XnrgCall(FUNC_SERIAL); break; + case FUNC_RESET_SETTINGS: + EnergySettingsLoad(1); + break; case FUNC_SAVE_SETTINGS: EnergySettingsSave(); EnergyRtcSettingsSave(); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino index bbad6d364..c8d728b7d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino @@ -1116,17 +1116,17 @@ bool LightModuleInit(void) #endif // USE_PWM_DIMMER if (TasmotaGlobal.light_type > LT_BASIC) { - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); } // post-process for lights uint32_t pwm_channels = (TasmotaGlobal.light_type & 7) > LST_MAX ? LST_MAX : (TasmotaGlobal.light_type & 7); if (Settings->flag3.pwm_multi_channels) { // SetOption68 - Enable multi-channels PWM instead of Color PWM if (0 == pwm_channels) { pwm_channels = 1; } - TasmotaGlobal.devices_present += pwm_channels - 1; // add the pwm channels controls at the end + UpdateDevicesPresent(pwm_channels - 1); // add the pwm channels controls at the end } else if ((Settings->param[P_RGB_REMAP] & 128) && (LST_RGBW <= pwm_channels)) { // SetOption37 // if RGBW or RGBCW, and SetOption37 >= 128, we manage RGB and W separately, hence adding a device - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); } else { #ifdef USE_LIGHT_VIRTUAL_CT initCTRange(pwm_channels); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino index d8ad9eed2..8fe9f2d50 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino @@ -1174,7 +1174,7 @@ bool RulesMqttData(void) { event_item = subscriptions.get(index); //AddLog(LOG_LEVEL_DEBUG, PSTR("RUL: Match MQTT message Topic %s with subscription topic %s"), sTopic.c_str(), event_item.Topic.c_str()); - if (sTopic.startsWith(event_item.Topic)) { + if ((sTopic == event_item.Topic) || sTopic.startsWith(event_item.Topic+"/")) { //This topic is subscribed by us, so serve it serviced = true; String value; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino index 76bf4f07b..076989292 100755 --- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino @@ -43,7 +43,14 @@ keywords if then else endif, or, and are better readable for beginners (others m #define XDRV_10 10 -const uint8_t SCRIPT_VERS[2] = {5, 0}; +#ifndef TS_FLOAT +#define TS_FLOAT float +#endif + + +// float = 4, double = 8 bytes + +const uint8_t SCRIPT_VERS[2] = {5, 1}; #define SCRIPT_DEBUG 0 @@ -76,17 +83,19 @@ const uint8_t SCRIPT_VERS[2] = {5, 0}; #endif #define MAX_SCRIPT_CMDBUFFER 4096 +#define SPI_FLASH_2SEC_SIZE SPI_FLASH_SEC_SIZE*2 #define SCRIPT_EOL '\n' #define SCRIPT_FLOAT_PRECISION 2 #define PMEM_SIZE sizeof(Settings->script_pram) -#define SCRIPT_MAXPERM (PMEM_SIZE)-4/sizeof(float) +#define SCRIPT_MAXPERM (PMEM_SIZE)-4/sizeof(TS_FLOAT) #define MAX_SCRIPT_SIZE MAX_RULE_SIZE*MAX_RULE_SETS #ifndef MAX_SARRAY_NUM #define MAX_SARRAY_NUM 32 #endif +int32_t fast_mux(uint32_t flag, uint32_t time, TS_FLOAT *buf, uint32_t len); void Draw_jpeg(uint8_t *mem, uint16_t jpgsize, uint16_t xp, uint16_t yp, uint8_t scale); uint32_t EncodeLightId(uint8_t relay_id); uint32_t DecodeLightId(uint32_t hue_id); @@ -117,8 +126,12 @@ char *Get_esc_char(char *cp, char *esc_chr); #pragma message "script 24c256 file option used" #else -#if EEP_SCRIPT_SIZE==SPECIAL_EEPMODE_SIZE +#if EEP_SCRIPT_SIZE==SPECIAL_EEPMODE_SIZE || EEP_SCRIPT_SIZE==SPI_FLASH_2SEC_SIZE +#if EEP_SCRIPT_SIZE==SPI_FLASH_2SEC_SIZE +#pragma message "internal special flash script buffer used" +#else #pragma message "internal compressed eeprom script buffer used" +#endif #else #error "unsupported eeprom option used" #endif @@ -203,23 +216,33 @@ extern uint8_t sml_options; uint32_t eeprom_block; -// these support only one 4 k block below EEPROM this steals 4k of application area +// these support only one 4 k block below EEPROM (eeprom @0x402FB000) this steals 4k of application area uint32_t alt_eeprom_init(uint32_t size) { //EEPROM.begin(size); //eeprom_block = (uint32_t)&_EEPROM_start - 0x40200000 - SPI_FLASH_SEC_SIZE; +#if EEP_SCRIPT_SIZE==SPI_FLASH_2SEC_SIZE + eeprom_block = SPEC_SCRIPT_FLASH - SPI_FLASH_SEC_SIZE; + //eeprom_block = SPEC_SCRIPT_FLASH; +#else eeprom_block = SPEC_SCRIPT_FLASH; +#endif return 1; } void alt_eeprom_writeBytes(uint32_t adr, uint32_t len, uint8_t *buf) { uint32_t *lwp = (uint32_t*)buf; +#if EEP_SCRIPT_SIZE==SPI_FLASH_2SEC_SIZE + ESP.flashEraseSector(eeprom_block / SPI_FLASH_SEC_SIZE); + ESP.flashEraseSector((eeprom_block + SPI_FLASH_SEC_SIZE) / SPI_FLASH_SEC_SIZE); +#else ESP.flashEraseSector(eeprom_block / SPI_FLASH_SEC_SIZE); - ESP.flashWrite(eeprom_block , lwp, SPI_FLASH_SEC_SIZE); +#endif + ESP.flashWrite(eeprom_block , lwp, len); } void alt_eeprom_readBytes(uint32_t adr, uint32_t len, uint8_t *buf) { uint32_t *lwp = (uint32_t*)buf; - ESP.flashRead(eeprom_block , lwp, SPI_FLASH_SEC_SIZE); + ESP.flashRead(eeprom_block, lwp, len); } #endif // EEP_SCRIPT_SIZE @@ -241,7 +264,7 @@ void alt_eeprom_readBytes(uint32_t adr, uint32_t len, uint8_t *buf) { #include #ifdef TESLA_POWERWALL -#include "powerwall.h" +#include "include/powerwall.h" #endif #ifdef USE_DISPLAY_DUMP @@ -293,11 +316,7 @@ extern VButton *buttons[MAX_TOUCH_BUTTONS]; #endif typedef union { -#if defined(USE_SCRIPT_GLOBVARS) || defined(USE_HOMEKIT) uint16_t data; -#else - uint8_t data; -#endif struct { uint8_t is_string : 1; // string or number uint8_t is_permanent : 1; @@ -307,12 +326,9 @@ typedef union { uint8_t settable : 1; uint8_t is_filter : 1; uint8_t constant : 1; -#ifdef USE_SCRIPT_GLOBVARS uint8_t global : 1; -#endif -#ifdef USE_SCRIPT_GLOBVARS uint8_t hchanged : 1; -#endif + uint8_t integer : 1; }; } SCRIPT_TYPE; @@ -329,8 +345,8 @@ struct M_FILT { uint8_t numvals; uint8_t index; #endif // LARGE_ARRAYS - float maccu; - float rbuff[1]; + TS_FLOAT maccu; + TS_FLOAT rbuff[1]; }; @@ -426,8 +442,8 @@ struct SCRIPT_SPI { #define SFS_MAX 4 // global memory struct SCRIPT_MEM { - float *fvars; // number var pointer - float *s_fvars; // shadow var pointer + TS_FLOAT *fvars; // number var pointer + TS_FLOAT *s_fvars; // shadow var pointer struct T_INDEX *type; // type and index pointer struct M_FILT *mfilt; char *glob_vnp; // var name pointer @@ -484,7 +500,7 @@ struct SCRIPT_MEM { uint32_t script_lastmillis; bool event_handeled = false; #ifdef USE_BUTTON_EVENT - int8_t script_button[MAX_KEYS_SET]; + int8_t script_button[MAX_KEYS]; #endif //USE_BUTTON_EVENT #ifdef USE_HOMEKIT @@ -494,7 +510,7 @@ struct SCRIPT_MEM { #ifdef USE_SCRIPT_SERIAL TasmotaSerial *sp; #endif - float retval; + TS_FLOAT retval; char *retstr; #ifdef USE_SCRIPT_SPI struct SCRIPT_SPI spi; @@ -511,12 +527,16 @@ struct SCRIPT_MEM { uint8_t tasm_cmd_activ = 0; +void flt2char(TS_FLOAT num, char *nbuff); -void flt2char(float num, char *nbuff) { +void flt2char(TS_FLOAT num, char *nbuff) { dtostrfd(num, glob_script_mem.script_dprec, nbuff); } + +void f2char(TS_FLOAT num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep); + // convert float to char with leading zeros -void f2char(float num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep) { +void f2char(TS_FLOAT num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep) { dtostrfd(num, dprec, nbuff); if (lzeros > 1) { // check leading zeros @@ -548,9 +568,10 @@ void f2char(float num, uint32_t dprec, uint32_t lzeros, char *nbuff, char dsep) } } - +uint32_t match_vars(char *dvnam, TS_FLOAT **fp, char **sp, uint32_t *ind); +uint32_t script_sspi_trans(int32_t cs_index, TS_FLOAT *array, uint32_t len, uint32_t size); char *scripter_sub(char *lp, uint8_t fromscriptcmd); -char *GetNumericArgument(char *lp,uint8_t lastop,float *fp, struct GVARS *gv); +char *GetNumericArgument(char *lp,uint8_t lastop,TS_FLOAT *fp, struct GVARS *gv); char *GetStringArgument(char *lp,uint8_t lastop,char *cp, struct GVARS *gv); char *ForceStringVar(char *lp,char *dstr); void send_download(void); @@ -559,20 +580,20 @@ uint8_t UfsReject(char *name); void fread_str_fp(File *fp, char *sp, uint16_t slen, uint16_t flg); int32_t script_copy_file(File *source, File *dest, uint32_t sf_from, uint32_t sf_to, uint32_t flag, WiFiClient *client); int32_t opt_fext(File *fp, char *ts_from, char *ts_to, uint32_t flg); -int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, float **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum); +int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, TS_FLOAT **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum); #endif -char *eval_sub(char *lp, float *fvar, char *rstr); +char *eval_sub(char *lp, TS_FLOAT *fvar, char *rstr); void ScriptEverySecond(void) { if (bitRead(Settings->rule_enabled, 0)) { struct T_INDEX *vtp = glob_script_mem.type; - float delta = (millis() - glob_script_mem.script_lastmillis) / 1000.0; + TS_FLOAT delta = (millis() - glob_script_mem.script_lastmillis) / 1000.0; glob_script_mem.script_lastmillis = millis(); for (uint8_t count=0; count0) { // decrement *fp -= delta; @@ -581,7 +602,7 @@ void ScriptEverySecond(void) { } if (vtp[count].bits.is_autoinc) { // increments timers - float *fp = &glob_script_mem.fvars[vtp[count].index]; + TS_FLOAT *fp = &glob_script_mem.fvars[vtp[count].index]; if (*fp>=0) { *fp += delta; } @@ -618,7 +639,39 @@ void SetChanged(uint32_t index) { #define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++; #define SCRIPT_SKIP_EOL while (*lp == SCRIPT_EOL) lp++; -float *Get_MFAddr(uint8_t index, uint16_t *len, uint16_t *ipos); +TS_FLOAT *Get_MFAddr(uint8_t index, uint16_t *len, uint16_t *ipos); + +uint32_t Script_Find_Vars(char *sp) { + uint16_t numvars = 0; + uint16_t svars = 0; + while (*sp) { + if (*sp == '\n' || *sp == '\r') { + sp++; + while (*sp == '=') { + sp++; + } + if (*sp == '#' || *sp == '>') { + break; + } + char *cp = strchr(sp, '='); + if (cp) { + cp++; + while (*cp == ' ') { + cp++; + } + if (*cp == '"') { + svars += 1; + } else if (isdigit(*cp) || *cp == '-') { + numvars += 1; + } + sp = cp; + } + } + sp++; + } + return (svars << 16) | numvars; +} + // allocates all variables and presets them int16_t Init_Scripter(void) { @@ -628,38 +681,43 @@ char *script; script = glob_script_mem.script_ram; if (!*script) return -999; + uint32_t xvars = Script_Find_Vars(script + 1); + uint16_t maxnvars = xvars & 0xffff; + if (maxnvars < 1) { + maxnvars = 1; + } + uint16_t maxsvars = xvars >> 16; + if (maxsvars < 1) { + maxsvars = 1; + } + uint16_t maxvars = maxsvars + maxnvars; + //AddLog(LOG_LEVEL_INFO, PSTR("Script: svar = %d, nvars = %d"), maxsvars, maxnvars); + // scan lines for >DEF uint16_t lines = 0; uint16_t nvars = 0; uint16_t svars = 0; uint16_t vars = 0; char *lp = script; - uint16_t imemsize = (MAXVARS*10) + 4; + uint16_t imemsize = (maxvars * 10) + 4; uint8_t *imemptr = (uint8_t*)calloc(imemsize, 1); if (!imemptr) { return -7; } - //ClaimSerial(); - //SetSerialBaudrate(115200); - //Serial.printf("size %d\n",imemsize); - //Serial.printf("stack %d\n",GetStack()); // 2848 - // 2896 - //char vnames[MAXVARS*10]; char *vnames = (char*)imemptr; - char *vnp[MAXVARS]; - float fvalues[MAXVARS]; - struct T_INDEX vtypes[MAXVARS]; - + char *vnp[maxvars]; + TS_FLOAT fvalues[maxvars]; + struct T_INDEX vtypes[maxvars]; //char strings[MAXSVARS*SCRIPT_MAXSSIZE]; //char *strings_p = strings; - char *strings_op = (char*)calloc(MAXSVARS*SCRIPT_MAXSSIZE, 1); + char *strings_op = (char*)calloc(maxsvars * SCRIPT_MAXSSIZE, 1); char *strings_p = strings_op; if (!strings_op) { free(imemptr); - return -7; + return -8; } /* @@ -674,9 +732,9 @@ char *script; imemp = (imemp & 0xfffc) + 4; Serial.printf(">2 %x\n",imemp); - float fvalues[MAXVARS]; - //float *fvalues = (float*)imemp; - imemp += (sizeof(float*)*MAXVARS); + TS_FLOAT fvalues[MAXVARS]; + //TS_FLOAT *fvalues = (TS_FLOAT*)imemp; + imemp += (sizeof(TS_FLOAT*)*MAXVARS); imemp = (imemp & 0xfffc) + 4; Serial.printf(">3 %x\n",imemp); @@ -687,7 +745,7 @@ char *script; char *vnames_p = vnames; char **vnp_p = vnp; - char *snp[MAXSVARS]; + char *snp[maxsvars]; struct M_FILT mfilt[MAXFILT]; @@ -705,12 +763,12 @@ char *script; // skip leading spaces SCRIPT_SKIP_SPACES // skip empty line - if (*lp=='\n' || *lp=='\r') goto next_line; + if (*lp == '\n' || *lp == '\r') goto next_line; // skip comment - if (*lp==';') goto next_line; + if (*lp == ';') goto next_line; if (init) { // init section - if (*lp=='>' || !*lp) { + if (*lp == '>' || !*lp) { init = 0; break; } @@ -718,22 +776,22 @@ char *script; if (op) { vtypes[vars].bits.data = 0; // found variable definition - if (*lp=='p' && *(lp+1)==':') { + if (*lp == 'p' && *(lp + 1) == ':') { lp += 2; - if (numpermMAXFILT) { + if (numflt > MAXFILT) { if (imemptr) free(imemptr); if (strings_op) free(strings_op); return -6; @@ -773,6 +837,7 @@ char *script; } else { vtypes[vars].bits.is_filter = 0; } + *vnp_p++ = vnames_p; while (lp < op) { *vnames_p++ = *lp++; @@ -780,19 +845,30 @@ char *script; *vnames_p++ = 0; // init variable op++; - if (*op!='"') { - float fv; - if (*op=='0' && *(op+1)=='x') { + while (*op == ' ') { + op++; + } + if (*op != '"') { + TS_FLOAT fv; + if (*op == '0' && *(op + 1) == 'x') { op += 2; - fv=strtol(op, &op, 16); + if (vtypes[vars].bits.integer) { + *(uint32_t*)&fv = strtoll(op, &op, 16); + } else { + fv = strtol(op, &op, 16); + } } else { - fv=CharToFloat(op); + if (vtypes[vars].bits.integer) { + *(int32_t*)&fv = strtol(op, &op, 10); + } else { + fv=CharToFloat(op); + } } fvalues[nvars] = fv; vtypes[vars].bits.is_string = 0; if (!vtypes[vars].bits.is_filter) vtypes[vars].index = nvars; nvars++; - if (nvars>MAXNVARS) { + if (nvars > maxnvars) { if (imemptr) free(imemptr); if (strings_op) free(strings_op); return -1; @@ -809,8 +885,8 @@ char *script; // limit array size flen = MAX_ARRAY_SIZE; } - mfilt[numflt-1].numvals &= OR_FILT_MASK; - mfilt[numflt-1].numvals |= flen & AND_FILT_MASK; + mfilt[numflt - 1].numvals &= OR_FILT_MASK; + mfilt[numflt - 1].numvals |= flen & AND_FILT_MASK; } } @@ -829,14 +905,14 @@ char *script; vtypes[vars].bits.is_string = 1; vtypes[vars].index = svars; svars++; - if (svars>MAXSVARS) { + if (svars > maxsvars) { if (imemptr) free(imemptr); if (strings_op) free(strings_op); return -2; } } vars++; - if (vars>MAXVARS) { + if (vars > maxvars) { if (imemptr) free(imemptr); if (strings_op) free(strings_op); return -3; @@ -847,8 +923,8 @@ char *script; lp += 2; SCRIPT_SKIP_SPACES if (isdigit(*lp)) { - uint8_t ssize = atoi(lp)+1; - if (ssize<10 || ssize>SCRIPT_MAXSSIZE) ssize=SCRIPT_MAXSSIZE; + uint8_t ssize = atoi(lp) + 1; + if (ssize < 10 || ssize > SCRIPT_MAXSSIZE) ssize = SCRIPT_MAXSSIZE; glob_script_mem.max_ssize = ssize; } init = 1; @@ -862,15 +938,15 @@ char *script; } uint16_t fsize = 0; - for (count=0; countnumvals = mfilt[count].numvals; - mp += sizeof(struct M_FILT) + ((mfilt[count].numvals & AND_FILT_MASK) - 1) * sizeof(float); + mp += sizeof(struct M_FILT) + ((mfilt[count].numvals & AND_FILT_MASK) - 1) * sizeof(TS_FLOAT); } glob_script_mem.numvars = vars; @@ -1008,19 +1084,22 @@ char *script; #if SCRIPT_DEBUG>2 struct T_INDEX *dvtp = glob_script_mem.type; - for (uint8_t count = 0; count", 2)) { lp += 2; char *cp=strchr(lp, '='); if (cp) { char vnam[32]; for (uint32_t count = 0; countrbuff[cnt]; } return summ / maxind; } + if (bind == -3) { + TS_FLOAT summ = 0; + for (uint32_t cnt = 0; cnt < maxind; cnt++) { + summ += mflp->rbuff[cnt]; + } + return summ; + } if (bind < -2 || bind > maxind ) bind = 1; return mflp->rbuff[bind - 1]; } - mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(float); + mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(TS_FLOAT); } return 0; } - -void Set_MFVal(uint8_t index, uint16_t bind, float val) { +void Set_MFVal(uint8_t index, uint16_t bind, TS_FLOAT val); +void Set_MFVal(uint8_t index, uint16_t bind, TS_FLOAT val) { uint8_t *mp = (uint8_t*)glob_script_mem.mfilt; for (uint8_t count = 0; count < MAXFILT; count++) { struct M_FILT *mflp = (struct M_FILT*)mp; @@ -1385,12 +1476,12 @@ void Set_MFVal(uint8_t index, uint16_t bind, float val) { } return; } - mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(float); + mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(TS_FLOAT); } } - -float Get_MFilter(uint8_t index) { +TS_FLOAT Get_MFilter(uint8_t index); +TS_FLOAT Get_MFilter(uint8_t index) { uint8_t *mp = (uint8_t*)glob_script_mem.mfilt; for (uint8_t count = 0; count < MAXFILT; count++) { struct M_FILT *mflp = (struct M_FILT*)mp; @@ -1403,12 +1494,12 @@ float Get_MFilter(uint8_t index) { return median_array(mflp->rbuff, mflp->numvals); } } - mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(float); + mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(TS_FLOAT); } return 0; } - -void Set_MFilter(uint8_t index, float invar) { +void Set_MFilter(uint8_t index, TS_FLOAT invar); +void Set_MFilter(uint8_t index, TS_FLOAT invar) { uint8_t *mp = (uint8_t*)glob_script_mem.mfilt; for (uint8_t count = 0; countnumvals & AND_FILT_MASK) - 1) * sizeof(float); + mp += sizeof(struct M_FILT) + ((mflp->numvals & AND_FILT_MASK) - 1) * sizeof(TS_FLOAT); } } @@ -1436,11 +1527,11 @@ void Set_MFilter(uint8_t index, float invar) { #define MEDIAN_FILTER_NUM 2 struct MEDIAN_FILTER { -float buffer[MEDIAN_SIZE]; +TS_FLOAT buffer[MEDIAN_SIZE]; int8_t index; } script_mf[MEDIAN_FILTER_NUM]; - -float DoMedian5(uint8_t index, float in) { +TS_FLOAT DoMedian5(uint8_t index, TS_FLOAT in); +TS_FLOAT DoMedian5(uint8_t index, TS_FLOAT in) { if (index >= MEDIAN_FILTER_NUM) index = 0; @@ -1673,10 +1764,10 @@ int32_t opt_fext(File *fp, char *ts_from, char *ts_to, uint32_t flg) { fread_str_fp(fp, tsf, sizeof(tsf), 0); uint32_t tssiz = tstamp2l(tsf) - ltsf; uint32_t tspos = tstamp2l(ts_from) - ltsf; - float perc = (float)tspos / (float)tssiz * 0.8; + TS_FLOAT perc = (TS_FLOAT)tspos / (TS_FLOAT)tssiz * 0.8; if (perc < 0) perc = 0; if (perc > 1) perc = 1; - float fsize = fp->size(); + TS_FLOAT fsize = fp->size(); uint32_t spos = perc * fsize; //AddLog(LOG_LEVEL_INFO,PSTR(">>> 1 %d, %d"), (uint32_t)perc, spos); fp->seek(spos, SeekSet); @@ -1695,7 +1786,7 @@ int32_t opt_fext(File *fp, char *ts_from, char *ts_to, uint32_t flg) { // assume 1. entry is timestamp, others are tab delimited values until LF // file reference, from timestamp, to timestampm, column offset, array pointers, array lenght, number of arrays -int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, float **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum) { +int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, TS_FLOAT **a_ptr, uint16_t *a_len, uint8_t numa, int16_t accum) { char rstr[32]; uint8_t sindex = 0; @@ -1770,8 +1861,8 @@ int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, f //AddLog(LOG_LEVEL_INFO, PSTR("from: %d to: %d"),tsfrom, tsto); uint16_t lines = 0; uint16_t rlines = 0; - float summs[numa]; - float lastv[numa]; + TS_FLOAT summs[numa]; + TS_FLOAT lastv[numa]; uint16_t accnt[numa]; uint8_t mflg[numa]; uint32_t lastpos = 0; @@ -1831,7 +1922,7 @@ int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, f uint8_t curpos = colpos - coffs; if (colpos >= coffs && curpos < numa) { if (a_len[curpos]) { - float fval = CharToFloat(rstr); + TS_FLOAT fval = CharToFloat(rstr); uint8_t flg = 1; if ((mflg[curpos] & 1) == 1) { // absolute values, build diffs @@ -1841,7 +1932,7 @@ int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, f flg = 0; } else { if (!(mflg[curpos] & 2)) { - float tmp = fval; + TS_FLOAT tmp = fval; fval -= lastv[curpos]; // must be positive value #ifndef EXTRACT_DIFF_NOCHK @@ -1890,6 +1981,7 @@ int32_t extract_from_file(File *fp, char *ts_from, char *ts_to, int8_t coffs, f #endif // USE_FEXTRACT #endif // USE_UFILESYS + uint32_t script_bcd(uint8_t sel, uint32_t val) { uint32_t res = 0; if (sel) { @@ -1924,18 +2016,19 @@ uint8_t script_hexnibble(char chr) { return rVal; } + #ifdef USE_LIGHT uint32_t HSVToRGB(uint16_t hue, uint8_t saturation, uint8_t value) { -float r = 0, g = 0, b = 0; +TS_FLOAT r = 0, g = 0, b = 0; struct HSV { - float H; - float S; - float V; + TS_FLOAT H; + TS_FLOAT S; + TS_FLOAT V; } hsv; hsv.H = hue; -hsv.S = (float)saturation / 100.0; -hsv.V = (float)value / 100.0; +hsv.S = (TS_FLOAT)saturation / 100.0; +hsv.V = (TS_FLOAT)value / 100.0; if (hsv.S == 0) { r = hsv.V; @@ -1943,7 +2036,7 @@ if (hsv.S == 0) { b = hsv.V; } else { int i; - float f, p, q, t; + TS_FLOAT f, p, q, t; if (hsv.H == 360) hsv.H = 0; @@ -2169,16 +2262,16 @@ uint32_t MeasurePulseTime(int32_t in) { #endif // USE_ANGLE_FUNC #ifdef USE_SCRIPT_GLOBVARS -uint32_t match_vars(char *dvnam, float **fp, char **sp, uint32_t *ind) { +uint32_t match_vars(char *dvnam, TS_FLOAT **fp, char **sp, uint32_t *ind) { uint16_t olen = strlen(dvnam); struct T_INDEX *vtp = glob_script_mem.type; - for (uint32_t count = 0; count ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number // no flash strings here for performance reasons!!! -char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, float *fp, char *sp, struct GVARS *gv) { - uint16_t count,len = 0; +char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, TS_FLOAT *fp, char *sp, struct GVARS *gv); +char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, TS_FLOAT *fp, char *sp, struct GVARS *gv) { + uint16_t count, len = 0; uint8_t nres = 0; char vname[64]; - float fvar = 0; + TS_FLOAT fvar = 0; tind->index = 0; tind->bits.data = 0; //Serial.printf("Stack 2: %d\n",GetStack()); - if (isdigit(*lp) || (*lp == '-' && isdigit(*(lp+1))) || *lp == '.') { + + if ( (*lp == '#') && (*(lp + 1) == '-' || isdigit(*(lp + 1))) ) { + // 32 bit integer + lp++; + if (fp) { + if (*lp == '0' && *(lp + 1) == 'x') { + lp += 2; + *(uint32_t*)fp = strtoll(lp, &lp, 16); + } else { + *(int32_t*)fp = strtoll(lp, &lp, 10); + } + } + tind->bits.constant = 1; + tind->bits.is_string = 0; + tind->bits.integer = 1; + *vtype = NUM_RES; + return lp; + } + + if (isdigit(*lp) || (*lp == '-' && isdigit(*(lp + 1))) || *lp == '.') { // isnumber if (fp) { if (*lp == '0' && *(lp + 1) == 'x') { lp += 2; - *fp = strtol(lp, &lp, 16); + *fp = strtoll(lp, &lp, 16); } else { *fp = CharToFloat(lp); if (*lp == '-') lp++; @@ -2399,11 +2527,11 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, float *fp, char *sp, uint8_t slen = strlen(cp); if (slen == olen && *cp == dvnam[0]) { if (!strncmp(cp, dvnam, olen)) { - uint8_t index = vtp[count].index; + uint16_t index = vtp[count].index; *tind = vtp[count]; tind->index = count; // overwrite with global var index if (vtp[count].bits.is_string == 0) { - *vtype = NTYPE | index; + *vtype = NTYPE; // | index; if (vtp[count].bits.is_filter) { if (ja) { lp += olen + 1; @@ -2422,7 +2550,7 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, float *fp, char *sp, if (nres) fvar = -fvar; if (fp) *fp = fvar; } else { - *vtype = STYPE|index; + *vtype = STYPE; //|index; if (sp) strlcpy(sp, glob_script_mem.glob_snp + (index * glob_script_mem.max_ssize), SCRIPT_MAXSSIZE); } return lp + len; @@ -2441,7 +2569,7 @@ char *isvar(char *lp, uint8_t *vtype, struct T_INDEX *tind, float *fp, char *sp, // epoch offset missing in this version char str_value[SCRIPT_MAXSSIZE]; str_value[0]=0; - float fv; + TS_FLOAT fv; uint32_t res = JsonParsePath(gv->jo, vname, '#', &fv, str_value, sizeof(str_value)); if (!res) { goto chknext; @@ -2456,10 +2584,10 @@ nexit: return lp + len; } else { // string - if (!strncmp(str_value, "ON", 2)) { + if (!strncmp_XP(str_value, XPSTR("ON"), 2)) { if (fp) *fp = 1; goto nexit; - } else if (!strncmp(str_value, "OFF", 3)) { + } else if (!strncmp_XP(str_value, XPSTR("OFF"), 3)) { if (fp) *fp = 0; goto nexit; } else { @@ -2484,7 +2612,7 @@ nexit: *ja = 0; ja++; // fetch array index - float fvar; + TS_FLOAT fvar; GetNumericArgument(ja, OPER_EQU, &fvar, 0); aindex = fvar; if (aindex<1 || aindex>6) aindex = 1; @@ -2542,10 +2670,10 @@ nexit: } if (str_value && *str_value) { if ((*jpo)[vn].isStr()) { - if (!strncmp(str_value, "ON", 2)) { + if (!strncmp_XP(str_value, XPSTR("ON"), 2)) { if (fp) *fp = 1; goto nexit; - } else if (!strncmp(str_value, "OFF", 3)) { + } else if (!strncmp_XP(str_value, XPSTR("OFF"), 3)) { if (fp) *fp = 0; goto nexit; } else { @@ -2558,7 +2686,7 @@ nexit: } else { if (fp) { - if (!strncmp(vn.c_str(), "Epoch", 5)) { + if (!strncmp_XP(vn.c_str(), XPSTR("Epoch"), 5)) { *fp = atoi(str_value) - (uint32_t)glob_script_mem.epoch_offset; } else { *fp = CharToFloat((char*)str_value); @@ -2586,28 +2714,28 @@ chknext: case 'a': #ifdef USE_ANGLE_FUNC - if (!strncmp(lp, "acos(", 5)) { + if (!strncmp_XP(lp, XPSTR("acos("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); fvar = acosf(fvar); goto nfuncexit; } #endif - if (!strncmp(lp, "abs(", 4)) { + if (!strncmp_XP(lp, XPSTR("abs("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = fabs(fvar); goto nfuncexit; } - if (!strncmp(lp, "asc(", 4)) { + if (!strncmp_XP(lp, XPSTR("asc("), 4)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, gv); fvar = str[0]; goto nfuncexit; } - if (!strncmp(lp, "adc(", 4)) { + if (!strncmp_XP(lp, XPSTR("adc("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); while (*lp==' ') lp++; - float pin = 1; + TS_FLOAT pin = 1; if (*lp!=')') { lp = GetNumericArgument(lp, OPER_EQU, &pin, gv); #ifdef CONFIG_IDF_TARGET_ESP32S3 @@ -2630,37 +2758,37 @@ chknext: #ifndef USE_ADC_VCC fvar = AdcRead(17, fvar); #else - fvar = (float)ESP.getVcc() / 1000.0; + fvar = (TS_FLOAT)ESP.getVcc() / 1000.0; #endif // USE_ADC_VCC #endif // ESP32 len = 0; goto exit; } - if (!strncmp(lp, "acp(", 4)) { + if (!strncmp_XP(lp, XPSTR("acp("), 4)) { lp += 4; SCRIPT_SKIP_SPACES uint16_t alend; fvar = -1; - float *fpd; + TS_FLOAT *fpd; lp = get_array_by_name(lp, &fpd, &alend, 0); SCRIPT_SKIP_SPACES uint16_t alens; - float *fps; + TS_FLOAT *fps; lp = get_array_by_name(lp, &fps, &alens, 0); SCRIPT_SKIP_SPACES if (alens < alend) { alend = alens; } - memcpy(fpd, fps, alend * sizeof(float)); + memcpy(fpd, fps, alend * sizeof(TS_FLOAT)); fvar = alend; goto nfuncexit; } - if (!strncmp(lp, "af(", 3)) { + if (!strncmp_XP(lp, XPSTR("af("), 3)) { // array to float uint16_t alend; - float *fpd; + TS_FLOAT *fpd; lp = get_array_by_name(lp + 3, &fpd, &alend, 0); SCRIPT_SKIP_SPACES if (*lp != ')') { @@ -2678,14 +2806,14 @@ chknext: fbytes[1] = *fpd++; fbytes[2] = *fpd++; fbytes[3] = *fpd++; - fpd = (float*)fbytes; + fpd = (TS_FLOAT*)fbytes; fvar = *fpd; } else { fvar = 0; } goto nfuncexit; } - if (!strncmp(lp, "ap(", 3)) { + if (!strncmp_XP(lp, XPSTR("ap("), 3)) { //TasmotaGlobal.restart_flag = 216; lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); switch ((uint8_t)fvar) { @@ -2719,7 +2847,7 @@ chknext: break; case 'b': - if (!strncmp(vname, "boot", 4)) { + if (!strncmp_XP(vname, XPSTR("boot"), 4)) { if (TasmotaGlobal.rules_flag.system_boot) { TasmotaGlobal.rules_flag.system_boot = 0; fvar = 1; @@ -2727,17 +2855,17 @@ chknext: goto exit; } #ifdef USE_BUTTON_EVENT - if (!strncmp(lp, "bt[", 3)) { + if (!strncmp_XP(lp, XPSTR("bt["), 3)) { // tasmota button state lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint32_t index = fvar; - if (index<1 || index>MAX_KEYS_SET) index = 1; + if (index<1 || index>MAX_KEYS) index = 1; fvar = glob_script_mem.script_button[index - 1]; glob_script_mem.script_button[index - 1] |= 0x80; goto nfuncexit; } #endif //USE_BUTTON_EVENT - if (!strncmp(lp, "bcd(", 4)) { + if (!strncmp_XP(lp, XPSTR("bcd("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); uint32_t sel = fvar; while (*lp==' ') lp++; @@ -2745,9 +2873,21 @@ chknext: fvar = script_bcd(sel, fvar); goto nfuncexit; } + +#ifdef USE_FLASH_BDIR + if (!strncmp_XP(lp, XPSTR("bdir("), 5)) { + lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); + char str[SCRIPT_MAXSSIZE]; + if (fvar > 1) { + lp = GetStringArgument(lp, OPER_EQU, str, 0); + } + fvar = flash_bindir(fvar, str); + goto nfuncexit; + } +#endif // USE_FLASH_BDIR break; case 'c': - if (!strncmp(lp, "chg[", 4)) { + if (!strncmp_XP(lp, XPSTR("chg["), 4)) { // var changed struct T_INDEX ind; uint8_t vtype; @@ -2762,15 +2902,15 @@ chknext: goto nfuncexit; } #ifdef ESP32 - if (!strncmp(vname, "core", 4)) { + if (!strncmp_XP(vname, XPSTR("core"), 4)) { fvar = xPortGetCoreID(); goto exit; } #ifdef USE_M5STACK_CORE2 - if (!strncmp(lp, "c2ps(", 5)) { + if (!strncmp_XP(lp, XPSTR("c2ps("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); while (*lp==' ') lp++; - float fvar1; + TS_FLOAT fvar1; lp = GetNumericArgument(lp, OPER_EQU, &fvar1, gv); fvar = Core2SetAxpPin(fvar, fvar1); goto nfuncexit; @@ -2778,21 +2918,21 @@ chknext: #endif // USE_M5STACK_CORE2 #ifdef USE_SCRIPT_TASK - if (!strncmp(lp, "ct(", 3)) { + if (!strncmp_XP(lp, XPSTR("ct("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); while (*lp==' ') lp++; - float fvar1; + TS_FLOAT fvar1; lp = GetNumericArgument(lp, OPER_EQU, &fvar1, gv); while (*lp==' ') lp++; - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); SCRIPT_SKIP_SPACES - float prio = STASK_PRIO; + TS_FLOAT prio = STASK_PRIO; if (*lp!=')') { lp = GetNumericArgument(lp, OPER_EQU, &prio, gv); } SCRIPT_SKIP_SPACES - float stack = STASK_STACK; + TS_FLOAT stack = STASK_STACK; if (*lp!=')') { lp = GetNumericArgument(lp, OPER_EQU, &stack, gv); } @@ -2803,14 +2943,19 @@ chknext: #endif //ESP32 #ifdef USE_ANGLE_FUNC - if (!strncmp(lp, "cos(", 4)) { + if (!strncmp_XP(lp, XPSTR("cos("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = cosf(fvar); goto nfuncexit; } + if (!strncmp_XP(lp, XPSTR("ceil("), 5)) { + lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); + fvar = ceilf(fvar); + goto nfuncexit; + } #endif #ifdef USE_FEXTRACT - if (!strncmp(lp, "cts(", 4)) { + if (!strncmp_XP(lp, XPSTR("cts("), 4)) { char tsin[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, tsin, 0); SCRIPT_SKIP_SPACES @@ -2827,7 +2972,7 @@ chknext: goto strexit; } #endif // USE_FEXTRACT - if (!strncmp(lp, "cbs", 3)) { + if (!strncmp_XP(lp, XPSTR("cbs"), 3)) { fvar = glob_script_mem.cmdbuffer_size; tind->index = SCRIPT_CBSIZE; goto exit_settable; @@ -2835,8 +2980,8 @@ chknext: #ifdef USE_W8960 extern void W8960_SetGain(uint8_t sel, uint16_t value); - if (!strncmp(lp, "codec(", 6)) { - float sel; + if (!strncmp_XP(lp, XPSTR("codec("), 6)) { + TS_FLOAT sel; lp = GetNumericArgument(lp + 6, OPER_EQU, &sel, gv); lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); W8960_SetGain(sel, fvar); @@ -2846,9 +2991,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif #ifdef USE_UFILESYS - if (!strncmp(lp, "cpf(", 4)) { + if (!strncmp_XP(lp, XPSTR("cpf("), 4)) { // copy file with offsets sfd, sfstart, sfstop, df - float sfd, sf_from, sf_to, dfd; + TS_FLOAT sfd, sf_from, sf_to, dfd; lp = GetNumericArgument(lp + 4, OPER_EQU, &sfd, 0); lp = GetNumericArgument(lp, OPER_EQU, &sf_from, 0); lp = GetNumericArgument(lp, OPER_EQU, &sf_to, 0); @@ -2879,15 +3024,15 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif break; case 'd': - if (!strncmp(vname, "day", 3)) { + if (!strncmp_XP(vname, XPSTR("day"), 3)) { fvar = RtcTime.day_of_month; goto exit; } - if (!strncmp(vname, "dvnm", 4)) { + if (!strncmp_XP(vname, XPSTR("dvnm"), 4)) { if (sp) strlcpy(sp, SettingsText(SET_DEVICENAME), glob_script_mem.max_ssize); goto strexit; } - if (!strncmp(lp, "dp(", 3)) { + if (!strncmp_XP(lp, XPSTR("dp("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); while (*lp == ' ') lp++; glob_script_mem.script_lzero = fvar; @@ -2901,7 +3046,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = 0; goto nfuncexit; } - if (!strncmp(lp, "diff[", 5)) { + if (!strncmp_XP(lp, XPSTR("diff["), 5)) { struct T_INDEX ind; uint8_t vtype; lp = isvar(lp + 5, &vtype, &ind, 0, 0, gv); @@ -2916,22 +3061,22 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } break; case 'e': - if (!strncmp(vname, "epoch", 5)) { + if (!strncmp_XP(vname, XPSTR("epoch"), 5)) { fvar = UtcTime() - (uint32_t)glob_script_mem.epoch_offset; goto exit; } - if (!strncmp(vname, "epoffs", 6)) { + if (!strncmp_XP(vname, XPSTR("epoffs"), 6)) { fvar = (uint32_t)glob_script_mem.epoch_offset; tind->index = SCRIPT_EPOFFS; goto exit_settable; } - if (!strncmp(vname, "eres", 4)) { + if (!strncmp_XP(vname, XPSTR("eres"), 4)) { fvar = glob_script_mem.event_handeled; tind->index = SCRIPT_EVENT_HANDLED; goto exit_settable; } #ifdef USE_ENERGY_SENSOR - if (!strncmp(lp, "enrg[", 5)) { + if (!strncmp_XP(lp, XPSTR("enrg["), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); while (*lp == ' ') lp++; switch ((uint32_t)fvar) { @@ -2986,7 +3131,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); case 'f': //#define DEBUG_FS #ifdef USE_SCRIPT_FATFS - if (!strncmp(lp, "fo(", 3)) { + if (!strncmp_XP(lp, XPSTR("fo("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); while (*lp == ' ') lp++; @@ -3047,7 +3192,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fc(", 3)) { + if (!strncmp_XP(lp, XPSTR("fc("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); if (fvar >= 0) { uint8_t ind = fvar; @@ -3061,7 +3206,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = 0; goto nfuncexit; } - if (!strncmp(lp, "ff(", 3)) { + if (!strncmp_XP(lp, XPSTR("ff("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t ind = fvar; if (ind >= SFS_MAX) ind = SFS_MAX - 1; @@ -3069,7 +3214,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = 0; goto nfuncexit; } - if (!strncmp(lp, "fw(", 3)) { + if (!strncmp_XP(lp, XPSTR("fw("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = ForceStringVar(lp + 3, str); while (*lp == ' ') lp++; @@ -3083,7 +3228,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fwb(", 4)) { + if (!strncmp_XP(lp, XPSTR("fwb("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); uint8_t buf[2]; buf[0] = fvar; @@ -3099,7 +3244,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } - if (!strncmp(lp, "fr(", 3)) { + if (!strncmp_XP(lp, XPSTR("fr("), 3)) { struct T_INDEX ind; uint8_t vtype; uint8_t sindex = 0; @@ -3172,7 +3317,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); len = 0; goto exit; } - if (!strncmp(lp, "frb(", 4)) { + if (!strncmp_XP(lp, XPSTR("frb("), 4)) { lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); uint8_t ind = fvar; if (ind >= SFS_MAX) ind = SFS_MAX - 1; @@ -3186,7 +3331,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fa(", 3)) { + if (!strncmp_XP(lp, XPSTR("fa("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t ind = fvar; if (ind >= SFS_MAX) ind = SFS_MAX - 1; @@ -3197,7 +3342,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fs(", 3)) { + if (!strncmp_XP(lp, XPSTR("fs("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t ind = fvar; SCRIPT_SKIP_SPACES @@ -3211,7 +3356,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fz(", 3)) { + if (!strncmp_XP(lp, XPSTR("fz("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES uint8_t ind = fvar; @@ -3223,14 +3368,14 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fd(", 3)) { + if (!strncmp_XP(lp, XPSTR("fd("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); ufsp->remove(str); goto nfuncexit; } #ifdef USE_UFILESYS - if (!strncmp(lp, "frw(", 4)) { + if (!strncmp_XP(lp, XPSTR("frw("), 4)) { // read file from web lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES @@ -3242,16 +3387,16 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif #if defined(ESP32) && defined(USE_WEBCAM) - if (!strncmp(lp, "fwp(", 4)) { + if (!strncmp_XP(lp, XPSTR("fwp("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); while (*lp == ' ') lp++; - float fvar1; + TS_FLOAT fvar1; lp = GetNumericArgument(lp, OPER_EQU, &fvar1, gv); uint8_t ind = fvar1; if (ind >= SFS_MAX) ind = SFS_MAX - 1; if (glob_script_mem.file_flags[ind].is_open) { uint8_t *buff; - float maxps = WcGetPicstore(-1, 0); + TS_FLOAT maxps = WcGetPicstore(-1, 0); if (fvar < 1 || fvar > maxps) fvar = 1; uint32_t len = WcGetPicstore(fvar - 1, &buff); if (len) { @@ -3268,14 +3413,14 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif //ESP32 && USE_WEBCAM #ifdef USE_SCRIPT_FATFS_EXT - if (!strncmp(lp, "fe(", 3)) { + if (!strncmp_XP(lp, XPSTR("fe("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); // execute script File ef = ufsp->open(str, FS_FILE_READ); if (ef) { uint16_t fsiz = ef.size(); - if (fsiz<2048) { + if (fsiz < 2048) { char *script = (char*)special_malloc(fsiz + 16); if (script) { memset(script, 0, fsiz + 16); @@ -3289,13 +3434,13 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fmd(", 4)) { + if (!strncmp_XP(lp, XPSTR("fmd("), 4)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); fvar = ufsp->mkdir(str); goto nfuncexit; } - if (!strncmp(lp, "fmt(", 4)) { + if (!strncmp_XP(lp, XPSTR("fmt("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (!fvar) { LittleFS.format(); @@ -3304,13 +3449,13 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "frd(", 4)) { + if (!strncmp_XP(lp, XPSTR("frd("), 4)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); fvar = ufsp->rmdir(str); goto nfuncexit; } - if (!strncmp(lp, "fx(", 3)) { + if (!strncmp_XP(lp, XPSTR("fx("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); if (ufsp->exists(str)) fvar = 1; @@ -3318,12 +3463,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } - if (!strncmp(lp, "fsi(", 4)) { + if (!strncmp_XP(lp, XPSTR("fsi("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = UfsInfo(fvar, 0); goto nfuncexit; } - if (!strncmp(lp, "frn(", 4)) { + if (!strncmp_XP(lp, XPSTR("frn("), 4)) { // rename a file char fn_from[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, fn_from, 0); @@ -3338,7 +3483,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #ifdef USE_FEXTRACT - if (!strncmp(lp, "fxt", 3)) { + if (!strncmp_XP(lp, XPSTR("fxt"), 3)) { lp += 3; uint8_t oflg = 0; if (*lp == 'o') { @@ -3373,7 +3518,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); int16_t accum = fvar; uint16_t a_len[MAX_EXT_ARRAYS]; - float *a_ptr[MAX_EXT_ARRAYS]; + TS_FLOAT *a_ptr[MAX_EXT_ARRAYS]; uint8_t index = 0; while (index < MAX_EXT_ARRAYS) { @@ -3414,9 +3559,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } #endif // USE_FEXTRACT - if (!strncmp(lp, "fwa(", 4)) { + if (!strncmp_XP(lp, XPSTR("fwa("), 4)) { uint16_t alen; - float *fa; + TS_FLOAT *fa; lp = get_array_by_name(lp + 4, &fa, &alen, 0); if (!fa) { fvar = 0; @@ -3455,9 +3600,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "fra(", 4)) { + if (!strncmp_XP(lp, XPSTR("fra("), 4)) { uint16_t alen; - float *fa; + TS_FLOAT *fa; lp = get_array_by_name(lp + 4, &fa, &alen, 0); if (!fa) { fvar = 0; @@ -3501,7 +3646,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif // USE_SCRIPT_FATFS_EXT - if (!strncmp(lp, "fl1(", 4) || !strncmp(lp, "fl2(", 4) ) { + if (!strncmp_XP(lp, XPSTR("fl1("), 4) || !strncmp_XP(lp, XPSTR("fl2("), 4) ) { uint8_t lknum = *(lp + 2) & 3; char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); @@ -3510,12 +3655,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = 0; goto nfuncexit; } - if (!strncmp(lp, "fsm", 3)) { + if (!strncmp_XP(lp, XPSTR("fsm"), 3)) { fvar = (uint32_t)ufsp; goto exit; } #endif //USE_SCRIPT_FATFS - if (!strncmp(lp, "freq", 4)) { + if (!strncmp_XP(lp, XPSTR("freq"), 4)) { #ifdef ESP32 fvar = getCpuFrequencyMhz(); #else @@ -3523,31 +3668,38 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif goto exit; } - if (!strncmp(lp, "frnm", 4)) { + if (!strncmp_XP(lp, XPSTR("frnm"), 4)) { if (sp) strlcpy(sp, SettingsText(SET_FRIENDLYNAME1), glob_script_mem.max_ssize); goto strexit; } +#ifdef USE_ANGLE_FUNC + if (!strncmp_XP(lp, XPSTR("floor("), 6)) { + lp = GetNumericArgument(lp + 6, OPER_EQU, &fvar, gv); + fvar = floorf(fvar); + goto nfuncexit; + } +#endif break; case 'g': - if (!strncmp(vname, "gtmp", 4)) { + if (!strncmp_XP(vname, XPSTR("gtmp"), 4)) { fvar = TasmotaGlobal.temperature_celsius; goto exit; } - if (!strncmp(vname, "ghum", 4)) { + if (!strncmp_XP(vname, XPSTR("ghum"), 4)) { fvar = TasmotaGlobal.humidity; goto exit; } - if (!strncmp(vname, "gprs", 4)) { + if (!strncmp_XP(vname, XPSTR("gprs"), 4)) { fvar = TasmotaGlobal.pressure_hpa; goto exit; } - if (!strncmp(vname, "gtopic", 6)) { + if (!strncmp_XP(vname, XPSTR("gtopic"), 6)) { if (sp) strlcpy(sp, SettingsText(SET_MQTT_GRP_TOPIC), glob_script_mem.max_ssize); goto strexit; } #ifdef USE_WEBSEND_RESPONSE - if (!strncmp(lp, "gwr(", 4)) { + if (!strncmp_XP(lp, XPSTR("gwr("), 4)) { char delim[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, delim, 0); SCRIPT_SKIP_SPACES @@ -3616,7 +3768,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif #ifdef SCRIPT_GET_HTTPS_JP - if (!strncmp(lp, "gjp(", 4)) { + if (!strncmp_XP(lp, XPSTR("gjp("), 4)) { char host[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, host, 0); SCRIPT_SKIP_SPACES @@ -3626,19 +3778,52 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } #endif //SCRIPT_GET_HTTPS_JP + +#ifdef TESLA_POWERWALL + if (!strncmp_XP(lp, XPSTR("gpwl("), 5)) { + char path[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp + 5, OPER_EQU, path, 0); + fvar = call2pwl(path); + goto nfuncexit; + } +#endif + + if (!strncmp_XP(lp, XPSTR("gi("), 3)) { + lp += 3; + if (!strncmp_XP(lp, XPSTR("epoch"), 5)) { + lp += 5; + *(uint32_t*)&fvar = UtcTime(); + } else if (*lp == '0' && *(lp + 1) == 'x') { + lp += 2; + *(uint32_t*)&fvar = strtoll(lp, &lp, 16); + } else { + *(int32_t*)&fvar = strtol(lp, &lp, 10); + } + goto nfuncexit; + } break; case 'h': - if (!strncmp(vname, "hours", 5)) { + if (!strncmp_XP(vname, XPSTR("hours"), 5)) { fvar = RtcTime.hour; goto exit; } - if (!strncmp(vname, "heap", 4)) { + if (!strncmp_XP(vname, XPSTR("heap"), 4)) { fvar = ESP_getFreeHeap(); goto exit; } - if (!strncmp(lp, "hn(", 3)) { + if (!strncmp_XP(lp, XPSTR("hni("), 4)) { + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); + uint8_t iob = *(uint32_t*)&fvar; + lp++; + len = 0; + if (sp) { + sprintf(sp, "%02x", iob); + } + goto strexit; + } + if (!strncmp_XP(lp, XPSTR("hn("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); - if (fvar<0 || fvar>255) fvar = 0; + if (fvar < 0 || fvar > 255) fvar = 0; lp++; len = 0; if (sp) { @@ -3646,7 +3831,16 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto strexit; } - if (!strncmp(lp, "hx(", 3)) { + if (!strncmp_XP(lp, XPSTR("hxi("), 4)) { + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); + lp++; + len = 0; + if (sp) { + sprintf(sp, "%08x", *(uint32_t*)&fvar); + } + goto strexit; + } + if (!strncmp_XP(lp, XPSTR("hx("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); lp++; len = 0; @@ -3655,13 +3849,13 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto strexit; } - if (!strncmp(lp, "hd(", 3)) { + if (!strncmp_XP(lp, XPSTR("hd("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); fvar = strtol(str, NULL, 16); goto nfuncexit; } - if (!strncmp(lp, "hf(", 3)) { + if (!strncmp_XP(lp, XPSTR("hf("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); SCRIPT_SKIP_SPACES @@ -3672,7 +3866,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); uint8_t rflg = 0; if (*lp == 'r') { rflg = 1; - ucp += sizeof(float); + ucp += sizeof(TS_FLOAT); lp++; } char substr[3]; @@ -3690,7 +3884,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "http(", 5)) { + if (!strncmp_XP(lp, XPSTR("http("), 5)) { char host[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 5, OPER_EQU, host, 0); SCRIPT_SKIP_SPACES @@ -3701,17 +3895,17 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } #ifdef USE_LIGHT - if (!strncmp(lp, "hsvrgb(", 7)) { + if (!strncmp_XP(lp, XPSTR("hsvrgb("), 7)) { lp = GetNumericArgument(lp + 7, OPER_EQU, &fvar, gv); if (fvar < 0 || fvar > 360) fvar = 0; SCRIPT_SKIP_SPACES // arg2 - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); if (fvar2 < 0 || fvar2 > 100) fvar2 = 0; SCRIPT_SKIP_SPACES // arg3 - float fvar3; + TS_FLOAT fvar3; lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv); if (fvar3 < 0 || fvar3 > 100) fvar3 = 0; @@ -3721,7 +3915,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif //USE_LIGHT #ifdef USE_HOMEKIT - if (!strncmp(lp, "hki(", 4)) { + if (!strncmp_XP(lp, XPSTR("hki("), 4)) { if (!TasmotaGlobal.global_state.wifi_down) { // erase nvs lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); @@ -3734,7 +3928,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto nfuncexit; } #endif - if (!strncmp(lp, "hstr(", 5)) { + if (!strncmp_XP(lp, XPSTR("hstr("), 5)) { char hstr[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 5, OPER_EQU, hstr, 0); uint16_t cnt; @@ -3752,7 +3946,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); break; case 'i': - if (!strncmp(lp, "ins(", 4)) { + if (!strncmp_XP(lp, XPSTR("ins("), 4)) { char s1[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, s1, 0); SCRIPT_SKIP_SPACES @@ -3767,46 +3961,46 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto nfuncexit; } - if (!strncmp(lp, "int(", 4)) { + if (!strncmp_XP(lp, XPSTR("int("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = floor(fvar); goto nfuncexit; } - if (!strncmp(lp, "is(", 3)) { + if (!strncmp_XP(lp, XPSTR("is("), 3)) { lp = isargs(lp + 3, 0); fvar = 0; len = 0; goto exit; } - if (!strncmp(lp, "is1(", 4)) { + if (!strncmp_XP(lp, XPSTR("is1("), 4)) { lp = isargs(lp + 4, 1); fvar = 0; len = 0; goto exit; } - if (!strncmp(lp, "is2(", 4)) { + if (!strncmp_XP(lp, XPSTR("is2("), 4)) { lp = isargs(lp + 4, 2); fvar = 0; len = 0; goto exit; } - if (!strncmp(lp, "is[", 3)) { + if (!strncmp_XP(lp, XPSTR("is["), 3)) { lp = isget(lp + 3, sp, 0, gv); len = 0; goto strexit; } - if (!strncmp(lp, "is1[", 4)) { + if (!strncmp_XP(lp, XPSTR("is1["), 4)) { lp = isget(lp + 4, sp, 1, gv); len = 0; goto strexit; } - if (!strncmp(lp, "is2[", 4)) { + if (!strncmp_XP(lp, XPSTR("is2["), 4)) { lp = isget(lp + 4, sp, 2, gv); len = 0; goto strexit; } #ifdef USE_SCRIPT_I2C - if (!strncmp(lp, "ia", 2)) { + if (!strncmp_XP(lp, XPSTR("ia"), 2)) { uint8_t bus = 0; lp += 2; if (*lp == '2') { @@ -3817,7 +4011,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); fvar = script_i2c(0, fvar, bus); goto nfuncexit; } - if (!strncmp(lp, "iw", 2)) { + if (!strncmp_XP(lp, XPSTR("iw"), 2)) { uint8_t bytes = 1; lp += 2; if (*lp != '(') { @@ -3829,12 +4023,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); lp = GetNumericArgument(lp + 1, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES // arg2 - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = script_i2c(9 + bytes, fvar, fvar2); goto nfuncexit; } - if (!strncmp(lp, "ir", 2)) { + if (!strncmp_XP(lp, XPSTR("ir"), 2)) { uint8_t bytes = 1; lp += 2; if (*lp != '(') { @@ -3851,11 +4045,11 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #ifdef ESP32 #ifdef USE_I2S_AUDIO - if (!strncmp(lp, "i2sw(", 5)) { - float port; + if (!strncmp_XP(lp, XPSTR("i2sw("), 5)) { + TS_FLOAT port; lp = GetNumericArgument(lp + 5, OPER_EQU, &port, gv); uint16_t alen = 0; - float *fa = 0; + TS_FLOAT *fa = 0; lp = get_array_by_name(lp, &fa, &alen, 0); if (!fa) { fvar = -1; @@ -3882,7 +4076,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #ifdef JPEG_PICTS #ifdef STREAM_JPEG_PICTS case 'j': - if (!strncmp(lp, "jpg(", 4)) { + if (!strncmp_XP(lp, XPSTR("jpg("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); uint8_t selector = fvar; switch (selector) { @@ -3890,7 +4084,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); // start streaming char url[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp, OPER_EQU, url, 0); - float xp, yp, scale ; + TS_FLOAT xp, yp, scale ; lp = GetNumericArgument(lp, OPER_EQU, &xp, 0); lp = GetNumericArgument(lp, OPER_EQU, &yp, 0); lp = GetNumericArgument(lp, OPER_EQU, &scale, 0); @@ -3910,8 +4104,8 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #ifdef USE_KNX case 'k': - if (!strncmp(lp, "knx(", 4)) { - float type; + if (!strncmp_XP(lp, XPSTR("knx("), 4)) { + TS_FLOAT type; lp = GetNumericArgument(lp + 4, OPER_EQU, &type, gv); lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES @@ -3922,17 +4116,17 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif case 'l': - if (!strncmp(lp, "lip", 3)) { + if (!strncmp_XP(lp, XPSTR("lip"), 3)) { if (sp) strlcpy(sp, (const char*)WiFi.localIP().toString().c_str(), glob_script_mem.max_ssize); goto strexit; } #ifdef USE_SCRIPT_GLOBVARS - if (!strncmp(vname, "luip", 4)) { + if (!strncmp_XP(vname, XPSTR("luip"), 4)) { if (sp) strlcpy(sp, glob_script_mem.last_udp_ip.toString().c_str(), glob_script_mem.max_ssize); goto strexit; } #endif //USE_SCRIPT_GLOBVARS - if (!strncmp(vname, "loglvl", 6)) { + if (!strncmp_XP(vname, XPSTR("loglvl"), 6)) { fvar = glob_script_mem.script_loglevel; tind->index = SCRIPT_LOGLEVEL; exit_settable: @@ -3943,7 +4137,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); return lp + len; } #ifdef USE_LVGL - if (!strncmp(lp, "lvgl(", 5)) { + if (!strncmp_XP(lp, XPSTR("lvgl("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES fvar = lvgl_test(&lp, fvar); @@ -3952,65 +4146,65 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif // USE_LVGL break; case 'm': - if (!strncmp(lp, "med(", 4)) { - float fvar1; + if (!strncmp_XP(lp, XPSTR("med("), 4)) { + TS_FLOAT fvar1; lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES // arg2 - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = DoMedian5(fvar1, fvar2); goto nfuncexit; } #ifdef USE_ANGLE_FUNC - if (!strncmp(lp, "mpt(", 4)) { + if (!strncmp_XP(lp, XPSTR("mpt("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = MeasurePulseTime(fvar); goto nfuncexit; } #endif //USE_ANGLE_FUNC - if (!strncmp(vname, "micros", 6)) { + if (!strncmp_XP(vname, XPSTR("micros"), 6)) { fvar = micros(); goto exit; } - if (!strncmp(vname, "millis", 6)) { + if (!strncmp_XP(vname, XPSTR("millis"), 6)) { fvar = millis(); goto exit; } - if (!strncmp(vname, "mins", 4)) { + if (!strncmp_XP(vname, XPSTR("mins"), 4)) { fvar = RtcTime.minute; goto exit; } - if (!strncmp(vname, "month", 5)) { + if (!strncmp_XP(vname, XPSTR("month"), 5)) { fvar = RtcTime.month; goto exit; } - if (!strncmp(vname, "mqttc", 5)) { + if (!strncmp_XP(vname, XPSTR("mqttc"), 5)) { if (TasmotaGlobal.rules_flag.mqtt_connected) { TasmotaGlobal.rules_flag.mqtt_connected = 0; fvar = 1; } goto exit; } - if (!strncmp(vname, "mqttd", 5)) { + if (!strncmp_XP(vname, XPSTR("mqttd"), 5)) { if (TasmotaGlobal.rules_flag.mqtt_disconnected) { TasmotaGlobal.rules_flag.mqtt_disconnected = 0; fvar = 1; } goto exit; } - if (!strncmp(vname, "mqtts", 5)) { + if (!strncmp_XP(vname, XPSTR("mqtts"), 5)) { fvar = !TasmotaGlobal.global_state.mqtt_down; goto exit; } - if (!strncmp(lp, "mp(", 3)) { - float fvar1; + if (!strncmp_XP(lp, XPSTR("mp("), 3)) { + TS_FLOAT fvar1; lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES while (*lp != ')') { char *opp = lp; lp++; - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); SCRIPT_SKIP_SPACES fvar = fvar1; @@ -4018,7 +4212,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); (*opp == '>' && fvar1 > fvar2) || (*opp == '=' && fvar1 == fvar2)) { if (*lp !='<' && *lp != '>' && *lp != '=' && *lp != ')' && *lp != SCRIPT_EOL) { - float fvar3; + TS_FLOAT fvar3; lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv); SCRIPT_SKIP_SPACES fvar = fvar3; @@ -4033,11 +4227,11 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto exit; } #ifdef USE_MORITZ - if (!strncmp(lp, "mo(", 3)) { - float fvar1; + if (!strncmp_XP(lp, XPSTR("mo("), 3)) { + TS_FLOAT fvar1; lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); SCRIPT_SKIP_SPACES char rbuff[64]; @@ -4049,19 +4243,19 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif //USE_MORITZ #ifdef ESP32_FAST_MUX - if (!strncmp(lp, "mux(", 4)) { + if (!strncmp_XP(lp, XPSTR("mux("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (fvar == 0) { // start lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); uint16_t alen; - float *fa; + TS_FLOAT *fa; lp = get_array_by_name(lp, &fa, &alen, 0); if (!fa) { fvar = -1; goto nfuncexit; } - float falen; + TS_FLOAT falen; lp = GetNumericArgument(lp, OPER_EQU, &falen, gv); if (falen > alen) { falen = alen; @@ -4073,7 +4267,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } else if (fvar == 2) { // set array uint16_t alen; - float *fa; + TS_FLOAT *fa; lp = get_array_by_name(lp, &fa, &alen, 0); if (!fa) { fvar = -1; @@ -4093,14 +4287,14 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); break; case 'n': - if (!strncmp(vname, "npwr", 4)) { + if (!strncmp_XP(vname, XPSTR("npwr"), 4)) { fvar = TasmotaGlobal.devices_present; goto exit; } break; case 'p': - if (!strncmp(lp, "pin[", 4)) { + if (!strncmp_XP(lp, XPSTR("pin["), 4)) { // raw pin level GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = digitalRead((uint8_t)fvar); @@ -4108,7 +4302,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); len++; goto exit; } - if (!strncmp(lp, "pn[", 3)) { + if (!strncmp_XP(lp, XPSTR("pn["), 3)) { GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); fvar = Pin(fvar); // skip ] bracket @@ -4116,7 +4310,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto exit; } #if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2)) - if (!strncmp(lp, "pl(", 3)) { + if (!strncmp_XP(lp, XPSTR("pl("), 3)) { char path[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, path, 0); Play_mp3(path); @@ -4125,7 +4319,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto exit; } #endif // USE_I2S_AUDIO - if (!strncmp(lp, "pd[", 3)) { + if (!strncmp_XP(lp, XPSTR("pd["), 3)) { GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t gpiopin = fvar; if ((gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) { @@ -4138,35 +4332,35 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto exit; } #ifdef ESP32 - if (!strncmp(vname, "pheap", 5)) { + if (!strncmp_XP(vname, XPSTR("pheap"), 5)) { fvar = ESP.getFreePsram(); goto exit; } #endif //ESP32 - if (!strncmp(vname, "prefix1", 7)) { + if (!strncmp_XP(vname, XPSTR("prefix1"), 7)) { if (sp) strlcpy(sp, SettingsText(SET_MQTTPREFIX1), glob_script_mem.max_ssize); goto strexit; } - if (!strncmp(vname, "prefix2", 7)) { + if (!strncmp_XP(vname, XPSTR("prefix2"), 7)) { if (sp) strlcpy(sp, SettingsText(SET_MQTTPREFIX2), glob_script_mem.max_ssize); goto strexit; } - if (!strncmp(vname, "prefix3", 7)) { + if (!strncmp_XP(vname, XPSTR("prefix3"), 7)) { if (sp) strlcpy(sp, SettingsText(SET_MQTTPREFIX3), glob_script_mem.max_ssize); goto strexit; } - if (!strncmp(lp, "pow(", 4)) { + if (!strncmp_XP(lp, XPSTR("pow("), 4)) { // arg1 - float fvar1; + TS_FLOAT fvar1; lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES // arg2 - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = FastPrecisePowf(fvar1, fvar2); goto nfuncexit; } - if (!strncmp(lp, "pwr[", 4)) { + if (!strncmp_XP(lp, XPSTR("pwr["), 4)) { GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); uint8_t index = fvar; if (index <= TasmotaGlobal.devices_present) { @@ -4177,7 +4371,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); len += 1; goto exit; } - if (!strncmp(lp, "pc[", 3)) { + if (!strncmp_XP(lp, XPSTR("pc["), 3)) { GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); uint8_t index = fvar; if (index < 1 || index > MAX_COUNTERS) index = 1; @@ -4189,11 +4383,11 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); break; case 'r': - if (!strncmp(vname, "ram", 3)) { + if (!strncmp_XP(vname, XPSTR("ram"), 3)) { fvar = glob_script_mem.script_mem_size + (glob_script_mem.script_size) + (PMEM_SIZE); goto exit; } - if (!strncmp(lp, "rnd(", 4)) { + if (!strncmp_XP(lp, XPSTR("rnd("), 4)) { // tasmota switch state GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (fvar<0) { @@ -4206,9 +4400,9 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); len++; goto exit; } - if (!strncmp(lp, "rma(", 4)) { + if (!strncmp_XP(lp, XPSTR("rma("), 4)) { uint16_t alen; - float *array; + TS_FLOAT *array; lp = get_array_by_name(lp + 4, &array, &alen, 0); char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp, OPER_EQU, str, 0); @@ -4238,7 +4432,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } /* #if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_M5STACK_CORE2) || defined(ESP32S3_BOX) || defined(USE_I2S_MIC)) - if (!strncmp(lp, "rec(", 4)) { + if (!strncmp_XP(lp, XPSTR("rec("), 4)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); //SCRIPT_SKIP_SPACES @@ -4250,7 +4444,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif */ - if (!strncmp(lp, "rr(", 3)) { + if (!strncmp_XP(lp, XPSTR("rr("), 3)) { lp += 4; len = 0; const char *cp = GetResetReason().c_str(); @@ -4263,22 +4457,34 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto strexit; } - if (!strncmp(lp, "rrsn", 4)) { + if (!strncmp_XP(lp, XPSTR("rrsn"), 4)) { fvar = ESP_ResetInfoReason(); goto exit; } - if (!strncmp(lp, "rax", 3)) { + if (!strncmp_XP(lp, XPSTR("rax"), 3)) { TasmotaGlobal.no_autoexec = 0; goto exit; } +#ifdef USE_ANGLE_FUNC + if (!strncmp_XP(lp, XPSTR("rad("), 4)) { + GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); + fvar = fvar * 3.1415916535f / 180.0f; + goto nfuncexit; + } + if (!strncmp_XP(lp, XPSTR("round("), 6)) { + lp = GetNumericArgument(lp + 6, OPER_EQU, &fvar, gv); + fvar = floorf(fvar); + goto nfuncexit; + } +#endif break; case 's': - if (!strncmp(vname, "secs", 4)) { + if (!strncmp_XP(vname, XPSTR("secs"), 4)) { fvar = RtcTime.second; goto exit; } - if (!strncmp(lp, "sw[", 3)) { + if (!strncmp_XP(lp, XPSTR("sw["), 3)) { // tasmota switch state GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); fvar = SwitchLastState((uint32_t)fvar); @@ -4286,34 +4492,34 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); len++; goto exit; } - if (!strncmp(vname, "stack", 5)) { + if (!strncmp_XP(vname, XPSTR("stack"), 5)) { fvar = GetStack(); goto exit; } #ifdef ESP32 - if (!strncmp(vname, "stkwm", 5)) { + if (!strncmp_XP(vname, XPSTR("stkwm"), 5)) { fvar = uxTaskGetStackHighWaterMark(NULL); goto exit; } #endif // ESP32 - if (!strncmp(vname, "slen", 4)) { + if (!strncmp_XP(vname, XPSTR("slen"), 4)) { fvar = strlen(glob_script_mem.script_ram); goto exit; } - if (!strncmp(lp, "sl(", 3)) { + if (!strncmp_XP(lp, XPSTR("sl("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); fvar = strlen(str); goto nfuncexit; } - if (!strncmp(lp, "sb(", 3)) { + if (!strncmp_XP(lp, XPSTR("sb("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); SCRIPT_SKIP_SPACES - float fvar1; + TS_FLOAT fvar1; lp = GetNumericArgument(lp, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); lp++; len = 0; @@ -4326,7 +4532,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto strexit; } - if (!strncmp(lp, "st(", 3)) { + if (!strncmp_XP(lp, XPSTR("st("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); SCRIPT_SKIP_SPACES @@ -4387,7 +4593,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } goto strexit; } - if (!strncmp(lp, "s(", 2)) { + if (!strncmp_XP(lp, XPSTR("s("), 2)) { lp += 2; uint8_t dprec = glob_script_mem.script_dprec; uint8_t lzero = glob_script_mem.script_lzero; @@ -4413,7 +4619,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); goto strexit; } #if defined(ESP32) && (defined(USE_I2S_AUDIO) || defined(USE_TTGO_WATCH) || defined(USE_M5STACK_CORE2)) - if (!strncmp(lp, "say(", 4)) { + if (!strncmp_XP(lp, XPSTR("say("), 4)) { char text[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, text, 0); Say(text); @@ -4424,7 +4630,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); #endif // USE_I2S_AUDIO #ifdef ESP32 - if (!strncmp(lp, "sf(", 3)) { + if (!strncmp_XP(lp, XPSTR("sf("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); if (fvar < 80) fvar = 80; if (fvar > 240) fvar = 240; @@ -4434,7 +4640,7 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif //ESP32 #ifdef USE_TTGO_WATCH - if (!strncmp(lp, "slp(", 4)) { + if (!strncmp_XP(lp, XPSTR("slp("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES TTGO_Sleep(fvar); @@ -4442,18 +4648,18 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif //USE_TTGO_WATCH #if defined(USE_TIMERS) && defined(USE_SUNRISE) - if (!strncmp(vname, "sunrise", 7)) { + if (!strncmp_XP(vname, XPSTR("sunrise"), 7)) { fvar = SunMinutes(0); goto exit; } - if (!strncmp(vname, "sunset", 6)) { + if (!strncmp_XP(vname, XPSTR("sunset"), 6)) { fvar = SunMinutes(1); goto exit; } #endif //USE_TIMERS #ifdef USE_SHUTTER - if (!strncmp(lp, "sht[", 4)) { + if (!strncmp_XP(lp, XPSTR("sht["), 4)) { GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); uint8_t index = fvar; if (index <= TasmotaGlobal.shutters_present) { @@ -4466,12 +4672,12 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); } #endif //USE_SHUTTER #ifdef USE_ANGLE_FUNC - if (!strncmp(lp, "sin(", 4)) { + if (!strncmp_XP(lp, XPSTR("sin("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = sinf(fvar); goto nfuncexit; } - if (!strncmp(lp, "sqrt(", 5)) { + if (!strncmp_XP(lp, XPSTR("sqrt("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); fvar = sqrtf(fvar); goto nfuncexit; @@ -4483,13 +4689,13 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value); uint32_t sml_status(uint32_t meter); extern char *SML_GetSVal(uint32_t index); - if (!strncmp(lp, "sml[", 4)) { + if (!strncmp_XP(lp, XPSTR("sml["), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES fvar = SML_GetVal(fvar); goto nfuncexit; } - if (!strncmp(lp, "smls[", 5)) { + if (!strncmp_XP(lp, XPSTR("smls["), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES lp++; @@ -4507,15 +4713,15 @@ extern char *SML_GetSVal(uint32_t index); } goto strexit; } - if (!strncmp(lp, "sml(", 4)) { - float fvar1; + if (!strncmp_XP(lp, XPSTR("sml("), 4)) { + TS_FLOAT fvar1; lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES - float fvar2; + TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); SCRIPT_SKIP_SPACES if (fvar2 == 0) { - float fvar3; + TS_FLOAT fvar3; lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv); fvar = SML_SetBaud(fvar1, fvar3); } else if (fvar2 == 1) { @@ -4553,18 +4759,18 @@ extern char *SML_GetSVal(uint32_t index); } goto nfuncexit; } - if (!strncmp(vname, "smlj", 4)) { + if (!strncmp_XP(vname, XPSTR("smlj"), 4)) { fvar = sml_options; tind->index = SML_JSON_ENABLE; goto exit_settable; } - if (!strncmp(lp, "smld(", 5)) { + if (!strncmp_XP(lp, XPSTR("smld("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); if (fvar < 1) fvar = 1; SML_Decode(fvar - 1); goto nfuncexit; } - if (!strncmp(lp, "smlv[", 5)) { + if (!strncmp_XP(lp, XPSTR("smlv["), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); fvar = sml_getv(fvar); goto nfuncexit; @@ -4572,8 +4778,8 @@ extern char *SML_GetSVal(uint32_t index); #endif //USE_SML_M #ifdef USE_SCRIPT_SERIAL - if (!strncmp(lp, "so(", 3)) { - float rxpin, txpin, br; + if (!strncmp_XP(lp, XPSTR("so("), 3)) { + TS_FLOAT rxpin, txpin, br; lp = GetNumericArgument(lp + 3, OPER_EQU, &rxpin, gv); SCRIPT_SKIP_SPACES lp = GetNumericArgument(lp, OPER_EQU, &txpin, gv); @@ -4593,7 +4799,7 @@ extern char *SML_GetSVal(uint32_t index); } SCRIPT_SKIP_SPACES // check for rec buffer - float rxbsiz = 128; + TS_FLOAT rxbsiz = 128; if (*lp != ')') { lp = GetNumericArgument(lp, OPER_EQU, &rxbsiz, gv); } @@ -4613,7 +4819,11 @@ extern char *SML_GetSVal(uint32_t index); //setRxBufferSize(TMSBSIZ); Settings->serial_config = sconfig; - AddLog(LOG_LEVEL_INFO, PSTR("Serial port set to %s %d bit/s at rx=%d tx=%d rbu=%d"), GetSerialConfig().c_str(), (uint32_t)br, (uint32_t)rxpin, (uint32_t)txpin, (uint32_t)rxbsiz); + uint8_t uart = 0; +#ifdef ESP32 + uart = glob_script_mem.sp->getUart(); +#endif + AddLog(LOG_LEVEL_INFO, PSTR("Serial port set to %s %d bit/s at rx=%d tx=%d rbu=%d uart=%d"), GetSerialConfig().c_str(), (uint32_t)br, (uint32_t)rxpin, (uint32_t)txpin, (uint32_t)rxbsiz, uart); Settings->serial_config = savc; if (rxpin == 3 and txpin == 1) ClaimSerial(); @@ -4623,7 +4833,7 @@ extern char *SML_GetSVal(uint32_t index); } goto nfuncexit; } - if (!strncmp(lp, "sw(", 3)) { + if (!strncmp_XP(lp, XPSTR("sw("), 3)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); fvar = -1; @@ -4633,7 +4843,7 @@ extern char *SML_GetSVal(uint32_t index); } goto nfuncexit; } - if (!strncmp(lp, "swb(", 4)) { + if (!strncmp_XP(lp, XPSTR("swb("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); if (glob_script_mem.sp) { glob_script_mem.sp->write((uint8_t)fvar); @@ -4641,14 +4851,14 @@ extern char *SML_GetSVal(uint32_t index); } goto nfuncexit; } - if (!strncmp(lp, "sa(", 3)) { + if (!strncmp_XP(lp, XPSTR("sa("), 3)) { fvar = -1; if (glob_script_mem.sp) { fvar = glob_script_mem.sp->available(); } goto nfuncexit; } - if (!strncmp(lp, "srb(", 3)) { + if (!strncmp_XP(lp, XPSTR("srb("), 3)) { fvar = -1; if (glob_script_mem.sp) { fvar = glob_script_mem.sp->available(); @@ -4658,7 +4868,7 @@ extern char *SML_GetSVal(uint32_t index); } goto nfuncexit; } - if (!strncmp(lp, "sp(", 3)) { + if (!strncmp_XP(lp, XPSTR("sp("), 3)) { fvar = -1; if (glob_script_mem.sp) { fvar = glob_script_mem.sp->available(); @@ -4668,7 +4878,7 @@ extern char *SML_GetSVal(uint32_t index); } goto nfuncexit; } - if (!strncmp(lp, "sr(", 3)) { + if (!strncmp_XP(lp, XPSTR("sr("), 3)) { uint16_t size = glob_script_mem.max_ssize; char str[SCRIPT_MAXSSIZE]; memset(str, 0, size); @@ -4701,7 +4911,7 @@ extern char *SML_GetSVal(uint32_t index); if (sp) strlcpy(sp, str, size); goto strexit;; } - if (!strncmp(lp, "sc(", 3)) { + if (!strncmp_XP(lp, XPSTR("sc("), 3)) { fvar = -1; if (Script_Close_Serial()) { fvar = 0; @@ -4711,23 +4921,23 @@ extern char *SML_GetSVal(uint32_t index); goto exit; } // serial write array - if (!strncmp(lp, "swa(", 4)) { + if (!strncmp_XP(lp, XPSTR("swa("), 4)) { fvar = -1; uint8_t modbus_buffer[64]; uint16_t alen; - float *array; + TS_FLOAT *array; lp = get_array_by_name(lp + 4, &array, &alen, 0); SCRIPT_SKIP_SPACES if (!array) { goto exit; } - float len; + TS_FLOAT len; lp = GetNumericArgument(lp, OPER_EQU, &len, 0); SCRIPT_SKIP_SPACES if (len > alen) len = alen; if (len < 1) len = 1; if (*lp != ')') { - float opt; + TS_FLOAT opt; lp = GetNumericArgument(lp, OPER_EQU, &opt, 0); SCRIPT_SKIP_SPACES uint16_t opts = opt; @@ -4800,17 +5010,17 @@ extern char *SML_GetSVal(uint32_t index); goto nfuncexit; } // serial read array - if (!strncmp(lp, "sra(", 4)) { + if (!strncmp_XP(lp, XPSTR("sra("), 4)) { fvar = -1; if (glob_script_mem.sp) { uint16_t alen; - float *array = 0; + TS_FLOAT *array = 0; lp = get_array_by_name(lp + 4, &array, &alen, 0); SCRIPT_SKIP_SPACES if (!array) { goto exit; } - float opts = -1; + TS_FLOAT opts = -1; if (*lp != ')') { lp = GetNumericArgument(lp, OPER_EQU, &opts, 0); SCRIPT_SKIP_SPACES @@ -4857,22 +5067,22 @@ extern char *SML_GetSVal(uint32_t index); } #ifdef USE_SML_M // serial modbus write float, 010404ffffffffxxxx - if (!strncmp(lp, "smw(", 4)) { + if (!strncmp_XP(lp, XPSTR("smw("), 4)) { fvar = -1; if (glob_script_mem.sp) { - float addr; + TS_FLOAT addr; lp = GetNumericArgument(lp + 4, OPER_EQU, &addr, 0); SCRIPT_SKIP_SPACES - float mode; + TS_FLOAT mode; lp = GetNumericArgument(lp, OPER_EQU, &mode, 0); SCRIPT_SKIP_SPACES uint16_t alend; - float *fpd; + TS_FLOAT *fpd; lp = get_array_by_name(lp, &fpd, &alend, 0); SCRIPT_SKIP_SPACES - float nvals; + TS_FLOAT nvals; lp = GetNumericArgument(lp, OPER_EQU, &nvals, 0); SCRIPT_SKIP_SPACES @@ -4896,7 +5106,7 @@ extern char *SML_GetSVal(uint32_t index); mb_index++; for (uint16_t cnt = 0; cnt < nvals; cnt++) { - float fpval = *fpd++; + TS_FLOAT fpval = *fpd++; uint32_t ui32 = fpval; uint32_t uval, *uvp; uvp = &uval; @@ -4966,7 +5176,7 @@ extern char *SML_GetSVal(uint32_t index); #ifdef USE_SCRIPT_SPI - if (!strncmp(lp, "spi(", 4)) { + if (!strncmp_XP(lp, XPSTR("spi("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); uint8_t sel = fvar; uint8_t index; @@ -5044,12 +5254,12 @@ extern char *SML_GetSVal(uint32_t index); lp = GetNumericArgument(lp , OPER_EQU, &fvar, 0); int8_t index = fvar - 1; - float *fpd = 0; + TS_FLOAT *fpd = 0; uint16_t alend; lp = get_array_by_name(lp, &fpd, &alend, 0); // len - float len = alend; + TS_FLOAT len = alend; lp = GetNumericArgument(lp , OPER_EQU, &len, 0); if (len > alend) { len = alend; @@ -5066,7 +5276,7 @@ extern char *SML_GetSVal(uint32_t index); goto exit; } #endif // USE_SCRIPT_SPI - if (!strncmp(lp, "s2hms(", 6)) { + if (!strncmp_XP(lp, XPSTR("s2hms("), 6)) { lp = GetNumericArgument(lp + 6, OPER_EQU, &fvar, 0); lp++; char tbuff[16]; @@ -5080,7 +5290,7 @@ extern char *SML_GetSVal(uint32_t index); goto strexit; } #ifdef USE_FEXTRACT - if (!strncmp(lp, "s2t(", 4)) { + if (!strncmp_XP(lp, XPSTR("s2t("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); char str[SCRIPT_MAXSSIZE]; s2tstamp(str, SCRIPT_MAXSSIZE, fvar, 0); @@ -5089,54 +5299,55 @@ extern char *SML_GetSVal(uint32_t index); goto strexit; } #endif // USE_FEXTRACT + break; case 't': - if (!strncmp(vname, "time", 4)) { + if (!strncmp_XP(vname, XPSTR("time"), 4)) { fvar = MinutesPastMidnight(); goto exit; } - if (!strncmp(vname, "tper", 4)) { + if (!strncmp_XP(vname, XPSTR("tper"), 4)) { fvar = Settings->tele_period; tind->index = SCRIPT_TELEPERIOD; goto exit_settable; } - if (!strncmp(vname, "tinit", 5)) { + if (!strncmp_XP(vname, XPSTR("tinit"), 5)) { fvar = TasmotaGlobal.rules_flag.time_init; goto exit; } - if (!strncmp(vname, "tset", 4)) { + if (!strncmp_XP(vname, XPSTR("tset"), 4)) { fvar = TasmotaGlobal.rules_flag.time_set; goto exit; } - if (!strncmp(vname, "tstamp", 6)) { + if (!strncmp_XP(vname, XPSTR("tstamp"), 6)) { if (sp) strlcpy(sp, GetDateAndTime(DT_LOCAL).c_str(), glob_script_mem.max_ssize); goto strexit; } - if (!strncmp(vname, "topic", 5)) { + if (!strncmp_XP(vname, XPSTR("topic"), 5)) { if (sp) strlcpy(sp, TasmotaGlobal.mqtt_topic, glob_script_mem.max_ssize); goto strexit; } #ifdef USE_SCRIPT_TIMER - if (!strncmp(lp, "ts1(", 4)) { + if (!strncmp_XP(lp, XPSTR("ts1("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (fvar < 10) fvar = 10; Script_ticker1.attach_ms(fvar, Script_ticker1_end); goto nfuncexit; } - if (!strncmp(lp, "ts2(", 4)) { + if (!strncmp_XP(lp, XPSTR("ts2("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (fvar < 10) fvar = 10; Script_ticker2.attach_ms(fvar, Script_ticker2_end); goto nfuncexit; } - if (!strncmp(lp, "ts3(", 4)) { + if (!strncmp_XP(lp, XPSTR("ts3("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (fvar < 10) fvar = 10; Script_ticker3.attach_ms(fvar, Script_ticker3_end); goto nfuncexit; } - if (!strncmp(lp, "ts4(", 4)) { + if (!strncmp_XP(lp, XPSTR("ts4("), 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); if (fvar < 10) fvar = 10; Script_ticker4.attach_ms(fvar, Script_ticker4_end); @@ -5146,7 +5357,7 @@ extern char *SML_GetSVal(uint32_t index); #ifdef USE_DISPLAY #ifdef USE_TOUCH_BUTTONS - if (!strncmp(lp, "tbut[", 5)) { + if (!strncmp_XP(lp, XPSTR("tbut["), 5)) { GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); uint8_t index = fvar; if (index < 1 || index > MAX_TOUCH_BUTTONS) index = 1; @@ -5165,11 +5376,13 @@ extern char *SML_GetSVal(uint32_t index); #if 0 - if (!strncmp(lp, "test(", 5)) { + if (!strncmp_XP(lp, XPSTR("test("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); uint32_t cycles; uint64_t accu = 0; char sbuffer[32]; + + GT911_Touch_Init(&Wire1, -1, -1, 960, 540); /* // PSTR performance test @@ -5191,7 +5404,7 @@ extern char *SML_GetSVal(uint32_t index); #endif #ifdef USE_TIMERS - if (!strncmp(lp, "ttget(", 6)) { + if (!strncmp_XP(lp, XPSTR("ttget("), 6)) { lp = GetNumericArgument(lp + 6, OPER_EQU, &fvar, gv); SCRIPT_SKIP_SPACES uint8_t index = fvar; @@ -5204,7 +5417,7 @@ extern char *SML_GetSVal(uint32_t index); #endif #ifdef USE_FEXTRACT - if (!strncmp(lp, "tso(", 4)) { + if (!strncmp_XP(lp, XPSTR("tso("), 4)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); fvar = -1; @@ -5222,14 +5435,14 @@ extern char *SML_GetSVal(uint32_t index); len = 0; goto strexit; } - if (!strncmp(lp, "tsn(", 4)) { + if (!strncmp_XP(lp, XPSTR("tsn("), 4)) { char str[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, str, 0); fvar = tstamp2l(str); goto nfuncexit; } #endif - if (!strncmp(lp, "tc(", 3)) { + if (!strncmp_XP(lp, XPSTR("tc("), 3)) { lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar, gv); lp++; if (sp) { @@ -5241,15 +5454,15 @@ extern char *SML_GetSVal(uint32_t index); } break; case 'u': - if (!strncmp(vname, "uptime", 6)) { + if (!strncmp_XP(vname, XPSTR("uptime"), 6)) { fvar = MinutesUptime(); goto exit; } - if (!strncmp(vname, "upsecs", 6)) { + if (!strncmp_XP(vname, XPSTR("upsecs"), 6)) { fvar = TasmotaGlobal.uptime; goto exit; } - if (!strncmp(lp, "upd[", 4)) { + if (!strncmp_XP(lp, XPSTR("upd["), 4)) { // var was updated struct T_INDEX ind; uint8_t vtype; @@ -5268,10 +5481,10 @@ extern char *SML_GetSVal(uint32_t index); } goto notfound; } - if (!strncmp(lp, "udp(", 4)) { + if (!strncmp_XP(lp, XPSTR("udp("), 4)) { char url[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 4, OPER_EQU, url, 0); - float port; + TS_FLOAT port; lp = GetNumericArgument(lp, OPER_EQU, &port, gv); char payload[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp, OPER_EQU, payload, 0); @@ -5282,25 +5495,25 @@ extern char *SML_GetSVal(uint32_t index); case 'w': #if defined(ESP32) && defined(USE_WEBCAM) - if (!strncmp(lp, "wc(", 3)) { - float fvar1; + if (!strncmp_XP(lp, XPSTR("wc("), 3)) { + TS_FLOAT fvar1; lp = GetNumericArgument(lp + 3, OPER_EQU, &fvar1, gv); SCRIPT_SKIP_SPACES switch ((uint32)fvar1) { case 0: - { float fvar2; + { TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = WcSetup(fvar2); } break; case 1: - { float fvar2; + { TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = WcGetFrame(fvar2); } break; case 2: - { float fvar2,fvar3; + { TS_FLOAT fvar2,fvar3; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); SCRIPT_SKIP_SPACES lp = GetNumericArgument(lp, OPER_EQU, &fvar3, gv); @@ -5314,13 +5527,13 @@ extern char *SML_GetSVal(uint32_t index); fvar = WcGetHeight(); break; case 5: - { float fvar2; + { TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = WcSetStreamserver(fvar2); } break; case 6: - { float fvar2; + { TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = WcSetMotionDetect(fvar2); } @@ -5328,7 +5541,7 @@ extern char *SML_GetSVal(uint32_t index); /* #ifdef USE_FACE_DETECT case 7: - { float fvar2; + { TS_FLOAT fvar2; lp = GetNumericArgument(lp, OPER_EQU, &fvar2, gv); fvar = WcSetFaceDetect(fvar2); } @@ -5342,55 +5555,55 @@ extern char *SML_GetSVal(uint32_t index); } #endif //ESP32, USE_WEBCAM #if defined(USE_TTGO_WATCH) && defined(USE_BMA423) - if (!strncmp(vname, "wdclk", 5)) { + if (!strncmp_XP(vname, XPSTR("wdclk"), 5)) { fvar = TTGO_doubleclick(); goto exit; } - if (!strncmp(vname, "wbut", 4)) { + if (!strncmp_XP(vname, XPSTR("wbut"), 4)) { fvar = TTGO_button(); goto exit; } #endif // USE_TTGO_WATCH #if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_GT911) - if (!strncmp(lp, "wtch(", 5)) { + if (!strncmp_XP(lp, XPSTR("wtch("), 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); fvar = Touch_Status(fvar); goto nfuncexit; } #endif // USE_FT5206 - if (!strncmp(vname, "wm", 2)) { + if (!strncmp_XP(vname, XPSTR("wm"), 2)) { fvar = glob_script_mem.web_mode; goto exit; } - if (!strncmp(vname, "wday", 4)) { + if (!strncmp_XP(vname, XPSTR("wday"), 4)) { fvar = RtcTime.day_of_week; goto exit; } - if (!strncmp(vname, "wific", 5)) { + if (!strncmp_XP(vname, XPSTR("wific"), 5)) { if (TasmotaGlobal.rules_flag.wifi_connected) { TasmotaGlobal.rules_flag.wifi_connected = 0; fvar = 1; } goto exit; } - if (!strncmp(vname, "wifid", 5)) { + if (!strncmp_XP(vname, XPSTR("wifid"), 5)) { if (TasmotaGlobal.rules_flag.wifi_disconnected) { TasmotaGlobal.rules_flag.wifi_disconnected = 0; fvar = 1; } goto exit; } - if (!strncmp(vname, "wifis", 5)) { + if (!strncmp_XP(vname, XPSTR("wifis"), 5)) { fvar = !TasmotaGlobal.global_state.wifi_down; goto exit; } - if (!strncmp(vname, "wlp", 3)) { + if (!strncmp_XP(vname, XPSTR("wlp"), 3)) { OsWatchLoop(); fvar = 0; goto exit; } #ifdef xUSE_SHINE - if (!strncmp(vname, "wav2mp3(", 8)) { + if (!strncmp_XP(vname, XPSTR("wav2mp3("), 8)) { char path[SCRIPT_MAXSSIZE]; lp = GetStringArgument(lp + 8, OPER_EQU, path, 0); fvar = wav2mp3(path); @@ -5399,7 +5612,7 @@ extern char *SML_GetSVal(uint32_t index); #endif break; case 'y': - if (!strncmp(vname, "year", 4)) { + if (!strncmp_XP(vname, XPSTR("year"), 4)) { fvar = RtcTime.year; goto exit; } @@ -5639,14 +5852,15 @@ char *GetStringArgument(char *lp, uint8_t lastop, char *cp, struct GVARS *gv) { } return lp; } - -char *GetNumericArgument(char *lp, uint8_t lastop, float *fp, struct GVARS *gv) { +char *GetNumericArgument(char *lp, uint8_t lastop, TS_FLOAT *fp, struct GVARS *gv); +char *GetNumericArgument(char *lp, uint8_t lastop, TS_FLOAT *fp, struct GVARS *gv) { uint8_t operand = 0; -float fvar1,fvar; +TS_FLOAT fvar1,fvar; char *slp; uint8_t vtype; while (*lp == ' ') { lp++; } // skip leading spaces struct T_INDEX ind; + ind.bits.integer = 0; while (1) { // get 1. value if (*lp=='(') { @@ -5656,12 +5870,52 @@ struct T_INDEX ind; //if (*lp==')') lp++; } else { lp = isvar(lp, &vtype, &ind, &fvar1, 0, gv); - if ((vtype!=NUM_RES) && (vtype&STYPE)) { + if ((vtype != NUM_RES) && (vtype & STYPE)) { // string type glob_script_mem.glob_error = 1; } } - switch (lastop) { + if (ind.bits.integer) { + switch (lastop) { + case OPER_EQU: + fvar = fvar1; + break; + case OPER_PLS: + *(int32_t*)&fvar += *(int32_t*)&fvar1; + break; + case OPER_MIN: + *(int32_t*)&fvar -= *(int32_t*)&fvar1; + break; + case OPER_MUL: + *(int32_t*)&fvar *= *(int32_t*)&fvar1; + break; + case OPER_DIV: + *(int32_t*)&fvar /= *(int32_t*)&fvar1; + break; + case OPER_PERC: + *(int32_t*)&fvar %= *(int32_t*)&fvar1; + break; + case OPER_XOR: + *(uint32_t*)&fvar ^= *(uint32_t*)&fvar1; + break; + case OPER_AND: + *(uint32_t*)&fvar &= *(uint32_t*)&fvar1; + break; + case OPER_OR: + *(uint32_t*)&fvar |= *(uint32_t*)&fvar1; + break; + case OPER_SHL: + *(uint32_t*)&fvar <<= *(uint32_t*)&fvar1; + break; + case OPER_SHR: + *(uint32_t*)&fvar >>= *(uint32_t*)&fvar1; + break; + default: + break; + + } + } else { + switch (lastop) { case OPER_EQU: fvar = fvar1; break; @@ -5698,6 +5952,7 @@ struct T_INDEX ind; default: break; + } } slp = lp; lp = getop(lp, &operand); @@ -5725,7 +5980,7 @@ struct T_INDEX ind; char *ForceStringVar(char *lp, char *dstr) { - float fvar; + TS_FLOAT fvar; char *slp = lp; glob_script_mem.glob_error = 0; lp = GetStringArgument(lp, OPER_EQU, dstr, 0); @@ -5739,7 +5994,11 @@ char *ForceStringVar(char *lp, char *dstr) { } #ifdef USE_HOMEKIT + +int32_t UpdVar(char *vname, float *fvar, uint32_t mode); + extern "C" { + uint32_t Ext_UpdVar(char *vname, float *fvar, uint32_t mode) { return UpdVar(vname, fvar, mode); } @@ -5779,7 +6038,7 @@ int32_t UpdVar(char *vname, float *fvar, uint32_t mode) { return 1; break; case 'b': - *fvar = ButtonLastState(index - 1); + *fvar = Button.last_state[index - 1]; return 1; break; } @@ -5787,7 +6046,7 @@ int32_t UpdVar(char *vname, float *fvar, uint32_t mode) { } struct T_INDEX ind; uint8_t vtype; - float res = *fvar; + TS_FLOAT res = *fvar; isvar(vname, &vtype, &ind, fvar, 0, 0); if (vtype != VAR_NV) { // found variable as result @@ -5839,7 +6098,7 @@ void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dst uint8_t dprec = glob_script_mem.script_dprec; char dsep = glob_script_mem.script_sepc; uint8_t lzero = glob_script_mem.script_lzero; - float fvar; + TS_FLOAT fvar; cp = srcbuf; struct T_INDEX ind; char string[SCRIPT_MAXSSIZE]; @@ -5884,11 +6143,15 @@ void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dst cp += 2; } else { cp = isvar(cp, &vtype, &ind, &fvar, string, 0); - if (vtype!=VAR_NV) { + if (vtype != VAR_NV) { // found variable as result - if (vtype==NUM_RES || (vtype&STYPE)==0) { + if (vtype == NUM_RES || (vtype & STYPE) == 0) { // numeric result - f2char(fvar, dprec, lzero, string, dsep); + if (ind.bits.integer) { + dtostrfd(*(int32_t*)&fvar, 0, string); + } else { + f2char(fvar, dprec, lzero, string, dsep); + } } else { // string result } @@ -5978,7 +6241,7 @@ void toSLog(const char *str) { } char *Evaluate_expression(char *lp, uint8_t and_or, uint8_t *result, struct GVARS *gv) { - float fvar,*dfvar,fvar1; + TS_FLOAT fvar,*dfvar,fvar1; uint8_t numeric; struct T_INDEX ind; uint8_t vtype = 0,lastop; @@ -6166,8 +6429,8 @@ void esp_pwm(int32_t value, uint32 freq, uint32_t channel) { } #endif // ESP32 } - -char *eval_sub(char *lp, float *fvar, char *rstr) { +char *eval_sub(char *lp, TS_FLOAT *fvar, char *rstr); +char *eval_sub(char *lp, TS_FLOAT *fvar, char *rstr) { scripter_sub(lp - 1, 0); while (1) { if (*lp == ')') { @@ -6254,7 +6517,6 @@ int16_t retval; if (js) { String jss = js; // copy the string to a new buffer, not sure we can change the original buffer - //JsonParser parser((char*)jss.c_str()); JsonParser parser((char*)jss.c_str()); jo = parser.getRootObject(); gv.jo = &jo; @@ -6275,7 +6537,7 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { int8_t loopdepth = -1; char *lp_next[SCRIPT_LOOP_NEST]; char *cv_ptr[SCRIPT_LOOP_NEST]; - float *cv_count[SCRIPT_LOOP_NEST], cv_max[SCRIPT_LOOP_NEST], cv_inc[SCRIPT_LOOP_NEST]; + TS_FLOAT *cv_count[SCRIPT_LOOP_NEST], cv_max[SCRIPT_LOOP_NEST], cv_inc[SCRIPT_LOOP_NEST]; int16_t globaindex, saindex; struct T_INDEX ind; uint8_t operand, lastop, numeric = 1, if_state[IF_NEST], if_exe[IF_NEST], if_result[IF_NEST], and_or, ifstck = 0; @@ -6283,9 +6545,9 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { if_result[ifstck] = 0; if_exe[ifstck] = 1; char cmpstr[SCRIPT_MAXSSIZE]; - float *dfvar; + TS_FLOAT *dfvar; - float fvar = 0, fvar1, sysvar, swvar; + TS_FLOAT fvar = 0, fvar1, sysvar, swvar; uint8_t section = 0, sysv_type = 0, swflg = 0; char *lp; @@ -6497,7 +6759,7 @@ getnext: } else if (!strncmp(lp, "case", 4) && swflg>0) { lp += 4; SCRIPT_SKIP_SPACES - float cvar; + TS_FLOAT cvar; if (!(swflg & 0x80)) { lp = GetNumericArgument(lp, OPER_EQU, &cvar, 0); if (swvar != cvar) { @@ -6585,7 +6847,7 @@ getnext: goto next_line; } #ifdef USE_DISPLAY - else if (!strncmp(lp, "dt", 2)) { + else if (!strncmp(lp, "dt ", 3)) { //char dstbuf[256]; lp += 2; SCRIPT_SKIP_SPACES @@ -6679,7 +6941,7 @@ getnext: // numeric result if (glob_script_mem.type[ind.index].bits.is_filter) { uint16_t len = 0; - float *fa = Get_MFAddr(index, &len, 0); + TS_FLOAT *fa = Get_MFAddr(index, &len, 0); //Serial.printf(">> 2 %d\n",(uint32_t)*fa); if (fa && len) ws2812_set_array(fa, len, fvar); } @@ -6693,7 +6955,7 @@ getnext: else if (!strncmp(lp, "beep(", 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, 0); SCRIPT_SKIP_SPACES - float fvar1; + TS_FLOAT fvar1; lp = GetNumericArgument(lp, OPER_EQU, &fvar1, 0); esp32_beep(fvar, fvar1); lp++; @@ -6701,29 +6963,20 @@ getnext: } #endif //ESP32 - else if (!strncmp(lp, "pwm", 3)) { + else if (!strncmp(lp, "pwm", 3) && lp[4] == '(') { lp += 3; - uint8_t channel = 1; - if (*(lp+1) == '(') { - channel = *lp & 0x0f; + uint8_t channel = *lp & 0x0f; #ifdef ESP8266 - if (channel > 5) {channel = 5;} + if (channel > 5) {channel = 5;} #endif // ESP8266 #ifdef ESP32 - if (channel > 8) {channel = 8;} + if (channel > 8) {channel = 8;} #endif // ESP32 - if (channel < 1) {channel = 1;} - lp += 2; - } else { - if (*lp == '(') { - lp++; - } else { - goto next_line; - } - } + if (channel < 1) {channel = 1;} + lp += 2; lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); SCRIPT_SKIP_SPACES - float fvar1=4000; + TS_FLOAT fvar1 = 4000; if (*lp != ')') { lp = GetNumericArgument(lp, OPER_EQU, &fvar1, 0); } @@ -6732,26 +6985,26 @@ getnext: goto next_line; } #ifdef USE_SCRIPT_WEB_DISPLAY - else if (!strncmp(lp, "wcs", 3)) { + else if (!strncmp(lp, "wcs ", 4)) { lp += 4; // skip one space after cmd web_send_line(0, lp); //WSContentFlush(); goto next_line; } - else if (!strncmp(lp, "wfs", 3)) { + else if (!strncmp(lp, "wfs ", 4)) { lp += 4; // skip one space after cmd web_send_file(0, lp); //WSContentFlush(); goto next_line; } - else if (!strncmp(lp, "wcf", 3)) { + else if (!strncmp(lp, "wcf\n", 4)) { WSContentFlush(); goto next_line; } #endif - else if (!strncmp(lp, "rapp", 3)) { + else if (!strncmp(lp, "rapp ", 4)) { lp += 4; // skip one space after cmd char *tmp = (char*)malloc(256); @@ -6765,7 +7018,7 @@ getnext: #if defined(USE_SENDMAIL) || defined(USE_ESP32MAIL) - else if (!strncmp(lp, "mail", 4)) { + else if (!strncmp(lp, "mail ", 5)) { lp += 5; //char tmp[256]; char *tmp = (char*)malloc(256); @@ -6922,7 +7175,51 @@ getnext: #ifdef SCRIPT_LM_SUB } #endif - switch (lastop) { + if (ind.bits.integer) { + switch (lastop) { + case OPER_EQU: + if (glob_script_mem.var_not_found) { + if (!gv || !gv->jo) toLogEOL("var not found: ",lp); + goto next_line; + } + *dfvar = fvar; + break; + case OPER_PLSEQU: + *(int32_t*)dfvar += *(int32_t*)&fvar; + break; + case OPER_MINEQU: + *(int32_t*)dfvar -= *(int32_t*)&fvar; + break; + case OPER_MULEQU: + *(int32_t*)dfvar *= *(int32_t*)&fvar; + break; + case OPER_DIVEQU: + *(int32_t*)dfvar /= *(int32_t*)&fvar; + break; + case OPER_PERCEQU: + *(int32_t*)dfvar %= *(int32_t*)&fvar; + break; + case OPER_ANDEQU: + *(uint32_t*)dfvar &= *(int32_t*)&fvar; + break; + case OPER_OREQU: + *(uint32_t*)dfvar |= *(int32_t*)&fvar; + break; + case OPER_XOREQU: + *(uint32_t*)dfvar ^= *(int32_t*)&fvar; + break; + case OPER_SHLEQU: + *(uint32_t*)dfvar <<= *(int32_t*)&fvar; + break; + case OPER_SHREQU: + *(uint32_t*)dfvar >>= *(int32_t*)&fvar; + break; + default: + // error + break; + } + } else { + switch (lastop) { case OPER_EQU: if (glob_script_mem.var_not_found) { if (!gv || !gv->jo) toLogEOL("var not found: ",lp); @@ -6963,7 +7260,9 @@ getnext: default: // error break; + } } + // var was changed if (globvindex >= 0) SetChanged(globvindex); #ifdef USE_SCRIPT_GLOBVARS @@ -7114,7 +7413,7 @@ getnext: lp += tlen; do { if (*ctype == nxttok && *lp == nxttok) { - float fparam; + TS_FLOAT fparam; numeric = 1; glob_script_mem.glob_error = 0; argptr = GetNumericArgument((char*)ctype + 1, OPER_EQU, &fparam, 0); @@ -7187,7 +7486,7 @@ getnext: #ifdef USE_SCRIPT_SPI // transfer 1-3 bytes -uint32_t script_sspi_trans(int32_t cs_index, float *array, uint32_t len, uint32_t size) { +uint32_t script_sspi_trans(int32_t cs_index, TS_FLOAT *array, uint32_t len, uint32_t size) { uint32_t out = 0; if (cs_index >= 0) { cs_index &= 3; @@ -7209,31 +7508,62 @@ uint32_t script_sspi_trans(int32_t cs_index, float *array, uint32_t len, uint32_ out <<= 16; out |= glob_script_mem.spi.spip->transfer16((uint32_t)*array); } + if (size == 4) { + // special byte transfer with cs low + digitalWrite(glob_script_mem.spi.cs[cs_index], 0); + out = glob_script_mem.spi.spip->transfer((uint8_t)*array); + digitalWrite(glob_script_mem.spi.cs[cs_index], 1); + } *array++ = out; } glob_script_mem.spi.spip->endTransaction(); } else { - if (size < 1 || size > 3) size = 1; - for (uint32_t cnt = 0; cnt < len; cnt++) { - uint32_t bit = 1 << ((size * 8) - 1); - out = 0; - uint32_t uvar = *array; - while (bit) { - digitalWrite(glob_script_mem.spi.sclk, 0); - if (glob_script_mem.spi.mosi >= 0) { - if (uvar & bit) digitalWrite(glob_script_mem.spi.mosi, 1); - else digitalWrite(glob_script_mem.spi.mosi, 0); - } - digitalWrite(glob_script_mem.spi.sclk, 1); - if (glob_script_mem.spi.miso >= 0) { - if (digitalRead(glob_script_mem.spi.miso)) { - out |= bit; + if (size == 4) { + for (uint32_t cnt = 0; cnt < len; cnt++) { + digitalWrite(glob_script_mem.spi.cs[cs_index], 0); + uint32_t bit = 1 << ((1 * 8) - 1); + out = 0; + uint32_t uvar = *array; + while (bit) { + digitalWrite(glob_script_mem.spi.sclk, 0); + if (glob_script_mem.spi.mosi >= 0) { + if (uvar & bit) digitalWrite(glob_script_mem.spi.mosi, 1); + else digitalWrite(glob_script_mem.spi.mosi, 0); } + digitalWrite(glob_script_mem.spi.sclk, 1); + if (glob_script_mem.spi.miso >= 0) { + if (digitalRead(glob_script_mem.spi.miso)) { + out |= bit; + } + } + bit >>= 1; } - bit >>= 1; + *array++ = out; + digitalWrite(glob_script_mem.spi.cs[cs_index], 1); + } + } else { + if (size < 1 || size > 3) size = 1; + for (uint32_t cnt = 0; cnt < len; cnt++) { + uint32_t bit = 1 << ((size * 8) - 1); + out = 0; + uint32_t uvar = *array; + while (bit) { + digitalWrite(glob_script_mem.spi.sclk, 0); + if (glob_script_mem.spi.mosi >= 0) { + if (uvar & bit) digitalWrite(glob_script_mem.spi.mosi, 1); + else digitalWrite(glob_script_mem.spi.mosi, 0); + } + digitalWrite(glob_script_mem.spi.sclk, 1); + if (glob_script_mem.spi.miso >= 0) { + if (digitalRead(glob_script_mem.spi.miso)) { + out |= bit; + } + } + bit >>= 1; + } + *array++ = out; } - *array++ = out; } } if (cs_index >= 0) { @@ -7289,8 +7619,8 @@ void ScripterEvery100ms(void) { // should report overflow later void Scripter_save_pvars(void) { int16_t mlen = 0; - float *fp = (float*)glob_script_mem.script_pram; - mlen+=sizeof(float); + TS_FLOAT *fp = (TS_FLOAT*)glob_script_mem.script_pram; + mlen+=sizeof(TS_FLOAT); struct T_INDEX *vtp = glob_script_mem.type; for (uint8_t count = 0; countglob_script_mem.script_pram_size) { vtp[count].bits.is_permanent = 0; return; @@ -7308,7 +7638,7 @@ void Scripter_save_pvars(void) { *fp++ = *fa++; } } else { - mlen += sizeof(float); + mlen += sizeof(TS_FLOAT); if (mlen>glob_script_mem.script_pram_size) { vtp[count].bits.is_permanent = 0; return; @@ -7657,9 +7987,12 @@ void SaveScript(void) { #ifdef EEP_SCRIPT_SIZE // here we handle EEPROM modes if (glob_script_mem.FLAGS.eeprom == true) { - if (EEP_SCRIPT_SIZE != SPECIAL_EEPMODE_SIZE) { + if (EEP_SCRIPT_SIZE < SPECIAL_EEPMODE_SIZE) { EEP_WRITE(0, EEP_SCRIPT_SIZE, glob_script_mem.script_ram); } else { +#if EEP_SCRIPT_SIZE==SPI_FLASH_2SEC_SIZE + alt_eeprom_writeBytes(0, SPI_FLASH_2SEC_SIZE, (uint8_t*)glob_script_mem.script_ram); +#else uint8_t *ucs; ucs = (uint8_t*)calloc(SPI_FLASH_SEC_SIZE + 4, 1); if (ucs) { @@ -7668,6 +8001,7 @@ void SaveScript(void) { } free(ucs); } +#endif } } #else @@ -7734,10 +8068,15 @@ void SaveScriptEnd(void) { #endif //USE_SCRIPT_GLOBVARS if (glob_script_mem.script_mem) { + // script was restarted + Run_Scripter1(">R\n", 3, 0); Scripter_save_pvars(); free(glob_script_mem.script_mem); glob_script_mem.script_mem = 0; glob_script_mem.script_mem_size = 0; + #ifdef USE_SCRIPT_SERIAL + Script_Close_Serial(); +#endif } if (bitRead(Settings->rule_enabled, 0)) { @@ -7748,10 +8087,6 @@ void SaveScriptEnd(void) { return; } -#ifdef USE_SCRIPT_SERIAL - Script_Close_Serial(); -#endif - set_callbacks(); Run_Scripter1(">B\n", 3, 0); @@ -7764,15 +8099,6 @@ void SaveScriptEnd(void) { } } - - -void set_callbacks() { - if (Run_Scripter1(">F", -2, 0) == 99) {glob_script_mem.fast_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.fast_script = 0;} - if (Run_Scripter1(">E", -2, 0) == 99) {glob_script_mem.event_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.event_script = 0;} - if (Run_Scripter1(">C", -2, 0) == 99) {glob_script_mem.html_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.html_script = 0;} - if (Run_Scripter1(">T", -2, 0) == 99) {glob_script_mem.teleperiod = glob_script_mem.section_ptr + 2;} else {glob_script_mem.teleperiod = 0;} -} - void set_wpages(char *id, uint16_t index) { uint16_t idlen = strlen(id); uint16_t idl2 = idlen; @@ -7802,6 +8128,15 @@ void script_set_web_pages(void) { #endif // USE_WEBSERVER +void set_callbacks() { + if (Run_Scripter1(">F", -2, 0) == 99) {glob_script_mem.fast_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.fast_script = 0;} + if (Run_Scripter1(">E", -2, 0) == 99) {glob_script_mem.event_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.event_script = 0;} + if (Run_Scripter1(">C", -2, 0) == 99) {glob_script_mem.html_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.html_script = 0;} + if (Run_Scripter1(">T", -2, 0) == 99) {glob_script_mem.teleperiod = glob_script_mem.section_ptr + 2;} else {glob_script_mem.teleperiod = 0;} +} + + +//#define SCRIPT_HUE_DEBUG #if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) #define HUE_DEV_MVNUM 5 @@ -7980,7 +8315,7 @@ void Script_HueStatus(String *response, uint16_t hue_devs) { light_status += ","; } - float temp; + TS_FLOAT temp; switch (hue_script[hue_devs].type) { case 'C': response->replace("{type}","Color Ligh"); // alexa ok @@ -8085,7 +8420,7 @@ void Script_Check_Hue(String *response) { struct T_INDEX ind; uint8_t vtype; char vname[16]; - for (uint32_t cnt = 0; cntc_str(), hue_devs); +#ifdef SCRIPT_HUE_DEBUG + AddLog(LOG_LEVEL_INFO, PSTR("Hue: %s - %d "),response->c_str(), hue_devs); +#endif } - hue_devs++; } if (*lp==SCRIPT_EOL) { @@ -8128,7 +8467,7 @@ void Script_Check_Hue(String *response) { lp++; } } -#if 0 +#ifdef SCRIPT_HUE_DEBUG if (response) { AddLog(LOG_LEVEL_DEBUG, PSTR("Hue: %d"), hue_devs); toLog(">>>>"); @@ -8204,7 +8543,7 @@ void Script_Handle_Hue(String path) { JsonParserToken hue_xy = root[PSTR("xy")]; if (hue_xy) { // Saturation of the light. 254 is the most saturated (colored) and 0 is the least saturated (white). - float x, y; + TS_FLOAT x, y; JsonParserArray arr_xy = JsonParserArray(hue_xy); JsonParserToken tok_x = arr_xy[0]; JsonParserToken tok_y = arr_xy[1]; @@ -8275,7 +8614,11 @@ void Script_Handle_Hue(String path) { } else { response = FPSTR(sHUE_ERROR_JSON); } +#ifdef SCRIPT_HUE_DEBUG + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_HUE " Result (%s)"), response.c_str()); +#else AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_HTTP D_HUE " Result (%s)"), response.c_str()); +#endif WSSend(code, CT_APP_JSON, response); if (resp) { //Run_Scripter(">E", 2, 0); @@ -8490,17 +8833,17 @@ bool ScriptCommand(void) { char *lp = XdrvMailbox.data; lp++; while (*lp==' ') lp++; - float fvar; + TS_FLOAT fvar; char str[SCRIPT_MAXSSIZE]; glob_script_mem.glob_error = 0; - float *fpd = 0; + TS_FLOAT *fpd = 0; uint16_t alend; char *cp = get_array_by_name(lp, &fpd, &alend, 0); if (fpd && cp && (!strchr(lp, '[')) ) { // is array Response_P(PSTR("{\"script\":{\"%s\":["), lp); for (uint16_t cnt = 0; cnt < alend; cnt++) { - float tvar = *fpd++; + TS_FLOAT tvar = *fpd++; ext_snprintf_P(str, sizeof(str), PSTR("%*_f"), -glob_script_mem.script_dprec, &tvar); if (cnt) { ResponseAppend_P(PSTR(",%s"), str); @@ -9333,7 +9676,7 @@ void Script_Check_HTML_Setvars(void) { struct T_INDEX ind; uint8_t vtype; isvar(vname, &vtype, &ind, 0, 0, 0); - if (vtype!=NUM_RES && vtype&STYPE) { + if (vtype != NUM_RES && vtype & STYPE) { // string type must insert quotes uint8_t tlen = strlen(cp1); memmove(cp1 + 1, cp1, tlen); @@ -9467,8 +9810,8 @@ const char SCRIPT_MSG_GTE1[] PROGMEM = "'%s'"; #define MAX_GARRAY 4 #endif - -char *gc_get_arrays(char *lp, float **arrays, uint8_t *ranum, uint16_t *rentries, uint16_t *ipos) { +char *gc_get_arrays(char *lp, TS_FLOAT **arrays, uint8_t *ranum, uint16_t *rentries, uint16_t *ipos); +char *gc_get_arrays(char *lp, TS_FLOAT **arrays, uint8_t *ranum, uint16_t *rentries, uint16_t *ipos) { struct T_INDEX ind; uint8_t vtype; uint16 entries = 0; @@ -9478,18 +9821,18 @@ uint16_t cipos = 0; while (anum < MAX_GARRAY) { if (*lp == ')' || *lp == 0) break; char *lp1 = lp; - float sysvar; + TS_FLOAT sysvar; lp = isvar(lp, &vtype, &ind, &sysvar, 0, 0); if (vtype != VAR_NV) { SCRIPT_SKIP_SPACES uint8_t index = glob_script_mem.type[ind.index].index; - if ((vtype&STYPE) == 0) { + if ((vtype & STYPE) == 0) { // numeric result //Serial.printf("numeric %d - %d \n",ind.index,index); if (glob_script_mem.type[ind.index].bits.is_filter) { //Serial.printf("numeric array\n"); uint16_t len = 0; - float *fa = Get_MFAddr(index, &len, &cipos); + TS_FLOAT *fa = Get_MFAddr(index, &len, &cipos); //Serial.printf(">> 2 %d\n",len); if (fa && len >= entries) { if (!entries) { @@ -9595,9 +9938,9 @@ char gs_ctype; #endif void ScriptWebShow(char mc, uint8_t page) { - float cv_max = 0; - float cv_inc = 0; - float *cv_count = 0; + TS_FLOAT cv_max = 0; + TS_FLOAT cv_inc = 0; + TS_FLOAT *cv_count = 0; char *cv_ptr; //uint8_t web_script; @@ -9639,7 +9982,7 @@ void ScriptWebShow(char mc, uint8_t page) { struct T_INDEX ind; uint8_t vtype; lp = isvar(lp + 5, &vtype, &ind, 0, 0, 0); - if ((vtype != VAR_NV) && (vtype&STYPE) == 0) { + if ((vtype != VAR_NV) && (vtype & STYPE) == 0) { uint16_t index = glob_script_mem.type[ind.index].index; cv_count = &glob_script_mem.fvars[index]; SCRIPT_SKIP_SPACES @@ -9744,7 +10087,7 @@ const char *gc_str; if (!strncmp(lin, "so(", 3)) { // set options - float var; + TS_FLOAT var; lin = GetNumericArgument(lin + 3, OPER_EQU, &var, 0); specopt = var; return lin; @@ -9775,14 +10118,14 @@ const char *gc_str; if (!strncmp(lin, "sl(", 3)) { // insert slider sl(min max var left mid right) char *lp = lin; - float min; + TS_FLOAT min; lp = GetNumericArgument(lp + 3, OPER_EQU, &min, 0); SCRIPT_SKIP_SPACES // arg2 - float max; + TS_FLOAT max; lp = GetNumericArgument(lp, OPER_EQU, &max, 0); SCRIPT_SKIP_SPACES - float val; + TS_FLOAT val; char *slp = lp; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); SCRIPT_SKIP_SPACES @@ -9806,7 +10149,7 @@ const char *gc_str; } else if (!strncmp(lin, "ck(", 3)) { char *lp = lin + 3; char *slp = lp; - float val; + TS_FLOAT val; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); SCRIPT_SKIP_SPACES @@ -9832,7 +10175,7 @@ const char *gc_str; // pull down char *lp = lin + 3; char *slp = lp; - float val; + TS_FLOAT val; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); SCRIPT_SKIP_SPACES @@ -9846,7 +10189,7 @@ const char *gc_str; glob_script_mem.glob_error = 0; uint16_t tsiz = 200; - float fvar; + TS_FLOAT fvar; char *slp1 = lp; lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); if (!glob_script_mem.glob_error) { @@ -9915,7 +10258,7 @@ const char *gc_str; if (optflg) WSContentSend_P(SCRIPT_MSG_BUT_START_TBL); else WSContentSend_P(SCRIPT_MSG_BUT_START); for (uint32_t cnt = 0; cnt < bcnt; cnt++) { - float val; + TS_FLOAT val; char *slp = lp; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); SCRIPT_SKIP_SPACES @@ -9957,7 +10300,7 @@ const char *gc_str; } else if (!strncmp(lin, "tm(", 3)) { // time only HH:MM - float val; + TS_FLOAT val; char *lp = lin + 3; char *slp = lp; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); @@ -9970,7 +10313,7 @@ const char *gc_str; SCRIPT_SKIP_SPACES uint16_t tsiz = 70; if (*lp != ')') { - float fvar; + TS_FLOAT fvar; lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); tsiz = fvar; } @@ -10001,7 +10344,7 @@ const char *gc_str; uint16_t tsiz = 200; if (*lp != ')') { glob_script_mem.glob_error = 0; - float fvar; + TS_FLOAT fvar; char *slp1 = lp; lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); SCRIPT_SKIP_SPACES @@ -10041,16 +10384,16 @@ const char *gc_str; } else if (!strncmp(lin, "nm(", 3)) { char *lp = lin; - float min; + TS_FLOAT min; lp = GetNumericArgument(lp + 3, OPER_EQU, &min, 0); SCRIPT_SKIP_SPACES - float max; + TS_FLOAT max; lp = GetNumericArgument(lp, OPER_EQU, &max, 0); SCRIPT_SKIP_SPACES - float step; + TS_FLOAT step; lp = GetNumericArgument(lp, OPER_EQU, &step, 0); SCRIPT_SKIP_SPACES - float val; + TS_FLOAT val; char *slp = lp; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); SCRIPT_SKIP_SPACES @@ -10063,7 +10406,7 @@ const char *gc_str; uint16_t tsiz = 200; uint8_t dprec = 1; if (*lp != ')') { - float val; + TS_FLOAT val; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); SCRIPT_SKIP_SPACES tsiz = val; @@ -10117,14 +10460,14 @@ exgc: strncpy(valstr, lin, len); valstr[len] = 0; WSContentSend_P(PSTR("%s"), valstr); - float *fpd = 0; + TS_FLOAT *fpd = 0; uint16_t alend; uint16_t ipos; lp = get_array_by_name(cp + 5, &fpd, &alend, &ipos); SCRIPT_SKIP_SPACES if (*lp != ')') { // limit array lenght - float val; + TS_FLOAT val; lp = GetNumericArgument(lp, OPER_EQU, &val, 0); if (val > alend) { val = alend; @@ -10240,14 +10583,14 @@ exgc: SCRIPT_SKIP_SPACES //Serial.printf("type %d\n",ctype); - float max_entries = 0; + TS_FLOAT max_entries = 0; struct T_INDEX ind; uint8_t vtype; char *slp = lp; lp = isvar(lp, &vtype, &ind, &max_entries, 0, 0); if (vtype != VAR_NV) { - if ((vtype&STYPE) == 0) { + if ((vtype & STYPE) == 0) { // numeric result if (!ind.bits.constant && glob_script_mem.type[ind.index].bits.is_filter) { // is 1. array @@ -10258,7 +10601,7 @@ exgc: } SCRIPT_SKIP_SPACES - float *arrays[MAX_GARRAY]; + TS_FLOAT *arrays[MAX_GARRAY]; uint8_t anum = 0; uint16_t entries = 0; uint16_t ipos = 0; @@ -10297,7 +10640,7 @@ exgc: for (uint32_t ind = 0; ind < anum; ind++) { char lbl[16]; - float *fp = arrays[ind]; + TS_FLOAT *fp = arrays[ind]; GetTextIndexed(lbl, sizeof(lbl), ind, label); char lbl2[16]; if (lab2[0]) { @@ -10399,7 +10742,7 @@ exgc: WSContentSend_P("['"); char lbl[16]; if (todflg >= 0) { - uint16_t mins = (float)(todflg % divflg) * (float)((float)60 / (float)divflg); + uint16_t mins = (TS_FLOAT)(todflg % divflg) * (TS_FLOAT)((TS_FLOAT)60 / (TS_FLOAT)divflg); if (hmflg) { sprintf(lbl, "%d:%02d", todflg / divflg, mins); } else { @@ -10428,8 +10771,8 @@ exgc: WSContentSend_P("',"); for (uint32_t ind = 0; ind < anum; ind++) { char acbuff[32]; - float *fp = arrays[ind]; - float fval; + TS_FLOAT *fp = arrays[ind]; + TS_FLOAT fval; if (asflg) { fval = fp[aind]; } else { @@ -10469,10 +10812,10 @@ exgc: if (y2f) { // 2 y axes variant SCRIPT_SKIP_SPACES - float max1; + TS_FLOAT max1; lp = GetNumericArgument(lp, OPER_EQU, &max1, 0); SCRIPT_SKIP_SPACES - float max2; + TS_FLOAT max2; lp = GetNumericArgument(lp, OPER_EQU, &max2, 0); SCRIPT_SKIP_SPACES char maxstr1[16]; @@ -10485,10 +10828,10 @@ exgc: SCRIPT_SKIP_SPACES if (gs_ctype != 'g') { if (*lp != ')') { - float max1; + TS_FLOAT max1; lp = GetNumericArgument(lp, OPER_EQU, &max1, 0); SCRIPT_SKIP_SPACES - float max2; + TS_FLOAT max2; lp = GetNumericArgument(lp, OPER_EQU, &max2, 0); SCRIPT_SKIP_SPACES char maxstr1[16]; @@ -10502,17 +10845,17 @@ exgc: } if (gs_ctype == 'g') { - float yellowFrom; + TS_FLOAT yellowFrom; lp = GetNumericArgument(lp, OPER_EQU, &yellowFrom, 0); SCRIPT_SKIP_SPACES - float redFrom; + TS_FLOAT redFrom; lp = GetNumericArgument(lp, OPER_EQU, &redFrom, 0); SCRIPT_SKIP_SPACES - float maxValue; + TS_FLOAT maxValue; lp = GetNumericArgument(lp, OPER_EQU, &maxValue, 0); SCRIPT_SKIP_SPACES - float redTo = maxValue; - float yellowTo = redFrom; + TS_FLOAT redTo = maxValue; + TS_FLOAT yellowTo = redFrom; snprintf_P(options, sizeof(options), SCRIPT_MSG_GAUGEOPT, (uint32_t)maxValue, (uint32_t)redFrom, (uint32_t)redTo, (uint32_t)yellowFrom, (uint32_t)yellowTo); } @@ -10690,7 +11033,7 @@ void IRAM_ATTR fast_mux_irq() { /* uint8_t pin nr, 0x40 = value, 0x80 = next */ -int32_t fast_mux(uint32_t flag, uint32_t time, float *buf, uint32_t len) { +int32_t fast_mux(uint32_t flag, uint32_t time, TS_FLOAT *buf, uint32_t len) { int32_t retval; if (!flag) { if (len > MUX_SIZE) { @@ -10839,14 +11182,14 @@ int32_t url2file(uint8_t fref, char *url) { HTTPClient http; int32_t httpCode = 0; String weburl = "http://"+UrlEncode(url); - //for (uint32_t retry = 0; retry < 15; retry++) { + for (uint32_t retry = 0; retry < 3; retry++) { http.begin(http_client, weburl); delay(100); httpCode = http.GET(); - //if (httpCode > 0) { - // break; - //} - //} + if (httpCode >= 0) { + break; + } + } if (httpCode < 0) { AddLog(LOG_LEVEL_INFO,PSTR("HTTP error %d = %s"), httpCode, http.errorToString(httpCode).c_str()); } @@ -10939,27 +11282,74 @@ int32_t http_req(char *host, char *request) { #ifdef SCRIPT_GET_HTTPS_JP + +#ifdef TESLA_POWERWALL +Powerwall powerwall = Powerwall(); + +int32_t call2pwl(const char *url) { + uint8_t debug = 0; + if (*url == 'D') { + url++; + debug = 1; + } + String cookie = powerwall.AuthCookie(); + if (*url == 'N') { + url++; + cookie = ""; + } + String result = powerwall.GetRequest(String(url), cookie); + //AddLog(LOG_LEVEL_INFO, PSTR("PWL: result: %s"), result.c_str()); + + // shrink data size because it exceeds json parser maxsize + result.replace("communication_time", "ct"); + result.replace("instant", "i"); + result.replace("apparent", "a"); + result.replace("reactive", "r"); + if (result.length()>4095) { + AddLog(LOG_LEVEL_INFO, PSTR("PWL: result overflow: %d"), result.length()); + } + + // meter aggregates has also too many tokens + char *cp = (char*)result.c_str(); + if (!strncmp_P(cp, PSTR("{\"site\""), 7)) { + // split into 2 sets + char *sp = strstr_P(cp, PSTR(",\"load\":")); + if (sp) { + *sp = '}'; + *(sp + 1 ) = 0; + if (debug) { + AddLog(LOG_LEVEL_INFO, PSTR("PWL: result 1: %s"), cp); + } + Run_Scripter(">jp", 3, cp); + *sp = '{'; + *(sp + 1 ) = '\"'; + if (debug) { + AddLog(LOG_LEVEL_INFO, PSTR("PWL: result 2: %s"), sp); + } + Run_Scripter(">jp", 3, sp); + } + } else { + if (debug) { + AddLog(LOG_LEVEL_INFO, PSTR("PWL: result: %s"), result.c_str()); + } + Run_Scripter(">jp", 3, result.c_str()); + } + return 0; +} +#endif // TESLA_POWERWALL + + #ifdef ESP8266 #include "WiFiClientSecureLightBearSSL.h" #else #include #endif //ESP8266 -#ifdef TESLA_POWERWALL -Powerwall powerwall = Powerwall(); -String authCookie = ""; -#endif - -// get tesla powerwall info page json string +// get https info page json string uint32_t call2https(const char *host, const char *path) { //if (TasmotaGlobal.global_state.wifi_down) return 1; uint32_t status = 0; -#ifdef TESLA_POWERWALL -// authCookie = powerwall.getAuthCookie(); -// return 0; -#endif - #ifdef ESP32 WiFiClientSecure *httpsClient; httpsClient = new WiFiClientSecure; @@ -10971,28 +11361,7 @@ uint32_t call2https(const char *host, const char *path) { httpsClient->setTimeout(2000); httpsClient->setInsecure(); -#if 0 - File file = ufsp->open("/tesla.cer", FS_FILE_READ); - uint16_t fsize = 0; - char *cert = 0; - if (file) { - fsize = file.size(); - if (fsize) { - cert = (char*)malloc(fsize +2); - if (cert) { - file.read((uint8_t*)cert, fsize); - file.close(); - httpsClient->setCACert(cert); - } - AddLog(LOG_LEVEL_INFO,PSTR(">>> cert %d"),fsize); - } - } else { - httpsClient->setCACert(root_ca); - } -#endif - - - AddLog(LOG_LEVEL_INFO,PSTR(">>> host %s"),host); + // AddLog(LOG_LEVEL_INFO,PSTR(">>> host %s"),host); uint32_t retry = 0; while ((!httpsClient->connect(host, 443)) && (retry < 10)) { @@ -11002,36 +11371,9 @@ uint32_t call2https(const char *host, const char *path) { if (retry == 10) { return 2; } - AddLog(LOG_LEVEL_INFO,PSTR("connected")); + AddLog(LOG_LEVEL_DEBUG,PSTR("connected")); -String request; -#if 0 - - File file = ufsp->open("/login.txt", FS_FILE_READ); - uint16_t fsize = 0; - char *cert = 0; - if (file) { - fsize = file.size(); - if (fsize) { - cert = (char*)calloc(fsize +2, 1); - if (cert) { - file.read((uint8_t*)cert, fsize); - file.close(); - //httpsClient->setCACert(cert); - } - AddLog(LOG_LEVEL_INFO,PSTR(">>> cert %d"),fsize); - } - } - - request = String("POST ") + "/api/login/Basic" + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + cert + "\r\n" + "Content-Type: application/json" + "\r\n"; - httpsClient->print(request); - AddLog(LOG_LEVEL_INFO,PSTR(">>> post request %s"),(char*)request.c_str()); - - String line = httpsClient->readStringUntil('\n'); - AddLog(LOG_LEVEL_INFO,PSTR(">>> post response 1a %s"),(char*)line.c_str()); - line = httpsClient->readStringUntil('\n'); - AddLog(LOG_LEVEL_INFO,PSTR(">>> post response 1b %s"),(char*)line.c_str()); -#endif + String request; request = String("GET ") + path + " HTTP/1.1\r\n" + @@ -11220,7 +11562,7 @@ int32_t lvgl_test(char **lpp, int32_t p) { char *lp = *lpp; lv_obj_t *obj; lv_obj_t *label; - float xp, yp, xs, ys, min, max; + TS_FLOAT xp, yp, xs, ys, min, max; lv_meter_scale_t * scale; lv_meter_indicator_t * indic; char str[SCRIPT_MAXSSIZE]; @@ -11627,7 +11969,7 @@ bool Xdrv10(uint32_t function) if (EEP_INIT(EEP_SCRIPT_SIZE)) { // found 32kb eeprom, char *script; - if (EEP_SCRIPT_SIZE != SPECIAL_EEPMODE_SIZE) { +#if EEP_SCRIPT_SIZE0) glob_script_mem.script_ram[len_decompressed] = 0; if (ucs) free(ucs); - - } +#endif // EEP_SCRIPT_SIZE==SPI_FLASH_2SEC_SIZE +#endif // EEP_SCRIPT_SIZErules[0]; @@ -11688,7 +12042,7 @@ bool Xdrv10(uint32_t function) bitWrite(Settings->rule_once, 7, 1); #ifdef USE_BUTTON_EVENT - for (uint32_t cnt = 0; cnt < MAX_KEYS_SET; cnt++) { + for (uint32_t cnt = 0; cnt < MAX_KEYS; cnt++) { glob_script_mem.script_button[cnt] = -1; } #endif //USE_BUTTON_EVENT @@ -11724,7 +12078,9 @@ bool Xdrv10(uint32_t function) if (bitRead(Settings->rule_enabled, 0)) { set_callbacks(); Run_Scripter1(">B\n", 3, 0); +#ifdef USE_WEBSERVER script_set_web_pages(); +#endif #if defined(USE_SCRIPT_HUE) && defined(USE_WEBSERVER) && defined(USE_EMULATION) && defined(USE_EMULATION_HUE) && defined(USE_LIGHT) Script_Check_Hue(0); #endif //USE_SCRIPT_HUE @@ -11879,6 +12235,8 @@ bool Xdrv10(uint32_t function) #endif break; + case FUNC_NETWORK_UP: + break; } return result; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino index 117bebc83..7637e8259 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino @@ -78,96 +78,81 @@ void CmndDrvText(void) { * Driver Settings load and save \*********************************************************************************************/ -uint32_t DrvDemoSettingsCrc32(void) { - // Use Tasmota CRC calculation function - return GetCfgCrc32((uint8_t*)&DrvDemoSettings +4, sizeof(DrvDemoSettings) -4); // Skip crc32 -} - -void DrvDemoSettingsDefault(void) { - // Init default values in case file is not found +void DrvDemoSettingsLoad(bool erase) { + // Called from FUNC_PRE_INIT (erase = 0) once at restart + // Called from FUNC_RESET_SETTINGS (erase = 1) after command reset 4, 5, or 6 + // *** Start init default values in case file is not found *** AddLog(LOG_LEVEL_INFO, PSTR("DRV: " D_USE_DEFAULTS)); memset(&DrvDemoSettings, 0x00, sizeof(DrvDemoSettings)); DrvDemoSettings.version = DRV_DEMO_VERSION; // Init any other parameter in struct DrvDemoSettings snprintf_P(DrvDemoSettings.drv_text[0], sizeof(DrvDemoSettings.drv_text[0]), PSTR("Azalea")); -} -void DrvDemoSettingsDelta(void) { - // Fix possible setting deltas - - if (DrvDemoSettings.version != DRV_DEMO_VERSION) { // Fix version dependent changes - - if (Settings->version < 0x01010100) { - AddLog(LOG_LEVEL_INFO, PSTR("DRV: Update oldest version restore")); - - } - if (Settings->version < 0x01010101) { - AddLog(LOG_LEVEL_INFO, PSTR("DRV: Update old version restore")); - - } - - // Set current version and save settings - DrvDemoSettings.version = DRV_DEMO_VERSION; - DrvDemoSettingsSave(); - } -} - -void DrvDemoSettingsLoad(void) { - // Called from FUNC_PRE_INIT once at restart - - // Init default values in case file is not found - DrvDemoSettingsDefault(); + // *** End Init default values *** +#ifndef USE_UFILESYS + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Demo use defaults as file system not enabled")); +#else // Try to load file /.drvset122 char filename[20]; // Use for sensors: // snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_122); // Use for drivers: snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_122); - - AddLog(LOG_LEVEL_INFO, PSTR("DRV: About to load settings from file %s"), filename); - -#ifdef USE_UFILESYS - if (TfsLoadFile(filename, (uint8_t*)&DrvDemoSettings, sizeof(DrvDemoSettings))) { - // Fix possible setting deltas - DrvDemoSettingsDelta(); - } else { - // File system not ready: No flash space reserved for file system - AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or file not found")); + if (erase) { + TfsDeleteFile(filename); // Use defaults } -#else - AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not enabled")); -#endif // USE_UFILESYS + else if (TfsLoadFile(filename, (uint8_t*)&DrvDemoSettings, sizeof(DrvDemoSettings))) { + if (DrvDemoSettings.version != DRV_DEMO_VERSION) { // Fix version dependent changes - DrvDemoSettings.crc32 = DrvDemoSettingsCrc32(); + // *** Start fix possible setting deltas *** + if (Settings->version < 0x01010100) { + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Update oldest version restore")); + + } + if (Settings->version < 0x01010101) { + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Update old version restore")); + + } + + // *** End setting deltas *** + + // Set current version and save settings + DrvDemoSettings.version = DRV_DEMO_VERSION; + DrvDemoSettingsSave(); + } + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Demo loaded from file")); + } + else { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_INFO, PSTR("CFG: Demo use defaults as file system not ready or file not found")); + } +#endif // USE_UFILESYS } void DrvDemoSettingsSave(void) { // Called from FUNC_SAVE_SETTINGS every SaveData second and at restart - - if (DrvDemoSettingsCrc32() != DrvDemoSettings.crc32) { +#ifdef USE_UFILESYS + uint32_t crc32 = GetCfgCrc32((uint8_t*)&DrvDemoSettings +4, sizeof(DrvDemoSettings) -4); // Skip crc32 + if (crc32 != DrvDemoSettings.crc32) { // Try to save file /.drvset122 - DrvDemoSettings.crc32 = DrvDemoSettingsCrc32(); + DrvDemoSettings.crc32 = crc32; char filename[20]; // Use for sensors: // snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_122); // Use for drivers: snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_122); - - AddLog(LOG_LEVEL_INFO, PSTR("DRV: About to save settings to file %s"), filename); - -#ifdef USE_UFILESYS - if (!TfsSaveFile(filename, (const uint8_t*)&DrvDemoSettings, sizeof(DrvDemoSettings))) { + if (TfsSaveFile(filename, (const uint8_t*)&DrvDemoSettings, sizeof(DrvDemoSettings))) { + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Demo saved to file")); + } else { // File system not ready: No flash space reserved for file system - AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or unable to save file")); + AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: ERROR Demo file system not ready or unable to save file")); } -#else - AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not enabled")); -#endif // USE_UFILESYS } +#endif // USE_UFILESYS } /*********************************************************************************************\ @@ -178,6 +163,9 @@ bool Xdrv122(uint32_t function) { bool result = false; switch (function) { + case FUNC_RESET_SETTINGS: + DrvDemoSettingsLoad(1); + break; case FUNC_SAVE_SETTINGS: DrvDemoSettingsSave(); break; @@ -185,7 +173,7 @@ bool Xdrv122(uint32_t function) { result = DecodeCommand(kDrvDemoCommands, DrvDemoCommand); break; case FUNC_PRE_INIT: - DrvDemoSettingsLoad(); + DrvDemoSettingsLoad(0); break; case FUNC_SAVE_BEFORE_RESTART: // !!! DO NOT USE AS IT'S FUNCTION IS BETTER HANDLED BY FUNC_SAVE_SETTINGS !!! diff --git a/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino b/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino index 5a02108eb..fd4e99cf7 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino @@ -60,6 +60,7 @@ #define D_CMND_I2CSTRETCH "I2CStretch" #define D_CMND_I2CCLOCK "I2CClock" #define D_CMND_SERBUFF "SerBufSize" +#define D_CMND_SOSET "SOSet" const char kDebugCommands[] PROGMEM = "|" // No prefix D_CMND_MEMDUMP "|" D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|" @@ -77,8 +78,9 @@ const char kDebugCommands[] PROGMEM = "|" // No prefix #endif D_CMND_FLASHDUMP "|" D_CMND_FLASHMODE "|" D_CMND_FREEMEM"|" D_CMND_HELP "|" D_CMND_RTCDUMP "|" #ifdef USE_I2C - D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK + D_CMND_I2CWRITE "|" D_CMND_I2CREAD "|" D_CMND_I2CSTRETCH "|" D_CMND_I2CCLOCK "|" #endif + D_CMND_SOSET ; void (* const DebugCommand[])(void) PROGMEM = { @@ -97,8 +99,9 @@ void (* const DebugCommand[])(void) PROGMEM = { #endif &CmndFlashDump, &CmndFlashMode, &CmndFreemem, &CmndHelp, &CmndRtcDump, #ifdef USE_I2C - &CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock + &CmndI2cWrite, &CmndI2cRead, &CmndI2cStretch, &CmndI2cClock, #endif + &CmndSoSet }; uint32_t CPU_loops = 0; @@ -209,23 +212,41 @@ extern "C" { extern cont_t* g_pcont; } -void DebugFreeMem(void) -{ +void DebugFreeMem(void) { register uint32_t *sp asm("a1"); AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), 4 * (sp - g_pcont->stack), XdrvMailbox.data); } +uint32_t FreeStack(void) { + register uint32_t *sp asm("a1"); + return 4 * (sp - g_pcont->stack); +} + +void AddLogMem(const char* function) { + register uint32_t *sp asm("a1"); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "== %s FreeRam %d, FreeStack %d"), function, ESP.getFreeHeap(), 4 * (sp - g_pcont->stack)); +} + #endif // ESP8266 #ifdef ESP32 -void DebugFreeMem(void) -{ +void DebugFreeMem(void) { register uint8_t *sp asm("a1"); AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "FreeRam %d, FreeStack %d (%s)"), ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL), XdrvMailbox.data); } +uint32_t FreeStack(void) { + register uint8_t *sp asm("a1"); + return sp - pxTaskGetStackStart(NULL); +} + +void AddLogMem(const char* function) { + register uint8_t *sp asm("a1"); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "== %s FreeRam %d, FreeStack %d"), function, ESP.getFreeHeap(), sp - pxTaskGetStackStart(NULL)); +} + #endif // ESP8266 - ESP32 /*******************************************************************************************/ @@ -724,6 +745,52 @@ void CmndI2cClock(void) } #endif // USE_I2C +void CmndSoSet(void) { + // Set option data as 32-bit hex value + // SoSet1 0x5400401B + if ((XdrvMailbox.index >= 1) && (XdrvMailbox.index <= 5)) { + uint32_t option = XdrvMailbox.index; + uint32_t data; + switch (option) { + case 1: + data = Settings->flag.data; // SetOption0 .. 31 + break; + case 2: + data = Settings->flag3.data; // SetOption50 .. 81 + break; + case 3: + data = Settings->flag4.data; // SetOption82 .. 113 + break; + case 4: + data = Settings->flag5.data; // SetOption114 .. 145 + break; + case 5: + data = Settings->flag6.data; // SetOption146 .. 177 + } + if (XdrvMailbox.data_len > 0) { + char *p; + data = strtoul(XdrvMailbox.data, &p, 0); // decimal, octal (0) or hex (0x) + switch (option) { + case 1: + Settings->flag.data = data; // SetOption0 .. 31 + break; + case 2: + Settings->flag3.data = data; // SetOption50 .. 81 + break; + case 3: + Settings->flag4.data = data; // SetOption82 .. 113 + break; + case 4: + Settings->flag5.data = data; // SetOption114 .. 145 + break; + case 5: Settings->flag6.data = data; // SetOption146 .. 177 + } +// TasmotaGlobal.restart_flag = 2; // Activate some SetOptions + } + Response_P(PSTR("{\"%s%d\":\"%08X\"}"), XdrvMailbox.command, XdrvMailbox.index, data); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino index cd5bcb71b..3df0f4ff3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino @@ -114,11 +114,11 @@ void TasDiscoverMessage(void) { #ifdef USE_SHUTTER if (Settings->flag3.shutter_mode) { - for (uint32_t k = 0; k < MAX_SHUTTERS; k++) { - if (Settings->shutter_startrelay[k] > 0) { - Shutter[Settings->shutter_startrelay[k]-1] = Shutter[Settings->shutter_startrelay[k]] = 1; + for (uint32_t k = 0; k < TasmotaGlobal.shutters_present; k++) { + if (ShutterGetStartRelay(k) > 0) { + Shutter[ShutterGetStartRelay(k)-1] = Shutter[ShutterGetStartRelay(k)] = 1; } else { - // terminate loop at first INVALID Settings->shutter_startrelay[i]. + // terminate loop at first INVALID ShutterGetStartRelay(k). break; } } @@ -199,7 +199,7 @@ void TasDiscoverMessage(void) { light_controller_isCTRGBLinked, light_subtype); - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + for (uint32_t i = 0; i < tmax(TasmotaGlobal.shutters_present, MAX_SHUTTERS); i++) { #ifdef USE_SHUTTER ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), Settings->shutter_options[i]); #else @@ -209,12 +209,12 @@ void TasDiscoverMessage(void) { ResponseAppend_P(PSTR("]," // Shutter Options (end) "\"sht\":[")); // Shutter Tilt (start) - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + for (uint32_t i = 0; i < tmax(TasmotaGlobal.shutters_present, MAX_SHUTTERS); i++) { #ifdef USE_SHUTTER ResponseAppend_P(PSTR("%s[%d,%d,%d]"), (i > 0 ? "," : ""), - Settings->shutter_tilt_config[0][i], - Settings->shutter_tilt_config[1][i], - Settings->shutter_tilt_config[2][i]); + ShutterGetTiltConfig(0,i), + ShutterGetTiltConfig(1,i), + ShutterGetTiltConfig(2,i)); #else ResponseAppend_P(PSTR("%s[0,0,0]"), (i > 0 ? "," : "")); #endif // USE_SHUTTER diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino index 2790bade4..71a729c41 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino @@ -308,11 +308,11 @@ void HassDiscoverMessage(void) { #ifdef USE_SHUTTER if (Settings->flag3.shutter_mode) { - for (uint32_t k = 0; k < MAX_SHUTTERS; k++) { - if (Settings->shutter_startrelay[k] > 0) { - Shutter[Settings->shutter_startrelay[k]-1] = Shutter[Settings->shutter_startrelay[k]] = 1; + for (uint32_t k = 0; k < TasmotaGlobal.shutters_present; k++) { + if (ShutterGetStartRelay(k) > 0) { + Shutter[ShutterGetStartRelay(k)-1] = Shutter[ShutterGetStartRelay(k)] = 1; } else { - // terminate loop at first INVALID Settings->shutter_startrelay[i]. + // terminate loop at first INVALID ShutterGetStartRelay(k). break; } } @@ -393,7 +393,7 @@ void HassDiscoverMessage(void) { light_controller_isCTRGBLinked, light_subtype); - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + for (uint32_t i = 0; i < tmax(TasmotaGlobal.shutters_present, MAX_SHUTTERS); i++) { #ifdef USE_SHUTTER ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), Settings->shutter_options[i]); #else @@ -403,12 +403,12 @@ void HassDiscoverMessage(void) { ResponseAppend_P(PSTR("]," // Shutter Options (end) "\"sht\":[")); // Shutter Tilt (start) - for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + for (uint32_t i = 0; i < tmax(TasmotaGlobal.shutters_present, MAX_SHUTTERS); i++) { #ifdef USE_SHUTTER ResponseAppend_P(PSTR("%s[%d,%d,%d]"), (i > 0 ? "," : ""), - Settings->shutter_tilt_config[0][i], - Settings->shutter_tilt_config[1][i], - Settings->shutter_tilt_config[2][i]); + ShutterGetTiltConfig(0,i), + ShutterGetTiltConfig(1,i), + ShutterGetTiltConfig(2,i)); #else ResponseAppend_P(PSTR("%s[0,0,0]"), (i > 0 ? "," : "")); #endif // USE_SHUTTER diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino index bbd9802aa..47bfd7c62 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino @@ -1875,10 +1875,10 @@ void DisplayInitDriver(void) { for (uint8_t count = 0; count < NUM_GRAPHS; count++) { graph[count] = 0; } #endif - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); if (!PinUsed(GPIO_BACKLIGHT)) { if (TasmotaGlobal.light_type && (4 == Settings->display_model)) { - TasmotaGlobal.devices_present--; // Assume PWM channel is used for backlight + UpdateDevicesPresent(-1); // Assume PWM channel is used for backlight } } disp_device = TasmotaGlobal.devices_present; @@ -2147,7 +2147,7 @@ void CmndDisplayText(void) { #ifndef USE_DISPLAY_MODES1TO5 DisplayText(); #else - if(Settings->display_model == 15) { + if(Settings->display_model == 15 || Settings->display_model == 20) { XdspCall(FUNC_DISPLAY_SEVENSEG_TEXT); } else if (!Settings->display_mode) { DisplayText(); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino index bd316122e..f71318c4d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino @@ -92,8 +92,11 @@ struct TUYA { uint32_t ignore_dimmer_cmd_timeout = 0; // Time until which received dimmer commands should be ignored bool ignore_tuyareceived = false; // When a modeset changes ignore stat bool active; + uint32_t time_last_cmd; // to compute timeout on response and not sending another message } Tuya; +#define TUYA_CMD_TIMEOUT 200 + #define D_JSON_TUYA_MCU_RECEIVED "TuyaReceived" #define D_PRFX_TUYA "Tuya" @@ -477,6 +480,7 @@ void TuyaSendCmd(uint8_t cmd, uint8_t payload[] = nullptr, uint16_t payload_len } TuyaSerial->write(checksum); TuyaSerial->flush(); + Tuya.time_last_cmd = millis() | 1; // cheap trick to avoid 0 snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x\""), log_data, checksum); AddLogData(LOG_LEVEL_DEBUG, log_data); } @@ -1181,13 +1185,13 @@ bool TuyaModuleSelected(void) { if ((Settings->tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1 && Settings->tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8 ) || (Settings->tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1_INV && Settings->tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8_INV )) { relaySet = true; - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); } } if (!relaySet && TuyaGetDpId(TUYA_MCU_FUNC_DUMMY) == 0) { //by default the first relay is created automatically the dummy let remove it if not needed TuyaAddMcuFunc(TUYA_MCU_FUNC_REL1, 1); - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); SettingsSaveAll(); } @@ -1287,6 +1291,7 @@ void TuyaSerialInput(void) uint8_t dpDataType = 0; char DataStr[15]; bool isCmdToSuppress = false; + Tuya.time_last_cmd = 0; if (len > 0) { ResponseAppend_P(PSTR(",\"CmndData\":\"%s\""), ToHex_P((unsigned char*)&Tuya.buffer[6], len, hex_char, sizeof(hex_char))); @@ -1416,7 +1421,9 @@ uint8_t TuyaGetTuyaWifiState(void) { break; } - if (MqttIsConnected()) { + // When Wifi is connected, Say "connected to cloud" if mqtt is disabled or mqtt is connected + // avoid MCU to resets ESP to desperately get state 4 while MQTT is not enabled + if ((3 == wifi_state) && (!Settings->flag.mqtt_enabled || MqttIsConnected())) { wifi_state = 0x04; } @@ -1567,7 +1574,7 @@ void TuyaSensorsShow(bool json) case 82: case 83: case 84: - WSContentSend_PD(PSTR("{s}Timer%d{m}%d{e}"), (sensor-80), Tuya.Sensors[sensor-71]); // No UoM for timers since they can be sec or min + WSContentSend_PD(PSTR("{s}Timer%d{m}%u{e}"), (sensor-80), Tuya.Sensors[sensor-71]); // No UoM for timers since they can be sec or min break; } } @@ -1650,6 +1657,12 @@ bool Xdrv16(uint32_t function) { result = TuyaButtonPressed(); break; case FUNC_EVERY_SECOND: + if (Tuya.time_last_cmd) { + if ((millis()-Tuya.time_last_cmd) < TUYA_CMD_TIMEOUT) + break; // don't send anything if we are already waiting for an answer + else + Tuya.time_last_cmd = 0; + } if (TuyaSerial && Tuya.wifi_state != TuyaGetTuyaWifiState()) { TuyaSetWifiLed(); } if (!Tuya.low_power_mode) { Tuya.heartbeat_timer++; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino index 6c3eb15d5..24370ef8c 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino @@ -1981,13 +1981,13 @@ bool TuyaModuleSelected(void) { if ((Settings->tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1 && Settings->tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8 ) || (Settings->tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1_INV && Settings->tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8_INV )) { relaySet = true; - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); } } if (!relaySet && TuyaGetDpId(TUYA_MCU_FUNC_DUMMY) == 0) { //by default the first relay is created automatically the dummy let remove it if not needed TuyaAddMcuFunc(TUYA_MCU_FUNC_REL1, 1); - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); SettingsSaveAll(); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino b/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino index 674ee9b3c..e070e5d82 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino @@ -86,7 +86,7 @@ void ArmtronixRequestState(void) bool ArmtronixModuleSelected(void) { - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); TasmotaGlobal.light_type = LT_SERIAL2; return true; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino index d23058b39..69d0a69c0 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino @@ -196,7 +196,7 @@ void PS16DZInit(void) bool PS16DZModuleSelected(void) { - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); TasmotaGlobal.light_type = LT_SERIAL1; return true; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino index dda38daf8..3efd52d91 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino @@ -1395,15 +1395,21 @@ void Z_SendSimpleDescReq(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluste // Iterate among // void Z_SendDeviceInfoRequest(uint16_t shortaddr) { - ZCLFrame zcl(4); // message is 4 bytes + ZCLFrame zcl(12); // message is 12 bytes zcl.shortaddr = shortaddr; - zcl.cluster = 0; + zcl.cluster = 0x0000; zcl.cmd = ZCL_READ_ATTRIBUTES; zcl.clusterSpecific = false; zcl.needResponse = true; zcl.direct = false; // discover route zcl.payload.add16(0x0005); zcl.payload.add16(0x0004); + // Tuya needs a magic spell reading more attributes + // cf https://github.com/zigpy/zha-device-handlers/issues/2042 + zcl.payload.add16(0x0000); // Manufacturer Name + zcl.payload.add16(0x0001); // Application Version + zcl.payload.add16(0x0007); // Power Source + zcl.payload.add16(0xfffe); // Unknown zigbeeZCLSendCmd(zcl); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino new file mode 100644 index 000000000..6b3499f4d --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino @@ -0,0 +1,2313 @@ +/* + xdrv_27_esp32_shutter.ino - Shutter/Blind support for Tasmota + + Copyright (C) 2023 Stefan Bode + + 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 . +*/ + +// Start temporarly extra tests for overriding USE_SHUTTER_ESP32 **** +// Remove once tests complete +#if defined(ESP32) && defined(USE_SHUTTER_ESP32) +// End ************************************************************** + +//#ifdef ESP32 +#ifdef USE_SHUTTER +/*********************************************************************************************\ + * Shutter or Blind support using two consecutive relays + * Shutters for ESP32 with max eight shutters using more RAM and Settings from filesystem +\*********************************************************************************************/ + +#define XDRV_27 27 +#ifndef SHUTTER_STEPPER + #define SHUTTER_STEPPER +#endif + +#ifndef SHUTTER_RELAY_OPERATION_TIME + #define SHUTTER_RELAY_OPERATION_TIME 100 // wait for direction relay 0.1sec before power up main relay +#endif + +#ifndef MOTOR_STOP_TIME + #define MOTOR_STOP_TIME 500 // wait 0.5 second after stop to do any other action. e.g. move in the opposite direction +#endif + +//#define SHUTTER_UNITTEST + +#define D_SHUTTER "SHUTTER" + +// Allow up to 16 shutters on ESP32 +#undef MAX_SHUTTERS_ESP32 +#define MAX_SHUTTERS_ESP32 16 + +// +const uint32_t SHUTTER_VERSION = 0x01010000; // Latest driver version (See settings deltas below) + +typedef struct { + int8_t pos; + int8_t tilt; + bool mqtt_broadcast; +} tPosition; + +typedef struct { + bool enabled; + bool mqtt_all; + uint8_t shutter_number; + tPosition position[4]; +} tButtonSettings; + +// Global structure containing shutter saved variables +struct SHUTTERSETTINGS { + uint32_t crc32; // To detect file changes + uint32_t version; // To detect driver function changes + uint8_t shutter_accuracy; + uint8_t shutter_mode; + uint16_t shutter_motorstop; + uint16_t open_velocity_max; + int8_t shutter_tilt_config[5][MAX_SHUTTERS_ESP32]; + int8_t shutter_tilt_pos[MAX_SHUTTERS_ESP32]; + uint16_t shutter_opentime[MAX_SHUTTERS_ESP32]; + uint16_t shutter_closetime[MAX_SHUTTERS_ESP32]; + int16_t shuttercoeff[5][MAX_SHUTTERS_ESP32]; + uint8_t shutter_options[MAX_SHUTTERS_ESP32]; + uint8_t shutter_set50percent[MAX_SHUTTERS_ESP32]; + uint8_t shutter_position[MAX_SHUTTERS_ESP32]; + uint8_t shutter_startrelay[MAX_SHUTTERS_ESP32]; + uint8_t shutter_motordelay[MAX_SHUTTERS_ESP32]; + uint16_t shutter_pwmrange[2][MAX_SHUTTERS_ESP32]; + tButtonSettings shutter_button[MAX_SHUTTERS_ESP32*2]; +} ShutterSettings; + +const uint16_t RESOLUTION = 1000; // incresed to 1000 in 8.5 to ramp servos +const uint8_t STEPS_PER_SECOND = 20; // FUNC_EVERY_50_MSECOND +const uint16_t pwm_servo_max = 500; +const uint16_t pwm_servo_min = 90; + +uint8_t calibrate_pos[6] = {0,30,50,70,90,100}; +uint16_t messwerte[5] = {30,50,70,90,100}; + +int32_t velocity_max = 0; +int32_t velocity_change_per_step_max = 0; +int32_t min_runtime_ms = 0; +int32_t current_stop_way = 0; +int32_t next_possible_stop_position = 0; +int32_t current_real_position = 0; +int32_t current_pwm_velocity = 0; + +const uint8_t MAX_MODES = 8; +enum Shutterposition_mode {SHT_UNDEF, SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,SHT_AUTOCONFIG}; +enum Shutterswitch_mode {SHT_SWITCH, SHT_PULSE,}; +enum ShutterButtonStates { SHT_NOT_PRESSED, SHT_PRESSED_MULTI, SHT_PRESSED_HOLD, SHT_PRESSED_IMMEDIATE, SHT_PRESSED_EXT_HOLD, SHT_PRESSED_MULTI_SIMULTANEOUS, SHT_PRESSED_HOLD_SIMULTANEOUS, SHT_PRESSED_EXT_HOLD_SIMULTANEOUS,}; + +const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|" + D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_TOGGLE "|" D_CMND_SHUTTER_TOGGLEDIR "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|" + D_CMND_SHUTTER_OPENTIME "|" D_CMND_SHUTTER_CLOSETIME "|" D_CMND_SHUTTER_RELAY "|" D_CMND_SHUTTER_MODE "|" D_CMND_SHUTTER_PWMRANGE "|" + D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_SETOPEN "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|" + D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME "|" D_CMND_SHUTTER_INVERTWEBBUTTONS "|" + D_CMND_SHUTTER_STOPOPEN "|" D_CMND_SHUTTER_STOPCLOSE "|" D_CMND_SHUTTER_STOPTOGGLE "|" D_CMND_SHUTTER_STOPTOGGLEDIR "|" D_CMND_SHUTTER_STOPPOSITION "|" D_CMND_SHUTTER_INCDEC "|" + D_CMND_SHUTTER_UNITTEST "|" D_CMND_SHUTTER_TILTCONFIG "|" D_CMND_SHUTTER_SETTILT "|" D_CMND_SHUTTER_TILTINCDEC "|" D_CMND_SHUTTER_MOTORSTOP "|" D_CMND_SHUTTER_SETUP; + +void (* const ShutterCommand[])(void) PROGMEM = { + &CmndShutterOpen, &CmndShutterClose, &CmndShutterToggle, &CmndShutterToggleDir, &CmndShutterStop, &CmndShutterPosition, + &CmndShutterOpenTime, &CmndShutterCloseTime, &CmndShutterRelay, &CmndShutterMode, &CmndShutterPwmRange, + &CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterSetOpen, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay, + &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime, &CmndShutterInvertWebButtons, + &CmndShutterStopOpen, &CmndShutterStopClose, &CmndShutterStopToggle, &CmndShutterStopToggleDir, &CmndShutterStopPosition, &CmndShutterIncDec, + &CmndShutterUnitTest,&CmndShutterTiltConfig,&CmndShutterSetTilt,&CmndShutterTiltIncDec,&CmndShutterMotorStop,&CmndShutterSetup + }; + + const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d,\"Tilt\":%d}"; + const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}"; + +#include + +Ticker TickerShutter; + +struct SHUTTER { + uint32_t time; // operating time of the shutter in 0.05sec + int32_t open_max; // max value on maximum open calculated + int32_t target_position; // position to go to + int32_t start_position; // position before a movement is started. init at start + int32_t real_position; // value between 0 and Shutter[i].open_max + uint16_t open_time; // duration to open the Shutter[i]. 112 = 11.2sec + uint16_t close_time; // duration to close the Shutter[i]. 112 = 11.2sec + uint16_t close_velocity; // in relation to open velocity. higher value = faster + int8_t direction; // 1 == UP , 0 == stop; -1 == down + int8_t lastdirection; // last direction (1 == UP , -1 == down) + uint8_t switch_mode; // how to switch relays: SHT_SWITCH, SHT_PULSE + int8_t motordelay; // initial motorstarttime in 0.05sec. Also uses for ramp at steppers and servos, negative if motor stops late + int16_t pwm_velocity; // frequency of PWN for stepper motors or PWM duty cycle change for PWM servo + uint16_t pwm_value; // dutyload of PWM 0..1023 on ESP8266 + uint16_t close_velocity_max; // maximum of PWM change during closeing. Defines velocity on opening. Steppers and Servos only + int32_t accelerator; // speed of ramp-up, ramp down of shutters with velocity control. Steppers and Servos only + int8_t tilt_config[5]; // tilt_min, tilt_max, duration, tilt_closed_value, tilt_opened_value + int8_t tilt_real_pos; // -90 to 90 + int8_t tilt_target_pos; // target positon for movements of the tilt + int8_t tilt_target_pos_override; // one time override of automatic calculation of tilt_target + int8_t tilt_start_pos; // saved start position before shutter moves + uint8_t tilt_velocity; // degree rotation per step 0.05sec + int8_t tiltmoving; // 0 operating move, 1 = operating tilt + uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position + uint16_t min_realPositionChange = 0; // minimum change of the position before the shutter operates. different for PWM and time based operations + uint16_t min_TiltChange = 0; // minimum change of the tilt before the shutter operates. different for PWM and time based operations + uint16_t last_reported_time = 0; // get information on skipped 50ms loop() slots + uint32_t last_stop_time = 0; // record the last time the relay was switched off +} Shutter[MAX_SHUTTERS_ESP32]; + +struct SHUTTERGLOBAL { + power_t RelayShutterMask = 0; // bit mask with 11 at the position of relays that belong to at least ONE shutter + power_t RelayOldMask = 0; // bitmatrix that contain the last known state of all relays. Required to detemine the manual changed relay. + power_t RelayCurrentMask = 0; // bitmatrix that contain the current state of all relays + uint8_t LastChangedRelay = 0; // Relay 1..32, 0 no change + uint8_t position_mode = 0; // how to calculate actual position: SHT_TIME, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME + uint8_t skip_relay_change; // avoid overrun at endstops + uint8_t start_reported = 0; // indicates of the shutter start was reported through MQTT JSON + uint16_t open_velocity_max = RESOLUTION; // maximum of PWM change during opening. Defines velocity on opening. Steppers and Servos only + bool callibration_run = false; // if true a callibration is running and additional measures are captured + uint8_t stopp_armed = 0; // Count each step power usage is below limit of 1 Watt +} ShutterGlobal; + +#define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B)) + +/*********************************************************************************************\ + * Driver Settings load and save +\*********************************************************************************************/ + +void ShutterSettingsDefault(void) { + // Init default values in case file is not found + + AddLog(LOG_LEVEL_INFO, PSTR("Shutter: " D_USE_DEFAULTS)); + + memset(&ShutterSettings, 0x00, sizeof(ShutterSettings)); + ShutterSettings.version = SHUTTER_VERSION; + // Init any other parameter in struct ShutterSettings + ShutterSettings.open_velocity_max = ShutterGlobal.open_velocity_max; + ShutterSettings.shutter_accuracy = Settings->shutter_accuracy; + ShutterSettings.shutter_mode = Settings->shutter_mode; + ShutterSettings.shutter_motorstop = Settings->shutter_motorstop; + for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + // copy values from settings + for (uint32_t j = 0; j < 5; j++) { + if (j<2) ShutterSettings.shutter_pwmrange[j][i] = Settings->shutter_pwmrange[j][i]; + ShutterSettings.shutter_tilt_config[j][i] = Settings->shutter_tilt_config[j][i]; + ShutterSettings.shuttercoeff[j][i] = Settings->shuttercoeff[j][i]; + } + ShutterSettings.shutter_tilt_pos[i] = Settings->shutter_tilt_pos[i]; + ShutterSettings.shutter_opentime[i] = Settings->shutter_opentime[i]; + ShutterSettings.shutter_closetime[i] = Settings->shutter_closetime[i]; + ShutterSettings.shutter_options[i] = Settings->shutter_options[i]; + ShutterSettings.shutter_set50percent[i] = Settings->shutter_set50percent[i]; + ShutterSettings.shutter_position[i] = Settings->shutter_position[i]; + ShutterSettings.shutter_startrelay[i] = Settings->shutter_startrelay[i]; + ShutterSettings.shutter_motordelay[i] = Settings->shutter_motordelay[i]; + + } + for (uint32_t i = 0; i < MAX_SHUTTER_KEYS; i++) { + ShutterSettings.shutter_button[i].shutter_number = Settings->shutter_button[i] & 0x03; + ShutterSettings.shutter_button[i].enabled = Settings->shutter_button[i] &(1<<31); + for (uint8_t j = 0; j < 4; j++) { + ShutterSettings.shutter_button[i].position[j].pos = (((Settings->shutter_button[i]>> (2+6*j))&(0x3f))-1)<<1; + ShutterSettings.shutter_button[i].position[j].tilt = -128; // -128 == DISBALED + ShutterSettings.shutter_button[i].position[j].mqtt_broadcast = ((Settings->shutter_button[i]>>(26+j))&(0x01)!=0); + } + } + for (uint32_t i = MAX_SHUTTERS; i < MAX_SHUTTERS_ESP32; i++) { + ShutterSettings.shutter_set50percent[i] = 50; + ShutterSettings.shutter_opentime[i] = 100; + ShutterSettings.shutter_closetime[i] = 100; + ShutterSettings.shutter_pwmrange[0][i] = pwm_servo_min; + ShutterSettings.shutter_pwmrange[1][i] = pwm_servo_max; + } +} + +void ShutterSettingsDelta(void) { + // Fix possible setting deltas + if (ShutterSettings.version != SHUTTER_VERSION) { // Fix version dependent changes +/* + if (ShutterSettings.version < 0x01010100) { + AddLog(LOG_LEVEL_INFO, PSTR("SHT: Update oldest version restore")); + + } + if (ShutterSettings.version < 0x01010101) { + AddLog(LOG_LEVEL_INFO, PSTR("SHT: Update old version restore")); + + } +*/ + // Set current version and save settings + ShutterSettings.version = SHUTTER_VERSION; + ShutterSettingsSave(); + } +} + +void ShutterSettingsLoad(bool erase) { + // Called from FUNC_PRE_INIT once at restart + + // Init default values in case file is not found + ShutterSettingsDefault(); + + // Try to load file /.drvset027 + char filename[20]; + // Use for sensors: +// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_27); + // Use for drivers: + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_27); + + AddLog(LOG_LEVEL_INFO, PSTR("SHUTTER: About to load settings from file %s"), filename); + +#ifdef USE_UFILESYS + if (erase) { + TfsDeleteFile(filename); // Use defaults + } + else if (TfsLoadFile(filename, (uint8_t*)&ShutterSettings, sizeof(ShutterSettings))) { + // Fix possible setting deltas + ShutterSettingsDelta(); + } else { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or file not found")); + + } +#else + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not enabled")); +#endif // USE_UFILESYS + +} + +void ShutterSettingsSave(void) { + // Called from FUNC_SAVE_SETTINGS every SaveData second and at restart + uint32_t crc32 = GetCfgCrc32((uint8_t*)&ShutterSettings +4, sizeof(ShutterSettings) -4); // Skip crc32 + if (crc32 != ShutterSettings.crc32) { + // Try to save file /.drvset027 + ShutterSettings.crc32 = crc32; + + char filename[20]; + // Use for sensors: +// snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_SENSOR), XSNS_27); + // Use for drivers: + snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_27); + + AddLog(LOG_LEVEL_INFO, PSTR("SHUTTER: About to save settings to file %s"), filename); + +#ifdef USE_UFILESYS + if (!TfsSaveFile(filename, (const uint8_t*)&ShutterSettings, sizeof(ShutterSettings))) { + // File system not ready: No flash space reserved for file system + AddLog(LOG_LEVEL_INFO, PSTR("DRV: ERROR File system not ready or unable to save file")); + } +#else + AddLog(LOG_LEVEL_INFO, PSTR("SHUTTER: ERROR File system not enabled")); +#endif // USE_UFILESYS + } +} + +uint8_t ShutterGetRelayNoFromBitfield(power_t number) { + int position = 0; + while (number != 0) { + position++; + if (number & 1) return position; + number >>= 1; + } + return 0; // return 0 if no relay found +} + +bool ShutterStatus(void) { + if (Settings->flag3.shutter_mode) { // SetOption80 - (Shutter) Enable shutter support (1) + Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS13_SHUTTER "\":{")); + for (uint32_t i = 0; i < MAX_SHUTTERS_ESP32; i++) { + if (0 == ShutterSettings.shutter_startrelay[i]) { break; } + if (i > 0) { ResponseAppend_P(PSTR(",")); } + ResponseAppend_P(PSTR("\"" D_STATUS13_SHUTTER "%d\":{\"Relay1\":%d,\"Relay2\":%d,\"Open\":%d,\"Close\":%d," + "\"50perc\":%d,\"Delay\":%d,\"Opt\":\"%s\"," + "\"Calib\":[%d,%d,%d,%d,%d]," + "\"Mode\":\"%d\"}"), + i, ShutterSettings.shutter_startrelay[i], ShutterSettings.shutter_startrelay[i] +1, ShutterSettings.shutter_opentime[i], ShutterSettings.shutter_closetime[i], + ShutterSettings.shutter_set50percent[i], ShutterSettings.shutter_motordelay[i], GetBinary8(Settings->shutter_options[i], 4).c_str(), + ShutterSettings.shuttercoeff[0][i], ShutterSettings.shuttercoeff[1][i], ShutterSettings.shuttercoeff[2][i], ShutterSettings.shuttercoeff[3][i], ShutterSettings.shuttercoeff[4][i], + ShutterSettings.shutter_mode); + } + ResponseJsonEndEnd(); + return true; + } + return false; +} + +void ShutterLogPos(uint32_t i) +{ + char stemp2[10]; + dtostrfd((float)Shutter[i].time / STEPS_PER_SECOND, 2, stemp2); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Real %d, Start %d, Stop %d, Dir %d, Delay %d, Rtc %s [s], Freq %d, PWM %d, Tilt %d"), + i+1, Shutter[i].real_position, Shutter[i].start_position, Shutter[i].target_position, Shutter[i].direction, Shutter[i].motordelay, stemp2, + Shutter[i].pwm_velocity, Shutter[i].pwm_value,Shutter[i].tilt_real_pos); +} + +uint8_t ShutterGetStartRelay(uint8_t index) { + return ShutterSettings.shutter_startrelay[index]; +} + +int8_t ShutterGetTiltConfig(uint8_t config_idx,uint8_t index) { + return Shutter[index].tilt_config[config_idx]; +} + +void ExecuteCommandPowerShutter(uint32_t device, uint32_t state, uint32_t source) +{ + // first implementation for virtual relays. Avoid switching relay numbers that do not exist. + if (device <= TasmotaGlobal.devices_present) ExecuteCommandPower(device,state,source); +} + +void ShutterUpdateVelocity(uint8_t i) +{ + // No Logging allowed. Part of RTC Timer + // will be calles through RTC every 50ms. + // do not allow accellerator to stop movement + Shutter[i].pwm_velocity = tmax(velocity_change_per_step_max, Shutter[i].pwm_velocity+Shutter[i].accelerator); + Shutter[i].pwm_velocity = tmin(Shutter[i].direction==1 ? ShutterGlobal.open_velocity_max : Shutter[i].close_velocity_max,Shutter[i].pwm_velocity); + // respect hard coded SDK limit of PWM_MIN on PWM frequency. + if (ShutterGlobal.position_mode == SHT_COUNTER) { + Shutter[i].pwm_velocity = tmax(PWM_MIN,Shutter[i].pwm_velocity); + } +} + +void ShutterRtc50mS(void) +{ +#ifdef ESP32 + bool pwm_apply = false; // ESP32 only, do we need to apply PWM changes +#endif + // No Logging allowed. RTC Timer + for (uint8_t i = 0; i < TasmotaGlobal.shutters_present; i++) { + if (Shutter[i].direction) { + // update position data before increasing counter + Shutter[i].real_position = ShutterCalculatePosition(i); + Shutter[i].time++; + ShutterCalculateAccelerator(i); + switch (ShutterGlobal.position_mode) { + case SHT_PWM_VALUE: + ShutterUpdateVelocity(i); + Shutter[i].real_position += Shutter[i].direction > 0 ? Shutter[i].pwm_velocity : (Shutter[i].direction < 0 ? -Shutter[i].pwm_velocity : 0); + Shutter[i].pwm_value = SHT_DIV_ROUND((ShutterSettings.shutter_pwmrange[1][i]-ShutterSettings.shutter_pwmrange[0][i]) * Shutter[i].real_position , Shutter[i].open_max)+ShutterSettings.shutter_pwmrange[0][i]; + analogWrite(Pin(GPIO_PWM1, i), Shutter[i].pwm_value); + break; + + case SHT_COUNTER: + if (Shutter[i].accelerator) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Accelerator i=%d -> %d"),i, Shutter[i].accelerator); + ShutterUpdateVelocity(i); + digitalWrite(Pin(GPIO_PWM1, i), LOW); + #ifdef ESP8266 + // Convert frequency into clock cycles + uint32_t cc = microsecondsToClockCycles(1000000UL) / Shutter[i].pwm_velocity; + startWaveformClockCycles(Pin(GPIO_PWM1, i), cc/2, cc/2, 0, -1, 0, false); + #endif // ESP8266 + #ifdef ESP32 + analogWriteFreq(Shutter[i].pwm_velocity,Pin(GPIO_PWM1, i)); + TasmotaGlobal.pwm_value[i] = 512; + pwm_apply = true; + #endif // ESP32 + } + break; + } + } // if (Shutter[i].direction) + } +#ifdef ESP32 + if (pwm_apply) { PwmApplyGPIO(false); } +#endif +} + +int32_t ShutterPercentToRealPosition(int16_t percent, uint32_t index) +{ + if (ShutterSettings.shutter_set50percent[index] != 50) { + return (percent <= 5) ? ShutterSettings.shuttercoeff[2][index] * percent*10 : (ShutterSettings.shuttercoeff[1][index] * percent + (ShutterSettings.shuttercoeff[0][index]*10))*10; + } else { + int64_t realpos; + // check against DIV 0 + for (uint32_t j = 0; j < 5; j++) { + if (0 == ShutterSettings.shuttercoeff[j][index]) { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: RESET/INIT CALIBRATION MATRIX DIV 0")); + for (uint32_t k = 0; k < 5; k++) { + ShutterSettings.shuttercoeff[k][index] = SHT_DIV_ROUND(calibrate_pos[k+1] * 1000, calibrate_pos[5]); + } + } + } + for (uint32_t k = 0; k < 5; k++) { + if ((percent * 10) >= ShutterSettings.shuttercoeff[k][index]) { + realpos = SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[k+1], 100); + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Realposition TEMP1: %d, %d %%, coeff %d"), realpos, percent, ShutterSettings.shuttercoeff[k][index]); + } else { + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Shutter[%d].open_max: %d"),index, Shutter[index].open_max); + if (0 == k) { + realpos = SHT_DIV_ROUND((int64_t)percent * Shutter[index].open_max * calibrate_pos[k+1], ShutterSettings.shuttercoeff[k][index]*10 ); + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Realposition TEMP3: %d, %d %%, coeff %d"), realpos, percent, ShutterSettings.shuttercoeff[k][index]); + } else { + //uint32_t addon = ( percent*10 - ShutterSettings.shuttercoeff[k-1][index] ) * Shutter[index].open_max * (calibrate_pos[k+1] - calibrate_pos[k]) / (ShutterSettings.shuttercoeff[k][index] -ShutterSettings.shuttercoeff[k-1][index]) / 100; + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Realposition TEMP2: %d, %d %%, coeff %d"), addon, (calibrate_pos[k+1] - calibrate_pos[k]), (ShutterSettings.shuttercoeff[k][index] -ShutterSettings.shuttercoeff[k-1][index])); + realpos += SHT_DIV_ROUND(((int64_t)percent*10 - ShutterSettings.shuttercoeff[k-1][index] ) * Shutter[index].open_max * (calibrate_pos[k+1] - calibrate_pos[k]), (ShutterSettings.shuttercoeff[k][index] - ShutterSettings.shuttercoeff[k-1][index])*100); + } + break; + } + } + return realpos < 0 ? 0 : realpos; + } +} + +uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) +{ + if (realpos == -9999) { + realpos = Shutter[index].real_position; + } + if (ShutterSettings.shutter_set50percent[index] != 50) { + return (ShutterSettings.shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, ShutterSettings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-ShutterSettings.shuttercoeff[0][index]*10, ShutterSettings.shuttercoeff[1][index]); + } else { + int64_t realpercent; + for (uint32_t j = 0; j < 5; j++) { + if (realpos >= Shutter[index].open_max * calibrate_pos[j+1] / 100) { + realpercent = SHT_DIV_ROUND(ShutterSettings.shuttercoeff[j][index], 10); + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Realpercent TEMP1: %d %%, %d, coeff %d"), realpercent, realpos, Shutter[index].open_max * calibrate_pos[j+1] / 100); + } else { + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Shutter[%d].open_max: %d"),index, Shutter[index].open_max); + if (0 == j) { + realpercent = SHT_DIV_ROUND(((int64_t)realpos - SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[j], 100)) * ShutterSettings.shuttercoeff[j][index], calibrate_pos[j+1]/10*Shutter[index].open_max); + } else { + //uint16_t addon = ( realpos - (Shutter[index].open_max * calibrate_pos[j] / 100) ) * 10 * (ShutterSettings.shuttercoeff[j][index] - ShutterSettings.shuttercoeff[j-1][index]) / (calibrate_pos[j+1] - calibrate_pos[j])/Shutter[index].open_max; + //uint16_t addon = ( realpercent*10 - ShutterSettings.shuttercoeff[j-1][index] ) * Shutter[index].open_max * (calibrate_pos[j+1] - calibrate_pos[j]) / (ShutterSettings.shuttercoeff[j][index] -ShutterSettings.shuttercoeff[j-1][index]) / 100; + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Realpercent TEMP2: %d %%, delta %d, %d, coeff %d"), addon,( realpos - (Shutter[index].open_max * calibrate_pos[j] / 100) ) , (calibrate_pos[j+1] - calibrate_pos[j])* Shutter[index].open_max/100, (ShutterSettings.shuttercoeff[j][index] -ShutterSettings.shuttercoeff[j-1][index])); + realpercent += SHT_DIV_ROUND(((int64_t)realpos - SHT_DIV_ROUND(Shutter[index].open_max * calibrate_pos[j], 100)) * (ShutterSettings.shuttercoeff[j][index] - ShutterSettings.shuttercoeff[j-1][index]), (calibrate_pos[j+1] - calibrate_pos[j])/10*Shutter[index].open_max) ; + } + break; + } + } + return realpercent < 0 ? 0 : realpercent; + } +} + +void ShutterInit(void) +{ + TasmotaGlobal.shutters_present = 0; + ShutterGlobal.RelayShutterMask = 0; + //Initialize to get relay that changed + ShutterGlobal.RelayOldMask = TasmotaGlobal.power; + + + // if shutter 4 is unused + if (ShutterSettings.shutter_startrelay[MAX_SHUTTERS_ESP32 -1] == 0) { + ShutterGlobal.open_velocity_max = ShutterSettings.shuttercoeff[4][3] > 0 ? ShutterSettings.shuttercoeff[4][3] : ShutterGlobal.open_velocity_max; + } + for (uint32_t i = 0; i < MAX_SHUTTERS_ESP32; i++) { + // set startrelay to 1 on first init, but only to shutter 1. 90% usecase + if (ShutterSettings.shutter_startrelay[i] && (ShutterSettings.shutter_startrelay[i] <= 32 )) { + bool relay_in_interlock = false; + TasmotaGlobal.shutters_present++; + + // Add the two relays to the mask to knaw they belong to shutters + ShutterGlobal.RelayShutterMask |= 3 << (ShutterSettings.shutter_startrelay[i] -1) ; + + // All shutters must have same mode. Switch OR Pulse. N + switch (Settings->pulse_timer[i]) { + case 0: + Shutter[i].switch_mode = SHT_SWITCH; + break; + default: + Shutter[i].switch_mode = SHT_PULSE; + break; + } + + // Check if the relay is in an INTERLOCK group. required to set the right mode or + // verify that on SHT_TIME INTERLOCK is set + for (uint32_t j = 0; j < MAX_INTERLOCKS * Settings->flag.interlock; j++) { // CMND_INTERLOCK - Enable/disable interlock + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Interlock state i=%d %d, flag %d, Shuttermask %d, MaskedIL %d"),i, ShutterSettings.interlock[i], ShutterSettings.flag.interlock,ShutterGlobal.RelayShutterMask, ShutterSettings.interlock[i]&ShutterGlobal.RelayShutterMask); + if (Settings->interlock[j] && (Settings->interlock[j] & ShutterGlobal.RelayShutterMask)) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Relay in Interlock group")); + relay_in_interlock = true; + } + } + + if (ShutterSettings.shutter_mode == SHT_AUTOCONFIG || ShutterSettings.shutter_mode == SHT_UNDEF) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Mode undef.. calculate...")); + ShutterGlobal.position_mode = SHT_TIME; + if (!relay_in_interlock) { + // temporary to maintain old functionality + if (ShutterSettings.shutter_mode == SHT_UNDEF) { + ShutterGlobal.position_mode = SHT_TIME_UP_DOWN; + } + if (PinUsed(GPIO_PWM1, i) && PinUsed(GPIO_CNTR1, i)) { + ShutterGlobal.position_mode = SHT_COUNTER; + } + } + } else { + ShutterGlobal.position_mode = ShutterSettings.shutter_mode; + } + AddLog(LOG_LEVEL_INFO, PSTR("SHT: ShutterMode: %d"), ShutterGlobal.position_mode); + // main function for stepper and servos to control velocity and acceleration. + TickerShutter.attach_ms(50, ShutterRtc50mS ); + + // default the 50 percent should not have any impact without changing it. set to 60 + ShutterSettings.shutter_set50percent[i] = (ShutterSettings.shutter_set50percent[i] > 0) ? ShutterSettings.shutter_set50percent[i] : 50; + + // use 10 sec. as default to allow everybody to play without deep initialize + Shutter[i].open_time = ShutterSettings.shutter_opentime[i] = (ShutterSettings.shutter_opentime[i] > 0) ? ShutterSettings.shutter_opentime[i] : 100; + Shutter[i].close_time = ShutterSettings.shutter_closetime[i] = (ShutterSettings.shutter_closetime[i] > 0) ? ShutterSettings.shutter_closetime[i] : 100; + + // Update Calculation 20 because time interval is 0.05 sec ans time is in 0.1sec + Shutter[i].open_max = STEPS_PER_SECOND * RESOLUTION * Shutter[i].open_time / 10; + Shutter[i].close_velocity = Shutter[i].open_max / Shutter[i].close_time / 2 ; + + // calculate a ramp slope at the first 5 percent to compensate that shutters move with down part later than the upper part + if (ShutterSettings.shutter_set50percent[i] != 50) { + ShutterSettings.shuttercoeff[1][i] = Shutter[i].open_max/10 * (100 - ShutterSettings.shutter_set50percent[i] ) / 5000 ; + ShutterSettings.shuttercoeff[0][i] = Shutter[i].open_max/100 - (ShutterSettings.shuttercoeff[1][i] * 10); + ShutterSettings.shuttercoeff[2][i] = (int32_t)(ShutterSettings.shuttercoeff[0][i]*10 + 5 * ShutterSettings.shuttercoeff[1][i]) / 5; + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Shutter[i].open_max %d, 50perc:%d, 0:%d, 1:%d 2:%d"), i, Shutter[i].open_max, ShutterSettings.shutter_set50percent[i], ShutterSettings.shuttercoeff[0][i],ShutterSettings.shuttercoeff[1][i],ShutterSettings.shuttercoeff[2][i]); + } + ShutterGlobal.RelayShutterMask |= 3 << (ShutterSettings.shutter_startrelay[i] -1); + + Shutter[i].real_position = ShutterPercentToRealPosition(ShutterSettings.shutter_position[i], i); + + Shutter[i].start_position = Shutter[i].target_position = Shutter[i].real_position; + Shutter[i].motordelay = ShutterSettings.shutter_motordelay[i]; + Shutter[i].lastdirection = (50 < ShutterSettings.shutter_position[i]) ? 1 : -1; + + // Venetian Blind + // ensure min is smaller than max + ShutterSettings.shutter_tilt_config[2][i] = ShutterSettings.shutter_tilt_config[0][i] >= ShutterSettings.shutter_tilt_config[1][i]?0:ShutterSettings.shutter_tilt_config[2][i]; + //copy config to shutter + for (uint8_t k=0; k<5; k++) { + Shutter[i].tilt_config[k] = ShutterSettings.shutter_tilt_config[k][i]; + } + // wipe open/close position if duration is 0 + if (Shutter[i].tilt_config[2]==0) { + Shutter[i].tilt_config[3] = Shutter[i].tilt_config[4] = 0; + } + Shutter[i].tilt_target_pos = Shutter[i].tilt_real_pos = ShutterSettings.shutter_tilt_pos[i]; + + Shutter[i].tilt_velocity = Shutter[i].tilt_config[2] > 0 ? ((Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])/Shutter[i].tilt_config[2])+1 : 1; + + Shutter[i].close_velocity_max = ShutterGlobal.open_velocity_max*Shutter[i].open_time / Shutter[i].close_time; + + Shutter[i].min_realPositionChange = 2 * tmax(ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); + Shutter[i].min_TiltChange = 2 * Shutter[i].tilt_velocity; + + switch (ShutterGlobal.position_mode) { + case SHT_PWM_VALUE: + ShutterGlobal.open_velocity_max = RESOLUTION; + // Initiate pwm range with defaults if not already set. + ShutterSettings.shutter_pwmrange[0][i] = ShutterSettings.shutter_pwmrange[0][i] > 0 ? ShutterSettings.shutter_pwmrange[0][i] : pwm_servo_min; + ShutterSettings.shutter_pwmrange[1][i] = ShutterSettings.shutter_pwmrange[1][i] > 0 ? ShutterSettings.shutter_pwmrange[1][i] : pwm_servo_max; + Shutter[i].min_realPositionChange = 0; + Shutter[i].min_TiltChange = 0; + break; + case SHT_TIME: + // Test is the relays are in interlock mode. Disable shuttermode if error + if (!relay_in_interlock) { + TasmotaGlobal.shutters_present = 0, + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ERROR: Shtr%d Relays are not in INTERLOCK. Pls read documentation. Shutter DISABLE. Fix and REBOOT"), i+1); + return; + } + break; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d min realpos_chg: %d, min tilt_chg %d"), i+1, Shutter[i].min_realPositionChange, Shutter[i].min_TiltChange); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Openvel %d, Closevel: %d"), i+1, ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init. Pos %d, Inv %d, Locked %d, Endstop enab %d, webButt inv %d, Motordel: %d"), + i+1, Shutter[i].real_position, + (ShutterSettings.shutter_options[i] & 1) ? 1 : 0, (ShutterSettings.shutter_options[i] & 2) ? 1 : 0, (ShutterSettings.shutter_options[i] & 4) ? 1 : 0, (ShutterSettings.shutter_options[i] & 8) ? 1 : 0, Shutter[i].motordelay); + + } else { + // terminate loop at first INVALID Shutter[i]. + break; + } + ShutterLimitRealAndTargetPositions(i); + ShutterSettings.shutter_accuracy = 1; + ShutterSettings.shutter_mode = ShutterGlobal.position_mode; + // initialize MotorStop time with 500ms if not set + // typical not set start values are 0 and 65535 + if (ShutterSettings.shutter_motorstop > 5000 || ShutterSettings.shutter_motorstop == 0) { + ShutterSettings.shutter_motorstop = 500; + } + } +} + +void ShutterReportPosition(bool always, uint32_t index) +{ + Response_P(PSTR("{")); + uint32_t i = 0; + uint32_t n = TasmotaGlobal.shutters_present; + uint8_t shutter_running = 0; + for (i; i < n; i++) { + if (Shutter[i].direction != 0) { + shutter_running++; + } + } + + // Allow function exit if nothing to report (99.9% use case) + if (!always && !shutter_running) return; + + if( index != MAX_SHUTTERS_ESP32) { + i = index; + n = index+1; + } else { + i = 0; + } + for (i; i < n; i++) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Real Pos %d"), i+1,Shutter[i].real_position); + + if (Shutter[i].direction != 0) { + ShutterLogPos(i); + shutter_running++; + } + if (i && index == MAX_SHUTTERS_ESP32) { ResponseAppend_P(PSTR(",")); } + uint32_t position = ShutterRealToPercentPosition(Shutter[i].real_position, i); + uint32_t target = ShutterRealToPercentPosition(Shutter[i].target_position, i); + ResponseAppend_P(JSON_SHUTTER_POS, i+1, (ShutterSettings.shutter_options[i] & 1) ? 100-position : position, Shutter[i].direction,(ShutterSettings.shutter_options[i] & 1) ? 100-target : target, Shutter[i].tilt_real_pos ); + } + ResponseJsonEnd(); + if (always || shutter_running) { + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); // RulesProcess() now re-entry protected + } + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), TasmotaGlobal.rules_flag.shutter_moving, TasmotaGlobal.rules_flag.shutter_moved); +} + +void ShutterLimitRealAndTargetPositions(uint32_t i) +{ + if (Shutter[i].real_position<0) Shutter[i].real_position = 0; + if (Shutter[i].real_position>Shutter[i].open_max) Shutter[i].real_position = Shutter[i].open_max; + if (Shutter[i].target_position<0) Shutter[i].target_position = 0; + if (Shutter[i].target_position>Shutter[i].open_max) Shutter[i].target_position = Shutter[i].open_max; +} + +void ShutterCalculateAccelerator(uint8_t i) +{ + // No Logging allowed. Part of RTC Timer + if (Shutter[i].direction != 0) { + switch (ShutterGlobal.position_mode) { + case SHT_COUNTER: + case SHT_PWM_VALUE: + current_real_position = Shutter[i].real_position; + current_pwm_velocity = Shutter[i].pwm_velocity; + // calculate max velocity allowed in this direction + velocity_max = Shutter[i].direction == 1 ? ShutterGlobal.open_velocity_max : Shutter[i].close_velocity_max; + // calculate max change of velocyty based on the defined motordelay in steps + velocity_change_per_step_max = velocity_max / (Shutter[i].motordelay>0 ? Shutter[i].motordelay : 1); + // minimumtime required from current velocity to stop + min_runtime_ms = current_pwm_velocity * 1000 / STEPS_PER_SECOND / velocity_change_per_step_max; + // decellaration way from current velocity + current_stop_way = min_runtime_ms * STEPS_PER_SECOND * (current_pwm_velocity + velocity_change_per_step_max) * Shutter[i].direction / 2 / ShutterGlobal.open_velocity_max - (Shutter[i].accelerator<0?Shutter[i].direction*1000*current_pwm_velocity/ShutterGlobal.open_velocity_max:0); + next_possible_stop_position = current_real_position + current_stop_way ; + // ensure that the accelerotor kicks in at the first overrun of the target position + if ( Shutter[i].accelerator < 0 || next_possible_stop_position * Shutter[i].direction > Shutter[i].target_position * Shutter[i].direction ) { + // if startet to early because of 0.05sec maximum accuracy and final position is to far away (200) accelerate a bit less + if (next_possible_stop_position * Shutter[i].direction+200 < Shutter[i].target_position * Shutter[i].direction) { + Shutter[i].accelerator = -velocity_change_per_step_max*9/10; + } else { + // in any case increase accelleration if overrun is detected during decelleration + if (next_possible_stop_position * Shutter[i].direction > Shutter[i].target_position * Shutter[i].direction && Shutter[i].accelerator < 0) { + Shutter[i].accelerator = -velocity_change_per_step_max*11/10; + } else { + // as long as the calculated end position is ok stay with proposed decelleration + Shutter[i].accelerator = -velocity_change_per_step_max; + } + } + // detect during the acceleration phase the point final speed is reached + } else if ( Shutter[i].accelerator > 0 && current_pwm_velocity == velocity_max) { + Shutter[i].accelerator = 0; + } + break; + } + } +} + +void ShutterDecellerateForStop(uint8_t i) +{ +#ifdef ESP32 + bool pwm_apply = false; // ESP32 only, do we need to apply PWM changes +#endif + switch (ShutterGlobal.position_mode) { + case SHT_PWM_VALUE: + case SHT_COUNTER: + int16_t missing_steps; + Shutter[i].accelerator = -(ShutterGlobal.open_velocity_max / (Shutter[i].motordelay>4 ? (Shutter[i].motordelay*11)/10 : 4) ); + + while (Shutter[i].pwm_velocity > -2*Shutter[i].accelerator && Shutter[i].pwm_velocity != PWM_MIN) { + delay(50); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Velocity %ld, Delta %d"), Shutter[i].pwm_velocity, Shutter[i].accelerator ); + // Control will be done in RTC Ticker. + } + if (ShutterGlobal.position_mode == SHT_COUNTER){ + missing_steps = ((Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND) - RtcSettings.pulse_counter[i]; + //prepare for stop PWM + Shutter[i].accelerator = 0; + Shutter[i].pwm_velocity = 0; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Remain %d count %d -> target %d, dir %d"), missing_steps, RtcSettings.pulse_counter[i], (uint32_t)(Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND, Shutter[i].direction); + while (RtcSettings.pulse_counter[i] < (uint32_t)(Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND && missing_steps > 0) { + } +#ifdef ESP8266 + analogWrite(Pin(GPIO_PWM1, i), 0); // removed with 8.3 because of reset caused by watchog +#endif +#ifdef ESP32 + TasmotaGlobal.pwm_value[i] = 0; + pwm_apply = true; +#endif // ESP32 + Shutter[i].real_position = ShutterCalculatePosition(i); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Remain steps %d"), missing_steps); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Real %d, Pulsecount %d, tobe %d, Start %d"), Shutter[i].real_position,RtcSettings.pulse_counter[i], (uint32_t)(Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND, Shutter[i].start_position); + } + Shutter[i].direction = 0; + Shutter[i].pwm_velocity = 0; + break; + } +#ifdef ESP32 + if (pwm_apply) { PwmApplyGPIO(false); } +#endif +} + +void ShutterPowerOff(uint8_t i) +{ + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Stop %d Mode %d time %d"), i+1,Shutter[i].switch_mode, Shutter[i].time); // fix log to indicate correct shutter number + ShutterDecellerateForStop(i); + uint8_t cur_relay = ShutterSettings.shutter_startrelay[i] + (Shutter[i].direction == 1 ? 0 : (uint8_t)(ShutterGlobal.position_mode == SHT_TIME)) ; + if (Shutter[i].direction !=0) { + Shutter[i].direction = 0; + } + if (Shutter[i].real_position == Shutter[i].start_position) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Update target tilt shutter %d from %d to %d"), i+1, Shutter[i].tilt_target_pos , Shutter[i].tilt_real_pos); + Shutter[i].tilt_target_pos = Shutter[i].tilt_real_pos; + } + TasmotaGlobal.rules_flag.shutter_moved = 1; + switch (Shutter[i].switch_mode) { + case SHT_SWITCH: + for (int8_t k=0;k<2;k++) { + if ((1 << (ShutterSettings.shutter_startrelay[i]+k-1)) & TasmotaGlobal.power) { + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[i]+k, 0, SRC_SHUTTER); + } + } + break; + case SHT_PULSE: + // we have a momentary switch here. Needs additional pulse on same relay after the end + if ((SRC_PULSETIMER == TasmotaGlobal.last_source || SRC_SHUTTER == TasmotaGlobal.last_source || SRC_WEBGUI == TasmotaGlobal.last_source)) { + ExecuteCommandPowerShutter(cur_relay, 1, SRC_SHUTTER); + // switch off direction relay to make it power less + if (((1 << (ShutterSettings.shutter_startrelay[i])) & TasmotaGlobal.power) && ShutterSettings.shutter_startrelay[i]+1 != cur_relay) { + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[i]+1, 0, SRC_SHUTTER); + } + } else { + TasmotaGlobal.last_source = SRC_SHUTTER; + } + break; + } + // Store current PWM value to ensure proper position after reboot. + switch (ShutterGlobal.position_mode) { + case SHT_PWM_VALUE: + Shutter[i].pwm_value = SHT_DIV_ROUND((ShutterSettings.shutter_pwmrange[1][i]-ShutterSettings.shutter_pwmrange[0][i]) * Shutter[i].target_position , Shutter[i].open_max)+ShutterSettings.shutter_pwmrange[0][i]; + analogWrite(Pin(GPIO_PWM1, i), Shutter[i].pwm_value); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: PWM final %d"),Shutter[i].pwm_value); + char scmnd[20]; + #ifdef SHUTTER_CLEAR_PWM_ONSTOP + // free the PWM servo lock on stop. + analogWrite(Pin(GPIO_PWM1, i), 0); + #endif + break; + } + if (Settings->save_data) { + TasmotaGlobal.save_data_counter = Settings->save_data; + } + //delay(MOTOR_STOP_TIME); + Shutter[i].last_stop_time = millis(); +} + +void ShutterWaitForMotorStop(uint8_t i) +{ + Shutter[i].last_stop_time = millis(); + ShutterWaitForMotorStart(i); +} + +void ShutterWaitForMotorStart(uint8_t i) +{ + while (millis() < Shutter[i].last_stop_time + ShutterSettings.shutter_motorstop) { + loop(); + } + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stoptime done")); +} + +void ShutterUpdatePosition(void) +{ + char scommand[CMDSZ]; + char stopic[TOPSZ]; + + // Iterate through all available shutters + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { + // Check if the shutter is in motion + if (Shutter[i].direction != 0) { + // Report the position of the shutter if not already done + if (!ShutterGlobal.start_reported) { + ShutterReportPosition(true, i); + ShutterGlobal.start_reported = 1; + } + // Update time information + int32_t deltatime = Shutter[i].time-Shutter[i].last_reported_time; + Shutter[i].last_reported_time = Shutter[i].time+1; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Time %d(%d), cStop %d, cVelo %d, mVelo %d, aVelo %d, mRun %d, aPos %d, aPos2 %d, nStop %d, Trgt %d, mVelo %d, Dir %d, Tilt %d, TrgtTilt: %d, Tiltmove: %d"), + i+1, Shutter[i].time, deltatime, current_stop_way, current_pwm_velocity, velocity_max, Shutter[i].accelerator, min_runtime_ms, current_real_position,Shutter[i].real_position, + next_possible_stop_position, Shutter[i].target_position, velocity_change_per_step_max, Shutter[i].direction,Shutter[i].tilt_real_pos, Shutter[i].tilt_target_pos, + Shutter[i].tiltmoving); + + // Check calibration mode and energy information + if (ShutterGlobal.callibration_run ) { + // update energy consumption on every loop to dectect stop of the shutter + XnrgCall(FUNC_ENERGY_EVERY_SECOND); + // fency calculation with direction gives index 0 and 1 of the energy meter + // stop if endpoint is reached + if (Energy->active_power[(1 - Shutter[i].direction ) / 2] < 1.0 && Shutter[i].time > 20){ + ShutterGlobal.stopp_armed++; + AddLog(LOG_LEVEL_INFO, PSTR("SHT: stopp_armed:%d"),ShutterGlobal.stopp_armed); + if (ShutterGlobal.stopp_armed > 2) { + Shutter[i].target_position = Shutter[i].real_position; + } + } else { + ShutterGlobal.stopp_armed = 0; + } + } + // Check if shutter reached its target position or if the speed falls below the minimum value + if ( ((Shutter[i].real_position * Shutter[i].direction >= Shutter[i].target_position * Shutter[i].direction && Shutter[i].tiltmoving==0) || + ((int16_t)Shutter[i].tilt_real_pos * Shutter[i].direction * Shutter[i].tilt_config[2] >= (int16_t)Shutter[i].tilt_target_pos * Shutter[i].direction * Shutter[i].tilt_config[2] && Shutter[i].tiltmoving==1)) + || (ShutterGlobal.position_mode == SHT_COUNTER && Shutter[i].accelerator <0 && Shutter[i].pwm_velocity+Shutter[i].accelerator %d, moving: %d"),Shutter[i].tilt_real_pos,Shutter[i].tilt_target_pos,Shutter[i].tiltmoving); + // Check if the tilt position doesn't match the target tilt position and the shutter is not currently tilting + if (abs(Shutter[i].tilt_real_pos - Shutter[i].tilt_target_pos) > Shutter[i].min_TiltChange && Shutter[i].tiltmoving == 0) { + AddLog(LOG_LEVEL_INFO, PSTR("SHT: Tilt not match %d -> %d"),Shutter[i].tilt_real_pos,Shutter[i].tilt_target_pos); + // Prepare the command to update the shutter position + char databuf[1] = ""; + XdrvMailbox.data = databuf; + XdrvMailbox.payload = -99; + XdrvMailbox.index = i+1; + // Set the shutter to tilting mode + Shutter[i].tiltmoving = 1; + CmndShutterPosition(); + return; + } else { + // Update the shutter tilt position setting to the current real tilt position + ShutterSettings.shutter_tilt_pos[i] = Shutter[i].tilt_real_pos; + } + ShutterLogPos(i); + + if (!Settings->flag4.only_json_message) { // SetOption90 - Disable non-json MQTT response + // sending MQTT result to broker + snprintf_P(scommand, sizeof(scommand),PSTR(D_SHUTTER "%d"), i+1); + GetTopic_P(stopic, STAT, TasmotaGlobal.mqtt_topic, scommand); + Response_P("%d", (ShutterSettings.shutter_options[i] & 1) ? 100 - ShutterSettings.shutter_position[i]: ShutterSettings.shutter_position[i]); + MqttPublish(stopic, Settings->flag.mqtt_power_retain); // CMND_POWERRETAIN + } + + // Report the shutter position + ShutterReportPosition(true, i); + TasmotaGlobal.rules_flag.shutter_moved = 1; + } + } + } +} + +bool ShutterState(uint32_t device) +{ + if (device > 4) { return false; } + device--; + device &= 3; + return (Settings->flag3.shutter_mode && // SetOption80 - Enable shutter support + (ShutterGlobal.RelayShutterMask & (1 << (ShutterSettings.shutter_startrelay[device]-1))) ); +} + +void ShutterAllowPreStartProcedure(uint8_t i) { + // Tricky!!! Execute command status 2 while in the 10 sec loop and you'll end up in an exception + // What PreStartProcedure do you want to execute here? + // Anyway, as long var1 != 99 this is skipped (luckily) +#ifdef USE_RULES + uint32_t uptime_Local=0; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Delay Start? var%d <99>=<%s>, max10s?"),i+1, rules_vars[i]); + uptime_Local = TasmotaGlobal.uptime; + while (uptime_Local+10 > TasmotaGlobal.uptime && (String)rules_vars[i] == "99") { + loop(); + } + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Delay Start. Done")); +#endif // USE_RULES +} + +void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos) +{ + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: dir %d, delta1 %d, delta2 %d"),direction, (Shutter[i].open_max - Shutter[i].real_position) / Shutter[i].close_velocity, Shutter[i].real_position / Shutter[i].close_velocity); + if ( ( ( (1 == direction) && ((Shutter[i].open_max - Shutter[i].real_position) <= Shutter[i].min_realPositionChange)) + || ( (-1 == direction) && (Shutter[i].real_position <= Shutter[i].min_realPositionChange)) ) + && abs(Shutter[i].tilt_real_pos-Shutter[i].tilt_target_pos) <= Shutter[i].min_TiltChange) { + ShutterGlobal.skip_relay_change = 1; + } else { + Shutter[i].pwm_velocity = 0; + ShutterWaitForMotorStart(i); + switch (ShutterGlobal.position_mode) { +#ifdef SHUTTER_STEPPER + case SHT_COUNTER: +#ifdef ESP8266 + analogWriteFreq(Shutter[i].pwm_velocity); + analogWrite(Pin(GPIO_PWM1, i), 0); +#endif +#ifdef ESP32 + analogWriteFreq(PWM_MIN,Pin(GPIO_PWM1, i)); + TasmotaGlobal.pwm_value[i] = 0; + PwmApplyGPIO(false); +#endif + RtcSettings.pulse_counter[i] = 0; + break; +#endif + } + + Shutter[i].accelerator = ShutterGlobal.open_velocity_max / (Shutter[i].motordelay>0 ? Shutter[i].motordelay : 1); + Shutter[i].target_position = target_pos; + Shutter[i].start_position = Shutter[i].real_position; + TasmotaGlobal.rules_flag.shutter_moving = 1; + ShutterAllowPreStartProcedure(i); + Shutter[i].time = Shutter[i].last_reported_time = 0; + + ShutterGlobal.skip_relay_change = 0; + TasmotaGlobal.rules_flag.shutter_moved = 0; + ShutterGlobal.start_reported = 0; + Shutter[i].tilt_real_pos = tmax(tmin(Shutter[i].tilt_real_pos,Shutter[i].tilt_config[1]),Shutter[i].tilt_config[0]); + Shutter[i].tilt_start_pos = Shutter[i].tilt_real_pos; + if (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0] != 0) { + Shutter[i].venetian_delay = SHT_DIV_ROUND((direction > 0 ? Shutter[i].tilt_config[1]-Shutter[i].tilt_real_pos : Shutter[i].tilt_real_pos-Shutter[i].tilt_config[0]) * Shutter[i].tilt_config[2], Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: real %d, start %d, counter %d,freq_max %d, dir %d, freq %d"),Shutter[i].real_position, Shutter[i].start_position ,RtcSettings.pulse_counter[i],ShutterGlobal.open_velocity_max , direction ,ShutterGlobal.open_velocity_max ); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: VenetianDelay: %d, Pos: %d, Dir: %d, Delta: %d, Dur: %d, StartP: %d, TgtP: %d"), + Shutter[i].venetian_delay, Shutter[i].tilt_real_pos,direction,(Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]), Shutter[i].tilt_config[2],Shutter[i].tilt_start_pos,Shutter[i].tilt_target_pos); + } + + // avoid file system writes during move to minimize missing steps + if (Settings->save_data) { + uint32_t move_duration = (direction > 0) ? Shutter[i].open_time : Shutter[i].close_time; + TasmotaGlobal.save_data_counter = Settings->save_data + (move_duration / 10) +1; + } + } + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Start shtr%d from %d to %d in dir: %d"), i, Shutter[i].start_position, Shutter[i].target_position, direction); + + Shutter[i].direction = direction; // Last action. This causes RTC to start. +} + +int32_t ShutterCalculatePosition(uint32_t i) +{ + // No Logging allowed. Part of RTC Timer + if (Shutter[i].direction != 0) { + switch (ShutterGlobal.position_mode) { + case SHT_COUNTER: + return ((int64_t)RtcSettings.pulse_counter[i]*Shutter[i].direction*STEPS_PER_SECOND * RESOLUTION / ShutterGlobal.open_velocity_max)+Shutter[i].start_position; + break; + case SHT_TIME: + case SHT_TIME_UP_DOWN: + case SHT_TIME_GARAGE: + if (Shutter[i].tilt_config[2] > 0) { + if (Shutter[i].time <= Shutter[i].venetian_delay+Shutter[i].motordelay) { + Shutter[i].tilt_real_pos = (Shutter[i].tilt_start_pos + ((Shutter[i].direction * (int16_t)(Shutter[i].time - tmin(Shutter[i].motordelay, Shutter[i].time)) * (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])) / Shutter[i].tilt_config[2])); + } else { + Shutter[i].tilt_real_pos = Shutter[i].direction == 1 ? Shutter[i].tilt_config[1] : Shutter[i].tilt_config[0]; + } + } + return Shutter[i].start_position + ( (Shutter[i].time - tmin(Shutter[i].venetian_delay+Shutter[i].motordelay, Shutter[i].time)) * (Shutter[i].direction > 0 ? RESOLUTION : -Shutter[i].close_velocity)); + break; + case SHT_PWM_TIME: + break; + case SHT_PWM_VALUE: + return Shutter[i].real_position; + break; + default: + break; + } + } else { + return Shutter[i].real_position; + } + return 0; // Never reaches here, Satisfy compiler +} + +void ShutterRelayChanged(void) +{ + + // ShutterGlobal.RelayCurrentMask = binary relay that was recently changed and cause an Action + // powerstate_local = binary powermatrix and relays from shutter: 0..3 + // relays_changed = bool if one of the relays that belong to the shutter changed not by shutter or pulsetimer + char stemp1[10]; + + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { + power_t powerstate_local = (TasmotaGlobal.power >> (ShutterSettings.shutter_startrelay[i] -1)) & 3; + // SRC_IGNORE added because INTERLOCK function bite causes this as last source for changing the relay. + //uint8 manual_relays_changed = ((ShutterGlobal.RelayCurrentMask >> (ShutterSettings.shutter_startrelay[i] -1)) & 3) && SRC_IGNORE != TasmotaGlobal.last_source && SRC_SHUTTER != TasmotaGlobal.last_source && SRC_PULSETIMER != TasmotaGlobal.last_source ; + uint8 manual_relays_changed = ((ShutterGlobal.RelayCurrentMask >> (ShutterSettings.shutter_startrelay[i] -1)) & 3) && SRC_SHUTTER != TasmotaGlobal.last_source && SRC_PULSETIMER != TasmotaGlobal.last_source ; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Source %s, Powerstate %ld, RelayMask %d, ManualChange %d"), + // i+1, GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource), powerstate_local,ShutterGlobal.RelayCurrentMask,manual_relays_changed); + if (manual_relays_changed) { + //ShutterGlobal.skip_relay_change = true; + ShutterLimitRealAndTargetPositions(i); + switch (Shutter[i].switch_mode ) { + case SHT_PULSE: + if (Shutter[i].direction != 0 && powerstate_local) { + Shutter[i].target_position = Shutter[i].real_position; + powerstate_local = 0; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Switch OFF motor. Target %ld, Source %s, Powerstate %ld, RelayMask %d, ManualChange %d"), + i+1, Shutter[i].target_position, GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource), powerstate_local,ShutterGlobal.RelayCurrentMask,manual_relays_changed); + } + break; + default: + TasmotaGlobal.last_source = SRC_SHUTTER; // avoid switch off in the next loop + if (Shutter[i].direction != 0 ) Shutter[i].target_position = Shutter[i].real_position; + } + if (powerstate_local > 0) { + Shutter[i].tiltmoving = 0; + } + switch (ShutterGlobal.position_mode) { + // enum Shutterposition_mode {SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,}; + case SHT_TIME_UP_DOWN: + case SHT_COUNTER: + case SHT_PWM_VALUE: + case SHT_PWM_TIME: + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: power off manual change")); + ShutterPowerOff(i); + switch (powerstate_local) { + case 1: + ShutterStartInit(i, 1, Shutter[i].open_max); + break; + case 3: + ShutterStartInit(i, -1, 0); + break; + default: + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i); + Shutter[i].target_position = Shutter[i].real_position; + Shutter[i].last_stop_time = millis(); + } + break; + case SHT_TIME: + switch (powerstate_local) { + case 1: + ShutterStartInit(i, 1, Shutter[i].open_max); + break; + case 2: + ShutterStartInit(i, -1, 0); + break; + default: + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i+1); + Shutter[i].target_position = Shutter[i].real_position; + Shutter[i].last_stop_time = millis(); + } + break; + case SHT_TIME_GARAGE: + switch (powerstate_local) { + case 1: + ShutterStartInit(i, Shutter[i].lastdirection*-1 , Shutter[i].lastdirection == 1 ? 0 : Shutter[i].open_max); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Garage. NewTarget %d"), i, Shutter[i].target_position); + break; + default: + Shutter[i].target_position = Shutter[i].real_position; + } + + + } // switch (ShutterGlobal.position_mode) + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Target %ld, Power: %d, tiltmv: %d"), i+1, Shutter[i].target_position, powerstate_local,Shutter[i].tiltmoving); + } // if (manual_relays_changed) + } // for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) +} + +bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) +{ + // check for simultaneous shutter button hold + uint32 min_shutterbutton_hold_timer = -1; // -1 == max(uint32) + for (uint32_t i = 0; i < MAX_SHUTTERS_ESP32*2 ; i++) { + if ((button_index != i) && (ShutterSettings.shutter_button[i].enabled) && (ShutterSettings.shutter_button[i].shutter_number == shutter_index) && (Button.hold_timer[i] < min_shutterbutton_hold_timer)) + min_shutterbutton_hold_timer = Button.hold_timer[i]; + } + return ((-1 != min_shutterbutton_hold_timer) && (min_shutterbutton_hold_timer > (Button.hold_timer[button_index]>>1))); +} + +bool ShutterButtonHandlerMulti(void) +{ + uint8_t button = XdrvMailbox.payload; + uint32_t button_index = XdrvMailbox.index; + uint8_t shutter_index = ShutterSettings.shutter_button[button_index].shutter_number; + uint8_t button_press_counter = Button.press_counter[button_index] ; + + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MULTI: SHT: Shtr%d, Button %d, hold %d, dir %d, index %d, payload %d, last state %d, press counter %d, window %d"), + shutter_index+1, button_index+1, Button.hold_timer[button_index],Shutter[shutter_index].direction,XdrvMailbox.index,XdrvMailbox.payload, + Button.last_state[button_index], Button.press_counter[button_index], Button.window_timer[button_index]); + + // multipress event handle back to main procedure + if (Button.press_counter[button_index]>4) return false; + + uint8_t pos_press_index = Button.press_counter[button_index]-1; + + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Button %d = %d (single=1, double=2, tripple=3, hold=4)"), shutter_index+1, button_index+1, pos_press_index+1); + XdrvMailbox.index = shutter_index +1; + TasmotaGlobal.last_source = SRC_BUTTON; + XdrvMailbox.data_len = 0; + char databuf[1] = ""; + XdrvMailbox.data = databuf; + XdrvMailbox.command = NULL; + uint8_t position = ShutterSettings.shutter_button[button_index].position[pos_press_index].pos; + XdrvMailbox.payload = position; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d -> %d"), shutter_index+1, position); + if (102 == position) { + XdrvMailbox.payload = XdrvMailbox.index; + CmndShutterToggle(); + } else { + if (position == ShutterRealToPercentPosition(Shutter[XdrvMailbox.index-1].real_position, XdrvMailbox.index-1) ) { + Shutter[XdrvMailbox.index -1].tilt_target_pos = position==0? Shutter[XdrvMailbox.index -1].tilt_config[0]:(position==100?Shutter[XdrvMailbox.index -1].tilt_config[1]:Shutter[XdrvMailbox.index -1].tilt_target_pos); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d -> Endpoint movement detected at %d. Set Tilt: %d"), shutter_index+1, position, Shutter[XdrvMailbox.index -1].tilt_target_pos); + } + // set the tilt + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Target tilt %d for button %d"), ShutterSettings.shutter_button[button_index].position[pos_press_index].tilt, button_index+1); + if (ShutterSettings.shutter_button[button_index].position[pos_press_index].tilt != -128) { + Shutter[shutter_index].tilt_target_pos_override = ShutterSettings.shutter_button[button_index].position[pos_press_index].tilt; + } + // reset button to default + Button.press_counter[button_index] = 0; + + CmndShutterPosition(); + } + + if (ShutterSettings.shutter_button[button_index].position[pos_press_index].mqtt_broadcast) { + // MQTT broadcast to grouptopic + char scommand[CMDSZ]; + char stopic[TOPSZ]; + for (uint32_t i = 0; i < MAX_SHUTTERS_ESP32; i++) { + if ((i==shutter_index) || (ShutterSettings.shutter_button[button_index].mqtt_all)) { + snprintf_P(scommand, sizeof(scommand),PSTR("ShutterPosition%d"), i+1); + GetGroupTopic_P(stopic, scommand, SET_MQTT_GRP_TOPIC); + Response_P("%d", position); + MqttPublish(stopic, false); + } + } // for (uint32_t) + } // ShutterSettings.shutter_button[button_index].positionmatrix & ((0x01<<26)< 0 || (button != Button.last_state[button_index] || Button.window_timer[button_index] > 0)) { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Button %d, hold %d, dir %d, index %d, payload %d, last state %d, press counter %d, window %d"), + shutter_index+1, button_index+1, Button.hold_timer[button_index],Shutter[shutter_index].direction,XdrvMailbox.index,XdrvMailbox.payload, + Button.last_state[button_index], Button.press_counter[button_index], Button.window_timer[button_index]); + + if (Button.hold_timer[button_index] > 100 ) { + Button.hold_timer[button_index] = 1; // Reset button hold counter to stay below hold trigger + } + } + + // handle on button release: start shutter on shortpress and stop running shutter after longpress. + if (NOT_PRESSED == button + && Shutter[shutter_index].direction != 0 // only act on shutters activly moving + && Button.hold_timer[button_index] > 0) // kick in on first release of botton. do not check for multipress + { + XdrvMailbox.index = shutter_index +1; + XdrvMailbox.payload = -99; // reset any payload to invalid + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("Stop moving shutter")); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Button %d, hold %d, dir %d, index %d, payload %d"), shutter_index+1, button_index+1, Button.hold_timer[button_index],Shutter[shutter_index].direction,XdrvMailbox.index,XdrvMailbox.payload); + CmndShutterStop(); + Button.press_counter[button_index] = 0; + return true; + } + + + //long press detected. Start moving shutter into direction + if (PRESSED == button + && Shutter[shutter_index].direction == 0 //shutter in STOP Position + && Button.window_timer[button_index] == 0 //time for waiting for multipress window expired + && Button.press_counter[button_index] > 0) //only execute if at least pressed ONECE. 0==disable + { + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("Start shutter after long press")); + Button.press_counter[button_index] = 4; + ShutterButtonHandlerMulti(); + } + return false; +} + +void ShutterSetPosition(uint32_t device, uint32_t position) +{ + char svalue[32]; // Command and number parameter + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_POSITION "%d %d"), device, position); + ExecuteCommand(svalue, SRC_SHUTTER); +} + +void ShutterToggle(bool dir) +{ + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Toggle: %d, i %d, dir %d, lastdir %d"), XdrvMailbox.payload, XdrvMailbox.index, dir, Shutter[XdrvMailbox.index-1].lastdirection); + if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { + XdrvMailbox.index = XdrvMailbox.payload; + } + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (dir) { + XdrvMailbox.payload = (Shutter[index].direction==0 ? ((Shutter[index].lastdirection > 0) ? 0 : 100) : (Shutter[index].direction > 0) ? 0 : 100); + } + else { + XdrvMailbox.payload = (50 < ShutterRealToPercentPosition(Shutter[index].real_position, index)) ? 0 : 100; + } + XdrvMailbox.data_len = 0; + TasmotaGlobal.last_source = SRC_WEBGUI; + CmndShutterPosition(); + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +void CmndShutterOpen(void) +{ + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Payload open: %d, i %d"), XdrvMailbox.payload, XdrvMailbox.index); + if ((!XdrvMailbox.usridx) && (XdrvMailbox.payload != -99)) { + XdrvMailbox.index = XdrvMailbox.payload; + } + XdrvMailbox.payload = 100; + TasmotaGlobal.last_source = SRC_WEBGUI; + CmndShutterPosition(); +} + +void CmndShutterStopOpen(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (Shutter[index].direction) { + CmndShutterStop(); + } else { + CmndShutterOpen(); + } + } +} + +void CmndShutterClose(void) +{ + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Payload close: %d, i %d"), XdrvMailbox.payload, XdrvMailbox.index); + if ((!XdrvMailbox.usridx) && (XdrvMailbox.payload != -99)) { + XdrvMailbox.index = XdrvMailbox.payload; + } + XdrvMailbox.payload = 0; + TasmotaGlobal.last_source = SRC_WEBGUI; + CmndShutterPosition(); +} + +void CmndShutterStopClose(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (Shutter[index].direction) { + CmndShutterStop(); + } else { + CmndShutterClose(); + } + } +} + +void CmndShutterToggle(void) +{ + ShutterToggle(false); +} + +void CmndShutterToggleDir(void) +{ + ShutterToggle(true); +} + +void CmndShutterStopToggle(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (Shutter[index].direction) { + CmndShutterStop(); + } else { + CmndShutterToggle(); + } + } +} + +void CmndShutterStopToggleDir(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (Shutter[index].direction) { + CmndShutterStop(); + } else { + CmndShutterToggleDir(); + } + } +} + +void CmndShutterStop(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Try Stop %d: dir: %d"), XdrvMailbox.index, Shutter[XdrvMailbox.index -1].direction); + if (!(ShutterSettings.shutter_options[XdrvMailbox.index-1] & 2)) { + if ((!XdrvMailbox.usridx) && (XdrvMailbox.payload != -99)) { + XdrvMailbox.index = XdrvMailbox.payload; + } + uint32_t i = XdrvMailbox.index -1; + if (Shutter[i].direction != 0) { + + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Stop %d: dir: %d"), XdrvMailbox.index, Shutter[i].direction); + Shutter[i].target_position = Shutter[i].real_position; + } + if (XdrvMailbox.command) + ResponseCmndDone(); + ShutterUpdatePosition(); + } else { + if (XdrvMailbox.command) + ResponseCmndIdxChar("Locked"); + } + } +} + +void CmndShutterIncDec(void) +{ + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Change in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, TasmotaGlobal.last_source ); + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + XdrvMailbox.payload = ShutterRealToPercentPosition(Shutter[XdrvMailbox.index-1].target_position, XdrvMailbox.index-1)+XdrvMailbox.payload; + // limit position to boundaries + XdrvMailbox.payload = XdrvMailbox.payload < 0 ? 0 : (XdrvMailbox.payload > 100 ? 100 : XdrvMailbox.payload); + CmndShutterPosition(); + } + } +} + +void CmndShutterPosition(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (!(ShutterSettings.shutter_options[XdrvMailbox.index-1] & 2)) { + uint32_t index = XdrvMailbox.index-1; + //limit the payload + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Pos. payload <%s> (%d), payload %d, idx %d (%d), src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, XdrvMailbox.usridx, TasmotaGlobal.last_source ); + + if (XdrvMailbox.data_len >= 3) { + // check if input is of format "position,tilt" + uint32_t i = 0; + char *str_ptr; + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ',' seperators. + for (char *str = strtok_r(data_copy, ",", &str_ptr); str && i < 2; str = strtok_r(nullptr, ",", &str_ptr), i++) { + switch(i) { + case 0: + XdrvMailbox.payload = atoi(str); + break; + case 1: + Shutter[index].tilt_target_pos_override = atoi(str); + break; + } + } + } + + + // value 0 with data_len > 0 can mean Open + // special handling fo UP,DOWN,TOGGLE,STOP command comming with payload -99 + // STOP will come with payload 0 because predefined value in TASMOTA + if ((XdrvMailbox.data_len > 3) && (XdrvMailbox.payload <= 0)) { + // set len to 0 to avoid loop on close where payload is 0 + XdrvMailbox.data_len = 0; + if ( ((Shutter[index].direction==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPOPEN))) { + CmndShutterOpen(); + return; + } + if ( ((Shutter[index].direction==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPCLOSE))) { + CmndShutterClose(); + return; + } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLE)) { + CmndShutterToggle(); + return; + } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEDIR)) { + CmndShutterToggleDir(); + return; + } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOP) || ((Shutter[index].direction) && (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPOPEN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPCLOSE)))) { + // Back to normal: all -99 if not a clear position + XdrvMailbox.payload = -99; + CmndShutterStop(); + return; + } + + } + + // if position is either 0 or 100 reset the tilt to avoid tilt moving at the end + if (XdrvMailbox.payload == 0 && ShutterRealToPercentPosition(Shutter[index].real_position, index) > 0 ) {Shutter[index].tilt_target_pos = Shutter[index].tilt_config[4];} + if (XdrvMailbox.payload == 100 && ShutterRealToPercentPosition(Shutter[index].real_position, index) < 100) {Shutter[index].tilt_target_pos = Shutter[index].tilt_config[3];} + + //override tiltposition if explicit set (shutterbutton) + if (Shutter[index].tilt_target_pos_override != -128) { + Shutter[index].tilt_target_pos = tmin(tmax( Shutter[index].tilt_config[0],Shutter[index].tilt_target_pos_override ), Shutter[index].tilt_config[1]); + Shutter[index].tilt_target_pos_override = -128; + } + + int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? (XdrvMailbox.payload == -99 ? ShutterRealToPercentPosition(Shutter[index].real_position, index) : 0) : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload); + // webgui still send also on inverted shutter the native position. + target_pos_percent = ((ShutterSettings.shutter_options[index] & 1) && (SRC_WEBGUI != TasmotaGlobal.last_source)) ? 100 - target_pos_percent : target_pos_percent; + if (XdrvMailbox.payload != -99) { + //target_pos_percent = (ShutterSettings.shutter_options[index] & 1) ? 100 - target_pos_percent : target_pos_percent; + Shutter[index].target_position = ShutterPercentToRealPosition(target_pos_percent, index); + //Shutter[i].accelerator[index] = ShutterGlobal.open_velocity_max / ((Shutter[i].motordelay[index] > 0) ? Shutter[i].motordelay[index] : 1); + //Shutter[i].target_position[index] = XdrvMailbox.payload < 5 ? ShutterSettings.shuttercoeff[2][index] * XdrvMailbox.payload : ShutterSettings.shuttercoeff[1][index] * XdrvMailbox.payload + ShutterSettings.shuttercoeff[0,index]; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: lastsource %d:, real %d, target %d, tiltreal: %d, tilttarget: %d, payload %d"), TasmotaGlobal.last_source, Shutter[index].real_position ,Shutter[index].target_position,Shutter[index].tilt_real_pos, Shutter[index].tilt_target_pos,target_pos_percent); + } + if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && + (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange || + abs(Shutter[index].tilt_target_pos - Shutter[index].tilt_real_pos ) > Shutter[index].min_TiltChange) ) { + if (ShutterSettings.shutter_options[index] & 4) { + if (0 == target_pos_percent && Shutter[index].real_position > 0) Shutter[index].target_position -= 1 * RESOLUTION * STEPS_PER_SECOND; + if (100 == target_pos_percent && Shutter[index].real_position < Shutter[index].open_max) Shutter[index].target_position += 1 * RESOLUTION * STEPS_PER_SECOND; + } + int8_t new_shutterdirection; + if (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange) { + new_shutterdirection = Shutter[index].real_position < Shutter[index].target_position ? 1 : -1; + Shutter[index].tiltmoving = 0; + } else { + new_shutterdirection = Shutter[index].tilt_real_pos < Shutter[index].tilt_target_pos ? 1 : -1; + Shutter[index].tiltmoving = 1; + } + + if (Shutter[index].direction == -new_shutterdirection) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stop shutter to reverse direction")); + ShutterPowerOff(index); + } + if (Shutter[index].direction != new_shutterdirection) { + ShutterStartInit(index, new_shutterdirection, Shutter[index].target_position); + uint8_t save_direction = Shutter[index].direction; + Shutter[index].direction = 0; // set temporary direction = 0 to avoid RTC timer sarting. Some delay may happen before shutter starts moving + switch (ShutterGlobal.position_mode) { + case SHT_COUNTER: + case SHT_PWM_TIME: + case SHT_PWM_VALUE: + case SHT_TIME_UP_DOWN: + if (!ShutterGlobal.skip_relay_change) { + // Code for shutters with circuit safe configuration, switch the direction Relay + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index] +1, new_shutterdirection == 1 ? 0 : 1, SRC_SHUTTER); + delay(SHUTTER_RELAY_OPERATION_TIME); + // power on + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index], 1, SRC_SHUTTER); + } + //if (ShutterGlobal.position_mode != SHT_TIME_UP_DOWN) ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index]+2, 1, SRC_SHUTTER); + break; + case SHT_TIME: + if (!ShutterGlobal.skip_relay_change) { + if ( (TasmotaGlobal.power >> (ShutterSettings.shutter_startrelay[index] -1)) & 3 > 0 ) { + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index] + (new_shutterdirection == 1 ? 1 : 0), Shutter[index].switch_mode == SHT_SWITCH ? 0 : 1, SRC_SHUTTER); + } + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index] + (new_shutterdirection == 1 ? 0 : 1), 1, SRC_SHUTTER); + } + break; + case SHT_TIME_GARAGE: + if (!ShutterGlobal.skip_relay_change) { + if (new_shutterdirection == Shutter[index].lastdirection) { + AddLog(LOG_LEVEL_INFO, PSTR("SHT: Garage not move in this direction: %d"), Shutter[index].switch_mode == SHT_PULSE); + for (uint8_t k=0 ; k <= (uint8_t)(Shutter[index].switch_mode == SHT_PULSE) ; k++) { + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index], 1, SRC_SHUTTER); + //delay(MOTOR_STOP_TIME); + ShutterWaitForMotorStop(index); + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index], 0, SRC_SHUTTER); + //delay(MOTOR_STOP_TIME); + ShutterWaitForMotorStop(index); + } + // reset shutter time to avoid 2 seconds above count as runtime + Shutter[index].time = 0; + } // if (new_shutterdirection == Shutter[i].lastdirection[index]) + ExecuteCommandPowerShutter(ShutterSettings.shutter_startrelay[index], 1, SRC_SHUTTER); + } // if (!ShutterGlobal.skip_relay_change) + break; + } // switch (ShutterGlobal.position_mode) + Shutter[index].direction = save_direction; + ShutterGlobal.RelayCurrentMask = 0; + } // if (Shutter[i].direction[index] != new_shutterdirection) + } else { + target_pos_percent = ShutterRealToPercentPosition(Shutter[index].real_position, index); + } + index = (!XdrvMailbox.usridx && !XdrvMailbox.data_len)?MAX_SHUTTERS_ESP32:index; + ShutterReportPosition(true, index); + ShutterGlobal.start_reported = 1; + XdrvMailbox.index = index +1; // Fix random index for ShutterClose + } else { + ShutterReportPosition(true, MAX_SHUTTERS_ESP32); + if (XdrvMailbox.command) + ResponseCmndIdxChar("Locked"); + } + } +} + +void CmndShutterStopPosition(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (Shutter[index].direction) { + XdrvMailbox.payload = -99; + CmndShutterStop(); + } else { + CmndShutterPosition(); + } + } +} + +void CmndShutterOpenTime(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + ShutterSettings.shutter_opentime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data)); + ShutterInit(); + } +/* + char time_chr[10]; + dtostrfd((float)(ShutterSettings.shutter_opentime[XdrvMailbox.index -1]) / 10, 1, time_chr); + ResponseCmndIdxChar(time_chr); +*/ + ResponseCmndIdxFloat((float)(ShutterSettings.shutter_opentime[XdrvMailbox.index -1]) / 10, 1); + } +} + +void CmndShutterCloseTime(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + ShutterSettings.shutter_closetime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data)); + ShutterInit(); + } +/* + char time_chr[10]; + dtostrfd((float)(ShutterSettings.shutter_closetime[XdrvMailbox.index -1]) / 10, 1, time_chr); + ResponseCmndIdxChar(time_chr); +*/ + ResponseCmndIdxFloat((float)(ShutterSettings.shutter_closetime[XdrvMailbox.index -1]) / 10, 1); + } +} + +void CmndShutterMotorDelay(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + ShutterSettings.shutter_motordelay[XdrvMailbox.index -1] = (uint8_t)(STEPS_PER_SECOND * CharToFloat(XdrvMailbox.data)); + ShutterInit(); + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr Init1. realdelay %d"),Shutter[XdrvMailbox.index -1].motordelay); + } +/* + char time_chr[10]; + dtostrfd((float)(Shutter[XdrvMailbox.index -1].motordelay) / STEPS_PER_SECOND, 2, time_chr); + ResponseCmndIdxChar(time_chr); +*/ + ResponseCmndIdxFloat((float)(Shutter[XdrvMailbox.index -1].motordelay) / STEPS_PER_SECOND, 2); + } +} + +void CmndShutterMode(void) +{ + if (!XdrvMailbox.usridx) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= MAX_MODES)) { + ShutterSettings.shutter_mode = ShutterGlobal.position_mode = XdrvMailbox.payload; + ShutterInit(); + } + ResponseCmndNumber(ShutterGlobal.position_mode); + } +} + +void CmndShutterRelay(void) +{ + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 32) && (XdrvMailbox.index <= MAX_SHUTTERS_ESP32)) { + //ShutterSettings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload; + if (XdrvMailbox.payload > 0) { + ShutterGlobal.RelayShutterMask |= 3 << (XdrvMailbox.payload - 1); + } else { + ShutterGlobal.RelayShutterMask ^= 3 << (ShutterSettings.shutter_startrelay[XdrvMailbox.index -1] - 1); + } + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: relold:%d index:%d, mode:%d, relaymask: %ld"), + ShutterSettings.shutter_startrelay[XdrvMailbox.index -1] , XdrvMailbox.index ,ShutterSettings.shutter_mode, ShutterGlobal.RelayShutterMask ); + if (ShutterSettings.shutter_startrelay[XdrvMailbox.index -1] == 0 && XdrvMailbox.index == 1 && ShutterSettings.shutter_mode == SHT_UNDEF) { + // first shutter was not defined, maybe init + ShutterSettings.shutter_mode = SHT_AUTOCONFIG; + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Autoconfig")); + } + ShutterSettings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload; + + ShutterInit(); + // if payload is 0 to disable the relay there must be a reboot. Otherwhise does not work + } + uint32_t start = (!XdrvMailbox.usridx && !XdrvMailbox.data_len)?0:XdrvMailbox.index -1; + uint32_t end = (!XdrvMailbox.usridx && !XdrvMailbox.data_len)?TasmotaGlobal.shutters_present:XdrvMailbox.index; + // {"ShutterRelay1":"1","ShutterRelay2":"3","ShutterRelay3":"5"} + Response_P(PSTR("{")); + for (uint32_t i = start; i < end; i++) { + ResponseAppend_P(PSTR("%s\"" D_PRFX_SHUTTER D_CMND_SHUTTER_RELAY "%d\":%d"), (i>start)?",":"", i+1, ShutterSettings.shutter_startrelay[i]); + } + ResponseAppend_P(PSTR("}")); +} + +void CmndShutterButton(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SHUTTERS_ESP32)) { + tButtonSettings setting; + memset(&setting, 0x00, sizeof(setting)); + // (setting>>31)&(0x01) : enabled + // (setting>>30)&(0x01) : mqtt broadcast to all index + // (setting>>29)&(0x01) : mqtt broadcast hold + // (setting>>28)&(0x01) : mqtt broadcast tripple press + // (setting>>27)&(0x01) : mqtt broadcast double press + // (setting>>26)&(0x01) : mqtt broadcast single press + // (setting>>20)&(0x3f) : shutter_position hold; 0 disabled, 1..101 == 0..100%, 102 == toggle + // (setting>>14)&(0x3f) : shutter_position tripple press 0 disabled, 1..101 == 0..100%, 102 == toggle + // (setting>> 8)&(0x3f) : shutter_position double press 0 disabled, 1..101 == 0..100%, 102 == toggle + // (setting>> 2)&(0x3f) : shutter_position single press 0 disabled, 1..101 == 0..100%, 102 == toggle + // (setting>> 0)&(0x03) : shutter_index + if (XdrvMailbox.data_len > 0) { + uint32_t i = 0; + uint32_t button_index = 0; + bool done = false; + bool isShortCommand = false; + char *str_ptr; + char *str_ptr2; + + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < (1+4+4+1); str = strtok_r(nullptr, " ", &str_ptr), i++) { + int field = -1; + int tilt = -128; + int j = 0; + char field_copy[strlen(str) +1]; + strncpy(field_copy, str, sizeof(field_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on '/' seperators. + for (char *str2 = strtok_r(field_copy, "/", &str_ptr2); str2 && j < 2; str2 = strtok_r(nullptr, "/", &str_ptr2), j++) { + switch (j) { + case 0: + switch (str2[0]) { + case '-': + field = -1; + break; + case 't': + field = 102; + break; + default: + field = atoi(str2); + break; + } + break; + case 1: + switch (str2[0]) { + case '-': // special handling to seperate a - from a negative number. e.g. -90 + if (strlen(str2)==1) { + tilt = -128; + } else { + tilt = atoi(str2); + } + break; + case 't': + tilt = 127; + break; + default: + tilt = atoi(str2); + break; + } + break; + } + } + switch (i) { + case 0: + if ((field >= -1) && (field<=MAX_SHUTTERS_ESP32*2)) { + button_index = (field<=0)?(-1):field; + done = (button_index==-1); + } else + done = true; + break; + case 1: + if (!strcmp_P(str, PSTR("up"))) { + setting.position[0].pos = 100; + setting.position[1].pos = 50; + setting.position[2].pos = 75; + setting.position[3].pos = 100; + isShortCommand = true; + break; + } else if (!strcmp_P(str, PSTR("down"))) { + setting.position[0].pos = 0; + setting.position[1].pos = 50; + setting.position[2].pos = 25; + setting.position[3].pos = 0; + isShortCommand = true; + break; + } else if (!strcmp_P(str, PSTR("updown"))) { + setting.position[0].pos = 100; + setting.position[1].pos = 0; + setting.position[2].pos = 50; + isShortCommand = true; + break; + } else if (!strcmp_P(str, PSTR("toggle"))) { + setting.position[0].pos = 102; + setting.position[1].pos = 50; + isShortCommand = true; + break; + } + case 2: + /* Currently not supported + if (isShortCommand) { + if ((field==1) && (setting & (0x3F<<(2+6*3)))) + // if short command up or down (hold press position set) then also enable MQTT broadcast + setting |= (0x3<<29); + done = true; + break; + } + */ + case 3: + case 4: + if ((field >= -1) && (field<=102)) + setting.position[i-1].pos = field; + if ((tilt >= -128) && (tilt<=127)) + setting.position[i-1].tilt = tilt; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + if (field==1) + setting.position[i-6].mqtt_broadcast = true; + break; + } + if (isShortCommand) { + for (uint8_t j=0; j<4; j++) setting.position[j].tilt = -128; + } + if (done) break; + } + + if (button_index) { + if (button_index==-1) { + // remove all buttons for this shutter + for (uint32_t i=0 ; i < MAX_SHUTTERS_ESP32*2 ; i++) + if (ShutterSettings.shutter_button[i].shutter_number == XdrvMailbox.index-1) + ShutterSettings.shutter_button[i].enabled = false; + ShutterSettings.shutter_button[i].shutter_number=0; + for (uint8_t j = 0; j < 4; j++) + ShutterSettings.shutter_button[i].position[j] = {-1,-128,0}; + } else { + setting.enabled = true; + setting.shutter_number == XdrvMailbox.index-1; + ShutterSettings.shutter_button[button_index-1] = setting; + } + } + } + char setting_chr[30*MAX_SHUTTER_KEYS] = "-", *setting_chr_ptr = setting_chr; + for (uint32_t i=0 ; i < MAX_SHUTTERS_ESP32*2 ; i++) { + setting = ShutterSettings.shutter_button[i]; + if ((setting.enabled) && (ShutterSettings.shutter_button[i].shutter_number == XdrvMailbox.index-1)) { + if (*setting_chr_ptr == 0) + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR("|")); + setting_chr_ptr += snprintf_P(setting_chr_ptr, 3, PSTR("%d"), i+1); + + for (uint32_t j=0 ; j < 4 ; j++) { + int8_t pos = setting.position[j].pos; + int8_t postilt = setting.position[j].tilt; + if (0 <= pos) + if (102 == pos) { + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" t")); + } else { + setting_chr_ptr += snprintf_P(setting_chr_ptr, 5, PSTR(" %d"), pos); + } + else + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" -")); + if (-128 != postilt) { + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR("/")); + if (127 == postilt) { + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR("t")); + } else { + setting_chr_ptr += snprintf_P(setting_chr_ptr, 5, PSTR("%d"), postilt); + } + } + } + for (uint32_t j=0 ; j < 4 ; j++) { + if (setting.position[j].mqtt_broadcast) + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" 1")); + else + setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" -")); + } + } + } + ShutterSettingsSave(); + ResponseCmndIdxChar(setting_chr); + } +} + +void CmndShutterSetHalfway(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { + ShutterSettings.shutter_set50percent[XdrvMailbox.index -1] = (ShutterSettings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - XdrvMailbox.payload : XdrvMailbox.payload; + ShutterSettings.shuttercoeff[0][XdrvMailbox.index -1] = 0; + if (XdrvMailbox.payload == ShutterSettings.shutter_position[XdrvMailbox.index -1]){ + ShutterSettings.shutter_position[XdrvMailbox.index -1] = 50; + } + // Init calculates the realposition from the %-Position + ShutterInit(); + } + ResponseCmndIdxNumber((ShutterSettings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - ShutterSettings.shutter_set50percent[XdrvMailbox.index -1] : ShutterSettings.shutter_set50percent[XdrvMailbox.index -1]); + } +} + +void CmndShutterFrequency(void) +{ + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 20000)) { + ShutterGlobal.open_velocity_max = XdrvMailbox.payload; + if (TasmotaGlobal.shutters_present < 4) { + ShutterSettings.shuttercoeff[4][3] = ShutterGlobal.open_velocity_max; + } + ShutterInit(); + } + ResponseCmndNumber(ShutterGlobal.open_velocity_max); +} + +void CmndShutterSetClose(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + Shutter[XdrvMailbox.index -1].real_position = 0; + Shutter[XdrvMailbox.index -1].tilt_real_pos = Shutter[XdrvMailbox.index -1].tilt_config[0]; + ShutterStartInit(XdrvMailbox.index -1, 0, 0); + ShutterSettings.shutter_position[XdrvMailbox.index -1] = 0; + ResponseCmndIdxChar(D_CONFIGURATION_RESET); + } +} + +void CmndShutterSetOpen(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + Shutter[XdrvMailbox.index -1].real_position = Shutter[XdrvMailbox.index -1].open_max; + Shutter[XdrvMailbox.index -1].tilt_real_pos = Shutter[XdrvMailbox.index -1].tilt_config[1]; + ShutterStartInit(XdrvMailbox.index -1, 0, Shutter[XdrvMailbox.index -1].open_max); + ShutterSettings.shutter_position[XdrvMailbox.index -1] = 100; + ResponseCmndIdxChar(D_CONFIGURATION_RESET); + } +} + +void CmndShutterPwmRange(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + uint8_t i = 0; + char *str_ptr; + + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 2; str = strtok_r(nullptr, " ", &str_ptr), i++) { + uint16_t field = atoi(str); + // The fields in a data string can only range from 1-30000. + // and following value must be higher than previous one + if ((field <= 0) || (field > 1023)) { + break; + } + ShutterSettings.shutter_pwmrange[i][XdrvMailbox.index -1] = field; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init1. pwmmin %d, pwmmax %d"), XdrvMailbox.index , ShutterSettings.shutter_pwmrange[0][XdrvMailbox.index -1], ShutterSettings.shutter_pwmrange[1][XdrvMailbox.index -1]); + ShutterInit(); + ResponseCmndIdxChar(XdrvMailbox.data); + } else { + char setting_chr[30] = "0"; + snprintf_P(setting_chr, sizeof(setting_chr), PSTR("Shutter %d: min:%d max:%d"), XdrvMailbox.index, ShutterSettings.shutter_pwmrange[0][XdrvMailbox.index -1], ShutterSettings.shutter_pwmrange[1][XdrvMailbox.index -1]); + ResponseCmndIdxChar(setting_chr); + } + } +} + +void CmndShutterCalibration(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + uint8_t i = 0; + char *str_ptr; + + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 5; str = strtok_r(nullptr, " ", &str_ptr), i++) { + int field = atoi(str); + // The fields in a data string can only range from 1-30000. + // and following value must be higher than previous one + if ((field <= 0) || (field > 30000) || ( (i>0) && (field <= messwerte[i-1]) ) ) { + break; + } + messwerte[i] = field; + } + ShutterSettings.shutter_set50percent[XdrvMailbox.index -1] = 50; + for (i = 0; i < 5; i++) { + ShutterSettings.shuttercoeff[i][XdrvMailbox.index -1] = SHT_DIV_ROUND((uint32_t)messwerte[i] * 1000, messwerte[4]); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shuttercoeff %d, i %d, Value %d, MeasuredValue %d"), i,XdrvMailbox.index -1,ShutterSettings.shuttercoeff[i][XdrvMailbox.index -1], messwerte[i]); + } + ShutterInit(); + ResponseCmndIdxChar(XdrvMailbox.data); + } else { + char setting_chr[30] = "0"; + snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), ShutterSettings.shuttercoeff[0][XdrvMailbox.index -1], ShutterSettings.shuttercoeff[1][XdrvMailbox.index -1], ShutterSettings.shuttercoeff[2][XdrvMailbox.index -1], ShutterSettings.shuttercoeff[3][XdrvMailbox.index -1], ShutterSettings.shuttercoeff[4][XdrvMailbox.index -1]); + ResponseCmndIdxChar(setting_chr); + } + } +} + +void ShutterOptionsSetHelper(uint16_t option) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.payload == 0) { + ShutterSettings.shutter_options[XdrvMailbox.index -1] &= ~(option); + } else if (XdrvMailbox.payload == 1) { + ShutterSettings.shutter_options[XdrvMailbox.index -1] |= (option); + } + ResponseCmndIdxNumber((ShutterSettings.shutter_options[XdrvMailbox.index -1] & option) ? 1 : 0); + } +} + +void CmndShutterInvert(void) +{ + ShutterOptionsSetHelper(1); +} + +void CmndShutterLock(void) +{ + ShutterOptionsSetHelper(2); +} + +void CmndShutterEnableEndStopTime(void) +{ + ShutterOptionsSetHelper(4); +} + +void CmndShutterInvertWebButtons(void) +{ + ShutterOptionsSetHelper(8); +} + +void CmndShutterSetTilt(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.payload != -99 ) { + Shutter[XdrvMailbox.index -1].tilt_target_pos = tmin(tmax(XdrvMailbox.payload, Shutter[XdrvMailbox.index -1].tilt_config[0]), Shutter[XdrvMailbox.index -1].tilt_config[1]); + } + // assuming OPEN=100=tilt_config[3]/CLOSE=0=tilt_config[4] + if (XdrvMailbox.data_len > 3 && XdrvMailbox.payload >= 0 ) { + Shutter[XdrvMailbox.index -1].tilt_target_pos = Shutter[XdrvMailbox.index -1].tilt_config[XdrvMailbox.payload?3:4]; + } + } + XdrvMailbox.data[0] = '\0'; + AddLog(LOG_LEVEL_INFO, PSTR("SHT: TiltTarget %d, payload %d"), Shutter[XdrvMailbox.index -1].tilt_target_pos,XdrvMailbox.payload); + Shutter[XdrvMailbox.index -1].tiltmoving = 1; + // Avoid shutterposition try to interpret "open/close or payload" + XdrvMailbox.data_len = 0; + XdrvMailbox.payload = -99; + CmndShutterPosition(); +} + +void CmndShutterTiltConfig(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + uint8_t i = 0; + char *str_ptr; + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 6; str = strtok_r(nullptr, " ", &str_ptr), i++) { + Shutter[XdrvMailbox.index -1].tilt_config[i] = ShutterSettings.shutter_tilt_config[i][XdrvMailbox.index -1] = atoi(str); + } + // avoid negative runtime + ShutterSettings.shutter_tilt_config[2][XdrvMailbox.index -1] = Shutter[XdrvMailbox.index -1].tilt_config[2] = Shutter[XdrvMailbox.index -1].tilt_config[2] >= 0 ? Shutter[XdrvMailbox.index -1].tilt_config[2] : 127; + ShutterInit(); + } + char setting_chr[30] = "0"; + snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); + ResponseCmndIdxChar(setting_chr); + AddLog(LOG_LEVEL_INFO, PSTR("SHT: TiltConfig %d, min: %d, max %d, runtime %d, close_pos: %d, open_pos: %d"), XdrvMailbox.index ,Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); + } +} + +void CmndShutterTiltIncDec(void) +{ + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Change in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, TasmotaGlobal.last_source ); + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present) && XdrvMailbox.data_len > 0) { + XdrvMailbox.payload = Shutter[XdrvMailbox.index -1].tilt_target_pos+XdrvMailbox.payload; + CmndShutterSetTilt(); + } else { + ResponseCmndIdxNumber(XdrvMailbox.payload); + } +} + +void CmndShutterMotorStop(void) +{ + if (!XdrvMailbox.usridx) { + if ((XdrvMailbox.payload >= 0) ) { + ShutterSettings.shutter_motorstop = XdrvMailbox.payload; + ShutterInit(); + } + ResponseCmndNumber(ShutterSettings.shutter_motorstop); + } +} + +uint16_t ShutterGetCycleTime(uint8_t i, uint8_t max_runtime) { + uint32_t cycle_time = 0; + bool started = false; + uint32_t last_time; + char time_chr[10]; + + last_time = millis(); + while (!started && millis()-last_time < max_runtime * 1000) { + loop(); + if (Shutter[i].direction) { + started = true; + last_time = millis(); + } + } + if (!started) return 0; + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup. Start detected. Waiting for STOP")); + while (Shutter[i].direction && millis()-last_time < max_runtime * 1000) { + loop(); + } + if (Shutter[i].direction) { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup. No stop detected... Cancel")); + return 0; + } + // reduce cycle time by 0.1 because 2 Steps required to detect motorstop + cycle_time = (millis()-last_time)/100 - (Shutter[i].motordelay * 10 / STEPS_PER_SECOND)-0.1 ; + dtostrfd((float)(cycle_time) / 10, 1, time_chr); + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup. Cycletime is: %s sec"),time_chr); + return cycle_time; +} + +void CmndShutterSetup(void) { + uint8_t index_no; + char time_chr[10]; + uint32_t new_opentime; + uint32_t new_closetime; + uint8_t max_runtime = 120; // max 120 seconds runtime + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + index_no = XdrvMailbox.index-1; // save, because will be changed in following operations + // init shutter to default settings + ShutterGlobal.callibration_run = true; + ShutterSettings.shutter_position[index_no] = 0; + ShutterSettings.shutter_closetime[index_no] = max_runtime * 10; + ShutterSettings.shutter_opentime[index_no] = max_runtime * 10; + ShutterInit(); + if (Energy->phase_count > 1) { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup: Ensure shutter is close. Now open, autostop detect. max duration is 2min Phase:%d"),Energy->phase_count); + ShutterWaitForMotorStop(index_no); + CmndShutterOpen(); + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup: Ensure shutter is close. Now open and stop when open. max duration is 2min")); + } + + new_opentime = ShutterGetCycleTime(index_no, max_runtime); + if (new_opentime) { + ShutterSettings.shutter_position[index_no] = 100; + ShutterInit(); + if (Energy->phase_count > 1) { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup: Now close, autostop detect. max duration is 2min")); + ShutterWaitForMotorStop(index_no); + CmndShutterClose(); + }else { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Setup: Now close and stop when closed. max duration is 2min")); + } + + new_closetime = ShutterGetCycleTime(index_no, max_runtime); + ShutterSettings.shutter_position[index_no] = 0; + if (new_closetime) { + ShutterSettings.shutter_opentime[index_no] = new_opentime; + ShutterSettings.shutter_closetime[index_no] = new_closetime; + //good default value for normal european shutters. Setting here because Position == 0 + ShutterSettings.shutter_set50percent[index_no] = 70; + ShutterInit(); + } + } + ShutterGlobal.callibration_run = false; + } else { + // print out help instructions + // will only work without TILT configuration + } + return; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv27(uint32_t function) +{ + bool result = false; + + if (Settings->flag3.shutter_mode) { // SetOption80 - Enable shutter support + uint8_t counter = XdrvMailbox.index==0?1:XdrvMailbox.index; + uint8_t counterend = XdrvMailbox.index==0?TasmotaGlobal.shutters_present:XdrvMailbox.index; + int32_t rescue_payload = XdrvMailbox.payload; + uint32_t rescue_data_len = XdrvMailbox.data_len; + char stemp1[10]; + power_t save_powermatrix; + switch (function) { + case FUNC_SAVE_SETTINGS: + ShutterSettingsSave(); + break; + case FUNC_PRE_INIT: + ShutterSettingsLoad(0); + ShutterInit(); + break; + case FUNC_RESET_SETTINGS: + ShutterSettingsLoad(1); + break; + case FUNC_EVERY_50_MSECOND: + ShutterUpdatePosition(); + break; + case FUNC_EVERY_SECOND: + //case FUNC_EVERY_250_MSECOND: + ShutterReportPosition(false, MAX_SHUTTERS_ESP32); + break; + case FUNC_COMMAND: + for (uint8_t i = counter; i <= counterend; i++) { + XdrvMailbox.index = i; + XdrvMailbox.payload = rescue_payload; + XdrvMailbox.data_len = rescue_data_len; + result = DecodeCommand(kShutterCommands, ShutterCommand); + } + break; + case FUNC_JSON_APPEND: + for (uint8_t i = 0; i < TasmotaGlobal.shutters_present; i++) { + uint8_t position = (ShutterSettings.shutter_options[i] & 1) ? 100 - ShutterSettings.shutter_position[i] : ShutterSettings.shutter_position[i]; + uint8_t target = (ShutterSettings.shutter_options[i] & 1) ? 100 - ShutterRealToPercentPosition(Shutter[i].target_position, i) : ShutterRealToPercentPosition(Shutter[i].target_position, i); + + ResponseAppend_P(","); + ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter[i].direction,target, Shutter[i].tilt_real_pos); +#ifdef USE_DOMOTICZ + if ((0 == TasmotaGlobal.tele_period) && (0 == i)) { + DomoticzSensor(DZ_SHUTTER, position); + } +#endif // USE_DOMOTICZ + } + break; + case FUNC_SET_POWER: + + // extract the number of the relay that was switched and save for later in Update Position. + ShutterGlobal.RelayCurrentMask = XdrvMailbox.index ^ ShutterGlobal.RelayOldMask; + ShutterGlobal.LastChangedRelay = ShutterGetRelayNoFromBitfield(XdrvMailbox.index ^ ShutterGlobal.RelayOldMask); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER Relaymask %d SwitchedRelay:%d by %s, payload %d, powermask %d"), ShutterGlobal.RelayOldMask, ShutterGlobal.LastChangedRelay,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource),XdrvMailbox.payload, TasmotaGlobal.power); + save_powermatrix = TasmotaGlobal.power; // can be changed in ShutterRelayChanged + if (!ShutterGlobal.LastChangedRelay) { + ShutterGlobal.skip_relay_change = 1; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("INVALID REQUEST")); + } else { + ShutterRelayChanged(); + ShutterGlobal.RelayOldMask = XdrvMailbox.index; // may be changed and now revert + TasmotaGlobal.power = save_powermatrix; + } + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER end. powermask %d"), TasmotaGlobal.power); + break; + case FUNC_SET_DEVICE_POWER: + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_DEVICE_POWER Skipping:%d, Source %s"), ShutterGlobal.skip_relay_change,GetTextIndexed(stemp1, sizeof(stemp1), XdrvMailbox.payload, kCommandSource)); + if (ShutterGlobal.skip_relay_change ) { + //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Skip relay change %d"), i+1); + result = true; + ShutterGlobal.skip_relay_change = 0; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), ShutterGlobal.LastChangedRelay); + //ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER); // should not required anymore. check for bugs + if (ShutterGlobal.LastChangedRelay) ShutterGlobal.RelayOldMask = TasmotaGlobal.power ^= 1<<(ShutterGlobal.LastChangedRelay-1); + } + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_DEVICE_POWER end. powermask %ld, current rel: %ld"), TasmotaGlobal.power, ShutterGlobal.RelayOldMask); + break; + case FUNC_BUTTON_MULTI_PRESSED: + if (XdrvMailbox.index < MAX_SHUTTERS_ESP32*2 && ShutterSettings.shutter_button[XdrvMailbox.index].enabled) { + result = ShutterButtonHandlerMulti(); + } + break; + case FUNC_BUTTON_PRESSED: + if (XdrvMailbox.index < MAX_SHUTTERS_ESP32*2 && ShutterSettings.shutter_button[XdrvMailbox.index].enabled) { + if (!Settings->flag3.mqtt_buttons) Settings->flag3.mqtt_buttons = 1; // ensure to detach buttons from relay to let the shutter controll the relay + ShutterButtonHandler(); + result = false; + } + break; + } + } + return result; +} + +#endif //USE_SHUTTER + +#ifdef SHUTTER_UNITTEST +void CmndShutterUnitTest(void) { + int16_t input_percent[10] = {-5,0,10,26,35,55,80,99,100,105}; + int16_t output_percent[10] = {0,0,10,26,35,55,80,99,100,100}; + uint32_t result_percent[2][2][10] = {{{0,0,24000,62400,84000,132000,192000,237600,240000,240000}, + {0,0,360000,936000,1260000,1980000,2880000,3564000,3600000,3600000}}, + {{0,0,76296,100000,113333,174299,205795,237983,240000,240000}, + {0,0,1144444,1500000,1700000,2614488,3086929,3569748,3600000,3600000}}}; + + uint32_t result = 0; + char svalue[50]; // Command and number parameter + ShutterSettings.shuttercoeff[0][0] = 0; + for (uint8_t i=0; i<2 ; i++){ + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_OPENTIME "%d %d"), 1, 12); + ExecuteCommand(svalue, SRC_SHUTTER); + ShutterInit(); + for (uint8_t j=0; j<2 ; j++){ + for (uint8_t k=0; k<10 ; k++){ + result += (result_percent[i][j][k] == ShutterPercentToRealPosition(input_percent[k] , 0) ? 0 : 1); + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ShutterPercentToRealPosition error %d: %d <-> %d"),result, ShutterPercentToRealPosition(input_percent[k] , 0), result_percent[i][j][k]); + } + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_OPENTIME "%d %d"), 1, 180); + ExecuteCommand(svalue, SRC_SHUTTER); + } + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_CLIBRATION "%d %s"), 1, "15 83 105 185 210"); + ExecuteCommand(svalue, SRC_SHUTTER); + } + if (!result){ + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ShutterPercentToRealPosition: PASS")); + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ShutterPercentToRealPosition: FAIL")); + } + ShutterSettings.shuttercoeff[0][0] = 0; + for (uint8_t i=0; i<2 ; i++){ + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_OPENTIME "%d %d"), 1, 12); + ExecuteCommand(svalue, SRC_SHUTTER); + ShutterInit(); + for (uint8_t j=0; j<2 ; j++){ + for (uint8_t k=0; k<10 ; k++){ + result += (output_percent[k] == ShutterRealToPercentPosition(result_percent[i][j][k] , 0) ? 0 : 1); + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ShutterRealToPercentPosition error %d: %d <-> %d"),result, ShutterRealToPercentPosition(result_percent[i][j][k] , 0), output_percent[k]); + } + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_OPENTIME "%d %d"), 1, 180); + ExecuteCommand(svalue, SRC_SHUTTER); + } + snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_CLIBRATION "%d %s"), 1, "15 83 105 185 210"); + ExecuteCommand(svalue, SRC_SHUTTER); + } + if (!result){ + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ShutterRealToPercentPosition: PASS")); + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("SHT: ShutterRealToPercentPosition: FAIL")); + } +} +#else +void CmndShutterUnitTest(void) {} +#endif + +#endif // ESP32 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index 235cdc8b8..18940e681 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -1,7 +1,7 @@ /* - xdrv_27_Shutter[i].ino - Shutter/Blind support for Tasmota + xdrv_27_Shutter.ino - Shutter/Blind support for Tasmota - Copyright (C) 2022 Stefan Bode + Copyright (C) 2023 Stefan Bode 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 @@ -17,6 +17,22 @@ along with this program. If not, see . */ +// Start temporarly extra tests for overriding USE_SHUTTER_ESP32 **** +// Remove once tests complete +#ifdef ESP8266 +#define USE_SHUTTER_ESP8266 +#endif + +#ifdef ESP32 +#ifndef USE_SHUTTER_ESP32 +#define USE_SHUTTER_ESP8266 +#endif // No USE_SHUTTER_ESP32 +#endif // ESP32 + +#ifdef USE_SHUTTER_ESP8266 +// End ************************************************************** + +//#ifdef ESP8266 #ifdef USE_SHUTTER /*********************************************************************************************\ * Shutter or Blind support using two consecutive relays @@ -104,10 +120,11 @@ struct SHUTTER { int8_t tilt_config[5]; // tilt_min, tilt_max, duration, tilt_closed_value, tilt_opened_value int8_t tilt_real_pos; // -90 to 90 int8_t tilt_target_pos; // target positon for movements of the tilt - int8_t tilt_start_pos; // saved start position before shutter moves - uint8_t tilt_velocity; // degree rotation per step 0.05sec - int8_t tiltmoving; // 0 operating move, 1 = operating tilt - uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position + int8_t tilt_target_pos_override; // one time override of automatic calculation of tilt_target + int8_t tilt_start_pos; // saved start position before shutter moves + uint8_t tilt_velocity; // degree rotation per step 0.05sec + int8_t tiltmoving; // 0 operating move, 1 = operating tilt + uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position uint16_t min_realPositionChange = 0; // minimum change of the position before the shutter operates. different for PWM and time based operations uint16_t min_TiltChange = 0; // minimum change of the tilt before the shutter operates. different for PWM and time based operations uint16_t last_reported_time = 0; // get information on skipped 50ms loop() slots @@ -118,6 +135,7 @@ struct SHUTTERGLOBAL { power_t RelayShutterMask = 0; // bit mask with 11 at the position of relays that belong to at least ONE shutter power_t RelayOldMask = 0; // bitmatrix that contain the last known state of all relays. Required to detemine the manual changed relay. power_t RelayCurrentMask = 0; // bitmatrix that contain the current state of all relays + uint8_t LastChangedRelay = 0; // Relay 1..32, 0 no change uint8_t position_mode = 0; // how to calculate actual position: SHT_TIME, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME uint8_t skip_relay_change; // avoid overrun at endstops uint8_t start_reported = 0; // indicates of the shutter start was reported through MQTT JSON @@ -126,6 +144,37 @@ struct SHUTTERGLOBAL { #define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B)) +uint8_t ShutterGetRelayNoFromBitfield(power_t number) { + int position = 0; + while (number != 0) { + position++; + if (number & 1) return position; + number >>= 1; + } + return 0; // return 0 if no relay found +} + +bool ShutterStatus(void) { + if (Settings->flag3.shutter_mode) { // SetOption80 - (Shutter) Enable shutter support (1) + Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS13_SHUTTER "\":{")); + for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + if (0 == Settings->shutter_startrelay[i]) { break; } + if (i > 0) { ResponseAppend_P(PSTR(",")); } + ResponseAppend_P(PSTR("\"" D_STATUS13_SHUTTER "%d\":{\"Relay1\":%d,\"Relay2\":%d,\"Open\":%d,\"Close\":%d," + "\"50perc\":%d,\"Delay\":%d,\"Opt\":\"%s\"," + "\"Calib\":[%d,%d,%d,%d,%d]," + "\"Mode\":\"%d\"}"), + i, Settings->shutter_startrelay[i], Settings->shutter_startrelay[i] +1, Settings->shutter_opentime[i], Settings->shutter_closetime[i], + Settings->shutter_set50percent[i], Settings->shutter_motordelay[i], GetBinary8(Settings->shutter_options[i], 4).c_str(), + Settings->shuttercoeff[0][i], Settings->shuttercoeff[1][i], Settings->shuttercoeff[2][i], Settings->shuttercoeff[3][i], Settings->shuttercoeff[4][i], + Settings->shutter_mode); + } + ResponseJsonEndEnd(); + return true; + } + return false; +} + void ShutterLogPos(uint32_t i) { @@ -136,6 +185,14 @@ void ShutterLogPos(uint32_t i) Shutter[i].pwm_velocity, Shutter[i].pwm_value,Shutter[i].tilt_real_pos); } +uint8_t ShutterGetStartRelay(uint8_t index) { + return Settings->shutter_startrelay[index]; +} + +int8_t ShutterGetTiltConfig(uint8_t config_idx,uint8_t index) { + return Shutter[index].tilt_config[config_idx]; +} + void ExecuteCommandPowerShutter(uint32_t device, uint32_t state, uint32_t source) { // first implementation for virtual relays. Avoid switching relay numbers that do not exist. @@ -238,6 +295,9 @@ int32_t ShutterPercentToRealPosition(int16_t percent, uint32_t index) uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) { + if (realpos == -9999) { + realpos = Shutter[index].real_position; + } if (Settings->shutter_set50percent[index] != 50) { return (Settings->shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, Settings->shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-Settings->shuttercoeff[0][index]*10, Settings->shuttercoeff[1][index]); } else { @@ -277,7 +337,6 @@ void ShutterInit(void) } for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { // set startrelay to 1 on first init, but only to shutter 1. 90% usecase - //Settings->shutter_startrelay[i] = (Settings->shutter_startrelay[i] == 0 && i == 0? 1 : Settings->shutter_startrelay[i]); if (Settings->shutter_startrelay[i] && (Settings->shutter_startrelay[i] <= 32 )) { bool relay_in_interlock = false; TasmotaGlobal.shutters_present++; @@ -596,15 +655,15 @@ void ShutterPowerOff(uint8_t i) Shutter[i].last_stop_time = millis(); } -void ShutterWaitForMotorStop(uint8_t index) +void ShutterWaitForMotorStop(uint8_t i) { - Shutter[index-1].last_stop_time = millis(); - ShutterWaitForMotorStart(index); + Shutter[i].last_stop_time = millis(); + ShutterWaitForMotorStart(i); } -void ShutterWaitForMotorStart(uint8_t index) +void ShutterWaitForMotorStart(uint8_t i) { - while (millis() < Shutter[index-1].last_stop_time + Settings->shutter_motorstop) { + while (millis() < Shutter[i].last_stop_time + Settings->shutter_motorstop) { loop(); } //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stoptime done")); @@ -700,7 +759,7 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos) ShutterGlobal.skip_relay_change = 1; } else { Shutter[i].pwm_velocity = 0; - ShutterWaitForMotorStart(i+1); + ShutterWaitForMotorStart(i); switch (ShutterGlobal.position_mode) { #ifdef SHUTTER_STEPPER case SHT_COUNTER: @@ -760,8 +819,8 @@ int32_t ShutterCalculatePosition(uint32_t i) case SHT_TIME_UP_DOWN: case SHT_TIME_GARAGE: if (Shutter[i].tilt_config[2] > 0) { - if (Shutter[i].time <= Shutter[i].venetian_delay) { - Shutter[i].tilt_real_pos = (Shutter[i].tilt_start_pos + ((Shutter[i].direction * (int16_t)Shutter[i].time * (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])) / Shutter[i].tilt_config[2])); + if (Shutter[i].time <= Shutter[i].venetian_delay+Shutter[i].motordelay) { + Shutter[i].tilt_real_pos = (Shutter[i].tilt_start_pos + ((Shutter[i].direction * (int16_t)(Shutter[i].time - tmin(Shutter[i].motordelay, Shutter[i].time)) * (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])) / Shutter[i].tilt_config[2])); } else { Shutter[i].tilt_real_pos = Shutter[i].direction == 1 ? Shutter[i].tilt_config[1] : Shutter[i].tilt_config[0]; } @@ -834,6 +893,7 @@ void ShutterRelayChanged(void) default: //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i); Shutter[i].target_position = Shutter[i].real_position; + Shutter[i].last_stop_time = millis(); } break; case SHT_TIME: @@ -845,8 +905,9 @@ void ShutterRelayChanged(void) ShutterStartInit(i, -1, 0); break; default: - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i+1); Shutter[i].target_position = Shutter[i].real_position; + Shutter[i].last_stop_time = millis(); } break; case SHT_TIME_GARAGE: @@ -877,7 +938,7 @@ bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_ind return ((-1 != min_shutterbutton_hold_timer) && (min_shutterbutton_hold_timer > (Button.hold_timer[button_index]>>1))); } -void ShutterButtonHandler(void) +bool ShutterButtonHandler(void) { uint8_t buttonState = SHT_NOT_PRESSED; uint8_t button = XdrvMailbox.payload; @@ -1002,14 +1063,14 @@ void ShutterButtonHandler(void) char scmnd[20]; snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); ExecuteCommand(scmnd, SRC_BUTTON); - return; + return true; } else if ((buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS) || ((shutter_index_num_buttons==1) && (buttonState == SHT_PRESSED_EXT_HOLD))){ // no SetOption1 (0) checked above // simultaneous or stand alone button extended hold detected char scmnd[20]; snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); ExecuteCommand(scmnd, SRC_BUTTON); - return; + return true; } } if (buttonState <= SHT_PRESSED_IMMEDIATE) { @@ -1068,6 +1129,7 @@ void ShutterButtonHandler(void) ResponseJsonEnd(); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); } + return true; } void ShutterSetPosition(uint32_t device, uint32_t position) @@ -1226,6 +1288,25 @@ void CmndShutterPosition(void) //limit the payload AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Pos. payload <%s> (%d), payload %d, idx %d (%d), src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, XdrvMailbox.usridx, TasmotaGlobal.last_source ); + if (XdrvMailbox.data_len >= 3) { + // check if input is of format "position,tilt" + uint32_t i = 0; + char *str_ptr; + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ',' seperators. + for (char *str = strtok_r(data_copy, ",", &str_ptr); str && i < 2; str = strtok_r(nullptr, ",", &str_ptr), i++) { + switch(i) { + case 0: + XdrvMailbox.payload = atoi(str); + break; + case 1: + Shutter[index].tilt_target_pos_override = atoi(str); + break; + } + } + } + // value 0 with data_len > 0 can mean Open // special handling fo UP,DOWN,TOGGLE,STOP command comming with payload -99 // STOP will come with payload 0 because predefined value in TASMOTA @@ -1259,6 +1340,12 @@ void CmndShutterPosition(void) // if position is either 0 or 100 reset the tilt to avoid tilt moving at the end if (XdrvMailbox.payload == 0 && ShutterRealToPercentPosition(Shutter[index].real_position, index) > 0 ) {Shutter[index].tilt_target_pos = Shutter[index].tilt_config[4];} if (XdrvMailbox.payload == 100 && ShutterRealToPercentPosition(Shutter[index].real_position, index) < 100) {Shutter[index].tilt_target_pos = Shutter[index].tilt_config[3];} + + // manual override of tiltposition + if (Shutter[index].tilt_target_pos_override != -128) { + Shutter[index].tilt_target_pos = tmin(tmax( Shutter[index].tilt_config[0],Shutter[index].tilt_target_pos_override ), Shutter[index].tilt_config[1]); + Shutter[index].tilt_target_pos_override = -128; + } int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? (XdrvMailbox.payload == -99 ? ShutterRealToPercentPosition(Shutter[index].real_position, index) : 0) : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload); // webgui still send also on inverted shutter the native position. @@ -1274,8 +1361,8 @@ void CmndShutterPosition(void) (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange || abs(Shutter[index].tilt_target_pos - Shutter[index].tilt_real_pos ) > Shutter[index].min_TiltChange) ) { if (Settings->shutter_options[index] & 4) { - if (0 == target_pos_percent) Shutter[index].target_position -= 1 * RESOLUTION * STEPS_PER_SECOND; - if (100 == target_pos_percent) Shutter[index].target_position += 1 * RESOLUTION * STEPS_PER_SECOND; + if (0 == target_pos_percent && Shutter[index].real_position > 0) Shutter[index].target_position -= 1 * RESOLUTION * STEPS_PER_SECOND; + if (100 == target_pos_percent && Shutter[index].real_position < Shutter[index].open_max) Shutter[index].target_position += 1 * RESOLUTION * STEPS_PER_SECOND; } int8_t new_shutterdirection; if (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange) { @@ -1814,6 +1901,8 @@ bool Xdrv27(uint32_t function) uint8_t counterend = XdrvMailbox.index==0?TasmotaGlobal.shutters_present:XdrvMailbox.index; int32_t rescue_payload = XdrvMailbox.payload; uint32_t rescue_data_len = XdrvMailbox.data_len; + char stemp1[10]; + power_t save_powermatrix; switch (function) { case FUNC_PRE_INIT: ShutterInit(); @@ -1848,27 +1937,31 @@ bool Xdrv27(uint32_t function) } break; case FUNC_SET_POWER: - char stemp1[10]; + // extract the number of the relay that was switched and save for later in Update Position. ShutterGlobal.RelayCurrentMask = XdrvMailbox.index ^ ShutterGlobal.RelayOldMask; - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Switched relay %d by %s"), ShutterGlobal.RelayCurrentMask,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource)); - ShutterRelayChanged(); - ShutterGlobal.RelayOldMask = XdrvMailbox.index; + ShutterGlobal.LastChangedRelay = ShutterGetRelayNoFromBitfield(XdrvMailbox.index ^ ShutterGlobal.RelayOldMask); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER Relaymask %d SwitchedRelay:%d by %s, payload %d, powermask %d"), ShutterGlobal.RelayOldMask, ShutterGlobal.LastChangedRelay,GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource),XdrvMailbox.payload, TasmotaGlobal.power); + save_powermatrix = TasmotaGlobal.power; + if (!ShutterGlobal.LastChangedRelay) { + ShutterGlobal.skip_relay_change = 1; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("INVALID REQUEST")); + } else { + ShutterRelayChanged(); + ShutterGlobal.RelayOldMask = XdrvMailbox.index; + TasmotaGlobal.power = save_powermatrix; + } + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: FUNC_SET_POWER end. powermask %d"), TasmotaGlobal.power); break; case FUNC_SET_DEVICE_POWER: if (ShutterGlobal.skip_relay_change ) { - uint8_t i; - for (i = 0; i < TasmotaGlobal.devices_present; i++) { - if (ShutterGlobal.RelayCurrentMask &1) { - break; - } - ShutterGlobal.RelayCurrentMask >>= 1; - } //AddLog(LOG_LEVEL_ERROR, PSTR("SHT: Skip relay change %d"), i+1); result = true; ShutterGlobal.skip_relay_change = 0; - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), i); - ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"), ShutterGlobal.LastChangedRelay); + //ExecuteCommandPowerShutter(i+1, 0, SRC_SHUTTER); + if (ShutterGlobal.LastChangedRelay) ShutterGlobal.RelayOldMask = TasmotaGlobal.power ^= 1<<(ShutterGlobal.LastChangedRelay-1); + //ShutterGlobal.RelayOldMask ^= 1<<(ShutterGlobal.LastChangedRelay-1); } break; case FUNC_BUTTON_PRESSED: @@ -1941,3 +2034,5 @@ void CmndShutterUnitTest(void) { #else void CmndShutterUnitTest(void) {} #endif + +#endif // ESP8266 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino deleted file mode 100644 index 891e07f44..000000000 --- a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino +++ /dev/null @@ -1,385 +0,0 @@ -/* - xdrv_28_pcf8574.ino - PCF8574 I2C support for Tasmota - - Copyright (C) 2021 Stefan Bode - - 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 . -*/ - -#ifdef USE_I2C -#ifdef USE_PCF8574 -/*********************************************************************************************\ - * PCF8574 - I2C IO Expander - * - * I2C Address: PCF8574 = 0x20 .. 0x27 (0x27 is not supported), - * PCF8574A = 0x39 .. 0x3F (0x38 is not supported) -\*********************************************************************************************/ - -#define XDRV_28 28 -#define XI2C_02 2 // See I2CDEVICES.md - -// Start address and count can be overriden in user_config_override.h to allow better -// sharing of the I2C address space. Still the covered range must remains valid. -// A count of 0 can be used totaly disable any of the 2 ranges. -// By default, the following addresses are explicitly excluded (as per the docs) : -// - 0x27 and 0x37 are reserved for USE_DISPLAY_LCD in xdsp_01_lcd.ino -// - 0X38 is reserved for other sensors -// If the respective drivers are not used, overrides allows to recover those addresses -// If defined, USE_MCP230xx_ADDR is also always excluded - -// PCF8574 address range from 0x20 to 0x26 -#ifndef PCF8574_ADDR1 -#define PCF8574_ADDR1 0x20 // PCF8574 -#endif -#ifndef PCF8574_ADDR1_COUNT -#define PCF8574_ADDR1_COUNT 7 -#endif -// PCF8574A address range from 0x39 to 0x3E -#ifndef PCF8574_ADDR2 -#define PCF8574_ADDR2 0x39 // PCF8574A -#endif -#ifndef PCF8574_ADDR2_COUNT -#define PCF8574_ADDR2_COUNT 6 -#endif - -// Consitency tests - Checked across the complete range for the PCF8574/PCF8574A to allow override -#if (PCF8574_ADDR1 < 0x20) || ((PCF8574_ADDR1 + PCF8574_ADDR1_COUNT - 1) > 0x27) -#error PCF8574_ADDR1 and/or PCF8574_ADDR1_COUNT badly overriden. Fix your user_config_override -#endif -#if (PCF8574_ADDR2 < 0x38) || ((PCF8574_ADDR2 + PCF8574_ADDR2_COUNT - 1) > 0x3F) -#error PCF8574_ADDR2 and/or PCF8574_ADDR2_COUNT badly overriden. Fix your user_config_override. -#endif - -struct PCF8574 { - int error; - uint8_t pin[64]; - uint8_t address[MAX_PCF8574]; - uint8_t pin_mask[MAX_PCF8574] = { 0 }; -#ifdef USE_PCF8574_MQTTINPUT - uint8_t last_input[MAX_PCF8574] = { 0 }; -#endif - uint8_t max_connected_ports = 0; // Max numbers of devices comming from PCF8574 modules - uint8_t max_devices = 0; // Max numbers of PCF8574 modules - char stype[9]; - bool type = false; -} Pcf8574; - -uint8_t Pcf8574Read(uint8_t idx) -{ - Wire.requestFrom(Pcf8574.address[idx],(uint8_t)1); - return Wire.read(); -} - -uint8_t Pcf8574Write(uint8_t idx) -{ - Wire.beginTransmission(Pcf8574.address[idx]); - Wire.write(Pcf8574.pin_mask[idx]); - return Wire.endTransmission(); -} - -void Pcf8574SwitchRelay(void) -{ - for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { - uint8_t relay_state = bitRead(XdrvMailbox.index, i); - - if (Pcf8574.max_devices > 0 && Pcf8574.pin[i] < 99) { - uint8_t board = Pcf8574.pin[i]>>3; - uint8_t pin = Pcf8574.pin[i]&0x7; - uint8_t oldpinmask = Pcf8574.pin_mask[board]; - uint8_t _val = bitRead(TasmotaGlobal.rel_inverted, i) ? !relay_state : relay_state; - - //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: SwitchRelay %d=%d => PCF-%d.D%d=%d"), i, relay_state, board +1, pin, _val); - bitWrite(Pcf8574.pin_mask[board], pin, _val); - if (oldpinmask != Pcf8574.pin_mask[board]) { - Pcf8574.error = Pcf8574Write(board); - } - //else AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: SwitchRelay skipped")); - } - } -} - -void Pcf8574Init(void) -{ - uint8_t pcf8574_address = (PCF8574_ADDR1_COUNT > 0) ? PCF8574_ADDR1 : PCF8574_ADDR2; - while ((Pcf8574.max_devices < MAX_PCF8574) && (pcf8574_address < PCF8574_ADDR2 +PCF8574_ADDR2_COUNT)) { - -#if defined(USE_MCP230xx) && defined(USE_MCP230xx_ADDR) - if (USE_MCP230xx_ADDR == pcf8574_address) { - AddLog(LOG_LEVEL_INFO, PSTR("PCF: Address 0x%02x reserved for MCP320xx skipped"), pcf8574_address); - pcf8574_address++; - if ((PCF8574_ADDR1 +PCF8574_ADDR1_COUNT) == pcf8574_address) { // See comment on allowed addresses and overrides - pcf8574_address = PCF8574_ADDR2; - } - } -#endif - - // AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Probing addr: 0x%x for PCF8574"), pcf8574_address); - - if (I2cSetDevice(pcf8574_address)) { - Pcf8574.type = true; - - Pcf8574.address[Pcf8574.max_devices] = pcf8574_address; - Pcf8574.max_devices++; - - strcpy(Pcf8574.stype, "PCF8574"); - if (pcf8574_address >= PCF8574_ADDR2) { - strcpy(Pcf8574.stype, "PCF8574A"); - } - I2cSetActiveFound(pcf8574_address, Pcf8574.stype); - } - - pcf8574_address++; - if ((PCF8574_ADDR1 +PCF8574_ADDR1_COUNT) == pcf8574_address) { // Support I2C addresses 0x20 to 0x26 and 0x39 to 0x3F - pcf8574_address = PCF8574_ADDR2; - } - } - if (Pcf8574.type) { - for (uint32_t i = 0; i < sizeof(Pcf8574.pin); i++) { - Pcf8574.pin[i] = 99; - } - TasmotaGlobal.devices_present = TasmotaGlobal.devices_present - Pcf8574.max_connected_ports; // reset no of devices to avoid duplicate ports on duplicate init. - Pcf8574.max_connected_ports = 0; // reset no of devices to avoid duplicate ports on duplicate init. - for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { // suport up to 8 boards PCF8574 - uint8_t gpio = Pcf8574Read(idx); - // Insure the input pins are actually writen a 1 for proper input operation - Pcf8574.pin_mask[idx] = gpio | ~Settings->pcf8574_config[idx]; - Pcf8574Write(idx); // Write back to the register -#ifdef USE_PCF8574_MQTTINPUT - Pcf8574.last_input[idx] = gpio & ~Settings->pcf8574_config[idx]; -#endif // #ifdef USE_PCF8574_MQTTINPUT - //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: PCF-%d config=0x%02x, gpio=0x%02X"), idx +1, Settings->pcf8574_config[idx], gpio); - - for (uint32_t i = 0; i < 8; i++, gpio>>=1) { - uint8_t _result = Settings->pcf8574_config[idx] >> i &1; - //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: I2C shift i %d: %d. Powerstate: %d, TasmotaGlobal.devices_present: %d"), i,_result, Settings->power>>i&1, TasmotaGlobal.devices_present); - if (_result > 0) { - Pcf8574.pin[TasmotaGlobal.devices_present] = i + 8 * idx; - bitWrite(TasmotaGlobal.rel_inverted, TasmotaGlobal.devices_present, Settings->flag3.pcf8574_ports_inverted); // SetOption81 - Invert all ports on PCF8574 devices - if (!Settings->flag.save_state && !Settings->flag3.no_power_feedback) { // SetOption63 - Don't scan relay power state at restart - #5594 and #5663 - //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Set power from from chip state")); - uint8_t power_state = Settings->flag3.pcf8574_ports_inverted ? 1 & ~gpio : 1 & gpio; - bitWrite(TasmotaGlobal.power, TasmotaGlobal.devices_present, power_state); - bitWrite(Settings->power, TasmotaGlobal.devices_present, power_state); - } - //else AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: DON'T set power from chip state")); - TasmotaGlobal.devices_present++; - Pcf8574.max_connected_ports++; - } - } - } - //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Settings->power=0x%08X, TasmotaGlobal.power=0x%08X"), Settings->power, TasmotaGlobal.power); - AddLog(LOG_LEVEL_INFO, PSTR("PCF: Total devices %d, PCF8574 output ports %d"), Pcf8574.max_devices, Pcf8574.max_connected_ports); - } -} - -/*********************************************************************************************\ - * Presentation -\*********************************************************************************************/ - -#ifdef USE_WEBSERVER - -#define WEB_HANDLE_PCF8574 "pcf" - -const char HTTP_BTN_MENU_PCF8574[] PROGMEM = - "

"; - -const char HTTP_FORM_I2C_PCF8574_1[] PROGMEM = - "
 " D_PCF8574_PARAMETERS " " - "
" - "


"; - -const char HTTP_FORM_I2C_PCF8574_2[] PROGMEM = - "
"; - -const char HTTP_SNS_PCF8574_GPIO[] PROGMEM = "{s}PCF8574%c%d D%d{m}%d{e}"; // {s} = - - -void HandlePcf8574(void) -{ - if (!HttpCheckPriviledgedAccess()) { return; } - - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_PCF8574)); - - if (Webserver->hasArg("save")) { - Pcf8574SaveSettings(); - WebRestart(1); - return; - } - - WSContentStart_P(D_CONFIGURE_PCF8574); - WSContentSendStyle(); - WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings->flag3.pcf8574_ports_inverted) ? PSTR(" checked") : ""); // SetOption81 - Invert all ports on PCF8574 devices - WSContentSend_P(HTTP_TABLE100); - for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { - for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574 - uint8_t helper = 1 << idx2; - WSContentSend_P(HTTP_FORM_I2C_PCF8574_2, - idx +1, idx2, - idx2 + 8*idx, - idx2 + 8*idx, - ((helper & Settings->pcf8574_config[idx]) >> idx2 == 0) ? PSTR(" selected ") : " ", - ((helper & Settings->pcf8574_config[idx]) >> idx2 == 1) ? PSTR(" selected ") : " " - ); - } - } - WSContentSend_P(PSTR("
" D_DEVICE " %d " D_PORT " %d
, {m} = , {e} =
")); - WSContentSend_P(HTTP_FORM_END); - WSContentSpaceButton(BUTTON_CONFIGURATION); - WSContentStop(); -} - -#if defined(USE_PCF8574_SENSOR) || defined(USE_PCF8574_DISPLAYINPUT) -void Pcf8574Show(bool json) -{ -#ifdef USE_PCF8574_SENSOR - if (json) { - for (int idx = 0 ; idx < Pcf8574.max_devices ; idx++) - { - uint8_t gpio = Pcf8574Read(idx); - ResponseAppend_P(PSTR(",\"PCF8574%c%d\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i}"), - IndexSeparator(), idx +1, - (gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); - } - } -#endif // #ifdef USE_PCF8574_SENSOR -#if defined(USE_WEBSERVER) && defined(USE_PCF8574_DISPLAYINPUT) - if(!json) { - for (int idx = 0 ; idx < Pcf8574.max_devices ; idx++) - { - uint8_t input_mask = ~Settings->pcf8574_config[idx]; //invert to 1 = input - uint8_t gpio = Pcf8574Read(idx); - for (int pin = 0 ; pin < 8 ; ++pin, input_mask>>=1, gpio>>=1) - { - if (input_mask & 1) - WSContentSend_P(HTTP_SNS_PCF8574_GPIO, IndexSeparator(), idx +1, pin, gpio & 1); - } - } - } -#endif // defined(USE_WEBSERVER) && defined(USE_PCF8574_DISPLAYINPUT) -} -#endif // #if defined(USE_PCF8574_SENSOR) || defined(USE_PCF8574_DISPLAYINPUT) - - -#ifdef USE_PCF8574_MQTTINPUT -void Pcf8574CheckForInputChange(void) -{ - for (int idx = 0 ; idx < Pcf8574.max_devices ; idx++) - { - uint8_t input_mask = ~Settings->pcf8574_config[idx]; //invert to 1 = input - uint8_t input = Pcf8574Read(idx) & input_mask; - uint8_t last_input = Pcf8574.last_input[idx]; - if (input != last_input) { // don't scan bits if no change (EVERY_50_MS !) - for (uint8_t pin = 0 ; pin < 8 ; ++pin) { - if (bitRead(input_mask,pin) && bitRead(input,pin) != bitRead(last_input,pin)) { - ResponseTime_P(PSTR(",\"PCF8574%c%d_INP\":{\"D%i\":%i}}"), IndexSeparator(), idx +1, pin, bitRead(input,pin)); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("PCF8574_INP")); - if (Settings->flag3.hass_tele_on_power) { // SetOption59 - Send tele/%topic%/SENSOR in addition to stat/%topic%/RESULT - MqttPublishSensor(); - } - } - Pcf8574.last_input[idx] = input; - } - } - } -} -#endif //#ifdef USE_PCF8574_MQTTINPUT - -void Pcf8574SaveSettings(void) -{ - char stemp[7]; - char tmp[100]; - - //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), Webserver->hasArg("b1"); - - Settings->flag3.pcf8574_ports_inverted = Webserver->hasArg("b1"); // SetOption81 - Invert all ports on PCF8574 devices - for (byte idx = 0; idx < Pcf8574.max_devices; idx++) { - byte count=0; - byte n = Settings->pcf8574_config[idx]; - while(n!=0) { - n = n&(n-1); - count++; - } - if (count <= TasmotaGlobal.devices_present) { - TasmotaGlobal.devices_present = TasmotaGlobal.devices_present - count; - } - for (byte i = 0; i < 8; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("i2cs%d"), i+8*idx); - WebGetArg(stemp, tmp, sizeof(tmp)); - byte _value = (!strlen(tmp)) ? 0 : atoi(tmp); - if (_value) { - Settings->pcf8574_config[idx] = Settings->pcf8574_config[idx] | 1 << i; - TasmotaGlobal.devices_present++; - Pcf8574.max_connected_ports++; - } else { - Settings->pcf8574_config[idx] = Settings->pcf8574_config[idx] & ~(1 << i ); - } - } - //Settings->pcf8574_config[0] = (!strlen(webServer->arg("i2cs0").c_str())) ? 0 : atoi(webServer->arg("i2cs0").c_str()); - //AddLog(LOG_LEVEL_INFO, PSTR("PCF: I2C Board: %d, Config: %2x")), idx, Settings->pcf8574_config[idx]; - - } -} -#endif // USE_WEBSERVER - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xdrv28(uint32_t function) -{ - if (!I2cEnabled(XI2C_02)) { return false; } - - bool result = false; - - if (FUNC_PRE_INIT == function) { - Pcf8574Init(); - } - else if (Pcf8574.type) { - switch (function) { - case FUNC_SET_POWER: - Pcf8574SwitchRelay(); - break; -#ifdef USE_PCF8574_MQTTINPUT - case FUNC_EVERY_50_MSECOND: - Pcf8574CheckForInputChange(); - break; -#endif // #ifdef USE_PCF8574_MQTTINPUT -#ifdef USE_PCF8574_SENSOR - case FUNC_JSON_APPEND: - Pcf8574Show(1); - break; -#endif // #ifdef USE_PCF8574_SENSOR -#ifdef USE_WEBSERVER - case FUNC_WEB_ADD_BUTTON: - WSContentSend_P(HTTP_BTN_MENU_PCF8574); - break; - case FUNC_WEB_ADD_HANDLER: - WebServer_on(PSTR("/" WEB_HANDLE_PCF8574), HandlePcf8574); - break; -#ifdef USE_PCF8574_DISPLAYINPUT - case FUNC_WEB_SENSOR: - Pcf8574Show(0); - break; -#endif // #ifdef USE_PCF8574_DISPLAYINPUT -#endif // USE_WEBSERVER - } - } - return result; -} - -#endif // USE_PCF8574 -#endif // USE_I2C diff --git a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574_v2.ino new file mode 100644 index 000000000..7a04696e4 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574_v2.ino @@ -0,0 +1,754 @@ +/* + xdrv_28_pcf8574.ino - PCF8574 I2C support for Tasmota + + Copyright (C) 2021 Stefan Bode and 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_PCF8574 +/*********************************************************************************************\ + * PCF8574 - I2C IO Expander + * + * I2C Address: PCF8574 = 0x20 .. 0x27 (0x27 is not supported), + * PCF8574A = 0x39 .. 0x3F (0x38 is not supported) + * + * Start address and count can be overriden in user_config_override.h to allow better + * sharing of the I2C address space. Still the covered range must remains valid. + * A count of 0 can be used totaly disable any of the 2 ranges. + * By default, the following addresses are explicitly excluded (as per the docs) : + * - 0x27 and 0x37 are reserved for USE_DISPLAY_LCD in xdsp_01_lcd.ino + * - 0X38 is reserved for other sensors + * If the respective drivers are not used, overrides allows to recover those addresses + * If defined, USE_MCP230xx_ADDR is also always excluded + * + * Mode 1: + * See documentation. + * + * Mode 2: + * Allows easy configuration by using a sequential list of pins configured as Tasmota + * template and handle any input and output as configured GPIOs. + * + * Restrictions: + * - Uses incremental I2C addresses until template pin count reached + * - Max support for 28 switches (input), 32 buttons (input), 32 relays (output) + * + * Supported template fields: + * NAME - Template name + * BASE - Optional. 0 = use relative buttons and switches (default), 1 = use absolute buttons and switches + * GPIO - Sequential list of pin 1 and up with configured GPIO function + * Function Code Description + * ------------------- -------- ---------------------------------------- + * None 0 Not used + * Button1..32 B 32..63 Button to Gnd with internal pullup + * Button_n1..32 Bn 64..95 Button to Gnd without internal pullup + * Button_i1..32 Bi 96..127 Button inverted to Vcc with internal pullup + * Button_in1..32 Bin 128..159 Button inverted to Vcc without internal pullup + * Switch1..28 S 160..187 Switch to Gnd with internal pullup + * Switch_n1..28 Sn 192..219 Switch to Gnd without internal pullup + * Relay1..32 R 224..255 Relay + * Relay_i1..32 Ri 256..287 Relay inverted + * Output_Hi Oh 3840 Fixed output high + * Output_lo Ol 3872 Fixed output low + * + * Prepare a template to be loaded either by: + * - a rule like: rule3 on file#pcf8574.dat do {"NAME":"PCF8574 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} endon + * - a script like: -y{"NAME":"PCF8574 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} + * - file called pcf8574.dat with contents: {"NAME":"PCF8574 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} + * + * Inverted relays and buttons Ri8 Ri7 Ri6 Ri5 Ri4 Ri3 Ri2 Ri1 B1 B2 B3 B4 B5 B6 B7 B8 + * {"NAME":"PCF8574 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} + * B1 B2 B3 B4 Ri4 Ri3 Ri2 Ri1 B5 B6 B7 B8 Ri8 Ri7 Ri6 Ri5 + * {"NAME":"PCF8574 A=B1-4,Ri4-1, B=B5-8,Ri8-5","GPIO":[32,33,34,35,259,258,257,256,36,37,38,39,263,262,261,260]} +\*********************************************************************************************/ + +#define XDRV_28 28 +#define XI2C_02 2 // See I2CDEVICES.md + +// PCF8574 address range from 0x20 to 0x26 +#ifndef PCF8574_ADDR1 +#define PCF8574_ADDR1 0x20 // PCF8574 +#endif +#ifndef PCF8574_ADDR1_COUNT +#define PCF8574_ADDR1_COUNT 7 +#endif +// PCF8574A address range from 0x39 to 0x3E +#ifndef PCF8574_ADDR2 +#define PCF8574_ADDR2 0x39 // PCF8574A +#endif +#ifndef PCF8574_ADDR2_COUNT +#define PCF8574_ADDR2_COUNT 6 +#endif + +//#define USE_PCF8574_MODE2 // Enable Mode2 virtual relays/buttons/switches (+2k3 code) +//#define USE_PCF8574_SENSOR // Enable Mode1 inputs and outputs in SENSOR message (+0k2 code) +//#define USE_PCF8574_DISPLAYINPUT // Enable Mode1 inputs display in Web page (+0k2 code) +//#define USE_PCF8574_MQTTINPUT // Enable Mode1 MQTT message & rule process on input change detection : stat/%topic%/PCF8574_INP = {"Time":"2021-03-07T16:19:23+01:00","PCF8574-1_INP":{"D1":1}} (+0k5 code) + +/*********************************************************************************************\ + * PCF8574 support +\*********************************************************************************************/ + +// Consistency tests - Checked across the complete range for the PCF8574/PCF8574A to allow override +#if (PCF8574_ADDR1 < 0x20) || ((PCF8574_ADDR1 + PCF8574_ADDR1_COUNT - 1) > 0x27) +#error PCF8574_ADDR1 and/or PCF8574_ADDR1_COUNT badly overriden. Fix your user_config_override +#endif +#if (PCF8574_ADDR2 < 0x38) || ((PCF8574_ADDR2 + PCF8574_ADDR2_COUNT - 1) > 0x3F) +#error PCF8574_ADDR2 and/or PCF8574_ADDR2_COUNT badly overriden. Fix your user_config_override. +#endif + +struct PCF8574 { + uint32_t relay_inverted; + uint32_t button_inverted; + uint8_t address[MAX_PCF8574]; + uint8_t pin_mask[MAX_PCF8574] = { 0 }; +#ifdef USE_PCF8574_MQTTINPUT + uint8_t last_input[MAX_PCF8574] = { 0 }; +#endif + uint8_t max_connected_ports = 0; // Max numbers of devices comming from PCF8574 modules + uint8_t max_devices = 0; // Max numbers of PCF8574 modules + uint8_t mode; + uint8_t relay_max; + uint8_t relay_offset; + uint8_t button_max; + uint8_t switch_max; + int8_t button_offset; + int8_t switch_offset; + bool base; + bool interrupt; +} Pcf8574; + +uint16_t *Pcf8574_pin = nullptr; + +/*********************************************************************************************\ + * PCF8574 - I2C +\*********************************************************************************************/ + +uint8_t Pcf8574Read(uint8_t idx) { + Wire.requestFrom(Pcf8574.address[idx], (uint8_t)1); + return Wire.read(); +} + +void Pcf8574Write(uint8_t idx) { + Wire.beginTransmission(Pcf8574.address[idx]); + Wire.write(Pcf8574.pin_mask[idx]); + Wire.endTransmission(); +} + +#ifdef USE_PCF8574_MODE2 + +bool Pcf8574DigitalRead(uint8_t pin) { + // pin 0 - 63 + uint32_t chip = pin / 8; + uint32_t bit = pin % 8; + uint32_t value = Pcf8574Read(chip); + return value & (1 << bit); +} + +void Pcf8574DigitalWrite(uint8_t pin, bool pin_value) { + // pin 0 - 63 + // INPUT or INPUT_PULLUP = Pcf8574DigitalWrite(pin, 1); + // OUTPUT = Pcf8574DigitalWrite(pin, 0); or Pcf8574DigitalWrite(pin, 1); + uint32_t chip = pin / 8; + uint32_t bit = pin % 8; + uint32_t value = Pcf8574Read(chip); + value |= Pcf8574.pin_mask[chip]; // Restore inputs + if (pin_value) { + value |= 1 << bit; + } else { + value &= ~(1 << bit); + } + Wire.beginTransmission(Pcf8574.address[chip]); + Wire.write(value); + Wire.endTransmission(); +} + +void Pcf8574DigitalWriteConfig(uint8_t pin, bool pin_value) { + if (pin_value) { + bitSet(Pcf8574.pin_mask[pin / 8], pin % 8); // Save inputs + } + Pcf8574DigitalWrite(pin, pin_value); +} + +/*********************************************************************************************\ + * PCF8574 Mode 2 - Theo Arends +\*********************************************************************************************/ + +int Pcf8574Pin(uint32_t gpio, uint32_t index = 0); +int Pcf8574Pin(uint32_t gpio, uint32_t index) { + uint16_t real_gpio = gpio << 5; + uint16_t mask = 0xFFE0; + if (index < GPIO_ANY) { + real_gpio += index; + mask = 0xFFFF; + } + for (uint32_t i = 0; i < Pcf8574.max_connected_ports; i++) { + if ((Pcf8574_pin[i] & mask) == real_gpio) { + return i; // Pin number configured for gpio + } + } + return -1; // No pin used for gpio +} + +bool Pcf8574PinUsed(uint32_t gpio, uint32_t index = 0); +bool Pcf8574PinUsed(uint32_t gpio, uint32_t index) { + return (Pcf8574Pin(gpio, index) >= 0); +} + +uint32_t Pcf8574GetPin(uint32_t lpin) { + if (lpin < Pcf8574.max_connected_ports) { + return Pcf8574_pin[lpin]; + } else { + return GPIO_NONE; + } +} + +/*********************************************************************************************/ + +String Pcf8574TemplateLoadFile(void) { + String pcftmplt = ""; +#ifdef USE_UFILESYS + pcftmplt = TfsLoadString("/pcf8574.dat"); +#endif // USE_UFILESYS +#ifdef USE_RULES + if (!pcftmplt.length()) { + pcftmplt = RuleLoadFile("PCF8574.DAT"); + } +#endif // USE_RULES +#ifdef USE_SCRIPT + if (!pcftmplt.length()) { + pcftmplt = ScriptLoadSection(">y"); + } +#endif // USE_SCRIPT + return pcftmplt; +} + +bool Pcf8574LoadTemplate(void) { + String pcftmplt = Pcf8574TemplateLoadFile(); + uint32_t len = pcftmplt.length() +1; + if (len < 7) { return false; } // No PcfTmplt found + + JsonParser parser((char*)pcftmplt.c_str()); + JsonParserObject root = parser.getRootObject(); + if (!root) { return false; } + + // rule3 on file#pcf8574.dat do {"NAME":"PCF8574 A=B12345678,B=Ri87654321","GPIO":[32,33,34,35,36,37,38,39,263,262,261,260,259,258,257,256]} endon + // rule3 on file#pcf8574.dat do {"NAME":"PCF8574 A=B1234,Ri4321,B=B5678,Ri8765","GPIO":[32,33,34,35,259,258,257,256,36,37,38,39,263,262,261,260]} endon + // rule3 on file#pcf8574.dat do {"NAME":"PCF8574 A=B3456,Ri6543,B=B78910,Ri10987","BASE":1,"GPIO":[34,35,36,37,261,260,259,258,38,39,40,41,265,264,263,262]} endon + JsonParserToken val = root[PSTR(D_JSON_BASE)]; + if (val) { + Pcf8574.base = (val.getUInt()) ? true : false; + } + val = root[PSTR(D_JSON_NAME)]; + if (val) { + AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Base %d, Template '%s'"), Pcf8574.base, val.getStr()); + } + JsonParserArray arr = root[PSTR(D_JSON_GPIO)]; + if (arr) { + uint32_t pin = 0; + for (pin; pin < Pcf8574.max_connected_ports; pin++) { // Max number of detected chip pins +// if (0 == (pin % 8)) { Pcf8574.pin_mask[pin / 8] = 0; } // Reset config for next 8-pins + JsonParserToken val = arr[pin]; + if (!val) { break; } + uint16_t mpin = val.getUInt(); + if (mpin) { // Above GPIO_NONE + if ((mpin >= AGPIO(GPIO_SWT1)) && (mpin < (AGPIO(GPIO_SWT1) + MAX_SWITCHES_SET))) { + Pcf8574.switch_max++; + Pcf8574DigitalWriteConfig(pin, 1); // INPUT_PULLUP + } + else if ((mpin >= AGPIO(GPIO_SWT1_NP)) && (mpin < (AGPIO(GPIO_SWT1_NP) + MAX_SWITCHES_SET))) { + mpin -= (AGPIO(GPIO_SWT1_NP) - AGPIO(GPIO_SWT1)); + Pcf8574.switch_max++; + Pcf8574DigitalWriteConfig(pin, 1); // INPUT + } + else if ((mpin >= AGPIO(GPIO_KEY1)) && (mpin < (AGPIO(GPIO_KEY1) + MAX_KEYS_SET))) { + Pcf8574.button_max++; + Pcf8574DigitalWriteConfig(pin, 1); // INPUT_PULLUP + } + else if ((mpin >= AGPIO(GPIO_KEY1_NP)) && (mpin < (AGPIO(GPIO_KEY1_NP) + MAX_KEYS_SET))) { + mpin -= (AGPIO(GPIO_KEY1_NP) - AGPIO(GPIO_KEY1)); + Pcf8574.button_max++; + Pcf8574DigitalWriteConfig(pin, 1); // INPUT + } + else if ((mpin >= AGPIO(GPIO_KEY1_INV)) && (mpin < (AGPIO(GPIO_KEY1_INV) + MAX_KEYS_SET))) { + bitSet(Pcf8574.button_inverted, mpin - AGPIO(GPIO_KEY1_INV)); + mpin -= (AGPIO(GPIO_KEY1_INV) - AGPIO(GPIO_KEY1)); + Pcf8574.button_max++; + Pcf8574DigitalWriteConfig(pin, 1); // INPUT_PULLUP + } + else if ((mpin >= AGPIO(GPIO_KEY1_INV_NP)) && (mpin < (AGPIO(GPIO_KEY1_INV_NP) + MAX_KEYS_SET))) { + bitSet(Pcf8574.button_inverted, mpin - AGPIO(GPIO_KEY1_INV_NP)); + mpin -= (AGPIO(GPIO_KEY1_INV_NP) - AGPIO(GPIO_KEY1)); + Pcf8574.button_max++; + Pcf8574DigitalWriteConfig(pin, 1); // INPUT + } + else if ((mpin >= AGPIO(GPIO_REL1)) && (mpin < (AGPIO(GPIO_REL1) + MAX_RELAYS_SET))) { + Pcf8574.relay_max++; +// Pcf8574DigitalWriteConfig(pin, 1); // OUTPUT - Leave unchanged to fix restart and power on spikes (default is 1) + } + else if ((mpin >= AGPIO(GPIO_REL1_INV)) && (mpin < (AGPIO(GPIO_REL1_INV) + MAX_RELAYS_SET))) { + bitSet(Pcf8574.relay_inverted, mpin - AGPIO(GPIO_REL1_INV)); + mpin -= (AGPIO(GPIO_REL1_INV) - AGPIO(GPIO_REL1)); + Pcf8574.relay_max++; +// Pcf8574DigitalWriteConfig(pin, 1); // OUTPUT - Leave unchanged to fix restart and power on spikes (default is 1) + } + else if (mpin == AGPIO(GPIO_OUTPUT_HI)) { + Pcf8574DigitalWriteConfig(pin, 1); // OUTPUT + } + else if (mpin == AGPIO(GPIO_OUTPUT_LO)) { + Pcf8574DigitalWriteConfig(pin, 0); // OUTPUT + } + else { mpin = 0; } + Pcf8574_pin[pin] = mpin; + } + if ((Pcf8574.switch_max >= MAX_SWITCHES_SET) || + (Pcf8574.button_max >= MAX_KEYS_SET) || + (Pcf8574.relay_max >= MAX_RELAYS_SET)) { + AddLog(LOG_LEVEL_INFO, PSTR("PCF: Max reached (S%d/B%d/R%d)"), Pcf8574.switch_max, Pcf8574.button_max, Pcf8574.relay_max); + break; + } + } + Pcf8574.max_connected_ports = pin; // Max number of configured pins + } + return true; +} + +void Pcf8574ServiceInput(void) { + Pcf8574.interrupt = false; + // This works with no interrupt too + uint32_t pin_offset = 0; + for (uint32_t chip = 0; chip < Pcf8574.max_devices; chip++) { + uint32_t gpio = Pcf8574Read(chip); // Reset interrupt + uint32_t mask = 1; + for (uint32_t pin = 0; pin < 8; pin++) { + uint32_t state = ((gpio & mask) != 0); + uint32_t lpin = Pcf8574GetPin(pin_offset + pin); // 0 for None, 32 for KEY1, 160 for SWT1, 224 for REL1 + uint32_t index = lpin & 0x001F; // Max 32 buttons or switches + lpin = BGPIO(lpin); // UserSelectablePins number + if (GPIO_KEY1 == lpin) { + ButtonSetVirtualPinState(Pcf8574.button_offset + index, (state != bitRead(Pcf8574.button_inverted, index))); +// Pcf8574DigitalWrite(pin_offset + pin, 1); // INPUT and reset interrupt + } + else if (GPIO_SWT1 == lpin) { + SwitchSetVirtualPinState(Pcf8574.switch_offset + index, state); +// Pcf8574DigitalWrite(pin_offset + pin, 1); // INPUT and reset interrupt + } + mask <<= 1; + } + pin_offset += 8; + } +} + +static void IRAM_ATTR Pcf8574InputIsr(void) { + Pcf8574.interrupt = true; +} + +void Pcf8574Init(void) { + if (Pcf8574.button_max || Pcf8574.switch_max) { + if (PinUsed(GPIO_PCF8574_INT)) { + pinMode(Pin(GPIO_PCF8574_INT), INPUT_PULLUP); + attachInterrupt(Pin(GPIO_PCF8574_INT), Pcf8574InputIsr, CHANGE); + } + } +} + +void Pcf8574Power(void) { + // XdrvMailbox.index = 32-bit rpower bit mask + // Use absolute relay indexes unique with main template + power_t rpower = XdrvMailbox.index; + uint32_t relay_max = TasmotaGlobal.devices_present; + if (!Pcf8574.base) { + // Use relative and sequential relay indexes + rpower >>= Pcf8574.relay_offset; + relay_max = Pcf8574.relay_max; + } + for (uint32_t index = 0; index < relay_max; index++) { + power_t state = rpower &1; + if (Pcf8574PinUsed(GPIO_REL1, index)) { + uint32_t pin = Pcf8574Pin(GPIO_REL1, index) & 0x3F; // Fix possible overflow over 63 gpios + Pcf8574DigitalWrite(pin, bitRead(Pcf8574.relay_inverted, index) ? !state : state); + } + rpower >>= 1; // Select next power + } +} + +bool Pcf8574AddButton(void) { + // XdrvMailbox.index = button/switch index + uint32_t index = XdrvMailbox.index; + if (!Pcf8574.base) { + // Use relative and sequential button indexes + if (Pcf8574.button_offset < 0) { Pcf8574.button_offset = index; } + index -= Pcf8574.button_offset; + if (index >= Pcf8574.button_max) { return false; } + } else { + // Use absolute button indexes unique with main template + if (!Pcf8574PinUsed(GPIO_KEY1, index)) { return false; } + Pcf8574.button_offset = 0; + } + XdrvMailbox.index = (Pcf8574DigitalRead(Pcf8574Pin(GPIO_KEY1, index)) != bitRead(Pcf8574.button_inverted, index)); + return true; +} + +bool Pcf8574AddSwitch(void) { + // XdrvMailbox.index = button/switch index + uint32_t index = XdrvMailbox.index; + if (!Pcf8574.base) { + // Use relative and sequential switch indexes + if (Pcf8574.switch_offset < 0) { Pcf8574.switch_offset = index; } + index -= Pcf8574.switch_offset; + if (index >= Pcf8574.switch_max) { return false; } + } else { + // Use absolute switch indexes unique with main template + if (!Pcf8574PinUsed(GPIO_SWT1, index)) { return false; } + Pcf8574.switch_offset = 0; + } + XdrvMailbox.index = Pcf8574DigitalRead(Pcf8574Pin(GPIO_SWT1, index)); + return true; +} + +#endif // USE_PCF8574_MODE2 + +/*********************************************************************************************\ + * PCF8574 Mode 1 - Stefan Bode +\*********************************************************************************************/ + +void Pcf8574SwitchRelay(void) { + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + uint8_t relay_state = bitRead(XdrvMailbox.index, i); + + if (Pcf8574.max_devices > 0 && Pcf8574_pin[i] < 99) { + uint8_t board = Pcf8574_pin[i]>>3; + uint8_t pin = Pcf8574_pin[i]&0x7; + uint8_t oldpinmask = Pcf8574.pin_mask[board]; + uint8_t _val = bitRead(TasmotaGlobal.rel_inverted, i) ? !relay_state : relay_state; + + //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: SwitchRelay %d=%d => PCF-%d.D%d=%d"), i, relay_state, board +1, pin, _val); + bitWrite(Pcf8574.pin_mask[board], pin, _val); + if (oldpinmask != Pcf8574.pin_mask[board]) { + Pcf8574Write(board); + } + //else AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: SwitchRelay skipped")); + } + } +} + +#ifdef USE_PCF8574_MQTTINPUT +void Pcf8574CheckForInputChange(void) { + for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { + uint8_t input_mask = ~Settings->pcf8574_config[idx]; // Invert to 1 = input + uint8_t input = Pcf8574Read(idx) & input_mask; + uint8_t last_input = Pcf8574.last_input[idx]; + if (input != last_input) { // Don't scan bits if no change (EVERY_50_MS !) + for (uint32_t pin = 0 ; pin < 8 ; ++pin) { + if (bitRead(input_mask,pin) && bitRead(input,pin) != bitRead(last_input,pin)) { + ResponseTime_P(PSTR(",\"PCF8574%c%d_INP\":{\"D%i\":%i}}"), IndexSeparator(), idx +1, pin, bitRead(input,pin)); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR("PCF8574_INP")); + if (Settings->flag3.hass_tele_on_power) { // SetOption59 - Send tele/%topic%/SENSOR in addition to stat/%topic%/RESULT + MqttPublishSensor(); + } + } + Pcf8574.last_input[idx] = input; + } + } + } +} +#endif // USE_PCF8574_MQTTINPUT + + +void Pcf8574ModuleInitMode1(void) { + for (uint32_t i = 0; i < Pcf8574.max_connected_ports; i++) { + Pcf8574_pin[i] = 99; + } + Pcf8574.max_connected_ports = 0; // Reset no of devices + + for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { // suport up to 8 boards PCF8574 + uint8_t gpio = Pcf8574Read(idx); + // Insure the input pins are actually writen a 1 for proper input operation + Pcf8574.pin_mask[idx] = gpio | ~Settings->pcf8574_config[idx]; + Pcf8574Write(idx); // Write back to the register +#ifdef USE_PCF8574_MQTTINPUT + Pcf8574.last_input[idx] = gpio & ~Settings->pcf8574_config[idx]; +#endif // USE_PCF8574_MQTTINPUT + //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: PCF-%d config=0x%02x, gpio=0x%02X"), idx +1, Settings->pcf8574_config[idx], gpio); + + for (uint32_t i = 0; i < 8; i++, gpio>>=1) { + uint8_t _result = Settings->pcf8574_config[idx] >> i &1; + //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: I2C shift i %d: %d. Powerstate: %d, TasmotaGlobal.devices_present: %d"), i,_result, Settings->power>>i&1, TasmotaGlobal.devices_present); + if (_result > 0) { + Pcf8574_pin[TasmotaGlobal.devices_present] = i + 8 * idx; + bitWrite(TasmotaGlobal.rel_inverted, TasmotaGlobal.devices_present, Settings->flag3.pcf8574_ports_inverted); // SetOption81 - Invert all ports on PCF8574 devices + if (!Settings->flag.save_state && !Settings->flag3.no_power_feedback) { // SetOption63 - Don't scan relay power state at restart - #5594 and #5663 + //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Set power from from chip state")); + uint8_t power_state = Settings->flag3.pcf8574_ports_inverted ? 1 & ~gpio : 1 & gpio; + bitWrite(TasmotaGlobal.power, TasmotaGlobal.devices_present, power_state); + bitWrite(Settings->power, TasmotaGlobal.devices_present, power_state); + } + //else AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: DON'T set power from chip state")); + UpdateDevicesPresent(1); + Pcf8574.max_connected_ports++; + } + } + } + //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Settings->power=0x%08X, TasmotaGlobal.power=0x%08X"), Settings->power, TasmotaGlobal.power); + AddLog(LOG_LEVEL_INFO, PSTR("PCF: Total devices %d, PCF8574 output ports %d"), Pcf8574.max_devices, Pcf8574.max_connected_ports); +} + +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +#ifdef USE_WEBSERVER +#define WEB_HANDLE_PCF8574 "pcf" + +const char HTTP_BTN_MENU_PCF8574[] PROGMEM = + "

"; + +const char HTTP_FORM_I2C_PCF8574_1[] PROGMEM = + "
 " D_PCF8574_PARAMETERS " " + "
" + "


"; + +const char HTTP_FORM_I2C_PCF8574_2[] PROGMEM = + "" D_DEVICE " %d " D_PORT " %d"; + +const char HTTP_SNS_PCF8574_GPIO[] PROGMEM = "{s}PCF8574%c%d D%d{m}%d{e}"; // {s} = , {m} = , {e} = + +void HandlePcf8574(void) { + if (!HttpCheckPriviledgedAccess()) { return; } + + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP D_CONFIGURE_PCF8574)); + + if (Webserver->hasArg("save")) { + Pcf8574SaveSettings(); + WebRestart(1); + return; + } + + WSContentStart_P(D_CONFIGURE_PCF8574); + WSContentSendStyle(); + WSContentSend_P(HTTP_FORM_I2C_PCF8574_1, (Settings->flag3.pcf8574_ports_inverted) ? PSTR(" checked") : ""); // SetOption81 - Invert all ports on PCF8574 devices + WSContentSend_P(HTTP_TABLE100); + for (uint32_t idx = 0; idx < Pcf8574.max_devices; idx++) { + for (uint32_t idx2 = 0; idx2 < 8; idx2++) { // 8 ports on PCF8574 + uint8_t helper = 1 << idx2; + WSContentSend_P(HTTP_FORM_I2C_PCF8574_2, + idx +1, idx2, + idx2 + 8*idx, + idx2 + 8*idx, + ((helper & Settings->pcf8574_config[idx]) >> idx2 == 0) ? PSTR(" selected ") : " ", + ((helper & Settings->pcf8574_config[idx]) >> idx2 == 1) ? PSTR(" selected ") : " " + ); + } + } + WSContentSend_P(PSTR("")); + WSContentSend_P(HTTP_FORM_END); + WSContentSpaceButton(BUTTON_CONFIGURATION); + WSContentStop(); +} + +void Pcf8574SaveSettings(void) { + char stemp[7]; + char tmp[100]; + + //AddLog(LOG_LEVEL_DEBUG, PSTR("PCF: Start working on Save arguements: inverted:%d")), Webserver->hasArg("b1"); + + Settings->flag3.pcf8574_ports_inverted = Webserver->hasArg("b1"); // SetOption81 - Invert all ports on PCF8574 devices + for (byte idx = 0; idx < Pcf8574.max_devices; idx++) { + byte count=0; + byte n = Settings->pcf8574_config[idx]; + while(n!=0) { + n = n&(n-1); + count++; + } + if (count <= TasmotaGlobal.devices_present) { + UpdateDevicesPresent(-count); + } + for (byte i = 0; i < 8; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("i2cs%d"), i+8*idx); + WebGetArg(stemp, tmp, sizeof(tmp)); + byte _value = (!strlen(tmp)) ? 0 : atoi(tmp); + if (_value) { + Settings->pcf8574_config[idx] = Settings->pcf8574_config[idx] | 1 << i; + UpdateDevicesPresent(1); + Pcf8574.max_connected_ports++; + } else { + Settings->pcf8574_config[idx] = Settings->pcf8574_config[idx] & ~(1 << i ); + } + } + //Settings->pcf8574_config[0] = (!strlen(webServer->arg("i2cs0").c_str())) ? 0 : atoi(webServer->arg("i2cs0").c_str()); + //AddLog(LOG_LEVEL_INFO, PSTR("PCF: I2C Board: %d, Config: %2x")), idx, Settings->pcf8574_config[idx]; + } +} + +#ifdef USE_PCF8574_DISPLAYINPUT +void Pcf8574ShowWeb(void) { + for (uint32_t idx = 0 ; idx < Pcf8574.max_devices ; idx++) { + uint8_t input_mask = ~Settings->pcf8574_config[idx]; // Invert to 1 = input + uint8_t gpio = Pcf8574Read(idx); + for (uint32_t pin = 0 ; pin < 8 ; ++pin, input_mask >>= 1, gpio >>= 1) { + if (input_mask & 1) { + WSContentSend_P(HTTP_SNS_PCF8574_GPIO, IndexSeparator(), idx +1, pin, gpio & 1); + } + } + } +} +#endif // USE_PCF8574_DISPLAYINPUT +#endif // USE_WEBSERVER + +#ifdef USE_PCF8574_SENSOR +void Pcf8574ShowJson(void) { + for (uint32_t idx = 0 ; idx < Pcf8574.max_devices ; idx++) { + uint8_t gpio = Pcf8574Read(idx); + ResponseAppend_P(PSTR(",\"PCF8574%c%d\":{"), IndexSeparator(), idx +1); + for (uint32_t pin = 0; pin < 8; ++pin, gpio >>= 1) { + ResponseAppend_P(PSTR("%s\"D%d\":%i"), (0==pin)?"":",", pin, gpio & 1); + } + ResponseJsonEnd(); + } +} +#endif // #ifdef USE_PCF8574_SENSOR + +/*********************************************************************************************\ + * PCF8574 Module Init +\*********************************************************************************************/ + +void Pcf8574ModuleInit(void) { + uint8_t pcf8574_address = (PCF8574_ADDR1_COUNT > 0) ? PCF8574_ADDR1 : PCF8574_ADDR2; + while ((Pcf8574.max_devices < MAX_PCF8574) && (pcf8574_address < PCF8574_ADDR2 +PCF8574_ADDR2_COUNT)) { + +#if defined(USE_MCP230xx) && defined(USE_MCP230xx_ADDR) + if (USE_MCP230xx_ADDR == pcf8574_address) { + AddLog(LOG_LEVEL_INFO, PSTR("PCF: Address 0x%02x reserved for MCP230xx"), pcf8574_address); + } else { +#endif + + if (I2cSetDevice(pcf8574_address)) { + Pcf8574.mode = 1; + + Pcf8574.max_connected_ports += 8; + Pcf8574.address[Pcf8574.max_devices] = pcf8574_address; + Pcf8574.max_devices++; + + char stype[12]; + sprintf_P(stype, PSTR("PCF8574%s"), (pcf8574_address >= PCF8574_ADDR2) ? "A" : ""); + I2cSetActiveFound(pcf8574_address, stype); + } + +#if defined(USE_MCP230xx) && defined(USE_MCP230xx_ADDR) + } +#endif + + pcf8574_address++; + if ((PCF8574_ADDR1 +PCF8574_ADDR1_COUNT) == pcf8574_address) { // Support I2C addresses 0x20 to 0x26 and 0x39 to 0x3F + pcf8574_address = PCF8574_ADDR2; + } + } + + if (Pcf8574.mode) { + Pcf8574_pin = (uint16_t*)malloc(Pcf8574.max_connected_ports * sizeof(uint16_t)); + if (Pcf8574_pin) { +#ifdef USE_PCF8574_MODE2 + if (Pcf8574LoadTemplate()) { + Pcf8574.mode = 2; + Pcf8574.button_offset = -1; + Pcf8574.switch_offset = -1; + Pcf8574.relay_offset = TasmotaGlobal.devices_present; + Pcf8574.relay_max -= UpdateDevicesPresent(Pcf8574.relay_max); + } else +#endif // USE_PCF8574_MODE2 + Pcf8574ModuleInitMode1(); + } else { + Pcf8574.mode = 0; + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv28(uint32_t function) { + if (!I2cEnabled(XI2C_02)) { return false; } + + bool result = false; + + if (FUNC_SETUP_RING2 == function) { + Pcf8574ModuleInit(); + } else if (1 == Pcf8574.mode) { + switch (function) { +#ifdef USE_PCF8574_MQTTINPUT + case FUNC_EVERY_50_MSECOND: + Pcf8574CheckForInputChange(); + break; +#endif // USE_PCF8574_MQTTINPUT + case FUNC_SET_POWER: + Pcf8574SwitchRelay(); + break; +#ifdef USE_PCF8574_SENSOR + case FUNC_JSON_APPEND: + Pcf8574ShowJson(); + break; +#endif // USE_PCF8574_SENSOR +#ifdef USE_WEBSERVER + case FUNC_WEB_ADD_BUTTON: + WSContentSend_P(HTTP_BTN_MENU_PCF8574); + break; + case FUNC_WEB_ADD_HANDLER: + WebServer_on(PSTR("/" WEB_HANDLE_PCF8574), HandlePcf8574); + break; +#ifdef USE_PCF8574_DISPLAYINPUT + case FUNC_WEB_SENSOR: + Pcf8574ShowWeb(); + break; +#endif // USE_PCF8574_DISPLAYINPUT +#endif // USE_WEBSERVER + } +#ifdef USE_PCF8574_MODE2 + } else if (2 == Pcf8574.mode) { + switch (function) { + case FUNC_LOOP: + case FUNC_SLEEP_LOOP: + if (!Pcf8574.interrupt) { return false; } +// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("PCF: Interrupt")); + Pcf8574ServiceInput(); + break; + case FUNC_EVERY_100_MSECOND: + if (Pcf8574.button_max || Pcf8574.switch_max) { + Pcf8574ServiceInput(); + } + break; + case FUNC_SET_POWER: + Pcf8574Power(); + break; + case FUNC_INIT: + Pcf8574Init(); + break; + case FUNC_ADD_BUTTON: + result = Pcf8574AddButton(); + break; + case FUNC_ADD_SWITCH: + result = Pcf8574AddSwitch(); + break; + } +#endif // USE_PCF8574_MODE2 + } + return result; +} + +#endif // USE_PCF8574 +#endif // USE_I2C diff --git a/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino index 597f3b9e6..7579072b3 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino @@ -354,7 +354,7 @@ bool ExsModuleSelected(void) Settings->flag3.pwm_multi_channels = 1; // SetOption68 - Enable multi-channels PWM instead of Color PWM SetSeriallog(LOG_LEVEL_NONE); - TasmotaGlobal.devices_present = +2; + UpdateDevicesPresent(2); TasmotaGlobal.light_type = LT_SERIAL2; return true; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino index 5ce566548..76e9e7bca 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino @@ -137,7 +137,7 @@ void PWMModulePreInit(void) first_device_group_is_local = false; // Back out the changes made in the light module under the assumtion we have a relay or PWM. - TasmotaGlobal.devices_present--; + UpdateDevicesPresent(-1); TasmotaGlobal.light_type = 0; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino b/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino index fde6dc1c9..a727b6080 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino @@ -163,7 +163,7 @@ bool SonoffD1ModuleSelected(void) { SetSerial(9600, TS_SERIAL_8N1); - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); TasmotaGlobal.light_type = LT_SERIAL1; return true; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino index d301aa0d7..95041ca47 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino @@ -1367,7 +1367,10 @@ void ThermostatGetLocalSensor(uint8_t ctr_output) { if ( (THERMOSTAT_SENSOR_NUMBER > 1) &&(THERMOSTAT_CONTROLLER_OUTPUTS > 1) &&(ctr_output < THERMOSTAT_SENSOR_NUMBER)) { - sensor_name.concat("_" + (ctr_output + 1)); + char temp[4]; + temp[0] = IndexSeparator(); + snprintf(&temp[1], 4, "%u", (ctr_output + 1)); + sensor_name.concat(temp); } JsonParserToken value_token = root[sensor_name].getObject()[PSTR("Temperature")]; if (value_token.isNum()) { @@ -2013,16 +2016,23 @@ void CmndEnableOutputSet(void) // To be done, add all of this defines in according languages file when all will be finished -// Avoid multiple changes on all language files during developement +// Avoid multiple changes on all language files during development // -------------------------------------------------- // xdrv_39_thermostat.ino -#define D_THERMOSTAT "Thermostat" -#define D_THERMOSTAT_SET_POINT "Set Point" -#define D_THERMOSTAT_SENSOR "Current" -#define D_THERMOSTAT_GRADIENT "Gradient" -#define D_THERMOSTAT_DUTY_CYCLE "Duty cycle" -#define D_THERMOSTAT_CYCLE_TIME "Cycle time" -#define D_THERMOSTAT_PI_AUTOTUNE "PI Auto tuning" +#define D_THERMOSTAT "Thermostat" +#define D_THERMOSTAT_SET_POINT "Set Point" +#define D_THERMOSTAT_SENSOR "Current" +#define D_THERMOSTAT_GRADIENT "Gradient" +#define D_THERMOSTAT_DUTY_CYCLE "Duty cycle" +#define D_THERMOSTAT_CYCLE_TIME "Cycle time" +#define D_THERMOSTAT_PI_AUTOTUNE "PI Auto tuning" +#define D_THERMOSTAT_CONTROL_METHOD "Control method" +#define D_THERMOSTAT_RAMP_UP "Ramp up" +#define D_THERMOSTAT_PI "PI" +#define D_THERMOSTAT_AUTOTUNE "Autotune" +#define D_THERMOSTAT_RAMP_UP_HYBRID "Ramp up (Hybrid)" +#define D_THERMOSTAT_PI_HYBRID "PI (Hybrid)" +#define D_THERMOSTAT_AUTOTUNE_HYBRID "Autotune (Hybrid)" // -------------------------------------------------- @@ -2031,11 +2041,15 @@ const char HTTP_THERMOSTAT_INFO[] PROGMEM = "{s}" D_THERMOSTAT "{m}%s{e}" const char HTTP_THERMOSTAT_TEMPERATURE[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}"; const char HTTP_THERMOSTAT_DUTY_CYCLE[] PROGMEM = "{s}" D_THERMOSTAT_DUTY_CYCLE "{m}%d " D_UNIT_PERCENT "{e}"; const char HTTP_THERMOSTAT_CYCLE_TIME[] PROGMEM = "{s}" D_THERMOSTAT_CYCLE_TIME "{m}%d " D_UNIT_MINUTE "{e}"; +const char HTTP_THERMOSTAT_CONTROL_METHOD[] PROGMEM = "{s}" D_THERMOSTAT_CONTROL_METHOD "{m}%s{e}"; const char HTTP_THERMOSTAT_PI_AUTOTUNE[] PROGMEM = "{s}" D_THERMOSTAT_PI_AUTOTUNE "{m}%s{e}"; const char HTTP_THERMOSTAT_HL[] PROGMEM = "{s}
{m}
{e}"; #endif // USE_WEBSERVER +#define D_THERMOSTAT_JSON_NAME_CONTROL_METHOD "ControlMethod" +#define D_THERMOSTAT_JSON_NAME_EMERGENCY_STATE "EmergencyState" + void ThermostatShow(uint8_t ctr_output, bool json) { if (json) { @@ -2044,6 +2058,8 @@ void ThermostatShow(uint8_t ctr_output, bool json) ResponseAppend_P(PSTR("%s\"%s\":%i"), "", D_CMND_THERMOSTATMODESET, Thermostat[ctr_output].status.thermostat_mode); ResponseAppend_P(PSTR("%s\"%s\":%2_f"), ",", D_CMND_TEMPTARGETSET, &f_target_temp); ResponseAppend_P(PSTR("%s\"%s\":%i"), ",", D_CMND_CTRDUTYCYCLEREAD, ThermostatGetDutyCycle(ctr_output)); + ResponseAppend_P(PSTR("%s\"%s\":%i"), ",", D_THERMOSTAT_JSON_NAME_CONTROL_METHOD, Thermostat[ctr_output].status.controller_mode == CTR_HYBRID ? Thermostat[ctr_output].status.phase_hybrid_ctr : Thermostat[ctr_output].status.controller_mode); + ResponseAppend_P(PSTR("%s\"%s\":%i"), ",", D_THERMOSTAT_JSON_NAME_EMERGENCY_STATE, Thermostat[ctr_output].diag.state_emergency == EMERGENCY_ON); ResponseJsonEnd(); return; } @@ -2056,11 +2072,11 @@ void ThermostatShow(uint8_t ctr_output, bool json) } else { char c_unit = Thermostat[ctr_output].status.temp_format==TEMP_CELSIUS ? D_UNIT_CELSIUS[0] : D_UNIT_FAHRENHEIT[0]; - float f_temperature ; + float f_temperature; - WSContentSend_P(HTTP_THERMOSTAT_INFO, D_ENABLED ); + WSContentSend_P(HTTP_THERMOSTAT_INFO, D_ENABLED); - f_temperature = Thermostat[ctr_output].temp_target_level / 10.0f ; + f_temperature = Thermostat[ctr_output].temp_target_level / 10.0f; WSContentSend_PD(HTTP_THERMOSTAT_TEMPERATURE, D_THERMOSTAT_SET_POINT, Settings->flag2.temperature_resolution, &f_temperature, c_unit); f_temperature = Thermostat[ctr_output].temp_measured / 10.0f; @@ -2072,17 +2088,46 @@ void ThermostatShow(uint8_t ctr_output, bool json) } f_temperature = value / 1000.0f; WSContentSend_PD(HTTP_THERMOSTAT_TEMPERATURE, D_THERMOSTAT_GRADIENT, Settings->flag2.temperature_resolution, &f_temperature, c_unit); - WSContentSend_P(HTTP_THERMOSTAT_DUTY_CYCLE, ThermostatGetDutyCycle(ctr_output) ); - WSContentSend_P(HTTP_THERMOSTAT_CYCLE_TIME, Thermostat[ctr_output].time_pi_cycle ); + + WSContentSend_P(HTTP_THERMOSTAT_DUTY_CYCLE, ThermostatGetDutyCycle(ctr_output)); + + switch (Thermostat[ctr_output].status.controller_mode) { + case CTR_HYBRID: + switch (Thermostat[ctr_output].status.phase_hybrid_ctr) { + case CTR_HYBRID_RAMP_UP: + WSContentSend_P(HTTP_THERMOSTAT_CONTROL_METHOD, D_THERMOSTAT_RAMP_UP_HYBRID); + break; + case CTR_HYBRID_PI: + WSContentSend_P(HTTP_THERMOSTAT_CONTROL_METHOD, D_THERMOSTAT_PI_HYBRID); + break; + #ifdef USE_PI_AUTOTUNING + case CTR_HYBRID_PI_AUTOTUNE: + WSContentSend_P(HTTP_THERMOSTAT_CONTROL_METHOD, D_THERMOSTAT_AUTOTUNE_HYBRID); + break; + #endif + } + break; + case CTR_PI: + WSContentSend_P(HTTP_THERMOSTAT_CONTROL_METHOD, D_THERMOSTAT_PI); + break; + case CTR_RAMP_UP: + WSContentSend_P(HTTP_THERMOSTAT_CONTROL_METHOD, D_THERMOSTAT_RAMP_UP); + break; + #ifdef USE_PI_AUTOTUNING + case CTR_PI_AUTOTUNE: + WSContentSend_P(HTTP_THERMOSTAT_CONTROL_METHOD, D_THERMOSTAT_AUTOTUNE); + break; + #endif + } + + WSContentSend_P(HTTP_THERMOSTAT_CYCLE_TIME, Thermostat[ctr_output].time_pi_cycle); #ifdef USE_PI_AUTOTUNING - WSContentSend_P(HTTP_THERMOSTAT_PI_AUTOTUNE, D_ENABLED ); + WSContentSend_P(HTTP_THERMOSTAT_PI_AUTOTUNE, D_ENABLED); #else - WSContentSend_P(HTTP_THERMOSTAT_PI_AUTOTUNE, D_DISABLED ); + WSContentSend_P(HTTP_THERMOSTAT_PI_AUTOTUNE, D_DISABLED); #endif - } - #endif // USE_WEBSERVER } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino index 65ab1ecdd..acdd3fa6a 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino @@ -1085,7 +1085,8 @@ miel_hvac_pre_init(void) SetSerial(baudrate, TS_SERIAL_8E1); } - sc->sc_device = TasmotaGlobal.devices_present++; /* claim a POWER device slot */ + UpdateDevicesPresent(1); /* claim a POWER device slot */ + sc->sc_device = TasmotaGlobal.devices_present; miel_hvac_sc = sc; return; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino index 0ed553765..42ba5df0b 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino @@ -725,7 +725,7 @@ bool ShdSerialInput(void) bool ShdModuleSelected(void) { if (PinUsed(GPIO_SHELLY_DIMMER_BOOT0) && PinUsed(GPIO_SHELLY_DIMMER_RST_INV)) { - TasmotaGlobal.devices_present++; + UpdateDevicesPresent(1); TasmotaGlobal.light_type = LT_SERIAL1; Shd.present = true; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino index 4b4e2d8a8..dce7fdee1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino @@ -609,7 +609,7 @@ const char UFS_FORM_FILE_UPGc[] PROGMEM = "
" D_FS_SIZE " %s MB - " D_FS_FREE " %s MB"; const char UFS_FORM_FILE_UPGc1[] PROGMEM = - "   %s"; + "   %s"; const char UFS_FORM_FILE_UPGc2[] PROGMEM = "
"; @@ -719,7 +719,7 @@ void UfsDirectory(void) { WSContentSend_PD(UFS_FORM_FILE_UPGc, WebColor(COL_TEXT), ts, fs); if (ufs_dir) { - WSContentSend_P(UFS_FORM_FILE_UPGc1, (uint32_t)WiFi.localIP(), (ufs_dir == 1)?2:1, (ufs_dir == 1)?PSTR("SDCard"):PSTR("FlashFS")); + WSContentSend_P(UFS_FORM_FILE_UPGc1, (ufs_dir == 1)?2:1, (ufs_dir == 1)?PSTR("SDCard"):PSTR("FlashFS")); } WSContentSend_P(UFS_FORM_FILE_UPGc2); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino index cc1f278a5..bec624546 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino @@ -232,7 +232,9 @@ extern "C" { int ret = br_ccm_reset(ccm_ctx, nonce, nonce_len, aad_len, data_len, tag_len); if (ret == 0) { be_raise(vm, "value_error", "br_ccm_reset failed"); } - br_ccm_aad_inject(ccm_ctx, aad, aad_len); + if (aad_len > 0) { + br_ccm_aad_inject(ccm_ctx, aad, aad_len); + } br_ccm_flip(ccm_ctx); be_return_nil(vm); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_light.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_light.ino index 89ba735e3..2b6072f16 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_light.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_light.ino @@ -150,47 +150,101 @@ extern "C" { be_pop(vm, 1); // remove last argument to have the map at the top of stack } - // power - if (map_find(vm, "power")) { - bool power = be_tobool(vm, -1); - bool current_power = bitRead(TasmotaGlobal.power, idx + Light.device - 1); - if (power != current_power) { // only send command if needed - ExecuteCommandPower(idx + Light.device, (power) ? POWER_ON : POWER_OFF, SRC_BERRY); + // read all arguments first and clear stack when calling Tasmota APIs + bool has_power = map_find(vm, "power"); + bool val_power; + if (has_power) { val_power = be_tobool(vm, -1); } + be_pop(vm, 1); + + bool has_ct = map_find(vm, "ct"); + int32_t val_ct; + if (has_ct) { val_ct = be_toint(vm, -1); } + be_pop(vm, 1); + + bool has_hue = map_find(vm, "hue"); + int32_t val_hue; + if (has_hue) { val_hue = be_toint(vm, -1); } + be_pop(vm, 1); + + bool has_sat = map_find(vm, "sat"); + int32_t val_sat; + if (has_sat) { val_sat = be_toint(vm, -1); } + be_pop(vm, 1); + + bool has_rgb = map_find(vm, "rgb"); + const char * val_rgb_s; + if (has_rgb) { val_rgb_s = be_tostring(vm, -1); } + be_pop(vm, 1); + + bool has_bri = map_find(vm, "bri"); + int32_t val_bri; + if (has_bri) { val_bri = be_toint(vm, -1); } + be_pop(vm, 1); + + bool has_channels = map_find(vm, "channels"); + uint8_t channels[LST_MAX] = {}; // initialized with all zeroes + bool val_on = false; // if all are zero, then only set power off + if (has_channels) { + if (be_isinstance(vm, -1)) { + be_getbuiltin(vm, "list"); // add "list" class + if (be_isderived(vm, -2)) { + be_pop(vm, 1); // remove "list" class from top + int32_t list_size = get_list_size(vm); + // AddLog(LOG_LEVEL_INFO, "Instance is list size = %d", list_size); + + uint8_t channels[LST_MAX] = {}; // initialized with all zeroes + if (list_size > LST_MAX) { list_size = LST_MAX; } // no more than 5 channels, no need to test for positive, any negative will be discarded by loop + for (uint32_t i = 0; i < list_size; i++) { + // be_dumpstack(vm); + get_list_item(vm, i); + // be_dumpstack(vm); + int32_t val = be_toint(vm, -1); + be_pop(vm, 1); // remove result from stack + channels[i] = to_u8(val); + if (channels[i]) { val_on = true; } + } + } else { + has_channels = false; + be_pop(vm, 1); // remove "list" class from top + } } } be_pop(vm, 1); - // ct - if (map_find(vm, "ct")) { - int32_t ct = be_toint(vm, -1); - light_controller.changeCTB(ct, light_state.getBriCT()); + be_pop(vm, be_top(vm)); // clear all stack for re_entrance + + // power + if (has_power) { + bool current_power = bitRead(TasmotaGlobal.power, idx + Light.device - 1); + if (val_power != current_power) { // only send command if needed + ExecuteCommandPower(idx + Light.device, (val_power) ? POWER_ON : POWER_OFF, SRC_BERRY); + } + } + + // ct + if (has_ct) { + light_controller.changeCTB(val_ct, light_state.getBriCT()); } - be_pop(vm, 1); // hue - if (map_find(vm, "hue")) { - int32_t hue = be_toint(vm, -1); + if (has_hue) { uint8_t sat; uint8_t bri; light_state.getHSB(nullptr, &sat, &bri); - light_controller.changeHSB(hue, sat, bri); + light_controller.changeHSB(val_hue, sat, bri); } - be_pop(vm, 1); // sat - if (map_find(vm, "sat")) { - int32_t sat = be_toint(vm, -1); + if (has_sat) { uint16_t hue; uint8_t bri; light_state.getHSB(&hue, nullptr, &bri); - light_controller.changeHSB(hue, sat, bri); + light_controller.changeHSB(hue, val_sat, bri); } - be_pop(vm, 1); // rgb - if (map_find(vm, "rgb")) { - const char * rgb_s = be_tostring(vm, -1); - SBuffer buf = SBuffer::SBufferFromHex(rgb_s, strlen(rgb_s)); + if (has_rgb) { + SBuffer buf = SBuffer::SBufferFromHex(val_rgb_s, strlen(val_rgb_s)); uint8_t channels[LST_MAX] = {}; memcpy(channels, buf.buf(), buf.len() > LST_MAX ? LST_MAX : buf.len()); bool on = false; // if all are zero, then only set power off @@ -203,48 +257,21 @@ extern "C" { ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); } } - be_pop(vm, 1); // channels - if (map_find(vm, "channels")) { - if (be_isinstance(vm, -1)) { - be_getbuiltin(vm, "list"); // add "list" class - if (be_isderived(vm, -2)) { - be_pop(vm, 1); // remove "list" class from top - int32_t list_size = get_list_size(vm); - // AddLog(LOG_LEVEL_INFO, "Instance is list size = %d", list_size); - - uint8_t channels[LST_MAX] = {}; // initialized with all zeroes - if (list_size > LST_MAX) { list_size = LST_MAX; } // no more than 5 channels, no need to test for positive, any negative will be discarded by loop - bool on = false; // if all are zero, then only set power off - for (uint32_t i = 0; i < list_size; i++) { - // be_dumpstack(vm); - get_list_item(vm, i); - // be_dumpstack(vm); - int32_t val = be_toint(vm, -1); - be_pop(vm, 1); // remove result from stack - channels[i] = to_u8(val); - if (channels[i]) { on = true; } - } - if (on) { - light_controller.changeChannels(channels); - } else { - ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); - } - } else { - be_pop(vm, 1); // remove "list" class from top - } + if (has_channels) { + if (val_on) { + light_controller.changeChannels(channels); + } else { + ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); } } - be_pop(vm, 1); // bri is done after channels and rgb // bri - if (map_find(vm, "bri")) { - int32_t bri = be_toint(vm, -1); - light_controller.changeBri(bri); + if (has_bri) { + light_controller.changeBri(val_bri); } - be_pop(vm, 1); push_getlight(vm, idx); be_return(vm); // Return diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino index cd44292ad..842d8804a 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino @@ -453,58 +453,64 @@ extern "C" { } // Find for an operator in the string - // takes a string, an offset to start the search from, and works in 2 modes. - // mode1 (false): loog for the first char of an operato - // mode2 (true): finds the last char of the operator + // returns -1 if not found, or returns start in low 16 bits, end in high 16 bits + // + // Detects the following operators: `=`, `==`, `!=`, `!==`, `<`, `<=`, `>`, `>=`, `$<`, `$>`, `$!`, `$|`, `$^`, `|` int32_t tasm_find_op(bvm *vm); int32_t tasm_find_op(bvm *vm) { int32_t top = be_top(vm); // Get the number of arguments - bool second_phase = false; int32_t ret = -1; if (top >= 2 && be_isstring(vm, 2)) { const char *c = be_tostring(vm, 2); - if (top >= 3) { - second_phase = be_tobool(vm, 3); - } + // new version, two phases in 1, return start in low 16 bits, end in high 16 bits - if (!second_phase) { - int32_t idx = 0; - // search for `=`, `==`, `!=`, `!==`, `<`, `<=`, `>`, `>=` - while (*c && ret < 0) { - switch (c[0]) { - case '=': - case '<': - case '>': - ret = idx; - break; // anything starting with `=`, `<` or `>` is a valid operator - case '!': - if (c[1] == '=') { - ret = idx; // needs to start with `!=` - } - break; - default: - break; - } - c++; - idx++; - } - } else { - // second phase + int32_t idx_start = -1; + int32_t idx = 0; + int32_t idx_end = -1; + // search for `=`, `==`, `!=`, `!==`, `<`, `<=`, `>`, `>=`, `$<`, `$>`, `$!`, `$|`, `$^`, `|` + while (*c && idx_start < 0) { switch (c[0]) { + case '=': case '<': case '>': - case '=': - if (c[1] != '=') { ret = 1; } // `<` or `>` or `=` - else { ret = 2; } // `<=` or `>=` or `==` + idx_start = idx; + if (c[1] == '=') { idx_end = idx_start + 2; } // `<=` or `>=` or `==` + else { idx_end = idx_start + 1; } // `<` or `>` or `=` break; case '!': - if (c[1] != '=') { ; } // this is invalid if isolated `!` - if (c[2] != '=') { ret = 2; } // `!=` - else { ret = 3; } // `!==` + if (c[1] == '=') { // this is invalid if isolated `!` + idx_start = idx; + if (c[2] != '=') { idx_end = idx_start + 2; } // `!=` + else { idx_end = idx_start + 3; } // `!==` + } + break; + case '$': + switch (c[1]) { + case '<': + case '>': + case '!': + case '|': + case '^': + idx_start = idx; // `$<`, `$>`, `$!`, `$|`, `$^` + idx_end = idx_start + 2; + break; + default: + break; + } + break; + case '|': + idx_start = idx; // `|` + idx_end = idx_start + 1; break; default: break; } + c++; + idx++; + } + + if (idx_start >= 0 && idx_end >= idx_start) { + ret = ((idx_end & 0x7FFF) << 16) | (idx_start & 0x7FFF); } } be_pushint(vm, ret); @@ -512,11 +518,162 @@ extern "C" { } /* - # test patterns - assert(tasmota._find_op("aaa#bbc==23",false) == 7) - assert(tasmota._find_op("==23",true) == 2) - assert(tasmota._find_op(">23",true) == 1) - assert(tasmota._find_op("aaa#bbc!23",false) == -1) + # test patterns for all-in-one version + assert(tasmota._find_op("aaa#bbc==23") == 0x80007) + assert(tasmota._find_op("az==23") == 0x30002) + assert(tasmota._find_op("a>23") == 0x10001) + assert(tasmota._find_op("aaa#bbc!23") == -1) + + */ + + // String utilities + // From https://stackoverflow.com/questions/68816324/substring-exists-in-string-in-c + // + // changed to case-insensitive version + static const char* substr_i(const char *haystack, const char *needle) { + do { + const char *htmp = haystack; + const char *ntmp = needle; + while (toupper(*htmp) == toupper(*ntmp) && *ntmp) { + htmp++; + ntmp++; + } + if (!*ntmp) { + return haystack; // Beginning of match + } + } while (*haystack++); + + return NULL; + } + + static bool startswith_i(const char *haystack, const char *needle) { + const char *htmp = haystack; + const char *ntmp = needle; + while (toupper(*htmp) == toupper(*ntmp) && *ntmp) { + htmp++; + ntmp++; + } + return !*ntmp; + } + + static bool endswith_i(const char *haystack, const char *needle) { + size_t h_len = strlen(haystack); + size_t n_len = strlen(needle); + if (h_len >= n_len) { + const char *htmp = haystack + h_len - n_len; + const char *ntmp = needle; + return (strcasecmp(htmp, ntmp) == 0); + } + return false; + } + + // Apply a string operator, without allocating any object (no pressure on GC) + // + // `tasmota._apply_str_op(op, a, b)` + // Args: + // op: operator (int) + // 1: `==` (equals) case insensitive + // 2: `!==` or `$!` (not equals) case insensitive + // 3: `$<` (starts with) case insensitive + // 4: `$>` (ends with) case insensitive + // 5: `$|` (contains) case insensitive + // 6: `$^` (does not contain) case insensitive + // a: first string + // b: second string + // + int32_t tasm_apply_str_op(bvm *vm); + int32_t tasm_apply_str_op(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + bbool ret = bfalse; + if (top >= 4 && be_isint(vm, 2) && be_isstring(vm, 3) && be_isstring(vm, 4)) { + int32_t op = be_toint(vm, 2); + const char *a = be_tostring(vm, 3); + const char *b = be_tostring(vm, 4); + + switch (op) { + case 1: // `==` (equals) case insensitive + ret = (strcasecmp(a, b) == 0); + break; + case 2: // `!==` or `$!` (not equals) case insensitive + ret = (strcasecmp(a, b) != 0); + break; + case 3: // `$<` (starts with) case insensitive + ret = startswith_i(a, b); + break; + case 4: // `$>` (ends with) case insensitive + ret = endswith_i(a, b); + break; + case 5: // `$|` (contains) case insensitive + ret = (substr_i(a, b) != NULL); + break; + case 6: // `$^` (does not contain) case insensitive + ret = (substr_i(a, b) == NULL); + break; + } + } + be_pushbool(vm, ret); + be_return(vm); + } + /* + + # unit tests + # equals + assert(tasmota._apply_str_op(1, "aa", "AA") == true) + assert(tasmota._apply_str_op(1, "aa", "AAA") == false) + assert(tasmota._apply_str_op(1, "a", "AA") == false) + assert(tasmota._apply_str_op(1, "", "AA") == false) + assert(tasmota._apply_str_op(1, "aa", "") == false) + assert(tasmota._apply_str_op(1, "", "") == true) + + # not equals + assert(tasmota._apply_str_op(2, "aa", "AA") == false) + assert(tasmota._apply_str_op(2, "aa", "AAA") == true) + assert(tasmota._apply_str_op(2, "a", "AA") == true) + assert(tasmota._apply_str_op(2, "", "AA") == true) + assert(tasmota._apply_str_op(2, "aa", "") == true) + assert(tasmota._apply_str_op(2, "", "") == false) + + # starts with + assert(tasmota._apply_str_op(3, "aabbcc", "AA") == true) + assert(tasmota._apply_str_op(3, "aaabbcc", "AA") == true) + assert(tasmota._apply_str_op(3, "abbaacc", "AA") == false) + assert(tasmota._apply_str_op(3, "aabbcc", "a") == true) + assert(tasmota._apply_str_op(3, "aabbcc", "") == true) + assert(tasmota._apply_str_op(3, "", "") == true) + assert(tasmota._apply_str_op(3, "", "a") == false) + + assert(tasmota._apply_str_op(3, "azeaze", "az") == true) + assert(tasmota._apply_str_op(3, "azeaze", "ze") == false) + + # ends with + assert(tasmota._apply_str_op(4, "azeaze", "az") == false) + assert(tasmota._apply_str_op(4, "azeaze", "ze") == true) + assert(tasmota._apply_str_op(4, "azeaze", "") == true) + assert(tasmota._apply_str_op(4, "", "aa") == false) + assert(tasmota._apply_str_op(4, "aa", "aa") == true) + assert(tasmota._apply_str_op(4, "aabaa", "aa") == true) + + # contains + assert(tasmota._apply_str_op(5, "azeaze", "az") == true) + assert(tasmota._apply_str_op(5, "azeaze", "ze") == true) + assert(tasmota._apply_str_op(5, "azeaze", "") == true) + assert(tasmota._apply_str_op(5, "azeaze", "e") == true) + assert(tasmota._apply_str_op(5, "azeaze", "a") == true) + assert(tasmota._apply_str_op(5, "azeaze", "z") == true) + assert(tasmota._apply_str_op(5, "azertyuiop", "tyui") == true) + assert(tasmota._apply_str_op(5, "azertyuiop", "azr") == false) + assert(tasmota._apply_str_op(5, "", "aze") == false) + + # not contains + assert(tasmota._apply_str_op(6, "azeaze", "az") == false) + assert(tasmota._apply_str_op(6, "azeaze", "ze") == false) + assert(tasmota._apply_str_op(6, "azeaze", "") == false) + assert(tasmota._apply_str_op(6, "azeaze", "e") == false) + assert(tasmota._apply_str_op(6, "azeaze", "a") == false) + assert(tasmota._apply_str_op(6, "azeaze", "z") == false) + assert(tasmota._apply_str_op(6, "azertyuiop", "tyui") == false) + assert(tasmota._apply_str_op(6, "azertyuiop", "azr") == true) + assert(tasmota._apply_str_op(6, "", "aze") == true) */ @@ -551,17 +708,25 @@ extern "C" { int32_t l_getpower(bvm *vm) { power_t pow = TasmotaGlobal.power; int32_t top = be_top(vm); // Get the number of arguments - if (top == 2 && be_isint(vm, 2)) { - pow = be_toint(vm, 2); - } - be_newobject(vm, "list"); - for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { - be_pushbool(vm, bitRead(pow, i)); - be_data_push(vm, -2); + if (top >= 2 && be_isint(vm, 2)) { + int32_t idx = be_toint(vm, 2); + if (idx >= 0 && idx < TasmotaGlobal.devices_present) { + be_pushbool(vm, bitRead(pow, idx)); + be_return(vm); + } else { + be_return_nil(vm); + } + } else { + // no parameter, return an array of all values + be_newobject(vm, "list"); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + be_pushbool(vm, bitRead(pow, i)); + be_data_push(vm, -2); + be_pop(vm, 1); + } be_pop(vm, 1); + be_return(vm); // Return } - be_pop(vm, 1); - be_return(vm); // Return } int32_t l_setpower(bvm *vm); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino index 854b3522c..905bc50d5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino @@ -33,24 +33,32 @@ extern "C" { extern const be_ctypes_structure_t be_tasmota_global_struct = { sizeof(TasmotaGlobal), /* size in bytes */ - 4, /* number of elements */ + 8, /* number of elements */ nullptr, - (const be_ctypes_structure_item_t[4]) { + (const be_ctypes_structure_item_t[8]) { // Warning: fields below need to be in alphabetical order { "devices_present", offsetof(TasmotaGlobal_t, devices_present), 0, 0, ctypes_u8, 0 }, { "fast_loop_enabled", offsetof(TasmotaGlobal_t, berry_fast_loop_enabled), 0, 0, ctypes_u8, 0 }, + { "masterlog_level", offsetof(TasmotaGlobal_t, masterlog_level), 0, 0, ctypes_u8, 0 }, { "restart_flag", offsetof(TasmotaGlobal_t, restart_flag), 0, 0, ctypes_u8, 0 }, + { "seriallog_level", offsetof(TasmotaGlobal_t, seriallog_level), 0, 0, ctypes_u8, 0 }, { "sleep", offsetof(TasmotaGlobal_t, sleep), 0, 0, ctypes_u8, 0 }, + { "syslog_level", offsetof(TasmotaGlobal_t, syslog_level), 0, 0, ctypes_u8, 0 }, + { "templog_level", offsetof(TasmotaGlobal_t, templog_level), 0, 0, ctypes_u8, 0 }, }}; extern const be_ctypes_structure_t be_tasmota_settings_struct = { sizeof(TSettings), /* size in bytes */ - 2, /* number of elements */ + 6, /* number of elements */ nullptr, - (const be_ctypes_structure_item_t[2]) { + (const be_ctypes_structure_item_t[6]) { // Warning: fields below need to be in alphabetical order { "bootcount", offsetof(TSettings, bootcount), 0, 0, ctypes_u16, 0 }, + { "mqttlog_level", offsetof(TSettings, mqttlog_level), 0, 0, ctypes_u8, 0 }, + { "seriallog_level", offsetof(TSettings, seriallog_level), 0, 0, ctypes_u8, 0 }, { "sleep", offsetof(TSettings, sleep), 0, 0, ctypes_u8, 0 }, + { "syslog_level", offsetof(TSettings, syslog_level), 0, 0, ctypes_u8, 0 }, + { "weblog_level", offsetof(TSettings, weblog_level), 0, 0, ctypes_u8, 0 }, }}; } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tf_lite_micro.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tf_lite_micro.ino new file mode 100644 index 000000000..d9511a589 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tf_lite_micro.ino @@ -0,0 +1,909 @@ +/* + xdrv_52_3_tf_lite_micro.ino - Berry scripting language, High-Level Tensor Flow Lite for Microprocessors model deployer + + Copyright (C) 2022 Christian Baars & Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + 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 . +*/ + + +#ifdef USE_BERRY + +#include + +#ifdef USE_BERRY_TF_LITE + +#include +#include "tensorflow/lite/micro/all_ops_resolver.h" +#include "tensorflow/lite/core/api/error_reporter.h" +#include "tensorflow/lite/micro/micro_interpreter.h" +#include "tensorflow/lite/c/c_api_types.h" +#include "tensorflow/lite/micro/system_setup.h" +#include "tensorflow/lite/schema/schema_generated.h" +#include "freertos/ringbuf.h" +#include "tensorflow/lite/c/common.h" + +#ifdef USE_I2S +#include +#include "mfcc.h" +#endif //USE_I2S + +/*********************************************************************************************\ + * Internal helper classes and constants +\*********************************************************************************************/ +#ifdef USE_I2S + +#define kObservationWindow 1000 //milliseconds +#define kAudioSampleFrequency 16000 +#define kAudioSampleBits 16 + +#endif //USE_I2S + +struct TFL_mic_descriptor_t{ + // uint8_t i2s_comm_format; // i2s_comm_format_t - enum as uint8_t + uint8_t channel_fmt; // i2s_channelformat_t - enum as uint8_t (right = 3, left = 4) + uint8_t preamp; // factor + uint8_t slice_dur; // milliseconds + uint8_t slice_stride; // milliseconds + uint8_t num_filter; // mfe bins + uint8_t num_coeff; // mfcc coefficients, if 0 -> compute MFE only + uint8_t fft_bins; // 2^fft_bins + uint8_t max_invocations; // max. invocations per second + uint8_t db_floor; // filter out noise below decibel threshold, treated as negative value + uint8_t preemphasis; // as preemphasis/100.0f , 0 - no preemphasis +}; + +struct TFL_mic_ctx_t{ + TaskHandle_t audio_capture_task = nullptr; + SemaphoreHandle_t feature_buffer_mutex = nullptr; + MFCC * mfcc = nullptr; + int8_t* model_input_buffer = nullptr; + File *file = nullptr; + int32_t file_bytes_left; + union{ + struct { + uint32_t is_audio_initialized:1; + uint32_t is_first_time:1; + uint32_t new_feature_data:1; + uint32_t continue_audio_capture:1; + uint32_t stop_audio_capture:1; + uint32_t audio_capture_ended:1; + uint32_t use_mfcc:1; + uint32_t use_gain_filter:1; + uint32_t mode_record_audio:1; + uint32_t file_is_open:1; + } flag; + uint32_t flags; + }; + int feature_buffer_idx = 0; + int8_t *feature_buffer; + // user input + // int32_t i2s_comm_format; + i2s_channel_fmt_t channel_fmt; + int32_t preamp; // factor + int32_t slice_dur; // milliseconds + int32_t slice_stride; // milliseconds + uint8_t num_filter; // mfe filter bins + uint8_t num_coeff; // mfcc coefficients, if 0 -> compute MFE only + int32_t fft_bins; // 2^fft_bins + // calculated + int32_t slice_size; // bytes + int32_t slice_count; + uint16_t i2s_samples_to_get; + int16_t db_floor; // filter out noise below decibel threshold, this is now a negative value + float preemphasis; +}; + +struct TFL_stats_t{ + uint32_t model_size = 0; + uint32_t used_arena_bytes = 0; + uint32_t invokations = 0; + uint32_t loop_task_free_stack_bytes = 0; + uint32_t mic_task_free_stack_bytes = 0; +}; + +struct TFL_ctx_t{ +const tflite::Model* model = nullptr; +TfLiteTensor* input = nullptr; +TfLiteTensor* output = nullptr; +int8_t *berry_output_buf = nullptr; +size_t berry_output_bufsize; +int TensorArenaSize = 2000; +uint8_t max_invocations; // max. invocations per second + +TaskHandle_t loop_task = nullptr; +// QueueHandle_t loop_queue = nullptr; +union{ + struct { + uint32_t init_done:1; + uint32_t delay_next_invocation:1; + uint32_t running_invocation:1; + uint32_t running_loop:1; + // uint32_t stop_loop:1; + uint32_t loop_ended:1; + uint32_t unread_output:1; + uint32_t use_cam:1; + uint32_t use_mic:1; + uint32_t mode_inference:1; + } option; + uint32_t options; +}; +#ifdef USE_I2S +TFL_mic_ctx_t *mic = nullptr; +#endif +TFL_stats_t *stats = nullptr; +}; + +TFL_ctx_t *TFL = nullptr; +RingbufHandle_t TFL_log_buffer = nullptr; + + +/*********************************************************************************************\ + * Internal driver functions +\*********************************************************************************************/ + +/** + * @brief This function is called from Microprint() from the Tensorflow framework + * Used to log from Tensorflow and from this (Tasmota) driver + * + * @param s - message as c-string + */ +void TFL_Log(char *s){ + size_t len = strlen(s); + if(len<5) return; // we assume this is for the trash + + xRingbufferSend(TFL_log_buffer, s, len+1 , pdMS_TO_TICKS(3)); +} + +bool TFL_create_task(){ + if (TFL->option.running_loop) return bfalse; + if(TFL->loop_task!=nullptr) vTaskDelete(TFL->loop_task); + + xTaskCreatePinnedToCore( + TFL_task_loop, /* Function to implement the task */ + "tfl_loop", /* Name of the task */ + 8000 + (TFL->TensorArenaSize),/* Stack size in words */ + NULL, /* Task input parameter */ + 1, /* Priority of the task */ + &TFL->loop_task, /* Task handle. */ + 1); /* Core where the task should run */ + + return btrue; +} + +bool TFL_init_CAM(){ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: mode webcam not implemented yet")); + delete TFL; + TFL = nullptr; + return bfalse; +} + +#ifdef USE_I2S +/** + * @brief Set up some buffers and tables for feature extraction of audio samples. Must run once before starting audio capturing. + * + * @return int - not used ATM + */ +int TFL_InitializeFeatures() { + uint32_t samples_to_process = (TFL->mic->i2s_samples_to_get * TFL->mic->slice_dur)/TFL->mic->slice_stride; + TFL->mic->mfcc = new MFCC(TFL->mic->num_coeff, samples_to_process, TFL->mic->num_filter, kAudioSampleFrequency, 300, 8000); + TFL->mic->mfcc->set_preamp(TFL->mic->preamp); + TFL->mic->mfcc->set_preemphasis(TFL->mic->preemphasis); + MicroPrintf( PSTR( "MFCC %u initialized for %u samples, preamp: %u, preemphasis: %f"),TFL->mic->num_coeff,samples_to_process, TFL->mic->preamp, TFL->mic->preemphasis); + return kTfLiteOk; +} + +/** + * @brief Computes features from every audio slice immediately after capturing it. + * + * @param input - audio buffer + * @param input_size - length auf audio input in samples (16-bit) + * @param output_size - length of feature buffer in bytes (we use int8_t quantization) + * @param output - feature buffer for one slice of audio + * @param num_samples_read - not used anymore, to be removed + * @return int + */ +int TFL_GenerateFeatures(const int16_t* input, int input_size, + int output_size, int8_t* output, + size_t* num_samples_read) { + + float out_buf[output_size]; + + TFL->mic->mfcc->mfcc_compute(input, out_buf); + if(TFL->mic->num_coeff == 0){ // mfe only + TFL->mic->mfcc->log10_normalize(out_buf, output_size, TFL->mic->db_floor); + } + + float scale = TFL->input->params.scale; + int32_t zero_point = TFL->input->params.zero_point; + float min_f = 1; + float max_f = 0; + + for (size_t i = 0; i < output_size; ++i) { + int32_t value = ((out_buf[i]/ scale) + zero_point); + if(value < -128){ + value = -128; + } + else if(value > 127){ + value = 127; + } + output[i] = value; + // if(min_f>out_buf[i]) min_f = out_buf[i]; + // if(max_fmic->file != nullptr){ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: close open file")); + TFL->mic->file->close(); + delete TFL->mic->file; + } + TFL->mic->file = new File(ufsp->open(fname, "w")); + if(TFL->mic->file != nullptr){ + TFL->mic->flag.file_is_open = 1; + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: file open")); + } + else{ + return false; + } + +#define WAVE_HEADER_SIZE 44 + + uint32_t sample_rate = kAudioSampleFrequency; + uint8_t sample_bits = kAudioSampleBits; + uint32_t byte_rate = sample_rate * (sample_bits/8); + uint32_t wav_size = byte_rate * record_time; + uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8; + +#define U32_BYTE(x,y) (uint8_t)((x>>(y*8))&0xff) + + const char set_wav_header[] = { + 'R','I','F','F', // ChunkID + U32_BYTE(file_size,0),U32_BYTE(file_size,1),U32_BYTE(file_size,2),U32_BYTE(file_size,3), // ChunkSize + 'W','A','V','E', // Format + 'f','m','t',' ', // Subchunk1ID + sample_bits, 0x00, 0x00, 0x00, // Subchunk1Size (16 for PCM) + 0x01, 0x00, // AudioFormat (1 for PCM) + 0x01, 0x00, // NumChannels (1 channel) + U32_BYTE(sample_rate,0),U32_BYTE(sample_rate,1),U32_BYTE(sample_rate,2),U32_BYTE(sample_rate,3), // ChuSampleRatekSize + U32_BYTE(byte_rate,0),U32_BYTE(byte_rate,1),U32_BYTE(byte_rate,2),U32_BYTE(byte_rate,3), // ByteRate + 0x02, 0x00, // BlockAlign + sample_bits, 0x00, // BitsPerSample (16 bits) + 'd','a','t','a', // Subchunk2ID + U32_BYTE(wav_size,0),U32_BYTE(wav_size,1),U32_BYTE(wav_size,2),U32_BYTE(wav_size,3), // ByteRate + }; + + TFL->mic->file->write((uint8_t*)set_wav_header,WAVE_HEADER_SIZE); + TFL->mic->file_bytes_left = wav_size; + + return true; +} + +/** + * @brief Init I2S microphone. Pins must be configured in the "usual" Tasmota way. Some properties are variables stored in the descriptor. + * + * @param descriptor - byte array passed from Berry. Arbitrary format - might change in the future!! + * @return true - success + * @return false - failure + */ +bool TFL_init_MIC(const uint8_t* descriptor){ + if (PinUsed(GPIO_I2S_BCLK) && PinUsed(GPIO_I2S_WS) && PinUsed(GPIO_I2S_DIN)) { + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: init mic")); + } + else{ + AddLog(LOG_LEVEL_ERROR, PSTR("TFL: I2S GPIO's not set for mic input!")); + return bfalse; + } + + #define I2S_NUM (i2s_port_t)I2S_NUM_0 // 0 or 1 + + TFL->mic = new TFL_mic_ctx_t; + TFL->mic->flags = 0; + TFL_set_mic_config(descriptor); + + i2s_config_t i2s_config = { + .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), + .sample_rate = kAudioSampleFrequency, + .bits_per_sample = (i2s_bits_per_sample_t)kAudioSampleBits, + .channel_format = TFL->mic->channel_fmt, + .communication_format = I2S_COMM_FORMAT_STAND_I2S, ///i2s_comm_format_t(1), // ?? I2S_COMM_FORMAT_STAND_I2S | I2S_COMM_FORMAT_STAND_MSB + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 5, + .dma_buf_len = 320, + .use_apll = false, + .tx_desc_auto_clear = false, + .fixed_mclk = 0 + }; + + i2s_pin_config_t pin_config = { + .bck_io_num = Pin(GPIO_I2S_BCLK), + .ws_io_num = Pin(GPIO_I2S_WS), + .data_out_num = I2S_PIN_NO_CHANGE, + .data_in_num = Pin(GPIO_I2S_DIN) + }; + + esp_err_t ret = ESP_OK; + ret = i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL); + + if (ret != ESP_OK) { + AddLog(LOG_LEVEL_ERROR, PSTR("TFL: Error in i2s_driver_install")); + return bfalse; + } + ret = i2s_set_pin(I2S_NUM, &pin_config); + if (ret != ESP_OK) { + AddLog(LOG_LEVEL_ERROR, PSTR("Error in i2s_set_pin")); + return bfalse; + } + + TFL->mic->feature_buffer_mutex = xSemaphoreCreateMutex(); + + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: MIC ctx created")); + return btrue; +} + +void TFL_append_audio_to_file(uint8_t *byte_buffer, uint16_t length){ + int16_t *samples = (int16_t *)byte_buffer; + + for(int i=0;imic->preamp; //gain ... a lot + } + + TFL->mic->file->write(byte_buffer,length); + + TFL->mic->file_bytes_left -= length; + if(TFL->mic->file_bytes_left<0){ + TFL->mic->file->close(); + delete TFL->mic->file; + TFL->mic->flag.file_is_open = 0; + TFL->mic->flag.continue_audio_capture = 0; + TFL->option.running_loop = 0; + MicroPrintf( PSTR( "Closing file.")); + } +} + +/** + * @brief Function spawned as a task for capturing audio. Used for recording or inference. + * + * @param arg - not used + */ +void TFL_capture_samples(void* arg) { + MicroPrintf( PSTR( "Capture task started")); + int i2s_bytes_to_read = TFL->mic->i2s_samples_to_get * 2; // according to slice duration + + int buffer_size = (i2s_bytes_to_read * TFL->mic->slice_dur)/TFL->mic->slice_stride; // in bytes, current slice duration plus (potential) history data + + size_t samples_to_read; + size_t bytes_read; + int tf_status = 0; + + int16_t i2s_sample_buffer[buffer_size/2] = {0}; // in shorts, add the size to hold history data + uint8_t *i2s_byte_buffer = (uint8_t*)i2s_sample_buffer; + uint32_t *i2s_long_buffer = (uint32_t*)i2s_sample_buffer; + uint8_t *i2s_read_buffer = i2s_byte_buffer + (buffer_size - i2s_bytes_to_read); // behind the history data, if slice duration != slice stride + + // read to "nowhere" to get no startup noise on some mics + i2s_read(I2S_NUM, i2s_byte_buffer, i2s_bytes_to_read, &bytes_read, pdMS_TO_TICKS(100)); + vTaskDelay(pdMS_TO_TICKS(1000)); + + if(TFL->option.mode_inference == 1){ + TFL_InitializeFeatures(); // TODO: check or not for success + } + + TFL->mic->flag.continue_audio_capture = 1; + MicroPrintf( PSTR( "Enter capture samples loop")); + + // "clean" the DMA buffers a last time + i2s_zero_dma_buffer(I2S_NUM); + vTaskDelay(pdMS_TO_TICKS(TFL->mic->slice_stride)); + + while (TFL->mic->flag.continue_audio_capture == 1) { + TFL->stats->mic_task_free_stack_bytes = uxTaskGetStackHighWaterMark(NULL); + TickType_t xLastWakeTime = xTaskGetTickCount(); + + /* read slice data at once from i2s */ + i2s_read(I2S_NUM, i2s_read_buffer, i2s_bytes_to_read, &bytes_read, pdMS_TO_TICKS(TFL->mic->slice_stride)); + + if (bytes_read <= 0) { + MicroPrintf( PSTR( "Error in I2S read : %d"), bytes_read); + } + else if(TFL->mic->flag.file_is_open == 1){ + TFL_append_audio_to_file(i2s_read_buffer,bytes_read); + if (bytes_read < i2s_bytes_to_read) { + MicroPrintf(PSTR("Partial I2S read: %d"), bytes_read); + } + } + else { + if (bytes_read < i2s_bytes_to_read) { + MicroPrintf(PSTR("Partial I2S read: %d"), bytes_read); + } + + xSemaphoreTake(TFL->mic->feature_buffer_mutex, pdMS_TO_TICKS(TFL->mic->slice_stride) ); + + tf_status = TFL_GenerateFeatures((const int16_t*)i2s_sample_buffer, buffer_size/2 , TFL->mic->slice_size, + TFL->mic->feature_buffer + (TFL->mic->feature_buffer_idx * TFL->mic->slice_size), + &samples_to_read); + + for(int i=0;i<(buffer_size - i2s_bytes_to_read)/4;i++){ + i2s_long_buffer[i] = i2s_long_buffer[i + ((buffer_size - i2s_bytes_to_read)/4)]; //move history to the front + } + + TFL->mic->feature_buffer_idx += 1; + if(TFL->mic->feature_buffer_idx == TFL->mic->slice_count){ + TFL->mic->feature_buffer_idx = 0; + } + TFL->mic->flag.new_feature_data = 1; + xSemaphoreGive(TFL->mic->feature_buffer_mutex); + + } + // MicroPrintf( PSTR("t: %u"),xTaskGetTickCount()-xLastWakeTime); + + if(TFL->mic->flag.continue_audio_capture == 1) vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS(TFL->mic->slice_stride) ); + } + i2s_driver_uninstall(I2S_NUM); + if(TFL->mic->mfcc != nullptr){ + delete TFL->mic->mfcc; + TFL->mic->mfcc = nullptr; + } + MicroPrintf( PSTR("end capture task")); + TFL->mic->flag.audio_capture_ended = 1; + vTaskDelete(NULL); +} + +/** + * @brief Pass descriptor variables from Berry to the MIC context. Will also calculate some vars. + * + * @param descriptor_buffer - byte array from Berry + */ +void TFL_set_mic_config(const uint8_t *descriptor_buffer){ + TFL_mic_descriptor_t *mic_descriptor = (TFL_mic_descriptor_t*)descriptor_buffer; + TFL->mic->channel_fmt = (i2s_channel_fmt_t)mic_descriptor->channel_fmt; + TFL->mic->preamp = mic_descriptor->preamp; + TFL->mic->slice_dur = mic_descriptor->slice_dur; + TFL->mic->slice_stride = mic_descriptor->slice_stride; + TFL->mic->num_filter = mic_descriptor->num_filter; + TFL->mic->num_coeff = mic_descriptor->num_coeff; + TFL->mic->fft_bins = mic_descriptor->fft_bins; + TFL->max_invocations = mic_descriptor->max_invocations; + // now calculate the other settings + TFL->mic->slice_size = mic_descriptor->num_coeff == 0 ? mic_descriptor->num_filter : mic_descriptor->num_coeff; + TFL->mic->slice_count = (int32_t)((kObservationWindow/(float)TFL->mic->slice_stride) - 0.01); // floor(x) to int + TFL->mic->preemphasis = (float)(mic_descriptor-> preemphasis)/100.0f; + TFL->mic->i2s_samples_to_get = (TFL->mic->slice_stride * (kAudioSampleFrequency / 1000)); + TFL->mic->db_floor = mic_descriptor->db_floor * -1; + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: filter: %u, coefficients: %u"), TFL->mic->num_filter, TFL->mic->num_coeff); + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: slice stride: %u ms -> slice count: %u, samples to read: %u"), TFL->mic->slice_stride, TFL->mic->slice_count, TFL->mic->i2s_samples_to_get); +} + +/** + * @brief Updates the input tensor with the data from the featuree buffer, which works as a ring buffer and is a shared resorce. + * + */ +void TFL_mic_feature_buf_to_input(){ + xSemaphoreTake(TFL->mic->feature_buffer_mutex, pdMS_TO_TICKS(TFL->mic->slice_stride) ); + // Copy feature buffer to input tensor + int idx = TFL->mic->feature_buffer_idx + 1; //oldest slice right after the newest slice + if(idx == TFL->mic->slice_count) idx = 0; + int slices_upperstack = TFL->mic->slice_count - idx; + int slices_lowerstack = TFL->mic->slice_count - slices_upperstack; + memcpy(TFL->mic->model_input_buffer,TFL->mic->feature_buffer + (idx * TFL->mic->slice_size), TFL->mic->slice_size * slices_upperstack); + memcpy(TFL->mic->model_input_buffer + (TFL->mic->slice_size * slices_upperstack),TFL->mic->feature_buffer, TFL->mic->slice_size * slices_lowerstack); + xSemaphoreGive(TFL->mic->feature_buffer_mutex); + return; +} + +/** + * @brief Helper function to stop audio capture task + * + */ +void TFL_stop_audio_capture(){ + MicroPrintf( PSTR("shall stop_capture_task")); + if(TFL->mic->flag.continue_audio_capture == 0) return; + TFL->mic->flag.continue_audio_capture = 0; + uint32_t timeout = 0; + while(TFL->mic->flag.audio_capture_ended == 0){ + if(timeout>3) break; + vTaskDelay(pdMS_TO_TICKS(TFL->mic->slice_stride) ); + timeout++; + } + vSemaphoreDelete(TFL->mic->feature_buffer_mutex); + delete[] TFL->mic->feature_buffer; +} +#endif //USE_I2S + +/** + * @brief Helper function to stop all runnning tasks + * + */ +void TFL_delete_tasks(){ + if(TFL == nullptr) return; + TFL->option.running_loop = 0; + while(TFL->option.loop_ended == 0){ + vTaskDelay(pdMS_TO_TICKS(10)); + } + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: task loop did stop")); + if(TFL->mic != nullptr){ + delete TFL->mic; + } + delete TFL; + TFL = nullptr; +} + +/** + * @brief Starts inference task and the run loop. Should be terminated by signal from helper function. + * + * @param pvParameters - not used + */ +void TFL_task_loop(void *pvParameters){ + uint8_t tensor_arena[TFL->TensorArenaSize]; + TFL->stats = new TFL_stats_t; + tflite::AllOpsResolver resolver; //TODO: infer needed Ops from model?? + tflite::MicroInterpreter interpreter( + TFL->model, resolver, tensor_arena, TFL->TensorArenaSize); + int allocate_status = interpreter.AllocateTensors(); + if (allocate_status != kTfLiteOk) { + MicroPrintf( PSTR("AllocateTensors() failed")); + goto loop_task_exit; + } + else{ + TFL->stats->used_arena_bytes = interpreter.arena_used_bytes(); + } + // Obtain pointers to the model's input/output, we can use it externally + TFL->input = interpreter.input(0); + TFL->output = interpreter.output(0); + +#ifdef USE_I2S + if(TFL->option.use_mic == 1){ + TFL->mic->feature_buffer = new int8_t[TFL->mic->slice_size * TFL->mic->slice_count](); + xTaskCreatePinnedToCore(TFL_capture_samples, "tfl_mic", 1024 * 5, NULL, 15, &TFL->mic->audio_capture_task, 0); + if(TFL->mic->audio_capture_task == nullptr){ + MicroPrintf( PSTR("Creating capture task failed")); + goto loop_task_exit; + } + MicroPrintf( PSTR("Created capture task")); + TFL->mic->model_input_buffer = TFL->input->data.int8; + vTaskDelay(pdMS_TO_TICKS(2000)); // wait for at least the time of the the microphone warm up + } +#endif + + TFL->option.running_loop = 1; + +// loop section + MicroPrintf(PSTR("Enter task loop")); + while (TFL->option.running_loop == 1) + { + TickType_t xLastWakeTime = xTaskGetTickCount(); + TFL->stats->loop_task_free_stack_bytes = uxTaskGetStackHighWaterMark(NULL); + #ifdef USE_I2S + if(TFL->option.use_mic == 1){ + if(TFL->mic->flag.mode_record_audio == 1){ + vTaskDelay(1000/ portTICK_PERIOD_MS); // sit and wait while recording + continue; + } + } + #endif //USE_I2S + + bool do_invokation = true; + while(TFL->option.delay_next_invocation == 1 && TFL->option.running_loop == 1){ + MicroPrintf(PSTR("delay_next_invocation")); + vTaskDelay(10/ portTICK_PERIOD_MS); + } + TFL->option.delay_next_invocation = 1; + + #ifdef USE_I2S + if(TFL->option.use_mic == 1){ + TFL->option.delay_next_invocation = 0; // Clean up later + if (TFL->mic->flag.new_feature_data == 0){ + do_invokation = false; + } + if(TFL->mic->flag.continue_audio_capture == 1){ + TFL_mic_feature_buf_to_input(); + } + } + #endif + if(do_invokation){ + // MicroPrintf(PSTR("Invokation requested")); + TFL->option.running_invocation = 1; + int invoke_status = interpreter.Invoke(); + if (invoke_status != kTfLiteOk) { + MicroPrintf(PSTR("Invoke failed")); + TFL->option.running_loop = 0; + } + if(TFL->berry_output_buf != nullptr){ + memcpy(TFL->berry_output_buf,(int8_t*)TFL->output->data.data,TFL->berry_output_bufsize); + } + TFL->stats->invokations++; + + TFL->option.unread_output = 1; + #ifdef USE_I2S + if(TFL->option.use_mic == 1) { + TFL->mic->flag.new_feature_data = 0; + } + TFL->option.running_invocation = 0; + #endif //USE_I2S + } + if(TFL->option.running_loop == 1) vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000 / TFL->max_invocations)); //maybe we already want to exit + } + +// end of loop section +loop_task_exit: + delete TFL->stats; + if(TFL->option.use_mic == 1) {TFL_stop_audio_capture();} + MicroPrintf(PSTR("end loop task")); + TFL->option.loop_ended = 1; + vTaskDelete( NULL ); +} + +/*********************************************************************************************\ + * Native functions mapped to Berry functions +\*********************************************************************************************/ +extern "C" { + +/** + * @brief Create a context for a tensor flow session, that will later run in a task + * + * @param vm + * @param type BUF - generic byte buffer, CAM - webcam input, MIC - microphone input + * @return btrue + * @return bfalse + */ + bbool be_TFL_begin(struct bvm *vm, const char* type, const uint8_t *descriptor, size_t len) { + if (TFL_log_buffer == nullptr){ + TFL_log_buffer = xRingbufferCreate(1028, RINGBUF_TYPE_NOSPLIT); + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: init log buffer")); + } + TFL_delete_tasks(); + if(strlen(type) == 0){ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: context deleted")); + return btrue; + } + TFL = new TFL_ctx_t; + TFL->options = 0; + + if(*(uint32_t*)type == 0x00465542){ //BUF + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: mode generic buffer")); + } + else if(*(uint32_t*)type == 0x004D4143){ //CAM - not yet implemented + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: mode webcam")); + if(TFL_init_CAM()){ + TFL->option.use_cam = 1; + } + else{ + return bfalse; + } + } + else if(*(uint32_t*)type == 0x0043494D){ //MIC + if(descriptor && len==sizeof(TFL_mic_descriptor_t)){ + if(TFL_init_MIC(descriptor)){ + TFL->option.use_mic = 1; + } + else{ + return bfalse; + } + } + else{ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: expected descriptor of size: %u"), sizeof(TFL_mic_descriptor_t)); + return bfalse; + } + } + else{ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: unknown mode")); + return bfalse; + } + if(TFL!=nullptr){ + AddLog(LOG_LEVEL_INFO, PSTR("TFL: start TFL context with type: %s"), type); + TFL->option.init_done = 1; + return btrue; + } + return bfalse; + } + +/** + * @brief Load tensor flow lite model and then start the tensor flow session in a task + * + * @param vm + * @param buf Model in a byte buffer + * @param size Size of buffer, must be 8-byte-aligned (auto-calculated by Berry) + * @param arena Size of the Tensor Arena in the stack of the TFL task + * @return btrue + * @return bfalse + */ + bbool be_TFL_load(struct bvm *vm, const uint8_t *model_buf, size_t model_size, const uint8_t *output_buf, size_t output_size,int arena) { + if(TFL){ + if(TFL->option.init_done){ + TFL->model = tflite::GetModel(model_buf); + if ( TFL->model->version() != TFLITE_SCHEMA_VERSION) { + AddLog(LOG_LEVEL_INFO, PSTR("TFL: Model schema version %d not supported " + "version %d."), TFL->model->version(), TFLITE_SCHEMA_VERSION); + return bfalse; + } + if(model_size%8 != 0){ + AddLog(LOG_LEVEL_INFO, PSTR("TFL: model not 8-byte aligned")); + return bfalse; + } + if(arena){ + TFL->TensorArenaSize = arena; + } + TFL->option.mode_inference = 1; + TFL->berry_output_buf = (int8_t*)output_buf; + TFL->berry_output_bufsize = output_size; + TFL_create_task(); + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: starting TFL task, model sz: %u, allocated arena sz: %u"),model_size,TFL->TensorArenaSize); + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: Berry output buffer of size: %u"),output_size); + return btrue; + } + } + return bfalse; + } + + /** + * @brief Send new input data to the tensor flow session + * + * @param vm + * @param buf Arbitrary data in a byte buffer, must fit to the TF model + * @param size Size of buffer (auto-calculated by Berry) + * @return btrue + * @return bfalse + */ + + bbool be_TFL_input(struct bvm *vm, const uint8_t *buf, size_t size){ + if(!TFL) return bfalse; + if(TFL->option.running_loop == 1){ + uint32_t timeout = 0; + while(!TFL->option.delay_next_invocation == 1) { + if(timeout>10) break; + delay(2); + timeout++; + } + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: imput new data and invoke")); + memcpy((uint8_t*)TFL->input->data.data,(uint8_t*)buf,size); + TFL->option.delay_next_invocation = 0; + return btrue; + } + return bfalse; + } + + /** + * @brief Get copy of the output sensor of the tensor flow session + * + * @param vm + * @param buf Arbitrary data in a byte buffer, must fit in size to the TF model + * @param size Size of buffer (auto-calculated by Berry) + * @return btrue - new data + * @return bfalse - old data + */ + bbool be_TFL_output(struct bvm *vm, const uint8_t *buf, size_t size){ + if(!TFL) return bfalse; + if(TFL->option.running_loop == 0) return bfalse; + if(TFL->option.unread_output == 1){ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: read output data")); + if(TFL->output != nullptr){ + TFL->option.unread_output = 0; + return btrue; //new data + } + } + return bfalse; // old data + } + +/** + * @brief Read from the logging buffer from the TFL tasks + * + * @param vm + * @return const char* + */ + const char * be_TFL_log(struct bvm *vm){ + size_t size; + char * item = (char *)xRingbufferReceive(TFL_log_buffer, &size, pdMS_TO_TICKS(5)); + if(item != NULL){ + // item[size] = 0; // 0-terminate string + vRingbufferReturnItem(TFL_log_buffer, (void *)item); + } + return (const char *)item; + } + + +/** + * @brief Shows statistics about the model and the running TFL session + * + * @param vm + * @return json string + */ + const char * be_TFL_stats(struct bvm *vm){ + + const size_t size = 512; + char * s = (char*)calloc(size,1); + uint32_t pos = 0; + uint32_t inc = 0; + inc = snprintf_P(s + pos, size, PSTR("{\"model\":{\"input_shape\":[")); + pos += inc; + uint32_t dims = TFL->input->dims->size; + for(int i=0;iinput->dims->data[i]); + pos += inc; + if (i != dims-1){ + inc = snprintf_P(s + pos, size-pos,","); + pos += inc; + } + } + inc = snprintf_P(s + pos, size-pos, PSTR("],\"input_type\":%u,\"output_shape\":["),TFL->input->type); + pos += inc; + dims = TFL->output->dims->size; + for(int i=0;ioutput->dims->data[i]); + pos += inc; + if (i != dims-1){ + inc = snprintf_P(s + pos, size-pos,","); + pos += inc; + } + } + inc = snprintf_P(s + pos, size-pos, PSTR("],\"output_type\":%u}"),TFL->output->type); + pos += inc; + inc = snprintf_P(s + pos, size-pos, PSTR(",\"sessiom\":{\"used_arena\":%u"),TFL->stats->used_arena_bytes); + pos += inc; + inc = snprintf_P(s + pos, size-pos, PSTR(",\"loop_stack\":%u"),TFL->stats->loop_task_free_stack_bytes); + pos += inc; + if(TFL->option.use_mic == 1){ + inc = snprintf_P(s + pos, size-pos, PSTR(",\"audio_stack\":%u"),TFL->stats->mic_task_free_stack_bytes); + pos += inc; + } + inc = snprintf_P(s + pos, size-pos, PSTR(",\"invokations\":%u}}"),TFL->stats->invokations); + be_pushstring(vm, s); + free(s); + return s; + } + + void be_TFL_rec(struct bvm *vm, const char* filename, size_t seconds){ + if(TFL){ + TFL->option.loop_ended = 1; // just in case someone wants to stop this from another scope + if(TFL->mic != nullptr){ + if(TFL->mic->flag.continue_audio_capture == 1){ + AddLog(LOG_LEVEL_DEBUG, PSTR("TFL: running recording, requesting termination")); + TFL->mic->flag.continue_audio_capture = 0; + return; + } + if(TFL_init_wave_file(filename,seconds)){ + TFL->mic->flag.mode_record_audio = 1; + TFL->stats = new TFL_stats_t; + xTaskCreatePinnedToCore(TFL_capture_samples, "tfl_mic", 1024 * 3, NULL, 10, &TFL->mic->audio_capture_task, 0); + } + } + } + else{ + AddLog(LOG_LEVEL_ERROR, PSTR("TFL: no MIC context initialized")); + } + } +} //extern "C" + +#endif // USE_BERRY_TF_LITE + +#endif // USE_BERRY diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino index 198103fd3..17d590879 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino @@ -259,6 +259,55 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } + // wc.set_follow_redirects(bool) -> self + int32_t wc_set_follow_redirects(struct bvm *vm); + int32_t wc_set_follow_redirects(struct bvm *vm) { + int32_t argc = be_top(vm); + if (argc >= 2 && be_isbool(vm, 2)) { + HTTPClientLight * cl = wc_getclient(vm); + bbool follow = be_tobool(vm, 2); + cl->setFollowRedirects(follow ? HTTPC_STRICT_FOLLOW_REDIRECTS : HTTPC_DISABLE_FOLLOW_REDIRECTS); + be_pushvalue(vm, 1); + be_return(vm); /* return self */ + } + be_raise(vm, kTypeError, nullptr); + } + + // wc.collect_headers( [header:string]+ ) -> self + int32_t wc_collect_headers(struct bvm *vm); + int32_t wc_collect_headers(struct bvm *vm) { + int32_t argc = be_top(vm); + if (argc >= 2) { + size_t header_len = argc-1; + const char** header_array = (const char**) be_os_malloc((header_len) * sizeof(const char*)); + if (!header_array) { be_throw(vm, BE_MALLOC_FAIL); } + + for (int32_t i = 0; i < header_len; i++) { + header_array[i] = be_tostring(vm, i + 2); + } + HTTPClientLight * cl = wc_getclient(vm); + cl->collectHeaders(header_array, header_len); + + be_os_free(header_array); + } + be_pushvalue(vm, 1); + be_return(vm); /* return self */ + } + + // wc.get_header(header_name:string) -> string + int32_t wc_get_header(struct bvm *vm); + int32_t wc_get_header(struct bvm *vm) { + int32_t argc = be_top(vm); + if (argc >= 2 && be_isstring(vm, 2)) { + HTTPClientLight * cl = wc_getclient(vm); + const char * header_name = be_tostring(vm, 2); + String ret = cl->header(header_name); + be_pushstring(vm, ret.c_str()); + be_return(vm); /* return self */ + } + be_raise(vm, kTypeError, nullptr); + } + // wc.wc_set_auth(auth:string | (user:string, password:string)) -> self int32_t wc_set_auth(struct bvm *vm); int32_t wc_set_auth(struct bvm *vm) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino index 599548ac4..f37be12b5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webserver.ino @@ -247,6 +247,20 @@ extern "C" { be_raise(vm, kTypeError, nullptr); } + // Berry: `webserver.html_escape(string) -> string` + // + int32_t w_webserver_html_escape(struct bvm *vm); + int32_t w_webserver_html_escape(struct bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isstring(vm, 1)) { + const char * text = be_tostring(vm, 1); + String html = HtmlEscape(text); + be_pushstring(vm, html.c_str()); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + // Berry: `webserver.args() -> int` // // Returns the number of arguments diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino index d453455a7..c78f30960 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_wire.ino @@ -109,7 +109,7 @@ extern "C" { TwoWire & myWire = getWire(vm); if (top == 1 || (top == 2 && be_isbool(vm, 2))) { // only 1 argument of type string accepted bool stop = true; - if (top == 1) { + if (top == 2) { stop = be_tobool(vm, 2); } uint32_t ret = myWire.endTransmission(stop); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino index d6e9fabf5..6ee7437b1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino @@ -24,7 +24,7 @@ #include #include "berry_tasmota.h" -#ifdef USE_MATTER +#ifdef USE_MATTER_DEVICE #include "berry_matter.h" #endif #include "be_vm.h" @@ -802,6 +802,9 @@ bool Xdrv52(uint32_t function) case FUNC_WEB_SENSOR: callBerryEventDispatcher(PSTR("web_sensor"), nullptr, 0, nullptr); break; + case FUNC_WEB_GET_ARG: + callBerryEventDispatcher(PSTR("web_get_arg"), nullptr, 0, nullptr); + break; case FUNC_JSON_APPEND: callBerryEventDispatcher(PSTR("json_append"), nullptr, 0, nullptr); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino b/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino index dc31523df..999f6a738 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino @@ -123,7 +123,8 @@ projector_ctrl_pre_init(void) SetSerial(baudrate, TS_SERIAL_8N1); } - sc->sc_device = ++(TasmotaGlobal.devices_present); /* claim a POWER device slot */ + UpdateDevicesPresent(1); /* claim a POWER device slot */ + sc->sc_device = TasmotaGlobal.devices_present; AddLog(LOG_LEVEL_INFO, PSTR(PROJECTOR_CTRL_LOGNAME ": new RELAY%d, polling serial for Projector status"), sc->sc_device); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino index b68c96c6d..1b4e4f598 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino @@ -504,7 +504,7 @@ bool Xdrv56(uint32_t function) { } #endif // RTC_NTP_SERVER - if (FUNC_I2C_INIT == function) { + if (FUNC_SETUP_RING1 == function) { RtcChipDetect(); } else if (RtcChip.detected) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino b/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino index d18410afb..f477fc8ff 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino @@ -58,7 +58,8 @@ void Shift595Init(void) { Shift595->first = TasmotaGlobal.devices_present; Shift595->outputs = Settings->shift595_device_count * 8; - TasmotaGlobal.devices_present += Shift595->outputs; + UpdateDevicesPresent(Shift595->outputs); + Shift595->connected = true; AddLog(LOG_LEVEL_DEBUG, PSTR("595: Controlling relays POWER%d to POWER%d"), Shift595->first + 1, Shift595->first + Shift595->outputs); } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino index 6c3c33d4e..f75217fd1 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino @@ -50,6 +50,7 @@ #define MBR_MAX_VALUE_LENGTH 30 #define MBR_BAUDRATE TM_MODBUS_BAUDRATE #define MBR_MAX_REGISTERS 64 +#define MBR_RECEIVE_BUFFER_SIZE (MBR_MAX_REGISTERS * 2) + 9 // Addres(1), Function(1), Length(1) or StartAddress(2), N/A or Number of addresses(2),Data(1..n), CRC(2) #define D_CMND_MODBUS_SEND "Send" #define D_CMND_MODBUS_SETBAUDRATE "Baudrate" @@ -80,12 +81,13 @@ void (*const ModbusBridgeCommand[])(void) PROGMEM = { #define D_CMND_MODBUS_TCP_START "TCPStart" #define D_CMND_MODBUS_TCP_CONNECT "TCPConnect" +#define D_CMND_MODBUS_TCP_MQTT "TCPMqtt" const char kModbusBridgeCommands[] PROGMEM = "Modbus|" // Prefix - D_CMND_MODBUS_TCP_START "|" D_CMND_MODBUS_TCP_CONNECT "|" D_CMND_MODBUS_SEND "|" D_CMND_MODBUS_SETBAUDRATE "|" D_CMND_MODBUS_SETSERIALCONFIG; + D_CMND_MODBUS_TCP_START "|" D_CMND_MODBUS_TCP_CONNECT "|" D_CMND_MODBUS_TCP_MQTT "|" D_CMND_MODBUS_SEND "|" D_CMND_MODBUS_SETBAUDRATE "|" D_CMND_MODBUS_SETSERIALCONFIG; void (*const ModbusBridgeCommand[])(void) PROGMEM = { - &CmndModbusTCPStart, &CmndModbusTCPConnect, + &CmndModbusTCPStart, &CmndModbusTCPConnect, &CmndModbusTCPMqtt, &CmndModbusBridgeSend, &CmndModbusBridgeSetBaudrate, &CmndModbusBridgeSetConfig}; struct ModbusBridgeTCP @@ -96,6 +98,7 @@ struct ModbusBridgeTCP uint8_t *tcp_buf = nullptr; // data transfer buffer IPAddress ip_filter; uint16_t tcp_transaction_id = 0; + bool output_mqtt = false; }; ModbusBridgeTCP modbusBridgeTCP; @@ -166,6 +169,7 @@ struct ModbusBridge uint8_t deviceAddress = 0; uint8_t count = 0; bool raw = false; + uint8_t *buffer = nullptr; }; ModbusBridge modbusBridge; @@ -204,6 +208,8 @@ bool ModbusBridgeBegin(void) } AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBR %s ser init at %d baud"), (2 == result ? "HW" : "SW"), Settings->modbus_sbaudrate * 300); } + modbusBridge.buffer = (uint8_t *)malloc(MBR_RECEIVE_BUFFER_SIZE); + return result; } @@ -241,16 +247,16 @@ void ModbusBridgeHandle(void) bool data_ready = modbusBridgeModbus->ReceiveReady(); if (data_ready) { - uint8_t *buffer; if (modbusBridge.byteCount == 0) modbusBridge.byteCount = modbusBridge.dataCount * 2; - buffer = (uint8_t *)malloc(9 + modbusBridge.byteCount); // Addres(1), Function(1), Length(1), Data(1..n), CRC(2) - if (nullptr == buffer) + if (nullptr == modbusBridge.buffer) { ModbusBridgeAllocError(PSTR("read")); + modbusBridge.dataCount = 0; + modbusBridge.byteCount = 0; return; } - memset(buffer, 0, 9 + modbusBridge.byteCount); - uint32_t error = modbusBridgeModbus->ReceiveBuffer(buffer, 0, modbusBridge.byteCount); + memset(modbusBridge.buffer, 0, MBR_RECEIVE_BUFFER_SIZE); + uint32_t error = modbusBridgeModbus->ReceiveBuffer(modbusBridge.buffer, 0, modbusBridge.byteCount); #ifdef USE_MODBUS_BRIDGE_TCP for (uint32_t i = 0; i < nitems(modbusBridgeTCP.client_tcp); i++) @@ -264,35 +270,35 @@ void ModbusBridgeHandle(void) header[1] = modbusBridgeTCP.tcp_transaction_id; header[2] = 0; header[3] = 0; - header[6] = buffer[0]; // Send slave address - header[7] = buffer[1]; // Send function code + header[6] = modbusBridge.buffer[0]; // Send slave address + header[7] = modbusBridge.buffer[1]; // Send function code if (error) { header[4] = 0; // Message Length Hi-Byte header[5] = 3; // Message Length Low-Byte - header[7] = buffer[1] | 0x80; // Send function code + header[7] = modbusBridge.buffer[1] | 0x80; // Send function code header[8] = error; nrOfBytes += 1; client.write(header, 9); } - else if (buffer[1] <= 2) + else if (modbusBridge.buffer[1] <= 2) { header[4] = modbusBridge.byteCount >> 8; header[5] = modbusBridge.byteCount + 3; header[8] = modbusBridge.byteCount; client.write(header, 9); nrOfBytes += 1; - client.write(buffer + 3, modbusBridge.byteCount); // Don't send CRC + client.write(modbusBridge.buffer + 3, modbusBridge.byteCount); // Don't send CRC nrOfBytes += modbusBridge.byteCount; } - else if (buffer[1] <= 4) + else if (modbusBridge.buffer[1] <= 4) { header[4] = modbusBridge.byteCount >> 8; header[5] = modbusBridge.byteCount + 3; header[8] = modbusBridge.byteCount; client.write(header, 9); nrOfBytes += 1; - client.write(buffer + 3, modbusBridge.byteCount); // Don't send CRC + client.write(modbusBridge.buffer + 3, modbusBridge.byteCount); // Don't send CRC nrOfBytes += modbusBridge.byteCount; } else @@ -300,57 +306,57 @@ void ModbusBridgeHandle(void) header[4] = 0; // Message Length Hi-Byte header[5] = 6; // Message Length Low-Byte client.write(header, 8); - client.write(buffer + 2, 4); // Don't send CRC + client.write(modbusBridge.buffer + 2, 4); // Don't send CRC nrOfBytes += 4; } client.flush(); - AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBRTCP from Modbus deviceAddress %d, writing %d bytes to client"), buffer[0], nrOfBytes); + AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBRTCP from Modbus deviceAddress %d, writing %d bytes to client"), modbusBridge.buffer[0], nrOfBytes); } } #endif + modbusBridge.byteCount = 0; + if (error) { AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBR Driver receive error %d"), error); - free(buffer); + modbusBridge.dataCount = 0; return; } - modbusBridge.byteCount = 0; ModbusBridgeError errorcode = ModbusBridgeError::noerror; if (modbusBridge.deviceAddress == 0) { #ifdef USE_MODBUS_BRIDGE_TCP // If tcp client connected don't log error and exit this function (do not process) - if (nitems(modbusBridgeTCP.client_tcp)) + if (nitems(modbusBridgeTCP.client_tcp) && !modbusBridgeTCP.output_mqtt) { - free(buffer); return; } #endif errorcode = ModbusBridgeError::nodataexpected; } - else if (modbusBridge.deviceAddress != (uint8_t)buffer[0]) + else if (modbusBridge.deviceAddress != (uint8_t)modbusBridge.buffer[0]) errorcode = ModbusBridgeError::wrongdeviceaddress; - else if ((uint8_t)modbusBridge.functionCode != (uint8_t)buffer[1]) + else if ((uint8_t)modbusBridge.functionCode != (uint8_t)modbusBridge.buffer[1]) errorcode = ModbusBridgeError::wrongfunctioncode; else if ((uint8_t)modbusBridge.functionCode < 5) { if ((uint8_t)modbusBridge.functionCode < 3) { - if ((uint8_t)(((modbusBridge.dataCount - 1) >> 3) + 1) != (uint8_t)buffer[2]) + if ((uint8_t)(((modbusBridge.dataCount - 1) >> 3) + 1) != (uint8_t)modbusBridge.buffer[2]) errorcode = ModbusBridgeError::wrongdataCount; } else { - if ((modbusBridge.type == ModbusBridgeType::mb_int8 || modbusBridge.type == ModbusBridgeType::mb_uint8) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)buffer[2])) + if ((modbusBridge.type == ModbusBridgeType::mb_int8 || modbusBridge.type == ModbusBridgeType::mb_uint8) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)modbusBridge.buffer[2])) errorcode = ModbusBridgeError::wrongdataCount; - else if ((modbusBridge.type == ModbusBridgeType::mb_bit) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)buffer[2])) + else if ((modbusBridge.type == ModbusBridgeType::mb_bit) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)modbusBridge.buffer[2])) errorcode = ModbusBridgeError::wrongdataCount; - else if ((modbusBridge.type == ModbusBridgeType::mb_int16 || modbusBridge.type == ModbusBridgeType::mb_uint16) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)buffer[2])) + else if ((modbusBridge.type == ModbusBridgeType::mb_int16 || modbusBridge.type == ModbusBridgeType::mb_uint16) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)modbusBridge.buffer[2])) errorcode = ModbusBridgeError::wrongdataCount; - else if ((modbusBridge.type == ModbusBridgeType::mb_int32 || modbusBridge.type == ModbusBridgeType::mb_uint32 || modbusBridge.type == ModbusBridgeType::mb_float) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)buffer[2])) + else if ((modbusBridge.type == ModbusBridgeType::mb_int32 || modbusBridge.type == ModbusBridgeType::mb_uint32 || modbusBridge.type == ModbusBridgeType::mb_float) && ((uint8_t)modbusBridge.dataCount * 2 != (uint8_t)modbusBridge.buffer[2])) errorcode = ModbusBridgeError::wrongdataCount; } } @@ -361,7 +367,7 @@ void ModbusBridgeHandle(void) Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{\"RAW\":[")); for (uint8_t i = 0; i < modbusBridgeModbus->ReceiveCount(); i++) { - ResponseAppend_P(PSTR("%d"), buffer[i]); + ResponseAppend_P(PSTR("%d"), modbusBridge.buffer[i]); if (i < modbusBridgeModbus->ReceiveCount() - 1) ResponseAppend_P(PSTR(",")); } @@ -374,7 +380,7 @@ void ModbusBridgeHandle(void) Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{\"HEX\":[")); for (uint8_t i = 0; i < modbusBridgeModbus->ReceiveCount(); i++) { - ResponseAppend_P(PSTR("0x%02X"), buffer[i]); + ResponseAppend_P(PSTR("0x%02X"), modbusBridge.buffer[i]); if (i < modbusBridgeModbus->ReceiveCount() - 1) ResponseAppend_P(PSTR(",")); } @@ -382,19 +388,19 @@ void ModbusBridgeHandle(void) ResponseJsonEnd(); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_MODBUS_RECEIVED)); } - else if ((buffer[1] > 0) && (buffer[1] < 7)) // Read Registers + else if ((modbusBridge.buffer[1] > 0) && (modbusBridge.buffer[1] < 7)) // Read Registers { uint8_t dataOffset = 3; Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{")); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_DEVICE_ADDRESS "\":%d,"), buffer[0]); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_FUNCTION_CODE "\":%d,"), buffer[1]); - if (buffer[1] < 5) + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_DEVICE_ADDRESS "\":%d,"), modbusBridge.buffer[0]); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_FUNCTION_CODE "\":%d,"), modbusBridge.buffer[1]); + if (modbusBridge.buffer[1] < 5) { ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), modbusBridge.startAddress); } else { - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (buffer[2] << 8) + buffer[3]); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (modbusBridge.buffer[2] << 8) + modbusBridge.buffer[3]); dataOffset = 4; } ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), modbusBridgeModbus->ReceiveCount()); @@ -418,24 +424,24 @@ void ModbusBridgeHandle(void) { // Convert next 4 bytes to float float value = 0; - if (buffer[1] < 3) + if (modbusBridge.buffer[1] < 3) { // In bit mode only convert returned bytes - if (buffer[2] - (count * 4)) - ((uint8_t *)&value)[0] = buffer[dataOffset + (count * 4)]; // Get float values - if ((buffer[2] - (count * 4)) >> 1) - ((uint8_t *)&value)[1] = buffer[dataOffset + 1 + (count * 4)]; - if ((buffer[2] - (count * 4) - 1) >> 1) - ((uint8_t *)&value)[2] = buffer[dataOffset + 2 + (count * 4)]; - if ((buffer[2] - (count * 4)) >> 2) - ((uint8_t *)&value)[3] = buffer[dataOffset + 3 + (count * 4)]; + if (modbusBridge.buffer[2] - (count * 4)) + ((uint8_t *)&value)[0] = modbusBridge.buffer[dataOffset + (count * 4)]; // Get float values + if ((modbusBridge.buffer[2] - (count * 4)) >> 1) + ((uint8_t *)&value)[1] = modbusBridge.buffer[dataOffset + 1 + (count * 4)]; + if ((modbusBridge.buffer[2] - (count * 4) - 1) >> 1) + ((uint8_t *)&value)[2] = modbusBridge.buffer[dataOffset + 2 + (count * 4)]; + if ((modbusBridge.buffer[2] - (count * 4)) >> 2) + ((uint8_t *)&value)[3] = modbusBridge.buffer[dataOffset + 3 + (count * 4)]; } else { - ((uint8_t *)&value)[3] = buffer[dataOffset + (count * 4)]; // Get float values - ((uint8_t *)&value)[2] = buffer[dataOffset + 1 + (count * 4)]; - ((uint8_t *)&value)[1] = buffer[dataOffset + 2 + (count * 4)]; - ((uint8_t *)&value)[0] = buffer[dataOffset + 3 + (count * 4)]; + ((uint8_t *)&value)[3] = modbusBridge.buffer[dataOffset + (count * 4)]; // Get float values + ((uint8_t *)&value)[2] = modbusBridge.buffer[dataOffset + 1 + (count * 4)]; + ((uint8_t *)&value)[1] = modbusBridge.buffer[dataOffset + 2 + (count * 4)]; + ((uint8_t *)&value)[0] = modbusBridge.buffer[dataOffset + 3 + (count * 4)]; } ext_snprintf_P(svalue, sizeof(svalue), "%*_f", 10, &value); } @@ -446,11 +452,11 @@ void ModbusBridgeHandle(void) if (bits_left < 8) { uint8_t bits_skip = 8 - bits_left; - value = (uint8_t)(buffer[dataOffset + ((count + bits_skip) >> 3)]); + value = (uint8_t)(modbusBridge.buffer[dataOffset + ((count + bits_skip) >> 3)]); } else { - value = (uint8_t)(buffer[dataOffset + (count >> 3)]); + value = (uint8_t)(modbusBridge.buffer[dataOffset + (count >> 3)]); } snprintf(svalue, MBR_MAX_VALUE_LENGTH, "%d", ((value >> (count & 7)) & 1)); } @@ -460,23 +466,23 @@ void ModbusBridgeHandle(void) (modbusBridge.type == ModbusBridgeType::mb_uint32)) { uint32_t value = 0; - if (buffer[1] < 3) + if (modbusBridge.buffer[1] < 3) { - if (buffer[2] - (count * 4)) - ((uint8_t *)&value)[0] = buffer[dataOffset + (count * 4)]; // Get uint values - if (buffer[2] - ((count * 4) - 1)) - ((uint8_t *)&value)[1] = buffer[dataOffset + 1 + (count * 4)]; - if (buffer[2] - ((count * 4) - 2)) - ((uint8_t *)&value)[2] = buffer[dataOffset + 2 + (count * 4)]; - if (buffer[2] - ((count * 4) - 3)) - ((uint8_t *)&value)[3] = buffer[dataOffset + 3 + (count * 4)]; + if (modbusBridge.buffer[2] - (count * 4)) + ((uint8_t *)&value)[0] = modbusBridge.buffer[dataOffset + (count * 4)]; // Get uint values + if (modbusBridge.buffer[2] - ((count * 4) - 1)) + ((uint8_t *)&value)[1] = modbusBridge.buffer[dataOffset + 1 + (count * 4)]; + if (modbusBridge.buffer[2] - ((count * 4) - 2)) + ((uint8_t *)&value)[2] = modbusBridge.buffer[dataOffset + 2 + (count * 4)]; + if (modbusBridge.buffer[2] - ((count * 4) - 3)) + ((uint8_t *)&value)[3] = modbusBridge.buffer[dataOffset + 3 + (count * 4)]; } else { - ((uint8_t *)&value)[3] = buffer[dataOffset + (count * 4)]; // Get uint values - ((uint8_t *)&value)[2] = buffer[dataOffset + 1 + (count * 4)]; - ((uint8_t *)&value)[1] = buffer[dataOffset + 2 + (count * 4)]; - ((uint8_t *)&value)[0] = buffer[dataOffset + 3 + (count * 4)]; + ((uint8_t *)&value)[3] = modbusBridge.buffer[dataOffset + (count * 4)]; // Get uint values + ((uint8_t *)&value)[2] = modbusBridge.buffer[dataOffset + 1 + (count * 4)]; + ((uint8_t *)&value)[1] = modbusBridge.buffer[dataOffset + 2 + (count * 4)]; + ((uint8_t *)&value)[0] = modbusBridge.buffer[dataOffset + 3 + (count * 4)]; } if (modbusBridge.type == ModbusBridgeType::mb_int32) snprintf(svalue, MBR_MAX_VALUE_LENGTH, "%d", value); @@ -487,17 +493,17 @@ void ModbusBridgeHandle(void) (modbusBridge.type == ModbusBridgeType::mb_uint16)) { uint16_t value = 0; - if (buffer[1] < 3) + if (modbusBridge.buffer[1] < 3) { - if (buffer[2] - (count * 2)) - ((uint8_t *)&value)[0] = buffer[dataOffset + (count * 2)]; - if (buffer[2] - ((count * 2) - 1)) - ((uint8_t *)&value)[1] = buffer[dataOffset + 1 + (count * 2)]; + if (modbusBridge.buffer[2] - (count * 2)) + ((uint8_t *)&value)[0] = modbusBridge.buffer[dataOffset + (count * 2)]; + if (modbusBridge.buffer[2] - ((count * 2) - 1)) + ((uint8_t *)&value)[1] = modbusBridge.buffer[dataOffset + 1 + (count * 2)]; } else { - ((uint8_t *)&value)[1] = buffer[dataOffset + (count * 2)]; - ((uint8_t *)&value)[0] = buffer[dataOffset + 1 + (count * 2)]; + ((uint8_t *)&value)[1] = modbusBridge.buffer[dataOffset + (count * 2)]; + ((uint8_t *)&value)[0] = modbusBridge.buffer[dataOffset + 1 + (count * 2)]; } if (modbusBridge.type == ModbusBridgeType::mb_int16) snprintf(svalue, MBR_MAX_VALUE_LENGTH, "%d", value); @@ -507,7 +513,7 @@ void ModbusBridgeHandle(void) else if ((modbusBridge.type == ModbusBridgeType::mb_int8) || (modbusBridge.type == ModbusBridgeType::mb_uint8)) { - uint8_t value = buffer[dataOffset + (count * 1)]; + uint8_t value = modbusBridge.buffer[dataOffset + (count * 1)]; if (modbusBridge.type == ModbusBridgeType::mb_int8) snprintf(svalue, MBR_MAX_VALUE_LENGTH, "%d", value); else @@ -525,14 +531,14 @@ void ModbusBridgeHandle(void) if (errorcode == ModbusBridgeError::noerror) MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_MODBUS_RECEIVED)); } - else if ((buffer[1] == 15) || (buffer[1] == 16)) // Write Multiple Registers + else if ((modbusBridge.buffer[1] == 15) || (modbusBridge.buffer[1] == 16)) // Write Multiple Registers { Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{")); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_DEVICE_ADDRESS "\":%d,"), buffer[0]); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_FUNCTION_CODE "\":%d,"), buffer[1]); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (buffer[2] << 8) + buffer[3]); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_DEVICE_ADDRESS "\":%d,"), modbusBridge.buffer[0]); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_FUNCTION_CODE "\":%d,"), modbusBridge.buffer[1]); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (modbusBridge.buffer[2] << 8) + modbusBridge.buffer[3]); ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), modbusBridgeModbus->ReceiveCount()); - ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_COUNT "\":%d"), (buffer[4] << 8) + buffer[5]); + ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_COUNT "\":%d"), (modbusBridge.buffer[4] << 8) + modbusBridge.buffer[5]); ResponseAppend_P(PSTR("}")); ResponseJsonEnd(); if (errorcode == ModbusBridgeError::noerror) @@ -546,7 +552,6 @@ void ModbusBridgeHandle(void) AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBR Recv Error %d"), (uint8_t)errorcode); } modbusBridge.deviceAddress = 0; - free(buffer); } } @@ -654,25 +659,28 @@ void ModbusTCPHandle(void) modbusBridgeTCP.tcp_transaction_id = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[0]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[1])); - if (mbfunctioncode <= 2) + if (mbfunctioncode <= 2) // Multiple Coils, Inputs { count = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[10]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[11])); modbusBridge.byteCount = ((count - 1) >> 3) + 1; - modbusBridge.dataCount = ((count - 1) >> 4) + 1; + modbusBridge.dataCount = count; + modbusBridge.type = ModbusBridgeType::mb_bit; } - else if (mbfunctioncode <= 4) + else if (mbfunctioncode <= 4) // Multiple Holding or input registers { count = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[10]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[11])); modbusBridge.byteCount = count * 2; modbusBridge.dataCount = count; + modbusBridge.type = ModbusBridgeType::mb_uint16; } - else + else // Write coil(s) or register(s) { // For functioncode 15 & 16 ignore bytecount, modbusBridgeModbus does calculate this uint8_t dataStartByte = mbfunctioncode <= 6 ? 10 : 13; uint16_t byteCount = (buf_len - dataStartByte); modbusBridge.byteCount = 2; modbusBridge.dataCount = 1; + modbusBridge.type = ModbusBridgeType::mb_uint16; writeData = (uint16_t *)malloc((byteCount / 2)+1); if (nullptr == writeData) @@ -702,6 +710,14 @@ void ModbusTCPHandle(void) modbusBridgeModbus->Send(mbdeviceaddress, mbfunctioncode, mbstartaddress, count, writeData); + if (modbusBridgeTCP.output_mqtt) + { + modbusBridge.deviceAddress = mbdeviceaddress; + modbusBridge.functionCode = (ModbusBridgeFunctionCode)mbfunctioncode; + modbusBridge.startAddress = mbstartaddress; + modbusBridge.count = count; + } + free(writeData); } } @@ -733,6 +749,8 @@ void CmndModbusBridgeSend(void) const char *stype = root.getStr(PSTR(D_JSON_MODBUS_TYPE), "uint8"); modbusBridge.count = root.getUInt(PSTR(D_JSON_MODBUS_COUNT), 1); // Number of bits or bytes to read / write + // If functioncode is 1, 2 or 15, the count is not the number of registers but the number + // of bit to read or write, so calculate the number data bytes to read/write. if ((functionCode == 1) || (functionCode == 2) || (functionCode == 15)) bitMode = true; if (modbusBridge.deviceAddress == 0) @@ -749,11 +767,11 @@ void CmndModbusBridgeSend(void) } modbusBridge.type = ModbusBridgeType::mb_undefined; + if (bitMode) modbusBridge.byteCount = (modbusBridge.count + 7) / 8; if (strcmp(stype, "int8") == 0) { modbusBridge.type = ModbusBridgeType::mb_int8; modbusBridge.dataCount = bitMode ? modbusBridge.count : ((modbusBridge.count - 1) / 2) + 1; - if (bitMode) modbusBridge.byteCount = (modbusBridge.count / 8) + 1; } else if (strcmp(stype, "int16") == 0) { @@ -803,13 +821,6 @@ void CmndModbusBridgeSend(void) else errorcode = ModbusBridgeError::wrongtype; - // If functioncode is 15, the count is not the number of registers but the number - // of bit to write, so calculate the number data bytes to write. - if (modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeMultipleCoils) - { - modbusBridge.dataCount = modbusBridge.count; - } - // Prevent buffer overflow due to usage of to many registers if ((!bitMode) && (modbusBridge.dataCount > MBR_MAX_REGISTERS)) errorcode = ModbusBridgeError::wrongcount; @@ -1113,6 +1124,12 @@ void CmndModbusTCPConnect(void) ResponseCmndDone(); } + +void CmndModbusTCPMqtt(void) +{ + modbusBridgeTCP.output_mqtt = XdrvMailbox.payload; + ResponseCmndDone(); +} #endif /*********************************************************************************************\ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino index 41dc91d10..e7d5f5a63 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_66_tm1638.ino @@ -163,22 +163,8 @@ void TmInit(void) { } digitalWrite(Tm1638.strobe_pin, HIGH); - // Dirty hack to offset TM1638 leds from GPIO relays - // At this time in code sequence the number of GPIO relays has not been established - uint32_t bi_device = 0; - uint32_t devices_present = 0; - for (uint32_t i = 0; i < MAX_RELAYS; i++) { - if (PinUsed(GPIO_REL1, i)) { - devices_present++; - if (bitRead(TasmotaGlobal.rel_bistable, i)) { - if (bi_device &1) { devices_present--; } - bi_device++; - } - } - } - - Tm1638.led_offset = devices_present; - TasmotaGlobal.devices_present += TM1638_MAX_LEDS; + Tm1638.led_offset = TasmotaGlobal.devices_present; + UpdateDevicesPresent(TM1638_MAX_LEDS); Tm1638.key_offset = -1; Tm1638.detected = true; } @@ -229,7 +215,7 @@ bool TmAddKey(void) { bool Xdrv66(uint32_t function) { bool result = false; - if (FUNC_MODULE_INIT == function) { + if (FUNC_SETUP_RING2 == function) { TmInit(); } else if (Tm1638.detected) { switch (function) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_67_mcp23xxx.ino b/tasmota/tasmota_xdrv_driver/xdrv_67_mcp23xxx.ino new file mode 100644 index 000000000..1186bf5db --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_67_mcp23xxx.ino @@ -0,0 +1,843 @@ +/* + xdrv_67_mcp23xxx.ino - MCP23008/MCP23017/MCP23S17 GPIO Expander support for Tasmota + + SPDX-FileCopyrightText: 2023 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#if defined(USE_I2C) || defined(USE_SPI) +#ifdef USE_MCP23XXX_DRV +/*********************************************************************************************\ + * MCP23008/17 (I2C) and MCP23S17 (SPI) GPIO Expander to be used as virtual button/switch/relay only + * + * Docs at https://www.microchip.com/wwwproducts/en/MCP23008 + * https://www.microchip.com/wwwproducts/en/MCP23017 + * + * I2C Address: 0x20 - 0x26 (0x27 is not supported) + * + * The goal of the driver is to provide a sequential list of pins configured as Tasmota template + * and handle any input and output as configured GPIOs. + * + * Restrictions: + * - Uses incremental I2C addresses / SPI Chip select until template pin count reached + * - Max support for 28 switches (input), 32 buttons (input), 32 relays (output) + * + * Supported template fields: + * NAME - Template name + * BASE - Optional. 0 = use relative buttons and switches (default), 1 = use absolute buttons and switches + * GPIO - Sequential list of pin 1 and up with configured GPIO function + * Function Code Description + * ------------------- -------- ---------------------------------------- + * None 0 Not used + * Button1..32 B 32..63 Button to Gnd with internal pullup + * Button_n1..32 Bn 64..95 Button to Gnd without internal pullup + * Button_i1..32 Bi 96..127 Button inverted to Vcc with internal pullup + * Button_in1..32 Bin 128..159 Button inverted to Vcc without internal pullup + * Switch1..28 S 160..187 Switch to Gnd with internal pullup + * Switch_n1..28 Sn 192..219 Switch to Gnd without internal pullup + * Relay1..32 R 224..255 Relay + * Relay_i1..32 Ri 256..287 Relay inverted + * Output_Hi Oh 3840 Fixed output high + * Output_lo Ol 3872 Fixed output low + * + * Prepare a template to be loaded either by: + * - a rule like: rule3 on file#mcp23x.dat do {"NAME":"MCP23017 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} endon + * - a script like: -y{"NAME":"MCP23017 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} + * - file called mcp23x.dat with contents: {"NAME":"MCP23017 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} + * + * S3 S2 B2 B3 Oh B1 S1 R1 R4 R2 R3 S4 + * {"NAME":"MCP23S17 Shelly Pro 4PM","GPIO":[194,193,65,66,3840,64,192,0,224,0,0,0,227,225,226,195]} + * + * Inverted relays and buttons Ri8 Ri7 Ri6 Ri5 Ri4 Ri3 Ri2 Ri1 B1 B2 B3 B4 B5 B6 B7 B8 + * {"NAME":"MCP23017 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} + * + * Inverted relays and buttons Ri1 Ri2 Ri3 Ri4 Ri5 Ri6 Ri7 Ri8 B1 B2 B3 B4 B5 B6 B7 B8 + * {"NAME":"MCP23017 A=Ri1-8, B=B1-8","GPIO":[256,257,258,259,260,261,262,263,32,33,34,35,36,37,38,39]} + * + * Relays and buttons R1 R2 R3 R4 R5 R6 R7 R8 B1 B2 B3 B4 B5 B6 B7 B8 + * {"NAME":"MCP23017 A=R1-8, B=B1-8","GPIO":[224,225,226,227,228,229,230,231,32,33,34,35,36,37,38,39]} + * + * Buttons and relays B1 B2 B3 B4 B5 B6 B7 B8 R1 R2 R3 R4 R5 R6 R7 R8 + * {"NAME":"MCP23017 A=B1-8, B=R1-8","GPIO":[32,33,34,35,36,37,38,39,224,225,226,227,228,229,230,231]} + * + * Buttons, relays, buttons and relays B1 B2 B3 B4 B5 B6 B7 B8 R1 R2 R3 R4 R5 R6 R7 R8 B9 B10B11B12B13B14B15B16R9 R10 R11 R12 R13 R14 R15 R16 + * {"NAME":"MCP23017 A=B1-8, B=R1-8, C=B9-16, D=R9-16","GPIO":[32,33,34,35,36,37,38,39,224,225,226,227,228,229,230,231,40,41,42,43,44,45,46,47,232,233,234,235,236,237,238,239]} + * + * {"NAME":"MCP23017 A=R1-8, B=B1-8, C=R9-16, D=B9-16","GPIO":[224,225,226,227,228,229,230,231,32,33,34,35,36,37,38,39,232,233,234,235,236,237,238,239,40,41,42,43,44,45,46,47]} + * + * 32 relays R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 R30 R31 R32 + * {"NAME":"MCP23017 A=Ri1-8, B=Ri9-16, C=Ri17-24, D=Ri25-32","GPIO":[256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287]} + * {"NAME":"MCP23017 A=R1-8, B=R9-16, C=R17-24, D=R25-32","GPIO":[224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]} + * +\*********************************************************************************************/ + +#define XDRV_67 67 +#define XI2C_77 77 // See I2CDEVICES.md + +#define MCP23XXX_ADDR_START 0x20 // 32 +#define MCP23XXX_ADDR_END 0x26 // 38 + +#define MCP23XXX_MAX_DEVICES 6 + +#define MCP23XXX_SPI_CLOCK 1000000 // SPI clock speed set to 1MHz in case of signal interference at higher speed (Max is 10MHz) + +/*********************************************************************************************\ + * MCP23017 support +\*********************************************************************************************/ + +enum MCP23S08GPIORegisters { + MCP23X08_IODIR = 0x00, + MCP23X08_IPOL = 0x01, + MCP23X08_GPINTEN = 0x02, + MCP23X08_DEFVAL = 0x03, + MCP23X08_INTCON = 0x04, + MCP23X08_IOCON = 0x05, + MCP23X08_GPPU = 0x06, + MCP23X08_INTF = 0x07, + MCP23X08_INTCAP = 0x08, + MCP23X08_GPIO = 0x09, + MCP23X08_OLAT = 0x0A, +}; + +enum MCP23X17GPIORegisters { + // A side + MCP23X17_IODIRA = 0x00, + MCP23X17_IPOLA = 0x02, + MCP23X17_GPINTENA = 0x04, + MCP23X17_DEFVALA = 0x06, + MCP23X17_INTCONA = 0x08, + MCP23X17_IOCONA = 0x0A, + MCP23X17_GPPUA = 0x0C, + MCP23X17_INTFA = 0x0E, + MCP23X17_INTCAPA = 0x10, + MCP23X17_GPIOA = 0x12, + MCP23X17_OLATA = 0x14, + // B side + MCP23X17_IODIRB = 0x01, + MCP23X17_IPOLB = 0x03, + MCP23X17_GPINTENB = 0x05, + MCP23X17_DEFVALB = 0x07, + MCP23X17_INTCONB = 0x09, + MCP23X17_IOCONB = 0x0B, + MCP23X17_GPPUB = 0x0D, + MCP23X17_INTFB = 0x0F, + MCP23X17_INTCAPB = 0x11, + MCP23X17_GPIOB = 0x13, + MCP23X17_OLATB = 0x15, +}; + +enum MCP23XInterruptMode { MCP23XXX_NO_INTERRUPT, MCP23XXX_CHANGE, MCP23XXX_RISING, MCP23XXX_FALLING }; + +enum MCP23XInterfaces { MCP23X_I2C, MCP23X_SPI }; + +typedef struct { + uint8_t olata; + uint8_t olatb; + uint8_t address; + uint8_t interface; + uint8_t pins; // 8 (MCP23008) or 16 (MCP23017 / MCP23S17) + int8_t pin_cs; + int8_t pin_int; +} tMcp23xDevice; + +struct MCP230 { + tMcp23xDevice device[MCP23XXX_MAX_DEVICES]; + uint32_t relay_inverted; + uint32_t button_inverted; + uint8_t chip; + uint8_t max_devices; + uint8_t max_pins; + uint8_t relay_max; + uint8_t relay_offset; + uint8_t button_max; + uint8_t switch_max; + int8_t button_offset; + int8_t switch_offset; + bool base; + bool interrupt; +} Mcp23x; + +uint16_t *Mcp23x_gpio_pin = nullptr; + +/*********************************************************************************************\ + * MCP23x17 - SPI and I2C +\*********************************************************************************************/ + +#ifdef USE_SPI +void MCP23xEnable(void) { + SPI.beginTransaction(SPISettings(MCP23XXX_SPI_CLOCK, MSBFIRST, SPI_MODE0)); + digitalWrite(Mcp23x.device[Mcp23x.chip].pin_cs, 0); +} + +void MCP23xDisable(void) { + SPI.endTransaction(); + digitalWrite(Mcp23x.device[Mcp23x.chip].pin_cs, 1); +} +#endif + +void MCP23xDumpRegs(void) { + uint8_t data[22]; + for (Mcp23x.chip = 0; Mcp23x.chip < Mcp23x.max_devices; Mcp23x.chip++) { + uint32_t data_size = sizeof(data); + if (8 == Mcp23x.device[Mcp23x.chip].pins) { data_size /= 2; } +#ifdef USE_SPI + if (MCP23X_SPI == Mcp23x.device[Mcp23x.chip].interface) { + MCP23xEnable(); + SPI.transfer(Mcp23x.device[Mcp23x.chip].address | 1); + SPI.transfer(0); + for (uint32_t i = 0; i < data_size; i++) { + data[i] = SPI.transfer(0xFF); + } + MCP23xDisable(); + } +#endif +#ifdef USE_I2C + if (MCP23X_I2C == Mcp23x.device[Mcp23x.chip].interface) { + I2cReadBuffer(Mcp23x.device[Mcp23x.chip].address, 0, data, data_size); + } +#endif + AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: Intf %d, Address %02X, Regs %*_H"), Mcp23x.device[Mcp23x.chip].interface, Mcp23x.device[Mcp23x.chip].address, data_size, data); + } +} + +uint32_t MCP23xRead16(uint8_t reg) { + // Read 16-bit registers: (regb << 8) | rega + uint32_t value = 0; +#ifdef USE_SPI + if (MCP23X_SPI == Mcp23x.device[Mcp23x.chip].interface) { + MCP23xEnable(); + SPI.transfer(Mcp23x.device[Mcp23x.chip].address | 1); + SPI.transfer(reg); + value = SPI.transfer(0xFF); // RegA + value |= (SPI.transfer(0xFF) << 8); // RegB + MCP23xDisable(); + } +#endif +#ifdef USE_I2C + if (MCP23X_I2C == Mcp23x.device[Mcp23x.chip].interface) { + value = I2cRead16LE(Mcp23x.device[Mcp23x.chip].address, reg); + } +#endif + return value; +} + +uint32_t MCP23xRead(uint8_t reg) { + uint32_t value = 0; +#ifdef USE_SPI + if (MCP23X_SPI == Mcp23x.device[Mcp23x.chip].interface) { + MCP23xEnable(); + SPI.transfer(Mcp23x.device[Mcp23x.chip].address | 1); + SPI.transfer(reg); + value = SPI.transfer(0xFF); + MCP23xDisable(); + } +#endif +#ifdef USE_I2C + if (MCP23X_I2C == Mcp23x.device[Mcp23x.chip].interface) { + value = I2cRead8(Mcp23x.device[Mcp23x.chip].address, reg); + } +#endif + return value; +} + +bool MCP23xValidRead(uint8_t reg, uint8_t *data) { +#ifdef USE_SPI + if (MCP23X_SPI == Mcp23x.device[Mcp23x.chip].interface) { + MCP23xEnable(); + SPI.transfer(Mcp23x.device[Mcp23x.chip].address | 1); + SPI.transfer(reg); + *data = SPI.transfer(0xFF); + MCP23xDisable(); + return true; + } +#endif +#ifdef USE_I2C + if (MCP23X_I2C == Mcp23x.device[Mcp23x.chip].interface) { + return I2cValidRead8(data, Mcp23x.device[Mcp23x.chip].address, reg); + } + return false; +#endif +} + +void MCP23xWrite(uint8_t reg, uint8_t value) { +#ifdef USE_SPI + if (MCP23X_SPI == Mcp23x.device[Mcp23x.chip].interface) { + MCP23xEnable(); + SPI.transfer(Mcp23x.device[Mcp23x.chip].address); + SPI.transfer(reg); + SPI.transfer(value); + MCP23xDisable(); + } +#endif +#ifdef USE_I2C + if (MCP23X_I2C == Mcp23x.device[Mcp23x.chip].interface) { + I2cWrite8(Mcp23x.device[Mcp23x.chip].address, reg, value); + } +#endif +} + +/*********************************************************************************************/ + +void MCP23xUpdate(uint8_t pin, bool pin_value, uint8_t reg_addr) { + // pin = 0 - 15 + uint8_t bit = pin % 8; + uint8_t reg_value = 0; + if (reg_addr == MCP23X17_OLATA) { + reg_value = Mcp23x.device[Mcp23x.chip].olata; + if (8 == Mcp23x.device[Mcp23x.chip].pins) { + reg_addr = MCP23X08_OLAT; + } + } else if (reg_addr == MCP23X17_OLATB) { + reg_value = Mcp23x.device[Mcp23x.chip].olatb; + } else { + reg_value = MCP23xRead(reg_addr); + } + if (pin_value) { + reg_value |= 1 << bit; + } else { + reg_value &= ~(1 << bit); + } + MCP23xWrite(reg_addr, reg_value); + if ((8 == Mcp23x.device[Mcp23x.chip].pins) && (reg_addr == MCP23X08_OLAT)) { + reg_addr = MCP23X17_OLATA; + } + if (reg_addr == MCP23X17_OLATA) { + Mcp23x.device[Mcp23x.chip].olata = reg_value; + } else if (reg_addr == MCP23X17_OLATB) { + Mcp23x.device[Mcp23x.chip].olatb = reg_value; + } +} + +/*********************************************************************************************/ + +uint32_t MCP23xSetChip(uint8_t pin) { + // Calculate chip based on number of pins per chip. 8 for MCP23008, 16 for MCP23x17 + // pin 0 - 63 + for (Mcp23x.chip = 0; Mcp23x.chip < Mcp23x.max_devices; Mcp23x.chip++) { + if (Mcp23x.device[Mcp23x.chip].pins > pin) { break; } + pin -= Mcp23x.device[Mcp23x.chip].pins; + } + return pin; // relative pin number within chip (0 ... 7 or 0 ... 15) +} + +void MCP23xPinMode(uint8_t pin, uint8_t flags) { + // pin 0 - 63 + pin = MCP23xSetChip(pin); + uint8_t iodir; + uint8_t gppu; + if (8 == Mcp23x.device[Mcp23x.chip].pins) { + iodir = MCP23X08_IODIR; + gppu = MCP23X08_GPPU; + } else { + iodir = pin < 8 ? MCP23X17_IODIRA : MCP23X17_IODIRB; + gppu = pin < 8 ? MCP23X17_GPPUA : MCP23X17_GPPUB; + } + switch (flags) { + case INPUT: + MCP23xUpdate(pin, true, iodir); + MCP23xUpdate(pin, false, gppu); + break; + case INPUT_PULLUP: + MCP23xUpdate(pin, true, iodir); + MCP23xUpdate(pin, true, gppu); + break; + case OUTPUT: + MCP23xUpdate(pin, false, iodir); + break; + } + +// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: MCP23xPinMode chip %d, pin %d, flags %d, regs %d,%d"), Mcp23x.chip, pin, flags, iodir, gppu); +} + +void MCP23xPinInterruptMode(uint8_t pin, uint8_t interrupt_mode) { + // pin 0 - 63 + pin = MCP23xSetChip(pin); + uint8_t gpinten; + uint8_t intcon; + uint8_t defval; + if (8 == Mcp23x.device[Mcp23x.chip].pins) { + gpinten = MCP23X08_GPINTEN; + intcon = MCP23X08_INTCON; + defval = MCP23X08_DEFVAL; + } else { + gpinten = pin < 8 ? MCP23X17_GPINTENA : MCP23X17_GPINTENB; + intcon = pin < 8 ? MCP23X17_INTCONA : MCP23X17_INTCONB; + defval = pin < 8 ? MCP23X17_DEFVALA : MCP23X17_DEFVALB; + } + switch (interrupt_mode) { + case MCP23XXX_CHANGE: + MCP23xUpdate(pin, true, gpinten); + MCP23xUpdate(pin, false, intcon); + break; + case MCP23XXX_RISING: + MCP23xUpdate(pin, true, gpinten); + MCP23xUpdate(pin, true, intcon); + MCP23xUpdate(pin, true, defval); + break; + case MCP23XXX_FALLING: + MCP23xUpdate(pin, true, gpinten); + MCP23xUpdate(pin, true, intcon); + MCP23xUpdate(pin, false, defval); + break; + case MCP23XXX_NO_INTERRUPT: + MCP23xUpdate(pin, false, gpinten); + break; + } +} + +void MCP23xSetPinModes(uint8_t pin, uint8_t flags) { + // pin 0 - 63 + MCP23xPinMode(pin, flags); + if (Mcp23x.device[Mcp23x.chip].pin_int > -1) { // Mcp23x.chip is updated by call to MCP23xPinMode + MCP23xPinInterruptMode(pin, MCP23XXX_CHANGE); + } +} + +bool MCP23xDigitalRead(uint8_t pin) { + // pin 0 - 63 + pin = MCP23xSetChip(pin); + uint8_t bit = pin % 8; + uint8_t reg_addr; + if (8 == Mcp23x.device[Mcp23x.chip].pins) { + reg_addr = MCP23X08_GPIO; + } else { + reg_addr = pin < 8 ? MCP23X17_GPIOA : MCP23X17_GPIOB; + } + uint8_t value = MCP23xRead(reg_addr); + return value & (1 << bit); +} + +void MCP23xDigitalWrite(uint8_t pin, bool value) { + // pin 0 - 63 + pin = MCP23xSetChip(pin); + uint8_t reg_addr = pin < 8 ? MCP23X17_OLATA : MCP23X17_OLATB; + +// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: MCP23xDigitalWrite chip %d, pin %d, state %d, reg %d"), Mcp23x.chip, pin, value, reg_addr); + + MCP23xUpdate(pin, value, reg_addr); +} + +/*********************************************************************************************\ + * Tasmota +\*********************************************************************************************/ + +int MCP23xPin(uint32_t gpio, uint32_t index = 0); +int MCP23xPin(uint32_t gpio, uint32_t index) { + uint16_t real_gpio = gpio << 5; + uint16_t mask = 0xFFE0; + if (index < GPIO_ANY) { + real_gpio += index; + mask = 0xFFFF; + } + for (uint32_t i = 0; i < Mcp23x.max_pins; i++) { + if ((Mcp23x_gpio_pin[i] & mask) == real_gpio) { + return i; // Pin number configured for gpio + } + } + return -1; // No pin used for gpio +} + +bool MCP23xPinUsed(uint32_t gpio, uint32_t index = 0); +bool MCP23xPinUsed(uint32_t gpio, uint32_t index) { + return (MCP23xPin(gpio, index) >= 0); +} + +uint32_t MCP23xGetPin(uint32_t lpin) { + if (lpin < Mcp23x.max_pins) { + return Mcp23x_gpio_pin[lpin]; + } else { + return GPIO_NONE; + } +} + +/*********************************************************************************************/ + +String MCP23xTemplateLoadFile(void) { + String mcptmplt = ""; +#ifdef USE_UFILESYS + mcptmplt = TfsLoadString("/mcp23x.dat"); +#endif // USE_UFILESYS +#ifdef USE_RULES + if (!mcptmplt.length()) { + mcptmplt = RuleLoadFile("MCP23X.DAT"); + } +#endif // USE_RULES +#ifdef USE_SCRIPT + if (!mcptmplt.length()) { + mcptmplt = ScriptLoadSection(">y"); + } +#endif // USE_SCRIPT + return mcptmplt; +} + +bool MCP23xLoadTemplate(void) { + String mcptmplt = MCP23xTemplateLoadFile(); + uint32_t len = mcptmplt.length() +1; + if (len < 7) { return false; } // No McpTmplt found + + JsonParser parser((char*)mcptmplt.c_str()); + JsonParserObject root = parser.getRootObject(); + if (!root) { return false; } + + // rule3 on file#mcp23x.dat do {"NAME":"MCP23017","GPIO":[32,33,34,35,36,37,38,39,224,225,226,227,228,229,230,231]} endon + // rule3 on file#mcp23x.dat do {"NAME":"MCP23017","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} endon + // rule3 on file#mcp23x.dat do {"NAME":"MCP23017 A=Ri8-1, B=B1-8","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39]} endon + // rule3 on file#mcp23x.dat do {"NAME":"MCP23017 A=Ri8-1, B=B1-8, C=Ri16-9, D=B9-16","GPIO":[263,262,261,260,259,258,257,256,32,33,34,35,36,37,38,39,271,270,269,268,267,266,265,264,40,41,42,43,44,45,46,47]} endon + + // {"NAME":"MCP23017","GPIO":[32,33,34,35,36,37,38,39,224,225,226,227,228,229,230,231]} + // {"NAME":"MCP23017","GPIO":[32,33,34,35,36,37,38,39,224,225,226,227,228,229,230,231,40,41,42,43,44,45,46,47,232,233,234,235,236,237,238,239]} + JsonParserToken val = root[PSTR(D_JSON_BASE)]; + if (val) { + Mcp23x.base = (val.getUInt()) ? true : false; + } + val = root[PSTR(D_JSON_NAME)]; + if (val) { + AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: Base %d, Template '%s'"), Mcp23x.base, val.getStr()); + } + JsonParserArray arr = root[PSTR(D_JSON_GPIO)]; + if (arr) { + uint32_t pin = 0; + for (pin; pin < Mcp23x.max_pins; pin++) { // Max number of detected chip pins + JsonParserToken val = arr[pin]; + if (!val) { break; } + uint16_t mpin = val.getUInt(); + if (mpin) { // Above GPIO_NONE + if ((mpin >= AGPIO(GPIO_SWT1)) && (mpin < (AGPIO(GPIO_SWT1) + MAX_SWITCHES_SET))) { + Mcp23x.switch_max++; + MCP23xSetPinModes(pin, INPUT_PULLUP); + } + else if ((mpin >= AGPIO(GPIO_SWT1_NP)) && (mpin < (AGPIO(GPIO_SWT1_NP) + MAX_SWITCHES_SET))) { + mpin -= (AGPIO(GPIO_SWT1_NP) - AGPIO(GPIO_SWT1)); + Mcp23x.switch_max++; + MCP23xSetPinModes(pin, INPUT); + } + else if ((mpin >= AGPIO(GPIO_KEY1)) && (mpin < (AGPIO(GPIO_KEY1) + MAX_KEYS_SET))) { + Mcp23x.button_max++; + MCP23xSetPinModes(pin, INPUT_PULLUP); + } + else if ((mpin >= AGPIO(GPIO_KEY1_NP)) && (mpin < (AGPIO(GPIO_KEY1_NP) + MAX_KEYS_SET))) { + mpin -= (AGPIO(GPIO_KEY1_NP) - AGPIO(GPIO_KEY1)); + Mcp23x.button_max++; + MCP23xSetPinModes(pin, INPUT); + } + else if ((mpin >= AGPIO(GPIO_KEY1_INV)) && (mpin < (AGPIO(GPIO_KEY1_INV) + MAX_KEYS_SET))) { + bitSet(Mcp23x.button_inverted, mpin - AGPIO(GPIO_KEY1_INV)); + mpin -= (AGPIO(GPIO_KEY1_INV) - AGPIO(GPIO_KEY1)); + Mcp23x.button_max++; + MCP23xSetPinModes(pin, INPUT_PULLUP); + } + else if ((mpin >= AGPIO(GPIO_KEY1_INV_NP)) && (mpin < (AGPIO(GPIO_KEY1_INV_NP) + MAX_KEYS_SET))) { + bitSet(Mcp23x.button_inverted, mpin - AGPIO(GPIO_KEY1_INV_NP)); + mpin -= (AGPIO(GPIO_KEY1_INV_NP) - AGPIO(GPIO_KEY1)); + Mcp23x.button_max++; + MCP23xSetPinModes(pin, INPUT); + } + else if ((mpin >= AGPIO(GPIO_REL1)) && (mpin < (AGPIO(GPIO_REL1) + MAX_RELAYS_SET))) { + Mcp23x.relay_max++; + MCP23xPinMode(pin, OUTPUT); + } + else if ((mpin >= AGPIO(GPIO_REL1_INV)) && (mpin < (AGPIO(GPIO_REL1_INV) + MAX_RELAYS_SET))) { + bitSet(Mcp23x.relay_inverted, mpin - AGPIO(GPIO_REL1_INV)); + mpin -= (AGPIO(GPIO_REL1_INV) - AGPIO(GPIO_REL1)); + Mcp23x.relay_max++; + MCP23xPinMode(pin, OUTPUT); + } + else if (mpin == AGPIO(GPIO_OUTPUT_HI)) { + MCP23xPinMode(pin, OUTPUT); + MCP23xDigitalWrite(pin, 1); + } + else if (mpin == AGPIO(GPIO_OUTPUT_LO)) { + MCP23xPinMode(pin, OUTPUT); + MCP23xDigitalWrite(pin, 0); + } + else { mpin = 0; } + Mcp23x_gpio_pin[pin] = mpin; + } + if ((Mcp23x.switch_max >= MAX_SWITCHES_SET) || + (Mcp23x.button_max >= MAX_KEYS_SET) || + (Mcp23x.relay_max >= MAX_RELAYS_SET)) { + AddLog(LOG_LEVEL_INFO, PSTR("MCP: Max reached (S%d/B%d/R%d)"), Mcp23x.switch_max, Mcp23x.button_max, Mcp23x.relay_max); + break; + } + } + Mcp23x.max_pins = pin; // Max number of configured pins + } + +// AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: Pins %d, Mcp23x_gpio_pin %*_V"), Mcp23x.max_pins, Mcp23x.max_pins, (uint8_t*)Mcp23x_gpio_pin); + + return true; +} + +uint32_t MCP23xTemplateGpio(void) { + String mcptmplt = MCP23xTemplateLoadFile(); + uint32_t len = mcptmplt.length() +1; + if (len < 7) { return 0; } // No McpTmplt found + + JsonParser parser((char*)mcptmplt.c_str()); + JsonParserObject root = parser.getRootObject(); + if (!root) { return 0; } + + JsonParserArray arr = root[PSTR(D_JSON_GPIO)]; + if (arr.isArray()) { + return arr.size(); // Number of requested pins + } + return 0; +} + +void MCP23xModuleInit(void) { + int32_t pins_needed = MCP23xTemplateGpio(); + if (!pins_needed) { + AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: Invalid template")); + return; + } + +#ifdef USE_SPI + if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && PinUsed(GPIO_MCP23SXX_CS, GPIO_ANY)) { +#ifdef ESP8266 + SPI.begin(); +#endif +#ifdef ESP32 + SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); +#endif + while ((Mcp23x.max_devices < MCP23XXX_MAX_DEVICES) && PinUsed(GPIO_MCP23SXX_CS, Mcp23x.max_devices)) { + Mcp23x.chip = Mcp23x.max_devices; + Mcp23x.device[Mcp23x.chip].pin_int = (PinUsed(GPIO_MCP23XXX_INT, Mcp23x.chip)) ? Pin(GPIO_MCP23XXX_INT, Mcp23x.chip) : -1; + Mcp23x.device[Mcp23x.chip].pin_cs = Pin(GPIO_MCP23SXX_CS, Mcp23x.max_devices); + digitalWrite(Mcp23x.device[Mcp23x.chip].pin_cs, 1); + pinMode(Mcp23x.device[Mcp23x.chip].pin_cs, OUTPUT); + Mcp23x.device[Mcp23x.chip].interface = MCP23X_SPI; + Mcp23x.device[Mcp23x.chip].address = MCP23XXX_ADDR_START << 1; + AddLog(LOG_LEVEL_INFO, PSTR("SPI: MCP23S17 found at CS%d"), Mcp23x.chip +1); + Mcp23x.device[Mcp23x.chip].pins = 16; + MCP23xWrite(MCP23X17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing + Mcp23x.device[Mcp23x.chip].olata = MCP23xRead(MCP23X17_OLATA); + Mcp23x.device[Mcp23x.chip].olatb = MCP23xRead(MCP23X17_OLATB); + Mcp23x.max_devices++; + + Mcp23x.max_pins += Mcp23x.device[Mcp23x.chip].pins; + pins_needed -= Mcp23x.device[Mcp23x.chip].pins; + if (!pins_needed) { break; } + } + } else { +#endif // USE_SPI +#ifdef USE_I2C + uint8_t mcp23xxx_address = MCP23XXX_ADDR_START; + while ((Mcp23x.max_devices < MCP23XXX_MAX_DEVICES) && (mcp23xxx_address < MCP23XXX_ADDR_END)) { + Mcp23x.chip = Mcp23x.max_devices; + if (I2cSetDevice(mcp23xxx_address)) { + Mcp23x.device[Mcp23x.chip].pin_int = (PinUsed(GPIO_MCP23XXX_INT, Mcp23x.chip)) ? Pin(GPIO_MCP23XXX_INT, Mcp23x.chip) : -1; + Mcp23x.device[Mcp23x.chip].interface = MCP23X_I2C; + Mcp23x.device[Mcp23x.chip].address = mcp23xxx_address; + + MCP23xWrite(MCP23X08_IOCON, 0x80); // Attempt to set bank mode - this will only work on MCP23017, so its the best way to detect the different chips 23008 vs 23017 + uint8_t buffer; + if (MCP23xValidRead(MCP23X08_IOCON, &buffer)) { + if (0x00 == buffer) { + I2cSetActiveFound(mcp23xxx_address, "MCP23008"); + Mcp23x.device[Mcp23x.chip].pins = 8; + MCP23xWrite(MCP23X08_IOCON, 0b00011000); // Slew rate disabled, HAEN pins for addressing + Mcp23x.device[Mcp23x.chip].olata = MCP23xRead(MCP23X08_OLAT); + Mcp23x.max_devices++; + } + else if (0x80 == buffer) { + I2cSetActiveFound(mcp23xxx_address, "MCP23017"); + Mcp23x.device[Mcp23x.chip].pins = 16; + MCP23xWrite(MCP23X08_IOCON, 0x00); // Reset bank mode to 0 (MCP23X17_GPINTENB) + MCP23xWrite(MCP23X17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing + Mcp23x.device[Mcp23x.chip].olata = MCP23xRead(MCP23X17_OLATA); + Mcp23x.device[Mcp23x.chip].olatb = MCP23xRead(MCP23X17_OLATB); + Mcp23x.max_devices++; + } + Mcp23x.max_pins += Mcp23x.device[Mcp23x.chip].pins; + pins_needed -= Mcp23x.device[Mcp23x.chip].pins; + } + } + if (pins_needed) { + mcp23xxx_address++; + } else { + mcp23xxx_address = MCP23XXX_ADDR_END; + } + } +#endif // USE_I2C +#ifdef USE_SPI + } +#endif // USE_SPI + + if (!Mcp23x.max_devices) { return; } + + Mcp23x_gpio_pin = (uint16_t*)calloc(Mcp23x.max_pins, 2); + if (!Mcp23x_gpio_pin) { return; } + + if (!MCP23xLoadTemplate()) { + AddLog(LOG_LEVEL_INFO, PSTR("MCP: No valid template found")); // Too many GPIO's + Mcp23x.max_devices = 0; + return; + } + + Mcp23x.relay_offset = TasmotaGlobal.devices_present; + Mcp23x.relay_max -= UpdateDevicesPresent(Mcp23x.relay_max); + + Mcp23x.button_offset = -1; + Mcp23x.switch_offset = -1; +} + +void MCP23xServiceInput(void) { + // I found no reliable way to receive interrupts; noise received at undefined moments - unstable usage + Mcp23x.interrupt = false; + // This works with no interrupt + uint32_t pin_offset = 0; + uint32_t gpio; + for (Mcp23x.chip = 0; Mcp23x.chip < Mcp23x.max_devices; Mcp23x.chip++) { + if (8 == Mcp23x.device[Mcp23x.chip].pins) { + gpio = MCP23xRead(MCP23X08_GPIO); // Read MCP23008 gpio + } else { + gpio = MCP23xRead16(MCP23X17_GPIOA); // Read MCP23x17 gpio + } + +// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MCP: Chip %d, State %04X"), Mcp23x.chip, gpio); + + uint32_t mask = 1; + for (uint32_t pin = 0; pin < Mcp23x.device[Mcp23x.chip].pins; pin++) { + uint32_t state = ((gpio & mask) != 0); + uint32_t lpin = MCP23xGetPin(pin_offset + pin); // 0 for None, 32 for KEY1, 160 for SWT1, 224 for REL1 + uint32_t index = lpin & 0x001F; // Max 32 buttons or switches + lpin = BGPIO(lpin); // UserSelectablePins number + if (GPIO_KEY1 == lpin) { + ButtonSetVirtualPinState(Mcp23x.button_offset + index, (state != bitRead(Mcp23x.button_inverted, index))); + } + else if (GPIO_SWT1 == lpin) { + SwitchSetVirtualPinState(Mcp23x.switch_offset + index, state); + } + mask <<= 1; + } + pin_offset += Mcp23x.device[Mcp23x.chip].pins; + } +} + +static void IRAM_ATTR MCP23xInputIsr(void) { + Mcp23x.interrupt = true; +} + +void MCP23xInit(void) { + if (Mcp23x.button_max || Mcp23x.switch_max) { + uint32_t gpio; + for (Mcp23x.chip = 0; Mcp23x.chip < Mcp23x.max_devices; Mcp23x.chip++) { + if (Mcp23x.device[Mcp23x.chip].pin_int > -1) { + if (8 == Mcp23x.device[Mcp23x.chip].pins) { + gpio = MCP23xRead(MCP23X08_GPIO); // Clear MCP23008 interrupt + } else { + gpio = MCP23xRead16(MCP23X17_GPIOA); // Clear MCP23x17 interrupt + } + pinMode(Mcp23x.device[Mcp23x.chip].pin_int, INPUT_PULLUP); + attachInterrupt(Mcp23x.device[Mcp23x.chip].pin_int, MCP23xInputIsr, CHANGE); + } + } + } +} + +void MCP23xPower(void) { + // XdrvMailbox.index = 32-bit rpower bit mask + // Use absolute relay indexes unique with main template + power_t rpower = XdrvMailbox.index; + uint32_t relay_max = TasmotaGlobal.devices_present; + if (!Mcp23x.base) { + // Use relative and sequential relay indexes + rpower >>= Mcp23x.relay_offset; + relay_max = Mcp23x.relay_max; + } + for (uint32_t index = 0; index < relay_max; index++) { + power_t state = rpower &1; + if (MCP23xPinUsed(GPIO_REL1, index)) { + uint32_t pin = MCP23xPin(GPIO_REL1, index) & 0x3F; // Fix possible overflow over 63 gpios + MCP23xDigitalWrite(pin, bitRead(Mcp23x.relay_inverted, index) ? !state : state); + } + rpower >>= 1; // Select next power + } +} + +bool MCP23xAddButton(void) { + // XdrvMailbox.index = button/switch index + uint32_t index = XdrvMailbox.index; + if (!Mcp23x.base) { + // Use relative and sequential button indexes + if (Mcp23x.button_offset < 0) { Mcp23x.button_offset = index; } + index -= Mcp23x.button_offset; + if (index >= Mcp23x.button_max) { return false; } + } else { + // Use absolute button indexes unique with main template + if (!MCP23xPinUsed(GPIO_KEY1, index)) { return false; } + Mcp23x.button_offset = 0; + } + XdrvMailbox.index = (MCP23xDigitalRead(MCP23xPin(GPIO_KEY1, index)) != bitRead(Mcp23x.button_inverted, index)); + return true; +} + +bool MCP23xAddSwitch(void) { + // XdrvMailbox.index = button/switch index + uint32_t index = XdrvMailbox.index; + if (!Mcp23x.base) { + // Use relative and sequential switch indexes + if (Mcp23x.switch_offset < 0) { Mcp23x.switch_offset = index; } + index -= Mcp23x.switch_offset; + if (index >= Mcp23x.switch_max) { return false; } + } else { + // Use absolute switch indexes unique with main template + if (!MCP23xPinUsed(GPIO_SWT1, index)) { return false; } + Mcp23x.switch_offset = 0; + } + XdrvMailbox.index = MCP23xDigitalRead(MCP23xPin(GPIO_SWT1, index)); + return true; +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv67(uint32_t function) { + bool spi_enabled = false; + bool i2c_enabled = false; +#ifdef USE_SPI + spi_enabled = (SPI_MOSI_MISO == TasmotaGlobal.spi_enabled); +#endif // USE_SPI +#ifdef USE_I2C + i2c_enabled = I2cEnabled(XI2C_77); +#endif // USE_I2C + if (!spi_enabled && !i2c_enabled) { return false; } + + bool result = false; + + if (FUNC_SETUP_RING2 == function) { + MCP23xModuleInit(); + } else if (Mcp23x.max_devices) { + switch (function) { + case FUNC_LOOP: + case FUNC_SLEEP_LOOP: + if (!Mcp23x.interrupt) { return false; } + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MCP: Interrupt")); + MCP23xServiceInput(); + break; + case FUNC_EVERY_100_MSECOND: + if (Mcp23x.button_max || Mcp23x.switch_max) { + MCP23xServiceInput(); + } + break; + case FUNC_SET_POWER: + MCP23xPower(); + break; + case FUNC_INIT: + MCP23xInit(); + break; + case FUNC_ADD_BUTTON: + result = MCP23xAddButton(); + break; + case FUNC_ADD_SWITCH: + result = MCP23xAddSwitch(); + break; + } + } + return result; +} + +#endif // USE_MCP23XXX_DRV +#endif // USE_I2C or USE_ESP_SPI diff --git a/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino b/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino index fabcf916e..6f9089e1f 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino @@ -204,7 +204,7 @@ namespace BLE_ESP32 { ///////////////////////////////////////////////////// #define BLE_ESP32_MAXNAMELEN 32 -#define BLE_ESP32_MAXALIASLEN 20 +#define BLE_ESP32_MAXALIASLEN 32 #define MAX_BLE_DATA_LEN 100 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino b/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino index 058f83813..5a3134762 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino @@ -310,7 +310,7 @@ TSspm *Sspm = nullptr; const uint32_t XDRV_86_VERSION = 0x0104; // Latest driver version (See settings deltas below) -void Xdrv86SettingsLoad(void) { +void Xdrv86SettingsLoad(bool erase) { // *** Start init default values in case file is not found *** memset(&Sspm->Settings, 0x00, sizeof(tSspmSettings)); Sspm->Settings.version = XDRV_86_VERSION; @@ -326,7 +326,10 @@ void Xdrv86SettingsLoad(void) { char filename[20]; // Use for drivers: snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_86); - if (TfsLoadFile(filename, (uint8_t*)&Sspm->Settings, sizeof(tSspmSettings))) { + if (erase) { + TfsDeleteFile(filename); // Use defaults + } + else if (TfsLoadFile(filename, (uint8_t*)&Sspm->Settings, sizeof(tSspmSettings))) { if (Sspm->Settings.version != XDRV_86_VERSION) { // Fix version dependent changes // *** Start fix possible setting deltas *** @@ -341,7 +344,8 @@ void Xdrv86SettingsLoad(void) { Xdrv86SettingsSave(); } AddLog(LOG_LEVEL_INFO, PSTR("CFG: XDRV86 loaded from file")); - } else { + } + else { // File system not ready: No flash space reserved for file system AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV86 Use defaults as file system not ready or file not found")); } @@ -1195,7 +1199,7 @@ void SSPMHandleReceivedData(void) { TasmotaGlobal.power |= current_state; Sspm->old_power = TasmotaGlobal.power; - TasmotaGlobal.devices_present += 4; + UpdateDevicesPresent(4); } SSPMSendGetOps(Sspm->module_selected -1); break; @@ -1907,7 +1911,7 @@ void SSPMInit(void) { return; } - Xdrv86SettingsLoad(); + Xdrv86SettingsLoad(0); pinMode(SSPM_GPIO_ARM_RESET, OUTPUT); digitalWrite(SSPM_GPIO_ARM_RESET, 1); @@ -2296,14 +2300,12 @@ void SSPMEnergyShow(bool json) { WSContentSend_PD(HTTP_SNS_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[0], Settings->flag2.voltage_resolution, indirect, offset, count)); WSContentSend_PD(HTTP_SNS_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[0], Settings->flag2.current_resolution, indirect, offset, count)); WSContentSend_PD(HTTP_SNS_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); - char valu2_chr[SSPM_SIZE]; - char valu3_chr[SSPM_SIZE]; - WSContentSend_PD(HTTP_ENERGY_SNS1, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count), - SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count), - SSPMEnergyFormat(valu3_chr, Sspm->power_factor[0], 2, indirect, offset, count)); - WSContentSend_PD(HTTP_ENERGY_SNS2, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count), - SSPMEnergyFormat(valu2_chr, Sspm->Settings.energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count), - SSPMEnergyFormat(valu3_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SNS_POWERUSAGE_APPARENT, SSPMEnergyFormat(value_chr, Sspm->apparent_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SNS_POWERUSAGE_REACTIVE, SSPMEnergyFormat(value_chr, Sspm->reactive_power[0], Settings->flag2.wattage_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SNS_POWER_FACTOR, SSPMEnergyFormat(value_chr, Sspm->power_factor[0], 2, indirect, offset, count)); + WSContentSend_PD(HTTP_SNS_ENERGY_TODAY, SSPMEnergyFormat(value_chr, Sspm->energy_today[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SNS_ENERGY_YESTERDAY, SSPMEnergyFormat(value_chr, Sspm->Settings.energy_yesterday[0], Settings->flag2.energy_resolution, indirect, offset, count)); + WSContentSend_PD(HTTP_SNS_ENERGY_TOTAL, SSPMEnergyFormat(value_chr, Sspm->energy_total[0], Settings->flag2.energy_resolution, indirect, offset, count)); WSContentSend_P(PSTR("
{t}")); // {t} = - Define for next FUNC_WEB_SENSOR } #endif // USE_WEBSERVER @@ -2645,6 +2647,9 @@ bool Xdrv86(uint32_t function) { case FUNC_EVERY_100_MSECOND: SSPMEvery100ms(); break; + case FUNC_RESET_SETTINGS: + Xdrv86SettingsLoad(1); + break; case FUNC_SAVE_SETTINGS: Xdrv86SettingsSave(); break; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino index 51fd818ad..090dfaa90 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino @@ -99,7 +99,7 @@ tXdrv87Settings Xdrv87Settings; /*********************************************************************************************/ -void Xdrv87SettingsLoad(void) { +void Xdrv87SettingsLoad(bool erase) { // *** Start init default values in case file is not found *** memset(&Xdrv87Settings, 0x00, sizeof(tXdrv87Settings)); Xdrv87Settings.version = XDRV_87_VERSION; @@ -115,7 +115,10 @@ void Xdrv87SettingsLoad(void) { char filename[20]; // Use for drivers: snprintf_P(filename, sizeof(filename), PSTR(TASM_FILE_DRIVER), XDRV_87); - if (TfsLoadFile(filename, (uint8_t*)&Xdrv87Settings, sizeof(tXdrv87Settings))) { + if (erase) { + TfsDeleteFile(filename); // Use defaults + } + else if (TfsLoadFile(filename, (uint8_t*)&Xdrv87Settings, sizeof(tXdrv87Settings))) { if (Xdrv87Settings.version != XDRV_87_VERSION) { // Fix version dependent changes // *** Start fix possible setting deltas *** @@ -130,7 +133,8 @@ void Xdrv87SettingsLoad(void) { Xdrv87SettingsSave(); } AddLog(LOG_LEVEL_INFO, PSTR("CFG: XDRV87 loaded from file")); - } else { + } + else { // File system not ready: No flash space reserved for file system AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: XDRV87 Use defaults as file system not ready or file not found")); } @@ -298,7 +302,7 @@ void TM1621PreInit(void) { pinMode(Tm1621.pin_wr, OUTPUT); digitalWrite(Tm1621.pin_wr, 1); - Xdrv87SettingsLoad(); + Xdrv87SettingsLoad(0); Tm1621.state = 200; @@ -578,6 +582,9 @@ bool Xdrv87(uint32_t function) { case FUNC_EVERY_SECOND: TM1621EverySecond(); break; + case FUNC_RESET_SETTINGS: + Xdrv87SettingsLoad(1); + break; case FUNC_SAVE_SETTINGS: Xdrv87SettingsSave(); break; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino index 16dd8db3e..db7671733 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino @@ -19,6 +19,7 @@ #ifdef ESP32 #ifdef USE_SPI +#ifdef USE_MCP23XXX_DRV #ifdef USE_SHELLY_PRO /*********************************************************************************************\ * Shelly Pro support @@ -27,7 +28,7 @@ * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} - * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,10272,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,10240,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;rule3 on file#mcp23x.dat do {\"NAME\":\"MCP23S17 Shelly Pro 4PM\",\"GPIO\":[194,193,65,66,3840,64,192,0,224,0,0,0,227,225,226,195]} endon"} * * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring * Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display @@ -37,9 +38,6 @@ #define XDRV_88 88 #define SHELLY_PRO_PIN_LAN8720_RESET 5 -#define SHELLY_PRO_4_PIN_SPI_CS 16 -#define SHELLY_PRO_4_PIN_MCP23S17_INT 35 -#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40 struct SPro { uint32_t last_update; @@ -47,146 +45,16 @@ struct SPro { int8_t switch_offset; int8_t button_offset; uint8_t pin_register_cs; - uint8_t pin_mcp23s17_int; uint8_t ledlink; uint8_t power; bool init_done; uint8_t detected; } SPro; -/*********************************************************************************************\ - * Shelly Pro MCP23S17 support -\*********************************************************************************************/ - -enum SP4MCP23X17GPIORegisters { - // A side - SP4_MCP23S17_IODIRA = 0x00, - SP4_MCP23S17_IPOLA = 0x02, - SP4_MCP23S17_GPINTENA = 0x04, - SP4_MCP23S17_DEFVALA = 0x06, - SP4_MCP23S17_INTCONA = 0x08, - SP4_MCP23S17_IOCONA = 0x0A, - SP4_MCP23S17_GPPUA = 0x0C, - SP4_MCP23S17_INTFA = 0x0E, - SP4_MCP23S17_INTCAPA = 0x10, - SP4_MCP23S17_GPIOA = 0x12, - SP4_MCP23S17_OLATA = 0x14, - // B side - SP4_MCP23S17_IODIRB = 0x01, - SP4_MCP23S17_IPOLB = 0x03, - SP4_MCP23S17_GPINTENB = 0x05, - SP4_MCP23S17_DEFVALB = 0x07, - SP4_MCP23S17_INTCONB = 0x09, - SP4_MCP23S17_IOCONB = 0x0B, - SP4_MCP23S17_GPPUB = 0x0D, - SP4_MCP23S17_INTFB = 0x0F, - SP4_MCP23S17_INTCAPB = 0x11, - SP4_MCP23S17_GPIOB = 0x13, - SP4_MCP23S17_OLATB = 0x15, -}; - -uint8_t sp4_mcp23s17_olata = 0; -uint8_t sp4_mcp23s17_olatb = 0; - -bool sp4_spi_busy; - -void SP4Mcp23S17Enable(void) { - sp4_spi_busy = true; - SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); - digitalWrite(SPro.pin_register_cs, 0); -} - -void SP4Mcp23S17Disable(void) { - SPI.endTransaction(); - digitalWrite(SPro.pin_register_cs, 1); - sp4_spi_busy = false; -} - -uint32_t SP4Mcp23S17Read16(uint8_t reg) { - // Read 16-bit registers: (regb << 8) | rega - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); - SPI.transfer(reg); - uint32_t value = SPI.transfer(0xFF); // RegA - value |= (SPI.transfer(0xFF) << 8); // RegB - SP4Mcp23S17Disable(); - return value; -} - -uint32_t SP4Mcp23S17Read(uint8_t reg) { - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); - SPI.transfer(reg); - uint32_t value = SPI.transfer(0xFF); - SP4Mcp23S17Disable(); - return value; -} - -void SP4Mcp23S17Write(uint8_t reg, uint8_t value) { - SP4Mcp23S17Enable(); - SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS); - SPI.transfer(reg); - SPI.transfer(value); - SP4Mcp23S17Disable(); -} - -void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { - uint8_t bit = pin % 8; - uint8_t reg_value = 0; - if (reg_addr == SP4_MCP23S17_OLATA) { - reg_value = sp4_mcp23s17_olata; - } else if (reg_addr == SP4_MCP23S17_OLATB) { - reg_value = sp4_mcp23s17_olatb; - } else { - reg_value = SP4Mcp23S17Read(reg_addr); - } - if (pin_value) { - reg_value |= 1 << bit; - } else { - reg_value &= ~(1 << bit); - } - SP4Mcp23S17Write(reg_addr, reg_value); - if (reg_addr == SP4_MCP23S17_OLATA) { - sp4_mcp23s17_olata = reg_value; - } else if (reg_addr == SP4_MCP23S17_OLATB) { - sp4_mcp23s17_olatb = reg_value; - } -} - -void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { - uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; - uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; - if (flags == INPUT) { - SP4Mcp23S17Update(pin, true, iodir); - SP4Mcp23S17Update(pin, false, gppu); - } else if (flags == (INPUT | PULLUP)) { - SP4Mcp23S17Update(pin, true, iodir); - SP4Mcp23S17Update(pin, true, gppu); - } else if (flags == OUTPUT) { - SP4Mcp23S17Update(pin, false, iodir); - } -} - -bool SP4Mcp23S17DigitalRead(uint8_t pin) { - uint8_t bit = pin % 8; - uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB; - uint8_t value = SP4Mcp23S17Read(reg_addr); - return value & (1 << bit); -} - -void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) { - uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB; - SP4Mcp23S17Update(pin, value, reg_addr); -} - /*********************************************************************************************\ * Shelly Pro 4 \*********************************************************************************************/ -const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 }; -const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 }; -const uint8_t sp4_button_pin[] = { 5, 2, 3 }; - void ShellyPro4Init(void) { /* Shelly Pro 4PM MCP23S17 registers @@ -207,97 +75,13 @@ void ShellyPro4Init(void) { bit 14 = output - Relay O3 bit 15 = input, inverted - Switch4 */ - SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing - SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change - SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change - - // Read current output register state - sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA); - sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB); - - SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 - SP4Mcp23S17DigitalWrite(4, 1); - - for (uint32_t i = 0; i < 3; i++) { - SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C) - } - SPro.button_offset = -1; - - for (uint32_t i = 0; i < 4; i++) { - SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 - SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4 - } - SPro.switch_offset = -1; - - // Read current input register state - SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt - attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE); } void ShellyPro4Reset(void) { - SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953 + MCP23xPinMode(4, OUTPUT); // Safeguard as also performed by MCP23x.dat template as Output_Hi + MCP23xDigitalWrite(4, 0); // Reset pin display, ADE7953 delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs. - SP4Mcp23S17DigitalWrite(4, 1); -} - -bool ShellyProAddButton(void) { - if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 - if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } - uint32_t index = XdrvMailbox.index - SPro.button_offset; - if (index > 2) { return false; } // Support three buttons -/* - uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart - AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Button default state %d"), state); - XdrvMailbox.index = state; -*/ - XdrvMailbox.index = 1; // 1 on power on and restart - return true; -} - -bool ShellyProAddSwitch(void) { - if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 - if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } - uint32_t index = XdrvMailbox.index - SPro.switch_offset; - if (index > 3) { return false; } // Support four switches -/* - uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart - AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Switch default state %d"), state); - XdrvMailbox.index = state; -*/ - XdrvMailbox.index = 0; // 0 on power on and restart - return true; -} - -void ShellyProUpdateIsr(void) { - /* - The goal if this function is to minimize SPI and SetVirtualPinState calls - */ - uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt - input_state &= 0x806F; // Only test input bits - -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state); - - if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron - - uint32_t mask = 1; - for (uint32_t j = 0; j < 16; j++) { - if ((input_state & mask) != (SPro.input_state & mask)) { - uint32_t state = (input_state >> j) &1; - -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state); - - for (uint32_t i = 0; i < 4; i++) { - if (j == sp4_switch_pin[i]) { - SwitchSetVirtualPinState(SPro.switch_offset +i, state); - } - else if ((i < 3) && (j == sp4_button_pin[i])) { - ButtonSetVirtualPinState(SPro.button_offset +i, state); - } - } - } - mask <<= 1; - } - SPro.input_state = input_state; + MCP23xDigitalWrite(4, 1); } bool ShellyProButton(void) { @@ -357,7 +141,7 @@ void ShellyProUpdate(void) { void ShellyProPreInit(void) { if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && - PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 + (PinUsed(GPIO_SPI_CS) || PinUsed(GPIO_MCP23SXX_CS)) && // 74HC595 rclk / MCP23S17 TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { @@ -365,26 +149,16 @@ void ShellyProPreInit(void) { if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { SPro.detected = 2; // Shelly Pro 2 } - SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 - } - if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) { - SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) - } - - if (SPro.detected) { - TasmotaGlobal.devices_present += SPro.detected; - + UpdateDevicesPresent(SPro.detected); // Shelly Pro 1/2 SPro.pin_register_cs = Pin(GPIO_SPI_CS); - digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk + digitalWrite(SPro.pin_register_cs, 0); // Prep 74HC595 rclk pinMode(SPro.pin_register_cs, OUTPUT); + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 // Does nothing if SPI is already initiated (by ADE7953) so no harm done SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); - - if (4 == SPro.detected) { - SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt - pinMode(SPro.pin_mcp23s17_int, INPUT); - ShellyPro4Init(); // Init MCP23S17 - } + } + if (PinUsed(GPIO_MCP23SXX_CS)) { + SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) } } } @@ -407,26 +181,6 @@ void ShellyProPower(void) { if (SPro.detected != 4) { SPro.power = XdrvMailbox.index &3; ShellyProUpdate(); - } else { - -// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); - - power_t rpower = XdrvMailbox.index; -/* - for (uint32_t i = 0; i < 4; i++) { - power_t state = rpower &1; - SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); // 4 SPI writes - rpower >>= 1; // Select next power - } -*/ - for (uint32_t i = 0; i < 4; i++) { - power_t state = rpower &1; - uint32_t bit = sp4_relay_pin[i] -8; // Adjust by 8 bits - bitWrite(sp4_mcp23s17_olatb, bit, state); - rpower >>= 1; // Select next power - } - SP4Mcp23S17Write(SP4_MCP23S17_OLATB, sp4_mcp23s17_olatb); // 1 SPI write - } } @@ -484,7 +238,7 @@ void ShellyProLedLinkWifiOff(void) { bool Xdrv88(uint32_t function) { bool result = false; - if (FUNC_MODULE_INIT == function) { + if (FUNC_PRE_INIT == function) { ShellyProPreInit(); } else if (SPro.detected) { switch (function) { @@ -502,12 +256,6 @@ bool Xdrv88(uint32_t function) { case FUNC_INIT: ShellyProInit(); break; - case FUNC_ADD_BUTTON: - result = ShellyProAddButton(); - break; - case FUNC_ADD_SWITCH: - result = ShellyProAddSwitch(); - break; case FUNC_LED_LINK: ShellyProLedLink(); break; @@ -517,5 +265,6 @@ bool Xdrv88(uint32_t function) { } #endif // USE_SHELLY_PRO +#endif // USE_MCP23XXX_DRV #endif // USE_SPI #endif // ESP32 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v1.ino new file mode 100644 index 000000000..6af3d65b7 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v1.ino @@ -0,0 +1,177 @@ +/* + xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota + + Copyright (C) 2022 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 . +*/ + +#ifdef ESP32 +#ifdef USE_SPI +#ifdef USE_SHELLY_PRO_V1 +/*********************************************************************************************\ + * Shelly Pro support + * + * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"} + * + * Shelly Pro uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring +\*********************************************************************************************/ + +#define XDRV_88 88 + +struct SPro { + uint32_t last_update; + uint8_t pin_shift595_rclk; + uint8_t ledlink; + uint8_t power; + bool detected; +} SPro; + +void ShellyProUpdate(void) { + // Shelly Pro 595 register + // bit 0 = relay/led 1 + // bit 1 = relay/led 2 + // bit 2 = wifi led blue + // bit 3 = wifi led green + // bit 4 = wifi led red + // bit 5 - 7 = nc + // OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 + // - this inhibits output of signals (also relay state) during power on for a few seconds + uint8_t val = SPro.power | SPro.ledlink; + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + SPI.transfer(val); // Write 74HC595 shift register + SPI.endTransaction(); +// delayMicroseconds(2); // Wait for SPI clock to stop + digitalWrite(SPro.pin_shift595_rclk, 1); // Latch data + delayMicroseconds(1); // Shelly 10mS + digitalWrite(SPro.pin_shift595_rclk, 0); +} + +void ShellyProPreInit(void) { + if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && + PinUsed(GPIO_SPI_CS) && + TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 + + if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { + UpdateDevicesPresent(1); // Shelly Pro 1 + + if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { + UpdateDevicesPresent(1); // Shelly Pro 2 + } + + SPro.pin_shift595_rclk = Pin(GPIO_SPI_CS); + digitalWrite(SPro.pin_shift595_rclk, 0); + pinMode(SPro.pin_shift595_rclk, OUTPUT); + // Does nothing if SPI is already initiated (by ADE7953) so no harm done + SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); + + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() + SPro.detected = true; + } + } +} + +void ShellyProInit(void) { + int pin_lan_reset = 5; // GPIO5 = LAN8720 nRST +// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on + digitalWrite(pin_lan_reset, 0); + pinMode(pin_lan_reset, OUTPUT); + delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS + digitalWrite(pin_lan_reset, 1); + + AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), + TasmotaGlobal.devices_present, (PinUsed(GPIO_ADE7953_CS))?"PM":""); +} + +void ShellyProPower(void) { + SPro.power = XdrvMailbox.index &3; + ShellyProUpdate(); +} + +void ShellyProUpdateLedLink(uint32_t ledlink) { + if (ledlink != SPro.ledlink) { + SPro.ledlink = ledlink; + ShellyProUpdate(); + } +} + +void ShellyProLedLink(void) { + /* + bit 2 = blue, 3 = green, 4 = red + Shelly Pro documentation + - Blue light indicator will be on if in AP mode. + - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. + - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. + - The light indicator will be flashing Red/Blue if OTA update is in progress. + Tasmota behaviour + - Blue light indicator will blink if no wifi or mqtt. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + SPro.last_update = TasmotaGlobal.uptime; + uint32_t ledlink = 0x1C; // All leds off + if (XdrvMailbox.index) { + ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + } + else if (!TasmotaGlobal.global_state.wifi_down) { + ledlink &= 0xF7; // Green On + } + + ShellyProUpdateLedLink(ledlink); +} + +void ShellyProLedLinkWifiOff(void) { + /* + bit 2 = blue, 3 = green, 4 = red + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + if (SPro.last_update +1 < TasmotaGlobal.uptime) { + ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv88(uint32_t function) { + bool result = false; + + if (FUNC_PRE_INIT == function) { + ShellyProPreInit(); + } else if (SPro.detected) { + switch (function) { + case FUNC_EVERY_SECOND: + ShellyProLedLinkWifiOff(); + break; + case FUNC_SET_POWER: + ShellyProPower(); + break; + case FUNC_LED_LINK: + ShellyProLedLink(); + break; + case FUNC_INIT: + ShellyProInit(); + break; + } + } + return result; +} + +#endif // USE_SHELLY_PRO +#endif // USE_SPI +#endif // ESP32 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino new file mode 100644 index 000000000..f7bea6ca5 --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro_v2.ino @@ -0,0 +1,521 @@ +/* + xdrv_88_esp32_shelly_pro.ino - Shelly pro family support for Tasmota + + Copyright (C) 2022 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 . +*/ + +#ifdef ESP32 +#ifdef USE_SPI +#ifdef USE_SHELLY_PRO_V2 +/*********************************************************************************************\ + * Shelly Pro support + * + * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350;AdcParam2 2,5600,4700,3350"} + * {"NAME":"Shelly Pro 4PM","GPIO":[0,6210,0,6214,9568,0,0,0,0,0,9569,0,768,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,736,704,3461,0,4736,0,0,672],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,5600,4700,3350"} + * + * Shelly Pro 1/2 uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring + * Shelly Pro 4 uses an SPI to control one MCP23S17 for buttons/switches/relays/leds and two ADE7953 for energy monitoring and a second SPI for the display + * To use display enable defines USE_DISPLAY, USE_UNIVERSAL_DISPLAY and SHOW_SPLASH. Load file ST7735S_Pro4PM_display.ini as display.ini +\*********************************************************************************************/ + +#define XDRV_88 88 + +#define SHELLY_PRO_PIN_LAN8720_RESET 5 +#define SHELLY_PRO_4_PIN_SPI_CS 16 +#define SHELLY_PRO_4_PIN_MCP23S17_INT 35 +#define SHELLY_PRO_4_MCP23S17_ADDRESS 0x40 + +struct SPro { + uint32_t last_update; + uint16_t input_state; + int8_t switch_offset; + int8_t button_offset; + uint8_t pin_register_cs; + uint8_t pin_mcp23s17_int; + uint8_t ledlink; + uint8_t power; + bool init_done; + uint8_t detected; +} SPro; + +/*********************************************************************************************\ + * Shelly Pro MCP23S17 support +\*********************************************************************************************/ + +enum SP4MCP23X17GPIORegisters { + // A side + SP4_MCP23S17_IODIRA = 0x00, + SP4_MCP23S17_IPOLA = 0x02, + SP4_MCP23S17_GPINTENA = 0x04, + SP4_MCP23S17_DEFVALA = 0x06, + SP4_MCP23S17_INTCONA = 0x08, + SP4_MCP23S17_IOCONA = 0x0A, + SP4_MCP23S17_GPPUA = 0x0C, + SP4_MCP23S17_INTFA = 0x0E, + SP4_MCP23S17_INTCAPA = 0x10, + SP4_MCP23S17_GPIOA = 0x12, + SP4_MCP23S17_OLATA = 0x14, + // B side + SP4_MCP23S17_IODIRB = 0x01, + SP4_MCP23S17_IPOLB = 0x03, + SP4_MCP23S17_GPINTENB = 0x05, + SP4_MCP23S17_DEFVALB = 0x07, + SP4_MCP23S17_INTCONB = 0x09, + SP4_MCP23S17_IOCONB = 0x0B, + SP4_MCP23S17_GPPUB = 0x0D, + SP4_MCP23S17_INTFB = 0x0F, + SP4_MCP23S17_INTCAPB = 0x11, + SP4_MCP23S17_GPIOB = 0x13, + SP4_MCP23S17_OLATB = 0x15, +}; + +uint8_t sp4_mcp23s17_olata = 0; +uint8_t sp4_mcp23s17_olatb = 0; + +bool sp4_spi_busy; + +void SP4Mcp23S17Enable(void) { + sp4_spi_busy = true; + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + digitalWrite(SPro.pin_register_cs, 0); +} + +void SP4Mcp23S17Disable(void) { + SPI.endTransaction(); + digitalWrite(SPro.pin_register_cs, 1); + sp4_spi_busy = false; +} + +uint32_t SP4Mcp23S17Read16(uint8_t reg) { + // Read 16-bit registers: (regb << 8) | rega + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(reg); + uint32_t value = SPI.transfer(0xFF); // RegA + value |= (SPI.transfer(0xFF) << 8); // RegB + SP4Mcp23S17Disable(); + return value; +} + +uint32_t SP4Mcp23S17Read(uint8_t reg) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1); + SPI.transfer(reg); + uint32_t value = SPI.transfer(0xFF); + SP4Mcp23S17Disable(); + return value; +} + +void SP4Mcp23S17Write(uint8_t reg, uint8_t value) { + SP4Mcp23S17Enable(); + SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS); + SPI.transfer(reg); + SPI.transfer(value); + SP4Mcp23S17Disable(); +} + +void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) { + uint8_t bit = pin % 8; + uint8_t reg_value = 0; + if (reg_addr == SP4_MCP23S17_OLATA) { + reg_value = sp4_mcp23s17_olata; + } else if (reg_addr == SP4_MCP23S17_OLATB) { + reg_value = sp4_mcp23s17_olatb; + } else { + reg_value = SP4Mcp23S17Read(reg_addr); + } + if (pin_value) { + reg_value |= 1 << bit; + } else { + reg_value &= ~(1 << bit); + } + SP4Mcp23S17Write(reg_addr, reg_value); + if (reg_addr == SP4_MCP23S17_OLATA) { + sp4_mcp23s17_olata = reg_value; + } else if (reg_addr == SP4_MCP23S17_OLATB) { + sp4_mcp23s17_olatb = reg_value; + } +} + +void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) { + uint8_t iodir = pin < 8 ? SP4_MCP23S17_IODIRA : SP4_MCP23S17_IODIRB; + uint8_t gppu = pin < 8 ? SP4_MCP23S17_GPPUA : SP4_MCP23S17_GPPUB; + if (flags == INPUT) { + SP4Mcp23S17Update(pin, true, iodir); + SP4Mcp23S17Update(pin, false, gppu); + } else if (flags == (INPUT | PULLUP)) { + SP4Mcp23S17Update(pin, true, iodir); + SP4Mcp23S17Update(pin, true, gppu); + } else if (flags == OUTPUT) { + SP4Mcp23S17Update(pin, false, iodir); + } +} + +bool SP4Mcp23S17DigitalRead(uint8_t pin) { + uint8_t bit = pin % 8; + uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB; + uint8_t value = SP4Mcp23S17Read(reg_addr); + return value & (1 << bit); +} + +void SP4Mcp23S17DigitalWrite(uint8_t pin, bool value) { + uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_OLATA : SP4_MCP23S17_OLATB; + SP4Mcp23S17Update(pin, value, reg_addr); +} + +/*********************************************************************************************\ + * Shelly Pro 4 +\*********************************************************************************************/ + +const uint8_t sp4_relay_pin[] = { 8, 13, 14, 12 }; +const uint8_t sp4_switch_pin[] = { 6, 1, 0, 15 }; +const uint8_t sp4_button_pin[] = { 5, 2, 3 }; + +void ShellyPro4Init(void) { + /* + Shelly Pro 4PM MCP23S17 registers + bit 0 = input, inverted - Switch3 + bit 1 = input, inverted - Switch2 + bit 2 = input - Button Down + bit 3 = input - Button OK + bit 4 = output - Reset, display, ADE7953 + bit 5 = input - Button Up + bit 6 = input, inverted - Switch1 + bit 7 + bit 8 = output - Relay O1 + bit 9 + bit 10 + bit 11 + bit 12 = output - Relay O4 + bit 13 = output - Relay O2 + bit 14 = output - Relay O3 + bit 15 = input, inverted - Switch4 + */ + SP4Mcp23S17Write(SP4_MCP23S17_IOCONA, 0b01011000); // Enable INT mirror, Slew rate disabled, HAEN pins for addressing + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENA, 0x6F); // Enable interrupt on change + SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change + + // Read current output register state + sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA); + sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB); + + SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943 + SP4Mcp23S17DigitalWrite(4, 1); + + for (uint32_t i = 0; i < 3; i++) { + SP4Mcp23S17PinMode(sp4_button_pin[i], INPUT); // Button Up, Down, OK (RC with 10k to 3V3 and button shorting C) + } + SPro.button_offset = -1; + + for (uint32_t i = 0; i < 4; i++) { + SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4 + SP4Mcp23S17PinMode(sp4_relay_pin[i], OUTPUT); // Relay O1..O4 + } + SPro.switch_offset = -1; + + // Read current input register state + SPro.input_state = SP4Mcp23S17Read16(SP4_MCP23S17_GPIOA) & 0x806F; // Read gpio and clear interrupt + attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE); +} + +void ShellyPro4Reset(void) { + SP4Mcp23S17DigitalWrite(4, 0); // Reset pin display, ADE7953 + delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs. + SP4Mcp23S17DigitalWrite(4, 1); +} + +bool ShellyProAddButton(void) { + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 + if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - SPro.button_offset; + if (index > 2) { return false; } // Support three buttons +/* + uint32_t state = bitRead(SPro.input_state, sp4_button_pin[index]); // 1 on power on and restart + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Button default state %d"), state); + XdrvMailbox.index = state; +*/ + XdrvMailbox.index = 1; // 1 on power on and restart + return true; +} + +bool ShellyProAddSwitch(void) { + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 + if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; } + uint32_t index = XdrvMailbox.index - SPro.switch_offset; + if (index > 3) { return false; } // Support four switches +/* + uint32_t state = bitRead(SPro.input_state, sp4_switch_pin[index]); // 0 on power on and restart + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Switch default state %d"), state); + XdrvMailbox.index = state; +*/ + XdrvMailbox.index = 0; // 0 on power on and restart + return true; +} + +void ShellyProUpdateIsr(void) { + /* + The goal if this function is to minimize SPI and SetVirtualPinState calls + */ + uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt + input_state &= 0x806F; // Only test input bits + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input from %04X to %04X"), SPro.input_state, input_state); + + if (TasmotaGlobal.uptime < 3) { return; } // Flush interrupt for 3 seconds after poweron + + uint32_t mask = 1; + for (uint32_t j = 0; j < 16; j++) { + if ((input_state & mask) != (SPro.input_state & mask)) { + uint32_t state = (input_state >> j) &1; + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state); + + for (uint32_t i = 0; i < 4; i++) { + if (j == sp4_switch_pin[i]) { + SwitchSetVirtualPinState(SPro.switch_offset +i, state); + } + else if ((i < 3) && (j == sp4_button_pin[i])) { + ButtonSetVirtualPinState(SPro.button_offset +i, state); + } + } + } + mask <<= 1; + } + SPro.input_state = input_state; +} + +bool ShellyProButton(void) { + if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4 + + uint32_t button_index = XdrvMailbox.index - SPro.button_offset; + if (button_index > 2) { return false; } // Only support Up, Down, Ok + + uint32_t button = XdrvMailbox.payload; + uint32_t last_state = XdrvMailbox.command_code; + if ((PRESSED == button) && (NOT_PRESSED == last_state)) { // Button pressed + + AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Button %d pressed"), button_index +1); + + // Do something with the Up,Down,Ok button + switch (button_index) { + case 0: // Up + break; + case 1: // Down + break; + case 2: // Ok + break; + } + } + return true; // Disable further button processing +} + +/*********************************************************************************************\ + * Shelly Pro 1/2 +\*********************************************************************************************/ + +void ShellyProUpdate(void) { + /* + Shelly Pro 1/2/PM 74HC595 register + bit 0 = relay/led 1 + bit 1 = relay/led 2 + bit 2 = wifi led blue + bit 3 = wifi led green + bit 4 = wifi led red + bit 5 - 7 = nc + OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3 + - this inhibits output of signals (also relay state) during power on for a few seconds + */ + uint8_t val = SPro.power | SPro.ledlink; + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); + SPI.transfer(val); // Write 74HC595 shift register + SPI.endTransaction(); +// delayMicroseconds(2); // Wait for SPI clock to stop + digitalWrite(SPro.pin_register_cs, 1); // Latch data + delayMicroseconds(1); // Shelly 10mS + digitalWrite(SPro.pin_register_cs, 0); +} + +/*********************************************************************************************\ + * Shelly Pro +\*********************************************************************************************/ + +void ShellyProPreInit(void) { + if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) && + PinUsed(GPIO_SPI_CS) && // 74HC595 rclk / MCP23S17 + TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7 + + if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) { + SPro.detected = 1; // Shelly Pro 1 + if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) { + SPro.detected = 2; // Shelly Pro 2 + } + SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower() - Shelly 1/2 + } + if (SHELLY_PRO_4_PIN_SPI_CS == Pin(GPIO_SPI_CS)) { + SPro.detected = 4; // Shelly Pro 4PM (No SWT or KEY) + } + + if (SPro.detected) { + UpdateDevicesPresent(SPro.detected); // Shelly Pro 1 + + SPro.pin_register_cs = Pin(GPIO_SPI_CS); + digitalWrite(SPro.pin_register_cs, (4 == SPro.detected) ? 1 : 0); // Prep 74HC595 rclk + pinMode(SPro.pin_register_cs, OUTPUT); + // Does nothing if SPI is already initiated (by ADE7953) so no harm done + SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1); + + if (4 == SPro.detected) { + SPro.pin_mcp23s17_int = SHELLY_PRO_4_PIN_MCP23S17_INT; // GPIO35 = MCP23S17 common interrupt + pinMode(SPro.pin_mcp23s17_int, INPUT); + ShellyPro4Init(); // Init MCP23S17 + } + } + } +} + +void ShellyProInit(void) { + int pin_lan_reset = SHELLY_PRO_PIN_LAN8720_RESET; // GPIO5 = LAN8720 nRST +// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on + digitalWrite(pin_lan_reset, 0); + pinMode(pin_lan_reset, OUTPUT); + delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS + digitalWrite(pin_lan_reset, 1); + + AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"), + SPro.detected, (PinUsed(GPIO_ADE7953_CS))?"PM":""); + + SPro.init_done = true; +} + +void ShellyProPower(void) { + if (SPro.detected != 4) { + SPro.power = XdrvMailbox.index &3; + ShellyProUpdate(); + } else { + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Set Power 0x%08X"), XdrvMailbox.index); + + power_t rpower = XdrvMailbox.index; +/* + for (uint32_t i = 0; i < 4; i++) { + power_t state = rpower &1; + SP4Mcp23S17DigitalWrite(sp4_relay_pin[i], state); // 4 SPI writes + rpower >>= 1; // Select next power + } +*/ + for (uint32_t i = 0; i < 4; i++) { + power_t state = rpower &1; + uint32_t bit = sp4_relay_pin[i] -8; // Adjust by 8 bits + bitWrite(sp4_mcp23s17_olatb, bit, state); + rpower >>= 1; // Select next power + } + SP4Mcp23S17Write(SP4_MCP23S17_OLATB, sp4_mcp23s17_olatb); // 1 SPI write + + } +} + +void ShellyProUpdateLedLink(uint32_t ledlink) { + if (ledlink != SPro.ledlink) { + SPro.ledlink = ledlink; + ShellyProUpdate(); + } +} + +void ShellyProLedLink(void) { + if (!SPro.init_done) { return; } // Block write before first power update + if (SPro.detected != 4) { + /* + bit 2 = blue, 3 = green, 4 = red + Shelly Pro documentation + - Blue light indicator will be on if in AP mode. + - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network. + - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud. + - The light indicator will be flashing Red/Blue if OTA update is in progress. + Tasmota behaviour + - Blue light indicator will blink if no wifi or mqtt. + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + SPro.last_update = TasmotaGlobal.uptime; + uint32_t ledlink = 0x1C; // All leds off + if (XdrvMailbox.index) { + ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost + } + else if (!TasmotaGlobal.global_state.wifi_down) { + ledlink &= 0xF7; // Green On + } + ShellyProUpdateLedLink(ledlink); + } +} + +void ShellyProLedLinkWifiOff(void) { + if (!SPro.init_done) { return; } + if (SPro.detected != 4) { + /* + bit 2 = blue, 3 = green, 4 = red + - Green light indicator will be on if in STA mode and connected to a Wi-Fi network. + */ + if (SPro.last_update +1 < TasmotaGlobal.uptime) { + ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv88(uint32_t function) { + bool result = false; + + if (FUNC_SETUP_RING2 == function) { + ShellyProPreInit(); + } else if (SPro.detected) { + switch (function) { +/* + case FUNC_BUTTON_PRESSED: + result = ShellyProButton(); + break; +*/ + case FUNC_EVERY_SECOND: + ShellyProLedLinkWifiOff(); + break; + case FUNC_SET_POWER: + ShellyProPower(); + break; + case FUNC_INIT: + ShellyProInit(); + break; + case FUNC_ADD_BUTTON: + result = ShellyProAddButton(); + break; + case FUNC_ADD_SWITCH: + result = ShellyProAddSwitch(); + break; + case FUNC_LED_LINK: + ShellyProLedLink(); + break; + } + } + return result; +} + +#endif // USE_SHELLY_PRO +#endif // USE_SPI +#endif // ESP32 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino b/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino index 459775dba..93bfd2a34 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino @@ -22,6 +22,14 @@ #define XDRV_90 90 +/******************************************************************************************************** + * Check defines + */ + +#if defined(DINGTIAN_USE_AS_BUTTON) && defined(DINGTIAN_USE_AS_SWITCH) +#error DINGTIAN - Only one of DINGTIAN_USE_AS_BUTTON or DINGTIAN_USE_AS_SWITCH should be defined +#endif + /******************************************************************************************************** * Global private data */ @@ -31,6 +39,7 @@ struct DINGTIAN_DATA { uint32_t last_inputs; // previous inputs state uint8_t count; // number of relay and input (8 * numver of shift registers) uint8_t first; // index of 1st Tasmota relay assigned to 1st Dingtian relays + int8_t key_offset; // index of virtual key // pins uint8_t pin_clk, pin_sdi, pin_q7, pin_pl, pin_rck; } *Dingtian = nullptr; @@ -63,7 +72,11 @@ uint32_t DingtianReadWrite(uint32_t outputs) digitalWrite(Dingtian->pin_rck, 1); // rclk pulse to load '595 into output registers digitalWrite(Dingtian->pin_pl, 0); // re-enable '595 ouputs +#ifdef DINGTIAN_INPUTS_INVERTED + return ~inputs; +#else return inputs; +#endif } /******************************************************************************************************** @@ -98,19 +111,51 @@ void DingtianInit(void) { DINGTIAN_SET_OUTPUT(Dingtian->pin_rck, 0); Dingtian->first = TasmotaGlobal.devices_present; - TasmotaGlobal.devices_present += Dingtian->count; - if (TasmotaGlobal.devices_present > POWER_SIZE) { - TasmotaGlobal.devices_present = POWER_SIZE; - } + Dingtian->key_offset = -1; + UpdateDevicesPresent(Dingtian->count); AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: Dingtian relays: POWER%d to POWER%d"), Dingtian->first + 1, TasmotaGlobal.devices_present); } } } +#if defined(DINGTIAN_USE_AS_BUTTON) || defined(DINGTIAN_USE_AS_SWITCH) +bool DingtianAddKey(void) { + if (Dingtian->key_offset < 0) { + Dingtian->key_offset = XdrvMailbox.index; + #ifdef DINGTIAN_USE_AS_BUTTON + AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: Dingtian inputs: Button%d to Button%d"), Dingtian->key_offset + 1, Dingtian->key_offset + Dingtian->count); + #else + AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: Dingtian inputs: Switch%d to Switch%d"), Dingtian->key_offset + 1, Dingtian->key_offset + Dingtian->count); + #endif + } + uint32_t index = XdrvMailbox.index - Dingtian->key_offset; + if (index >= Dingtian->count) { + return false; + } + XdrvMailbox.index = 0; // Default is 0 - Button will also set invert + return true; +} +#endif + /******************************************************************************************************** * Driver operations */ +#if defined(DINGTIAN_USE_AS_BUTTON) || defined(DINGTIAN_USE_AS_SWITCH) +void DingtianLoop() +{ + uint32_t inputs = DingtianReadWrite(Dingtian->outputs); + Dingtian->last_inputs = inputs; + + for (int i = 0 ; i < Dingtian->count ; i++, inputs>>=1) { +#ifdef DINGTIAN_USE_AS_BUTTON + ButtonSetVirtualPinState(Dingtian->key_offset +i, inputs &1); +#else + SwitchSetVirtualPinState(Dingtian->key_offset +i, inputs &1); +#endif + } +} +#else void DingtianLoop() { uint32_t inputs = DingtianReadWrite(Dingtian->outputs); @@ -134,6 +179,7 @@ void DingtianLoop() } } } +#endif void DingtianSetPower(void) { @@ -149,30 +195,32 @@ void DingtianSetPower(void) const char HTTP_DINGTIAN_INPUTS[] PROGMEM = "{s}DINGTIAN " D_SENSOR_INPUT "%d.." D_SENSOR_INPUT "%d{m}%s{e}"; -void DingtianShow(bool json) +#if !defined(DINGTIAN_USE_AS_BUTTON) && !defined(DINGTIAN_USE_AS_SWITCH) +void DingtianJsonAppend(void) { - if (json) { - bool first_done = false; - ResponseAppend_P(PSTR(",\"DINGTIAN\":{")); - for (int i = 0 ; i < Dingtian->count ; i++) { - if (first_done) ResponseAppend_P(PSTR(",")); - ResponseAppend_P(PSTR("\"IN%d\":%d"), i +1, bitRead(Dingtian->last_inputs, i)); - first_done = true; - } - ResponseAppend_P(PSTR("}")); + bool first_done = false; + ResponseAppend_P(PSTR(",\"DINGTIAN\":{")); + for (int i = 0 ; i < Dingtian->count ; i++) { + if (first_done) ResponseAppend_P(PSTR(",")); + ResponseAppend_P(PSTR("\"IN%d\":%d"), i +1, bitRead(Dingtian->last_inputs, i)); + first_done = true; } -#ifdef USE_WEBSERVER - else { - char input_str[9]; - for (int block_input = 0 ; block_input < Dingtian->count ; block_input += 8 ) { - for (int i = 0 ; i < 8 ; i++ ) - input_str[i] = '0' + bitRead(Dingtian->last_inputs, block_input +i); - input_str[8] = '\0'; - WSContentSend_P(HTTP_DINGTIAN_INPUTS, block_input, block_input +7, input_str); - } - } -#endif + ResponseAppend_P(PSTR("}")); } +#endif + +#ifdef USE_WEBSERVER +void DingtianWebSensor(void) +{ + char input_str[9]; + for (int block_input = 0 ; block_input < Dingtian->count ; block_input += 8 ) { + for (int i = 0 ; i < 8 ; i++ ) + input_str[i] = '0' + bitRead(Dingtian->last_inputs, block_input +i); + input_str[8] = '\0'; + WSContentSend_P(HTTP_DINGTIAN_INPUTS, block_input, block_input +7, input_str); + } +} +#endif /*********************************************************************************************\ @@ -182,7 +230,7 @@ void DingtianShow(bool json) bool Xdrv90(uint32_t function) { bool result = false; - if (FUNC_PRE_INIT == function) { + if (FUNC_SETUP_RING2 == function) { DingtianInit(); } else if (Dingtian) { switch (function) { @@ -193,14 +241,26 @@ bool Xdrv90(uint32_t function) { //case FUNC_EVERY_250_MSECOND: DingtianLoop(); break; +#if !defined(DINGTIAN_USE_AS_BUTTON) && !defined(DINGTIAN_USE_AS_SWITCH) case FUNC_JSON_APPEND: - DingtianShow(1); + DingtianJsonAppend(); break; +#endif #ifdef USE_WEBSERVER case FUNC_WEB_SENSOR: - DingtianShow(0); + DingtianWebSensor(); break; #endif // USE_WEBSERVER +#ifdef DINGTIAN_USE_AS_BUTTON + case FUNC_ADD_BUTTON: + result = DingtianAddKey(); + break; +#endif +#ifdef DINGTIAN_USE_AS_SWITCH + case FUNC_ADD_SWITCH: + result = DingtianAddKey(); + break; +#endif } } return result; diff --git a/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino b/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino index 1d7540895..9677abf09 100644 --- a/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino +++ b/tasmota/tasmota_xdsp_display/xdsp_20_tm1650.ino @@ -2,6 +2,7 @@ xdsp_20_tm1650.ino - TM1650 four-digit seven-segment LED display controller support for Tasmota Copyright (C) 2021 Stefan Oskamp, Theo Arends, Anatoli Arkhipenko + Copyright (C) 2023 Gabriele Lauricella 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 @@ -32,15 +33,139 @@ connected. This wiring of the XY-Clock has been reflected in the time format. Other clocks using a TM1650 might be wired differently. */ + #ifdef USE_I2C #ifdef USE_DISPLAY #ifdef USE_DISPLAY_TM1650 -#include + +/*********************************************************************************************\ + This driver enables the display of numbers (both integers and floats) and basic text + on the inexpensive TM1650 seven-segment modules. + + Raw segments can also be displayed. + + In addition, it is also possible to set brightness (8 levels), clear the display, scroll text, + display a rudimentary bar graph, and a Clock (12 hr and 24 hr). + + To use, compile Tasmota with USE_I2C, USE_DISPLAY and USE_DISPLAY_TM1650, or build the tasmota-display env. + + For TM1650: + Connect the TM1650 display module's pins to any free GPIOs of the ESP8266 module + and assign the pins as follows from Tasmota's GUI: + + DIO hardware pin --> "I2C SCA" + CLK hardware pin --> "I2C SCL" + + Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, + set the Display Model to 20 and Display Mode to 0 + using the command "Backlog DisplayModel 20 ; DisplayMode 0;" + Before using it set the Display Type, if you have an XY-Clock set it to 0 otherwise if you + have a 303WifiL01 set it to 2 using the "DisplayType 0" command. + + + After the ESP8266/ESP32 module restarts again, turn ON the display with the command "Power 1" + + Now, the following "Display" commands can be used: + + + DisplayClear + + Clears the display, command: "DisplayClear" + + + DisplayNumber num [,position {0-(Settings->display_width-1))} [,leading_zeros {0|1} [,length {1 to Settings->display_width}]]] + + Clears and then displays number without decimal. command e.g., "DisplayNumber 1234" + Control 'leading zeros', 'length' and 'position' with "DisplayNumber 1234, , , " + 'leading zeros' can be 1 or 0 (default), 'length' can be 1 to Settings->display_width, 'position' can be 0 (left-most) to Settings->display_width (right-most). + See function description below for more details. + + DisplayNumberNC num [,position {0-(Settings->display_width-1))} [,leading_zeros {0|1} [,length {1 to Settings->display_width}]]] + + Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above. + + + + DisplayFloat num [,position {0-(Settings->display_width-1)} [,precision {0-Settings->display_width} [,length {1 to Settings->display_width}]]] + + Clears and then displays float (with decimal point) command e.g., "DisplayFloat 12.34" + See function description below for more details. + + + + DisplayFloatNC num [,position {0-(Settings->display_width-1)} [,precision {0-Settings->display_width} [,length {1 to Settings->display_width}]]] + + Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34" + See function description below for more details. + + + + DisplayRaw position {0-(Settings->display_width-1)},length {1 to Settings->display_width}, num1 [, num2[, num3[, num4[, ...upto Settings->display_width numbers]]]]] + + Takes upto Settings->display_width comma-separated integers (0-255) and displays raw segments. Each number represents a + 7-segment digit. Each 8-bit number represents individual segments of a digit. + For example, the command "DisplayRaw 0, 4, 255, 255, 255, 255" would display "[8.8.8.8.]" + + + + DisplayText text [, position {0-(Settings->display_width-1)} [,length {1 to Settings->display_width}]] + + Clears and then displays basic text. command e.g., "DisplayText ajith vasudevan" + Control 'length' and 'position' with "DisplayText , , " + 'length' can be 1 to Settings->display_width, 'position' can be 0 (left-most) to Settings->display_width-1 (right-most) + A caret(^) or backtick(`) symbol in the text input is dispayed as the degrees(°) symbol. This is useful for + displaying Temperature! For example, the command "DisplayText 22.5^" will display "22.5°". + + + DisplayTextNC text [, position {0-Settings->display_width-1} [,length {1 to Settings->display_width}]] + + Clears first, then displays text. Usage is same as above. + + + + DisplayScrollText text [, num_loops] + + Displays scrolling text indefinitely, until another Display- command (other than DisplayScrollText + or DisplayScrollDelay is issued). Optionally, stop scrolling after num_loops iterations. + + + + DisplayScrollDelay delay {0-15} // default = 4 + + Sets the speed of text scroll. Smaller delay = faster scrolling. + + + + DisplayLevel num {0-100} + + Display a horizontal bar graph (0-100) command e.g., "DisplayLevel 50" will display [|||| ] + + + + DisplayClock 1|2|0 + + Displays a clock. + Commands "DisplayClock 1" // 12 hr format + "DisplayClock 2" // 24 hr format + "DisplayClock 0" // turn off clock + + +In addition, if you compile using USE_DISPLAY_MODES1TO5, setting DisplayMode to 1 shows the time, +setting it to 2 shows the date and setting it to 3 alternates between time and date (using "DisplayRefresh [1..7]" +for the time and seconds you want to show the time before displaying the date) + +\*********************************************************************************************/ + #define XDSP_20 20 #define XI2C_74 74 // See I2CDEVICES.md +#define CMD_MAX_LEN 55 +#define LEVEL_MIN 0 +#define LEVEL_MAX 100 +#define SCROLL_MAX_LEN 50 + #define TM1650_CONTROL_BASE 0x24 // I2C address to control left-most digit. #define TM1650_DISPLAY_BASE 0x34 // I2C address to display something in the left-most digit. #define TM1650_DIGITS 4 // One TM1650 can only control modules with up to four digits. @@ -56,6 +181,7 @@ #define TM1650_CONTROL_BRIGHTNESS 4 // Bits 4...6 #define TM1650_CONTROL_RESERVED3 7 +#include static unsigned char TM1650Control[TM1650_DIGITS] = {0, 0, 0, 0}; static unsigned char TM1650Display[TM1650_DIGITS] = {0, 0, 0, 0}; @@ -64,57 +190,69 @@ static const byte TM1650Font[128] { //0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x10 +// ! " ' ( ) - 0x00, 0x82, 0x21, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x0F, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, // 0x20 +//0 1 2 3 4 5 6 7 8 9 = ? 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7f, 0x6f, 0x00, 0x00, 0x00, 0x48, 0x00, 0x53, // 0x30 +// A B C D E F G H I J L N O 0x00, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x6F, 0x76, 0x06, 0x1E, 0x00, 0x38, 0x00, 0x54, 0x3F, // 0x40 - 0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x00, 0x0F, 0x00, 0x08, // 0x50 +//P Q R S T U Y [ ] ^=° _ + 0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x00, 0x0F, 0x63, 0x08, // 0x50 +//`=° a b c d e f g h i j l n o 0x63, 0x5F, 0x7C, 0x58, 0x5E, 0x7B, 0x71, 0x6F, 0x74, 0x02, 0x1E, 0x00, 0x06, 0x00, 0x54, 0x5C, // 0x60 +//p q r s t u y { | } 0x73, 0x67, 0x50, 0x6D, 0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00, 0x39, 0x30, 0x0F, 0x00, 0x00 // 0x70 }; -const uint8_t TM1650Remap[] = { - 0x00, 0x20, 0x80, 0xA0, 0x04, 0x24, 0x84, 0xA4, 0x08, 0x28, 0x88, 0xA8, 0x0C, 0x2C, 0x8C, 0xAC, - 0x10, 0x30, 0x90, 0xB0, 0x14, 0x34, 0x94, 0xB4, 0x18, 0x38, 0x98, 0xB8, 0x1C, 0x3C, 0x9C, 0xBC, - 0x40, 0x60, 0xC0, 0xE0, 0x44, 0x64, 0xC4, 0xE4, 0x48, 0x68, 0xC8, 0xE8, 0x4C, 0x6C, 0xCC, 0xEC, - 0x50, 0x70, 0xD0, 0xF0, 0x54, 0x74, 0xD4, 0xF4, 0x58, 0x78, 0xD8, 0xF8, 0x5C, 0x7C, 0xDC, 0xFC, - 0x02, 0x22, 0x82, 0xA2, 0x06, 0x26, 0x86, 0xA6, 0x0A, 0x2A, 0x8A, 0xAA, 0x0E, 0x2E, 0x8E, 0xAE, - 0x12, 0x32, 0x92, 0xB2, 0x16, 0x36, 0x96, 0xB6, 0x1A, 0x3A, 0x9A, 0xBA, 0x1E, 0x3E, 0x9E, 0xBE, - 0x42, 0x62, 0xC2, 0xE2, 0x46, 0x66, 0xC6, 0xE6, 0x4A, 0x6A, 0xCA, 0xEA, 0x4E, 0x6E, 0xCE, 0xEE, - 0x52, 0x72, 0xD2, 0xF2, 0x56, 0x76, 0xD6, 0xF6, 0x5A, 0x7A, 0xDA, 0xFA, 0x5E, 0x7E, 0xDE, 0xFE, - 0x01, 0x21, 0x81, 0xA1, 0x05, 0x25, 0x85, 0xA5, 0x09, 0x29, 0x89, 0xA9, 0x0D, 0x2D, 0x8D, 0xAD, - 0x11, 0x31, 0x91, 0xB1, 0x15, 0x35, 0x95, 0xB5, 0x19, 0x39, 0x99, 0xB9, 0x1D, 0x3D, 0x9D, 0xBD, - 0x41, 0x61, 0xC1, 0xE1, 0x45, 0x65, 0xC5, 0xE5, 0x49, 0x69, 0xC9, 0xE9, 0x4D, 0x6D, 0xCD, 0xED, - 0x51, 0x71, 0xD1, 0xF1, 0x55, 0x75, 0xD5, 0xF5, 0x59, 0x79, 0xD9, 0xF9, 0x5D, 0x7D, 0xDD, 0xFD, - 0x03, 0x23, 0x83, 0xA3, 0x07, 0x27, 0x87, 0xA7, 0x0B, 0x2B, 0x8B, 0xAB, 0x0F, 0x2F, 0x8F, 0xAF, - 0x13, 0x33, 0x93, 0xB3, 0x17, 0x37, 0x97, 0xB7, 0x1B, 0x3B, 0x9B, 0xBB, 0x1F, 0x3F, 0x9F, 0xBF, - 0x43, 0x63, 0xC3, 0xE3, 0x47, 0x67, 0xC7, 0xE7, 0x4B, 0x6B, 0xCB, 0xEB, 0x4F, 0x6F, 0xCF, 0xEF, - 0x53, 0x73, 0xD3, 0xF3, 0x57, 0x77, 0xD7, 0xF7, 0x5B, 0x7B, 0xDB, 0xFB, 0x5F, 0x7F, 0xDF, 0xFF +enum display_options_types +{ + T_XY_CLOCK, // XY-Clock - white PCB with a perpendicular small daughter board + NOTUSED, + T_303WIFILC01 // 303WifiLC01 - green clock }; -/*********************************************************************************************/ - -void TM1650InitMode(void) +struct { - TM1650Dim(); - TM1650Clear(); -} // void TM1650InitMode(void) + char scroll_text[CMD_MAX_LEN]; + char msg[60]; + char model_name[8]; + uint8_t scroll_delay = 4; + uint8_t scroll_index = 0; + uint8_t iteration = 0; + uint8_t scroll_counter = 0; + uint8_t scroll_counter_max = 3; + uint8_t display_type = XDSP_20; + bool init_driver_done = false; + bool scroll = false; + bool show_clock = false; + bool clock_24 = false; + bool clock_blynk_dots = true; +} TM1650Data; + +/*********************************************************************************************\ +* Init function +\*********************************************************************************************/ void TM1650Init(uint8_t mode) { switch(mode) { case DISPLAY_INIT_MODE: - TM1650InitMode(); + TM1650Dim(); + TM1650ClearDisplay(); break; case DISPLAY_INIT_PARTIAL: case DISPLAY_INIT_FULL: - TM1650InitMode(); + TM1650Dim(); + TM1650ClearDisplay(); break; } -} // void TM1650Init(uint8_t mode) +} +/*********************************************************************************************\ +* Init Drive function +\*********************************************************************************************/ void TM1650InitDriver(void) { - // AddLog(LOG_LEVEL_DEBUG, PSTR("M1650InitDriver()")); if (!TasmotaGlobal.i2c_enabled) { return; } @@ -130,37 +268,50 @@ void TM1650InitDriver(void) I2cSetActiveFound(Settings->display_address[0], "TM1650"); Settings->display_cols[0] = 4; - Settings->display_cols[0] = 1; + Settings->display_rows = 1; Settings->display_width = Settings->display_cols[0]; Settings->display_height = Settings->display_rows; - TM1650InitMode(); + if (T_XY_CLOCK == Settings->display_options.type) + { + strcpy_P(TM1650Data.model_name, PSTR("XY-Clock")); + } + else if (NOTUSED == Settings->display_options.type) + { + strcpy_P(TM1650Data.model_name, PSTR("NOTUSED")); + } + else if (T_303WIFILC01 == Settings->display_options.type) + { + strcpy_P(TM1650Data.model_name, PSTR("303WiFiLC01")); + } - AddLog(LOG_LEVEL_INFO, PSTR("DSP: TM1650")); + TM1650Dim(); + TM1650ClearDisplay(); + + AddLog(LOG_LEVEL_INFO, PSTR("DSP: TM1650 \"%s\" with %d digits (type %d)"), TM1650Data.model_name, Settings->display_width, Settings->display_options.type); + TM1650Data.init_driver_done = true; } -} // void TM1650InitDriver(void) +} void TM1650DisplayOn () { - // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayOn()")); for (int i = 0; i < TM1650_DIGITS; i++) { TM1650Control[i] |= _BV(TM1650_CONTROL_ON); Wire.beginTransmission(TM1650_CONTROL_BASE + i); Wire.write(TM1650Control[i]); Wire.endTransmission(); } -} // void TM1650DisplayOn () +} void TM1650DisplayOff () { - // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayOff()")); for (int i = 0; i < TM1650_DIGITS; i++) { TM1650Control[i] &= ~_BV(TM1650_CONTROL_ON); Wire.beginTransmission(TM1650_CONTROL_BASE + i); Wire.write(TM1650Control[i]); Wire.endTransmission(); } -} // void TM1650DisplayOff () +} void TM1650DisplayOnOff() { @@ -170,11 +321,10 @@ void TM1650DisplayOnOff() else { TM1650DisplayOff(); } -} // void TM1650DisplayOnOff() +} void TM1650SetBrightness (unsigned int level) { - // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650SetBrightness()")); if (level > 0b111) level = 0b111; for (int i = 0; i < TM1650_DIGITS; i++) { @@ -183,41 +333,14 @@ void TM1650SetBrightness (unsigned int level) Wire.write(TM1650Control[i]); Wire.endTransmission(); } -} // void TM1650SetBrightness (unsigned int level) +} -void TM1650Dim(void) -{ - int b = GetDisplayDimmer16(); - if (b < 2) { - TM1650DisplayOff(); - } - else if (b > 14) { - TM1650DisplayOn(); - TM1650SetBrightness(0); // In TM1650, brightness 0 means max brightness (level 8). - TM1650DisplayOn(); - } - else { - // Map 2...14 to 1...7: - TM1650SetBrightness(b >> 1); - TM1650DisplayOn(); - } -} // void TM1650Dim(void) -void TM1650Clear (void) +void TM1650DisplayText (char *text) // Text shall match regex (([^.]?\.?){0,4}\0), e.g., 123.4 or 8.8.8.8 for full digit { - // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650Clear()")); - for (int i = 0; i < TM1650_DIGITS; i++) { - TM1650Display[i] = 0; - Wire.beginTransmission(TM1650_DISPLAY_BASE + i); - Wire.write(TM1650Display[i]); - Wire.endTransmission(); - } -} // void TM1650Clear (void) - -void TM1650DisplayText (char *text) // Text shall match regex (([^.]?\.?){0,4}\0), e.g., 123.4 -{ - // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayText(\"%s\")"), text); + //AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650DisplayText(\"%s\")"), text); for (int i = 0; i < TM1650_DIGITS; i++) { + if (*text != 0) { if (*text == '.') { TM1650Display[i] = 0; // Blank this digit, set the dot below. @@ -232,42 +355,791 @@ void TM1650DisplayText (char *text) // Text shall match regex (([^.]?\.?){0,4}\ TM1650Display[i] |= _BV(TM1650_DISPLAY_DOT); } - if (Settings->display_options.type == 2) { - TM1650Display[i] = TM1650Remap[TM1650Display[i]]; // 303WIFILC01 board has special wiring + if (T_303WIFILC01 == Settings->display_options.type) { + TM1650Display[i] = swapbits(TM1650Display[i]); // 303WIFILC01 board has special wiring } - } // if (not at end of text) - else { // No more text. + } + else { TM1650Display[i] = 0; // Clear digits after the text. } Wire.beginTransmission(TM1650_DISPLAY_BASE + i); Wire.write(TM1650Display[i]); Wire.endTransmission(); - } // for (all digits) -} // void TM1650DisplayText (char *text) + } +} + +uint8_t swapbits(uint8_t n) +{ + // For model 303WiFiLC01 board has different segments wiring + // PGFEDCBA -> BFAEDCGP + + //seg EDC //seg A //seg B + return (n & 0x1C) | ((n & 0x01) << 5) | ((n & 0x02) << 6) + | ((n & 0x20) << 1) | ((n & 0x40) >> 5) | ((n & 0x80) >> 7); + //seg F //seg G //seg P +} + +void TM1650DisplayRaw (char *text) // Text shall match regex (([^.]?\.?){0,4}\0), e.g., 123.4 +{ + for (int i = 0; i < TM1650_DIGITS; i++) { + char c = *text++; + TM1650Display[i] = c; + //AddLog(LOG_LEVEL_DEBUG, PSTR("Raw Digit(%d - %d - %c)"), i, TM1650Display[i], TM1650Display[i]); + Wire.beginTransmission(TM1650_DISPLAY_BASE + i); + Wire.write(TM1650Display[i]); + Wire.endTransmission(); + } +} + + +/*********************************************************************************************\ +* Displays number without decimal, with/without leading zeros, specifying start-position +* and length, optionally skipping clearing display before displaying the number. +* commands: DisplayNumber num [,position {0-(Settings->display_width-1)} [,leading_zeros {0|1} [,length {1 to Settings->display_width}]]] +* DisplayNumberNC num [,position {0-(Settings->display_width-1)} [,leading_zeros {0|1} [,length {1 to Settings->display_width}]]] // "NC" --> "No Clear" +\*********************************************************************************************/ + +bool CmndTM1650Number(bool clear) +{ + char sNum[CMD_MAX_LEN]; + char sLeadingzeros[CMD_MAX_LEN]; + char sPosition[CMD_MAX_LEN]; + char sLength[CMD_MAX_LEN]; + uint8_t length = 0; + bool leadingzeros = false; + uint8_t position = 0; + + uint32_t num = 0; + + switch (ArgC()) + { + case 4: + subStr(sLength, XdrvMailbox.data, ",", 4); + length = atoi(sLength); + case 3: + subStr(sLeadingzeros, XdrvMailbox.data, ",", 3); + leadingzeros = atoi(sLeadingzeros); + case 2: + subStr(sPosition, XdrvMailbox.data, ",", 2); + position = atoi(sPosition); + case 1: + subStr(sNum, XdrvMailbox.data, ",", 1); + num = TextToInt(sNum); + } + + if ((position < 0) || (position > (Settings->display_width - 1))) + position = 0; + + AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: num %d, pos %d, lead %d, len %d"), num, position, leadingzeros, length); + + if (clear) + TM1650ClearDisplay(); + + char txt[30]; + snprintf_P(txt, sizeof(txt), PSTR("%d"), num); + if (!length) + length = strlen(txt); + if ((length < 0) || (length > Settings->display_width)) + length = Settings->display_width; + + char pad = (leadingzeros ? '0' : ' '); + uint32_t i = position; + + char text[TM1650_DIGITS + 1]; + + //write empty pos + for (uint32_t j=0; j < position; j++) + { + if (j >= Settings->display_width) + break; + text[j] = ' '; + } + + //write pads + for (; i < position + (length - strlen(txt)); i++) + { + if (i >= Settings->display_width) + break; + text[i] = pad; + } + + //write digits + for (uint32_t j = 0; i < position + length; i++, j++) + { + if (i >= Settings->display_width) + break; + if (txt[j] == 0) + break; + if (txt[j] == '.') { + i--; + continue; + } + text[i] = txt[j]; + } + + text[i] = 0; //string termination + + TM1650DisplayText(text); + return true; +} + + +/*********************************************************************************************\ +* Displays number with decimal, specifying position, precision and length, +* optionally skipping clearing display before displaying the number. +* commands: DisplayFloat num [,position {0-(Settings->display_width-1)} [,precision {0-Settings->display_width} [,length {1 to Settings->display_width}]]] +* DisplayFloatNC num [,position {0-(Settings->display_width-1)} [,precision {0-Settings->display_width} [,length {1 to Settings->display_width}]]] // "NC" --> "No Clear" +\*********************************************************************************************/ + +bool CmndTM1650Float(bool clear) +{ + + char sNum[CMD_MAX_LEN]; + char sPrecision[CMD_MAX_LEN]; + char sPosition[CMD_MAX_LEN]; + char sLength[CMD_MAX_LEN]; + uint8_t length = 0; + uint8_t precision = Settings->display_width-1; + uint8_t position = 0; + + float fnum = 0.0f; + + switch (ArgC()) + { + case 4: + subStr(sLength, XdrvMailbox.data, ",", 4); + length = atoi(sLength); + case 3: + subStr(sPrecision, XdrvMailbox.data, ",", 3); + precision = atoi(sPrecision); + case 2: + subStr(sPosition, XdrvMailbox.data, ",", 2); + position = atoi(sPosition); + case 1: + subStr(sNum, XdrvMailbox.data, ",", 1); + fnum = CharToFloat(sNum); + } + + if ((position < 0) || (position > (Settings->display_width))) + position = 0; + if ((precision < 0) || (precision >= Settings->display_width)) + precision = Settings->display_width-1; + + if (clear) + TM1650ClearDisplay(); + + char txt[30]; + ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), precision, &fnum); + + if (!length) + length = strlen(txt); + if ((length <= 0) || (length > Settings->display_width)) + length = Settings->display_width; + + AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: num %4_f, pos %d, prec %d, len %d, txt %s"), &fnum, position, precision, length, txt); + + uint32_t i = position; + uint32_t dots = 0; + char text[TM1650_DIGITS + 1 + 1]; + + //write empty pos + for (uint32_t j=0; j < position; j++) + { + if (j >= Settings->display_width) + break; + text[j] = ' '; + } + + if (T_XY_CLOCK == Settings->display_options.type) { + + for (uint32_t j = 0; i < position + length + dots; i++, j++) + { + if (txt[j] == '.') dots++; + if (i >= Settings->display_width + dots) + break; + if (txt[j] == 0) + break; + if (txt[j] == '.') { + if(i==2) { + //2nd dot ok + } + else if(i==3){ + //3rd dot but move do 1st + text[i] = text[i-1]; + text[i-1] = text[i-2]; + text[i-2] = txt[j]; + continue; + } + else { + //dot on 1st or 4th + AddLog(LOG_LEVEL_INFO, PSTR("TM5: Can't display this float")); + return false; + } + } + text[i] = txt[j]; + } + + } + else if (T_303WIFILC01 == Settings->display_options.type) { + //todo + AddLog(LOG_LEVEL_INFO, PSTR("TM5: DisplayFloat not implemented yet for display type: 303WifiClock")); + return false; + } + + text[i] = 0; //string termination + + TM1650DisplayText(text); + return true; +} + +// /*********************************************************************************************\ +// * Clears the display +// * Command: DisplayClear +// \*********************************************************************************************/ +bool CmndTM1650Clear(void) +{ + TM1650ClearDisplay(); + sprintf(TM1650Data.msg, PSTR("Cleared")); + XdrvMailbox.data = TM1650Data.msg; + return true; +} + +// /*********************************************************************************************\ +// * Clears the display +// \*********************************************************************************************/ +void TM1650ClearDisplay (void) +{ + for (int i = 0; i < TM1650_DIGITS; i++) { + TM1650Display[i] = 0; + Wire.beginTransmission(TM1650_DISPLAY_BASE + i); + Wire.write(TM1650Display[i]); + Wire.endTransmission(); + } +} + +/*********************************************************************************************\ +* Display scrolling text +* Command: DisplayScrollText text +\*********************************************************************************************/ +bool CmndTM1650ScrollText(void) +{ + + char sString[SCROLL_MAX_LEN + 1]; + char sMaxLoopCount[CMD_MAX_LEN]; + uint8_t maxLoopCount = 0; + + switch (ArgC()) + { + case 2: + subStr(sMaxLoopCount, XdrvMailbox.data, ",", 2); + maxLoopCount = atoi(sMaxLoopCount); + case 1: + subStr(sString, XdrvMailbox.data, ",", 1); + } + + if (maxLoopCount < 0) + maxLoopCount = 0; + + //AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: sString %s, maxLoopCount %d"), sString, maxLoopCount); + + TM1650Data.scroll_counter_max = maxLoopCount; + + if (strlen(sString) > SCROLL_MAX_LEN) + { + snprintf(TM1650Data.msg, sizeof(TM1650Data.msg), PSTR("Text too long. Length should be less than %d"), SCROLL_MAX_LEN); + XdrvMailbox.data = TM1650Data.msg; + return false; + } + else + { + snprintf(TM1650Data.scroll_text, sizeof(TM1650Data.scroll_text), PSTR(" ")); + snprintf(TM1650Data.scroll_text, Settings->display_width + sizeof(TM1650Data.scroll_text), PSTR(" %s"), &sString); + TM1650Data.scroll_text[strlen(sString) + Settings->display_width] = 0; + TM1650Data.scroll_index = 0; + TM1650Data.scroll = true; + TM1650Data.scroll_counter = 0; + return true; + } +} + +/*********************************************************************************************\ +* Sets the scroll delay for scrolling text. +* Command: DisplayScrollDelay delay {0-15} // default = 4 +\*********************************************************************************************/ +bool CmndTM1650ScrollDelay(void) +{ + if (ArgC() == 0) + { + XdrvMailbox.payload = TM1650Data.scroll_delay; + return true; + } + if (TM1650Data.scroll_delay < 0) + TM1650Data.scroll_delay = 0; + TM1650Data.scroll_delay = XdrvMailbox.payload; + return true; +} + +/*********************************************************************************************\ +* Scrolls a given string. Called every 50ms +\*********************************************************************************************/ +void TM1650ScrollText(void) +{ + if(!TM1650Data.scroll) return; + TM1650Data.iteration++; + if (TM1650Data.scroll_delay) + TM1650Data.iteration = TM1650Data.iteration % TM1650Data.scroll_delay; + else + TM1650Data.iteration = 0; + if (TM1650Data.iteration) + return; + + if (TM1650Data.scroll_index > strlen(TM1650Data.scroll_text)) + { + TM1650Data.scroll_index = 0; + TM1650Data.scroll_counter++; + if(TM1650Data.scroll_counter_max != 0 && (TM1650Data.scroll_counter >= TM1650Data.scroll_counter_max)) { + TM1650Data.scroll = false; + return; + } + } + + char text[CMD_MAX_LEN + 2 + 1]; + uint32_t i; + uint32_t j; + for (i = 0, j = TM1650Data.scroll_index; i < 1 + strlen(TM1650Data.scroll_text); i++, j++) + { + if (i > (Settings->display_width - 1)) + { + break; + } + text[i] = TM1650Data.scroll_text[j]; + } + + text[i] = 0; //string termination + + TM1650DisplayText(text); + TM1650Data.scroll_index++; +} + +/*********************************************************************************************\ +* Displays a horizontal bar graph. Takes a percentage number (0-100) as input +* Command: DisplayLevel level {0-100} +\*********************************************************************************************/ +bool CmndTM1650Level(void) +{ + uint16_t val = XdrvMailbox.payload; + if ((val < LEVEL_MIN) || (val > LEVEL_MAX)) + { + Response_P(PSTR("{\"Error\":\"Level should be a number in the range [%d, %d]\"}"), LEVEL_MIN, LEVEL_MAX); + return false; + } + + char text[TM1650_DIGITS + 1]; + for (uint32_t i = 0; i < TM1650_DIGITS; i++) + { + text[i]=0; + } + + uint8_t totalBars = 2 * Settings->display_width; + AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: CmndTM1650Level totalBars=%d"), totalBars); + float barsToDisplay = totalBars * val / 100.0f; + char txt[5]; + ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), 1, &barsToDisplay); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: CmndTM1650Level barsToDisplay=%s"), txt); + char s[4]; + ext_snprintf_P(s, sizeof(s), PSTR("%0_f"), &barsToDisplay); + uint8_t numBars = atoi(s); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: CmndTM1650Level numBars %d"), numBars); + + TM1650ClearDisplay(); + + uint8_t digit = numBars / 2; + uint8_t remainder = numBars % 2; + + for (uint32_t i = 0; i < TM1650_DIGITS; i++) + { + if (i >= Settings->display_width) + break; + if(idisplay_width-1)},length {1 to Settings->display_width}, a [, b[, c[, d[...upto Settings->display_width]]]] +* where a,b,c,d... are upto Settings->display_width numbers in the range 0-255, each number (byte) +* corresponding to a single 7-segment digit. Within each byte, bit 0 is segment A, +* bit 1 is segment B etc. The function may either set the entire display +* or any desired part using the length and position parameters. +\*********************************************************************************************/ +bool CmndTM1650Raw(void) +{ + char text[TM1650_DIGITS + 1]; + for (uint32_t i = 0; i < TM1650_DIGITS; i++) + { + text[i]=0; + } + + uint8_t DATA[4] = {0, 0, 0, 0}; + + char as[CMD_MAX_LEN]; + char bs[CMD_MAX_LEN]; + char cs[CMD_MAX_LEN]; + char ds[CMD_MAX_LEN]; + + + char sLength[CMD_MAX_LEN]; + char sPos[CMD_MAX_LEN]; + + uint32_t position = 0; + uint32_t length = 0; + + switch (ArgC()) + { + case 6: + subStr(ds, XdrvMailbox.data, ",", 6); + DATA[3] = atoi(ds); + case 5: + subStr(cs, XdrvMailbox.data, ",", 5); + DATA[2] = atoi(cs); + case 4: + subStr(bs, XdrvMailbox.data, ",", 4); + DATA[1] = atoi(bs); + case 3: + subStr(as, XdrvMailbox.data, ",", 3); + DATA[0] = atoi(as); + case 2: + subStr(sLength, XdrvMailbox.data, ",", 2); + length = atoi(sLength); + case 1: + subStr(sPos, XdrvMailbox.data, ",", 1); + position = atoi(sPos); + } + + if (!length) + length = ArgC() - 2; + if (length < 0 || length > Settings->display_width) + length = Settings->display_width; + if (position < 0 || position > (Settings->display_width - 1)) + position = 0; + + AddLog(LOG_LEVEL_DEBUG, PSTR("TM5: a %d, b %d, c %d, d %d, len %d, pos %d"), + DATA[0], DATA[1], DATA[2], DATA[3], length, position); + + for (uint32_t i = position; i < position + length; i++) + { + if (i >= Settings->display_width) + break; + text[i] = DATA[i - position]; + } + + TM1650DisplayRaw(text); + + return true; +} + +/*********************************************************************************************\ +* Display a given string. +* Text can be placed at arbitrary location on the display using the length and +* position parameters without affecting the rest of the display. +* Command: DisplayText text [, position {0-(Settings->display_width-1)} [,length {1 to Settings->display_width}]] +\*********************************************************************************************/ +bool CmndTM1650Text(bool clear) +{ + char text[CMD_MAX_LEN + 2 + 1]; + char sString[CMD_MAX_LEN + 2 + 1]; + char sPosition[CMD_MAX_LEN]; + char sLength[CMD_MAX_LEN]; + uint8_t length = 0; + uint8_t position = 0; + uint8_t dots = 0; + uint8_t strLen = 0; + + switch (ArgC()) + { + case 3: + subStr(sLength, XdrvMailbox.data, ",", 3); + length = atoi(sLength); + case 2: + subStr(sPosition, XdrvMailbox.data, ",", 2); + position = atoi(sPosition); + case 1: + subStr(sString, XdrvMailbox.data, ",", 1); + } + + if ((position < 0) || (position > (Settings->display_width - 1))) + position = 0; + + strLen = strlen(sString); + + if (!length) + length = Settings->display_width; + if ((length < 0) || (length > Settings->display_width)) + length = Settings->display_width; + + if (clear) + TM1650ClearDisplay(); + + uint32_t s = 0; + uint32_t i = 0; + + for (i = 0; i < (strLen + position); i++) + { + if ((i >= (length + dots + position)) || dots > 4) { + break; + } + + if(i 2)) + return false; + + if (val == 1) { + TM1650Data.show_clock = true; + TM1650Data.clock_24 = false; + } + else if (val == 2) { + TM1650Data.show_clock = true; + TM1650Data.clock_24 = true; + } else { + TM1650Data.show_clock = false; + TM1650Data.clock_24 = false; + } + + TM1650ClearDisplay(); + return true; +} + + +/*********************************************************************************************\ +* refreshes the time if clock is displayed +\*********************************************************************************************/ +void TM1650ShowTime() +{ + TM1650Data.iteration++; + if (20 != TM1650Data.iteration) { + // every 20*50ms = 1000 ms should be enough + return; + } + TM1650Data.iteration = 0; + + char text[TM1650_DIGITS + 2 + 1]; + int i = 0; + uint8_t hour = RtcTime.hour; + uint8_t min = RtcTime.minute; + + if (!TM1650Data.clock_24) + { + if (hour > 12) + hour -= 12; + if (hour == 0) + hour = 12; + } + + text[i++] = '0' + hour / 10; + text[i++] = '0' + hour % 10; + + if (T_XY_CLOCK == Settings->display_options.type) { + text[i++] = '0' + min / 10; + if(TM1650Data.clock_blynk_dots) text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. + text[i++] = '0' + min % 10; + if(TM1650Data.clock_blynk_dots) text[i++] = '.'; // Upper half of the colon. + } + else if (T_303WIFILC01 == Settings->display_options.type) { + if(TM1650Data.clock_blynk_dots) text[i++] = '.'; // Colon for 303WIFILC01 + text[i++] = '0' + min / 10; + text[i++] = '0' + min % 10; + } + + text[i++] = 0; + + if (!TM1650Data.clock_24 && text[0] == '0') + { + text[0] = ' '; + } + + TM1650Data.clock_blynk_dots = !TM1650Data.clock_blynk_dots; + TM1650DisplayText(text); +} + +/*********************************************************************************************\ +* This function is called for all Display functions. +\*********************************************************************************************/ +bool TM1650MainFunc(uint8_t fn) +{ + bool result = false; + if(fn != FUNC_DISPLAY_SCROLLDELAY) TM1650Data.scroll = false; + if (XdrvMailbox.data_len > CMD_MAX_LEN) + { + Response_P(PSTR("{\"Error\":\"Command text too long. Please limit it to %d characters\"}"), CMD_MAX_LEN); + return false; + } + + switch (fn) + { + case FUNC_DISPLAY_CLEAR: + result = CmndTM1650Clear(); + break; + case FUNC_DISPLAY_NUMBER: + result = CmndTM1650Number(true); + break; + case FUNC_DISPLAY_NUMBERNC: + result = CmndTM1650Number(false); + break; + case FUNC_DISPLAY_FLOAT: + result = CmndTM1650Float(true); + break; + case FUNC_DISPLAY_FLOATNC: + result = CmndTM1650Float(false); + break; + case FUNC_DISPLAY_RAW: + result = CmndTM1650Raw(); + break; + case FUNC_DISPLAY_SEVENSEG_TEXT: + result = CmndTM1650Text(true); + break; + case FUNC_DISPLAY_SEVENSEG_TEXTNC: + result = CmndTM1650Text(false); + break; + case FUNC_DISPLAY_LEVEL: + result = CmndTM1650Level(); + break; + case FUNC_DISPLAY_SCROLLTEXT: + result = CmndTM1650ScrollText(); + break; + case FUNC_DISPLAY_SCROLLDELAY: + result = CmndTM1650ScrollDelay(); + break; + case FUNC_DISPLAY_CLOCK: + result = CmndTM1650Clock(); + break; + } + + return result; +} + + +void TM1650Dim(void) +{ + int brightness = GetDisplayDimmer16(); + if (brightness < 2) { + TM1650DisplayOff(); + } + else if (brightness > 14) { + TM1650DisplayOn(); + TM1650SetBrightness(0); // In TM1650, brightness 0 means max brightness (level 8). + TM1650DisplayOn(); + } + else { + // Map 2...14 to 1...7: + TM1650SetBrightness(brightness >> 1); + TM1650DisplayOn(); + } +} + + +/*********************************************************************************************/ + +#ifdef USE_DISPLAY_MODES1TO5 void TM1650Time(void) { - // AddLog(LOG_LEVEL_DEBUG, PSTR("TM1650Time()")); char text[TM1650_DIGITS + 2 + 1]; int i = 0; text[i++] = '0' + RtcTime.hour / 10; text[i++] = '0' + RtcTime.hour % 10; - if (Settings->display_options.type == 2) { - text[i++] = '.'; // Colon for 303WIFILC01 + if (T_XY_CLOCK == Settings->display_options.type) { text[i++] = '0' + RtcTime.minute / 10; + if(TM1650Data.clock_blynk_dots) text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. text[i++] = '0' + RtcTime.minute % 10; + if(TM1650Data.clock_blynk_dots) text[i++] = '.'; // Upper half of the colon. } - else { + else if (T_303WIFILC01 == Settings->display_options.type) { + if(TM1650Data.clock_blynk_dots) text[i++] = '.'; // Colon for 303WIFILC01 text[i++] = '0' + RtcTime.minute / 10; - text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. text[i++] = '0' + RtcTime.minute % 10; - text[i++] = '.'; // Upper half of the colon. } + text[i++] = 0; + + TM1650Data.clock_blynk_dots = !TM1650Data.clock_blynk_dots; TM1650DisplayText(text); -} // void TM1650Time(void) +} + +void TM1650Date(void) +{ + char text[TM1650_DIGITS + 2 + 1]; + int i = 0; + + text[i++] = '0' + RtcTime.day_of_month / 10; + text[i++] = '0' + RtcTime.day_of_month % 10; + + if (T_XY_CLOCK == Settings->display_options.type) { + text[i++] = '0' + RtcTime.month / 10; + text[i++] = '0' + RtcTime.month % 10; + text[i++] = '.'; // Lower half of the colon, depending on how the LEDs are connected to the TM1650 in the XY-Clock. + } + else if (T_303WIFILC01 == Settings->display_options.type ) { + text[i++] = '.'; // Colon for 303WIFILC01 + text[i++] = '0' + RtcTime.month / 10; + text[i++] = '0' + RtcTime.month % 10; + } + + text[i++] = 0; + + TM1650DisplayText(text); +} void TM1650Refresh(void) // Every second { @@ -276,22 +1148,30 @@ void TM1650Refresh(void) // Every second case 1: // Time TM1650Time(); break; - case 2: // Local - case 4: // Mqtt - // TM1650PrintLog(); + case 2: // Date + TM1650Date(); break; - case 3: // Local + case 3: // Time/Date + if (TasmotaGlobal.uptime % Settings->display_refresh) + { + TM1650Time(); + } + else + { + TM1650Date(); + } + break; + case 4: case 5: -// // Mqtt -// if (!TM1650PrintLog()) { -// TM1650Time(); -// } + // not in use break; } } -} // void TM1650Refresh(void) +} +#endif // USE_DISPLAY_MODES1TO5 + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -302,58 +1182,62 @@ bool Xdsp20(uint32_t function) bool result = false; - if (FUNC_DISPLAY_INIT_DRIVER == function) { + if (FUNC_DISPLAY_INIT_DRIVER == function) + { TM1650InitDriver(); } - else if (XDSP_20 == Settings->display_model) { + else if ((TM1650Data.init_driver_done || FUNC_DISPLAY_MODEL == function) + && (XDSP_20 == Settings->display_model)) { switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; + case FUNC_DISPLAY_EVERY_50_MSECOND: + if (disp_power && !Settings->display_mode) + { + if (TM1650Data.scroll) + { + TM1650ScrollText(); + } + if (TM1650Data.show_clock) + { + TM1650ShowTime(); + } + } + break; case FUNC_DISPLAY_INIT: TM1650Init(dsp_init); break; - case FUNC_DISPLAY_POWER: - TM1650DisplayOnOff(); - break; - case FUNC_DISPLAY_DIM: - TM1650Dim(); - break; - case FUNC_DISPLAY_CLEAR: - TM1650Clear(); - break; - case FUNC_DISPLAY_DRAW_STRING: - TM1650DisplayText(dsp_str); - break; #ifdef USE_DISPLAY_MODES1TO5 case FUNC_DISPLAY_EVERY_SECOND: TM1650Refresh(); break; #endif // USE_DISPLAY_MODES1TO5 -// case FUNC_DISPLAY_DRAW_HLINE: -// break; -// case FUNC_DISPLAY_DRAW_VLINE: -// break; -// case FUNC_DISPLAY_DRAW_CIRCLE: -// break; -// case FUNC_DISPLAY_FILL_CIRCLE: -// break; -// case FUNC_DISPLAY_DRAW_RECTANGLE: -// break; -// case FUNC_DISPLAY_FILL_RECTANGLE: -// break; -// case FUNC_DISPLAY_DRAW_FRAME: -// break; -// case FUNC_DISPLAY_TEXT_SIZE: -// break; -// case FUNC_DISPLAY_FONT_SIZE: -// break; -// case FUNC_DISPLAY_ROTATION: -// break; - } // switch (function) - } // else if (display model matches) + case FUNC_DISPLAY_MODEL: + result = true; + break; + case FUNC_DISPLAY_SEVENSEG_TEXT: + case FUNC_DISPLAY_CLEAR: + case FUNC_DISPLAY_NUMBER: + case FUNC_DISPLAY_FLOAT: + case FUNC_DISPLAY_NUMBERNC: + case FUNC_DISPLAY_FLOATNC: + case FUNC_DISPLAY_RAW: + case FUNC_DISPLAY_LEVEL: + case FUNC_DISPLAY_SEVENSEG_TEXTNC: + case FUNC_DISPLAY_SCROLLTEXT: + case FUNC_DISPLAY_SCROLLDELAY: + case FUNC_DISPLAY_CLOCK: + result = TM1650MainFunc(function); + break; + case FUNC_DISPLAY_DIM: + TM1650Dim(); + break; + case FUNC_DISPLAY_POWER: + TM1650DisplayOnOff(); + break; + + } + } return result; -} // bool Xdsp20(uint32_t function) +} #endif // USE_DISPLAY_TM1650 #endif // USE_DISPLAY diff --git a/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino b/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino index 41644df77..a965dbb6d 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino @@ -30,7 +30,7 @@ #define XNRG_03 3 -const uint32_t PZEM_STABILIZE = 30; // Number of seconds to stabilize configuration +const uint32_t PZEM_STABILIZE = 10; // Number of seconds to stabilize 1 pzem const uint32_t PZEM_RETRY = 5; // Number of 250 ms retries #include @@ -194,7 +194,7 @@ void PzemEvery250ms(void) case 4: // Total energy as 99999Wh Energy->import_active[Pzem.phase] = value / 1000.0f; // 99.999kWh if (Pzem.phase == Energy->phase_count -1) { - if (TasmotaGlobal.uptime > PZEM_STABILIZE) { + if (TasmotaGlobal.uptime > (PZEM_STABILIZE * ENERGY_MAX_PHASES)) { EnergyUpdateTotal(); } } @@ -229,7 +229,7 @@ void PzemEvery250ms(void) } else { Pzem.send_retry--; - if ((Energy->phase_count > 1) && (0 == Pzem.send_retry) && (TasmotaGlobal.uptime < PZEM_STABILIZE)) { + if ((Energy->phase_count > 1) && (0 == Pzem.send_retry) && (TasmotaGlobal.uptime < (PZEM_STABILIZE * ENERGY_MAX_PHASES))) { Energy->phase_count--; // Decrement phases if no response after retry within 30 seconds after restart if (TasmotaGlobal.discovery_counter) { TasmotaGlobal.discovery_counter += (PZEM_RETRY / 4) + 1; // Don't send Discovery yet, delay by 5 * 250ms + 1s diff --git a/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino b/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino index 242254d71..03c0f1e10 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino @@ -33,7 +33,7 @@ #define XNRG_05 5 const uint8_t PZEM_AC_DEVICE_ADDRESS = 0x01; // PZEM default address -const uint32_t PZEM_AC_STABILIZE = 30; // Number of seconds to stabilize configuration +const uint32_t PZEM_AC_STABILIZE = 10; // Number of seconds to stabilize 1 pzem #include TasmotaModbus *PzemAcModbus; @@ -79,7 +79,7 @@ void PzemAcEverySecond(void) Energy->power_factor[PzemAc.phase] = (float)((buffer[19] << 8) + buffer[20]) / 100.0f; // 1.00 Energy->import_active[PzemAc.phase] = (float)((buffer[15] << 24) + (buffer[16] << 16) + (buffer[13] << 8) + buffer[14]) / 1000.0f; // 4294967.295 kWh if (PzemAc.phase == Energy->phase_count -1) { - if (TasmotaGlobal.uptime > PZEM_AC_STABILIZE) { + if (TasmotaGlobal.uptime > (PZEM_AC_STABILIZE * ENERGY_MAX_PHASES)) { EnergyUpdateTotal(); } } @@ -103,7 +103,7 @@ void PzemAcEverySecond(void) } else { PzemAc.send_retry--; - if ((Energy->phase_count > 1) && (0 == PzemAc.send_retry) && (TasmotaGlobal.uptime < PZEM_AC_STABILIZE)) { + if ((Energy->phase_count > 1) && (0 == PzemAc.send_retry) && (TasmotaGlobal.uptime < (PZEM_AC_STABILIZE * ENERGY_MAX_PHASES))) { Energy->phase_count--; // Decrement phases if no response after retry within 30 seconds after restart if (TasmotaGlobal.discovery_counter) { TasmotaGlobal.discovery_counter += ENERGY_WATCHDOG + 1; // Don't send Discovery yet, delay by 4s + 1s diff --git a/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino b/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino index 1fddb68d0..a1d2cceb6 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino @@ -32,7 +32,7 @@ #define XNRG_06 6 const uint8_t PZEM_DC_DEVICE_ADDRESS = 0x01; // PZEM default address -const uint32_t PZEM_DC_STABILIZE = 30; // Number of seconds to stabilize configuration +const uint32_t PZEM_DC_STABILIZE = 10; // Number of seconds to stabilize 1 pzem #include TasmotaModbus *PzemDcModbus; @@ -76,7 +76,7 @@ void PzemDcEverySecond(void) Energy->active_power[PzemDc.channel] = (float)((buffer[9] << 24) + (buffer[10] << 16) + (buffer[7] << 8) + buffer[8]) / 10.0f; // 429496729.0 W Energy->import_active[PzemDc.channel] = (float)((buffer[13] << 24) + (buffer[14] << 16) + (buffer[11] << 8) + buffer[12]) / 1000.0f; // 4294967.295 kWh if (PzemDc.channel == Energy->phase_count -1) { - if (TasmotaGlobal.uptime > PZEM_DC_STABILIZE) { + if (TasmotaGlobal.uptime > (PZEM_DC_STABILIZE * ENERGY_MAX_PHASES)) { EnergyUpdateTotal(); } } @@ -100,7 +100,7 @@ void PzemDcEverySecond(void) } else { PzemDc.send_retry--; - if ((Energy->phase_count > 1) && (0 == PzemDc.send_retry) && (TasmotaGlobal.uptime < PZEM_DC_STABILIZE)) { + if ((Energy->phase_count > 1) && (0 == PzemDc.send_retry) && (TasmotaGlobal.uptime < (PZEM_DC_STABILIZE * ENERGY_MAX_PHASES))) { Energy->phase_count--; // Decrement channels if no response after retry within 30 seconds after restart if (TasmotaGlobal.discovery_counter) { TasmotaGlobal.discovery_counter += ENERGY_WATCHDOG + 1; // Don't send Discovery yet, delay by 4s + 1s diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino index 8f5fb7237..2f2c75795 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino @@ -231,6 +231,7 @@ typedef struct { } tAde7953Channel; struct Ade7953 { + uint32_t last_update; uint32_t voltage_rms[ADE7953_MAX_CHANNEL] = { 0, 0 }; uint32_t current_rms[ADE7953_MAX_CHANNEL] = { 0, 0 }; uint32_t active_power[ADE7953_MAX_CHANNEL] = { 0, 0 }; @@ -523,6 +524,21 @@ void Ade7953GetData(void) { } if (Energy->power_on) { // Powered on + +#ifdef USE_ESP32_SPI + float correction = 1.0f; + if (Ade7953.use_spi) { // SPI + uint32_t time = millis(); + if (Ade7953.last_update) { + uint32_t difference = time - Ade7953.last_update; + correction = (float)difference / 1000; // Correction to 1 second + +// AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Correction %4_f"), &correction); + } + Ade7953.last_update = time; + } +#endif // USE_ESP32_SPI + float divider; for (uint32_t channel = 0; channel < Energy->phase_count; channel++) { Energy->data_valid[channel] = 0; @@ -557,6 +573,14 @@ void Ade7953GetData(void) { divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration; Energy->apparent_power[channel] = (float)apparent_power[channel] / divider; +#ifdef USE_ESP32_SPI + if (Ade7953.use_spi) { // SPI + Energy->active_power[channel] /= correction; + Energy->reactive_power[channel] /= correction; + Energy->apparent_power[channel] /= correction; + } +#endif // USE_ESP32_SPI + if (0 == Energy->active_power[channel]) { Energy->current[channel] = 0; } else { @@ -836,6 +860,7 @@ bool Xnrg07(uint32_t function) { bool result = false; switch (function) { +#ifdef USE_ESP32_SPI case FUNC_ENERGY_EVERY_SECOND: // Use energy interrupt timer (fails on SPI) if (!Ade7953.use_spi) { // No SPI Ade7953EnergyEverySecond(); @@ -846,6 +871,11 @@ bool Xnrg07(uint32_t function) { Ade7953EnergyEverySecond(); } break; +#else // ESP8266 + case FUNC_ENERGY_EVERY_SECOND: // Use energy interrupt timer + Ade7953EnergyEverySecond(); + break; +#endif // USE_ESP32_SPI case FUNC_COMMAND: result = Ade7953Command(); break; diff --git a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino index e3c5b9b76..9264be095 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino @@ -203,56 +203,19 @@ void Sdm220Reset(void) Sdm120.phase_angle = 0; } -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM220[] PROGMEM = - "{s}" D_IMPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - "{s}" D_EXPORT_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}"; -#endif // USE_WEBSERVER - -/* void Sdm220Show(bool json) { if (isnan(Sdm120.import_active)) { return; } - char import_active_chr[FLOATSZ]; - dtostrfd(Sdm120.import_active, Settings->flag2.energy_resolution, import_active_chr); - char import_reactive_chr[FLOATSZ]; - dtostrfd(Sdm120.import_reactive, Settings->flag2.energy_resolution, import_reactive_chr); - char export_reactive_chr[FLOATSZ]; - dtostrfd(Sdm120.export_reactive, Settings->flag2.energy_resolution, export_reactive_chr); - char phase_angle_chr[FLOATSZ]; - dtostrfd(Sdm120.phase_angle, 2, phase_angle_chr); - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s"), - import_active_chr, import_reactive_chr, export_reactive_chr, phase_angle_chr); + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s"), EnergyFmt(&Sdm120.import_active, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_REACTIVE "\":%s"), EnergyFmt(&Sdm120.import_reactive, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_REACTIVE "\":%s"), EnergyFmt(&Sdm120.export_reactive, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s"), EnergyFmt(&Sdm120.phase_angle, 2)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_SDM220, import_reactive_chr, export_reactive_chr, phase_angle_chr); -#endif // USE_WEBSERVER - } -} -*/ - -void Sdm220Show(bool json) { - if (isnan(Sdm120.import_active)) { return; } - - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - char value4_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_ACTIVE "\":%s,\"" D_JSON_IMPORT_REACTIVE "\":%s,\"" D_JSON_EXPORT_REACTIVE "\":%s,\"" D_JSON_PHASE_ANGLE "\":%s"), - EnergyFormat(value_chr, &Sdm120.import_active, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, &Sdm120.import_reactive, Settings->flag2.energy_resolution), - EnergyFormat(value3_chr, &Sdm120.export_reactive, Settings->flag2.energy_resolution), - EnergyFormat(value4_chr, &Sdm120.phase_angle, 2)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_SDM220, WebEnergyFormat(value_chr, &Sdm120.import_reactive, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value2_chr, &Sdm120.export_reactive, Settings->flag2.energy_resolution, 2), - WebEnergyFormat(value3_chr, &Sdm120.phase_angle, 2)); + WSContentSend_PD(HTTP_SNS_IMPORT_REACTIVE, WebEnergyFmt(&Sdm120.import_reactive, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_EXPORT_REACTIVE, WebEnergyFmt(&Sdm120.export_reactive, Settings->flag2.energy_resolution, 2)); + WSContentSend_PD(HTTP_SNS_PHASE_ANGLE, WebEnergyFmt(&Sdm120.phase_angle, 2)); #endif // USE_WEBSERVER } } @@ -273,11 +236,7 @@ bool Xnrg08(uint32_t function) Sdm220Show(1); break; #ifdef USE_WEBSERVER -#ifdef USE_ENERGY_COLUMN_GUI case FUNC_WEB_COL_SENSOR: -#else // not USE_ENERGY_COLUMN_GUI - case FUNC_WEB_SENSOR: -#endif // USE_ENERGY_COLUMN_GUI Sdm220Show(0); break; #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino index 5be6cc2b2..9d56c7b08 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino @@ -236,44 +236,14 @@ void FifLEReset(void) Le01mr.total_reactive = 0; } -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_LE01MR[] PROGMEM = - "{s}" D_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}" - "{s}" D_TOTAL_REACTIVE "{m}%s " D_UNIT_KWARH "{e}" - ; -#endif // USE_WEBSERVER - -/* void FifLEShow(bool json) { - char total_reactive_chr[FLOATSZ]; - dtostrfd(Le01mr.total_reactive, Settings->flag2.energy_resolution, total_reactive_chr); - char total_active_chr[FLOATSZ]; - dtostrfd(Le01mr.total_active, Settings->flag2.energy_resolution, total_active_chr); - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s"), - total_active_chr, total_reactive_chr); + ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s"), EnergyFmt(&Le01mr.total_active, Settings->flag2.energy_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_REACTIVE "\":%s"), EnergyFmt(&Le01mr.total_reactive, Settings->flag2.energy_resolution)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_LE01MR, total_active_chr, total_reactive_chr); -#endif // USE_WEBSERVER - } -} -*/ - -void FifLEShow(bool json) { - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_TOTAL_ACTIVE "\":%s,\"" D_JSON_TOTAL_REACTIVE "\":%s"), - EnergyFormat(value_chr, &Le01mr.total_active, Settings->flag2.energy_resolution), - EnergyFormat(value2_chr, &Le01mr.total_reactive, Settings->flag2.energy_resolution)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_LE01MR, WebEnergyFormat(value_chr, &Le01mr.total_active, Settings->flag2.energy_resolution), - WebEnergyFormat(value2_chr, &Le01mr.total_reactive, Settings->flag2.energy_resolution)); - + WSContentSend_PD(HTTP_SNS_TOTAL_ACTIVE, WebEnergyFmt(&Le01mr.total_active, Settings->flag2.energy_resolution)); + WSContentSend_PD(HTTP_SNS_TOTAL_REACTIVE, WebEnergyFmt(&Le01mr.total_reactive, Settings->flag2.energy_resolution)); #endif // USE_WEBSERVER } } @@ -294,11 +264,7 @@ bool Xnrg13(uint32_t function) FifLEShow(1); break; #ifdef USE_WEBSERVER -#ifdef USE_ENERGY_COLUMN_GUI case FUNC_WEB_COL_SENSOR: -#else // not USE_ENERGY_COLUMN_GUI - case FUNC_WEB_SENSOR: -#endif // USE_ENERGY_COLUMN_GUI FifLEShow(0); break; #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino index c25025197..bc40715b4 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino @@ -45,10 +45,10 @@ // Json Command //const char S_JSON_TELEINFO_COMMAND_STRING[] PROGMEM = "{\"" D_NAME_TELEINFO "\":{\"%s\":%s}}"; //const char S_JSON_TELEINFO_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_TELEINFO "\":{\"%s\":%d}}"; -const char TELEINFO_COMMAND_SETTINGS[] PROGMEM = "TIC: Settings Mode:%s, RX:%s, EN:%s, Raw:%s, Skip:%d, Limit:%d"; +const char TELEINFO_COMMAND_SETTINGS[] PROGMEM = "TIC: Settings Mode:%s, RX:%s, EN:%s, Raw:%s, Skip:%d, Limit:%d, Stats:%d"; #define MAX_TINFO_COMMAND_NAME 16+1 // Change this if one of the following kTInfo_Commands is higher then 16 char -const char kTInfo_Commands[] PROGMEM = "historique|standard|noraw|full|changed|skip|limit"; +const char kTInfo_Commands[] PROGMEM = "historique|standard|noraw|full|changed|skip|limit|stats"; enum TInfoCommands { // commands for Console CMND_TELEINFO_HISTORIQUE=0, // Set Legacy mode @@ -57,7 +57,8 @@ enum TInfoCommands { // commands for Console CMND_TELEINFO_RAW_FULL, // Enable all RAW frame send CMND_TELEINFO_RAW_CHANGE, // Enable only changed values RAW frame send CMND_TELEINFO_SKIP, // Set number of frame to skip when raw mode is enabled - CMND_TELEINFO_LIMIT // Limit RAW frame to values subject to fast change (Power, Current, ...), TBD + CMND_TELEINFO_LIMIT, // Limit RAW frame to values subject to fast change (Power, Current, ...), TBD + CMND_TELEINFO_STATS // Show / clear / Enable TIC reception errors stats }; @@ -126,7 +127,7 @@ enum TInfoLabel{ LABEL_HCJB,LABEL_HPJB,LABEL_HCJW,LABEL_HPJW,LABEL_HCJR,LABEL_HPJR, LABEL_EASF03, LABEL_EASF04, LABEL_EASF05, LABEL_EASF06, LABEL_OPTARIF, LABEL_NGTF, LABEL_ISOUSC, LABEL_PREF, LABEL_PTEC, LABEL_LTARF, LABEL_NTARF, - LABEL_PAPP, LABEL_SINSTS, LABEL_IINST, LABEL_IINST1, LABEL_IINST2, LABEL_IINST3, LABEL_IRMS1, LABEL_IRMS2, LABEL_IRMS3, + LABEL_PAPP, LABEL_SINSTS, LABEL_SINSTS1, LABEL_SINSTS2, LABEL_SINSTS3, LABEL_IINST, LABEL_IINST1, LABEL_IINST2, LABEL_IINST3, LABEL_IRMS1, LABEL_IRMS2, LABEL_IRMS3, LABEL_TENSION, LABEL_URMS1, LABEL_URMS2, LABEL_URMS3, LABEL_IMAX, LABEL_IMAX1, LABEL_IMAX2, LABEL_IMAX3, LABEL_PMAX, LABEL_SMAXSN, LABEL_DEMAIN,LABEL_MSG1,LABEL_MSG2,LABEL_STGE, @@ -139,7 +140,7 @@ const char kLabel[] PROGMEM = "|BBRHCJB|BBRHPJB|BBRHCJW|BBRHPJW|BBRHCJR|BBRHPJR" "|EASF03|EASF04|EASF05|EASF06" "|OPTARIF|NGTF|ISOUSC|PREF|PTEC|LTARF|NTARF" - "|PAPP|SINSTS|IINST|IINST1|IINST2|IINST3|IRMS1|IRMS2|IRMS3" + "|PAPP|SINSTS|SINSTS1|SINSTS2|SINSTS3|IINST|IINST1|IINST2|IINST3|IRMS1|IRMS2|IRMS3" "|TENSION|URMS1|URMS2|URMS3" "|IMAX|IMAX1|IMAX2|IMAX3|PMAX|SMAXSN" "|DEMAIN|MSG1|MSG2|STGE" @@ -155,6 +156,7 @@ PROGMEM = "|PJOURF+1" "|MSG1" + "|PPOINTE" "|" ; @@ -197,6 +199,10 @@ const char HTTP_ENERGY_LOAD_BAR[] PROGMEM = "
" "%d%%
" ""; +const char HTTP_ENERGY_STATS_TELEINFO[] PROGMEM = "{s}Bad Checksum{m}%d{e}" + "{s}Wrong Size{m}%d{e}" + "{s}Bad Format{m}%d{e}" + "{s}Interruption{m}%d{e}" ; #endif // USE_WEBSERVER @@ -319,10 +325,18 @@ void DataCallback(struct _ValueList * me, uint8_t flags) } // Power P - else if (ilabel == LABEL_PAPP || ilabel == LABEL_SINSTS) + else if (ilabel == LABEL_PAPP || ilabel == LABEL_SINSTS || ilabel == LABEL_SINSTS1 || ilabel == LABEL_SINSTS2 || ilabel == LABEL_SINSTS3) { - Energy->active_power[0] = (float) atoi(me->value);; - AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s, now %d"), me->value, (int) Energy->active_power[0]); + float power = (float) atoi(me->value); + AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Power %s=%s, now %d"), me->name, me->value, (int) power); + + if (ilabel == LABEL_PAPP || ilabel == LABEL_SINSTS1 || (ilabel == LABEL_SINSTS && Energy->phase_count == 1)) { + Energy->active_power[0] = power; + } else if (ilabel == LABEL_SINSTS2) { + Energy->active_power[1] = power; + } else if (ilabel == LABEL_SINSTS3) { + Energy->active_power[2] = power; + } } // Ok now not so real time values Does this value is new or changed? @@ -527,53 +541,60 @@ bool ResponseAppendTInfo(char sep, bool all) if (me->name && me->value && *me->name && *me->value) { - // Does this label blacklisted ? - if (!isBlacklistedLabel(me->name)) { + // Check back checksum in case of any memory corruption + if (me->checksum==tinfo.calcChecksum(me->name, me->value)) { - // Add values only if we want all data or if data has changed - if (all || ( Settings->teleinfo.raw_report_changed && (me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) ) ) { + // Does this label blacklisted ? + if (!isBlacklistedLabel(me->name)) { - isNumber = true; - hasValue = true; - p = me->value; + // Add values only if we want all data or if data has changed + if (all || ( Settings->teleinfo.raw_report_changed && (me->flags & (TINFO_FLAGS_UPDATED | TINFO_FLAGS_ADDED | TINFO_FLAGS_ALERT) ) ) ) { - // Specific treatment serial number don't convert to number later - if (strcmp(me->name, "ADCO")==0 || strcmp(me->name, "ADSC")==0) { - isNumber = false; - } else { - // check if value is number - while (*p && isNumber) { - if ( *p < '0' || *p > '9' ) { - isNumber = false; - } - p++; - } - } + isNumber = true; + hasValue = true; + p = me->value; - // Avoid unneeded space - if (sep == ' ') { - ResponseAppend_P( PSTR("\"%s\":"), me->name ); - } else { - ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name ); - } - - if (!isNumber) { - // Some values contains space - if (strcmp(me->name, "NGTF")==0 || strcmp(me->name, "LTARF")==0 || strcmp(me->name, "MSG1")==0) { - char trimmed_value[strlen(me->value)+1]; - strcpy(trimmed_value, me->value); - ResponseAppend_P( PSTR("\"%s\""), Trim(trimmed_value) ); + // Specific treatment serial number don't convert to number later + if (strcmp(me->name, "ADCO")==0 || strcmp(me->name, "ADSC")==0) { + isNumber = false; } else { - ResponseAppend_P( PSTR("\"%s\""), me->value ); + // check if value is number + while (*p && isNumber) { + if ( *p < '0' || *p > '9' ) { + isNumber = false; + } + p++; + } } - } else { - ResponseAppend_P( PSTR("%ld"), atol(me->value)); - } + // Avoid unneeded space + if (sep == ' ') { + ResponseAppend_P( PSTR("\"%s\":"), me->name ); + } else { + ResponseAppend_P( PSTR("%c\"%s\":"), sep, me->name ); + } - // Now JSON separator is needed - sep =','; + if (!isNumber) { + // Some values contains space + if (strcmp(me->name, "NGTF")==0 || strcmp(me->name, "LTARF")==0 || strcmp(me->name, "MSG1")==0) { + char trimmed_value[strlen(me->value)+1]; + strcpy(trimmed_value, me->value); + ResponseAppend_P( PSTR("\"%s\""), Trim(trimmed_value) ); + } else { + ResponseAppend_P( PSTR("\"%s\""), me->value ); + } + + } else { + ResponseAppend_P( PSTR("%ld"), atol(me->value)); + } + + // Now JSON separator is needed + sep =','; + } } + + } else { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: bad checksum for %s"), me->name); } } } @@ -790,7 +811,7 @@ bool TInfoCmd(void) { sprintf_P(en_pin, PSTR("GPIO%d"), Pin(GPIO_TELEINFO_ENABLE)); } - AddLog(LOG_LEVEL_INFO, TELEINFO_COMMAND_SETTINGS, mode_name, rx_pin, en_pin, raw_name, Settings->teleinfo.raw_skip, Settings->teleinfo.raw_limit); + AddLog(LOG_LEVEL_INFO, TELEINFO_COMMAND_SETTINGS, mode_name, rx_pin, en_pin, raw_name, Settings->teleinfo.raw_skip, Settings->teleinfo.raw_limit, Settings->teleinfo.show_stats); serviced = true; @@ -897,6 +918,34 @@ bool TInfoCmd(void) { } break; + case CMND_TELEINFO_STATS: { + char stats_name[MAX_TINFO_COMMAND_NAME]; + // Get the raw name + GetTextIndexed(stats_name, MAX_TINFO_COMMAND_NAME, command_code, kTInfo_Commands); + int l = strlen(stats_name); + // At least "EnergyConfig Stats" plus one space and one (or more) digit + // so "EnergyConfig Stats" or "EnergyConfig Stats 0" + if ( pValue ) { + int value = atoi(pValue); + if (value==0 || value==1) { + Settings->teleinfo.show_stats = value ; + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Show stats=%d"), value); + } else if (value == 2) { + tinfo.clearStats(); + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Stats cleared")); + } else { + AddLog(LOG_LEVEL_INFO, PSTR("TIC: bad Stats param '%d'"), value); + } + } + // Show stats + AddLog(LOG_LEVEL_INFO, PSTR("TIC: Frame error CheckSum:%d Size:%d Format:%d Interrupt:%d"), + tinfo.getChecksumErrorCount(), + tinfo.getFrameSizeErrorCount(), + tinfo.getFrameFormatErrorCount(), + tinfo.getFrameInterruptedCount() ); + } + break; + default: AddLog(LOG_LEVEL_INFO, PSTR("TIC: bad cmd param '%s'"), pParam); break; @@ -1127,7 +1176,7 @@ void TInfoShow(bool json) char phase_color[8]; for (int i=0; iphase_count ; i++ ) { - percent = (int) ((Energy->current[i]*100.0f) / isousc) ; + percent = (int) ((Energy->current[i]*100.0f) / (isousc / Energy->phase_count)) ; if (percent > 100) { percent = 100; } @@ -1234,6 +1283,11 @@ void TInfoShow(bool json) WSContentSend_P(HTTP_ENERGY_ID_TELEINFO, serialNumber); } + if (Settings->teleinfo.show_stats) { + WSContentSend_P(HTTP_ENERGY_STATS_TELEINFO, tinfo.getChecksumErrorCount(), tinfo.getFrameSizeErrorCount() + , tinfo.getFrameFormatErrorCount(), tinfo.getFrameInterruptedCount()); + } + #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino index b058b09c0..b5f3c0379 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino @@ -151,56 +151,19 @@ void Sdm72DrvInit(void) } #ifdef SDM72_IMPEXP - -/* -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM72[] PROGMEM = - "{s}" D_EXPORT_POWER "{m}%*_f " D_UNIT_WATT "{e}" - "{s}" D_IMPORT_POWER "{m}%*_f " D_UNIT_WATT "{e}"; -#endif // USE_WEBSERVER - void Sdm72Show(bool json) { if (isnan(Sdm72.total_active)) { return; } if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_POWER "\":%*_f,\"" D_JSON_IMPORT_POWER "\":%*_f"), - Settings->flag2.wattage_resolution, &Sdm72.export_power, - Settings->flag2.wattage_resolution, &Sdm72.import_power); + ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_POWER "\":%s"), EnergyFmt(&Sdm72.export_power, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_IMPORT_POWER "\":%s"), EnergyFmt(&Sdm72.import_power, Settings->flag2.wattage_resolution)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_SDM72, - Settings->flag2.wattage_resolution, &Sdm72.export_power, - Settings->flag2.wattage_resolution, &Sdm72.import_power); + WSContentSend_PD(HTTP_SNS_EXPORT_POWER, WebEnergyFmt(&Sdm72.export_power, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_IMPORT_POWER, WebEnergyFmt(&Sdm72.import_power, Settings->flag2.wattage_resolution)); #endif // USE_WEBSERVER } } -*/ - -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM72[] PROGMEM = - "{s}" D_EXPORT_POWER "{m}%s" D_UNIT_WATT "{e}" - "{s}" D_IMPORT_POWER "{m}%s" D_UNIT_WATT "{e}"; -#endif // USE_WEBSERVER - -void Sdm72Show(bool json) { - if (isnan(Sdm72.total_active)) { return; } - - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_EXPORT_POWER "\":%s,\"" D_JSON_IMPORT_POWER "\":%s"), - EnergyFormat(value_chr, &Sdm72.export_power, Settings->flag2.wattage_resolution), - EnergyFormat(value2_chr, &Sdm72.import_power, Settings->flag2.wattage_resolution)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_SDM72, WebEnergyFormat(value_chr, &Sdm72.export_power, Settings->flag2.wattage_resolution), - WebEnergyFormat(value2_chr, &Sdm72.import_power, Settings->flag2.wattage_resolution)); - -#endif // USE_WEBSERVER - } -} - #endif // SDM72_IMPEXP /*********************************************************************************************\ @@ -220,11 +183,7 @@ bool Xnrg18(uint32_t function) Sdm72Show(1); break; #ifdef USE_WEBSERVER -#ifdef USE_ENERGY_COLUMN_GUI case FUNC_WEB_COL_SENSOR: -#else // not USE_ENERGY_COLUMN_GUI - case FUNC_WEB_SENSOR: -#endif // USE_ENERGY_COLUMN_GUI Sdm72Show(0); break; #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino index f851b8110..5c6cd19ab 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino @@ -216,48 +216,16 @@ void Sdm230Reset(void) } #ifdef SDM230_MORE_REGS -#ifdef USE_WEBSERVER -const char HTTP_ENERGY_SDM230[] PROGMEM = - "{s}" D_PHASE_ANGLE "{m}%s " D_UNIT_ANGLE "{e}" - "{s}" D_MAX_POWER "{m}%s " D_UNIT_WATT "{e}" - "{s}" D_RESETTABLE_TOTAL_ACTIVE "{m}%s " D_UNIT_KILOWATTHOUR "{e}"; -#endif // USE_WEBSERVER - -/* void Sdm230Show(bool json) { - char phase_angle_chr[FLOATSZ]; - dtostrfd(Sdm230.phase_angle, 2, phase_angle_chr); - char maximum_demand_chr[FLOATSZ]; - dtostrfd(Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution, maximum_demand_chr); - char resettable_energy_chr[FLOATSZ]; - dtostrfd(Sdm230.resettable_total_energy, Settings->flag2.energy_resolution, resettable_energy_chr); - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s,\"" D_JSON_POWERMAX "\":%s,\"" D_JSON_RESETTABLE_TOTAL_ACTIVE "\":%s"), - phase_angle_chr, maximum_demand_chr, resettable_energy_chr); + ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s"), EnergyFmt(&Sdm230.phase_angle, 2)); + ResponseAppend_P(PSTR(",\"" D_JSON_POWERMAX "\":%s"), EnergyFmt(&Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution)); + ResponseAppend_P(PSTR(",\"" D_JSON_RESETTABLE_TOTAL_ACTIVE "\":%s"), EnergyFmt(&Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ENERGY_SDM230, phase_angle_chr, maximum_demand_chr, resettable_energy_chr); -#endif // USE_WEBSERVER - } -} -*/ - -void Sdm230Show(bool json) { - char value_chr[GUISZ]; - char value2_chr[GUISZ]; - char value3_chr[GUISZ]; - - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_PHASE_ANGLE "\":%s,\"" D_JSON_POWERMAX "\":%s,\"" D_JSON_RESETTABLE_TOTAL_ACTIVE "\":%s"), - EnergyFormat(value_chr, &Sdm230.phase_angle, 2), - EnergyFormat(value2_chr, &Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution), - EnergyFormat(value3_chr, &Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_ENERGY_SDM230, WebEnergyFormat(value_chr, &Sdm230.phase_angle, 2), - WebEnergyFormat(value2_chr, &Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution), - WebEnergyFormat(value3_chr, &Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); + WSContentSend_PD(HTTP_SNS_PHASE_ANGLE, WebEnergyFmt(&Sdm230.phase_angle, 2)); + WSContentSend_PD(HTTP_SNS_MAX_POWER, WebEnergyFmt(&Sdm230.maximum_total_demand_power_active, Settings->flag2.wattage_resolution)); + WSContentSend_PD(HTTP_SNS_RSTTBL_TOTAL_ACTIVE, WebEnergyFmt(&Sdm230.resettable_total_energy, Settings->flag2.energy_resolution)); #endif // USE_WEBSERVER } } @@ -280,11 +248,7 @@ bool Xnrg21(uint32_t function) Sdm230Show(1); break; #ifdef USE_WEBSERVER -#ifdef USE_ENERGY_COLUMN_GUI case FUNC_WEB_COL_SENSOR: -#else // not USE_ENERGY_COLUMN_GUI - case FUNC_WEB_SENSOR: -#endif // USE_ENERGY_COLUMN_GUI Sdm230Show(0); break; #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino index d4799833f..08fb4a11f 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino @@ -444,13 +444,17 @@ bool Ade7880SetCalibrate(void) { uint32_t start = millis(); #endif // ADE7880_PROFILING - int reset = Pin(GPIO_RESET); - if (-1 == reset) { reset = 16; } // Reset pin ADE7880 in Shelly 3EM - pinMode(reset, OUTPUT); - digitalWrite(reset, 0); - delay(1); - digitalWrite(reset, 1); - pinMode(reset, INPUT); + int pin_reset = Pin(GPIO_RESET); +#ifdef ESP8266 + if (-1 == pin_reset) { pin_reset = 16; } // Reset pin ADE7880 in Shelly 3EM +#endif + if (pin_reset >= 0) { + pinMode(pin_reset, OUTPUT); + digitalWrite(pin_reset, 0); + delay(1); + digitalWrite(pin_reset, 1); + pinMode(pin_reset, INPUT); + } Ade7880.cycle_count = 2; // Skip first two cycles @@ -737,19 +741,12 @@ bool Ade7880Command(void) { \*********************************************************************************************/ #ifdef ADE7880_MORE_REGS -#ifdef USE_WEBSERVER -const char HTTP_ADE7880_CURRENT[] PROGMEM = "{s}" D_CURRENT_NEUTRAL "{m}%s " D_UNIT_AMPERE "{e}"; -#endif // USE_WEBSERVER - void Ade7880Show(bool json) { - char value_chr[GUISZ]; - if (json) { - ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT_NEUTRAL "\":%s"), - EnergyFormat(value_chr, &Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); + ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT_NEUTRAL "\":%s"), EnergyFmt(&Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_ADE7880_CURRENT, WebEnergyFormat(value_chr, &Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); + WSContentSend_PD(HTTP_SNS_CURRENT_N, WebEnergyFmt(&Ade7880.neutral_current, Settings->flag2.current_resolution, 1)); #endif // USE_WEBSERVER } } @@ -776,11 +773,7 @@ bool Xnrg23(uint32_t function) { Ade7880Show(1); break; #ifdef USE_WEBSERVER -#ifdef USE_ENERGY_COLUMN_GUI case FUNC_WEB_COL_SENSOR: -#else // not USE_ENERGY_COLUMN_GUI - case FUNC_WEB_SENSOR: -#endif // USE_ENERGY_COLUMN_GUI Ade7880Show(0); break; #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino b/tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino index 8af5ecb85..ac681fbf3 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_24_esp32_biopdu.ino @@ -69,7 +69,7 @@ #define BIOPDU_MAX_PHASES 6 // BioPDU support max six phases/channels const uint8_t BIOPDU_DEVICE_ADDRESS = 0x01; // PZEM default address -const uint32_t BIOPDU_STABILIZE = 30; // Number of seconds to stabilize configuration +const uint32_t BIOPDU_STABILIZE = 10; // Number of seconds to stabilize 1 device #include TasmotaModbus *BioPduModbus; @@ -273,7 +273,7 @@ bool Xnrg24(uint32_t function) } // Fix start up issue #5875 break; case FUNC_ENERGY_EVERY_SECOND: - if (TasmotaGlobal.uptime > BIOPDU_STABILIZE) + if (TasmotaGlobal.uptime > (BIOPDU_STABILIZE * BIOPDU_MAX_PHASES)) { BioPduEverySecond(); } diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino index 8dde49a5a..a97da8f83 100644 --- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino +++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino @@ -799,7 +799,6 @@ uint32_t EnergyModbusResolution(uint32_t resolution) { } void EnergyModbusShow(bool json) { - char value_chr[GUISZ]; float values[ENERGY_MAX_PHASES]; for (uint32_t i = 0; i < NrgMbsParam.user_adds; i++) { uint32_t reg_index = NRG_MBS_MAX_REGS + i; @@ -829,16 +828,12 @@ void EnergyModbusShow(bool json) { #ifdef ENERGY_MODBUS_DEBUG_SHOW AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: resolution %d -> %d"), NrgMbsUser[i].resolution, resolution); #endif - if (json) { - ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFormat(value_chr, values, resolution, single)); + ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFmt(values, resolution, single)); #ifdef USE_WEBSERVER } else { if (strlen(NrgMbsUser[i].gui_name)) { // Skip empty GUI names - WSContentSend_PD(PSTR("{s}%s{m}%s %s{e}"), - NrgMbsUser[i].gui_name, - WebEnergyFormat(value_chr, values, resolution, single), - NrgMbsUser[i].gui_unit); + WSContentSend_PD(PSTR("{s}%s{m}%s %s{e}"), NrgMbsUser[i].gui_name, WebEnergyFmt(values, resolution, single), NrgMbsUser[i].gui_unit); } #endif // USE_WEBSERVER } @@ -864,11 +859,7 @@ bool Xnrg29(uint32_t function) { EnergyModbusShow(1); break; #ifdef USE_WEBSERVER -#ifdef USE_ENERGY_COLUMN_GUI case FUNC_WEB_COL_SENSOR: -#else // not USE_ENERGY_COLUMN_GUI - case FUNC_WEB_SENSOR: -#endif // USE_ENERGY_COLUMN_GUI EnergyModbusShow(0); break; #endif // USE_WEBSERVER diff --git a/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino b/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino index 5abb6b56a..094cbb798 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino @@ -452,7 +452,7 @@ float AdcGetRange(uint32_t idx) { // formula for calibration: value, fromLow, fromHigh, toLow, toHigh // Example: 514, 632, 236, 0, 100 // int( (( - ) / ( - ) ) * ( - ) ) + ) - int adc = AdcRead(Adc[idx].pin, 2); + int adc = AdcRead(Adc[idx].pin, 5); double adcrange = ( ((double)Adc[idx].param2 - (double)adc) / ( ((double)Adc[idx].param2 - (double)Adc[idx].param1)) * ((double)Adc[idx].param3 - (double)Adc[idx].param4) + (double)Adc[idx].param4 ); return (float)adcrange; } @@ -469,7 +469,8 @@ void AdcGetCurrentPower(uint8_t idx, uint8_t factor) { uint16_t analog_max = 0; if (0 == Adc[idx].param1) { - for (uint32_t i = 0; i < samples; i++) { + unsigned long tstart=millis(); + while (millis()-tstart < 35) { analog = analogRead(Adc[idx].pin); if (analog < analog_min) { analog_min = analog; @@ -477,9 +478,11 @@ void AdcGetCurrentPower(uint8_t idx, uint8_t factor) { if (analog > analog_max) { analog_max = analog; } - delay(1); } + //AddLog(0, PSTR("min: %u, max:%u, dif:%u"), analog_min, analog_max, analog_max-analog_min); Adc[idx].current = (float)(analog_max-analog_min) * ((float)(Adc[idx].param2) / 100000); + if (Adc[idx].current < (((float)Adc[idx].param4) / 10000.0)) + Adc[idx].current = 0.0; } else { analog = AdcRead(Adc[idx].pin, 5); @@ -834,7 +837,13 @@ void CmndAdcParam(void) { } char param3[FLOATSZ]; dtostrfd(((double)Adc[idx].param3)/10000, precision, param3); - ResponseAppend_P(PSTR(",%s,%d"), param3, Adc[idx].param4); + if (ADC_CT_POWER == Adc[idx].type) { + char param4[FLOATSZ]; + dtostrfd(((double)Adc[idx].param4)/10000, 3, param4); + ResponseAppend_P(PSTR(",%s,%s"), param3, param4); + } else { + ResponseAppend_P(PSTR(",%s,%d"), param3, Adc[idx].param4); + } } ResponseAppend_P(PSTR("]}")); } @@ -851,7 +860,7 @@ bool Xsns02(uint32_t function) { case FUNC_COMMAND: result = DecodeCommand(kAdcCommands, AdcCommand); break; - case FUNC_MODULE_INIT: + case FUNC_SETUP_RING2: AdcInit(); break; default: diff --git a/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino b/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino index 16bc77212..c71a47f02 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino @@ -165,6 +165,9 @@ bool Xsns04(uint32_t function) case FUNC_INIT: SonoffScInit(); break; + case FUNC_PRE_INIT: + SetSerial(19200, TS_SERIAL_8N1); + break; } } return result; diff --git a/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino b/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino index 720550137..2682ae815 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_103_sen5x.ino @@ -20,12 +20,12 @@ #ifdef USE_I2C #ifdef USE_SEN5X /*********************************************************************************************\ - * SEN5X - Gas (VOC - Volatile Organic Compounds / NOx - Nitrous Oxides) and Particulates (PPM) + * SEN5X - Gas (VOC - Volatile Organic Compounds / NOx - Nitrous Oxides) and Particulates (PM) * * Source: Sensirion SEN5X Driver + Example, and Tasmota Driver 98 by Jean-Pierre Deschamps * Adaption for TASMOTA: Tyeth Gundry * - * I2C Address: 0x59 + * I2C Address: 0x69 \*********************************************************************************************/ #define XSNS_103 103 @@ -38,8 +38,6 @@ SensirionI2CSen5x *sen5x = nullptr; struct SEN5XDATA_s { - bool sen5x_ready; - float abshum; float massConcentrationPm1p0; float massConcentrationPm2p5; float massConcentrationPm4p0; @@ -49,100 +47,62 @@ struct SEN5XDATA_s { float vocIndex; float noxIndex; } *SEN5XDATA = nullptr; + /********************************************************************************************/ -void sen5x_Init(void) -{ - if(!TasmotaGlobal.i2c_enabled){ - DEBUG_SENSOR_LOG(PSTR("I2C Not enabled, so not loading SEN5X driver.")); - return; - } +void sen5x_Init(void) { int usingI2cBus = 0; #ifdef ESP32 - if (!I2cSetDevice(SEN5X_ADDRESS, 0)) - { + if (!I2cSetDevice(SEN5X_ADDRESS, 0)) { DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 0")); - if (TasmotaGlobal.i2c_enabled_2 ){ - - if(!I2cSetDevice(SEN5X_ADDRESS, 1)){ + if (TasmotaGlobal.i2c_enabled_2 ) { + if(!I2cSetDevice(SEN5X_ADDRESS, 1)) { DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 1")); return; } usingI2cBus = 1; - } - else { + } else { return; } } #else - if (!I2cSetDevice(SEN5X_ADDRESS)) - { + if (!I2cSetDevice(SEN5X_ADDRESS)) { DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X not found, i2c bus 0")); return; } #endif - if (SEN5XDATA == nullptr) - SEN5XDATA = (SEN5XDATA_s *)calloc(1, sizeof(struct SEN5XDATA_s)); - SEN5XDATA->sen5x_ready = false; - if(sen5x == nullptr) sen5x = new SensirionI2CSen5x(); - if(usingI2cBus==1){ + + sen5x = new SensirionI2CSen5x(); + if (1 == usingI2cBus) { #ifdef ESP32 sen5x->begin(Wire1); #else sen5x->begin(Wire); #endif - } + } else { sen5x->begin(Wire); - } + } int error_stop = sen5x->deviceReset(); - if (error_stop != 0) - { + if (error_stop != 0) { DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X failed to reset device (I2C Bus %d)"), usingI2cBus); return; } // Wait 1 second for sensors to start recording + 100ms for reset command delay(1100); int error_start = sen5x->startMeasurement(); - if (error_start != 0) - { + if (error_start != 0) { DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X failed to start measurement (I2C Bus %d)"), usingI2cBus); return; } - SEN5XDATA->sen5x_ready = true; + + SEN5XDATA = (SEN5XDATA_s *)calloc(1, sizeof(struct SEN5XDATA_s)); I2cSetActiveFound(SEN5X_ADDRESS, "SEN5X", usingI2cBus); - DEBUG_SENSOR_LOG(PSTR("Sensirion SEN5X found, i2c bus %d"), usingI2cBus); -} - -// #define POW_FUNC pow -#define POW_FUNC FastPrecisePow - -float sen5x_AbsoluteHumidity(float temperature, float humidity) -{ - // 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 - float temp = NAN; - const float mw = 18.01534f; // molar mass of water g/mol - const float r = 8.31447215f; // Universal gas constant J/mol/K - - if (isnan(temperature) || isnan(humidity)) - { - return NAN; - } - - temp = POW_FUNC(2.718281828f, (17.67f * temperature) / (temperature + 243.5f)); - - // return (6.112 * temp * humidity * 2.1674) / (273.15 + temperature); //simplified version - return (6.112f * temp * humidity * mw) / ((273.15f + temperature) * r); // long version } #define SAVE_PERIOD 30 -void SEN5XUpdate(void) // Perform every second to ensure proper operation of the baseline compensation algorithm -{ +void SEN5XUpdate(void) { // Perform every second to ensure proper operation of the baseline compensation algorithm uint16_t error; char errorMessage[256]; DEBUG_SENSOR_LOG(PSTR("Running readMeasuredValues for SEN5X...")); @@ -152,121 +112,90 @@ void SEN5XUpdate(void) // Perform every second to ensure proper operation of the SEN5XDATA->massConcentrationPm10p0, SEN5XDATA->ambientHumidity, SEN5XDATA->ambientTemperature, SEN5XDATA->vocIndex, SEN5XDATA->noxIndex); - if (error) - { - AddLog(LOG_LEVEL_DEBUG, PSTR("Failed to retrieve SEN5X readings.")); - #ifdef DEBUG_TASMOTA_SENSOR - DEBUG_SENSOR_LOG(PSTR("Error trying to execute readMeasuredValues(): \n")); + if (error) { + AddLog(LOG_LEVEL_DEBUG, PSTR("S5X: Failed to retrieve readings")); +#ifdef DEBUG_TASMOTA_SENSOR + DEBUG_SENSOR_LOG(PSTR("Error trying to execute readMeasuredValues():")); errorToString(error, errorMessage, 256); DEBUG_SENSOR_LOG(errorMessage); - #endif - } - else - { -#ifdef DEBUG_TASMOTA_SENSOR + } else { DEBUG_SENSOR_LOG(PSTR("SEN5x readings:-")); - DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm1p0: %f\n"), SEN5XDATA->massConcentrationPm1p0); - DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm2p5: %f\n"), SEN5XDATA->massConcentrationPm2p5); - DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm4p0: %f\n"), SEN5XDATA->massConcentrationPm4p0); - DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm10p0: %f\n"), SEN5XDATA->massConcentrationPm10p0); - if (isnan(SEN5XDATA->ambientHumidity)) - { - DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: n/a\n")); - } - else - { - DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: %f\n"), SEN5XDATA->ambientHumidity); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm1p0: %1_f"), &SEN5XDATA->massConcentrationPm1p0); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm2p5: %1_f"), &SEN5XDATA->massConcentrationPm2p5); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm4p0: %1_f"), &SEN5XDATA->massConcentrationPm4p0); + DEBUG_SENSOR_LOG(PSTR("MassConcentrationPm10p0: %1_f"), &SEN5XDATA->massConcentrationPm10p0); + if (isnan(SEN5XDATA->ambientHumidity)) { + DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: n/a")); + } else { + DEBUG_SENSOR_LOG(PSTR("AmbientHumidity: %*_f"), 2, &SEN5XDATA->ambientHumidity); } - if (isnan(SEN5XDATA->ambientTemperature)) - { - DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: n/a\n")); + if (isnan(SEN5XDATA->ambientTemperature)) { + DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: n/a")); + } else { + DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: %*_f"), 2, &SEN5XDATA->ambientTemperature); } - else - { - DEBUG_SENSOR_LOG(PSTR("AmbientTemperature: %f\n"), SEN5XDATA->ambientTemperature); + + if (isnan(SEN5XDATA->vocIndex)) { + DEBUG_SENSOR_LOG(PSTR("VocIndex: n/a")); + } else { + DEBUG_SENSOR_LOG(PSTR("VocIndex: %*_f"), 0, &SEN5XDATA->vocIndex); } - - if (isnan(SEN5XDATA->vocIndex)) - { - DEBUG_SENSOR_LOG(PSTR("VocIndex: n/a\n")); - } - else - { - DEBUG_SENSOR_LOG(PSTR("VocIndex: %f\n"), SEN5XDATA->vocIndex); - } - - if (isnan(SEN5XDATA->noxIndex)) - { - DEBUG_SENSOR_LOG(PSTR("NoxIndex: n/a\n")); - } - else - { - DEBUG_SENSOR_LOG(PSTR("NoxIndex: %f\n"), SEN5XDATA->noxIndex); + + if (isnan(SEN5XDATA->noxIndex)) { + DEBUG_SENSOR_LOG(PSTR("NoxIndex: n/a")); + } else { + DEBUG_SENSOR_LOG(PSTR("NoxIndex: %*_f"), 0, &SEN5XDATA->noxIndex); } #endif } - if (!isnan(SEN5XDATA->ambientTemperature) && SEN5XDATA->ambientHumidity > 0) { - SEN5XDATA->abshum = sen5x_AbsoluteHumidity(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity); - DEBUG_SENSOR_LOG(PSTR("AbsoluteHumidity: %f\n"), SEN5XDATA->abshum); - } } -#ifdef USE_WEBSERVER -const char HTTP_SNS_SEN5X_UNITS[] PROGMEM = "{s}SEN5X %s{m}%.*f %s{e}"; -const char HTTP_SNS_SEN5X_UNITLESS[] PROGMEM = "{s}SEN5X %s{m}%.*f{e}"; -// {s} = -const char HTTP_SNS_AHUMSEN5X[] PROGMEM = "{s}SEN5X Abs Humidity{m}%s g/m³{e}"; -#endif +void SEN5XShow(bool json) { + char types[10]; + strcpy_P(types, PSTR("SEN5X")); -#define D_JSON_AHUM "aHumidity" + float temperature = 0; + float humidity = 0; + float abs_humidity = 0; + bool ahum_available = (!isnan(SEN5XDATA->ambientTemperature) && !isnan(SEN5XDATA->ambientHumidity) && (SEN5XDATA->ambientHumidity > 0)); + if (ahum_available) { + temperature = ConvertTemp(SEN5XDATA->ambientTemperature); + humidity = ConvertHumidity(SEN5XDATA->ambientHumidity); + abs_humidity = CalcTempHumToAbsHum(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity); + } -void SEN5XShow(bool json) -{ - if (SEN5XDATA->sen5x_ready) - { - char sen5x_abs_hum[33]; - bool ahum_available = !isnan(SEN5XDATA->ambientTemperature) && (SEN5XDATA->ambientHumidity > 0); - if (ahum_available) - { - // has humidity + temperature - dtostrfd(SEN5XDATA->abshum, 4, sen5x_abs_hum); + if (json) { + ResponseAppend_P(PSTR(",\"%s\":{\"PM1\":%1_f,\"PM2.5\":%1_f,\"PM4\":%1_f,\"PM10\":%1_f,"), + types, + &SEN5XDATA->massConcentrationPm1p0, &SEN5XDATA->massConcentrationPm2p5, &SEN5XDATA->massConcentrationPm4p0, &SEN5XDATA->massConcentrationPm10p0); + if (!isnan(SEN5XDATA->noxIndex)) { + ResponseAppend_P(PSTR("\"NOx\":%0_f,"), &SEN5XDATA->noxIndex); } - if (json) - { - ResponseAppend_P(PSTR(",\"SEN5X\":{")); - ResponseAppend_P(PSTR("\"PM1\":%.1f,"), SEN5XDATA->massConcentrationPm1p0); - ResponseAppend_P(PSTR("\"PM2.5\":%.1f,"), SEN5XDATA->massConcentrationPm2p5); - ResponseAppend_P(PSTR("\"PM4\":%.1f,"), SEN5XDATA->massConcentrationPm4p0); - ResponseAppend_P(PSTR("\"PM10\":%.1f,"), SEN5XDATA->massConcentrationPm10p0); - if (!isnan(SEN5XDATA->noxIndex)) - ResponseAppend_P(PSTR("\"NOx\":%.0f,"), SEN5XDATA->noxIndex); - if (!isnan(SEN5XDATA->vocIndex)) - ResponseAppend_P(PSTR("\"VOC\":%.0f,"), SEN5XDATA->vocIndex); - if (!isnan(SEN5XDATA->ambientTemperature)) - ResponseAppendTHD(SEN5XDATA->ambientTemperature, SEN5XDATA->ambientHumidity); - if (ahum_available) - ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"), sen5x_abs_hum); - ResponseJsonEnd(); + if (!isnan(SEN5XDATA->vocIndex)) { + ResponseAppend_P(PSTR("\"VOC\":%0_f,"), &SEN5XDATA->vocIndex); } - + if (ahum_available) { + ResponseAppendTHD(temperature, humidity); + ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%4_f"), &abs_humidity); + } + ResponseJsonEnd(); #ifdef USE_WEBSERVER - - WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM1", 1, SEN5XDATA->massConcentrationPm1p0, "μg/m³"); - WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM2.5", 1, SEN5XDATA->massConcentrationPm2p5, "μg/m³"); - WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM4", 1, SEN5XDATA->massConcentrationPm4p0, "μg/m³"); - WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "PM10", 1, SEN5XDATA->massConcentrationPm10p0, "μg/m³"); - if (!isnan(SEN5XDATA->noxIndex)) - WSContentSend_PD(HTTP_SNS_SEN5X_UNITLESS, "NOx", 0, SEN5XDATA->noxIndex); - if (!isnan(SEN5XDATA->vocIndex)) - WSContentSend_PD(HTTP_SNS_SEN5X_UNITLESS, "VOC", 0, SEN5XDATA->vocIndex); - if (!isnan(SEN5XDATA->ambientTemperature)) - WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "Temperature", 2, SEN5XDATA->ambientTemperature, "°C"); - if (!isnan(SEN5XDATA->ambientHumidity)) - WSContentSend_PD(HTTP_SNS_SEN5X_UNITS, "Humidity", 2, SEN5XDATA->ambientHumidity, "%RH"); - if (ahum_available) - WSContentSend_PD(HTTP_SNS_AHUMSEN5X, sen5x_abs_hum); - + } else { + WSContentSend_PD(HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION, types, "1", &SEN5XDATA->massConcentrationPm1p0); + WSContentSend_PD(HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION, types, "2.5", &SEN5XDATA->massConcentrationPm2p5); + WSContentSend_PD(HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION, types, "4", &SEN5XDATA->massConcentrationPm4p0); + WSContentSend_PD(HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION, types, "10", &SEN5XDATA->massConcentrationPm10p0); + if (!isnan(SEN5XDATA->noxIndex)) { + WSContentSend_PD(HTTP_SNS_F_NOX, types, 0, &SEN5XDATA->noxIndex); + } + if (!isnan(SEN5XDATA->vocIndex)) { + WSContentSend_PD(HTTP_SNS_F_VOC, types, 0, &SEN5XDATA->vocIndex); + } + if (ahum_available) { + WSContentSend_THD(types, temperature, humidity); + WSContentSend_PD(HTTP_SNS_F_ABS_HUM, types, 4, &abs_humidity); + } #endif } } @@ -275,23 +204,16 @@ void SEN5XShow(bool json) * Interface \*********************************************************************************************/ -bool Xsns103(uint32_t function) -{ - if (!I2cEnabled(XI2C_76)) - { - return false; - } +bool Xsns103(uint32_t function) { + if (!I2cEnabled(XI2C_76)) { return false; } bool result = false; - if (FUNC_INIT == function) - { + if (FUNC_INIT == function) { sen5x_Init(); } - else if (SEN5XDATA != nullptr) - { - switch (function) - { + else if (SEN5XDATA != nullptr) { + switch (function) { case FUNC_EVERY_SECOND: SEN5XUpdate(); break; diff --git a/tasmota/tasmota_xsns_sensor/xsns_104_pmsa003i.ino b/tasmota/tasmota_xsns_sensor/xsns_104_pmsa003i.ino new file mode 100644 index 000000000..b0961c167 --- /dev/null +++ b/tasmota/tasmota_xsns_sensor/xsns_104_pmsa003i.ino @@ -0,0 +1,155 @@ +/* + xsns_104_pmsa003i.ino - PMSA003I air quality sensor support for Tasmota + + Copyright (C) 2023 Jean-Pierre Deschamps + + 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_PMSA003I +/*********************************************************************************************\ + * PMSA003I - PM2.5 Air Quality Sensor with I2C Interface + * + * Source: Adafruit Industries + * Adaption for TASMOTA: Jean-Pierre Deschamps + * + * I2C Address: 0x12 +\*********************************************************************************************/ + +#define XSNS_104 104 +#define XI2C_78 78 // See I2CDEVICES.md + +#define PMSA003I_ADDRESS 0x12 + +#ifndef PMSA003I_WARMUP_DELAY +#define PMSA003I_WARMUP_DELAY 30 // Ignore PMSA003I readings for XX seconds after start +#endif + +#include "Adafruit_PM25AQI.h" + +struct PMSA003I { + bool type = false; + bool ready = false; + uint8_t warmup_counter; // count for warmup + PM25_AQI_Data data; + Adafruit_PM25AQI aqi = Adafruit_PM25AQI(); +} Pmsa003i; + + +/********************************************************************************************/ + +void pmsa003i_Init(void) +{ + if (!I2cSetDevice(PMSA003I_ADDRESS)) { + // AddLog(LOG_LEVEL_DEBUG, PSTR("PMS: " D_JSON_I2CSCAN_NO_DEVICES_FOUND)); + return; + } + + if (Pmsa003i.aqi.begin_I2C()) { + Pmsa003i.type = true; + Pmsa003i.warmup_counter = PMSA003I_WARMUP_DELAY; + I2cSetActiveFound(PMSA003I_ADDRESS, "PMSA003I"); +// } else { +// AddLog(LOG_LEVEL_DEBUG, PSTR("PMS: " "Begin_I2C failed")); + } +} + + +void Pmsa003iUpdate(void) +{ + if (Pmsa003i.warmup_counter > 0) { + Pmsa003i.warmup_counter--; + return; + } + + Pmsa003i.ready = false; + PM25_AQI_Data data; + if (! Pmsa003i.aqi.read(&data)) { // Could not read from AQI + return; + } + Pmsa003i.data = data; + Pmsa003i.ready = true; +} + +void Pmsa003iShow(bool json) { + if (Pmsa003i.ready) { + char types[10]; + strcpy_P(types, PSTR("PMSA003I")); + + if (json) { + ResponseAppend_P(PSTR(",\"%s\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"), + types, + Pmsa003i.data.pm10_standard, Pmsa003i.data.pm25_standard, Pmsa003i.data.pm100_standard, + Pmsa003i.data.pm10_env, Pmsa003i.data.pm25_env, Pmsa003i.data.pm100_env, + Pmsa003i.data.particles_03um, Pmsa003i.data.particles_05um, Pmsa003i.data.particles_10um, Pmsa003i.data.particles_25um, Pmsa003i.data.particles_50um, Pmsa003i.data.particles_100um); +#ifdef USE_DOMOTICZ + if (0 == TasmotaGlobal.tele_period) { + DomoticzSensor(DZ_COUNT, Pmsa003i.data.pm10_env); // PM1 + DomoticzSensor(DZ_VOLTAGE, Pmsa003i.data.pm25_env); // PM2.5 + DomoticzSensor(DZ_CURRENT, Pmsa003i.data.pm100_env); // PM10 + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "1", Pmsa003i.data.pm10_standard); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "2.5", Pmsa003i.data.pm25_standard); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "10", Pmsa003i.data.pm100_standard); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "1", Pmsa003i.data.pm10_env); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "2.5", Pmsa003i.data.pm25_env); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "10", Pmsa003i.data.pm100_env); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.3", Pmsa003i.data.particles_03um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.5", Pmsa003i.data.particles_05um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "1", Pmsa003i.data.particles_10um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "2.5", Pmsa003i.data.particles_25um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "5", Pmsa003i.data.particles_50um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "10", Pmsa003i.data.particles_100um); +#endif + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns104(uint32_t function) +{ + if (!I2cEnabled(XI2C_78)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + pmsa003i_Init(); + } + else if (Pmsa003i.type) { + switch (function) { + case FUNC_EVERY_SECOND: + Pmsa003iUpdate(); + break; + case FUNC_JSON_APPEND: + Pmsa003iShow(1); + break; + #ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + Pmsa003iShow(0); + break; + #endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_PMSA003I +#endif // USE_I2C diff --git a/tasmota/tasmota_xsns_sensor/xsns_105_lox_o2.ino b/tasmota/tasmota_xsns_sensor/xsns_105_lox_o2.ino new file mode 100644 index 000000000..a644e964f --- /dev/null +++ b/tasmota/tasmota_xsns_sensor/xsns_105_lox_o2.ino @@ -0,0 +1,156 @@ +/* + xsns_105_lox_o2.ino - Support for LuminOx Sealed Optical Oxygen Sensor on Tasmota + + Copyright (C) 2023 Anton ACE Elizarov + https://github.com/ACE1046 + + 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 . +*/ + +#ifdef USE_LOX_O2 +/*********************************************************************************************\ + * LuminOx Sealed Optical Oxygen Sensor LOX-02-S + * + * LuminOx requires no additional signal conditioning circuitry and connects + * directly to the interfacing microcontroller via a 3.3V-level USART link + * All USART communication is preformed using ascii characters + * By default, stream mode is initiated on sensor power-up and will supply an output string + * approximately once every second. This provides the data for ppO2, Temperature, Pressure, O2 and + * sensor status. Format is fixed, shown below: + * O xxxx.x T yxx.x P xxxx % xxx.xx e xxxx\r\n + * i.e. + * O 0198.5 T +21.7 P 0983 % 020.19 e 0000\r\n +\*********************************************************************************************/ + +#define XSNS_105 105 + +#define LOX_O2_BAUDRATE 9600 + +#include +TasmotaSerial *LOXSerial = nullptr; + +#define RESPONSE_LEN (sizeof("O 0198.5 T +21.7 P 0983 % 020.19 e 0000\r\n") - 1) // not including terminating zero + +struct LOX_O2 +{ + float ppO2 = 0.0; + float temperature = 0.0; + uint32_t pressure = 0; + float O2 = 0.0; + uint32 error = 0; +} *lox_o2 = nullptr; + +/********************************************************************************************/ + +void LOXInit() +{ + if (PinUsed(GPIO_LOX_O2_RX)) + { + lox_o2 = (LOX_O2 *)calloc(1, sizeof(struct LOX_O2)); + + LOXSerial = new TasmotaSerial(Pin(GPIO_LOX_O2_RX), -1, 1); + if (LOXSerial->begin(LOX_O2_BAUDRATE)) + { + if (LOXSerial->hardwareSerial()) + ClaimSerial(); + } + } +} + +void LOXParse(uint8_t *buf) +{ + if (!lox_o2) return; + // O 0198.5 T +21.7 P 0983 % 020.19 e 0000 + if (buf[0] != 'O' || buf[9] != 'T' || buf[17] != 'P' || buf[24] != '%' || buf[33] != 'e') return; // check for valid response + lox_o2->pressure = strtoul((char *)buf+19, nullptr, 10); + lox_o2->ppO2 = CharToFloat((char *)buf+2); + lox_o2->temperature = CharToFloat((char *)buf+11); + lox_o2->O2 = CharToFloat((char *)buf+26); + lox_o2->error = strtoul((char *)buf+35, nullptr, 10); +} + +void LOXJson() +{ + if (!lox_o2) return; + if (lox_o2->pressure > 0 && lox_o2->error == 0) + { + float temperature = ConvertTemp(lox_o2->temperature); + ResponseAppend_P(PSTR(",\"LOX\":{\"" D_JSON_PRESSURE "\":%i,\"ppO2\":%1_f,\"" D_JSON_TEMPERATURE "\":%1_f,\"" D_JSON_O2 "\":%2_f"), + lox_o2->pressure, &lox_o2->ppO2, &temperature, &lox_o2->O2); + ResponseJsonEnd(); + } +} + +void LOXRead() +{ + uint8_t buf[RESPONSE_LEN+1]; + uint32_t in_buf = 0; + + if (!LOXSerial || !lox_o2) return; + + buf[RESPONSE_LEN] = 0; + + while (LOXSerial->available() >= RESPONSE_LEN) + { + in_buf = 0; + while (LOXSerial->available() && in_buf < RESPONSE_LEN) + { + char c = LOXSerial->read(); + buf[in_buf++] = c; + if (c == '\n') break; + } + if (in_buf == RESPONSE_LEN) LOXParse(buf); + } +} + +#ifdef USE_WEBSERVER +const char types[] = "LOX"; +void LOXShow(void) +{ + if (!LOXSerial || !lox_o2) return; + //AddLog(LOG_LEVEL_DEBUG, PSTR("LOX: %s"), value); + WSContentSend_PD(PSTR("{s}%s " D_PRESSURE "{m} %i " D_UNIT_PRESSURE "{e}"), types, lox_o2->pressure); + WSContentSend_PD(PSTR("{s}%s ppO2{m} %1_f " D_UNIT_PRESSURE "{e}"), types, &lox_o2->ppO2); + WSContentSend_Temp(types, ConvertTemp(lox_o2->temperature)); + WSContentSend_PD(PSTR("{s}%s " D_O2 "{m} %2_f %%{e}"), types, &lox_o2->O2); +} +#endif // USE_WEBSERVER + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns105(uint32_t function) { + bool result = false; + + switch (function) { + case FUNC_INIT: + LOXInit(); + break; + case FUNC_EVERY_SECOND: + LOXRead(); + break; + case FUNC_JSON_APPEND: + LOXJson(); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + LOXShow(); + break; +#endif // USE_WEBSERVER + } + return result; +} + +#endif // USE_LOX diff --git a/tasmota/tasmota_xsns_sensor/xsns_106_gdk101.ino b/tasmota/tasmota_xsns_sensor/xsns_106_gdk101.ino new file mode 100644 index 000000000..e8cdcb782 --- /dev/null +++ b/tasmota/tasmota_xsns_sensor/xsns_106_gdk101.ino @@ -0,0 +1,302 @@ +/* + xsns_106_gdk101.ino - Support for GDK101 gamma radiation sensor + + Copyright (C) 2019 Petr Novacek + + 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_GDK101 + +/*********************************************************************************************\ + * GDK101 gamma radiation sensor ftlab.co.kr + * + * For background information see http://allsmartlab.com/eng/294-2/ + * + * I2C Address: + * A0 Short, A1 Short : 0x18 + * A0 Open, A1 Short : 0x19 + * A0 Short, A1 Open : 0x1A + * A0 Open, A1 Open : 0x1B +\*********************************************************************************************/ + +#define XSNS_106 106 + +#define XI2C_79 79 // See I2CDEVICES.md + +// I2C adresses +#define GDK101_ADDRESS1 0x18 +#define GDK101_ADDRESS2 0x19 +#define GDK101_ADDRESS3 0x1A +#define GDK101_ADDRESS4 0x1B + +// I2C register +#define READ_FIRMWARE 0xB4 +#define RESET 0xA0 +#define READ_STATUS 0xB0 +#define READ_MEASURING_TIME 0xB1 +#define READ_10MIN_AVG 0xB2 +#define READ_1MIN_AVG 0xB3 + +// gdk101 variables +uint8_t gdk101_address; +uint8_t gdk101_addresses[] = { GDK101_ADDRESS1, GDK101_ADDRESS2, GDK101_ADDRESS3, GDK101_ADDRESS4 }; +uint8_t gdk101_discovered = false; + +typedef enum { + GDK_STATUS_READY, + GDK_STATUS_UNDER_10_MINUTES, + GDK_STATUS_NORMAL, + GDK_STATUS_INVALID, +} gdk_status_t; + +typedef struct gdk_status_data { + gdk_status_t status; + bool vibration; +} gdk_status_data_t; + +typedef struct gdk_measuring_time { + uint8_t min; + uint8_t sec; +} gdk_measuring_time_t; + +typedef struct gdk_fW_version { + uint8_t major; + uint8_t minor; +} gdk_fW_version_t; + +typedef struct gdk_avg_dose { + uint8_t integral; + uint8_t fractional; +} gdk_avg_dose_t; + +bool gdk_ready = false; +gdk_fW_version_t fw_version; +gdk_avg_dose_t mea_10min_avg; +gdk_avg_dose_t mea_1min_avg; +gdk_status_data_t gdk_status = {GDK_STATUS_INVALID, false}; +gdk_measuring_time_t gdk_time = {0, 0}; +uint8_t evr10 = 0; +// uint8_t vibr = 0; + +#ifdef USE_WEBSERVER +const char HTTP_GDK101_FW[] PROGMEM = "{s}%s " "FW Version" "{m}%d.%d{e}"; +const char HTTP_GDK101_STATUS[] PROGMEM = "{s}%s " "Status" "{m}%d{e}"; +const char HTTP_GDK101_VIB_STATUS[] PROGMEM = "{s}%s " "Vibration Status" "{m}%d{e}"; +const char HTTP_GDK101_MEAS_TIME[] PROGMEM = "{s}%s " "Measurement Time" "{m}%d:%02d{e}"; +#endif // USE_WEBSERVER + +bool gdk101_reset(bool *reset); + +void gdk101_err_log(bool ret) { + if(!ret) { + DEBUG_SENSOR_LOG("GDK101: I2C read error"); + } +} + +void gdk101_detect(void) +{ + bool ret = false; + bool reset = false; + for (uint32_t i = 0; i < sizeof(gdk101_addresses); i++) { + gdk101_address = gdk101_addresses[i]; + if (!I2cSetDevice(gdk101_address)) { + continue; // do not make the next step without a confirmed device on the bus + } + ret = gdk101_reset(&reset); + if(ret) { + if(reset) { + delay(10); + I2cSetActiveFound(gdk101_address, "GDK101"); + ret = gdk101_get_fw_version(&fw_version); + gdk101_err_log(ret); + gdk_ready = true; + break; + } + } + } +} + +void gdk101_init() { + + if (gdk_ready) return; + + gdk101_detect(); + +} + +bool gdk101_reset(bool *reset) { + uint8_t buf; + bool ret = false; + ret = I2cValidRead8(&buf, gdk101_address, RESET); + if (ret) { + *reset = (bool) buf; + } + return ret; +} + +bool gdk101_get_fw_version(struct gdk_fW_version *fw) { + uint8_t buf[2]; + bool ret = false; + ret = I2cValidRead16LE((uint16_t*) buf, gdk101_address, READ_FIRMWARE); + if (ret) { + fw->major = buf[0]; + fw->minor = buf[1]; + } + return ret; +} + +bool gdk101_get_10min_avg(struct gdk_avg_dose *avg) { + uint8_t buf[2]; + bool ret = false; + ret = I2cValidRead16LE((uint16_t*) buf, gdk101_address, READ_10MIN_AVG); + if (ret) { + avg->integral = buf[0]; + avg->fractional = buf[1]; + } + return ret; +} + +bool gdk101_get_1min_avg(struct gdk_avg_dose *avg) { + uint8_t buf[2]; + bool ret = false; + ret = I2cValidRead16LE((uint16_t*) buf, gdk101_address, READ_1MIN_AVG); + if (ret) { + avg->integral = buf[0]; + avg->fractional = buf[1]; + } + return ret; +} + +bool gdk101_get_status(struct gdk_status_data *status) { + uint8_t buf[2]; + bool ret = false; + ret = I2cValidRead16LE((uint16_t*) buf, gdk101_address, READ_STATUS); + if (ret) { + status->status = (gdk_status_t) buf[0]; + status->vibration = (bool) buf[1]; + } + return ret; +} + +bool gdk101_get_measuring_time(struct gdk_measuring_time *meas_time) { + uint8_t buf[2]; + bool ret = false; + ret = I2cValidRead16LE((uint16_t*) buf, gdk101_address, READ_MEASURING_TIME); + if (ret) { + meas_time->min = buf[0]; + meas_time->sec = buf[1]; + } + return ret; +} + +void every_second(void) { + if (!gdk_ready) return; + + gdk101_every_second(); + + if (evr10 == 10) { + gdk101_every_10_second(); + evr10 = 1; + } + else { + evr10++; + } + +} + +void gdk101_every_second(void) { + bool ret = false; + + ret = gdk101_get_status(&gdk_status); + gdk101_err_log(ret); +} + +void gdk101_every_10_second(void) { + bool ret = false; + + ret = gdk101_get_10min_avg(&mea_10min_avg); + gdk101_err_log(ret); + ret = gdk101_get_1min_avg(&mea_1min_avg); + gdk101_err_log(ret); + ret = gdk101_get_measuring_time(&gdk_time); + gdk101_err_log(ret); +} + +void gdk101_show(uint8_t json) { + char types[16]; + strcpy_P(types, PSTR("GDK101")); + + if (!gdk_ready) return; + + if (json) { + ResponseAppend_P(PSTR(",\"%s\":{"), types); + ResponseAppend_P(PSTR("\"FW_V\":%i.%i,"), fw_version.major, fw_version.minor); + ResponseAppend_P(PSTR("\"10MIN_AVG\":%i.%02i,"), mea_10min_avg.integral, mea_10min_avg.fractional); + ResponseAppend_P(PSTR("\"1MIN_AVG\":%i.%02i,"), mea_1min_avg.integral, mea_1min_avg.fractional); + ResponseAppend_P(PSTR("\"STATUS\":%i,"), gdk_status.status); + ResponseAppend_P(PSTR("\"VIBRATION\":%i,"), gdk_status.vibration); + ResponseAppend_P(PSTR("\"MEAS_TIME\":\"%i:%02i\""), gdk_time.min, gdk_time.sec); + ResponseJsonEnd(); +#ifdef USE_WEBSERVER + } else { +#ifdef GDK101_SHOW_FW_VERSION + WSContentSend_PD(HTTP_GDK101_FW, types, fw_version.major, fw_version.minor); +#endif + WSContentSend_PD(HTTP_SNS_AVG_RAD_DOSE, types, "@10", mea_10min_avg.integral, mea_10min_avg.fractional); + WSContentSend_PD(HTTP_SNS_AVG_RAD_DOSE, types, "@1", mea_1min_avg.integral, mea_1min_avg.fractional); +#ifdef GDK101_SHOW_STATUS + WSContentSend_PD(HTTP_GDK101_STATUS, types, gdk_status.status); +#endif +#ifdef GDK101_SHOW_VIBRATION_STATUS + WSContentSend_PD(HTTP_GDK101_VIB_STATUS, types, gdk_status.vibration); +#endif +#ifdef GDK101_SHOW_MEAS_TIME + WSContentSend_PD(HTTP_GDK101_MEAS_TIME, types, gdk_time.min, gdk_time.sec); +#endif +#endif // USE_WEBSERVER + } +} +/*********************************************************************************************\ + Interface +\*********************************************************************************************/ + +bool Xsns106(uint32_t function) +{ + bool result = false; + + if (!I2cEnabled(XI2C_79)) { return false; } + + switch (function) { + case FUNC_INIT: + gdk101_init(); + break; + case FUNC_EVERY_SECOND: + every_second(); + break; + case FUNC_JSON_APPEND: + gdk101_show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + gdk101_show(0); + break; +#endif // USE_WEBSERVER + } + return result; +} + +#endif // USE_GDK +#endif // USE_I2C diff --git a/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino b/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino index 7a403fdb6..9471d9c18 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino @@ -248,8 +248,7 @@ void PmsSecond(void) // Every second /*********************************************************************************************/ -void PmsInit(void) -{ +void PmsInit(void) { Pms.type = 0; if (PinUsed(GPIO_PMS5003_RX)) { PmsSerial = new TasmotaSerial(Pin(GPIO_PMS5003_RX), (PinUsed(GPIO_PMS5003_TX)) ? Pin(GPIO_PMS5003_TX) : -1, 1); @@ -274,62 +273,39 @@ void PmsInit(void) } } -#ifdef USE_WEBSERVER -#ifdef PMS_MODEL_PMS3003 -const char HTTP_PMS3003_SNS[] PROGMEM = -// "{s}PMS3003 " D_STANDARD_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" -// "{s}PMS3003 " D_STANDARD_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" -// "{s}PMS3003 " D_STANDARD_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS3003 " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS3003 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS3003 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; -#else -const char HTTP_PMS5003_SNS[] PROGMEM = -// "{s}PMS5003 " D_STANDARD_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" -// "{s}PMS5003 " D_STANDARD_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" -// "{s}PMS5003 " D_STANDARD_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 0.3 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 0.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" -#ifdef PMS_MODEL_PMS5003T - "{s}PMS5003 " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}" - "{s}PMS5003 " D_HUMIDITY "{m}%*_f " D_UNIT_PERCENT "{e}"; -#else - "{s}PMS5003 " D_PARTICALS_BEYOND " 5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}PMS5003 " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; // {s} = -#endif // PMS_MODEL_PMS5003T -#endif // PMS_MODEL_PMS3003 -#endif // USE_WEBSERVER - -void PmsShow(bool json) -{ +void PmsShow(bool json) { if (Pms.valid) { + char types[10]; +#ifdef PMS_MODEL_PMS3003 + strcpy_P(types, PSTR("PMS3003")); +#elif defined(PMS_MODEL_PMS5003T) + strcpy_P(types, PSTR("PMS5003T")); +#else + strcpy_P(types, PSTR("PMS5003")); +#endif + #ifdef PMS_MODEL_PMS5003T float temperature = ConvertTemp(pms_data.temperature10x/10.0); float humidity = ConvertHumidity(pms_data.humidity10x/10.0); #endif // PMS_MODEL_PMS5003T + if (json) { -#ifdef PMS_MODEL_PMS3003 - ResponseAppend_P(PSTR(",\"PMS3003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d}"), + ResponseAppend_P(PSTR(",\"%s\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d"), + types, pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard, pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env); -#else - ResponseAppend_P(PSTR(",\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,"), - pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard, - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env, +#ifndef PMS_MODEL_PMS3003 + ResponseAppend_P(PSTR(",\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,"), pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um); #ifdef PMS_MODEL_PMS5003T - ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_HUMIDITY "\":%*_f}"), - Settings->flag2.temperature_resolution, &temperature, Settings->flag2.humidity_resolution, &humidity); + ResponseAppendTHD(temperature, humidity); #else - ResponseAppend_P(PSTR("\"PB5\":%d,\"PB10\":%d}"), + ResponseAppend_P(PSTR("\"PB5\":%d,\"PB10\":%d"), pms_data.particles_50um, pms_data.particles_100um); #endif // PMS_MODEL_PMS5003T -#endif // PMS_MODEL_PMS3003 +#endif // No PMS_MODEL_PMS3003 + ResponseJsonEnd(); + #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) { DomoticzSensor(DZ_COUNT, pms_data.pm10_env); // PM1 @@ -339,21 +315,24 @@ void PmsShow(bool json) #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - -#ifdef PMS_MODEL_PMS3003 - WSContentSend_PD(HTTP_PMS3003_SNS, -// pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard, - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env); -#elif defined(PMS_MODEL_PMS5003T) - WSContentSend_PD(HTTP_PMS5003_SNS, - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env, - pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, Settings->flag2.temperature_resolution, &temperature, TempUnit(), Settings->flag2.humidity_resolution, &humidity); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "1", pms_data.pm10_standard); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "2.5", pms_data.pm25_standard); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "10", pms_data.pm100_standard); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "1", pms_data.pm10_env); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "2.5", pms_data.pm25_env); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "10", pms_data.pm100_env); +#ifndef PMS_MODEL_PMS3003 + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.3", pms_data.particles_03um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.5", pms_data.particles_05um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "1", pms_data.particles_10um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "2.5", pms_data.particles_25um); +#ifdef PMS_MODEL_PMS5003T + WSContentSend_THD(types, temperature, humidity); #else - WSContentSend_PD(HTTP_PMS5003_SNS, -// pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard, - pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env, - pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um); -#endif // PMS_MODEL_PMS3003 + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "5", pms_data.particles_50um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "10", pms_data.particles_100um); +#endif // PMS_MODEL_PMS5003T +#endif // No PMS_MODEL_PMS3003 #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino b/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino index a0c773923..3bd0d3933 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino @@ -214,32 +214,25 @@ void NovaSdsInit(void) } } -#ifdef USE_WEBSERVER -const char HTTP_SDS0X1_SNS[] PROGMEM = - "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = -#endif // USE_WEBSERVER - -void NovaSdsShow(bool json) -{ +void NovaSdsShow(bool json) { if (novasds_valid) { - float pm10f = (float)(novasds_data.pm100) / 10.0f; - float pm2_5f = (float)(novasds_data.pm25) / 10.0f; - char pm10[33]; - dtostrfd(pm10f, 1, pm10); - char pm2_5[33]; - dtostrfd(pm2_5f, 1, pm2_5); + char types[10]; + strcpy_P(types, PSTR("SDS0X1")); + + float pm10 = (float)(novasds_data.pm100) / 10.0f; + float pm2_5 = (float)(novasds_data.pm25) / 10.0f; if (json) { - ResponseAppend_P(PSTR(",\"SDS0X1\":{\"PM2.5\":%s,\"PM10\":%s}"), pm2_5, pm10); + ResponseAppend_P(PSTR(",\"%s\":{\"PM2.5\":%1_f,\"PM10\":%1_f}"), types, &pm2_5, &pm10); #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) { - DomoticzSensor(DZ_VOLTAGE, pm2_5); // PM2.5 - DomoticzSensor(DZ_CURRENT, pm10); // PM10 + DomoticzFloatSensor(DZ_VOLTAGE, pm2_5); // PM2.5 - VoltRes 1 + DomoticzFloatSensor(DZ_CURRENT, pm10); // PM10 - AmpRes 1 } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_SDS0X1_SNS, pm2_5, pm10); + WSContentSend_PD(HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION, types, "2.5", pm2_5); + WSContentSend_PD(HTTP_SNS_F_ENVIRONMENTAL_CONCENTRATION, types, "10", pm10); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino b/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino index 54a7a77b5..a68c0908c 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino @@ -108,8 +108,6 @@ const char HTTP_SNS_SGP30[] PROGMEM = const char HTTP_SNS_AHUM[] PROGMEM = "{s}SGP30 Abs Humidity{m}%s g/m3{e}"; #endif -#define D_JSON_AHUM "aHumidity" - void Sgp30Show(bool json) { if (sgp30_ready) { diff --git a/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino b/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino index 01f5a22a9..4a4e28e17 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino @@ -124,7 +124,7 @@ void Sr04TModeDetect(void) { if (PinUsed(GPIO_SR04_TRIG)) { SR04.type = (Sr04TMiddleValue(Sr04TMode3Distance(), Sr04TMode3Distance(), Sr04TMode3Distance()) != 0) ? SR04_MODE_SER_TRANSCEIVER : SR04_MODE_TRIGGER_ECHO; } else { - SR04.type = SR04_MODE_SER_RECEIVER; + SR04.type = (Sr04TMiddleValue(Sr04TMode2Distance(), Sr04TMode2Distance(), Sr04TMode2Distance()) != 0) ? SR04_MODE_SER_RECEIVER : SR04_MODE_TRIGGER_ECHO; } } else { SR04.type = SR04_MODE_TRIGGER_ECHO; diff --git a/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino b/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino index aa3d8b6d1..9b66bcded 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino @@ -46,8 +46,7 @@ #define RFSNS_SIGNAL_TIMEOUT 10 // Pulse timings in mSec. Beyond this value indicate end of message #define RFSNS_SIGNAL_REPEAT_TIME 500 // (500) Tijd in mSec. waarbinnen hetzelfde event niet nogmaals via RF mag binnenkomen. Onderdrukt ongewenste herhalingen van signaal -typedef struct RawSignalStruct // Variabelen geplaatst in struct zodat deze later eenvoudig kunnen worden weggeschreven naar SDCard -{ +typedef struct RawSignalStruct { // Variabelen geplaatst in struct zodat deze later eenvoudig kunnen worden weggeschreven naar SDCard int Number; // aantal bits, maal twee omdat iedere bit een mark en een space heeft. uint8_t Repeats; // Aantal maal dat de pulsreeks verzonden moet worden bij een zendactie. uint8_t Multiply; // Pulses[] * Multiply is de echte tijd van een puls in microseconden @@ -65,8 +64,7 @@ uint8_t rfsns_any_sensor = 0; * Fetch signals from RF pin \*********************************************************************************************/ -bool RfSnsFetchSignal(uint8_t DataPin, bool StateSignal) -{ +bool RfSnsFetchSignal(uint8_t DataPin, bool StateSignal) { uint8_t Fbit = digitalPinToBitMask(DataPin); uint8_t Fport = digitalPinToPort(DataPin); uint8_t FstateMask = (StateSignal ? Fbit : 0); @@ -168,16 +166,14 @@ typedef struct { theo_v2_t1_t *rfsns_theo_v2_t1 = nullptr; theo_v2_t2_t *rfsns_theo_v2_t2 = nullptr; -void RfSnsInitTheoV2(void) -{ - rfsns_theo_v2_t1 = (theo_v2_t1_t*)malloc(RFSNS_THEOV2_MAX_CHANNEL * sizeof(theo_v2_t1_t)); - rfsns_theo_v2_t2 = (theo_v2_t2_t*)malloc(RFSNS_THEOV2_MAX_CHANNEL * sizeof(theo_v2_t2_t)); +void RfSnsInitTheoV2(void) { + rfsns_theo_v2_t1 = (theo_v2_t1_t*)calloc(RFSNS_THEOV2_MAX_CHANNEL, sizeof(theo_v2_t1_t)); + rfsns_theo_v2_t2 = (theo_v2_t2_t*)calloc(RFSNS_THEOV2_MAX_CHANNEL, sizeof(theo_v2_t2_t)); rfsns_any_sensor++; } -void RfSnsAnalyzeTheov2(void) -{ - if (rfsns_raw_signal->Number != RFSNS_THEOV2_PULSECOUNT) { return; } +bool RfSnsAnalyzeTheov2(void) { + if (rfsns_raw_signal->Number != RFSNS_THEOV2_PULSECOUNT) { return false; } uint8_t Checksum; // 8 bits Checksum over following bytes uint8_t Channel; // 3 bits channel @@ -185,15 +181,13 @@ void RfSnsAnalyzeTheov2(void) uint8_t Voltage; // 8 bits Vcc like 45 = 4.5V, bit 8 is batt low int Payload1; // 16 bits int Payload2; // 16 bits - - uint8_t b, bytes, bits, id; + uint8_t id; uint8_t idx = 3; uint8_t chksum = 0; - for (bytes = 0; bytes < 7; bytes++) { - b = 0; - for (bits = 0; bits <= 7; bits++) - { + for (uint32_t bytes = 0; bytes < 7; bytes++) { + uint8_t b = 0; + for (uint32_t bits = 0; bits <= 7; bits++) { if ((rfsns_raw_signal->Pulses[idx] * rfsns_raw_signal->Multiply) > RFSNS_THEOV2_RF_PULSE_MID) { b |= 1 << bits; } @@ -228,8 +222,8 @@ void RfSnsAnalyzeTheov2(void) } } - if (Checksum != chksum) { return; } - if ((Channel == 0) || (Channel > RFSNS_THEOV2_MAX_CHANNEL)) { return; } + if (Checksum != chksum) { return false; } + if ((Channel == 0) || (Channel > RFSNS_THEOV2_MAX_CHANNEL)) { return false; } Channel--; rfsns_raw_signal->Repeats = 1; // het is een herhalend signaal. Bij ontvangst herhalingen onderdukken @@ -253,10 +247,11 @@ void RfSnsAnalyzeTheov2(void) AddLog(LOG_LEVEL_DEBUG, PSTR("RFS: TheoV2, ChkCalc %d, Chksum %d, id %d, Type %d, Ch %d, Volt %d, BattLo %d, Pld1 %d, Pld2 %d"), chksum, Checksum, id, Type, Channel +1, Payload3, (Voltage & 0x80) >> 7, Payload1, Payload2); + + return true; } -void RfSnsTheoV2Show(bool json) -{ +void RfSnsTheoV2Show(bool json) { bool sensor_once = false; for (uint32_t i = 0; i < RFSNS_THEOV2_MAX_CHANNEL; i++) { @@ -422,16 +417,14 @@ typedef struct { alecto_v2_t *rfsns_alecto_v2 = nullptr; uint16_t rfsns_alecto_rain_base = 0; -void RfSnsInitAlectoV2(void) -{ - rfsns_alecto_v2 = (alecto_v2_t*)malloc(sizeof(alecto_v2_t)); +void RfSnsInitAlectoV2(void) { + rfsns_alecto_v2 = (alecto_v2_t*)calloc(1, sizeof(alecto_v2_t)); rfsns_any_sensor++; } -void RfSnsAnalyzeAlectov2() -{ +bool RfSnsAnalyzeAlectov2() { if (!(((rfsns_raw_signal->Number >= RFSNS_ACH2010_MIN_PULSECOUNT) && - (rfsns_raw_signal->Number <= RFSNS_ACH2010_MAX_PULSECOUNT)) || (rfsns_raw_signal->Number == RFSNS_DKW2012_PULSECOUNT))) { return; } + (rfsns_raw_signal->Number <= RFSNS_ACH2010_MAX_PULSECOUNT)) || (rfsns_raw_signal->Number == RFSNS_DKW2012_PULSECOUNT))) { return false; } uint8_t c = 0; uint8_t rfbit; @@ -470,8 +463,8 @@ void RfSnsAnalyzeAlectov2() msgtype = (data[0] >> 4) & 0xf; rc = (data[0] << 4) | (data[1] >> 4); - if (checksum != checksumcalc) { return; } - if ((msgtype != 10) && (msgtype != 5)) { return; } + if (checksum != checksumcalc) { return false; } + if ((msgtype != 10) && (msgtype != 5)) { return false; } rfsns_raw_signal->Repeats = 1; // het is een herhalend signaal. Bij ontvangst herhalingen onderdukken @@ -504,10 +497,11 @@ void RfSnsAnalyzeAlectov2() AddLog(LOG_LEVEL_DEBUG, PSTR("RFS: " D_ALECTOV2 ", ChkCalc %d, Chksum %d, rc %d, Temp %d, Hum %d, Rain %d, Wind %d, Gust %d, Dir %d, Factor %s"), checksumcalc, checksum, rc, ((data[1] & 0x3) * 256 + data[2]) - 400, data[3], (data[6] * 256) + data[7], data[4], data[5], data[8] & 0xf, dtostrfd(factor, 3, buf1)); + + return true; } -void RfSnsAlectoResetRain(void) -{ +void RfSnsAlectoResetRain(void) { if ((RtcTime.hour == 0) && (RtcTime.minute == 0) && (RtcTime.second == 5)) { rfsns_alecto_v2->rain = 0; // Reset Rain } @@ -519,8 +513,7 @@ void RfSnsAlectoResetRain(void) * http://lucsmall.com/2012/04/30/weather-station-hacking-part-3/ * https://github.com/lucsmall/WH2-Weather-Sensor-Library-for-Arduino/blob/master/WeatherSensorWH2.cpp \*********************************************************************************************/ -uint8_t RfSnsAlectoCRC8(uint8_t *addr, uint8_t len) -{ +uint8_t RfSnsAlectoCRC8(uint8_t *addr, uint8_t len) { uint8_t crc = 0; while (len--) { uint8_t inbyte = *addr++; @@ -543,8 +536,7 @@ const char HTTP_SNS_ALECTOV2_WDIR[] PROGMEM = "{s}" D_ALECTOV2 " " D_TX20_WIND_DIRECTION "{m}%s{e}"; #endif -void RfSnsAlectoV2Show(bool json) -{ +void RfSnsAlectoV2Show(bool json) { if (rfsns_alecto_v2->time) { if (rfsns_alecto_v2->time < LocalTime() - RFSNS_VALID_WINDOW) { if (json) { @@ -594,11 +586,12 @@ void RfSnsAlectoV2Show(bool json) } #endif // USE_ALECTO_V2 ********************************************************************** -void RfSnsInit(void) -{ - rfsns_raw_signal = (raw_signal_t*)(malloc(sizeof(raw_signal_t))); +void RfSnsInit(void) { + if (!PinUsed(GPIO_RF_SENSOR)) { return; } + + rfsns_raw_signal = (raw_signal_t*)(calloc(1, sizeof(raw_signal_t))); if (rfsns_raw_signal) { - memset(rfsns_raw_signal, 0, sizeof(raw_signal_t)); // Init defaults to 0 +// memset(rfsns_raw_signal, 0, sizeof(raw_signal_t)); // Init defaults to 0 #ifdef USE_THEO_V2 RfSnsInitTheoV2(); #endif @@ -616,27 +609,26 @@ void RfSnsInit(void) } } -void RfSnsAnalyzeRawSignal(void) -{ +void RfSnsAnalyzeRawSignal(void) { AddLog(LOG_LEVEL_DEBUG, PSTR("RFS: Pulses %d"), (int)rfsns_raw_signal->Number); + bool valid = false; #ifdef USE_THEO_V2 - RfSnsAnalyzeTheov2(); + if (RfSnsAnalyzeTheov2()) { valid = true; } #endif #ifdef USE_ALECTO_V2 - RfSnsAnalyzeAlectov2(); + if (RfSnsAnalyzeAlectov2()) { valid = true; } #endif + if (valid) { MqttPublishSensor(); } } -void RfSnsEverySecond(void) -{ +void RfSnsEverySecond(void) { #ifdef USE_ALECTO_V2 RfSnsAlectoResetRain(); #endif } -void RfSnsShow(bool json) -{ +void RfSnsShow(bool json) { #ifdef USE_THEO_V2 RfSnsTheoV2Show(json); #endif @@ -649,11 +641,10 @@ void RfSnsShow(bool json) * Interface \*********************************************************************************************/ -bool Xsns37(uint32_t function) -{ +bool Xsns37(uint32_t function) { bool result = false; - if (PinUsed(GPIO_RF_SENSOR) && (FUNC_INIT == function)) { + if (FUNC_INIT == function) { RfSnsInit(); } else if (rfsns_raw_signal) { diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino index 0df0973f7..0fe912e89 100755 --- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino @@ -32,7 +32,6 @@ //#define DEBUG_CNT_LED1 2 //#define DEBUG_CNT_LED1 2 - #include @@ -81,6 +80,22 @@ #define USE_SML_DECRYPT #endif +#ifndef NO_USE_SML_TCP +// modbus over TCP +#define USE_SML_TCP +#endif + +#ifndef NO_SML_OBIS_LINE +// obis in line mode +#define SML_OBIS_LINE +#endif + + +#ifdef USE_SML_TCP_SECURE +#define USE_SML_TCP_IP_STR +#endif + + // median filter eliminates outliers, but uses much RAM and CPU cycles // 672 bytes extra RAM with SML_MAX_VARS = 16 // default compile on, but must be enabled by descriptor flag 16 @@ -132,6 +147,10 @@ needs USE_SML_AUTHKEY synchronisation timout in milliseconds, after no serial data within this time serial pointer is reset to zero +7: +on esp32 the uart index may be set, normally it is allocated from 2 down to 0 automatically +thus you can combine serial SML with serial script , berry or serial drivers. + */ //#define MODBUS_DEBUG @@ -409,7 +428,8 @@ struct METER_DESC { uint8_t so_bpos1; uint8_t so_fcode2; uint8_t so_bpos2; -#endif +#endif // USE_SML_SPECOPT + #ifdef ESP32 #ifndef USE_ESP32_SW_SERIAL HardwareSerial *meter_ss; @@ -417,10 +437,12 @@ struct METER_DESC { SML_ESP32_SERIAL *meter_ss; #endif #endif // ESP32 + // software serial pointers #ifdef ESP8266 TasmotaSerial *meter_ss; #endif // ESP8266 + #ifdef USE_SML_DECRYPT bool use_crypt = false; uint8_t last_iob; @@ -428,11 +450,34 @@ struct METER_DESC { Han_Parser *hp; #ifdef USE_SML_AUTHKEY uint8_t auth[SML_CRYPT_SIZE]; -#endif +#endif // USE_SML_AUTHKEY +#endif // USE_SML_DECRYPT + +#ifdef USE_SML_TCP + +#ifdef USE_SML_TCP_IP_STR + char ip_addr[16]; +#else + IPAddress ip_addr; +#endif // USE_SML_TCP_IP_STR + +#ifdef USE_SML_TCP_SECURE + WiFiClientSecure *client; +#else + WiFiClient *client; +#endif // USE_SML_TCP_SECURE + +#endif // USE_SML_TCP + +#ifdef ESP32 + int8_t uart_index; #endif }; + +#define TCP_MODE_FLG 0x7f + struct METER_DESC meter_desc[MAX_METERS]; @@ -492,6 +537,7 @@ struct SML_GLOBS { #endif uint8_t *script_meter; struct METER_DESC *mp; + uint8_t to_cnt; bool ready; } sml_globs; @@ -573,22 +619,49 @@ double sml_median(struct SML_MEDIAN_FILTER* mf, double in) { uint16_t Serial_available() { uint8_t num = sml_globs.dump2log & 7; if (num < 1 || num > sml_globs.meters_used) num = 1; - if (!meter_desc[num - 1].meter_ss) return 0; - return meter_desc[num - 1].meter_ss->available(); + num--; + if (meter_desc[num].srcpin != TCP_MODE_FLG) { + if (!meter_desc[num].meter_ss) return 0; + return meter_desc[num].meter_ss->available(); + } else { + if (meter_desc[num].client) { + return meter_desc[num].client->available(); + } else { + return 0; + } + } } uint8_t Serial_read() { uint8_t num = sml_globs.dump2log & 7; if (num < 1 || num > sml_globs.meters_used) num = 1; - if (!meter_desc[num - 1].meter_ss) return 0; - return meter_desc[num - 1].meter_ss->read(); + num--; + if (meter_desc[num].srcpin != TCP_MODE_FLG) { + if (!meter_desc[num].meter_ss) return 0; + return meter_desc[num].meter_ss->read(); + } else { + if (meter_desc[num].client) { + return meter_desc[num].client->read(); + } else { + return 0; + } + } } uint8_t Serial_peek() { uint8_t num = sml_globs.dump2log & 7; if (num < 1 || num > sml_globs.meters_used) num = 1; - if (!meter_desc[num - 1].meter_ss) return 0; - return meter_desc[num - 1].meter_ss->peek(); + num--; + if (meter_desc[num].srcpin != TCP_MODE_FLG) { + if (!meter_desc[num].meter_ss) return 0; + return meter_desc[num].meter_ss->peek(); + } else { + if (meter_desc[num].client) { + return meter_desc[num].client->peek(); + } else { + return 0; + } + } } void sml_dump_start(char c) { @@ -599,7 +672,7 @@ void sml_dump_start(char c) { #define SML_EBUS_SKIP_SYNC_DUMPS -uint8_t *hdlc_decode(struct METER_DESC *mp, uint16_t *size); + void dump2log(void) { int16_t index = 0, hcnt = 0; @@ -1206,7 +1279,17 @@ void sml_shift_in(uint32_t meters, uint32_t shard) { mp->sbuff[count] = mp->sbuff[count + 1]; } } - uint8_t iob = (uint8_t)mp->meter_ss->read(); + + uint8_t iob; + if (mp->srcpin != TCP_MODE_FLG) { + iob = (uint8_t)mp->meter_ss->read(); + } else { + if (mp->client) { + iob = (uint8_t)mp->client->read(); + } else { + iob = 0; + } + } switch (mp->type) { case 'o': @@ -1289,6 +1372,22 @@ void sml_shift_in(uint32_t meters, uint32_t shard) { if (mp->spos >= mp->sbsiz) { mp->spos = 0; } + if (mp->srcpin == TCP_MODE_FLG) { + // tcp read + if (mp->spos >= 6) { + uint8_t tlen = (mp->sbuff[4] << 8) | mp->sbuff[5]; + if (mp->spos == 6 + tlen) { + mp->spos = 0; + SML_Decode(meters); + if (mp->client) { + mp->client->flush(); + } + //Hexdump(mp->sbuff + 6, 10); + } + } + break; + } + if (mp->spos >= 3) { uint32_t mlen = mp->sbuff[2] + 5; if (mlen > mp->sbsiz) mlen = mp->sbsiz; @@ -1369,23 +1468,26 @@ void SML_Poll(void) { uint32_t meters; for (meters = 0; meters < sml_globs.meters_used; meters++) { - if (sml_globs.mp[meters].type != 'c') { - // poll for serial input - if (!meter_desc[meters].meter_ss) continue; - if (sml_globs.ser_act_LED_pin != 255 && (sml_globs.ser_act_meter_num == 0 || sml_globs.ser_act_meter_num - 1 == meters)) { - digitalWrite(sml_globs.ser_act_LED_pin, meter_desc[meters].meter_ss->available() && !digitalRead(sml_globs.ser_act_LED_pin)); // Invert LED, if queue is continuously full + struct METER_DESC *mp = &meter_desc[meters]; + if (mp->type != 'c') { + if (mp->srcpin != TCP_MODE_FLG) { + if (!mp->meter_ss) continue; + // poll for serial input + if (sml_globs.ser_act_LED_pin != 255 && (sml_globs.ser_act_meter_num == 0 || sml_globs.ser_act_meter_num - 1 == meters)) { + digitalWrite(sml_globs.ser_act_LED_pin, mp->meter_ss->available() && !digitalRead(sml_globs.ser_act_LED_pin)); // Invert LED, if queue is continuously full + } + while (mp->meter_ss->available()) { + sml_shift_in(meters, 0); + } + } else { +#ifdef USE_SML_TCP + if (mp->client) { + while (mp->client->available()){ + sml_shift_in(meters, 0); + } + } +#endif } - while (meter_desc[meters].meter_ss->available()) { - sml_shift_in(meters, 0); - } -/* - if (meter_desc[meters].meter_ss->available()) { - sml_count++; - uint8_t iob = meter_desc[meters].meter_ss->read(); - if (sml_count<5 || sml_count > 100) { - AddLog(LOG_LEVEL_INFO, PSTR(">> %02x - %d"),iob,sml_count); - } - }*/ } } } @@ -1656,6 +1758,11 @@ void SML_Decode(uint8_t index) { double ebus_dval = 99; double mbus_dval = 99; while (*mp != '@') { + if (found == 0) { + // skip rest of decoder part + mp++; + continue; + } if (sml_globs.mp[mindex].type == 'o' || sml_globs.mp[mindex].type == 'c') { if (*mp++ != *cp++) { found=0; @@ -2545,12 +2652,18 @@ struct METER_DESC *mp = &meter_desc[mnum]; mp->auth[cnt / 2] = (sml_hexnibble(cp[cnt]) << 4) | sml_hexnibble(cp[cnt + 1]); } break; +#endif // USE_SML_AUTHKEY +#endif // USE_SML_DECRYPT case '6': cp += 2; mp->tout_ms = strtol(cp, &cp, 10); + break; + case '7': + cp += 2; +#ifdef ESP32 + mp->uart_index = strtol(cp, &cp, 10); +#endif // ESP32 break; -#endif -#endif } return cp; } @@ -2630,6 +2743,10 @@ void reset_sml_vars(uint16_t maxmeters) { mp->lastms = millis(); mp->tout_ms = SML_STIMEOUT; +#ifdef ESP32 + mp->uart_index = -1; +#endif + #ifdef USE_SML_DECRYPT if (mp->use_crypt) { if (mp->hp) { @@ -2707,8 +2824,13 @@ void SML_Init(void) { uint32_t mlen; uint16_t memory = 0; +#ifdef ESP32 + uint32_t uart_index = SOC_UART_NUM - 1; +#endif + sml_globs.sml_send_blocks = 0; lp = glob_script_mem.section_ptr; + struct METER_DESC *mmp; while (lp) { if (!section) { if (*lp == '>' && *(lp + 1) == 'M') { @@ -2741,93 +2863,119 @@ void SML_Init(void) { goto next_line; } index--; - srcpin = strtol(lp, &lp, 10); - if (Gpio_used(abs(srcpin))) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"), abs(srcpin), index + 1); + mmp = &meter_desc[index]; + if (*lp == '[') { + // sign TCP mode + srcpin = TCP_MODE_FLG; + lp++; + char str[32]; + uint8_t cnt; + for (cnt = 0; cnt < sizeof(str) - 1; cnt++) { + if (!*lp || *lp == '\n' || *lp == ']') { + break; + } + str[cnt] = *lp++; + } + str[cnt] = 0; + lp++; +#ifdef USE_SML_TCP +#ifdef USE_SML_TCP_IP_STR + strcpy(mmp->ip_addr, str); +#else + mmp->ip_addr.fromString(str); +#endif +#endif + } else { + srcpin = strtol(lp, &lp, 10); + if (Gpio_used(abs(srcpin))) { + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"), abs(srcpin), index + 1); dddef_exit: - if (sml_globs.script_meter) free(sml_globs.script_meter); - sml_globs.script_meter = 0; - return; + if (sml_globs.script_meter) free(sml_globs.script_meter); + sml_globs.script_meter = 0; + return; + } } - meter_desc[index].srcpin = srcpin; + mmp->srcpin = srcpin; if (*lp != ',') goto next_line; lp++; - meter_desc[index].type = *lp; + mmp->type = *lp; lp++; if (*lp != ',') { switch (*lp) { case 'N': lp++; - meter_desc[index].sopt = 0x10 | (*lp & 3); + mmp->sopt = 0x10 | (*lp & 3); lp++; break; case 'E': lp++; - meter_desc[index].sopt = 0x20 | (*lp & 3); + mmp->sopt = 0x20 | (*lp & 3); lp++; break; case 'O': lp++; - meter_desc[index].sopt = 0x30 | (*lp & 3); + mmp->sopt = 0x30 | (*lp & 3); lp++; break; default: - meter_desc[index].sopt = *lp&7; + mmp->sopt = *lp&7; lp++; } } else { - meter_desc[index].sopt = 0; + mmp->sopt = 0; } lp++; - meter_desc[index].flag = strtol(lp, &lp, 10); + mmp->flag = strtol(lp, &lp, 10); if (*lp != ',') goto next_line; lp++; - meter_desc[index].params = strtol(lp, &lp, 10); + mmp->params = strtol(lp, &lp, 10); if (*lp != ',') goto next_line; lp++; - meter_desc[index].prefix[7] = 0; + mmp->prefix[7] = 0; for (uint32_t cnt = 0; cnt < 8; cnt++) { if (*lp == SCRIPT_EOL || *lp == ',') { - meter_desc[index].prefix[cnt] = 0; + mmp->prefix[cnt] = 0; break; } - meter_desc[index].prefix[cnt] = *lp++; + mmp->prefix[cnt] = *lp++; } if (*lp == ',') { lp++; // get TRX pin - meter_desc[index].trxpin = strtol(lp, &lp, 10); - if (Gpio_used(meter_desc[index].trxpin)) { - AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), meter_desc[index].trxpin, index + 1); - goto dddef_exit; + mmp->trxpin = strtol(lp, &lp, 10); + if (mmp->srcpin != TCP_MODE_FLG) { + if (Gpio_used(mmp->trxpin)) { + AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), meter_desc[index].trxpin, index + 1); + goto dddef_exit; + } } // optional transmit enable pin if (*lp == '(') { lp++; if (*lp == 'i') { lp++; - meter_desc[index].trx_en.trxenpol = 1; + mmp->trx_en.trxenpol = 1; } else { - meter_desc[index].trx_en.trxenpol = 0; + mmp->trx_en.trxenpol = 0; } - meter_desc[index].trx_en.trxenpin = strtol(lp, &lp, 10); + mmp->trx_en.trxenpin = strtol(lp, &lp, 10); if (*lp != ')') { goto dddef_exit; } lp++; - if (Gpio_used(meter_desc[index].trx_en.trxenpin)) { + if (Gpio_used(mmp->trx_en.trxenpin)) { AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX enable in meter number %d"), meter_desc[index].trx_en.trxenpin, index + 1); goto dddef_exit; } - meter_desc[index].trx_en.trxen = 1; - pinMode(meter_desc[index].trx_en.trxenpin, OUTPUT); - digitalWrite(meter_desc[index].trx_en.trxenpin, meter_desc[index].trx_en.trxenpol); + mmp->trx_en.trxen = 1; + pinMode(mmp->trx_en.trxenpin, OUTPUT); + digitalWrite(mmp->trx_en.trxenpin, mmp->trx_en.trxenpol); } else { - meter_desc[index].trx_en.trxen = 0; + mmp->trx_en.trxen = 0; } if (*lp != ',') goto next_line; lp++; - meter_desc[index].tsecs = strtol(lp, &lp, 10); + mmp->tsecs = strtol(lp, &lp, 10); if (*lp == ',') { lp++; // look ahead @@ -2851,9 +2999,9 @@ dddef_exit: txlen++; } if (txlen) { - meter_desc[index].txmem = (char*)calloc(txlen + 2, 1); + mmp->txmem = (char*)calloc(txlen + 2, 1); memory += txlen + 2; - if (meter_desc[index].txmem) { + if (mmp->txmem) { // now copy send blocks char *txp = lp; uint16_t tind = 0; @@ -2861,14 +3009,14 @@ dddef_exit: if (*txp == SCRIPT_EOL) { txp++; } else { - meter_desc[index].txmem[tind] = *txp++; + mmp->txmem[tind] = *txp++; tind++; } } } //AddLog(LOG_LEVEL_INFO, PSTR(">>> %s - %d"), meter_desc[index].txmem, txlen); - meter_desc[index].index = 0; - meter_desc[index].max_index = tx_entries; + mmp->index = 0; + mmp->max_index = tx_entries; sml_globs.sml_send_blocks++; lp += txlen; } @@ -2948,28 +3096,27 @@ next_line: RtcSettings.pulse_counter[i] = Settings->pulse_counter[i]; sml_counters[i].sml_cnt_last_ts = millis(); } -#ifdef ESP32 - uint32_t uart_index = SOC_UART_NUM - 1; -#endif + sml_counter_pinstate = 0; for (uint8_t meters = 0; meters < sml_globs.meters_used; meters++) { - if (sml_globs.mp[meters].type == 'c') { - if (sml_globs.mp[meters].flag & 2) { + METER_DESC *mp = &meter_desc[meters]; + if (mp->type == 'c') { + if (mp->flag & 2) { } else { // counters, set to input with pullup - if (sml_globs.mp[meters].flag & 1) { - pinMode(sml_globs.mp[meters].srcpin, INPUT_PULLUP); + if (mp->flag & 1) { + pinMode(mp->srcpin, INPUT_PULLUP); } else { - pinMode(sml_globs.mp[meters].srcpin, INPUT); + pinMode(mp->srcpin, INPUT); } // check for irq mode - if (sml_globs.mp[meters].params <= 0) { + if (mp->params <= 0) { // init irq mode sml_counters[cindex].sml_cnt_old_state = meters; sml_counters[cindex].sml_debounce = -sml_globs.mp[meters].params; - attachInterruptArg(sml_globs.mp[meters].srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE); - if (digitalRead(sml_globs.mp[meters].srcpin) > 0) { + attachInterruptArg(mp->srcpin, SML_CounterIsr, &sml_cnt_index[cindex], CHANGE); + if (digitalRead(mp->srcpin) > 0) { sml_counter_pinstate |= (1 << cindex); } sml_counters[cindex].sml_counter_ltime = millis(); @@ -2981,86 +3128,97 @@ next_line: } } else { // serial input, init + if (mp->srcpin == TCP_MODE_FLG) { +#ifdef USE_SML_TCP + sml_tcp_init(mp); +#endif + } else { + // serial mode #ifdef ESP8266 #ifdef SPECIAL_SS - char type = sml_globs.mp[meters].type; + char type = mp->type; if (type == 'm' || type == 'M' || type == 'k' || type == 'p' || type == 'R' || type == 'v') { - meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); + mp->meter_ss = new TasmotaSerial(mp->srcpin, mp->trxpin, 1, 0, mp->sibsiz); } else { - meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 1, meter_desc[meters].sibsiz); + mp->meter_ss = new TasmotaSerial(mp->srcpin, mp->trxpin, 1, 1, mp->sibsiz); } #else - meter_desc[meters].meter_ss = new TasmotaSerial(sml_globs.mp[meters].srcpin,sml_globs.mp[meters].trxpin, 1, 0, meter_desc[meters].sibsiz); + mp->meter_ss = new TasmotaSerial(mp->srcpin, mp->trxpin, 1, 0, mp->sibsiz); #endif // SPECIAL_SS #endif // ESP8266 #ifdef ESP32 // use hardware serial + if (mp->uart_index >= 0) { + uart_index = mp->uart_index; + } + AddLog(LOG_LEVEL_INFO, PSTR("SML: uart used: %d"),uart_index); #ifdef USE_ESP32_SW_SERIAL - meter_desc[meters].meter_ss = new SML_ESP32_SERIAL(uart_index); - if (sml_globs.mp[meters].srcpin >= 0) { + mp->meter_ss = new SML_ESP32_SERIAL(uart_index); + if (mp->srcpin >= 0) { if (uart_index == 0) { ClaimSerial(); } uart_index--; if (uart_index < 0) uart_index = 0; } #else - meter_desc[meters].meter_ss = new HardwareSerial(uart_index); + mp->meter_ss = new HardwareSerial(uart_index); if (uart_index == 0) { ClaimSerial(); } uart_index--; if (uart_index < 0) uart_index = 0; - meter_desc[meters].meter_ss->setRxBufferSize(meter_desc[meters].sibsiz); + mp->meter_ss->setRxBufferSize(mp->sibsiz); #endif // USE_ESP32_SW_SERIAL #endif // ESP32 - SerialConfig smode = SERIAL_8N1; + uint32_t smode = SERIAL_8N1; - if (sml_globs.mp[meters].sopt & 0xf0) { + if (mp->sopt & 0xf0) { // new serial config - switch (sml_globs.mp[meters].sopt >> 4) { + switch (mp->sopt >> 4) { case 1: - if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8N1; + if ((mp->sopt & 1) == 1) smode = SERIAL_8N1; else smode = SERIAL_8N2; break; case 2: - if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8E1; + if ((mp->sopt & 1) == 1) smode = SERIAL_8E1; else smode = SERIAL_8E2; break; case 3: - if ((sml_globs.mp[meters].sopt & 1) == 1) smode = SERIAL_8O1; + if ((mp->sopt & 1) == 1) smode = SERIAL_8O1; else smode = SERIAL_8O2; break; } } else { // deprecated serial config - if (sml_globs.mp[meters].sopt == 2) { + if (mp->sopt == 2) { smode = SERIAL_8N2; } - if (sml_globs.mp[meters].type=='M') { + if (mp->type=='M') { smode = SERIAL_8E1; - if (sml_globs.mp[meters].sopt == 2) { + if (mp->sopt == 2) { smode = SERIAL_8E2; } } } #ifdef ESP8266 - if (meter_desc[meters].meter_ss->begin(sml_globs.mp[meters].params)) { - meter_desc[meters].meter_ss->flush(); + if (mp->meter_ss->begin(mp->params)) { + mp->meter_ss->flush(); } - if (meter_desc[meters].meter_ss->hardwareSerial()) { - Serial.begin(sml_globs.mp[meters].params, smode); + if (mp->meter_ss->hardwareSerial()) { + Serial.begin(mp->params, (SerialConfig)smode); ClaimSerial(); //Serial.setRxBufferSize(512); } #endif // ESP8266 #ifdef ESP32 - meter_desc[meters].meter_ss->begin(sml_globs.mp[meters].params, smode, sml_globs.mp[meters].srcpin, sml_globs.mp[meters].trxpin); + mp->meter_ss->begin(mp->params, smode, mp->srcpin, mp->trxpin); #ifdef USE_ESP32_SW_SERIAL - meter_desc[meters].meter_ss->setRxBufferSize(meter_desc[meters].sibsiz); + mp->meter_ss->setRxBufferSize(mp->sibsiz); #endif #endif // ESP32 + } } } @@ -3163,7 +3321,7 @@ uint32_t SML_Write(int32_t meter, char *hstr) { hstr++; // currently only 8 bits and ignore stopbits hstr++; - SerialConfig smode; + uint32_t smode; switch (*hstr) { case 'N': smode = SERIAL_8N1; @@ -3177,7 +3335,7 @@ uint32_t SML_Write(int32_t meter, char *hstr) { } #ifdef ESP8266 - Serial.begin(baud, smode); + Serial.begin(baud, (SerialConfig)smode); #else meter_desc[meter].meter_ss->begin(baud, smode, sml_globs.mp[meter].srcpin, sml_globs.mp[meter].trxpin); #endif @@ -3276,8 +3434,10 @@ void SML_Counter_Poll_1s(void) { } } -#define CNT_PULSE_TIMEOUT 5000 +#ifndef CNT_PULSE_TIMEOUT +#define CNT_PULSE_TIMEOUT 5000 +#endif // fast counter polling void SML_Counter_Poll(void) { @@ -3439,8 +3599,105 @@ uint8_t sml_hexnibble(char chr) { return rVal; } +typedef struct { + uint16_t T_ID; + uint16_t P_ID; + uint16_t SIZE; + uint8_t U_ID; + uint8_t payload[8]; + } MODBUS_TCP_HEADER; + +uint16_t sml_swap(uint16_t in) { + return (in << 8) || in >> 8; +} + +// send modbus TCP frame with payload +// given ip addr and port in baudrate +void sml_tcp_send(uint32_t meter, uint8_t *sbuff, uint16_t slen) { +MODBUS_TCP_HEADER tcph; + + tcph.T_ID = sml_swap(0x1234); + tcph.P_ID = 0; + tcph.SIZE = sml_swap(6); + tcph.U_ID = *sbuff; + + sbuff++; + for (uint8_t cnt = 0; cnt < slen - 3; cnt++) { + tcph.payload[cnt] = *sbuff++; + } + +#ifdef USE_SML_TCP + // AddLog(LOG_LEVEL_INFO, PSTR("slen >> %d "),slen); + if (meter_desc[meter].client) { + if (meter_desc[meter].client->connected()) { + meter_desc[meter].client->write((uint8_t*)&tcph, 7 + slen - 3); + } + } +#endif +} + +#ifdef USE_SML_TCP +int32_t sml_tcp_init(struct METER_DESC *mp) { + if (!TasmotaGlobal.global_state.wifi_down) { + if (!mp->client) { + // tcp mode +#ifdef USE_SML_TCP_SECURE + mp->client = new WiFiClientSecure; + //client(new BearSSL::WiFiClientSecure_light(1024,1024)) { + mp->client->setInsecure(); +#else + mp->client = new WiFiClient; +#endif // USE_SML_TCP_SECURE + } + int32_t err = mp->client->connect(mp->ip_addr, mp->params); + char ipa[32]; +#ifdef USE_SML_TCP_IP_STR + strcpy(ipa, mp->ip_addr); +#else + strcpy(ipa, mp->ip_addr.toString().c_str()); +#endif + if (!err) { + AddLog(LOG_LEVEL_INFO, PSTR("SML: could not connect TCP to %s:%d"),ipa, mp->params); + } else { + AddLog(LOG_LEVEL_INFO, PSTR("SML: connected TCP to %s:%d"),ipa, mp->params); + } + } else { + AddLog(LOG_LEVEL_INFO, PSTR("SML: could not connect TCP since wifi is down")); + mp->client = nullptr; + return -1; + } + return 0; +} + +#ifndef TCP_TIMEOUT +#define TCP_TIMEOUT 30 +#endif + +void sml_tcp_check(void) { + sml_globs.to_cnt++; + if (sml_globs.to_cnt > TCP_TIMEOUT) { + sml_globs.to_cnt = 0; + for (uint32_t meter = 0; meter < sml_globs.meters_used; meter++) { + struct METER_DESC *mp = &sml_globs.mp[meter]; + if (mp->srcpin == TCP_MODE_FLG) { + if (!mp->client) { + sml_tcp_init(mp); + } else { + if (!mp->client->connected()) { + sml_tcp_init(mp); + } + } + } + } + } +} + + +#endif // USE_SML_TCP + + // send sequence every N Seconds -void SML_Send_Seq(uint32_t meter,char *seq) { +void SML_Send_Seq(uint32_t meter, char *seq) { uint8_t sbuff[48]; uint8_t *ucp = sbuff, slen = 0; char *cp = seq; @@ -3517,16 +3774,19 @@ void SML_Send_Seq(uint32_t meter,char *seq) { slen += 6; } - if (meter_desc[meter].trx_en.trxen) { - digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1); - } - meter_desc[meter].meter_ss->flush(); - meter_desc[meter].meter_ss->write(sbuff, slen); - - if (meter_desc[meter].trx_en.trxen) { - // must wait for all data sent + if (meter_desc[meter].srcpin == TCP_MODE_FLG) { + sml_tcp_send(meter, sbuff, slen); + } else { + if (meter_desc[meter].trx_en.trxen) { + digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol ^ 1); + } meter_desc[meter].meter_ss->flush(); - digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol); + meter_desc[meter].meter_ss->write(sbuff, slen); + if (meter_desc[meter].trx_en.trxen) { + // must wait for all data sent + meter_desc[meter].meter_ss->flush(); + digitalWrite(meter_desc[meter].trx_en.trxenpin, meter_desc[meter].trx_en.trxenpol); + } } if (sml_globs.dump2log) { @@ -3750,6 +4010,9 @@ bool Xsns53(uint32_t function) { if (bitRead(Settings->rule_enabled, 0)) { if (sml_globs.ready) { SML_Counter_Poll_1s(); +#ifdef USE_SML_TCP + sml_tcp_check(); +#endif } } break; diff --git a/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino b/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino index 65b1fe6b9..a318150d7 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino @@ -78,31 +78,23 @@ void HpmaInit(void) } } -#ifdef USE_WEBSERVER -const char HTTP_HPMA_SNS[] PROGMEM = - "{s}HPMA " D_ENVIRONMENTAL_CONCENTRATION "2.5 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}HPMA " D_ENVIRONMENTAL_CONCENTRATION "10 " D_UNIT_MICROMETER "{m}%s " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = -#endif // USE_WEBSERVER - -void HpmaShow(bool json) -{ +void HpmaShow(bool json) { if (hpma_valid) { - char pm10[33]; - snprintf_P(pm10, 33, PSTR("%d"), hpma_data.pm10); - char pm2_5[33]; - snprintf_P(pm2_5, 33, PSTR("%d"), hpma_data.pm2_5); + char types[10]; + strcpy_P(types, PSTR("HPMA")); if (json) { - ResponseAppend_P(PSTR(",\"HPMA\":{\"PM2.5\":%d,\"PM10\":%d}"), hpma_data.pm2_5, hpma_data.pm10); + ResponseAppend_P(PSTR(",\"%s\":{\"PM2.5\":%d,\"PM10\":%d}"), types, hpma_data.pm2_5, hpma_data.pm10); #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) { - DomoticzSensor(DZ_VOLTAGE, pm2_5); // PM2.5 - DomoticzSensor(DZ_CURRENT, pm10); // PM10 + DomoticzSensor(DZ_VOLTAGE, hpma_data.pm2_5); // PM2.5 + DomoticzSensor(DZ_CURRENT, hpma_data.pm10); // PM10 } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_HPMA_SNS, pm2_5, pm10); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "2.5", hpma_data.pm2_5); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "10", hpma_data.pm10); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino b/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino index c170e1b0e..fc53bd920 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino @@ -48,6 +48,7 @@ Driver is tested on a NEO-6m and a Beitian-220. Series 7 should work too. This a - Web-UI - simplified NTP-server and UART-over-TCP/IP-bridge (virtual serial port) - command interface +- velocity and heading information with #define USE_GPS_VELOCITY ## Usage: The serial pins are GPS_RX and GPS_TX, no further installation steps needed. To get more debug information compile it with option "DEBUG_TASMOTA_SENSOR". @@ -129,7 +130,7 @@ const char S_JSON_UBX_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_UBX "%s\":%d}"; const char kUBXTypes[] PROGMEM = "UBX"; -#define UBX_LAT_LON_THRESHOLD 1000 // filter out some noise of local drift +#define UBX_LAT_LON_THRESHOLD 100 // filter out some noise of local drift #define UBX_SERIAL_BUFFER_SIZE 256 #define UBX_TCP_PORT 1234 @@ -153,13 +154,18 @@ const char UBLOX_INIT[] PROGMEM = { 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xB9, //NAV-POSLLH off 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0xC0, //NAV-STATUS off 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x92, //NAV-TIMEUTC off +#ifdef USE_GPS_VELOCITY + 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x22,0x29, //NAV-VELNED off +#endif // Enable UBX // 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x07,0x00,0x01,0x00,0x00,0x00,0x00,0x18,0xE1, //NAV-PVT on 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x02,0x00,0x01,0x00,0x00,0x00,0x00,0x13,0xBE, //NAV-POSLLH on 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x14,0xC5, //NAV-STATUS on 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x21,0x00,0x01,0x00,0x00,0x00,0x00,0x32,0x97, //NAV-TIMEUTC on - +#ifdef USE_GPS_VELOCITY + 0xB5,0x62,0x06,0x01,0x08,0x00,0x01,0x12,0x00,0x01,0x00,0x00,0x00,0x00,0x23,0x2E, //NAV-VELNED on +#endif // Rate - we will not reset it for the moment after restart // 0xB5,0x62,0x06,0x08,0x06,0x00,0x64,0x00,0x01,0x00,0x01,0x00,0x7A,0x12, //(10Hz) // 0xB5,0x62,0x06,0x08,0x06,0x00,0xC8,0x00,0x01,0x00,0x01,0x00,0xDE,0x6A, //(5Hz) @@ -174,6 +180,9 @@ struct UBX_t { const char NAV_POSLLH_HEADER[2] = { 0x01, 0x02 }; const char NAV_STATUS_HEADER[2] = { 0x01, 0x03 }; const char NAV_TIME_HEADER[2] = { 0x01, 0x21 }; +#ifdef USE_GPS_VELOCITY + const char NAV_VEL_HEADER[2] = { 0x01, 0x12 }; +#endif struct entry_t { int32_t lat; //raw sensor value @@ -238,7 +247,22 @@ struct UBX_t { uint8_t padding:5; } valid; }; - +#ifdef USE_GPS_VELOCITY + struct NAV_VEL { + uint8_t cls; + uint8_t id; + uint16_t len; + uint32_t iTOW; + int32_t velN; + int32_t velE; //bit 0 - gpsfix valid + int32_t velD; + uint32_t speed; + uint32_t gSpeed; + int32_t heading; + uint32_t sAcc; + uint32_t cAcc; + }; +#endif struct CFG_RATE { uint8_t cls; //0x06 uint8_t id; //0x08 @@ -276,6 +300,9 @@ struct UBX_t { NAV_POSLLH navPosllh; NAV_STATUS navStatus; NAV_TIME_UTC navTime; +#ifdef USE_GPS_VELOCITY + NAV_VEL navVel; +#endif POLL_MSG pollMsg; CFG_RATE cfgRate; } Message; @@ -291,6 +318,9 @@ enum UBXMsgType { MT_NAV_POSLLH, MT_NAV_STATUS, MT_NAV_TIME, +#ifdef USE_GPS_VELOCITY + MT_NAV_VEL, +#endif MT_POLL }; @@ -426,6 +456,13 @@ uint32_t UBXprocessGPS() payloadSize = sizeof(UBX_t::NAV_TIME_UTC); DEBUG_SENSOR_LOG(PSTR("UBX: got NAV_TIME_UTC")); } +#ifdef USE_GPS_VELOCITY + else if ( UBXcompareMsgHeader(UBX.NAV_VEL_HEADER) ) { + currentMsgType = MT_NAV_VEL; + payloadSize = sizeof(UBX_t::NAV_VEL); + DEBUG_SENSOR_LOG(PSTR("UBX: got NAV_VEL")); + } +#endif else { // unknown message type, bail fpos = 0; @@ -506,7 +543,7 @@ void UBXsendRecord(uint8_t *buf) void UBXsendFooter(void) { - Webserver->sendContent(F("\n\n")); + Webserver->sendContent(F("\n\n")); Webserver->sendContent(""); Rtc.user_time_entry = false; // we have blocked the main loop and want a new valid time } @@ -590,8 +627,15 @@ void UBXSelectMode(uint16_t mode) break; case 10: UBX.mode.runningNTP = false; +#ifdef USE_GPS_VELOCITY + UBXsendCFGLine(11); //NAV-POSLLH on + UBXsendCFGLine(12); //NAV-STATUS on + UBXsendCFGLine(14); //NAV-VELNED on +#endif +#ifndef USE_GPS_VELOCITY UBXsendCFGLine(10); //NAV-POSLLH on UBXsendCFGLine(11); //NAV-STATUS on +#endif break; case 11: UBX.mode.forceUTCupdate = true; @@ -646,7 +690,11 @@ bool UBXHandlePOSLLH() if (UBX.mode.runningNTP){ // after receiving pos-data at least once -> go to pure NTP-mode UBXsendCFGLine(7); //NAV-POSLLH off UBXsendCFGLine(8); //NAV-STATUS off +#ifdef USE_GPS_VELOCITY + UBXsendCFGLine(10); //NAV-VELNED off +#endif } + //UBX_LAT_LON_THRESHOLD = 20 * UBX.Message.navPosllh.hAcc; return true; // new position } else { DEBUG_SENSOR_LOG(PSTR("UBX: no valid position data")); @@ -654,6 +702,20 @@ bool UBXHandlePOSLLH() return false; // no GPS-fix } +#ifdef USE_GPS_VELOCITY +void UBXHandleVEL() + { + DEBUG_SENSOR_LOG(PSTR("UBX: iTOWvel: %u"),UBX.Message.navVel.iTOW); + if (UBX.state.gpsFix>1) { + DEBUG_SENSOR_LOG(PSTR("UBX: speed: %d"), UBX.Message.navVel.gSpeed); + DEBUG_SENSOR_LOG(PSTR("UBX: heading: %i"), UBX.Message.navVel.heading); + DEBUG_SENSOR_LOG(PSTR("UBX: spd accuracy: %i"), UBX.Message.navVel.sAcc); + DEBUG_SENSOR_LOG(PSTR("UBX: hdng accuracy: %i"), UBX.Message.navVel.cAcc); + } + +} +#endif + void UBXHandleSTATUS() { DEBUG_SENSOR_LOG(PSTR("UBX: gpsFix: %u, valid: %u"), UBX.Message.navStatus.gpsFix, (UBX.Message.navStatus.flags)&1); @@ -667,7 +729,7 @@ void UBXHandleSTATUS() void UBXHandleTIME() { DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time: %u-%u-%u %u:%u:%u"), UBX.Message.navTime.year, UBX.Message.navTime.month ,UBX.Message.navTime.day,UBX.Message.navTime.hour,UBX.Message.navTime.min,UBX.Message.navTime.sec); - if ((UBX.Message.navTime.valid.UTC == 1) && (UBX.Message.navTime.year >= 2023)) { + if ((UBX.Message.navTime.valid.UTC == 1) && (UBX.Message.navTime.year >= 2023)) { UBX.state.timeOffset = millis(); // iTOW%1000 should be 0 here, when NTP-server is enabled and in "pure mode" DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time is valid")); bool resync = (Rtc.utc_time > UBX.utc_time); // Sync local time every hour @@ -744,6 +806,11 @@ void UBXLoop(void) case MT_NAV_TIME: UBXHandleTIME(); break; +#ifdef USE_GPS_VELOCITY + case MT_NAV_VEL: + UBXHandleVEL(); + break; +#endif default: UBXHandleOther(); break; @@ -791,7 +858,14 @@ void UBXLoop(void) "{s} GPS altitude {m}%s m{e}" "{s} GPS hor. Accuracy {m}%s m{e}" "{s} GPS vert. Accuracy {m}%s m{e}" - "{s} GPS sat-fix status {m}%s{e}"; + "{s} GPS sat-fix status {m}%s{e}" +#ifdef USE_GPS_VELOCITY + "{s} GPS Speed {m}%s{e}" + "{s} GPS Heading {m}%s{e}" + "{s} GPS Heading Acc {m}%s{e}" + "{s} GPS Speed Acc {m}%s{e}" +#endif + ; const char kGPSFix0[] PROGMEM = "no fix"; const char kGPSFix1[] PROGMEM = "dead reckoning only"; @@ -815,11 +889,23 @@ void UBXShow(bool json) char alt[12]; char hAcc[12]; char vAcc[12]; + #ifdef USE_GPS_VELOCITY + char spd[12]; + char hdng[12]; + char cAcc[12]; + char sAcc[12]; + #endif dtostrfd((double)UBX.rec_buffer.values.lat/10000000.0f,7,lat); dtostrfd((double)UBX.rec_buffer.values.lon/10000000.0f,7,lon); dtostrfd((double)UBX.state.last_alt/1000.0f,3,alt); dtostrfd((double)UBX.state.last_vAcc/1000.0f,3,hAcc); dtostrfd((double)UBX.state.last_hAcc/1000.0f,3,vAcc); + #ifdef USE_GPS_VELOCITY + dtostrfd((double)UBX.Message.navVel.gSpeed/27.778f,1,spd); + dtostrfd((double)UBX.Message.navVel.heading/100000.0f,1,hdng); + dtostrfd((double)UBX.Message.navVel.cAcc/100000.0f,2,cAcc); + dtostrfd((double)UBX.Message.navVel.sAcc/100000.0f,2,sAcc); + #endif if (json) { ResponseAppend_P(PSTR(",\"GPS\":{")); @@ -827,7 +913,11 @@ void UBXShow(bool json) uint32_t i = UBX.state.log_interval / 10; ResponseAppend_P(PSTR("\"fil\":%u,\"int\":%u}"), UBX.mode.filter_noise, i); } else { - ResponseAppend_P(PSTR("\"lat\":%s,\"lon\":%s,\"alt\":%s,\"hAcc\":%s,\"vAcc\":%s}"), lat, lon, alt, hAcc, vAcc); + ResponseAppend_P(PSTR("\"lat\":%s,\"lon\":%s,\"alt\":%s,\"hAcc\":%s,\"vAcc\":%s,\"fix\":\"%s\""), lat, lon, alt, hAcc, vAcc, kGPSFix[UBX.state.gpsFix]); +#ifdef USE_GPS_VELOCITY + ResponseAppend_P(PSTR(,\"spd\":%s,\"hdng\":%s,\"cAcc\":%s,\"sAcc\":%s"), spd, hdng, cAcc, sAcc); +#endif + ResponseAppend_P(PSTR("}")); } #ifdef USE_FLOG ResponseAppend_P(PSTR(",\"FLOG\":{\"rec\":%u,\"mode\":%u,\"sec\":%u}"), Flog->recording, Flog->mode, Flog->sectors_left); @@ -835,7 +925,12 @@ void UBXShow(bool json) UBX.mode.send_UI_only = false; #ifdef USE_WEBSERVER } else { +#ifdef USE_GPS_VELOCITY + WSContentSend_PD(HTTP_SNS_GPS, lat, lon, alt, hAcc, vAcc, kGPSFix[UBX.state.gpsFix], spd, hdng, cAcc, sAcc); +#endif +#ifndef USE_GPS_VELOCITY WSContentSend_PD(HTTP_SNS_GPS, lat, lon, alt, hAcc, vAcc, kGPSFix[UBX.state.gpsFix]); +#endif //WSContentSend_P(UBX_GOOGLE_MAPS, lat, lon); #ifdef DEBUG_TASMOTA_SENSOR #ifdef USE_FLOG @@ -927,4 +1022,4 @@ bool Xsns60(uint32_t function) return result; } -#endif // USE_GPS \ No newline at end of file +#endif // USE_GPS diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino index d1a0ebcb6..6f5a9d124 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino @@ -304,6 +304,19 @@ struct PVVXPacket_t { uint8_t flags; }; +struct CGDK2Packet_t { + //uint8_t size; // = 17 + uint16_t framedata; + uint8_t MAC[6]; // [0] - lo, .. [6] - hi digits + uint16_t devicetype; + int16_t temperature; // x 0.1 degree + uint16_t humidity; // x 0.01 % + uint16_t battery_mv; // mV + uint8_t battery_level; // 0..100 % + uint8_t counter; // measurement count + uint8_t flags; +}; + struct MiScaleV1Packet_t { //uint8_t size; // = 14 //uint8_t uid; // = 0x16, 16-bit UUID @@ -469,8 +482,9 @@ void (*const MI32_Commands[])(void) PROGMEM = { #define MI_DOOR 14 #define MI_SCALE_V1 15 #define MI_SCALE_V2 16 +#define MI_CGDK2 17 -#define MI_MI32_TYPES 16 //count this manually +#define MI_MI32_TYPES 17 //count this manually const uint16_t kMI32DeviceID[MI_MI32_TYPES]={ 0x0000, // Unkown @@ -488,7 +502,8 @@ const uint16_t kMI32DeviceID[MI_MI32_TYPES]={ 0x0a1c, // ATC -> this is a fake ID 0x098b, // door/window sensor 0x181d, // Mi Scale V1 - 0x181b // Mi Scale V2 + 0x181b, // Mi Scale V2 + 0x066f, // CGDK2 }; const char kMI32DeviceType0[] PROGMEM = "Unknown"; @@ -507,7 +522,8 @@ const char kMI32DeviceType12[] PROGMEM ="ATC"; const char kMI32DeviceType13[] PROGMEM ="DOOR"; const char kMI32DeviceType14[] PROGMEM ="MISCALEV1"; const char kMI32DeviceType15[] PROGMEM ="MISCALEV2"; -const char * kMI32DeviceType[] PROGMEM = {kMI32DeviceType0,kMI32DeviceType1,kMI32DeviceType2,kMI32DeviceType3,kMI32DeviceType4,kMI32DeviceType5,kMI32DeviceType6,kMI32DeviceType7,kMI32DeviceType8,kMI32DeviceType9,kMI32DeviceType10,kMI32DeviceType11,kMI32DeviceType12,kMI32DeviceType13,kMI32DeviceType14,kMI32DeviceType15}; +const char kMI32DeviceType16[] PROGMEM ="CGDK2"; +const char * kMI32DeviceType[] PROGMEM = {kMI32DeviceType0,kMI32DeviceType1,kMI32DeviceType2,kMI32DeviceType3,kMI32DeviceType4,kMI32DeviceType5,kMI32DeviceType6,kMI32DeviceType7,kMI32DeviceType8,kMI32DeviceType9,kMI32DeviceType10,kMI32DeviceType11,kMI32DeviceType12,kMI32DeviceType13,kMI32DeviceType14,kMI32DeviceType15,kMI32DeviceType16}; typedef int BATREAD_FUNCTION(int slot); typedef int UNITWRITE_FUNCTION(int slot, int unit); @@ -1073,9 +1089,16 @@ int MI32advertismentCallback(BLE_ESP32::ble_advertisment_t *pStruct) TasAutoMutex localmutex(&slotmutex, "Mi32AdCB2"); switch(UUID){ case 0xfe95: // std MI? - case 0xfdcd: // CGD1? { - MI32ParseResponse(ServiceData, ServiceDataLength, addr, RSSI); + MI32ParseResponse(ServiceData, ServiceDataLength, addr, RSSI); + } break; + case 0xfdcd: // CGD1 & CGDK2 + { + if (ServiceDataLength == 17){ // CGDK2 + MI32ParseCGDK2Packet(ServiceData, ServiceDataLength, addr, RSSI); + } else { + MI32ParseResponse(ServiceData, ServiceDataLength, addr, RSSI); + } } break; case 0x181a: { //ATC MI32ParseATCPacket(ServiceData, ServiceDataLength, addr, RSSI); @@ -1758,6 +1781,42 @@ void MI32ParseATCPacket(const uint8_t * _buf, uint32_t length, const uint8_t *ad } } +void MI32ParseCGDK2Packet(const uint8_t * _buf, uint32_t length, const uint8_t *addr, int RSSI){ + CGDK2Packet_t *cgdk_packet = (CGDK2Packet_t*)_buf; + + if (length == 17){ // + uint8_t addrrev[6]; + memcpy(addrrev, addr, 6); + MI32_ReverseMAC(addrrev); + + if (!memcmp(addrrev, cgdk_packet->MAC, 6)){ + uint32_t _slot = MIBLEgetSensorSlot(addr, 0x066f, cgdk_packet->counter); // This must be a hard-coded fake ID + if(_slot==0xff) return; + + if ((_slot >= 0) && (_slot < MIBLEsensors.size())){ + if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG,PSTR("M32: %s:pvvx at slot %u"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot); + MIBLEsensors[_slot].RSSI=RSSI; + MIBLEsensors[_slot].needkey=KEY_NOT_REQUIRED; + MIBLEsensors[_slot].temp = (float)(cgdk_packet->temperature)/10.0f; + MIBLEsensors[_slot].hum = (float)(cgdk_packet->humidity)/10.0f; + MIBLEsensors[_slot].eventType.tempHum = 1; + MIBLEsensors[_slot].bat = cgdk_packet->battery_level; + MIBLEsensors[_slot].eventType.bat = 1; + + if(MI32.option.directBridgeMode) { + MIBLEsensors[_slot].shallSendMQTT = 1; + MI32.mode.shallTriggerTele = 1; + } + } + return; + } else { + AddLog(LOG_LEVEL_ERROR, PSTR("M32: CGDK2 packet mac mismatch - ignored?")); + return; + } + } + +} + void MI32ParseMiScalePacket(const uint8_t * _buf, uint32_t length, const uint8_t *addr, int RSSI, int UUID) { MiScaleV1Packet_t *_packetV1 = (MiScaleV1Packet_t*)_buf; MiScaleV2Packet_t *_packetV2 = (MiScaleV2Packet_t*)_buf; @@ -3569,4 +3628,4 @@ bool Xsns62(uint32_t function) #endif // CONFIG_IDF_TARGET_ESP32 or CONFIG_IDF_TARGET_ESP32C3 #endif // ESP32 -#endif \ No newline at end of file +#endif diff --git a/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino b/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino index 7cb2daf93..dcd9f5d3a 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino @@ -86,7 +86,7 @@ void RC522ScanForTag(void) { } #endif // USE_RC522_DATA_FUNCTION #ifdef USE_RC522_TYPE_INFORMATION - ResponseAppend_P(PSTR(",\"" D_JSON_TYPE "\":\"%s\""), Mfrc522->PICC_GetTypeName(picc_type)); + ResponseAppend_P(PSTR(",\"" D_JSON_TYPE "\":\"%s\""), Mfrc522->PICC_GetTypeName(picc_type).c_str()); #endif // USE_RC522_TYPE_INFORMATION ResponseJsonEndEnd(); MqttPublishTeleSensor(); diff --git a/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino b/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino index ea32fcb22..02cce9e27 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino @@ -191,7 +191,7 @@ void TfmpShow(bool json) { float distance = (float)tfminiplus_sensor.distance; // cm if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":\"%1_f\",\"" D_JSON_SIGNALSTRENGTH "\":\"%d\",\"" D_JSON_CHIPTEMPERATURE "\":%d}"), + ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":%1_f,\"" D_JSON_SIGNALSTRENGTH "\":%d,\"" D_JSON_CHIPTEMPERATURE "\":%d}"), sensor_name, &distance, tfminiplus_sensor.sigstrength, tfminiplus_sensor.chiptemp); #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) { @@ -242,4 +242,4 @@ bool Xsns86(uint32_t callback_id) } return result; } -#endif // USE_TFMINIPLUS \ No newline at end of file +#endif // USE_TFMINIPLUS diff --git a/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino b/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino index 3248ea7f6..2f866bf9c 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino @@ -119,15 +119,13 @@ void VindriktningInit(void) { } } -#ifdef USE_WEBSERVER -const char HTTP_VINDRIKTNING_SNS[] PROGMEM = - "{s}VINDRIKTNING " D_ENVIRONMENTAL_CONCENTRATION " %s " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = -#endif // USE_WEBSERVER - void VindriktningShow(bool json) { if (Vindriktning.valid) { + char types[16]; + strcpy_P(types, PSTR("VINDRIKTNING")); + if (json) { - ResponseAppend_P(PSTR(",\"VINDRIKTNING\":{")); + ResponseAppend_P(PSTR(",\"%s\":{"), types); #ifdef VINDRIKTNING_SHOW_PM1 ResponseAppend_P(PSTR("\"PM1\":%d,"), Vindriktning.pm1_0); #endif // VINDRIKTNING_SHOW_PM1 @@ -150,11 +148,11 @@ void VindriktningShow(bool json) { #ifdef USE_WEBSERVER } else { #ifdef VINDRIKTNING_SHOW_PM1 - WSContentSend_PD(HTTP_VINDRIKTNING_SNS, "1", Vindriktning.pm1_0); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "1", Vindriktning.pm1_0); #endif // VINDRIKTNING_SHOW_PM1 - WSContentSend_PD(HTTP_VINDRIKTNING_SNS, "2.5", Vindriktning.pm2_5); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "2.5", Vindriktning.pm2_5); #ifdef VINDRIKTNING_SHOW_PM10 - WSContentSend_PD(HTTP_VINDRIKTNING_SNS, "10", Vindriktning.pm10); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "10", Vindriktning.pm10); #endif // VINDRIKTNING_SHOW_PM10 #endif // USE_WEBSERVER } diff --git a/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino b/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino index e18ae6de8..0a4128671 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino @@ -269,32 +269,14 @@ void HM330XEnterSleep() * SNS Interface \*********************************************************************************************/ -const char JSON_HM330X_SNS[] PROGMEM = ",\"HM330X\":{" - "\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d," - "\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d," - "\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"; +void HM330XShow(bool json) { + if (HM330Xdata->valid) { + char types[10]; + strcpy_P(types, PSTR("HM330X")); -const char HTTP_HM330X_SNS[] PROGMEM = - // "{s}HM330X " D_STANDARD_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - // "{s}HM330X " D_STANDARD_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - // "{s}HM330X " D_STANDARD_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}HM330X " D_ENVIRONMENTAL_CONCENTRATION " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}HM330X " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}HM330X " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" - "{s}HM330X " D_PARTICALS_BEYOND " 0.3 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}HM330X " D_PARTICALS_BEYOND " 0.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}HM330X " D_PARTICALS_BEYOND " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}HM330X " D_PARTICALS_BEYOND " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}HM330X " D_PARTICALS_BEYOND " 5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}" - "{s}HM330X " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; // {s} = - - -void HM330XShow(bool json) -{ - if (HM330Xdata->valid) - { if (json) { - ResponseAppend_P(JSON_HM330X_SNS, + ResponseAppend_P(PSTR(",\"%s\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"), + types, HM330Xdata->rx_buffer.pm1_0_standard, HM330Xdata->rx_buffer.pm2_5_standard, HM330Xdata->rx_buffer.pm10_0_standard, HM330Xdata->rx_buffer.pm1_0_env, HM330Xdata->rx_buffer.pm2_5_env, HM330Xdata->rx_buffer.pm10_0_env, HM330Xdata->rx_buffer.particles_0_3um, HM330Xdata->rx_buffer.particles_0_5um, HM330Xdata->rx_buffer.particles_1_0um, @@ -308,11 +290,18 @@ void HM330XShow(bool json) #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_HM330X_SNS, - // HM330Xdata->rx_buffer.pm1_0_standard, HM330Xdata->rx_buffer.pm2_5_standard, HM330Xdata->rx_buffer.pm10_0_standard, - HM330Xdata->rx_buffer.pm1_0_env, HM330Xdata->rx_buffer.pm2_5_env, HM330Xdata->rx_buffer.pm10_0_env, - HM330Xdata->rx_buffer.particles_0_3um, HM330Xdata->rx_buffer.particles_0_5um, HM330Xdata->rx_buffer.particles_1_0um, - HM330Xdata->rx_buffer.particles_2_5um, HM330Xdata->rx_buffer.particles_5_0um, HM330Xdata->rx_buffer.particles_10_0um); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "1", HM330Xdata->rx_buffer.pm1_0_standard); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "2.5", HM330Xdata->rx_buffer.pm2_5_standard); +// WSContentSend_PD(HTTP_SNS_STANDARD_CONCENTRATION, types, "10", HM330Xdata->rx_buffer.pm10_0_standard); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "1", HM330Xdata->rx_buffer.pm1_0_env); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "2.5", HM330Xdata->rx_buffer.pm2_5_env); + WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "10", HM330Xdata->rx_buffer.pm10_0_env); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.3", HM330Xdata->rx_buffer.particles_0_3um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.5", HM330Xdata->rx_buffer.particles_0_5um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "1", HM330Xdata->rx_buffer.particles_1_0um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "2.5", HM330Xdata->rx_buffer.particles_2_5um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "5", HM330Xdata->rx_buffer.particles_5_0um); + WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "10", HM330Xdata->rx_buffer.particles_10_0um); #endif // USE_WEBSERVER } } diff --git a/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino b/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino index e40df3f07..c72794912 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino @@ -104,8 +104,6 @@ const char HTTP_SNS_SGP40[] PROGMEM = const char HTTP_SNS_AHUM40[] PROGMEM = "{s}SGP40 Abs Humidity{m}%s g/m3{e}"; #endif -#define D_JSON_AHUM "aHumidity" - void Sgp40Show(bool json) { if (sgp40_ready) { diff --git a/tasmota/zigbee/Tuya_hpsz.zb b/tasmota/zigbee/Tuya_hpsz.zb new file mode 100644 index 000000000..3057dac73 --- /dev/null +++ b/tasmota/zigbee/Tuya_hpsz.zb @@ -0,0 +1,10 @@ +#Z2Tv1 +# Human presence sensor Zigbee +# https://zigbee.blakadder.com/Tuya_PS-HPS.html +:TS0601,_TZE200_0u3bj3rc +:TS0601,_TZE200_v6ossqfy +:TS0601,_TZE200_mx6u6l4y +EF00/0401=0406/0000 # map to Occupancy +EF00/0265,HPSZPresenceTime # Shows the presence duration in minutes +EF00/0266,HPSZLeavingTime # Shows the duration of the absence in minutes +EF00/0167,HPSZLEDState # Turns the onboard LED on or off diff --git a/tools/decode-status.py b/tools/decode-status.py index 65c5c9a5f..490e8e79a 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -293,8 +293,8 @@ a_features = [[ "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ", "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","USE_ME007", "USE_DISPLAY_TM1650","USE_PCA9632","USE_TUYAMCUBR","USE_SEN5X", - "USE_BIOPDU","","","", - "","","","", + "USE_BIOPDU","USE_MCP23XXX_DRV","USE_PMSA003I","USE_LOX_O2", + "USE_GDK101","","","", "","","","", "","","","" ]] @@ -324,7 +324,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v12.3.1.6 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v12.4.0.5 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) diff --git a/tools/lv_gpio/lv_gpio_enum.h b/tools/lv_gpio/lv_gpio_enum.h index cfb7bdb92..0484e4490 100644 --- a/tools/lv_gpio/lv_gpio_enum.h +++ b/tools/lv_gpio/lv_gpio_enum.h @@ -332,5 +332,6 @@ ADE7953_CS = GPIO_ADE7953_CS BIOPDU_PZEM0XX_TX = GPIO_BIOPDU_PZEM0XX_TX BIOPDU_PZEM016_RX = GPIO_BIOPDU_PZEM016_RX BIOPDU_BIT = GPIO_BIOPDU_BIT +LOX_O2_RX = GPIO_LOX_O2_RX SENSOR_END = GPIO_SENSOR_END
, {m} = , {e} =
, {m} = , {e} =
, {m} = , {e} =
, {m} = , {e} =
, {m} = , {e} =
, {m} = , {e} =